]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libsmartcols: support custom wrap and remove SCOLS_FL_WRAPNL
authorKarel Zak <kzak@redhat.com>
Mon, 26 Sep 2016 09:20:07 +0000 (11:20 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 26 Sep 2016 09:20:07 +0000 (11:20 +0200)
This new API provides full control on multi-line cells, you can wrap
text by new lines (build-in support) or by another way (after words,
commas, etc.) Changes:

* new scols_column_set_wrapfunc() sets pointers to two callback functions

   1/ chunksize() - returns largest data chunk size; used when we
                    calculate columns width
   2/ nextchunk() - terminate the current chunk and returns pointer to
                    the next; used when we print data

* remove SCOLS_FL_WRAPNL and add new functions scols_wrapnl_chunksize()
  and scols_wrapnl_nextchunk() to provide build-in functionality to
  wrap cells on \n

* remove scols_column_is_wrapnl() add scols_column_is_customwrap()
  (returns true if custom wrap functions are defined)

* add scols_column_set_safechars() and scols_column_get_safechars() to
  allow to control output encoding, safe chars are not encoded by \xFOO

* modify "fromfile" test code to use build-in scols_wrapnl_* callbacks
  for "wrapnl" tests

* add new function scols_column_get_table()

Signed-off-by: Karel Zak <kzak@redhat.com>
libsmartcols/docs/libsmartcols-sections.txt
libsmartcols/samples/fromfile.c
libsmartcols/src/column.c
libsmartcols/src/libsmartcols.h.in
libsmartcols/src/libsmartcols.sym
libsmartcols/src/smartcolsP.h
libsmartcols/src/table_print.c

index 12366bd34ba87436ec130381f49b7dbad96020d3..f05d45479e816aab78848ba7e4ba5c7aadfd524a 100644 (file)
@@ -21,7 +21,10 @@ libscols_column
 scols_column_get_color
 scols_column_get_flags
 scols_column_get_header
+scols_column_get_safechars;
+scols_column_get_table;
 scols_column_get_whint
+scols_column_is_customwrap;
 scols_column_is_hidden
 scols_column_is_noextremes
 scols_column_is_right
@@ -29,15 +32,18 @@ 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
+scols_column_set_safechars;
 scols_column_set_whint
+scols_column_set_wrapfunc;
 scols_copy_column
 scols_new_column
 scols_ref_column
 scols_unref_column
+scols_wrapnl_chunksize;
+scols_wrapnl_nextchunk;
 </SECTION>
 
 <SECTION>
index 6d4ee4aafe2448ae903751e5bc89e8a081fc135f..fcf01c74990fe17178b2e2a3054f1a036a90b17d 100644 (file)
@@ -34,7 +34,7 @@ static const struct column_flag flags[] = {
        { "noextremes", SCOLS_FL_NOEXTREMES },
        { "hidden",     SCOLS_FL_HIDDEN },
        { "wrap",       SCOLS_FL_WRAP },
-       { "wrapnl",     SCOLS_FL_WRAPNL },
+       { "wrapnl",     SCOLS_FL_WRAP },
        { "none",       0 }
 };
 
@@ -101,6 +101,13 @@ static struct libscols_column *parse_column(FILE *f)
                        int flags = parse_column_flags(line);
                        if (scols_column_set_flags(cl, flags))
                                goto fail;
+                       if (strcmp(line, "wrapnl") == 0) {
+                               scols_column_set_wrapfunc(cl,
+                                               scols_wrapnl_chunksize,
+                                               scols_wrapnl_nextchunk,
+                                               NULL);
+                               scols_column_set_safechars(cl, "\n");
+                       }
                        break;
                }
                case 3: /* COLOR */
index 6f4ccc3bd1ca2f7e5b499535081e03e955fd6190..1e84a6363e70db4bcdc5087ba31c38a38a894cba 100644 (file)
@@ -22,6 +22,8 @@
 #include <string.h>
 #include <ctype.h>
 
+#include "mbsalign.h"
+
 #include "smartcolsP.h"
 
 /**
@@ -168,6 +170,17 @@ int scols_column_set_flags(struct libscols_column *cl, int flags)
        return 0;
 }
 
+/**
+ * scols_column_get_table:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Returns: pointer to the table where columns is used
+ */
+struct libscols_table *scols_column_get_table(struct libscols_column *cl)
+{
+       return cl->table;
+}
+
 /**
  * scols_column_get_flags:
  * @cl: a pointer to a struct libscols_column instance
@@ -227,6 +240,69 @@ const char *scols_column_get_color(const struct libscols_column *cl)
        return cl->color;
 }
 
+/**
+ * scols_wrapnl_nextchunk:
+ * @cl: a pointer to a struct libscols_column instance
+ * @data: string
+ * @userdata: any data or NULL
+ *
+ * This is build-in function for scols_column_set_wrapfunc(). This function
+ * terminates the current chunk by \0 and returns pointer to the begin of
+ * the next chunk. The chunks are based on \n.
+ *
+ * For example for data "AAA\nBBB\nCCC" the next chunk is "BBB".
+ *
+ * Returns: next chunk
+ */
+char *scols_wrapnl_nextchunk(const struct libscols_column *cl __attribute__((unused)),
+                       char *data,
+                       void *userdata __attribute__((unused)))
+{
+       char *p = data ? strchr(data, '\n') : NULL;
+
+       if (p) {
+               *p = '\0';
+               return p + 1;
+       }
+       return NULL;
+}
+
+/**
+ * scols_wrapnl_chunksize:
+ * @cl: a pointer to a struct libscols_column instance
+ * @data: string
+ *
+ * Analyzes @data and returns size of the largest chunk. The chunks are based
+ * on \n. For example for data "AAA\nBBB\nCCCC" the largest chunk size is 4.
+ *
+ * Note that the size has to be based on number of terminal cells rather than
+ * bytes to support multu-byte output.
+ *
+ * Returns: size of the largest chunk.
+ */
+size_t scols_wrapnl_chunksize(const struct libscols_column *cl __attribute__((unused)),
+               const char *data,
+               void *userdata __attribute__((unused)))
+{
+       size_t sum = 0;
+
+       while (data && *data) {
+               const char *p = data;
+               size_t sz;
+
+               p = strchr(data, '\n');
+               if (p) {
+                       sz = mbs_safe_nwidth(data, p - data, NULL);
+                       p++;
+               } else
+                       sz = mbs_safe_width(data);
+
+               sum = max(sum, sz);
+               data = p;;
+       }
+
+       return sum;
+}
 
 /**
  * scols_column_set_cmpfunc:
@@ -250,6 +326,66 @@ int scols_column_set_cmpfunc(struct libscols_column *cl,
        return 0;
 }
 
+/**
+ * scols_column_set_wrapfunc:
+ * @cl: a pointer to a struct libscols_column instance
+ * @wrap_chunksize: function to return size of the largest chink of data
+ * @wrap_nextchunk: function to return next zero terminated data
+ *
+ * Extends SCOLS_FL_WRAP and allows to set custom wrap function. The default
+ * is to wrap by column size, but you can create functions to wrap for example
+ * after \n or after words, etc.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_column_set_wrapfunc(struct libscols_column *cl,
+                       size_t (*wrap_chunksize)(const struct libscols_column *,
+                                                const char *,
+                                                void *),
+                       char * (*wrap_nextchunk)(const struct libscols_column *,
+                                                char *,
+                                                void *),
+                       void *data)
+{
+       if (!cl)
+               return -EINVAL;
+
+       cl->wrap_nextchunk = wrap_nextchunk;
+       cl->wrap_chunksize = wrap_chunksize;
+       cl->wrapfunc_data = data;
+       return 0;
+}
+
+/**
+ * scols_column_set_safechars:
+ * @cl: a pointer to a struct libscols_column instance
+ * @safe: safe characters (e.g. "\n\t")
+ *
+ * Use for bytes you don't want to encode on output. This is for example
+ * necessary if you want to use custom wrap function based on \n, in this case
+ * you have to set "\n" as a safe char.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_column_set_safechars(struct libscols_column *cl, const char *safe)
+{
+       if (!cl)
+               return -EINVAL;
+       cl->safechars = safe;
+       return 0;
+}
+
+/**
+ * scols_column_get_safechars:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Returns: safe chars
+ */
+const char *scols_column_get_safechars(const struct libscols_column *cl)
+{
+       return cl->safechars;
+}
+
 /**
  * scols_column_is_hidden:
  * @cl: a pointer to a struct libscols_column instance
@@ -340,16 +476,16 @@ int scols_column_is_wrap(const struct libscols_column *cl)
        return cl->flags & SCOLS_FL_WRAP ? 1 : 0;
 }
 /**
- * scols_column_is_wrapnl:
+ * scols_column_is_customwrap:
  * @cl: a pointer to a struct libscols_column instance
  *
- * Gets the value of @cl's flag wrap.
- *
  * Returns: 0 or 1
  *
  * Since: 2.29
  */
-int scols_column_is_wrapnl(const struct libscols_column *cl)
+int scols_column_is_customwrap(const struct libscols_column *cl)
 {
-       return cl->flags & SCOLS_FL_WRAPNL ? 1 : 0;
+       return (cl->flags & SCOLS_FL_WRAP)
+               && cl->wrap_chunksize
+               && cl->wrap_nextchunk ? 1 : 0;
 }
index 22cab64a1f4e168d902ebaf8abc81e598fe8c555..d6ae91f608592e567d746e6219d28e61691ea681 100644 (file)
@@ -84,8 +84,7 @@ enum {
        SCOLS_FL_STRICTWIDTH = (1 << 3),   /* don't reduce width if column is empty */
        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 */
+       SCOLS_FL_WRAP        = (1 << 6)    /* wrap long lines to multi-line cells */
 };
 
 /*
@@ -146,7 +145,10 @@ extern int scols_column_is_strict_width(const struct libscols_column *cl);
 extern int scols_column_is_hidden(const struct libscols_column *cl);
 extern int scols_column_is_noextremes(const struct libscols_column *cl);
 extern int scols_column_is_wrap(const struct libscols_column *cl);
-extern int scols_column_is_wrapnl(const struct libscols_column *cl);
+extern int scols_column_is_customwrap(const struct libscols_column *cl);
+
+extern int scols_column_set_safechars(struct libscols_column *cl, const char *safe);
+extern const char *scols_column_get_safechars(const struct libscols_column *cl);
 
 extern int scols_column_set_flags(struct libscols_column *cl, int flags);
 extern int scols_column_get_flags(const struct libscols_column *cl);
@@ -159,12 +161,23 @@ extern double scols_column_get_whint(const struct libscols_column *cl);
 extern struct libscols_cell *scols_column_get_header(struct libscols_column *cl);
 extern int scols_column_set_color(struct libscols_column *cl, const char *color);
 extern const char *scols_column_get_color(const struct libscols_column *cl);
+extern struct libscols_table *scols_column_get_table(struct libscols_column *cl);
 
 extern int scols_column_set_cmpfunc(struct libscols_column *cl,
                        int (*cmp)(struct libscols_cell *a,
                                   struct libscols_cell *b, void *),
                        void *data);
 
+extern int scols_column_set_wrapfunc(struct libscols_column *cl,
+                       size_t (*wrap_chunksize)(const struct libscols_column *,
+                                        const char *, void *),
+                       char * (*wrap_nextchunk)(const struct libscols_column *,
+                                        char *, void *),
+                       void *data);
+
+extern char *scols_wrapnl_nextchunk(const struct libscols_column *cl, char *data, void *userdata);
+extern size_t scols_wrapnl_chunksize(const struct libscols_column *cl, const char *data, void *userdata);
+
 /* line.c */
 extern struct libscols_line *scols_new_line(void);
 extern void scols_ref_line(struct libscols_line *ln);
index aca648b631a524678d74ed04202320502461eff6..d5c3674b87183e94e6163b001f0bfc9fe70215b9 100644 (file)
@@ -139,15 +139,21 @@ global:
 
 SMARTCOLS_2.29 {
 global:
-       scols_column_is_wrapnl;
+       scols_column_get_safechars;
+       scols_column_get_table;
+       scols_column_is_customwrap;
+       scols_column_set_safechars;
+       scols_column_set_wrapfunc;
        scols_symbols_set_cell_padding;
+       scols_table_get_name;
        scols_table_get_symbols;
        scols_table_get_termforce;
        scols_table_get_termwidth;
+       scols_table_is_nolinesep;
+       scols_table_is_nowrap;
        scols_table_set_default_symbols;
        scols_table_set_termforce;
        scols_table_set_termwidth;
-       scols_table_get_name;
-       scols_table_is_nowrap;
-       scols_table_is_nolinesep;
+       scols_wrapnl_chunksize;
+       scols_wrapnl_nextchunk;
 } SMARTCOLS_2.28;
index 8e8bd768ef07f07f866942f74b0e29277d50aff1..2f29c9f630ae2ade28bf8ec6e575619b2d80f110 100644 (file)
@@ -95,6 +95,14 @@ struct libscols_column {
                       void *);                 /* cells comparison function */
        void *cmpfunc_data;
 
+       size_t (*wrap_chunksize)(const struct libscols_column *,
+                       const char *, void *);
+       char *(*wrap_nextchunk)(const struct libscols_column *,
+                       char *, void *);
+       void *wrapfunc_data;
+
+       const char *safechars;  /* do not encode this bytes */
+
        struct libscols_cell    header;
        struct list_head        cl_columns;
 
index 5771111b3f84970be844f73bdc5211bf61f3d609..c73154ec6facba6354589d43936d9d07b7e666ab 100644 (file)
@@ -370,7 +370,7 @@ static int print_pending_data(
        size_t width = cl->width, bytes;
        size_t len = width, i;
        char *data;
-       char *wrapnl = NULL;
+       char *nextchunk = NULL;
 
        if (!cl->pending_data)
                return 0;
@@ -381,10 +381,9 @@ static int print_pending_data(
        if (!data)
                goto err;
 
-       if (scols_column_is_wrapnl(cl) && (wrapnl = strchr(data, '\n'))) {
-               *wrapnl = '\0';
-               wrapnl++;
-               bytes = wrapnl - data;
+       if (scols_column_is_customwrap(cl)
+           && (nextchunk = cl->wrap_nextchunk(cl, data, cl->wrapfunc_data))) {
+               bytes = nextchunk - data;
 
                len = mbs_safe_nwidth(data, bytes, NULL);
        } else
@@ -423,7 +422,7 @@ static int print_data(struct libscols_table *tb,
 {
        size_t len = 0, i, width, bytes;
        const char *color = NULL;
-       char *data, *wrapnl;
+       char *data, *nextchunk;
        int is_last;
 
        assert(tb);
@@ -471,21 +470,18 @@ 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.
-        * 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);
+       data = buffer_get_safe_data(buf, &len, scols_column_get_safechars(cl));
        if (!data)
                data = "";
        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;
+       /* custom multi-line cell based */
+       if (*data && scols_column_is_customwrap(cl)
+           && (nextchunk = cl->wrap_nextchunk(cl, data, cl->wrapfunc_data))) {
+               set_pending_data(cl, nextchunk, bytes - (nextchunk - data));
+               bytes = nextchunk - data;
                len = mbs_safe_nwidth(data, bytes, NULL);
        }
 
@@ -501,8 +497,9 @@ static int print_data(struct libscols_table *tb,
                bytes = mbs_truncate(data, &len);       /* updates 'len' */
        }
 
-       /* multi-line cell */
-       if (len > width && scols_column_is_wrap(cl)) {
+       /* standard multi-line cell */
+       if (len > width && scols_column_is_wrap(cl)
+           && !scols_column_is_customwrap(cl)) {
                set_pending_data(cl, data, bytes);
 
                len = width;
@@ -989,30 +986,6 @@ 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;
-               size_t sz;
-
-               p = strchr(data, '\n');
-               if (p) {
-                       sz = mbs_safe_nwidth(data, p - data, NULL);
-                       p++;
-               } else
-                       sz = mbs_safe_width(data);
-
-               sum = max(sum, sz);
-               data = p;;
-       }
-
-       return sum;
-}
 
 /*
  * This function counts column width.
@@ -1061,8 +1034,8 @@ static int count_column_width(struct libscols_table *tb,
 
                if (!data)
                        len = 0;
-               else if (scols_column_is_wrapnl(cl))
-                       len = count_wrapnl_size(data);
+               else if (scols_column_is_customwrap(cl))
+                       len = cl->wrap_chunksize(cl, data, cl->wrapfunc_data);
                else
                        len = mbs_safe_width(data);
 
@@ -1265,7 +1238,8 @@ static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf
                                continue;       /* never truncate columns with absolute sizes */
                        if (scols_column_is_tree(cl) && width <= cl->width_treeart)
                                continue;       /* never truncate the tree */
-                       if (trunc_only && !(scols_column_is_trunc(cl) || scols_column_is_wrap(cl)))
+                       if (trunc_only && !(scols_column_is_trunc(cl) ||
+                                       (scols_column_is_wrap(cl) && !scols_column_is_customwrap(cl))))
                                continue;
                        if (cl->width == cl->width_min)
                                continue;