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