jaillex.l revision 250227
1214117Sjamie%{
2214117Sjamie/*-
3223190Sjamie * Copyright (c) 2011 James Gritton
4214117Sjamie * All rights reserved.
5214117Sjamie *
6214117Sjamie * Redistribution and use in source and binary forms, with or without
7214117Sjamie * modification, are permitted provided that the following conditions
8214117Sjamie * are met:
9214117Sjamie * 1. Redistributions of source code must retain the above copyright
10214117Sjamie *    notice, this list of conditions and the following disclaimer.
11214117Sjamie * 2. Redistributions in binary form must reproduce the above copyright
12214117Sjamie *    notice, this list of conditions and the following disclaimer in the
13214117Sjamie *    documentation and/or other materials provided with the distribution.
14214117Sjamie *
15214117Sjamie * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16214117Sjamie * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17214117Sjamie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18214117Sjamie * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19214117Sjamie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20214117Sjamie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21214117Sjamie * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22214117Sjamie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23214117Sjamie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24214117Sjamie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25214117Sjamie * SUCH DAMAGE.
26214117Sjamie */
27214117Sjamie
28214117Sjamie#include <sys/cdefs.h>
29214117Sjamie__FBSDID("$FreeBSD: head/usr.sbin/jail/jaillex.l 250227 2013-05-03 23:51:32Z jkim $");
30214117Sjamie
31214117Sjamie#include <err.h>
32214117Sjamie#include <stddef.h>
33214117Sjamie#include <stdlib.h>
34214117Sjamie#include <string.h>
35214117Sjamie
36214117Sjamie#include "jailp.h"
37214117Sjamie#include "y.tab.h"
38214117Sjamie
39214117Sjamieextern int yynerrs;
40214117Sjamie
41214117Sjamiestatic ssize_t text2lval(size_t triml, size_t trimr, int tovar);
42214117Sjamie
43214117Sjamiestatic int instr;
44214117Sjamiestatic int lineno = 1;
45214117Sjamie%}
46214117Sjamie
47250227Sjkim%option noinput
48250227Sjkim%option nounput
49250227Sjkim
50214117Sjamie%start _ DQ
51214117Sjamie
52214117Sjamie%%
53214117Sjamie
54214117Sjamie			/* Whitespace or equivalent */
55214117Sjamie<_>[ \t]+		instr = 0;
56214117Sjamie<_>#.*			;
57214117Sjamie<_>\/\/.*		;
58214117Sjamie<_>\/\*([^*]|(\*+([^*\/])))*\*+\/ {
59214117Sjamie				const char *s;
60214117Sjamie
61214117Sjamie				for (s = yytext; s < yytext + yyleng; s++)
62214117Sjamie					if (*s == '\n')
63214117Sjamie						lineno++;
64214117Sjamie				instr = 0;
65214117Sjamie			}
66214117Sjamie<_>\n			{
67214117Sjamie				lineno++;
68214117Sjamie				instr = 0;
69214117Sjamie			}
70214117Sjamie
71214117Sjamie			/* Reserved tokens */
72214117Sjamie<_>\+=			{
73214117Sjamie				instr = 0;
74214117Sjamie				return PLEQ;
75214117Sjamie			}
76214117Sjamie<_>[,;={}]		{
77214117Sjamie				instr = 0;
78214117Sjamie				return yytext[0];
79214117Sjamie			}
80214117Sjamie
81214117Sjamie			/* Atomic (unquoted) strings */
82214117Sjamie<_,DQ>[A-Za-z0-9_!%&()\-.:<>?@\[\]^`|~]+ |
83214117Sjamie<_,DQ>\\(.|\n|[0-7]{1,3}|x[0-9A-Fa-f]{1,2}) |
84214117Sjamie<_,DQ>[$*+/\\]		{
85214117Sjamie				(void)text2lval(0, 0, 0);
86214117Sjamie				return instr ? STR1 : (instr = 1, STR);
87214117Sjamie			}
88214117Sjamie
89214117Sjamie			/* Single and double quoted strings */
90214117Sjamie<_>'([^\'\\]|\\(.|\n))*' {
91214117Sjamie				(void)text2lval(1, 1, 0);
92214117Sjamie				return instr ? STR1 : (instr = 1, STR);
93214117Sjamie			}
94214117Sjamie<_>\"([^"\\]|\\(.|\n))*\" |
95214117Sjamie<DQ>[^\"$\\]([^"\\]|\\(.|\n))*\" {
96214117Sjamie				size_t skip;
97214117Sjamie				ssize_t atvar;
98214117Sjamie
99214117Sjamie				skip = yytext[0] == '"' ? 1 : 0;
100214117Sjamie				atvar = text2lval(skip, 1, 1);
101214117Sjamie				if (atvar < 0)
102214117Sjamie					BEGIN _;
103214117Sjamie				else {
104214117Sjamie					/*
105214117Sjamie					 * The string has a variable inside it.
106214117Sjamie					 * Go into DQ mode to get the variable
107214117Sjamie					 * and then the rest of the string.
108214117Sjamie					 */
109214117Sjamie					BEGIN DQ;
110214117Sjamie					yyless(atvar);
111214117Sjamie				}
112214117Sjamie				return instr ? STR1 : (instr = 1, STR);
113214117Sjamie			}
114214117Sjamie<DQ>\"			BEGIN _;
115214117Sjamie
116214117Sjamie			/* Variables, single-word or bracketed */
117214117Sjamie<_,DQ>$[A-Za-z_][A-Za-z_0-9]* {
118214117Sjamie				(void)text2lval(1, 0, 0);
119214117Sjamie				return instr ? VAR1 : (instr = 1, VAR);
120214117Sjamie			}
121214117Sjamie<_>$\{([^\n{}]|\\(.|\n))*\} |
122214117Sjamie<DQ>$\{([^\n\"{}]|\\(.|\n))*\} {
123214117Sjamie				(void)text2lval(2, 1, 0);
124214117Sjamie				return instr ? VAR1 : (instr = 1, VAR);
125214117Sjamie			}
126214117Sjamie
127214117Sjamie			/* Partially formed bits worth complaining about */
128214117Sjamie<_>\/\*([^*]|(\*+([^*\/])))*\** {
129214117Sjamie				warnx("%s line %d: unterminated comment",
130214117Sjamie				    cfname, lineno);
131214117Sjamie				yynerrs++;
132214117Sjamie			}
133214117Sjamie<_>'([^\n'\\]|\\.)*	|
134214117Sjamie<_>\"([^\n\"\\]|\\.)*	{
135214117Sjamie				warnx("%s line %d: unterminated string",
136214117Sjamie				    cfname, lineno);
137214117Sjamie				yynerrs++;
138214117Sjamie			}
139214117Sjamie<_>$\{([^\n{}]|\\.)*	|
140214117Sjamie<DQ>$\{([^\n\"{}]|\\.)*	{
141214117Sjamie				warnx("%s line %d: unterminated variable",
142214117Sjamie				    cfname, lineno);
143214117Sjamie				yynerrs++;
144214117Sjamie			}
145214117Sjamie
146214117Sjamie			/* A hack because "<0>" rules aren't allowed */
147214117Sjamie<_>.			return yytext[0];
148214117Sjamie.|\n			{
149214117Sjamie				BEGIN _;
150214117Sjamie				yyless(0);
151214117Sjamie			}
152214117Sjamie
153214117Sjamie%%
154214117Sjamie
155214117Sjamievoid
156214117Sjamieyyerror(const char *s)
157214117Sjamie{
158214117Sjamie	if (!yytext)
159214117Sjamie		warnx("%s line %d: %s", cfname, lineno, s);
160214117Sjamie	else if (!yytext[0])
161214117Sjamie		warnx("%s: unexpected EOF", cfname);
162214117Sjamie	else
163214117Sjamie		warnx("%s line %d: %s: %s", cfname, lineno, yytext, s);
164214117Sjamie}
165214117Sjamie
166214117Sjamie/*
167214117Sjamie * Copy string from yytext to yylval, handling backslash escapes,
168214117Sjamie * and optionally stopping at the beginning of a variable.
169214117Sjamie */
170214117Sjamiestatic ssize_t
171214117Sjamietext2lval(size_t triml, size_t trimr, int tovar)
172214117Sjamie{
173214117Sjamie	char *d;
174214117Sjamie	const char *s, *se;
175214117Sjamie
176214117Sjamie	yylval.cs = d = emalloc(yyleng - trimr - triml + 1);
177214117Sjamie	se = yytext + (yyleng - trimr);
178214117Sjamie	for (s = yytext + triml; s < se; s++, d++) {
179214117Sjamie		if (*s != '\\') {
180214117Sjamie			if (tovar && *s == '$') {
181214117Sjamie				*d = '\0';
182214117Sjamie				return s - yytext;
183214117Sjamie			}
184214117Sjamie			if (*s == '\n')
185214117Sjamie				lineno++;
186214117Sjamie			*d = *s;
187214117Sjamie			continue;
188214117Sjamie		}
189214117Sjamie		s++;
190214117Sjamie		if (*s >= '0' && *s <= '7') {
191214117Sjamie			*d = *s - '0';
192214117Sjamie			if (s + 1 < se && s[1] >= '0' && s[1] <= '7') {
193214117Sjamie				*d = 010 * *d + (*++s - '0');
194214117Sjamie				if (s + 1 < se && s[1] >= '0' && s[1] <= '7')
195214117Sjamie					*d = 010 * *d + (*++s - '0');
196214117Sjamie			}
197214117Sjamie			continue;
198214117Sjamie		}
199214117Sjamie		switch (*s) {
200214117Sjamie		case 'a':	*d = '\a';	break;
201214117Sjamie		case 'b':	*d = '\b';	break;
202214117Sjamie		case 'f':	*d = '\f';	break;
203214117Sjamie		case 'n':	*d = '\n';	break;
204214117Sjamie		case 'r':	*d = '\r';	break;
205214117Sjamie		case 't':	*d = '\t';	break;
206214117Sjamie		case 'v':	*d = '\v';	break;
207214117Sjamie		case '\n':	d--; lineno++;	break;
208214117Sjamie		default:	*d = *s;	break;
209214117Sjamie		case 'x':
210214117Sjamie			*d = 0;
211214117Sjamie			if (s + 1 >= se)
212214117Sjamie				break;
213214117Sjamie			if (s[1] >= '0' && s[1] <= '9')
214214117Sjamie				*d = *++s - '0';
215214117Sjamie			else if (s[1] >= 'A' && s[1] <= 'F')
216214117Sjamie				*d = *++s + (0xA - 'A');
217214117Sjamie			else if (s[1] >= 'a' && s[1] <= 'a')
218214117Sjamie				*d = *++s + (0xa - 'a');
219214117Sjamie			else
220214117Sjamie				break;
221214117Sjamie			if (s + 1 >= se)
222214117Sjamie				break;
223214117Sjamie			if (s[1] >= '0' && s[1] <= '9')
224214117Sjamie				*d = *d * 0x10 + (*++s - '0');
225214117Sjamie			else if (s[1] >= 'A' && s[1] <= 'F')
226214117Sjamie				*d = *d * 0x10 + (*++s + (0xA - 'A'));
227214117Sjamie			else if (s[1] >= 'a' && s[1] <= 'a')
228214117Sjamie				*d = *d * 0x10 + (*++s + (0xa - 'a'));
229214117Sjamie		}
230214117Sjamie	}
231214117Sjamie	*d = '\0';
232214117Sjamie	return -1;
233214117Sjamie}
234