2 * UCW Library -- Shell Interface to Configuration Files
4 * (c) 2002--2005 Martin Mares <mj@ucw.cz>
5 * (c) 2006 Robert Spalek <robert@ucw.cz>
6 * (c) 2006 Pavel Charvat <pchar@ucw.cz>
8 * Once we were using this beautiful Shell version, but it turned out
9 * that it doesn't work with nested config files:
11 * eval `sed <cf/sherlock '/^#/d;/^ *$/d;s/ \+$//;
12 * h;s@[^ ]*@@;x;s@[ ].*@@;y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/;G;s/\n//;
13 * /^\[SECTION\]/,/^\[/ {; /^[A-Z]/ { s/^\([^ ]\+\)[ ]*\(.*\)$/SH_\1="\2"/; p; }; };
16 * This software may be freely distributed and used according to the terms
17 * of the GNU Lesser General Public License.
22 #include "ucw/getopt.h"
23 #include "ucw/conf-internal.h"
24 #include "ucw/clists.h"
25 #include "ucw/mempool.h"
26 #include "ucw/chartype.h"
28 #include "ucw/string.h"
39 Usage: config [-C<configfile>] [-S<section>.<option>=<value>] <sections>\n\
41 <sections>\t<section>[;<sections>]\n\
42 <section>\t[!]<name>{[<items>]}\n\
43 <items>\t\t[-]<item>[;<items>]\n\
44 <item>\t\t<static> | <array> | <list>\n\
45 <static>\t<type><name>[=<value>]\n\
46 <list>\t\t@<name>{[<items>]}\n\
47 <array>\t\t<type><name><left-bracket>[<number>]<right-bracket>\n\
48 <value>\t\t[a-zA-Z0-9.-/]* | 'string without single quotes'<value> | \"c-like string\"<value>\n\
52 #\t\t32-bit integer\n\
53 ##\t\t64-bit integer\n\
54 $\t\tFloating point number\n\
57 !\t\tReport unknown items as errors\n\
58 -\t\tDo not dump item's value\n\
72 #define FLAG_NO_UNKNOWN 0x2
89 static struct mempool *pool;
90 static clist sections;
104 die("Missing '%c'", c);
113 uns len = pos - name;
115 die("Expected item/section name");
116 byte *buf = mp_alloc(pool, len + 1);
117 memcpy(buf, name, len);
123 parse_section(struct section *section)
125 #define TRY(x) do{byte *_err=(x); if (_err) die(_err); }while(0)
126 for (uns sep = 0; ; sep = 1)
129 if (!*pos || *pos == '}')
140 struct section *sec = mp_alloc_zero(pool, sizeof(*sec));
141 sec->size = sizeof(cnode);
142 clist_init(&sec->list);
144 item->cf.name = parse_name();
145 item->cf.cls = CC_LIST;
154 item = mp_alloc_zero(pool, sizeof(*item));
157 item->flags |= FLAG_HIDE;
160 item->cf.cls = CC_STATIC;
168 item->cf.type = CT_U64;
171 item->cf.type = CT_INT;
175 item->cf.type = CT_DOUBLE;
179 die("Invalid type syntax");
180 item->cf.type = CT_STRING;
184 item->cf.name = parse_name();
190 item->cf.cls = CC_DYNAMIC;
192 while (*pos && *pos != ']')
198 item->cf.number = CF_ANY_NUM;
202 TRY(cf_parse_int(num, &inum));
204 die("Invalid array length");
205 item->cf.number = inum;
213 if (section->item.cf.cls == CC_LIST)
214 die("List items can not have default values");
215 if (item->cf.cls == CC_DYNAMIC)
216 die("Arrays can not have default values");
217 byte *def = pos, *d = def;
218 while (*pos != ';' && *pos != '}' && !Cspace(*pos))
226 die("Unterminated string");
231 else if (*pos == '"')
236 while (*pos != '"' || esc)
239 die("Unterminated string");
248 d = str_unesc(start, start);
254 byte *buf = mp_alloc(pool, len + 1);
255 memcpy(buf, def, len);
257 switch (item->cf.type)
260 item->value.v_ptr = buf;
263 TRY(cf_parse_int(buf, &item->value.v_int));
266 TRY(cf_parse_u64(buf, &item->value.v_u64));
269 TRY(cf_parse_double(buf, &item->value.v_double));
276 if (section->item.cf.cls == CC_LIST)
278 item->cf.ptr = (void *)(uintptr_t)section->size;
279 section->size += sizeof(union value);
282 item->cf.ptr = &item->value;
283 clist_add_tail(§ion->list, &item->node);
292 for (uns sep = 0; ; sep = 1)
300 struct section *sec = mp_alloc_zero(pool, sizeof(*sec));
304 sec->item.flags |= FLAG_NO_UNKNOWN;
306 sec->item.cf.name = parse_name();
309 clist_add_tail(§ions, &sec->item.node);
310 clist_init(&sec->list);
316 static struct cf_section *
317 generate_section(struct section *section)
319 struct cf_section *sec = mp_alloc_zero(pool, sizeof(*sec));
320 if (section->item.cf.cls == CC_LIST)
321 sec->size = section->size;
322 struct cf_item *c = sec->cfg = mp_alloc_zero(pool, sizeof(struct cf_item) * (section->count + 1));
323 CLIST_FOR_EACH(struct item *, item, section->list)
326 if (c->cls == CC_LIST)
327 c->u.sec = generate_section((struct section *)item);
337 dump_value(uns array, struct item *item, void *v)
339 byte buf[128], *value = buf;
341 printf("CF_%s_%s='", path.ptr, item->cf.name);
343 printf("CF_%s_%s[%u]='", path.ptr, item->cf.name, ++item->index);
344 switch (item->cf.type)
347 sprintf(buf, "%d", *(int *)v);
350 sprintf(buf, "%llu", (long long) *(u64 *)v);
353 sprintf(buf, "%g", *(double *)v);
375 dump_item(struct item *item, void *ptr, uns path_len)
377 if (item->flags & FLAG_HIDE)
379 byte *val = (byte *)((uintptr_t)ptr + (uintptr_t)item->cf.ptr);
380 if (item->cf.cls == CC_LIST)
382 uns len = strlen(item->cf.name);
383 bb_grow(&path, path_len + len + 1);
384 path.ptr[path_len] = '_';
385 memcpy(path.ptr + path_len + 1, item->cf.name, len);
386 CLIST_FOR_EACH(cnode *, ptr2, *(clist *)val)
387 CLIST_FOR_EACH(struct item *, item2, ((struct section *)item)->list)
388 dump_item(item2, ptr2, path_len + len + 1);
392 bb_grow(&path, path_len + 1)[path_len] = 0;
393 if (item->cf.cls == CC_STATIC)
394 dump_value(!!ptr, item, val);
398 uns len = DARY_LEN(val);
399 uns size = cf_type_size(item->cf.type, NULL);
400 for (uns i = 0; i < len; i++, val += size)
401 dump_value(1, item, val);
406 int main(int argc, char **argv)
411 pos = argv[argc - 1];
412 argv[argc - 1] = NULL;
414 pool = mp_new(0x1000);
415 clist_init(§ions);
417 CLIST_FOR_EACH(struct section *, sec, sections)
418 cf_declare_section(sec->item.cf.name, generate_section(sec), !(sec->item.flags & FLAG_NO_UNKNOWN));
420 if (cf_getopt(argc - 1, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL) != -1)
424 CLIST_FOR_EACH(struct section *, section, sections)
426 uns len = strlen(section->item.cf.name);
427 memcpy(bb_grow(&path, len), section->item.cf.name, len);
428 CLIST_FOR_EACH(struct item *, item, section->list)
429 dump_item(item, NULL, len);