]> mj.ucw.cz Git - libucw.git/commitdiff
conf2: enhanced the interpreter so that it can parse almost anything on 1 line
authorRobert Spalek <robert@ucw.cz>
Fri, 21 Apr 2006 09:26:24 +0000 (11:26 +0200)
committerRobert Spalek <robert@ucw.cz>
Fri, 21 Apr 2006 09:26:24 +0000 (11:26 +0200)
I cleaned up the subroutines so that they form a nice recursive structure
that allows to parse almost anything (static and dynamic arrays, lists,
parsed value, and sections in all combinations) on 1 line, while detecting
ambiguities.

lib/conf2.c

index 7c55384b2901191528125698dc87f937480d6e10..9e772e1603d68885a981721fb9cb570a955d3899 100644 (file)
@@ -460,25 +460,24 @@ static struct item_stack {
 static uns level;
 
 static byte *
-parse_dynamic(struct cf_item *item, int number, byte **pars, void **ptr)
+interpret_set_dynamic(struct cf_item *item, int number, byte **pars, void **ptr)
 {
   enum cf_type type = item->u.type;
-  if (number > item->number)
-    return "Expecting shorter array";
   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);
 }
 
 static byte *
-add_to_dynamic(struct cf_item *item, int number, byte **pars, void **ptr, enum operation op)
+interpret_add_dynamic(struct cf_item *item, int number, byte **pars, void **ptr, enum operation op)
 {
   enum cf_type type = item->u.type;
   void *old_p = *ptr;
   int old_nr = * (int*) (old_p - parsers[type].size);
   if (old_nr + number > item->number)
-    return "Cannot enlarge dynamic array";
+    return "Too many parameters for the dynamic array";
   // stretch the dynamic array
   void *new_p = cf_malloc((old_nr + number + 1) * parsers[type].size) + parsers[type].size;
   * (uns*) (new_p - parsers[type].size) = old_nr + number;
@@ -498,33 +497,22 @@ add_to_dynamic(struct cf_item *item, int number, byte **pars, void **ptr, enum o
     ASSERT(0);
 }
 
+static byte *interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, uns allow_dynamic, void *ptr);
+
 static byte *
-parse_subsection(struct cf_section *sec, int number, byte **pars, void *ptr)
+interpret_subsection(struct cf_section *sec, int number, byte **pars, int *processed, uns allow_dynamic, void *ptr)
 {
-  struct cf_item *ci;
-  for (ci=sec->cfg; ci->cls; ci++)
+  *processed = 0;
+  for (struct cf_item *ci=sec->cfg; ci->cls; ci++)
   {
-    if (ci->cls == CC_DYNAMIC && !ci[1].cls)
-      break;
-    if (ci->cls != CC_STATIC)
-      return "Only sections consisting entirely of basic attributes can be written on 1 line";
-    if (number)
-    {
-      if (number < ci->number)
-       return "The number of parameters does not fit the section attributes";
-      void *p = ptr + (addr_int_t) ci->ptr;
-      cf_journal_block(p, ci->number * parsers[ci->u.type].size);
-      byte *msg = cf_parse_ary(ci->number, pars, p, ci->u.type);
-      if (msg)
-       return cf_printf("Attribute %s: %s", ci->name, msg);
-      number -= ci->number;
-      pars += ci->number;
-    }
+    int taken;
+    byte *msg = interpret_set_item(ci, number, pars, &taken, allow_dynamic && !ci[1].cls, ptr + (addr_int_t) ci->ptr);
+    if (msg)
+      return cf_printf("Item %s: %s", ci->name, msg);
+    *processed += taken;
+    number -= taken;
+    pars += taken;
   }
-  if (ci->cls == CC_DYNAMIC)
-    return parse_dynamic(ci, number, pars, ptr + (addr_int_t) ci->ptr);
-  else if (number)
-    return "Too many parameters for this section";
   return NULL;
 }
 
@@ -532,7 +520,7 @@ static void
 add_to_list(struct clist *list, struct cnode *node, enum operation op)
 {
   cf_journal_block(list, sizeof(struct clist));
-  if (op == OP_APPEND || op == OP_SET)
+  if (op == OP_APPEND)
     clist_add_tail(list, node);
   else if (op == OP_PREPEND)
     clist_add_head(list, node);
@@ -540,6 +528,63 @@ add_to_list(struct clist *list, struct cnode *node, enum operation op)
     ASSERT(0);
 }
 
+static byte *
+interpret_add_list(struct cf_item *item, int number, byte **pars, void *ptr, enum operation op)
+{
+  while (number > 0)
+  {
+    void *node = cf_malloc(item->u.sec->size);
+    cf_init_section(item->name, item->u.sec, node);
+    add_to_list(ptr, node, op);
+    int taken;
+    byte *msg = interpret_subsection(item->u.sec, number, pars, &taken, 0, node);
+    if (msg)
+      return msg;
+    number -= taken;
+    pars += taken;
+  }
+  return NULL;
+}
+
+static byte *
+interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, uns allow_dynamic, void *ptr)
+{
+  int taken;
+  switch (item->cls)
+  {
+    case CC_STATIC:
+      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);
+    case CC_DYNAMIC:
+      if (!allow_dynamic)
+       return "Dynamic array cannot be used here";
+      taken = MIN(number, item->number);
+      *processed = taken;
+      return interpret_set_dynamic(item, taken, pars, ptr);
+    case CC_PARSER:
+      if (item->number < 0 && !allow_dynamic)
+       return "Parsers with variable number of parameters cannot be used here";
+      if (item->number > 0 && number < item->number)
+       return "Not enough parameters available for the parser";
+      taken = MIN(number, ABS(item->number));
+      *processed = taken;
+      for (int i=0; i<taken; i++)
+       pars[i] = cf_strdup(pars[i]);
+      return item->u.par(taken, pars, ptr);
+    case CC_SECTION:
+      return interpret_subsection(item->u.sec, number, pars, processed, allow_dynamic, ptr);
+    case CC_LIST:
+      if (!allow_dynamic)
+       return "Lists cannot be used here";
+      *processed = number;
+      return interpret_add_list(item, number, pars, ptr, OP_APPEND);
+    default:
+      ASSERT(0);
+  }
+}
+
 static byte *
 increase_stack(struct cf_item *item, enum operation op)
 {
@@ -569,7 +614,7 @@ increase_stack(struct cf_item *item, enum operation op)
 }
 
 static byte *
-interpret_item(byte *name, enum operation op, int number, byte **pars)
+interpret_line(byte *name, enum operation op, int number, byte **pars)
 {
   byte *msg;
   struct cf_item *item = find_item(stack[level].sec, name, &msg);
@@ -579,53 +624,28 @@ interpret_item(byte *name, enum operation op, int number, byte **pars)
     return msg;
 
   void *ptr = stack[level].base_ptr + (addr_int_t) item->ptr;
-  if (op == OP_CLEAR)          // clear link-list
+  if (op == OP_CLEAR)
   {
     if (item->cls != CC_LIST)
       return "The item is not a list";
     cf_journal_block(ptr, sizeof(struct clist));
     clist_init(ptr);
   }
-  else if (op == OP_SET && item->cls != CC_LIST)
-    switch (item->cls)         // setting regular variables
-    {
-      case CC_STATIC:
-       if (number != item->number)
-         return item->number==1 ? "Expecting one scalar value, not an array" : "Expecting array of different length";
-       cf_journal_block(ptr, number * parsers[item->u.type].size);
-       return cf_parse_ary(number, pars, ptr, item->u.type);
-      case CC_DYNAMIC:
-       return parse_dynamic(item, number, pars, ptr);
-      case CC_PARSER:
-       if (item->number >= 0)
-       {
-         if (number != item->number)
-           return "Expecting different number of parameters";
-       } else {
-         if (number > -item->number)
-           return "Expecting less parameters";
-       }
-       for (int i=0; i<number; i++)
-         pars[i] = cf_strdup(pars[i]);
-       return item->u.par(number, pars, ptr);
-      case CC_SECTION:         // setting a subsection at once
-       return parse_subsection(item->u.sec, number, pars, ptr);
-      default:
-       ASSERT(0);
-    }
-  else if (item->cls == CC_DYNAMIC)
-    return add_to_dynamic(item, number, pars, ptr, op);
-  else if (item->cls == CC_LIST)
-  {                            // adding to a list at once
-    void *node = cf_malloc(item->u.sec->size);
-    cf_init_section(item->name, item->u.sec, node);
-    msg = parse_subsection(item->u.sec, number, pars, node);
+  else if (op == OP_SET)
+  {
+    int taken;
+    msg = interpret_set_item(item, number, pars, &taken, 1, ptr);
     if (msg)
       return msg;
-    add_to_list(ptr, node, op);
+    if (taken < number)
+      return "Too many parameters";
   }
+  else if (item->cls == CC_DYNAMIC)
+    return interpret_add_dynamic(item, number, pars, ptr, op);
+  else if (item->cls == CC_LIST)
+    return interpret_add_list(item, number, pars, ptr, op);
   else
-    ASSERT(0);
+    return cf_printf("Operation %d not supported for class %d", op, item->cls);
   return NULL;
 }