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

Defined functions

Unsetenv defined in line 1179; used 1 times
doagain defined in line 545; used 4 times
doalias defined in line 212; used 1 times
dobreak defined in line 396; used 3 times
docontin defined in line 537; used 1 times
doecho defined in line 892; used 2 times
doelse defined in line 345; used 1 times
doend defined in line 528; used 1 times
doeval defined in line 1641; used 2 times
doexit defined in line 405; used 1 times
doforeach defined in line 425; used 1 times
doglob defined in line 899; used 1 times
dogoto defined in line 351; used 1 times
doif defined in line 291; used 1 times
dolimit defined in line 1343; used 1 times
dologin defined in line 253; used 1 times
dologout defined in line 246; used 1 times
donewgrp defined in line 267; used 1 times
donohup defined in line 187; used 1 times
doonintr defined in line 141; used 1 times
dorepeat defined in line 566; used 1 times
dosetenv defined in line 1015; used 1 times
dosuspend defined in line 1586; used 1 times
doswbrk defined in line 605; used 1 times
doswitch defined in line 378; used 1 times
doumask defined in line 1203; used 1 times
dounlimit defined in line 1526; used 1 times
dounsetenv defined in line 1074; used 1 times
dowhile defined in line 466; used 1 times
dozip defined in line 200; used 6 times
findlim defined in line 1323; used 3 times
func defined in line 124; used 11 times
getval defined in line 1371; used 2 times
getword defined in line 751; used 5 times
isbfunc defined in line 71; used 1 times
islogin defined in line 281; used 2 times
isrchx defined in line 635; used 1 times
keyword defined in line 842; used 1 times
limtail defined in line 1473; used 8 times
plim defined in line 1486; used 3 times
preread defined in line 508; used 2 times
prvars defined in line 206; used 2 times
rcsid defined in line 40; never used
reexecute defined in line 331; used 2 times
restrict_limit defined in line 1306; used 4 times
search defined in line 652; used 16 times
setlim defined in line 1554; used 4 times
srchx defined in line 611; used 3 times
toend defined in line 860; used 2 times
unalias defined in line 238; used 1 times
wfree defined in line 872; used 5 times
xecho defined in line 907; used 2 times

Defined variables

Sgoal defined in line 649; used 2 times
Stype defined in line 648; used 2 times
gv defined in line 1640; used 6 times
limits defined in line 1250; used 3 times
zlast defined in line 59; used 4 times

Defined struct's

limits defined in line 1245; used 18 times

Defined typedef's

RLIM_TYPE defined in line 1225; used 17 times

Defined macros

RLIMIT_FSIZE defined in line 1231; used 4 times
RLIMIT_STACK defined in line 1235; used 2 times
RLIM_INFINITY defined in line 1230; used 8 times
toset defined in line 1237; used 1 times
Last modified: 1991-08-21
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 60
Valid CSS Valid XHTML 1.0 Strict