Coverage Report

Created: 2025-09-04 06:45

/src/opensc/src/scconf/scconf.c
Line
Count
Source (jump to first uncovered line)
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
31.1k
{
37
31.1k
  scconf_context *config;
38
39
31.1k
  config = calloc(1, sizeof(scconf_context));
40
31.1k
  if (!config) {
41
0
    return NULL;
42
0
  }
43
31.1k
  config->filename = filename ? strdup(filename) : NULL;
44
31.1k
  config->root = calloc(1, sizeof(scconf_block));
45
31.1k
  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
31.1k
  return config;
53
31.1k
}
54
55
void scconf_free(scconf_context * config)
56
31.1k
{
57
31.1k
  if (config) {
58
31.1k
    scconf_block_destroy(config->root);
59
31.1k
    if (config->filename) {
60
17.8k
      free(config->filename);
61
17.8k
    }
62
31.1k
    free(config);
63
31.1k
  }
64
31.1k
}
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
0
{
87
0
  scconf_block **blocks = NULL, **tmp;
88
0
  int alloc_size, size;
89
0
  scconf_item *item;
90
91
0
  if (!block) {
92
0
    block = config->root;
93
0
  }
94
0
  if (!item_name) {
95
0
    return NULL;
96
0
  }
97
0
  size = 0;
98
0
  alloc_size = 10;
99
0
  tmp = (scconf_block **) realloc(blocks, sizeof(scconf_block *) * alloc_size);
100
0
  if (!tmp) {
101
0
    free(blocks);
102
0
    return NULL;
103
0
  }
104
0
  blocks = tmp;
105
106
0
  for (item = block->items; item; item = item->next) {
107
0
    if (item->type == SCCONF_ITEM_TYPE_BLOCK &&
108
0
        strcasecmp(item_name, item->key) == 0) {
109
0
      if (!item->value.block)
110
0
        continue;
111
0
      if (key && strcasecmp(key, item->value.block->name->data)) {
112
0
        continue;
113
0
      }
114
0
      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
0
      blocks[size++] = item->value.block;
124
0
    }
125
0
  }
126
0
  blocks[size] = NULL;
127
0
  return blocks;
128
0
}
129
130
const scconf_list *scconf_find_list(const scconf_block * block, const char *option)
131
92.3k
{
132
92.3k
  scconf_item *item;
133
134
92.3k
  if (!block)
135
92.3k
    return NULL;
136
137
0
  for (item = block->items; item; item = item->next)
138
0
    if (item->type == SCCONF_ITEM_TYPE_VALUE && strcasecmp(option, item->key) == 0)
139
0
      return item->value.list;
140
0
  return NULL;
141
0
}
142
143
const char *scconf_get_str(const scconf_block * block, const char *option, const char *def)
144
65.8k
{
145
65.8k
  const scconf_list *list;
146
147
65.8k
  list = scconf_find_list(block, option);
148
65.8k
  if (!list)
149
65.8k
    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
0
{
160
0
  const scconf_list *list;
161
0
  long res;
162
163
0
  list = scconf_find_list(block, option);
164
0
  if (!list) {
165
0
    return def;
166
0
  }
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
26.4k
{
176
26.4k
  const scconf_list *list;
177
178
26.4k
  list = scconf_find_list(block, option);
179
26.4k
  if (!list) {
180
26.4k
    return def;
181
26.4k
  }
182
0
  return toupper((int) *list->data) == 'T' || toupper((int) *list->data) == 'Y';
183
26.4k
}
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
95.3k
{
257
95.3k
  scconf_item *next;
258
259
282k
  while (item) {
260
186k
    next = item->next;
261
262
186k
    switch (item->type) {
263
57.6k
    case SCCONF_ITEM_TYPE_COMMENT:
264
57.6k
      if (item->value.comment) {
265
34.8k
        free(item->value.comment);
266
34.8k
      }
267
57.6k
      item->value.comment = NULL;
268
57.6k
      break;
269
64.1k
    case SCCONF_ITEM_TYPE_BLOCK:
270
64.1k
      scconf_block_destroy(item->value.block);
271
64.1k
      break;
272
64.8k
    case SCCONF_ITEM_TYPE_VALUE:
273
64.8k
      scconf_list_destroy(item->value.list);
274
64.8k
      break;
275
186k
    }
276
277
186k
    if (item->key) {
278
129k
      free(item->key);
279
129k
    }
280
186k
    item->key = NULL;
281
186k
    free(item);
282
186k
    item = next;
283
186k
  }
284
95.3k
}
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
95.3k
{
310
95.3k
  if (block) {
311
95.3k
    scconf_list_destroy(block->name);
312
95.3k
    scconf_item_destroy(block->items);
313
95.3k
    free(block);
314
95.3k
  }
315
95.3k
}
316
317
scconf_list *scconf_list_add(scconf_list ** list, const char *value)
318
159k
{
319
159k
  scconf_list *rec, **tmp;
320
321
159k
  rec = calloc(1, sizeof(scconf_list));
322
159k
  if (!rec) {
323
0
    return NULL;
324
0
  }
325
159k
  rec->data = value ? strdup(value) : NULL;
326
327
159k
  if (!*list) {
328
143k
    *list = rec;
329
143k
  } else {
330
77.0k
    for (tmp = list; *tmp; tmp = &(*tmp)->next);
331
15.7k
    *tmp = rec;
332
15.7k
  }
333
159k
  return rec;
334
159k
}
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
330k
{
350
330k
  scconf_list *next;
351
352
489k
  while (list) {
353
159k
    next = list->next;
354
159k
    if (list->data) {
355
159k
      free(list->data);
356
159k
    }
357
159k
    free(list);
358
159k
    list = next;
359
159k
  }
360
330k
}
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
}