diff options
author | Karel Zak | 2014-04-14 16:41:20 +0200 |
---|---|---|
committer | Karel Zak | 2014-04-14 16:41:20 +0200 |
commit | b233dcb6ffa9a880882d58f85162ff97cede050f (patch) | |
tree | 2a4ac538f2b1c2974e39902444131f19bf91b925 /libsmartcols/src/table_print.c | |
parent | delpart: minor man page improvements (diff) | |
download | kernel-qcow2-util-linux-b233dcb6ffa9a880882d58f85162ff97cede050f.tar.gz kernel-qcow2-util-linux-b233dcb6ffa9a880882d58f85162ff97cede050f.tar.xz kernel-qcow2-util-linux-b233dcb6ffa9a880882d58f85162ff97cede050f.zip |
libsmartcols: use buffer struct in table_print.c
* consolidate code in table_print.c
* make the code easy to extend
* use return codes everywhere
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'libsmartcols/src/table_print.c')
-rw-r--r-- | libsmartcols/src/table_print.c | 318 |
1 files changed, 208 insertions, 110 deletions
diff --git a/libsmartcols/src/table_print.c b/libsmartcols/src/table_print.c index 0a3a30760..082cc0bf3 100644 --- a/libsmartcols/src/table_print.c +++ b/libsmartcols/src/table_print.c @@ -28,24 +28,92 @@ #include "carefulputc.h" #include "smartcolsP.h" +/* This is private struct to work with output data */ +struct libscols_buffer { + char *begin; /* begin of the buffer */ + char *cur; /* current end of the buffer */ + + size_t bufsz; /* size of the buffer */ +}; + +static struct libscols_buffer *new_buffer(size_t sz) +{ + struct libscols_buffer *buf = malloc(sz + sizeof(struct libscols_buffer)); + + if (!buf) + return NULL; + + buf->cur = buf->begin = ((char *) buf) + sizeof(struct libscols_buffer); + buf->bufsz = sz; + return buf; +} + +static void free_buffer(struct libscols_buffer *buf) +{ + free(buf); +} + +static int buffer_reset_data(struct libscols_buffer *buf) +{ + if (!buf) + return -EINVAL; + + buf->begin[0] = '\0'; + buf->cur = buf->begin; + return 0; +} + +static int buffer_append_data(struct libscols_buffer *buf, const char *str) +{ + size_t maxsz, sz; + + if (!buf) + return -EINVAL; + if (!str || !*str) + return 0; + + sz = strlen(str); + maxsz = buf->bufsz - (buf->cur - buf->begin); + + if (maxsz <= sz) + return -EINVAL; + + memcpy(buf->cur, str, sz + 1); + buf->cur += sz; + return 0; +} + +static int buffer_set_data(struct libscols_buffer *buf, const char *str) +{ + int rc = buffer_reset_data(buf); + return rc ? rc : buffer_append_data(buf, str); +} + +static char *buffer_get_data(struct libscols_buffer *buf) +{ + return buf ? buf->begin : NULL; +} + #define is_last_column(_tb, _cl) \ list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns) #define colsep(tb) ((tb)->colsep ? (tb)->colsep : " ") #define linesep(tb) ((tb)->linesep ? (tb)->linesep : "\n") -static void print_data(struct libscols_table *tb, - struct libscols_column *cl, - struct libscols_line *ln, /* optional */ - struct libscols_cell *ce, /* optional */ - char *data) + +static int print_data(struct libscols_table *tb, + struct libscols_column *cl, + struct libscols_line *ln, /* optional */ + struct libscols_cell *ce, /* optional */ + struct libscols_buffer *buf) { size_t len = 0, i, width; - char *buf; const char *color = NULL; + char *data, *data_enc = NULL; assert(tb); assert(cl); + data = buffer_get_data(buf); if (!data) data = ""; @@ -54,7 +122,7 @@ static void print_data(struct libscols_table *tb, fputs_nonblank(data, tb->out); if (!is_last_column(tb, cl)) fputs(colsep(tb), tb->out); - return; + return 0; } /* NAME=value mode */ @@ -63,7 +131,7 @@ static void print_data(struct libscols_table *tb, fputs_quoted(data, tb->out); if (!is_last_column(tb, cl)) fputs(colsep(tb), tb->out); - return; + return 0; } if (tb->colors_wanted) { @@ -76,8 +144,7 @@ static void print_data(struct libscols_table *tb, } /* note that 'len' and 'width' are number of cells, not bytes */ - buf = mbs_safe_encode(data, &len); - data = buf; + data_enc = data = mbs_safe_encode(data, &len); if (!data) data = ""; @@ -132,110 +199,109 @@ static void print_data(struct libscols_table *tb, fputs(colsep(tb), tb->out); /* columns separator */ } - free(buf); + free(data_enc); + return 0; } -static char *line_get_ascii_art(struct libscols_table *tb, - struct libscols_line *ln, - char *buf, size_t *bufsz) +/* returns pointer to the end of used data */ +static int line_ascii_art_to_buffer(struct libscols_table *tb, + struct libscols_line *ln, + struct libscols_buffer *buf) { const char *art; - size_t len; + int rc; assert(ln); + assert(buf); if (!ln->parent) - return buf; + return 0; - buf = line_get_ascii_art(tb, ln->parent, buf, bufsz); - if (!buf) - return NULL; + rc = line_ascii_art_to_buffer(tb, ln->parent, buf); + if (rc) + return rc; if (list_entry_is_last(&ln->ln_children, &ln->parent->ln_branch)) art = " "; else art = tb->symbols->vert; - len = strlen(art); - if (*bufsz < len) - return NULL; /* no space, internal error */ - - memcpy(buf, art, len); - *bufsz -= len; - return buf + len; + return buffer_append_data(buf, art); } -static char *line_get_data(struct libscols_table *tb, - struct libscols_line *ln, - struct libscols_column *cl, - char *buf, size_t bufsz) +static int cell_to_buffer(struct libscols_table *tb, + struct libscols_line *ln, + struct libscols_column *cl, + struct libscols_buffer *buf) { const char *data; - struct libscols_symbols *sym; struct libscols_cell *ce; - char *p = buf; + int rc = 0; assert(tb); assert(ln); assert(cl); + assert(buf); assert(cl->seqnum <= tb->ncols); - memset(buf, 0, bufsz); - ce = scols_line_get_cell(ln, cl->seqnum); data = ce ? scols_cell_get_data(ce) : NULL; if (!data) - return NULL; + return 0; - if (!scols_column_is_tree(cl)) { - strncpy(buf, data, bufsz); - buf[bufsz - 1] = '\0'; - return buf; - } + if (!scols_column_is_tree(cl)) + return buffer_set_data(buf, data); /* * Tree stuff */ - if (ln->parent) { - p = line_get_ascii_art(tb, ln->parent, buf, &bufsz); - if (!p) - return NULL; - } + buffer_reset_data(buf); - sym = tb->symbols; + if (ln->parent) { + rc = line_ascii_art_to_buffer(tb, ln->parent, buf); - if (!ln->parent) - snprintf(p, bufsz, "%s", data); /* root node */ - else if (list_entry_is_last(&ln->ln_children, &ln->parent->ln_branch)) - snprintf(p, bufsz, "%s%s", sym->right, data); /* last chaild */ - else - snprintf(p, bufsz, "%s%s", sym->branch, data); /* any child */ + if (!rc && list_entry_is_last(&ln->ln_children, &ln->parent->ln_branch)) + rc = buffer_append_data(buf, tb->symbols->right); + else if (!rc) + rc = buffer_append_data(buf, tb->symbols->branch); + } - return buf; + if (!rc) + rc = buffer_append_data(buf, data); + return rc; } /* * Prints data, data maybe be printed in more formats (raw, NAME=xxx pairs) and * control and non-printable chars maybe encoded in \x?? hex encoding. */ -static void print_line(struct libscols_table *tb, - struct libscols_line *ln, char *buf, size_t bufsz) +static int print_line(struct libscols_table *tb, + struct libscols_line *ln, + struct libscols_buffer *buf) { + int rc = 0; struct libscols_column *cl; struct libscols_iter itr; assert(ln); scols_reset_iter(&itr, SCOLS_ITER_FORWARD); - while (scols_table_next_column(tb, &itr, &cl) == 0) - print_data(tb, cl, ln, - scols_line_get_cell(ln, cl->seqnum), - line_get_data(tb, ln, cl, buf, bufsz)); - fputs(linesep(tb), tb->out); + while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) { + rc = cell_to_buffer(tb, ln, cl, buf); + if (!rc) + rc = print_data(tb, cl, ln, + scols_line_get_cell(ln, cl->seqnum), + buf); + } + + if (rc == 0) + fputs(linesep(tb), tb->out); + return 0; } -static void print_header(struct libscols_table *tb, char *buf, size_t bufsz) +static int print_header(struct libscols_table *tb, struct libscols_buffer *buf) { + int rc = 0; struct libscols_column *cl; struct libscols_iter itr; @@ -244,67 +310,82 @@ static void print_header(struct libscols_table *tb, char *buf, size_t bufsz) if (scols_table_is_noheadings(tb) || scols_table_is_export(tb) || list_empty(&tb->tb_lines)) - return; + return 0; /* set width according to the size of data */ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); - while (scols_table_next_column(tb, &itr, &cl) == 0) { - strncpy(buf, scols_cell_get_data(&cl->header), bufsz); - buf[bufsz - 1] = '\0'; - print_data(tb, cl, NULL, &cl->header, buf); + while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) { + rc = buffer_set_data(buf, scols_cell_get_data(&cl->header)); + if (!rc) + rc = print_data(tb, cl, NULL, &cl->header, buf); } - fputs(linesep(tb), tb->out); + + if (rc == 0) + fputs(linesep(tb), tb->out); + return rc; } -static void print_table(struct libscols_table *tb, char *buf, size_t bufsz) +static int print_table(struct libscols_table *tb, struct libscols_buffer *buf) { + int rc; struct libscols_line *ln; struct libscols_iter itr; assert(tb); - print_header(tb, buf, bufsz); + rc = print_header(tb, buf); scols_reset_iter(&itr, SCOLS_ITER_FORWARD); - while (scols_table_next_line(tb, &itr, &ln) == 0) - print_line(tb, ln, buf, bufsz); + while (rc == 0 && scols_table_next_line(tb, &itr, &ln) == 0) + rc = print_line(tb, ln, buf); + + return rc; } -static void print_tree_line(struct libscols_table *tb, - struct libscols_line *ln, - char *buf, size_t bufsz) +static int print_tree_line(struct libscols_table *tb, + struct libscols_line *ln, + struct libscols_buffer *buf) { + int rc; struct list_head *p; - print_line(tb, ln, buf, bufsz); - + rc = print_line(tb, ln, buf); + if (rc) + return rc; if (list_empty(&ln->ln_branch)) - return; + return 0; /* print all children */ list_for_each(p, &ln->ln_branch) { struct libscols_line *chld = list_entry(p, struct libscols_line, ln_children); - print_tree_line(tb, chld, buf, bufsz); + rc = print_tree_line(tb, chld, buf); + if (rc) + break; } + + return rc; } -static void print_tree(struct libscols_table *tb, char *buf, size_t bufsz) +static int print_tree(struct libscols_table *tb, struct libscols_buffer *buf) { + int rc; struct libscols_line *ln; struct libscols_iter itr; assert(tb); - print_header(tb, buf, bufsz); + rc = print_header(tb, buf); scols_reset_iter(&itr, SCOLS_ITER_FORWARD); - while (scols_table_next_line(tb, &itr, &ln) == 0) { + while (rc == 0 && scols_table_next_line(tb, &itr, &ln) == 0) { if (ln->parent) continue; - print_tree_line(tb, ln, buf, bufsz); + rc = print_tree_line(tb, ln, buf); } + + return rc; } /* @@ -316,14 +397,13 @@ static void print_tree(struct libscols_table *tb, char *buf, size_t bufsz) * is marked as "extreme". In the second pass all extreme fields are ignored * and column width is counted from non-extreme fields only. */ -static void count_column_width(struct libscols_table *tb, - struct libscols_column *cl, - char *buf, - size_t bufsz) +static int count_column_width(struct libscols_table *tb, + struct libscols_column *cl, + struct libscols_buffer *buf) { struct libscols_line *ln; struct libscols_iter itr; - int count = 0; + int count = 0, rc = 0; size_t sum = 0; assert(tb); @@ -333,8 +413,15 @@ static void count_column_width(struct libscols_table *tb, scols_reset_iter(&itr, SCOLS_ITER_FORWARD); while (scols_table_next_line(tb, &itr, &ln) == 0) { - char *data = line_get_data(tb, ln, cl, buf, bufsz); - size_t len = data ? mbs_safe_width(data) : 0; + size_t len; + char *data; + + rc = cell_to_buffer(tb, ln, cl, buf); + if (rc) + return rc; + + data = buffer_get_data(buf); + len = data ? mbs_safe_width(data) : 0; if (len == (size_t) -1) /* ignore broken multibyte strings */ len = 0; @@ -371,30 +458,35 @@ static void count_column_width(struct libscols_table *tb, && cl->width_min < (size_t) cl->width_hint) cl->width = (size_t) cl->width_hint; + + return rc; } /* * This is core of the scols_* voodo... */ -static void recount_widths(struct libscols_table *tb, char *buf, size_t bufsz) +static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf) { struct libscols_column *cl; struct libscols_iter itr; size_t width = 0; /* output width */ - int trunc_only; + int trunc_only, rc = 0; int extremes = 0; /* set basic columns width */ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); while (scols_table_next_column(tb, &itr, &cl) == 0) { - count_column_width(tb, cl, buf, bufsz); + rc = count_column_width(tb, cl, buf); + if (rc) + return rc; + width += cl->width + (is_last_column(tb, cl) ? 0 : 1); extremes += cl->is_extreme; } if (!tb->is_term) - return; + return 0; /* reduce columns with extreme fields */ @@ -407,7 +499,9 @@ static void recount_widths(struct libscols_table *tb, char *buf, size_t bufsz) continue; org_width = cl->width; - count_column_width(tb, cl, buf, bufsz); + rc = count_column_width(tb, cl, buf); + if (rc) + return rc; if (org_width > cl->width) width -= org_width - cl->width; @@ -526,8 +620,9 @@ static void recount_widths(struct libscols_table *tb, char *buf, size_t bufsz) cl->is_extreme ? "yes" : "not"); } */ - return; + return rc; } + static size_t strlen_line(struct libscols_line *ln) { size_t i, sz = 0; @@ -544,6 +639,8 @@ static size_t strlen_line(struct libscols_line *ln) return sz; } + + /** * scols_print_table: * @tb: table @@ -554,10 +651,11 @@ static size_t strlen_line(struct libscols_line *ln) */ int scols_print_table(struct libscols_table *tb) { - char *line; - size_t line_sz; + int rc = 0; + size_t bufsz; struct libscols_line *ln; struct libscols_iter itr; + struct libscols_buffer *buf; assert(tb); if (!tb) @@ -572,30 +670,29 @@ int scols_print_table(struct libscols_table *tb) tb->termwidth = 80; tb->termwidth -= tb->termreduce; - line_sz = tb->termwidth; + bufsz = tb->termwidth; scols_reset_iter(&itr, SCOLS_ITER_FORWARD); while (scols_table_next_line(tb, &itr, &ln) == 0) { size_t sz = strlen_line(ln); - if (sz > line_sz) - line_sz = sz; + if (sz > bufsz) + bufsz = sz; } - line_sz++; /* make a space for \0 */ - line = malloc(line_sz); - if (!line) + buf = new_buffer(bufsz + 1); /* data + space for \0 */ + if (!buf) return -ENOMEM; if (!(scols_table_is_raw(tb) || scols_table_is_export(tb))) - recount_widths(tb, line, line_sz); + rc = recount_widths(tb, buf); if (scols_table_is_tree(tb)) - print_tree(tb, line, line_sz); + rc = print_tree(tb, buf); else - print_table(tb, line, line_sz); + rc = print_table(tb, buf); - free(line); - return 0; + free_buffer(buf); + return rc; } /** @@ -612,6 +709,7 @@ int scols_print_table_to_string(struct libscols_table *tb, char **data) #ifdef HAVE_OPEN_MEMSTREAM FILE *stream; size_t sz; + int rc; if (!tb) return -EINVAL; @@ -622,10 +720,10 @@ int scols_print_table_to_string(struct libscols_table *tb, char **data) return -ENOMEM; scols_table_set_stream(tb, stream); - scols_print_table(tb); + rc = scols_print_table(tb); fclose(stream); - return 0; + return rc; #else return -ENOSYS; #endif |