]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - crypto/heimdal/lib/roken/rtbl.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / crypto / heimdal / lib / roken / rtbl.c
1 /*
2  * Copyright (c) 2000, 2002, 2004 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include <config.h>
35
36 #include "roken.h"
37 #include "rtbl.h"
38
39 struct column_entry {
40     char *data;
41 };
42
43 struct column_data {
44     char *header;
45     char *prefix;
46     int width;
47     unsigned flags;
48     size_t num_rows;
49     struct column_entry *rows;
50     unsigned int column_id;
51     char *suffix;
52 };
53
54 struct rtbl_data {
55     char *column_prefix;
56     size_t num_columns;
57     struct column_data **columns;
58     unsigned int flags;
59     char *column_separator;
60 };
61
62 ROKEN_LIB_FUNCTION rtbl_t ROKEN_LIB_CALL
63 rtbl_create (void)
64 {
65     return calloc (1, sizeof (struct rtbl_data));
66 }
67
68 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
69 rtbl_set_flags (rtbl_t table, unsigned int flags)
70 {
71     table->flags = flags;
72 }
73
74 ROKEN_LIB_FUNCTION unsigned int ROKEN_LIB_CALL
75 rtbl_get_flags (rtbl_t table)
76 {
77     return table->flags;
78 }
79
80 static struct column_data *
81 rtbl_get_column_by_id (rtbl_t table, unsigned int id)
82 {
83     size_t i;
84     for(i = 0; i < table->num_columns; i++)
85         if(table->columns[i]->column_id == id)
86             return table->columns[i];
87     return NULL;
88 }
89
90 static struct column_data *
91 rtbl_get_column (rtbl_t table, const char *column)
92 {
93     size_t i;
94     for(i = 0; i < table->num_columns; i++)
95         if(strcmp(table->columns[i]->header, column) == 0)
96             return table->columns[i];
97     return NULL;
98 }
99
100 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
101 rtbl_destroy (rtbl_t table)
102 {
103     size_t i, j;
104
105     for (i = 0; i < table->num_columns; i++) {
106         struct column_data *c = table->columns[i];
107
108         for (j = 0; j < c->num_rows; j++)
109             free (c->rows[j].data);
110         free (c->rows);
111         free (c->header);
112         free (c->prefix);
113         free (c->suffix);
114         free (c);
115     }
116     free (table->column_prefix);
117     free (table->column_separator);
118     free (table->columns);
119     free (table);
120 }
121
122 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
123 rtbl_add_column_by_id (rtbl_t table, unsigned int id,
124                        const char *header, unsigned int flags)
125 {
126     struct column_data *col, **tmp;
127
128     tmp = realloc (table->columns, (table->num_columns + 1) * sizeof (*tmp));
129     if (tmp == NULL)
130         return ENOMEM;
131     table->columns = tmp;
132     col = malloc (sizeof (*col));
133     if (col == NULL)
134         return ENOMEM;
135     col->header = strdup (header);
136     if (col->header == NULL) {
137         free (col);
138         return ENOMEM;
139     }
140     col->prefix = NULL;
141     col->width = 0;
142     col->flags = flags;
143     col->num_rows = 0;
144     col->rows = NULL;
145     col->column_id = id;
146     col->suffix = NULL;
147     table->columns[table->num_columns++] = col;
148     return 0;
149 }
150
151 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
152 rtbl_add_column (rtbl_t table, const char *header, unsigned int flags)
153 {
154     return rtbl_add_column_by_id(table, 0, header, flags);
155 }
156
157 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
158 rtbl_new_row(rtbl_t table)
159 {
160     size_t max_rows = 0;
161     size_t c;
162     for (c = 0; c < table->num_columns; c++)
163         if(table->columns[c]->num_rows > max_rows)
164             max_rows = table->columns[c]->num_rows;
165     for (c = 0; c < table->num_columns; c++) {
166         struct column_entry *tmp;
167
168         if(table->columns[c]->num_rows == max_rows)
169             continue;
170         tmp = realloc(table->columns[c]->rows,
171                       max_rows * sizeof(table->columns[c]->rows));
172         if(tmp == NULL)
173             return ENOMEM;
174         table->columns[c]->rows = tmp;
175         while(table->columns[c]->num_rows < max_rows) {
176             if((tmp[table->columns[c]->num_rows++].data = strdup("")) == NULL)
177                 return ENOMEM;
178         }
179     }
180     return 0;
181 }
182
183 static void
184 column_compute_width (rtbl_t table, struct column_data *column)
185 {
186     size_t i;
187
188     if(table->flags & RTBL_HEADER_STYLE_NONE)
189         column->width = 0;
190     else
191         column->width = strlen (column->header);
192     for (i = 0; i < column->num_rows; i++)
193         column->width = max (column->width, (int) strlen (column->rows[i].data));
194 }
195
196 /* DEPRECATED */
197 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
198 rtbl_set_prefix (rtbl_t table, const char *prefix)
199 {
200     if (table->column_prefix)
201         free (table->column_prefix);
202     table->column_prefix = strdup (prefix);
203     if (table->column_prefix == NULL)
204         return ENOMEM;
205     return 0;
206 }
207
208 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
209 rtbl_set_separator (rtbl_t table, const char *separator)
210 {
211     if (table->column_separator)
212         free (table->column_separator);
213     table->column_separator = strdup (separator);
214     if (table->column_separator == NULL)
215         return ENOMEM;
216     return 0;
217 }
218
219 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
220 rtbl_set_column_prefix (rtbl_t table, const char *column,
221                         const char *prefix)
222 {
223     struct column_data *c = rtbl_get_column (table, column);
224
225     if (c == NULL)
226         return -1;
227     if (c->prefix)
228         free (c->prefix);
229     c->prefix = strdup (prefix);
230     if (c->prefix == NULL)
231         return ENOMEM;
232     return 0;
233 }
234
235 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
236 rtbl_set_column_affix_by_id(rtbl_t table, unsigned int id,
237                             const char *prefix, const char *suffix)
238 {
239     struct column_data *c = rtbl_get_column_by_id (table, id);
240
241     if (c == NULL)
242         return -1;
243     if (c->prefix)
244         free (c->prefix);
245     if(prefix == NULL)
246         c->prefix = NULL;
247     else {
248         c->prefix = strdup (prefix);
249         if (c->prefix == NULL)
250             return ENOMEM;
251     }
252
253     if (c->suffix)
254         free (c->suffix);
255     if(suffix == NULL)
256         c->suffix = NULL;
257     else {
258         c->suffix = strdup (suffix);
259         if (c->suffix == NULL)
260             return ENOMEM;
261     }
262     return 0;
263 }
264
265
266 static const char *
267 get_column_prefix (rtbl_t table, struct column_data *c)
268 {
269     if (c == NULL)
270         return "";
271     if (c->prefix)
272         return c->prefix;
273     if (table->column_prefix)
274         return table->column_prefix;
275     return "";
276 }
277
278 static const char *
279 get_column_suffix (rtbl_t table, struct column_data *c)
280 {
281     if (c && c->suffix)
282         return c->suffix;
283     return "";
284 }
285
286 static int
287 add_column_entry (struct column_data *c, const char *data)
288 {
289     struct column_entry row, *tmp;
290
291     row.data = strdup (data);
292     if (row.data == NULL)
293         return ENOMEM;
294     tmp = realloc (c->rows, (c->num_rows + 1) * sizeof (*tmp));
295     if (tmp == NULL) {
296         free (row.data);
297         return ENOMEM;
298     }
299     c->rows = tmp;
300     c->rows[c->num_rows++] = row;
301     return 0;
302 }
303
304 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
305 rtbl_add_column_entry_by_id (rtbl_t table, unsigned int id, const char *data)
306 {
307     struct column_data *c = rtbl_get_column_by_id (table, id);
308
309     if (c == NULL)
310         return -1;
311
312     return add_column_entry(c, data);
313 }
314
315 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
316 rtbl_add_column_entryv_by_id (rtbl_t table, unsigned int id,
317                               const char *fmt, ...)
318 {
319     va_list ap;
320     char *str;
321     int ret;
322
323     va_start(ap, fmt);
324     ret = vasprintf(&str, fmt, ap);
325     va_end(ap);
326     if (ret == -1)
327         return -1;
328     ret = rtbl_add_column_entry_by_id(table, id, str);
329     free(str);
330     return ret;
331 }
332
333 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
334 rtbl_add_column_entry (rtbl_t table, const char *column, const char *data)
335 {
336     struct column_data *c = rtbl_get_column (table, column);
337
338     if (c == NULL)
339         return -1;
340
341     return add_column_entry(c, data);
342 }
343
344 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
345 rtbl_add_column_entryv (rtbl_t table, const char *column, const char *fmt, ...)
346 {
347     va_list ap;
348     char *str;
349     int ret;
350
351     va_start(ap, fmt);
352     ret = vasprintf(&str, fmt, ap);
353     va_end(ap);
354     if (ret == -1)
355         return -1;
356     ret = rtbl_add_column_entry(table, column, str);
357     free(str);
358     return ret;
359 }
360
361
362 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
363 rtbl_format (rtbl_t table, FILE * f)
364 {
365     size_t i, j;
366
367     for (i = 0; i < table->num_columns; i++)
368         column_compute_width (table, table->columns[i]);
369     if((table->flags & RTBL_HEADER_STYLE_NONE) == 0) {
370         for (i = 0; i < table->num_columns; i++) {
371             struct column_data *c = table->columns[i];
372
373             if(table->column_separator != NULL && i > 0)
374                 fprintf (f, "%s", table->column_separator);
375             fprintf (f, "%s", get_column_prefix (table, c));
376             if(i == table->num_columns - 1 && c->suffix == NULL)
377                 /* last column, so no need to pad with spaces */
378                 fprintf (f, "%-*s", 0, c->header);
379             else
380                 fprintf (f, "%-*s", (int)c->width, c->header);
381             fprintf (f, "%s", get_column_suffix (table, c));
382         }
383         fprintf (f, "\n");
384     }
385
386     for (j = 0;; j++) {
387         int flag = 0;
388
389         /* are there any more rows left? */
390         for (i = 0; flag == 0 && i < table->num_columns; ++i) {
391             struct column_data *c = table->columns[i];
392
393             if (c->num_rows > j) {
394                 ++flag;
395                 break;
396             }
397         }
398         if (flag == 0)
399             break;
400
401         for (i = 0; i < table->num_columns; i++) {
402             int w;
403             struct column_data *c = table->columns[i];
404
405             if(table->column_separator != NULL && i > 0)
406                 fprintf (f, "%s", table->column_separator);
407
408             w = c->width;
409
410             if ((c->flags & RTBL_ALIGN_RIGHT) == 0) {
411                 if(i == table->num_columns - 1 && c->suffix == NULL)
412                     /* last column, so no need to pad with spaces */
413                     w = 0;
414                 else
415                     w = -w;
416             }
417             fprintf (f, "%s", get_column_prefix (table, c));
418             if (c->num_rows <= j)
419                 fprintf (f, "%*s", w, "");
420             else
421                 fprintf (f, "%*s", w, c->rows[j].data);
422             fprintf (f, "%s", get_column_suffix (table, c));
423         }
424         fprintf (f, "\n");
425     }
426     return 0;
427 }
428
429 #ifdef TEST
430 int
431 main (int argc, char **argv)
432 {
433     rtbl_t table;
434
435     table = rtbl_create ();
436     rtbl_add_column_by_id (table, 0, "Issued", 0);
437     rtbl_add_column_by_id (table, 1, "Expires", 0);
438     rtbl_add_column_by_id (table, 2, "Foo", RTBL_ALIGN_RIGHT);
439     rtbl_add_column_by_id (table, 3, "Principal", 0);
440
441     rtbl_add_column_entry_by_id (table, 0, "Jul  7 21:19:29");
442     rtbl_add_column_entry_by_id (table, 1, "Jul  8 07:19:29");
443     rtbl_add_column_entry_by_id (table, 2, "73");
444     rtbl_add_column_entry_by_id (table, 2, "0");
445     rtbl_add_column_entry_by_id (table, 2, "-2000");
446     rtbl_add_column_entry_by_id (table, 3, "krbtgt/NADA.KTH.SE@NADA.KTH.SE");
447
448     rtbl_add_column_entry_by_id (table, 0, "Jul  7 21:19:29");
449     rtbl_add_column_entry_by_id (table, 1, "Jul  8 07:19:29");
450     rtbl_add_column_entry_by_id (table, 3, "afs/pdc.kth.se@NADA.KTH.SE");
451
452     rtbl_add_column_entry_by_id (table, 0, "Jul  7 21:19:29");
453     rtbl_add_column_entry_by_id (table, 1, "Jul  8 07:19:29");
454     rtbl_add_column_entry_by_id (table, 3, "afs@NADA.KTH.SE");
455
456     rtbl_set_separator (table, "  ");
457
458     rtbl_format (table, stdout);
459
460     rtbl_destroy (table);
461
462     printf("\n");
463
464     table = rtbl_create ();
465     rtbl_add_column_by_id (table, 0, "Column A", 0);
466     rtbl_set_column_affix_by_id (table, 0, "<", ">");
467     rtbl_add_column_by_id (table, 1, "Column B", 0);
468     rtbl_set_column_affix_by_id (table, 1, "[", "]");
469     rtbl_add_column_by_id (table, 2, "Column C", 0);
470     rtbl_set_column_affix_by_id (table, 2, "(", ")");
471
472     rtbl_add_column_entry_by_id (table, 0, "1");
473     rtbl_new_row(table);
474     rtbl_add_column_entry_by_id (table, 1, "2");
475     rtbl_new_row(table);
476     rtbl_add_column_entry_by_id (table, 2, "3");
477     rtbl_new_row(table);
478
479     rtbl_set_separator (table, "  ");
480     rtbl_format (table, stdout);
481
482     rtbl_destroy (table);
483
484     return 0;
485 }
486
487 #endif