static void dump_section(struct fastbuf *fb, struct cf_section *sec, int level, void *ptr);
-static byte *class_names[] = { "end", "static", "dynamic", "parser", "section", "list" };
-static byte *type_names[] = { "int", "u64", "double", "ip", "string", "lookup", "user" };
+static byte *class_names[] = { "end", "static", "dynamic", "parser", "section", "list", "bitmap" };
static void
dump_item(struct fastbuf *fb, struct cf_item *item, int level, void *ptr)
bputs(fb, "any ");
else
bprintf(fb, "%d ", item->number);
- if (item->cls == CC_STATIC || item->cls == CC_DYNAMIC) {
- bprintf(fb, "T%s ", type_names[type]);
+ if (item->cls == CC_STATIC || item->cls == CC_DYNAMIC || item->cls == CC_BITMAP) {
+ bprintf(fb, "T%s ", cf_type_names[type]);
if (item->type == CT_USER)
bprintf(fb, "U%s S%d ", item->u.utype->name, size);
}
dump_basic(fb, ptr + i * size, type, &item->u);
} else
bprintf(fb, "NULL ");
+ } else if (item->cls == CC_BITMAP) {
+ u32 mask = * (u32*) ptr;
+ for (i=0; i<32; i++) {
+ if (item->type == CT_LOOKUP && !item->u.lookup[i])
+ break;
+ if (mask & (1<<i)) {
+ if (item->type == CT_INT)
+ bprintf(fb, "%d ", i);
+ else if (item->type == CT_LOOKUP)
+ bprintf(fb, "%s ", item->u.lookup[i]);
+ }
+ }
}
bputc(fb, '\n');
if (item->cls == CC_SECTION)
*c++ = 0;
switch (Clocase(*c)) {
case 's': op = OP_SET; break;
+ case 'u': op = OP_UNSET; break;
case 'c': op = Clocase(c[1]) == 'l' ? OP_CLEAR: OP_COPY; break;
- case 'a': op = Clocase(c[1]) == 'p' ? OP_APPEND : OP_AFTER; break;
+ case 'a': switch (Clocase(c[1])) {
+ case 'p': op = OP_APPEND; break;
+ case 'f': op = OP_AFTER; break;
+ default: op = OP_ALL;
+ }; break;
case 'p': op = OP_PREPEND; break;
case 'r': op = OP_REMOVE; break;
case 'e': op = OP_EDIT; break;
#define OP_2ND 0x400 // in the 2nd phase real data are entered
enum cf_operation;
extern byte *cf_op_names[];
+extern byte *cf_type_names[];
uns cf_type_size(enum cf_type type, struct cf_user_type *utype);
byte *cf_interpret_line(byte *name, enum cf_operation op, int number, byte **pars);
#define T(x) #x,
byte *cf_op_names[] = { CF_OPERATIONS };
#undef T
+byte *cf_type_names[] = { "int", "u64", "double", "ip", "string", "lookup", "user" };
#define DARY_HDR_SIZE ALIGN(sizeof(uns), CPU_STRUCT_ALIGN)
return NULL;
}
+static byte *
+interpret_bitmap(struct cf_item *item, int number, byte **pars, int *processed, u32 *ptr, enum cf_operation op)
+{
+ if (item->cls != CC_BITMAP)
+ return cf_printf("Expecting a bitmap");
+ 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 byte *
interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic)
{
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_bitmap(item, number, pars, processed, ptr, OP_SET);
default:
ASSERT(0);
}
} else if (item->cls == CC_STATIC && item->type == CT_STRING) {
cf_journal_block(ptr, item->number * sizeof(byte*));
bzero(ptr, item->number * sizeof(byte*));
+ } else if (item->cls == CC_BITMAP) {
+ cf_journal_block(ptr, sizeof(u32));
+ * (u32*) ptr = 0;
} 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;
}
+static byte *
+interpret_set_all(struct cf_item *item, void *ptr)
+{
+ if (item->cls == CC_BITMAP) {
+ cf_journal_block(ptr, sizeof(u32));
+ 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
+ return "The item is not a bitmap";
+}
+
static int
cmp_items(void *i1, void *i2, struct cf_item *item)
{
{
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_UNSET || pure_op == OP_ALL)
+ return "Bitmap operations are not supported for 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;
op &= OP_MASK;
- int taken; // process as many parameters as possible
+ int taken = 0; // process as many parameters as possible
if (op == OP_CLEAR)
- taken = 0, msg = interpret_clear(item, ptr);
+ msg = interpret_clear(item, ptr);
+ else if (op == OP_ALL)
+ msg = interpret_set_all(item, ptr);
else if (op == OP_SET)
msg = interpret_set_item(item, number, pars, &taken, ptr, 1);
+ else if (op == OP_UNSET)
+ msg = interpret_bitmap(item, number, pars, &taken, ptr, OP_UNSET);
else if (item->cls == CC_DYNAMIC)
msg = interpret_add_dynamic(item, number, pars, &taken, ptr, op);
else if (item->cls == CC_LIST)
cf_write_item(struct cf_item *item, enum cf_operation op, int number, byte **pars)
{
byte *msg;
- int taken;
+ 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);
break;
+ case OP_UNSET:
+ msg = interpret_bitmap(item, number, pars, &taken, item->ptr, OP_UNSET);
+ break;
+ case OP_ALL:
+ msg = interpret_set_all(item, item->ptr);
+ break;
case OP_APPEND:
case OP_PREPEND:
if (item->cls == CC_DYNAMIC)
} else if (ci->cls == CC_LIST) {
inspect_section(ci->u.sec);
sec->flags |= SEC_FLAG_DYNAMIC | SEC_FLAG_CANT_COPY;
- } else if (ci->cls == CC_DYNAMIC)
+ } else if (ci->cls == CC_DYNAMIC || ci->cls == CC_BITMAP)
sec->flags |= SEC_FLAG_DYNAMIC;
else if (ci->cls == CC_PARSER) {
sec->flags |= SEC_FLAG_CANT_COPY;
static u32 ip;
static int *look = DARY_ALLOC(int, 2, 2, 1);
static u16 numbers[10] = { 2, 100, 1, 5 };
+static u32 bitmap1 = 0xff;
+static u32 bitmap2 = 3;
static byte *
parse_u16(byte *string, u16 *ptr)
CF_IP("ip", &ip),
CF_LOOKUP_DYN("look", &look, alphabet, 1000),
CF_USER_ARY("numbers", numbers, &u16_type, 10),
+ CF_BITMAP_INT("bitmap1", &bitmap1),
+ CF_BITMAP_LOOKUP("bitmap2", &bitmap2, ((byte*[]) {
+ "one", "two", "three", "four", "five", "six", "seven", "eight",
+ "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "seventeen",
+ "eighteen", "nineteen", "twenty", NULL // hidden joke here
+ })),
CF_END
}
};
look Alpha
look:prepend Beta GAMMA
numbers 11000 65535
+ bitmap1 31
+ bitmap1:unset 3 3
+ bitmap2:all
+ bitmap2:unset eleven twelve one
};;;;;;
unknown.ignored :-)
CC_DYNAMIC, // dynamically allocated array
CC_PARSER, // arbitrary parser function
CC_SECTION, // section appears exactly once
- CC_LIST // list with 0..many nodes
+ CC_LIST, // list with 0..many nodes
+ CC_BITMAP // of up to 32 items
};
enum cf_type {
#define CF_PARSER(n,p,f,c) { .cls = CC_PARSER, .name = n, .number = c, .ptr = p, .u.par = (cf_parser*) f }
#define CF_SECTION(n,p,s) { .cls = CC_SECTION, .name = n, .number = 1, .ptr = p, .u.sec = s }
#define CF_LIST(n,p,s) { .cls = CC_LIST, .name = n, .number = 1, .ptr = CHECK_PTR_TYPE(p,clist*), .u.sec = s }
+#define CF_BITMAP_INT(n,p) { .cls = CC_BITMAP, .type = CT_INT, .name = n, .number = 1, .ptr = CHECK_PTR_TYPE(p,u32*) }
+#define CF_BITMAP_LOOKUP(n,p,t) { .cls = CC_BITMAP, .type = CT_LOOKUP, .name = n, .number = 1, .ptr = CHECK_PTR_TYPE(p,u32*), .u.lookup = t }
/* Configuration items for basic types */
#define CF_INT(n,p) CF_STATIC(n,p,INT,int,1)
#define CF_INT_ARY(n,p,c) CF_STATIC(n,p,INT,int,c)
/* Direct access to configuration items: conf-intr.c */
-#define CF_OPERATIONS T(CLOSE) T(SET) T(CLEAR) T(APPEND) T(PREPEND) \
- T(REMOVE) T(EDIT) T(AFTER) T(BEFORE) T(COPY)
+#define CF_OPERATIONS T(CLOSE) T(SET) T(CLEAR) T(UNSET) T(ALL) \
+ T(APPEND) T(PREPEND) T(REMOVE) T(EDIT) T(AFTER) T(BEFORE) T(COPY)
/* Closing brace finishes previous block.
* Basic attributes (static, dynamic, parsed) can be used with SET.
* Dynamic arrays can be used with SET, APPEND, PREPEND.