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 void 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: done\n")); 526 expdest = dest; 527 INTON; 528 } 529 530 531 532 static void 533 recordleft(const char *str, const char *loc, char *startp) 534 { 535 int amount; 536 537 amount = ((str - 1) - (loc - startp)) - expdest; 538 STADJUST(amount, expdest); 539 while (loc != str - 1) 540 *startp++ = *loc++; 541 } 542 543 static void 544 subevalvar_trim(const char *p, struct nodelist *argbackq, int strloc, 545 int subtype, int startloc) 546 { 547 char *startp; 548 char *loc = NULL; 549 char *str; 550 int c = 0; 551 struct nodelist *argbackqcopy = argbackq; 552 int amount; 553 554 argstr(p, &argbackqcopy, EXP_CASE | EXP_TILDE, NULL); 555 STACKSTRNUL(expdest); 556 startp = stackblock() + startloc; 557 str = stackblock() + strloc; 558 559 switch (subtype) { 560 case VSTRIMLEFT: 561 for (loc = startp; loc < str; loc++) { 562 c = *loc; 563 *loc = '\0'; 564 if (patmatch(str, startp)) { 565 *loc = c; 566 recordleft(str, loc, startp); 567 return; 568 } 569 *loc = c; 570 } 571 break; 572 573 case VSTRIMLEFTMAX: 574 for (loc = str - 1; loc >= startp;) { 575 c = *loc; 576 *loc = '\0'; 577 if (patmatch(str, startp)) { 578 *loc = c; 579 recordleft(str, loc, startp); 580 return; 581 } 582 *loc = c; 583 loc--; 584 } 585 break; 586 587 case VSTRIMRIGHT: 588 for (loc = str - 1; loc >= startp;) { 589 if (patmatch(str, loc)) { 590 amount = loc - expdest; 591 STADJUST(amount, expdest); 592 return; 593 } 594 loc--; 595 } 596 break; 597 598 case VSTRIMRIGHTMAX: 599 for (loc = startp; loc < str - 1; loc++) { 600 if (patmatch(str, loc)) { 601 amount = loc - expdest; 602 STADJUST(amount, expdest); 603 return; 604 } 605 } 606 break; 607 608 609 default: 610 abort(); 611 } 612 amount = (expdest - stackblock() - strloc) + 1; 613 STADJUST(-amount, expdest); 614 } 615 616 617 static void 618 subevalvar_misc(const char *p, struct nodelist *argbackq, const char *var, int subtype, int startloc, 619 int varflags) 620 { 621 char *startp; 622 struct nodelist *argbackqcopy = argbackq; 623 int amount; 624 625 argstr(p, &argbackqcopy, EXP_TILDE, NULL); 626 STACKSTRNUL(expdest); 627 startp = stackblock() + startloc; 628 629 switch (subtype) { 630 case VSASSIGN: 631 setvar(var, startp, 0); 632 amount = startp - expdest; 633 STADJUST(amount, expdest); 634 return; 635 636 case VSQUESTION: 637 if (*p != CTLENDVAR) { 638 outfmt(out2, "%s\n", startp); 639 error((char *)NULL); 640 } 641 error("%.*s: parameter %snot set", (int)(p - var - 1), 642 var, (varflags & VSNUL) ? "null or " : ""); 643 644 default: 645 abort(); 646 } 647 } 648 649 650 /* 651 * Expand a variable, and return a pointer to the next character in the 652 * input string. 653 */ 654 655 static const char * 656 evalvar(const char *p, struct nodelist **restrict argbackq, int flag, 657 struct worddest *dst) 658 { 659 int subtype; 660 int varflags; 661 const char *var; 662 const char *val; 663 int patloc; 664 int c; 665 int set; 666 int special; 667 int startloc; 668 int varlen; 669 int varlenb; 670 char buf[21]; 671 672 varflags = (unsigned char)*p++; 673 subtype = varflags & VSTYPE; 674 var = p; 675 special = 0; 676 if (! is_name(*p)) 677 special = 1; 678 p = strchr(p, '=') + 1; 679 again: /* jump here after setting a variable with ${var=text} */ 680 if (varflags & VSLINENO) { 681 set = 1; 682 special = 1; 683 val = NULL; 684 } else if (special) { 685 set = varisset(var, varflags & VSNUL); 686 val = NULL; 687 } else { 688 val = bltinlookup(var, 1); 689 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) { 690 val = NULL; 691 set = 0; 692 } else 693 set = 1; 694 } 695 varlen = 0; 696 startloc = expdest - stackblock(); 697 if (!set && uflag && *var != '@' && *var != '*') { 698 switch (subtype) { 699 case VSNORMAL: 700 case VSTRIMLEFT: 701 case VSTRIMLEFTMAX: 702 case VSTRIMRIGHT: 703 case VSTRIMRIGHTMAX: 704 case VSLENGTH: 705 error("%.*s: parameter not set", (int)(p - var - 1), 706 var); 707 } 708 } 709 if (set && subtype != VSPLUS) { 710 /* insert the value of the variable */ 711 if (special) { 712 if (varflags & VSLINENO) { 713 if (p - var > (ptrdiff_t)sizeof(buf)) 714 abort(); 715 memcpy(buf, var, p - var - 1); 716 buf[p - var - 1] = '\0'; 717 strtodest(buf, flag, subtype, 718 varflags & VSQUOTE, dst); 719 } else 720 varvalue(var, varflags & VSQUOTE, subtype, flag, 721 dst); 722 if (subtype == VSLENGTH) { 723 varlenb = expdest - stackblock() - startloc; 724 varlen = varlenb; 725 if (localeisutf8) { 726 val = stackblock() + startloc; 727 for (;val != expdest; val++) 728 if ((*val & 0xC0) == 0x80) 729 varlen--; 730 } 731 STADJUST(-varlenb, expdest); 732 } 733 } else { 734 if (subtype == VSLENGTH) { 735 for (;*val; val++) 736 if (!localeisutf8 || 737 (*val & 0xC0) != 0x80) 738 varlen++; 739 } 740 else 741 strtodest(val, flag, subtype, 742 varflags & VSQUOTE, dst); 743 } 744 } 745 746 if (subtype == VSPLUS) 747 set = ! set; 748 749 switch (subtype) { 750 case VSLENGTH: 751 cvtnum(varlen, buf); 752 strtodest(buf, flag, VSNORMAL, varflags & VSQUOTE, dst); 753 break; 754 755 case VSNORMAL: 756 break; 757 758 case VSPLUS: 759 case VSMINUS: 760 if (!set) { 761 argstr(p, argbackq, 762 flag | (flag & EXP_SPLIT ? EXP_SPLIT_LIT : 0) | 763 (varflags & VSQUOTE ? EXP_LIT_QUOTED : 0), dst); 764 break; 765 } 766 break; 767 768 case VSTRIMLEFT: 769 case VSTRIMLEFTMAX: 770 case VSTRIMRIGHT: 771 case VSTRIMRIGHTMAX: 772 if (!set) { 773 set = 1; 774 break; 775 } 776 /* 777 * Terminate the string and start recording the pattern 778 * right after it 779 */ 780 STPUTC('\0', expdest); 781 patloc = expdest - stackblock(); 782 subevalvar_trim(p, *argbackq, patloc, subtype, startloc); 783 reprocess(startloc, flag, VSNORMAL, varflags & VSQUOTE, dst); 784 if (flag & EXP_SPLIT && *var == '@' && varflags & VSQUOTE) 785 dst->state = WORD_QUOTEMARK; 786 break; 787 788 case VSASSIGN: 789 case VSQUESTION: 790 if (!set) { 791 subevalvar_misc(p, *argbackq, var, subtype, 792 startloc, varflags); 793 /* assert(subtype == VSASSIGN); */ 794 varflags &= ~VSNUL; 795 goto again; 796 } 797 break; 798 799 case VSERROR: 800 c = p - var - 1; 801 error("${%.*s%s}: Bad substitution", c, var, 802 (c > 0 && *p != CTLENDVAR) ? "..." : ""); 803 804 default: 805 abort(); 806 } 807 808 if (subtype != VSNORMAL) { /* skip to end of alternative */ 809 int nesting = 1; 810 for (;;) { 811 if ((c = *p++) == CTLESC) 812 p++; 813 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { 814 if (set) 815 *argbackq = (*argbackq)->next; 816 } else if (c == CTLVAR) { 817 if ((*p++ & VSTYPE) != VSNORMAL) 818 nesting++; 819 } else if (c == CTLENDVAR) { 820 if (--nesting == 0) 821 break; 822 } 823 } 824 } 825 return p; 826 } 827 828 829 830 /* 831 * Test whether a specialized variable is set. 832 */ 833 834 static int 835 varisset(const char *name, int nulok) 836 { 837 838 if (*name == '!') 839 return backgndpidset(); 840 else if (*name == '@' || *name == '*') { 841 if (*shellparam.p == NULL) 842 return 0; 843 844 if (nulok) { 845 char **av; 846 847 for (av = shellparam.p; *av; av++) 848 if (**av != '\0') 849 return 1; 850 return 0; 851 } 852 } else if (is_digit(*name)) { 853 char *ap; 854 long num; 855 856 errno = 0; 857 num = strtol(name, NULL, 10); 858 if (errno != 0 || num > shellparam.nparam) 859 return 0; 860 861 if (num == 0) 862 ap = arg0; 863 else 864 ap = shellparam.p[num - 1]; 865 866 if (nulok && (ap == NULL || *ap == '\0')) 867 return 0; 868 } 869 return 1; 870 } 871 872 static void 873 strtodest(const char *p, int flag, int subtype, int quoted, 874 struct worddest *dst) 875 { 876 if (subtype == VSLENGTH || subtype == VSTRIMLEFT || 877 subtype == VSTRIMLEFTMAX || subtype == VSTRIMRIGHT || 878 subtype == VSTRIMRIGHTMAX) 879 STPUTS(p, expdest); 880 else if (flag & EXP_SPLIT && !quoted && dst != NULL) 881 STPUTS_SPLIT(p, BASESYNTAX, flag, expdest, dst); 882 else if (flag & (EXP_GLOB | EXP_CASE)) 883 STPUTS_QUOTES(p, quoted ? DQSYNTAX : BASESYNTAX, expdest); 884 else 885 STPUTS(p, expdest); 886 } 887 888 static void 889 reprocess(int startloc, int flag, int subtype, int quoted, 890 struct worddest *dst) 891 { 892 static char *buf = NULL; 893 static size_t buflen = 0; 894 char *startp; 895 size_t len, zpos, zlen; 896 897 startp = stackblock() + startloc; 898 len = expdest - startp; 899 if (len >= SIZE_MAX / 2) 900 abort(); 901 INTOFF; 902 if (len >= buflen) { 903 ckfree(buf); 904 buf = NULL; 905 } 906 if (buflen < 128) 907 buflen = 128; 908 while (len >= buflen) 909 buflen <<= 1; 910 if (buf == NULL) 911 buf = ckmalloc(buflen); 912 INTON; 913 memcpy(buf, startp, len); 914 buf[len] = '\0'; 915 STADJUST(-len, expdest); 916 for (zpos = 0;;) { 917 zlen = strlen(buf + zpos); 918 strtodest(buf + zpos, flag, subtype, quoted, dst); 919 zpos += zlen + 1; 920 if (zpos == len + 1) 921 break; 922 if (flag & EXP_SPLIT && (quoted || (zlen > 0 && zpos < len))) 923 NEXTWORD('\0', flag, expdest, dst); 924 } 925 } 926 927 /* 928 * Add the value of a specialized variable to the stack string. 929 */ 930 931 static void 932 varvalue(const char *name, int quoted, int subtype, int flag, 933 struct worddest *dst) 934 { 935 int num; 936 char *p; 937 int i; 938 int splitlater; 939 char sep[2]; 940 char **ap; 941 char buf[(NSHORTOPTS > 10 ? NSHORTOPTS : 10) + 1]; 942 943 if (subtype == VSLENGTH) 944 flag &= ~EXP_FULL; 945 splitlater = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX || 946 subtype == VSTRIMRIGHT || subtype == VSTRIMRIGHTMAX; 947 948 switch (*name) { 949 case '$': 950 num = rootpid; 951 break; 952 case '?': 953 num = oexitstatus; 954 break; 955 case '#': 956 num = shellparam.nparam; 957 break; 958 case '!': 959 num = backgndpidval(); 960 break; 961 case '-': 962 p = buf; 963 for (i = 0 ; i < NSHORTOPTS ; i++) { 964 if (optval[i]) 965 *p++ = optletter[i]; 966 } 967 *p = '\0'; 968 strtodest(buf, flag, subtype, quoted, dst); 969 return; 970 case '@': 971 if (flag & EXP_SPLIT && quoted) { 972 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { 973 strtodest(p, flag, subtype, quoted, dst); 974 if (*ap) { 975 if (splitlater) 976 STPUTC('\0', expdest); 977 else 978 NEXTWORD('\0', flag, expdest, 979 dst); 980 } 981 } 982 if (shellparam.nparam > 0) 983 dst->state = WORD_QUOTEMARK; 984 return; 985 } 986 /* FALLTHROUGH */ 987 case '*': 988 if (ifsset()) 989 sep[0] = ifsval()[0]; 990 else 991 sep[0] = ' '; 992 sep[1] = '\0'; 993 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { 994 strtodest(p, flag, subtype, quoted, dst); 995 if (!*ap) 996 break; 997 if (sep[0]) 998 strtodest(sep, flag, subtype, quoted, dst); 999 else if (flag & EXP_SPLIT && !quoted && **ap != '\0') { 1000 if (splitlater) 1001 STPUTC('\0', expdest); 1002 else 1003 NEXTWORD('\0', flag, expdest, dst); 1004 } 1005 } 1006 return; 1007 default: 1008 if (is_digit(*name)) { 1009 num = atoi(name); 1010 if (num == 0) 1011 p = arg0; 1012 else if (num > 0 && num <= shellparam.nparam) 1013 p = shellparam.p[num - 1]; 1014 else 1015 return; 1016 strtodest(p, flag, subtype, quoted, dst); 1017 } 1018 return; 1019 } 1020 cvtnum(num, buf); 1021 strtodest(buf, flag, subtype, quoted, dst); 1022 } 1023 1024 1025 1026 static char expdir[PATH_MAX]; 1027 #define expdir_end (expdir + sizeof(expdir)) 1028 1029 /* 1030 * Perform pathname generation and remove control characters. 1031 * At this point, the only control characters should be CTLESC. 1032 * The results are stored in the list dstlist. 1033 */ 1034 static void 1035 expandmeta(char *pattern, struct arglist *dstlist) 1036 { 1037 char *p; 1038 int firstmatch; 1039 char c; 1040 1041 firstmatch = dstlist->count; 1042 p = pattern; 1043 for (; (c = *p) != '\0'; p++) { 1044 /* fast check for meta chars */ 1045 if (c == '*' || c == '?' || c == '[') { 1046 INTOFF; 1047 expmeta(expdir, pattern, dstlist); 1048 INTON; 1049 break; 1050 } 1051 } 1052 if (dstlist->count == firstmatch) { 1053 /* 1054 * no matches 1055 */ 1056 rmescapes(pattern); 1057 appendarglist(dstlist, pattern); 1058 } else { 1059 qsort(&dstlist->args[firstmatch], 1060 dstlist->count - firstmatch, 1061 sizeof(dstlist->args[0]), expsortcmp); 1062 } 1063 } 1064 1065 1066 /* 1067 * Do metacharacter (i.e. *, ?, [...]) expansion. 1068 */ 1069 1070 static void 1071 expmeta(char *enddir, char *name, struct arglist *arglist) 1072 { 1073 const char *p; 1074 const char *q; 1075 const char *start; 1076 char *endname; 1077 int metaflag; 1078 struct stat statb; 1079 DIR *dirp; 1080 struct dirent *dp; 1081 int atend; 1082 int matchdot; 1083 int esc; 1084 int namlen; 1085 1086 metaflag = 0; 1087 start = name; 1088 for (p = name; esc = 0, *p; p += esc + 1) { 1089 if (*p == '*' || *p == '?') 1090 metaflag = 1; 1091 else if (*p == '[') { 1092 q = p + 1; 1093 if (*q == '!' || *q == '^') 1094 q++; 1095 for (;;) { 1096 if (*q == CTLESC) 1097 q++; 1098 if (*q == '/' || *q == '\0') 1099 break; 1100 if (*++q == ']') { 1101 metaflag = 1; 1102 break; 1103 } 1104 } 1105 } else if (*p == '\0') 1106 break; 1107 else { 1108 if (*p == CTLESC) 1109 esc++; 1110 if (p[esc] == '/') { 1111 if (metaflag) 1112 break; 1113 start = p + esc + 1; 1114 } 1115 } 1116 } 1117 if (metaflag == 0) { /* we've reached the end of the file name */ 1118 if (enddir != expdir) 1119 metaflag++; 1120 for (p = name ; ; p++) { 1121 if (*p == CTLESC) 1122 p++; 1123 *enddir++ = *p; 1124 if (*p == '\0') 1125 break; 1126 if (enddir == expdir_end) 1127 return; 1128 } 1129 if (metaflag == 0 || lstat(expdir, &statb) >= 0) 1130 appendarglist(arglist, stsavestr(expdir)); 1131 return; 1132 } 1133 endname = name + (p - name); 1134 if (start != name) { 1135 p = name; 1136 while (p < start) { 1137 if (*p == CTLESC) 1138 p++; 1139 *enddir++ = *p++; 1140 if (enddir == expdir_end) 1141 return; 1142 } 1143 } 1144 if (enddir == expdir) { 1145 p = "."; 1146 } else if (enddir == expdir + 1 && *expdir == '/') { 1147 p = "/"; 1148 } else { 1149 p = expdir; 1150 enddir[-1] = '\0'; 1151 } 1152 if ((dirp = opendir(p)) == NULL) 1153 return; 1154 if (enddir != expdir) 1155 enddir[-1] = '/'; 1156 if (*endname == 0) { 1157 atend = 1; 1158 } else { 1159 atend = 0; 1160 *endname = '\0'; 1161 endname += esc + 1; 1162 } 1163 matchdot = 0; 1164 p = start; 1165 if (*p == CTLESC) 1166 p++; 1167 if (*p == '.') 1168 matchdot++; 1169 while (! int_pending() && (dp = readdir(dirp)) != NULL) { 1170 if (dp->d_name[0] == '.' && ! matchdot) 1171 continue; 1172 if (patmatch(start, dp->d_name)) { 1173 namlen = dp->d_namlen; 1174 if (enddir + namlen + 1 > expdir_end) 1175 continue; 1176 memcpy(enddir, dp->d_name, namlen + 1); 1177 if (atend) 1178 appendarglist(arglist, stsavestr(expdir)); 1179 else { 1180 if (dp->d_type != DT_UNKNOWN && 1181 dp->d_type != DT_DIR && 1182 dp->d_type != DT_LNK) 1183 continue; 1184 if (enddir + namlen + 2 > expdir_end) 1185 continue; 1186 enddir[namlen] = '/'; 1187 enddir[namlen + 1] = '\0'; 1188 expmeta(enddir + namlen + 1, endname, arglist); 1189 } 1190 } 1191 } 1192 closedir(dirp); 1193 if (! atend) 1194 endname[-esc - 1] = esc ? CTLESC : '/'; 1195 } 1196 1197 1198 static int 1199 expsortcmp(const void *p1, const void *p2) 1200 { 1201 const char *s1 = *(const char * const *)p1; 1202 const char *s2 = *(const char * const *)p2; 1203 1204 return (strcoll(s1, s2)); 1205 } 1206 1207 1208 1209 static wchar_t 1210 get_wc(const char **p) 1211 { 1212 wchar_t c; 1213 int chrlen; 1214 1215 chrlen = mbtowc(&c, *p, 4); 1216 if (chrlen == 0) 1217 return 0; 1218 else if (chrlen == -1) 1219 c = 0; 1220 else 1221 *p += chrlen; 1222 return c; 1223 } 1224 1225 1226 /* 1227 * See if a character matches a character class, starting at the first colon 1228 * of "[:class:]". 1229 * If a valid character class is recognized, a pointer to the next character 1230 * after the final closing bracket is stored into *end, otherwise a null 1231 * pointer is stored into *end. 1232 */ 1233 static int 1234 match_charclass(const char *p, wchar_t chr, const char **end) 1235 { 1236 char name[20]; 1237 const char *nameend; 1238 wctype_t cclass; 1239 1240 *end = NULL; 1241 p++; 1242 nameend = strstr(p, ":]"); 1243 if (nameend == NULL || (size_t)(nameend - p) >= sizeof(name) || 1244 nameend == p) 1245 return 0; 1246 memcpy(name, p, nameend - p); 1247 name[nameend - p] = '\0'; 1248 *end = nameend + 2; 1249 cclass = wctype(name); 1250 /* An unknown class matches nothing but is valid nevertheless. */ 1251 if (cclass == 0) 1252 return 0; 1253 return iswctype(chr, cclass); 1254 } 1255 1256 1257 /* 1258 * Returns true if the pattern matches the string. 1259 */ 1260 1261 static int 1262 patmatch(const char *pattern, const char *string) 1263 { 1264 const char *p, *q, *end; 1265 const char *bt_p, *bt_q; 1266 char c; 1267 wchar_t wc, wc2; 1268 1269 p = pattern; 1270 q = string; 1271 bt_p = NULL; 1272 bt_q = NULL; 1273 for (;;) { 1274 switch (c = *p++) { 1275 case '\0': 1276 if (*q != '\0') 1277 goto backtrack; 1278 return 1; 1279 case CTLESC: 1280 if (*q++ != *p++) 1281 goto backtrack; 1282 break; 1283 case '?': 1284 if (*q == '\0') 1285 return 0; 1286 if (localeisutf8) { 1287 wc = get_wc(&q); 1288 /* 1289 * A '?' does not match invalid UTF-8 but a 1290 * '*' does, so backtrack. 1291 */ 1292 if (wc == 0) 1293 goto backtrack; 1294 } else 1295 q++; 1296 break; 1297 case '*': 1298 c = *p; 1299 while (c == '*') 1300 c = *++p; 1301 /* 1302 * If the pattern ends here, we know the string 1303 * matches without needing to look at the rest of it. 1304 */ 1305 if (c == '\0') 1306 return 1; 1307 /* 1308 * First try the shortest match for the '*' that 1309 * could work. We can forget any earlier '*' since 1310 * there is no way having it match more characters 1311 * can help us, given that we are already here. 1312 */ 1313 bt_p = p; 1314 bt_q = q; 1315 break; 1316 case '[': { 1317 const char *savep, *saveq; 1318 int invert, found; 1319 wchar_t chr; 1320 1321 savep = p, saveq = q; 1322 invert = 0; 1323 if (*p == '!' || *p == '^') { 1324 invert++; 1325 p++; 1326 } 1327 found = 0; 1328 if (*q == '\0') 1329 return 0; 1330 if (localeisutf8) { 1331 chr = get_wc(&q); 1332 if (chr == 0) 1333 goto backtrack; 1334 } else 1335 chr = (unsigned char)*q++; 1336 c = *p++; 1337 do { 1338 if (c == '\0') { 1339 p = savep, q = saveq; 1340 c = '['; 1341 goto dft; 1342 } 1343 if (c == '[' && *p == ':') { 1344 found |= match_charclass(p, chr, &end); 1345 if (end != NULL) 1346 p = end; 1347 } 1348 if (c == CTLESC) 1349 c = *p++; 1350 if (localeisutf8 && c & 0x80) { 1351 p--; 1352 wc = get_wc(&p); 1353 if (wc == 0) /* bad utf-8 */ 1354 return 0; 1355 } else 1356 wc = (unsigned char)c; 1357 if (*p == '-' && p[1] != ']') { 1358 p++; 1359 if (*p == CTLESC) 1360 p++; 1361 if (localeisutf8) { 1362 wc2 = get_wc(&p); 1363 if (wc2 == 0) /* bad utf-8 */ 1364 return 0; 1365 } else 1366 wc2 = (unsigned char)*p++; 1367 if ( collate_range_cmp(chr, wc) >= 0 1368 && collate_range_cmp(chr, wc2) <= 0 1369 ) 1370 found = 1; 1371 } else { 1372 if (chr == wc) 1373 found = 1; 1374 } 1375 } while ((c = *p++) != ']'); 1376 if (found == invert) 1377 goto backtrack; 1378 break; 1379 } 1380 dft: default: 1381 if (*q == '\0') 1382 return 0; 1383 if (*q++ == c) 1384 break; 1385 backtrack: 1386 /* 1387 * If we have a mismatch (other than hitting the end 1388 * of the string), go back to the last '*' seen and 1389 * have it match one additional character. 1390 */ 1391 if (bt_p == NULL) 1392 return 0; 1393 if (*bt_q == '\0') 1394 return 0; 1395 bt_q++; 1396 p = bt_p; 1397 q = bt_q; 1398 break; 1399 } 1400 } 1401 } 1402 1403 1404 1405 /* 1406 * Remove any CTLESC and CTLQUOTEMARK characters from a string. 1407 */ 1408 1409 void 1410 rmescapes(char *str) 1411 { 1412 char *p, *q; 1413 1414 p = str; 1415 while (*p != CTLESC && *p != CTLQUOTEMARK && *p != CTLQUOTEEND) { 1416 if (*p++ == '\0') 1417 return; 1418 } 1419 q = p; 1420 while (*p) { 1421 if (*p == CTLQUOTEMARK || *p == CTLQUOTEEND) { 1422 p++; 1423 continue; 1424 } 1425 if (*p == CTLESC) 1426 p++; 1427 *q++ = *p++; 1428 } 1429 *q = '\0'; 1430 } 1431 1432 1433 1434 /* 1435 * See if a pattern matches in a case statement. 1436 */ 1437 1438 int 1439 casematch(union node *pattern, const char *val) 1440 { 1441 struct stackmark smark; 1442 struct nodelist *argbackq; 1443 int result; 1444 char *p; 1445 1446 setstackmark(&smark); 1447 argbackq = pattern->narg.backquote; 1448 STARTSTACKSTR(expdest); 1449 argstr(pattern->narg.text, &argbackq, EXP_TILDE | EXP_CASE, NULL); 1450 STPUTC('\0', expdest); 1451 p = grabstackstr(expdest); 1452 result = patmatch(p, val); 1453 popstackmark(&smark); 1454 return result; 1455 } 1456 1457 /* 1458 * Our own itoa(). 1459 */ 1460 1461 static void 1462 cvtnum(int num, char *buf) 1463 { 1464 char temp[32]; 1465 int neg = num < 0; 1466 char *p = temp + 31; 1467 1468 temp[31] = '\0'; 1469 1470 do { 1471 *--p = num % 10 + '0'; 1472 } while ((num /= 10) != 0); 1473 1474 if (neg) 1475 *--p = '-'; 1476 1477 memcpy(buf, p, temp + 32 - p); 1478 } 1479 1480 /* 1481 * Do most of the work for wordexp(3). 1482 */ 1483 1484 int 1485 wordexpcmd(int argc, char **argv) 1486 { 1487 size_t len; 1488 int i; 1489 1490 out1fmt("%08x", argc - 1); 1491 for (i = 1, len = 0; i < argc; i++) 1492 len += strlen(argv[i]); 1493 out1fmt("%08x", (int)len); 1494 for (i = 1; i < argc; i++) 1495 outbin(argv[i], strlen(argv[i]) + 1, out1); 1496 return (0); 1497 } 1498 1499 /* 1500 * Do most of the work for wordexp(3), new version. 1501 */ 1502 1503 int 1504 freebsd_wordexpcmd(int argc __unused, char **argv __unused) 1505 { 1506 struct arglist arglist; 1507 union node *args, *n; 1508 size_t len; 1509 int ch; 1510 int protected = 0; 1511 int fd = -1; 1512 int i; 1513 1514 while ((ch = nextopt("f:p")) != '\0') { 1515 switch (ch) { 1516 case 'f': 1517 fd = number(shoptarg); 1518 break; 1519 case 'p': 1520 protected = 1; 1521 break; 1522 } 1523 } 1524 if (*argptr != NULL) 1525 error("wrong number of arguments"); 1526 if (fd < 0) 1527 error("missing fd"); 1528 INTOFF; 1529 setinputfd(fd, 1); 1530 INTON; 1531 args = parsewordexp(); 1532 popfile(); /* will also close fd */ 1533 if (protected) 1534 for (n = args; n != NULL; n = n->narg.next) { 1535 if (n->narg.backquote != NULL) { 1536 outcslow('C', out1); 1537 error("command substitution disabled"); 1538 } 1539 } 1540 outcslow(' ', out1); 1541 emptyarglist(&arglist); 1542 for (n = args; n != NULL; n = n->narg.next) 1543 expandarg(n, &arglist, EXP_FULL | EXP_TILDE); 1544 for (i = 0, len = 0; i < arglist.count; i++) 1545 len += strlen(arglist.args[i]); 1546 out1fmt("%016x %016zx", arglist.count, len); 1547 for (i = 0; i < arglist.count; i++) 1548 outbin(arglist.args[i], strlen(arglist.args[i]) + 1, out1); 1549 return (0); 1550 } 1551