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 "lib/getopt.h"
23 #include "lib/clists.h"
24 #include "lib/mempool.h"
25 #include "lib/chartype.h"
37 Usage: config [-C<configfile>] [-S<section>.<option>=<value>] <sections>\n\
39 <sections>\t<section>[,<sections>]\n\
40 <section>\t[*]<name>{[<items>]}\n\
41 <items>\t\t<item>[,<items>]\n\
42 <item>\t\t<static> | @<list>\n\
43 <static>\t[-]<type><name>\n\
44 <list>\t\t<name>{[<items>]}\n\
48 #\t\t32-bit integer\n\
49 ##\t\t64-bit integer\n\
50 $\t\tFloating point number\n\
53 !\t\tReport unknown items as errors\n\
54 -\t\tDo not dump item's value\n\
68 #define FLAG_NO_UNKNOWN 0x2
84 static struct mempool *pool;
85 static clist sections;
99 die("Missing '%c'", c);
108 uns len = pos - name;
110 die("Expected item/section name");
111 byte *buf = mp_alloc(pool, len + 1);
112 memcpy(buf, name, len);
118 parse_section(struct section *section)
120 for (uns sep = 0; ; sep = 1)
123 if (!*pos || *pos == '}')
134 struct section *sec = mp_alloc_zero(pool, sizeof(*sec));
135 sec->size = sizeof(cnode);
136 clist_init(&sec->list);
138 item->cf.name = parse_name();
139 item->cf.cls = CC_LIST;
148 item = mp_alloc_zero(pool, sizeof(*item));
151 item->flags |= FLAG_HIDE;
154 item->cf.cls = CC_STATIC;
162 item->cf.type = CT_U64;
165 item->cf.type = CT_INT;
169 item->cf.type = CT_DOUBLE;
173 die("Invalid type syntax");
174 item->cf.type = CT_STRING;
177 item->cf.name = parse_name();
179 if (section->item.cf.cls == CC_LIST)
181 item->cf.ptr = (void *)section->size;
182 section->size += sizeof(union value);
185 item->cf.ptr = &item->value;
186 clist_add_tail(§ion->list, &item->node);
194 for (uns sep = 0; ; sep = 1)
202 struct section *sec = mp_alloc_zero(pool, sizeof(*sec));
206 sec->item.flags |= FLAG_NO_UNKNOWN;
208 sec->item.cf.name = parse_name();
211 clist_add_tail(§ions, &sec->item.node);
212 clist_init(&sec->list);
218 static struct cf_section *
219 generate_section(struct section *section)
221 struct cf_section *sec = mp_alloc_zero(pool, sizeof(*sec));
222 if (section->item.cf.cls == CC_LIST)
223 sec->size = section->size;
224 struct cf_item *c = sec->cfg = mp_alloc_zero(pool, sizeof(struct cf_item) * (section->count + 1));
225 CLIST_FOR_EACH(struct item *, item, section->list)
228 if (c->cls == CC_LIST)
229 c->u.sec = generate_section((struct section *)item);
239 dump_item(struct item *item, void *ptr, uns path_len)
241 if (item->flags & FLAG_HIDE)
243 union value *val = (union value *)((addr_int_t)ptr + (addr_int_t)item->cf.ptr);
244 if (item->cf.cls == CC_LIST)
246 uns len = strlen(item->cf.name);
247 bb_grow(&path, path_len + len + 1);
248 path.ptr[path_len] = '_';
249 memcpy(path.ptr + path_len + 1, item->cf.name, len);
250 CLIST_FOR_EACH(cnode *, ptr2, val->list)
251 CLIST_FOR_EACH(struct item *, item2, ((struct section *)item)->list)
252 dump_item(item2, ptr2, path_len + len + 1);
256 byte *name = item->cf.name;
257 byte buf[128], *value = buf;
258 bb_grow(&path, path_len + 1)[path_len] = 0;
260 printf("CF_%s_%s='", path.ptr, name);
262 printf("CF_%s_%s[${#CF_%s_%s[*]}]='", path.ptr, name, path.ptr, name);
263 switch (item->cf.type)
266 sprintf(buf, "%d", val->v_int);
269 sprintf(buf, "%Lu", val->v_u64);
272 sprintf(buf, "%g", val->v_double);
286 die("Apostrophes are not supported in config of scripts");
298 int main(int argc, char **argv)
303 pos = argv[argc - 1];
304 argv[argc - 1] = NULL;
306 pool = mp_new(0x1000);
307 clist_init(§ions);
309 CLIST_FOR_EACH(struct section *, sec, sections)
310 cf_declare_section(sec->item.cf.name, generate_section(sec), !(sec->item.flags & FLAG_NO_UNKNOWN));
312 if (cf_getopt(argc - 1, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL) != -1)
316 CLIST_FOR_EACH(struct section *, section, sections)
318 uns len = strlen(section->item.cf.name);
319 memcpy(bb_grow(&path, len), section->item.cf.name, len);
320 CLIST_FOR_EACH(struct item *, item, section->list)
321 dump_item(item, NULL, len);