From 5b470214ced0b72f173d55504552a4be24819abe Mon Sep 17 00:00:00 2001 From: Robert Spalek Date: Tue, 25 Apr 2006 22:25:27 +0200 Subject: [PATCH] conf2: add basic type CT_LOOKUP that maps strings to integers Since I need to store both type==CT_LOOKUP and a pointer to the lookup table, I moved the type out the union. However, I have not blown up the size of struct cf_item, because I have compressed class and type to 16 bits. --- lib/conf2-test.c | 3 +++ lib/conf2.c | 61 +++++++++++++++++++++++++++++++++++------------- lib/conf2.h | 19 +++++++++------ lib/conf2.t | 1 + 4 files changed, 61 insertions(+), 23 deletions(-) diff --git a/lib/conf2-test.c b/lib/conf2-test.c index dca21e67..257141af 100644 --- a/lib/conf2-test.c +++ b/lib/conf2-test.c @@ -74,6 +74,7 @@ static double d1 = -1.1; static struct clist secs; static time_t t1, t2; static u32 ip; +static int look[2] = {2, 1}; static byte * init_top(void *ptr UNUSED) @@ -103,6 +104,7 @@ time_parser(uns number, byte **pars, time_t *ptr) return NULL; } +static char *alphabet[] = { "alpha", "beta", "gamma", "delta", NULL }; static struct cf_section cf_top = { CF_INIT(init_top), CF_COMMIT(commit_top), @@ -119,6 +121,7 @@ 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_END } }; diff --git a/lib/conf2.c b/lib/conf2.c index 7216becd..71814115 100644 --- a/lib/conf2.c +++ b/lib/conf2.c @@ -590,6 +590,27 @@ cf_parse_string(byte *str, byte **ptr) return NULL; } +static byte * +cf_parse_lookup(byte *str, int *ptr, char **t) +{ + char **n = t; + uns total_len = 0; + while (*n && strcasecmp(*n, str)) { + total_len += strlen(*n) + 2; + n++; + } + if (*n) { + *ptr = n - t; + return NULL; + } + byte *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); + *ptr = -1; + return err; +} + /* Register size of and parser for each basic type */ typedef byte *cf_basic_parser(byte *str, void *ptr); @@ -601,15 +622,22 @@ static struct { { sizeof(u64), cf_parse_u64 }, { sizeof(double), cf_parse_double }, { sizeof(u32), cf_parse_ip }, - { sizeof(byte*), cf_parse_string } + { sizeof(byte*), cf_parse_string }, + { sizeof(int), NULL } // lookups are parsed extra }; static byte * -cf_parse_ary(uns number, byte **pars, void *ptr, enum cf_type type) +cf_parse_ary(uns number, byte **pars, void *ptr, enum cf_type type, union cf_union *u) { for (uns i=0; ilookup); + else + ASSERT(0); if (msg) return cf_printf("Cannot parse item %d: %s", i+1, msg); } @@ -630,18 +658,18 @@ static byte *op_names[] = { CF_OPERATIONS }; static byte * interpret_set_dynamic(struct cf_item *item, int number, byte **pars, void **ptr) { - enum cf_type type = item->u.type; + 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; - return cf_parse_ary(number, pars, *ptr, type); + 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) { - enum cf_type type = item->u.type; + enum cf_type type = item->type; void *old_p = *ptr; int old_nr = * (int*) (old_p - parsers[type].size); int taken = MIN(number, item->number-old_nr); @@ -653,10 +681,10 @@ interpret_add_dynamic(struct cf_item *item, int number, byte **pars, int *proces *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); + return cf_parse_ary(taken, pars, new_p + old_nr * parsers[type].size, type, &item->u); } else if (op == OP_PREPEND) { memcpy(new_p + taken * parsers[type].size, old_p, old_nr * parsers[type].size); - return cf_parse_ary(taken, pars, new_p, type); + 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]); } @@ -751,8 +779,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->u.type].size); - return cf_parse_ary(taken, pars, ptr, item->u.type); + cf_journal_block(ptr, taken * parsers[item->type].size); + return cf_parse_ary(taken, pars, ptr, item->type, &item->u); case CC_DYNAMIC: if (!allow_dynamic) return "Dynamic array cannot be used here"; @@ -800,10 +828,10 @@ 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; - if (item->u.type == CT_STRING) + if (item->type == CT_STRING) return strcmp(* (byte**) i1, * (byte**) i2); else // all numeric types - return memcmp(i1, i2, parsers[item->u.type].size); + return memcmp(i1, i2, parsers[item->type].size); } static void * @@ -1367,7 +1395,7 @@ spaces(struct fastbuf *fb, uns nr) } static void -dump_basic(struct fastbuf *fb, void *ptr, enum cf_type type) +dump_basic(struct fastbuf *fb, void *ptr, enum cf_type type, union cf_union *u) { switch (type) { case CT_INT: bprintf(fb, "%d ", *(uns*)ptr); break; @@ -1375,6 +1403,7 @@ dump_basic(struct fastbuf *fb, void *ptr, enum cf_type type) case CT_DOUBLE: bprintf(fb, "%lg ", *(double*)ptr); break; 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; } } @@ -1384,7 +1413,7 @@ static void dump_item(struct fastbuf *fb, struct cf_item *item, int level, void *ptr) { ptr += (addr_int_t) item->ptr; - enum cf_type type = item->u.type; + enum cf_type type = item->type; int i; spaces(fb, level); bprintf(fb, "%s: c%d #%d ", item->name, item->cls, item->number); @@ -1392,14 +1421,14 @@ dump_item(struct fastbuf *fb, struct cf_item *item, int level, void *ptr) bprintf(fb, "t%d ", type); if (item->cls == CC_STATIC) { for (i=0; inumber; i++) - dump_basic(fb, ptr + i * parsers[type].size, type); + dump_basic(fb, ptr + i * parsers[type].size, type, &item->u); } else if (item->cls == CC_DYNAMIC) { ptr = * (void**) ptr; if (ptr) { int real_nr = * (int*) (ptr - parsers[type].size); bprintf(fb, "##%d ", real_nr); for (i=0; iu); } else bprintf(fb, "NULL "); } diff --git a/lib/conf2.h b/lib/conf2.h index c341e0d2..947e9ddd 100644 --- a/lib/conf2.h +++ b/lib/conf2.h @@ -23,7 +23,8 @@ enum cf_class { enum cf_type { CT_INT, CT_U64, CT_DOUBLE, // number types CT_IP, // IP address - CT_STRING // string type + CT_STRING, // string type + CT_LOOKUP // in a string table }; typedef byte *cf_parser(uns number, byte **pars, void *ptr); @@ -44,15 +45,16 @@ typedef byte *cf_hook(void *ptr); struct cf_section; struct cf_item { - enum cf_class cls; - byte *name; + byte *name; // case insensitive int number; // length of an array or #parameters of a parser (negative means at most) void *ptr; // pointer to a global variable or an offset in a section - union { - enum cf_type type; // type of a static or dynamic attribute + union cf_union { 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 } u; + enum cf_class cls:16; // attribute class + enum cf_type type:16; // type of a static or dynamic attribute }; struct cf_section { @@ -71,8 +73,8 @@ struct cf_section { #define CF_END { .cls = CC_END } /* Configuration items */ struct clist; -#define CF_STATIC(n,p,T,t,c) { .cls = CC_STATIC, .name = n, .number = c, .ptr = CHECK_PTR_TYPE(p,t*), .u.type = CT_##T } -#define CF_DYNAMIC(n,p,T,t,c) { .cls = CC_DYNAMIC, .name = n, .number = c, .ptr = CHECK_PTR_TYPE(p,t**), .u.type = CT_##T } +#define CF_STATIC(n,p,T,t,c) { .cls = CC_STATIC, .type = CT_##T, .name = n, .number = c, .ptr = CHECK_PTR_TYPE(p,t*) } +#define CF_DYNAMIC(n,p,T,t,c) { .cls = CC_DYNAMIC, .type = CT_##T, .name = n, .number = c, .ptr = CHECK_PTR_TYPE(p,t**) } #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,struct clist*), .u.sec = s } @@ -95,6 +97,9 @@ struct clist; #define CF_STRING(n,p) CF_STATIC(n,p,STRING,byte*,1) #define CF_STRING_ARY(n,p,c) CF_STATIC(n,p,STRING,byte*,c) #define CF_STRING_DYN(n,p,c) CF_DYNAMIC(n,p,STRING,byte*,c) +#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 } /* If you aren't picky about the number of parameters */ #define CF_ANY_NUM -0x7fffffff diff --git a/lib/conf2.t b/lib/conf2.t index 9ffc82cc..0279eaf4 100644 --- a/lib/conf2.t +++ b/lib/conf2.t @@ -23,6 +23,7 @@ Top { \ slaves:clear ip 0xa ip 195.113.31.123 + look Alpha Gamma };;;;;; unknown.ignored :-) -- 2.39.2