]> mj.ucw.cz Git - libucw.git/commitdiff
conf2: added support for user-defined types (tested on u16)
authorRobert Spalek <robert@ucw.cz>
Tue, 25 Apr 2006 21:25:11 +0000 (23:25 +0200)
committerRobert Spalek <robert@ucw.cz>
Tue, 25 Apr 2006 21:25:11 +0000 (23:25 +0200)
lib/conf2-test.c
lib/conf2.c
lib/conf2.h
lib/conf2.t

index 257141af3e78b2dd0a8adfe73515e5b6dc917007..aa804cfd92beaf8f827667fee6a352b19052d47f 100644 (file)
@@ -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
   }
 };
index 7181411532ce07fee4fc0afa87b07b656dfda012..7ef69ff973d887b78a572977f1adbcceb9a6b610 100644 (file)
@@ -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; i<number; i++)
   {
     byte *msg;
+    uns size = type_size(type, u->utype);
     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; i<item->number; 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; i<real_nr; i++)
-       dump_basic(fb, ptr + i * parsers[type].size, type, &item->u);
+       dump_basic(fb, ptr + i * size, type, &item->u);
     } else
       bprintf(fb, "NULL ");
   }
index 947e9ddd09c2083227c00835675cb3db3e5fa854..7d4ad5d309827ede7efa4c9e7f56a790e17643c1 100644 (file)
@@ -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);
index 0279eaf4e04f1f3f10a2168de101e78ebc4616ad..037ed70b0f74b4f76fb52f222aa7ed611c7892a4 100644 (file)
@@ -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 :-)