Home | History | Annotate | Download | only in csh
      1     0   stevel /*
      2  2182     chin  * Copyright 2006 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 <locale.h>	/* For LC_ALL */
     19     0   stevel #include "sh.tconst.h"
     20     0   stevel #include <sys/types.h>
     21     0   stevel #include <stdlib.h>
     22     0   stevel 
     23     0   stevel /*
     24     0   stevel  * N.B.: Some of the limits change from SunOS 4.x to SunOS 5.0.  In
     25     0   stevel  * particular, RLIMIT_RSS is gone and RLIMIT_VMEM is new.  Beware of consusing
     26     0   stevel  * the keywords that the command prints for these two.  The old one was
     27     0   stevel  * "memoryuse" and the new one is "memorysize".  Note also that a given limit
     28     0   stevel  * doesn't necessarily appear in the same position in the two releases.
     29     0   stevel  */
     30     0   stevel struct limits {
     31     0   stevel 	int	limconst;
     32     0   stevel 	tchar *limname;
     33     0   stevel 	int	limdiv;
     34     0   stevel 	tchar *limscale;
     35     0   stevel } limits[] = {
     36     0   stevel 	RLIMIT_CPU,	S_cputime,	/* "cputime" */
     37     0   stevel 		1,	S_seconds,	/* "seconds" */
     38     0   stevel 	RLIMIT_FSIZE,	S_filesize,	/* "filesize" */
     39     0   stevel 		1024,	S_kbytes,	/* "kbytes" */
     40     0   stevel 	RLIMIT_DATA,	S_datasize,	/* "datasize" */
     41     0   stevel 		1024,	S_kbytes,	/* "kbytes" */
     42     0   stevel 	RLIMIT_STACK,	S_stacksize,	/* "stacksize" */
     43     0   stevel 		1024,	S_kbytes,	/* "kbytes" */
     44     0   stevel 	RLIMIT_CORE,	S_coredumpsize, /* "coredumpsize" */
     45     0   stevel 		1024,	S_kbytes,	/* "kbytes" */
     46     0   stevel 	RLIMIT_NOFILE,	S_descriptors,	/* "descriptors" */
     47     0   stevel 		1,	S_,		/* "" */
     48     0   stevel 	RLIMIT_VMEM,	S_memorysize,	/* "memorysize" */
     49     0   stevel 		1024,	S_kbytes,	/* "kbytes" */
     50     0   stevel 	-1,		0,
     51     0   stevel };
     52     0   stevel 
     53   356   muffin 
     54     0   stevel static int getval(struct limits *lp, tchar **v, rlim_t *);
     55   356   muffin void islogin(void);
     56   356   muffin int dolabel(void);
     57     0   stevel void reexecute(struct command *kp);
     58   356   muffin void preread_(void);
     59   356   muffin void doagain(void);
     60   356   muffin void toend(void);
     61   356   muffin void wfree(void);
     62     0   stevel void echo(tchar sep, tchar **v);
     63     0   stevel void local_setenv(tchar *name, tchar *val);
     64     0   stevel void local_unsetenv(tchar *name);
     65     0   stevel void limtail(tchar *cp, tchar *str0);
     66     0   stevel void plim(struct limits *lp, tchar hard);
     67     0   stevel void search();
     68     0   stevel 
     69     0   stevel #define	BUFSZ	1028
     70     0   stevel 
     71     0   stevel /*
     72     0   stevel  * C shell
     73     0   stevel  */
     74     0   stevel 
     75   356   muffin struct biltins *
     76     0   stevel isbfunc(struct command *t)
     77     0   stevel {
     78     0   stevel 	tchar *cp = t->t_dcom[0];
     79     0   stevel 	struct biltins *bp, *bp1, *bp2;
     80     0   stevel 	int dofg1(), dobg1();
     81     0   stevel 
     82     0   stevel 	static struct biltins label = { S_, dolabel, 0, 0 };
     83     0   stevel 	static struct biltins foregnd = { S_Pjob, dofg1, 0, 0 };
     84     0   stevel 	static struct biltins backgnd = { S_PjobAND, dobg1, 0, 0 };
     85     0   stevel #ifdef TRACE
     86     0   stevel 	tprintf("TRACE- isbfunc()\n");
     87     0   stevel #endif
     88     0   stevel 	if (lastchr(cp) == ':') {
     89     0   stevel 		label.bname = cp;
     90     0   stevel 		return (&label);
     91     0   stevel 	}
     92     0   stevel 	if (*cp == '%') {
     93     0   stevel 		if (t->t_dflg & FAND) {
     94     0   stevel 			t->t_dflg &= ~FAND;
     95     0   stevel 			backgnd.bname = cp;
     96     0   stevel 			return (&backgnd);
     97     0   stevel 		}
     98     0   stevel 		foregnd.bname = cp;
     99     0   stevel 		return (&foregnd);
    100     0   stevel 	}
    101     0   stevel 	/*
    102     0   stevel 	 * Binary search
    103     0   stevel 	 * Bp1 is the beginning of the current search range.
    104     0   stevel 	 * Bp2 is one past the end.
    105     0   stevel 	 */
    106     0   stevel 	for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2; ) {
    107     0   stevel 		int i;
    108     0   stevel 
    109     0   stevel 		bp = bp1 + (bp2 - bp1 >> 1);
    110     0   stevel 		if ((i = *cp - *bp->bname) == 0 &&
    111     0   stevel 		    (i = strcmp_(cp, bp->bname)) == 0) {
    112     0   stevel 			return (bp);
    113     0   stevel 		}
    114     0   stevel 		if (i < 0) {
    115     0   stevel 			bp2 = bp;
    116     0   stevel 		} else {
    117     0   stevel 			bp1 = bp + 1;
    118     0   stevel 		}
    119     0   stevel 	}
    120     0   stevel 	return (0);
    121     0   stevel }
    122     0   stevel 
    123     0   stevel void
    124     0   stevel func(struct command *t, struct biltins *bp)
    125     0   stevel {
    126     0   stevel 	int i;
    127     0   stevel 
    128     0   stevel #ifdef TRACE
    129     0   stevel 	tprintf("TRACE- func()\n");
    130     0   stevel #endif
    131     0   stevel 	xechoit(t->t_dcom);
    132     0   stevel 	setname(bp->bname);
    133     0   stevel 	i = blklen(t->t_dcom) - 1;
    134     0   stevel 	if (i < bp->minargs) {
    135     0   stevel 		bferr("Too few arguments");
    136     0   stevel 	}
    137     0   stevel 	if (i > bp->maxargs) {
    138     0   stevel 		bferr("Too many arguments");
    139     0   stevel 	}
    140     0   stevel 	(*bp->bfunct)(t->t_dcom, t);
    141     0   stevel }
    142     0   stevel 
    143     0   stevel int
    144   356   muffin dolabel(void)
    145     0   stevel {
    146     0   stevel #ifdef TRACE
    147     0   stevel 	tprintf("TRACE- dolabel()\n");
    148     0   stevel #endif
    149   356   muffin 	return (0);
    150     0   stevel }
    151     0   stevel 
    152     0   stevel void
    153     0   stevel doonintr(tchar **v)
    154     0   stevel {
    155     0   stevel 	tchar *cp;
    156     0   stevel 	tchar *vv = v[1];
    157     0   stevel 
    158     0   stevel #ifdef TRACE
    159     0   stevel 	tprintf("TRACE- doonintr()\n");
    160     0   stevel #endif
    161     0   stevel 	if (parintr == SIG_IGN) {
    162     0   stevel 		return;
    163     0   stevel 	}
    164     0   stevel 	if (setintr && intty) {
    165     0   stevel 		bferr("Can't from terminal");
    166     0   stevel 	}
    167     0   stevel 	cp = gointr, gointr = 0, xfree(cp);
    168     0   stevel 	if (vv == 0) {
    169     0   stevel 		if (setintr) {
    170     0   stevel 			(void) sigblock(sigmask(SIGINT));
    171     0   stevel 		} else {
    172     0   stevel 			(void) signal(SIGINT, SIG_DFL);
    173     0   stevel 		}
    174     0   stevel 		gointr = 0;
    175     0   stevel 	} else if (eq((vv = strip(vv)), S_MINUS)) {
    176     0   stevel 		(void) signal(SIGINT, SIG_IGN);
    177     0   stevel 		gointr = S_MINUS;
    178     0   stevel 	} else {
    179     0   stevel 		gointr = savestr(vv);
    180     0   stevel 		(void) signal(SIGINT, pintr);
    181     0   stevel 	}
    182     0   stevel }
    183     0   stevel 
    184     0   stevel void
    185   356   muffin donohup(void)
    186     0   stevel {
    187     0   stevel 
    188     0   stevel #ifdef TRACE
    189     0   stevel 	tprintf("TRACE- donohup()\n");
    190     0   stevel #endif
    191     0   stevel 	if (intty) {
    192     0   stevel 		bferr("Can't from terminal");
    193     0   stevel 	}
    194     0   stevel 	if (setintr == 0) {
    195     0   stevel 		(void) signal(SIGHUP, SIG_IGN);
    196     0   stevel #ifdef CC
    197     0   stevel 		submit(getpid());
    198     0   stevel #endif
    199     0   stevel 	}
    200     0   stevel }
    201     0   stevel 
    202     0   stevel void
    203   356   muffin dozip(void)
    204     0   stevel {
    205     0   stevel 	;
    206     0   stevel }
    207     0   stevel 
    208     0   stevel void
    209   356   muffin prvars(void)
    210     0   stevel {
    211     0   stevel #ifdef TRACE
    212     0   stevel 	tprintf("TRACE- prvars()\n");
    213     0   stevel #endif
    214     0   stevel 
    215     0   stevel 	plist(&shvhed);
    216     0   stevel }
    217     0   stevel 
    218     0   stevel void
    219     0   stevel doalias(tchar **v)
    220     0   stevel {
    221     0   stevel 	struct varent *vp;
    222     0   stevel 	tchar *p;
    223     0   stevel 
    224     0   stevel #ifdef TRACE
    225     0   stevel 	tprintf("TRACE- doalias()\n");
    226     0   stevel #endif
    227     0   stevel 	v++;
    228     0   stevel 	p = *v++;
    229     0   stevel 	if (p == 0) {
    230     0   stevel 		plist(&aliases);
    231     0   stevel 	} else if (*v == 0) {
    232     0   stevel 		vp = adrof1(strip(p), &aliases);
    233     0   stevel 		if (vp) {
    234     0   stevel 			blkpr(vp->vec), printf("\n");
    235     0   stevel 		}
    236     0   stevel 	} else {
    237     0   stevel 		if (eq(p, S_alias) ||
    238     0   stevel 		    eq(p, S_unalias)) {
    239     0   stevel 			setname(p);
    240     0   stevel 			bferr("Too dangerous to alias that");
    241     0   stevel 		}
    242     0   stevel 		set1(strip(p), saveblk(v), &aliases);
    243     0   stevel 	}
    244     0   stevel }
    245     0   stevel 
    246     0   stevel void
    247     0   stevel unalias(tchar **v)
    248     0   stevel {
    249     0   stevel 
    250     0   stevel #ifdef TRACE
    251     0   stevel 	tprintf("TRACE- unalias()\n");
    252     0   stevel #endif
    253     0   stevel 	unset1(v, &aliases);
    254     0   stevel }
    255     0   stevel 
    256     0   stevel void
    257   356   muffin dologout(void)
    258     0   stevel {
    259     0   stevel 
    260     0   stevel #ifdef TRACE
    261     0   stevel 	tprintf("TRACE- dologout()\n");
    262     0   stevel #endif
    263     0   stevel 	islogin();
    264     0   stevel 	goodbye();
    265     0   stevel }
    266     0   stevel 
    267     0   stevel void
    268     0   stevel dologin(tchar **v)
    269     0   stevel {
    270     0   stevel 
    271     0   stevel 	char *v_;	/* work */
    272     0   stevel #ifdef TRACE
    273     0   stevel 	tprintf("TRACE- dologin()\n");
    274     0   stevel #endif
    275     0   stevel 	islogin();
    276     0   stevel 	rechist();
    277     0   stevel 	(void) signal(SIGTERM, parterm);
    278     0   stevel 	if (v[1] != NULL) {
    279     0   stevel 		v_ = tstostr(NULL, v[1]);	/* No need to free */
    280     0   stevel 	} else {
    281     0   stevel 		v_ = 0;
    282     0   stevel 	}
    283     0   stevel 	execl("/bin/login", "login", v_, 0);
    284     0   stevel 	untty();
    285     0   stevel 	exit(1);
    286     0   stevel }
    287     0   stevel 
    288     0   stevel #ifdef NEWGRP
    289     0   stevel void
    290     0   stevel donewgrp(tchar **v)
    291     0   stevel {
    292     0   stevel 
    293     0   stevel 	char *v_;	/* work */
    294     0   stevel #ifdef TRACE
    295     0   stevel 	tprintf("TRACE- donewgrp()\n");
    296     0   stevel #endif
    297     0   stevel 	if (chkstop == 0 && setintr) {
    298     0   stevel 		panystop(0);
    299     0   stevel 	}
    300     0   stevel 	(void) signal(SIGTERM, parterm);
    301     0   stevel 
    302     0   stevel 	if (v[1] != NULL) {
    303     0   stevel 		v_ = tstostr(NOSTR, v[1]);	/* No need to free */
    304     0   stevel 	} else {
    305     0   stevel 		v_ = 0;
    306     0   stevel 	}
    307     0   stevel 	execl("/bin/newgrp", "newgrp", v_, 0);
    308     0   stevel 	execl("/usr/bin/newgrp", "newgrp", v_, 0);
    309     0   stevel 	untty();
    310     0   stevel 	exit(1);
    311     0   stevel }
    312     0   stevel #endif
    313     0   stevel 
    314     0   stevel void
    315   356   muffin islogin(void)
    316     0   stevel {
    317     0   stevel 
    318     0   stevel #ifdef TRACE
    319     0   stevel 	tprintf("TRACE- islogin()\n");
    320     0   stevel #endif
    321     0   stevel 	if (chkstop == 0 && setintr) {
    322     0   stevel 		panystop(0);
    323     0   stevel 	}
    324     0   stevel 	if (loginsh) {
    325     0   stevel 		return;
    326     0   stevel 	}
    327     0   stevel 	error("Not login shell");
    328     0   stevel }
    329     0   stevel 
    330     0   stevel void
    331     0   stevel doif(tchar **v, struct command *kp)
    332     0   stevel {
    333     0   stevel 	int i;
    334     0   stevel 	tchar **vv;
    335     0   stevel 
    336     0   stevel #ifdef TRACE
    337     0   stevel 	tprintf("TRACE- doif()\n");
    338     0   stevel #endif
    339     0   stevel 	v++;
    340     0   stevel 	i = exp(&v);
    341     0   stevel 	vv = v;
    342     0   stevel 	if (*vv == NOSTR) {
    343     0   stevel 		bferr("Empty if");
    344     0   stevel 	}
    345     0   stevel 	if (eq(*vv, S_then)) {
    346     0   stevel 		if (*++vv) {
    347     0   stevel 			bferr("Improper then");
    348     0   stevel 		}
    349     0   stevel 		setname(S_then);
    350     0   stevel 		/*
    351     0   stevel 		 * If expression was zero, then scan to else,
    352     0   stevel 		 * otherwise just fall into following code.
    353     0   stevel 		 */
    354     0   stevel 		if (!i) {
    355     0   stevel 			search(ZIF, 0);
    356     0   stevel 		}
    357     0   stevel 		return;
    358     0   stevel 	}
    359     0   stevel 	/*
    360     0   stevel 	 * Simple command attached to this if.
    361     0   stevel 	 * Left shift the node in this tree, munging it
    362     0   stevel 	 * so we can reexecute it.
    363     0   stevel 	 */
    364     0   stevel 	if (i) {
    365     0   stevel 		lshift(kp->t_dcom, vv - kp->t_dcom);
    366     0   stevel 		reexecute(kp);
    367     0   stevel 		donefds();
    368     0   stevel 	}
    369     0   stevel }
    370     0   stevel 
    371     0   stevel /*
    372     0   stevel  * Reexecute a command, being careful not
    373     0   stevel  * to redo i/o redirection, which is already set up.
    374     0   stevel  */
    375     0   stevel void
    376     0   stevel reexecute(struct command *kp)
    377     0   stevel {
    378     0   stevel 
    379     0   stevel #ifdef TRACE
    380     0   stevel 	tprintf("TRACE- reexecute()\n");
    381     0   stevel #endif
    382     0   stevel 	kp->t_dflg &= FSAVE;
    383     0   stevel 	kp->t_dflg |= FREDO;
    384     0   stevel 	/*
    385     0   stevel 	 * If tty is still ours to arbitrate, arbitrate it;
    386     0   stevel 	 * otherwise dont even set pgrp's as the jobs would
    387     0   stevel 	 * then have no way to get the tty (we can't give it
    388     0   stevel 	 * to them, and our parent wouldn't know their pgrp, etc.
    389     0   stevel 	 */
    390     0   stevel 	execute(kp, tpgrp > 0 ? tpgrp : -1);
    391     0   stevel }
    392     0   stevel 
    393     0   stevel void
    394   356   muffin doelse(void)
    395     0   stevel {
    396     0   stevel 
    397     0   stevel #ifdef TRACE
    398     0   stevel 	tprintf("TRACE- doelse()\n");
    399     0   stevel #endif
    400     0   stevel 	search(ZELSE, 0);
    401     0   stevel }
    402     0   stevel 
    403     0   stevel void
    404     0   stevel dogoto(tchar **v)
    405     0   stevel {
    406     0   stevel 	struct whyle *wp;
    407     0   stevel 	tchar *lp;
    408     0   stevel #ifdef TRACE
    409     0   stevel 	tprintf("TRACE- dogoto()\n");
    410     0   stevel #endif
    411     0   stevel 
    412     0   stevel 	/*
    413     0   stevel 	 * While we still can, locate any unknown ends of existing loops.
    414     0   stevel 	 * This obscure code is the WORST result of the fact that we
    415     0   stevel 	 * don't really parse.
    416     0   stevel 	 */
    417     0   stevel 	for (wp = whyles; wp; wp = wp->w_next) {
    418     0   stevel 		if (wp->w_end == 0) {
    419     0   stevel 			search(ZBREAK, 0);
    420     0   stevel 			wp->w_end = btell();
    421     0   stevel 		} else {
    422     0   stevel 			bseek(wp->w_end);
    423     0   stevel 		}
    424     0   stevel 	}
    425     0   stevel 	search(ZGOTO, 0, lp = globone(v[1]));
    426     0   stevel 	xfree(lp);
    427     0   stevel 	/*
    428     0   stevel 	 * Eliminate loops which were exited.
    429     0   stevel 	 */
    430     0   stevel 	wfree();
    431     0   stevel }
    432     0   stevel 
    433     0   stevel void
    434     0   stevel doswitch(tchar **v)
    435     0   stevel {
    436     0   stevel 	tchar *cp, *lp;
    437     0   stevel 
    438     0   stevel #ifdef TRACE
    439     0   stevel 	tprintf("TRACE- doswitch()\n");
    440     0   stevel #endif
    441     0   stevel 	v++;
    442     0   stevel 	if (!*v || *(*v++) != '(') {
    443     0   stevel 		goto syntax;
    444     0   stevel 	}
    445     0   stevel 	cp = **v == ')' ? S_ : *v++;
    446     0   stevel 	if (*(*v++) != ')') {
    447     0   stevel 		v--;
    448     0   stevel 	}
    449     0   stevel 	if (*v) {
    450     0   stevel syntax:
    451     0   stevel 		error("Syntax error");
    452     0   stevel 	}
    453     0   stevel 	search(ZSWITCH, 0, lp = globone(cp));
    454     0   stevel 	xfree(lp);
    455     0   stevel }
    456     0   stevel 
    457     0   stevel void
    458   356   muffin dobreak(void)
    459     0   stevel {
    460     0   stevel 
    461     0   stevel #ifdef TRACE
    462     0   stevel 	tprintf("TRACE- dobreak()\n");
    463     0   stevel #endif
    464     0   stevel 	if (whyles) {
    465     0   stevel 		toend();
    466     0   stevel 	} else {
    467     0   stevel 		bferr("Not in while/foreach");
    468     0   stevel 	}
    469     0   stevel }
    470     0   stevel 
    471     0   stevel void
    472     0   stevel doexit(tchar **v)
    473     0   stevel {
    474     0   stevel 
    475     0   stevel #ifdef TRACE
    476     0   stevel 	tprintf("TRACE- doexit()\n");
    477     0   stevel #endif
    478     0   stevel 	if (chkstop == 0) {
    479     0   stevel 		panystop(0);
    480     0   stevel 	}
    481     0   stevel 	/*
    482     0   stevel 	 * Don't DEMAND parentheses here either.
    483     0   stevel 	 */
    484     0   stevel 	v++;
    485     0   stevel 	if (*v) {
    486     0   stevel 		set(S_status, putn(exp(&v)));
    487     0   stevel 		if (*v) {
    488     0   stevel 			bferr("Expression syntax");
    489     0   stevel 		}
    490     0   stevel 	}
    491     0   stevel 	btoeof();
    492     0   stevel 	if (intty) {
    493     0   stevel 		(void) close(SHIN);
    494     0   stevel 		unsetfd(SHIN);
    495     0   stevel 	}
    496     0   stevel }
    497     0   stevel 
    498     0   stevel void
    499     0   stevel doforeach(tchar **v)
    500     0   stevel {
    501     0   stevel 	tchar *cp;
    502     0   stevel 	struct whyle *nwp;
    503     0   stevel 
    504     0   stevel #ifdef TRACE
    505     0   stevel 	tprintf("TRACE- doforeach()\n");
    506     0   stevel #endif
    507     0   stevel 	v++;
    508     0   stevel 	cp = strip(*v);
    509     0   stevel 	while (*cp && alnum(*cp)) {
    510     0   stevel 		cp++;
    511     0   stevel 	}
    512  2182     chin 	if (*cp || strlen_(*v) >= MAX_VAR_LEN || !letter(**v)) {
    513     0   stevel 		bferr("Invalid variable");
    514     0   stevel 	}
    515     0   stevel 	cp = *v++;
    516     0   stevel 	if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') {
    517     0   stevel 		bferr("Words not ()'ed");
    518     0   stevel 	}
    519     0   stevel 	v++;
    520     0   stevel 	gflag = 0, tglob(v);
    521     0   stevel 	v = glob(v);
    522     0   stevel 	if (v == 0) {
    523     0   stevel 		bferr("No match");
    524     0   stevel 	}
    525   559  nakanon 	nwp = (struct whyle *)xcalloc(1, sizeof (*nwp));
    526     0   stevel 	nwp->w_fe = nwp->w_fe0 = v; gargv = 0;
    527     0   stevel 	nwp->w_start = btell();
    528     0   stevel 	nwp->w_fename = savestr(cp);
    529     0   stevel 	nwp->w_next = whyles;
    530     0   stevel 	whyles = nwp;
    531     0   stevel 	/*
    532     0   stevel 	 * Pre-read the loop so as to be more
    533     0   stevel 	 * comprehensible to a terminal user.
    534     0   stevel 	 */
    535     0   stevel 	if (intty) {
    536     0   stevel 		preread_();
    537     0   stevel 	}
    538     0   stevel 	doagain();
    539     0   stevel }
    540     0   stevel 
    541     0   stevel void
    542     0   stevel dowhile(tchar **v)
    543     0   stevel {
    544     0   stevel 	int status;
    545     0   stevel 	bool again = whyles != 0 && whyles->w_start == lineloc &&
    546     0   stevel 	    whyles->w_fename == 0;
    547     0   stevel 
    548     0   stevel #ifdef TRACE
    549     0   stevel 	tprintf("TRACE- dowhile()\n");
    550     0   stevel #endif
    551     0   stevel 	v++;
    552     0   stevel 	/*
    553     0   stevel 	 * Implement prereading here also, taking care not to
    554     0   stevel 	 * evaluate the expression before the loop has been read up
    555     0   stevel 	 * from a terminal.
    556     0   stevel 	 */
    557     0   stevel 	if (intty && !again) {
    558     0   stevel 		status = !exp0(&v, 1);
    559     0   stevel 	} else {
    560     0   stevel 		status = !exp(&v);
    561     0   stevel 	}
    562     0   stevel 	if (*v) {
    563     0   stevel 		bferr("Expression syntax");
    564     0   stevel 	}
    565     0   stevel 	if (!again) {
    566   559  nakanon 		struct whyle *nwp = (struct whyle *)xcalloc(1, sizeof (*nwp));
    567     0   stevel 
    568     0   stevel 		nwp->w_start = lineloc;
    569     0   stevel 		nwp->w_end = 0;
    570     0   stevel 		nwp->w_next = whyles;
    571     0   stevel 		whyles = nwp;
    572     0   stevel 		if (intty) {
    573     0   stevel 			/*
    574     0   stevel 			 * The tty preread
    575     0   stevel 			 */
    576     0   stevel 			preread_();
    577     0   stevel 			doagain();
    578     0   stevel 			return;
    579     0   stevel 		}
    580     0   stevel 	}
    581     0   stevel 	if (status) {
    582     0   stevel 		/* We ain't gonna loop no more, no more! */
    583     0   stevel 		toend();
    584     0   stevel 	}
    585     0   stevel }
    586     0   stevel 
    587     0   stevel void
    588   356   muffin preread_(void)
    589     0   stevel {
    590     0   stevel #ifdef TRACE
    591     0   stevel 	tprintf("TRACE- preread()\n");
    592     0   stevel #endif
    593     0   stevel 
    594     0   stevel 	whyles->w_end = -1;
    595     0   stevel 	if (setintr) {
    596     0   stevel 		(void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
    597     0   stevel 	}
    598     0   stevel 	search(ZBREAK, 0);
    599     0   stevel 	if (setintr) {
    600     0   stevel 		(void) sigblock(sigmask(SIGINT));
    601     0   stevel 	}
    602     0   stevel 	whyles->w_end = btell();
    603     0   stevel }
    604     0   stevel 
    605     0   stevel void
    606   356   muffin doend(void)
    607     0   stevel {
    608     0   stevel 
    609     0   stevel #ifdef TRACE
    610     0   stevel 	tprintf("TRACE- doend()\n");
    611     0   stevel #endif
    612     0   stevel 	if (!whyles) {
    613     0   stevel 		bferr("Not in while/foreach");
    614     0   stevel 	}
    615     0   stevel 	whyles->w_end = btell();
    616     0   stevel 	doagain();
    617     0   stevel }
    618     0   stevel 
    619     0   stevel void
    620   356   muffin docontin(void)
    621     0   stevel {
    622     0   stevel #ifdef TRACE
    623     0   stevel 	tprintf("TRACE- docontin()\n");
    624     0   stevel #endif
    625     0   stevel 
    626     0   stevel 	if (!whyles) {
    627     0   stevel 		bferr("Not in while/foreach");
    628     0   stevel 	}
    629     0   stevel 	doagain();
    630     0   stevel }
    631     0   stevel 
    632     0   stevel void
    633   356   muffin doagain(void)
    634     0   stevel {
    635     0   stevel 
    636     0   stevel #ifdef TRACE
    637     0   stevel 	tprintf("TRACE- doagain()\n");
    638     0   stevel #endif
    639     0   stevel 	/* Repeating a while is simple */
    640     0   stevel 	if (whyles->w_fename == 0) {
    641     0   stevel 		bseek(whyles->w_start);
    642     0   stevel 		return;
    643     0   stevel 	}
    644     0   stevel 	/*
    645     0   stevel 	 * The foreach variable list actually has a spurious word
    646     0   stevel 	 * ")" at the end of the w_fe list.  Thus we are at the
    647     0   stevel 	 * of the list if one word beyond this is 0.
    648     0   stevel 	 */
    649     0   stevel 	if (!whyles->w_fe[1]) {
    650     0   stevel 		dobreak();
    651     0   stevel 		return;
    652     0   stevel 	}
    653     0   stevel 	set(whyles->w_fename, savestr(*whyles->w_fe++));
    654     0   stevel 	bseek(whyles->w_start);
    655     0   stevel }
    656     0   stevel 
    657     0   stevel void
    658     0   stevel dorepeat(tchar **v, struct command *kp)
    659     0   stevel {
    660     0   stevel 	int i, omask;
    661     0   stevel 
    662     0   stevel #ifdef TRACE
    663     0   stevel 	tprintf("TRACE- dorepeat()\n");
    664     0   stevel #endif
    665     0   stevel 	i = getn(v[1]);
    666     0   stevel 	if (setintr) {
    667     0   stevel 		omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
    668     0   stevel 	}
    669     0   stevel 	lshift(v, 2);
    670     0   stevel 	while (i > 0) {
    671     0   stevel 		if (setintr) {
    672     0   stevel 			(void) sigsetmask(omask);
    673     0   stevel 		}
    674     0   stevel 		reexecute(kp);
    675     0   stevel 		--i;
    676     0   stevel 	}
    677     0   stevel 	donefds();
    678     0   stevel 	if (setintr) {
    679     0   stevel 		(void) sigsetmask(omask);
    680     0   stevel 	}
    681     0   stevel }
    682     0   stevel 
    683     0   stevel void
    684   356   muffin doswbrk(void)
    685     0   stevel {
    686     0   stevel 
    687     0   stevel #ifdef TRACE
    688     0   stevel 	tprintf("TRACE- doswbrk()\n");
    689     0   stevel #endif
    690     0   stevel 	search(ZBRKSW, 0);
    691     0   stevel }
    692     0   stevel 
    693     0   stevel int
    694     0   stevel srchx(tchar *cp)
    695     0   stevel {
    696     0   stevel 	struct srch *sp, *sp1, *sp2;
    697     0   stevel 	int i;
    698     0   stevel 
    699     0   stevel #ifdef TRACE
    700     0   stevel 	tprintf("TRACE- srchx()\n");
    701     0   stevel #endif
    702     0   stevel 	/*
    703     0   stevel 	 * Binary search
    704     0   stevel 	 * Sp1 is the beginning of the current search range.
    705     0   stevel 	 * Sp2 is one past the end.
    706     0   stevel 	 */
    707     0   stevel 	for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2; ) {
    708     0   stevel 		sp = sp1 + (sp2 - sp1 >> 1);
    709     0   stevel 		if ((i = *cp - *sp->s_name) == 0 &&
    710     0   stevel 		    (i = strcmp_(cp, sp->s_name)) == 0) {
    711     0   stevel 			return (sp->s_value);
    712     0   stevel 		}
    713     0   stevel 		if (i < 0) {
    714     0   stevel 			sp2 = sp;
    715     0   stevel 		} else {
    716     0   stevel 			sp1 = sp + 1;
    717     0   stevel 		}
    718     0   stevel 	}
    719     0   stevel 	return (-1);
    720     0   stevel }
    721     0   stevel 
    722     0   stevel tchar Stype;
    723     0   stevel tchar *Sgoal;
    724     0   stevel 
    725     0   stevel /*VARARGS2*/
    726     0   stevel void
    727     0   stevel search(type, level, goal)
    728     0   stevel 	int type; int level; tchar *goal;
    729     0   stevel {
    730     0   stevel 	tchar wordbuf[BUFSIZ];
    731     0   stevel 	tchar *aword = wordbuf;
    732     0   stevel 	tchar *cp;
    733     0   stevel 
    734     0   stevel #ifdef TRACE
    735     0   stevel 	tprintf("TRACE- search()\n");
    736     0   stevel #endif
    737     0   stevel 	Stype = type; Sgoal = goal;
    738     0   stevel 	if (type == ZGOTO) {
    739     0   stevel 		bseek((off_t)0);
    740     0   stevel 	}
    741     0   stevel 	do {
    742     0   stevel 		if (intty && fseekp == feobp) {
    743     0   stevel 			printf("? "), flush();
    744     0   stevel 		}
    745     0   stevel 		aword[0] = 0;
    746     0   stevel 		(void) getword(aword);
    747     0   stevel 
    748     0   stevel 		switch (srchx(aword)) {
    749     0   stevel 
    750     0   stevel 		case ZELSE:
    751     0   stevel 			if (level == 0 && type == ZIF) {
    752     0   stevel 				return;
    753     0   stevel 			}
    754     0   stevel 			break;
    755     0   stevel 
    756     0   stevel 		case ZIF:
    757     0   stevel 			while (getword(aword)) {
    758     0   stevel 				continue;
    759     0   stevel 			}
    760     0   stevel 			if ((type == ZIF || type == ZELSE) &&
    761     0   stevel 			    eq(aword, S_then)) {
    762     0   stevel 				level++;
    763     0   stevel 			}
    764     0   stevel 			break;
    765     0   stevel 
    766     0   stevel 		case ZENDIF:
    767     0   stevel 			if (type == ZIF || type == ZELSE) {
    768     0   stevel 				level--;
    769     0   stevel 			}
    770     0   stevel 			break;
    771     0   stevel 
    772     0   stevel 		case ZFOREACH:
    773     0   stevel 		case ZWHILE:
    774     0   stevel 			if (type == ZBREAK) {
    775     0   stevel 				level++;
    776     0   stevel 			}
    777     0   stevel 			break;
    778     0   stevel 
    779     0   stevel 		case ZEND:
    780     0   stevel 			if (type == ZBREAK) {
    781     0   stevel 				level--;
    782     0   stevel 			}
    783     0   stevel 			break;
    784     0   stevel 
    785     0   stevel 		case ZSWITCH:
    786     0   stevel 			if (type == ZSWITCH || type == ZBRKSW) {
    787     0   stevel 				level++;
    788     0   stevel 			}
    789     0   stevel 			break;
    790     0   stevel 
    791     0   stevel 		case ZENDSW:
    792     0   stevel 			if (type == ZSWITCH || type == ZBRKSW) {
    793     0   stevel 				level--;
    794     0   stevel 			}
    795     0   stevel 			break;
    796     0   stevel 
    797     0   stevel 		case ZLABEL:
    798     0   stevel 			if (type == ZGOTO && getword(aword) &&
    799     0   stevel 			    eq(aword, goal)) {
    800     0   stevel 				level = -1;
    801     0   stevel 			}
    802     0   stevel 			break;
    803     0   stevel 
    804     0   stevel 		default:
    805     0   stevel 			if (type != ZGOTO && (type != ZSWITCH || level != 0)) {
    806     0   stevel 				break;
    807     0   stevel 			}
    808     0   stevel 			if (lastchr(aword) != ':') {
    809     0   stevel 				break;
    810     0   stevel 			}
    811     0   stevel 			aword[strlen_(aword) - 1] = 0;
    812     0   stevel 			if (type == ZGOTO && eq(aword, goal) ||
    813     0   stevel 			    type == ZSWITCH && eq(aword, S_default)) {
    814     0   stevel 				level = -1;
    815     0   stevel 			}
    816     0   stevel 			break;
    817     0   stevel 
    818     0   stevel 		case ZCASE:
    819     0   stevel 			if (type != ZSWITCH || level != 0) {
    820     0   stevel 				break;
    821     0   stevel 			}
    822     0   stevel 			(void) getword(aword);
    823     0   stevel 			if (lastchr(aword) == ':') {
    824     0   stevel 				aword[strlen_(aword) - 1] = 0;
    825     0   stevel 			}
    826     0   stevel 			cp = strip(Dfix1(aword));
    827     0   stevel 			if (Gmatch(goal, cp)) {
    828     0   stevel 				level = -1;
    829     0   stevel 			}
    830     0   stevel 			xfree(cp);
    831     0   stevel 			break;
    832     0   stevel 
    833     0   stevel 		case ZDEFAULT:
    834     0   stevel 			if (type == ZSWITCH && level == 0) {
    835     0   stevel 				level = -1;
    836     0   stevel 			}
    837     0   stevel 			break;
    838     0   stevel 		}
    839     0   stevel 		(void) getword(NOSTR);
    840     0   stevel 	} while (level >= 0);
    841     0   stevel }
    842     0   stevel 
    843     0   stevel int
    844     0   stevel getword(tchar *wp)
    845     0   stevel {
    846     0   stevel 	int found = 0;
    847     0   stevel 	int c, d;
    848     0   stevel #ifdef TRACE
    849     0   stevel 	tprintf("TRACE- getword()\n");
    850     0   stevel #endif
    851     0   stevel 
    852     0   stevel 	c = readc(1);
    853     0   stevel 	d = 0;
    854     0   stevel 	do {
    855     0   stevel 		while (issp(c)) {
    856     0   stevel 			c = readc(1);
    857     0   stevel 		}
    858     0   stevel 		if (c == '#') {
    859     0   stevel 			do {
    860     0   stevel 				c = readc(1);
    861     0   stevel 			} while (c >= 0 && c != '\n');
    862     0   stevel 		}
    863     0   stevel 		if (c < 0) {
    864     0   stevel 			goto past;
    865     0   stevel 		}
    866     0   stevel 		if (c == '\n') {
    867     0   stevel 			if (wp) {
    868     0   stevel 				break;
    869     0   stevel 			}
    870     0   stevel 			return (0);
    871     0   stevel 		}
    872     0   stevel 
    873     0   stevel 		/* ( and ) form separate words */
    874     0   stevel 		if (c == '(' || c == ')') {
    875     0   stevel 			return (1);
    876     0   stevel 		}
    877     0   stevel 
    878     0   stevel 		unreadc(c);
    879     0   stevel 		found = 1;
    880     0   stevel 		do {
    881     0   stevel 			c = readc(1);
    882     0   stevel 			if (c == '\\' && (c = readc(1)) == '\n') {
    883     0   stevel 				c = ' ';
    884     0   stevel 			}
    885     0   stevel 			if (c == '\'' || c == '"') {
    886     0   stevel 				if (d == 0) {
    887     0   stevel 					d = c;
    888     0   stevel 				} else if (d == c) {
    889     0   stevel 					d = 0;
    890     0   stevel 				}
    891     0   stevel 			}
    892     0   stevel 			if (c < 0) {
    893     0   stevel 				goto past;
    894     0   stevel 			}
    895     0   stevel 			if (wp) {
    896     0   stevel 				*wp++ = c;
    897     0   stevel 			}
    898     0   stevel 		} while ((d || !issp(c) && c != '(' && c != ')') && c != '\n');
    899     0   stevel 	} while (wp == 0);
    900     0   stevel 	unreadc(c);
    901     0   stevel 	if (found) {
    902     0   stevel 		*--wp = 0;
    903     0   stevel 	}
    904     0   stevel 	return (found);
    905     0   stevel 
    906     0   stevel past:
    907     0   stevel 	switch (Stype) {
    908     0   stevel 
    909     0   stevel 	case ZIF:
    910     0   stevel 		bferr("then/endif not found");
    911     0   stevel 
    912     0   stevel 	case ZELSE:
    913     0   stevel 		bferr("endif not found");
    914     0   stevel 
    915     0   stevel 	case ZBRKSW:
    916     0   stevel 	case ZSWITCH:
    917     0   stevel 		bferr("endsw not found");
    918     0   stevel 
    919     0   stevel 	case ZBREAK:
    920     0   stevel 		bferr("end not found");
    921     0   stevel 
    922     0   stevel 	case ZGOTO:
    923     0   stevel 		setname(Sgoal);
    924     0   stevel 		bferr("label not found");
    925     0   stevel 	}
    926     0   stevel 	/*NOTREACHED*/
    927   356   muffin 
    928   356   muffin 	return (0);
    929     0   stevel }
    930     0   stevel 
    931     0   stevel void
    932   356   muffin toend(void)
    933     0   stevel {
    934     0   stevel 
    935     0   stevel #ifdef TRACE
    936     0   stevel 	tprintf("TRACE- toend()\n");
    937     0   stevel #endif
    938     0   stevel 	if (whyles->w_end == 0) {
    939     0   stevel 		search(ZBREAK, 0);
    940     0   stevel 		whyles->w_end = btell() - 1;
    941     0   stevel 	} else {
    942     0   stevel 		bseek(whyles->w_end);
    943     0   stevel 	}
    944     0   stevel 	wfree();
    945     0   stevel }
    946     0   stevel 
    947     0   stevel void
    948   356   muffin wfree(void)
    949     0   stevel {
    950     0   stevel 	long o = btell();
    951     0   stevel 
    952     0   stevel #ifdef TRACE
    953     0   stevel 	tprintf("TRACE- wfree()\n");
    954     0   stevel #endif
    955     0   stevel 	while (whyles) {
    956     0   stevel 		struct whyle *wp = whyles;
    957     0   stevel 		struct whyle *nwp = wp->w_next;
    958     0   stevel 
    959     0   stevel 		if (o >= wp->w_start && (wp->w_end == 0 || o < wp->w_end)) {
    960     0   stevel 			break;
    961     0   stevel 		}
    962     0   stevel 		if (wp->w_fe0) {
    963     0   stevel 			blkfree(wp->w_fe0);
    964     0   stevel 		}
    965     0   stevel 		if (wp->w_fename) {
    966     0   stevel 			xfree(wp->w_fename);
    967     0   stevel 		}
    968     0   stevel 		xfree((char *)wp);
    969     0   stevel 		whyles = nwp;
    970     0   stevel 	}
    971     0   stevel }
    972     0   stevel 
    973     0   stevel void
    974     0   stevel doecho(tchar **v)
    975     0   stevel {
    976     0   stevel 
    977     0   stevel #ifdef TRACE
    978     0   stevel 	tprintf("TRACE- doecho()\n");
    979     0   stevel #endif
    980     0   stevel 	echo(' ', v);
    981     0   stevel }
    982     0   stevel 
    983     0   stevel void
    984     0   stevel doglob(tchar **v)
    985     0   stevel {
    986     0   stevel 
    987     0   stevel #ifdef TRACE
    988     0   stevel 	tprintf("TRACE- doglob()\n");
    989     0   stevel #endif
    990     0   stevel 	echo(0, v);
    991     0   stevel 	flush();
    992     0   stevel }
    993     0   stevel 
    994     0   stevel void
    995     0   stevel echo(tchar sep, tchar **v)
    996     0   stevel {
    997     0   stevel 	tchar *cp;
    998     0   stevel 	int nonl = 0;
    999     0   stevel 
   1000     0   stevel #ifdef TRACE
   1001     0   stevel 	tprintf("TRACE- echo()\n");
   1002     0   stevel #endif
   1003     0   stevel 	if (setintr) {
   1004     0   stevel 		(void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
   1005     0   stevel 	}
   1006     0   stevel 	v++;
   1007     0   stevel 	if (*v == 0) {
   1008     0   stevel 		/*
   1009     0   stevel 		 * echo command needs to have newline when there are no
   1010     0   stevel 		 * flags or arguments.  glob should have no newline.  If
   1011     0   stevel 		 * the separator is a blank, we are doing an echo.  If the
   1012     0   stevel 		 * separator is zero, we are globbing.
   1013     0   stevel 		 */
   1014     0   stevel 		if (sep == (tchar)' ')
   1015     0   stevel 			Putchar('\n');
   1016     0   stevel 		return;
   1017     0   stevel 	}
   1018     0   stevel 	gflag = 0, tglob(v);
   1019     0   stevel 	if (gflag) {
   1020     0   stevel 		v = glob(v);
   1021     0   stevel 		if (v == 0) {
   1022     0   stevel 			bferr("No match");
   1023     0   stevel 		}
   1024     0   stevel 	}
   1025     0   stevel 	/* check for -n arg, NOTE: it might be quoted */
   1026     0   stevel 	if (sep == ' ' && *v && strlen_(*v) == 2 &&
   1027     0   stevel 	    ((**v&TRIM) == '-' && (*(*v + 1) & TRIM) == 'n' &&
   1028     0   stevel 	    (*(*v+2)&TRIM) == 0)) {
   1029     0   stevel 		nonl++, v++;
   1030     0   stevel 	}
   1031     0   stevel 	while (cp = *v++) {
   1032     0   stevel 		int c;
   1033     0   stevel 
   1034     0   stevel 		while (c = *cp++) {
   1035     0   stevel 			Putchar(c | QUOTE);
   1036     0   stevel 		}
   1037     0   stevel 		if (*v) {
   1038     0   stevel 			Putchar(sep | QUOTE);
   1039     0   stevel 		}
   1040     0   stevel 	}
   1041     0   stevel 	if (sep && nonl == 0) {
   1042     0   stevel 		Putchar('\n');
   1043     0   stevel 	} else {
   1044     0   stevel 		flush();
   1045     0   stevel 	}
   1046     0   stevel 	if (setintr) {
   1047     0   stevel 		(void) sigblock(sigmask(SIGINT));
   1048     0   stevel 	}
   1049     0   stevel 	if (gargv) {
   1050     0   stevel 		blkfree(gargv), gargv = 0;
   1051     0   stevel 	}
   1052     0   stevel }
   1053     0   stevel 
   1054     0   stevel extern char **environ;
   1055     0   stevel 
   1056     0   stevel /*
   1057     0   stevel  * Check if the environment variable vp affects this csh's behavior
   1058     0   stevel  * and therefore we should call setlocale() or not.
   1059     0   stevel  * This function has two side effects when it returns 1:
   1060     0   stevel  *	variable islocalevar_catnum is set to the LC_xxx value.
   1061     0   stevel  *	variable islocalevar_catname is set to the string "LC_xxx"
   1062     0   stevel  */
   1063     0   stevel static int	islocalevar_catnum;
   1064     0   stevel static char	*islocalevar_catname;
   1065     0   stevel 
   1066     0   stevel static
   1067     0   stevel bool
   1068     0   stevel islocalevar(tchar *vp)
   1069     0   stevel {
   1070     0   stevel 	static struct lcinfo {
   1071     0   stevel 		tchar *	evname; /* The name of the env. var. */
   1072     0   stevel 	} categories_we_care[] = {
   1073     0   stevel 	    S_LANG, S_LC_ALL, S_LC_CTYPE, S_LC_MESSAGES,
   1074     0   stevel 	    NOSTR		/* assumption: LC_xxx >= 0 */
   1075     0   stevel 	};
   1076     0   stevel 	struct lcinfo *p = categories_we_care;
   1077     0   stevel 
   1078     0   stevel 	do {
   1079     0   stevel 		if (strcmp_(vp, p->evname) == 0) {
   1080     0   stevel 			return (1);
   1081     0   stevel 		}
   1082     0   stevel 	} while (((++p)->evname) != NOSTR);
   1083     0   stevel 	return (0);
   1084     0   stevel }
   1085     0   stevel 
   1086     0   stevel void
   1087     0   stevel dosetenv(tchar **v)
   1088     0   stevel {
   1089     0   stevel 	tchar *vp, *lp;
   1090     0   stevel 
   1091     0   stevel #ifdef TRACE
   1092     0   stevel 	tprintf("TRACE- dosetenv()\n");
   1093     0   stevel #endif
   1094     0   stevel 	v++;
   1095     0   stevel 	if ((vp = *v++) == 0) {
   1096     0   stevel 		char **ep;
   1097     0   stevel 
   1098     0   stevel 		if (setintr) {
   1099     0   stevel 			(void) sigsetmask(sigblock(0) & ~ sigmask(SIGINT));
   1100     0   stevel 		}
   1101     0   stevel 		for (ep = environ; *ep; ep++) {
   1102     0   stevel 			printf("%s\n", *ep);
   1103     0   stevel 		}
   1104     0   stevel 		return;
   1105     0   stevel 	}
   1106     0   stevel 
   1107     0   stevel 	if ((lp = *v++) == 0) {
   1108     0   stevel 		lp = S_;	/* "" */
   1109     0   stevel 	}
   1110     0   stevel 	local_setenv(vp, lp = globone(lp));
   1111     0   stevel 	if (eq(vp, S_PATH)) {
   1112     0   stevel 		importpath(lp);
   1113     0   stevel 		dohash(xhash);
   1114     0   stevel 	} else if (islocalevar(vp)) {
   1115     0   stevel 		if (!setlocale(LC_ALL, "")) {
   1116     0   stevel 			error("Locale could not be set properly");
   1117     0   stevel 		}
   1118     0   stevel 	}
   1119     0   stevel 
   1120     0   stevel 	xfree(lp);
   1121     0   stevel }
   1122     0   stevel 
   1123     0   stevel void
   1124     0   stevel dounsetenv(tchar **v)
   1125     0   stevel {
   1126     0   stevel #ifdef TRACE
   1127     0   stevel 	tprintf("TRACE- dounsetenv()\n");
   1128     0   stevel #endif
   1129     0   stevel 	v++;
   1130     0   stevel 	do {
   1131     0   stevel 		local_unsetenv(*v);
   1132     0   stevel 		if (islocalevar(*v++)) {
   1133     0   stevel 			setlocale(LC_ALL, "");	/* Hope no error! */
   1134     0   stevel 		}
   1135     0   stevel 	} while (*v);
   1136     0   stevel }
   1137     0   stevel 
   1138     0   stevel void
   1139     0   stevel local_setenv(tchar *name, tchar *val)
   1140     0   stevel {
   1141     0   stevel 	char **ep = environ;
   1142     0   stevel 	tchar *cp;
   1143     0   stevel 	char *dp;
   1144     0   stevel 	tchar *ep_;	/* temporary */
   1145     0   stevel 	char *blk[2], **oep = ep;
   1146     0   stevel 
   1147     0   stevel #ifdef TRACE
   1148     0   stevel 	/* tprintf("TRACE- local_setenv(%t, %t)\n", name, val); */
   1149     0   stevel 	/* printf("IN local_setenv args = (%t)\n", val); */
   1150     0   stevel #endif
   1151     0   stevel 	for (; *ep; ep++) {
   1152     0   stevel #ifdef MBCHAR
   1153     0   stevel 		for (cp = name, dp = *ep; *cp && *dp; cp++) {
   1154     0   stevel 			/*
   1155     0   stevel 			 * This loop compares two chars in different
   1156     0   stevel 			 * representations, EUC (as char *) and wchar_t
   1157     0   stevel 			 * (in tchar), and ends when they are different.
   1158     0   stevel 			 */
   1159     0   stevel 			wchar_t	dwc;
   1160     0   stevel 			int	n;
   1161     0   stevel 
   1162     0   stevel 			n = mbtowc(&dwc, dp, MB_CUR_MAX);
   1163     0   stevel 			if (n <= 0) {
   1164     0   stevel 				break; /* Illegal multibyte. */
   1165     0   stevel 			}
   1166     0   stevel 			dp += n; /* Advance to next multibyte char. */
   1167     0   stevel 			if (dwc == (wchar_t)(*cp & TRIM)) {
   1168     0   stevel 				continue;
   1169     0   stevel 			} else  {
   1170     0   stevel 				break;
   1171     0   stevel 			}
   1172     0   stevel 		}
   1173     0   stevel #else /* !MBCHAR */
   1174     0   stevel 		for (cp = name, dp = *ep; *cp && (char)*cp == *dp; cp++, dp++) {
   1175     0   stevel 			continue;
   1176     0   stevel 		}
   1177     0   stevel #endif /* !MBCHAR */
   1178     0   stevel 		if (*cp != 0 || *dp != '=') {
   1179     0   stevel 			continue;
   1180     0   stevel 		}
   1181     0   stevel 		cp = strspl(S_EQ, val);
   1182     0   stevel 		xfree(*ep);
   1183     0   stevel 		ep_ = strspl(name, cp);		/* ep_ is xalloc'ed */
   1184     0   stevel 		xfree(cp);
   1185     0   stevel 		/*
   1186     0   stevel 		 * Trimming is not needed here.
   1187     0   stevel 		 * trim();
   1188     0   stevel 		 */
   1189     0   stevel 		*ep = tstostr(NULL, ep_);
   1190     0   stevel 		xfree(ep_);			/* because temp.  use */
   1191     0   stevel 		return;
   1192     0   stevel 	}
   1193     0   stevel 	ep_ = strspl(name, S_EQ);		/* ep_ is xalloc'ed */
   1194     0   stevel 	blk[0] = tstostr(NULL, ep_);
   1195     0   stevel 	blk[1] = 0;
   1196     0   stevel 	xfree(ep_);
   1197   356   muffin 	environ = (char **)blkspl_((char **)environ, blk);
   1198     0   stevel 	xfree((void *)oep);
   1199     0   stevel 	local_setenv(name, val);
   1200     0   stevel }
   1201     0   stevel 
   1202     0   stevel void
   1203     0   stevel local_unsetenv(tchar *name)
   1204     0   stevel {
   1205     0   stevel 	char **ep = environ;
   1206     0   stevel 	tchar *cp;
   1207     0   stevel 	char *dp;
   1208     0   stevel 	char **oep = ep;
   1209     0   stevel 	char *cp_;	/* tmp use */
   1210   356   muffin 	static int cnt = 0;	/* delete counter */
   1211     0   stevel 
   1212     0   stevel #ifdef TRACE
   1213     0   stevel 	tprintf("TRACE- local_unsetenv()\n");
   1214     0   stevel #endif
   1215     0   stevel 	for (; *ep; ep++) {
   1216     0   stevel #ifdef MBCHAR
   1217     0   stevel 		for (cp = name, dp = *ep; *cp && *dp; cp++) {
   1218     0   stevel 			/*
   1219     0   stevel 			 * This loop compares two chars in different
   1220     0   stevel 			 * representations, EUC (as char *) and wchar_t
   1221     0   stevel 			 * (in tchar), and ends when they are different.
   1222     0   stevel 			 */
   1223     0   stevel 			wchar_t	dwc;
   1224     0   stevel 			int	n;
   1225     0   stevel 
   1226     0   stevel 			n = mbtowc(&dwc, dp, MB_CUR_MAX);
   1227     0   stevel 			if (n <= 0) {
   1228     0   stevel 				break; /* Illegal multibyte. */
   1229     0   stevel 			}
   1230     0   stevel 			dp += n; /* Advance to next multibyte char. */
   1231     0   stevel 			if (dwc == (wchar_t)(*cp & TRIM)) {
   1232     0   stevel 				continue;
   1233     0   stevel 			} else {
   1234     0   stevel 				break;
   1235     0   stevel 			}
   1236     0   stevel 		}
   1237     0   stevel #else /* !MBCHAR */
   1238     0   stevel 		for (cp = name, dp = *ep; *cp && (char)*cp == *dp; cp++, dp++) {
   1239     0   stevel 			continue;
   1240     0   stevel 		}
   1241     0   stevel #endif /* !MBCHAR */
   1242     0   stevel 		if (*cp != 0 || *dp != '=') {
   1243     0   stevel 			continue;
   1244     0   stevel 		}
   1245     0   stevel 		cp_ = *ep;
   1246     0   stevel 		*ep = 0;
   1247   356   muffin 		environ = (char **)blkspl_((char **)environ, ep+1);
   1248     0   stevel 		*ep = cp_;
   1249     0   stevel 		xfree(cp_);
   1250     0   stevel 		xfree((void *)oep);
   1251     0   stevel 		return;
   1252     0   stevel 	}
   1253     0   stevel }
   1254     0   stevel 
   1255     0   stevel void
   1256     0   stevel doumask(tchar **v)
   1257     0   stevel {
   1258     0   stevel 	tchar *cp = v[1];
   1259     0   stevel 	int i;
   1260     0   stevel 
   1261     0   stevel #ifdef TRACE
   1262     0   stevel 	tprintf("TRACE- dounmask()\n");
   1263     0   stevel #endif
   1264     0   stevel 	if (cp == 0) {
   1265     0   stevel 		i = umask(0);
   1266     0   stevel 		(void) umask(i);
   1267     0   stevel 		printf("%o\n", i);
   1268     0   stevel 		return;
   1269     0   stevel 	}
   1270     0   stevel 	i = 0;
   1271     0   stevel 	while (digit(*cp) && *cp != '8' && *cp != '9') {
   1272     0   stevel 		i = i * 8 + *cp++ - '0';
   1273     0   stevel 	}
   1274     0   stevel 	if (*cp || i < 0 || i > 0777) {
   1275     0   stevel 		bferr("Improper mask");
   1276     0   stevel 	}
   1277     0   stevel 	(void) umask(i);
   1278     0   stevel }
   1279     0   stevel 
   1280     0   stevel 
   1281     0   stevel struct limits *
   1282     0   stevel findlim(tchar *cp)
   1283     0   stevel {
   1284     0   stevel 	struct limits *lp, *res;
   1285     0   stevel 
   1286     0   stevel #ifdef TRACE
   1287     0   stevel 	tprintf("TRACE- findlim()\n");
   1288     0   stevel #endif
   1289     0   stevel 	res = 0;
   1290     0   stevel 	for (lp = limits; lp->limconst >= 0; lp++) {
   1291     0   stevel 		if (prefix(cp, lp->limname)) {
   1292     0   stevel 			if (res) {
   1293     0   stevel 				bferr("Ambiguous");
   1294     0   stevel 			}
   1295     0   stevel 			res = lp;
   1296     0   stevel 		}
   1297     0   stevel 	}
   1298     0   stevel 	if (res) {
   1299     0   stevel 		return (res);
   1300     0   stevel 	}
   1301     0   stevel 	bferr("No such limit");
   1302     0   stevel 	/*NOTREACHED*/
   1303     0   stevel }
   1304     0   stevel 
   1305     0   stevel void
   1306     0   stevel dolimit(tchar **v)
   1307     0   stevel {
   1308     0   stevel 	struct limits *lp;
   1309     0   stevel 	rlim_t limit;
   1310     0   stevel 	tchar hard = 0;
   1311     0   stevel 
   1312     0   stevel #ifdef TRACE
   1313     0   stevel 	tprintf("TRACE- dolimit()\n");
   1314     0   stevel #endif
   1315     0   stevel 	v++;
   1316     0   stevel 	if (*v && eq(*v, S_h)) {
   1317     0   stevel 		hard = 1;
   1318     0   stevel 		v++;
   1319     0   stevel 	}
   1320     0   stevel 	if (*v == 0) {
   1321     0   stevel 		for (lp = limits; lp->limconst >= 0; lp++) {
   1322     0   stevel 			plim(lp, hard);
   1323     0   stevel 		}
   1324     0   stevel 		return;
   1325     0   stevel 	}
   1326     0   stevel 	lp = findlim(v[0]);
   1327     0   stevel 	if (v[1] == 0) {
   1328     0   stevel 		plim(lp,  hard);
   1329     0   stevel 		return;
   1330     0   stevel 	}
   1331     0   stevel 	switch (getval(lp, v+1, &limit)) {
   1332     0   stevel 	case 0:
   1333     0   stevel 		error("Value specified for limit is too large");
   1334     0   stevel 		return;
   1335     0   stevel 	case (-1):
   1336     0   stevel 		error("Numeric conversion failed");
   1337     0   stevel 		return;
   1338     0   stevel 	default:
   1339     0   stevel 		if (setlim(lp, hard, limit) < 0) {
   1340     0   stevel 			error(NOSTR);
   1341     0   stevel 		}
   1342     0   stevel 	}
   1343     0   stevel }
   1344     0   stevel 
   1345     0   stevel static int
   1346     0   stevel getval(struct limits *lp, tchar **v, rlim_t *retval)
   1347     0   stevel {
   1348     0   stevel 	rlim_t value, tmp, tmp2;
   1349     0   stevel 	tchar *cp = *v++;
   1350     0   stevel 	char chbuf[BUFSIZ * MB_LEN_MAX];
   1351     0   stevel 
   1352     0   stevel #ifdef TRACE
   1353     0   stevel 	tprintf("TRACE- getval()\n");
   1354     0   stevel #endif
   1355     0   stevel 
   1356     0   stevel 	tstostr(chbuf, cp);
   1357     0   stevel 	errno = 0;
   1358     0   stevel 	value = strtoull(chbuf, NULL, 0);
   1359     0   stevel /*
   1360     0   stevel  * we must accept zero, but the conversion can fail and give us
   1361     0   stevel  * zero as well...try to deal with it as gracefully as possible
   1362     0   stevel  * by checking for EINVAL
   1363     0   stevel  */
   1364     0   stevel 	if (value == 0 && errno == EINVAL)
   1365     0   stevel 		return (-1);
   1366     0   stevel 
   1367     0   stevel 	while (digit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') {
   1368     0   stevel 		cp++;
   1369     0   stevel 	}
   1370     0   stevel 	if (*cp == 0) {
   1371     0   stevel 		if (*v == 0) {
   1372     0   stevel 			tmp = value * (rlim_t)lp->limdiv;
   1373     0   stevel 			/* Check for overflow */
   1374     0   stevel 			if (tmp >= value) {
   1375     0   stevel 				*retval = tmp;
   1376     0   stevel 				return (1);
   1377     0   stevel 			} else {
   1378     0   stevel 				return (0);
   1379     0   stevel 			}
   1380     0   stevel 		}
   1381     0   stevel 		cp = *v;
   1382     0   stevel 	}
   1383     0   stevel 	switch (*cp) {
   1384     0   stevel 
   1385     0   stevel 	case ':':
   1386     0   stevel 		if (lp->limconst != RLIMIT_CPU) {
   1387     0   stevel 			goto badscal;
   1388     0   stevel 		}
   1389     0   stevel 		tstostr(chbuf, cp + 1);
   1390     0   stevel 		tmp = strtoull(chbuf, NULL, 0);
   1391     0   stevel 		tmp2 = value * 60 + tmp;
   1392     0   stevel 		if (tmp2 >= value) {
   1393     0   stevel 			*retval = tmp2;
   1394     0   stevel 			return (1);
   1395     0   stevel 		} else {
   1396     0   stevel 			return (0);
   1397     0   stevel 		}
   1398     0   stevel 
   1399     0   stevel 	case 'h':
   1400     0   stevel 		if (lp->limconst != RLIMIT_CPU) {
   1401     0   stevel 			goto badscal;
   1402     0   stevel 		}
   1403     0   stevel 		limtail(cp, S_hours);
   1404     0   stevel 		tmp = value * 3600;
   1405     0   stevel 		if (tmp < value) {
   1406     0   stevel 			return (0);
   1407     0   stevel 		}
   1408     0   stevel 		value = tmp;
   1409     0   stevel 		break;
   1410     0   stevel 
   1411     0   stevel 	case 'm':
   1412     0   stevel 		if (lp->limconst == RLIMIT_CPU) {
   1413     0   stevel 			limtail(cp, S_minutes);
   1414     0   stevel 			tmp = value * 60;
   1415     0   stevel 			if (tmp < value) {
   1416     0   stevel 				return (0);
   1417     0   stevel 			}
   1418     0   stevel 			value = tmp;
   1419     0   stevel 			break;
   1420     0   stevel 		}
   1421     0   stevel 	case 'M':
   1422     0   stevel 		if (lp->limconst == RLIMIT_CPU) {
   1423     0   stevel 			goto badscal;
   1424     0   stevel 		}
   1425     0   stevel 		*cp = 'm';
   1426     0   stevel 		limtail(cp, S_megabytes);
   1427     0   stevel 		tmp = value * 1024 * 1024;
   1428     0   stevel 		if (tmp < value) {
   1429     0   stevel 			return (0);
   1430     0   stevel 		}
   1431     0   stevel 		value = tmp;
   1432     0   stevel 		break;
   1433     0   stevel 
   1434     0   stevel 	case 's':
   1435     0   stevel 		if (lp->limconst != RLIMIT_CPU) {
   1436     0   stevel 			goto badscal;
   1437     0   stevel 		}
   1438     0   stevel 		limtail(cp, S_seconds);
   1439     0   stevel 		break;
   1440     0   stevel 
   1441     0   stevel 	case 'k':
   1442     0   stevel 		if (lp->limconst == RLIMIT_CPU) {
   1443     0   stevel 			goto badscal;
   1444     0   stevel 		}
   1445     0   stevel 		limtail(cp, S_kbytes);
   1446     0   stevel 		tmp = value * 1024;
   1447     0   stevel 		if (tmp < value) {
   1448     0   stevel 			return (0);
   1449     0   stevel 		}
   1450     0   stevel 		value = tmp;
   1451     0   stevel 		break;
   1452     0   stevel 
   1453     0   stevel 	case 'u':
   1454     0   stevel 		limtail(cp, S_unlimited);
   1455     0   stevel 		*retval = RLIM_INFINITY;
   1456     0   stevel 		return (1);
   1457     0   stevel 
   1458     0   stevel 	default:
   1459     0   stevel badscal:
   1460     0   stevel 		bferr("Improper or unknown scale factor");
   1461     0   stevel 	}
   1462     0   stevel 	*retval = value;
   1463     0   stevel 	return (1);
   1464     0   stevel }
   1465     0   stevel 
   1466     0   stevel void
   1467     0   stevel limtail(tchar *cp, tchar *str0)
   1468     0   stevel {
   1469     0   stevel 	tchar *str = str0;
   1470     0   stevel #ifdef TRACE
   1471     0   stevel 	tprintf("TRACE- limtail()\n");
   1472     0   stevel #endif
   1473     0   stevel 
   1474     0   stevel 	while (*cp && *cp == *str) {
   1475     0   stevel 		cp++, str++;
   1476     0   stevel 	}
   1477     0   stevel 	if (*cp) {
   1478     0   stevel 		error("Bad scaling; did you mean ``%t''?", str0);
   1479     0   stevel 	}
   1480     0   stevel }
   1481     0   stevel 
   1482     0   stevel void
   1483     0   stevel plim(struct limits *lp, tchar hard)
   1484     0   stevel {
   1485     0   stevel 	struct rlimit rlim;
   1486     0   stevel 	char buf[BUFSZ];
   1487     0   stevel 	char *pbuf;
   1488     0   stevel 	rlim_t limit;
   1489     0   stevel 
   1490     0   stevel #ifdef TRACE
   1491     0   stevel 	tprintf("TRACE- plim()\n");
   1492     0   stevel #endif
   1493     0   stevel 	printf("%t \t", lp->limname);
   1494     0   stevel 	(void) getrlimit(lp->limconst, &rlim);
   1495     0   stevel 	limit = hard ? rlim.rlim_max : rlim.rlim_cur;
   1496     0   stevel 	if (limit == RLIM_INFINITY) {
   1497     0   stevel 		printf("unlimited");
   1498     0   stevel 	} else if (lp->limconst == RLIMIT_CPU) {
   1499     0   stevel 		psecs_ull(limit);
   1500     0   stevel 	} else {
   1501     0   stevel 		buf[BUFSZ - 1] = '\0';
   1502     0   stevel 		pbuf = ulltostr((limit / lp->limdiv), &buf[BUFSZ - 1]);
   1503     0   stevel 		printf("%s %t", pbuf, lp->limscale);
   1504     0   stevel 	}
   1505     0   stevel 	printf("\n");
   1506     0   stevel }
   1507     0   stevel 
   1508     0   stevel void
   1509     0   stevel dounlimit(tchar **v)
   1510     0   stevel {
   1511     0   stevel 	struct limits *lp;
   1512     0   stevel 	int err = 0;
   1513     0   stevel 	tchar hard = 0;
   1514     0   stevel #ifdef TRACE
   1515     0   stevel 	tprintf("TRACE- dounlimit()\n");
   1516     0   stevel #endif
   1517     0   stevel 
   1518     0   stevel 	v++;
   1519     0   stevel 	if (*v && eq(*v, S_h)) {
   1520     0   stevel 		hard = 1;
   1521     0   stevel 		v++;
   1522     0   stevel 	}
   1523     0   stevel 	if (*v == 0) {
   1524     0   stevel 		for (lp = limits; lp->limconst >= 0; lp++) {
   1525     0   stevel 			if (setlim(lp, hard, RLIM_INFINITY) < 0) {
   1526     0   stevel 				err++;
   1527     0   stevel 			}
   1528     0   stevel 		}
   1529     0   stevel 		if (err) {
   1530     0   stevel 			error(NULL);
   1531     0   stevel 		}
   1532     0   stevel 		return;
   1533     0   stevel 	}
   1534     0   stevel 	while (*v) {
   1535     0   stevel 		lp = findlim(*v++);
   1536     0   stevel 		if (setlim(lp, hard, RLIM_INFINITY) < 0) {
   1537     0   stevel 			error(NULL);
   1538     0   stevel 		}
   1539     0   stevel 	}
   1540     0   stevel }
   1541     0   stevel 
   1542     0   stevel int
   1543     0   stevel setlim(struct limits *lp, tchar hard, rlim_t limit)
   1544     0   stevel {
   1545     0   stevel 	struct rlimit rlim;
   1546     0   stevel 
   1547     0   stevel #ifdef TRACE
   1548     0   stevel 	tprintf("TRACE- setlim()\n");
   1549     0   stevel #endif
   1550     0   stevel 	(void) getrlimit(lp->limconst, &rlim);
   1551     0   stevel 	if (hard) {
   1552     0   stevel 		rlim.rlim_max = limit;
   1553     0   stevel 	} else if (limit == RLIM_INFINITY && geteuid() != 0) {
   1554     0   stevel 		rlim.rlim_cur = rlim.rlim_max;
   1555     0   stevel 	} else {
   1556     0   stevel 		rlim.rlim_cur = limit;
   1557     0   stevel 	}
   1558     0   stevel 	if (setrlimit(lp->limconst, &rlim) < 0) {
   1559     0   stevel 		printf("%t: %t: Can't %s%s limit\n", bname, lp->limname,
   1560     0   stevel 		    limit == RLIM_INFINITY ? "remove" : "set",
   1561     0   stevel 		    hard ? " hard" : "");
   1562     0   stevel 		return (-1);
   1563     0   stevel 	}
   1564     0   stevel 	return (0);
   1565     0   stevel }
   1566     0   stevel 
   1567     0   stevel void
   1568     0   stevel dosuspend()
   1569     0   stevel {
   1570     0   stevel 	int ctpgrp;
   1571     0   stevel 	void (*old)();
   1572     0   stevel 
   1573     0   stevel #ifdef TRACE
   1574     0   stevel 	tprintf("TRACE- dosuspend()\n");
   1575     0   stevel #endif
   1576     0   stevel 	if (loginsh) {
   1577     0   stevel 		error("Can't suspend a login shell (yet)");
   1578     0   stevel 	}
   1579     0   stevel 	if (getpid() == getsid(0)) {
   1580     0   stevel 		error("Can't suspend this shell");
   1581     0   stevel 	}
   1582     0   stevel 	untty();
   1583     0   stevel 	old = (void (*)())signal(SIGTSTP, SIG_DFL);
   1584     0   stevel 	(void) kill(0, SIGTSTP);
   1585     0   stevel 	/* the shell stops here */
   1586     0   stevel 	(void) signal(SIGTSTP, old);
   1587     0   stevel 	if (tpgrp != -1) {
   1588     0   stevel retry:
   1589     0   stevel 		(void) ioctl(FSHTTY, TIOCGPGRP,  (char *)&ctpgrp);
   1590     0   stevel 		if (ctpgrp != opgrp) {
   1591     0   stevel 			old = (void (*)())signal(SIGTTIN, SIG_DFL);
   1592     0   stevel 			(void) kill(0, SIGTTIN);
   1593     0   stevel 			(void) signal(SIGTTIN, old);
   1594     0   stevel 			goto retry;
   1595     0   stevel 		}
   1596     0   stevel 		(void) setpgid(0, shpgrp);
   1597     0   stevel 		(void) ioctl(FSHTTY, TIOCSPGRP, (char *)&shpgrp);
   1598     0   stevel 	}
   1599     0   stevel }
   1600     0   stevel 
   1601     0   stevel void
   1602     0   stevel doeval(tchar **v)
   1603     0   stevel {
   1604     0   stevel 	tchar **oevalvec = evalvec;
   1605     0   stevel 	tchar *oevalp = evalp;
   1606     0   stevel 	jmp_buf osetexit;
   1607     0   stevel 	int reenter;
   1608     0   stevel 	tchar **gv = 0;
   1609     0   stevel 
   1610     0   stevel #ifdef TRACE
   1611     0   stevel 	tprintf("TRACE- doeval()\n");
   1612     0   stevel #endif
   1613     0   stevel 	v++;
   1614     0   stevel 	if (*v == 0) {
   1615     0   stevel 		return;
   1616     0   stevel 	}
   1617     0   stevel 	gflag = 0, tglob(v);
   1618     0   stevel 	if (gflag) {
   1619     0   stevel 		gv = v = glob(v);
   1620     0   stevel 		gargv = 0;
   1621     0   stevel 		if (v == 0) {
   1622     0   stevel 			error("No match");
   1623     0   stevel 		}
   1624     0   stevel 		v = copyblk(v);
   1625     0   stevel 	} else {
   1626     0   stevel 		trim(v);
   1627     0   stevel 	}
   1628     0   stevel 	getexit(osetexit);
   1629     0   stevel 	reenter = 0;
   1630     0   stevel 	setexit();
   1631     0   stevel 	reenter++;
   1632     0   stevel 	if (reenter == 1) {
   1633     0   stevel 		evalvec = v;
   1634     0   stevel 		evalp = 0;
   1635     0   stevel 		process(0);
   1636     0   stevel 	}
   1637     0   stevel 	evalvec = oevalvec;
   1638     0   stevel 	evalp = oevalp;
   1639     0   stevel 	doneinp = 0;
   1640     0   stevel 	if (gv) {
   1641     0   stevel 		blkfree(gv);
   1642     0   stevel 	}
   1643     0   stevel 	resexit(osetexit);
   1644     0   stevel 	if (reenter >= 2) {
   1645     0   stevel 		error(NULL);
   1646     0   stevel 	}
   1647     0   stevel }
   1648