]> mj.ucw.cz Git - libucw.git/blob - ucw/table-types.c
tableprinter: code cleanup
[libucw.git] / ucw / table-types.c
1 #include <ucw/lib.h>
2 #include <ucw/table-types.h>
3 #include <ucw/fastbuf.h>
4 #include <ucw/table.h>
5 #include <time.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8
9 static const char *unit_suffix[] = {
10   [UNIT_SIZE_BYTE] = "",
11   [UNIT_SIZE_KILOBYTE] = "KB",
12   [UNIT_SIZE_MEGABYTE] = "MB",
13   [UNIT_SIZE_GIGABYTE] = "GB",
14   [UNIT_SIZE_TERABYTE] = "TB"
15 };
16
17 static bool table_set_col_opt_size(struct table *tbl, uint col_copy_idx, const char *col_arg, char **err)
18 {
19   struct table_column *col_def = tbl->column_order[col_copy_idx].col_def;
20   if(col_def->type != COL_TYPE_SIZE) {
21     *err = NULL;
22     return false;
23   }
24
25   if(col_arg == NULL || strcasecmp(col_arg, "b") == 0 || strcasecmp(col_arg, "bytes") == 0) {
26     tbl->column_order[col_copy_idx].output_type = UNIT_SIZE_BYTE;
27     *err = NULL;
28     return true;
29   }
30
31   tbl->column_order[col_copy_idx].output_type = CELL_OUT_UNINITIALIZED;
32   for(uint i = 0; i < ARRAY_SIZE(unit_suffix); i++) {
33     if(strcasecmp(col_arg, unit_suffix[i]) == 0) {
34       tbl->column_order[col_copy_idx].output_type = i;
35     }
36   }
37
38   if(tbl->column_order[col_copy_idx].output_type == CELL_OUT_UNINITIALIZED) {
39     *err = mp_printf(tbl->pool, "Invalid column format option: '%s' for column %d (counted from 0)", col_arg, col_copy_idx);
40     return true;
41   }
42
43   *err = NULL;
44   return true;
45 }
46
47 struct table_user_type table_type_size = {
48   .set_col_instance_option = table_set_col_opt_size,
49   .type = COL_TYPE_SIZE,
50 };
51
52 static bool table_set_col_opt_timestamp(struct table *tbl, uint col_copy_idx, const char *col_arg, char **err)
53 {
54   int col_type_idx = tbl->column_order[col_copy_idx].idx;
55   if(tbl->columns[col_type_idx].type != COL_TYPE_TIMESTAMP) {
56     *err = NULL;
57     return false;
58   }
59
60   if(col_arg == NULL) {
61     *err = NULL;
62     return true;
63   }
64
65   if(strcasecmp(col_arg, "timestamp") == 0 || strcasecmp(col_arg, "epoch") == 0) {
66     tbl->column_order[col_copy_idx].output_type = TIMESTAMP_EPOCH;
67   } else if(strcasecmp(col_arg, "datetime") == 0) {
68     tbl->column_order[col_copy_idx].output_type = TIMESTAMP_DATETIME;
69   } else {
70     *err = mp_printf(tbl->pool, "Invalid column format option: '%s' for column %d.", col_arg, col_copy_idx);
71     return true;
72   }
73
74   *err = NULL;
75   return true;
76 }
77
78 struct table_user_type table_type_timestamp = {
79   .set_col_instance_option = table_set_col_opt_timestamp,
80   .type = COL_TYPE_TIMESTAMP,
81 };
82
83 void table_col_size_name(struct table *tbl, const char *col_name, u64 val)
84 {
85   int col = table_get_col_idx(tbl, col_name);
86   table_col_size(tbl, col, val);
87 }
88
89 void table_col_size(struct table *tbl, int col, u64 val)
90 {
91   ASSERT_MSG(col < tbl->column_count && col >= 0, "Table column %d does not exist.", col);
92   ASSERT(tbl->columns[col].type == COL_TYPE_ANY || COL_TYPE_SIZE == tbl->columns[col].type);
93
94   tbl->last_printed_col = col;
95   tbl->row_printing_started = 1;
96
97   static u64 unit_div[] = {
98     [UNIT_SIZE_BYTE] = (u64) 1,
99     [UNIT_SIZE_KILOBYTE] = (u64) 1024LLU,
100     [UNIT_SIZE_MEGABYTE] = (u64) (1024LLU * 1024LLU),
101     [UNIT_SIZE_GIGABYTE] = (u64) (1024LLU * 1024LLU * 1024LLU),
102     [UNIT_SIZE_TERABYTE] = (u64) (1024LLU * 1024LLU * 1024LLU * 1024LLU)
103   };
104
105   TBL_COL_ITER_START(tbl, col, curr_col, curr_col_idx) {
106     // FIXME: do some rounding? Or maybe use double and floating-point printing?
107     uint out_type = 0;
108     u64 curr_val = val;
109     if(curr_col->output_type == CELL_OUT_UNINITIALIZED) {
110       curr_val = curr_val / unit_div[UNIT_SIZE_BYTE];
111       out_type = 0;
112     } else {
113       curr_val = curr_val / unit_div[curr_col->output_type];
114       out_type = curr_col->output_type;
115     }
116
117     curr_col->cell_content = mp_printf(tbl->pool, "%lu%s", curr_val, unit_suffix[out_type]);
118   } TBL_COL_ITER_END
119 }
120
121 #define FORMAT_TIME_SIZE 20     // Minimum buffer size
122
123 void table_col_timestamp_name(struct table *tbl, const char * col_name, u64 val)
124 {
125   int col = table_get_col_idx(tbl, col_name);
126   table_col_size(tbl, col, val);
127 }
128
129 void table_col_timestamp(struct table *tbl, int col, u64 val)
130 {
131   ASSERT_MSG(col < tbl->column_count && col >= 0, "Table column %d does not exist.", col);
132   ASSERT(tbl->columns[col].type == COL_TYPE_ANY || COL_TYPE_TIMESTAMP == tbl->columns[col].type);
133
134   char formatted_time_buf[FORMAT_TIME_SIZE] = { 0 };
135
136   time_t tmp_time = (time_t)val;
137   struct tm t = *gmtime(&tmp_time);
138   TBL_COL_ITER_START(tbl, col, curr_col, curr_col_idx) {
139     switch (curr_col->output_type) {
140     case TIMESTAMP_EPOCH:
141     case CELL_OUT_UNINITIALIZED:
142       sprintf(formatted_time_buf, "%lu", val);
143       break;
144     case TIMESTAMP_DATETIME:
145       strftime(formatted_time_buf, FORMAT_TIME_SIZE, "%F %T", &t);
146     break;
147     default:
148       abort();
149       break;
150     }
151
152     curr_col->cell_content = mp_printf(tbl->pool, "%s", formatted_time_buf);
153   } TBL_COL_ITER_END
154 }