]> mj.ucw.cz Git - libucw.git/blob - ucw/table.h
Merge branch 'table'
[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,
15   COL_TYPE_INT,
16   COL_TYPE_INTMAX,
17   COL_TYPE_UINT,
18   COL_TYPE_UINTMAX,
19   COL_TYPE_BOOL,
20   COL_TYPE_DOUBLE,
21   COL_TYPE_ANY,
22   COL_TYPE_LAST
23 };
24
25 #define CELL_ALIGN_LEFT     (1<<(sizeof(enum column_type)*8 - 1))
26 // FIXME: an example of another flag, not implemented now
27 #define CELL_ALIGN_CENTER   (1<<(sizeof(enum column_type)*8 - 2))
28 #define CELL_ALIGN_FLOAT    (1<<(sizeof(enum column_type)*8 - 3))
29
30 // CELL_ALIGN_MASK is a mask which has 1's on positions used by some alignment mask.
31 // that is: col_width & CELL_ALIGN_MASK  gives column width (in characters).
32 // the top bit is reserved for left alignment and is not demasked by CELL_ALIGN_MASK.
33 // the reason is that all printf and friends are using negative number for left alignment.
34 #define CELL_ALIGN_MASK     (~(CELL_ALIGN_LEFT | CELL_ALIGN_FLOAT | CELL_ALIGN_CENTER))
35
36 #define TBL_COL_STR(_name, _width)            { .name = _name, .width = _width, .fmt = "%s", .type = COL_TYPE_STR }
37 #define TBL_COL_INT(_name, _width)            { .name = _name, .width = _width, .fmt = "%d", .type = COL_TYPE_INT }
38 #define TBL_COL_UINT(_name, _width)           { .name = _name, .width = _width, .fmt = "%u", .type = COL_TYPE_UINT }
39 #define TBL_COL_INTMAX(_name, _width)         { .name = _name, .width = _width, .fmt = "%jd", .type = COL_TYPE_INTMAX }
40 #define TBL_COL_UINTMAX(_name, _width)        { .name = _name, .width = _width, .fmt = "%ju", .type = COL_TYPE_UINTMAX }
41 #define TBL_COL_HEXUINT(_name, _width)        { .name = _name, .width = _width, .fmt = "0x%x", .type = COL_TYPE_UINT }
42 #define TBL_COL_DOUBLE(_name, _width, _prec)  { .name = _name, .width = _width, .fmt = "%." #_prec "lf", .type = COL_TYPE_DOUBLE }
43 #define TBL_COL_BOOL(_name, _width)           { .name = _name, .width = _width, .fmt = "%s", .type = COL_TYPE_BOOL }
44 #define TBL_COL_ANY(_name, _width)            { .name = _name, .width = _width, .fmt = 0, .type = COL_TYPE_ANY }
45
46 #define TBL_COL_STR_FMT(_name, _width, _fmt)            { .name = _name, .width = _width, .fmt = _fmt, .type = COL_TYPE_STR }
47 #define TBL_COL_INT_FMT(_name, _width, _fmt)            { .name = _name, .width = _width, .fmt = _fmt, .type = COL_TYPE_INT }
48 #define TBL_COL_UINT_FMT(_name, _width, _fmt)           { .name = _name, .width = _width, .fmt = _fmt, .type = COL_TYPE_UINT }
49 #define TBL_COL_INTMAX_FMT(_name, _width, _fmt)         { .name = _name, .width = _width, .fmt = _fmt, .type = COL_TYPE_INTMAX }
50 #define TBL_COL_UINTMAX_FMT(_name, _width, _fmt)        { .name = _name, .width = _width, .fmt = _fmt, .type = COL_TYPE_UINTMAX }
51 #define TBL_COL_HEXUINT_FMT(_name, _width, _fmt)        { .name = _name, .width = _width, .fmt = _fmt, .type = COL_TYPE_UINT }
52 #define TBL_COL_BOOL_FMT(_name, _width, _fmt)           { .name = _name, .width = _width, .fmt = _fmt, .type = COL_TYPE_BOOL }
53
54 #define TBL_COL_END { .name = 0, .width = 0, .fmt = 0, .type = COL_TYPE_LAST }
55
56 #define TBL_COLUMNS  .columns = (struct table_column [])
57 #define TBL_COL_ORDER(order) .column_order = (int *) order, .cols_to_output = ARRAY_SIZE(order)
58 #define TBL_COL_DELIMITER(_delimiter_) .col_delimiter = _delimiter_
59 #define TBL_APPEND_DELIMITER(_delimiter_) .append_delimiter = _delimiter_
60
61 #define TBL_OUTPUT_HUMAN_READABLE     .formatter = &table_fmt_human_readable
62 #define TBL_OUTPUT_MACHINE_READABLE   .formatter = &table_fmt_machine_readable
63
64 /***
65  * [[ Usage ]]
66  * The table works as follows:
67  * The table can be used after table_init is called. Then at the beginning of each printing, the
68  * table_start function must be called. After printing, the table_end must be called. The
69  * table_start MUST be paired with table_end. Inbetween table_start/table_end the user can set the
70  * cells of one row and one row is finished and printed using table_end_row. The pairs
71  * table_start/table_end can be used multiple-times for one table. The table is deallocated using
72  * table_cleanup. After table_cleanup is called it is not possible to further use the struct table.
73  * The struct table must be reinitialized.
74  *
75  * Default behaviour of the table_col_* is replacement of already set data. To append, the user
76  * must use table_append_*
77  *
78  * To summarize:
79  * 1) @table_init is called;
80  * 2) @table_start is called following by table_col_xxx functions and @table_end.
81  *    table_start/table_end forms 1-level parenthesis structure. Some of the table
82  *    settings can be changed only between table_init and @table_start or after table_end
83  *    is called (but before next table_start.
84  * 3) the table is deallocated using @table_cleanup. After the cleanup
85  *    is done, the struct table is unusable and must be initialized.
86  *
87  *
88  * An example of the procedure is following sequence of calls:
89  *  table_init
90  *
91  *  table_start
92  *  table_end
93  *  table_start
94  *  table_end
95  *
96  *  table_cleanup
97  *
98  * The tableprinter supports user-specified callback for each row and table-print (i.e., a callback
99  * that is called in table_end).
100  *
101  * The table is initialized by defining a table struct using the following macros:
102  *  o TBL_COLUMNS    indicates start of definition of columns
103  *  o TBL_COL_XXX    macros specify the column types with some default formatting the column is specified using a column
104  *                   name (which should be C identifier) and a prefix.  the column name is the a string with the column
105  *                   name. The prefix is used for discriminating between columns from different tables. The column index
106  *                   should be taken from an enum. The enum identifier is prefix concatenated with the column name identifier.
107  *  o TBL_COL_XXX_F  macros specify column types with user supplied formatting
108  *  o TBL_COL_END    indicates end of column definitions
109  *  o TBL_COL_ORDER  specify the column order
110  *  o TBL_COL_DELIMITER specify the in-between cell delimiter
111  *
112  * The table cells have strict type control, with the exception of type TBL_COL_ANY. In the case of
113  * TBL_COL_ANY, the type is not tested and an arbitrary value can be printed into the cell.
114  * It is also possible to print string to an arbitrary cell.
115  *
116  * Features:
117  * * user supplied callback functions can be used for modifying the output format.
118  *
119  * TODO part/Planned features:
120  * * computing statistics of columns via the table_start_callback/table_end_callback.
121  * * unsupported: (dynamic) alignment of cells which is computed in table_end
122  *
123  * TODO: table_set_col_fmt: this functin takes the format string and the value. But I'm not able to
124  * test whether the format string and the type match !!!
125  *
126  * TODO: how to print column which is aligned to the left flag for alignment: 1) left; 2) right;
127  *       3) decimal point alignment;
128  ***/
129
130 struct table;
131
132 /** Specification of a single table column */
133 struct table_column {
134   const char *name;             // [*] Name of the column displayed in table header
135   int width;                    // [*] Width of the column (in characters). Negative number indicates alignment to left.
136                                 // FIXME: Request left alignment by a flag.
137   const char *fmt;              // [*] Default format of each cell in the column
138   enum column_type type;        // Type of the cells in the column
139 };
140
141 /** The definition of a table. Contains column definitions plus internal data. */
142 struct table {
143   struct table_column *columns;         // [*] Definition of columns
144   int column_count;                     // [*] Number of columns (calculated by table_init())
145   struct mempool *pool;                 // Memory pool used for storing table data. Contains global state
146                                         // and data of the current row.
147   struct mempool_state pool_state;      // State of the pool after the table is initialized, i.e., before
148                                         // per-row data have been allocated.
149
150   char **col_str_ptrs;                  // Values of cells in the current row (allocated from the pool)
151
152   uint *column_order;                   // [*] Order of the columns in the print-out of the table
153   uint cols_to_output;                  // [*] Number of columns that are printed
154   const char *col_delimiter;            // [*] Delimiter that is placed between columns
155   const char *append_delimiter;         // [*] Separator of multiple values in a single cell (see table_append_...())
156   uint print_header;                    // [*] 0 indicates that table header should not be printed
157
158   struct fastbuf *out;                  // Fastbuffer to which the table is printed
159   int last_printed_col;                 // Index of the last column which was set. -1 indicates start of row.
160                                         // Used for example for appending to the current column.
161   int row_printing_started;             // Indicates that a row has been started. Duplicates last_printed_col, but harmlessly.
162   struct fbpool fb_col_out;             // Per-cell fastbuf, see table_col_fbstart()
163   int col_out;                          // Index of the column that is currently printed using fb_col_out
164
165   // Back-end used for table formatting and its private data
166   struct table_formatter *formatter;
167   void *data;
168 };
169
170
171 /**
172  * table_init serves for initialization of the table. The @tbl parameter should have set the columns member of
173  * the table structure. The @out parameter is supplied by the caller and can be deallocated after table_deinit
174  * is called.
175  *
176  * FIXME: Why the fastbuf is set there? It would make sense to pass it to table_start(), so that
177  * different instances of the table can be printed to different destinations. Also, the remark
178  * about deallocation does not make much sense, the fastbuf is definitely not copied, only
179  * a pointer to it.
180  **/
181 void table_init(struct table *tbl);
182 void table_cleanup(struct table *tbl);
183
184 /**
185  * table_start is called before the cells of the table are set. After the table_start is called, the
186  * user can call the table_col_* or table_append_ functions and cannot call the table_set_*
187  * functions. The table_end_row function can be called after the table_start is called (but before
188  * the table_end is called)
189  **/
190 void table_start(struct table *tbl, struct fastbuf *out);
191
192 /**
193  * This function must be called after all the rows of the current table are printed. The table_set_*
194  * functions can be called in between table_start and table_end calls.
195  **/
196 void table_end(struct table *tbl);
197
198 /**
199  * Sets the order in which the columns are printed. The @col_order parameter is used until the table_end or
200  * table_cleanup is called. The table stores the pointer only and the memory pointed to by @col_order is
201  * allocated and deallocated by the caller.
202  **/
203 void table_set_col_order(struct table *tbl, int *col_order, int col_order_size);
204
205 /**
206  * Sets the order in which the columns are printed. The specification is a string with comma-separated column
207  * names. Returns NULL for success and an error message otherwise.
208  **/
209 const char * table_set_col_order_by_name(struct table *tbl, const char *col_order);
210
211 /**
212  * Called when all the cells have filled values. The function the prints a table row into the output stream.
213  * The table row has newline at the end.
214  **/
215 void table_end_row(struct table *tbl);
216
217 /**
218  * Prints a string that is printf-like formated into a particular column. This function does not check the
219  * type of the column, i.e., it can be used to print double into an int column
220  **/
221 void table_col_printf(struct table *tbl, int col, const char *fmt, ...) FORMAT_CHECK(printf, 3, 4);
222
223 /**
224  * Appends a string that is printf-like formated to the last printed column. This function does not check the
225  * type of the column, i.e., it can be used to print double into an int column.
226  **/
227 void table_append_printf(struct table *tbl, const char *fmt, ...) FORMAT_CHECK(printf, 2, 3);
228
229 /**
230  * Find the index of a column with name @col_name and returns it. Returns -1 if the column was not found.
231  **/
232 int table_get_col_idx(struct table *tbl, const char *col_name);
233
234 /**
235  * Returns comma-and-space-separated list of column names, allocated from table's internal
236  * memory pool.
237  **/
238 const char * table_get_col_list(struct table *tbl);
239
240 /**
241  * Opens a fastbuf stream that can be used for creating a cell content. The @sz parameter is the initial size
242  * allocated on the memory pool.
243  **/
244 struct fastbuf *table_col_fbstart(struct table *tbl, int col);
245 // FIXME: test table_col_fbstart/table_col_fbend
246
247 /**
248  * Closes the stream that is used for printing of the last column.
249  **/
250 void table_col_fbend(struct table *tbl);
251
252 /**
253  * Sets table formatter for @tbl.
254  **/
255 void table_set_formatter(struct table *tbl, struct table_formatter *fmt);
256
257 /** Definition of a formatter back-end. **/
258 struct table_formatter {
259   void (*row_output)(struct table *tbl);        // [*] Function that outputs one row
260   void (*table_start)(struct table *tbl);       // [*] table_start callback (optional)
261   void (*table_end)(struct table *tbl);         // [*] table_end callback (optional)
262   bool (*process_option)(struct table *tbl, const char *key, const char *value, const char **err);
263         // [*] Process table option and possibly return an error message (optional)
264 };
265
266 // Standard formatters
267 extern struct table_formatter table_fmt_human_readable;
268 extern struct table_formatter table_fmt_machine_readable;
269
270 /**
271  * Process the table one option and sets the values in @tbl according to the command-line parameters.
272  * The option has the following format: a) "<key>:<value>"; b) "<key>" (currently not used).
273  *
274  * Possible key-value pairs:
275  * header:[0|1]                     - 1 indicates that the header should be printed, 0 otherwise
276  * noheader                         - equivalent to header:0
277  * cols:<string-with-col-names>     - comma-separated list of columns that will be printed (in the order specified on the cmd-line)
278  * fmt:[human|machine|...]          - output type
279  * col-delim:<char>                 - column delimiter
280  *
281  * Returns NULL on success or an error string otherwise.
282  **/
283 const char *table_set_option(struct table *tbl, const char *opt);
284 const char *table_set_option_value(struct table *tbl, const char *key, const char *value);
285 const char *table_set_gary_options(struct table *tbl, char **gary_table_opts);
286
287 #define TABLE_COL_PROTO(_name_, _type_) void table_col_##_name_(struct table *tbl, int col, _type_ val);\
288   void table_col_##_name_##_name(struct table *tbl, const char *col_name, _type_ val);\
289   void table_col_##_name_##_fmt(struct table *tbl, int col, const char *fmt, _type_ val) FORMAT_CHECK(printf, 3, 0);
290
291 // table_col_<type>_fmt has one disadvantage: it is not possible to
292 // check whether fmt contains format that contains formatting that is
293 // compatible with _type_
294
295 TABLE_COL_PROTO(int, int);
296 TABLE_COL_PROTO(uint, uint);
297 TABLE_COL_PROTO(double, double);
298 TABLE_COL_PROTO(str, const char *);
299 TABLE_COL_PROTO(intmax, intmax_t);
300 TABLE_COL_PROTO(uintmax, uintmax_t);
301
302 void table_col_bool(struct table *tbl, int col, uint val);
303 void table_col_bool_name(struct table *tbl, const char *col_name, uint val);
304 void table_col_bool_fmt(struct table *tbl, int col, const char *fmt, uint val);
305 #undef TABLE_COL_PROTO
306
307 #define TABLE_APPEND_PROTO(_name_, _type_) void table_append_##_name_(struct table *tbl, _type_ val)
308 TABLE_APPEND_PROTO(int, int);
309 TABLE_APPEND_PROTO(uint, uint);
310 TABLE_APPEND_PROTO(double, double);
311 TABLE_APPEND_PROTO(str, const char *);
312 TABLE_APPEND_PROTO(intmax, intmax_t);
313 TABLE_APPEND_PROTO(uintmax, uintmax_t);
314 void table_append_bool(struct table *tbl, int val);
315 #undef TABLE_APPEND_PROTO
316
317 #endif