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