Coverage Report

Created: 2026-05-24 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/third_party/heimdal/lib/roken/rtbl.c
Line
Count
Source
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 <ctype.h>
38
#include "rtbl.h"
39
40
struct column_entry {
41
    char *data;
42
};
43
44
struct column_data {
45
    char *header;
46
    char *prefix;
47
    int width;
48
    unsigned flags;
49
    size_t num_rows;
50
    struct column_entry *rows;
51
    unsigned int column_id;
52
    char *suffix;
53
};
54
55
struct rtbl_data {
56
    char *column_prefix;
57
    size_t num_columns;
58
    struct column_data **columns;
59
    unsigned int flags;
60
    char *column_separator;
61
};
62
63
ROKEN_LIB_FUNCTION rtbl_t ROKEN_LIB_CALL
64
rtbl_create (void)
65
0
{
66
0
    return calloc (1, sizeof (struct rtbl_data));
67
0
}
68
69
ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
70
rtbl_set_flags (rtbl_t table, unsigned int flags)
71
0
{
72
0
    table->flags = flags;
73
0
}
74
75
ROKEN_LIB_FUNCTION unsigned int ROKEN_LIB_CALL
76
rtbl_get_flags (rtbl_t table)
77
0
{
78
0
    return table->flags;
79
0
}
80
81
static struct column_data *
82
rtbl_get_column_by_id (rtbl_t table, unsigned int id)
83
0
{
84
0
    size_t i;
85
0
    for(i = 0; i < table->num_columns; i++)
86
0
  if(table->columns[i]->column_id == id)
87
0
      return table->columns[i];
88
0
    return NULL;
89
0
}
90
91
static struct column_data *
92
rtbl_get_column (rtbl_t table, const char *column)
93
0
{
94
0
    size_t i;
95
0
    for(i = 0; i < table->num_columns; i++)
96
0
  if(strcmp(table->columns[i]->header, column) == 0)
97
0
      return table->columns[i];
98
0
    return NULL;
99
0
}
100
101
ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
102
rtbl_destroy (rtbl_t table)
103
0
{
104
0
    size_t i, j;
105
106
0
    for (i = 0; i < table->num_columns; i++) {
107
0
  struct column_data *c = table->columns[i];
108
109
0
  for (j = 0; j < c->num_rows; j++)
110
0
      free (c->rows[j].data);
111
0
  free (c->rows);
112
0
  free (c->header);
113
0
  free (c->prefix);
114
0
  free (c->suffix);
115
0
  free (c);
116
0
    }
117
0
    free (table->column_prefix);
118
0
    free (table->column_separator);
119
0
    free (table->columns);
120
0
    free (table);
121
0
}
122
123
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
124
rtbl_add_column_by_id (rtbl_t table, unsigned int id,
125
           const char *header, unsigned int flags)
126
0
{
127
0
    struct column_data *col, **tmp;
128
129
0
    tmp = realloc (table->columns, (table->num_columns + 1) * sizeof (*tmp));
130
0
    if (tmp == NULL)
131
0
  return ENOMEM;
132
0
    table->columns = tmp;
133
0
    col = malloc (sizeof (*col));
134
0
    if (col == NULL)
135
0
  return ENOMEM;
136
0
    col->header = strdup (header);
137
0
    if (col->header == NULL) {
138
0
  free (col);
139
0
  return ENOMEM;
140
0
    }
141
0
    col->prefix = NULL;
142
0
    col->width = 0;
143
0
    col->flags = flags;
144
0
    col->num_rows = 0;
145
0
    col->rows = NULL;
146
0
    col->column_id = id;
147
0
    col->suffix = NULL;
148
0
    table->columns[table->num_columns++] = col;
149
0
    return 0;
150
0
}
151
152
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
153
rtbl_add_column (rtbl_t table, const char *header, unsigned int flags)
154
0
{
155
0
    return rtbl_add_column_by_id(table, 0, header, flags);
156
0
}
157
158
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
159
rtbl_new_row(rtbl_t table)
160
0
{
161
0
    size_t max_rows = 0;
162
0
    size_t c;
163
0
    for (c = 0; c < table->num_columns; c++)
164
0
  if(table->columns[c]->num_rows > max_rows)
165
0
      max_rows = table->columns[c]->num_rows;
166
0
    for (c = 0; c < table->num_columns; c++) {
167
0
  struct column_entry *tmp;
168
169
0
  if(table->columns[c]->num_rows == max_rows)
170
0
      continue;
171
0
  tmp = realloc(table->columns[c]->rows,
172
0
          max_rows * sizeof(table->columns[c]->rows[0]));
173
0
  if(tmp == NULL)
174
0
      return ENOMEM;
175
0
  table->columns[c]->rows = tmp;
176
0
  while(table->columns[c]->num_rows < max_rows) {
177
0
      if((tmp[table->columns[c]->num_rows++].data = strdup("")) == NULL)
178
0
    return ENOMEM;
179
0
  }
180
0
    }
181
0
    return 0;
182
0
}
183
184
static void
185
column_compute_width (rtbl_t table, struct column_data *column)
186
0
{
187
0
    size_t i;
188
189
0
    if(table->flags & RTBL_HEADER_STYLE_NONE)
190
0
  column->width = 0;
191
0
    else
192
0
  column->width = (int)strlen (column->header);
193
0
    for (i = 0; i < column->num_rows; i++)
194
0
  column->width = max (column->width, (int) strlen (column->rows[i].data));
195
0
}
196
197
/* DEPRECATED */
198
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
199
rtbl_set_prefix (rtbl_t table, const char *prefix)
200
0
{
201
0
    if (table->column_prefix)
202
0
  free (table->column_prefix);
203
0
    table->column_prefix = strdup (prefix);
204
0
    if (table->column_prefix == NULL)
205
0
  return ENOMEM;
206
0
    return 0;
207
0
}
208
209
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
210
rtbl_set_separator (rtbl_t table, const char *separator)
211
0
{
212
0
    if (table->column_separator)
213
0
  free (table->column_separator);
214
0
    table->column_separator = strdup (separator);
215
0
    if (table->column_separator == NULL)
216
0
  return ENOMEM;
217
0
    return 0;
218
0
}
219
220
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
221
rtbl_set_column_prefix (rtbl_t table, const char *column,
222
      const char *prefix)
223
0
{
224
0
    struct column_data *c = rtbl_get_column (table, column);
225
226
0
    if (c == NULL)
227
0
  return -1;
228
0
    if (c->prefix)
229
0
  free (c->prefix);
230
0
    c->prefix = strdup (prefix);
231
0
    if (c->prefix == NULL)
232
0
  return ENOMEM;
233
0
    return 0;
234
0
}
235
236
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
237
rtbl_set_column_affix_by_id(rtbl_t table, unsigned int id,
238
          const char *prefix, const char *suffix)
239
0
{
240
0
    struct column_data *c = rtbl_get_column_by_id (table, id);
241
242
0
    if (c == NULL)
243
0
  return -1;
244
0
    if (c->prefix)
245
0
  free (c->prefix);
246
0
    if(prefix == NULL)
247
0
  c->prefix = NULL;
248
0
    else {
249
0
  c->prefix = strdup (prefix);
250
0
  if (c->prefix == NULL)
251
0
      return ENOMEM;
252
0
    }
253
254
0
    if (c->suffix)
255
0
  free (c->suffix);
256
0
    if(suffix == NULL)
257
0
  c->suffix = NULL;
258
0
    else {
259
0
  c->suffix = strdup (suffix);
260
0
  if (c->suffix == NULL)
261
0
      return ENOMEM;
262
0
    }
263
0
    return 0;
264
0
}
265
266
267
static const char *
268
get_column_prefix (rtbl_t table, struct column_data *c)
269
0
{
270
0
    if (c == NULL)
271
0
  return "";
272
0
    if (c->prefix)
273
0
  return c->prefix;
274
0
    if (table->column_prefix)
275
0
  return table->column_prefix;
276
0
    return "";
277
0
}
278
279
static const char *
280
get_column_suffix (rtbl_t table, struct column_data *c)
281
0
{
282
0
    if (c && c->suffix)
283
0
  return c->suffix;
284
0
    return "";
285
0
}
286
287
static int
288
add_column_entry (struct column_data *c, const char *data)
289
0
{
290
0
    struct column_entry row, *tmp;
291
292
0
    row.data = strdup (data);
293
0
    if (row.data == NULL)
294
0
  return ENOMEM;
295
0
    tmp = realloc (c->rows, (c->num_rows + 1) * sizeof (*tmp));
296
0
    if (tmp == NULL) {
297
0
  free (row.data);
298
0
  return ENOMEM;
299
0
    }
300
0
    c->rows = tmp;
301
0
    c->rows[c->num_rows++] = row;
302
0
    return 0;
303
0
}
304
305
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
306
rtbl_add_column_entry_by_id (rtbl_t table, unsigned int id, const char *data)
307
0
{
308
0
    struct column_data *c = rtbl_get_column_by_id (table, id);
309
310
0
    if (c == NULL)
311
0
  return -1;
312
313
0
    return add_column_entry(c, data);
314
0
}
315
316
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
317
rtbl_add_column_entryv_by_id (rtbl_t table, unsigned int id,
318
            const char *fmt, ...)
319
0
{
320
0
    va_list ap;
321
0
    char *str;
322
0
    int ret;
323
324
0
    va_start(ap, fmt);
325
0
    ret = vasprintf(&str, fmt, ap);
326
0
    va_end(ap);
327
0
    if (ret == -1)
328
0
  return -1;
329
0
    ret = rtbl_add_column_entry_by_id(table, id, str);
330
0
    free(str);
331
0
    return ret;
332
0
}
333
334
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
335
rtbl_add_column_entry (rtbl_t table, const char *column, const char *data)
336
0
{
337
0
    struct column_data *c = rtbl_get_column (table, column);
338
339
0
    if (c == NULL)
340
0
  return -1;
341
342
0
    return add_column_entry(c, data);
343
0
}
344
345
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
346
rtbl_add_column_entryv (rtbl_t table, const char *column, const char *fmt, ...)
347
0
{
348
0
    va_list ap;
349
0
    char *str;
350
0
    int ret;
351
352
0
    va_start(ap, fmt);
353
0
    ret = vasprintf(&str, fmt, ap);
354
0
    va_end(ap);
355
0
    if (ret == -1)
356
0
  return -1;
357
0
    ret = rtbl_add_column_entry(table, column, str);
358
0
    free(str);
359
0
    return ret;
360
0
}
361
362
363
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
364
rtbl_format (rtbl_t table, FILE * f)
365
0
{
366
0
    char *str = rtbl_format_str(table);
367
0
    if (str == NULL)
368
0
  return ENOMEM;
369
0
    fprintf(f, "%s", str);
370
0
    free(str);
371
0
    return 0;
372
0
}
373
374
static char *
375
rtbl_format_pretty(rtbl_t table)
376
0
{
377
0
    struct rk_strpool *p = NULL;
378
0
    size_t i, j;
379
380
0
    for (i = 0; i < table->num_columns; i++)
381
0
  column_compute_width (table, table->columns[i]);
382
0
    if((table->flags & RTBL_HEADER_STYLE_NONE) == 0) {
383
0
  for (i = 0; i < table->num_columns; i++) {
384
0
      struct column_data *c = table->columns[i];
385
386
0
      if(table->column_separator != NULL && i > 0)
387
0
    p = rk_strpoolprintf(p, "%s", table->column_separator);
388
0
      p = rk_strpoolprintf(p, "%s", get_column_prefix (table, c));
389
0
      if (c == NULL) {
390
    /* do nothing if no column */
391
0
      } else if(i == table->num_columns - 1 && c->suffix == NULL)
392
    /* last column, so no need to pad with spaces */
393
0
    p = rk_strpoolprintf(p, "%-*s", 0, c->header);
394
0
      else
395
0
    p = rk_strpoolprintf(p, "%-*s", (int)c->width, c->header);
396
0
      p = rk_strpoolprintf(p, "%s", get_column_suffix (table, c));
397
0
  }
398
0
  p = rk_strpoolprintf(p, "\n");
399
0
    }
400
401
0
    for (j = 0;; j++) {
402
0
  int flag = 0;
403
404
  /* are there any more rows left? */
405
0
  for (i = 0; flag == 0 && i < table->num_columns; ++i) {
406
0
      struct column_data *c = table->columns[i];
407
408
0
      if (c->num_rows > j) {
409
0
    ++flag;
410
0
    break;
411
0
      }
412
0
  }
413
0
  if (flag == 0)
414
0
      break;
415
416
0
  for (i = 0; i < table->num_columns; i++) {
417
0
      int w;
418
0
      struct column_data *c = table->columns[i];
419
420
0
      if(table->column_separator != NULL && i > 0)
421
0
    p = rk_strpoolprintf(p, "%s", table->column_separator);
422
423
0
      w = c->width;
424
425
0
      if ((c->flags & RTBL_ALIGN_RIGHT) == 0) {
426
0
    if(i == table->num_columns - 1 && c->suffix == NULL)
427
        /* last column, so no need to pad with spaces */
428
0
        w = 0;
429
0
    else
430
0
        w = -w;
431
0
      }
432
0
      p = rk_strpoolprintf(p, "%s", get_column_prefix (table, c));
433
0
      if (c->num_rows <= j)
434
0
    p = rk_strpoolprintf(p, "%*s", w, "");
435
0
      else
436
0
    p = rk_strpoolprintf(p, "%*s", w, c->rows[j].data);
437
0
      p = rk_strpoolprintf(p, "%s", get_column_suffix (table, c));
438
0
  }
439
0
  p = rk_strpoolprintf(p, "\n");
440
0
    }
441
442
0
    return rk_strpoolcollect(p);
443
0
}
444
445
static char *
446
rtbl_format_json(rtbl_t table)
447
0
{
448
0
    struct rk_strpool *p = NULL;
449
0
    size_t i, j;
450
0
    int comma;
451
452
0
    p = rk_strpoolprintf(p, "[");
453
0
    for (j = 0;; j++) {
454
0
  int flag = 0;
455
456
  /* are there any more rows left? */
457
0
  for (i = 0; flag == 0 && i < table->num_columns; ++i) {
458
0
      struct column_data *c = table->columns[i];
459
460
0
      if (c->num_rows > j) {
461
0
    ++flag;
462
0
    break;
463
0
      }
464
0
  }
465
0
  if (flag == 0)
466
0
      break;
467
468
0
  p = rk_strpoolprintf(p, "%s{", j > 0 ? "," : "");
469
470
0
  comma = 0;
471
0
  for (i = 0; i < table->num_columns; i++) {
472
0
      struct column_data *c = table->columns[i];
473
474
0
      if (c->num_rows > j) {
475
0
    char *header = c->header;
476
0
    while (isspace((unsigned char)header[0])) /* trim off prefixed whitespace */
477
0
        header++;
478
0
    p = rk_strpoolprintf(p, "%s\"%s\" : \"%s\"",
479
0
             comma ? "," : "", header,
480
0
             c->rows[j].data);
481
0
    comma = 1;
482
0
      }
483
0
  }
484
0
  p = rk_strpoolprintf(p, "}");
485
0
    }
486
0
    p = rk_strpoolprintf(p, "]");
487
488
0
    return rk_strpoolcollect(p);
489
0
}
490
491
ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
492
rtbl_format_str (rtbl_t table)
493
0
{
494
0
    if (table->flags & RTBL_JSON)
495
0
  return rtbl_format_json(table);
496
497
0
    return rtbl_format_pretty(table);
498
0
}
499
500
#ifdef TEST
501
int
502
main (int argc, char **argv)
503
{
504
    rtbl_t table;
505
506
    table = rtbl_create ();
507
    rtbl_add_column_by_id (table, 0, "Issued", 0);
508
    rtbl_add_column_by_id (table, 1, "Expires", 0);
509
    rtbl_add_column_by_id (table, 2, "Foo", RTBL_ALIGN_RIGHT);
510
    rtbl_add_column_by_id (table, 3, "Principal", 0);
511
512
    rtbl_add_column_entry_by_id (table, 0, "Jul  7 21:19:29");
513
    rtbl_add_column_entry_by_id (table, 1, "Jul  8 07:19:29");
514
    rtbl_add_column_entry_by_id (table, 2, "73");
515
    rtbl_add_column_entry_by_id (table, 2, "0");
516
    rtbl_add_column_entry_by_id (table, 2, "-2000");
517
    rtbl_add_column_entry_by_id (table, 3, "krbtgt/NADA.KTH.SE@NADA.KTH.SE");
518
519
    rtbl_add_column_entry_by_id (table, 0, "Jul  7 21:19:29");
520
    rtbl_add_column_entry_by_id (table, 1, "Jul  8 07:19:29");
521
    rtbl_add_column_entry_by_id (table, 3, "afs/pdc.kth.se@NADA.KTH.SE");
522
523
    rtbl_add_column_entry_by_id (table, 0, "Jul  7 21:19:29");
524
    rtbl_add_column_entry_by_id (table, 1, "Jul  8 07:19:29");
525
    rtbl_add_column_entry_by_id (table, 3, "afs@NADA.KTH.SE");
526
527
    rtbl_set_separator (table, "  ");
528
529
    rtbl_format (table, stdout);
530
531
    rtbl_destroy (table);
532
533
    printf("\n");
534
535
    table = rtbl_create ();
536
    rtbl_add_column_by_id (table, 0, "Column A", 0);
537
    rtbl_set_column_affix_by_id (table, 0, "<", ">");
538
    rtbl_add_column_by_id (table, 1, "Column B", 0);
539
    rtbl_set_column_affix_by_id (table, 1, "[", "]");
540
    rtbl_add_column_by_id (table, 2, "Column C", 0);
541
    rtbl_set_column_affix_by_id (table, 2, "(", ")");
542
543
    rtbl_add_column_entry_by_id (table, 0, "1");
544
    rtbl_new_row(table);
545
    rtbl_add_column_entry_by_id (table, 1, "2");
546
    rtbl_new_row(table);
547
    rtbl_add_column_entry_by_id (table, 2, "3");
548
    rtbl_new_row(table);
549
550
    rtbl_set_separator (table, "  ");
551
    rtbl_format (table, stdout);
552
553
    rtbl_destroy (table);
554
555
    return 0;
556
}
557
558
#endif