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