]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libsmartcols: move width calculation to separate file
authorKarel Zak <kzak@redhat.com>
Thu, 25 Oct 2018 14:01:23 +0000 (16:01 +0200)
committerKarel Zak <kzak@redhat.com>
Fri, 7 Dec 2018 11:33:34 +0000 (12:33 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
libsmartcols/src/Makemodule.am
libsmartcols/src/calculate.c [new file with mode: 0644]
libsmartcols/src/print.c
libsmartcols/src/smartcolsP.h

index a916ce1b3002d1a7b3b8cba165a9744332f8a811..3d18180f44ce051a758af681f021bee17920145b 100644 (file)
@@ -18,6 +18,7 @@ libsmartcols_la_SOURCES= \
        libsmartcols/src/print.c \
        libsmartcols/src/version.c \
        libsmartcols/src/buffer.c \
+       libsmartcols/src/calculate.c \
        libsmartcols/src/init.c
 
 libsmartcols_la_LIBADD = $(LDADD) libcommon.la
diff --git a/libsmartcols/src/calculate.c b/libsmartcols/src/calculate.c
new file mode 100644 (file)
index 0000000..8dd65a2
--- /dev/null
@@ -0,0 +1,391 @@
+#include "smartcolsP.h"
+#include "mbsalign.h"
+
+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...
+ */
+int __scols_calculate(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;
+}
index 2c024ca5ad509a713328857fa2bccf8792efb729..7e56f466ec86f02ae0ad2464ccf5e11587e8d92a 100644 (file)
@@ -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;
        }
index 6fa739045001f151fab19ffe5bb02380bf6432c4..94a2bc242c103137f479ab4aa356bbe3e7b27313 100644 (file)
@@ -115,6 +115,9 @@ struct libscols_column {
        struct libscols_table   *table;
 };
 
+#define colsep(tb)     ((tb)->colsep ? (tb)->colsep : " ")
+#define linesep(tb)    ((tb)->linesep ? (tb)->linesep : "\n")
+
 /*
  * Table line
  */
@@ -214,6 +217,8 @@ static inline int scols_iter_is_last(const struct libscols_iter *itr)
        return itr->p == itr->head;
 }
 
+
+
 /*
  * buffer.c
  */
@@ -232,6 +237,18 @@ extern char *buffer_get_safe_data(struct libscols_table *tb,
                                  const char *safechars);
 extern size_t buffer_get_safe_art_size(struct libscols_buffer *buf);
 
+/*
+ * calculate.c
+ */
+extern int __scols_calculate(struct libscols_table *tb, struct libscols_buffer *buf);
+
+/*
+ * print.c
+ */
+extern int __cell_to_buffer(struct libscols_table *tb,
+                          struct libscols_line *ln,
+                          struct libscols_column *cl,
+                          struct libscols_buffer *buf);
 
 static inline int is_last_child(struct libscols_line *ln)
 {