Coverage Report

Created: 2026-09-14 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/src/scconf/scconf.c
Line
Count
Source
1
/*
2
 * $Id$
3
 *
4
 * Copyright (C) 2002
5
 *  Antti Tapaninen <aet@cc.hut.fi>
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
22
#include "config.h"
23
24
#include <stdio.h>
25
#include <stdlib.h>
26
#include <string.h>
27
#ifdef HAVE_STRINGS_H
28
#include <strings.h>
29
#endif
30
#include <ctype.h>
31
#include <limits.h>
32
33
#include "common/compat_strlcat.h"
34
#include "scconf.h"
35
36
scconf_context *scconf_new(const char *filename)
37
16.3k
{
38
16.3k
  scconf_context *config;
39
40
16.3k
  config = calloc(1, sizeof(scconf_context));
41
16.3k
  if (!config) {
42
0
    return NULL;
43
0
  }
44
16.3k
  config->filename = filename ? strdup(filename) : NULL;
45
16.3k
  config->root = calloc(1, sizeof(scconf_block));
46
16.3k
  if (!config->root) {
47
0
    if (config->filename) {
48
0
      free(config->filename);
49
0
    }
50
0
    free(config);
51
0
    return NULL;
52
0
  }
53
16.3k
  return config;
54
16.3k
}
55
56
void scconf_free(scconf_context * config)
57
16.3k
{
58
16.3k
  if (config) {
59
16.3k
    scconf_block_destroy(config->root);
60
16.3k
    if (config->filename) {
61
16.3k
      free(config->filename);
62
16.3k
    }
63
16.3k
    free(config);
64
16.3k
  }
65
16.3k
}
66
67
const scconf_block *scconf_find_block(const scconf_context * config, const scconf_block * block, const char *item_name)
68
0
{
69
0
  scconf_item *item;
70
71
0
  if (!block) {
72
0
    block = config->root;
73
0
  }
74
0
  if (!item_name) {
75
0
    return NULL;
76
0
  }
77
0
  for (item = block->items; item; item = item->next) {
78
0
    if (item->type == SCCONF_ITEM_TYPE_BLOCK &&
79
0
        strcasecmp(item_name, item->key) == 0) {
80
0
      return item->value.block;
81
0
    }
82
0
  }
83
0
  return NULL;
84
0
}
85
86
scconf_block **scconf_find_blocks(const scconf_context * config, const scconf_block * block, const char *item_name, const char *key)
87
891k
{
88
891k
  scconf_block **blocks = NULL, **tmp;
89
891k
  int alloc_size, size;
90
891k
  scconf_item *item;
91
92
891k
  if (!block) {
93
48.6k
    block = config->root;
94
48.6k
  }
95
891k
  if (!item_name) {
96
0
    return NULL;
97
0
  }
98
891k
  size = 0;
99
891k
  alloc_size = 10;
100
891k
  tmp = (scconf_block **) realloc(blocks, sizeof(scconf_block *) * alloc_size);
101
891k
  if (!tmp) {
102
0
    free(blocks);
103
0
    return NULL;
104
0
  }
105
891k
  blocks = tmp;
106
107
1.78M
  for (item = block->items; item; item = item->next) {
108
891k
    if (item->type == SCCONF_ITEM_TYPE_BLOCK &&
109
48.6k
        strcasecmp(item_name, item->key) == 0) {
110
48.6k
      if (!item->value.block)
111
0
        continue;
112
48.6k
      if (key && strcasecmp(key, item->value.block->name->data)) {
113
32.4k
        continue;
114
32.4k
      }
115
16.2k
      if (size + 1 >= alloc_size) {
116
0
        alloc_size *= 2;
117
0
        tmp = (scconf_block **) realloc(blocks, sizeof(scconf_block *) * alloc_size);
118
0
        if (!tmp) {
119
0
          free(blocks);
120
0
          return NULL;
121
0
        }
122
0
        blocks = tmp;
123
0
      }
124
16.2k
      blocks[size++] = item->value.block;
125
16.2k
    }
126
891k
  }
127
891k
  blocks[size] = NULL;
128
891k
  return blocks;
129
891k
}
130
131
const scconf_list *scconf_find_list(const scconf_block * block, const char *option)
132
147k
{
133
147k
  scconf_item *item;
134
135
147k
  if (!block)
136
33.5k
    return NULL;
137
138
211k
  for (item = block->items; item; item = item->next)
139
113k
    if (item->type == SCCONF_ITEM_TYPE_VALUE && strcasecmp(option, item->key) == 0)
140
16.2k
      return item->value.list;
141
97.4k
  return NULL;
142
113k
}
143
144
const char *scconf_get_str(const scconf_block * block, const char *option, const char *def)
145
35.0k
{
146
35.0k
  const scconf_list *list;
147
148
35.0k
  list = scconf_find_list(block, option);
149
35.0k
  if (!list)
150
35.0k
    return def;
151
152
  /* ignore non 'auto-configured' values */
153
0
  if (*list->data == '@' && *(list->data + strlen(list->data) - 1) == '@')
154
0
    return def;
155
156
0
  return list->data;
157
0
}
158
159
int scconf_get_int(const scconf_block * block, const char *option, int def)
160
16.2k
{
161
16.2k
  const scconf_list *list;
162
16.2k
  long res;
163
164
16.2k
  list = scconf_find_list(block, option);
165
16.2k
  if (!list) {
166
16.2k
    return def;
167
16.2k
  }
168
0
  res = strtol(list->data, NULL, 0);
169
0
  if (res <= INT_MAX) {
170
0
    return (int)res;
171
0
  }
172
0
  return def;
173
0
}
174
175
int scconf_get_bool(const scconf_block * block, const char *option, int def)
176
79.6k
{
177
79.6k
  const scconf_list *list;
178
179
79.6k
  list = scconf_find_list(block, option);
180
79.6k
  if (!list) {
181
79.6k
    return def;
182
79.6k
  }
183
0
  return toupper((int) *list->data) == 'T' || toupper((int) *list->data) == 'Y';
184
79.6k
}
185
186
const char *scconf_put_str(scconf_block * block, const char *option, const char *value)
187
0
{
188
0
  scconf_list *list = NULL;
189
190
0
  scconf_list_add(&list, value);
191
0
  scconf_item_add(NULL, block, NULL, SCCONF_ITEM_TYPE_VALUE, option, list);
192
0
  scconf_list_destroy(list);
193
0
  return value;
194
0
}
195
196
int scconf_put_int(scconf_block * block, const char *option, int value)
197
0
{
198
0
  char *str;
199
200
0
  str = malloc(64);
201
0
  if (!str) {
202
0
    return value;
203
0
  }
204
0
  snprintf(str, 64, "%i", value);
205
0
  scconf_put_str(block, option, str);
206
0
  free(str);
207
0
  return value;
208
0
}
209
210
int scconf_put_bool(scconf_block * block, const char *option, int value)
211
0
{
212
0
  scconf_put_str(block, option, !value ? "false" : "true");
213
0
  return value;
214
0
}
215
216
scconf_item *scconf_item_copy(const scconf_item * src, scconf_item ** dst)
217
0
{
218
0
  scconf_item *ptr, *_dst = NULL, *next = NULL;
219
220
0
  next = calloc(1, sizeof(scconf_item));
221
0
  if (!next) {
222
0
    return NULL;
223
0
  }
224
0
  ptr = next;
225
0
  _dst = next;
226
0
  while (src) {
227
0
    if (!next) {
228
0
      next = calloc(1, sizeof(scconf_item));
229
0
      if (!next) {
230
0
        scconf_item_destroy(ptr);
231
0
        return NULL;
232
0
      }
233
0
      _dst->next = next;
234
0
    }
235
0
    next->type = src->type;
236
0
    switch (src->type) {
237
0
    case SCCONF_ITEM_TYPE_COMMENT:
238
0
      next->value.comment = src->value.comment ? strdup(src->value.comment) : NULL;
239
0
      break;
240
0
    case SCCONF_ITEM_TYPE_BLOCK:
241
0
      scconf_block_copy(src->value.block, &next->value.block);
242
0
      break;
243
0
    case SCCONF_ITEM_TYPE_VALUE:
244
0
      scconf_list_copy(src->value.list, &next->value.list);
245
0
      break;
246
0
    }
247
0
    next->key = src->key ? strdup(src->key) : NULL;
248
0
    _dst = next;
249
0
    next = NULL;
250
0
    src = src->next;
251
0
  }
252
0
  *dst = ptr;
253
0
  return ptr;
254
0
}
255
256
void scconf_item_destroy(scconf_item * item)
257
32.5k
{
258
32.5k
  scconf_item *next;
259
260
64.9k
  while (item) {
261
32.4k
    next = item->next;
262
263
32.4k
    switch (item->type) {
264
0
    case SCCONF_ITEM_TYPE_COMMENT:
265
0
      if (item->value.comment) {
266
0
        free(item->value.comment);
267
0
      }
268
0
      item->value.comment = NULL;
269
0
      break;
270
16.2k
    case SCCONF_ITEM_TYPE_BLOCK:
271
16.2k
      scconf_block_destroy(item->value.block);
272
16.2k
      break;
273
16.2k
    case SCCONF_ITEM_TYPE_VALUE:
274
16.2k
      scconf_list_destroy(item->value.list);
275
16.2k
      break;
276
32.4k
    }
277
278
32.4k
    if (item->key) {
279
32.4k
      free(item->key);
280
32.4k
    }
281
32.4k
    item->key = NULL;
282
32.4k
    free(item);
283
32.4k
    item = next;
284
32.4k
  }
285
32.5k
}
286
287
scconf_block *scconf_block_copy(const scconf_block * src, scconf_block ** dst)
288
0
{
289
0
  if (src) {
290
0
    scconf_block *_dst = NULL;
291
292
0
    _dst = calloc(1, sizeof(scconf_block));
293
0
    if (!_dst) {
294
0
      return NULL;
295
0
    }
296
0
    memset(_dst, 0, sizeof(scconf_block));
297
0
    if (src->name) {
298
0
      scconf_list_copy(src->name, &_dst->name);
299
0
    }
300
0
    if (src->items) {
301
0
      scconf_item_copy(src->items, &_dst->items);
302
0
    }
303
0
    *dst = _dst;
304
0
    return _dst;
305
0
  }
306
0
  return NULL;
307
0
}
308
309
void scconf_block_destroy(scconf_block * block)
310
32.5k
{
311
32.5k
  if (block) {
312
32.5k
    scconf_list_destroy(block->name);
313
32.5k
    scconf_item_destroy(block->items);
314
32.5k
    free(block);
315
32.5k
  }
316
32.5k
}
317
318
scconf_list *scconf_list_add(scconf_list ** list, const char *value)
319
48.6k
{
320
48.6k
  scconf_list *rec, **tmp;
321
322
48.6k
  rec = calloc(1, sizeof(scconf_list));
323
48.6k
  if (!rec) {
324
0
    return NULL;
325
0
  }
326
48.6k
  rec->data = value ? strdup(value) : NULL;
327
328
48.6k
  if (!*list) {
329
32.4k
    *list = rec;
330
32.4k
  } else {
331
32.4k
    for (tmp = list; *tmp; tmp = &(*tmp)->next);
332
16.2k
    *tmp = rec;
333
16.2k
  }
334
48.6k
  return rec;
335
48.6k
}
336
337
scconf_list *scconf_list_copy(const scconf_list * src, scconf_list ** dst)
338
0
{
339
0
  scconf_list *next;
340
341
0
  while (src) {
342
0
    next = src->next;
343
0
    scconf_list_add(dst, src->data);
344
0
    src = next;
345
0
  }
346
0
  return *dst;
347
0
}
348
349
void scconf_list_destroy(scconf_list * list)
350
97.4k
{
351
97.4k
  scconf_list *next;
352
353
146k
  while (list) {
354
48.6k
    next = list->next;
355
48.6k
    if (list->data) {
356
48.6k
      free(list->data);
357
48.6k
    }
358
48.6k
    free(list);
359
48.6k
    list = next;
360
48.6k
  }
361
97.4k
}
362
363
int scconf_list_array_length(const scconf_list * list)
364
0
{
365
0
  int len = 0;
366
367
0
  while (list) {
368
0
    len++;
369
0
    list = list->next;
370
0
  }
371
0
  return len;
372
0
}
373
374
int scconf_list_strings_length(const scconf_list * list)
375
0
{
376
0
  int len = 0;
377
378
0
  while (list && list->data) {
379
0
    len += strlen(list->data) + 1;
380
0
    list = list->next;
381
0
  }
382
0
  return len;
383
0
}
384
385
const char **scconf_list_toarray(const scconf_list * list)
386
0
{
387
0
  const scconf_list * lp = list;
388
0
  const char **tp;
389
0
  int len = 0;
390
391
0
  while (lp) {
392
0
    len++;
393
0
    lp = lp->next;
394
0
  }
395
0
  tp = malloc(sizeof(char *) * (len + 1));
396
0
  if (!tp)
397
0
    return tp;
398
0
  lp = list;
399
0
  len = 0;
400
0
  while (lp) {
401
0
    tp[len] = lp->data;
402
0
    len++;
403
0
    lp = lp->next;
404
0
  }
405
0
  tp[len] = NULL;
406
0
  return tp;
407
0
}
408
409
char *scconf_list_strdup(const scconf_list * list, const char *filler)
410
0
{
411
0
  char *buf = NULL;
412
0
  int len = 0;
413
414
0
  if (!list) {
415
0
    return NULL;
416
0
  }
417
0
  len = scconf_list_strings_length(list);
418
0
  if (filler) {
419
0
    len += scconf_list_array_length(list) * (strlen(filler) + 1);
420
0
  }
421
0
  if (len == 0)
422
0
    return NULL;
423
0
  buf = calloc(1, len);
424
0
  if (!buf) {
425
0
    return NULL;
426
0
  }
427
0
  while (list && list->data) {
428
0
    strlcat(buf, list->data, len);
429
0
    if (filler) {
430
0
      strlcat(buf, filler, len);
431
0
    }
432
0
    list = list->next;
433
0
  }
434
0
  if (filler)
435
0
    buf[strlen(buf) - strlen(filler)] = '\0';
436
0
  return buf;
437
0
}