]> mj.ucw.cz Git - libucw.git/blob - ucw/table-types.c
xtypes&tableprinter: added parsing of size and tests
[libucw.git] / ucw / table-types.c
1 /*
2  *      UCW Library -- Table printer types
3  *
4  *      (c) 2014 Robert Kessl <robert.kessl@economia.cz>
5  */
6
7 #include <ucw/lib.h>
8 #include <ucw/table-types.h>
9 #include <ucw/fastbuf.h>
10 #include <ucw/table.h>
11 #include <time.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <inttypes.h>
15 #include <errno.h>
16
17 /** xt_size **/
18
19 static const char *unit_suffix[] = {
20   [SIZE_UNIT_BYTE] = "",
21   [SIZE_UNIT_KILOBYTE] = "KB",
22   [SIZE_UNIT_MEGABYTE] = "MB",
23   [SIZE_UNIT_GIGABYTE] = "GB",
24   [SIZE_UNIT_TERABYTE] = "TB"
25 };
26
27 static u64 unit_div[] = {
28   [SIZE_UNIT_BYTE] = 1LLU,
29   [SIZE_UNIT_KILOBYTE] = 1024LLU,
30   [SIZE_UNIT_MEGABYTE] = 1024LLU * 1024LLU,
31   [SIZE_UNIT_GIGABYTE] = 1024LLU * 1024LLU * 1024LLU,
32   [SIZE_UNIT_TERABYTE] = 1024LLU * 1024LLU * 1024LLU * 1024LLU
33 };
34
35 static const char *xt_size_format(void *src, u32 fmt, struct mempool *pool)
36 {
37   u64 curr_val = *(u64*) src;
38
39   if(fmt == XTYPE_FMT_RAW) {
40     return mp_printf(pool, "%"PRIu64, curr_val);
41   }
42
43   uint out_type = SIZE_UNIT_BYTE;
44
45   if(fmt == XTYPE_FMT_DEFAULT) {
46     curr_val = curr_val / unit_div[SIZE_UNIT_BYTE];
47     out_type = SIZE_UNIT_BYTE;
48   } else if(fmt == XTYPE_FMT_PRETTY) {
49     curr_val = curr_val / unit_div[SIZE_UNIT_BYTE];
50     out_type = SIZE_UNIT_BYTE;
51   } else if((fmt & SIZE_UNITS_FIXED) != 0) {
52     curr_val = curr_val / unit_div[fmt & ~SIZE_UNITS_FIXED];
53     out_type = fmt & ~SIZE_UNITS_FIXED;
54   }
55
56   return mp_printf(pool, "%"PRIu64"%s", curr_val, unit_suffix[out_type]);
57 }
58
59 static const char * xt_size_fmt_parse(const char *opt_str, u32 *dest, struct mempool *pool UNUSED)
60 {
61   if(opt_str == NULL) {
62     return "NULL is not supported as a column argument.";
63   }
64
65   if(strlen(opt_str) == 0 || strcasecmp(opt_str, "b") == 0 || strcasecmp(opt_str, "bytes") == 0) {
66     *dest = SIZE_UNIT_BYTE | SIZE_UNITS_FIXED;
67     return NULL;
68   }
69
70   for(uint i = SIZE_UNIT_BYTE; i <= SIZE_UNIT_TERABYTE; i++) {
71     if(strcasecmp(opt_str, unit_suffix[i]) == 0) {
72       *dest = i | SIZE_UNITS_FIXED;
73       return NULL;
74     }
75   }
76
77   return "Unknown option.";
78 }
79
80 static const char *xt_size_parse(const char *str, void *dest, struct mempool *pool UNUSED)
81 {
82   errno = 0;
83   char *units_start = NULL;
84   u64 parsed = strtol(str, &units_start, 10);
85   if(str == units_start) {
86     return mp_printf(pool, "Invalid value of size: '%s'.", str);
87   }
88   if(*units_start == 0) {
89     *(u64*) dest = (u64) parsed;
90     return NULL;
91   }
92
93   if(errno == EINVAL || errno == ERANGE) {
94     return mp_printf(pool, "Invalid value of size: '%s'.", str);
95   }
96
97   for(uint i = 0; i < ARRAY_SIZE(unit_suffix); i++) {
98     if(strcmp(unit_suffix[i], units_start) == 0) {
99       *(u64*) dest = parsed * unit_div[i];
100       return NULL;
101     }
102   }
103
104   return mp_printf(pool, "Invalid format of size: '%s'.", str);
105 }
106
107 TABLE_COL_BODY(size, u64)
108
109 const struct xtype xt_size = {
110   .size = sizeof(u64),
111   .name = "size",
112   .parse = xt_size_parse,
113   .format = xt_size_format,
114   .parse_fmt = xt_size_fmt_parse
115 };
116
117 /** xt_timestamp **/
118
119 #define FORMAT_TIME_SIZE 20     // Minimum buffer size
120
121 static const char *xt_timestamp_format(void *src, u32 fmt, struct mempool *pool)
122 {
123   char formatted_time_buf[FORMAT_TIME_SIZE] = { 0 };
124
125   u64 tmp_time_u64 = *(u64*)src;
126   time_t tmp_time = (time_t) tmp_time_u64;
127   struct tm t = *gmtime(&tmp_time);
128   switch (fmt) {
129   case XTYPE_FMT_DEFAULT:
130   case XTYPE_FMT_RAW:
131     sprintf(formatted_time_buf, "%"PRIu64, tmp_time_u64);
132     break;
133   case XTYPE_FMT_PRETTY:
134     strftime(formatted_time_buf, FORMAT_TIME_SIZE, "%F %T", &t);
135     break;
136   default:
137     ASSERT(0);
138     break;
139   }
140
141   return mp_printf(pool, "%s", formatted_time_buf);
142 }
143
144 static const char * xt_timestamp_fmt_parse(const char *opt_str, u32 *dest, struct mempool *pool)
145 {
146   if(opt_str == NULL) {
147     return "NULL is not supported as a column argument.";
148   }
149
150   if(strcasecmp(opt_str, "timestamp") == 0 || strcasecmp(opt_str, "epoch") == 0) {
151     *dest = TIMESTAMP_EPOCH;
152     return NULL;
153   } else if(strcasecmp(opt_str, "datetime") == 0) {
154     *dest = TIMESTAMP_DATETIME;
155     return NULL;
156   }
157
158   return mp_printf(pool, "Invalid column format option: '%s'.", opt_str);
159 }
160
161 TABLE_COL_BODY(timestamp, u64)
162
163 const struct xtype xt_timestamp = {
164   .size = sizeof(u64),
165   .name = "timestamp",
166   //.parse = xt_timestamp_parse,
167   .format = xt_timestamp_format,
168   .parse_fmt = xt_timestamp_fmt_parse
169 };