]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lib,tt: add TT_FL_NOEXTREMES
authorKarel Zak <kzak@redhat.com>
Thu, 10 Nov 2011 01:02:38 +0000 (02:02 +0100)
committerKarel Zak <kzak@redhat.com>
Thu, 10 Nov 2011 11:39:02 +0000 (12:39 +0100)
If you mark a column with TT_FL_NOEXTREMES flag then extremely
large fields will no have effect to column width. Foe example:

 without the TT_FL_NOEXTREMES flag for the 'AAA' column:

 AAA         BBB CCC  DDD
 aa          bbb ccc  ddd
 aaaaaaaaaaa  bb ccc  ddd
 aa           bb ccc  ddd
 aa           bb ccc  ddd

 with the flags:

 AAA  BBB CCC  DDD
 aa   bbb ccc  dddddddddd
 aaaaaaaaaaa
       bb ccc  dddddddd
 aa    bb ccc  dddddd
 aa    bb ccc  ddddddddd

Signed-off-by: Karel Zak <kzak@redhat.com>
include/tt.h
lib/tt.c
misc-utils/findmnt.c
misc-utils/lsblk.c

index 1ae71337dfdaaa7a4e59ae6bc42ed2541255e152..9b5f15a9c48abf9331ecd85b90abaf175c03809d 100644 (file)
@@ -23,10 +23,11 @@ enum {
        /*
         * Column flags
         */
-       TT_FL_TRUNC       = (1 << 5),
-       TT_FL_TREE        = (1 << 6),
-       TT_FL_RIGHT       = (1 << 7),
-       TT_FL_STRICTWIDTH = (1 << 8)
+       TT_FL_TRUNC       = (1 << 5),   /* truncate fields data if necessary */
+       TT_FL_TREE        = (1 << 6),   /* use tree "ascii art" */
+       TT_FL_RIGHT       = (1 << 7),   /* align to the right */
+       TT_FL_STRICTWIDTH = (1 << 8),   /* don't reduce width if column is empty */
+       TT_FL_NOEXTREMES  = (1 << 9)    /* ignore extreme fields when count column width*/
 };
 
 struct tt {
@@ -46,10 +47,13 @@ struct tt_column {
        size_t  seqnum;
 
        size_t  width;          /* real column width */
-       size_t  width_min;      /* minimal width (width of header) */
+       size_t  width_min;      /* minimal width (usually header width) */
+       size_t  width_max;      /* maximal width */
+       size_t  width_avg;      /* average width, used to detect extreme fields */
        double  width_hint;     /* hint (N < 1 is in percent of termwidth) */
 
        int     flags;
+       int     is_extreme;
 
        struct list_head        cl_columns;
 };
index e458717e6924dde8a057c5aec079e9237da92f8e..4ce0276596aa5e800e96dee79df4de5aab8cd9c7 100644 (file)
--- a/lib/tt.c
+++ b/lib/tt.c
@@ -326,6 +326,10 @@ static char *line_get_data(struct tt_line *ln, struct tt_column *cl,
                buf[bufsz - 1] = '\0';
                return buf;
        }
+
+       /*
+        * Tree stuff
+        */
        if (ln->parent) {
                p = line_get_ascii_art(ln->parent, buf, &bufsz);
                if (!p)
@@ -344,63 +348,138 @@ static char *line_get_data(struct tt_line *ln, struct tt_column *cl,
        return buf;
 }
 
-static void recount_widths(struct tt *tb, char *buf, size_t bufsz)
+/*
+ * This function counts column width.
+ *
+ * For the TT_FL_NOEXTREMES columns is possible to call this function two
+ * times.  The first pass counts width and average width. If the column
+ * contains too large fields (width greater than 2 * average) then the column
+ * is marked as "extreme". In the second pass all extreme fields are ignored
+ * and column width is counted from non-extreme fields only.
+ */
+static size_t count_column_width(struct tt *tb, struct tt_column *cl,
+                                char *buf, size_t bufsz)
 {
-       struct list_head *p;
-       size_t width = 0;
-       int trunc_only;
+       struct list_head *lp;
+       int count = 0;
+       size_t sum = 0;
 
-       /* set width according to the size of data
-        */
-       list_for_each(p, &tb->tb_columns) {
-               struct tt_column *cl =
-                               list_entry(p, struct tt_column, cl_columns);
-               struct list_head *lp;
+       cl->width = 0;
 
-               list_for_each(lp, &tb->tb_lines) {
-                       struct tt_line *ln =
-                               list_entry(lp, struct tt_line, ln_lines);
+       list_for_each(lp, &tb->tb_lines) {
+               struct tt_line *ln = list_entry(lp, struct tt_line, ln_lines);
+               char *data = line_get_data(ln, cl, buf, bufsz);
+               size_t len = data ? mbs_width(data) : 0;
 
-                       char *data = line_get_data(ln, cl, buf, bufsz);
-                       size_t len = data ? mbs_width(data) : 0;
+               if (len > cl->width_max)
+                       cl->width_max = len;
 
-                       if (cl->width < len)
-                               cl->width = len;
+               if (cl->is_extreme && len > cl->width_avg * 2)
+                       continue;
+               else if (cl->flags & TT_FL_NOEXTREMES) {
+                       sum += len;
+                       count++;
                }
+               if (len > cl->width)
+                       cl->width = len;
+       }
+
+       if (count && cl->width_avg == 0) {
+               cl->width_avg = sum / count;
+
+               if (cl->width_max > cl->width_avg * 2)
+                       cl->is_extreme = 1;
        }
 
-       /* set minimal width (= size of column header)
+       /* check and set minimal column width */
+       if (cl->name)
+               cl->width_min = mbs_width(cl->name);
+
+       /* enlarge to minimal width */
+       if (cl->width < cl->width_min && !(cl->flags & TT_FL_STRICTWIDTH))
+               cl->width = cl->width_min;
+
+       /* use relative 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;
+}
+
+/*
+ * This is core of the tt_* voodo...
+ */
+static void recount_widths(struct tt *tb, char *buf, size_t bufsz)
+{
+       struct list_head *p;
+       size_t width = 0;       /* output width */
+       int trunc_only;
+       int extremes = 0;
+
+       /* set basic columns width
         */
        list_for_each(p, &tb->tb_columns) {
                struct tt_column *cl =
                                list_entry(p, struct tt_column, cl_columns);
 
-               if (cl->name)
-                       cl->width_min = mbs_width(cl->name);
+               count_column_width(tb, cl, buf, bufsz);
+               width += cl->width + (is_last_column(tb, cl) ? 0 : 1);
+               extremes += cl->is_extreme;
+       }
 
-               if (cl->width < cl->width_min &&
-                   !(cl->flags & TT_FL_STRICTWIDTH))
-                       cl->width = cl->width_min;
+       /* reduce columns with extreme fields
+        */
+       if (width > tb->termwidth && extremes) {
+               list_for_each(p, &tb->tb_columns) {
+                       struct tt_column *cl = list_entry(p, struct tt_column, cl_columns);
+                       size_t org_width;
 
-               else if (cl->width_hint >= 1 &&
-                        cl->width < (size_t) cl->width_hint &&
-                        cl->width_min < (size_t) cl->width_hint)
+                       if (!cl->is_extreme)
+                               continue;
 
-                       cl->width = (size_t) cl->width_hint;
+                       org_width = cl->width;
+                       count_column_width(tb, cl, buf, bufsz);
 
-               width += cl->width + (is_last_column(tb, cl) ? 0 : 1);
+                       if (org_width > cl->width)
+                               width -= org_width - cl->width;
+                       else
+                               extremes--;     /* hmm... nothing reduced */
+               }
        }
 
-       if (width == tb->termwidth)
-               goto leave;
        if (width < tb->termwidth) {
-               /* cool, use the extra space for the last column */
-               struct tt_column *cl = list_entry(
-                       tb->tb_columns.prev, struct tt_column, cl_columns);
-
-               if (!(cl->flags & TT_FL_RIGHT) && tb->termwidth - width > 0)
-                       cl->width += tb->termwidth - width;
-               goto leave;
+               /* cool, use the extra space for the extreme columns or/and last column
+                */
+               if (extremes) {
+                       /* enlarge the first extreme column */
+                       list_for_each(p, &tb->tb_columns) {
+                               struct tt_column *cl =
+                                       list_entry(p, struct tt_column, cl_columns);
+                               size_t add;
+
+                               if (!cl->is_extreme)
+                                       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) {
+                       /* enalarge the last column */
+                       struct tt_column *cl = list_entry(
+                               tb->tb_columns.prev, struct tt_column, cl_columns);
+
+                       if (!(cl->flags & TT_FL_RIGHT) && tb->termwidth - width > 0) {
+                               cl->width += tb->termwidth - width;
+                               width = tb->termwidth;
+                       }
+               }
        }
 
        /* bad, we have to reduce output width, this is done in two steps:
@@ -408,7 +487,7 @@ static void recount_widths(struct tt *tb, char *buf, size_t bufsz)
         * 2) reduce columns with a relative width without truncate flag
         */
        trunc_only = 1;
-       while(width > tb->termwidth) {
+       while (width > tb->termwidth) {
                size_t org = width;
 
                list_for_each(p, &tb->tb_columns) {
@@ -438,6 +517,7 @@ static void recount_widths(struct tt *tb, char *buf, size_t bufsz)
                                cl->width--;
                                width--;
                        }
+
                }
                if (org == width) {
                        if (trunc_only)
@@ -446,7 +526,7 @@ static void recount_widths(struct tt *tb, char *buf, size_t bufsz)
                                break;
                }
        }
-leave:
+
 /*
        fprintf(stderr, "terminal: %d, output: %d\n", tb->termwidth, width);
 
@@ -454,10 +534,13 @@ leave:
                struct tt_column *cl =
                        list_entry(p, struct tt_column, cl_columns);
 
-               fprintf(stderr, "width: %s=%zd [hint=%d]\n",
+               fprintf(stderr, "width: %s=%zd [hint=%d, avg=%zd, max=%zd, extreme=%s]\n",
                        cl->name, cl->width,
                        cl->width_hint > 1 ? (int) cl->width_hint :
-                                            (int) (cl->width_hint * tb->termwidth));
+                                            (int) (cl->width_hint * tb->termwidth),
+                       cl->width_avg,
+                       cl->width_max,
+                       cl->is_extreme ? "yes" : "not");
        }
 */
        return;
index 2c1b20c45b515ccd0611075eebc6368e3b6f795d..9c2b9fc6b7c79768926f0bd46ec11a4d673e2a3a 100644 (file)
@@ -80,8 +80,8 @@ struct colinfo {
 
 /* columns descriptions (don't use const, this is writable) */
 static struct colinfo infos[FINDMNT_NCOLUMNS] = {
-       [COL_SOURCE]       = { "SOURCE",       0.25, 0, N_("source device") },
-       [COL_TARGET]       = { "TARGET",       0.30, TT_FL_TREE, N_("mountpoint") },
+       [COL_SOURCE]       = { "SOURCE",       0.25, TT_FL_NOEXTREMES, N_("source device") },
+       [COL_TARGET]       = { "TARGET",       0.30, TT_FL_TREE | TT_FL_NOEXTREMES, N_("mountpoint") },
        [COL_FSTYPE]       = { "FSTYPE",       0.10, TT_FL_TRUNC, N_("filesystem type") },
        [COL_OPTIONS]      = { "OPTIONS",      0.10, TT_FL_TRUNC, N_("all mount options") },
        [COL_VFS_OPTIONS]  = { "VFS-OPTIONS",  0.20, TT_FL_TRUNC, N_("VFS specific mount options") },
index f8bf26590d5883b7b8cfc09a84a746efd78e05c1..4fd7189e220e96f40b0bb2906a269e29264c5b13 100644 (file)
@@ -100,7 +100,7 @@ struct colinfo {
 
 /* columns descriptions */
 static struct colinfo infos[] = {
-       [COL_NAME]   = { "NAME",    0.25, TT_FL_TREE, N_("device name") },
+       [COL_NAME]   = { "NAME",    0.25, TT_FL_TREE | TT_FL_NOEXTREMES, N_("device name") },
        [COL_KNAME]  = { "KNAME",   0.3, 0, N_("internal kernel device name") },
        [COL_MAJMIN] = { "MAJ:MIN", 6, 0, N_("major:minor device number") },
        [COL_FSTYPE] = { "FSTYPE",  0.1, TT_FL_TRUNC, N_("filesystem type") },