vlib: clean up r2 plugin registration relocator
[vpp.git] / src / vppinfra / format_table.c
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 format_text_cell (table_t *t, u8 *s, table_cell_t *c, table_text_attr_t *def,
51                   int size)
52 {
53   table_text_attr_t _a = {}, *a = &_a;
54
55   if (c == 0)
56     return format (s, t->no_ansi ? "" : "\x1b[0m");
57
58   clib_memcpy (a, def, sizeof (table_text_attr_t));
59
60   if (t->no_ansi == 0)
61     {
62       int *codes = 0;
63       if (c->attr.flags & TTAF_FG_COLOR_SET)
64         {
65           a->fg_color = c->attr.fg_color;
66           a->flags |= TTAF_FG_COLOR_SET;
67           a->flags |= c->attr.flags & TTAF_FG_COLOR_BRIGHT;
68         }
69
70       if (c->attr.flags & TTAF_BG_COLOR_SET)
71         {
72           a->bg_color = c->attr.bg_color;
73           a->flags |= TTAF_BG_COLOR_SET;
74           a->flags |= c->attr.flags & TTAF_BG_COLOR_BRIGHT;
75         }
76
77       if (a->flags & TTAF_RESET)
78         vec_add1 (codes, 0);
79
80       if (a->flags & TTAF_BOLD)
81         vec_add1 (codes, 1);
82
83       if (a->flags & TTAF_DIM)
84         vec_add1 (codes, 2);
85
86       if (a->flags & TTAF_UNDERLINE)
87         vec_add1 (codes, 4);
88
89       if (a->flags & TTAF_FG_COLOR_SET)
90         vec_add1 (codes,
91                   (a->flags & TTAF_FG_COLOR_BRIGHT ? 90 : 30) + a->fg_color);
92
93       if (a->flags & TTAF_BG_COLOR_SET)
94         vec_add1 (codes,
95                   (a->flags & TTAF_BG_COLOR_BRIGHT ? 100 : 40) + a->bg_color);
96
97       if (codes)
98         {
99           s = format (s, "\x1b[");
100           for (int i = 0; i < vec_len (codes); i++)
101             s = format (s, "%s%u", i ? ";" : "", codes[i]);
102           s = format (s, "m");
103           vec_free (codes);
104         }
105     }
106
107   u8 *fmt = 0;
108   table_text_attr_align_t align = c->attr.align;
109   if (align == TTAA_DEFAULT)
110     align = a->align;
111   if (align == TTAA_LEFT)
112     fmt = format (fmt, "%%-%uv%c", size, 0);
113   else if (align == TTAA_CENTER)
114     fmt = format (fmt, "%%=%uv%c", size, 0);
115   else
116     fmt = format (fmt, "%%%uv%c", size, 0);
117   s = format (s, (char *) fmt, c->text);
118   vec_free (fmt);
119   return format (s, t->no_ansi ? "" : "\x1b[0m");
120 }
121
122 u8 *
123 format_table (u8 *s, va_list *args)
124 {
125   table_t *t = va_arg (*args, table_t *);
126   table_cell_t title_cell = { .text = t->title };
127   int table_width = 0;
128   u32 indent = format_get_indent (s);
129   for (int i = 0; i < vec_len (t->row_sizes); i++)
130     table_width += t->row_sizes[i];
131
132   if (t->title)
133     {
134       table_text_attr_t *title_default;
135       title_default =
136         t->default_title.as_u32 ? &t->default_title : &default_title;
137       s = format_text_cell (t, s, &title_cell, title_default, table_width);
138       s = format (s, "\n%U", format_white_space, indent);
139     }
140
141   for (int c = 0; c < vec_len (t->cells); c++)
142     {
143       table_text_attr_t *col_default;
144
145       if (c < t->n_header_cols)
146         col_default = t->default_header_col.as_u32 ? &t->default_header_col :
147                                                      &default_header_col;
148       else
149         col_default =
150           t->default_body.as_u32 ? &t->default_body : &default_body;
151
152       for (int r = 0; r < vec_len (t->cells[c]); r++)
153         {
154           table_text_attr_t *row_default = col_default;
155           if (r)
156             s = format (s, " ");
157           if (r < t->n_header_rows && c >= t->n_header_cols)
158             row_default = t->default_header_row.as_u32 ?
159                             &t->default_header_row :
160                             &default_header_row;
161           s = format_text_cell (t, s, &t->cells[c][r], row_default,
162                                 t->row_sizes[r]);
163         }
164       if (c + 1 < vec_len (t->cells))
165         s = format (s, "\n%U", format_white_space, indent);
166     }
167
168   return s;
169 }
170
171 void
172 table_format_title (table_t *t, char *fmt, ...)
173 {
174   va_list va;
175
176   va_start (va, fmt);
177   t->title = va_format (t->title, fmt, &va);
178   va_end (va);
179 }
180
181 static table_cell_t *
182 table_get_cell (table_t *t, int c, int r)
183 {
184   c += t->n_header_cols;
185   r += t->n_header_rows;
186
187   /* grow table if needed */
188   vec_validate (t->cells, c);
189   for (int i = 0; i < vec_len (t->cells); i++)
190     vec_validate (t->cells[i], r);
191   return &t->cells[c][r];
192 }
193
194 void
195 table_format_cell (table_t *t, int c, int r, char *fmt, ...)
196 {
197   table_cell_t *cell = table_get_cell (t, c, r);
198   va_list va;
199
200   c += t->n_header_cols;
201   r += t->n_header_rows;
202
203   va_start (va, fmt);
204   cell->text = va_format (t->cells[c][r].text, fmt, &va);
205   va_end (va);
206
207   vec_validate (t->row_sizes, r);
208   t->row_sizes[r] = clib_max (t->row_sizes[r], vec_len (t->cells[c][r].text));
209 }
210
211 void
212 table_set_cell_align (table_t *t, int c, int r, table_text_attr_align_t a)
213 {
214   table_cell_t *cell = table_get_cell (t, c, r);
215   cell->attr.align = a;
216 }
217
218 void
219 table_set_cell_fg_color (table_t *t, int c, int r, table_text_attr_color_t v)
220 {
221   table_cell_t *cell = table_get_cell (t, c, r);
222   cell->attr.fg_color = v & 0x7;
223   cell->attr.flags |= TTAF_FG_COLOR_SET;
224   if (v & 8)
225     cell->attr.flags |= TTAF_FG_COLOR_BRIGHT;
226   else
227     cell->attr.flags &= ~TTAF_FG_COLOR_BRIGHT;
228 }
229
230 void
231 table_set_cell_bg_color (table_t *t, int c, int r, table_text_attr_color_t v)
232 {
233   table_cell_t *cell = table_get_cell (t, c, r);
234   cell->attr.bg_color = v & 0x7;
235   cell->attr.flags |= TTAF_BG_COLOR_SET;
236   if (v & 8)
237     cell->attr.flags |= TTAF_BG_COLOR_BRIGHT;
238   else
239     cell->attr.flags &= ~TTAF_BG_COLOR_BRIGHT;
240 }
241
242 void
243 table_free (table_t *t)
244 {
245   for (int c = 0; c < vec_len (t->cells); c++)
246     {
247       for (int r = 0; r < vec_len (t->cells[c]); r++)
248         vec_free (t->cells[c][r].text);
249       vec_free (t->cells[c]);
250     }
251   vec_free (t->cells);
252   vec_free (t->row_sizes);
253   vec_free (t->title);
254   clib_memset (t, 0, sizeof (table_t));
255 }
256
257 void
258 table_add_header_col (table_t *t, int n_strings, ...)
259 {
260   va_list arg;
261   int r, c = t->n_header_cols++;
262   int n_rows;
263
264   vec_insert (t->cells, 1, c);
265   n_rows = clib_max (n_strings, 1);
266   n_rows = clib_max (vec_len (t->row_sizes), n_rows);
267   vec_validate (t->cells[c], n_rows - 1);
268
269   va_start (arg, n_strings);
270   for (r = 0; r < n_rows; r++)
271     {
272       if (n_strings-- > 0)
273         table_format_cell (t, -1, r - t->n_header_rows, "%s",
274                            va_arg (arg, char *));
275     }
276   va_end (arg);
277 }
278
279 void
280 table_add_header_row (table_t *t, int n_strings, ...)
281 {
282   va_list arg;
283   int c, r = t->n_header_rows++;
284
285   vec_validate (t->cells, n_strings + t->n_header_cols - 1);
286
287   va_start (arg, n_strings);
288   for (c = t->n_header_cols; c < vec_len (t->cells); c++)
289     {
290       vec_insert (t->cells[c + t->n_header_cols], 1, r);
291       if (n_strings-- > 0)
292         table_format_cell (t, c, -1, "%s", va_arg (arg, char *));
293     }
294   va_end (arg);
295 }