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