]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libsmartcols: support multi-line cells based on line breaks
authorKarel Zak <kzak@redhat.com>
Tue, 6 Sep 2016 08:51:25 +0000 (10:51 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 6 Sep 2016 08:51:25 +0000 (10:51 +0200)
Now libsmartcols completely control when and how wrap long
lines/cells. This is sometimes user unfriendly and it would be nice to
support multi-line cells where wrap is based on \n (new line char).

This patch add new column flag SCOLS_FL_WRAPNL.

Signed-off-by: Karel Zak <kzak@redhat.com>
include/mbsalign.h
lib/mbsalign.c
libsmartcols/docs/libsmartcols-sections.txt
libsmartcols/samples/Makemodule.am
libsmartcols/src/column.c
libsmartcols/src/libsmartcols.h.in
libsmartcols/src/libsmartcols.sym
libsmartcols/src/table_print.c

index 74d25da11c872315474ec01b17ccf68961ef26e7..6bdb50d3f5b74a4654ff558ba1b27eb9849317e9 100644 (file)
@@ -54,7 +54,7 @@ extern size_t mbs_safe_nwidth(const char *buf, size_t bufsz, size_t *sz);
 extern size_t mbs_safe_width(const char *s);
 
 extern char *mbs_safe_encode(const char *s, size_t *width);
-extern char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf);
+extern char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf, const char *safechars);
 extern size_t mbs_safe_encode_size(size_t bytes);
 
 #endif /* UTIL_LINUX_MBSALIGN_H */
index 5c21ddeb44d5e07b9410ff99f78322d96d219b71..c017ed1b3d402d4fdad2b412738ccde2efb2f9ee 100644 (file)
@@ -107,12 +107,13 @@ size_t mbs_safe_width(const char *s)
 
 /*
  * Copy @s to @buf and replace control and non-printable chars with
- * \x?? hex sequence. The @width returns number of cells.
+ * \x?? hex sequence. The @width returns number of cells. The @safechars
+ * are not encoded.
  *
  * The @buf has to be big enough to store mbs_safe_encode_size(strlen(s)))
  * bytes.
  */
-char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf)
+char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf, const char *safechars)
 {
        const char *p = s;
        char *r;
@@ -129,6 +130,11 @@ char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf)
        *width = 0;
 
        while (p && *p) {
+               if (safechars && strchr(safechars, *p)) {
+                       *r++ = *p++;
+                       continue;
+               }
+
                if (iscntrl((unsigned char) *p)) {
                        sprintf(r, "\\x%02x", (unsigned char) *p);
                        r += 4;
@@ -208,7 +214,7 @@ char *mbs_safe_encode(const char *s, size_t *width)
        if (!buf)
                return NULL;
 
-       return mbs_safe_encode_to_buffer(s, width, buf);
+       return mbs_safe_encode_to_buffer(s, width, buf, NULL);
 }
 
 #ifdef HAVE_WIDECHAR
index 75ff0eb2c483be6ccd02b1ddc4ad4a5f7eda2e03..e752e7056799c1d33ebc24e2faded26e46d3359a 100644 (file)
@@ -29,6 +29,7 @@ scols_column_is_strict_width
 scols_column_is_tree
 scols_column_is_trunc
 scols_column_is_wrap
+scols_column_is_wrapnl
 scols_column_set_cmpfunc
 scols_column_set_color
 scols_column_set_flags
index 413da5e4870ac0f0288a36748288679031a19244..32cf8b70db8c102a315ccf6c948afccf85117120 100644 (file)
@@ -2,6 +2,7 @@
 check_PROGRAMS += \
        sample-scols-title \
        sample-scols-wrap \
+       sample-scols-wrapnl \
        sample-scols-continuous \
        sample-scols-maxout
 
@@ -24,6 +25,10 @@ sample_scols_wrap_SOURCES = libsmartcols/samples/wrap.c
 sample_scols_wrap_LDADD = $(sample_scols_ldadd)
 sample_scols_wrap_CFLAGS = $(sample_scols_cflags)
 
+sample_scols_wrapnl_SOURCES = libsmartcols/samples/wrapnl.c
+sample_scols_wrapnl_LDADD = $(sample_scols_ldadd) libcommon.la
+sample_scols_wrapnl_CFLAGS = $(sample_scols_cflags)
+
 sample_scols_continuous_SOURCES = libsmartcols/samples/continuous.c
 sample_scols_continuous_LDADD = $(sample_scols_ldadd) libcommon.la
 sample_scols_continuous_CFLAGS = $(sample_scols_cflags)
index a49d3de5c50049e884d28eb7974f12ab9e2c6fd3..3d4017fdc28abdf7db0be96e17108b8f69ae275e 100644 (file)
@@ -356,3 +356,19 @@ int scols_column_is_wrap(struct libscols_column *cl)
                return -EINVAL;
        return cl->flags & SCOLS_FL_WRAP;
 }
+/**
+ * scols_column_is_wrapnl:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Gets the value of @cl's flag wrap.
+ *
+ * Returns: wrapnl flag value, negative value in case of an error.
+ *
+ * Since: 2.29
+ */
+int scols_column_is_wrapnl(struct libscols_column *cl)
+{
+       if (!cl)
+               return -EINVAL;
+       return cl->flags & SCOLS_FL_WRAPNL;
+}
index b2a750f1b13b9ba67f77295073c7e9039f5295fd..02867e2f5dfd981307ff8a071e499d46aef579a5 100644 (file)
@@ -85,6 +85,7 @@ enum {
        SCOLS_FL_NOEXTREMES  = (1 << 4),   /* ignore extreme fields when count column width*/
        SCOLS_FL_HIDDEN      = (1 << 5),   /* maintain data, but don't print */
        SCOLS_FL_WRAP        = (1 << 6),   /* wrap long lines to multi-line cells */
+       SCOLS_FL_WRAPNL      = (1 << 7)    /* wrap based on '\n' char */
 };
 
 /*
@@ -144,6 +145,7 @@ extern int scols_column_is_strict_width(struct libscols_column *cl);
 extern int scols_column_is_hidden(struct libscols_column *cl);
 extern int scols_column_is_noextremes(struct libscols_column *cl);
 extern int scols_column_is_wrap(struct libscols_column *cl);
+extern int scols_column_is_wrapnl(struct libscols_column *cl);
 
 extern int scols_column_set_flags(struct libscols_column *cl, int flags);
 extern int scols_column_get_flags(struct libscols_column *cl);
index 862262c8cb5565007e773c1a20e818e8cc1bbd99..9a4997dd866088c6f8f3c44e4d0ae9d0af5e1b7e 100644 (file)
@@ -136,3 +136,8 @@ global:
        scols_table_print_range_to_string;
        scols_table_enable_nolinesep;
 } SMARTCOLS_2.27;
+
+SMARTCOLS_2.29 {
+global:
+       scols_column_is_wrapnl;
+} SMARTCOLS_2.28;
index d625f8148609dae9a12b76335d6bee68594a2216..4d902b1d6a6cf4b559c63bf01b4f88e131c01308 100644 (file)
@@ -113,7 +113,8 @@ static char *buffer_get_data(struct libscols_buffer *buf)
 }
 
 /* encode data by mbs_safe_encode() to avoid control and non-printable chars */
-static char *buffer_get_safe_data(struct libscols_buffer *buf, size_t *cells)
+static char *buffer_get_safe_data(struct libscols_buffer *buf, size_t *cells,
+                                 const char *safechars)
 {
        char *data = buffer_get_data(buf);
        char *res = NULL;
@@ -127,7 +128,7 @@ static char *buffer_get_safe_data(struct libscols_buffer *buf, size_t *cells)
                        goto nothing;
        }
 
-       res = mbs_safe_encode_to_buffer(data, cells, buf->encdata);
+       res = mbs_safe_encode_to_buffer(data, cells, buf->encdata, safechars);
        if (!res || !*cells || *cells == (size_t) -1)
                goto nothing;
        return res;
@@ -234,7 +235,7 @@ static void print_empty_cell(struct libscols_table *tb,
                                line_ascii_art_to_buffer(tb, ln, art);
                                if (!list_empty(&ln->ln_branch) && has_pending_data(tb))
                                        buffer_append_data(art, tb->symbols->vert);
-                               data = buffer_get_safe_data(art, &len_pad);
+                               data = buffer_get_safe_data(art, &len_pad, NULL);
                                if (data && len_pad)
                                        fputs(data, tb->out);
                                free_buffer(art);
@@ -242,8 +243,11 @@ static void print_empty_cell(struct libscols_table *tb,
                }
        }
        /* fill rest of cell with space */
-       for(; len_pad <= cl->width; ++len_pad)
+       for(; len_pad < cl->width; ++len_pad)
                fputc(' ', tb->out);
+
+       if (!is_last_column(cl))
+               fputs(colsep(tb), tb->out);
 }
 
 
@@ -350,6 +354,7 @@ static int print_pending_data(
        size_t width = cl->width, bytes;
        size_t len = width, i;
        char *data;
+       char *wrapnl = NULL;
 
        if (!cl->pending_data)
                return 0;
@@ -359,7 +364,16 @@ static int print_pending_data(
        data = strdup(cl->pending_data);
        if (!data)
                goto err;
-       bytes = mbs_truncate(data, &len);
+
+       if (scols_column_is_wrapnl(cl) && (wrapnl = strchr(data, '\n'))) {
+               *wrapnl = '\0';
+               wrapnl++;
+               bytes = wrapnl - data;
+
+               len = mbs_safe_nwidth(data, bytes, NULL);
+       } else
+               bytes = mbs_truncate(data, &len);
+
        if (bytes == (size_t) -1)
                goto err;
 
@@ -375,10 +389,9 @@ static int print_pending_data(
        for (i = len; i < width; i++)
                fputc(' ', tb->out);            /* padding */
 
-       if (is_last_column(cl))
-               return 0;
+       if (!is_last_column(cl))
+               fputs(colsep(tb), tb->out);     /* columns separator */
 
-       fputs(colsep(tb), tb->out);             /* columns separator */
        return 0;
 err:
        free(data);
@@ -393,7 +406,7 @@ static int print_data(struct libscols_table *tb,
 {
        size_t len = 0, i, width, bytes;
        const char *color = NULL;
-       char *data;
+       char *data, *wrapnl;
 
        assert(tb);
        assert(cl);
@@ -437,18 +450,31 @@ static int print_data(struct libscols_table *tb,
 
        color = get_cell_color(tb, cl, ln, ce);
 
-       /* encode, note that 'len' and 'width' are number of cells, not bytes */
-       data = buffer_get_safe_data(buf, &len);
+       /* Encode. Note that 'len' and 'width' are number of cells, not bytes.
+        * For the columns with WRAPNL we mark \n as a safe char.
+        */
+       data = buffer_get_safe_data(buf, &len,
+                       scols_column_is_wrapnl(cl) ? "\n" : NULL);
        if (!data)
                data = "";
-       width = cl->width;
        bytes = strlen(data);
+       width = cl->width;
+
+       /* multi-line cell based on '\n' */
+       if (*data && scols_column_is_wrapnl(cl) && (wrapnl = strchr(data, '\n'))) {
+               *wrapnl = '\0';
+               wrapnl++;
+               set_pending_data(cl, wrapnl, bytes - (wrapnl - data));
+               bytes = wrapnl - data;
+               len = mbs_safe_nwidth(data, bytes, NULL);
+       }
 
        if (is_last_column(cl)
            && len < width
            && !scols_table_is_maxout(tb)
            && !scols_column_is_right(cl)
-           && !scols_column_is_wrap(cl))
+           && !scols_column_is_wrap(cl)
+           && !scols_column_is_wrapnl(cl))
                width = len;
 
        /* truncate data */
@@ -724,7 +750,7 @@ static int print_title(struct libscols_table *tb)
                goto done;
        }
 
-       if (!mbs_safe_encode_to_buffer(tb->title.data, &bufsz, buf) ||
+       if (!mbs_safe_encode_to_buffer(tb->title.data, &bufsz, buf, NULL) ||
            !bufsz || bufsz == (size_t) -1) {
                rc = -EINVAL;
                goto done;
@@ -941,6 +967,29 @@ static void dbg_columns(struct libscols_table *tb)
                dbg_column(tb, cl);
 }
 
+/* count the maximal size of \n terminated chunk in the @data
+ * for example for "AAA\nBBBB\nXX" the wrap size is 4 ('BBBB').
+ */
+static size_t count_wrapnl_size(const char *data)
+{
+       size_t sum = 0;
+
+       while (data && *data) {
+               const char *p = data;
+
+               p = strchr(data, '\n');
+               if (p) {
+                       size_t sz = mbs_safe_nwidth(data, p - data, NULL);
+
+                       sum = max(sum, sz);
+                       p++;
+               }
+               data = p;;
+       }
+
+       return sum;
+}
+
 /*
  * This function counts column width.
  *
@@ -985,7 +1034,13 @@ static int count_column_width(struct libscols_table *tb,
                        goto done;
 
                data = buffer_get_data(buf);
-               len = data ? mbs_safe_width(data) : 0;
+
+               if (!data)
+                       len = 0;
+               else if (scols_column_is_wrapnl(cl))
+                       len = count_wrapnl_size(data);
+               else
+                       len = mbs_safe_width(data);
 
                if (len == (size_t) -1)         /* ignore broken multibyte strings */
                        len = 0;