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 __FBSDID("$FreeBSD$"); 32 33 #include <err.h> 34 #include <stddef.h> 35 #include <stdlib.h> 36 #include <string.h> 37 38 #include "jailp.h" 39 #include "y.tab.h" 40 41 #define YY_DECL int yylex(YYSTYPE *yylval, yyscan_t yyscanner) 42 #define YY_EXTRA_TYPE struct cflex* 43 44 extern YY_DECL; 45 46 static ssize_t text2lval(size_t triml, size_t trimr, int tovar, 47 YYSTYPE *yylval, yyscan_t scanner); 48 49 static int instr; 50 %} 51 52 %option noyywrap 53 %option noinput 54 %option nounput 55 %option reentrant 56 %option yylineno 57 58 %start _ DQ 59 60 %% 61 62 /* Whitespace or equivalent */ 63 <_>[ \t\r\n]+ instr = 0; 64 <_>#.* instr = 0; 65 <_>\/\/.* instr = 0; 66 <_>\/\*([^*]|(\*+([^*\/])))*\*+\/ instr = 0; 67 68 /* Reserved tokens */ 69 <_>\+= { 70 instr = 0; 71 return PLEQ; 72 } 73 <_>[,;={}] { 74 instr = 0; 75 return yytext[0]; 76 } 77 78 /* Atomic (unquoted) strings */ 79 <_,DQ>[A-Za-z0-9_!%&()\-.:<>?@\[\]^`|~]+ | 80 <_,DQ>\\(.|\n|[0-7]{1,3}|x[0-9A-Fa-f]{1,2}) | 81 <_,DQ>[$*+/\\] { 82 (void)text2lval(0, 0, 0, yylval, yyscanner); 83 return instr ? STR1 : (instr = 1, STR); 84 } 85 86 /* Single and double quoted strings */ 87 <_>'([^\'\\]|\\(.|\n))*' { 88 (void)text2lval(1, 1, 0, yylval, yyscanner); 89 return instr ? STR1 : (instr = 1, STR); 90 } 91 <_>\"([^"\\]|\\(.|\n))*\" | 92 <DQ>[^\"$\\]([^"\\]|\\(.|\n))*\" { 93 size_t skip; 94 ssize_t atvar; 95 96 skip = yytext[0] == '"' ? 1 : 0; 97 atvar = text2lval(skip, 1, 1, yylval, 98 yyscanner); 99 if (atvar < 0) 100 BEGIN _; 101 else { 102 /* 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. 106 */ 107 BEGIN DQ; 108 yyless(atvar); 109 } 110 return instr ? STR1 : (instr = 1, STR); 111 } 112 <DQ>\" BEGIN _; 113 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); 118 } 119 <_>$\{([^\n{}]|\\(.|\n))*\} | 120 <DQ>$\{([^\n\"{}]|\\(.|\n))*\} { 121 (void)text2lval(2, 1, 0, yylval, yyscanner); 122 return instr ? VAR1 : (instr = 1, VAR); 123 } 124 125 /* Partially formed bits worth complaining about */ 126 <_>\/\*([^*]|(\*+([^*\/])))*\** { 127 warnx("%s line %d: unterminated comment", 128 yyextra->cfname, yylineno); 129 yyextra->error = 1; 130 } 131 <_>'([^\n'\\]|\\.)* | 132 <_>\"([^\n\"\\]|\\.)* { 133 warnx("%s line %d: unterminated string", 134 yyextra->cfname, yylineno); 135 yyextra->error = 1; 136 } 137 <_>$\{([^\n{}]|\\.)* | 138 <DQ>$\{([^\n\"{}]|\\.)* { 139 warnx("%s line %d: unterminated variable", 140 yyextra->cfname, yylineno); 141 yyextra->error = 1; 142 } 143 144 /* A hack because "<0>" rules aren't allowed */ 145 <_>. return yytext[0]; 146 .|\n { 147 BEGIN _; 148 yyless(0); 149 } 150 151 %% 152 153 /* 154 * Copy string from yytext to yylval, handling backslash escapes, 155 * and optionally stopping at the beginning of a variable. 156 */ 157 static ssize_t 158 text2lval(size_t triml, size_t trimr, int tovar, YYSTYPE *yylval, 159 yyscan_t scanner) 160 { 161 char *d; 162 const char *s, *se; 163 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++) { 168 if (*s != '\\') { 169 if (tovar && *s == '$') { 170 *d = '\0'; 171 return s - yytext; 172 } 173 *d = *s; 174 continue; 175 } 176 s++; 177 if (*s >= '0' && *s <= '7') { 178 *d = *s - '0'; 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'); 183 } 184 continue; 185 } 186 switch (*s) { 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; 196 case 'x': 197 *d = 0; 198 if (s + 1 >= se) 199 break; 200 if (s[1] >= '0' && s[1] <= '9') 201 *d = *++s - '0'; 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'); 206 else 207 break; 208 if (s + 1 >= se) 209 break; 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')); 216 } 217 } 218 *d = '\0'; 219 return -1; 220 } 221