1 /*- 2 * Copyright (c) 1980, 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)glob.c 5.27 (Berkeley) 08/02/91"; 10 #endif /* not lint */ 11 12 #include <sys/param.h> 13 #include <glob.h> 14 #include <errno.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include <unistd.h> 18 #if __STDC__ 19 # include <stdarg.h> 20 #else 21 # include <varargs.h> 22 #endif 23 24 #include "csh.h" 25 #include "extern.h" 26 27 static int noglob; 28 static int pargsiz, gargsiz; 29 30 /* 31 * Values for gflag 32 */ 33 #define G_NONE 0 /* No globbing needed */ 34 #define G_GLOB 1 /* string contains *?[] characters */ 35 #define G_CSH 2 /* string contains ~`{ characters */ 36 37 #define GLOBSPACE 100 /* Alloc increment */ 38 39 #define LBRC '{' 40 #define RBRC '}' 41 #define LBRK '[' 42 #define RBRK ']' 43 #define EOS '\0' 44 45 Char **gargv = NULL; 46 long gargc = 0; 47 Char **pargv = NULL; 48 long pargc = 0; 49 50 /* 51 * globbing is now done in two stages. In the first pass we expand 52 * csh globbing idioms ~`{ and then we proceed doing the normal 53 * globbing if needed ?*[ 54 * 55 * Csh type globbing is handled in globexpand() and the rest is 56 * handled in glob() which is part of the 4.4BSD libc. 57 * 58 */ 59 static Char *globtilde __P((Char **, Char *)); 60 static Char **libglob __P((Char **)); 61 static Char **globexpand __P((Char **)); 62 static int globbrace __P((Char *, Char *, Char ***)); 63 static void pword __P((void)); 64 static void psave __P((int)); 65 static void backeval __P((Char *, bool)); 66 67 68 static Char * 69 globtilde(nv, s) 70 Char **nv, *s; 71 { 72 Char gbuf[MAXPATHLEN], *gstart, *b, *u, *e; 73 74 gstart = gbuf; 75 *gstart++ = *s++; 76 u = s; 77 for (b = gstart, e = &gbuf[MAXPATHLEN - 1]; *s && *s != '/' && b < e; 78 *b++ = *s++); 79 *b = EOS; 80 if (gethdir(gstart)) { 81 blkfree(nv); 82 if (*gstart) 83 stderror(ERR_UNKUSER, short2str(gstart)); 84 else 85 stderror(ERR_NOHOME); 86 } 87 b = &gstart[Strlen(gstart)]; 88 while (*s) 89 *b++ = *s++; 90 *b = EOS; 91 --u; 92 xfree((ptr_t) u); 93 return (Strsave(gstart)); 94 } 95 96 static int 97 globbrace(s, p, bl) 98 Char *s, *p, ***bl; 99 { 100 int i, len; 101 Char *pm, *pe, *lm, *pl; 102 Char **nv, **vl; 103 Char gbuf[MAXPATHLEN]; 104 int size = GLOBSPACE; 105 106 nv = vl = (Char **) xmalloc((size_t) sizeof(Char *) * size); 107 *vl = NULL; 108 109 len = 0; 110 /* copy part up to the brace */ 111 for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++) 112 continue; 113 114 /* check for balanced braces */ 115 for (i = 0, pe = ++p; *pe; pe++) 116 if (*pe == LBRK) { 117 /* Ignore everything between [] */ 118 for (++pe; *pe != RBRK && *pe != EOS; pe++) 119 continue; 120 if (*pe == EOS) { 121 blkfree(nv); 122 return (-LBRK); 123 } 124 } 125 else if (*pe == LBRC) 126 i++; 127 else if (*pe == RBRC) { 128 if (i == 0) 129 break; 130 i--; 131 } 132 133 if (i != 0 || *pe == '\0') { 134 blkfree(nv); 135 return (-RBRC); 136 } 137 138 for (i = 0, pl = pm = p; pm <= pe; pm++) 139 switch (*pm) { 140 case LBRK: 141 for (++pm; *pm != RBRK && *pm != EOS; pm++) 142 continue; 143 if (*pm == EOS) { 144 *vl = NULL; 145 blkfree(nv); 146 return (-RBRK); 147 } 148 break; 149 case LBRC: 150 i++; 151 break; 152 case RBRC: 153 if (i) { 154 i--; 155 break; 156 } 157 /* FALLTHROUGH */ 158 case ',': 159 if (i && *pm == ',') 160 break; 161 else { 162 Char savec = *pm; 163 164 *pm = EOS; 165 (void) Strcpy(lm, pl); 166 (void) Strcat(gbuf, pe + 1); 167 *pm = savec; 168 *vl++ = Strsave(gbuf); 169 len++; 170 pl = pm + 1; 171 if (vl == &nv[size]) { 172 size += GLOBSPACE; 173 nv = (Char **) xrealloc((ptr_t) nv, (size_t) 174 size * sizeof(Char *)); 175 vl = &nv[size - GLOBSPACE]; 176 } 177 } 178 break; 179 } 180 *vl = NULL; 181 *bl = nv; 182 return (len); 183 } 184 185 static Char ** 186 globexpand(v) 187 Char **v; 188 { 189 Char *s; 190 Char **nv, **vl, **el; 191 int size = GLOBSPACE; 192 193 194 nv = vl = (Char **) xmalloc((size_t) sizeof(Char *) * size); 195 *vl = NULL; 196 197 /* 198 * Step 1: expand backquotes. 199 */ 200 while (s = *v++) { 201 if (Strchr(s, '`')) { 202 int i; 203 204 (void) dobackp(s, 0); 205 for (i = 0; i < pargc; i++) { 206 *vl++ = pargv[i]; 207 if (vl == &nv[size]) { 208 size += GLOBSPACE; 209 nv = (Char **) xrealloc((ptr_t) nv, 210 (size_t) size * sizeof(Char *)); 211 vl = &nv[size - GLOBSPACE]; 212 } 213 } 214 xfree((ptr_t) pargv); 215 pargv = NULL; 216 } 217 else { 218 *vl++ = Strsave(s); 219 if (vl == &nv[size]) { 220 size += GLOBSPACE; 221 nv = (Char **) xrealloc((ptr_t) nv, (size_t) 222 size * sizeof(Char *)); 223 vl = &nv[size - GLOBSPACE]; 224 } 225 } 226 } 227 *vl = NULL; 228 229 if (noglob) 230 return (nv); 231 232 /* 233 * Step 2: expand braces 234 */ 235 el = vl; 236 vl = nv; 237 for (s = *vl; s; s = *++vl) { 238 Char *b; 239 Char **vp, **bp; 240 241 if ((b = Strchr(s, LBRC)) != NULL && b[1] != '\0' && b[1] != RBRC) { 242 Char **bl; 243 int len; 244 245 if ((len = globbrace(s, b, &bl)) < 0) { 246 blkfree(nv); 247 stderror(ERR_MISSING, -len); 248 } 249 xfree((ptr_t) s); 250 if (len == 1) { 251 *vl-- = *bl; 252 xfree((ptr_t) bl); 253 continue; 254 } 255 len = blklen(bl); 256 if (&el[len] >= &nv[size]) { 257 int l, e; 258 259 l = &el[len] - &nv[size]; 260 size += GLOBSPACE > l ? GLOBSPACE : l; 261 l = vl - nv; 262 e = el - nv; 263 nv = (Char **) xrealloc((ptr_t) nv, (size_t) 264 size * sizeof(Char *)); 265 vl = nv + l; 266 el = nv + e; 267 } 268 vp = vl--; 269 *vp = *bl; 270 len--; 271 for (bp = el; bp != vp; bp--) 272 bp[len] = *bp; 273 el += len; 274 vp++; 275 for (bp = bl + 1; *bp; *vp++ = *bp++) 276 continue; 277 xfree((ptr_t) bl); 278 } 279 280 } 281 282 /* 283 * Step 3: expand ~ 284 */ 285 vl = nv; 286 for (s = *vl; s; s = *++vl) 287 if (*s == '~') 288 *vl = globtilde(nv, s); 289 vl = nv; 290 return (vl); 291 } 292 293 static Char * 294 handleone(str, vl, action) 295 Char *str, **vl; 296 int action; 297 { 298 299 Char *cp, **vlp = vl; 300 301 switch (action) { 302 case G_ERROR: 303 setname(short2str(str)); 304 blkfree(vl); 305 stderror(ERR_NAME | ERR_AMBIG); 306 break; 307 case G_APPEND: 308 trim(vlp); 309 str = Strsave(*vlp++); 310 do { 311 cp = Strspl(str, STRspace); 312 xfree((ptr_t) str); 313 str = Strspl(cp, *vlp); 314 xfree((ptr_t) cp); 315 } 316 while (*++vlp); 317 blkfree(vl); 318 break; 319 case G_IGNORE: 320 str = Strsave(strip(*vlp)); 321 blkfree(vl); 322 break; 323 } 324 return (str); 325 } 326 327 static Char ** 328 libglob(vl) 329 Char **vl; 330 { 331 int gflgs = GLOB_QUOTE | GLOB_NOMAGIC; 332 glob_t globv; 333 char *ptr; 334 int nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0; 335 336 if (!vl || !vl[0]) 337 return (vl); 338 339 globv.gl_offs = 0; 340 globv.gl_pathv = 0; 341 globv.gl_pathc = 0; 342 343 if (nonomatch) 344 gflgs |= GLOB_NOCHECK; 345 346 do { 347 ptr = short2qstr(*vl); 348 switch (glob(ptr, gflgs, 0, &globv)) { 349 case GLOB_ABEND: 350 setname(ptr); 351 stderror(ERR_NAME | ERR_GLOB); 352 /* NOTREACHED */ 353 case GLOB_NOSPACE: 354 stderror(ERR_NOMEM); 355 /* NOTREACHED */ 356 default: 357 break; 358 } 359 if (globv.gl_flags & GLOB_MAGCHAR) { 360 match |= (globv.gl_matchc != 0); 361 magic = 1; 362 } 363 gflgs |= GLOB_APPEND; 364 } 365 while (*++vl); 366 vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ? 367 NULL : blk2short(globv.gl_pathv); 368 globfree(&globv); 369 return (vl); 370 } 371 372 Char * 373 globone(str, action) 374 Char *str; 375 int action; 376 { 377 Char *v[2], **vl, **vo; 378 int gflg; 379 380 noglob = adrof(STRnoglob) != 0; 381 gflag = 0; 382 v[0] = str; 383 v[1] = 0; 384 tglob(v); 385 gflg = gflag; 386 if (gflg == G_NONE) 387 return (strip(Strsave(str))); 388 389 if (gflg & G_CSH) { 390 /* 391 * Expand back-quote, tilde and brace 392 */ 393 vo = globexpand(v); 394 if (noglob || (gflg & G_GLOB) == 0) { 395 if (vo[0] == NULL) { 396 xfree((ptr_t) vo); 397 return (Strsave(STRNULL)); 398 } 399 if (vo[1] != NULL) 400 return (handleone(str, vo, action)); 401 else { 402 str = strip(vo[0]); 403 xfree((ptr_t) vo); 404 return (str); 405 } 406 } 407 } 408 else if (noglob || (gflg & G_GLOB) == 0) 409 return (strip(Strsave(str))); 410 else 411 vo = v; 412 413 vl = libglob(vo); 414 if ((gflg & G_CSH) && vl != vo) 415 blkfree(vo); 416 if (vl == NULL) { 417 setname(short2str(str)); 418 stderror(ERR_NAME | ERR_NOMATCH); 419 } 420 if (vl[0] == NULL) { 421 xfree((ptr_t) vl); 422 return (Strsave(STRNULL)); 423 } 424 if (vl[1] != NULL) 425 return (handleone(str, vl, action)); 426 else { 427 str = strip(*vl); 428 xfree((ptr_t) vl); 429 return (str); 430 } 431 } 432 433 Char ** 434 globall(v) 435 Char **v; 436 { 437 Char **vl, **vo; 438 int gflg = gflag; 439 440 if (!v || !v[0]) { 441 gargv = saveblk(v); 442 gargc = blklen(gargv); 443 return (gargv); 444 } 445 446 noglob = adrof(STRnoglob) != 0; 447 448 if (gflg & G_CSH) 449 /* 450 * Expand back-quote, tilde and brace 451 */ 452 vl = vo = globexpand(v); 453 else 454 vl = vo = saveblk(v); 455 456 if (!noglob && (gflg & G_GLOB)) { 457 vl = libglob(vo); 458 if ((gflg & G_CSH) && vl != vo) 459 blkfree(vo); 460 } 461 462 gargc = vl ? blklen(vl) : 0; 463 return (gargv = vl); 464 } 465 466 void 467 ginit() 468 { 469 gargsiz = GLOBSPACE; 470 gargv = (Char **) xmalloc((size_t) sizeof(Char *) * gargsiz); 471 gargv[0] = 0; 472 gargc = 0; 473 } 474 475 void 476 rscan(t, f) 477 register Char **t; 478 void (*f) (); 479 { 480 register Char *p; 481 482 while (p = *t++) 483 while (*p) 484 (*f) (*p++); 485 } 486 487 void 488 trim(t) 489 register Char **t; 490 { 491 register Char *p; 492 493 while (p = *t++) 494 while (*p) 495 *p++ &= TRIM; 496 } 497 498 void 499 tglob(t) 500 register Char **t; 501 { 502 register Char *p, c; 503 504 while (p = *t++) { 505 if (*p == '~' || *p == '=') 506 gflag |= G_CSH; 507 else if (*p == '{' && 508 (p[1] == '\0' || p[1] == '}' && p[2] == '\0')) 509 continue; 510 while (c = *p++) 511 if (isglob(c)) 512 gflag |= (c == '{' || c == '`') ? G_CSH : G_GLOB; 513 } 514 } 515 516 /* 517 * Command substitute cp. If literal, then this is a substitution from a 518 * << redirection, and so we should not crunch blanks and tabs, separating 519 * words only at newlines. 520 */ 521 Char ** 522 dobackp(cp, literal) 523 Char *cp; 524 bool literal; 525 { 526 register Char *lp, *rp; 527 Char *ep, word[MAXPATHLEN]; 528 529 if (pargv) { 530 abort(); 531 blkfree(pargv); 532 } 533 pargsiz = GLOBSPACE; 534 pargv = (Char **) xmalloc((size_t) sizeof(Char *) * pargsiz); 535 pargv[0] = NULL; 536 pargcp = pargs = word; 537 pargc = 0; 538 pnleft = MAXPATHLEN - 4; 539 for (;;) { 540 for (lp = cp; *lp != '`'; lp++) { 541 if (*lp == 0) { 542 if (pargcp != pargs) 543 pword(); 544 return (pargv); 545 } 546 psave(*lp); 547 } 548 lp++; 549 for (rp = lp; *rp && *rp != '`'; rp++) 550 if (*rp == '\\') { 551 rp++; 552 if (!*rp) 553 goto oops; 554 } 555 if (!*rp) 556 oops: stderror(ERR_UNMATCHED, '`'); 557 ep = Strsave(lp); 558 ep[rp - lp] = 0; 559 backeval(ep, literal); 560 cp = rp + 1; 561 } 562 } 563 564 static void 565 backeval(cp, literal) 566 Char *cp; 567 bool literal; 568 { 569 register int icnt, c; 570 register Char *ip; 571 struct command faket; 572 bool hadnl; 573 int pvec[2], quoted; 574 Char *fakecom[2], ibuf[BUFSIZ]; 575 char tibuf[BUFSIZ]; 576 577 hadnl = 0; 578 icnt = 0; 579 quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; 580 faket.t_dtyp = NODE_COMMAND; 581 faket.t_dflg = 0; 582 faket.t_dlef = 0; 583 faket.t_drit = 0; 584 faket.t_dspr = 0; 585 faket.t_dcom = fakecom; 586 fakecom[0] = STRfakecom1; 587 fakecom[1] = 0; 588 589 /* 590 * We do the psave job to temporarily change the current job so that the 591 * following fork is considered a separate job. This is so that when 592 * backquotes are used in a builtin function that calls glob the "current 593 * job" is not corrupted. We only need one level of pushed jobs as long as 594 * we are sure to fork here. 595 */ 596 psavejob(); 597 598 /* 599 * It would be nicer if we could integrate this redirection more with the 600 * routines in sh.sem.c by doing a fake execute on a builtin function that 601 * was piped out. 602 */ 603 mypipe(pvec); 604 if (pfork(&faket, -1) == 0) { 605 struct wordent paraml; 606 struct command *t; 607 608 (void) close(pvec[0]); 609 (void) dmove(pvec[1], 1); 610 (void) dmove(SHERR, 2); 611 initdesc(); 612 /* 613 * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>, 614 * posted to comp.bugs.4bsd 12 Sep. 1989. 615 */ 616 if (pargv) /* mg, 21.dec.88 */ 617 blkfree(pargv), pargv = 0, pargsiz = 0; 618 /* mg, 21.dec.88 */ 619 arginp = cp; 620 while (*cp) 621 *cp++ &= TRIM; 622 (void) lex(¶ml); 623 if (seterr) 624 stderror(ERR_OLD); 625 alias(¶ml); 626 t = syntax(paraml.next, ¶ml, 0); 627 if (seterr) 628 stderror(ERR_OLD); 629 if (t) 630 t->t_dflg |= F_NOFORK; 631 (void) signal(SIGTSTP, SIG_IGN); 632 (void) signal(SIGTTIN, SIG_IGN); 633 (void) signal(SIGTTOU, SIG_IGN); 634 execute(t, -1, NULL, NULL); 635 exitstat(); 636 } 637 xfree((ptr_t) cp); 638 (void) close(pvec[1]); 639 c = 0; 640 ip = NULL; 641 do { 642 int cnt = 0; 643 644 for (;;) { 645 if (icnt == 0) { 646 int i; 647 648 ip = ibuf; 649 do 650 icnt = read(pvec[0], tibuf, BUFSIZ); 651 while (icnt == -1 && errno == EINTR); 652 if (icnt <= 0) { 653 c = -1; 654 break; 655 } 656 for (i = 0; i < icnt; i++) 657 ip[i] = (unsigned char) tibuf[i]; 658 } 659 if (hadnl) 660 break; 661 --icnt; 662 c = (*ip++ & TRIM); 663 if (c == 0) 664 break; 665 if (c == '\n') { 666 /* 667 * Continue around the loop one more time, so that we can eat 668 * the last newline without terminating this word. 669 */ 670 hadnl = 1; 671 continue; 672 } 673 if (!quoted && (c == ' ' || c == '\t')) 674 break; 675 cnt++; 676 psave(c | quoted); 677 } 678 /* 679 * Unless at end-of-file, we will form a new word here if there were 680 * characters in the word, or in any case when we take text literally. 681 * If we didn't make empty words here when literal was set then we 682 * would lose blank lines. 683 */ 684 if (c != -1 && (cnt || literal)) 685 pword(); 686 hadnl = 0; 687 } while (c >= 0); 688 (void) close(pvec[0]); 689 pwait(); 690 prestjob(); 691 } 692 693 static void 694 psave(c) 695 int c; 696 { 697 if (--pnleft <= 0) 698 stderror(ERR_WTOOLONG); 699 *pargcp++ = c; 700 } 701 702 static void 703 pword() 704 { 705 psave(0); 706 if (pargc == pargsiz - 1) { 707 pargsiz += GLOBSPACE; 708 pargv = (Char **) xrealloc((ptr_t) pargv, 709 (size_t) pargsiz * sizeof(Char *)); 710 } 711 pargv[pargc++] = Strsave(pargs); 712 pargv[pargc] = NULL; 713 pargcp = pargs; 714 pnleft = MAXPATHLEN - 4; 715 } 716 717 int 718 Gmatch(string, pattern) 719 register Char *string, *pattern; 720 { 721 register Char stringc, patternc; 722 int match; 723 Char rangec; 724 725 for (;; ++string) { 726 stringc = *string & TRIM; 727 patternc = *pattern++; 728 switch (patternc) { 729 case 0: 730 return (stringc == 0); 731 case '?': 732 if (stringc == 0) 733 return (0); 734 break; 735 case '*': 736 if (!*pattern) 737 return (1); 738 while (*string) 739 if (Gmatch(string++, pattern)) 740 return (1); 741 return (0); 742 case '[': 743 match = 0; 744 while (rangec = *pattern++) { 745 if (rangec == ']') 746 if (match) 747 break; 748 else 749 return (0); 750 if (match) 751 continue; 752 if (rangec == '-' && *(pattern - 2) != '[' && *pattern != ']') { 753 match = (stringc <= (*pattern & TRIM) && 754 (*(pattern - 2) & TRIM) <= stringc); 755 pattern++; 756 } 757 else 758 match = (stringc == rangec); 759 } 760 if (rangec == 0) 761 stderror(ERR_NAME | ERR_MISSING, ']'); 762 break; 763 default: 764 if ((patternc & TRIM) != stringc) 765 return (0); 766 break; 767 768 } 769 } 770 } 771 772 void 773 Gcat(s1, s2) 774 Char *s1, *s2; 775 { 776 register Char *p, *q; 777 int n; 778 779 for (p = s1; *p++;); 780 for (q = s2; *q++;); 781 n = (p - s1) + (q - s2) - 1; 782 if (++gargc >= gargsiz) { 783 gargsiz += GLOBSPACE; 784 gargv = (Char **) xrealloc((ptr_t) gargv, 785 (size_t) gargsiz * sizeof(Char *)); 786 } 787 gargv[gargc] = 0; 788 p = gargv[gargc - 1] = (Char *) xmalloc((size_t) n * sizeof(Char)); 789 for (q = s1; *p++ = *q++;); 790 for (p--, q = s2; *p++ = *q++;); 791 } 792 793 #ifdef FILEC 794 int 795 sortscmp(a, b) 796 register Char **a, **b; 797 { 798 #if defined(NLS) && !defined(NOSTRCOLL) 799 char buf[2048]; 800 801 #endif 802 803 if (!a) /* check for NULL */ 804 return (b ? 1 : 0); 805 if (!b) 806 return (-1); 807 808 if (!*a) /* check for NULL */ 809 return (*b ? 1 : 0); 810 if (!*b) 811 return (-1); 812 813 #if defined(NLS) && !defined(NOSTRCOLL) 814 (void) strcpy(buf, short2str(*a)); 815 return ((int) strcoll(buf, short2str(*b))); 816 #else 817 return ((int) Strcmp(*a, *b)); 818 #endif 819 } 820 #endif /* FILEC */ 821