From cbe3e495357308177ca12e07996217ea663cbf78 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 24 Feb 2016 12:34:37 +0100 Subject: [PATCH] libsmartcols: fix relative column width for maxout Signed-off-by: Karel Zak --- libsmartcols/samples/continuous.c | 7 ++-- libsmartcols/src/column.c | 2 +- libsmartcols/src/table.c | 12 +++--- libsmartcols/src/table_print.c | 70 +++++++++++++++++++------------ 4 files changed, 56 insertions(+), 35 deletions(-) diff --git a/libsmartcols/samples/continuous.c b/libsmartcols/samples/continuous.c index 2fe720e2f..02efd5de9 100644 --- a/libsmartcols/samples/continuous.c +++ b/libsmartcols/samples/continuous.c @@ -30,11 +30,12 @@ static double time_diff(struct timeval *a, struct timeval *b) /* add columns to the @tb */ static void setup_columns(struct libscols_table *tb) { - if (!scols_table_new_column(tb, "#NUM", 0, SCOLS_FL_RIGHT)) + scols_table_enable_maxout(tb, 1); + if (!scols_table_new_column(tb, "#NUM", 0.1, SCOLS_FL_RIGHT)) goto fail; - if (!scols_table_new_column(tb, "DATA", 0, 0)) + if (!scols_table_new_column(tb, "DATA", 0.7, 0)) goto fail; - if (!scols_table_new_column(tb, "TIME", 0, 0)) + if (!scols_table_new_column(tb, "TIME", 0.2, 0)) goto fail; return; fail: diff --git a/libsmartcols/src/column.c b/libsmartcols/src/column.c index 55c24da22..5e7050192 100644 --- a/libsmartcols/src/column.c +++ b/libsmartcols/src/column.c @@ -119,7 +119,7 @@ err: * @cl: a pointer to a struct libscols_column instance * @whint: a width hint * - * Sets the width hint of column @cl to @whint. + * Sets the width hint of column @cl to @whint. See scols_table_new_column(). * * Returns: 0, a negative value in case of an error. */ diff --git a/libsmartcols/src/table.c b/libsmartcols/src/table.c index cc19e4ab2..d4261c067 100644 --- a/libsmartcols/src/table.c +++ b/libsmartcols/src/table.c @@ -233,17 +233,19 @@ int scols_table_remove_columns(struct libscols_table *tb) * scols_column_set_....(cl, ...); * scols_table_add_column(tb, cl); * - * The column width is possible to define by three ways: + * The column width is possible to define by: * * @whint = 0..1 : relative width, percent of terminal width * * @whint = 1..N : absolute width, empty column will be truncated to - * the column header width + * the column header width if no specified STRICTWIDTH flag * - * @whint = 1..N + * Note that if table has disabled "maxout" flag (disabled by default) than + * relative width is used as a hint only. It's possible that column will be + * narrow if the specified size is too large for column data. * - * The column is necessary to address by - * sequential number. The first defined column has the colnum = 0. For example: + * The column is necessary to address by sequential number. The first defined + * column has the colnum = 0. For example: * * scols_table_new_column(tab, "FOO", 0.5, 0); // colnum = 0 * scols_table_new_column(tab, "BAR", 0.5, 0); // colnum = 1 diff --git a/libsmartcols/src/table_print.c b/libsmartcols/src/table_print.c index d6622be64..e37f27761 100644 --- a/libsmartcols/src/table_print.c +++ b/libsmartcols/src/table_print.c @@ -177,9 +177,9 @@ static int line_ascii_art_to_buffer(struct libscols_table *tb, return buffer_append_data(buf, art); } -static int is_last_column(struct libscols_table *tb, struct libscols_column *cl) +static int is_last_column(struct libscols_column *cl) { - int rc = list_entry_is_last(&cl->cl_columns, &tb->tb_columns); + int rc = list_entry_is_last(&cl->cl_columns, &cl->table->tb_columns); struct libscols_column *next; if (rc) @@ -378,7 +378,7 @@ static int print_pending_data( for (i = len; i < width; i++) fputc(' ', tb->out); /* padding */ - if (is_last_column(tb, cl)) + if (is_last_column(cl)) return 0; fputs(colsep(tb), tb->out); /* columns separator */ @@ -412,14 +412,14 @@ static int print_data(struct libscols_table *tb, switch (tb->format) { case SCOLS_FMT_RAW: fputs_nonblank(data, tb->out); - if (!is_last_column(tb, cl)) + if (!is_last_column(cl)) fputs(colsep(tb), tb->out); return 0; case SCOLS_FMT_EXPORT: fprintf(tb->out, "%s=", scols_cell_get_data(&cl->header)); fputs_quoted(data, tb->out); - if (!is_last_column(tb, cl)) + if (!is_last_column(cl)) fputs(colsep(tb), tb->out); return 0; @@ -430,7 +430,7 @@ static int print_data(struct libscols_table *tb, fputs("null", tb->out); else fputs_quoted(data, tb->out); - if (!is_last_column(tb, cl)) + if (!is_last_column(cl)) fputs(", ", tb->out); return 0; @@ -447,7 +447,7 @@ static int print_data(struct libscols_table *tb, width = cl->width; bytes = strlen(data); - if (is_last_column(tb, cl) + if (is_last_column(cl) && len < width && !scols_table_is_maxout(tb) && !scols_column_is_right(cl) @@ -505,7 +505,7 @@ static int print_data(struct libscols_table *tb, for (i = len; i < width; i++) fputc(' ', tb->out); /* padding */ - if (is_last_column(tb, cl)) + if (is_last_column(cl)) return 0; if (len > width && !scols_column_is_trunc(cl)) @@ -957,6 +957,16 @@ static int count_column_width(struct libscols_table *tb, cl->width = 0; + + if (cl->width_min) { + if (cl->width_hint < 1 && scols_table_is_maxout(tb)) + cl->width_min = (size_t) (cl->width_hint * tb->termwidth) - (is_last_column(cl) ? 0 : 1); + 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); + } + } + scols_reset_iter(&itr, SCOLS_ITER_FORWARD); while (scols_table_next_line(tb, &itr, &ln) == 0) { size_t len; @@ -988,20 +998,15 @@ static int count_column_width(struct libscols_table *tb, if (count && cl->width_avg == 0) { cl->width_avg = sum / count; - if (cl->width_max > cl->width_avg * 2) cl->is_extreme = 1; } - /* check and set minimal column width */ - if (scols_cell_get_data(&cl->header)) - cl->width_min = mbs_safe_width(scols_cell_get_data(&cl->header)); - /* enlarge to minimal width */ if (cl->width < cl->width_min && !scols_column_is_strict_width(cl)) cl->width = cl->width_min; - /* use relative size for large columns */ + /* 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) @@ -1009,7 +1014,6 @@ static int count_column_width(struct libscols_table *tb, done: ON_DBG(COL, dbg_column(tb, cl)); - DBG(COL, ul_debugobj(cl, "column width=%zu, rc=%d", cl->width, rc)); return rc; } @@ -1020,7 +1024,7 @@ 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 */ + size_t width = 0, width_min = 0; /* output width */ int trunc_only, rc = 0; int extremes = 0; @@ -1035,18 +1039,32 @@ static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf if (rc) goto done; - width += cl->width + (is_last_column(tb, cl) ? 0 : 1); /* separator for non-last column */ + width += cl->width + (is_last_column(cl) ? 0 : 1); /* separator for non-last column */ + width_min += cl->width_min + (is_last_column(cl) ? 0 : 1); extremes += cl->is_extreme; } if (!tb->is_term) { - DBG(TAB, ul_debugobj(tb, " non-terminal output")); + 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) { + 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)")); + 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) { @@ -1069,7 +1087,7 @@ static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf if (width < tb->termwidth) { if (extremes) { - DBG(TAB, ul_debugobj(tb, " enlarge width (extreme columns)")); + DBG(TAB, ul_debugobj(tb, " enlarge width (extreme columns)")); /* enlarge the first extreme column */ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); @@ -1098,7 +1116,7 @@ static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf } if (width < tb->termwidth && scols_table_is_maxout(tb)) { - DBG(TAB, ul_debugobj(tb, " enlarge width (max-out)")); + DBG(TAB, ul_debugobj(tb, " enlarge width (max-out)")); /* try enlarging all columns */ while (width < tb->termwidth) { @@ -1115,7 +1133,7 @@ static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf struct libscols_column *col = list_entry( tb->tb_columns.prev, struct libscols_column, cl_columns); - DBG(TAB, ul_debugobj(tb, " enlarge width (last column)")); + DBG(TAB, ul_debugobj(tb, " enlarge width (last column)")); if (!scols_column_is_right(col) && tb->termwidth - width > 0) { col->width += tb->termwidth - width; @@ -1132,7 +1150,7 @@ static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf while (width > tb->termwidth) { size_t org = width; - DBG(TAB, ul_debugobj(tb, " reduce width (current=%zu, " + DBG(TAB, ul_debugobj(tb, " reduce width (current=%zu, " "wanted=%zu, mode=%s)", width, tb->termwidth, trunc_only ? "trunc-only" : "all-relative")); @@ -1140,7 +1158,7 @@ static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf scols_reset_iter(&itr, SCOLS_ITER_FORWARD); while (scols_table_next_column(tb, &itr, &cl) == 0) { - DBG(TAB, ul_debugobj(cl, " checking %s (width=%zu, treeart=%zu)", + DBG(TAB, ul_debugobj(cl, " checking %s (width=%zu, treeart=%zu)", cl->header.data, cl->width, cl->width_treeart)); if (width <= tb->termwidth) @@ -1154,7 +1172,7 @@ static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf if (cl->width == cl->width_min) continue; - DBG(TAB, ul_debugobj(tb, " tring to reduce: %s (width=%zu)", cl->header.data, cl->width)); + DBG(TAB, ul_debugobj(tb, " tring to reduce: %s (width=%zu)", cl->header.data, cl->width)); /* truncate column with relative sizes */ if (cl->width_hint < 1 && cl->width > 0 && width > 0 && @@ -1199,7 +1217,7 @@ static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf } } done: - DBG(TAB, ul_debugobj(tb, " final width: %zu (rc=%d)", width, rc)); + DBG(TAB, ul_debugobj(tb, " final width: %zu (rc=%d)", width, rc)); ON_DBG(TAB, dbg_columns(tb)); return rc;