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