1 /* $NetBSD: expand.c,v 1.91 2014/01/20 14:05:51 roy 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.91 2014/01/20 14:05:51 roy 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); 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 herefd = fd; 125 expandarg(arg, NULL, 0); 126 xwrite(fd, stackblock(), expdest - stackblock()); 127 } 128 129 130 /* 131 * Perform variable substitution and command substitution on an argument, 132 * placing the resulting list of arguments in arglist. If EXP_FULL is true, 133 * perform splitting and file name expansion. When arglist is NULL, perform 134 * here document expansion. 135 */ 136 137 void 138 expandarg(union node *arg, struct arglist *arglist, int flag) 139 { 140 struct strlist *sp; 141 char *p; 142 143 argbackq = arg->narg.backquote; 144 STARTSTACKSTR(expdest); 145 ifsfirst.next = NULL; 146 ifslastp = NULL; 147 argstr(arg->narg.text, flag); 148 if (arglist == NULL) { 149 return; /* here document expanded */ 150 } 151 STPUTC('\0', expdest); 152 p = grabstackstr(expdest); 153 exparg.lastp = &exparg.list; 154 /* 155 * TODO - EXP_REDIR 156 */ 157 if (flag & EXP_FULL) { 158 ifsbreakup(p, &exparg); 159 *exparg.lastp = NULL; 160 exparg.lastp = &exparg.list; 161 expandmeta(exparg.list, flag); 162 } else { 163 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ 164 rmescapes(p); 165 sp = (struct strlist *)stalloc(sizeof (struct strlist)); 166 sp->text = p; 167 *exparg.lastp = sp; 168 exparg.lastp = &sp->next; 169 } 170 ifsfree(); 171 *exparg.lastp = NULL; 172 if (exparg.list) { 173 *arglist->lastp = exparg.list; 174 arglist->lastp = exparg.lastp; 175 } 176 } 177 178 179 180 /* 181 * Perform variable and command substitution. 182 * If EXP_FULL is set, output CTLESC characters to allow for further processing. 183 * Otherwise treat $@ like $* since no splitting will be performed. 184 */ 185 186 STATIC void 187 argstr(char *p, int flag) 188 { 189 char c; 190 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ 191 int firsteq = 1; 192 const char *ifs = NULL; 193 int ifs_split = EXP_IFS_SPLIT; 194 195 if (flag & EXP_IFS_SPLIT) 196 ifs = ifsset() ? ifsval() : " \t\n"; 197 198 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE))) 199 p = exptilde(p, flag); 200 for (;;) { 201 switch (c = *p++) { 202 case '\0': 203 case CTLENDVAR: /* end of expanding yyy in ${xxx-yyy} */ 204 return; 205 case CTLQUOTEMARK: 206 /* "$@" syntax adherence hack */ 207 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=') 208 break; 209 if ((flag & EXP_FULL) != 0) 210 STPUTC(c, expdest); 211 ifs_split = 0; 212 break; 213 case CTLQUOTEEND: 214 ifs_split = EXP_IFS_SPLIT; 215 break; 216 case CTLESC: 217 if (quotes) 218 STPUTC(c, expdest); 219 c = *p++; 220 STPUTC(c, expdest); 221 break; 222 case CTLVAR: 223 p = evalvar(p, (flag & ~EXP_IFS_SPLIT) | (flag & ifs_split)); 224 break; 225 case CTLBACKQ: 226 case CTLBACKQ|CTLQUOTE: 227 expbackq(argbackq->n, c & CTLQUOTE, flag); 228 argbackq = argbackq->next; 229 break; 230 case CTLENDARI: 231 expari(flag); 232 break; 233 case ':': 234 case '=': 235 /* 236 * sort of a hack - expand tildes in variable 237 * assignments (after the first '=' and after ':'s). 238 */ 239 STPUTC(c, expdest); 240 if (flag & EXP_VARTILDE && *p == '~') { 241 if (c == '=') { 242 if (firsteq) 243 firsteq = 0; 244 else 245 break; 246 } 247 p = exptilde(p, flag); 248 } 249 break; 250 default: 251 STPUTC(c, expdest); 252 if (flag & ifs_split && strchr(ifs, c) != NULL) { 253 /* We need to get the output split here... */ 254 recordregion(expdest - stackblock() - 1, 255 expdest - stackblock(), 0); 256 } 257 break; 258 } 259 } 260 } 261 262 STATIC char * 263 exptilde(char *p, int flag) 264 { 265 char c, *startp = p; 266 struct passwd *pw; 267 const char *home; 268 int quotes = flag & (EXP_FULL | EXP_CASE); 269 270 while ((c = *p) != '\0') { 271 switch(c) { 272 case CTLESC: 273 return (startp); 274 case CTLQUOTEMARK: 275 return (startp); 276 case ':': 277 if (flag & EXP_VARTILDE) 278 goto done; 279 break; 280 case '/': 281 goto done; 282 } 283 p++; 284 } 285 done: 286 *p = '\0'; 287 if (*(startp+1) == '\0') { 288 if ((home = lookupvar("HOME")) == NULL) 289 goto lose; 290 } else { 291 if ((pw = getpwnam(startp+1)) == NULL) 292 goto lose; 293 home = pw->pw_dir; 294 } 295 if (*home == '\0') 296 goto lose; 297 *p = c; 298 while ((c = *home++) != '\0') { 299 if (quotes && SQSYNTAX[(int)c] == CCTL) 300 STPUTC(CTLESC, expdest); 301 STPUTC(c, expdest); 302 } 303 return (p); 304 lose: 305 *p = c; 306 return (startp); 307 } 308 309 310 STATIC void 311 removerecordregions(int endoff) 312 { 313 if (ifslastp == NULL) 314 return; 315 316 if (ifsfirst.endoff > endoff) { 317 while (ifsfirst.next != NULL) { 318 struct ifsregion *ifsp; 319 INTOFF; 320 ifsp = ifsfirst.next->next; 321 ckfree(ifsfirst.next); 322 ifsfirst.next = ifsp; 323 INTON; 324 } 325 if (ifsfirst.begoff > endoff) 326 ifslastp = NULL; 327 else { 328 ifslastp = &ifsfirst; 329 ifsfirst.endoff = endoff; 330 } 331 return; 332 } 333 334 ifslastp = &ifsfirst; 335 while (ifslastp->next && ifslastp->next->begoff < endoff) 336 ifslastp=ifslastp->next; 337 while (ifslastp->next != NULL) { 338 struct ifsregion *ifsp; 339 INTOFF; 340 ifsp = ifslastp->next->next; 341 ckfree(ifslastp->next); 342 ifslastp->next = ifsp; 343 INTON; 344 } 345 if (ifslastp->endoff > endoff) 346 ifslastp->endoff = endoff; 347 } 348 349 350 /* 351 * Expand arithmetic expression. Backup to start of expression, 352 * evaluate, place result in (backed up) result, adjust string position. 353 */ 354 void 355 expari(int flag) 356 { 357 char *p, *start; 358 intmax_t result; 359 int adjustment; 360 int begoff; 361 int quotes = flag & (EXP_FULL | EXP_CASE); 362 int quoted; 363 364 /* ifsfree(); */ 365 366 /* 367 * This routine is slightly over-complicated for 368 * efficiency. First we make sure there is 369 * enough space for the result, which may be bigger 370 * than the expression if we add exponentation. Next we 371 * scan backwards looking for the start of arithmetic. If the 372 * next previous character is a CTLESC character, then we 373 * have to rescan starting from the beginning since CTLESC 374 * characters have to be processed left to right. 375 */ 376 /* SPACE_NEEDED is enough for all digits, plus possible "-", plus 2 (why?) */ 377 #define SPACE_NEEDED ((sizeof(intmax_t) * CHAR_BIT + 2) / 3 + 1 + 2) 378 CHECKSTRSPACE((int)(SPACE_NEEDED - 2), expdest); 379 USTPUTC('\0', expdest); 380 start = stackblock(); 381 p = expdest - 1; 382 while (*p != CTLARI && p >= start) 383 --p; 384 if (*p != CTLARI) 385 error("missing CTLARI (shouldn't happen)"); 386 if (p > start && *(p-1) == CTLESC) 387 for (p = start; *p != CTLARI; p++) 388 if (*p == CTLESC) 389 p++; 390 391 if (p[1] == '"') 392 quoted=1; 393 else 394 quoted=0; 395 begoff = p - start; 396 removerecordregions(begoff); 397 if (quotes) 398 rmescapes(p+2); 399 result = arith(p+2); 400 fmtstr(p, SPACE_NEEDED, "%"PRIdMAX, result); 401 402 while (*p++) 403 ; 404 405 if (quoted == 0) 406 recordregion(begoff, p - 1 - start, 0); 407 adjustment = expdest - p + 1; 408 STADJUST(-adjustment, expdest); 409 } 410 411 412 /* 413 * Expand stuff in backwards quotes. 414 */ 415 416 STATIC void 417 expbackq(union node *cmd, int quoted, int flag) 418 { 419 struct backcmd in; 420 int i; 421 char buf[128]; 422 char *p; 423 char *dest = expdest; 424 struct ifsregion saveifs, *savelastp; 425 struct nodelist *saveargbackq; 426 char lastc; 427 int startloc = dest - stackblock(); 428 char const *syntax = quoted? DQSYNTAX : BASESYNTAX; 429 int saveherefd; 430 int quotes = flag & (EXP_FULL | EXP_CASE); 431 int nnl; 432 433 INTOFF; 434 saveifs = ifsfirst; 435 savelastp = ifslastp; 436 saveargbackq = argbackq; 437 saveherefd = herefd; 438 herefd = -1; 439 p = grabstackstr(dest); 440 evalbackcmd(cmd, &in); 441 ungrabstackstr(p, dest); 442 ifsfirst = saveifs; 443 ifslastp = savelastp; 444 argbackq = saveargbackq; 445 herefd = saveherefd; 446 447 p = in.buf; 448 lastc = '\0'; 449 nnl = 0; 450 for (;;) { 451 if (--in.nleft < 0) { 452 if (in.fd < 0) 453 break; 454 while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR); 455 TRACE(("expbackq: read returns %d\n", i)); 456 if (i <= 0) 457 break; 458 p = buf; 459 in.nleft = i - 1; 460 } 461 lastc = *p++; 462 if (lastc != '\0') { 463 if (lastc == '\n') 464 nnl++; 465 else { 466 CHECKSTRSPACE(nnl + 2, dest); 467 while (nnl > 0) { 468 nnl--; 469 USTPUTC('\n', dest); 470 } 471 if (quotes && syntax[(int)lastc] == CCTL) 472 USTPUTC(CTLESC, dest); 473 USTPUTC(lastc, dest); 474 } 475 } 476 } 477 478 if (in.fd >= 0) 479 close(in.fd); 480 if (in.buf) 481 ckfree(in.buf); 482 if (in.jp) 483 back_exitstatus = waitforjob(in.jp); 484 if (quoted == 0) 485 recordregion(startloc, dest - stackblock(), 0); 486 TRACE(("evalbackq: size=%d: \"%.*s\"\n", 487 (int)((dest - stackblock()) - startloc), 488 (int)((dest - stackblock()) - startloc), 489 stackblock() + startloc)); 490 expdest = dest; 491 INTON; 492 } 493 494 495 496 STATIC int 497 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags) 498 { 499 char *startp; 500 char *loc = NULL; 501 char *q; 502 int c = 0; 503 int saveherefd = herefd; 504 struct nodelist *saveargbackq = argbackq; 505 int amount, how; 506 507 herefd = -1; 508 switch (subtype) { 509 case VSTRIMLEFT: 510 case VSTRIMLEFTMAX: 511 case VSTRIMRIGHT: 512 case VSTRIMRIGHTMAX: 513 how = (varflags & VSQUOTE) ? 0 : EXP_CASE; 514 break; 515 default: 516 how = 0; 517 break; 518 } 519 argstr(p, how); 520 STACKSTRNUL(expdest); 521 herefd = saveherefd; 522 argbackq = saveargbackq; 523 startp = stackblock() + startloc; 524 if (str == NULL) 525 str = stackblock() + strloc; 526 527 switch (subtype) { 528 case VSASSIGN: 529 setvar(str, startp, 0); 530 amount = startp - expdest; 531 STADJUST(amount, expdest); 532 varflags &= ~VSNUL; 533 return 1; 534 535 case VSQUESTION: 536 if (*p != CTLENDVAR) { 537 outfmt(&errout, "%s\n", startp); 538 error(NULL); 539 } 540 error("%.*s: parameter %snot set", 541 (int)(p - str - 1), 542 str, (varflags & VSNUL) ? "null or " 543 : nullstr); 544 /* NOTREACHED */ 545 546 case VSTRIMLEFT: 547 for (loc = startp; loc < str; loc++) { 548 c = *loc; 549 *loc = '\0'; 550 if (patmatch(str, startp, varflags & VSQUOTE)) 551 goto recordleft; 552 *loc = c; 553 if ((varflags & VSQUOTE) && *loc == CTLESC) 554 loc++; 555 } 556 return 0; 557 558 case VSTRIMLEFTMAX: 559 for (loc = str - 1; loc >= startp;) { 560 c = *loc; 561 *loc = '\0'; 562 if (patmatch(str, startp, varflags & VSQUOTE)) 563 goto recordleft; 564 *loc = c; 565 loc--; 566 if ((varflags & VSQUOTE) && loc > startp && 567 *(loc - 1) == CTLESC) { 568 for (q = startp; q < loc; q++) 569 if (*q == CTLESC) 570 q++; 571 if (q > loc) 572 loc--; 573 } 574 } 575 return 0; 576 577 case VSTRIMRIGHT: 578 for (loc = str - 1; loc >= startp;) { 579 if (patmatch(str, loc, varflags & VSQUOTE)) 580 goto recordright; 581 loc--; 582 if ((varflags & VSQUOTE) && loc > startp && 583 *(loc - 1) == CTLESC) { 584 for (q = startp; q < loc; q++) 585 if (*q == CTLESC) 586 q++; 587 if (q > loc) 588 loc--; 589 } 590 } 591 return 0; 592 593 case VSTRIMRIGHTMAX: 594 for (loc = startp; loc < str - 1; loc++) { 595 if (patmatch(str, loc, varflags & VSQUOTE)) 596 goto recordright; 597 if ((varflags & VSQUOTE) && *loc == CTLESC) 598 loc++; 599 } 600 return 0; 601 602 default: 603 abort(); 604 } 605 606 recordleft: 607 *loc = c; 608 amount = ((str - 1) - (loc - startp)) - expdest; 609 STADJUST(amount, expdest); 610 while (loc != str - 1) 611 *startp++ = *loc++; 612 return 1; 613 614 recordright: 615 amount = loc - expdest; 616 STADJUST(amount, expdest); 617 STPUTC('\0', expdest); 618 STADJUST(-1, expdest); 619 return 1; 620 } 621 622 623 /* 624 * Expand a variable, and return a pointer to the next character in the 625 * input string. 626 */ 627 628 STATIC char * 629 evalvar(char *p, int flag) 630 { 631 int subtype; 632 int varflags; 633 char *var; 634 char *val; 635 int patloc; 636 int c; 637 int set; 638 int special; 639 int startloc; 640 int varlen; 641 int apply_ifs; 642 int quotes = flag & (EXP_FULL | EXP_CASE); 643 644 varflags = (unsigned char)*p++; 645 subtype = varflags & VSTYPE; 646 var = p; 647 special = !is_name(*p); 648 p = strchr(p, '=') + 1; 649 650 again: /* jump here after setting a variable with ${var=text} */ 651 if (varflags & VSLINENO) { 652 set = 1; 653 special = 0; 654 val = var; 655 p[-1] = '\0'; 656 } else if (special) { 657 set = varisset(var, varflags & VSNUL); 658 val = NULL; 659 } else { 660 val = lookupvar(var); 661 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) { 662 val = NULL; 663 set = 0; 664 } else 665 set = 1; 666 } 667 668 varlen = 0; 669 startloc = expdest - stackblock(); 670 671 if (!set && uflag && *var != '@' && *var != '*') { 672 switch (subtype) { 673 case VSNORMAL: 674 case VSTRIMLEFT: 675 case VSTRIMLEFTMAX: 676 case VSTRIMRIGHT: 677 case VSTRIMRIGHTMAX: 678 case VSLENGTH: 679 error("%.*s: parameter not set", 680 (int)(p - var - 1), var); 681 /* NOTREACHED */ 682 } 683 } 684 685 if (set && subtype != VSPLUS) { 686 /* insert the value of the variable */ 687 if (special) { 688 varvalue(var, varflags & VSQUOTE, subtype, flag); 689 if (subtype == VSLENGTH) { 690 varlen = expdest - stackblock() - startloc; 691 STADJUST(-varlen, expdest); 692 } 693 } else { 694 char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX 695 : BASESYNTAX; 696 697 if (subtype == VSLENGTH) { 698 for (;*val; val++) 699 varlen++; 700 } else { 701 while (*val) { 702 if (quotes && syntax[(int)*val] == CCTL) 703 STPUTC(CTLESC, expdest); 704 STPUTC(*val++, expdest); 705 } 706 707 } 708 } 709 } 710 711 712 if (flag & EXP_IN_QUOTES) 713 apply_ifs = 0; 714 else if (varflags & VSQUOTE) { 715 if (*var == '@' && shellparam.nparam != 1) 716 apply_ifs = 1; 717 else { 718 /* 719 * Mark so that we don't apply IFS if we recurse through 720 * here expanding $bar from "${foo-$bar}". 721 */ 722 flag |= EXP_IN_QUOTES; 723 apply_ifs = 0; 724 } 725 } else 726 apply_ifs = 1; 727 728 switch (subtype) { 729 case VSLENGTH: 730 expdest = cvtnum(varlen, expdest); 731 break; 732 733 case VSNORMAL: 734 break; 735 736 case VSPLUS: 737 set = !set; 738 /* FALLTHROUGH */ 739 case VSMINUS: 740 if (!set) { 741 argstr(p, flag | (apply_ifs ? EXP_IFS_SPLIT : 0)); 742 /* 743 * ${x-a b c} doesn't get split, but removing the 744 * 'apply_ifs = 0' apparently breaks ${1+"$@"}.. 745 * ${x-'a b' c} should generate 2 args. 746 */ 747 /* We should have marked stuff already */ 748 apply_ifs = 0; 749 } 750 break; 751 752 case VSTRIMLEFT: 753 case VSTRIMLEFTMAX: 754 case VSTRIMRIGHT: 755 case VSTRIMRIGHTMAX: 756 if (!set) 757 break; 758 /* 759 * Terminate the string and start recording the pattern 760 * right after it 761 */ 762 STPUTC('\0', expdest); 763 patloc = expdest - stackblock(); 764 if (subevalvar(p, NULL, patloc, subtype, 765 startloc, varflags) == 0) { 766 int amount = (expdest - stackblock() - patloc) + 1; 767 STADJUST(-amount, expdest); 768 } 769 /* Remove any recorded regions beyond start of variable */ 770 removerecordregions(startloc); 771 apply_ifs = 1; 772 break; 773 774 case VSASSIGN: 775 case VSQUESTION: 776 if (set) 777 break; 778 if (subevalvar(p, var, 0, subtype, startloc, varflags)) { 779 varflags &= ~VSNUL; 780 /* 781 * Remove any recorded regions beyond 782 * start of variable 783 */ 784 removerecordregions(startloc); 785 goto again; 786 } 787 apply_ifs = 0; 788 break; 789 790 default: 791 abort(); 792 } 793 p[-1] = '='; /* recover overwritten '=' */ 794 795 if (apply_ifs) 796 recordregion(startloc, expdest - stackblock(), 797 varflags & VSQUOTE); 798 799 if (subtype != VSNORMAL) { /* skip to end of alternative */ 800 int nesting = 1; 801 for (;;) { 802 if ((c = *p++) == CTLESC) 803 p++; 804 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { 805 if (set) 806 argbackq = argbackq->next; 807 } else if (c == CTLVAR) { 808 if ((*p++ & VSTYPE) != VSNORMAL) 809 nesting++; 810 } else if (c == CTLENDVAR) { 811 if (--nesting == 0) 812 break; 813 } 814 } 815 } 816 return p; 817 } 818 819 820 821 /* 822 * Test whether a specialized variable is set. 823 */ 824 825 STATIC int 826 varisset(char *name, int nulok) 827 { 828 if (*name == '!') 829 return backgndpid != -1; 830 else if (*name == '@' || *name == '*') { 831 if (*shellparam.p == NULL) 832 return 0; 833 834 if (nulok) { 835 char **av; 836 837 for (av = shellparam.p; *av; av++) 838 if (**av != '\0') 839 return 1; 840 return 0; 841 } 842 } else if (is_digit(*name)) { 843 char *ap; 844 int num = atoi(name); 845 846 if (num > shellparam.nparam) 847 return 0; 848 849 if (num == 0) 850 ap = arg0; 851 else 852 ap = shellparam.p[num - 1]; 853 854 if (nulok && (ap == NULL || *ap == '\0')) 855 return 0; 856 } 857 return 1; 858 } 859 860 861 862 /* 863 * Add the value of a specialized variable to the stack string. 864 */ 865 866 STATIC void 867 varvalue(char *name, int quoted, int subtype, int flag) 868 { 869 int num; 870 char *p; 871 int i; 872 char sep; 873 char **ap; 874 char const *syntax; 875 876 #define STRTODEST(p) \ 877 do {\ 878 if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH) { \ 879 syntax = quoted? DQSYNTAX : BASESYNTAX; \ 880 while (*p) { \ 881 if (syntax[(int)*p] == CCTL) \ 882 STPUTC(CTLESC, expdest); \ 883 STPUTC(*p++, expdest); \ 884 } \ 885 } else \ 886 while (*p) \ 887 STPUTC(*p++, expdest); \ 888 } while (0) 889 890 891 switch (*name) { 892 case '$': 893 num = rootpid; 894 goto numvar; 895 case '?': 896 num = exitstatus; 897 goto numvar; 898 case '#': 899 num = shellparam.nparam; 900 goto numvar; 901 case '!': 902 num = backgndpid; 903 numvar: 904 expdest = cvtnum(num, expdest); 905 break; 906 case '-': 907 for (i = 0; optlist[i].name; i++) { 908 if (optlist[i].val && optlist[i].letter) 909 STPUTC(optlist[i].letter, expdest); 910 } 911 break; 912 case '@': 913 if (flag & EXP_FULL && quoted) { 914 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { 915 STRTODEST(p); 916 if (*ap) 917 /* A NUL separates args inside "" */ 918 STPUTC('\0', expdest); 919 } 920 break; 921 } 922 /* fall through */ 923 case '*': 924 if (ifsset() != 0) 925 sep = ifsval()[0]; 926 else 927 sep = ' '; 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 = (struct strlist *)stalloc(sizeof *sp); 1005 sp->text = start; 1006 *arglist->lastp = sp; 1007 arglist->lastp = &sp->next; 1008 return; 1009 } 1010 1011 ifs = ifsset() ? ifsval() : " \t\n"; 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 = (struct strlist *)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 = (struct strlist *)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 = (struct strlist *)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