1%{
2/*-
3 * SPDX-License-Identifier: BSD-2-Clause
4 *
5 * Copyright (c) 2011 James Gritton
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31#include <err.h>
32#include <stddef.h>
33#include <stdlib.h>
34#include <string.h>
35
36#include "jailp.h"
37#include "y.tab.h"
38
39#define YY_DECL int yylex(YYSTYPE *yylval, yyscan_t yyscanner)
40#define YY_EXTRA_TYPE struct cflex*
41
42extern YY_DECL;
43
44static ssize_t text2lval(size_t triml, size_t trimr, int tovar,
45    YYSTYPE *yylval, yyscan_t scanner);
46
47static int instr;
48%}
49
50%option noyywrap
51%option noinput
52%option nounput
53%option reentrant
54%option yylineno
55
56%start _ DQ
57
58%%
59
60			/* Whitespace or equivalent */
61<_>[ \t\r\n]+		instr = 0;
62<_>#.*			instr = 0;
63<_>\/\/.*		instr = 0;
64<_>\/\*([^*]|(\*+([^*\/])))*\*+\/ instr = 0;
65
66			/* Reserved tokens */
67<_>\+=			{
68				instr = 0;
69				return PLEQ;
70			}
71<_>[,;={}]		{
72				instr = 0;
73				return yytext[0];
74			}
75
76			/* Atomic (unquoted) strings */
77<_,DQ>[A-Za-z0-9_!%&()\-.:<>?@\[\]^`|~]+ |
78<_,DQ>\\(.|\n|[0-7]{1,3}|x[0-9A-Fa-f]{1,2}) |
79<_,DQ>[$*+/\\]		{
80				(void)text2lval(0, 0, 0, yylval, yyscanner);
81				return instr ? STR1 : (instr = 1, STR);
82			}
83
84			/* Single and double quoted strings */
85<_>'([^\'\\]|\\(.|\n))*' {
86				(void)text2lval(1, 1, 0, yylval, yyscanner);
87				return instr ? STR1 : (instr = 1, STR);
88			}
89<_>\"([^"\\]|\\(.|\n))*\" |
90<DQ>[^\"$\\]([^"\\]|\\(.|\n))*\" {
91				size_t skip;
92				ssize_t atvar;
93
94				skip = yytext[0] == '"' ? 1 : 0;
95				atvar = text2lval(skip, 1, 1, yylval,
96					yyscanner);
97				if (atvar < 0)
98					BEGIN _;
99				else {
100					/*
101					 * The string has a variable inside it.
102					 * Go into DQ mode to get the variable
103					 * and then the rest of the string.
104					 */
105					BEGIN DQ;
106					yyless(atvar);
107				}
108				return instr ? STR1 : (instr = 1, STR);
109			}
110<DQ>\"			BEGIN _;
111
112			/* Variables, single-word or bracketed */
113<_,DQ>$[A-Za-z_][A-Za-z_0-9]* {
114				(void)text2lval(1, 0, 0, yylval, yyscanner);
115				return instr ? VAR1 : (instr = 1, VAR);
116			}
117<_>$\{([^\n{}]|\\(.|\n))*\} |
118<DQ>$\{([^\n\"{}]|\\(.|\n))*\} {
119				(void)text2lval(2, 1, 0, yylval, yyscanner);
120				return instr ? VAR1 : (instr = 1, VAR);
121			}
122
123			/* Partially formed bits worth complaining about */
124<_>\/\*([^*]|(\*+([^*\/])))*\** {
125				warnx("%s line %d: unterminated comment",
126				    yyextra->cfname, yylineno);
127				yyextra->error = 1;
128			}
129<_>'([^\n'\\]|\\.)*	|
130<_>\"([^\n\"\\]|\\.)*	{
131				warnx("%s line %d: unterminated string",
132				    yyextra->cfname, yylineno);
133				yyextra->error = 1;
134			}
135<_>$\{([^\n{}]|\\.)*	|
136<DQ>$\{([^\n\"{}]|\\.)*	{
137				warnx("%s line %d: unterminated variable",
138				    yyextra->cfname, yylineno);
139				yyextra->error = 1;
140			}
141
142			/* A hack because "<0>" rules aren't allowed */
143<_>.			return yytext[0];
144.|\n			{
145				BEGIN _;
146				yyless(0);
147			}
148
149%%
150
151/*
152 * Copy string from yytext to yylval, handling backslash escapes,
153 * and optionally stopping at the beginning of a variable.
154 */
155static ssize_t
156text2lval(size_t triml, size_t trimr, int tovar, YYSTYPE *yylval,
157    yyscan_t scanner)
158{
159	char *d;
160	const char *s, *se;
161
162	struct yyguts_t *yyg = scanner;
163	yylval->cs = d = emalloc(yyleng - trimr - triml + 1);
164	se = yytext + (yyleng - trimr);
165	for (s = yytext + triml; s < se; s++, d++) {
166		if (*s != '\\') {
167			if (tovar && *s == '$') {
168				*d = '\0';
169				return s - yytext;
170			}
171			*d = *s;
172			continue;
173		}
174		s++;
175		if (*s >= '0' && *s <= '7') {
176			*d = *s - '0';
177			if (s + 1 < se && s[1] >= '0' && s[1] <= '7') {
178				*d = 010 * *d + (*++s - '0');
179				if (s + 1 < se && s[1] >= '0' && s[1] <= '7')
180					*d = 010 * *d + (*++s - '0');
181			}
182			continue;
183		}
184		switch (*s) {
185		case 'a':	*d = '\a';	break;
186		case 'b':	*d = '\b';	break;
187		case 'f':	*d = '\f';	break;
188		case 'n':	*d = '\n';	break;
189		case 'r':	*d = '\r';	break;
190		case 't':	*d = '\t';	break;
191		case 'v':	*d = '\v';	break;
192		default:	*d = *s;	break;
193		case '\n':	d--;		break;
194		case 'x':
195			*d = 0;
196			if (s + 1 >= se)
197				break;
198			if (s[1] >= '0' && s[1] <= '9')
199				*d = *++s - '0';
200			else if (s[1] >= 'A' && s[1] <= 'F')
201				*d = *++s + (0xA - 'A');
202			else if (s[1] >= 'a' && s[1] <= 'f')
203				*d = *++s + (0xa - 'a');
204			else
205				break;
206			if (s + 1 >= se)
207				break;
208			if (s[1] >= '0' && s[1] <= '9')
209				*d = *d * 0x10 + (*++s - '0');
210			else if (s[1] >= 'A' && s[1] <= 'F')
211				*d = *d * 0x10 + (*++s + (0xA - 'A'));
212			else if (s[1] >= 'a' && s[1] <= 'f')
213				*d = *d * 0x10 + (*++s + (0xa - 'a'));
214		}
215	}
216	*d = '\0';
217	return -1;
218}
219