iniparser.c 25.5 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 35
  @brief    Convert a string to lowercase.
  @param    s   String to convert.
36

37 38
  This function modifies the string passed, the modified string
  contains a lowercased version of the input string.
39 40
 */
/*--------------------------------------------------------------------------*/
41 42

static void strlwc(char * s)
43 44 45
{
    int i ;

46
    if (s==NULL) return;
47
    i=0 ;
48 49
    while (s[i]) {
        s[i] = (char)tolower((int)s[i]);
50 51 52 53 54 55
        i++ ;
    }
}

/*-------------------------------------------------------------------------*/
/**
56 57
  @brief    Remove blanks at the beginning and the end of a string.
  @param    s   String to parse.
58

59
  This function modifies the input string and returns a modified string
60 61 62 63
  which is identical to the input string, except that all blank
  characters at the end and the beg. of the string have been removed.
 */
/*--------------------------------------------------------------------------*/
64
void strstrip(char * s)
65
{
66 67
    if (s==NULL) return ;

68 69
    char *last = s + strlen(s);
    char *dest = s;
70 71
    
    while (isspace((int)*s) && *s) s++;
72
    while (last > s) {
73 74 75 76 77
        if (!isspace((int)*(last-1)))
            break ;
        last -- ;
    }
    *last = (char)0;
78 79

    memmove(dest,s,last - s + 1);
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 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 159 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 194 195
}

/*-------------------------------------------------------------------------*/
/**
  @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.
 */
/*--------------------------------------------------------------------------*/
int iniparser_getnsec(dictionary * d)
{
    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.
 */
/*--------------------------------------------------------------------------*/
char * iniparser_getsecname(dictionary * d, int n)
{
    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.
 */
/*--------------------------------------------------------------------------*/
void iniparser_dump(dictionary * d, FILE * f)
{
    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.
 */
/*--------------------------------------------------------------------------*/
void iniparser_dump_ini(dictionary * d, FILE * f)
{
196
    int     i ;
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
    int     nsec ;
    char *  secname ;

    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) ;
214
        iniparser_dumpsection_ini(d, secname, f) ;
215 216 217 218 219
    }
    fprintf(f, "\n");
    return ;
}

220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
/*-------------------------------------------------------------------------*/
/**
  @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.
 */
/*--------------------------------------------------------------------------*/
void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f)
{
    int     j ;
235 236
    char    *keym;
    int     secsize ;
237 238 239 240 241

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

    fprintf(f, "\n[%s]\n", s);
242 243 244
    secsize = (int)strlen(s) + 2;
    keym = malloc(secsize);
    snprintf(keym, secsize, "%s:", s);
245 246 247
    for (j=0 ; j<d->size ; j++) {
        if (d->key[j]==NULL)
            continue ;
248
        if (!strncmp(d->key[j], keym, secsize-1)) {
249 250
            fprintf(f,
                    "%-30s = %s\n",
251
                    d->key[j]+secsize-1,
252 253 254 255
                    d->val[j] ? d->val[j] : "");
        }
    }
    fprintf(f, "\n");
256
    free(keym);
257 258 259
    return ;
}

260 261 262 263 264 265 266 267 268 269
/*-------------------------------------------------------------------------*/
/**
  @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
 */
/*--------------------------------------------------------------------------*/
int iniparser_getsecnkeys(dictionary * d, char * s)
{
270 271
    int     secsize, nkeys ;
    char    *keym;
272 273 274 275 276 277 278
    int j ;

    nkeys = 0;

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

279 280 281
    secsize  = (int)strlen(s)+2;
    keym = malloc(secsize);
    snprintf(keym, secsize, "%s:", s);
282 283 284 285

    for (j=0 ; j<d->size ; j++) {
        if (d->key[j]==NULL)
            continue ;
286
        if (!strncmp(d->key[j], keym, secsize-1)) 
287 288
            nkeys++;
    }
289
    free(keym);
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
    return nkeys;

}

/*-------------------------------------------------------------------------*/
/**
  @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   pointer to statically allocated character strings

  This function queries a dictionary and finds all keys in a given section.
  Each pointer in the returned char pointer-to-pointer is pointing to
  a string allocated in the dictionary; do not free or modify them.
  
  This function returns NULL in case of error.
 */
/*--------------------------------------------------------------------------*/
char ** iniparser_getseckeys(dictionary * d, char * s)
{

    char **keys;

    int i, j ;
314 315
    char    *keym;
    int     secsize, nkeys ;
316 317 318 319 320 321 322 323 324 325

    keys = NULL;

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

    nkeys = iniparser_getsecnkeys(d, s);

    keys = (char**) malloc(nkeys*sizeof(char*));

326 327 328
    secsize  = (int)strlen(s) + 2;
    keym = malloc(secsize);
    snprintf(keym, secsize, "%s:", s);
329 330 331 332 333 334
    
    i = 0;

    for (j=0 ; j<d->size ; j++) {
        if (d->key[j]==NULL)
            continue ;
335
        if (!strncmp(d->key[j], keym, secsize-1)) {
336 337 338 339
            keys[i] = d->key[j];
            i++;
        }
    }
340
    free(keym);
341 342 343 344
    return keys;

}

345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
/*-------------------------------------------------------------------------*/
/**
  @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.
 */
/*--------------------------------------------------------------------------*/
360
char * iniparser_getstring(dictionary * d, const char * key, char * def)
361 362 363 364 365 366 367
{
    char * lc_key ;
    char * sval ;

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

368 369
    lc_key = xstrdup(key);
    strlwc(lc_key);
370
    sval = dictionary_get(d, lc_key, def);
371
    free(lc_key);
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
    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()
 */
/*--------------------------------------------------------------------------*/
402
int iniparser_getint(dictionary * d, const char * key, int notfound)
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
{
    char    *   str ;

    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.
 */
/*--------------------------------------------------------------------------*/
424
double iniparser_getdouble(dictionary * d, const char * key, double notfound)
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
{
    char    *   str ;

    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.
 */
/*--------------------------------------------------------------------------*/
465
int iniparser_getboolean(dictionary * d, const char * key, int notfound)
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
{
    char    *   c ;
    int         ret ;

    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.
 */
/*--------------------------------------------------------------------------*/
int iniparser_find_entry(
    dictionary  *   ini,
496
    const char  *   entry
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
)
{
    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
  contain the provided value. If it cannot be found, -1 is returned.
  It is Ok to set val to NULL.
 */
/*--------------------------------------------------------------------------*/
519
int iniparser_set(dictionary * ini, const char * entry, const char * val)
520
{
521 522 523 524 525 526
    int result = 0;
    char *lc_entry = xstrdup(entry);
    strlwc(lc_entry); 
    result = dictionary_set(ini, lc_entry, val) ;
    free(lc_entry);
    return result;
527 528 529 530 531 532 533 534 535 536 537 538
}

/*-------------------------------------------------------------------------*/
/**
  @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.
 */
/*--------------------------------------------------------------------------*/
539
void iniparser_unset(dictionary * ini, const char * entry)
540
{
541 542 543 544
    char* lc_entry = xstrdup(entry);
    strlwc(lc_entry);
    dictionary_unset(ini, lc_entry);
    free(lc_entry);
545 546 547 548
}

/*-------------------------------------------------------------------------*/
/**
549
  @brief    Load a single line from an INI file
550 551 552 553 554 555 556 557
  @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(
558
    int line_size,
559
    const char * input_line,
560 561 562
    char ** section_out,
    char ** key_out,
    char ** value_out)
563 564
{   
    line_status sta ;
565 566 567 568 569 570 571 572 573 574 575 576 577
    int len = line_size-1;
    char * line = malloc(line_size);
    char * key = NULL;
    char * value = NULL;
    char * equals = NULL;

    if (!line) {
        fprintf(stderr, "iniparser: memory alloc error\n");
        return LINE_ERROR;
    }

    *line = 0;

578

579 580
    strcpy(line, input_line);
    strstrip(line); 
581 582
    len = (int)strlen(line);

583 584 585 586 587 588 589 590 591 592 593 594
    /* only allocate necessary space for key & val */
    equals = strchr(line,'=');
    if (equals) {
        value = malloc((len + line) - equals + 1);
        key = malloc(equals - line + 1);
       *value = 0;
    } else {
        key = malloc(line_size + 1);
    }

    if (!key || (equals && !value)) {
        fprintf(stderr, "iniparser: memory alloc error\n");
595 596
        sta = LINE_ERROR;
        goto out;
597 598 599 600
    }

    *key = 0;

601 602 603 604
    sta = LINE_UNPROCESSED ;
    if (len<1) {
        /* Empty line */
        sta = LINE_EMPTY ;
605
    } else if (line[0]=='#' || line[0]==';') {
606 607 608 609
        /* Comment line */
        sta = LINE_COMMENT ; 
    } else if (line[0]=='[' && line[len-1]==']') {
        /* Section name */
610 611 612
        sscanf(line, "[%[^]]", key);
        strstrip(key);
        strlwc(key);
613
        sta = LINE_SECTION ;
614 615 616 617
	*section_out=key;
        /* don't free key's memory */
        key = NULL;
    } else if (equals && (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
618
           ||  sscanf (line, "%[^=] = '%[^\']'",   key, value) == 2
619
           ||  sscanf (line, "%[^=] = %[^;#]",     key, value) == 2)) {
620
        /* Usual key=value, with or without comments */
621 622 623
        strstrip(key);
        strlwc(key);
        strstrip(value);
624 625 626 627 628 629 630
        /*
         * sscanf cannot handle '' or "" as empty values
         * this is done here
         */
        if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
            value[0]=0 ;
        }
631 632 633 634
        *key_out = key;
        *value_out = value;
        key = NULL;
        value = NULL;
635
        sta = LINE_VALUE ;
636 637
    } else if (equals && (sscanf(line, "%[^=] = %[;#]", key, value)==2
           ||  sscanf(line, "%[^=] %[=]", key, value) == 2)) {
638 639 640 641 642 643
        /*
         * Special cases:
         * key=
         * key=;
         * key=#
         */
644 645
        strstrip(key);
        strlwc(key);
646
        value[0]=0 ;
647 648 649 650 651 652
        *key_out = key;
        *value_out = value;

        /* don't free out params key or val's memory */
        key = NULL;
        value = NULL;
653 654 655 656 657
        sta = LINE_VALUE ;
    } else {
        /* Generate syntax error */
        sta = LINE_ERROR ;
    }
658 659

out:    
660 661 662 663 664 665 666 667 668 669 670 671
    if (line) {
        free(line);
        line = NULL;
    }
    if (key) {
        free(key);
        key = NULL;
    }
    if (value) {
        free(value);
        value= NULL;
    }
672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688
    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().
 */
/*--------------------------------------------------------------------------*/
689
dictionary * iniparser_load(const char * ininame)
690
{
691
    FILE * in = NULL ;
692 693

    char line    [ASCIILINESZ+1] ;
694 695 696 697 698 699
    char *section = xstrdup("");
    char *current_section = NULL;
    char *key = NULL;
    char *val = NULL;
    char* full_line = NULL;
    char* prev_line = NULL;
700 701 702 703

    int  len ;
    int  lineno=0 ;
    int  errs=0;
704
    int  seckey_size=0;
705

706
    dictionary * dict = NULL ;
707 708 709

    if ((in=fopen(ininame, "r"))==NULL) {
        fprintf(stderr, "iniparser: cannot open %s\n", ininame);
710
	goto out;
711 712 713 714
    }

    dict = dictionary_new(0) ;
    if (!dict) {
715
	goto out;
716 717 718 719
    }

    memset(line,    0, ASCIILINESZ);

720 721 722 723 724 725 726 727 728 729 730 731 732 733 734
    while (fgets(line, ASCIILINESZ, in)!=NULL) {
        int prev_line_len = 0;
        int multi_line = 0;
        int total_size = 0;

        if (key) {
            free(key);
            key = NULL;
        }
        if (val) {
            free(val);
            val = NULL;
        }

         
735 736
        lineno++ ;
        len = (int)strlen(line)-1;
N
ndevilla 已提交
737 738
        if (len==0)
            continue;
739
        /* Safety check against buffer overflows */
740
        if (line[len]!='\n' && !feof(in)) {
741 742 743 744
            fprintf(stderr,
                    "iniparser: input line too long in %s (%d)\n",
                    ininame,
                    lineno);
745 746
            errs++;
            goto out;
747 748 749 750 751 752 753
        }
        /* Get rid of \n and spaces at end of line */
        while ((len>=0) &&
                ((line[len]=='\n') || (isspace(line[len])))) {
            line[len]=0 ;
            len-- ;
        }
754

755 756 757 758
        if (len < 0) { /* Line was entirely \n and/or spaces */
            len = 0;
        }

759 760
        /* Detect multi-line */
        if (line[len]=='\\') {
761 762 763
            multi_line = 1;
        }
        if (multi_line) {
764
            /* Multi-line value */
765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
            /* length without trailing '\' */
            /* remove multi-line indicator before appending*/
            line[len] = 0;
            len--;
        }

        /*
         * If processing a multi-line then append it the previous portion,
         * at this point 'full_line' has the previously read portion of a
         * multi-line line (or NULL)
         */
        prev_line = full_line;
        prev_line_len=0;
        if (prev_line) {
            prev_line_len = strlen(prev_line);
        }

	/* len is not strlen(line) but strlen(line) -1 */
        total_size = (len+1) + prev_line_len + 1;

        full_line = malloc(total_size);
        if (!full_line) {
            fprintf(stderr,
                    "iniparser: out of mem\n");
            errs++;
            goto out;
        }

        memset(full_line,0,total_size);

        if (prev_line) {
            strcpy(full_line,prev_line);
        }

        strcpy(full_line+prev_line_len,line);
        free(prev_line);
        prev_line = NULL;

        if (multi_line) {
804 805
            continue ;
        }
806 807

        switch (iniparser_line(total_size, full_line, &current_section, &key, &val)) {
808 809 810 811 812
            case LINE_EMPTY:
            case LINE_COMMENT:
            break ;

            case LINE_SECTION:
813 814 815 816 817 818
            if (section) {
                free(section);
                section=NULL;
            }
            errs = dictionary_set(dict, current_section, NULL);
            section = current_section;
819 820 821
            break ;

            case LINE_VALUE:
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
            {
                char *seckey;
                /* section + ':' + key + eos */
                seckey_size = strlen(section) + strlen(key) +2;
                seckey = malloc(seckey_size);
                if (!seckey) {
                    errs++;
                    fprintf(stderr,
                           "iniparser: out of mem\n");
                    goto out;
                }
                snprintf(seckey, seckey_size, "%s:%s", section, key);
                errs = dictionary_set(dict, seckey, val) ;
                free(seckey);
                seckey = NULL;
            }
838 839 840 841 842 843
            break ;

            case LINE_ERROR:
            fprintf(stderr, "iniparser: syntax error in %s (%d):\n",
                    ininame,
                    lineno);
844
            fprintf(stderr, "-> %s\n", full_line);
845 846 847 848 849 850 851
            errs++ ;
            break;

            default:
            break ;
        }
        memset(line, 0, ASCIILINESZ);
852 853 854 855
        if (full_line) {
            free(full_line);
            full_line = NULL;
        }
856 857 858 859 860
        if (errs<0) {
            fprintf(stderr, "iniparser: memory allocation failure\n");
            break ;
        }
    }
861
out:
862 863 864 865
    if (errs) {
        dictionary_del(dict);
        dict = NULL ;
    }
866 867 868 869 870 871 872 873 874 875 876 877
    if (val) {
        free(val);
        val = NULL;
    }
    if (key) {
        free(key);
        key = NULL;
    }
    if (section) {
        free(section);
        section = NULL;
    }
878 879 880 881 882 883 884 885
    if (full_line) {
        free(full_line);
        full_line = NULL;
    }
    if (prev_line) {
        free(prev_line);
        prev_line = NULL;
    }
886 887 888
    if (in) {
        fclose(in);
    }
889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
    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);
}

/* vim: set ts=4 et sw=4 tw=75 */