summaryrefslogtreecommitdiffstats
path: root/libsmartcols/src/print.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libsmartcols/src/print.c301
1 files changed, 153 insertions, 148 deletions
diff --git a/libsmartcols/src/print.c b/libsmartcols/src/print.c
index 6a7e6da..88ab5a2 100644
--- a/libsmartcols/src/print.c
+++ b/libsmartcols/src/print.c
@@ -232,21 +232,6 @@ static int groups_ascii_art_to_buffer( struct libscols_table *tb,
return 0;
}
-static int has_pending_data(struct libscols_table *tb)
-{
- struct libscols_column *cl;
- struct libscols_iter itr;
-
- scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
- while (scols_table_next_column(tb, &itr, &cl) == 0) {
- if (scols_column_is_hidden(cl))
- continue;
- if (cl->pending_data)
- return 1;
- }
- return 0;
-}
-
static void fputs_color_reset(struct libscols_table *tb)
{
if (tb->cur_color) {
@@ -349,7 +334,7 @@ static void print_empty_cell(struct libscols_table *tb,
tree_ascii_art_to_buffer(tb, ln, &art);
- if (!list_empty(&ln->ln_branch) && has_pending_data(tb))
+ if (!list_empty(&ln->ln_branch))
ul_buffer_append_string(&art, vertical_symbol(tb));
if (scols_table_is_noencoding(tb))
@@ -423,95 +408,43 @@ static void print_newline_padding(struct libscols_table *tb,
fputs_color_line_close(tb);
}
-/*
- * Pending data
- *
- * The first line in the multi-line cells (columns with SCOLS_FL_WRAP flag) is
- * printed as usually and output is truncated to match column width.
- *
- * The rest of the long text is printed on next extra line(s). The extra lines
- * don't exist in the table (not represented by libscols_line). The data for
- * the extra lines are stored in libscols_column->pending_data_buf and the
- * function print_line() adds extra lines until the buffer is not empty in all
- * columns.
- */
-
-/* set data that will be printed by extra lines */
-static int set_pending_data(struct libscols_column *cl, const char *data, size_t sz)
+static int print_pending_data(struct libscols_table *tb, struct ul_buffer *buf)
{
- char *p = NULL;
-
- if (data && *data) {
- DBG(COL, ul_debugobj(cl, "setting pending data"));
- assert(sz);
- p = strdup(data);
- if (!p)
- return -ENOMEM;
- }
-
- free(cl->pending_data_buf);
- cl->pending_data_buf = p;
- cl->pending_data_sz = sz;
- cl->pending_data = cl->pending_data_buf;
- return 0;
-}
-
-/* the next extra line has been printed, move pending data cursor */
-static int step_pending_data(struct libscols_column *cl, size_t bytes)
-{
- DBG(COL, ul_debugobj(cl, "step pending data %zu -= %zu", cl->pending_data_sz, bytes));
-
- if (bytes >= cl->pending_data_sz)
- return set_pending_data(cl, NULL, 0);
-
- cl->pending_data += bytes;
- cl->pending_data_sz -= bytes;
- return 0;
-}
-
-/* print next pending data for the column @cl */
-static int print_pending_data(
- struct libscols_table *tb,
- struct libscols_column *cl,
- struct libscols_line *ln, /* optional */
- struct libscols_cell *ce)
-{
- size_t width = cl->width, bytes;
- size_t len = width, i;
+ struct libscols_line *ln;
+ struct libscols_column *cl;
+ struct libscols_cell *ce;
char *data;
- char *nextchunk = NULL;
+ size_t i, width = 0, len = 0, bytes = 0;
- if (!cl->pending_data)
- return 0;
+ scols_table_get_cursor(tb, &ln, &cl, &ce);
+
+ width = cl->width;
if (!width)
return -EINVAL;
DBG(COL, ul_debugobj(cl, "printing pending data"));
- data = strdup(cl->pending_data);
+ if (scols_table_is_noencoding(tb))
+ data = ul_buffer_get_data(buf, &bytes, &len);
+ else
+ data = ul_buffer_get_safe_data(buf, &bytes, &len, scols_column_get_safechars(cl));
+
if (!data)
- goto err;
+ return 0;
- if (scols_column_is_customwrap(cl)
- && (nextchunk = cl->wrap_nextchunk(cl, data, cl->wrapfunc_data))) {
- bytes = nextchunk - data;
+ /* standard multi-line cell */
+ if (len > width && scols_column_is_wrap(cl)
+ && !scols_column_is_customwrap(cl)) {
- len = scols_table_is_noencoding(tb) ?
- mbs_nwidth(data, bytes) :
- mbs_safe_nwidth(data, bytes, NULL);
- } else
+ len = width;
bytes = mbs_truncate(data, &len);
- if (bytes == (size_t) -1)
- goto err;
-
- if (bytes)
- step_pending_data(cl, bytes);
+ if (bytes != (size_t) -1 && bytes > 0)
+ scols_column_move_wrap(cl, mbs_safe_decode_size(data));
+ }
fputs_color_cell_open(tb, cl, ln, ce);
-
fputs(data, tb->out);
- free(data);
/* minout -- don't fill */
if (scols_table_is_minout(tb) && is_next_columns_empty(tb, cl, ln)) {
@@ -535,9 +468,6 @@ static int print_pending_data(
fputs(colsep(tb), tb->out);
return 0;
-err:
- free(data);
- return -errno;
}
static void print_json_data(struct libscols_table *tb,
@@ -551,6 +481,7 @@ static void print_json_data(struct libscols_table *tb,
ul_jsonwrt_value_s(&tb->json, name, data);
break;
case SCOLS_JSON_NUMBER:
+ case SCOLS_JSON_FLOAT:
/* name: 123 */
ul_jsonwrt_value_raw(&tb->json, name, data);
break;
@@ -574,47 +505,45 @@ static void print_json_data(struct libscols_table *tb,
if (!scols_column_is_customwrap(cl))
ul_jsonwrt_value_s(&tb->json, NULL, data);
else do {
- char *next = cl->wrap_nextchunk(cl, data, cl->wrapfunc_data);
-
- if (cl->json_type == SCOLS_JSON_ARRAY_STRING)
- ul_jsonwrt_value_s(&tb->json, NULL, data);
- else
- ul_jsonwrt_value_raw(&tb->json, NULL, data);
- data = next;
- } while (data);
+ if (cl->json_type == SCOLS_JSON_ARRAY_STRING)
+ ul_jsonwrt_value_s(&tb->json, NULL, data);
+ else
+ ul_jsonwrt_value_raw(&tb->json, NULL, data);
+ } while (scols_column_next_wrap(cl, NULL, &data) == 0);
ul_jsonwrt_array_close(&tb->json);
break;
}
}
-static int print_data(struct libscols_table *tb,
- struct libscols_column *cl,
- struct libscols_line *ln, /* optional */
- struct libscols_cell *ce, /* optional */
- struct ul_buffer *buf)
+static int print_data(struct libscols_table *tb, struct ul_buffer *buf)
{
+ struct libscols_line *ln; /* NULL for header line! */
+ struct libscols_column *cl;
+ struct libscols_cell *ce;
size_t len = 0, i, width, bytes;
- char *data, *nextchunk;
+ char *data = NULL;
const char *name = NULL;
int is_last;
assert(tb);
- assert(cl);
- data = ul_buffer_get_data(buf, NULL, NULL);
- if (!data)
- data = "";
+ scols_table_get_cursor(tb, &ln, &cl, &ce);
+ assert(cl);
if (tb->format != SCOLS_FMT_HUMAN) {
name = scols_table_is_shellvar(tb) ?
scols_column_get_name_as_shellvar(cl) :
scols_column_get_name(cl);
+
+ data = ul_buffer_get_data(buf, NULL, NULL);
+ if (!data)
+ data = "";
}
is_last = is_last_column(cl);
- if (is_last && scols_table_is_json(tb) &&
+ if (ln && is_last && scols_table_is_json(tb) &&
scols_table_is_tree(tb) && has_children(ln))
/* "children": [] is the real last value */
is_last = 0;
@@ -642,7 +571,7 @@ static int print_data(struct libscols_table *tb,
break; /* continue below */
}
- /* Encode. Note that 'len' and 'width' are number of cells, not bytes.
+ /* Encode. Note that 'len' and 'width' are number of glyphs not bytes.
*/
if (scols_table_is_noencoding(tb))
data = ul_buffer_get_data(buf, &bytes, &len);
@@ -653,17 +582,6 @@ static int print_data(struct libscols_table *tb,
data = "";
width = cl->width;
- /* 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 = scols_table_is_noencoding(tb) ?
- mbs_nwidth(data, bytes) :
- mbs_safe_nwidth(data, bytes, NULL);
- }
-
if (is_last
&& len < width
&& !scols_table_is_maxout(tb)
@@ -679,12 +597,12 @@ static int print_data(struct libscols_table *tb,
/* 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;
bytes = mbs_truncate(data, &len);
- if (bytes != (size_t) -1 && bytes > 0)
- step_pending_data(cl, bytes);
+
+ if (bytes != (size_t) -1 && bytes > 0)
+ scols_column_move_wrap(cl, mbs_safe_decode_size(data));
}
if (bytes == (size_t) -1) {
@@ -701,7 +619,6 @@ static int print_data(struct libscols_table *tb,
len = width;
}
fputs(data, tb->out);
-
}
/* minout -- don't fill */
@@ -732,16 +649,24 @@ static int print_data(struct libscols_table *tb,
return 0;
}
-int __cell_to_buffer(struct libscols_table *tb,
- struct libscols_line *ln,
- struct libscols_column *cl,
- struct ul_buffer *buf)
+/*
+ * Copy current cell data to buffer. The @cal means "calculation" phase.
+ */
+int __cursor_to_buffer(struct libscols_table *tb,
+ struct ul_buffer *buf,
+ int cal)
{
- const char *data;
+ const char *data = NULL;
+ size_t datasiz = 0;
struct libscols_cell *ce;
+ struct libscols_line *ln;
+ struct libscols_column *cl;
int rc = 0;
assert(tb);
+
+ scols_table_get_cursor(tb, &ln, &cl, &ce);
+
assert(ln);
assert(cl);
assert(buf);
@@ -749,11 +674,8 @@ int __cell_to_buffer(struct libscols_table *tb,
ul_buffer_reset_data(buf);
- ce = scols_line_get_cell(ln, cl->seqnum);
- data = ce ? scols_cell_get_data(ce) : NULL;
-
if (!scols_column_is_tree(cl))
- return data ? ul_buffer_append_string(buf, data) : 0;
+ goto notree;
/*
* Group stuff
@@ -775,9 +697,79 @@ int __cell_to_buffer(struct libscols_table *tb,
if (!rc && (ln->parent || cl->is_groups) && !scols_table_is_json(tb))
ul_buffer_save_pointer(buf, SCOLS_BUFPTR_TREEEND);
+notree:
+ if (!rc && ce) {
+ int do_wrap = scols_column_is_wrap(cl);
+
+ /* Disable multi-line cells for "raw" and "export" formats.
+ * JSON uses data wrapping to generate arrays */
+ if (do_wrap && (tb->format == SCOLS_FMT_RAW ||
+ tb->format == SCOLS_FMT_EXPORT))
+ do_wrap = 0;
+
+ /* Wrapping enabled; append the next chunk if cell data */
+ if (do_wrap) {
+ char *x = NULL;
+
+ rc = cal ? scols_column_greatest_wrap(cl, ce, &x) :
+ scols_column_next_wrap(cl, ce, &x);
+ /* rc: error: <0; nodata: 1; success: 0 */
+ if (rc < 0)
+ goto done;
+ data = x;
+ rc = 0;
+ if (data && *data)
+ datasiz = strlen(data);
+ if (data && datasiz)
+ rc = ul_buffer_append_data(buf, data, datasiz);
+
+ /* Wrapping disabled, but data maintained by custom wrapping
+ * callback. Try to use data as a string, if not possible,
+ * append all chunks separated by \n (backward compatibility).
+ * */
+ } else if (scols_column_is_customwrap(cl)) {
+ size_t len;
+ int i = 0;
+ char *x = NULL;
+
+ data = scols_cell_get_data(ce);
+ datasiz = scols_cell_get_datasiz(ce);
+ len = data ? strnlen(data, datasiz) : 0;
+
+ if (len && len + 1 == datasiz)
+ rc = ul_buffer_append_data(buf, data, datasiz);
+
+ else while (scols_column_next_wrap(cl, ce, &x) == 0) {
+ /* non-string data in cell, use a nextchunk callback */
+ if (!x)
+ continue;
+ datasiz = strlen(x);
+ if (i)
+ rc = ul_buffer_append_data(buf, "\n", 1);
+ if (!rc)
+ rc = ul_buffer_append_data(buf, x, datasiz);
+ i++;
+ }
+
+ /* Wrapping disabled; let's use data as a classic string. */
+ } else {
+ data = scols_cell_get_data(ce);
+ datasiz = scols_cell_get_datasiz(ce);
+
+ if (data && *data && !datasiz)
+ datasiz = strlen(data); /* cell content may be updated */
- if (!rc && data)
- rc = ul_buffer_append_string(buf, data);
+ if (data && datasiz)
+ rc = ul_buffer_append_data(buf, data, datasiz);
+ }
+ }
+
+ /* reset wrapping after greatest chunk calculation */
+ if (cal && scols_column_is_wrap(cl))
+ scols_column_reset_wrap(cl);
+
+done:
+ DBG(COL, ul_debugobj(cl, "__cursor_to_buffer rc=%d", rc));
return rc;
}
@@ -801,16 +793,18 @@ static int print_line(struct libscols_table *tb,
/* regular line */
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+
while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) {
if (scols_column_is_hidden(cl))
continue;
- rc = __cell_to_buffer(tb, ln, cl, buf);
- if (rc == 0)
- rc = print_data(tb, cl, ln,
- scols_line_get_cell(ln, cl->seqnum),
- buf);
- if (rc == 0 && cl->pending_data)
+
+ scols_table_set_cursor(tb, ln, cl, scols_line_get_cell(ln, cl->seqnum));
+ rc = __cursor_to_buffer(tb, buf, 0);
+ if (!rc)
+ rc = print_data(tb, buf);
+ if (!rc && scols_column_has_pending_wrap(cl))
pending = 1;
+ scols_table_reset_cursor(tb);
}
fputs_color_line_close(tb);
@@ -821,16 +815,25 @@ static int print_line(struct libscols_table *tb,
fputs(linesep(tb), tb->out);
fputs_color_line_open(tb, ln);
tb->termlines_used++;
+
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+
while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) {
if (scols_column_is_hidden(cl))
continue;
- if (cl->pending_data) {
- rc = print_pending_data(tb, cl, ln, scols_line_get_cell(ln, cl->seqnum));
- if (rc == 0 && cl->pending_data)
+
+ scols_table_set_cursor(tb, ln, cl, scols_line_get_cell(ln, cl->seqnum));
+ if (scols_column_has_pending_wrap(cl)) {
+ rc = __cursor_to_buffer(tb, buf, 0);
+ if (!rc)
+ rc = print_pending_data(tb, buf);
+ if (!rc && scols_column_has_pending_wrap(cl))
pending = 1;
+ if (!rc && !pending)
+ scols_column_reset_wrap(cl);
} else
print_empty_cell(tb, cl, ln, NULL, ul_buffer_get_bufsiz(buf));
+ scols_table_reset_cursor(tb);
}
fputs_color_line_close(tb);
}
@@ -963,6 +966,7 @@ int __scols_print_header(struct libscols_table *tb, struct ul_buffer *buf)
continue;
ul_buffer_reset_data(buf);
+ scols_table_set_cursor(tb, NULL, cl, &cl->header);
if (cl->is_groups
&& scols_table_is_tree(tb) && scols_column_is_tree(cl)) {
@@ -979,7 +983,8 @@ int __scols_print_header(struct libscols_table *tb, struct ul_buffer *buf)
scols_column_get_name_as_shellvar(cl) :
scols_column_get_name(cl));
if (!rc)
- rc = print_data(tb, cl, NULL, &cl->header, buf);
+ rc = print_data(tb, buf);
+ scols_table_reset_cursor(tb);
}
if (rc == 0) {