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>
This commit is contained in:
parent
0d71eb9c4b
commit
949ea05f1a
|
@ -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>
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue