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