1 #include "mk.h" 2 3 static int initdone = 0; 4 5 static int bquote(Biobuf *, Bufblock *); 6 static int assquote(Biobuf *, Bufblock *, int, int); 7 static char *squote(char*); 8 static long nextrune(Biobuf*, int); 9 static int expandvar(Biobuf *, Bufblock *); 10 static Bufblock *varname(Biobuf*); 11 static int varsub(Biobuf *, Bufblock *); 12 13 /* 14 * Assemble a line skipping blank lines, comments, and eliding 15 * escaped newlines 16 */ 17 int 18 assline(Biobuf *bp, Bufblock *buf) 19 { 20 int c; 21 int lastc; 22 23 initdone = 0; 24 buf->current=buf->start; 25 while ((c = nextrune(bp, 1)) >= 0){ 26 switch(c) 27 { 28 case '\n': 29 if (buf->current != buf->start) { 30 insert(buf, 0); 31 return 1; 32 } 33 break; /* skip empty lines */ 34 case '\'': 35 rinsert(buf, c); 36 if (!assquote(bp, buf, 1, c)) 37 Exit(); 38 break; 39 case '`': 40 if (!bquote(bp, buf)) 41 Exit(); 42 break; 43 case '$': 44 if (!varsub(bp, buf)) 45 Exit(); 46 break; 47 case '#': 48 lastc = '#'; 49 while ((c = Bgetc(bp)) != '\n') { 50 if (c < 0) 51 goto eof; 52 lastc = c; 53 } 54 inline++; 55 if (lastc == '\\') 56 break; /* propagate escaped newlines??*/ 57 if (buf->current != buf->start) { 58 insert(buf, 0); 59 return 1; 60 } 61 break; 62 default: 63 rinsert(buf, c); 64 break; 65 } 66 } 67 eof: 68 insert(buf, 0); 69 return *buf->start != 0; 70 } 71 /* 72 * Assemble a token surrounded by single quotes 73 */ 74 static int 75 assquote(Biobuf *bp, Bufblock *buf, int preserve, int termchar) 76 { 77 int c, line; 78 79 line = inline; 80 while ((c = nextrune(bp, 0)) >= 0) { 81 if (c == termchar) { 82 if (preserve) 83 rinsert(buf, c); 84 c = Bgetrune(bp); 85 if (c < 0) 86 break; 87 if (c != termchar) { 88 Bungetrune(bp); 89 return 1; 90 } 91 } 92 rinsert(buf, c); 93 } 94 SYNERR(line); fprint(2, "missing closing '\n"); 95 return 0; 96 } 97 /* 98 * assemble a back-quoted shell command 99 */ 100 static int 101 bquote(Biobuf *bp, Bufblock *buf) 102 { 103 int c, line; 104 int start; 105 char *end; 106 107 line = inline; 108 while ((c = Bgetrune(bp)) == ' ' || c == '\t') 109 ; 110 if(c != '{') { 111 SYNERR(line); 112 fprint(2, "missing opening { after `\n"); 113 return 0; 114 } 115 start = buf->current-buf->start; 116 while ((c = nextrune(bp, 0)) > 0) { 117 if (c == '\n') 118 break; 119 if (c == '}') { 120 insert(buf, '\n'); 121 insert(buf,0); 122 end = buf->current-1; 123 buf->current = buf->start+start; 124 if(initdone == 0){ 125 execinit(); 126 initdone = 1; 127 } 128 rcexec(buf->current, end, buf); 129 return 1; 130 } else if (QUOTE(c)) { 131 insert(buf, c); 132 if (!assquote(bp, buf, 1, c)) 133 return 0; 134 continue; 135 } 136 rinsert(buf, c); 137 } 138 SYNERR(line); 139 fprint(2, "missing closing } after `{\n"); 140 return 0; 141 } 142 143 static int 144 varsub(Biobuf *bp, Bufblock *buf) 145 { 146 int c; 147 Bufblock *buf2; 148 149 c = Bgetrune(bp); 150 if(c == '{') /* either ${name} or ${name: A%B==C%D}*/ 151 return expandvar(bp, buf); 152 Bungetrune(bp); 153 buf2 = varname(bp); 154 if (!buf2) 155 return 0; 156 varmatch(buf2->start, buf); 157 freebuf(buf2); 158 return 1; 159 } 160 161 static int 162 expandvar(Biobuf *bp, Bufblock *buf) 163 { 164 Bufblock *buf2; 165 int c; 166 int start; 167 Symtab *sym; 168 169 buf2 = varname(bp); 170 if (!buf2) 171 return 0; 172 c = Bgetrune(bp); 173 if (c == '}') { /* ${name} variant*/ 174 varmatch(buf2->start, buf); 175 freebuf(buf2); 176 return 1; 177 } 178 if (c != ':') { 179 SYNERR(-1); 180 fprint(2, "bad variable name <%s>\n", buf2->start); 181 freebuf(buf2); 182 return 0; 183 } 184 start = buf2->current-buf2->start; 185 while ((c = Bgetrune(bp)) != '}') { /* ${name:A%B=C%D} variant */ 186 switch(c) 187 { 188 case 0: 189 case '\n': 190 SYNERR(-1); 191 fprint(2, "missing '}'\n"); 192 freebuf(buf2); 193 return 0; 194 case '\'': 195 if (!assquote(bp, buf2, 0, c)) { 196 freebuf(buf2); 197 return 0; 198 } 199 break; 200 case '`': 201 if (!bquote(bp, buf2)) { 202 freebuf(buf2); 203 return 0; 204 } 205 break; 206 case '$': 207 if (!varsub(bp, buf2)) { 208 freebuf(buf2); 209 return 0; 210 } 211 break; 212 case ' ': 213 case '\t': 214 break; 215 default: 216 rinsert(buf2, c); 217 break; 218 } 219 } 220 insert(buf2, 0); 221 sym = symlook(buf2->start, S_VAR, 0); 222 if (!sym || !sym->value) 223 bufcpy(buf, buf2->start, start-2); 224 else 225 subsub((Word *) sym->value, buf2->start+start, buf); 226 freebuf(buf2); 227 return 1; 228 } 229 /* 230 * extract a variable name 231 */ 232 static Bufblock * 233 varname(Biobuf *bp) 234 { 235 Bufblock *buf; 236 int c; 237 238 buf = newbuf(); 239 c = Bgetrune(bp); 240 while (WORDCHR(c)) { 241 rinsert(buf, c); 242 c = Bgetrune(bp); 243 } 244 if (c < 0 || buf->current == buf->start) { 245 SYNERR(-1); 246 fprint(2, "bad variable name <%s>\n", buf->start); 247 freebuf(buf); 248 return 0; 249 } 250 Bungetrune(bp); 251 insert(buf, 0); 252 return buf; 253 } 254 /* 255 * search a string for unescaped characters in a pattern set 256 */ 257 char * 258 charin(char *cp, char *pat) 259 { 260 Rune r; 261 int n; 262 263 while (*cp) { 264 n = chartorune(&r, cp); 265 if (r == '\'') { /* skip quoted string */ 266 cp = squote(cp); /* n must = 1 */ 267 if (!cp) 268 return 0; 269 } else 270 if (utfrune(pat, r)) 271 return cp; 272 cp += n; 273 } 274 return 0; 275 } 276 /* 277 * skip a token in single quotes. 278 */ 279 static char * 280 squote(char *cp) 281 { 282 Rune r; 283 int n; 284 285 cp++; /* skip opening quote */ 286 while (*cp) { 287 n = chartorune(&r, cp); 288 if (r == '\'') { 289 n += chartorune(&r, cp+n); 290 if (r != '\'') 291 return(cp); 292 } 293 cp += n; 294 } 295 SYNERR(-1); /* should never occur */ 296 fprint(2, "missing closing '\n"); 297 return 0; 298 } 299 /* 300 * get next character stripping escaped newlines 301 * the flag specifies whether escaped newlines are to be elided or 302 * replaced with a blank. 303 */ 304 static long 305 nextrune(Biobuf *bp, int elide) 306 { 307 int c; 308 309 for (;;) { 310 c = Bgetrune(bp); 311 if (c == '\\') { 312 if (Bgetrune(bp) == '\n') { 313 inline++; 314 if (elide) 315 continue; 316 return ' '; 317 } 318 Bungetrune(bp); 319 } 320 if (c == '\n') 321 inline++; 322 return c; 323 } 324 return 0; 325 } 326