Annotation of embedaddon/strongswan/src/libstrongswan/settings/settings.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2010-2018 Tobias Brunner
                      3:  * Copyright (C) 2008 Martin Willi
                      4:  * HSR Hochschule fuer Technik Rapperswil
                      5:  *
                      6:  * This program is free software; you can redistribute it and/or modify it
                      7:  * under the terms of the GNU General Public License as published by the
                      8:  * Free Software Foundation; either version 2 of the License, or (at your
                      9:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                     10:  *
                     11:  * This program is distributed in the hope that it will be useful, but
                     12:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     13:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     14:  * for more details.
                     15:  */
                     16: 
                     17: #define _GNU_SOURCE
                     18: #include <string.h>
                     19: #include <stdarg.h>
                     20: #include <stdio.h>
                     21: #include <errno.h>
                     22: #include <limits.h>
                     23: #include <sys/types.h>
                     24: #include <sys/stat.h>
                     25: #include <unistd.h>
                     26: #include <ctype.h>
                     27: 
                     28: #include "settings.h"
                     29: #include "settings_types.h"
                     30: 
                     31: #include "collections/array.h"
                     32: #include "collections/hashtable.h"
                     33: #include "collections/linked_list.h"
                     34: #include "threading/rwlock.h"
                     35: #include "utils/debug.h"
                     36: 
                     37: typedef struct private_settings_t private_settings_t;
                     38: 
                     39: /**
                     40:  * Parse functions provided by the generated parser.
                     41:  */
                     42: bool settings_parser_parse_file(section_t *root, char *name);
                     43: bool settings_parser_parse_string(section_t *root, char *settings);
                     44: 
                     45: /**
                     46:  * Private data of settings
                     47:  */
                     48: struct private_settings_t {
                     49: 
                     50:        /**
                     51:         * Public interface
                     52:         */
                     53:        settings_t public;
                     54: 
                     55:        /**
                     56:         * Top level section
                     57:         */
                     58:        section_t *top;
                     59: 
                     60:        /**
                     61:         * Contents of replaced settings (char*)
                     62:         *
                     63:         * FIXME: This is required because the pointer returned by get_str()
                     64:         * is not refcounted.  Might cause ever increasing usage stats.
                     65:         */
                     66:        array_t *contents;
                     67: 
                     68:        /**
                     69:         * Lock to safely access the settings
                     70:         */
                     71:        rwlock_t *lock;
                     72: };
                     73: 
                     74: /**
                     75:  * Print a format key, but consume already processed arguments
                     76:  * Note that key and start point into the same string
                     77:  */
                     78: static bool print_key(char *buf, int len, char *start, char *key, va_list args)
                     79: {
                     80:        va_list copy;
                     81:        char *pos = start;
                     82:        bool res;
                     83: 
                     84:        va_copy(copy, args);
                     85:        while (TRUE)
                     86:        {
                     87:                pos = memchr(pos, '%', key - pos);
                     88:                if (!pos)
                     89:                {
                     90:                        break;
                     91:                }
                     92:                pos++;
                     93:                switch (*pos)
                     94:                {
                     95:                        case 'd':
                     96:                                va_arg(copy, int);
                     97:                                break;
                     98:                        case 's':
                     99:                                va_arg(copy, char*);
                    100:                                break;
                    101:                        case 'N':
                    102:                                va_arg(copy, enum_name_t*);
                    103:                                va_arg(copy, int);
                    104:                                break;
                    105:                        case '%':
                    106:                                break;
                    107:                        default:
                    108:                                DBG1(DBG_CFG, "settings with %%%c not supported!", *pos);
                    109:                                break;
                    110:                }
                    111:                pos++;
                    112:        }
                    113:        res = vsnprintf(buf, len, key, copy) < len;
                    114:        va_end(copy);
                    115:        return res;
                    116: }
                    117: 
                    118: /**
                    119:  * Check if the given section is contained in the given array.
                    120:  */
                    121: static bool has_section(array_t *array, section_t *section)
                    122: {
                    123:        section_t *current;
                    124:        int i;
                    125: 
                    126:        for (i = 0; i < array_count(array); i++)
                    127:        {
                    128:                array_get(array, i, &current);
                    129:                if (current == section)
                    130:                {
                    131:                        return TRUE;
                    132:                }
                    133:        }
                    134:        return FALSE;
                    135: }
                    136: 
                    137: /**
                    138:  * Find a section by a given key, using buffered key, reusable buffer.
                    139:  * If "ensure" is TRUE, the sections are created if they don't exist.
                    140:  */
                    141: static section_t *find_section_buffered(section_t *section,
                    142:                                        char *start, char *key, va_list args, char *buf, int len,
                    143:                                        bool ensure)
                    144: {
                    145:        char *pos;
                    146:        section_t *found = NULL;
                    147: 
                    148:        if (section == NULL)
                    149:        {
                    150:                return NULL;
                    151:        }
                    152:        pos = strchr(key, '.');
                    153:        if (pos)
                    154:        {
                    155:                *pos = '\0';
                    156:                pos++;
                    157:        }
                    158:        if (!print_key(buf, len, start, key, args))
                    159:        {
                    160:                return NULL;
                    161:        }
                    162:        if (!strlen(buf))
                    163:        {
                    164:                found = section;
                    165:        }
                    166:        else if (array_bsearch(section->sections, buf, settings_section_find,
                    167:                                                   &found) == -1)
                    168:        {
                    169:                if (ensure)
                    170:                {
                    171:                        found = settings_section_create(strdup(buf));
                    172:                        settings_section_add(section, found, NULL);
                    173:                }
                    174:        }
                    175:        if (found && pos)
                    176:        {
                    177:                return find_section_buffered(found, start, pos, args, buf, len, ensure);
                    178:        }
                    179:        return found;
                    180: }
                    181: 
                    182: /**
                    183:  * Forward declaration
                    184:  */
                    185: static array_t *find_sections(private_settings_t *this, section_t *section,
                    186:                                                          char *key, va_list args, array_t **sections);
                    187: 
                    188: /**
                    189:  * Resolve the given reference. Not thread-safe.
                    190:  * Only a vararg function to get an empty va_list.
                    191:  */
                    192: static void resolve_reference(private_settings_t *this, section_ref_t *ref,
                    193:                                                array_t **sections, ...)
                    194: {
                    195:        va_list args;
                    196: 
                    197:        va_start(args, sections);
                    198:        find_sections(this, this->top, ref->name, args, sections);
                    199:        va_end(args);
                    200: }
                    201: 
                    202: /**
                    203:  * Find all sections via a given key considering references, using buffered key,
                    204:  * reusable buffer.
                    205:  */
                    206: static void find_sections_buffered(private_settings_t *this, section_t *section,
                    207:                                                                   char *start, char *key, va_list args,
                    208:                                                                   char *buf, int len, bool ignore_refs,
                    209:                                                                   array_t **sections)
                    210: {
                    211:        section_t *found = NULL, *reference;
                    212:        array_t *references;
                    213:        section_ref_t *ref;
                    214:        char *pos;
                    215:        int i, j;
                    216: 
                    217:        if (!section)
                    218:        {
                    219:                return;
                    220:        }
                    221:        pos = strchr(key, '.');
                    222:        if (pos)
                    223:        {
                    224:                *pos = '\0';
                    225:        }
                    226:        if (!print_key(buf, len, start, key, args))
                    227:        {
                    228:                return;
                    229:        }
                    230:        if (pos)
                    231:        {       /* restore so we can follow references */
                    232:                *pos = '.';
                    233:        }
                    234:        if (!strlen(buf))
                    235:        {
                    236:                found = section;
                    237:        }
                    238:        else
                    239:        {
                    240:                array_bsearch(section->sections, buf, settings_section_find, &found);
                    241:        }
                    242:        if (found)
                    243:        {
                    244:                if (pos)
                    245:                {
                    246:                        find_sections_buffered(this, found, start, pos+1, args, buf, len,
                    247:                                                                   FALSE, sections);
                    248:                }
                    249:                else if (!has_section(*sections, found))
                    250:                {
                    251:                        /* ignore if already added to avoid loops */
                    252:                        array_insert_create(sections, ARRAY_TAIL, found);
                    253:                        /* add all sections that are referenced here (also resolves
                    254:                         * references in parent sections of the referenced section) */
                    255:                        for (i = 0; i < array_count(found->references); i++)
                    256:                        {
                    257:                                array_get(found->references, i, &ref);
                    258:                                resolve_reference(this, ref, sections);
                    259:                        }
                    260:                }
                    261:        }
                    262:        if (!ignore_refs && section != found && section->references)
                    263:        {
                    264:                /* find matching sub-sections relative to the referenced sections */
                    265:                for (i = 0; i < array_count(section->references); i++)
                    266:                {
                    267:                        array_get(section->references, i, &ref);
                    268:                        references = NULL;
                    269:                        resolve_reference(this, ref, &references);
                    270:                        for (j = 0; j < array_count(references); j++)
                    271:                        {
                    272:                                array_get(references, j, &reference);
                    273:                                /* ignore references in this referenced section, they were
                    274:                                 * resolved via resolve_reference() */
                    275:                                find_sections_buffered(this, reference, start, key, args,
                    276:                                                                           buf, len, TRUE, sections);
                    277:                        }
                    278:                        array_destroy(references);
                    279:                }
                    280:        }
                    281: }
                    282: 
                    283: /**
                    284:  * Ensure that the section with the given key exists (not thread-safe).
                    285:  */
                    286: static section_t *ensure_section(private_settings_t *this, section_t *section,
                    287:                                                                 const char *key, va_list args)
                    288: {
                    289:        char buf[128], keybuf[512];
                    290: 
                    291:        if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
                    292:        {
                    293:                return NULL;
                    294:        }
                    295:        return find_section_buffered(section, keybuf, keybuf, args, buf,
                    296:                                                                 sizeof(buf), TRUE);
                    297: }
                    298: 
                    299: /**
                    300:  * Find a section by a given key with resolved references (not thread-safe!).
                    301:  * The array is allocated. NULL is returned if no sections are found.
                    302:  */
                    303: static array_t *find_sections(private_settings_t *this, section_t *section,
                    304:                                                          char *key, va_list args, array_t **sections)
                    305: {
                    306:        char buf[128], keybuf[512];
                    307: 
                    308:        if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
                    309:        {
                    310:                return NULL;
                    311:        }
                    312:        find_sections_buffered(this, section, keybuf, keybuf, args, buf,
                    313:                                                   sizeof(buf), FALSE, sections);
                    314:        return *sections;
                    315: }
                    316: 
                    317: /**
                    318:  * Find the key/value pair for a key, using buffered key, reusable buffer
                    319:  * There are two modes: 1. To find a key at an exact location and create the
                    320:  * sections (and key/value pair) if necessary, don't pass an array for sections.
                    321:  * 2. To find a key and follow references pass a pointer to an array to store
                    322:  * visited sections. NULL is returned in this case if the key is not found.
                    323:  */
                    324: static kv_t *find_value_buffered(private_settings_t *this, section_t *section,
                    325:                                                                 char *start, char *key, va_list args,
                    326:                                                                 char *buf, int len, bool ignore_refs,
                    327:                                                                 array_t **sections)
                    328: {
                    329:        section_t *found = NULL;
                    330:        kv_t *kv = NULL;
                    331:        section_ref_t *ref;
                    332:        array_t *references;
                    333:        char *pos;
                    334:        int i, j;
                    335: 
                    336:        if (!section)
                    337:        {
                    338:                return NULL;
                    339:        }
                    340:        pos = strchr(key, '.');
                    341:        if (pos)
                    342:        {
                    343:                *pos = '\0';
                    344:                if (!print_key(buf, len, start, key, args))
                    345:                {
                    346:                        return NULL;
                    347:                }
                    348:                /* restore so we can follow references */
                    349:                *pos = '.';
                    350:                if (!strlen(buf))
                    351:                {
                    352:                        found = section;
                    353:                }
                    354:                else if (array_bsearch(section->sections, buf, settings_section_find,
                    355:                                                           &found) == -1)
                    356:                {
                    357:                        if (!sections)
                    358:                        {
                    359:                                found = settings_section_create(strdup(buf));
                    360:                                settings_section_add(section, found, NULL);
                    361:                        }
                    362:                }
                    363:                if (found)
                    364:                {
                    365:                        kv = find_value_buffered(this, found, start, pos+1, args, buf, len,
                    366:                                                                         FALSE, sections);
                    367:                }
                    368:        }
                    369:        else
                    370:        {
                    371:                if (sections)
                    372:                {
                    373:                        array_insert_create(sections, ARRAY_TAIL, section);
                    374:                }
                    375:                if (!print_key(buf, len, start, key, args))
                    376:                {
                    377:                        return NULL;
                    378:                }
                    379:                if (array_bsearch(section->kv, buf, settings_kv_find, &kv) == -1)
                    380:                {
                    381:                        if (!sections)
                    382:                        {
                    383:                                kv = settings_kv_create(strdup(buf), NULL);
                    384:                                settings_kv_add(section, kv, NULL);
                    385:                        }
                    386:                }
                    387:        }
                    388:        if (!kv && !ignore_refs && sections && section->references)
                    389:        {
                    390:                /* find key relative to the referenced sections */
                    391:                for (i = 0; !kv && i < array_count(section->references); i++)
                    392:                {
                    393:                        array_get(section->references, i, &ref);
                    394:                        references = NULL;
                    395:                        resolve_reference(this, ref, &references);
                    396:                        for (j = 0; !kv && j < array_count(references); j++)
                    397:                        {
                    398:                                array_get(references, j, &found);
                    399:                                /* ignore if already added to avoid loops */
                    400:                                if (!has_section(*sections, found))
                    401:                                {
                    402:                                        /* ignore references in this referenced section, they were
                    403:                                         * resolved via resolve_reference() */
                    404:                                        kv = find_value_buffered(this, found, start, key, args,
                    405:                                                                                         buf, len, TRUE, sections);
                    406:                                }
                    407:                        }
                    408:                        array_destroy(references);
                    409:                }
                    410:        }
                    411:        return kv;
                    412: }
                    413: 
                    414: /**
                    415:  * Remove the key/value pair for a key, using buffered key, reusable buffer
                    416:  */
                    417: static void remove_value_buffered(private_settings_t *this, section_t *section,
                    418:                                                                  char *start, char *key, va_list args,
                    419:                                                                  char *buf, int len)
                    420: {
                    421:        section_t *found = NULL;
                    422:        kv_t *kv = NULL, *ordered = NULL;
                    423:        char *pos;
                    424:        int idx, i;
                    425: 
                    426:        if (!section)
                    427:        {
                    428:                return;
                    429:        }
                    430:        pos = strchr(key, '.');
                    431:        if (pos)
                    432:        {
                    433:                *pos = '\0';
                    434:                pos++;
                    435:        }
                    436:        if (!print_key(buf, len, start, key, args))
                    437:        {
                    438:                return;
                    439:        }
                    440:        if (!strlen(buf))
                    441:        {
                    442:                found = section;
                    443:        }
                    444:        if (pos)
                    445:        {
                    446:                if (array_bsearch(section->sections, buf, settings_section_find,
                    447:                                                  &found) != -1)
                    448:                {
                    449:                        remove_value_buffered(this, found, start, pos, args, buf, len);
                    450:                }
                    451:        }
                    452:        else
                    453:        {
                    454:                idx = array_bsearch(section->kv, buf, settings_kv_find, &kv);
                    455:                if (idx != -1)
                    456:                {
                    457:                        array_remove(section->kv, idx, NULL);
                    458:                        for (i = 0; i < array_count(section->kv_order); i++)
                    459:                        {
                    460:                                array_get(section->kv_order, i, &ordered);
                    461:                                if (kv == ordered)
                    462:                                {
                    463:                                        array_remove(section->kv_order, i, NULL);
                    464:                                        settings_kv_destroy(kv, this->contents);
                    465:                                        break;
                    466:                                }
                    467:                        }
                    468:                }
                    469:        }
                    470: }
                    471: 
                    472: /*
                    473:  * Described in header
                    474:  */
                    475: void settings_remove_value(settings_t *settings, char *key, ...)
                    476: {
                    477:        private_settings_t *this = (private_settings_t*)settings;
                    478:        char buf[128], keybuf[512];
                    479:        va_list args;
                    480: 
                    481:        if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
                    482:        {
                    483:                return;
                    484:        }
                    485:        va_start(args, key);
                    486: 
                    487:        this->lock->read_lock(this->lock);
                    488:        remove_value_buffered(this, this->top, keybuf, keybuf, args, buf,
                    489:                                                  sizeof(buf));
                    490:        this->lock->unlock(this->lock);
                    491: 
                    492:        va_end(args);
                    493: }
                    494: 
                    495: /**
                    496:  * Find the string value for a key (thread-safe).
                    497:  */
                    498: static char *find_value(private_settings_t *this, section_t *section,
                    499:                                                char *key, va_list args)
                    500: {
                    501:        char buf[128], keybuf[512], *value = NULL;
                    502:        array_t *sections = NULL;
                    503:        kv_t *kv;
                    504: 
                    505:        if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
                    506:        {
                    507:                return NULL;
                    508:        }
                    509:        this->lock->read_lock(this->lock);
                    510:        kv = find_value_buffered(this, section, keybuf, keybuf, args,
                    511:                                                         buf, sizeof(buf), FALSE, &sections);
                    512:        if (kv)
                    513:        {
                    514:                value = kv->value;
                    515:        }
                    516:        this->lock->unlock(this->lock);
                    517:        array_destroy(sections);
                    518:        return value;
                    519: }
                    520: 
                    521: /**
                    522:  * Set a value to a copy of the given string (thread-safe).
                    523:  */
                    524: static void set_value(private_settings_t *this, section_t *section,
                    525:                                          char *key, va_list args, char *value)
                    526: {
                    527:        char buf[128], keybuf[512];
                    528:        kv_t *kv;
                    529: 
                    530:        if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
                    531:        {
                    532:                return;
                    533:        }
                    534:        this->lock->write_lock(this->lock);
                    535:        kv = find_value_buffered(this, section, keybuf, keybuf, args,
                    536:                                                         buf, sizeof(buf), FALSE, NULL);
                    537:        if (kv)
                    538:        {
                    539:                settings_kv_set(kv, strdupnull(value), this->contents);
                    540:        }
                    541:        this->lock->unlock(this->lock);
                    542: }
                    543: 
                    544: METHOD(settings_t, get_str, char*,
                    545:        private_settings_t *this, char *key, char *def, ...)
                    546: {
                    547:        char *value;
                    548:        va_list args;
                    549: 
                    550:        va_start(args, def);
                    551:        value = find_value(this, this->top, key, args);
                    552:        va_end(args);
                    553:        if (value)
                    554:        {
                    555:                return value;
                    556:        }
                    557:        return def;
                    558: }
                    559: 
                    560: /**
                    561:  * Described in header
                    562:  */
                    563: inline bool settings_value_as_bool(char *value, bool def)
                    564: {
                    565:        if (value)
                    566:        {
                    567:                if (strcaseeq(value, "1") ||
                    568:                        strcaseeq(value, "yes") ||
                    569:                        strcaseeq(value, "true") ||
                    570:                        strcaseeq(value, "enabled"))
                    571:                {
                    572:                        return TRUE;
                    573:                }
                    574:                else if (strcaseeq(value, "0") ||
                    575:                                 strcaseeq(value, "no") ||
                    576:                                 strcaseeq(value, "false") ||
                    577:                                 strcaseeq(value, "disabled"))
                    578:                {
                    579:                        return FALSE;
                    580:                }
                    581:        }
                    582:        return def;
                    583: }
                    584: 
                    585: METHOD(settings_t, get_bool, bool,
                    586:        private_settings_t *this, char *key, int def, ...)
                    587: {
                    588:        char *value;
                    589:        va_list args;
                    590: 
                    591:        /* we can't use bool for def due to this call */
                    592:        va_start(args, def);
                    593:        value = find_value(this, this->top, key, args);
                    594:        va_end(args);
                    595:        return settings_value_as_bool(value, def);
                    596: }
                    597: 
                    598: /**
                    599:  * Described in header
                    600:  */
                    601: inline int settings_value_as_int(char *value, int def)
                    602: {
                    603:        int intval;
                    604:        char *end;
                    605:        int base = 10;
                    606: 
                    607:        if (value)
                    608:        {
                    609:                errno = 0;
                    610:                if (value[0] == '0' && value[1] == 'x')
                    611:                {       /* manually detect 0x prefix as we want to avoid octal encoding */
                    612:                        base = 16;
                    613:                }
                    614:                intval = strtoul(value, &end, base);
                    615:                if (errno == 0 && *end == 0 && end != value)
                    616:                {
                    617:                        return intval;
                    618:                }
                    619:        }
                    620:        return def;
                    621: }
                    622: 
                    623: METHOD(settings_t, get_int, int,
                    624:        private_settings_t *this, char *key, int def, ...)
                    625: {
                    626:        char *value;
                    627:        va_list args;
                    628: 
                    629:        va_start(args, def);
                    630:        value = find_value(this, this->top, key, args);
                    631:        va_end(args);
                    632:        return settings_value_as_int(value, def);
                    633: }
                    634: 
                    635: /**
                    636:  * Described in header
                    637:  */
                    638: inline uint64_t settings_value_as_uint64(char *value, uint64_t def)
                    639: {
                    640:        uint64_t intval;
                    641:        char *end;
                    642:        int base = 10;
                    643: 
                    644:        if (value)
                    645:        {
                    646:                errno = 0;
                    647:                if (value[0] == '0' && value[1] == 'x')
                    648:                {       /* manually detect 0x prefix as we want to avoid octal encoding */
                    649:                        base = 16;
                    650:                }
                    651:                intval = strtoull(value, &end, base);
                    652:                if (errno == 0 && *end == 0 && end != value)
                    653:                {
                    654:                        return intval;
                    655:                }
                    656:        }
                    657:        return def;
                    658: }
                    659: 
                    660: /**
                    661:  * Described in header
                    662:  */
                    663: inline double settings_value_as_double(char *value, double def)
                    664: {
                    665:        double dval;
                    666:        char *end;
                    667: 
                    668:        if (value)
                    669:        {
                    670:                errno = 0;
                    671:                dval = strtod(value, &end);
                    672:                if (errno == 0 && *end == 0 && end != value)
                    673:                {
                    674:                        return dval;
                    675:                }
                    676:        }
                    677:        return def;
                    678: }
                    679: 
                    680: METHOD(settings_t, get_double, double,
                    681:        private_settings_t *this, char *key, double def, ...)
                    682: {
                    683:        char *value;
                    684:        va_list args;
                    685: 
                    686:        va_start(args, def);
                    687:        value = find_value(this, this->top, key, args);
                    688:        va_end(args);
                    689:        return settings_value_as_double(value, def);
                    690: }
                    691: 
                    692: /**
                    693:  * Described in header
                    694:  */
                    695: inline uint32_t settings_value_as_time(char *value, uint32_t def)
                    696: {
                    697:        time_t val;
                    698: 
                    699:        if (timespan_from_string(value, NULL, &val))
                    700:        {
                    701:                return val;
                    702:        }
                    703:        return def;
                    704: }
                    705: 
                    706: METHOD(settings_t, get_time, uint32_t,
                    707:        private_settings_t *this, char *key, uint32_t def, ...)
                    708: {
                    709:        char *value;
                    710:        va_list args;
                    711: 
                    712:        va_start(args, def);
                    713:        value = find_value(this, this->top, key, args);
                    714:        va_end(args);
                    715:        return settings_value_as_time(value, def);
                    716: }
                    717: 
                    718: METHOD(settings_t, set_str, void,
                    719:        private_settings_t *this, char *key, char *value, ...)
                    720: {
                    721:        va_list args;
                    722:        va_start(args, value);
                    723:        set_value(this, this->top, key, args, value);
                    724:        va_end(args);
                    725: }
                    726: 
                    727: METHOD(settings_t, set_bool, void,
                    728:        private_settings_t *this, char *key, int value, ...)
                    729: {
                    730:        va_list args;
                    731:        /* we can't use bool for value due to this call */
                    732:        va_start(args, value);
                    733:        set_value(this, this->top, key, args, value ? "1" : "0");
                    734:        va_end(args);
                    735: }
                    736: 
                    737: METHOD(settings_t, set_int, void,
                    738:        private_settings_t *this, char *key, int value, ...)
                    739: {
                    740:        char val[16];
                    741:        va_list args;
                    742:        va_start(args, value);
                    743:        if (snprintf(val, sizeof(val), "%d", value) < sizeof(val))
                    744:        {
                    745:                set_value(this, this->top, key, args, val);
                    746:        }
                    747:        va_end(args);
                    748: }
                    749: 
                    750: METHOD(settings_t, set_double, void,
                    751:        private_settings_t *this, char *key, double value, ...)
                    752: {
                    753:        char val[64];
                    754:        va_list args;
                    755:        va_start(args, value);
                    756:        if (snprintf(val, sizeof(val), "%f", value) < sizeof(val))
                    757:        {
                    758:                set_value(this, this->top, key, args, val);
                    759:        }
                    760:        va_end(args);
                    761: }
                    762: 
                    763: METHOD(settings_t, set_time, void,
                    764:        private_settings_t *this, char *key, uint32_t value, ...)
                    765: {
                    766:        char val[16];
                    767:        va_list args;
                    768:        va_start(args, value);
                    769:        if (snprintf(val, sizeof(val), "%u", value) < sizeof(val))
                    770:        {
                    771:                set_value(this, this->top, key, args, val);
                    772:        }
                    773:        va_end(args);
                    774: }
                    775: 
                    776: METHOD(settings_t, set_default_str, bool,
                    777:        private_settings_t *this, char *key, char *value, ...)
                    778: {
                    779:        char *old;
                    780:        va_list args;
                    781: 
                    782:        va_start(args, value);
                    783:        old = find_value(this, this->top, key, args);
                    784:        va_end(args);
                    785: 
                    786:        if (!old)
                    787:        {
                    788:                va_start(args, value);
                    789:                set_value(this, this->top, key, args, value);
                    790:                va_end(args);
                    791:                return TRUE;
                    792:        }
                    793:        return FALSE;
                    794: }
                    795: 
                    796: /**
                    797:  * Data for enumerators
                    798:  */
                    799: typedef struct {
                    800:        /** settings_t instance */
                    801:        private_settings_t *settings;
                    802:        /** sections to enumerate */
                    803:        array_t *sections;
                    804:        /** sections/keys that were already enumerated */
                    805:        hashtable_t *seen;
                    806: } enumerator_data_t;
                    807: 
                    808: CALLBACK(enumerator_destroy, void,
                    809:        enumerator_data_t *this)
                    810: {
                    811:        this->settings->lock->unlock(this->settings->lock);
                    812:        this->seen->destroy(this->seen);
                    813:        array_destroy(this->sections);
                    814:        free(this);
                    815: }
                    816: 
                    817: CALLBACK(section_filter, bool,
                    818:        hashtable_t *seen, enumerator_t *orig, va_list args)
                    819: {
                    820:        section_t *section;
                    821:        char **out;
                    822: 
                    823:        VA_ARGS_VGET(args, out);
                    824: 
                    825:        while (orig->enumerate(orig, &section))
                    826:        {
                    827:                if (seen->get(seen, section->name))
                    828:                {
                    829:                        continue;
                    830:                }
                    831:                *out = section->name;
                    832:                seen->put(seen, section->name, section->name);
                    833:                return TRUE;
                    834:        }
                    835:        return FALSE;
                    836: }
                    837: 
                    838: /**
                    839:  * Enumerate sections of the given section
                    840:  */
                    841: static enumerator_t *section_enumerator(section_t *section,
                    842:                                                                                enumerator_data_t *data)
                    843: {
                    844:        return enumerator_create_filter(
                    845:                                                        array_create_enumerator(section->sections_order),
                    846:                                                        section_filter, data->seen, NULL);
                    847: }
                    848: 
                    849: METHOD(settings_t, create_section_enumerator, enumerator_t*,
                    850:        private_settings_t *this, char *key, ...)
                    851: {
                    852:        enumerator_data_t *data;
                    853:        array_t *sections = NULL;
                    854:        va_list args;
                    855: 
                    856:        this->lock->read_lock(this->lock);
                    857:        va_start(args, key);
                    858:        sections = find_sections(this, this->top, key, args, &sections);
                    859:        va_end(args);
                    860: 
                    861:        if (!sections)
                    862:        {
                    863:                this->lock->unlock(this->lock);
                    864:                return enumerator_create_empty();
                    865:        }
                    866:        INIT(data,
                    867:                .settings = this,
                    868:                .sections = sections,
                    869:                .seen = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
                    870:        );
                    871:        return enumerator_create_nested(array_create_enumerator(sections),
                    872:                                                (void*)section_enumerator, data, enumerator_destroy);
                    873: }
                    874: 
                    875: CALLBACK(kv_filter, bool,
                    876:        hashtable_t *seen, enumerator_t *orig, va_list args)
                    877: {
                    878:        kv_t *kv;
                    879:        char **key, **value;
                    880: 
                    881:        VA_ARGS_VGET(args, key, value);
                    882: 
                    883:        while (orig->enumerate(orig, &kv))
                    884:        {
                    885:                if (seen->get(seen, kv->key))
                    886:                {
                    887:                        continue;
                    888:                }
                    889:                seen->put(seen, kv->key, kv->key);
                    890:                if (!kv->value)
                    891:                {
                    892:                        continue;
                    893:                }
                    894:                *key = kv->key;
                    895:                *value = kv->value;
                    896:                return TRUE;
                    897:        }
                    898:        return FALSE;
                    899: }
                    900: 
                    901: /**
                    902:  * Enumerate key/value pairs of the given section
                    903:  */
                    904: static enumerator_t *kv_enumerator(section_t *section, enumerator_data_t *data)
                    905: {
                    906:        return enumerator_create_filter(array_create_enumerator(section->kv_order),
                    907:                                                                        kv_filter, data->seen, NULL);
                    908: }
                    909: 
                    910: METHOD(settings_t, create_key_value_enumerator, enumerator_t*,
                    911:        private_settings_t *this, char *key, ...)
                    912: {
                    913:        enumerator_data_t *data;
                    914:        array_t *sections = NULL;
                    915:        va_list args;
                    916: 
                    917:        this->lock->read_lock(this->lock);
                    918:        va_start(args, key);
                    919:        sections = find_sections(this, this->top, key, args, &sections);
                    920:        va_end(args);
                    921: 
                    922:        if (!sections)
                    923:        {
                    924:                this->lock->unlock(this->lock);
                    925:                return enumerator_create_empty();
                    926:        }
                    927:        INIT(data,
                    928:                .settings = this,
                    929:                .sections = sections,
                    930:                .seen = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
                    931:        );
                    932:        return enumerator_create_nested(array_create_enumerator(sections),
                    933:                                        (void*)kv_enumerator, data, (void*)enumerator_destroy);
                    934: }
                    935: 
                    936: METHOD(settings_t, add_fallback, void,
                    937:        private_settings_t *this, const char *key, const char *fallback, ...)
                    938: {
                    939:        section_t *section;
                    940:        va_list args;
                    941:        char buf[512];
                    942: 
                    943:        this->lock->write_lock(this->lock);
                    944:        va_start(args, fallback);
                    945:        section = ensure_section(this, this->top, key, args);
                    946:        va_end(args);
                    947: 
                    948:        va_start(args, fallback);
                    949:        if (section && vsnprintf(buf, sizeof(buf), fallback, args) < sizeof(buf))
                    950:        {
                    951:                settings_reference_add(section, strdup(buf), TRUE);
                    952:        }
                    953:        va_end(args);
                    954:        this->lock->unlock(this->lock);
                    955: }
                    956: 
                    957: /**
                    958:  * Load settings from files matching the given file pattern or from a string.
                    959:  * All files (even included ones) have to be loaded successfully.
                    960:  */
                    961: static section_t *load_internal(char *pattern, bool string)
                    962: {
                    963:        section_t *section;
                    964:        bool loaded;
                    965: 
                    966:        if (pattern == NULL || !pattern[0])
                    967:        {
                    968:                return settings_section_create(NULL);
                    969:        }
                    970: 
                    971:        section = settings_section_create(NULL);
                    972:        loaded = string ? settings_parser_parse_string(section, pattern) :
                    973:                                          settings_parser_parse_file(section, pattern);
                    974:        if (!loaded)
                    975:        {
                    976:                settings_section_destroy(section, NULL);
                    977:                section = NULL;
                    978:        }
                    979:        return section;
                    980: }
                    981: 
                    982: /**
                    983:  * Add sections and values in "section" relative to "parent".
                    984:  * If merge is FALSE the contents of parent are replaced with the parsed
                    985:  * contents, otherwise they are merged together.
                    986:  *
                    987:  * Releases the write lock and destroys the given section.
                    988:  * If parent is NULL this is all that happens.
                    989:  */
                    990: static bool extend_section(private_settings_t *this, section_t *parent,
                    991:                                                   section_t *section, bool merge)
                    992: {
                    993:        if (parent)
                    994:        {
                    995:                settings_section_extend(parent, section, this->contents, !merge);
                    996:        }
                    997:        this->lock->unlock(this->lock);
                    998:        settings_section_destroy(section, NULL);
                    999:        return parent != NULL;
                   1000: }
                   1001: 
                   1002: METHOD(settings_t, load_files, bool,
                   1003:        private_settings_t *this, char *pattern, bool merge)
                   1004: {
                   1005:        section_t *section;
                   1006: 
                   1007:        section = load_internal(pattern, FALSE);
                   1008:        if (!section)
                   1009:        {
                   1010:                return FALSE;
                   1011:        }
                   1012: 
                   1013:        this->lock->write_lock(this->lock);
                   1014:        return extend_section(this, this->top, section, merge);
                   1015: }
                   1016: 
                   1017: METHOD(settings_t, load_files_section, bool,
                   1018:        private_settings_t *this, char *pattern, bool merge, char *key, ...)
                   1019: {
                   1020:        section_t *section, *parent;
                   1021:        va_list args;
                   1022: 
                   1023:        section = load_internal(pattern, FALSE);
                   1024:        if (!section)
                   1025:        {
                   1026:                return FALSE;
                   1027:        }
                   1028: 
                   1029:        this->lock->write_lock(this->lock);
                   1030: 
                   1031:        va_start(args, key);
                   1032:        parent = ensure_section(this, this->top, key, args);
                   1033:        va_end(args);
                   1034: 
                   1035:        return extend_section(this, parent, section, merge);
                   1036: }
                   1037: 
                   1038: METHOD(settings_t, load_string, bool,
                   1039:        private_settings_t *this, char *settings, bool merge)
                   1040: {
                   1041:        section_t *section;
                   1042: 
                   1043:        section = load_internal(settings, TRUE);
                   1044:        if (!section)
                   1045:        {
                   1046:                return FALSE;
                   1047:        }
                   1048: 
                   1049:        this->lock->write_lock(this->lock);
                   1050:        return extend_section(this, this->top, section, merge);
                   1051: }
                   1052: 
                   1053: METHOD(settings_t, load_string_section, bool,
                   1054:        private_settings_t *this, char *settings, bool merge, char *key, ...)
                   1055: {
                   1056:        section_t *section, *parent;
                   1057:        va_list args;
                   1058: 
                   1059:        section = load_internal(settings, TRUE);
                   1060:        if (!section)
                   1061:        {
                   1062:                return FALSE;
                   1063:        }
                   1064: 
                   1065:        this->lock->write_lock(this->lock);
                   1066: 
                   1067:        va_start(args, key);
                   1068:        parent = ensure_section(this, this->top, key, args);
                   1069:        va_end(args);
                   1070: 
                   1071:        return extend_section(this, parent, section, merge);
                   1072: }
                   1073: 
                   1074: METHOD(settings_t, destroy, void,
                   1075:        private_settings_t *this)
                   1076: {
                   1077:        settings_section_destroy(this->top, NULL);
                   1078:        array_destroy_function(this->contents, (void*)free, NULL);
                   1079:        this->lock->destroy(this->lock);
                   1080:        free(this);
                   1081: }
                   1082: 
                   1083: static private_settings_t *settings_create_base()
                   1084: {
                   1085:        private_settings_t *this;
                   1086: 
                   1087:        INIT(this,
                   1088:                .public = {
                   1089:                        .get_str = _get_str,
                   1090:                        .get_int = _get_int,
                   1091:                        .get_double = _get_double,
                   1092:                        .get_time = _get_time,
                   1093:                        .get_bool = _get_bool,
                   1094:                        .set_str = _set_str,
                   1095:                        .set_int = _set_int,
                   1096:                        .set_double = _set_double,
                   1097:                        .set_time = _set_time,
                   1098:                        .set_bool = _set_bool,
                   1099:                        .set_default_str = _set_default_str,
                   1100:                        .create_section_enumerator = _create_section_enumerator,
                   1101:                        .create_key_value_enumerator = _create_key_value_enumerator,
                   1102:                        .add_fallback = _add_fallback,
                   1103:                        .load_files = _load_files,
                   1104:                        .load_files_section = _load_files_section,
                   1105:                        .load_string = _load_string,
                   1106:                        .load_string_section = _load_string_section,
                   1107:                        .destroy = _destroy,
                   1108:                },
                   1109:                .top = settings_section_create(NULL),
                   1110:                .contents = array_create(0, 0),
                   1111:                .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
                   1112:        );
                   1113:        return this;
                   1114: }
                   1115: 
                   1116: /*
                   1117:  * see header file
                   1118:  */
                   1119: settings_t *settings_create(char *file)
                   1120: {
                   1121:        private_settings_t *this = settings_create_base();
                   1122: 
                   1123:        load_files(this, file, FALSE);
                   1124: 
                   1125:        return &this->public;
                   1126: }
                   1127: 
                   1128: /*
                   1129:  * see header file
                   1130:  */
                   1131: settings_t *settings_create_string(char *settings)
                   1132: {
                   1133:        private_settings_t *this = settings_create_base();
                   1134: 
                   1135:        load_string(this, settings, FALSE);
                   1136: 
                   1137:        return &this->public;
                   1138: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>