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
return 0;
}
+
/**
* scols_table_enable_colors:
* @tb: table
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.
*/
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
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
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) {
/*
* 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))
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.
buf);
}
- if (rc == 0)
- fputs(linesep(tb), tb->out);
return 0;
}
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;
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;