Line data Source code
1 : /*
2 : Copyright (c) 2020 Damjan Marion
3 :
4 : Permission is hereby granted, free of charge, to any person obtaining
5 : a copy of this software and associated documentation files (the
6 : "Software"), to deal in the Software without restriction, including
7 : without limitation the rights to use, copy, modify, merge, publish,
8 : distribute, sublicense, and/or sell copies of the Software, and to
9 : permit persons to whom the Software is furnished to do so, subject to
10 : the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be
13 : included in all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 : EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 : MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 : NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 : OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 : WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 : */
23 :
24 : #include <vppinfra/format.h>
25 : #include <vppinfra/format_table.h>
26 :
27 : static table_text_attr_t default_title = {
28 : .flags = TTAF_FG_COLOR_SET | TTAF_BOLD,
29 : .fg_color = TTAC_YELLOW,
30 : .align = TTAA_CENTER,
31 : };
32 :
33 : static table_text_attr_t default_body = {
34 : .align = TTAA_RIGHT,
35 : };
36 :
37 : static table_text_attr_t default_header_col = {
38 : .flags = TTAF_FG_COLOR_SET,
39 : .fg_color = TTAC_YELLOW,
40 : .align = TTAA_CENTER,
41 : };
42 :
43 : static table_text_attr_t default_header_row = {
44 : .flags = TTAF_FG_COLOR_SET | TTAF_BOLD,
45 : .fg_color = TTAC_GREEN,
46 : .align = TTAA_LEFT,
47 : };
48 :
49 : u8 *
50 0 : format_text_cell (table_t *t, u8 *s, table_cell_t *c, table_text_attr_t *def,
51 : int size)
52 : {
53 0 : table_text_attr_t _a = {}, *a = &_a;
54 :
55 0 : if (c == 0)
56 0 : return format (s, t->no_ansi ? "" : "\x1b[0m");
57 :
58 0 : clib_memcpy (a, def, sizeof (table_text_attr_t));
59 :
60 0 : if (t->no_ansi == 0)
61 : {
62 0 : int *codes = 0;
63 0 : if (c->attr.flags & TTAF_FG_COLOR_SET)
64 : {
65 0 : a->fg_color = c->attr.fg_color;
66 0 : a->flags |= TTAF_FG_COLOR_SET;
67 0 : a->flags |= c->attr.flags & TTAF_FG_COLOR_BRIGHT;
68 : }
69 :
70 0 : if (c->attr.flags & TTAF_BG_COLOR_SET)
71 : {
72 0 : a->bg_color = c->attr.bg_color;
73 0 : a->flags |= TTAF_BG_COLOR_SET;
74 0 : a->flags |= c->attr.flags & TTAF_BG_COLOR_BRIGHT;
75 : }
76 :
77 0 : if (a->flags & TTAF_RESET)
78 0 : vec_add1 (codes, 0);
79 :
80 0 : if (a->flags & TTAF_BOLD)
81 0 : vec_add1 (codes, 1);
82 :
83 0 : if (a->flags & TTAF_DIM)
84 0 : vec_add1 (codes, 2);
85 :
86 0 : if (a->flags & TTAF_UNDERLINE)
87 0 : vec_add1 (codes, 4);
88 :
89 0 : if (a->flags & TTAF_FG_COLOR_SET)
90 0 : vec_add1 (codes,
91 : (a->flags & TTAF_FG_COLOR_BRIGHT ? 90 : 30) + a->fg_color);
92 :
93 0 : if (a->flags & TTAF_BG_COLOR_SET)
94 0 : vec_add1 (codes,
95 : (a->flags & TTAF_BG_COLOR_BRIGHT ? 100 : 40) + a->bg_color);
96 :
97 0 : if (codes)
98 : {
99 0 : s = format (s, "\x1b[");
100 0 : for (int i = 0; i < vec_len (codes); i++)
101 0 : s = format (s, "%s%u", i ? ";" : "", codes[i]);
102 0 : s = format (s, "m");
103 0 : vec_free (codes);
104 : }
105 : }
106 :
107 0 : u8 *fmt = 0;
108 0 : table_text_attr_align_t align = c->attr.align;
109 0 : if (align == TTAA_DEFAULT)
110 0 : align = a->align;
111 0 : if (align == TTAA_LEFT)
112 0 : fmt = format (fmt, "%%-%uv%c", size, 0);
113 0 : else if (align == TTAA_CENTER)
114 0 : fmt = format (fmt, "%%=%uv%c", size, 0);
115 : else
116 0 : fmt = format (fmt, "%%%uv%c", size, 0);
117 0 : s = format (s, (char *) fmt, c->text);
118 0 : vec_free (fmt);
119 0 : return format (s, t->no_ansi ? "" : "\x1b[0m");
120 : }
121 :
122 : u8 *
123 0 : format_table (u8 *s, va_list *args)
124 : {
125 0 : table_t *t = va_arg (*args, table_t *);
126 0 : table_cell_t title_cell = { .text = t->title };
127 0 : int table_width = 0;
128 0 : for (int i = 0; i < vec_len (t->row_sizes); i++)
129 0 : table_width += t->row_sizes[i];
130 :
131 0 : if (t->title)
132 : {
133 : table_text_attr_t *title_default;
134 0 : title_default =
135 0 : t->default_title.as_u32 ? &t->default_title : &default_title;
136 0 : s = format_text_cell (t, s, &title_cell, title_default, table_width);
137 0 : s = format (s, "\n");
138 : }
139 :
140 0 : for (int c = 0; c < vec_len (t->cells); c++)
141 : {
142 : table_text_attr_t *col_default;
143 :
144 0 : if (c < t->n_header_cols)
145 0 : col_default = t->default_header_col.as_u32 ? &t->default_header_col :
146 : &default_header_col;
147 : else
148 0 : col_default =
149 0 : t->default_body.as_u32 ? &t->default_body : &default_body;
150 :
151 0 : for (int r = 0; r < vec_len (t->cells[c]); r++)
152 : {
153 0 : table_text_attr_t *row_default = col_default;
154 0 : if (r)
155 0 : s = format (s, " ");
156 0 : if (r < t->n_header_rows && c >= t->n_header_cols)
157 0 : row_default = t->default_header_row.as_u32 ?
158 0 : &t->default_header_row :
159 : &default_header_row;
160 0 : s = format_text_cell (t, s, &t->cells[c][r], row_default,
161 0 : t->row_sizes[r]);
162 : }
163 0 : if (c + 1 < vec_len (t->cells))
164 0 : s = format (s, "\n");
165 : }
166 :
167 0 : return s;
168 : }
169 :
170 : void
171 0 : table_format_title (table_t *t, char *fmt, ...)
172 : {
173 : va_list va;
174 :
175 0 : va_start (va, fmt);
176 0 : t->title = va_format (t->title, fmt, &va);
177 0 : va_end (va);
178 0 : }
179 :
180 : static table_cell_t *
181 0 : table_get_cell (table_t *t, int c, int r)
182 : {
183 0 : c += t->n_header_cols;
184 0 : r += t->n_header_rows;
185 :
186 : /* grow table if needed */
187 0 : vec_validate (t->cells, c);
188 0 : for (int i = 0; i < vec_len (t->cells); i++)
189 0 : vec_validate (t->cells[i], r);
190 0 : return &t->cells[c][r];
191 : }
192 :
193 : void
194 0 : table_format_cell (table_t *t, int c, int r, char *fmt, ...)
195 : {
196 0 : table_cell_t *cell = table_get_cell (t, c, r);
197 : va_list va;
198 :
199 0 : c += t->n_header_cols;
200 0 : r += t->n_header_rows;
201 :
202 0 : va_start (va, fmt);
203 0 : cell->text = va_format (t->cells[c][r].text, fmt, &va);
204 0 : va_end (va);
205 :
206 0 : vec_validate (t->row_sizes, r);
207 0 : t->row_sizes[r] = clib_max (t->row_sizes[r], vec_len (t->cells[c][r].text));
208 0 : }
209 :
210 : void
211 0 : table_set_cell_align (table_t *t, int c, int r, table_text_attr_align_t a)
212 : {
213 0 : table_cell_t *cell = table_get_cell (t, c, r);
214 0 : cell->attr.align = a;
215 0 : }
216 :
217 : void
218 0 : table_set_cell_fg_color (table_t *t, int c, int r, table_text_attr_color_t v)
219 : {
220 0 : table_cell_t *cell = table_get_cell (t, c, r);
221 0 : cell->attr.fg_color = v & 0x7;
222 0 : cell->attr.flags |= TTAF_FG_COLOR_SET;
223 0 : if (v & 8)
224 0 : cell->attr.flags |= TTAF_FG_COLOR_BRIGHT;
225 : else
226 0 : cell->attr.flags &= ~TTAF_FG_COLOR_BRIGHT;
227 0 : }
228 :
229 : void
230 0 : table_set_cell_bg_color (table_t *t, int c, int r, table_text_attr_color_t v)
231 : {
232 0 : table_cell_t *cell = table_get_cell (t, c, r);
233 0 : cell->attr.bg_color = v & 0x7;
234 0 : cell->attr.flags |= TTAF_BG_COLOR_SET;
235 0 : if (v & 8)
236 0 : cell->attr.flags |= TTAF_BG_COLOR_BRIGHT;
237 : else
238 0 : cell->attr.flags &= ~TTAF_BG_COLOR_BRIGHT;
239 0 : }
240 :
241 : void
242 0 : table_free (table_t *t)
243 : {
244 0 : for (int c = 0; c < vec_len (t->cells); c++)
245 : {
246 0 : for (int r = 0; r < vec_len (t->cells[c]); r++)
247 0 : vec_free (t->cells[c][r].text);
248 0 : vec_free (t->cells[c]);
249 : }
250 0 : vec_free (t->cells);
251 0 : vec_free (t->row_sizes);
252 0 : vec_free (t->title);
253 0 : clib_memset (t, 0, sizeof (table_t));
254 0 : }
255 :
256 : void
257 0 : table_add_header_col (table_t *t, int n_strings, ...)
258 : {
259 : va_list arg;
260 0 : int r, c = t->n_header_cols++;
261 : int n_rows;
262 :
263 0 : vec_insert (t->cells, 1, c);
264 0 : n_rows = clib_max (n_strings, 1);
265 0 : n_rows = clib_max (vec_len (t->row_sizes), n_rows);
266 0 : vec_validate (t->cells[c], n_rows - 1);
267 :
268 0 : va_start (arg, n_strings);
269 0 : for (r = 0; r < n_rows; r++)
270 : {
271 0 : if (n_strings-- > 0)
272 0 : table_format_cell (t, -1, r - t->n_header_rows, "%s",
273 : va_arg (arg, char *));
274 : }
275 0 : va_end (arg);
276 0 : }
277 :
278 : void
279 0 : table_add_header_row (table_t *t, int n_strings, ...)
280 : {
281 : va_list arg;
282 0 : int c, r = t->n_header_rows++;
283 :
284 0 : vec_validate (t->cells, n_strings + t->n_header_cols - 1);
285 :
286 0 : va_start (arg, n_strings);
287 0 : for (c = t->n_header_cols; c < vec_len (t->cells); c++)
288 : {
289 0 : vec_insert (t->cells[c + t->n_header_cols], 1, r);
290 0 : if (n_strings-- > 0)
291 0 : table_format_cell (t, c, -1, "%s", va_arg (arg, char *));
292 : }
293 0 : va_end (arg);
294 0 : }
|