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