📄 parser.c
字号:
options_clausesets[] = { options_clauses, view_clauses, zone_clauses, NULL};static cfg_type_t cfg_type_options = { "options", parse_map, print_map, &cfg_rep_map, options_clausesets };/* The "view" statement syntax. */static cfg_clausedef_t *view_clausesets[] = { view_only_clauses, namedconf_or_view_clauses, view_clauses, zone_clauses, NULL};static cfg_type_t cfg_type_viewopts = { "view", parse_map, print_map, &cfg_rep_map, view_clausesets };/* The "zone" statement syntax. */static cfg_clausedef_t *zone_clausesets[] = { zone_only_clauses, zone_clauses, NULL};static cfg_type_t cfg_type_zoneopts = { "zoneopts", parse_map, print_map, &cfg_rep_map, zone_clausesets };/* * Clauses that can be found within the 'key' statement. */static cfg_clausedef_tkey_clauses[] = { { "algorithm", &cfg_type_astring, 0 }, { "secret", &cfg_type_astring, 0 }, { NULL, NULL, 0 }};static cfg_clausedef_t *key_clausesets[] = { key_clauses, NULL};static cfg_type_t cfg_type_key = { "key", parse_named_map, print_map, &cfg_rep_map, key_clausesets };/* * Clauses that can be found in a 'server' statement. */static cfg_clausedef_tserver_clauses[] = { { "bogus", &cfg_type_boolean, 0 }, { "provide-ixfr", &cfg_type_boolean, 0 }, { "request-ixfr", &cfg_type_boolean, 0 }, { "support-ixfr", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, { "transfers", &cfg_type_uint32, 0 }, { "transfer-format", &cfg_type_transferformat, 0 }, { "keys", &cfg_type_server_key_kludge, 0 }, { "edns", &cfg_type_boolean, 0 }, { NULL, NULL, 0 }};static cfg_clausedef_t *server_clausesets[] = { server_clauses, NULL};static cfg_type_t cfg_type_server = { "server", parse_addressed_map, print_map, &cfg_rep_map, server_clausesets};/* * Clauses that can be found in a 'channel' clause in the * 'logging' statement. * * These have some additional constraints that need to be * checked after parsing: * - There must exactly one of file/syslog/null/stderr * */static cfg_clausedef_tchannel_clauses[] = { /* Destinations. We no longer require these to be first. */ { "file", &cfg_type_logfile, 0 }, { "syslog", &cfg_type_optional_facility, 0 }, { "null", &cfg_type_void, 0 }, { "stderr", &cfg_type_void, 0 }, /* Options. We now accept these for the null channel, too. */ { "severity", &cfg_type_logseverity, 0 }, { "print-time", &cfg_type_boolean, 0 }, { "print-severity", &cfg_type_boolean, 0 }, { "print-category", &cfg_type_boolean, 0 }, { NULL, NULL, 0 }};static cfg_clausedef_t *channel_clausesets[] = { channel_clauses, NULL};static cfg_type_t cfg_type_channel = { "channel", parse_named_map, print_map, &cfg_rep_map, channel_clausesets};/* A list of log destination, used in the "category" clause. */static cfg_type_t cfg_type_destinationlist = { "destinationlist", parse_bracketed_list, print_bracketed_list, &cfg_rep_list, &cfg_type_astring };/* * Clauses that can be found in a 'logging' statement. */static cfg_clausedef_tlogging_clauses[] = { { "channel", &cfg_type_channel, CFG_CLAUSEFLAG_MULTI }, { "category", &cfg_type_category, CFG_CLAUSEFLAG_MULTI }, { NULL, NULL, 0 }};static cfg_clausedef_t *logging_clausesets[] = { logging_clauses, NULL};static cfg_type_t cfg_type_logging = { "logging", parse_map, print_map, &cfg_rep_map, logging_clausesets };/* Functions. */static voidprint_obj(cfg_printer_t *pctx, cfg_obj_t *obj) { obj->type->print(pctx, obj);}static voidprint(cfg_printer_t *pctx, const char *text, int len) { pctx->f(pctx->closure, text, len);}static voidprint_open(cfg_printer_t *pctx) { print(pctx, "{\n", 2); pctx->indent++;}static voidprint_indent(cfg_printer_t *pctx) { int indent = pctx->indent; while (indent > 0) { print(pctx, "\t", 1); indent--; }}static voidprint_close(cfg_printer_t *pctx) { pctx->indent--; print_indent(pctx); print(pctx, "}", 1);}static isc_result_tparse(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; INSIST(ret != NULL && *ret == NULL); result = type->parse(pctx, type, ret); if (result != ISC_R_SUCCESS) return (result); INSIST(*ret != NULL); return (ISC_R_SUCCESS);}voidcfg_print(cfg_obj_t *obj, void (*f)(void *closure, const char *text, int textlen), void *closure){ cfg_printer_t pctx; pctx.f = f; pctx.closure = closure; pctx.indent = 0; obj->type->print(&pctx, obj);}/* Tuples. */ static isc_result_tcreate_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; const cfg_tuplefielddef_t *fields = type->of; const cfg_tuplefielddef_t *f; cfg_obj_t *obj = NULL; unsigned int nfields = 0; int i; for (f = fields; f->name != NULL; f++) nfields++; CHECK(create_cfgobj(pctx, type, &obj)); obj->value.tuple = isc_mem_get(pctx->mctx, nfields * sizeof(cfg_obj_t *)); if (obj->value.tuple == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } for (f = fields, i = 0; f->name != NULL; f++, i++) obj->value.tuple[i] = NULL; *ret = obj; return (ISC_R_SUCCESS); cleanup: if (obj != NULL) isc_mem_put(pctx->mctx, obj, sizeof(*obj)); return (result);}static isc_result_tparse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret){ isc_result_t result; const cfg_tuplefielddef_t *fields = type->of; const cfg_tuplefielddef_t *f; cfg_obj_t *obj = NULL; unsigned int i; CHECK(create_tuple(pctx, type, &obj)); for (f = fields, i = 0; f->name != NULL; f++, i++) CHECK(parse(pctx, f->type, &obj->value.tuple[i])); *ret = obj; return (ISC_R_SUCCESS); cleanup: CLEANUP_OBJ(obj); return (result);}static voidprint_tuple(cfg_printer_t *pctx, cfg_obj_t *obj) { unsigned int i; const cfg_tuplefielddef_t *fields = obj->type->of; const cfg_tuplefielddef_t *f; isc_boolean_t need_space = ISC_FALSE; for (f = fields, i = 0; f->name != NULL; f++, i++) { cfg_obj_t *fieldobj = obj->value.tuple[i]; if (need_space) print(pctx, " ", 1); print_obj(pctx, fieldobj); need_space = ISC_TF(fieldobj->type->print != print_void); }}static voidfree_tuple(cfg_parser_t *pctx, cfg_obj_t *obj) { unsigned int i; const cfg_tuplefielddef_t *fields = obj->type->of; const cfg_tuplefielddef_t *f; unsigned int nfields = 0; if (obj->value.tuple == NULL) return; for (f = fields, i = 0; f->name != NULL; f++, i++) { CLEANUP_OBJ(obj->value.tuple[i]); nfields++; } isc_mem_put(pctx->mctx, obj->value.tuple, nfields * sizeof(cfg_obj_t *));}isc_boolean_tcfg_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; const cfg_tuplefielddef_t *fields; const cfg_tuplefielddef_t *f; REQUIRE(tupleobj != NULL && tupleobj->type->rep == &cfg_rep_tuple); fields = tupleobj->type->of; for (f = fields, i = 0; f->name != NULL; f++, i++) { if (strcmp(f->name, name) == 0) return (tupleobj->value.tuple[i]); } INSIST(0); return (NULL);}/* * Parse a required special character. */static isc_result_tparse_special(cfg_parser_t *pctx, int special) { isc_result_t result; CHECK(cfg_gettoken(pctx, 0)); if (pctx->token.type == isc_tokentype_special && pctx->token.value.as_char == special) return (ISC_R_SUCCESS); parser_error(pctx, LOG_NEAR, "'%c' expected", special); return (ISC_R_UNEXPECTEDTOKEN); cleanup: return (result);}/* * Parse a required semicolon. If it is not there, log * an error and increment the error count but continue * parsing. Since the next token is pushed back, * care must be taken to make sure it is eventually * consumed or an infinite loop may result. */static isc_result_tparse_semicolon(cfg_parser_t *pctx) { isc_result_t result; CHECK(cfg_gettoken(pctx, 0)); if (pctx->token.type == isc_tokentype_special && pctx->token.value.as_char == ';') return (ISC_R_SUCCESS); parser_error(pctx, LOG_BEFORE, "missing ';'"); cfg_ungettoken(pctx); cleanup: return (result);}/* * Parse EOF, logging and returning an error if not there. */static isc_result_tparse_eof(cfg_parser_t *pctx) { isc_result_t result; CHECK(cfg_gettoken(pctx, 0)); if (pctx->token.type == isc_tokentype_eof) return (ISC_R_SUCCESS); parser_error(pctx, LOG_NEAR, "syntax error"); return (ISC_R_UNEXPECTEDTOKEN); cleanup: return(result);}/* A list of files, used internally for pctx->files. */static cfg_type_t cfg_type_filelist = { "filelist", NULL, print_list, &cfg_rep_list, &cfg_type_qstring};isc_result_tcfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret){ isc_result_t result; cfg_parser_t *pctx; isc_lexspecials_t specials; REQUIRE(mctx != NULL); REQUIRE(ret != NULL && *ret == NULL); pctx = isc_mem_get(mctx, sizeof(*pctx)); if (pctx == NULL) return (ISC_R_NOMEMORY); pctx->mctx = mctx; pctx->lctx = lctx; pctx->lexer = NULL; pctx->seen_eof = ISC_FALSE; pctx->ungotten = ISC_FALSE; pctx->errors = 0; pctx->warnings = 0; pctx->open_files = NULL; pctx->closed_files = NULL; pctx->line = 0; pctx->callback = NULL; pctx->callbackarg = NULL; pctx->token.type = isc_tokentype_unknown; memset(specials, 0, sizeof(specials)); specials['{'] = 1; specials['}'] = 1; specials[';'] = 1; specials['/'] = 1; specials['"'] = 1; specials['!'] = 1; CHECK(isc_lex_create(pctx->mctx, 1024, &pctx->lexer)); isc_lex_setspecials(pctx->lexer, specials); isc_lex_setcomments(pctx->lexer, (ISC_LEXCOMMENT_C | ISC_LEXCOMMENT_CPLUSPLUS | ISC_LEXCOMMENT_SHELL)); CHECK(create_list(pctx, &cfg_type_filelist, &pctx->open_files)); CHECK(create_list(pctx, &cfg_type_filelist, &pctx->closed_files)); *ret = pctx; return (ISC_R_SUCCESS); cleanup: if (pctx->lexer != NULL) isc_lex_destroy(&pctx->lexer); CLEANUP_OBJ(pctx->open_files); CLEANUP_OBJ(pctx->closed_files); isc_mem_put(mctx, pctx, sizeof(*pctx)); return (result);}static isc_result_tparser_openfile(cfg_parser_t *pctx, const char *filename) { isc_result_t result; cfg_listelt_t *elt = NULL; cfg_obj_t *stringobj = NULL; result = isc_lex_openfile(pctx->lexer, filename); if (result != ISC_R_SUCCESS) { parser_error(pctx, 0, "open: %s: %s", filename, isc_result_totext(result)); goto cleanup; } CHECK(create_string(pctx, filename, &cfg_type_qstring, &stringobj)); CHECK(create_listelt(pctx, &elt)); elt->obj = stringobj; ISC_LIST_APPEND(pctx->open_files->value.list, elt, link); return (ISC_R_SUCCESS); cleanup: CLEANUP_OBJ(stringobj); return (result);}voidcfg_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. */static isc_result_tparse2(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; cfg_obj_t *obj = NULL; result = parse(pctx, type, &obj); if (pctx->errors != 0) { /* Errors have been logged. */ if (result == ISC_R_SUCCESS) result = ISC_R_FAILURE; goto cleanup; } if (result != ISC_R_SUCCESS) { /* Parsing failed but no errors have been logged. */ parser_error(pctx, 0, "parsing failed"); goto cleanup; } CHECK(parse_eof(pctx)); *ret = obj; return (ISC_R_SUCCESS); cleanup: CLEANUP_OBJ(obj); return (result);}isc_result_tcfg_parse_file(cfg_parser_t *pctx, const char *filename, const cfg_type_t *type, cfg_obj_t **ret){ isc_result_t result; REQUIRE(filename != NULL); CHECK(parser_openfile(pctx, filename));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -