]> mj.ucw.cz Git - libucw.git/commitdiff
conf2: add basic type CT_LOOKUP that maps strings to integers
authorRobert Spalek <robert@ucw.cz>
Tue, 25 Apr 2006 20:25:27 +0000 (22:25 +0200)
committerRobert Spalek <robert@ucw.cz>
Tue, 25 Apr 2006 20:25:27 +0000 (22:25 +0200)
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
lib/conf2.c
lib/conf2.h
lib/conf2.t

index dca21e675866b602433c3608a7a15390dfe35865..257141af3e78b2dd0a8adfe73515e5b6dc917007 100644 (file)
@@ -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
   }
 };
index 7216becd8f03acdf0f753bf4755d08f100e75048..7181411532ce07fee4fc0afa87b07b656dfda012 100644 (file)
@@ -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; i<number; i++)
   {
-    byte *msg = ((cf_basic_parser*) parsers[type].parser) (pars[i], ptr + i * parsers[type].size);
+    byte *msg;
+    if (type < CT_LOOKUP)
+      msg = ((cf_basic_parser*) parsers[type].parser) (pars[i], ptr + i * parsers[type].size);
+    else if (type == CT_LOOKUP)
+      msg = cf_parse_lookup(pars[i], ptr + i * sizeof(int), u->lookup);
+    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; i<item->number; 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; i<real_nr; i++)
-       dump_basic(fb, ptr + i * parsers[type].size, type);
+       dump_basic(fb, ptr + i * parsers[type].size, type, &item->u);
     } else
       bprintf(fb, "NULL ");
   }
index c341e0d2812d9c548a7ed18d2bc5c43b2d1a7e9a..947e9ddd09c2083227c00835675cb3db3e5fa854 100644 (file)
@@ -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
index 9ffc82cc514a8fd7253cd598ae7a99d072d4eb1a..0279eaf4e04f1f3f10a2168de101e78ebc4616ad 100644 (file)
@@ -23,6 +23,7 @@ Top { \
   slaves:clear
   ip 0xa
   ip 195.113.31.123
+  look Alpha Gamma
 };;;;;;
 
 unknown.ignored :-)