Workshop o mikrokontrolérech na SKSP 2024.
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

3 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