Coverage Report

Created: 2026-04-12 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdbm/tools/datconv.c
Line
Count
Source
1
/* This file is part of GDBM, the GNU data base manager.
2
   Copyright (C) 1990-2025 Free Software Foundation, Inc.
3
4
   GDBM is free software; you can redistribute it and/or modify
5
   it under the terms of the GNU General Public License as published by
6
   the Free Software Foundation; either version 3, or (at your option)
7
   any later version.
8
9
   GDBM is distributed in the hope that it will be useful,
10
   but WITHOUT ANY WARRANTY; without even the implied warranty of
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
   GNU General Public License for more details.
13
14
   You should have received a copy of the GNU General Public License
15
   along with GDBM. If not, see <http://www.gnu.org/licenses/>.    */
16
17
#include "gdbmtool.h"
18
#include <wctype.h>
19
20
#define DEFFMT(name, type, fmt)     \
21
static int          \
22
0
 name (PAGERFILE *fp, void *ptr, int size)  \
23
0
{                                               \
24
0
  pager_printf (fp, fmt, *(type*) ptr);   \
25
0
  return size;                                  \
26
0
}
Unexecuted instantiation: datconv.c:f_char
Unexecuted instantiation: datconv.c:f_short
Unexecuted instantiation: datconv.c:f_ushort
Unexecuted instantiation: datconv.c:f_int
Unexecuted instantiation: datconv.c:f_uint
Unexecuted instantiation: datconv.c:f_long
Unexecuted instantiation: datconv.c:f_ulong
Unexecuted instantiation: datconv.c:f_llong
Unexecuted instantiation: datconv.c:f_ullong
Unexecuted instantiation: datconv.c:f_float
Unexecuted instantiation: datconv.c:f_double
27
28
DEFFMT (f_char, char, "%c")
29
DEFFMT (f_short, short, "%hd")
30
DEFFMT (f_ushort, unsigned short, "%hu")
31
DEFFMT (f_int, int, "%d")
32
DEFFMT (f_uint, unsigned, "%u")
33
DEFFMT (f_long, long, "%ld")
34
DEFFMT (f_ulong, unsigned long, "%lu")
35
DEFFMT (f_llong, long long, "%lld")
36
DEFFMT (f_ullong, unsigned long long, "%llu")
37
DEFFMT (f_float, float, "%f")
38
DEFFMT (f_double, double, "%e")
39
40
static int
41
f_stringz (PAGERFILE *fp, void *ptr, int size)
42
0
{
43
0
  wchar_t wc;
44
0
  char *str = ptr;
45
0
  int i;
46
47
0
  mbtowc (NULL, NULL, 0);
48
0
  for (i = 0; i < size; )
49
0
    {
50
0
      int n = mbtowc (&wc, &str[i], MB_CUR_MAX);
51
0
      if (n == 0)
52
0
  break;
53
0
      if (n == -1 || !iswprint (wc))
54
0
  {
55
0
    int c;
56
0
    if ((c = escape (str[i])))
57
0
      pager_printf (fp, "\\%c", c);
58
0
    else
59
0
      pager_printf (fp, "\\%03o", *(unsigned char*)(str+i));
60
0
    i++;
61
0
  }
62
0
      else
63
0
  {
64
0
    pager_write (fp, str + i, n);
65
0
    i += n;
66
0
  }
67
0
    }
68
0
  return i + 1;
69
0
}
70
71
static int
72
f_string (PAGERFILE *fp, void *ptr, int size)
73
392
{
74
392
  wchar_t wc;
75
392
  char *str = ptr;
76
392
  int i;
77
  
78
392
  mbtowc (NULL, NULL, 0);
79
1.29M
  for (i = 0; i < size; )
80
1.29M
    {
81
1.29M
      int n = mbtowc (&wc, &str[i], MB_CUR_MAX);
82
1.29M
      if (n == 0)
83
1.00M
  {
84
1.00M
    pager_printf (fp, "\\%03o", *(unsigned char*)(str+i));
85
1.00M
    i++;
86
1.00M
  }
87
282k
      else if (n == -1 || !iswprint (wc))
88
198k
  {
89
198k
    int c;
90
198k
    if ((c = escape (str[i])))
91
15.3k
      pager_printf (fp, "\\%c", c);
92
183k
    else
93
183k
      pager_printf (fp, "\\%03o", *(unsigned char*)(str+i));
94
198k
    i++;
95
198k
  }
96
83.2k
      else
97
83.2k
  {
98
83.2k
    pager_write (fp, str + i, n);
99
83.2k
    i += n;
100
83.2k
  }
101
1.29M
    }
102
392
  return i;
103
392
}
104

105
int
106
s_char (struct xdatum *xd, char *str)
107
0
{
108
0
  xd_store (xd, str, 1);
109
0
  return 0;
110
0
}
111
112
#define DEFNSCAN(name, type, temptype, strto) \
113
int           \
114
0
name (struct xdatum *xd, char *str)             \
115
0
{                                               \
116
0
  temptype n;                                   \
117
0
  type t;                                       \
118
0
  char *p;                                      \
119
0
                                                \
120
0
  errno = 0;                                    \
121
0
  n = strto (str, &p, 0);                       \
122
0
  if (*p)                                       \
123
0
    return 1;                                   \
124
0
  if (errno == ERANGE || (t = n) != n)          \
125
0
    return 1;                                   \
126
0
  xd_store (xd, &t, sizeof (t));                \
127
0
  return 0;                                     \
128
0
}
129
130
0
DEFNSCAN(s_short, short, long, strtol);
131
0
DEFNSCAN(s_ushort, unsigned short, unsigned long, strtoul);
132
0
DEFNSCAN(s_int, int, long, strtol)
133
0
DEFNSCAN(s_uint, unsigned, unsigned long, strtol)
134
0
DEFNSCAN(s_long, long, long, strtoul)
135
0
DEFNSCAN(s_ulong, unsigned long, unsigned long, strtoul)
136
0
DEFNSCAN(s_llong, long long, long long, strtoll)
137
0
DEFNSCAN(s_ullong, unsigned long long, unsigned long long, strtoull)
138
139
int
140
s_double (struct xdatum *xd, char *str)
141
0
{
142
0
  double d;
143
0
  char *p;
144
  
145
0
  errno = 0;
146
0
  d = strtod (str, &p);
147
0
  if (errno || *p)
148
0
    return 1;
149
0
  xd_store (xd, &d, sizeof (d));
150
0
  return 0;
151
0
}
152
153
int
154
s_float (struct xdatum *xd, char *str)
155
0
{
156
0
  float d;
157
0
  char *p;
158
  
159
0
  errno = 0;
160
0
  d = strtod (str, &p);
161
0
  if (errno || *p)
162
0
    return 1;
163
0
  xd_store (xd, &d, sizeof (d));
164
0
  return 0;
165
0
}
166
167
int
168
s_stringz (struct xdatum *xd, char *str)
169
0
{
170
0
  xd_store (xd, str, strlen (str) + 1);
171
0
  return 0;
172
0
}
173
174
int
175
s_string (struct xdatum *xd, char *str)
176
9.48k
{
177
9.48k
  xd_store (xd, str, strlen (str));
178
9.48k
  return 0;
179
9.48k
}
180
181
static struct datadef datatab[] = {
182
  { "char",     sizeof(char),      f_char, s_char },
183
  { "short",    sizeof(short),     f_short, s_short },
184
  { "ushort",   sizeof(unsigned short), f_ushort, s_ushort },
185
  { "int",      sizeof(int),       f_int, s_int  },
186
  { "unsigned", sizeof(unsigned),  f_uint, s_uint },
187
  { "uint",     sizeof(unsigned),  f_uint, s_uint },
188
  { "long",     sizeof(long),      f_long, s_long },
189
  { "ulong",    sizeof(unsigned long),     f_ulong, s_ulong },
190
  { "llong",    sizeof(long long), f_llong, s_llong },
191
  { "ullong",   sizeof(unsigned long long), f_ullong, s_ullong },
192
  { "float",    sizeof(float),     f_float, s_float }, 
193
  { "double",   sizeof(double),    f_double, s_double },
194
  { "stringz",  0, f_stringz, s_stringz },
195
  { "string",   0, f_string, s_string },
196
  { NULL }
197
};
198
199
struct datadef *
200
datadef_lookup (const char *name)
201
5.13k
{
202
5.13k
  struct datadef *p;
203
204
71.8k
  for (p = datatab; p->name; p++)
205
71.8k
    if (strcmp (p->name, name) == 0)
206
5.13k
      return p;
207
0
  return NULL;
208
5.13k
}
209

210
struct dsegm *
211
dsegm_new (int type)
212
5.13k
{
213
5.13k
  struct dsegm *p = emalloc (sizeof (*p));
214
5.13k
  p->next = NULL;
215
5.13k
  p->type = type;
216
5.13k
  return p;
217
5.13k
}
218
219
struct dsegm *
220
dsegm_new_field (struct datadef *type, char *id, int dim)
221
5.13k
{
222
5.13k
  struct dsegm *p = dsegm_new (FDEF_FLD);
223
5.13k
  p->v.field.type = type;
224
5.13k
  p->v.field.name = id;
225
5.13k
  p->v.field.dim = dim;
226
5.13k
  return p;
227
5.13k
}
228
229
void
230
dsegm_list_free (struct dsegm *dp)
231
5.13k
{
232
10.2k
  while (dp)
233
5.13k
    {
234
5.13k
      struct dsegm *next = dp->next;
235
5.13k
      if (dp->type == FDEF_FLD)
236
5.13k
  free (dp->v.field.name);
237
5.13k
      free (dp);
238
5.13k
      dp = next;
239
5.13k
    }
240
5.13k
}
241
242
struct dsegm *
243
dsegm_list_find (struct dsegm *dp, char const *name)
244
0
{
245
0
  for (; dp; dp = dp->next)
246
0
    if (dp->type == FDEF_FLD && dp->v.field.name &&
247
0
  strcmp (dp->v.field.name, name) == 0)
248
0
      break;
249
0
  return dp;
250
0
}
251
252
void
253
datum_format (PAGERFILE *fp, datum const *dat, struct dsegm *ds)
254
392
{
255
392
  int off = 0;
256
392
  char *delim[2];
257
392
  int first_field = 1;
258
  
259
392
  if (!ds)
260
0
    {
261
0
      pager_printf (fp, "%.*s\n", dat->dsize, dat->dptr);
262
0
      return;
263
0
    }
264
265
392
  if (variable_get ("delim1", VART_STRING, (void*) &delim[0]))
266
0
    abort ();
267
392
  if (variable_get ("delim2", VART_STRING, (void*) &delim[1]))
268
0
    abort ();
269
  
270
784
  for (; ds && off <= dat->dsize; ds = ds->next)
271
392
    {
272
392
      switch (ds->type)
273
392
  {
274
392
  case FDEF_FLD:
275
392
    if (!first_field)
276
0
      pager_writez (fp, delim[1]);
277
392
    if (ds->v.field.name)
278
0
      pager_printf (fp, "%s=", ds->v.field.name);
279
392
    if (ds->v.field.dim > 1)
280
0
      pager_printf (fp, "{ ");
281
392
    if (ds->v.field.type->format)
282
392
      {
283
392
        int i, n;
284
285
784
        for (i = 0; i < ds->v.field.dim; i++)
286
392
    {
287
392
      if (i)
288
0
        pager_write (fp, delim[0], strlen (delim[0]));
289
392
      if (off + ds->v.field.type->size > dat->dsize)
290
0
        {
291
0
          pager_printf (fp, _("(not enough data)"));
292
0
          off += dat->dsize;
293
0
          break;
294
0
        }
295
392
      else
296
392
        {
297
392
          n = ds->v.field.type->format (fp,
298
392
                (char*) dat->dptr + off,
299
392
                ds->v.field.type->size ?
300
0
                  ds->v.field.type->size :
301
392
                  dat->dsize - off);
302
392
          off += n;
303
392
        }
304
392
    }
305
392
      }
306
392
    if (ds->v.field.dim > 1)
307
0
      pager_printf (fp, " }");
308
392
    first_field = 0;
309
392
    break;
310
    
311
0
  case FDEF_OFF:
312
0
    off = ds->v.n;
313
0
    break;
314
    
315
0
  case FDEF_PAD:
316
0
    off += ds->v.n;
317
0
    break;
318
392
  }
319
392
    }
320
392
}
321
322
void
323
datum_format_file (FILE *fp, datum const *dat, struct dsegm *ds)
324
0
{
325
0
  PAGERFILE *pager = pager_open (fp, 0, NULL);
326
0
  datum_format (pager, dat, ds);
327
0
  pager_close (pager);
328
0
}
329

330
struct xdatum
331
{
332
  char *dptr;
333
  size_t dsize;
334
  size_t dmax;
335
  int off;
336
};
337
338
void
339
xd_expand (struct xdatum *xd, size_t size)
340
9.48k
{
341
9.48k
  if (xd->dmax < size || 1)
342
9.48k
    {
343
9.48k
      xd->dptr = erealloc (xd->dptr, size);
344
9.48k
      memset (xd->dptr + xd->dmax, 0, size - xd->dmax);
345
9.48k
      xd->dmax = size;
346
9.48k
    }
347
9.48k
}
348
  
349
void
350
xd_store (struct xdatum *xd, void *val, size_t size)
351
9.48k
{
352
9.48k
  xd_expand (xd, xd->off + size);
353
9.48k
  memcpy (xd->dptr + xd->off, val, size);
354
9.48k
  xd->off += size;
355
9.48k
  if (xd->off > xd->dsize)
356
9.48k
    xd->dsize = xd->off;
357
9.48k
} 
358

359
static int
360
dsconv (struct xdatum *xd, struct dsegm *ds, struct kvpair *kv)
361
9.48k
{
362
9.48k
  int i;
363
9.48k
  int err = 0;
364
9.48k
  struct slist *s;
365
  
366
9.48k
  if (!ds->v.field.type->scan)
367
0
    abort ();
368
  
369
9.48k
  if (kv->type == KV_STRING && ds->v.field.dim > 1)
370
0
    {
371
      /* If a char[] value was supplied as a quoted string.
372
   convert it to list for further processing */
373
0
      if (ds->v.field.type->size == 1)
374
0
  {
375
0
    struct slist *head = slist_new_l (kv->val.s, 1);
376
0
    struct slist *tail = head;
377
0
    char *p;
378
0
    for (p = kv->val.s + 1; *p; p++)
379
0
      slist_insert (&tail, slist_new_l (p, 1));
380
0
    free (kv->val.s);
381
0
    kv->val.l = head;
382
0
    kv->type = KV_LIST;
383
0
  }
384
0
    }
385
    
386
9.48k
  switch (kv->type)
387
9.48k
    {
388
9.48k
    case KV_STRING:
389
9.48k
      err = ds->v.field.type->scan (xd, kv->val.s);
390
9.48k
      if (err)
391
0
  lerror (&kv->loc, _("cannot convert"));
392
9.48k
      break;
393
        
394
0
    case KV_LIST:
395
0
      for (i = 0, s = kv->val.l; i < ds->v.field.dim && s; i++, s = s->next)
396
0
  {
397
0
    err = ds->v.field.type->scan (xd, s->str);
398
0
    if (err)
399
0
      {
400
0
        lerror (&kv->loc, _("cannot convert value #%d: %s"), i, s->str);
401
0
        break;
402
0
      }
403
0
  }
404
0
      if (s)
405
0
  {
406
0
    lerror (&kv->loc, "surplus initializers ignored");
407
0
    err = 1;
408
0
  }
409
9.48k
    }
410
9.48k
  return err;
411
9.48k
}
412
  
413
static int
414
datum_scan_notag (datum *dat, struct dsegm *ds, struct kvpair *kv)
415
9.48k
{
416
9.48k
  struct xdatum xd;
417
9.48k
  int err = 0;
418
  
419
9.48k
  memset (&xd, 0, sizeof (xd));
420
  
421
18.9k
  for (; err == 0 && ds && kv; ds = ds->next)
422
9.48k
    {
423
9.48k
      if (kv->key)
424
0
  {
425
0
    lerror (&kv->loc,
426
0
           _("mixing tagged and untagged values is not allowed"));
427
0
    err = 1;
428
0
    break;
429
0
  }
430
      
431
9.48k
      switch (ds->type)
432
9.48k
  {
433
9.48k
  case FDEF_FLD:
434
9.48k
    err = dsconv (&xd, ds, kv);
435
9.48k
    kv = kv->next;
436
9.48k
    break;
437
438
0
  case FDEF_OFF:
439
0
    xd_expand (&xd, ds->v.n);
440
0
    xd.off = ds->v.n;
441
0
    break;
442
    
443
0
  case FDEF_PAD:
444
0
    xd_expand (&xd, xd.off + ds->v.n);
445
0
    xd.off += ds->v.n;
446
0
    break;
447
9.48k
  }
448
9.48k
    }
449
450
9.48k
  if (err)
451
0
    {
452
0
      free (xd.dptr);
453
0
      return 1;
454
0
    }
455
456
9.48k
  dat->dptr  = xd.dptr;
457
9.48k
  dat->dsize = xd.dsize;
458
      
459
9.48k
  return 0;
460
9.48k
}
461
462
static int
463
datum_scan_tag (datum *dat, struct dsegm *ds, struct kvpair *kvlist)
464
0
{
465
0
  struct xdatum xd;
466
0
  int err = 0;
467
0
  struct kvpair *kv;
468
469
  /* Check keywords for consistency */
470
0
  for (kv = kvlist; kv; kv = kv->next)
471
0
    {
472
0
      if (!kv->key)
473
0
  {
474
0
    lerror (&kv->loc,
475
0
      _("mixing tagged and untagged values is not allowed"));
476
0
    return 1;
477
0
  }
478
0
      if (!dsegm_list_find (ds, kv->key))
479
0
  {
480
0
    lerror (&kv->loc, _("%s: no such field in datum"), kv->key);
481
0
    return 1;
482
0
  }
483
0
    }
484
485
  /* Initialize datum */
486
0
  memset (&xd, 0, sizeof (xd));
487
488
0
  for (; err == 0 && ds; ds = ds->next)
489
0
    {
490
0
      switch (ds->type)
491
0
  {
492
0
  case FDEF_FLD:
493
0
    kv = kvlist_find (kvlist, ds->v.field.name);
494
0
    if (kv)
495
0
      err = dsconv (&xd, ds, kv);
496
0
    else
497
0
      {
498
0
        size_t sz = ds->v.field.type->size * ds->v.field.dim;
499
0
        xd_expand (&xd, xd.off + sz);
500
0
        xd.off += sz;
501
0
      }
502
0
    break;
503
504
0
  case FDEF_OFF:
505
0
    xd_expand (&xd, ds->v.n);
506
0
    xd.off = ds->v.n;
507
0
    break;
508
    
509
0
  case FDEF_PAD:
510
0
    xd_expand (&xd, xd.off + ds->v.n);
511
0
    xd.off += ds->v.n;
512
0
    break;
513
0
  }
514
0
    }
515
516
0
  if (err)
517
0
    {
518
0
      free (xd.dptr);
519
0
      return 1;
520
0
    }
521
522
0
  dat->dptr  = xd.dptr;
523
0
  dat->dsize = xd.dsize;
524
      
525
0
  return 0;
526
0
}
527
528
int
529
datum_scan (datum *dat, struct dsegm *ds, struct kvpair *kv)
530
9.48k
{
531
9.48k
  return (kv->key ? datum_scan_tag : datum_scan_notag) (dat, ds, kv);
532
9.48k
}
533
534
void
535
dsprint (PAGERFILE *fp, int what, struct dsegm *ds)
536
3.79k
{
537
3.79k
  static char *dsstr[] = { "key", "content" };
538
3.79k
  int delim;
539
  
540
3.79k
  pager_printf (fp, "define %s", dsstr[what]);
541
3.79k
  if (ds->next)
542
0
    {
543
0
      pager_printf (fp, " {\n");
544
0
      delim = '\t';
545
0
    }
546
3.79k
  else
547
3.79k
    delim = ' ';
548
7.58k
  for (; ds; ds = ds->next)
549
3.79k
    {
550
3.79k
      switch (ds->type)
551
3.79k
  {
552
3.79k
  case FDEF_FLD:
553
3.79k
    pager_printf (fp, "%c%s", delim, ds->v.field.type->name);
554
3.79k
    if (ds->v.field.name)
555
0
      pager_printf (fp, " %s", ds->v.field.name);
556
3.79k
    if (ds->v.field.dim > 1)
557
0
      pager_printf (fp, "[%d]", ds->v.field.dim);
558
3.79k
    break;
559
    
560
0
  case FDEF_OFF:
561
0
    pager_printf (fp, "%coffset %d", delim, ds->v.n);
562
0
    break;
563
564
0
  case FDEF_PAD:
565
0
    pager_printf (fp, "%cpad %d", delim, ds->v.n);
566
0
    break;
567
3.79k
  }
568
3.79k
      if (ds->next)
569
0
  pager_putc (fp, ',');
570
3.79k
      pager_putc (fp, '\n');
571
3.79k
    }
572
3.79k
  if (delim == '\t')
573
0
    pager_writeln (fp, "}");
574
3.79k
}