]> mj.ucw.cz Git - libucw.git/commitdiff
implemented parser of a single line and top-level sections unified
authorRobert Spalek <robert@ucw.cz>
Thu, 20 Apr 2006 22:56:54 +0000 (00:56 +0200)
committerRobert Spalek <robert@ucw.cz>
Thu, 20 Apr 2006 22:56:54 +0000 (00:56 +0200)
- we store registered sections in the same format as subsections so that we
  can search/process them in a uniform way
- implemented find_item() that can parse both absolute and relative paths
- all parsers of basic types simplified to take care of only 1 value;
  arrays are handled by the caller
- implemented a part of the interpretter: it gets parsed line (attribute
  name, desired operations, and parameters) and loads the values into
  memory.  since declarations can be nested and they can span over multiple
  lines, the interpretter operates on a stack

lib/conf2.c
lib/conf2.h

index b82210bda50fd007adba5ab087988eba38e1090e..594ad757b04cde266d37b7da6b30a84be1fda955 100644 (file)
@@ -140,24 +140,41 @@ journal_rollback_section(uns new_pool, struct journal_item *oldj, byte *msg)
 
 /* Initialization */
 
-static struct section {
-  struct section *prev;
-  byte *name;
-  struct cf_section *sec;
-} *sections;
+static struct cf_section sections;     // root section
+
+static struct cf_item *
+find_subitem(struct cf_section *sec, byte *name)
+{
+  struct cf_item *ci = sec->cfg;
+  for (; ci->cls; ci++)
+    if (!strcasecmp(ci->name, name))
+      return ci;
+  return ci;
+}
 
 void
 cf_declare_section(byte *name, struct cf_section *sec)
 {
-  struct section *s = sections;
-  for (; s; s=s->prev)
-    if (!strcasecmp(s->name, name))
-      die("Cannot register cf_section %s twice", name);
-  s = xmalloc(sizeof(struct section));
-  s->prev = sections;
-  s->name = name;
-  s->sec = sec;
-  sections = s;
+  if (!sections.cfg)
+  {
+    sections.size = 50;
+    sections.cfg = xmalloc_zero(sections.size * sizeof(struct cf_item));
+  }
+  struct cf_item *ci = find_subitem(&sections, name);
+  if (ci->cls)
+    die("Cannot register section %s twice", name);
+  ci->cls = CC_SECTION;
+  ci->name = name;
+  ci->number = 1;
+  ci->ptr = NULL;
+  ci->u.sec = sec;
+  ci++;
+  if (ci - sections.cfg >= (int) sections.size)
+  {
+    sections.cfg = xrealloc(sections.cfg, 2*sections.size * sizeof(struct cf_item));
+    bzero(sections.cfg + sections.size, sections.size * sizeof(struct cf_item));
+    sections.size *= 2;
+  }
 }
 
 void
@@ -178,14 +195,52 @@ cf_init_section(byte *name, struct cf_section *sec, void *ptr)
 static void
 global_init(void)
 {
-  for (struct section *s=sections; s; s=s->prev)
-    cf_init_section(s->name, s->sec, NULL);
+  for (struct cf_item *ci=sections.cfg; ci->cls; ci++)
+    cf_init_section(ci->name, ci->u.sec, NULL);
+}
+
+static struct cf_item *
+find_item(struct cf_section *curr_sec, byte *name, byte **msg)
+{
+  *msg = NULL;
+  if (name[0] == '.')
+    name++;
+  else if (strchr(name, '.'))
+    curr_sec = &sections;
+  if (!curr_sec)
+    return NULL;
+  byte *c;
+  while ((c = strchr(name, '.')))
+  {
+    *c++ = 0;
+    struct cf_item *ci = find_subitem(curr_sec, name);
+    if (ci->cls != CC_SECTION)
+    {
+      *msg = cf_printf("Item %s %s", name, !ci->cls ? "does not exist" : "is not a subsection");
+      return NULL;
+    }
+    curr_sec = ci->u.sec;
+    name = c;
+  }
+  struct cf_item *ci = find_subitem(curr_sec, name);
+  if (!ci->cls)
+  {
+    *msg = "Unknown item";
+    return NULL;
+  }
+  return ci;
 }
 
 /* Safe loading and reloading */
 
 byte *cf_def_file = DEFAULT_CONFIG;
 
+#ifndef DEFAULT_CONFIG
+#define DEFAULT_CONFIG NULL
+#endif
+
+byte *cfdeffile = DEFAULT_CONFIG;
+
 static byte *load_file(byte *file);
 static byte *load_string(byte *string);
 
@@ -275,108 +330,94 @@ lookup_unit(byte *value, byte *end, byte **msg)
 static char cf_rngerr[] = "Number out of range";
 
 byte *
-cf_parse_int(uns number, byte **pars, int *ptr)
+cf_parse_int(byte *str, int *ptr)
 {
-  for (uns i=0; i<number; i++)
-  {
-    byte *msg = NULL;
-    if (!*pars[i])
-      msg = "Missing number";
-    else {
-      const struct unit *u;
-      char *end;
-      errno = 0;
-      uns x = strtoul(pars[i], &end, 0);
-      if (errno == ERANGE)
-       msg = cf_rngerr;
-      else if (u = lookup_unit(pars[i], end, &msg)) {
-       u64 y = (u64)x * u->num;
-       if (y % u->den)
-         msg = "Number is not an integer";
-       else {
-         y /= u->den;
-         if (y > 0xffffffff)
-           msg = cf_rngerr;
-         ptr[i] = y;
-       }
-      } else
-       ptr[i] = x;
-    }
-    if (msg)
-      return number==1 ? msg : cf_printf("Item #%d: %s", i+1, msg);
+  byte *msg = NULL;
+  if (!*str)
+    msg = "Missing number";
+  else {
+    const struct unit *u;
+    char *end;
+    errno = 0;
+    uns x = strtoul(str, &end, 0);
+    if (errno == ERANGE)
+      msg = cf_rngerr;
+    else if (u = lookup_unit(str, end, &msg)) {
+      u64 y = (u64)x * u->num;
+      if (y % u->den)
+       msg = "Number is not an integer";
+      else {
+       y /= u->den;
+       if (y > 0xffffffff)
+         msg = cf_rngerr;
+       *ptr = y;
+      }
+    } else
+      *ptr = x;
   }
-  return NULL;
+  return msg;
 }
 
 byte *
-cf_parse_u64(uns number, byte **pars, u64 *ptr)
+cf_parse_u64(byte *str, u64 *ptr)
 {
-  for (uns i=0; i<number; i++)
-  {
-    byte *msg = NULL;
-    if (!*pars[i])
-      msg = "Missing number";
-    else {
-      const struct unit *u;
-      char *end;
-      errno = 0;
-      u64 x = strtoull(pars[i], &end, 0);
-      if (errno == ERANGE)
-       msg = cf_rngerr;
-      else if (u = lookup_unit(pars[i], end, &msg)) {
-       if (x > ~(u64)0 / u->num)
-         msg = "Number out of range";
-       else {
-         x *= u->num;
-         if (x % u->den)
-           msg = "Number is not an integer";
-         else
-           ptr[i] = x / u->den;
-       }
-      } else
-       ptr[i] = x;
-    }
-    if (msg)
-      return number==1 ? msg : cf_printf("Item #%d: %s", i+1, msg);
+  byte *msg = NULL;
+  if (!*str)
+    msg = "Missing number";
+  else {
+    const struct unit *u;
+    char *end;
+    errno = 0;
+    u64 x = strtoull(str, &end, 0);
+    if (errno == ERANGE)
+      msg = cf_rngerr;
+    else if (u = lookup_unit(str, end, &msg)) {
+      if (x > ~(u64)0 / u->num)
+       msg = "Number out of range";
+      else {
+       x *= u->num;
+       if (x % u->den)
+         msg = "Number is not an integer";
+       else
+         *ptr = x / u->den;
+      }
+    } else
+      *ptr = x;
   }
-  return NULL;
+  return msg;
 }
 
 byte *
-cf_parse_double(uns number, byte **pars, double *ptr)
+cf_parse_double(byte *str, double *ptr)
 {
-  for (uns i=0; i<number; i++)
-  {
-    byte *msg = NULL;
-    if (!*pars[i])
-      msg = "Missing number";
-    else {
-      const struct unit *u;
-      char *end;
-      errno = 0;
-      double x = strtoul(pars[i], &end, 0);
-      if (errno == ERANGE)
-       msg = cf_rngerr;
-      else if (u = lookup_unit(pars[i], end, &msg))
-       ptr[i] = x * u->num / u->den;
-      else
-       ptr[i] = x;
-    }
-    if (msg)
-      return number==1 ? msg : cf_printf("Item #%d: %s", i+1, msg);
+  byte *msg = NULL;
+  if (!*str)
+    msg = "Missing number";
+  else {
+    const struct unit *u;
+    char *end;
+    errno = 0;
+    double x = strtoul(str, &end, 0);
+    if (errno == ERANGE)
+      msg = cf_rngerr;
+    else if (u = lookup_unit(str, end, &msg))
+      *ptr = x * u->num / u->den;
+    else
+      *ptr = x;
   }
-  return NULL;
+  return msg;
 }
 
 static byte *
-cf_parse_string(uns number, byte **pars, byte **ptr)
+cf_parse_string(byte *str, byte **ptr)
 {
-  for (uns i=0; i<number; i++)
-    ptr[i] = cf_strdup(pars[i]);
+  *ptr = cf_strdup(str);
   return NULL;
 }
 
 /* Register size of and parser for each basic type */
+
+typedef byte *cf_basic_parser(byte *str, void *ptr);
 static struct {
   uns size;
   void *parser;
@@ -388,11 +429,201 @@ static struct {
 };
 
 static byte *
-cf_parse_dyn(uns number, byte **pars, void **ptr, enum cf_type type)
+cf_parse_ary(uns number, byte **pars, void *ptr, enum cf_type type)
+{
+  for (uns i=0; i<number; i++)
+  {
+    byte *msg = ((cf_basic_parser*) parsers[type].parser) (pars[i], ptr + i * parsers[type].size);
+    if (msg)
+      return cf_printf("Cannot parse item %d: %s", i+1, msg);
+  }
+  return NULL;
+}
+
+/* Interpreter */
+
+enum operation {
+  OP_CLEAR,                    // list
+  OP_SET,                      // basic attribute (static, dynamic, parsed), section, list
+  OP_APPEND,                   // dynamic array, list
+  OP_PREPEND,                  // dynamic array, list
+  OP_REMOVE,                   // list
+  OP_OPEN = 0x80               // here we only have an opening brace
+};
+
+#define MAX_STACK_SIZE 100
+static struct item_stack {
+  void *base_ptr;
+  struct cf_section *sec;
+  enum operation op;
+} stack[MAX_STACK_SIZE];
+static uns level;
+
+static byte *
+parse_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*));
   *ptr = cf_malloc((number+1) * parsers[type].size) + parsers[type].size;
   * (uns*) (*ptr - parsers[type].size) = number;
-  return ((cf_parser*) parsers[type].parser) (number, pars, *ptr);
+  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)
+{
+  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";
+  // 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;
+  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(number, pars, new_p + old_nr * parsers[type].size, type);
+  }
+  else if (op == OP_PREPEND)
+  {
+    memcpy(new_p + number * parsers[type].size, old_p, old_nr * parsers[type].size);
+    return cf_parse_ary(number, pars, new_p, type);
+  }
+  else
+    ASSERT(0);
+}
+
+static byte *
+parse_subsection(struct cf_section *sec, int number, byte **pars, void *ptr)
+{
+  struct cf_item *ci;
+  for (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;
+    }
+  }
+  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;
+}
+
+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)
+    clist_add_tail(list, node);
+  else if (op == OP_PREPEND)
+    clist_add_head(list, node);
+  else
+    ASSERT(0);
+}
+
+static byte *
+increase_stack(struct cf_item *item, enum operation op)
+{
+  if (level >= MAX_STACK_SIZE-1)
+    return "Too many nested sections";
+  ++level;
+  if (item)                    // fill in the base pointer
+  {
+    if (item->cls == CC_SECTION)
+      stack[level].base_ptr = stack[level].base_ptr + (addr_int_t) item->ptr;
+    else if (item->cls != CC_LIST)
+    {
+      stack[level].base_ptr = cf_malloc(item->u.sec->size);
+      cf_init_section(item->name, item->u.sec, stack[level].base_ptr);
+    }
+    else
+      return "Opening brace can only be used on sections and lists";
+    stack[level].sec = item->u.sec;
+  }
+  else                         // unknown is also handled here, since we need to trace recursion
+  {
+    stack[level].base_ptr = NULL;
+    stack[level].sec = NULL;
+  }
+  stack[level].op = op;
+  return NULL;
+}
+
+static byte *
+interpret_item(byte *name, enum operation op, int number, byte **pars)
+{
+  byte *msg;
+  struct cf_item *item = find_item(stack[level].sec, name, &msg);
+  if (op & OP_OPEN)            // the operation will be performed after the closing brace
+    return increase_stack(item, op) ? : msg;
+  if (!item)
+    return msg;
+
+  void *ptr = stack[level].base_ptr + (addr_int_t) item->ptr;
+  if (op == OP_CLEAR)          // clear link-list
+  {
+    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 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";
+       }
+       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);
+    if (msg)
+      return msg;
+    add_to_list(ptr, node, op);
+  }
+  else
+    ASSERT(0);
+  return NULL;
 }
 
index 94e85160557e2606a07628855448ee6835a436e6..2a2281ff616fdb26c67907c77119d597257227b0 100644 (file)
@@ -115,8 +115,8 @@ byte *cf_load(byte *file);
 byte *cf_set(byte *string);
 
 /* Parsers for basic types */
-byte *cf_parse_int(uns number, byte **pars, int *ptr);
-byte *cf_parse_u64(uns number, byte **pars, u64 *ptr);
-byte *cf_parse_double(uns number, byte **pars, double *ptr);
+byte *cf_parse_int(byte *str, int *ptr);
+byte *cf_parse_u64(byte *str, u64 *ptr);
+byte *cf_parse_double(byte *str, double *ptr);
 
 #endif