libsmartcols: add JSON output format
Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
1280109fdc
commit
2a6cfc1361
|
@ -93,6 +93,7 @@ scols_table_colors_wanted
|
|||
scols_table_enable_ascii
|
||||
scols_table_enable_colors
|
||||
scols_table_enable_export
|
||||
scols_table_enable_json
|
||||
scols_table_enable_maxout
|
||||
scols_table_enable_noheadings
|
||||
scols_table_enable_raw
|
||||
|
@ -106,6 +107,7 @@ scols_table_get_stream
|
|||
scols_table_is_ascii
|
||||
scols_table_is_empty
|
||||
scols_table_is_export
|
||||
scols_table_is_json
|
||||
scols_table_is_maxout
|
||||
scols_table_is_noheadings
|
||||
scols_table_is_raw
|
||||
|
@ -121,6 +123,7 @@ scols_table_remove_line
|
|||
scols_table_remove_lines
|
||||
scols_table_set_column_separator
|
||||
scols_table_set_line_separator
|
||||
scols_table_set_name
|
||||
scols_table_set_stream
|
||||
scols_table_set_symbols
|
||||
scols_sort_table
|
||||
|
|
|
@ -172,8 +172,10 @@ extern struct libscols_line *scols_copy_line(struct libscols_line *ln);
|
|||
|
||||
/* table */
|
||||
extern int scols_table_colors_wanted(struct libscols_table *tb);
|
||||
extern int scols_table_set_name(struct libscols_table *tb, const char *name);
|
||||
extern int scols_table_is_raw(struct libscols_table *tb);
|
||||
extern int scols_table_is_ascii(struct libscols_table *tb);
|
||||
extern int scols_table_is_json(struct libscols_table *tb);
|
||||
extern int scols_table_is_noheadings(struct libscols_table *tb);
|
||||
extern int scols_table_is_empty(struct libscols_table *tb);
|
||||
extern int scols_table_is_export(struct libscols_table *tb);
|
||||
|
@ -183,6 +185,7 @@ extern int scols_table_is_tree(struct libscols_table *tb);
|
|||
extern int scols_table_enable_colors(struct libscols_table *tb, int enable);
|
||||
extern int scols_table_enable_raw(struct libscols_table *tb, int enable);
|
||||
extern int scols_table_enable_ascii(struct libscols_table *tb, int enable);
|
||||
extern int scols_table_enable_json(struct libscols_table *tb, int enable);
|
||||
extern int scols_table_enable_noheadings(struct libscols_table *tb, int enable);
|
||||
extern int scols_table_enable_export(struct libscols_table *tb, int enable);
|
||||
extern int scols_table_enable_maxout(struct libscols_table *tb, int enable);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* symbols since util-linux 2.25
|
||||
*
|
||||
* Copyright (C) 2014 Karel Zak <kzak@redhat.com>
|
||||
* Copyright (C) 2014-2015 Karel Zak <kzak@redhat.com>
|
||||
*/
|
||||
SMARTCOLS_2.25 {
|
||||
global:
|
||||
|
@ -112,3 +112,11 @@ global:
|
|||
local:
|
||||
*;
|
||||
};
|
||||
|
||||
|
||||
SMARTCOLS_2.27 {
|
||||
global:
|
||||
scols_table_enable_json;
|
||||
scols_table_is_json;
|
||||
scols_table_set_name;
|
||||
} SMARTCOLS_2.25;
|
||||
|
|
|
@ -122,7 +122,8 @@ struct libscols_line {
|
|||
enum {
|
||||
SCOLS_FMT_HUMAN = 0, /* default, human readable */
|
||||
SCOLS_FMT_RAW, /* space separated */
|
||||
SCOLS_FMT_EXPORT /* COLNAME="data" ... */
|
||||
SCOLS_FMT_EXPORT, /* COLNAME="data" ... */
|
||||
SCOLS_FMT_JSON /* http://en.wikipedia.org/wiki/JSON */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -130,6 +131,7 @@ enum {
|
|||
*/
|
||||
struct libscols_table {
|
||||
int refcount;
|
||||
char *name; /* optional table table */
|
||||
size_t ncols; /* number of columns */
|
||||
size_t ntreecols; /* number of columns with SCOLS_FL_TREE */
|
||||
size_t nlines; /* number of lines */
|
||||
|
@ -144,6 +146,8 @@ struct libscols_table {
|
|||
struct list_head tb_lines;
|
||||
struct libscols_symbols *symbols;
|
||||
|
||||
int indent; /* indention counter */
|
||||
int indent_last_sep;/* last printed has been line separator */
|
||||
int format; /* SCOLS_FMT_* */
|
||||
|
||||
/* flags */
|
||||
|
@ -171,4 +175,13 @@ struct libscols_table {
|
|||
(itr)->p->next : (itr)->p->prev; \
|
||||
} while(0)
|
||||
|
||||
|
||||
static inline int scols_iter_is_last(struct libscols_iter *itr)
|
||||
{
|
||||
if (!itr || !itr->head || !itr->p)
|
||||
return 0;
|
||||
|
||||
return itr->p == itr->head;
|
||||
}
|
||||
|
||||
#endif /* _LIBSMARTCOLS_PRIVATE_H */
|
||||
|
|
|
@ -89,10 +89,38 @@ void scols_unref_table(struct libscols_table *tb)
|
|||
scols_unref_symbols(tb->symbols);
|
||||
free(tb->linesep);
|
||||
free(tb->colsep);
|
||||
free(tb->name);
|
||||
free(tb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* scols_table_set_name:
|
||||
* @tb: a pointer to a struct libscols_table instance
|
||||
* @name: a name
|
||||
*
|
||||
* The table name is used for example for JSON top level object name.
|
||||
*
|
||||
* Returns: 0, a negative number in case of an error.
|
||||
*/
|
||||
int scols_table_set_name(struct libscols_table *tb, const char *name)
|
||||
{
|
||||
char *p = NULL;
|
||||
|
||||
if (!tb)
|
||||
return -EINVAL;
|
||||
|
||||
if (name) {
|
||||
p = strdup(name);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
}
|
||||
free(tb->name);
|
||||
tb->name = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* scols_table_add_column:
|
||||
* @tb: a pointer to a struct libscols_table instance
|
||||
|
@ -659,6 +687,7 @@ int scols_table_set_symbols(struct libscols_table *tb,
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* scols_table_enable_colors:
|
||||
* @tb: table
|
||||
|
@ -677,13 +706,14 @@ int scols_table_enable_colors(struct libscols_table *tb, int enable)
|
|||
tb->colors_wanted = enable;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* scols_table_enable_raw:
|
||||
* @tb: table
|
||||
* @enable: 1 or 0
|
||||
*
|
||||
* Enable/disable raw output format. The parsable output formats
|
||||
* (export and raw) are mutually exclusive.
|
||||
* (export, raw, JSON, ...) are mutually exclusive.
|
||||
*
|
||||
* Returns: 0 on success, negative number in case of an error.
|
||||
*/
|
||||
|
@ -700,6 +730,29 @@ int scols_table_enable_raw(struct libscols_table *tb, int enable)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* scols_table_enable_json:
|
||||
* @tb: table
|
||||
* @enable: 1 or 0
|
||||
*
|
||||
* Enable/disable JSON output format. The parsable output formats
|
||||
* (export, raw, JSON, ...) are mutually exclusive.
|
||||
*
|
||||
* Returns: 0 on success, negative number in case of an error.
|
||||
*/
|
||||
int scols_table_enable_json(struct libscols_table *tb, int enable)
|
||||
{
|
||||
if (!tb)
|
||||
return -EINVAL;
|
||||
|
||||
DBG(TAB, ul_debugobj(tb, "json: %s", enable ? "ENABLE" : "DISABLE"));
|
||||
if (enable)
|
||||
tb->format = SCOLS_FMT_JSON;
|
||||
else if (tb->format == SCOLS_FMT_JSON)
|
||||
tb->format = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* scols_table_enable_export:
|
||||
* @tb: table
|
||||
|
@ -851,6 +904,17 @@ int scols_table_is_raw(struct libscols_table *tb)
|
|||
return tb && tb->format == SCOLS_FMT_RAW;
|
||||
}
|
||||
|
||||
/**
|
||||
* scols_table_is_json:
|
||||
* @tb: table
|
||||
*
|
||||
* Returns: 1 if JSON output format is enabled.
|
||||
*/
|
||||
int scols_table_is_json(struct libscols_table *tb)
|
||||
{
|
||||
return tb && tb->format == SCOLS_FMT_JSON;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* scols_table_is_maxout
|
||||
|
|
|
@ -269,21 +269,33 @@ static int print_data(struct libscols_table *tb,
|
|||
if (!data)
|
||||
data = "";
|
||||
|
||||
/* raw mode */
|
||||
if (scols_table_is_raw(tb)) {
|
||||
switch (tb->format) {
|
||||
case SCOLS_FMT_RAW:
|
||||
fputs_nonblank(data, tb->out);
|
||||
if (!is_last_column(tb, cl))
|
||||
fputs(colsep(tb), tb->out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* NAME=value mode */
|
||||
if (scols_table_is_export(tb)) {
|
||||
case SCOLS_FMT_EXPORT:
|
||||
fprintf(tb->out, "%s=", scols_cell_get_data(&cl->header));
|
||||
fputs_quoted(data, tb->out);
|
||||
if (!is_last_column(tb, cl))
|
||||
fputs(colsep(tb), tb->out);
|
||||
return 0;
|
||||
|
||||
case SCOLS_FMT_JSON:
|
||||
fputs_quoted(scols_cell_get_data(&cl->header), tb->out);
|
||||
fputs(": ", tb->out);
|
||||
if (!data || !*data)
|
||||
fputs("null", tb->out);
|
||||
else
|
||||
fputs_quoted(data, tb->out);
|
||||
if (!is_last_column(tb, cl))
|
||||
fputs(", ", tb->out);
|
||||
return 0;
|
||||
|
||||
case SCOLS_FMT_HUMAN:
|
||||
break; /* continue below */
|
||||
}
|
||||
|
||||
if (tb->colors_wanted) {
|
||||
|
@ -384,7 +396,7 @@ static int cell_to_buffer(struct libscols_table *tb,
|
|||
/*
|
||||
* Tree stuff
|
||||
*/
|
||||
if (ln->parent) {
|
||||
if (ln->parent && !scols_table_is_json(tb)) {
|
||||
rc = line_ascii_art_to_buffer(tb, ln->parent, buf);
|
||||
|
||||
if (!rc && list_entry_is_last(&ln->ln_children, &ln->parent->ln_branch))
|
||||
|
@ -400,6 +412,95 @@ static int cell_to_buffer(struct libscols_table *tb,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void fput_indent(struct libscols_table *tb)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= tb->indent; i++)
|
||||
fputs(" ", tb->out);
|
||||
}
|
||||
|
||||
static void fput_table_open(struct libscols_table *tb)
|
||||
{
|
||||
tb->indent = 0;
|
||||
|
||||
if (scols_table_is_json(tb)) {
|
||||
fputc('{', tb->out);
|
||||
fputs(linesep(tb), tb->out);
|
||||
|
||||
fput_indent(tb);
|
||||
fputs_quoted(tb->name, tb->out);
|
||||
fputs(": [", tb->out);
|
||||
fputs(linesep(tb), tb->out);
|
||||
|
||||
tb->indent++;
|
||||
tb->indent_last_sep = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void fput_table_close(struct libscols_table *tb)
|
||||
{
|
||||
tb->indent--;
|
||||
|
||||
if (scols_table_is_json(tb)) {
|
||||
fput_indent(tb);
|
||||
fputc(']', tb->out);
|
||||
tb->indent--;
|
||||
fputs(linesep(tb), tb->out);
|
||||
fputc('}', tb->out);
|
||||
fputs(linesep(tb), tb->out);
|
||||
tb->indent_last_sep = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void fput_children_open(struct libscols_table *tb)
|
||||
{
|
||||
if (scols_table_is_json(tb)) {
|
||||
fputc(',', tb->out);
|
||||
fputs(linesep(tb), tb->out);
|
||||
fput_indent(tb);
|
||||
fputs("\"children\": [", tb->out);
|
||||
}
|
||||
/* between parent and child is separator */
|
||||
fputs(linesep(tb), tb->out);
|
||||
tb->indent_last_sep = 1;
|
||||
tb->indent++;
|
||||
}
|
||||
|
||||
static void fput_children_close(struct libscols_table *tb)
|
||||
{
|
||||
tb->indent--;
|
||||
|
||||
if (scols_table_is_json(tb)) {
|
||||
fput_indent(tb);
|
||||
fputc(']', tb->out);
|
||||
fputs(linesep(tb), tb->out);
|
||||
tb->indent_last_sep = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void fput_line_open(struct libscols_table *tb)
|
||||
{
|
||||
if (scols_table_is_json(tb)) {
|
||||
fput_indent(tb);
|
||||
fputc('{', tb->out);
|
||||
tb->indent_last_sep = 0;
|
||||
}
|
||||
tb->indent++;
|
||||
}
|
||||
|
||||
static void fput_line_close(struct libscols_table *tb, int last)
|
||||
{
|
||||
tb->indent--;
|
||||
if (scols_table_is_json(tb)) {
|
||||
if (tb->indent_last_sep)
|
||||
fput_indent(tb);
|
||||
fputs(last ? "}" : "},", tb->out);
|
||||
}
|
||||
fputs(linesep(tb), tb->out);
|
||||
tb->indent_last_sep = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prints data. Data can be printed in more formats (raw, NAME=xxx pairs), and
|
||||
* control and non-printable characters can be encoded in the \x?? encoding.
|
||||
|
@ -425,8 +526,6 @@ static int print_line(struct libscols_table *tb,
|
|||
buf);
|
||||
}
|
||||
|
||||
if (rc == 0)
|
||||
fputs(linesep(tb), tb->out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -460,63 +559,82 @@ static int print_header(struct libscols_table *tb, struct libscols_buffer *buf)
|
|||
|
||||
static int print_table(struct libscols_table *tb, struct libscols_buffer *buf)
|
||||
{
|
||||
int rc;
|
||||
int rc = 0;
|
||||
struct libscols_line *ln;
|
||||
struct libscols_iter itr;
|
||||
|
||||
assert(tb);
|
||||
|
||||
rc = print_header(tb, buf);
|
||||
|
||||
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||||
while (rc == 0 && scols_table_next_line(tb, &itr, &ln) == 0)
|
||||
while (rc == 0 && scols_table_next_line(tb, &itr, &ln) == 0) {
|
||||
fput_line_open(tb);
|
||||
rc = print_line(tb, ln, buf);
|
||||
fput_line_close(tb, scols_iter_is_last(&itr));
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int print_tree_line(struct libscols_table *tb,
|
||||
struct libscols_line *ln,
|
||||
struct libscols_buffer *buf)
|
||||
struct libscols_buffer *buf,
|
||||
int last)
|
||||
{
|
||||
int rc;
|
||||
struct list_head *p;
|
||||
|
||||
fput_line_open(tb);
|
||||
|
||||
rc = print_line(tb, ln, buf);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (list_empty(&ln->ln_branch))
|
||||
goto done;
|
||||
|
||||
if (list_empty(&ln->ln_branch)) {
|
||||
fput_line_close(tb, last);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fput_children_open(tb);
|
||||
|
||||
/* print all children */
|
||||
list_for_each(p, &ln->ln_branch) {
|
||||
struct libscols_line *chld =
|
||||
list_entry(p, struct libscols_line, ln_children);
|
||||
rc = print_tree_line(tb, chld, buf);
|
||||
|
||||
rc = print_tree_line(tb, chld, buf, p->next == &ln->ln_branch);
|
||||
if (rc)
|
||||
break;
|
||||
goto done;
|
||||
}
|
||||
|
||||
fput_children_close(tb);
|
||||
|
||||
if (scols_table_is_json(tb))
|
||||
fput_line_close(tb, last);
|
||||
done:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int print_tree(struct libscols_table *tb, struct libscols_buffer *buf)
|
||||
{
|
||||
int rc;
|
||||
struct libscols_line *ln;
|
||||
int rc = 0;
|
||||
struct libscols_line *ln, *last = NULL;
|
||||
struct libscols_iter itr;
|
||||
|
||||
assert(tb);
|
||||
|
||||
DBG(TAB, ul_debugobj(tb, "printing tree"));
|
||||
|
||||
rc = print_header(tb, buf);
|
||||
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||||
|
||||
while (scols_table_next_line(tb, &itr, &ln) == 0)
|
||||
if (!last || !ln->parent)
|
||||
last = ln;
|
||||
|
||||
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||||
while (rc == 0 && scols_table_next_line(tb, &itr, &ln) == 0) {
|
||||
if (ln->parent)
|
||||
continue;
|
||||
rc = print_tree_line(tb, ln, buf);
|
||||
rc = print_tree_line(tb, ln, buf, ln == last);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
@ -852,11 +970,20 @@ int scols_print_table(struct libscols_table *tb)
|
|||
goto done;
|
||||
}
|
||||
|
||||
fput_table_open(tb);
|
||||
|
||||
if (!scols_table_is_json(tb)) {
|
||||
rc = print_header(tb, buf);
|
||||
if (rc)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (scols_table_is_tree(tb))
|
||||
rc = print_tree(tb, buf);
|
||||
else
|
||||
rc = print_table(tb, buf);
|
||||
|
||||
fput_table_close(tb);
|
||||
done:
|
||||
free_buffer(buf);
|
||||
return rc;
|
||||
|
|
Loading…
Reference in New Issue