Coverage Report

Created: 2025-12-07 06:37

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 "scconf.h"
34
35
scconf_context *scconf_new(const char *filename)
36
230
{
37
230
  scconf_context *config;
38
39
230
  config = calloc(1, sizeof(scconf_context));
40
230
  if (!config) {
41
0
    return NULL;
42
0
  }
43
230
  config->filename = filename ? strdup(filename) : NULL;
44
230
  config->root = calloc(1, sizeof(scconf_block));
45
230
  if (!config->root) {
46
0
    if (config->filename) {
47
0
      free(config->filename);
48
0
    }
49
0
    free(config);
50
0
    return NULL;
51
0
  }
52
230
  return config;
53
230
}
54
55
void scconf_free(scconf_context * config)
56
230
{
57
230
  if (config) {
58
230
    scconf_block_destroy(config->root);
59
230
    if (config->filename) {
60
230
      free(config->filename);
61
230
    }
62
230
    free(config);
63
230
  }
64
230
}
65
66
const scconf_block *scconf_find_block(const scconf_context * config, const scconf_block * block, const char *item_name)
67
0
{
68
0
  scconf_item *item;
69
70
0
  if (!block) {
71
0
    block = config->root;
72
0
  }
73
0
  if (!item_name) {
74
0
    return NULL;
75
0
  }
76
0
  for (item = block->items; item; item = item->next) {
77
0
    if (item->type == SCCONF_ITEM_TYPE_BLOCK &&
78
0
        strcasecmp(item_name, item->key) == 0) {
79
0
      return item->value.block;
80
0
    }
81
0
  }
82
0
  return NULL;
83
0
}
84
85
scconf_block **scconf_find_blocks(const scconf_context * config, const scconf_block * block, const char *item_name, const char *key)
86
11.0k
{
87
11.0k
  scconf_block **blocks = NULL, **tmp;
88
11.0k
  int alloc_size, size;
89
11.0k
  scconf_item *item;
90
91
11.0k
  if (!block) {
92
690
    block = config->root;
93
690
  }
94
11.0k
  if (!item_name) {
95
0
    return NULL;
96
0
  }
97
11.0k
  size = 0;
98
11.0k
  alloc_size = 10;
99
11.0k
  tmp = (scconf_block **) realloc(blocks, sizeof(scconf_block *) * alloc_size);
100
11.0k
  if (!tmp) {
101
0
    free(blocks);
102
0
    return NULL;
103
0
  }
104
11.0k
  blocks = tmp;
105
106
22.0k
  for (item = block->items; item; item = item->next) {
107
11.0k
    if (item->type == SCCONF_ITEM_TYPE_BLOCK &&
108
690
        strcasecmp(item_name, item->key) == 0) {
109
690
      if (!item->value.block)
110
0
        continue;
111
690
      if (key && strcasecmp(key, item->value.block->name->data)) {
112
460
        continue;
113
460
      }
114
230
      if (size + 1 >= alloc_size) {
115
0
        alloc_size *= 2;
116
0
        tmp = (scconf_block **) realloc(blocks, sizeof(scconf_block *) * alloc_size);
117
0
        if (!tmp) {
118
0
          free(blocks);
119
0
          return NULL;
120
0
        }
121
0
        blocks = tmp;
122
0
      }
123
230
      blocks[size++] = item->value.block;
124
230
    }
125
11.0k
  }
126
11.0k
  blocks[size] = NULL;
127
11.0k
  return blocks;
128
11.0k
}
129
130
const scconf_list *scconf_find_list(const scconf_block * block, const char *option)
131
1.83k
{
132
1.83k
  scconf_item *item;
133
134
1.83k
  if (!block)
135
221
    return NULL;
136
137
2.99k
  for (item = block->items; item; item = item->next)
138
1.61k
    if (item->type == SCCONF_ITEM_TYPE_VALUE && strcasecmp(option, item->key) == 0)
139
230
      return item->value.list;
140
1.38k
  return NULL;
141
1.61k
}
142
143
const char *scconf_get_str(const scconf_block * block, const char *option, const char *def)
144
681
{
145
681
  const scconf_list *list;
146
147
681
  list = scconf_find_list(block, option);
148
681
  if (!list)
149
681
    return def;
150
151
  /* ignore non 'auto-configured' values */
152
0
  if (*list->data == '@' && *(list->data + strlen(list->data) - 1) == '@')
153
0
    return def;
154
155
0
  return list->data;
156
0
}
157
158
int scconf_get_int(const scconf_block * block, const char *option, int def)
159
230
{
160
230
  const scconf_list *list;
161
230
  long res;
162
163
230
  list = scconf_find_list(block, option);
164
230
  if (!list) {
165
230
    return def;
166
230
  }
167
0
  res = strtol(list->data, NULL, 0);
168
0
  if (res <= INT_MAX) {
169
0
    return (int)res;
170
0
  }
171
0
  return def;
172
0
}
173
174
int scconf_get_bool(const scconf_block * block, const char *option, int def)
175
690
{
176
690
  const scconf_list *list;
177
178
690
  list = scconf_find_list(block, option);
179
690
  if (!list) {
180
690
    return def;
181
690
  }
182
0
  return toupper((int) *list->data) == 'T' || toupper((int) *list->data) == 'Y';
183
690
}
184
185
const char *scconf_put_str(scconf_block * block, const char *option, const char *value)
186
0
{
187
0
  scconf_list *list = NULL;
188
189
0
  scconf_list_add(&list, value);
190
0
  scconf_item_add(NULL, block, NULL, SCCONF_ITEM_TYPE_VALUE, option, list);
191
0
  scconf_list_destroy(list);
192
0
  return value;
193
0
}
194
195
int scconf_put_int(scconf_block * block, const char *option, int value)
196
0
{
197
0
  char *str;
198
199
0
  str = malloc(64);
200
0
  if (!str) {
201
0
    return value;
202
0
  }
203
0
  snprintf(str, 64, "%i", value);
204
0
  scconf_put_str(block, option, str);
205
0
  free(str);
206
0
  return value;
207
0
}
208
209
int scconf_put_bool(scconf_block * block, const char *option, int value)
210
0
{
211
0
  scconf_put_str(block, option, !value ? "false" : "true");
212
0
  return value;
213
0
}
214
215
scconf_item *scconf_item_copy(const scconf_item * src, scconf_item ** dst)
216
0
{
217
0
  scconf_item *ptr, *_dst = NULL, *next = NULL;
218
219
0
  next = calloc(1, sizeof(scconf_item));
220
0
  if (!next) {
221
0
    return NULL;
222
0
  }
223
0
  ptr = next;
224
0
  _dst = next;
225
0
  while (src) {
226
0
    if (!next) {
227
0
      next = calloc(1, sizeof(scconf_item));
228
0
      if (!next) {
229
0
        scconf_item_destroy(ptr);
230
0
        return NULL;
231
0
      }
232
0
      _dst->next = next;
233
0
    }
234
0
    next->type = src->type;
235
0
    switch (src->type) {
236
0
    case SCCONF_ITEM_TYPE_COMMENT:
237
0
      next->value.comment = src->value.comment ? strdup(src->value.comment) : NULL;
238
0
      break;
239
0
    case SCCONF_ITEM_TYPE_BLOCK:
240
0
      scconf_block_copy(src->value.block, &next->value.block);
241
0
      break;
242
0
    case SCCONF_ITEM_TYPE_VALUE:
243
0
      scconf_list_copy(src->value.list, &next->value.list);
244
0
      break;
245
0
    }
246
0
    next->key = src->key ? strdup(src->key) : NULL;
247
0
    _dst = next;
248
0
    next = NULL;
249
0
    src = src->next;
250
0
  }
251
0
  *dst = ptr;
252
0
  return ptr;
253
0
}
254
255
void scconf_item_destroy(scconf_item * item)
256
460
{
257
460
  scconf_item *next;
258
259
920
  while (item) {
260
460
    next = item->next;
261
262
460
    switch (item->type) {
263
0
    case SCCONF_ITEM_TYPE_COMMENT:
264
0
      if (item->value.comment) {
265
0
        free(item->value.comment);
266
0
      }
267
0
      item->value.comment = NULL;
268
0
      break;
269
230
    case SCCONF_ITEM_TYPE_BLOCK:
270
230
      scconf_block_destroy(item->value.block);
271
230
      break;
272
230
    case SCCONF_ITEM_TYPE_VALUE:
273
230
      scconf_list_destroy(item->value.list);
274
230
      break;
275
460
    }
276
277
460
    if (item->key) {
278
460
      free(item->key);
279
460
    }
280
460
    item->key = NULL;
281
460
    free(item);
282
460
    item = next;
283
460
  }
284
460
}
285
286
scconf_block *scconf_block_copy(const scconf_block * src, scconf_block ** dst)
287
0
{
288
0
  if (src) {
289
0
    scconf_block *_dst = NULL;
290
291
0
    _dst = calloc(1, sizeof(scconf_block));
292
0
    if (!_dst) {
293
0
      return NULL;
294
0
    }
295
0
    memset(_dst, 0, sizeof(scconf_block));
296
0
    if (src->name) {
297
0
      scconf_list_copy(src->name, &_dst->name);
298
0
    }
299
0
    if (src->items) {
300
0
      scconf_item_copy(src->items, &_dst->items);
301
0
    }
302
0
    *dst = _dst;
303
0
    return _dst;
304
0
  }
305
0
  return NULL;
306
0
}
307
308
void scconf_block_destroy(scconf_block * block)
309
460
{
310
460
  if (block) {
311
460
    scconf_list_destroy(block->name);
312
460
    scconf_item_destroy(block->items);
313
460
    free(block);
314
460
  }
315
460
}
316
317
scconf_list *scconf_list_add(scconf_list ** list, const char *value)
318
690
{
319
690
  scconf_list *rec, **tmp;
320
321
690
  rec = calloc(1, sizeof(scconf_list));
322
690
  if (!rec) {
323
0
    return NULL;
324
0
  }
325
690
  rec->data = value ? strdup(value) : NULL;
326
327
690
  if (!*list) {
328
460
    *list = rec;
329
460
  } else {
330
460
    for (tmp = list; *tmp; tmp = &(*tmp)->next);
331
230
    *tmp = rec;
332
230
  }
333
690
  return rec;
334
690
}
335
336
scconf_list *scconf_list_copy(const scconf_list * src, scconf_list ** dst)
337
0
{
338
0
  scconf_list *next;
339
340
0
  while (src) {
341
0
    next = src->next;
342
0
    scconf_list_add(dst, src->data);
343
0
    src = next;
344
0
  }
345
0
  return *dst;
346
0
}
347
348
void scconf_list_destroy(scconf_list * list)
349
1.38k
{
350
1.38k
  scconf_list *next;
351
352
2.07k
  while (list) {
353
690
    next = list->next;
354
690
    if (list->data) {
355
690
      free(list->data);
356
690
    }
357
690
    free(list);
358
690
    list = next;
359
690
  }
360
1.38k
}
361
362
int scconf_list_array_length(const scconf_list * list)
363
0
{
364
0
  int len = 0;
365
366
0
  while (list) {
367
0
    len++;
368
0
    list = list->next;
369
0
  }
370
0
  return len;
371
0
}
372
373
int scconf_list_strings_length(const scconf_list * list)
374
0
{
375
0
  int len = 0;
376
377
0
  while (list && list->data) {
378
0
    len += strlen(list->data) + 1;
379
0
    list = list->next;
380
0
  }
381
0
  return len;
382
0
}
383
384
const char **scconf_list_toarray(const scconf_list * list)
385
0
{
386
0
  const scconf_list * lp = list;
387
0
  const char **tp;
388
0
  int len = 0;
389
390
0
  while (lp) {
391
0
    len++;
392
0
    lp = lp->next;
393
0
  }
394
0
  tp = malloc(sizeof(char *) * (len + 1));
395
0
  if (!tp)
396
0
    return tp;
397
0
  lp = list;
398
0
  len = 0;
399
0
  while (lp) {
400
0
    tp[len] = lp->data;
401
0
    len++;
402
0
    lp = lp->next;
403
0
  }
404
0
  tp[len] = NULL;
405
0
  return tp;
406
0
}
407
408
char *scconf_list_strdup(const scconf_list * list, const char *filler)
409
0
{
410
0
  char *buf = NULL;
411
0
  int len = 0;
412
413
0
  if (!list) {
414
0
    return NULL;
415
0
  }
416
0
  len = scconf_list_strings_length(list);
417
0
  if (filler) {
418
0
    len += scconf_list_array_length(list) * (strlen(filler) + 1);
419
0
  }
420
0
  if (len == 0)
421
0
    return NULL;
422
0
  buf = calloc(1, len);
423
0
  if (!buf) {
424
0
    return NULL;
425
0
  }
426
0
  while (list && list->data) {
427
0
    strcat(buf, list->data);
428
0
    if (filler) {
429
0
      strcat(buf, filler);
430
0
    }
431
0
    list = list->next;
432
0
  }
433
0
  if (filler)
434
0
    buf[strlen(buf) - strlen(filler)] = '\0';
435
0
  return buf;
436
0
}