xref: /titanic_52/usr/src/cmd/csh/sh.glob.c (revision 65b0c20e9bbaf87a200ce20a4decf18585e61a25)
17c478bd9Sstevel@tonic-gate /*
26c02b4a4Smuffin  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
77c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
87c478bd9Sstevel@tonic-gate 
97c478bd9Sstevel@tonic-gate /*
107c478bd9Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
117c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley Software License Agreement
127c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
137c478bd9Sstevel@tonic-gate  */
147c478bd9Sstevel@tonic-gate 
157c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
167c478bd9Sstevel@tonic-gate 
177c478bd9Sstevel@tonic-gate #include "sh.h"
187c478bd9Sstevel@tonic-gate #include "sh.tconst.h"
197c478bd9Sstevel@tonic-gate #include <dirent.h>
206c02b4a4Smuffin #include <strings.h>
217c478bd9Sstevel@tonic-gate #ifdef MBCHAR
227c478bd9Sstevel@tonic-gate #include <widec.h>	/* wcsetno() */
237c478bd9Sstevel@tonic-gate #include <fnmatch.h>	/* fnmatch() */
247c478bd9Sstevel@tonic-gate #endif /* MBCHAR */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * C Shell
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate int	globcnt;
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate tchar	*gpath, *gpathp, *lastgpathp;
337c478bd9Sstevel@tonic-gate int	globbed;
347c478bd9Sstevel@tonic-gate bool	noglob;
357c478bd9Sstevel@tonic-gate bool	nonomatch;
367c478bd9Sstevel@tonic-gate tchar	*entp;
377c478bd9Sstevel@tonic-gate tchar	**sortbas;
386c02b4a4Smuffin int	sortscmp(tchar **, tchar **);
396c02b4a4Smuffin void	ginit(tchar **);
406c02b4a4Smuffin void	collect(tchar *);
416c02b4a4Smuffin void	acollect(tchar *);
426c02b4a4Smuffin void	expand(tchar *);
436c02b4a4Smuffin void	matchdir_(tchar *);
446c02b4a4Smuffin void	Gcat(tchar *, tchar *);
456c02b4a4Smuffin void	addpath(tchar);
466c02b4a4Smuffin void	tglob(tchar **);
476c02b4a4Smuffin tchar	**dobackp(tchar *, bool);
486c02b4a4Smuffin void	backeval(tchar *, bool);
496c02b4a4Smuffin void	psave(tchar);
506c02b4a4Smuffin void	pword(void);
516c02b4a4Smuffin 
526c02b4a4Smuffin extern	DIR *opendir_(tchar *);
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #define	sort()	qsort((char *)sortbas, &gargv[gargc] - sortbas, \
557c478bd9Sstevel@tonic-gate 			sizeof (*sortbas), (int (*)(const void *, \
567c478bd9Sstevel@tonic-gate 			const void *)) sortscmp), sortbas = &gargv[gargc]
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate tchar **
606c02b4a4Smuffin glob(tchar **v)
617c478bd9Sstevel@tonic-gate {
627c478bd9Sstevel@tonic-gate 	tchar agpath[BUFSIZ];
637c478bd9Sstevel@tonic-gate 	tchar *agargv[GAVSIZ];
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate 	gpath = agpath; gpathp = gpath; *gpathp = 0;
667c478bd9Sstevel@tonic-gate 	lastgpathp = &gpath[BUFSIZ - 2];
677c478bd9Sstevel@tonic-gate 	ginit(agargv); globcnt = 0;
687c478bd9Sstevel@tonic-gate #ifdef TRACE
697c478bd9Sstevel@tonic-gate 	tprintf("TRACE- glob()\n");
707c478bd9Sstevel@tonic-gate #endif
717c478bd9Sstevel@tonic-gate #ifdef GDEBUG
727c478bd9Sstevel@tonic-gate 	printf("glob entered: "); blkpr(v); printf("\n");
737c478bd9Sstevel@tonic-gate #endif
747c478bd9Sstevel@tonic-gate 	noglob = adrof(S_noglob /* "noglob" */) != 0;
757c478bd9Sstevel@tonic-gate 	nonomatch = adrof(S_nonomatch /* "nonomatch" */) != 0;
767c478bd9Sstevel@tonic-gate 	globcnt = noglob | nonomatch;
777c478bd9Sstevel@tonic-gate 	while (*v)
787c478bd9Sstevel@tonic-gate 		collect(*v++);
797c478bd9Sstevel@tonic-gate #ifdef GDEBUG
807c478bd9Sstevel@tonic-gate 	printf("glob done, globcnt=%d, gflag=%d: ", globcnt, gflag);
817c478bd9Sstevel@tonic-gate 	blkpr(gargv); printf("\n");
827c478bd9Sstevel@tonic-gate #endif
837c478bd9Sstevel@tonic-gate 	if (globcnt == 0 && (gflag&1)) {
847c478bd9Sstevel@tonic-gate 		blkfree(gargv), gargv = 0;
857c478bd9Sstevel@tonic-gate 		return (0);
867c478bd9Sstevel@tonic-gate 	} else
877c478bd9Sstevel@tonic-gate 		return (gargv = copyblk(gargv));
887c478bd9Sstevel@tonic-gate }
897c478bd9Sstevel@tonic-gate 
906c02b4a4Smuffin void
916c02b4a4Smuffin ginit(tchar **agargv)
927c478bd9Sstevel@tonic-gate {
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
957c478bd9Sstevel@tonic-gate 	gnleft = NCARGS - 4;
967c478bd9Sstevel@tonic-gate }
977c478bd9Sstevel@tonic-gate 
986c02b4a4Smuffin void
996c02b4a4Smuffin collect(tchar *as)
1007c478bd9Sstevel@tonic-gate {
1016c02b4a4Smuffin 	int i;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate #ifdef TRACE
1047c478bd9Sstevel@tonic-gate 	tprintf("TRACE- collect()\n");
1057c478bd9Sstevel@tonic-gate #endif
1067c478bd9Sstevel@tonic-gate 	if (any('`', as)) {
1077c478bd9Sstevel@tonic-gate #ifdef GDEBUG
1087c478bd9Sstevel@tonic-gate 		printf("doing backp of %t\n", as);
1097c478bd9Sstevel@tonic-gate #endif
1107c478bd9Sstevel@tonic-gate 		(void) dobackp(as, 0);
1117c478bd9Sstevel@tonic-gate #ifdef GDEBUG
1127c478bd9Sstevel@tonic-gate 		printf("backp done, acollect'ing\n");
1137c478bd9Sstevel@tonic-gate #endif
1147c478bd9Sstevel@tonic-gate 		/*
1157c478bd9Sstevel@tonic-gate 		 * dobackp has the side effect of messing with
1167c478bd9Sstevel@tonic-gate 		 * gflag, since it does more globbing, so check
1177c478bd9Sstevel@tonic-gate 		 * if the results is still globbable
1187c478bd9Sstevel@tonic-gate 		 */
1197c478bd9Sstevel@tonic-gate 		tglob(pargv);
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 		for (i = 0; i < pargc; i++)
1227c478bd9Sstevel@tonic-gate 			if (noglob) {
1237c478bd9Sstevel@tonic-gate 				Gcat(pargv[i], S_ /* "" */);
1247c478bd9Sstevel@tonic-gate 				sortbas = &gargv[gargc];
1257c478bd9Sstevel@tonic-gate 			} else
1267c478bd9Sstevel@tonic-gate 				acollect(pargv[i]);
1277c478bd9Sstevel@tonic-gate 		if (pargv)
1287c478bd9Sstevel@tonic-gate 			blkfree(pargv), pargv = 0;
1297c478bd9Sstevel@tonic-gate #ifdef GDEBUG
1307c478bd9Sstevel@tonic-gate 		printf("acollect done\n");
1317c478bd9Sstevel@tonic-gate #endif
1327c478bd9Sstevel@tonic-gate 	} else if (noglob || eq(as, S_LBRA /* "{" */) ||
1337c478bd9Sstevel@tonic-gate 			eq(as, S_BRABRA /* "{}" */)) {
1347c478bd9Sstevel@tonic-gate 		Gcat(as, S_ /* "" */);
1357c478bd9Sstevel@tonic-gate 		sort();
1367c478bd9Sstevel@tonic-gate 	} else
1377c478bd9Sstevel@tonic-gate 		acollect(as);
1387c478bd9Sstevel@tonic-gate }
1397c478bd9Sstevel@tonic-gate 
1406c02b4a4Smuffin void
1416c02b4a4Smuffin acollect(tchar *as)
1427c478bd9Sstevel@tonic-gate {
1436c02b4a4Smuffin 	long ogargc = gargc;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate #ifdef TRACE
1467c478bd9Sstevel@tonic-gate 	tprintf("TRACE- acollect()\n");
1477c478bd9Sstevel@tonic-gate #endif
1487c478bd9Sstevel@tonic-gate 	gpathp = gpath; *gpathp = 0; globbed = 0;
1497c478bd9Sstevel@tonic-gate 	expand(as);
1507c478bd9Sstevel@tonic-gate 	if (gargc == ogargc) {
1517c478bd9Sstevel@tonic-gate 		if (nonomatch) {
1527c478bd9Sstevel@tonic-gate 			Gcat(as, S_ /* "" */);
1537c478bd9Sstevel@tonic-gate 			sort();
1547c478bd9Sstevel@tonic-gate 		}
1557c478bd9Sstevel@tonic-gate 	} else
1567c478bd9Sstevel@tonic-gate 		sort();
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate /*
1607c478bd9Sstevel@tonic-gate  * String compare for qsort.  Also used by filec code in sh.file.c.
1617c478bd9Sstevel@tonic-gate  */
1626c02b4a4Smuffin int
1636c02b4a4Smuffin sortscmp(tchar **a1, tchar **a2)
1647c478bd9Sstevel@tonic-gate {
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	return (strcoll_(*a1, *a2));
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate 
1696c02b4a4Smuffin void
1706c02b4a4Smuffin expand(tchar *as)
1717c478bd9Sstevel@tonic-gate {
1726c02b4a4Smuffin 	tchar *cs;
1736c02b4a4Smuffin 	tchar *sgpathp, *oldcs;
1747c478bd9Sstevel@tonic-gate 	struct stat stb;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate #ifdef TRACE
1777c478bd9Sstevel@tonic-gate 	tprintf("TRACE- expand()\n");
1787c478bd9Sstevel@tonic-gate #endif
1797c478bd9Sstevel@tonic-gate 	sgpathp = gpathp;
1807c478bd9Sstevel@tonic-gate 	cs = as;
1817c478bd9Sstevel@tonic-gate 	if (*cs == '~' && gpathp == gpath) {
1827c478bd9Sstevel@tonic-gate 		addpath('~');
1837c478bd9Sstevel@tonic-gate 		for (cs++; alnum(*cs) || *cs == '-'; )
1847c478bd9Sstevel@tonic-gate 			addpath(*cs++);
1857c478bd9Sstevel@tonic-gate 		if (!*cs || *cs == '/') {
1867c478bd9Sstevel@tonic-gate 			if (gpathp != gpath + 1) {
1877c478bd9Sstevel@tonic-gate 				*gpathp = 0;
1887c478bd9Sstevel@tonic-gate 				if (gethdir(gpath + 1))
1897c478bd9Sstevel@tonic-gate 					/*
1907c478bd9Sstevel@tonic-gate 					 * modified from %s to %t
1917c478bd9Sstevel@tonic-gate 					 */
1927c478bd9Sstevel@tonic-gate 					error("Unknown user: %t", gpath + 1);
1937c478bd9Sstevel@tonic-gate 				(void) strcpy_(gpath, gpath + 1);
1947c478bd9Sstevel@tonic-gate 			} else
1957c478bd9Sstevel@tonic-gate 				(void) strcpy_(gpath,
1967c478bd9Sstevel@tonic-gate 					value(S_home /* "home" */));
1977c478bd9Sstevel@tonic-gate 			gpathp = strend(gpath);
1987c478bd9Sstevel@tonic-gate 		}
1997c478bd9Sstevel@tonic-gate 	}
2007c478bd9Sstevel@tonic-gate 	while (!isglob(*cs)) {
2017c478bd9Sstevel@tonic-gate 		if (*cs == 0) {
2027c478bd9Sstevel@tonic-gate 			if (!globbed)
2037c478bd9Sstevel@tonic-gate 				Gcat(gpath, S_ /* "" */);
2047c478bd9Sstevel@tonic-gate 			else if (lstat_(gpath, &stb) >= 0) {
2057c478bd9Sstevel@tonic-gate 				Gcat(gpath, S_ /* "" */);
2067c478bd9Sstevel@tonic-gate 				globcnt++;
2077c478bd9Sstevel@tonic-gate 			}
2087c478bd9Sstevel@tonic-gate 			goto endit;
2097c478bd9Sstevel@tonic-gate 		}
2107c478bd9Sstevel@tonic-gate 		addpath(*cs++);
2117c478bd9Sstevel@tonic-gate 	}
2127c478bd9Sstevel@tonic-gate 	oldcs = cs;
2137c478bd9Sstevel@tonic-gate 	while (cs > as && *cs != '/')
2147c478bd9Sstevel@tonic-gate 		cs--, gpathp--;
2157c478bd9Sstevel@tonic-gate 	if (*cs == '/')
2167c478bd9Sstevel@tonic-gate 		cs++, gpathp++;
2177c478bd9Sstevel@tonic-gate 	*gpathp = 0;
2187c478bd9Sstevel@tonic-gate 	if (*oldcs == '{') {
2197c478bd9Sstevel@tonic-gate 		(void) execbrc(cs, NOSTR);
2207c478bd9Sstevel@tonic-gate 		return;
2217c478bd9Sstevel@tonic-gate 	}
2227c478bd9Sstevel@tonic-gate 	matchdir_(cs);
2237c478bd9Sstevel@tonic-gate endit:
2247c478bd9Sstevel@tonic-gate 	gpathp = sgpathp;
2257c478bd9Sstevel@tonic-gate 	*gpathp = 0;
2267c478bd9Sstevel@tonic-gate }
2277c478bd9Sstevel@tonic-gate 
2286c02b4a4Smuffin void
2296c02b4a4Smuffin matchdir_(tchar *pattern)
2307c478bd9Sstevel@tonic-gate {
2317c478bd9Sstevel@tonic-gate 	struct stat stb;
2326c02b4a4Smuffin 	struct dirent *dp;
2336c02b4a4Smuffin 	DIR *dirp;
2347c478bd9Sstevel@tonic-gate 	tchar curdir_[MAXNAMLEN+1];
2357c478bd9Sstevel@tonic-gate 	int slproc = 0;
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate #ifdef TRACE
2387c478bd9Sstevel@tonic-gate 	tprintf("TRACE- matchdir()\n");
2397c478bd9Sstevel@tonic-gate #endif
2407c478bd9Sstevel@tonic-gate 	/*
2417c478bd9Sstevel@tonic-gate 	 * BSD's opendir would open "." if argument is NULL, but not S5
2427c478bd9Sstevel@tonic-gate 	 */
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	if (*gpath == NULL)
2457c478bd9Sstevel@tonic-gate 		dirp = opendir_(S_DOT /* "." */);
2467c478bd9Sstevel@tonic-gate 	else
2477c478bd9Sstevel@tonic-gate 		dirp = opendir_(gpath);
2487c478bd9Sstevel@tonic-gate 	if (dirp == NULL) {
2497c478bd9Sstevel@tonic-gate 		if (globbed)
2507c478bd9Sstevel@tonic-gate 			return;
2517c478bd9Sstevel@tonic-gate 		goto patherr2;
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 	if (fstat(dirp->dd_fd, &stb) < 0)
2547c478bd9Sstevel@tonic-gate 		goto patherr1;
2557c478bd9Sstevel@tonic-gate 	if (!isdir(stb)) {
2567c478bd9Sstevel@tonic-gate 		errno = ENOTDIR;
2577c478bd9Sstevel@tonic-gate 		goto patherr1;
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate 	while ((dp = readdir(dirp)) != NULL) {
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 		if (dp->d_ino == 0)
2627c478bd9Sstevel@tonic-gate 			continue;
2637c478bd9Sstevel@tonic-gate 		strtots(curdir_, dp->d_name);
2647c478bd9Sstevel@tonic-gate 		slproc = 0;
2657c478bd9Sstevel@tonic-gate 		if (match(curdir_, pattern, &slproc)) {
2667c478bd9Sstevel@tonic-gate 			Gcat(gpath, curdir_);
2677c478bd9Sstevel@tonic-gate 			globcnt++;
2687c478bd9Sstevel@tonic-gate 		}
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 	unsetfd(dirp->dd_fd);
2717c478bd9Sstevel@tonic-gate 	closedir_(dirp);
2727c478bd9Sstevel@tonic-gate 	return;
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate patherr1:
2757c478bd9Sstevel@tonic-gate 	unsetfd(dirp->dd_fd);
2767c478bd9Sstevel@tonic-gate 	closedir_(dirp);
2777c478bd9Sstevel@tonic-gate patherr2:
2787c478bd9Sstevel@tonic-gate 	Perror(gpath);
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate 
2816c02b4a4Smuffin int
2826c02b4a4Smuffin execbrc(tchar *p, tchar *s)
2837c478bd9Sstevel@tonic-gate {
2847c478bd9Sstevel@tonic-gate 	tchar restbuf[BUFSIZ + 2];
2856c02b4a4Smuffin 	tchar *pe, *pm, *pl;
2867c478bd9Sstevel@tonic-gate 	int brclev = 0;
2877c478bd9Sstevel@tonic-gate 	tchar *lm, savec, *sgpathp;
2887c478bd9Sstevel@tonic-gate 	int slproc = 0;
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate #ifdef TRACE
2917c478bd9Sstevel@tonic-gate 	tprintf("TRACE- execbrc()\n");
2927c478bd9Sstevel@tonic-gate #endif
2937c478bd9Sstevel@tonic-gate 	for (lm = restbuf; *p != '{'; *lm++ = *p++)
2947c478bd9Sstevel@tonic-gate 		continue;
2957c478bd9Sstevel@tonic-gate 	for (pe = ++p; *pe; pe++)
2967c478bd9Sstevel@tonic-gate 	switch (*pe) {
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	case '{':
2997c478bd9Sstevel@tonic-gate 		brclev++;
3007c478bd9Sstevel@tonic-gate 		continue;
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	case '}':
3037c478bd9Sstevel@tonic-gate 		if (brclev == 0)
3047c478bd9Sstevel@tonic-gate 			goto pend;
3057c478bd9Sstevel@tonic-gate 		brclev--;
3067c478bd9Sstevel@tonic-gate 		continue;
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	case '[':
3097c478bd9Sstevel@tonic-gate 		for (pe++; *pe && *pe != ']'; pe++)
3107c478bd9Sstevel@tonic-gate 			continue;
3117c478bd9Sstevel@tonic-gate 		if (!*pe)
3127c478bd9Sstevel@tonic-gate 			error("Missing ]");
3137c478bd9Sstevel@tonic-gate 		continue;
3147c478bd9Sstevel@tonic-gate 	}
3157c478bd9Sstevel@tonic-gate pend:
3167c478bd9Sstevel@tonic-gate 	if (brclev || !*pe)
3177c478bd9Sstevel@tonic-gate 		error("Missing }");
3187c478bd9Sstevel@tonic-gate 	for (pl = pm = p; pm <= pe; pm++)
3197c478bd9Sstevel@tonic-gate 	switch (*pm & (QUOTE|TRIM)) {
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	case '{':
3227c478bd9Sstevel@tonic-gate 		brclev++;
3237c478bd9Sstevel@tonic-gate 		continue;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	case '}':
3267c478bd9Sstevel@tonic-gate 		if (brclev) {
3277c478bd9Sstevel@tonic-gate 			brclev--;
3287c478bd9Sstevel@tonic-gate 			continue;
3297c478bd9Sstevel@tonic-gate 		}
3307c478bd9Sstevel@tonic-gate 		goto doit;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	case ',':
3337c478bd9Sstevel@tonic-gate 		if (brclev)
3347c478bd9Sstevel@tonic-gate 			continue;
3357c478bd9Sstevel@tonic-gate doit:
3367c478bd9Sstevel@tonic-gate 		savec = *pm;
3377c478bd9Sstevel@tonic-gate 		*pm = 0;
3387c478bd9Sstevel@tonic-gate 		(void) strcpy_(lm, pl);
3397c478bd9Sstevel@tonic-gate 		(void) strcat_(restbuf, pe + 1);
3407c478bd9Sstevel@tonic-gate 		*pm = savec;
3417c478bd9Sstevel@tonic-gate 		if (s == 0) {
3427c478bd9Sstevel@tonic-gate 			sgpathp = gpathp;
3437c478bd9Sstevel@tonic-gate 			expand(restbuf);
3447c478bd9Sstevel@tonic-gate 			gpathp = sgpathp;
3457c478bd9Sstevel@tonic-gate 			*gpathp = 0;
3467c478bd9Sstevel@tonic-gate 		} else if (amatch(s, restbuf, &slproc))
3477c478bd9Sstevel@tonic-gate 			return (1);
3487c478bd9Sstevel@tonic-gate 		sort();
3497c478bd9Sstevel@tonic-gate 		pl = pm + 1;
3507c478bd9Sstevel@tonic-gate 		continue;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	case '[':
3537c478bd9Sstevel@tonic-gate 		for (pm++; *pm && *pm != ']'; pm++)
3547c478bd9Sstevel@tonic-gate 			continue;
3557c478bd9Sstevel@tonic-gate 		if (!*pm)
3567c478bd9Sstevel@tonic-gate 			error("Missing ]");
3577c478bd9Sstevel@tonic-gate 		continue;
3587c478bd9Sstevel@tonic-gate 	}
3597c478bd9Sstevel@tonic-gate 	return (0);
3607c478bd9Sstevel@tonic-gate }
3617c478bd9Sstevel@tonic-gate 
3626c02b4a4Smuffin int
3636c02b4a4Smuffin match(tchar *s, tchar *p, int *slproc)
3647c478bd9Sstevel@tonic-gate {
3656c02b4a4Smuffin 	int c;
3666c02b4a4Smuffin 	tchar *sentp;
3677c478bd9Sstevel@tonic-gate 	tchar sglobbed = globbed;
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate #ifdef TRACE
3707c478bd9Sstevel@tonic-gate 	tprintf("TRACE- match()\n");
3717c478bd9Sstevel@tonic-gate #endif
3727c478bd9Sstevel@tonic-gate 	if (*s == '.' && *p != '.')
3737c478bd9Sstevel@tonic-gate 		return (0);
3747c478bd9Sstevel@tonic-gate 	sentp = entp;
3757c478bd9Sstevel@tonic-gate 	entp = s;
3767c478bd9Sstevel@tonic-gate 	c = amatch(s, p, slproc);
3777c478bd9Sstevel@tonic-gate 	entp = sentp;
3787c478bd9Sstevel@tonic-gate 	globbed = sglobbed;
3797c478bd9Sstevel@tonic-gate 	return (c);
3807c478bd9Sstevel@tonic-gate }
3817c478bd9Sstevel@tonic-gate 
3826c02b4a4Smuffin int
3836c02b4a4Smuffin amatch(tchar *s, tchar *p, int *slproc)
3847c478bd9Sstevel@tonic-gate {
3856c02b4a4Smuffin 	int scc;
3867c478bd9Sstevel@tonic-gate 	int ok, lc;
3877c478bd9Sstevel@tonic-gate 	tchar *sgpathp;
3887c478bd9Sstevel@tonic-gate 	struct stat stb;
3897c478bd9Sstevel@tonic-gate 	int c, cc;
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate #ifdef TRACE
3927c478bd9Sstevel@tonic-gate 	tprintf("TRACE- amatch()\n");
3937c478bd9Sstevel@tonic-gate #endif
3947c478bd9Sstevel@tonic-gate 	globbed = 1;
3957c478bd9Sstevel@tonic-gate 	for (;;) {
3967c478bd9Sstevel@tonic-gate 		scc = *s++ & TRIM;
3977c478bd9Sstevel@tonic-gate 		switch (c = *p++) {
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 		case '{':
4007c478bd9Sstevel@tonic-gate 			return (execbrc(p - 1, s - 1));
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 		case '[':
4037c478bd9Sstevel@tonic-gate 			ok = 0;
4047c478bd9Sstevel@tonic-gate 			lc = TRIM;
4057c478bd9Sstevel@tonic-gate 			while (cc = *p++) {
4067c478bd9Sstevel@tonic-gate 				if (cc == ']') {
4077c478bd9Sstevel@tonic-gate 					if (ok)
4087c478bd9Sstevel@tonic-gate 						break;
4097c478bd9Sstevel@tonic-gate 					return (0);
4107c478bd9Sstevel@tonic-gate 				}
4117c478bd9Sstevel@tonic-gate 				if (cc == '-') {
4127c478bd9Sstevel@tonic-gate #ifdef MBCHAR
4137c478bd9Sstevel@tonic-gate 					wchar_t rc = *p++;
4147c478bd9Sstevel@tonic-gate 					if (rc == ']') {
4157c478bd9Sstevel@tonic-gate 						p--;
4167c478bd9Sstevel@tonic-gate 						continue;
4177c478bd9Sstevel@tonic-gate 					}
4187c478bd9Sstevel@tonic-gate 					/*
4197c478bd9Sstevel@tonic-gate 					 * Both ends of the char range
4207c478bd9Sstevel@tonic-gate 					 * must belong to the same codeset.
4217c478bd9Sstevel@tonic-gate 					 */
4227c478bd9Sstevel@tonic-gate 					if (sh_bracket_exp(scc, lc, rc))
4237c478bd9Sstevel@tonic-gate 						ok++;
4247c478bd9Sstevel@tonic-gate #else /* !MBCHAR */
4257c478bd9Sstevel@tonic-gate 					if (lc <= scc && scc <= (int)*p++)
4267c478bd9Sstevel@tonic-gate 						ok++;
4277c478bd9Sstevel@tonic-gate #endif /* !MBCHAR */
4287c478bd9Sstevel@tonic-gate 				} else
4297c478bd9Sstevel@tonic-gate 					if (scc == (lc = cc))
4307c478bd9Sstevel@tonic-gate 						ok++;
4317c478bd9Sstevel@tonic-gate 			}
4327c478bd9Sstevel@tonic-gate 			if (cc == 0)
4337c478bd9Sstevel@tonic-gate 				error("Missing ]");
4347c478bd9Sstevel@tonic-gate 			continue;
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 		case '*':
4377c478bd9Sstevel@tonic-gate 			if (!*p)
4387c478bd9Sstevel@tonic-gate 				return (1);
4397c478bd9Sstevel@tonic-gate 			if (*p == '/') {
4407c478bd9Sstevel@tonic-gate 				p++;
4417c478bd9Sstevel@tonic-gate 				goto slash;
4427c478bd9Sstevel@tonic-gate 			} else if (*p == '*') {
4437c478bd9Sstevel@tonic-gate 				s--;
4447c478bd9Sstevel@tonic-gate 				continue;
4457c478bd9Sstevel@tonic-gate 			}
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 			for (s--; *s; s++)
4487c478bd9Sstevel@tonic-gate 				if (amatch(s, p, slproc))
4497c478bd9Sstevel@tonic-gate 					return (1);
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 			return (0);
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 		case 0:
4547c478bd9Sstevel@tonic-gate 			return (scc == 0);
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 		default:
4577c478bd9Sstevel@tonic-gate 			if ((c & TRIM) != scc)
4587c478bd9Sstevel@tonic-gate 				return (0);
4597c478bd9Sstevel@tonic-gate 			continue;
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 		case '?':
4627c478bd9Sstevel@tonic-gate 			if (scc == 0)
4637c478bd9Sstevel@tonic-gate 				return (0);
4647c478bd9Sstevel@tonic-gate 			continue;
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 		case '/':
4677c478bd9Sstevel@tonic-gate 			if (scc)
4687c478bd9Sstevel@tonic-gate 				return (0);
4697c478bd9Sstevel@tonic-gate slash:
4707c478bd9Sstevel@tonic-gate 			if (*slproc)	/* Need to expand "/" only once */
4717c478bd9Sstevel@tonic-gate 				return (0);
4727c478bd9Sstevel@tonic-gate 			else
4737c478bd9Sstevel@tonic-gate 				*slproc = 1;
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 			s = entp;
4767c478bd9Sstevel@tonic-gate 			sgpathp = gpathp;
4777c478bd9Sstevel@tonic-gate 			while (*s)
4787c478bd9Sstevel@tonic-gate 				addpath(*s++);
4797c478bd9Sstevel@tonic-gate 			addpath('/');
4807c478bd9Sstevel@tonic-gate 			if (stat_(gpath, &stb) == 0 && isdir(stb))
4817c478bd9Sstevel@tonic-gate 				if (*p == 0) {
4827c478bd9Sstevel@tonic-gate 					Gcat(gpath, S_ /* "" */);
4837c478bd9Sstevel@tonic-gate 					globcnt++;
4847c478bd9Sstevel@tonic-gate 				} else
4857c478bd9Sstevel@tonic-gate 					expand(p);
4867c478bd9Sstevel@tonic-gate 			gpathp = sgpathp;
4877c478bd9Sstevel@tonic-gate 			*gpathp = 0;
4887c478bd9Sstevel@tonic-gate 			return (0);
4897c478bd9Sstevel@tonic-gate 		}
4907c478bd9Sstevel@tonic-gate 	}
4917c478bd9Sstevel@tonic-gate }
4927c478bd9Sstevel@tonic-gate 
4936c02b4a4Smuffin int
4946c02b4a4Smuffin Gmatch(tchar *s, tchar *p)
4957c478bd9Sstevel@tonic-gate {
4966c02b4a4Smuffin 	int scc;
4977c478bd9Sstevel@tonic-gate 	int ok, lc;
4987c478bd9Sstevel@tonic-gate 	int c, cc;
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate #ifdef TRACE
5017c478bd9Sstevel@tonic-gate 	tprintf("TRACE- Gmatch()\n");
5027c478bd9Sstevel@tonic-gate #endif
5037c478bd9Sstevel@tonic-gate 	for (;;) {
5047c478bd9Sstevel@tonic-gate 		scc = *s++ & TRIM;
5057c478bd9Sstevel@tonic-gate 		switch (c = *p++) {
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 		case '[':
5087c478bd9Sstevel@tonic-gate 			ok = 0;
5097c478bd9Sstevel@tonic-gate 			lc = TRIM;
5107c478bd9Sstevel@tonic-gate 			while (cc = *p++) {
5117c478bd9Sstevel@tonic-gate 				if (cc == ']') {
5127c478bd9Sstevel@tonic-gate 					if (ok)
5137c478bd9Sstevel@tonic-gate 						break;
5147c478bd9Sstevel@tonic-gate 					return (0);
5157c478bd9Sstevel@tonic-gate 				}
5167c478bd9Sstevel@tonic-gate 				if (cc == '-') {
5177c478bd9Sstevel@tonic-gate #ifdef MBCHAR
5187c478bd9Sstevel@tonic-gate 					wchar_t rc = *p++;
5197c478bd9Sstevel@tonic-gate 					/*
5207c478bd9Sstevel@tonic-gate 					 * Both ends of the char range
5217c478bd9Sstevel@tonic-gate 					 * must belong to the same codeset...
5227c478bd9Sstevel@tonic-gate 					 */
5237c478bd9Sstevel@tonic-gate 					if (sh_bracket_exp(scc, lc, rc))
5247c478bd9Sstevel@tonic-gate 						ok++;
5257c478bd9Sstevel@tonic-gate #else /* !MBCHAR */
5267c478bd9Sstevel@tonic-gate 					if (lc <= scc && scc <= (int)*p++)
5277c478bd9Sstevel@tonic-gate 						ok++;
5287c478bd9Sstevel@tonic-gate #endif /* !MBCHAR */
5297c478bd9Sstevel@tonic-gate 				} else
5307c478bd9Sstevel@tonic-gate 					if (scc == (lc = cc))
5317c478bd9Sstevel@tonic-gate 						ok++;
5327c478bd9Sstevel@tonic-gate 			}
5337c478bd9Sstevel@tonic-gate 			if (cc == 0)
5347c478bd9Sstevel@tonic-gate 				bferr("Missing ]");
5357c478bd9Sstevel@tonic-gate 			continue;
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 		case '*':
5387c478bd9Sstevel@tonic-gate 			if (!*p)
5397c478bd9Sstevel@tonic-gate 				return (1);
5407c478bd9Sstevel@tonic-gate 			for (s--; *s; s++)
5417c478bd9Sstevel@tonic-gate 				if (Gmatch(s, p))
5427c478bd9Sstevel@tonic-gate 					return (1);
5437c478bd9Sstevel@tonic-gate 			return (0);
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 		case 0:
5467c478bd9Sstevel@tonic-gate 			return (scc == 0);
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 		default:
5497c478bd9Sstevel@tonic-gate 			if ((c & TRIM) != scc)
5507c478bd9Sstevel@tonic-gate 				return (0);
5517c478bd9Sstevel@tonic-gate 			continue;
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 		case '?':
5547c478bd9Sstevel@tonic-gate 			if (scc == 0)
5557c478bd9Sstevel@tonic-gate 				return (0);
5567c478bd9Sstevel@tonic-gate 			continue;
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 		}
5597c478bd9Sstevel@tonic-gate 	}
5607c478bd9Sstevel@tonic-gate }
5617c478bd9Sstevel@tonic-gate 
5626c02b4a4Smuffin void
5636c02b4a4Smuffin Gcat(tchar *s1, tchar *s2)
5647c478bd9Sstevel@tonic-gate {
5656c02b4a4Smuffin 	tchar *p, *q;
5667c478bd9Sstevel@tonic-gate 	int n;
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate #ifdef TRACE
5697c478bd9Sstevel@tonic-gate 	tprintf("TRACE- Gcat()\n");
5707c478bd9Sstevel@tonic-gate #endif
5717c478bd9Sstevel@tonic-gate 	for (p = s1; *p++; )
5727c478bd9Sstevel@tonic-gate 		;
5737c478bd9Sstevel@tonic-gate 	for (q = s2; *q++; )
5747c478bd9Sstevel@tonic-gate 		;
5757c478bd9Sstevel@tonic-gate 	gnleft -= (n = (p - s1) + (q - s2) - 1);
5767c478bd9Sstevel@tonic-gate 	if (gnleft <= 0 || ++gargc >= GAVSIZ)
5777c478bd9Sstevel@tonic-gate 		error("Arguments too long");
5787c478bd9Sstevel@tonic-gate 	gargv[gargc] = 0;
5797c478bd9Sstevel@tonic-gate 	p = gargv[gargc - 1] = (tchar *) xalloc((unsigned)n*sizeof (tchar));
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	for (q = s1; *p++ = *q++; )
5827c478bd9Sstevel@tonic-gate 		;
5837c478bd9Sstevel@tonic-gate 	for (p--, q = s2; *p++ = *q++; )
5847c478bd9Sstevel@tonic-gate 		;
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate 
5876c02b4a4Smuffin void
5886c02b4a4Smuffin addpath(tchar c)
5897c478bd9Sstevel@tonic-gate {
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate #ifdef TRACE
5927c478bd9Sstevel@tonic-gate 	tprintf("TRACE- addpath()\n");
5937c478bd9Sstevel@tonic-gate #endif
5947c478bd9Sstevel@tonic-gate 	if (gpathp >= lastgpathp)
5957c478bd9Sstevel@tonic-gate 		error("Pathname too long");
5967c478bd9Sstevel@tonic-gate 	*gpathp++ = c & TRIM;
5977c478bd9Sstevel@tonic-gate 	*gpathp = 0;
5987c478bd9Sstevel@tonic-gate }
5997c478bd9Sstevel@tonic-gate 
6006c02b4a4Smuffin void
6016c02b4a4Smuffin rscan(tchar **t, int (*f)(int))
6027c478bd9Sstevel@tonic-gate {
6036c02b4a4Smuffin 	tchar *p;
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate #ifdef TRACE
6067c478bd9Sstevel@tonic-gate 	tprintf("TRACE- rscan()\n");
6077c478bd9Sstevel@tonic-gate #endif
6087c478bd9Sstevel@tonic-gate 	while (p = *t++)
6097c478bd9Sstevel@tonic-gate 		while (*p)
6107c478bd9Sstevel@tonic-gate 			(*f)(*p++);
6117c478bd9Sstevel@tonic-gate }
6127c478bd9Sstevel@tonic-gate 
6136c02b4a4Smuffin void
6146c02b4a4Smuffin trim(tchar **t)
6157c478bd9Sstevel@tonic-gate {
6166c02b4a4Smuffin 	tchar *p;
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate #ifdef TRACE
6197c478bd9Sstevel@tonic-gate 	tprintf("TRACE- trim()\n");
6207c478bd9Sstevel@tonic-gate #endif
6217c478bd9Sstevel@tonic-gate 	while (p = *t++)
6227c478bd9Sstevel@tonic-gate 		while (*p)
6237c478bd9Sstevel@tonic-gate 			*p++ &= TRIM;
6247c478bd9Sstevel@tonic-gate }
6257c478bd9Sstevel@tonic-gate 
6266c02b4a4Smuffin void
6276c02b4a4Smuffin tglob(tchar **t)
6287c478bd9Sstevel@tonic-gate {
6296c02b4a4Smuffin 	tchar *p, c;
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate #ifdef TRACE
6327c478bd9Sstevel@tonic-gate 	tprintf("TRACE- tglob()\n");
6337c478bd9Sstevel@tonic-gate #endif
6347c478bd9Sstevel@tonic-gate 	while (p = *t++) {
6357c478bd9Sstevel@tonic-gate 		if (*p == '~')
6367c478bd9Sstevel@tonic-gate 			gflag |= 2;
6377c478bd9Sstevel@tonic-gate 		else if (*p == '{' && (p[1] == '\0' ||
6387c478bd9Sstevel@tonic-gate 			p[1] == '}' && p[2] == '\0'))
6397c478bd9Sstevel@tonic-gate 			continue;
6407c478bd9Sstevel@tonic-gate 		while (c = *p++)
6417c478bd9Sstevel@tonic-gate 			if (isglob(c))
6427c478bd9Sstevel@tonic-gate 				gflag |= c == '{' ? 2 : 1;
6437c478bd9Sstevel@tonic-gate 	}
6447c478bd9Sstevel@tonic-gate }
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate tchar *
6476c02b4a4Smuffin globone(tchar *str)
6487c478bd9Sstevel@tonic-gate {
6497c478bd9Sstevel@tonic-gate 	tchar *gv[2];
6506c02b4a4Smuffin 	tchar **gvp;
6516c02b4a4Smuffin 	tchar *cp;
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate #ifdef TRACE
6547c478bd9Sstevel@tonic-gate 	tprintf("TRACE- globone()\n");
6557c478bd9Sstevel@tonic-gate #endif
6567c478bd9Sstevel@tonic-gate 	gv[0] = str;
6577c478bd9Sstevel@tonic-gate 	gv[1] = 0;
6587c478bd9Sstevel@tonic-gate 	gflag = 0;
6597c478bd9Sstevel@tonic-gate 	tglob(gv);
6607c478bd9Sstevel@tonic-gate 	if (gflag) {
6617c478bd9Sstevel@tonic-gate 		gvp = glob(gv);
6627c478bd9Sstevel@tonic-gate 		if (gvp == 0) {
6637c478bd9Sstevel@tonic-gate 			setname(str);
6647c478bd9Sstevel@tonic-gate 			bferr("No match");
6657c478bd9Sstevel@tonic-gate 		}
6667c478bd9Sstevel@tonic-gate 		cp = *gvp++;
6677c478bd9Sstevel@tonic-gate 		if (cp == 0)
6687c478bd9Sstevel@tonic-gate 			cp = S_ /* "" */;
6697c478bd9Sstevel@tonic-gate 		else if (*gvp) {
6707c478bd9Sstevel@tonic-gate 			setname(str);
6717c478bd9Sstevel@tonic-gate 			bferr("Ambiguous");
6727c478bd9Sstevel@tonic-gate 		} else
6737c478bd9Sstevel@tonic-gate 			cp = strip(cp);
674*65b0c20eSnakanon #if 0
6757c478bd9Sstevel@tonic-gate 		if (cp == 0 || *gvp) {
6767c478bd9Sstevel@tonic-gate 			setname(str);
6777c478bd9Sstevel@tonic-gate 			bferr(cp ? "Ambiguous" : "No output");
6787c478bd9Sstevel@tonic-gate 		}
679*65b0c20eSnakanon #endif
6807c478bd9Sstevel@tonic-gate 		xfree((char *)gargv); gargv = 0;
6817c478bd9Sstevel@tonic-gate 	} else {
6827c478bd9Sstevel@tonic-gate 		trim(gv);
6837c478bd9Sstevel@tonic-gate 		cp = savestr(gv[0]);
6847c478bd9Sstevel@tonic-gate 	}
6857c478bd9Sstevel@tonic-gate 	return (cp);
6867c478bd9Sstevel@tonic-gate }
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate /*
6897c478bd9Sstevel@tonic-gate  * Command substitute cp.  If literal, then this is
6907c478bd9Sstevel@tonic-gate  * a substitution from a << redirection, and so we should
6917c478bd9Sstevel@tonic-gate  * not crunch blanks and tabs, separating words only at newlines.
6927c478bd9Sstevel@tonic-gate  */
6937c478bd9Sstevel@tonic-gate tchar **
6946c02b4a4Smuffin dobackp(tchar *cp, bool literal)
6957c478bd9Sstevel@tonic-gate {
6966c02b4a4Smuffin 	tchar *lp, *rp;
6977c478bd9Sstevel@tonic-gate 	tchar *ep;
6987c478bd9Sstevel@tonic-gate 	tchar word[BUFSIZ];
6997c478bd9Sstevel@tonic-gate 	tchar *apargv[GAVSIZ + 2];
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate #ifdef TRACE
7027c478bd9Sstevel@tonic-gate 	tprintf("TRACE- dobackp()\n");
7037c478bd9Sstevel@tonic-gate #endif
7047c478bd9Sstevel@tonic-gate 	if (pargv) {
7057c478bd9Sstevel@tonic-gate 		blkfree(pargv);
7067c478bd9Sstevel@tonic-gate 	}
7077c478bd9Sstevel@tonic-gate 	pargv = apargv;
7087c478bd9Sstevel@tonic-gate 	pargv[0] = NOSTR;
7097c478bd9Sstevel@tonic-gate 	pargcp = pargs = word;
7107c478bd9Sstevel@tonic-gate 	pargc = 0;
7117c478bd9Sstevel@tonic-gate 	pnleft = BUFSIZ - 4;
7127c478bd9Sstevel@tonic-gate 	for (;;) {
7137c478bd9Sstevel@tonic-gate 		for (lp = cp; *lp != '`'; lp++) {
7147c478bd9Sstevel@tonic-gate 			if (*lp == 0) {
7157c478bd9Sstevel@tonic-gate 				if (pargcp != pargs)
7167c478bd9Sstevel@tonic-gate 					pword();
7177c478bd9Sstevel@tonic-gate #ifdef GDEBUG
7187c478bd9Sstevel@tonic-gate 				printf("leaving dobackp\n");
7197c478bd9Sstevel@tonic-gate #endif
7207c478bd9Sstevel@tonic-gate 				return (pargv = copyblk(pargv));
7217c478bd9Sstevel@tonic-gate 			}
7227c478bd9Sstevel@tonic-gate 			psave(*lp);
7237c478bd9Sstevel@tonic-gate 		}
7247c478bd9Sstevel@tonic-gate 		lp++;
7257c478bd9Sstevel@tonic-gate 		for (rp = lp; *rp && *rp != '`'; rp++)
7267c478bd9Sstevel@tonic-gate 			if (*rp == '\\') {
7277c478bd9Sstevel@tonic-gate 				rp++;
7287c478bd9Sstevel@tonic-gate 				if (!*rp)
7297c478bd9Sstevel@tonic-gate 					goto oops;
7307c478bd9Sstevel@tonic-gate 			}
7317c478bd9Sstevel@tonic-gate 		if (!*rp)
7327c478bd9Sstevel@tonic-gate oops:
7337c478bd9Sstevel@tonic-gate 			error("Unmatched `");
7347c478bd9Sstevel@tonic-gate 		ep = savestr(lp);
7357c478bd9Sstevel@tonic-gate 		ep[rp - lp] = 0;
7367c478bd9Sstevel@tonic-gate 		backeval(ep, literal);
7377c478bd9Sstevel@tonic-gate #ifdef GDEBUG
7387c478bd9Sstevel@tonic-gate 		printf("back from backeval\n");
7397c478bd9Sstevel@tonic-gate #endif
7407c478bd9Sstevel@tonic-gate 		cp = rp + 1;
7417c478bd9Sstevel@tonic-gate 	}
7427c478bd9Sstevel@tonic-gate }
7437c478bd9Sstevel@tonic-gate 
7446c02b4a4Smuffin void
7456c02b4a4Smuffin backeval(tchar *cp, bool literal)
7467c478bd9Sstevel@tonic-gate {
7477c478bd9Sstevel@tonic-gate 	int pvec[2];
7487c478bd9Sstevel@tonic-gate 	int quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
749*65b0c20eSnakanon 	tchar ibuf[BUFSIZ + MB_LEN_MAX]; /* read_ can return extra bytes */
7506c02b4a4Smuffin 	int icnt = 0, c;
7516c02b4a4Smuffin 	tchar *ip;
7527c478bd9Sstevel@tonic-gate 	bool hadnl = 0;
7537c478bd9Sstevel@tonic-gate 	tchar *fakecom[2];
7547c478bd9Sstevel@tonic-gate 	struct command faket;
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate #ifdef TRACE
7577c478bd9Sstevel@tonic-gate 	tprintf("TRACE- backeval()\n");
7587c478bd9Sstevel@tonic-gate #endif
7597c478bd9Sstevel@tonic-gate 	faket.t_dtyp = TCOM;
7607c478bd9Sstevel@tonic-gate 	faket.t_dflg = 0;
7617c478bd9Sstevel@tonic-gate 	faket.t_dlef = 0;
7627c478bd9Sstevel@tonic-gate 	faket.t_drit = 0;
7637c478bd9Sstevel@tonic-gate 	faket.t_dspr = 0;
7647c478bd9Sstevel@tonic-gate 	faket.t_dcom = fakecom;
7657c478bd9Sstevel@tonic-gate 	fakecom[0] = S_QPPPQ; /* "` ... `" */;
7667c478bd9Sstevel@tonic-gate 	fakecom[1] = 0;
7677c478bd9Sstevel@tonic-gate 	/*
7687c478bd9Sstevel@tonic-gate 	 * We do the psave job to temporarily change the current job
7697c478bd9Sstevel@tonic-gate 	 * so that the following fork is considered a separate job.
7707c478bd9Sstevel@tonic-gate 	 * This is so that when backquotes are used in a
7717c478bd9Sstevel@tonic-gate 	 * builtin function that calls glob the "current job" is not corrupted.
7727c478bd9Sstevel@tonic-gate 	 * We only need one level of pushed jobs as long as we are sure to
7737c478bd9Sstevel@tonic-gate 	 * fork here.
7747c478bd9Sstevel@tonic-gate 	 */
7757c478bd9Sstevel@tonic-gate 	psavejob();
7767c478bd9Sstevel@tonic-gate 	/*
7777c478bd9Sstevel@tonic-gate 	 * It would be nicer if we could integrate this redirection more
7787c478bd9Sstevel@tonic-gate 	 * with the routines in sh.sem.c by doing a fake execute on a builtin
7797c478bd9Sstevel@tonic-gate 	 * function that was piped out.
7807c478bd9Sstevel@tonic-gate 	 */
7817c478bd9Sstevel@tonic-gate 	mypipe(pvec);
7827c478bd9Sstevel@tonic-gate 	if (pfork(&faket, -1) == 0) {
7837c478bd9Sstevel@tonic-gate 		struct wordent paraml;
7847c478bd9Sstevel@tonic-gate 		struct command *t;
7857c478bd9Sstevel@tonic-gate 		tchar oHIST;
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 		new_process();
7887c478bd9Sstevel@tonic-gate 		(void) close(pvec[0]);
7897c478bd9Sstevel@tonic-gate 		unsetfd(pvec[0]);
7907c478bd9Sstevel@tonic-gate 		(void) dmove(pvec[1], 1);
7917c478bd9Sstevel@tonic-gate 		(void) dmove(SHDIAG, 2);
7927c478bd9Sstevel@tonic-gate 		reinitdesc(0, NULL);
7937c478bd9Sstevel@tonic-gate 		arginp = cp;
7947c478bd9Sstevel@tonic-gate 		while (*cp)
7957c478bd9Sstevel@tonic-gate 			*cp++ &= TRIM;
7967c478bd9Sstevel@tonic-gate 		/*
7977c478bd9Sstevel@tonic-gate 		 *	disable history subsitution in sub-shell
7987c478bd9Sstevel@tonic-gate 		 *  of `` evaluation prevents possible
7997c478bd9Sstevel@tonic-gate 		 *  infinite recursion of `` evaluation
8007c478bd9Sstevel@tonic-gate 		 */
8017c478bd9Sstevel@tonic-gate 		oHIST = HIST;
8027c478bd9Sstevel@tonic-gate 		HIST = 0;
8037c478bd9Sstevel@tonic-gate 		(void) lex(&paraml);
8047c478bd9Sstevel@tonic-gate 		HIST = oHIST;
8057c478bd9Sstevel@tonic-gate 		if (err)
8067c478bd9Sstevel@tonic-gate 			error("%s", gettext(err));
8077c478bd9Sstevel@tonic-gate 		alias(&paraml);
8087c478bd9Sstevel@tonic-gate 		t = syntax(paraml.next, &paraml, 0);
8097c478bd9Sstevel@tonic-gate 		if (err)
8107c478bd9Sstevel@tonic-gate 			error("%s", gettext(err));
8117c478bd9Sstevel@tonic-gate 		if (t)
8127c478bd9Sstevel@tonic-gate 			t->t_dflg |= FPAR;
8137c478bd9Sstevel@tonic-gate 		(void) signal(SIGTSTP, SIG_IGN);
8147c478bd9Sstevel@tonic-gate 		(void) signal(SIGTTIN, SIG_IGN);
8157c478bd9Sstevel@tonic-gate 		(void) signal(SIGTTOU, SIG_IGN);
8167c478bd9Sstevel@tonic-gate 		execute(t, -1);
8177c478bd9Sstevel@tonic-gate 		exitstat();
8187c478bd9Sstevel@tonic-gate 	}
8197c478bd9Sstevel@tonic-gate 	xfree(cp);
8207c478bd9Sstevel@tonic-gate 	(void) close(pvec[1]);
8217c478bd9Sstevel@tonic-gate 	unsetfd(pvec[1]);
8227c478bd9Sstevel@tonic-gate 	do {
8237c478bd9Sstevel@tonic-gate 		int cnt = 0;
8247c478bd9Sstevel@tonic-gate 		for (;;) {
8257c478bd9Sstevel@tonic-gate 			if (icnt == 0) {
8267c478bd9Sstevel@tonic-gate 				ip = ibuf;
8277c478bd9Sstevel@tonic-gate 				icnt = read_(pvec[0], ip, BUFSIZ);
8287c478bd9Sstevel@tonic-gate 				if (icnt <= 0) {
8297c478bd9Sstevel@tonic-gate 					c = -1;
8307c478bd9Sstevel@tonic-gate 					break;
8317c478bd9Sstevel@tonic-gate 				}
8327c478bd9Sstevel@tonic-gate 			}
8337c478bd9Sstevel@tonic-gate 			if (hadnl)
8347c478bd9Sstevel@tonic-gate 				break;
8357c478bd9Sstevel@tonic-gate 			--icnt;
8367c478bd9Sstevel@tonic-gate 			c = (*ip++ & TRIM);
8377c478bd9Sstevel@tonic-gate 			if (c == 0)
8387c478bd9Sstevel@tonic-gate 				break;
8397c478bd9Sstevel@tonic-gate 			if (c == '\n') {
8407c478bd9Sstevel@tonic-gate 				/*
8417c478bd9Sstevel@tonic-gate 				 * Continue around the loop one
8427c478bd9Sstevel@tonic-gate 				 * more time, so that we can eat
8437c478bd9Sstevel@tonic-gate 				 * the last newline without terminating
8447c478bd9Sstevel@tonic-gate 				 * this word.
8457c478bd9Sstevel@tonic-gate 				 */
8467c478bd9Sstevel@tonic-gate 				hadnl = 1;
8477c478bd9Sstevel@tonic-gate 				continue;
8487c478bd9Sstevel@tonic-gate 			}
8497c478bd9Sstevel@tonic-gate 			if (!quoted && issp(c))
8507c478bd9Sstevel@tonic-gate 				break;
8517c478bd9Sstevel@tonic-gate 			cnt++;
8527c478bd9Sstevel@tonic-gate 			psave(c | quoted);
8537c478bd9Sstevel@tonic-gate 		}
8547c478bd9Sstevel@tonic-gate 		/*
8557c478bd9Sstevel@tonic-gate 		 * Unless at end-of-file, we will form a new word
8567c478bd9Sstevel@tonic-gate 		 * here if there were characters in the word, or in
8577c478bd9Sstevel@tonic-gate 		 * any case when we take text literally.  If
8587c478bd9Sstevel@tonic-gate 		 * we didn't make empty words here when literal was
8597c478bd9Sstevel@tonic-gate 		 * set then we would lose blank lines.
8607c478bd9Sstevel@tonic-gate 		 */
8617c478bd9Sstevel@tonic-gate 		if (c != -1 && (cnt || literal)) {
8627c478bd9Sstevel@tonic-gate 			if (pargc == GAVSIZ)
8637c478bd9Sstevel@tonic-gate 				break;
8647c478bd9Sstevel@tonic-gate 			pword();
8657c478bd9Sstevel@tonic-gate 		}
8667c478bd9Sstevel@tonic-gate 		hadnl = 0;
8677c478bd9Sstevel@tonic-gate 	} while (c >= 0);
8687c478bd9Sstevel@tonic-gate #ifdef GDEBUG
8697c478bd9Sstevel@tonic-gate 	printf("done in backeval, pvec: %d %d\n", pvec[0], pvec[1]);
8707c478bd9Sstevel@tonic-gate 	printf("also c = %c <%o>\n", (tchar) c, (tchar) c);
8717c478bd9Sstevel@tonic-gate #endif
8727c478bd9Sstevel@tonic-gate 	(void) close(pvec[0]);
8737c478bd9Sstevel@tonic-gate 	unsetfd(pvec[0]);
8747c478bd9Sstevel@tonic-gate 	pwait();
8757c478bd9Sstevel@tonic-gate 	prestjob();
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate 
8786c02b4a4Smuffin void
8796c02b4a4Smuffin psave(tchar c)
8807c478bd9Sstevel@tonic-gate {
8817c478bd9Sstevel@tonic-gate #ifdef TRACE
8827c478bd9Sstevel@tonic-gate 	tprintf("TRACE- psave()\n");
8837c478bd9Sstevel@tonic-gate #endif
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	if (--pnleft <= 0)
8867c478bd9Sstevel@tonic-gate 		error("Word too long");
8877c478bd9Sstevel@tonic-gate 	*pargcp++ = c;
8887c478bd9Sstevel@tonic-gate }
8897c478bd9Sstevel@tonic-gate 
8906c02b4a4Smuffin void
8916c02b4a4Smuffin pword(void)
8927c478bd9Sstevel@tonic-gate {
8937c478bd9Sstevel@tonic-gate #ifdef TRACE
8947c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pword()\n");
8957c478bd9Sstevel@tonic-gate #endif
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	psave(0);
8987c478bd9Sstevel@tonic-gate 	if (pargc == GAVSIZ)
8997c478bd9Sstevel@tonic-gate 		error("Too many words from ``");
9007c478bd9Sstevel@tonic-gate 	pargv[pargc++] = savestr(pargs);
9017c478bd9Sstevel@tonic-gate 	pargv[pargc] = NOSTR;
9027c478bd9Sstevel@tonic-gate #ifdef GDEBUG
9037c478bd9Sstevel@tonic-gate 	printf("got word %t\n", pargv[pargc-1]);
9047c478bd9Sstevel@tonic-gate #endif
9057c478bd9Sstevel@tonic-gate 	pargcp = pargs;
9067c478bd9Sstevel@tonic-gate 	pnleft = BUFSIZ - 4;
9077c478bd9Sstevel@tonic-gate }
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate /*
9127c478bd9Sstevel@tonic-gate  * returns pathname of the form dir/file;
9137c478bd9Sstevel@tonic-gate  *  dir is a null-terminated string;
9147c478bd9Sstevel@tonic-gate  */
9157c478bd9Sstevel@tonic-gate char *
9166c02b4a4Smuffin makename(char *dir, char *file)
9177c478bd9Sstevel@tonic-gate {
9187c478bd9Sstevel@tonic-gate 	/*
9197c478bd9Sstevel@tonic-gate 	 *  Maximum length of a
9207c478bd9Sstevel@tonic-gate 	 *  file/dir name in ls-command;
9217c478bd9Sstevel@tonic-gate 	 *  dfile is static as this is returned
9227c478bd9Sstevel@tonic-gate 	 *  by makename();
9237c478bd9Sstevel@tonic-gate 	 */
9247c478bd9Sstevel@tonic-gate 	static char dfile[MAXNAMLEN];
9257c478bd9Sstevel@tonic-gate 
9266c02b4a4Smuffin 	char *dp, *fp;
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	dp = dfile;
9297c478bd9Sstevel@tonic-gate 	fp = dir;
9307c478bd9Sstevel@tonic-gate 	while (*fp)
9317c478bd9Sstevel@tonic-gate 		*dp++ = *fp++;
9327c478bd9Sstevel@tonic-gate 	if (dp > dfile && *(dp - 1) != '/')
9337c478bd9Sstevel@tonic-gate 		*dp++ = '/';
9347c478bd9Sstevel@tonic-gate 	fp = file;
9357c478bd9Sstevel@tonic-gate 	while (*fp)
9367c478bd9Sstevel@tonic-gate 		*dp++ = *fp++;
9377c478bd9Sstevel@tonic-gate 	*dp = '\0';
9387c478bd9Sstevel@tonic-gate 	/*
9397c478bd9Sstevel@tonic-gate 	 * dfile points to the absolute pathname. We are
9407c478bd9Sstevel@tonic-gate 	 * only interested in the last component.
9417c478bd9Sstevel@tonic-gate 	 */
9427c478bd9Sstevel@tonic-gate 	return (rindex(dfile, '/') + 1);
9437c478bd9Sstevel@tonic-gate }
9447c478bd9Sstevel@tonic-gate 
9456c02b4a4Smuffin int
9466c02b4a4Smuffin sh_bracket_exp(tchar t_ch, tchar t_fch, tchar t_lch)
9477c478bd9Sstevel@tonic-gate {
9487c478bd9Sstevel@tonic-gate 	char	t_char[MB_LEN_MAX + 1];
9497c478bd9Sstevel@tonic-gate 	char	t_patan[MB_LEN_MAX * 2 + 8];
9507c478bd9Sstevel@tonic-gate 	char	*p;
9517c478bd9Sstevel@tonic-gate 	int	i;
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	if ((t_ch == t_fch) || (t_ch == t_lch))
9547c478bd9Sstevel@tonic-gate 		return (1);
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 	p = t_patan;
9577c478bd9Sstevel@tonic-gate 	if ((i = wctomb(t_char, (wchar_t)t_ch)) <= 0)
9587c478bd9Sstevel@tonic-gate 		return (0);
9597c478bd9Sstevel@tonic-gate 	t_char[i] = 0;
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	*p++ = '[';
9627c478bd9Sstevel@tonic-gate 	if ((i = wctomb(p, (wchar_t)t_fch)) <= 0)
9637c478bd9Sstevel@tonic-gate 		return (0);
9647c478bd9Sstevel@tonic-gate 	p += i;
9657c478bd9Sstevel@tonic-gate 	*p++ = '-';
9667c478bd9Sstevel@tonic-gate 	if ((i = wctomb(p, (wchar_t)t_lch)) <= 0)
9677c478bd9Sstevel@tonic-gate 		return (0);
9687c478bd9Sstevel@tonic-gate 	p += i;
9697c478bd9Sstevel@tonic-gate 	*p++ = ']';
9707c478bd9Sstevel@tonic-gate 	*p = 0;
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 	if (fnmatch(t_patan, t_char, FNM_NOESCAPE))
9737c478bd9Sstevel@tonic-gate 		return (0);
9747c478bd9Sstevel@tonic-gate 	return (1);
9757c478bd9Sstevel@tonic-gate }
976