From: Robert Kessl Date: Wed, 4 Jun 2014 10:55:08 +0000 (+0200) Subject: Table: added left alignment flag X-Git-Tag: v6.0~13^2~1 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=f53152837305edbc3ea771836a0e7dbfb3b9ee99;p=libucw.git Table: added left alignment flag - added tests of alignment flag (table-test-align) - modified cmd line switches in table-test --- diff --git a/ucw/Makefile b/ucw/Makefile index 527e2beb..e45a339c 100644 --- a/ucw/Makefile +++ b/ucw/Makefile @@ -133,6 +133,7 @@ $(o)/ucw/ipaccess-test: $(o)/ucw/ipaccess-test.o $(LIBUCW) $(o)/ucw/trie-test: $(o)/ucw/trie-test.o $(LIBUCW) $(o)/ucw/opt-test: $(o)/ucw/opt-test.o $(LIBUCW) $(o)/ucw/table-test: $(o)/ucw/table-test.o $(LIBUCW) +$(o)/ucw/table-test-align: $(o)/ucw/table-test-align.o $(LIBUCW) TESTS+=$(addprefix $(o)/ucw/,regex.test unicode.test hash-test.test mempool.test stkstring.test \ slists.test bbuf.test kmp-test.test getopt.test ff-unicode.test eltpool.test \ @@ -141,7 +142,7 @@ TESTS+=$(addprefix $(o)/ucw/,regex.test unicode.test hash-test.test mempool.test fb-mem.test fb-buffer.test fb-mmap.test fb-multi.test fb-null.test \ redblack-test.test url.test strtonum-test.test \ gary.test time.test crc.test signames.test md5.test bitops.test opt.test \ - table.test table-test.test) + table.test table-test.test table-test-align.test) $(o)/ucw/varint.test: $(o)/ucw/varint-t $(o)/ucw/regex.test: $(o)/ucw/regex-t @@ -175,6 +176,7 @@ $(o)/ucw/md5.test: $(o)/ucw/md5-t $(o)/ucw/opt.test: $(o)/ucw/opt-test $(o)/ucw/table.test: $(o)/ucw/table-t $(o)/ucw/table-test.test: $(o)/ucw/table-test +$(o)/ucw/table-test-align.test: $(o)/ucw/table-test-align ifdef CONFIG_UCW_THREADS TESTS+=$(addprefix $(o)/ucw/,asio.test) diff --git a/ucw/table-test-align.c b/ucw/table-test-align.c new file mode 100644 index 00000000..4df4292e --- /dev/null +++ b/ucw/table-test-align.c @@ -0,0 +1,114 @@ +/* + * Unit tests of table printer + * + * (c) 2014 Robert Kessl + */ + +#include +#include +#include +#include + + +enum test_table_cols { + test_col0_str, test_col1_int, test_col2_uint, test_col3_bool, test_col4_double +}; + +static struct table test_tbl = { + TBL_COLUMNS { + [test_col0_str] = TBL_COL_STR("col0_str", 30 | CELL_ALIGN_LEFT), + [test_col1_int] = TBL_COL_INT("col1_int", 8), + [test_col2_uint] = TBL_COL_UINT("col2_uint", 9), + [test_col3_bool] = TBL_COL_BOOL("col3_bool", 9 | CELL_ALIGN_LEFT), + [test_col4_double] = TBL_COL_DOUBLE("col4_double", 11 | CELL_ALIGN_LEFT, 5), + TBL_COL_END + }, + TBL_OUTPUT_HUMAN_READABLE, + TBL_COL_DELIMITER("\t"), +}; + +static int test_to_perform = -1; +static char **cli_table_opts; + +static struct opt_section table_printer_opts = { + OPT_ITEMS { + OPT_HELP("Options:"), + OPT_STRING_MULTIPLE('T', "table", cli_table_opts, OPT_REQUIRED_VALUE, "\tSets options for the table."), + OPT_END + } +}; + + +static void process_command_line_opts(char *argv[], struct table *tbl) +{ + GARY_INIT(cli_table_opts, 0); + + opt_parse(&table_printer_opts, argv+1); + table_set_gary_options(tbl, cli_table_opts); + + GARY_FREE(cli_table_opts); +} + +static void print_table(struct table *tbl, struct fastbuf *out) +{ + table_start(tbl, out); + + struct fastbuf *colfb = table_col_fbstart(tbl, test_col0_str); + bputs(colfb, "HELLO"); + bprintf(colfb, ",col_idx:%d", test_col0_str); + table_col_fbend(tbl); + + table_col_int(tbl, test_col1_int, -10); + table_col_uint(tbl, test_col2_uint, 10); + table_col_bool(tbl, test_col3_bool, 0); + table_col_double(tbl, test_col4_double, 3.1415926535897); + table_end_row(tbl); + + + + colfb = table_col_fbstart(tbl, test_col0_str); + bputs(colfb, "EHLO"); + bprintf(colfb, ",col_idx:%d", test_col0_str); + table_col_fbend(tbl); + + table_col_int(tbl, test_col1_int, -12345); + table_col_uint(tbl, test_col2_uint, 0xFF); + table_col_bool(tbl, test_col3_bool, 1); + table_col_double(tbl, test_col4_double, 1.61803398875); + table_end_row(tbl); + + + + colfb = table_col_fbstart(tbl, test_col0_str); + bputs(colfb, "AHOJ"); + bprintf(colfb, ",col_idx:%d", test_col0_str); + table_col_fbend(tbl); + + table_col_int(tbl, test_col1_int, -54321); + table_col_uint(tbl, test_col2_uint, 0xFF00); + table_col_bool(tbl, test_col3_bool, 0); + table_col_double(tbl, test_col4_double, 2.718281828459045); + table_end_row(tbl); + + table_end(tbl); +} + + +int main(int argc UNUSED, char **argv) +{ + struct fastbuf *out; + out = bfdopen_shared(1, 4096); + + table_init(&test_tbl); + process_command_line_opts(argv, &test_tbl); + + //bprintf(out, "width: %X; masked: %d; mask: %X\n", test_tbl.columns[0].width, test_tbl.columns[0].width & CELL_ALIGN_MASK, CELL_ALIGN_MASK); + //bflush(out); + + print_table(&test_tbl, out); + table_cleanup(&test_tbl); + bclose(out); + + return 0; +} + diff --git a/ucw/table-test-align.t b/ucw/table-test-align.t new file mode 100644 index 00000000..ae50de66 --- /dev/null +++ b/ucw/table-test-align.t @@ -0,0 +1,7 @@ +Run: ../obj/ucw/table-test-align +Out <cols_to_output; i++) { int col_idx = tbl->column_order[i]; - int col_width = tbl->columns[col_idx].width; if(i) { bputs(tbl->out, tbl->col_delimiter); } + int col_width = tbl->columns[col_idx].width & CELL_ALIGN_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]); } bputc(tbl->out, '\n'); @@ -427,7 +428,9 @@ static void table_write_header(struct table *tbl) if(i) { bputs(tbl->out, tbl->col_delimiter); } - bprintf(tbl->out, "%*s", tbl->columns[col_idx].width, tbl->columns[col_idx].name); + int col_width = tbl->columns[col_idx].width & CELL_ALIGN_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); } bputc(tbl->out, '\n'); } diff --git a/ucw/table.h b/ucw/table.h index f191c8bb..2a4d3894 100644 --- a/ucw/table.h +++ b/ucw/table.h @@ -22,6 +22,17 @@ enum column_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)) + +// 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)) + #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 } #define TBL_COL_UINT(_name, _width) { .name = _name, .width = _width, .fmt = "%u", .type = COL_TYPE_UINT } @@ -61,12 +72,12 @@ enum column_type { * 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 + * 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_set_xxx functions and @table_end. + * 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. @@ -88,7 +99,7 @@ enum column_type { * 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_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 @@ -105,21 +116,15 @@ enum column_type { * Features: * * user supplied callback functions can be used for modifying the output format. * - * Non-tested features: + * TODO part/Planned 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 + * 3) decimal point alignment; ***/ struct table; @@ -177,9 +182,10 @@ void table_init(struct table *tbl); 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_row function can be called after the table_start is called - * (but before the table_end is called) + * 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 and 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) **/ void table_start(struct table *tbl, struct fastbuf *out);