summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarel Zak2015-06-04 15:47:21 +0200
committerKarel Zak2015-06-04 15:47:21 +0200
commit2a6cfc1361e793c595f53987b83506382caa2d9b (patch)
tree293e018da8163f671572ec2d5cb47b4ba5b63961
parentlibmount: (docs) fix wording (diff)
downloadkernel-qcow2-util-linux-2a6cfc1361e793c595f53987b83506382caa2d9b.tar.gz
kernel-qcow2-util-linux-2a6cfc1361e793c595f53987b83506382caa2d9b.tar.xz
kernel-qcow2-util-linux-2a6cfc1361e793c595f53987b83506382caa2d9b.zip
libsmartcols: add JSON output format
Signed-off-by: Karel Zak <kzak@redhat.com>
-rw-r--r--libsmartcols/docs/libsmartcols-sections.txt3
-rw-r--r--libsmartcols/src/libsmartcols.h.in3
-rw-r--r--libsmartcols/src/libsmartcols.sym10
-rw-r--r--libsmartcols/src/smartcolsP.h15
-rw-r--r--libsmartcols/src/table.c66
-rw-r--r--libsmartcols/src/table_print.c169
6 files changed, 242 insertions, 24 deletions
diff --git a/libsmartcols/docs/libsmartcols-sections.txt b/libsmartcols/docs/libsmartcols-sections.txt
index 2b8180c52..01bc2a63c 100644
--- a/libsmartcols/docs/libsmartcols-sections.txt
+++ b/libsmartcols/docs/libsmartcols-sections.txt
@@ -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
diff --git a/libsmartcols/src/libsmartcols.h.in b/libsmartcols/src/libsmartcols.h.in
index e61256022..d2a88c9cd 100644
--- a/libsmartcols/src/libsmartcols.h.in
+++ b/libsmartcols/src/libsmartcols.h.in
@@ -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);
diff --git a/libsmartcols/src/libsmartcols.sym b/libsmartcols/src/libsmartcols.sym
index 2629213c1..0ef3322b3 100644
--- a/libsmartcols/src/libsmartcols.sym
+++ b/libsmartcols/src/libsmartcols.sym
@@ -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;
diff --git a/libsmartcols/src/smartcolsP.h b/libsmartcols/src/smartcolsP.h
index 511b182a2..c4fe725d0 100644
--- a/libsmartcols/src/smartcolsP.h
+++ b/libsmartcols/src/smartcolsP.h
@@ -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 */
diff --git a/libsmartcols/src/table.c b/libsmartcols/src/table.c
index 45d6a309c..a42ae514d 100644
--- a/libsmartcols/src/table.c
+++ b/libsmartcols/src/table.c
@@ -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.
*/
@@ -701,6 +731,29 @@ int scols_table_enable_raw(struct libscols_table *tb, int enable)
}
/**
+ * 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
* @enable: 1 or 0
@@ -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
diff --git a/libsmartcols/src/table_print.c b/libsmartcols/src/table_print.c
index fbca28a1f..37d75c962 100644
--- a/libsmartcols/src/table_print.c
+++ b/libsmartcols/src/table_print.c
@@ -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;