Coverage Report

Created: 2024-05-20 06:38

/src/adhd/external/iniparser/src/iniparser.c
Line
Count
Source (jump to first uncovered line)
1
2
/*-------------------------------------------------------------------------*/
3
/**
4
   @file    iniparser.c
5
   @author  N. Devillard
6
   @brief   Parser for ini files.
7
*/
8
/*--------------------------------------------------------------------------*/
9
/*---------------------------- Includes ------------------------------------*/
10
#include <ctype.h>
11
#include <stdarg.h>
12
#include "iniparser.h"
13
14
/*---------------------------- Defines -------------------------------------*/
15
0
#define ASCIILINESZ         (1024)
16
240
#define INI_INVALID_KEY     ((char*)-1)
17
18
/*---------------------------------------------------------------------------
19
                        Private to this module
20
 ---------------------------------------------------------------------------*/
21
/**
22
 * This enum stores the status for each parsed line (internal use only).
23
 */
24
typedef enum _line_status_ {
25
    LINE_UNPROCESSED,
26
    LINE_ERROR,
27
    LINE_EMPTY,
28
    LINE_COMMENT,
29
    LINE_SECTION,
30
    LINE_VALUE
31
} line_status ;
32
33
/*-------------------------------------------------------------------------*/
34
/**
35
  @brief    Convert a string to lowercase.
36
  @param    in   String to convert.
37
  @param    out Output buffer.
38
  @param    len Size of the out buffer.
39
  @return   ptr to the out buffer or NULL if an error occured.
40
41
  This function convert a string into lowercase.
42
  At most len - 1 elements of the input string will be converted.
43
 */
44
/*--------------------------------------------------------------------------*/
45
static const char * strlwc(const char * in, char *out, unsigned len)
46
132
{
47
132
    unsigned i ;
48
49
132
    if (in==NULL || out == NULL || len==0) return NULL ;
50
132
    i=0 ;
51
3.76k
    while (in[i] != '\0' && i < len-1) {
52
3.63k
        out[i] = (char)tolower((int)in[i]);
53
3.63k
        i++ ;
54
3.63k
    }
55
132
    out[i] = '\0';
56
132
    return out ;
57
132
}
58
59
/*-------------------------------------------------------------------------*/
60
/**
61
  @brief    Duplicate a string
62
  @param    s String to duplicate
63
  @return   Pointer to a newly allocated string, to be freed with free()
64
65
  This is a replacement for strdup(). This implementation is provided
66
  for systems that do not have it.
67
 */
68
/*--------------------------------------------------------------------------*/
69
static char * xstrdup(const char * s)
70
0
{
71
0
    char * t ;
72
0
    size_t len ;
73
0
    if (!s)
74
0
        return NULL ;
75
76
0
    len = strlen(s) + 1 ;
77
0
    t = (char*) malloc(len) ;
78
0
    if (t) {
79
0
        memcpy(t, s, len) ;
80
0
    }
81
0
    return t ;
82
0
}
83
84
/*-------------------------------------------------------------------------*/
85
/**
86
  @brief    Remove blanks at the beginning and the end of a string.
87
  @param    str  String to parse and alter.
88
  @return   unsigned New size of the string.
89
 */
90
/*--------------------------------------------------------------------------*/
91
static unsigned strstrip(char * s)
92
0
{
93
0
    char *last = NULL ;
94
0
    char *dest = s;
95
96
0
    if (s==NULL) return 0;
97
98
0
    last = s + strlen(s);
99
0
    while (isspace((int)*s) && *s) s++;
100
0
    while (last > s) {
101
0
        if (!isspace((int)*(last-1)))
102
0
            break ;
103
0
        last -- ;
104
0
    }
105
0
    *last = (char)0;
106
107
0
    memmove(dest,s,last - s + 1);
108
0
    return last - s;
109
0
}
110
111
/*-------------------------------------------------------------------------*/
112
/**
113
  @brief    Default error callback for iniparser: wraps `fprintf(stderr, ...)`.
114
 */
115
/*--------------------------------------------------------------------------*/
116
static int default_error_callback(const char *format, ...)
117
0
{
118
0
  int ret;
119
0
  va_list argptr;
120
0
  va_start(argptr, format);
121
0
  ret = vfprintf(stderr, format, argptr);
122
0
  va_end(argptr);
123
0
  return ret;
124
0
}
125
126
static int (*iniparser_error_callback)(const char*, ...) = default_error_callback;
127
128
/*-------------------------------------------------------------------------*/
129
/**
130
  @brief    Configure a function to receive the error messages.
131
  @param    errback  Function to call.
132
133
  By default, the error will be printed on stderr. If a null pointer is passed
134
  as errback the error callback will be switched back to default.
135
 */
136
/*--------------------------------------------------------------------------*/
137
void iniparser_set_error_callback(int (*errback)(const char *, ...))
138
0
{
139
0
  if (errback) {
140
0
    iniparser_error_callback = errback;
141
0
  } else {
142
0
    iniparser_error_callback = default_error_callback;
143
0
  }
144
0
}
145
146
/*-------------------------------------------------------------------------*/
147
/**
148
  @brief    Get number of sections in a dictionary
149
  @param    d   Dictionary to examine
150
  @return   int Number of sections found in dictionary
151
152
  This function returns the number of sections found in a dictionary.
153
  The test to recognize sections is done on the string stored in the
154
  dictionary: a section name is given as "section" whereas a key is
155
  stored as "section:key", thus the test looks for entries that do not
156
  contain a colon.
157
158
  This clearly fails in the case a section name contains a colon, but
159
  this should simply be avoided.
160
161
  This function returns -1 in case of error.
162
 */
163
/*--------------------------------------------------------------------------*/
164
int iniparser_getnsec(const dictionary * d)
165
0
{
166
0
    int i ;
167
0
    int nsec ;
168
169
0
    if (d==NULL) return -1 ;
170
0
    nsec=0 ;
171
0
    for (i=0 ; i<d->size ; i++) {
172
0
        if (d->key[i]==NULL)
173
0
            continue ;
174
0
        if (strchr(d->key[i], ':')==NULL) {
175
0
            nsec ++ ;
176
0
        }
177
0
    }
178
0
    return nsec ;
179
0
}
180
181
/*-------------------------------------------------------------------------*/
182
/**
183
  @brief    Get name for section n in a dictionary.
184
  @param    d   Dictionary to examine
185
  @param    n   Section number (from 0 to nsec-1).
186
  @return   Pointer to char string
187
188
  This function locates the n-th section in a dictionary and returns
189
  its name as a pointer to a string statically allocated inside the
190
  dictionary. Do not free or modify the returned string!
191
192
  This function returns NULL in case of error.
193
 */
194
/*--------------------------------------------------------------------------*/
195
const char * iniparser_getsecname(const dictionary * d, int n)
196
0
{
197
0
    int i ;
198
0
    int foundsec ;
199
200
0
    if (d==NULL || n<0) return NULL ;
201
0
    foundsec=0 ;
202
0
    for (i=0 ; i<d->size ; i++) {
203
0
        if (d->key[i]==NULL)
204
0
            continue ;
205
0
        if (strchr(d->key[i], ':')==NULL) {
206
0
            foundsec++ ;
207
0
            if (foundsec>n)
208
0
                break ;
209
0
        }
210
0
    }
211
0
    if (foundsec<=n) {
212
0
        return NULL ;
213
0
    }
214
0
    return d->key[i] ;
215
0
}
216
217
/*-------------------------------------------------------------------------*/
218
/**
219
  @brief    Dump a dictionary to an opened file pointer.
220
  @param    d   Dictionary to dump.
221
  @param    f   Opened file pointer to dump to.
222
  @return   void
223
224
  This function prints out the contents of a dictionary, one element by
225
  line, onto the provided file pointer. It is OK to specify @c stderr
226
  or @c stdout as output files. This function is meant for debugging
227
  purposes mostly.
228
 */
229
/*--------------------------------------------------------------------------*/
230
void iniparser_dump(const dictionary * d, FILE * f)
231
0
{
232
0
    int     i ;
233
234
0
    if (d==NULL || f==NULL) return ;
235
0
    for (i=0 ; i<d->size ; i++) {
236
0
        if (d->key[i]==NULL)
237
0
            continue ;
238
0
        if (d->val[i]!=NULL) {
239
0
            fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
240
0
        } else {
241
0
            fprintf(f, "[%s]=UNDEF\n", d->key[i]);
242
0
        }
243
0
    }
244
0
    return ;
245
0
}
246
247
/*-------------------------------------------------------------------------*/
248
/**
249
  @brief    Save a dictionary to a loadable ini file
250
  @param    d   Dictionary to dump
251
  @param    f   Opened file pointer to dump to
252
  @return   void
253
254
  This function dumps a given dictionary into a loadable ini file.
255
  It is Ok to specify @c stderr or @c stdout as output files.
256
 */
257
/*--------------------------------------------------------------------------*/
258
void iniparser_dump_ini(const dictionary * d, FILE * f)
259
0
{
260
0
    int          i ;
261
0
    int          nsec ;
262
0
    const char * secname ;
263
264
0
    if (d==NULL || f==NULL) return ;
265
266
0
    nsec = iniparser_getnsec(d);
267
0
    if (nsec<1) {
268
        /* No section in file: dump all keys as they are */
269
0
        for (i=0 ; i<d->size ; i++) {
270
0
            if (d->key[i]==NULL)
271
0
                continue ;
272
0
            fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
273
0
        }
274
0
        return ;
275
0
    }
276
0
    for (i=0 ; i<nsec ; i++) {
277
0
        secname = iniparser_getsecname(d, i) ;
278
0
        iniparser_dumpsection_ini(d, secname, f);
279
0
    }
280
0
    fprintf(f, "\n");
281
0
    return ;
282
0
}
283
284
/*-------------------------------------------------------------------------*/
285
/**
286
  @brief    Save a dictionary section to a loadable ini file
287
  @param    d   Dictionary to dump
288
  @param    s   Section name of dictionary to dump
289
  @param    f   Opened file pointer to dump to
290
  @return   void
291
292
  This function dumps a given section of a given dictionary into a loadable ini
293
  file.  It is Ok to specify @c stderr or @c stdout as output files.
294
 */
295
/*--------------------------------------------------------------------------*/
296
void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f)
297
0
{
298
0
    int     j ;
299
0
    char    keym[ASCIILINESZ+1];
300
0
    int     seclen ;
301
302
0
    if (d==NULL || f==NULL) return ;
303
0
    if (! iniparser_find_entry(d, s)) return ;
304
305
0
    seclen  = (int)strlen(s);
306
0
    fprintf(f, "\n[%s]\n", s);
307
0
    sprintf(keym, "%s:", s);
308
0
    for (j=0 ; j<d->size ; j++) {
309
0
        if (d->key[j]==NULL)
310
0
            continue ;
311
0
        if (!strncmp(d->key[j], keym, seclen+1)) {
312
0
            fprintf(f,
313
0
                    "%-30s = %s\n",
314
0
                    d->key[j]+seclen+1,
315
0
                    d->val[j] ? d->val[j] : "");
316
0
        }
317
0
    }
318
0
    fprintf(f, "\n");
319
0
    return ;
320
0
}
321
322
/*-------------------------------------------------------------------------*/
323
/**
324
  @brief    Get the number of keys in a section of a dictionary.
325
  @param    d   Dictionary to examine
326
  @param    s   Section name of dictionary to examine
327
  @return   Number of keys in section
328
 */
329
/*--------------------------------------------------------------------------*/
330
int iniparser_getsecnkeys(const dictionary * d, const char * s)
331
0
{
332
0
    int     seclen, nkeys ;
333
0
    char    keym[ASCIILINESZ+1];
334
0
    int j ;
335
336
0
    nkeys = 0;
337
338
0
    if (d==NULL) return nkeys;
339
0
    if (! iniparser_find_entry(d, s)) return nkeys;
340
341
0
    seclen  = (int)strlen(s);
342
0
    strlwc(s, keym, sizeof(keym));
343
0
    keym[seclen] = ':';
344
345
0
    for (j=0 ; j<d->size ; j++) {
346
0
        if (d->key[j]==NULL)
347
0
            continue ;
348
0
        if (!strncmp(d->key[j], keym, seclen+1))
349
0
            nkeys++;
350
0
    }
351
352
0
    return nkeys;
353
354
0
}
355
356
/*-------------------------------------------------------------------------*/
357
/**
358
  @brief    Get the number of keys in a section of a dictionary.
359
  @param    d    Dictionary to examine
360
  @param    s    Section name of dictionary to examine
361
  @param    keys Already allocated array to store the keys in
362
  @return   The pointer passed as `keys` argument or NULL in case of error
363
364
  This function queries a dictionary and finds all keys in a given section.
365
  The keys argument should be an array of pointers which size has been
366
  determined by calling `iniparser_getsecnkeys` function prior to this one.
367
368
  Each pointer in the returned char pointer-to-pointer is pointing to
369
  a string allocated in the dictionary; do not free or modify them.
370
 */
371
/*--------------------------------------------------------------------------*/
372
const char ** iniparser_getseckeys(const dictionary * d, const char * s, const char ** keys)
373
0
{
374
0
    int i, j, seclen ;
375
0
    char keym[ASCIILINESZ+1];
376
377
0
    if (d==NULL || keys==NULL) return NULL;
378
0
    if (! iniparser_find_entry(d, s)) return NULL;
379
380
0
    seclen  = (int)strlen(s);
381
0
    strlwc(s, keym, sizeof(keym));
382
0
    keym[seclen] = ':';
383
384
0
    i = 0;
385
386
0
    for (j=0 ; j<d->size ; j++) {
387
0
        if (d->key[j]==NULL)
388
0
            continue ;
389
0
        if (!strncmp(d->key[j], keym, seclen+1)) {
390
0
            keys[i] = d->key[j];
391
0
            i++;
392
0
        }
393
0
    }
394
395
0
    return keys;
396
0
}
397
398
/*-------------------------------------------------------------------------*/
399
/**
400
  @brief    Get the string associated to a key
401
  @param    d       Dictionary to search
402
  @param    key     Key string to look for
403
  @param    def     Default value to return if key not found.
404
  @return   pointer to statically allocated character string
405
406
  This function queries a dictionary for a key. A key as read from an
407
  ini file is given as "section:key". If the key cannot be found,
408
  the pointer passed as 'def' is returned.
409
  The returned char pointer is pointing to a string allocated in
410
  the dictionary, do not free or modify it.
411
 */
412
/*--------------------------------------------------------------------------*/
413
const char * iniparser_getstring(const dictionary * d, const char * key, const char * def)
414
132
{
415
132
    const char * lc_key ;
416
132
    const char * sval ;
417
132
    char tmp_str[ASCIILINESZ+1];
418
419
132
    if (d==NULL || key==NULL)
420
0
        return def ;
421
422
132
    lc_key = strlwc(key, tmp_str, sizeof(tmp_str));
423
132
    sval = dictionary_get(d, lc_key, def);
424
132
    return sval ;
425
132
}
426
427
/*-------------------------------------------------------------------------*/
428
/**
429
  @brief    Get the string associated to a key, convert to an long int
430
  @param    d Dictionary to search
431
  @param    key Key string to look for
432
  @param    notfound Value to return in case of error
433
  @return   long integer
434
435
  This function queries a dictionary for a key. A key as read from an
436
  ini file is given as "section:key". If the key cannot be found,
437
  the notfound value is returned.
438
439
  Supported values for integers include the usual C notation
440
  so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
441
  are supported. Examples:
442
443
  "42"      ->  42
444
  "042"     ->  34 (octal -> decimal)
445
  "0x42"    ->  66 (hexa  -> decimal)
446
447
  Warning: the conversion may overflow in various ways. Conversion is
448
  totally outsourced to strtol(), see the associated man page for overflow
449
  handling.
450
451
  Credits: Thanks to A. Becker for suggesting strtol()
452
 */
453
/*--------------------------------------------------------------------------*/
454
long int iniparser_getlongint(const dictionary * d, const char * key, long int notfound)
455
120
{
456
120
    const char * str ;
457
458
120
    str = iniparser_getstring(d, key, INI_INVALID_KEY);
459
120
    if (str==INI_INVALID_KEY) return notfound ;
460
0
    return strtol(str, NULL, 0);
461
120
}
462
463
464
/*-------------------------------------------------------------------------*/
465
/**
466
  @brief    Get the string associated to a key, convert to an int
467
  @param    d Dictionary to search
468
  @param    key Key string to look for
469
  @param    notfound Value to return in case of error
470
  @return   integer
471
472
  This function queries a dictionary for a key. A key as read from an
473
  ini file is given as "section:key". If the key cannot be found,
474
  the notfound value is returned.
475
476
  Supported values for integers include the usual C notation
477
  so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
478
  are supported. Examples:
479
480
  "42"      ->  42
481
  "042"     ->  34 (octal -> decimal)
482
  "0x42"    ->  66 (hexa  -> decimal)
483
484
  Warning: the conversion may overflow in various ways. Conversion is
485
  totally outsourced to strtol(), see the associated man page for overflow
486
  handling.
487
488
  Credits: Thanks to A. Becker for suggesting strtol()
489
 */
490
/*--------------------------------------------------------------------------*/
491
int iniparser_getint(const dictionary * d, const char * key, int notfound)
492
120
{
493
120
    return (int)iniparser_getlongint(d, key, notfound);
494
120
}
495
496
/*-------------------------------------------------------------------------*/
497
/**
498
  @brief    Get the string associated to a key, convert to a double
499
  @param    d Dictionary to search
500
  @param    key Key string to look for
501
  @param    notfound Value to return in case of error
502
  @return   double
503
504
  This function queries a dictionary for a key. A key as read from an
505
  ini file is given as "section:key". If the key cannot be found,
506
  the notfound value is returned.
507
 */
508
/*--------------------------------------------------------------------------*/
509
double iniparser_getdouble(const dictionary * d, const char * key, double notfound)
510
0
{
511
0
    const char * str ;
512
513
0
    str = iniparser_getstring(d, key, INI_INVALID_KEY);
514
0
    if (str==INI_INVALID_KEY) return notfound ;
515
0
    return atof(str);
516
0
}
517
518
/*-------------------------------------------------------------------------*/
519
/**
520
  @brief    Get the string associated to a key, convert to a boolean
521
  @param    d Dictionary to search
522
  @param    key Key string to look for
523
  @param    notfound Value to return in case of error
524
  @return   integer
525
526
  This function queries a dictionary for a key. A key as read from an
527
  ini file is given as "section:key". If the key cannot be found,
528
  the notfound value is returned.
529
530
  A true boolean is found if one of the following is matched:
531
532
  - A string starting with 'y'
533
  - A string starting with 'Y'
534
  - A string starting with 't'
535
  - A string starting with 'T'
536
  - A string starting with '1'
537
538
  A false boolean is found if one of the following is matched:
539
540
  - A string starting with 'n'
541
  - A string starting with 'N'
542
  - A string starting with 'f'
543
  - A string starting with 'F'
544
  - A string starting with '0'
545
546
  The notfound value returned if no boolean is identified, does not
547
  necessarily have to be 0 or 1.
548
 */
549
/*--------------------------------------------------------------------------*/
550
int iniparser_getboolean(const dictionary * d, const char * key, int notfound)
551
0
{
552
0
    int          ret ;
553
0
    const char * c ;
554
555
0
    c = iniparser_getstring(d, key, INI_INVALID_KEY);
556
0
    if (c==INI_INVALID_KEY) return notfound ;
557
0
    if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
558
0
        ret = 1 ;
559
0
    } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
560
0
        ret = 0 ;
561
0
    } else {
562
0
        ret = notfound ;
563
0
    }
564
0
    return ret;
565
0
}
566
567
/*-------------------------------------------------------------------------*/
568
/**
569
  @brief    Finds out if a given entry exists in a dictionary
570
  @param    ini     Dictionary to search
571
  @param    entry   Name of the entry to look for
572
  @return   integer 1 if entry exists, 0 otherwise
573
574
  Finds out if a given entry exists in the dictionary. Since sections
575
  are stored as keys with NULL associated values, this is the only way
576
  of querying for the presence of sections in a dictionary.
577
 */
578
/*--------------------------------------------------------------------------*/
579
int iniparser_find_entry(const dictionary * ini, const char * entry)
580
0
{
581
0
    int found=0 ;
582
0
    if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
583
0
        found = 1 ;
584
0
    }
585
0
    return found ;
586
0
}
587
588
/*-------------------------------------------------------------------------*/
589
/**
590
  @brief    Set an entry in a dictionary.
591
  @param    ini     Dictionary to modify.
592
  @param    entry   Entry to modify (entry name)
593
  @param    val     New value to associate to the entry.
594
  @return   int 0 if Ok, -1 otherwise.
595
596
  If the given entry can be found in the dictionary, it is modified to
597
  contain the provided value. If it cannot be found, the entry is created.
598
  It is Ok to set val to NULL.
599
 */
600
/*--------------------------------------------------------------------------*/
601
int iniparser_set(dictionary * ini, const char * entry, const char * val)
602
0
{
603
0
    char tmp_str[ASCIILINESZ+1];
604
0
    return dictionary_set(ini, strlwc(entry, tmp_str, sizeof(tmp_str)), val) ;
605
0
}
606
607
/*-------------------------------------------------------------------------*/
608
/**
609
  @brief    Delete an entry in a dictionary
610
  @param    ini     Dictionary to modify
611
  @param    entry   Entry to delete (entry name)
612
  @return   void
613
614
  If the given entry can be found, it is deleted from the dictionary.
615
 */
616
/*--------------------------------------------------------------------------*/
617
void iniparser_unset(dictionary * ini, const char * entry)
618
0
{
619
0
    char tmp_str[ASCIILINESZ+1];
620
0
    dictionary_unset(ini, strlwc(entry, tmp_str, sizeof(tmp_str)));
621
0
}
622
623
/*-------------------------------------------------------------------------*/
624
/**
625
  @brief    Load a single line from an INI file
626
  @param    input_line  Input line, may be concatenated multi-line input
627
  @param    section     Output space to store section
628
  @param    key         Output space to store key
629
  @param    value       Output space to store value
630
  @return   line_status value
631
 */
632
/*--------------------------------------------------------------------------*/
633
static line_status iniparser_line(
634
    const char * input_line,
635
    char * section,
636
    char * key,
637
    char * value)
638
0
{
639
0
    line_status sta ;
640
0
    char * line = NULL;
641
0
    size_t      len ;
642
643
0
    line = xstrdup(input_line);
644
0
    len = strstrip(line);
645
646
0
    sta = LINE_UNPROCESSED ;
647
0
    if (len<1) {
648
        /* Empty line */
649
0
        sta = LINE_EMPTY ;
650
0
    } else if (line[0]=='#' || line[0]==';') {
651
        /* Comment line */
652
0
        sta = LINE_COMMENT ;
653
0
    } else if (line[0]=='[' && line[len-1]==']') {
654
        /* Section name */
655
0
        sscanf(line, "[%[^]]", section);
656
0
        strstrip(section);
657
0
        strlwc(section, section, len);
658
0
        sta = LINE_SECTION ;
659
0
    } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
660
0
           ||  sscanf (line, "%[^=] = '%[^\']'",   key, value) == 2) {
661
        /* Usual key=value with quotes, with or without comments */
662
0
        strstrip(key);
663
0
        strlwc(key, key, len);
664
        /* Don't strip spaces from values surrounded with quotes */
665
0
        sta = LINE_VALUE ;
666
0
    } else if (sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
667
        /* Usual key=value without quotes, with or without comments */
668
0
        strstrip(key);
669
0
        strlwc(key, key, len);
670
0
        strstrip(value);
671
        /*
672
         * sscanf cannot handle '' or "" as empty values
673
         * this is done here
674
         */
675
0
        if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
676
0
            value[0]=0 ;
677
0
        }
678
0
        sta = LINE_VALUE ;
679
0
    } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2
680
0
           ||  sscanf(line, "%[^=] %[=]", key, value) == 2) {
681
        /*
682
         * Special cases:
683
         * key=
684
         * key=;
685
         * key=#
686
         */
687
0
        strstrip(key);
688
0
        strlwc(key, key, len);
689
0
        value[0]=0 ;
690
0
        sta = LINE_VALUE ;
691
0
    } else {
692
        /* Generate syntax error */
693
0
        sta = LINE_ERROR ;
694
0
    }
695
696
0
    free(line);
697
0
    return sta ;
698
0
}
699
700
/*-------------------------------------------------------------------------*/
701
/**
702
  @brief    Parse an ini file and return an allocated dictionary object
703
  @param    ininame Name of the ini file to read.
704
  @return   Pointer to newly allocated dictionary
705
706
  This is the parser for ini files. This function is called, providing
707
  the name of the file to be read. It returns a dictionary object that
708
  should not be accessed directly, but through accessor functions
709
  instead.
710
711
  The returned dictionary must be freed using iniparser_freedict().
712
 */
713
/*--------------------------------------------------------------------------*/
714
dictionary * iniparser_load(const char * ininame)
715
0
{
716
0
    FILE * in ;
717
718
0
    char line    [ASCIILINESZ+1] ;
719
0
    char section [ASCIILINESZ+1] ;
720
0
    char key     [ASCIILINESZ+1] ;
721
0
    char tmp     [(ASCIILINESZ * 2) + 1] ;
722
0
    char val     [ASCIILINESZ+1] ;
723
724
0
    int  last=0 ;
725
0
    int  len ;
726
0
    int  lineno=0 ;
727
0
    int  errs=0;
728
0
    int  mem_err=0;
729
730
0
    dictionary * dict ;
731
732
0
    if ((in=fopen(ininame, "r"))==NULL) {
733
0
        iniparser_error_callback("iniparser: cannot open %s\n", ininame);
734
0
        return NULL ;
735
0
    }
736
737
0
    dict = dictionary_new(0) ;
738
0
    if (!dict) {
739
0
        fclose(in);
740
0
        return NULL ;
741
0
    }
742
743
0
    memset(line,    0, ASCIILINESZ);
744
0
    memset(section, 0, ASCIILINESZ);
745
0
    memset(key,     0, ASCIILINESZ);
746
0
    memset(val,     0, ASCIILINESZ);
747
0
    last=0 ;
748
749
0
    while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
750
0
        lineno++ ;
751
0
        len = (int)strlen(line)-1;
752
0
        if (len<=0)
753
0
            continue;
754
        /* Safety check against buffer overflows */
755
0
        if (line[len]!='\n' && !feof(in)) {
756
0
            iniparser_error_callback(
757
0
              "iniparser: input line too long in %s (%d)\n",
758
0
              ininame,
759
0
              lineno);
760
0
            dictionary_del(dict);
761
0
            fclose(in);
762
0
            return NULL ;
763
0
        }
764
        /* Get rid of \n and spaces at end of line */
765
0
        while ((len>=0) &&
766
0
                ((line[len]=='\n') || (isspace(line[len])))) {
767
0
            line[len]=0 ;
768
0
            len-- ;
769
0
        }
770
0
        if (len < 0) { /* Line was entirely \n and/or spaces */
771
0
            len = 0;
772
0
        }
773
        /* Detect multi-line */
774
0
        if (line[len]=='\\') {
775
            /* Multi-line value */
776
0
            last=len ;
777
0
            continue ;
778
0
        } else {
779
0
            last=0 ;
780
0
        }
781
0
        switch (iniparser_line(line, section, key, val)) {
782
0
            case LINE_EMPTY:
783
0
            case LINE_COMMENT:
784
0
            break ;
785
786
0
            case LINE_SECTION:
787
0
            mem_err = dictionary_set(dict, section, NULL);
788
0
            break ;
789
790
0
            case LINE_VALUE:
791
0
            sprintf(tmp, "%s:%s", section, key);
792
0
            mem_err = dictionary_set(dict, tmp, val);
793
0
            break ;
794
795
0
            case LINE_ERROR:
796
0
            iniparser_error_callback(
797
0
              "iniparser: syntax error in %s (%d):\n-> %s\n",
798
0
              ininame,
799
0
              lineno,
800
0
              line);
801
0
            errs++ ;
802
0
            break;
803
804
0
            default:
805
0
            break ;
806
0
        }
807
0
        memset(line, 0, ASCIILINESZ);
808
0
        last=0;
809
0
        if (mem_err<0) {
810
0
            iniparser_error_callback("iniparser: memory allocation failure\n");
811
0
            break ;
812
0
        }
813
0
    }
814
0
    if (errs) {
815
0
        dictionary_del(dict);
816
0
        dict = NULL ;
817
0
    }
818
0
    fclose(in);
819
0
    return dict ;
820
0
}
821
822
/*-------------------------------------------------------------------------*/
823
/**
824
  @brief    Free all memory associated to an ini dictionary
825
  @param    d Dictionary to free
826
  @return   void
827
828
  Free all memory associated to an ini dictionary.
829
  It is mandatory to call this function before the dictionary object
830
  gets out of the current context.
831
 */
832
/*--------------------------------------------------------------------------*/
833
void iniparser_freedict(dictionary * d)
834
6
{
835
6
    dictionary_del(d);
836
6
}