diff --git a/lib/isccfg/include/isccfg/cfg.h b/lib/isccfg/include/isccfg/cfg.h index 7f982f5876..4a2b3c4c92 100644 --- a/lib/isccfg/include/isccfg/cfg.h +++ b/lib/isccfg/include/isccfg/cfg.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: cfg.h,v 1.5 2001/02/17 00:15:22 gson Exp $ */ +/* $Id: cfg.h,v 1.6 2001/02/22 00:23:31 gson Exp $ */ #ifndef DNS_CFG_H #define DNS_CFG_H 1 @@ -68,6 +68,14 @@ typedef struct cfg_obj cfg_obj_t; */ typedef struct cfg_listelt cfg_listelt_t; +/* + * A callback function to be called when parsing an option + * that needs to be interpreted at parsing time, like + * "directory". + */ +typedef isc_result_t +(*cfg_parsecallback_t)(const char *clausename, cfg_obj_t *obj, void *arg); + /*** *** Functions ***/ @@ -81,6 +89,20 @@ cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret); * messages will be logged to 'lctx'. */ +void +cfg_parser_setcallback(cfg_parser_t *pctx, + cfg_parsecallback_t callback, + void *arg); +/* + * Make the parser call 'callback' whenever it encounters + * a configuration clause with the callback attribute, + * passing it the clause name, the clause value, + * and 'arg' as arguments. + * + * To restore the default of not invoking callbacks, pass + * callback==NULL and arg==NULL. + */ + isc_result_t cfg_parse_file(cfg_parser_t *pctx, const char *filename, cfg_type_t *type, cfg_obj_t **ret); diff --git a/lib/isccfg/parser.c b/lib/isccfg/parser.c index 99c007a118..2e8de09907 100644 --- a/lib/isccfg/parser.c +++ b/lib/isccfg/parser.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: parser.c,v 1.10 2001/02/17 00:46:58 gson Exp $ */ +/* $Id: parser.c,v 1.11 2001/02/22 00:23:29 gson Exp $ */ #include @@ -47,9 +47,6 @@ #define LOG_BEFORE 0x00000002 /* Say "before " */ #define LOG_NOPREP 0x00000004 /* Say just "" */ -#define ISC_R_BADTYPE 90 -#define ISC_R_MULTIPLEVALUES 91 - #define MAP_SYM 1 /* Unique type for isc_symtab */ /* Clause may occur multiple times (e.g., "zone") */ @@ -60,8 +57,14 @@ #define CFG_CLAUSEFLAG_NOTIMP 0x00000004 /* Clause is not implemented yet */ #define CFG_CLAUSEFLAG_NYI 0x00000008 -/* Default value has changed since earlier release*/ +/* Default value has changed since earlier release */ #define CFG_CLAUSEFLAG_NEWDEFAULT 0x00000008 +/* + * Clause needs to be interpreted during parsing + * by calling a callback function, like the + * "directory" option. + */ +#define CFG_CLAUSEFLAG_CALLBACK 0x00000010 /* * Flags defining whether to accept certain types of network addresses. @@ -97,6 +100,7 @@ typedef isc_result_t (*cfg_parsefunc_t)(cfg_parser_t *, cfg_type_t *type, typedef void (*cfg_printfunc_t)(cfg_printer_t *, cfg_obj_t *); typedef void (*cfg_freefunc_t)(cfg_parser_t *, cfg_obj_t *); + /* * Structure definitions */ @@ -133,6 +137,9 @@ struct cfg_parser { * when a file has just been closed. */ unsigned int line; + + cfg_parsecallback_t callback; + void *callbackarg; }; /* The printer object. */ @@ -316,7 +323,8 @@ parse_negated(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret); static isc_result_t parse_symtab_elt(cfg_parser_t *pctx, const char *name, - cfg_type_t *elttype, isc_symtab_t *symtab); + cfg_type_t *elttype, isc_symtab_t *symtab, + isc_boolean_t callback); static void free_noop(cfg_parser_t *pctx, cfg_obj_t *obj); @@ -1196,6 +1204,8 @@ cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) pctx->errors = 0; pctx->files = 0; pctx->line = 0; + pctx->callback = NULL; + pctx->callbackarg = NULL; memset(specials, 0, sizeof(specials)); specials['{'] = 1; @@ -1249,6 +1259,15 @@ parser_openfile(cfg_parser_t *pctx, const char *filename) { return (result); } +void +cfg_parser_setcallback(cfg_parser_t *pctx, + cfg_parsecallback_t callback, + void *arg) +{ + pctx->callback = callback; + pctx->callbackarg = arg; +} + /* * Parse a configuration using a pctx where a lexer has already * been set up with a source. @@ -1986,7 +2005,7 @@ parse_controls_clause(cfg_parser_t *pctx, cfg_obj_t *mapobj, return (ISC_R_UNEXPECTEDTOKEN); } CHECK(parse_symtab_elt(pctx, name, type, - mapobj->value.map.symtab)); + mapobj->value.map.symtab, ISC_FALSE)); cleanup: return (result); @@ -2806,9 +2825,13 @@ parse_mapbody(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret) } else { /* Single-valued clause */ if (result == ISC_R_NOTFOUND) { + isc_boolean_t callback = + ISC_TF((clause->flags & + CFG_CLAUSEFLAG_CALLBACK) != 0); CHECK(parse_symtab_elt(pctx, clause->name, clause->type, - obj->value.map.symtab)); + obj->value.map.symtab, + callback)); CHECK(parse_semicolon(pctx)); } else if (result == ISC_R_SUCCESS) { parser_error(pctx, LOG_NEAR, "'%s' redefined", @@ -2836,13 +2859,18 @@ parse_mapbody(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret) static isc_result_t parse_symtab_elt(cfg_parser_t *pctx, const char *name, - cfg_type_t *elttype, isc_symtab_t *symtab) + cfg_type_t *elttype, isc_symtab_t *symtab, + isc_boolean_t callback) { isc_result_t result; cfg_obj_t *obj = NULL; isc_symvalue_t symval; CHECK(parse(pctx, elttype, &obj)); + + if (callback && pctx->callback != NULL) + CHECK(pctx->callback(name, obj, pctx->callbackarg)); + symval.as_pointer = obj; CHECK(isc_symtab_define(symtab, name, 1, symval,