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