You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
107 lines
3.9 KiB
107 lines
3.9 KiB
2 months ago
|
Table printer
|
||
|
=============
|
||
|
|
||
|
The table printer module provides formatting of 2-dimensional tables
|
||
|
in various ways.
|
||
|
|
||
|
Each table print-out consists of a number of 'rows', which are processed
|
||
|
one after another. All rows have the same number of 'columns', each intersection
|
||
|
of a row with a column is called a 'cell'. Each cell holds data, represented
|
||
|
using the <<xtypes:,extended types>> (a.k.a. 'xtypes'). The table printer
|
||
|
checks that the cells are filled by values of the appropriate types;
|
||
|
additionally, a string value is allowed in any cell (for example,
|
||
|
this allows a numeric cell to be set to "--" or "unknown").
|
||
|
|
||
|
Once a table is defined, it can be printed using a variety of 'formatters'
|
||
|
(human-readable, tab-separated values, etc.) and its cells can be formatted
|
||
|
using at least three different formats: pretty (or human-readable), raw,
|
||
|
default. Formatting of cells is handled by the xtype module.
|
||
|
|
||
|
The order of columns can be modified, columns can be omitted, or even printed
|
||
|
multiple times with different formatting options. We therefore distinguish
|
||
|
between columns (according to the definition of the table) and 'column
|
||
|
instances' (in the specific print-out).
|
||
|
|
||
|
Example
|
||
|
-------
|
||
|
|
||
|
Let us construct a simple table of music recordings:
|
||
|
|
||
|
First, we define an enum with column indices (the values are automatically
|
||
|
numbered starting from 0):
|
||
|
|
||
|
enum table_columns {
|
||
|
TBL_REC_ID,
|
||
|
TBL_REC_ALBUM_NAME,
|
||
|
TBL_REC_ARTIST,
|
||
|
TBL_REC_YEAR
|
||
|
};
|
||
|
|
||
|
Then we create a structure with the definition of our table.
|
||
|
The table columns are defined using the `TBL_COL_`'type' and `TBL_COL_`'type'`_FMT`
|
||
|
macros. Each macro gets the name of the column and its default width
|
||
|
in characters. The `_FMT` version adds an explicit 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.
|
||
|
|
||
|
To define the column order, we can create an array of struct table_col_info
|
||
|
using the following macros: TBL_COL, TBL_COL_FMT, TBL_COL_TYPE. An example
|
||
|
follows:
|
||
|
|
||
|
struct table_col_info column_order[] = { TBL_COL(TBL_REC_ID), TBL_COL(TBL_REC_ALBUM_NAME) };
|
||
|
|
||
|
The column order is supplied in the struct table_template using the TBL_COL_ORDER macro.
|
||
|
|
||
|
struct table_template recording_table_template = {
|
||
|
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
|
||
|
},
|
||
|
TBL_COL_ORDER(column_order)
|
||
|
};
|
||
|
|
||
|
|
||
|
Each table definition has to be created from a template before use by @table_init():
|
||
|
|
||
|
struct table *rec_table = table_init(&recording_table_template);
|
||
|
|
||
|
Once it is initialized, we can use it for printing multiple tables.
|
||
|
At the start of each table, we should obtain a <<fastbuf:,fastbuf>> where the output
|
||
|
should be sent, store it in the table structure and call @table_start():
|
||
|
|
||
|
struct fastbuf *out = bfdopen_shared(1, 4096);
|
||
|
table_start(&rec_table, out);
|
||
|
|
||
|
Then we can fill the rows one after another. Each row is ended by
|
||
|
@table_end_row():
|
||
|
|
||
|
table_col_uint(&rec_table, TBL_REC_ID, 0);
|
||
|
table_col_str(&rec_table, TBL_REC_ALBUM_NAME, "The Wall");
|
||
|
table_col_str(&rec_table, TBL_REC_ARTIST, "Pink Floyd");
|
||
|
table_col_uint(&rec_table, TBL_REC_YEAR, 1979);
|
||
|
table_end_row(&rec_table);
|
||
|
|
||
|
table_col_uint(&rec_table, TBL_REC_ID, 1);
|
||
|
table_col_str(&rec_table, TBL_REC_ALBUM_NAME, "Rio Grande Mud");
|
||
|
table_col_str(&rec_table, TBL_REC_ARTIST, "ZZ Top");
|
||
|
table_col_uint(&rec_table, TBL_REC_YEAR, 1972);
|
||
|
table_end_row(&rec_table);
|
||
|
|
||
|
Finally, we should close the table by calling @table_end():
|
||
|
|
||
|
table_end(&rec_table);
|
||
|
|
||
|
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():
|
||
|
|
||
|
table_cleanup(&rec_table);
|
||
|
|
||
|
ucw/table.h
|
||
|
-----------
|
||
|
|
||
|
!!ucw/table.h
|