2 * UCW Library -- Reading of configuration files
4 * (c) 2001--2006 Robert Spalek <robert@ucw.cz>
5 * (c) 2003--2006 Martin Mares <mj@ucw.cz>
7 * This software may be freely distributed and used according to the terms
8 * of the GNU Lesser General Public License.
12 #include "lib/conf2.h"
13 #include "lib/mempool.h"
14 #include "lib/clists.h"
20 /* Memory allocation */
22 struct mempool *cf_pool; // current pool for loading new configuration
23 static struct old_pools {
24 struct old_pools *prev;
26 } *pools; // link-list of older cf_pool's
31 return mp_alloc(cf_pool, size);
35 cf_malloc_zero(uns size)
37 return mp_alloc_zero(cf_pool, size);
43 return mp_strdup(cf_pool, s);
47 cf_printf(char *fmt, ...)
51 byte *res = mp_vprintf(cf_pool, fmt, args);
58 uns cf_need_journal; // some programs do not need journal
59 static struct journal_item {
60 struct journal_item *prev;
67 cf_journal_block(void *ptr, uns len)
71 struct journal_item *ji = cf_malloc(sizeof(struct journal_item) + len);
75 memcpy(ji->copy, ptr, len);
81 // swaps the contents of the memory and the journal, and reverses the list
83 struct journal_item *curr, *prev, *next;
84 for (next=NULL, curr=journal; curr; next=curr, curr=prev)
88 for (uns i=0; i<curr->len; i++)
90 byte x = curr->copy[i];
91 curr->copy[i] = curr->ptr[i];
98 static struct journal_item *
99 journal_new_section(uns new_pool)
102 cf_pool = mp_new(1<<14);
103 struct journal_item *oldj = journal;
109 journal_commit_section(uns new_pool, struct journal_item *oldj)
113 struct old_pools *p = cf_malloc(sizeof(struct old_pools));
120 struct journal_item **j = &journal;
128 journal_rollback_section(uns new_pool, struct journal_item *oldj, byte *msg)
130 if (!cf_need_journal)
131 die("Cannot rollback the configuration, because the journal is disabled. Error: %s", msg);
137 cf_pool = pools ? pools->pool : NULL;
143 static struct section {
144 struct section *prev;
146 struct cf_section *sec;
150 cf_declare_section(byte *name, struct cf_section *sec)
152 struct section *s = sections;
154 if (!strcasecmp(s->name, name))
155 die("Cannot register cf_section %s twice", name);
156 s = xmalloc(sizeof(struct section));
164 cf_init_section(byte *name, struct cf_section *sec, void *ptr)
167 bzero(ptr, sec->size);
168 for (uns i=0; sec->cfg[i].cls; i++)
169 if (sec->cfg[i].cls == CC_SECTION)
170 cf_init_section(sec->cfg[i].name, sec->cfg[i].u.sec, ptr + (addr_int_t) sec->cfg[i].ptr);
171 else if (sec->cfg[i].cls == CC_LIST)
172 clist_init(sec->cfg[i].ptr);
173 byte *msg = sec->init(ptr);
175 die("Cannot initialize section %s: %s", name, msg);
181 for (struct section *s=sections; s; s=s->prev)
182 cf_init_section(s->name, s->sec, NULL);
185 /* Safe loading and reloading */
187 byte *cf_def_file = DEFAULT_CONFIG;
189 static byte *load_file(byte *file);
190 static byte *load_string(byte *string);
193 cf_reload(byte *file)
196 struct journal_item *oldj = journal_new_section(1);
197 byte *msg = load_file(file);
200 for (struct old_pools *p=pools; p; p=pools)
205 journal_commit_section(1, NULL);
209 journal_rollback_section(1, oldj, msg);
218 struct journal_item *oldj = journal_new_section(1);
219 byte *msg = load_file(file);
221 journal_commit_section(1, oldj);
223 journal_rollback_section(1, oldj, msg);
230 struct journal_item *oldj = journal_new_section(0);
231 byte *msg = load_string(string);
233 journal_commit_section(0, oldj);
235 journal_rollback_section(0, oldj, msg);
239 /* Parsers for standard types */
242 uns name; // one-letter name of the unit
243 uns num, den; // fraction
246 static const struct unit units[] = {
251 { 'g', 1000000000, 1 },
254 { 'G', 1073741824, 1 },
259 static const struct unit *
260 lookup_unit(byte *value, byte *end, byte **msg)
263 if (end == value || end[1] || *end >= '0' && *end <= '9')
264 *msg = "Invalid number";
266 for (const struct unit *u=units; u->name; u++)
269 *msg = "Invalid unit";
275 static char cf_rngerr[] = "Number out of range";
278 cf_parse_int(uns number, byte **pars, int *ptr)
280 for (uns i=0; i<number; i++)
284 msg = "Missing number";
286 const struct unit *u;
289 uns x = strtoul(pars[i], &end, 0);
292 else if (u = lookup_unit(pars[i], end, &msg)) {
293 u64 y = (u64)x * u->num;
295 msg = "Number is not an integer";
306 return number==1 ? msg : cf_printf("Item #%d: %s", i+1, msg);
312 cf_parse_u64(uns number, byte **pars, u64 *ptr)
314 for (uns i=0; i<number; i++)
318 msg = "Missing number";
320 const struct unit *u;
323 u64 x = strtoull(pars[i], &end, 0);
326 else if (u = lookup_unit(pars[i], end, &msg)) {
327 if (x > ~(u64)0 / u->num)
328 msg = "Number out of range";
332 msg = "Number is not an integer";
340 return number==1 ? msg : cf_printf("Item #%d: %s", i+1, msg);
346 cf_parse_double(uns number, byte **pars, double *ptr)
348 for (uns i=0; i<number; i++)
352 msg = "Missing number";
354 const struct unit *u;
357 double x = strtoul(pars[i], &end, 0);
360 else if (u = lookup_unit(pars[i], end, &msg))
361 ptr[i] = x * u->num / u->den;
366 return number==1 ? msg : cf_printf("Item #%d: %s", i+1, msg);
372 cf_parse_string(uns number, byte **pars, byte **ptr)
374 for (uns i=0; i<number; i++)
375 ptr[i] = cf_strdup(pars[i]);
379 /* Register size of and parser for each basic type */
384 { sizeof(int), cf_parse_int },
385 { sizeof(u64), cf_parse_u64 },
386 { sizeof(double), cf_parse_double },
387 { sizeof(byte*), cf_parse_string }
391 cf_parse_dyn(uns number, byte **pars, void **ptr, enum cf_type type)
393 cf_journal_block(ptr, sizeof(void*));
394 *ptr = cf_malloc((number+1) * parsers[type].size) + parsers[type].size;
395 * (uns*) (*ptr - parsers[type].size) = number;
396 return ((cf_parser*) parsers[type].parser) (number, pars, *ptr);