#include <string.h>
#include <stdio.h>
-#define TRY(f) do { byte *_msg = f; if (_msg) return _msg; } while (0)
+#define TRY(f) do { char *_msg = f; if (_msg) return _msg; } while (0)
/* Register size of and parser for each basic type */
-static byte *
-cf_parse_string(byte *str, byte **ptr)
+static char *
+cf_parse_string(char *str, char **ptr)
{
*ptr = cf_strdup(str);
return NULL;
}
-typedef byte *cf_basic_parser(byte *str, void *ptr);
+typedef char *cf_basic_parser(char *str, void *ptr);
static struct {
uns size;
void *parser;
{ sizeof(u64), cf_parse_u64 },
{ sizeof(double), cf_parse_double },
{ sizeof(u32), cf_parse_ip },
- { sizeof(byte*), cf_parse_string },
+ { sizeof(char*), cf_parse_string },
{ sizeof(int), NULL }, // lookups are parsed extra
{ 0, NULL }, // user-defined types are parsed extra
};
return utype->size;
}
-static byte *
-cf_parse_lookup(byte *str, int *ptr, byte **t)
+static char *
+cf_parse_lookup(char *str, int *ptr, char **t)
{
- byte **n = t;
+ char **n = t;
uns total_len = 0;
while (*n && strcasecmp(*n, str)) {
total_len += strlen(*n) + 2;
*ptr = n - t;
return NULL;
}
- byte *err = cf_malloc(total_len + strlen(str) + 60), *c = err;
+ char *err = cf_malloc(total_len + strlen(str) + 60), *c = err;
c += sprintf(err, "Invalid value %s, possible values are: ", str);
for (n=t; *n; n++)
c+= sprintf(c, "%s, ", *n);
return err;
}
-static byte *
-cf_parse_ary(uns number, byte **pars, void *ptr, enum cf_type type, union cf_union *u)
+static char *
+cf_parse_ary(uns number, char **pars, void *ptr, enum cf_type type, union cf_union *u)
{
for (uns i=0; i<number; i++)
{
- byte *msg;
+ char *msg;
uns size = cf_type_size(type, u->utype);
if (type < CT_LOOKUP)
msg = ((cf_basic_parser*) parsers[type].parser) (pars[i], ptr + i * size);
else
ASSERT(0);
if (msg)
- return cf_printf("Cannot parse item %d: %s", i+1, msg);
+ return number > 1 ? cf_printf("Item %d: %s", i+1, msg) : msg;
}
return NULL;
}
/* Interpreter */
#define T(x) #x,
-byte *cf_op_names[] = { CF_OPERATIONS };
+char *cf_op_names[] = { CF_OPERATIONS };
#undef T
+char *cf_type_names[] = { "int", "u64", "double", "ip", "string", "lookup", "user" };
-static byte *
-interpret_set_dynamic(struct cf_item *item, int number, byte **pars, void **ptr)
+#define DARY_HDR_SIZE ALIGN_TO(sizeof(uns), CPU_STRUCT_ALIGN)
+
+static char *
+interpret_set_dynamic(struct cf_item *item, int number, char **pars, void **ptr)
{
enum cf_type type = item->type;
cf_journal_block(ptr, sizeof(void*));
// boundary checks done by the caller
uns size = cf_type_size(item->type, item->u.utype);
- ASSERT(size >= sizeof(uns));
- *ptr = cf_malloc((number+1) * size) + size;
- * (uns*) (*ptr - size) = number;
+ *ptr = cf_malloc(DARY_HDR_SIZE + number * size) + DARY_HDR_SIZE;
+ DARY_LEN(*ptr) = number;
return cf_parse_ary(number, pars, *ptr, type, &item->u);
}
-static byte *
-interpret_add_dynamic(struct cf_item *item, int number, byte **pars, int *processed, void **ptr, enum cf_operation op)
+static char *
+interpret_add_dynamic(struct cf_item *item, int number, char **pars, int *processed, void **ptr, enum cf_operation op)
{
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 ? * (int*) (old_p - size) : 0;
+ int old_nr = old_p ? DARY_LEN(old_p) : 0;
int taken = MIN(number, ABS(item->number)-old_nr);
*processed = taken;
// stretch the dynamic array
- void *new_p = cf_malloc((old_nr + taken + 1) * size) + size;
- * (uns*) (new_p - size) = old_nr + taken;
+ void *new_p = cf_malloc(DARY_HDR_SIZE + (old_nr + taken) * size) + DARY_HDR_SIZE;
+ DARY_LEN(new_p) = old_nr + taken;
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 byte *interpret_set_item(struct cf_item *item, int number, byte **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, uns allow_dynamic);
-static byte *
-interpret_section(struct cf_section *sec, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic)
+static char *
+interpret_section(struct cf_section *sec, int number, char **pars, int *processed, void *ptr, uns allow_dynamic)
{
cf_add_dirty(sec, ptr);
*processed = 0;
for (struct cf_item *ci=sec->cfg; ci->cls; ci++)
{
int taken;
- byte *msg = interpret_set_item(ci, number, pars, &taken, ptr + (addr_int_t) ci->ptr, allow_dynamic && !ci[1].cls);
+ char *msg = interpret_set_item(ci, number, pars, &taken, ptr + (uintptr_t) ci->ptr, allow_dynamic && !ci[1].cls);
if (msg)
return cf_printf("Item %s: %s", ci->name, msg);
*processed += taken;
}
}
-static byte *
-interpret_add_list(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, enum cf_operation op)
+static char *
+interpret_add_list(struct cf_item *item, int number, char **pars, int *processed, void *ptr, enum cf_operation op)
{
if (op >= OP_REMOVE)
return cf_printf("You have to open a block for operation %s", cf_op_names[op]);
return "Nothing to add to the list";
struct cf_section *sec = item->u.sec;
*processed = 0;
+ uns index = 0;
while (number > 0)
{
void *node = cf_malloc(sec->size);
int taken;
/* If the node contains any dynamic attribute at the end, we suppress
* auto-repetition here and pass the flag inside instead. */
- TRY( interpret_section(sec, number, pars, &taken, node, sec->flags & SEC_FLAG_DYNAMIC) );
+ index++;
+ char *msg = interpret_section(sec, number, pars, &taken, node, sec->flags & SEC_FLAG_DYNAMIC);
+ if (msg)
+ return sec->flags & SEC_FLAG_DYNAMIC ? msg : cf_printf("Node %d of list %s: %s", index, item->name, msg);
*processed += taken;
number -= taken;
pars += taken;
return NULL;
}
-static byte *
-interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic)
+static char *
+interpret_add_bitmap(struct cf_item *item, int number, char **pars, int *processed, u32 *ptr, enum cf_operation op)
+{
+ 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;
+ if (item->type == CT_INT)
+ TRY( cf_parse_int(pars[i], &idx) );
+ else
+ TRY( cf_parse_lookup(pars[i], &idx, item->u.lookup) );
+ if (idx >= 32)
+ return "Bitmaps only have 32 bits";
+ if (op == OP_SET)
+ *ptr |= 1<<idx;
+ else
+ *ptr &= ~(1<<idx);
+ }
+ *processed = number;
+ return NULL;
+}
+
+static char *
+interpret_set_item(struct cf_item *item, int number, char **pars, int *processed, void *ptr, uns allow_dynamic)
{
int taken;
switch (item->cls)
if (!allow_dynamic)
return "Lists cannot be used here";
return interpret_add_list(item, number, pars, processed, ptr, OP_SET);
+ case CC_BITMAP:
+ if (!allow_dynamic)
+ return "Bitmaps cannot be used here";
+ return interpret_add_bitmap(item, number, pars, processed, ptr, OP_SET);
default:
ASSERT(0);
}
}
-static byte *
-interpret_clear(struct cf_item *item, void *ptr)
+static char *
+interpret_set_all(struct cf_item *item, void *ptr, enum cf_operation op)
{
+ if (item->cls == CC_BITMAP) {
+ cf_journal_block(ptr, sizeof(u32));
+ if (op == OP_CLEAR)
+ * (u32*) ptr = 0;
+ else
+ if (item->type == CT_INT)
+ * (u32*) ptr = ~0u;
+ else {
+ uns nr = -1;
+ while (item->u.lookup[++nr]);
+ * (u32*) ptr = ~0u >> (32-nr);
+ }
+ return NULL;
+ } else if (op != OP_CLEAR)
+ return "The item is not a bitmap";
+
if (item->cls == CC_LIST) {
cf_journal_block(ptr, sizeof(clist));
clist_init(ptr);
} else if (item->cls == CC_DYNAMIC) {
cf_journal_block(ptr, sizeof(void *));
- * (void**) ptr = NULL;
+ static uns zero = 0;
+ * (void**) ptr = (&zero) + 1;
} else if (item->cls == CC_STATIC && item->type == CT_STRING) {
- cf_journal_block(ptr, item->number * sizeof(byte*));
- bzero(ptr, item->number * sizeof(byte*));
+ cf_journal_block(ptr, item->number * sizeof(char*));
+ bzero(ptr, item->number * sizeof(char*));
} else
- return "The item is not a list, dynamic array, or string";
+ return "The item is not a list, dynamic array, bitmap, or string";
return NULL;
}
cmp_items(void *i1, void *i2, struct cf_item *item)
{
ASSERT(item->cls == CC_STATIC);
- i1 += (addr_int_t) item->ptr;
- i2 += (addr_int_t) item->ptr;
+ i1 += (uintptr_t) item->ptr;
+ i2 += (uintptr_t) item->ptr;
if (item->type == CT_STRING)
- return strcmp(* (byte**) i1, * (byte**) i2);
+ return strcmp(* (char**) i1, * (char**) i2);
else // all numeric types
return memcmp(i1, i2, cf_type_size(item->type, item->u.utype));
}
return NULL;
}
-static byte *
+static char *
record_selector(struct cf_item *item, struct cf_section *sec, u32 *mask)
{
uns nr = sec->flags & SEC_FLAG_NUMBER;
} stack[MAX_STACK_SIZE];
static uns level;
-static byte *
+static char *
opening_brace(struct cf_item *item, void *ptr, enum cf_operation op)
{
if (level >= MAX_STACK_SIZE-1)
return "Too many nested sections";
+ enum cf_operation pure_op = op & OP_MASK;
stack[++level] = (struct item_stack) {
.sec = NULL,
.base_ptr = NULL,
- .op = op & OP_MASK,
+ .op = pure_op,
.list = NULL,
.mask = 0,
.item = NULL,
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
}
cf_init_section(item->name, item->u.sec, stack[level].base_ptr, 1);
stack[level].list = ptr;
stack[level].item = item;
- if ((op & OP_MASK) < OP_REMOVE) {
- add_to_list(ptr, stack[level].base_ptr, op & OP_MASK);
+ 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;
} else
stack[level].op |= OP_1ST;
return NULL;
}
-static byte *
-closing_brace(struct item_stack *st, enum cf_operation op, int number, byte **pars)
+static char *
+closing_brace(struct item_stack *st, enum cf_operation op, int number, char **pars)
{
if (st->op == OP_CLOSE) // top-level
return "Unmatched } parenthesis";
}
static struct cf_item *
-find_item(struct cf_section *curr_sec, byte *name, byte **msg, void **ptr)
+find_item(struct cf_section *curr_sec, const char *name, char **msg, void **ptr)
{
*msg = NULL;
if (name[0] == '^') // absolute name instead of relative
{
if (curr_sec != &cf_sections)
cf_add_dirty(curr_sec, *ptr);
- byte *c = strchr(name, '.');
+ char *c = strchr(name, '.');
if (c)
*c++ = 0;
struct cf_item *ci = cf_find_subitem(curr_sec, name);
*msg = cf_printf("Unknown item %s", name);
return NULL;
}
- *ptr += (addr_int_t) ci->ptr;
+ *ptr += (uintptr_t) ci->ptr;
if (!c)
return ci;
if (ci->cls != CC_SECTION)
}
}
-byte *
-cf_interpret_line(byte *name, enum cf_operation op, int number, byte **pars)
+char *
+cf_interpret_line(char *name, enum cf_operation op, int number, char **pars)
{
- byte *msg;
+ char *msg;
if ((op & OP_MASK) == OP_CLOSE)
return closing_brace(stack+level, op, number, pars);
void *ptr = stack[level].base_ptr;
return NULL;
op &= OP_MASK;
- int taken; // process as many parameters as possible
- if (op == OP_CLEAR)
- taken = 0, msg = interpret_clear(item, ptr);
+ 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);
if (msg)
return NULL;
}
-byte *
-cf_find_item(byte *name, struct cf_item *item)
+char *
+cf_find_item(const char *name, struct cf_item *item)
{
- byte *msg;
- void *ptr;
+ char *msg;
+ void *ptr = NULL;
struct cf_item *ci = find_item(&cf_sections, name, &msg, &ptr);
if (msg)
return msg;
return NULL;
}
-byte *
-cf_write_item(struct cf_item *item, enum cf_operation op, int number, byte **pars)
+char *
+cf_write_item(struct cf_item *item, enum cf_operation op, int number, char **pars)
{
- byte *msg;
- int taken;
+ char *msg;
+ int taken = 0;
switch (op) {
case OP_SET:
msg = interpret_set_item(item, number, pars, &taken, item->ptr, 1);
break;
case OP_CLEAR:
- taken = 0;
- msg = interpret_clear(item, item->ptr);
+ case OP_ALL:
+ msg = interpret_set_all(item, item->ptr, op);
break;
case OP_APPEND:
case OP_PREPEND:
else if (item->cls == CC_LIST)
msg = interpret_add_list(item, number, pars, &taken, item->ptr, op);
else
- return "The attribute class does not support append/prepend";
+ return "The attribute does not support append/prepend";
+ break;
+ case OP_REMOVE:
+ if (item->cls == CC_BITMAP)
+ msg = interpret_add_bitmap(item, number, pars, &taken, item->ptr, op);
+ else
+ return "Only applicable on bitmaps";
break;
default:
return "Unsupported operation";
cf_check_stack(void)
{
if (level > 0) {
- log(L_ERROR, "Unterminated block");
+ msg(L_ERROR, "Unterminated block");
return 1;
}
return 0;