]> mj.ucw.cz Git - libucw.git/commitdiff
XTypes: Added support to configuration and option parser.
authorPavel Charvat <pchar@ucw.cz>
Thu, 4 Sep 2014 11:39:06 +0000 (11:39 +0000)
committerPavel Charvat <pchar@ucw.cz>
Thu, 4 Sep 2014 11:39:06 +0000 (11:39 +0000)
ucw/conf-dump.c
ucw/conf-internal.h
ucw/conf-intr.c
ucw/conf-test.c
ucw/conf-test.cf
ucw/conf.h
ucw/doc/conf.txt
ucw/doc/opt.txt
ucw/opt.c
ucw/opt.h

index cb80db70ca05cd54547f8518bc7d9f7e3f024ab3..cc5ddb37792953fdc6da29dafad20c1cadf42e9f 100644 (file)
@@ -3,6 +3,7 @@
  *
  *     (c) 2001--2006 Robert Spalek <robert@ucw.cz>
  *     (c) 2003--2012 Martin Mares <mj@ucw.cz>
+ *     (c) 2014 Pavel Charvat <pchar@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
@@ -14,6 +15,7 @@
 #include <ucw/conf-internal.h>
 #include <ucw/clists.h>
 #include <ucw/fastbuf.h>
+#include <ucw/xtypes.h>
 
 static void
 spaces(struct fastbuf *fb, uint nr)
@@ -43,6 +45,9 @@ dump_basic(struct fastbuf *fb, void *ptr, enum cf_type type, union cf_union *u)
       else
        bprintf(fb, "??? ");
       break;
+    case CT_XTYPE:
+      bprintf(fb, "'%s' ", u->xtype->format(ptr, XTYPE_FMT_DEFAULT, cf_get_pool()));
+      break;
   }
 }
 
@@ -55,7 +60,7 @@ dump_item(struct fastbuf *fb, struct cf_item *item, int level, void *ptr)
 {
   ptr += (uintptr_t) item->ptr;
   enum cf_type type = item->type;
-  uint size = cf_type_size(item->type, item->u.utype);
+  uint size = cf_type_size(item->type, &item->u);
   int i;
   spaces(fb, level);
   bprintf(fb, "%s: C%s #", item->name, class_names[item->cls]);
@@ -64,9 +69,12 @@ dump_item(struct fastbuf *fb, struct cf_item *item, int level, void *ptr)
   else
     bprintf(fb, "%d ", item->number);
   if (item->cls == CC_STATIC || item->cls == CC_DYNAMIC || item->cls == CC_BITMAP) {
-    bprintf(fb, "T%s ", cf_type_names[type]);
     if (item->type == CT_USER)
       bprintf(fb, "U%s S%d ", item->u.utype->name, size);
+    else if (item->type == CT_XTYPE)
+      bprintf(fb, "X%s S%d ", item->u.xtype->name, size);
+    else
+      bprintf(fb, "T%s ", cf_type_names[type]);
   }
   if (item->cls == CC_STATIC) {
     for (i=0; i<item->number; i++)
index 7ac490fbed4fd58bfc0804c48a67ad7e6fce8398..408fc19b6427001bff67a6c1265adcb4d35ad7f6 100644 (file)
@@ -3,6 +3,7 @@
  *
  *     (c) 2001--2006 Robert Spalek <robert@ucw.cz>
  *     (c) 2003--2012 Martin Mares <mj@ucw.cz>
+ *     (c) 2014 Pavel Charvat <pchar@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
@@ -98,7 +99,7 @@ enum cf_operation;
 extern char *cf_op_names[];
 extern char *cf_type_names[];
 
-uint cf_type_size(enum cf_type type, struct cf_user_type *utype);
+uint cf_type_size(enum cf_type type, const union cf_union *u);
 char *cf_interpret_line(struct cf_context *cc, char *name, enum cf_operation op, int number, char **pars);
 void cf_init_stack(struct cf_context *cc);
 int cf_done_stack(struct cf_context *cc);
index cf98b35bca112028037492e765e0825b373ff659..6ef07830a37b3eebfd358286a63a8e0fdea0693d 100644 (file)
@@ -3,6 +3,7 @@
  *
  *     (c) 2001--2006 Robert Spalek <robert@ucw.cz>
  *     (c) 2003--2014 Martin Mares <mj@ucw.cz>
+ *     (c) 2014 Pavel Charvat <pchar@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
@@ -15,6 +16,7 @@
 #include <ucw/clists.h>
 #include <ucw/gary.h>
 #include <ucw/mempool.h>
+#include <ucw/xtypes.h>
 
 #include <string.h>
 #include <stdio.h>
@@ -45,12 +47,18 @@ static struct {
 };
 
 inline uint
-cf_type_size(enum cf_type type, struct cf_user_type *utype)
+cf_type_size(enum cf_type type, const union cf_union *u)
 {
-  if (type < CT_USER)
-    return parsers[type].size;
-  else
-    return utype->size;
+  switch (type)
+    {
+      case CT_USER:
+        return u->utype->size;
+      case CT_XTYPE:
+       return u->xtype->size;
+      default:
+       ASSERT(type < ARRAY_SIZE(parsers) - 1);
+       return parsers[type].size;
+    }
 }
 
 static char *
@@ -82,13 +90,15 @@ cf_parse_ary(uint number, char **pars, void *ptr, enum cf_type type, union cf_un
   for (uint i=0; i<number; i++)
   {
     char *msg;
-    uint size = cf_type_size(type, u->utype);
+    uint size = cf_type_size(type, u);
     if (type < CT_LOOKUP)
       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 * size, u->lookup);
     else if (type == CT_USER)
       msg = u->utype->parser(pars[i], ptr + i * size);
+    else if (type == CT_XTYPE)
+      msg = (char *)u->xtype->parse(pars[i], ptr + i * size, cf_get_pool());
     else
       ASSERT(0);
     if (msg)
@@ -108,7 +118,7 @@ static char *
 interpret_set_dynamic(struct cf_item *item, int number, char **pars, void **ptr)
 {
   enum cf_type type = item->type;
-  uint size = cf_type_size(type, item->u.utype);
+  uint size = cf_type_size(type, &item->u);
   cf_journal_block(ptr, sizeof(void*));
   // boundary checks done by the caller
   *ptr = gary_init(size, number, mp_get_allocator(cf_get_pool()));
@@ -120,7 +130,7 @@ interpret_add_dynamic(struct cf_item *item, int number, char **pars, int *proces
 {
   enum cf_type type = item->type;
   void *old_p = *ptr;
-  uint size = cf_type_size(item->type, item->u.utype);
+  uint size = cf_type_size(item->type, &item->u);
   ASSERT(size >= sizeof(uint));
   int old_nr = old_p ? GARY_SIZE(old_p) : 0;
   int taken = MIN(number, ABS(item->number)-old_nr);
@@ -261,7 +271,7 @@ interpret_set_item(struct cf_item *item, int number, char **pars, int *processed
        return "Missing value";
       taken = MIN(number, item->number);
       *processed = taken;
-      uint size = cf_type_size(item->type, item->u.utype);
+      uint size = cf_type_size(item->type, &item->u);
       cf_journal_block(ptr, taken * size);
       return cf_parse_ary(taken, pars, ptr, item->type, &item->u);
     case CC_DYNAMIC:
@@ -337,7 +347,7 @@ cmp_items(void *i1, void *i2, struct cf_item *item)
   if (item->type == CT_STRING)
     return strcmp(* (char**) i1, * (char**) i2);
   else                         // all numeric types
-    return memcmp(i1, i2, cf_type_size(item->type, item->u.utype));
+    return memcmp(i1, i2, cf_type_size(item->type, &item->u));
 }
 
 static void *
index 715d9beed3a0642a6131038c793bc736701f4fcc..12434c9868394725b5c9eca3aec674671acb74cc 100644 (file)
@@ -3,6 +3,7 @@
  *
  *     (c) 2006 Robert Spalek <robert@ucw.cz>
  *     (c) 2012--2014 Martin Mares <mj@ucw.cz>
+ *     (c) 2014 Pavel Charvat <pchar@ucw.cz>
  */
 
 #include <ucw/lib.h>
@@ -11,6 +12,7 @@
 #include <ucw/clists.h>
 #include <ucw/fastbuf.h>
 #include <ucw/gary.h>
+#include <ucw/xtypes.h>
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -88,6 +90,7 @@ static int *look;
 static u16 numbers[10] = { 2, 100, 1, 5 };
 static u32 bitmap1 = 0xff;
 static u32 bitmap2 = 3;
+static intmax_t intmax;
 
 static char *
 parse_u16(char *string, u16 *ptr)
@@ -155,6 +158,7 @@ static struct cf_section cf_top = {
     CF_IP("ip", &ip),
     CF_LOOKUP_DYN("look", &look, alphabet, 1000),
     CF_USER_ARY("numbers", numbers, &u16_type, 10),
+    CF_XTYPE("intmax", &intmax, xt_intmax),
     CF_BITMAP_INT("bitmap1", &bitmap1),
     CF_BITMAP_LOOKUP("bitmap2", &bitmap2, ((const char* const[]) {
          "one", "two", "three", "four", "five", "six", "seven", "eight", 
index 448ccfcb9c1e4cdb50822b15d51202072a5725b3..33a964307e11a53305723c4f8a4aac678f284eaf 100644 (file)
@@ -29,6 +29,7 @@ Top {
   bitmap1:remove 3 3
   bitmap2:all
   bitmap2:remove eleven twelve one
+  intmax 1000000000
 };;;;;;
 
 unknown.ignored :-)
index 11026b7a6fdf7d0bffde4468412e485ee11a12a8..3de2938deed1ffa0f37ab706a6201d23243d1049 100644 (file)
@@ -3,6 +3,7 @@
  *
  *     (c) 2001--2006 Robert Spalek <robert@ucw.cz>
  *     (c) 2003--2014 Martin Mares <mj@ucw.cz>
+ *     (c) 2014 Pavel Charvat <pchar@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
@@ -155,7 +156,8 @@ enum cf_type {                              /** Type of a single value. **/
   CT_IP,                               // IP address
   CT_STRING,                           // string type
   CT_LOOKUP,                           // in a string table
-  CT_USER                              // user-defined type
+  CT_USER,                             // user-defined type (obsolete)
+  CT_XTYPE                             // extended type
 };
 
 struct fastbuf;
@@ -212,7 +214,8 @@ struct cf_item {                    /** Single configuration item. **/
     struct cf_section *sec;            // declaration of a section or a list
     cf_parser *par;                    // parser function
     const char * const *lookup;                // NULL-terminated sequence of allowed strings for lookups
-    struct cf_user_type *utype;                // specification of the user-defined type
+    struct cf_user_type *utype;                // specification of the user-defined type (obsolete)
+    const struct xtype *xtype;         // specification of the extended type
   } u;
   enum cf_class cls:16;                        // attribute class
   enum cf_type type:16;                        // type of a static or dynamic attribute
@@ -424,6 +427,21 @@ struct cf_section {                        /** A section. **/
  * See <<custom_parser,creating custom parsers>> section.
  **/
 #define CF_USER_DYN(n,p,t,c)   { .cls = CC_DYNAMIC, .type = CT_USER, .name = n, .number = c, .ptr = p, .u.utype = t }
+/**
+ * An extended type.
+ * See <<xtypes:,extended types>> if you want to know more.
+ **/
+#define CF_XTYPE(n,p,t)                { .cls = CC_STATIC, .type = CT_XTYPE, .name = n, .number = 1, .ptr = p, .u.xtype = &t }
+/**
+ * Static array of extended types (all of the same type).
+ * See <<xtypes:,extended types>>.
+ **/
+#define CF_XTYPE_ARY(n,p,t,c)  { .cls = CC_STATIC, .type = CT_XTYPE, .name = n, .number = c, .ptr = p, .u.xtype = &t }
+/**
+ * Dynamic array of extended types.
+ * See <<xtypes:,extended types>>.
+ **/
+#define CF_XTYPE_DYN(n,p,t,c)  { .cls = CC_DYNAMIC, .type = CT_XTYPE, .name = n, .number = c, .ptr = p, .u.xtype = &t }
 
 /**
  * Any number of dynamic array elements
index 777dbe10facca83e30255028803bca7296a2a71b..813a18358365c893b3885fc3fc611b4a0e0d3e3d 100644 (file)
@@ -219,8 +219,11 @@ Creating custom parsers
 ~~~~~~~~~~~~~~~~~~~~~~~
 
 If you need to parse some data type the configuration system can't
-handle, you can write your own parser. But before you start, you
-should know a few things.
+handle, you can write your own <<xtypes:,extended type>>
+and use <<def_CF_XTYPE,`CF_XTYPE`>> macro to declare a new option.
+
+There is also an obsolete way to write a custom parser.
+Before you start, you should know a few things.
 
 The parser needs to support <<journal,journalling>>. To accomplish that,
 you have to use the <<alloc,configuration mempool>> for memory allocation.
index 610ce1ef01976b691fc108b4d95617a5dc7f1ddd..e920d64af3111dc620e1a0f6b3d080255c438617 100644 (file)
@@ -65,8 +65,9 @@ Most options have the following properties:
 - Long name: an arbitrary string. Set to NULL if the option has no long form.
 - Variable, where the value of the option shall be stored, together with
   its <<conf:enum_cf_type,data type>>. The type is either one of the conventional
-  types (`int`, `uint`, etc.), or a user-defined type providing its own parser
-  function via <<conf:struct_cf_user_type,`cf_user_type`>>.
+  types (`int`, `uint`, etc.), an extended type providing its own parser
+  function via <<xtypes:struct_xtype,`xtype`>>, or an obsolete user-type
+  defined by <<conf:struct_cf_user_type,`cf_user_type`>>.
 - <<flags,Flags>> further specifying behavior of the option (whether it is mandatory,
   whether it carries a value, whether it can be set repeatedly, etc.).
 - Help text, from which the help displayed to the user is constructed.
index 713ee784d3f384bbc501553f8d4ab74781ea75ac..d082d03b9e4e11f3c1f0d0f2285ce49cace614de 100644 (file)
--- a/ucw/opt.c
+++ b/ucw/opt.c
@@ -3,6 +3,7 @@
  *
  *     (c) 2013 Jan Moskyto Matejka <mq@ucw.cz>
  *     (c) 2014 Martin Mares <mj@ucw.cz>
+ *     (c) 2014 Pavel Charvat <pchar@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
@@ -201,6 +202,13 @@ static void opt_parse_value(struct opt_context * oc, struct opt_precomputed * op
                  opt_failure("Cannot parse the value of %s: %s", THIS_OPT, e);
                break;
              }
+         case CT_XTYPE:
+             {
+               const char * e = item->u.xtype->parse(value, ptr, cf_get_pool());
+               if (e)
+                 opt_failure("Cannot parse the value of %s: %s", THIS_OPT, e);
+               break;
+             }
          default:
            ASSERT(0);
        }
index 20df7fd7b340d5277c4e34ed175d2b39988c8b36..c8c683c03cb70775137fd20185f3c00a604e5f4f 100644 (file)
--- a/ucw/opt.h
+++ b/ucw/opt.h
@@ -14,6 +14,7 @@
 
 #include <ucw/lib.h>
 #include <ucw/conf.h>
+#include <ucw/xtypes.h>
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -110,6 +111,7 @@ struct opt_item {
     void (* call)(const struct opt_item * opt, const char * value, void * data);               // function to call for OPT_CL_CALL
     void (* hook)(const struct opt_item * opt, uint event, const char * value, void * data);   // function to call for OPT_CL_HOOK
     struct cf_user_type * utype;       // specification of the user-defined type for CT_USER
+    const struct xtype * xtype;                // specification of the extended type for CT_XTYPE
   } u;
   u16 flags;                           // as defined below (for hooks, event mask is stored instead)
   byte cls;                            // enum opt_class
@@ -239,6 +241,16 @@ struct opt_item {
 /** Multi-valued option of user-defined type. @target should be a growing array of the right kind of items. **/
 #define OPT_USER_MULTIPLE(shortopt, longopt, target, ttype, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .u.utype = &ttype, .flags = fl, .help = desc, .cls = OPT_CL_MULTIPLE, .type = CT_USER }
 
+/**
+ * An option with user-defined syntax. @xtype is a <<xtypes:struct_xtype,`xtype`>>
+ * describing the syntax, @target is a variable of the corresponding type. If the @OPT_REQUIRED_VALUE
+ * flag is not set, the parser must be able to parse a NULL value.
+ **/
+#define OPT_XTYPE(shortopt, longopt, target, ttype, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .u.xtype = &ttype, .flags = fl, .help = desc, .cls = OPT_CL_STATIC, .type = CT_XTYPE }
+
+/** Multi-valued option of extended type. @target should be a growing array of the right kind of items. **/
+#define OPT_XTYPE_MULTIPLE(shortopt, longopt, target, ttype, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .u.xtype = &ttype, .flags = fl, .help = desc, .cls = OPT_CL_MULTIPLE, .type = CT_XTYPE }
+
 /** A sub-section. **/
 #define OPT_SECTION(sec) { .cls = OPT_CL_SECTION, .u.section = &sec }