00001
00002
00003
00004
00005 static const char rcsid[] =
00006 "$Id: config.c,v 1.11 2006/01/11 14:07:10 tat Exp $";
00007
00008 #include <sys/types.h>
00009 #include <stdlib.h>
00010 #include <unistd.h>
00011 #include <string.h>
00012 #include <stdio.h>
00013
00014 #include <u/carpal.h>
00015 #include <u/queue.h>
00016 #include <u/config.h>
00017 #include <u/misc.h>
00018 #include <u/memory.h>
00019 #include <u/str.h>
00020
00033 TAILQ_HEAD(u_config_list_s, u_config_s);
00034 typedef struct u_config_list_s u_config_list_t;
00035
00036 struct u_config_s
00037 {
00038 TAILQ_ENTRY(u_config_s) np;
00039 char *key;
00040 char *value;
00041 u_config_list_t children;
00042 u_config_t *parent;
00043 };
00044
00056 void u_config_print(u_config_t *c, int lev)
00057 {
00058 u_config_t *item;
00059 int i;
00060
00061 for(i = 0; i < lev; ++i)
00062 printf(" ");
00063 printf("%s: %s\n", c->key, c->value);
00064
00065 ++lev;
00066 TAILQ_FOREACH(item, &c->children, np)
00067 u_config_print(item, lev);
00068 }
00069
00070 int u_config_add_child(u_config_t *c, const char *key, u_config_t **pc)
00071 {
00072 u_config_t *child = NULL;
00073
00074 dbg_err_if(u_config_create(&child));
00075
00076 child->parent = c;
00077 child->key = u_strdup(key);
00078 dbg_err_if(child->key == NULL);
00079
00080 TAILQ_INSERT_TAIL(&c->children, child, np);
00081
00082 *pc = child;
00083
00084 return 0;
00085 err:
00086 return ~0;
00087 }
00088
00089
00090 u_config_t* u_config_get_child_n(u_config_t *c, const char *key, int n)
00091 {
00092 u_config_t *item;
00093
00094 TAILQ_FOREACH(item, &c->children, np)
00095 {
00096 if(strcmp(item->key, key) == 0 && n-- == 0)
00097 return item;
00098 }
00099
00100 return NULL;
00101 }
00102
00103 u_config_t* u_config_get_child(u_config_t *c, const char *key)
00104 {
00105 return u_config_get_child_n(c, key, 0);
00106 }
00107
00108 int u_config_get_subkey_nth(u_config_t *c, const char *subkey, int n,
00109 u_config_t **pc)
00110 {
00111 u_config_t *child = NULL;
00112 char *first_key = NULL, *p;
00113
00114 if((p = strchr(subkey, '.')) == NULL)
00115 {
00116 if((child = u_config_get_child_n(c, subkey, n)) != NULL)
00117 {
00118 *pc = child;
00119 return 0;
00120 }
00121 } else {
00122 if((first_key = u_strndup(subkey, p-subkey)) != NULL)
00123 {
00124 child = u_config_get_child(c, first_key);
00125 U_FREE(first_key);
00126 }
00127 if(child != NULL)
00128 return u_config_get_subkey(child, ++p, pc);
00129 }
00130 return ~0;
00131
00132 }
00133
00134 int u_config_get_subkey(u_config_t *c, const char *subkey, u_config_t **pc)
00135 {
00136 return u_config_get_subkey_nth(c, subkey, 0, pc);
00137 }
00138
00139 static u_config_t* u_config_get_root(u_config_t *c)
00140 {
00141 while(c->parent)
00142 c = c->parent;
00143 return c;
00144 }
00145
00146 static int u_config_set_value(u_config_t *c, const char *val)
00147 {
00148 u_config_t *root, *ignore;
00149 const char *varval, *vs, *ve, *p;
00150 u_string_t *var = NULL, *value = NULL;
00151
00152 dbg_err_if(c == NULL);
00153
00154
00155 if(c->value)
00156 {
00157 U_FREE(c->value);
00158 c->value = NULL;
00159 }
00160
00161 if(val)
00162 {
00163 dbg_err_if(u_string_create(NULL, 0, &var));
00164 dbg_err_if(u_string_create(NULL, 0, &value));
00165
00166 root = u_config_get_root(c);
00167 dbg_err_if(root == NULL);
00168
00169
00170 vs = ve = val;
00171 for(; vs && *vs && (p = strstr(vs, "${")) != NULL; vs = ++ve)
00172 {
00173 dbg_err_if(u_string_append(value, vs, p-vs));
00174
00175
00176 vs = p+2;
00177
00178
00179 ve = strchr(vs, '}');
00180 dbg_err_if(ve == NULL);
00181
00182
00183 dbg_err_if(u_string_set(var, vs, ve-vs));
00184
00185
00186
00187 root = c->parent;
00188 if(u_config_get_subkey(root, u_string_c(var), &ignore))
00189 root = u_config_get_root(c);
00190 dbg_err_if(root == NULL);
00191
00192
00193 varval = u_config_get_subkey_value(root, u_string_c(var));
00194 if(varval != NULL)
00195 dbg_err_if(u_string_append(value, varval, strlen(varval)));
00196 }
00197 if(ve && *ve)
00198 dbg_err_if(u_string_append(value, ve, strlen(ve)));
00199
00200 u_string_trim(value);
00201
00202 c->value = u_strdup(u_string_c(value));;
00203 dbg_err_if(c->value == NULL);
00204
00205 u_string_free(value);
00206 u_string_free(var);
00207 }
00208
00209 return 0;
00210 err:
00211 if(value)
00212 u_string_free(value);
00213 if(var)
00214 u_string_free(var);
00215 return ~0;
00216 }
00217
00218 static int u_config_do_set_key(u_config_t *c, const char *key, const char *val,
00219 int overwrite)
00220 {
00221 u_config_t *child = NULL;
00222 char *p, *child_key;
00223
00224 if((p = strchr(key, '.')) == NULL)
00225 {
00226 child = u_config_get_child(c, key);
00227 if(child == NULL || !overwrite)
00228 {
00229 dbg_err_if(u_config_add_child(c, key, &child));
00230 }
00231 dbg_err_if(u_config_set_value(child, val));
00232 } else {
00233 child_key = u_strndup(key, p-key);
00234 dbg_err_if(child_key == NULL);
00235 if((child = u_config_get_child(c, child_key)) == NULL)
00236 dbg_err_if(u_config_add_child(c, child_key, &child));
00237 U_FREE(child_key);
00238 return u_config_do_set_key(child, ++p, val, overwrite);
00239 }
00240 return 0;
00241 err:
00242 return ~0;
00243 }
00244
00245 int u_config_add_key(u_config_t *c, const char *key, const char *val)
00246 {
00247 return u_config_do_set_key(c, key, val, 0 );
00248 }
00249
00250 int u_config_set_key(u_config_t *c, const char *key, const char *val)
00251 {
00252 return u_config_do_set_key(c, key, val, 1 );
00253 }
00254
00255 static int cs_getline(u_config_gets_t cb, void *arg, u_string_t *ln)
00256 {
00257 enum { BUFSZ = 1024 };
00258 char buf[BUFSZ], *p = NULL;
00259 ssize_t len;
00260
00261 u_string_clear(ln);
00262
00263 while((p = cb(arg, buf, BUFSZ)) != NULL)
00264 {
00265 len = strlen(buf);
00266 dbg_err_if(u_string_append(ln, buf, --len));
00267 if(!u_isnl(buf[len]))
00268 continue;
00269 else
00270 break;
00271 }
00272
00273 dbg_err_if(p == NULL);
00274
00275 return 0;
00276 err:
00277 return ~0;
00278 }
00279
00280 static int u_config_do_load(u_config_t *c, u_config_gets_t cb, void *arg,
00281 int overwrite)
00282 {
00283 enum { MAX_NEST_LEV = 20 };
00284 u_string_t *line = NULL, *key = NULL, *lastkey = NULL, *value = NULL;
00285 const char *ln, *p;
00286 size_t len;
00287 int lineno = 1;
00288 u_config_t *child = NULL;
00289
00290 dbg_err_if(u_string_create(NULL, 0, &line));
00291 dbg_err_if(u_string_create(NULL, 0, &key));
00292 dbg_err_if(u_string_create(NULL, 0, &value));
00293 dbg_err_if(u_string_create(NULL, 0, &lastkey));
00294
00295 for(; cs_getline(cb, arg, line) == 0; u_string_clear(line), ++lineno)
00296 {
00297
00298 if((p = strchr(u_string_c(line), '#')) != NULL)
00299 dbg_err_if(u_string_set_length(line, p - u_string_c(line)));
00300
00301
00302 dbg_err_if(u_string_trim(line));
00303
00304 ln = u_string_c(line);
00305 len = u_string_len(line);
00306
00307
00308 while(len && u_isnl(ln[len-1]))
00309 u_string_set_length(line, --len);
00310
00311 if(len == 0)
00312 continue;
00313
00314
00315 for(; u_isblank(*ln); ++ln);
00316
00317 if(ln[0] == '{')
00318 {
00319 if(u_string_len(lastkey) == 0)
00320 warn_err("config error [line %d]: { not after a no-value key",
00321 lineno);
00322 if(!u_isblank_str(++ln))
00323 warn_err("config error [line %d]: { or } must be the "
00324 "only not-blank char in a line", lineno);
00325
00326 dbg_err_if(u_config_add_child(c, u_string_c(lastkey), &child));
00327 dbg_err_if(u_config_do_load(child, cb, arg, overwrite));
00328 dbg_err_if(u_string_clear(lastkey));
00329 continue;
00330 } else if(ln[0] == '}') {
00331 warn_err_ifm(c->parent == NULL,"config error: unmatched '}'");
00332 if(!u_isblank_str(++ln))
00333 warn_err("config error [line %d]: { or } must be the "
00334 "only not-blank char in a line", lineno);
00335 return 0;
00336 }
00337
00338
00339 for(p = ln; *p && !u_isblank(*p); ++p);
00340
00341
00342 dbg_err_if(u_string_set(key, ln, p-ln));
00343
00344
00345 dbg_err_if(u_string_set(value, p, strlen(p)));
00346 dbg_err_if(u_string_trim(value));
00347
00348
00349 if(u_string_len(value) == 0)
00350 {
00351 dbg_err_if(u_string_set(lastkey, ln, p-ln));
00352 continue;
00353 }
00354
00355
00356 dbg_err_if(u_config_do_set_key(c,
00357 u_string_c(key),
00358 u_string_len(value) ? u_string_c(value) : NULL,
00359 overwrite));
00360 }
00361
00362 u_string_free(lastkey);
00363 u_string_free(value);
00364 u_string_free(key);
00365 u_string_free(line);
00366
00367 return 0;
00368 err:
00369 if(lastkey)
00370 u_string_free(lastkey);
00371 if(key)
00372 u_string_free(key);
00373 if(value)
00374 u_string_free(value);
00375 if(line)
00376 u_string_free(line);
00377 return ~0;
00378 }
00379
00380 int u_config_load_from(u_config_t *c, u_config_gets_t cb,
00381 void *arg, int overwrite)
00382 {
00383 dbg_err_if(u_config_do_load(c, cb, arg, overwrite));
00384
00385 return 0;
00386 err:
00387 return ~0;
00388 }
00389
00390 static char *u_config_fgetline(void* arg, char * buf, size_t size)
00391 {
00392 FILE *f = (FILE*)arg;
00393
00394 return fgets(buf, size, f);
00395 }
00396
00412 int u_config_load(u_config_t *c, int fd, int overwrite)
00413 {
00414 FILE *file;
00415
00416
00417 file = fdopen(dup(fd), "r");
00418 dbg_err_if(file == NULL);
00419
00420 dbg_err_if(u_config_do_load(c, u_config_fgetline, file, overwrite));
00421
00422 fclose(file);
00423
00424 return 0;
00425 err:
00426 U_FCLOSE(file);
00427 return ~0;
00428 }
00429
00430
00441 int u_config_create(u_config_t **pc)
00442 {
00443 u_config_t *c = NULL;
00444
00445 c = u_zalloc(sizeof(u_config_t));
00446 dbg_err_if(c == NULL);
00447
00448 TAILQ_INIT(&c->children);
00449
00450 *pc = c;
00451
00452 return 0;
00453 err:
00454 if(c)
00455 u_config_free(c);
00456 return ~0;
00457 }
00458
00468 static void u_config_del_key(u_config_t *c, u_config_t *child)
00469 {
00470 TAILQ_REMOVE(&c->children, child, np);
00471 }
00472
00482 int u_config_free(u_config_t *c)
00483 {
00484 u_config_t *child = NULL;
00485 if(c)
00486 {
00487
00488 while((child = TAILQ_FIRST(&c->children)) != NULL)
00489 {
00490 u_config_del_key(c, child);
00491 dbg_err_if(u_config_free(child));
00492 }
00493
00494 if(c->key)
00495 U_FREE(c->key);
00496 if(c->value)
00497 U_FREE(c->value);
00498 U_FREE(c);
00499 }
00500 return 0;
00501 err:
00502 return ~0;
00503 }
00504
00514 const char* u_config_get_key(u_config_t *c)
00515 {
00516 dbg_err_if(!c);
00517
00518 return c->key;
00519 err:
00520 return NULL;
00521 }
00522
00532 const char* u_config_get_value(u_config_t *c)
00533 {
00534 dbg_err_if(!c);
00535
00536 return c->value;
00537 err:
00538 return NULL;
00539 }
00540
00551 const char* u_config_get_subkey_value(u_config_t *c, const char *subkey)
00552 {
00553 u_config_t *skey;
00554
00555 nop_err_if(u_config_get_subkey(c, subkey, &skey));
00556
00557 return u_config_get_value(skey);
00558 err:
00559 return NULL;
00560 }
00561
00575 int u_config_get_subkey_value_i(u_config_t *c, const char *subkey, int def,
00576 int *out)
00577 {
00578 const char *v;
00579 char *ep = NULL;
00580 long l;
00581
00582 if((v = u_config_get_subkey_value(c, subkey)) == NULL)
00583 {
00584 *out = def;
00585 return 0;
00586 }
00587
00588 l = strtol(v, &ep, 0);
00589 dbg_err_if(*ep != '\0');
00590
00591
00592 *out = (int)l;
00593
00594 return 0;
00595 err:
00596 return ~0;
00597 }
00598
00613 int u_config_get_subkey_value_b(u_config_t *c, const char *subkey, int def,
00614 int *out)
00615 {
00616 const char *true_words[] = { "yes", "enable", "1", "on", NULL };
00617 const char *false_words[] = { "no", "disable", "0", "off", NULL };
00618 const char *v, *w;
00619
00620 if((v = u_config_get_subkey_value(c, subkey)) == NULL)
00621 {
00622 *out = def;
00623 return 0;
00624 }
00625
00626 for(w = *true_words; *w; ++w)
00627 {
00628 if(!strcasecmp(v, w))
00629 {
00630 *out = 1;
00631 return 0;
00632 }
00633 }
00634
00635 for(w = *false_words; *w; ++w)
00636 {
00637 if(!strcasecmp(v, w))
00638 {
00639 *out = 0;
00640 return 0;
00641 }
00642 }
00643
00644 return ~0;
00645 }
00646