1238106Sdes%{
2238106Sdes/*
3238106Sdes * configlexer.lex - lexical analyzer for unbound config file
4238106Sdes *
5238106Sdes * Copyright (c) 2001-2006, NLnet Labs. All rights reserved
6238106Sdes *
7238106Sdes * See LICENSE for the license.
8238106Sdes *
9238106Sdes */
10238106Sdes
11269257Sdes#include "config.h"
12269257Sdes
13238106Sdes#include <ctype.h>
14238106Sdes#include <string.h>
15238106Sdes#include <strings.h>
16249141Sdes#ifdef HAVE_GLOB_H
17249141Sdes# include <glob.h>
18249141Sdes#endif
19238106Sdes
20238106Sdes#include "util/config_file.h"
21269257Sdes#include "configparser.h"
22238106Sdesvoid ub_c_error(const char *message);
23238106Sdes
24238106Sdes#if 0
25238106Sdes#define LEXOUT(s)  printf s /* used ONLY when debugging */
26238106Sdes#else
27238106Sdes#define LEXOUT(s)
28238106Sdes#endif
29238106Sdes
30238106Sdes/** avoid warning in about fwrite return value */
31269257Sdes#define ECHO ub_c_error_msg("syntax error at text: %s", ub_c_text)
32238106Sdes
33238106Sdes/** A parser variable, this is a statement in the config file which is
34238106Sdes * of the form variable: value1 value2 ...  nargs is the number of values. */
35238106Sdes#define YDVAR(nargs, var) \
36238106Sdes	num_args=(nargs); \
37269257Sdes	LEXOUT(("v(%s%d) ", ub_c_text, num_args)); \
38238106Sdes	if(num_args > 0) { BEGIN(val); } \
39238106Sdes	return (var);
40238106Sdes
41238106Sdesstruct inc_state {
42238106Sdes	char* filename;
43238106Sdes	int line;
44269257Sdes	YY_BUFFER_STATE buffer;
45269257Sdes	struct inc_state* next;
46238106Sdes};
47269257Sdesstatic struct inc_state* config_include_stack = NULL;
48269257Sdesstatic int inc_depth = 0;
49238106Sdesstatic int inc_prev = 0;
50238106Sdesstatic int num_args = 0;
51238106Sdes
52269257Sdesvoid init_cfg_parse(void)
53269257Sdes{
54269257Sdes	config_include_stack = NULL;
55269257Sdes	inc_depth = 0;
56269257Sdes	inc_prev = 0;
57269257Sdes	num_args = 0;
58269257Sdes}
59249141Sdes
60238106Sdesstatic void config_start_include(const char* filename)
61238106Sdes{
62238106Sdes	FILE *input;
63269257Sdes	struct inc_state* s;
64269257Sdes	char* nm;
65269257Sdes	if(inc_depth++ > 100000) {
66269257Sdes		ub_c_error_msg("too many include files");
67269257Sdes		return;
68269257Sdes	}
69238106Sdes	if(strlen(filename) == 0) {
70238106Sdes		ub_c_error_msg("empty include file name");
71238106Sdes		return;
72238106Sdes	}
73269257Sdes	s = (struct inc_state*)malloc(sizeof(*s));
74269257Sdes	if(!s) {
75269257Sdes		ub_c_error_msg("include %s: malloc failure", filename);
76238106Sdes		return;
77238106Sdes	}
78238106Sdes	if(cfg_parser->chroot && strncmp(filename, cfg_parser->chroot,
79238106Sdes		strlen(cfg_parser->chroot)) == 0) {
80238106Sdes		filename += strlen(cfg_parser->chroot);
81238106Sdes	}
82269257Sdes	nm = strdup(filename);
83269257Sdes	if(!nm) {
84269257Sdes		ub_c_error_msg("include %s: strdup failure", filename);
85269257Sdes		free(s);
86269257Sdes		return;
87269257Sdes	}
88238106Sdes	input = fopen(filename, "r");
89238106Sdes	if(!input) {
90238106Sdes		ub_c_error_msg("cannot open include file '%s': %s",
91238106Sdes			filename, strerror(errno));
92269257Sdes		free(s);
93269257Sdes		free(nm);
94238106Sdes		return;
95238106Sdes	}
96269257Sdes	LEXOUT(("switch_to_include_file(%s)\n", filename));
97269257Sdes	s->filename = cfg_parser->filename;
98269257Sdes	s->line = cfg_parser->line;
99269257Sdes	s->buffer = YY_CURRENT_BUFFER;
100269257Sdes	s->next = config_include_stack;
101269257Sdes	config_include_stack = s;
102269257Sdes	cfg_parser->filename = nm;
103238106Sdes	cfg_parser->line = 1;
104238106Sdes	yy_switch_to_buffer(yy_create_buffer(input, YY_BUF_SIZE));
105238106Sdes}
106238106Sdes
107249141Sdesstatic void config_start_include_glob(const char* filename)
108249141Sdes{
109249141Sdes
110249141Sdes	/* check for wildcards */
111249141Sdes#ifdef HAVE_GLOB
112249141Sdes	glob_t g;
113249141Sdes	size_t i;
114249141Sdes	int r, flags;
115249141Sdes	if(!(!strchr(filename, '*') && !strchr(filename, '?') && !strchr(filename, '[') &&
116249141Sdes		!strchr(filename, '{') && !strchr(filename, '~'))) {
117249141Sdes		flags = 0
118249141Sdes#ifdef GLOB_ERR
119249141Sdes			| GLOB_ERR
120249141Sdes#endif
121249141Sdes#ifdef GLOB_NOSORT
122249141Sdes			| GLOB_NOSORT
123249141Sdes#endif
124249141Sdes#ifdef GLOB_BRACE
125249141Sdes			| GLOB_BRACE
126249141Sdes#endif
127249141Sdes#ifdef GLOB_TILDE
128249141Sdes			| GLOB_TILDE
129249141Sdes#endif
130249141Sdes		;
131249141Sdes		memset(&g, 0, sizeof(g));
132249141Sdes		r = glob(filename, flags, NULL, &g);
133249141Sdes		if(r) {
134249141Sdes			/* some error */
135249141Sdes			globfree(&g);
136269257Sdes			if(r == GLOB_NOMATCH)
137269257Sdes				return; /* no matches for pattern */
138249141Sdes			config_start_include(filename); /* let original deal with it */
139249141Sdes			return;
140249141Sdes		}
141249141Sdes		/* process files found, if any */
142249141Sdes		for(i=0; i<(size_t)g.gl_pathc; i++) {
143249141Sdes			config_start_include(g.gl_pathv[i]);
144249141Sdes		}
145249141Sdes		globfree(&g);
146249141Sdes		return;
147249141Sdes	}
148249141Sdes#endif /* HAVE_GLOB */
149249141Sdes
150249141Sdes	config_start_include(filename);
151249141Sdes}
152249141Sdes
153238106Sdesstatic void config_end_include(void)
154238106Sdes{
155269257Sdes	struct inc_state* s = config_include_stack;
156269257Sdes	--inc_depth;
157269257Sdes	if(!s) return;
158238106Sdes	free(cfg_parser->filename);
159269257Sdes	cfg_parser->filename = s->filename;
160269257Sdes	cfg_parser->line = s->line;
161238106Sdes	yy_delete_buffer(YY_CURRENT_BUFFER);
162269257Sdes	yy_switch_to_buffer(s->buffer);
163269257Sdes	config_include_stack = s->next;
164269257Sdes	free(s);
165238106Sdes}
166238106Sdes
167238106Sdes#ifndef yy_set_bol /* compat definition, for flex 2.4.6 */
168238106Sdes#define yy_set_bol(at_bol) \
169238106Sdes        { \
170238106Sdes	        if ( ! yy_current_buffer ) \
171269257Sdes	                yy_current_buffer = yy_create_buffer( ub_c_in, YY_BUF_SIZE ); \
172238106Sdes	        yy_current_buffer->yy_ch_buf[0] = ((at_bol)?'\n':' '); \
173238106Sdes        }
174238106Sdes#endif
175238106Sdes
176238106Sdes%}
177238106Sdes%option noinput
178238106Sdes%option nounput
179238106Sdes%{
180238106Sdes#ifndef YY_NO_UNPUT
181238106Sdes#define YY_NO_UNPUT 1
182238106Sdes#endif
183238106Sdes#ifndef YY_NO_INPUT
184238106Sdes#define YY_NO_INPUT 1
185238106Sdes#endif
186238106Sdes%}
187238106Sdes
188238106SdesSPACE   [ \t]
189238106SdesLETTER  [a-zA-Z]
190238106SdesUNQUOTEDLETTER [^\'\"\n\r \t\\]|\\.
191238106SdesUNQUOTEDLETTER_NOCOLON [^\:\'\"\n\r \t\\]|\\.
192238106SdesNEWLINE [\r\n]
193238106SdesCOMMENT \#
194238106SdesCOLON 	\:
195238106SdesDQANY     [^\"\n\r\\]|\\.
196238106SdesSQANY     [^\'\n\r\\]|\\.
197238106Sdes
198238106Sdes%x	quotedstring singlequotedstr include include_quoted val
199238106Sdes
200238106Sdes%%
201238106Sdes<INITIAL,val>{SPACE}*	{
202238106Sdes	LEXOUT(("SP ")); /* ignore */ }
203238106Sdes<INITIAL,val>{SPACE}*{COMMENT}.*	{
204238106Sdes	/* note that flex makes the longest match and '.' is any but not nl */
205269257Sdes	LEXOUT(("comment(%s) ", ub_c_text)); /* ignore */ }
206238106Sdesserver{COLON}			{ YDVAR(0, VAR_SERVER) }
207238106Sdesnum-threads{COLON}		{ YDVAR(1, VAR_NUM_THREADS) }
208238106Sdesverbosity{COLON}		{ YDVAR(1, VAR_VERBOSITY) }
209238106Sdesport{COLON}			{ YDVAR(1, VAR_PORT) }
210238106Sdesoutgoing-range{COLON}		{ YDVAR(1, VAR_OUTGOING_RANGE) }
211238106Sdesoutgoing-port-permit{COLON}	{ YDVAR(1, VAR_OUTGOING_PORT_PERMIT) }
212238106Sdesoutgoing-port-avoid{COLON}	{ YDVAR(1, VAR_OUTGOING_PORT_AVOID) }
213238106Sdesoutgoing-num-tcp{COLON}		{ YDVAR(1, VAR_OUTGOING_NUM_TCP) }
214238106Sdesincoming-num-tcp{COLON}		{ YDVAR(1, VAR_INCOMING_NUM_TCP) }
215238106Sdesdo-ip4{COLON}			{ YDVAR(1, VAR_DO_IP4) }
216238106Sdesdo-ip6{COLON}			{ YDVAR(1, VAR_DO_IP6) }
217238106Sdesdo-udp{COLON}			{ YDVAR(1, VAR_DO_UDP) }
218238106Sdesdo-tcp{COLON}			{ YDVAR(1, VAR_DO_TCP) }
219238106Sdestcp-upstream{COLON}		{ YDVAR(1, VAR_TCP_UPSTREAM) }
220238106Sdesssl-upstream{COLON}		{ YDVAR(1, VAR_SSL_UPSTREAM) }
221238106Sdesssl-service-key{COLON}		{ YDVAR(1, VAR_SSL_SERVICE_KEY) }
222238106Sdesssl-service-pem{COLON}		{ YDVAR(1, VAR_SSL_SERVICE_PEM) }
223238106Sdesssl-port{COLON}			{ YDVAR(1, VAR_SSL_PORT) }
224238106Sdesdo-daemonize{COLON}		{ YDVAR(1, VAR_DO_DAEMONIZE) }
225238106Sdesinterface{COLON}		{ YDVAR(1, VAR_INTERFACE) }
226269257Sdesip-address{COLON}		{ YDVAR(1, VAR_INTERFACE) }
227238106Sdesoutgoing-interface{COLON}	{ YDVAR(1, VAR_OUTGOING_INTERFACE) }
228238106Sdesinterface-automatic{COLON}	{ YDVAR(1, VAR_INTERFACE_AUTOMATIC) }
229238106Sdesso-rcvbuf{COLON}		{ YDVAR(1, VAR_SO_RCVBUF) }
230238106Sdesso-sndbuf{COLON}		{ YDVAR(1, VAR_SO_SNDBUF) }
231269257Sdesso-reuseport{COLON}		{ YDVAR(1, VAR_SO_REUSEPORT) }
232238106Sdeschroot{COLON}			{ YDVAR(1, VAR_CHROOT) }
233238106Sdesusername{COLON}			{ YDVAR(1, VAR_USERNAME) }
234238106Sdesdirectory{COLON}		{ YDVAR(1, VAR_DIRECTORY) }
235238106Sdeslogfile{COLON}			{ YDVAR(1, VAR_LOGFILE) }
236238106Sdespidfile{COLON}			{ YDVAR(1, VAR_PIDFILE) }
237238106Sdesroot-hints{COLON}		{ YDVAR(1, VAR_ROOT_HINTS) }
238238106Sdesedns-buffer-size{COLON}		{ YDVAR(1, VAR_EDNS_BUFFER_SIZE) }
239238106Sdesmsg-buffer-size{COLON}		{ YDVAR(1, VAR_MSG_BUFFER_SIZE) }
240238106Sdesmsg-cache-size{COLON}		{ YDVAR(1, VAR_MSG_CACHE_SIZE) }
241238106Sdesmsg-cache-slabs{COLON}		{ YDVAR(1, VAR_MSG_CACHE_SLABS) }
242238106Sdesrrset-cache-size{COLON}		{ YDVAR(1, VAR_RRSET_CACHE_SIZE) }
243238106Sdesrrset-cache-slabs{COLON}	{ YDVAR(1, VAR_RRSET_CACHE_SLABS) }
244238106Sdescache-max-ttl{COLON}     	{ YDVAR(1, VAR_CACHE_MAX_TTL) }
245238106Sdescache-min-ttl{COLON}     	{ YDVAR(1, VAR_CACHE_MIN_TTL) }
246238106Sdesinfra-host-ttl{COLON}		{ YDVAR(1, VAR_INFRA_HOST_TTL) }
247238106Sdesinfra-lame-ttl{COLON}		{ YDVAR(1, VAR_INFRA_LAME_TTL) }
248238106Sdesinfra-cache-slabs{COLON}	{ YDVAR(1, VAR_INFRA_CACHE_SLABS) }
249238106Sdesinfra-cache-numhosts{COLON}	{ YDVAR(1, VAR_INFRA_CACHE_NUMHOSTS) }
250238106Sdesinfra-cache-lame-size{COLON}	{ YDVAR(1, VAR_INFRA_CACHE_LAME_SIZE) }
251238106Sdesnum-queries-per-thread{COLON}	{ YDVAR(1, VAR_NUM_QUERIES_PER_THREAD) }
252238106Sdesjostle-timeout{COLON}		{ YDVAR(1, VAR_JOSTLE_TIMEOUT) }
253269257Sdesdelay-close{COLON}		{ YDVAR(1, VAR_DELAY_CLOSE) }
254238106Sdestarget-fetch-policy{COLON}	{ YDVAR(1, VAR_TARGET_FETCH_POLICY) }
255238106Sdesharden-short-bufsize{COLON}	{ YDVAR(1, VAR_HARDEN_SHORT_BUFSIZE) }
256238106Sdesharden-large-queries{COLON}	{ YDVAR(1, VAR_HARDEN_LARGE_QUERIES) }
257238106Sdesharden-glue{COLON}		{ YDVAR(1, VAR_HARDEN_GLUE) }
258238106Sdesharden-dnssec-stripped{COLON}	{ YDVAR(1, VAR_HARDEN_DNSSEC_STRIPPED) }
259238106Sdesharden-below-nxdomain{COLON}	{ YDVAR(1, VAR_HARDEN_BELOW_NXDOMAIN) }
260238106Sdesharden-referral-path{COLON}	{ YDVAR(1, VAR_HARDEN_REFERRAL_PATH) }
261238106Sdesuse-caps-for-id{COLON}		{ YDVAR(1, VAR_USE_CAPS_FOR_ID) }
262238106Sdesunwanted-reply-threshold{COLON}	{ YDVAR(1, VAR_UNWANTED_REPLY_THRESHOLD) }
263238106Sdesprivate-address{COLON}		{ YDVAR(1, VAR_PRIVATE_ADDRESS) }
264238106Sdesprivate-domain{COLON}		{ YDVAR(1, VAR_PRIVATE_DOMAIN) }
265238106Sdesprefetch-key{COLON}		{ YDVAR(1, VAR_PREFETCH_KEY) }
266238106Sdesprefetch{COLON}			{ YDVAR(1, VAR_PREFETCH) }
267238106Sdesstub-zone{COLON}		{ YDVAR(0, VAR_STUB_ZONE) }
268238106Sdesname{COLON}			{ YDVAR(1, VAR_NAME) }
269238106Sdesstub-addr{COLON}		{ YDVAR(1, VAR_STUB_ADDR) }
270238106Sdesstub-host{COLON}		{ YDVAR(1, VAR_STUB_HOST) }
271238106Sdesstub-prime{COLON}		{ YDVAR(1, VAR_STUB_PRIME) }
272238106Sdesstub-first{COLON}		{ YDVAR(1, VAR_STUB_FIRST) }
273238106Sdesforward-zone{COLON}		{ YDVAR(0, VAR_FORWARD_ZONE) }
274238106Sdesforward-addr{COLON}		{ YDVAR(1, VAR_FORWARD_ADDR) }
275238106Sdesforward-host{COLON}		{ YDVAR(1, VAR_FORWARD_HOST) }
276238106Sdesforward-first{COLON}		{ YDVAR(1, VAR_FORWARD_FIRST) }
277238106Sdesdo-not-query-address{COLON}	{ YDVAR(1, VAR_DO_NOT_QUERY_ADDRESS) }
278238106Sdesdo-not-query-localhost{COLON}	{ YDVAR(1, VAR_DO_NOT_QUERY_LOCALHOST) }
279238106Sdesaccess-control{COLON}		{ YDVAR(2, VAR_ACCESS_CONTROL) }
280238106Sdeshide-identity{COLON}		{ YDVAR(1, VAR_HIDE_IDENTITY) }
281238106Sdeshide-version{COLON}		{ YDVAR(1, VAR_HIDE_VERSION) }
282238106Sdesidentity{COLON}			{ YDVAR(1, VAR_IDENTITY) }
283238106Sdesversion{COLON}			{ YDVAR(1, VAR_VERSION) }
284238106Sdesmodule-config{COLON}     	{ YDVAR(1, VAR_MODULE_CONF) }
285238106Sdesdlv-anchor{COLON}		{ YDVAR(1, VAR_DLV_ANCHOR) }
286238106Sdesdlv-anchor-file{COLON}		{ YDVAR(1, VAR_DLV_ANCHOR_FILE) }
287238106Sdestrust-anchor-file{COLON}	{ YDVAR(1, VAR_TRUST_ANCHOR_FILE) }
288238106Sdesauto-trust-anchor-file{COLON}	{ YDVAR(1, VAR_AUTO_TRUST_ANCHOR_FILE) }
289238106Sdestrusted-keys-file{COLON}	{ YDVAR(1, VAR_TRUSTED_KEYS_FILE) }
290238106Sdestrust-anchor{COLON}		{ YDVAR(1, VAR_TRUST_ANCHOR) }
291238106Sdesval-override-date{COLON}	{ YDVAR(1, VAR_VAL_OVERRIDE_DATE) }
292238106Sdesval-sig-skew-min{COLON}		{ YDVAR(1, VAR_VAL_SIG_SKEW_MIN) }
293238106Sdesval-sig-skew-max{COLON}		{ YDVAR(1, VAR_VAL_SIG_SKEW_MAX) }
294238106Sdesval-bogus-ttl{COLON}		{ YDVAR(1, VAR_BOGUS_TTL) }
295238106Sdesval-clean-additional{COLON}	{ YDVAR(1, VAR_VAL_CLEAN_ADDITIONAL) }
296238106Sdesval-permissive-mode{COLON}	{ YDVAR(1, VAR_VAL_PERMISSIVE_MODE) }
297238106Sdesignore-cd-flag{COLON}		{ YDVAR(1, VAR_IGNORE_CD_FLAG) }
298238106Sdesval-log-level{COLON}		{ YDVAR(1, VAR_VAL_LOG_LEVEL) }
299238106Sdeskey-cache-size{COLON}		{ YDVAR(1, VAR_KEY_CACHE_SIZE) }
300238106Sdeskey-cache-slabs{COLON}		{ YDVAR(1, VAR_KEY_CACHE_SLABS) }
301238106Sdesneg-cache-size{COLON}		{ YDVAR(1, VAR_NEG_CACHE_SIZE) }
302238106Sdesval-nsec3-keysize-iterations{COLON}	{
303238106Sdes				  YDVAR(1, VAR_VAL_NSEC3_KEYSIZE_ITERATIONS) }
304238106Sdesadd-holddown{COLON}		{ YDVAR(1, VAR_ADD_HOLDDOWN) }
305238106Sdesdel-holddown{COLON}		{ YDVAR(1, VAR_DEL_HOLDDOWN) }
306238106Sdeskeep-missing{COLON}		{ YDVAR(1, VAR_KEEP_MISSING) }
307238106Sdesuse-syslog{COLON}		{ YDVAR(1, VAR_USE_SYSLOG) }
308238106Sdeslog-time-ascii{COLON}		{ YDVAR(1, VAR_LOG_TIME_ASCII) }
309238106Sdeslog-queries{COLON}		{ YDVAR(1, VAR_LOG_QUERIES) }
310238106Sdeslocal-zone{COLON}		{ YDVAR(2, VAR_LOCAL_ZONE) }
311238106Sdeslocal-data{COLON}		{ YDVAR(1, VAR_LOCAL_DATA) }
312238106Sdeslocal-data-ptr{COLON}		{ YDVAR(1, VAR_LOCAL_DATA_PTR) }
313269257Sdesunblock-lan-zones{COLON}	{ YDVAR(1, VAR_UNBLOCK_LAN_ZONES) }
314238106Sdesstatistics-interval{COLON}	{ YDVAR(1, VAR_STATISTICS_INTERVAL) }
315238106Sdesstatistics-cumulative{COLON}	{ YDVAR(1, VAR_STATISTICS_CUMULATIVE) }
316238106Sdesextended-statistics{COLON}	{ YDVAR(1, VAR_EXTENDED_STATISTICS) }
317238106Sdesremote-control{COLON}		{ YDVAR(0, VAR_REMOTE_CONTROL) }
318238106Sdescontrol-enable{COLON}		{ YDVAR(1, VAR_CONTROL_ENABLE) }
319238106Sdescontrol-interface{COLON}	{ YDVAR(1, VAR_CONTROL_INTERFACE) }
320238106Sdescontrol-port{COLON}		{ YDVAR(1, VAR_CONTROL_PORT) }
321238106Sdesserver-key-file{COLON}		{ YDVAR(1, VAR_SERVER_KEY_FILE) }
322238106Sdesserver-cert-file{COLON}		{ YDVAR(1, VAR_SERVER_CERT_FILE) }
323238106Sdescontrol-key-file{COLON}		{ YDVAR(1, VAR_CONTROL_KEY_FILE) }
324238106Sdescontrol-cert-file{COLON}	{ YDVAR(1, VAR_CONTROL_CERT_FILE) }
325238106Sdespython-script{COLON}		{ YDVAR(1, VAR_PYTHON_SCRIPT) }
326238106Sdespython{COLON}			{ YDVAR(0, VAR_PYTHON) }
327238106Sdesdomain-insecure{COLON}		{ YDVAR(1, VAR_DOMAIN_INSECURE) }
328238106Sdesminimal-responses{COLON}	{ YDVAR(1, VAR_MINIMAL_RESPONSES) }
329238106Sdesrrset-roundrobin{COLON}		{ YDVAR(1, VAR_RRSET_ROUNDROBIN) }
330269257Sdesmax-udp-size{COLON}		{ YDVAR(1, VAR_MAX_UDP_SIZE) }
331238106Sdes<INITIAL,val>{NEWLINE}		{ LEXOUT(("NL\n")); cfg_parser->line++; }
332238106Sdes
333238106Sdes	/* Quoted strings. Strip leading and ending quotes */
334238106Sdes<val>\"			{ BEGIN(quotedstring); LEXOUT(("QS ")); }
335238106Sdes<quotedstring><<EOF>>   {
336269257Sdes        ub_c_error("EOF inside quoted string");
337238106Sdes	if(--num_args == 0) { BEGIN(INITIAL); }
338238106Sdes	else		    { BEGIN(val); }
339238106Sdes}
340269257Sdes<quotedstring>{DQANY}*  { LEXOUT(("STR(%s) ", ub_c_text)); yymore(); }
341269257Sdes<quotedstring>{NEWLINE} { ub_c_error("newline inside quoted string, no end \"");
342238106Sdes			  cfg_parser->line++; BEGIN(INITIAL); }
343238106Sdes<quotedstring>\" {
344238106Sdes        LEXOUT(("QE "));
345238106Sdes	if(--num_args == 0) { BEGIN(INITIAL); }
346238106Sdes	else		    { BEGIN(val); }
347269257Sdes        ub_c_text[ub_c_leng - 1] = '\0';
348269257Sdes	ub_c_lval.str = strdup(ub_c_text);
349269257Sdes	if(!ub_c_lval.str)
350269257Sdes		ub_c_error("out of memory");
351238106Sdes        return STRING_ARG;
352238106Sdes}
353238106Sdes
354238106Sdes	/* Single Quoted strings. Strip leading and ending quotes */
355238106Sdes<val>\'			{ BEGIN(singlequotedstr); LEXOUT(("SQS ")); }
356238106Sdes<singlequotedstr><<EOF>>   {
357269257Sdes        ub_c_error("EOF inside quoted string");
358238106Sdes	if(--num_args == 0) { BEGIN(INITIAL); }
359238106Sdes	else		    { BEGIN(val); }
360238106Sdes}
361269257Sdes<singlequotedstr>{SQANY}*  { LEXOUT(("STR(%s) ", ub_c_text)); yymore(); }
362269257Sdes<singlequotedstr>{NEWLINE} { ub_c_error("newline inside quoted string, no end '");
363238106Sdes			     cfg_parser->line++; BEGIN(INITIAL); }
364238106Sdes<singlequotedstr>\' {
365238106Sdes        LEXOUT(("SQE "));
366238106Sdes	if(--num_args == 0) { BEGIN(INITIAL); }
367238106Sdes	else		    { BEGIN(val); }
368269257Sdes        ub_c_text[ub_c_leng - 1] = '\0';
369269257Sdes	ub_c_lval.str = strdup(ub_c_text);
370269257Sdes	if(!ub_c_lval.str)
371269257Sdes		ub_c_error("out of memory");
372238106Sdes        return STRING_ARG;
373238106Sdes}
374238106Sdes
375238106Sdes	/* include: directive */
376238106Sdes<INITIAL,val>include{COLON}	{
377269257Sdes	LEXOUT(("v(%s) ", ub_c_text)); inc_prev = YYSTATE; BEGIN(include); }
378238106Sdes<include><<EOF>>	{
379269257Sdes        ub_c_error("EOF inside include directive");
380238106Sdes        BEGIN(inc_prev);
381238106Sdes}
382238106Sdes<include>{SPACE}*	{ LEXOUT(("ISP ")); /* ignore */ }
383238106Sdes<include>{NEWLINE}	{ LEXOUT(("NL\n")); cfg_parser->line++;}
384238106Sdes<include>\"		{ LEXOUT(("IQS ")); BEGIN(include_quoted); }
385238106Sdes<include>{UNQUOTEDLETTER}*	{
386269257Sdes	LEXOUT(("Iunquotedstr(%s) ", ub_c_text));
387269257Sdes	config_start_include_glob(ub_c_text);
388238106Sdes	BEGIN(inc_prev);
389238106Sdes}
390238106Sdes<include_quoted><<EOF>>	{
391269257Sdes        ub_c_error("EOF inside quoted string");
392238106Sdes        BEGIN(inc_prev);
393238106Sdes}
394269257Sdes<include_quoted>{DQANY}*	{ LEXOUT(("ISTR(%s) ", ub_c_text)); yymore(); }
395269257Sdes<include_quoted>{NEWLINE}	{ ub_c_error("newline before \" in include name");
396238106Sdes				  cfg_parser->line++; BEGIN(inc_prev); }
397238106Sdes<include_quoted>\"	{
398238106Sdes	LEXOUT(("IQE "));
399269257Sdes	ub_c_text[ub_c_leng - 1] = '\0';
400269257Sdes	config_start_include_glob(ub_c_text);
401238106Sdes	BEGIN(inc_prev);
402238106Sdes}
403238106Sdes<INITIAL,val><<EOF>>	{
404269257Sdes	LEXOUT(("LEXEOF "));
405238106Sdes	yy_set_bol(1); /* Set beginning of line, so "^" rules match.  */
406269257Sdes	if (!config_include_stack) {
407238106Sdes		yyterminate();
408238106Sdes	} else {
409269257Sdes		fclose(ub_c_in);
410238106Sdes		config_end_include();
411238106Sdes	}
412238106Sdes}
413238106Sdes
414269257Sdes<val>{UNQUOTEDLETTER}*	{ LEXOUT(("unquotedstr(%s) ", ub_c_text));
415238106Sdes			if(--num_args == 0) { BEGIN(INITIAL); }
416269257Sdes			ub_c_lval.str = strdup(ub_c_text); return STRING_ARG; }
417238106Sdes
418238106Sdes{UNQUOTEDLETTER_NOCOLON}*	{
419269257Sdes	ub_c_error_msg("unknown keyword '%s'", ub_c_text);
420238106Sdes	}
421238106Sdes
422238106Sdes<*>.	{
423269257Sdes	ub_c_error_msg("stray '%s'", ub_c_text);
424238106Sdes	}
425238106Sdes
426238106Sdes%%
427