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 \
$(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)
--- /dev/null
+/*
+ * Insane tester of reading configuration files
+ *
+ * (c) 2006 Robert Spalek <robert@ucw.cz>
+ */
+
+#include "lib/lib.h"
+#include "lib/conf.h"
+#include "lib/getopt.h"
+#include "lib/clists.h"
+#include "lib/fastbuf.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+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 <options>\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;
+}
--- /dev/null
+/*
+ * UCW Library -- Reading of configuration files
+ *
+ * (c) 2001--2006 Robert Spalek <robert@ucw.cz>
+ * (c) 2003--2006 Martin Mares <mj@ucw.cz>
+ *
+ * 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
+
+++ /dev/null
-/*
- * 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 "lib/fastbuf.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <time.h>
-#include <getopt.h>
-
-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 <options>\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;
-}
*/
#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"
#include <errno.h>
#include <stdarg.h>
#include <fcntl.h>
-#include <getopt.h>
#define TRY(f) do { byte *_msg = f; if (_msg) return _msg; } while (0)
};
}
-static uns postpone_commit; // only for cf_get_opt()
+static uns postpone_commit; // only for cf_getopt()
static int
done_stack(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) {
+++ /dev/null
-/*
- * UCW Library -- Reading of configuration files
- *
- * (c) 2001--2006 Robert Spalek <robert@ucw.cz>
- * (c) 2003--2006 Martin Mares <mj@ucw.cz>
- *
- * 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 <getopt.h>
-struct option;
-int cf_get_opt(int argc, char * const argv[], const char *short_opts, const struct option *long_opts, int *long_index);
-
-#endif
#define NAME "GDBM"
#endif
-#include <getopt.h>
+#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
-#include <getopt.h>
static int verbose=0;
static int cache=1024;
#include "lib/lib.h"
#include "lib/fastbuf.h"
#include "lib/lfs.h"
-#include "lib/conf2.h"
+#include "lib/conf.h"
#include <string.h>
#include <fcntl.h>
*/
#include "lib/lib.h"
-#include "lib/conf2.h"
+#include "lib/conf.h"
#include "lib/fastbuf.h"
#include <unistd.h>
--- /dev/null
+/*
+ * UCW Library -- Reading of configuration files
+ *
+ * (c) 2001--2006 Robert Spalek <robert@ucw.cz>
+ * (c) 2003--2006 Martin Mares <mj@ucw.cz>
+ *
+ * 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 <getopt.h>
+int cf_getopt(int argc, char * const argv[], const char *short_opts, const struct option *long_opts, int *long_index);
+
+#endif
#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"
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];
#include "lib/lib.h"
-#include "lib/conf2.h"
+#include "lib/getopt.h"
#include "lib/fastbuf.h"
#include "lib/lizard.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
-#include <getopt.h>
#include <sys/user.h>
static char *options = CF_SHORT_OPTS "cdtx";
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':
*/
#include "lib/lib.h"
-#include "lib/conf2.h"
+#include "lib/getopt.h"
#include "lib/fastbuf.h"
#include <stdio.h>
#include <stdlib.h>
-#include <getopt.h>
struct my1_node
{
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':
*/
#include "lib/lib.h"
-#include "lib/conf2.h"
+#include "lib/conf.h"
+#include "lib/getopt.h"
#include <stdlib.h>
#include <stdio.h>
}
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;
}
/* Test for sorting routines */
#include "lib/lib.h"
-#include "lib/conf2.h"
+#include "lib/getopt.h"
#include "lib/fastbuf.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <getopt.h>
struct key {
char line[4096];
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);
*/
#include "lib/lib.h"
-#include "lib/conf2.h"
+#include "lib/conf.h"
#include "lib/fastbuf.h"
#include <unistd.h>
#include "lib/lib.h"
#include "lib/url.h"
#include "lib/chartype.h"
-#include "lib/conf2.h"
+#include "lib/conf.h"
#include <string.h>
#include <stdlib.h>