]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libsmartcols: add JSON output format
authorKarel Zak <kzak@redhat.com>
Thu, 4 Jun 2015 13:47:21 +0000 (15:47 +0200)
committerKarel Zak <kzak@redhat.com>
Thu, 4 Jun 2015 13:47:21 +0000 (15:47 +0200)
Signed-off-by: Karel Zak <kzak@redhat.com>
libsmartcols/docs/libsmartcols-sections.txt
libsmartcols/src/libsmartcols.h.in
libsmartcols/src/libsmartcols.sym
libsmartcols/src/smartcolsP.h
libsmartcols/src/table.c
libsmartcols/src/table_print.c

index 2b8180c52a478bdc6888c8e519085b4f96781ff3..01bc2a63c13dd55cc5b219b5e8eb6cab9d84319a 100644 (file)
@@ -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
index e61256022610b931306d6d0ee9a145f0ddf8a803..d2a88c9cdb9128100fcc4f7bedec81893784f629 100644 (file)
@@ -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);
index 2629213c19bd74a4e381fbbdbeb491b60a2ad55b..0ef3322b384e8c3a6adb100406205b7356825a2e 100644 (file)
@@ -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;
index 511b182a249254d33d7c727a9f3339dc4eab4153..c4fe725d0b1253e38c78e102221f52207a272cd7 100644 (file)
@@ -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 */
index 45d6a309cb95ec1673544763189a8f6638ee7261..a42ae514dae6bc8318f9890373dcc88f521874d6 100644 (file)
@@ -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
index fbca28a1f62ad9207ea94f2aff8e0a01315a335c..37d75c9627b5d41055e8f38eef690c697f1a009b 100644 (file)
@@ -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;