summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/tt.h14
-rw-r--r--lib/tt.c165
-rw-r--r--misc-utils/findmnt.c4
-rw-r--r--misc-utils/lsblk.c2
4 files changed, 136 insertions, 49 deletions
diff --git a/include/tt.h b/include/tt.h
index 1ae71337d..9b5f15a9c 100644
--- a/include/tt.h
+++ b/include/tt.h
@@ -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;
};
diff --git a/lib/tt.c b/lib/tt.c
index e458717e6..4ce027659 100644
--- 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;
diff --git a/misc-utils/findmnt.c b/misc-utils/findmnt.c
index 2c1b20c45..9c2b9fc6b 100644
--- a/misc-utils/findmnt.c
+++ b/misc-utils/findmnt.c
@@ -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") },
diff --git a/misc-utils/lsblk.c b/misc-utils/lsblk.c
index f8bf26590..4fd7189e2 100644
--- a/misc-utils/lsblk.c
+++ b/misc-utils/lsblk.c
@@ -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") },