1 /* 2 * Copyright 2001 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7 /* All Rights Reserved */ 8 9 /* 10 * Copyright (c) 1980 Regents of the University of California. 11 * All rights reserved. The Berkeley Software License Agreement 12 * specifies the terms and conditions for redistribution. 13 */ 14 15 #pragma ident "%Z%%M% %I% %E% SMI" 16 17 #include "sh.h" 18 #include "sh.tconst.h" 19 #include <dirent.h> 20 #ifdef MBCHAR 21 #include <widec.h> /* wcsetno() */ 22 #include <fnmatch.h> /* fnmatch() */ 23 #endif /* MBCHAR */ 24 25 /* 26 * C Shell 27 */ 28 29 int globcnt; 30 31 tchar *gpath, *gpathp, *lastgpathp; 32 int globbed; 33 bool noglob; 34 bool nonomatch; 35 tchar *entp; 36 tchar **sortbas; 37 int sortscmp(); 38 extern DIR *opendir_(); 39 40 #define sort() qsort((char *)sortbas, &gargv[gargc] - sortbas, \ 41 sizeof (*sortbas), (int (*)(const void *, \ 42 const void *)) sortscmp), sortbas = &gargv[gargc] 43 44 45 tchar ** 46 glob(v) 47 register tchar **v; 48 { 49 tchar agpath[BUFSIZ]; 50 tchar *agargv[GAVSIZ]; 51 52 gpath = agpath; gpathp = gpath; *gpathp = 0; 53 lastgpathp = &gpath[BUFSIZ - 2]; 54 ginit(agargv); globcnt = 0; 55 #ifdef TRACE 56 tprintf("TRACE- glob()\n"); 57 #endif 58 #ifdef GDEBUG 59 printf("glob entered: "); blkpr(v); printf("\n"); 60 #endif 61 noglob = adrof(S_noglob /* "noglob" */) != 0; 62 nonomatch = adrof(S_nonomatch /* "nonomatch" */) != 0; 63 globcnt = noglob | nonomatch; 64 while (*v) 65 collect(*v++); 66 #ifdef GDEBUG 67 printf("glob done, globcnt=%d, gflag=%d: ", globcnt, gflag); 68 blkpr(gargv); printf("\n"); 69 #endif 70 if (globcnt == 0 && (gflag&1)) { 71 blkfree(gargv), gargv = 0; 72 return (0); 73 } else 74 return (gargv = copyblk(gargv)); 75 } 76 77 ginit(agargv) 78 tchar **agargv; 79 { 80 81 agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0; 82 gnleft = NCARGS - 4; 83 } 84 85 collect(as) 86 register tchar *as; 87 { 88 register int i; 89 90 #ifdef TRACE 91 tprintf("TRACE- collect()\n"); 92 #endif 93 if (any('`', as)) { 94 #ifdef GDEBUG 95 printf("doing backp of %t\n", as); 96 #endif 97 (void) dobackp(as, 0); 98 #ifdef GDEBUG 99 printf("backp done, acollect'ing\n"); 100 #endif 101 /* 102 * dobackp has the side effect of messing with 103 * gflag, since it does more globbing, so check 104 * if the results is still globbable 105 */ 106 tglob(pargv); 107 108 for (i = 0; i < pargc; i++) 109 if (noglob) { 110 Gcat(pargv[i], S_ /* "" */); 111 sortbas = &gargv[gargc]; 112 } else 113 acollect(pargv[i]); 114 if (pargv) 115 blkfree(pargv), pargv = 0; 116 #ifdef GDEBUG 117 printf("acollect done\n"); 118 #endif 119 } else if (noglob || eq(as, S_LBRA /* "{" */) || 120 eq(as, S_BRABRA /* "{}" */)) { 121 Gcat(as, S_ /* "" */); 122 sort(); 123 } else 124 acollect(as); 125 } 126 127 acollect(as) 128 register tchar *as; 129 { 130 register long ogargc = gargc; 131 132 #ifdef TRACE 133 tprintf("TRACE- acollect()\n"); 134 #endif 135 gpathp = gpath; *gpathp = 0; globbed = 0; 136 expand(as); 137 if (gargc == ogargc) { 138 if (nonomatch) { 139 Gcat(as, S_ /* "" */); 140 sort(); 141 } 142 } else 143 sort(); 144 } 145 146 /* 147 * String compare for qsort. Also used by filec code in sh.file.c. 148 */ 149 sortscmp(a1, a2) 150 tchar **a1, **a2; 151 { 152 153 return (strcoll_(*a1, *a2)); 154 } 155 156 expand(as) 157 tchar *as; 158 { 159 register tchar *cs; 160 register tchar *sgpathp, *oldcs; 161 struct stat stb; 162 163 #ifdef TRACE 164 tprintf("TRACE- expand()\n"); 165 #endif 166 sgpathp = gpathp; 167 cs = as; 168 if (*cs == '~' && gpathp == gpath) { 169 addpath('~'); 170 for (cs++; alnum(*cs) || *cs == '-'; ) 171 addpath(*cs++); 172 if (!*cs || *cs == '/') { 173 if (gpathp != gpath + 1) { 174 *gpathp = 0; 175 if (gethdir(gpath + 1)) 176 /* 177 * modified from %s to %t 178 */ 179 error("Unknown user: %t", gpath + 1); 180 (void) strcpy_(gpath, gpath + 1); 181 } else 182 (void) strcpy_(gpath, 183 value(S_home /* "home" */)); 184 gpathp = strend(gpath); 185 } 186 } 187 while (!isglob(*cs)) { 188 if (*cs == 0) { 189 if (!globbed) 190 Gcat(gpath, S_ /* "" */); 191 else if (lstat_(gpath, &stb) >= 0) { 192 Gcat(gpath, S_ /* "" */); 193 globcnt++; 194 } 195 goto endit; 196 } 197 addpath(*cs++); 198 } 199 oldcs = cs; 200 while (cs > as && *cs != '/') 201 cs--, gpathp--; 202 if (*cs == '/') 203 cs++, gpathp++; 204 *gpathp = 0; 205 if (*oldcs == '{') { 206 (void) execbrc(cs, NOSTR); 207 return; 208 } 209 matchdir_(cs); 210 endit: 211 gpathp = sgpathp; 212 *gpathp = 0; 213 } 214 215 matchdir_(pattern) 216 tchar *pattern; 217 { 218 struct stat stb; 219 register struct dirent *dp; 220 register DIR *dirp; 221 tchar curdir_[MAXNAMLEN+1]; 222 int slproc = 0; 223 224 #ifdef TRACE 225 tprintf("TRACE- matchdir()\n"); 226 #endif 227 /* 228 * BSD's opendir would open "." if argument is NULL, but not S5 229 */ 230 231 if (*gpath == NULL) 232 dirp = opendir_(S_DOT /* "." */); 233 else 234 dirp = opendir_(gpath); 235 if (dirp == NULL) { 236 if (globbed) 237 return; 238 goto patherr2; 239 } 240 if (fstat(dirp->dd_fd, &stb) < 0) 241 goto patherr1; 242 if (!isdir(stb)) { 243 errno = ENOTDIR; 244 goto patherr1; 245 } 246 while ((dp = readdir(dirp)) != NULL) { 247 248 if (dp->d_ino == 0) 249 continue; 250 strtots(curdir_, dp->d_name); 251 slproc = 0; 252 if (match(curdir_, pattern, &slproc)) { 253 Gcat(gpath, curdir_); 254 globcnt++; 255 } 256 } 257 unsetfd(dirp->dd_fd); 258 closedir_(dirp); 259 return; 260 261 patherr1: 262 unsetfd(dirp->dd_fd); 263 closedir_(dirp); 264 patherr2: 265 Perror(gpath); 266 } 267 268 execbrc(p, s) 269 tchar *p, *s; 270 { 271 tchar restbuf[BUFSIZ + 2]; 272 register tchar *pe, *pm, *pl; 273 int brclev = 0; 274 tchar *lm, savec, *sgpathp; 275 int slproc = 0; 276 277 #ifdef TRACE 278 tprintf("TRACE- execbrc()\n"); 279 #endif 280 for (lm = restbuf; *p != '{'; *lm++ = *p++) 281 continue; 282 for (pe = ++p; *pe; pe++) 283 switch (*pe) { 284 285 case '{': 286 brclev++; 287 continue; 288 289 case '}': 290 if (brclev == 0) 291 goto pend; 292 brclev--; 293 continue; 294 295 case '[': 296 for (pe++; *pe && *pe != ']'; pe++) 297 continue; 298 if (!*pe) 299 error("Missing ]"); 300 continue; 301 } 302 pend: 303 if (brclev || !*pe) 304 error("Missing }"); 305 for (pl = pm = p; pm <= pe; pm++) 306 switch (*pm & (QUOTE|TRIM)) { 307 308 case '{': 309 brclev++; 310 continue; 311 312 case '}': 313 if (brclev) { 314 brclev--; 315 continue; 316 } 317 goto doit; 318 319 case ',': 320 if (brclev) 321 continue; 322 doit: 323 savec = *pm; 324 *pm = 0; 325 (void) strcpy_(lm, pl); 326 (void) strcat_(restbuf, pe + 1); 327 *pm = savec; 328 if (s == 0) { 329 sgpathp = gpathp; 330 expand(restbuf); 331 gpathp = sgpathp; 332 *gpathp = 0; 333 } else if (amatch(s, restbuf, &slproc)) 334 return (1); 335 sort(); 336 pl = pm + 1; 337 continue; 338 339 case '[': 340 for (pm++; *pm && *pm != ']'; pm++) 341 continue; 342 if (!*pm) 343 error("Missing ]"); 344 continue; 345 } 346 return (0); 347 } 348 349 match(s, p, slproc) 350 tchar *s, *p; 351 int *slproc; 352 { 353 register int c; 354 register tchar *sentp; 355 tchar sglobbed = globbed; 356 357 #ifdef TRACE 358 tprintf("TRACE- match()\n"); 359 #endif 360 if (*s == '.' && *p != '.') 361 return (0); 362 sentp = entp; 363 entp = s; 364 c = amatch(s, p, slproc); 365 entp = sentp; 366 globbed = sglobbed; 367 return (c); 368 } 369 370 amatch(s, p, slproc) 371 register tchar *s, *p; 372 int *slproc; 373 { 374 register int scc; 375 int ok, lc; 376 tchar *sgpathp; 377 struct stat stb; 378 int c, cc; 379 380 #ifdef TRACE 381 tprintf("TRACE- amatch()\n"); 382 #endif 383 globbed = 1; 384 for (;;) { 385 scc = *s++ & TRIM; 386 switch (c = *p++) { 387 388 case '{': 389 return (execbrc(p - 1, s - 1)); 390 391 case '[': 392 ok = 0; 393 lc = TRIM; 394 while (cc = *p++) { 395 if (cc == ']') { 396 if (ok) 397 break; 398 return (0); 399 } 400 if (cc == '-') { 401 #ifdef MBCHAR 402 wchar_t rc = *p++; 403 if (rc == ']') { 404 p--; 405 continue; 406 } 407 /* 408 * Both ends of the char range 409 * must belong to the same codeset. 410 */ 411 if (sh_bracket_exp(scc, lc, rc)) 412 ok++; 413 #else /* !MBCHAR */ 414 if (lc <= scc && scc <= (int) *p++) 415 ok++; 416 #endif /* !MBCHAR */ 417 } else 418 if (scc == (lc = cc)) 419 ok++; 420 } 421 if (cc == 0) 422 error("Missing ]"); 423 continue; 424 425 case '*': 426 if (!*p) 427 return (1); 428 if (*p == '/') { 429 p++; 430 goto slash; 431 } else if (*p == '*') { 432 s--; 433 continue; 434 } 435 436 for (s--; *s; s++) 437 if (amatch(s, p, slproc)) 438 return (1); 439 440 return (0); 441 442 case 0: 443 return (scc == 0); 444 445 default: 446 if ((c & TRIM) != scc) 447 return (0); 448 continue; 449 450 case '?': 451 if (scc == 0) 452 return (0); 453 continue; 454 455 case '/': 456 if (scc) 457 return (0); 458 slash: 459 if (*slproc) /* Need to expand "/" only once */ 460 return (0); 461 else 462 *slproc = 1; 463 464 s = entp; 465 sgpathp = gpathp; 466 while (*s) 467 addpath(*s++); 468 addpath('/'); 469 if (stat_(gpath, &stb) == 0 && isdir(stb)) 470 if (*p == 0) { 471 Gcat(gpath, S_ /* "" */); 472 globcnt++; 473 } else 474 expand(p); 475 gpathp = sgpathp; 476 *gpathp = 0; 477 return (0); 478 } 479 } 480 } 481 482 Gmatch(s, p) 483 register tchar *s, *p; 484 { 485 register int scc; 486 int ok, lc; 487 int c, cc; 488 489 #ifdef TRACE 490 tprintf("TRACE- Gmatch()\n"); 491 #endif 492 for (;;) { 493 scc = *s++ & TRIM; 494 switch (c = *p++) { 495 496 case '[': 497 ok = 0; 498 lc = TRIM; 499 while (cc = *p++) { 500 if (cc == ']') { 501 if (ok) 502 break; 503 return (0); 504 } 505 if (cc == '-') { 506 #ifdef MBCHAR 507 wchar_t rc = *p++; 508 /* 509 * Both ends of the char range 510 * must belong to the same codeset... 511 */ 512 if (sh_bracket_exp(scc, lc, rc)) 513 ok++; 514 #else /* !MBCHAR */ 515 if (lc <= scc && scc <= (int) *p++) 516 ok++; 517 #endif /* !MBCHAR */ 518 } else 519 if (scc == (lc = cc)) 520 ok++; 521 } 522 if (cc == 0) 523 bferr("Missing ]"); 524 continue; 525 526 case '*': 527 if (!*p) 528 return (1); 529 for (s--; *s; s++) 530 if (Gmatch(s, p)) 531 return (1); 532 return (0); 533 534 case 0: 535 return (scc == 0); 536 537 default: 538 if ((c & TRIM) != scc) 539 return (0); 540 continue; 541 542 case '?': 543 if (scc == 0) 544 return (0); 545 continue; 546 547 } 548 } 549 } 550 551 Gcat(s1, s2) 552 tchar *s1, *s2; 553 { 554 register tchar *p, *q; 555 int n; 556 557 #ifdef TRACE 558 tprintf("TRACE- Gcat()\n"); 559 #endif 560 for (p = s1; *p++; ) 561 ; 562 for (q = s2; *q++; ) 563 ; 564 gnleft -= (n = (p - s1) + (q - s2) - 1); 565 if (gnleft <= 0 || ++gargc >= GAVSIZ) 566 error("Arguments too long"); 567 gargv[gargc] = 0; 568 p = gargv[gargc - 1] = (tchar *) xalloc((unsigned)n*sizeof (tchar)); 569 570 for (q = s1; *p++ = *q++; ) 571 ; 572 for (p--, q = s2; *p++ = *q++; ) 573 ; 574 } 575 576 addpath(c) 577 tchar c; 578 { 579 580 #ifdef TRACE 581 tprintf("TRACE- addpath()\n"); 582 #endif 583 if (gpathp >= lastgpathp) 584 error("Pathname too long"); 585 *gpathp++ = c & TRIM; 586 *gpathp = 0; 587 } 588 589 rscan(t, f) 590 register tchar **t; 591 int (*f)(); 592 { 593 register tchar *p; 594 595 #ifdef TRACE 596 tprintf("TRACE- rscan()\n"); 597 #endif 598 while (p = *t++) 599 while (*p) 600 (*f)(*p++); 601 } 602 603 trim(t) 604 register tchar **t; 605 { 606 register tchar *p; 607 608 #ifdef TRACE 609 tprintf("TRACE- trim()\n"); 610 #endif 611 while (p = *t++) 612 while (*p) 613 *p++ &= TRIM; 614 } 615 616 tglob(t) 617 register tchar **t; 618 { 619 register tchar *p, c; 620 621 #ifdef TRACE 622 tprintf("TRACE- tglob()\n"); 623 #endif 624 while (p = *t++) { 625 if (*p == '~') 626 gflag |= 2; 627 else if (*p == '{' && (p[1] == '\0' || 628 p[1] == '}' && p[2] == '\0')) 629 continue; 630 while (c = *p++) 631 if (isglob(c)) 632 gflag |= c == '{' ? 2 : 1; 633 } 634 } 635 636 tchar * 637 globone(str) 638 register tchar *str; 639 { 640 tchar *gv[2]; 641 register tchar **gvp; 642 register tchar *cp; 643 644 #ifdef TRACE 645 tprintf("TRACE- globone()\n"); 646 #endif 647 gv[0] = str; 648 gv[1] = 0; 649 gflag = 0; 650 tglob(gv); 651 if (gflag) { 652 gvp = glob(gv); 653 if (gvp == 0) { 654 setname(str); 655 bferr("No match"); 656 } 657 cp = *gvp++; 658 if (cp == 0) 659 cp = S_ /* "" */; 660 else if (*gvp) { 661 setname(str); 662 bferr("Ambiguous"); 663 } else 664 cp = strip(cp); 665 /* 666 if (cp == 0 || *gvp) { 667 setname(str); 668 bferr(cp ? "Ambiguous" : "No output"); 669 } 670 */ 671 xfree((char *)gargv); gargv = 0; 672 } else { 673 trim(gv); 674 cp = savestr(gv[0]); 675 } 676 return (cp); 677 } 678 679 /* 680 * Command substitute cp. If literal, then this is 681 * a substitution from a << redirection, and so we should 682 * not crunch blanks and tabs, separating words only at newlines. 683 */ 684 tchar ** 685 dobackp(cp, literal) 686 tchar *cp; 687 bool literal; 688 { 689 register tchar *lp, *rp; 690 tchar *ep; 691 tchar word[BUFSIZ]; 692 tchar *apargv[GAVSIZ + 2]; 693 694 #ifdef TRACE 695 tprintf("TRACE- dobackp()\n"); 696 #endif 697 if (pargv) { 698 blkfree(pargv); 699 } 700 pargv = apargv; 701 pargv[0] = NOSTR; 702 pargcp = pargs = word; 703 pargc = 0; 704 pnleft = BUFSIZ - 4; 705 for (;;) { 706 for (lp = cp; *lp != '`'; lp++) { 707 if (*lp == 0) { 708 if (pargcp != pargs) 709 pword(); 710 #ifdef GDEBUG 711 printf("leaving dobackp\n"); 712 #endif 713 return (pargv = copyblk(pargv)); 714 } 715 psave(*lp); 716 } 717 lp++; 718 for (rp = lp; *rp && *rp != '`'; rp++) 719 if (*rp == '\\') { 720 rp++; 721 if (!*rp) 722 goto oops; 723 } 724 if (!*rp) 725 oops: 726 error("Unmatched `"); 727 ep = savestr(lp); 728 ep[rp - lp] = 0; 729 backeval(ep, literal); 730 #ifdef GDEBUG 731 printf("back from backeval\n"); 732 #endif 733 cp = rp + 1; 734 } 735 } 736 737 backeval(cp, literal) 738 tchar *cp; 739 bool literal; 740 { 741 int pvec[2]; 742 int quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; 743 tchar ibuf[BUFSIZ]; 744 register int icnt = 0, c; 745 register tchar *ip; 746 bool hadnl = 0; 747 tchar *fakecom[2]; 748 struct command faket; 749 750 #ifdef TRACE 751 tprintf("TRACE- backeval()\n"); 752 #endif 753 faket.t_dtyp = TCOM; 754 faket.t_dflg = 0; 755 faket.t_dlef = 0; 756 faket.t_drit = 0; 757 faket.t_dspr = 0; 758 faket.t_dcom = fakecom; 759 fakecom[0] = S_QPPPQ; /* "` ... `" */; 760 fakecom[1] = 0; 761 /* 762 * We do the psave job to temporarily change the current job 763 * so that the following fork is considered a separate job. 764 * This is so that when backquotes are used in a 765 * builtin function that calls glob the "current job" is not corrupted. 766 * We only need one level of pushed jobs as long as we are sure to 767 * fork here. 768 */ 769 psavejob(); 770 /* 771 * It would be nicer if we could integrate this redirection more 772 * with the routines in sh.sem.c by doing a fake execute on a builtin 773 * function that was piped out. 774 */ 775 mypipe(pvec); 776 if (pfork(&faket, -1) == 0) { 777 struct wordent paraml; 778 struct command *t; 779 tchar oHIST; 780 781 new_process(); 782 (void) close(pvec[0]); 783 unsetfd(pvec[0]); 784 (void) dmove(pvec[1], 1); 785 (void) dmove(SHDIAG, 2); 786 reinitdesc(0, NULL); 787 arginp = cp; 788 while (*cp) 789 *cp++ &= TRIM; 790 /* 791 * disable history subsitution in sub-shell 792 * of `` evaluation prevents possible 793 * infinite recursion of `` evaluation 794 */ 795 oHIST = HIST; 796 HIST = 0; 797 (void) lex(¶ml); 798 HIST = oHIST; 799 if (err) 800 error("%s", gettext(err)); 801 alias(¶ml); 802 t = syntax(paraml.next, ¶ml, 0); 803 if (err) 804 error("%s", gettext(err)); 805 if (t) 806 t->t_dflg |= FPAR; 807 (void) signal(SIGTSTP, SIG_IGN); 808 (void) signal(SIGTTIN, SIG_IGN); 809 (void) signal(SIGTTOU, SIG_IGN); 810 execute(t, -1); 811 exitstat(); 812 } 813 xfree(cp); 814 (void) close(pvec[1]); 815 unsetfd(pvec[1]); 816 do { 817 int cnt = 0; 818 for (;;) { 819 if (icnt == 0) { 820 ip = ibuf; 821 icnt = read_(pvec[0], ip, BUFSIZ); 822 if (icnt <= 0) { 823 c = -1; 824 break; 825 } 826 } 827 if (hadnl) 828 break; 829 --icnt; 830 c = (*ip++ & TRIM); 831 if (c == 0) 832 break; 833 if (c == '\n') { 834 /* 835 * Continue around the loop one 836 * more time, so that we can eat 837 * the last newline without terminating 838 * this word. 839 */ 840 hadnl = 1; 841 continue; 842 } 843 if (!quoted && issp(c)) 844 break; 845 cnt++; 846 psave(c | quoted); 847 } 848 /* 849 * Unless at end-of-file, we will form a new word 850 * here if there were characters in the word, or in 851 * any case when we take text literally. If 852 * we didn't make empty words here when literal was 853 * set then we would lose blank lines. 854 */ 855 if (c != -1 && (cnt || literal)) { 856 if (pargc == GAVSIZ) 857 break; 858 pword(); 859 } 860 hadnl = 0; 861 } while (c >= 0); 862 #ifdef GDEBUG 863 printf("done in backeval, pvec: %d %d\n", pvec[0], pvec[1]); 864 printf("also c = %c <%o>\n", (tchar) c, (tchar) c); 865 #endif 866 (void) close(pvec[0]); 867 unsetfd(pvec[0]); 868 pwait(); 869 prestjob(); 870 } 871 872 psave(c) 873 tchar c; 874 { 875 #ifdef TRACE 876 tprintf("TRACE- psave()\n"); 877 #endif 878 879 if (--pnleft <= 0) 880 error("Word too long"); 881 *pargcp++ = c; 882 } 883 884 pword() 885 { 886 #ifdef TRACE 887 tprintf("TRACE- pword()\n"); 888 #endif 889 890 psave(0); 891 if (pargc == GAVSIZ) 892 error("Too many words from ``"); 893 pargv[pargc++] = savestr(pargs); 894 pargv[pargc] = NOSTR; 895 #ifdef GDEBUG 896 printf("got word %t\n", pargv[pargc-1]); 897 #endif 898 pargcp = pargs; 899 pnleft = BUFSIZ - 4; 900 } 901 902 903 904 /* 905 * returns pathname of the form dir/file; 906 * dir is a null-terminated string; 907 */ 908 char * 909 makename(dir, file) 910 char *dir; 911 char *file; 912 { 913 /* 914 * Maximum length of a 915 * file/dir name in ls-command; 916 * dfile is static as this is returned 917 * by makename(); 918 */ 919 static char dfile[MAXNAMLEN]; 920 921 register char *dp, *fp; 922 923 dp = dfile; 924 fp = dir; 925 while (*fp) 926 *dp++ = *fp++; 927 if (dp > dfile && *(dp - 1) != '/') 928 *dp++ = '/'; 929 fp = file; 930 while (*fp) 931 *dp++ = *fp++; 932 *dp = '\0'; 933 /* 934 * dfile points to the absolute pathname. We are 935 * only interested in the last component. 936 */ 937 return (rindex(dfile, '/') + 1); 938 } 939 940 sh_bracket_exp(t_ch, t_fch, t_lch) 941 tchar t_ch; 942 tchar t_fch; 943 tchar t_lch; 944 { 945 char t_char[MB_LEN_MAX + 1]; 946 char t_patan[MB_LEN_MAX * 2 + 8]; 947 char *p; 948 int i; 949 950 if ((t_ch == t_fch) || (t_ch == t_lch)) 951 return(1); 952 953 p = t_patan; 954 if ((i = wctomb(t_char, (wchar_t)t_ch)) <= 0) 955 return(0); 956 t_char[i] = 0; 957 958 *p++ = '['; 959 if ((i = wctomb(p, (wchar_t)t_fch)) <= 0) 960 return(0); 961 p += i; 962 *p++ = '-'; 963 if ((i = wctomb(p, (wchar_t)t_lch)) <= 0) 964 return(0); 965 p += i; 966 *p++ = ']'; 967 *p = 0; 968 969 if (fnmatch(t_patan, t_char, FNM_NOESCAPE)) 970 return(0); 971 return(1); 972 } 973