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