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 42 extern YY_DECL; 43 44 static ssize_t text2lval(size_t triml, size_t trimr, int tovar, 45 YYSTYPE *yylval, yyscan_t scanner); 46 47 static 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 */ 155 static ssize_t 156 text2lval(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