2 * UCW Library -- Table printer
4 * (c) 2014 Robert Kessl <robert.kessl@economia.cz>
7 #ifndef _TABLEPRINTER_H
8 #define _TABLEPRINTER_H
10 #include <ucw/fastbuf.h>
11 #include <ucw/mempool.h>
14 COL_TYPE_STR, COL_TYPE_INT, COL_TYPE_INTMAX, COL_TYPE_UINT, COL_TYPE_UINTMAX, COL_TYPE_BOOL, COL_TYPE_DOUBLE, COL_TYPE_ANY, COL_TYPE_LAST
17 #define TBL_COL_STR(_enum_prefix, _name, _width) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = "%s", .type = COL_TYPE_STR }
18 #define TBL_COL_INT(_enum_prefix, _name, _width) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = "%d", .type = COL_TYPE_INT }
19 #define TBL_COL_UINT(_enum_prefix, _name, _width) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = "%u", .type = COL_TYPE_UINT }
20 #define TBL_COL_INTMAX(_enum_prefix, _name, _width) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = "%jd", .type = COL_TYPE_INTMAX }
21 #define TBL_COL_UINTMAX(_enum_prefix, _name, _width) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = "%ju", .type = COL_TYPE_UINTMAX }
22 #define TBL_COL_HEXUINT(_enum_prefix, _name, _width) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = "0x%x", .type = COL_TYPE_UINT }
23 #define TBL_COL_DOUBLE(_enum_prefix, _name, _width, _prec) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = "%." #_prec "lf", .type = COL_TYPE_DOUBLE }
24 #define TBL_COL_BOOL(_enum_prefix, _name, _width) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = "%s", .type = COL_TYPE_BOOL }
25 #define TBL_COL_ANY(_enum_prefix, _name, _width) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = 0, .type = COL_TYPE_ANY }
27 #define TBL_COL_STR_FMT(_enum_prefix, _name, _width, _fmt) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = _fmt, .type = COL_TYPE_STR }
28 #define TBL_COL_INT_FMT(_enum_prefix, _name, _width, _fmt) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = _fmt, .type = COL_TYPE_INT }
29 #define TBL_COL_UINT_FMT(_enum_prefix, _name, _width, _fmt) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = _fmt, .type = COL_TYPE_UINT }
30 #define TBL_COL_INTMAX_FMT(_enum_prefix, _name, _width, _fmt) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = _fmt, .type = COL_TYPE_INTMAX }
31 #define TBL_COL_UINTMAX_FMT(_enum_prefix, _name, _width, _fmt) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = _fmt, .type = COL_TYPE_UINTMAX }
32 #define TBL_COL_HEXUINT_FMT(_enum_prefix, _name, _width, _fmt) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = _fmt, .type = COL_TYPE_UINT }
33 #define TBL_COL_BOOL_FMT(_enum_prefix, _name, _width, _fmt) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = _fmt, .type = COL_TYPE_BOOL }
35 #define TBL_COL_END { .name = 0, .width = 0, .fmt = 0, .type = COL_TYPE_LAST }
37 #define TBL_COLUMNS .columns = (struct table_column [])
38 #define TBL_COL_ORDER(order) .column_order = (int *) order, .cols_to_output = ARRAY_SIZE(order)
39 #define TBL_COL_DELIMITER(_delimiter_) .col_delimiter = _delimiter_
40 #define TBL_APPEND_DELIMITER(_delimiter_) .append_delimiter = _delimiter_
42 #define TBL_OUTPUT_HUMAN_READABLE .callbacks = &table_fmt_human_readable
43 #define TBL_OUTPUT_MACHINE_READABLE .callbacks = &table_fmt_machine_readable
47 * The table works as follows:
48 * The table can be used after table_init is called. Then at the beginning of each printing, the
49 * table_start function must be called. After printing, the table_end must be called. The
50 * table_start MUST be paired with table_end. Inbetween table_start/table_end the user can set the
51 * cells of one row and one row is finished and printed using table_end_of_row. The pairs
52 * table_start/table_end can be used multiple-times for one table. The table is deallocated using
53 * table_cleanup. After table_cleanup is called it is not possible to further use the struct table.
54 * The struct table must be reinitialized.
56 * Default behaviour of the table_set_col_* is replacement of already set data. To append, the user
57 * must use table_append_*
60 * 1) @table_init is called;
61 * 2) @table_start is called following by table_set_xxx functions and @table_end.
62 * table_start/table_end forms 1-level parenthesis structure. Some of the table
63 * settings can be changed only between table_init and @table_start or after table_end
64 * is called (but before next table_start.
65 * 3) the table is deallocated using @table_cleanup. After the cleanup
66 * is done, the struct table is unusable and must be initialized.
69 * An example of the procedure is following sequence of calls:
79 * The tableprinter supports user-specified callback for each row and table-print (i.e., a callback
80 * that is called in table_end).
82 * The table is initialized by defining a table struct using the following macros:
83 * o TBL_START_COLUMNS indicates start of definition of columns
84 * o TBL_COL_XXX macros specify the column types with some default formatting the column is specified using a column
85 * name (which should be C identifier) and a prefix. the column name is the a string with the column
86 * name. The prefix is used for discriminating between columns from different tables. The column index
87 * should be taken from an enum. The enum identifier is prefix concatenated with the column name identifier.
88 * o TBL_COL_XXX_F macros specify column types with user supplied formatting
89 * o TBL_COL_END indicates end of column definitions
90 * o TBL_COL_ORDER specify the column order
91 * o TBL_COL_DELIMITER specify the in-between cell delimiter
93 * The table cells have strict type control, with the exception of type TBL_COL_ANY. In the case of
94 * TBL_COL_ANY, the type is not tested and an arbitrary value can be printed into the cell.
95 * It is also possible to print string to an arbitrary cell.
98 * * user supplied callback functions can be used for modifying the output format.
100 * Non-tested features:
101 * * computing statistics of columns via the table_start_callback/table_end_callback.
102 * TODO: is it better to have callback for each cell with the original value supplied by the caller of the table_set_* functions?
104 * * unsupported: (dynamic) alignment of cells which is computed in table_end
106 * TODO: table_set_col_fmt: this functin takes the format string and the value. But I'm not able to
107 * test whether the format string and the type match !!!
109 * TODO: Return value of the parser should be a string allocated on the mempool of the table. But:
110 * is the return value really necessary? The error should be show to the user on the terminal
112 * TODO: all macros prefix TBL_ should be changed to TABLE_ ?
113 * TODO: how to print column which is aligned to the left flag for alignment: 1) left; 2) right;
114 * 3) decimal point alignment; 4) arbitrary separator alignment
119 /** Specification of a single table column */
120 struct table_column {
121 const char *name; // [*] name of the column displayed in the header
122 int width; // [*] width of the column (in characters). Negative number indicates alignment to left. SHOULD BE RATHER INDICATED BY A FLAG?
123 const char *fmt; // [*] default format of each cell in the column
124 enum column_type type; // type of the cells in the column.
127 struct table_output_callbacks {
128 int (*row_output_func)(struct table *tbl); // [*] function that outputs one row
129 int (*table_start_callback)(struct table *tbl); // [*] table_start callback
130 int (*table_end_callback)(struct table *tbl); // [*] table_end callback
131 // FIXME: Int -> void?
132 int (*process_option)(struct table *tbl, const char *key, const char *value);
133 // FIXME: Shouldn't it be possible to return also a custom error string? For example in an optionally writeable `const char **' argument.
136 /** The definition of a table. Contains column definitions plus internal data. */
138 struct table_column *columns; // [*] columns definition
139 int column_count; // [*] number of columns of the table
140 struct mempool *pool; // memory pool used for storing all the data. At the beggining are the data needed for printing
141 // the whole table (delimited by table_start, table_end)
142 struct mempool_state pool_state; // state of the pool AFTER the table is initialized. The state is used for
143 // deallocation of the strings used for printing single table row
145 char **col_str_ptrs; // used to store the position of the row in the memory pool
147 uint *column_order; // [*] order of the columns in the print-out of the table.
148 uint cols_to_output; // [*] number of columns that are printed.
149 const char *col_delimiter; // [*] delimiter that is placed between the columns
150 const char *append_delimiter; // [*] character used for delimiting the values in a single cell
151 uint print_header; // [*] 0 indicates that the header should not be printed
153 struct fastbuf *out; // fastbuffer that is used for outputing the table rows
154 int last_printed_col; // index of the last column which was set. -1 indicates start of row. Used for example for
155 // appending to the last column.
156 int row_printing_started; // this can be considered as a duplicity of last_printed_col (it is -1 if the row printing
157 // did not start), but it is probably better to store the flag separately
159 struct fbpool fb_col_out; // used for printing using the fast buffers(into the mempool), @see table_col_fbstart()
160 int col_out; // index of the column that is currently printed using fb_col_out
162 struct table_output_callbacks *callbacks;
163 void *data; // [*] user-managed data. the data can be used for example in row_output_func, table_start_callback, table_end_callback
168 * table_init serves for initialization of the table. The @tbl parameter should have set the columns member of
169 * the table structure. The @out parameter is supplied by the caller and can be deallocated after table_deinit
172 void table_init(struct table *tbl, struct fastbuf *out);
173 void table_cleanup(struct table *tbl);
176 * table_start is called before the cells of the table are set. After the table_start is called, the user can
177 * call the table_set_* functions. The table_end_of_row function can be called after the table_start is called
178 * (but before the table_end is called)
180 void table_start(struct table *tbl);
183 * This function must be called after all the rows of the current table are printed. The table_set_*
184 * functions can be called in between table_start and table_end calls.
186 void table_end(struct table *tbl);
189 * Sets the order in which the columns are printed. The @col_order parameter is used until the table_end or
190 * table_cleanup is called. The table stores the pointer only and the memory pointed to by @col_order is
191 * allocated and deallocated by the caller.
193 void table_col_order(struct table *tbl, int *col_order, int col_order_size);
196 * Sets the order in which the columns are printed. The specification is a string with comma delimited column
199 int table_col_order_by_name(struct table *tbl, const char *col_order);
202 * Called when all the cells have filled values. The function the prints a table row into the output stream.
203 * The table row has newline at the end.
205 void table_end_row(struct table *tbl);
208 * Prints a string that is printf-like formated into a particular column. This function does not check the
209 * type of the column, i.e., it can be used to print double into an int column
211 void table_set_printf(struct table *tbl, int col, const char *fmt, ...) FORMAT_CHECK(printf, 3, 4);
214 * Appends a string that is printf-like formated to the last printed column. This function does not check the
215 * type of the column, i.e., it can be used to print double into an int column
217 void table_append_printf(struct table *tbl, const char *fmt, ...) FORMAT_CHECK(printf, 2, 3);
220 * Find the index of a column with name @col_name and returns it. Returns -1 if the column was not found.
222 int table_get_col_idx(struct table *tbl, const char *col_name);
225 * Returns comma-separated list of column names
227 const char * table_get_col_list(struct table *tbl);
230 * Opens a fastbuf stream that can be used for creating a cell content. The @sz parameter is the initial size
231 * allocated on the memory pool.
233 struct fastbuf *table_col_fbstart(struct table *tbl, int col);
234 // FIXME: test table_col_fbstart/table_col_fbend
237 * Closes the stream that is used for printing of the last column
239 void table_col_fbend(struct table *tbl);
242 * Sets the callbacks in @tbl. The callbacks are stored the arg @callbacks.
244 void table_set_output_callbacks(struct table *tbl, struct table_output_callbacks *callbacks);
248 * Process the table one option and sets the values in @tbl according to the command-line parameters.
249 * The option has the following format: a) "<key>:<value>"; b) "<key>" (currently not used).
251 * Possible key-value pairs:
252 * header:[0|1] - 1 indicates that the header should be printed, 0 otherwise
253 * noheader - equivalent to header:0
254 * cols:<string-with-col-names> - comma-separated list of columns that will be printed (in the order specified on the cmd-line)
255 * fmt:[human|machine|...] - output type
256 * col-delim:<char> - column delimiter
258 * Returns NULL on success or an error string otherwise.
260 const char *table_set_option(struct table *tbl, const char *opt);
261 const char *table_set_gary_options(struct table *tbl, char **gary_table_opts);
263 extern struct table_output_callbacks table_fmt_human_readable;
264 extern struct table_output_callbacks table_fmt_machine_readable;
266 #define TABLE_SET_COL_PROTO(_name_, _type_) void table_set_##_name_(struct table *tbl, int col, _type_ val);\
267 void table_set_##_name_##_name(struct table *tbl, const char *col_name, _type_ val);\
268 void table_set_##_name_##_fmt(struct table *tbl, int col, const char *fmt, _type_ val) FORMAT_CHECK(printf, 3, 0);
270 // table_set_<type>_fmt has one disadvantage: it is not possible to
271 // check whether fmt contains format that contains formatting that is
272 // compatible with _type_
274 TABLE_SET_COL_PROTO(int, int);
275 TABLE_SET_COL_PROTO(uint, uint);
276 TABLE_SET_COL_PROTO(double, double);
277 TABLE_SET_COL_PROTO(str, const char *);
278 TABLE_SET_COL_PROTO(intmax, intmax_t);
279 TABLE_SET_COL_PROTO(uintmax, uintmax_t);
281 void table_set_bool(struct table *tbl, int col, uint val);
282 void table_set_bool_name(struct table *tbl, const char *col_name, uint val);
283 void table_set_bool_fmt(struct table *tbl, int col, const char *fmt, uint val);
284 #undef TABLE_SET_COL_PROTO
286 #define TABLE_APPEND_PROTO(_name_, _type_) void table_append_##_name_(struct table *tbl, _type_ val)
287 TABLE_APPEND_PROTO(int, int);
288 TABLE_APPEND_PROTO(uint, uint);
289 TABLE_APPEND_PROTO(double, double);
290 TABLE_APPEND_PROTO(str, const char *);
291 TABLE_APPEND_PROTO(intmax, intmax_t);
292 TABLE_APPEND_PROTO(uintmax, uintmax_t);
293 void table_append_bool(struct table *tbl, int val);
294 #undef TABLE_APPEND_PROTO