libsmartcols: use buffer struct in table_print.c

* consolidate code in table_print.c
 * make the code easy to extend
 * use return codes everywhere

Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2014-04-14 16:41:20 +02:00
parent b32fc3bb32
commit b233dcb6ff
1 changed files with 208 additions and 110 deletions

View File

@ -28,24 +28,92 @@
#include "carefulputc.h"
#include "smartcolsP.h"
/* This is private struct to work with output data */
struct libscols_buffer {
char *begin; /* begin of the buffer */
char *cur; /* current end of the buffer */
size_t bufsz; /* size of the buffer */
};
static struct libscols_buffer *new_buffer(size_t sz)
{
struct libscols_buffer *buf = malloc(sz + sizeof(struct libscols_buffer));
if (!buf)
return NULL;
buf->cur = buf->begin = ((char *) buf) + sizeof(struct libscols_buffer);
buf->bufsz = sz;
return buf;
}
static void free_buffer(struct libscols_buffer *buf)
{
free(buf);
}
static int buffer_reset_data(struct libscols_buffer *buf)
{
if (!buf)
return -EINVAL;
buf->begin[0] = '\0';
buf->cur = buf->begin;
return 0;
}
static int buffer_append_data(struct libscols_buffer *buf, const char *str)
{
size_t maxsz, sz;
if (!buf)
return -EINVAL;
if (!str || !*str)
return 0;
sz = strlen(str);
maxsz = buf->bufsz - (buf->cur - buf->begin);
if (maxsz <= sz)
return -EINVAL;
memcpy(buf->cur, str, sz + 1);
buf->cur += sz;
return 0;
}
static int buffer_set_data(struct libscols_buffer *buf, const char *str)
{
int rc = buffer_reset_data(buf);
return rc ? rc : buffer_append_data(buf, str);
}
static char *buffer_get_data(struct libscols_buffer *buf)
{
return buf ? buf->begin : NULL;
}
#define is_last_column(_tb, _cl) \
list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns)
#define colsep(tb) ((tb)->colsep ? (tb)->colsep : " ")
#define linesep(tb) ((tb)->linesep ? (tb)->linesep : "\n")
static void print_data(struct libscols_table *tb,
struct libscols_column *cl,
struct libscols_line *ln, /* optional */
struct libscols_cell *ce, /* optional */
char *data)
static int print_data(struct libscols_table *tb,
struct libscols_column *cl,
struct libscols_line *ln, /* optional */
struct libscols_cell *ce, /* optional */
struct libscols_buffer *buf)
{
size_t len = 0, i, width;
char *buf;
const char *color = NULL;
char *data, *data_enc = NULL;
assert(tb);
assert(cl);
data = buffer_get_data(buf);
if (!data)
data = "";
@ -54,7 +122,7 @@ static void print_data(struct libscols_table *tb,
fputs_nonblank(data, tb->out);
if (!is_last_column(tb, cl))
fputs(colsep(tb), tb->out);
return;
return 0;
}
/* NAME=value mode */
@ -63,7 +131,7 @@ static void print_data(struct libscols_table *tb,
fputs_quoted(data, tb->out);
if (!is_last_column(tb, cl))
fputs(colsep(tb), tb->out);
return;
return 0;
}
if (tb->colors_wanted) {
@ -76,8 +144,7 @@ static void print_data(struct libscols_table *tb,
}
/* note that 'len' and 'width' are number of cells, not bytes */
buf = mbs_safe_encode(data, &len);
data = buf;
data_enc = data = mbs_safe_encode(data, &len);
if (!data)
data = "";
@ -132,110 +199,109 @@ static void print_data(struct libscols_table *tb,
fputs(colsep(tb), tb->out); /* columns separator */
}
free(buf);
free(data_enc);
return 0;
}
static char *line_get_ascii_art(struct libscols_table *tb,
struct libscols_line *ln,
char *buf, size_t *bufsz)
/* returns pointer to the end of used data */
static int line_ascii_art_to_buffer(struct libscols_table *tb,
struct libscols_line *ln,
struct libscols_buffer *buf)
{
const char *art;
size_t len;
int rc;
assert(ln);
assert(buf);
if (!ln->parent)
return buf;
return 0;
buf = line_get_ascii_art(tb, ln->parent, buf, bufsz);
if (!buf)
return NULL;
rc = line_ascii_art_to_buffer(tb, ln->parent, buf);
if (rc)
return rc;
if (list_entry_is_last(&ln->ln_children, &ln->parent->ln_branch))
art = " ";
else
art = tb->symbols->vert;
len = strlen(art);
if (*bufsz < len)
return NULL; /* no space, internal error */
memcpy(buf, art, len);
*bufsz -= len;
return buf + len;
return buffer_append_data(buf, art);
}
static char *line_get_data(struct libscols_table *tb,
struct libscols_line *ln,
struct libscols_column *cl,
char *buf, size_t bufsz)
static int cell_to_buffer(struct libscols_table *tb,
struct libscols_line *ln,
struct libscols_column *cl,
struct libscols_buffer *buf)
{
const char *data;
struct libscols_symbols *sym;
struct libscols_cell *ce;
char *p = buf;
int rc = 0;
assert(tb);
assert(ln);
assert(cl);
assert(buf);
assert(cl->seqnum <= tb->ncols);
memset(buf, 0, bufsz);
ce = scols_line_get_cell(ln, cl->seqnum);
data = ce ? scols_cell_get_data(ce) : NULL;
if (!data)
return NULL;
return 0;
if (!scols_column_is_tree(cl)) {
strncpy(buf, data, bufsz);
buf[bufsz - 1] = '\0';
return buf;
}
if (!scols_column_is_tree(cl))
return buffer_set_data(buf, data);
/*
* Tree stuff
*/
buffer_reset_data(buf);
if (ln->parent) {
p = line_get_ascii_art(tb, ln->parent, buf, &bufsz);
if (!p)
return NULL;
rc = line_ascii_art_to_buffer(tb, ln->parent, buf);
if (!rc && list_entry_is_last(&ln->ln_children, &ln->parent->ln_branch))
rc = buffer_append_data(buf, tb->symbols->right);
else if (!rc)
rc = buffer_append_data(buf, tb->symbols->branch);
}
sym = tb->symbols;
if (!ln->parent)
snprintf(p, bufsz, "%s", data); /* root node */
else if (list_entry_is_last(&ln->ln_children, &ln->parent->ln_branch))
snprintf(p, bufsz, "%s%s", sym->right, data); /* last chaild */
else
snprintf(p, bufsz, "%s%s", sym->branch, data); /* any child */
return buf;
if (!rc)
rc = buffer_append_data(buf, data);
return rc;
}
/*
* Prints data, data maybe be printed in more formats (raw, NAME=xxx pairs) and
* control and non-printable chars maybe encoded in \x?? hex encoding.
*/
static void print_line(struct libscols_table *tb,
struct libscols_line *ln, char *buf, size_t bufsz)
static int print_line(struct libscols_table *tb,
struct libscols_line *ln,
struct libscols_buffer *buf)
{
int rc = 0;
struct libscols_column *cl;
struct libscols_iter itr;
assert(ln);
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
while (scols_table_next_column(tb, &itr, &cl) == 0)
print_data(tb, cl, ln,
scols_line_get_cell(ln, cl->seqnum),
line_get_data(tb, ln, cl, buf, bufsz));
fputs(linesep(tb), tb->out);
while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) {
rc = cell_to_buffer(tb, ln, cl, buf);
if (!rc)
rc = print_data(tb, cl, ln,
scols_line_get_cell(ln, cl->seqnum),
buf);
}
if (rc == 0)
fputs(linesep(tb), tb->out);
return 0;
}
static void print_header(struct libscols_table *tb, char *buf, size_t bufsz)
static int print_header(struct libscols_table *tb, struct libscols_buffer *buf)
{
int rc = 0;
struct libscols_column *cl;
struct libscols_iter itr;
@ -244,67 +310,82 @@ static void print_header(struct libscols_table *tb, char *buf, size_t bufsz)
if (scols_table_is_noheadings(tb) ||
scols_table_is_export(tb) ||
list_empty(&tb->tb_lines))
return;
return 0;
/* set width according to the size of data
*/
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
while (scols_table_next_column(tb, &itr, &cl) == 0) {
strncpy(buf, scols_cell_get_data(&cl->header), bufsz);
buf[bufsz - 1] = '\0';
print_data(tb, cl, NULL, &cl->header, buf);
while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) {
rc = buffer_set_data(buf, scols_cell_get_data(&cl->header));
if (!rc)
rc = print_data(tb, cl, NULL, &cl->header, buf);
}
fputs(linesep(tb), tb->out);
if (rc == 0)
fputs(linesep(tb), tb->out);
return rc;
}
static void print_table(struct libscols_table *tb, char *buf, size_t bufsz)
static int print_table(struct libscols_table *tb, struct libscols_buffer *buf)
{
int rc;
struct libscols_line *ln;
struct libscols_iter itr;
assert(tb);
print_header(tb, buf, bufsz);
rc = print_header(tb, buf);
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
while (scols_table_next_line(tb, &itr, &ln) == 0)
print_line(tb, ln, buf, bufsz);
while (rc == 0 && scols_table_next_line(tb, &itr, &ln) == 0)
rc = print_line(tb, ln, buf);
return rc;
}
static void print_tree_line(struct libscols_table *tb,
struct libscols_line *ln,
char *buf, size_t bufsz)
static int print_tree_line(struct libscols_table *tb,
struct libscols_line *ln,
struct libscols_buffer *buf)
{
int rc;
struct list_head *p;
print_line(tb, ln, buf, bufsz);
rc = print_line(tb, ln, buf);
if (rc)
return rc;
if (list_empty(&ln->ln_branch))
return;
return 0;
/* print all children */
list_for_each(p, &ln->ln_branch) {
struct libscols_line *chld =
list_entry(p, struct libscols_line, ln_children);
print_tree_line(tb, chld, buf, bufsz);
rc = print_tree_line(tb, chld, buf);
if (rc)
break;
}
return rc;
}
static void print_tree(struct libscols_table *tb, char *buf, size_t bufsz)
static int print_tree(struct libscols_table *tb, struct libscols_buffer *buf)
{
int rc;
struct libscols_line *ln;
struct libscols_iter itr;
assert(tb);
print_header(tb, buf, bufsz);
rc = print_header(tb, buf);
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
while (scols_table_next_line(tb, &itr, &ln) == 0) {
while (rc == 0 && scols_table_next_line(tb, &itr, &ln) == 0) {
if (ln->parent)
continue;
print_tree_line(tb, ln, buf, bufsz);
rc = print_tree_line(tb, ln, buf);
}
return rc;
}
/*
@ -316,14 +397,13 @@ static void print_tree(struct libscols_table *tb, char *buf, size_t bufsz)
* is marked as "extreme". In the second pass all extreme fields are ignored
* and column width is counted from non-extreme fields only.
*/
static void count_column_width(struct libscols_table *tb,
struct libscols_column *cl,
char *buf,
size_t bufsz)
static int count_column_width(struct libscols_table *tb,
struct libscols_column *cl,
struct libscols_buffer *buf)
{
struct libscols_line *ln;
struct libscols_iter itr;
int count = 0;
int count = 0, rc = 0;
size_t sum = 0;
assert(tb);
@ -333,8 +413,15 @@ static void count_column_width(struct libscols_table *tb,
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
while (scols_table_next_line(tb, &itr, &ln) == 0) {
char *data = line_get_data(tb, ln, cl, buf, bufsz);
size_t len = data ? mbs_safe_width(data) : 0;
size_t len;
char *data;
rc = cell_to_buffer(tb, ln, cl, buf);
if (rc)
return rc;
data = buffer_get_data(buf);
len = data ? mbs_safe_width(data) : 0;
if (len == (size_t) -1) /* ignore broken multibyte strings */
len = 0;
@ -371,30 +458,35 @@ static void count_column_width(struct libscols_table *tb,
&& cl->width_min < (size_t) cl->width_hint)
cl->width = (size_t) cl->width_hint;
return rc;
}
/*
* This is core of the scols_* voodo...
*/
static void recount_widths(struct libscols_table *tb, char *buf, size_t bufsz)
static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf)
{
struct libscols_column *cl;
struct libscols_iter itr;
size_t width = 0; /* output width */
int trunc_only;
int trunc_only, rc = 0;
int extremes = 0;
/* set basic columns width
*/
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
while (scols_table_next_column(tb, &itr, &cl) == 0) {
count_column_width(tb, cl, buf, bufsz);
rc = count_column_width(tb, cl, buf);
if (rc)
return rc;
width += cl->width + (is_last_column(tb, cl) ? 0 : 1);
extremes += cl->is_extreme;
}
if (!tb->is_term)
return;
return 0;
/* reduce columns with extreme fields
*/
@ -407,7 +499,9 @@ static void recount_widths(struct libscols_table *tb, char *buf, size_t bufsz)
continue;
org_width = cl->width;
count_column_width(tb, cl, buf, bufsz);
rc = count_column_width(tb, cl, buf);
if (rc)
return rc;
if (org_width > cl->width)
width -= org_width - cl->width;
@ -526,8 +620,9 @@ static void recount_widths(struct libscols_table *tb, char *buf, size_t bufsz)
cl->is_extreme ? "yes" : "not");
}
*/
return;
return rc;
}
static size_t strlen_line(struct libscols_line *ln)
{
size_t i, sz = 0;
@ -544,6 +639,8 @@ static size_t strlen_line(struct libscols_line *ln)
return sz;
}
/**
* scols_print_table:
* @tb: table
@ -554,10 +651,11 @@ static size_t strlen_line(struct libscols_line *ln)
*/
int scols_print_table(struct libscols_table *tb)
{
char *line;
size_t line_sz;
int rc = 0;
size_t bufsz;
struct libscols_line *ln;
struct libscols_iter itr;
struct libscols_buffer *buf;
assert(tb);
if (!tb)
@ -572,30 +670,29 @@ int scols_print_table(struct libscols_table *tb)
tb->termwidth = 80;
tb->termwidth -= tb->termreduce;
line_sz = tb->termwidth;
bufsz = tb->termwidth;
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
while (scols_table_next_line(tb, &itr, &ln) == 0) {
size_t sz = strlen_line(ln);
if (sz > line_sz)
line_sz = sz;
if (sz > bufsz)
bufsz = sz;
}
line_sz++; /* make a space for \0 */
line = malloc(line_sz);
if (!line)
buf = new_buffer(bufsz + 1); /* data + space for \0 */
if (!buf)
return -ENOMEM;
if (!(scols_table_is_raw(tb) || scols_table_is_export(tb)))
recount_widths(tb, line, line_sz);
rc = recount_widths(tb, buf);
if (scols_table_is_tree(tb))
print_tree(tb, line, line_sz);
rc = print_tree(tb, buf);
else
print_table(tb, line, line_sz);
rc = print_table(tb, buf);
free(line);
return 0;
free_buffer(buf);
return rc;
}
/**
@ -612,6 +709,7 @@ int scols_print_table_to_string(struct libscols_table *tb, char **data)
#ifdef HAVE_OPEN_MEMSTREAM
FILE *stream;
size_t sz;
int rc;
if (!tb)
return -EINVAL;
@ -622,10 +720,10 @@ int scols_print_table_to_string(struct libscols_table *tb, char **data)
return -ENOMEM;
scols_table_set_stream(tb, stream);
scols_print_table(tb);
rc = scols_print_table(tb);
fclose(stream);
return 0;
return rc;
#else
return -ENOSYS;
#endif