]> mj.ucw.cz Git - libucw.git/commitdiff
designed the interface of the new configuration reader. no code has been
authorRobert Spalek <robert@ucw.cz>
Mon, 17 Apr 2006 18:15:39 +0000 (20:15 +0200)
committerRobert Spalek <robert@ucw.cz>
Mon, 17 Apr 2006 18:15:39 +0000 (20:15 +0200)
written yet, because I better wait for an opinion first.  a tester app that
currently just checks compilability of all messy cf-declaration macros is
included.  don't worry about filenames; they will be eventually renamed.

lib/Makefile
lib/conf2-test.c [new file with mode: 0644]
lib/conf2.h [new file with mode: 0644]

index 35b865a1a70ed4a82191684d8038fcf3c646b0c0..757d2149f6de0eba440260589caedbf5050eaaef 100644 (file)
@@ -6,6 +6,9 @@ ifdef CONFIG_UCW_DBTOOL
 PROGS+=$(o)/lib/db-tool
 endif
 
+# hey dude, I'm Robert!
+PROGS+=$(o)/lib/conf2-test
+
 LIBUCW_MODS= \
        alloc alloc_str realloc mempool mempool-str mempool-fmt \
        mmap pagecache partmap hashfunc \
@@ -67,6 +70,7 @@ $(o)/lib/lizard.o: CFLAGS += $(COPT2) -funroll-loops
 $(o)/lib/db-test: $(o)/lib/db-test.o $(LIBUCW)
 $(o)/lib/db-tool: $(o)/lib/db-tool.o $(LIBUCW)
 $(o)/lib/conf-test: $(o)/lib/conf-test.o $(LIBUCW)
+$(o)/lib/conf2-test: $(o)/lib/conf2-test.o $(LIBUCW)
 $(o)/lib/sort-test: $(o)/lib/sort-test.o $(LIBUCW)
 $(o)/lib/lfs-test: $(o)/lib/lfs-test.o $(LIBUCW)
 $(o)/lib/hash-test: $(o)/lib/hash-test.o $(LIBUCW)
diff --git a/lib/conf2-test.c b/lib/conf2-test.c
new file mode 100644 (file)
index 0000000..540ffed
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ *     Insane tester of reading configuration files
+ *
+ *     (c) 2006 Robert Spalek <robert@ucw.cz>
+ */
+
+#include "lib/lib.h"
+#include "lib/conf2.h"
+#include "lib/clists.h"
+
+#include <stdlib.h>
+#include <time.h>
+
+struct sub_sect_1 {
+  byte *name;
+  byte *level;
+  int confidence;
+};
+
+static byte *
+init_sec_1(void *ptr, struct cf_section *sec UNUSED)
+{
+  struct sub_sect_1 *s = ptr;
+  s->name = "unknown";
+  s->level = "default";
+  s->confidence = 5;
+  return NULL;
+}
+
+static byte *
+commit_sec_1(void *ptr, struct cf_section *sec UNUSED)
+{
+  struct sub_sect_1 *s = ptr;
+  if (s->confidence < 0 || s->confidence > 10)
+    return "Well, this can't be";
+  return NULL;
+}
+
+static struct cf_section cf_sec_1 = {
+  .size = sizeof(struct sub_sect_1),
+  .init = init_sec_1,
+  .commit = commit_sec_1,
+  .cfg = (struct cf_item[]) {
+#define F(x)   CF_FIELD(struct sub_sect_1, x)
+    CF_STRING("name", F(name)),
+    CF_STRING("level", F(level)),
+    CF_INT("confidence", F(confidence)),
+    CF_END
+#undef F
+  }
+};
+
+static int nr1 = 15;
+static int *nrs1 = DEFAULT_ARRAY(int, 5, 5, 4, 3, 2, 1);
+static int *nrs2;
+static byte *str1 = "no worries";
+static byte **str2 = DEFAULT_ARRAY(byte *, 2, "Alice", "Bob");
+static u64 u1 = 0xCafeBeefDeadC00ll;
+static double d1 = -1.1;
+static struct sub_sect_1 sec_1 = { "Charlie", "WBAFC", 0 };
+static struct cnode secs;
+static time_t t1, t2;
+
+static byte *
+commit_top(void *ptr UNUSED, struct cf_section *sec UNUSED)
+{
+  return NULL;
+}
+
+static byte *
+time_parser(uns nr_pars, byte **pars, void *sec_ptr, struct cf_section *sec, uns index)
+{
+  if (nr_pars != 0 && nr_pars != 1)
+    return "Either now or 1 parameter!";
+  ASSERT(!sec_ptr);
+  time_t t = nr_pars ? atoi(pars[0]) : time(NULL);
+  if (sec->cfg[index].name[0] == 'F')
+    t1 = t;
+  else
+    t2 = t;
+  return NULL;
+}
+
+static struct cf_section cf_top = {
+  .commit = commit_top,
+  .cfg = (struct cf_item []) {
+    CF_INT("nr1", &nr1),
+    CF_INT_AR("nrs1", &nrs1, 5),
+    CF_INT_AR("nrs2", &nrs2, -1000),
+    CF_STRING("str1", &str1),
+    CF_STRING_AR("str2", &str2, 2),
+    CF_U64("u1", &u1),
+    CF_DOUBLE("d1", &d1),
+    CF_FUNCTION("FirstTime", time_parser),
+    CF_FUNCTION("SecondTime", time_parser),
+    CF_SUB_SECTION("master", &sec_1, &cf_sec_1),
+    CF_LINK_LIST("slaves", &secs, &cf_sec_1),
+    CF_END
+  }
+};
+
+int
+main(void)
+{
+  return 0;
+}
diff --git a/lib/conf2.h b/lib/conf2.h
new file mode 100644 (file)
index 0000000..dfb024d
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ *     UCW Library -- Reading of configuration files
+ *
+ *     (c) 2006 Robert Spalek <robert@ucw.cz>
+ *
+ *     This software may be freely distributed and used according to the terms
+ *     of the GNU Lesser General Public License.
+ */
+
+#ifndef        _LIB_CONF2_H
+#define        _LIB_CONF2_H
+
+enum cf_type {
+  CT_END,                              // end of list
+  CT_INT, CT_U64, CT_DOUBLE,           // number types
+  CT_STRING,                           // string type
+  CT_FUNCTION,                         // arbitrary parser function
+  CT_SUB_SECTION,                      // sub-section appears exactly once
+  CT_LINK_LIST                         // link-list with 0..many nodes
+};
+
+struct cf_section;
+typedef byte *cf_hook(void *sec_ptr, struct cf_section *sec);
+  /* An init- or commit-hook gets a pointer to the sub-section or NULL if this
+   * is the global section, and a declaration of the section it is called on.
+   * It returns an error message or NULL if everything is all right.  */
+typedef byte *cf_parser(uns nr_pars, byte **pars, void *sec_ptr, struct cf_section *sec, uns index);
+  /* A parser function gets an array of strings and stores it in any way it
+   * likes into its own data structures.  It gets a pointer to the sub-section
+   * or NULL if this is the global section, a declaration of the section it is
+   * called in, and the index of the item it is called on.  It returns an error
+   * message or NULL if everything is all right.  */
+
+struct cf_item {
+  enum cf_type type;
+  byte *name;
+  int number;                          // number of values: k>0 means exactly k, k<0 means at most k
+  void *ptr;                           // pointer to a global variable or an offset in a sub-section
+  struct cf_section *sub;              // declaration of a sub-section or link-list
+};
+
+struct cf_section {
+  uns size;                            // 0 for a global block, sizeof(struct) for a sub-section
+  cf_hook *init;                       // fills in default values
+  cf_hook *commit;                     // verifies parsed data and checks ranges (optional)
+  struct cf_item *cfg;                 // CT_END-terminated array of items
+};
+
+#define CHECK_VAR_TYPE(x,type) ((x)-(type)0 + (type)0)
+  // for a pointer x it returns x, and performs a compile-time check whether typeof(x)==type
+#define DEFAULT_ARRAY(type,len,val...) (type[]) { (type)len, ##val } + 1
+  // creates an array with an allocated space in the front for the (Pascal-like) length
+#define CF_FIELD(str,f)        &((str*)0)->f
+  // returns a pointer to a field inside a structure suitable for passing as cf_item->ptr
+
+#define CF_END         { .type = CT_END }
+  // please better put this at the end of each section
+#define CF_INT(n,p)    { .type = CT_INT, .name = n, .number = 1, .ptr = CHECK_VAR_TYPE(p,int*) }
+#define CF_U64(n,p)    { .type = CT_U64, .name = n, .number = 1, .ptr = CHECK_VAR_TYPE(p,u64*) }
+#define CF_DOUBLE(n,p) { .type = CT_DOUBLE, .name = n, .number = 1, .ptr = CHECK_VAR_TYPE(p,double*) }
+#define CF_STRING(n,p) { .type = CT_STRING, .name = n, .number = 1, .ptr = CHECK_VAR_TYPE(p,byte**) }
+#define CF_FUNCTION(n,p)       { .type = CT_FUNCTION, .name = n, .number = 1, .ptr = CHECK_VAR_TYPE(p,cf_parser*) }
+#define CF_SUB_SECTION(n,p,s)  { .type = CT_SUB_SECTION, .name = n, .number = 1, .ptr = p, .sub = s }
+#define CF_LINK_LIST(n,p,s)    { .type = CT_LINK_LIST, .name = n, .number = 1, .ptr = CHECK_VAR_TYPE(p,struct cnode*), .sub = s }
+  // use the macros above to declare configuration items for single variables
+#define CF_INT_AR(n,p,c)       { .type = CT_INT, .name = n, .number = c, .ptr = CHECK_VAR_TYPE(p,int**) }
+#define CF_U64_AR(n,p,c)       { .type = CT_U64, .name = n, .number = c, .ptr = CHECK_VAR_TYPE(p,u64**) }
+#define CF_DOUBLE_AR(n,p,c)    { .type = CT_DOUBLE, .name = n, .number = c, .ptr = CHECK_VAR_TYPE(p,double**) }
+#define CF_STRING_AR(n,p,c)    { .type = CT_STRING, .name = n, .number = c, .ptr = CHECK_VAR_TYPE(p,byte***) }
+  // use the macros above to declare configuration items for arrays of variables
+
+#endif