]> mj.ucw.cz Git - libucw.git/blob - ucw/table-types.c
tableprinter: size units are now static
[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 struct unit_definition xtype_units_size[] = {
20   [SIZE_UNIT_BYTE] = { "", 1LLU, 1 },
21   [SIZE_UNIT_KILOBYTE] = { "KB", 1024LLU, 1 },
22   [SIZE_UNIT_MEGABYTE] = { "MB", 1024LLU * 1024LLU, 1 },
23   [SIZE_UNIT_GIGABYTE] = { "GB", 1024LLU * 1024LLU * 1024LLU, 1 },
24   [SIZE_UNIT_TERABYTE] = { "TB", 1024LLU * 1024LLU * 1024LLU * 1024LLU, 1 },
25   { 0, 0, 0 }
26 };
27
28 static const char *xt_size_format(void *src, u32 fmt, struct mempool *pool)
29 {
30   u64 curr_val = *(u64*) src;
31
32   if(fmt == XTYPE_FMT_RAW) {
33     return mp_printf(pool, "%"PRIu64, curr_val);
34   }
35
36   uint out_units = SIZE_UNIT_BYTE;
37
38   if(fmt == XTYPE_FMT_DEFAULT) {
39     curr_val = curr_val;
40     out_units = SIZE_UNIT_BYTE;
41   } else if(fmt == XTYPE_FMT_PRETTY) {
42     curr_val = curr_val;
43     out_units = SIZE_UNIT_BYTE;
44   } else if((fmt & SIZE_UNITS_FIXED) != 0) {
45     curr_val = curr_val / xtype_units_size[fmt & ~SIZE_UNITS_FIXED].num;
46     out_units = fmt & ~SIZE_UNITS_FIXED;
47   }
48
49   return mp_printf(pool, "%"PRIu64"%s", curr_val, xtype_units_size[out_units].unit);
50 }
51
52 static const char *xt_size_fmt_parse(const char *opt_str, u32 *dest, struct mempool *pool)
53 {
54   if(opt_str == NULL) {
55     return "NULL is not supported as a column argument.";
56   }
57
58   if(strlen(opt_str) == 0 || strcmp(opt_str, "B") == 0 || strcmp(opt_str, "Bytes") == 0) {
59     *dest = SIZE_UNIT_BYTE | SIZE_UNITS_FIXED;
60     return NULL;
61   }
62
63   int unit_idx = xtype_unit_parser(opt_str, xtype_units_size);
64   if(unit_idx == -1) {
65     return mp_printf(pool, "Unknown option '%s'", opt_str);
66   }
67
68   *dest = unit_idx | SIZE_UNITS_FIXED;
69   return NULL;
70 }
71
72 static const char *xt_size_parse(const char *str, void *dest, struct mempool *pool)
73 {
74   errno = 0;
75   char *units_start = NULL;
76   u64 parsed = strtoul(str, &units_start, 10);
77   if(str == units_start) {
78     return mp_printf(pool, "Invalid value of size: '%s'.", str);
79   }
80
81   if(errno == EINVAL) {
82     return "Error occured during parsing of size.";
83   }
84   if(errno == ERANGE) {
85     return "Error: size value either too large or too small.";
86   }
87
88   if(*units_start == 0) {
89     *(u64*) dest = (u64) parsed;
90     return NULL;
91   }
92
93   int unit_idx = xtype_unit_parser(units_start, xtype_units_size);
94   if(unit_idx == -1) {
95     return mp_printf(pool, "Invalid units: '%s'.", units_start);
96   }
97
98   *(u64*) dest = parsed * xtype_units_size[unit_idx].num;
99   return NULL;
100 }
101
102 TABLE_COL_BODY(size, u64)
103
104 const struct xtype xt_size = {
105   .size = sizeof(u64),
106   .name = "size",
107   .parse = xt_size_parse,
108   .format = xt_size_format,
109   .parse_fmt = xt_size_fmt_parse
110 };
111
112 /** xt_timestamp **/
113
114 #define FORMAT_TIME_SIZE 20     // Minimum buffer size
115
116 static const char *xt_timestamp_format(void *src, u32 fmt, struct mempool *pool)
117 {
118   char formatted_time_buf[FORMAT_TIME_SIZE] = { 0 };
119
120   u64 tmp_time_u64 = *(u64*)src;
121   time_t tmp_time = (time_t) tmp_time_u64;
122   struct tm t = *gmtime(&tmp_time);
123   switch (fmt) {
124   case XTYPE_FMT_DEFAULT:
125   case XTYPE_FMT_RAW:
126     sprintf(formatted_time_buf, "%"PRIu64, tmp_time_u64);
127     break;
128   case XTYPE_FMT_PRETTY:
129     strftime(formatted_time_buf, FORMAT_TIME_SIZE, "%F %T", &t);
130     break;
131   default:
132     ASSERT(0);
133     break;
134   }
135
136   return mp_printf(pool, "%s", formatted_time_buf);
137 }
138
139 static const char *xt_timestamp_fmt_parse(const char *opt_str, u32 *dest, struct mempool *pool)
140 {
141   if(opt_str == NULL) {
142     return "NULL is not supported as a column argument.";
143   }
144
145   if(strcasecmp(opt_str, "timestamp") == 0 || strcasecmp(opt_str, "epoch") == 0) {
146     *dest = TIMESTAMP_EPOCH;
147     return NULL;
148   } else if(strcasecmp(opt_str, "datetime") == 0) {
149     *dest = TIMESTAMP_DATETIME;
150     return NULL;
151   }
152
153   return mp_printf(pool, "Invalid column format option: '%s'.", opt_str);
154 }
155
156 static const char *xt_timestamp_parse(const char *str, void *dest, struct mempool *pool)
157 {
158   errno = 0;
159   char *parse_end = NULL;
160   u64 parsed = strtoul(str, &parse_end, 10);
161   if(str == parse_end) {
162     return mp_printf(pool, "Invalid value of timestamp: '%s'.", str);
163   }
164   if(errno == EINVAL) {
165     return "Error occured during parsing of size.";
166   }
167
168   if(errno == ERANGE) {
169     return "Error: size value either too large or too small.";
170   }
171
172   if(*parse_end == 0) {
173     *(u64*) dest = (u64) parsed;
174     return NULL;
175   }
176
177   struct tm parsed_time;
178   parse_end = strptime(str, "%F %T", &parsed_time);
179   if(parse_end == NULL) {
180     return mp_printf(pool, "Invalid value of timestamp: '%s'.", str);
181   }
182   if(*parse_end != 0) {
183     return mp_printf(pool, "Invalid value of timestamp: '%s'.", str);
184   }
185
186   time_t tmp_time = mktime(&parsed_time);
187   *(u64*)dest = (u64) tmp_time;
188
189   return NULL;
190 }
191
192 TABLE_COL_BODY(timestamp, u64)
193
194 const struct xtype xt_timestamp = {
195   .size = sizeof(u64),
196   .name = "timestamp",
197   .parse = xt_timestamp_parse,
198   .format = xt_timestamp_format,
199   .parse_fmt = xt_timestamp_fmt_parse
200 };