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