X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ucw%2Ftable.c;h=0e3f9ae81ea88d719059707e03e160618cc30036;hb=a6368763d08042207963c941b1c52b5fafcb0cb3;hp=352cf936ea65ff585b0331d44a03f8f775b3b475;hpb=dc199c55a6a07d9f5bed3a8c44c6de0edb19683c;p=libucw.git diff --git a/ucw/table.c b/ucw/table.c index 352cf936..0e3f9ae8 100644 --- a/ucw/table.c +++ b/ucw/table.c @@ -14,10 +14,8 @@ /*** Management of tables ***/ -void table_init(struct table *tbl, struct fastbuf *out) +void table_init(struct table *tbl) { - tbl->out = out; - int col_count = 0; // count the number of columns in the struct table for(;;) { @@ -56,24 +54,24 @@ static void table_make_default_column_order(struct table *tbl) for(int i = 0; i < tbl->column_count; i++) { col_order_int[i] = i; } - table_col_order(tbl, col_order_int, tbl->column_count); + table_set_col_order(tbl, col_order_int, tbl->column_count); } -void table_start(struct table *tbl) +void table_start(struct table *tbl, struct fastbuf *out) { tbl->last_printed_col = -1; tbl->row_printing_started = 0; + tbl->out = out; - // FIXME: Memory leak - tbl->col_str_ptrs = mp_alloc_zero(tbl->pool, sizeof(char *) * tbl->column_count); + ASSERT_MSG(tbl->out, "Output fastbuf not specified."); + + if(!tbl->col_str_ptrs) { + tbl->col_str_ptrs = mp_alloc_zero(tbl->pool, sizeof(char *) * tbl->column_count); + } if(tbl->column_order == NULL) table_make_default_column_order(tbl); if(tbl->formatter->table_start != NULL) tbl->formatter->table_start(tbl); - if(tbl->cols_to_output == 0) { - // FIXME: Why? - die("Table should output at least one column."); - } mp_save(tbl->pool, &tbl->pool_state); @@ -85,7 +83,6 @@ void table_end(struct table *tbl) { tbl->last_printed_col = -1; tbl->row_printing_started = 0; - tbl->print_header = 1; mp_restore(tbl->pool, &tbl->pool_state); @@ -109,23 +106,21 @@ int table_get_col_idx(struct table *tbl, const char *col_name) const char * table_get_col_list(struct table *tbl) { - if(tbl->column_count == 0) return NULL; + if(tbl->column_count == 0) return ""; - // FIXME: This does not work! The start of the string may be reallocated later. - char *tmp = mp_printf(tbl->pool, "%s", tbl->columns[0].name); + char *tmp = mp_strdup(tbl->pool, tbl->columns[0].name); for(int i = 1; i < tbl->column_count; i++) { - mp_printf_append(tbl->pool, tmp, ",%s", tbl->columns[i].name); + tmp = mp_printf_append(tbl->pool, tmp, ", %s", tbl->columns[i].name); } return tmp; } -// FIXME: Shouldn't this be table_SET_col_order() ? -void table_col_order(struct table *tbl, int *col_order, int cols_to_output) +void table_set_col_order(struct table *tbl, int *col_order, int cols_to_output) { for(int i = 0; i < cols_to_output; i++) { - 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); + 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; @@ -133,27 +128,26 @@ void table_col_order(struct table *tbl, int *col_order, int cols_to_output) } /** - * TODO: ERROR! this function deliberately causes memory leak. the - * problem is that when table_col_order_by_name is called multiple-times, - * the mp_save adds all the resulting column orders on the memory pool. - * The memory leak is small, but it is present. + * TODO: This function deliberately leaks memory. When it is called multiple times, + * previous column orders still remain allocated in the table's memory pool. **/ -int table_col_order_by_name(struct table *tbl, const char *col_order_str) +const char * table_set_col_order_by_name(struct table *tbl, const char *col_order_str) { - int col_order_len = strlen(col_order_str); + if(!col_order_str[0]) { + tbl->column_order = mp_alloc(tbl->pool, 0); + tbl->cols_to_output = 0; + return NULL; + } char *tmp_col_order = stk_strdup(col_order_str); int col_count = 1; - for(int i = 0; i < col_order_len; i++) { + for(int i = 0; col_order_str[i] != 0; i++) { if(col_order_str[i] == ',') { col_count++; } } - struct mempool_state mp_tmp_state; - mp_save(tbl->pool, &mp_tmp_state); - int *col_order_int = mp_alloc_zero(tbl->pool, sizeof(int) * col_count); int curr_col_order_int = 0; const char *name_start = tmp_col_order; @@ -164,25 +158,22 @@ int table_col_order_by_name(struct table *tbl, const char *col_order_str) } int idx = table_get_col_idx(tbl, name_start); - col_order_int[curr_col_order_int] = idx; if(idx == -1) { - //ASSERT_MSG(idx != -1, "Table column with name '%s' does not exist.", name_start); - mp_restore(tbl->pool, &mp_tmp_state); - return -1; + return mp_printf(tbl->pool, "Unknown table column '%s'", name_start); } - curr_col_order_int++; + col_order_int[curr_col_order_int++] = idx; name_start = next; } tbl->column_order = col_order_int; tbl->cols_to_output = curr_col_order_int; - return 0; + return NULL; } /*** Table cells ***/ -void table_set_printf(struct table *tbl, int col, const char *fmt, ...) +void table_col_printf(struct table *tbl, int col, const char *fmt, ...) { ASSERT_MSG(col < tbl->column_count && col >= 0, "Table column %d does not exist.", col); tbl->last_printed_col = col; @@ -193,7 +184,7 @@ void table_set_printf(struct table *tbl, int col, const char *fmt, ...) va_end(args); } -static const char *table_set_col_default_fmts[] = { +static const char *table_col_default_fmts[] = { [COL_TYPE_STR] = "%s", [COL_TYPE_INT] = "%d", [COL_TYPE_INTMAX] = "%jd", @@ -205,22 +196,22 @@ static const char *table_set_col_default_fmts[] = { [COL_TYPE_LAST] = NULL }; -#define TABLE_SET_COL(_name_, _type_, _typeconst_) void table_set_##_name_(struct table *tbl, int col, _type_ val) \ +#define TABLE_COL(_name_, _type_, _typeconst_) void table_col_##_name_(struct table *tbl, int col, _type_ val) \ {\ const char *fmt = tbl->columns[col].fmt;\ if(tbl->columns[col].type == COL_TYPE_ANY) {\ - fmt = table_set_col_default_fmts[_typeconst_];\ + fmt = table_col_default_fmts[_typeconst_];\ }\ - table_set_##_name_##_fmt(tbl, col, fmt, val);\ + table_col_##_name_##_fmt(tbl, col, fmt, val);\ } -#define TABLE_SET_COL_STR(_name_, _type_, _typeconst_) void table_set_##_name_##_name(struct table *tbl, const char *col_name, _type_ val) \ +#define TABLE_COL_STR(_name_, _type_, _typeconst_) void table_col_##_name_##_name(struct table *tbl, const char *col_name, _type_ val) \ {\ int col = table_get_col_idx(tbl, col_name);\ - table_set_##_name_(tbl, col, val);\ + table_col_##_name_(tbl, col, val);\ } -#define TABLE_SET_COL_FMT(_name_, _type_, _typeconst_) void table_set_##_name_##_fmt(struct table *tbl, int col, const char *fmt, _type_ val)\ +#define TABLE_COL_FMT(_name_, _type_, _typeconst_) void table_col_##_name_##_fmt(struct table *tbl, int col, const char *fmt, _type_ val)\ {\ ASSERT_MSG(col < tbl->column_count && col >= 0, "Table column %d does not exist.", col);\ ASSERT(tbl->columns[col].type == COL_TYPE_ANY || _typeconst_ == tbl->columns[col].type);\ @@ -230,33 +221,34 @@ static const char *table_set_col_default_fmts[] = { tbl->col_str_ptrs[col] = mp_printf(tbl->pool, fmt, val);\ } -#define TABLE_SET(_name_, _type_, _typeconst_) TABLE_SET_COL(_name_, _type_, _typeconst_);\ - TABLE_SET_COL_STR(_name_, _type_, _typeconst_);\ - TABLE_SET_COL_FMT(_name_, _type_, _typeconst_); - -TABLE_SET(int, int, COL_TYPE_INT) -TABLE_SET(uint, uint, COL_TYPE_UINT) -TABLE_SET(double, double, COL_TYPE_DOUBLE) -TABLE_SET(str, const char *, COL_TYPE_STR) -TABLE_SET(intmax, intmax_t, COL_TYPE_INTMAX) -TABLE_SET(uintmax, uintmax_t, COL_TYPE_UINTMAX) -#undef TABLE_SET_COL_FMT -#undef TABLE_SET_COL_STR -#undef TABLE_SET_COL -#undef TABLE_SET - -void table_set_bool(struct table *tbl, int col, uint val) +#define TABLE_COL_BODIES(_name_, _type_, _typeconst_) TABLE_COL(_name_, _type_, _typeconst_);\ + TABLE_COL_STR(_name_, _type_, _typeconst_);\ + TABLE_COL_FMT(_name_, _type_, _typeconst_); + +TABLE_COL_BODIES(int, int, COL_TYPE_INT) +TABLE_COL_BODIES(uint, uint, COL_TYPE_UINT) +TABLE_COL_BODIES(double, double, COL_TYPE_DOUBLE) +TABLE_COL_BODIES(str, const char *, COL_TYPE_STR) +TABLE_COL_BODIES(intmax, intmax_t, COL_TYPE_INTMAX) +TABLE_COL_BODIES(uintmax, uintmax_t, COL_TYPE_UINTMAX) +TABLE_COL_BODIES(u64, u64, COL_TYPE_U64) +#undef TABLE_COL +#undef TABLE_COL_FMT +#undef TABLE_COL_STR +#undef TABLE_COL_BODIES + +void table_col_bool(struct table *tbl, int col, uint val) { - table_set_bool_fmt(tbl, col, tbl->columns[col].fmt, val); + table_col_bool_fmt(tbl, col, tbl->columns[col].fmt, val); } -void table_set_bool_name(struct table *tbl, const char *col_name, uint val) +void table_col_bool_name(struct table *tbl, const char *col_name, uint val) { int col = table_get_col_idx(tbl, col_name); - table_set_bool(tbl, col, val); + table_col_bool(tbl, col, val); } -void table_set_bool_fmt(struct table *tbl, int col, const char *fmt, uint val) +void table_col_bool_fmt(struct table *tbl, int col, const char *fmt, uint val) { ASSERT_MSG(col < tbl->column_count && col >= 0, "Table column %d does not exist.", col); ASSERT(COL_TYPE_BOOL == tbl->columns[col].type); @@ -281,6 +273,7 @@ TABLE_APPEND(double, double, COL_TYPE_DOUBLE) TABLE_APPEND(str, const char *, COL_TYPE_STR) TABLE_APPEND(intmax, intmax_t, COL_TYPE_INTMAX) TABLE_APPEND(uintmax, uintmax_t, COL_TYPE_UINTMAX) +TABLE_APPEND(u64, u64, COL_TYPE_U64) #undef TABLE_APPEND void table_append_bool(struct table *tbl, int val) @@ -350,9 +343,6 @@ const char *table_set_option_value(struct table *tbl, const char *key, const cha // Options with a value if(value) { if(strcmp(key, "header") == 0) { - // FIXME: Check syntax of value. - //tbl->print_header = strtol(value, NULL, 10); //atoi(value); - //if(errno != 0) tbl->print_header if(value[1] != 0) return mp_printf(tbl->pool, "Tableprinter: invalid option: '%s' has invalid value: '%s'.", key, value); uint tmp = value[0] - '0'; @@ -361,10 +351,9 @@ const char *table_set_option_value(struct table *tbl, const char *key, const cha tbl->print_header = tmp; return NULL; } else if(strcmp(key, "cols") == 0) { - // FIXME: We should not exit/abort on errors caused from command line. - if(table_col_order_by_name(tbl, value) != 0) { - const char *tmp = table_get_col_list(tbl); - return mp_printf(tbl->pool, "Invalid tableprinter column list: possible column names are %s.", tmp); + const char *err = table_set_col_order_by_name(tbl, value); + if(err != NULL) { + return mp_printf(tbl->pool, "%s, possible column names are: %s.", err, table_get_col_list(tbl)); } return NULL; } else if(strcmp(key, "fmt") == 0) { @@ -418,30 +407,29 @@ const char *table_set_gary_options(struct table *tbl, char **gary_table_opts) static void table_row_human_readable(struct table *tbl) { - uint col = tbl->column_order[0]; - int col_width = tbl->columns[col].width; - bprintf(tbl->out, "%*s", col_width, tbl->col_str_ptrs[col]); - for(uint i = 1; i < tbl->cols_to_output; i++) { - col = tbl->column_order[i]; - col_width = tbl->columns[col].width; - bputs(tbl->out, tbl->col_delimiter); - bprintf(tbl->out, "%*s", col_width, tbl->col_str_ptrs[col]); + for(uint i = 0; i < tbl->cols_to_output; i++) { + int col_idx = tbl->column_order[i]; + 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'); } static void table_write_header(struct table *tbl) { - uint col_idx = tbl->column_order[0]; - bprintf(tbl->out, "%*s", tbl->columns[col_idx].width, tbl->columns[col_idx].name); - - for(uint i = 1; i < tbl->cols_to_output; i++) { - col_idx = tbl->column_order[i]; - bputs(tbl->out, tbl->col_delimiter); - bprintf(tbl->out, "%*s", tbl->columns[col_idx].width, tbl->columns[col_idx].name); + for(uint i = 0; i < tbl->cols_to_output; i++) { + int col_idx = tbl->column_order[i]; + 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->columns[col_idx].name); } - bputc(tbl->out, '\n'); } @@ -456,7 +444,6 @@ static void table_start_human_readable(struct table *tbl) } if(tbl->print_header != 0) { - tbl->print_header = 0; table_write_header(tbl); } } @@ -470,14 +457,13 @@ struct table_formatter table_fmt_human_readable = { static void table_row_machine_readable(struct table *tbl) { - uint col = tbl->column_order[0]; - bputs(tbl->out, tbl->col_str_ptrs[col]); - for(uint i = 1; i < tbl->cols_to_output; i++) { - col = tbl->column_order[i]; - bputs(tbl->out, tbl->col_delimiter); - bputs(tbl->out, tbl->col_str_ptrs[col]); + for(uint i = 0; i < tbl->cols_to_output; i++) { + int col_idx = tbl->column_order[i]; + if(i) { + bputs(tbl->out, tbl->col_delimiter); + } + bputs(tbl->out, tbl->col_str_ptrs[col_idx]); } - bputc(tbl->out, '\n'); } @@ -492,10 +478,6 @@ static void table_start_machine_readable(struct table *tbl) } if(tbl->print_header != 0) { - // FIXME: This magic is not needed, the value of print_header should be kept - // to the value set during table initialization (e.g., by command-line options) - tbl->print_header = 0; - uint col_idx = tbl->column_order[0]; bputs(tbl->out, tbl->columns[col_idx].name); for(uint i = 1; i < tbl->cols_to_output; i++) { @@ -526,11 +508,11 @@ static uint test_column_order[] = {test_col3_bool, test_col4_double, test_col2_u static struct table test_tbl = { TBL_COLUMNS { - TBL_COL_STR(test, col0_str, 20), - TBL_COL_INT(test, col1_int, 8), - TBL_COL_UINT(test, col2_uint, 9), - TBL_COL_BOOL(test, col3_bool, 9), - TBL_COL_DOUBLE(test, col4_double, 11, 2), + [test_col0_str] = TBL_COL_STR("col0_str", 20), + [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), + [test_col4_double] = TBL_COL_DOUBLE("col4_double", 11, 2), TBL_COL_END }, TBL_COL_ORDER(test_column_order), @@ -544,69 +526,71 @@ static struct table test_tbl = { **/ static void do_print1(struct table *test_tbl) { - table_set_str(test_tbl, test_col0_str, "sdsdf"); + table_col_str(test_tbl, test_col0_str, "sdsdf"); table_append_str(test_tbl, "aaaaa"); - table_set_int(test_tbl, test_col1_int, -10); - table_set_int(test_tbl, test_col1_int, 10000); - table_set_uint(test_tbl, test_col2_uint, 10); - table_set_printf(test_tbl, test_col2_uint, "XXX-%u", 22222); - table_set_bool(test_tbl, test_col3_bool, 1); - table_set_double(test_tbl, test_col4_double, 1.5); - table_set_printf(test_tbl, test_col4_double, "AAA"); + table_col_int(test_tbl, test_col1_int, -10); + table_col_int(test_tbl, test_col1_int, 10000); + table_col_uint(test_tbl, test_col2_uint, 10); + table_col_printf(test_tbl, test_col2_uint, "XXX-%u", 22222); + table_col_bool(test_tbl, test_col3_bool, 1); + table_col_double(test_tbl, test_col4_double, 1.5); + table_col_printf(test_tbl, test_col4_double, "AAA"); table_end_row(test_tbl); - table_set_str(test_tbl, test_col0_str, "test"); + table_col_str(test_tbl, test_col0_str, "test"); table_append_str(test_tbl, "bbbbb"); - table_set_int(test_tbl, test_col1_int, -100); - table_set_uint(test_tbl, test_col2_uint, 100); - table_set_bool(test_tbl, test_col3_bool, 0); - table_set_printf(test_tbl, test_col4_double, "%.2lf", 1.5); + table_col_int(test_tbl, test_col1_int, -100); + table_col_uint(test_tbl, test_col2_uint, 100); + table_col_bool(test_tbl, test_col3_bool, 0); + table_col_printf(test_tbl, test_col4_double, "%.2lf", 1.5); table_end_row(test_tbl); } static void test_simple1(struct fastbuf *out) { - table_init(&test_tbl, out); + table_init(&test_tbl); + // print table with header - table_col_order_by_name(&test_tbl, "col3_bool"); - table_start(&test_tbl); + table_set_col_order_by_name(&test_tbl, "col3_bool"); + table_start(&test_tbl, out); do_print1(&test_tbl); table_end(&test_tbl); // print the same table as in the previous case without header - table_col_order_by_name(&test_tbl, "col0_str,col2_uint,col1_int,col3_bool"); - table_start(&test_tbl); + table_set_col_order_by_name(&test_tbl, "col0_str,col2_uint,col1_int,col3_bool"); + table_start(&test_tbl, out); do_print1(&test_tbl); table_end(&test_tbl); - // this also tests whether there is need to call table_col_order_by_name after table_end was called + // this also tests whether there is need to call table_set_col_order_by_name after table_end was called test_tbl.print_header = 0; - table_start(&test_tbl); + table_start(&test_tbl, out); do_print1(&test_tbl); table_end(&test_tbl); + test_tbl.print_header = 1; - table_col_order_by_name(&test_tbl, "col3_bool"); - table_start(&test_tbl); + table_set_col_order_by_name(&test_tbl, "col3_bool"); + table_start(&test_tbl, out); do_print1(&test_tbl); table_end(&test_tbl); - table_col_order_by_name(&test_tbl, "col3_bool,col0_str"); - table_start(&test_tbl); + table_set_col_order_by_name(&test_tbl, "col3_bool,col0_str"); + table_start(&test_tbl, out); do_print1(&test_tbl); table_end(&test_tbl); - table_col_order_by_name(&test_tbl, "col0_str,col3_bool,col2_uint"); - table_start(&test_tbl); + table_set_col_order_by_name(&test_tbl, "col0_str,col3_bool,col2_uint"); + table_start(&test_tbl, out); do_print1(&test_tbl); table_end(&test_tbl); - table_col_order_by_name(&test_tbl, "col0_str,col3_bool,col2_uint,col0_str,col3_bool,col2_uint,col0_str,col3_bool,col2_uint"); - table_start(&test_tbl); + table_set_col_order_by_name(&test_tbl, "col0_str,col3_bool,col2_uint,col0_str,col3_bool,col2_uint,col0_str,col3_bool,col2_uint"); + table_start(&test_tbl, out); do_print1(&test_tbl); table_end(&test_tbl); - table_col_order_by_name(&test_tbl, "col0_str,col1_int,col2_uint,col3_bool,col4_double"); - table_start(&test_tbl); + table_set_col_order_by_name(&test_tbl, "col0_str,col1_int,col2_uint,col3_bool,col4_double"); + table_start(&test_tbl, out); do_print1(&test_tbl); table_end(&test_tbl); @@ -621,8 +605,8 @@ static uint test_any_column_order[] = { test_any_col0_int, test_any_col1_any }; static struct table test_any_tbl = { TBL_COLUMNS { - TBL_COL_INT(test_any, col0_int, 8), - TBL_COL_ANY(test_any, col1_any, 9), + [test_any_col0_int] = TBL_COL_INT("col0_int", 8), + [test_any_col1_any] = TBL_COL_ANY("col1_any", 9), TBL_COL_END }, TBL_COL_ORDER(test_any_column_order), @@ -633,21 +617,22 @@ static struct table test_any_tbl = { static void test_any_type(struct fastbuf *out) { - table_init(&test_any_tbl, out); - table_start(&test_any_tbl); + table_init(&test_any_tbl); + + table_start(&test_any_tbl, out); - table_set_int(&test_any_tbl, test_any_col0_int, -10); - table_set_int(&test_any_tbl, test_any_col1_any, 10000); + table_col_int(&test_any_tbl, test_any_col0_int, -10); + table_col_int(&test_any_tbl, test_any_col1_any, 10000); table_end_row(&test_any_tbl); - table_set_int(&test_any_tbl, test_any_col0_int, -10); - table_set_double(&test_any_tbl, test_any_col1_any, 1.4); + table_col_int(&test_any_tbl, test_any_col0_int, -10); + table_col_double(&test_any_tbl, test_any_col1_any, 1.4); table_end_row(&test_any_tbl); - table_set_printf(&test_any_tbl, test_any_col0_int, "%d", 10); + table_col_printf(&test_any_tbl, test_any_col0_int, "%d", 10); table_append_printf(&test_any_tbl, "%d", 20); table_append_printf(&test_any_tbl, "%d", 30); - table_set_double(&test_any_tbl, test_any_col1_any, 1.4); + table_col_double(&test_any_tbl, test_any_col1_any, 1.4); table_append_printf(&test_any_tbl, "%.2lf", 1.5); table_append_printf(&test_any_tbl, "%.2lf", 1.6); table_end_row(&test_any_tbl);