Subversion Repositories FlightCtrl

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
56 elmo 1
 
2
/*-------------------------------------------------------------------------*/
3
/**
4
   @file    iniparser.c
5
   @author  N. Devillard
6
   @date    Mar 2000
7
   @version $Revision: 2.14 $
8
   @brief   Parser for ini files.
9
*/
10
/*--------------------------------------------------------------------------*/
11
 
12
/*
13
    $Id: iniparser.c,v 2.14 2002/12/12 10:49:01 ndevilla Exp $
14
    $Author: ndevilla $
15
    $Date: 2002/12/12 10:49:01 $
16
    $Revision: 2.14 $
17
*/
18
 
19
/*---------------------------------------------------------------------------
20
                                Includes
21
 ---------------------------------------------------------------------------*/
22
 
23
#include "iniparser.h"
24
#include "strlib.h"
25
 
26
#define ASCIILINESZ         1024
27
#define INI_INVALID_KEY     ((char*)-1)
28
 
29
/*---------------------------------------------------------------------------
30
                        Private to this module
31
 ---------------------------------------------------------------------------*/
32
 
33
/* Private: add an entry to the dictionary */
34
static void iniparser_add_entry(
35
    dictionary * d,
36
    char * sec,
37
    char * key,
38
    char * val)
39
{
40
    char longkey[2*ASCIILINESZ+1];
41
 
42
    /* Make a key as section:keyword */
43
    if (key!=NULL) {
44
        sprintf(longkey, "%s:%s", sec, key);
45
    } else {
46
        strcpy(longkey, sec);
47
    }
48
 
49
    /* Add (key,val) to dictionary */
50
    dictionary_set(d, longkey, val);
51
    return ;
52
}
53
 
54
 
55
/*-------------------------------------------------------------------------*/
56
/**
57
  @brief    Get number of sections in a dictionary
58
  @param    d   Dictionary to examine
59
  @return   int Number of sections found in dictionary
60
 
61
  This function returns the number of sections found in a dictionary.
62
  The test to recognize sections is done on the string stored in the
63
  dictionary: a section name is given as "section" whereas a key is
64
  stored as "section:key", thus the test looks for entries that do not
65
  contain a colon.
66
 
67
  This clearly fails in the case a section name contains a colon, but
68
  this should simply be avoided.
69
 
70
  This function returns -1 in case of error.
71
 */
72
/*--------------------------------------------------------------------------*/
73
 
74
int iniparser_getnsec(dictionary * d)
75
{
76
    int i ;
77
    int nsec ;
78
 
79
    if (d==NULL) return -1 ;
80
    nsec=0 ;
81
    for (i=0 ; i<d->size ; i++) {
82
        if (d->key[i]==NULL)
83
            continue ;
84
        if (strchr(d->key[i], ':')==NULL) {
85
            nsec ++ ;
86
        }
87
    }
88
    return nsec ;
89
}
90
 
91
 
92
/*-------------------------------------------------------------------------*/
93
/**
94
  @brief    Get name for section n in a dictionary.
95
  @param    d   Dictionary to examine
96
  @param    n   Section number (from 0 to nsec-1).
97
  @return   Pointer to char string
98
 
99
  This function locates the n-th section in a dictionary and returns
100
  its name as a pointer to a string statically allocated inside the
101
  dictionary. Do not free or modify the returned string!
102
 
103
  This function returns NULL in case of error.
104
 */
105
/*--------------------------------------------------------------------------*/
106
 
107
char * iniparser_getsecname(dictionary * d, int n)
108
{
109
    int i ;
110
    int foundsec ;
111
 
112
    if (d==NULL || n<0) return NULL ;
113
    foundsec=0 ;
114
    for (i=0 ; i<d->size ; i++) {
115
        if (d->key[i]==NULL)
116
            continue ;
117
        if (strchr(d->key[i], ':')==NULL) {
118
            foundsec++ ;
119
            if (foundsec>n)
120
                break ;
121
        }
122
    }
123
    if (foundsec<=n) {
124
        return NULL ;
125
    }
126
    return d->key[i] ;
127
}
128
 
129
 
130
/*-------------------------------------------------------------------------*/
131
/**
132
  @brief    Dump a dictionary to an opened file pointer.
133
  @param    d   Dictionary to dump.
134
  @param    f   Opened file pointer to dump to.
135
  @return   void
136
 
137
  This function prints out the contents of a dictionary, one element by
138
  line, onto the provided file pointer. It is OK to specify @c stderr
139
  or @c stdout as output files. This function is meant for debugging
140
  purposes mostly.
141
 */
142
/*--------------------------------------------------------------------------*/
143
void iniparser_dump(dictionary * d, FILE * f)
144
{
145
    int     i ;
146
 
147
    if (d==NULL || f==NULL) return ;
148
    for (i=0 ; i<d->size ; i++) {
149
        if (d->key[i]==NULL)
150
            continue ;
151
        if (d->val[i]!=NULL) {
152
            fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
153
        } else {
154
            fprintf(f, "[%s]=UNDEF\n", d->key[i]);
155
        }
156
    }
157
    return ;
158
}
159
 
160
/*-------------------------------------------------------------------------*/
161
/**
162
  @brief    Save a dictionary to a loadable ini file
163
  @param    d   Dictionary to dump
164
  @param    f   Opened file pointer to dump to
165
  @return   void
166
 
167
  This function dumps a given dictionary into a loadable ini file.
168
  It is Ok to specify @c stderr or @c stdout as output files.
169
 */
170
/*--------------------------------------------------------------------------*/
171
 
172
void iniparser_dump_ini(dictionary * d, FILE * f)
173
{
174
    int     i, j ;
175
    char    keym[ASCIILINESZ+1];
176
    int     nsec ;
177
    char *  secname ;
178
    int     seclen ;
179
 
180
    if (d==NULL || f==NULL) return ;
181
 
182
    nsec = iniparser_getnsec(d);
183
    if (nsec<1) {
184
        /* No section in file: dump all keys as they are */
185
        for (i=0 ; i<d->size ; i++) {
186
            if (d->key[i]==NULL)
187
                continue ;
188
            fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
189
        }
190
        return ;
191
    }
192
    for (i=0 ; i<nsec ; i++) {
193
        secname = iniparser_getsecname(d, i) ;
194
        seclen  = (int)strlen(secname);
195
        fprintf(f, "\n[%s]\n", secname);
196
        sprintf(keym, "%s:", secname);
197
        for (j=0 ; j<d->size ; j++) {
198
            if (d->key[j]==NULL)
199
                continue ;
200
            if (!strncmp(d->key[j], keym, seclen+1)) {
201
                fprintf(f,
202
                        "%-30s = %s\n",
203
                        d->key[j]+seclen+1,
204
                        d->val[j] ? d->val[j] : "");
205
            }
206
        }
207
    }
208
    fprintf(f, "\n");
209
    return ;
210
}
211
 
212
 
213
 
214
 
215
/*-------------------------------------------------------------------------*/
216
/**
217
  @brief        Get the string associated to a key, return NULL if not found
218
  @param    d   Dictionary to search
219
  @param    key Key string to look for
220
  @return   pointer to statically allocated character string, or NULL.
221
 
222
  This function queries a dictionary for a key. A key as read from an
223
  ini file is given as "section:key". If the key cannot be found,
224
  NULL is returned.
225
  The returned char pointer is pointing to a string allocated in
226
  the dictionary, do not free or modify it.
227
 
228
  This function is only provided for backwards compatibility with
229
  previous versions of iniparser. It is recommended to use
230
  iniparser_getstring() instead.
231
 */
232
/*--------------------------------------------------------------------------*/
233
char * iniparser_getstr(dictionary * d, const char * key)
234
{
235
    return iniparser_getstring(d, key, NULL);
236
}
237
 
238
 
239
/*-------------------------------------------------------------------------*/
240
/**
241
  @brief    Get the string associated to a key
242
  @param    d       Dictionary to search
243
  @param    key     Key string to look for
244
  @param    def     Default value to return if key not found.
245
  @return   pointer to statically allocated character string
246
 
247
  This function queries a dictionary for a key. A key as read from an
248
  ini file is given as "section:key". If the key cannot be found,
249
  the pointer passed as 'def' is returned.
250
  The returned char pointer is pointing to a string allocated in
251
  the dictionary, do not free or modify it.
252
 */
253
/*--------------------------------------------------------------------------*/
254
char * iniparser_getstring(dictionary * d, const char * key, char * def)
255
{
256
    char * lc_key ;
257
    char * sval ;
258
 
259
    if (d==NULL || key==NULL)
260
        return def ;
261
 
262
    if (!(lc_key = strdup(strlwc(key)))) {
263
            return NULL;
264
    }
265
    sval = dictionary_get(d, lc_key, def);
266
    free(lc_key);
267
    return sval ;
268
}
269
 
270
 
271
 
272
/*-------------------------------------------------------------------------*/
273
/**
274
  @brief    Get the string associated to a key, convert to an int
275
  @param    d Dictionary to search
276
  @param    key Key string to look for
277
  @param    notfound Value to return in case of error
278
  @return   integer
279
 
280
  This function queries a dictionary for a key. A key as read from an
281
  ini file is given as "section:key". If the key cannot be found,
282
  the notfound value is returned.
283
 */
284
/*--------------------------------------------------------------------------*/
285
int iniparser_getint(dictionary * d, const char * key, int notfound)
286
{
287
    char    *   str ;
288
 
289
    str = iniparser_getstring(d, key, INI_INVALID_KEY);
290
    if (str==INI_INVALID_KEY) return notfound ;
291
    return atoi(str);
292
}
293
 
294
 
295
/*-------------------------------------------------------------------------*/
296
/**
297
  @brief    Get the string associated to a key, convert to a double
298
  @param    d Dictionary to search
299
  @param    key Key string to look for
300
  @param    notfound Value to return in case of error
301
  @return   double
302
 
303
  This function queries a dictionary for a key. A key as read from an
304
  ini file is given as "section:key". If the key cannot be found,
305
  the notfound value is returned.
306
 */
307
/*--------------------------------------------------------------------------*/
308
double iniparser_getdouble(dictionary * d, char * key, double notfound)
309
{
310
    char    *   str ;
311
 
312
    str = iniparser_getstring(d, key, INI_INVALID_KEY);
313
    if (str==INI_INVALID_KEY) return notfound ;
314
    return atof(str);
315
}
316
 
317
 
318
 
319
/*-------------------------------------------------------------------------*/
320
/**
321
  @brief    Get the string associated to a key, convert to a boolean
322
  @param    d Dictionary to search
323
  @param    key Key string to look for
324
  @param    notfound Value to return in case of error
325
  @return   integer
326
 
327
  This function queries a dictionary for a key. A key as read from an
328
  ini file is given as "section:key". If the key cannot be found,
329
  the notfound value is returned.
330
 
331
  A true boolean is found if one of the following is matched:
332
 
333
  - A string starting with 'y'
334
  - A string starting with 'Y'
335
  - A string starting with 't'
336
  - A string starting with 'T'
337
  - A string starting with '1'
338
 
339
  A false boolean is found if one of the following is matched:
340
 
341
  - A string starting with 'n'
342
  - A string starting with 'N'
343
  - A string starting with 'f'
344
  - A string starting with 'F'
345
  - A string starting with '0'
346
 
347
  The notfound value returned if no boolean is identified, does not
348
  necessarily have to be 0 or 1.
349
 */
350
/*--------------------------------------------------------------------------*/
351
int iniparser_getboolean(dictionary * d, const char * key, int notfound)
352
{
353
    char    *   c ;
354
    int         ret ;
355
 
356
    c = iniparser_getstring(d, key, INI_INVALID_KEY);
357
    if (c==INI_INVALID_KEY) return notfound ;
358
    if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
359
        ret = 1 ;
360
    } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
361
        ret = 0 ;
362
    } else {
363
        ret = notfound ;
364
    }
365
    return ret;
366
}
367
 
368
 
369
/*-------------------------------------------------------------------------*/
370
/**
371
  @brief    Finds out if a given entry exists in a dictionary
372
  @param    ini     Dictionary to search
373
  @param    entry   Name of the entry to look for
374
  @return   integer 1 if entry exists, 0 otherwise
375
 
376
  Finds out if a given entry exists in the dictionary. Since sections
377
  are stored as keys with NULL associated values, this is the only way
378
  of querying for the presence of sections in a dictionary.
379
 */
380
/*--------------------------------------------------------------------------*/
381
 
382
int iniparser_find_entry(
383
    dictionary  *   ini,
384
    char        *   entry
385
)
386
{
387
    int found=0 ;
388
    if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
389
        found = 1 ;
390
    }
391
    return found ;
392
}
393
 
394
 
395
 
396
/*-------------------------------------------------------------------------*/
397
/**
398
  @brief    Set an entry in a dictionary.
399
  @param    ini     Dictionary to modify.
400
  @param    entry   Entry to modify (entry name)
401
  @param    val     New value to associate to the entry.
402
  @return   int 0 if Ok, -1 otherwise.
403
 
404
  If the given entry can be found in the dictionary, it is modified to
405
  contain the provided value. If it cannot be found, -1 is returned.
406
  It is Ok to set val to NULL.
407
 */
408
/*--------------------------------------------------------------------------*/
409
 
410
int iniparser_setstr(dictionary * ini, char * entry, char * val)
411
{
412
    dictionary_set(ini, strlwc(entry), val);
413
    return 0 ;
414
}
415
 
416
/*-------------------------------------------------------------------------*/
417
/**
418
  @brief    Delete an entry in a dictionary
419
  @param    ini     Dictionary to modify
420
  @param    entry   Entry to delete (entry name)
421
  @return   void
422
 
423
  If the given entry can be found, it is deleted from the dictionary.
424
 */
425
/*--------------------------------------------------------------------------*/
426
void iniparser_unset(dictionary * ini, char * entry)
427
{
428
    dictionary_unset(ini, strlwc(entry));
429
}
430
 
431
 
432
/*-------------------------------------------------------------------------*/
433
/**
434
  @brief    Parse an ini file and return an allocated dictionary object
435
  @param    ininame Name of the ini file to read.
436
  @return   Pointer to newly allocated dictionary
437
 
438
  This is the parser for ini files. This function is called, providing
439
  the name of the file to be read. It returns a dictionary object that
440
  should not be accessed directly, but through accessor functions
441
  instead.
442
 
443
  The returned dictionary must be freed using iniparser_freedict().
444
 */
445
/*--------------------------------------------------------------------------*/
446
 
447
dictionary * iniparser_load(const char * ininame)
448
{
449
    dictionary  *   d ;
450
    char        lin[ASCIILINESZ+1];
451
    char        sec[ASCIILINESZ+1];
452
    char        key[ASCIILINESZ+1];
453
    char        val[ASCIILINESZ+1];
454
    char    *   where ;
455
    FILE    *   ini ;
456
    int         lineno ;
457
 
458
    if ((ini=fopen(ininame, "r"))==NULL) {
459
        return NULL ;
460
    }
461
 
462
    sec[0]=0;
463
 
464
    /*
465
     * Initialize a new dictionary entry
466
     */
467
    if (!(d = dictionary_new(0))) {
468
            fclose(ini);
469
            return NULL;
470
    }
471
    lineno = 0 ;
472
    while (fgets(lin, ASCIILINESZ, ini)!=NULL) {
473
        lineno++ ;
474
        where = strskp(lin); /* Skip leading spaces */
475
        if (*where==';' || *where=='#' || *where==0)
476
            continue ; /* Comment lines */
477
        else {
478
            if (sscanf(where, "[%[^]]", sec)==1) {
479
                /* Valid section name */
480
                strcpy(sec, strlwc(sec));
481
                iniparser_add_entry(d, sec, NULL, NULL);
482
            } else if (sscanf (where, "%[^=] = \"%[^\"]\"", key, val) == 2
483
                   ||  sscanf (where, "%[^=] = '%[^\']'",   key, val) == 2
484
                   ||  sscanf (where, "%[^=] = %[^;#]",     key, val) == 2) {
485
                strcpy(key, strlwc(strcrop(key)));
486
                /*
487
                 * sscanf cannot handle "" or '' as empty value,
488
                 * this is done here
489
                 */
490
                if (!strcmp(val, "\"\"") || !strcmp(val, "''")) {
491
                    val[0] = (char)0;
492
                } else {
493
                    strcpy(val, strcrop(val));
494
                }
495
                iniparser_add_entry(d, sec, key, val);
496
            }
497
        }
498
    }
499
    fclose(ini);
500
    return d ;
501
}
502
 
503
 
504
 
505
/*-------------------------------------------------------------------------*/
506
/**
507
  @brief    Free all memory associated to an ini dictionary
508
  @param    d Dictionary to free
509
  @return   void
510
 
511
  Free all memory associated to an ini dictionary.
512
  It is mandatory to call this function before the dictionary object
513
  gets out of the current context.
514
 */
515
/*--------------------------------------------------------------------------*/
516
 
517
void iniparser_freedict(dictionary * d)
518
{
519
    dictionary_del(d);
520
}
521
 
522
/* vim: set ts=4 et sw=4 tw=75 */