3 * SPDX-License-Identifier: BSD-2-Clause
5 * Copyright (c) 2011 James Gritton
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
41 #define YY_DECL int yylex(YYSTYPE *yylval, yyscan_t yyscanner)
42 #define YY_EXTRA_TYPE struct cflex*
46 static ssize_t text2lval(size_t triml, size_t trimr, int tovar,
47 YYSTYPE *yylval, yyscan_t scanner);
62 /* Whitespace or equivalent */
63 <_>[ \t\r\n]+ instr = 0;
66 <_>\/\*([^*]|(\*+([^*\/])))*\*+\/ instr = 0;
78 /* Atomic (unquoted) strings */
79 <_,DQ>[A-Za-z0-9_!%&()\-.:<>?@\[\]^`|~]+ |
80 <_,DQ>\\(.|\n|[0-7]{1,3}|x[0-9A-Fa-f]{1,2}) |
82 (void)text2lval(0, 0, 0, yylval, yyscanner);
83 return instr ? STR1 : (instr = 1, STR);
86 /* Single and double quoted strings */
87 <_>'([^\'\\]|\\(.|\n))*' {
88 (void)text2lval(1, 1, 0, yylval, yyscanner);
89 return instr ? STR1 : (instr = 1, STR);
91 <_>\"([^"\\]|\\(.|\n))*\" |
92 <DQ>[^\"$\\]([^"\\]|\\(.|\n))*\" {
96 skip = yytext[0] == '"' ? 1 : 0;
97 atvar = text2lval(skip, 1, 1, yylval,
103 * The string has a variable inside it.
104 * Go into DQ mode to get the variable
105 * and then the rest of the string.
110 return instr ? STR1 : (instr = 1, STR);
114 /* Variables, single-word or bracketed */
115 <_,DQ>$[A-Za-z_][A-Za-z_0-9]* {
116 (void)text2lval(1, 0, 0, yylval, yyscanner);
117 return instr ? VAR1 : (instr = 1, VAR);
119 <_>$\{([^\n{}]|\\(.|\n))*\} |
120 <DQ>$\{([^\n\"{}]|\\(.|\n))*\} {
121 (void)text2lval(2, 1, 0, yylval, yyscanner);
122 return instr ? VAR1 : (instr = 1, VAR);
125 /* Partially formed bits worth complaining about */
126 <_>\/\*([^*]|(\*+([^*\/])))*\** {
127 warnx("%s line %d: unterminated comment",
128 yyextra->cfname, yylineno);
131 <_>'([^\n'\\]|\\.)* |
132 <_>\"([^\n\"\\]|\\.)* {
133 warnx("%s line %d: unterminated string",
134 yyextra->cfname, yylineno);
137 <_>$\{([^\n{}]|\\.)* |
138 <DQ>$\{([^\n\"{}]|\\.)* {
139 warnx("%s line %d: unterminated variable",
140 yyextra->cfname, yylineno);
144 /* A hack because "<0>" rules aren't allowed */
145 <_>. return yytext[0];
154 * Copy string from yytext to yylval, handling backslash escapes,
155 * and optionally stopping at the beginning of a variable.
158 text2lval(size_t triml, size_t trimr, int tovar, YYSTYPE *yylval,
164 struct yyguts_t *yyg = scanner;
165 yylval->cs = d = emalloc(yyleng - trimr - triml + 1);
166 se = yytext + (yyleng - trimr);
167 for (s = yytext + triml; s < se; s++, d++) {
169 if (tovar && *s == '$') {
177 if (*s >= '0' && *s <= '7') {
179 if (s + 1 < se && s[1] >= '0' && s[1] <= '7') {
180 *d = 010 * *d + (*++s - '0');
181 if (s + 1 < se && s[1] >= '0' && s[1] <= '7')
182 *d = 010 * *d + (*++s - '0');
187 case 'a': *d = '\a'; break;
188 case 'b': *d = '\b'; break;
189 case 'f': *d = '\f'; break;
190 case 'n': *d = '\n'; break;
191 case 'r': *d = '\r'; break;
192 case 't': *d = '\t'; break;
193 case 'v': *d = '\v'; break;
194 default: *d = *s; break;
195 case '\n': d--; break;
200 if (s[1] >= '0' && s[1] <= '9')
202 else if (s[1] >= 'A' && s[1] <= 'F')
203 *d = *++s + (0xA - 'A');
204 else if (s[1] >= 'a' && s[1] <= 'f')
205 *d = *++s + (0xa - 'a');
210 if (s[1] >= '0' && s[1] <= '9')
211 *d = *d * 0x10 + (*++s - '0');
212 else if (s[1] >= 'A' && s[1] <= 'F')
213 *d = *d * 0x10 + (*++s + (0xA - 'A'));
214 else if (s[1] >= 'a' && s[1] <= 'f')
215 *d = *d * 0x10 + (*++s + (0xa - 'a'));