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 * Copyright (c) 2010-2015 7 * Jilles Tjoelker <jilles@stack.nl>. All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * Kenneth Almquist. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)expand.c 8.5 (Berkeley) 5/15/95"; 40 #endif 41 #endif /* not lint */ 42 #include <sys/cdefs.h> 43 __FBSDID("$FreeBSD$"); 44 45 #include <sys/types.h> 46 #include <sys/time.h> 47 #include <sys/stat.h> 48 #include <dirent.h> 49 #include <errno.h> 50 #include <inttypes.h> 51 #include <limits.h> 52 #include <pwd.h> 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> 56 #include <unistd.h> 57 #include <wchar.h> 58 #include <wctype.h> 59 60 /* 61 * Routines to expand arguments to commands. We have to deal with 62 * backquotes, shell variables, and file metacharacters. 63 */ 64 65 #include "shell.h" 66 #include "main.h" 67 #include "nodes.h" 68 #include "eval.h" 69 #include "expand.h" 70 #include "syntax.h" 71 #include "parser.h" 72 #include "jobs.h" 73 #include "options.h" 74 #include "var.h" 75 #include "input.h" 76 #include "output.h" 77 #include "memalloc.h" 78 #include "error.h" 79 #include "mystring.h" 80 #include "arith.h" 81 #include "show.h" 82 #include "builtins.h" 83 84 enum wordstate { WORD_IDLE, WORD_WS_DELIMITED, WORD_QUOTEMARK }; 85 86 struct worddest { 87 struct arglist *list; 88 enum wordstate state; 89 }; 90 91 static char *expdest; /* output of current string */ 92 93 static const char *argstr(const char *, struct nodelist **restrict, int, 94 struct worddest *); 95 static const char *exptilde(const char *, int); 96 static const char *expari(const char *, struct nodelist **restrict, int, 97 struct worddest *); 98 static void expbackq(union node *, int, int, struct worddest *); 99 static void subevalvar_trim(const char *, struct nodelist *, int, int, int); 100 static int subevalvar_misc(const char *, struct nodelist *, const char *, int, 101 int, int); 102 static const char *evalvar(const char *, struct nodelist **restrict, int, 103 struct worddest *); 104 static int varisset(const char *, int); 105 static void strtodest(const char *, int, int, int, struct worddest *); 106 static void reprocess(int, int, int, int, struct worddest *); 107 static void varvalue(const char *, int, int, int, struct worddest *); 108 static void expandmeta(char *, struct arglist *); 109 static void expmeta(char *, char *, struct arglist *); 110 static int expsortcmp(const void *, const void *); 111 static int patmatch(const char *, const char *); 112 static void cvtnum(int, char *); 113 static int collate_range_cmp(wchar_t, wchar_t); 114 115 void 116 emptyarglist(struct arglist *list) 117 { 118 119 list->args = list->smallarg; 120 list->count = 0; 121 list->capacity = sizeof(list->smallarg) / sizeof(list->smallarg[0]); 122 } 123 124 void 125 appendarglist(struct arglist *list, char *str) 126 { 127 char **newargs; 128 int newcapacity; 129 130 if (list->count >= list->capacity) { 131 newcapacity = list->capacity * 2; 132 if (newcapacity < 16) 133 newcapacity = 16; 134 if (newcapacity > INT_MAX / (int)sizeof(newargs[0])) 135 error("Too many entries in arglist"); 136 newargs = stalloc(newcapacity * sizeof(newargs[0])); 137 memcpy(newargs, list->args, list->count * sizeof(newargs[0])); 138 list->args = newargs; 139 list->capacity = newcapacity; 140 } 141 list->args[list->count++] = str; 142 } 143 144 static int 145 collate_range_cmp(wchar_t c1, wchar_t c2) 146 { 147 static wchar_t s1[2], s2[2]; 148 149 s1[0] = c1; 150 s2[0] = c2; 151 return (wcscoll(s1, s2)); 152 } 153 154 static char * 155 stputs_quotes(const char *data, const char *syntax, char *p) 156 { 157 while (*data) { 158 CHECKSTRSPACE(2, p); 159 if (syntax[(int)*data] == CCTL) 160 USTPUTC(CTLESC, p); 161 USTPUTC(*data++, p); 162 } 163 return (p); 164 } 165 #define STPUTS_QUOTES(data, syntax, p) p = stputs_quotes((data), syntax, p) 166 167 static char * 168 nextword(char c, int flag, char *p, struct worddest *dst) 169 { 170 int is_ws; 171 172 is_ws = c == '\t' || c == '\n' || c == ' '; 173 if (p != stackblock() || (is_ws ? dst->state == WORD_QUOTEMARK : 174 dst->state != WORD_WS_DELIMITED) || c == '\0') { 175 STPUTC('\0', p); 176 if (flag & EXP_GLOB) 177 expandmeta(grabstackstr(p), dst->list); 178 else 179 appendarglist(dst->list, grabstackstr(p)); 180 dst->state = is_ws ? WORD_WS_DELIMITED : WORD_IDLE; 181 } else if (!is_ws && dst->state == WORD_WS_DELIMITED) 182 dst->state = WORD_IDLE; 183 /* Reserve space while the stack string is empty. */ 184 appendarglist(dst->list, NULL); 185 dst->list->count--; 186 STARTSTACKSTR(p); 187 return p; 188 } 189 #define NEXTWORD(c, flag, p, dstlist) p = nextword(c, flag, p, dstlist) 190 191 static char * 192 stputs_split(const char *data, const char *syntax, int flag, char *p, 193 struct worddest *dst) 194 { 195 const char *ifs; 196 char c; 197 198 ifs = ifsset() ? ifsval() : " \t\n"; 199 while (*data) { 200 CHECKSTRSPACE(2, p); 201 c = *data++; 202 if (strchr(ifs, c) != NULL) { 203 NEXTWORD(c, flag, p, dst); 204 continue; 205 } 206 if (flag & EXP_GLOB && syntax[(int)c] == CCTL) 207 USTPUTC(CTLESC, p); 208 USTPUTC(c, p); 209 } 210 return (p); 211 } 212 #define STPUTS_SPLIT(data, syntax, flag, p, dst) p = stputs_split((data), syntax, flag, p, dst) 213 214 /* 215 * Perform expansions on an argument, placing the resulting list of arguments 216 * in arglist. Parameter expansion, command substitution and arithmetic 217 * expansion are always performed; additional expansions can be requested 218 * via flag (EXP_*). 219 * The result is left in the stack string. 220 * When arglist is NULL, perform here document expansion. 221 * 222 * Caution: this function uses global state and is not reentrant. 223 * However, a new invocation after an interrupted invocation is safe 224 * and will reset the global state for the new call. 225 */ 226 void 227 expandarg(union node *arg, struct arglist *arglist, int flag) 228 { 229 struct worddest exparg; 230 struct nodelist *argbackq; 231 232 if (fflag) 233 flag &= ~EXP_GLOB; 234 argbackq = arg->narg.backquote; 235 exparg.list = arglist; 236 exparg.state = WORD_IDLE; 237 STARTSTACKSTR(expdest); 238 argstr(arg->narg.text, &argbackq, flag, &exparg); 239 if (arglist == NULL) { 240 STACKSTRNUL(expdest); 241 return; /* here document expanded */ 242 } 243 if ((flag & EXP_SPLIT) == 0 || expdest != stackblock() || 244 exparg.state == WORD_QUOTEMARK) { 245 STPUTC('\0', expdest); 246 if (flag & EXP_SPLIT) { 247 if (flag & EXP_GLOB) 248 expandmeta(grabstackstr(expdest), exparg.list); 249 else 250 appendarglist(exparg.list, grabstackstr(expdest)); 251 } 252 } 253 if ((flag & EXP_SPLIT) == 0) 254 appendarglist(arglist, grabstackstr(expdest)); 255 } 256 257 258 259 /* 260 * Perform parameter expansion, command substitution and arithmetic 261 * expansion, and tilde expansion if requested via EXP_TILDE/EXP_VARTILDE. 262 * Processing ends at a CTLENDVAR or CTLENDARI character as well as '\0'. 263 * This is used to expand word in ${var+word} etc. 264 * If EXP_GLOB or EXP_CASE are set, keep and/or generate CTLESC 265 * characters to allow for further processing. 266 * 267 * If EXP_SPLIT is set, dst receives any complete words produced. 268 */ 269 static const char * 270 argstr(const char *p, struct nodelist **restrict argbackq, int flag, 271 struct worddest *dst) 272 { 273 char c; 274 int quotes = flag & (EXP_GLOB | EXP_CASE); /* do CTLESC */ 275 int firsteq = 1; 276 int split_lit; 277 int lit_quoted; 278 279 split_lit = flag & EXP_SPLIT_LIT; 280 lit_quoted = flag & EXP_LIT_QUOTED; 281 flag &= ~(EXP_SPLIT_LIT | EXP_LIT_QUOTED); 282 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE))) 283 p = exptilde(p, flag); 284 for (;;) { 285 CHECKSTRSPACE(2, expdest); 286 switch (c = *p++) { 287 case '\0': 288 return (p - 1); 289 case CTLENDVAR: 290 case CTLENDARI: 291 return (p); 292 case CTLQUOTEMARK: 293 lit_quoted = 1; 294 /* "$@" syntax adherence hack */ 295 if (p[0] == CTLVAR && (p[1] & VSQUOTE) != 0 && 296 p[2] == '@' && p[3] == '=') 297 break; 298 if ((flag & EXP_SPLIT) != 0 && expdest == stackblock()) 299 dst->state = WORD_QUOTEMARK; 300 break; 301 case CTLQUOTEEND: 302 lit_quoted = 0; 303 break; 304 case CTLESC: 305 c = *p++; 306 if (split_lit && !lit_quoted && 307 strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) { 308 NEXTWORD(c, flag, expdest, dst); 309 break; 310 } 311 if (quotes) 312 USTPUTC(CTLESC, expdest); 313 USTPUTC(c, expdest); 314 break; 315 case CTLVAR: 316 p = evalvar(p, argbackq, flag, dst); 317 break; 318 case CTLBACKQ: 319 case CTLBACKQ|CTLQUOTE: 320 expbackq((*argbackq)->n, c & CTLQUOTE, flag, dst); 321 *argbackq = (*argbackq)->next; 322 break; 323 case CTLARI: 324 p = expari(p, argbackq, flag, dst); 325 break; 326 case ':': 327 case '=': 328 /* 329 * sort of a hack - expand tildes in variable 330 * assignments (after the first '=' and after ':'s). 331 */ 332 if (split_lit && !lit_quoted && 333 strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) { 334 NEXTWORD(c, flag, expdest, dst); 335 break; 336 } 337 USTPUTC(c, expdest); 338 if (flag & EXP_VARTILDE && *p == '~' && 339 (c != '=' || firsteq)) { 340 if (c == '=') 341 firsteq = 0; 342 p = exptilde(p, flag); 343 } 344 break; 345 default: 346 if (split_lit && !lit_quoted && 347 strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) { 348 NEXTWORD(c, flag, expdest, dst); 349 break; 350 } 351 USTPUTC(c, expdest); 352 } 353 } 354 } 355 356 /* 357 * Perform tilde expansion, placing the result in the stack string and 358 * returning the next position in the input string to process. 359 */ 360 static const char * 361 exptilde(const char *p, int flag) 362 { 363 char c; 364 const char *startp = p; 365 const char *user; 366 struct passwd *pw; 367 char *home; 368 int len; 369 370 for (;;) { 371 c = *p; 372 switch(c) { 373 case CTLESC: /* This means CTL* are always considered quoted. */ 374 case CTLVAR: 375 case CTLBACKQ: 376 case CTLBACKQ | CTLQUOTE: 377 case CTLARI: 378 case CTLENDARI: 379 case CTLQUOTEMARK: 380 return (startp); 381 case ':': 382 if ((flag & EXP_VARTILDE) == 0) 383 break; 384 /* FALLTHROUGH */ 385 case '\0': 386 case '/': 387 case CTLENDVAR: 388 len = p - startp - 1; 389 STPUTBIN(startp + 1, len, expdest); 390 STACKSTRNUL(expdest); 391 user = expdest - len; 392 if (*user == '\0') { 393 home = lookupvar("HOME"); 394 } else { 395 pw = getpwnam(user); 396 home = pw != NULL ? pw->pw_dir : NULL; 397 } 398 STADJUST(-len, expdest); 399 if (home == NULL || *home == '\0') 400 return (startp); 401 strtodest(home, flag, VSNORMAL, 1, NULL); 402 return (p); 403 } 404 p++; 405 } 406 } 407 408 409 /* 410 * Expand arithmetic expression. 411 */ 412 static const char * 413 expari(const char *p, struct nodelist **restrict argbackq, int flag, 414 struct worddest *dst) 415 { 416 char *q, *start; 417 arith_t result; 418 int begoff; 419 int quoted; 420 int adj; 421 422 quoted = *p++ == '"'; 423 begoff = expdest - stackblock(); 424 p = argstr(p, argbackq, 0, NULL); 425 STPUTC('\0', expdest); 426 start = stackblock() + begoff; 427 428 q = grabstackstr(expdest); 429 result = arith(start); 430 ungrabstackstr(q, expdest); 431 432 start = stackblock() + begoff; 433 adj = start - expdest; 434 STADJUST(adj, expdest); 435 436 CHECKSTRSPACE((int)(DIGITS(result) + 1), expdest); 437 fmtstr(expdest, DIGITS(result), ARITH_FORMAT_STR, result); 438 adj = strlen(expdest); 439 STADJUST(adj, expdest); 440 if (!quoted) 441 reprocess(expdest - adj - stackblock(), flag, VSNORMAL, 0, dst); 442 return p; 443 } 444 445 446 /* 447 * Perform command substitution. 448 */ 449 static void 450 expbackq(union node *cmd, int quoted, int flag, struct worddest *dst) 451 { 452 struct backcmd in; 453 int i; 454 char buf[128]; 455 char *p; 456 char *dest = expdest; 457 char lastc; 458 char const *syntax = quoted? DQSYNTAX : BASESYNTAX; 459 int quotes = flag & (EXP_GLOB | EXP_CASE); 460 size_t nnl; 461 const char *ifs; 462 463 INTOFF; 464 p = grabstackstr(dest); 465 evalbackcmd(cmd, &in); 466 ungrabstackstr(p, dest); 467 468 p = in.buf; 469 nnl = 0; 470 if (!quoted && flag & EXP_SPLIT) 471 ifs = ifsset() ? ifsval() : " \t\n"; 472 else 473 ifs = ""; 474 /* Don't copy trailing newlines */ 475 for (;;) { 476 if (--in.nleft < 0) { 477 if (in.fd < 0) 478 break; 479 while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR) 480 ; 481 TRACE(("expbackq: read returns %d\n", i)); 482 if (i <= 0) 483 break; 484 p = buf; 485 in.nleft = i - 1; 486 } 487 lastc = *p++; 488 if (lastc == '\0') 489 continue; 490 if (lastc == '\n') { 491 nnl++; 492 } else { 493 if (nnl > 0) { 494 if (strchr(ifs, '\n') != NULL) { 495 NEXTWORD('\n', flag, dest, dst); 496 nnl = 0; 497 } else { 498 CHECKSTRSPACE(nnl + 2, dest); 499 while (nnl > 0) { 500 nnl--; 501 USTPUTC('\n', dest); 502 } 503 } 504 } 505 if (strchr(ifs, lastc) != NULL) 506 NEXTWORD(lastc, flag, dest, dst); 507 else { 508 CHECKSTRSPACE(2, dest); 509 if (quotes && syntax[(int)lastc] == CCTL) 510 USTPUTC(CTLESC, dest); 511 USTPUTC(lastc, dest); 512 } 513 } 514 } 515 516 if (in.fd >= 0) 517 close(in.fd); 518 if (in.buf) 519 ckfree(in.buf); 520 if (in.jp) { 521 p = grabstackstr(dest); 522 exitstatus = waitforjob(in.jp, (int *)NULL); 523 ungrabstackstr(p, dest); 524 } 525 TRACE(("expbackq: size=%td: \"%.*s\"\n", 526 ((dest - stackblock()) - startloc), 527 (int)((dest - stackblock()) - startloc), 528 stackblock() + startloc)); 529 expdest = dest; 530 INTON; 531 } 532 533 534 535 static void 536 recordleft(const char *str, const char *loc, char *startp) 537 { 538 int amount; 539 540 amount = ((str - 1) - (loc - startp)) - expdest; 541 STADJUST(amount, expdest); 542 while (loc != str - 1) 543 *startp++ = *loc++; 544 } 545 546 static void 547 subevalvar_trim(const char *p, struct nodelist *argbackq, int strloc, 548 int subtype, int startloc) 549 { 550 char *startp; 551 char *loc = NULL; 552 char *str; 553 int c = 0; 554 struct nodelist *argbackqcopy = argbackq; 555 int amount; 556 557 argstr(p, &argbackqcopy, EXP_CASE | EXP_TILDE, NULL); 558 STACKSTRNUL(expdest); 559 startp = stackblock() + startloc; 560 str = stackblock() + strloc; 561 562 switch (subtype) { 563 case VSTRIMLEFT: 564 for (loc = startp; loc < str; loc++) { 565 c = *loc; 566 *loc = '\0'; 567 if (patmatch(str, startp)) { 568 *loc = c; 569 recordleft(str, loc, startp); 570 return; 571 } 572 *loc = c; 573 } 574 break; 575 576 case VSTRIMLEFTMAX: 577 for (loc = str - 1; loc >= startp;) { 578 c = *loc; 579 *loc = '\0'; 580 if (patmatch(str, startp)) { 581 *loc = c; 582 recordleft(str, loc, startp); 583 return; 584 } 585 *loc = c; 586 loc--; 587 } 588 break; 589 590 case VSTRIMRIGHT: 591 for (loc = str - 1; loc >= startp;) { 592 if (patmatch(str, loc)) { 593 amount = loc - expdest; 594 STADJUST(amount, expdest); 595 return; 596 } 597 loc--; 598 } 599 break; 600 601 case VSTRIMRIGHTMAX: 602 for (loc = startp; loc < str - 1; loc++) { 603 if (patmatch(str, loc)) { 604 amount = loc - expdest; 605 STADJUST(amount, expdest); 606 return; 607 } 608 } 609 break; 610 611 612 default: 613 abort(); 614 } 615 amount = (expdest - stackblock() - strloc) + 1; 616 STADJUST(-amount, expdest); 617 } 618 619 620 static int 621 subevalvar_misc(const char *p, struct nodelist *argbackq, const char *var, int subtype, int startloc, 622 int varflags) 623 { 624 char *startp; 625 struct nodelist *argbackqcopy = argbackq; 626 int amount; 627 628 argstr(p, &argbackqcopy, EXP_TILDE, NULL); 629 STACKSTRNUL(expdest); 630 startp = stackblock() + startloc; 631 632 switch (subtype) { 633 case VSASSIGN: 634 setvar(var, startp, 0); 635 amount = startp - expdest; 636 STADJUST(amount, expdest); 637 return 1; 638 639 case VSQUESTION: 640 if (*p != CTLENDVAR) { 641 outfmt(out2, "%s\n", startp); 642 error((char *)NULL); 643 } 644 error("%.*s: parameter %snot set", (int)(p - var - 1), 645 var, (varflags & VSNUL) ? "null or " : ""); 646 return 0; 647 648 default: 649 abort(); 650 } 651 } 652 653 654 /* 655 * Expand a variable, and return a pointer to the next character in the 656 * input string. 657 */ 658 659 static const char * 660 evalvar(const char *p, struct nodelist **restrict argbackq, int flag, 661 struct worddest *dst) 662 { 663 int subtype; 664 int varflags; 665 const char *var; 666 const char *val; 667 int patloc; 668 int c; 669 int set; 670 int special; 671 int startloc; 672 int varlen; 673 int varlenb; 674 char buf[21]; 675 676 varflags = (unsigned char)*p++; 677 subtype = varflags & VSTYPE; 678 var = p; 679 special = 0; 680 if (! is_name(*p)) 681 special = 1; 682 p = strchr(p, '=') + 1; 683 again: /* jump here after setting a variable with ${var=text} */ 684 if (varflags & VSLINENO) { 685 set = 1; 686 special = 1; 687 val = NULL; 688 } else if (special) { 689 set = varisset(var, varflags & VSNUL); 690 val = NULL; 691 } else { 692 val = bltinlookup(var, 1); 693 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) { 694 val = NULL; 695 set = 0; 696 } else 697 set = 1; 698 } 699 varlen = 0; 700 startloc = expdest - stackblock(); 701 if (!set && uflag && *var != '@' && *var != '*') { 702 switch (subtype) { 703 case VSNORMAL: 704 case VSTRIMLEFT: 705 case VSTRIMLEFTMAX: 706 case VSTRIMRIGHT: 707 case VSTRIMRIGHTMAX: 708 case VSLENGTH: 709 error("%.*s: parameter not set", (int)(p - var - 1), 710 var); 711 } 712 } 713 if (set && subtype != VSPLUS) { 714 /* insert the value of the variable */ 715 if (special) { 716 if (varflags & VSLINENO) { 717 if (p - var > (ptrdiff_t)sizeof(buf)) 718 abort(); 719 memcpy(buf, var, p - var - 1); 720 buf[p - var - 1] = '\0'; 721 strtodest(buf, flag, subtype, 722 varflags & VSQUOTE, dst); 723 } else 724 varvalue(var, varflags & VSQUOTE, subtype, flag, 725 dst); 726 if (subtype == VSLENGTH) { 727 varlenb = expdest - stackblock() - startloc; 728 varlen = varlenb; 729 if (localeisutf8) { 730 val = stackblock() + startloc; 731 for (;val != expdest; val++) 732 if ((*val & 0xC0) == 0x80) 733 varlen--; 734 } 735 STADJUST(-varlenb, expdest); 736 } 737 } else { 738 if (subtype == VSLENGTH) { 739 for (;*val; val++) 740 if (!localeisutf8 || 741 (*val & 0xC0) != 0x80) 742 varlen++; 743 } 744 else 745 strtodest(val, flag, subtype, 746 varflags & VSQUOTE, dst); 747 } 748 } 749 750 if (subtype == VSPLUS) 751 set = ! set; 752 753 switch (subtype) { 754 case VSLENGTH: 755 cvtnum(varlen, buf); 756 strtodest(buf, flag, VSNORMAL, varflags & VSQUOTE, dst); 757 break; 758 759 case VSNORMAL: 760 break; 761 762 case VSPLUS: 763 case VSMINUS: 764 if (!set) { 765 argstr(p, argbackq, 766 flag | (flag & EXP_SPLIT ? EXP_SPLIT_LIT : 0) | 767 (varflags & VSQUOTE ? EXP_LIT_QUOTED : 0), dst); 768 break; 769 } 770 break; 771 772 case VSTRIMLEFT: 773 case VSTRIMLEFTMAX: 774 case VSTRIMRIGHT: 775 case VSTRIMRIGHTMAX: 776 if (!set) { 777 set = 1; 778 break; 779 } 780 /* 781 * Terminate the string and start recording the pattern 782 * right after it 783 */ 784 STPUTC('\0', expdest); 785 patloc = expdest - stackblock(); 786 subevalvar_trim(p, *argbackq, patloc, subtype, startloc); 787 reprocess(startloc, flag, VSNORMAL, varflags & VSQUOTE, dst); 788 if (flag & EXP_SPLIT && *var == '@' && varflags & VSQUOTE) 789 dst->state = WORD_QUOTEMARK; 790 break; 791 792 case VSASSIGN: 793 case VSQUESTION: 794 if (!set) { 795 if (subevalvar_misc(p, *argbackq, var, subtype, 796 startloc, varflags)) { 797 varflags &= ~VSNUL; 798 goto again; 799 } 800 break; 801 } 802 break; 803 804 case VSERROR: 805 c = p - var - 1; 806 error("${%.*s%s}: Bad substitution", c, var, 807 (c > 0 && *p != CTLENDVAR) ? "..." : ""); 808 809 default: 810 abort(); 811 } 812 813 if (subtype != VSNORMAL) { /* skip to end of alternative */ 814 int nesting = 1; 815 for (;;) { 816 if ((c = *p++) == CTLESC) 817 p++; 818 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { 819 if (set) 820 *argbackq = (*argbackq)->next; 821 } else if (c == CTLVAR) { 822 if ((*p++ & VSTYPE) != VSNORMAL) 823 nesting++; 824 } else if (c == CTLENDVAR) { 825 if (--nesting == 0) 826 break; 827 } 828 } 829 } 830 return p; 831 } 832 833 834 835 /* 836 * Test whether a specialized variable is set. 837 */ 838 839 static int 840 varisset(const char *name, int nulok) 841 { 842 843 if (*name == '!') 844 return backgndpidset(); 845 else if (*name == '@' || *name == '*') { 846 if (*shellparam.p == NULL) 847 return 0; 848 849 if (nulok) { 850 char **av; 851 852 for (av = shellparam.p; *av; av++) 853 if (**av != '\0') 854 return 1; 855 return 0; 856 } 857 } else if (is_digit(*name)) { 858 char *ap; 859 long num; 860 861 errno = 0; 862 num = strtol(name, NULL, 10); 863 if (errno != 0 || num > shellparam.nparam) 864 return 0; 865 866 if (num == 0) 867 ap = arg0; 868 else 869 ap = shellparam.p[num - 1]; 870 871 if (nulok && (ap == NULL || *ap == '\0')) 872 return 0; 873 } 874 return 1; 875 } 876 877 static void 878 strtodest(const char *p, int flag, int subtype, int quoted, 879 struct worddest *dst) 880 { 881 if (subtype == VSLENGTH || subtype == VSTRIMLEFT || 882 subtype == VSTRIMLEFTMAX || subtype == VSTRIMRIGHT || 883 subtype == VSTRIMRIGHTMAX) 884 STPUTS(p, expdest); 885 else if (flag & EXP_SPLIT && !quoted && dst != NULL) 886 STPUTS_SPLIT(p, BASESYNTAX, flag, expdest, dst); 887 else if (flag & (EXP_GLOB | EXP_CASE)) 888 STPUTS_QUOTES(p, quoted ? DQSYNTAX : BASESYNTAX, expdest); 889 else 890 STPUTS(p, expdest); 891 } 892 893 static void 894 reprocess(int startloc, int flag, int subtype, int quoted, 895 struct worddest *dst) 896 { 897 static char *buf = NULL; 898 static size_t buflen = 0; 899 char *startp; 900 size_t len, zpos, zlen; 901 902 startp = stackblock() + startloc; 903 len = expdest - startp; 904 if (len >= SIZE_MAX / 2) 905 abort(); 906 INTOFF; 907 if (len >= buflen) { 908 ckfree(buf); 909 buf = NULL; 910 } 911 if (buflen < 128) 912 buflen = 128; 913 while (len >= buflen) 914 buflen <<= 1; 915 if (buf == NULL) 916 buf = ckmalloc(buflen); 917 INTON; 918 memcpy(buf, startp, len); 919 buf[len] = '\0'; 920 STADJUST(-len, expdest); 921 for (zpos = 0;;) { 922 zlen = strlen(buf + zpos); 923 strtodest(buf + zpos, flag, subtype, quoted, dst); 924 zpos += zlen + 1; 925 if (zpos == len + 1) 926 break; 927 if (flag & EXP_SPLIT && (quoted || (zlen > 0 && zpos < len))) 928 NEXTWORD('\0', flag, expdest, dst); 929 } 930 } 931 932 /* 933 * Add the value of a specialized variable to the stack string. 934 */ 935 936 static void 937 varvalue(const char *name, int quoted, int subtype, int flag, 938 struct worddest *dst) 939 { 940 int num; 941 char *p; 942 int i; 943 int splitlater; 944 char sep[2]; 945 char **ap; 946 char buf[(NSHORTOPTS > 10 ? NSHORTOPTS : 10) + 1]; 947 948 if (subtype == VSLENGTH) 949 flag &= ~EXP_FULL; 950 splitlater = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX || 951 subtype == VSTRIMRIGHT || subtype == VSTRIMRIGHTMAX; 952 953 switch (*name) { 954 case '$': 955 num = rootpid; 956 break; 957 case '?': 958 num = oexitstatus; 959 break; 960 case '#': 961 num = shellparam.nparam; 962 break; 963 case '!': 964 num = backgndpidval(); 965 break; 966 case '-': 967 p = buf; 968 for (i = 0 ; i < NSHORTOPTS ; i++) { 969 if (optval[i]) 970 *p++ = optletter[i]; 971 } 972 *p = '\0'; 973 strtodest(buf, flag, subtype, quoted, dst); 974 return; 975 case '@': 976 if (flag & EXP_SPLIT && quoted) { 977 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { 978 strtodest(p, flag, subtype, quoted, dst); 979 if (*ap) { 980 if (splitlater) 981 STPUTC('\0', expdest); 982 else 983 NEXTWORD('\0', flag, expdest, 984 dst); 985 } 986 } 987 if (shellparam.nparam > 0) 988 dst->state = WORD_QUOTEMARK; 989 return; 990 } 991 /* FALLTHROUGH */ 992 case '*': 993 if (ifsset()) 994 sep[0] = ifsval()[0]; 995 else 996 sep[0] = ' '; 997 sep[1] = '\0'; 998 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { 999 strtodest(p, flag, subtype, quoted, dst); 1000 if (!*ap) 1001 break; 1002 if (sep[0]) 1003 strtodest(sep, flag, subtype, quoted, dst); 1004 else if (flag & EXP_SPLIT && !quoted && **ap != '\0') { 1005 if (splitlater) 1006 STPUTC('\0', expdest); 1007 else 1008 NEXTWORD('\0', flag, expdest, dst); 1009 } 1010 } 1011 return; 1012 default: 1013 if (is_digit(*name)) { 1014 num = atoi(name); 1015 if (num == 0) 1016 p = arg0; 1017 else if (num > 0 && num <= shellparam.nparam) 1018 p = shellparam.p[num - 1]; 1019 else 1020 return; 1021 strtodest(p, flag, subtype, quoted, dst); 1022 } 1023 return; 1024 } 1025 cvtnum(num, buf); 1026 strtodest(buf, flag, subtype, quoted, dst); 1027 } 1028 1029 1030 1031 static char expdir[PATH_MAX]; 1032 #define expdir_end (expdir + sizeof(expdir)) 1033 1034 /* 1035 * Perform pathname generation and remove control characters. 1036 * At this point, the only control characters should be CTLESC. 1037 * The results are stored in the list dstlist. 1038 */ 1039 static void 1040 expandmeta(char *pattern, struct arglist *dstlist) 1041 { 1042 char *p; 1043 int firstmatch; 1044 char c; 1045 1046 firstmatch = dstlist->count; 1047 p = pattern; 1048 for (; (c = *p) != '\0'; p++) { 1049 /* fast check for meta chars */ 1050 if (c == '*' || c == '?' || c == '[') { 1051 INTOFF; 1052 expmeta(expdir, pattern, dstlist); 1053 INTON; 1054 break; 1055 } 1056 } 1057 if (dstlist->count == firstmatch) { 1058 /* 1059 * no matches 1060 */ 1061 rmescapes(pattern); 1062 appendarglist(dstlist, pattern); 1063 } else { 1064 qsort(&dstlist->args[firstmatch], 1065 dstlist->count - firstmatch, 1066 sizeof(dstlist->args[0]), expsortcmp); 1067 } 1068 } 1069 1070 1071 /* 1072 * Do metacharacter (i.e. *, ?, [...]) expansion. 1073 */ 1074 1075 static void 1076 expmeta(char *enddir, char *name, struct arglist *arglist) 1077 { 1078 const char *p; 1079 const char *q; 1080 const char *start; 1081 char *endname; 1082 int metaflag; 1083 struct stat statb; 1084 DIR *dirp; 1085 struct dirent *dp; 1086 int atend; 1087 int matchdot; 1088 int esc; 1089 int namlen; 1090 1091 metaflag = 0; 1092 start = name; 1093 for (p = name; esc = 0, *p; p += esc + 1) { 1094 if (*p == '*' || *p == '?') 1095 metaflag = 1; 1096 else if (*p == '[') { 1097 q = p + 1; 1098 if (*q == '!' || *q == '^') 1099 q++; 1100 for (;;) { 1101 if (*q == CTLESC) 1102 q++; 1103 if (*q == '/' || *q == '\0') 1104 break; 1105 if (*++q == ']') { 1106 metaflag = 1; 1107 break; 1108 } 1109 } 1110 } else if (*p == '\0') 1111 break; 1112 else { 1113 if (*p == CTLESC) 1114 esc++; 1115 if (p[esc] == '/') { 1116 if (metaflag) 1117 break; 1118 start = p + esc + 1; 1119 } 1120 } 1121 } 1122 if (metaflag == 0) { /* we've reached the end of the file name */ 1123 if (enddir != expdir) 1124 metaflag++; 1125 for (p = name ; ; p++) { 1126 if (*p == CTLESC) 1127 p++; 1128 *enddir++ = *p; 1129 if (*p == '\0') 1130 break; 1131 if (enddir == expdir_end) 1132 return; 1133 } 1134 if (metaflag == 0 || lstat(expdir, &statb) >= 0) 1135 appendarglist(arglist, stsavestr(expdir)); 1136 return; 1137 } 1138 endname = name + (p - name); 1139 if (start != name) { 1140 p = name; 1141 while (p < start) { 1142 if (*p == CTLESC) 1143 p++; 1144 *enddir++ = *p++; 1145 if (enddir == expdir_end) 1146 return; 1147 } 1148 } 1149 if (enddir == expdir) { 1150 p = "."; 1151 } else if (enddir == expdir + 1 && *expdir == '/') { 1152 p = "/"; 1153 } else { 1154 p = expdir; 1155 enddir[-1] = '\0'; 1156 } 1157 if ((dirp = opendir(p)) == NULL) 1158 return; 1159 if (enddir != expdir) 1160 enddir[-1] = '/'; 1161 if (*endname == 0) { 1162 atend = 1; 1163 } else { 1164 atend = 0; 1165 *endname = '\0'; 1166 endname += esc + 1; 1167 } 1168 matchdot = 0; 1169 p = start; 1170 if (*p == CTLESC) 1171 p++; 1172 if (*p == '.') 1173 matchdot++; 1174 while (! int_pending() && (dp = readdir(dirp)) != NULL) { 1175 if (dp->d_name[0] == '.' && ! matchdot) 1176 continue; 1177 if (patmatch(start, dp->d_name)) { 1178 namlen = dp->d_namlen; 1179 if (enddir + namlen + 1 > expdir_end) 1180 continue; 1181 memcpy(enddir, dp->d_name, namlen + 1); 1182 if (atend) 1183 appendarglist(arglist, stsavestr(expdir)); 1184 else { 1185 if (dp->d_type != DT_UNKNOWN && 1186 dp->d_type != DT_DIR && 1187 dp->d_type != DT_LNK) 1188 continue; 1189 if (enddir + namlen + 2 > expdir_end) 1190 continue; 1191 enddir[namlen] = '/'; 1192 enddir[namlen + 1] = '\0'; 1193 expmeta(enddir + namlen + 1, endname, arglist); 1194 } 1195 } 1196 } 1197 closedir(dirp); 1198 if (! atend) 1199 endname[-esc - 1] = esc ? CTLESC : '/'; 1200 } 1201 1202 1203 static int 1204 expsortcmp(const void *p1, const void *p2) 1205 { 1206 const char *s1 = *(const char * const *)p1; 1207 const char *s2 = *(const char * const *)p2; 1208 1209 return (strcoll(s1, s2)); 1210 } 1211 1212 1213 1214 static wchar_t 1215 get_wc(const char **p) 1216 { 1217 wchar_t c; 1218 int chrlen; 1219 1220 chrlen = mbtowc(&c, *p, 4); 1221 if (chrlen == 0) 1222 return 0; 1223 else if (chrlen == -1) 1224 c = 0; 1225 else 1226 *p += chrlen; 1227 return c; 1228 } 1229 1230 1231 /* 1232 * See if a character matches a character class, starting at the first colon 1233 * of "[:class:]". 1234 * If a valid character class is recognized, a pointer to the next character 1235 * after the final closing bracket is stored into *end, otherwise a null 1236 * pointer is stored into *end. 1237 */ 1238 static int 1239 match_charclass(const char *p, wchar_t chr, const char **end) 1240 { 1241 char name[20]; 1242 const char *nameend; 1243 wctype_t cclass; 1244 1245 *end = NULL; 1246 p++; 1247 nameend = strstr(p, ":]"); 1248 if (nameend == NULL || (size_t)(nameend - p) >= sizeof(name) || 1249 nameend == p) 1250 return 0; 1251 memcpy(name, p, nameend - p); 1252 name[nameend - p] = '\0'; 1253 *end = nameend + 2; 1254 cclass = wctype(name); 1255 /* An unknown class matches nothing but is valid nevertheless. */ 1256 if (cclass == 0) 1257 return 0; 1258 return iswctype(chr, cclass); 1259 } 1260 1261 1262 /* 1263 * Returns true if the pattern matches the string. 1264 */ 1265 1266 static int 1267 patmatch(const char *pattern, const char *string) 1268 { 1269 const char *p, *q, *end; 1270 const char *bt_p, *bt_q; 1271 char c; 1272 wchar_t wc, wc2; 1273 1274 p = pattern; 1275 q = string; 1276 bt_p = NULL; 1277 bt_q = NULL; 1278 for (;;) { 1279 switch (c = *p++) { 1280 case '\0': 1281 if (*q != '\0') 1282 goto backtrack; 1283 return 1; 1284 case CTLESC: 1285 if (*q++ != *p++) 1286 goto backtrack; 1287 break; 1288 case '?': 1289 if (*q == '\0') 1290 return 0; 1291 if (localeisutf8) { 1292 wc = get_wc(&q); 1293 /* 1294 * A '?' does not match invalid UTF-8 but a 1295 * '*' does, so backtrack. 1296 */ 1297 if (wc == 0) 1298 goto backtrack; 1299 } else 1300 q++; 1301 break; 1302 case '*': 1303 c = *p; 1304 while (c == '*') 1305 c = *++p; 1306 /* 1307 * If the pattern ends here, we know the string 1308 * matches without needing to look at the rest of it. 1309 */ 1310 if (c == '\0') 1311 return 1; 1312 /* 1313 * First try the shortest match for the '*' that 1314 * could work. We can forget any earlier '*' since 1315 * there is no way having it match more characters 1316 * can help us, given that we are already here. 1317 */ 1318 bt_p = p; 1319 bt_q = q; 1320 break; 1321 case '[': { 1322 const char *savep, *saveq; 1323 int invert, found; 1324 wchar_t chr; 1325 1326 savep = p, saveq = q; 1327 invert = 0; 1328 if (*p == '!' || *p == '^') { 1329 invert++; 1330 p++; 1331 } 1332 found = 0; 1333 if (*q == '\0') 1334 return 0; 1335 if (localeisutf8) { 1336 chr = get_wc(&q); 1337 if (chr == 0) 1338 goto backtrack; 1339 } else 1340 chr = (unsigned char)*q++; 1341 c = *p++; 1342 do { 1343 if (c == '\0') { 1344 p = savep, q = saveq; 1345 c = '['; 1346 goto dft; 1347 } 1348 if (c == '[' && *p == ':') { 1349 found |= match_charclass(p, chr, &end); 1350 if (end != NULL) 1351 p = end; 1352 } 1353 if (c == CTLESC) 1354 c = *p++; 1355 if (localeisutf8 && c & 0x80) { 1356 p--; 1357 wc = get_wc(&p); 1358 if (wc == 0) /* bad utf-8 */ 1359 return 0; 1360 } else 1361 wc = (unsigned char)c; 1362 if (*p == '-' && p[1] != ']') { 1363 p++; 1364 if (*p == CTLESC) 1365 p++; 1366 if (localeisutf8) { 1367 wc2 = get_wc(&p); 1368 if (wc2 == 0) /* bad utf-8 */ 1369 return 0; 1370 } else 1371 wc2 = (unsigned char)*p++; 1372 if ( collate_range_cmp(chr, wc) >= 0 1373 && collate_range_cmp(chr, wc2) <= 0 1374 ) 1375 found = 1; 1376 } else { 1377 if (chr == wc) 1378 found = 1; 1379 } 1380 } while ((c = *p++) != ']'); 1381 if (found == invert) 1382 goto backtrack; 1383 break; 1384 } 1385 dft: default: 1386 if (*q == '\0') 1387 return 0; 1388 if (*q++ == c) 1389 break; 1390 backtrack: 1391 /* 1392 * If we have a mismatch (other than hitting the end 1393 * of the string), go back to the last '*' seen and 1394 * have it match one additional character. 1395 */ 1396 if (bt_p == NULL) 1397 return 0; 1398 if (*bt_q == '\0') 1399 return 0; 1400 bt_q++; 1401 p = bt_p; 1402 q = bt_q; 1403 break; 1404 } 1405 } 1406 } 1407 1408 1409 1410 /* 1411 * Remove any CTLESC and CTLQUOTEMARK characters from a string. 1412 */ 1413 1414 void 1415 rmescapes(char *str) 1416 { 1417 char *p, *q; 1418 1419 p = str; 1420 while (*p != CTLESC && *p != CTLQUOTEMARK && *p != CTLQUOTEEND) { 1421 if (*p++ == '\0') 1422 return; 1423 } 1424 q = p; 1425 while (*p) { 1426 if (*p == CTLQUOTEMARK || *p == CTLQUOTEEND) { 1427 p++; 1428 continue; 1429 } 1430 if (*p == CTLESC) 1431 p++; 1432 *q++ = *p++; 1433 } 1434 *q = '\0'; 1435 } 1436 1437 1438 1439 /* 1440 * See if a pattern matches in a case statement. 1441 */ 1442 1443 int 1444 casematch(union node *pattern, const char *val) 1445 { 1446 struct stackmark smark; 1447 struct nodelist *argbackq; 1448 int result; 1449 char *p; 1450 1451 setstackmark(&smark); 1452 argbackq = pattern->narg.backquote; 1453 STARTSTACKSTR(expdest); 1454 argstr(pattern->narg.text, &argbackq, EXP_TILDE | EXP_CASE, NULL); 1455 STPUTC('\0', expdest); 1456 p = grabstackstr(expdest); 1457 result = patmatch(p, val); 1458 popstackmark(&smark); 1459 return result; 1460 } 1461 1462 /* 1463 * Our own itoa(). 1464 */ 1465 1466 static void 1467 cvtnum(int num, char *buf) 1468 { 1469 char temp[32]; 1470 int neg = num < 0; 1471 char *p = temp + 31; 1472 1473 temp[31] = '\0'; 1474 1475 do { 1476 *--p = num % 10 + '0'; 1477 } while ((num /= 10) != 0); 1478 1479 if (neg) 1480 *--p = '-'; 1481 1482 memcpy(buf, p, temp + 32 - p); 1483 } 1484 1485 /* 1486 * Do most of the work for wordexp(3). 1487 */ 1488 1489 int 1490 wordexpcmd(int argc, char **argv) 1491 { 1492 size_t len; 1493 int i; 1494 1495 out1fmt("%08x", argc - 1); 1496 for (i = 1, len = 0; i < argc; i++) 1497 len += strlen(argv[i]); 1498 out1fmt("%08x", (int)len); 1499 for (i = 1; i < argc; i++) 1500 outbin(argv[i], strlen(argv[i]) + 1, out1); 1501 return (0); 1502 } 1503 1504 /* 1505 * Do most of the work for wordexp(3), new version. 1506 */ 1507 1508 int 1509 freebsd_wordexpcmd(int argc __unused, char **argv __unused) 1510 { 1511 struct arglist arglist; 1512 union node *args, *n; 1513 size_t len; 1514 int ch; 1515 int protected = 0; 1516 int fd = -1; 1517 int i; 1518 1519 while ((ch = nextopt("f:p")) != '\0') { 1520 switch (ch) { 1521 case 'f': 1522 fd = number(shoptarg); 1523 break; 1524 case 'p': 1525 protected = 1; 1526 break; 1527 } 1528 } 1529 if (*argptr != NULL) 1530 error("wrong number of arguments"); 1531 if (fd < 0) 1532 error("missing fd"); 1533 INTOFF; 1534 setinputfd(fd, 1); 1535 INTON; 1536 args = parsewordexp(); 1537 popfile(); /* will also close fd */ 1538 if (protected) 1539 for (n = args; n != NULL; n = n->narg.next) { 1540 if (n->narg.backquote != NULL) { 1541 outcslow('C', out1); 1542 error("command substitution disabled"); 1543 } 1544 } 1545 outcslow(' ', out1); 1546 emptyarglist(&arglist); 1547 for (n = args; n != NULL; n = n->narg.next) 1548 expandarg(n, &arglist, EXP_FULL | EXP_TILDE); 1549 for (i = 0, len = 0; i < arglist.count; i++) 1550 len += strlen(arglist.args[i]); 1551 out1fmt("%016x %016zx", arglist.count, len); 1552 for (i = 0; i < arglist.count; i++) 1553 outbin(arglist.args[i], strlen(arglist.args[i]) + 1, out1); 1554 return (0); 1555 } 1556