Merge pull request #11037 from poettering/json-table
optionally output tables as JSON
This commit is contained in:
@@ -1399,7 +1399,7 @@ static int assess(const struct security_info *info, Table *overview_table, Analy
|
||||
int r;
|
||||
|
||||
if (!FLAGS_SET(flags, ANALYZE_SECURITY_SHORT)) {
|
||||
details_table = table_new("", "NAME", "DESCRIPTION", "WEIGHT", "BADNESS", "RANGE", "EXPOSURE");
|
||||
details_table = table_new(" ", "name", "description", "weight", "badness", "range", "exposure");
|
||||
if (!details_table)
|
||||
return log_oom();
|
||||
|
||||
@@ -1973,7 +1973,7 @@ int analyze_security(sd_bus *bus, char **units, AnalyzeSecurityFlags flags) {
|
||||
assert(bus);
|
||||
|
||||
if (strv_length(units) != 1) {
|
||||
overview_table = table_new("UNIT", "EXPOSURE", "PREDICATE", "HAPPY");
|
||||
overview_table = table_new("unit", "exposure", "predicate", "happy");
|
||||
if (!overview_table)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
+1
-1
@@ -1939,7 +1939,7 @@ static void json_dump_with_flags(JsonVariant *v, FILE *f) {
|
||||
|
||||
json_variant_dump(v,
|
||||
(arg_json == JSON_PRETTY ? JSON_FORMAT_PRETTY : JSON_FORMAT_NEWLINE) |
|
||||
colors_enabled() * JSON_FORMAT_COLOR,
|
||||
JSON_FORMAT_COLOR_AUTO,
|
||||
f, NULL);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -83,7 +83,7 @@ static int print_inhibitors(sd_bus *bus) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not get active inhibitors: %s", bus_error_message(&error, r));
|
||||
|
||||
table = table_new("WHO", "UID", "USER", "PID", "COMM", "WHAT", "WHY", "MODE");
|
||||
table = table_new("who", "uid", "user", "pid", "comm", "what", "why", "mode");
|
||||
if (!table)
|
||||
return log_oom();
|
||||
|
||||
|
||||
+11
-4
@@ -101,7 +101,10 @@ static int show_table(Table *table, const char *word) {
|
||||
|
||||
table_set_header(table, arg_legend);
|
||||
|
||||
r = table_print(table, NULL);
|
||||
if (OUTPUT_MODE_IS_JSON(arg_output))
|
||||
r = table_print_json(table, NULL, output_mode_to_json_format_flags(arg_output) | JSON_FORMAT_COLOR_AUTO);
|
||||
else
|
||||
r = table_print(table, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to show table: %m");
|
||||
}
|
||||
@@ -143,7 +146,7 @@ static int list_sessions(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
table = table_new("SESSION", "UID", "USER", "SEAT", "TTY");
|
||||
table = table_new("session", "uid", "user", "seat", "tty");
|
||||
if (!table)
|
||||
return log_oom();
|
||||
|
||||
@@ -224,7 +227,7 @@ static int list_users(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
table = table_new("UID", "USER");
|
||||
table = table_new("uid", "user");
|
||||
if (!table)
|
||||
return log_oom();
|
||||
|
||||
@@ -281,7 +284,7 @@ static int list_seats(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
table = table_new("SEAT");
|
||||
table = table_new("seat");
|
||||
if (!table)
|
||||
return log_oom();
|
||||
|
||||
@@ -1434,6 +1437,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (arg_output < 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Unknown output '%s'.", optarg);
|
||||
|
||||
if (OUTPUT_MODE_IS_JSON(arg_output))
|
||||
arg_legend = false;
|
||||
|
||||
break;
|
||||
|
||||
case ARG_NO_PAGER:
|
||||
|
||||
@@ -259,7 +259,10 @@ static int show_table(Table *table, const char *word) {
|
||||
|
||||
table_set_header(table, arg_legend);
|
||||
|
||||
r = table_print(table, NULL);
|
||||
if (OUTPUT_MODE_IS_JSON(arg_output))
|
||||
r = table_print_json(table, NULL, output_mode_to_json_format_flags(arg_output) | JSON_FORMAT_COLOR_AUTO);
|
||||
else
|
||||
r = table_print(table, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to show table: %m");
|
||||
}
|
||||
@@ -297,7 +300,7 @@ static int list_machines(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not get machines: %s", bus_error_message(&error, r));
|
||||
|
||||
table = table_new("MACHINE", "CLASS", "SERVICE", "OS", "VERSION", "ADDRESSES");
|
||||
table = table_new("machine", "class", "service", "os", "version", "addresses");
|
||||
if (!table)
|
||||
return log_oom();
|
||||
|
||||
@@ -377,7 +380,7 @@ static int list_images(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not get images: %s", bus_error_message(&error, r));
|
||||
|
||||
table = table_new("NAME", "TYPE", "RO", "USAGE", "CREATED", "MODIFIED");
|
||||
table = table_new("name", "type", "ro", "usage", "created", "modified");
|
||||
if (!table)
|
||||
return log_oom();
|
||||
|
||||
@@ -2921,6 +2924,9 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (arg_output < 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Unknown output '%s'.", optarg);
|
||||
|
||||
if (OUTPUT_MODE_IS_JSON(arg_output))
|
||||
arg_legend = false;
|
||||
break;
|
||||
|
||||
case ARG_NO_PAGER:
|
||||
|
||||
@@ -500,7 +500,7 @@ static int list_images(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to list images: %s", bus_error_message(&error, r));
|
||||
|
||||
table = table_new("NAME", "TYPE", "RO", "CRTIME", "MTIME", "USAGE", "STATE");
|
||||
table = table_new("name", "type", "ro", "crtime", "mtime", "usage", "state");
|
||||
if (!table)
|
||||
return log_oom();
|
||||
|
||||
|
||||
+222
-13
@@ -1,5 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio_ext.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
@@ -58,6 +59,8 @@ typedef struct TableData {
|
||||
unsigned ellipsize_percent; /* 0 … 100, where to place the ellipsis when compression is needed */
|
||||
unsigned align_percent; /* 0 … 100, where to pad with spaces when expanding is needed. 0: left-aligned, 100: right-aligned */
|
||||
|
||||
bool uppercase; /* Uppercase string on display */
|
||||
|
||||
const char *color; /* ANSI color string to use for this cell. When written to terminal should not move cursor. Will automatically be reset after the cell */
|
||||
char *url; /* A URL to use for a clickable hyperlink */
|
||||
char *formatted; /* A cached textual representation of the cell data, before ellipsation/alignment */
|
||||
@@ -132,6 +135,7 @@ Table *table_new_raw(size_t n_columns) {
|
||||
Table *table_new_internal(const char *first_header, ...) {
|
||||
_cleanup_(table_unrefp) Table *t = NULL;
|
||||
size_t n_columns = 1;
|
||||
const char *h;
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
@@ -139,8 +143,6 @@ Table *table_new_internal(const char *first_header, ...) {
|
||||
|
||||
va_start(ap, first_header);
|
||||
for (;;) {
|
||||
const char *h;
|
||||
|
||||
h = va_arg(ap, const char*);
|
||||
if (!h)
|
||||
break;
|
||||
@@ -153,19 +155,18 @@ Table *table_new_internal(const char *first_header, ...) {
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
r = table_add_cell(t, NULL, TABLE_STRING, first_header);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
|
||||
va_start(ap, first_header);
|
||||
for (;;) {
|
||||
const char *h;
|
||||
for (h = first_header; h; h = va_arg(ap, const char*)) {
|
||||
TableCell *cell;
|
||||
|
||||
h = va_arg(ap, const char*);
|
||||
if (!h)
|
||||
break;
|
||||
r = table_add_cell(t, &cell, TABLE_STRING, h);
|
||||
if (r < 0) {
|
||||
va_end(ap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = table_add_cell(t, NULL, TABLE_STRING, h);
|
||||
/* Make the table header uppercase */
|
||||
r = table_set_uppercase(t, cell, true);
|
||||
if (r < 0) {
|
||||
va_end(ap);
|
||||
return NULL;
|
||||
@@ -269,6 +270,14 @@ static bool table_data_matches(
|
||||
if (d->ellipsize_percent != ellipsize_percent)
|
||||
return false;
|
||||
|
||||
/* If a color/url/uppercase flag is set, refuse to merge */
|
||||
if (d->color)
|
||||
return false;
|
||||
if (d->url)
|
||||
return false;
|
||||
if (d->uppercase)
|
||||
return false;
|
||||
|
||||
k = table_data_size(type, data);
|
||||
l = table_data_size(d->type, d->data);
|
||||
|
||||
@@ -427,6 +436,7 @@ static int table_dedup_cell(Table *t, TableCell *cell) {
|
||||
|
||||
nd->color = od->color;
|
||||
nd->url = TAKE_PTR(curl);
|
||||
nd->uppercase = od->uppercase;
|
||||
|
||||
table_data_unref(od);
|
||||
t->data[i] = nd;
|
||||
@@ -574,6 +584,27 @@ int table_set_url(Table *t, TableCell *cell, const char *url) {
|
||||
return free_and_replace(table_get_data(t, cell)->url, copy);
|
||||
}
|
||||
|
||||
int table_set_uppercase(Table *t, TableCell *cell, bool b) {
|
||||
TableData *d;
|
||||
int r;
|
||||
|
||||
assert(t);
|
||||
assert(cell);
|
||||
|
||||
r = table_dedup_cell(t, cell);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
assert_se(d = table_get_data(t, cell));
|
||||
|
||||
if (d->uppercase == b)
|
||||
return 0;
|
||||
|
||||
d->formatted = mfree(d->formatted);
|
||||
d->uppercase = b;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int table_update(Table *t, TableCell *cell, TableDataType type, const void *data) {
|
||||
_cleanup_free_ char *curl = NULL;
|
||||
TableData *nd, *od;
|
||||
@@ -607,6 +638,7 @@ int table_update(Table *t, TableCell *cell, TableDataType type, const void *data
|
||||
|
||||
nd->color = od->color;
|
||||
nd->url = TAKE_PTR(curl);
|
||||
nd->uppercase = od->uppercase;
|
||||
|
||||
table_data_unref(od);
|
||||
t->data[i] = nd;
|
||||
@@ -858,6 +890,20 @@ static const char *table_data_format(TableData *d) {
|
||||
return "";
|
||||
|
||||
case TABLE_STRING:
|
||||
if (d->uppercase) {
|
||||
char *p, *q;
|
||||
|
||||
d->formatted = new(char, strlen(d->string) + 1);
|
||||
if (!d->formatted)
|
||||
return NULL;
|
||||
|
||||
for (p = d->string, q = d->formatted; *p; p++, q++)
|
||||
*q = (char) toupper((unsigned char) *p);
|
||||
*q = 0;
|
||||
|
||||
return d->formatted;
|
||||
}
|
||||
|
||||
return d->string;
|
||||
|
||||
case TABLE_BOOLEAN:
|
||||
@@ -884,7 +930,7 @@ static const char *table_data_format(TableData *d) {
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
if (!format_timespan(p, FORMAT_TIMESPAN_MAX, d->timestamp, 0))
|
||||
if (!format_timespan(p, FORMAT_TIMESPAN_MAX, d->timespan, 0))
|
||||
return "n/a";
|
||||
|
||||
d->formatted = TAKE_PTR(p);
|
||||
@@ -1414,3 +1460,166 @@ const void* table_get_at(Table *t, size_t row, size_t column) {
|
||||
|
||||
return table_get(t, cell);
|
||||
}
|
||||
|
||||
static int table_data_to_json(TableData *d, JsonVariant **ret) {
|
||||
|
||||
switch (d->type) {
|
||||
|
||||
case TABLE_EMPTY:
|
||||
return json_variant_new_null(ret);
|
||||
|
||||
case TABLE_STRING:
|
||||
return json_variant_new_string(ret, d->string);
|
||||
|
||||
case TABLE_BOOLEAN:
|
||||
return json_variant_new_boolean(ret, d->boolean);
|
||||
|
||||
case TABLE_TIMESTAMP:
|
||||
if (d->timestamp == USEC_INFINITY)
|
||||
return json_variant_new_null(ret);
|
||||
|
||||
return json_variant_new_unsigned(ret, d->timestamp);
|
||||
|
||||
case TABLE_TIMESPAN:
|
||||
if (d->timespan == USEC_INFINITY)
|
||||
return json_variant_new_null(ret);
|
||||
|
||||
return json_variant_new_unsigned(ret, d->timespan);
|
||||
|
||||
case TABLE_SIZE:
|
||||
if (d->size == (size_t) -1)
|
||||
return json_variant_new_null(ret);
|
||||
|
||||
return json_variant_new_unsigned(ret, d->size);
|
||||
|
||||
case TABLE_UINT32:
|
||||
return json_variant_new_unsigned(ret, d->uint32);
|
||||
|
||||
case TABLE_UINT64:
|
||||
return json_variant_new_unsigned(ret, d->uint64);
|
||||
|
||||
case TABLE_PERCENT:
|
||||
return json_variant_new_integer(ret, d->percent);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int table_to_json(Table *t, JsonVariant **ret) {
|
||||
JsonVariant **rows = NULL, **elements = NULL;
|
||||
_cleanup_free_ size_t *sorted = NULL;
|
||||
size_t n_rows, i, j, display_columns;
|
||||
int r;
|
||||
|
||||
assert(t);
|
||||
|
||||
/* Ensure we have no incomplete rows */
|
||||
assert(t->n_cells % t->n_columns == 0);
|
||||
|
||||
n_rows = t->n_cells / t->n_columns;
|
||||
assert(n_rows > 0); /* at least the header row must be complete */
|
||||
|
||||
if (t->sort_map) {
|
||||
/* If sorting is requested, let's calculate an index table we use to lookup the actual index to display with. */
|
||||
|
||||
sorted = new(size_t, n_rows);
|
||||
if (!sorted) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_rows; i++)
|
||||
sorted[i] = i * t->n_columns;
|
||||
|
||||
typesafe_qsort_r(sorted, n_rows, table_data_compare, t);
|
||||
}
|
||||
|
||||
if (t->display_map)
|
||||
display_columns = t->n_display_map;
|
||||
else
|
||||
display_columns = t->n_columns;
|
||||
assert(display_columns > 0);
|
||||
|
||||
elements = new0(JsonVariant*, display_columns * 2);
|
||||
if (!elements) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
for (j = 0; j < display_columns; j++) {
|
||||
TableData *d;
|
||||
|
||||
assert_se(d = t->data[t->display_map ? t->display_map[j] : j]);
|
||||
|
||||
r = table_data_to_json(d, elements + j*2);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
rows = new0(JsonVariant*, n_rows-1);
|
||||
if (!rows) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
for (i = 1; i < n_rows; i++) {
|
||||
TableData **row;
|
||||
|
||||
if (sorted)
|
||||
row = t->data + sorted[i];
|
||||
else
|
||||
row = t->data + i * t->n_columns;
|
||||
|
||||
for (j = 0; j < display_columns; j++) {
|
||||
TableData *d;
|
||||
size_t k;
|
||||
|
||||
assert_se(d = row[t->display_map ? t->display_map[j] : j]);
|
||||
|
||||
k = j*2+1;
|
||||
elements[k] = json_variant_unref(elements[k]);
|
||||
|
||||
r = table_data_to_json(d, elements + k);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = json_variant_new_object(rows + i - 1, elements, display_columns * 2);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = json_variant_new_array(ret, rows, n_rows - 1);
|
||||
|
||||
finish:
|
||||
if (rows) {
|
||||
json_variant_unref_many(rows, n_rows-1);
|
||||
free(rows);
|
||||
}
|
||||
|
||||
if (elements) {
|
||||
json_variant_unref_many(elements, display_columns*2);
|
||||
free(elements);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int table_print_json(Table *t, FILE *f, JsonFormatFlags flags) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
int r;
|
||||
|
||||
assert(t);
|
||||
|
||||
if (!f)
|
||||
f = stdout;
|
||||
|
||||
r = table_to_json(t, &v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
json_variant_dump(v, flags, f, NULL);
|
||||
|
||||
return fflush_and_check(f);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "json.h"
|
||||
#include "macro.h"
|
||||
|
||||
typedef enum TableDataType {
|
||||
@@ -45,6 +46,7 @@ int table_set_align_percent(Table *t, TableCell *cell, unsigned percent);
|
||||
int table_set_ellipsize_percent(Table *t, TableCell *cell, unsigned percent);
|
||||
int table_set_color(Table *t, TableCell *cell, const char *color);
|
||||
int table_set_url(Table *t, TableCell *cell, const char *color);
|
||||
int table_set_uppercase(Table *t, TableCell *cell, bool b);
|
||||
|
||||
int table_update(Table *t, TableCell *cell, TableDataType type, const void *data);
|
||||
|
||||
@@ -71,3 +73,6 @@ TableCell *table_get_cell(Table *t, size_t row, size_t column);
|
||||
|
||||
const void *table_get(Table *t, TableCell *cell);
|
||||
const void *table_get_at(Table *t, size_t row, size_t column);
|
||||
|
||||
int table_to_json(Table *t, JsonVariant **ret);
|
||||
int table_print_json(Table *t, FILE *f, unsigned json_flags);
|
||||
|
||||
+7
-4
@@ -1236,7 +1236,7 @@ int json_variant_get_source(JsonVariant *v, const char **ret_source, unsigned *r
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_source(FILE *f, JsonVariant *v, unsigned flags, bool whitespace) {
|
||||
static int print_source(FILE *f, JsonVariant *v, JsonFormatFlags flags, bool whitespace) {
|
||||
size_t w, k;
|
||||
|
||||
if (!FLAGS_SET(flags, JSON_FORMAT_SOURCE|JSON_FORMAT_PRETTY))
|
||||
@@ -1289,7 +1289,7 @@ static int print_source(FILE *f, JsonVariant *v, unsigned flags, bool whitespace
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int json_format(FILE *f, JsonVariant *v, unsigned flags, const char *prefix) {
|
||||
static int json_format(FILE *f, JsonVariant *v, JsonFormatFlags flags, const char *prefix) {
|
||||
int r;
|
||||
|
||||
assert(f);
|
||||
@@ -1546,7 +1546,7 @@ static int json_format(FILE *f, JsonVariant *v, unsigned flags, const char *pref
|
||||
return 0;
|
||||
}
|
||||
|
||||
int json_variant_format(JsonVariant *v, unsigned flags, char **ret) {
|
||||
int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
size_t sz = 0;
|
||||
int r;
|
||||
@@ -1576,7 +1576,7 @@ int json_variant_format(JsonVariant *v, unsigned flags, char **ret) {
|
||||
return (int) sz;
|
||||
}
|
||||
|
||||
void json_variant_dump(JsonVariant *v, unsigned flags, FILE *f, const char *prefix) {
|
||||
void json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix) {
|
||||
if (!v)
|
||||
return;
|
||||
|
||||
@@ -1585,6 +1585,9 @@ void json_variant_dump(JsonVariant *v, unsigned flags, FILE *f, const char *pref
|
||||
|
||||
print_source(f, v, flags, false);
|
||||
|
||||
if (((flags & (JSON_FORMAT_COLOR_AUTO|JSON_FORMAT_COLOR)) == JSON_FORMAT_COLOR_AUTO) && colors_enabled())
|
||||
flags |= JSON_FORMAT_COLOR;
|
||||
|
||||
if (flags & JSON_FORMAT_SSE)
|
||||
fputs("data: ", f);
|
||||
if (flags & JSON_FORMAT_SEQ)
|
||||
|
||||
+11
-10
@@ -150,17 +150,18 @@ struct json_variant_foreach_state {
|
||||
|
||||
int json_variant_get_source(JsonVariant *v, const char **ret_source, unsigned *ret_line, unsigned *ret_column);
|
||||
|
||||
enum {
|
||||
JSON_FORMAT_NEWLINE = 1 << 0, /* suffix with newline */
|
||||
JSON_FORMAT_PRETTY = 1 << 1, /* add internal whitespace to appeal to human readers */
|
||||
JSON_FORMAT_COLOR = 1 << 2, /* insert ANSI color sequences */
|
||||
JSON_FORMAT_SOURCE = 1 << 3, /* prefix with source filename/line/column */
|
||||
JSON_FORMAT_SSE = 1 << 4, /* prefix/suffix with W3C server-sent events */
|
||||
JSON_FORMAT_SEQ = 1 << 5, /* prefix/suffix with RFC 7464 application/json-seq */
|
||||
};
|
||||
typedef enum JsonFormatFlags {
|
||||
JSON_FORMAT_NEWLINE = 1 << 0, /* suffix with newline */
|
||||
JSON_FORMAT_PRETTY = 1 << 1, /* add internal whitespace to appeal to human readers */
|
||||
JSON_FORMAT_COLOR = 1 << 2, /* insert ANSI color sequences */
|
||||
JSON_FORMAT_COLOR_AUTO = 1 << 3, /* insetr ANSI color sequences if colors_enabled() says so */
|
||||
JSON_FORMAT_SOURCE = 1 << 4, /* prefix with source filename/line/column */
|
||||
JSON_FORMAT_SSE = 1 << 5, /* prefix/suffix with W3C server-sent events */
|
||||
JSON_FORMAT_SEQ = 1 << 6, /* prefix/suffix with RFC 7464 application/json-seq */
|
||||
} JsonFormatFlags;
|
||||
|
||||
int json_variant_format(JsonVariant *v, unsigned flags, char **ret);
|
||||
void json_variant_dump(JsonVariant *v, unsigned flags, FILE *f, const char *prefix);
|
||||
int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret);
|
||||
void json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix);
|
||||
|
||||
int json_parse(const char *string, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
|
||||
int json_parse_continue(const char **p, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
|
||||
|
||||
@@ -946,10 +946,7 @@ static int output_json(
|
||||
}
|
||||
|
||||
json_variant_dump(object,
|
||||
(mode == OUTPUT_JSON_SSE ? JSON_FORMAT_SSE :
|
||||
mode == OUTPUT_JSON_SEQ ? JSON_FORMAT_SEQ :
|
||||
mode == OUTPUT_JSON_PRETTY ? JSON_FORMAT_PRETTY :
|
||||
JSON_FORMAT_NEWLINE) |
|
||||
output_mode_to_json_format_flags(mode) |
|
||||
(FLAGS_SET(flags, OUTPUT_COLOR) ? JSON_FORMAT_COLOR : 0),
|
||||
f, NULL);
|
||||
|
||||
|
||||
@@ -3,6 +3,24 @@
|
||||
#include "output-mode.h"
|
||||
#include "string-table.h"
|
||||
|
||||
JsonFormatFlags output_mode_to_json_format_flags(OutputMode m) {
|
||||
|
||||
switch (m) {
|
||||
|
||||
case OUTPUT_JSON_SSE:
|
||||
return JSON_FORMAT_SSE;
|
||||
|
||||
case OUTPUT_JSON_SEQ:
|
||||
return JSON_FORMAT_SEQ;
|
||||
|
||||
case OUTPUT_JSON_PRETTY:
|
||||
return JSON_FORMAT_PRETTY;
|
||||
|
||||
default:
|
||||
return JSON_FORMAT_NEWLINE;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
|
||||
[OUTPUT_SHORT] = "short",
|
||||
[OUTPUT_SHORT_FULL] = "short-full",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#pragma once
|
||||
|
||||
#include "json.h"
|
||||
#include "macro.h"
|
||||
|
||||
typedef enum OutputMode {
|
||||
@@ -23,6 +24,10 @@ typedef enum OutputMode {
|
||||
_OUTPUT_MODE_INVALID = -1
|
||||
} OutputMode;
|
||||
|
||||
static inline bool OUTPUT_MODE_IS_JSON(OutputMode m) {
|
||||
return IN_SET(m, OUTPUT_JSON, OUTPUT_JSON_PRETTY, OUTPUT_JSON_SSE, OUTPUT_JSON_SEQ);
|
||||
}
|
||||
|
||||
/* The output flags definitions are shared by the logs and process tree output. Some apply to both, some only to the
|
||||
* logs output, others only to the process tree output. */
|
||||
|
||||
@@ -39,5 +44,7 @@ typedef enum OutputFlags {
|
||||
OUTPUT_NO_HOSTNAME = 1 << 9,
|
||||
} OutputFlags;
|
||||
|
||||
JsonFormatFlags output_mode_to_json_format_flags(OutputMode m);
|
||||
|
||||
const char* output_mode_to_string(OutputMode m) _const_;
|
||||
OutputMode output_mode_from_string(const char *s) _pure_;
|
||||
|
||||
@@ -9,7 +9,7 @@ static void test_issue_9549(void) {
|
||||
_cleanup_(table_unrefp) Table *table = NULL;
|
||||
_cleanup_free_ char *formatted = NULL;
|
||||
|
||||
assert_se(table = table_new("NAME", "TYPE", "RO", "USAGE", "CREATED", "MODIFIED"));
|
||||
assert_se(table = table_new("name", "type", "ro", "usage", "created", "modified"));
|
||||
assert_se(table_set_align_percent(table, TABLE_HEADER_CELL(3), 100) >= 0);
|
||||
assert_se(table_add_many(table,
|
||||
TABLE_STRING, "foooo",
|
||||
@@ -36,7 +36,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
assert_se(setenv("COLUMNS", "40", 1) >= 0);
|
||||
|
||||
assert_se(t = table_new("ONE", "TWO", "THREE"));
|
||||
assert_se(t = table_new("one", "two", "three"));
|
||||
|
||||
assert_se(table_set_align_percent(t, TABLE_HEADER_CELL(2), 100) >= 0);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user