X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ucw%2Ftable-types.c;h=1894a9a6daddf673b929461bc69ee7b3eeac75a9;hb=7f0dc8b815a7d0e0f66e82b55114c89793babf69;hp=ab2e5b696ab9f0542b72924f1d4159379d0f7cff;hpb=d9656daa5fad2bd5e7ef0de655aa94ac0eea9035;p=libucw.git diff --git a/ucw/table-types.c b/ucw/table-types.c index ab2e5b69..1894a9a6 100644 --- a/ucw/table-types.c +++ b/ucw/table-types.c @@ -1,158 +1,200 @@ +/* + * UCW Library -- Table printer types + * + * (c) 2014 Robert Kessl + */ + #include -#include #include #include -#include #include #include #include #include - -static const char *unit_suffix[] = { - [UNIT_BYTE] = "", - [UNIT_KILOBYTE] = "KB", - [UNIT_MEGABYTE] = "MB", - [UNIT_GIGABYTE] = "GB", - [UNIT_TERABYTE] = "TB" +#include +#include + +/** xt_size **/ + +static struct unit_definition xtype_units_size[] = { + [SIZE_UNIT_BYTE] = { "", 1LLU, 1 }, + [SIZE_UNIT_KILOBYTE] = { "KB", 1024LLU, 1 }, + [SIZE_UNIT_MEGABYTE] = { "MB", 1024LLU * 1024LLU, 1 }, + [SIZE_UNIT_GIGABYTE] = { "GB", 1024LLU * 1024LLU * 1024LLU, 1 }, + [SIZE_UNIT_TERABYTE] = { "TB", 1024LLU * 1024LLU * 1024LLU * 1024LLU, 1 }, + { 0, 0, 0 } }; -static bool table_set_col_opt_size(struct table *tbl, uint col_copy_idx, const char *col_arg, char **err) +static const char *xt_size_format(void *src, u32 fmt, struct mempool *pool) { - int col_type_idx = tbl->column_order[col_copy_idx].idx; - if(tbl->columns[col_type_idx].type != COL_TYPE_SIZE) { - *err = NULL; - return false; + u64 curr_val = *(u64*) src; + + if(fmt == XTYPE_FMT_RAW) { + return mp_printf(pool, "%"PRIu64, curr_val); } - if(col_arg == NULL) { - *err = NULL; - return true; + uint out_units = SIZE_UNIT_BYTE; + + if(fmt == XTYPE_FMT_DEFAULT) { + curr_val = curr_val; + out_units = SIZE_UNIT_BYTE; + } else if(fmt == XTYPE_FMT_PRETTY) { + curr_val = curr_val; + out_units = SIZE_UNIT_BYTE; + } else if((fmt & SIZE_UNITS_FIXED) != 0) { + curr_val = curr_val / xtype_units_size[fmt & ~SIZE_UNITS_FIXED].num; + out_units = fmt & ~SIZE_UNITS_FIXED; } - if(strcasecmp(col_arg, "b") == 0 || strcasecmp(col_arg, "bytes") == 0) { - tbl->column_order[col_copy_idx].output_type = UNIT_BYTE; + return mp_printf(pool, "%"PRIu64"%s", curr_val, xtype_units_size[out_units].unit); +} + +static const char *xt_size_fmt_parse(const char *opt_str, u32 *dest, struct mempool *pool) +{ + if(opt_str == NULL) { + return "NULL is not supported as a column argument."; } - tbl->column_order[col_copy_idx].output_type = CELL_OUT_UNINITIALIZED; - for(uint i = 0; i < ARRAY_SIZE(unit_suffix); i++) { - if(strcasecmp(col_arg, unit_suffix[i]) == 0) { - tbl->column_order[col_copy_idx].output_type = i; - } + if(strlen(opt_str) == 0 || strcmp(opt_str, "B") == 0 || strcmp(opt_str, "Bytes") == 0) { + *dest = SIZE_UNIT_BYTE | SIZE_UNITS_FIXED; + return NULL; } - if(tbl->column_order[col_copy_idx].output_type == CELL_OUT_UNINITIALIZED) { - *err = mp_printf(tbl->pool, "Tableprinter: invalid column format option: '%s' for column %d (counted from 0)", col_arg, col_copy_idx); - return true; + int unit_idx = xtype_unit_parser(opt_str, xtype_units_size); + if(unit_idx == -1) { + return mp_printf(pool, "Unknown option '%s'", opt_str); } - *err = NULL; - return true; + *dest = unit_idx | SIZE_UNITS_FIXED; + return NULL; } -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_copy_idx, const char *col_arg, char **err) +static const char *xt_size_parse(const char *str, void *dest, struct mempool *pool) { - int col_type_idx = tbl->column_order[col_copy_idx].idx; - if(tbl->columns[col_type_idx].type != COL_TYPE_TIMESTAMP) { - *err = NULL; - return false; + errno = 0; + char *units_start = NULL; + u64 parsed = strtoul(str, &units_start, 10); + if(str == units_start) { + return mp_printf(pool, "Invalid value of size: '%s'.", str); + } + + if(errno == EINVAL) { + return "Error occured during parsing of size."; + } + if(errno == ERANGE) { + return "Error: size value either too large or too small."; } - if(col_arg == NULL) { - *err = NULL; - return true; + if(*units_start == 0) { + *(u64*) dest = (u64) parsed; + return NULL; } - if(strcasecmp(col_arg, "timestamp") == 0 || strcasecmp(col_arg, "epoch") == 0) { - tbl->column_order[col_copy_idx].output_type = TIMESTAMP_EPOCH; - } else if(strcasecmp(col_arg, "datetime") == 0) { - tbl->column_order[col_copy_idx].output_type = TIMESTAMP_DATETIME; - } else { - *err = mp_printf(tbl->pool, "Tableprinter: invalid column format option: '%s' for column %d.", col_arg, col_copy_idx); - return true; + int unit_idx = xtype_unit_parser(units_start, xtype_units_size); + if(unit_idx == -1) { + return mp_printf(pool, "Invalid units: '%s'.", units_start); } - *err = NULL; - return true; + *(u64*) dest = parsed * xtype_units_size[unit_idx].num; + return NULL; } -struct table_user_type table_type_timestamp = { - .set_col_instance_option = table_set_col_opt_timestamp, - .type = COL_TYPE_TIMESTAMP, +TABLE_COL_BODY(size, u64) + +const struct xtype xt_size = { + .size = sizeof(u64), + .name = "size", + .parse = xt_size_parse, + .format = xt_size_format, + .parse_fmt = xt_size_fmt_parse }; -void table_col_size_name(struct table *tbl, const char *col_name, u64 val) +/** xt_timestamp **/ + +#define FORMAT_TIME_SIZE 20 // Minimum buffer size + +static const char *xt_timestamp_format(void *src, u32 fmt, struct mempool *pool) { - int col = table_get_col_idx(tbl, col_name); - table_col_size(tbl, col, val); + char formatted_time_buf[FORMAT_TIME_SIZE] = { 0 }; + + u64 tmp_time_u64 = *(u64*)src; + time_t tmp_time = (time_t) tmp_time_u64; + struct tm t = *gmtime(&tmp_time); + switch (fmt) { + case XTYPE_FMT_DEFAULT: + case XTYPE_FMT_RAW: + sprintf(formatted_time_buf, "%"PRIu64, tmp_time_u64); + break; + case XTYPE_FMT_PRETTY: + strftime(formatted_time_buf, FORMAT_TIME_SIZE, "%F %T", &t); + break; + default: + ASSERT(0); + break; + } + + return mp_printf(pool, "%s", formatted_time_buf); } -void table_col_size(struct table *tbl, int col, u64 val) +static const char *xt_timestamp_fmt_parse(const char *opt_str, u32 *dest, struct mempool *pool) { - 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) 1024LLU, - [UNIT_MEGABYTE] = (u64) (1024LLU * 1024LLU), - [UNIT_GIGABYTE] = (u64) (1024LLU * 1024LLU * 1024LLU), - [UNIT_TERABYTE] = (u64) (1024LLU * 1024LLU * 1024LLU * 1024LLU) - }; - - TBL_COL_ITER(tbl, col, curr_col, curr_col_idx) { - // FIXME: do some rounding? - uint out_type = 0; - if(curr_col->output_type == CELL_OUT_UNINITIALIZED) { - val = val / unit_div[UNIT_BYTE]; - out_type = 0; - } else { - val = val / unit_div[curr_col->output_type]; - out_type = curr_col->output_type; - } - - curr_col->cell_content = mp_printf(tbl->pool, "%lu%s", val, unit_suffix[out_type]); + if(opt_str == NULL) { + return "NULL is not supported as a column argument."; } -} -#define FORMAT_TIME_SIZE 20 // Minimum buffer size + if(strcasecmp(opt_str, "timestamp") == 0 || strcasecmp(opt_str, "epoch") == 0) { + *dest = TIMESTAMP_EPOCH; + return NULL; + } else if(strcasecmp(opt_str, "datetime") == 0) { + *dest = TIMESTAMP_DATETIME; + return NULL; + } -void table_col_timestamp_name(struct table *tbl, const char * col_name, u64 val) -{ - int col = table_get_col_idx(tbl, col_name); - table_col_size(tbl, col, val); + return mp_printf(pool, "Invalid column format option: '%s'.", opt_str); } -void table_col_timestamp(struct table *tbl, int col, u64 val) +static const char *xt_timestamp_parse(const char *str, void *dest, struct mempool *pool) { - 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); + errno = 0; + char *parse_end = NULL; + u64 parsed = strtoul(str, &parse_end, 10); + if(str == parse_end) { + return mp_printf(pool, "Invalid value of timestamp: '%s'.", str); + } + if(errno == EINVAL) { + return "Error occured during parsing of size."; + } - char formatted_time_buf[FORMAT_TIME_SIZE] = { 0 }; + if(errno == ERANGE) { + return "Error: size value either too large or too small."; + } - time_t tmp_time = (time_t)val; - struct tm t = *gmtime(&tmp_time); - TBL_COL_ITER(tbl, col, curr_col, curr_col_idx) { - switch (curr_col->output_type) { - case TIMESTAMP_EPOCH: - case CELL_OUT_UNINITIALIZED: - sprintf(formatted_time_buf, "%lu", val); - break; - case TIMESTAMP_DATETIME: - strftime(formatted_time_buf, FORMAT_TIME_SIZE, "%F %T", &t); - break; - default: - abort(); - break; - } + if(*parse_end == 0) { + *(u64*) dest = (u64) parsed; + return NULL; + } - curr_col->cell_content = mp_printf(tbl->pool, "%s", formatted_time_buf); + struct tm parsed_time; + parse_end = strptime(str, "%F %T", &parsed_time); + if(parse_end == NULL) { + return mp_printf(pool, "Invalid value of timestamp: '%s'.", str); + } + if(*parse_end != 0) { + return mp_printf(pool, "Invalid value of timestamp: '%s'.", str); } + + time_t tmp_time = mktime(&parsed_time); + *(u64*)dest = (u64) tmp_time; + + return NULL; } + +TABLE_COL_BODY(timestamp, u64) + +const struct xtype xt_timestamp = { + .size = sizeof(u64), + .name = "timestamp", + .parse = xt_timestamp_parse, + .format = xt_timestamp_format, + .parse_fmt = xt_timestamp_fmt_parse +};