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