iniparser.c 23.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

/*-------------------------------------------------------------------------*/
/**
   @file    iniparser.c
   @author  N. Devillard
   @brief   Parser for ini files.
*/
/*--------------------------------------------------------------------------*/
/*---------------------------- Includes ------------------------------------*/
#include <ctype.h>
#include "iniparser.h"

/*---------------------------- Defines -------------------------------------*/
#define ASCIILINESZ         (1024)
#define INI_INVALID_KEY     ((char*)-1)

/*---------------------------------------------------------------------------
                        Private to this module
 ---------------------------------------------------------------------------*/
/**
 * This enum stores the status for each parsed line (internal use only).
 */
typedef enum _line_status_ {
    LINE_UNPROCESSED,
    LINE_ERROR,
    LINE_EMPTY,
    LINE_COMMENT,
    LINE_SECTION,
    LINE_VALUE
} line_status ;

/*-------------------------------------------------------------------------*/
/**
34
  @brief    Convert a string to lowercase.
E
Emmanuel Leblond 已提交
35 36 37 38
  @param    in   String to convert.
  @param    out Output buffer.
  @param    len Size of the out buffer.
  @return   ptr to the out buffer or NULL if an error occured.
39

E
Emmanuel Leblond 已提交
40 41
  This function convert a string into lowercase.
  At most len - 1 elements of the input string will be converted.
42 43
 */
/*--------------------------------------------------------------------------*/
E
Emmanuel Leblond 已提交
44
static const char * strlwc(const char * in, char *out, unsigned len)
45
{
E
Emmanuel Leblond 已提交
46
    unsigned i ;
47

E
Emmanuel Leblond 已提交
48
    if (in==NULL || out == NULL || len==0) return NULL ;
49
    i=0 ;
E
Emmanuel Leblond 已提交
50 51
    while (in[i] != '\0' && i < len-1) {
        out[i] = (char)tolower((int)in[i]);
52 53
        i++ ;
    }
E
Emmanuel Leblond 已提交
54 55
    out[i] = '\0';
    return out ;
56 57 58 59
}

/*-------------------------------------------------------------------------*/
/**
60 61 62
  @brief    Duplicate a string
  @param    s String to duplicate
  @return   Pointer to a newly allocated string, to be freed with free()
E
Emmanuel Leblond 已提交
63

64 65
  This is a replacement for strdup(). This implementation is provided
  for systems that do not have it.
E
Emmanuel Leblond 已提交
66 67
 */
/*--------------------------------------------------------------------------*/
68
static char * xstrdup(const char * s)
E
Emmanuel Leblond 已提交
69
{
70 71 72 73 74 75 76 77 78 79 80
    char * t ;
    size_t len ;
    if (!s)
        return NULL ;

    len = strlen(s) + 1 ;
    t = (char*) malloc(len) ;
    if (t) {
        memcpy(t, s, len) ;
    }
    return t ;
E
Emmanuel Leblond 已提交
81
}
82

E
Emmanuel Leblond 已提交
83 84 85 86 87
/*-------------------------------------------------------------------------*/
/**
  @brief    Remove blanks at the beginning and the end of a string.
  @param    str  String to parse and alter.
  @return   unsigned New size of the string.
88 89
 */
/*--------------------------------------------------------------------------*/
E
Emmanuel Leblond 已提交
90
unsigned strstrip(char * s)
91
{
E
Emmanuel Leblond 已提交
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
    char *last = NULL ;
    char *dest = s;

    if (s==NULL) return 0;

    last = s + strlen(s);
    while (isspace((int)*s) && *s) s++;
    while (last > s) {
        if (!isspace((int)*(last-1)))
            break ;
        last -- ;
    }
    *last = (char)0;

    memmove(dest,s,last - s + 1);
    return last - s;
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Get number of sections in a dictionary
  @param    d   Dictionary to examine
  @return   int Number of sections found in dictionary

  This function returns the number of sections found in a dictionary.
  The test to recognize sections is done on the string stored in the
  dictionary: a section name is given as "section" whereas a key is
  stored as "section:key", thus the test looks for entries that do not
  contain a colon.

  This clearly fails in the case a section name contains a colon, but
  this should simply be avoided.

  This function returns -1 in case of error.
 */
/*--------------------------------------------------------------------------*/
E
Emmanuel Leblond 已提交
128
int iniparser_getnsec(const dictionary * d)
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
{
    int i ;
    int nsec ;

    if (d==NULL) return -1 ;
    nsec=0 ;
    for (i=0 ; i<d->size ; i++) {
        if (d->key[i]==NULL)
            continue ;
        if (strchr(d->key[i], ':')==NULL) {
            nsec ++ ;
        }
    }
    return nsec ;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Get name for section n in a dictionary.
  @param    d   Dictionary to examine
  @param    n   Section number (from 0 to nsec-1).
  @return   Pointer to char string

  This function locates the n-th section in a dictionary and returns
  its name as a pointer to a string statically allocated inside the
  dictionary. Do not free or modify the returned string!

  This function returns NULL in case of error.
 */
/*--------------------------------------------------------------------------*/
E
Emmanuel Leblond 已提交
159
const char * iniparser_getsecname(const dictionary * d, int n)
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
{
    int i ;
    int foundsec ;

    if (d==NULL || n<0) return NULL ;
    foundsec=0 ;
    for (i=0 ; i<d->size ; i++) {
        if (d->key[i]==NULL)
            continue ;
        if (strchr(d->key[i], ':')==NULL) {
            foundsec++ ;
            if (foundsec>n)
                break ;
        }
    }
    if (foundsec<=n) {
        return NULL ;
    }
    return d->key[i] ;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Dump a dictionary to an opened file pointer.
  @param    d   Dictionary to dump.
  @param    f   Opened file pointer to dump to.
  @return   void

  This function prints out the contents of a dictionary, one element by
  line, onto the provided file pointer. It is OK to specify @c stderr
  or @c stdout as output files. This function is meant for debugging
  purposes mostly.
 */
/*--------------------------------------------------------------------------*/
E
Emmanuel Leblond 已提交
194
void iniparser_dump(const dictionary * d, FILE * f)
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
{
    int     i ;

    if (d==NULL || f==NULL) return ;
    for (i=0 ; i<d->size ; i++) {
        if (d->key[i]==NULL)
            continue ;
        if (d->val[i]!=NULL) {
            fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
        } else {
            fprintf(f, "[%s]=UNDEF\n", d->key[i]);
        }
    }
    return ;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Save a dictionary to a loadable ini file
  @param    d   Dictionary to dump
  @param    f   Opened file pointer to dump to
  @return   void

  This function dumps a given dictionary into a loadable ini file.
  It is Ok to specify @c stderr or @c stdout as output files.
 */
/*--------------------------------------------------------------------------*/
E
Emmanuel Leblond 已提交
222
void iniparser_dump_ini(const dictionary * d, FILE * f)
223
{
E
Emmanuel Leblond 已提交
224 225 226
    int          i ;
    int          nsec ;
    const char * secname ;
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241

    if (d==NULL || f==NULL) return ;

    nsec = iniparser_getnsec(d);
    if (nsec<1) {
        /* No section in file: dump all keys as they are */
        for (i=0 ; i<d->size ; i++) {
            if (d->key[i]==NULL)
                continue ;
            fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
        }
        return ;
    }
    for (i=0 ; i<nsec ; i++) {
        secname = iniparser_getsecname(d, i) ;
E
Emmanuel Leblond 已提交
242
        iniparser_dumpsection_ini(d, secname, f);
243 244 245 246 247
    }
    fprintf(f, "\n");
    return ;
}

248 249 250 251 252 253 254 255 256 257 258 259
/*-------------------------------------------------------------------------*/
/**
  @brief    Save a dictionary section to a loadable ini file
  @param    d   Dictionary to dump
  @param    s   Section name of dictionary to dump
  @param    f   Opened file pointer to dump to
  @return   void

  This function dumps a given section of a given dictionary into a loadable ini
  file.  It is Ok to specify @c stderr or @c stdout as output files.
 */
/*--------------------------------------------------------------------------*/
E
Emmanuel Leblond 已提交
260
void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f)
261 262
{
    int     j ;
E
Emmanuel Leblond 已提交
263 264
    char    keym[ASCIILINESZ+1];
    int     seclen ;
265 266 267 268

    if (d==NULL || f==NULL) return ;
    if (! iniparser_find_entry(d, s)) return ;

E
Emmanuel Leblond 已提交
269
    seclen  = (int)strlen(s);
270
    fprintf(f, "\n[%s]\n", s);
E
Emmanuel Leblond 已提交
271
    sprintf(keym, "%s:", s);
272 273 274
    for (j=0 ; j<d->size ; j++) {
        if (d->key[j]==NULL)
            continue ;
E
Emmanuel Leblond 已提交
275
        if (!strncmp(d->key[j], keym, seclen+1)) {
276 277
            fprintf(f,
                    "%-30s = %s\n",
E
Emmanuel Leblond 已提交
278
                    d->key[j]+seclen+1,
279 280 281 282 283 284 285
                    d->val[j] ? d->val[j] : "");
        }
    }
    fprintf(f, "\n");
    return ;
}

286 287 288 289 290 291 292 293
/*-------------------------------------------------------------------------*/
/**
  @brief    Get the number of keys in a section of a dictionary.
  @param    d   Dictionary to examine
  @param    s   Section name of dictionary to examine
  @return   Number of keys in section
 */
/*--------------------------------------------------------------------------*/
E
Emmanuel Leblond 已提交
294
int iniparser_getsecnkeys(const dictionary * d, const char * s)
295
{
E
Emmanuel Leblond 已提交
296 297
    int     seclen, nkeys ;
    char    keym[ASCIILINESZ+1];
298 299 300 301 302 303 304
    int j ;

    nkeys = 0;

    if (d==NULL) return nkeys;
    if (! iniparser_find_entry(d, s)) return nkeys;

E
Emmanuel Leblond 已提交
305
    seclen  = (int)strlen(s);
D
dobragab 已提交
306 307
    strlwc(s, keym, sizeof(keym));
    keym[seclen] = ':';
308 309 310 311

    for (j=0 ; j<d->size ; j++) {
        if (d->key[j]==NULL)
            continue ;
E
Emmanuel Leblond 已提交
312
        if (!strncmp(d->key[j], keym, seclen+1))
313 314
            nkeys++;
    }
E
Emmanuel Leblond 已提交
315

316 317 318 319 320 321 322
    return nkeys;

}

/*-------------------------------------------------------------------------*/
/**
  @brief    Get the number of keys in a section of a dictionary.
323 324 325 326
  @param    d    Dictionary to examine
  @param    s    Section name of dictionary to examine
  @param    keys Already allocated array to store the keys in
  @return   The pointer passed as `keys` argument or NULL in case of error
327 328

  This function queries a dictionary and finds all keys in a given section.
329 330 331
  The keys argument should be an array of pointers which size has been
  determined by calling `iniparser_getsecnkeys` function prior to this one.

332 333 334 335
  Each pointer in the returned char pointer-to-pointer is pointing to
  a string allocated in the dictionary; do not free or modify them.
 */
/*--------------------------------------------------------------------------*/
336
const char ** iniparser_getseckeys(const dictionary * d, const char * s, const char ** keys)
337
{
338 339
    int i, j, seclen ;
    char keym[ASCIILINESZ+1];
340

341 342
    if (d==NULL || keys==NULL) return NULL;
    if (! iniparser_find_entry(d, s)) return NULL;
343

E
Emmanuel Leblond 已提交
344
    seclen  = (int)strlen(s);
D
dobragab 已提交
345 346
    strlwc(s, keym, sizeof(keym));
    keym[seclen] = ':';
A
Andrey Mazo 已提交
347

348 349 350 351 352
    i = 0;

    for (j=0 ; j<d->size ; j++) {
        if (d->key[j]==NULL)
            continue ;
E
Emmanuel Leblond 已提交
353
        if (!strncmp(d->key[j], keym, seclen+1)) {
354 355 356 357
            keys[i] = d->key[j];
            i++;
        }
    }
E
Emmanuel Leblond 已提交
358

359 360 361
    return keys;
}

362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
/*-------------------------------------------------------------------------*/
/**
  @brief    Get the string associated to a key
  @param    d       Dictionary to search
  @param    key     Key string to look for
  @param    def     Default value to return if key not found.
  @return   pointer to statically allocated character string

  This function queries a dictionary for a key. A key as read from an
  ini file is given as "section:key". If the key cannot be found,
  the pointer passed as 'def' is returned.
  The returned char pointer is pointing to a string allocated in
  the dictionary, do not free or modify it.
 */
/*--------------------------------------------------------------------------*/
E
Emmanuel Leblond 已提交
377
const char * iniparser_getstring(const dictionary * d, const char * key, const char * def)
378
{
E
Emmanuel Leblond 已提交
379 380 381
    const char * lc_key ;
    const char * sval ;
    char tmp_str[ASCIILINESZ+1];
382 383 384 385

    if (d==NULL || key==NULL)
        return def ;

E
Emmanuel Leblond 已提交
386
    lc_key = strlwc(key, tmp_str, sizeof(tmp_str));
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
    sval = dictionary_get(d, lc_key, def);
    return sval ;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Get the string associated to a key, convert to an int
  @param    d Dictionary to search
  @param    key Key string to look for
  @param    notfound Value to return in case of error
  @return   integer

  This function queries a dictionary for a key. A key as read from an
  ini file is given as "section:key". If the key cannot be found,
  the notfound value is returned.

  Supported values for integers include the usual C notation
  so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
  are supported. Examples:

  "42"      ->  42
  "042"     ->  34 (octal -> decimal)
  "0x42"    ->  66 (hexa  -> decimal)

  Warning: the conversion may overflow in various ways. Conversion is
  totally outsourced to strtol(), see the associated man page for overflow
  handling.

  Credits: Thanks to A. Becker for suggesting strtol()
 */
/*--------------------------------------------------------------------------*/
E
Emmanuel Leblond 已提交
418
int iniparser_getint(const dictionary * d, const char * key, int notfound)
419
{
E
Emmanuel Leblond 已提交
420
    const char * str ;
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439

    str = iniparser_getstring(d, key, INI_INVALID_KEY);
    if (str==INI_INVALID_KEY) return notfound ;
    return (int)strtol(str, NULL, 0);
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Get the string associated to a key, convert to a double
  @param    d Dictionary to search
  @param    key Key string to look for
  @param    notfound Value to return in case of error
  @return   double

  This function queries a dictionary for a key. A key as read from an
  ini file is given as "section:key". If the key cannot be found,
  the notfound value is returned.
 */
/*--------------------------------------------------------------------------*/
E
Emmanuel Leblond 已提交
440
double iniparser_getdouble(const dictionary * d, const char * key, double notfound)
441
{
E
Emmanuel Leblond 已提交
442
    const char * str ;
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480

    str = iniparser_getstring(d, key, INI_INVALID_KEY);
    if (str==INI_INVALID_KEY) return notfound ;
    return atof(str);
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Get the string associated to a key, convert to a boolean
  @param    d Dictionary to search
  @param    key Key string to look for
  @param    notfound Value to return in case of error
  @return   integer

  This function queries a dictionary for a key. A key as read from an
  ini file is given as "section:key". If the key cannot be found,
  the notfound value is returned.

  A true boolean is found if one of the following is matched:

  - A string starting with 'y'
  - A string starting with 'Y'
  - A string starting with 't'
  - A string starting with 'T'
  - A string starting with '1'

  A false boolean is found if one of the following is matched:

  - A string starting with 'n'
  - A string starting with 'N'
  - A string starting with 'f'
  - A string starting with 'F'
  - A string starting with '0'

  The notfound value returned if no boolean is identified, does not
  necessarily have to be 0 or 1.
 */
/*--------------------------------------------------------------------------*/
E
Emmanuel Leblond 已提交
481
int iniparser_getboolean(const dictionary * d, const char * key, int notfound)
482
{
E
Emmanuel Leblond 已提交
483 484
    int          ret ;
    const char * c ;
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509

    c = iniparser_getstring(d, key, INI_INVALID_KEY);
    if (c==INI_INVALID_KEY) return notfound ;
    if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
        ret = 1 ;
    } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
        ret = 0 ;
    } else {
        ret = notfound ;
    }
    return ret;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Finds out if a given entry exists in a dictionary
  @param    ini     Dictionary to search
  @param    entry   Name of the entry to look for
  @return   integer 1 if entry exists, 0 otherwise

  Finds out if a given entry exists in the dictionary. Since sections
  are stored as keys with NULL associated values, this is the only way
  of querying for the presence of sections in a dictionary.
 */
/*--------------------------------------------------------------------------*/
E
Emmanuel Leblond 已提交
510
int iniparser_find_entry(const dictionary * ini, const char * entry)
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
{
    int found=0 ;
    if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
        found = 1 ;
    }
    return found ;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Set an entry in a dictionary.
  @param    ini     Dictionary to modify.
  @param    entry   Entry to modify (entry name)
  @param    val     New value to associate to the entry.
  @return   int 0 if Ok, -1 otherwise.

  If the given entry can be found in the dictionary, it is modified to
E
Emmanuel Leblond 已提交
528
  contain the provided value. If it cannot be found, the entry is created.
529 530 531
  It is Ok to set val to NULL.
 */
/*--------------------------------------------------------------------------*/
532
int iniparser_set(dictionary * ini, const char * entry, const char * val)
533
{
E
Emmanuel Leblond 已提交
534 535
    char tmp_str[ASCIILINESZ+1];
    return dictionary_set(ini, strlwc(entry, tmp_str, sizeof(tmp_str)), val) ;
536 537 538 539 540 541 542 543 544 545 546 547
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Delete an entry in a dictionary
  @param    ini     Dictionary to modify
  @param    entry   Entry to delete (entry name)
  @return   void

  If the given entry can be found, it is deleted from the dictionary.
 */
/*--------------------------------------------------------------------------*/
548
void iniparser_unset(dictionary * ini, const char * entry)
549
{
E
Emmanuel Leblond 已提交
550 551
    char tmp_str[ASCIILINESZ+1];
    dictionary_unset(ini, strlwc(entry, tmp_str, sizeof(tmp_str)));
552 553 554 555
}

/*-------------------------------------------------------------------------*/
/**
556
  @brief    Load a single line from an INI file
557 558 559 560 561 562 563 564
  @param    input_line  Input line, may be concatenated multi-line input
  @param    section     Output space to store section
  @param    key         Output space to store key
  @param    value       Output space to store value
  @return   line_status value
 */
/*--------------------------------------------------------------------------*/
static line_status iniparser_line(
565
    const char * input_line,
E
Emmanuel Leblond 已提交
566 567 568
    char * section,
    char * key,
    char * value)
A
Andrey Mazo 已提交
569
{
570
    line_status sta ;
E
Emmanuel Leblond 已提交
571 572
    char * line = NULL;
    size_t      len ;
573

574
    line = xstrdup(input_line);
E
Emmanuel Leblond 已提交
575
    len = strstrip(line);
576

577 578 579 580
    sta = LINE_UNPROCESSED ;
    if (len<1) {
        /* Empty line */
        sta = LINE_EMPTY ;
581
    } else if (line[0]=='#' || line[0]==';') {
582
        /* Comment line */
A
Andrey Mazo 已提交
583
        sta = LINE_COMMENT ;
584 585
    } else if (line[0]=='[' && line[len-1]==']') {
        /* Section name */
E
Emmanuel Leblond 已提交
586 587 588
        sscanf(line, "[%[^]]", section);
        strstrip(section);
        strlwc(section, section, len);
589
        sta = LINE_SECTION ;
E
Emmanuel Leblond 已提交
590
    } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
J
Jesper Jensen 已提交
591 592
           ||  sscanf (line, "%[^=] = '%[^\']'",   key, value) == 2) {
        /* Usual key=value with quotes, with or without comments */
593
        strstrip(key);
E
Emmanuel Leblond 已提交
594
        strlwc(key, key, len);
J
Jesper Jensen 已提交
595
        /* Don't strip spaces from values surrounded with quotes */
E
Emmanuel Leblond 已提交
596 597 598 599 600 601
        sta = LINE_VALUE ;
    } else if (sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
        /* Usual key=value without quotes, with or without comments */
        strstrip(key);
        strlwc(key, key, len);
        strstrip(value);
602 603 604 605 606 607 608 609
        /*
         * sscanf cannot handle '' or "" as empty values
         * this is done here
         */
        if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
            value[0]=0 ;
        }
        sta = LINE_VALUE ;
E
Emmanuel Leblond 已提交
610 611
    } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2
           ||  sscanf(line, "%[^=] %[=]", key, value) == 2) {
612 613 614 615 616 617
        /*
         * Special cases:
         * key=
         * key=;
         * key=#
         */
618
        strstrip(key);
E
Emmanuel Leblond 已提交
619
        strlwc(key, key, len);
620 621 622 623 624 625
        value[0]=0 ;
        sta = LINE_VALUE ;
    } else {
        /* Generate syntax error */
        sta = LINE_ERROR ;
    }
626

E
Emmanuel Leblond 已提交
627
    free(line);
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
    return sta ;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Parse an ini file and return an allocated dictionary object
  @param    ininame Name of the ini file to read.
  @return   Pointer to newly allocated dictionary

  This is the parser for ini files. This function is called, providing
  the name of the file to be read. It returns a dictionary object that
  should not be accessed directly, but through accessor functions
  instead.

  The returned dictionary must be freed using iniparser_freedict().
 */
/*--------------------------------------------------------------------------*/
645
dictionary * iniparser_load(const char * ininame)
646
{
E
Emmanuel Leblond 已提交
647
    FILE * in ;
648 649

    char line    [ASCIILINESZ+1] ;
E
Emmanuel Leblond 已提交
650 651 652 653
    char section [ASCIILINESZ+1] ;
    char key     [ASCIILINESZ+1] ;
    char tmp     [(ASCIILINESZ * 2) + 1] ;
    char val     [ASCIILINESZ+1] ;
654

E
Emmanuel Leblond 已提交
655
    int  last=0 ;
656 657 658 659
    int  len ;
    int  lineno=0 ;
    int  errs=0;

E
Emmanuel Leblond 已提交
660
    dictionary * dict ;
661 662 663

    if ((in=fopen(ininame, "r"))==NULL) {
        fprintf(stderr, "iniparser: cannot open %s\n", ininame);
E
Emmanuel Leblond 已提交
664
        return NULL ;
665 666 667 668
    }

    dict = dictionary_new(0) ;
    if (!dict) {
E
Emmanuel Leblond 已提交
669 670
        fclose(in);
        return NULL ;
671 672 673
    }

    memset(line,    0, ASCIILINESZ);
E
Emmanuel Leblond 已提交
674 675 676 677
    memset(section, 0, ASCIILINESZ);
    memset(key,     0, ASCIILINESZ);
    memset(val,     0, ASCIILINESZ);
    last=0 ;
678

E
Emmanuel Leblond 已提交
679
    while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
680 681
        lineno++ ;
        len = (int)strlen(line)-1;
682
        if (len<=0)
N
ndevilla 已提交
683
            continue;
684
        /* Safety check against buffer overflows */
685
        if (line[len]!='\n' && !feof(in)) {
686 687 688 689
            fprintf(stderr,
                    "iniparser: input line too long in %s (%d)\n",
                    ininame,
                    lineno);
E
Emmanuel Leblond 已提交
690 691 692
            dictionary_del(dict);
            fclose(in);
            return NULL ;
693 694 695 696 697 698 699
        }
        /* Get rid of \n and spaces at end of line */
        while ((len>=0) &&
                ((line[len]=='\n') || (isspace(line[len])))) {
            line[len]=0 ;
            len-- ;
        }
700 701 702
        if (len < 0) { /* Line was entirely \n and/or spaces */
            len = 0;
        }
703 704 705
        /* Detect multi-line */
        if (line[len]=='\\') {
            /* Multi-line value */
E
Emmanuel Leblond 已提交
706
            last=len ;
707
            continue ;
E
Emmanuel Leblond 已提交
708 709
        } else {
            last=0 ;
710
        }
E
Emmanuel Leblond 已提交
711
        switch (iniparser_line(line, section, key, val)) {
712 713 714 715 716
            case LINE_EMPTY:
            case LINE_COMMENT:
            break ;

            case LINE_SECTION:
E
Emmanuel Leblond 已提交
717
            errs = dictionary_set(dict, section, NULL);
718 719 720
            break ;

            case LINE_VALUE:
E
Emmanuel Leblond 已提交
721 722
            sprintf(tmp, "%s:%s", section, key);
            errs = dictionary_set(dict, tmp, val) ;
723 724 725 726 727 728
            break ;

            case LINE_ERROR:
            fprintf(stderr, "iniparser: syntax error in %s (%d):\n",
                    ininame,
                    lineno);
E
Emmanuel Leblond 已提交
729
            fprintf(stderr, "-> %s\n", line);
730 731 732 733 734 735 736
            errs++ ;
            break;

            default:
            break ;
        }
        memset(line, 0, ASCIILINESZ);
E
Emmanuel Leblond 已提交
737
        last=0;
738 739 740 741 742 743 744 745 746
        if (errs<0) {
            fprintf(stderr, "iniparser: memory allocation failure\n");
            break ;
        }
    }
    if (errs) {
        dictionary_del(dict);
        dict = NULL ;
    }
E
Emmanuel Leblond 已提交
747
    fclose(in);
748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765
    return dict ;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Free all memory associated to an ini dictionary
  @param    d Dictionary to free
  @return   void

  Free all memory associated to an ini dictionary.
  It is mandatory to call this function before the dictionary object
  gets out of the current context.
 */
/*--------------------------------------------------------------------------*/
void iniparser_freedict(dictionary * d)
{
    dictionary_del(d);
}