Home | History | Annotate | Line # | Download | only in csh
func.c revision 1.6
      1 /*-
      2  * Copyright (c) 1980, 1991 The Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 #ifndef lint
     35 /*static char sccsid[] = "from: @(#)func.c	5.20 (Berkeley) 6/27/91";*/
     36 static char rcsid[] = "$Id: func.c,v 1.6 1994/05/05 03:00:45 cgd Exp $";
     37 #endif /* not lint */
     38 
     39 #include <sys/types.h>
     40 #include <sys/stat.h>
     41 #include <signal.h>
     42 #include <locale.h>
     43 #include <stdlib.h>
     44 #include <string.h>
     45 #include <unistd.h>
     46 #if __STDC__
     47 # include <stdarg.h>
     48 #else
     49 # include <varargs.h>
     50 #endif
     51 
     52 #include "csh.h"
     53 #include "extern.h"
     54 #include "pathnames.h"
     55 
     56 extern char **environ;
     57 
     58 static int zlast = -1;
     59 static void	islogin __P((void));
     60 static void	reexecute __P((struct command *));
     61 static void	preread __P((void));
     62 static void	doagain __P((void));
     63 static int	getword __P((Char *));
     64 static int	keyword __P((Char *));
     65 static void	Unsetenv __P((Char *));
     66 static void	toend __P((void));
     67 static void	xecho __P((int, Char **));
     68 
     69 struct biltins *
     70 isbfunc(t)
     71     struct command *t;
     72 {
     73     register Char *cp = t->t_dcom[0];
     74     register struct biltins *bp, *bp1, *bp2;
     75     static struct biltins label = {"", dozip, 0, 0};
     76     static struct biltins foregnd = {"%job", dofg1, 0, 0};
     77     static struct biltins backgnd = {"%job &", dobg1, 0, 0};
     78 
     79     if (lastchr(cp) == ':') {
     80 	label.bname = short2str(cp);
     81 	return (&label);
     82     }
     83     if (*cp == '%') {
     84 	if (t->t_dflg & F_AMPERSAND) {
     85 	    t->t_dflg &= ~F_AMPERSAND;
     86 	    backgnd.bname = short2str(cp);
     87 	    return (&backgnd);
     88 	}
     89 	foregnd.bname = short2str(cp);
     90 	return (&foregnd);
     91     }
     92     /*
     93      * Binary search Bp1 is the beginning of the current search range. Bp2 is
     94      * one past the end.
     95      */
     96     for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) {
     97 	register i;
     98 
     99 	bp = bp1 + ((bp2 - bp1) >> 1);
    100 	if ((i = *cp - *bp->bname) == 0 &&
    101 	    (i = Strcmp(cp, str2short(bp->bname))) == 0)
    102 	    return bp;
    103 	if (i < 0)
    104 	    bp2 = bp;
    105 	else
    106 	    bp1 = bp + 1;
    107     }
    108     return (0);
    109 }
    110 
    111 void
    112 func(t, bp)
    113     register struct command *t;
    114     register struct biltins *bp;
    115 {
    116     int     i;
    117 
    118     xechoit(t->t_dcom);
    119     setname(bp->bname);
    120     i = blklen(t->t_dcom) - 1;
    121     if (i < bp->minargs)
    122 	stderror(ERR_NAME | ERR_TOOFEW);
    123     if (i > bp->maxargs)
    124 	stderror(ERR_NAME | ERR_TOOMANY);
    125     (*bp->bfunct) (t->t_dcom, t);
    126 }
    127 
    128 void
    129 doonintr(v)
    130     Char  **v;
    131 {
    132     register Char *cp;
    133     register Char *vv = v[1];
    134 
    135     if (parintr == SIG_IGN)
    136 	return;
    137     if (setintr && intty)
    138 	stderror(ERR_NAME | ERR_TERMINAL);
    139     cp = gointr;
    140     gointr = 0;
    141     xfree((ptr_t) cp);
    142     if (vv == 0) {
    143 	if (setintr)
    144 	    (void) sigblock(sigmask(SIGINT));
    145 	else
    146 	    (void) signal(SIGINT, SIG_DFL);
    147 	gointr = 0;
    148     }
    149     else if (eq((vv = strip(vv)), STRminus)) {
    150 	(void) signal(SIGINT, SIG_IGN);
    151 	gointr = Strsave(STRminus);
    152     }
    153     else {
    154 	gointr = Strsave(vv);
    155 	(void) signal(SIGINT, pintr);
    156     }
    157 }
    158 
    159 void
    160 donohup()
    161 {
    162     if (intty)
    163 	stderror(ERR_NAME | ERR_TERMINAL);
    164     if (setintr == 0) {
    165 	(void) signal(SIGHUP, SIG_IGN);
    166     }
    167 }
    168 
    169 void
    170 dozip()
    171 {
    172     ;
    173 }
    174 
    175 void
    176 prvars()
    177 {
    178     plist(&shvhed);
    179 }
    180 
    181 void
    182 doalias(v)
    183     register Char **v;
    184 {
    185     register struct varent *vp;
    186     register Char *p;
    187 
    188     v++;
    189     p = *v++;
    190     if (p == 0)
    191 	plist(&aliases);
    192     else if (*v == 0) {
    193 	vp = adrof1(strip(p), &aliases);
    194 	if (vp)
    195 	    blkpr(vp->vec), xprintf("\n");
    196     }
    197     else {
    198 	if (eq(p, STRalias) || eq(p, STRunalias)) {
    199 	    setname(short2str(p));
    200 	    stderror(ERR_NAME | ERR_DANGER);
    201 	}
    202 	set1(strip(p), saveblk(v), &aliases);
    203     }
    204 }
    205 
    206 void
    207 unalias(v)
    208     Char  **v;
    209 {
    210     unset1(v, &aliases);
    211 }
    212 
    213 void
    214 dologout()
    215 {
    216     islogin();
    217     goodbye();
    218 }
    219 
    220 void
    221 dologin(v)
    222     Char  **v;
    223 {
    224     islogin();
    225     rechist();
    226     (void) signal(SIGTERM, parterm);
    227     (void) execl(_PATH_LOGIN, "login", short2str(v[1]), NULL);
    228     untty();
    229     xexit(1);
    230 }
    231 
    232 static void
    233 islogin()
    234 {
    235     if (chkstop == 0 && setintr)
    236 	panystop(0);
    237     if (loginsh)
    238 	return;
    239     stderror(ERR_NOTLOGIN);
    240 }
    241 
    242 void
    243 doif(v, kp)
    244     Char  **v;
    245     struct command *kp;
    246 {
    247     register int i;
    248     register Char **vv;
    249 
    250     v++;
    251     i = exp(&v);
    252     vv = v;
    253     if (*vv == NULL)
    254 	stderror(ERR_NAME | ERR_EMPTYIF);
    255     if (eq(*vv, STRthen)) {
    256 	if (*++vv)
    257 	    stderror(ERR_NAME | ERR_IMPRTHEN);
    258 	setname(short2str(STRthen));
    259 	/*
    260 	 * If expression was zero, then scan to else, otherwise just fall into
    261 	 * following code.
    262 	 */
    263 	if (!i)
    264 	    search(T_IF, 0, NULL);
    265 	return;
    266     }
    267     /*
    268      * Simple command attached to this if. Left shift the node in this tree,
    269      * munging it so we can reexecute it.
    270      */
    271     if (i) {
    272 	lshift(kp->t_dcom, vv - kp->t_dcom);
    273 	reexecute(kp);
    274 	donefds();
    275     }
    276 }
    277 
    278 /*
    279  * Reexecute a command, being careful not
    280  * to redo i/o redirection, which is already set up.
    281  */
    282 static void
    283 reexecute(kp)
    284     register struct command *kp;
    285 {
    286     kp->t_dflg &= F_SAVE;
    287     kp->t_dflg |= F_REPEAT;
    288     /*
    289      * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set
    290      * pgrp's as the jobs would then have no way to get the tty (we can't give
    291      * it to them, and our parent wouldn't know their pgrp, etc.
    292      */
    293     execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL);
    294 }
    295 
    296 void
    297 doelse()
    298 {
    299     search(T_ELSE, 0, NULL);
    300 }
    301 
    302 void
    303 dogoto(v)
    304     Char  **v;
    305 {
    306     register struct whyle *wp;
    307     Char   *lp;
    308 
    309     /*
    310      * While we still can, locate any unknown ends of existing loops. This
    311      * obscure code is the WORST result of the fact that we don't really parse.
    312      */
    313     zlast = T_GOTO;
    314     for (wp = whyles; wp; wp = wp->w_next)
    315 	if (wp->w_end == 0) {
    316 	    search(T_BREAK, 0, NULL);
    317 	    wp->w_end = fseekp;
    318 	}
    319 	else
    320 	    bseek(wp->w_end);
    321     search(T_GOTO, 0, lp = globone(v[1], G_ERROR));
    322     xfree((ptr_t) lp);
    323     /*
    324      * Eliminate loops which were exited.
    325      */
    326     wfree();
    327 }
    328 
    329 void
    330 doswitch(v)
    331     register Char **v;
    332 {
    333     register Char *cp, *lp;
    334 
    335     v++;
    336     if (!*v || *(*v++) != '(')
    337 	stderror(ERR_SYNTAX);
    338     cp = **v == ')' ? STRNULL : *v++;
    339     if (*(*v++) != ')')
    340 	v--;
    341     if (*v)
    342 	stderror(ERR_SYNTAX);
    343     search(T_SWITCH, 0, lp = globone(cp, G_ERROR));
    344     xfree((ptr_t) lp);
    345 }
    346 
    347 void
    348 dobreak()
    349 {
    350     if (whyles)
    351 	toend();
    352     else
    353 	stderror(ERR_NAME | ERR_NOTWHILE);
    354 }
    355 
    356 void
    357 doexit(v)
    358     Char  **v;
    359 {
    360     if (chkstop == 0 && (intty || intact) && evalvec == 0)
    361 	panystop(0);
    362     /*
    363      * Don't DEMAND parentheses here either.
    364      */
    365     v++;
    366     if (*v) {
    367 	set(STRstatus, putn(exp(&v)));
    368 	if (*v)
    369 	    stderror(ERR_NAME | ERR_EXPRESSION);
    370     }
    371     btoeof();
    372     if (intty)
    373 	(void) close(SHIN);
    374 }
    375 
    376 void
    377 doforeach(v)
    378     register Char **v;
    379 {
    380     register Char *cp, *sp;
    381     register struct whyle *nwp;
    382 
    383     v++;
    384     sp = cp = strip(*v);
    385     if (!letter(*sp))
    386 	stderror(ERR_NAME | ERR_VARBEGIN);
    387     while (*cp && alnum(*cp))
    388 	cp++;
    389     if (*cp)
    390 	stderror(ERR_NAME | ERR_VARALNUM);
    391     if ((cp - sp) > MAXVARLEN)
    392 	stderror(ERR_NAME | ERR_VARTOOLONG);
    393     cp = *v++;
    394     if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')')
    395 	stderror(ERR_NAME | ERR_NOPAREN);
    396     v++;
    397     gflag = 0, tglob(v);
    398     v = globall(v);
    399     if (v == 0)
    400 	stderror(ERR_NAME | ERR_NOMATCH);
    401     nwp = (struct whyle *) xcalloc(1, sizeof *nwp);
    402     nwp->w_fe = nwp->w_fe0 = v;
    403     gargv = 0;
    404     nwp->w_start = fseekp;
    405     nwp->w_fename = Strsave(cp);
    406     nwp->w_next = whyles;
    407     whyles = nwp;
    408     /*
    409      * Pre-read the loop so as to be more comprehensible to a terminal user.
    410      */
    411     zlast = T_FOREACH;
    412     if (intty)
    413 	preread();
    414     doagain();
    415 }
    416 
    417 void
    418 dowhile(v)
    419     Char  **v;
    420 {
    421     register int status;
    422     register bool again = whyles != 0 && whyles->w_start == lineloc &&
    423     whyles->w_fename == 0;
    424 
    425     v++;
    426     /*
    427      * Implement prereading here also, taking care not to evaluate the
    428      * expression before the loop has been read up from a terminal.
    429      */
    430     if (intty && !again)
    431 	status = !exp0(&v, 1);
    432     else
    433 	status = !exp(&v);
    434     if (*v)
    435 	stderror(ERR_NAME | ERR_EXPRESSION);
    436     if (!again) {
    437 	register struct whyle *nwp =
    438 	(struct whyle *) xcalloc(1, sizeof(*nwp));
    439 
    440 	nwp->w_start = lineloc;
    441 	nwp->w_end = 0;
    442 	nwp->w_next = whyles;
    443 	whyles = nwp;
    444 	zlast = T_WHILE;
    445 	if (intty) {
    446 	    /*
    447 	     * The tty preread
    448 	     */
    449 	    preread();
    450 	    doagain();
    451 	    return;
    452 	}
    453     }
    454     if (status)
    455 	/* We ain't gonna loop no more, no more! */
    456 	toend();
    457 }
    458 
    459 static void
    460 preread()
    461 {
    462     whyles->w_end = -1;
    463     if (setintr)
    464 	(void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT));
    465 
    466     search(T_BREAK, 0, NULL);		/* read the expression in */
    467     if (setintr)
    468 	(void) sigblock(sigmask(SIGINT));
    469     whyles->w_end = fseekp;
    470 }
    471 
    472 void
    473 doend()
    474 {
    475     if (!whyles)
    476 	stderror(ERR_NAME | ERR_NOTWHILE);
    477     whyles->w_end = fseekp;
    478     doagain();
    479 }
    480 
    481 void
    482 docontin()
    483 {
    484     if (!whyles)
    485 	stderror(ERR_NAME | ERR_NOTWHILE);
    486     doagain();
    487 }
    488 
    489 static void
    490 doagain()
    491 {
    492     /* Repeating a while is simple */
    493     if (whyles->w_fename == 0) {
    494 	bseek(whyles->w_start);
    495 	return;
    496     }
    497     /*
    498      * The foreach variable list actually has a spurious word ")" at the end of
    499      * the w_fe list.  Thus we are at the of the list if one word beyond this
    500      * is 0.
    501      */
    502     if (!whyles->w_fe[1]) {
    503 	dobreak();
    504 	return;
    505     }
    506     set(whyles->w_fename, Strsave(*whyles->w_fe++));
    507     bseek(whyles->w_start);
    508 }
    509 
    510 void
    511 dorepeat(v, kp)
    512     Char  **v;
    513     struct command *kp;
    514 {
    515     register int i;
    516     register sigset_t omask = 0;
    517 
    518     i = getn(v[1]);
    519     if (setintr)
    520 	omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
    521     lshift(v, 2);
    522     while (i > 0) {
    523 	if (setintr)
    524 	    (void) sigsetmask(omask);
    525 	reexecute(kp);
    526 	--i;
    527     }
    528     donefds();
    529     if (setintr)
    530 	(void) sigsetmask(omask);
    531 }
    532 
    533 void
    534 doswbrk()
    535 {
    536     search(T_BRKSW, 0, NULL);
    537 }
    538 
    539 int
    540 srchx(cp)
    541     register Char *cp;
    542 {
    543     register struct srch *sp, *sp1, *sp2;
    544     register i;
    545 
    546     /*
    547      * Binary search Sp1 is the beginning of the current search range. Sp2 is
    548      * one past the end.
    549      */
    550     for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) {
    551 	sp = sp1 + ((sp2 - sp1) >> 1);
    552 	if ((i = *cp - *sp->s_name) == 0 &&
    553 	    (i = Strcmp(cp, str2short(sp->s_name))) == 0)
    554 	    return sp->s_value;
    555 	if (i < 0)
    556 	    sp2 = sp;
    557 	else
    558 	    sp1 = sp + 1;
    559     }
    560     return (-1);
    561 }
    562 
    563 static Char Stype;
    564 static Char *Sgoal;
    565 
    566 /*VARARGS2*/
    567 void
    568 search(type, level, goal)
    569     int     type;
    570     register int level;
    571     Char   *goal;
    572 {
    573     Char    wordbuf[BUFSIZ];
    574     register Char *aword = wordbuf;
    575     register Char *cp;
    576 
    577     Stype = type;
    578     Sgoal = goal;
    579     if (type == T_GOTO)
    580 	bseek((off_t) 0);
    581     do {
    582 	if (intty && fseekp == feobp)
    583 	    xprintf("? "), flush();
    584 	aword[0] = 0;
    585 	(void) getword(aword);
    586 	switch (srchx(aword)) {
    587 
    588 	case T_ELSE:
    589 	    if (level == 0 && type == T_IF)
    590 		return;
    591 	    break;
    592 
    593 	case T_IF:
    594 	    while (getword(aword))
    595 		continue;
    596 	    if ((type == T_IF || type == T_ELSE) &&
    597 		eq(aword, STRthen))
    598 		level++;
    599 	    break;
    600 
    601 	case T_ENDIF:
    602 	    if (type == T_IF || type == T_ELSE)
    603 		level--;
    604 	    break;
    605 
    606 	case T_FOREACH:
    607 	case T_WHILE:
    608 	    if (type == T_BREAK)
    609 		level++;
    610 	    break;
    611 
    612 	case T_END:
    613 	    if (type == T_BREAK)
    614 		level--;
    615 	    break;
    616 
    617 	case T_SWITCH:
    618 	    if (type == T_SWITCH || type == T_BRKSW)
    619 		level++;
    620 	    break;
    621 
    622 	case T_ENDSW:
    623 	    if (type == T_SWITCH || type == T_BRKSW)
    624 		level--;
    625 	    break;
    626 
    627 	case T_LABEL:
    628 	    if (type == T_GOTO && getword(aword) && eq(aword, goal))
    629 		level = -1;
    630 	    break;
    631 
    632 	default:
    633 	    if (type != T_GOTO && (type != T_SWITCH || level != 0))
    634 		break;
    635 	    if (lastchr(aword) != ':')
    636 		break;
    637 	    aword[Strlen(aword) - 1] = 0;
    638 	    if (type == T_GOTO && eq(aword, goal) ||
    639 		type == T_SWITCH && eq(aword, STRdefault))
    640 		level = -1;
    641 	    break;
    642 
    643 	case T_CASE:
    644 	    if (type != T_SWITCH || level != 0)
    645 		break;
    646 	    (void) getword(aword);
    647 	    if (lastchr(aword) == ':')
    648 		aword[Strlen(aword) - 1] = 0;
    649 	    cp = strip(Dfix1(aword));
    650 	    if (Gmatch(goal, cp))
    651 		level = -1;
    652 	    xfree((ptr_t) cp);
    653 	    break;
    654 
    655 	case T_DEFAULT:
    656 	    if (type == T_SWITCH && level == 0)
    657 		level = -1;
    658 	    break;
    659 	}
    660 	(void) getword(NULL);
    661     } while (level >= 0);
    662 }
    663 
    664 static int
    665 getword(wp)
    666     register Char *wp;
    667 {
    668     register int found = 0;
    669     register int c, d;
    670     int     kwd = 0;
    671     Char   *owp = wp;
    672 
    673     c = readc(1);
    674     d = 0;
    675     do {
    676 	while (c == ' ' || c == '\t')
    677 	    c = readc(1);
    678 	if (c == '#')
    679 	    do
    680 		c = readc(1);
    681 	    while (c >= 0 && c != '\n');
    682 	if (c < 0)
    683 	    goto past;
    684 	if (c == '\n') {
    685 	    if (wp)
    686 		break;
    687 	    return (0);
    688 	}
    689 	unreadc(c);
    690 	found = 1;
    691 	do {
    692 	    c = readc(1);
    693 	    if (c == '\\' && (c = readc(1)) == '\n')
    694 		c = ' ';
    695 	    if (c == '\'' || c == '"')
    696 		if (d == 0)
    697 		    d = c;
    698 		else if (d == c)
    699 		    d = 0;
    700 	    if (c < 0)
    701 		goto past;
    702 	    if (wp) {
    703 		*wp++ = c;
    704 		*wp = 0;	/* end the string b4 test */
    705 	    }
    706 	} while ((d || !(kwd = keyword(owp)) && c != ' '
    707 		  && c != '\t') && c != '\n');
    708     } while (wp == 0);
    709 
    710     /*
    711      * if we have read a keyword ( "if", "switch" or "while" ) then we do not
    712      * need to unreadc the look-ahead char
    713      */
    714     if (!kwd) {
    715 	unreadc(c);
    716 	if (found)
    717 	    *--wp = 0;
    718     }
    719 
    720     return (found);
    721 
    722 past:
    723     switch (Stype) {
    724 
    725     case T_IF:
    726 	stderror(ERR_NAME | ERR_NOTFOUND, "then/endif");
    727 
    728     case T_ELSE:
    729 	stderror(ERR_NAME | ERR_NOTFOUND, "endif");
    730 
    731     case T_BRKSW:
    732     case T_SWITCH:
    733 	stderror(ERR_NAME | ERR_NOTFOUND, "endsw");
    734 
    735     case T_BREAK:
    736 	stderror(ERR_NAME | ERR_NOTFOUND, "end");
    737 
    738     case T_GOTO:
    739 	setname(short2str(Sgoal));
    740 	stderror(ERR_NAME | ERR_NOTFOUND, "label");
    741     }
    742     /* NOTREACHED */
    743     return (0);
    744 }
    745 
    746 /*
    747  * keyword(wp) determines if wp is one of the built-n functions if,
    748  * switch or while. It seems that when an if statement looks like
    749  * "if(" then getword above sucks in the '(' and so the search routine
    750  * never finds what it is scanning for. Rather than rewrite doword, I hack
    751  * in a test to see if the string forms a keyword. Then doword stops
    752  * and returns the word "if" -strike
    753  */
    754 
    755 static int
    756 keyword(wp)
    757     Char   *wp;
    758 {
    759     static Char STRif[] = {'i', 'f', '\0'};
    760     static Char STRwhile[] = {'w', 'h', 'i', 'l', 'e', '\0'};
    761     static Char STRswitch[] = {'s', 'w', 'i', 't', 'c', 'h', '\0'};
    762 
    763     if (!wp)
    764 	return (0);
    765 
    766     if ((Strcmp(wp, STRif) == 0) || (Strcmp(wp, STRwhile) == 0)
    767 	|| (Strcmp(wp, STRswitch) == 0))
    768 	return (1);
    769 
    770     return (0);
    771 }
    772 
    773 static void
    774 toend()
    775 {
    776     if (whyles->w_end == 0) {
    777 	search(T_BREAK, 0, NULL);
    778 	whyles->w_end = fseekp - 1;
    779     }
    780     else
    781 	bseek(whyles->w_end);
    782     wfree();
    783 }
    784 
    785 void
    786 wfree()
    787 {
    788     long    o = fseekp;
    789 
    790     while (whyles) {
    791 	register struct whyle *wp = whyles;
    792 	register struct whyle *nwp = wp->w_next;
    793 
    794 	if (o >= wp->w_start && (wp->w_end == 0 || o < wp->w_end))
    795 	    break;
    796 	if (wp->w_fe0)
    797 	    blkfree(wp->w_fe0);
    798 	if (wp->w_fename)
    799 	    xfree((ptr_t) wp->w_fename);
    800 	xfree((ptr_t) wp);
    801 	whyles = nwp;
    802     }
    803 }
    804 
    805 void
    806 doecho(v)
    807     Char  **v;
    808 {
    809     xecho(' ', v);
    810 }
    811 
    812 void
    813 doglob(v)
    814     Char  **v;
    815 {
    816     xecho(0, v);
    817     flush();
    818 }
    819 
    820 static void
    821 xecho(sep, v)
    822     int    sep;
    823     register Char **v;
    824 {
    825     register Char *cp;
    826     int     nonl = 0;
    827 
    828     if (setintr)
    829 	(void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT));
    830     v++;
    831     if (*v == 0)
    832 	return;
    833     gflag = 0, tglob(v);
    834     if (gflag) {
    835 	v = globall(v);
    836 	if (v == 0)
    837 	    stderror(ERR_NAME | ERR_NOMATCH);
    838     }
    839     else {
    840 	v = gargv = saveblk(v);
    841 	trim(v);
    842     }
    843     if (sep == ' ' && *v && eq(*v, STRmn))
    844 	nonl++, v++;
    845     while (cp = *v++) {
    846 	register int c;
    847 
    848 	while (c = *cp++)
    849 	    xputchar(c | QUOTE);
    850 
    851 	if (*v)
    852 	    xputchar(sep | QUOTE);
    853     }
    854     if (sep && nonl == 0)
    855 	xputchar('\n');
    856     else
    857 	flush();
    858     if (setintr)
    859 	(void) sigblock(sigmask(SIGINT));
    860     if (gargv)
    861 	blkfree(gargv), gargv = 0;
    862 }
    863 
    864 /* from "Karl Berry." <karl%mote.umb.edu (at) relay.cs.net> -- for NeXT things
    865    (and anything else with a modern compiler) */
    866 
    867 void
    868 dosetenv(v)
    869     register Char **v;
    870 {
    871     Char   *vp, *lp;
    872 
    873     v++;
    874     if ((vp = *v++) == 0) {
    875 	register Char **ep;
    876 
    877 	if (setintr)
    878 	    (void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT));
    879 	for (ep = STR_environ; *ep; ep++)
    880 	    xprintf("%s\n", short2str(*ep));
    881 	return;
    882     }
    883     if ((lp = *v++) == 0)
    884 	lp = STRNULL;
    885     Setenv(vp, lp = globone(lp, G_ERROR));
    886     if (eq(vp, STRPATH)) {
    887 	importpath(lp);
    888 	dohash();
    889     }
    890     else if (eq(vp, STRLANG) || eq(vp, STRLC_CTYPE)) {
    891 #ifdef NLS
    892 	int     k;
    893 
    894 	(void) setlocale(LC_ALL, "");
    895 	for (k = 0200; k <= 0377 && !Isprint(k); k++);
    896 	AsciiOnly = k > 0377;
    897 #else
    898 	AsciiOnly = 0;
    899 #endif				/* NLS */
    900     }
    901     xfree((ptr_t) lp);
    902 }
    903 
    904 void
    905 dounsetenv(v)
    906     register Char **v;
    907 {
    908     Char  **ep, *p, *n;
    909     int     i, maxi;
    910     static Char *name = NULL;
    911 
    912     if (name)
    913 	xfree((ptr_t) name);
    914     /*
    915      * Find the longest environment variable
    916      */
    917     for (maxi = 0, ep = STR_environ; *ep; ep++) {
    918 	for (i = 0, p = *ep; *p && *p != '='; p++, i++);
    919 	if (i > maxi)
    920 	    maxi = i;
    921     }
    922 
    923     name = (Char *) xmalloc((size_t) (maxi + 1) * sizeof(Char));
    924 
    925     while (++v && *v)
    926 	for (maxi = 1; maxi;)
    927 	    for (maxi = 0, ep = STR_environ; *ep; ep++) {
    928 		for (n = name, p = *ep; *p && *p != '='; *n++ = *p++);
    929 		*n = '\0';
    930 		if (!Gmatch(name, *v))
    931 		    continue;
    932 		maxi = 1;
    933 		if (eq(name, STRLANG) || eq(name, STRLC_CTYPE)) {
    934 #ifdef NLS
    935 		    int     k;
    936 
    937 		    (void) setlocale(LC_ALL, "");
    938 		    for (k = 0200; k <= 0377 && !Isprint(k); k++);
    939 		    AsciiOnly = k > 0377;
    940 #else
    941 		    AsciiOnly = getenv("LANG") == NULL &&
    942 			getenv("LC_CTYPE") == NULL;
    943 #endif				/* NLS */
    944 		}
    945 		/*
    946 		 * Delete name, and start again cause the environment changes
    947 		 */
    948 		Unsetenv(name);
    949 		break;
    950 	    }
    951     xfree((ptr_t) name), name = NULL;
    952 }
    953 
    954 void
    955 Setenv(name, val)
    956     Char   *name, *val;
    957 {
    958     register Char **ep = STR_environ;
    959     register Char *cp, *dp;
    960     Char   *blk[2];
    961     Char  **oep = ep;
    962 
    963 
    964     for (; *ep; ep++) {
    965 	for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
    966 	    continue;
    967 	if (*cp != 0 || *dp != '=')
    968 	    continue;
    969 	cp = Strspl(STRequal, val);
    970 	xfree((ptr_t) * ep);
    971 	*ep = strip(Strspl(name, cp));
    972 	xfree((ptr_t) cp);
    973 	blkfree((Char **) environ);
    974 	environ = short2blk(STR_environ);
    975 	return;
    976     }
    977     cp = Strspl(name, STRequal);
    978     blk[0] = strip(Strspl(cp, val));
    979     xfree((ptr_t) cp);
    980     blk[1] = 0;
    981     STR_environ = blkspl(STR_environ, blk);
    982     blkfree((Char **) environ);
    983     environ = short2blk(STR_environ);
    984     xfree((ptr_t) oep);
    985 }
    986 
    987 static void
    988 Unsetenv(name)
    989     Char   *name;
    990 {
    991     register Char **ep = STR_environ;
    992     register Char *cp, *dp;
    993     Char  **oep = ep;
    994 
    995     for (; *ep; ep++) {
    996 	for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
    997 	    continue;
    998 	if (*cp != 0 || *dp != '=')
    999 	    continue;
   1000 	cp = *ep;
   1001 	*ep = 0;
   1002 	STR_environ = blkspl(STR_environ, ep + 1);
   1003 	environ = short2blk(STR_environ);
   1004 	*ep = cp;
   1005 	xfree((ptr_t) cp);
   1006 	xfree((ptr_t) oep);
   1007 	return;
   1008     }
   1009 }
   1010 
   1011 void
   1012 doumask(v)
   1013     register Char **v;
   1014 {
   1015     register Char *cp = v[1];
   1016     register int i;
   1017 
   1018     if (cp == 0) {
   1019 	i = umask(0);
   1020 	(void) umask(i);
   1021 	xprintf("%o\n", i);
   1022 	return;
   1023     }
   1024     i = 0;
   1025     while (Isdigit(*cp) && *cp != '8' && *cp != '9')
   1026 	i = i * 8 + *cp++ - '0';
   1027     if (*cp || i < 0 || i > 0777)
   1028 	stderror(ERR_NAME | ERR_MASK);
   1029     (void) umask(i);
   1030 }
   1031 
   1032 typedef quad_t RLIM_TYPE;
   1033 
   1034 static struct limits {
   1035     int     limconst;
   1036     char   *limname;
   1037     int     limdiv;
   1038     char   *limscale;
   1039 }       limits[] = {
   1040     RLIMIT_CPU, 	"cputime",	1,	"seconds",
   1041     RLIMIT_FSIZE,	"filesize",	1024,	"kbytes",
   1042     RLIMIT_DATA,	"datasize",	1024,	"kbytes",
   1043     RLIMIT_STACK,	"stacksize",	1024,	"kbytes",
   1044     RLIMIT_CORE,	"coredumpsize", 1024,	"kbytes",
   1045     RLIMIT_RSS,		"memoryuse", 	1024,	"kbytes",
   1046     RLIMIT_MEMLOCK,	"memorylocked",	1024,	"kbytes",
   1047     RLIMIT_NPROC,	"maxproc",	1,	"",
   1048     RLIMIT_NOFILE,	"openfiles",	1,	"",
   1049     -1, 		NULL, 		0,	NULL
   1050 };
   1051 
   1052 static struct limits *findlim();
   1053 static RLIM_TYPE getval();
   1054 static void limtail();
   1055 static void plim();
   1056 static int setlim();
   1057 
   1058 static struct limits *
   1059 findlim(cp)
   1060     Char   *cp;
   1061 {
   1062     register struct limits *lp, *res;
   1063 
   1064     res = (struct limits *) NULL;
   1065     for (lp = limits; lp->limconst >= 0; lp++)
   1066 	if (prefix(cp, str2short(lp->limname))) {
   1067 	    if (res)
   1068 		stderror(ERR_NAME | ERR_AMBIG);
   1069 	    res = lp;
   1070 	}
   1071     if (res)
   1072 	return (res);
   1073     stderror(ERR_NAME | ERR_LIMIT);
   1074     /* NOTREACHED */
   1075     return (0);
   1076 }
   1077 
   1078 void
   1079 dolimit(v)
   1080     register Char **v;
   1081 {
   1082     register struct limits *lp;
   1083     register RLIM_TYPE limit;
   1084     char    hard = 0;
   1085 
   1086     v++;
   1087     if (*v && eq(*v, STRmh)) {
   1088 	hard = 1;
   1089 	v++;
   1090     }
   1091     if (*v == 0) {
   1092 	for (lp = limits; lp->limconst >= 0; lp++)
   1093 	    plim(lp, hard);
   1094 	return;
   1095     }
   1096     lp = findlim(v[0]);
   1097     if (v[1] == 0) {
   1098 	plim(lp, hard);
   1099 	return;
   1100     }
   1101     limit = getval(lp, v + 1);
   1102     if (setlim(lp, hard, limit) < 0)
   1103 	stderror(ERR_SILENT);
   1104 }
   1105 
   1106 static  RLIM_TYPE
   1107 getval(lp, v)
   1108     register struct limits *lp;
   1109     Char  **v;
   1110 {
   1111     register float f;
   1112     double  atof();
   1113     Char   *cp = *v++;
   1114 
   1115     f = atof(short2str(cp));
   1116 
   1117     while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
   1118 	cp++;
   1119     if (*cp == 0) {
   1120 	if (*v == 0)
   1121 	    return ((RLIM_TYPE) ((f + 0.5) * lp->limdiv));
   1122 	cp = *v;
   1123     }
   1124     switch (*cp) {
   1125     case ':':
   1126 	if (lp->limconst != RLIMIT_CPU)
   1127 	    goto badscal;
   1128 	return ((RLIM_TYPE) (f * 60.0 + atof(short2str(cp + 1))));
   1129     case 'h':
   1130 	if (lp->limconst != RLIMIT_CPU)
   1131 	    goto badscal;
   1132 	limtail(cp, "hours");
   1133 	f *= 3600.0;
   1134 	break;
   1135     case 'm':
   1136 	if (lp->limconst == RLIMIT_CPU) {
   1137 	    limtail(cp, "minutes");
   1138 	    f *= 60.0;
   1139 	    break;
   1140 	}
   1141 	*cp = 'm';
   1142 	limtail(cp, "megabytes");
   1143 	f *= 1024.0 * 1024.0;
   1144 	break;
   1145     case 's':
   1146 	if (lp->limconst != RLIMIT_CPU)
   1147 	    goto badscal;
   1148 	limtail(cp, "seconds");
   1149 	break;
   1150     case 'M':
   1151 	if (lp->limconst == RLIMIT_CPU)
   1152 	    goto badscal;
   1153 	*cp = 'm';
   1154 	limtail(cp, "megabytes");
   1155 	f *= 1024.0 * 1024.0;
   1156 	break;
   1157     case 'k':
   1158 	if (lp->limconst == RLIMIT_CPU)
   1159 	    goto badscal;
   1160 	limtail(cp, "kbytes");
   1161 	f *= 1024.0;
   1162 	break;
   1163     case 'u':
   1164 	limtail(cp, "unlimited");
   1165 	return (RLIM_INFINITY);
   1166     default:
   1167 badscal:
   1168 	stderror(ERR_NAME | ERR_SCALEF);
   1169     }
   1170     return ((RLIM_TYPE) (f + 0.5));
   1171 }
   1172 
   1173 static void
   1174 limtail(cp, str)
   1175     Char   *cp;
   1176     char   *str;
   1177 {
   1178     while (*cp && *cp == *str)
   1179 	cp++, str++;
   1180     if (*cp)
   1181 	stderror(ERR_BADSCALE, str);
   1182 }
   1183 
   1184 
   1185 /*ARGSUSED*/
   1186 static void
   1187 plim(lp, hard)
   1188     register struct limits *lp;
   1189     Char    hard;
   1190 {
   1191     struct rlimit rlim;
   1192     RLIM_TYPE limit;
   1193 
   1194     xprintf("%s \t", lp->limname);
   1195 
   1196     (void) getrlimit(lp->limconst, &rlim);
   1197     limit = hard ? rlim.rlim_max : rlim.rlim_cur;
   1198 
   1199     if (limit == RLIM_INFINITY)
   1200 	xprintf("unlimited");
   1201     else if (lp->limconst == RLIMIT_CPU)
   1202 	psecs((long) limit);
   1203     else
   1204 	xprintf("%ld %s", (long) (limit / lp->limdiv), lp->limscale);
   1205     xprintf("\n");
   1206 }
   1207 
   1208 void
   1209 dounlimit(v)
   1210     register Char **v;
   1211 {
   1212     register struct limits *lp;
   1213     int     lerr = 0;
   1214     Char    hard = 0;
   1215 
   1216     v++;
   1217     if (*v && eq(*v, STRmh)) {
   1218 	hard = 1;
   1219 	v++;
   1220     }
   1221     if (*v == 0) {
   1222 	for (lp = limits; lp->limconst >= 0; lp++)
   1223 	    if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
   1224 		lerr++;
   1225 	if (lerr)
   1226 	    stderror(ERR_SILENT);
   1227 	return;
   1228     }
   1229     while (*v) {
   1230 	lp = findlim(*v++);
   1231 	if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
   1232 	    stderror(ERR_SILENT);
   1233     }
   1234 }
   1235 
   1236 static int
   1237 setlim(lp, hard, limit)
   1238     register struct limits *lp;
   1239     Char    hard;
   1240     RLIM_TYPE limit;
   1241 {
   1242     struct rlimit rlim;
   1243 
   1244     (void) getrlimit(lp->limconst, &rlim);
   1245 
   1246     if (hard)
   1247 	rlim.rlim_max = limit;
   1248     else if (limit == RLIM_INFINITY && geteuid() != 0)
   1249 	rlim.rlim_cur = rlim.rlim_max;
   1250     else
   1251 	rlim.rlim_cur = limit;
   1252 
   1253     if (setrlimit(lp->limconst, &rlim) < 0) {
   1254 	xprintf("%s: %s: Can't %s%s limit\n", bname, lp->limname,
   1255 		limit == RLIM_INFINITY ? "remove" : "set",
   1256 		hard ? " hard" : "");
   1257 	return (-1);
   1258     }
   1259     return (0);
   1260 }
   1261 
   1262 void
   1263 dosuspend()
   1264 {
   1265     int     ctpgrp;
   1266 
   1267     void    (*old) ();
   1268 
   1269     if (loginsh)
   1270 	stderror(ERR_SUSPLOG);
   1271     untty();
   1272 
   1273     old = signal(SIGTSTP, SIG_DFL);
   1274     (void) kill(0, SIGTSTP);
   1275     /* the shell stops here */
   1276     (void) signal(SIGTSTP, old);
   1277 
   1278     if (tpgrp != -1) {
   1279 retry:
   1280 	ctpgrp = tcgetpgrp(FSHTTY);
   1281 	if (ctpgrp != opgrp) {
   1282 	    old = signal(SIGTTIN, SIG_DFL);
   1283 	    (void) kill(0, SIGTTIN);
   1284 	    (void) signal(SIGTTIN, old);
   1285 	    goto retry;
   1286 	}
   1287 	(void) setpgid(0, shpgrp);
   1288 	(void) tcsetpgrp(FSHTTY, shpgrp);
   1289     }
   1290 }
   1291 
   1292 /* This is the dreaded EVAL built-in.
   1293  *   If you don't fiddle with file descriptors, and reset didfds,
   1294  *   this command will either ignore redirection inside or outside
   1295  *   its aguments, e.g. eval "date >x"  vs.  eval "date" >x
   1296  *   The stuff here seems to work, but I did it by trial and error rather
   1297  *   than really knowing what was going on.  If tpgrp is zero, we are
   1298  *   probably a background eval, e.g. "eval date &", and we want to
   1299  *   make sure that any processes we start stay in our pgrp.
   1300  *   This is also the case for "time eval date" -- stay in same pgrp.
   1301  *   Otherwise, under stty tostop, processes will stop in the wrong
   1302  *   pgrp, with no way for the shell to get them going again.  -IAN!
   1303  */
   1304 void
   1305 doeval(v)
   1306     Char  **v;
   1307 {
   1308     Char  **oevalvec;
   1309     Char   *oevalp;
   1310     int     odidfds;
   1311     jmp_buf osetexit;
   1312     int     my_reenter;
   1313     Char  **gv;
   1314     int     saveIN;
   1315     int     saveOUT;
   1316     int     saveDIAG;
   1317     int     oSHIN;
   1318     int     oSHOUT;
   1319     int     oSHDIAG;
   1320 
   1321     oevalvec = evalvec;
   1322     oevalp = evalp;
   1323     odidfds = didfds;
   1324     oSHIN = SHIN;
   1325     oSHOUT = SHOUT;
   1326     oSHDIAG = SHDIAG;
   1327 
   1328     v++;
   1329     if (*v == 0)
   1330 	return;
   1331     gflag = 0, tglob(v);
   1332     if (gflag) {
   1333 	gv = v = globall(v);
   1334 	gargv = 0;
   1335 	if (v == 0)
   1336 	    stderror(ERR_NOMATCH);
   1337 	v = copyblk(v);
   1338     }
   1339     else {
   1340 	gv = NULL;
   1341 	v = copyblk(v);
   1342 	trim(v);
   1343     }
   1344 
   1345     saveIN = dcopy(SHIN, -1);
   1346     saveOUT = dcopy(SHOUT, -1);
   1347     saveDIAG = dcopy(SHDIAG, -1);
   1348 
   1349     getexit(osetexit);
   1350 
   1351     if ((my_reenter = setexit()) == 0) {
   1352 	evalvec = v;
   1353 	evalp = 0;
   1354 	SHIN = dcopy(0, -1);
   1355 	SHOUT = dcopy(1, -1);
   1356 	SHDIAG = dcopy(2, -1);
   1357 	didfds = 0;
   1358 	process(0);
   1359     }
   1360 
   1361     evalvec = oevalvec;
   1362     evalp = oevalp;
   1363     doneinp = 0;
   1364     didfds = odidfds;
   1365     (void) close(SHIN);
   1366     (void) close(SHOUT);
   1367     (void) close(SHDIAG);
   1368     SHIN = dmove(saveIN, oSHIN);
   1369     SHOUT = dmove(saveOUT, oSHOUT);
   1370     SHDIAG = dmove(saveDIAG, oSHDIAG);
   1371 
   1372     if (gv)
   1373 	blkfree(gv);
   1374     resexit(osetexit);
   1375     if (my_reenter)
   1376 	stderror(ERR_SILENT);
   1377 }
   1378