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