📄 parser.c
字号:
cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags) { isc_result_t result; isc_netaddr_t na_dummy; result = token_addr(pctx, flags, &na_dummy); return (ISC_TF(result == ISC_R_SUCCESS));}isc_result_tcfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port) { isc_result_t result; CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER)); if ((flags & CFG_ADDR_WILDOK) != 0 && pctx->token.type == isc_tokentype_string && strcmp(TOKEN_STRING(pctx), "*") == 0) { *port = 0; return (ISC_R_SUCCESS); } if (pctx->token.type != isc_tokentype_number) { cfg_parser_error(pctx, CFG_LOG_NEAR, "expected port number or '*'"); return (ISC_R_UNEXPECTEDTOKEN); } if (pctx->token.value.as_ulong >= 65536U) { cfg_parser_error(pctx, CFG_LOG_NEAR, "port number out of range"); return (ISC_R_UNEXPECTEDTOKEN); } *port = (in_port_t)(pctx->token.value.as_ulong); return (ISC_R_SUCCESS); cleanup: return (result);}voidcfg_print_rawaddr(cfg_printer_t *pctx, isc_netaddr_t *na) { isc_result_t result; char text[128]; isc_buffer_t buf; isc_buffer_init(&buf, text, sizeof(text)); result = isc_netaddr_totext(na, &buf); RUNTIME_CHECK(result == ISC_R_SUCCESS); cfg_print_chars(pctx, isc_buffer_base(&buf), isc_buffer_usedlength(&buf));}/* netaddr */static isc_result_tparse_netaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; cfg_obj_t *obj = NULL; isc_netaddr_t netaddr; UNUSED(type); CHECK(cfg_create_obj(pctx, type, &obj)); CHECK(cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK, &netaddr)); isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, 0); *ret = obj; return (ISC_R_SUCCESS); cleanup: CLEANUP_OBJ(obj); return (result);}cfg_type_t cfg_type_netaddr = { "netaddr", parse_netaddr, cfg_print_sockaddr, cfg_doc_terminal, &cfg_rep_sockaddr, NULL};/* netprefix */isc_result_tcfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret){ cfg_obj_t *obj = NULL; isc_result_t result; isc_netaddr_t netaddr; unsigned int addrlen, prefixlen; UNUSED(type); CHECK(cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK | CFG_ADDR_V6OK, &netaddr)); switch (netaddr.family) { case AF_INET: addrlen = 32; break; case AF_INET6: addrlen = 128; break; default: addrlen = 0; INSIST(0); break; } CHECK(cfg_peektoken(pctx, 0)); if (pctx->token.type == isc_tokentype_special && pctx->token.value.as_char == '/') { CHECK(cfg_gettoken(pctx, 0)); /* read "/" */ CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER)); if (pctx->token.type != isc_tokentype_number) { cfg_parser_error(pctx, CFG_LOG_NEAR, "expected prefix length"); return (ISC_R_UNEXPECTEDTOKEN); } prefixlen = pctx->token.value.as_ulong; if (prefixlen > addrlen) { cfg_parser_error(pctx, CFG_LOG_NOPREP, "invalid prefix length"); return (ISC_R_RANGE); } } else { prefixlen = addrlen; } CHECK(cfg_create_obj(pctx, &cfg_type_netprefix, &obj)); obj->value.netprefix.address = netaddr; obj->value.netprefix.prefixlen = prefixlen; *ret = obj; return (ISC_R_SUCCESS); cleanup: cfg_parser_error(pctx, CFG_LOG_NEAR, "expected network prefix"); return (result);}static voidprint_netprefix(cfg_printer_t *pctx, cfg_obj_t *obj) { cfg_netprefix_t *p = &obj->value.netprefix; cfg_print_rawaddr(pctx, &p->address); cfg_print_chars(pctx, "/", 1); cfg_print_rawuint(pctx, p->prefixlen);}isc_boolean_tcfg_obj_isnetprefix(cfg_obj_t *obj) { REQUIRE(obj != NULL); return (ISC_TF(obj->type->rep == &cfg_rep_netprefix));}voidcfg_obj_asnetprefix(cfg_obj_t *obj, isc_netaddr_t *netaddr, unsigned int *prefixlen) { REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_netprefix); *netaddr = obj->value.netprefix.address; *prefixlen = obj->value.netprefix.prefixlen;}cfg_type_t cfg_type_netprefix = { "netprefix", cfg_parse_netprefix, print_netprefix, cfg_doc_terminal, &cfg_rep_netprefix, NULL};static isc_result_tparse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type, int flags, cfg_obj_t **ret){ isc_result_t result; isc_netaddr_t netaddr; in_port_t port = 0; cfg_obj_t *obj = NULL; CHECK(cfg_create_obj(pctx, type, &obj)); CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr)); CHECK(cfg_peektoken(pctx, 0)); if (pctx->token.type == isc_tokentype_string && strcasecmp(TOKEN_STRING(pctx), "port") == 0) { CHECK(cfg_gettoken(pctx, 0)); /* read "port" */ CHECK(cfg_parse_rawport(pctx, flags, &port)); } isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port); *ret = obj; return (ISC_R_SUCCESS); cleanup: CLEANUP_OBJ(obj); return (result);}static unsigned int sockaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK;cfg_type_t cfg_type_sockaddr = { "sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr_flags};isc_result_tcfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { const unsigned int *flagp = type->of; return (parse_sockaddrsub(pctx, &cfg_type_sockaddr, *flagp, ret));}voidcfg_print_sockaddr(cfg_printer_t *pctx, cfg_obj_t *obj) { isc_netaddr_t netaddr; in_port_t port; char buf[ISC_NETADDR_FORMATSIZE]; isc_netaddr_fromsockaddr(&netaddr, &obj->value.sockaddr); isc_netaddr_format(&netaddr, buf, sizeof(buf)); cfg_print_cstr(pctx, buf); port = isc_sockaddr_getport(&obj->value.sockaddr); if (port != 0) { cfg_print_chars(pctx, " port ", 6); cfg_print_rawuint(pctx, port); }}voidcfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) { const unsigned int *flagp = type->of; int n = 0; cfg_print_chars(pctx, "( ", 2); if (*flagp & CFG_ADDR_V4OK) { if (n != 0) cfg_print_chars(pctx, " | ", 3); cfg_print_cstr(pctx, "<ipv4_address>"); n++; } if (*flagp & CFG_ADDR_V6OK) { if (n != 0) cfg_print_chars(pctx, " | ", 3); cfg_print_cstr(pctx, "<ipv6_address>"); n++; } if (*flagp & CFG_ADDR_WILDOK) { if (n != 0) cfg_print_chars(pctx, " | ", 3); cfg_print_chars(pctx, "*", 1); n++; } cfg_print_chars(pctx, " ) ", 3); if (*flagp & CFG_ADDR_WILDOK) { cfg_print_cstr(pctx, "[ port ( <integer> | * ) ]"); } else { cfg_print_cstr(pctx, "[ port <integer> ]"); }}isc_boolean_tcfg_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);}isc_result_tcfg_gettoken(cfg_parser_t *pctx, int options) { isc_result_t result; if (pctx->seen_eof) return (ISC_R_SUCCESS); options |= (ISC_LEXOPT_EOF | ISC_LEXOPT_NOMORE); redo: pctx->token.type = isc_tokentype_unknown; result = isc_lex_gettoken(pctx->lexer, options, &pctx->token); pctx->ungotten = ISC_FALSE; pctx->line = isc_lex_getsourceline(pctx->lexer); switch (result) { case ISC_R_SUCCESS: if (pctx->token.type == isc_tokentype_eof) { result = isc_lex_close(pctx->lexer); INSIST(result == ISC_R_NOMORE || result == ISC_R_SUCCESS); if (isc_lex_getsourcename(pctx->lexer) != NULL) { /* * Closed an included file, not the main file. */ cfg_listelt_t *elt; elt = ISC_LIST_TAIL(pctx->open_files-> value.list); INSIST(elt != NULL); ISC_LIST_UNLINK(pctx->open_files-> value.list, elt, link); ISC_LIST_APPEND(pctx->closed_files-> value.list, elt, link); goto redo; } pctx->seen_eof = ISC_TRUE; } break; case ISC_R_NOSPACE: /* More understandable than "ran out of space". */ cfg_parser_error(pctx, CFG_LOG_NEAR, "token too big"); break; case ISC_R_IOERROR: cfg_parser_error(pctx, 0, "%s", isc_result_totext(result)); break; default: cfg_parser_error(pctx, CFG_LOG_NEAR, "%s", isc_result_totext(result)); break; } return (result);}voidcfg_ungettoken(cfg_parser_t *pctx) { if (pctx->seen_eof) return; isc_lex_ungettoken(pctx->lexer, &pctx->token); pctx->ungotten = ISC_TRUE;}isc_result_tcfg_peektoken(cfg_parser_t *pctx, int options) { isc_result_t result; CHECK(cfg_gettoken(pctx, options)); cfg_ungettoken(pctx); cleanup: return (result);}/* * Get a string token, accepting both the quoted and the unquoted form. * Log an error if the next token is not a string. */static isc_result_tcfg_getstringtoken(cfg_parser_t *pctx) { isc_result_t result; result = cfg_gettoken(pctx, CFG_LEXOPT_QSTRING); if (result != ISC_R_SUCCESS) return (result); if (pctx->token.type != isc_tokentype_string && pctx->token.type != isc_tokentype_qstring) { cfg_parser_error(pctx, CFG_LOG_NEAR, "expected string"); return (ISC_R_UNEXPECTEDTOKEN); } return (ISC_R_SUCCESS);}voidcfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) { va_list args; va_start(args, fmt); parser_complain(pctx, ISC_FALSE, flags, fmt, args); va_end(args); pctx->errors++;}voidcfg_parser_warning(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) { va_list args; va_start(args, fmt); parser_complain(pctx, ISC_TRUE, flags, fmt, args); va_end(args); pctx->warnings++;}#define MAX_LOG_TOKEN 30 /* How much of a token to quote in log messages. */static char *current_file(cfg_parser_t *pctx) { static char none[] = "none"; cfg_listelt_t *elt; cfg_obj_t *fileobj; if (pctx->open_files == NULL) return (none); elt = ISC_LIST_TAIL(pctx->open_files->value.list); if (elt == NULL) return (none); fileobj = elt->obj; INSIST(fileobj->type == &cfg_type_qstring); return (fileobj->value.string.base);}static voidparser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning, unsigned int flags, const char *format, va_list args){ char tokenbuf[MAX_LOG_TOKEN + 10]; static char where[ISC_DIR_PATHMAX + 100]; static char message[2048]; int level = ISC_LOG_ERROR; const char *prep = ""; size_t len; if (is_warning) level = ISC_LOG_WARNING; snprintf(where, sizeof(where), "%s:%u: ", current_file(pctx), pctx->line); len = vsnprintf(message, sizeof(message), format, args); if (len >= sizeof(message)) FATAL_ERROR(__FILE__, __LINE__, "error message would overflow"); if ((flags & (CFG_LOG_NEAR|CFG_LOG_BEFORE|CFG_LOG_NOPREP)) != 0) { isc_region_t r; if (pctx->ungotten) (void)cfg_gettoken(pctx, 0); if (pctx->token.type == isc_tokentype_eof) { snprintf(tokenbuf, sizeof(tokenbuf), "end of file"); } else if (pctx->token.type == isc_tokentype_unknown) { flags = 0; tokenbuf[0] = '\0'; } else { isc_lex_getlasttokentext(pctx->lexer, &pctx->token, &r); if (r.length > MAX_LOG_TOKEN) snprintf(tokenbuf, sizeof(tokenbuf), "'%.*s...'", MAX_LOG_TOKEN, r.base); else snprintf(tokenbuf, sizeof(tokenbuf), "'%.*s'", (int)r.length, r.base); } /* Choose a preposition. */ if (flags & CFG_LOG_NEAR) prep = " near "; else if (flags & CFG_LOG_BEFORE) prep = " before "; else prep = " "; } else { tokenbuf[0] = '\0'; } isc_log_write(pctx->lctx, CAT, MOD, level, "%s%s%s%s", where, message, prep, tokenbuf);}voidcfg_obj_log(cfg_obj_t *obj, isc_log_t *lctx, int level, const char *fmt, ...) { va_list ap; char msgbuf[2048]; if (! isc_log_wouldlog(lctx, level)) return; va_start(ap, fmt); vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); isc_log_write(lctx, CAT, MOD, level, "%s:%u: %s", obj->file == NULL ? "<unknown file>" : obj->file, obj->line, msgbuf); va_end(ap);}const char *cfg_obj_file(cfg_obj_t *obj) { return (obj->file);}unsigned intcfg_obj_line(cfg_obj_t *obj) { return (obj->line);}isc_result_tcfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { cfg_obj_t *obj; obj = isc_mem_get(pctx->mctx, sizeof(cfg_obj_t)); if (obj == NULL) return (ISC_R_NOMEMORY); obj->type = type; obj->file = current_file(pctx); obj->line = pctx->line; *ret = obj; return (ISC_R_SUCCESS);}static voidmap_symtabitem_destroy(char *key, unsigned int type, isc_symvalue_t symval, void *userarg){ cfg_obj_t *obj = symval.as_pointer; cfg_parser_t *pctx = (cfg_parser_t *)userarg; UNUSED(key); UNUSED(type); cfg_obj_destroy(pctx, &obj);}static isc_result_tcreate_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; isc_symtab_t *symtab = NULL; cfg_obj_t *obj = NULL; CHECK(cfg_create_obj(pctx, type, &obj)); CHECK(isc_symtab_create(pctx->mctx, 5, /* XXX */ map_symtabitem_destroy, pctx, ISC_FALSE, &symtab)); obj->value.map.symtab = symtab; obj->value.map.id = NULL; *ret = obj; return (ISC_R_SUCCESS); cleanup: if (obj != NULL) isc_mem_put(pctx->mctx, obj, sizeof(*obj)); return (result);}static voidfree_map(cfg_parser_t *pctx, cfg_obj_t *obj) { CLEANUP_OBJ(obj->value.map.id); isc_symtab_destroy(&obj->value.map.symtab);}isc_boolean_tcfg_obj_istype(cfg_obj_t *obj, const cfg_type_t *type) { return (ISC_TF(obj->type == type));}/* * Destroy 'obj', a configuration object created in 'pctx'. */voidcfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **objp) { cfg_obj_t *obj = *objp; obj->type->rep->free(pctx, obj); isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t)); *objp = NULL;}static voidfree_noop(cfg_parser_t *pctx, cfg_obj_t *obj) { UNUSED(pctx); UNUSED(obj);}voidcfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type) { type->doc(pctx, type);}voidcfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type) { cfg_print_chars(pctx, "<", 1); cfg_print_cstr(pctx, type->name); cfg_print_chars(pctx, ">", 1);}voidcfg_print_grammar(const cfg_type_t *type, void (*f)(void *closure, const char *text, int textlen), void *closure){ cfg_printer_t pctx; pctx.f = f; pctx.closure = closure; pctx.indent = 0; cfg_doc_obj(&pctx, type);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -