summaryrefslogtreecommitdiffstats
path: root/libsmartcols
diff options
context:
space:
mode:
authorKarel Zak2016-09-26 11:20:07 +0200
committerKarel Zak2016-09-26 11:20:07 +0200
commit949ea05f1af647834db24b9172ac006488d2e4f4 (patch)
tree0e735393ebe57f1f53cab8da3288b96fcc756f27 /libsmartcols
parentlibsmartcols: (docs) add missing functions (diff)
downloadkernel-qcow2-util-linux-949ea05f1af647834db24b9172ac006488d2e4f4.tar.gz
kernel-qcow2-util-linux-949ea05f1af647834db24b9172ac006488d2e4f4.tar.xz
kernel-qcow2-util-linux-949ea05f1af647834db24b9172ac006488d2e4f4.zip
libsmartcols: support custom wrap and remove SCOLS_FL_WRAPNL
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>
Diffstat (limited to 'libsmartcols')
-rw-r--r--libsmartcols/docs/libsmartcols-sections.txt8
-rw-r--r--libsmartcols/samples/fromfile.c9
-rw-r--r--libsmartcols/src/column.c146
-rw-r--r--libsmartcols/src/libsmartcols.h.in19
-rw-r--r--libsmartcols/src/libsmartcols.sym14
-rw-r--r--libsmartcols/src/smartcolsP.h8
-rw-r--r--libsmartcols/src/table_print.c62
7 files changed, 208 insertions, 58 deletions
diff --git a/libsmartcols/docs/libsmartcols-sections.txt b/libsmartcols/docs/libsmartcols-sections.txt
index 12366bd34..f05d45479 100644
--- a/libsmartcols/docs/libsmartcols-sections.txt
+++ b/libsmartcols/docs/libsmartcols-sections.txt
@@ -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>
diff --git a/libsmartcols/samples/fromfile.c b/libsmartcols/samples/fromfile.c
index 6d4ee4aaf..fcf01c749 100644
--- a/libsmartcols/samples/fromfile.c
+++ b/libsmartcols/samples/fromfile.c
@@ -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 */
diff --git a/libsmartcols/src/column.c b/libsmartcols/src/column.c
index 6f4ccc3bd..1e84a6363 100644
--- a/libsmartcols/src/column.c
+++ b/libsmartcols/src/column.c
@@ -22,6 +22,8 @@
#include <string.h>
#include <ctype.h>
+#include "mbsalign.h"
+
#include "smartcolsP.h"
/**
@@ -169,6 +171,17 @@ int scols_column_set_flags(struct libscols_column *cl, int flags)
}
/**
+ * 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:
@@ -251,6 +327,66 @@ int scols_column_set_cmpfunc(struct libscols_column *cl,
}
/**
+ * 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;
}
diff --git a/libsmartcols/src/libsmartcols.h.in b/libsmartcols/src/libsmartcols.h.in
index 22cab64a1..d6ae91f60 100644
--- a/libsmartcols/src/libsmartcols.h.in
+++ b/libsmartcols/src/libsmartcols.h.in
@@ -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);
diff --git a/libsmartcols/src/libsmartcols.sym b/libsmartcols/src/libsmartcols.sym
index aca648b63..d5c3674b8 100644
--- a/libsmartcols/src/libsmartcols.sym
+++ b/libsmartcols/src/libsmartcols.sym
@@ -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;
diff --git a/libsmartcols/src/smartcolsP.h b/libsmartcols/src/smartcolsP.h
index 8e8bd768e..2f29c9f63 100644
--- a/libsmartcols/src/smartcolsP.h
+++ b/libsmartcols/src/smartcolsP.h
@@ -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;
diff --git a/libsmartcols/src/table_print.c b/libsmartcols/src/table_print.c
index 5771111b3..c73154ec6 100644
--- a/libsmartcols/src/table_print.c
+++ b/libsmartcols/src/table_print.c
@@ -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;