xref: /titanic_44/usr/src/cmd/csh/sh.glob.c (revision b7f45089ccbe01bab3d7c7377b49d80d2ae18a69)
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(&paraml);
798 		HIST = oHIST;
799 		if (err)
800 			error("%s", gettext(err));
801 		alias(&paraml);
802 		t = syntax(paraml.next, &paraml, 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