1 /* $NetBSD: expand.c,v 1.82 2009/01/18 00:30:54 lukem Exp $ */ 2 3 /*- 4 * Copyright (c) 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Kenneth Almquist. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 #ifndef lint 37 #if 0 38 static char sccsid[] = "@(#)expand.c 8.5 (Berkeley) 5/15/95"; 39 #else 40 __RCSID("$NetBSD: expand.c,v 1.82 2009/01/18 00:30:54 lukem Exp $"); 41 #endif 42 #endif /* not lint */ 43 44 #include <sys/types.h> 45 #include <sys/time.h> 46 #include <sys/stat.h> 47 #include <errno.h> 48 #include <dirent.h> 49 #include <unistd.h> 50 #include <pwd.h> 51 #include <stdlib.h> 52 #include <stdio.h> 53 54 /* 55 * Routines to expand arguments to commands. We have to deal with 56 * backquotes, shell variables, and file metacharacters. 57 */ 58 59 #include "shell.h" 60 #include "main.h" 61 #include "nodes.h" 62 #include "eval.h" 63 #include "expand.h" 64 #include "syntax.h" 65 #include "parser.h" 66 #include "jobs.h" 67 #include "options.h" 68 #include "var.h" 69 #include "input.h" 70 #include "output.h" 71 #include "memalloc.h" 72 #include "error.h" 73 #include "mystring.h" 74 #include "show.h" 75 76 /* 77 * Structure specifying which parts of the string should be searched 78 * for IFS characters. 79 */ 80 81 struct ifsregion { 82 struct ifsregion *next; /* next region in list */ 83 int begoff; /* offset of start of region */ 84 int endoff; /* offset of end of region */ 85 int inquotes; /* search for nul bytes only */ 86 }; 87 88 89 char *expdest; /* output of current string */ 90 struct nodelist *argbackq; /* list of back quote expressions */ 91 struct ifsregion ifsfirst; /* first struct in list of ifs regions */ 92 struct ifsregion *ifslastp; /* last struct in list */ 93 struct arglist exparg; /* holds expanded arg list */ 94 95 STATIC void argstr(char *, int); 96 STATIC char *exptilde(char *, int); 97 STATIC void expbackq(union node *, int, int); 98 STATIC int subevalvar(char *, char *, int, int, int, int); 99 STATIC char *evalvar(char *, int); 100 STATIC int varisset(char *, int); 101 STATIC void varvalue(char *, int, int, int); 102 STATIC void recordregion(int, int, int); 103 STATIC void removerecordregions(int); 104 STATIC void ifsbreakup(char *, struct arglist *); 105 STATIC void ifsfree(void); 106 STATIC void expandmeta(struct strlist *, int); 107 STATIC void expmeta(char *, char *); 108 STATIC void addfname(char *); 109 STATIC struct strlist *expsort(struct strlist *); 110 STATIC struct strlist *msort(struct strlist *, int); 111 STATIC int pmatch(char *, char *, int); 112 STATIC char *cvtnum(int, char *); 113 114 /* 115 * Expand shell variables and backquotes inside a here document. 116 */ 117 118 void 119 expandhere(union node *arg, int fd) 120 { 121 herefd = fd; 122 expandarg(arg, (struct arglist *)NULL, 0); 123 xwrite(fd, stackblock(), expdest - stackblock()); 124 } 125 126 127 /* 128 * Perform variable substitution and command substitution on an argument, 129 * placing the resulting list of arguments in arglist. If EXP_FULL is true, 130 * perform splitting and file name expansion. When arglist is NULL, perform 131 * here document expansion. 132 */ 133 134 void 135 expandarg(union node *arg, struct arglist *arglist, int flag) 136 { 137 struct strlist *sp; 138 char *p; 139 140 argbackq = arg->narg.backquote; 141 STARTSTACKSTR(expdest); 142 ifsfirst.next = NULL; 143 ifslastp = NULL; 144 argstr(arg->narg.text, flag); 145 if (arglist == NULL) { 146 return; /* here document expanded */ 147 } 148 STPUTC('\0', expdest); 149 p = grabstackstr(expdest); 150 exparg.lastp = &exparg.list; 151 /* 152 * TODO - EXP_REDIR 153 */ 154 if (flag & EXP_FULL) { 155 ifsbreakup(p, &exparg); 156 *exparg.lastp = NULL; 157 exparg.lastp = &exparg.list; 158 expandmeta(exparg.list, flag); 159 } else { 160 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ 161 rmescapes(p); 162 sp = (struct strlist *)stalloc(sizeof (struct strlist)); 163 sp->text = p; 164 *exparg.lastp = sp; 165 exparg.lastp = &sp->next; 166 } 167 ifsfree(); 168 *exparg.lastp = NULL; 169 if (exparg.list) { 170 *arglist->lastp = exparg.list; 171 arglist->lastp = exparg.lastp; 172 } 173 } 174 175 176 177 /* 178 * Perform variable and command substitution. 179 * If EXP_FULL is set, output CTLESC characters to allow for further processing. 180 * Otherwise treat $@ like $* since no splitting will be performed. 181 */ 182 183 STATIC void 184 argstr(char *p, int flag) 185 { 186 char c; 187 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ 188 int firsteq = 1; 189 const char *ifs = NULL; 190 int ifs_split = EXP_IFS_SPLIT; 191 192 if (flag & EXP_IFS_SPLIT) 193 ifs = ifsset() ? ifsval() : " \t\n"; 194 195 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE))) 196 p = exptilde(p, flag); 197 for (;;) { 198 switch (c = *p++) { 199 case '\0': 200 case CTLENDVAR: /* end of expanding yyy in ${xxx-yyy} */ 201 return; 202 case CTLQUOTEMARK: 203 /* "$@" syntax adherence hack */ 204 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=') 205 break; 206 if ((flag & EXP_FULL) != 0) 207 STPUTC(c, expdest); 208 ifs_split = 0; 209 break; 210 case CTLQUOTEEND: 211 ifs_split = EXP_IFS_SPLIT; 212 break; 213 case CTLESC: 214 if (quotes) 215 STPUTC(c, expdest); 216 c = *p++; 217 STPUTC(c, expdest); 218 break; 219 case CTLVAR: 220 p = evalvar(p, (flag & ~EXP_IFS_SPLIT) | (flag & ifs_split)); 221 break; 222 case CTLBACKQ: 223 case CTLBACKQ|CTLQUOTE: 224 expbackq(argbackq->n, c & CTLQUOTE, flag); 225 argbackq = argbackq->next; 226 break; 227 case CTLENDARI: 228 expari(flag); 229 break; 230 case ':': 231 case '=': 232 /* 233 * sort of a hack - expand tildes in variable 234 * assignments (after the first '=' and after ':'s). 235 */ 236 STPUTC(c, expdest); 237 if (flag & EXP_VARTILDE && *p == '~') { 238 if (c == '=') { 239 if (firsteq) 240 firsteq = 0; 241 else 242 break; 243 } 244 p = exptilde(p, flag); 245 } 246 break; 247 default: 248 STPUTC(c, expdest); 249 if (flag & EXP_IFS_SPLIT & ifs_split && strchr(ifs, c) != NULL) { 250 /* We need to get the output split here... */ 251 recordregion(expdest - stackblock() - 1, 252 expdest - stackblock(), 0); 253 } 254 break; 255 } 256 } 257 } 258 259 STATIC char * 260 exptilde(char *p, int flag) 261 { 262 char c, *startp = p; 263 struct passwd *pw; 264 const char *home; 265 int quotes = flag & (EXP_FULL | EXP_CASE); 266 267 while ((c = *p) != '\0') { 268 switch(c) { 269 case CTLESC: 270 return (startp); 271 case CTLQUOTEMARK: 272 return (startp); 273 case ':': 274 if (flag & EXP_VARTILDE) 275 goto done; 276 break; 277 case '/': 278 goto done; 279 } 280 p++; 281 } 282 done: 283 *p = '\0'; 284 if (*(startp+1) == '\0') { 285 if ((home = lookupvar("HOME")) == NULL) 286 goto lose; 287 } else { 288 if ((pw = getpwnam(startp+1)) == NULL) 289 goto lose; 290 home = pw->pw_dir; 291 } 292 if (*home == '\0') 293 goto lose; 294 *p = c; 295 while ((c = *home++) != '\0') { 296 if (quotes && SQSYNTAX[(int)c] == CCTL) 297 STPUTC(CTLESC, expdest); 298 STPUTC(c, expdest); 299 } 300 return (p); 301 lose: 302 *p = c; 303 return (startp); 304 } 305 306 307 STATIC void 308 removerecordregions(int endoff) 309 { 310 if (ifslastp == NULL) 311 return; 312 313 if (ifsfirst.endoff > endoff) { 314 while (ifsfirst.next != NULL) { 315 struct ifsregion *ifsp; 316 INTOFF; 317 ifsp = ifsfirst.next->next; 318 ckfree(ifsfirst.next); 319 ifsfirst.next = ifsp; 320 INTON; 321 } 322 if (ifsfirst.begoff > endoff) 323 ifslastp = NULL; 324 else { 325 ifslastp = &ifsfirst; 326 ifsfirst.endoff = endoff; 327 } 328 return; 329 } 330 331 ifslastp = &ifsfirst; 332 while (ifslastp->next && ifslastp->next->begoff < endoff) 333 ifslastp=ifslastp->next; 334 while (ifslastp->next != NULL) { 335 struct ifsregion *ifsp; 336 INTOFF; 337 ifsp = ifslastp->next->next; 338 ckfree(ifslastp->next); 339 ifslastp->next = ifsp; 340 INTON; 341 } 342 if (ifslastp->endoff > endoff) 343 ifslastp->endoff = endoff; 344 } 345 346 347 /* 348 * Expand arithmetic expression. Backup to start of expression, 349 * evaluate, place result in (backed up) result, adjust string position. 350 */ 351 void 352 expari(int flag) 353 { 354 char *p, *start; 355 intmax_t result; 356 int adjustment; 357 int begoff; 358 int quotes = flag & (EXP_FULL | EXP_CASE); 359 int quoted; 360 361 /* ifsfree(); */ 362 363 /* 364 * This routine is slightly over-complicated for 365 * efficiency. First we make sure there is 366 * enough space for the result, which may be bigger 367 * than the expression if we add exponentation. Next we 368 * scan backwards looking for the start of arithmetic. If the 369 * next previous character is a CTLESC character, then we 370 * have to rescan starting from the beginning since CTLESC 371 * characters have to be processed left to right. 372 */ 373 /* SPACE_NEEDED is enough for all digits, plus possible "-", plus 2 (why?) */ 374 #define SPACE_NEEDED ((sizeof(intmax_t) * CHAR_BIT + 2) / 3 + 1 + 2) 375 CHECKSTRSPACE((int)(SPACE_NEEDED - 2), expdest); 376 USTPUTC('\0', expdest); 377 start = stackblock(); 378 p = expdest - 1; 379 while (*p != CTLARI && p >= start) 380 --p; 381 if (*p != CTLARI) 382 error("missing CTLARI (shouldn't happen)"); 383 if (p > start && *(p-1) == CTLESC) 384 for (p = start; *p != CTLARI; p++) 385 if (*p == CTLESC) 386 p++; 387 388 if (p[1] == '"') 389 quoted=1; 390 else 391 quoted=0; 392 begoff = p - start; 393 removerecordregions(begoff); 394 if (quotes) 395 rmescapes(p+2); 396 result = arith(p+2); 397 fmtstr(p, SPACE_NEEDED, "%"PRIdMAX, result); 398 399 while (*p++) 400 ; 401 402 if (quoted == 0) 403 recordregion(begoff, p - 1 - start, 0); 404 adjustment = expdest - p + 1; 405 STADJUST(-adjustment, expdest); 406 } 407 408 409 /* 410 * Expand stuff in backwards quotes. 411 */ 412 413 STATIC void 414 expbackq(union node *cmd, int quoted, int flag) 415 { 416 struct backcmd in; 417 int i; 418 char buf[128]; 419 char *p; 420 char *dest = expdest; 421 struct ifsregion saveifs, *savelastp; 422 struct nodelist *saveargbackq; 423 char lastc; 424 int startloc = dest - stackblock(); 425 char const *syntax = quoted? DQSYNTAX : BASESYNTAX; 426 int saveherefd; 427 int quotes = flag & (EXP_FULL | EXP_CASE); 428 429 INTOFF; 430 saveifs = ifsfirst; 431 savelastp = ifslastp; 432 saveargbackq = argbackq; 433 saveherefd = herefd; 434 herefd = -1; 435 p = grabstackstr(dest); 436 evalbackcmd(cmd, &in); 437 ungrabstackstr(p, dest); 438 ifsfirst = saveifs; 439 ifslastp = savelastp; 440 argbackq = saveargbackq; 441 herefd = saveherefd; 442 443 p = in.buf; 444 lastc = '\0'; 445 for (;;) { 446 if (--in.nleft < 0) { 447 if (in.fd < 0) 448 break; 449 while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR); 450 TRACE(("expbackq: read returns %d\n", i)); 451 if (i <= 0) 452 break; 453 p = buf; 454 in.nleft = i - 1; 455 } 456 lastc = *p++; 457 if (lastc != '\0') { 458 if (quotes && syntax[(int)lastc] == CCTL) 459 STPUTC(CTLESC, dest); 460 STPUTC(lastc, dest); 461 } 462 } 463 464 /* Eat all trailing newlines */ 465 p = stackblock() + startloc; 466 while (dest > p && dest[-1] == '\n') 467 STUNPUTC(dest); 468 469 if (in.fd >= 0) 470 close(in.fd); 471 if (in.buf) 472 ckfree(in.buf); 473 if (in.jp) 474 back_exitstatus = waitforjob(in.jp); 475 if (quoted == 0) 476 recordregion(startloc, dest - stackblock(), 0); 477 TRACE(("evalbackq: size=%d: \"%.*s\"\n", 478 (int)((dest - stackblock()) - startloc), 479 (int)((dest - stackblock()) - startloc), 480 stackblock() + startloc)); 481 expdest = dest; 482 INTON; 483 } 484 485 486 487 STATIC int 488 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags) 489 { 490 char *startp; 491 char *loc = NULL; 492 char *q; 493 int c = 0; 494 int saveherefd = herefd; 495 struct nodelist *saveargbackq = argbackq; 496 int amount, how; 497 498 herefd = -1; 499 switch (subtype) { 500 case VSTRIMLEFT: 501 case VSTRIMLEFTMAX: 502 case VSTRIMRIGHT: 503 case VSTRIMRIGHTMAX: 504 how = (varflags & VSQUOTE) ? 0 : EXP_CASE; 505 break; 506 default: 507 how = 0; 508 break; 509 } 510 argstr(p, how); 511 STACKSTRNUL(expdest); 512 herefd = saveherefd; 513 argbackq = saveargbackq; 514 startp = stackblock() + startloc; 515 if (str == NULL) 516 str = stackblock() + strloc; 517 518 switch (subtype) { 519 case VSASSIGN: 520 setvar(str, startp, 0); 521 amount = startp - expdest; 522 STADJUST(amount, expdest); 523 varflags &= ~VSNUL; 524 return 1; 525 526 case VSQUESTION: 527 if (*p != CTLENDVAR) { 528 outfmt(&errout, "%s\n", startp); 529 error((char *)NULL); 530 } 531 error("%.*s: parameter %snot set", 532 (int)(p - str - 1), 533 str, (varflags & VSNUL) ? "null or " 534 : nullstr); 535 /* NOTREACHED */ 536 537 case VSTRIMLEFT: 538 for (loc = startp; loc < str; loc++) { 539 c = *loc; 540 *loc = '\0'; 541 if (patmatch(str, startp, varflags & VSQUOTE)) 542 goto recordleft; 543 *loc = c; 544 if ((varflags & VSQUOTE) && *loc == CTLESC) 545 loc++; 546 } 547 return 0; 548 549 case VSTRIMLEFTMAX: 550 for (loc = str - 1; loc >= startp;) { 551 c = *loc; 552 *loc = '\0'; 553 if (patmatch(str, startp, varflags & VSQUOTE)) 554 goto recordleft; 555 *loc = c; 556 loc--; 557 if ((varflags & VSQUOTE) && loc > startp && 558 *(loc - 1) == CTLESC) { 559 for (q = startp; q < loc; q++) 560 if (*q == CTLESC) 561 q++; 562 if (q > loc) 563 loc--; 564 } 565 } 566 return 0; 567 568 case VSTRIMRIGHT: 569 for (loc = str - 1; loc >= startp;) { 570 if (patmatch(str, loc, varflags & VSQUOTE)) 571 goto recordright; 572 loc--; 573 if ((varflags & VSQUOTE) && loc > startp && 574 *(loc - 1) == CTLESC) { 575 for (q = startp; q < loc; q++) 576 if (*q == CTLESC) 577 q++; 578 if (q > loc) 579 loc--; 580 } 581 } 582 return 0; 583 584 case VSTRIMRIGHTMAX: 585 for (loc = startp; loc < str - 1; loc++) { 586 if (patmatch(str, loc, varflags & VSQUOTE)) 587 goto recordright; 588 if ((varflags & VSQUOTE) && *loc == CTLESC) 589 loc++; 590 } 591 return 0; 592 593 default: 594 abort(); 595 } 596 597 recordleft: 598 *loc = c; 599 amount = ((str - 1) - (loc - startp)) - expdest; 600 STADJUST(amount, expdest); 601 while (loc != str - 1) 602 *startp++ = *loc++; 603 return 1; 604 605 recordright: 606 amount = loc - expdest; 607 STADJUST(amount, expdest); 608 STPUTC('\0', expdest); 609 STADJUST(-1, expdest); 610 return 1; 611 } 612 613 614 /* 615 * Expand a variable, and return a pointer to the next character in the 616 * input string. 617 */ 618 619 STATIC char * 620 evalvar(char *p, int flag) 621 { 622 int subtype; 623 int varflags; 624 char *var; 625 char *val; 626 int patloc; 627 int c; 628 int set; 629 int special; 630 int startloc; 631 int varlen; 632 int apply_ifs; 633 int quotes = flag & (EXP_FULL | EXP_CASE); 634 635 varflags = (unsigned char)*p++; 636 subtype = varflags & VSTYPE; 637 var = p; 638 special = !is_name(*p); 639 p = strchr(p, '=') + 1; 640 641 again: /* jump here after setting a variable with ${var=text} */ 642 if (special) { 643 set = varisset(var, varflags & VSNUL); 644 val = NULL; 645 } else { 646 val = lookupvar(var); 647 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) { 648 val = NULL; 649 set = 0; 650 } else 651 set = 1; 652 } 653 654 varlen = 0; 655 startloc = expdest - stackblock(); 656 657 if (!set && uflag) { 658 switch (subtype) { 659 case VSNORMAL: 660 case VSTRIMLEFT: 661 case VSTRIMLEFTMAX: 662 case VSTRIMRIGHT: 663 case VSTRIMRIGHTMAX: 664 case VSLENGTH: 665 error("%.*s: parameter not set", 666 (int)(p - var - 1), var); 667 /* NOTREACHED */ 668 } 669 } 670 671 if (set && subtype != VSPLUS) { 672 /* insert the value of the variable */ 673 if (special) { 674 varvalue(var, varflags & VSQUOTE, subtype, flag); 675 if (subtype == VSLENGTH) { 676 varlen = expdest - stackblock() - startloc; 677 STADJUST(-varlen, expdest); 678 } 679 } else { 680 char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX 681 : BASESYNTAX; 682 683 if (subtype == VSLENGTH) { 684 for (;*val; val++) 685 varlen++; 686 } else { 687 while (*val) { 688 if (quotes && syntax[(int)*val] == CCTL) 689 STPUTC(CTLESC, expdest); 690 STPUTC(*val++, expdest); 691 } 692 693 } 694 } 695 } 696 697 698 apply_ifs = ((varflags & VSQUOTE) == 0 || 699 (*var == '@' && shellparam.nparam != 1)); 700 701 switch (subtype) { 702 case VSLENGTH: 703 expdest = cvtnum(varlen, expdest); 704 break; 705 706 case VSNORMAL: 707 break; 708 709 case VSPLUS: 710 set = !set; 711 /* FALLTHROUGH */ 712 case VSMINUS: 713 if (!set) { 714 argstr(p, flag | (apply_ifs ? EXP_IFS_SPLIT : 0)); 715 /* 716 * ${x-a b c} doesn't get split, but removing the 717 * 'apply_ifs = 0' apparently breaks ${1+"$@"}.. 718 * ${x-'a b' c} should generate 2 args. 719 */ 720 /* We should have marked stuff already */ 721 apply_ifs = 0; 722 } 723 break; 724 725 case VSTRIMLEFT: 726 case VSTRIMLEFTMAX: 727 case VSTRIMRIGHT: 728 case VSTRIMRIGHTMAX: 729 if (!set) 730 break; 731 /* 732 * Terminate the string and start recording the pattern 733 * right after it 734 */ 735 STPUTC('\0', expdest); 736 patloc = expdest - stackblock(); 737 if (subevalvar(p, NULL, patloc, subtype, 738 startloc, varflags) == 0) { 739 int amount = (expdest - stackblock() - patloc) + 1; 740 STADJUST(-amount, expdest); 741 } 742 /* Remove any recorded regions beyond start of variable */ 743 removerecordregions(startloc); 744 apply_ifs = 1; 745 break; 746 747 case VSASSIGN: 748 case VSQUESTION: 749 if (set) 750 break; 751 if (subevalvar(p, var, 0, subtype, startloc, varflags)) { 752 varflags &= ~VSNUL; 753 /* 754 * Remove any recorded regions beyond 755 * start of variable 756 */ 757 removerecordregions(startloc); 758 goto again; 759 } 760 apply_ifs = 0; 761 break; 762 763 default: 764 abort(); 765 } 766 767 if (apply_ifs) 768 recordregion(startloc, expdest - stackblock(), 769 varflags & VSQUOTE); 770 771 if (subtype != VSNORMAL) { /* skip to end of alternative */ 772 int nesting = 1; 773 for (;;) { 774 if ((c = *p++) == CTLESC) 775 p++; 776 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { 777 if (set) 778 argbackq = argbackq->next; 779 } else if (c == CTLVAR) { 780 if ((*p++ & VSTYPE) != VSNORMAL) 781 nesting++; 782 } else if (c == CTLENDVAR) { 783 if (--nesting == 0) 784 break; 785 } 786 } 787 } 788 return p; 789 } 790 791 792 793 /* 794 * Test whether a specialized variable is set. 795 */ 796 797 STATIC int 798 varisset(char *name, int nulok) 799 { 800 if (*name == '!') 801 return backgndpid != -1; 802 else if (*name == '@' || *name == '*') { 803 if (*shellparam.p == NULL) 804 return 0; 805 806 if (nulok) { 807 char **av; 808 809 for (av = shellparam.p; *av; av++) 810 if (**av != '\0') 811 return 1; 812 return 0; 813 } 814 } else if (is_digit(*name)) { 815 char *ap; 816 int num = atoi(name); 817 818 if (num > shellparam.nparam) 819 return 0; 820 821 if (num == 0) 822 ap = arg0; 823 else 824 ap = shellparam.p[num - 1]; 825 826 if (nulok && (ap == NULL || *ap == '\0')) 827 return 0; 828 } 829 return 1; 830 } 831 832 833 834 /* 835 * Add the value of a specialized variable to the stack string. 836 */ 837 838 STATIC void 839 varvalue(char *name, int quoted, int subtype, int flag) 840 { 841 int num; 842 char *p; 843 int i; 844 char sep; 845 char **ap; 846 char const *syntax; 847 848 #define STRTODEST(p) \ 849 do {\ 850 if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH) { \ 851 syntax = quoted? DQSYNTAX : BASESYNTAX; \ 852 while (*p) { \ 853 if (syntax[(int)*p] == CCTL) \ 854 STPUTC(CTLESC, expdest); \ 855 STPUTC(*p++, expdest); \ 856 } \ 857 } else \ 858 while (*p) \ 859 STPUTC(*p++, expdest); \ 860 } while (0) 861 862 863 switch (*name) { 864 case '$': 865 num = rootpid; 866 goto numvar; 867 case '?': 868 num = exitstatus; 869 goto numvar; 870 case '#': 871 num = shellparam.nparam; 872 goto numvar; 873 case '!': 874 num = backgndpid; 875 numvar: 876 expdest = cvtnum(num, expdest); 877 break; 878 case '-': 879 for (i = 0; optlist[i].name; i++) { 880 if (optlist[i].val && optlist[i].letter) 881 STPUTC(optlist[i].letter, expdest); 882 } 883 break; 884 case '@': 885 if (flag & EXP_FULL && quoted) { 886 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { 887 STRTODEST(p); 888 if (*ap) 889 /* A NUL separates args inside "" */ 890 STPUTC('\0', expdest); 891 } 892 break; 893 } 894 /* fall through */ 895 case '*': 896 if (ifsset() != 0) 897 sep = ifsval()[0]; 898 else 899 sep = ' '; 900 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { 901 STRTODEST(p); 902 if (*ap && sep) 903 STPUTC(sep, expdest); 904 } 905 break; 906 case '0': 907 p = arg0; 908 STRTODEST(p); 909 break; 910 default: 911 if (is_digit(*name)) { 912 num = atoi(name); 913 if (num > 0 && num <= shellparam.nparam) { 914 p = shellparam.p[num - 1]; 915 STRTODEST(p); 916 } 917 } 918 break; 919 } 920 } 921 922 923 924 /* 925 * Record the fact that we have to scan this region of the 926 * string for IFS characters. 927 */ 928 929 STATIC void 930 recordregion(int start, int end, int inquotes) 931 { 932 struct ifsregion *ifsp; 933 934 if (ifslastp == NULL) { 935 ifsp = &ifsfirst; 936 } else { 937 if (ifslastp->endoff == start 938 && ifslastp->inquotes == inquotes) { 939 /* extend previous area */ 940 ifslastp->endoff = end; 941 return; 942 } 943 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion)); 944 ifslastp->next = ifsp; 945 } 946 ifslastp = ifsp; 947 ifslastp->next = NULL; 948 ifslastp->begoff = start; 949 ifslastp->endoff = end; 950 ifslastp->inquotes = inquotes; 951 } 952 953 954 955 /* 956 * Break the argument string into pieces based upon IFS and add the 957 * strings to the argument list. The regions of the string to be 958 * searched for IFS characters have been stored by recordregion. 959 */ 960 STATIC void 961 ifsbreakup(char *string, struct arglist *arglist) 962 { 963 struct ifsregion *ifsp; 964 struct strlist *sp; 965 char *start; 966 char *p; 967 char *q; 968 const char *ifs; 969 const char *ifsspc; 970 int had_param_ch = 0; 971 972 start = string; 973 974 if (ifslastp == NULL) { 975 /* Return entire argument, IFS doesn't apply to any of it */ 976 sp = (struct strlist *)stalloc(sizeof *sp); 977 sp->text = start; 978 *arglist->lastp = sp; 979 arglist->lastp = &sp->next; 980 return; 981 } 982 983 ifs = ifsset() ? ifsval() : " \t\n"; 984 985 for (ifsp = &ifsfirst; ifsp != NULL; ifsp = ifsp->next) { 986 p = string + ifsp->begoff; 987 while (p < string + ifsp->endoff) { 988 had_param_ch = 1; 989 q = p; 990 if (*p == CTLESC) 991 p++; 992 if (ifsp->inquotes) { 993 /* Only NULs (should be from "$@") end args */ 994 if (*p != 0) { 995 p++; 996 continue; 997 } 998 ifsspc = NULL; 999 } else { 1000 if (!strchr(ifs, *p)) { 1001 p++; 1002 continue; 1003 } 1004 had_param_ch = 0; 1005 ifsspc = strchr(" \t\n", *p); 1006 1007 /* Ignore IFS whitespace at start */ 1008 if (q == start && ifsspc != NULL) { 1009 p++; 1010 start = p; 1011 continue; 1012 } 1013 } 1014 1015 /* Save this argument... */ 1016 *q = '\0'; 1017 sp = (struct strlist *)stalloc(sizeof *sp); 1018 sp->text = start; 1019 *arglist->lastp = sp; 1020 arglist->lastp = &sp->next; 1021 p++; 1022 1023 if (ifsspc != NULL) { 1024 /* Ignore further trailing IFS whitespace */ 1025 for (; p < string + ifsp->endoff; p++) { 1026 q = p; 1027 if (*p == CTLESC) 1028 p++; 1029 if (strchr(ifs, *p) == NULL) { 1030 p = q; 1031 break; 1032 } 1033 if (strchr(" \t\n", *p) == NULL) { 1034 p++; 1035 break; 1036 } 1037 } 1038 } 1039 start = p; 1040 } 1041 } 1042 1043 /* 1044 * Save anything left as an argument. 1045 * Traditionally we have treated 'IFS=':'; set -- x$IFS' as 1046 * generating 2 arguments, the second of which is empty. 1047 * Some recent clarification of the Posix spec say that it 1048 * should only generate one.... 1049 */ 1050 if (had_param_ch || *start != 0) { 1051 sp = (struct strlist *)stalloc(sizeof *sp); 1052 sp->text = start; 1053 *arglist->lastp = sp; 1054 arglist->lastp = &sp->next; 1055 } 1056 } 1057 1058 STATIC void 1059 ifsfree(void) 1060 { 1061 while (ifsfirst.next != NULL) { 1062 struct ifsregion *ifsp; 1063 INTOFF; 1064 ifsp = ifsfirst.next->next; 1065 ckfree(ifsfirst.next); 1066 ifsfirst.next = ifsp; 1067 INTON; 1068 } 1069 ifslastp = NULL; 1070 ifsfirst.next = NULL; 1071 } 1072 1073 1074 1075 /* 1076 * Expand shell metacharacters. At this point, the only control characters 1077 * should be escapes. The results are stored in the list exparg. 1078 */ 1079 1080 char *expdir; 1081 1082 1083 STATIC void 1084 expandmeta(struct strlist *str, int flag) 1085 { 1086 char *p; 1087 struct strlist **savelastp; 1088 struct strlist *sp; 1089 char c; 1090 /* TODO - EXP_REDIR */ 1091 1092 while (str) { 1093 if (fflag) 1094 goto nometa; 1095 p = str->text; 1096 for (;;) { /* fast check for meta chars */ 1097 if ((c = *p++) == '\0') 1098 goto nometa; 1099 if (c == '*' || c == '?' || c == '[' || c == '!') 1100 break; 1101 } 1102 savelastp = exparg.lastp; 1103 INTOFF; 1104 if (expdir == NULL) { 1105 int i = strlen(str->text); 1106 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ 1107 } 1108 1109 expmeta(expdir, str->text); 1110 ckfree(expdir); 1111 expdir = NULL; 1112 INTON; 1113 if (exparg.lastp == savelastp) { 1114 /* 1115 * no matches 1116 */ 1117 nometa: 1118 *exparg.lastp = str; 1119 rmescapes(str->text); 1120 exparg.lastp = &str->next; 1121 } else { 1122 *exparg.lastp = NULL; 1123 *savelastp = sp = expsort(*savelastp); 1124 while (sp->next != NULL) 1125 sp = sp->next; 1126 exparg.lastp = &sp->next; 1127 } 1128 str = str->next; 1129 } 1130 } 1131 1132 1133 /* 1134 * Do metacharacter (i.e. *, ?, [...]) expansion. 1135 */ 1136 1137 STATIC void 1138 expmeta(char *enddir, char *name) 1139 { 1140 char *p; 1141 const char *cp; 1142 char *q; 1143 char *start; 1144 char *endname; 1145 int metaflag; 1146 struct stat statb; 1147 DIR *dirp; 1148 struct dirent *dp; 1149 int atend; 1150 int matchdot; 1151 1152 metaflag = 0; 1153 start = name; 1154 for (p = name ; ; p++) { 1155 if (*p == '*' || *p == '?') 1156 metaflag = 1; 1157 else if (*p == '[') { 1158 q = p + 1; 1159 if (*q == '!') 1160 q++; 1161 for (;;) { 1162 while (*q == CTLQUOTEMARK) 1163 q++; 1164 if (*q == CTLESC) 1165 q++; 1166 if (*q == '/' || *q == '\0') 1167 break; 1168 if (*++q == ']') { 1169 metaflag = 1; 1170 break; 1171 } 1172 } 1173 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) { 1174 metaflag = 1; 1175 } else if (*p == '\0') 1176 break; 1177 else if (*p == CTLQUOTEMARK) 1178 continue; 1179 else if (*p == CTLESC) 1180 p++; 1181 if (*p == '/') { 1182 if (metaflag) 1183 break; 1184 start = p + 1; 1185 } 1186 } 1187 if (metaflag == 0) { /* we've reached the end of the file name */ 1188 if (enddir != expdir) 1189 metaflag++; 1190 for (p = name ; ; p++) { 1191 if (*p == CTLQUOTEMARK) 1192 continue; 1193 if (*p == CTLESC) 1194 p++; 1195 *enddir++ = *p; 1196 if (*p == '\0') 1197 break; 1198 } 1199 if (metaflag == 0 || lstat(expdir, &statb) >= 0) 1200 addfname(expdir); 1201 return; 1202 } 1203 endname = p; 1204 if (start != name) { 1205 p = name; 1206 while (p < start) { 1207 while (*p == CTLQUOTEMARK) 1208 p++; 1209 if (*p == CTLESC) 1210 p++; 1211 *enddir++ = *p++; 1212 } 1213 } 1214 if (enddir == expdir) { 1215 cp = "."; 1216 } else if (enddir == expdir + 1 && *expdir == '/') { 1217 cp = "/"; 1218 } else { 1219 cp = expdir; 1220 enddir[-1] = '\0'; 1221 } 1222 if ((dirp = opendir(cp)) == NULL) 1223 return; 1224 if (enddir != expdir) 1225 enddir[-1] = '/'; 1226 if (*endname == 0) { 1227 atend = 1; 1228 } else { 1229 atend = 0; 1230 *endname++ = '\0'; 1231 } 1232 matchdot = 0; 1233 p = start; 1234 while (*p == CTLQUOTEMARK) 1235 p++; 1236 if (*p == CTLESC) 1237 p++; 1238 if (*p == '.') 1239 matchdot++; 1240 while (! int_pending() && (dp = readdir(dirp)) != NULL) { 1241 if (dp->d_name[0] == '.' && ! matchdot) 1242 continue; 1243 if (patmatch(start, dp->d_name, 0)) { 1244 if (atend) { 1245 scopy(dp->d_name, enddir); 1246 addfname(expdir); 1247 } else { 1248 for (p = enddir, cp = dp->d_name; 1249 (*p++ = *cp++) != '\0';) 1250 continue; 1251 p[-1] = '/'; 1252 expmeta(p, endname); 1253 } 1254 } 1255 } 1256 closedir(dirp); 1257 if (! atend) 1258 endname[-1] = '/'; 1259 } 1260 1261 1262 /* 1263 * Add a file name to the list. 1264 */ 1265 1266 STATIC void 1267 addfname(char *name) 1268 { 1269 char *p; 1270 struct strlist *sp; 1271 1272 p = stalloc(strlen(name) + 1); 1273 scopy(name, p); 1274 sp = (struct strlist *)stalloc(sizeof *sp); 1275 sp->text = p; 1276 *exparg.lastp = sp; 1277 exparg.lastp = &sp->next; 1278 } 1279 1280 1281 /* 1282 * Sort the results of file name expansion. It calculates the number of 1283 * strings to sort and then calls msort (short for merge sort) to do the 1284 * work. 1285 */ 1286 1287 STATIC struct strlist * 1288 expsort(struct strlist *str) 1289 { 1290 int len; 1291 struct strlist *sp; 1292 1293 len = 0; 1294 for (sp = str ; sp ; sp = sp->next) 1295 len++; 1296 return msort(str, len); 1297 } 1298 1299 1300 STATIC struct strlist * 1301 msort(struct strlist *list, int len) 1302 { 1303 struct strlist *p, *q = NULL; 1304 struct strlist **lpp; 1305 int half; 1306 int n; 1307 1308 if (len <= 1) 1309 return list; 1310 half = len >> 1; 1311 p = list; 1312 for (n = half ; --n >= 0 ; ) { 1313 q = p; 1314 p = p->next; 1315 } 1316 q->next = NULL; /* terminate first half of list */ 1317 q = msort(list, half); /* sort first half of list */ 1318 p = msort(p, len - half); /* sort second half */ 1319 lpp = &list; 1320 for (;;) { 1321 if (strcmp(p->text, q->text) < 0) { 1322 *lpp = p; 1323 lpp = &p->next; 1324 if ((p = *lpp) == NULL) { 1325 *lpp = q; 1326 break; 1327 } 1328 } else { 1329 *lpp = q; 1330 lpp = &q->next; 1331 if ((q = *lpp) == NULL) { 1332 *lpp = p; 1333 break; 1334 } 1335 } 1336 } 1337 return list; 1338 } 1339 1340 1341 1342 /* 1343 * Returns true if the pattern matches the string. 1344 */ 1345 1346 int 1347 patmatch(char *pattern, char *string, int squoted) 1348 { 1349 #ifdef notdef 1350 if (pattern[0] == '!' && pattern[1] == '!') 1351 return 1 - pmatch(pattern + 2, string); 1352 else 1353 #endif 1354 return pmatch(pattern, string, squoted); 1355 } 1356 1357 1358 STATIC int 1359 pmatch(char *pattern, char *string, int squoted) 1360 { 1361 char *p, *q; 1362 char c; 1363 1364 p = pattern; 1365 q = string; 1366 for (;;) { 1367 switch (c = *p++) { 1368 case '\0': 1369 goto breakloop; 1370 case CTLESC: 1371 if (squoted && *q == CTLESC) 1372 q++; 1373 if (*q++ != *p++) 1374 return 0; 1375 break; 1376 case CTLQUOTEMARK: 1377 continue; 1378 case '?': 1379 if (squoted && *q == CTLESC) 1380 q++; 1381 if (*q++ == '\0') 1382 return 0; 1383 break; 1384 case '*': 1385 c = *p; 1386 while (c == CTLQUOTEMARK || c == '*') 1387 c = *++p; 1388 if (c != CTLESC && c != CTLQUOTEMARK && 1389 c != '?' && c != '*' && c != '[') { 1390 while (*q != c) { 1391 if (squoted && *q == CTLESC && 1392 q[1] == c) 1393 break; 1394 if (*q == '\0') 1395 return 0; 1396 if (squoted && *q == CTLESC) 1397 q++; 1398 q++; 1399 } 1400 } 1401 do { 1402 if (pmatch(p, q, squoted)) 1403 return 1; 1404 if (squoted && *q == CTLESC) 1405 q++; 1406 } while (*q++ != '\0'); 1407 return 0; 1408 case '[': { 1409 char *endp; 1410 int invert, found; 1411 char chr; 1412 1413 endp = p; 1414 if (*endp == '!') 1415 endp++; 1416 for (;;) { 1417 while (*endp == CTLQUOTEMARK) 1418 endp++; 1419 if (*endp == '\0') 1420 goto dft; /* no matching ] */ 1421 if (*endp == CTLESC) 1422 endp++; 1423 if (*++endp == ']') 1424 break; 1425 } 1426 invert = 0; 1427 if (*p == '!') { 1428 invert++; 1429 p++; 1430 } 1431 found = 0; 1432 chr = *q++; 1433 if (squoted && chr == CTLESC) 1434 chr = *q++; 1435 if (chr == '\0') 1436 return 0; 1437 c = *p++; 1438 do { 1439 if (c == CTLQUOTEMARK) 1440 continue; 1441 if (c == CTLESC) 1442 c = *p++; 1443 if (*p == '-' && p[1] != ']') { 1444 p++; 1445 while (*p == CTLQUOTEMARK) 1446 p++; 1447 if (*p == CTLESC) 1448 p++; 1449 if (chr >= c && chr <= *p) 1450 found = 1; 1451 p++; 1452 } else { 1453 if (chr == c) 1454 found = 1; 1455 } 1456 } while ((c = *p++) != ']'); 1457 if (found == invert) 1458 return 0; 1459 break; 1460 } 1461 dft: default: 1462 if (squoted && *q == CTLESC) 1463 q++; 1464 if (*q++ != c) 1465 return 0; 1466 break; 1467 } 1468 } 1469 breakloop: 1470 if (*q != '\0') 1471 return 0; 1472 return 1; 1473 } 1474 1475 1476 1477 /* 1478 * Remove any CTLESC characters from a string. 1479 */ 1480 1481 void 1482 rmescapes(char *str) 1483 { 1484 char *p, *q; 1485 1486 p = str; 1487 while (*p != CTLESC && *p != CTLQUOTEMARK) { 1488 if (*p++ == '\0') 1489 return; 1490 } 1491 q = p; 1492 while (*p) { 1493 if (*p == CTLQUOTEMARK) { 1494 p++; 1495 continue; 1496 } 1497 if (*p == CTLESC) 1498 p++; 1499 *q++ = *p++; 1500 } 1501 *q = '\0'; 1502 } 1503 1504 1505 1506 /* 1507 * See if a pattern matches in a case statement. 1508 */ 1509 1510 int 1511 casematch(union node *pattern, char *val) 1512 { 1513 struct stackmark smark; 1514 int result; 1515 char *p; 1516 1517 setstackmark(&smark); 1518 argbackq = pattern->narg.backquote; 1519 STARTSTACKSTR(expdest); 1520 ifslastp = NULL; 1521 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); 1522 STPUTC('\0', expdest); 1523 p = grabstackstr(expdest); 1524 result = patmatch(p, val, 0); 1525 popstackmark(&smark); 1526 return result; 1527 } 1528 1529 /* 1530 * Our own itoa(). 1531 */ 1532 1533 STATIC char * 1534 cvtnum(int num, char *buf) 1535 { 1536 char temp[32]; 1537 int neg = num < 0; 1538 char *p = temp + 31; 1539 1540 temp[31] = '\0'; 1541 1542 do { 1543 *--p = num % 10 + '0'; 1544 } while ((num /= 10) != 0); 1545 1546 if (neg) 1547 *--p = '-'; 1548 1549 while (*p) 1550 STPUTC(*p++, buf); 1551 return buf; 1552 } 1553 1554 /* 1555 * Do most of the work for wordexp(3). 1556 */ 1557 1558 int 1559 wordexpcmd(int argc, char **argv) 1560 { 1561 size_t len; 1562 int i; 1563 1564 out1fmt("%d", argc - 1); 1565 out1c('\0'); 1566 for (i = 1, len = 0; i < argc; i++) 1567 len += strlen(argv[i]); 1568 out1fmt("%zd", len); 1569 out1c('\0'); 1570 for (i = 1; i < argc; i++) { 1571 out1str(argv[i]); 1572 out1c('\0'); 1573 } 1574 return (0); 1575 } 1576