xref: /illumos-gate/usr/src/cmd/csh/sh.glob.c (revision 1b863af9bc9a5c76ed773e129889fc19dbf9e41c)
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 **
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
94 ginit(tchar **agargv)
95 {
96 
97 	agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
98 	gnleft = NCARGS - 4;
99 }
100 
101 void
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
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
166 sortscmp(tchar **a1, tchar **a2)
167 {
168 
169 	return (strcoll_(*a1, *a2));
170 }
171 
172 void
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
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
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
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
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
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
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
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
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
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
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 *
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 **
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
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(&paraml);
807 		HIST = oHIST;
808 		if (err_msg)
809 			error("%s", gettext(err_msg));
810 		alias(&paraml);
811 		t = syntax(paraml.next, &paraml, 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
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
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 *
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
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