X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ucw%2Ftable.h;h=494276bada5f4d14a95de042d5a468c01390961e;hb=a7bae3293ad367903df28054af1e0b9be3d169b5;hp=3ef913e8e7bcc803ca747e2321bdda0d9cc78f52;hpb=16f90580d144c1fa891020dc997032d8cc80ad9c;p=libucw.git diff --git a/ucw/table.h b/ucw/table.h index 3ef913e8..494276ba 100644 --- a/ucw/table.h +++ b/ucw/table.h @@ -7,290 +7,406 @@ #ifndef _UCW_TABLE_H #define _UCW_TABLE_H +#include + #include #include +#include + +#ifdef CONFIG_UCW_CLEAN_ABI +#define table_cleanup ucw_table_cleanup +#define table_col_bool ucw_table_col_bool +#define table_col_double ucw_table_col_double +#define table_col_fbend ucw_table_col_fbend +#define table_col_fbstart ucw_table_col_fbstart +#define table_col_generic_format ucw_table_col_generic_format +#define table_col_int ucw_table_col_int +#define table_col_intmax ucw_table_col_intmax +#define table_col_is_printed ucw_table_col_is_printed +#define table_col_printf ucw_table_col_printf +#define table_col_s64 ucw_table_col_s64 +#define table_col_str ucw_table_col_str +#define table_col_str ucw_table_col_str +#define table_col_u64 ucw_table_col_u64 +#define table_col_uint ucw_table_col_uint +#define table_col_uintmax ucw_table_col_uintmax +#define table_end ucw_table_end +#define table_end_row ucw_table_end_row +#define table_fmt_blockline ucw_table_fmt_blockline +#define table_fmt_human_readable ucw_table_fmt_human_readable +#define table_fmt_machine_readable ucw_table_fmt_machine_readable +#define table_get_col_idx ucw_table_get_col_idx +#define table_get_col_list ucw_table_get_col_list +#define table_init ucw_table_init +#define table_reset_row ucw_table_reset_row +#define table_set_col_opt ucw_table_set_col_opt +#define table_set_col_order ucw_table_set_col_order +#define table_set_col_order_by_name ucw_table_set_col_order_by_name +#define table_set_formatter ucw_table_set_formatter +#define table_set_gary_options ucw_table_set_gary_options +#define table_set_option ucw_table_set_option +#define table_set_option_value ucw_table_set_option_value +#define table_start ucw_table_start +#endif -enum column_type { - 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 -}; +/*** + * Table definitions + * ----------------- + ***/ -#define TBL_COL_STR(_enum_prefix, _name, _width) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = "%s", .type = COL_TYPE_STR } -#define TBL_COL_INT(_enum_prefix, _name, _width) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = "%d", .type = COL_TYPE_INT } -#define TBL_COL_UINT(_enum_prefix, _name, _width) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = "%u", .type = COL_TYPE_UINT } -#define TBL_COL_INTMAX(_enum_prefix, _name, _width) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = "%jd", .type = COL_TYPE_INTMAX } -#define TBL_COL_UINTMAX(_enum_prefix, _name, _width) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = "%ju", .type = COL_TYPE_UINTMAX } -#define TBL_COL_HEXUINT(_enum_prefix, _name, _width) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = "0x%x", .type = COL_TYPE_UINT } -#define TBL_COL_DOUBLE(_enum_prefix, _name, _width, _prec) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = "%." #_prec "lf", .type = COL_TYPE_DOUBLE } -#define TBL_COL_BOOL(_enum_prefix, _name, _width) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = "%s", .type = COL_TYPE_BOOL } -#define TBL_COL_ANY(_enum_prefix, _name, _width) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = 0, .type = COL_TYPE_ANY } - -#define TBL_COL_STR_FMT(_enum_prefix, _name, _width, _fmt) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = _fmt, .type = COL_TYPE_STR } -#define TBL_COL_INT_FMT(_enum_prefix, _name, _width, _fmt) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = _fmt, .type = COL_TYPE_INT } -#define TBL_COL_UINT_FMT(_enum_prefix, _name, _width, _fmt) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = _fmt, .type = COL_TYPE_UINT } -#define TBL_COL_INTMAX_FMT(_enum_prefix, _name, _width, _fmt) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = _fmt, .type = COL_TYPE_INTMAX } -#define TBL_COL_UINTMAX_FMT(_enum_prefix, _name, _width, _fmt) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = _fmt, .type = COL_TYPE_UINTMAX } -#define TBL_COL_HEXUINT_FMT(_enum_prefix, _name, _width, _fmt) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = _fmt, .type = COL_TYPE_UINT } -#define TBL_COL_BOOL_FMT(_enum_prefix, _name, _width, _fmt) [_enum_prefix##_##_name] = { .name = #_name, .width = _width, .fmt = _fmt, .type = COL_TYPE_BOOL } - -#define TBL_COL_END { .name = 0, .width = 0, .fmt = 0, .type = COL_TYPE_LAST } +// FIXME: update documentation according to the changes made in recent commits! -#define TBL_COLUMNS .columns = (struct table_column []) -#define TBL_COL_ORDER(order) .column_order = (int *) order, .cols_to_output = ARRAY_SIZE(order) -#define TBL_COL_DELIMITER(_delimiter_) .col_delimiter = _delimiter_ -#define TBL_APPEND_DELIMITER(_delimiter_) .append_delimiter = _delimiter_ +/** The COL_TYPE_ANY macro specifies a column type which can be filled with arbitrary type. **/ -#define TBL_OUTPUT_HUMAN_READABLE .callbacks = &table_fmt_human_readable -#define TBL_OUTPUT_MACHINE_READABLE .callbacks = &table_fmt_machine_readable +#define COL_TYPE_ANY NULL -/*** - * [[ Usage ]] - * The table works as follows: - * The table can be used after table_init is called. Then at the beginning of each printing, the - * table_start function must be called. After printing, the table_end must be called. The - * table_start MUST be paired with table_end. Inbetween table_start/table_end the user can set the - * cells of one row and one row is finished and printed using table_end_of_row. The pairs - * table_start/table_end can be used multiple-times for one table. The table is deallocated using - * table_cleanup. After table_cleanup is called it is not possible to further use the struct table. - * The struct table must be reinitialized. - * - * Default behaviour of the table_set_col_* is replacement of already set data. To append, the user - * must use table_append_* - * - * To summarize: - * 1) @table_init is called; - * 2) @table_start is called following by table_set_xxx functions and @table_end. - * table_start/table_end forms 1-level parenthesis structure. Some of the table - * settings can be changed only between table_init and @table_start or after table_end - * is called (but before next table_start. - * 3) the table is deallocated using @table_cleanup. After the cleanup - * is done, the struct table is unusable and must be initialized. - * - * - * An example of the procedure is following sequence of calls: - * table_init - * - * table_start - * table_end - * table_start - * table_end - * - * table_cleanup - * - * The tableprinter supports user-specified callback for each row and table-print (i.e., a callback - * that is called in table_end). - * - * The table is initialized by defining a table struct using the following macros: - * o TBL_START_COLUMNS indicates start of definition of columns - * o TBL_COL_XXX macros specify the column types with some default formatting the column is specified using a column - * name (which should be C identifier) and a prefix. the column name is the a string with the column - * name. The prefix is used for discriminating between columns from different tables. The column index - * should be taken from an enum. The enum identifier is prefix concatenated with the column name identifier. - * o TBL_COL_XXX_F macros specify column types with user supplied formatting - * o TBL_COL_END indicates end of column definitions - * o TBL_COL_ORDER specify the column order - * o TBL_COL_DELIMITER specify the in-between cell delimiter - * - * The table cells have strict type control, with the exception of type TBL_COL_ANY. In the case of - * TBL_COL_ANY, the type is not tested and an arbitrary value can be printed into the cell. - * It is also possible to print string to an arbitrary cell. - * - * Features: - * * user supplied callback functions can be used for modifying the output format. - * - * Non-tested features: - * * computing statistics of columns via the table_start_callback/table_end_callback. - * TODO: is it better to have callback for each cell with the original value supplied by the caller of the table_set_* functions? - * TODO: - * * unsupported: (dynamic) alignment of cells which is computed in table_end - * - * TODO: table_set_col_fmt: this functin takes the format string and the value. But I'm not able to - * test whether the format string and the type match !!! - * - * TODO: Return value of the parser should be a string allocated on the mempool of the table. But: - * is the return value really necessary? The error should be show to the user on the terminal - * (std. out). - * TODO: all macros prefix TBL_ should be changed to TABLE_ ? - * TODO: how to print column which is aligned to the left flag for alignment: 1) left; 2) right; - * 3) decimal point alignment; 4) arbitrary separator alignment - ***/ +/** Justify cell contents to the left. **/ +#define CELL_ALIGN_LEFT (1U << 31) + +// CELL_FLAG_MASK has 1's in bits used for column flags, +// CELL_WIDTH_MASK has 1's in bits used for column width. +#define CELL_FLAG_MASK (CELL_ALIGN_LEFT) +#define CELL_WIDTH_MASK (~CELL_FLAG_MASK) struct table; -/** Specification of a single table column */ +/** + * Definition of a single table column. + * Usually, this is generated using the `TABLE_COL_`'type' macros. + * Fields marked with `[*]` are user-accessible. + **/ struct table_column { - const char *name; // [*] name of the column displayed in the header - int width; // [*] width of the column (in characters). Negative number indicates alignment to left. SHOULD BE RATHER INDICATED BY A FLAG? - const char *fmt; // [*] default format of each cell in the column - enum column_type type; // type of the cells in the column. + const char *name; // [*] Name of the column displayed in table header + uint width; // [*] Width of the column (in characters) OR'ed with column flags + uint fmt; // [*] default format of the column + const struct xtype *type_def; // [*] pointer to xtype of this column + + const char * (*set_col_opt)(struct table *tbl, uint col_inst_idx, const char *col_opt); + // [*] process table option for a column instance. @col_inst_idx is the index of the column + // instance to which the @col_opt is set. Return value is the error string. }; -struct table_output_callbacks { - int (*row_output_func)(struct table *tbl); // [*] function that outputs one row - int (*table_start_callback)(struct table *tbl); // [*] table_start callback - int (*table_end_callback)(struct table *tbl); // [*] table_end callback - // FIXME: Int -> void? - int (*process_option)(struct table *tbl, const char *key, const char *value); - // FIXME: Shouldn't it be possible to return also a custom error string? For example in an optionally writeable `const char **' argument. +/** + * Definition of a column instance. The table_col_instance belongs to a struct table. col_def is + * pointing to a definition of the column in struct table::columns. The user can fill only the @idx + * and @fmt. The @col_def, @cell_content, @next_column are private fields. + * + * Please use only fields marked with `[*]`. + **/ +struct table_col_instance { + uint idx; // [*] idx is a index into struct table::columns + const struct table_column *col_def; // this is pointer to the column definition, located in the array struct table::columns + const char *cell_content; // content of the cell of the current row + int next_column; // index of next column in linked list of columns of the same type + uint fmt; // [*] format of this column +}; + +/** + * Definition of a table. Contains column definitions, and some per-table settings. + * Please use only fields marked with `[*]`. + **/ +struct table_template { + const struct table_column *columns; // [*] Definition of columns + struct table_col_instance *column_order; // [*] Order of the columns in the print-out of the table + const char *col_delimiter; // [*] Delimiter that is placed between columns + // Back-end used for table formatting and its private data + const struct table_formatter *formatter; }; -/** The definition of a table. Contains column definitions plus internal data. */ +/** + * Handle of a table. Contains column definitions, per-table settings + * and internal data. To change the table definition, please use only + * fields marked with `[*]`. + **/ struct table { - struct table_column *columns; // [*] columns definition - int column_count; // [*] number of columns of the table - struct mempool *pool; // memory pool used for storing all the data. At the beggining are the data needed for printing - // the whole table (delimited by table_start, table_end) - struct mempool_state pool_state; // state of the pool AFTER the table is initialized. The state is used for - // deallocation of the strings used for printing single table row - - char **col_str_ptrs; // used to store the position of the row in the memory pool - - uint *column_order; // [*] order of the columns in the print-out of the table. - uint cols_to_output; // [*] number of columns that are printed. - const char *col_delimiter; // [*] delimiter that is placed between the columns - const char *append_delimiter; // [*] character used for delimiting the values in a single cell - uint print_header; // [*] 0 indicates that the header should not be printed - - struct fastbuf *out; // fastbuffer that is used for outputing the table rows - int last_printed_col; // index of the last column which was set. -1 indicates start of row. Used for example for - // appending to the last column. - int row_printing_started; // this can be considered as a duplicity of last_printed_col (it is -1 if the row printing - // did not start), but it is probably better to store the flag separately - - struct fbpool fb_col_out; // used for printing using the fast buffers(into the mempool), @see table_col_fbstart() - int col_out; // index of the column that is currently printed using fb_col_out - - struct table_output_callbacks *callbacks; - void *data; // [*] user-managed data. the data can be used for example in row_output_func, table_start_callback, table_end_callback + const struct table_column *columns; // [*] Definition of columns + int column_count; // [*] Number of columns (calculated by table_init()) + int *ll_headers; // headers of linked lists that connects column instances + struct mempool *pool; // Memory pool used for storing table data. Contains global state + // and data of the current row. + struct mempool_state pool_state; // State of the pool after the table is initialized, i.e., before + // per-row data have been allocated. + + struct table_col_instance *column_order; // [*] Order of the columns in the print-out of the table + uint cols_to_output; // [*] Number of columns that are printed + const char *col_delimiter; // [*] Delimiter that is placed between columns + bool print_header; // [*] false indicates that table header should not be printed + + struct fastbuf *out; // [*] Fastbuffer to which the table is printed + bool row_printing_started; // Indicates that a row has been started. + struct fbpool fb_col_out; // Per-cell fastbuf, see table_col_fbstart() + int col_out; // Index of the column that is currently printed using fb_col_out + + // Back-end used for table formatting and its private data + const struct table_formatter *formatter; + void *formatter_data; }; +/**** + * In most cases, table descriptions are constructed using the following macros. + * See the examples above for more details. + * + * * `TBL_COLUMNS` indicates the start of definition of columns + * * `TBL_COL_`'type'`(name, width)` defines a column of a given type + * * `TBL_COL_`'type'`_FMT(name, width, fmt)` defines a column with a custom format string + * * `TBL_COL_END` ends the column definitions + * * `TBL_COL_ORDER` specifies custom ordering of columns in the output + * * `TBL_COL_DELIMITER` overrides the default delimiter + * * `TBL_FMT_HUMAN_READABLE` requests human-readable formatting (this is the default) + * * `TBL_FMT_MACHINE_READABLE` requests machine-readable TSV output + * * `TBL_FMT_BLOCKLINE` requests block formatting (each cell printed a pair of a key and value on its own line) + * + ***/ + +#define TBL_COL_STR(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = &xt_str } +#define TBL_COL_INT(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = &xt_int } +#define TBL_COL_S64(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = &xt_s64 } +#define TBL_COL_UINT(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = &xt_uint } +#define TBL_COL_U64(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = &xt_u64 } +#define TBL_COL_INTMAX(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = &xt_intmax } +#define TBL_COL_UINTMAX(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = &xt_uintmax } +#define TBL_COL_HEXUINT(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = &xt_uint } +#define TBL_COL_DOUBLE(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = &xt_double } +#define TBL_COL_BOOL(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = &xt_bool } +#define TBL_COL_ANY(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = COL_TYPE_ANY } +#define TBL_COL_XTYPE(_name, _width, _xtype) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = _xtype } + +#define TBL_COL_STR_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = &xt_str } +#define TBL_COL_INT_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = &xt_int } +#define TBL_COL_S64_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = &xt_s64 } +#define TBL_COL_UINT_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = &xt_uint } +#define TBL_COL_U64_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = &xt_u64 } +#define TBL_COL_INTMAX_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = &xt_intmax } +#define TBL_COL_UINTMAX_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = &xt_uintmax } +#define TBL_COL_HEXUINT_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = &xt_uint } +#define TBL_COL_BOOL_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = &xt_bool } +#define TBL_COL_ANY_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = COL_TYPE_ANY } +#define TBL_COL_DOUBLE_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = &xt_double } + +#define TBL_COL_END { .name = 0, .width = 0, .fmt = 0, .type_def = NULL } + +#define TBL_COLUMNS .columns = (struct table_column []) +#define TBL_COL_ORDER(order) .column_order = (struct table_col_instance *) order +#define TBL_COL_DELIMITER(_delimiter) .col_delimiter = _delimiter + +/** + * These macros are used for definition of column order + **/ +#define TBL_COL(_idx) { .idx = _idx, .fmt = XTYPE_FMT_DEFAULT, .next_column = -1 } +#define TBL_COL_FMT(_idx, _fmt) { .idx = _idx, .fmt = _fmt, .next_column = -1 } +#define TBL_COL_ORDER_END { .col_def = 0, .idx = ~0U, .fmt = 0, .next_column = -1 } + +/** + * These macros are aliases to various kinds of table formats. + **/ +#define TBL_FMT_HUMAN_READABLE .formatter = &table_fmt_human_readable +#define TBL_FMT_BLOCKLINE .formatter = &table_fmt_blockline +#define TBL_FMT_MACHINE_READABLE .formatter = &table_fmt_machine_readable +#define TBL_FMT(_fmt) .formatter = _fmt /** - * table_init serves for initialization of the table. The @tbl parameter should have set the columns member of - * the table structure. The @out parameter is supplied by the caller and can be deallocated after table_deinit - * is called. + * Creates a new table from a table template. The template should already contain + * the definitions of columns. **/ -void table_init(struct table *tbl, struct fastbuf *out); +struct table *table_init(const struct table_template *tbl_template); + +/** Destroy a table instance, freeing all memory used by it. **/ void table_cleanup(struct table *tbl); /** - * table_start is called before the cells of the table are set. After the table_start is called, the user can - * call the table_set_* functions. The table_end_of_row function can be called after the table_start is called - * (but before the table_end is called) + * Start printing of a table. This is a prerequisite to setting of column values. + * After @table_start() is called, it is no longer possible to change parameters + * of the table by `table_set_`'something' nor by direct access to the table structure. **/ -void table_start(struct table *tbl); +void table_start(struct table *tbl, struct fastbuf *out); /** - * This function must be called after all the rows of the current table are printed. The table_set_* - * functions can be called in between table_start and table_end calls. + * This function must be called after all the rows of the current table are printed, + * making the table structure ready for the next table. You can call `table_set_`'something' + * between @table_end() and @table_start(). **/ void table_end(struct table *tbl); +/*** + * Filling tables with data + * ------------------------ + * + * For each column type, there are functions for filling of cells + * of the particular type: + * + * * `table_col_`'type'`(table, col_def_idx, value)` sets the cell in column `col_def_idx` + * to the `value` + ***/ + +#define TABLE_COL_PROTO(_name, _type) void table_col_##_name(struct table *tbl, int col, _type val); + +TABLE_COL_PROTO(int, int) +TABLE_COL_PROTO(uint, uint) +TABLE_COL_PROTO(double, double) +TABLE_COL_PROTO(intmax, intmax_t) +TABLE_COL_PROTO(uintmax, uintmax_t) +TABLE_COL_PROTO(s64, s64) +TABLE_COL_PROTO(u64, u64) +TABLE_COL_PROTO(bool, bool) +TABLE_COL_PROTO(str, const char *) + +/** TABLE_COL_BODY macro enables easy definitions of bodies of table_col_ functions **/ +#define TABLE_COL_BODY(_name, _type) void table_col_##_name(struct table *tbl, int col, _type val) {\ + table_col_generic_format(tbl, col, (void*)&val, &xt_##_name);\ + } + /** - * Sets the order in which the columns are printed. The @col_order parameter is used until the table_end or - * table_cleanup is called. The table stores the pointer only and the memory pointed to by @col_order is - * allocated and deallocated by the caller. + * The table_col_generic_format performs all the checks necessary while filling cell with value, + * calls the format function from expected_type and stores its result as a cell value. The function + * guarantees that each column instance is printed with its format. **/ -void table_col_order(struct table *tbl, int *col_order, int col_order_size); +void table_col_generic_format(struct table *tbl, int col, void *value, const struct xtype *expected_type); /** - * Sets the order in which the columns are printed. The specification is a string with comma delimited column - * names. + * Set a particular cell of the current row to a string formatted + * by sprintf(). This function can set a column of an arbitrary type. **/ -int table_col_order_by_name(struct table *tbl, const char *col_order); +void table_col_printf(struct table *tbl, int col, const char *fmt, ...) FORMAT_CHECK(printf, 3, 4); /** - * Called when all the cells have filled values. The function the prints a table row into the output stream. - * The table row has newline at the end. + * Alternatively, a string cell can be constructed as a stream. + * This function creates a fastbuf stream connected to the contents + * of the particular cell. Before you close the stream by @table_col_fbend(), + * no other operations with cells are allowed. **/ -void table_end_row(struct table *tbl); +struct fastbuf *table_col_fbstart(struct table *tbl, int col); + +/** + * Close the stream that is used for printing of the current column. + **/ +void table_col_fbend(struct table *tbl); /** - * Prints a string that is printf-like formated into a particular column. This function does not check the - * type of the column, i.e., it can be used to print double into an int column + * Called when all cells of the current row have their values filled in. + * It sends the completed row to the output stream. **/ -void table_set_printf(struct table *tbl, int col, const char *fmt, ...) FORMAT_CHECK(printf, 3, 4); +void table_end_row(struct table *tbl); /** - * Appends a string that is printf-like formated to the last printed column. This function does not check the - * type of the column, i.e., it can be used to print double into an int column + * Resets data in the current row. **/ -void table_append_printf(struct table *tbl, const char *fmt, ...) FORMAT_CHECK(printf, 2, 3); +void table_reset_row(struct table *tbl); + +/*** + * Configuration functions + * ----------------------- + ***/ /** - * Find the index of a column with name @col_name and returns it. Returns -1 if the column was not found. + * Find the index of a column definition with name @col_name. Returns -1 if there is no such column. **/ int table_get_col_idx(struct table *tbl, const char *col_name); /** - * Returns comma-separated list of column names + * Sets a string option on a column instance. + * + * By default, the option is parsed as a formatting mode of the corresponding <> + * using <>. + * + * As special cases might require special handling (e.g., column decoration, post-processing, etc.), + * a column can define a `set_col_opt` hook, which takes over option parsing. (Beware, the hook must + * not be called directly and it must not call this function.) + * + * See <> for more. **/ -const char * table_get_col_list(struct table *tbl); +const char *table_set_col_opt(struct table *tbl, uint col_inst_idx, const char *col_opt); /** - * Opens a fastbuf stream that can be used for creating a cell content. The @sz parameter is the initial size - * allocated on the memory pool. + * Returns a comma-and-space-separated list of column names, allocated from table's internal + * memory pool. **/ -struct fastbuf *table_col_fbstart(struct table *tbl, int col); -// FIXME: test table_col_fbstart/table_col_fbend +const char *table_get_col_list(struct table *tbl); /** - * Closes the stream that is used for printing of the last column + * Sets the order in which the columns are printed. The columns are specified by array of struct + * @table_col_instance. This allows specification of format. The user should make an array of struct + * @table_col_instance and fill the array using the TBL_COL and TBL_COL_FMT. The array has a special + * last element: @TBL_COL_ORDER_END. + * + * The table copies content of @col_order into an internal representation stored + * in `column_order`. Options to column instances can be set using @table_set_col_opt(). **/ -void table_col_fbend(struct table *tbl); +void table_set_col_order(struct table *tbl, const struct table_col_instance *col_order); + +/** + * Sets the order in which the columns are printed. The specification is a string with comma-separated column + * names. Returns NULL for success and an error message otherwise. The string is not referenced after + * this function returns. + * + * See <> for full syntax. + **/ +const char *table_set_col_order_by_name(struct table *tbl, const char *col_order); /** - * Sets the callbacks in @tbl. The callbacks are stored the arg @callbacks. + * Returns true if @col_def_idx will be printed, false otherwise. **/ -void table_set_output_callbacks(struct table *tbl, struct table_output_callbacks *callbacks); +bool table_col_is_printed(struct table *tbl, uint col_def_idx); +/** + * Sets table formatter. See below for the list of formatters. + **/ +void table_set_formatter(struct table *tbl, const struct table_formatter *fmt); /** - * Process the table one option and sets the values in @tbl according to the command-line parameters. - * The option has the following format: a) ":"; b) "" (currently not used). - * - * Possible key-value pairs: - * header:[0|1] - 1 indicates that the header should be printed, 0 otherwise - * noheader - equivalent to header:0 - * cols: - comma-separated list of columns that will be printed (in the order specified on the cmd-line) - * fmt:[human|machine|...] - output type - * col-delim: - column delimiter - * - * Returns NULL on success or an error string otherwise. + * Set a table option. All options have a key and a value. + * See <>. + **/ +const char *table_set_option_value(struct table *tbl, const char *key, const char *value); + +/** + * Sets a table option given as 'key'`:`'value' or 'key' (with no value). **/ const char *table_set_option(struct table *tbl, const char *opt); + +/** + * Sets several table option in 'key'`:`'value' form, stored in a growing array. + * This is frequently used for options given on the command line. + **/ const char *table_set_gary_options(struct table *tbl, char **gary_table_opts); -extern struct table_output_callbacks table_fmt_human_readable; -extern struct table_output_callbacks table_fmt_machine_readable; - -#define TABLE_SET_COL_PROTO(_name_, _type_) void table_set_##_name_(struct table *tbl, int col, _type_ val);\ - void table_set_##_name_##_name(struct table *tbl, const char *col_name, _type_ val);\ - void table_set_##_name_##_fmt(struct table *tbl, int col, const char *fmt, _type_ val) FORMAT_CHECK(printf, 3, 0); - -// table_set__fmt has one disadvantage: it is not possible to -// check whether fmt contains format that contains formatting that is -// compatible with _type_ - -TABLE_SET_COL_PROTO(int, int); -TABLE_SET_COL_PROTO(uint, uint); -TABLE_SET_COL_PROTO(double, double); -TABLE_SET_COL_PROTO(str, const char *); -TABLE_SET_COL_PROTO(intmax, intmax_t); -TABLE_SET_COL_PROTO(uintmax, uintmax_t); - -void table_set_bool(struct table *tbl, int col, uint val); -void table_set_bool_name(struct table *tbl, const char *col_name, uint val); -void table_set_bool_fmt(struct table *tbl, int col, const char *fmt, uint val); -#undef TABLE_SET_COL_PROTO - -#define TABLE_APPEND_PROTO(_name_, _type_) void table_append_##_name_(struct table *tbl, _type_ val) -TABLE_APPEND_PROTO(int, int); -TABLE_APPEND_PROTO(uint, uint); -TABLE_APPEND_PROTO(double, double); -TABLE_APPEND_PROTO(str, const char *); -TABLE_APPEND_PROTO(intmax, intmax_t); -TABLE_APPEND_PROTO(uintmax, uintmax_t); -void table_append_bool(struct table *tbl, int val); -#undef TABLE_APPEND_PROTO +/*** + * Formatters + * ---------- + * + * Transformation of abstract cell data to the characters in the output stream + * is under control of a formatter (which serves as a back-end of the table printer). + * There are several built-in formatters, but you can define your own. + * + * A formatter is described by a structure, which contains pointers to several + * call-back functions, which are called by the table printer at specific occasions. + * + * The formatter can keep its internal state in the `data` field of `struct table` + * and allocate temporary data from the table's memory pool. Memory allocated in + * the `row_output` call-back is freed before the next row begins. Memory allocated + * between the beginning of `table_start` and the end of `table_end` is freed after + * `table_end`. Memory allocated by `process_option` when no table is started + * is kept until @table_cleanup(). + ***/ + +/** Definition of a formatter back-end. **/ +struct table_formatter { + void (*row_output)(struct table *tbl); // [*] Function that outputs one row + void (*table_start)(struct table *tbl); // [*] table_start callback (optional) + void (*table_end)(struct table *tbl); // [*] table_end callback (optional) + bool (*process_option)(struct table *tbl, const char *key, const char *value, const char **err); + // [*] Process table option and possibly return an error message (optional) +}; + +/** Standard formatter for human-readable output. **/ +extern const struct table_formatter table_fmt_human_readable; + +/** Standard formatter for machine-readable output (tab-separated values). **/ +extern const struct table_formatter table_fmt_machine_readable; + +/** + * Standard formatter for block output. Each cell is output on its own line + * of the form `column_name: value`. Rows are separated by blank lines. + **/ +extern const struct table_formatter table_fmt_blockline; #endif