Blame lib/isccfg/parser.c

Packit Service ae04f2
/*
Packit Service ae04f2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
Packit Service ae04f2
 *
Packit Service ae04f2
 * This Source Code Form is subject to the terms of the Mozilla Public
Packit Service ae04f2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit Service ae04f2
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
Packit Service ae04f2
 *
Packit Service ae04f2
 * See the COPYRIGHT file distributed with this work for additional
Packit Service ae04f2
 * information regarding copyright ownership.
Packit Service ae04f2
 */
Packit Service ae04f2
Packit Service ae04f2
/*! \file */
Packit Service ae04f2
Packit Service ae04f2
#include <config.h>
Packit Service ae04f2
Packit Service ae04f2
#include <inttypes.h>
Packit Service ae04f2
#include <stdbool.h>
Packit Service ae04f2
#include <stdlib.h>
Packit Service ae04f2
Packit Service ae04f2
#include <isc/buffer.h>
Packit Service ae04f2
#include <isc/dir.h>
Packit Service ae04f2
#include <isc/formatcheck.h>
Packit Service ae04f2
#include <isc/lex.h>
Packit Service ae04f2
#include <isc/log.h>
Packit Service ae04f2
#include <isc/mem.h>
Packit Service ae04f2
#include <isc/net.h>
Packit Service ae04f2
#include <isc/netaddr.h>
Packit Service ae04f2
#include <isc/netscope.h>
Packit Service ae04f2
#include <isc/print.h>
Packit Service ae04f2
#include <isc/refcount.h>
Packit Service ae04f2
#include <isc/string.h>
Packit Service ae04f2
#include <isc/sockaddr.h>
Packit Service ae04f2
#include <isc/symtab.h>
Packit Service ae04f2
#include <isc/util.h>
Packit Service ae04f2
Packit Service ae04f2
#include <isccfg/cfg.h>
Packit Service ae04f2
#include <isccfg/grammar.h>
Packit Service ae04f2
#include <isccfg/log.h>
Packit Service ae04f2
Packit Service ae04f2
/* Shorthand */
Packit Service ae04f2
#define CAT CFG_LOGCATEGORY_CONFIG
Packit Service ae04f2
#define MOD CFG_LOGMODULE_PARSER
Packit Service ae04f2
Packit Service ae04f2
#define MAP_SYM 1 	/* Unique type for isc_symtab */
Packit Service ae04f2
Packit Service ae04f2
#define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)
Packit Service ae04f2
Packit Service ae04f2
/* Check a return value. */
Packit Service ae04f2
#define CHECK(op) 						\
Packit Service ae04f2
	do { result = (op); 					\
Packit Service ae04f2
		if (result != ISC_R_SUCCESS) goto cleanup; 	\
Packit Service ae04f2
	} while (0)
Packit Service ae04f2
Packit Service ae04f2
/* Clean up a configuration object if non-NULL. */
Packit Service ae04f2
#define CLEANUP_OBJ(obj) \
Packit Service ae04f2
	do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0)
Packit Service ae04f2
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Forward declarations of static functions.
Packit Service ae04f2
 */
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj);
Packit Service ae04f2
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
parse_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
print_list(cfg_printer_t *pctx, const cfg_obj_t *obj);
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
free_list(cfg_parser_t *pctx, cfg_obj_t *obj);
Packit Service ae04f2
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp);
Packit Service ae04f2
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type,
Packit Service ae04f2
	      cfg_obj_t **ret);
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
free_string(cfg_parser_t *pctx, cfg_obj_t *obj);
Packit Service ae04f2
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp);
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
free_map(cfg_parser_t *pctx, cfg_obj_t *obj);
Packit Service ae04f2
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
parse_symtab_elt(cfg_parser_t *pctx, const char *name,
Packit Service ae04f2
		 cfg_type_t *elttype, isc_symtab_t *symtab,
Packit Service ae04f2
		 bool callback);
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
free_noop(cfg_parser_t *pctx, cfg_obj_t *obj);
Packit Service ae04f2
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
cfg_getstringtoken(cfg_parser_t *pctx);
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
parser_complain(cfg_parser_t *pctx, bool is_warning,
Packit Service ae04f2
		unsigned int flags, const char *format, va_list args);
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Data representations.  These correspond to members of the
Packit Service ae04f2
 * "value" union in struct cfg_obj (except "void", which does
Packit Service ae04f2
 * not need a union member).
Packit Service ae04f2
 */
Packit Service ae04f2
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_uint32 = { "uint32", free_noop };
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_uint64 = { "uint64", free_noop };
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_string = { "string", free_string };
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_boolean = { "boolean", free_noop };
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_map = { "map", free_map };
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_list = { "list", free_list };
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_tuple = { "tuple", free_tuple };
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_sockaddr = { "sockaddr", free_noop };
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_netprefix =
Packit Service ae04f2
	{ "netprefix", free_noop };
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_void = { "void", free_noop };
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_fixedpoint =
Packit Service ae04f2
	{ "fixedpoint", free_noop };
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_percentage =
Packit Service ae04f2
	{ "percentage", free_noop };
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Configuration type definitions.
Packit Service ae04f2
 */
Packit Service ae04f2
Packit Service ae04f2
/*%
Packit Service ae04f2
 * An implicit list.  These are formed by clauses that occur multiple times.
Packit Service ae04f2
 */
Packit Service ae04f2
static cfg_type_t cfg_type_implicitlist = {
Packit Service ae04f2
	"implicitlist", NULL, print_list, NULL, &cfg_rep_list, NULL };
Packit Service ae04f2
Packit Service ae04f2
/* Functions. */
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_obj(cfg_printer_t *pctx, const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
Packit Service ae04f2
	obj->type->print(pctx, obj);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_chars(cfg_printer_t *pctx, const char *text, int len) {
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(text != NULL);
Packit Service ae04f2
Packit Service ae04f2
	pctx->f(pctx->closure, text, len);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
print_open(cfg_printer_t *pctx) {
Packit Service ae04f2
	if ((pctx->flags & CFG_PRINTER_ONELINE) != 0)
Packit Service ae04f2
		cfg_print_cstr(pctx, "{ ");
Packit Service ae04f2
	else {
Packit Service ae04f2
		cfg_print_cstr(pctx, "{\n");
Packit Service ae04f2
		pctx->indent++;
Packit Service ae04f2
	}
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_indent(cfg_printer_t *pctx) {
Packit Service ae04f2
	int indent = pctx->indent;
Packit Service ae04f2
	if ((pctx->flags & CFG_PRINTER_ONELINE) != 0) {
Packit Service ae04f2
		cfg_print_cstr(pctx, " ");
Packit Service ae04f2
		return;
Packit Service ae04f2
	}
Packit Service ae04f2
	while (indent > 0) {
Packit Service ae04f2
		cfg_print_cstr(pctx, "\t");
Packit Service ae04f2
		indent--;
Packit Service ae04f2
	}
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
print_close(cfg_printer_t *pctx) {
Packit Service ae04f2
	if ((pctx->flags & CFG_PRINTER_ONELINE) == 0) {
Packit Service ae04f2
		pctx->indent--;
Packit Service ae04f2
		cfg_print_indent(pctx);
Packit Service ae04f2
	}
Packit Service ae04f2
	cfg_print_cstr(pctx, "}");
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	result = type->parse(pctx, type, ret);
Packit Service ae04f2
	if (result != ISC_R_SUCCESS)
Packit Service ae04f2
		return (result);
Packit Service ae04f2
	ENSURE(*ret != NULL);
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print(const cfg_obj_t *obj,
Packit Service ae04f2
	  void (*f)(void *closure, const char *text, int textlen),
Packit Service ae04f2
	  void *closure)
Packit Service ae04f2
{
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
	REQUIRE(f != NULL);
Packit Service ae04f2
Packit Service ae04f2
	cfg_printx(obj, 0, f, closure);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_printx(const cfg_obj_t *obj, unsigned int flags,
Packit Service ae04f2
	     void (*f)(void *closure, const char *text, int textlen),
Packit Service ae04f2
	     void *closure)
Packit Service ae04f2
{
Packit Service ae04f2
	cfg_printer_t pctx;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
	REQUIRE(f != NULL);
Packit Service ae04f2
Packit Service ae04f2
	pctx.f = f;
Packit Service ae04f2
	pctx.closure = closure;
Packit Service ae04f2
	pctx.indent = 0;
Packit Service ae04f2
	pctx.flags = flags;
Packit Service ae04f2
	obj->type->print(&pctx, obj);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/* Tuples. */
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	const cfg_tuplefielddef_t *fields;
Packit Service ae04f2
	const cfg_tuplefielddef_t *f;
Packit Service ae04f2
	cfg_obj_t *obj = NULL;
Packit Service ae04f2
	unsigned int nfields = 0;
Packit Service ae04f2
	int i;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	fields = type->of;
Packit Service ae04f2
Packit Service ae04f2
	for (f = fields; f->name != NULL; f++)
Packit Service ae04f2
		nfields++;
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_create_obj(pctx, type, &obj));
Packit Service ae04f2
	obj->value.tuple = isc_mem_get(pctx->mctx,
Packit Service ae04f2
				       nfields * sizeof(cfg_obj_t *));
Packit Service ae04f2
	if (obj->value.tuple == NULL) {
Packit Service ae04f2
		result = ISC_R_NOMEMORY;
Packit Service ae04f2
		goto cleanup;
Packit Service ae04f2
	}
Packit Service ae04f2
	for (f = fields, i = 0; f->name != NULL; f++, i++)
Packit Service ae04f2
		obj->value.tuple[i] = NULL;
Packit Service ae04f2
	*ret = obj;
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	if (obj != NULL)
Packit Service ae04f2
		isc_mem_put(pctx->mctx, obj, sizeof(*obj));
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	const cfg_tuplefielddef_t *fields;
Packit Service ae04f2
	const cfg_tuplefielddef_t *f;
Packit Service ae04f2
	cfg_obj_t *obj = NULL;
Packit Service ae04f2
	unsigned int i;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	fields = type->of;
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_create_tuple(pctx, type, &obj));
Packit Service ae04f2
	for (f = fields, i = 0; f->name != NULL; f++, i++)
Packit Service ae04f2
		CHECK(cfg_parse_obj(pctx, f->type, &obj->value.tuple[i]));
Packit Service ae04f2
Packit Service ae04f2
	*ret = obj;
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	CLEANUP_OBJ(obj);
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj) {
Packit Service ae04f2
	unsigned int i;
Packit Service ae04f2
	const cfg_tuplefielddef_t *fields;
Packit Service ae04f2
	const cfg_tuplefielddef_t *f;
Packit Service ae04f2
	bool need_space = false;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
Packit Service ae04f2
	fields = obj->type->of;
Packit Service ae04f2
Packit Service ae04f2
	for (f = fields, i = 0; f->name != NULL; f++, i++) {
Packit Service ae04f2
		const cfg_obj_t *fieldobj = obj->value.tuple[i];
Packit Service ae04f2
		if (need_space && fieldobj->type->rep != &cfg_rep_void)
Packit Service ae04f2
			cfg_print_cstr(pctx, " ");
Packit Service ae04f2
		cfg_print_obj(pctx, fieldobj);
Packit Service ae04f2
		need_space = (need_space ||
Packit Service ae04f2
			      fieldobj->type->print != cfg_print_void);
Packit Service ae04f2
	}
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_doc_tuple(cfg_printer_t *pctx, const cfg_type_t *type) {
Packit Service ae04f2
	const cfg_tuplefielddef_t *fields;
Packit Service ae04f2
	const cfg_tuplefielddef_t *f;
Packit Service ae04f2
	bool need_space = false;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
Packit Service ae04f2
	fields = type->of;
Packit Service ae04f2
Packit Service ae04f2
	for (f = fields; f->name != NULL; f++) {
Packit Service ae04f2
		if (need_space)
Packit Service ae04f2
			cfg_print_cstr(pctx, " ");
Packit Service ae04f2
		cfg_doc_obj(pctx, f->type);
Packit Service ae04f2
		need_space = (f->type->print != cfg_print_void);
Packit Service ae04f2
	}
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj) {
Packit Service ae04f2
	unsigned int i;
Packit Service ae04f2
	const cfg_tuplefielddef_t *fields = obj->type->of;
Packit Service ae04f2
	const cfg_tuplefielddef_t *f;
Packit Service ae04f2
	unsigned int nfields = 0;
Packit Service ae04f2
Packit Service ae04f2
	if (obj->value.tuple == NULL)
Packit Service ae04f2
		return;
Packit Service ae04f2
Packit Service ae04f2
	for (f = fields, i = 0; f->name != NULL; f++, i++) {
Packit Service ae04f2
		CLEANUP_OBJ(obj->value.tuple[i]);
Packit Service ae04f2
		nfields++;
Packit Service ae04f2
	}
Packit Service ae04f2
	isc_mem_put(pctx->mctx, obj->value.tuple,
Packit Service ae04f2
		    nfields * sizeof(cfg_obj_t *));
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
bool
Packit Service ae04f2
cfg_obj_istuple(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
	return (obj->type->rep == &cfg_rep_tuple);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
const cfg_obj_t *
Packit Service ae04f2
cfg_tuple_get(const cfg_obj_t *tupleobj, const char* name) {
Packit Service ae04f2
	unsigned int i;
Packit Service ae04f2
	const cfg_tuplefielddef_t *fields;
Packit Service ae04f2
	const cfg_tuplefielddef_t *f;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(tupleobj != NULL && tupleobj->type->rep == &cfg_rep_tuple);
Packit Service ae04f2
	REQUIRE(name != NULL);
Packit Service ae04f2
Packit Service ae04f2
	fields = tupleobj->type->of;
Packit Service ae04f2
	for (f = fields, i = 0; f->name != NULL; f++, i++) {
Packit Service ae04f2
		if (strcmp(f->name, name) == 0)
Packit Service ae04f2
			return (tupleobj->value.tuple[i]);
Packit Service ae04f2
	}
Packit Service ae04f2
	INSIST(0);
Packit Service ae04f2
	ISC_UNREACHABLE();
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_special(cfg_parser_t *pctx, int special) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_gettoken(pctx, 0));
Packit Service ae04f2
	if (pctx->token.type == isc_tokentype_special &&
Packit Service ae04f2
	    pctx->token.value.as_char == special)
Packit Service ae04f2
		return (ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
	cfg_parser_error(pctx, CFG_LOG_NEAR, "'%c' expected", special);
Packit Service ae04f2
	return (ISC_R_UNEXPECTEDTOKEN);
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Parse a required semicolon.  If it is not there, log
Packit Service ae04f2
 * an error and increment the error count but continue
Packit Service ae04f2
 * parsing.  Since the next token is pushed back,
Packit Service ae04f2
 * care must be taken to make sure it is eventually
Packit Service ae04f2
 * consumed or an infinite loop may result.
Packit Service ae04f2
 */
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
parse_semicolon(cfg_parser_t *pctx) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_gettoken(pctx, 0));
Packit Service ae04f2
	if (pctx->token.type == isc_tokentype_special &&
Packit Service ae04f2
	    pctx->token.value.as_char == ';')
Packit Service ae04f2
		return (ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
	cfg_parser_error(pctx, CFG_LOG_BEFORE, "missing ';'");
Packit Service ae04f2
	cfg_ungettoken(pctx);
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Parse EOF, logging and returning an error if not there.
Packit Service ae04f2
 */
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
parse_eof(cfg_parser_t *pctx) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_gettoken(pctx, 0));
Packit Service ae04f2
Packit Service ae04f2
	if (pctx->token.type == isc_tokentype_eof)
Packit Service ae04f2
		return (ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
	cfg_parser_error(pctx, CFG_LOG_NEAR, "syntax error");
Packit Service ae04f2
	return (ISC_R_UNEXPECTEDTOKEN);
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/* A list of files, used internally for pctx->files. */
Packit Service ae04f2
Packit Service ae04f2
static cfg_type_t cfg_type_filelist = {
Packit Service ae04f2
	"filelist", NULL, print_list, NULL, &cfg_rep_list,
Packit Service ae04f2
	&cfg_type_qstring
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	cfg_parser_t *pctx;
Packit Service ae04f2
	isc_lexspecials_t specials;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(mctx != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	pctx = isc_mem_get(mctx, sizeof(*pctx));
Packit Service ae04f2
	if (pctx == NULL)
Packit Service ae04f2
		return (ISC_R_NOMEMORY);
Packit Service ae04f2
Packit Service ae04f2
	pctx->mctx = NULL;
Packit Service ae04f2
	isc_mem_attach(mctx, &pctx->mctx);
Packit Service ae04f2
Packit Service ae04f2
	result = isc_refcount_init(&pctx->references, 1);
Packit Service ae04f2
	if (result != ISC_R_SUCCESS) {
Packit Service ae04f2
		isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx));
Packit Service ae04f2
		return (result);
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	pctx->lctx = lctx;
Packit Service ae04f2
	pctx->lexer = NULL;
Packit Service ae04f2
	pctx->seen_eof = false;
Packit Service ae04f2
	pctx->ungotten = false;
Packit Service ae04f2
	pctx->errors = 0;
Packit Service ae04f2
	pctx->warnings = 0;
Packit Service ae04f2
	pctx->open_files = NULL;
Packit Service ae04f2
	pctx->closed_files = NULL;
Packit Service ae04f2
	pctx->line = 0;
Packit Service ae04f2
	pctx->callback = NULL;
Packit Service ae04f2
	pctx->callbackarg = NULL;
Packit Service ae04f2
	pctx->token.type = isc_tokentype_unknown;
Packit Service ae04f2
	pctx->flags = 0;
Packit Service ae04f2
	pctx->buf_name = NULL;
Packit Service ae04f2
Packit Service ae04f2
	memset(specials, 0, sizeof(specials));
Packit Service ae04f2
	specials['{'] = 1;
Packit Service ae04f2
	specials['}'] = 1;
Packit Service ae04f2
	specials[';'] = 1;
Packit Service ae04f2
	specials['/'] = 1;
Packit Service ae04f2
	specials['"'] = 1;
Packit Service ae04f2
	specials['!'] = 1;
Packit Service ae04f2
Packit Service ae04f2
	CHECK(isc_lex_create(pctx->mctx, 1024, &pctx->lexer));
Packit Service ae04f2
Packit Service ae04f2
	isc_lex_setspecials(pctx->lexer, specials);
Packit Service ae04f2
	isc_lex_setcomments(pctx->lexer, (ISC_LEXCOMMENT_C |
Packit Service ae04f2
					 ISC_LEXCOMMENT_CPLUSPLUS |
Packit Service ae04f2
					 ISC_LEXCOMMENT_SHELL));
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->open_files));
Packit Service ae04f2
	CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->closed_files));
Packit Service ae04f2
Packit Service ae04f2
	*ret = pctx;
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	if (pctx->lexer != NULL)
Packit Service ae04f2
		isc_lex_destroy(&pctx->lexer);
Packit Service ae04f2
	CLEANUP_OBJ(pctx->open_files);
Packit Service ae04f2
	CLEANUP_OBJ(pctx->closed_files);
Packit Service ae04f2
	isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx));
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
parser_openfile(cfg_parser_t *pctx, const char *filename) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	cfg_listelt_t *elt = NULL;
Packit Service ae04f2
	cfg_obj_t *stringobj = NULL;
Packit Service ae04f2
Packit Service ae04f2
	result = isc_lex_openfile(pctx->lexer, filename);
Packit Service ae04f2
	if (result != ISC_R_SUCCESS) {
Packit Service ae04f2
		cfg_parser_error(pctx, 0, "open: %s: %s",
Packit Service ae04f2
			     filename, isc_result_totext(result));
Packit Service ae04f2
		goto cleanup;
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	CHECK(create_string(pctx, filename, &cfg_type_qstring, &stringobj));
Packit Service ae04f2
	CHECK(create_listelt(pctx, &elt));
Packit Service ae04f2
	elt->obj = stringobj;
Packit Service ae04f2
	ISC_LIST_APPEND(pctx->open_files->value.list, elt, link);
Packit Service ae04f2
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	CLEANUP_OBJ(stringobj);
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_parser_setcallback(cfg_parser_t *pctx,
Packit Service ae04f2
		       cfg_parsecallback_t callback,
Packit Service ae04f2
		       void *arg)
Packit Service ae04f2
{
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
Packit Service ae04f2
	pctx->callback = callback;
Packit Service ae04f2
	pctx->callbackarg = arg;
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_parser_reset(cfg_parser_t *pctx) {
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
Packit Service ae04f2
	if (pctx->lexer != NULL)
Packit Service ae04f2
		isc_lex_close(pctx->lexer);
Packit Service ae04f2
Packit Service ae04f2
	pctx->seen_eof = false;
Packit Service ae04f2
	pctx->ungotten = false;
Packit Service ae04f2
	pctx->errors = 0;
Packit Service ae04f2
	pctx->warnings = 0;
Packit Service ae04f2
	pctx->line = 0;
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Parse a configuration using a pctx where a lexer has already
Packit Service ae04f2
 * been set up with a source.
Packit Service ae04f2
 */
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
parse2(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	cfg_obj_t *obj = NULL;
Packit Service ae04f2
Packit Service ae04f2
	result = cfg_parse_obj(pctx, type, &obj);
Packit Service ae04f2
Packit Service ae04f2
	if (pctx->errors != 0) {
Packit Service ae04f2
		/* Errors have been logged. */
Packit Service ae04f2
		if (result == ISC_R_SUCCESS)
Packit Service ae04f2
			result = ISC_R_FAILURE;
Packit Service ae04f2
		goto cleanup;
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	if (result != ISC_R_SUCCESS) {
Packit Service ae04f2
		/* Parsing failed but no errors have been logged. */
Packit Service ae04f2
		cfg_parser_error(pctx, 0, "parsing failed: %s",
Packit Service ae04f2
				 isc_result_totext(result));
Packit Service ae04f2
		goto cleanup;
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	CHECK(parse_eof(pctx));
Packit Service ae04f2
Packit Service ae04f2
	*ret = obj;
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	CLEANUP_OBJ(obj);
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_file(cfg_parser_t *pctx, const char *filename,
Packit Service ae04f2
	       const cfg_type_t *type, cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	cfg_listelt_t *elt;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(filename != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(parser_openfile(pctx, filename));
Packit Service ae04f2
Packit Service ae04f2
	result = parse2(pctx, type, ret);
Packit Service ae04f2
Packit Service ae04f2
	/* Clean up the opened file */
Packit Service ae04f2
	elt = ISC_LIST_TAIL(pctx->open_files->value.list);
Packit Service ae04f2
	INSIST(elt != NULL);
Packit Service ae04f2
	ISC_LIST_UNLINK(pctx->open_files->value.list, elt, link);
Packit Service ae04f2
	ISC_LIST_APPEND(pctx->closed_files->value.list, elt, link);
Packit Service ae04f2
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer,
Packit Service ae04f2
	const cfg_type_t *type, cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	return (cfg_parse_buffer4(pctx, buffer, NULL, 0, type, 0, ret));
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_buffer2(cfg_parser_t *pctx, isc_buffer_t *buffer,
Packit Service ae04f2
		  const char *file, const cfg_type_t *type,
Packit Service ae04f2
		  cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	return (cfg_parse_buffer4(pctx, buffer, file, 0, type, 0, ret));
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_buffer3(cfg_parser_t *pctx, isc_buffer_t *buffer,
Packit Service ae04f2
		  const char *file, unsigned int line,
Packit Service ae04f2
		  const cfg_type_t *type, cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	return (cfg_parse_buffer4(pctx, buffer, file, line, type, 0, ret));
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_buffer4(cfg_parser_t *pctx, isc_buffer_t *buffer,
Packit Service ae04f2
		  const char *file, unsigned int line,
Packit Service ae04f2
		  const cfg_type_t *type, unsigned int flags,
Packit Service ae04f2
		  cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
	REQUIRE(buffer != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
	REQUIRE((flags & ~(CFG_PCTX_NODEPRECATED)) == 0);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(isc_lex_openbuffer(pctx->lexer, buffer));
Packit Service ae04f2
Packit Service ae04f2
	pctx->buf_name = file;
Packit Service ae04f2
	pctx->flags = flags;
Packit Service ae04f2
Packit Service ae04f2
	if (line != 0U)
Packit Service ae04f2
		CHECK(isc_lex_setsourceline(pctx->lexer, line));
Packit Service ae04f2
Packit Service ae04f2
	CHECK(parse2(pctx, type, ret));
Packit Service ae04f2
	pctx->buf_name = NULL;
Packit Service ae04f2
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_parser_attach(cfg_parser_t *src, cfg_parser_t **dest) {
Packit Service ae04f2
	REQUIRE(src != NULL);
Packit Service ae04f2
	REQUIRE(dest != NULL && *dest == NULL);
Packit Service ae04f2
Packit Service ae04f2
	isc_refcount_increment(&src->references, NULL);
Packit Service ae04f2
	*dest = src;
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_parser_destroy(cfg_parser_t **pctxp) {
Packit Service ae04f2
	cfg_parser_t *pctx;
Packit Service ae04f2
	unsigned int refs;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctxp != NULL && *pctxp != NULL);
Packit Service ae04f2
Packit Service ae04f2
	pctx = *pctxp;
Packit Service ae04f2
	*pctxp = NULL;
Packit Service ae04f2
Packit Service ae04f2
	isc_refcount_decrement(&pctx->references, &refs);
Packit Service ae04f2
	if (refs == 0) {
Packit Service ae04f2
		isc_lex_destroy(&pctx->lexer);
Packit Service ae04f2
		/*
Packit Service ae04f2
		 * Cleaning up open_files does not
Packit Service ae04f2
		 * close the files; that was already done
Packit Service ae04f2
		 * by closing the lexer.
Packit Service ae04f2
		 */
Packit Service ae04f2
		CLEANUP_OBJ(pctx->open_files);
Packit Service ae04f2
		CLEANUP_OBJ(pctx->closed_files);
Packit Service ae04f2
		isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx));
Packit Service ae04f2
	}
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * void
Packit Service ae04f2
 */
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_void(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	UNUSED(type);
Packit Service ae04f2
Packit Service ae04f2
	return (cfg_create_obj(pctx, &cfg_type_void, ret));
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_void(cfg_printer_t *pctx, const cfg_obj_t *obj) {
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
Packit Service ae04f2
	UNUSED(pctx);
Packit Service ae04f2
	UNUSED(obj);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type) {
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
Packit Service ae04f2
	UNUSED(pctx);
Packit Service ae04f2
	UNUSED(type);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
bool
Packit Service ae04f2
cfg_obj_isvoid(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
	return (obj->type->rep == &cfg_rep_void);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_void = {
Packit Service ae04f2
	"void", cfg_parse_void, cfg_print_void, cfg_doc_void, &cfg_rep_void,
Packit Service ae04f2
	NULL };
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * percentage
Packit Service ae04f2
 */
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_percentage(cfg_parser_t *pctx, const cfg_type_t *type,
Packit Service ae04f2
		     cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	char *endp;
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	cfg_obj_t *obj = NULL;
Packit Service ae04f2
	uint64_t percent;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	UNUSED(type);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_gettoken(pctx, 0));
Packit Service ae04f2
	if (pctx->token.type != isc_tokentype_string) {
Packit Service ae04f2
		cfg_parser_error(pctx, CFG_LOG_NEAR,
Packit Service ae04f2
				 "expected percentage");
Packit Service ae04f2
		return (ISC_R_UNEXPECTEDTOKEN);
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	percent = isc_string_touint64(TOKEN_STRING(pctx), &endp, 10);
Packit Service ae04f2
	if (*endp != '%' || *(endp+1) != 0) {
Packit Service ae04f2
		cfg_parser_error(pctx, CFG_LOG_NEAR,
Packit Service ae04f2
				 "expected percentage");
Packit Service ae04f2
		return (ISC_R_UNEXPECTEDTOKEN);
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_create_obj(pctx, &cfg_type_percentage, &obj));
Packit Service ae04f2
	obj->value.uint32 = (uint32_t)percent;
Packit Service ae04f2
	*ret = obj;
Packit Service ae04f2
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_percentage(cfg_printer_t *pctx, const cfg_obj_t *obj) {
Packit Service ae04f2
	char buf[64];
Packit Service ae04f2
	int n;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
Packit Service ae04f2
	n = snprintf(buf, sizeof(buf), "%u%%", obj->value.uint32);
Packit Service ae04f2
	INSIST(n > 0 && (size_t)n < sizeof(buf));
Packit Service ae04f2
	cfg_print_chars(pctx, buf, strlen(buf));
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
uint32_t
Packit Service ae04f2
cfg_obj_aspercentage(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_percentage);
Packit Service ae04f2
	return (obj->value.uint32);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_percentage = {
Packit Service ae04f2
	"percentage", cfg_parse_percentage, cfg_print_percentage,
Packit Service ae04f2
	cfg_doc_terminal, &cfg_rep_percentage, NULL
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
bool
Packit Service ae04f2
cfg_obj_ispercentage(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
	return (obj->type->rep == &cfg_rep_percentage);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Fixed point
Packit Service ae04f2
 */
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_fixedpoint(cfg_parser_t *pctx, const cfg_type_t *type,
Packit Service ae04f2
		     cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	cfg_obj_t *obj = NULL;
Packit Service ae04f2
	size_t n1, n2, n3, l;
Packit Service ae04f2
	const char *p;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	UNUSED(type);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_gettoken(pctx, 0));
Packit Service ae04f2
	if (pctx->token.type != isc_tokentype_string) {
Packit Service ae04f2
		cfg_parser_error(pctx, CFG_LOG_NEAR,
Packit Service ae04f2
				 "expected fixed point number");
Packit Service ae04f2
		return (ISC_R_UNEXPECTEDTOKEN);
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
Packit Service ae04f2
	p = TOKEN_STRING(pctx);
Packit Service ae04f2
	l = strlen(p);
Packit Service ae04f2
	n1 = strspn(p, "0123456789");
Packit Service ae04f2
	n2 = strspn(p + n1, ".");
Packit Service ae04f2
	n3 = strspn(p + n1 + n2, "0123456789");
Packit Service ae04f2
Packit Service ae04f2
	if ((n1 + n2 + n3 != l) || (n1 + n3 == 0) ||
Packit Service ae04f2
	    n1 > 5 || n2 > 1 || n3 > 2) {
Packit Service ae04f2
		cfg_parser_error(pctx, CFG_LOG_NEAR,
Packit Service ae04f2
				 "expected fixed point number");
Packit Service ae04f2
		return (ISC_R_UNEXPECTEDTOKEN);
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_create_obj(pctx, &cfg_type_fixedpoint, &obj));
Packit Service ae04f2
Packit Service ae04f2
	obj->value.uint32 = strtoul(p, NULL, 10) * 100;
Packit Service ae04f2
	switch (n3) {
Packit Service ae04f2
	case 2:
Packit Service ae04f2
		obj->value.uint32 += strtoul(p + n1 + n2, NULL, 10);
Packit Service ae04f2
		break;
Packit Service ae04f2
	case 1:
Packit Service ae04f2
		obj->value.uint32 += strtoul(p + n1 + n2, NULL, 10) * 10;
Packit Service ae04f2
		break;
Packit Service ae04f2
	}
Packit Service ae04f2
	*ret = obj;
Packit Service ae04f2
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_fixedpoint(cfg_printer_t *pctx, const cfg_obj_t *obj) {
Packit Service ae04f2
	char buf[64];
Packit Service ae04f2
	int n;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
Packit Service ae04f2
	n = snprintf(buf, sizeof(buf), "%u.%02u",
Packit Service ae04f2
		     obj->value.uint32/100, obj->value.uint32%100);
Packit Service ae04f2
	INSIST(n > 0 && (size_t)n < sizeof(buf));
Packit Service ae04f2
	cfg_print_chars(pctx, buf, strlen(buf));
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
uint32_t
Packit Service ae04f2
cfg_obj_asfixedpoint(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_fixedpoint);
Packit Service ae04f2
	return (obj->value.uint32);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_fixedpoint = {
Packit Service ae04f2
	"fixedpoint", cfg_parse_fixedpoint, cfg_print_fixedpoint,
Packit Service ae04f2
	cfg_doc_terminal, &cfg_rep_fixedpoint, NULL
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
bool
Packit Service ae04f2
cfg_obj_isfixedpoint(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
	return (obj->type->rep == &cfg_rep_fixedpoint);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * uint32
Packit Service ae04f2
 */
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_uint32(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	cfg_obj_t *obj = NULL;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	UNUSED(type);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
Packit Service ae04f2
	if (pctx->token.type != isc_tokentype_number) {
Packit Service ae04f2
		cfg_parser_error(pctx, CFG_LOG_NEAR, "expected number");
Packit Service ae04f2
		return (ISC_R_UNEXPECTEDTOKEN);
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_create_obj(pctx, &cfg_type_uint32, &obj));
Packit Service ae04f2
Packit Service ae04f2
	obj->value.uint32 = pctx->token.value.as_ulong;
Packit Service ae04f2
	*ret = obj;
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_cstr(cfg_printer_t *pctx, const char *s) {
Packit Service ae04f2
	cfg_print_chars(pctx, s, strlen(s));
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_rawuint(cfg_printer_t *pctx, unsigned int u) {
Packit Service ae04f2
	char buf[32];
Packit Service ae04f2
Packit Service ae04f2
	snprintf(buf, sizeof(buf), "%u", u);
Packit Service ae04f2
	cfg_print_cstr(pctx, buf);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_uint32(cfg_printer_t *pctx, const cfg_obj_t *obj) {
Packit Service ae04f2
	cfg_print_rawuint(pctx, obj->value.uint32);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
bool
Packit Service ae04f2
cfg_obj_isuint32(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
	return (obj->type->rep == &cfg_rep_uint32);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
uint32_t
Packit Service ae04f2
cfg_obj_asuint32(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint32);
Packit Service ae04f2
	return (obj->value.uint32);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_uint32 = {
Packit Service ae04f2
	"integer", cfg_parse_uint32, cfg_print_uint32, cfg_doc_terminal,
Packit Service ae04f2
	&cfg_rep_uint32, NULL
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * uint64
Packit Service ae04f2
 */
Packit Service ae04f2
bool
Packit Service ae04f2
cfg_obj_isuint64(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
	return (obj->type->rep == &cfg_rep_uint64);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
uint64_t
Packit Service ae04f2
cfg_obj_asuint64(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint64);
Packit Service ae04f2
	return (obj->value.uint64);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_uint64(cfg_printer_t *pctx, const cfg_obj_t *obj) {
Packit Service ae04f2
	char buf[32];
Packit Service ae04f2
Packit Service ae04f2
	snprintf(buf, sizeof(buf), "%" PRIu64,
Packit Service ae04f2
		 obj->value.uint64);
Packit Service ae04f2
	cfg_print_cstr(pctx, buf);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_uint64 = {
Packit Service ae04f2
	"64_bit_integer", NULL, cfg_print_uint64, cfg_doc_terminal,
Packit Service ae04f2
	&cfg_rep_uint64, NULL
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * qstring (quoted string), ustring (unquoted string), astring
Packit Service ae04f2
 * (any string)
Packit Service ae04f2
 */
Packit Service ae04f2
Packit Service ae04f2
/* Create a string object from a null-terminated C string. */
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type,
Packit Service ae04f2
	      cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	cfg_obj_t *obj = NULL;
Packit Service ae04f2
	int len;
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_create_obj(pctx, type, &obj));
Packit Service ae04f2
	len = strlen(contents);
Packit Service ae04f2
	obj->value.string.length = len;
Packit Service ae04f2
	obj->value.string.base = isc_mem_get(pctx->mctx, len + 1);
Packit Service ae04f2
	if (obj->value.string.base == 0) {
Packit Service ae04f2
		isc_mem_put(pctx->mctx, obj, sizeof(*obj));
Packit Service ae04f2
		return (ISC_R_NOMEMORY);
Packit Service ae04f2
	}
Packit Service ae04f2
	memmove(obj->value.string.base, contents, len);
Packit Service ae04f2
	obj->value.string.base[len] = '\0';
Packit Service ae04f2
Packit Service ae04f2
	*ret = obj;
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	UNUSED(type);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
Packit Service ae04f2
	if (pctx->token.type != isc_tokentype_qstring) {
Packit Service ae04f2
		cfg_parser_error(pctx, CFG_LOG_NEAR, "expected quoted string");
Packit Service ae04f2
		return (ISC_R_UNEXPECTEDTOKEN);
Packit Service ae04f2
	}
Packit Service ae04f2
	return (create_string(pctx, TOKEN_STRING(pctx),
Packit Service ae04f2
			      &cfg_type_qstring, ret));
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
parse_ustring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	UNUSED(type);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_gettoken(pctx, 0));
Packit Service ae04f2
	if (pctx->token.type != isc_tokentype_string) {
Packit Service ae04f2
		cfg_parser_error(pctx, CFG_LOG_NEAR, "expected unquoted string");
Packit Service ae04f2
		return (ISC_R_UNEXPECTEDTOKEN);
Packit Service ae04f2
	}
Packit Service ae04f2
	return (create_string(pctx,
Packit Service ae04f2
			      TOKEN_STRING(pctx),
Packit Service ae04f2
			      &cfg_type_ustring,
Packit Service ae04f2
			      ret));
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type,
Packit Service ae04f2
		  cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	UNUSED(type);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_getstringtoken(pctx));
Packit Service ae04f2
	return (create_string(pctx,
Packit Service ae04f2
			      TOKEN_STRING(pctx),
Packit Service ae04f2
			      &cfg_type_qstring,
Packit Service ae04f2
			      ret));
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_sstring(cfg_parser_t *pctx, const cfg_type_t *type,
Packit Service ae04f2
		  cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	UNUSED(type);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_getstringtoken(pctx));
Packit Service ae04f2
	return (create_string(pctx,
Packit Service ae04f2
			      TOKEN_STRING(pctx),
Packit Service ae04f2
			      &cfg_type_sstring,
Packit Service ae04f2
			      ret));
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
parse_btext(cfg_parser_t *pctx, const cfg_type_t *type,
Packit Service ae04f2
	    cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	UNUSED(type);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_gettoken(pctx, ISC_LEXOPT_BTEXT));
Packit Service ae04f2
	if (pctx->token.type != isc_tokentype_btext) {
Packit Service ae04f2
		cfg_parser_error(pctx, CFG_LOG_NEAR,
Packit Service ae04f2
				 "expected bracketed text");
Packit Service ae04f2
		return (ISC_R_UNEXPECTEDTOKEN);
Packit Service ae04f2
	}
Packit Service ae04f2
	return (create_string(pctx,
Packit Service ae04f2
			      TOKEN_STRING(pctx),
Packit Service ae04f2
			      &cfg_type_bracketed_text,
Packit Service ae04f2
			      ret));
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
print_btext(cfg_printer_t *pctx, const cfg_obj_t *obj) {
Packit Service ae04f2
	/*
Packit Service ae04f2
	 * We need to print "{" instead of running print_open()
Packit Service ae04f2
	 * in order to preserve the exact original formatting
Packit Service ae04f2
	 * of the bracketed text. But we increment the indent value
Packit Service ae04f2
	 * so that print_close() will leave us back in our original
Packit Service ae04f2
	 * state.
Packit Service ae04f2
	 */
Packit Service ae04f2
	pctx->indent++;
Packit Service ae04f2
	cfg_print_cstr(pctx, "{");
Packit Service ae04f2
	cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length);
Packit Service ae04f2
	print_close(pctx);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
doc_btext(cfg_printer_t *pctx, const cfg_type_t *type) {
Packit Service ae04f2
	UNUSED(type);
Packit Service ae04f2
Packit Service ae04f2
	cfg_print_cstr(pctx, "{ <unspecified-text> }");
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
Packit Service ae04f2
bool
Packit Service ae04f2
cfg_is_enum(const char *s, const char *const *enums) {
Packit Service ae04f2
	const char * const *p;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(s != NULL);
Packit Service ae04f2
	REQUIRE(enums != NULL);
Packit Service ae04f2
Packit Service ae04f2
	for (p = enums; *p != NULL; p++) {
Packit Service ae04f2
		if (strcasecmp(*p, s) == 0)
Packit Service ae04f2
			return (true);
Packit Service ae04f2
	}
Packit Service ae04f2
	return (false);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
check_enum(cfg_parser_t *pctx, cfg_obj_t *obj, const char *const *enums) {
Packit Service ae04f2
	const char *s = obj->value.string.base;
Packit Service ae04f2
Packit Service ae04f2
	if (cfg_is_enum(s, enums))
Packit Service ae04f2
		return (ISC_R_SUCCESS);
Packit Service ae04f2
	cfg_parser_error(pctx, 0, "'%s' unexpected", s);
Packit Service ae04f2
	return (ISC_R_UNEXPECTEDTOKEN);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	cfg_obj_t *obj = NULL;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(parse_ustring(pctx, NULL, &obj));
Packit Service ae04f2
	CHECK(check_enum(pctx, obj, type->of));
Packit Service ae04f2
	*ret = obj;
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	CLEANUP_OBJ(obj);
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) {
Packit Service ae04f2
	const char * const *p;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
Packit Service ae04f2
	cfg_print_cstr(pctx, "( ");
Packit Service ae04f2
	for (p = type->of; *p != NULL; p++) {
Packit Service ae04f2
		cfg_print_cstr(pctx, *p);
Packit Service ae04f2
		if (p[1] != NULL)
Packit Service ae04f2
			cfg_print_cstr(pctx, " | ");
Packit Service ae04f2
	}
Packit Service ae04f2
	cfg_print_cstr(pctx, " )");
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_ustring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
Packit Service ae04f2
	cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
print_qstring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
Packit Service ae04f2
	cfg_print_cstr(pctx, "\"");
Packit Service ae04f2
	for (size_t i = 0; i < obj->value.string.length; i++) {
Packit Service ae04f2
		if (obj->value.string.base[i] == '"') {
Packit Service ae04f2
			cfg_print_cstr(pctx, "\\");
Packit Service ae04f2
		}
Packit Service ae04f2
		cfg_print_chars(pctx, &obj->value.string.base[i], 1);
Packit Service ae04f2
	}
Packit Service ae04f2
	cfg_print_cstr(pctx, "\"");
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
print_sstring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
Packit Service ae04f2
	cfg_print_cstr(pctx, "\"");
Packit Service ae04f2
	if ((pctx->flags & CFG_PRINTER_XKEY) != 0) {
Packit Service ae04f2
		unsigned int len = obj->value.string.length;
Packit Service ae04f2
		while (len-- > 0)
Packit Service ae04f2
			cfg_print_cstr(pctx, "?");
Packit Service ae04f2
	} else
Packit Service ae04f2
		cfg_print_ustring(pctx, obj);
Packit Service ae04f2
	cfg_print_cstr(pctx, "\"");
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
free_string(cfg_parser_t *pctx, cfg_obj_t *obj) {
Packit Service ae04f2
	isc_mem_put(pctx->mctx, obj->value.string.base,
Packit Service ae04f2
		    obj->value.string.length + 1);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
bool
Packit Service ae04f2
cfg_obj_isstring(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
	return (obj->type->rep == &cfg_rep_string);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
const char *
Packit Service ae04f2
cfg_obj_asstring(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_string);
Packit Service ae04f2
	return (obj->value.string.base);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/* Quoted string only */
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_qstring = {
Packit Service ae04f2
	"quoted_string", cfg_parse_qstring, print_qstring, cfg_doc_terminal,
Packit Service ae04f2
	&cfg_rep_string, NULL
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
/* Unquoted string only */
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_ustring = {
Packit Service ae04f2
	"string", parse_ustring, cfg_print_ustring, cfg_doc_terminal,
Packit Service ae04f2
	&cfg_rep_string, NULL
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
/* Any string (quoted or unquoted); printed with quotes */
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_astring = {
Packit Service ae04f2
	"string", cfg_parse_astring, print_qstring, cfg_doc_terminal,
Packit Service ae04f2
	&cfg_rep_string, NULL
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Any string (quoted or unquoted); printed with quotes.
Packit Service ae04f2
 * If CFG_PRINTER_XKEY is set when printing the string will be '?' out.
Packit Service ae04f2
 */
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sstring = {
Packit Service ae04f2
	"string", cfg_parse_sstring, print_sstring, cfg_doc_terminal,
Packit Service ae04f2
	&cfg_rep_string, NULL
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Text enclosed in brackets. Used to pass a block of configuration
Packit Service ae04f2
 * text to dynamic library or external application. Checked for
Packit Service ae04f2
 * bracket balance, but not otherwise parsed.
Packit Service ae04f2
 */
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bracketed_text = {
Packit Service ae04f2
	"bracketed_text", parse_btext, print_btext, doc_btext,
Packit Service ae04f2
	&cfg_rep_string, NULL
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Booleans
Packit Service ae04f2
 */
Packit Service ae04f2
Packit Service ae04f2
bool
Packit Service ae04f2
cfg_obj_isboolean(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
	return (obj->type->rep == &cfg_rep_boolean);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
bool
Packit Service ae04f2
cfg_obj_asboolean(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_boolean);
Packit Service ae04f2
	return (obj->value.boolean);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	bool value;
Packit Service ae04f2
	cfg_obj_t *obj = NULL;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	UNUSED(type);
Packit Service ae04f2
Packit Service ae04f2
	result = cfg_gettoken(pctx, 0);
Packit Service ae04f2
	if (result != ISC_R_SUCCESS)
Packit Service ae04f2
		return (result);
Packit Service ae04f2
Packit Service ae04f2
	if (pctx->token.type != isc_tokentype_string)
Packit Service ae04f2
		goto bad_boolean;
Packit Service ae04f2
Packit Service ae04f2
	if ((strcasecmp(TOKEN_STRING(pctx), "true") == 0) ||
Packit Service ae04f2
	    (strcasecmp(TOKEN_STRING(pctx), "yes") == 0) ||
Packit Service ae04f2
	    (strcmp(TOKEN_STRING(pctx), "1") == 0)) {
Packit Service ae04f2
		value = true;
Packit Service ae04f2
	} else if ((strcasecmp(TOKEN_STRING(pctx), "false") == 0) ||
Packit Service ae04f2
		   (strcasecmp(TOKEN_STRING(pctx), "no") == 0) ||
Packit Service ae04f2
		   (strcmp(TOKEN_STRING(pctx), "0") == 0)) {
Packit Service ae04f2
		value = false;
Packit Service ae04f2
	} else {
Packit Service ae04f2
		goto bad_boolean;
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_create_obj(pctx, &cfg_type_boolean, &obj));
Packit Service ae04f2
	obj->value.boolean = value;
Packit Service ae04f2
	*ret = obj;
Packit Service ae04f2
	return (result);
Packit Service ae04f2
Packit Service ae04f2
 bad_boolean:
Packit Service ae04f2
	cfg_parser_error(pctx, CFG_LOG_NEAR, "boolean expected");
Packit Service ae04f2
	return (ISC_R_UNEXPECTEDTOKEN);
Packit Service ae04f2
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
Packit Service ae04f2
	if (obj->value.boolean)
Packit Service ae04f2
		cfg_print_cstr(pctx, "yes");
Packit Service ae04f2
	else
Packit Service ae04f2
		cfg_print_cstr(pctx, "no");
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_boolean = {
Packit Service ae04f2
	"boolean", cfg_parse_boolean, cfg_print_boolean, cfg_doc_terminal,
Packit Service ae04f2
	&cfg_rep_boolean, NULL
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Lists.
Packit Service ae04f2
 */
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **obj) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
	REQUIRE(obj != NULL && *obj == NULL);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_create_obj(pctx, type, obj));
Packit Service ae04f2
	ISC_LIST_INIT((*obj)->value.list);
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp) {
Packit Service ae04f2
	cfg_listelt_t *elt;
Packit Service ae04f2
Packit Service ae04f2
	elt = isc_mem_get(pctx->mctx, sizeof(*elt));
Packit Service ae04f2
	if (elt == NULL)
Packit Service ae04f2
		return (ISC_R_NOMEMORY);
Packit Service ae04f2
	elt->obj = NULL;
Packit Service ae04f2
	ISC_LINK_INIT(elt, link);
Packit Service ae04f2
	*eltp = elt;
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
free_listelt(cfg_parser_t *pctx, cfg_listelt_t *elt) {
Packit Service ae04f2
	if (elt->obj != NULL)
Packit Service ae04f2
		cfg_obj_destroy(pctx, &elt->obj);
Packit Service ae04f2
	isc_mem_put(pctx->mctx, elt, sizeof(*elt));
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
free_list(cfg_parser_t *pctx, cfg_obj_t *obj) {
Packit Service ae04f2
	cfg_listelt_t *elt, *next;
Packit Service ae04f2
	for (elt = ISC_LIST_HEAD(obj->value.list);
Packit Service ae04f2
	     elt != NULL;
Packit Service ae04f2
	     elt = next)
Packit Service ae04f2
	{
Packit Service ae04f2
		next = ISC_LIST_NEXT(elt, link);
Packit Service ae04f2
		free_listelt(pctx, elt);
Packit Service ae04f2
	}
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_listelt(cfg_parser_t *pctx, const cfg_type_t *elttype,
Packit Service ae04f2
		  cfg_listelt_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	cfg_listelt_t *elt = NULL;
Packit Service ae04f2
	cfg_obj_t *value = NULL;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(elttype != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(create_listelt(pctx, &elt));
Packit Service ae04f2
Packit Service ae04f2
	result = cfg_parse_obj(pctx, elttype, &value);
Packit Service ae04f2
	if (result != ISC_R_SUCCESS)
Packit Service ae04f2
		goto cleanup;
Packit Service ae04f2
Packit Service ae04f2
	elt->obj = value;
Packit Service ae04f2
Packit Service ae04f2
	*ret = elt;
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	isc_mem_put(pctx->mctx, elt, sizeof(*elt));
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Parse a homogeneous list whose elements are of type 'elttype'
Packit Service ae04f2
 * and where each element is terminated by a semicolon.
Packit Service ae04f2
 */
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
parse_list(cfg_parser_t *pctx, const cfg_type_t *listtype, cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	cfg_obj_t *listobj = NULL;
Packit Service ae04f2
	const cfg_type_t *listof = listtype->of;
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	cfg_listelt_t *elt = NULL;
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_create_list(pctx, listtype, &listobj));
Packit Service ae04f2
Packit Service ae04f2
	for (;;) {
Packit Service ae04f2
		CHECK(cfg_peektoken(pctx, 0));
Packit Service ae04f2
		if (pctx->token.type == isc_tokentype_special &&
Packit Service ae04f2
		    pctx->token.value.as_char == /*{*/ '}')
Packit Service ae04f2
			break;
Packit Service ae04f2
		CHECK(cfg_parse_listelt(pctx, listof, &elt));
Packit Service ae04f2
		CHECK(parse_semicolon(pctx));
Packit Service ae04f2
		ISC_LIST_APPEND(listobj->value.list, elt, link);
Packit Service ae04f2
		elt = NULL;
Packit Service ae04f2
	}
Packit Service ae04f2
	*ret = listobj;
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	if (elt != NULL)
Packit Service ae04f2
		free_listelt(pctx, elt);
Packit Service ae04f2
	CLEANUP_OBJ(listobj);
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
print_list(cfg_printer_t *pctx, const cfg_obj_t *obj) {
Packit Service ae04f2
	const cfg_list_t *list = &obj->value.list;
Packit Service ae04f2
	const cfg_listelt_t *elt;
Packit Service ae04f2
Packit Service ae04f2
	for (elt = ISC_LIST_HEAD(*list);
Packit Service ae04f2
	     elt != NULL;
Packit Service ae04f2
	     elt = ISC_LIST_NEXT(elt, link))
Packit Service ae04f2
	{
Packit Service ae04f2
		if ((pctx->flags & CFG_PRINTER_ONELINE) != 0) {
Packit Service ae04f2
			cfg_print_obj(pctx, elt->obj);
Packit Service ae04f2
			cfg_print_cstr(pctx, "; ");
Packit Service ae04f2
		} else {
Packit Service ae04f2
			cfg_print_indent(pctx);
Packit Service ae04f2
			cfg_print_obj(pctx, elt->obj);
Packit Service ae04f2
			cfg_print_cstr(pctx, ";\n");
Packit Service ae04f2
		}
Packit Service ae04f2
	}
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type,
Packit Service ae04f2
		     cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_parse_special(pctx, '{'));
Packit Service ae04f2
	CHECK(parse_list(pctx, type, ret));
Packit Service ae04f2
	CHECK(cfg_parse_special(pctx, '}'));
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
Packit Service ae04f2
	print_open(pctx);
Packit Service ae04f2
	print_list(pctx, obj);
Packit Service ae04f2
	print_close(pctx);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) {
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
Packit Service ae04f2
	cfg_print_cstr(pctx, "{ ");
Packit Service ae04f2
	cfg_doc_obj(pctx, type->of);
Packit Service ae04f2
	cfg_print_cstr(pctx, "; ... }");
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Parse a homogeneous list whose elements are of type 'elttype'
Packit Service ae04f2
 * and where elements are separated by space.  The list ends
Packit Service ae04f2
 * before the first semicolon.
Packit Service ae04f2
 */
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *listtype,
Packit Service ae04f2
		    cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	cfg_obj_t *listobj = NULL;
Packit Service ae04f2
	const cfg_type_t *listof;
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(listtype != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	listof = listtype->of;
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_create_list(pctx, listtype, &listobj));
Packit Service ae04f2
Packit Service ae04f2
	for (;;) {
Packit Service ae04f2
		cfg_listelt_t *elt = NULL;
Packit Service ae04f2
Packit Service ae04f2
		CHECK(cfg_peektoken(pctx, 0));
Packit Service ae04f2
		if (pctx->token.type == isc_tokentype_special &&
Packit Service ae04f2
		    pctx->token.value.as_char == ';')
Packit Service ae04f2
			break;
Packit Service ae04f2
		CHECK(cfg_parse_listelt(pctx, listof, &elt));
Packit Service ae04f2
		ISC_LIST_APPEND(listobj->value.list, elt, link);
Packit Service ae04f2
	}
Packit Service ae04f2
	*ret = listobj;
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	CLEANUP_OBJ(listobj);
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_spacelist(cfg_printer_t *pctx, const cfg_obj_t *obj) {
Packit Service ae04f2
	const cfg_list_t *list = &obj->value.list;
Packit Service ae04f2
	const cfg_listelt_t *elt;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
Packit Service ae04f2
	for (elt = ISC_LIST_HEAD(*list);
Packit Service ae04f2
	     elt != NULL;
Packit Service ae04f2
	     elt = ISC_LIST_NEXT(elt, link)) {
Packit Service ae04f2
		cfg_print_obj(pctx, elt->obj);
Packit Service ae04f2
		if (ISC_LIST_NEXT(elt, link) != NULL)
Packit Service ae04f2
			cfg_print_cstr(pctx, " ");
Packit Service ae04f2
	}
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
bool
Packit Service ae04f2
cfg_obj_islist(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
	return (obj->type->rep == &cfg_rep_list);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
const cfg_listelt_t *
Packit Service ae04f2
cfg_list_first(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj == NULL || obj->type->rep == &cfg_rep_list);
Packit Service ae04f2
	if (obj == NULL)
Packit Service ae04f2
		return (NULL);
Packit Service ae04f2
	return (ISC_LIST_HEAD(obj->value.list));
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
const cfg_listelt_t *
Packit Service ae04f2
cfg_list_next(const cfg_listelt_t *elt) {
Packit Service ae04f2
	REQUIRE(elt != NULL);
Packit Service ae04f2
	return (ISC_LIST_NEXT(elt, link));
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Return the length of a list object.  If obj is NULL or is not
Packit Service ae04f2
 * a list, return 0.
Packit Service ae04f2
 */
Packit Service ae04f2
unsigned int
Packit Service ae04f2
cfg_list_length(const cfg_obj_t *obj, bool recurse) {
Packit Service ae04f2
	const cfg_listelt_t *elt;
Packit Service ae04f2
	unsigned int count = 0;
Packit Service ae04f2
Packit Service ae04f2
	if (obj == NULL || !cfg_obj_islist(obj))
Packit Service ae04f2
		return (0U);
Packit Service ae04f2
	for (elt = cfg_list_first(obj);
Packit Service ae04f2
	     elt != NULL;
Packit Service ae04f2
	     elt = cfg_list_next(elt)) {
Packit Service ae04f2
		if (recurse && cfg_obj_islist(elt->obj)) {
Packit Service ae04f2
			count += cfg_list_length(elt->obj, recurse);
Packit Service ae04f2
		} else {
Packit Service ae04f2
			count++;
Packit Service ae04f2
		}
Packit Service ae04f2
	}
Packit Service ae04f2
	return (count);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
cfg_obj_t *
Packit Service ae04f2
cfg_listelt_value(const cfg_listelt_t *elt) {
Packit Service ae04f2
	REQUIRE(elt != NULL);
Packit Service ae04f2
	return (elt->obj);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Maps.
Packit Service ae04f2
 */
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Parse a map body.  That's something like
Packit Service ae04f2
 *
Packit Service ae04f2
 *   "foo 1; bar { glub; }; zap true; zap false;"
Packit Service ae04f2
 *
Packit Service ae04f2
 * i.e., a sequence of option names followed by values and
Packit Service ae04f2
 * terminated by semicolons.  Used for the top level of
Packit Service ae04f2
 * the named.conf syntax, as well as for the body of the
Packit Service ae04f2
 * options, view, zone, and other statements.
Packit Service ae04f2
 */
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	const cfg_clausedef_t * const *clausesets;
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	const cfg_clausedef_t * const *clauseset;
Packit Service ae04f2
	const cfg_clausedef_t *clause;
Packit Service ae04f2
	cfg_obj_t *value = NULL;
Packit Service ae04f2
	cfg_obj_t *obj = NULL;
Packit Service ae04f2
	cfg_obj_t *eltobj = NULL;
Packit Service ae04f2
	cfg_obj_t *includename = NULL;
Packit Service ae04f2
	isc_symvalue_t symval;
Packit Service ae04f2
	cfg_list_t *list = NULL;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	clausesets = type->of;
Packit Service ae04f2
Packit Service ae04f2
	CHECK(create_map(pctx, type, &obj));
Packit Service ae04f2
Packit Service ae04f2
	obj->value.map.clausesets = clausesets;
Packit Service ae04f2
Packit Service ae04f2
	for (;;) {
Packit Service ae04f2
		cfg_listelt_t *elt;
Packit Service ae04f2
Packit Service ae04f2
	redo:
Packit Service ae04f2
		/*
Packit Service ae04f2
		 * Parse the option name and see if it is known.
Packit Service ae04f2
		 */
Packit Service ae04f2
		CHECK(cfg_gettoken(pctx, 0));
Packit Service ae04f2
Packit Service ae04f2
		if (pctx->token.type != isc_tokentype_string) {
Packit Service ae04f2
			cfg_ungettoken(pctx);
Packit Service ae04f2
			break;
Packit Service ae04f2
		}
Packit Service ae04f2
Packit Service ae04f2
		/*
Packit Service ae04f2
		 * We accept "include" statements wherever a map body
Packit Service ae04f2
		 * clause can occur.
Packit Service ae04f2
		 */
Packit Service ae04f2
		if (strcasecmp(TOKEN_STRING(pctx), "include") == 0) {
Packit Service ae04f2
			/*
Packit Service ae04f2
			 * Turn the file name into a temporary configuration
Packit Service ae04f2
			 * object just so that it is not overwritten by the
Packit Service ae04f2
			 * semicolon token.
Packit Service ae04f2
			 */
Packit Service ae04f2
			CHECK(cfg_parse_obj(pctx, &cfg_type_qstring, &includename));
Packit Service ae04f2
			CHECK(parse_semicolon(pctx));
Packit Service ae04f2
			CHECK(parser_openfile(pctx, includename->
Packit Service ae04f2
					      value.string.base));
Packit Service ae04f2
			 cfg_obj_destroy(pctx, &includename);
Packit Service ae04f2
			 goto redo;
Packit Service ae04f2
		}
Packit Service ae04f2
Packit Service ae04f2
		clause = NULL;
Packit Service ae04f2
		for (clauseset = clausesets; *clauseset != NULL; clauseset++) {
Packit Service ae04f2
			for (clause = *clauseset;
Packit Service ae04f2
			     clause->name != NULL;
Packit Service ae04f2
			     clause++) {
Packit Service ae04f2
				if (strcasecmp(TOKEN_STRING(pctx),
Packit Service ae04f2
					   clause->name) == 0)
Packit Service ae04f2
					goto done;
Packit Service ae04f2
			}
Packit Service ae04f2
		}
Packit Service ae04f2
	done:
Packit Service ae04f2
		if (clause == NULL || clause->name == NULL) {
Packit Service ae04f2
			cfg_parser_error(pctx, CFG_LOG_NOPREP,
Packit Service ae04f2
					 "unknown option");
Packit Service ae04f2
			/*
Packit Service ae04f2
			 * Try to recover by parsing this option as an unknown
Packit Service ae04f2
			 * option and discarding it.
Packit Service ae04f2
			 */
Packit Service ae04f2
			CHECK(cfg_parse_obj(pctx, &cfg_type_unsupported,
Packit Service ae04f2
					    &eltobj));
Packit Service ae04f2
			cfg_obj_destroy(pctx, &eltobj);
Packit Service ae04f2
			CHECK(parse_semicolon(pctx));
Packit Service ae04f2
			continue;
Packit Service ae04f2
		}
Packit Service ae04f2
Packit Service ae04f2
		/* Clause is known. */
Packit Service ae04f2
Packit Service ae04f2
		/* Issue warnings if appropriate */
Packit Service ae04f2
		if ((pctx->flags & CFG_PCTX_NODEPRECATED) == 0 &&
Packit Service ae04f2
		    (clause->flags & CFG_CLAUSEFLAG_DEPRECATED) != 0)
Packit Service ae04f2
		{
Packit Service ae04f2
			cfg_parser_warning(pctx, 0, "option '%s' is deprecated",
Packit Service ae04f2
					   clause->name);
Packit Service ae04f2
		}
Packit Service ae04f2
		if ((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0) {
Packit Service ae04f2
			cfg_parser_warning(pctx, 0, "option '%s' is obsolete",
Packit Service ae04f2
					   clause->name);
Packit Service ae04f2
		}
Packit Service ae04f2
		if ((clause->flags & CFG_CLAUSEFLAG_NOTIMP) != 0) {
Packit Service ae04f2
			cfg_parser_warning(pctx, 0, "option '%s' is "
Packit Service ae04f2
					   "not implemented", clause->name);
Packit Service ae04f2
		}
Packit Service ae04f2
		if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0) {
Packit Service ae04f2
			cfg_parser_warning(pctx, 0, "option '%s' is "
Packit Service ae04f2
					   "not implemented", clause->name);
Packit Service ae04f2
		}
Packit Service ae04f2
		if ((clause->flags & CFG_CLAUSEFLAG_NOOP) != 0) {
Packit Service ae04f2
			cfg_parser_warning(pctx, 0, "option '%s' was not "
Packit Service ae04f2
					   "enabled at compile time "
Packit Service ae04f2
					   "(ignored)", clause->name);
Packit Service ae04f2
		}
Packit Service ae04f2
Packit Service ae04f2
		if ((clause->flags & CFG_CLAUSEFLAG_NOTCONFIGURED) != 0) {
Packit Service ae04f2
			cfg_parser_warning(pctx, 0, "option '%s' was not "
Packit Service ae04f2
					   "enabled at compile time",
Packit Service ae04f2
					   clause->name);
Packit Service ae04f2
			result = ISC_R_FAILURE;
Packit Service ae04f2
			goto cleanup;
Packit Service ae04f2
		}
Packit Service ae04f2
Packit Service ae04f2
		/*
Packit Service ae04f2
		 * Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT
Packit Service ae04f2
		 * set here - we need to log the *lack* of such an option,
Packit Service ae04f2
		 * not its presence.
Packit Service ae04f2
		 */
Packit Service ae04f2
Packit Service ae04f2
		/* See if the clause already has a value; if not create one. */
Packit Service ae04f2
		result = isc_symtab_lookup(obj->value.map.symtab,
Packit Service ae04f2
					   clause->name, 0, &symval);
Packit Service ae04f2
Packit Service ae04f2
		if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) {
Packit Service ae04f2
			/* Multivalued clause */
Packit Service ae04f2
			cfg_obj_t *listobj = NULL;
Packit Service ae04f2
			if (result == ISC_R_NOTFOUND) {
Packit Service ae04f2
				CHECK(cfg_create_list(pctx,
Packit Service ae04f2
						  &cfg_type_implicitlist,
Packit Service ae04f2
						  &listobj));
Packit Service ae04f2
				symval.as_pointer = listobj;
Packit Service ae04f2
				result = isc_symtab_define(obj->value.
Packit Service ae04f2
						   map.symtab,
Packit Service ae04f2
						   clause->name,
Packit Service ae04f2
						   1, symval,
Packit Service ae04f2
						   isc_symexists_reject);
Packit Service ae04f2
				if (result != ISC_R_SUCCESS) {
Packit Service ae04f2
					cfg_parser_error(pctx, CFG_LOG_NEAR,
Packit Service ae04f2
						     "isc_symtab_define(%s) "
Packit Service ae04f2
						     "failed", clause->name);
Packit Service ae04f2
					isc_mem_put(pctx->mctx, list,
Packit Service ae04f2
						    sizeof(cfg_list_t));
Packit Service ae04f2
					goto cleanup;
Packit Service ae04f2
				}
Packit Service ae04f2
			} else {
Packit Service ae04f2
				INSIST(result == ISC_R_SUCCESS);
Packit Service ae04f2
				listobj = symval.as_pointer;
Packit Service ae04f2
			}
Packit Service ae04f2
Packit Service ae04f2
			elt = NULL;
Packit Service ae04f2
			CHECK(cfg_parse_listelt(pctx, clause->type, &elt));
Packit Service ae04f2
			CHECK(parse_semicolon(pctx));
Packit Service ae04f2
Packit Service ae04f2
			ISC_LIST_APPEND(listobj->value.list, elt, link);
Packit Service ae04f2
		} else {
Packit Service ae04f2
			/* Single-valued clause */
Packit Service ae04f2
			if (result == ISC_R_NOTFOUND) {
Packit Service ae04f2
				bool callback =
Packit Service ae04f2
					((clause->flags &
Packit Service ae04f2
					  CFG_CLAUSEFLAG_CALLBACK) != 0);
Packit Service ae04f2
				CHECK(parse_symtab_elt(pctx, clause->name,
Packit Service ae04f2
						       clause->type,
Packit Service ae04f2
						       obj->value.map.symtab,
Packit Service ae04f2
						       callback));
Packit Service ae04f2
				CHECK(parse_semicolon(pctx));
Packit Service ae04f2
			} else if (result == ISC_R_SUCCESS) {
Packit Service ae04f2
				cfg_parser_error(pctx, CFG_LOG_NEAR, "'%s' redefined",
Packit Service ae04f2
					     clause->name);
Packit Service ae04f2
				result = ISC_R_EXISTS;
Packit Service ae04f2
				goto cleanup;
Packit Service ae04f2
			} else {
Packit Service ae04f2
				cfg_parser_error(pctx, CFG_LOG_NEAR,
Packit Service ae04f2
					     "isc_symtab_define() failed");
Packit Service ae04f2
				goto cleanup;
Packit Service ae04f2
			}
Packit Service ae04f2
		}
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
Packit Service ae04f2
	*ret = obj;
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	CLEANUP_OBJ(value);
Packit Service ae04f2
	CLEANUP_OBJ(obj);
Packit Service ae04f2
	CLEANUP_OBJ(eltobj);
Packit Service ae04f2
	CLEANUP_OBJ(includename);
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
parse_symtab_elt(cfg_parser_t *pctx, const char *name,
Packit Service ae04f2
		 cfg_type_t *elttype, isc_symtab_t *symtab,
Packit Service ae04f2
		 bool callback)
Packit Service ae04f2
{
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	cfg_obj_t *obj = NULL;
Packit Service ae04f2
	isc_symvalue_t symval;
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_parse_obj(pctx, elttype, &obj));
Packit Service ae04f2
Packit Service ae04f2
	if (callback && pctx->callback != NULL)
Packit Service ae04f2
		CHECK(pctx->callback(name, obj, pctx->callbackarg));
Packit Service ae04f2
Packit Service ae04f2
	symval.as_pointer = obj;
Packit Service ae04f2
	CHECK(isc_symtab_define(symtab, name,
Packit Service ae04f2
				1, symval,
Packit Service ae04f2
				isc_symexists_reject));
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	CLEANUP_OBJ(obj);
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }"
Packit Service ae04f2
 */
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_parse_special(pctx, '{'));
Packit Service ae04f2
	CHECK(cfg_parse_mapbody(pctx, type, ret));
Packit Service ae04f2
	CHECK(cfg_parse_special(pctx, '}'));
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Subroutine for cfg_parse_named_map() and cfg_parse_addressed_map().
Packit Service ae04f2
 */
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
parse_any_named_map(cfg_parser_t *pctx, cfg_type_t *nametype,
Packit Service ae04f2
		    const cfg_type_t *type, cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	cfg_obj_t *idobj = NULL;
Packit Service ae04f2
	cfg_obj_t *mapobj = NULL;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(nametype != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_parse_obj(pctx, nametype, &idobj));
Packit Service ae04f2
	CHECK(cfg_parse_map(pctx, type, &mapobj));
Packit Service ae04f2
	mapobj->value.map.id = idobj;
Packit Service ae04f2
	*ret = mapobj;
Packit Service ae04f2
	return (result);
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	CLEANUP_OBJ(idobj);
Packit Service ae04f2
	CLEANUP_OBJ(mapobj);
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Parse a map identified by a string name.  E.g., "name { foo 1; }".
Packit Service ae04f2
 * Used for the "key" and "channel" statements.
Packit Service ae04f2
 */
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
Packit Service ae04f2
	return (parse_any_named_map(pctx, &cfg_type_astring, type, ret));
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Parse a map identified by a network address.
Packit Service ae04f2
 * Used to be used for the "server" statement.
Packit Service ae04f2
 */
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
Packit Service ae04f2
	return (parse_any_named_map(pctx, &cfg_type_netaddr, type, ret));
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Parse a map identified by a network prefix.
Packit Service ae04f2
 * Used for the "server" statement.
Packit Service ae04f2
 */
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_netprefix_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
Packit Service ae04f2
	return (parse_any_named_map(pctx, &cfg_type_netprefix, type, ret));
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
print_symval(cfg_printer_t *pctx, const char *name, cfg_obj_t *obj) {
Packit Service ae04f2
	if ((pctx->flags & CFG_PRINTER_ONELINE) == 0)
Packit Service ae04f2
		cfg_print_indent(pctx);
Packit Service ae04f2
Packit Service ae04f2
	cfg_print_cstr(pctx, name);
Packit Service ae04f2
	cfg_print_cstr(pctx, " ");
Packit Service ae04f2
	cfg_print_obj(pctx, obj);
Packit Service ae04f2
Packit Service ae04f2
	if ((pctx->flags & CFG_PRINTER_ONELINE) == 0)
Packit Service ae04f2
		cfg_print_cstr(pctx, ";\n");
Packit Service ae04f2
	else
Packit Service ae04f2
		cfg_print_cstr(pctx, "; ");
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) {
Packit Service ae04f2
	const cfg_clausedef_t * const *clauseset;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
Packit Service ae04f2
	for (clauseset = obj->value.map.clausesets;
Packit Service ae04f2
	     *clauseset != NULL;
Packit Service ae04f2
	     clauseset++)
Packit Service ae04f2
	{
Packit Service ae04f2
		isc_symvalue_t symval;
Packit Service ae04f2
		const cfg_clausedef_t *clause;
Packit Service ae04f2
Packit Service ae04f2
		for (clause = *clauseset;
Packit Service ae04f2
		     clause->name != NULL;
Packit Service ae04f2
		     clause++) {
Packit Service ae04f2
			isc_result_t result;
Packit Service ae04f2
			result = isc_symtab_lookup(obj->value.map.symtab,
Packit Service ae04f2
						   clause->name, 0, &symval);
Packit Service ae04f2
			if (result == ISC_R_SUCCESS) {
Packit Service ae04f2
				cfg_obj_t *symobj = symval.as_pointer;
Packit Service ae04f2
				if (symobj->type == &cfg_type_implicitlist) {
Packit Service ae04f2
					/* Multivalued. */
Packit Service ae04f2
					cfg_list_t *list = &symobj->value.list;
Packit Service ae04f2
					cfg_listelt_t *elt;
Packit Service ae04f2
					for (elt = ISC_LIST_HEAD(*list);
Packit Service ae04f2
					     elt != NULL;
Packit Service ae04f2
					     elt = ISC_LIST_NEXT(elt, link)) {
Packit Service ae04f2
						print_symval(pctx,
Packit Service ae04f2
							     clause->name,
Packit Service ae04f2
							     elt->obj);
Packit Service ae04f2
					}
Packit Service ae04f2
				} else {
Packit Service ae04f2
					/* Single-valued. */
Packit Service ae04f2
					print_symval(pctx, clause->name,
Packit Service ae04f2
						     symobj);
Packit Service ae04f2
				}
Packit Service ae04f2
			} else if (result == ISC_R_NOTFOUND) {
Packit Service ae04f2
				; /* do nothing */
Packit Service ae04f2
			} else {
Packit Service ae04f2
				INSIST(0);
Packit Service ae04f2
				ISC_UNREACHABLE();
Packit Service ae04f2
			}
Packit Service ae04f2
		}
Packit Service ae04f2
	}
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static struct flagtext {
Packit Service ae04f2
	unsigned int flag;
Packit Service ae04f2
	const char *text;
Packit Service ae04f2
} flagtexts[] = {
Packit Service ae04f2
	{ CFG_CLAUSEFLAG_NOTIMP, "not implemented" },
Packit Service ae04f2
	{ CFG_CLAUSEFLAG_NYI, "not yet implemented" },
Packit Service ae04f2
	{ CFG_CLAUSEFLAG_OBSOLETE, "obsolete" },
Packit Service ae04f2
	{ CFG_CLAUSEFLAG_NEWDEFAULT, "default changed" },
Packit Service ae04f2
	{ CFG_CLAUSEFLAG_TESTONLY, "test only" },
Packit Service ae04f2
	{ CFG_CLAUSEFLAG_NOTCONFIGURED, "not configured" },
Packit Service ae04f2
	{ CFG_CLAUSEFLAG_MULTI, "may occur multiple times" },
Packit Service ae04f2
	{ CFG_CLAUSEFLAG_EXPERIMENTAL, "experimental" },
Packit Service ae04f2
	{ CFG_CLAUSEFLAG_NOOP, "non-operational" },
Packit Service ae04f2
	{ 0, NULL }
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_clauseflags(cfg_printer_t *pctx, unsigned int flags) {
Packit Service ae04f2
	struct flagtext *p;
Packit Service ae04f2
	bool first = true;
Packit Service ae04f2
	for (p = flagtexts; p->flag != 0; p++) {
Packit Service ae04f2
		if ((flags & p->flag) != 0) {
Packit Service ae04f2
			if (first)
Packit Service ae04f2
				cfg_print_cstr(pctx, " // ");
Packit Service ae04f2
			else
Packit Service ae04f2
				cfg_print_cstr(pctx, ", ");
Packit Service ae04f2
			cfg_print_cstr(pctx, p->text);
Packit Service ae04f2
			first = false;
Packit Service ae04f2
		}
Packit Service ae04f2
	}
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) {
Packit Service ae04f2
	const cfg_clausedef_t * const *clauseset;
Packit Service ae04f2
	const cfg_clausedef_t *clause;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
Packit Service ae04f2
	for (clauseset = type->of; *clauseset != NULL; clauseset++) {
Packit Service ae04f2
		for (clause = *clauseset; clause->name != NULL; clause++) {
Packit Service ae04f2
			cfg_print_cstr(pctx, clause->name);
Packit Service ae04f2
			cfg_print_cstr(pctx, " ");
Packit Service ae04f2
			cfg_doc_obj(pctx, clause->type);
Packit Service ae04f2
			cfg_print_cstr(pctx, ";");
Packit Service ae04f2
			cfg_print_clauseflags(pctx, clause->flags);
Packit Service ae04f2
			cfg_print_cstr(pctx, "\n\n");
Packit Service ae04f2
		}
Packit Service ae04f2
	}
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_map(cfg_printer_t *pctx, const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
Packit Service ae04f2
	if (obj->value.map.id != NULL) {
Packit Service ae04f2
		cfg_print_obj(pctx, obj->value.map.id);
Packit Service ae04f2
		cfg_print_cstr(pctx, " ");
Packit Service ae04f2
	}
Packit Service ae04f2
	print_open(pctx);
Packit Service ae04f2
	cfg_print_mapbody(pctx, obj);
Packit Service ae04f2
	print_close(pctx);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) {
Packit Service ae04f2
	const cfg_clausedef_t * const *clauseset;
Packit Service ae04f2
	const cfg_clausedef_t *clause;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
Packit Service ae04f2
	if (type->parse == cfg_parse_named_map) {
Packit Service ae04f2
		cfg_doc_obj(pctx, &cfg_type_astring);
Packit Service ae04f2
		cfg_print_cstr(pctx, " ");
Packit Service ae04f2
	} else if (type->parse == cfg_parse_addressed_map) {
Packit Service ae04f2
		cfg_doc_obj(pctx, &cfg_type_netaddr);
Packit Service ae04f2
		cfg_print_cstr(pctx, " ");
Packit Service ae04f2
	} else if (type->parse == cfg_parse_netprefix_map) {
Packit Service ae04f2
		cfg_doc_obj(pctx, &cfg_type_netprefix);
Packit Service ae04f2
		cfg_print_cstr(pctx, " ");
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	print_open(pctx);
Packit Service ae04f2
Packit Service ae04f2
	for (clauseset = type->of; *clauseset != NULL; clauseset++) {
Packit Service ae04f2
		for (clause = *clauseset; clause->name != NULL; clause++) {
Packit Service ae04f2
			cfg_print_indent(pctx);
Packit Service ae04f2
			cfg_print_cstr(pctx, clause->name);
Packit Service ae04f2
			if (clause->type->print != cfg_print_void)
Packit Service ae04f2
				cfg_print_cstr(pctx, " ");
Packit Service ae04f2
			cfg_doc_obj(pctx, clause->type);
Packit Service ae04f2
			cfg_print_cstr(pctx, ";");
Packit Service ae04f2
			cfg_print_clauseflags(pctx, clause->flags);
Packit Service ae04f2
			cfg_print_cstr(pctx, "\n");
Packit Service ae04f2
		}
Packit Service ae04f2
	}
Packit Service ae04f2
	print_close(pctx);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
bool
Packit Service ae04f2
cfg_obj_ismap(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
	return (obj->type->rep == &cfg_rep_map);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_map_get(const cfg_obj_t *mapobj, const char* name, const cfg_obj_t **obj) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	isc_symvalue_t val;
Packit Service ae04f2
	const cfg_map_t *map;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
Packit Service ae04f2
	REQUIRE(name != NULL);
Packit Service ae04f2
	REQUIRE(obj != NULL && *obj == NULL);
Packit Service ae04f2
Packit Service ae04f2
	map = &mapobj->value.map;
Packit Service ae04f2
Packit Service ae04f2
	result = isc_symtab_lookup(map->symtab, name, MAP_SYM, &val;;
Packit Service ae04f2
	if (result != ISC_R_SUCCESS)
Packit Service ae04f2
		return (result);
Packit Service ae04f2
	*obj = val.as_pointer;
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
const cfg_obj_t *
Packit Service ae04f2
cfg_map_getname(const cfg_obj_t *mapobj) {
Packit Service ae04f2
	REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
Packit Service ae04f2
	return (mapobj->value.map.id);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
unsigned int
Packit Service ae04f2
cfg_map_count(const cfg_obj_t *mapobj) {
Packit Service ae04f2
	const cfg_map_t *map;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
Packit Service ae04f2
Packit Service ae04f2
	map = &mapobj->value.map;
Packit Service ae04f2
	return (isc_symtab_count(map->symtab));
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
#if _WIN32
Packit Service ae04f2
#pragma warning(disable : 4090)
Packit Service ae04f2
#endif
Packit Service ae04f2
const char *
Packit Service ae04f2
cfg_map_firstclause(const cfg_type_t *map, const void **clauses,
Packit Service ae04f2
		    unsigned int *idx)
Packit Service ae04f2
{
Packit Service ae04f2
	cfg_clausedef_t * const * clauseset;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(map != NULL && map->rep == &cfg_rep_map);
Packit Service ae04f2
	REQUIRE(idx != NULL);
Packit Service ae04f2
	REQUIRE(clauses != NULL && *clauses == NULL);
Packit Service ae04f2
Packit Service ae04f2
	clauseset = map->of;
Packit Service ae04f2
	if (*clauseset == NULL) {
Packit Service ae04f2
		return (NULL);
Packit Service ae04f2
	}
Packit Service ae04f2
	*clauses = *clauseset;
Packit Service ae04f2
	*idx = 0;
Packit Service ae04f2
	while ((*clauseset)[*idx].name == NULL) {
Packit Service ae04f2
		*clauses = (*++clauseset);
Packit Service ae04f2
		if (*clauses == NULL)
Packit Service ae04f2
			return (NULL);
Packit Service ae04f2
	}
Packit Service ae04f2
	return ((*clauseset)[*idx].name);
Packit Service ae04f2
#if _WIN32
Packit Service ae04f2
#pragma warning(default : 4090)
Packit Service ae04f2
#endif
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
#if _WIN32
Packit Service ae04f2
#pragma warning(disable : 4090)
Packit Service ae04f2
#endif
Packit Service ae04f2
const char *
Packit Service ae04f2
cfg_map_nextclause(const cfg_type_t *map, const void **clauses,
Packit Service ae04f2
		   unsigned int *idx)
Packit Service ae04f2
{
Packit Service ae04f2
	cfg_clausedef_t * const * clauseset;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(map != NULL && map->rep == &cfg_rep_map);
Packit Service ae04f2
	REQUIRE(idx != NULL);
Packit Service ae04f2
	REQUIRE(clauses != NULL && *clauses != NULL);
Packit Service ae04f2
Packit Service ae04f2
	clauseset = map->of;
Packit Service ae04f2
	while (*clauseset != NULL && *clauseset != *clauses) {
Packit Service ae04f2
		clauseset++;
Packit Service ae04f2
	}
Packit Service ae04f2
	INSIST(*clauseset == *clauses);
Packit Service ae04f2
	(*idx)++;
Packit Service ae04f2
	while ((*clauseset)[*idx].name == NULL) {
Packit Service ae04f2
		*idx = 0;
Packit Service ae04f2
		*clauses = (*++clauseset);
Packit Service ae04f2
		if (*clauses == NULL)
Packit Service ae04f2
			return (NULL);
Packit Service ae04f2
	}
Packit Service ae04f2
	return ((*clauseset)[*idx].name);
Packit Service ae04f2
#if _WIN32
Packit Service ae04f2
#pragma warning(default : 4090)
Packit Service ae04f2
#endif
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/* Parse an arbitrary token, storing its raw text representation. */
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
Packit Service ae04f2
	cfg_obj_t *obj = NULL;
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	isc_region_t r;
Packit Service ae04f2
Packit Service ae04f2
	UNUSED(type);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_create_obj(pctx, &cfg_type_token, &obj));
Packit Service ae04f2
	CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
Packit Service ae04f2
	if (pctx->token.type == isc_tokentype_eof) {
Packit Service ae04f2
		cfg_ungettoken(pctx);
Packit Service ae04f2
		result = ISC_R_EOF;
Packit Service ae04f2
		goto cleanup;
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	isc_lex_getlasttokentext(pctx->lexer, &pctx->token, &r);
Packit Service ae04f2
Packit Service ae04f2
	obj->value.string.base = isc_mem_get(pctx->mctx, r.length + 1);
Packit Service ae04f2
	if (obj->value.string.base == NULL) {
Packit Service ae04f2
		result = ISC_R_NOMEMORY;
Packit Service ae04f2
		goto cleanup;
Packit Service ae04f2
	}
Packit Service ae04f2
	obj->value.string.length = r.length;
Packit Service ae04f2
	memmove(obj->value.string.base, r.base, r.length);
Packit Service ae04f2
	obj->value.string.base[r.length] = '\0';
Packit Service ae04f2
	*ret = obj;
Packit Service ae04f2
	return (result);
Packit Service ae04f2
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	if (obj != NULL)
Packit Service ae04f2
		isc_mem_put(pctx->mctx, obj, sizeof(*obj));
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_token = {
Packit Service ae04f2
	"token", parse_token, cfg_print_ustring, cfg_doc_terminal,
Packit Service ae04f2
	&cfg_rep_string, NULL
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * An unsupported option.  This is just a list of tokens with balanced braces
Packit Service ae04f2
 * ending in a semicolon.
Packit Service ae04f2
 */
Packit Service ae04f2
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
parse_unsupported(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
Packit Service ae04f2
	cfg_obj_t *listobj = NULL;
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	int braces = 0;
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_create_list(pctx, type, &listobj));
Packit Service ae04f2
Packit Service ae04f2
	for (;;) {
Packit Service ae04f2
		cfg_listelt_t *elt = NULL;
Packit Service ae04f2
Packit Service ae04f2
		CHECK(cfg_peektoken(pctx, 0));
Packit Service ae04f2
		if (pctx->token.type == isc_tokentype_special) {
Packit Service ae04f2
			if (pctx->token.value.as_char == '{')
Packit Service ae04f2
				braces++;
Packit Service ae04f2
			else if (pctx->token.value.as_char == '}')
Packit Service ae04f2
				braces--;
Packit Service ae04f2
			else if (pctx->token.value.as_char == ';')
Packit Service ae04f2
				if (braces == 0)
Packit Service ae04f2
					break;
Packit Service ae04f2
		}
Packit Service ae04f2
		if (pctx->token.type == isc_tokentype_eof || braces < 0) {
Packit Service ae04f2
			cfg_parser_error(pctx, CFG_LOG_NEAR, "unexpected token");
Packit Service ae04f2
			result = ISC_R_UNEXPECTEDTOKEN;
Packit Service ae04f2
			goto cleanup;
Packit Service ae04f2
		}
Packit Service ae04f2
Packit Service ae04f2
		CHECK(cfg_parse_listelt(pctx, &cfg_type_token, &elt));
Packit Service ae04f2
		ISC_LIST_APPEND(listobj->value.list, elt, link);
Packit Service ae04f2
	}
Packit Service ae04f2
	INSIST(braces == 0);
Packit Service ae04f2
	*ret = listobj;
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	CLEANUP_OBJ(listobj);
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_unsupported = {
Packit Service ae04f2
	"unsupported", parse_unsupported, cfg_print_spacelist, cfg_doc_terminal,
Packit Service ae04f2
	&cfg_rep_list, NULL
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Try interpreting the current token as a network address.
Packit Service ae04f2
 *
Packit Service ae04f2
 * If CFG_ADDR_WILDOK is set in flags, "*" can be used as a wildcard
Packit Service ae04f2
 * and at least one of CFG_ADDR_V4OK and CFG_ADDR_V6OK must also be set.  The
Packit Service ae04f2
 * "*" is interpreted as the IPv4 wildcard address if CFG_ADDR_V4OK is
Packit Service ae04f2
 * set (including the case where CFG_ADDR_V4OK and CFG_ADDR_V6OK are both set),
Packit Service ae04f2
 * and the IPv6 wildcard address otherwise.
Packit Service ae04f2
 */
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) {
Packit Service ae04f2
	char *s;
Packit Service ae04f2
	struct in_addr in4a;
Packit Service ae04f2
	struct in6_addr in6a;
Packit Service ae04f2
Packit Service ae04f2
	if (pctx->token.type != isc_tokentype_string)
Packit Service ae04f2
		return (ISC_R_UNEXPECTEDTOKEN);
Packit Service ae04f2
Packit Service ae04f2
	s = TOKEN_STRING(pctx);
Packit Service ae04f2
	if ((flags & CFG_ADDR_WILDOK) != 0 && strcmp(s, "*") == 0) {
Packit Service ae04f2
		if ((flags & CFG_ADDR_V4OK) != 0) {
Packit Service ae04f2
			isc_netaddr_any(na);
Packit Service ae04f2
			return (ISC_R_SUCCESS);
Packit Service ae04f2
		} else if ((flags & CFG_ADDR_V6OK) != 0) {
Packit Service ae04f2
			isc_netaddr_any6(na);
Packit Service ae04f2
			return (ISC_R_SUCCESS);
Packit Service ae04f2
		} else {
Packit Service ae04f2
			INSIST(0);
Packit Service ae04f2
			ISC_UNREACHABLE();
Packit Service ae04f2
		}
Packit Service ae04f2
	} else {
Packit Service ae04f2
		if ((flags & (CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK)) != 0) {
Packit Service ae04f2
			if (inet_pton(AF_INET, s, &in4a) == 1) {
Packit Service ae04f2
				isc_netaddr_fromin(na, &in4a);
Packit Service ae04f2
				return (ISC_R_SUCCESS);
Packit Service ae04f2
			}
Packit Service ae04f2
		}
Packit Service ae04f2
		if ((flags & CFG_ADDR_V4PREFIXOK) != 0 && strlen(s) <= 15U) {
Packit Service ae04f2
			char buf[64];
Packit Service ae04f2
			int i;
Packit Service ae04f2
Packit Service ae04f2
			strlcpy(buf, s, sizeof(buf));
Packit Service ae04f2
			for (i = 0; i < 3; i++) {
Packit Service ae04f2
				strlcat(buf, ".0", sizeof(buf));
Packit Service ae04f2
				if (inet_pton(AF_INET, buf, &in4a) == 1) {
Packit Service ae04f2
					isc_netaddr_fromin(na, &in4a);
Packit Service ae04f2
					return (ISC_R_IPV4PREFIX);
Packit Service ae04f2
				}
Packit Service ae04f2
			}
Packit Service ae04f2
		}
Packit Service ae04f2
		if ((flags & CFG_ADDR_V6OK) != 0 && strlen(s) <= 127U) {
Packit Service ae04f2
			char buf[128]; /* see lib/bind9/getaddresses.c */
Packit Service ae04f2
			char *d; /* zone delimiter */
Packit Service ae04f2
			uint32_t zone = 0; /* scope zone ID */
Packit Service ae04f2
Packit Service ae04f2
			strlcpy(buf, s, sizeof(buf));
Packit Service ae04f2
			d = strchr(buf, '%');
Packit Service ae04f2
			if (d != NULL)
Packit Service ae04f2
				*d = '\0';
Packit Service ae04f2
Packit Service ae04f2
			if (inet_pton(AF_INET6, buf, &in6a) == 1) {
Packit Service ae04f2
				if (d != NULL) {
Packit Service ae04f2
#ifdef ISC_PLATFORM_HAVESCOPEID
Packit Service ae04f2
					isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
					result = isc_netscope_pton(AF_INET6,
Packit Service ae04f2
								   d + 1,
Packit Service ae04f2
								   &in6a,
Packit Service ae04f2
								   &zone);
Packit Service ae04f2
					if (result != ISC_R_SUCCESS)
Packit Service ae04f2
						return (result);
Packit Service ae04f2
#else
Packit Service ae04f2
				return (ISC_R_BADADDRESSFORM);
Packit Service ae04f2
#endif
Packit Service ae04f2
				}
Packit Service ae04f2
Packit Service ae04f2
				isc_netaddr_fromin6(na, &in6a);
Packit Service ae04f2
				isc_netaddr_setzone(na, zone);
Packit Service ae04f2
				return (ISC_R_SUCCESS);
Packit Service ae04f2
			}
Packit Service ae04f2
		}
Packit Service ae04f2
	}
Packit Service ae04f2
	return (ISC_R_UNEXPECTEDTOKEN);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	const char *wild = "";
Packit Service ae04f2
	const char *prefix = "";
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(na != NULL);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_gettoken(pctx, 0));
Packit Service ae04f2
	result = token_addr(pctx, flags, na);
Packit Service ae04f2
	if (result == ISC_R_UNEXPECTEDTOKEN) {
Packit Service ae04f2
		if ((flags & CFG_ADDR_WILDOK) != 0)
Packit Service ae04f2
			wild = " or '*'";
Packit Service ae04f2
		if ((flags & CFG_ADDR_V4PREFIXOK) != 0)
Packit Service ae04f2
			wild = " or IPv4 prefix";
Packit Service ae04f2
		if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V4OK)
Packit Service ae04f2
			cfg_parser_error(pctx, CFG_LOG_NEAR,
Packit Service ae04f2
					 "expected IPv4 address%s%s",
Packit Service ae04f2
					 prefix, wild);
Packit Service ae04f2
		else if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V6OK)
Packit Service ae04f2
			cfg_parser_error(pctx, CFG_LOG_NEAR,
Packit Service ae04f2
					 "expected IPv6 address%s%s",
Packit Service ae04f2
					 prefix, wild);
Packit Service ae04f2
		else
Packit Service ae04f2
			cfg_parser_error(pctx, CFG_LOG_NEAR,
Packit Service ae04f2
					 "expected IP address%s%s",
Packit Service ae04f2
					 prefix, wild);
Packit Service ae04f2
	}
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
bool
Packit Service ae04f2
cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	isc_netaddr_t na_dummy;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
Packit Service ae04f2
	result = token_addr(pctx, flags, &na_dummy);
Packit Service ae04f2
	return (result == ISC_R_SUCCESS || result == ISC_R_IPV4PREFIX);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(port != NULL);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER));
Packit Service ae04f2
Packit Service ae04f2
	if ((flags & CFG_ADDR_WILDOK) != 0 &&
Packit Service ae04f2
	    pctx->token.type == isc_tokentype_string &&
Packit Service ae04f2
	    strcmp(TOKEN_STRING(pctx), "*") == 0) {
Packit Service ae04f2
		*port = 0;
Packit Service ae04f2
		return (ISC_R_SUCCESS);
Packit Service ae04f2
	}
Packit Service ae04f2
	if (pctx->token.type != isc_tokentype_number) {
Packit Service ae04f2
		cfg_parser_error(pctx, CFG_LOG_NEAR,
Packit Service ae04f2
			     "expected port number or '*'");
Packit Service ae04f2
		return (ISC_R_UNEXPECTEDTOKEN);
Packit Service ae04f2
	}
Packit Service ae04f2
	if (pctx->token.value.as_ulong >= 65536U) {
Packit Service ae04f2
		cfg_parser_error(pctx, CFG_LOG_NEAR,
Packit Service ae04f2
			     "port number out of range");
Packit Service ae04f2
		return (ISC_R_UNEXPECTEDTOKEN);
Packit Service ae04f2
	}
Packit Service ae04f2
	*port = (in_port_t)(pctx->token.value.as_ulong);
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_rawaddr(cfg_printer_t *pctx, const isc_netaddr_t *na) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	char text[128];
Packit Service ae04f2
	isc_buffer_t buf;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(na != NULL);
Packit Service ae04f2
Packit Service ae04f2
	isc_buffer_init(&buf, text, sizeof(text));
Packit Service ae04f2
	result = isc_netaddr_totext(na, &buf;;
Packit Service ae04f2
	RUNTIME_CHECK(result == ISC_R_SUCCESS);
Packit Service ae04f2
	cfg_print_chars(pctx, isc_buffer_base(&buf),
Packit Service ae04f2
			isc_buffer_usedlength(&buf));
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_dscp(cfg_parser_t *pctx, isc_dscp_t *dscp) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(dscp != NULL);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
Packit Service ae04f2
Packit Service ae04f2
	if (pctx->token.type != isc_tokentype_number) {
Packit Service ae04f2
		cfg_parser_error(pctx, CFG_LOG_NEAR,
Packit Service ae04f2
			     "expected number");
Packit Service ae04f2
		return (ISC_R_UNEXPECTEDTOKEN);
Packit Service ae04f2
	}
Packit Service ae04f2
	if (pctx->token.value.as_ulong > 63U) {
Packit Service ae04f2
		cfg_parser_error(pctx, CFG_LOG_NEAR,
Packit Service ae04f2
			     "dscp out of range");
Packit Service ae04f2
		return (ISC_R_RANGE);
Packit Service ae04f2
	}
Packit Service ae04f2
	*dscp = (isc_dscp_t)(pctx->token.value.as_ulong);
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/* netaddr */
Packit Service ae04f2
Packit Service ae04f2
static unsigned int netaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK;
Packit Service ae04f2
static unsigned int netaddr4_flags = CFG_ADDR_V4OK;
Packit Service ae04f2
static unsigned int netaddr4wild_flags = CFG_ADDR_V4OK | CFG_ADDR_WILDOK;
Packit Service ae04f2
static unsigned int netaddr6_flags = CFG_ADDR_V6OK;
Packit Service ae04f2
static unsigned int netaddr6wild_flags = CFG_ADDR_V6OK | CFG_ADDR_WILDOK;
Packit Service ae04f2
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
parse_netaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	cfg_obj_t *obj = NULL;
Packit Service ae04f2
	isc_netaddr_t netaddr;
Packit Service ae04f2
	unsigned int flags = *(const unsigned int *)type->of;
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_create_obj(pctx, type, &obj));
Packit Service ae04f2
	CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr));
Packit Service ae04f2
	isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, 0);
Packit Service ae04f2
	obj->value.sockaddrdscp.dscp = -1;
Packit Service ae04f2
	*ret = obj;
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	CLEANUP_OBJ(obj);
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
cfg_doc_netaddr(cfg_printer_t *pctx, const cfg_type_t *type) {
Packit Service ae04f2
	const unsigned int *flagp = type->of;
Packit Service ae04f2
	int n = 0;
Packit Service ae04f2
	if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK) {
Packit Service ae04f2
		cfg_print_cstr(pctx, "( ");
Packit Service ae04f2
	}
Packit Service ae04f2
	if ((*flagp & CFG_ADDR_V4OK) != 0) {
Packit Service ae04f2
		cfg_print_cstr(pctx, "<ipv4_address>");
Packit Service ae04f2
		n++;
Packit Service ae04f2
	}
Packit Service ae04f2
	if ((*flagp & CFG_ADDR_V6OK) != 0) {
Packit Service ae04f2
		if (n != 0)
Packit Service ae04f2
			cfg_print_cstr(pctx, " | ");
Packit Service ae04f2
		cfg_print_cstr(pctx, "<ipv6_address>");
Packit Service ae04f2
		n++;
Packit Service ae04f2
	}
Packit Service ae04f2
	if ((*flagp & CFG_ADDR_WILDOK) != 0) {
Packit Service ae04f2
		if (n != 0)
Packit Service ae04f2
			cfg_print_cstr(pctx, " | ");
Packit Service ae04f2
		cfg_print_cstr(pctx, "*");
Packit Service ae04f2
		n++;
Packit Service ae04f2
		POST(n);
Packit Service ae04f2
	}
Packit Service ae04f2
	if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK) {
Packit Service ae04f2
		cfg_print_cstr(pctx, " )");
Packit Service ae04f2
	}
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netaddr = {
Packit Service ae04f2
	"netaddr", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
Packit Service ae04f2
	&cfg_rep_sockaddr, &netaddr_flags
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netaddr4 = {
Packit Service ae04f2
	"netaddr4", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
Packit Service ae04f2
	&cfg_rep_sockaddr, &netaddr4_flags
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netaddr4wild = {
Packit Service ae04f2
	"netaddr4wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
Packit Service ae04f2
	&cfg_rep_sockaddr, &netaddr4wild_flags
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netaddr6 = {
Packit Service ae04f2
	"netaddr6", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
Packit Service ae04f2
	&cfg_rep_sockaddr, &netaddr6_flags
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netaddr6wild = {
Packit Service ae04f2
	"netaddr6wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
Packit Service ae04f2
	&cfg_rep_sockaddr, &netaddr6wild_flags
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
/* netprefix */
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type,
Packit Service ae04f2
		    cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	cfg_obj_t *obj = NULL;
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	isc_netaddr_t netaddr;
Packit Service ae04f2
	unsigned int addrlen = 0, prefixlen;
Packit Service ae04f2
	bool expectprefix;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	UNUSED(type);
Packit Service ae04f2
Packit Service ae04f2
	result = cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK |
Packit Service ae04f2
				   CFG_ADDR_V6OK, &netaddr);
Packit Service ae04f2
	if (result != ISC_R_SUCCESS && result != ISC_R_IPV4PREFIX) {
Packit Service ae04f2
		CHECK(result);
Packit Service ae04f2
	}
Packit Service ae04f2
	switch (netaddr.family) {
Packit Service ae04f2
	case AF_INET:
Packit Service ae04f2
		addrlen = 32;
Packit Service ae04f2
		break;
Packit Service ae04f2
	case AF_INET6:
Packit Service ae04f2
		addrlen = 128;
Packit Service ae04f2
		break;
Packit Service ae04f2
	default:
Packit Service ae04f2
		INSIST(0);
Packit Service ae04f2
		ISC_UNREACHABLE();
Packit Service ae04f2
	}
Packit Service ae04f2
	expectprefix = (result == ISC_R_IPV4PREFIX);
Packit Service ae04f2
	CHECK(cfg_peektoken(pctx, 0));
Packit Service ae04f2
	if (pctx->token.type == isc_tokentype_special &&
Packit Service ae04f2
	    pctx->token.value.as_char == '/') {
Packit Service ae04f2
		CHECK(cfg_gettoken(pctx, 0)); /* read "/" */
Packit Service ae04f2
		CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER));
Packit Service ae04f2
		if (pctx->token.type != isc_tokentype_number) {
Packit Service ae04f2
			cfg_parser_error(pctx, CFG_LOG_NEAR,
Packit Service ae04f2
					 "expected prefix length");
Packit Service ae04f2
			return (ISC_R_UNEXPECTEDTOKEN);
Packit Service ae04f2
		}
Packit Service ae04f2
		prefixlen = pctx->token.value.as_ulong;
Packit Service ae04f2
		if (prefixlen > addrlen) {
Packit Service ae04f2
			cfg_parser_error(pctx, CFG_LOG_NOPREP,
Packit Service ae04f2
					 "invalid prefix length");
Packit Service ae04f2
			return (ISC_R_RANGE);
Packit Service ae04f2
		}
Packit Service ae04f2
	} else {
Packit Service ae04f2
		if (expectprefix) {
Packit Service ae04f2
			cfg_parser_error(pctx, CFG_LOG_NEAR,
Packit Service ae04f2
					 "incomplete IPv4 address or prefix");
Packit Service ae04f2
			return (ISC_R_FAILURE);
Packit Service ae04f2
		}
Packit Service ae04f2
		prefixlen = addrlen;
Packit Service ae04f2
	}
Packit Service ae04f2
	CHECK(cfg_create_obj(pctx, &cfg_type_netprefix, &obj));
Packit Service ae04f2
	obj->value.netprefix.address = netaddr;
Packit Service ae04f2
	obj->value.netprefix.prefixlen = prefixlen;
Packit Service ae04f2
	*ret = obj;
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	cfg_parser_error(pctx, CFG_LOG_NEAR, "expected network prefix");
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
print_netprefix(cfg_printer_t *pctx, const cfg_obj_t *obj) {
Packit Service ae04f2
	const cfg_netprefix_t *p = &obj->value.netprefix;
Packit Service ae04f2
Packit Service ae04f2
	cfg_print_rawaddr(pctx, &p->address);
Packit Service ae04f2
	cfg_print_cstr(pctx, "/");
Packit Service ae04f2
	cfg_print_rawuint(pctx, p->prefixlen);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
bool
Packit Service ae04f2
cfg_obj_isnetprefix(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
	return (obj->type->rep == &cfg_rep_netprefix);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_obj_asnetprefix(const cfg_obj_t *obj, isc_netaddr_t *netaddr,
Packit Service ae04f2
		    unsigned int *prefixlen)
Packit Service ae04f2
{
Packit Service ae04f2
	REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_netprefix);
Packit Service ae04f2
	REQUIRE(netaddr != NULL);
Packit Service ae04f2
	REQUIRE(prefixlen != NULL);
Packit Service ae04f2
Packit Service ae04f2
	*netaddr = obj->value.netprefix.address;
Packit Service ae04f2
	*prefixlen = obj->value.netprefix.prefixlen;
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netprefix = {
Packit Service ae04f2
	"netprefix", cfg_parse_netprefix, print_netprefix, cfg_doc_terminal,
Packit Service ae04f2
	&cfg_rep_netprefix, NULL
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type,
Packit Service ae04f2
		  int flags, cfg_obj_t **ret)
Packit Service ae04f2
{
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	isc_netaddr_t netaddr;
Packit Service ae04f2
	in_port_t port = 0;
Packit Service ae04f2
	isc_dscp_t dscp = -1;
Packit Service ae04f2
	cfg_obj_t *obj = NULL;
Packit Service ae04f2
	int have_port = 0, have_dscp = 0;
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_create_obj(pctx, type, &obj));
Packit Service ae04f2
	CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr));
Packit Service ae04f2
	for (;;) {
Packit Service ae04f2
		CHECK(cfg_peektoken(pctx, 0));
Packit Service ae04f2
		if (pctx->token.type == isc_tokentype_string) {
Packit Service ae04f2
			if (strcasecmp(TOKEN_STRING(pctx), "port") == 0) {
Packit Service ae04f2
				CHECK(cfg_gettoken(pctx, 0)); /* read "port" */
Packit Service ae04f2
				CHECK(cfg_parse_rawport(pctx, flags, &port));
Packit Service ae04f2
				++have_port;
Packit Service ae04f2
			} else if ((flags & CFG_ADDR_DSCPOK) != 0 &&
Packit Service ae04f2
				   strcasecmp(TOKEN_STRING(pctx), "dscp") == 0)
Packit Service ae04f2
			{
Packit Service ae04f2
				CHECK(cfg_gettoken(pctx, 0)); /* read "dscp" */
Packit Service ae04f2
				CHECK(cfg_parse_dscp(pctx, &dscp));
Packit Service ae04f2
				++have_dscp;
Packit Service ae04f2
			} else
Packit Service ae04f2
				break;
Packit Service ae04f2
		} else
Packit Service ae04f2
			break;
Packit Service ae04f2
	}
Packit Service ae04f2
	if (have_port > 1) {
Packit Service ae04f2
		cfg_parser_error(pctx, 0, "expected at most one port");
Packit Service ae04f2
		result = ISC_R_UNEXPECTEDTOKEN;
Packit Service ae04f2
		goto cleanup;
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	if (have_dscp > 1) {
Packit Service ae04f2
		cfg_parser_error(pctx, 0, "expected at most one dscp");
Packit Service ae04f2
		result = ISC_R_UNEXPECTEDTOKEN;
Packit Service ae04f2
		goto cleanup;
Packit Service ae04f2
	}
Packit Service ae04f2
	isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port);
Packit Service ae04f2
	obj->value.sockaddrdscp.dscp = dscp;
Packit Service ae04f2
	*ret = obj;
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	CLEANUP_OBJ(obj);
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static unsigned int sockaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK;
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sockaddr = {
Packit Service ae04f2
	"sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr,
Packit Service ae04f2
	&cfg_rep_sockaddr, &sockaddr_flags
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
static unsigned int sockaddrdscp_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK |
Packit Service ae04f2
					 CFG_ADDR_DSCPOK;
Packit Service ae04f2
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sockaddrdscp = {
Packit Service ae04f2
	"sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr,
Packit Service ae04f2
	&cfg_rep_sockaddr, &sockaddrdscp_flags
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
Packit Service ae04f2
	const unsigned int *flagp;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	flagp = type->of;
Packit Service ae04f2
Packit Service ae04f2
	return (parse_sockaddrsub(pctx, &cfg_type_sockaddr, *flagp, ret));
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj) {
Packit Service ae04f2
	isc_netaddr_t netaddr;
Packit Service ae04f2
	in_port_t port;
Packit Service ae04f2
	char buf[ISC_NETADDR_FORMATSIZE];
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
Packit Service ae04f2
	isc_netaddr_fromsockaddr(&netaddr, &obj->value.sockaddr);
Packit Service ae04f2
	isc_netaddr_format(&netaddr, buf, sizeof(buf));
Packit Service ae04f2
	cfg_print_cstr(pctx, buf);
Packit Service ae04f2
	port = isc_sockaddr_getport(&obj->value.sockaddr);
Packit Service ae04f2
	if (port != 0) {
Packit Service ae04f2
		cfg_print_cstr(pctx, " port ");
Packit Service ae04f2
		cfg_print_rawuint(pctx, port);
Packit Service ae04f2
	}
Packit Service ae04f2
	if (obj->value.sockaddrdscp.dscp != -1) {
Packit Service ae04f2
		cfg_print_cstr(pctx, " dscp ");
Packit Service ae04f2
		cfg_print_rawuint(pctx, obj->value.sockaddrdscp.dscp);
Packit Service ae04f2
	}
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) {
Packit Service ae04f2
	const unsigned int *flagp;
Packit Service ae04f2
	int n = 0;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
Packit Service ae04f2
	flagp = type->of;
Packit Service ae04f2
Packit Service ae04f2
	cfg_print_cstr(pctx, "( ");
Packit Service ae04f2
	if ((*flagp & CFG_ADDR_V4OK) != 0) {
Packit Service ae04f2
		cfg_print_cstr(pctx, "<ipv4_address>");
Packit Service ae04f2
		n++;
Packit Service ae04f2
	}
Packit Service ae04f2
	if ((*flagp & CFG_ADDR_V6OK) != 0) {
Packit Service ae04f2
		if (n != 0)
Packit Service ae04f2
			cfg_print_cstr(pctx, " | ");
Packit Service ae04f2
		cfg_print_cstr(pctx, "<ipv6_address>");
Packit Service ae04f2
		n++;
Packit Service ae04f2
	}
Packit Service ae04f2
	if ((*flagp & CFG_ADDR_WILDOK) != 0) {
Packit Service ae04f2
		if (n != 0)
Packit Service ae04f2
			cfg_print_cstr(pctx, " | ");
Packit Service ae04f2
		cfg_print_cstr(pctx, "*");
Packit Service ae04f2
		n++;
Packit Service ae04f2
		POST(n);
Packit Service ae04f2
	}
Packit Service ae04f2
	cfg_print_cstr(pctx, " ) ");
Packit Service ae04f2
	if ((*flagp & CFG_ADDR_WILDOK) != 0) {
Packit Service ae04f2
		cfg_print_cstr(pctx, "[ port ( <integer> | * ) ]");
Packit Service ae04f2
	} else {
Packit Service ae04f2
		cfg_print_cstr(pctx, "[ port <integer> ]");
Packit Service ae04f2
	}
Packit Service ae04f2
	if ((*flagp & CFG_ADDR_DSCPOK) != 0) {
Packit Service ae04f2
		cfg_print_cstr(pctx, " [ dscp <integer> ]");
Packit Service ae04f2
	}
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
bool
Packit Service ae04f2
cfg_obj_issockaddr(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
	return (obj->type->rep == &cfg_rep_sockaddr);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
const isc_sockaddr_t *
Packit Service ae04f2
cfg_obj_assockaddr(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr);
Packit Service ae04f2
	return (&obj->value.sockaddr);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_dscp_t
Packit Service ae04f2
cfg_obj_getdscp(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr);
Packit Service ae04f2
	return (obj->value.sockaddrdscp.dscp);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_gettoken(cfg_parser_t *pctx, int options) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
Packit Service ae04f2
	if (pctx->seen_eof)
Packit Service ae04f2
		return (ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
	options |= (ISC_LEXOPT_EOF | ISC_LEXOPT_NOMORE);
Packit Service ae04f2
Packit Service ae04f2
 redo:
Packit Service ae04f2
	pctx->token.type = isc_tokentype_unknown;
Packit Service ae04f2
	result = isc_lex_gettoken(pctx->lexer, options, &pctx->token);
Packit Service ae04f2
	pctx->ungotten = false;
Packit Service ae04f2
	pctx->line = isc_lex_getsourceline(pctx->lexer);
Packit Service ae04f2
Packit Service ae04f2
	switch (result) {
Packit Service ae04f2
	case ISC_R_SUCCESS:
Packit Service ae04f2
		if (pctx->token.type == isc_tokentype_eof) {
Packit Service ae04f2
			result = isc_lex_close(pctx->lexer);
Packit Service ae04f2
			INSIST(result == ISC_R_NOMORE ||
Packit Service ae04f2
			       result == ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
			if (isc_lex_getsourcename(pctx->lexer) != NULL) {
Packit Service ae04f2
				/*
Packit Service ae04f2
				 * Closed an included file, not the main file.
Packit Service ae04f2
				 */
Packit Service ae04f2
				cfg_listelt_t *elt;
Packit Service ae04f2
				elt = ISC_LIST_TAIL(pctx->open_files->
Packit Service ae04f2
						    value.list);
Packit Service ae04f2
				INSIST(elt != NULL);
Packit Service ae04f2
				ISC_LIST_UNLINK(pctx->open_files->
Packit Service ae04f2
						value.list, elt, link);
Packit Service ae04f2
				ISC_LIST_APPEND(pctx->closed_files->
Packit Service ae04f2
						value.list, elt, link);
Packit Service ae04f2
				goto redo;
Packit Service ae04f2
			}
Packit Service ae04f2
			pctx->seen_eof = true;
Packit Service ae04f2
		}
Packit Service ae04f2
		break;
Packit Service ae04f2
Packit Service ae04f2
	case ISC_R_NOSPACE:
Packit Service ae04f2
		/* More understandable than "ran out of space". */
Packit Service ae04f2
		cfg_parser_error(pctx, CFG_LOG_NEAR, "token too big");
Packit Service ae04f2
		break;
Packit Service ae04f2
Packit Service ae04f2
	case ISC_R_IOERROR:
Packit Service ae04f2
		cfg_parser_error(pctx, 0, "%s",
Packit Service ae04f2
				 isc_result_totext(result));
Packit Service ae04f2
		break;
Packit Service ae04f2
Packit Service ae04f2
	default:
Packit Service ae04f2
		cfg_parser_error(pctx, CFG_LOG_NEAR, "%s",
Packit Service ae04f2
				 isc_result_totext(result));
Packit Service ae04f2
		break;
Packit Service ae04f2
	}
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_ungettoken(cfg_parser_t *pctx) {
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
Packit Service ae04f2
	if (pctx->seen_eof)
Packit Service ae04f2
		return;
Packit Service ae04f2
	isc_lex_ungettoken(pctx->lexer, &pctx->token);
Packit Service ae04f2
	pctx->ungotten = true;
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_peektoken(cfg_parser_t *pctx, int options) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_gettoken(pctx, options));
Packit Service ae04f2
	cfg_ungettoken(pctx);
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Get a string token, accepting both the quoted and the unquoted form.
Packit Service ae04f2
 * Log an error if the next token is not a string.
Packit Service ae04f2
 */
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
cfg_getstringtoken(cfg_parser_t *pctx) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	result = cfg_gettoken(pctx, CFG_LEXOPT_QSTRING);
Packit Service ae04f2
	if (result != ISC_R_SUCCESS)
Packit Service ae04f2
		return (result);
Packit Service ae04f2
Packit Service ae04f2
	if (pctx->token.type != isc_tokentype_string &&
Packit Service ae04f2
	    pctx->token.type != isc_tokentype_qstring) {
Packit Service ae04f2
		cfg_parser_error(pctx, CFG_LOG_NEAR, "expected string");
Packit Service ae04f2
		return (ISC_R_UNEXPECTEDTOKEN);
Packit Service ae04f2
	}
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) {
Packit Service ae04f2
	va_list args;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(fmt != NULL);
Packit Service ae04f2
Packit Service ae04f2
	va_start(args, fmt);
Packit Service ae04f2
	parser_complain(pctx, false, flags, fmt, args);
Packit Service ae04f2
	va_end(args);
Packit Service ae04f2
	pctx->errors++;
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_parser_warning(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) {
Packit Service ae04f2
	va_list args;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(fmt != NULL);
Packit Service ae04f2
Packit Service ae04f2
	va_start(args, fmt);
Packit Service ae04f2
	parser_complain(pctx, true, flags, fmt, args);
Packit Service ae04f2
	va_end(args);
Packit Service ae04f2
	pctx->warnings++;
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
#define MAX_LOG_TOKEN 30 /* How much of a token to quote in log messages. */
Packit Service ae04f2
Packit Service ae04f2
static bool
Packit Service ae04f2
have_current_file(cfg_parser_t *pctx) {
Packit Service ae04f2
	cfg_listelt_t *elt;
Packit Service ae04f2
	if (pctx->open_files == NULL)
Packit Service ae04f2
		return (false);
Packit Service ae04f2
Packit Service ae04f2
	elt = ISC_LIST_TAIL(pctx->open_files->value.list);
Packit Service ae04f2
	if (elt == NULL)
Packit Service ae04f2
	      return (false);
Packit Service ae04f2
Packit Service ae04f2
	return (true);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static char *
Packit Service ae04f2
current_file(cfg_parser_t *pctx) {
Packit Service ae04f2
	static char none[] = "none";
Packit Service ae04f2
	cfg_listelt_t *elt;
Packit Service ae04f2
	cfg_obj_t *fileobj;
Packit Service ae04f2
Packit Service ae04f2
	if (!have_current_file(pctx))
Packit Service ae04f2
		return (none);
Packit Service ae04f2
Packit Service ae04f2
	elt = ISC_LIST_TAIL(pctx->open_files->value.list);
Packit Service ae04f2
	if (elt == NULL)	/* shouldn't be possible, but... */
Packit Service ae04f2
	      return (none);
Packit Service ae04f2
Packit Service ae04f2
	fileobj = elt->obj;
Packit Service ae04f2
	INSIST(fileobj->type == &cfg_type_qstring);
Packit Service ae04f2
	return (fileobj->value.string.base);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
parser_complain(cfg_parser_t *pctx, bool is_warning,
Packit Service ae04f2
		unsigned int flags, const char *format,
Packit Service ae04f2
		va_list args)
Packit Service ae04f2
{
Packit Service ae04f2
	char tokenbuf[MAX_LOG_TOKEN + 10];
Packit Service ae04f2
	static char where[PATH_MAX + 100];
Packit Service ae04f2
	static char message[2048];
Packit Service ae04f2
	int level = ISC_LOG_ERROR;
Packit Service ae04f2
	const char *prep = "";
Packit Service ae04f2
	size_t len;
Packit Service ae04f2
Packit Service ae04f2
	if (is_warning)
Packit Service ae04f2
		level = ISC_LOG_WARNING;
Packit Service ae04f2
Packit Service ae04f2
	where[0] = '\0';
Packit Service ae04f2
	if (have_current_file(pctx))
Packit Service ae04f2
		snprintf(where, sizeof(where), "%s:%u: ",
Packit Service ae04f2
			 current_file(pctx), pctx->line);
Packit Service ae04f2
	else if (pctx->buf_name != NULL)
Packit Service ae04f2
		snprintf(where, sizeof(where), "%s: ", pctx->buf_name);
Packit Service ae04f2
Packit Service ae04f2
	len = vsnprintf(message, sizeof(message), format, args);
Packit Service ae04f2
#define ELLIPSIS " ... "
Packit Service ae04f2
	if (len >= sizeof(message)) {
Packit Service ae04f2
		message[sizeof(message) - sizeof(ELLIPSIS)] = 0;
Packit Service ae04f2
		strlcat(message, ELLIPSIS, sizeof(message));
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	if ((flags & (CFG_LOG_NEAR|CFG_LOG_BEFORE|CFG_LOG_NOPREP)) != 0) {
Packit Service ae04f2
		isc_region_t r;
Packit Service ae04f2
Packit Service ae04f2
		if (pctx->ungotten)
Packit Service ae04f2
			(void)cfg_gettoken(pctx, 0);
Packit Service ae04f2
Packit Service ae04f2
		if (pctx->token.type == isc_tokentype_eof) {
Packit Service ae04f2
			snprintf(tokenbuf, sizeof(tokenbuf), "end of file");
Packit Service ae04f2
		} else if (pctx->token.type == isc_tokentype_unknown) {
Packit Service ae04f2
			flags = 0;
Packit Service ae04f2
			tokenbuf[0] = '\0';
Packit Service ae04f2
		} else {
Packit Service ae04f2
			isc_lex_getlasttokentext(pctx->lexer,
Packit Service ae04f2
						 &pctx->token, &r);
Packit Service ae04f2
			if (r.length > MAX_LOG_TOKEN)
Packit Service ae04f2
				snprintf(tokenbuf, sizeof(tokenbuf),
Packit Service ae04f2
					 "'%.*s...'", MAX_LOG_TOKEN, r.base);
Packit Service ae04f2
			else
Packit Service ae04f2
				snprintf(tokenbuf, sizeof(tokenbuf),
Packit Service ae04f2
					 "'%.*s'", (int)r.length, r.base);
Packit Service ae04f2
		}
Packit Service ae04f2
Packit Service ae04f2
		/* Choose a preposition. */
Packit Service ae04f2
		if ((flags & CFG_LOG_NEAR) != 0) {
Packit Service ae04f2
			prep = " near ";
Packit Service ae04f2
		} else if ((flags & CFG_LOG_BEFORE) != 0) {
Packit Service ae04f2
			prep = " before ";
Packit Service ae04f2
		} else {
Packit Service ae04f2
			prep = " ";
Packit Service ae04f2
		}
Packit Service ae04f2
	} else {
Packit Service ae04f2
		tokenbuf[0] = '\0';
Packit Service ae04f2
	}
Packit Service ae04f2
	isc_log_write(pctx->lctx, CAT, MOD, level,
Packit Service ae04f2
		      "%s%s%s%s", where, message, prep, tokenbuf);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_obj_log(const cfg_obj_t *obj, isc_log_t *lctx, int level,
Packit Service ae04f2
	    const char *fmt, ...) {
Packit Service ae04f2
	va_list ap;
Packit Service ae04f2
	char msgbuf[2048];
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
	REQUIRE(fmt != NULL);
Packit Service ae04f2
Packit Service ae04f2
	if (! isc_log_wouldlog(lctx, level))
Packit Service ae04f2
		return;
Packit Service ae04f2
Packit Service ae04f2
	va_start(ap, fmt);
Packit Service ae04f2
	vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
Packit Service ae04f2
	va_end(ap);
Packit Service ae04f2
Packit Service ae04f2
	if (obj->file != NULL) {
Packit Service ae04f2
		isc_log_write(lctx, CAT, MOD, level,
Packit Service ae04f2
			      "%s:%u: %s", obj->file, obj->line, msgbuf);
Packit Service ae04f2
	} else {
Packit Service ae04f2
		isc_log_write(lctx, CAT, MOD, level, "%s", msgbuf);
Packit Service ae04f2
	}
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
const char *
Packit Service ae04f2
cfg_obj_file(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
Packit Service ae04f2
	return (obj->file);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
unsigned int
Packit Service ae04f2
cfg_obj_line(const cfg_obj_t *obj) {
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
Packit Service ae04f2
	return (obj->line);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	cfg_obj_t *obj;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
	REQUIRE(ret != NULL && *ret == NULL);
Packit Service ae04f2
Packit Service ae04f2
	obj = isc_mem_get(pctx->mctx, sizeof(cfg_obj_t));
Packit Service ae04f2
	if (obj == NULL)
Packit Service ae04f2
		return (ISC_R_NOMEMORY);
Packit Service ae04f2
Packit Service ae04f2
	obj->type = type;
Packit Service ae04f2
	obj->file = current_file(pctx);
Packit Service ae04f2
	obj->line = pctx->line;
Packit Service ae04f2
	obj->pctx = pctx;
Packit Service ae04f2
Packit Service ae04f2
	result = isc_refcount_init(&obj->references, 1);
Packit Service ae04f2
	if (result != ISC_R_SUCCESS) {
Packit Service ae04f2
		isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t));
Packit Service ae04f2
		return (result);
Packit Service ae04f2
	}
Packit Service ae04f2
	*ret = obj;
Packit Service ae04f2
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
map_symtabitem_destroy(char *key, unsigned int type,
Packit Service ae04f2
		       isc_symvalue_t symval, void *userarg)
Packit Service ae04f2
{
Packit Service ae04f2
	cfg_obj_t *obj = symval.as_pointer;
Packit Service ae04f2
	cfg_parser_t *pctx = (cfg_parser_t *)userarg;
Packit Service ae04f2
Packit Service ae04f2
	UNUSED(key);
Packit Service ae04f2
	UNUSED(type);
Packit Service ae04f2
Packit Service ae04f2
	cfg_obj_destroy(pctx, &obj);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
	isc_symtab_t *symtab = NULL;
Packit Service ae04f2
	cfg_obj_t *obj = NULL;
Packit Service ae04f2
Packit Service ae04f2
	CHECK(cfg_create_obj(pctx, type, &obj));
Packit Service ae04f2
	CHECK(isc_symtab_create(pctx->mctx, 5, /* XXX */
Packit Service ae04f2
				map_symtabitem_destroy,
Packit Service ae04f2
				pctx, false, &symtab));
Packit Service ae04f2
	obj->value.map.symtab = symtab;
Packit Service ae04f2
	obj->value.map.id = NULL;
Packit Service ae04f2
Packit Service ae04f2
	*ret = obj;
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	if (obj != NULL)
Packit Service ae04f2
		isc_mem_put(pctx->mctx, obj, sizeof(*obj));
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
free_map(cfg_parser_t *pctx, cfg_obj_t *obj) {
Packit Service ae04f2
	CLEANUP_OBJ(obj->value.map.id);
Packit Service ae04f2
	isc_symtab_destroy(&obj->value.map.symtab);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
bool
Packit Service ae04f2
cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type) {
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
Packit Service ae04f2
	return (obj->type == type);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Destroy 'obj', a configuration object created in 'pctx'.
Packit Service ae04f2
 */
Packit Service ae04f2
void
Packit Service ae04f2
cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **objp) {
Packit Service ae04f2
	cfg_obj_t *obj;
Packit Service ae04f2
	unsigned int refs;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(objp != NULL && *objp != NULL);
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
Packit Service ae04f2
	obj = *objp;
Packit Service ae04f2
Packit Service ae04f2
	isc_refcount_decrement(&obj->references, &refs);
Packit Service ae04f2
	if (refs == 0) {
Packit Service ae04f2
		obj->type->rep->free(pctx, obj);
Packit Service ae04f2
		isc_refcount_destroy(&obj->references);
Packit Service ae04f2
		isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t));
Packit Service ae04f2
	}
Packit Service ae04f2
	*objp = NULL;
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_obj_attach(cfg_obj_t *src, cfg_obj_t **dest) {
Packit Service ae04f2
    REQUIRE(src != NULL);
Packit Service ae04f2
    REQUIRE(dest != NULL && *dest == NULL);
Packit Service ae04f2
Packit Service ae04f2
    isc_refcount_increment(&src->references, NULL);
Packit Service ae04f2
    *dest = src;
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
free_noop(cfg_parser_t *pctx, cfg_obj_t *obj) {
Packit Service ae04f2
	UNUSED(pctx);
Packit Service ae04f2
	UNUSED(obj);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type) {
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
Packit Service ae04f2
	type->doc(pctx, type);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type) {
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(type != NULL);
Packit Service ae04f2
Packit Service ae04f2
	cfg_print_cstr(pctx, "<");
Packit Service ae04f2
	cfg_print_cstr(pctx, type->name);
Packit Service ae04f2
	cfg_print_cstr(pctx, ">");
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
cfg_print_grammar(const cfg_type_t *type,
Packit Service ae04f2
	void (*f)(void *closure, const char *text, int textlen),
Packit Service ae04f2
	void *closure)
Packit Service ae04f2
{
Packit Service ae04f2
	cfg_printer_t pctx;
Packit Service ae04f2
Packit Service ae04f2
	pctx.f = f;
Packit Service ae04f2
	pctx.closure = closure;
Packit Service ae04f2
	pctx.indent = 0;
Packit Service ae04f2
	pctx.flags = 0;
Packit Service ae04f2
	cfg_doc_obj(&pctx, type);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
cfg_parser_mapadd(cfg_parser_t *pctx, cfg_obj_t *mapobj,
Packit Service ae04f2
		  cfg_obj_t *obj, const char *clausename)
Packit Service ae04f2
{
Packit Service ae04f2
	isc_result_t result = ISC_R_SUCCESS;
Packit Service ae04f2
	const cfg_map_t *map;
Packit Service ae04f2
	isc_symvalue_t symval;
Packit Service ae04f2
	cfg_obj_t *destobj = NULL;
Packit Service ae04f2
	cfg_listelt_t *elt = NULL;
Packit Service ae04f2
	const cfg_clausedef_t * const *clauseset;
Packit Service ae04f2
	const cfg_clausedef_t *clause;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(pctx != NULL);
Packit Service ae04f2
	REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
Packit Service ae04f2
	REQUIRE(obj != NULL);
Packit Service ae04f2
	REQUIRE(clausename != NULL);
Packit Service ae04f2
Packit Service ae04f2
	map = &mapobj->value.map;
Packit Service ae04f2
Packit Service ae04f2
	clause = NULL;
Packit Service ae04f2
	for (clauseset = map->clausesets; *clauseset != NULL; clauseset++) {
Packit Service ae04f2
		for (clause = *clauseset; clause->name != NULL; clause++) {
Packit Service ae04f2
			if (strcasecmp(clause->name, clausename) == 0) {
Packit Service ae04f2
				goto breakout;
Packit Service ae04f2
			}
Packit Service ae04f2
		}
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
 breakout:
Packit Service ae04f2
	if (clause == NULL || clause->name == NULL)
Packit Service ae04f2
		return (ISC_R_FAILURE);
Packit Service ae04f2
Packit Service ae04f2
	result = isc_symtab_lookup(map->symtab, clausename, 0, &symval);
Packit Service ae04f2
	if (result == ISC_R_NOTFOUND) {
Packit Service ae04f2
		if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) {
Packit Service ae04f2
			CHECK(cfg_create_list(pctx, &cfg_type_implicitlist,
Packit Service ae04f2
					      &destobj));
Packit Service ae04f2
			CHECK(create_listelt(pctx, &elt));
Packit Service ae04f2
			cfg_obj_attach(obj, &elt->obj);
Packit Service ae04f2
			ISC_LIST_APPEND(destobj->value.list, elt, link);
Packit Service ae04f2
			symval.as_pointer = destobj;
Packit Service ae04f2
		} else
Packit Service ae04f2
			symval.as_pointer = obj;
Packit Service ae04f2
Packit Service ae04f2
		CHECK(isc_symtab_define(map->symtab, clausename, 1, symval,
Packit Service ae04f2
					isc_symexists_reject));
Packit Service ae04f2
	} else {
Packit Service ae04f2
		cfg_obj_t *destobj2 = symval.as_pointer;
Packit Service ae04f2
Packit Service ae04f2
		INSIST(result == ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
		if (destobj2->type == &cfg_type_implicitlist) {
Packit Service ae04f2
			CHECK(create_listelt(pctx, &elt));
Packit Service ae04f2
			cfg_obj_attach(obj, &elt->obj);
Packit Service ae04f2
			ISC_LIST_APPEND(destobj2->value.list, elt, link);
Packit Service ae04f2
		} else
Packit Service ae04f2
			result = ISC_R_EXISTS;
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	destobj = NULL;
Packit Service ae04f2
	elt = NULL;
Packit Service ae04f2
Packit Service ae04f2
 cleanup:
Packit Service ae04f2
	if (elt != NULL)
Packit Service ae04f2
		free_listelt(pctx, elt);
Packit Service ae04f2
	CLEANUP_OBJ(destobj);
Packit Service ae04f2
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}