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