From c6a4125250b97d41d18dbeeea13043a86e9b8f55 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 2 Feb 2011 11:24:35 -0800 Subject: [PATCH] table: Add new "bare" output formatting options. --format=list corresponds to the output format that "ovs-vsctl list" has always used. --bare is easier for scripts to parse. --- lib/ovsdb-data.c | 39 +++++++++++++++++++++++++++++++++- lib/ovsdb-data.h | 6 +++++- lib/table.c | 46 +++++++++++++++++++++++++++++++++++++---- lib/table.h | 14 +++++++++++-- lib/table.man | 13 ++++++++++-- ovsdb/ovsdb-client.1.in | 1 + ovsdb/ovsdb-client.c | 2 +- 7 files changed, 110 insertions(+), 11 deletions(-) diff --git a/lib/ovsdb-data.c b/lib/ovsdb-data.c index 20d333ef..5b91ea0b 100644 --- a/lib/ovsdb-data.c +++ b/lib/ovsdb-data.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, 2010 Nicira Networks +/* Copyright (c) 2009, 2010, 2011 Nicira Networks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -625,6 +625,20 @@ ovsdb_atom_to_string(const union ovsdb_atom *atom, enum ovsdb_atomic_type type, } } +/* Appends 'atom' (which has the given 'type') to 'out', in a bare string + * format that cannot be parsed uniformly back into a datum but is easier for + * shell scripts, etc., to deal with. */ +void +ovsdb_atom_to_bare(const union ovsdb_atom *atom, enum ovsdb_atomic_type type, + struct ds *out) +{ + if (type == OVSDB_TYPE_STRING) { + ds_put_cstr(out, atom->string); + } else { + ovsdb_atom_to_string(atom, type, out); + } +} + static struct ovsdb_error * check_string_constraints(const char *s, const struct ovsdb_string_constraints *c) @@ -1445,6 +1459,29 @@ ovsdb_datum_to_string(const struct ovsdb_datum *datum, } } +/* Appends to 'out' the 'datum' (with the given 'type') in a bare string format + * that cannot be parsed uniformly back into a datum but is easier for shell + * scripts, etc., to deal with. */ +void +ovsdb_datum_to_bare(const struct ovsdb_datum *datum, + const struct ovsdb_type *type, struct ds *out) +{ + bool is_map = ovsdb_type_is_map(type); + size_t i; + + for (i = 0; i < datum->n; i++) { + if (i > 0) { + ds_put_cstr(out, " "); + } + + ovsdb_atom_to_bare(&datum->keys[i], type->key.type, out); + if (is_map) { + ds_put_char(out, '='); + ovsdb_atom_to_bare(&datum->values[i], type->value.type, out); + } + } +} + /* Initializes 'datum' as a string-to-string map whose contents are taken from * 'sh'. Destroys 'sh'. */ void diff --git a/lib/ovsdb-data.h b/lib/ovsdb-data.h index f7e98a84..ced30339 100644 --- a/lib/ovsdb-data.h +++ b/lib/ovsdb-data.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, 2010 Nicira Networks +/* Copyright (c) 2009, 2010, 2011 Nicira Networks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -94,6 +94,8 @@ char *ovsdb_atom_from_string(union ovsdb_atom *, WARN_UNUSED_RESULT; void ovsdb_atom_to_string(const union ovsdb_atom *, enum ovsdb_atomic_type, struct ds *); +void ovsdb_atom_to_bare(const union ovsdb_atom *, enum ovsdb_atomic_type, + struct ds *); struct ovsdb_error *ovsdb_atom_check_constraints( const union ovsdb_atom *, const struct ovsdb_base_type *) @@ -167,6 +169,8 @@ char *ovsdb_datum_from_string(struct ovsdb_datum *, WARN_UNUSED_RESULT; void ovsdb_datum_to_string(const struct ovsdb_datum *, const struct ovsdb_type *, struct ds *); +void ovsdb_datum_to_bare(const struct ovsdb_datum *, + const struct ovsdb_type *, struct ds *); void ovsdb_datum_from_shash(struct ovsdb_datum *, struct shash *); diff --git a/lib/table.c b/lib/table.c index d150b292..86366d0d 100644 --- a/lib/table.c +++ b/lib/table.c @@ -36,7 +36,7 @@ cell_to_text(struct cell *cell, const struct table_style *style) if (cell->json) { if (style->cell_format == CF_JSON || !cell->type) { cell->text = json_to_string(cell->json, JSSF_SORT); - } else if (style->cell_format == CF_STRING) { + } else { struct ovsdb_datum datum; struct ovsdb_error *error; struct ds s; @@ -45,14 +45,16 @@ cell_to_text(struct cell *cell, const struct table_style *style) NULL); if (!error) { ds_init(&s); - ovsdb_datum_to_string(&datum, cell->type, &s); + if (style->cell_format == CF_STRING) { + ovsdb_datum_to_string(&datum, cell->type, &s); + } else { + ovsdb_datum_to_bare(&datum, cell->type, &s); + } ovsdb_datum_destroy(&datum, cell->type); cell->text = ds_steal_cstr(&s); } else { cell->text = json_to_string(cell->json, JSSF_SORT); } - } else { - NOT_REACHED(); } } else { cell->text = xstrdup(""); @@ -272,6 +274,34 @@ table_print_table__(const struct table *table, const struct table_style *style) free(widths); } +static void +table_print_list__(const struct table *table, const struct table_style *style) +{ + static int n = 0; + size_t x, y; + + if (n++ > 0) { + putchar('\n'); + } + + if (table->caption) { + puts(table->caption); + } + + for (y = 0; y < table->n_rows; y++) { + if (y > 0) { + putchar('\n'); + } + for (x = 0; x < table->n_columns; x++) { + const char *text = cell_to_text(table_cell__(table, y, x), style); + if (style->headings) { + printf("%-20s: ", table->columns[x].heading); + } + puts(text); + } + } +} + static void table_escape_html_text__(const char *s, size_t n) { @@ -469,6 +499,8 @@ table_parse_format(struct table_style *style, const char *format) { if (!strcmp(format, "table")) { style->format = TF_TABLE; + } else if (!strcmp(format, "list")) { + style->format = TF_LIST; } else if (!strcmp(format, "html")) { style->format = TF_HTML; } else if (!strcmp(format, "csv")) { @@ -487,6 +519,8 @@ table_parse_cell_format(struct table_style *style, const char *format) { if (!strcmp(format, "string")) { style->cell_format = CF_STRING; + } else if (!strcmp(format, "bare")) { + style->cell_format = CF_BARE; } else if (!strcmp(format, "json")) { style->cell_format = CF_JSON; } else { @@ -503,6 +537,10 @@ table_print(const struct table *table, const struct table_style *style) table_print_table__(table, style); break; + case TF_LIST: + table_print_list__(table, style); + break; + case TF_HTML: table_print_html__(table, style); break; diff --git a/lib/table.h b/lib/table.h index c24bca2a..e35fefaf 100644 --- a/lib/table.h +++ b/lib/table.h @@ -59,6 +59,7 @@ struct cell *table_add_cell(struct table *); enum table_format { TF_TABLE, /* 2-d table. */ + TF_LIST, /* One cell per line, one row per paragraph. */ TF_HTML, /* HTML table. */ TF_CSV, /* Comma-separated lines. */ TF_JSON /* JSON. */ @@ -66,6 +67,7 @@ enum table_format { enum cell_format { CF_STRING, /* String format. */ + CF_BARE, /* String format without most punctuation. */ CF_JSON /* JSON. */ }; @@ -80,13 +82,15 @@ struct table_style { #define TABLE_OPTION_ENUMS \ OPT_NO_HEADINGS, \ - OPT_PRETTY + OPT_PRETTY, \ + OPT_BARE #define TABLE_LONG_OPTIONS \ {"format", required_argument, 0, 'f'}, \ {"data", required_argument, 0, 'd'}, \ {"no-headings", no_argument, 0, OPT_NO_HEADINGS}, \ - {"pretty", no_argument, 0, OPT_PRETTY}, + {"pretty", no_argument, 0, OPT_PRETTY}, \ + {"bare", no_argument, 0, OPT_BARE} #define TABLE_OPTION_HANDLERS(STYLE) \ case 'f': \ @@ -103,6 +107,12 @@ struct table_style { \ case OPT_PRETTY: \ (STYLE)->json_flags |= JSSF_PRETTY; \ + break; \ + \ + case OPT_BARE: \ + (STYLE)->format = TF_LIST; \ + (STYLE)->cell_format = CF_BARE; \ + (STYLE)->headings = false; \ break; void table_parse_format(struct table_style *, const char *format); diff --git a/lib/table.man b/lib/table.man index 8be272aa..41e039c1 100644 --- a/lib/table.man +++ b/lib/table.man @@ -3,8 +3,10 @@ Sets the type of table formatting. The following types of \fIformat\fR are available: .RS -.IP "\fBtable\fR (default)" -Text-based tables with aligned columns. +.IP "\fBtable\fR" +2-D text tables with aligned columns. +.IP "\fBlist\fR" +A list with one column per line and rows separated by a blank line. .IP "\fBhtml\fR" HTML tables. .IP "\fBcvs\fR" @@ -37,6 +39,11 @@ types of \fIformat\fR are available: .RS .IP "\fBstring\fR (default)" The simple format described in \fBovs\-vsctl\fR(8). +.IP "\fBbare\fR" +The simple format with punctuation stripped off: \fB[]\fR and \fB{}\fR +are omitted around sets, maps, and empty columns, items within sets +and maps are space-separated, and strings are never quoted. This +format may be easier for scripts to parse. .IP "\fBjson\fR" JSON. .RE @@ -56,3 +63,5 @@ per line, with indentation. .IP This option does not affect JSON in tables, which is always printed compactly. +.IP "\fB\-\-bare\fR" +Equivalent to \fB\-\-format=list \-\-data=bare \-\-no\-headings\fR. diff --git a/ovsdb/ovsdb-client.1.in b/ovsdb/ovsdb-client.1.in index 2b1281dc..fe7b7fa2 100644 --- a/ovsdb/ovsdb-client.1.in +++ b/ovsdb/ovsdb-client.1.in @@ -127,6 +127,7 @@ contents of \fItable\fR. Much of the output from \fBovsdb\-client\fR is in the form of tables. The following options controlling output formatting: . +.ds TD (default) .so lib/table.man . .SS "Daemon Options" diff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c index 6402e907..a66b013b 100644 --- a/ovsdb/ovsdb-client.c +++ b/ovsdb/ovsdb-client.c @@ -80,7 +80,7 @@ parse_options(int argc, char *argv[]) DAEMON_LONG_OPTIONS, #ifdef HAVE_OPENSSL {"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT}, - TABLE_LONG_OPTIONS + TABLE_LONG_OPTIONS, STREAM_SSL_LONG_OPTIONS #endif {0, 0, 0, 0}, -- 2.30.2