1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1995 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 /* 32 * UNIX shell 33 */ 34 35 #include "defs.h" 36 #include "sym.h" 37 #include <wait.h> 38 39 static unsigned char quote; /* used locally */ 40 static unsigned char quoted; /* used locally */ 41 static int getch(); 42 static void comsubst(int); 43 static void flush(int); 44 45 static void 46 copyto(unsigned char endch, int trimflag) 47 /* trimflag - flag to check if argument will be trimmed */ 48 { 49 unsigned int c; 50 unsigned int d; 51 unsigned char *pc; 52 53 while ((c = getch(endch, trimflag)) != endch && c) 54 if (quote) { 55 if(c == '\\') { /* don't interpret next character */ 56 if (staktop >= brkend) 57 growstak(staktop); 58 pushstak(c); 59 d = readwc(); 60 if(!escchar(d)) { /* both \ and following 61 character are quoted if next 62 character is not $, `, ", or \*/ 63 if (staktop >= brkend) 64 growstak(staktop); 65 pushstak('\\'); 66 if (staktop >= brkend) 67 growstak(staktop); 68 pushstak('\\'); 69 pc = readw(d); 70 /* push entire multibyte char */ 71 while(*pc) { 72 if (staktop >= brkend) 73 growstak(staktop); 74 pushstak(*pc++); 75 } 76 } else { 77 pc = readw(d); 78 /* d might be NULL */ 79 /* Evenif d is NULL, we have to save it */ 80 if (*pc) { 81 while (*pc) { 82 if (staktop >= brkend) 83 growstak(staktop); 84 pushstak(*pc++); 85 } 86 } else { 87 if (staktop >= brkend) 88 growstak(staktop); 89 pushstak(*pc); 90 } 91 } 92 } else { /* push escapes onto stack to quote characters */ 93 pc = readw(c); 94 if (staktop >= brkend) 95 growstak(staktop); 96 pushstak('\\'); 97 while(*pc) { 98 if (staktop >= brkend) 99 growstak(staktop); 100 pushstak(*pc++); 101 } 102 } 103 } else if(c == '\\') { 104 c = readwc(); /* get character to be escaped */ 105 if (staktop >= brkend) 106 growstak(staktop); 107 pushstak('\\'); 108 pc = readw(c); 109 /* c might be NULL */ 110 /* Evenif c is NULL, we have to save it */ 111 if (*pc) { 112 while (*pc) { 113 if (staktop >= brkend) 114 growstak(staktop); 115 pushstak(*pc++); 116 } 117 } else { 118 if (staktop >= brkend) 119 growstak(staktop); 120 pushstak(*pc); 121 } 122 } else { 123 pc = readw(c); 124 while (*pc) { 125 if (staktop >= brkend) 126 growstak(staktop); 127 pushstak(*pc++); 128 } 129 } 130 if (staktop >= brkend) 131 growstak(staktop); 132 zerostak(); 133 if (c != endch) 134 error(badsub); 135 } 136 137 static void 138 skipto(unsigned char endch) 139 { 140 /* 141 * skip chars up to } 142 */ 143 unsigned int c; 144 145 while ((c = readwc()) && c != endch) 146 { 147 switch (c) 148 { 149 case SQUOTE: 150 skipto(SQUOTE); 151 break; 152 153 case DQUOTE: 154 skipto(DQUOTE); 155 break; 156 157 case DOLLAR: 158 if (readwc() == BRACE) 159 skipto('}'); 160 } 161 } 162 if (c != endch) 163 error(badsub); 164 } 165 166 static 167 int getch(endch, trimflag) 168 unsigned char endch; 169 int trimflag; /* flag to check if an argument is going to be trimmed, here document 170 output is never trimmed 171 */ 172 { 173 unsigned int d; 174 int atflag; /* flag to check if $@ has already been seen within double 175 quotes */ 176 retry: 177 d = readwc(); 178 if (!subchar(d)) 179 return(d); 180 181 if (d == DOLLAR) 182 { 183 unsigned int c; 184 185 if ((c = readwc(), dolchar(c))) 186 { 187 struct namnod *n = (struct namnod *)NIL; 188 int dolg = 0; 189 BOOL bra; 190 BOOL nulflg; 191 unsigned char *argp, *v; 192 unsigned char idb[2]; 193 unsigned char *id = idb; 194 195 if (bra = (c == BRACE)) 196 c = readwc(); 197 if (letter(c)) 198 { 199 argp = (unsigned char *)relstak(); 200 while (alphanum(c)) 201 { 202 if (staktop >= brkend) 203 growstak(staktop); 204 pushstak(c); 205 c = readwc(); 206 } 207 if (staktop >= brkend) 208 growstak(staktop); 209 zerostak(); 210 n = lookup(absstak(argp)); 211 setstak(argp); 212 if (n->namflg & N_FUNCTN) 213 error(badsub); 214 v = n->namval; 215 id = (unsigned char *)n->namid; 216 peekc = c | MARK; 217 } 218 else if (digchar(c)) 219 { 220 *id = c; 221 idb[1] = 0; 222 if (astchar(c)) 223 { 224 if(c == '@' && !atflag && quote) { 225 quoted--; 226 atflag = 1; 227 } 228 dolg = 1; 229 c = '1'; 230 } 231 c -= '0'; 232 v = ((c == 0) ? cmdadr : ((int)c <= dolc) ? dolv[c] : (unsigned char *)(dolg = 0)); 233 } 234 else if (c == '$') 235 v = pidadr; 236 else if (c == '!') 237 v = pcsadr; 238 else if (c == '#') 239 { 240 itos(dolc); 241 v = numbuf; 242 } 243 else if (c == '?') 244 { 245 itos(retval); 246 v = numbuf; 247 } 248 else if (c == '-') 249 v = flagadr; 250 else if (bra) 251 error(badsub); 252 else 253 goto retry; 254 c = readwc(); 255 if (c == ':' && bra) /* null and unset fix */ 256 { 257 nulflg = 1; 258 c = readwc(); 259 } 260 else 261 nulflg = 0; 262 if (!defchar(c) && bra) 263 error(badsub); 264 argp = 0; 265 if (bra) 266 { 267 if (c != '}') 268 { 269 argp = (unsigned char *)relstak(); 270 if ((v == 0 || (nulflg && *v == 0)) ^ (setchar(c))) 271 copyto('}', trimflag); 272 else 273 skipto('}'); 274 argp = absstak(argp); 275 } 276 } 277 else 278 { 279 peekc = c | MARK; 280 c = 0; 281 } 282 if (v && (!nulflg || *v)) 283 { 284 285 if (c != '+') 286 { 287 for (;;) 288 { 289 if (*v == 0 && quote) { 290 if (staktop >= brkend) 291 growstak(staktop); 292 pushstak('\\'); 293 if (staktop >= brkend) 294 growstak(staktop); 295 pushstak('\0'); 296 } else { 297 while (c = *v) { 298 wchar_t wc; 299 int length; 300 if ((length = mbtowc(&wc, (char *)v, MB_LEN_MAX)) <= 0) 301 length = 1; 302 303 if(quote || (c == '\\' && trimflag)) { 304 if (staktop >= brkend) 305 growstak(staktop); 306 pushstak('\\'); 307 } 308 while(length-- > 0) { 309 if (staktop >= brkend) 310 growstak(staktop); 311 pushstak(*v++); 312 } 313 } 314 } 315 316 if (dolg == 0 || (++dolg > dolc)) 317 break; 318 else /* $* and $@ expansion */ 319 { 320 v = dolv[dolg]; 321 if(*id == '*' && quote) { 322 /* push quoted space so that " $* " will not be broken into separate arguments */ 323 if (staktop >= brkend) 324 growstak(staktop); 325 pushstak('\\'); 326 } 327 if (staktop >= brkend) 328 growstak(staktop); 329 pushstak(' '); 330 } 331 } 332 } 333 } 334 else if (argp) 335 { 336 if (c == '?') { 337 if(trimflag) 338 trim(argp); 339 failed(id, *argp ? (const char *)argp : 340 badparam); 341 } 342 else if (c == '=') 343 { 344 if (n) 345 { 346 int strlngth = staktop - stakbot; 347 unsigned char *savptr = fixstak(); 348 unsigned char *newargp; 349 /* 350 * copy word onto stack, trim it, and then 351 * do assignment 352 */ 353 usestak(); 354 while(c = *argp) { 355 wchar_t wc; 356 int len; 357 358 if ((len = mbtowc(&wc, (char *)argp, MB_LEN_MAX)) <= 0) 359 len = 1; 360 361 if(c == '\\' && trimflag) { 362 argp++; 363 if (*argp == 0) { 364 argp++; 365 continue; 366 } 367 if ((len = mbtowc(&wc, (char *)argp, MB_LEN_MAX)) <= 0) 368 len = 1; 369 } 370 while(len-- > 0) { 371 if (staktop >= brkend) 372 growstak(staktop); 373 pushstak(*argp++); 374 } 375 } 376 newargp = fixstak(); 377 assign(n, newargp); 378 tdystak(savptr); 379 memcpy(stakbot, savptr, strlngth); 380 staktop = stakbot + strlngth; 381 } 382 else 383 error(badsub); 384 } 385 } 386 else if (flags & setflg) 387 failed(id, unset); 388 goto retry; 389 } 390 else 391 peekc = c | MARK; 392 } 393 else if (d == endch) 394 return(d); 395 else if (d == SQUOTE) 396 { 397 comsubst(trimflag); 398 goto retry; 399 } 400 else if (d == DQUOTE && trimflag) 401 { 402 if(!quote) { 403 atflag = 0; 404 quoted++; 405 } 406 quote ^= QUOTE; 407 goto retry; 408 } 409 return(d); 410 } 411 412 unsigned char * 413 macro(as) 414 unsigned char *as; 415 { 416 /* 417 * Strip "" and do $ substitution 418 * Leaves result on top of stack 419 */ 420 BOOL savqu = quoted; 421 unsigned char savq = quote; 422 struct filehdr fb; 423 424 push(&fb); 425 estabf(as); 426 usestak(); 427 quote = 0; 428 quoted = 0; 429 copyto(0, 1); 430 pop(); 431 if (quoted && (stakbot == staktop)) { 432 if (staktop >= brkend) 433 growstak(staktop); 434 pushstak('\\'); 435 if (staktop >= brkend) 436 growstak(staktop); 437 pushstak('\0'); 438 /* 439 * above is the fix for *'.c' bug 440 */ 441 } 442 quote = savq; 443 quoted = savqu; 444 return(fixstak()); 445 } 446 /* Save file descriptor for command substitution */ 447 int savpipe = -1; 448 449 static void 450 comsubst(int trimflag) 451 /* trimflag - used to determine if argument will later be trimmed */ 452 { 453 /* 454 * command substn 455 */ 456 struct fileblk cb; 457 unsigned int d; 458 int strlngth = staktop - stakbot; 459 unsigned char *oldstaktop; 460 unsigned char *savptr = fixstak(); 461 unsigned char *pc; 462 463 usestak(); 464 while ((d = readwc()) != SQUOTE && d) { 465 if(d == '\\') { 466 d = readwc(); 467 if(!escchar(d) || (d == '"' && !quote)) { 468 /* trim quotes for `, \, or " if command substitution is within 469 double quotes */ 470 if (staktop >= brkend) 471 growstak(staktop); 472 pushstak('\\'); 473 } 474 } 475 pc = readw(d); 476 /* d might be NULL */ 477 if (*pc) { 478 while (*pc) { 479 if (staktop >= brkend) 480 growstak(staktop); 481 pushstak(*pc++); 482 } 483 } else { 484 if (staktop >= brkend) 485 growstak(staktop); 486 pushstak(*pc); 487 } 488 } 489 { 490 unsigned char *argc; 491 492 argc = fixstak(); 493 push(&cb); 494 estabf(argc); /* read from string */ 495 } 496 { 497 struct trenod *t; 498 int pv[2]; 499 500 /* 501 * this is done like this so that the pipe 502 * is open only when needed 503 */ 504 t = makefork(FPOU, cmd(EOFSYM, MTFLG | NLFLG )); 505 chkpipe(pv); 506 savpipe = pv[OTPIPE]; 507 initf(pv[INPIPE]); /* read from pipe */ 508 execute(t, XEC_NOSTOP, (int)(flags & errflg), 0, pv); 509 close(pv[OTPIPE]); 510 savpipe = -1; 511 } 512 tdystak(savptr); 513 memcpy(stakbot, savptr, strlngth); 514 oldstaktop = staktop = stakbot + strlngth; 515 while (d = readwc()) { 516 if(quote || (d == '\\' && trimflag)) { 517 unsigned char *rest; 518 /* quote output from command subst. if within double 519 quotes or backslash part of output */ 520 rest = readw(d); 521 if (staktop >= brkend) 522 growstak(staktop); 523 pushstak('\\'); 524 while(d = *rest++) { 525 /* Pick up all of multibyte character */ 526 if (staktop >= brkend) 527 growstak(staktop); 528 pushstak(d); 529 } 530 } 531 else { 532 pc = readw(d); 533 while (*pc) { 534 if (staktop >= brkend) 535 growstak(staktop); 536 pushstak(*pc++); 537 } 538 } 539 } 540 { 541 extern pid_t parent; 542 int stat; 543 int rc; 544 int ret = 0; 545 546 while ((ret = waitpid(parent,&stat,0)) != parent) { 547 /* break out if waitpid(2) has failed */ 548 if (ret == -1) 549 break; 550 } 551 if (WIFEXITED(stat)) 552 rc = WEXITSTATUS(stat); 553 else 554 rc = (WTERMSIG(stat) | SIGFLG); 555 if (rc && (flags & errflg)) 556 exitsh(rc); 557 exitval = rc; 558 flags |= eflag; 559 exitset(); 560 } 561 while (oldstaktop != staktop) 562 { /* strip off trailing newlines from command substitution only */ 563 if ((*--staktop) != NL) 564 { 565 ++staktop; 566 break; 567 } else if(quote) 568 staktop--; /* skip past backslashes if quoting */ 569 } 570 pop(); 571 } 572 573 #define CPYSIZ 512 574 575 void 576 subst(int in, int ot) 577 { 578 unsigned int c; 579 struct fileblk fb; 580 int count = CPYSIZ; 581 unsigned char *pc; 582 583 push(&fb); 584 initf(in); 585 /* 586 * DQUOTE used to stop it from quoting 587 */ 588 while (c = (getch(DQUOTE, 0))) /* read characters from here document 589 and interpret them */ 590 { 591 if(c == '\\') { 592 c = readwc(); /* check if character in here document is 593 escaped */ 594 if(!escchar(c) || c == '"') { 595 if (staktop >= brkend) 596 growstak(staktop); 597 pushstak('\\'); 598 } 599 } 600 pc = readw(c); 601 /* c might be NULL */ 602 if (*pc) { 603 while (*pc) { 604 if (staktop >= brkend) 605 growstak(staktop); 606 pushstak(*pc++); 607 } 608 } else { 609 if (staktop >= brkend) 610 growstak(staktop); 611 pushstak(*pc); 612 } 613 if (--count == 0) 614 { 615 flush(ot); 616 count = CPYSIZ; 617 } 618 } 619 flush(ot); 620 pop(); 621 } 622 623 static void 624 flush(int ot) 625 { 626 write(ot, stakbot, staktop - stakbot); 627 if (flags & execpr) 628 write(output, stakbot, staktop - stakbot); 629 staktop = stakbot; 630 } 631