From: Robert Spalek Date: Thu, 27 Apr 2006 23:31:57 +0000 (+0200) Subject: split conf2.h into conf.h and getopt.h X-Git-Tag: holmes-import~645^2~11^2~13 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=a86e328ab75068b1c27e17e3fb33a9b5845f63aa;p=libucw.git split conf2.h into conf.h and getopt.h --- diff --git a/lib/Makefile b/lib/Makefile index 846d320b..f163c34d 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -39,7 +39,7 @@ LIBUCW_INCLUDES= \ hashfunc.h hashtable.h \ heap.h binheap.h binheap-node.h \ redblack.h \ - conf2.h ipaccess.h \ + conf.h getopt.h ipaccess.h \ profile.h \ fastbuf.h lfs.h ff-utf8.h \ chartype.h unicode.h stkstring.h \ @@ -67,7 +67,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/conf2-test: $(o)/lib/conf2-test.o $(LIBUCW) +$(o)/lib/conf-test: $(o)/lib/conf-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/conf-test.c b/lib/conf-test.c new file mode 100644 index 00000000..458689de --- /dev/null +++ b/lib/conf-test.c @@ -0,0 +1,213 @@ +/* + * Insane tester of reading configuration files + * + * (c) 2006 Robert Spalek + */ + +#include "lib/lib.h" +#include "lib/conf.h" +#include "lib/getopt.h" +#include "lib/clists.h" +#include "lib/fastbuf.h" + +#include +#include +#include + +static int verbose; + +struct sub_sect_1 { + cnode n; + byte *name; + time_t t; + byte *level; + int confidence[2]; + double *list; +}; + +static struct sub_sect_1 sec1 = { {}, "Charlie", 0, "WBAFC", { 0, -1}, DARY_ALLOC(double, 3, 1e4, -1e-4, 8) }; + +static byte * +init_sec_1(struct sub_sect_1 *s) +{ + if (s == &sec1) { // this is a static variable; skip clearing + DARY_LEN(sec1.list) = 3; // XXX: fix for the bug in DARY_ALLOC() + return NULL; + } + s->name = "unknown"; + s->level = "default"; + s->confidence[0] = 5; + s->confidence[1] = 6; + // leave s->list==NULL + return NULL; +} + +static byte * +commit_sec_1(struct sub_sect_1 *s) +{ + if (s->confidence[0] < 0 || s->confidence[0] > 10) + return "Well, this can't be"; + return NULL; +} + +static byte * +time_parser(uns number, byte **pars, time_t *ptr) +{ + *ptr = number ? atoi(pars[0]) : time(NULL); + return NULL; +} + +static struct cf_section cf_sec_1 = { + CF_TYPE(struct sub_sect_1), + CF_INIT(init_sec_1), + CF_COMMIT(commit_sec_1), +#define F(x) PTR_TO(struct sub_sect_1, x) + CF_ITEMS { + CF_STRING("name", F(name)), + //CF_PARSER("t", F(t), time_parser, 0), + CF_STRING("level", F(level)), + CF_INT_ARY("confidence", F(confidence[0]), 2), // XXX: the [0] is needed for the sake of type checking + CF_DOUBLE_DYN("list", F(list), 100), + CF_END + } +#undef F +}; + +static uns nr1 = 15; +static int *nrs1 = DARY_ALLOC(int, 5, 5, 4, 3, 2, 1); +static int nrs2[5]; +static byte *str1 = "no worries"; +static byte **str2 = DARY_ALLOC(byte *, 2, "Alice", "Bob"); +static u64 u1 = 0xCafeBeefDeadC00ll; +static double d1 = -1.1; +static clist secs; +static time_t t1, t2; +static u32 ip; +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), + .name = "u16", + .parser = (cf_parser1*) parse_u16, + .dumper = (cf_dumper1*) dump_u16 +}; + +static byte * +init_top(void *ptr UNUSED) +{ + for (uns i=0; i<5; i++) + { + struct sub_sect_1 *s = xmalloc(sizeof(struct sub_sect_1)); // XXX: cannot by cf_malloc(), because it's deleted when cf_reload()'ed + cf_init_section("slaves", &cf_sec_1, s, 1); + s->confidence[1] = i; + clist_add_tail(&secs, &s->n); + } + return NULL; +} + +static byte * +commit_top(void *ptr UNUSED) +{ + if (nr1 != 15) + return "Don't touch my variable!"; + return NULL; +} + +static byte *alphabet[] = { "alpha", "beta", "gamma", "delta", NULL }; +static struct cf_section cf_top = { + CF_INIT(init_top), + CF_COMMIT(commit_top), + CF_ITEMS { + CF_UNS("nr1", &nr1), + CF_INT_DYN("nrs1", &nrs1, 1000), + CF_INT_ARY("nrs2", nrs2, 5), + CF_STRING("str1", &str1), + CF_STRING_DYN("str2", &str2, 20), + CF_U64("u1", &u1), + CF_DOUBLE("d1", &d1), + CF_PARSER("FirstTime", &t1, time_parser, -1), + CF_PARSER("SecondTime", &t2, time_parser, 1), + CF_SECTION("master", &sec1, &cf_sec_1), + CF_LIST("slaves", &secs, &cf_sec_1), + CF_IP("ip", &ip), + CF_LOOKUP_DYN("look", &look, alphabet, 1000), + CF_USER_ARY("numbers", numbers, &u16_type, 10), + CF_END + } +}; + +static byte short_opts[] = CF_SHORT_OPTS "v"; +static struct option long_opts[] = { + CF_LONG_OPTS + {"verbose", 0, 0, 'v'}, + {NULL, 0, 0, 0} +}; + +static char *help = "\ +Usage: conf2-test \n\ +\n\ +Options:\n" +CF_USAGE +"-v\t\t\tBe verbose\n\ +"; + +static void NONRET +usage(byte *msg, ...) +{ + va_list va; + va_start(va, msg); + if (msg) + vfprintf(stderr, msg, va); + fputs(help, stderr); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + log_init(argv[0]); + cf_declare_section("top", &cf_top, 0); + cf_def_file = "lib/conf2.t"; + + int opt; + while ((opt = cf_getopt(argc, argv, short_opts, long_opts, NULL)) >= 0) + switch (opt) { + case 'v': verbose++; break; + default: usage("unknown option %c\n", opt); + } + if (optind < argc) + usage("too many parameters (%d more)\n", argc-optind); + + /* + cf_load("non-existent file"); + //cf_reload("non-existent file"); + cf_load("non-existent file"); + cf_set("top.d1 -1.1; top.master b"); + */ + + struct fastbuf *out = bfdopen(1, 1<<14); + cf_dump_sections(out); + bclose(out); + + return 0; +} diff --git a/lib/conf.h b/lib/conf.h new file mode 100644 index 00000000..033b7590 --- /dev/null +++ b/lib/conf.h @@ -0,0 +1,167 @@ +/* + * UCW Library -- Reading of configuration files + * + * (c) 2001--2006 Robert Spalek + * (c) 2003--2006 Martin Mares + * + * This software may be freely distributed and used according to the terms + * of the GNU Lesser General Public License. + */ + +#ifndef _UCW_CONF_H +#define _UCW_CONF_H + +enum cf_class { + CC_END, // end of list + CC_STATIC, // single variable or static array + CC_DYNAMIC, // dynamically allocated array + CC_PARSER, // arbitrary parser function + CC_SECTION, // section appears exactly once + CC_LIST // list with 0..many nodes +}; + +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_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 gets a string and a pointer to + * the destination variable. It must store the value within [ptr,ptr+size), + * where size is fixed for each type. It should not 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 + * is all right. The init-hook should fill in default values (needed for + * dynamically allocated nodes of link lists or for filling global variables + * that are run-time dependent). The commit-hook should perform sanity + * 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. */ +typedef byte *cf_copier(void *dest, void *src); + /* Similar to init-hook, but it copies attributes from another list node + * instead of setting the attributes to default values. You have to provide + * it if your node contains parsed values and/or sub-lists. */ + +struct cf_user_type { + uns size; // of the parsed attribute + byte *name; // name of the type (for dumping) + cf_parser1 *parser; // how to parse it + cf_dumper1 *dumper; // how to dump the type +}; + +struct cf_section; +struct cf_item { + byte *name; // case insensitive + int number; // length of an array or #parameters of a parser (negative means at most) + void *ptr; // pointer to a global variable or an offset in a section + union cf_union { + struct cf_section *sec; // declaration of a section or a list + cf_parser *par; // parser function + byte **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 +}; + +struct cf_section { + uns size; // 0 for a global block, sizeof(struct) for a section + cf_hook *init; // fills in default values (no need to bzero) + cf_hook *commit; // verifies parsed data (optional) + cf_copier *copy; // copies values from another instance (optional, no need to copy basic attributes) + struct cf_item *cfg; // CC_END-terminated array of items + uns flags; // for internal use only +}; + +/* Declaration of cf_section */ +#define CF_TYPE(s) .size = sizeof(s) +#define CF_INIT(f) .init = (cf_hook*) f +#define CF_COMMIT(f) .commit = (cf_hook*) f +#define CF_COPY(f) .copy = (cf_copier*) f +#define CF_ITEMS .cfg = ( struct cf_item[] ) +#define CF_END { .cls = CC_END } +/* Configuration items */ +#define CF_STATIC(n,p,T,t,c) { .cls = CC_STATIC, .type = CT_##T, .name = n, .number = c, .ptr = CHECK_PTR_TYPE(p,t*) } +#define CF_DYNAMIC(n,p,T,t,c) { .cls = CC_DYNAMIC, .type = CT_##T, .name = n, .number = c, .ptr = CHECK_PTR_TYPE(p,t**) } +#define CF_PARSER(n,p,f,c) { .cls = CC_PARSER, .name = n, .number = c, .ptr = p, .u.par = (cf_parser*) f } +#define CF_SECTION(n,p,s) { .cls = CC_SECTION, .name = n, .number = 1, .ptr = p, .u.sec = s } +#define CF_LIST(n,p,s) { .cls = CC_LIST, .name = n, .number = 1, .ptr = CHECK_PTR_TYPE(p,clist*), .u.sec = s } +/* Configuration items for basic types */ +#define CF_INT(n,p) CF_STATIC(n,p,INT,int,1) +#define CF_INT_ARY(n,p,c) CF_STATIC(n,p,INT,int,c) +#define CF_INT_DYN(n,p,c) CF_DYNAMIC(n,p,INT,int,c) +#define CF_UNS(n,p) CF_STATIC(n,p,INT,uns,1) +#define CF_UNS_ARY(n,p,c) CF_STATIC(n,p,INT,uns,c) +#define CF_UNS_DYN(n,p,c) CF_DYNAMIC(n,p,INT,uns,c) +#define CF_U64(n,p) CF_STATIC(n,p,U64,u64,1) +#define CF_U64_ARY(n,p,c) CF_STATIC(n,p,U64,u64,c) +#define CF_U64_DYN(n,p,c) CF_DYNAMIC(n,p,U64,u64,c) +#define CF_DOUBLE(n,p) CF_STATIC(n,p,DOUBLE,double,1) +#define CF_DOUBLE_ARY(n,p,c) CF_STATIC(n,p,DOUBLE,double,c) +#define CF_DOUBLE_DYN(n,p,c) CF_DYNAMIC(n,p,DOUBLE,double,c) +#define CF_IP(n,p) CF_STATIC(n,p,IP,u32,1) +#define CF_IP_ARY(n,p,c) CF_STATIC(n,p,IP,u32,c) +#define CF_IP_DYN(n,p,c) CF_DYNAMIC(n,p,IP,u32,c) +#define CF_STRING(n,p) CF_STATIC(n,p,STRING,byte*,1) +#define CF_STRING_ARY(n,p,c) CF_STATIC(n,p,STRING,byte*,c) +#define CF_STRING_DYN(n,p,c) CF_DYNAMIC(n,p,STRING,byte*,c) +#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 + +#define DARY_LEN(a) *(uns*)(a-1) + // length of a dynamic array +#define DARY_ALLOC(type,len,val...) (type[]) { (type)len, ##val } + 1 + // creates a static instance of a dynamic array + // FIXME: overcast doesn't work for the double type + +/* Memory allocation */ +struct mempool; +extern struct mempool *cf_pool; +void *cf_malloc(uns size); +void *cf_malloc_zero(uns size); +byte *cf_strdup(byte *s); +byte *cf_printf(char *fmt, ...) FORMAT_CHECK(printf,1,2); + +/* Undo journal for error recovery */ +extern uns cf_need_journal; +void cf_journal_block(void *ptr, uns len); +#define CF_JOURNAL_VAR(var) cf_journal_block(&(var), sizeof(var)) + +struct cf_journal_item; +struct cf_journal_item *cf_journal_new_transaction(uns new_pool); +void cf_journal_commit_transaction(uns new_pool, struct cf_journal_item *oldj); +void cf_journal_rollback_transaction(uns new_pool, struct cf_journal_item *oldj); + +/* Declaration */ +void cf_declare_section(byte *name, struct cf_section *sec, uns allow_unknown); +void cf_init_section(byte *name, struct cf_section *sec, void *ptr, uns do_bzero); + +/* Parsers for basic types */ +byte *cf_parse_int(byte *str, int *ptr); +byte *cf_parse_u64(byte *str, u64 *ptr); +byte *cf_parse_double(byte *str, double *ptr); +byte *cf_parse_ip(byte *p, u32 *varp); + +#endif + diff --git a/lib/conf2-test.c b/lib/conf2-test.c deleted file mode 100644 index daf24e7b..00000000 --- a/lib/conf2-test.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Insane tester of reading configuration files - * - * (c) 2006 Robert Spalek - */ - -#include "lib/lib.h" -#include "lib/conf2.h" -#include "lib/clists.h" -#include "lib/fastbuf.h" - -#include -#include -#include -#include - -static int verbose; - -struct sub_sect_1 { - cnode n; - byte *name; - time_t t; - byte *level; - int confidence[2]; - double *list; -}; - -static struct sub_sect_1 sec1 = { {}, "Charlie", 0, "WBAFC", { 0, -1}, DARY_ALLOC(double, 3, 1e4, -1e-4, 8) }; - -static byte * -init_sec_1(struct sub_sect_1 *s) -{ - if (s == &sec1) { // this is a static variable; skip clearing - DARY_LEN(sec1.list) = 3; // XXX: fix for the bug in DARY_ALLOC() - return NULL; - } - s->name = "unknown"; - s->level = "default"; - s->confidence[0] = 5; - s->confidence[1] = 6; - // leave s->list==NULL - return NULL; -} - -static byte * -commit_sec_1(struct sub_sect_1 *s) -{ - if (s->confidence[0] < 0 || s->confidence[0] > 10) - return "Well, this can't be"; - return NULL; -} - -static byte * -time_parser(uns number, byte **pars, time_t *ptr) -{ - *ptr = number ? atoi(pars[0]) : time(NULL); - return NULL; -} - -static struct cf_section cf_sec_1 = { - CF_TYPE(struct sub_sect_1), - CF_INIT(init_sec_1), - CF_COMMIT(commit_sec_1), -#define F(x) PTR_TO(struct sub_sect_1, x) - CF_ITEMS { - CF_STRING("name", F(name)), - //CF_PARSER("t", F(t), time_parser, 0), - CF_STRING("level", F(level)), - CF_INT_ARY("confidence", F(confidence[0]), 2), // XXX: the [0] is needed for the sake of type checking - CF_DOUBLE_DYN("list", F(list), 100), - CF_END - } -#undef F -}; - -static uns nr1 = 15; -static int *nrs1 = DARY_ALLOC(int, 5, 5, 4, 3, 2, 1); -static int nrs2[5]; -static byte *str1 = "no worries"; -static byte **str2 = DARY_ALLOC(byte *, 2, "Alice", "Bob"); -static u64 u1 = 0xCafeBeefDeadC00ll; -static double d1 = -1.1; -static clist secs; -static time_t t1, t2; -static u32 ip; -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), - .name = "u16", - .parser = (cf_parser1*) parse_u16, - .dumper = (cf_dumper1*) dump_u16 -}; - -static byte * -init_top(void *ptr UNUSED) -{ - for (uns i=0; i<5; i++) - { - struct sub_sect_1 *s = xmalloc(sizeof(struct sub_sect_1)); // XXX: cannot by cf_malloc(), because it's deleted when cf_reload()'ed - cf_init_section("slaves", &cf_sec_1, s, 1); - s->confidence[1] = i; - clist_add_tail(&secs, &s->n); - } - return NULL; -} - -static byte * -commit_top(void *ptr UNUSED) -{ - if (nr1 != 15) - return "Don't touch my variable!"; - return NULL; -} - -static byte *alphabet[] = { "alpha", "beta", "gamma", "delta", NULL }; -static struct cf_section cf_top = { - CF_INIT(init_top), - CF_COMMIT(commit_top), - CF_ITEMS { - CF_UNS("nr1", &nr1), - CF_INT_DYN("nrs1", &nrs1, 1000), - CF_INT_ARY("nrs2", nrs2, 5), - CF_STRING("str1", &str1), - CF_STRING_DYN("str2", &str2, 20), - CF_U64("u1", &u1), - CF_DOUBLE("d1", &d1), - CF_PARSER("FirstTime", &t1, time_parser, -1), - CF_PARSER("SecondTime", &t2, time_parser, 1), - CF_SECTION("master", &sec1, &cf_sec_1), - CF_LIST("slaves", &secs, &cf_sec_1), - CF_IP("ip", &ip), - CF_LOOKUP_DYN("look", &look, alphabet, 1000), - CF_USER_ARY("numbers", numbers, &u16_type, 10), - CF_END - } -}; - -static byte short_opts[] = CF_SHORT_OPTS "v"; -static struct option long_opts[] = { - CF_LONG_OPTS - {"verbose", 0, 0, 'v'}, - {NULL, 0, 0, 0} -}; - -static char *help = "\ -Usage: conf2-test \n\ -\n\ -Options:\n" -CF_USAGE -"-v\t\t\tBe verbose\n\ -"; - -static void NONRET -usage(byte *msg, ...) -{ - va_list va; - va_start(va, msg); - if (msg) - vfprintf(stderr, msg, va); - fputs(help, stderr); - exit(1); -} - -int -main(int argc, char *argv[]) -{ - log_init(argv[0]); - cf_declare_section("top", &cf_top, 0); - cf_def_file = "lib/conf2.t"; - - int opt; - while ((opt = cf_get_opt(argc, argv, short_opts, long_opts, NULL)) >= 0) - switch (opt) { - case 'v': verbose++; break; - default: usage("unknown option %c\n", opt); - } - if (optind < argc) - usage("too many parameters (%d more)\n", argc-optind); - - /* - cf_load("non-existent file"); - //cf_reload("non-existent file"); - cf_load("non-existent file"); - cf_set("top.d1 -1.1; top.master b"); - */ - - struct fastbuf *out = bfdopen(1, 1<<14); - cf_dump_sections(out); - bclose(out); - - return 0; -} diff --git a/lib/conf2.c b/lib/conf2.c index dad7399e..55118203 100644 --- a/lib/conf2.c +++ b/lib/conf2.c @@ -9,7 +9,8 @@ */ #include "lib/lib.h" -#include "lib/conf2.h" +#include "lib/conf.h" +#include "lib/getopt.h" #include "lib/mempool.h" #include "lib/clists.h" #include "lib/fastbuf.h" @@ -23,7 +24,6 @@ #include #include #include -#include #define TRY(f) do { byte *_msg = f; if (_msg) return _msg; } while (0) @@ -1085,7 +1085,7 @@ init_stack(void) }; } -static uns postpone_commit; // only for cf_get_opt() +static uns postpone_commit; // only for cf_getopt() static int done_stack(void) @@ -1403,7 +1403,7 @@ load_default(void) } int -cf_get_opt(int argc, char * const argv[], const char *short_opts, const struct option *long_opts, int *long_index) +cf_getopt(int argc, char * const argv[], const char *short_opts, const struct option *long_opts, int *long_index) { static int other_options = 0; while (1) { diff --git a/lib/conf2.h b/lib/conf2.h deleted file mode 100644 index 399ad005..00000000 --- a/lib/conf2.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * UCW Library -- Reading of configuration files - * - * (c) 2001--2006 Robert Spalek - * (c) 2003--2006 Martin Mares - * - * This software may be freely distributed and used according to the terms - * of the GNU Lesser General Public License. - */ - -#ifndef _UCW_CONF2_H -#define _UCW_CONF2_H - -enum cf_class { - CC_END, // end of list - CC_STATIC, // single variable or static array - CC_DYNAMIC, // dynamically allocated array - CC_PARSER, // arbitrary parser function - CC_SECTION, // section appears exactly once - CC_LIST // list with 0..many nodes -}; - -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_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 gets a string and a pointer to - * the destination variable. It must store the value within [ptr,ptr+size), - * where size is fixed for each type. It should not 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 - * is all right. The init-hook should fill in default values (needed for - * dynamically allocated nodes of link lists or for filling global variables - * that are run-time dependent). The commit-hook should perform sanity - * 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. */ -typedef byte *cf_copier(void *dest, void *src); - /* Similar to init-hook, but it copies attributes from another list node - * instead of setting the attributes to default values. You have to provide - * it if your node contains parsed values and/or sub-lists. */ - -struct cf_user_type { - uns size; // of the parsed attribute - byte *name; // name of the type (for dumping) - cf_parser1 *parser; // how to parse it - cf_dumper1 *dumper; // how to dump the type -}; - -struct cf_section; -struct cf_item { - byte *name; // case insensitive - int number; // length of an array or #parameters of a parser (negative means at most) - void *ptr; // pointer to a global variable or an offset in a section - union cf_union { - struct cf_section *sec; // declaration of a section or a list - cf_parser *par; // parser function - byte **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 -}; - -struct cf_section { - uns size; // 0 for a global block, sizeof(struct) for a section - cf_hook *init; // fills in default values (no need to bzero) - cf_hook *commit; // verifies parsed data (optional) - cf_copier *copy; // copies values from another instance (optional, no need to copy basic attributes) - struct cf_item *cfg; // CC_END-terminated array of items - uns flags; // for internal use only -}; - -/* Declaration of cf_section */ -#define CF_TYPE(s) .size = sizeof(s) -#define CF_INIT(f) .init = (cf_hook*) f -#define CF_COMMIT(f) .commit = (cf_hook*) f -#define CF_COPY(f) .copy = (cf_copier*) f -#define CF_ITEMS .cfg = ( struct cf_item[] ) -#define CF_END { .cls = CC_END } -/* Configuration items */ -#define CF_STATIC(n,p,T,t,c) { .cls = CC_STATIC, .type = CT_##T, .name = n, .number = c, .ptr = CHECK_PTR_TYPE(p,t*) } -#define CF_DYNAMIC(n,p,T,t,c) { .cls = CC_DYNAMIC, .type = CT_##T, .name = n, .number = c, .ptr = CHECK_PTR_TYPE(p,t**) } -#define CF_PARSER(n,p,f,c) { .cls = CC_PARSER, .name = n, .number = c, .ptr = p, .u.par = (cf_parser*) f } -#define CF_SECTION(n,p,s) { .cls = CC_SECTION, .name = n, .number = 1, .ptr = p, .u.sec = s } -#define CF_LIST(n,p,s) { .cls = CC_LIST, .name = n, .number = 1, .ptr = CHECK_PTR_TYPE(p,clist*), .u.sec = s } -/* Configuration items for basic types */ -#define CF_INT(n,p) CF_STATIC(n,p,INT,int,1) -#define CF_INT_ARY(n,p,c) CF_STATIC(n,p,INT,int,c) -#define CF_INT_DYN(n,p,c) CF_DYNAMIC(n,p,INT,int,c) -#define CF_UNS(n,p) CF_STATIC(n,p,INT,uns,1) -#define CF_UNS_ARY(n,p,c) CF_STATIC(n,p,INT,uns,c) -#define CF_UNS_DYN(n,p,c) CF_DYNAMIC(n,p,INT,uns,c) -#define CF_U64(n,p) CF_STATIC(n,p,U64,u64,1) -#define CF_U64_ARY(n,p,c) CF_STATIC(n,p,U64,u64,c) -#define CF_U64_DYN(n,p,c) CF_DYNAMIC(n,p,U64,u64,c) -#define CF_DOUBLE(n,p) CF_STATIC(n,p,DOUBLE,double,1) -#define CF_DOUBLE_ARY(n,p,c) CF_STATIC(n,p,DOUBLE,double,c) -#define CF_DOUBLE_DYN(n,p,c) CF_DYNAMIC(n,p,DOUBLE,double,c) -#define CF_IP(n,p) CF_STATIC(n,p,IP,u32,1) -#define CF_IP_ARY(n,p,c) CF_STATIC(n,p,IP,u32,c) -#define CF_IP_DYN(n,p,c) CF_DYNAMIC(n,p,IP,u32,c) -#define CF_STRING(n,p) CF_STATIC(n,p,STRING,byte*,1) -#define CF_STRING_ARY(n,p,c) CF_STATIC(n,p,STRING,byte*,c) -#define CF_STRING_DYN(n,p,c) CF_DYNAMIC(n,p,STRING,byte*,c) -#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 - -#define DARY_LEN(a) *(uns*)(a-1) - // length of a dynamic array -#define DARY_ALLOC(type,len,val...) (type[]) { (type)len, ##val } + 1 - // creates a static instance of a dynamic array - // FIXME: overcast doesn't work for the double type - -/* Memory allocation */ -struct mempool; -extern struct mempool *cf_pool; -void *cf_malloc(uns size); -void *cf_malloc_zero(uns size); -byte *cf_strdup(byte *s); -byte *cf_printf(char *fmt, ...) FORMAT_CHECK(printf,1,2); - -/* Undo journal for error recovery */ -extern uns cf_need_journal; -void cf_journal_block(void *ptr, uns len); -#define CF_JOURNAL_VAR(var) cf_journal_block(&(var), sizeof(var)) - -struct cf_journal_item; -struct cf_journal_item *cf_journal_new_transaction(uns new_pool); -void cf_journal_commit_transaction(uns new_pool, struct cf_journal_item *oldj); -void cf_journal_rollback_transaction(uns new_pool, struct cf_journal_item *oldj); - -/* Declaration */ -void cf_declare_section(byte *name, struct cf_section *sec, uns allow_unknown); -void cf_init_section(byte *name, struct cf_section *sec, void *ptr, uns do_bzero); - -/* Safe reloading and loading of configuration files */ -extern byte *cf_def_file; -int cf_reload(byte *file); -int cf_load(byte *file); -int cf_set(byte *string); - -/* Parsers for basic types */ -byte *cf_parse_int(byte *str, int *ptr); -byte *cf_parse_u64(byte *str, u64 *ptr); -byte *cf_parse_double(byte *str, double *ptr); -byte *cf_parse_ip(byte *p, u32 *varp); - -/* Direct access to configuration items */ - -#define CF_OPERATIONS T(CLOSE) T(SET) T(CLEAR) T(APPEND) T(PREPEND) \ - T(REMOVE) T(EDIT) T(AFTER) T(BEFORE) T(COPY) - /* Closing brace finishes previous block. - * Basic attributes (static, dynamic, parsed) can be used with SET. - * Dynamic arrays can be used with SET, APPEND, PREPEND. - * Sections can be used with SET. - * Lists can be used with everything. */ -#define T(x) OP_##x, -enum cf_operation { CF_OPERATIONS }; -#undef T - -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); - -/* - * When using cf_get_opt(), you must prefix your own short/long options by the - * CF_(SHORT|LONG)_OPTS. - * - * cf_def_file contains the name of a configuration file that will be - * automatically loaded before the first --set option is executed. If no --set - * option occurs, it will be loaded after getopt() returns -1 (i.e. at the end - * of the configuration options). cf_def_file will be ignored if another - * configuration file has already been loaded using the --config option. The - * initial value of cf_def_file is DEFAULT_CONFIG from config.h, but you can - * override it manually before calling cf_get_opt(). - */ - -#define CF_SHORT_OPTS "C:S:" -#define CF_LONG_OPTS {"config", 1, 0, 'C'}, {"set", 1, 0, 'S'}, CF_LONG_OPTS_DEBUG -#define CF_NO_LONG_OPTS (const struct option []) { CF_LONG_OPTS { NULL, 0, 0, 0 } } -#ifndef CF_USAGE_TAB -#define CF_USAGE_TAB "" -#endif -#define CF_USAGE \ -"-C, --config filename\t" CF_USAGE_TAB "Override the default configuration file\n\ --S, --set sec.item=val\t" CF_USAGE_TAB "Manual setting of a configuration item\n" CF_USAGE_DEBUG - -#ifdef CONFIG_DEBUG -#define CF_LONG_OPTS_DEBUG { "dumpconfig", 0, 0, 0x64436667 } , -#define CF_USAGE_DEBUG " --dumpconfig\t" CF_USAGE_TAB "Dump program configuration\n" -#else -#define CF_LONG_OPTS_DEBUG -#define CF_USAGE_DEBUG -#endif - -#include -struct option; -int cf_get_opt(int argc, char * const argv[], const char *short_opts, const struct option *long_opts, int *long_index); - -#endif diff --git a/lib/db-test.c b/lib/db-test.c index 23d3f21c..d0f3a5eb 100644 --- a/lib/db-test.c +++ b/lib/db-test.c @@ -15,7 +15,7 @@ #define NAME "GDBM" #endif -#include +#include #include #include #include diff --git a/lib/db-tool.c b/lib/db-tool.c index 4453ab8d..8dca5204 100644 --- a/lib/db-tool.c +++ b/lib/db-tool.c @@ -18,7 +18,6 @@ #include #include #include -#include static int verbose=0; static int cache=1024; diff --git a/lib/fb-mmap.c b/lib/fb-mmap.c index ceb44c2a..d7eaa3d0 100644 --- a/lib/fb-mmap.c +++ b/lib/fb-mmap.c @@ -10,7 +10,7 @@ #include "lib/lib.h" #include "lib/fastbuf.h" #include "lib/lfs.h" -#include "lib/conf2.h" +#include "lib/conf.h" #include #include diff --git a/lib/fb-temp.c b/lib/fb-temp.c index 62c6e382..b8189ab9 100644 --- a/lib/fb-temp.c +++ b/lib/fb-temp.c @@ -8,7 +8,7 @@ */ #include "lib/lib.h" -#include "lib/conf2.h" +#include "lib/conf.h" #include "lib/fastbuf.h" #include diff --git a/lib/getopt.h b/lib/getopt.h new file mode 100644 index 00000000..ca3eaf00 --- /dev/null +++ b/lib/getopt.h @@ -0,0 +1,73 @@ +/* + * UCW Library -- Reading of configuration files + * + * (c) 2001--2006 Robert Spalek + * (c) 2003--2006 Martin Mares + * + * This software may be freely distributed and used according to the terms + * of the GNU Lesser General Public License. + */ + +#ifndef _UCW_GETOPT_H +#define _UCW_GETOPT_H + +/* Safe reloading and loading of configuration files */ +extern byte *cf_def_file; +int cf_reload(byte *file); +int cf_load(byte *file); +int cf_set(byte *string); + +/* Direct access to configuration items */ + +#define CF_OPERATIONS T(CLOSE) T(SET) T(CLEAR) T(APPEND) T(PREPEND) \ + T(REMOVE) T(EDIT) T(AFTER) T(BEFORE) T(COPY) + /* Closing brace finishes previous block. + * Basic attributes (static, dynamic, parsed) can be used with SET. + * Dynamic arrays can be used with SET, APPEND, PREPEND. + * Sections can be used with SET. + * Lists can be used with everything. */ +#define T(x) OP_##x, +enum cf_operation { CF_OPERATIONS }; +#undef T + +struct cf_item; +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); + +/* + * When using cf_get_opt(), you must prefix your own short/long options by the + * CF_(SHORT|LONG)_OPTS. + * + * cf_def_file contains the name of a configuration file that will be + * automatically loaded before the first --set option is executed. If no --set + * option occurs, it will be loaded after getopt() returns -1 (i.e. at the end + * of the configuration options). cf_def_file will be ignored if another + * configuration file has already been loaded using the --config option. The + * initial value of cf_def_file is DEFAULT_CONFIG from config.h, but you can + * override it manually before calling cf_get_opt(). + */ + +#define CF_SHORT_OPTS "C:S:" +#define CF_LONG_OPTS {"config", 1, 0, 'C'}, {"set", 1, 0, 'S'}, CF_LONG_OPTS_DEBUG +#define CF_NO_LONG_OPTS (const struct option []) { CF_LONG_OPTS { NULL, 0, 0, 0 } } +#ifndef CF_USAGE_TAB +#define CF_USAGE_TAB "" +#endif +#define CF_USAGE \ +"-C, --config filename\t" CF_USAGE_TAB "Override the default configuration file\n\ +-S, --set sec.item=val\t" CF_USAGE_TAB "Manual setting of a configuration item\n" CF_USAGE_DEBUG + +#ifdef CONFIG_DEBUG +#define CF_LONG_OPTS_DEBUG { "dumpconfig", 0, 0, 0x64436667 } , +#define CF_USAGE_DEBUG " --dumpconfig\t" CF_USAGE_TAB "Dump program configuration\n" +#else +#define CF_LONG_OPTS_DEBUG +#define CF_USAGE_DEBUG +#endif + +#include +int cf_getopt(int argc, char * const argv[], const char *short_opts, const struct option *long_opts, int *long_index); + +#endif diff --git a/lib/ipaccess.c b/lib/ipaccess.c index 81b35ed0..79508ab0 100644 --- a/lib/ipaccess.c +++ b/lib/ipaccess.c @@ -9,7 +9,8 @@ #include "lib/lib.h" #include "lib/clists.h" -#include "lib/conf2.h" +#include "lib/conf.h" +#include "lib/getopt.h" #include "lib/fastbuf.h" #include "lib/ipaccess.h" @@ -103,7 +104,7 @@ static struct cf_section test_cf = { int main(int argc, char **argv) { cf_declare_section("T", &test_cf, 0); - if (cf_get_opt(argc, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL) != -1) + if (cf_getopt(argc, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL) != -1) die("Invalid arguments"); byte buf[256]; diff --git a/lib/lizard-test.c b/lib/lizard-test.c index 22fc96e4..3973cfcd 100644 --- a/lib/lizard-test.c +++ b/lib/lizard-test.c @@ -1,12 +1,11 @@ #include "lib/lib.h" -#include "lib/conf2.h" +#include "lib/getopt.h" #include "lib/fastbuf.h" #include "lib/lizard.h" #include #include #include #include -#include #include static char *options = CF_SHORT_OPTS "cdtx"; @@ -35,7 +34,7 @@ main(int argc, char **argv) uns action = 't'; uns crash = 0; log_init(argv[0]); - while ((opt = cf_get_opt(argc, argv, options, CF_NO_LONG_OPTS, NULL)) >= 0) + while ((opt = cf_getopt(argc, argv, options, CF_NO_LONG_OPTS, NULL)) >= 0) switch (opt) { case 'c': diff --git a/lib/redblack-test.c b/lib/redblack-test.c index 3c48f18f..80a7a000 100644 --- a/lib/redblack-test.c +++ b/lib/redblack-test.c @@ -5,11 +5,10 @@ */ #include "lib/lib.h" -#include "lib/conf2.h" +#include "lib/getopt.h" #include "lib/fastbuf.h" #include #include -#include struct my1_node { @@ -130,7 +129,7 @@ main(int argc, char **argv) int i; cf_def_file = NULL; log_init(argv[0]); - while ((opt = cf_get_opt(argc, argv, options, CF_NO_LONG_OPTS, NULL)) >= 0) + while ((opt = cf_getopt(argc, argv, options, CF_NO_LONG_OPTS, NULL)) >= 0) switch (opt) { case 'v': diff --git a/lib/shell/config.c b/lib/shell/config.c index f9fa9ae0..7fa16117 100644 --- a/lib/shell/config.c +++ b/lib/shell/config.c @@ -17,7 +17,8 @@ */ #include "lib/lib.h" -#include "lib/conf2.h" +#include "lib/conf.h" +#include "lib/getopt.h" #include #include @@ -171,7 +172,7 @@ int main(int argc, char **argv) } c->cls = CC_END; cf_declare_section(sec_name, sec, allow_unknown); - if (cf_get_opt(start, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL) != -1) + if (cf_getopt(start, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL) != -1) help(); return 0; } diff --git a/lib/sort-test.c b/lib/sort-test.c index 14f4a658..c3a48c8c 100644 --- a/lib/sort-test.c +++ b/lib/sort-test.c @@ -1,13 +1,12 @@ /* Test for sorting routines */ #include "lib/lib.h" -#include "lib/conf2.h" +#include "lib/getopt.h" #include "lib/fastbuf.h" #include #include #include -#include struct key { char line[4096]; @@ -79,7 +78,7 @@ int main(int argc, char **argv) { log_init(NULL); - if (cf_get_opt(argc, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL) >= 0 || + if (cf_getopt(argc, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL) >= 0 || optind != argc - 2) { fputs("This program supports only the following command-line arguments:\n" CF_USAGE, stderr); diff --git a/lib/sorter.c b/lib/sorter.c index 2272df72..2424bf46 100644 --- a/lib/sorter.c +++ b/lib/sorter.c @@ -8,7 +8,7 @@ */ #include "lib/lib.h" -#include "lib/conf2.h" +#include "lib/conf.h" #include "lib/fastbuf.h" #include diff --git a/lib/url.c b/lib/url.c index 2419f71f..c4662372 100644 --- a/lib/url.c +++ b/lib/url.c @@ -18,7 +18,7 @@ #include "lib/lib.h" #include "lib/url.h" #include "lib/chartype.h" -#include "lib/conf2.h" +#include "lib/conf.h" #include #include