📄 parser.c
字号:
CHECK(create_cfgobj(pctx, &cfg_type_boolean, &obj)); obj->value.boolean = value; *ret = obj; return (result); bad_boolean: parser_error(pctx, LOG_NEAR, "boolean expected"); return (ISC_R_UNEXPECTEDTOKEN); cleanup: return (result);}static voidprint_boolean(cfg_printer_t *pctx, cfg_obj_t *obj) { if (obj->value.boolean) print(pctx, "yes", 3); else print(pctx, "no", 2);}static cfg_type_t cfg_type_boolean = { "boolean", parse_boolean, print_boolean, &cfg_rep_boolean, NULL };static const char *dialup_enums[] = { "notify", "notify-passive", "refresh", "passive", NULL };static isc_result_tparse_dialup_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));}static cfg_type_t cfg_type_dialuptype = { "dialuptype", parse_dialup_type, print_ustring, &cfg_rep_string, dialup_enums};static const char *notify_enums[] = { "explicit", NULL };static isc_result_tparse_notify_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));}static cfg_type_t cfg_type_notifytype = { "notifytype", parse_notify_type, print_ustring, &cfg_rep_string, notify_enums,};static keyword_type_t key_kw = { "key", &cfg_type_astring };LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_keyref = { "keyref", parse_keyvalue, print_keyvalue, &cfg_rep_string, &key_kw};static cfg_type_t cfg_type_optional_keyref = { "optional_keyref", parse_optional_keyvalue, print_keyvalue, &cfg_rep_string, &key_kw};/* * Lists. */static isc_result_tcreate_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **obj) { isc_result_t result; CHECK(create_cfgobj(pctx, type, obj)); ISC_LIST_INIT((*obj)->value.list); cleanup: return (result);}static isc_result_tcreate_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp) { cfg_listelt_t *elt; elt = isc_mem_get(pctx->mctx, sizeof(*elt)); if (elt == NULL) return (ISC_R_NOMEMORY); elt->obj = NULL; ISC_LINK_INIT(elt, link); *eltp = elt; return (ISC_R_SUCCESS);}static voidfree_list_elt(cfg_parser_t *pctx, cfg_listelt_t *elt) { cfg_obj_destroy(pctx, &elt->obj); isc_mem_put(pctx->mctx, elt, sizeof(*elt));}static voidfree_list(cfg_parser_t *pctx, cfg_obj_t *obj) { cfg_listelt_t *elt, *next; for (elt = ISC_LIST_HEAD(obj->value.list); elt != NULL; elt = next) { next = ISC_LIST_NEXT(elt, link); free_list_elt(pctx, elt); }}static isc_result_tparse_list_elt(cfg_parser_t *pctx, const cfg_type_t *elttype, cfg_listelt_t **ret){ isc_result_t result; cfg_listelt_t *elt = NULL; cfg_obj_t *value = NULL; CHECK(create_listelt(pctx, &elt)); result = parse(pctx, elttype, &value); if (result != ISC_R_SUCCESS) goto cleanup; elt->obj = value; *ret = elt; return (ISC_R_SUCCESS); cleanup: isc_mem_put(pctx->mctx, elt, sizeof(*elt)); return (result);}/* * Parse a homogeneous list whose elements are of type 'elttype' * and where each element is terminated by a semicolon. */static isc_result_tparse_list(cfg_parser_t *pctx, const cfg_type_t *listtype, cfg_obj_t **ret){ cfg_obj_t *listobj = NULL; const cfg_type_t *listof = listtype->of; isc_result_t result; cfg_listelt_t *elt = NULL; CHECK(create_list(pctx, listtype, &listobj)); for (;;) { CHECK(cfg_peektoken(pctx, 0)); if (pctx->token.type == isc_tokentype_special && pctx->token.value.as_char == /*{*/ '}') break; CHECK(parse_list_elt(pctx, listof, &elt)); CHECK(parse_semicolon(pctx)); ISC_LIST_APPEND(listobj->value.list, elt, link); elt = NULL; } *ret = listobj; return (ISC_R_SUCCESS); cleanup: if (elt != NULL) free_list_elt(pctx, elt); CLEANUP_OBJ(listobj); return (result);}static voidprint_list(cfg_printer_t *pctx, cfg_obj_t *obj) { cfg_list_t *list = &obj->value.list; cfg_listelt_t *elt; for (elt = ISC_LIST_HEAD(*list); elt != NULL; elt = ISC_LIST_NEXT(elt, link)) { print_indent(pctx); print_obj(pctx, elt->obj); print(pctx, ";\n", 2); }}static isc_result_tparse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret){ isc_result_t result; CHECK(parse_special(pctx, '{')); CHECK(parse_list(pctx, type, ret)); CHECK(parse_special(pctx, '}')); cleanup: return (result);}static voidprint_bracketed_list(cfg_printer_t *pctx, cfg_obj_t *obj) { print_open(pctx); print_list(pctx, obj); print_close(pctx);}/* * Parse a homogeneous list whose elements are of type 'elttype' * and where elements are separated by space. The list ends * before the first semicolon. */static isc_result_tparse_spacelist(cfg_parser_t *pctx, const cfg_type_t *listtype, cfg_obj_t **ret){ cfg_obj_t *listobj = NULL; const cfg_type_t *listof = listtype->of; isc_result_t result; CHECK(create_list(pctx, listtype, &listobj)); for (;;) { cfg_listelt_t *elt = NULL; CHECK(cfg_peektoken(pctx, 0)); if (pctx->token.type == isc_tokentype_special && pctx->token.value.as_char == ';') break; CHECK(parse_list_elt(pctx, listof, &elt)); ISC_LIST_APPEND(listobj->value.list, elt, link); } *ret = listobj; return (ISC_R_SUCCESS); cleanup: CLEANUP_OBJ(listobj); return (result);}static voidprint_spacelist(cfg_printer_t *pctx, cfg_obj_t *obj) { cfg_list_t *list = &obj->value.list; cfg_listelt_t *elt; for (elt = ISC_LIST_HEAD(*list); elt != NULL; elt = ISC_LIST_NEXT(elt, link)) { print_obj(pctx, elt->obj); if (ISC_LIST_NEXT(elt, link) != NULL) print(pctx, " ", 1); }}isc_boolean_tcfg_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); if (obj == NULL) return (NULL); return (ISC_LIST_HEAD(obj->value.list));}cfg_listelt_t *cfg_list_next(cfg_listelt_t *elt) { REQUIRE(elt != NULL); return (ISC_LIST_NEXT(elt, link));}cfg_obj_t *cfg_listelt_value(cfg_listelt_t *elt) { REQUIRE(elt != NULL); return (elt->obj);}/* * 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_tparse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret){ const cfg_clausedef_t * const *clausesets = type->of; isc_result_t result; const cfg_clausedef_t * const *clauseset; const 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 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) { parser_error(pctx, LOG_NEAR, "isc_symtab_define(%s) " "failed", clause->name); isc_mem_put(pctx->mctx, list, sizeof(cfg_list_t)); goto cleanup; } } else { INSIST(result == ISC_R_SUCCESS); listobj = symval.as_pointer; } 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); result = ISC_R_EXISTS; 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_tparse_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)); 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_tparse_map(cfg_parser_t *pctx, const 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);}/* * Subroutine for parse_named_map() and parse_addressed_map(). */static isc_result_tparse_any_named_map(cfg_parser_t *pctx, cfg_type_t *nametype, const cfg_type_t *type, cfg_obj_t **ret){ isc_result_t result; cfg_obj_t *idobj = NULL; cfg_obj_t *mapobj = NULL; CHECK(parse(pctx, nametype, &idobj)); CHECK(parse_map(pctx, type, &mapobj)); mapobj->value.map.id = idobj; idobj = NULL; *ret = mapobj; cleanup: CLEANUP_OBJ(idobj); return (re
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -