Annotation of embedaddon/strongswan/src/libstrongswan/settings/settings.c, revision 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, ¤t);
! 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, §ions);
! 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, §ion))
! 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, §ions);
! 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, §ions);
! 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>