diff options
Diffstat (limited to 'src/utils/libsmartcols/src/print.c')
-rw-r--r-- | src/utils/libsmartcols/src/print.c | 261 |
1 files changed, 179 insertions, 82 deletions
diff --git a/src/utils/libsmartcols/src/print.c b/src/utils/libsmartcols/src/print.c index 9d78c90..9f60148 100644 --- a/src/utils/libsmartcols/src/print.c +++ b/src/utils/libsmartcols/src/print.c @@ -1,5 +1,4 @@ -/* - * table.c - functions handling the data at the table level + /* print.c - functions to print table * * Copyright (C) 2010-2014 Karel Zak <kzak@redhat.com> * Copyright (C) 2016 Igor Gnatenko <i.gnatenko.brain@gmail.com> @@ -217,16 +216,94 @@ static int has_pending_data(struct libscols_table *tb) return 0; } +static void fputs_color_reset(struct libscols_table *tb) +{ + if (tb->cur_color) { + fputs(UL_COLOR_RESET, tb->out); + tb->cur_color = NULL; + } +} + +static void fputs_color(struct libscols_table *tb, const char *color) +{ + if (tb->cur_color) + fputs_color_reset(tb); + + tb->cur_color = color; + if (color) + fputs(color, tb->out); +} + +static const char *get_cell_color(struct libscols_table *tb, + struct libscols_column *cl, + struct libscols_line *ln, + struct libscols_cell *ce) +{ + const char *color = NULL; + + if (!tb || !tb->colors_wanted || tb->format != SCOLS_FMT_HUMAN) + return NULL; + if (ce) + color = ce->color; + if (!color && (!ln || !ln->color) && cl) + color = cl->color; + return color; +} + +/* switch from line color to cell/column color */ +static void fputs_color_cell_open(struct libscols_table *tb, + struct libscols_column *cl, + struct libscols_line *ln, + struct libscols_cell *ce) +{ + const char *color = get_cell_color(tb, cl, ln, ce); + + if (color) + fputs_color(tb, color); +} + +/* switch from cell/column color to line color or reset */ +static void fputs_color_cell_close(struct libscols_table *tb, + struct libscols_column *cl, + struct libscols_line *ln, + struct libscols_cell *ce) +{ + const char *color = get_cell_color(tb, cl, ln, ce); + + if (color) + fputs_color(tb, ln ? ln->color : NULL); +} + +/* switch to line color */ +static void fputs_color_line_open(struct libscols_table *tb, + struct libscols_line *ln) +{ + if (!tb || !tb->colors_wanted || tb->format != SCOLS_FMT_HUMAN) + return; + fputs_color(tb, ln ? ln->color : NULL); +} + +/* switch off all colors */ +static void fputs_color_line_close(struct libscols_table *tb) +{ + if (!tb || !tb->colors_wanted || tb->format != SCOLS_FMT_HUMAN) + return; + fputs_color_reset(tb); +} + /* print padding or ASCII-art instead of data of @cl */ static void print_empty_cell(struct libscols_table *tb, struct libscols_column *cl, struct libscols_line *ln, /* optional */ + struct libscols_cell *ce, size_t bufsz) { size_t len_pad = 0; /* in screen cells as opposed to bytes */ DBG(COL, ul_debugobj(cl, " printing empty cell")); + fputs_color_cell_open(tb, cl, ln, ce); + /* generate tree ASCII-art rather than padding */ if (ln && scols_column_is_tree(cl)) { if (!ln->parent) { @@ -256,39 +333,28 @@ static void print_empty_cell(struct libscols_table *tb, } /* minout -- don't fill */ - if (scols_table_is_minout(tb) && is_next_columns_empty(tb, cl, ln)) + if (scols_table_is_minout(tb) && is_next_columns_empty(tb, cl, ln)) { + fputs_color_cell_close(tb, cl, ln, ce); return; + } /* default -- fill except last column */ - if (!scols_table_is_maxout(tb) && is_last_column(cl)) + if (!scols_table_is_maxout(tb) && is_last_column(cl)) { + fputs_color_cell_close(tb, cl, ln, ce); return; + } /* fill rest of cell with space */ for(; len_pad < cl->width; ++len_pad) fputs(cellpadding_symbol(tb), tb->out); + fputs_color_cell_close(tb, cl, ln, ce); + if (!is_last_column(cl)) fputs(colsep(tb), tb->out); } -static const char *get_cell_color(struct libscols_table *tb, - struct libscols_column *cl, - struct libscols_line *ln, /* optional */ - struct libscols_cell *ce) /* optional */ -{ - const char *color = NULL; - - if (tb && tb->colors_wanted) { - if (ce) - color = ce->color; - if (ln && !color) - color = ln->color; - if (!color) - color = cl->color; - } - return color; -} /* Fill the start of a line with padding (or with tree ascii-art). * @@ -304,6 +370,7 @@ static const char *get_cell_color(struct libscols_table *tb, static void print_newline_padding(struct libscols_table *tb, struct libscols_column *cl, struct libscols_line *ln, /* optional */ + struct libscols_cell *ce, size_t bufsz) { size_t i; @@ -316,9 +383,13 @@ static void print_newline_padding(struct libscols_table *tb, fputs(linesep(tb), tb->out); /* line break */ tb->termlines_used++; + fputs_color_line_open(tb, ln); + /* fill cells after line break */ for (i = 0; i <= (size_t) cl->seqnum; i++) - print_empty_cell(tb, scols_table_get_column(tb, i), ln, bufsz); + print_empty_cell(tb, scols_table_get_column(tb, i), ln, ce, bufsz); + + fputs_color_line_close(tb); } /* @@ -374,7 +445,6 @@ static int print_pending_data( struct libscols_line *ln, /* optional */ struct libscols_cell *ce) { - const char *color = get_cell_color(tb, cl, ln, ce); size_t width = cl->width, bytes; size_t len = width, i; char *data; @@ -407,25 +477,29 @@ static int print_pending_data( if (bytes) step_pending_data(cl, bytes); - if (color) - fputs(color, tb->out); + fputs_color_cell_open(tb, cl, ln, ce); + fputs(data, tb->out); - if (color) - fputs(UL_COLOR_RESET, tb->out); free(data); /* minout -- don't fill */ - if (scols_table_is_minout(tb) && is_next_columns_empty(tb, cl, ln)) + if (scols_table_is_minout(tb) && is_next_columns_empty(tb, cl, ln)) { + fputs_color_cell_close(tb, cl, ln, ce); return 0; + } /* default -- fill except last column */ - if (!scols_table_is_maxout(tb) && is_last_column(cl)) + if (!scols_table_is_maxout(tb) && is_last_column(cl)) { + fputs_color_cell_close(tb, cl, ln, ce); return 0; + } /* fill rest of cell with space */ for(i = len; i < width; i++) fputs(cellpadding_symbol(tb), tb->out); + fputs_color_cell_close(tb, cl, ln, ce); + if (!is_last_column(cl)) fputs(colsep(tb), tb->out); @@ -435,6 +509,49 @@ err: return -errno; } +static void print_json_data(struct libscols_table *tb, + struct libscols_column *cl, + const char *name, + char *data) +{ + switch (cl->json_type) { + case SCOLS_JSON_STRING: + /* name: "aaa" */ + ul_jsonwrt_value_s(&tb->json, name, data); + break; + case SCOLS_JSON_NUMBER: + /* name: 123 */ + ul_jsonwrt_value_raw(&tb->json, name, data); + break; + case SCOLS_JSON_BOOLEAN: + /* name: true|false */ + ul_jsonwrt_value_boolean(&tb->json, name, + !*data ? 0 : + *data == '0' ? 0 : + *data == 'N' || *data == 'n' ? 0 : 1); + break; + case SCOLS_JSON_ARRAY_STRING: + case SCOLS_JSON_ARRAY_NUMBER: + /* name: [ "aaa", "bbb", "ccc" ] */ + ul_jsonwrt_array_open(&tb->json, name); + + if (!scols_column_is_customwrap(cl)) + ul_jsonwrt_value_s(&tb->json, NULL, data); + else do { + char *next = cl->wrap_nextchunk(cl, data, cl->wrapfunc_data); + + if (cl->json_type == SCOLS_JSON_ARRAY_STRING) + ul_jsonwrt_value_s(&tb->json, NULL, data); + else + ul_jsonwrt_value_raw(&tb->json, NULL, data); + data = next; + } while (data); + + ul_jsonwrt_array_close(&tb->json); + break; + } +} + static int print_data(struct libscols_table *tb, struct libscols_column *cl, struct libscols_line *ln, /* optional */ @@ -442,7 +559,6 @@ static int print_data(struct libscols_table *tb, struct libscols_buffer *buf) { size_t len = 0, i, width, bytes; - const char *color = NULL; char *data, *nextchunk; const char *name = NULL; int is_last; @@ -472,36 +588,23 @@ static int print_data(struct libscols_table *tb, return 0; case SCOLS_FMT_EXPORT: - fprintf(tb->out, "%s=", name); + fputs_shell_ident(name, tb->out); + if (endswith(name, "%")) + fputs("PCT", tb->out); + fputc('=', tb->out); fputs_quoted(data, tb->out); if (!is_last) fputs(colsep(tb), tb->out); return 0; case SCOLS_FMT_JSON: - switch (cl->json_type) { - case SCOLS_JSON_STRING: - ul_jsonwrt_value_s(&tb->json, name, data, is_last); - break; - case SCOLS_JSON_NUMBER: - ul_jsonwrt_value_raw(&tb->json, name, data, is_last); - break; - case SCOLS_JSON_BOOLEAN: - ul_jsonwrt_value_boolean(&tb->json, name, - !*data ? 0 : - *data == '0' ? 0 : - *data == 'N' || *data == 'n' ? 0 : 1, - is_last); - break; - } + print_json_data(tb, cl, name, data); return 0; case SCOLS_FMT_HUMAN: break; /* continue below */ } - color = get_cell_color(tb, cl, ln, ce); - /* Encode. Note that 'len' and 'width' are number of cells, not bytes. */ data = buffer_get_safe_data(tb, buf, &len, scols_column_get_safechars(cl)); @@ -549,49 +652,39 @@ static int print_data(struct libscols_table *tb, data = NULL; } + fputs_color_cell_open(tb, cl, ln, ce); + if (data && *data) { if (scols_column_is_right(cl)) { - if (color) - fputs(color, tb->out); for (i = len; i < width; i++) fputs(cellpadding_symbol(tb), tb->out); - fputs(data, tb->out); - if (color) - fputs(UL_COLOR_RESET, tb->out); len = width; + } + fputs(data, tb->out); - } else if (color) { - char *p = data; - size_t art = buffer_get_safe_art_size(buf); - - /* we don't want to colorize tree ascii art */ - if (scols_column_is_tree(cl) && art && art < bytes) { - fwrite(p, 1, art, tb->out); - p += art; - } - - fputs(color, tb->out); - fputs(p, tb->out); - fputs(UL_COLOR_RESET, tb->out); - } else - fputs(data, tb->out); } /* minout -- don't fill */ - if (scols_table_is_minout(tb) && is_next_columns_empty(tb, cl, ln)) + if (scols_table_is_minout(tb) && is_next_columns_empty(tb, cl, ln)) { + fputs_color_cell_close(tb, cl, ln, ce); return 0; + } /* default -- fill except last column */ - if (!scols_table_is_maxout(tb) && is_last) + if (!scols_table_is_maxout(tb) && is_last) { + fputs_color_cell_close(tb, cl, ln, ce); return 0; + } /* fill rest of cell with space */ for(i = len; i < width; i++) fputs(cellpadding_symbol(tb), tb->out); + fputs_color_cell_close(tb, cl, ln, ce); + if (len > width && !scols_column_is_trunc(cl)) { DBG(COL, ul_debugobj(cl, "*** data len=%zu > column width=%zu", len, width)); - print_newline_padding(tb, cl, ln, buffer_get_size(buf)); /* next column starts on next line */ + print_newline_padding(tb, cl, ln, ce, buffer_get_size(buf)); /* next column starts on next line */ } else if (!is_last) fputs(colsep(tb), tb->out); /* columns separator */ @@ -664,6 +757,8 @@ static int print_line(struct libscols_table *tb, DBG(LINE, ul_debugobj(ln, "printing line")); + fputs_color_line_open(tb, ln); + /* regular line */ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) { @@ -677,12 +772,14 @@ static int print_line(struct libscols_table *tb, if (rc == 0 && cl->pending_data) pending = 1; } + fputs_color_line_close(tb); /* extra lines of the multi-line cells */ while (rc == 0 && pending) { DBG(LINE, ul_debugobj(ln, "printing pending data")); pending = 0; fputs(linesep(tb), tb->out); + fputs_color_line_open(tb, ln); tb->termlines_used++; scols_reset_iter(&itr, SCOLS_ITER_FORWARD); while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) { @@ -693,8 +790,9 @@ static int print_line(struct libscols_table *tb, if (rc == 0 && cl->pending_data) pending = 1; } else - print_empty_cell(tb, cl, ln, buffer_get_size(buf)); + print_empty_cell(tb, cl, ln, NULL, buffer_get_size(buf)); } + fputs_color_line_close(tb); } return 0; @@ -702,7 +800,7 @@ static int print_line(struct libscols_table *tb, int __scols_print_title(struct libscols_table *tb) { - int rc, color = 0; + int rc; mbs_align_t align; size_t width, len = 0, bufsz, titlesz; char *title = NULL, *buf = NULL; @@ -783,15 +881,14 @@ int __scols_print_title(struct libscols_table *tb) goto done; } - if (tb->colors_wanted && tb->title.color) - color = 1; - if (color) - fputs(tb->title.color, tb->out); + + if (tb->colors_wanted) + fputs_color(tb, tb->title.color); fputs(title, tb->out); - if (color) - fputs(UL_COLOR_RESET, tb->out); + if (tb->colors_wanted) + fputs_color_reset(tb); fputc('\n', tb->out); rc = 0; @@ -877,7 +974,7 @@ int __scols_print_range(struct libscols_table *tb, rc = print_line(tb, ln, buf); if (scols_table_is_json(tb)) - ul_jsonwrt_object_close(&tb->json, last); + ul_jsonwrt_object_close(&tb->json); else if (last == 0 && tb->no_linesep == 0) { fputs(linesep(tb), tb->out); tb->termlines_used++; @@ -937,9 +1034,9 @@ static int print_tree_line(struct libscols_table *tb, last = (is_child(ln) && is_last_child(ln)) || (is_tree_root(ln) && is_last_tree_root(tb, ln)); - ul_jsonwrt_object_close(&tb->json, last); + ul_jsonwrt_object_close(&tb->json); if (last && is_child(ln)) - ul_jsonwrt_array_close(&tb->json, last); + ul_jsonwrt_array_close(&tb->json); ln = ln->parent; } while(ln && last); |