xref: /onnv-gate/usr/src/cmd/csh/sh.func.c (revision 2182:221c5b409327)
10Sstevel@tonic-gate /*
2*2182Schin  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate 
60Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
70Sstevel@tonic-gate /*	  All Rights Reserved  	*/
80Sstevel@tonic-gate 
90Sstevel@tonic-gate /*
100Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
110Sstevel@tonic-gate  * All rights reserved.  The Berkeley Software License Agreement
120Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
130Sstevel@tonic-gate  */
140Sstevel@tonic-gate 
150Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
160Sstevel@tonic-gate 
170Sstevel@tonic-gate #include "sh.h"
180Sstevel@tonic-gate #include <locale.h>	/* For LC_ALL */
190Sstevel@tonic-gate #include "sh.tconst.h"
200Sstevel@tonic-gate #include <sys/types.h>
210Sstevel@tonic-gate #include <stdlib.h>
220Sstevel@tonic-gate 
230Sstevel@tonic-gate /*
240Sstevel@tonic-gate  * N.B.: Some of the limits change from SunOS 4.x to SunOS 5.0.  In
250Sstevel@tonic-gate  * particular, RLIMIT_RSS is gone and RLIMIT_VMEM is new.  Beware of consusing
260Sstevel@tonic-gate  * the keywords that the command prints for these two.  The old one was
270Sstevel@tonic-gate  * "memoryuse" and the new one is "memorysize".  Note also that a given limit
280Sstevel@tonic-gate  * doesn't necessarily appear in the same position in the two releases.
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate struct limits {
310Sstevel@tonic-gate 	int	limconst;
320Sstevel@tonic-gate 	tchar *limname;
330Sstevel@tonic-gate 	int	limdiv;
340Sstevel@tonic-gate 	tchar *limscale;
350Sstevel@tonic-gate } limits[] = {
360Sstevel@tonic-gate 	RLIMIT_CPU,	S_cputime,	/* "cputime" */
370Sstevel@tonic-gate 		1,	S_seconds,	/* "seconds" */
380Sstevel@tonic-gate 	RLIMIT_FSIZE,	S_filesize,	/* "filesize" */
390Sstevel@tonic-gate 		1024,	S_kbytes,	/* "kbytes" */
400Sstevel@tonic-gate 	RLIMIT_DATA,	S_datasize,	/* "datasize" */
410Sstevel@tonic-gate 		1024,	S_kbytes,	/* "kbytes" */
420Sstevel@tonic-gate 	RLIMIT_STACK,	S_stacksize,	/* "stacksize" */
430Sstevel@tonic-gate 		1024,	S_kbytes,	/* "kbytes" */
440Sstevel@tonic-gate 	RLIMIT_CORE,	S_coredumpsize, /* "coredumpsize" */
450Sstevel@tonic-gate 		1024,	S_kbytes,	/* "kbytes" */
460Sstevel@tonic-gate 	RLIMIT_NOFILE,	S_descriptors,	/* "descriptors" */
470Sstevel@tonic-gate 		1,	S_,		/* "" */
480Sstevel@tonic-gate 	RLIMIT_VMEM,	S_memorysize,	/* "memorysize" */
490Sstevel@tonic-gate 		1024,	S_kbytes,	/* "kbytes" */
500Sstevel@tonic-gate 	-1,		0,
510Sstevel@tonic-gate };
520Sstevel@tonic-gate 
53356Smuffin 
540Sstevel@tonic-gate static int getval(struct limits *lp, tchar **v, rlim_t *);
55356Smuffin void islogin(void);
56356Smuffin int dolabel(void);
570Sstevel@tonic-gate void reexecute(struct command *kp);
58356Smuffin void preread_(void);
59356Smuffin void doagain(void);
60356Smuffin void toend(void);
61356Smuffin void wfree(void);
620Sstevel@tonic-gate void echo(tchar sep, tchar **v);
630Sstevel@tonic-gate void local_setenv(tchar *name, tchar *val);
640Sstevel@tonic-gate void local_unsetenv(tchar *name);
650Sstevel@tonic-gate void limtail(tchar *cp, tchar *str0);
660Sstevel@tonic-gate void plim(struct limits *lp, tchar hard);
670Sstevel@tonic-gate void search();
680Sstevel@tonic-gate 
690Sstevel@tonic-gate #define	BUFSZ	1028
700Sstevel@tonic-gate 
710Sstevel@tonic-gate /*
720Sstevel@tonic-gate  * C shell
730Sstevel@tonic-gate  */
740Sstevel@tonic-gate 
75356Smuffin struct biltins *
isbfunc(struct command * t)760Sstevel@tonic-gate isbfunc(struct command *t)
770Sstevel@tonic-gate {
780Sstevel@tonic-gate 	tchar *cp = t->t_dcom[0];
790Sstevel@tonic-gate 	struct biltins *bp, *bp1, *bp2;
800Sstevel@tonic-gate 	int dofg1(), dobg1();
810Sstevel@tonic-gate 
820Sstevel@tonic-gate 	static struct biltins label = { S_, dolabel, 0, 0 };
830Sstevel@tonic-gate 	static struct biltins foregnd = { S_Pjob, dofg1, 0, 0 };
840Sstevel@tonic-gate 	static struct biltins backgnd = { S_PjobAND, dobg1, 0, 0 };
850Sstevel@tonic-gate #ifdef TRACE
860Sstevel@tonic-gate 	tprintf("TRACE- isbfunc()\n");
870Sstevel@tonic-gate #endif
880Sstevel@tonic-gate 	if (lastchr(cp) == ':') {
890Sstevel@tonic-gate 		label.bname = cp;
900Sstevel@tonic-gate 		return (&label);
910Sstevel@tonic-gate 	}
920Sstevel@tonic-gate 	if (*cp == '%') {
930Sstevel@tonic-gate 		if (t->t_dflg & FAND) {
940Sstevel@tonic-gate 			t->t_dflg &= ~FAND;
950Sstevel@tonic-gate 			backgnd.bname = cp;
960Sstevel@tonic-gate 			return (&backgnd);
970Sstevel@tonic-gate 		}
980Sstevel@tonic-gate 		foregnd.bname = cp;
990Sstevel@tonic-gate 		return (&foregnd);
1000Sstevel@tonic-gate 	}
1010Sstevel@tonic-gate 	/*
1020Sstevel@tonic-gate 	 * Binary search
1030Sstevel@tonic-gate 	 * Bp1 is the beginning of the current search range.
1040Sstevel@tonic-gate 	 * Bp2 is one past the end.
1050Sstevel@tonic-gate 	 */
1060Sstevel@tonic-gate 	for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2; ) {
1070Sstevel@tonic-gate 		int i;
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 		bp = bp1 + (bp2 - bp1 >> 1);
1100Sstevel@tonic-gate 		if ((i = *cp - *bp->bname) == 0 &&
1110Sstevel@tonic-gate 		    (i = strcmp_(cp, bp->bname)) == 0) {
1120Sstevel@tonic-gate 			return (bp);
1130Sstevel@tonic-gate 		}
1140Sstevel@tonic-gate 		if (i < 0) {
1150Sstevel@tonic-gate 			bp2 = bp;
1160Sstevel@tonic-gate 		} else {
1170Sstevel@tonic-gate 			bp1 = bp + 1;
1180Sstevel@tonic-gate 		}
1190Sstevel@tonic-gate 	}
1200Sstevel@tonic-gate 	return (0);
1210Sstevel@tonic-gate }
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate void
func(struct command * t,struct biltins * bp)1240Sstevel@tonic-gate func(struct command *t, struct biltins *bp)
1250Sstevel@tonic-gate {
1260Sstevel@tonic-gate 	int i;
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate #ifdef TRACE
1290Sstevel@tonic-gate 	tprintf("TRACE- func()\n");
1300Sstevel@tonic-gate #endif
1310Sstevel@tonic-gate 	xechoit(t->t_dcom);
1320Sstevel@tonic-gate 	setname(bp->bname);
1330Sstevel@tonic-gate 	i = blklen(t->t_dcom) - 1;
1340Sstevel@tonic-gate 	if (i < bp->minargs) {
1350Sstevel@tonic-gate 		bferr("Too few arguments");
1360Sstevel@tonic-gate 	}
1370Sstevel@tonic-gate 	if (i > bp->maxargs) {
1380Sstevel@tonic-gate 		bferr("Too many arguments");
1390Sstevel@tonic-gate 	}
1400Sstevel@tonic-gate 	(*bp->bfunct)(t->t_dcom, t);
1410Sstevel@tonic-gate }
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate int
dolabel(void)144356Smuffin dolabel(void)
1450Sstevel@tonic-gate {
1460Sstevel@tonic-gate #ifdef TRACE
1470Sstevel@tonic-gate 	tprintf("TRACE- dolabel()\n");
1480Sstevel@tonic-gate #endif
149356Smuffin 	return (0);
1500Sstevel@tonic-gate }
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate void
doonintr(tchar ** v)1530Sstevel@tonic-gate doonintr(tchar **v)
1540Sstevel@tonic-gate {
1550Sstevel@tonic-gate 	tchar *cp;
1560Sstevel@tonic-gate 	tchar *vv = v[1];
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate #ifdef TRACE
1590Sstevel@tonic-gate 	tprintf("TRACE- doonintr()\n");
1600Sstevel@tonic-gate #endif
1610Sstevel@tonic-gate 	if (parintr == SIG_IGN) {
1620Sstevel@tonic-gate 		return;
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate 	if (setintr && intty) {
1650Sstevel@tonic-gate 		bferr("Can't from terminal");
1660Sstevel@tonic-gate 	}
1670Sstevel@tonic-gate 	cp = gointr, gointr = 0, xfree(cp);
1680Sstevel@tonic-gate 	if (vv == 0) {
1690Sstevel@tonic-gate 		if (setintr) {
1700Sstevel@tonic-gate 			(void) sigblock(sigmask(SIGINT));
1710Sstevel@tonic-gate 		} else {
1720Sstevel@tonic-gate 			(void) signal(SIGINT, SIG_DFL);
1730Sstevel@tonic-gate 		}
1740Sstevel@tonic-gate 		gointr = 0;
1750Sstevel@tonic-gate 	} else if (eq((vv = strip(vv)), S_MINUS)) {
1760Sstevel@tonic-gate 		(void) signal(SIGINT, SIG_IGN);
1770Sstevel@tonic-gate 		gointr = S_MINUS;
1780Sstevel@tonic-gate 	} else {
1790Sstevel@tonic-gate 		gointr = savestr(vv);
1800Sstevel@tonic-gate 		(void) signal(SIGINT, pintr);
1810Sstevel@tonic-gate 	}
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate void
donohup(void)185356Smuffin donohup(void)
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate #ifdef TRACE
1890Sstevel@tonic-gate 	tprintf("TRACE- donohup()\n");
1900Sstevel@tonic-gate #endif
1910Sstevel@tonic-gate 	if (intty) {
1920Sstevel@tonic-gate 		bferr("Can't from terminal");
1930Sstevel@tonic-gate 	}
1940Sstevel@tonic-gate 	if (setintr == 0) {
1950Sstevel@tonic-gate 		(void) signal(SIGHUP, SIG_IGN);
1960Sstevel@tonic-gate #ifdef CC
1970Sstevel@tonic-gate 		submit(getpid());
1980Sstevel@tonic-gate #endif
1990Sstevel@tonic-gate 	}
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate void
dozip(void)203356Smuffin dozip(void)
2040Sstevel@tonic-gate {
2050Sstevel@tonic-gate 	;
2060Sstevel@tonic-gate }
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate void
prvars(void)209356Smuffin prvars(void)
2100Sstevel@tonic-gate {
2110Sstevel@tonic-gate #ifdef TRACE
2120Sstevel@tonic-gate 	tprintf("TRACE- prvars()\n");
2130Sstevel@tonic-gate #endif
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	plist(&shvhed);
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate void
doalias(tchar ** v)2190Sstevel@tonic-gate doalias(tchar **v)
2200Sstevel@tonic-gate {
2210Sstevel@tonic-gate 	struct varent *vp;
2220Sstevel@tonic-gate 	tchar *p;
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate #ifdef TRACE
2250Sstevel@tonic-gate 	tprintf("TRACE- doalias()\n");
2260Sstevel@tonic-gate #endif
2270Sstevel@tonic-gate 	v++;
2280Sstevel@tonic-gate 	p = *v++;
2290Sstevel@tonic-gate 	if (p == 0) {
2300Sstevel@tonic-gate 		plist(&aliases);
2310Sstevel@tonic-gate 	} else if (*v == 0) {
2320Sstevel@tonic-gate 		vp = adrof1(strip(p), &aliases);
2330Sstevel@tonic-gate 		if (vp) {
2340Sstevel@tonic-gate 			blkpr(vp->vec), printf("\n");
2350Sstevel@tonic-gate 		}
2360Sstevel@tonic-gate 	} else {
2370Sstevel@tonic-gate 		if (eq(p, S_alias) ||
2380Sstevel@tonic-gate 		    eq(p, S_unalias)) {
2390Sstevel@tonic-gate 			setname(p);
2400Sstevel@tonic-gate 			bferr("Too dangerous to alias that");
2410Sstevel@tonic-gate 		}
2420Sstevel@tonic-gate 		set1(strip(p), saveblk(v), &aliases);
2430Sstevel@tonic-gate 	}
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate void
unalias(tchar ** v)2470Sstevel@tonic-gate unalias(tchar **v)
2480Sstevel@tonic-gate {
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate #ifdef TRACE
2510Sstevel@tonic-gate 	tprintf("TRACE- unalias()\n");
2520Sstevel@tonic-gate #endif
2530Sstevel@tonic-gate 	unset1(v, &aliases);
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate void
dologout(void)257356Smuffin dologout(void)
2580Sstevel@tonic-gate {
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate #ifdef TRACE
2610Sstevel@tonic-gate 	tprintf("TRACE- dologout()\n");
2620Sstevel@tonic-gate #endif
2630Sstevel@tonic-gate 	islogin();
2640Sstevel@tonic-gate 	goodbye();
2650Sstevel@tonic-gate }
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate void
dologin(tchar ** v)2680Sstevel@tonic-gate dologin(tchar **v)
2690Sstevel@tonic-gate {
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	char *v_;	/* work */
2720Sstevel@tonic-gate #ifdef TRACE
2730Sstevel@tonic-gate 	tprintf("TRACE- dologin()\n");
2740Sstevel@tonic-gate #endif
2750Sstevel@tonic-gate 	islogin();
2760Sstevel@tonic-gate 	rechist();
2770Sstevel@tonic-gate 	(void) signal(SIGTERM, parterm);
2780Sstevel@tonic-gate 	if (v[1] != NULL) {
2790Sstevel@tonic-gate 		v_ = tstostr(NULL, v[1]);	/* No need to free */
2800Sstevel@tonic-gate 	} else {
2810Sstevel@tonic-gate 		v_ = 0;
2820Sstevel@tonic-gate 	}
2830Sstevel@tonic-gate 	execl("/bin/login", "login", v_, 0);
2840Sstevel@tonic-gate 	untty();
2850Sstevel@tonic-gate 	exit(1);
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate #ifdef NEWGRP
2890Sstevel@tonic-gate void
donewgrp(tchar ** v)2900Sstevel@tonic-gate donewgrp(tchar **v)
2910Sstevel@tonic-gate {
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	char *v_;	/* work */
2940Sstevel@tonic-gate #ifdef TRACE
2950Sstevel@tonic-gate 	tprintf("TRACE- donewgrp()\n");
2960Sstevel@tonic-gate #endif
2970Sstevel@tonic-gate 	if (chkstop == 0 && setintr) {
2980Sstevel@tonic-gate 		panystop(0);
2990Sstevel@tonic-gate 	}
3000Sstevel@tonic-gate 	(void) signal(SIGTERM, parterm);
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	if (v[1] != NULL) {
3030Sstevel@tonic-gate 		v_ = tstostr(NOSTR, v[1]);	/* No need to free */
3040Sstevel@tonic-gate 	} else {
3050Sstevel@tonic-gate 		v_ = 0;
3060Sstevel@tonic-gate 	}
3070Sstevel@tonic-gate 	execl("/bin/newgrp", "newgrp", v_, 0);
3080Sstevel@tonic-gate 	execl("/usr/bin/newgrp", "newgrp", v_, 0);
3090Sstevel@tonic-gate 	untty();
3100Sstevel@tonic-gate 	exit(1);
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate #endif
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate void
islogin(void)315356Smuffin islogin(void)
3160Sstevel@tonic-gate {
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate #ifdef TRACE
3190Sstevel@tonic-gate 	tprintf("TRACE- islogin()\n");
3200Sstevel@tonic-gate #endif
3210Sstevel@tonic-gate 	if (chkstop == 0 && setintr) {
3220Sstevel@tonic-gate 		panystop(0);
3230Sstevel@tonic-gate 	}
3240Sstevel@tonic-gate 	if (loginsh) {
3250Sstevel@tonic-gate 		return;
3260Sstevel@tonic-gate 	}
3270Sstevel@tonic-gate 	error("Not login shell");
3280Sstevel@tonic-gate }
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate void
doif(tchar ** v,struct command * kp)3310Sstevel@tonic-gate doif(tchar **v, struct command *kp)
3320Sstevel@tonic-gate {
3330Sstevel@tonic-gate 	int i;
3340Sstevel@tonic-gate 	tchar **vv;
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate #ifdef TRACE
3370Sstevel@tonic-gate 	tprintf("TRACE- doif()\n");
3380Sstevel@tonic-gate #endif
3390Sstevel@tonic-gate 	v++;
3400Sstevel@tonic-gate 	i = exp(&v);
3410Sstevel@tonic-gate 	vv = v;
3420Sstevel@tonic-gate 	if (*vv == NOSTR) {
3430Sstevel@tonic-gate 		bferr("Empty if");
3440Sstevel@tonic-gate 	}
3450Sstevel@tonic-gate 	if (eq(*vv, S_then)) {
3460Sstevel@tonic-gate 		if (*++vv) {
3470Sstevel@tonic-gate 			bferr("Improper then");
3480Sstevel@tonic-gate 		}
3490Sstevel@tonic-gate 		setname(S_then);
3500Sstevel@tonic-gate 		/*
3510Sstevel@tonic-gate 		 * If expression was zero, then scan to else,
3520Sstevel@tonic-gate 		 * otherwise just fall into following code.
3530Sstevel@tonic-gate 		 */
3540Sstevel@tonic-gate 		if (!i) {
3550Sstevel@tonic-gate 			search(ZIF, 0);
3560Sstevel@tonic-gate 		}
3570Sstevel@tonic-gate 		return;
3580Sstevel@tonic-gate 	}
3590Sstevel@tonic-gate 	/*
3600Sstevel@tonic-gate 	 * Simple command attached to this if.
3610Sstevel@tonic-gate 	 * Left shift the node in this tree, munging it
3620Sstevel@tonic-gate 	 * so we can reexecute it.
3630Sstevel@tonic-gate 	 */
3640Sstevel@tonic-gate 	if (i) {
3650Sstevel@tonic-gate 		lshift(kp->t_dcom, vv - kp->t_dcom);
3660Sstevel@tonic-gate 		reexecute(kp);
3670Sstevel@tonic-gate 		donefds();
3680Sstevel@tonic-gate 	}
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate /*
3720Sstevel@tonic-gate  * Reexecute a command, being careful not
3730Sstevel@tonic-gate  * to redo i/o redirection, which is already set up.
3740Sstevel@tonic-gate  */
3750Sstevel@tonic-gate void
reexecute(struct command * kp)3760Sstevel@tonic-gate reexecute(struct command *kp)
3770Sstevel@tonic-gate {
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate #ifdef TRACE
3800Sstevel@tonic-gate 	tprintf("TRACE- reexecute()\n");
3810Sstevel@tonic-gate #endif
3820Sstevel@tonic-gate 	kp->t_dflg &= FSAVE;
3830Sstevel@tonic-gate 	kp->t_dflg |= FREDO;
3840Sstevel@tonic-gate 	/*
3850Sstevel@tonic-gate 	 * If tty is still ours to arbitrate, arbitrate it;
3860Sstevel@tonic-gate 	 * otherwise dont even set pgrp's as the jobs would
3870Sstevel@tonic-gate 	 * then have no way to get the tty (we can't give it
3880Sstevel@tonic-gate 	 * to them, and our parent wouldn't know their pgrp, etc.
3890Sstevel@tonic-gate 	 */
3900Sstevel@tonic-gate 	execute(kp, tpgrp > 0 ? tpgrp : -1);
3910Sstevel@tonic-gate }
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate void
doelse(void)394356Smuffin doelse(void)
3950Sstevel@tonic-gate {
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate #ifdef TRACE
3980Sstevel@tonic-gate 	tprintf("TRACE- doelse()\n");
3990Sstevel@tonic-gate #endif
4000Sstevel@tonic-gate 	search(ZELSE, 0);
4010Sstevel@tonic-gate }
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate void
dogoto(tchar ** v)4040Sstevel@tonic-gate dogoto(tchar **v)
4050Sstevel@tonic-gate {
4060Sstevel@tonic-gate 	struct whyle *wp;
4070Sstevel@tonic-gate 	tchar *lp;
4080Sstevel@tonic-gate #ifdef TRACE
4090Sstevel@tonic-gate 	tprintf("TRACE- dogoto()\n");
4100Sstevel@tonic-gate #endif
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	/*
4130Sstevel@tonic-gate 	 * While we still can, locate any unknown ends of existing loops.
4140Sstevel@tonic-gate 	 * This obscure code is the WORST result of the fact that we
4150Sstevel@tonic-gate 	 * don't really parse.
4160Sstevel@tonic-gate 	 */
4170Sstevel@tonic-gate 	for (wp = whyles; wp; wp = wp->w_next) {
4180Sstevel@tonic-gate 		if (wp->w_end == 0) {
4190Sstevel@tonic-gate 			search(ZBREAK, 0);
4200Sstevel@tonic-gate 			wp->w_end = btell();
4210Sstevel@tonic-gate 		} else {
4220Sstevel@tonic-gate 			bseek(wp->w_end);
4230Sstevel@tonic-gate 		}
4240Sstevel@tonic-gate 	}
4250Sstevel@tonic-gate 	search(ZGOTO, 0, lp = globone(v[1]));
4260Sstevel@tonic-gate 	xfree(lp);
4270Sstevel@tonic-gate 	/*
4280Sstevel@tonic-gate 	 * Eliminate loops which were exited.
4290Sstevel@tonic-gate 	 */
4300Sstevel@tonic-gate 	wfree();
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate void
doswitch(tchar ** v)4340Sstevel@tonic-gate doswitch(tchar **v)
4350Sstevel@tonic-gate {
4360Sstevel@tonic-gate 	tchar *cp, *lp;
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate #ifdef TRACE
4390Sstevel@tonic-gate 	tprintf("TRACE- doswitch()\n");
4400Sstevel@tonic-gate #endif
4410Sstevel@tonic-gate 	v++;
4420Sstevel@tonic-gate 	if (!*v || *(*v++) != '(') {
4430Sstevel@tonic-gate 		goto syntax;
4440Sstevel@tonic-gate 	}
4450Sstevel@tonic-gate 	cp = **v == ')' ? S_ : *v++;
4460Sstevel@tonic-gate 	if (*(*v++) != ')') {
4470Sstevel@tonic-gate 		v--;
4480Sstevel@tonic-gate 	}
4490Sstevel@tonic-gate 	if (*v) {
4500Sstevel@tonic-gate syntax:
4510Sstevel@tonic-gate 		error("Syntax error");
4520Sstevel@tonic-gate 	}
4530Sstevel@tonic-gate 	search(ZSWITCH, 0, lp = globone(cp));
4540Sstevel@tonic-gate 	xfree(lp);
4550Sstevel@tonic-gate }
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate void
dobreak(void)458356Smuffin dobreak(void)
4590Sstevel@tonic-gate {
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate #ifdef TRACE
4620Sstevel@tonic-gate 	tprintf("TRACE- dobreak()\n");
4630Sstevel@tonic-gate #endif
4640Sstevel@tonic-gate 	if (whyles) {
4650Sstevel@tonic-gate 		toend();
4660Sstevel@tonic-gate 	} else {
4670Sstevel@tonic-gate 		bferr("Not in while/foreach");
4680Sstevel@tonic-gate 	}
4690Sstevel@tonic-gate }
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate void
doexit(tchar ** v)4720Sstevel@tonic-gate doexit(tchar **v)
4730Sstevel@tonic-gate {
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate #ifdef TRACE
4760Sstevel@tonic-gate 	tprintf("TRACE- doexit()\n");
4770Sstevel@tonic-gate #endif
4780Sstevel@tonic-gate 	if (chkstop == 0) {
4790Sstevel@tonic-gate 		panystop(0);
4800Sstevel@tonic-gate 	}
4810Sstevel@tonic-gate 	/*
4820Sstevel@tonic-gate 	 * Don't DEMAND parentheses here either.
4830Sstevel@tonic-gate 	 */
4840Sstevel@tonic-gate 	v++;
4850Sstevel@tonic-gate 	if (*v) {
4860Sstevel@tonic-gate 		set(S_status, putn(exp(&v)));
4870Sstevel@tonic-gate 		if (*v) {
4880Sstevel@tonic-gate 			bferr("Expression syntax");
4890Sstevel@tonic-gate 		}
4900Sstevel@tonic-gate 	}
4910Sstevel@tonic-gate 	btoeof();
4920Sstevel@tonic-gate 	if (intty) {
4930Sstevel@tonic-gate 		(void) close(SHIN);
4940Sstevel@tonic-gate 		unsetfd(SHIN);
4950Sstevel@tonic-gate 	}
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate void
doforeach(tchar ** v)4990Sstevel@tonic-gate doforeach(tchar **v)
5000Sstevel@tonic-gate {
5010Sstevel@tonic-gate 	tchar *cp;
5020Sstevel@tonic-gate 	struct whyle *nwp;
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate #ifdef TRACE
5050Sstevel@tonic-gate 	tprintf("TRACE- doforeach()\n");
5060Sstevel@tonic-gate #endif
5070Sstevel@tonic-gate 	v++;
5080Sstevel@tonic-gate 	cp = strip(*v);
5090Sstevel@tonic-gate 	while (*cp && alnum(*cp)) {
5100Sstevel@tonic-gate 		cp++;
5110Sstevel@tonic-gate 	}
512*2182Schin 	if (*cp || strlen_(*v) >= MAX_VAR_LEN || !letter(**v)) {
5130Sstevel@tonic-gate 		bferr("Invalid variable");
5140Sstevel@tonic-gate 	}
5150Sstevel@tonic-gate 	cp = *v++;
5160Sstevel@tonic-gate 	if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') {
5170Sstevel@tonic-gate 		bferr("Words not ()'ed");
5180Sstevel@tonic-gate 	}
5190Sstevel@tonic-gate 	v++;
5200Sstevel@tonic-gate 	gflag = 0, tglob(v);
5210Sstevel@tonic-gate 	v = glob(v);
5220Sstevel@tonic-gate 	if (v == 0) {
5230Sstevel@tonic-gate 		bferr("No match");
5240Sstevel@tonic-gate 	}
525559Snakanon 	nwp = (struct whyle *)xcalloc(1, sizeof (*nwp));
5260Sstevel@tonic-gate 	nwp->w_fe = nwp->w_fe0 = v; gargv = 0;
5270Sstevel@tonic-gate 	nwp->w_start = btell();
5280Sstevel@tonic-gate 	nwp->w_fename = savestr(cp);
5290Sstevel@tonic-gate 	nwp->w_next = whyles;
5300Sstevel@tonic-gate 	whyles = nwp;
5310Sstevel@tonic-gate 	/*
5320Sstevel@tonic-gate 	 * Pre-read the loop so as to be more
5330Sstevel@tonic-gate 	 * comprehensible to a terminal user.
5340Sstevel@tonic-gate 	 */
5350Sstevel@tonic-gate 	if (intty) {
5360Sstevel@tonic-gate 		preread_();
5370Sstevel@tonic-gate 	}
5380Sstevel@tonic-gate 	doagain();
5390Sstevel@tonic-gate }
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate void
dowhile(tchar ** v)5420Sstevel@tonic-gate dowhile(tchar **v)
5430Sstevel@tonic-gate {
5440Sstevel@tonic-gate 	int status;
5450Sstevel@tonic-gate 	bool again = whyles != 0 && whyles->w_start == lineloc &&
5460Sstevel@tonic-gate 	    whyles->w_fename == 0;
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate #ifdef TRACE
5490Sstevel@tonic-gate 	tprintf("TRACE- dowhile()\n");
5500Sstevel@tonic-gate #endif
5510Sstevel@tonic-gate 	v++;
5520Sstevel@tonic-gate 	/*
5530Sstevel@tonic-gate 	 * Implement prereading here also, taking care not to
5540Sstevel@tonic-gate 	 * evaluate the expression before the loop has been read up
5550Sstevel@tonic-gate 	 * from a terminal.
5560Sstevel@tonic-gate 	 */
5570Sstevel@tonic-gate 	if (intty && !again) {
5580Sstevel@tonic-gate 		status = !exp0(&v, 1);
5590Sstevel@tonic-gate 	} else {
5600Sstevel@tonic-gate 		status = !exp(&v);
5610Sstevel@tonic-gate 	}
5620Sstevel@tonic-gate 	if (*v) {
5630Sstevel@tonic-gate 		bferr("Expression syntax");
5640Sstevel@tonic-gate 	}
5650Sstevel@tonic-gate 	if (!again) {
566559Snakanon 		struct whyle *nwp = (struct whyle *)xcalloc(1, sizeof (*nwp));
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 		nwp->w_start = lineloc;
5690Sstevel@tonic-gate 		nwp->w_end = 0;
5700Sstevel@tonic-gate 		nwp->w_next = whyles;
5710Sstevel@tonic-gate 		whyles = nwp;
5720Sstevel@tonic-gate 		if (intty) {
5730Sstevel@tonic-gate 			/*
5740Sstevel@tonic-gate 			 * The tty preread
5750Sstevel@tonic-gate 			 */
5760Sstevel@tonic-gate 			preread_();
5770Sstevel@tonic-gate 			doagain();
5780Sstevel@tonic-gate 			return;
5790Sstevel@tonic-gate 		}
5800Sstevel@tonic-gate 	}
5810Sstevel@tonic-gate 	if (status) {
5820Sstevel@tonic-gate 		/* We ain't gonna loop no more, no more! */
5830Sstevel@tonic-gate 		toend();
5840Sstevel@tonic-gate 	}
5850Sstevel@tonic-gate }
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate void
preread_(void)588356Smuffin preread_(void)
5890Sstevel@tonic-gate {
5900Sstevel@tonic-gate #ifdef TRACE
5910Sstevel@tonic-gate 	tprintf("TRACE- preread()\n");
5920Sstevel@tonic-gate #endif
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	whyles->w_end = -1;
5950Sstevel@tonic-gate 	if (setintr) {
5960Sstevel@tonic-gate 		(void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
5970Sstevel@tonic-gate 	}
5980Sstevel@tonic-gate 	search(ZBREAK, 0);
5990Sstevel@tonic-gate 	if (setintr) {
6000Sstevel@tonic-gate 		(void) sigblock(sigmask(SIGINT));
6010Sstevel@tonic-gate 	}
6020Sstevel@tonic-gate 	whyles->w_end = btell();
6030Sstevel@tonic-gate }
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate void
doend(void)606356Smuffin doend(void)
6070Sstevel@tonic-gate {
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate #ifdef TRACE
6100Sstevel@tonic-gate 	tprintf("TRACE- doend()\n");
6110Sstevel@tonic-gate #endif
6120Sstevel@tonic-gate 	if (!whyles) {
6130Sstevel@tonic-gate 		bferr("Not in while/foreach");
6140Sstevel@tonic-gate 	}
6150Sstevel@tonic-gate 	whyles->w_end = btell();
6160Sstevel@tonic-gate 	doagain();
6170Sstevel@tonic-gate }
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate void
docontin(void)620356Smuffin docontin(void)
6210Sstevel@tonic-gate {
6220Sstevel@tonic-gate #ifdef TRACE
6230Sstevel@tonic-gate 	tprintf("TRACE- docontin()\n");
6240Sstevel@tonic-gate #endif
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	if (!whyles) {
6270Sstevel@tonic-gate 		bferr("Not in while/foreach");
6280Sstevel@tonic-gate 	}
6290Sstevel@tonic-gate 	doagain();
6300Sstevel@tonic-gate }
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate void
doagain(void)633356Smuffin doagain(void)
6340Sstevel@tonic-gate {
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate #ifdef TRACE
6370Sstevel@tonic-gate 	tprintf("TRACE- doagain()\n");
6380Sstevel@tonic-gate #endif
6390Sstevel@tonic-gate 	/* Repeating a while is simple */
6400Sstevel@tonic-gate 	if (whyles->w_fename == 0) {
6410Sstevel@tonic-gate 		bseek(whyles->w_start);
6420Sstevel@tonic-gate 		return;
6430Sstevel@tonic-gate 	}
6440Sstevel@tonic-gate 	/*
6450Sstevel@tonic-gate 	 * The foreach variable list actually has a spurious word
6460Sstevel@tonic-gate 	 * ")" at the end of the w_fe list.  Thus we are at the
6470Sstevel@tonic-gate 	 * of the list if one word beyond this is 0.
6480Sstevel@tonic-gate 	 */
6490Sstevel@tonic-gate 	if (!whyles->w_fe[1]) {
6500Sstevel@tonic-gate 		dobreak();
6510Sstevel@tonic-gate 		return;
6520Sstevel@tonic-gate 	}
6530Sstevel@tonic-gate 	set(whyles->w_fename, savestr(*whyles->w_fe++));
6540Sstevel@tonic-gate 	bseek(whyles->w_start);
6550Sstevel@tonic-gate }
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate void
dorepeat(tchar ** v,struct command * kp)6580Sstevel@tonic-gate dorepeat(tchar **v, struct command *kp)
6590Sstevel@tonic-gate {
6600Sstevel@tonic-gate 	int i, omask;
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate #ifdef TRACE
6630Sstevel@tonic-gate 	tprintf("TRACE- dorepeat()\n");
6640Sstevel@tonic-gate #endif
6650Sstevel@tonic-gate 	i = getn(v[1]);
6660Sstevel@tonic-gate 	if (setintr) {
6670Sstevel@tonic-gate 		omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
6680Sstevel@tonic-gate 	}
6690Sstevel@tonic-gate 	lshift(v, 2);
6700Sstevel@tonic-gate 	while (i > 0) {
6710Sstevel@tonic-gate 		if (setintr) {
6720Sstevel@tonic-gate 			(void) sigsetmask(omask);
6730Sstevel@tonic-gate 		}
6740Sstevel@tonic-gate 		reexecute(kp);
6750Sstevel@tonic-gate 		--i;
6760Sstevel@tonic-gate 	}
6770Sstevel@tonic-gate 	donefds();
6780Sstevel@tonic-gate 	if (setintr) {
6790Sstevel@tonic-gate 		(void) sigsetmask(omask);
6800Sstevel@tonic-gate 	}
6810Sstevel@tonic-gate }
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate void
doswbrk(void)684356Smuffin doswbrk(void)
6850Sstevel@tonic-gate {
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate #ifdef TRACE
6880Sstevel@tonic-gate 	tprintf("TRACE- doswbrk()\n");
6890Sstevel@tonic-gate #endif
6900Sstevel@tonic-gate 	search(ZBRKSW, 0);
6910Sstevel@tonic-gate }
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate int
srchx(tchar * cp)6940Sstevel@tonic-gate srchx(tchar *cp)
6950Sstevel@tonic-gate {
6960Sstevel@tonic-gate 	struct srch *sp, *sp1, *sp2;
6970Sstevel@tonic-gate 	int i;
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate #ifdef TRACE
7000Sstevel@tonic-gate 	tprintf("TRACE- srchx()\n");
7010Sstevel@tonic-gate #endif
7020Sstevel@tonic-gate 	/*
7030Sstevel@tonic-gate 	 * Binary search
7040Sstevel@tonic-gate 	 * Sp1 is the beginning of the current search range.
7050Sstevel@tonic-gate 	 * Sp2 is one past the end.
7060Sstevel@tonic-gate 	 */
7070Sstevel@tonic-gate 	for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2; ) {
7080Sstevel@tonic-gate 		sp = sp1 + (sp2 - sp1 >> 1);
7090Sstevel@tonic-gate 		if ((i = *cp - *sp->s_name) == 0 &&
7100Sstevel@tonic-gate 		    (i = strcmp_(cp, sp->s_name)) == 0) {
7110Sstevel@tonic-gate 			return (sp->s_value);
7120Sstevel@tonic-gate 		}
7130Sstevel@tonic-gate 		if (i < 0) {
7140Sstevel@tonic-gate 			sp2 = sp;
7150Sstevel@tonic-gate 		} else {
7160Sstevel@tonic-gate 			sp1 = sp + 1;
7170Sstevel@tonic-gate 		}
7180Sstevel@tonic-gate 	}
7190Sstevel@tonic-gate 	return (-1);
7200Sstevel@tonic-gate }
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate tchar Stype;
7230Sstevel@tonic-gate tchar *Sgoal;
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate /*VARARGS2*/
7260Sstevel@tonic-gate void
search(type,level,goal)7270Sstevel@tonic-gate search(type, level, goal)
7280Sstevel@tonic-gate 	int type; int level; tchar *goal;
7290Sstevel@tonic-gate {
7300Sstevel@tonic-gate 	tchar wordbuf[BUFSIZ];
7310Sstevel@tonic-gate 	tchar *aword = wordbuf;
7320Sstevel@tonic-gate 	tchar *cp;
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate #ifdef TRACE
7350Sstevel@tonic-gate 	tprintf("TRACE- search()\n");
7360Sstevel@tonic-gate #endif
7370Sstevel@tonic-gate 	Stype = type; Sgoal = goal;
7380Sstevel@tonic-gate 	if (type == ZGOTO) {
7390Sstevel@tonic-gate 		bseek((off_t)0);
7400Sstevel@tonic-gate 	}
7410Sstevel@tonic-gate 	do {
7420Sstevel@tonic-gate 		if (intty && fseekp == feobp) {
7430Sstevel@tonic-gate 			printf("? "), flush();
7440Sstevel@tonic-gate 		}
7450Sstevel@tonic-gate 		aword[0] = 0;
7460Sstevel@tonic-gate 		(void) getword(aword);
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 		switch (srchx(aword)) {
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 		case ZELSE:
7510Sstevel@tonic-gate 			if (level == 0 && type == ZIF) {
7520Sstevel@tonic-gate 				return;
7530Sstevel@tonic-gate 			}
7540Sstevel@tonic-gate 			break;
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 		case ZIF:
7570Sstevel@tonic-gate 			while (getword(aword)) {
7580Sstevel@tonic-gate 				continue;
7590Sstevel@tonic-gate 			}
7600Sstevel@tonic-gate 			if ((type == ZIF || type == ZELSE) &&
7610Sstevel@tonic-gate 			    eq(aword, S_then)) {
7620Sstevel@tonic-gate 				level++;
7630Sstevel@tonic-gate 			}
7640Sstevel@tonic-gate 			break;
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 		case ZENDIF:
7670Sstevel@tonic-gate 			if (type == ZIF || type == ZELSE) {
7680Sstevel@tonic-gate 				level--;
7690Sstevel@tonic-gate 			}
7700Sstevel@tonic-gate 			break;
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 		case ZFOREACH:
7730Sstevel@tonic-gate 		case ZWHILE:
7740Sstevel@tonic-gate 			if (type == ZBREAK) {
7750Sstevel@tonic-gate 				level++;
7760Sstevel@tonic-gate 			}
7770Sstevel@tonic-gate 			break;
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 		case ZEND:
7800Sstevel@tonic-gate 			if (type == ZBREAK) {
7810Sstevel@tonic-gate 				level--;
7820Sstevel@tonic-gate 			}
7830Sstevel@tonic-gate 			break;
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 		case ZSWITCH:
7860Sstevel@tonic-gate 			if (type == ZSWITCH || type == ZBRKSW) {
7870Sstevel@tonic-gate 				level++;
7880Sstevel@tonic-gate 			}
7890Sstevel@tonic-gate 			break;
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 		case ZENDSW:
7920Sstevel@tonic-gate 			if (type == ZSWITCH || type == ZBRKSW) {
7930Sstevel@tonic-gate 				level--;
7940Sstevel@tonic-gate 			}
7950Sstevel@tonic-gate 			break;
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 		case ZLABEL:
7980Sstevel@tonic-gate 			if (type == ZGOTO && getword(aword) &&
7990Sstevel@tonic-gate 			    eq(aword, goal)) {
8000Sstevel@tonic-gate 				level = -1;
8010Sstevel@tonic-gate 			}
8020Sstevel@tonic-gate 			break;
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 		default:
8050Sstevel@tonic-gate 			if (type != ZGOTO && (type != ZSWITCH || level != 0)) {
8060Sstevel@tonic-gate 				break;
8070Sstevel@tonic-gate 			}
8080Sstevel@tonic-gate 			if (lastchr(aword) != ':') {
8090Sstevel@tonic-gate 				break;
8100Sstevel@tonic-gate 			}
8110Sstevel@tonic-gate 			aword[strlen_(aword) - 1] = 0;
8120Sstevel@tonic-gate 			if (type == ZGOTO && eq(aword, goal) ||
8130Sstevel@tonic-gate 			    type == ZSWITCH && eq(aword, S_default)) {
8140Sstevel@tonic-gate 				level = -1;
8150Sstevel@tonic-gate 			}
8160Sstevel@tonic-gate 			break;
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 		case ZCASE:
8190Sstevel@tonic-gate 			if (type != ZSWITCH || level != 0) {
8200Sstevel@tonic-gate 				break;
8210Sstevel@tonic-gate 			}
8220Sstevel@tonic-gate 			(void) getword(aword);
8230Sstevel@tonic-gate 			if (lastchr(aword) == ':') {
8240Sstevel@tonic-gate 				aword[strlen_(aword) - 1] = 0;
8250Sstevel@tonic-gate 			}
8260Sstevel@tonic-gate 			cp = strip(Dfix1(aword));
8270Sstevel@tonic-gate 			if (Gmatch(goal, cp)) {
8280Sstevel@tonic-gate 				level = -1;
8290Sstevel@tonic-gate 			}
8300Sstevel@tonic-gate 			xfree(cp);
8310Sstevel@tonic-gate 			break;
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 		case ZDEFAULT:
8340Sstevel@tonic-gate 			if (type == ZSWITCH && level == 0) {
8350Sstevel@tonic-gate 				level = -1;
8360Sstevel@tonic-gate 			}
8370Sstevel@tonic-gate 			break;
8380Sstevel@tonic-gate 		}
8390Sstevel@tonic-gate 		(void) getword(NOSTR);
8400Sstevel@tonic-gate 	} while (level >= 0);
8410Sstevel@tonic-gate }
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate int
getword(tchar * wp)8440Sstevel@tonic-gate getword(tchar *wp)
8450Sstevel@tonic-gate {
8460Sstevel@tonic-gate 	int found = 0;
8470Sstevel@tonic-gate 	int c, d;
8480Sstevel@tonic-gate #ifdef TRACE
8490Sstevel@tonic-gate 	tprintf("TRACE- getword()\n");
8500Sstevel@tonic-gate #endif
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	c = readc(1);
8530Sstevel@tonic-gate 	d = 0;
8540Sstevel@tonic-gate 	do {
8550Sstevel@tonic-gate 		while (issp(c)) {
8560Sstevel@tonic-gate 			c = readc(1);
8570Sstevel@tonic-gate 		}
8580Sstevel@tonic-gate 		if (c == '#') {
8590Sstevel@tonic-gate 			do {
8600Sstevel@tonic-gate 				c = readc(1);
8610Sstevel@tonic-gate 			} while (c >= 0 && c != '\n');
8620Sstevel@tonic-gate 		}
8630Sstevel@tonic-gate 		if (c < 0) {
8640Sstevel@tonic-gate 			goto past;
8650Sstevel@tonic-gate 		}
8660Sstevel@tonic-gate 		if (c == '\n') {
8670Sstevel@tonic-gate 			if (wp) {
8680Sstevel@tonic-gate 				break;
8690Sstevel@tonic-gate 			}
8700Sstevel@tonic-gate 			return (0);
8710Sstevel@tonic-gate 		}
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate 		/* ( and ) form separate words */
8740Sstevel@tonic-gate 		if (c == '(' || c == ')') {
8750Sstevel@tonic-gate 			return (1);
8760Sstevel@tonic-gate 		}
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 		unreadc(c);
8790Sstevel@tonic-gate 		found = 1;
8800Sstevel@tonic-gate 		do {
8810Sstevel@tonic-gate 			c = readc(1);
8820Sstevel@tonic-gate 			if (c == '\\' && (c = readc(1)) == '\n') {
8830Sstevel@tonic-gate 				c = ' ';
8840Sstevel@tonic-gate 			}
8850Sstevel@tonic-gate 			if (c == '\'' || c == '"') {
8860Sstevel@tonic-gate 				if (d == 0) {
8870Sstevel@tonic-gate 					d = c;
8880Sstevel@tonic-gate 				} else if (d == c) {
8890Sstevel@tonic-gate 					d = 0;
8900Sstevel@tonic-gate 				}
8910Sstevel@tonic-gate 			}
8920Sstevel@tonic-gate 			if (c < 0) {
8930Sstevel@tonic-gate 				goto past;
8940Sstevel@tonic-gate 			}
8950Sstevel@tonic-gate 			if (wp) {
8960Sstevel@tonic-gate 				*wp++ = c;
8970Sstevel@tonic-gate 			}
8980Sstevel@tonic-gate 		} while ((d || !issp(c) && c != '(' && c != ')') && c != '\n');
8990Sstevel@tonic-gate 	} while (wp == 0);
9000Sstevel@tonic-gate 	unreadc(c);
9010Sstevel@tonic-gate 	if (found) {
9020Sstevel@tonic-gate 		*--wp = 0;
9030Sstevel@tonic-gate 	}
9040Sstevel@tonic-gate 	return (found);
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate past:
9070Sstevel@tonic-gate 	switch (Stype) {
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	case ZIF:
9100Sstevel@tonic-gate 		bferr("then/endif not found");
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 	case ZELSE:
9130Sstevel@tonic-gate 		bferr("endif not found");
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 	case ZBRKSW:
9160Sstevel@tonic-gate 	case ZSWITCH:
9170Sstevel@tonic-gate 		bferr("endsw not found");
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 	case ZBREAK:
9200Sstevel@tonic-gate 		bferr("end not found");
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 	case ZGOTO:
9230Sstevel@tonic-gate 		setname(Sgoal);
9240Sstevel@tonic-gate 		bferr("label not found");
9250Sstevel@tonic-gate 	}
9260Sstevel@tonic-gate 	/*NOTREACHED*/
927356Smuffin 
928356Smuffin 	return (0);
9290Sstevel@tonic-gate }
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate void
toend(void)932356Smuffin toend(void)
9330Sstevel@tonic-gate {
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate #ifdef TRACE
9360Sstevel@tonic-gate 	tprintf("TRACE- toend()\n");
9370Sstevel@tonic-gate #endif
9380Sstevel@tonic-gate 	if (whyles->w_end == 0) {
9390Sstevel@tonic-gate 		search(ZBREAK, 0);
9400Sstevel@tonic-gate 		whyles->w_end = btell() - 1;
9410Sstevel@tonic-gate 	} else {
9420Sstevel@tonic-gate 		bseek(whyles->w_end);
9430Sstevel@tonic-gate 	}
9440Sstevel@tonic-gate 	wfree();
9450Sstevel@tonic-gate }
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate void
wfree(void)948356Smuffin wfree(void)
9490Sstevel@tonic-gate {
9500Sstevel@tonic-gate 	long o = btell();
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate #ifdef TRACE
9530Sstevel@tonic-gate 	tprintf("TRACE- wfree()\n");
9540Sstevel@tonic-gate #endif
9550Sstevel@tonic-gate 	while (whyles) {
9560Sstevel@tonic-gate 		struct whyle *wp = whyles;
9570Sstevel@tonic-gate 		struct whyle *nwp = wp->w_next;
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 		if (o >= wp->w_start && (wp->w_end == 0 || o < wp->w_end)) {
9600Sstevel@tonic-gate 			break;
9610Sstevel@tonic-gate 		}
9620Sstevel@tonic-gate 		if (wp->w_fe0) {
9630Sstevel@tonic-gate 			blkfree(wp->w_fe0);
9640Sstevel@tonic-gate 		}
9650Sstevel@tonic-gate 		if (wp->w_fename) {
9660Sstevel@tonic-gate 			xfree(wp->w_fename);
9670Sstevel@tonic-gate 		}
9680Sstevel@tonic-gate 		xfree((char *)wp);
9690Sstevel@tonic-gate 		whyles = nwp;
9700Sstevel@tonic-gate 	}
9710Sstevel@tonic-gate }
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate void
doecho(tchar ** v)9740Sstevel@tonic-gate doecho(tchar **v)
9750Sstevel@tonic-gate {
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate #ifdef TRACE
9780Sstevel@tonic-gate 	tprintf("TRACE- doecho()\n");
9790Sstevel@tonic-gate #endif
9800Sstevel@tonic-gate 	echo(' ', v);
9810Sstevel@tonic-gate }
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate void
doglob(tchar ** v)9840Sstevel@tonic-gate doglob(tchar **v)
9850Sstevel@tonic-gate {
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate #ifdef TRACE
9880Sstevel@tonic-gate 	tprintf("TRACE- doglob()\n");
9890Sstevel@tonic-gate #endif
9900Sstevel@tonic-gate 	echo(0, v);
9910Sstevel@tonic-gate 	flush();
9920Sstevel@tonic-gate }
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate void
echo(tchar sep,tchar ** v)9950Sstevel@tonic-gate echo(tchar sep, tchar **v)
9960Sstevel@tonic-gate {
9970Sstevel@tonic-gate 	tchar *cp;
9980Sstevel@tonic-gate 	int nonl = 0;
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate #ifdef TRACE
10010Sstevel@tonic-gate 	tprintf("TRACE- echo()\n");
10020Sstevel@tonic-gate #endif
10030Sstevel@tonic-gate 	if (setintr) {
10040Sstevel@tonic-gate 		(void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
10050Sstevel@tonic-gate 	}
10060Sstevel@tonic-gate 	v++;
10070Sstevel@tonic-gate 	if (*v == 0) {
10080Sstevel@tonic-gate 		/*
10090Sstevel@tonic-gate 		 * echo command needs to have newline when there are no
10100Sstevel@tonic-gate 		 * flags or arguments.  glob should have no newline.  If
10110Sstevel@tonic-gate 		 * the separator is a blank, we are doing an echo.  If the
10120Sstevel@tonic-gate 		 * separator is zero, we are globbing.
10130Sstevel@tonic-gate 		 */
10140Sstevel@tonic-gate 		if (sep == (tchar)' ')
10150Sstevel@tonic-gate 			Putchar('\n');
10160Sstevel@tonic-gate 		return;
10170Sstevel@tonic-gate 	}
10180Sstevel@tonic-gate 	gflag = 0, tglob(v);
10190Sstevel@tonic-gate 	if (gflag) {
10200Sstevel@tonic-gate 		v = glob(v);
10210Sstevel@tonic-gate 		if (v == 0) {
10220Sstevel@tonic-gate 			bferr("No match");
10230Sstevel@tonic-gate 		}
10240Sstevel@tonic-gate 	}
10250Sstevel@tonic-gate 	/* check for -n arg, NOTE: it might be quoted */
10260Sstevel@tonic-gate 	if (sep == ' ' && *v && strlen_(*v) == 2 &&
10270Sstevel@tonic-gate 	    ((**v&TRIM) == '-' && (*(*v + 1) & TRIM) == 'n' &&
10280Sstevel@tonic-gate 	    (*(*v+2)&TRIM) == 0)) {
10290Sstevel@tonic-gate 		nonl++, v++;
10300Sstevel@tonic-gate 	}
10310Sstevel@tonic-gate 	while (cp = *v++) {
10320Sstevel@tonic-gate 		int c;
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 		while (c = *cp++) {
10350Sstevel@tonic-gate 			Putchar(c | QUOTE);
10360Sstevel@tonic-gate 		}
10370Sstevel@tonic-gate 		if (*v) {
10380Sstevel@tonic-gate 			Putchar(sep | QUOTE);
10390Sstevel@tonic-gate 		}
10400Sstevel@tonic-gate 	}
10410Sstevel@tonic-gate 	if (sep && nonl == 0) {
10420Sstevel@tonic-gate 		Putchar('\n');
10430Sstevel@tonic-gate 	} else {
10440Sstevel@tonic-gate 		flush();
10450Sstevel@tonic-gate 	}
10460Sstevel@tonic-gate 	if (setintr) {
10470Sstevel@tonic-gate 		(void) sigblock(sigmask(SIGINT));
10480Sstevel@tonic-gate 	}
10490Sstevel@tonic-gate 	if (gargv) {
10500Sstevel@tonic-gate 		blkfree(gargv), gargv = 0;
10510Sstevel@tonic-gate 	}
10520Sstevel@tonic-gate }
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate extern char **environ;
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate /*
10570Sstevel@tonic-gate  * Check if the environment variable vp affects this csh's behavior
10580Sstevel@tonic-gate  * and therefore we should call setlocale() or not.
10590Sstevel@tonic-gate  * This function has two side effects when it returns 1:
10600Sstevel@tonic-gate  *	variable islocalevar_catnum is set to the LC_xxx value.
10610Sstevel@tonic-gate  *	variable islocalevar_catname is set to the string "LC_xxx"
10620Sstevel@tonic-gate  */
10630Sstevel@tonic-gate static int	islocalevar_catnum;
10640Sstevel@tonic-gate static char	*islocalevar_catname;
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate static
10670Sstevel@tonic-gate bool
islocalevar(tchar * vp)10680Sstevel@tonic-gate islocalevar(tchar *vp)
10690Sstevel@tonic-gate {
10700Sstevel@tonic-gate 	static struct lcinfo {
10710Sstevel@tonic-gate 		tchar *	evname; /* The name of the env. var. */
10720Sstevel@tonic-gate 	} categories_we_care[] = {
10730Sstevel@tonic-gate 	    S_LANG, S_LC_ALL, S_LC_CTYPE, S_LC_MESSAGES,
10740Sstevel@tonic-gate 	    NOSTR		/* assumption: LC_xxx >= 0 */
10750Sstevel@tonic-gate 	};
10760Sstevel@tonic-gate 	struct lcinfo *p = categories_we_care;
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate 	do {
10790Sstevel@tonic-gate 		if (strcmp_(vp, p->evname) == 0) {
10800Sstevel@tonic-gate 			return (1);
10810Sstevel@tonic-gate 		}
10820Sstevel@tonic-gate 	} while (((++p)->evname) != NOSTR);
10830Sstevel@tonic-gate 	return (0);
10840Sstevel@tonic-gate }
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate void
dosetenv(tchar ** v)10870Sstevel@tonic-gate dosetenv(tchar **v)
10880Sstevel@tonic-gate {
10890Sstevel@tonic-gate 	tchar *vp, *lp;
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate #ifdef TRACE
10920Sstevel@tonic-gate 	tprintf("TRACE- dosetenv()\n");
10930Sstevel@tonic-gate #endif
10940Sstevel@tonic-gate 	v++;
10950Sstevel@tonic-gate 	if ((vp = *v++) == 0) {
10960Sstevel@tonic-gate 		char **ep;
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 		if (setintr) {
10990Sstevel@tonic-gate 			(void) sigsetmask(sigblock(0) & ~ sigmask(SIGINT));
11000Sstevel@tonic-gate 		}
11010Sstevel@tonic-gate 		for (ep = environ; *ep; ep++) {
11020Sstevel@tonic-gate 			printf("%s\n", *ep);
11030Sstevel@tonic-gate 		}
11040Sstevel@tonic-gate 		return;
11050Sstevel@tonic-gate 	}
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 	if ((lp = *v++) == 0) {
11080Sstevel@tonic-gate 		lp = S_;	/* "" */
11090Sstevel@tonic-gate 	}
11100Sstevel@tonic-gate 	local_setenv(vp, lp = globone(lp));
11110Sstevel@tonic-gate 	if (eq(vp, S_PATH)) {
11120Sstevel@tonic-gate 		importpath(lp);
11130Sstevel@tonic-gate 		dohash(xhash);
11140Sstevel@tonic-gate 	} else if (islocalevar(vp)) {
11150Sstevel@tonic-gate 		if (!setlocale(LC_ALL, "")) {
11160Sstevel@tonic-gate 			error("Locale could not be set properly");
11170Sstevel@tonic-gate 		}
11180Sstevel@tonic-gate 	}
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 	xfree(lp);
11210Sstevel@tonic-gate }
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate void
dounsetenv(tchar ** v)11240Sstevel@tonic-gate dounsetenv(tchar **v)
11250Sstevel@tonic-gate {
11260Sstevel@tonic-gate #ifdef TRACE
11270Sstevel@tonic-gate 	tprintf("TRACE- dounsetenv()\n");
11280Sstevel@tonic-gate #endif
11290Sstevel@tonic-gate 	v++;
11300Sstevel@tonic-gate 	do {
11310Sstevel@tonic-gate 		local_unsetenv(*v);
11320Sstevel@tonic-gate 		if (islocalevar(*v++)) {
11330Sstevel@tonic-gate 			setlocale(LC_ALL, "");	/* Hope no error! */
11340Sstevel@tonic-gate 		}
11350Sstevel@tonic-gate 	} while (*v);
11360Sstevel@tonic-gate }
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate void
local_setenv(tchar * name,tchar * val)11390Sstevel@tonic-gate local_setenv(tchar *name, tchar *val)
11400Sstevel@tonic-gate {
11410Sstevel@tonic-gate 	char **ep = environ;
11420Sstevel@tonic-gate 	tchar *cp;
11430Sstevel@tonic-gate 	char *dp;
11440Sstevel@tonic-gate 	tchar *ep_;	/* temporary */
11450Sstevel@tonic-gate 	char *blk[2], **oep = ep;
11460Sstevel@tonic-gate 
11470Sstevel@tonic-gate #ifdef TRACE
11480Sstevel@tonic-gate 	/* tprintf("TRACE- local_setenv(%t, %t)\n", name, val); */
11490Sstevel@tonic-gate 	/* printf("IN local_setenv args = (%t)\n", val); */
11500Sstevel@tonic-gate #endif
11510Sstevel@tonic-gate 	for (; *ep; ep++) {
11520Sstevel@tonic-gate #ifdef MBCHAR
11530Sstevel@tonic-gate 		for (cp = name, dp = *ep; *cp && *dp; cp++) {
11540Sstevel@tonic-gate 			/*
11550Sstevel@tonic-gate 			 * This loop compares two chars in different
11560Sstevel@tonic-gate 			 * representations, EUC (as char *) and wchar_t
11570Sstevel@tonic-gate 			 * (in tchar), and ends when they are different.
11580Sstevel@tonic-gate 			 */
11590Sstevel@tonic-gate 			wchar_t	dwc;
11600Sstevel@tonic-gate 			int	n;
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate 			n = mbtowc(&dwc, dp, MB_CUR_MAX);
11630Sstevel@tonic-gate 			if (n <= 0) {
11640Sstevel@tonic-gate 				break; /* Illegal multibyte. */
11650Sstevel@tonic-gate 			}
11660Sstevel@tonic-gate 			dp += n; /* Advance to next multibyte char. */
11670Sstevel@tonic-gate 			if (dwc == (wchar_t)(*cp & TRIM)) {
11680Sstevel@tonic-gate 				continue;
11690Sstevel@tonic-gate 			} else  {
11700Sstevel@tonic-gate 				break;
11710Sstevel@tonic-gate 			}
11720Sstevel@tonic-gate 		}
11730Sstevel@tonic-gate #else /* !MBCHAR */
11740Sstevel@tonic-gate 		for (cp = name, dp = *ep; *cp && (char)*cp == *dp; cp++, dp++) {
11750Sstevel@tonic-gate 			continue;
11760Sstevel@tonic-gate 		}
11770Sstevel@tonic-gate #endif /* !MBCHAR */
11780Sstevel@tonic-gate 		if (*cp != 0 || *dp != '=') {
11790Sstevel@tonic-gate 			continue;
11800Sstevel@tonic-gate 		}
11810Sstevel@tonic-gate 		cp = strspl(S_EQ, val);
11820Sstevel@tonic-gate 		xfree(*ep);
11830Sstevel@tonic-gate 		ep_ = strspl(name, cp);		/* ep_ is xalloc'ed */
11840Sstevel@tonic-gate 		xfree(cp);
11850Sstevel@tonic-gate 		/*
11860Sstevel@tonic-gate 		 * Trimming is not needed here.
11870Sstevel@tonic-gate 		 * trim();
11880Sstevel@tonic-gate 		 */
11890Sstevel@tonic-gate 		*ep = tstostr(NULL, ep_);
11900Sstevel@tonic-gate 		xfree(ep_);			/* because temp.  use */
11910Sstevel@tonic-gate 		return;
11920Sstevel@tonic-gate 	}
11930Sstevel@tonic-gate 	ep_ = strspl(name, S_EQ);		/* ep_ is xalloc'ed */
11940Sstevel@tonic-gate 	blk[0] = tstostr(NULL, ep_);
11950Sstevel@tonic-gate 	blk[1] = 0;
11960Sstevel@tonic-gate 	xfree(ep_);
1197356Smuffin 	environ = (char **)blkspl_((char **)environ, blk);
11980Sstevel@tonic-gate 	xfree((void *)oep);
11990Sstevel@tonic-gate 	local_setenv(name, val);
12000Sstevel@tonic-gate }
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate void
local_unsetenv(tchar * name)12030Sstevel@tonic-gate local_unsetenv(tchar *name)
12040Sstevel@tonic-gate {
12050Sstevel@tonic-gate 	char **ep = environ;
12060Sstevel@tonic-gate 	tchar *cp;
12070Sstevel@tonic-gate 	char *dp;
12080Sstevel@tonic-gate 	char **oep = ep;
12090Sstevel@tonic-gate 	char *cp_;	/* tmp use */
1210356Smuffin 	static int cnt = 0;	/* delete counter */
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate #ifdef TRACE
12130Sstevel@tonic-gate 	tprintf("TRACE- local_unsetenv()\n");
12140Sstevel@tonic-gate #endif
12150Sstevel@tonic-gate 	for (; *ep; ep++) {
12160Sstevel@tonic-gate #ifdef MBCHAR
12170Sstevel@tonic-gate 		for (cp = name, dp = *ep; *cp && *dp; cp++) {
12180Sstevel@tonic-gate 			/*
12190Sstevel@tonic-gate 			 * This loop compares two chars in different
12200Sstevel@tonic-gate 			 * representations, EUC (as char *) and wchar_t
12210Sstevel@tonic-gate 			 * (in tchar), and ends when they are different.
12220Sstevel@tonic-gate 			 */
12230Sstevel@tonic-gate 			wchar_t	dwc;
12240Sstevel@tonic-gate 			int	n;
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate 			n = mbtowc(&dwc, dp, MB_CUR_MAX);
12270Sstevel@tonic-gate 			if (n <= 0) {
12280Sstevel@tonic-gate 				break; /* Illegal multibyte. */
12290Sstevel@tonic-gate 			}
12300Sstevel@tonic-gate 			dp += n; /* Advance to next multibyte char. */
12310Sstevel@tonic-gate 			if (dwc == (wchar_t)(*cp & TRIM)) {
12320Sstevel@tonic-gate 				continue;
12330Sstevel@tonic-gate 			} else {
12340Sstevel@tonic-gate 				break;
12350Sstevel@tonic-gate 			}
12360Sstevel@tonic-gate 		}
12370Sstevel@tonic-gate #else /* !MBCHAR */
12380Sstevel@tonic-gate 		for (cp = name, dp = *ep; *cp && (char)*cp == *dp; cp++, dp++) {
12390Sstevel@tonic-gate 			continue;
12400Sstevel@tonic-gate 		}
12410Sstevel@tonic-gate #endif /* !MBCHAR */
12420Sstevel@tonic-gate 		if (*cp != 0 || *dp != '=') {
12430Sstevel@tonic-gate 			continue;
12440Sstevel@tonic-gate 		}
12450Sstevel@tonic-gate 		cp_ = *ep;
12460Sstevel@tonic-gate 		*ep = 0;
1247356Smuffin 		environ = (char **)blkspl_((char **)environ, ep+1);
12480Sstevel@tonic-gate 		*ep = cp_;
12490Sstevel@tonic-gate 		xfree(cp_);
12500Sstevel@tonic-gate 		xfree((void *)oep);
12510Sstevel@tonic-gate 		return;
12520Sstevel@tonic-gate 	}
12530Sstevel@tonic-gate }
12540Sstevel@tonic-gate 
12550Sstevel@tonic-gate void
doumask(tchar ** v)12560Sstevel@tonic-gate doumask(tchar **v)
12570Sstevel@tonic-gate {
12580Sstevel@tonic-gate 	tchar *cp = v[1];
12590Sstevel@tonic-gate 	int i;
12600Sstevel@tonic-gate 
12610Sstevel@tonic-gate #ifdef TRACE
12620Sstevel@tonic-gate 	tprintf("TRACE- dounmask()\n");
12630Sstevel@tonic-gate #endif
12640Sstevel@tonic-gate 	if (cp == 0) {
12650Sstevel@tonic-gate 		i = umask(0);
12660Sstevel@tonic-gate 		(void) umask(i);
12670Sstevel@tonic-gate 		printf("%o\n", i);
12680Sstevel@tonic-gate 		return;
12690Sstevel@tonic-gate 	}
12700Sstevel@tonic-gate 	i = 0;
12710Sstevel@tonic-gate 	while (digit(*cp) && *cp != '8' && *cp != '9') {
12720Sstevel@tonic-gate 		i = i * 8 + *cp++ - '0';
12730Sstevel@tonic-gate 	}
12740Sstevel@tonic-gate 	if (*cp || i < 0 || i > 0777) {
12750Sstevel@tonic-gate 		bferr("Improper mask");
12760Sstevel@tonic-gate 	}
12770Sstevel@tonic-gate 	(void) umask(i);
12780Sstevel@tonic-gate }
12790Sstevel@tonic-gate 
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate struct limits *
findlim(tchar * cp)12820Sstevel@tonic-gate findlim(tchar *cp)
12830Sstevel@tonic-gate {
12840Sstevel@tonic-gate 	struct limits *lp, *res;
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate #ifdef TRACE
12870Sstevel@tonic-gate 	tprintf("TRACE- findlim()\n");
12880Sstevel@tonic-gate #endif
12890Sstevel@tonic-gate 	res = 0;
12900Sstevel@tonic-gate 	for (lp = limits; lp->limconst >= 0; lp++) {
12910Sstevel@tonic-gate 		if (prefix(cp, lp->limname)) {
12920Sstevel@tonic-gate 			if (res) {
12930Sstevel@tonic-gate 				bferr("Ambiguous");
12940Sstevel@tonic-gate 			}
12950Sstevel@tonic-gate 			res = lp;
12960Sstevel@tonic-gate 		}
12970Sstevel@tonic-gate 	}
12980Sstevel@tonic-gate 	if (res) {
12990Sstevel@tonic-gate 		return (res);
13000Sstevel@tonic-gate 	}
13010Sstevel@tonic-gate 	bferr("No such limit");
13020Sstevel@tonic-gate 	/*NOTREACHED*/
13030Sstevel@tonic-gate }
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate void
dolimit(tchar ** v)13060Sstevel@tonic-gate dolimit(tchar **v)
13070Sstevel@tonic-gate {
13080Sstevel@tonic-gate 	struct limits *lp;
13090Sstevel@tonic-gate 	rlim_t limit;
13100Sstevel@tonic-gate 	tchar hard = 0;
13110Sstevel@tonic-gate 
13120Sstevel@tonic-gate #ifdef TRACE
13130Sstevel@tonic-gate 	tprintf("TRACE- dolimit()\n");
13140Sstevel@tonic-gate #endif
13150Sstevel@tonic-gate 	v++;
13160Sstevel@tonic-gate 	if (*v && eq(*v, S_h)) {
13170Sstevel@tonic-gate 		hard = 1;
13180Sstevel@tonic-gate 		v++;
13190Sstevel@tonic-gate 	}
13200Sstevel@tonic-gate 	if (*v == 0) {
13210Sstevel@tonic-gate 		for (lp = limits; lp->limconst >= 0; lp++) {
13220Sstevel@tonic-gate 			plim(lp, hard);
13230Sstevel@tonic-gate 		}
13240Sstevel@tonic-gate 		return;
13250Sstevel@tonic-gate 	}
13260Sstevel@tonic-gate 	lp = findlim(v[0]);
13270Sstevel@tonic-gate 	if (v[1] == 0) {
13280Sstevel@tonic-gate 		plim(lp,  hard);
13290Sstevel@tonic-gate 		return;
13300Sstevel@tonic-gate 	}
13310Sstevel@tonic-gate 	switch (getval(lp, v+1, &limit)) {
13320Sstevel@tonic-gate 	case 0:
13330Sstevel@tonic-gate 		error("Value specified for limit is too large");
13340Sstevel@tonic-gate 		return;
13350Sstevel@tonic-gate 	case (-1):
13360Sstevel@tonic-gate 		error("Numeric conversion failed");
13370Sstevel@tonic-gate 		return;
13380Sstevel@tonic-gate 	default:
13390Sstevel@tonic-gate 		if (setlim(lp, hard, limit) < 0) {
13400Sstevel@tonic-gate 			error(NOSTR);
13410Sstevel@tonic-gate 		}
13420Sstevel@tonic-gate 	}
13430Sstevel@tonic-gate }
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate static int
getval(struct limits * lp,tchar ** v,rlim_t * retval)13460Sstevel@tonic-gate getval(struct limits *lp, tchar **v, rlim_t *retval)
13470Sstevel@tonic-gate {
13480Sstevel@tonic-gate 	rlim_t value, tmp, tmp2;
13490Sstevel@tonic-gate 	tchar *cp = *v++;
13500Sstevel@tonic-gate 	char chbuf[BUFSIZ * MB_LEN_MAX];
13510Sstevel@tonic-gate 
13520Sstevel@tonic-gate #ifdef TRACE
13530Sstevel@tonic-gate 	tprintf("TRACE- getval()\n");
13540Sstevel@tonic-gate #endif
13550Sstevel@tonic-gate 
13560Sstevel@tonic-gate 	tstostr(chbuf, cp);
13570Sstevel@tonic-gate 	errno = 0;
13580Sstevel@tonic-gate 	value = strtoull(chbuf, NULL, 0);
13590Sstevel@tonic-gate /*
13600Sstevel@tonic-gate  * we must accept zero, but the conversion can fail and give us
13610Sstevel@tonic-gate  * zero as well...try to deal with it as gracefully as possible
13620Sstevel@tonic-gate  * by checking for EINVAL
13630Sstevel@tonic-gate  */
13640Sstevel@tonic-gate 	if (value == 0 && errno == EINVAL)
13650Sstevel@tonic-gate 		return (-1);
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate 	while (digit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') {
13680Sstevel@tonic-gate 		cp++;
13690Sstevel@tonic-gate 	}
13700Sstevel@tonic-gate 	if (*cp == 0) {
13710Sstevel@tonic-gate 		if (*v == 0) {
13720Sstevel@tonic-gate 			tmp = value * (rlim_t)lp->limdiv;
13730Sstevel@tonic-gate 			/* Check for overflow */
13740Sstevel@tonic-gate 			if (tmp >= value) {
13750Sstevel@tonic-gate 				*retval = tmp;
13760Sstevel@tonic-gate 				return (1);
13770Sstevel@tonic-gate 			} else {
13780Sstevel@tonic-gate 				return (0);
13790Sstevel@tonic-gate 			}
13800Sstevel@tonic-gate 		}
13810Sstevel@tonic-gate 		cp = *v;
13820Sstevel@tonic-gate 	}
13830Sstevel@tonic-gate 	switch (*cp) {
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate 	case ':':
13860Sstevel@tonic-gate 		if (lp->limconst != RLIMIT_CPU) {
13870Sstevel@tonic-gate 			goto badscal;
13880Sstevel@tonic-gate 		}
13890Sstevel@tonic-gate 		tstostr(chbuf, cp + 1);
13900Sstevel@tonic-gate 		tmp = strtoull(chbuf, NULL, 0);
13910Sstevel@tonic-gate 		tmp2 = value * 60 + tmp;
13920Sstevel@tonic-gate 		if (tmp2 >= value) {
13930Sstevel@tonic-gate 			*retval = tmp2;
13940Sstevel@tonic-gate 			return (1);
13950Sstevel@tonic-gate 		} else {
13960Sstevel@tonic-gate 			return (0);
13970Sstevel@tonic-gate 		}
13980Sstevel@tonic-gate 
13990Sstevel@tonic-gate 	case 'h':
14000Sstevel@tonic-gate 		if (lp->limconst != RLIMIT_CPU) {
14010Sstevel@tonic-gate 			goto badscal;
14020Sstevel@tonic-gate 		}
14030Sstevel@tonic-gate 		limtail(cp, S_hours);
14040Sstevel@tonic-gate 		tmp = value * 3600;
14050Sstevel@tonic-gate 		if (tmp < value) {
14060Sstevel@tonic-gate 			return (0);
14070Sstevel@tonic-gate 		}
14080Sstevel@tonic-gate 		value = tmp;
14090Sstevel@tonic-gate 		break;
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 	case 'm':
14120Sstevel@tonic-gate 		if (lp->limconst == RLIMIT_CPU) {
14130Sstevel@tonic-gate 			limtail(cp, S_minutes);
14140Sstevel@tonic-gate 			tmp = value * 60;
14150Sstevel@tonic-gate 			if (tmp < value) {
14160Sstevel@tonic-gate 				return (0);
14170Sstevel@tonic-gate 			}
14180Sstevel@tonic-gate 			value = tmp;
14190Sstevel@tonic-gate 			break;
14200Sstevel@tonic-gate 		}
14210Sstevel@tonic-gate 	case 'M':
14220Sstevel@tonic-gate 		if (lp->limconst == RLIMIT_CPU) {
14230Sstevel@tonic-gate 			goto badscal;
14240Sstevel@tonic-gate 		}
14250Sstevel@tonic-gate 		*cp = 'm';
14260Sstevel@tonic-gate 		limtail(cp, S_megabytes);
14270Sstevel@tonic-gate 		tmp = value * 1024 * 1024;
14280Sstevel@tonic-gate 		if (tmp < value) {
14290Sstevel@tonic-gate 			return (0);
14300Sstevel@tonic-gate 		}
14310Sstevel@tonic-gate 		value = tmp;
14320Sstevel@tonic-gate 		break;
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate 	case 's':
14350Sstevel@tonic-gate 		if (lp->limconst != RLIMIT_CPU) {
14360Sstevel@tonic-gate 			goto badscal;
14370Sstevel@tonic-gate 		}
14380Sstevel@tonic-gate 		limtail(cp, S_seconds);
14390Sstevel@tonic-gate 		break;
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 	case 'k':
14420Sstevel@tonic-gate 		if (lp->limconst == RLIMIT_CPU) {
14430Sstevel@tonic-gate 			goto badscal;
14440Sstevel@tonic-gate 		}
14450Sstevel@tonic-gate 		limtail(cp, S_kbytes);
14460Sstevel@tonic-gate 		tmp = value * 1024;
14470Sstevel@tonic-gate 		if (tmp < value) {
14480Sstevel@tonic-gate 			return (0);
14490Sstevel@tonic-gate 		}
14500Sstevel@tonic-gate 		value = tmp;
14510Sstevel@tonic-gate 		break;
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate 	case 'u':
14540Sstevel@tonic-gate 		limtail(cp, S_unlimited);
14550Sstevel@tonic-gate 		*retval = RLIM_INFINITY;
14560Sstevel@tonic-gate 		return (1);
14570Sstevel@tonic-gate 
14580Sstevel@tonic-gate 	default:
14590Sstevel@tonic-gate badscal:
14600Sstevel@tonic-gate 		bferr("Improper or unknown scale factor");
14610Sstevel@tonic-gate 	}
14620Sstevel@tonic-gate 	*retval = value;
14630Sstevel@tonic-gate 	return (1);
14640Sstevel@tonic-gate }
14650Sstevel@tonic-gate 
14660Sstevel@tonic-gate void
limtail(tchar * cp,tchar * str0)14670Sstevel@tonic-gate limtail(tchar *cp, tchar *str0)
14680Sstevel@tonic-gate {
14690Sstevel@tonic-gate 	tchar *str = str0;
14700Sstevel@tonic-gate #ifdef TRACE
14710Sstevel@tonic-gate 	tprintf("TRACE- limtail()\n");
14720Sstevel@tonic-gate #endif
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate 	while (*cp && *cp == *str) {
14750Sstevel@tonic-gate 		cp++, str++;
14760Sstevel@tonic-gate 	}
14770Sstevel@tonic-gate 	if (*cp) {
14780Sstevel@tonic-gate 		error("Bad scaling; did you mean ``%t''?", str0);
14790Sstevel@tonic-gate 	}
14800Sstevel@tonic-gate }
14810Sstevel@tonic-gate 
14820Sstevel@tonic-gate void
plim(struct limits * lp,tchar hard)14830Sstevel@tonic-gate plim(struct limits *lp, tchar hard)
14840Sstevel@tonic-gate {
14850Sstevel@tonic-gate 	struct rlimit rlim;
14860Sstevel@tonic-gate 	char buf[BUFSZ];
14870Sstevel@tonic-gate 	char *pbuf;
14880Sstevel@tonic-gate 	rlim_t limit;
14890Sstevel@tonic-gate 
14900Sstevel@tonic-gate #ifdef TRACE
14910Sstevel@tonic-gate 	tprintf("TRACE- plim()\n");
14920Sstevel@tonic-gate #endif
14930Sstevel@tonic-gate 	printf("%t \t", lp->limname);
14940Sstevel@tonic-gate 	(void) getrlimit(lp->limconst, &rlim);
14950Sstevel@tonic-gate 	limit = hard ? rlim.rlim_max : rlim.rlim_cur;
14960Sstevel@tonic-gate 	if (limit == RLIM_INFINITY) {
14970Sstevel@tonic-gate 		printf("unlimited");
14980Sstevel@tonic-gate 	} else if (lp->limconst == RLIMIT_CPU) {
14990Sstevel@tonic-gate 		psecs_ull(limit);
15000Sstevel@tonic-gate 	} else {
15010Sstevel@tonic-gate 		buf[BUFSZ - 1] = '\0';
15020Sstevel@tonic-gate 		pbuf = ulltostr((limit / lp->limdiv), &buf[BUFSZ - 1]);
15030Sstevel@tonic-gate 		printf("%s %t", pbuf, lp->limscale);
15040Sstevel@tonic-gate 	}
15050Sstevel@tonic-gate 	printf("\n");
15060Sstevel@tonic-gate }
15070Sstevel@tonic-gate 
15080Sstevel@tonic-gate void
dounlimit(tchar ** v)15090Sstevel@tonic-gate dounlimit(tchar **v)
15100Sstevel@tonic-gate {
15110Sstevel@tonic-gate 	struct limits *lp;
15120Sstevel@tonic-gate 	int err = 0;
15130Sstevel@tonic-gate 	tchar hard = 0;
15140Sstevel@tonic-gate #ifdef TRACE
15150Sstevel@tonic-gate 	tprintf("TRACE- dounlimit()\n");
15160Sstevel@tonic-gate #endif
15170Sstevel@tonic-gate 
15180Sstevel@tonic-gate 	v++;
15190Sstevel@tonic-gate 	if (*v && eq(*v, S_h)) {
15200Sstevel@tonic-gate 		hard = 1;
15210Sstevel@tonic-gate 		v++;
15220Sstevel@tonic-gate 	}
15230Sstevel@tonic-gate 	if (*v == 0) {
15240Sstevel@tonic-gate 		for (lp = limits; lp->limconst >= 0; lp++) {
15250Sstevel@tonic-gate 			if (setlim(lp, hard, RLIM_INFINITY) < 0) {
15260Sstevel@tonic-gate 				err++;
15270Sstevel@tonic-gate 			}
15280Sstevel@tonic-gate 		}
15290Sstevel@tonic-gate 		if (err) {
15300Sstevel@tonic-gate 			error(NULL);
15310Sstevel@tonic-gate 		}
15320Sstevel@tonic-gate 		return;
15330Sstevel@tonic-gate 	}
15340Sstevel@tonic-gate 	while (*v) {
15350Sstevel@tonic-gate 		lp = findlim(*v++);
15360Sstevel@tonic-gate 		if (setlim(lp, hard, RLIM_INFINITY) < 0) {
15370Sstevel@tonic-gate 			error(NULL);
15380Sstevel@tonic-gate 		}
15390Sstevel@tonic-gate 	}
15400Sstevel@tonic-gate }
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate int
setlim(struct limits * lp,tchar hard,rlim_t limit)15430Sstevel@tonic-gate setlim(struct limits *lp, tchar hard, rlim_t limit)
15440Sstevel@tonic-gate {
15450Sstevel@tonic-gate 	struct rlimit rlim;
15460Sstevel@tonic-gate 
15470Sstevel@tonic-gate #ifdef TRACE
15480Sstevel@tonic-gate 	tprintf("TRACE- setlim()\n");
15490Sstevel@tonic-gate #endif
15500Sstevel@tonic-gate 	(void) getrlimit(lp->limconst, &rlim);
15510Sstevel@tonic-gate 	if (hard) {
15520Sstevel@tonic-gate 		rlim.rlim_max = limit;
15530Sstevel@tonic-gate 	} else if (limit == RLIM_INFINITY && geteuid() != 0) {
15540Sstevel@tonic-gate 		rlim.rlim_cur = rlim.rlim_max;
15550Sstevel@tonic-gate 	} else {
15560Sstevel@tonic-gate 		rlim.rlim_cur = limit;
15570Sstevel@tonic-gate 	}
15580Sstevel@tonic-gate 	if (setrlimit(lp->limconst, &rlim) < 0) {
15590Sstevel@tonic-gate 		printf("%t: %t: Can't %s%s limit\n", bname, lp->limname,
15600Sstevel@tonic-gate 		    limit == RLIM_INFINITY ? "remove" : "set",
15610Sstevel@tonic-gate 		    hard ? " hard" : "");
15620Sstevel@tonic-gate 		return (-1);
15630Sstevel@tonic-gate 	}
15640Sstevel@tonic-gate 	return (0);
15650Sstevel@tonic-gate }
15660Sstevel@tonic-gate 
15670Sstevel@tonic-gate void
dosuspend()15680Sstevel@tonic-gate dosuspend()
15690Sstevel@tonic-gate {
15700Sstevel@tonic-gate 	int ctpgrp;
15710Sstevel@tonic-gate 	void (*old)();
15720Sstevel@tonic-gate 
15730Sstevel@tonic-gate #ifdef TRACE
15740Sstevel@tonic-gate 	tprintf("TRACE- dosuspend()\n");
15750Sstevel@tonic-gate #endif
15760Sstevel@tonic-gate 	if (loginsh) {
15770Sstevel@tonic-gate 		error("Can't suspend a login shell (yet)");
15780Sstevel@tonic-gate 	}
15790Sstevel@tonic-gate 	if (getpid() == getsid(0)) {
15800Sstevel@tonic-gate 		error("Can't suspend this shell");
15810Sstevel@tonic-gate 	}
15820Sstevel@tonic-gate 	untty();
15830Sstevel@tonic-gate 	old = (void (*)())signal(SIGTSTP, SIG_DFL);
15840Sstevel@tonic-gate 	(void) kill(0, SIGTSTP);
15850Sstevel@tonic-gate 	/* the shell stops here */
15860Sstevel@tonic-gate 	(void) signal(SIGTSTP, old);
15870Sstevel@tonic-gate 	if (tpgrp != -1) {
15880Sstevel@tonic-gate retry:
15890Sstevel@tonic-gate 		(void) ioctl(FSHTTY, TIOCGPGRP,  (char *)&ctpgrp);
15900Sstevel@tonic-gate 		if (ctpgrp != opgrp) {
15910Sstevel@tonic-gate 			old = (void (*)())signal(SIGTTIN, SIG_DFL);
15920Sstevel@tonic-gate 			(void) kill(0, SIGTTIN);
15930Sstevel@tonic-gate 			(void) signal(SIGTTIN, old);
15940Sstevel@tonic-gate 			goto retry;
15950Sstevel@tonic-gate 		}
15960Sstevel@tonic-gate 		(void) setpgid(0, shpgrp);
15970Sstevel@tonic-gate 		(void) ioctl(FSHTTY, TIOCSPGRP, (char *)&shpgrp);
15980Sstevel@tonic-gate 	}
15990Sstevel@tonic-gate }
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate void
doeval(tchar ** v)16020Sstevel@tonic-gate doeval(tchar **v)
16030Sstevel@tonic-gate {
16040Sstevel@tonic-gate 	tchar **oevalvec = evalvec;
16050Sstevel@tonic-gate 	tchar *oevalp = evalp;
16060Sstevel@tonic-gate 	jmp_buf osetexit;
16070Sstevel@tonic-gate 	int reenter;
16080Sstevel@tonic-gate 	tchar **gv = 0;
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate #ifdef TRACE
16110Sstevel@tonic-gate 	tprintf("TRACE- doeval()\n");
16120Sstevel@tonic-gate #endif
16130Sstevel@tonic-gate 	v++;
16140Sstevel@tonic-gate 	if (*v == 0) {
16150Sstevel@tonic-gate 		return;
16160Sstevel@tonic-gate 	}
16170Sstevel@tonic-gate 	gflag = 0, tglob(v);
16180Sstevel@tonic-gate 	if (gflag) {
16190Sstevel@tonic-gate 		gv = v = glob(v);
16200Sstevel@tonic-gate 		gargv = 0;
16210Sstevel@tonic-gate 		if (v == 0) {
16220Sstevel@tonic-gate 			error("No match");
16230Sstevel@tonic-gate 		}
16240Sstevel@tonic-gate 		v = copyblk(v);
16250Sstevel@tonic-gate 	} else {
16260Sstevel@tonic-gate 		trim(v);
16270Sstevel@tonic-gate 	}
16280Sstevel@tonic-gate 	getexit(osetexit);
16290Sstevel@tonic-gate 	reenter = 0;
16300Sstevel@tonic-gate 	setexit();
16310Sstevel@tonic-gate 	reenter++;
16320Sstevel@tonic-gate 	if (reenter == 1) {
16330Sstevel@tonic-gate 		evalvec = v;
16340Sstevel@tonic-gate 		evalp = 0;
16350Sstevel@tonic-gate 		process(0);
16360Sstevel@tonic-gate 	}
16370Sstevel@tonic-gate 	evalvec = oevalvec;
16380Sstevel@tonic-gate 	evalp = oevalp;
16390Sstevel@tonic-gate 	doneinp = 0;
16400Sstevel@tonic-gate 	if (gv) {
16410Sstevel@tonic-gate 		blkfree(gv);
16420Sstevel@tonic-gate 	}
16430Sstevel@tonic-gate 	resexit(osetexit);
16440Sstevel@tonic-gate 	if (reenter >= 2) {
16450Sstevel@tonic-gate 		error(NULL);
16460Sstevel@tonic-gate 	}
16470Sstevel@tonic-gate }
1648