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 43 static void 44 copyto(endch, trimflag) 45 int trimflag; /* flag to check if argument will be trimmed */ 46 register unsigned char endch; 47 { 48 register unsigned int c; 49 register unsigned int d; 50 register unsigned char *pc; 51 52 while ((c = getch(endch, trimflag)) != endch && c) 53 if (quote) { 54 if(c == '\\') { /* don't interpret next character */ 55 if (staktop >= brkend) 56 growstak(staktop); 57 pushstak(c); 58 d = readwc(); 59 if(!escchar(d)) { /* both \ and following 60 character are quoted if next 61 character is not $, `, ", or \*/ 62 if (staktop >= brkend) 63 growstak(staktop); 64 pushstak('\\'); 65 if (staktop >= brkend) 66 growstak(staktop); 67 pushstak('\\'); 68 pc = readw(d); 69 /* push entire multibyte char */ 70 while(*pc) { 71 if (staktop >= brkend) 72 growstak(staktop); 73 pushstak(*pc++); 74 } 75 } else { 76 pc = readw(d); 77 /* d might be NULL */ 78 /* Evenif d is NULL, we have to save it */ 79 if (*pc) { 80 while (*pc) { 81 if (staktop >= brkend) 82 growstak(staktop); 83 pushstak(*pc++); 84 } 85 } else { 86 if (staktop >= brkend) 87 growstak(staktop); 88 pushstak(*pc); 89 } 90 } 91 } else { /* push escapes onto stack to quote characters */ 92 pc = readw(c); 93 if (staktop >= brkend) 94 growstak(staktop); 95 pushstak('\\'); 96 while(*pc) { 97 if (staktop >= brkend) 98 growstak(staktop); 99 pushstak(*pc++); 100 } 101 } 102 } else if(c == '\\') { 103 c = readwc(); /* get character to be escaped */ 104 if (staktop >= brkend) 105 growstak(staktop); 106 pushstak('\\'); 107 pc = readw(c); 108 /* c might be NULL */ 109 /* Evenif c is NULL, we have to save it */ 110 if (*pc) { 111 while (*pc) { 112 if (staktop >= brkend) 113 growstak(staktop); 114 pushstak(*pc++); 115 } 116 } else { 117 if (staktop >= brkend) 118 growstak(staktop); 119 pushstak(*pc); 120 } 121 } else { 122 pc = readw(c); 123 while (*pc) { 124 if (staktop >= brkend) 125 growstak(staktop); 126 pushstak(*pc++); 127 } 128 } 129 if (staktop >= brkend) 130 growstak(staktop); 131 zerostak(); 132 if (c != endch) 133 error(badsub); 134 } 135 136 static 137 skipto(endch) 138 register unsigned char endch; 139 { 140 /* 141 * skip chars up to } 142 */ 143 register 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 register 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 register 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 register 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 ? argp : (unsigned char *)badparam); 340 } 341 else if (c == '=') 342 { 343 if (n) 344 { 345 int strlngth = staktop - stakbot; 346 unsigned char *savptr = fixstak(); 347 unsigned char *newargp; 348 /* 349 * copy word onto stack, trim it, and then 350 * do assignment 351 */ 352 usestak(); 353 while(c = *argp) { 354 wchar_t wc; 355 register int len; 356 357 if ((len = mbtowc(&wc, (char *)argp, MB_LEN_MAX)) <= 0) 358 len = 1; 359 360 if(c == '\\' && trimflag) { 361 argp++; 362 if (*argp == 0) { 363 argp++; 364 continue; 365 } 366 if ((len = mbtowc(&wc, (char *)argp, MB_LEN_MAX)) <= 0) 367 len = 1; 368 } 369 while(len-- > 0) { 370 if (staktop >= brkend) 371 growstak(staktop); 372 pushstak(*argp++); 373 } 374 } 375 newargp = fixstak(); 376 assign(n, newargp); 377 tdystak(savptr); 378 memcpy(stakbot, savptr, strlngth); 379 staktop = stakbot + strlngth; 380 } 381 else 382 error(badsub); 383 } 384 } 385 else if (flags & setflg) 386 failed(id, unset); 387 goto retry; 388 } 389 else 390 peekc = c | MARK; 391 } 392 else if (d == endch) 393 return(d); 394 else if (d == SQUOTE) 395 { 396 comsubst(trimflag); 397 goto retry; 398 } 399 else if (d == DQUOTE && trimflag) 400 { 401 if(!quote) { 402 atflag = 0; 403 quoted++; 404 } 405 quote ^= QUOTE; 406 goto retry; 407 } 408 return(d); 409 } 410 411 unsigned char * 412 macro(as) 413 unsigned char *as; 414 { 415 /* 416 * Strip "" and do $ substitution 417 * Leaves result on top of stack 418 */ 419 register BOOL savqu = quoted; 420 register unsigned char savq = quote; 421 struct filehdr fb; 422 423 push(&fb); 424 estabf(as); 425 usestak(); 426 quote = 0; 427 quoted = 0; 428 copyto(0, 1); 429 pop(); 430 if (quoted && (stakbot == staktop)) { 431 if (staktop >= brkend) 432 growstak(staktop); 433 pushstak('\\'); 434 if (staktop >= brkend) 435 growstak(staktop); 436 pushstak('\0'); 437 /* 438 * above is the fix for *'.c' bug 439 */ 440 } 441 quote = savq; 442 quoted = savqu; 443 return(fixstak()); 444 } 445 /* Save file descriptor for command substitution */ 446 int savpipe = -1; 447 448 comsubst(trimflag) 449 int trimflag; /* used to determine if argument will later be trimmed */ 450 { 451 /* 452 * command substn 453 */ 454 struct fileblk cb; 455 register unsigned int d; 456 int strlngth = staktop - stakbot; 457 register unsigned char *oldstaktop; 458 unsigned char *savptr = fixstak(); 459 unsigned char *pc; 460 461 usestak(); 462 while ((d = readwc()) != SQUOTE && d) { 463 if(d == '\\') { 464 d = readwc(); 465 if(!escchar(d) || (d == '"' && !quote)) { 466 /* trim quotes for `, \, or " if command substitution is within 467 double quotes */ 468 if (staktop >= brkend) 469 growstak(staktop); 470 pushstak('\\'); 471 } 472 } 473 pc = readw(d); 474 /* d might be NULL */ 475 if (*pc) { 476 while (*pc) { 477 if (staktop >= brkend) 478 growstak(staktop); 479 pushstak(*pc++); 480 } 481 } else { 482 if (staktop >= brkend) 483 growstak(staktop); 484 pushstak(*pc); 485 } 486 } 487 { 488 register unsigned char *argc; 489 490 argc = fixstak(); 491 push(&cb); 492 estabf(argc); /* read from string */ 493 } 494 { 495 register struct trenod *t; 496 int pv[2]; 497 498 /* 499 * this is done like this so that the pipe 500 * is open only when needed 501 */ 502 t = makefork(FPOU, cmd(EOFSYM, MTFLG | NLFLG )); 503 chkpipe(pv); 504 savpipe = pv[OTPIPE]; 505 initf(pv[INPIPE]); /* read from pipe */ 506 execute(t, XEC_NOSTOP, (int)(flags & errflg), 0, pv); 507 close(pv[OTPIPE]); 508 savpipe = -1; 509 } 510 tdystak(savptr); 511 memcpy(stakbot, savptr, strlngth); 512 oldstaktop = staktop = stakbot + strlngth; 513 while (d = readwc()) { 514 if(quote || (d == '\\' && trimflag)) { 515 register unsigned char *rest; 516 /* quote output from command subst. if within double 517 quotes or backslash part of output */ 518 rest = readw(d); 519 if (staktop >= brkend) 520 growstak(staktop); 521 pushstak('\\'); 522 while(d = *rest++) { 523 /* Pick up all of multibyte character */ 524 if (staktop >= brkend) 525 growstak(staktop); 526 pushstak(d); 527 } 528 } 529 else { 530 pc = readw(d); 531 while (*pc) { 532 if (staktop >= brkend) 533 growstak(staktop); 534 pushstak(*pc++); 535 } 536 } 537 } 538 { 539 extern pid_t parent; 540 int stat; 541 register rc; 542 int ret = 0; 543 544 while ((ret = waitpid(parent,&stat,0)) != parent) { 545 /* break out if waitpid(2) has failed */ 546 if (ret == -1) 547 break; 548 } 549 if (WIFEXITED(stat)) 550 rc = WEXITSTATUS(stat); 551 else 552 rc = (WTERMSIG(stat) | SIGFLG); 553 if (rc && (flags & errflg)) 554 exitsh(rc); 555 exitval = rc; 556 flags |= eflag; 557 exitset(); 558 } 559 while (oldstaktop != staktop) 560 { /* strip off trailing newlines from command substitution only */ 561 if ((*--staktop) != NL) 562 { 563 ++staktop; 564 break; 565 } else if(quote) 566 staktop--; /* skip past backslashes if quoting */ 567 } 568 pop(); 569 } 570 571 #define CPYSIZ 512 572 573 subst(in, ot) 574 int in, ot; 575 { 576 register unsigned int c; 577 struct fileblk fb; 578 register int count = CPYSIZ; 579 unsigned char *pc; 580 581 push(&fb); 582 initf(in); 583 /* 584 * DQUOTE used to stop it from quoting 585 */ 586 while (c = (getch(DQUOTE, 0))) /* read characters from here document 587 and interpret them */ 588 { 589 if(c == '\\') { 590 c = readwc(); /* check if character in here document is 591 escaped */ 592 if(!escchar(c) || c == '"') { 593 if (staktop >= brkend) 594 growstak(staktop); 595 pushstak('\\'); 596 } 597 } 598 pc = readw(c); 599 /* c might be NULL */ 600 if (*pc) { 601 while (*pc) { 602 if (staktop >= brkend) 603 growstak(staktop); 604 pushstak(*pc++); 605 } 606 } else { 607 if (staktop >= brkend) 608 growstak(staktop); 609 pushstak(*pc); 610 } 611 if (--count == 0) 612 { 613 flush(ot); 614 count = CPYSIZ; 615 } 616 } 617 flush(ot); 618 pop(); 619 } 620 621 flush(ot) 622 { 623 write(ot, stakbot, staktop - stakbot); 624 if (flags & execpr) 625 write(output, stakbot, staktop - stakbot); 626 staktop = stakbot; 627 } 628