From patchwork Mon Jul 9 23:34:00 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 941734 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=ovn.org Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41PhW069rHz9ryt for ; Tue, 10 Jul 2018 09:34:20 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 2DF43E5A; Mon, 9 Jul 2018 23:34:10 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id AA5B2E43 for ; Mon, 9 Jul 2018 23:34:08 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 1E66777E for ; Mon, 9 Jul 2018 23:34:06 +0000 (UTC) X-Originating-IP: 208.91.3.26 Received: from sigabrt.benpfaff.org (unknown [208.91.3.26]) (Authenticated sender: blp@ovn.org) by relay4-d.mail.gandi.net (Postfix) with ESMTPSA id E18A2E0003; Mon, 9 Jul 2018 23:34:03 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Mon, 9 Jul 2018 16:34:00 -0700 Message-Id: <20180709233400.20901-1-blp@ovn.org> X-Mailer: git-send-email 2.16.1 X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: Ben Pfaff Subject: [ovs-dev] [PATCH] table: New function table_format() for formatting a table as a string. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org This will be useful for daemonized ovn-nbctl. Signed-off-by: Ben Pfaff Acked-by: Jakub Sitnicki --- lib/table.c | 222 ++++++++++++++++++++++++++++++++---------------------------- lib/table.h | 3 + 2 files changed, 121 insertions(+), 104 deletions(-) diff --git a/lib/table.c b/lib/table.c index 98599d67cfcf..cd811caf5b88 100644 --- a/lib/table.c +++ b/lib/table.c @@ -212,13 +212,12 @@ table_add_cell(struct table *table) } static void -table_print_table_line__(struct ds *line) +table_finish_line(struct ds *s) { - while (ds_last(line) == ' ') { - line->length--; + while (ds_last(s) == ' ') { + s->length--; } - puts(ds_cstr(line)); - ds_clear(line); + ds_put_char(s, '\n'); } static char * @@ -228,31 +227,31 @@ table_format_timestamp__(void) } static void -table_print_timestamp__(const struct table *table) +table_print_timestamp__(const struct table *table, struct ds *s) { if (table->timestamp) { - char *s = table_format_timestamp__(); - puts(s); - free(s); + char *timestamp = table_format_timestamp__(); + ds_put_format(s, "%s\n", timestamp); + free(timestamp); } } 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; - struct ds line = DS_EMPTY_INITIALIZER; int *widths; size_t x, y; if (n++ > 0) { - putchar('\n'); + ds_put_char(s, '\n'); } - table_print_timestamp__(table); + table_print_timestamp__(table, s); if (table->caption) { - puts(table->caption); + ds_put_format(s, "%s\n", table->caption); } 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++) { const struct column *column = &table->columns[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++) { 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 (x = 0; x < table->n_columns; x++) { const char *text = cell_to_text(table_cell__(table, y, x), style); 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); } 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; size_t x, y; if (n++ > 0) { - putchar('\n'); + ds_put_char(s, '\n'); } - table_print_timestamp__(table); + table_print_timestamp__(table, s); if (table->caption) { - puts(table->caption); + ds_put_format(s, "%s\n", table->caption); } for (y = 0; y < table->n_rows; y++) { if (y > 0) { - putchar('\n'); + ds_put_char(s, '\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); + ds_put_format(s, "%-20s: ", table->columns[x].heading); } - puts(text); + ds_put_format(s, "%s\n", text); } } } 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) { - size_t i; - - for (i = 0; i < n; i++) { - char c = s[i]; - - switch (c) { - case '&': - fputs("&", stdout); - break; - case '<': - fputs("<", stdout); - break; - case '>': - fputs(">", stdout); - break; - case '"': - fputs(""", stdout); - break; - default: - putchar(c); - break; + if (!strpbrk(content, "&<>\"")) { + ds_put_cstr(s, content); + } else { + size_t i; + + for (i = 0; i < n; i++) { + char c = content[i]; + + switch (c) { + case '&': + ds_put_cstr(s, "&"); + break; + case '<': + ds_put_cstr(s, "<"); + break; + case '>': + ds_put_cstr(s, ">"); + break; + case '"': + ds_put_cstr(s, """); + break; + default: + ds_put_char(s, c); + break; + } } } } 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; - printf(" <%s>", element); + ds_put_format(s, " <%s>", element); for (p = content; *p; ) { struct uuid uuid; if (uuid_from_string_prefix(&uuid, p)) { - printf("%.*s", UUID_LEN, p, 8, p); + ds_put_format(s, "%.*s", UUID_LEN, p, 8, p); p += UUID_LEN; } else { - table_escape_html_text__(p, 1); + table_escape_html_text__(p, 1, s); p++; } } - printf("\n", element); + ds_put_format(s, "\n", element); } 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; - table_print_timestamp__(table); + table_print_timestamp__(table, s); - fputs("\n", stdout); + ds_put_cstr(s, "
\n"); if (table->caption) { - table_print_html_cell__("caption", table->caption); + table_print_html_cell__("caption", table->caption, s); } if (style->headings) { - fputs(" \n", stdout); + ds_put_cstr(s, " \n"); for (x = 0; x < table->n_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(" \n", stdout); + ds_put_cstr(s, " \n"); } for (y = 0; y < table->n_rows; y++) { - fputs(" \n", stdout); + ds_put_cstr(s, " \n"); for (x = 0; x < table->n_columns; x++) { const char *content; content = cell_to_text(table_cell__(table, y, x), style); if (!strcmp(table->columns[x].heading, "_uuid")) { - fputs(" \n", stdout); + ds_put_cstr(s, " \n"); } else { - table_print_html_cell__("td", content); + table_print_html_cell__("td", content, s); } } - fputs(" \n", stdout); + ds_put_cstr(s, " \n"); } - fputs("
", stdout); - table_escape_html_text__(content, 8); - fputs(""); + table_escape_html_text__(content, 8, s); + ds_put_cstr(s, "
\n", stdout); + ds_put_cstr(s, "\n"); } static void -table_print_csv_cell__(const char *content) +table_print_csv_cell__(const char *content, struct ds *s) { const char *p; if (!strpbrk(content, "\n\",")) { - fputs(content, stdout); + ds_put_cstr(s, content); } else { - putchar('"'); + ds_put_char(s, '"'); for (p = content; *p != '\0'; p++) { switch (*p) { case '"': - fputs("\"\"", stdout); + ds_put_cstr(s, "\"\""); break; default: - putchar(*p); + ds_put_char(s, *p); break; } } - putchar('"'); + ds_put_char(s, '"'); } } 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; size_t x, y; if (n++ > 0) { - putchar('\n'); + ds_put_char(s, '\n'); } - table_print_timestamp__(table); + table_print_timestamp__(table, s); if (table->caption) { - puts(table->caption); + ds_put_format(s, "%s\n", table->caption); } if (style->headings) { for (x = 0; x < table->n_columns; x++) { const struct column *column = &table->columns[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 (x = 0; x < table->n_columns; x++) { if (x) { - putchar(','); + ds_put_char(s, ','); } table_print_csv_cell__(cell_to_text(table_cell__(table, y, x), - style)); + style), s); } - putchar('\n'); + ds_put_char(s, '\n'); } } 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; 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); } if (table->timestamp) { - char *s = table_format_timestamp__(); - json_object_put_string(json, "time", s); - free(s); + json_object_put_nocopy( + json, "time", + json_string_create_nocopy(table_format_timestamp__())); } 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); - char *s = json_to_string(json, style->json_flags); + json_to_ds(json, style->json_flags, s); json_destroy(json); - puts(s); - free(s); } /* Parses 'format' as the argument to a --format command line option, updating @@ -582,33 +586,43 @@ table_parse_cell_format(struct table_style *style, const char *format) } } -/* Outputs 'table' on stdout in the specified 'style'. */ void -table_print(const struct table *table, const struct table_style *style) +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); + table_print_table__(table, style, s); break; case TF_LIST: - table_print_list__(table, style); + table_print_list__(table, style, s); break; case TF_HTML: - table_print_html__(table, style); + table_print_html__(table, style, s); break; case TF_CSV: - table_print_csv__(table, style); + table_print_csv__(table, style, s); break; case TF_JSON: - table_print_json__(table, style); + table_print_json__(table, style, s); break; } } +/* Outputs 'table' on stdout in the specified 'style'. */ +void +table_print(const struct table *table, const struct table_style *style) +{ + struct ds s = DS_EMPTY_INITIALIZER; + table_format(table, style, &s); + fputs(ds_cstr(&s), stdout); + ds_destroy(&s); +} + void table_usage(void) { diff --git a/lib/table.h b/lib/table.h index f1221716a8f3..313ac1dd2877 100644 --- a/lib/table.h +++ b/lib/table.h @@ -21,6 +21,7 @@ #include #include "compiler.h" +struct ds; struct table_style; /* 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_print(const struct table *, const struct table_style *); +void table_format(const struct table *, const struct table_style *, + struct ds *); void table_usage(void); #endif /* table.h */