2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 14:07:59 +00:00

the values of the notify and dialup options may now be of either boolean or

string types; added cfg_obj_is*() functions for determining the type of a configuration object;
reordered some functions in parser.c
This commit is contained in:
Andreas Gustafsson
2001-02-23 00:15:55 +00:00
parent fba7c63ea4
commit 4428702688
2 changed files with 398 additions and 274 deletions

View File

@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: cfg.h,v 1.11 2001/02/22 23:59:28 bwelling Exp $ */
/* $Id: cfg.h,v 1.12 2001/02/23 00:15:55 gson Exp $ */
#ifndef DNS_CFG_H
#define DNS_CFG_H 1
@@ -138,6 +138,19 @@ cfg_parser_destroy(cfg_parser_t **pctxp);
* Destroy a configuration parser.
*/
isc_boolean_t
cfg_obj_isvoid(cfg_obj_t *obj);
/*
* Return true iff 'obj' is of void type (e.g., an optional
* value not specified).
*/
isc_boolean_t
cfg_obj_ismap(cfg_obj_t *obj);
/*
* Return true iff 'obj' is of a map type.
*/
isc_result_t
cfg_map_get(cfg_obj_t *mapobj, const char* name, cfg_obj_t **obj);
/*
@@ -167,6 +180,12 @@ cfg_map_getname(cfg_obj_t *mapobj);
* or NULL if the map object does not have a name.
*/
isc_boolean_t
cfg_obj_istuple(cfg_obj_t *obj);
/*
* Return true iff 'obj' is of a map type.
*/
cfg_obj_t *
cfg_tuple_get(cfg_obj_t *tupleobj, const char* name);
/*
@@ -179,6 +198,12 @@ cfg_tuple_get(cfg_obj_t *tupleobj, const char* name);
* fields of said tuple type.
*/
isc_boolean_t
cfg_obj_isuint32(cfg_obj_t *obj);
/*
* Return true iff 'obj' is of integer type.
*/
isc_uint32_t
cfg_obj_asuint32(cfg_obj_t *obj);
/*
@@ -191,6 +216,12 @@ cfg_obj_asuint32(cfg_obj_t *obj);
* A 32-bit unsigned integer.
*/
isc_boolean_t
cfg_obj_isstring(cfg_obj_t *obj);
/*
* Return true iff 'obj' is of string type.
*/
char *
cfg_obj_asstring(cfg_obj_t *obj);
/*
@@ -204,6 +235,12 @@ cfg_obj_asstring(cfg_obj_t *obj);
* A pointer to a null terminated string.
*/
isc_boolean_t
cfg_obj_isboolean(cfg_obj_t *obj);
/*
* Return true iff 'obj' is of a boolean type.
*/
isc_boolean_t
cfg_obj_asboolean(cfg_obj_t *obj);
/*
@@ -216,6 +253,12 @@ cfg_obj_asboolean(cfg_obj_t *obj);
* A boolean value.
*/
isc_boolean_t
cfg_obj_issockaddr(cfg_obj_t *obj);
/*
* Return true iff 'obj' is of sockaddr type.
*/
isc_sockaddr_t *
cfg_obj_assockaddr(cfg_obj_t *obj);
/*
@@ -229,6 +272,12 @@ cfg_obj_assockaddr(cfg_obj_t *obj);
* if necessary.
*/
isc_boolean_t
cfg_obj_islist(cfg_obj_t *obj);
/*
* Return true iff 'obj' is of list type.
*/
cfg_listelt_t *
cfg_list_first(cfg_obj_t *obj);
/*

View File

@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: parser.c,v 1.19 2001/02/22 23:59:27 bwelling Exp $ */
/* $Id: parser.c,v 1.20 2001/02/23 00:15:53 gson Exp $ */
#include <config.h>
@@ -387,6 +387,7 @@ cfg_rep_t cfg_rep_void = { "void", free_noop };
*/
static cfg_type_t cfg_type_boolean;
static cfg_type_t cfg_type_boolean_or_ustring;
static cfg_type_t cfg_type_uint32;
static cfg_type_t cfg_type_qstring;
static cfg_type_t cfg_type_astring;
@@ -429,7 +430,7 @@ static cfg_type_t cfg_type_server_key_kludge;
static cfg_type_t cfg_type_optional_facility;
static cfg_type_t cfg_type_logseverity;
static cfg_type_t cfg_type_lwres;
static cfg_type_t cfg_type_boolean_or_ustring;
/*
* Configuration type definitions.
@@ -837,9 +838,9 @@ static cfg_clausedef_t
zone_clauses[] = {
{ "allow-query", &cfg_type_bracketed_aml, 0 },
{ "allow-transfer", &cfg_type_bracketed_aml, 0 },
{ "notify", &cfg_type_ustring, 0 },
{ "notify", &cfg_type_boolean_or_ustring, 0 },
{ "also-notify", &cfg_type_portiplist, 0 },
{ "dialup", &cfg_type_ustring, 0 },
{ "dialup", &cfg_type_boolean_or_ustring, 0 },
{ "forward", &cfg_type_ustring, 0 },
{ "forwarders", &cfg_type_portiplist, 0 },
{ "maintain-ixfr-base", &cfg_type_boolean, 0 },
@@ -1134,6 +1135,12 @@ free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj) {
nfields * sizeof(cfg_obj_t *));
}
isc_boolean_t
cfg_obj_istuple(cfg_obj_t *obj) {
REQUIRE(obj != NULL);
return (ISC_TF(obj->type->rep == &cfg_rep_tuple));
}
cfg_obj_t *
cfg_tuple_get(cfg_obj_t *tupleobj, const char* name) {
unsigned int i;
@@ -1368,31 +1375,6 @@ cfg_parser_destroy(cfg_parser_t **pctxp) {
*pctxp = NULL;
}
isc_result_t
cfg_map_get(cfg_obj_t *mapobj, const char* name, cfg_obj_t **obj) {
isc_result_t result;
isc_symvalue_t val;
cfg_map_t *map;
REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
REQUIRE(name != NULL);
REQUIRE(obj != NULL && *obj == NULL);
map = &mapobj->value.map;
result = isc_symtab_lookup(map->symtab, name, MAP_SYM, &val);
if (result != ISC_R_SUCCESS)
return (result);
*obj = val.as_pointer;
return (ISC_R_SUCCESS);
}
cfg_obj_t *
cfg_map_getname(cfg_obj_t *mapobj) {
REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
return (mapobj->value.map.id);
}
/*
* void
*/
@@ -1407,6 +1389,13 @@ print_void(cfg_printer_t *pctx, cfg_obj_t *obj) {
UNUSED(pctx);
UNUSED(obj);
}
isc_boolean_t
cfg_obj_isvoid(cfg_obj_t *obj) {
REQUIRE(obj != NULL);
return (ISC_TF(obj->type->rep == &cfg_rep_void));
}
static cfg_type_t cfg_type_void = {
"void", parse_void, print_void, &cfg_rep_void, NULL };
@@ -1451,6 +1440,12 @@ print_uint32(cfg_printer_t *pctx, cfg_obj_t *obj) {
print_uint(pctx, obj->value.uint32);
}
isc_boolean_t
cfg_obj_isuint32(cfg_obj_t *obj) {
REQUIRE(obj != NULL);
return (ISC_TF(obj->type->rep == &cfg_rep_uint32));
}
isc_uint32_t
cfg_obj_asuint32(cfg_obj_t *obj) {
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint32);
@@ -1592,24 +1587,30 @@ free_string(cfg_parser_t *pctx, cfg_obj_t *obj) {
obj->value.string.length + 1);
}
isc_boolean_t
cfg_obj_isstring(cfg_obj_t *obj) {
REQUIRE(obj != NULL);
return (ISC_TF(obj->type->rep == &cfg_rep_string));
}
char *
cfg_obj_asstring(cfg_obj_t *obj) {
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_string);
return (obj->value.string.base);
}
isc_boolean_t
cfg_obj_isboolean(cfg_obj_t *obj) {
REQUIRE(obj != NULL);
return (ISC_TF(obj->type->rep == &cfg_rep_boolean));
}
isc_boolean_t
cfg_obj_asboolean(cfg_obj_t *obj) {
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_boolean);
return (obj->value.boolean);
}
isc_sockaddr_t *
cfg_obj_assockaddr(cfg_obj_t *obj) {
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr);
return (&obj->value.sockaddr);
}
/* Quoted string only */
static cfg_type_t cfg_type_qstring = {
"qstring", parse_qstring, print_qstring, &cfg_rep_string, NULL };
@@ -1634,7 +1635,9 @@ static cfg_type_t cfg_type_size = {
* boolean
*/
static isc_result_t
parse_boolean(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret) {
parse_boolean_like(cfg_parser_t *pctx, cfg_type_t *type,
cfg_obj_t **ret, isc_boolean_t accept_string)
{
isc_result_t result;
isc_boolean_t value;
cfg_obj_t *obj = NULL;
@@ -1645,7 +1648,7 @@ parse_boolean(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret) {
return (result);
if (pctx->token.type != isc_tokentype_string)
goto bad_boolean;
goto no_string;
if ((strcasecmp(pctx->token.value.as_pointer, "true") == 0) ||
(strcasecmp(pctx->token.value.as_pointer, "yes") == 0) ||
@@ -1665,6 +1668,12 @@ parse_boolean(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret) {
return (result);
bad_boolean:
if (accept_string)
return (create_string(pctx,
pctx->token.value.as_pointer,
&cfg_type_ustring,
ret));
no_string:
parser_error(pctx, LOG_NEAR, "boolean expected");
return (ISC_R_UNEXPECTEDTOKEN);
@@ -1672,6 +1681,18 @@ parse_boolean(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret) {
return (result);
}
static isc_result_t
parse_boolean(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret) {
return (parse_boolean_like(pctx, type, ret, ISC_FALSE));
}
static isc_result_t
parse_boolean_or_ustring(cfg_parser_t *pctx, cfg_type_t *type,
cfg_obj_t **ret)
{
return (parse_boolean_like(pctx, type, ret, ISC_TRUE));
}
static void
print_boolean(cfg_printer_t *pctx, cfg_obj_t *obj) {
if (obj->value.boolean)
@@ -1683,9 +1704,14 @@ print_boolean(cfg_printer_t *pctx, cfg_obj_t *obj) {
static cfg_type_t cfg_type_boolean = {
"boolean", parse_boolean, print_boolean, &cfg_rep_boolean, NULL };
static cfg_type_t cfg_type_boolean_or_ustring = {
"boolean_or_string", parse_boolean_or_ustring, NULL, NULL, NULL };
static keyword_type_t key_kw = { "key", &cfg_type_astring };
static cfg_type_t cfg_type_optional_keyref = {
"optional_keyref", parse_optional_keyvalue, print_optional_keyvalue, &cfg_rep_string, &key_kw };
"optional_keyref", parse_optional_keyvalue, print_optional_keyvalue,
&cfg_rep_string, &key_kw
};
/*
@@ -1859,6 +1885,12 @@ print_spacelist(cfg_printer_t *pctx, cfg_obj_t *obj) {
}
}
isc_boolean_t
cfg_obj_islist(cfg_obj_t *obj) {
REQUIRE(obj != NULL);
return (ISC_TF(obj->type->rep == &cfg_rep_list));
}
cfg_listelt_t *
cfg_list_first(cfg_obj_t *obj) {
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_list);
@@ -1881,6 +1913,240 @@ cfg_listelt_value(cfg_listelt_t *elt) {
* Maps.
*/
/*
* Parse a map body. That's something like
*
* "foo 1; bar { glub; }; zap true; zap false;"
*
* i.e., a sequence of option names followed by values and
* terminated by semicolons. Used for the top level of
* the named.conf syntax, as well as for the body of the
* options, view, zone, and other statements.
*/
static isc_result_t
parse_mapbody(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret)
{
cfg_clausedef_t **clausesets = type->of;
isc_result_t result;
cfg_clausedef_t **clauseset;
cfg_clausedef_t *clause;
cfg_obj_t *value = NULL;
cfg_obj_t *obj = NULL;
cfg_obj_t *eltobj = NULL;
cfg_obj_t *includename = NULL;
isc_symvalue_t symval;
cfg_list_t *list = NULL;
CHECK(create_map(pctx, type, &obj));
obj->value.map.clausesets = clausesets;
for (;;) {
cfg_listelt_t *elt;
redo:
/*
* Parse the option name and see if it is known.
*/
CHECK(cfg_gettoken(pctx, 0));
if (pctx->token.type != isc_tokentype_string) {
cfg_ungettoken(pctx);
break;
}
/*
* We accept "include" statements wherever a map body
* clause can occur.
*/
if (strcasecmp(pctx->token.value.as_pointer, "include") == 0) {
/*
* Turn the file name into a temporary configuration
* object just so that it is not overwritten by the
* semicolon token.
*/
CHECK(parse(pctx, &cfg_type_qstring, &includename));
CHECK(parse_semicolon(pctx));
CHECK(parser_openfile(pctx, includename->
value.string.base));
cfg_obj_destroy(pctx, &includename);
goto redo;
}
clause = NULL;
for (clauseset = clausesets; *clauseset != NULL; clauseset++) {
for (clause = *clauseset;
clause->name != NULL;
clause++) {
if (strcasecmp(pctx->token.value.as_pointer,
clause->name) == 0)
goto done;
}
}
done:
if (clause == NULL || clause->name == NULL) {
parser_error(pctx, LOG_NOPREP, "unknown option");
/*
* Try to recover by parsing this option as an unknown
* option and discarding it.
*/
CHECK(parse(pctx, &cfg_type_unsupported, &eltobj));
cfg_obj_destroy(pctx, &eltobj);
CHECK(parse_semicolon(pctx));
continue;
}
/* Clause is known. */
/* Issue warnings if appropriate */
if ((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0)
parser_warning(pctx, 0, "option '%s' is obsolete",
clause->name);
if ((clause->flags & CFG_CLAUSEFLAG_NOTIMP) != 0)
parser_warning(pctx, 0, "option '%s' is "
"not implemented",
clause->name);
if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0)
parser_warning(pctx, 0, "option '%s' is "
"not yet implemented", clause->name);
/*
* Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT
* set here - we need to log the *lack* of such an option,
* not its presence.
*/
/* See if the clause already has a value; if not create one. */
result = isc_symtab_lookup(obj->value.map.symtab,
clause->name, 0, &symval);
if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) {
/* Multivalued clause */
cfg_obj_t *listobj = NULL;
if (result == ISC_R_NOTFOUND) {
CHECK(create_list(pctx,
&cfg_type_implicitlist,
&listobj));
symval.as_pointer = listobj;
result = isc_symtab_define(obj->value.
map.symtab,
clause->name,
1, symval,
isc_symexists_reject);
if (result != ISC_R_SUCCESS) {
isc_mem_put(pctx->mctx, list,
sizeof(cfg_list_t));
goto cleanup;
}
} else if (result == ISC_R_SUCCESS) {
listobj = symval.as_pointer;
} else {
parser_error(pctx, LOG_NEAR,
"isc_symtab_define() failed",
clause->name);
goto cleanup;
}
elt = NULL;
CHECK(parse_list_elt(pctx, clause->type, &elt));
CHECK(parse_semicolon(pctx));
ISC_LIST_APPEND(listobj->value.list, elt, link);
} 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,
callback));
CHECK(parse_semicolon(pctx));
} else if (result == ISC_R_SUCCESS) {
parser_error(pctx, LOG_NEAR, "'%s' redefined",
clause->name);
goto cleanup;
} else {
parser_error(pctx, LOG_NEAR,
"isc_symtab_define() failed");
goto cleanup;
}
}
}
*ret = obj;
return (ISC_R_SUCCESS);
cleanup:
CLEANUP_OBJ(value);
CLEANUP_OBJ(obj);
CLEANUP_OBJ(eltobj);
CLEANUP_OBJ(includename);
return (result);
}
static isc_result_t
parse_symtab_elt(cfg_parser_t *pctx, const char *name,
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,
isc_symexists_reject));
obj = NULL;
return (ISC_R_SUCCESS);
cleanup:
CLEANUP_OBJ(obj);
return (result);
}
/*
* Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }"
*/
static isc_result_t
parse_map(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret)
{
isc_result_t result;
CHECK(parse_special(pctx, '{'));
CHECK(parse_mapbody(pctx, type, ret));
CHECK(parse_special(pctx, '}'));
cleanup:
return (result);
}
/*
* Parse a named map; e.g., "name { foo 1; }". Used for the "key", "server",
* and "channel" statements.
*/
static isc_result_t
parse_named_map(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret)
{
isc_result_t result;
cfg_obj_t *idobj = NULL;
cfg_obj_t *mapobj = NULL;
CHECK(parse_astring(pctx, NULL, &idobj));
CHECK(parse_map(pctx, type, &mapobj));
mapobj->value.map.id = idobj;
idobj = NULL;
*ret = mapobj;
cleanup:
CLEANUP_OBJ(idobj);
return (result);
}
static void
print_mapbody(cfg_printer_t *pctx, cfg_obj_t *obj) {
isc_result_t result = ISC_R_SUCCESS;
@@ -1944,6 +2210,38 @@ print_map(cfg_printer_t *pctx, cfg_obj_t *obj) {
print_close(pctx);
}
isc_boolean_t
cfg_obj_ismap(cfg_obj_t *obj) {
REQUIRE(obj != NULL);
return (ISC_TF(obj->type->rep == &cfg_rep_map));
}
isc_result_t
cfg_map_get(cfg_obj_t *mapobj, const char* name, cfg_obj_t **obj) {
isc_result_t result;
isc_symvalue_t val;
cfg_map_t *map;
REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
REQUIRE(name != NULL);
REQUIRE(obj != NULL && *obj == NULL);
map = &mapobj->value.map;
result = isc_symtab_lookup(map->symtab, name, MAP_SYM, &val);
if (result != ISC_R_SUCCESS)
return (result);
*obj = val.as_pointer;
return (ISC_R_SUCCESS);
}
cfg_obj_t *
cfg_map_getname(cfg_obj_t *mapobj) {
REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
return (mapobj->value.map.id);
}
/* Parse an arbitrary token, storing its raw text representation. */
static isc_result_t
parse_token(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret) {
@@ -2529,6 +2827,18 @@ print_sockaddr(cfg_printer_t *pctx, cfg_obj_t *obj) {
}
}
isc_boolean_t
cfg_obj_issockaddr(cfg_obj_t *obj) {
REQUIRE(obj != NULL);
return (ISC_TF(obj->type->rep == &cfg_rep_sockaddr));
}
isc_sockaddr_t *
cfg_obj_assockaddr(cfg_obj_t *obj) {
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr);
return (&obj->value.sockaddr);
}
/* An IPv4/IPv6 address with optional port, "*" accepted as wildcard. */
static cfg_type_t cfg_type_sockaddr4wild = {
"sockaddr4wild", parse_sockaddr4wild, print_sockaddr,
@@ -2726,241 +3036,6 @@ cfg_type_t cfg_type_rndcconf = {
rndcconf_clausesets
};
/*
* Parse a map body. That's something like
*
* "foo 1; bar { glub; }; zap true; zap false;"
*
* i.e., a sequence of option names followed by values and
* terminated by semicolons. Used for the top level of
* the named.conf syntax, as well as for the body of the
* options, view, zone, and other statements.
*/
static isc_result_t
parse_mapbody(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret)
{
cfg_clausedef_t **clausesets = type->of;
isc_result_t result;
cfg_clausedef_t **clauseset;
cfg_clausedef_t *clause;
cfg_obj_t *value = NULL;
cfg_obj_t *obj = NULL;
cfg_obj_t *eltobj = NULL;
cfg_obj_t *includename = NULL;
isc_symvalue_t symval;
cfg_list_t *list = NULL;
CHECK(create_map(pctx, type, &obj));
obj->value.map.clausesets = clausesets;
for (;;) {
cfg_listelt_t *elt;
redo:
/*
* Parse the option name and see if it is known.
*/
CHECK(cfg_gettoken(pctx, 0));
if (pctx->token.type != isc_tokentype_string) {
cfg_ungettoken(pctx);
break;
}
/*
* We accept "include" statements wherever a map body
* clause can occur.
*/
if (strcasecmp(pctx->token.value.as_pointer, "include") == 0) {
/*
* Turn the file name into a temporary configuration
* object just so that it is not overwritten by the
* semicolon token.
*/
CHECK(parse(pctx, &cfg_type_qstring, &includename));
CHECK(parse_semicolon(pctx));
CHECK(parser_openfile(pctx, includename->
value.string.base));
cfg_obj_destroy(pctx, &includename);
goto redo;
}
clause = NULL;
for (clauseset = clausesets; *clauseset != NULL; clauseset++) {
for (clause = *clauseset;
clause->name != NULL;
clause++) {
if (strcasecmp(pctx->token.value.as_pointer,
clause->name) == 0)
goto done;
}
}
done:
if (clause == NULL || clause->name == NULL) {
parser_error(pctx, LOG_NOPREP, "unknown option");
/*
* Try to recover by parsing this option as an unknown
* option and discarding it.
*/
CHECK(parse(pctx, &cfg_type_unsupported, &eltobj));
cfg_obj_destroy(pctx, &eltobj);
CHECK(parse_semicolon(pctx));
continue;
}
/* Clause is known. */
/* Issue warnings if appropriate */
if ((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0)
parser_warning(pctx, 0, "option '%s' is obsolete",
clause->name);
if ((clause->flags & CFG_CLAUSEFLAG_NOTIMP) != 0)
parser_warning(pctx, 0, "option '%s' is "
"not implemented",
clause->name);
if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0)
parser_warning(pctx, 0, "option '%s' is "
"not yet implemented", clause->name);
/*
* Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT
* set here - we need to log the *lack* of such an option,
* not its presence.
*/
/* See if the clause already has a value; if not create one. */
result = isc_symtab_lookup(obj->value.map.symtab,
clause->name, 0, &symval);
if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) {
/* Multivalued clause */
cfg_obj_t *listobj = NULL;
if (result == ISC_R_NOTFOUND) {
CHECK(create_list(pctx,
&cfg_type_implicitlist,
&listobj));
symval.as_pointer = listobj;
result = isc_symtab_define(obj->value.
map.symtab,
clause->name,
1, symval,
isc_symexists_reject);
if (result != ISC_R_SUCCESS) {
isc_mem_put(pctx->mctx, list,
sizeof(cfg_list_t));
goto cleanup;
}
} else if (result == ISC_R_SUCCESS) {
listobj = symval.as_pointer;
} else {
parser_error(pctx, LOG_NEAR,
"isc_symtab_define() failed",
clause->name);
goto cleanup;
}
elt = NULL;
CHECK(parse_list_elt(pctx, clause->type, &elt));
CHECK(parse_semicolon(pctx));
ISC_LIST_APPEND(listobj->value.list, elt, link);
} 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,
callback));
CHECK(parse_semicolon(pctx));
} else if (result == ISC_R_SUCCESS) {
parser_error(pctx, LOG_NEAR, "'%s' redefined",
clause->name);
goto cleanup;
} else {
parser_error(pctx, LOG_NEAR,
"isc_symtab_define() failed");
goto cleanup;
}
}
}
*ret = obj;
return (ISC_R_SUCCESS);
cleanup:
CLEANUP_OBJ(value);
CLEANUP_OBJ(obj);
CLEANUP_OBJ(eltobj);
CLEANUP_OBJ(includename);
return (result);
}
static isc_result_t
parse_symtab_elt(cfg_parser_t *pctx, const char *name,
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,
isc_symexists_reject));
obj = NULL;
return (ISC_R_SUCCESS);
cleanup:
CLEANUP_OBJ(obj);
return (result);
}
/*
* Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }"
*/
static isc_result_t
parse_map(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret)
{
isc_result_t result;
CHECK(parse_special(pctx, '{'));
CHECK(parse_mapbody(pctx, type, ret));
CHECK(parse_special(pctx, '}'));
cleanup:
return (result);
}
/*
* Parse a named map; e.g., "name { foo 1; }". Used for the "key", "server",
* and "channel" statements.
*/
static isc_result_t
parse_named_map(cfg_parser_t *pctx, cfg_type_t *type, cfg_obj_t **ret)
{
isc_result_t result;
cfg_obj_t *idobj = NULL;
cfg_obj_t *mapobj = NULL;
CHECK(parse_astring(pctx, NULL, &idobj));
CHECK(parse_map(pctx, type, &mapobj));
mapobj->value.map.id = idobj;
idobj = NULL;
*ret = mapobj;
cleanup:
CLEANUP_OBJ(idobj);
return (result);
}
static isc_result_t
cfg_gettoken(cfg_parser_t *pctx, int options) {
isc_result_t result;