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