diff --git a/libsmartcols/docs/libsmartcols-sections.txt b/libsmartcols/docs/libsmartcols-sections.txt index a8dc884ab..bdb35082f 100644 --- a/libsmartcols/docs/libsmartcols-sections.txt +++ b/libsmartcols/docs/libsmartcols-sections.txt @@ -92,7 +92,9 @@ scols_table_enable_maxout scols_table_enable_noheadings scols_table_enable_raw scols_table_get_column +scols_table_get_column_separator scols_table_get_line +scols_table_get_line_separator scols_table_get_ncols scols_table_get_nlines scols_table_get_stream @@ -112,6 +114,8 @@ scols_table_remove_column scols_table_remove_columns scols_table_remove_line scols_table_remove_lines +scols_table_set_column_separator +scols_table_set_line_separator scols_table_set_stream scols_table_set_symbols scols_unref_table diff --git a/libsmartcols/src/libsmartcols.h.in b/libsmartcols/src/libsmartcols.h.in index b3ceeeab9..1307013a1 100644 --- a/libsmartcols/src/libsmartcols.h.in +++ b/libsmartcols/src/libsmartcols.h.in @@ -174,6 +174,9 @@ extern int scols_table_enable_noheadings(struct libscols_table *tb, int enable); extern int scols_table_enable_export(struct libscols_table *tb, int enable); extern int scols_table_enable_maxout(struct libscols_table *tb, int enable); +extern int scols_table_set_column_separator(struct libscols_table *tb, char *sep); +extern int scols_table_set_line_separator(struct libscols_table *tb, char *sep); + extern struct libscols_table *scols_new_table(void); extern void scols_ref_table(struct libscols_table *tb); extern void scols_unref_table(struct libscols_table *tb); @@ -182,6 +185,8 @@ extern int scols_table_remove_column(struct libscols_table *tb, struct libscols_ extern int scols_table_remove_columns(struct libscols_table *tb); extern struct libscols_column *scols_table_new_column(struct libscols_table *tb, const char *name, double whint, int flags); extern int scols_table_next_column(struct libscols_table *tb, struct libscols_iter *itr, struct libscols_column **cl); +extern char *scols_table_get_column_separator(struct libscols_table *tb); +extern char *scols_table_get_line_separator(struct libscols_table *tb); extern int scols_table_get_ncols(struct libscols_table *tb); extern int scols_table_get_nlines(struct libscols_table *tb); extern struct libscols_column *scols_table_get_column(struct libscols_table *tb, size_t n); diff --git a/libsmartcols/src/libsmartcols.sym b/libsmartcols/src/libsmartcols.sym index 3984751cf..4b64f280c 100644 --- a/libsmartcols/src/libsmartcols.sym +++ b/libsmartcols/src/libsmartcols.sym @@ -71,7 +71,9 @@ global: scols_table_enable_noheadings; scols_table_enable_raw; scols_table_get_column; + scols_table_get_column_separator; scols_table_get_line; + scols_table_get_line_separator; scols_table_get_ncols; scols_table_get_nlines; scols_table_get_stream; @@ -91,6 +93,8 @@ global: scols_table_remove_columns; scols_table_remove_line; scols_table_remove_lines; + scols_table_set_column_separator; + scols_table_set_line_separator; scols_table_set_stream; scols_table_set_symbols; scols_unref_column; diff --git a/libsmartcols/src/smartcolsP.h b/libsmartcols/src/smartcolsP.h index b7f1f2b6d..ebdc9295f 100644 --- a/libsmartcols/src/smartcolsP.h +++ b/libsmartcols/src/smartcolsP.h @@ -125,6 +125,9 @@ struct libscols_table { size_t termreduce; /* extra blank space */ FILE *out; /* output stream */ + char *colsep; /* column separator */ + char *linesep; /* line separator */ + struct list_head tb_columns; struct list_head tb_lines; struct libscols_symbols *symbols; diff --git a/libsmartcols/src/table.c b/libsmartcols/src/table.c index 914cc2ed9..34b43b508 100644 --- a/libsmartcols/src/table.c +++ b/libsmartcols/src/table.c @@ -84,6 +84,8 @@ void scols_unref_table(struct libscols_table *tb) scols_table_remove_lines(tb); scols_table_remove_columns(tb); scols_unref_symbols(tb->symbols); + free(tb->linesep); + free(tb->colsep); free(tb); } } @@ -609,6 +611,11 @@ struct libscols_table *scols_copy_table(struct libscols_table *tb) scols_unref_line(newln); } + /* separators */ + if (scols_table_set_column_separator(ret, tb->colsep) || + scols_table_set_line_separator(ret, tb->linesep)) + goto err; + return ret; err: scols_unref_table(ret); @@ -880,3 +887,87 @@ int scols_table_is_tree(struct libscols_table *tb) assert(tb); return tb && tb->ntreecols > 0; } + +/** + * scols_table_set_column_separator: + * @tb: table + * @sep: separator + * + * Sets the column separator of @tb to @sep. + * Please note that @sep should always take up a single cell in the output. + * + * Returns: 0, a negative value in case of an error. + */ +int scols_table_set_column_separator(struct libscols_table *tb, char *sep) +{ + assert (tb); + + if (!tb) + return -EINVAL; + + sep = strdup(sep); + if (!sep) + return -ENOMEM; + + free(tb->colsep); + tb->colsep = sep; + + return 0; +} + +/** + * scols_table_set_line_separator: + * @tb: table + * @sep: separator + * + * Sets the line separator of @tb to @sep. + * + * Returns: 0, a negative value in case of an error. + */ +int scols_table_set_line_separator(struct libscols_table *tb, char *sep) +{ + assert (tb); + + if (!tb) + return -EINVAL; + + sep = strdup(sep); + if (!sep) + return -ENOMEM; + + free(tb->linesep); + tb->linesep = sep; + + return 0; +} + +/** + * scols_table_get_column_separator: + * @tb: table + * + * Returns: @tb column separator, NULL in case of an error + */ +char *scols_table_get_column_separator(struct libscols_table *tb) +{ + assert (tb); + + if (!tb) + return NULL; + return tb->colsep; +} + +/** + * scols_table_get_line_separator: + * @tb: table + * + * Returns: @tb line separator, NULL in case of an error + */ +char *scols_table_get_line_separator(struct libscols_table *tb) +{ + assert (tb); + + if (!tb) + return NULL; + return tb->linesep; + +} diff --git a/libsmartcols/src/table_print.c b/libsmartcols/src/table_print.c index d25bd252d..0a3a30760 100644 --- a/libsmartcols/src/table_print.c +++ b/libsmartcols/src/table_print.c @@ -31,6 +31,8 @@ #define is_last_column(_tb, _cl) \ list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns) +#define colsep(tb) ((tb)->colsep ? (tb)->colsep : " ") +#define linesep(tb) ((tb)->linesep ? (tb)->linesep : "\n") static void print_data(struct libscols_table *tb, struct libscols_column *cl, struct libscols_line *ln, /* optional */ @@ -51,7 +53,7 @@ static void print_data(struct libscols_table *tb, if (scols_table_is_raw(tb)) { fputs_nonblank(data, tb->out); if (!is_last_column(tb, cl)) - fputc(' ', tb->out); + fputs(colsep(tb), tb->out); return; } @@ -60,7 +62,7 @@ static void print_data(struct libscols_table *tb, fprintf(tb->out, "%s=", scols_cell_get_data(&cl->header)); fputs_quoted(data, tb->out); if (!is_last_column(tb, cl)) - fputc(' ', tb->out); + fputs(colsep(tb), tb->out); return; } @@ -117,17 +119,17 @@ static void print_data(struct libscols_table *tb, } } for (i = len; i < width; i++) - fputc(' ', tb->out); /* padding */ + fputs(colsep(tb), tb->out); /* padding */ if (!is_last_column(tb, cl)) { if (len > width && !scols_column_is_trunc(cl)) { - fputc('\n', tb->out); + fputs(linesep(tb), tb->out); for (i = 0; i <= (size_t) cl->seqnum; i++) { struct libscols_column *x = scols_table_get_column(tb, i); fprintf(tb->out, "%*s ", -((int)x->width), " "); } } else - fputc(' ', tb->out); /* columns separator */ + fputs(colsep(tb), tb->out); /* columns separator */ } free(buf); @@ -229,7 +231,7 @@ static void print_line(struct libscols_table *tb, print_data(tb, cl, ln, scols_line_get_cell(ln, cl->seqnum), line_get_data(tb, ln, cl, buf, bufsz)); - fputc('\n', tb->out); + fputs(linesep(tb), tb->out); } static void print_header(struct libscols_table *tb, char *buf, size_t bufsz) @@ -252,7 +254,7 @@ static void print_header(struct libscols_table *tb, char *buf, size_t bufsz) buf[bufsz - 1] = '\0'; print_data(tb, cl, NULL, &cl->header, buf); } - fputc('\n', tb->out); + fputs(linesep(tb), tb->out); } static void print_table(struct libscols_table *tb, char *buf, size_t bufsz) diff --git a/libsmartcols/src/test.c b/libsmartcols/src/test.c index 90f9df443..eaff49e7e 100644 --- a/libsmartcols/src/test.c +++ b/libsmartcols/src/test.c @@ -157,6 +157,7 @@ static void __attribute__((__noreturn__)) usage(FILE *out) fputs(_(" -n, --noheadings don't print headings\n"), out); fputs(_(" -p, --pairs use key=\"value\" output format\n"), out); fputs(_(" -r, --raw use raw output format\n"), out); + fputs(_(" -c, --csv display a csv-like output\n"), out); fputs(USAGE_SEPARATOR, out); fputs(USAGE_HELP, out); @@ -175,9 +176,9 @@ int main(int argc, char *argv[]) { "noheadings", 0, 0, 'n' }, { "list", 0, 0, 'l' }, { "ascii", 0, 0, 'i' }, - { "raw", 0, 0, 'r' }, { "pairs", 0, 0, 'p' }, { "clone", 0, 0, 'C' }, + { "csv", 0, 0, 'c' }, { NULL, 0, 0, 0 }, }; @@ -191,7 +192,7 @@ int main(int argc, char *argv[]) if (!tb) err(EXIT_FAILURE, "faild to create output table"); - while((c = getopt_long(argc, argv, "nlirpC", longopts, NULL)) != -1) { + while((c = getopt_long(argc, argv, "nlirpCc", longopts, NULL)) != -1) { switch(c) { case 'h': usage(stdout); @@ -213,6 +214,12 @@ int main(int argc, char *argv[]) scols_table_enable_raw(tb, 1); notree = 1; break; + case 'c': + scols_table_set_line_separator(tb, ","); + /* a column separator should always take up one cell */ + scols_table_set_column_separator(tb, ":"); + scols_table_enable_raw(tb, 1); + break; case 'C': clonetb = 1; default: