From 6198757b40ad3e42ace89a5f5a7f232fd8993e4d Mon Sep 17 00:00:00 2001 From: Robert Kessl Date: Mon, 14 Jul 2014 10:14:43 +0200 Subject: [PATCH] xtype&tableprinter: first shot on incorporating xtypes to tableprinter --- ucw/table-test-2.c | 12 ++-- ucw/table-types.c | 51 ++++++++--------- ucw/table-types.h | 29 +++++----- ucw/table.c | 128 ++++++++++-------------------------------- ucw/table.h | 107 +++++++++++++++++++---------------- ucw/xtypes-basic.c | 137 ++++++++++++++++++++++++++++++++++++++++++--- ucw/xtypes.h | 8 +++ 7 files changed, 271 insertions(+), 201 deletions(-) diff --git a/ucw/table-test-2.c b/ucw/table-test-2.c index 8b58dfa9..b31295d1 100644 --- a/ucw/table-test-2.c +++ b/ucw/table-test-2.c @@ -16,7 +16,7 @@ enum test_table_cols { static struct table_template test_tbl = { TBL_COLUMNS { - [TEST_COL0_SIZE] = TBL_COL_SIZE_FMT("size", 15, UNIT_SIZE_BYTE), + [TEST_COL0_SIZE] = TBL_COL_SIZE_FMT("size", 15, SIZE_UNITS_FIXED | UNIT_SIZE_BYTE), [TEST_COL1_TS] = TBL_COL_TIMESTAMP("ts", 20), TBL_COL_END }, @@ -37,24 +37,24 @@ static void do_test(void) table_col_timestamp(tbl, TEST_COL1_TS, test_time); table_end_row(tbl); - tbl->column_order[TEST_COL0_SIZE].output_type = SIZE_UNIT_KILOBYTE; + tbl->column_order[TEST_COL0_SIZE].output_type = SIZE_UNITS_FIXED | SIZE_UNIT_KILOBYTE; table_col_size(tbl, TEST_COL0_SIZE, test_size); table_col_timestamp(tbl, TEST_COL1_TS, test_time); table_end_row(tbl); - tbl->column_order[TEST_COL0_SIZE].output_type = SIZE_UNIT_MEGABYTE; + tbl->column_order[TEST_COL0_SIZE].output_type = SIZE_UNITS_FIXED | SIZE_UNIT_MEGABYTE; table_col_size(tbl, TEST_COL0_SIZE, test_size); table_col_timestamp(tbl, TEST_COL1_TS, test_time); table_end_row(tbl); - tbl->column_order[TEST_COL0_SIZE].output_type = SIZE_UNIT_GIGABYTE; + tbl->column_order[TEST_COL0_SIZE].output_type = SIZE_UNITS_FIXED | SIZE_UNIT_GIGABYTE; tbl->column_order[TEST_COL1_TS].output_type = TIMESTAMP_DATETIME; table_col_size(tbl, TEST_COL0_SIZE, test_size); table_col_timestamp(tbl, TEST_COL1_TS, test_time); table_end_row(tbl); test_size = test_size * 1024LU; - tbl->column_order[TEST_COL0_SIZE].output_type = SIZE_UNIT_TERABYTE; + tbl->column_order[TEST_COL0_SIZE].output_type = SIZE_UNITS_FIXED | SIZE_UNIT_TERABYTE; tbl->column_order[TEST_COL1_TS].output_type = TIMESTAMP_DATETIME; table_col_size(tbl, TEST_COL0_SIZE, test_size); table_col_timestamp(tbl, TEST_COL1_TS, test_time); @@ -68,7 +68,7 @@ static void do_test(void) static struct table_template test_tbl2 = { TBL_COLUMNS { - [TEST_COL0_SIZE] = TBL_COL_SIZE_FMT("size", 15, SIZE_UNIT_BYTE), + [TEST_COL0_SIZE] = TBL_COL_SIZE_FMT("size", 15, SIZE_UNITS_FIXED | SIZE_UNIT_BYTE), [TEST_COL1_TS] = TBL_COL_TIMESTAMP("ts", 20), TBL_COL_END }, diff --git a/ucw/table-types.c b/ucw/table-types.c index 992ee208..fc8f6ed8 100644 --- a/ucw/table-types.c +++ b/ucw/table-types.c @@ -6,6 +6,9 @@ #include #include +const struct xtype xt_size; +const struct xtype xt_timestamp; + static const char *unit_suffix[] = { [SIZE_UNIT_BYTE] = "", [SIZE_UNIT_KILOBYTE] = "KB", @@ -14,28 +17,28 @@ static const char *unit_suffix[] = { [SIZE_UNIT_TERABYTE] = "TB" }; -static bool table_set_col_opt_size(struct table *tbl, uint col_inst_idx, const char *col_arg, char **err) +bool table_set_col_opt_size(struct table *tbl, uint col_inst_idx, const char *col_arg, char **err) { struct table_column *col_def = tbl->column_order[col_inst_idx].col_def; - if(col_def->type != COL_TYPE_SIZE) { + if(col_def->type_def != COL_TYPE_SIZE) { *err = NULL; return false; } if(col_arg == NULL || strcasecmp(col_arg, "b") == 0 || strcasecmp(col_arg, "bytes") == 0) { - tbl->column_order[col_inst_idx].output_type = SIZE_UNIT_BYTE; + tbl->column_order[col_inst_idx].output_type = SIZE_UNIT_BYTE | SIZE_UNITS_FIXED; *err = NULL; return true; } - tbl->column_order[col_inst_idx].output_type = CELL_OUT_UNINITIALIZED; + tbl->column_order[col_inst_idx].output_type = XTYPE_FMT_DEFAULT; // CELL_OUT_UNINITIALIZED; for(uint i = SIZE_UNIT_BYTE; i <= SIZE_UNIT_TERABYTE; i++) { if(strcasecmp(col_arg, unit_suffix[i]) == 0) { - tbl->column_order[col_inst_idx].output_type = i; + tbl->column_order[col_inst_idx].output_type = i | SIZE_UNITS_FIXED; } } - if(tbl->column_order[col_inst_idx].output_type == CELL_OUT_UNINITIALIZED) { + if(tbl->column_order[col_inst_idx].output_type == XTYPE_FMT_DEFAULT) { *err = mp_printf(tbl->pool, "Invalid column format option: '%s' for column %d (counted from 0)", col_arg, col_inst_idx); return true; } @@ -44,15 +47,10 @@ static bool table_set_col_opt_size(struct table *tbl, uint col_inst_idx, const c return true; } -struct table_user_type table_type_size = { - .set_col_instance_option = table_set_col_opt_size, - .type = COL_TYPE_SIZE, -}; - -static bool table_set_col_opt_timestamp(struct table *tbl, uint col_inst_idx, const char *col_arg, char **err) +bool table_set_col_opt_timestamp(struct table *tbl, uint col_inst_idx, const char *col_arg, char **err) { int col_type_idx = tbl->column_order[col_inst_idx].idx; - if(tbl->columns[col_type_idx].type != COL_TYPE_TIMESTAMP) { + if(tbl->columns[col_type_idx].type_def != COL_TYPE_TIMESTAMP) { *err = NULL; return false; } @@ -75,11 +73,6 @@ static bool table_set_col_opt_timestamp(struct table *tbl, uint col_inst_idx, co return true; } -struct table_user_type table_type_timestamp = { - .set_col_instance_option = table_set_col_opt_timestamp, - .type = COL_TYPE_TIMESTAMP, -}; - void table_col_size_name(struct table *tbl, const char *col_name, u64 val) { int col = table_get_col_idx(tbl, col_name); @@ -89,7 +82,7 @@ void table_col_size_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); + ASSERT(tbl->columns[col].type_def == COL_TYPE_ANY || COL_TYPE_SIZE == tbl->columns[col].type_def); tbl->last_printed_col = col; tbl->row_printing_started = 1; @@ -107,12 +100,16 @@ void table_col_size(struct table *tbl, int col, u64 val) // FIXME: do some rounding? Or maybe use double and floating-point printing? uint out_type = 0; u64 curr_val = val; - if(curr_col->output_type == CELL_OUT_UNINITIALIZED) { + + if(curr_col->output_type == XTYPE_FMT_DEFAULT || curr_col->output_type == XTYPE_FMT_RAW) { curr_val = curr_val / unit_div[SIZE_UNIT_BYTE]; out_type = SIZE_UNIT_BYTE; - } else { - curr_val = curr_val / unit_div[curr_col->output_type]; - out_type = curr_col->output_type; + } else if(curr_col->output_type == XTYPE_FMT_PRETTY) { + curr_val = curr_val / unit_div[SIZE_UNIT_BYTE]; + out_type = SIZE_UNIT_BYTE; // curr_col->output_type; + } else if((curr_col->output_type & SIZE_UNITS_FIXED) != 0) { + curr_val = curr_val / unit_div[curr_col->output_type & ~SIZE_UNITS_FIXED]; + out_type = curr_col->output_type & ~SIZE_UNITS_FIXED; } curr_col->cell_content = mp_printf(tbl->pool, "%lu%s", curr_val, unit_suffix[out_type]); @@ -130,7 +127,7 @@ void table_col_timestamp_name(struct table *tbl, const char * col_name, u64 val) 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(tbl->columns[col].type_def == COL_TYPE_ANY || COL_TYPE_TIMESTAMP == tbl->columns[col].type_def); char formatted_time_buf[FORMAT_TIME_SIZE] = { 0 }; @@ -138,11 +135,11 @@ void table_col_timestamp(struct table *tbl, int col, u64 val) struct tm t = *gmtime(&tmp_time); TBL_COL_ITER_START(tbl, col, curr_col, curr_col_idx) { switch (curr_col->output_type) { - case TIMESTAMP_EPOCH: - case CELL_OUT_UNINITIALIZED: + case XTYPE_FMT_DEFAULT: + case XTYPE_FMT_RAW: sprintf(formatted_time_buf, "%lu", val); break; - case TIMESTAMP_DATETIME: + case XTYPE_FMT_PRETTY: strftime(formatted_time_buf, FORMAT_TIME_SIZE, "%F %T", &t); break; default: diff --git a/ucw/table-types.h b/ucw/table-types.h index e6b542a9..8ca14f6e 100644 --- a/ucw/table-types.h +++ b/ucw/table-types.h @@ -10,7 +10,7 @@ #include enum size_units { - SIZE_UNIT_BYTE = CELL_OUT_USER_DEF_START, + SIZE_UNIT_BYTE, SIZE_UNIT_KILOBYTE, SIZE_UNIT_MEGABYTE, SIZE_UNIT_GIGABYTE, @@ -18,22 +18,25 @@ enum size_units { SIZE_UNIT_AUTO }; -enum timestamp_format { - TIMESTAMP_EPOCH, - TIMESTAMP_DATETIME -}; +#define COL_TYPE_SIZE &xt_size +#define COL_TYPE_TIMESTAMP &xt_timestamp + +#define TIMESTAMP_EPOCH XTYPE_FMT_RAW +#define TIMESTAMP_DATETIME XTYPE_FMT_PRETTY + +#define SIZE_UNITS_FIXED 0x40000000 -#define COL_TYPE_SIZE COL_TYPE_UCW -#define COL_TYPE_TIMESTAMP (COL_TYPE_UCW+1) +extern const struct xtype xt_size; +extern const struct xtype xt_timestamp; -extern struct table_user_type table_type_timestamp; -extern struct table_user_type table_type_size; +bool table_set_col_opt_size(struct table *tbl, uint col_inst_idx, const char *col_arg, char **err); +bool table_set_col_opt_timestamp(struct table *tbl, uint col_inst_idx, const char *col_arg, char **err); -#define TBL_COL_SIZE(_name, _width) { .name = _name, .width = _width, .fmt = "%llu", .type = COL_TYPE_SIZE, .type_def = &table_type_size } -#define TBL_COL_TIMESTAMP(_name, _width) { .name = _name, .width = _width, .fmt = "%lld", .type = COL_TYPE_TIMESTAMP, .type_def = &table_type_timestamp } +#define TBL_COL_SIZE(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = COL_TYPE_SIZE, .set_col_instance_option = table_set_col_opt_size } +#define TBL_COL_TIMESTAMP(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = COL_TYPE_TIMESTAMP, .set_col_instance_option = table_set_col_opt_timestamp } -#define TBL_COL_SIZE_FMT(_name, _width, _units) { .name = _name, .width = _width, .fmt = "%llu", .type = COL_TYPE_SIZE, .type_def = &table_type_size } -#define TBL_COL_TIMESTAMP_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = "%lld", .type = COL_TYPE_TIMESTAMP, .type_def = &table_type_timestamp } +#define TBL_COL_SIZE_FMT(_name, _width, _units) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = COL_TYPE_SIZE, .set_col_instance_option = table_set_col_opt_size } +#define TBL_COL_TIMESTAMP_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = COL_TYPE_TIMESTAMP, .set_col_instance_option = table_set_col_opt_timestamp } void table_col_size_name(struct table *tbl, const char *col_name, u64 val); void table_col_timestamp_name(struct table *tbl, const char * col_name, u64 val); diff --git a/ucw/table.c b/ucw/table.c index 0fc8b572..c5d59a58 100644 --- a/ucw/table.c +++ b/ucw/table.c @@ -22,7 +22,8 @@ static void table_update_ll(struct table *tbl); static struct table *table_make_instance(const struct table_template *tbl_template) { - struct table *new_inst = xmalloc_zero(sizeof(struct table)); // FIXME: update allocation to the weird schema made by pchar and mj? + struct mempool *pool = mp_new(4096); + struct table *new_inst = mp_alloc_zero(pool, sizeof(struct table)); // FIXME: update allocation to the weird schema made by pchar and mj? new_inst->pool = mp_new(4096); @@ -30,12 +31,10 @@ static struct table *table_make_instance(const struct table_template *tbl_templa int col_count = 0; // count the number of columns in the struct table for(;;) { if(tbl_template->columns[col_count].name == NULL && - tbl_template->columns[col_count].fmt == NULL && tbl_template->columns[col_count].width == 0 && - tbl_template->columns[col_count].type == COL_TYPE_LAST) + tbl_template->columns[col_count].type_def == COL_TYPE_ANY) break; ASSERT(tbl_template->columns[col_count].name != NULL); - ASSERT(tbl_template->columns[col_count].type == COL_TYPE_ANY || tbl_template->columns[col_count].fmt != NULL); ASSERT(tbl_template->columns[col_count].width != 0); col_count++; @@ -51,8 +50,7 @@ static struct table *table_make_instance(const struct table_template *tbl_templa memcpy(new_inst->column_order, tbl_template->column_order, sizeof(struct table_col_instance) * tbl_template->cols_to_output); for(uint i = 0; i < new_inst->cols_to_output; i++) { new_inst->column_order[i].cell_content = NULL; - //new_inst->column_order[i].col_def = NULL; // FIXME: col_def should not be touched, probably ... - int col_idx = new_inst->column_order[i].idx;//col_order[i]; + int col_idx = new_inst->column_order[i].idx; new_inst->column_order[i].col_def = new_inst->columns + col_idx; new_inst->column_order[i].output_type = tbl_template->column_order[i].output_type; } @@ -87,7 +85,6 @@ void table_cleanup(struct table *tbl) { mp_delete(tbl->pool); memset(tbl, 0, sizeof(struct table)); - xfree(tbl); } // TODO: test default column order @@ -196,7 +193,7 @@ void table_set_col_order(struct table *tbl, int *col_order, int cols_to_output) tbl->column_order[i].idx = col_idx; tbl->column_order[i].col_def = tbl->columns + col_idx; tbl->column_order[i].cell_content = NULL; - tbl->column_order[i].output_type = CELL_OUT_UNINITIALIZED; + tbl->column_order[i].output_type = XTYPE_FMT_DEFAULT; } table_update_ll(tbl); } @@ -227,14 +224,14 @@ bool table_set_col_opt_default(struct table *tbl, int col_idx, const char *col_a { struct table_column *col_def = tbl->column_order[col_idx].col_def; - if(col_def->type == COL_TYPE_DOUBLE) { + if(col_def->type_def == COL_TYPE_DOUBLE) { uint precision = 0; const char *tmp_err = str_to_uint(&precision, col_arg, NULL, 0); if(tmp_err) { *err = mp_printf(tbl->pool, "An error occured while parsing precision: %s", tmp_err); return false; } - tbl->column_order[col_idx].output_type = precision; + tbl->column_order[col_idx].output_type = precision; // FIXME: shift the value of precision return true; } @@ -293,10 +290,10 @@ const char * table_set_col_order_by_name(struct table *tbl, const char *col_orde tbl->column_order[curr_col_idx].col_def = tbl->columns + col_idx; tbl->column_order[curr_col_idx].idx = col_idx; tbl->column_order[curr_col_idx].cell_content = NULL; - tbl->column_order[curr_col_idx].output_type = CELL_OUT_UNINITIALIZED; - if(tbl->columns[col_idx].type_def && tbl->columns[col_idx].type_def->set_col_instance_option) { + tbl->column_order[curr_col_idx].output_type = XTYPE_FMT_DEFAULT; + if(tbl->columns[col_idx].type_def && tbl->columns[col_idx].set_col_instance_option) { char *err = NULL; - tbl->columns[col_idx].type_def->set_col_instance_option(tbl, curr_col_idx, arg, &err); + tbl->columns[col_idx].set_col_instance_option(tbl, curr_col_idx, arg, &err); if(err) return mp_printf(tbl->pool, "Error occured while setting column option: %s.", err); } @@ -311,12 +308,12 @@ const char * table_set_col_order_by_name(struct table *tbl, const char *col_orde /*** Table cells ***/ -static void table_set_all_inst_content(struct table *tbl, int col_templ, char *col_content, int override) +static void table_set_all_inst_content(struct table *tbl, int col_templ, const char *col_content) { TBL_COL_ITER_START(tbl, col_templ, curr_col_ptr, curr_col) { - if(override == 0 && curr_col_ptr->output_type != CELL_OUT_UNINITIALIZED ) { - die("Error while setting content of all cells of a single type column, cell format should not be overriden."); - } + //if( override == 0 ) { + //die("Error while setting content of all cells of a single type column, cell format should not be overriden."); + //} curr_col_ptr->cell_content = col_content; } TBL_COL_ITER_END } @@ -329,30 +326,13 @@ void table_col_printf(struct table *tbl, int col, const char *fmt, ...) va_list args; va_start(args, fmt); char *cell_content = mp_vprintf(tbl->pool, fmt, args); - table_set_all_inst_content(tbl, col, cell_content, 1); + table_set_all_inst_content(tbl, col, cell_content); va_end(args); } -static const char *table_col_default_fmts[] = { - [COL_TYPE_STR] = "%s", - [COL_TYPE_INT] = "%d", - [COL_TYPE_S64] = "%lld", - [COL_TYPE_INTMAX] = "%jd", - [COL_TYPE_UINT] = "%u", - [COL_TYPE_U64] = "%llu", - [COL_TYPE_UINTMAX] = "%ju", - [COL_TYPE_BOOL] = "%d", - [COL_TYPE_DOUBLE] = "%.2lf", - [COL_TYPE_ANY] = NULL, - [COL_TYPE_LAST] = NULL -}; - #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_col_default_fmts[_typeconst_];\ - }\ + enum xtype_fmt fmt = tbl->columns[col].fmt;\ table_col_##_name_##_fmt(tbl, col, fmt, val);\ } @@ -362,15 +342,16 @@ static const char *table_col_default_fmts[] = { table_col_##_name_(tbl, col, val);\ } -#define TABLE_COL_FMT(_name_, _type_, _typeconst_, _override) void table_col_##_name_##_fmt(struct table *tbl, int col, const char *fmt, _type_ val) \ +#define TABLE_COL_FMT(_name_, _type_, _typeconst_, _override) void table_col_##_name_##_fmt(struct table *tbl, int col, enum xtype_fmt 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);\ - ASSERT(fmt != NULL);\ + ASSERT(tbl->columns[col].type_def == COL_TYPE_ANY || _typeconst_ == tbl->columns[col].type_def);\ tbl->last_printed_col = col;\ tbl->row_printing_started = 1;\ - char *cell_content = mp_printf(tbl->pool, fmt, val);\ - table_set_all_inst_content(tbl, col, cell_content, _override);\ + const char *cell_content = NULL;\ + if(tbl->columns[col].type_def != COL_TYPE_ANY) cell_content = tbl->columns[col].type_def->format(&val, fmt, tbl->pool);\ + else cell_content = (_typeconst_)->format(&val, fmt, tbl->pool); \ + table_set_all_inst_content(tbl, col, cell_content);\ } #define TABLE_COL_BODIES(_name_, _type_, _typeconst_, _override) TABLE_COL(_name_, _type_, _typeconst_); \ @@ -384,71 +365,22 @@ TABLE_COL_BODIES(intmax, intmax_t, COL_TYPE_INTMAX, 0) TABLE_COL_BODIES(uintmax, uintmax_t, COL_TYPE_UINTMAX, 0) TABLE_COL_BODIES(s64, s64, COL_TYPE_S64, 0) TABLE_COL_BODIES(u64, u64, COL_TYPE_U64, 0) +TABLE_COL_BODIES(double, double, COL_TYPE_DOUBLE, 0) +//TABLE_COL_BODIES(bool, bool, COL_TYPE_BOOL, 0) // column type double is a special case -TABLE_COL(double, double, COL_TYPE_DOUBLE); -TABLE_COL_STR(double, double, COL_TYPE_DOUBLE); +//TABLE_COL(double, double, COL_TYPE_DOUBLE); +//TABLE_COL_STR(double, double, COL_TYPE_DOUBLE); -TABLE_COL(bool, bool, COL_TYPE_BOOL); -TABLE_COL_STR(bool, bool, COL_TYPE_BOOL); +TABLE_COL(bool, bool, COL_TYPE_BOOL) +TABLE_COL_STR(bool, bool, COL_TYPE_BOOL) +TABLE_COL_FMT(bool, bool, COL_TYPE_BOOL, 0) #undef TABLE_COL #undef TABLE_COL_FMT #undef TABLE_COL_STR #undef TABLE_COL_BODIES -void table_col_double_fmt(struct table *tbl, int col, const char *fmt, double 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_DOUBLE == tbl->columns[col].type); - ASSERT(fmt != NULL); - tbl->last_printed_col = col; - tbl->row_printing_started = 1; - char *cell_content = mp_printf(tbl->pool, fmt, val); - int curr_col = tbl->columns[col].first_column; - while(curr_col != -1) { - char *cell_content_tmp = NULL; - switch(tbl->column_order[curr_col].output_type) { - case CELL_OUT_UNINITIALIZED: - cell_content_tmp = cell_content; - break; - case CELL_OUT_MACHINE_READABLE: - cell_content_tmp = mp_printf(tbl->pool, "%4lf", val); - break; - default: - cell_content_tmp = mp_printf(tbl->pool, "%.*lf", tbl->column_order[curr_col].output_type, val); - break; - } - tbl->column_order[curr_col].cell_content = cell_content_tmp; - curr_col = tbl->column_order[curr_col].next_column; - } -} - -void table_col_bool_fmt(struct table *tbl, int col, const char *fmt, bool val) -{ - ASSERT_MSG(col < tbl->column_count && col >= 0, "Table column %d does not exist.", col); - ASSERT(COL_TYPE_BOOL == tbl->columns[col].type); - - tbl->last_printed_col = col; - tbl->row_printing_started = 1; - - int curr_col = tbl->columns[col].first_column; - while(curr_col != -1) { - switch(tbl->column_order[curr_col].output_type) { - case CELL_OUT_HUMAN_READABLE: - case CELL_OUT_UNINITIALIZED: - tbl->column_order[curr_col].cell_content = mp_printf(tbl->pool, fmt, val ? "true" : "false"); - break; - case CELL_OUT_MACHINE_READABLE: - // FIXME: this is just an example of printing in different formats - tbl->column_order[curr_col].cell_content = mp_printf(tbl->pool, fmt, val ? "1" : "0"); - break; - default: - die("Unsupported output type."); - } - curr_col = tbl->column_order[curr_col].next_column; - } -} void table_reset_row(struct table *tbl) { @@ -481,7 +413,7 @@ struct fastbuf *table_col_fbstart(struct table *tbl, int col) void table_col_fbend(struct table *tbl) { char *cell_content = fbpool_end(&tbl->fb_col_out); - table_set_all_inst_content(tbl, tbl->col_out, cell_content, 1); + table_set_all_inst_content(tbl, tbl->col_out, cell_content); tbl->col_out = -1; } diff --git a/ucw/table.h b/ucw/table.h index 488c4833..885d64cd 100644 --- a/ucw/table.h +++ b/ucw/table.h @@ -9,7 +9,9 @@ #include #include +#include +// FIXME: update these macros #ifdef CONFIG_UCW_CLEAN_ABI #define table_append_bool ucw_table_append_bool #define table_append_double ucw_table_append_double @@ -76,6 +78,19 @@ // FIXME: update documentation according to the changes made in recent commits! /** Types of columns. These are seldom used explicitly, using a column definition macro is preferred. **/ + +#define COL_TYPE_STR &xt_str +#define COL_TYPE_INT &xt_int +#define COL_TYPE_S64 &xt_s64 +#define COL_TYPE_INTMAX &xt_intmax +#define COL_TYPE_UINT &xt_uint +#define COL_TYPE_U64 &xt_u64 +#define COL_TYPE_UINTMAX &xt_uintmax +#define COL_TYPE_BOOL &xt_bool +#define COL_TYPE_DOUBLE &xt_double +#define COL_TYPE_ANY NULL + +/* enum column_type { COL_TYPE_STR, // String COL_TYPE_INT, // int @@ -89,9 +104,7 @@ enum column_type { COL_TYPE_ANY, // Any 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) @@ -101,20 +114,13 @@ enum column_type { #define CELL_FLAG_MASK (CELL_ALIGN_LEFT) #define CELL_WIDTH_MASK (~CELL_FLAG_MASK) -#define CELL_OUT_UNINITIALIZED -1 -#define CELL_OUT_HUMAN_READABLE -2 -#define CELL_OUT_MACHINE_READABLE -3 -#define CELL_OUT_USER_DEF_START 5 +//#define CELL_OUT_UNINITIALIZED -1 +//#define CELL_OUT_HUMAN_READABLE -2 +//#define CELL_OUT_MACHINE_READABLE -3 +//#define CELL_OUT_USER_DEF_START 5 struct table; -struct table_user_type { - bool (*set_col_instance_option)(struct table *tbl, uint col, const char *value, char **err); - // [*] process table option for a column instance - uint type; // [*] type identifier, should be a number shifted by COL_TYPE_CUSTOM - const char *default_fmt; // [*] default format used for printing -}; - /** * Definition of a single table column. * Usually, this is generated using the `TABLE_COL_`'type' macros. @@ -123,10 +129,14 @@ struct table_user_type { struct table_column { const char *name; // [*] Name of the column displayed in table header int width; // [*] Width of the column (in characters) OR'ed with column flags - const char *fmt; // [*] Default format of each cell in the column - enum column_type type; // [*] Type of the cells in the column + //const char *fmt; // [*] Default format of each cell in the column + //enum column_type type; // [*] Type of the cells in the column + enum xtype_fmt fmt; int first_column; // head of linked list of columns of this type - struct table_user_type *type_def; + const struct xtype *type_def; + + bool (*set_col_instance_option)(struct table *tbl, uint col, const char *value, char **err); + // [*] process table option for a column instance }; // FIXME: is it correct to have idx and col_def? idx is sufficient and in fact a duplicity of idx @@ -134,9 +144,9 @@ struct table_column { struct table_col_instance { uint idx; // idx is a index into struct table::columns struct table_column *col_def; // this is pointer to the column definition, located in the array struct table::columns - char *cell_content; // content of the cell of the current row + const char *cell_content; // content of the cell of the current row int next_column; // index of next column in linked list of columns of the same type - int output_type; // format of this column + enum xtype_fmt output_type; // format of this column }; /** @@ -199,35 +209,35 @@ struct table { ***/ #define TBL_COL_LIST_INIT .first_column = -1 -#define TBL_COL_STR(_name, _width) { .name = _name, .width = _width, .fmt = "%s", .type = COL_TYPE_STR, TBL_COL_LIST_INIT } -#define TBL_COL_INT(_name, _width) { .name = _name, .width = _width, .fmt = "%d", .type = COL_TYPE_INT, TBL_COL_LIST_INIT } -#define TBL_COL_S64(_name, _width) { .name = _name, .width = _width, .fmt = "%lld", .type = COL_TYPE_S64, TBL_COL_LIST_INIT } -#define TBL_COL_UINT(_name, _width) { .name = _name, .width = _width, .fmt = "%u", .type = COL_TYPE_UINT, TBL_COL_LIST_INIT } -#define TBL_COL_U64(_name, _width) { .name = _name, .width = _width, .fmt = "%llu", .type = COL_TYPE_U64, TBL_COL_LIST_INIT } -#define TBL_COL_INTMAX(_name, _width) { .name = _name, .width = _width, .fmt = "%jd", .type = COL_TYPE_INTMAX, TBL_COL_LIST_INIT } -#define TBL_COL_UINTMAX(_name, _width) { .name = _name, .width = _width, .fmt = "%ju", .type = COL_TYPE_UINTMAX, TBL_COL_LIST_INIT } -#define TBL_COL_HEXUINT(_name, _width) { .name = _name, .width = _width, .fmt = "0x%x", .type = COL_TYPE_UINT, TBL_COL_LIST_INIT } -#define TBL_COL_DOUBLE(_name, _width, _prec) { .name = _name, .width = _width, .fmt = "%." #_prec "lf", .type = COL_TYPE_DOUBLE, TBL_COL_LIST_INIT } -#define TBL_COL_BOOL(_name, _width) { .name = _name, .width = _width, .fmt = "%s", .type = COL_TYPE_BOOL, TBL_COL_LIST_INIT } -#define TBL_COL_ANY(_name, _width) { .name = _name, .width = _width, .fmt = 0, .type = COL_TYPE_ANY, TBL_COL_LIST_INIT } - -#define TBL_COL_STR_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type = COL_TYPE_STR, TBL_COL_LIST_INIT } -#define TBL_COL_INT_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type = COL_TYPE_INT, TBL_COL_LIST_INIT } -#define TBL_COL_S64_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type = COL_TYPE_S64, TBL_COL_LIST_INIT } -#define TBL_COL_UINT_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type = COL_TYPE_UINT, TBL_COL_LIST_INIT } -#define TBL_COL_U64_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type = COL_TYPE_U64, TBL_COL_LIST_INIT } -#define TBL_COL_INTMAX_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type = COL_TYPE_INTMAX, TBL_COL_LIST_INIT } -#define TBL_COL_UINTMAX_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type = COL_TYPE_UINTMAX, TBL_COL_LIST_INIT } -#define TBL_COL_HEXUINT_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type = COL_TYPE_UINT, TBL_COL_LIST_INIT } -#define TBL_COL_BOOL_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type = COL_TYPE_BOOL, TBL_COL_LIST_INIT } - -#define TBL_COL_END { .name = 0, .width = 0, .fmt = 0, .type = COL_TYPE_LAST } +#define TBL_COL_STR(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = COL_TYPE_STR, TBL_COL_LIST_INIT } +#define TBL_COL_INT(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = COL_TYPE_INT, TBL_COL_LIST_INIT } +#define TBL_COL_S64(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = COL_TYPE_S64, TBL_COL_LIST_INIT } +#define TBL_COL_UINT(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = COL_TYPE_UINT, TBL_COL_LIST_INIT } +#define TBL_COL_U64(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = COL_TYPE_U64, TBL_COL_LIST_INIT } +#define TBL_COL_INTMAX(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = COL_TYPE_INTMAX, TBL_COL_LIST_INIT } +#define TBL_COL_UINTMAX(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = COL_TYPE_UINTMAX, TBL_COL_LIST_INIT } +#define TBL_COL_HEXUINT(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = COL_TYPE_UINT, TBL_COL_LIST_INIT } +#define TBL_COL_DOUBLE(_name, _width, _prec) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = COL_TYPE_DOUBLE, TBL_COL_LIST_INIT } +#define TBL_COL_BOOL(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = COL_TYPE_BOOL, TBL_COL_LIST_INIT } +#define TBL_COL_ANY(_name, _width) { .name = _name, .width = _width, .fmt = XTYPE_FMT_DEFAULT, .type_def = COL_TYPE_ANY, TBL_COL_LIST_INIT } + +#define TBL_COL_STR_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = COL_TYPE_STR, TBL_COL_LIST_INIT } +#define TBL_COL_INT_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = COL_TYPE_INT, TBL_COL_LIST_INIT } +#define TBL_COL_S64_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = COL_TYPE_S64, TBL_COL_LIST_INIT } +#define TBL_COL_UINT_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = COL_TYPE_UINT, TBL_COL_LIST_INIT } +#define TBL_COL_U64_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = COL_TYPE_U64, TBL_COL_LIST_INIT } +#define TBL_COL_INTMAX_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = COL_TYPE_INTMAX, TBL_COL_LIST_INIT } +#define TBL_COL_UINTMAX_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = COL_TYPE_UINTMAX, TBL_COL_LIST_INIT } +#define TBL_COL_HEXUINT_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = COL_TYPE_UINT, TBL_COL_LIST_INIT } +#define TBL_COL_BOOL_FMT(_name, _width, _fmt) { .name = _name, .width = _width, .fmt = _fmt, .type_def = COL_TYPE_BOOL, TBL_COL_LIST_INIT } + +#define TBL_COL_END { .name = 0, .width = 0, .fmt = 0, .type_def = NULL } #define TBL_COLUMNS .columns = (struct table_column []) #define TBL_COL_ORDER(order) .column_order = (struct table_col_instance *) order, .cols_to_output = ARRAY_SIZE(order) #define TBL_COL_DELIMITER(_delimiter_) .col_delimiter = _delimiter_ -#define TBL_COL(_idx) { .idx = _idx, .output_type = CELL_OUT_UNINITIALIZED, .next_column = -1 } -#define TBL_COL_FMT(_idx, _fmt) { .idx = _idx, .output_type = CELL_OUT_UNINITIALIZED, .next_column = -1, .fmt = _fmt } +#define TBL_COL(_idx) { .idx = _idx, .output_type = XTYPE_FMT_DEFAULT, .next_column = -1 } +#define TBL_COL_FMT(_idx, _fmt) { .idx = _idx, .output_type = XTYPE_FMT_DEFAULT, .next_column = -1, .fmt = _fmt } #define TBL_COL_TYPE(_idx, _type) { .idx = _idx, .output_type = _type, .next_column = -1 } #define TBL_OUTPUT_HUMAN_READABLE .formatter = &table_fmt_human_readable @@ -281,7 +291,7 @@ void table_end(struct table *tbl); #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, const char *fmt, _type_ val) FORMAT_CHECK(printf, 3, 0); + void table_col_##_name_##_fmt(struct table *tbl, int col, enum xtype_fmt fmt, _type_ val); // table_col__fmt has one disadvantage: it is not possible to // check whether fmt contains format that contains formatting that is @@ -295,10 +305,11 @@ TABLE_COL_PROTO(intmax, intmax_t); TABLE_COL_PROTO(uintmax, uintmax_t); TABLE_COL_PROTO(s64, s64); TABLE_COL_PROTO(u64, u64); +TABLE_COL_PROTO(bool, bool); -void table_col_bool(struct table *tbl, int col, bool val); -void table_col_bool_name(struct table *tbl, const char *col_name, bool val); -void table_col_bool_fmt(struct table *tbl, int col, const char *fmt, bool val); +//void table_col_bool(struct table *tbl, int col, bool val); +//void table_col_bool_name(struct table *tbl, const char *col_name, bool val); +//void table_col_bool_fmt(struct table *tbl, int col, enum xtype_fmt fmt, bool val); #undef TABLE_COL_PROTO /** diff --git a/ucw/xtypes-basic.c b/ucw/xtypes-basic.c index f17fc4e5..5ddb359d 100644 --- a/ucw/xtypes-basic.c +++ b/ucw/xtypes-basic.c @@ -11,20 +11,139 @@ #include #include #include +#include +#include -static const char *xt_int_parse(const char *str, void *dest, struct mempool *pool UNUSED) +#define XTYPE_NUM_FORMAT(_type, _fmt, _typename) static const char *xt_##_typename##_format(void *src, u32 fmt UNUSED, struct mempool *pool) \ +{\ + return mp_printf(pool, _fmt, *(_type *)src);\ +} + +#define XTYPE_NUM_PARSE(_typename) static const char *xt_##_typename##_parse(const char *str, void *dest, struct mempool *pool UNUSED)\ +{\ + return str_to_##_typename(dest, str, NULL, 10 | STN_WHOLE | STN_MINUS | STN_PLUS | STN_HEX | STN_BIN | STN_OCT);\ +} + +#define XTYPE_NUM_STRUCT(_type, _typename) const struct xtype xt_##_typename = {\ + .size = sizeof(_type),\ + .name = #_typename,\ + .parse = xt_##_typename##_parse,\ + .format = xt_##_typename##_format,\ +}; + + +#define XTYPE_NUM_DEF(_type, _fmt, _typename) XTYPE_NUM_FORMAT(_type, _fmt, _typename) \ + XTYPE_NUM_PARSE(_typename)\ + XTYPE_NUM_STRUCT(_type, _typename) + +XTYPE_NUM_DEF(int, "%d", int) +XTYPE_NUM_DEF(s64, "%ld", s64) +XTYPE_NUM_DEF(intmax_t, "%jd", intmax) +XTYPE_NUM_DEF(uint, "%u", uint) +XTYPE_NUM_DEF(u64, "%lu", u64) +XTYPE_NUM_DEF(uintmax_t, "%ju", uintmax) + +/* double */ + +static const char *xt_double_format(void *src, u32 fmt, struct mempool *pool) +{ + switch(fmt) { + case XTYPE_FMT_RAW: + return mp_printf(pool, "%.2lf", *(double *)src); + case XTYPE_FMT_PRETTY: + return mp_printf(pool, "%.2lf", *(double *)src); + + case XTYPE_FMT_DEFAULT: + default: + return mp_printf(pool, "%.2lf", *(double *)src); + } +} + +static const char *xt_double_parse(const char *str, void *dest, struct mempool *pool UNUSED) +{ + char *endptr = NULL; + errno = 0; + double result = strtod(str, &endptr); + size_t sz = strlen(str); + if(endptr != str + sz) return "Could not parse double."; + if(errno == ERANGE) return "Could not parse double: overflow happend during parsing"; + + *((double *) dest) = result; + + return NULL; +} + +const struct xtype xt_double = { + .size = sizeof(double), + .name = "double", + .parse = xt_double_parse, + .format = xt_double_format, +}; + +/* bool */ + +static const char *xt_bool_format(void *src, u32 fmt UNUSED, struct mempool *pool) // (struct table *tbl, int col, enum xtype_fmt fmt, bool val) +{ + switch(fmt) { + case XTYPE_FMT_DEFAULT: + case XTYPE_FMT_PRETTY: + return mp_printf(pool, "%s", *((bool *)src) ? "true" : "false"); + case XTYPE_FMT_RAW: + return mp_printf(pool, "%s", *((bool *)src) ? "1" : "0"); + default: + die("Unsupported output type."); + } +} + +static const char *xt_bool_parse(const char *str, void *dest, struct mempool *pool UNUSED) +{ + if(str[1] == 0) { + if(str[0] == '1') { + *((bool *)dest) = false; + return NULL; + } + if(str[0] == '1') { + *((bool *)dest) = true; + return NULL; + } + } + + if(strcasecmp(str, "false") == 0) { + *((bool *)dest) = false; + return NULL; + } + + if(strcasecmp(str, "true") == 0) { + *((bool *)dest) = true; + return NULL; + } + + return "Could not parse bool."; +} + +const struct xtype xt_bool = { + .size = sizeof(bool), + .name = "bool", + .parse = xt_bool_parse, + .format = xt_bool_format, +}; + + +/* str */ +static const char *xt_str_format(void *src, u32 fmt UNUSED, struct mempool *pool) // (struct table *tbl, int col, enum xtype_fmt fmt, bool val) { - return str_to_int(dest, str, NULL, 10 | STN_WHOLE | STN_MINUS | STN_PLUS | STN_HEX | STN_BIN | STN_OCT); + return mp_printf(pool, "%s", *((char **) src)); } -static const char *xt_int_format(void *src, u32 fmt UNUSED, struct mempool *pool) +static const char *xt_str_parse(const char *str, void *dest, struct mempool *pool UNUSED) { - return mp_printf(pool, "%d", *(int *)src); + *((const char **) dest) = str; + return NULL; } -const struct xtype xt_int = { - .size = sizeof(int), - .name = "int", - .parse = xt_int_parse, - .format = xt_int_format, +const struct xtype xt_str = { + .size = sizeof(char *), + .name = "str", + .parse = xt_str_parse, + .format = xt_str_format, }; diff --git a/ucw/xtypes.h b/ucw/xtypes.h index c06b3a22..380524e8 100644 --- a/ucw/xtypes.h +++ b/ucw/xtypes.h @@ -88,6 +88,14 @@ const char *xtype_parse_fmt(struct xtype *xt, const char *str, u32 *dest, struct const char *xtype_format_fmt(struct xtype *xt, u32 fmt, struct mempool *pool); // Basic set of extended types +extern const struct xtype xt_str; extern const struct xtype xt_int; +extern const struct xtype xt_s64; +extern const struct xtype xt_intmax; +extern const struct xtype xt_uint; +extern const struct xtype xt_u64; +extern const struct xtype xt_uintmax; +extern const struct xtype xt_bool; +extern const struct xtype xt_double; #endif -- 2.39.2