X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=lib%2Fconf.h;h=80857449ca41367258cb4e636038c21efdb68785;hb=da2f99caf76902aacb06fd389994ac79182a92da;hp=c94f1ad082b437fb664dbdafc8e2dede7763ef8c;hpb=a7cb891bfea5a2e47d91612eb6dd728dfbfbd45a;p=libucw.git diff --git a/lib/conf.h b/lib/conf.h index c94f1ad0..80857449 100644 --- a/lib/conf.h +++ b/lib/conf.h @@ -1,49 +1,163 @@ /* - * Sherlock Library -- Reading configuration files + * UCW Library -- Configuration files * - * (c) 2001 Robert Spalek - */ - -/* - * Every module places its configuration setting into some section. Section is - * an array of cfitem, whose first record is of type CT_SECTION and contains - * the name of the section. The configuration sections are registered by - * calling cf_register(). + * (c) 2001--2006 Robert Spalek + * (c) 2003--2006 Martin Mares * - * item->var is a pointer to the destination variable or to the special parsing - * function. + * This software may be freely distributed and used according to the terms + * of the GNU Lesser General Public License. */ -enum cftype { CT_STOP, CT_SECTION, CT_INT, CT_STRING, CT_FUNCTION }; +#ifndef _UCW_CONF_H +#define _UCW_CONF_H -struct cfitem { - byte *name; - enum cftype type; - void *var; +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 + CC_BITMAP // of up to 32 items }; -typedef byte *(*ci_func)(struct cfitem *, byte *); +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 +}; -void cf_register(struct cfitem *items); +struct fastbuf; +typedef char *cf_parser(uns number, char **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 char *cf_parser1(char *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 char *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 char *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. */ -/* - * Direct setting of configuration items and parsing the configuration file. - */ +struct cf_user_type { + uns size; // of the parsed attribute + char *name; // name of the type (for dumping) + cf_parser1 *parser; // how to parse it + cf_dumper1 *dumper; // how to dump the type +}; -byte *cf_set_item(byte *sect, byte *name, byte *value); -void cf_read(byte *filename); +struct cf_section; +struct cf_item { + const char *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 + char **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 +}; -/* - * When using cf_getopt, you must prefix your own short/long options by the - * CF_(SHORT|LONG)_OPTS. - */ +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 } +#define CF_BITMAP_INT(n,p) { .cls = CC_BITMAP, .type = CT_INT, .name = n, .number = 1, .ptr = CHECK_PTR_TYPE(p,u32*) } +#define CF_BITMAP_LOOKUP(n,p,t) { .cls = CC_BITMAP, .type = CT_LOOKUP, .name = n, .number = 1, .ptr = CHECK_PTR_TYPE(p,u32*), .u.lookup = t } +/* 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,char*,1) +#define CF_STRING_ARY(n,p,c) CF_STATIC(n,p,STRING,char*,c) +#define CF_STRING_DYN(n,p,c) CF_DYNAMIC(n,p,STRING,char*,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 } + +/* 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...) ((struct { uns l; type a[len]; }) { .l = len, .a = { val } }).a + // creates a static instance of a dynamic array + +/* Memory allocation: conf-alloc.c */ +struct mempool; +extern struct mempool *cf_pool; +void *cf_malloc(uns size); +void *cf_malloc_zero(uns size); +char *cf_strdup(const char *s); +char *cf_printf(const char *fmt, ...) FORMAT_CHECK(printf,1,2); + +/* Undo journal for error recovery: conf-journal.c */ +extern uns cf_need_journal; +void cf_journal_block(void *ptr, uns len); +#define CF_JOURNAL_VAR(var) cf_journal_block(&(var), sizeof(var)) + +/* Declaration: conf-section.c */ +void cf_declare_section(const char *name, struct cf_section *sec, uns allow_unknown); +void cf_init_section(const char *name, struct cf_section *sec, void *ptr, uns do_bzero); -#define CF_SHORT_OPTS "S:C:" -#define CF_LONG_OPTS \ - {"set", 1, 0, 'S'},\ - {"config", 1, 0, 'C'}, +/* Parsers for basic types: conf-parse.c */ +char *cf_parse_int(const char *str, int *ptr); +char *cf_parse_u64(const char *str, u64 *ptr); +char *cf_parse_double(const char *str, double *ptr); +char *cf_parse_ip(const char *p, u32 *varp); -int cf_getopt(int argc,char * const argv[], - const char *shortopts,const struct option *longopts, - int *longindex); +#endif