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