From: Robert Kessl Date: Fri, 27 Jun 2014 12:20:35 +0000 (+0200) Subject: tableprinter: now uses struct table_col_info * for column ordering X-Git-Tag: v6.1~3^2~134 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=19472b9df3b61631b819acb78bdaedcef2182e9c;p=libucw.git tableprinter: now uses struct table_col_info * for column ordering --- diff --git a/ucw/Makefile b/ucw/Makefile index e45a339c..71e66311 100644 --- a/ucw/Makefile +++ b/ucw/Makefile @@ -38,7 +38,7 @@ LIBUCW_MODS= \ daemon daemon-ctrl \ signames \ opt opt-help opt-conf \ - table + table table-types LIBUCW_MAIN_INCLUDES= \ lib.h log.h tbf.h threads.h time.h \ @@ -69,7 +69,7 @@ LIBUCW_MAIN_INCLUDES= \ signames.h \ sighandler.h \ opt.h \ - table.h + table.h table-types.h ifdef CONFIG_UCW_THREADS # Some modules require threading @@ -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-2: $(o)/ucw/table-test-2.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 \ @@ -142,7 +143,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-align.test) + table.test table-test.test table-test-2.test table-test-align.test) $(o)/ucw/varint.test: $(o)/ucw/varint-t $(o)/ucw/regex.test: $(o)/ucw/regex-t @@ -176,6 +177,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-2.test: $(o)/ucw/table-test-2 $(o)/ucw/table-test-align.test: $(o)/ucw/table-test-align ifdef CONFIG_UCW_THREADS diff --git a/ucw/table-test-2.c b/ucw/table-test-2.c new file mode 100644 index 00000000..49fce1db --- /dev/null +++ b/ucw/table-test-2.c @@ -0,0 +1,67 @@ +/* + * Unit tests of table printer + * + * (c) 2014 Robert Kessl + */ + +#include +#include +#include +#include +#include + +enum test_table_cols { + TEST_COL0_SIZE, TEST_COL1_TS +}; + +static struct table test_tbl = { + TBL_COLUMNS { + [TEST_COL0_SIZE] = TBL_COL_SIZE_FMT("size", 10, UNIT_BYTE), + [TEST_COL1_TS] = TBL_COL_TIMESTAMP("ts", 20), + TBL_COL_END + }, + TBL_OUTPUT_HUMAN_READABLE, +}; + +static void do_test(void) +{ + struct fastbuf *out; + out = bfdopen_shared(1, 4096); + table_init(&test_tbl); + table_start(&test_tbl, out); + + u64 test_time = 1403685533; + s64 test_size = 4LU*(1024LU * 1024LU * 1024LU); + + table_col_size(&test_tbl, TEST_COL0_SIZE, test_size); + table_col_timestamp(&test_tbl, TEST_COL1_TS, test_time); + table_end_row(&test_tbl); + + test_tbl.column_order[TEST_COL0_SIZE].output_type = UNIT_KILOBYTE; + table_col_size(&test_tbl, TEST_COL0_SIZE, test_size); + table_col_timestamp(&test_tbl, TEST_COL1_TS, test_time); + table_end_row(&test_tbl); + + test_tbl.column_order[TEST_COL0_SIZE].output_type = UNIT_MEGABYTE; + table_col_size(&test_tbl, TEST_COL0_SIZE, test_size); + table_col_timestamp(&test_tbl, TEST_COL1_TS, test_time); + table_end_row(&test_tbl); + + test_tbl.column_order[TEST_COL0_SIZE].output_type = UNIT_GIGABYTE; + test_tbl.column_order[TEST_COL1_TS].output_type = TIMESTAMP_DATETIME; + table_col_size(&test_tbl, TEST_COL0_SIZE, test_size); + table_col_timestamp(&test_tbl, TEST_COL1_TS, test_time); + table_end_row(&test_tbl); + + table_end(&test_tbl); + table_cleanup(&test_tbl); + + bclose(out); +} + +int main(int argc UNUSED, char **argv UNUSED) +{ + do_test(); + return 0; +} + diff --git a/ucw/table-test-2.t b/ucw/table-test-2.t new file mode 100644 index 00000000..1b933c97 --- /dev/null +++ b/ucw/table-test-2.t @@ -0,0 +1,8 @@ +Run: ../obj/ucw/table-test-2 +Out < +#include +#include +#include +#include +#include +#include +#include + +void table_col_name(struct table *tbl, const char *col_name, u64 val) +{ +} + +void table_col_size(struct table *tbl, int col, u64 val) +{ + ASSERT_MSG(col < tbl->column_count && col >= 0, "Table column %d does not exist.", col); + ASSERT(tbl->columns[col].type == COL_TYPE_ANY || COL_TYPE_SIZE == tbl->columns[col].type); + + tbl->last_printed_col = col; + tbl->row_printing_started = 1; + + static u64 unit_div[] = { + [UNIT_BYTE] = (u64) 1, + [UNIT_KILOBYTE] = (u64) 1024LU, + [UNIT_MEGABYTE] = (u64) (1024LU * 1024LU), + [UNIT_GIGABYTE] = (u64) (1024LU * 1024LU * 1024LU), + [UNIT_TERABYTE] = (u64) (1024LU * 1024LU * 1024LU * 1024LU) + }; + + static const char *unit_suffix[] = { + [UNIT_BYTE] = "", + [UNIT_KILOBYTE] = "KB", + [UNIT_MEGABYTE] = "MB", + [UNIT_GIGABYTE] = "GB", + [UNIT_TERABYTE] = "TB" + }; + + // FIXME: do some rounding? + val = val / unit_div[tbl->column_order[col].output_type]; + + tbl->col_str_ptrs[col] = mp_printf(tbl->pool, "%lu%s", val, unit_suffix[tbl->column_order[col].output_type]); +} + +#define FORMAT_TIME_SIZE 20 // Minimum buffer size + +void table_col_timestamp(struct table *tbl, int col, u64 val) +{ + ASSERT_MSG(col < tbl->column_count && col >= 0, "Table column %d does not exist.", col); + ASSERT(tbl->columns[col].type == COL_TYPE_ANY || COL_TYPE_TIMESTAMP == tbl->columns[col].type); + //ASSERT(fmt != NULL); + + char formatted_time_buf[FORMAT_TIME_SIZE]; + + time_t tmp_time = (time_t)val; + struct tm t = *gmtime(&tmp_time); + + switch (tbl->column_order[col].output_type) { + case TIMESTAMP_EPOCH: + sprintf(formatted_time_buf, "%u", (uint) val); + break; + case TIMESTAMP_DATETIME: + strftime(formatted_time_buf, FORMAT_TIME_SIZE, "%F %T", &t); + default: + break; + } + + tbl->col_str_ptrs[col] = mp_printf(tbl->pool, "%s", formatted_time_buf); +} + diff --git a/ucw/table-types.h b/ucw/table-types.h new file mode 100644 index 00000000..3ef4375b --- /dev/null +++ b/ucw/table-types.h @@ -0,0 +1,61 @@ +#ifndef _UCW_TABLE_TYPES_H +#define _UCW_TABLE_TYPES_H + +#include + +enum size_units { + UNIT_BYTE, + UNIT_KILOBYTE, + UNIT_MEGABYTE, + UNIT_GIGABYTE, + UNIT_TERABYTE, + UNIT_AUTO +}; + +enum timestamp_format { + TIMESTAMP_EPOCH, + TIMESTAMP_DATETIME +}; + + +#define COL_TYPE_SIZE COL_TYPE_CUSTOM +#define COL_TYPE_TIMESTAMP (COL_TYPE_CUSTOM+1) + +#define TBL_COL_SIZE(_name, _width) { .name = _name, .width = _width, .fmt = "%llu", .type = COL_TYPE_SIZE } +#define TBL_COL_TIMESTAMP(_name, _width) { .name = _name, .width = _width, .fmt = "%lld", .type = COL_TYPE_TIMESTAMP } + +#define TBL_COL_SIZE_FMT(_name, _width, _units) { .name = _name, .width = _width, .fmt = "%llu", .type = COL_TYPE_SIZE } +#define TBL_COL_TIMESTAMP_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = "%lld", .type = COL_TYPE_TIMESTAMP } + +/* + union { + enum size_units units; + enum timestamp_format ts_fmt; + }; +*/ +/* +#define TBL_COL_SIZE(_name, _width) { .name = _name, .width = _width, .fmt = "%llu", .type = COL_TYPE_SIZE } +#define TBL_COL_TIMESTAMP(_name, _width) { .name = _name, .width = _width, .fmt = "%lld", .type = COL_TYPE_TIMESTAMP } + +#define TBL_COL_SIZE_FMT(_name, _width, _units) { .name = _name, .width = _width, .fmt = "%llu", .type = COL_TYPE_SIZE } +#define TBL_COL_TIMESTAMP_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = "%lld", .type = COL_TYPE_TIMESTAMP } + +#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, _type_ val) FORMAT_CHECK(printf, 3, 0); +//TABLE_COL_PROTO(size, u64); +//TABLE_COL_PROTO(timestamp, u64); +#undef TABLE_COL_PROTO +*/ + +void table_col_size(struct table *tbl, int col, u64 val); +void table_col_timestamp(struct table *tbl, int col, u64 val); + +//TABLE_COL(size, u64, COL_TYPE_SIZE) +//TABLE_COL_STR(size, u64, COL_TYPE_SIZE) + +//TABLE_COL(timestamp, u64, COL_TYPE_TIMESTAMP) +//TABLE_COL_STR(timestamp, u64, COL_TYPE_TIMESTAMP) + + +#endif diff --git a/ucw/table.c b/ucw/table.c index cba1c6da..ff6d6250 100644 --- a/ucw/table.c +++ b/ucw/table.c @@ -27,7 +27,6 @@ void table_init(struct table *tbl) ASSERT(tbl->columns[col_count].name != NULL); ASSERT(tbl->columns[col_count].type == COL_TYPE_ANY || tbl->columns[col_count].fmt != NULL); ASSERT(tbl->columns[col_count].width != 0); - ASSERT(tbl->columns[col_count].type < COL_TYPE_LAST); col_count++; } tbl->pool = mp_new(4096); @@ -123,15 +122,18 @@ void table_set_col_order(struct table *tbl, int *col_order, int cols_to_output) ASSERT_MSG(col_order[i] >= 0 && col_order[i] < tbl->column_count, "Column %d does not exist (column number should be between 0 and %d)", col_order[i], tbl->column_count - 1); } - tbl->column_order = col_order; tbl->cols_to_output = cols_to_output; + tbl->column_order = mp_alloc_zero(tbl->pool, sizeof(struct table_col_info) * cols_to_output); + for(int i = 0; i < cols_to_output; i++) { + tbl->column_order[i].idx = col_order[i]; + } } bool table_col_is_printed(struct table *tbl, uint col_idx) { for(uint i = 0; i < tbl->cols_to_output; i++) { - if(tbl->column_order[i] == col_idx) return 1; + if(tbl->column_order[i].idx == col_idx) return 1; } return 0; @@ -144,9 +146,12 @@ bool table_col_is_printed(struct table *tbl, uint col_idx) const char * table_set_col_order_by_name(struct table *tbl, const char *col_order_str) { if(col_order_str[0] == '*') { - tbl->column_order = mp_alloc(tbl->pool, sizeof(int) * tbl->column_count); + tbl->column_order = mp_alloc(tbl->pool, sizeof(struct table_col_info) * tbl->column_count); tbl->cols_to_output = tbl->column_count; - for(uint i = 0; i < tbl->cols_to_output; i++) tbl->column_order[i] = i; + for(uint i = 0; i < tbl->cols_to_output; i++) { + tbl->column_order[i].idx = i; + tbl->column_order[i].output_type = 0; + } return NULL; } @@ -166,7 +171,7 @@ const char * table_set_col_order_by_name(struct table *tbl, const char *col_orde } } - int *col_order_int = mp_alloc_zero(tbl->pool, sizeof(int) * col_count); + int *col_order_int = alloca(sizeof(int) * col_count); //mp_alloc_zero(tbl->pool, sizeof(int) * col_count); int curr_col_order_int = 0; const char *name_start = tmp_col_order; while(name_start) { @@ -184,8 +189,9 @@ const char * table_set_col_order_by_name(struct table *tbl, const char *col_orde name_start = next; } - tbl->column_order = col_order_int; - tbl->cols_to_output = curr_col_order_int; + //tbl->column_order = col_order_int; + //tbl->cols_to_output = curr_col_order_int; + table_set_col_order(tbl, col_order_int, curr_col_order_int); return NULL; } @@ -436,7 +442,7 @@ const char *table_set_gary_options(struct table *tbl, char **gary_table_opts) static void table_row_human_readable(struct table *tbl) { for(uint i = 0; i < tbl->cols_to_output; i++) { - int col_idx = tbl->column_order[i]; + int col_idx = tbl->column_order[i].idx; if(i) { bputs(tbl->out, tbl->col_delimiter); } @@ -450,7 +456,7 @@ static void table_row_human_readable(struct table *tbl) static void table_write_header(struct table *tbl) { for(uint i = 0; i < tbl->cols_to_output; i++) { - int col_idx = tbl->column_order[i]; + int col_idx = tbl->column_order[i].idx; if(i) { bputs(tbl->out, tbl->col_delimiter); } @@ -486,7 +492,7 @@ struct table_formatter table_fmt_human_readable = { static void table_row_machine_readable(struct table *tbl) { for(uint i = 0; i < tbl->cols_to_output; i++) { - int col_idx = tbl->column_order[i]; + int col_idx = tbl->column_order[i].idx; if(i) { bputs(tbl->out, tbl->col_delimiter); } @@ -506,10 +512,10 @@ static void table_start_machine_readable(struct table *tbl) } if(tbl->print_header != 0) { - uint col_idx = tbl->column_order[0]; + uint col_idx = tbl->column_order[0].idx; bputs(tbl->out, tbl->columns[col_idx].name); for(uint i = 1; i < tbl->cols_to_output; i++) { - col_idx = tbl->column_order[i]; + col_idx = tbl->column_order[i].idx; bputs(tbl->out, tbl->col_delimiter); bputs(tbl->out, tbl->columns[col_idx].name); } @@ -528,7 +534,7 @@ struct table_formatter table_fmt_machine_readable = { static void table_row_blockline_output(struct table *tbl) { for(uint i = 0; i < tbl->cols_to_output; i++) { - int col_idx = tbl->column_order[i]; + int col_idx = tbl->column_order[i].idx; bprintf(tbl->out, "%s: %s\n", tbl->columns[col_idx].name, tbl->col_str_ptrs[col_idx]); } bputc(tbl->out, '\n'); @@ -562,7 +568,7 @@ enum test_table_cols { test_col0_str, test_col1_int, test_col2_uint, test_col3_bool, test_col4_double }; -static uint test_column_order[] = {test_col3_bool, test_col4_double, test_col2_uint,test_col1_int, test_col0_str}; +static struct table_col_info test_column_order[] = { TBL_COL(test_col3_bool), TBL_COL(test_col4_double), TBL_COL(test_col2_uint), TBL_COL(test_col1_int), TBL_COL(test_col0_str) }; static struct table test_tbl = { TBL_COLUMNS { @@ -659,7 +665,7 @@ enum test_any_table_cols { test_any_col0_int, test_any_col1_any }; -static uint test_any_column_order[] = { test_any_col0_int, test_any_col1_any }; +static struct table_col_info test_any_column_order[] = { TBL_COL(test_any_col0_int), TBL_COL(test_any_col1_any) }; static struct table test_any_tbl = { TBL_COLUMNS { diff --git a/ucw/table.h b/ucw/table.h index 06da5481..a43a0476 100644 --- a/ucw/table.h +++ b/ucw/table.h @@ -88,6 +88,9 @@ enum column_type { COL_TYPE_LAST }; +#define COL_TYPE_UCW 0x100 +#define COL_TYPE_CUSTOM 0x1000 + /** Justify cell contents to the left. **/ #define CELL_ALIGN_LEFT (1U << 31) @@ -108,6 +111,11 @@ struct table_column { enum column_type type; // [*] Type of the cells in the column }; +struct table_col_info { + uint idx; + uint output_type; +}; + /** * Definition of a table. Contains column definitions, per-table settings * and internal data. Please use only fields marked with `[*]`. @@ -122,7 +130,7 @@ struct table { 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 + struct table_col_info *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_...()) @@ -181,9 +189,10 @@ struct table { #define TBL_COL_END { .name = 0, .width = 0, .fmt = 0, .type = COL_TYPE_LAST } #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_ORDER(order) .column_order = (struct table_col_info *) order, .cols_to_output = ARRAY_SIZE(order) #define TBL_COL_DELIMITER(_delimiter_) .col_delimiter = _delimiter_ #define TBL_APPEND_DELIMITER(_delimiter_) .append_delimiter = _delimiter_ +#define TBL_COL(_idx) { .idx = _idx, .output_type = 0 } #define TBL_OUTPUT_HUMAN_READABLE .formatter = &table_fmt_human_readable #define TBL_OUTPUT_BLOCKLINE .formatter = &table_fmt_blockline