1 /* $NetBSD: expand.c,v 1.84 2011/06/18 21:18:46 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.84 2011/06/18 21:18:46 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 <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, (struct arglist *)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 430 INTOFF; 431 saveifs = ifsfirst; 432 savelastp = ifslastp; 433 saveargbackq = argbackq; 434 saveherefd = herefd; 435 herefd = -1; 436 p = grabstackstr(dest); 437 evalbackcmd(cmd, &in); 438 ungrabstackstr(p, dest); 439 ifsfirst = saveifs; 440 ifslastp = savelastp; 441 argbackq = saveargbackq; 442 herefd = saveherefd; 443 444 p = in.buf; 445 lastc = '\0'; 446 for (;;) { 447 if (--in.nleft < 0) { 448 if (in.fd < 0) 449 break; 450 while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR); 451 TRACE(("expbackq: read returns %d\n", i)); 452 if (i <= 0) 453 break; 454 p = buf; 455 in.nleft = i - 1; 456 } 457 lastc = *p++; 458 if (lastc != '\0') { 459 if (quotes && syntax[(int)lastc] == CCTL) 460 STPUTC(CTLESC, dest); 461 STPUTC(lastc, dest); 462 } 463 } 464 465 /* Eat all trailing newlines */ 466 p = stackblock() + startloc; 467 while (dest > p && dest[-1] == '\n') 468 STUNPUTC(dest); 469 470 if (in.fd >= 0) 471 close(in.fd); 472 if (in.buf) 473 ckfree(in.buf); 474 if (in.jp) 475 back_exitstatus = waitforjob(in.jp); 476 if (quoted == 0) 477 recordregion(startloc, dest - stackblock(), 0); 478 TRACE(("evalbackq: size=%d: \"%.*s\"\n", 479 (int)((dest - stackblock()) - startloc), 480 (int)((dest - stackblock()) - startloc), 481 stackblock() + startloc)); 482 expdest = dest; 483 INTON; 484 } 485 486 487 488 STATIC int 489 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags) 490 { 491 char *startp; 492 char *loc = NULL; 493 char *q; 494 int c = 0; 495 int saveherefd = herefd; 496 struct nodelist *saveargbackq = argbackq; 497 int amount, how; 498 499 herefd = -1; 500 switch (subtype) { 501 case VSTRIMLEFT: 502 case VSTRIMLEFTMAX: 503 case VSTRIMRIGHT: 504 case VSTRIMRIGHTMAX: 505 how = (varflags & VSQUOTE) ? 0 : EXP_CASE; 506 break; 507 default: 508 how = 0; 509 break; 510 } 511 argstr(p, how); 512 STACKSTRNUL(expdest); 513 herefd = saveherefd; 514 argbackq = saveargbackq; 515 startp = stackblock() + startloc; 516 if (str == NULL) 517 str = stackblock() + strloc; 518 519 switch (subtype) { 520 case VSASSIGN: 521 setvar(str, startp, 0); 522 amount = startp - expdest; 523 STADJUST(amount, expdest); 524 varflags &= ~VSNUL; 525 return 1; 526 527 case VSQUESTION: 528 if (*p != CTLENDVAR) { 529 outfmt(&errout, "%s\n", startp); 530 error((char *)NULL); 531 } 532 error("%.*s: parameter %snot set", 533 (int)(p - str - 1), 534 str, (varflags & VSNUL) ? "null or " 535 : nullstr); 536 /* NOTREACHED */ 537 538 case VSTRIMLEFT: 539 for (loc = startp; loc < str; loc++) { 540 c = *loc; 541 *loc = '\0'; 542 if (patmatch(str, startp, varflags & VSQUOTE)) 543 goto recordleft; 544 *loc = c; 545 if ((varflags & VSQUOTE) && *loc == CTLESC) 546 loc++; 547 } 548 return 0; 549 550 case VSTRIMLEFTMAX: 551 for (loc = str - 1; loc >= startp;) { 552 c = *loc; 553 *loc = '\0'; 554 if (patmatch(str, startp, varflags & VSQUOTE)) 555 goto recordleft; 556 *loc = c; 557 loc--; 558 if ((varflags & VSQUOTE) && loc > startp && 559 *(loc - 1) == CTLESC) { 560 for (q = startp; q < loc; q++) 561 if (*q == CTLESC) 562 q++; 563 if (q > loc) 564 loc--; 565 } 566 } 567 return 0; 568 569 case VSTRIMRIGHT: 570 for (loc = str - 1; loc >= startp;) { 571 if (patmatch(str, loc, varflags & VSQUOTE)) 572 goto recordright; 573 loc--; 574 if ((varflags & VSQUOTE) && loc > startp && 575 *(loc - 1) == CTLESC) { 576 for (q = startp; q < loc; q++) 577 if (*q == CTLESC) 578 q++; 579 if (q > loc) 580 loc--; 581 } 582 } 583 return 0; 584 585 case VSTRIMRIGHTMAX: 586 for (loc = startp; loc < str - 1; loc++) { 587 if (patmatch(str, loc, varflags & VSQUOTE)) 588 goto recordright; 589 if ((varflags & VSQUOTE) && *loc == CTLESC) 590 loc++; 591 } 592 return 0; 593 594 default: 595 abort(); 596 } 597 598 recordleft: 599 *loc = c; 600 amount = ((str - 1) - (loc - startp)) - expdest; 601 STADJUST(amount, expdest); 602 while (loc != str - 1) 603 *startp++ = *loc++; 604 return 1; 605 606 recordright: 607 amount = loc - expdest; 608 STADJUST(amount, expdest); 609 STPUTC('\0', expdest); 610 STADJUST(-1, expdest); 611 return 1; 612 } 613 614 615 /* 616 * Expand a variable, and return a pointer to the next character in the 617 * input string. 618 */ 619 620 STATIC char * 621 evalvar(char *p, int flag) 622 { 623 int subtype; 624 int varflags; 625 char *var; 626 char *val; 627 int patloc; 628 int c; 629 int set; 630 int special; 631 int startloc; 632 int varlen; 633 int apply_ifs; 634 int quotes = flag & (EXP_FULL | EXP_CASE); 635 636 varflags = (unsigned char)*p++; 637 subtype = varflags & VSTYPE; 638 var = p; 639 special = !is_name(*p); 640 p = strchr(p, '=') + 1; 641 642 again: /* jump here after setting a variable with ${var=text} */ 643 if (special) { 644 set = varisset(var, varflags & VSNUL); 645 val = NULL; 646 } else { 647 val = lookupvar(var); 648 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) { 649 val = NULL; 650 set = 0; 651 } else 652 set = 1; 653 } 654 655 varlen = 0; 656 startloc = expdest - stackblock(); 657 658 if (!set && uflag) { 659 switch (subtype) { 660 case VSNORMAL: 661 case VSTRIMLEFT: 662 case VSTRIMLEFTMAX: 663 case VSTRIMRIGHT: 664 case VSTRIMRIGHTMAX: 665 case VSLENGTH: 666 error("%.*s: parameter not set", 667 (int)(p - var - 1), var); 668 /* NOTREACHED */ 669 } 670 } 671 672 if (set && subtype != VSPLUS) { 673 /* insert the value of the variable */ 674 if (special) { 675 varvalue(var, varflags & VSQUOTE, subtype, flag); 676 if (subtype == VSLENGTH) { 677 varlen = expdest - stackblock() - startloc; 678 STADJUST(-varlen, expdest); 679 } 680 } else { 681 char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX 682 : BASESYNTAX; 683 684 if (subtype == VSLENGTH) { 685 for (;*val; val++) 686 varlen++; 687 } else { 688 while (*val) { 689 if (quotes && syntax[(int)*val] == CCTL) 690 STPUTC(CTLESC, expdest); 691 STPUTC(*val++, expdest); 692 } 693 694 } 695 } 696 } 697 698 699 apply_ifs = ((varflags & VSQUOTE) == 0 || 700 (*var == '@' && shellparam.nparam != 1)); 701 702 switch (subtype) { 703 case VSLENGTH: 704 expdest = cvtnum(varlen, expdest); 705 break; 706 707 case VSNORMAL: 708 break; 709 710 case VSPLUS: 711 set = !set; 712 /* FALLTHROUGH */ 713 case VSMINUS: 714 if (!set) { 715 argstr(p, flag | (apply_ifs ? EXP_IFS_SPLIT : 0)); 716 /* 717 * ${x-a b c} doesn't get split, but removing the 718 * 'apply_ifs = 0' apparently breaks ${1+"$@"}.. 719 * ${x-'a b' c} should generate 2 args. 720 */ 721 /* We should have marked stuff already */ 722 apply_ifs = 0; 723 } 724 break; 725 726 case VSTRIMLEFT: 727 case VSTRIMLEFTMAX: 728 case VSTRIMRIGHT: 729 case VSTRIMRIGHTMAX: 730 if (!set) 731 break; 732 /* 733 * Terminate the string and start recording the pattern 734 * right after it 735 */ 736 STPUTC('\0', expdest); 737 patloc = expdest - stackblock(); 738 if (subevalvar(p, NULL, patloc, subtype, 739 startloc, varflags) == 0) { 740 int amount = (expdest - stackblock() - patloc) + 1; 741 STADJUST(-amount, expdest); 742 } 743 /* Remove any recorded regions beyond start of variable */ 744 removerecordregions(startloc); 745 apply_ifs = 1; 746 break; 747 748 case VSASSIGN: 749 case VSQUESTION: 750 if (set) 751 break; 752 if (subevalvar(p, var, 0, subtype, startloc, varflags)) { 753 varflags &= ~VSNUL; 754 /* 755 * Remove any recorded regions beyond 756 * start of variable 757 */ 758 removerecordregions(startloc); 759 goto again; 760 } 761 apply_ifs = 0; 762 break; 763 764 default: 765 abort(); 766 } 767 768 if (apply_ifs) 769 recordregion(startloc, expdest - stackblock(), 770 varflags & VSQUOTE); 771 772 if (subtype != VSNORMAL) { /* skip to end of alternative */ 773 int nesting = 1; 774 for (;;) { 775 if ((c = *p++) == CTLESC) 776 p++; 777 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { 778 if (set) 779 argbackq = argbackq->next; 780 } else if (c == CTLVAR) { 781 if ((*p++ & VSTYPE) != VSNORMAL) 782 nesting++; 783 } else if (c == CTLENDVAR) { 784 if (--nesting == 0) 785 break; 786 } 787 } 788 } 789 return p; 790 } 791 792 793 794 /* 795 * Test whether a specialized variable is set. 796 */ 797 798 STATIC int 799 varisset(char *name, int nulok) 800 { 801 if (*name == '!') 802 return backgndpid != -1; 803 else if (*name == '@' || *name == '*') { 804 if (*shellparam.p == NULL) 805 return 0; 806 807 if (nulok) { 808 char **av; 809 810 for (av = shellparam.p; *av; av++) 811 if (**av != '\0') 812 return 1; 813 return 0; 814 } 815 } else if (is_digit(*name)) { 816 char *ap; 817 int num = atoi(name); 818 819 if (num > shellparam.nparam) 820 return 0; 821 822 if (num == 0) 823 ap = arg0; 824 else 825 ap = shellparam.p[num - 1]; 826 827 if (nulok && (ap == NULL || *ap == '\0')) 828 return 0; 829 } 830 return 1; 831 } 832 833 834 835 /* 836 * Add the value of a specialized variable to the stack string. 837 */ 838 839 STATIC void 840 varvalue(char *name, int quoted, int subtype, int flag) 841 { 842 int num; 843 char *p; 844 int i; 845 char sep; 846 char **ap; 847 char const *syntax; 848 849 #define STRTODEST(p) \ 850 do {\ 851 if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH) { \ 852 syntax = quoted? DQSYNTAX : BASESYNTAX; \ 853 while (*p) { \ 854 if (syntax[(int)*p] == CCTL) \ 855 STPUTC(CTLESC, expdest); \ 856 STPUTC(*p++, expdest); \ 857 } \ 858 } else \ 859 while (*p) \ 860 STPUTC(*p++, expdest); \ 861 } while (0) 862 863 864 switch (*name) { 865 case '$': 866 num = rootpid; 867 goto numvar; 868 case '?': 869 num = exitstatus; 870 goto numvar; 871 case '#': 872 num = shellparam.nparam; 873 goto numvar; 874 case '!': 875 num = backgndpid; 876 numvar: 877 expdest = cvtnum(num, expdest); 878 break; 879 case '-': 880 for (i = 0; optlist[i].name; i++) { 881 if (optlist[i].val && optlist[i].letter) 882 STPUTC(optlist[i].letter, expdest); 883 } 884 break; 885 case '@': 886 if (flag & EXP_FULL && quoted) { 887 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { 888 STRTODEST(p); 889 if (*ap) 890 /* A NUL separates args inside "" */ 891 STPUTC('\0', expdest); 892 } 893 break; 894 } 895 /* fall through */ 896 case '*': 897 if (ifsset() != 0) 898 sep = ifsval()[0]; 899 else 900 sep = ' '; 901 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { 902 STRTODEST(p); 903 if (*ap && sep) 904 STPUTC(sep, expdest); 905 } 906 break; 907 case '0': 908 p = arg0; 909 STRTODEST(p); 910 break; 911 default: 912 if (is_digit(*name)) { 913 num = atoi(name); 914 if (num > 0 && num <= shellparam.nparam) { 915 p = shellparam.p[num - 1]; 916 STRTODEST(p); 917 } 918 } 919 break; 920 } 921 } 922 923 924 925 /* 926 * Record the fact that we have to scan this region of the 927 * string for IFS characters. 928 */ 929 930 STATIC void 931 recordregion(int start, int end, int inquotes) 932 { 933 struct ifsregion *ifsp; 934 935 if (ifslastp == NULL) { 936 ifsp = &ifsfirst; 937 } else { 938 if (ifslastp->endoff == start 939 && ifslastp->inquotes == inquotes) { 940 /* extend previous area */ 941 ifslastp->endoff = end; 942 return; 943 } 944 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion)); 945 ifslastp->next = ifsp; 946 } 947 ifslastp = ifsp; 948 ifslastp->next = NULL; 949 ifslastp->begoff = start; 950 ifslastp->endoff = end; 951 ifslastp->inquotes = inquotes; 952 } 953 954 955 956 /* 957 * Break the argument string into pieces based upon IFS and add the 958 * strings to the argument list. The regions of the string to be 959 * searched for IFS characters have been stored by recordregion. 960 */ 961 STATIC void 962 ifsbreakup(char *string, struct arglist *arglist) 963 { 964 struct ifsregion *ifsp; 965 struct strlist *sp; 966 char *start; 967 char *p; 968 char *q; 969 const char *ifs; 970 const char *ifsspc; 971 int had_param_ch = 0; 972 973 start = string; 974 975 if (ifslastp == NULL) { 976 /* Return entire argument, IFS doesn't apply to any of it */ 977 sp = (struct strlist *)stalloc(sizeof *sp); 978 sp->text = start; 979 *arglist->lastp = sp; 980 arglist->lastp = &sp->next; 981 return; 982 } 983 984 ifs = ifsset() ? ifsval() : " \t\n"; 985 986 for (ifsp = &ifsfirst; ifsp != NULL; ifsp = ifsp->next) { 987 p = string + ifsp->begoff; 988 while (p < string + ifsp->endoff) { 989 had_param_ch = 1; 990 q = p; 991 if (*p == CTLESC) 992 p++; 993 if (ifsp->inquotes) { 994 /* Only NULs (should be from "$@") end args */ 995 if (*p != 0) { 996 p++; 997 continue; 998 } 999 ifsspc = NULL; 1000 } else { 1001 if (!strchr(ifs, *p)) { 1002 p++; 1003 continue; 1004 } 1005 had_param_ch = 0; 1006 ifsspc = strchr(" \t\n", *p); 1007 1008 /* Ignore IFS whitespace at start */ 1009 if (q == start && ifsspc != NULL) { 1010 p++; 1011 start = p; 1012 continue; 1013 } 1014 } 1015 1016 /* Save this argument... */ 1017 *q = '\0'; 1018 sp = (struct strlist *)stalloc(sizeof *sp); 1019 sp->text = start; 1020 *arglist->lastp = sp; 1021 arglist->lastp = &sp->next; 1022 p++; 1023 1024 if (ifsspc != NULL) { 1025 /* Ignore further trailing IFS whitespace */ 1026 for (; p < string + ifsp->endoff; p++) { 1027 q = p; 1028 if (*p == CTLESC) 1029 p++; 1030 if (strchr(ifs, *p) == NULL) { 1031 p = q; 1032 break; 1033 } 1034 if (strchr(" \t\n", *p) == NULL) { 1035 p++; 1036 break; 1037 } 1038 } 1039 } 1040 start = p; 1041 } 1042 } 1043 1044 /* 1045 * Save anything left as an argument. 1046 * Traditionally we have treated 'IFS=':'; set -- x$IFS' as 1047 * generating 2 arguments, the second of which is empty. 1048 * Some recent clarification of the Posix spec say that it 1049 * should only generate one.... 1050 */ 1051 if (had_param_ch || *start != 0) { 1052 sp = (struct strlist *)stalloc(sizeof *sp); 1053 sp->text = start; 1054 *arglist->lastp = sp; 1055 arglist->lastp = &sp->next; 1056 } 1057 } 1058 1059 STATIC void 1060 ifsfree(void) 1061 { 1062 while (ifsfirst.next != NULL) { 1063 struct ifsregion *ifsp; 1064 INTOFF; 1065 ifsp = ifsfirst.next->next; 1066 ckfree(ifsfirst.next); 1067 ifsfirst.next = ifsp; 1068 INTON; 1069 } 1070 ifslastp = NULL; 1071 ifsfirst.next = NULL; 1072 } 1073 1074 1075 1076 /* 1077 * Expand shell metacharacters. At this point, the only control characters 1078 * should be escapes. The results are stored in the list exparg. 1079 */ 1080 1081 char *expdir; 1082 1083 1084 STATIC void 1085 expandmeta(struct strlist *str, int flag) 1086 { 1087 char *p; 1088 struct strlist **savelastp; 1089 struct strlist *sp; 1090 char c; 1091 /* TODO - EXP_REDIR */ 1092 1093 while (str) { 1094 if (fflag) 1095 goto nometa; 1096 p = str->text; 1097 for (;;) { /* fast check for meta chars */ 1098 if ((c = *p++) == '\0') 1099 goto nometa; 1100 if (c == '*' || c == '?' || c == '[' || c == '!') 1101 break; 1102 } 1103 savelastp = exparg.lastp; 1104 INTOFF; 1105 if (expdir == NULL) { 1106 int i = strlen(str->text); 1107 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ 1108 } 1109 1110 expmeta(expdir, str->text); 1111 ckfree(expdir); 1112 expdir = NULL; 1113 INTON; 1114 if (exparg.lastp == savelastp) { 1115 /* 1116 * no matches 1117 */ 1118 nometa: 1119 *exparg.lastp = str; 1120 rmescapes(str->text); 1121 exparg.lastp = &str->next; 1122 } else { 1123 *exparg.lastp = NULL; 1124 *savelastp = sp = expsort(*savelastp); 1125 while (sp->next != NULL) 1126 sp = sp->next; 1127 exparg.lastp = &sp->next; 1128 } 1129 str = str->next; 1130 } 1131 } 1132 1133 1134 /* 1135 * Do metacharacter (i.e. *, ?, [...]) expansion. 1136 */ 1137 1138 STATIC void 1139 expmeta(char *enddir, char *name) 1140 { 1141 char *p; 1142 const char *cp; 1143 char *q; 1144 char *start; 1145 char *endname; 1146 int metaflag; 1147 struct stat statb; 1148 DIR *dirp; 1149 struct dirent *dp; 1150 int atend; 1151 int matchdot; 1152 1153 metaflag = 0; 1154 start = name; 1155 for (p = name ; ; p++) { 1156 if (*p == '*' || *p == '?') 1157 metaflag = 1; 1158 else if (*p == '[') { 1159 q = p + 1; 1160 if (*q == '!') 1161 q++; 1162 for (;;) { 1163 while (*q == CTLQUOTEMARK) 1164 q++; 1165 if (*q == CTLESC) 1166 q++; 1167 if (*q == '/' || *q == '\0') 1168 break; 1169 if (*++q == ']') { 1170 metaflag = 1; 1171 break; 1172 } 1173 } 1174 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) { 1175 metaflag = 1; 1176 } else if (*p == '\0') 1177 break; 1178 else if (*p == CTLQUOTEMARK) 1179 continue; 1180 else if (*p == CTLESC) 1181 p++; 1182 if (*p == '/') { 1183 if (metaflag) 1184 break; 1185 start = p + 1; 1186 } 1187 } 1188 if (metaflag == 0) { /* we've reached the end of the file name */ 1189 if (enddir != expdir) 1190 metaflag++; 1191 for (p = name ; ; p++) { 1192 if (*p == CTLQUOTEMARK) 1193 continue; 1194 if (*p == CTLESC) 1195 p++; 1196 *enddir++ = *p; 1197 if (*p == '\0') 1198 break; 1199 } 1200 if (metaflag == 0 || lstat(expdir, &statb) >= 0) 1201 addfname(expdir); 1202 return; 1203 } 1204 endname = p; 1205 if (start != name) { 1206 p = name; 1207 while (p < start) { 1208 while (*p == CTLQUOTEMARK) 1209 p++; 1210 if (*p == CTLESC) 1211 p++; 1212 *enddir++ = *p++; 1213 } 1214 } 1215 if (enddir == expdir) { 1216 cp = "."; 1217 } else if (enddir == expdir + 1 && *expdir == '/') { 1218 cp = "/"; 1219 } else { 1220 cp = expdir; 1221 enddir[-1] = '\0'; 1222 } 1223 if ((dirp = opendir(cp)) == NULL) 1224 return; 1225 if (enddir != expdir) 1226 enddir[-1] = '/'; 1227 if (*endname == 0) { 1228 atend = 1; 1229 } else { 1230 atend = 0; 1231 *endname++ = '\0'; 1232 } 1233 matchdot = 0; 1234 p = start; 1235 while (*p == CTLQUOTEMARK) 1236 p++; 1237 if (*p == CTLESC) 1238 p++; 1239 if (*p == '.') 1240 matchdot++; 1241 while (! int_pending() && (dp = readdir(dirp)) != NULL) { 1242 if (dp->d_name[0] == '.' && ! matchdot) 1243 continue; 1244 if (patmatch(start, dp->d_name, 0)) { 1245 if (atend) { 1246 scopy(dp->d_name, enddir); 1247 addfname(expdir); 1248 } else { 1249 for (p = enddir, cp = dp->d_name; 1250 (*p++ = *cp++) != '\0';) 1251 continue; 1252 p[-1] = '/'; 1253 expmeta(p, endname); 1254 } 1255 } 1256 } 1257 closedir(dirp); 1258 if (! atend) 1259 endname[-1] = '/'; 1260 } 1261 1262 1263 /* 1264 * Add a file name to the list. 1265 */ 1266 1267 STATIC void 1268 addfname(char *name) 1269 { 1270 char *p; 1271 struct strlist *sp; 1272 1273 p = stalloc(strlen(name) + 1); 1274 scopy(name, p); 1275 sp = (struct strlist *)stalloc(sizeof *sp); 1276 sp->text = p; 1277 *exparg.lastp = sp; 1278 exparg.lastp = &sp->next; 1279 } 1280 1281 1282 /* 1283 * Sort the results of file name expansion. It calculates the number of 1284 * strings to sort and then calls msort (short for merge sort) to do the 1285 * work. 1286 */ 1287 1288 STATIC struct strlist * 1289 expsort(struct strlist *str) 1290 { 1291 int len; 1292 struct strlist *sp; 1293 1294 len = 0; 1295 for (sp = str ; sp ; sp = sp->next) 1296 len++; 1297 return msort(str, len); 1298 } 1299 1300 1301 STATIC struct strlist * 1302 msort(struct strlist *list, int len) 1303 { 1304 struct strlist *p, *q = NULL; 1305 struct strlist **lpp; 1306 int half; 1307 int n; 1308 1309 if (len <= 1) 1310 return list; 1311 half = len >> 1; 1312 p = list; 1313 for (n = half ; --n >= 0 ; ) { 1314 q = p; 1315 p = p->next; 1316 } 1317 q->next = NULL; /* terminate first half of list */ 1318 q = msort(list, half); /* sort first half of list */ 1319 p = msort(p, len - half); /* sort second half */ 1320 lpp = &list; 1321 for (;;) { 1322 if (strcmp(p->text, q->text) < 0) { 1323 *lpp = p; 1324 lpp = &p->next; 1325 if ((p = *lpp) == NULL) { 1326 *lpp = q; 1327 break; 1328 } 1329 } else { 1330 *lpp = q; 1331 lpp = &q->next; 1332 if ((q = *lpp) == NULL) { 1333 *lpp = p; 1334 break; 1335 } 1336 } 1337 } 1338 return list; 1339 } 1340 1341 1342 1343 /* 1344 * Returns true if the pattern matches the string. 1345 */ 1346 1347 int 1348 patmatch(char *pattern, char *string, int squoted) 1349 { 1350 #ifdef notdef 1351 if (pattern[0] == '!' && pattern[1] == '!') 1352 return 1 - pmatch(pattern + 2, string); 1353 else 1354 #endif 1355 return pmatch(pattern, string, squoted); 1356 } 1357 1358 1359 STATIC int 1360 pmatch(char *pattern, char *string, int squoted) 1361 { 1362 char *p, *q; 1363 char c; 1364 1365 p = pattern; 1366 q = string; 1367 for (;;) { 1368 switch (c = *p++) { 1369 case '\0': 1370 goto breakloop; 1371 case CTLESC: 1372 if (squoted && *q == CTLESC) 1373 q++; 1374 if (*q++ != *p++) 1375 return 0; 1376 break; 1377 case CTLQUOTEMARK: 1378 continue; 1379 case '?': 1380 if (squoted && *q == CTLESC) 1381 q++; 1382 if (*q++ == '\0') 1383 return 0; 1384 break; 1385 case '*': 1386 c = *p; 1387 while (c == CTLQUOTEMARK || c == '*') 1388 c = *++p; 1389 if (c != CTLESC && c != CTLQUOTEMARK && 1390 c != '?' && c != '*' && c != '[') { 1391 while (*q != c) { 1392 if (squoted && *q == CTLESC && 1393 q[1] == c) 1394 break; 1395 if (*q == '\0') 1396 return 0; 1397 if (squoted && *q == CTLESC) 1398 q++; 1399 q++; 1400 } 1401 } 1402 do { 1403 if (pmatch(p, q, squoted)) 1404 return 1; 1405 if (squoted && *q == CTLESC) 1406 q++; 1407 } while (*q++ != '\0'); 1408 return 0; 1409 case '[': { 1410 char *endp; 1411 int invert, found; 1412 char chr; 1413 1414 endp = p; 1415 if (*endp == '!') 1416 endp++; 1417 for (;;) { 1418 while (*endp == CTLQUOTEMARK) 1419 endp++; 1420 if (*endp == '\0') 1421 goto dft; /* no matching ] */ 1422 if (*endp == CTLESC) 1423 endp++; 1424 if (*++endp == ']') 1425 break; 1426 } 1427 invert = 0; 1428 if (*p == '!') { 1429 invert++; 1430 p++; 1431 } 1432 found = 0; 1433 chr = *q++; 1434 if (squoted && chr == CTLESC) 1435 chr = *q++; 1436 if (chr == '\0') 1437 return 0; 1438 c = *p++; 1439 do { 1440 if (c == CTLQUOTEMARK) 1441 continue; 1442 if (c == CTLESC) 1443 c = *p++; 1444 if (*p == '-' && p[1] != ']') { 1445 p++; 1446 while (*p == CTLQUOTEMARK) 1447 p++; 1448 if (*p == CTLESC) 1449 p++; 1450 if (chr >= c && chr <= *p) 1451 found = 1; 1452 p++; 1453 } else { 1454 if (chr == c) 1455 found = 1; 1456 } 1457 } while ((c = *p++) != ']'); 1458 if (found == invert) 1459 return 0; 1460 break; 1461 } 1462 dft: default: 1463 if (squoted && *q == CTLESC) 1464 q++; 1465 if (*q++ != c) 1466 return 0; 1467 break; 1468 } 1469 } 1470 breakloop: 1471 if (*q != '\0') 1472 return 0; 1473 return 1; 1474 } 1475 1476 1477 1478 /* 1479 * Remove any CTLESC characters from a string. 1480 */ 1481 1482 void 1483 rmescapes(char *str) 1484 { 1485 char *p, *q; 1486 1487 p = str; 1488 while (*p != CTLESC && *p != CTLQUOTEMARK) { 1489 if (*p++ == '\0') 1490 return; 1491 } 1492 q = p; 1493 while (*p) { 1494 if (*p == CTLQUOTEMARK) { 1495 p++; 1496 continue; 1497 } 1498 if (*p == CTLESC) 1499 p++; 1500 *q++ = *p++; 1501 } 1502 *q = '\0'; 1503 } 1504 1505 1506 1507 /* 1508 * See if a pattern matches in a case statement. 1509 */ 1510 1511 int 1512 casematch(union node *pattern, char *val) 1513 { 1514 struct stackmark smark; 1515 int result; 1516 char *p; 1517 1518 setstackmark(&smark); 1519 argbackq = pattern->narg.backquote; 1520 STARTSTACKSTR(expdest); 1521 ifslastp = NULL; 1522 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); 1523 STPUTC('\0', expdest); 1524 p = grabstackstr(expdest); 1525 result = patmatch(p, val, 0); 1526 popstackmark(&smark); 1527 return result; 1528 } 1529 1530 /* 1531 * Our own itoa(). 1532 */ 1533 1534 STATIC char * 1535 cvtnum(int num, char *buf) 1536 { 1537 char temp[32]; 1538 int neg = num < 0; 1539 char *p = temp + 31; 1540 1541 temp[31] = '\0'; 1542 1543 do { 1544 *--p = num % 10 + '0'; 1545 } while ((num /= 10) != 0); 1546 1547 if (neg) 1548 *--p = '-'; 1549 1550 while (*p) 1551 STPUTC(*p++, buf); 1552 return buf; 1553 } 1554 1555 /* 1556 * Do most of the work for wordexp(3). 1557 */ 1558 1559 int 1560 wordexpcmd(int argc, char **argv) 1561 { 1562 size_t len; 1563 int i; 1564 1565 out1fmt("%d", argc - 1); 1566 out1c('\0'); 1567 for (i = 1, len = 0; i < argc; i++) 1568 len += strlen(argv[i]); 1569 out1fmt("%zu", len); 1570 out1c('\0'); 1571 for (i = 1; i < argc; i++) { 1572 out1str(argv[i]); 1573 out1c('\0'); 1574 } 1575 return (0); 1576 } 1577