From 86e97319bde70d98a90fcd1452d2fab15a5561bb Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Fri, 20 Jun 2014 16:56:35 +0200 Subject: [PATCH] Docs: Improved table printer documentation First of all, I have added AsciiDoc markup to the whole document and removed redundant parts. Second, I tried to re-arrange everything to bring related concepts together. Finally, I renamed CELL_ALIGN_MASK to something less confusing :) This is a rough draft, which desperately needs proof-reading. --- ucw/doc/Makefile | 2 +- ucw/doc/table.txt | 132 ++++++++------- ucw/table.c | 4 +- ucw/table.h | 422 +++++++++++++++++++++++----------------------- 4 files changed, 287 insertions(+), 273 deletions(-) diff --git a/ucw/doc/Makefile b/ucw/doc/Makefile index 05cf5647..0b60aa10 100644 --- a/ucw/doc/Makefile +++ b/ucw/doc/Makefile @@ -2,7 +2,7 @@ DIRS+=ucw/doc -UCW_DOCS=basics log fastbuf index config configure install basecode hash docsys conf mempool eltpool mainloop generic growbuf unaligned lists chartype unicode prime binsearch heap binheap compress sort hashtable relnotes trans string time daemon signal varint opt alloc gary +UCW_DOCS=basics log fastbuf index config configure install basecode hash docsys conf mempool eltpool mainloop generic growbuf unaligned lists chartype unicode prime binsearch heap binheap compress sort hashtable relnotes trans string time daemon signal varint opt alloc gary table UCW_INDEX=$(o)/ucw/doc/def_index.html UCW_DOCS_HTML=$(addprefix $(o)/ucw/doc/,$(addsuffix .html,$(UCW_DOCS))) diff --git a/ucw/doc/table.txt b/ucw/doc/table.txt index bc352b3e..22e6119d 100644 --- a/ucw/doc/table.txt +++ b/ucw/doc/table.txt @@ -1,83 +1,91 @@ -Tableprinter -============ +Table printer +============= -The table.h provides table printing facility. We need to print table -with arbitrary column types (e.g. int, uint, u64, etc.). The table -columns have names and the order of the columns is configurable. The -table checks that the user writes correct type into a cell of the -table. Additionally, the table allows to print string to an arbitrary -cell (in order to make the table slightly more flexible). +The table printer module provides formatting of 2-dimensional tables +in various ways. -We should be able to print the table in various formats. Currently -there is a human readable format +Each table consists of a number of rows, which are processed one +after another. All rows have the same number of columns. Internally, +the columns have a fixed order, each column has its name and a data +type (e.g., int, uint, u64, etc.). The table printer checks that +each cell is filled by a value of the appropriate type, except that +a string value is allowed in any cell (for example, this allows +a numeric cell to be set to "--" or "unknown"). -We demonstrate the table on a table that contains music recordings: +Once a table is defined, it can be printed using a variety of formatters +(human-readable, tab-separated values, etc.). Also, a subset of columns +can be selected and their order changed. -The following enum defines the column indices (the enum is indexed -starting from 0): +Example +------- -// definition of columns -enum table_columns { - TBL_REC_ID, - TBL_REC_ALBUM_NAME, - TBL_REC_ARTIST, - TBL_REC_YEAR -}; +Let us construct a simple table of music recordings: -The following structure contains definition of the table. The table -columns are defined using the TBL_COL_xxx and TBL_COL_xxx_FMT -macros. The TBL_COL_xxx macro has two arguments: (1) column name; (2) -width of the table column. The TBL_COL_xxx_FMT has an additional -format argument. There exists flags that causes the column to be -left-aligned (see TBL_REC_ALBUM_NAME for a reference). An example of -the table follows: +First, we define an enum with column indices (the values are automatically +numbered starting from 0): -struct table recording_table = { - TBL_COLUMNS { - [TBL_REC_ID] = TBL_COL_UINT("id", 16), - [TBL_REC_ALBUM_NAME] = TBL_COL_STR_FMT("album-name", 20 | CELL_ALIGN_LEFT, "%s"), - [TBL_REC_ARTIST] = TBL_COL_STR("artist", 20), - [TBL_REC_YEAR] = TBL_COL_UINT("year", 10), - TBL_COL_END - } -}; + // Definition of columns + enum table_columns { + TBL_REC_ID, + TBL_REC_ALBUM_NAME, + TBL_REC_ARTIST, + TBL_REC_YEAR + }; -The table struct can be reused for printing of multiple tables. The -usage of the table is used as follows. After the table init is called: +Then we create a structure with the definition of our table. +The table columns are defined using the `TBL_COL_xxx` and `TBL_COL_xxx_FMT` +macros. Each macro gets the name of the column and its default width +in character. The `_FMT` version has an additional argument: the format +string for `printf` used for this column. Moreover, various flags can +be OR-ed to the width of the column, for example `CELL_ALIGN_LEFT` prescribes +that the cell should be aligned to the left. -table_init(&recording_table); + struct table recording_table = { + TBL_COLUMNS { + [TBL_REC_ID] = TBL_COL_UINT("id", 16), + [TBL_REC_ALBUM_NAME] = TBL_COL_STR_FMT("album-name", 20 | CELL_ALIGN_LEFT, "%s"), + [TBL_REC_ARTIST] = TBL_COL_STR("artist", 20), + [TBL_REC_YEAR] = TBL_COL_UINT("year", 10), + TBL_COL_END + } + }; -the table is initialized and ready to use. To start printing of the -table, the user has to initialize the fastbuf (which is used for -output) and call table_start: +Before you use the table definition, you need to initialize it: -struct fastbuf *out = bfdopen_shared(1, 4096); + table_init(&recording_table); -table_start(&recording_table, out); +With a single definition, you can print multiple tables. At the start +of each table, you should obtain a <> where the output +should be sent, store it in the table structure and call table_start(): -after the table_start is called, we can start filling the rows. Each -row is ended by table_end_row: + struct fastbuf *out = bfdopen_shared(1, 4096); + table_start(&recording_table, out); -table_col_uint(&recording_table, TBL_REC_ID, 0); -table_col_str(&recording_table, TBL_REC_ALBUM_NAME, "The Wall"); -table_col_str(&recording_table, TBL_REC_ARTIST, "Pink Floyd"); -table_col_uint(&recording_table, TBL_REC_YEAR, 1979); -table_end_row(&recording_table); +Then you can fill the rows one after another. Each row is ended by +table_end_row(): -table_col_uint(&recording_table, TBL_REC_ID, 1); -table_col_str(&recording_table, TBL_REC_ALBUM_NAME, "Rio Grande Mud"); -table_col_str(&recording_table, TBL_REC_ARTIST, "ZZ Top"); -table_col_uint(&recording_table, TBL_REC_YEAR, 1972); -table_end_row(&recording_table); + table_col_uint(&recording_table, TBL_REC_ID, 0); + table_col_str(&recording_table, TBL_REC_ALBUM_NAME, "The Wall"); + table_col_str(&recording_table, TBL_REC_ARTIST, "Pink Floyd"); + table_col_uint(&recording_table, TBL_REC_YEAR, 1979); + table_end_row(&recording_table); -Printing of the whole table is endded by calling of the table_end(): + table_col_uint(&recording_table, TBL_REC_ID, 1); + table_col_str(&recording_table, TBL_REC_ALBUM_NAME, "Rio Grande Mud"); + table_col_str(&recording_table, TBL_REC_ARTIST, "ZZ Top"); + table_col_uint(&recording_table, TBL_REC_YEAR, 1972); + table_end_row(&recording_table); -table_end(&recording_table); +Finally, you should close the table by calling table_end(): + table_end(&recording_table); -To reuse the recording_table, we just call table_start followed by -table_end once again. +At this moment, the table structure is ready to be used again. When +you do not need it any longer, you can dispose of it by table_cleanup(): -At the end of the lifetime of the struct recording_table we call: -table_cleanup(&recording_table); + table_cleanup(&recording_table); +ucw/table.h +----------- + +!!ucw/table.h diff --git a/ucw/table.c b/ucw/table.c index cc3c9add..d9b904ce 100644 --- a/ucw/table.c +++ b/ucw/table.c @@ -422,7 +422,7 @@ static void table_row_human_readable(struct table *tbl) if(i) { bputs(tbl->out, tbl->col_delimiter); } - int col_width = tbl->columns[col_idx].width & CELL_ALIGN_MASK; + int col_width = tbl->columns[col_idx].width & CELL_WIDTH_MASK; if(tbl->columns[col_idx].width & CELL_ALIGN_LEFT) col_width = -1 * col_width; bprintf(tbl->out, "%*s", col_width, tbl->col_str_ptrs[col_idx]); } @@ -436,7 +436,7 @@ static void table_write_header(struct table *tbl) if(i) { bputs(tbl->out, tbl->col_delimiter); } - int col_width = tbl->columns[col_idx].width & CELL_ALIGN_MASK; + int col_width = tbl->columns[col_idx].width & CELL_WIDTH_MASK; if(tbl->columns[col_idx].width & CELL_ALIGN_LEFT) col_width = -1 * col_width; bprintf(tbl->out, "%*s", col_width, tbl->columns[col_idx].name); } diff --git a/ucw/table.h b/ucw/table.h index 1e771f86..0f2c8b13 100644 --- a/ucw/table.h +++ b/ucw/table.h @@ -51,32 +51,93 @@ #define table_start ucw_table_start #endif +/*** + * Table definitions + * ----------------- + ***/ + +/** Types of columns. These are seldom used explicitly, a column definition macro is used instead. **/ enum column_type { - COL_TYPE_STR, - COL_TYPE_INT, - COL_TYPE_S64, - COL_TYPE_INTMAX, - COL_TYPE_UINT, - COL_TYPE_U64, - COL_TYPE_UINTMAX, - COL_TYPE_BOOL, - COL_TYPE_DOUBLE, - COL_TYPE_ANY, + COL_TYPE_STR, // String + COL_TYPE_INT, // int + COL_TYPE_S64, // Signed 64-bit integer + COL_TYPE_INTMAX, // intmax_t + COL_TYPE_UINT, // unsigned int + COL_TYPE_U64, // Unsigned 64-bit integer + COL_TYPE_UINTMAX, // uintmax_t + COL_TYPE_BOOL, // bool + COL_TYPE_DOUBLE, // double + COL_TYPE_ANY, // Any type COL_TYPE_LAST }; -#define CELL_ALIGN_LEFT (1<<(sizeof(enum column_type)*8 - 1)) -// FIXME: an example of another flag, not implemented now -#define CELL_ALIGN_CENTER (1<<(sizeof(enum column_type)*8 - 2)) -#define CELL_ALIGN_FLOAT (1<<(sizeof(enum column_type)*8 - 3)) +/** Column flag (to be OR-ed to column's width) **/ +#define CELL_ALIGN_LEFT (1U << 31) // Justify cell contents to the left + +// 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) -#define CELL_TRUNC_RIGHT (1<<(sizeof(enum column_type)*8 - 4)) +/** + * Definition of a single table column. + * Usually, this is generated using the `TABLE_COL_xxx` macros. + * Fields marked with `[*]` are user-accessible. + **/ +struct table_column { + const char *name; // [*] Name of the column displayed in table header + int width; // [*] Width of the column (in characters) OR'ed with column flags + const char *fmt; // [*] Default format of each cell in the column + enum column_type type; // [*] Type of the cells in the column +}; -// CELL_ALIGN_MASK is a mask which has 1's on positions used by some alignment mask. -// that is: col_width & CELL_ALIGN_MASK gives column width (in characters). -// the top bit is reserved for left alignment and is not demasked by CELL_ALIGN_MASK. -// the reason is that all printf and friends are using negative number for left alignment. -#define CELL_ALIGN_MASK (~(CELL_ALIGN_LEFT | CELL_ALIGN_FLOAT | CELL_ALIGN_CENTER)) +/** + * Definition of a table. Contains column definitions, per-table settings + * and internal data. Please use only fields marked with `[*]`. + **/ +struct table { + struct table_column *columns; // [*] Definition of columns + int column_count; // [*] Number of columns (calculated by table_init()) + 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. + + char **col_str_ptrs; // Values of cells in the current row (allocated from the 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 columns + const char *append_delimiter; // [*] Separator of multiple values in a single cell (see table_append_...()) + uint print_header; // [*] 0 indicates that table header should not be printed + + struct fastbuf *out; // [*] Fastbuffer to which the table is printed + int last_printed_col; // Index of the last column which was set. -1 indicates start of row. + // Used for example for appending to the current column. + int row_printing_started; // Indicates that a row has been started. Duplicates last_printed_col, but harmlessly. + 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 + struct table_formatter *formatter; + void *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_xxx(name, width)` defines a column of type `xxx` + * * `TBL_COL_xxx_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` and `TBL_APPEND_DELIMITER` override default delimiters + * * `TBL_OUTPUT_HUMAN_READABLE` requests human-readable formatting (this is the default) + * * `TBL_OUTPUT_MACHINE_READABLE` requests machine-readable TSV output + * * `TBL_OUTPUT_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 = "%s", .type = COL_TYPE_STR } #define TBL_COL_INT(_name, _width) { .name = _name, .width = _width, .fmt = "%d", .type = COL_TYPE_INT } @@ -111,190 +172,182 @@ enum column_type { #define TBL_OUTPUT_BLOCKLINE .formatter = &table_fmt_blockline #define TBL_OUTPUT_MACHINE_READABLE .formatter = &table_fmt_machine_readable +/** + * @table_init serves for initialization of the table. The structure should + * already contain the definitions of columns. + **/ +void table_init(struct table *tbl); + +/** Destroy a table definition, freeing all memory used by it. **/ +void table_cleanup(struct table *tbl); + +/** + * 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_xxx` nor by direct access to the table structure. + **/ +void table_start(struct table *tbl, struct fastbuf *out); + +/** + * 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_*` + * between table_end() and table_start(). + **/ +void table_end(struct table *tbl); + /*** - * [[ 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_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_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_col_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_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. + * Filling tables with data + * ------------------------ * - * Command-line options (provided through table_set_option and friends): - * key value explanation - * header [0|1] 0=do not print the header - * cols [,]* list of column names delimited by comma ',' - * '*' or star '*' meaning all columns - * fmt [human|machine|blockline] output format - * col-delim string used as a column delimiter + * For each column type, there are functions for filling of cells + * of the particular type: * + * * `table_col_`'type'`(table, idx, value)` sets the cell in column `idx` + * to the `value` + * * `table_col_`'type'`_fmt(table, idx, fmt, ...)` does the same with + * a custom printf-like format string + * * `table_col_`'type'`_name(table, name, value)` refers to the column + * by its name instead of its index. + * * `table_append_`'type'`(table, value)` appends a value to the most + * recently accessed cell. ***/ -struct table; - -/** Specification of a single table column */ -struct table_column { - const char *name; // [*] Name of the column displayed in table header - int width; // [*] Width of the column (in characters). Negative number indicates alignment to left. - // FIXME: Request left alignment 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 -}; - -/** The definition of a table. Contains column definitions plus internal data. */ -struct table { - struct table_column *columns; // [*] Definition of columns - int column_count; // [*] Number of columns (calculated by table_init()) - 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. - - char **col_str_ptrs; // Values of cells in the current row (allocated from the pool) +#define TABLE_COL_PROTO(_name_, _type_) void table_col_##_name_(struct table *tbl, int col, _type_ val);\ + void table_col_##_name_##_name(struct table *tbl, const char *col_name, _type_ val);\ + void table_col_##_name_##_fmt(struct table *tbl, int col, const char *fmt, _type_ val) FORMAT_CHECK(printf, 3, 0); - 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 columns - const char *append_delimiter; // [*] Separator of multiple values in a single cell (see table_append_...()) - uint print_header; // [*] 0 indicates that table header should not be printed +// table_col__fmt has one disadvantage: it is not possible to +// check whether fmt contains format that contains formatting that is +// compatible with _type_ - struct fastbuf *out; // [*] Fastbuffer to which the table is printed - int last_printed_col; // Index of the last column which was set. -1 indicates start of row. - // Used for example for appending to the current column. - int row_printing_started; // Indicates that a row has been started. Duplicates last_printed_col, but harmlessly. - 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 +TABLE_COL_PROTO(int, int); +TABLE_COL_PROTO(uint, uint); +TABLE_COL_PROTO(double, double); +TABLE_COL_PROTO(str, const char *); +TABLE_COL_PROTO(intmax, intmax_t); +TABLE_COL_PROTO(uintmax, uintmax_t); +TABLE_COL_PROTO(s64, s64); +TABLE_COL_PROTO(u64, u64); - // Back-end used for table formatting and its private data - struct table_formatter *formatter; - void *data; -}; +void table_col_bool(struct table *tbl, int col, uint val); +void table_col_bool_name(struct table *tbl, const char *col_name, uint val); +void table_col_bool_fmt(struct table *tbl, int col, const char *fmt, uint val); +#undef TABLE_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); +TABLE_APPEND_PROTO(s64, s64); +TABLE_APPEND_PROTO(u64, u64); +void table_append_bool(struct table *tbl, int val); +#undef TABLE_APPEND_PROTO /** - * @table_init serves for initialization of the table. The @tbl parameter should have set the columns member of - * the table structure. + * Set a particular cell of the current row to a string formatted + * by sprintf(). This function can set a column of an arbitrary type. **/ -void table_init(struct table *tbl); -void table_cleanup(struct table *tbl); +void table_col_printf(struct table *tbl, int col, const char *fmt, ...) FORMAT_CHECK(printf, 3, 4); /** - * table_start is called before the cells of the table are set. After the table_start is called, the - * user can call the table_col_* or table_append_ functions, but cannot call the table_set_* - * functions. The table_end_row function can be called after the table_start is called (but before - * the table_end is called) + * Appends a string formatted by sprintf() to the most recently filled cell. + * This function can work with columns of an arbitrary type. **/ -void table_start(struct table *tbl, struct fastbuf *out); +void table_append_printf(struct table *tbl, const char *fmt, ...) FORMAT_CHECK(printf, 2, 3); /** - * 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. + * 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(struct table *tbl); +struct fastbuf *table_col_fbstart(struct table *tbl, int col); /** - * 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. + * Closes the stream that is used for printing of the current column. **/ -void table_set_col_order(struct table *tbl, int *col_order, int col_order_size); +void table_col_fbend(struct table *tbl); /** - * 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. + * Called when all cells of the current row have their values filled in. + * It sends the completed row to the output stream. **/ -const char *table_set_col_order_by_name(struct table *tbl, const char *col_order); +void table_end_row(struct table *tbl); + +/*** + * Configuration functions + * ----------------------- + ***/ /** - * 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. + * Find the index of a column with name @col_name. Returns -1 if there is no such column. **/ -void table_end_row(struct table *tbl); +int table_get_col_idx(struct table *tbl, const char *col_name); /** - * 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 + * Returns a comma-and-space-separated list of column names, allocated from table's internal + * memory pool. **/ -void table_col_printf(struct table *tbl, int col, const char *fmt, ...) FORMAT_CHECK(printf, 3, 4); +const char *table_get_col_list(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. + * Sets the order in which the columns are printed. The @col_order parameter is used until table_end() or + * table_cleanup() is called. The table stores only the pointer and the memory pointed to by @col_order is + * allocated and deallocated by the caller. **/ -void table_append_printf(struct table *tbl, const char *fmt, ...) FORMAT_CHECK(printf, 2, 3); +void table_set_col_order(struct table *tbl, int *col_order, int col_order_size); /** - * Find the index of a column with name @col_name and returns it. Returns -1 if the column was not found. + * 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. **/ -int table_get_col_idx(struct table *tbl, const char *col_name); +const char *table_set_col_order_by_name(struct table *tbl, const char *col_order); /** - * Returns comma-and-space-separated list of column names, allocated from table's internal - * memory pool. + * Sets table formatter for @tbl. See below for the list of formatters. **/ -const char *table_get_col_list(struct table *tbl); +void table_set_formatter(struct table *tbl, struct table_formatter *fmt); /** - * 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. + * Set a table option. All options have a key and a value. Currently, + * the following keys are defined (other keys can be accepted by formatters): + * + * [options="header"] + * |======================= + * | key | value | meaning + * | `header` | 0 or 1 | set whether a table header should be printed + * | `noheader` | 'none' | equivalent to `header`=0 + * | `cols` | column list | set order of columns (accepts a comma-separated list of column names) + * | `fmt` | formatter | set table formatter (`human`, `machine`, `block`) + * | `col-delim`| string | set column delimiter + * |======================== **/ -struct fastbuf *table_col_fbstart(struct table *tbl, int col); +const char *table_set_option_value(struct table *tbl, const char *key, const char *value); /** - * Closes the stream that is used for printing of the last column. + * Sets a table option given as 'key'`:`'value' or `key` (with no value). **/ -void table_col_fbend(struct table *tbl); +const char *table_set_option(struct table *tbl, const char *opt); /** - * Sets table formatter for @tbl. + * Sets several table option in 'key'`:`'value' form, stored in a growing array. + * This is frequently used for options given on the command line. **/ -void table_set_formatter(struct table *tbl, struct table_formatter *fmt); +const char *table_set_gary_options(struct table *tbl, char **gary_table_opts); + +/*** + * Formatters + * ---------- + * + * Each formatter defines several call-back functions, which are called + * by the table printer at specific points. The formatter can keep its internal + * state in the `data` field of `struct table` and allocate temporary data + * from the table's memory pool. + ***/ /** Definition of a formatter back-end. **/ struct table_formatter { @@ -305,60 +358,13 @@ struct table_formatter { // [*] Process table option and possibly return an error message (optional) }; -// Standard formatters +/** Standard formatter for human-readable output **/ extern struct table_formatter table_fmt_human_readable; -extern struct table_formatter table_fmt_machine_readable; -extern struct table_formatter table_fmt_blockline; - -/** - * 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. - **/ -const char *table_set_option(struct table *tbl, const char *opt); -const char *table_set_option_value(struct table *tbl, const char *key, const char *value); -const char *table_set_gary_options(struct table *tbl, char **gary_table_opts); - -#define TABLE_COL_PROTO(_name_, _type_) void table_col_##_name_(struct table *tbl, int col, _type_ val);\ - void table_col_##_name_##_name(struct table *tbl, const char *col_name, _type_ val);\ - void table_col_##_name_##_fmt(struct table *tbl, int col, const char *fmt, _type_ val) FORMAT_CHECK(printf, 3, 0); - -// table_col__fmt has one disadvantage: it is not possible to -// check whether fmt contains format that contains formatting that is -// compatible with _type_ -TABLE_COL_PROTO(int, int); -TABLE_COL_PROTO(uint, uint); -TABLE_COL_PROTO(double, double); -TABLE_COL_PROTO(str, const char *); -TABLE_COL_PROTO(intmax, intmax_t); -TABLE_COL_PROTO(uintmax, uintmax_t); -TABLE_COL_PROTO(s64, s64); -TABLE_COL_PROTO(u64, u64); - -void table_col_bool(struct table *tbl, int col, uint val); -void table_col_bool_name(struct table *tbl, const char *col_name, uint val); -void table_col_bool_fmt(struct table *tbl, int col, const char *fmt, uint val); -#undef TABLE_COL_PROTO +/** Standard formatter for machine-readable output (tab-separated values) **/ +extern struct table_formatter table_fmt_machine_readable; -#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); -TABLE_APPEND_PROTO(s64, s64); -TABLE_APPEND_PROTO(u64, u64); -void table_append_bool(struct table *tbl, int val); -#undef TABLE_APPEND_PROTO +/** Standard formatter for block output (one cell per line) **/ +extern struct table_formatter table_fmt_blockline; #endif -- 2.39.2