1 /* $NetBSD: expand.c,v 1.152 2026/08/15 19:23:51 kre Exp $ */ 2 3 /*- 4 * Copyright (c) 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Kenneth Almquist. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 #ifndef lint 37 #if 0 38 static char sccsid[] = "@(#)expand.c 8.5 (Berkeley) 5/15/95"; 39 #else 40 __RCSID("$NetBSD: expand.c,v 1.152 2026/08/15 19:23:51 kre Exp $"); 41 #endif 42 #endif /* not lint */ 43 44 #include <sys/types.h> 45 #include <sys/time.h> 46 #include <sys/stat.h> 47 #include <errno.h> 48 #include <dirent.h> 49 #include <unistd.h> 50 #include <pwd.h> 51 #include <limits.h> 52 #include <stdlib.h> 53 #include <stdio.h> 54 #include <wctype.h> 55 #include <wchar.h> 56 57 /* 58 * Routines to expand arguments to commands. We have to deal with 59 * backquotes, shell variables, and file metacharacters. 60 */ 61 62 #include "shell.h" 63 #include "main.h" 64 #include "nodes.h" 65 #include "eval.h" 66 #include "expand.h" 67 #include "syntax.h" 68 #include "arithmetic.h" 69 #include "parser.h" 70 #include "jobs.h" 71 #include "options.h" 72 #include "builtins.h" 73 #include "var.h" 74 #include "input.h" 75 #include "output.h" 76 #include "memalloc.h" 77 #include "error.h" 78 #include "mystring.h" 79 #include "show.h" 80 81 /* 82 * Structure specifying which parts of the string should be searched 83 * for IFS characters. 84 */ 85 86 struct ifsregion { 87 struct ifsregion *next; /* next region in list */ 88 int begoff; /* offset of start of region */ 89 int endoff; /* offset of end of region */ 90 int inquotes; /* search for nul bytes only */ 91 }; 92 93 94 char *expdest; /* output of current string */ 95 struct nodelist *argbackq; /* list of back quote expressions */ 96 struct ifsregion ifsfirst; /* first struct in list of ifs regions */ 97 struct ifsregion *ifslastp; /* last struct in list */ 98 struct arglist exparg; /* holds expanded arg list */ 99 100 static int empty_dollar_at; /* have expanded "$@" to nothing */ 101 102 STATIC const char *argstr(const char *, int); 103 STATIC const char *exptilde(const char *, int); 104 STATIC void expbackq(union node *, int, int); 105 STATIC const char *expari(const char *); 106 STATIC int subevalvar(const char *, const char *, int, int, int); 107 STATIC int subevalvar_trim(const char *, int, int, int, int, int); 108 STATIC const char *evalvar(const char *, int); 109 STATIC int varisset(const char *, int); 110 STATIC void varvalue(const char *, int, int, int); 111 STATIC void recordregion(int, int, int); 112 STATIC void removerecordregions(int); 113 STATIC void ifsbreakup(char *, size_t, struct arglist *); 114 STATIC void ifsfree(void); 115 STATIC void expandmeta(struct strlist *, int); 116 STATIC void expmeta(char *, char *); 117 STATIC void addfname(char *); 118 STATIC struct strlist *expsort(struct strlist *); 119 STATIC struct strlist *msort(struct strlist *, int); 120 STATIC int patmatch(const char *, const char *, int); 121 STATIC char *cvtnum(int, char *); 122 static int collate_range_cmp(wchar_t, wchar_t); 123 STATIC void add_args(struct strlist *); 124 STATIC void rmescapes_nl(char *); 125 126 #ifdef DEBUG 127 static char *showchar(char *, char, int *); 128 static char *showstr(const char *, int); 129 #define NULLTERM_4_TRACE(p) STACKSTRNUL(p) 130 #else 131 #define NULLTERM_4_TRACE(p) do { /* nothing */ } while (0) 132 #endif 133 134 #define IS_BORING(_ch) \ 135 ((_ch) == CTLQUOTEMARK || (_ch) == CTLQUOTEEND || (_ch) == CTLNONL) 136 #define SKIP_BORING(p) \ 137 do { \ 138 char _ch; \ 139 \ 140 while ((_ch = *(p)), IS_BORING(_ch)) \ 141 (p)++; \ 142 } while (0) 143 144 /* 145 * Expand shell variables and backquotes inside a here document. 146 */ 147 148 char * 149 expandhere(union node *arg) 150 { 151 int len; 152 153 VTRACE(DBG_EXPAND|DBG_REDIR, ("expandhere(%p)\n", arg)); 154 expandarg(arg, NULL, 0); 155 len = rmescapes(stackblock()); 156 VTRACE(DBG_EXPAND|DBG_REDIR, ("expandhere() -> %d\n", len)); 157 return stalloc(len + 1); /* include the \0 */ 158 } 159 160 161 static int 162 collate_range_cmp(wchar_t c1, wchar_t c2) 163 { 164 wchar_t s1[2], s2[2]; 165 166 s1[0] = c1; 167 s1[1] = L'\0'; 168 s2[0] = c2; 169 s2[1] = L'\0'; 170 return (wcscoll(s1, s2)); 171 } 172 173 /* 174 * Perform variable substitution and command substitution on an argument, 175 * placing the resulting list of arguments in arglist. If EXP_FULL is true, 176 * perform splitting and file name expansion. When arglist is NULL, perform 177 * here document expansion. 178 */ 179 180 void 181 expandarg(union node *arg, struct arglist *arglist, int flag) 182 { 183 struct strlist *sp; 184 char *p; 185 size_t len; 186 187 CTRACE(DBG_EXPAND, ("expandarg(fl=%#x)\n", flag)); 188 if (fflag) /* no filename expandsion */ 189 flag &= ~EXP_GLOB; 190 191 empty_dollar_at = 0; 192 argbackq = arg->narg.backquote; 193 STARTSTACKSTR(expdest); 194 ifsfirst.next = NULL; 195 ifslastp = NULL; 196 line_number = arg->narg.lineno; 197 argstr(arg->narg.text, flag); 198 if (arglist == NULL) { 199 STACKSTRNUL(expdest); 200 DEBUG_ONLY(len = expdest - stackblock()); 201 CTRACE(DBG_EXPAND, 202 ("expandarg: no arglist, done[%d] (len %zu) \"%s\"\n", 203 back_exitstatus, len, showstr(stackblock(), (int)len))); 204 return; /* here document expanded */ 205 } 206 STPUTC('\0', expdest); 207 len = expdest - stackblock() - 1; 208 CTRACE(DBG_EXPAND, ("expandarg: arglist got (%zu) \"%s\"\n", 209 len, showstr(stackblock(), (int)len))); 210 p = grabstackstr(expdest); 211 exparg.lastp = &exparg.list; 212 /* 213 * TODO - EXP_REDIR 214 */ 215 if (flag & EXP_SPLIT) { 216 ifsbreakup(p, len, &exparg); 217 *exparg.lastp = NULL; 218 exparg.lastp = &exparg.list; 219 if (flag & EXP_GLOB) 220 expandmeta(exparg.list, flag); 221 else 222 add_args(exparg.list); 223 #if 0 224 } else if (flag & EXP_REDIR) { 225 /* if EXP_REDIR ever happens, it happens here */ 226 /* for now just (below) remove escapes, and leave it alone */ 227 #endif 228 } else { 229 rmescapes(p); /* we might have escaped CTL bytes to remove */ 230 sp = stalloc(sizeof(*sp)); 231 sp->text = p; 232 *exparg.lastp = sp; 233 exparg.lastp = &sp->next; 234 } 235 ifsfree(); 236 *exparg.lastp = NULL; 237 if (exparg.list) { 238 *arglist->lastp = exparg.list; 239 arglist->lastp = exparg.lastp; 240 } 241 } 242 243 /* 244 * Perform variable and command substitution. 245 * If EXP_GLOB is set, output CTLESC characters to allow for further processing. 246 * If EXP_SPLIT is set, remember location of result for later, 247 * Otherwise treat $@ like $* since no splitting will be performed. 248 */ 249 250 STATIC const char * 251 argstr(const char *p, int flag) 252 { 253 char c; 254 const int quotes = flag & EXP_QNEEDED; /* do CTLESC */ 255 int firsteq = 1; 256 int had_dol_at = 0; 257 int startoff; 258 const char *ifs = NULL; 259 int ifs_split = EXP_IFS_SPLIT; 260 261 if (flag & EXP_IFS_SPLIT) 262 ifs = ifsval(); 263 264 CTRACE(DBG_EXPAND, ("argstr(\"%s\", %#x)%s\n", 265 showstr(p, -1), flag, quotes ? " EXP_QNEEDED" : "")); 266 267 startoff = expdest - stackblock(); 268 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE))) 269 p = exptilde(p, flag); 270 for (;;) { 271 switch (c = *p++) { 272 case '\0': 273 NULLTERM_4_TRACE(expdest); 274 VTRACE(DBG_EXPAND, ("argstr returning at \"\" " 275 "added \"%s\" to expdest\n", 276 showstr(stackblock(), expdest - stackblock()))); 277 return p - 1; 278 case CTLENDVAR: /* end of expanding yyy in ${xxx-yyy} */ 279 case CTLENDARI: /* end of a $(( )) string */ 280 if (had_dol_at && *p == CTLQUOTEEND) 281 p++; 282 NULLTERM_4_TRACE(expdest); 283 VTRACE(DBG_EXPAND, ("argstr returning at \"%.6s\"..." 284 " after %2.2X; added \"%s\" to expdest\n", 285 p, (c & 0xff), 286 showstr(stackblock(), expdest - stackblock()))); 287 return p; 288 case CTLQUOTEMARK: 289 /* "$@" syntax adherence hack */ 290 if (p[0] == CTLVAR && p[1] & VSQUOTE && 291 p[2] == '@' && p[3] == '=') { 292 had_dol_at = 1; 293 break; 294 } 295 had_dol_at = 0; 296 empty_dollar_at = 0; 297 if ((flag & EXP_SPLIT) != 0) 298 STPUTC(c, expdest); 299 ifs_split = 0; 300 break; 301 case CTLNONL: 302 if (flag & EXP_NL) 303 STPUTC(c, expdest); 304 line_number++; 305 break; 306 case CTLCNL: 307 STPUTC('\n', expdest); /* no line_number++ */ 308 break; 309 case CTLQUOTEEND: 310 if (empty_dollar_at && 311 expdest - stackblock() > startoff && 312 expdest[-1] == CTLQUOTEMARK) 313 STUNPUTC(expdest); 314 else if (!had_dol_at && (flag & EXP_SPLIT) != 0) 315 STPUTC(c, expdest); 316 ifs_split = EXP_IFS_SPLIT; 317 had_dol_at = 0; 318 break; 319 case CTLESC: 320 if (quotes || ISCTL(*p)) 321 STPUTC(c, expdest); 322 c = *p++; 323 STPUTC(c, expdest); 324 if (c == '\n') /* should not happen, but ... */ 325 line_number++; 326 break; 327 case CTLVAR: { 328 int xf = 0; 329 DEBUG_ONLY(unsigned int pos = expdest - stackblock()); 330 331 NULLTERM_4_TRACE(expdest); 332 if (shellparam.nparam > 1) { 333 /* 334 * Flags just in case we are expanding $* ($@) 335 * in a field splitting context. These are 336 * irrelevant (unused) in all other cases. 337 * 338 * If there are 0 or 1 numeric params, then $* 339 * should just vanish if $1 exists and is "" 340 * 341 * But for 2 or more params, we need to keep 342 * "" first and last params, if our expansion 343 * abuts other text (before or after) 344 */ 345 if (expdest != stackblock() && 346 expdest[-1] != '\0') 347 xf |= EXP_NEEDFIRST; /* $* magic */ 348 if (p[0] == VSNORMAL && /* p[2] == '=' && */ 349 (p[1] == '*' || p[1] == '@') && 350 p[3] != '\0') 351 xf |= EXP_NEEDLAST; /* magic++ */ 352 } 353 354 p = evalvar(p, (flag & ~EXP_IFS_SPLIT) | 355 (flag & ifs_split) | xf); 356 357 NULLTERM_4_TRACE(expdest); 358 VTRACE(DBG_EXPAND, ("argstr evalvar " 359 "added %zd \"%s\" to expdest\n", 360 (size_t)(expdest - (stackblock() + pos)), 361 showstr(stackblock() + pos, 362 (int)(expdest - (stackblock() + pos))))); 363 break; 364 } 365 case CTLBACKQ: 366 case CTLBACKQ|CTLQUOTE: { 367 DEBUG_ONLY(unsigned int pos = expdest - stackblock()); 368 369 expbackq(argbackq->n, c & CTLQUOTE, flag); 370 argbackq = argbackq->next; 371 NULLTERM_4_TRACE(expdest); 372 VTRACE(DBG_EXPAND, ("argstr expbackq added \"%s\" " 373 "to expdest\n", showstr(stackblock() + pos, 374 (int)(expdest - (stackblock() + pos))))); 375 break; 376 } 377 case CTLARI: { 378 DEBUG_ONLY(unsigned int pos = expdest - stackblock()); 379 380 p = expari(p); 381 NULLTERM_4_TRACE(expdest); 382 VTRACE(DBG_EXPAND, ("argstr expari " 383 "+ \"%s\" to expdest p=\"%.5s...\"\n", 384 stackblock() + pos, p)); 385 break; 386 } 387 case ':': 388 case '=': 389 /* 390 * sort of a hack - expand tildes in variable 391 * assignments (after the first '=' and after ':'s). 392 */ 393 STPUTC(c, expdest); 394 if (flag & ifs_split && strchr(ifs, c) != NULL) { 395 /* We need to get the output split here... */ 396 recordregion(expdest - stackblock() - 1, 397 expdest - stackblock(), 0); 398 } 399 if (flag & EXP_VARTILDE && *p == '~') { 400 if (c == '=') { 401 if (firsteq) 402 firsteq = 0; 403 else 404 break; 405 } 406 p = exptilde(p, flag); 407 } 408 break; 409 default: 410 if (c == '\n') 411 line_number++; 412 STPUTC(c, expdest); 413 if (flag & ifs_split && strchr(ifs, c) != NULL) { 414 /* We need to get the output split here... */ 415 recordregion(expdest - stackblock() - 1, 416 expdest - stackblock(), 0); 417 } 418 break; 419 } 420 } 421 } 422 423 STATIC const char * 424 exptilde(const char *p, int flag) 425 { 426 char c, last; 427 const char *startp = p; 428 struct passwd *pw; 429 const char *home; 430 const int quotes = flag & EXP_QNEEDED; 431 char *user; 432 struct stackmark smark; 433 DEBUG_ONLY(unsigned int offs = expdest - stackblock()); 434 435 setstackmark(&smark); 436 (void) grabstackstr(expdest); 437 user = stackblock(); /* we will just borrow top of stack */ 438 439 while ((c = *++p) != '\0') { 440 switch(c) { 441 case CTLESC: /* any of these occurring */ 442 case CTLVAR: /* means ~ expansion */ 443 case CTLBACKQ: /* does not happen at all */ 444 case CTLBACKQ | CTLQUOTE: 445 case CTLARI: /* just leave original unchanged */ 446 case CTLENDARI: 447 case CTLQUOTEMARK: 448 case '\n': 449 popstackmark(&smark); 450 return (startp); 451 case CTLNONL: 452 continue; 453 case ':': 454 if (!posix || flag & EXP_VARTILDE) 455 goto done; 456 break; 457 case CTLENDVAR: 458 case '/': 459 goto done; 460 } 461 STPUTC(c, user); 462 } 463 done: 464 STACKSTRNUL(user); 465 user = stackblock(); /* to start of collected username */ 466 467 CTRACE(DBG_EXPAND, ("exptilde, found \"~%s\"", user)); 468 if (*user == '\0') { 469 home = lookupvar("HOME"); 470 /* 471 * If HOME is unset, results are unspecified. 472 * We used to just leave the ~ unchanged, but 473 * (some) other shells do ... and this seems more useful. 474 */ 475 if (home == NULL && (pw = getpwuid(getuid())) != NULL) 476 home = pw->pw_dir; 477 } else if ((pw = getpwnam(user)) == NULL) { 478 /* 479 * If user does not exist, results are undefined. 480 * so we can abort() here if we want, but let's not! 481 */ 482 home = NULL; 483 } else 484 home = pw->pw_dir; 485 486 VTRACE(DBG_EXPAND, (" ->\"%s\"", home ? home : "<<NULL>>")); 487 popstackmark(&smark); /* now expdest is valid again */ 488 489 /* 490 * Posix XCU 2.6.1: The value of $HOME (for ~) or the initial 491 * working directory from getpwnam() for ~user 492 * Nothing there about "except if a null string". So do what it wants. 493 * In later drafts (to become Issue 8), it is even required that in 494 * this case, (where HOME='') a bare ~ expands to "" (which must not 495 * be reduced to nothing). 496 */ 497 last = '\0'; /* just in case *home == '\0' (already) */ 498 if (home == NULL) { 499 CTRACE(DBG_EXPAND, (": returning unused \"%s\"\n", startp)); 500 return startp; 501 } 502 while ((c = *home++) != '\0') { 503 /* The value must be quoted to prevent globbing */ 504 if ((quotes && NEEDESC(c)) || ISCTL(c)) 505 STPUTC(CTLESC, expdest); 506 STPUTC(c, expdest); 507 last = c; 508 } 509 /* 510 * No need for special handling of empty strings, 511 * the results from tilde expansions are not subject 512 * to field splitting, so nothing that follows (in the 513 * execution flow) will alter the data here, even an 514 * empty string. 515 */ 516 517 /* 518 * If HOME (or whatever) ended in a '/' (last == '/'), and 519 * the ~prefix was terminated by a '/', then only keep one 520 * of them - since we already took the one from HOME, just 521 * skip over the one that ended the tilde prefix. 522 * 523 * Current (Issue 8) drafts say this is permitted, and recommend 524 * it - a later version of the standard will probably require it. 525 * This is to prevent ~/foo generating //foo when HOME=/ (and 526 * other cases like it, but that's the important one). 527 */ 528 if (last == '/' && *p == '/') 529 p++; 530 531 CTRACE(DBG_EXPAND, (": added %d \"%.*s\" returning \"%s\"\n", 532 expdest - stackblock() - offs, expdest - stackblock() - offs, 533 stackblock() + offs, p)); 534 535 return (p); 536 } 537 538 539 STATIC void 540 removerecordregions(int endoff) 541 { 542 543 VTRACE(DBG_EXPAND, ("removerecordregions(%d):", endoff)); 544 if (ifslastp == NULL) { 545 VTRACE(DBG_EXPAND, (" none\n", endoff)); 546 return; 547 } 548 549 if (ifsfirst.endoff > endoff) { 550 VTRACE(DBG_EXPAND, (" first(%d)", ifsfirst.endoff)); 551 while (ifsfirst.next != NULL) { 552 struct ifsregion *ifsp; 553 INTOFF; 554 ifsp = ifsfirst.next->next; 555 ckfree(ifsfirst.next); 556 ifsfirst.next = ifsp; 557 INTON; 558 } 559 if (ifsfirst.begoff > endoff) 560 ifslastp = NULL; 561 else { 562 VTRACE(DBG_EXPAND,("->(%d,%d)",ifsfirst.begoff,endoff)); 563 ifslastp = &ifsfirst; 564 ifsfirst.endoff = endoff; 565 } 566 VTRACE(DBG_EXPAND, ("\n")); 567 return; 568 } 569 570 ifslastp = &ifsfirst; 571 while (ifslastp->next && ifslastp->next->begoff < endoff) 572 ifslastp=ifslastp->next; 573 VTRACE(DBG_EXPAND, (" found(%d,%d)",ifslastp->begoff,ifslastp->endoff)); 574 while (ifslastp->next != NULL) { 575 struct ifsregion *ifsp; 576 INTOFF; 577 ifsp = ifslastp->next->next; 578 ckfree(ifslastp->next); 579 ifslastp->next = ifsp; 580 INTON; 581 } 582 if (ifslastp->endoff > endoff) 583 ifslastp->endoff = endoff; 584 VTRACE(DBG_EXPAND, ("->(%d,%d)", ifslastp->begoff, ifslastp->endoff)); 585 } 586 587 588 /* 589 * Expand arithmetic expression. 590 * 591 * In this incarnation, we start at the beginning (yes, "Let's start at the 592 * very beginning. A very good place to start.") and collect the expression 593 * until the end - which means expanding anything contained within. 594 * 595 * Fortunately, argstr() just happens to do that for us... 596 */ 597 STATIC const char * 598 expari(const char *p) 599 { 600 char *q, *start; 601 intmax_t result; 602 int adjustment; 603 int begoff; 604 int quoted; 605 struct stackmark smark; 606 607 /* 608 * SPACE_NEEDED is enough for all possible digits (rounded up) 609 * plus possible "-", and the terminating '\0', hence, plus 2 610 * 611 * The calculation produces the number of bytes needed to 612 * represent the biggest possible value, in octal. We only 613 * generate decimal, which takes (often) less digits (never more) 614 * so this is safe, if occasionally slightly wasteful. 615 */ 616 #define SPACE_NEEDED ((int)((sizeof(intmax_t) * CHAR_BIT + 2) / 3 + 2)) 617 618 quoted = *p++ == '"'; 619 begoff = expdest - stackblock(); 620 VTRACE(DBG_EXPAND, ("expari%s: \"%s\" begoff %d\n", 621 quoted ? "(quoted)" : "", p, begoff)); 622 623 p = argstr(p, EXP_NL); /* expand $(( )) string */ 624 STPUTC('\0', expdest); 625 start = stackblock() + begoff; 626 627 removerecordregions(begoff); /* nothing there is kept */ 628 rmescapes_nl(start); /* convert CRTNONL back into \n's */ 629 630 setstackmark(&smark); 631 q = grabstackstr(expdest); /* keep the expression while eval'ing */ 632 result = arith(start, line_number); 633 popstackmark(&smark); /* return the stack to before grab */ 634 635 start = stackblock() + begoff; /* block may have moved */ 636 adjustment = expdest - start; 637 STADJUST(-adjustment, expdest); /* remove the argstr() result */ 638 639 CHECKSTRSPACE(SPACE_NEEDED, expdest); /* nb: stack block might move */ 640 fmtstr(expdest, SPACE_NEEDED, "%"PRIdMAX, result); 641 642 for (q = expdest; *q++ != '\0'; ) /* find end of what we added */ 643 ; 644 645 if (quoted == 0) /* allow weird splitting */ 646 recordregion(begoff, begoff + q - 1 - expdest, 0); 647 adjustment = q - expdest - 1; 648 STADJUST(adjustment, expdest); /* move expdest to end */ 649 VTRACE(DBG_EXPAND, ("expari: adding %d \"%s\", returning \"%.5s...\"\n", 650 adjustment, stackblock() + begoff, p)); 651 652 return p; 653 } 654 655 656 /* 657 * Expand stuff in backwards quotes (these days, any command substitution). 658 */ 659 660 STATIC void 661 expbackq(union node *cmd, int quoted, int flag) 662 { 663 struct backcmd in; 664 int i; 665 char buf[128]; 666 char *p; 667 char *dest = expdest; /* expdest may be reused by eval, use an alt */ 668 struct ifsregion saveifs, *savelastp; 669 struct nodelist *saveargbackq; 670 char lastc; 671 int startloc = dest - stackblock(); 672 const int quotes = flag & EXP_QNEEDED; 673 int nnl; 674 struct stackmark smark; 675 676 VTRACE(DBG_EXPAND, ("expbackq( ..., q=%d flag=%#x) have %d\n", 677 quoted, flag, startloc)); 678 INTOFF; 679 saveifs = ifsfirst; 680 savelastp = ifslastp; 681 saveargbackq = argbackq; 682 683 setstackmark(&smark); /* preserve the stack */ 684 p = grabstackstr(dest); /* save what we have there currently */ 685 evalbackcmd(cmd, &in); /* evaluate the $( ) tree (using stack) */ 686 popstackmark(&smark); /* and return stack to when we entered */ 687 688 ifsfirst = saveifs; 689 ifslastp = savelastp; 690 argbackq = saveargbackq; 691 692 p = in.buf; /* now extract the results */ 693 nnl = 0; /* dropping trailing \n's */ 694 for (;;) { 695 if (--in.nleft < 0) { 696 if (in.fd < 0) 697 break; 698 INTON; 699 while ((i = read(in.fd, buf, sizeof buf)) < 0 && 700 errno == EINTR) 701 continue; 702 INTOFF; 703 VTRACE(DBG_EXPAND, ("expbackq: read returns %d\n", i)); 704 if (i <= 0) 705 break; 706 p = buf; 707 in.nleft = i - 1; 708 } 709 lastc = *p++; 710 if (lastc != '\0') { 711 if (lastc == '\n') /* don't save \n yet */ 712 nnl++; /* it might be trailing */ 713 else { 714 /* 715 * We have something other than \n 716 * 717 * Before saving it, we need to insert 718 * any \n's that we have just skipped. 719 */ 720 CHECKSTRSPACE(nnl + 2, dest); 721 while (nnl > 0) { 722 nnl--; 723 USTPUTC('\n', dest); 724 } 725 if ((quotes && quoted && NEEDESC(lastc)) || 726 ISCTL(lastc)) 727 USTPUTC(CTLESC, dest); 728 USTPUTC(lastc, dest); 729 } 730 } 731 } 732 733 if (in.fd >= 0) 734 close(in.fd); 735 if (in.buf) 736 ckfree(in.buf); 737 if (in.jp) 738 back_exitstatus = waitforjob(in.jp); 739 if (quoted == 0) 740 recordregion(startloc, dest - stackblock(), 0); 741 742 CTRACE(DBG_EXPAND, ("evalbackq: [%d] size=%d: \"%.*s\"\n", 743 back_exitstatus, 744 (int)((dest - stackblock()) - startloc), 745 (int)((dest - stackblock()) - startloc), 746 stackblock() + startloc)); 747 748 expdest = dest; /* all done, expdest is all ours again */ 749 INTON; 750 } 751 752 753 STATIC int 754 subevalvar(const char *p, const char *str, int subtype, int startloc, 755 int varflags) 756 { 757 char *startp; 758 struct nodelist *saveargbackq = argbackq; 759 int amount; 760 761 VTRACE(DBG_EXPAND, ("subevalvar(%d) \"%.20s\" ${%.*s} sloc=%d vf=%x\n", 762 subtype, p, p-str, str, startloc, varflags)); 763 argstr(p, subtype == VSASSIGN ? EXP_VARTILDE : EXP_TILDE); 764 STACKSTRNUL(expdest); 765 argbackq = saveargbackq; 766 startp = stackblock() + startloc; 767 768 switch (subtype) { 769 case VSASSIGN: 770 setvar(str, startp, 0); 771 amount = startp - expdest; /* remove what argstr added */ 772 STADJUST(amount, expdest); 773 varflags &= ~VSNUL; /*XXX Huh? What's that achieve? */ 774 return 1; /* go back and eval var again */ 775 776 case VSQUESTION: 777 if (*p != CTLENDVAR) { 778 outfmt(&errout, "%s\n", startp); 779 error(NULL); 780 } 781 error("%.*s: parameter %snot set", 782 (int)(p - str - 1), 783 str, (varflags & VSNUL) ? "null or " 784 : nullstr); 785 /* NOTREACHED */ 786 787 default: 788 abort(); 789 } 790 } 791 792 STATIC int 793 subevalvar_trim(const char *p, int strloc, int subtype, int startloc, 794 int varflags, int quotes) 795 { 796 char *startp; 797 char *str; 798 char *loc = NULL; 799 char *q; 800 int c = 0; 801 struct nodelist *saveargbackq = argbackq; 802 int amount; 803 804 switch (subtype) { 805 case VSTRIMLEFT: 806 case VSTRIMLEFTMAX: 807 case VSTRIMRIGHT: 808 case VSTRIMRIGHTMAX: 809 break; 810 default: 811 abort(); 812 break; 813 } 814 815 VTRACE(DBG_EXPAND, 816 ("subevalvar_trim(\"%.9s\", STR@%d, SUBT=%d, start@%d, vf=%x, q=%x)\n", 817 p, strloc, subtype, startloc, varflags, quotes)); 818 819 argstr(p, (varflags & (VSQUOTE|VSPATQ)) == VSQUOTE ? 0 : EXP_CASE); 820 STACKSTRNUL(expdest); 821 argbackq = saveargbackq; 822 startp = stackblock() + startloc; 823 str = stackblock() + strloc; 824 825 switch (subtype) { 826 827 case VSTRIMLEFT: 828 for (loc = startp; loc < str; loc++) { 829 c = *loc; 830 *loc = '\0'; 831 if (patmatch(str, startp, quotes)) 832 goto recordleft; 833 *loc = c; 834 if (quotes && *loc == CTLESC) 835 loc++; 836 } 837 return 0; 838 839 case VSTRIMLEFTMAX: 840 for (loc = str - 1; loc >= startp;) { 841 c = *loc; 842 *loc = '\0'; 843 if (patmatch(str, startp, quotes)) 844 goto recordleft; 845 *loc = c; 846 loc--; 847 if (quotes && loc > startp && 848 *(loc - 1) == CTLESC) { 849 for (q = startp; q < loc; q++) 850 if (*q == CTLESC) 851 q++; 852 if (q > loc) 853 loc--; 854 } 855 } 856 return 0; 857 858 case VSTRIMRIGHT: 859 for (loc = str - 1; loc >= startp;) { 860 if (patmatch(str, loc, quotes)) 861 goto recordright; 862 loc--; 863 if (quotes && loc > startp && 864 *(loc - 1) == CTLESC) { 865 for (q = startp; q < loc; q++) 866 if (*q == CTLESC) 867 q++; 868 if (q > loc) 869 loc--; 870 } 871 } 872 return 0; 873 874 case VSTRIMRIGHTMAX: 875 for (loc = startp; loc < str - 1; loc++) { 876 if (patmatch(str, loc, quotes)) 877 goto recordright; 878 if (quotes && *loc == CTLESC) 879 loc++; 880 } 881 return 0; 882 883 default: 884 abort(); 885 } 886 887 recordleft: 888 *loc = c; 889 amount = ((str - 1) - (loc - startp)) - expdest; 890 STADJUST(amount, expdest); 891 while (loc != str - 1) 892 *startp++ = *loc++; 893 return 1; 894 895 recordright: 896 amount = loc - expdest; 897 STADJUST(amount, expdest); 898 STPUTC('\0', expdest); 899 STADJUST(-1, expdest); 900 return 1; 901 } 902 903 904 /* 905 * Expand a variable, and return a pointer to the next character in the 906 * input string. 907 */ 908 909 STATIC const char * 910 evalvar(const char *p, int flag) 911 { 912 int subtype; 913 int varflags; 914 const char *var; 915 char *val; 916 int patloc; 917 int c; 918 int set; 919 int special; 920 int startloc; 921 int varlen; 922 int apply_ifs; 923 const int quotes = flag & EXP_QNEEDED; 924 925 varflags = (unsigned char)*p++; 926 subtype = varflags & VSTYPE; 927 var = p; 928 special = subtype != VSUNKNOWN && !is_name(*p); 929 p = strchr(p, '=') + 1; 930 931 CTRACE(DBG_EXPAND, 932 ("evalvar \"%.*s\", flag=%#X quotes=%#X vf=%#X subtype=%X\n", 933 (int)(p - var - 1), var, flag, quotes, varflags, subtype)); 934 935 again: /* jump here after setting a variable with ${var=text} */ 936 if (special) { 937 set = varisset(var, varflags & VSNUL); 938 val = NULL; 939 if (!set && *var == '@') 940 empty_dollar_at = 1; 941 } else { 942 val = lookupvar(var); 943 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) { 944 val = NULL; 945 set = 0; 946 } else 947 set = 1; 948 } 949 950 varlen = 0; 951 startloc = expdest - stackblock(); 952 953 if (!set && uflag && *var != '@' && *var != '*') { 954 switch (subtype) { 955 case VSNORMAL: 956 case VSTRIMLEFT: 957 case VSTRIMLEFTMAX: 958 case VSTRIMRIGHT: 959 case VSTRIMRIGHTMAX: 960 case VSLENGTH: 961 error("%.*s: parameter not set", 962 (int)(p - var - 1), var); 963 /* NOTREACHED */ 964 } 965 } 966 967 if (set && subtype != VSPLUS) { 968 /* insert the value of the variable */ 969 if (special) { 970 varvalue(var, varflags&VSQUOTE, subtype, flag); 971 if (subtype == VSLENGTH) { 972 varlen = expdest - stackblock() - startloc; 973 STADJUST(-varlen, expdest); 974 } 975 } else { 976 977 if (subtype == VSLENGTH) { 978 for (; *val; val++) 979 varlen++; 980 } else if (quotes && varflags & VSQUOTE) { 981 /* 982 * If we are going to look for magic in the 983 * value (quotes is set) and the expansion 984 * occurs inside "" (VSQUOTE) then any char 985 * that has any potential special meaning 986 * needs to have that meaning suppressed, 987 * so supply a CTLESC prefix for it. 988 */ 989 for (; (c = *val) != '\0'; val++) { 990 if (NEEDESC(c)) 991 STPUTC(CTLESC, expdest); 992 STPUTC(c, expdest); 993 } 994 } else { 995 /* 996 * We are going to rmescapes() later, 997 * so make sure that any data char that 998 * might be mistaken for one of our CTLxxx 999 * magic chars is protected ... always. 1000 */ 1001 for (; (c = *val) != '\0'; val++) { 1002 if (ISCTL(c)) 1003 STPUTC(CTLESC, expdest); 1004 STPUTC(c, expdest); 1005 } 1006 } 1007 } 1008 } 1009 1010 1011 if (varflags & VSQUOTE) { 1012 if (*var == '@' && shellparam.nparam != 1) 1013 apply_ifs = 1; 1014 else { 1015 /* 1016 * Mark so that we don't apply IFS if we recurse through 1017 * here expanding $bar from "${foo-$bar}". 1018 */ 1019 flag |= EXP_IN_QUOTES; 1020 apply_ifs = 0; 1021 } 1022 } else if (flag & EXP_IN_QUOTES || 1023 !(flag & (EXP_SPLIT|EXP_IFS_SPLIT))) { 1024 apply_ifs = 0; 1025 } else 1026 apply_ifs = 1; 1027 1028 switch (subtype) { 1029 case VSLENGTH: 1030 expdest = cvtnum(varlen, expdest); 1031 break; 1032 1033 case VSNORMAL: 1034 break; 1035 1036 case VSPLUS: 1037 set = !set; 1038 /* FALLTHROUGH */ 1039 case VSMINUS: 1040 if (!set) { 1041 argstr(p, flag | (apply_ifs ? EXP_IFS_SPLIT : 0)); 1042 /* 1043 * ${x-a b c} doesn't get split, but removing the 1044 * 'apply_ifs = 0' apparently breaks ${1+"$@"}.. 1045 * ${x-'a b' c} should generate 2 args. 1046 */ 1047 if (*p != CTLENDVAR) 1048 /* We should have marked stuff already */ 1049 apply_ifs = 0; 1050 } 1051 break; 1052 1053 case VSTRIMLEFT: 1054 case VSTRIMLEFTMAX: 1055 case VSTRIMRIGHT: 1056 case VSTRIMRIGHTMAX: 1057 if (!set) { 1058 set = 1; /* allow argbackq to be advanced if needed */ 1059 break; 1060 } 1061 /* 1062 * Terminate the string and start recording the pattern 1063 * right after it 1064 */ 1065 STPUTC('\0', expdest); 1066 patloc = expdest - stackblock(); 1067 if (subevalvar_trim(p, patloc, subtype, startloc, varflags, 1068 quotes) == 0) { 1069 int amount = (expdest - stackblock() - patloc) + 1; 1070 STADJUST(-amount, expdest); 1071 } 1072 /* Remove any recorded regions beyond start of variable */ 1073 removerecordregions(startloc); 1074 apply_ifs = 1; 1075 break; 1076 1077 case VSASSIGN: 1078 case VSQUESTION: 1079 if (set) 1080 break; 1081 if (subevalvar(p, var, subtype, startloc, varflags)) { 1082 /* if subevalvar() returns, it always returns 1 */ 1083 1084 varflags &= ~VSNUL; 1085 /* 1086 * Remove any recorded regions beyond 1087 * start of variable 1088 */ 1089 removerecordregions(startloc); 1090 goto again; 1091 } 1092 apply_ifs = 0; /* never executed */ 1093 break; 1094 1095 case VSUNKNOWN: 1096 VTRACE(DBG_EXPAND, 1097 ("evalvar \"%.*s\", unknown [%p %p] \"%.3s\" (%#2x %#2x)\n", 1098 (int)(p-var-1), var, var, p, p, p[0]&0xFF, p[1]&0xFF)); 1099 1100 if ((p - var) <= 1) 1101 error("%d: unknown expansion type", line_number); 1102 else { 1103 if (*p == '#') /* only VSUNKNOWN as a ${#var:...} */ 1104 error("%d: ${#%.*s%c..}: unknown modifier", 1105 line_number, (int)(p - var - 1), 1106 var, p[1]&0xFF); 1107 1108 if (*p == CTLESC) 1109 p++; 1110 error("%d: ${%.*s%c..}: unknown modifier", 1111 line_number, (int)(p - var - 1), var, (*p & 0xFF)); 1112 } 1113 /* NOTREACHED */ 1114 1115 default: 1116 abort(); 1117 } 1118 1119 if (apply_ifs) 1120 recordregion(startloc, expdest - stackblock(), 1121 varflags & VSQUOTE); 1122 1123 if (subtype != VSNORMAL) { /* skip to end of alternative */ 1124 int nesting = 1; 1125 for (;;) { 1126 if ((c = *p++) == CTLESC) 1127 p++; 1128 else if (c == CTLNONL) 1129 ; 1130 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { 1131 if (set) 1132 argbackq = argbackq->next; 1133 } else if (c == CTLVAR) { 1134 if ((*p++ & VSTYPE) != VSNORMAL) 1135 nesting++; 1136 } else if (c == CTLENDVAR) { 1137 if (--nesting == 0) 1138 break; 1139 } 1140 } 1141 } 1142 return p; 1143 } 1144 1145 1146 1147 /* 1148 * Test whether a special parameter is set. 1149 */ 1150 1151 STATIC int 1152 varisset(const char *name, int nulok) 1153 { 1154 if (*name == '!') 1155 return backgndpid != -1; 1156 else if (*name == '@' || *name == '*') { 1157 if (*shellparam.p == NULL) 1158 return 0; 1159 1160 if (nulok) { 1161 char **av; 1162 1163 for (av = shellparam.p; *av; av++) 1164 if (**av != '\0') 1165 return 1; 1166 return 0; 1167 } 1168 } else if (is_digit(*name)) { 1169 char *ap; 1170 long num; 1171 1172 /* 1173 * handle overflow sensibly (the *ap tests should never fail) 1174 */ 1175 errno = 0; 1176 num = strtol(name, &ap, 10); 1177 if (errno != 0 || (*ap != '\0' && *ap != '=')) 1178 return 0; 1179 1180 if (num == 0) 1181 ap = arg0; 1182 else if (num > shellparam.nparam) 1183 return 0; 1184 else 1185 ap = shellparam.p[num - 1]; 1186 1187 if (nulok && (ap == NULL || *ap == '\0')) 1188 return 0; 1189 } 1190 return 1; 1191 } 1192 1193 1194 1195 /* 1196 * Add the value of a specialized variable to the stack string. 1197 */ 1198 1199 STATIC void 1200 varvalue(const char *name, int quoted, int subtype, int flag) 1201 { 1202 int num; 1203 char *p; 1204 int i; 1205 int sep; 1206 char **ap; 1207 const int start = expdest - stackblock(); 1208 1209 #define START (stackblock() + start) 1210 #define LENGTH (expdest - START) 1211 1212 VTRACE(DBG_EXPAND, ("varvalue(%c%s, sub=%d, fl=%#x)", *name, 1213 quoted ? ", quoted" : "", subtype, flag)); 1214 1215 if (subtype == VSLENGTH) /* no magic required ... */ 1216 flag &= ~(EXP_FULL | EXP_QNEEDED); 1217 1218 #define STRTODEST(p) \ 1219 do {\ 1220 if ((flag & EXP_QNEEDED) && quoted) { \ 1221 while (*p) { \ 1222 if (NEEDESC(*p)) \ 1223 STPUTC(CTLESC, expdest); \ 1224 STPUTC(*p++, expdest); \ 1225 } \ 1226 } else \ 1227 while (*p) { \ 1228 if ((flag & EXP_QNEEDED) && ISCTL(*p)) \ 1229 STPUTC(CTLESC, expdest); \ 1230 STPUTC(*p++, expdest); \ 1231 } \ 1232 } while (0) 1233 1234 1235 switch (*name) { 1236 case '$': 1237 num = rootpid; 1238 break; 1239 case '?': 1240 num = exitstatus; 1241 break; 1242 case '#': 1243 num = shellparam.nparam; 1244 break; 1245 case '!': 1246 num = backgndpid; 1247 break; 1248 case '-': 1249 for (i = 0; i < option_flags; i++) { 1250 if (optlist[optorder[i]].val) 1251 STPUTC(optlist[optorder[i]].letter, expdest); 1252 } 1253 VTRACE(DBG_EXPAND, (": %.*s\n", LENGTH, START)); 1254 return; 1255 1256 case '@': 1257 if (flag & EXP_SPLIT && quoted) { 1258 VTRACE(DBG_EXPAND, (": $@ split (%d)\n", 1259 shellparam.nparam)); 1260 if (shellparam.nparam == 0) 1261 empty_dollar_at = 1; 1262 1263 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { 1264 if (*p == '\0') { 1265 /* retain an explicit null string */ 1266 STPUTC(CTLQUOTEMARK, expdest); 1267 STPUTC(CTLQUOTEEND, expdest); 1268 } else 1269 STRTODEST(p); 1270 if (*ap) 1271 /* A NUL separates args inside "" */ 1272 STPUTC('\0', expdest); 1273 } 1274 VTRACE(DBG_EXPAND, 1275 (":= \"%s\"\n", showstr(START, LENGTH))); 1276 return; 1277 } 1278 /* fall through */ 1279 case '*': 1280 if (!quoted && (flag & EXP_SPLIT)) { 1281 int first = 1; int lastnull = 0; 1282 1283 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { 1284 if (*p == '\0') { 1285 lastnull = 1; 1286 if (first && flag & EXP_NEEDFIRST) 1287 STPUTC('\0', expdest); 1288 first = 0; 1289 continue; 1290 } 1291 first = lastnull = 0; 1292 STRTODEST(p); 1293 STPUTC('\0', expdest); 1294 } 1295 if (expdest > START && 1296 (!lastnull || !(flag & EXP_NEEDLAST))) 1297 STUNPUTC(expdest); /* delete the final \0 */ 1298 VTRACE(DBG_EXPAND, 1299 (":: \"%s\"\n", showstr(START, LENGTH))); 1300 return; 1301 } 1302 1303 /* the "$*" case, and others which act the same */ 1304 sep = ifsval()[0]; 1305 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { 1306 STRTODEST(p); 1307 if (!*ap) 1308 break; 1309 if (sep) { 1310 if (quoted && (flag & EXP_QNEEDED) && 1311 NEEDESC(sep)) 1312 STPUTC(CTLESC, expdest); 1313 STPUTC(sep, expdest); 1314 } 1315 } 1316 VTRACE(DBG_EXPAND, (": \"%s\"\n", showstr(START, LENGTH))); 1317 return; 1318 1319 default: 1320 if (is_digit(*name)) { 1321 long lnum; 1322 1323 errno = 0; 1324 lnum = strtol(name, &p, 10); 1325 if (errno != 0 || (*p != '\0' && *p != '=')) 1326 return; 1327 1328 if (lnum == 0) 1329 p = arg0; 1330 else if (lnum > 0 && lnum <= shellparam.nparam) 1331 p = shellparam.p[lnum - 1]; 1332 else 1333 return; 1334 STRTODEST(p); 1335 } 1336 VTRACE(DBG_EXPAND, (": \"%s\"\n", showstr(START, LENGTH))); 1337 return; 1338 } 1339 /* 1340 * only the specials with an int value arrive here 1341 */ 1342 VTRACE(DBG_EXPAND, ("(%d)", num)); 1343 expdest = cvtnum(num, expdest); 1344 VTRACE(DBG_EXPAND, (": %.*s\n", LENGTH, START)); 1345 } 1346 1347 1348 1349 /* 1350 * Record the fact that we have to scan this region of the 1351 * string for IFS characters. 1352 */ 1353 1354 STATIC void 1355 recordregion(int start, int end, int inquotes) 1356 { 1357 struct ifsregion *ifsp; 1358 1359 inquotes = !!inquotes; 1360 1361 VTRACE(DBG_EXPAND, ("recordregion(%d,%d,%d)\n", start, end, inquotes)); 1362 if (ifslastp == NULL) { 1363 ifsp = &ifsfirst; 1364 } else { 1365 if (ifslastp->endoff == start 1366 && ifslastp->inquotes == inquotes) { 1367 /* extend previous area */ 1368 ifslastp->endoff = end; 1369 return; 1370 } 1371 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion)); 1372 ifslastp->next = ifsp; 1373 } 1374 ifslastp = ifsp; 1375 ifslastp->next = NULL; 1376 ifslastp->begoff = start; 1377 ifslastp->endoff = end; 1378 ifslastp->inquotes = inquotes; 1379 } 1380 1381 1382 1383 /* 1384 * Break the argument string into pieces based upon IFS and add the 1385 * strings to the argument list. The regions of the string to be 1386 * searched for IFS characters have been stored by recordregion. 1387 */ 1388 STATIC void 1389 ifsbreakup(char *string, size_t len __debugused, struct arglist *arglist) 1390 { 1391 struct ifsregion *ifsp; 1392 struct strlist *sp; 1393 char *start; 1394 char *p; 1395 char *q; 1396 const char *ifs; 1397 const char *ifsspc; 1398 int had_param_ch = 0; 1399 1400 start = string; 1401 1402 VTRACE(DBG_EXPAND, ("ifsbreakup(\"%s\")", showstr(string, (int)len))); 1403 if (ifslastp == NULL) { 1404 /* Return entire argument, IFS doesn't apply to any of it */ 1405 VTRACE(DBG_EXPAND, ("no regions\n", string)); 1406 sp = stalloc(sizeof(*sp)); 1407 sp->text = start; 1408 *arglist->lastp = sp; 1409 arglist->lastp = &sp->next; 1410 return; 1411 } 1412 1413 ifs = ifsval(); 1414 1415 for (ifsp = &ifsfirst; ifsp != NULL; ifsp = ifsp->next) { 1416 p = string + ifsp->begoff; 1417 VTRACE(DBG_EXPAND, ("\n%d..%d%s !%s!(%d)", 1418 ifsp->begoff, ifsp->endoff, 1419 ifsp->inquotes ? "Q" : "", 1420 showstr(p, ifsp->endoff - ifsp->begoff), 1421 ifsp->endoff - ifsp->begoff)); 1422 while (p < string + ifsp->endoff) { 1423 had_param_ch = 1; 1424 q = p; 1425 if (IS_BORING(*p)) { 1426 p++; 1427 continue; 1428 } 1429 if (*p == CTLESC) 1430 p++; 1431 if (*p == '\0') { 1432 ifsspc = NULL; 1433 VTRACE(DBG_EXPAND, 1434 (" \\0 Nxt:\"%s\" ", 1435 showstr(p+1,ifsp->endoff-(p-string-1)))); 1436 } else if (ifsp->inquotes) { 1437 p++; /* A quoted char to keep */ 1438 continue; 1439 } else { 1440 if (!strchr(ifs, *p)) { 1441 p++; /* Not an IFS char, keep it */ 1442 continue; 1443 } 1444 had_param_ch = 0; 1445 ifsspc = strchr(" \t\n", *p); 1446 1447 /* Ignore IFS whitespace at start */ 1448 if (q == start && ifsspc != NULL) { 1449 p++; 1450 start = p; 1451 continue; 1452 } 1453 } 1454 /* Save this argument... */ 1455 *q = '\0'; 1456 VTRACE(DBG_EXPAND, 1457 ("<%s>", showstr(start,(int)(q-start)))); 1458 sp = stalloc(sizeof(*sp)); 1459 sp->text = start; 1460 *arglist->lastp = sp; 1461 arglist->lastp = &sp->next; 1462 p++; 1463 if (*p == '\0') { 1464 if (!ifsp->inquotes && 1465 p - string + 1 < ifsp->endoff) 1466 /* skip embedded \0 */ 1467 p++; 1468 } else if (ifsspc != NULL) { 1469 /* Ignore further trailing IFS whitespace */ 1470 for (; p < string + ifsp->endoff; p++) { 1471 q = p; 1472 if (*p == CTLNONL) 1473 continue; 1474 if (*p == CTLESC) 1475 p++; 1476 if (strchr(ifs, *p) == NULL) { 1477 p = q; 1478 break; 1479 } 1480 if (*p != '\0' && 1481 strchr(" \t\n", *p) == NULL) { 1482 p++; 1483 break; 1484 } 1485 } 1486 } 1487 start = p; 1488 } 1489 } 1490 1491 /* 1492 * Save anything left as an argument (as long as not empty). 1493 */ 1494 if (had_param_ch || *start != 0) { 1495 VTRACE(DBG_EXPAND, (" T(%zu)<%s>", strlen(start), 1496 showstr(start, strlen(start)))); 1497 sp = stalloc(sizeof(*sp)); 1498 sp->text = start; 1499 *arglist->lastp = sp; 1500 arglist->lastp = &sp->next; 1501 } 1502 VTRACE(DBG_EXPAND, ("\n")); 1503 } 1504 1505 STATIC void 1506 ifsfree(void) 1507 { 1508 while (ifsfirst.next != NULL) { 1509 struct ifsregion *ifsp; 1510 INTOFF; 1511 ifsp = ifsfirst.next->next; 1512 ckfree(ifsfirst.next); 1513 ifsfirst.next = ifsp; 1514 INTON; 1515 } 1516 ifslastp = NULL; 1517 ifsfirst.next = NULL; 1518 } 1519 1520 #ifdef DEBUG 1521 /* 1522 * DEBUG mode only utility routines so tracing can show 1523 * exactly what is in strings that are being processed 1524 * (including embedded \0's sometimes) 1525 */ 1526 static char * 1527 showchar(char *o, char c, int *l) 1528 { 1529 if (c >= ' ' && c <= '~') { 1530 if (c == '\\') { 1531 *o++ = c; 1532 (*l)--; 1533 } 1534 *o++ = c; 1535 } else { 1536 if (c == 0) { 1537 *o++ = '\\'; 1538 *o++ = '0'; 1539 *l -= 1; 1540 } else { 1541 sprintf(o, "\\x%2.2X", (c & 0xFF)); 1542 o += 4; 1543 *l -= 3; 1544 } 1545 } 1546 return o; 1547 } 1548 1549 static char * 1550 showstr(const char *str, int len) 1551 { 1552 static char strbuf[128]; 1553 int lhs, rhs; 1554 const char *p; 1555 char *q; 1556 1557 if (len < 0) 1558 len = (int)strlen(str); 1559 if (len >= (int)sizeof strbuf - 4) { 1560 lhs = ((int)sizeof strbuf - 8) / 2; 1561 rhs = (int)sizeof strbuf - lhs - 8; 1562 } else { 1563 lhs = len; 1564 rhs = 0; 1565 } 1566 1567 for (p = str, q = strbuf; --lhs >= 0; ) { 1568 q = showchar(q, *p++, &rhs); 1569 if (q >= &strbuf[sizeof strbuf - 4]) { 1570 while (q < &strbuf[sizeof strbuf - 1]) 1571 *q++ = '.'; 1572 *q = '\0'; 1573 return strbuf; 1574 } 1575 } 1576 if (p < str + len) { 1577 if (rhs <= 0 || q >= &strbuf[sizeof strbuf - 8]) { 1578 while (q < &strbuf[sizeof strbuf - 1]) 1579 *q++ = '.'; 1580 *q = '\0'; 1581 return strbuf; 1582 } 1583 1584 *q++ = '.'; *q++ = '|'; *q++='.'; 1585 1586 if (p < str + len - rhs) 1587 p = str + len - rhs; 1588 else 1589 rhs = str + len - p; 1590 1591 while (--rhs >= 0) { 1592 q = showchar(q, *p++, &lhs); 1593 if (q >= &strbuf[sizeof strbuf - 5]) { 1594 while (q < &strbuf[sizeof strbuf - 1]) 1595 *q++ = '.'; 1596 *q = '\0'; 1597 return strbuf; 1598 } 1599 } 1600 } 1601 *q = '\0'; 1602 return strbuf; 1603 1604 } 1605 #endif /* DEBUG */ 1606 1607 1608 1609 /* 1610 * Expand shell metacharacters. At this point, the only control characters 1611 * should be escapes. The results are stored in the list exparg. 1612 */ 1613 1614 char *expdir; 1615 1616 STATIC void 1617 expandmeta(struct strlist *str, int flag) 1618 { 1619 char *p; 1620 struct strlist **savelastp; 1621 struct strlist *sp; 1622 char c; 1623 /* TODO - EXP_REDIR */ 1624 1625 while (str) { 1626 p = str->text; 1627 for (;;) { /* fast check for meta chars */ 1628 if ((c = *p++) == '\0') 1629 goto nometa; 1630 if (c == '*' || c == '?' || c == '[' /* || c == '!' */) 1631 break; 1632 } 1633 savelastp = exparg.lastp; 1634 INTOFF; 1635 if (expdir == NULL) { 1636 int i = strlen(str->text); 1637 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ 1638 } 1639 1640 expmeta(expdir, str->text); 1641 ckfree(expdir); 1642 expdir = NULL; 1643 INTON; 1644 if (exparg.lastp == savelastp) { 1645 /* 1646 * no matches 1647 */ 1648 nometa: 1649 *exparg.lastp = str; 1650 rmescapes(str->text); 1651 exparg.lastp = &str->next; 1652 } else { 1653 *exparg.lastp = NULL; 1654 *savelastp = sp = expsort(*savelastp); 1655 while (sp->next != NULL) 1656 sp = sp->next; 1657 exparg.lastp = &sp->next; 1658 } 1659 str = str->next; 1660 } 1661 } 1662 1663 STATIC void 1664 add_args(struct strlist *str) 1665 { 1666 while (str) { 1667 *exparg.lastp = str; 1668 rmescapes(str->text); 1669 exparg.lastp = &str->next; 1670 str = str->next; 1671 } 1672 } 1673 1674 1675 /* 1676 * Do metacharacter (i.e. *, ?, [...]) expansion. 1677 */ 1678 1679 STATIC void 1680 expmeta(char *enddir, char *name) 1681 { 1682 char *p; 1683 const char *cp; 1684 char *q; 1685 char *start; 1686 char *endname; 1687 int metaflag; 1688 struct stat statb; 1689 DIR *dirp; 1690 struct dirent *dp; 1691 int atend; 1692 int matchdot; 1693 1694 CTRACE(DBG_EXPAND|DBG_MATCH, ("expmeta(\"%s\")\n", name)); 1695 metaflag = 0; 1696 start = name; 1697 for (p = name ; ; p++) { 1698 if (*p == '*' || *p == '?') 1699 metaflag = 1; 1700 else if (*p == '[') { 1701 q = p + 1; 1702 if (*q == '!' || *q == '^') 1703 q++; 1704 for (;;) { 1705 while (IS_BORING(*q)) 1706 q++; 1707 if (*q == ']') { 1708 q++; 1709 metaflag = 1; 1710 break; 1711 } 1712 if (*q == '[' && q[1] == ':') { 1713 /* 1714 * character class, look for :] ending 1715 * also stop on ']' (end bracket expr) 1716 * or '\0' or '/' (end pattern) 1717 */ 1718 while (*++q != '\0' && *q != ']' && 1719 *q != '/') { 1720 if (*q == CTLESC) { 1721 if (*++q == '\0') 1722 break; 1723 if (*q == '/') 1724 break; 1725 } else if (*q == ':' && 1726 q[1] == ']') 1727 break; 1728 } 1729 if (*q == ':') { 1730 /* 1731 * stopped at ':]' 1732 * still in [...] 1733 * skip ":]" and continue; 1734 */ 1735 q += 2; 1736 continue; 1737 } 1738 1739 /* done at end of pattern, not [...] */ 1740 if (*q == '\0' || *q == '/') 1741 break; 1742 1743 /* found the ']', we have a [...] */ 1744 metaflag = 1; 1745 q++; /* skip ']' */ 1746 break; 1747 } 1748 if (*q == CTLESC) 1749 q++; 1750 /* end of pattern cannot be escaped */ 1751 if (*q == '/' || *q == '\0') 1752 break; 1753 q++; 1754 } 1755 } else if (*p == '\0') 1756 break; 1757 else if (IS_BORING(*p)) 1758 continue; 1759 else if (*p == CTLESC) 1760 p++; 1761 if (*p == '/') { 1762 if (metaflag) 1763 break; 1764 start = p + 1; 1765 } 1766 } 1767 if (metaflag == 0) { /* we've reached the end of the file name */ 1768 if (enddir != expdir) 1769 metaflag++; 1770 for (p = name ; ; p++) { 1771 if (IS_BORING(*p)) 1772 continue; 1773 if (*p == CTLESC) 1774 p++; 1775 *enddir++ = *p; 1776 if (*p == '\0') 1777 break; 1778 } 1779 if (metaflag == 0 || lstat(expdir, &statb) >= 0) 1780 addfname(expdir); 1781 return; 1782 } 1783 endname = p; 1784 if (start != name) { 1785 p = name; 1786 while (p < start) { 1787 while (IS_BORING(*p)) 1788 p++; 1789 if (*p == CTLESC) 1790 p++; 1791 *enddir++ = *p++; 1792 } 1793 } 1794 if (enddir == expdir) { 1795 cp = "."; 1796 } else if (enddir == expdir + 1 && *expdir == '/') { 1797 cp = "/"; 1798 } else { 1799 cp = expdir; 1800 enddir[-1] = '\0'; 1801 } 1802 if ((dirp = opendir(cp)) == NULL) 1803 return; 1804 if (enddir != expdir) 1805 enddir[-1] = '/'; 1806 if (*endname == 0) { 1807 atend = 1; 1808 } else { 1809 atend = 0; 1810 *endname++ = '\0'; 1811 } 1812 matchdot = 0; 1813 p = start; 1814 while (IS_BORING(*p)) 1815 p++; 1816 if (*p == CTLESC) 1817 p++; 1818 if (*p == '.') 1819 matchdot++; 1820 while (!int_pending() && (dp = readdir(dirp)) != NULL) { 1821 #ifndef SMALL 1822 if (dotglob) { 1823 /* 1824 * When dotglob is enabled, potential matches 1825 * starting with '.' are treated as any others, 1826 * except for "." and ".." which require an 1827 * explicit leading '.' (matchdot) in the pattern. 1828 */ 1829 if (!matchdot && dp->d_name[0] == '.' && 1830 (dp->d_name[1] == '\0' || 1831 (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) 1832 continue; 1833 } else 1834 #endif 1835 { 1836 /* 1837 * When dotglob is not enabled (always not if SMALL) 1838 * then files starting with a '.' only match when the 1839 * pattern starts with an explicit '.' (matchdot) 1840 */ 1841 if (dp->d_name[0] == '.' && !matchdot) 1842 continue; 1843 } 1844 1845 if (patmatch(start, dp->d_name, 0)) { 1846 if (atend) { 1847 scopy(dp->d_name, enddir); 1848 addfname(expdir); 1849 } else { 1850 for (p = enddir, cp = dp->d_name; 1851 (*p++ = *cp++) != '\0';) 1852 continue; 1853 p[-1] = '/'; 1854 expmeta(p, endname); 1855 } 1856 } 1857 } 1858 closedir(dirp); 1859 if (!atend) 1860 endname[-1] = '/'; 1861 } 1862 1863 1864 /* 1865 * Add a file name to the list. 1866 */ 1867 1868 STATIC void 1869 addfname(char *name) 1870 { 1871 char *p; 1872 struct strlist *sp; 1873 1874 p = stalloc(strlen(name) + 1); 1875 scopy(name, p); 1876 sp = stalloc(sizeof(*sp)); 1877 sp->text = p; 1878 *exparg.lastp = sp; 1879 exparg.lastp = &sp->next; 1880 } 1881 1882 1883 /* 1884 * Sort the results of file name expansion. It calculates the number of 1885 * strings to sort and then calls msort (short for merge sort) to do the 1886 * work. 1887 */ 1888 1889 STATIC struct strlist * 1890 expsort(struct strlist *str) 1891 { 1892 int len; 1893 struct strlist *sp; 1894 1895 len = 0; 1896 for (sp = str ; sp ; sp = sp->next) 1897 len++; 1898 return msort(str, len); 1899 } 1900 1901 1902 STATIC struct strlist * 1903 msort(struct strlist *list, int len) 1904 { 1905 struct strlist *p, *q = NULL; 1906 struct strlist **lpp; 1907 int half; 1908 int n; 1909 1910 if (len <= 1) 1911 return list; 1912 half = len >> 1; 1913 p = list; 1914 for (n = half ; --n >= 0 ; ) { 1915 q = p; 1916 p = p->next; 1917 } 1918 q->next = NULL; /* terminate first half of list */ 1919 q = msort(list, half); /* sort first half of list */ 1920 p = msort(p, len - half); /* sort second half */ 1921 lpp = &list; 1922 for (;;) { 1923 if (strcmp(p->text, q->text) < 0) { 1924 *lpp = p; 1925 lpp = &p->next; 1926 if ((p = *lpp) == NULL) { 1927 *lpp = q; 1928 break; 1929 } 1930 } else { 1931 *lpp = q; 1932 lpp = &q->next; 1933 if ((q = *lpp) == NULL) { 1934 *lpp = p; 1935 break; 1936 } 1937 } 1938 } 1939 return list; 1940 } 1941 1942 1943 /* 1944 * See if a character matches a character class, starting at the first colon 1945 * of "[:class:]". 1946 * If a valid character class is recognized, a pointer to the next character 1947 * after the final closing bracket is stored into *end, otherwise a null 1948 * pointer is stored into *end. 1949 */ 1950 static int 1951 match_charclass(const char *p, wchar_t chr, const char **end) 1952 { 1953 char name[20]; 1954 const char *nameend; 1955 wctype_t cclass; 1956 char *q; 1957 1958 *end = NULL; 1959 p++; 1960 q = &name[0]; 1961 nameend = strstr(p, ":]"); 1962 if (nameend == NULL || nameend == p) /* not a valid class */ 1963 return 0; 1964 1965 if (*p == CTLESC) { 1966 if (*++p == CTLESC) 1967 return 0; 1968 if (p == nameend) 1969 return 0; 1970 } 1971 if (!is_alpha(*p)) 1972 return 0; 1973 while (p < nameend) { 1974 if (*p == CTLESC) { 1975 p++; 1976 if (p == nameend) 1977 return 0; 1978 } 1979 if (!is_in_name(*p)) /* '_' is a local extension */ 1980 return 0; 1981 if (q < &name[sizeof name]) 1982 *q++ = *p++; 1983 else 1984 p++; 1985 } 1986 1987 *end = nameend + 2; /* committed to it being a char class */ 1988 1989 if (q < &name[sizeof name]) /* a usable name found */ 1990 *q++ = '\0'; 1991 else /* too long, valid, but no match */ 1992 return 0; 1993 1994 cclass = wctype(name); 1995 /* An unknown class matches nothing but is valid nevertheless. */ 1996 if (cclass == 0) 1997 return 0; 1998 return iswctype(chr, cclass); 1999 } 2000 2001 2002 /* 2003 * Returns true if the pattern matches the string. 2004 */ 2005 2006 STATIC int 2007 patmatch(const char *pattern, const char *string, int squoted) 2008 { 2009 const char *p, *q, *end; 2010 const char *bt_p, *bt_q; 2011 char c; 2012 wchar_t wc, wc2; 2013 2014 VTRACE(DBG_MATCH, ("patmatch(P=\"%s\", W=\"%s\"%s): ", 2015 pattern, string, squoted ? ", SQ" : "")); 2016 p = pattern; 2017 q = string; 2018 bt_p = NULL; 2019 bt_q = NULL; 2020 for (;;) { 2021 switch (c = *p++) { 2022 case '\0': 2023 if (squoted && *q == CTLESC) { 2024 if (q[1] == '\0') 2025 q++; 2026 } 2027 if (*q != '\0') 2028 goto backtrack; 2029 VTRACE(DBG_MATCH, ("match\n")); 2030 return 1; 2031 case CTLESC: 2032 if (squoted && *q == CTLESC) 2033 q++; 2034 if (*p == '\0' && *q == '\0') { 2035 VTRACE(DBG_MATCH, ("match-\\\n")); 2036 return 1; 2037 } 2038 if (*q++ != *p++) 2039 goto backtrack; 2040 break; 2041 case '\\': 2042 if (squoted && *q == CTLESC) 2043 q++; 2044 if (*q++ != *p++) 2045 goto backtrack; 2046 break; 2047 case CTLQUOTEMARK: 2048 case CTLQUOTEEND: 2049 case CTLNONL: 2050 continue; 2051 case '?': 2052 if (squoted && *q == CTLESC) 2053 q++; 2054 if (*q++ == '\0') { 2055 VTRACE(DBG_MATCH, ("?fail\n")); 2056 return 0; 2057 } 2058 break; 2059 case '*': 2060 c = *p; 2061 while (c == CTLQUOTEMARK || c == '*') 2062 c = *++p; 2063 if (c != CTLESC && !IS_BORING(c) && 2064 c != '?' && c != '*' && c != '[') { 2065 while (*q != c) { 2066 if (squoted && *q == CTLESC && 2067 q[1] == c) 2068 break; 2069 if (*q == '\0') { 2070 VTRACE(DBG_MATCH, ("*fail\n")); 2071 return 0; 2072 } 2073 if (squoted && *q == CTLESC) 2074 q++; 2075 q++; 2076 } 2077 } 2078 if (c == CTLESC && p[1] == '\0') { 2079 VTRACE(DBG_MATCH, ("match+\\\n")); 2080 return 1; 2081 } 2082 /* 2083 * First try the shortest match for the '*' that 2084 * could work. We can forget any earlier '*' since 2085 * there is no way having it match more characters 2086 * can help us, given that we are already here. 2087 */ 2088 bt_p = p; 2089 bt_q = q; 2090 break; 2091 case '[': { 2092 const char *savep, *saveq, *endp; 2093 int invert, found; 2094 unsigned char chr; 2095 2096 /* 2097 * First quick check to see if there is a 2098 * possible matching ']' - if not, then this 2099 * is not a char class, and the '[' is just 2100 * a literal '['. 2101 * 2102 * This check will not detect all non classes, but 2103 * that's OK - It just means that we execute the 2104 * harder code sometimes when it it cannot succeed. 2105 */ 2106 endp = p; 2107 if (*endp == '!' || *endp == '^') 2108 endp++; 2109 for (;;) { 2110 while (IS_BORING(*endp)) 2111 endp++; 2112 if (*endp == '\0') 2113 goto dft; /* no matching ] */ 2114 if (*endp++ == ']') 2115 break; 2116 } 2117 /* end shortcut */ 2118 2119 savep = p, saveq = q; 2120 invert = 0; 2121 if (*p == '!' || *p == '^') { 2122 invert++; 2123 p++; 2124 } 2125 found = 0; 2126 if (*q == '\0') { 2127 VTRACE(DBG_MATCH, ("[]fail\n")); 2128 return 0; 2129 } 2130 if (squoted && *q == CTLESC) 2131 q++; 2132 chr = (unsigned char)*q++; 2133 c = *p++; 2134 do { 2135 if (IS_BORING(c)) 2136 continue; 2137 if (c == '\0') { 2138 p = savep, q = saveq; 2139 c = '['; 2140 goto dft; 2141 } 2142 if (c == '[' && *p == ':') { 2143 found |= match_charclass(p, chr, &end); 2144 if (end != NULL) { 2145 p = end; 2146 continue; 2147 } 2148 } 2149 if (c == CTLESC || c == '\\') 2150 c = *p++; 2151 wc = (unsigned char)c; 2152 if (*p == '-' && p[1] != ']') { 2153 p++; 2154 if (*p == CTLESC || *p == '\\') 2155 p++; 2156 wc2 = (unsigned char)*p++; 2157 if ( collate_range_cmp(chr, wc) >= 0 2158 && collate_range_cmp(chr, wc2) <= 0 2159 ) 2160 found = 1; 2161 } else { 2162 if (chr == wc) 2163 found = 1; 2164 } 2165 } while ((c = *p++) != ']'); 2166 if (found == invert) 2167 goto backtrack; 2168 break; 2169 } 2170 dft: default: 2171 if (squoted && *q == CTLESC) 2172 q++; 2173 if (*q++ == c) 2174 break; 2175 backtrack: 2176 /* 2177 * If we have a mismatch (other than hitting the end 2178 * of the string), go back to the last '*' seen and 2179 * have it match one additional character. 2180 */ 2181 if (bt_p == NULL) { 2182 VTRACE(DBG_MATCH, ("BTP fail\n")); 2183 return 0; 2184 } 2185 if (*bt_q == '\0') { 2186 VTRACE(DBG_MATCH, ("BTQ fail\n")); 2187 return 0; 2188 } 2189 bt_q++; 2190 p = bt_p; 2191 q = bt_q; 2192 break; 2193 } 2194 } 2195 } 2196 2197 2198 2199 /* 2200 * Remove any CTLESC or CTLNONL characters from a string. 2201 * 2202 * String is modified in place, and we return the length of the result 2203 */ 2204 2205 int 2206 rmescapes(char *str) 2207 { 2208 char *p, *q; 2209 2210 p = str; 2211 while (!ISCTL(*p)) { 2212 if (*p++ == '\0') 2213 return ((int)(p - str) - 1); 2214 } 2215 q = p; 2216 while (*p) { 2217 if (IS_BORING(*p)) { 2218 p++; 2219 continue; 2220 } 2221 if (*p == CTLCNL) { 2222 p++; 2223 *q++ = '\n'; 2224 continue; 2225 } 2226 if (*p == CTLESC) 2227 p++; 2228 #ifdef DEBUG 2229 else if (ISCTL(*p)) 2230 abort(); 2231 #endif 2232 *q++ = *p++; 2233 } 2234 *q = '\0'; 2235 2236 return ((int)(q - str)); 2237 } 2238 2239 /* 2240 * and a special version for dealing with expressions to be parsed 2241 * by the arithmetic evaluator. That needs to be able to count \n's 2242 * even ones that were \newline elided \n's, so we have to put the 2243 * latter back into the string - just being careful to put them only 2244 * at a place where white space can reasonably occur in the string 2245 * -- then the \n we insert will just be white space, and ignored 2246 * for all purposes except line counting. 2247 */ 2248 2249 void 2250 rmescapes_nl(char *str) 2251 { 2252 char *p, *q; 2253 int nls = 0, holdnl = 0, holdlast; 2254 2255 p = str; 2256 while (!ISCTL(*p)) { 2257 if (*p++ == '\0') 2258 return; 2259 } 2260 if (p > str) /* must reprocess char before stopper (if any) */ 2261 --p; /* so we do not place a \n badly */ 2262 q = p; 2263 while (*p) { 2264 if (*p == CTLQUOTEMARK || *p == CTLQUOTEEND) { 2265 p++; 2266 continue; 2267 } 2268 if (*p == CTLNONL) { 2269 p++; 2270 nls++; 2271 continue; 2272 } 2273 if (*p == CTLCNL) { 2274 p++; 2275 *q++ = '\n'; 2276 continue; 2277 } 2278 if (*p == CTLESC) 2279 p++; 2280 #ifdef DEBUG 2281 else if (ISCTL(*p)) 2282 abort(); 2283 #endif 2284 2285 holdlast = holdnl; 2286 holdnl = is_in_name(*p); /* letters, digits, _ */ 2287 if (q == str || is_space(q[-1]) || (*p != '=' && q[-1] != *p)) { 2288 if (nls > 0 && holdnl != holdlast) { 2289 while (nls > 0) 2290 *q++ = '\n', nls--; 2291 } 2292 } 2293 *q++ = *p++; 2294 } 2295 while (--nls >= 0) 2296 *q++ = '\n'; 2297 *q = '\0'; 2298 } 2299 2300 2301 2302 /* 2303 * See if a pattern matches in a case statement. 2304 */ 2305 2306 int 2307 casematch(union node *pattern, char *val) 2308 { 2309 struct stackmark smark; 2310 int result; 2311 char *p; 2312 2313 CTRACE(DBG_MATCH, ("casematch(P=\"%s\", W=\"%s\")\n", 2314 pattern->narg.text, val)); 2315 setstackmark(&smark); 2316 argbackq = pattern->narg.backquote; 2317 STARTSTACKSTR(expdest); 2318 ifslastp = NULL; 2319 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); 2320 STPUTC('\0', expdest); 2321 p = grabstackstr(expdest); 2322 result = patmatch(p, val, 0); 2323 popstackmark(&smark); 2324 return result; 2325 } 2326 2327 /* 2328 * Our own itoa(). Assumes result buffer is on the stack 2329 */ 2330 2331 STATIC char * 2332 cvtnum(int num, char *buf) 2333 { 2334 char temp[32]; 2335 int neg = num < 0; 2336 char *p = temp + sizeof temp - 1; 2337 2338 if (neg) 2339 num = -num; 2340 2341 *p = '\0'; 2342 do { 2343 *--p = num % 10 + '0'; 2344 } while ((num /= 10) != 0 && p > temp + 1); 2345 2346 if (neg) 2347 *--p = '-'; 2348 2349 while (*p) 2350 STPUTC(*p++, buf); 2351 return buf; 2352 } 2353 2354 /* 2355 * Do most of the work for wordexp(3). 2356 */ 2357 2358 int 2359 wordexpcmd(int argc, char **argv) 2360 { 2361 size_t len; 2362 int i; 2363 2364 out1fmt("%d", argc - 1); 2365 out1c('\0'); 2366 for (i = 1, len = 0; i < argc; i++) 2367 len += strlen(argv[i]); 2368 out1fmt("%zu", len); 2369 out1c('\0'); 2370 for (i = 1; i < argc; i++) { 2371 out1str(argv[i]); 2372 out1c('\0'); 2373 } 2374 return (0); 2375 } 2376