1 #ifndef lint 2 static char *sccsid = "@(#)glob.c 4.9 (Berkeley) 02/28/85"; 3 #endif 4 5 #include "sh.h" 6 #include "sh.char.h" 7 #include <sys/dir.h> 8 9 /* 10 * C Shell 11 */ 12 13 int globcnt; 14 15 char *gpath, *gpathp, *lastgpathp; 16 int globbed; 17 bool noglob; 18 bool nonomatch; 19 char *entp; 20 char **sortbas; 21 22 char ** 23 glob(v) 24 register char **v; 25 { 26 char agpath[BUFSIZ]; 27 char *agargv[GAVSIZ]; 28 29 gpath = agpath; gpathp = gpath; *gpathp = 0; 30 lastgpathp = &gpath[sizeof agpath - 2]; 31 ginit(agargv); globcnt = 0; 32 #ifdef GDEBUG 33 printf("glob entered: "); blkpr(v); printf("\n"); 34 #endif 35 noglob = adrof("noglob") != 0; 36 nonomatch = adrof("nonomatch") != 0; 37 globcnt = noglob | nonomatch; 38 while (*v) 39 collect(*v++); 40 #ifdef GDEBUG 41 printf("glob done, globcnt=%d, gflag=%d: ", globcnt, gflag); blkpr(gargv); printf("\n"); 42 #endif 43 if (globcnt == 0 && (gflag&1)) { 44 blkfree(gargv), gargv = 0; 45 return (0); 46 } else 47 return (gargv = copyblk(gargv)); 48 } 49 50 ginit(agargv) 51 char **agargv; 52 { 53 54 agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0; 55 gnleft = NCARGS - 4; 56 } 57 58 collect(as) 59 register char *as; 60 { 61 register int i; 62 63 if (any('`', as)) { 64 #ifdef GDEBUG 65 printf("doing backp of %s\n", as); 66 #endif 67 (void) dobackp(as, 0); 68 #ifdef GDEBUG 69 printf("backp done, acollect'ing\n"); 70 #endif 71 for (i = 0; i < pargc; i++) 72 if (noglob) { 73 Gcat(pargv[i], ""); 74 sortbas = &gargv[gargc]; 75 } else 76 acollect(pargv[i]); 77 if (pargv) 78 blkfree(pargv), pargv = 0; 79 #ifdef GDEBUG 80 printf("acollect done\n"); 81 #endif 82 } else if (noglob || eq(as, "{") || eq(as, "{}")) { 83 Gcat(as, ""); 84 sort(); 85 } else 86 acollect(as); 87 } 88 89 acollect(as) 90 register char *as; 91 { 92 register int ogargc = gargc; 93 94 gpathp = gpath; *gpathp = 0; globbed = 0; 95 expand(as); 96 if (gargc == ogargc) { 97 if (nonomatch) { 98 Gcat(as, ""); 99 sort(); 100 } 101 } else 102 sort(); 103 } 104 105 sort() 106 { 107 register char **p1, **p2, *c; 108 char **Gvp = &gargv[gargc]; 109 110 p1 = sortbas; 111 while (p1 < Gvp-1) { 112 p2 = p1; 113 while (++p2 < Gvp) 114 if (strcmp(*p1, *p2) > 0) 115 c = *p1, *p1 = *p2, *p2 = c; 116 p1++; 117 } 118 sortbas = Gvp; 119 } 120 121 expand(as) 122 char *as; 123 { 124 register char *cs; 125 register char *sgpathp, *oldcs; 126 struct stat stb; 127 128 sgpathp = gpathp; 129 cs = as; 130 if (*cs == '~' && gpathp == gpath) { 131 addpath('~'); 132 for (cs++; letter(*cs) || digit(*cs) || *cs == '-';) 133 addpath(*cs++); 134 if (!*cs || *cs == '/') { 135 if (gpathp != gpath + 1) { 136 *gpathp = 0; 137 if (gethdir(gpath + 1)) 138 error("Unknown user: %s", gpath + 1); 139 (void) strcpy(gpath, gpath + 1); 140 } else 141 (void) strcpy(gpath, value("home")); 142 gpathp = strend(gpath); 143 } 144 } 145 while (!cmap(*cs, _GLOB)) { 146 if (*cs == 0) { 147 if (!globbed) 148 Gcat(gpath, ""); 149 else if (stat(gpath, &stb) >= 0) { 150 Gcat(gpath, ""); 151 globcnt++; 152 } 153 goto endit; 154 } 155 addpath(*cs++); 156 } 157 oldcs = cs; 158 while (cs > as && *cs != '/') 159 cs--, gpathp--; 160 if (*cs == '/') 161 cs++, gpathp++; 162 *gpathp = 0; 163 if (*oldcs == '{') { 164 (void) execbrc(cs, NOSTR); 165 return; 166 } 167 matchdir(cs); 168 endit: 169 gpathp = sgpathp; 170 *gpathp = 0; 171 } 172 173 matchdir(pattern) 174 char *pattern; 175 { 176 struct stat stb; 177 register struct direct *dp; 178 register DIR *dirp; 179 180 dirp = opendir(gpath); 181 if (dirp == NULL) { 182 if (globbed) 183 return; 184 goto patherr2; 185 } 186 if (fstat(dirp->dd_fd, &stb) < 0) 187 goto patherr1; 188 if (!isdir(stb)) { 189 errno = ENOTDIR; 190 goto patherr1; 191 } 192 while ((dp = readdir(dirp)) != NULL) { 193 if (dp->d_ino == 0) 194 continue; 195 if (match(dp->d_name, pattern)) { 196 Gcat(gpath, dp->d_name); 197 globcnt++; 198 } 199 } 200 closedir(dirp); 201 return; 202 203 patherr1: 204 closedir(dirp); 205 patherr2: 206 Perror(gpath); 207 } 208 209 execbrc(p, s) 210 char *p, *s; 211 { 212 char restbuf[BUFSIZ + 2]; 213 register char *pe, *pm, *pl; 214 int brclev = 0; 215 char *lm, savec, *sgpathp; 216 217 for (lm = restbuf; *p != '{'; *lm++ = *p++) 218 continue; 219 for (pe = ++p; *pe; pe++) 220 switch (*pe) { 221 222 case '{': 223 brclev++; 224 continue; 225 226 case '}': 227 if (brclev == 0) 228 goto pend; 229 brclev--; 230 continue; 231 232 case '[': 233 for (pe++; *pe && *pe != ']'; pe++) 234 continue; 235 if (!*pe) 236 error("Missing ]"); 237 continue; 238 } 239 pend: 240 if (brclev || !*pe) 241 error("Missing }"); 242 for (pl = pm = p; pm <= pe; pm++) 243 switch (*pm & (QUOTE|TRIM)) { 244 245 case '{': 246 brclev++; 247 continue; 248 249 case '}': 250 if (brclev) { 251 brclev--; 252 continue; 253 } 254 goto doit; 255 256 case ','|QUOTE: 257 case ',': 258 if (brclev) 259 continue; 260 doit: 261 savec = *pm; 262 *pm = 0; 263 (void) strcpy(lm, pl); 264 (void) strcat(restbuf, pe + 1); 265 *pm = savec; 266 if (s == 0) { 267 sgpathp = gpathp; 268 expand(restbuf); 269 gpathp = sgpathp; 270 *gpathp = 0; 271 } else if (amatch(s, restbuf)) 272 return (1); 273 sort(); 274 pl = pm + 1; 275 continue; 276 277 case '[': 278 for (pm++; *pm && *pm != ']'; pm++) 279 continue; 280 if (!*pm) 281 error("Missing ]"); 282 continue; 283 } 284 return (0); 285 } 286 287 match(s, p) 288 char *s, *p; 289 { 290 register int c; 291 register char *sentp; 292 char sglobbed = globbed; 293 294 if (*s == '.' && *p != '.') 295 return (0); 296 sentp = entp; 297 entp = s; 298 c = amatch(s, p); 299 entp = sentp; 300 globbed = sglobbed; 301 return (c); 302 } 303 304 amatch(s, p) 305 register char *s, *p; 306 { 307 register int scc; 308 int ok, lc; 309 char *sgpathp; 310 struct stat stb; 311 int c, cc; 312 313 globbed = 1; 314 for (;;) { 315 scc = *s++ & TRIM; 316 switch (c = *p++) { 317 318 case '{': 319 return (execbrc(p - 1, s - 1)); 320 321 case '[': 322 ok = 0; 323 lc = 077777; 324 while (cc = *p++) { 325 if (cc == ']') { 326 if (ok) 327 break; 328 return (0); 329 } 330 if (cc == '-') { 331 if (lc <= scc && scc <= *p++) 332 ok++; 333 } else 334 if (scc == (lc = cc)) 335 ok++; 336 } 337 if (cc == 0) 338 error("Missing ]"); 339 continue; 340 341 case '*': 342 if (!*p) 343 return (1); 344 if (*p == '/') { 345 p++; 346 goto slash; 347 } 348 for (s--; *s; s++) 349 if (amatch(s, p)) 350 return (1); 351 return (0); 352 353 case 0: 354 return (scc == 0); 355 356 default: 357 if ((c & TRIM) != scc) 358 return (0); 359 continue; 360 361 case '?': 362 if (scc == 0) 363 return (0); 364 continue; 365 366 case '/': 367 if (scc) 368 return (0); 369 slash: 370 s = entp; 371 sgpathp = gpathp; 372 while (*s) 373 addpath(*s++); 374 addpath('/'); 375 if (stat(gpath, &stb) == 0 && isdir(stb)) 376 if (*p == 0) { 377 Gcat(gpath, ""); 378 globcnt++; 379 } else 380 expand(p); 381 gpathp = sgpathp; 382 *gpathp = 0; 383 return (0); 384 } 385 } 386 } 387 388 Gmatch(s, p) 389 register char *s, *p; 390 { 391 register int scc; 392 int ok, lc; 393 int c, cc; 394 395 for (;;) { 396 scc = *s++ & TRIM; 397 switch (c = *p++) { 398 399 case '[': 400 ok = 0; 401 lc = 077777; 402 while (cc = *p++) { 403 if (cc == ']') { 404 if (ok) 405 break; 406 return (0); 407 } 408 if (cc == '-') { 409 if (lc <= scc && scc <= *p++) 410 ok++; 411 } else 412 if (scc == (lc = cc)) 413 ok++; 414 } 415 if (cc == 0) 416 bferr("Missing ]"); 417 continue; 418 419 case '*': 420 if (!*p) 421 return (1); 422 for (s--; *s; s++) 423 if (Gmatch(s, p)) 424 return (1); 425 return (0); 426 427 case 0: 428 return (scc == 0); 429 430 default: 431 if ((c & TRIM) != scc) 432 return (0); 433 continue; 434 435 case '?': 436 if (scc == 0) 437 return (0); 438 continue; 439 440 } 441 } 442 } 443 444 Gcat(s1, s2) 445 char *s1, *s2; 446 { 447 register char *p, *q; 448 int n; 449 450 for (p = s1; *p++;) 451 ; 452 for (q = s2; *q++;) 453 ; 454 gnleft -= (n = (p - s1) + (q - s2) - 1); 455 if (gnleft <= 0 || ++gargc >= GAVSIZ) 456 error("Arguments too long"); 457 gargv[gargc] = 0; 458 p = gargv[gargc - 1] = xalloc((unsigned)n); 459 for (q = s1; *p++ = *q++;) 460 ; 461 for (p--, q = s2; *p++ = *q++;) 462 ; 463 } 464 465 addpath(c) 466 char c; 467 { 468 469 if (gpathp >= lastgpathp) 470 error("Pathname too long"); 471 *gpathp++ = c & TRIM; 472 *gpathp = 0; 473 } 474 475 rscan(t, f) 476 register char **t; 477 int (*f)(); 478 { 479 register char *p; 480 481 while (p = *t++) 482 while (*p) 483 (*f)(*p++); 484 } 485 486 trim(t) 487 register char **t; 488 { 489 register char *p; 490 491 while (p = *t++) 492 while (*p) 493 *p++ &= TRIM; 494 } 495 496 tglob(t) 497 register char **t; 498 { 499 register char *p, c; 500 501 while (p = *t++) { 502 if (*p == '~') 503 gflag |= 2; 504 else if (*p == '{' && (p[1] == '\0' || p[1] == '}' && p[2] == '\0')) 505 continue; 506 while (c = *p++) 507 if (cmap(c, _GLOB)) 508 gflag |= c == '{' ? 2 : 1; 509 } 510 } 511 512 char * 513 globone(str) 514 register char *str; 515 { 516 char *gv[2]; 517 register char **gvp; 518 register char *cp; 519 520 gv[0] = str; 521 gv[1] = 0; 522 gflag = 0; 523 tglob(gv); 524 if (gflag) { 525 gvp = glob(gv); 526 if (gvp == 0) { 527 setname(str); 528 bferr("No match"); 529 } 530 cp = *gvp++; 531 if (cp == 0) 532 cp = ""; 533 else if (*gvp) { 534 setname(str); 535 bferr("Ambiguous"); 536 } else 537 cp = strip(cp); 538 /* 539 if (cp == 0 || *gvp) { 540 setname(str); 541 bferr(cp ? "Ambiguous" : "No output"); 542 } 543 */ 544 xfree((char *)gargv); gargv = 0; 545 } else { 546 trim(gv); 547 cp = savestr(gv[0]); 548 } 549 return (cp); 550 } 551 552 /* 553 * Command substitute cp. If literal, then this is 554 * a substitution from a << redirection, and so we should 555 * not crunch blanks and tabs, separating words only at newlines. 556 */ 557 char ** 558 dobackp(cp, literal) 559 char *cp; 560 bool literal; 561 { 562 register char *lp, *rp; 563 char *ep; 564 char word[BUFSIZ]; 565 char *apargv[GAVSIZ + 2]; 566 567 if (pargv) { 568 abort(); 569 blkfree(pargv); 570 } 571 pargv = apargv; 572 pargv[0] = NOSTR; 573 pargcp = pargs = word; 574 pargc = 0; 575 pnleft = BUFSIZ - 4; 576 for (;;) { 577 for (lp = cp; *lp != '`'; lp++) { 578 if (*lp == 0) { 579 if (pargcp != pargs) 580 pword(); 581 #ifdef GDEBUG 582 printf("leaving dobackp\n"); 583 #endif 584 return (pargv = copyblk(pargv)); 585 } 586 psave(*lp); 587 } 588 lp++; 589 for (rp = lp; *rp && *rp != '`'; rp++) 590 if (*rp == '\\') { 591 rp++; 592 if (!*rp) 593 goto oops; 594 } 595 if (!*rp) 596 oops: 597 error("Unmatched `"); 598 ep = savestr(lp); 599 ep[rp - lp] = 0; 600 backeval(ep, literal); 601 #ifdef GDEBUG 602 printf("back from backeval\n"); 603 #endif 604 cp = rp + 1; 605 } 606 } 607 608 backeval(cp, literal) 609 char *cp; 610 bool literal; 611 { 612 int pvec[2]; 613 int quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; 614 char ibuf[BUFSIZ]; 615 register int icnt = 0, c; 616 register char *ip; 617 bool hadnl = 0; 618 char *fakecom[2]; 619 struct command faket; 620 621 faket.t_dtyp = TCOM; 622 faket.t_dflg = 0; 623 faket.t_dlef = 0; 624 faket.t_drit = 0; 625 faket.t_dspr = 0; 626 faket.t_dcom = fakecom; 627 fakecom[0] = "` ... `"; 628 fakecom[1] = 0; 629 /* 630 * We do the psave job to temporarily change the current job 631 * so that the following fork is considered a separate job. 632 * This is so that when backquotes are used in a 633 * builtin function that calls glob the "current job" is not corrupted. 634 * We only need one level of pushed jobs as long as we are sure to 635 * fork here. 636 */ 637 psavejob(); 638 /* 639 * It would be nicer if we could integrate this redirection more 640 * with the routines in sh.sem.c by doing a fake execute on a builtin 641 * function that was piped out. 642 */ 643 mypipe(pvec); 644 if (pfork(&faket, -1) == 0) { 645 struct wordent paraml; 646 struct command *t; 647 648 (void) close(pvec[0]); 649 (void) dmove(pvec[1], 1); 650 (void) dmove(SHDIAG, 2); 651 initdesc(); 652 arginp = cp; 653 while (*cp) 654 *cp++ &= TRIM; 655 (void) lex(¶ml); 656 if (err) 657 error(err); 658 alias(¶ml); 659 t = syntax(paraml.next, ¶ml, 0); 660 if (err) 661 error(err); 662 if (t) 663 t->t_dflg |= FPAR; 664 (void) signal(SIGTSTP, SIG_IGN); 665 (void) signal(SIGTTIN, SIG_IGN); 666 (void) signal(SIGTTOU, SIG_IGN); 667 execute(t, -1); 668 exitstat(); 669 } 670 xfree(cp); 671 (void) close(pvec[1]); 672 do { 673 int cnt = 0; 674 for (;;) { 675 if (icnt == 0) { 676 ip = ibuf; 677 icnt = read(pvec[0], ip, BUFSIZ); 678 if (icnt <= 0) { 679 c = -1; 680 break; 681 } 682 } 683 if (hadnl) 684 break; 685 --icnt; 686 c = (*ip++ & TRIM); 687 if (c == 0) 688 break; 689 if (c == '\n') { 690 /* 691 * Continue around the loop one 692 * more time, so that we can eat 693 * the last newline without terminating 694 * this word. 695 */ 696 hadnl = 1; 697 continue; 698 } 699 if (!quoted && (c == ' ' || c == '\t')) 700 break; 701 cnt++; 702 psave(c | quoted); 703 } 704 /* 705 * Unless at end-of-file, we will form a new word 706 * here if there were characters in the word, or in 707 * any case when we take text literally. If 708 * we didn't make empty words here when literal was 709 * set then we would lose blank lines. 710 */ 711 if (c != -1 && (cnt || literal)) 712 pword(); 713 hadnl = 0; 714 } while (c >= 0); 715 #ifdef GDEBUG 716 printf("done in backeval, pvec: %d %d\n", pvec[0], pvec[1]); 717 printf("also c = %c <%o>\n", c, c); 718 #endif 719 (void) close(pvec[0]); 720 pwait(); 721 prestjob(); 722 } 723 724 psave(c) 725 char c; 726 { 727 728 if (--pnleft <= 0) 729 error("Word too long"); 730 *pargcp++ = c; 731 } 732 733 pword() 734 { 735 736 psave(0); 737 if (pargc == GAVSIZ) 738 error("Too many words from ``"); 739 pargv[pargc++] = savestr(pargs); 740 pargv[pargc] = NOSTR; 741 #ifdef GDEBUG 742 printf("got word %s\n", pargv[pargc-1]); 743 #endif 744 pargcp = pargs; 745 pnleft = BUFSIZ - 4; 746 } 747