scols_reset_cell(&cl->header);
free(cl->color);
free(cl->safechars);
- free(cl->pending_data_buf);
+ free(cl->wrap_data);
free(cl->shellvar);
free(cl);
}
* Note that the size has to be based on number of terminal cells rather than
* bytes to support multu-byte output.
*
+ * Deprecated since 2.40.
+ *
* Returns: size of the largest chunk.
*
* Since: 2.29
/**
* 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_chunksize: function to return size of the largest chink of data (deprecated)
* @wrap_nextchunk: function to return next zero terminated data
* @userdata: optional stuff for callbacks
*
* is to wrap by column size, but you can create functions to wrap for example
* after \n or after words, etc.
*
+ * Note that since 2.40 the @wrap_chunksize is unnecessary. The library calculates
+ * the size itself.
+ *
* Returns: 0, a negative value in case of an error.
*
* Since: 2.29
int scols_column_set_wrapfunc(struct libscols_column *cl,
size_t (*wrap_chunksize)(const struct libscols_column *,
const char *,
- void *),
+ void *) __attribute__((__unused__)),
char * (*wrap_nextchunk)(const struct libscols_column *,
char *,
void *),
return -EINVAL;
cl->wrap_nextchunk = wrap_nextchunk;
- cl->wrap_chunksize = wrap_chunksize;
cl->wrapfunc_data = userdata;
return 0;
}
int scols_column_is_customwrap(const struct libscols_column *cl)
{
return (cl->flags & SCOLS_FL_WRAP)
- && cl->wrap_chunksize
&& cl->wrap_nextchunk ? 1 : 0;
}
return rc;
}
+static void scols_column_reset_wrap(struct libscols_column *cl)
+{
+ if (!cl)
+ return;
+
+ if (cl->wrap_data)
+ memset(cl->wrap_data, 0, cl->wrap_datamax);
+ cl->wrap_cell = NULL;
+ cl->wrap_datasz = 0;
+ cl->wrap_cur = NULL;
+ cl->wrap_next = NULL;
+}
+
+static int scols_column_init_wrap(
+ struct libscols_column *cl,
+ struct libscols_cell *ce)
+{
+ const char *data = scols_cell_get_data(ce);
+
+ if (!cl || !ce)
+ return -EINVAL;
+
+ assert(cl->table->cur_column == cl);
+ assert(cl->table->cur_cell == ce);
+
+ scols_column_reset_wrap(cl);
+
+ cl->wrap_cell = ce;
+ if (data) {
+ void *tmp;
+ cl->wrap_datasz = strlen(data) + 1; /* TODO: use scols_cell_get_datasiz() */
+
+ if (cl->wrap_datasz > cl->wrap_datamax) {
+ cl->wrap_datamax = cl->wrap_datasz;
+ tmp = realloc(cl->wrap_data, cl->wrap_datamax);
+ if (!tmp)
+ return -ENOMEM;
+ cl->wrap_data = tmp;
+ }
+ memcpy(cl->wrap_data, data, cl->wrap_datasz);
+ cl->wrap_cur = cl->wrap_data;
+ cl->wrap_next = NULL;
+ }
+
+ return 0;
+}
+
+/* Returns the next chunk of cell data in multi-line cells */
+int scols_column_next_wrap(
+ struct libscols_column *cl,
+ struct libscols_cell *ce,
+ char **data)
+{
+ if (!cl || !data || (!cl->wrap_cell && !ce))
+ return -EINVAL;
+
+ *data = NULL;
+
+ if (ce && cl->wrap_cell != ce)
+ scols_column_init_wrap(cl, ce); /* init */
+ else {
+ cl->wrap_cur = cl->wrap_next; /* next step */
+ cl->wrap_next = NULL;
+ }
+
+ if (!cl->wrap_cur)
+ return 1; /* no more data */
+ if (scols_column_is_customwrap(cl))
+ cl->wrap_next = cl->wrap_nextchunk(cl, cl->wrap_cur, cl->wrapfunc_data);
+
+ *data = cl->wrap_cur;
+ return 0;
+}
+
+int scols_column_greatest_wrap(
+ struct libscols_column *cl,
+ struct libscols_cell *ce,
+ char **data)
+{
+ size_t maxsz = 0;
+ char *res = NULL;;
+
+ if (!scols_column_is_customwrap(cl))
+ return scols_column_next_wrap(cl, ce, data);
+
+ while (scols_column_next_wrap(cl, ce, data) == 0) {
+ size_t sz = strlen(*data);
+
+ maxsz = max(maxsz, sz);
+ if (maxsz == sz)
+ res = *data;
+ }
+
+ *data = res;
+ return 0;
+}
+
+/* Set the "next" chunk in multi-line cell to offset specified by @bytes.
+ * Don't use it for columns with custom wrapfunc().
+ */
+int scols_column_move_wrap(struct libscols_column *cl, size_t bytes)
+{
+ size_t x; /* remaining bytes */
+
+ if (!cl->wrap_cur)
+ return -EINVAL; /* scols_column_init_wrap() not called */
+
+ x = cl->wrap_datasz - (cl->wrap_cur - cl->wrap_data);
+ if (bytes >= x)
+ cl->wrap_next = NULL; /* done */
+ else
+ cl->wrap_next = cl->wrap_cur + bytes;
+ return 0;
+}
+
+int scols_column_has_pending_wrap(struct libscols_column *cl)
+{
+ return cl && cl->wrap_next;
+}
while (scols_table_next_column(tb, &itr, &cl) == 0) {
if (scols_column_is_hidden(cl))
continue;
- if (cl->pending_data)
+ if (scols_column_has_pending_wrap(cl))
return 1;
}
return 0;
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)
-{
- 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)
+static int print_pending_data(struct libscols_table *tb, struct ul_buffer *buf)
{
- 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)) {
fputs(colsep(tb), tb->out);
return 0;
-err:
- free(data);
- return -errno;
}
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;
const char *name = NULL;
int is_last;
assert(tb);
+
+ scols_table_get_cursor(tb, &ln, &cl, &ce);
assert(cl);
data = ul_buffer_get_data(buf, NULL, NULL);
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;
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);
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)
/* 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) {
len = width;
}
fputs(data, tb->out);
-
}
/* minout -- don't fill */
return 0;
}
-int __cell_to_buffer(struct libscols_table *tb,
- struct libscols_line *ln,
- struct libscols_column *cl,
- struct ul_buffer *buf)
+/*
+ * Copy curret 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;
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);
ul_buffer_reset_data(buf);
- ce = scols_line_get_cell(ln, cl->seqnum);
- data = ce ? scols_cell_get_data(ce) : NULL;
+ if (ce) {
+ if (scols_column_is_wrap(cl)) {
+ char *x = NULL;
+
+ rc = cal ? scols_column_greatest_wrap(cl, ce, &x) :
+ scols_column_next_wrap(cl, ce, &x);
+ if (rc < 0)
+ return rc;
+ data = x;
+ rc = 0;
+ } else
+ data = scols_cell_get_data(ce);
+ }
if (!scols_column_is_tree(cl))
- return data ? ul_buffer_append_string(buf, data) : 0;
+ goto notree;
/*
* Group stuff
if (!rc && (ln->parent || cl->is_groups) && !scols_table_is_json(tb))
ul_buffer_save_pointer(buf, SCOLS_BUFPTR_TREEEND);
-
+notree:
if (!rc && data)
rc = ul_buffer_append_string(buf, data);
return rc;
/* 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);
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;
} else
print_empty_cell(tb, cl, ln, NULL, ul_buffer_get_bufsiz(buf));
+ scols_table_reset_cursor(tb);
}
fputs_color_line_close(tb);
}
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)) {
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) {