xref: /netbsd-src/tests/lib/libcurses/director/testlang_conf.l (revision 3587d6f89c746bbb4f886219ddacd41ace480ecf)
1 %{
2 /*	$NetBSD: testlang_conf.l,v 1.26 2021/11/15 21:45:46 blymn Exp $ 	*/
3 
4 /*-
5  * Copyright 2009 Brett Lymn <blymn@NetBSD.org>
6  * Copyright 2021 Roland Illig <rillig@NetBSD.org>
7  *
8  * All rights reserved.
9  *
10  * This code has been donated to The NetBSD Foundation by the Author.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <curses.h>
33 #include <ctype.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/param.h>
38 #include <err.h>
39 #include "returns.h"
40 #include "testlang_parse.h"
41 
42 #define MAX_INCLUDES 32 /* limit for the number of nested includes */
43 
44 int yylex(void);
45 
46 extern size_t line;
47 extern char *cur_file;		/* from director.c */
48 
49 static int include_stack[MAX_INCLUDES];
50 static char *include_files[MAX_INCLUDES];
51 static int include_ptr = 0;
52 
53 static char *
54 dequote(const char *s, size_t *len)
55 {
56 	const unsigned char *p;
57 	char *buf, *q;
58 
59 	*len = 0;
60 	p = (const unsigned char *)s;
61 	while (*p) {
62 		if (*p == '\\' && p[1]) {
63 			if (isdigit(p[1]) && isdigit(p[2]) && isdigit(p[3]))
64 				p += 3;
65 			else
66 				++p;
67 		}
68 		++(*len);
69 		++p;
70 	}
71 
72 	buf = malloc(*len + 1);
73 	if (buf == NULL)
74 		return NULL;
75 
76 	p = (const unsigned char *)s;
77 	q = buf;
78 	while (*p) {
79 		if (*p == '\\' && p[1]) {
80 			++p;
81 
82 			if (isdigit(p[0])) {
83 				if (isdigit(p[1]) && isdigit(p[2])) {
84 					*q++ = (p[0] - '0') * 64 +
85 					    (p[1] - '0') * 8 +
86 					    (p[2] - '0');
87 					p += 3;
88 				} else {
89 					*q++ = *p++;
90 				}
91 				continue;
92 			}
93 
94 			switch (*p) {
95 			case 'b':
96 				/* backspace */
97 				*q++ = '\b';
98 				p++;
99 				break;
100 
101 			case 'e':
102 				/* escape */
103 				*q++ = '\e';
104 				p++;
105 				break;
106 
107 			case 'n':
108 				/* newline */
109 				*q++ = '\n';
110 				p++;
111 				break;
112 
113 			case 'r':
114 				/* carriage return */
115 				*q++ = '\r';
116 				p++;
117 				break;
118 
119 			case 't':
120 				/* tab */
121 				*q++ = '\t';
122 				p++;
123 				break;
124 
125 			case '\\':
126 				/* backslash */
127 				*q++ = '\\';
128 				p++;
129 				break;
130 
131 			default:
132 				if (isalpha(*p))
133 					errx(2,
134 					    "%s:%zu: Invalid escape sequence "
135 					    "'\\%c' in string literal",
136 					    cur_file, line, *p);
137 				*q++ = *p++;
138 			}
139 		} else
140 			*q++ = *p++;
141 	}
142 	*q++ = '\0';
143 
144 	return buf;
145 }
146 %}
147 
148 HEX		0[xX][0-9a-zA-Z]+
149 STRING		[0-9a-z!#-&(-^ \t%._\\]+
150 numeric		[-0-9]+
151 PCHAR           (\\.|[!-~])
152 ASSIGN		assign
153 CALL2		call2
154 CALL3		call3
155 CALL4		call4
156 CALL		call
157 CHECK		check
158 DELAY		delay
159 INPUT		input
160 NOINPUT		noinput
161 OK_RET		OK
162 ERR_RET		ERR
163 COMPARE		compare
164 COMPAREND	comparend
165 FILENAME	[A-Za-z0-9.][A-Za-z0-9./_-]+
166 VARNAME		[A-Za-z][A-Za-z0-9_-]+
167 NULL_RET	NULL
168 NON_NULL	NON_NULL
169 CCHAR		cchar
170 WCHAR		wchar
171 BYTE		BYTE
172 OR		\|
173 LPAREN		\(
174 RPAREN		\)
175 LBRACK		\[
176 RBRACK		\]
177 MULTIPLIER	\*
178 COMMA		,
179 
180 %x incl
181 %option noinput nounput
182 
183 %%
184 
185 include		BEGIN(incl);
186 
187 <incl>[ \t]*	/* eat the whitespace */
188 <incl>[^ \t\n]+ { /* got the include file name */
189 		char *inc_file;
190 
191 		if (include_ptr > MAX_INCLUDES) {
192 			errx(2,
193 			    "%s:%zu: Maximum number of nested includes "
194 			    "exceeded", cur_file, line);
195 		}
196 
197 		const char *dir_begin;
198 		int dir_len;
199 		if (yytext[0] == '/') {
200 			dir_begin = "";
201 			dir_len = 0;
202 		} else {
203 			dir_begin = cur_file;
204 			const char *dir_end = strrchr(cur_file, '/');
205 			if (dir_end != NULL) {
206 				dir_len = (int)(dir_end + 1 - dir_begin);
207 			} else {
208 				dir_begin = ".";
209 				dir_len = 1;
210 			}
211 		}
212 
213 		if (asprintf(&inc_file, "%.*s%s",
214 		    dir_len, dir_begin, yytext) == -1)
215 			err(2, "Cannot construct include path");
216 
217 		yyin = fopen(inc_file, "r");
218 
219 		if (!yyin)
220 			err(1, "Error opening %s", inc_file);
221 
222 		yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
223 
224 		include_stack[include_ptr] = line;
225 		include_files[include_ptr++] = cur_file;
226 		cur_file = inc_file;
227 		line = 1;
228 		BEGIN(INITIAL);
229 	}
230 
231 <<EOF>>	{
232 		yypop_buffer_state();
233 
234 		if (!YY_CURRENT_BUFFER)
235 			yyterminate();
236 
237 		if (--include_ptr < 0)
238 			errx(2, "Include stack underflow");
239 
240 		free(cur_file);
241 		cur_file = include_files[include_ptr];
242 		line = include_stack[include_ptr];
243 	}
244 
245 {ASSIGN}	return ASSIGN;
246 {CALL2}		return CALL2;
247 {CALL3}		return CALL3;
248 {CALL4}		return CALL4;
249 {CALL}		return CALL;
250 {CHECK}		return CHECK;
251 {DELAY}		return DELAY;
252 {INPUT}		return INPUT;
253 {NOINPUT}	return NOINPUT;
254 {COMPARE}	return COMPARE;
255 {COMPAREND}	return COMPAREND;
256 {NON_NULL}	return NON_NULL;
257 {NULL_RET}	return NULL_RET;
258 {OK_RET}	return OK_RET;
259 {ERR_RET}	return ERR_RET;
260 {MULTIPLIER}	return MULTIPLIER;
261 {COMMA}		return COMMA;
262 {CCHAR}		return CCHAR;
263 {WCHAR}		return WCHAR;
264 {OR}		return OR;
265 {LPAREN}	return LPAREN;
266 {RPAREN}	return RPAREN;
267 {LBRACK}	return LBRACK;
268 {RBRACK}	return RBRACK;
269 
270 {HEX}		{
271 			/* Hex value, convert to decimal and return numeric */
272 			unsigned long val;
273 
274 			if (sscanf(yytext, "%lx", &val) != 1)
275 				errx(1, "Bad hex conversion");
276 
277 			asprintf(&yylval.string, "%ld", val);
278 			return numeric;
279 		}
280 
281 {numeric}	{
282 			if ((yylval.string = strdup(yytext)) == NULL)
283 				err(1, "Cannot allocate numeric string");
284 			return numeric;
285 		}
286 
287 {VARNAME}	{
288 			if ((yylval.string = strdup(yytext)) == NULL)
289 				err(1, "Cannot allocate string for varname");
290 			return VARNAME;
291 		}
292 
293 {FILENAME}	{
294 			size_t len;
295 
296 			if ((yylval.string = dequote(yytext, &len)) == NULL)
297 				err(1, "Cannot allocate filename string");
298 			return FILENAME;
299 		}
300 
301 	/* path */
302 \/{PCHAR}+	{
303 			size_t len;
304 			if ((yylval.string = dequote(yytext, &len)) == NULL)
305 				err(1, "Cannot allocate string");
306 			return PATH;
307 		}
308 
309 \'{STRING}\' 	{
310 			char *p;
311 			size_t len;
312 
313 			if ((yylval.retval = malloc(sizeof(ct_data_t))) == NULL)
314 				err(1, "Cannot allocate return struct");
315 			p = yytext;
316 			p++; /* skip the leading ' */
317 			if ((yylval.retval->data_value = dequote(p, &len))
318 			     == NULL)
319 				err(1, "Cannot allocate string");
320 
321 			yylval.retval->data_type = data_byte;
322 			/* trim trailing ' */
323 			yylval.retval->data_len = len - 1;
324 			return BYTE;
325 		}
326 
327 \`{STRING}\` 	{
328 			char *p, *str;
329 			size_t len, chlen;
330 			size_t i;
331 			chtype *rv;
332 
333 			if ((yylval.retval = malloc(sizeof(ct_data_t))) == NULL)
334 				err(1, "Cannot allocate return struct");
335 			p = yytext;
336 			p++; /* skip the leading ` */
337 			if ((str = dequote(p, &len)) == NULL)
338 				err(1, "Cannot allocate string");
339 			len--; /* trim trailing ` */
340 			if ((len % 2) != 0)
341 				len--;
342 
343 			chlen = ((len / 2) + 1) * sizeof(chtype);
344 			if ((yylval.retval->data_value = malloc(chlen))
345 			    == NULL)
346 				err(1, "Cannot allocate chtype array");
347 
348 			rv = yylval.retval->data_value;
349 			for (i = 0; i < len; i += 2)
350 				*rv++ = (str[i] << 8) | str[i+1];
351 			*rv = __NORMAL | '\0'; /* terminates chtype array */
352 			yylval.retval->data_type = data_byte;
353 			yylval.retval->data_len = chlen;
354 			return BYTE;
355 		}
356 
357 \"{STRING}\" 	{
358 			char *p;
359 			size_t len;
360 
361 			p = yytext;
362 			p++; /* skip the leading " */
363 			if ((yylval.string = dequote(p, &len)) == NULL)
364 				err(1, "Cannot allocate string");
365 
366 			/* remove trailing " */
367 			yylval.string[len - 1] = '\0';
368 			return STRING;
369 		}
370 
371 \${VARNAME}	{
372 			char *p;
373 
374 			p = yytext;
375 			p++; /* skip $ before var name */
376 			if ((yylval.string = strdup(p)) == NULL)
377 				err(1, "Cannot allocate string for varname");
378 			return VARIABLE;
379 		}
380 
381 	/* whitespace, comments */
382 [ \t\r]		|
383 #.*		;
384 
385 ^[ \t\r]*#.*\n	|
386 \\\n		|
387 ^\n		line++;
388 
389 	/* eol on a line with data. need to process, return eol */
390 #.*\n		|
391 \n		{
392 			line++;
393 			return EOL;
394 		}
395 
396 .		{
397 			if (isprint((unsigned char)yytext[0]))
398 				errx(1, "%s:%zu: Invalid character '%c'",
399 				    cur_file, line + 1, yytext[0]);
400 			else
401 				errx(1, "%s:%zu: Invalid character '0x%02x'",
402 				    cur_file, line + 1, yytext[0]);
403 		}
404 
405 %%
406 
407 int
408 yywrap(void)
409 {
410 	return 1;
411 }
412