]> mj.ucw.cz Git - libucw.git/blob - ucw/table.h
3ef913e8e7bcc803ca747e2321bdda0d9cc78f52
[libucw.git] / ucw / table.h
1 /*
2  *      UCW Library -- Table printer
3  *
4  *      (c) 2014 Robert Kessl <robert.kessl@economia.cz>
5  */
6
7 #ifndef _UCW_TABLE_H
8 #define _UCW_TABLE_H
9
10 #include <ucw/fastbuf.h>
11 #include <ucw/mempool.h>
12
13 enum column_type {
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
15 };
16
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 }
26
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 }
34
35 #define TBL_COL_END { .name = 0, .width = 0, .fmt = 0, .type = COL_TYPE_LAST }
36
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_
41
42 #define TBL_OUTPUT_HUMAN_READABLE     .callbacks = &table_fmt_human_readable
43 #define TBL_OUTPUT_MACHINE_READABLE   .callbacks = &table_fmt_machine_readable
44
45 /***
46  * [[ Usage ]]
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.
55  *
56  * Default behaviour of the table_set_col_* is replacement of already set data. To append, the user
57  * must use table_append_*
58  *
59  * To summarize:
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.
67  *
68  *
69  * An example of the procedure is following sequence of calls:
70  *  table_init
71  *
72  *  table_start
73  *  table_end
74  *  table_start
75  *  table_end
76  *
77  *  table_cleanup
78  *
79  * The tableprinter supports user-specified callback for each row and table-print (i.e., a callback
80  * that is called in table_end).
81  *
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
92  *
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.
96  *
97  * Features:
98  * * user supplied callback functions can be used for modifying the output format.
99  *
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?
103  * TODO:
104  * * unsupported: (dynamic) alignment of cells which is computed in table_end
105  *
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 !!!
108  *
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
111  * (std. out).
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
115  ***/
116
117 struct table;
118
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.
125 };
126
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.
134 };
135
136 /** The definition of a table. Contains column definitions plus internal data. */
137 struct table {
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
144
145   char **col_str_ptrs; // used to store the position of the row in the memory pool
146
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
152
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
158
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
161
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
164 };
165
166
167 /**
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
170  * is called.
171  **/
172 void table_init(struct table *tbl, struct fastbuf *out);
173 void table_cleanup(struct table *tbl);
174
175 /**
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)
179  **/
180 void table_start(struct table *tbl);
181
182 /**
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.
185  **/
186 void table_end(struct table *tbl);
187
188 /**
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.
192  **/
193 void table_col_order(struct table *tbl, int *col_order, int col_order_size);
194
195 /**
196  * Sets the order in which the columns are printed. The specification is a string with comma delimited column
197  * names.
198  **/
199 int table_col_order_by_name(struct table *tbl, const char *col_order);
200
201 /**
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.
204  **/
205 void table_end_row(struct table *tbl);
206
207 /**
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
210  **/
211 void table_set_printf(struct table *tbl, int col, const char *fmt, ...) FORMAT_CHECK(printf, 3, 4);
212
213 /**
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
216  **/
217 void table_append_printf(struct table *tbl, const char *fmt, ...) FORMAT_CHECK(printf, 2, 3);
218
219 /**
220  * Find the index of a column with name @col_name and returns it. Returns -1 if the column was not found.
221  **/
222 int table_get_col_idx(struct table *tbl, const char *col_name);
223
224 /**
225  * Returns comma-separated list of column names
226  **/
227 const char * table_get_col_list(struct table *tbl);
228
229 /**
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.
232  **/
233 struct fastbuf *table_col_fbstart(struct table *tbl, int col);
234 // FIXME: test table_col_fbstart/table_col_fbend
235
236 /**
237  * Closes the stream that is used for printing of the last column
238  **/
239 void table_col_fbend(struct table *tbl);
240
241 /**
242  * Sets the callbacks in @tbl. The callbacks are stored the arg @callbacks.
243  **/
244 void table_set_output_callbacks(struct table *tbl, struct table_output_callbacks *callbacks);
245
246
247 /**
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).
250  *
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
257  *
258  * Returns NULL on success or an error string otherwise.
259  **/
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);
262
263 extern struct table_output_callbacks table_fmt_human_readable;
264 extern struct table_output_callbacks table_fmt_machine_readable;
265
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);
269
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_
273
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);
280
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
285
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
295
296 #endif