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