expand.c revision 36150
11558Srgrimes/*- 21558Srgrimes * Copyright (c) 1991, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * This code is derived from software contributed to Berkeley by 61558Srgrimes * Kenneth Almquist. 71558Srgrimes * 81558Srgrimes * Redistribution and use in source and binary forms, with or without 91558Srgrimes * modification, are permitted provided that the following conditions 101558Srgrimes * are met: 111558Srgrimes * 1. Redistributions of source code must retain the above copyright 121558Srgrimes * notice, this list of conditions and the following disclaimer. 131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141558Srgrimes * notice, this list of conditions and the following disclaimer in the 151558Srgrimes * documentation and/or other materials provided with the distribution. 161558Srgrimes * 3. All advertising materials mentioning features or use of this software 171558Srgrimes * must display the following acknowledgement: 181558Srgrimes * This product includes software developed by the University of 191558Srgrimes * California, Berkeley and its contributors. 201558Srgrimes * 4. Neither the name of the University nor the names of its contributors 211558Srgrimes * may be used to endorse or promote products derived from this software 221558Srgrimes * without specific prior written permission. 231558Srgrimes * 241558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34114589Sobrien * SUCH DAMAGE. 351558Srgrimes */ 3623675Speter 37114589Sobrien#ifndef lint 3841477Sjulian#if 0 39114589Sobrienstatic char sccsid[] = "@(#)expand.c 8.5 (Berkeley) 5/15/95"; 40114589Sobrien#endif 411558Srgrimesstatic const char rcsid[] = 421558Srgrimes "$Id$"; 4323675Speter#endif /* not lint */ 441558Srgrimes 4541474Sjulian#include <sys/types.h> 4641474Sjulian#include <sys/time.h> 4723675Speter#include <sys/stat.h> 4841474Sjulian#include <errno.h> 4941474Sjulian#include <dirent.h> 501558Srgrimes#include <unistd.h> 511558Srgrimes#include <pwd.h> 527585Sbde#include <stdlib.h> 5392839Simp#include <limits.h> 541558Srgrimes 5541474Sjulian/* 5641474Sjulian * Routines to expand arguments to commands. We have to deal with 571558Srgrimes * backquotes, shell variables, and file metacharacters. 5841474Sjulian */ 5941474Sjulian 601558Srgrimes#include "shell.h" 6141474Sjulian#include "main.h" 6270050Siedowse#include "nodes.h" 6370050Siedowse#include "eval.h" 6486514Siedowse#include "expand.h" 6586514Siedowse#include "syntax.h" 6670050Siedowse#include "parser.h" 6770050Siedowse#include "jobs.h" 6841474Sjulian#include "options.h" 6941474Sjulian#include "var.h" 701558Srgrimes#include "input.h" 7141474Sjulian#include "output.h" 721558Srgrimes#include "memalloc.h" 7341474Sjulian#include "error.h" 741558Srgrimes#include "mystring.h" 7541474Sjulian#include "arith.h" 7641474Sjulian#include "show.h" 7741474Sjulian 7841474Sjulian/* 7941474Sjulian * Structure specifying which parts of the string should be searched 8041474Sjulian * for IFS characters. 8174556Smckusick */ 8274556Smckusick 8341474Sjulianstruct ifsregion { 8441474Sjulian struct ifsregion *next; /* next region in list */ 8541474Sjulian int begoff; /* offset of start of region */ 8641474Sjulian int endoff; /* offset of end of region */ 871558Srgrimes int nulonly; /* search for nul bytes only */ 881558Srgrimes}; 891558Srgrimes 9041474Sjulian 9141474Sjulianchar *expdest; /* output of current string */ 921558Srgrimesstruct nodelist *argbackq; /* list of back quote expressions */ 931558Srgrimesstruct ifsregion ifsfirst; /* first struct in list of ifs regions */ 941558Srgrimesstruct ifsregion *ifslastp; /* last struct in list */ 9541474Sjulianstruct arglist exparg; /* holds expanded arg list */ 9641474Sjulian 9741474SjulianSTATIC void argstr __P((char *, int)); 9841474SjulianSTATIC char *exptilde __P((char *, int)); 9941474SjulianSTATIC void expbackq __P((union node *, int, int)); 10041474SjulianSTATIC int subevalvar __P((char *, char *, int, int, int, int)); 10141474SjulianSTATIC char *evalvar __P((char *, int)); 10241474SjulianSTATIC int varisset __P((char *, int)); 10341474SjulianSTATIC void varvalue __P((char *, int, int)); 10486514SiedowseSTATIC void recordregion __P((int, int, int)); 10586514SiedowseSTATIC void ifsbreakup __P((char *, struct arglist *)); 10641474SjulianSTATIC void expandmeta __P((struct strlist *, int)); 10741474SjulianSTATIC void expmeta __P((char *, char *)); 10841474SjulianSTATIC void addfname __P((char *)); 10941474SjulianSTATIC struct strlist *expsort __P((struct strlist *)); 11041474SjulianSTATIC struct strlist *msort __P((struct strlist *, int)); 11141474SjulianSTATIC int pmatch __P((char *, char *)); 11241474SjulianSTATIC char *cvtnum __P((int, char *)); 11341474SjulianSTATIC int collate_range_cmp __P((int, int)); 11441474Sjulian 11541474SjulianSTATIC int collate_range_cmp (c1, c2) 11641474Sjulian int c1, c2; 11741474Sjulian{ 11841474Sjulian static char s1[2], s2[2]; 11941474Sjulian int ret; 12041474Sjulian 12141474Sjulian c1 &= UCHAR_MAX; 12241474Sjulian c2 &= UCHAR_MAX; 12341474Sjulian if (c1 == c2) 1241558Srgrimes return (0); 1251558Srgrimes s1[0] = c1; 1261558Srgrimes s2[0] = c2; 127 if ((ret = strcoll(s1, s2)) != 0) 128 return (ret); 129 return (c1 - c2); 130} 131 132/* 133 * Expand shell variables and backquotes inside a here document. 134 */ 135 136void 137expandhere(arg, fd) 138 union node *arg; /* the document */ 139 int fd; /* where to write the expanded version */ 140 { 141 herefd = fd; 142 expandarg(arg, (struct arglist *)NULL, 0); 143 xwrite(fd, stackblock(), expdest - stackblock()); 144} 145 146 147/* 148 * Perform variable substitution and command substitution on an argument, 149 * placing the resulting list of arguments in arglist. If EXP_FULL is true, 150 * perform splitting and file name expansion. When arglist is NULL, perform 151 * here document expansion. 152 */ 153 154void 155expandarg(arg, arglist, flag) 156 union node *arg; 157 struct arglist *arglist; 158 int flag; 159{ 160 struct strlist *sp; 161 char *p; 162 163 argbackq = arg->narg.backquote; 164 STARTSTACKSTR(expdest); 165 ifsfirst.next = NULL; 166 ifslastp = NULL; 167 argstr(arg->narg.text, flag); 168 if (arglist == NULL) { 169 return; /* here document expanded */ 170 } 171 STPUTC('\0', expdest); 172 p = grabstackstr(expdest); 173 exparg.lastp = &exparg.list; 174 /* 175 * TODO - EXP_REDIR 176 */ 177 if (flag & EXP_FULL) { 178 ifsbreakup(p, &exparg); 179 *exparg.lastp = NULL; 180 exparg.lastp = &exparg.list; 181 expandmeta(exparg.list, flag); 182 } else { 183 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ 184 rmescapes(p); 185 sp = (struct strlist *)stalloc(sizeof (struct strlist)); 186 sp->text = p; 187 *exparg.lastp = sp; 188 exparg.lastp = &sp->next; 189 } 190 while (ifsfirst.next != NULL) { 191 struct ifsregion *ifsp; 192 INTOFF; 193 ifsp = ifsfirst.next->next; 194 ckfree(ifsfirst.next); 195 ifsfirst.next = ifsp; 196 INTON; 197 } 198 *exparg.lastp = NULL; 199 if (exparg.list) { 200 *arglist->lastp = exparg.list; 201 arglist->lastp = exparg.lastp; 202 } 203} 204 205 206 207/* 208 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC 209 * characters to allow for further processing. Otherwise treat 210 * $@ like $* since no splitting will be performed. 211 */ 212 213STATIC void 214argstr(p, flag) 215 char *p; 216 int flag; 217{ 218 char c; 219 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ 220 int firsteq = 1; 221 222 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE))) 223 p = exptilde(p, flag); 224 for (;;) { 225 switch (c = *p++) { 226 case '\0': 227 case CTLENDVAR: /* ??? */ 228 goto breakloop; 229 case CTLESC: 230 if (quotes) 231 STPUTC(c, expdest); 232 c = *p++; 233 STPUTC(c, expdest); 234 break; 235 case CTLVAR: 236 p = evalvar(p, flag); 237 break; 238 case CTLBACKQ: 239 case CTLBACKQ|CTLQUOTE: 240 expbackq(argbackq->n, c & CTLQUOTE, flag); 241 argbackq = argbackq->next; 242 break; 243 case CTLENDARI: 244 expari(flag); 245 break; 246 case ':': 247 case '=': 248 /* 249 * sort of a hack - expand tildes in variable 250 * assignments (after the first '=' and after ':'s). 251 */ 252 STPUTC(c, expdest); 253 if (flag & EXP_VARTILDE && *p == '~') { 254 if (c == '=') { 255 if (firsteq) 256 firsteq = 0; 257 else 258 break; 259 } 260 p = exptilde(p, flag); 261 } 262 break; 263 default: 264 STPUTC(c, expdest); 265 } 266 } 267breakloop:; 268} 269 270STATIC char * 271exptilde(p, flag) 272 char *p; 273 int flag; 274{ 275 char c, *startp = p; 276 struct passwd *pw; 277 char *home; 278 int quotes = flag & (EXP_FULL | EXP_CASE); 279 280 while ((c = *p) != '\0') { 281 switch(c) { 282 case CTLESC: 283 return (startp); 284 case ':': 285 if (flag & EXP_VARTILDE) 286 goto done; 287 break; 288 case '/': 289 goto done; 290 } 291 p++; 292 } 293done: 294 *p = '\0'; 295 if (*(startp+1) == '\0') { 296 if ((home = lookupvar("HOME")) == NULL) 297 goto lose; 298 } else { 299 if ((pw = getpwnam(startp+1)) == NULL) 300 goto lose; 301 home = pw->pw_dir; 302 } 303 if (*home == '\0') 304 goto lose; 305 *p = c; 306 while ((c = *home++) != '\0') { 307 if (quotes && SQSYNTAX[c] == CCTL) 308 STPUTC(CTLESC, expdest); 309 STPUTC(c, expdest); 310 } 311 return (p); 312lose: 313 *p = c; 314 return (startp); 315} 316 317 318/* 319 * Expand arithmetic expression. Backup to start of expression, 320 * evaluate, place result in (backed up) result, adjust string position. 321 */ 322void 323expari(flag) 324 int flag; 325{ 326 char *p, *start; 327 int result; 328 int quotes = flag & (EXP_FULL | EXP_CASE); 329 330 while (ifsfirst.next != NULL) { 331 struct ifsregion *ifsp; 332 INTOFF; 333 ifsp = ifsfirst.next->next; 334 ckfree(ifsfirst.next); 335 ifsfirst.next = ifsp; 336 INTON; 337 } 338 ifslastp = NULL; 339 340 /* 341 * This routine is slightly over-compilcated for 342 * efficiency. First we make sure there is 343 * enough space for the result, which may be bigger 344 * than the expression if we add exponentation. Next we 345 * scan backwards looking for the start of arithmetic. If the 346 * next previous character is a CTLESC character, then we 347 * have to rescan starting from the beginning since CTLESC 348 * characters have to be processed left to right. 349 */ 350#if INT_MAX / 1000000000 >= 10 || INT_MIN / 1000000000 <= -10 351#error "integers with more than 10 digits are not supported" 352#endif 353 CHECKSTRSPACE(12 - 2, expdest); 354 USTPUTC('\0', expdest); 355 start = stackblock(); 356 p = expdest; 357 while (*p != CTLARI && p >= start) 358 --p; 359 if (*p != CTLARI) 360 error("missing CTLARI (shouldn't happen)"); 361 if (p > start && *(p-1) == CTLESC) 362 for (p = start; *p != CTLARI; p++) 363 if (*p == CTLESC) 364 p++; 365 if (quotes) 366 rmescapes(p+1); 367 result = arith(p+1); 368 fmtstr(p, 12, "%d", result); 369 while (*p++) 370 ; 371 result = expdest - p + 1; 372 STADJUST(-result, expdest); 373} 374 375 376/* 377 * Expand stuff in backwards quotes. 378 */ 379 380STATIC void 381expbackq(cmd, quoted, flag) 382 union node *cmd; 383 int quoted; 384 int flag; 385{ 386 struct backcmd in; 387 int i; 388 char buf[128]; 389 char *p; 390 char *dest = expdest; 391 struct ifsregion saveifs, *savelastp; 392 struct nodelist *saveargbackq; 393 char lastc; 394 int startloc = dest - stackblock(); 395 char const *syntax = quoted? DQSYNTAX : BASESYNTAX; 396 int saveherefd; 397 int quotes = flag & (EXP_FULL | EXP_CASE); 398 399 INTOFF; 400 saveifs = ifsfirst; 401 savelastp = ifslastp; 402 saveargbackq = argbackq; 403 saveherefd = herefd; 404 herefd = -1; 405 p = grabstackstr(dest); 406 evalbackcmd(cmd, &in); 407 ungrabstackstr(p, dest); 408 ifsfirst = saveifs; 409 ifslastp = savelastp; 410 argbackq = saveargbackq; 411 herefd = saveherefd; 412 413 p = in.buf; 414 lastc = '\0'; 415 for (;;) { 416 if (--in.nleft < 0) { 417 if (in.fd < 0) 418 break; 419 while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR); 420 TRACE(("expbackq: read returns %d\n", i)); 421 if (i <= 0) 422 break; 423 p = buf; 424 in.nleft = i - 1; 425 } 426 lastc = *p++; 427 if (lastc != '\0') { 428 if (quotes && syntax[lastc] == CCTL) 429 STPUTC(CTLESC, dest); 430 STPUTC(lastc, dest); 431 } 432 } 433 434 /* Eat all trailing newlines */ 435 for (p--; lastc == '\n'; lastc = *--p) 436 STUNPUTC(dest); 437 438 if (in.fd >= 0) 439 close(in.fd); 440 if (in.buf) 441 ckfree(in.buf); 442 if (in.jp) 443 exitstatus = waitforjob(in.jp); 444 if (quoted == 0) 445 recordregion(startloc, dest - stackblock(), 0); 446 TRACE(("evalbackq: size=%d: \"%.*s\"\n", 447 (dest - stackblock()) - startloc, 448 (dest - stackblock()) - startloc, 449 stackblock() + startloc)); 450 expdest = dest; 451 INTON; 452} 453 454 455 456STATIC int 457subevalvar(p, str, strloc, subtype, startloc, varflags) 458 char *p; 459 char *str; 460 int strloc; 461 int subtype; 462 int startloc; 463 int varflags; 464{ 465 char *startp; 466 char *loc = NULL; 467 int c = 0; 468 int saveherefd = herefd; 469 struct nodelist *saveargbackq = argbackq; 470 int amount; 471 472 herefd = -1; 473 argstr(p, 0); 474 STACKSTRNUL(expdest); 475 herefd = saveherefd; 476 argbackq = saveargbackq; 477 startp = stackblock() + startloc; 478 if (str == NULL) 479 str = stackblock() + strloc; 480 481 switch (subtype) { 482 case VSASSIGN: 483 setvar(str, startp, 0); 484 amount = startp - expdest; 485 STADJUST(amount, expdest); 486 varflags &= ~VSNUL; 487 if (c != 0) 488 *loc = c; 489 return 1; 490 491 case VSQUESTION: 492 if (*p != CTLENDVAR) { 493 outfmt(&errout, "%s\n", startp); 494 error((char *)NULL); 495 } 496 error("%.*s: parameter %snot set", p - str - 1, 497 str, (varflags & VSNUL) ? "null or " 498 : nullstr); 499 return 0; 500 501 case VSTRIMLEFT: 502 for (loc = startp; loc < str; loc++) { 503 c = *loc; 504 *loc = '\0'; 505 if (patmatch(str, startp)) { 506 *loc = c; 507 goto recordleft; 508 } 509 *loc = c; 510 } 511 return 0; 512 513 case VSTRIMLEFTMAX: 514 for (loc = str - 1; loc >= startp; loc--) { 515 c = *loc; 516 *loc = '\0'; 517 if (patmatch(str, startp)) { 518 *loc = c; 519 goto recordleft; 520 } 521 *loc = c; 522 } 523 return 0; 524 525 case VSTRIMRIGHT: 526 for (loc = str - 1; loc >= startp; loc--) { 527 if (patmatch(str, loc)) { 528 amount = loc - expdest; 529 STADJUST(amount, expdest); 530 return 1; 531 } 532 } 533 return 0; 534 535 case VSTRIMRIGHTMAX: 536 for (loc = startp; loc < str - 1; loc++) { 537 if (patmatch(str, loc)) { 538 amount = loc - expdest; 539 STADJUST(amount, expdest); 540 return 1; 541 } 542 } 543 return 0; 544 545 546 default: 547 abort(); 548 } 549 550recordleft: 551 amount = ((str - 1) - (loc - startp)) - expdest; 552 STADJUST(amount, expdest); 553 while (loc != str - 1) 554 *startp++ = *loc++; 555 return 1; 556} 557 558 559/* 560 * Expand a variable, and return a pointer to the next character in the 561 * input string. 562 */ 563 564STATIC char * 565evalvar(p, flag) 566 char *p; 567 int flag; 568{ 569 int subtype; 570 int varflags; 571 char *var; 572 char *val; 573 char *pat; 574 int c; 575 int set; 576 int special; 577 int startloc; 578 int varlen; 579 int easy; 580 int quotes = flag & (EXP_FULL | EXP_CASE); 581 582 varflags = *p++; 583 subtype = varflags & VSTYPE; 584 var = p; 585 special = 0; 586 if (! is_name(*p)) 587 special = 1; 588 p = strchr(p, '=') + 1; 589again: /* jump here after setting a variable with ${var=text} */ 590 if (special) { 591 set = varisset(var, varflags & VSNUL); 592 val = NULL; 593 } else { 594 val = lookupvar(var); 595 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) { 596 val = NULL; 597 set = 0; 598 } else 599 set = 1; 600 } 601 varlen = 0; 602 startloc = expdest - stackblock(); 603 if (set && subtype != VSPLUS) { 604 /* insert the value of the variable */ 605 if (special) { 606 varvalue(var, varflags & VSQUOTE, flag & EXP_FULL); 607 if (subtype == VSLENGTH) { 608 varlen = expdest - stackblock() - startloc; 609 STADJUST(-varlen, expdest); 610 } 611 } else { 612 char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX 613 : BASESYNTAX; 614 615 if (subtype == VSLENGTH) { 616 for (;*val; val++) 617 varlen++; 618 } 619 else { 620 while (*val) { 621 if (quotes && syntax[*val] == CCTL) 622 STPUTC(CTLESC, expdest); 623 STPUTC(*val++, expdest); 624 } 625 626 } 627 } 628 } 629 630 if (subtype == VSPLUS) 631 set = ! set; 632 633 easy = ((varflags & VSQUOTE) == 0 || 634 (*var == '@' && shellparam.nparam != 1)); 635 636 637 switch (subtype) { 638 case VSLENGTH: 639 expdest = cvtnum(varlen, expdest); 640 goto record; 641 642 case VSNORMAL: 643 if (!easy) 644 break; 645record: 646 recordregion(startloc, expdest - stackblock(), 647 varflags & VSQUOTE); 648 break; 649 650 case VSPLUS: 651 case VSMINUS: 652 if (!set) { 653 argstr(p, flag); 654 break; 655 } 656 if (easy) 657 goto record; 658 break; 659 660 case VSTRIMLEFT: 661 case VSTRIMLEFTMAX: 662 case VSTRIMRIGHT: 663 case VSTRIMRIGHTMAX: 664 if (!set) 665 break; 666 /* 667 * Terminate the string and start recording the pattern 668 * right after it 669 */ 670 STPUTC('\0', expdest); 671 pat = expdest; 672 if (subevalvar(p, NULL, expdest - stackblock(), subtype, 673 startloc, varflags)) 674 goto record; 675 else { 676 int amount = (expdest - pat) + 1; 677 STADJUST(-amount, expdest); 678 } 679 break; 680 681 case VSASSIGN: 682 case VSQUESTION: 683 if (!set) { 684 if (subevalvar(p, var, 0, subtype, startloc, varflags)) { 685 varflags &= ~VSNUL; 686 goto again; 687 } 688 break; 689 } 690 if (easy) 691 goto record; 692 break; 693 694 default: 695 abort(); 696 } 697 698 if (subtype != VSNORMAL) { /* skip to end of alternative */ 699 int nesting = 1; 700 for (;;) { 701 if ((c = *p++) == CTLESC) 702 p++; 703 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { 704 if (set) 705 argbackq = argbackq->next; 706 } else if (c == CTLVAR) { 707 if ((*p++ & VSTYPE) != VSNORMAL) 708 nesting++; 709 } else if (c == CTLENDVAR) { 710 if (--nesting == 0) 711 break; 712 } 713 } 714 } 715 return p; 716} 717 718 719 720/* 721 * Test whether a specialized variable is set. 722 */ 723 724STATIC int 725varisset(name, nulok) 726 char *name; 727 int nulok; 728{ 729 730 if (*name == '!') 731 return backgndpid != -1; 732 else if (*name == '@' || *name == '*') { 733 if (*shellparam.p == NULL) 734 return 0; 735 736 if (nulok) { 737 char **av; 738 739 for (av = shellparam.p; *av; av++) 740 if (**av != '\0') 741 return 1; 742 return 0; 743 } 744 } else if (is_digit(*name)) { 745 char *ap; 746 int num = atoi(name); 747 748 if (num > shellparam.nparam) 749 return 0; 750 751 if (num == 0) 752 ap = arg0; 753 else 754 ap = shellparam.p[num - 1]; 755 756 if (nulok && (ap == NULL || *ap == '\0')) 757 return 0; 758 } 759 return 1; 760} 761 762 763 764/* 765 * Add the value of a specialized variable to the stack string. 766 */ 767 768STATIC void 769varvalue(name, quoted, allow_split) 770 char *name; 771 int quoted; 772 int allow_split; 773{ 774 int num; 775 char *p; 776 int i; 777 extern int oexitstatus; 778 char sep; 779 char **ap; 780 char const *syntax; 781 782#define STRTODEST(p) \ 783 do {\ 784 if (allow_split) { \ 785 syntax = quoted? DQSYNTAX : BASESYNTAX; \ 786 while (*p) { \ 787 if (syntax[*p] == CCTL) \ 788 STPUTC(CTLESC, expdest); \ 789 STPUTC(*p++, expdest); \ 790 } \ 791 } else \ 792 while (*p) \ 793 STPUTC(*p++, expdest); \ 794 } while (0) 795 796 797 switch (*name) { 798 case '$': 799 num = rootpid; 800 goto numvar; 801 case '?': 802 num = oexitstatus; 803 goto numvar; 804 case '#': 805 num = shellparam.nparam; 806 goto numvar; 807 case '!': 808 num = backgndpid; 809numvar: 810 expdest = cvtnum(num, expdest); 811 break; 812 case '-': 813 for (i = 0 ; i < NOPTS ; i++) { 814 if (optlist[i].val) 815 STPUTC(optlist[i].letter, expdest); 816 } 817 break; 818 case '@': 819 if (allow_split) { 820 sep = '\0'; 821 goto allargs; 822 } 823 /* fall through */ 824 case '*': 825 sep = ' '; 826allargs: 827 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { 828 STRTODEST(p); 829 if (*ap) 830 STPUTC(sep, expdest); 831 } 832 break; 833 case '0': 834 p = arg0; 835 STRTODEST(p); 836 break; 837 default: 838 if (is_digit(*name)) { 839 num = atoi(name); 840 if (num > 0 && num <= shellparam.nparam) { 841 p = shellparam.p[num - 1]; 842 STRTODEST(p); 843 } 844 } 845 break; 846 } 847} 848 849 850 851/* 852 * Record the the fact that we have to scan this region of the 853 * string for IFS characters. 854 */ 855 856STATIC void 857recordregion(start, end, nulonly) 858 int start; 859 int end; 860 int nulonly; 861{ 862 struct ifsregion *ifsp; 863 864 if (ifslastp == NULL) { 865 ifsp = &ifsfirst; 866 } else { 867 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion)); 868 ifslastp->next = ifsp; 869 } 870 ifslastp = ifsp; 871 ifslastp->next = NULL; 872 ifslastp->begoff = start; 873 ifslastp->endoff = end; 874 ifslastp->nulonly = nulonly; 875} 876 877 878 879/* 880 * Break the argument string into pieces based upon IFS and add the 881 * strings to the argument list. The regions of the string to be 882 * searched for IFS characters have been stored by recordregion. 883 */ 884STATIC void 885ifsbreakup(string, arglist) 886 char *string; 887 struct arglist *arglist; 888 { 889 struct ifsregion *ifsp; 890 struct strlist *sp; 891 char *start; 892 char *p; 893 char *q; 894 char *ifs; 895 int ifsspc; 896 897 898 start = string; 899 if (ifslastp != NULL) { 900 ifsp = &ifsfirst; 901 do { 902 p = string + ifsp->begoff; 903 ifs = ifsp->nulonly? nullstr : ifsval(); 904 ifsspc = strchr(ifs, ' ') != NULL; 905 while (p < string + ifsp->endoff) { 906 q = p; 907 if (*p == CTLESC) 908 p++; 909 if (strchr(ifs, *p++)) { 910 if (q > start || !ifsspc) { 911 *q = '\0'; 912 sp = (struct strlist *)stalloc(sizeof *sp); 913 sp->text = start; 914 *arglist->lastp = sp; 915 arglist->lastp = &sp->next; 916 } 917 if (ifsspc) { 918 for (;;) { 919 if (p >= string + ifsp->endoff) 920 break; 921 q = p; 922 if (*p == CTLESC) 923 p++; 924 if (strchr(ifs, *p++) == NULL) { 925 p = q; 926 break; 927 } 928 } 929 } 930 start = p; 931 } 932 } 933 } while ((ifsp = ifsp->next) != NULL); 934 if (*start || (!ifsspc && start > string)) { 935 sp = (struct strlist *)stalloc(sizeof *sp); 936 sp->text = start; 937 *arglist->lastp = sp; 938 arglist->lastp = &sp->next; 939 } 940 } else { 941 sp = (struct strlist *)stalloc(sizeof *sp); 942 sp->text = start; 943 *arglist->lastp = sp; 944 arglist->lastp = &sp->next; 945 } 946} 947 948 949 950/* 951 * Expand shell metacharacters. At this point, the only control characters 952 * should be escapes. The results are stored in the list exparg. 953 */ 954 955char *expdir; 956 957 958STATIC void 959expandmeta(str, flag) 960 struct strlist *str; 961 int flag __unused; 962{ 963 char *p; 964 struct strlist **savelastp; 965 struct strlist *sp; 966 char c; 967 /* TODO - EXP_REDIR */ 968 969 while (str) { 970 if (fflag) 971 goto nometa; 972 p = str->text; 973 for (;;) { /* fast check for meta chars */ 974 if ((c = *p++) == '\0') 975 goto nometa; 976 if (c == '*' || c == '?' || c == '[' || c == '!') 977 break; 978 } 979 savelastp = exparg.lastp; 980 INTOFF; 981 if (expdir == NULL) { 982 int i = strlen(str->text); 983 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ 984 } 985 986 expmeta(expdir, str->text); 987 ckfree(expdir); 988 expdir = NULL; 989 INTON; 990 if (exparg.lastp == savelastp) { 991 /* 992 * no matches 993 */ 994nometa: 995 *exparg.lastp = str; 996 rmescapes(str->text); 997 exparg.lastp = &str->next; 998 } else { 999 *exparg.lastp = NULL; 1000 *savelastp = sp = expsort(*savelastp); 1001 while (sp->next != NULL) 1002 sp = sp->next; 1003 exparg.lastp = &sp->next; 1004 } 1005 str = str->next; 1006 } 1007} 1008 1009 1010/* 1011 * Do metacharacter (i.e. *, ?, [...]) expansion. 1012 */ 1013 1014STATIC void 1015expmeta(enddir, name) 1016 char *enddir; 1017 char *name; 1018 { 1019 char *p; 1020 char *q; 1021 char *start; 1022 char *endname; 1023 int metaflag; 1024 struct stat statb; 1025 DIR *dirp; 1026 struct dirent *dp; 1027 int atend; 1028 int matchdot; 1029 1030 metaflag = 0; 1031 start = name; 1032 for (p = name ; ; p++) { 1033 if (*p == '*' || *p == '?') 1034 metaflag = 1; 1035 else if (*p == '[') { 1036 q = p + 1; 1037 if (*q == '!' || *q == '^') 1038 q++; 1039 for (;;) { 1040 if (*q == CTLESC) 1041 q++; 1042 if (*q == '/' || *q == '\0') 1043 break; 1044 if (*++q == ']') { 1045 metaflag = 1; 1046 break; 1047 } 1048 } 1049 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) { 1050 metaflag = 1; 1051 } else if (*p == '\0') 1052 break; 1053 else if (*p == CTLESC) 1054 p++; 1055 if (*p == '/') { 1056 if (metaflag) 1057 break; 1058 start = p + 1; 1059 } 1060 } 1061 if (metaflag == 0) { /* we've reached the end of the file name */ 1062 if (enddir != expdir) 1063 metaflag++; 1064 for (p = name ; ; p++) { 1065 if (*p == CTLESC) 1066 p++; 1067 *enddir++ = *p; 1068 if (*p == '\0') 1069 break; 1070 } 1071 if (metaflag == 0 || stat(expdir, &statb) >= 0) 1072 addfname(expdir); 1073 return; 1074 } 1075 endname = p; 1076 if (start != name) { 1077 p = name; 1078 while (p < start) { 1079 if (*p == CTLESC) 1080 p++; 1081 *enddir++ = *p++; 1082 } 1083 } 1084 if (enddir == expdir) { 1085 p = "."; 1086 } else if (enddir == expdir + 1 && *expdir == '/') { 1087 p = "/"; 1088 } else { 1089 p = expdir; 1090 enddir[-1] = '\0'; 1091 } 1092 if ((dirp = opendir(p)) == NULL) 1093 return; 1094 if (enddir != expdir) 1095 enddir[-1] = '/'; 1096 if (*endname == 0) { 1097 atend = 1; 1098 } else { 1099 atend = 0; 1100 *endname++ = '\0'; 1101 } 1102 matchdot = 0; 1103 if (start[0] == '.' || (start[0] == CTLESC && start[1] == '.')) 1104 matchdot++; 1105 while (! int_pending() && (dp = readdir(dirp)) != NULL) { 1106 if (dp->d_name[0] == '.' && ! matchdot) 1107 continue; 1108 if (patmatch(start, dp->d_name)) { 1109 if (atend) { 1110 scopy(dp->d_name, enddir); 1111 addfname(expdir); 1112 } else { 1113 char *q; 1114 for (p = enddir, q = dp->d_name; 1115 (*p++ = *q++) != '\0';) 1116 continue; 1117 p[-1] = '/'; 1118 expmeta(p, endname); 1119 } 1120 } 1121 } 1122 closedir(dirp); 1123 if (! atend) 1124 endname[-1] = '/'; 1125} 1126 1127 1128/* 1129 * Add a file name to the list. 1130 */ 1131 1132STATIC void 1133addfname(name) 1134 char *name; 1135 { 1136 char *p; 1137 struct strlist *sp; 1138 1139 p = stalloc(strlen(name) + 1); 1140 scopy(name, p); 1141 sp = (struct strlist *)stalloc(sizeof *sp); 1142 sp->text = p; 1143 *exparg.lastp = sp; 1144 exparg.lastp = &sp->next; 1145} 1146 1147 1148/* 1149 * Sort the results of file name expansion. It calculates the number of 1150 * strings to sort and then calls msort (short for merge sort) to do the 1151 * work. 1152 */ 1153 1154STATIC struct strlist * 1155expsort(str) 1156 struct strlist *str; 1157 { 1158 int len; 1159 struct strlist *sp; 1160 1161 len = 0; 1162 for (sp = str ; sp ; sp = sp->next) 1163 len++; 1164 return msort(str, len); 1165} 1166 1167 1168STATIC struct strlist * 1169msort(list, len) 1170 struct strlist *list; 1171 int len; 1172{ 1173 struct strlist *p, *q = NULL; 1174 struct strlist **lpp; 1175 int half; 1176 int n; 1177 1178 if (len <= 1) 1179 return list; 1180 half = len >> 1; 1181 p = list; 1182 for (n = half ; --n >= 0 ; ) { 1183 q = p; 1184 p = p->next; 1185 } 1186 q->next = NULL; /* terminate first half of list */ 1187 q = msort(list, half); /* sort first half of list */ 1188 p = msort(p, len - half); /* sort second half */ 1189 lpp = &list; 1190 for (;;) { 1191 if (strcmp(p->text, q->text) < 0) { 1192 *lpp = p; 1193 lpp = &p->next; 1194 if ((p = *lpp) == NULL) { 1195 *lpp = q; 1196 break; 1197 } 1198 } else { 1199 *lpp = q; 1200 lpp = &q->next; 1201 if ((q = *lpp) == NULL) { 1202 *lpp = p; 1203 break; 1204 } 1205 } 1206 } 1207 return list; 1208} 1209 1210 1211 1212/* 1213 * Returns true if the pattern matches the string. 1214 */ 1215 1216int 1217patmatch(pattern, string) 1218 char *pattern; 1219 char *string; 1220 { 1221#ifdef notdef 1222 if (pattern[0] == '!' && pattern[1] == '!') 1223 return 1 - pmatch(pattern + 2, string); 1224 else 1225#endif 1226 return pmatch(pattern, string); 1227} 1228 1229 1230STATIC int 1231pmatch(pattern, string) 1232 char *pattern; 1233 char *string; 1234 { 1235 char *p, *q; 1236 char c; 1237 1238 p = pattern; 1239 q = string; 1240 for (;;) { 1241 switch (c = *p++) { 1242 case '\0': 1243 goto breakloop; 1244 case CTLESC: 1245 if (*q++ != *p++) 1246 return 0; 1247 break; 1248 case '?': 1249 if (*q++ == '\0') 1250 return 0; 1251 break; 1252 case '*': 1253 c = *p; 1254 if (c != CTLESC && c != '?' && c != '*' && c != '[') { 1255 while (*q != c) { 1256 if (*q == '\0') 1257 return 0; 1258 q++; 1259 } 1260 } 1261 do { 1262 if (pmatch(p, q)) 1263 return 1; 1264 } while (*q++ != '\0'); 1265 return 0; 1266 case '[': { 1267 char *endp; 1268 int invert, found; 1269 char chr; 1270 1271 endp = p; 1272 if (*endp == '!' || *endp == '^') 1273 endp++; 1274 for (;;) { 1275 if (*endp == '\0') 1276 goto dft; /* no matching ] */ 1277 if (*endp == CTLESC) 1278 endp++; 1279 if (*++endp == ']') 1280 break; 1281 } 1282 invert = 0; 1283 if (*p == '!' || *p == '^') { 1284 invert++; 1285 p++; 1286 } 1287 found = 0; 1288 chr = *q++; 1289 if (chr == '\0') 1290 return 0; 1291 c = *p++; 1292 do { 1293 if (c == CTLESC) 1294 c = *p++; 1295 if (*p == '-' && p[1] != ']') { 1296 p++; 1297 if (*p == CTLESC) 1298 p++; 1299 if ( collate_range_cmp(chr, c) >= 0 1300 && collate_range_cmp(chr, *p) <= 0 1301 ) 1302 found = 1; 1303 p++; 1304 } else { 1305 if (chr == c) 1306 found = 1; 1307 } 1308 } while ((c = *p++) != ']'); 1309 if (found == invert) 1310 return 0; 1311 break; 1312 } 1313dft: default: 1314 if (*q++ != c) 1315 return 0; 1316 break; 1317 } 1318 } 1319breakloop: 1320 if (*q != '\0') 1321 return 0; 1322 return 1; 1323} 1324 1325 1326 1327/* 1328 * Remove any CTLESC characters from a string. 1329 */ 1330 1331void 1332rmescapes(str) 1333 char *str; 1334 { 1335 char *p, *q; 1336 1337 p = str; 1338 while (*p != CTLESC) { 1339 if (*p++ == '\0') 1340 return; 1341 } 1342 q = p; 1343 while (*p) { 1344 if (*p == CTLESC) 1345 p++; 1346 *q++ = *p++; 1347 } 1348 *q = '\0'; 1349} 1350 1351 1352 1353/* 1354 * See if a pattern matches in a case statement. 1355 */ 1356 1357int 1358casematch(pattern, val) 1359 union node *pattern; 1360 char *val; 1361 { 1362 struct stackmark smark; 1363 int result; 1364 char *p; 1365 1366 setstackmark(&smark); 1367 argbackq = pattern->narg.backquote; 1368 STARTSTACKSTR(expdest); 1369 ifslastp = NULL; 1370 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); 1371 STPUTC('\0', expdest); 1372 p = grabstackstr(expdest); 1373 result = patmatch(p, val); 1374 popstackmark(&smark); 1375 return result; 1376} 1377 1378/* 1379 * Our own itoa(). 1380 */ 1381 1382STATIC char * 1383cvtnum(num, buf) 1384 int num; 1385 char *buf; 1386 { 1387 char temp[32]; 1388 int neg = num < 0; 1389 char *p = temp + 31; 1390 1391 temp[31] = '\0'; 1392 1393 do { 1394 *--p = num % 10 + '0'; 1395 } while ((num /= 10) != 0); 1396 1397 if (neg) 1398 *--p = '-'; 1399 1400 while (*p) 1401 STPUTC(*p++, buf); 1402 return buf; 1403} 1404