api: Remove deprecated message from API
[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   for (int i = 0; i < vec_len (t->row_sizes); i++)
129     table_width += t->row_sizes[i];
130
131   if (t->title)
132     {
133       table_text_attr_t *title_default;
134       title_default =
135         t->default_title.as_u32 ? &t->default_title : &default_title;
136       s = format_text_cell (t, s, &title_cell, title_default, table_width);
137       s = format (s, "\n");
138     }
139
140   for (int c = 0; c < vec_len (t->cells); c++)
141     {
142       table_text_attr_t *col_default;
143
144       if (c < t->n_header_cols)
145         col_default = t->default_header_col.as_u32 ? &t->default_header_col :
146                                                      &default_header_col;
147       else
148         col_default =
149           t->default_body.as_u32 ? &t->default_body : &default_body;
150
151       for (int r = 0; r < vec_len (t->cells[c]); r++)
152         {
153           table_text_attr_t *row_default = col_default;
154           if (r)
155             s = format (s, " ");
156           if (r < t->n_header_rows && c >= t->n_header_cols)
157             row_default = t->default_header_row.as_u32 ?
158                             &t->default_header_row :
159                             &default_header_row;
160           s = format_text_cell (t, s, &t->cells[c][r], row_default,
161                                 t->row_sizes[r]);
162         }
163       if (c + 1 < vec_len (t->cells))
164         s = format (s, "\n");
165     }
166
167   return s;
168 }
169
170 void
171 table_format_title (table_t *t, char *fmt, ...)
172 {
173   va_list va;
174
175   va_start (va, fmt);
176   t->title = va_format (t->title, fmt, &va);
177   va_end (va);
178 }
179
180 static table_cell_t *
181 table_get_cell (table_t *t, int c, int r)
182 {
183   c += t->n_header_cols;
184   r += t->n_header_rows;
185
186   /* grow table if needed */
187   vec_validate (t->cells, c);
188   for (int i = 0; i < vec_len (t->cells); i++)
189     vec_validate (t->cells[i], r);
190   return &t->cells[c][r];
191 }
192
193 void
194 table_format_cell (table_t *t, int c, int r, char *fmt, ...)
195 {
196   table_cell_t *cell = table_get_cell (t, c, r);
197   va_list va;
198
199   c += t->n_header_cols;
200   r += t->n_header_rows;
201
202   va_start (va, fmt);
203   cell->text = va_format (t->cells[c][r].text, fmt, &va);
204   va_end (va);
205
206   vec_validate (t->row_sizes, r);
207   t->row_sizes[r] = clib_max (t->row_sizes[r], vec_len (t->cells[c][r].text));
208 }
209
210 void
211 table_set_cell_align (table_t *t, int c, int r, table_text_attr_align_t a)
212 {
213   table_cell_t *cell = table_get_cell (t, c, r);
214   cell->attr.align = a;
215 }
216
217 void
218 table_set_cell_fg_color (table_t *t, int c, int r, table_text_attr_color_t v)
219 {
220   table_cell_t *cell = table_get_cell (t, c, r);
221   cell->attr.fg_color = v & 0x7;
222   cell->attr.flags |= TTAF_FG_COLOR_SET;
223   if (v & 8)
224     cell->attr.flags |= TTAF_FG_COLOR_BRIGHT;
225   else
226     cell->attr.flags &= ~TTAF_FG_COLOR_BRIGHT;
227 }
228
229 void
230 table_set_cell_bg_color (table_t *t, int c, int r, table_text_attr_color_t v)
231 {
232   table_cell_t *cell = table_get_cell (t, c, r);
233   cell->attr.bg_color = v & 0x7;
234   cell->attr.flags |= TTAF_BG_COLOR_SET;
235   if (v & 8)
236     cell->attr.flags |= TTAF_BG_COLOR_BRIGHT;
237   else
238     cell->attr.flags &= ~TTAF_BG_COLOR_BRIGHT;
239 }
240
241 void
242 table_free (table_t *t)
243 {
244   for (int c = 0; c < vec_len (t->cells); c++)
245     {
246       for (int r = 0; r < vec_len (t->cells[c]); r++)
247         vec_free (t->cells[c][r].text);
248       vec_free (t->cells[c]);
249     }
250   vec_free (t->cells);
251   vec_free (t->row_sizes);
252   vec_free (t->title);
253   clib_memset (t, 0, sizeof (table_t));
254 }
255
256 void
257 table_add_header_col (table_t *t, int n_strings, ...)
258 {
259   va_list arg;
260   int r, c = t->n_header_cols++;
261   int n_rows;
262
263   vec_insert (t->cells, 1, c);
264   n_rows = clib_max (n_strings, 1);
265   n_rows = clib_max (vec_len (t->row_sizes), n_rows);
266   vec_validate (t->cells[c], n_rows - 1);
267
268   va_start (arg, n_strings);
269   for (r = 0; r < n_rows; r++)
270     {
271       if (n_strings-- > 0)
272         table_format_cell (t, -1, r - t->n_header_rows, "%s",
273                            va_arg (arg, char *));
274     }
275   va_end (arg);
276 }
277
278 void
279 table_add_header_row (table_t *t, int n_strings, ...)
280 {
281   va_list arg;
282   int c, r = t->n_header_rows++;
283
284   vec_validate (t->cells, n_strings + t->n_header_cols - 1);
285
286   va_start (arg, n_strings);
287   for (c = t->n_header_cols; c < vec_len (t->cells); c++)
288     {
289       vec_insert (t->cells[c + t->n_header_cols], 1, r);
290       if (n_strings-- > 0)
291         table_format_cell (t, c, -1, "%s", va_arg (arg, char *));
292     }
293   va_end (arg);
294 }