From 2bed3c955c723cedc39f9d27df31f31bcb1dd585 Mon Sep 17 00:00:00 2001 From: Robert Spalek Date: Tue, 25 Apr 2006 23:25:11 +0200 Subject: [PATCH] conf2: added support for user-defined types (tested on u16) --- lib/conf2-test.c | 31 +++++++++++++++++++++++-- lib/conf2.c | 59 +++++++++++++++++++++++++++++++++++------------- lib/conf2.h | 23 +++++++++++++++++-- lib/conf2.t | 4 +++- 4 files changed, 96 insertions(+), 21 deletions(-) diff --git a/lib/conf2-test.c b/lib/conf2-test.c index 257141af..aa804cfd 100644 --- a/lib/conf2-test.c +++ b/lib/conf2-test.c @@ -74,7 +74,33 @@ static double d1 = -1.1; static struct clist secs; static time_t t1, t2; static u32 ip; -static int look[2] = {2, 1}; +static int *look = DARY_ALLOC(int, 2, 2, 1); +static u16 numbers[10] = { 2, 100, 1, 5 }; + +static byte * +parse_u16(byte *string, u16 *ptr) +{ + uns a; + byte *msg = cf_parse_int(string, &a); + if (msg) + return msg; + if (a >= (1<<16)) + return "Come on, man, this doesn't fit to 16 bits"; + *ptr = a; + return NULL; +} + +static void +dump_u16(struct fastbuf *fb, u16 *ptr) +{ + bprintf(fb, "%d ", *ptr); +} + +static struct cf_user_type u16_type = { + .size = sizeof(u16), + .parser = (cf_parser1*) parse_u16, + .dumper = (cf_dumper1*) dump_u16 +}; static byte * init_top(void *ptr UNUSED) @@ -121,7 +147,8 @@ static struct cf_section cf_top = { CF_SECTION("master", &sec1, &cf_sec_1), CF_LIST("slaves", &secs, &cf_sec_1), CF_IP("ip", &ip), - CF_LOOKUP_ARY("look", look, alphabet, 2), + CF_LOOKUP_DYN("look", &look, alphabet, 1000), + CF_USER_ARY("numbers", numbers, &u16_type, 10), CF_END } }; diff --git a/lib/conf2.c b/lib/conf2.c index 71814115..7ef69ff9 100644 --- a/lib/conf2.c +++ b/lib/conf2.c @@ -623,19 +623,32 @@ static struct { { sizeof(double), cf_parse_double }, { sizeof(u32), cf_parse_ip }, { sizeof(byte*), cf_parse_string }, - { sizeof(int), NULL } // lookups are parsed extra + { sizeof(int), NULL }, // lookups are parsed extra + { 0, NULL }, // user-defined types are parsed extra }; +static inline uns +type_size(enum cf_type type, struct cf_user_type *utype) +{ + if (type < CT_USER) + return parsers[type].size; + else + return utype->size; +} + static byte * cf_parse_ary(uns number, byte **pars, void *ptr, enum cf_type type, union cf_union *u) { for (uns i=0; iutype); if (type < CT_LOOKUP) - msg = ((cf_basic_parser*) parsers[type].parser) (pars[i], ptr + i * parsers[type].size); + 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 * sizeof(int), u->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 ASSERT(0); if (msg) @@ -661,8 +674,9 @@ interpret_set_dynamic(struct cf_item *item, int number, byte **pars, void **ptr) enum cf_type type = item->type; cf_journal_block(ptr, sizeof(void*)); // boundary checks done by the caller - *ptr = cf_malloc((number+1) * parsers[type].size) + parsers[type].size; - * (uns*) (*ptr - parsers[type].size) = number; + uns size = type_size(item->type, item->u.utype); + *ptr = cf_malloc((number+1) * size) + size; + * (uns*) (*ptr - size) = number; return cf_parse_ary(number, pars, *ptr, type, &item->u); } @@ -671,19 +685,20 @@ interpret_add_dynamic(struct cf_item *item, int number, byte **pars, int *proces { enum cf_type type = item->type; void *old_p = *ptr; - int old_nr = * (int*) (old_p - parsers[type].size); + uns size = type_size(item->type, item->u.utype); + int old_nr = * (int*) (old_p - size); int taken = MIN(number, item->number-old_nr); *processed = taken; // stretch the dynamic array - void *new_p = cf_malloc((old_nr + taken + 1) * parsers[type].size) + parsers[type].size; - * (uns*) (new_p - parsers[type].size) = old_nr + taken; + void *new_p = cf_malloc((old_nr + taken + 1) * size) + size; + * (uns*) (new_p - size) = old_nr + taken; cf_journal_block(ptr, sizeof(void*)); *ptr = new_p; if (op == OP_APPEND) { - memcpy(new_p, old_p, old_nr * parsers[type].size); - return cf_parse_ary(taken, pars, new_p + old_nr * parsers[type].size, type, &item->u); + memcpy(new_p, old_p, old_nr * size); + return cf_parse_ary(taken, pars, new_p + old_nr * size, type, &item->u); } else if (op == OP_PREPEND) { - memcpy(new_p + taken * parsers[type].size, old_p, old_nr * parsers[type].size); + memcpy(new_p + taken * size, old_p, old_nr * size); return cf_parse_ary(taken, pars, new_p, type, &item->u); } else return cf_printf("Dynamic arrays do not support operation %s", op_names[op]); @@ -779,7 +794,8 @@ interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed return "Missing value"; taken = MIN(number, item->number); *processed = taken; - cf_journal_block(ptr, taken * parsers[item->type].size); + uns size = type_size(item->type, item->u.utype); + cf_journal_block(ptr, taken * size); return cf_parse_ary(taken, pars, ptr, item->type, &item->u); case CC_DYNAMIC: if (!allow_dynamic) @@ -831,7 +847,7 @@ cmp_items(void *i1, void *i2, struct cf_item *item) if (item->type == CT_STRING) return strcmp(* (byte**) i1, * (byte**) i2); else // all numeric types - return memcmp(i1, i2, parsers[item->type].size); + return memcmp(i1, i2, type_size(item->type, item->u.utype)); } static void * @@ -1404,6 +1420,12 @@ dump_basic(struct fastbuf *fb, void *ptr, enum cf_type type, union cf_union *u) case CT_IP: bprintf(fb, "%08x ", *(uns*)ptr); break; case CT_STRING: bprintf(fb, "'%s' ", *(byte**)ptr); break; case CT_LOOKUP: bprintf(fb, "%s ", *(int*)ptr >= 0 ? u->lookup[ *(int*)ptr ] : "???"); break; + case CT_USER: + if (u->utype->dumper) + u->utype->dumper(fb, ptr); + else + bprintf(fb, "??? "); + break; } } @@ -1414,21 +1436,26 @@ dump_item(struct fastbuf *fb, struct cf_item *item, int level, void *ptr) { ptr += (addr_int_t) item->ptr; enum cf_type type = item->type; + uns size = type_size(item->type, item->u.utype); int i; spaces(fb, level); bprintf(fb, "%s: c%d #%d ", item->name, item->cls, item->number); if (item->cls == CC_STATIC || item->cls == CC_DYNAMIC) bprintf(fb, "t%d ", type); if (item->cls == CC_STATIC) { + if (item->type == CT_USER) + bprintf(fb, "S%d ", size); for (i=0; inumber; i++) - dump_basic(fb, ptr + i * parsers[type].size, type, &item->u); + dump_basic(fb, ptr + i * size, type, &item->u); } else if (item->cls == CC_DYNAMIC) { + if (item->type == CT_USER) + bprintf(fb, "S%d ", size); ptr = * (void**) ptr; if (ptr) { - int real_nr = * (int*) (ptr - parsers[type].size); + int real_nr = * (int*) (ptr - size); bprintf(fb, "##%d ", real_nr); for (i=0; iu); + dump_basic(fb, ptr + i * size, type, &item->u); } else bprintf(fb, "NULL "); } diff --git a/lib/conf2.h b/lib/conf2.h index 947e9ddd..7d4ad5d3 100644 --- a/lib/conf2.h +++ b/lib/conf2.h @@ -24,15 +24,22 @@ enum cf_type { CT_INT, CT_U64, CT_DOUBLE, // number types CT_IP, // IP address CT_STRING, // string type - CT_LOOKUP // in a string table + CT_LOOKUP, // in a string table + CT_USER // user-defined type }; +struct fastbuf; typedef byte *cf_parser(uns number, byte **pars, void *ptr); /* A parser function gets an array of (strdup'ed) strings and a pointer with * the customized information (most likely the target address). It can store * the parsed value anywhere in any way it likes, however it must first call * cf_journal_block() on the overwritten memory block. It returns an error * message or NULL if everything is all right. */ +typedef byte *cf_parser1(byte *string, void *ptr); + /* A parser function for user-defined types get one string and pointer to the + * destination variable. It can only store the value inside [ptr,ptr+size), + * where size is fixed for each type. It does not have to call + * cf_journal_block(). */ typedef byte *cf_hook(void *ptr); /* An init- or commit-hook gets a pointer to the section or NULL if this * is the global section. It returns an error message or NULL if everything @@ -42,6 +49,14 @@ typedef byte *cf_hook(void *ptr); * checks and postprocess the parsed values. Commit-hooks must call * cf_journal_block() too. Caveat! init-hooks for static sections must not * use cf_malloc() but normal xmalloc(). */ +typedef void *cf_dumper1(struct fastbuf *fb, void *ptr); + /* Dumps the contents of a variable of a user-defined type. */ + +struct cf_user_type { + uns size; // of the parsed attribute + cf_parser1 *parser; // how to parse it + cf_dumper1 *dumper; // optional and for debugging purposes only +}; struct cf_section; struct cf_item { @@ -52,6 +67,7 @@ struct cf_item { struct cf_section *sec; // declaration of a section or a list cf_parser *par; // parser function char **lookup; // NULL-terminated sequence of allowed strings for lookups + struct cf_user_type *utype; // specification of the user-defined type } u; enum cf_class cls:16; // attribute class enum cf_type type:16; // type of a static or dynamic attribute @@ -100,6 +116,10 @@ struct clist; #define CF_LOOKUP(n,p,t) { .cls = CC_STATIC, .type = CT_LOOKUP, .name = n, .number = 1, .ptr = CHECK_PTR_TYPE(p,int*), .u.lookup = t } #define CF_LOOKUP_ARY(n,p,t,c) { .cls = CC_STATIC, .type = CT_LOOKUP, .name = n, .number = c, .ptr = CHECK_PTR_TYPE(p,int*), .u.lookup = t } #define CF_LOOKUP_DYN(n,p,t,c) { .cls = CC_DYNAMIC, .type = CT_LOOKUP, .name = n, .number = c, .ptr = CHECK_PTR_TYPE(p,int**), .u.lookup = t } +#define CF_USER(n,p,t) { .cls = CC_STATIC, .type = CT_USER, .name = n, .number = 1, .ptr = p, .u.utype = t } +#define CF_USER_ARY(n,p,t,c) { .cls = CC_STATIC, .type = CT_USER, .name = n, .number = c, .ptr = p, .u.utype = t } +#define CF_USER_DYN(n,p,t,c) { .cls = CC_DYNAMIC, .type = CT_USER, .name = n, .number = c, .ptr = p, .u.utype = t } + // Beware that CF_USER_DYN can only be used on user-defined types of size at least 4 /* If you aren't picky about the number of parameters */ #define CF_ANY_NUM -0x7fffffff @@ -152,7 +172,6 @@ byte *cf_parse_ip(byte *p, u32 *varp); enum cf_operation { CF_OPERATIONS }; #undef T -struct fastbuf; byte *cf_find_item(byte *name, struct cf_item *item); byte *cf_write_item(struct cf_item *item, enum cf_operation op, int number, byte **pars); void cf_dump_sections(struct fastbuf *fb); diff --git a/lib/conf2.t b/lib/conf2.t index 0279eaf4..037ed70b 100644 --- a/lib/conf2.t +++ b/lib/conf2.t @@ -23,7 +23,9 @@ Top { \ slaves:clear ip 0xa ip 195.113.31.123 - look Alpha Gamma + look Alpha + look:prepend Beta GAMMA + numbers 11000 65535 };;;;;; unknown.ignored :-) -- 2.39.2