mirror of
https://github.com/openvswitch/ovs
synced 2025-09-04 00:05:15 +00:00
table: New function table_format() for formatting a table as a string.
This will be useful for daemonized ovn-nbctl. Signed-off-by: Ben Pfaff <blp@ovn.org> Acked-by: Jakub Sitnicki <jkbs@redhat.com>
This commit is contained in:
220
lib/table.c
220
lib/table.c
@@ -212,13 +212,12 @@ table_add_cell(struct table *table)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
table_print_table_line__(struct ds *line)
|
table_finish_line(struct ds *s)
|
||||||
{
|
{
|
||||||
while (ds_last(line) == ' ') {
|
while (ds_last(s) == ' ') {
|
||||||
line->length--;
|
s->length--;
|
||||||
}
|
}
|
||||||
puts(ds_cstr(line));
|
ds_put_char(s, '\n');
|
||||||
ds_clear(line);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
@@ -228,31 +227,31 @@ table_format_timestamp__(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
table_print_timestamp__(const struct table *table)
|
table_print_timestamp__(const struct table *table, struct ds *s)
|
||||||
{
|
{
|
||||||
if (table->timestamp) {
|
if (table->timestamp) {
|
||||||
char *s = table_format_timestamp__();
|
char *timestamp = table_format_timestamp__();
|
||||||
puts(s);
|
ds_put_format(s, "%s\n", timestamp);
|
||||||
free(s);
|
free(timestamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
table_print_table__(const struct table *table, const struct table_style *style)
|
table_print_table__(const struct table *table, const struct table_style *style,
|
||||||
|
struct ds *s)
|
||||||
{
|
{
|
||||||
static int n = 0;
|
static int n = 0;
|
||||||
struct ds line = DS_EMPTY_INITIALIZER;
|
|
||||||
int *widths;
|
int *widths;
|
||||||
size_t x, y;
|
size_t x, y;
|
||||||
|
|
||||||
if (n++ > 0) {
|
if (n++ > 0) {
|
||||||
putchar('\n');
|
ds_put_char(s, '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
table_print_timestamp__(table);
|
table_print_timestamp__(table, s);
|
||||||
|
|
||||||
if (table->caption) {
|
if (table->caption) {
|
||||||
puts(table->caption);
|
ds_put_format(s, "%s\n", table->caption);
|
||||||
}
|
}
|
||||||
|
|
||||||
widths = xzalloc(table->n_columns * sizeof *widths);
|
widths = xzalloc(table->n_columns * sizeof *widths);
|
||||||
@@ -286,222 +285,229 @@ table_print_table__(const struct table *table, const struct table_style *style)
|
|||||||
for (x = 0; x < table->n_columns; x++) {
|
for (x = 0; x < table->n_columns; x++) {
|
||||||
const struct column *column = &table->columns[x];
|
const struct column *column = &table->columns[x];
|
||||||
if (x) {
|
if (x) {
|
||||||
ds_put_char(&line, ' ');
|
ds_put_char(s, ' ');
|
||||||
}
|
}
|
||||||
ds_put_format(&line, "%-*s", widths[x], column->heading);
|
ds_put_format(s, "%-*s", widths[x], column->heading);
|
||||||
}
|
}
|
||||||
table_print_table_line__(&line);
|
table_finish_line(s);
|
||||||
|
|
||||||
for (x = 0; x < table->n_columns; x++) {
|
for (x = 0; x < table->n_columns; x++) {
|
||||||
if (x) {
|
if (x) {
|
||||||
ds_put_char(&line, ' ');
|
ds_put_char(s, ' ');
|
||||||
}
|
}
|
||||||
ds_put_char_multiple(&line, '-', widths[x]);
|
ds_put_char_multiple(s, '-', widths[x]);
|
||||||
}
|
}
|
||||||
table_print_table_line__(&line);
|
table_finish_line(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (y = 0; y < table->n_rows; y++) {
|
for (y = 0; y < table->n_rows; y++) {
|
||||||
for (x = 0; x < table->n_columns; x++) {
|
for (x = 0; x < table->n_columns; x++) {
|
||||||
const char *text = cell_to_text(table_cell__(table, y, x), style);
|
const char *text = cell_to_text(table_cell__(table, y, x), style);
|
||||||
if (x) {
|
if (x) {
|
||||||
ds_put_char(&line, ' ');
|
ds_put_char(s, ' ');
|
||||||
}
|
}
|
||||||
ds_put_format(&line, "%-*.*s", widths[x], widths[x], text);
|
ds_put_format(s, "%-*.*s", widths[x], widths[x], text);
|
||||||
}
|
}
|
||||||
table_print_table_line__(&line);
|
table_finish_line(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
ds_destroy(&line);
|
|
||||||
free(widths);
|
free(widths);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
table_print_list__(const struct table *table, const struct table_style *style)
|
table_print_list__(const struct table *table, const struct table_style *style,
|
||||||
|
struct ds *s)
|
||||||
{
|
{
|
||||||
static int n = 0;
|
static int n = 0;
|
||||||
size_t x, y;
|
size_t x, y;
|
||||||
|
|
||||||
if (n++ > 0) {
|
if (n++ > 0) {
|
||||||
putchar('\n');
|
ds_put_char(s, '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
table_print_timestamp__(table);
|
table_print_timestamp__(table, s);
|
||||||
|
|
||||||
if (table->caption) {
|
if (table->caption) {
|
||||||
puts(table->caption);
|
ds_put_format(s, "%s\n", table->caption);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (y = 0; y < table->n_rows; y++) {
|
for (y = 0; y < table->n_rows; y++) {
|
||||||
if (y > 0) {
|
if (y > 0) {
|
||||||
putchar('\n');
|
ds_put_char(s, '\n');
|
||||||
}
|
}
|
||||||
for (x = 0; x < table->n_columns; x++) {
|
for (x = 0; x < table->n_columns; x++) {
|
||||||
const char *text = cell_to_text(table_cell__(table, y, x), style);
|
const char *text = cell_to_text(table_cell__(table, y, x), style);
|
||||||
if (style->headings) {
|
if (style->headings) {
|
||||||
printf("%-20s: ", table->columns[x].heading);
|
ds_put_format(s, "%-20s: ", table->columns[x].heading);
|
||||||
}
|
}
|
||||||
puts(text);
|
ds_put_format(s, "%s\n", text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
table_escape_html_text__(const char *s, size_t n)
|
table_escape_html_text__(const char *content, size_t n, struct ds *s)
|
||||||
{
|
{
|
||||||
|
if (!strpbrk(content, "&<>\"")) {
|
||||||
|
ds_put_cstr(s, content);
|
||||||
|
} else {
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
char c = s[i];
|
char c = content[i];
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '&':
|
case '&':
|
||||||
fputs("&", stdout);
|
ds_put_cstr(s, "&");
|
||||||
break;
|
break;
|
||||||
case '<':
|
case '<':
|
||||||
fputs("<", stdout);
|
ds_put_cstr(s, "<");
|
||||||
break;
|
break;
|
||||||
case '>':
|
case '>':
|
||||||
fputs(">", stdout);
|
ds_put_cstr(s, ">");
|
||||||
break;
|
break;
|
||||||
case '"':
|
case '"':
|
||||||
fputs(""", stdout);
|
ds_put_cstr(s, """);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
putchar(c);
|
ds_put_char(s, c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
table_print_html_cell__(const char *element, const char *content)
|
table_print_html_cell__(const char *element, const char *content, struct ds *s)
|
||||||
{
|
{
|
||||||
const char *p;
|
const char *p;
|
||||||
|
|
||||||
printf(" <%s>", element);
|
ds_put_format(s, " <%s>", element);
|
||||||
for (p = content; *p; ) {
|
for (p = content; *p; ) {
|
||||||
struct uuid uuid;
|
struct uuid uuid;
|
||||||
|
|
||||||
if (uuid_from_string_prefix(&uuid, p)) {
|
if (uuid_from_string_prefix(&uuid, p)) {
|
||||||
printf("<a href=\"#%.*s\">%.*s</a>", UUID_LEN, p, 8, p);
|
ds_put_format(s, "<a href=\"#%.*s\">%.*s</a>", UUID_LEN, p, 8, p);
|
||||||
p += UUID_LEN;
|
p += UUID_LEN;
|
||||||
} else {
|
} else {
|
||||||
table_escape_html_text__(p, 1);
|
table_escape_html_text__(p, 1, s);
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("</%s>\n", element);
|
ds_put_format(s, "</%s>\n", element);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
table_print_html__(const struct table *table, const struct table_style *style)
|
table_print_html__(const struct table *table, const struct table_style *style,
|
||||||
|
struct ds *s)
|
||||||
{
|
{
|
||||||
size_t x, y;
|
size_t x, y;
|
||||||
|
|
||||||
table_print_timestamp__(table);
|
table_print_timestamp__(table, s);
|
||||||
|
|
||||||
fputs("<table border=1>\n", stdout);
|
ds_put_cstr(s, "<table border=1>\n");
|
||||||
|
|
||||||
if (table->caption) {
|
if (table->caption) {
|
||||||
table_print_html_cell__("caption", table->caption);
|
table_print_html_cell__("caption", table->caption, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (style->headings) {
|
if (style->headings) {
|
||||||
fputs(" <tr>\n", stdout);
|
ds_put_cstr(s, " <tr>\n");
|
||||||
for (x = 0; x < table->n_columns; x++) {
|
for (x = 0; x < table->n_columns; x++) {
|
||||||
const struct column *column = &table->columns[x];
|
const struct column *column = &table->columns[x];
|
||||||
table_print_html_cell__("th", column->heading);
|
table_print_html_cell__("th", column->heading, s);
|
||||||
}
|
}
|
||||||
fputs(" </tr>\n", stdout);
|
ds_put_cstr(s, " </tr>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (y = 0; y < table->n_rows; y++) {
|
for (y = 0; y < table->n_rows; y++) {
|
||||||
fputs(" <tr>\n", stdout);
|
ds_put_cstr(s, " <tr>\n");
|
||||||
for (x = 0; x < table->n_columns; x++) {
|
for (x = 0; x < table->n_columns; x++) {
|
||||||
const char *content;
|
const char *content;
|
||||||
|
|
||||||
content = cell_to_text(table_cell__(table, y, x), style);
|
content = cell_to_text(table_cell__(table, y, x), style);
|
||||||
if (!strcmp(table->columns[x].heading, "_uuid")) {
|
if (!strcmp(table->columns[x].heading, "_uuid")) {
|
||||||
fputs(" <td><a name=\"", stdout);
|
ds_put_cstr(s, " <td><a name=\"");
|
||||||
table_escape_html_text__(content, strlen(content));
|
table_escape_html_text__(content, strlen(content), s);
|
||||||
fputs("\">", stdout);
|
ds_put_cstr(s, "\">");
|
||||||
table_escape_html_text__(content, 8);
|
table_escape_html_text__(content, 8, s);
|
||||||
fputs("</a></td>\n", stdout);
|
ds_put_cstr(s, "</a></td>\n");
|
||||||
} else {
|
} else {
|
||||||
table_print_html_cell__("td", content);
|
table_print_html_cell__("td", content, s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fputs(" </tr>\n", stdout);
|
ds_put_cstr(s, " </tr>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fputs("</table>\n", stdout);
|
ds_put_cstr(s, "</table>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
table_print_csv_cell__(const char *content)
|
table_print_csv_cell__(const char *content, struct ds *s)
|
||||||
{
|
{
|
||||||
const char *p;
|
const char *p;
|
||||||
|
|
||||||
if (!strpbrk(content, "\n\",")) {
|
if (!strpbrk(content, "\n\",")) {
|
||||||
fputs(content, stdout);
|
ds_put_cstr(s, content);
|
||||||
} else {
|
} else {
|
||||||
putchar('"');
|
ds_put_char(s, '"');
|
||||||
for (p = content; *p != '\0'; p++) {
|
for (p = content; *p != '\0'; p++) {
|
||||||
switch (*p) {
|
switch (*p) {
|
||||||
case '"':
|
case '"':
|
||||||
fputs("\"\"", stdout);
|
ds_put_cstr(s, "\"\"");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
putchar(*p);
|
ds_put_char(s, *p);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
putchar('"');
|
ds_put_char(s, '"');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
table_print_csv__(const struct table *table, const struct table_style *style)
|
table_print_csv__(const struct table *table, const struct table_style *style,
|
||||||
|
struct ds *s)
|
||||||
{
|
{
|
||||||
static int n = 0;
|
static int n = 0;
|
||||||
size_t x, y;
|
size_t x, y;
|
||||||
|
|
||||||
if (n++ > 0) {
|
if (n++ > 0) {
|
||||||
putchar('\n');
|
ds_put_char(s, '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
table_print_timestamp__(table);
|
table_print_timestamp__(table, s);
|
||||||
|
|
||||||
if (table->caption) {
|
if (table->caption) {
|
||||||
puts(table->caption);
|
ds_put_format(s, "%s\n", table->caption);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (style->headings) {
|
if (style->headings) {
|
||||||
for (x = 0; x < table->n_columns; x++) {
|
for (x = 0; x < table->n_columns; x++) {
|
||||||
const struct column *column = &table->columns[x];
|
const struct column *column = &table->columns[x];
|
||||||
if (x) {
|
if (x) {
|
||||||
putchar(',');
|
ds_put_char(s, ',');
|
||||||
}
|
}
|
||||||
table_print_csv_cell__(column->heading);
|
table_print_csv_cell__(column->heading, s);
|
||||||
}
|
}
|
||||||
putchar('\n');
|
ds_put_char(s, '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
for (y = 0; y < table->n_rows; y++) {
|
for (y = 0; y < table->n_rows; y++) {
|
||||||
for (x = 0; x < table->n_columns; x++) {
|
for (x = 0; x < table->n_columns; x++) {
|
||||||
if (x) {
|
if (x) {
|
||||||
putchar(',');
|
ds_put_char(s, ',');
|
||||||
}
|
}
|
||||||
table_print_csv_cell__(cell_to_text(table_cell__(table, y, x),
|
table_print_csv_cell__(cell_to_text(table_cell__(table, y, x),
|
||||||
style));
|
style), s);
|
||||||
}
|
}
|
||||||
putchar('\n');
|
ds_put_char(s, '\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
table_print_json__(const struct table *table, const struct table_style *style)
|
table_print_json__(const struct table *table, const struct table_style *style,
|
||||||
|
struct ds *s)
|
||||||
{
|
{
|
||||||
struct json *json, *headings, *data;
|
struct json *json, *headings, *data;
|
||||||
size_t x, y;
|
size_t x, y;
|
||||||
@@ -511,9 +517,9 @@ table_print_json__(const struct table *table, const struct table_style *style)
|
|||||||
json_object_put_string(json, "caption", table->caption);
|
json_object_put_string(json, "caption", table->caption);
|
||||||
}
|
}
|
||||||
if (table->timestamp) {
|
if (table->timestamp) {
|
||||||
char *s = table_format_timestamp__();
|
json_object_put_nocopy(
|
||||||
json_object_put_string(json, "time", s);
|
json, "time",
|
||||||
free(s);
|
json_string_create_nocopy(table_format_timestamp__()));
|
||||||
}
|
}
|
||||||
|
|
||||||
headings = json_array_create_empty();
|
headings = json_array_create_empty();
|
||||||
@@ -540,10 +546,8 @@ table_print_json__(const struct table *table, const struct table_style *style)
|
|||||||
}
|
}
|
||||||
json_object_put(json, "data", data);
|
json_object_put(json, "data", data);
|
||||||
|
|
||||||
char *s = json_to_string(json, style->json_flags);
|
json_to_ds(json, style->json_flags, s);
|
||||||
json_destroy(json);
|
json_destroy(json);
|
||||||
puts(s);
|
|
||||||
free(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parses 'format' as the argument to a --format command line option, updating
|
/* Parses 'format' as the argument to a --format command line option, updating
|
||||||
@@ -582,31 +586,41 @@ table_parse_cell_format(struct table_style *style, const char *format)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
table_format(const struct table *table, const struct table_style *style,
|
||||||
|
struct ds *s)
|
||||||
|
{
|
||||||
|
switch (style->format) {
|
||||||
|
case TF_TABLE:
|
||||||
|
table_print_table__(table, style, s);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TF_LIST:
|
||||||
|
table_print_list__(table, style, s);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TF_HTML:
|
||||||
|
table_print_html__(table, style, s);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TF_CSV:
|
||||||
|
table_print_csv__(table, style, s);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TF_JSON:
|
||||||
|
table_print_json__(table, style, s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Outputs 'table' on stdout in the specified 'style'. */
|
/* Outputs 'table' on stdout in the specified 'style'. */
|
||||||
void
|
void
|
||||||
table_print(const struct table *table, const struct table_style *style)
|
table_print(const struct table *table, const struct table_style *style)
|
||||||
{
|
{
|
||||||
switch (style->format) {
|
struct ds s = DS_EMPTY_INITIALIZER;
|
||||||
case TF_TABLE:
|
table_format(table, style, &s);
|
||||||
table_print_table__(table, style);
|
fputs(ds_cstr(&s), stdout);
|
||||||
break;
|
ds_destroy(&s);
|
||||||
|
|
||||||
case TF_LIST:
|
|
||||||
table_print_list__(table, style);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TF_HTML:
|
|
||||||
table_print_html__(table, style);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TF_CSV:
|
|
||||||
table_print_csv__(table, style);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TF_JSON:
|
|
||||||
table_print_json__(table, style);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
|
|
||||||
|
struct ds;
|
||||||
struct table_style;
|
struct table_style;
|
||||||
|
|
||||||
/* Manipulating tables and their rows and columns. */
|
/* Manipulating tables and their rows and columns. */
|
||||||
@@ -128,6 +129,8 @@ void table_parse_format(struct table_style *, const char *format);
|
|||||||
void table_parse_cell_format(struct table_style *, const char *format);
|
void table_parse_cell_format(struct table_style *, const char *format);
|
||||||
|
|
||||||
void table_print(const struct table *, const struct table_style *);
|
void table_print(const struct table *, const struct table_style *);
|
||||||
|
void table_format(const struct table *, const struct table_style *,
|
||||||
|
struct ds *);
|
||||||
void table_usage(void);
|
void table_usage(void);
|
||||||
|
|
||||||
#endif /* table.h */
|
#endif /* table.h */
|
||||||
|
Reference in New Issue
Block a user