X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ucw%2Ftable-types.c;h=1894a9a6daddf673b929461bc69ee7b3eeac75a9;hb=7f0dc8b815a7d0e0f66e82b55114c89793babf69;hp=bea583a720ac45f3cbb940791acb2e3b6fd37c8f;hpb=7bd1bf513e4047f2314807ad3f65c0b4ed383328;p=libucw.git diff --git a/ucw/table-types.c b/ucw/table-types.c index bea583a7..1894a9a6 100644 --- a/ucw/table-types.c +++ b/ucw/table-types.c @@ -1,3 +1,9 @@ +/* + * UCW Library -- Table printer types + * + * (c) 2014 Robert Kessl + */ + #include #include #include @@ -5,72 +11,92 @@ #include #include #include +#include +#include /** xt_size **/ -static const char *unit_suffix[] = { - [SIZE_UNIT_BYTE] = "", - [SIZE_UNIT_KILOBYTE] = "KB", - [SIZE_UNIT_MEGABYTE] = "MB", - [SIZE_UNIT_GIGABYTE] = "GB", - [SIZE_UNIT_TERABYTE] = "TB" +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 const char *xt_size_format(void *src, u32 fmt, struct mempool *pool) { u64 curr_val = *(u64*) src; - uint out_type = 0; - - static u64 unit_div[] = { - [SIZE_UNIT_BYTE] = (u64) 1, - [SIZE_UNIT_KILOBYTE] = (u64) 1024LLU, - [SIZE_UNIT_MEGABYTE] = (u64) (1024LLU * 1024LLU), - [SIZE_UNIT_GIGABYTE] = (u64) (1024LLU * 1024LLU * 1024LLU), - [SIZE_UNIT_TERABYTE] = (u64) (1024LLU * 1024LLU * 1024LLU * 1024LLU) - }; - - if(fmt == XTYPE_FMT_DEFAULT || fmt == XTYPE_FMT_RAW) { - curr_val = curr_val / unit_div[SIZE_UNIT_BYTE]; - out_type = SIZE_UNIT_BYTE; + + if(fmt == XTYPE_FMT_RAW) { + return mp_printf(pool, "%"PRIu64, curr_val); + } + + 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 / unit_div[SIZE_UNIT_BYTE]; - out_type = SIZE_UNIT_BYTE; + curr_val = curr_val; + out_units = SIZE_UNIT_BYTE; } else if((fmt & SIZE_UNITS_FIXED) != 0) { - curr_val = curr_val / unit_div[fmt & ~SIZE_UNITS_FIXED]; - out_type = fmt & ~SIZE_UNITS_FIXED; + curr_val = curr_val / xtype_units_size[fmt & ~SIZE_UNITS_FIXED].num; + out_units = fmt & ~SIZE_UNITS_FIXED; } - return mp_printf(pool, "%lu%s", curr_val, unit_suffix[out_type]); + return mp_printf(pool, "%"PRIu64"%s", curr_val, xtype_units_size[out_units].unit); } -bool table_set_col_opt_size(struct table *tbl, uint col_inst_idx, const char *col_arg, char **err) +static const char *xt_size_fmt_parse(const char *opt_str, u32 *dest, struct mempool *pool) { - struct table_column *col_def = tbl->column_order[col_inst_idx].col_def; - if(col_def->type_def != COL_TYPE_SIZE) { - *err = NULL; - return false; + if(opt_str == NULL) { + return "NULL is not supported as a column argument."; + } + + 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(col_arg == NULL || strcasecmp(col_arg, "b") == 0 || strcasecmp(col_arg, "bytes") == 0) { - tbl->column_order[col_inst_idx].output_type = SIZE_UNIT_BYTE | SIZE_UNITS_FIXED; - *err = NULL; - 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); } - 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 | SIZE_UNITS_FIXED; - } + *dest = unit_idx | SIZE_UNITS_FIXED; + return NULL; +} + +static const char *xt_size_parse(const char *str, void *dest, struct mempool *pool) +{ + 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(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; + if(errno == EINVAL) { + return "Error occured during parsing of size."; + } + if(errno == ERANGE) { + return "Error: size value either too large or too small."; } - *err = NULL; - return true; + if(*units_start == 0) { + *(u64*) dest = (u64) parsed; + return NULL; + } + + int unit_idx = xtype_unit_parser(units_start, xtype_units_size); + if(unit_idx == -1) { + return mp_printf(pool, "Invalid units: '%s'.", units_start); + } + + *(u64*) dest = parsed * xtype_units_size[unit_idx].num; + return NULL; } TABLE_COL_BODY(size, u64) @@ -78,67 +104,97 @@ TABLE_COL_BODY(size, u64) const struct xtype xt_size = { .size = sizeof(u64), .name = "size", - //.parse = xt_size_parse, + .parse = xt_size_parse, .format = xt_size_format, + .parse_fmt = xt_size_fmt_parse }; /** xt_timestamp **/ #define FORMAT_TIME_SIZE 20 // Minimum buffer size -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_def != COL_TYPE_TIMESTAMP) { - *err = NULL; - return false; - } - - if(col_arg == NULL) { - *err = NULL; - return true; - } - - if(strcasecmp(col_arg, "timestamp") == 0 || strcasecmp(col_arg, "epoch") == 0) { - tbl->column_order[col_inst_idx].output_type = TIMESTAMP_EPOCH; - } else if(strcasecmp(col_arg, "datetime") == 0) { - tbl->column_order[col_inst_idx].output_type = TIMESTAMP_DATETIME; - } else { - *err = mp_printf(tbl->pool, "Invalid column format option: '%s' for column %d.", col_arg, col_inst_idx); - return true; - } - - *err = NULL; - return true; -} - static const char *xt_timestamp_format(void *src, u32 fmt, struct mempool *pool) { char formatted_time_buf[FORMAT_TIME_SIZE] = { 0 }; - time_t tmp_time = *(time_t*)src; + 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, "%lu", tmp_time); + 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: - abort(); + ASSERT(0); break; } return mp_printf(pool, "%s", formatted_time_buf); } +static const char *xt_timestamp_fmt_parse(const char *opt_str, u32 *dest, struct mempool *pool) +{ + if(opt_str == NULL) { + return "NULL is not supported as a column argument."; + } + + 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; + } + + return mp_printf(pool, "Invalid column format option: '%s'.", opt_str); +} + +static const char *xt_timestamp_parse(const char *str, void *dest, struct mempool *pool) +{ + 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."; + } + + if(errno == ERANGE) { + return "Error: size value either too large or too small."; + } + + if(*parse_end == 0) { + *(u64*) dest = (u64) parsed; + return NULL; + } + + 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, + .parse = xt_timestamp_parse, .format = xt_timestamp_format, + .parse_fmt = xt_timestamp_fmt_parse };