* UCW Library -- Configuration files: interpreter
*
* (c) 2001--2006 Robert Spalek <robert@ucw.cz>
- * (c) 2003--2006 Martin Mares <mj@ucw.cz>
+ * (c) 2003--2014 Martin Mares <mj@ucw.cz>
+ * (c) 2014 Pavel Charvat <pchar@ucw.cz>
*
* This software may be freely distributed and used according to the terms
* of the GNU Lesser General Public License.
*/
-#include "ucw/lib.h"
-#include "ucw/conf.h"
-#include "ucw/getopt.h"
-#include "ucw/conf-internal.h"
-#include "ucw/clists.h"
+#include <ucw/lib.h>
+#include <ucw/conf.h>
+#include <ucw/getopt.h>
+#include <ucw/conf-internal.h>
+#include <ucw/clists.h>
+#include <ucw/gary.h>
+#include <ucw/mempool.h>
+#include <ucw/xtypes.h>
#include <string.h>
#include <stdio.h>
typedef char *cf_basic_parser(char *str, void *ptr);
static struct {
- uns size;
+ uint size;
void *parser;
} parsers[] = {
{ sizeof(int), cf_parse_int },
{ 0, NULL }, // user-defined types are parsed extra
};
-inline uns
-cf_type_size(enum cf_type type, struct cf_user_type *utype)
+inline uint
+cf_type_size(enum cf_type type, const union cf_union *u)
{
- if (type < CT_USER)
- return parsers[type].size;
- else
- return utype->size;
+ switch (type)
+ {
+ case CT_USER:
+ return u->utype->size;
+ case CT_XTYPE:
+ return u->xtype->size;
+ default:
+ ASSERT(type < ARRAY_SIZE(parsers) - 1);
+ return parsers[type].size;
+ }
}
static char *
cf_parse_lookup(char *str, int *ptr, const char * const *t)
{
const char * const *n = t;
- uns total_len = 0;
+ uint total_len = 0;
while (*n && strcasecmp(*n, str)) {
total_len += strlen(*n) + 2;
n++;
}
static char *
-cf_parse_ary(uns number, char **pars, void *ptr, enum cf_type type, union cf_union *u)
+cf_parse_ary(uint number, char **pars, void *ptr, enum cf_type type, union cf_union *u)
{
- for (uns i=0; i<number; i++)
+ for (uint i=0; i<number; i++)
{
char *msg;
- uns size = cf_type_size(type, u->utype);
+ uint size = cf_type_size(type, u);
if (type < CT_LOOKUP)
msg = ((cf_basic_parser*) parsers[type].parser) (pars[i], ptr + i * size);
else if (type == CT_LOOKUP)
msg = cf_parse_lookup(pars[i], ptr + i * size, u->lookup);
else if (type == CT_USER)
msg = u->utype->parser(pars[i], ptr + i * size);
+ else if (type == CT_XTYPE)
+ msg = (char *)u->xtype->parse(pars[i], ptr + i * size, cf_get_pool());
else
ASSERT(0);
if (msg)
#define T(x) #x,
char *cf_op_names[] = { CF_OPERATIONS };
#undef T
-char *cf_type_names[] = { "int", "u64", "double", "ip", "string", "lookup", "user" };
-
-#define DARY_HDR_SIZE ALIGN_TO(sizeof(uns), CPU_STRUCT_ALIGN)
+char *cf_type_names[] = { "int", "u64", "double", "ip", "string", "lookup", "user", "xtype" };
static char *
interpret_set_dynamic(struct cf_item *item, int number, char **pars, void **ptr)
{
enum cf_type type = item->type;
+ uint size = cf_type_size(type, &item->u);
cf_journal_block(ptr, sizeof(void*));
// boundary checks done by the caller
- uns size = cf_type_size(item->type, item->u.utype);
- *ptr = cf_malloc(DARY_HDR_SIZE + number * size) + DARY_HDR_SIZE;
- DARY_LEN(*ptr) = number;
+ *ptr = gary_init(size, number, mp_get_allocator(cf_get_pool()));
return cf_parse_ary(number, pars, *ptr, type, &item->u);
}
{
enum cf_type type = item->type;
void *old_p = *ptr;
- uns size = cf_type_size(item->type, item->u.utype);
- ASSERT(size >= sizeof(uns));
- int old_nr = old_p ? DARY_LEN(old_p) : 0;
+ uint size = cf_type_size(item->type, &item->u);
+ ASSERT(size >= sizeof(uint));
+ int old_nr = old_p ? GARY_SIZE(old_p) : 0;
int taken = MIN(number, ABS(item->number)-old_nr);
*processed = taken;
// stretch the dynamic array
- void *new_p = cf_malloc(DARY_HDR_SIZE + (old_nr + taken) * size) + DARY_HDR_SIZE;
- DARY_LEN(new_p) = old_nr + taken;
+ void *new_p = gary_init(size, old_nr + taken, mp_get_allocator(cf_get_pool()));
cf_journal_block(ptr, sizeof(void*));
*ptr = new_p;
if (op == OP_APPEND) {
return cf_printf("Dynamic arrays do not support operation %s", cf_op_names[op]);
}
-static char *interpret_set_item(struct cf_item *item, int number, char **pars, int *processed, void *ptr, uns allow_dynamic);
+static char *interpret_set_item(struct cf_item *item, int number, char **pars, int *processed, void *ptr, uint allow_dynamic);
static char *
-interpret_section(struct cf_section *sec, int number, char **pars, int *processed, void *ptr, uns allow_dynamic)
+interpret_section(struct cf_section *sec, int number, char **pars, int *processed, void *ptr, uint allow_dynamic)
{
cf_add_dirty(sec, ptr);
*processed = 0;
return "Nothing to add to the list";
struct cf_section *sec = item->u.sec;
*processed = 0;
- uns index = 0;
+ uint index = 0;
while (number > 0)
{
void *node = cf_malloc(sec->size);
static char *
interpret_add_bitmap(struct cf_item *item, int number, char **pars, int *processed, u32 *ptr, enum cf_operation op)
{
+ if (op == OP_PREPEND || op == OP_APPEND)
+ op = OP_SET;
if (op != OP_SET && op != OP_REMOVE)
return cf_printf("Cannot apply operation %s on a bitmap", cf_op_names[op]);
else if (item->type != CT_INT && item->type != CT_LOOKUP)
return cf_printf("Type %s cannot be used with bitmaps", cf_type_names[item->type]);
cf_journal_block(ptr, sizeof(u32));
for (int i=0; i<number; i++) {
- uns idx;
+ uint idx;
if (item->type == CT_INT)
TRY( cf_parse_int(pars[i], &idx) );
else
}
static char *
-interpret_set_item(struct cf_item *item, int number, char **pars, int *processed, void *ptr, uns allow_dynamic)
+interpret_set_item(struct cf_item *item, int number, char **pars, int *processed, void *ptr, uint allow_dynamic)
{
int taken;
switch (item->cls)
return "Missing value";
taken = MIN(number, item->number);
*processed = taken;
- uns size = cf_type_size(item->type, item->u.utype);
+ uint size = cf_type_size(item->type, &item->u);
cf_journal_block(ptr, taken * size);
return cf_parse_ary(taken, pars, ptr, item->type, &item->u);
case CC_DYNAMIC:
if (item->type == CT_INT)
* (u32*) ptr = ~0u;
else {
- uns nr = -1;
+ uint nr = -1;
while (item->u.lookup[++nr]);
* (u32*) ptr = ~0u >> (32-nr);
}
clist_init(ptr);
} else if (item->cls == CC_DYNAMIC) {
cf_journal_block(ptr, sizeof(void *));
- static uns zero = 0;
- * (void**) ptr = (&zero) + 1;
+ * (void**) ptr = GARY_FOREVER_EMPTY;
} else if (item->cls == CC_STATIC && item->type == CT_STRING) {
cf_journal_block(ptr, item->number * sizeof(char*));
bzero(ptr, item->number * sizeof(char*));
if (item->type == CT_STRING)
return strcmp(* (char**) i1, * (char**) i2);
else // all numeric types
- return memcmp(i1, i2, cf_type_size(item->type, item->u.utype));
+ return memcmp(i1, i2, cf_type_size(item->type, &item->u));
}
static void *
{
CLIST_FOR_EACH(cnode *, n, *list)
{
- uns found = 1;
- for (uns i=0; i<32; i++)
+ uint found = 1;
+ for (uint i=0; i<32; i++)
if (mask & (1<<i))
if (cmp_items(n, query, sec->cfg+i))
{
static char *
record_selector(struct cf_item *item, struct cf_section *sec, u32 *mask)
{
- uns nr = sec->flags & SEC_FLAG_NUMBER;
+ uint nr = sec->flags & SEC_FLAG_NUMBER;
if (item >= sec->cfg && item < sec->cfg + nr) // setting an attribute relative to this section
{
- uns i = item - sec->cfg;
+ uint i = item - sec->cfg;
if (i >= 32)
return "Cannot select list nodes by this attribute";
if (sec->cfg[i].cls != CC_STATIC)
return NULL;
}
-#define MAX_STACK_SIZE 10
-static struct item_stack {
- struct cf_section *sec; // nested section
- void *base_ptr; // because original pointers are often relative
- enum cf_operation op; // it is performed when a closing brace is encountered
- void *list; // list the operations should be done on
- u32 mask; // bit array of selectors searching in a list
- struct cf_item *item; // cf_item of the list
-} stack[MAX_STACK_SIZE];
-static uns level;
-
static char *
-opening_brace(struct cf_item *item, void *ptr, enum cf_operation op)
+opening_brace(struct cf_context *cc, struct cf_item *item, void *ptr, enum cf_operation op)
{
- if (level >= MAX_STACK_SIZE-1)
+ if (cc->stack_level >= MAX_STACK_SIZE-1)
return "Too many nested sections";
enum cf_operation pure_op = op & OP_MASK;
- stack[++level] = (struct item_stack) {
+ cc->stack[++cc->stack_level] = (struct item_stack) {
.sec = NULL,
.base_ptr = NULL,
.op = pure_op,
};
if (!item) // unknown is ignored; we just need to trace recursion
return NULL;
- stack[level].sec = item->u.sec;
+ cc->stack[cc->stack_level].sec = item->u.sec;
if (item->cls == CC_SECTION)
{
if (pure_op != OP_SET)
return "Only SET operation can be used with a section";
- stack[level].base_ptr = ptr;
- stack[level].op = OP_EDIT | OP_2ND; // this list operation does nothing
+ cc->stack[cc->stack_level].base_ptr = ptr;
+ cc->stack[cc->stack_level].op = OP_EDIT | OP_2ND; // this list operation does nothing
}
else if (item->cls == CC_LIST)
{
- stack[level].base_ptr = cf_malloc(item->u.sec->size);
- cf_init_section(item->name, item->u.sec, stack[level].base_ptr, 1);
- stack[level].list = ptr;
- stack[level].item = item;
+ cc->stack[cc->stack_level].base_ptr = cf_malloc(item->u.sec->size);
+ cf_init_section(item->name, item->u.sec, cc->stack[cc->stack_level].base_ptr, 1);
+ cc->stack[cc->stack_level].list = ptr;
+ cc->stack[cc->stack_level].item = item;
if (pure_op == OP_ALL)
return "Operation ALL cannot be applied on lists";
else if (pure_op < OP_REMOVE) {
- add_to_list(ptr, stack[level].base_ptr, pure_op);
- stack[level].op |= OP_2ND;
+ add_to_list(ptr, cc->stack[cc->stack_level].base_ptr, pure_op);
+ cc->stack[cc->stack_level].op |= OP_2ND;
} else
- stack[level].op |= OP_1ST;
+ cc->stack[cc->stack_level].op |= OP_1ST;
}
else
return "Opening brace can only be used on sections and lists";
}
static char *
-closing_brace(struct item_stack *st, enum cf_operation op, int number, char **pars)
+closing_brace(struct cf_context *cc, struct item_stack *st, enum cf_operation op, int number, char **pars)
{
if (st->op == OP_CLOSE) // top-level
return "Unmatched } parenthesis";
if (!st->sec) { // dummy run on unknown section
if (!(op & OP_OPEN))
- level--;
+ cc->stack_level--;
return NULL;
}
enum cf_operation pure_op = st->op & OP_MASK;
}
add_to_list(st->list, st->base_ptr, pure_op);
}
- level--;
+ cc->stack_level--;
if (number)
return "No parameters expected after the }";
else if (op & OP_OPEN)
static struct cf_item *
find_item(struct cf_section *curr_sec, const char *name, char **msg, void **ptr)
{
+ struct cf_context *cc = cf_get_context();
*msg = NULL;
if (name[0] == '^') // absolute name instead of relative
- name++, curr_sec = &cf_sections, *ptr = NULL;
+ name++, curr_sec = &cc->sections, *ptr = NULL;
if (!curr_sec) // don't even search in an unknown section
return NULL;
while (1)
{
- if (curr_sec != &cf_sections)
+ if (curr_sec != &cc->sections)
cf_add_dirty(curr_sec, *ptr);
char *c = strchr(name, '.');
if (c)
}
}
+static char *
+interpret_add(char *name, struct cf_item *item, int number, char **pars, int *takenp, void *ptr, enum cf_operation op)
+{
+ switch (item->cls) {
+ case CC_DYNAMIC:
+ return interpret_add_dynamic(item, number, pars, takenp, ptr, op);
+ case CC_LIST:
+ return interpret_add_list(item, number, pars, takenp, ptr, op);
+ case CC_BITMAP:
+ return interpret_add_bitmap(item, number, pars, takenp, ptr, op);
+ default:
+ return cf_printf("Operation %s not supported on attribute %s", cf_op_names[op], name);
+ }
+}
+
char *
-cf_interpret_line(char *name, enum cf_operation op, int number, char **pars)
+cf_interpret_line(struct cf_context *cc, char *name, enum cf_operation op, int number, char **pars)
{
char *msg;
if ((op & OP_MASK) == OP_CLOSE)
- return closing_brace(stack+level, op, number, pars);
- void *ptr = stack[level].base_ptr;
- struct cf_item *item = find_item(stack[level].sec, name, &msg, &ptr);
+ return closing_brace(cc, cc->stack+cc->stack_level, op, number, pars);
+ void *ptr = cc->stack[cc->stack_level].base_ptr;
+ struct cf_item *item = find_item(cc->stack[cc->stack_level].sec, name, &msg, &ptr);
if (msg)
return msg;
- if (stack[level].op & OP_1ST)
- TRY( record_selector(item, stack[level].sec, &stack[level].mask) );
+ if (cc->stack[cc->stack_level].op & OP_1ST)
+ TRY( record_selector(item, cc->stack[cc->stack_level].sec, &cc->stack[cc->stack_level].mask) );
if (op & OP_OPEN) { // the operation will be performed after the closing brace
if (number)
return "Cannot open a block after a parameter has been passed on a line";
- return opening_brace(item, ptr, op);
+ return opening_brace(cc, item, ptr, op);
}
if (!item) // ignored item in an unknown section
return NULL;
op &= OP_MASK;
int taken = 0; // process as many parameters as possible
- if (op == OP_CLEAR || op == OP_ALL)
- msg = interpret_set_all(item, ptr, op);
- else if (op == OP_SET)
- msg = interpret_set_item(item, number, pars, &taken, ptr, 1);
- else if (item->cls == CC_DYNAMIC)
- msg = interpret_add_dynamic(item, number, pars, &taken, ptr, op);
- else if (item->cls == CC_LIST)
- msg = interpret_add_list(item, number, pars, &taken, ptr, op);
- else if (item->cls == CC_BITMAP)
- msg = interpret_add_bitmap(item, number, pars, &taken, ptr, op);
- else
- return cf_printf("Operation %s not supported on attribute %s", cf_op_names[op], name);
+ switch (op) {
+ case OP_CLEAR:
+ case OP_ALL:
+ msg = interpret_set_all(item, ptr, op);
+ break;
+ case OP_SET:
+ msg = interpret_set_item(item, number, pars, &taken, ptr, 1);
+ break;
+ case OP_RESET:
+ msg = interpret_set_all(item, ptr, OP_CLEAR);
+ if (!msg)
+ msg = interpret_add(name, item, number, pars, &taken, ptr, OP_APPEND);
+ break;
+ default:
+ msg = interpret_add(name, item, number, pars, &taken, ptr, op);
+ }
if (msg)
return msg;
if (taken < number)
char *
cf_find_item(const char *name, struct cf_item *item)
{
+ struct cf_context *cc = cf_get_context();
char *msg;
void *ptr = NULL;
- struct cf_item *ci = find_item(&cf_sections, name, &msg, &ptr);
+ struct cf_item *ci = find_item(&cc->sections, name, &msg, &ptr);
if (msg)
return msg;
if (ci) {
break;
case OP_APPEND:
case OP_PREPEND:
- if (item->cls == CC_DYNAMIC)
- msg = interpret_add_dynamic(item, number, pars, &taken, item->ptr, op);
- else if (item->cls == CC_LIST)
- msg = interpret_add_list(item, number, pars, &taken, item->ptr, op);
- else
- return "The attribute does not support append/prepend";
+ switch (item->cls) {
+ case CC_DYNAMIC:
+ msg = interpret_add_dynamic(item, number, pars, &taken, item->ptr, op);
+ break;
+ case CC_LIST:
+ msg = interpret_add_list(item, number, pars, &taken, item->ptr, op);
+ break;
+ case CC_BITMAP:
+ msg = interpret_add_bitmap(item, number, pars, &taken, item->ptr, op);
+ break;
+ default:
+ return "The attribute does not support append/prepend";
+ }
break;
case OP_REMOVE:
if (item->cls == CC_BITMAP)
}
void
-cf_init_stack(void)
+cf_init_stack(struct cf_context *cc)
{
- static uns initialized = 0;
- if (!initialized++) {
- cf_sections.flags |= SEC_FLAG_UNKNOWN;
- cf_sections.size = 0; // size of allocated array used to be stored here
- cf_init_section(NULL, &cf_sections, NULL, 0);
+ if (!cc->sections_initialized++) {
+ cc->sections.flags |= SEC_FLAG_UNKNOWN;
+ cc->sections.size = 0; // size of allocated array used to be stored here
+ cf_init_section(NULL, &cc->sections, NULL, 0);
}
- level = 0;
- stack[0] = (struct item_stack) {
- .sec = &cf_sections,
+ cc->stack_level = 0;
+ cc->stack[0] = (struct item_stack) {
+ .sec = &cc->sections,
.base_ptr = NULL,
.op = OP_CLOSE,
.list = NULL,
}
int
-cf_check_stack(void)
+cf_done_stack(struct cf_context *cc)
{
- if (level > 0) {
- msg(L_ERROR, "Unterminated block");
- return 1;
- }
- return 0;
+ return (cc->stack_level > 0);
}
-