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 #define YY_NO_INPUT 40 #define YY_NO_UNPUT 41 42 extern int yynerrs; 43 44 static ssize_t text2lval(size_t triml, size_t trimr, int tovar); 45 46 static int instr; 47 static int lineno = 1; 48 %} 49 50 %start _ DQ 51 52 %% 53 54 /* Whitespace or equivalent */ 55 <_>[ \t]+ instr = 0; 56 <_>#.* ; 57 <_>\/\/.* ; 58 <_>\/\*([^*]|(\*+([^*\/])))*\*+\/ { 59 const char *s; 60 61 for (s = yytext; s < yytext + yyleng; s++) 62 if (*s == '\n') 63 lineno++; 64 instr = 0; 65 } 66 <_>\n { 67 lineno++; 68 instr = 0; 69 } 70 71 /* Reserved tokens */ 72 <_>\+= { 73 instr = 0; 74 return PLEQ; 75 } 76 <_>[,;={}] { 77 instr = 0; 78 return yytext[0]; 79 } 80 81 /* Atomic (unquoted) strings */ 82 <_,DQ>[A-Za-z0-9_!%&()\-.:<>?@\[\]^`|~]+ | 83 <_,DQ>\\(.|\n|[0-7]{1,3}|x[0-9A-Fa-f]{1,2}) | 84 <_,DQ>[$*+/\\] { 85 (void)text2lval(0, 0, 0); 86 return instr ? STR1 : (instr = 1, STR); 87 } 88 89 /* Single and double quoted strings */ 90 <_>'([^\'\\]|\\(.|\n))*' { 91 (void)text2lval(1, 1, 0); 92 return instr ? STR1 : (instr = 1, STR); 93 } 94 <_>\"([^"\\]|\\(.|\n))*\" | 95 <DQ>[^\"$\\]([^"\\]|\\(.|\n))*\" { 96 size_t skip; 97 ssize_t atvar; 98 99 skip = yytext[0] == '"' ? 1 : 0; 100 atvar = text2lval(skip, 1, 1); 101 if (atvar < 0) 102 BEGIN _; 103 else { 104 /* 105 * The string has a variable inside it. 106 * Go into DQ mode to get the variable 107 * and then the rest of the string. 108 */ 109 BEGIN DQ; 110 yyless(atvar); 111 } 112 return instr ? STR1 : (instr = 1, STR); 113 } 114 <DQ>\" BEGIN _; 115 116 /* Variables, single-word or bracketed */ 117 <_,DQ>$[A-Za-z_][A-Za-z_0-9]* { 118 (void)text2lval(1, 0, 0); 119 return instr ? VAR1 : (instr = 1, VAR); 120 } 121 <_>$\{([^\n{}]|\\(.|\n))*\} | 122 <DQ>$\{([^\n\"{}]|\\(.|\n))*\} { 123 (void)text2lval(2, 1, 0); 124 return instr ? VAR1 : (instr = 1, VAR); 125 } 126 127 /* Partially formed bits worth complaining about */ 128 <_>\/\*([^*]|(\*+([^*\/])))*\** { 129 warnx("%s line %d: unterminated comment", 130 cfname, lineno); 131 yynerrs++; 132 } 133 <_>'([^\n'\\]|\\.)* | 134 <_>\"([^\n\"\\]|\\.)* { 135 warnx("%s line %d: unterminated string", 136 cfname, lineno); 137 yynerrs++; 138 } 139 <_>$\{([^\n{}]|\\.)* | 140 <DQ>$\{([^\n\"{}]|\\.)* { 141 warnx("%s line %d: unterminated variable", 142 cfname, lineno); 143 yynerrs++; 144 } 145 146 /* A hack because "<0>" rules aren't allowed */ 147 <_>. return yytext[0]; 148 .|\n { 149 BEGIN _; 150 yyless(0); 151 } 152 153 %% 154 155 void 156 yyerror(const char *s) 157 { 158 if (!yytext) 159 warnx("%s line %d: %s", cfname, lineno, s); 160 else if (!yytext[0]) 161 warnx("%s: unexpected EOF", cfname); 162 else 163 warnx("%s line %d: %s: %s", cfname, lineno, yytext, s); 164 } 165 166 /* 167 * Copy string from yytext to yylval, handling backslash escapes, 168 * and optionally stopping at the beginning of a variable. 169 */ 170 static ssize_t 171 text2lval(size_t triml, size_t trimr, int tovar) 172 { 173 char *d; 174 const char *s, *se; 175 176 yylval.cs = d = emalloc(yyleng - trimr - triml + 1); 177 se = yytext + (yyleng - trimr); 178 for (s = yytext + triml; s < se; s++, d++) { 179 if (*s != '\\') { 180 if (tovar && *s == '$') { 181 *d = '\0'; 182 return s - yytext; 183 } 184 if (*s == '\n') 185 lineno++; 186 *d = *s; 187 continue; 188 } 189 s++; 190 if (*s >= '0' && *s <= '7') { 191 *d = *s - '0'; 192 if (s + 1 < se && s[1] >= '0' && s[1] <= '7') { 193 *d = 010 * *d + (*++s - '0'); 194 if (s + 1 < se && s[1] >= '0' && s[1] <= '7') 195 *d = 010 * *d + (*++s - '0'); 196 } 197 continue; 198 } 199 switch (*s) { 200 case 'a': *d = '\a'; break; 201 case 'b': *d = '\b'; break; 202 case 'f': *d = '\f'; break; 203 case 'n': *d = '\n'; break; 204 case 'r': *d = '\r'; break; 205 case 't': *d = '\t'; break; 206 case 'v': *d = '\v'; break; 207 case '\n': d--; lineno++; break; 208 default: *d = *s; break; 209 case 'x': 210 *d = 0; 211 if (s + 1 >= se) 212 break; 213 if (s[1] >= '0' && s[1] <= '9') 214 *d = *++s - '0'; 215 else if (s[1] >= 'A' && s[1] <= 'F') 216 *d = *++s + (0xA - 'A'); 217 else if (s[1] >= 'a' && s[1] <= 'a') 218 *d = *++s + (0xa - 'a'); 219 else 220 break; 221 if (s + 1 >= se) 222 break; 223 if (s[1] >= '0' && s[1] <= '9') 224 *d = *d * 0x10 + (*++s - '0'); 225 else if (s[1] >= 'A' && s[1] <= 'F') 226 *d = *d * 0x10 + (*++s + (0xA - 'A')); 227 else if (s[1] >= 'a' && s[1] <= 'a') 228 *d = *d * 0x10 + (*++s + (0xa - 'a')); 229 } 230 } 231 *d = '\0'; 232 return -1; 233 } 234