00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00033 #include <stdio.h>
00034 #include <string.h>
00035 #include <stdlib.h>
00036 #include <limits.h>
00037 #include <stdarg.h>
00038 #include <ctype.h>
00039 #include <assert.h>
00040 #include "config.h"
00041
00042 #define DEFAULT_CONFIG_PATH "../lr3.cfg"
00043
00044 #define err(args...) fprintf(stderr, args)
00045
00046 typedef struct _Parser Parser;
00047 typedef struct _ParserFile ParserFile;
00048 typedef struct _ConfigElement ConfigElement;
00049
00050 typedef int (*GetChFunc)(Parser *);
00051
00052 typedef enum {
00053 ParserTypeFile,
00054 } ParserType;
00055
00056 struct _Parser {
00057 ParserType type;
00058 GetChFunc get_ch;
00059 int extra_ch;
00060 };
00061
00062 struct _ParserFile {
00063 Parser p;
00064 char * filename;
00065 FILE * file;
00066 int row;
00067 int col;
00068 int in_comment;
00069 };
00070
00071 typedef enum {
00072 TokInvalid,
00073 TokIdentifier,
00074 TokOpenStruct,
00075 TokCloseStruct,
00076 TokOpenArray,
00077 TokCloseArray,
00078 TokArraySep,
00079 TokAssign,
00080 TokString,
00081 TokEndStatement,
00082 TokCast,
00083 TokEOF,
00084 } ConfigToken;
00085
00086 typedef enum {
00087 ConfigContainer,
00088 ConfigArray
00089 } ConfigType;
00090
00091 typedef enum {
00092 ConfigDataString,
00093 ConfigDataInt,
00094 ConfigDataBool,
00095 ConfigDataDouble
00096 } ConfigDataType;
00097
00098 struct _ConfigElement {
00099 ConfigType type;
00100 ConfigDataType data_type;
00101 ConfigElement * parent;
00102 char * name;
00103 ConfigElement * next;
00104 ConfigElement * children;
00105 int num_values;
00106 char ** values;
00107 };
00108
00109 struct _Config {
00110 ConfigElement * root;
00111 };
00112
00113
00114
00115 static int
00116 print_msg (Parser * p, char * format, ...)
00117 {
00118 va_list args;
00119 if (p->type == ParserTypeFile) {
00120 ParserFile * pf = (ParserFile *) p;
00121 char * fname = strrchr (pf->filename, '/');
00122 if (fname)
00123 fname++;
00124 else
00125 fname = pf->filename;
00126 fprintf (stderr, "%s:%d ", fname, pf->row+1);
00127 va_start (args, format);
00128 vfprintf (stderr, format, args);
00129 va_end (args);
00130 return 0;
00131 }
00132 return -1;
00133 }
00134
00135
00136
00137
00138
00139
00140
00141 static int
00142 get_ch_file (Parser * p)
00143 {
00144 ParserFile * pf = (ParserFile *) p;
00145 int ch;
00146
00147
00148 if (p->extra_ch) {
00149 ch = p->extra_ch;
00150 p->extra_ch = 0;
00151 return ch;
00152 }
00153
00154 while ((ch = getc (pf->file)) != EOF) {
00155 if (ch == '\n') {
00156 pf->row++;
00157 pf->col = 0;
00158 pf->in_comment = 0;
00159 return ' ';
00160 }
00161 if (ch == '#')
00162 pf->in_comment = 1;
00163 if (pf->in_comment)
00164 continue;
00165
00166 pf->col++;
00167 if (isspace (ch))
00168 return ' ';
00169 if (!isprint (ch)) {
00170 print_msg (p, "Error: Non-printable character 0x%02x\n", ch);
00171 return -1;
00172 }
00173 return ch;
00174 }
00175 return 0;
00176 }
00177
00178
00179
00180
00181 static int
00182 unget_ch (Parser * p, int ch)
00183 {
00184 p->extra_ch = ch;
00185 return 0;
00186 }
00187
00188
00189
00190
00191
00192
00193
00194 static int
00195 get_token (Parser * p, ConfigToken * tok, char * str, int len)
00196 {
00197 int prev_ch = 0;
00198 int ch, end_ch=0, c=0, escape=0;
00199 *tok = TokInvalid;
00200
00201
00202 while ((ch = p->get_ch (p)) == ' ');
00203
00204 if (ch == -1)
00205 return -1;
00206
00207 if (len < 4) {
00208 fprintf (stderr, "Error: not enough space to store token\n");
00209 return -1;
00210 }
00211
00212 if (ch == 0) {
00213 snprintf (str, len, "EOF");
00214 *tok = TokEOF;
00215 return 0;
00216 }
00217
00218 str[c++] = ch;
00219 if (ch == ';') {
00220 *tok = TokEndStatement;
00221 goto finish;
00222 }
00223 if (ch == '=') {
00224 *tok = TokAssign;
00225 goto finish;
00226 }
00227 if (ch == '[') {
00228 *tok = TokOpenArray;
00229 goto finish;
00230 }
00231 if (ch == ']') {
00232 *tok = TokCloseArray;
00233 goto finish;
00234 }
00235 if (ch == '{') {
00236 *tok = TokOpenStruct;
00237 goto finish;
00238 }
00239 if (ch == '}') {
00240 *tok = TokCloseStruct;
00241 goto finish;
00242 }
00243 if (ch == ',') {
00244 *tok = TokArraySep;
00245 goto finish;
00246 }
00247
00248
00249 if (ch == '\"') {
00250 c--;
00251 *tok = TokString;
00252 end_ch = '\"';
00253 escape = '\\';
00254 }
00255
00256
00257
00258 if (ch == '(') {
00259 c--;
00260 *tok = TokCast;
00261 end_ch = ')';
00262 escape = 0;
00263 }
00264
00265 if (isalnum (ch) || ch == '_' || ch == '-' || ch == '.') {
00266 *tok = TokIdentifier;
00267 end_ch = 0;
00268 escape = 0;
00269 }
00270
00271 if (*tok == TokInvalid) {
00272 print_msg (p, "Error: Unexpected character \"%c\"\n", ch);
00273 return -1;
00274 }
00275
00276
00277 while (1) {
00278 ch = p->get_ch (p);
00279
00280
00281 if (*tok == TokIdentifier &&
00282 !isalnum (ch) && ch != '_' && ch != '-' && ch != '.') {
00283 if (ch != 0)
00284 unget_ch (p, ch);
00285 goto finish;
00286 }
00287 if (ch == 0) {
00288 print_msg (p, "Error: Expected '%c' but got end-of-file\n",
00289 end_ch);
00290 return -1;
00291 }
00292
00293
00294 if (ch == end_ch && prev_ch != escape)
00295 goto finish;
00296 prev_ch = ch;
00297 str[c++] = ch;
00298
00299 if (c >= len) {
00300 print_msg (p, "Error: Token is too large for buffer (%d bytes)\n",
00301 len);
00302 return -1;
00303 }
00304 }
00305 finish:
00306 str[c] = '\0';
00307 return 0;
00308 }
00309
00310 static ConfigElement *
00311 new_element (const char * name)
00312 {
00313 ConfigElement * el;
00314
00315 el = (ConfigElement*) malloc (sizeof (ConfigElement));
00316 memset (el, 0, sizeof (ConfigElement));
00317 if (name)
00318 el->name = strdup (name);
00319 el->data_type = ConfigDataString;
00320
00321 return el;
00322 }
00323
00324 static void
00325 free_element (ConfigElement * el)
00326 {
00327 free (el->name);
00328 ConfigElement * child, * next;
00329 for (child = el->children; child; child = next) {
00330 next = child->next;
00331 free_element (child);
00332 }
00333 int i;
00334 for (i = 0; i < el->num_values; i++)
00335 free (el->values[i]);
00336 free (el->values);
00337 free (el);
00338 }
00339
00340 #if 0
00341
00342 static int
00343 print_all_tokens (Parser * p)
00344 {
00345 ConfigToken tok;
00346 char str[256];
00347
00348 while (get_token (p, &tok, str, sizeof (str)) == 0) {
00349 printf ("tok %d: %s\n", tok, str);
00350 if (tok == TokEOF)
00351 return 0;
00352 }
00353 return -1;
00354 }
00355 #endif
00356
00357
00358 static int
00359 add_child (Parser * p, ConfigElement * el, ConfigElement * child)
00360 {
00361 ConfigElement ** nptr;
00362 for (nptr = &el->children; *nptr != NULL; nptr = &((*nptr)->next));
00363 *nptr = child;
00364 child->next = NULL;
00365 child->parent = el;
00366 return 0;
00367 }
00368
00369
00370 static int
00371 add_value (Parser * p, ConfigElement * el, const char * str)
00372 {
00373 int n = el->num_values;
00374 el->values = (char**)realloc (el->values, (n + 1) * sizeof (char *));
00375 el->values[n] = strdup (str);
00376 el->num_values = n + 1;
00377 return 0;
00378 }
00379
00380
00381
00382
00383
00384 static int
00385 parse_array (Parser * p, ConfigElement * el)
00386 {
00387 ConfigToken tok;
00388 char str[256];
00389
00390 while (1) {
00391 if (get_token (p, &tok, str, sizeof (str)) < 0)
00392 goto fail;
00393
00394 if (tok == TokIdentifier || tok == TokString) {
00395 add_value (p, el, str);
00396 }
00397 else if (tok == TokCloseArray) {
00398 return 0;
00399 }
00400 else {
00401 print_msg (p, "Error: unexpected token \"%s\", expected value or "
00402 "end of array\n", str);
00403 goto fail;
00404 }
00405
00406 if (get_token (p, &tok, str, sizeof (str)) < 0)
00407 goto fail;
00408
00409 if (tok == TokArraySep) {
00410
00411 }
00412 else if (tok == TokCloseArray) {
00413 return 0;
00414 }
00415 else {
00416 print_msg (p, "Error: unexpected token \"%s\", expected comma or "
00417 "end of array\n", str);
00418 goto fail;
00419 }
00420 }
00421
00422 fail:
00423 return -1;
00424 }
00425
00426
00427
00428
00429
00430 static int
00431 parse_right_side (Parser * p, ConfigElement * el)
00432 {
00433 ConfigToken tok;
00434 char str[256];
00435
00436 if (get_token (p, &tok, str, sizeof (str)) != 0)
00437 goto fail;
00438
00439
00440 if (tok == TokCast) {
00441
00442 if (get_token (p, &tok, str, sizeof (str)) != 0)
00443 goto fail;
00444 }
00445
00446 if (tok == TokIdentifier || tok == TokString) {
00447 add_value (p, el, str);
00448 }
00449 else if (tok == TokOpenArray) {
00450 if (parse_array (p, el) < 0)
00451 goto fail;
00452 }
00453 else {
00454 print_msg (p, "Error: unexpected token \"%s\", expected right-hand "
00455 "side\n", str);
00456 goto fail;
00457 }
00458
00459 if (get_token (p, &tok, str, sizeof (str)) != 0)
00460 goto fail;
00461
00462 if (tok != TokEndStatement) {
00463 print_msg (p, "Error: unexpected token \"%s\", expected semicolon\n", str);
00464 goto fail;
00465 }
00466
00467 return 0;
00468
00469 fail:
00470 return -1;
00471 }
00472
00473
00474
00475
00476
00477 static int
00478 parse_container (Parser * p, ConfigElement * cont, ConfigToken end_token)
00479 {
00480 ConfigToken tok;
00481 char str[256];
00482 ConfigElement * child = NULL;
00483
00484 while (get_token (p, &tok, str, sizeof (str)) == 0) {
00485
00486 if (!child && tok == TokIdentifier) {
00487 child = new_element (str);
00488 }
00489 else if (child && tok == TokAssign) {
00490 child->type = ConfigArray;
00491 if (parse_right_side (p, child) < 0)
00492 goto fail;
00493 add_child (p, cont, child);
00494 child = NULL;
00495 }
00496 else if (child && tok == TokOpenStruct) {
00497 child->type = ConfigContainer;
00498 if (parse_container (p, child, TokCloseStruct) < 0)
00499 goto fail;
00500 add_child (p, cont, child);
00501 child = NULL;
00502 }
00503 else if (!child && tok == end_token)
00504 return 0;
00505 else {
00506 print_msg (p, "Error: unexpected token \"%s\"\n", str);
00507 goto fail;
00508 }
00509 }
00510
00511 fail:
00512 if (child) {
00513 free_element (child);
00514 }
00515 return -1;
00516 }
00517
00518 static int
00519 print_array (ConfigElement * el, int indent)
00520 {
00521 printf ("%*s%s = [", indent, "", el->name);
00522
00523 int i;
00524 for (i = 0; i < el->num_values; i++) {
00525 printf ("\"%s\", ", el->values[i]);
00526 }
00527 printf ("];\n");
00528 return 0;
00529 }
00530
00531 static int
00532 print_container (ConfigElement * el, int indent)
00533 {
00534 ConfigElement * child;
00535
00536 printf ("%*s%s {\n", indent, "", el->name);
00537
00538 for (child = el->children; child; child = child->next) {
00539 if (child->type == ConfigContainer)
00540 print_container (child, indent + 4);
00541 else if (child->type == ConfigArray)
00542 print_array (child, indent + 4);
00543 else {
00544 fprintf (stderr, "Error: unknown child (%d)\n", child->type);
00545 return -1;
00546 }
00547 }
00548
00549 printf ("%*s}\n", indent, "");
00550 return 0;
00551 }
00552
00553
00554
00555 int
00556 config_print (Config * conf)
00557 {
00558 ConfigElement * child, * root;
00559
00560 root = conf->root;
00561
00562 for (child = root->children; child; child = child->next) {
00563 if (child->type == ConfigContainer)
00564 print_container (child, 0);
00565 else if (child->type == ConfigArray)
00566 print_array (child, 0);
00567 else {
00568 fprintf (stderr, "Error: unknown child (%d)\n", child->type);
00569 return -1;
00570 }
00571 }
00572 return 0;
00573 }
00574
00575 Config *
00576 config_parse_file (FILE * f, char * filename)
00577 {
00578 ParserFile pf;
00579
00580 memset (&pf, 0, sizeof (ParserFile));
00581 pf.p.get_ch = get_ch_file;
00582 pf.p.type = ParserTypeFile;
00583 pf.file = f;
00584 pf.filename = filename;
00585
00586 ConfigElement * root;
00587
00588 root = new_element (NULL);
00589 root->type = ConfigContainer;
00590 if (parse_container (&pf.p, root, TokEOF) < 0) {
00591 free_element (root);
00592 return NULL;
00593 }
00594
00595 Config * conf;
00596 conf = (Config*)malloc (sizeof (Config));
00597 conf->root = root;
00598
00599 return conf;
00600 }
00601
00602 Config *
00603 config_parse_default (void)
00604 {
00605 char path[PATH_MAX];
00606 int status = config_get_default_src (path, sizeof (path));
00607 assert (0 == status);
00608
00609 FILE * f = fopen (path, "r");
00610 if (!f) {
00611 fprintf (stderr, "Error: failed to open %s\n", path);
00612 fprintf (stderr, "ERROR (%s:%d): Unable to load config file.\n"
00613 " If this is a clean svn checkout, then you must create a\n"
00614 " symbolic link to master.cfg from the actual config file used.\n"
00615 " e.g.\n"
00616 "\n"
00617 " $ cd dgc/software/trunk/config\n"
00618 " $ ln -s lr3.cfg master.cfg\n"
00619 "\n", __FILE__, __LINE__);
00620 return NULL;
00621 }
00622
00623 Config * conf = config_parse_file (f, path);
00624 fclose (f);
00625 return conf;
00626 }
00627
00628 int
00629 config_get_default_src (char *buf, int buflen)
00630 {
00631 char * path = getenv ("DGC_CONFIG_PATH");
00632 if (!path) path = DEFAULT_CONFIG_PATH;
00633 if (strlen (path) > (unsigned int) buflen - 1) return -1;
00634 strcpy (buf, path);
00635 return 0;
00636 }
00637
00638 void
00639 config_free (Config * conf)
00640 {
00641 free_element (conf->root);
00642 free (conf);
00643 }
00644
00645 static ConfigElement *
00646 find_key (ConfigElement * el, const char * key, int inherit)
00647 {
00648 size_t len = strcspn (key, ".");
00649 char str[len+1];
00650 memcpy (str, key, len);
00651 str[len] = '\0';
00652
00653 const char * remainder = NULL;
00654 if (key[len] == '.')
00655 remainder = key + len + 1;
00656
00657 ConfigElement * child;
00658 for (child = el->children; child; child = child->next) {
00659 if (!strcmp (str, child->name)) {
00660 if (remainder)
00661 return find_key (child, remainder, inherit);
00662 else
00663 return child;
00664 }
00665 }
00666 if (inherit && !remainder && el->parent)
00667 return find_key (el->parent, str, inherit);
00668 else
00669 return NULL;
00670 }
00671
00672 static int
00673 cast_to_int (const char * key, const char * val, int * out)
00674 {
00675 char * end;
00676 *out = strtol (val, &end, 0);
00677 if (end == val || *end != '\0') {
00678 fprintf (stderr, "Error: key \"%s\" (\"%s\") did not cast "
00679 "properly to int\n", key, val);
00680 return -1;
00681 }
00682 return 0;
00683 }
00684
00685 static int
00686 cast_to_boolean (const char * key, const char * val, int * out)
00687 {
00688 if (!strcasecmp (val, "y") || !strcasecmp (val, "yes") ||
00689 !strcasecmp (val, "true") || !strcmp (val, "1"))
00690 *out = 1;
00691 else if (!strcasecmp (val, "n") || !strcasecmp (val, "no") ||
00692 !strcasecmp (val, "false") || !strcmp (val, "0"))
00693 *out = 0;
00694 else {
00695 fprintf (stderr, "Error: key \"%s\" (\"%s\") did not cast "
00696 "properly to boolean\n", key, val);
00697 return -1;
00698 }
00699 return 0;
00700 }
00701
00702 static double
00703 cast_to_double (const char * key, const char * val, double * out)
00704 {
00705 char * end;
00706 *out = strtod (val, &end);
00707 if (end == val || *end != '\0') {
00708 fprintf (stderr, "Error: key \"%s\" (\"%s\") did not cast "
00709 "properly to double\n", key, val);
00710 return -1;
00711 }
00712 return 0;
00713 }
00714
00715 #define PRINT_KEY_NOT_FOUND(key) \
00716 err("WARNING: Config: could not find key %s!\n", (key));
00717
00718
00719 int
00720 config_has_key (Config *conf, const char *key)
00721 {
00722 return (find_key (conf->root, key, 1) != NULL);
00723 }
00724
00725 int
00726 config_get_num_subkeys (Config * conf, const char * containerKey)
00727 {
00728 ConfigElement* el = conf->root;
00729 if ((NULL != containerKey) && (0 < strlen(containerKey)))
00730 el = find_key (conf->root, containerKey, 1);
00731 if (NULL == el)
00732 return -1;
00733
00734 int count = 0;
00735 ConfigElement* child;
00736 for (child = el->children; child; child = child->next)
00737 ++count;
00738
00739 return count;
00740 }
00741
00742
00743 char **
00744 config_get_subkeys (Config * conf, const char * containerKey)
00745 {
00746 ConfigElement* el = conf->root;
00747 if ((NULL != containerKey) && (0 < strlen(containerKey)))
00748 el = find_key (conf->root, containerKey, 1);
00749 if (NULL == el)
00750 return NULL;
00751
00752 int count = 0;
00753 ConfigElement* child;
00754 for (child = el->children; child; child = child->next, ++count);
00755
00756 char **result = (char**)calloc (count + 1, sizeof (char*));
00757
00758 int i = 0;
00759 for (child = el->children; child; child = child->next) {
00760 result[i] = strdup (child->name);
00761 i++;
00762 }
00763
00764 return result;
00765 }
00766
00767
00768
00769 int
00770 config_get_int (Config * conf, const char * key, int * val)
00771 {
00772 ConfigElement * el = find_key (conf->root, key, 1);
00773 if (!el || el->type != ConfigArray || el->num_values < 1) {
00774 return -1;
00775 }
00776 return cast_to_int (key, el->values[0], val);
00777 }
00778
00779 int
00780 config_get_boolean (Config * conf, const char * key, int * val)
00781 {
00782 ConfigElement * el = find_key (conf->root, key, 1);
00783 if (!el || el->type != ConfigArray || el->num_values < 1) {
00784 return -1;
00785 }
00786 return cast_to_boolean (key, el->values[0], val);
00787 }
00788
00789 int
00790 config_get_double (Config * conf, const char * key, double * val)
00791 {
00792 ConfigElement * el = find_key (conf->root, key, 1);
00793 if (!el || el->type != ConfigArray || el->num_values < 1) {
00794 return -1;
00795 }
00796 return cast_to_double (key, el->values[0], val);
00797 }
00798
00799 double config_get_double_or_fail (Config *conf, const char *key)
00800 {
00801 double v;
00802 int res = config_get_double(conf, key, &v);
00803 if (res) {
00804 printf("Missing config key: %s\n", key);
00805 abort();
00806 }
00807
00808 return v;
00809 }
00810
00811 int
00812 config_get_str (Config * conf, const char * key, char ** val)
00813 {
00814 ConfigElement * el = find_key (conf->root, key, 1);
00815 if (!el || el->type != ConfigArray || el->num_values < 1) {
00816 return -1;
00817 }
00818 *val = el->values[0];
00819 return 0;
00820 }
00821
00822 char *config_get_str_or_fail (Config *conf, const char *key)
00823 {
00824 char * str;
00825 if (config_get_str (conf, key, &str) == 0)
00826 return str;
00827 else {
00828 printf("Missing config key: %s\n", key);
00829 abort();
00830 }
00831 }
00832
00833 int
00834 config_get_int_or_default (Config * conf, const char * key, int def)
00835 {
00836 int val;
00837 if (config_get_int (conf, key, &val) == 0)
00838 return val;
00839 else
00840 return def;
00841 }
00842
00843 int
00844 config_get_boolean_or_default (Config * conf, const char * key, int def)
00845 {
00846 int val;
00847 if (config_get_boolean (conf, key, &val) == 0)
00848 return val;
00849 else
00850 return def;
00851 }
00852
00853 double
00854 config_get_double_or_default (Config * conf, const char * key, double def)
00855 {
00856 double val;
00857 if (config_get_double (conf, key, &val) == 0)
00858 return val;
00859 else
00860 return def;
00861 }
00862
00863 char *
00864 config_get_str_or_default (Config * conf, const char * key, char * def)
00865 {
00866 char * str;
00867 if (config_get_str (conf, key, &str) == 0)
00868 return str;
00869 else
00870 return def;
00871 }
00872
00873 int
00874 config_get_int_array (Config * conf, const char * key, int * vals, int len)
00875 {
00876 ConfigElement * el = find_key (conf->root, key, 1);
00877 if (!el || el->type != ConfigArray) {
00878 return -1;
00879 }
00880 int i;
00881 for (i = 0; i < el->num_values; i++) {
00882 if (i == len)
00883 break;
00884 if (cast_to_int (key, el->values[i], vals + i) < 0) {
00885 err("WARNING: Config: cast error parsing int array %s\n", key);
00886 return -1;
00887 }
00888 }
00889 if( i < len ) {
00890 err("WARNING: Config: only read %d of %d values for integer array\n"
00891 " %s\n", i, len, key);
00892 }
00893 return i;
00894 }
00895
00896 int
00897 config_get_boolean_array (Config * conf, const char * key, int * vals, int len)
00898 {
00899 ConfigElement * el = find_key (conf->root, key, 1);
00900 if (!el || el->type != ConfigArray) {
00901 return -1;
00902 }
00903 int i;
00904 for (i = 0; i < el->num_values; i++) {
00905 if (i == len)
00906 break;
00907 if (cast_to_boolean (key, el->values[i], vals + i) < 0) {
00908 err("WARNING: Config: cast error parsing boolean array %s\n", key);
00909 return -1;
00910 }
00911 }
00912 if( i < len ) {
00913 err("WARNING: Config: only read %d of %d values for boolean array\n"
00914 " %s\n", i, len, key);
00915 }
00916 return i;
00917 }
00918
00919 int
00920 config_get_double_array (Config * conf, const char * key, double * vals, int len)
00921 {
00922 ConfigElement * el = find_key (conf->root, key, 1);
00923 if (!el || el->type != ConfigArray) {
00924 return -1;
00925 }
00926 int i;
00927 for (i = 0; i < el->num_values; i++) {
00928 if (i == len)
00929 break;
00930 if (cast_to_double (key, el->values[i], vals + i) < 0) {
00931 err("WARNING: Config: cast error parsing double array %s\n", key);
00932 return -1;
00933 }
00934 }
00935 if( i < len ) {
00936 err("WARNING: Config: only read %d of %d values for double array\n"
00937 " %s\n", i, len, key);
00938 }
00939 return i;
00940 }
00941
00942 int
00943 config_get_str_array (Config * conf, const char * key, char ** vals, int len)
00944 {
00945 ConfigElement * el = find_key (conf->root, key, 1);
00946 if (!el || el->type != ConfigArray) {
00947 return -1;
00948 }
00949 int i;
00950 for (i = 0; i < el->num_values; i++) {
00951 if (i == len)
00952 break;
00953 vals[i] = el->values[i];
00954 }
00955 if( i < len ) {
00956 err("WARNING: Config: only read %d of %d values for string array\n"
00957 " %s\n", i, len, key);
00958 }
00959 return i;
00960 }
00961
00962 int
00963 config_get_array_len (Config *conf, const char * key)
00964 {
00965 ConfigElement * el = find_key (conf->root, key, 1);
00966 if (!el || el->type != ConfigArray) {
00967 return -1;
00968 }
00969 return el->num_values;
00970 }
00971
00972 char **
00973 config_get_str_array_alloc (Config * conf, const char * key)
00974 {
00975 ConfigElement * el = find_key (conf->root, key, 1);
00976 if (!el || el->type != ConfigArray) {
00977 return NULL;
00978 }
00979
00980
00981 char **data = (char**)calloc(el->num_values + 1, sizeof(char*));
00982
00983 int i;
00984 for (i = 0; i < el->num_values; i++) {
00985 data[i] = strdup(el->values[i]);
00986 }
00987
00988 return data;
00989 }
00990
00991 void config_str_array_free(char **data)
00992 {
00993 int idx = 0;
00994 while (data[idx] != NULL)
00995 free(data[idx++]);
00996
00997 free(data);
00998 }
00999
01000 Config *
01001 config_alloc( void )
01002 {
01003 ConfigElement * root;
01004 root = new_element (NULL);
01005 root->type = ConfigContainer;
01006
01007 Config * conf;
01008 conf =(Config*)malloc (sizeof (Config));
01009 conf->root = root;
01010
01011 return conf;
01012 }
01013
01014 static ConfigElement *
01015 create_key(ConfigElement * el,
01016 const char * key)
01017 {
01018 size_t len = strcspn (key, ".");
01019 char str[len+1];
01020 memcpy (str, key, len);
01021 str[len] = '\0';
01022
01023 const char * remainder = NULL;
01024 if (key[len] == '.')
01025 remainder = key + len + 1;
01026
01027 ConfigElement * child;
01028 for (child = el->children; child; child = child->next) {
01029 if (!strcmp (str, child->name)) {
01030 if (remainder)
01031 return create_key (child, remainder);
01032 else
01033 return child;
01034 }
01035 }
01036
01037 child = new_element (str);
01038 add_child (NULL, el, child);
01039 if (remainder) {
01040 child->type = ConfigContainer;
01041 return create_key (child, remainder);
01042 }
01043 else {
01044 child->type = ConfigArray;
01045 return child;
01046 }
01047 }
01048
01049
01050
01051
01052
01053
01054 static int
01055 set_value (Config * conf,
01056 const char * key,
01057 const char * val)
01058 {
01059 ConfigElement * el = find_key (conf->root, key, 0);
01060 if (el == NULL)
01061 el = create_key (conf->root, key);
01062 else if (el->type != ConfigArray)
01063 return -1;
01064
01065 if (el->num_values < 1)
01066 add_value (NULL, el, val);
01067 else {
01068 free (el->values[0]);
01069 el->values[0] = strdup (val);
01070 }
01071 return 1;
01072 }
01073
01074
01075 int
01076 config_set_int (Config * conf,
01077 const char * key,
01078 int val)
01079 {
01080 char str[16];
01081 sprintf (str, "%d", val);
01082 return set_value (conf, key, str);
01083 }
01084
01085 int
01086 config_set_boolean (Config * conf,
01087 const char * key,
01088 int val)
01089 {
01090 return set_value (conf, key, (val == 0 ? "false" : "true"));
01091 }
01092
01093 int
01094 config_set_double (Config * conf,
01095 const char * key,
01096 double val)
01097 {
01098 char str[32];
01099 sprintf (str, "%f", val);
01100 return set_value (conf, key, str);
01101 }
01102
01103 int
01104 config_set_str (Config * conf,
01105 const char * key,
01106 char * val)
01107 {
01108 return set_value (conf, key, val);
01109 }
01110
01111
01112
01113
01114
01115
01116 int
01117 config_set_int_array (Config * conf,
01118 const char * key,
01119 int * vals,
01120 int len)
01121 {
01122 char* str;
01123 char single_val[16];
01124 int string_len = 1;
01125 int single_len;
01126 int i;
01127
01128 str = (char*)malloc(1);
01129 str[0] = '\0';
01130 for (i = 0; i < len; ++i) {
01131 if (i < len-1)
01132 sprintf (single_val, "%d,", vals[i]);
01133 else
01134 sprintf (single_val, "%d", vals[i]);
01135 single_len = strlen(single_val);
01136 str =(char*) realloc (str, string_len + single_len);
01137 strcat(str,single_val);
01138 string_len += single_len;
01139 }
01140
01141 int ret_val = set_value (conf, key, str);
01142 free (str);
01143 return ret_val;
01144 }
01145
01146 int
01147 config_set_boolean_array (Config * conf,
01148 const char * key,
01149 int * vals,
01150 int len)
01151 {
01152 char* str;
01153 char single_val[16];
01154 int string_len = 1;
01155 int single_len;
01156 int i;
01157 char val_str[8];
01158
01159 str = (char*)malloc(1);
01160 str[0] = '\0';
01161 for (i = 0; i < len; ++i) {
01162 strcpy(val_str, (vals[i] == 0 ? "false" : "true"));
01163 if (i < len-1)
01164 sprintf (single_val, "%s,", val_str);
01165 else
01166 sprintf (single_val, "%s", val_str);
01167 single_len = strlen(single_val);
01168 str = (char*)realloc (str, string_len + single_len);
01169 strcat(str,single_val);
01170 string_len += single_len;
01171 }
01172
01173 int ret_val = set_value (conf, key, str);
01174 free (str);
01175 return ret_val;
01176 }
01177
01178 int
01179 config_set_double_array (Config * conf,
01180 const char * key,
01181 double * vals,
01182 int len)
01183 {
01184 char* str;
01185 char single_val[32];
01186 int string_len = 1;
01187 int single_len;
01188 int i;
01189
01190 str =(char*) malloc(1);
01191 str[0] = '\0';
01192 for (i = 0; i < len; ++i) {
01193 if (i < len-1)
01194 sprintf (single_val, "%f,", vals[i]);
01195 else
01196 sprintf (single_val, "%f", vals[i]);
01197 single_len = strlen(single_val);
01198 str = (char*)realloc (str, string_len + single_len);
01199 strcat(str,single_val);
01200 string_len += single_len;
01201 }
01202
01203 int ret_val = set_value (conf, key, str);
01204 free (str);
01205 return ret_val;
01206 }
01207
01208 int
01209 config_set_str_array (Config * conf,
01210 const char * key,
01211 char ** vals,
01212 int len)
01213 {
01214 char* str;
01215 char single_val[256];
01216 int string_len = 1;
01217 int single_len;
01218 int i;
01219
01220 str = (char*)malloc(1);
01221 str[0] = '\0';
01222 for (i = 0; i < len; ++i) {
01223 if (i < len-1)
01224 sprintf (single_val, "%s,", vals[i]);
01225 else
01226 sprintf (single_val, "%s", vals[i]);
01227 single_len = strlen(single_val);
01228 str =(char*) realloc (str, string_len + single_len);
01229 strcat(str,single_val);
01230 string_len += single_len;
01231 }
01232
01233 int ret_val = set_value (conf, key, str);
01234 free (str);
01235 return ret_val;
01236 }