diff options
Diffstat (limited to 'libsmartcols/src/print.c')
-rw-r--r-- | libsmartcols/src/print.c | 398 |
1 files changed, 3 insertions, 395 deletions
diff --git a/libsmartcols/src/print.c b/libsmartcols/src/print.c index 2c024ca5a..7e56f466e 100644 --- a/libsmartcols/src/print.c +++ b/libsmartcols/src/print.c @@ -26,9 +26,6 @@ #include "carefulputc.h" #include "smartcolsP.h" -#define colsep(tb) ((tb)->colsep ? (tb)->colsep : " ") -#define linesep(tb) ((tb)->linesep ? (tb)->linesep : "\n") - /* Fallback for symbols * * Note that by default library define all the symbols, but in case user does @@ -435,7 +432,7 @@ static int print_data(struct libscols_table *tb, return 0; } -static int cell_to_buffer(struct libscols_table *tb, +int __cell_to_buffer(struct libscols_table *tb, struct libscols_line *ln, struct libscols_column *cl, struct libscols_buffer *buf) @@ -595,7 +592,7 @@ static int print_line(struct libscols_table *tb, while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) { if (scols_column_is_hidden(cl)) continue; - rc = cell_to_buffer(tb, ln, cl, buf); + rc = __cell_to_buffer(tb, ln, cl, buf); if (rc == 0) rc = print_data(tb, cl, ln, scols_line_get_cell(ln, cl->seqnum), @@ -873,395 +870,6 @@ static int print_tree(struct libscols_table *tb, struct libscols_buffer *buf) return rc; } -static void dbg_column(struct libscols_table *tb, struct libscols_column *cl) -{ - if (scols_column_is_hidden(cl)) { - DBG(COL, ul_debugobj(cl, "%s (hidden) ignored", cl->header.data)); - return; - } - - DBG(COL, ul_debugobj(cl, "%15s seq=%zu, width=%zd, " - "hint=%d, avg=%zu, max=%zu, min=%zu, " - "extreme=%s %s", - - cl->header.data, cl->seqnum, cl->width, - cl->width_hint > 1 ? (int) cl->width_hint : - (int) (cl->width_hint * tb->termwidth), - cl->width_avg, - cl->width_max, - cl->width_min, - cl->is_extreme ? "yes" : "not", - cl->flags & SCOLS_FL_TRUNC ? "trunc" : "")); -} - -static void dbg_columns(struct libscols_table *tb) -{ - struct libscols_iter itr; - struct libscols_column *cl; - - scols_reset_iter(&itr, SCOLS_ITER_FORWARD); - while (scols_table_next_column(tb, &itr, &cl) == 0) - dbg_column(tb, cl); -} - - -/* - * This function counts column width. - * - * For the SCOLS_FL_NOEXTREMES columns it is possible to call this function - * two times. The first pass counts the width and average width. If the column - * contains fields that are too large (a width greater than 2 * average) then - * the column is marked as "extreme". In the second pass all extreme fields - * are ignored and the column width is counted from non-extreme fields only. - */ -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 extreme_count = 0, rc = 0, no_header = 0; - size_t extreme_sum = 0; - - assert(tb); - assert(cl); - - cl->width = 0; - if (!cl->width_min) { - if (cl->width_hint < 1 && scols_table_is_maxout(tb) && tb->is_term) { - cl->width_min = (size_t) (cl->width_hint * tb->termwidth); - if (cl->width_min && !is_last_column(cl)) - cl->width_min--; - } - if (scols_cell_get_data(&cl->header)) { - size_t len = mbs_safe_width(scols_cell_get_data(&cl->header)); - cl->width_min = max(cl->width_min, len); - } else - no_header = 1; - - if (!cl->width_min) - cl->width_min = 1; - } - - scols_reset_iter(&itr, SCOLS_ITER_FORWARD); - while (scols_table_next_line(tb, &itr, &ln) == 0) { - size_t len; - char *data; - - rc = cell_to_buffer(tb, ln, cl, buf); - if (rc) - goto done; - - data = buffer_get_data(buf); - - if (!data) - len = 0; - else if (scols_column_is_customwrap(cl)) - len = cl->wrap_chunksize(cl, data, cl->wrapfunc_data); - else - len = mbs_safe_width(data); - - if (len == (size_t) -1) /* ignore broken multibyte strings */ - len = 0; - cl->width_max = max(len, cl->width_max); - - if (cl->is_extreme && cl->width_avg && len > cl->width_avg * 2) - continue; - else if (scols_column_is_noextremes(cl)) { - extreme_sum += len; - extreme_count++; - } - cl->width = max(len, cl->width); - if (scols_column_is_tree(cl)) { - size_t treewidth = buffer_get_safe_art_size(buf); - cl->width_treeart = max(cl->width_treeart, treewidth); - } - } - - if (extreme_count && cl->width_avg == 0) { - cl->width_avg = extreme_sum / extreme_count; - if (cl->width_avg && cl->width_max > cl->width_avg * 2) - cl->is_extreme = 1; - } - - /* enlarge to minimal width */ - if (cl->width < cl->width_min && !scols_column_is_strict_width(cl)) - cl->width = cl->width_min; - - /* use absolute size for large columns */ - else if (cl->width_hint >= 1 && cl->width < (size_t) cl->width_hint - && cl->width_min < (size_t) cl->width_hint) - - cl->width = (size_t) cl->width_hint; - - - /* Column without header and data, set minimal size to zero (default is 1) */ - if (cl->width_max == 0 && no_header && cl->width_min == 1 && cl->width <= 1) - cl->width = cl->width_min = 0; - -done: - ON_DBG(COL, dbg_column(tb, cl)); - return rc; -} - -/* - * This is core of the scols_* voodoo... - */ -static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf) -{ - struct libscols_column *cl; - struct libscols_iter itr; - size_t width = 0, width_min = 0; /* output width */ - int stage, rc = 0; - int extremes = 0; - size_t colsepsz; - - - DBG(TAB, ul_debugobj(tb, "recounting widths (termwidth=%zu)", tb->termwidth)); - - colsepsz = mbs_safe_width(colsep(tb)); - - /* set basic columns width - */ - scols_reset_iter(&itr, SCOLS_ITER_FORWARD); - while (scols_table_next_column(tb, &itr, &cl) == 0) { - int is_last; - - if (scols_column_is_hidden(cl)) - continue; - rc = count_column_width(tb, cl, buf); - if (rc) - goto done; - - is_last = is_last_column(cl); - - width += cl->width + (is_last ? 0 : colsepsz); /* separator for non-last column */ - width_min += cl->width_min + (is_last ? 0 : colsepsz); - extremes += cl->is_extreme; - } - - if (!tb->is_term) { - DBG(TAB, ul_debugobj(tb, " non-terminal output")); - goto done; - } - - /* be paranoid */ - if (width_min > tb->termwidth && scols_table_is_maxout(tb)) { - DBG(TAB, ul_debugobj(tb, " min width larger than terminal! [width=%zu, term=%zu]", width_min, tb->termwidth)); - - scols_reset_iter(&itr, SCOLS_ITER_FORWARD); - while (width_min > tb->termwidth - && scols_table_next_column(tb, &itr, &cl) == 0) { - if (scols_column_is_hidden(cl)) - continue; - width_min--; - cl->width_min--; - } - DBG(TAB, ul_debugobj(tb, " min width reduced to %zu", width_min)); - } - - /* reduce columns with extreme fields */ - if (width > tb->termwidth && extremes) { - DBG(TAB, ul_debugobj(tb, " reduce width (extreme columns)")); - - scols_reset_iter(&itr, SCOLS_ITER_FORWARD); - while (scols_table_next_column(tb, &itr, &cl) == 0) { - size_t org_width; - - if (!cl->is_extreme || scols_column_is_hidden(cl)) - continue; - - org_width = cl->width; - rc = count_column_width(tb, cl, buf); - if (rc) - goto done; - - if (org_width > cl->width) - width -= org_width - cl->width; - else - extremes--; /* hmm... nothing reduced */ - } - } - - if (width < tb->termwidth) { - if (extremes) { - DBG(TAB, ul_debugobj(tb, " enlarge width (extreme columns)")); - - /* enlarge the first extreme column */ - scols_reset_iter(&itr, SCOLS_ITER_FORWARD); - while (scols_table_next_column(tb, &itr, &cl) == 0) { - size_t add; - - if (!cl->is_extreme || scols_column_is_hidden(cl)) - continue; - - /* this column is too large, ignore? - if (cl->width_max - cl->width > - (tb->termwidth - width)) - continue; - */ - - add = tb->termwidth - width; - if (add && cl->width + add > cl->width_max) - add = cl->width_max - cl->width; - - cl->width += add; - width += add; - - if (width == tb->termwidth) - break; - } - } - - if (width < tb->termwidth && scols_table_is_maxout(tb)) { - DBG(TAB, ul_debugobj(tb, " enlarge width (max-out)")); - - /* try enlarging all columns */ - while (width < tb->termwidth) { - scols_reset_iter(&itr, SCOLS_ITER_FORWARD); - while (scols_table_next_column(tb, &itr, &cl) == 0) { - if (scols_column_is_hidden(cl)) - continue; - cl->width++; - width++; - if (width == tb->termwidth) - break; - } - } - } else if (width < tb->termwidth) { - /* enlarge the last column */ - struct libscols_column *col = list_entry( - tb->tb_columns.prev, struct libscols_column, cl_columns); - - DBG(TAB, ul_debugobj(tb, " enlarge width (last column)")); - - if (!scols_column_is_right(col) && tb->termwidth - width > 0) { - col->width += tb->termwidth - width; - width = tb->termwidth; - } - } - } - - /* bad, we have to reduce output width, this is done in three stages: - * - * 1) trunc relative with trunc flag if the column width is greater than - * expected column width (it means "width_hint * terminal_width"). - * - * 2) trunc all with trunc flag - * - * 3) trunc relative without trunc flag - * - * Note that SCOLS_FL_WRAP (if no custom wrap function is specified) is - * interpreted as SCOLS_FL_TRUNC. - */ - for (stage = 1; width > tb->termwidth && stage <= 3; ) { - size_t org_width = width; - - DBG(TAB, ul_debugobj(tb, " reduce width - #%d stage (current=%zu, wanted=%zu)", - stage, width, tb->termwidth)); - - scols_reset_iter(&itr, SCOLS_ITER_FORWARD); - while (scols_table_next_column(tb, &itr, &cl) == 0) { - - int trunc_flag = 0; - - DBG(TAB, ul_debugobj(cl, " checking %s (width=%zu, treeart=%zu)", - cl->header.data, cl->width, cl->width_treeart)); - if (scols_column_is_hidden(cl)) - continue; - if (width <= tb->termwidth) - break; - - /* never truncate if already minimal width */ - if (cl->width == cl->width_min) - continue; - - /* never truncate the tree */ - if (scols_column_is_tree(cl) && width <= cl->width_treeart) - continue; - - /* nothing to truncate */ - if (cl->width == 0 || width == 0) - continue; - - trunc_flag = scols_column_is_trunc(cl) - || (scols_column_is_wrap(cl) && !scols_column_is_customwrap(cl)); - - switch (stage) { - /* #1 stage - trunc relative with TRUNC flag */ - case 1: - if (!trunc_flag) /* ignore: missing flag */ - break; - if (cl->width_hint <= 0 || cl->width_hint >= 1) /* ignore: no relative */ - break; - if (cl->width < (size_t) (cl->width_hint * tb->termwidth)) /* ignore: smaller than expected width */ - break; - - DBG(TAB, ul_debugobj(tb, " reducing (relative with flag)")); - cl->width--; - width--; - break; - - /* #2 stage - trunc all with TRUNC flag */ - case 2: - if (!trunc_flag) /* ignore: missing flag */ - break; - - DBG(TAB, ul_debugobj(tb, " reducing (all with flag)")); - cl->width--; - width--; - break; - - /* #3 stage - trunc relative without flag */ - case 3: - if (cl->width_hint <= 0 || cl->width_hint >= 1) /* ignore: no relative */ - break; - - DBG(TAB, ul_debugobj(tb, " reducing (relative without flag)")); - cl->width--; - width--; - break; - } - - /* hide zero width columns */ - if (cl->width == 0) - cl->flags |= SCOLS_FL_HIDDEN; - } - - /* the current stage is without effect, go to the next */ - if (org_width == width) - stage++; - } - - /* ignore last column(s) or force last column to be truncated if - * nowrap mode enabled */ - if (tb->no_wrap && width > tb->termwidth) { - scols_reset_iter(&itr, SCOLS_ITER_BACKWARD); - while (scols_table_next_column(tb, &itr, &cl) == 0) { - - if (scols_column_is_hidden(cl)) - continue; - if (width <= tb->termwidth) - break; - if (width - cl->width < tb->termwidth) { - size_t r = width - tb->termwidth; - - cl->flags |= SCOLS_FL_TRUNC; - cl->width -= r; - width -= r; - } else { - cl->flags |= SCOLS_FL_HIDDEN; - width -= cl->width + colsepsz; - } - } - } -done: - DBG(TAB, ul_debugobj(tb, " final width: %zu (rc=%d)", width, rc)); - ON_DBG(TAB, dbg_columns(tb)); - - return rc; -} - static size_t strlen_line(struct libscols_line *ln) { size_t i, sz = 0; @@ -1381,7 +989,7 @@ static int initialize_printing(struct libscols_table *tb, struct libscols_buffer } if (tb->format == SCOLS_FMT_HUMAN) { - rc = recount_widths(tb, *buf); + rc = __scols_calculate(tb, *buf); if (rc != 0) goto err; } |