xref: /minix3/external/bsd/bind/dist/lib/isccfg/parser.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: parser.c,v 1.9 2015/07/08 17:29:00 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (C) 2004-2015  Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek  * Copyright (C) 2000-2003  Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek  *
7*00b67f09SDavid van Moolenbroek  * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek  *
11*00b67f09SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek  * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek  */
19*00b67f09SDavid van Moolenbroek 
20*00b67f09SDavid van Moolenbroek /* Id */
21*00b67f09SDavid van Moolenbroek 
22*00b67f09SDavid van Moolenbroek /*! \file */
23*00b67f09SDavid van Moolenbroek 
24*00b67f09SDavid van Moolenbroek #include <config.h>
25*00b67f09SDavid van Moolenbroek 
26*00b67f09SDavid van Moolenbroek #include <isc/buffer.h>
27*00b67f09SDavid van Moolenbroek #include <isc/dir.h>
28*00b67f09SDavid van Moolenbroek #include <isc/formatcheck.h>
29*00b67f09SDavid van Moolenbroek #include <isc/lex.h>
30*00b67f09SDavid van Moolenbroek #include <isc/log.h>
31*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
32*00b67f09SDavid van Moolenbroek #include <isc/net.h>
33*00b67f09SDavid van Moolenbroek #include <isc/netaddr.h>
34*00b67f09SDavid van Moolenbroek #include <isc/netscope.h>
35*00b67f09SDavid van Moolenbroek #include <isc/print.h>
36*00b67f09SDavid van Moolenbroek #include <isc/string.h>
37*00b67f09SDavid van Moolenbroek #include <isc/sockaddr.h>
38*00b67f09SDavid van Moolenbroek #include <isc/symtab.h>
39*00b67f09SDavid van Moolenbroek #include <isc/util.h>
40*00b67f09SDavid van Moolenbroek 
41*00b67f09SDavid van Moolenbroek #include <isccfg/cfg.h>
42*00b67f09SDavid van Moolenbroek #include <isccfg/grammar.h>
43*00b67f09SDavid van Moolenbroek #include <isccfg/log.h>
44*00b67f09SDavid van Moolenbroek 
45*00b67f09SDavid van Moolenbroek /* Shorthand */
46*00b67f09SDavid van Moolenbroek #define CAT CFG_LOGCATEGORY_CONFIG
47*00b67f09SDavid van Moolenbroek #define MOD CFG_LOGMODULE_PARSER
48*00b67f09SDavid van Moolenbroek 
49*00b67f09SDavid van Moolenbroek #define MAP_SYM 1 	/* Unique type for isc_symtab */
50*00b67f09SDavid van Moolenbroek 
51*00b67f09SDavid van Moolenbroek #define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)
52*00b67f09SDavid van Moolenbroek 
53*00b67f09SDavid van Moolenbroek /* Check a return value. */
54*00b67f09SDavid van Moolenbroek #define CHECK(op) 						\
55*00b67f09SDavid van Moolenbroek 	do { result = (op); 					\
56*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) goto cleanup; 	\
57*00b67f09SDavid van Moolenbroek 	} while (/*CONSTCOND*/0)
58*00b67f09SDavid van Moolenbroek 
59*00b67f09SDavid van Moolenbroek /* Clean up a configuration object if non-NULL. */
60*00b67f09SDavid van Moolenbroek #define CLEANUP_OBJ(obj) \
61*00b67f09SDavid van Moolenbroek 	do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (/*CONSTCOND*/0)
62*00b67f09SDavid van Moolenbroek 
63*00b67f09SDavid van Moolenbroek 
64*00b67f09SDavid van Moolenbroek /*
65*00b67f09SDavid van Moolenbroek  * Forward declarations of static functions.
66*00b67f09SDavid van Moolenbroek  */
67*00b67f09SDavid van Moolenbroek 
68*00b67f09SDavid van Moolenbroek static void
69*00b67f09SDavid van Moolenbroek free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj);
70*00b67f09SDavid van Moolenbroek 
71*00b67f09SDavid van Moolenbroek static isc_result_t
72*00b67f09SDavid van Moolenbroek parse_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
73*00b67f09SDavid van Moolenbroek 
74*00b67f09SDavid van Moolenbroek static void
75*00b67f09SDavid van Moolenbroek print_list(cfg_printer_t *pctx, const cfg_obj_t *obj);
76*00b67f09SDavid van Moolenbroek 
77*00b67f09SDavid van Moolenbroek static void
78*00b67f09SDavid van Moolenbroek free_list(cfg_parser_t *pctx, cfg_obj_t *obj);
79*00b67f09SDavid van Moolenbroek 
80*00b67f09SDavid van Moolenbroek static isc_result_t
81*00b67f09SDavid van Moolenbroek create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp);
82*00b67f09SDavid van Moolenbroek 
83*00b67f09SDavid van Moolenbroek static isc_result_t
84*00b67f09SDavid van Moolenbroek create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type,
85*00b67f09SDavid van Moolenbroek 	      cfg_obj_t **ret);
86*00b67f09SDavid van Moolenbroek 
87*00b67f09SDavid van Moolenbroek static void
88*00b67f09SDavid van Moolenbroek free_string(cfg_parser_t *pctx, cfg_obj_t *obj);
89*00b67f09SDavid van Moolenbroek 
90*00b67f09SDavid van Moolenbroek static isc_result_t
91*00b67f09SDavid van Moolenbroek create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp);
92*00b67f09SDavid van Moolenbroek 
93*00b67f09SDavid van Moolenbroek static void
94*00b67f09SDavid van Moolenbroek free_map(cfg_parser_t *pctx, cfg_obj_t *obj);
95*00b67f09SDavid van Moolenbroek 
96*00b67f09SDavid van Moolenbroek static isc_result_t
97*00b67f09SDavid van Moolenbroek parse_symtab_elt(cfg_parser_t *pctx, const char *name,
98*00b67f09SDavid van Moolenbroek 		 cfg_type_t *elttype, isc_symtab_t *symtab,
99*00b67f09SDavid van Moolenbroek 		 isc_boolean_t callback);
100*00b67f09SDavid van Moolenbroek 
101*00b67f09SDavid van Moolenbroek static void
102*00b67f09SDavid van Moolenbroek free_noop(cfg_parser_t *pctx, cfg_obj_t *obj);
103*00b67f09SDavid van Moolenbroek 
104*00b67f09SDavid van Moolenbroek static isc_result_t
105*00b67f09SDavid van Moolenbroek cfg_getstringtoken(cfg_parser_t *pctx);
106*00b67f09SDavid van Moolenbroek 
107*00b67f09SDavid van Moolenbroek static void
108*00b67f09SDavid van Moolenbroek parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning,
109*00b67f09SDavid van Moolenbroek 		unsigned int flags, const char *format, va_list args);
110*00b67f09SDavid van Moolenbroek 
111*00b67f09SDavid van Moolenbroek /*
112*00b67f09SDavid van Moolenbroek  * Data representations.  These correspond to members of the
113*00b67f09SDavid van Moolenbroek  * "value" union in struct cfg_obj (except "void", which does
114*00b67f09SDavid van Moolenbroek  * not need a union member).
115*00b67f09SDavid van Moolenbroek  */
116*00b67f09SDavid van Moolenbroek 
117*00b67f09SDavid van Moolenbroek cfg_rep_t cfg_rep_uint32 = { "uint32", free_noop };
118*00b67f09SDavid van Moolenbroek cfg_rep_t cfg_rep_uint64 = { "uint64", free_noop };
119*00b67f09SDavid van Moolenbroek cfg_rep_t cfg_rep_string = { "string", free_string };
120*00b67f09SDavid van Moolenbroek cfg_rep_t cfg_rep_boolean = { "boolean", free_noop };
121*00b67f09SDavid van Moolenbroek cfg_rep_t cfg_rep_map = { "map", free_map };
122*00b67f09SDavid van Moolenbroek cfg_rep_t cfg_rep_list = { "list", free_list };
123*00b67f09SDavid van Moolenbroek cfg_rep_t cfg_rep_tuple = { "tuple", free_tuple };
124*00b67f09SDavid van Moolenbroek cfg_rep_t cfg_rep_sockaddr = { "sockaddr", free_noop };
125*00b67f09SDavid van Moolenbroek cfg_rep_t cfg_rep_netprefix = { "netprefix", free_noop };
126*00b67f09SDavid van Moolenbroek cfg_rep_t cfg_rep_void = { "void", free_noop };
127*00b67f09SDavid van Moolenbroek 
128*00b67f09SDavid van Moolenbroek /*
129*00b67f09SDavid van Moolenbroek  * Configuration type definitions.
130*00b67f09SDavid van Moolenbroek  */
131*00b67f09SDavid van Moolenbroek 
132*00b67f09SDavid van Moolenbroek /*%
133*00b67f09SDavid van Moolenbroek  * An implicit list.  These are formed by clauses that occur multiple times.
134*00b67f09SDavid van Moolenbroek  */
135*00b67f09SDavid van Moolenbroek static cfg_type_t cfg_type_implicitlist = {
136*00b67f09SDavid van Moolenbroek 	"implicitlist", NULL, print_list, NULL, &cfg_rep_list, NULL };
137*00b67f09SDavid van Moolenbroek 
138*00b67f09SDavid van Moolenbroek /* Functions. */
139*00b67f09SDavid van Moolenbroek 
140*00b67f09SDavid van Moolenbroek void
cfg_print_obj(cfg_printer_t * pctx,const cfg_obj_t * obj)141*00b67f09SDavid van Moolenbroek cfg_print_obj(cfg_printer_t *pctx, const cfg_obj_t *obj) {
142*00b67f09SDavid van Moolenbroek 	obj->type->print(pctx, obj);
143*00b67f09SDavid van Moolenbroek }
144*00b67f09SDavid van Moolenbroek 
145*00b67f09SDavid van Moolenbroek void
cfg_print_chars(cfg_printer_t * pctx,const char * text,int len)146*00b67f09SDavid van Moolenbroek cfg_print_chars(cfg_printer_t *pctx, const char *text, int len) {
147*00b67f09SDavid van Moolenbroek 	pctx->f(pctx->closure, text, len);
148*00b67f09SDavid van Moolenbroek }
149*00b67f09SDavid van Moolenbroek 
150*00b67f09SDavid van Moolenbroek static void
print_open(cfg_printer_t * pctx)151*00b67f09SDavid van Moolenbroek print_open(cfg_printer_t *pctx) {
152*00b67f09SDavid van Moolenbroek 	cfg_print_chars(pctx, "{\n", 2);
153*00b67f09SDavid van Moolenbroek 	pctx->indent++;
154*00b67f09SDavid van Moolenbroek }
155*00b67f09SDavid van Moolenbroek 
156*00b67f09SDavid van Moolenbroek static void
print_indent(cfg_printer_t * pctx)157*00b67f09SDavid van Moolenbroek print_indent(cfg_printer_t *pctx) {
158*00b67f09SDavid van Moolenbroek 	int indent = pctx->indent;
159*00b67f09SDavid van Moolenbroek 	while (indent > 0) {
160*00b67f09SDavid van Moolenbroek 		cfg_print_chars(pctx, "\t", 1);
161*00b67f09SDavid van Moolenbroek 		indent--;
162*00b67f09SDavid van Moolenbroek 	}
163*00b67f09SDavid van Moolenbroek }
164*00b67f09SDavid van Moolenbroek 
165*00b67f09SDavid van Moolenbroek static void
print_close(cfg_printer_t * pctx)166*00b67f09SDavid van Moolenbroek print_close(cfg_printer_t *pctx) {
167*00b67f09SDavid van Moolenbroek 	pctx->indent--;
168*00b67f09SDavid van Moolenbroek 	print_indent(pctx);
169*00b67f09SDavid van Moolenbroek 	cfg_print_chars(pctx, "}", 1);
170*00b67f09SDavid van Moolenbroek }
171*00b67f09SDavid van Moolenbroek 
172*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_obj(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)173*00b67f09SDavid van Moolenbroek cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
174*00b67f09SDavid van Moolenbroek 	isc_result_t result;
175*00b67f09SDavid van Moolenbroek 	INSIST(ret != NULL && *ret == NULL);
176*00b67f09SDavid van Moolenbroek 	result = type->parse(pctx, type, ret);
177*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
178*00b67f09SDavid van Moolenbroek 		return (result);
179*00b67f09SDavid van Moolenbroek 	INSIST(*ret != NULL);
180*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
181*00b67f09SDavid van Moolenbroek }
182*00b67f09SDavid van Moolenbroek 
183*00b67f09SDavid van Moolenbroek void
cfg_print(const cfg_obj_t * obj,void (* f)(void * closure,const char * text,int textlen),void * closure)184*00b67f09SDavid van Moolenbroek cfg_print(const cfg_obj_t *obj,
185*00b67f09SDavid van Moolenbroek 	  void (*f)(void *closure, const char *text, int textlen),
186*00b67f09SDavid van Moolenbroek 	  void *closure)
187*00b67f09SDavid van Moolenbroek {
188*00b67f09SDavid van Moolenbroek 	cfg_printx(obj, 0, f, closure);
189*00b67f09SDavid van Moolenbroek }
190*00b67f09SDavid van Moolenbroek 
191*00b67f09SDavid van Moolenbroek void
cfg_printx(const cfg_obj_t * obj,unsigned int flags,void (* f)(void * closure,const char * text,int textlen),void * closure)192*00b67f09SDavid van Moolenbroek cfg_printx(const cfg_obj_t *obj, unsigned int flags,
193*00b67f09SDavid van Moolenbroek 	     void (*f)(void *closure, const char *text, int textlen),
194*00b67f09SDavid van Moolenbroek 	     void *closure)
195*00b67f09SDavid van Moolenbroek {
196*00b67f09SDavid van Moolenbroek 	cfg_printer_t pctx;
197*00b67f09SDavid van Moolenbroek 	pctx.f = f;
198*00b67f09SDavid van Moolenbroek 	pctx.closure = closure;
199*00b67f09SDavid van Moolenbroek 	pctx.indent = 0;
200*00b67f09SDavid van Moolenbroek 	pctx.flags = flags;
201*00b67f09SDavid van Moolenbroek 	obj->type->print(&pctx, obj);
202*00b67f09SDavid van Moolenbroek }
203*00b67f09SDavid van Moolenbroek 
204*00b67f09SDavid van Moolenbroek /* Tuples. */
205*00b67f09SDavid van Moolenbroek 
206*00b67f09SDavid van Moolenbroek isc_result_t
cfg_create_tuple(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)207*00b67f09SDavid van Moolenbroek cfg_create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
208*00b67f09SDavid van Moolenbroek 	isc_result_t result;
209*00b67f09SDavid van Moolenbroek 	const cfg_tuplefielddef_t *fields = type->of;
210*00b67f09SDavid van Moolenbroek 	const cfg_tuplefielddef_t *f;
211*00b67f09SDavid van Moolenbroek 	cfg_obj_t *obj = NULL;
212*00b67f09SDavid van Moolenbroek 	unsigned int nfields = 0;
213*00b67f09SDavid van Moolenbroek 	int i;
214*00b67f09SDavid van Moolenbroek 
215*00b67f09SDavid van Moolenbroek 	for (f = fields; f->name != NULL; f++)
216*00b67f09SDavid van Moolenbroek 		nfields++;
217*00b67f09SDavid van Moolenbroek 
218*00b67f09SDavid van Moolenbroek 	CHECK(cfg_create_obj(pctx, type, &obj));
219*00b67f09SDavid van Moolenbroek 	obj->value.tuple = isc_mem_get(pctx->mctx,
220*00b67f09SDavid van Moolenbroek 				       nfields * sizeof(cfg_obj_t *));
221*00b67f09SDavid van Moolenbroek 	if (obj->value.tuple == NULL) {
222*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOMEMORY;
223*00b67f09SDavid van Moolenbroek 		goto cleanup;
224*00b67f09SDavid van Moolenbroek 	}
225*00b67f09SDavid van Moolenbroek 	for (f = fields, i = 0; f->name != NULL; f++, i++)
226*00b67f09SDavid van Moolenbroek 		obj->value.tuple[i] = NULL;
227*00b67f09SDavid van Moolenbroek 	*ret = obj;
228*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
229*00b67f09SDavid van Moolenbroek 
230*00b67f09SDavid van Moolenbroek  cleanup:
231*00b67f09SDavid van Moolenbroek 	if (obj != NULL)
232*00b67f09SDavid van Moolenbroek 		isc_mem_put(pctx->mctx, obj, sizeof(*obj));
233*00b67f09SDavid van Moolenbroek 	return (result);
234*00b67f09SDavid van Moolenbroek }
235*00b67f09SDavid van Moolenbroek 
236*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_tuple(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)237*00b67f09SDavid van Moolenbroek cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
238*00b67f09SDavid van Moolenbroek {
239*00b67f09SDavid van Moolenbroek 	isc_result_t result;
240*00b67f09SDavid van Moolenbroek 	const cfg_tuplefielddef_t *fields = type->of;
241*00b67f09SDavid van Moolenbroek 	const cfg_tuplefielddef_t *f;
242*00b67f09SDavid van Moolenbroek 	cfg_obj_t *obj = NULL;
243*00b67f09SDavid van Moolenbroek 	unsigned int i;
244*00b67f09SDavid van Moolenbroek 
245*00b67f09SDavid van Moolenbroek 	CHECK(cfg_create_tuple(pctx, type, &obj));
246*00b67f09SDavid van Moolenbroek 	for (f = fields, i = 0; f->name != NULL; f++, i++)
247*00b67f09SDavid van Moolenbroek 		CHECK(cfg_parse_obj(pctx, f->type, &obj->value.tuple[i]));
248*00b67f09SDavid van Moolenbroek 
249*00b67f09SDavid van Moolenbroek 	*ret = obj;
250*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
251*00b67f09SDavid van Moolenbroek 
252*00b67f09SDavid van Moolenbroek  cleanup:
253*00b67f09SDavid van Moolenbroek 	CLEANUP_OBJ(obj);
254*00b67f09SDavid van Moolenbroek 	return (result);
255*00b67f09SDavid van Moolenbroek }
256*00b67f09SDavid van Moolenbroek 
257*00b67f09SDavid van Moolenbroek void
cfg_print_tuple(cfg_printer_t * pctx,const cfg_obj_t * obj)258*00b67f09SDavid van Moolenbroek cfg_print_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj) {
259*00b67f09SDavid van Moolenbroek 	unsigned int i;
260*00b67f09SDavid van Moolenbroek 	const cfg_tuplefielddef_t *fields = obj->type->of;
261*00b67f09SDavid van Moolenbroek 	const cfg_tuplefielddef_t *f;
262*00b67f09SDavid van Moolenbroek 	isc_boolean_t need_space = ISC_FALSE;
263*00b67f09SDavid van Moolenbroek 
264*00b67f09SDavid van Moolenbroek 	for (f = fields, i = 0; f->name != NULL; f++, i++) {
265*00b67f09SDavid van Moolenbroek 		const cfg_obj_t *fieldobj = obj->value.tuple[i];
266*00b67f09SDavid van Moolenbroek 		if (need_space)
267*00b67f09SDavid van Moolenbroek 			cfg_print_chars(pctx, " ", 1);
268*00b67f09SDavid van Moolenbroek 		cfg_print_obj(pctx, fieldobj);
269*00b67f09SDavid van Moolenbroek 		need_space = ISC_TF(fieldobj->type->print != cfg_print_void);
270*00b67f09SDavid van Moolenbroek 	}
271*00b67f09SDavid van Moolenbroek }
272*00b67f09SDavid van Moolenbroek 
273*00b67f09SDavid van Moolenbroek void
cfg_doc_tuple(cfg_printer_t * pctx,const cfg_type_t * type)274*00b67f09SDavid van Moolenbroek cfg_doc_tuple(cfg_printer_t *pctx, const cfg_type_t *type) {
275*00b67f09SDavid van Moolenbroek 	const cfg_tuplefielddef_t *fields = type->of;
276*00b67f09SDavid van Moolenbroek 	const cfg_tuplefielddef_t *f;
277*00b67f09SDavid van Moolenbroek 	isc_boolean_t need_space = ISC_FALSE;
278*00b67f09SDavid van Moolenbroek 
279*00b67f09SDavid van Moolenbroek 	for (f = fields; f->name != NULL; f++) {
280*00b67f09SDavid van Moolenbroek 		if (need_space)
281*00b67f09SDavid van Moolenbroek 			cfg_print_chars(pctx, " ", 1);
282*00b67f09SDavid van Moolenbroek 		cfg_doc_obj(pctx, f->type);
283*00b67f09SDavid van Moolenbroek 		need_space = ISC_TF(f->type->print != cfg_print_void);
284*00b67f09SDavid van Moolenbroek 	}
285*00b67f09SDavid van Moolenbroek }
286*00b67f09SDavid van Moolenbroek 
287*00b67f09SDavid van Moolenbroek static void
free_tuple(cfg_parser_t * pctx,cfg_obj_t * obj)288*00b67f09SDavid van Moolenbroek free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj) {
289*00b67f09SDavid van Moolenbroek 	unsigned int i;
290*00b67f09SDavid van Moolenbroek 	const cfg_tuplefielddef_t *fields = obj->type->of;
291*00b67f09SDavid van Moolenbroek 	const cfg_tuplefielddef_t *f;
292*00b67f09SDavid van Moolenbroek 	unsigned int nfields = 0;
293*00b67f09SDavid van Moolenbroek 
294*00b67f09SDavid van Moolenbroek 	if (obj->value.tuple == NULL)
295*00b67f09SDavid van Moolenbroek 		return;
296*00b67f09SDavid van Moolenbroek 
297*00b67f09SDavid van Moolenbroek 	for (f = fields, i = 0; f->name != NULL; f++, i++) {
298*00b67f09SDavid van Moolenbroek 		CLEANUP_OBJ(obj->value.tuple[i]);
299*00b67f09SDavid van Moolenbroek 		nfields++;
300*00b67f09SDavid van Moolenbroek 	}
301*00b67f09SDavid van Moolenbroek 	isc_mem_put(pctx->mctx, obj->value.tuple,
302*00b67f09SDavid van Moolenbroek 		    nfields * sizeof(cfg_obj_t *));
303*00b67f09SDavid van Moolenbroek }
304*00b67f09SDavid van Moolenbroek 
305*00b67f09SDavid van Moolenbroek isc_boolean_t
cfg_obj_istuple(const cfg_obj_t * obj)306*00b67f09SDavid van Moolenbroek cfg_obj_istuple(const cfg_obj_t *obj) {
307*00b67f09SDavid van Moolenbroek 	REQUIRE(obj != NULL);
308*00b67f09SDavid van Moolenbroek 	return (ISC_TF(obj->type->rep == &cfg_rep_tuple));
309*00b67f09SDavid van Moolenbroek }
310*00b67f09SDavid van Moolenbroek 
311*00b67f09SDavid van Moolenbroek const cfg_obj_t *
cfg_tuple_get(const cfg_obj_t * tupleobj,const char * name)312*00b67f09SDavid van Moolenbroek cfg_tuple_get(const cfg_obj_t *tupleobj, const char* name) {
313*00b67f09SDavid van Moolenbroek 	unsigned int i;
314*00b67f09SDavid van Moolenbroek 	const cfg_tuplefielddef_t *fields;
315*00b67f09SDavid van Moolenbroek 	const cfg_tuplefielddef_t *f;
316*00b67f09SDavid van Moolenbroek 
317*00b67f09SDavid van Moolenbroek 	REQUIRE(tupleobj != NULL && tupleobj->type->rep == &cfg_rep_tuple);
318*00b67f09SDavid van Moolenbroek 
319*00b67f09SDavid van Moolenbroek 	fields = tupleobj->type->of;
320*00b67f09SDavid van Moolenbroek 	for (f = fields, i = 0; f->name != NULL; f++, i++) {
321*00b67f09SDavid van Moolenbroek 		if (strcmp(f->name, name) == 0)
322*00b67f09SDavid van Moolenbroek 			return (tupleobj->value.tuple[i]);
323*00b67f09SDavid van Moolenbroek 	}
324*00b67f09SDavid van Moolenbroek 	INSIST(0);
325*00b67f09SDavid van Moolenbroek 	return (NULL);
326*00b67f09SDavid van Moolenbroek }
327*00b67f09SDavid van Moolenbroek 
328*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_special(cfg_parser_t * pctx,int special)329*00b67f09SDavid van Moolenbroek cfg_parse_special(cfg_parser_t *pctx, int special) {
330*00b67f09SDavid van Moolenbroek 	isc_result_t result;
331*00b67f09SDavid van Moolenbroek 	CHECK(cfg_gettoken(pctx, 0));
332*00b67f09SDavid van Moolenbroek 	if (pctx->token.type == isc_tokentype_special &&
333*00b67f09SDavid van Moolenbroek 	    pctx->token.value.as_char == special)
334*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
335*00b67f09SDavid van Moolenbroek 
336*00b67f09SDavid van Moolenbroek 	cfg_parser_error(pctx, CFG_LOG_NEAR, "'%c' expected", special);
337*00b67f09SDavid van Moolenbroek 	return (ISC_R_UNEXPECTEDTOKEN);
338*00b67f09SDavid van Moolenbroek  cleanup:
339*00b67f09SDavid van Moolenbroek 	return (result);
340*00b67f09SDavid van Moolenbroek }
341*00b67f09SDavid van Moolenbroek 
342*00b67f09SDavid van Moolenbroek /*
343*00b67f09SDavid van Moolenbroek  * Parse a required semicolon.  If it is not there, log
344*00b67f09SDavid van Moolenbroek  * an error and increment the error count but continue
345*00b67f09SDavid van Moolenbroek  * parsing.  Since the next token is pushed back,
346*00b67f09SDavid van Moolenbroek  * care must be taken to make sure it is eventually
347*00b67f09SDavid van Moolenbroek  * consumed or an infinite loop may result.
348*00b67f09SDavid van Moolenbroek  */
349*00b67f09SDavid van Moolenbroek static isc_result_t
parse_semicolon(cfg_parser_t * pctx)350*00b67f09SDavid van Moolenbroek parse_semicolon(cfg_parser_t *pctx) {
351*00b67f09SDavid van Moolenbroek 	isc_result_t result;
352*00b67f09SDavid van Moolenbroek 	CHECK(cfg_gettoken(pctx, 0));
353*00b67f09SDavid van Moolenbroek 	if (pctx->token.type == isc_tokentype_special &&
354*00b67f09SDavid van Moolenbroek 	    pctx->token.value.as_char == ';')
355*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
356*00b67f09SDavid van Moolenbroek 
357*00b67f09SDavid van Moolenbroek 	cfg_parser_error(pctx, CFG_LOG_BEFORE, "missing ';'");
358*00b67f09SDavid van Moolenbroek 	cfg_ungettoken(pctx);
359*00b67f09SDavid van Moolenbroek  cleanup:
360*00b67f09SDavid van Moolenbroek 	return (result);
361*00b67f09SDavid van Moolenbroek }
362*00b67f09SDavid van Moolenbroek 
363*00b67f09SDavid van Moolenbroek /*
364*00b67f09SDavid van Moolenbroek  * Parse EOF, logging and returning an error if not there.
365*00b67f09SDavid van Moolenbroek  */
366*00b67f09SDavid van Moolenbroek static isc_result_t
parse_eof(cfg_parser_t * pctx)367*00b67f09SDavid van Moolenbroek parse_eof(cfg_parser_t *pctx) {
368*00b67f09SDavid van Moolenbroek 	isc_result_t result;
369*00b67f09SDavid van Moolenbroek 	CHECK(cfg_gettoken(pctx, 0));
370*00b67f09SDavid van Moolenbroek 
371*00b67f09SDavid van Moolenbroek 	if (pctx->token.type == isc_tokentype_eof)
372*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
373*00b67f09SDavid van Moolenbroek 
374*00b67f09SDavid van Moolenbroek 	cfg_parser_error(pctx, CFG_LOG_NEAR, "syntax error");
375*00b67f09SDavid van Moolenbroek 	return (ISC_R_UNEXPECTEDTOKEN);
376*00b67f09SDavid van Moolenbroek  cleanup:
377*00b67f09SDavid van Moolenbroek 	return (result);
378*00b67f09SDavid van Moolenbroek }
379*00b67f09SDavid van Moolenbroek 
380*00b67f09SDavid van Moolenbroek /* A list of files, used internally for pctx->files. */
381*00b67f09SDavid van Moolenbroek 
382*00b67f09SDavid van Moolenbroek static cfg_type_t cfg_type_filelist = {
383*00b67f09SDavid van Moolenbroek 	"filelist", NULL, print_list, NULL, &cfg_rep_list,
384*00b67f09SDavid van Moolenbroek 	&cfg_type_qstring
385*00b67f09SDavid van Moolenbroek };
386*00b67f09SDavid van Moolenbroek 
387*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parser_create(isc_mem_t * mctx,isc_log_t * lctx,cfg_parser_t ** ret)388*00b67f09SDavid van Moolenbroek cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) {
389*00b67f09SDavid van Moolenbroek 	isc_result_t result;
390*00b67f09SDavid van Moolenbroek 	cfg_parser_t *pctx;
391*00b67f09SDavid van Moolenbroek 	isc_lexspecials_t specials;
392*00b67f09SDavid van Moolenbroek 
393*00b67f09SDavid van Moolenbroek 	REQUIRE(mctx != NULL);
394*00b67f09SDavid van Moolenbroek 	REQUIRE(ret != NULL && *ret == NULL);
395*00b67f09SDavid van Moolenbroek 
396*00b67f09SDavid van Moolenbroek 	pctx = isc_mem_get(mctx, sizeof(*pctx));
397*00b67f09SDavid van Moolenbroek 	if (pctx == NULL)
398*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
399*00b67f09SDavid van Moolenbroek 
400*00b67f09SDavid van Moolenbroek 	pctx->mctx = NULL;
401*00b67f09SDavid van Moolenbroek 	isc_mem_attach(mctx, &pctx->mctx);
402*00b67f09SDavid van Moolenbroek 
403*00b67f09SDavid van Moolenbroek 	result = isc_refcount_init(&pctx->references, 1);
404*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
405*00b67f09SDavid van Moolenbroek 		isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx));
406*00b67f09SDavid van Moolenbroek 		return (result);
407*00b67f09SDavid van Moolenbroek 	}
408*00b67f09SDavid van Moolenbroek 
409*00b67f09SDavid van Moolenbroek 	pctx->lctx = lctx;
410*00b67f09SDavid van Moolenbroek 	pctx->lexer = NULL;
411*00b67f09SDavid van Moolenbroek 	pctx->seen_eof = ISC_FALSE;
412*00b67f09SDavid van Moolenbroek 	pctx->ungotten = ISC_FALSE;
413*00b67f09SDavid van Moolenbroek 	pctx->errors = 0;
414*00b67f09SDavid van Moolenbroek 	pctx->warnings = 0;
415*00b67f09SDavid van Moolenbroek 	pctx->open_files = NULL;
416*00b67f09SDavid van Moolenbroek 	pctx->closed_files = NULL;
417*00b67f09SDavid van Moolenbroek 	pctx->line = 0;
418*00b67f09SDavid van Moolenbroek 	pctx->callback = NULL;
419*00b67f09SDavid van Moolenbroek 	pctx->callbackarg = NULL;
420*00b67f09SDavid van Moolenbroek 	pctx->token.type = isc_tokentype_unknown;
421*00b67f09SDavid van Moolenbroek 	pctx->flags = 0;
422*00b67f09SDavid van Moolenbroek 
423*00b67f09SDavid van Moolenbroek 	memset(specials, 0, sizeof(specials));
424*00b67f09SDavid van Moolenbroek 	specials['{'] = 1;
425*00b67f09SDavid van Moolenbroek 	specials['}'] = 1;
426*00b67f09SDavid van Moolenbroek 	specials[';'] = 1;
427*00b67f09SDavid van Moolenbroek 	specials['/'] = 1;
428*00b67f09SDavid van Moolenbroek 	specials['"'] = 1;
429*00b67f09SDavid van Moolenbroek 	specials['!'] = 1;
430*00b67f09SDavid van Moolenbroek 
431*00b67f09SDavid van Moolenbroek 	CHECK(isc_lex_create(pctx->mctx, 1024, &pctx->lexer));
432*00b67f09SDavid van Moolenbroek 
433*00b67f09SDavid van Moolenbroek 	isc_lex_setspecials(pctx->lexer, specials);
434*00b67f09SDavid van Moolenbroek 	isc_lex_setcomments(pctx->lexer, (ISC_LEXCOMMENT_C |
435*00b67f09SDavid van Moolenbroek 					 ISC_LEXCOMMENT_CPLUSPLUS |
436*00b67f09SDavid van Moolenbroek 					 ISC_LEXCOMMENT_SHELL));
437*00b67f09SDavid van Moolenbroek 
438*00b67f09SDavid van Moolenbroek 	CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->open_files));
439*00b67f09SDavid van Moolenbroek 	CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->closed_files));
440*00b67f09SDavid van Moolenbroek 
441*00b67f09SDavid van Moolenbroek 	*ret = pctx;
442*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
443*00b67f09SDavid van Moolenbroek 
444*00b67f09SDavid van Moolenbroek  cleanup:
445*00b67f09SDavid van Moolenbroek 	if (pctx->lexer != NULL)
446*00b67f09SDavid van Moolenbroek 		isc_lex_destroy(&pctx->lexer);
447*00b67f09SDavid van Moolenbroek 	CLEANUP_OBJ(pctx->open_files);
448*00b67f09SDavid van Moolenbroek 	CLEANUP_OBJ(pctx->closed_files);
449*00b67f09SDavid van Moolenbroek 	isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx));
450*00b67f09SDavid van Moolenbroek 	return (result);
451*00b67f09SDavid van Moolenbroek }
452*00b67f09SDavid van Moolenbroek 
453*00b67f09SDavid van Moolenbroek static isc_result_t
parser_openfile(cfg_parser_t * pctx,const char * filename)454*00b67f09SDavid van Moolenbroek parser_openfile(cfg_parser_t *pctx, const char *filename) {
455*00b67f09SDavid van Moolenbroek 	isc_result_t result;
456*00b67f09SDavid van Moolenbroek 	cfg_listelt_t *elt = NULL;
457*00b67f09SDavid van Moolenbroek 	cfg_obj_t *stringobj = NULL;
458*00b67f09SDavid van Moolenbroek 
459*00b67f09SDavid van Moolenbroek 	result = isc_lex_openfile(pctx->lexer, filename);
460*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
461*00b67f09SDavid van Moolenbroek 		cfg_parser_error(pctx, 0, "open: %s: %s",
462*00b67f09SDavid van Moolenbroek 			     filename, isc_result_totext(result));
463*00b67f09SDavid van Moolenbroek 		goto cleanup;
464*00b67f09SDavid van Moolenbroek 	}
465*00b67f09SDavid van Moolenbroek 
466*00b67f09SDavid van Moolenbroek 	CHECK(create_string(pctx, filename, &cfg_type_qstring, &stringobj));
467*00b67f09SDavid van Moolenbroek 	CHECK(create_listelt(pctx, &elt));
468*00b67f09SDavid van Moolenbroek 	elt->obj = stringobj;
469*00b67f09SDavid van Moolenbroek 	ISC_LIST_APPEND(pctx->open_files->value.list, elt, link);
470*00b67f09SDavid van Moolenbroek 
471*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
472*00b67f09SDavid van Moolenbroek  cleanup:
473*00b67f09SDavid van Moolenbroek 	CLEANUP_OBJ(stringobj);
474*00b67f09SDavid van Moolenbroek 	return (result);
475*00b67f09SDavid van Moolenbroek }
476*00b67f09SDavid van Moolenbroek 
477*00b67f09SDavid van Moolenbroek void
cfg_parser_setcallback(cfg_parser_t * pctx,cfg_parsecallback_t callback,void * arg)478*00b67f09SDavid van Moolenbroek cfg_parser_setcallback(cfg_parser_t *pctx,
479*00b67f09SDavid van Moolenbroek 		       cfg_parsecallback_t callback,
480*00b67f09SDavid van Moolenbroek 		       void *arg)
481*00b67f09SDavid van Moolenbroek {
482*00b67f09SDavid van Moolenbroek 	pctx->callback = callback;
483*00b67f09SDavid van Moolenbroek 	pctx->callbackarg = arg;
484*00b67f09SDavid van Moolenbroek }
485*00b67f09SDavid van Moolenbroek 
486*00b67f09SDavid van Moolenbroek /*
487*00b67f09SDavid van Moolenbroek  * Parse a configuration using a pctx where a lexer has already
488*00b67f09SDavid van Moolenbroek  * been set up with a source.
489*00b67f09SDavid van Moolenbroek  */
490*00b67f09SDavid van Moolenbroek static isc_result_t
parse2(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)491*00b67f09SDavid van Moolenbroek parse2(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
492*00b67f09SDavid van Moolenbroek 	isc_result_t result;
493*00b67f09SDavid van Moolenbroek 	cfg_obj_t *obj = NULL;
494*00b67f09SDavid van Moolenbroek 
495*00b67f09SDavid van Moolenbroek 	result = cfg_parse_obj(pctx, type, &obj);
496*00b67f09SDavid van Moolenbroek 
497*00b67f09SDavid van Moolenbroek 	if (pctx->errors != 0) {
498*00b67f09SDavid van Moolenbroek 		/* Errors have been logged. */
499*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_SUCCESS)
500*00b67f09SDavid van Moolenbroek 			result = ISC_R_FAILURE;
501*00b67f09SDavid van Moolenbroek 		goto cleanup;
502*00b67f09SDavid van Moolenbroek 	}
503*00b67f09SDavid van Moolenbroek 
504*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
505*00b67f09SDavid van Moolenbroek 		/* Parsing failed but no errors have been logged. */
506*00b67f09SDavid van Moolenbroek 		cfg_parser_error(pctx, 0, "parsing failed");
507*00b67f09SDavid van Moolenbroek 		goto cleanup;
508*00b67f09SDavid van Moolenbroek 	}
509*00b67f09SDavid van Moolenbroek 
510*00b67f09SDavid van Moolenbroek 	CHECK(parse_eof(pctx));
511*00b67f09SDavid van Moolenbroek 
512*00b67f09SDavid van Moolenbroek 	*ret = obj;
513*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
514*00b67f09SDavid van Moolenbroek 
515*00b67f09SDavid van Moolenbroek  cleanup:
516*00b67f09SDavid van Moolenbroek 	CLEANUP_OBJ(obj);
517*00b67f09SDavid van Moolenbroek 	return (result);
518*00b67f09SDavid van Moolenbroek }
519*00b67f09SDavid van Moolenbroek 
520*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_file(cfg_parser_t * pctx,const char * filename,const cfg_type_t * type,cfg_obj_t ** ret)521*00b67f09SDavid van Moolenbroek cfg_parse_file(cfg_parser_t *pctx, const char *filename,
522*00b67f09SDavid van Moolenbroek 	       const cfg_type_t *type, cfg_obj_t **ret)
523*00b67f09SDavid van Moolenbroek {
524*00b67f09SDavid van Moolenbroek 	isc_result_t result;
525*00b67f09SDavid van Moolenbroek 
526*00b67f09SDavid van Moolenbroek 	REQUIRE(filename != NULL);
527*00b67f09SDavid van Moolenbroek 
528*00b67f09SDavid van Moolenbroek 	CHECK(parser_openfile(pctx, filename));
529*00b67f09SDavid van Moolenbroek 	CHECK(parse2(pctx, type, ret));
530*00b67f09SDavid van Moolenbroek  cleanup:
531*00b67f09SDavid van Moolenbroek 	return (result);
532*00b67f09SDavid van Moolenbroek }
533*00b67f09SDavid van Moolenbroek 
534*00b67f09SDavid van Moolenbroek 
535*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_buffer(cfg_parser_t * pctx,isc_buffer_t * buffer,const cfg_type_t * type,cfg_obj_t ** ret)536*00b67f09SDavid van Moolenbroek cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer,
537*00b67f09SDavid van Moolenbroek 	const cfg_type_t *type, cfg_obj_t **ret)
538*00b67f09SDavid van Moolenbroek {
539*00b67f09SDavid van Moolenbroek 	isc_result_t result;
540*00b67f09SDavid van Moolenbroek 	REQUIRE(buffer != NULL);
541*00b67f09SDavid van Moolenbroek 	CHECK(isc_lex_openbuffer(pctx->lexer, buffer));
542*00b67f09SDavid van Moolenbroek 	CHECK(parse2(pctx, type, ret));
543*00b67f09SDavid van Moolenbroek  cleanup:
544*00b67f09SDavid van Moolenbroek 	return (result);
545*00b67f09SDavid van Moolenbroek }
546*00b67f09SDavid van Moolenbroek 
547*00b67f09SDavid van Moolenbroek void
cfg_parser_attach(cfg_parser_t * src,cfg_parser_t ** dest)548*00b67f09SDavid van Moolenbroek cfg_parser_attach(cfg_parser_t *src, cfg_parser_t **dest) {
549*00b67f09SDavid van Moolenbroek 	REQUIRE(src != NULL);
550*00b67f09SDavid van Moolenbroek 	REQUIRE(dest != NULL && *dest == NULL);
551*00b67f09SDavid van Moolenbroek 	isc_refcount_increment(&src->references, NULL);
552*00b67f09SDavid van Moolenbroek 	*dest = src;
553*00b67f09SDavid van Moolenbroek }
554*00b67f09SDavid van Moolenbroek 
555*00b67f09SDavid van Moolenbroek void
cfg_parser_destroy(cfg_parser_t ** pctxp)556*00b67f09SDavid van Moolenbroek cfg_parser_destroy(cfg_parser_t **pctxp) {
557*00b67f09SDavid van Moolenbroek 	cfg_parser_t *pctx = *pctxp;
558*00b67f09SDavid van Moolenbroek 	unsigned int refs;
559*00b67f09SDavid van Moolenbroek 
560*00b67f09SDavid van Moolenbroek 	isc_refcount_decrement(&pctx->references, &refs);
561*00b67f09SDavid van Moolenbroek 	if (refs == 0) {
562*00b67f09SDavid van Moolenbroek 		isc_lex_destroy(&pctx->lexer);
563*00b67f09SDavid van Moolenbroek 		/*
564*00b67f09SDavid van Moolenbroek 		 * Cleaning up open_files does not
565*00b67f09SDavid van Moolenbroek 		 * close the files; that was already done
566*00b67f09SDavid van Moolenbroek 		 * by closing the lexer.
567*00b67f09SDavid van Moolenbroek 		 */
568*00b67f09SDavid van Moolenbroek 		CLEANUP_OBJ(pctx->open_files);
569*00b67f09SDavid van Moolenbroek 		CLEANUP_OBJ(pctx->closed_files);
570*00b67f09SDavid van Moolenbroek 		isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx));
571*00b67f09SDavid van Moolenbroek 	}
572*00b67f09SDavid van Moolenbroek 	*pctxp = NULL;
573*00b67f09SDavid van Moolenbroek }
574*00b67f09SDavid van Moolenbroek 
575*00b67f09SDavid van Moolenbroek /*
576*00b67f09SDavid van Moolenbroek  * void
577*00b67f09SDavid van Moolenbroek  */
578*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_void(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)579*00b67f09SDavid van Moolenbroek cfg_parse_void(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
580*00b67f09SDavid van Moolenbroek 	UNUSED(type);
581*00b67f09SDavid van Moolenbroek 	return (cfg_create_obj(pctx, &cfg_type_void, ret));
582*00b67f09SDavid van Moolenbroek }
583*00b67f09SDavid van Moolenbroek 
584*00b67f09SDavid van Moolenbroek void
cfg_print_void(cfg_printer_t * pctx,const cfg_obj_t * obj)585*00b67f09SDavid van Moolenbroek cfg_print_void(cfg_printer_t *pctx, const cfg_obj_t *obj) {
586*00b67f09SDavid van Moolenbroek 	UNUSED(pctx);
587*00b67f09SDavid van Moolenbroek 	UNUSED(obj);
588*00b67f09SDavid van Moolenbroek }
589*00b67f09SDavid van Moolenbroek 
590*00b67f09SDavid van Moolenbroek void
cfg_doc_void(cfg_printer_t * pctx,const cfg_type_t * type)591*00b67f09SDavid van Moolenbroek cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type) {
592*00b67f09SDavid van Moolenbroek 	UNUSED(pctx);
593*00b67f09SDavid van Moolenbroek 	UNUSED(type);
594*00b67f09SDavid van Moolenbroek }
595*00b67f09SDavid van Moolenbroek 
596*00b67f09SDavid van Moolenbroek isc_boolean_t
cfg_obj_isvoid(const cfg_obj_t * obj)597*00b67f09SDavid van Moolenbroek cfg_obj_isvoid(const cfg_obj_t *obj) {
598*00b67f09SDavid van Moolenbroek 	REQUIRE(obj != NULL);
599*00b67f09SDavid van Moolenbroek 	return (ISC_TF(obj->type->rep == &cfg_rep_void));
600*00b67f09SDavid van Moolenbroek }
601*00b67f09SDavid van Moolenbroek 
602*00b67f09SDavid van Moolenbroek cfg_type_t cfg_type_void = {
603*00b67f09SDavid van Moolenbroek 	"void", cfg_parse_void, cfg_print_void, cfg_doc_void, &cfg_rep_void,
604*00b67f09SDavid van Moolenbroek 	NULL };
605*00b67f09SDavid van Moolenbroek 
606*00b67f09SDavid van Moolenbroek 
607*00b67f09SDavid van Moolenbroek /*
608*00b67f09SDavid van Moolenbroek  * uint32
609*00b67f09SDavid van Moolenbroek  */
610*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_uint32(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)611*00b67f09SDavid van Moolenbroek cfg_parse_uint32(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
612*00b67f09SDavid van Moolenbroek 	isc_result_t result;
613*00b67f09SDavid van Moolenbroek 	cfg_obj_t *obj = NULL;
614*00b67f09SDavid van Moolenbroek 	UNUSED(type);
615*00b67f09SDavid van Moolenbroek 
616*00b67f09SDavid van Moolenbroek 	CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
617*00b67f09SDavid van Moolenbroek 	if (pctx->token.type != isc_tokentype_number) {
618*00b67f09SDavid van Moolenbroek 		cfg_parser_error(pctx, CFG_LOG_NEAR, "expected number");
619*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTEDTOKEN);
620*00b67f09SDavid van Moolenbroek 	}
621*00b67f09SDavid van Moolenbroek 
622*00b67f09SDavid van Moolenbroek 	CHECK(cfg_create_obj(pctx, &cfg_type_uint32, &obj));
623*00b67f09SDavid van Moolenbroek 
624*00b67f09SDavid van Moolenbroek 	obj->value.uint32 = pctx->token.value.as_ulong;
625*00b67f09SDavid van Moolenbroek 	*ret = obj;
626*00b67f09SDavid van Moolenbroek  cleanup:
627*00b67f09SDavid van Moolenbroek 	return (result);
628*00b67f09SDavid van Moolenbroek }
629*00b67f09SDavid van Moolenbroek 
630*00b67f09SDavid van Moolenbroek void
cfg_print_cstr(cfg_printer_t * pctx,const char * s)631*00b67f09SDavid van Moolenbroek cfg_print_cstr(cfg_printer_t *pctx, const char *s) {
632*00b67f09SDavid van Moolenbroek 	cfg_print_chars(pctx, s, strlen(s));
633*00b67f09SDavid van Moolenbroek }
634*00b67f09SDavid van Moolenbroek 
635*00b67f09SDavid van Moolenbroek void
cfg_print_rawuint(cfg_printer_t * pctx,unsigned int u)636*00b67f09SDavid van Moolenbroek cfg_print_rawuint(cfg_printer_t *pctx, unsigned int u) {
637*00b67f09SDavid van Moolenbroek 	char buf[32];
638*00b67f09SDavid van Moolenbroek 	snprintf(buf, sizeof(buf), "%u", u);
639*00b67f09SDavid van Moolenbroek 	cfg_print_cstr(pctx, buf);
640*00b67f09SDavid van Moolenbroek }
641*00b67f09SDavid van Moolenbroek 
642*00b67f09SDavid van Moolenbroek void
cfg_print_uint32(cfg_printer_t * pctx,const cfg_obj_t * obj)643*00b67f09SDavid van Moolenbroek cfg_print_uint32(cfg_printer_t *pctx, const cfg_obj_t *obj) {
644*00b67f09SDavid van Moolenbroek 	cfg_print_rawuint(pctx, obj->value.uint32);
645*00b67f09SDavid van Moolenbroek }
646*00b67f09SDavid van Moolenbroek 
647*00b67f09SDavid van Moolenbroek isc_boolean_t
cfg_obj_isuint32(const cfg_obj_t * obj)648*00b67f09SDavid van Moolenbroek cfg_obj_isuint32(const cfg_obj_t *obj) {
649*00b67f09SDavid van Moolenbroek 	REQUIRE(obj != NULL);
650*00b67f09SDavid van Moolenbroek 	return (ISC_TF(obj->type->rep == &cfg_rep_uint32));
651*00b67f09SDavid van Moolenbroek }
652*00b67f09SDavid van Moolenbroek 
653*00b67f09SDavid van Moolenbroek isc_uint32_t
cfg_obj_asuint32(const cfg_obj_t * obj)654*00b67f09SDavid van Moolenbroek cfg_obj_asuint32(const cfg_obj_t *obj) {
655*00b67f09SDavid van Moolenbroek 	REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint32);
656*00b67f09SDavid van Moolenbroek 	return (obj->value.uint32);
657*00b67f09SDavid van Moolenbroek }
658*00b67f09SDavid van Moolenbroek 
659*00b67f09SDavid van Moolenbroek cfg_type_t cfg_type_uint32 = {
660*00b67f09SDavid van Moolenbroek 	"integer", cfg_parse_uint32, cfg_print_uint32, cfg_doc_terminal,
661*00b67f09SDavid van Moolenbroek 	&cfg_rep_uint32, NULL
662*00b67f09SDavid van Moolenbroek };
663*00b67f09SDavid van Moolenbroek 
664*00b67f09SDavid van Moolenbroek 
665*00b67f09SDavid van Moolenbroek /*
666*00b67f09SDavid van Moolenbroek  * uint64
667*00b67f09SDavid van Moolenbroek  */
668*00b67f09SDavid van Moolenbroek isc_boolean_t
cfg_obj_isuint64(const cfg_obj_t * obj)669*00b67f09SDavid van Moolenbroek cfg_obj_isuint64(const cfg_obj_t *obj) {
670*00b67f09SDavid van Moolenbroek 	REQUIRE(obj != NULL);
671*00b67f09SDavid van Moolenbroek 	return (ISC_TF(obj->type->rep == &cfg_rep_uint64));
672*00b67f09SDavid van Moolenbroek }
673*00b67f09SDavid van Moolenbroek 
674*00b67f09SDavid van Moolenbroek isc_uint64_t
cfg_obj_asuint64(const cfg_obj_t * obj)675*00b67f09SDavid van Moolenbroek cfg_obj_asuint64(const cfg_obj_t *obj) {
676*00b67f09SDavid van Moolenbroek 	REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint64);
677*00b67f09SDavid van Moolenbroek 	return (obj->value.uint64);
678*00b67f09SDavid van Moolenbroek }
679*00b67f09SDavid van Moolenbroek 
680*00b67f09SDavid van Moolenbroek void
cfg_print_uint64(cfg_printer_t * pctx,const cfg_obj_t * obj)681*00b67f09SDavid van Moolenbroek cfg_print_uint64(cfg_printer_t *pctx, const cfg_obj_t *obj) {
682*00b67f09SDavid van Moolenbroek 	char buf[32];
683*00b67f09SDavid van Moolenbroek 	snprintf(buf, sizeof(buf), "%" ISC_PRINT_QUADFORMAT "u",
684*00b67f09SDavid van Moolenbroek 		 obj->value.uint64);
685*00b67f09SDavid van Moolenbroek 	cfg_print_cstr(pctx, buf);
686*00b67f09SDavid van Moolenbroek }
687*00b67f09SDavid van Moolenbroek 
688*00b67f09SDavid van Moolenbroek cfg_type_t cfg_type_uint64 = {
689*00b67f09SDavid van Moolenbroek 	"64_bit_integer", NULL, cfg_print_uint64, cfg_doc_terminal,
690*00b67f09SDavid van Moolenbroek 	&cfg_rep_uint64, NULL
691*00b67f09SDavid van Moolenbroek };
692*00b67f09SDavid van Moolenbroek 
693*00b67f09SDavid van Moolenbroek /*
694*00b67f09SDavid van Moolenbroek  * qstring (quoted string), ustring (unquoted string), astring
695*00b67f09SDavid van Moolenbroek  * (any string)
696*00b67f09SDavid van Moolenbroek  */
697*00b67f09SDavid van Moolenbroek 
698*00b67f09SDavid van Moolenbroek /* Create a string object from a null-terminated C string. */
699*00b67f09SDavid van Moolenbroek static isc_result_t
create_string(cfg_parser_t * pctx,const char * contents,const cfg_type_t * type,cfg_obj_t ** ret)700*00b67f09SDavid van Moolenbroek create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type,
701*00b67f09SDavid van Moolenbroek 	      cfg_obj_t **ret)
702*00b67f09SDavid van Moolenbroek {
703*00b67f09SDavid van Moolenbroek 	isc_result_t result;
704*00b67f09SDavid van Moolenbroek 	cfg_obj_t *obj = NULL;
705*00b67f09SDavid van Moolenbroek 	int len;
706*00b67f09SDavid van Moolenbroek 
707*00b67f09SDavid van Moolenbroek 	CHECK(cfg_create_obj(pctx, type, &obj));
708*00b67f09SDavid van Moolenbroek 	len = strlen(contents);
709*00b67f09SDavid van Moolenbroek 	obj->value.string.length = len;
710*00b67f09SDavid van Moolenbroek 	obj->value.string.base = isc_mem_get(pctx->mctx, len + 1);
711*00b67f09SDavid van Moolenbroek 	if (obj->value.string.base == 0) {
712*00b67f09SDavid van Moolenbroek 		isc_mem_put(pctx->mctx, obj, sizeof(*obj));
713*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
714*00b67f09SDavid van Moolenbroek 	}
715*00b67f09SDavid van Moolenbroek 	memmove(obj->value.string.base, contents, len);
716*00b67f09SDavid van Moolenbroek 	obj->value.string.base[len] = '\0';
717*00b67f09SDavid van Moolenbroek 
718*00b67f09SDavid van Moolenbroek 	*ret = obj;
719*00b67f09SDavid van Moolenbroek  cleanup:
720*00b67f09SDavid van Moolenbroek 	return (result);
721*00b67f09SDavid van Moolenbroek }
722*00b67f09SDavid van Moolenbroek 
723*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_qstring(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)724*00b67f09SDavid van Moolenbroek cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
725*00b67f09SDavid van Moolenbroek 	isc_result_t result;
726*00b67f09SDavid van Moolenbroek 	UNUSED(type);
727*00b67f09SDavid van Moolenbroek 
728*00b67f09SDavid van Moolenbroek 	CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
729*00b67f09SDavid van Moolenbroek 	if (pctx->token.type != isc_tokentype_qstring) {
730*00b67f09SDavid van Moolenbroek 		cfg_parser_error(pctx, CFG_LOG_NEAR, "expected quoted string");
731*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTEDTOKEN);
732*00b67f09SDavid van Moolenbroek 	}
733*00b67f09SDavid van Moolenbroek 	return (create_string(pctx,
734*00b67f09SDavid van Moolenbroek 			      TOKEN_STRING(pctx),
735*00b67f09SDavid van Moolenbroek 			      &cfg_type_qstring,
736*00b67f09SDavid van Moolenbroek 			      ret));
737*00b67f09SDavid van Moolenbroek  cleanup:
738*00b67f09SDavid van Moolenbroek 	return (result);
739*00b67f09SDavid van Moolenbroek }
740*00b67f09SDavid van Moolenbroek 
741*00b67f09SDavid van Moolenbroek static isc_result_t
parse_ustring(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)742*00b67f09SDavid van Moolenbroek parse_ustring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
743*00b67f09SDavid van Moolenbroek 	isc_result_t result;
744*00b67f09SDavid van Moolenbroek 	UNUSED(type);
745*00b67f09SDavid van Moolenbroek 
746*00b67f09SDavid van Moolenbroek 	CHECK(cfg_gettoken(pctx, 0));
747*00b67f09SDavid van Moolenbroek 	if (pctx->token.type != isc_tokentype_string) {
748*00b67f09SDavid van Moolenbroek 		cfg_parser_error(pctx, CFG_LOG_NEAR, "expected unquoted string");
749*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTEDTOKEN);
750*00b67f09SDavid van Moolenbroek 	}
751*00b67f09SDavid van Moolenbroek 	return (create_string(pctx,
752*00b67f09SDavid van Moolenbroek 			      TOKEN_STRING(pctx),
753*00b67f09SDavid van Moolenbroek 			      &cfg_type_ustring,
754*00b67f09SDavid van Moolenbroek 			      ret));
755*00b67f09SDavid van Moolenbroek  cleanup:
756*00b67f09SDavid van Moolenbroek 	return (result);
757*00b67f09SDavid van Moolenbroek }
758*00b67f09SDavid van Moolenbroek 
759*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_astring(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)760*00b67f09SDavid van Moolenbroek cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type,
761*00b67f09SDavid van Moolenbroek 		  cfg_obj_t **ret)
762*00b67f09SDavid van Moolenbroek {
763*00b67f09SDavid van Moolenbroek 	isc_result_t result;
764*00b67f09SDavid van Moolenbroek 	UNUSED(type);
765*00b67f09SDavid van Moolenbroek 
766*00b67f09SDavid van Moolenbroek 	CHECK(cfg_getstringtoken(pctx));
767*00b67f09SDavid van Moolenbroek 	return (create_string(pctx,
768*00b67f09SDavid van Moolenbroek 			      TOKEN_STRING(pctx),
769*00b67f09SDavid van Moolenbroek 			      &cfg_type_qstring,
770*00b67f09SDavid van Moolenbroek 			      ret));
771*00b67f09SDavid van Moolenbroek  cleanup:
772*00b67f09SDavid van Moolenbroek 	return (result);
773*00b67f09SDavid van Moolenbroek }
774*00b67f09SDavid van Moolenbroek 
775*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_sstring(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)776*00b67f09SDavid van Moolenbroek cfg_parse_sstring(cfg_parser_t *pctx, const cfg_type_t *type,
777*00b67f09SDavid van Moolenbroek 		  cfg_obj_t **ret)
778*00b67f09SDavid van Moolenbroek {
779*00b67f09SDavid van Moolenbroek 	isc_result_t result;
780*00b67f09SDavid van Moolenbroek 	UNUSED(type);
781*00b67f09SDavid van Moolenbroek 
782*00b67f09SDavid van Moolenbroek 	CHECK(cfg_getstringtoken(pctx));
783*00b67f09SDavid van Moolenbroek 	return (create_string(pctx,
784*00b67f09SDavid van Moolenbroek 			      TOKEN_STRING(pctx),
785*00b67f09SDavid van Moolenbroek 			      &cfg_type_sstring,
786*00b67f09SDavid van Moolenbroek 			      ret));
787*00b67f09SDavid van Moolenbroek  cleanup:
788*00b67f09SDavid van Moolenbroek 	return (result);
789*00b67f09SDavid van Moolenbroek }
790*00b67f09SDavid van Moolenbroek 
791*00b67f09SDavid van Moolenbroek isc_boolean_t
cfg_is_enum(const char * s,const char * const * enums)792*00b67f09SDavid van Moolenbroek cfg_is_enum(const char *s, const char *const *enums) {
793*00b67f09SDavid van Moolenbroek 	const char * const *p;
794*00b67f09SDavid van Moolenbroek 	for (p = enums; *p != NULL; p++) {
795*00b67f09SDavid van Moolenbroek 		if (strcasecmp(*p, s) == 0)
796*00b67f09SDavid van Moolenbroek 			return (ISC_TRUE);
797*00b67f09SDavid van Moolenbroek 	}
798*00b67f09SDavid van Moolenbroek 	return (ISC_FALSE);
799*00b67f09SDavid van Moolenbroek }
800*00b67f09SDavid van Moolenbroek 
801*00b67f09SDavid van Moolenbroek static isc_result_t
check_enum(cfg_parser_t * pctx,cfg_obj_t * obj,const char * const * enums)802*00b67f09SDavid van Moolenbroek check_enum(cfg_parser_t *pctx, cfg_obj_t *obj, const char *const *enums) {
803*00b67f09SDavid van Moolenbroek 	const char *s = obj->value.string.base;
804*00b67f09SDavid van Moolenbroek 	if (cfg_is_enum(s, enums))
805*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
806*00b67f09SDavid van Moolenbroek 	cfg_parser_error(pctx, 0, "'%s' unexpected", s);
807*00b67f09SDavid van Moolenbroek 	return (ISC_R_UNEXPECTEDTOKEN);
808*00b67f09SDavid van Moolenbroek }
809*00b67f09SDavid van Moolenbroek 
810*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_enum(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)811*00b67f09SDavid van Moolenbroek cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
812*00b67f09SDavid van Moolenbroek 	isc_result_t result;
813*00b67f09SDavid van Moolenbroek 	cfg_obj_t *obj = NULL;
814*00b67f09SDavid van Moolenbroek 	CHECK(parse_ustring(pctx, NULL, &obj));
815*00b67f09SDavid van Moolenbroek 	CHECK(check_enum(pctx, obj, type->of));
816*00b67f09SDavid van Moolenbroek 	*ret = obj;
817*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
818*00b67f09SDavid van Moolenbroek  cleanup:
819*00b67f09SDavid van Moolenbroek 	CLEANUP_OBJ(obj);
820*00b67f09SDavid van Moolenbroek 	return (result);
821*00b67f09SDavid van Moolenbroek }
822*00b67f09SDavid van Moolenbroek 
823*00b67f09SDavid van Moolenbroek void
cfg_doc_enum(cfg_printer_t * pctx,const cfg_type_t * type)824*00b67f09SDavid van Moolenbroek cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) {
825*00b67f09SDavid van Moolenbroek 	const char * const *p;
826*00b67f09SDavid van Moolenbroek 	cfg_print_chars(pctx, "( ", 2);
827*00b67f09SDavid van Moolenbroek 	for (p = type->of; *p != NULL; p++) {
828*00b67f09SDavid van Moolenbroek 		cfg_print_cstr(pctx, *p);
829*00b67f09SDavid van Moolenbroek 		if (p[1] != NULL)
830*00b67f09SDavid van Moolenbroek 			cfg_print_chars(pctx, " | ", 3);
831*00b67f09SDavid van Moolenbroek 	}
832*00b67f09SDavid van Moolenbroek 	cfg_print_chars(pctx, " )", 2);
833*00b67f09SDavid van Moolenbroek }
834*00b67f09SDavid van Moolenbroek 
835*00b67f09SDavid van Moolenbroek void
cfg_print_ustring(cfg_printer_t * pctx,const cfg_obj_t * obj)836*00b67f09SDavid van Moolenbroek cfg_print_ustring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
837*00b67f09SDavid van Moolenbroek 	cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length);
838*00b67f09SDavid van Moolenbroek }
839*00b67f09SDavid van Moolenbroek 
840*00b67f09SDavid van Moolenbroek static void
print_qstring(cfg_printer_t * pctx,const cfg_obj_t * obj)841*00b67f09SDavid van Moolenbroek print_qstring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
842*00b67f09SDavid van Moolenbroek 	cfg_print_chars(pctx, "\"", 1);
843*00b67f09SDavid van Moolenbroek 	cfg_print_ustring(pctx, obj);
844*00b67f09SDavid van Moolenbroek 	cfg_print_chars(pctx, "\"", 1);
845*00b67f09SDavid van Moolenbroek }
846*00b67f09SDavid van Moolenbroek 
847*00b67f09SDavid van Moolenbroek static void
print_sstring(cfg_printer_t * pctx,const cfg_obj_t * obj)848*00b67f09SDavid van Moolenbroek print_sstring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
849*00b67f09SDavid van Moolenbroek 	cfg_print_chars(pctx, "\"", 1);
850*00b67f09SDavid van Moolenbroek 	if ((pctx->flags & CFG_PRINTER_XKEY) != 0) {
851*00b67f09SDavid van Moolenbroek 		unsigned int len = obj->value.string.length;
852*00b67f09SDavid van Moolenbroek 		while (len-- > 0)
853*00b67f09SDavid van Moolenbroek 			cfg_print_chars(pctx, "?", 1);
854*00b67f09SDavid van Moolenbroek 	} else
855*00b67f09SDavid van Moolenbroek 		cfg_print_ustring(pctx, obj);
856*00b67f09SDavid van Moolenbroek 	cfg_print_chars(pctx, "\"", 1);
857*00b67f09SDavid van Moolenbroek }
858*00b67f09SDavid van Moolenbroek 
859*00b67f09SDavid van Moolenbroek static void
free_string(cfg_parser_t * pctx,cfg_obj_t * obj)860*00b67f09SDavid van Moolenbroek free_string(cfg_parser_t *pctx, cfg_obj_t *obj) {
861*00b67f09SDavid van Moolenbroek 	isc_mem_put(pctx->mctx, obj->value.string.base,
862*00b67f09SDavid van Moolenbroek 		    obj->value.string.length + 1);
863*00b67f09SDavid van Moolenbroek }
864*00b67f09SDavid van Moolenbroek 
865*00b67f09SDavid van Moolenbroek isc_boolean_t
cfg_obj_isstring(const cfg_obj_t * obj)866*00b67f09SDavid van Moolenbroek cfg_obj_isstring(const cfg_obj_t *obj) {
867*00b67f09SDavid van Moolenbroek 	REQUIRE(obj != NULL);
868*00b67f09SDavid van Moolenbroek 	return (ISC_TF(obj->type->rep == &cfg_rep_string));
869*00b67f09SDavid van Moolenbroek }
870*00b67f09SDavid van Moolenbroek 
871*00b67f09SDavid van Moolenbroek const char *
cfg_obj_asstring(const cfg_obj_t * obj)872*00b67f09SDavid van Moolenbroek cfg_obj_asstring(const cfg_obj_t *obj) {
873*00b67f09SDavid van Moolenbroek 	REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_string);
874*00b67f09SDavid van Moolenbroek 	return (obj->value.string.base);
875*00b67f09SDavid van Moolenbroek }
876*00b67f09SDavid van Moolenbroek 
877*00b67f09SDavid van Moolenbroek /* Quoted string only */
878*00b67f09SDavid van Moolenbroek cfg_type_t cfg_type_qstring = {
879*00b67f09SDavid van Moolenbroek 	"quoted_string", cfg_parse_qstring, print_qstring, cfg_doc_terminal,
880*00b67f09SDavid van Moolenbroek 	&cfg_rep_string, NULL
881*00b67f09SDavid van Moolenbroek };
882*00b67f09SDavid van Moolenbroek 
883*00b67f09SDavid van Moolenbroek /* Unquoted string only */
884*00b67f09SDavid van Moolenbroek cfg_type_t cfg_type_ustring = {
885*00b67f09SDavid van Moolenbroek 	"string", parse_ustring, cfg_print_ustring, cfg_doc_terminal,
886*00b67f09SDavid van Moolenbroek 	&cfg_rep_string, NULL
887*00b67f09SDavid van Moolenbroek };
888*00b67f09SDavid van Moolenbroek 
889*00b67f09SDavid van Moolenbroek /* Any string (quoted or unquoted); printed with quotes */
890*00b67f09SDavid van Moolenbroek cfg_type_t cfg_type_astring = {
891*00b67f09SDavid van Moolenbroek 	"string", cfg_parse_astring, print_qstring, cfg_doc_terminal,
892*00b67f09SDavid van Moolenbroek 	&cfg_rep_string, NULL
893*00b67f09SDavid van Moolenbroek };
894*00b67f09SDavid van Moolenbroek 
895*00b67f09SDavid van Moolenbroek /*
896*00b67f09SDavid van Moolenbroek  * Any string (quoted or unquoted); printed with quotes.
897*00b67f09SDavid van Moolenbroek  * If CFG_PRINTER_XKEY is set when printing the string will be '?' out.
898*00b67f09SDavid van Moolenbroek  */
899*00b67f09SDavid van Moolenbroek cfg_type_t cfg_type_sstring = {
900*00b67f09SDavid van Moolenbroek 	"string", cfg_parse_sstring, print_sstring, cfg_doc_terminal,
901*00b67f09SDavid van Moolenbroek 	&cfg_rep_string, NULL
902*00b67f09SDavid van Moolenbroek };
903*00b67f09SDavid van Moolenbroek 
904*00b67f09SDavid van Moolenbroek /*
905*00b67f09SDavid van Moolenbroek  * Booleans
906*00b67f09SDavid van Moolenbroek  */
907*00b67f09SDavid van Moolenbroek 
908*00b67f09SDavid van Moolenbroek isc_boolean_t
cfg_obj_isboolean(const cfg_obj_t * obj)909*00b67f09SDavid van Moolenbroek cfg_obj_isboolean(const cfg_obj_t *obj) {
910*00b67f09SDavid van Moolenbroek 	REQUIRE(obj != NULL);
911*00b67f09SDavid van Moolenbroek 	return (ISC_TF(obj->type->rep == &cfg_rep_boolean));
912*00b67f09SDavid van Moolenbroek }
913*00b67f09SDavid van Moolenbroek 
914*00b67f09SDavid van Moolenbroek isc_boolean_t
cfg_obj_asboolean(const cfg_obj_t * obj)915*00b67f09SDavid van Moolenbroek cfg_obj_asboolean(const cfg_obj_t *obj) {
916*00b67f09SDavid van Moolenbroek 	REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_boolean);
917*00b67f09SDavid van Moolenbroek 	return (obj->value.boolean);
918*00b67f09SDavid van Moolenbroek }
919*00b67f09SDavid van Moolenbroek 
920*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_boolean(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)921*00b67f09SDavid van Moolenbroek cfg_parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
922*00b67f09SDavid van Moolenbroek {
923*00b67f09SDavid van Moolenbroek 	isc_result_t result;
924*00b67f09SDavid van Moolenbroek 	isc_boolean_t value;
925*00b67f09SDavid van Moolenbroek 	cfg_obj_t *obj = NULL;
926*00b67f09SDavid van Moolenbroek 	UNUSED(type);
927*00b67f09SDavid van Moolenbroek 
928*00b67f09SDavid van Moolenbroek 	result = cfg_gettoken(pctx, 0);
929*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
930*00b67f09SDavid van Moolenbroek 		return (result);
931*00b67f09SDavid van Moolenbroek 
932*00b67f09SDavid van Moolenbroek 	if (pctx->token.type != isc_tokentype_string)
933*00b67f09SDavid van Moolenbroek 		goto bad_boolean;
934*00b67f09SDavid van Moolenbroek 
935*00b67f09SDavid van Moolenbroek 	if ((strcasecmp(TOKEN_STRING(pctx), "true") == 0) ||
936*00b67f09SDavid van Moolenbroek 	    (strcasecmp(TOKEN_STRING(pctx), "yes") == 0) ||
937*00b67f09SDavid van Moolenbroek 	    (strcmp(TOKEN_STRING(pctx), "1") == 0)) {
938*00b67f09SDavid van Moolenbroek 		value = ISC_TRUE;
939*00b67f09SDavid van Moolenbroek 	} else if ((strcasecmp(TOKEN_STRING(pctx), "false") == 0) ||
940*00b67f09SDavid van Moolenbroek 		   (strcasecmp(TOKEN_STRING(pctx), "no") == 0) ||
941*00b67f09SDavid van Moolenbroek 		   (strcmp(TOKEN_STRING(pctx), "0") == 0)) {
942*00b67f09SDavid van Moolenbroek 		value = ISC_FALSE;
943*00b67f09SDavid van Moolenbroek 	} else {
944*00b67f09SDavid van Moolenbroek 		goto bad_boolean;
945*00b67f09SDavid van Moolenbroek 	}
946*00b67f09SDavid van Moolenbroek 
947*00b67f09SDavid van Moolenbroek 	CHECK(cfg_create_obj(pctx, &cfg_type_boolean, &obj));
948*00b67f09SDavid van Moolenbroek 	obj->value.boolean = value;
949*00b67f09SDavid van Moolenbroek 	*ret = obj;
950*00b67f09SDavid van Moolenbroek 	return (result);
951*00b67f09SDavid van Moolenbroek 
952*00b67f09SDavid van Moolenbroek  bad_boolean:
953*00b67f09SDavid van Moolenbroek 	cfg_parser_error(pctx, CFG_LOG_NEAR, "boolean expected");
954*00b67f09SDavid van Moolenbroek 	return (ISC_R_UNEXPECTEDTOKEN);
955*00b67f09SDavid van Moolenbroek 
956*00b67f09SDavid van Moolenbroek  cleanup:
957*00b67f09SDavid van Moolenbroek 	return (result);
958*00b67f09SDavid van Moolenbroek }
959*00b67f09SDavid van Moolenbroek 
960*00b67f09SDavid van Moolenbroek void
cfg_print_boolean(cfg_printer_t * pctx,const cfg_obj_t * obj)961*00b67f09SDavid van Moolenbroek cfg_print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj) {
962*00b67f09SDavid van Moolenbroek 	if (obj->value.boolean)
963*00b67f09SDavid van Moolenbroek 		cfg_print_chars(pctx, "yes", 3);
964*00b67f09SDavid van Moolenbroek 	else
965*00b67f09SDavid van Moolenbroek 		cfg_print_chars(pctx, "no", 2);
966*00b67f09SDavid van Moolenbroek }
967*00b67f09SDavid van Moolenbroek 
968*00b67f09SDavid van Moolenbroek cfg_type_t cfg_type_boolean = {
969*00b67f09SDavid van Moolenbroek 	"boolean", cfg_parse_boolean, cfg_print_boolean, cfg_doc_terminal,
970*00b67f09SDavid van Moolenbroek 	&cfg_rep_boolean, NULL
971*00b67f09SDavid van Moolenbroek };
972*00b67f09SDavid van Moolenbroek 
973*00b67f09SDavid van Moolenbroek /*
974*00b67f09SDavid van Moolenbroek  * Lists.
975*00b67f09SDavid van Moolenbroek  */
976*00b67f09SDavid van Moolenbroek 
977*00b67f09SDavid van Moolenbroek isc_result_t
cfg_create_list(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** obj)978*00b67f09SDavid van Moolenbroek cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **obj) {
979*00b67f09SDavid van Moolenbroek 	isc_result_t result;
980*00b67f09SDavid van Moolenbroek 	CHECK(cfg_create_obj(pctx, type, obj));
981*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT((*obj)->value.list);
982*00b67f09SDavid van Moolenbroek  cleanup:
983*00b67f09SDavid van Moolenbroek 	return (result);
984*00b67f09SDavid van Moolenbroek }
985*00b67f09SDavid van Moolenbroek 
986*00b67f09SDavid van Moolenbroek static isc_result_t
create_listelt(cfg_parser_t * pctx,cfg_listelt_t ** eltp)987*00b67f09SDavid van Moolenbroek create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp) {
988*00b67f09SDavid van Moolenbroek 	cfg_listelt_t *elt;
989*00b67f09SDavid van Moolenbroek 	elt = isc_mem_get(pctx->mctx, sizeof(*elt));
990*00b67f09SDavid van Moolenbroek 	if (elt == NULL)
991*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
992*00b67f09SDavid van Moolenbroek 	elt->obj = NULL;
993*00b67f09SDavid van Moolenbroek 	ISC_LINK_INIT(elt, link);
994*00b67f09SDavid van Moolenbroek 	*eltp = elt;
995*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
996*00b67f09SDavid van Moolenbroek }
997*00b67f09SDavid van Moolenbroek 
998*00b67f09SDavid van Moolenbroek static void
free_list_elt(cfg_parser_t * pctx,cfg_listelt_t * elt)999*00b67f09SDavid van Moolenbroek free_list_elt(cfg_parser_t *pctx, cfg_listelt_t *elt) {
1000*00b67f09SDavid van Moolenbroek 	cfg_obj_destroy(pctx, &elt->obj);
1001*00b67f09SDavid van Moolenbroek 	isc_mem_put(pctx->mctx, elt, sizeof(*elt));
1002*00b67f09SDavid van Moolenbroek }
1003*00b67f09SDavid van Moolenbroek 
1004*00b67f09SDavid van Moolenbroek static void
free_list(cfg_parser_t * pctx,cfg_obj_t * obj)1005*00b67f09SDavid van Moolenbroek free_list(cfg_parser_t *pctx, cfg_obj_t *obj) {
1006*00b67f09SDavid van Moolenbroek 	cfg_listelt_t *elt, *next;
1007*00b67f09SDavid van Moolenbroek 	for (elt = ISC_LIST_HEAD(obj->value.list);
1008*00b67f09SDavid van Moolenbroek 	     elt != NULL;
1009*00b67f09SDavid van Moolenbroek 	     elt = next)
1010*00b67f09SDavid van Moolenbroek 	{
1011*00b67f09SDavid van Moolenbroek 		next = ISC_LIST_NEXT(elt, link);
1012*00b67f09SDavid van Moolenbroek 		free_list_elt(pctx, elt);
1013*00b67f09SDavid van Moolenbroek 	}
1014*00b67f09SDavid van Moolenbroek }
1015*00b67f09SDavid van Moolenbroek 
1016*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_listelt(cfg_parser_t * pctx,const cfg_type_t * elttype,cfg_listelt_t ** ret)1017*00b67f09SDavid van Moolenbroek cfg_parse_listelt(cfg_parser_t *pctx, const cfg_type_t *elttype,
1018*00b67f09SDavid van Moolenbroek 		  cfg_listelt_t **ret)
1019*00b67f09SDavid van Moolenbroek {
1020*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1021*00b67f09SDavid van Moolenbroek 	cfg_listelt_t *elt = NULL;
1022*00b67f09SDavid van Moolenbroek 	cfg_obj_t *value = NULL;
1023*00b67f09SDavid van Moolenbroek 
1024*00b67f09SDavid van Moolenbroek 	CHECK(create_listelt(pctx, &elt));
1025*00b67f09SDavid van Moolenbroek 
1026*00b67f09SDavid van Moolenbroek 	result = cfg_parse_obj(pctx, elttype, &value);
1027*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1028*00b67f09SDavid van Moolenbroek 		goto cleanup;
1029*00b67f09SDavid van Moolenbroek 
1030*00b67f09SDavid van Moolenbroek 	elt->obj = value;
1031*00b67f09SDavid van Moolenbroek 
1032*00b67f09SDavid van Moolenbroek 	*ret = elt;
1033*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
1034*00b67f09SDavid van Moolenbroek 
1035*00b67f09SDavid van Moolenbroek  cleanup:
1036*00b67f09SDavid van Moolenbroek 	isc_mem_put(pctx->mctx, elt, sizeof(*elt));
1037*00b67f09SDavid van Moolenbroek 	return (result);
1038*00b67f09SDavid van Moolenbroek }
1039*00b67f09SDavid van Moolenbroek 
1040*00b67f09SDavid van Moolenbroek /*
1041*00b67f09SDavid van Moolenbroek  * Parse a homogeneous list whose elements are of type 'elttype'
1042*00b67f09SDavid van Moolenbroek  * and where each element is terminated by a semicolon.
1043*00b67f09SDavid van Moolenbroek  */
1044*00b67f09SDavid van Moolenbroek static isc_result_t
parse_list(cfg_parser_t * pctx,const cfg_type_t * listtype,cfg_obj_t ** ret)1045*00b67f09SDavid van Moolenbroek parse_list(cfg_parser_t *pctx, const cfg_type_t *listtype, cfg_obj_t **ret)
1046*00b67f09SDavid van Moolenbroek {
1047*00b67f09SDavid van Moolenbroek 	cfg_obj_t *listobj = NULL;
1048*00b67f09SDavid van Moolenbroek 	const cfg_type_t *listof = listtype->of;
1049*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1050*00b67f09SDavid van Moolenbroek 	cfg_listelt_t *elt = NULL;
1051*00b67f09SDavid van Moolenbroek 
1052*00b67f09SDavid van Moolenbroek 	CHECK(cfg_create_list(pctx, listtype, &listobj));
1053*00b67f09SDavid van Moolenbroek 
1054*00b67f09SDavid van Moolenbroek 	for (;;) {
1055*00b67f09SDavid van Moolenbroek 		CHECK(cfg_peektoken(pctx, 0));
1056*00b67f09SDavid van Moolenbroek 		if (pctx->token.type == isc_tokentype_special &&
1057*00b67f09SDavid van Moolenbroek 		    pctx->token.value.as_char == /*{*/ '}')
1058*00b67f09SDavid van Moolenbroek 			break;
1059*00b67f09SDavid van Moolenbroek 		CHECK(cfg_parse_listelt(pctx, listof, &elt));
1060*00b67f09SDavid van Moolenbroek 		CHECK(parse_semicolon(pctx));
1061*00b67f09SDavid van Moolenbroek 		ISC_LIST_APPEND(listobj->value.list, elt, link);
1062*00b67f09SDavid van Moolenbroek 		elt = NULL;
1063*00b67f09SDavid van Moolenbroek 	}
1064*00b67f09SDavid van Moolenbroek 	*ret = listobj;
1065*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
1066*00b67f09SDavid van Moolenbroek 
1067*00b67f09SDavid van Moolenbroek  cleanup:
1068*00b67f09SDavid van Moolenbroek 	if (elt != NULL)
1069*00b67f09SDavid van Moolenbroek 		free_list_elt(pctx, elt);
1070*00b67f09SDavid van Moolenbroek 	CLEANUP_OBJ(listobj);
1071*00b67f09SDavid van Moolenbroek 	return (result);
1072*00b67f09SDavid van Moolenbroek }
1073*00b67f09SDavid van Moolenbroek 
1074*00b67f09SDavid van Moolenbroek static void
print_list(cfg_printer_t * pctx,const cfg_obj_t * obj)1075*00b67f09SDavid van Moolenbroek print_list(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1076*00b67f09SDavid van Moolenbroek 	const cfg_list_t *list = &obj->value.list;
1077*00b67f09SDavid van Moolenbroek 	const cfg_listelt_t *elt;
1078*00b67f09SDavid van Moolenbroek 
1079*00b67f09SDavid van Moolenbroek 	for (elt = ISC_LIST_HEAD(*list);
1080*00b67f09SDavid van Moolenbroek 	     elt != NULL;
1081*00b67f09SDavid van Moolenbroek 	     elt = ISC_LIST_NEXT(elt, link)) {
1082*00b67f09SDavid van Moolenbroek 		print_indent(pctx);
1083*00b67f09SDavid van Moolenbroek 		cfg_print_obj(pctx, elt->obj);
1084*00b67f09SDavid van Moolenbroek 		cfg_print_chars(pctx, ";\n", 2);
1085*00b67f09SDavid van Moolenbroek 	}
1086*00b67f09SDavid van Moolenbroek }
1087*00b67f09SDavid van Moolenbroek 
1088*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_bracketed_list(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)1089*00b67f09SDavid van Moolenbroek cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type,
1090*00b67f09SDavid van Moolenbroek 		     cfg_obj_t **ret)
1091*00b67f09SDavid van Moolenbroek {
1092*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1093*00b67f09SDavid van Moolenbroek 	CHECK(cfg_parse_special(pctx, '{'));
1094*00b67f09SDavid van Moolenbroek 	CHECK(parse_list(pctx, type, ret));
1095*00b67f09SDavid van Moolenbroek 	CHECK(cfg_parse_special(pctx, '}'));
1096*00b67f09SDavid van Moolenbroek  cleanup:
1097*00b67f09SDavid van Moolenbroek 	return (result);
1098*00b67f09SDavid van Moolenbroek }
1099*00b67f09SDavid van Moolenbroek 
1100*00b67f09SDavid van Moolenbroek void
cfg_print_bracketed_list(cfg_printer_t * pctx,const cfg_obj_t * obj)1101*00b67f09SDavid van Moolenbroek cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1102*00b67f09SDavid van Moolenbroek 	print_open(pctx);
1103*00b67f09SDavid van Moolenbroek 	print_list(pctx, obj);
1104*00b67f09SDavid van Moolenbroek 	print_close(pctx);
1105*00b67f09SDavid van Moolenbroek }
1106*00b67f09SDavid van Moolenbroek 
1107*00b67f09SDavid van Moolenbroek void
cfg_doc_bracketed_list(cfg_printer_t * pctx,const cfg_type_t * type)1108*00b67f09SDavid van Moolenbroek cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) {
1109*00b67f09SDavid van Moolenbroek 	cfg_print_chars(pctx, "{ ", 2);
1110*00b67f09SDavid van Moolenbroek 	cfg_doc_obj(pctx, type->of);
1111*00b67f09SDavid van Moolenbroek 	cfg_print_chars(pctx, "; ... }", 7);
1112*00b67f09SDavid van Moolenbroek }
1113*00b67f09SDavid van Moolenbroek 
1114*00b67f09SDavid van Moolenbroek /*
1115*00b67f09SDavid van Moolenbroek  * Parse a homogeneous list whose elements are of type 'elttype'
1116*00b67f09SDavid van Moolenbroek  * and where elements are separated by space.  The list ends
1117*00b67f09SDavid van Moolenbroek  * before the first semicolon.
1118*00b67f09SDavid van Moolenbroek  */
1119*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_spacelist(cfg_parser_t * pctx,const cfg_type_t * listtype,cfg_obj_t ** ret)1120*00b67f09SDavid van Moolenbroek cfg_parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *listtype,
1121*00b67f09SDavid van Moolenbroek 		    cfg_obj_t **ret)
1122*00b67f09SDavid van Moolenbroek {
1123*00b67f09SDavid van Moolenbroek 	cfg_obj_t *listobj = NULL;
1124*00b67f09SDavid van Moolenbroek 	const cfg_type_t *listof = listtype->of;
1125*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1126*00b67f09SDavid van Moolenbroek 
1127*00b67f09SDavid van Moolenbroek 	CHECK(cfg_create_list(pctx, listtype, &listobj));
1128*00b67f09SDavid van Moolenbroek 
1129*00b67f09SDavid van Moolenbroek 	for (;;) {
1130*00b67f09SDavid van Moolenbroek 		cfg_listelt_t *elt = NULL;
1131*00b67f09SDavid van Moolenbroek 
1132*00b67f09SDavid van Moolenbroek 		CHECK(cfg_peektoken(pctx, 0));
1133*00b67f09SDavid van Moolenbroek 		if (pctx->token.type == isc_tokentype_special &&
1134*00b67f09SDavid van Moolenbroek 		    pctx->token.value.as_char == ';')
1135*00b67f09SDavid van Moolenbroek 			break;
1136*00b67f09SDavid van Moolenbroek 		CHECK(cfg_parse_listelt(pctx, listof, &elt));
1137*00b67f09SDavid van Moolenbroek 		ISC_LIST_APPEND(listobj->value.list, elt, link);
1138*00b67f09SDavid van Moolenbroek 	}
1139*00b67f09SDavid van Moolenbroek 	*ret = listobj;
1140*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
1141*00b67f09SDavid van Moolenbroek 
1142*00b67f09SDavid van Moolenbroek  cleanup:
1143*00b67f09SDavid van Moolenbroek 	CLEANUP_OBJ(listobj);
1144*00b67f09SDavid van Moolenbroek 	return (result);
1145*00b67f09SDavid van Moolenbroek }
1146*00b67f09SDavid van Moolenbroek 
1147*00b67f09SDavid van Moolenbroek void
cfg_print_spacelist(cfg_printer_t * pctx,const cfg_obj_t * obj)1148*00b67f09SDavid van Moolenbroek cfg_print_spacelist(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1149*00b67f09SDavid van Moolenbroek 	const cfg_list_t *list = &obj->value.list;
1150*00b67f09SDavid van Moolenbroek 	const cfg_listelt_t *elt;
1151*00b67f09SDavid van Moolenbroek 
1152*00b67f09SDavid van Moolenbroek 	for (elt = ISC_LIST_HEAD(*list);
1153*00b67f09SDavid van Moolenbroek 	     elt != NULL;
1154*00b67f09SDavid van Moolenbroek 	     elt = ISC_LIST_NEXT(elt, link)) {
1155*00b67f09SDavid van Moolenbroek 		cfg_print_obj(pctx, elt->obj);
1156*00b67f09SDavid van Moolenbroek 		if (ISC_LIST_NEXT(elt, link) != NULL)
1157*00b67f09SDavid van Moolenbroek 			cfg_print_chars(pctx, " ", 1);
1158*00b67f09SDavid van Moolenbroek 	}
1159*00b67f09SDavid van Moolenbroek }
1160*00b67f09SDavid van Moolenbroek 
1161*00b67f09SDavid van Moolenbroek isc_boolean_t
cfg_obj_islist(const cfg_obj_t * obj)1162*00b67f09SDavid van Moolenbroek cfg_obj_islist(const cfg_obj_t *obj) {
1163*00b67f09SDavid van Moolenbroek 	REQUIRE(obj != NULL);
1164*00b67f09SDavid van Moolenbroek 	return (ISC_TF(obj->type->rep == &cfg_rep_list));
1165*00b67f09SDavid van Moolenbroek }
1166*00b67f09SDavid van Moolenbroek 
1167*00b67f09SDavid van Moolenbroek const cfg_listelt_t *
cfg_list_first(const cfg_obj_t * obj)1168*00b67f09SDavid van Moolenbroek cfg_list_first(const cfg_obj_t *obj) {
1169*00b67f09SDavid van Moolenbroek 	REQUIRE(obj == NULL || obj->type->rep == &cfg_rep_list);
1170*00b67f09SDavid van Moolenbroek 	if (obj == NULL)
1171*00b67f09SDavid van Moolenbroek 		return (NULL);
1172*00b67f09SDavid van Moolenbroek 	return (ISC_LIST_HEAD(obj->value.list));
1173*00b67f09SDavid van Moolenbroek }
1174*00b67f09SDavid van Moolenbroek 
1175*00b67f09SDavid van Moolenbroek const cfg_listelt_t *
cfg_list_next(const cfg_listelt_t * elt)1176*00b67f09SDavid van Moolenbroek cfg_list_next(const cfg_listelt_t *elt) {
1177*00b67f09SDavid van Moolenbroek 	REQUIRE(elt != NULL);
1178*00b67f09SDavid van Moolenbroek 	return (ISC_LIST_NEXT(elt, link));
1179*00b67f09SDavid van Moolenbroek }
1180*00b67f09SDavid van Moolenbroek 
1181*00b67f09SDavid van Moolenbroek /*
1182*00b67f09SDavid van Moolenbroek  * Return the length of a list object.  If obj is NULL or is not
1183*00b67f09SDavid van Moolenbroek  * a list, return 0.
1184*00b67f09SDavid van Moolenbroek  */
1185*00b67f09SDavid van Moolenbroek unsigned int
cfg_list_length(const cfg_obj_t * obj,isc_boolean_t recurse)1186*00b67f09SDavid van Moolenbroek cfg_list_length(const cfg_obj_t *obj, isc_boolean_t recurse) {
1187*00b67f09SDavid van Moolenbroek 	const cfg_listelt_t *elt;
1188*00b67f09SDavid van Moolenbroek 	unsigned int count = 0;
1189*00b67f09SDavid van Moolenbroek 
1190*00b67f09SDavid van Moolenbroek 	if (obj == NULL || !cfg_obj_islist(obj))
1191*00b67f09SDavid van Moolenbroek 		return (0U);
1192*00b67f09SDavid van Moolenbroek 	for (elt = cfg_list_first(obj);
1193*00b67f09SDavid van Moolenbroek 	     elt != NULL;
1194*00b67f09SDavid van Moolenbroek 	     elt = cfg_list_next(elt)) {
1195*00b67f09SDavid van Moolenbroek 		if (recurse && cfg_obj_islist(elt->obj)) {
1196*00b67f09SDavid van Moolenbroek 			count += cfg_list_length(elt->obj, recurse);
1197*00b67f09SDavid van Moolenbroek 		} else {
1198*00b67f09SDavid van Moolenbroek 			count++;
1199*00b67f09SDavid van Moolenbroek 		}
1200*00b67f09SDavid van Moolenbroek 	}
1201*00b67f09SDavid van Moolenbroek 	return (count);
1202*00b67f09SDavid van Moolenbroek }
1203*00b67f09SDavid van Moolenbroek 
1204*00b67f09SDavid van Moolenbroek cfg_obj_t *
cfg_listelt_value(const cfg_listelt_t * elt)1205*00b67f09SDavid van Moolenbroek cfg_listelt_value(const cfg_listelt_t *elt) {
1206*00b67f09SDavid van Moolenbroek 	REQUIRE(elt != NULL);
1207*00b67f09SDavid van Moolenbroek 	return (elt->obj);
1208*00b67f09SDavid van Moolenbroek }
1209*00b67f09SDavid van Moolenbroek 
1210*00b67f09SDavid van Moolenbroek /*
1211*00b67f09SDavid van Moolenbroek  * Maps.
1212*00b67f09SDavid van Moolenbroek  */
1213*00b67f09SDavid van Moolenbroek 
1214*00b67f09SDavid van Moolenbroek /*
1215*00b67f09SDavid van Moolenbroek  * Parse a map body.  That's something like
1216*00b67f09SDavid van Moolenbroek  *
1217*00b67f09SDavid van Moolenbroek  *   "foo 1; bar { glub; }; zap true; zap false;"
1218*00b67f09SDavid van Moolenbroek  *
1219*00b67f09SDavid van Moolenbroek  * i.e., a sequence of option names followed by values and
1220*00b67f09SDavid van Moolenbroek  * terminated by semicolons.  Used for the top level of
1221*00b67f09SDavid van Moolenbroek  * the named.conf syntax, as well as for the body of the
1222*00b67f09SDavid van Moolenbroek  * options, view, zone, and other statements.
1223*00b67f09SDavid van Moolenbroek  */
1224*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_mapbody(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)1225*00b67f09SDavid van Moolenbroek cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
1226*00b67f09SDavid van Moolenbroek {
1227*00b67f09SDavid van Moolenbroek 	const cfg_clausedef_t * const *clausesets = type->of;
1228*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1229*00b67f09SDavid van Moolenbroek 	const cfg_clausedef_t * const *clauseset;
1230*00b67f09SDavid van Moolenbroek 	const cfg_clausedef_t *clause;
1231*00b67f09SDavid van Moolenbroek 	cfg_obj_t *value = NULL;
1232*00b67f09SDavid van Moolenbroek 	cfg_obj_t *obj = NULL;
1233*00b67f09SDavid van Moolenbroek 	cfg_obj_t *eltobj = NULL;
1234*00b67f09SDavid van Moolenbroek 	cfg_obj_t *includename = NULL;
1235*00b67f09SDavid van Moolenbroek 	isc_symvalue_t symval;
1236*00b67f09SDavid van Moolenbroek 	cfg_list_t *list = NULL;
1237*00b67f09SDavid van Moolenbroek 
1238*00b67f09SDavid van Moolenbroek 	CHECK(create_map(pctx, type, &obj));
1239*00b67f09SDavid van Moolenbroek 
1240*00b67f09SDavid van Moolenbroek 	obj->value.map.clausesets = clausesets;
1241*00b67f09SDavid van Moolenbroek 
1242*00b67f09SDavid van Moolenbroek 	for (;;) {
1243*00b67f09SDavid van Moolenbroek 		cfg_listelt_t *elt;
1244*00b67f09SDavid van Moolenbroek 
1245*00b67f09SDavid van Moolenbroek 	redo:
1246*00b67f09SDavid van Moolenbroek 		/*
1247*00b67f09SDavid van Moolenbroek 		 * Parse the option name and see if it is known.
1248*00b67f09SDavid van Moolenbroek 		 */
1249*00b67f09SDavid van Moolenbroek 		CHECK(cfg_gettoken(pctx, 0));
1250*00b67f09SDavid van Moolenbroek 
1251*00b67f09SDavid van Moolenbroek 		if (pctx->token.type != isc_tokentype_string) {
1252*00b67f09SDavid van Moolenbroek 			cfg_ungettoken(pctx);
1253*00b67f09SDavid van Moolenbroek 			break;
1254*00b67f09SDavid van Moolenbroek 		}
1255*00b67f09SDavid van Moolenbroek 
1256*00b67f09SDavid van Moolenbroek 		/*
1257*00b67f09SDavid van Moolenbroek 		 * We accept "include" statements wherever a map body
1258*00b67f09SDavid van Moolenbroek 		 * clause can occur.
1259*00b67f09SDavid van Moolenbroek 		 */
1260*00b67f09SDavid van Moolenbroek 		if (strcasecmp(TOKEN_STRING(pctx), "include") == 0) {
1261*00b67f09SDavid van Moolenbroek 			/*
1262*00b67f09SDavid van Moolenbroek 			 * Turn the file name into a temporary configuration
1263*00b67f09SDavid van Moolenbroek 			 * object just so that it is not overwritten by the
1264*00b67f09SDavid van Moolenbroek 			 * semicolon token.
1265*00b67f09SDavid van Moolenbroek 			 */
1266*00b67f09SDavid van Moolenbroek 			CHECK(cfg_parse_obj(pctx, &cfg_type_qstring, &includename));
1267*00b67f09SDavid van Moolenbroek 			CHECK(parse_semicolon(pctx));
1268*00b67f09SDavid van Moolenbroek 			CHECK(parser_openfile(pctx, includename->
1269*00b67f09SDavid van Moolenbroek 					      value.string.base));
1270*00b67f09SDavid van Moolenbroek 			 cfg_obj_destroy(pctx, &includename);
1271*00b67f09SDavid van Moolenbroek 			 goto redo;
1272*00b67f09SDavid van Moolenbroek 		}
1273*00b67f09SDavid van Moolenbroek 
1274*00b67f09SDavid van Moolenbroek 		clause = NULL;
1275*00b67f09SDavid van Moolenbroek 		for (clauseset = clausesets; *clauseset != NULL; clauseset++) {
1276*00b67f09SDavid van Moolenbroek 			for (clause = *clauseset;
1277*00b67f09SDavid van Moolenbroek 			     clause->name != NULL;
1278*00b67f09SDavid van Moolenbroek 			     clause++) {
1279*00b67f09SDavid van Moolenbroek 				if (strcasecmp(TOKEN_STRING(pctx),
1280*00b67f09SDavid van Moolenbroek 					   clause->name) == 0)
1281*00b67f09SDavid van Moolenbroek 					goto done;
1282*00b67f09SDavid van Moolenbroek 			}
1283*00b67f09SDavid van Moolenbroek 		}
1284*00b67f09SDavid van Moolenbroek 	done:
1285*00b67f09SDavid van Moolenbroek 		if (clause == NULL || clause->name == NULL) {
1286*00b67f09SDavid van Moolenbroek 			cfg_parser_error(pctx, CFG_LOG_NOPREP, "unknown option");
1287*00b67f09SDavid van Moolenbroek 			/*
1288*00b67f09SDavid van Moolenbroek 			 * Try to recover by parsing this option as an unknown
1289*00b67f09SDavid van Moolenbroek 			 * option and discarding it.
1290*00b67f09SDavid van Moolenbroek 			 */
1291*00b67f09SDavid van Moolenbroek 			CHECK(cfg_parse_obj(pctx, &cfg_type_unsupported, &eltobj));
1292*00b67f09SDavid van Moolenbroek 			cfg_obj_destroy(pctx, &eltobj);
1293*00b67f09SDavid van Moolenbroek 			CHECK(parse_semicolon(pctx));
1294*00b67f09SDavid van Moolenbroek 			continue;
1295*00b67f09SDavid van Moolenbroek 		}
1296*00b67f09SDavid van Moolenbroek 
1297*00b67f09SDavid van Moolenbroek 		/* Clause is known. */
1298*00b67f09SDavid van Moolenbroek 
1299*00b67f09SDavid van Moolenbroek 		/* Issue warnings if appropriate */
1300*00b67f09SDavid van Moolenbroek 		if ((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0)
1301*00b67f09SDavid van Moolenbroek 			cfg_parser_warning(pctx, 0, "option '%s' is obsolete",
1302*00b67f09SDavid van Moolenbroek 				       clause->name);
1303*00b67f09SDavid van Moolenbroek 		if ((clause->flags & CFG_CLAUSEFLAG_NOTIMP) != 0)
1304*00b67f09SDavid van Moolenbroek 			cfg_parser_warning(pctx, 0, "option '%s' is "
1305*00b67f09SDavid van Moolenbroek 				       "not implemented", clause->name);
1306*00b67f09SDavid van Moolenbroek 		if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0)
1307*00b67f09SDavid van Moolenbroek 			cfg_parser_warning(pctx, 0, "option '%s' is "
1308*00b67f09SDavid van Moolenbroek 				       "not implemented", clause->name);
1309*00b67f09SDavid van Moolenbroek 
1310*00b67f09SDavid van Moolenbroek 		if ((clause->flags & CFG_CLAUSEFLAG_NOTCONFIGURED) != 0) {
1311*00b67f09SDavid van Moolenbroek 			cfg_parser_warning(pctx, 0, "option '%s' was not "
1312*00b67f09SDavid van Moolenbroek 					   "enabled at compile time",
1313*00b67f09SDavid van Moolenbroek 					   clause->name);
1314*00b67f09SDavid van Moolenbroek 			result = ISC_R_FAILURE;
1315*00b67f09SDavid van Moolenbroek 			goto cleanup;
1316*00b67f09SDavid van Moolenbroek 		}
1317*00b67f09SDavid van Moolenbroek 
1318*00b67f09SDavid van Moolenbroek 		/*
1319*00b67f09SDavid van Moolenbroek 		 * Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT
1320*00b67f09SDavid van Moolenbroek 		 * set here - we need to log the *lack* of such an option,
1321*00b67f09SDavid van Moolenbroek 		 * not its presence.
1322*00b67f09SDavid van Moolenbroek 		 */
1323*00b67f09SDavid van Moolenbroek 
1324*00b67f09SDavid van Moolenbroek 		/* See if the clause already has a value; if not create one. */
1325*00b67f09SDavid van Moolenbroek 		result = isc_symtab_lookup(obj->value.map.symtab,
1326*00b67f09SDavid van Moolenbroek 					   clause->name, 0, &symval);
1327*00b67f09SDavid van Moolenbroek 
1328*00b67f09SDavid van Moolenbroek 		if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) {
1329*00b67f09SDavid van Moolenbroek 			/* Multivalued clause */
1330*00b67f09SDavid van Moolenbroek 			cfg_obj_t *listobj = NULL;
1331*00b67f09SDavid van Moolenbroek 			if (result == ISC_R_NOTFOUND) {
1332*00b67f09SDavid van Moolenbroek 				CHECK(cfg_create_list(pctx,
1333*00b67f09SDavid van Moolenbroek 						  &cfg_type_implicitlist,
1334*00b67f09SDavid van Moolenbroek 						  &listobj));
1335*00b67f09SDavid van Moolenbroek 				symval.as_pointer = listobj;
1336*00b67f09SDavid van Moolenbroek 				result = isc_symtab_define(obj->value.
1337*00b67f09SDavid van Moolenbroek 						   map.symtab,
1338*00b67f09SDavid van Moolenbroek 						   clause->name,
1339*00b67f09SDavid van Moolenbroek 						   1, symval,
1340*00b67f09SDavid van Moolenbroek 						   isc_symexists_reject);
1341*00b67f09SDavid van Moolenbroek 				if (result != ISC_R_SUCCESS) {
1342*00b67f09SDavid van Moolenbroek 					cfg_parser_error(pctx, CFG_LOG_NEAR,
1343*00b67f09SDavid van Moolenbroek 						     "isc_symtab_define(%s) "
1344*00b67f09SDavid van Moolenbroek 						     "failed", clause->name);
1345*00b67f09SDavid van Moolenbroek 					isc_mem_put(pctx->mctx, list,
1346*00b67f09SDavid van Moolenbroek 						    sizeof(cfg_list_t));
1347*00b67f09SDavid van Moolenbroek 					goto cleanup;
1348*00b67f09SDavid van Moolenbroek 				}
1349*00b67f09SDavid van Moolenbroek 			} else {
1350*00b67f09SDavid van Moolenbroek 				INSIST(result == ISC_R_SUCCESS);
1351*00b67f09SDavid van Moolenbroek 				listobj = symval.as_pointer;
1352*00b67f09SDavid van Moolenbroek 			}
1353*00b67f09SDavid van Moolenbroek 
1354*00b67f09SDavid van Moolenbroek 			elt = NULL;
1355*00b67f09SDavid van Moolenbroek 			CHECK(cfg_parse_listelt(pctx, clause->type, &elt));
1356*00b67f09SDavid van Moolenbroek 			CHECK(parse_semicolon(pctx));
1357*00b67f09SDavid van Moolenbroek 
1358*00b67f09SDavid van Moolenbroek 			ISC_LIST_APPEND(listobj->value.list, elt, link);
1359*00b67f09SDavid van Moolenbroek 		} else {
1360*00b67f09SDavid van Moolenbroek 			/* Single-valued clause */
1361*00b67f09SDavid van Moolenbroek 			if (result == ISC_R_NOTFOUND) {
1362*00b67f09SDavid van Moolenbroek 				isc_boolean_t callback =
1363*00b67f09SDavid van Moolenbroek 					ISC_TF((clause->flags &
1364*00b67f09SDavid van Moolenbroek 						CFG_CLAUSEFLAG_CALLBACK) != 0);
1365*00b67f09SDavid van Moolenbroek 				CHECK(parse_symtab_elt(pctx, clause->name,
1366*00b67f09SDavid van Moolenbroek 						       clause->type,
1367*00b67f09SDavid van Moolenbroek 						       obj->value.map.symtab,
1368*00b67f09SDavid van Moolenbroek 						       callback));
1369*00b67f09SDavid van Moolenbroek 				CHECK(parse_semicolon(pctx));
1370*00b67f09SDavid van Moolenbroek 			} else if (result == ISC_R_SUCCESS) {
1371*00b67f09SDavid van Moolenbroek 				cfg_parser_error(pctx, CFG_LOG_NEAR, "'%s' redefined",
1372*00b67f09SDavid van Moolenbroek 					     clause->name);
1373*00b67f09SDavid van Moolenbroek 				result = ISC_R_EXISTS;
1374*00b67f09SDavid van Moolenbroek 				goto cleanup;
1375*00b67f09SDavid van Moolenbroek 			} else {
1376*00b67f09SDavid van Moolenbroek 				cfg_parser_error(pctx, CFG_LOG_NEAR,
1377*00b67f09SDavid van Moolenbroek 					     "isc_symtab_define() failed");
1378*00b67f09SDavid van Moolenbroek 				goto cleanup;
1379*00b67f09SDavid van Moolenbroek 			}
1380*00b67f09SDavid van Moolenbroek 		}
1381*00b67f09SDavid van Moolenbroek 	}
1382*00b67f09SDavid van Moolenbroek 
1383*00b67f09SDavid van Moolenbroek 
1384*00b67f09SDavid van Moolenbroek 	*ret = obj;
1385*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
1386*00b67f09SDavid van Moolenbroek 
1387*00b67f09SDavid van Moolenbroek  cleanup:
1388*00b67f09SDavid van Moolenbroek 	CLEANUP_OBJ(value);
1389*00b67f09SDavid van Moolenbroek 	CLEANUP_OBJ(obj);
1390*00b67f09SDavid van Moolenbroek 	CLEANUP_OBJ(eltobj);
1391*00b67f09SDavid van Moolenbroek 	CLEANUP_OBJ(includename);
1392*00b67f09SDavid van Moolenbroek 	return (result);
1393*00b67f09SDavid van Moolenbroek }
1394*00b67f09SDavid van Moolenbroek 
1395*00b67f09SDavid van Moolenbroek static isc_result_t
parse_symtab_elt(cfg_parser_t * pctx,const char * name,cfg_type_t * elttype,isc_symtab_t * symtab,isc_boolean_t callback)1396*00b67f09SDavid van Moolenbroek parse_symtab_elt(cfg_parser_t *pctx, const char *name,
1397*00b67f09SDavid van Moolenbroek 		 cfg_type_t *elttype, isc_symtab_t *symtab,
1398*00b67f09SDavid van Moolenbroek 		 isc_boolean_t callback)
1399*00b67f09SDavid van Moolenbroek {
1400*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1401*00b67f09SDavid van Moolenbroek 	cfg_obj_t *obj = NULL;
1402*00b67f09SDavid van Moolenbroek 	isc_symvalue_t symval;
1403*00b67f09SDavid van Moolenbroek 
1404*00b67f09SDavid van Moolenbroek 	CHECK(cfg_parse_obj(pctx, elttype, &obj));
1405*00b67f09SDavid van Moolenbroek 
1406*00b67f09SDavid van Moolenbroek 	if (callback && pctx->callback != NULL)
1407*00b67f09SDavid van Moolenbroek 		CHECK(pctx->callback(name, obj, pctx->callbackarg));
1408*00b67f09SDavid van Moolenbroek 
1409*00b67f09SDavid van Moolenbroek 	symval.as_pointer = obj;
1410*00b67f09SDavid van Moolenbroek 	CHECK(isc_symtab_define(symtab, name,
1411*00b67f09SDavid van Moolenbroek 				1, symval,
1412*00b67f09SDavid van Moolenbroek 				isc_symexists_reject));
1413*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
1414*00b67f09SDavid van Moolenbroek 
1415*00b67f09SDavid van Moolenbroek  cleanup:
1416*00b67f09SDavid van Moolenbroek 	CLEANUP_OBJ(obj);
1417*00b67f09SDavid van Moolenbroek 	return (result);
1418*00b67f09SDavid van Moolenbroek }
1419*00b67f09SDavid van Moolenbroek 
1420*00b67f09SDavid van Moolenbroek /*
1421*00b67f09SDavid van Moolenbroek  * Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }"
1422*00b67f09SDavid van Moolenbroek  */
1423*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_map(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)1424*00b67f09SDavid van Moolenbroek cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1425*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1426*00b67f09SDavid van Moolenbroek 	CHECK(cfg_parse_special(pctx, '{'));
1427*00b67f09SDavid van Moolenbroek 	CHECK(cfg_parse_mapbody(pctx, type, ret));
1428*00b67f09SDavid van Moolenbroek 	CHECK(cfg_parse_special(pctx, '}'));
1429*00b67f09SDavid van Moolenbroek  cleanup:
1430*00b67f09SDavid van Moolenbroek 	return (result);
1431*00b67f09SDavid van Moolenbroek }
1432*00b67f09SDavid van Moolenbroek 
1433*00b67f09SDavid van Moolenbroek /*
1434*00b67f09SDavid van Moolenbroek  * Subroutine for cfg_parse_named_map() and cfg_parse_addressed_map().
1435*00b67f09SDavid van Moolenbroek  */
1436*00b67f09SDavid van Moolenbroek static isc_result_t
parse_any_named_map(cfg_parser_t * pctx,cfg_type_t * nametype,const cfg_type_t * type,cfg_obj_t ** ret)1437*00b67f09SDavid van Moolenbroek parse_any_named_map(cfg_parser_t *pctx, cfg_type_t *nametype, const cfg_type_t *type,
1438*00b67f09SDavid van Moolenbroek 		    cfg_obj_t **ret)
1439*00b67f09SDavid van Moolenbroek {
1440*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1441*00b67f09SDavid van Moolenbroek 	cfg_obj_t *idobj = NULL;
1442*00b67f09SDavid van Moolenbroek 	cfg_obj_t *mapobj = NULL;
1443*00b67f09SDavid van Moolenbroek 
1444*00b67f09SDavid van Moolenbroek 	CHECK(cfg_parse_obj(pctx, nametype, &idobj));
1445*00b67f09SDavid van Moolenbroek 	CHECK(cfg_parse_map(pctx, type, &mapobj));
1446*00b67f09SDavid van Moolenbroek 	mapobj->value.map.id = idobj;
1447*00b67f09SDavid van Moolenbroek 	idobj = NULL;
1448*00b67f09SDavid van Moolenbroek 	*ret = mapobj;
1449*00b67f09SDavid van Moolenbroek  cleanup:
1450*00b67f09SDavid van Moolenbroek 	CLEANUP_OBJ(idobj);
1451*00b67f09SDavid van Moolenbroek 	return (result);
1452*00b67f09SDavid van Moolenbroek }
1453*00b67f09SDavid van Moolenbroek 
1454*00b67f09SDavid van Moolenbroek /*
1455*00b67f09SDavid van Moolenbroek  * Parse a map identified by a string name.  E.g., "name { foo 1; }".
1456*00b67f09SDavid van Moolenbroek  * Used for the "key" and "channel" statements.
1457*00b67f09SDavid van Moolenbroek  */
1458*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_named_map(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)1459*00b67f09SDavid van Moolenbroek cfg_parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1460*00b67f09SDavid van Moolenbroek 	return (parse_any_named_map(pctx, &cfg_type_astring, type, ret));
1461*00b67f09SDavid van Moolenbroek }
1462*00b67f09SDavid van Moolenbroek 
1463*00b67f09SDavid van Moolenbroek /*
1464*00b67f09SDavid van Moolenbroek  * Parse a map identified by a network address.
1465*00b67f09SDavid van Moolenbroek  * Used to be used for the "server" statement.
1466*00b67f09SDavid van Moolenbroek  */
1467*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_addressed_map(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)1468*00b67f09SDavid van Moolenbroek cfg_parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1469*00b67f09SDavid van Moolenbroek 	return (parse_any_named_map(pctx, &cfg_type_netaddr, type, ret));
1470*00b67f09SDavid van Moolenbroek }
1471*00b67f09SDavid van Moolenbroek 
1472*00b67f09SDavid van Moolenbroek /*
1473*00b67f09SDavid van Moolenbroek  * Parse a map identified by a network prefix.
1474*00b67f09SDavid van Moolenbroek  * Used for the "server" statement.
1475*00b67f09SDavid van Moolenbroek  */
1476*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_netprefix_map(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)1477*00b67f09SDavid van Moolenbroek cfg_parse_netprefix_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1478*00b67f09SDavid van Moolenbroek 	return (parse_any_named_map(pctx, &cfg_type_netprefix, type, ret));
1479*00b67f09SDavid van Moolenbroek }
1480*00b67f09SDavid van Moolenbroek 
1481*00b67f09SDavid van Moolenbroek void
cfg_print_mapbody(cfg_printer_t * pctx,const cfg_obj_t * obj)1482*00b67f09SDavid van Moolenbroek cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1483*00b67f09SDavid van Moolenbroek 	isc_result_t result = ISC_R_SUCCESS;
1484*00b67f09SDavid van Moolenbroek 
1485*00b67f09SDavid van Moolenbroek 	const cfg_clausedef_t * const *clauseset;
1486*00b67f09SDavid van Moolenbroek 
1487*00b67f09SDavid van Moolenbroek 	for (clauseset = obj->value.map.clausesets;
1488*00b67f09SDavid van Moolenbroek 	     *clauseset != NULL;
1489*00b67f09SDavid van Moolenbroek 	     clauseset++)
1490*00b67f09SDavid van Moolenbroek 	{
1491*00b67f09SDavid van Moolenbroek 		isc_symvalue_t symval;
1492*00b67f09SDavid van Moolenbroek 		const cfg_clausedef_t *clause;
1493*00b67f09SDavid van Moolenbroek 
1494*00b67f09SDavid van Moolenbroek 		for (clause = *clauseset;
1495*00b67f09SDavid van Moolenbroek 		     clause->name != NULL;
1496*00b67f09SDavid van Moolenbroek 		     clause++) {
1497*00b67f09SDavid van Moolenbroek 			result = isc_symtab_lookup(obj->value.map.symtab,
1498*00b67f09SDavid van Moolenbroek 						   clause->name, 0, &symval);
1499*00b67f09SDavid van Moolenbroek 			if (result == ISC_R_SUCCESS) {
1500*00b67f09SDavid van Moolenbroek 				cfg_obj_t *symobj = symval.as_pointer;
1501*00b67f09SDavid van Moolenbroek 				if (symobj->type == &cfg_type_implicitlist) {
1502*00b67f09SDavid van Moolenbroek 					/* Multivalued. */
1503*00b67f09SDavid van Moolenbroek 					cfg_list_t *list = &symobj->value.list;
1504*00b67f09SDavid van Moolenbroek 					cfg_listelt_t *elt;
1505*00b67f09SDavid van Moolenbroek 					for (elt = ISC_LIST_HEAD(*list);
1506*00b67f09SDavid van Moolenbroek 					     elt != NULL;
1507*00b67f09SDavid van Moolenbroek 					     elt = ISC_LIST_NEXT(elt, link)) {
1508*00b67f09SDavid van Moolenbroek 						print_indent(pctx);
1509*00b67f09SDavid van Moolenbroek 						cfg_print_cstr(pctx, clause->name);
1510*00b67f09SDavid van Moolenbroek 						cfg_print_chars(pctx, " ", 1);
1511*00b67f09SDavid van Moolenbroek 						cfg_print_obj(pctx, elt->obj);
1512*00b67f09SDavid van Moolenbroek 						cfg_print_chars(pctx, ";\n", 2);
1513*00b67f09SDavid van Moolenbroek 					}
1514*00b67f09SDavid van Moolenbroek 				} else {
1515*00b67f09SDavid van Moolenbroek 					/* Single-valued. */
1516*00b67f09SDavid van Moolenbroek 					print_indent(pctx);
1517*00b67f09SDavid van Moolenbroek 					cfg_print_cstr(pctx, clause->name);
1518*00b67f09SDavid van Moolenbroek 					cfg_print_chars(pctx, " ", 1);
1519*00b67f09SDavid van Moolenbroek 					cfg_print_obj(pctx, symobj);
1520*00b67f09SDavid van Moolenbroek 					cfg_print_chars(pctx, ";\n", 2);
1521*00b67f09SDavid van Moolenbroek 				}
1522*00b67f09SDavid van Moolenbroek 			} else if (result == ISC_R_NOTFOUND) {
1523*00b67f09SDavid van Moolenbroek 				; /* do nothing */
1524*00b67f09SDavid van Moolenbroek 			} else {
1525*00b67f09SDavid van Moolenbroek 				INSIST(0);
1526*00b67f09SDavid van Moolenbroek 			}
1527*00b67f09SDavid van Moolenbroek 		}
1528*00b67f09SDavid van Moolenbroek 	}
1529*00b67f09SDavid van Moolenbroek }
1530*00b67f09SDavid van Moolenbroek 
1531*00b67f09SDavid van Moolenbroek void
cfg_doc_mapbody(cfg_printer_t * pctx,const cfg_type_t * type)1532*00b67f09SDavid van Moolenbroek cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) {
1533*00b67f09SDavid van Moolenbroek 	const cfg_clausedef_t * const *clauseset;
1534*00b67f09SDavid van Moolenbroek 	const cfg_clausedef_t *clause;
1535*00b67f09SDavid van Moolenbroek 
1536*00b67f09SDavid van Moolenbroek 	for (clauseset = type->of; *clauseset != NULL; clauseset++) {
1537*00b67f09SDavid van Moolenbroek 		for (clause = *clauseset;
1538*00b67f09SDavid van Moolenbroek 		     clause->name != NULL;
1539*00b67f09SDavid van Moolenbroek 		     clause++) {
1540*00b67f09SDavid van Moolenbroek 			cfg_print_cstr(pctx, clause->name);
1541*00b67f09SDavid van Moolenbroek 			cfg_print_chars(pctx, " ", 1);
1542*00b67f09SDavid van Moolenbroek 			cfg_doc_obj(pctx, clause->type);
1543*00b67f09SDavid van Moolenbroek 			cfg_print_chars(pctx, ";", 1);
1544*00b67f09SDavid van Moolenbroek 			/* XXX print flags here? */
1545*00b67f09SDavid van Moolenbroek 			cfg_print_chars(pctx, "\n\n", 2);
1546*00b67f09SDavid van Moolenbroek 		}
1547*00b67f09SDavid van Moolenbroek 	}
1548*00b67f09SDavid van Moolenbroek }
1549*00b67f09SDavid van Moolenbroek 
1550*00b67f09SDavid van Moolenbroek static struct flagtext {
1551*00b67f09SDavid van Moolenbroek 	unsigned int flag;
1552*00b67f09SDavid van Moolenbroek 	const char *text;
1553*00b67f09SDavid van Moolenbroek } flagtexts[] = {
1554*00b67f09SDavid van Moolenbroek 	{ CFG_CLAUSEFLAG_NOTIMP, "not implemented" },
1555*00b67f09SDavid van Moolenbroek 	{ CFG_CLAUSEFLAG_NYI, "not yet implemented" },
1556*00b67f09SDavid van Moolenbroek 	{ CFG_CLAUSEFLAG_OBSOLETE, "obsolete" },
1557*00b67f09SDavid van Moolenbroek 	{ CFG_CLAUSEFLAG_NEWDEFAULT, "default changed" },
1558*00b67f09SDavid van Moolenbroek 	{ CFG_CLAUSEFLAG_TESTONLY, "test only" },
1559*00b67f09SDavid van Moolenbroek 	{ CFG_CLAUSEFLAG_NOTCONFIGURED, "not configured" },
1560*00b67f09SDavid van Moolenbroek 	{ 0, NULL }
1561*00b67f09SDavid van Moolenbroek };
1562*00b67f09SDavid van Moolenbroek 
1563*00b67f09SDavid van Moolenbroek void
cfg_print_map(cfg_printer_t * pctx,const cfg_obj_t * obj)1564*00b67f09SDavid van Moolenbroek cfg_print_map(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1565*00b67f09SDavid van Moolenbroek 	if (obj->value.map.id != NULL) {
1566*00b67f09SDavid van Moolenbroek 		cfg_print_obj(pctx, obj->value.map.id);
1567*00b67f09SDavid van Moolenbroek 		cfg_print_chars(pctx, " ", 1);
1568*00b67f09SDavid van Moolenbroek 	}
1569*00b67f09SDavid van Moolenbroek 	print_open(pctx);
1570*00b67f09SDavid van Moolenbroek 	cfg_print_mapbody(pctx, obj);
1571*00b67f09SDavid van Moolenbroek 	print_close(pctx);
1572*00b67f09SDavid van Moolenbroek }
1573*00b67f09SDavid van Moolenbroek 
1574*00b67f09SDavid van Moolenbroek static void
print_clause_flags(cfg_printer_t * pctx,unsigned int flags)1575*00b67f09SDavid van Moolenbroek print_clause_flags(cfg_printer_t *pctx, unsigned int flags) {
1576*00b67f09SDavid van Moolenbroek 	struct flagtext *p;
1577*00b67f09SDavid van Moolenbroek 	isc_boolean_t first = ISC_TRUE;
1578*00b67f09SDavid van Moolenbroek 	for (p = flagtexts; p->flag != 0; p++) {
1579*00b67f09SDavid van Moolenbroek 		if ((flags & p->flag) != 0) {
1580*00b67f09SDavid van Moolenbroek 			if (first)
1581*00b67f09SDavid van Moolenbroek 				cfg_print_chars(pctx, " // ", 4);
1582*00b67f09SDavid van Moolenbroek 			else
1583*00b67f09SDavid van Moolenbroek 				cfg_print_chars(pctx, ", ", 2);
1584*00b67f09SDavid van Moolenbroek 			cfg_print_cstr(pctx, p->text);
1585*00b67f09SDavid van Moolenbroek 			first = ISC_FALSE;
1586*00b67f09SDavid van Moolenbroek 		}
1587*00b67f09SDavid van Moolenbroek 	}
1588*00b67f09SDavid van Moolenbroek }
1589*00b67f09SDavid van Moolenbroek 
1590*00b67f09SDavid van Moolenbroek void
cfg_doc_map(cfg_printer_t * pctx,const cfg_type_t * type)1591*00b67f09SDavid van Moolenbroek cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) {
1592*00b67f09SDavid van Moolenbroek 	const cfg_clausedef_t * const *clauseset;
1593*00b67f09SDavid van Moolenbroek 	const cfg_clausedef_t *clause;
1594*00b67f09SDavid van Moolenbroek 
1595*00b67f09SDavid van Moolenbroek 	if (type->parse == cfg_parse_named_map) {
1596*00b67f09SDavid van Moolenbroek 		cfg_doc_obj(pctx, &cfg_type_astring);
1597*00b67f09SDavid van Moolenbroek 		cfg_print_chars(pctx, " ", 1);
1598*00b67f09SDavid van Moolenbroek 	} else if (type->parse == cfg_parse_addressed_map) {
1599*00b67f09SDavid van Moolenbroek 		cfg_doc_obj(pctx, &cfg_type_netaddr);
1600*00b67f09SDavid van Moolenbroek 		cfg_print_chars(pctx, " ", 1);
1601*00b67f09SDavid van Moolenbroek 	} else if (type->parse == cfg_parse_netprefix_map) {
1602*00b67f09SDavid van Moolenbroek 		cfg_doc_obj(pctx, &cfg_type_netprefix);
1603*00b67f09SDavid van Moolenbroek 		cfg_print_chars(pctx, " ", 1);
1604*00b67f09SDavid van Moolenbroek 	}
1605*00b67f09SDavid van Moolenbroek 
1606*00b67f09SDavid van Moolenbroek 	print_open(pctx);
1607*00b67f09SDavid van Moolenbroek 
1608*00b67f09SDavid van Moolenbroek 	for (clauseset = type->of; *clauseset != NULL; clauseset++) {
1609*00b67f09SDavid van Moolenbroek 		for (clause = *clauseset;
1610*00b67f09SDavid van Moolenbroek 		     clause->name != NULL;
1611*00b67f09SDavid van Moolenbroek 		     clause++) {
1612*00b67f09SDavid van Moolenbroek 			print_indent(pctx);
1613*00b67f09SDavid van Moolenbroek 			cfg_print_cstr(pctx, clause->name);
1614*00b67f09SDavid van Moolenbroek 			if (clause->type->print != cfg_print_void)
1615*00b67f09SDavid van Moolenbroek 				cfg_print_chars(pctx, " ", 1);
1616*00b67f09SDavid van Moolenbroek 			cfg_doc_obj(pctx, clause->type);
1617*00b67f09SDavid van Moolenbroek 			cfg_print_chars(pctx, ";", 1);
1618*00b67f09SDavid van Moolenbroek 			print_clause_flags(pctx, clause->flags);
1619*00b67f09SDavid van Moolenbroek 			cfg_print_chars(pctx, "\n", 1);
1620*00b67f09SDavid van Moolenbroek 		}
1621*00b67f09SDavid van Moolenbroek 	}
1622*00b67f09SDavid van Moolenbroek 	print_close(pctx);
1623*00b67f09SDavid van Moolenbroek }
1624*00b67f09SDavid van Moolenbroek 
1625*00b67f09SDavid van Moolenbroek isc_boolean_t
cfg_obj_ismap(const cfg_obj_t * obj)1626*00b67f09SDavid van Moolenbroek cfg_obj_ismap(const cfg_obj_t *obj) {
1627*00b67f09SDavid van Moolenbroek 	REQUIRE(obj != NULL);
1628*00b67f09SDavid van Moolenbroek 	return (ISC_TF(obj->type->rep == &cfg_rep_map));
1629*00b67f09SDavid van Moolenbroek }
1630*00b67f09SDavid van Moolenbroek 
1631*00b67f09SDavid van Moolenbroek isc_result_t
cfg_map_get(const cfg_obj_t * mapobj,const char * name,const cfg_obj_t ** obj)1632*00b67f09SDavid van Moolenbroek cfg_map_get(const cfg_obj_t *mapobj, const char* name, const cfg_obj_t **obj) {
1633*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1634*00b67f09SDavid van Moolenbroek 	isc_symvalue_t val;
1635*00b67f09SDavid van Moolenbroek 	const cfg_map_t *map;
1636*00b67f09SDavid van Moolenbroek 
1637*00b67f09SDavid van Moolenbroek 	REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
1638*00b67f09SDavid van Moolenbroek 	REQUIRE(name != NULL);
1639*00b67f09SDavid van Moolenbroek 	REQUIRE(obj != NULL && *obj == NULL);
1640*00b67f09SDavid van Moolenbroek 
1641*00b67f09SDavid van Moolenbroek 	map = &mapobj->value.map;
1642*00b67f09SDavid van Moolenbroek 
1643*00b67f09SDavid van Moolenbroek 	result = isc_symtab_lookup(map->symtab, name, MAP_SYM, &val);
1644*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1645*00b67f09SDavid van Moolenbroek 		return (result);
1646*00b67f09SDavid van Moolenbroek 	*obj = val.as_pointer;
1647*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
1648*00b67f09SDavid van Moolenbroek }
1649*00b67f09SDavid van Moolenbroek 
1650*00b67f09SDavid van Moolenbroek const cfg_obj_t *
cfg_map_getname(const cfg_obj_t * mapobj)1651*00b67f09SDavid van Moolenbroek cfg_map_getname(const cfg_obj_t *mapobj) {
1652*00b67f09SDavid van Moolenbroek 	REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
1653*00b67f09SDavid van Moolenbroek 	return (mapobj->value.map.id);
1654*00b67f09SDavid van Moolenbroek }
1655*00b67f09SDavid van Moolenbroek 
1656*00b67f09SDavid van Moolenbroek unsigned int
cfg_map_count(const cfg_obj_t * mapobj)1657*00b67f09SDavid van Moolenbroek cfg_map_count(const cfg_obj_t *mapobj) {
1658*00b67f09SDavid van Moolenbroek 	const cfg_map_t *map;
1659*00b67f09SDavid van Moolenbroek 	REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
1660*00b67f09SDavid van Moolenbroek 	map = &mapobj->value.map;
1661*00b67f09SDavid van Moolenbroek 	return (isc_symtab_count(map->symtab));
1662*00b67f09SDavid van Moolenbroek }
1663*00b67f09SDavid van Moolenbroek 
1664*00b67f09SDavid van Moolenbroek /* Parse an arbitrary token, storing its raw text representation. */
1665*00b67f09SDavid van Moolenbroek static isc_result_t
parse_token(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)1666*00b67f09SDavid van Moolenbroek parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1667*00b67f09SDavid van Moolenbroek 	cfg_obj_t *obj = NULL;
1668*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1669*00b67f09SDavid van Moolenbroek 	isc_region_t r;
1670*00b67f09SDavid van Moolenbroek 
1671*00b67f09SDavid van Moolenbroek 	UNUSED(type);
1672*00b67f09SDavid van Moolenbroek 
1673*00b67f09SDavid van Moolenbroek 	CHECK(cfg_create_obj(pctx, &cfg_type_token, &obj));
1674*00b67f09SDavid van Moolenbroek 	CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
1675*00b67f09SDavid van Moolenbroek 	if (pctx->token.type == isc_tokentype_eof) {
1676*00b67f09SDavid van Moolenbroek 		cfg_ungettoken(pctx);
1677*00b67f09SDavid van Moolenbroek 		result = ISC_R_EOF;
1678*00b67f09SDavid van Moolenbroek 		goto cleanup;
1679*00b67f09SDavid van Moolenbroek 	}
1680*00b67f09SDavid van Moolenbroek 
1681*00b67f09SDavid van Moolenbroek 	isc_lex_getlasttokentext(pctx->lexer, &pctx->token, &r);
1682*00b67f09SDavid van Moolenbroek 
1683*00b67f09SDavid van Moolenbroek 	obj->value.string.base = isc_mem_get(pctx->mctx, r.length + 1);
1684*00b67f09SDavid van Moolenbroek 	if (obj->value.string.base == NULL) {
1685*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOMEMORY;
1686*00b67f09SDavid van Moolenbroek 		goto cleanup;
1687*00b67f09SDavid van Moolenbroek 	}
1688*00b67f09SDavid van Moolenbroek 	obj->value.string.length = r.length;
1689*00b67f09SDavid van Moolenbroek 	memmove(obj->value.string.base, r.base, r.length);
1690*00b67f09SDavid van Moolenbroek 	obj->value.string.base[r.length] = '\0';
1691*00b67f09SDavid van Moolenbroek 	*ret = obj;
1692*00b67f09SDavid van Moolenbroek 	return (result);
1693*00b67f09SDavid van Moolenbroek 
1694*00b67f09SDavid van Moolenbroek  cleanup:
1695*00b67f09SDavid van Moolenbroek 	if (obj != NULL)
1696*00b67f09SDavid van Moolenbroek 		isc_mem_put(pctx->mctx, obj, sizeof(*obj));
1697*00b67f09SDavid van Moolenbroek 	return (result);
1698*00b67f09SDavid van Moolenbroek }
1699*00b67f09SDavid van Moolenbroek 
1700*00b67f09SDavid van Moolenbroek cfg_type_t cfg_type_token = {
1701*00b67f09SDavid van Moolenbroek 	"token", parse_token, cfg_print_ustring, cfg_doc_terminal,
1702*00b67f09SDavid van Moolenbroek 	&cfg_rep_string, NULL
1703*00b67f09SDavid van Moolenbroek };
1704*00b67f09SDavid van Moolenbroek 
1705*00b67f09SDavid van Moolenbroek /*
1706*00b67f09SDavid van Moolenbroek  * An unsupported option.  This is just a list of tokens with balanced braces
1707*00b67f09SDavid van Moolenbroek  * ending in a semicolon.
1708*00b67f09SDavid van Moolenbroek  */
1709*00b67f09SDavid van Moolenbroek 
1710*00b67f09SDavid van Moolenbroek static isc_result_t
parse_unsupported(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)1711*00b67f09SDavid van Moolenbroek parse_unsupported(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1712*00b67f09SDavid van Moolenbroek 	cfg_obj_t *listobj = NULL;
1713*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1714*00b67f09SDavid van Moolenbroek 	int braces = 0;
1715*00b67f09SDavid van Moolenbroek 
1716*00b67f09SDavid van Moolenbroek 	CHECK(cfg_create_list(pctx, type, &listobj));
1717*00b67f09SDavid van Moolenbroek 
1718*00b67f09SDavid van Moolenbroek 	for (;;) {
1719*00b67f09SDavid van Moolenbroek 		cfg_listelt_t *elt = NULL;
1720*00b67f09SDavid van Moolenbroek 
1721*00b67f09SDavid van Moolenbroek 		CHECK(cfg_peektoken(pctx, 0));
1722*00b67f09SDavid van Moolenbroek 		if (pctx->token.type == isc_tokentype_special) {
1723*00b67f09SDavid van Moolenbroek 			if (pctx->token.value.as_char == '{')
1724*00b67f09SDavid van Moolenbroek 				braces++;
1725*00b67f09SDavid van Moolenbroek 			else if (pctx->token.value.as_char == '}')
1726*00b67f09SDavid van Moolenbroek 				braces--;
1727*00b67f09SDavid van Moolenbroek 			else if (pctx->token.value.as_char == ';')
1728*00b67f09SDavid van Moolenbroek 				if (braces == 0)
1729*00b67f09SDavid van Moolenbroek 					break;
1730*00b67f09SDavid van Moolenbroek 		}
1731*00b67f09SDavid van Moolenbroek 		if (pctx->token.type == isc_tokentype_eof || braces < 0) {
1732*00b67f09SDavid van Moolenbroek 			cfg_parser_error(pctx, CFG_LOG_NEAR, "unexpected token");
1733*00b67f09SDavid van Moolenbroek 			result = ISC_R_UNEXPECTEDTOKEN;
1734*00b67f09SDavid van Moolenbroek 			goto cleanup;
1735*00b67f09SDavid van Moolenbroek 		}
1736*00b67f09SDavid van Moolenbroek 
1737*00b67f09SDavid van Moolenbroek 		CHECK(cfg_parse_listelt(pctx, &cfg_type_token, &elt));
1738*00b67f09SDavid van Moolenbroek 		ISC_LIST_APPEND(listobj->value.list, elt, link);
1739*00b67f09SDavid van Moolenbroek 	}
1740*00b67f09SDavid van Moolenbroek 	INSIST(braces == 0);
1741*00b67f09SDavid van Moolenbroek 	*ret = listobj;
1742*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
1743*00b67f09SDavid van Moolenbroek 
1744*00b67f09SDavid van Moolenbroek  cleanup:
1745*00b67f09SDavid van Moolenbroek 	CLEANUP_OBJ(listobj);
1746*00b67f09SDavid van Moolenbroek 	return (result);
1747*00b67f09SDavid van Moolenbroek }
1748*00b67f09SDavid van Moolenbroek 
1749*00b67f09SDavid van Moolenbroek cfg_type_t cfg_type_unsupported = {
1750*00b67f09SDavid van Moolenbroek 	"unsupported", parse_unsupported, cfg_print_spacelist, cfg_doc_terminal,
1751*00b67f09SDavid van Moolenbroek 	&cfg_rep_list, NULL
1752*00b67f09SDavid van Moolenbroek };
1753*00b67f09SDavid van Moolenbroek 
1754*00b67f09SDavid van Moolenbroek /*
1755*00b67f09SDavid van Moolenbroek  * Try interpreting the current token as a network address.
1756*00b67f09SDavid van Moolenbroek  *
1757*00b67f09SDavid van Moolenbroek  * If CFG_ADDR_WILDOK is set in flags, "*" can be used as a wildcard
1758*00b67f09SDavid van Moolenbroek  * and at least one of CFG_ADDR_V4OK and CFG_ADDR_V6OK must also be set.  The
1759*00b67f09SDavid van Moolenbroek  * "*" is interpreted as the IPv4 wildcard address if CFG_ADDR_V4OK is
1760*00b67f09SDavid van Moolenbroek  * set (including the case where CFG_ADDR_V4OK and CFG_ADDR_V6OK are both set),
1761*00b67f09SDavid van Moolenbroek  * and the IPv6 wildcard address otherwise.
1762*00b67f09SDavid van Moolenbroek  */
1763*00b67f09SDavid van Moolenbroek static isc_result_t
token_addr(cfg_parser_t * pctx,unsigned int flags,isc_netaddr_t * na)1764*00b67f09SDavid van Moolenbroek token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) {
1765*00b67f09SDavid van Moolenbroek 	char *s;
1766*00b67f09SDavid van Moolenbroek 	struct in_addr in4a;
1767*00b67f09SDavid van Moolenbroek 	struct in6_addr in6a;
1768*00b67f09SDavid van Moolenbroek 
1769*00b67f09SDavid van Moolenbroek 	if (pctx->token.type != isc_tokentype_string)
1770*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTEDTOKEN);
1771*00b67f09SDavid van Moolenbroek 
1772*00b67f09SDavid van Moolenbroek 	s = TOKEN_STRING(pctx);
1773*00b67f09SDavid van Moolenbroek 	if ((flags & CFG_ADDR_WILDOK) != 0 && strcmp(s, "*") == 0) {
1774*00b67f09SDavid van Moolenbroek 		if ((flags & CFG_ADDR_V4OK) != 0) {
1775*00b67f09SDavid van Moolenbroek 			isc_netaddr_any(na);
1776*00b67f09SDavid van Moolenbroek 			return (ISC_R_SUCCESS);
1777*00b67f09SDavid van Moolenbroek 		} else if ((flags & CFG_ADDR_V6OK) != 0) {
1778*00b67f09SDavid van Moolenbroek 			isc_netaddr_any6(na);
1779*00b67f09SDavid van Moolenbroek 			return (ISC_R_SUCCESS);
1780*00b67f09SDavid van Moolenbroek 		} else {
1781*00b67f09SDavid van Moolenbroek 			INSIST(0);
1782*00b67f09SDavid van Moolenbroek 		}
1783*00b67f09SDavid van Moolenbroek 	} else {
1784*00b67f09SDavid van Moolenbroek 		if ((flags & (CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK)) != 0) {
1785*00b67f09SDavid van Moolenbroek 			if (inet_pton(AF_INET, s, &in4a) == 1) {
1786*00b67f09SDavid van Moolenbroek 				isc_netaddr_fromin(na, &in4a);
1787*00b67f09SDavid van Moolenbroek 				return (ISC_R_SUCCESS);
1788*00b67f09SDavid van Moolenbroek 			}
1789*00b67f09SDavid van Moolenbroek 		}
1790*00b67f09SDavid van Moolenbroek 		if ((flags & CFG_ADDR_V4PREFIXOK) != 0 &&
1791*00b67f09SDavid van Moolenbroek 		    strlen(s) <= 15U) {
1792*00b67f09SDavid van Moolenbroek 			char buf[64];
1793*00b67f09SDavid van Moolenbroek 			int i;
1794*00b67f09SDavid van Moolenbroek 
1795*00b67f09SDavid van Moolenbroek 			strcpy(buf, s);
1796*00b67f09SDavid van Moolenbroek 			for (i = 0; i < 3; i++) {
1797*00b67f09SDavid van Moolenbroek 				strcat(buf, ".0");
1798*00b67f09SDavid van Moolenbroek 				if (inet_pton(AF_INET, buf, &in4a) == 1) {
1799*00b67f09SDavid van Moolenbroek 					isc_netaddr_fromin(na, &in4a);
1800*00b67f09SDavid van Moolenbroek 					return (ISC_R_SUCCESS);
1801*00b67f09SDavid van Moolenbroek 				}
1802*00b67f09SDavid van Moolenbroek 			}
1803*00b67f09SDavid van Moolenbroek 		}
1804*00b67f09SDavid van Moolenbroek 		if ((flags & CFG_ADDR_V6OK) != 0 &&
1805*00b67f09SDavid van Moolenbroek 		    strlen(s) <= 127U) {
1806*00b67f09SDavid van Moolenbroek 			char buf[128]; /* see lib/bind9/getaddresses.c */
1807*00b67f09SDavid van Moolenbroek 			char *d; /* zone delimiter */
1808*00b67f09SDavid van Moolenbroek 			isc_uint32_t zone = 0; /* scope zone ID */
1809*00b67f09SDavid van Moolenbroek 
1810*00b67f09SDavid van Moolenbroek 			strcpy(buf, s);
1811*00b67f09SDavid van Moolenbroek 			d = strchr(buf, '%');
1812*00b67f09SDavid van Moolenbroek 			if (d != NULL)
1813*00b67f09SDavid van Moolenbroek 				*d = '\0';
1814*00b67f09SDavid van Moolenbroek 
1815*00b67f09SDavid van Moolenbroek 			if (inet_pton(AF_INET6, buf, &in6a) == 1) {
1816*00b67f09SDavid van Moolenbroek 				if (d != NULL) {
1817*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_HAVESCOPEID
1818*00b67f09SDavid van Moolenbroek 					isc_result_t result;
1819*00b67f09SDavid van Moolenbroek 
1820*00b67f09SDavid van Moolenbroek 					result = isc_netscope_pton(AF_INET6,
1821*00b67f09SDavid van Moolenbroek 								   d + 1,
1822*00b67f09SDavid van Moolenbroek 								   &in6a,
1823*00b67f09SDavid van Moolenbroek 								   &zone);
1824*00b67f09SDavid van Moolenbroek 					if (result != ISC_R_SUCCESS)
1825*00b67f09SDavid van Moolenbroek 						return (result);
1826*00b67f09SDavid van Moolenbroek #else
1827*00b67f09SDavid van Moolenbroek 				return (ISC_R_BADADDRESSFORM);
1828*00b67f09SDavid van Moolenbroek #endif
1829*00b67f09SDavid van Moolenbroek 				}
1830*00b67f09SDavid van Moolenbroek 
1831*00b67f09SDavid van Moolenbroek 				isc_netaddr_fromin6(na, &in6a);
1832*00b67f09SDavid van Moolenbroek 				isc_netaddr_setzone(na, zone);
1833*00b67f09SDavid van Moolenbroek 				return (ISC_R_SUCCESS);
1834*00b67f09SDavid van Moolenbroek 			}
1835*00b67f09SDavid van Moolenbroek 		}
1836*00b67f09SDavid van Moolenbroek 	}
1837*00b67f09SDavid van Moolenbroek 	return (ISC_R_UNEXPECTEDTOKEN);
1838*00b67f09SDavid van Moolenbroek }
1839*00b67f09SDavid van Moolenbroek 
1840*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_rawaddr(cfg_parser_t * pctx,unsigned int flags,isc_netaddr_t * na)1841*00b67f09SDavid van Moolenbroek cfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) {
1842*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1843*00b67f09SDavid van Moolenbroek 	const char *wild = "";
1844*00b67f09SDavid van Moolenbroek 	const char *prefix = "";
1845*00b67f09SDavid van Moolenbroek 
1846*00b67f09SDavid van Moolenbroek 	CHECK(cfg_gettoken(pctx, 0));
1847*00b67f09SDavid van Moolenbroek 	result = token_addr(pctx, flags, na);
1848*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_UNEXPECTEDTOKEN) {
1849*00b67f09SDavid van Moolenbroek 		if ((flags & CFG_ADDR_WILDOK) != 0)
1850*00b67f09SDavid van Moolenbroek 			wild = " or '*'";
1851*00b67f09SDavid van Moolenbroek 		if ((flags & CFG_ADDR_V4PREFIXOK) != 0)
1852*00b67f09SDavid van Moolenbroek 			wild = " or IPv4 prefix";
1853*00b67f09SDavid van Moolenbroek 		if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V4OK)
1854*00b67f09SDavid van Moolenbroek 			cfg_parser_error(pctx, CFG_LOG_NEAR,
1855*00b67f09SDavid van Moolenbroek 					 "expected IPv4 address%s%s",
1856*00b67f09SDavid van Moolenbroek 					 prefix, wild);
1857*00b67f09SDavid van Moolenbroek 		else if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V6OK)
1858*00b67f09SDavid van Moolenbroek 			cfg_parser_error(pctx, CFG_LOG_NEAR,
1859*00b67f09SDavid van Moolenbroek 					 "expected IPv6 address%s%s",
1860*00b67f09SDavid van Moolenbroek 					 prefix, wild);
1861*00b67f09SDavid van Moolenbroek 		else
1862*00b67f09SDavid van Moolenbroek 			cfg_parser_error(pctx, CFG_LOG_NEAR,
1863*00b67f09SDavid van Moolenbroek 					 "expected IP address%s%s",
1864*00b67f09SDavid van Moolenbroek 					 prefix, wild);
1865*00b67f09SDavid van Moolenbroek 	}
1866*00b67f09SDavid van Moolenbroek  cleanup:
1867*00b67f09SDavid van Moolenbroek 	return (result);
1868*00b67f09SDavid van Moolenbroek }
1869*00b67f09SDavid van Moolenbroek 
1870*00b67f09SDavid van Moolenbroek isc_boolean_t
cfg_lookingat_netaddr(cfg_parser_t * pctx,unsigned int flags)1871*00b67f09SDavid van Moolenbroek cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags) {
1872*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1873*00b67f09SDavid van Moolenbroek 	isc_netaddr_t na_dummy;
1874*00b67f09SDavid van Moolenbroek 	result = token_addr(pctx, flags, &na_dummy);
1875*00b67f09SDavid van Moolenbroek 	return (ISC_TF(result == ISC_R_SUCCESS));
1876*00b67f09SDavid van Moolenbroek }
1877*00b67f09SDavid van Moolenbroek 
1878*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_rawport(cfg_parser_t * pctx,unsigned int flags,in_port_t * port)1879*00b67f09SDavid van Moolenbroek cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port) {
1880*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1881*00b67f09SDavid van Moolenbroek 
1882*00b67f09SDavid van Moolenbroek 	CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER));
1883*00b67f09SDavid van Moolenbroek 
1884*00b67f09SDavid van Moolenbroek 	if ((flags & CFG_ADDR_WILDOK) != 0 &&
1885*00b67f09SDavid van Moolenbroek 	    pctx->token.type == isc_tokentype_string &&
1886*00b67f09SDavid van Moolenbroek 	    strcmp(TOKEN_STRING(pctx), "*") == 0) {
1887*00b67f09SDavid van Moolenbroek 		*port = 0;
1888*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
1889*00b67f09SDavid van Moolenbroek 	}
1890*00b67f09SDavid van Moolenbroek 	if (pctx->token.type != isc_tokentype_number) {
1891*00b67f09SDavid van Moolenbroek 		cfg_parser_error(pctx, CFG_LOG_NEAR,
1892*00b67f09SDavid van Moolenbroek 			     "expected port number or '*'");
1893*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTEDTOKEN);
1894*00b67f09SDavid van Moolenbroek 	}
1895*00b67f09SDavid van Moolenbroek 	if (pctx->token.value.as_ulong >= 65536U) {
1896*00b67f09SDavid van Moolenbroek 		cfg_parser_error(pctx, CFG_LOG_NEAR,
1897*00b67f09SDavid van Moolenbroek 			     "port number out of range");
1898*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTEDTOKEN);
1899*00b67f09SDavid van Moolenbroek 	}
1900*00b67f09SDavid van Moolenbroek 	*port = (in_port_t)(pctx->token.value.as_ulong);
1901*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
1902*00b67f09SDavid van Moolenbroek  cleanup:
1903*00b67f09SDavid van Moolenbroek 	return (result);
1904*00b67f09SDavid van Moolenbroek }
1905*00b67f09SDavid van Moolenbroek 
1906*00b67f09SDavid van Moolenbroek void
cfg_print_rawaddr(cfg_printer_t * pctx,const isc_netaddr_t * na)1907*00b67f09SDavid van Moolenbroek cfg_print_rawaddr(cfg_printer_t *pctx, const isc_netaddr_t *na) {
1908*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1909*00b67f09SDavid van Moolenbroek 	char text[128];
1910*00b67f09SDavid van Moolenbroek 	isc_buffer_t buf;
1911*00b67f09SDavid van Moolenbroek 
1912*00b67f09SDavid van Moolenbroek 	isc_buffer_init(&buf, text, sizeof(text));
1913*00b67f09SDavid van Moolenbroek 	result = isc_netaddr_totext(na, &buf);
1914*00b67f09SDavid van Moolenbroek 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
1915*00b67f09SDavid van Moolenbroek 	cfg_print_chars(pctx, isc_buffer_base(&buf), isc_buffer_usedlength(&buf));
1916*00b67f09SDavid van Moolenbroek }
1917*00b67f09SDavid van Moolenbroek 
1918*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_dscp(cfg_parser_t * pctx,isc_dscp_t * dscp)1919*00b67f09SDavid van Moolenbroek cfg_parse_dscp(cfg_parser_t *pctx, isc_dscp_t *dscp) {
1920*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1921*00b67f09SDavid van Moolenbroek 
1922*00b67f09SDavid van Moolenbroek 	CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
1923*00b67f09SDavid van Moolenbroek 
1924*00b67f09SDavid van Moolenbroek 	if (pctx->token.type != isc_tokentype_number) {
1925*00b67f09SDavid van Moolenbroek 		cfg_parser_error(pctx, CFG_LOG_NEAR,
1926*00b67f09SDavid van Moolenbroek 			     "expected number");
1927*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTEDTOKEN);
1928*00b67f09SDavid van Moolenbroek 	}
1929*00b67f09SDavid van Moolenbroek 	if (pctx->token.value.as_ulong > 63U) {
1930*00b67f09SDavid van Moolenbroek 		cfg_parser_error(pctx, CFG_LOG_NEAR,
1931*00b67f09SDavid van Moolenbroek 			     "dscp out of range");
1932*00b67f09SDavid van Moolenbroek 		return (ISC_R_RANGE);
1933*00b67f09SDavid van Moolenbroek 	}
1934*00b67f09SDavid van Moolenbroek 	*dscp = (isc_dscp_t)(pctx->token.value.as_ulong);
1935*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
1936*00b67f09SDavid van Moolenbroek  cleanup:
1937*00b67f09SDavid van Moolenbroek 	return (result);
1938*00b67f09SDavid van Moolenbroek }
1939*00b67f09SDavid van Moolenbroek 
1940*00b67f09SDavid van Moolenbroek /* netaddr */
1941*00b67f09SDavid van Moolenbroek 
1942*00b67f09SDavid van Moolenbroek static unsigned int netaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK;
1943*00b67f09SDavid van Moolenbroek static unsigned int netaddr4_flags = CFG_ADDR_V4OK;
1944*00b67f09SDavid van Moolenbroek static unsigned int netaddr4wild_flags = CFG_ADDR_V4OK | CFG_ADDR_WILDOK;
1945*00b67f09SDavid van Moolenbroek static unsigned int netaddr6_flags = CFG_ADDR_V6OK;
1946*00b67f09SDavid van Moolenbroek static unsigned int netaddr6wild_flags = CFG_ADDR_V6OK | CFG_ADDR_WILDOK;
1947*00b67f09SDavid van Moolenbroek 
1948*00b67f09SDavid van Moolenbroek static isc_result_t
parse_netaddr(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)1949*00b67f09SDavid van Moolenbroek parse_netaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1950*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1951*00b67f09SDavid van Moolenbroek 	cfg_obj_t *obj = NULL;
1952*00b67f09SDavid van Moolenbroek 	isc_netaddr_t netaddr;
1953*00b67f09SDavid van Moolenbroek 	unsigned int flags = *(const unsigned int *)type->of;
1954*00b67f09SDavid van Moolenbroek 
1955*00b67f09SDavid van Moolenbroek 	CHECK(cfg_create_obj(pctx, type, &obj));
1956*00b67f09SDavid van Moolenbroek 	CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr));
1957*00b67f09SDavid van Moolenbroek 	isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, 0);
1958*00b67f09SDavid van Moolenbroek 	*ret = obj;
1959*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
1960*00b67f09SDavid van Moolenbroek  cleanup:
1961*00b67f09SDavid van Moolenbroek 	CLEANUP_OBJ(obj);
1962*00b67f09SDavid van Moolenbroek 	return (result);
1963*00b67f09SDavid van Moolenbroek }
1964*00b67f09SDavid van Moolenbroek 
1965*00b67f09SDavid van Moolenbroek static void
cfg_doc_netaddr(cfg_printer_t * pctx,const cfg_type_t * type)1966*00b67f09SDavid van Moolenbroek cfg_doc_netaddr(cfg_printer_t *pctx, const cfg_type_t *type) {
1967*00b67f09SDavid van Moolenbroek 	const unsigned int *flagp = type->of;
1968*00b67f09SDavid van Moolenbroek 	int n = 0;
1969*00b67f09SDavid van Moolenbroek 	if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK)
1970*00b67f09SDavid van Moolenbroek 		cfg_print_chars(pctx, "( ", 2);
1971*00b67f09SDavid van Moolenbroek 	if (*flagp & CFG_ADDR_V4OK) {
1972*00b67f09SDavid van Moolenbroek 		cfg_print_cstr(pctx, "<ipv4_address>");
1973*00b67f09SDavid van Moolenbroek 		n++;
1974*00b67f09SDavid van Moolenbroek 	}
1975*00b67f09SDavid van Moolenbroek 	if (*flagp & CFG_ADDR_V6OK) {
1976*00b67f09SDavid van Moolenbroek 		if (n != 0)
1977*00b67f09SDavid van Moolenbroek 			cfg_print_chars(pctx, " | ", 3);
1978*00b67f09SDavid van Moolenbroek 		cfg_print_cstr(pctx, "<ipv6_address>");
1979*00b67f09SDavid van Moolenbroek 		n++;
1980*00b67f09SDavid van Moolenbroek 	}
1981*00b67f09SDavid van Moolenbroek 	if (*flagp & CFG_ADDR_WILDOK) {
1982*00b67f09SDavid van Moolenbroek 		if (n != 0)
1983*00b67f09SDavid van Moolenbroek 			cfg_print_chars(pctx, " | ", 3);
1984*00b67f09SDavid van Moolenbroek 		cfg_print_chars(pctx, "*", 1);
1985*00b67f09SDavid van Moolenbroek 		n++;
1986*00b67f09SDavid van Moolenbroek 		POST(n);
1987*00b67f09SDavid van Moolenbroek 	}
1988*00b67f09SDavid van Moolenbroek 	if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK)
1989*00b67f09SDavid van Moolenbroek 		cfg_print_chars(pctx, " )", 2);
1990*00b67f09SDavid van Moolenbroek }
1991*00b67f09SDavid van Moolenbroek 
1992*00b67f09SDavid van Moolenbroek cfg_type_t cfg_type_netaddr = {
1993*00b67f09SDavid van Moolenbroek 	"netaddr", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
1994*00b67f09SDavid van Moolenbroek 	&cfg_rep_sockaddr, &netaddr_flags
1995*00b67f09SDavid van Moolenbroek };
1996*00b67f09SDavid van Moolenbroek 
1997*00b67f09SDavid van Moolenbroek cfg_type_t cfg_type_netaddr4 = {
1998*00b67f09SDavid van Moolenbroek 	"netaddr4", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
1999*00b67f09SDavid van Moolenbroek 	&cfg_rep_sockaddr, &netaddr4_flags
2000*00b67f09SDavid van Moolenbroek };
2001*00b67f09SDavid van Moolenbroek 
2002*00b67f09SDavid van Moolenbroek cfg_type_t cfg_type_netaddr4wild = {
2003*00b67f09SDavid van Moolenbroek 	"netaddr4wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
2004*00b67f09SDavid van Moolenbroek 	&cfg_rep_sockaddr, &netaddr4wild_flags
2005*00b67f09SDavid van Moolenbroek };
2006*00b67f09SDavid van Moolenbroek 
2007*00b67f09SDavid van Moolenbroek cfg_type_t cfg_type_netaddr6 = {
2008*00b67f09SDavid van Moolenbroek 	"netaddr6", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
2009*00b67f09SDavid van Moolenbroek 	&cfg_rep_sockaddr, &netaddr6_flags
2010*00b67f09SDavid van Moolenbroek };
2011*00b67f09SDavid van Moolenbroek 
2012*00b67f09SDavid van Moolenbroek cfg_type_t cfg_type_netaddr6wild = {
2013*00b67f09SDavid van Moolenbroek 	"netaddr6wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
2014*00b67f09SDavid van Moolenbroek 	&cfg_rep_sockaddr, &netaddr6wild_flags
2015*00b67f09SDavid van Moolenbroek };
2016*00b67f09SDavid van Moolenbroek 
2017*00b67f09SDavid van Moolenbroek /* netprefix */
2018*00b67f09SDavid van Moolenbroek 
2019*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_netprefix(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)2020*00b67f09SDavid van Moolenbroek cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type,
2021*00b67f09SDavid van Moolenbroek 		    cfg_obj_t **ret)
2022*00b67f09SDavid van Moolenbroek {
2023*00b67f09SDavid van Moolenbroek 	cfg_obj_t *obj = NULL;
2024*00b67f09SDavid van Moolenbroek 	isc_result_t result;
2025*00b67f09SDavid van Moolenbroek 	isc_netaddr_t netaddr;
2026*00b67f09SDavid van Moolenbroek 	unsigned int addrlen = 0, prefixlen;
2027*00b67f09SDavid van Moolenbroek 	UNUSED(type);
2028*00b67f09SDavid van Moolenbroek 
2029*00b67f09SDavid van Moolenbroek 	CHECK(cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK |
2030*00b67f09SDavid van Moolenbroek 				CFG_ADDR_V6OK, &netaddr));
2031*00b67f09SDavid van Moolenbroek 	switch (netaddr.family) {
2032*00b67f09SDavid van Moolenbroek 	case AF_INET:
2033*00b67f09SDavid van Moolenbroek 		addrlen = 32;
2034*00b67f09SDavid van Moolenbroek 		break;
2035*00b67f09SDavid van Moolenbroek 	case AF_INET6:
2036*00b67f09SDavid van Moolenbroek 		addrlen = 128;
2037*00b67f09SDavid van Moolenbroek 		break;
2038*00b67f09SDavid van Moolenbroek 	default:
2039*00b67f09SDavid van Moolenbroek 		INSIST(0);
2040*00b67f09SDavid van Moolenbroek 		break;
2041*00b67f09SDavid van Moolenbroek 	}
2042*00b67f09SDavid van Moolenbroek 	CHECK(cfg_peektoken(pctx, 0));
2043*00b67f09SDavid van Moolenbroek 	if (pctx->token.type == isc_tokentype_special &&
2044*00b67f09SDavid van Moolenbroek 	    pctx->token.value.as_char == '/') {
2045*00b67f09SDavid van Moolenbroek 		CHECK(cfg_gettoken(pctx, 0)); /* read "/" */
2046*00b67f09SDavid van Moolenbroek 		CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER));
2047*00b67f09SDavid van Moolenbroek 		if (pctx->token.type != isc_tokentype_number) {
2048*00b67f09SDavid van Moolenbroek 			cfg_parser_error(pctx, CFG_LOG_NEAR,
2049*00b67f09SDavid van Moolenbroek 				     "expected prefix length");
2050*00b67f09SDavid van Moolenbroek 			return (ISC_R_UNEXPECTEDTOKEN);
2051*00b67f09SDavid van Moolenbroek 		}
2052*00b67f09SDavid van Moolenbroek 		prefixlen = pctx->token.value.as_ulong;
2053*00b67f09SDavid van Moolenbroek 		if (prefixlen > addrlen) {
2054*00b67f09SDavid van Moolenbroek 			cfg_parser_error(pctx, CFG_LOG_NOPREP,
2055*00b67f09SDavid van Moolenbroek 				     "invalid prefix length");
2056*00b67f09SDavid van Moolenbroek 			return (ISC_R_RANGE);
2057*00b67f09SDavid van Moolenbroek 		}
2058*00b67f09SDavid van Moolenbroek 	} else {
2059*00b67f09SDavid van Moolenbroek 		prefixlen = addrlen;
2060*00b67f09SDavid van Moolenbroek 	}
2061*00b67f09SDavid van Moolenbroek 	CHECK(cfg_create_obj(pctx, &cfg_type_netprefix, &obj));
2062*00b67f09SDavid van Moolenbroek 	obj->value.netprefix.address = netaddr;
2063*00b67f09SDavid van Moolenbroek 	obj->value.netprefix.prefixlen = prefixlen;
2064*00b67f09SDavid van Moolenbroek 	*ret = obj;
2065*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
2066*00b67f09SDavid van Moolenbroek  cleanup:
2067*00b67f09SDavid van Moolenbroek 	cfg_parser_error(pctx, CFG_LOG_NEAR, "expected network prefix");
2068*00b67f09SDavid van Moolenbroek 	return (result);
2069*00b67f09SDavid van Moolenbroek }
2070*00b67f09SDavid van Moolenbroek 
2071*00b67f09SDavid van Moolenbroek static void
print_netprefix(cfg_printer_t * pctx,const cfg_obj_t * obj)2072*00b67f09SDavid van Moolenbroek print_netprefix(cfg_printer_t *pctx, const cfg_obj_t *obj) {
2073*00b67f09SDavid van Moolenbroek 	const cfg_netprefix_t *p = &obj->value.netprefix;
2074*00b67f09SDavid van Moolenbroek 
2075*00b67f09SDavid van Moolenbroek 	cfg_print_rawaddr(pctx, &p->address);
2076*00b67f09SDavid van Moolenbroek 	cfg_print_chars(pctx, "/", 1);
2077*00b67f09SDavid van Moolenbroek 	cfg_print_rawuint(pctx, p->prefixlen);
2078*00b67f09SDavid van Moolenbroek }
2079*00b67f09SDavid van Moolenbroek 
2080*00b67f09SDavid van Moolenbroek isc_boolean_t
cfg_obj_isnetprefix(const cfg_obj_t * obj)2081*00b67f09SDavid van Moolenbroek cfg_obj_isnetprefix(const cfg_obj_t *obj) {
2082*00b67f09SDavid van Moolenbroek 	REQUIRE(obj != NULL);
2083*00b67f09SDavid van Moolenbroek 	return (ISC_TF(obj->type->rep == &cfg_rep_netprefix));
2084*00b67f09SDavid van Moolenbroek }
2085*00b67f09SDavid van Moolenbroek 
2086*00b67f09SDavid van Moolenbroek void
cfg_obj_asnetprefix(const cfg_obj_t * obj,isc_netaddr_t * netaddr,unsigned int * prefixlen)2087*00b67f09SDavid van Moolenbroek cfg_obj_asnetprefix(const cfg_obj_t *obj, isc_netaddr_t *netaddr,
2088*00b67f09SDavid van Moolenbroek 		    unsigned int *prefixlen)
2089*00b67f09SDavid van Moolenbroek {
2090*00b67f09SDavid van Moolenbroek 	REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_netprefix);
2091*00b67f09SDavid van Moolenbroek 	REQUIRE(netaddr != NULL);
2092*00b67f09SDavid van Moolenbroek 	REQUIRE(prefixlen != NULL);
2093*00b67f09SDavid van Moolenbroek 
2094*00b67f09SDavid van Moolenbroek 	*netaddr = obj->value.netprefix.address;
2095*00b67f09SDavid van Moolenbroek 	*prefixlen = obj->value.netprefix.prefixlen;
2096*00b67f09SDavid van Moolenbroek }
2097*00b67f09SDavid van Moolenbroek 
2098*00b67f09SDavid van Moolenbroek cfg_type_t cfg_type_netprefix = {
2099*00b67f09SDavid van Moolenbroek 	"netprefix", cfg_parse_netprefix, print_netprefix, cfg_doc_terminal,
2100*00b67f09SDavid van Moolenbroek 	&cfg_rep_netprefix, NULL
2101*00b67f09SDavid van Moolenbroek };
2102*00b67f09SDavid van Moolenbroek 
2103*00b67f09SDavid van Moolenbroek static isc_result_t
parse_sockaddrsub(cfg_parser_t * pctx,const cfg_type_t * type,int flags,cfg_obj_t ** ret)2104*00b67f09SDavid van Moolenbroek parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type,
2105*00b67f09SDavid van Moolenbroek 		  int flags, cfg_obj_t **ret)
2106*00b67f09SDavid van Moolenbroek {
2107*00b67f09SDavid van Moolenbroek 	isc_result_t result;
2108*00b67f09SDavid van Moolenbroek 	isc_netaddr_t netaddr;
2109*00b67f09SDavid van Moolenbroek 	in_port_t port = 0;
2110*00b67f09SDavid van Moolenbroek 	isc_dscp_t dscp = -1;
2111*00b67f09SDavid van Moolenbroek 	cfg_obj_t *obj = NULL;
2112*00b67f09SDavid van Moolenbroek 	int have_port = 0, have_dscp = 0;
2113*00b67f09SDavid van Moolenbroek 
2114*00b67f09SDavid van Moolenbroek 	CHECK(cfg_create_obj(pctx, type, &obj));
2115*00b67f09SDavid van Moolenbroek 	CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr));
2116*00b67f09SDavid van Moolenbroek 	for (;;) {
2117*00b67f09SDavid van Moolenbroek 		CHECK(cfg_peektoken(pctx, 0));
2118*00b67f09SDavid van Moolenbroek 		if (pctx->token.type == isc_tokentype_string) {
2119*00b67f09SDavid van Moolenbroek 			if (strcasecmp(TOKEN_STRING(pctx), "port") == 0) {
2120*00b67f09SDavid van Moolenbroek 				CHECK(cfg_gettoken(pctx, 0)); /* read "port" */
2121*00b67f09SDavid van Moolenbroek 				CHECK(cfg_parse_rawport(pctx, flags, &port));
2122*00b67f09SDavid van Moolenbroek 				++have_port;
2123*00b67f09SDavid van Moolenbroek 			} else if ((flags & CFG_ADDR_DSCPOK) != 0 &&
2124*00b67f09SDavid van Moolenbroek 				   strcasecmp(TOKEN_STRING(pctx), "dscp") == 0)
2125*00b67f09SDavid van Moolenbroek 			{
2126*00b67f09SDavid van Moolenbroek 				CHECK(cfg_gettoken(pctx, 0)); /* read "dscp" */
2127*00b67f09SDavid van Moolenbroek 				CHECK(cfg_parse_dscp(pctx, &dscp));
2128*00b67f09SDavid van Moolenbroek 				++have_dscp;
2129*00b67f09SDavid van Moolenbroek 			} else
2130*00b67f09SDavid van Moolenbroek 				break;
2131*00b67f09SDavid van Moolenbroek 		} else
2132*00b67f09SDavid van Moolenbroek 			break;
2133*00b67f09SDavid van Moolenbroek 	}
2134*00b67f09SDavid van Moolenbroek 	if (have_port > 1) {
2135*00b67f09SDavid van Moolenbroek 		cfg_parser_error(pctx, 0, "expected at most one port");
2136*00b67f09SDavid van Moolenbroek 		result = ISC_R_UNEXPECTEDTOKEN;
2137*00b67f09SDavid van Moolenbroek 		goto cleanup;
2138*00b67f09SDavid van Moolenbroek 	}
2139*00b67f09SDavid van Moolenbroek 
2140*00b67f09SDavid van Moolenbroek 	if (have_dscp > 1) {
2141*00b67f09SDavid van Moolenbroek 		cfg_parser_error(pctx, 0, "expected at most one dscp");
2142*00b67f09SDavid van Moolenbroek 		result = ISC_R_UNEXPECTEDTOKEN;
2143*00b67f09SDavid van Moolenbroek 		goto cleanup;
2144*00b67f09SDavid van Moolenbroek 	}
2145*00b67f09SDavid van Moolenbroek 	isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port);
2146*00b67f09SDavid van Moolenbroek 	obj->value.sockaddrdscp.dscp = dscp;
2147*00b67f09SDavid van Moolenbroek 	*ret = obj;
2148*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
2149*00b67f09SDavid van Moolenbroek 
2150*00b67f09SDavid van Moolenbroek  cleanup:
2151*00b67f09SDavid van Moolenbroek 	CLEANUP_OBJ(obj);
2152*00b67f09SDavid van Moolenbroek 	return (result);
2153*00b67f09SDavid van Moolenbroek }
2154*00b67f09SDavid van Moolenbroek 
2155*00b67f09SDavid van Moolenbroek static unsigned int sockaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK;
2156*00b67f09SDavid van Moolenbroek cfg_type_t cfg_type_sockaddr = {
2157*00b67f09SDavid van Moolenbroek 	"sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr,
2158*00b67f09SDavid van Moolenbroek 	&cfg_rep_sockaddr, &sockaddr_flags
2159*00b67f09SDavid van Moolenbroek };
2160*00b67f09SDavid van Moolenbroek 
2161*00b67f09SDavid van Moolenbroek static unsigned int sockaddrdscp_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK |
2162*00b67f09SDavid van Moolenbroek 					 CFG_ADDR_DSCPOK;
2163*00b67f09SDavid van Moolenbroek cfg_type_t cfg_type_sockaddrdscp = {
2164*00b67f09SDavid van Moolenbroek 	"sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr,
2165*00b67f09SDavid van Moolenbroek 	&cfg_rep_sockaddr, &sockaddrdscp_flags
2166*00b67f09SDavid van Moolenbroek };
2167*00b67f09SDavid van Moolenbroek 
2168*00b67f09SDavid van Moolenbroek isc_result_t
cfg_parse_sockaddr(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)2169*00b67f09SDavid van Moolenbroek cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
2170*00b67f09SDavid van Moolenbroek 	const unsigned int *flagp = type->of;
2171*00b67f09SDavid van Moolenbroek 	return (parse_sockaddrsub(pctx, &cfg_type_sockaddr, *flagp, ret));
2172*00b67f09SDavid van Moolenbroek }
2173*00b67f09SDavid van Moolenbroek 
2174*00b67f09SDavid van Moolenbroek void
cfg_print_sockaddr(cfg_printer_t * pctx,const cfg_obj_t * obj)2175*00b67f09SDavid van Moolenbroek cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj) {
2176*00b67f09SDavid van Moolenbroek 	isc_netaddr_t netaddr;
2177*00b67f09SDavid van Moolenbroek 	in_port_t port;
2178*00b67f09SDavid van Moolenbroek 	char buf[ISC_NETADDR_FORMATSIZE];
2179*00b67f09SDavid van Moolenbroek 
2180*00b67f09SDavid van Moolenbroek 	isc_netaddr_fromsockaddr(&netaddr, &obj->value.sockaddr);
2181*00b67f09SDavid van Moolenbroek 	isc_netaddr_format(&netaddr, buf, sizeof(buf));
2182*00b67f09SDavid van Moolenbroek 	cfg_print_cstr(pctx, buf);
2183*00b67f09SDavid van Moolenbroek 	port = isc_sockaddr_getport(&obj->value.sockaddr);
2184*00b67f09SDavid van Moolenbroek 	if (port != 0) {
2185*00b67f09SDavid van Moolenbroek 		cfg_print_chars(pctx, " port ", 6);
2186*00b67f09SDavid van Moolenbroek 		cfg_print_rawuint(pctx, port);
2187*00b67f09SDavid van Moolenbroek 	}
2188*00b67f09SDavid van Moolenbroek 	if (obj->value.sockaddrdscp.dscp != -1) {
2189*00b67f09SDavid van Moolenbroek 		cfg_print_chars(pctx, " dscp ", 6);
2190*00b67f09SDavid van Moolenbroek 		cfg_print_rawuint(pctx, obj->value.sockaddrdscp.dscp);
2191*00b67f09SDavid van Moolenbroek 	}
2192*00b67f09SDavid van Moolenbroek }
2193*00b67f09SDavid van Moolenbroek 
2194*00b67f09SDavid van Moolenbroek void
cfg_doc_sockaddr(cfg_printer_t * pctx,const cfg_type_t * type)2195*00b67f09SDavid van Moolenbroek cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) {
2196*00b67f09SDavid van Moolenbroek 	const unsigned int *flagp = type->of;
2197*00b67f09SDavid van Moolenbroek 	int n = 0;
2198*00b67f09SDavid van Moolenbroek 	cfg_print_chars(pctx, "( ", 2);
2199*00b67f09SDavid van Moolenbroek 	if (*flagp & CFG_ADDR_V4OK) {
2200*00b67f09SDavid van Moolenbroek 		cfg_print_cstr(pctx, "<ipv4_address>");
2201*00b67f09SDavid van Moolenbroek 		n++;
2202*00b67f09SDavid van Moolenbroek 	}
2203*00b67f09SDavid van Moolenbroek 	if (*flagp & CFG_ADDR_V6OK) {
2204*00b67f09SDavid van Moolenbroek 		if (n != 0)
2205*00b67f09SDavid van Moolenbroek 			cfg_print_chars(pctx, " | ", 3);
2206*00b67f09SDavid van Moolenbroek 		cfg_print_cstr(pctx, "<ipv6_address>");
2207*00b67f09SDavid van Moolenbroek 		n++;
2208*00b67f09SDavid van Moolenbroek 	}
2209*00b67f09SDavid van Moolenbroek 	if (*flagp & CFG_ADDR_WILDOK) {
2210*00b67f09SDavid van Moolenbroek 		if (n != 0)
2211*00b67f09SDavid van Moolenbroek 			cfg_print_chars(pctx, " | ", 3);
2212*00b67f09SDavid van Moolenbroek 		cfg_print_chars(pctx, "*", 1);
2213*00b67f09SDavid van Moolenbroek 		n++;
2214*00b67f09SDavid van Moolenbroek 		POST(n);
2215*00b67f09SDavid van Moolenbroek 	}
2216*00b67f09SDavid van Moolenbroek 	cfg_print_chars(pctx, " ) ", 3);
2217*00b67f09SDavid van Moolenbroek 	if (*flagp & CFG_ADDR_WILDOK) {
2218*00b67f09SDavid van Moolenbroek 		cfg_print_cstr(pctx, "[ port ( <integer> | * ) ]");
2219*00b67f09SDavid van Moolenbroek 	} else {
2220*00b67f09SDavid van Moolenbroek 		cfg_print_cstr(pctx, "[ port <integer> ]");
2221*00b67f09SDavid van Moolenbroek 	}
2222*00b67f09SDavid van Moolenbroek 	if ((*flagp & CFG_ADDR_DSCPOK) != 0) {
2223*00b67f09SDavid van Moolenbroek 		cfg_print_cstr(pctx, " [ dscp <integer> ]");
2224*00b67f09SDavid van Moolenbroek 	}
2225*00b67f09SDavid van Moolenbroek }
2226*00b67f09SDavid van Moolenbroek 
2227*00b67f09SDavid van Moolenbroek isc_boolean_t
cfg_obj_issockaddr(const cfg_obj_t * obj)2228*00b67f09SDavid van Moolenbroek cfg_obj_issockaddr(const cfg_obj_t *obj) {
2229*00b67f09SDavid van Moolenbroek 	REQUIRE(obj != NULL);
2230*00b67f09SDavid van Moolenbroek 	return (ISC_TF(obj->type->rep == &cfg_rep_sockaddr));
2231*00b67f09SDavid van Moolenbroek }
2232*00b67f09SDavid van Moolenbroek 
2233*00b67f09SDavid van Moolenbroek const isc_sockaddr_t *
cfg_obj_assockaddr(const cfg_obj_t * obj)2234*00b67f09SDavid van Moolenbroek cfg_obj_assockaddr(const cfg_obj_t *obj) {
2235*00b67f09SDavid van Moolenbroek 	REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr);
2236*00b67f09SDavid van Moolenbroek 	return (&obj->value.sockaddr);
2237*00b67f09SDavid van Moolenbroek }
2238*00b67f09SDavid van Moolenbroek 
2239*00b67f09SDavid van Moolenbroek isc_dscp_t
cfg_obj_getdscp(const cfg_obj_t * obj)2240*00b67f09SDavid van Moolenbroek cfg_obj_getdscp(const cfg_obj_t *obj) {
2241*00b67f09SDavid van Moolenbroek 	REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr);
2242*00b67f09SDavid van Moolenbroek 	return (obj->value.sockaddrdscp.dscp);
2243*00b67f09SDavid van Moolenbroek }
2244*00b67f09SDavid van Moolenbroek 
2245*00b67f09SDavid van Moolenbroek isc_result_t
cfg_gettoken(cfg_parser_t * pctx,int options)2246*00b67f09SDavid van Moolenbroek cfg_gettoken(cfg_parser_t *pctx, int options) {
2247*00b67f09SDavid van Moolenbroek 	isc_result_t result;
2248*00b67f09SDavid van Moolenbroek 
2249*00b67f09SDavid van Moolenbroek 	if (pctx->seen_eof)
2250*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
2251*00b67f09SDavid van Moolenbroek 
2252*00b67f09SDavid van Moolenbroek 	options |= (ISC_LEXOPT_EOF | ISC_LEXOPT_NOMORE);
2253*00b67f09SDavid van Moolenbroek 
2254*00b67f09SDavid van Moolenbroek  redo:
2255*00b67f09SDavid van Moolenbroek 	pctx->token.type = isc_tokentype_unknown;
2256*00b67f09SDavid van Moolenbroek 	result = isc_lex_gettoken(pctx->lexer, options, &pctx->token);
2257*00b67f09SDavid van Moolenbroek 	pctx->ungotten = ISC_FALSE;
2258*00b67f09SDavid van Moolenbroek 	pctx->line = isc_lex_getsourceline(pctx->lexer);
2259*00b67f09SDavid van Moolenbroek 
2260*00b67f09SDavid van Moolenbroek 	switch (result) {
2261*00b67f09SDavid van Moolenbroek 	case ISC_R_SUCCESS:
2262*00b67f09SDavid van Moolenbroek 		if (pctx->token.type == isc_tokentype_eof) {
2263*00b67f09SDavid van Moolenbroek 			result = isc_lex_close(pctx->lexer);
2264*00b67f09SDavid van Moolenbroek 			INSIST(result == ISC_R_NOMORE ||
2265*00b67f09SDavid van Moolenbroek 			       result == ISC_R_SUCCESS);
2266*00b67f09SDavid van Moolenbroek 
2267*00b67f09SDavid van Moolenbroek 			if (isc_lex_getsourcename(pctx->lexer) != NULL) {
2268*00b67f09SDavid van Moolenbroek 				/*
2269*00b67f09SDavid van Moolenbroek 				 * Closed an included file, not the main file.
2270*00b67f09SDavid van Moolenbroek 				 */
2271*00b67f09SDavid van Moolenbroek 				cfg_listelt_t *elt;
2272*00b67f09SDavid van Moolenbroek 				elt = ISC_LIST_TAIL(pctx->open_files->
2273*00b67f09SDavid van Moolenbroek 						    value.list);
2274*00b67f09SDavid van Moolenbroek 				INSIST(elt != NULL);
2275*00b67f09SDavid van Moolenbroek 				ISC_LIST_UNLINK(pctx->open_files->
2276*00b67f09SDavid van Moolenbroek 						value.list, elt, link);
2277*00b67f09SDavid van Moolenbroek 				ISC_LIST_APPEND(pctx->closed_files->
2278*00b67f09SDavid van Moolenbroek 						value.list, elt, link);
2279*00b67f09SDavid van Moolenbroek 				goto redo;
2280*00b67f09SDavid van Moolenbroek 			}
2281*00b67f09SDavid van Moolenbroek 			pctx->seen_eof = ISC_TRUE;
2282*00b67f09SDavid van Moolenbroek 		}
2283*00b67f09SDavid van Moolenbroek 		break;
2284*00b67f09SDavid van Moolenbroek 
2285*00b67f09SDavid van Moolenbroek 	case ISC_R_NOSPACE:
2286*00b67f09SDavid van Moolenbroek 		/* More understandable than "ran out of space". */
2287*00b67f09SDavid van Moolenbroek 		cfg_parser_error(pctx, CFG_LOG_NEAR, "token too big");
2288*00b67f09SDavid van Moolenbroek 		break;
2289*00b67f09SDavid van Moolenbroek 
2290*00b67f09SDavid van Moolenbroek 	case ISC_R_IOERROR:
2291*00b67f09SDavid van Moolenbroek 		cfg_parser_error(pctx, 0, "%s",
2292*00b67f09SDavid van Moolenbroek 				 isc_result_totext(result));
2293*00b67f09SDavid van Moolenbroek 		break;
2294*00b67f09SDavid van Moolenbroek 
2295*00b67f09SDavid van Moolenbroek 	default:
2296*00b67f09SDavid van Moolenbroek 		cfg_parser_error(pctx, CFG_LOG_NEAR, "%s",
2297*00b67f09SDavid van Moolenbroek 				 isc_result_totext(result));
2298*00b67f09SDavid van Moolenbroek 		break;
2299*00b67f09SDavid van Moolenbroek 	}
2300*00b67f09SDavid van Moolenbroek 	return (result);
2301*00b67f09SDavid van Moolenbroek }
2302*00b67f09SDavid van Moolenbroek 
2303*00b67f09SDavid van Moolenbroek void
cfg_ungettoken(cfg_parser_t * pctx)2304*00b67f09SDavid van Moolenbroek cfg_ungettoken(cfg_parser_t *pctx) {
2305*00b67f09SDavid van Moolenbroek 	if (pctx->seen_eof)
2306*00b67f09SDavid van Moolenbroek 		return;
2307*00b67f09SDavid van Moolenbroek 	isc_lex_ungettoken(pctx->lexer, &pctx->token);
2308*00b67f09SDavid van Moolenbroek 	pctx->ungotten = ISC_TRUE;
2309*00b67f09SDavid van Moolenbroek }
2310*00b67f09SDavid van Moolenbroek 
2311*00b67f09SDavid van Moolenbroek isc_result_t
cfg_peektoken(cfg_parser_t * pctx,int options)2312*00b67f09SDavid van Moolenbroek cfg_peektoken(cfg_parser_t *pctx, int options) {
2313*00b67f09SDavid van Moolenbroek 	isc_result_t result;
2314*00b67f09SDavid van Moolenbroek 	CHECK(cfg_gettoken(pctx, options));
2315*00b67f09SDavid van Moolenbroek 	cfg_ungettoken(pctx);
2316*00b67f09SDavid van Moolenbroek  cleanup:
2317*00b67f09SDavid van Moolenbroek 	return (result);
2318*00b67f09SDavid van Moolenbroek }
2319*00b67f09SDavid van Moolenbroek 
2320*00b67f09SDavid van Moolenbroek /*
2321*00b67f09SDavid van Moolenbroek  * Get a string token, accepting both the quoted and the unquoted form.
2322*00b67f09SDavid van Moolenbroek  * Log an error if the next token is not a string.
2323*00b67f09SDavid van Moolenbroek  */
2324*00b67f09SDavid van Moolenbroek static isc_result_t
cfg_getstringtoken(cfg_parser_t * pctx)2325*00b67f09SDavid van Moolenbroek cfg_getstringtoken(cfg_parser_t *pctx) {
2326*00b67f09SDavid van Moolenbroek 	isc_result_t result;
2327*00b67f09SDavid van Moolenbroek 
2328*00b67f09SDavid van Moolenbroek 	result = cfg_gettoken(pctx, CFG_LEXOPT_QSTRING);
2329*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
2330*00b67f09SDavid van Moolenbroek 		return (result);
2331*00b67f09SDavid van Moolenbroek 
2332*00b67f09SDavid van Moolenbroek 	if (pctx->token.type != isc_tokentype_string &&
2333*00b67f09SDavid van Moolenbroek 	    pctx->token.type != isc_tokentype_qstring) {
2334*00b67f09SDavid van Moolenbroek 		cfg_parser_error(pctx, CFG_LOG_NEAR, "expected string");
2335*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTEDTOKEN);
2336*00b67f09SDavid van Moolenbroek 	}
2337*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
2338*00b67f09SDavid van Moolenbroek }
2339*00b67f09SDavid van Moolenbroek 
2340*00b67f09SDavid van Moolenbroek void
cfg_parser_error(cfg_parser_t * pctx,unsigned int flags,const char * fmt,...)2341*00b67f09SDavid van Moolenbroek cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) {
2342*00b67f09SDavid van Moolenbroek 	va_list args;
2343*00b67f09SDavid van Moolenbroek 	va_start(args, fmt);
2344*00b67f09SDavid van Moolenbroek 	parser_complain(pctx, ISC_FALSE, flags, fmt, args);
2345*00b67f09SDavid van Moolenbroek 	va_end(args);
2346*00b67f09SDavid van Moolenbroek 	pctx->errors++;
2347*00b67f09SDavid van Moolenbroek }
2348*00b67f09SDavid van Moolenbroek 
2349*00b67f09SDavid van Moolenbroek void
cfg_parser_warning(cfg_parser_t * pctx,unsigned int flags,const char * fmt,...)2350*00b67f09SDavid van Moolenbroek cfg_parser_warning(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) {
2351*00b67f09SDavid van Moolenbroek 	va_list args;
2352*00b67f09SDavid van Moolenbroek 	va_start(args, fmt);
2353*00b67f09SDavid van Moolenbroek 	parser_complain(pctx, ISC_TRUE, flags, fmt, args);
2354*00b67f09SDavid van Moolenbroek 	va_end(args);
2355*00b67f09SDavid van Moolenbroek 	pctx->warnings++;
2356*00b67f09SDavid van Moolenbroek }
2357*00b67f09SDavid van Moolenbroek 
2358*00b67f09SDavid van Moolenbroek #define MAX_LOG_TOKEN 30 /* How much of a token to quote in log messages. */
2359*00b67f09SDavid van Moolenbroek 
2360*00b67f09SDavid van Moolenbroek static isc_boolean_t
have_current_file(cfg_parser_t * pctx)2361*00b67f09SDavid van Moolenbroek have_current_file(cfg_parser_t *pctx) {
2362*00b67f09SDavid van Moolenbroek 	cfg_listelt_t *elt;
2363*00b67f09SDavid van Moolenbroek 	if (pctx->open_files == NULL)
2364*00b67f09SDavid van Moolenbroek 		return (ISC_FALSE);
2365*00b67f09SDavid van Moolenbroek 
2366*00b67f09SDavid van Moolenbroek 	elt = ISC_LIST_TAIL(pctx->open_files->value.list);
2367*00b67f09SDavid van Moolenbroek 	if (elt == NULL)
2368*00b67f09SDavid van Moolenbroek 	      return (ISC_FALSE);
2369*00b67f09SDavid van Moolenbroek 
2370*00b67f09SDavid van Moolenbroek 	return (ISC_TRUE);
2371*00b67f09SDavid van Moolenbroek }
2372*00b67f09SDavid van Moolenbroek 
2373*00b67f09SDavid van Moolenbroek static char *
current_file(cfg_parser_t * pctx)2374*00b67f09SDavid van Moolenbroek current_file(cfg_parser_t *pctx) {
2375*00b67f09SDavid van Moolenbroek 	static char none[] = "none";
2376*00b67f09SDavid van Moolenbroek 	cfg_listelt_t *elt;
2377*00b67f09SDavid van Moolenbroek 	cfg_obj_t *fileobj;
2378*00b67f09SDavid van Moolenbroek 
2379*00b67f09SDavid van Moolenbroek 	if (!have_current_file(pctx))
2380*00b67f09SDavid van Moolenbroek 		return (none);
2381*00b67f09SDavid van Moolenbroek 
2382*00b67f09SDavid van Moolenbroek 	elt = ISC_LIST_TAIL(pctx->open_files->value.list);
2383*00b67f09SDavid van Moolenbroek 	if (elt == NULL)	/* shouldn't be possible, but... */
2384*00b67f09SDavid van Moolenbroek 	      return (none);
2385*00b67f09SDavid van Moolenbroek 
2386*00b67f09SDavid van Moolenbroek 	fileobj = elt->obj;
2387*00b67f09SDavid van Moolenbroek 	INSIST(fileobj->type == &cfg_type_qstring);
2388*00b67f09SDavid van Moolenbroek 	return (fileobj->value.string.base);
2389*00b67f09SDavid van Moolenbroek }
2390*00b67f09SDavid van Moolenbroek 
2391*00b67f09SDavid van Moolenbroek static void
parser_complain(cfg_parser_t * pctx,isc_boolean_t is_warning,unsigned int flags,const char * format,va_list args)2392*00b67f09SDavid van Moolenbroek parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning,
2393*00b67f09SDavid van Moolenbroek 		unsigned int flags, const char *format,
2394*00b67f09SDavid van Moolenbroek 		va_list args)
2395*00b67f09SDavid van Moolenbroek {
2396*00b67f09SDavid van Moolenbroek 	char tokenbuf[MAX_LOG_TOKEN + 10];
2397*00b67f09SDavid van Moolenbroek 	static char where[ISC_DIR_PATHMAX + 100];
2398*00b67f09SDavid van Moolenbroek 	static char message[2048];
2399*00b67f09SDavid van Moolenbroek 	int level = ISC_LOG_ERROR;
2400*00b67f09SDavid van Moolenbroek 	const char *prep = "";
2401*00b67f09SDavid van Moolenbroek 	size_t len;
2402*00b67f09SDavid van Moolenbroek 
2403*00b67f09SDavid van Moolenbroek 	if (is_warning)
2404*00b67f09SDavid van Moolenbroek 		level = ISC_LOG_WARNING;
2405*00b67f09SDavid van Moolenbroek 
2406*00b67f09SDavid van Moolenbroek 	where[0] = '\0';
2407*00b67f09SDavid van Moolenbroek 	if (have_current_file(pctx))
2408*00b67f09SDavid van Moolenbroek 		snprintf(where, sizeof(where), "%s:%u: ",
2409*00b67f09SDavid van Moolenbroek 			 current_file(pctx), pctx->line);
2410*00b67f09SDavid van Moolenbroek 
2411*00b67f09SDavid van Moolenbroek 	len = vsnprintf(message, sizeof(message), format, args);
2412*00b67f09SDavid van Moolenbroek 	if (len >= sizeof(message))
2413*00b67f09SDavid van Moolenbroek 		FATAL_ERROR(__FILE__, __LINE__,
2414*00b67f09SDavid van Moolenbroek 			    "error message would overflow");
2415*00b67f09SDavid van Moolenbroek 
2416*00b67f09SDavid van Moolenbroek 	if ((flags & (CFG_LOG_NEAR|CFG_LOG_BEFORE|CFG_LOG_NOPREP)) != 0) {
2417*00b67f09SDavid van Moolenbroek 		isc_region_t r;
2418*00b67f09SDavid van Moolenbroek 
2419*00b67f09SDavid van Moolenbroek 		if (pctx->ungotten)
2420*00b67f09SDavid van Moolenbroek 			(void)cfg_gettoken(pctx, 0);
2421*00b67f09SDavid van Moolenbroek 
2422*00b67f09SDavid van Moolenbroek 		if (pctx->token.type == isc_tokentype_eof) {
2423*00b67f09SDavid van Moolenbroek 			snprintf(tokenbuf, sizeof(tokenbuf), "end of file");
2424*00b67f09SDavid van Moolenbroek 		} else if (pctx->token.type == isc_tokentype_unknown) {
2425*00b67f09SDavid van Moolenbroek 			flags = 0;
2426*00b67f09SDavid van Moolenbroek 			tokenbuf[0] = '\0';
2427*00b67f09SDavid van Moolenbroek 		} else {
2428*00b67f09SDavid van Moolenbroek 			isc_lex_getlasttokentext(pctx->lexer,
2429*00b67f09SDavid van Moolenbroek 						 &pctx->token, &r);
2430*00b67f09SDavid van Moolenbroek 			if (r.length > MAX_LOG_TOKEN)
2431*00b67f09SDavid van Moolenbroek 				snprintf(tokenbuf, sizeof(tokenbuf),
2432*00b67f09SDavid van Moolenbroek 					 "'%.*s...'", MAX_LOG_TOKEN, r.base);
2433*00b67f09SDavid van Moolenbroek 			else
2434*00b67f09SDavid van Moolenbroek 				snprintf(tokenbuf, sizeof(tokenbuf),
2435*00b67f09SDavid van Moolenbroek 					 "'%.*s'", (int)r.length, r.base);
2436*00b67f09SDavid van Moolenbroek 		}
2437*00b67f09SDavid van Moolenbroek 
2438*00b67f09SDavid van Moolenbroek 		/* Choose a preposition. */
2439*00b67f09SDavid van Moolenbroek 		if (flags & CFG_LOG_NEAR)
2440*00b67f09SDavid van Moolenbroek 			prep = " near ";
2441*00b67f09SDavid van Moolenbroek 		else if (flags & CFG_LOG_BEFORE)
2442*00b67f09SDavid van Moolenbroek 			prep = " before ";
2443*00b67f09SDavid van Moolenbroek 		else
2444*00b67f09SDavid van Moolenbroek 			prep = " ";
2445*00b67f09SDavid van Moolenbroek 	} else {
2446*00b67f09SDavid van Moolenbroek 		tokenbuf[0] = '\0';
2447*00b67f09SDavid van Moolenbroek 	}
2448*00b67f09SDavid van Moolenbroek 	isc_log_write(pctx->lctx, CAT, MOD, level,
2449*00b67f09SDavid van Moolenbroek 		      "%s%s%s%s", where, message, prep, tokenbuf);
2450*00b67f09SDavid van Moolenbroek }
2451*00b67f09SDavid van Moolenbroek 
2452*00b67f09SDavid van Moolenbroek void
cfg_obj_log(const cfg_obj_t * obj,isc_log_t * lctx,int level,const char * fmt,...)2453*00b67f09SDavid van Moolenbroek cfg_obj_log(const cfg_obj_t *obj, isc_log_t *lctx, int level,
2454*00b67f09SDavid van Moolenbroek 	    const char *fmt, ...) {
2455*00b67f09SDavid van Moolenbroek 	va_list ap;
2456*00b67f09SDavid van Moolenbroek 	char msgbuf[2048];
2457*00b67f09SDavid van Moolenbroek 
2458*00b67f09SDavid van Moolenbroek 	if (! isc_log_wouldlog(lctx, level))
2459*00b67f09SDavid van Moolenbroek 		return;
2460*00b67f09SDavid van Moolenbroek 
2461*00b67f09SDavid van Moolenbroek 	va_start(ap, fmt);
2462*00b67f09SDavid van Moolenbroek 
2463*00b67f09SDavid van Moolenbroek 	vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
2464*00b67f09SDavid van Moolenbroek 	isc_log_write(lctx, CAT, MOD, level,
2465*00b67f09SDavid van Moolenbroek 		      "%s:%u: %s",
2466*00b67f09SDavid van Moolenbroek 		      obj->file == NULL ? "<unknown file>" : obj->file,
2467*00b67f09SDavid van Moolenbroek 		      obj->line, msgbuf);
2468*00b67f09SDavid van Moolenbroek 	va_end(ap);
2469*00b67f09SDavid van Moolenbroek }
2470*00b67f09SDavid van Moolenbroek 
2471*00b67f09SDavid van Moolenbroek const char *
cfg_obj_file(const cfg_obj_t * obj)2472*00b67f09SDavid van Moolenbroek cfg_obj_file(const cfg_obj_t *obj) {
2473*00b67f09SDavid van Moolenbroek 	return (obj->file);
2474*00b67f09SDavid van Moolenbroek }
2475*00b67f09SDavid van Moolenbroek 
2476*00b67f09SDavid van Moolenbroek unsigned int
cfg_obj_line(const cfg_obj_t * obj)2477*00b67f09SDavid van Moolenbroek cfg_obj_line(const cfg_obj_t *obj) {
2478*00b67f09SDavid van Moolenbroek 	return (obj->line);
2479*00b67f09SDavid van Moolenbroek }
2480*00b67f09SDavid van Moolenbroek 
2481*00b67f09SDavid van Moolenbroek isc_result_t
cfg_create_obj(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)2482*00b67f09SDavid van Moolenbroek cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
2483*00b67f09SDavid van Moolenbroek 	isc_result_t result;
2484*00b67f09SDavid van Moolenbroek 	cfg_obj_t *obj;
2485*00b67f09SDavid van Moolenbroek 
2486*00b67f09SDavid van Moolenbroek 	obj = isc_mem_get(pctx->mctx, sizeof(cfg_obj_t));
2487*00b67f09SDavid van Moolenbroek 	if (obj == NULL)
2488*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
2489*00b67f09SDavid van Moolenbroek 	obj->type = type;
2490*00b67f09SDavid van Moolenbroek 	obj->file = current_file(pctx);
2491*00b67f09SDavid van Moolenbroek 	obj->line = pctx->line;
2492*00b67f09SDavid van Moolenbroek 	result = isc_refcount_init(&obj->references, 1);
2493*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
2494*00b67f09SDavid van Moolenbroek 		isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t));
2495*00b67f09SDavid van Moolenbroek 		return (result);
2496*00b67f09SDavid van Moolenbroek 	}
2497*00b67f09SDavid van Moolenbroek 	*ret = obj;
2498*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
2499*00b67f09SDavid van Moolenbroek }
2500*00b67f09SDavid van Moolenbroek 
2501*00b67f09SDavid van Moolenbroek 
2502*00b67f09SDavid van Moolenbroek static void
map_symtabitem_destroy(char * key,unsigned int type,isc_symvalue_t symval,void * userarg)2503*00b67f09SDavid van Moolenbroek map_symtabitem_destroy(char *key, unsigned int type,
2504*00b67f09SDavid van Moolenbroek 		       isc_symvalue_t symval, void *userarg)
2505*00b67f09SDavid van Moolenbroek {
2506*00b67f09SDavid van Moolenbroek 	cfg_obj_t *obj = symval.as_pointer;
2507*00b67f09SDavid van Moolenbroek 	cfg_parser_t *pctx = (cfg_parser_t *)userarg;
2508*00b67f09SDavid van Moolenbroek 
2509*00b67f09SDavid van Moolenbroek 	UNUSED(key);
2510*00b67f09SDavid van Moolenbroek 	UNUSED(type);
2511*00b67f09SDavid van Moolenbroek 
2512*00b67f09SDavid van Moolenbroek 	cfg_obj_destroy(pctx, &obj);
2513*00b67f09SDavid van Moolenbroek }
2514*00b67f09SDavid van Moolenbroek 
2515*00b67f09SDavid van Moolenbroek 
2516*00b67f09SDavid van Moolenbroek static isc_result_t
create_map(cfg_parser_t * pctx,const cfg_type_t * type,cfg_obj_t ** ret)2517*00b67f09SDavid van Moolenbroek create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
2518*00b67f09SDavid van Moolenbroek 	isc_result_t result;
2519*00b67f09SDavid van Moolenbroek 	isc_symtab_t *symtab = NULL;
2520*00b67f09SDavid van Moolenbroek 	cfg_obj_t *obj = NULL;
2521*00b67f09SDavid van Moolenbroek 
2522*00b67f09SDavid van Moolenbroek 	CHECK(cfg_create_obj(pctx, type, &obj));
2523*00b67f09SDavid van Moolenbroek 	CHECK(isc_symtab_create(pctx->mctx, 5, /* XXX */
2524*00b67f09SDavid van Moolenbroek 				map_symtabitem_destroy,
2525*00b67f09SDavid van Moolenbroek 				pctx, ISC_FALSE, &symtab));
2526*00b67f09SDavid van Moolenbroek 	obj->value.map.symtab = symtab;
2527*00b67f09SDavid van Moolenbroek 	obj->value.map.id = NULL;
2528*00b67f09SDavid van Moolenbroek 
2529*00b67f09SDavid van Moolenbroek 	*ret = obj;
2530*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
2531*00b67f09SDavid van Moolenbroek 
2532*00b67f09SDavid van Moolenbroek  cleanup:
2533*00b67f09SDavid van Moolenbroek 	if (obj != NULL)
2534*00b67f09SDavid van Moolenbroek 		isc_mem_put(pctx->mctx, obj, sizeof(*obj));
2535*00b67f09SDavid van Moolenbroek 	return (result);
2536*00b67f09SDavid van Moolenbroek }
2537*00b67f09SDavid van Moolenbroek 
2538*00b67f09SDavid van Moolenbroek static void
free_map(cfg_parser_t * pctx,cfg_obj_t * obj)2539*00b67f09SDavid van Moolenbroek free_map(cfg_parser_t *pctx, cfg_obj_t *obj) {
2540*00b67f09SDavid van Moolenbroek 	CLEANUP_OBJ(obj->value.map.id);
2541*00b67f09SDavid van Moolenbroek 	isc_symtab_destroy(&obj->value.map.symtab);
2542*00b67f09SDavid van Moolenbroek }
2543*00b67f09SDavid van Moolenbroek 
2544*00b67f09SDavid van Moolenbroek isc_boolean_t
cfg_obj_istype(const cfg_obj_t * obj,const cfg_type_t * type)2545*00b67f09SDavid van Moolenbroek cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type) {
2546*00b67f09SDavid van Moolenbroek 	return (ISC_TF(obj->type == type));
2547*00b67f09SDavid van Moolenbroek }
2548*00b67f09SDavid van Moolenbroek 
2549*00b67f09SDavid van Moolenbroek /*
2550*00b67f09SDavid van Moolenbroek  * Destroy 'obj', a configuration object created in 'pctx'.
2551*00b67f09SDavid van Moolenbroek  */
2552*00b67f09SDavid van Moolenbroek void
cfg_obj_destroy(cfg_parser_t * pctx,cfg_obj_t ** objp)2553*00b67f09SDavid van Moolenbroek cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **objp) {
2554*00b67f09SDavid van Moolenbroek 	cfg_obj_t *obj;
2555*00b67f09SDavid van Moolenbroek 	unsigned int refs;
2556*00b67f09SDavid van Moolenbroek 
2557*00b67f09SDavid van Moolenbroek 	REQUIRE(objp != NULL && *objp != NULL);
2558*00b67f09SDavid van Moolenbroek 	REQUIRE(pctx != NULL);
2559*00b67f09SDavid van Moolenbroek 
2560*00b67f09SDavid van Moolenbroek 	obj = *objp;
2561*00b67f09SDavid van Moolenbroek 
2562*00b67f09SDavid van Moolenbroek 	isc_refcount_decrement(&obj->references, &refs);
2563*00b67f09SDavid van Moolenbroek 	if (refs == 0) {
2564*00b67f09SDavid van Moolenbroek 		obj->type->rep->free(pctx, obj);
2565*00b67f09SDavid van Moolenbroek 		isc_refcount_destroy(&obj->references);
2566*00b67f09SDavid van Moolenbroek 		isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t));
2567*00b67f09SDavid van Moolenbroek 	}
2568*00b67f09SDavid van Moolenbroek 	*objp = NULL;
2569*00b67f09SDavid van Moolenbroek }
2570*00b67f09SDavid van Moolenbroek 
2571*00b67f09SDavid van Moolenbroek void
cfg_obj_attach(cfg_obj_t * src,cfg_obj_t ** dest)2572*00b67f09SDavid van Moolenbroek cfg_obj_attach(cfg_obj_t *src, cfg_obj_t **dest) {
2573*00b67f09SDavid van Moolenbroek     REQUIRE(src != NULL);
2574*00b67f09SDavid van Moolenbroek     REQUIRE(dest != NULL && *dest == NULL);
2575*00b67f09SDavid van Moolenbroek     isc_refcount_increment(&src->references, NULL);
2576*00b67f09SDavid van Moolenbroek     *dest = src;
2577*00b67f09SDavid van Moolenbroek }
2578*00b67f09SDavid van Moolenbroek 
2579*00b67f09SDavid van Moolenbroek static void
free_noop(cfg_parser_t * pctx,cfg_obj_t * obj)2580*00b67f09SDavid van Moolenbroek free_noop(cfg_parser_t *pctx, cfg_obj_t *obj) {
2581*00b67f09SDavid van Moolenbroek 	UNUSED(pctx);
2582*00b67f09SDavid van Moolenbroek 	UNUSED(obj);
2583*00b67f09SDavid van Moolenbroek }
2584*00b67f09SDavid van Moolenbroek 
2585*00b67f09SDavid van Moolenbroek void
cfg_doc_obj(cfg_printer_t * pctx,const cfg_type_t * type)2586*00b67f09SDavid van Moolenbroek cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type) {
2587*00b67f09SDavid van Moolenbroek 	type->doc(pctx, type);
2588*00b67f09SDavid van Moolenbroek }
2589*00b67f09SDavid van Moolenbroek 
2590*00b67f09SDavid van Moolenbroek void
cfg_doc_terminal(cfg_printer_t * pctx,const cfg_type_t * type)2591*00b67f09SDavid van Moolenbroek cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type) {
2592*00b67f09SDavid van Moolenbroek 	cfg_print_chars(pctx, "<", 1);
2593*00b67f09SDavid van Moolenbroek 	cfg_print_cstr(pctx, type->name);
2594*00b67f09SDavid van Moolenbroek 	cfg_print_chars(pctx, ">", 1);
2595*00b67f09SDavid van Moolenbroek }
2596*00b67f09SDavid van Moolenbroek 
2597*00b67f09SDavid van Moolenbroek void
cfg_print_grammar(const cfg_type_t * type,void (* f)(void * closure,const char * text,int textlen),void * closure)2598*00b67f09SDavid van Moolenbroek cfg_print_grammar(const cfg_type_t *type,
2599*00b67f09SDavid van Moolenbroek 	void (*f)(void *closure, const char *text, int textlen),
2600*00b67f09SDavid van Moolenbroek 	void *closure)
2601*00b67f09SDavid van Moolenbroek {
2602*00b67f09SDavid van Moolenbroek 	cfg_printer_t pctx;
2603*00b67f09SDavid van Moolenbroek 	pctx.f = f;
2604*00b67f09SDavid van Moolenbroek 	pctx.closure = closure;
2605*00b67f09SDavid van Moolenbroek 	pctx.indent = 0;
2606*00b67f09SDavid van Moolenbroek 	pctx.flags = 0;
2607*00b67f09SDavid van Moolenbroek 	cfg_doc_obj(&pctx, type);
2608*00b67f09SDavid van Moolenbroek }
2609