}
static void
-table_print_table_line__(struct ds *line)
+table_finish_line(struct ds *s)
{
- puts(ds_cstr(line));
- ds_clear(line);
+ while (ds_last(s) == ' ') {
+ s->length--;
+ }
+ ds_put_char(s, '\n');
}
static char *
}
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 = xmalloc(table->n_columns * sizeof *widths);
+ widths = xzalloc(table->n_columns * sizeof *widths);
for (x = 0; x < table->n_columns; x++) {
const struct column *column = &table->columns[x];
- widths[x] = strlen(column->heading);
+ int w = 0;
for (y = 0; y < table->n_rows; y++) {
const char *text = cell_to_text(table_cell__(table, y, x), style);
size_t length = strlen(text);
- if (length > widths[x]) {
- widths[x] = length;
+ if (length > w) {
+ w = length;
}
}
+
+ int max = style->max_column_width;
+ if (max > 0 && w > max) {
+ w = max;
+ }
+ if (style->headings) {
+ int min = strlen(column->heading);
+ if (w < min) {
+ w = min;
+ }
+ }
+ widths[x] = w;
}
if (style->headings) {
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], 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("<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;
} else {
- table_escape_html_text__(p, 1);
+ table_escape_html_text__(p, 1, s);
p++;
}
}
- printf("</%s>\n", element);
+ ds_put_format(s, "</%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("<table border=1>\n", stdout);
+ ds_put_cstr(s, "<table border=1>\n");
if (table->caption) {
- table_print_html_cell__("caption", table->caption);
+ table_print_html_cell__("caption", table->caption, s);
}
if (style->headings) {
- fputs(" <tr>\n", stdout);
+ ds_put_cstr(s, " <tr>\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(" </tr>\n", stdout);
+ ds_put_cstr(s, " </tr>\n");
}
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++) {
const char *content;
content = cell_to_text(table_cell__(table, y, x), style);
if (!strcmp(table->columns[x].heading, "_uuid")) {
- fputs(" <td><a name=\"", stdout);
- table_escape_html_text__(content, strlen(content));
- fputs("\">", stdout);
- table_escape_html_text__(content, 8);
- fputs("</a></td>\n", stdout);
+ ds_put_cstr(s, " <td><a name=\"");
+ table_escape_html_text__(content, strlen(content), s);
+ ds_put_cstr(s, "\">");
+ table_escape_html_text__(content, 8, s);
+ ds_put_cstr(s, "</a></td>\n");
} 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
-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;
- char *s;
json = json_object_create();
if (table->caption) {
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();
}
json_object_put(json, "data", data);
- s = json_to_string(json, style->json_flags);
+ json_to_ds(json, style->json_flags, s);
json_destroy(json);
- puts(s);
- free(s);
}
\f
/* Parses 'format' as the argument to a --format command line option, updating
}
}
-/* 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)
{