1: /*
   2:  * Copyright (c) 1980 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley Software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #if !defined(lint) && defined(DOSCCS)
   8: static char *sccsid = "@(#)sh.lex.c	5.4 (Berkeley) 3/29/86";
   9: #endif
  10: 
  11: #include "sh.h"
  12: #include <sgtty.h>
  13: 
  14: /*
  15:  * C shell
  16:  */
  17: 
  18: /*
  19:  * These lexical routines read input and form lists of words.
  20:  * There is some involved processing here, because of the complications
  21:  * of input buffering, and especially because of history substitution.
  22:  */
  23: 
  24: char    *word();
  25: 
  26: /*
  27:  * Peekc is a peek characer for getC, peekread for readc.
  28:  * There is a subtlety here in many places... history routines
  29:  * will read ahead and then insert stuff into the input stream.
  30:  * If they push back a character then they must push it behind
  31:  * the text substituted by the history substitution.  On the other
  32:  * hand in several places we need 2 peek characters.  To make this
  33:  * all work, the history routines read with getC, and make use both
  34:  * of ungetC and unreadc.  The key observation is that the state
  35:  * of getC at the call of a history reference is such that calls
  36:  * to getC from the history routines will always yield calls of
  37:  * readc, unless this peeking is involved.  That is to say that during
  38:  * getexcl the variables lap, exclp, and exclnxt are all zero.
  39:  *
  40:  * Getdol invokes history substitution, hence the extra peek, peekd,
  41:  * which it can ungetD to be before history substitutions.
  42:  */
  43: char    peekc, peekd;
  44: char    peekread;
  45: 
  46: char    *exclp;         /* (Tail of) current word from ! subst */
  47: struct  wordent *exclnxt;   /* The rest of the ! subst words */
  48: int exclc;          /* Count of remainig words in ! subst */
  49: char    *alvecp;        /* "Globp" for alias resubstitution */
  50: 
  51: /*
  52:  * Lex returns to its caller not only a wordlist (as a "var" parameter)
  53:  * but also whether a history substitution occurred.  This is used in
  54:  * the main (process) routine to determine whether to echo, and also
  55:  * when called by the alias routine to determine whether to keep the
  56:  * argument list.
  57:  */
  58: bool    hadhist;
  59: 
  60: char getCtmp;
  61: #define getC(f)     ((getCtmp = peekc) ? (peekc = 0, getCtmp) : getC1(f))
  62: #define ungetC(c)   peekc = c
  63: #define ungetD(c)   peekd = c
  64: 
  65: lex(hp)
  66:     register struct wordent *hp;
  67: {
  68:     register struct wordent *wdp;
  69:     int c;
  70: 
  71:     lineloc = btell();
  72:     hp->next = hp->prev = hp;
  73:     hp->word = "";
  74:     alvecp = 0, hadhist = 0;
  75:     do
  76:         c = readc(0);
  77:     while (c == ' ' || c == '\t');
  78:     if (c == HISTSUB && intty)
  79:         /* ^lef^rit	from tty is short !:s^lef^rit */
  80:         getexcl(c);
  81:     else
  82:         unreadc(c);
  83:     wdp = hp;
  84:     /*
  85: 	 * The following loop is written so that the links needed
  86: 	 * by freelex will be ready and rarin to go even if it is
  87: 	 * interrupted.
  88: 	 */
  89:     do {
  90:         register struct wordent *new = (struct wordent *) xalloc(sizeof *wdp);
  91: 
  92:         new->word = 0;
  93:         new->prev = wdp;
  94:         new->next = hp;
  95:         wdp->next = new;
  96:         wdp = new;
  97:         wdp->word = word();
  98:     } while (wdp->word[0] != '\n');
  99:     hp->prev = wdp;
 100:     return (hadhist);
 101: }
 102: 
 103: prlex(sp0)
 104:     struct wordent *sp0;
 105: {
 106:     register struct wordent *sp = sp0->next;
 107: 
 108:     for (;;) {
 109:         printf("%s", sp->word);
 110:         sp = sp->next;
 111:         if (sp == sp0)
 112:             break;
 113:         if (sp->word[0] != '\n')
 114:             putchar(' ');
 115:     }
 116: }
 117: 
 118: copylex(hp, fp)
 119:     register struct wordent *hp;
 120:     register struct wordent *fp;
 121: {
 122:     register struct wordent *wdp;
 123: 
 124:     wdp = hp;
 125:     fp = fp->next;
 126:     do {
 127:         register struct wordent *new = (struct wordent *) xalloc(sizeof *wdp);
 128: 
 129:         new->prev = wdp;
 130:         new->next = hp;
 131:         wdp->next = new;
 132:         wdp = new;
 133:         wdp->word = savestr(fp->word);
 134:         fp = fp->next;
 135:     } while (wdp->word[0] != '\n');
 136:     hp->prev = wdp;
 137: }
 138: 
 139: freelex(vp)
 140:     register struct wordent *vp;
 141: {
 142:     register struct wordent *fp;
 143: 
 144:     while (vp->next != vp) {
 145:         fp = vp->next;
 146:         vp->next = fp->next;
 147:         XFREE(fp->word)
 148:         XFREE((char *)fp)
 149:     }
 150:     vp->prev = vp;
 151: }
 152: 
 153: char *
 154: word()
 155: {
 156:     register char c, c1;
 157:     register char *wp;
 158:     char wbuf[BUFSIZ];
 159:     register bool dolflg;
 160:     register int i;
 161: 
 162:     wp = wbuf;
 163:     i = BUFSIZ - 4;
 164: loop:
 165:     while ((c = getC(DOALL)) == ' ' || c == '\t')
 166:         ;
 167:     if (cmap(c, _META|_ESC))
 168:         switch (c) {
 169:         case '&':
 170:         case '|':
 171:         case '<':
 172:         case '>':
 173:             *wp++ = c;
 174:             c1 = getC(DOALL);
 175:             if (c1 == c)
 176:                 *wp++ = c1;
 177:             else
 178:                 ungetC(c1);
 179:             goto ret;
 180: 
 181:         case '#':
 182:             if (intty)
 183:                 break;
 184:             c = 0;
 185:             do {
 186:                 c1 = c;
 187:                 c = getC(0);
 188:             } while (c != '\n');
 189:             if (c1 == '\\')
 190:                 goto loop;
 191:             /* fall into ... */
 192: 
 193:         case ';':
 194:         case '(':
 195:         case ')':
 196:         case '\n':
 197:             *wp++ = c;
 198:             goto ret;
 199: 
 200:         case '\\':
 201:             c = getC(0);
 202:             if (c == '\n') {
 203:                 if (onelflg == 1)
 204:                     onelflg = 2;
 205:                 goto loop;
 206:             }
 207:             if (c != HIST)
 208:                 *wp++ = '\\', --i;
 209:             c |= QUOTE;
 210:         }
 211:     c1 = 0;
 212:     dolflg = DOALL;
 213:     for (;;) {
 214:         if (c1) {
 215:             if (c == c1) {
 216:                 c1 = 0;
 217:                 dolflg = DOALL;
 218:             } else if (c == '\\') {
 219:                 c = getC(0);
 220:                 if (c == HIST)
 221:                     c |= QUOTE;
 222:                 else {
 223:                     if (c == '\n')
 224:                         /*
 225: 						if (c1 == '`')
 226: 							c = ' ';
 227: 						else
 228: 						*/
 229:                             c |= QUOTE;
 230:                     ungetC(c);
 231:                     c = '\\';
 232:                 }
 233:             } else if (c == '\n') {
 234:                 seterrc("Unmatched ", c1);
 235:                 ungetC(c);
 236:                 break;
 237:             }
 238:         } else if (cmap(c, _META|_Q|_Q1|_ESC)) {
 239:             if (c == '\\') {
 240:                 c = getC(0);
 241:                 if (c == '\n') {
 242:                     if (onelflg == 1)
 243:                         onelflg = 2;
 244:                     break;
 245:                 }
 246:                 if (c != HIST)
 247:                     *wp++ = '\\', --i;
 248:                 c |= QUOTE;
 249:             } else if (cmap(c, _Q|_Q1)) {       /* '"` */
 250:                 c1 = c;
 251:                 dolflg = c == '"' ? DOALL : DOEXCL;
 252:             } else if (c != '#' || !intty) {
 253:                 ungetC(c);
 254:                 break;
 255:             }
 256:         }
 257:         if (--i > 0) {
 258:             *wp++ = c;
 259:             c = getC(dolflg);
 260:         } else {
 261:             seterr("Word too long");
 262:             wp = &wbuf[1];
 263:             break;
 264:         }
 265:     }
 266: ret:
 267:     *wp = 0;
 268:     return (savestr(wbuf));
 269: }
 270: 
 271: getC1(flag)
 272:     register int flag;
 273: {
 274:     register char c;
 275: 
 276: top:
 277:     if (c = peekc) {
 278:         peekc = 0;
 279:         return (c);
 280:     }
 281:     if (lap) {
 282:         if ((c = *lap++) == 0)
 283:             lap = 0;
 284:         else {
 285:             if (cmap(c, _META|_Q|_Q1))
 286:                 c |= QUOTE;
 287:             return (c);
 288:         }
 289:     }
 290:     if (c = peekd) {
 291:         peekd = 0;
 292:         return (c);
 293:     }
 294:     if (exclp) {
 295:         if (c = *exclp++)
 296:             return (c);
 297:         if (exclnxt && --exclc >= 0) {
 298:             exclnxt = exclnxt->next;
 299:             setexclp(exclnxt->word);
 300:             return (' ');
 301:         }
 302:         exclp = 0;
 303:         exclnxt = 0;
 304:     }
 305:     if (exclnxt) {
 306:         exclnxt = exclnxt->next;
 307:         if (--exclc < 0)
 308:             exclnxt = 0;
 309:         else
 310:             setexclp(exclnxt->word);
 311:         goto top;
 312:     }
 313:     c = readc(0);
 314:     if (c == '$' && (flag & DODOL)) {
 315:         getdol();
 316:         goto top;
 317:     }
 318:     if (c == HIST && (flag & DOEXCL)) {
 319:         getexcl(0);
 320:         goto top;
 321:     }
 322:     return (c);
 323: }
 324: 
 325: getdol()
 326: {
 327:     register char *np;
 328:     char name[40];
 329:     register int c;
 330:     int sc;
 331:     bool special = 0;
 332: 
 333:     np = name, *np++ = '$';
 334:     c = sc = getC(DOEXCL);
 335:     if (any(c, "\t \n")) {
 336:         ungetD(c);
 337:         ungetC('$' | QUOTE);
 338:         return;
 339:     }
 340:     if (c == '{')
 341:         *np++ = c, c = getC(DOEXCL);
 342:     if (c == '#' || c == '?')
 343:         special++, *np++ = c, c = getC(DOEXCL);
 344:     *np++ = c;
 345:     switch (c) {
 346: 
 347:     case '<':
 348:     case '$':
 349:         if (special)
 350:             goto vsyn;
 351:         goto ret;
 352: 
 353:     case '\n':
 354:         ungetD(c);
 355:         np--;
 356:         goto vsyn;
 357: 
 358:     case '*':
 359:         if (special)
 360:             goto vsyn;
 361:         goto ret;
 362: 
 363:     default:
 364:         if (digit(c)) {
 365: /*
 366:  * let $?0 pass for now
 367: 			if (special)
 368: 				goto vsyn;
 369: */
 370:             while (digit(c = getC(DOEXCL))) {
 371:                 if (np < &name[sizeof name / 2])
 372:                     *np++ = c;
 373:             }
 374:         } else if (letter(c))
 375:             while (letter(c = getC(DOEXCL))) {
 376:                 if (np < &name[sizeof name / 2])
 377:                     *np++ = c;
 378:             }
 379:         else
 380:             goto vsyn;
 381:     }
 382:     if (c == '[') {
 383:         *np++ = c;
 384:         do {
 385:             c = getC(DOEXCL);
 386:             if (c == '\n') {
 387:                 ungetD(c);
 388:                 np--;
 389:                 goto vsyn;
 390:             }
 391:             if (np >= &name[sizeof name - 8])
 392:                 goto vsyn;
 393:             *np++ = c;
 394:         } while (c != ']');
 395:         c = getC(DOEXCL);
 396:     }
 397:     if (c == ':') {
 398:         *np++ = c, c = getC(DOEXCL);
 399:         if (c == 'g')
 400:             *np++ = c, c = getC(DOEXCL);
 401:         *np++ = c;
 402:         if (!any(c, "htrqxe"))
 403:             goto vsyn;
 404:     } else
 405:         ungetD(c);
 406:     if (sc == '{') {
 407:         c = getC(DOEXCL);
 408:         if (c != '}') {
 409:             ungetC(c);
 410:             goto vsyn;
 411:         }
 412:         *np++ = c;
 413:     }
 414: ret:
 415:     *np = 0;
 416:     addla(name);
 417:     return;
 418: 
 419: vsyn:
 420:     seterr("Variable syntax");
 421:     goto ret;
 422: }
 423: 
 424: addla(cp)
 425:     char *cp;
 426: {
 427:     char buf[BUFSIZ];
 428: 
 429:     if (lap != 0 && strlen(cp) + strlen(lap) >= sizeof (labuf) - 4) {
 430:         seterr("Expansion buf ovflo");
 431:         return;
 432:     }
 433:     if (lap)
 434:         (void) strcpy(buf, lap);
 435:     (void) strcpy(labuf, cp);
 436:     if (lap)
 437:         (void) strcat(labuf, buf);
 438:     lap = labuf;
 439: }
 440: 
 441: char    lhsb[32];
 442: char    slhs[32];
 443: char    rhsb[64];
 444: int quesarg;
 445: 
 446: getexcl(sc)
 447:     char sc;
 448: {
 449:     register struct wordent *hp, *ip;
 450:     int left, right, dol;
 451:     register int c;
 452: 
 453:     if (sc == 0) {
 454:         sc = getC(0);
 455:         if (sc != '{') {
 456:             ungetC(sc);
 457:             sc = 0;
 458:         }
 459:     }
 460:     quesarg = -1;
 461:     lastev = eventno;
 462:     hp = gethent(sc);
 463:     if (hp == 0)
 464:         return;
 465:     hadhist = 1;
 466:     dol = 0;
 467:     if (hp == alhistp)
 468:         for (ip = hp->next->next; ip != alhistt; ip = ip->next)
 469:             dol++;
 470:     else
 471:         for (ip = hp->next->next; ip != hp->prev; ip = ip->next)
 472:             dol++;
 473:     left = 0, right = dol;
 474:     if (sc == HISTSUB) {
 475:         ungetC('s'), unreadc(HISTSUB), c = ':';
 476:         goto subst;
 477:     }
 478:     c = getC(0);
 479:     if (!any(c, ":^$*-%"))
 480:         goto subst;
 481:     left = right = -1;
 482:     if (c == ':') {
 483:         c = getC(0);
 484:         unreadc(c);
 485:         if (letter(c) || c == '&') {
 486:             c = ':';
 487:             left = 0, right = dol;
 488:             goto subst;
 489:         }
 490:     } else
 491:         ungetC(c);
 492:     if (!getsel(&left, &right, dol))
 493:         return;
 494:     c = getC(0);
 495:     if (c == '*')
 496:         ungetC(c), c = '-';
 497:     if (c == '-') {
 498:         if (!getsel(&left, &right, dol))
 499:             return;
 500:         c = getC(0);
 501:     }
 502: subst:
 503:     exclc = right - left + 1;
 504:     while (--left >= 0)
 505:         hp = hp->next;
 506:     if (sc == HISTSUB || c == ':') {
 507:         do {
 508:             hp = getsub(hp);
 509:             c = getC(0);
 510:         } while (c == ':');
 511:     }
 512:     unreadc(c);
 513:     if (sc == '{') {
 514:         c = getC(0);
 515:         if (c != '}')
 516:             seterr("Bad ! form");
 517:     }
 518:     exclnxt = hp;
 519: }
 520: 
 521: struct wordent *
 522: getsub(en)
 523:     struct wordent *en;
 524: {
 525:     register char *cp;
 526:     int delim;
 527:     register int c;
 528:     int sc;
 529:     bool global = 0;
 530:     char orhsb[sizeof rhsb];
 531: 
 532:     exclnxt = 0;
 533:     sc = c = getC(0);
 534:     if (c == 'g')
 535:         global++, c = getC(0);
 536:     switch (c) {
 537: 
 538:     case 'p':
 539:         justpr++;
 540:         goto ret;
 541: 
 542:     case 'x':
 543:     case 'q':
 544:         global++;
 545:         /* fall into ... */
 546: 
 547:     case 'h':
 548:     case 'r':
 549:     case 't':
 550:     case 'e':
 551:         break;
 552: 
 553:     case '&':
 554:         if (slhs[0] == 0) {
 555:             seterr("No prev sub");
 556:             goto ret;
 557:         }
 558:         (void) strcpy(lhsb, slhs);
 559:         break;
 560: 
 561: /*
 562: 	case '~':
 563: 		if (lhsb[0] == 0)
 564: 			goto badlhs;
 565: 		break;
 566: */
 567: 
 568:     case 's':
 569:         delim = getC(0);
 570:         if (letter(delim) || digit(delim) || any(delim, " \t\n")) {
 571:             unreadc(delim);
 572: bads:
 573:             lhsb[0] = 0;
 574:             seterr("Bad substitute");
 575:             goto ret;
 576:         }
 577:         cp = lhsb;
 578:         for (;;) {
 579:             c = getC(0);
 580:             if (c == '\n') {
 581:                 unreadc(c);
 582:                 break;
 583:             }
 584:             if (c == delim)
 585:                 break;
 586:             if (cp > &lhsb[sizeof lhsb - 2])
 587:                 goto bads;
 588:             if (c == '\\') {
 589:                 c = getC(0);
 590:                 if (c != delim && c != '\\')
 591:                     *cp++ = '\\';
 592:             }
 593:             *cp++ = c;
 594:         }
 595:         if (cp != lhsb)
 596:             *cp++ = 0;
 597:         else if (lhsb[0] == 0) {
 598: /*badlhs:*/
 599:             seterr("No prev lhs");
 600:             goto ret;
 601:         }
 602:         cp = rhsb;
 603:         (void) strcpy(orhsb, cp);
 604:         for (;;) {
 605:             c = getC(0);
 606:             if (c == '\n') {
 607:                 unreadc(c);
 608:                 break;
 609:             }
 610:             if (c == delim)
 611:                 break;
 612: /*
 613: 			if (c == '~') {
 614: 				if (&cp[strlen(orhsb)] > &rhsb[sizeof rhsb - 2])
 615: 					goto toorhs;
 616: 				(void) strcpy(cp, orhsb);
 617: 				cp = strend(cp);
 618: 				continue;
 619: 			}
 620: */
 621:             if (cp > &rhsb[sizeof rhsb - 2]) {
 622: /*toorhs:*/
 623:                 seterr("Rhs too long");
 624:                 goto ret;
 625:             }
 626:             if (c == '\\') {
 627:                 c = getC(0);
 628:                 if (c != delim /* && c != '~' */)
 629:                     *cp++ = '\\';
 630:             }
 631:             *cp++ = c;
 632:         }
 633:         *cp++ = 0;
 634:         break;
 635: 
 636:     default:
 637:         if (c == '\n')
 638:             unreadc(c);
 639:         seterrc("Bad ! modifier: ", c);
 640:         goto ret;
 641:     }
 642:     (void) strcpy(slhs, lhsb);
 643:     if (exclc)
 644:         en = dosub(sc, en, global);
 645: ret:
 646:     return (en);
 647: }
 648: 
 649: struct wordent *
 650: dosub(sc, en, global)
 651:     int sc;
 652:     struct wordent *en;
 653:     bool global;
 654: {
 655:     struct wordent lex;
 656:     bool didsub = 0;
 657:     struct wordent *hp = &lex;
 658:     register struct wordent *wdp;
 659:     register int i = exclc;
 660: 
 661:     wdp = hp;
 662:     while (--i >= 0) {
 663:         register struct wordent *new = (struct wordent *) calloc(1, sizeof *wdp);
 664: 
 665:         new->prev = wdp;
 666:         new->next = hp;
 667:         wdp->next = new;
 668:         wdp = new;
 669:         en = en->next;
 670:         wdp->word = global || didsub == 0 ?
 671:             subword(en->word, sc, &didsub) : savestr(en->word);
 672:     }
 673:     if (didsub == 0)
 674:         seterr("Modifier failed");
 675:     hp->prev = wdp;
 676:     return (&enthist(-1000, &lex, 0)->Hlex);
 677: }
 678: 
 679: char *
 680: subword(cp, type, adid)
 681:     char *cp;
 682:     int type;
 683:     bool *adid;
 684: {
 685:     char wbuf[BUFSIZ];
 686:     register char *wp, *mp, *np;
 687:     register int i;
 688: 
 689:     switch (type) {
 690: 
 691:     case 'r':
 692:     case 'e':
 693:     case 'h':
 694:     case 't':
 695:     case 'q':
 696:     case 'x':
 697:         wp = domod(cp, type);
 698:         if (wp == 0)
 699:             return (savestr(cp));
 700:         *adid = 1;
 701:         return (wp);
 702: 
 703:     default:
 704:         wp = wbuf;
 705:         i = BUFSIZ - 4;
 706:         for (mp = cp; *mp; mp++)
 707:             if (matchs(mp, lhsb)) {
 708:                 for (np = cp; np < mp;)
 709:                     *wp++ = *np++, --i;
 710:                 for (np = rhsb; *np; np++) switch (*np) {
 711: 
 712:                 case '\\':
 713:                     if (np[1] == '&')
 714:                         np++;
 715:                     /* fall into ... */
 716: 
 717:                 default:
 718:                     if (--i < 0)
 719:                         goto ovflo;
 720:                     *wp++ = *np;
 721:                     continue;
 722: 
 723:                 case '&':
 724:                     i -= strlen(lhsb);
 725:                     if (i < 0)
 726:                         goto ovflo;
 727:                     *wp = 0;
 728:                     (void) strcat(wp, lhsb);
 729:                     wp = strend(wp);
 730:                     continue;
 731:                 }
 732:                 mp += strlen(lhsb);
 733:                 i -= strlen(mp);
 734:                 if (i < 0) {
 735: ovflo:
 736:                     seterr("Subst buf ovflo");
 737:                     return ("");
 738:                 }
 739:                 *wp = 0;
 740:                 (void) strcat(wp, mp);
 741:                 *adid = 1;
 742:                 return (savestr(wbuf));
 743:             }
 744:         return (savestr(cp));
 745:     }
 746: }
 747: 
 748: char *
 749: domod(cp, type)
 750:     char *cp;
 751:     int type;
 752: {
 753:     register char *wp, *xp;
 754:     register int c;
 755: 
 756:     switch (type) {
 757: 
 758:     case 'x':
 759:     case 'q':
 760:         wp = savestr(cp);
 761:         for (xp = wp; c = *xp; xp++)
 762:             if ((c != ' ' && c != '\t') || type == 'q')
 763:                 *xp |= QUOTE;
 764:         return (wp);
 765: 
 766:     case 'h':
 767:     case 't':
 768:         if (!any('/', cp))
 769:             return (type == 't' ? savestr(cp) : 0);
 770:         wp = strend(cp);
 771:         while (*--wp != '/')
 772:             continue;
 773:         if (type == 'h')
 774:             xp = savestr(cp), xp[wp - cp] = 0;
 775:         else
 776:             xp = savestr(wp + 1);
 777:         return (xp);
 778: 
 779:     case 'e':
 780:     case 'r':
 781:         wp = strend(cp);
 782:         for (wp--; wp >= cp && *wp != '/'; wp--)
 783:             if (*wp == '.') {
 784:                 if (type == 'e')
 785:                     xp = savestr(wp + 1);
 786:                 else
 787:                     xp = savestr(cp), xp[wp - cp] = 0;
 788:                 return (xp);
 789:             }
 790:         return (savestr(type == 'e' ? "" : cp));
 791:     }
 792:     return (0);
 793: }
 794: 
 795: matchs(str, pat)
 796:     register char *str, *pat;
 797: {
 798: 
 799:     while (*str && *pat && *str == *pat)
 800:         str++, pat++;
 801:     return (*pat == 0);
 802: }
 803: 
 804: getsel(al, ar, dol)
 805:     register int *al, *ar;
 806:     int dol;
 807: {
 808:     register int c = getC(0);
 809:     register int i;
 810:     bool first = *al < 0;
 811: 
 812:     switch (c) {
 813: 
 814:     case '%':
 815:         if (quesarg == -1)
 816:             goto bad;
 817:         if (*al < 0)
 818:             *al = quesarg;
 819:         *ar = quesarg;
 820:         break;
 821: 
 822:     case '-':
 823:         if (*al < 0) {
 824:             *al = 0;
 825:             *ar = dol - 1;
 826:             unreadc(c);
 827:         }
 828:         return (1);
 829: 
 830:     case '^':
 831:         if (*al < 0)
 832:             *al = 1;
 833:         *ar = 1;
 834:         break;
 835: 
 836:     case '$':
 837:         if (*al < 0)
 838:             *al = dol;
 839:         *ar = dol;
 840:         break;
 841: 
 842:     case '*':
 843:         if (*al < 0)
 844:             *al = 1;
 845:         *ar = dol;
 846:         if (*ar < *al) {
 847:             *ar = 0;
 848:             *al = 1;
 849:             return (1);
 850:         }
 851:         break;
 852: 
 853:     default:
 854:         if (digit(c)) {
 855:             i = 0;
 856:             while (digit(c)) {
 857:                 i = i * 10 + c - '0';
 858:                 c = getC(0);
 859:             }
 860:             if (i < 0)
 861:                 i = dol + 1;
 862:             if (*al < 0)
 863:                 *al = i;
 864:             *ar = i;
 865:         } else
 866:             if (*al < 0)
 867:                 *al = 0, *ar = dol;
 868:             else
 869:                 *ar = dol - 1;
 870:         unreadc(c);
 871:         break;
 872:     }
 873:     if (first) {
 874:         c = getC(0);
 875:         unreadc(c);
 876:         if (any(c, "-$*"))
 877:             return (1);
 878:     }
 879:     if (*al > *ar || *ar > dol) {
 880: bad:
 881:         seterr("Bad ! arg selector");
 882:         return (0);
 883:     }
 884:     return (1);
 885: 
 886: }
 887: 
 888: struct wordent *
 889: gethent(sc)
 890:     int sc;
 891: {
 892:     register struct Hist *hp;
 893:     register char *np;
 894:     register int c;
 895:     int event;
 896:     bool back = 0;
 897: 
 898:     c = sc == HISTSUB ? HIST : getC(0);
 899:     if (c == HIST) {
 900:         if (alhistp)
 901:             return (alhistp);
 902:         event = eventno;
 903:         goto skip;
 904:     }
 905:     switch (c) {
 906: 
 907:     case ':':
 908:     case '^':
 909:     case '$':
 910:     case '*':
 911:     case '%':
 912:         ungetC(c);
 913:         if (lastev == eventno && alhistp)
 914:             return (alhistp);
 915:         event = lastev;
 916:         break;
 917: 
 918:     case '-':
 919:         back = 1;
 920:         c = getC(0);
 921:         goto number;
 922: 
 923:     case '#':           /* !# is command being typed in (mrh) */
 924:         return(&paraml);
 925: 
 926:     default:
 927:         if (any(c, "(=~")) {
 928:             unreadc(c);
 929:             ungetC(HIST);
 930:             return (0);
 931:         }
 932:         if (digit(c))
 933:             goto number;
 934:         np = lhsb;
 935:         while (!any(c, ": \t\\\n}")) {
 936:             if (np < &lhsb[sizeof lhsb - 2])
 937:                 *np++ = c;
 938:             c = getC(0);
 939:         }
 940:         unreadc(c);
 941:         if (np == lhsb) {
 942:             ungetC(HIST);
 943:             return (0);
 944:         }
 945:         *np++ = 0;
 946:         hp = findev(lhsb, 0);
 947:         if (hp)
 948:             lastev = hp->Hnum;
 949:         return (&hp->Hlex);
 950: 
 951:     case '?':
 952:         np = lhsb;
 953:         for (;;) {
 954:             c = getC(0);
 955:             if (c == '\n') {
 956:                 unreadc(c);
 957:                 break;
 958:             }
 959:             if (c == '?')
 960:                 break;
 961:             if (np < &lhsb[sizeof lhsb - 2])
 962:                 *np++ = c;
 963:         }
 964:         if (np == lhsb) {
 965:             if (lhsb[0] == 0) {
 966:                 seterr("No prev search");
 967:                 return (0);
 968:             }
 969:         } else
 970:             *np++ = 0;
 971:         hp = findev(lhsb, 1);
 972:         if (hp)
 973:             lastev = hp->Hnum;
 974:         return (&hp->Hlex);
 975: 
 976:     number:
 977:         event = 0;
 978:         while (digit(c)) {
 979:             event = event * 10 + c - '0';
 980:             c = getC(0);
 981:         }
 982:         if (back)
 983:             event = eventno + (alhistp == 0) - (event ? event : 0);
 984:         unreadc(c);
 985:         break;
 986:     }
 987: skip:
 988:     for (hp = Histlist.Hnext; hp; hp = hp->Hnext)
 989:         if (hp->Hnum == event) {
 990:             hp->Href = eventno;
 991:             lastev = hp->Hnum;
 992:             return (&hp->Hlex);
 993:         }
 994:     np = putn(event);
 995:     noev(np);
 996:     return (0);
 997: }
 998: 
 999: struct Hist *
1000: findev(cp, anyarg)
1001:     char *cp;
1002:     bool anyarg;
1003: {
1004:     register struct Hist *hp;
1005: 
1006:     for (hp = Histlist.Hnext; hp; hp = hp->Hnext) {
1007:         char *dp;
1008:         register char *p, *q;
1009:         register struct wordent *lp = hp->Hlex.next;
1010:         int argno = 0;
1011: 
1012:         if (lp->word[0] == '\n')
1013:             continue;
1014:         if (!anyarg) {
1015:             p = cp;
1016:             q = lp->word;
1017:             do
1018:                 if (!*p)
1019:                     return (hp);
1020:             while (*p++ == *q++);
1021:             continue;
1022:         }
1023:         do {
1024:             for (dp = lp->word; *dp; dp++) {
1025:                 p = cp;
1026:                 q = dp;
1027:                 do
1028:                     if (!*p) {
1029:                         quesarg = argno;
1030:                         return (hp);
1031:                     }
1032:                 while (*p++ == *q++);
1033:             }
1034:             lp = lp->next;
1035:             argno++;
1036:         } while (lp->word[0] != '\n');
1037:     }
1038:     noev(cp);
1039:     return (0);
1040: }
1041: 
1042: noev(cp)
1043:     char *cp;
1044: {
1045: 
1046:     seterr2(cp, ": Event not found");
1047: }
1048: 
1049: setexclp(cp)
1050:     register char *cp;
1051: {
1052: 
1053:     if (cp && cp[0] == '\n')
1054:         return;
1055:     exclp = cp;
1056: }
1057: 
1058: unreadc(c)
1059:     char c;
1060: {
1061: 
1062:     peekread = c;
1063: }
1064: 
1065: readc(wanteof)
1066:     bool wanteof;
1067: {
1068:     register int c;
1069:     static sincereal;
1070: 
1071:     if (c = peekread) {
1072:         peekread = 0;
1073:         return (c);
1074:     }
1075: top:
1076:     if (alvecp) {
1077:         if (c = *alvecp++)
1078:             return (c);
1079:         if (*alvec) {
1080:             alvecp = *alvec++;
1081:             return (' ');
1082:         }
1083:     }
1084:     if (alvec) {
1085:         if (alvecp = *alvec) {
1086:             alvec++;
1087:             goto top;
1088:         }
1089:         /* Infinite source! */
1090:         return ('\n');
1091:     }
1092:     if (evalp) {
1093:         if (c = *evalp++)
1094:             return (c);
1095:         if (*evalvec) {
1096:             evalp = *evalvec++;
1097:             return (' ');
1098:         }
1099:         evalp = 0;
1100:     }
1101:     if (evalvec) {
1102:         if (evalvec == (char **)1) {
1103:             doneinp = 1;
1104:             reset();
1105:         }
1106:         if (evalp = *evalvec) {
1107:             evalvec++;
1108:             goto top;
1109:         }
1110:         evalvec = (char **)1;
1111:         return ('\n');
1112:     }
1113:     do {
1114:         if (arginp == (char *) 1 || onelflg == 1) {
1115:             if (wanteof)
1116:                 return (-1);
1117:             exitstat();
1118:         }
1119:         if (arginp) {
1120:             if ((c = *arginp++) == 0) {
1121:                 arginp = (char *) 1;
1122:                 return ('\n');
1123:             }
1124:             return (c);
1125:         }
1126: reread:
1127:         c = bgetc();
1128:         if (c < 0) {
1129:             struct sgttyb tty;
1130: 
1131:             if (wanteof)
1132:                 return (-1);
1133:             /* was isatty but raw with ignoreeof yields problems */
1134:             if (ioctl(SHIN, TIOCGETP, (char *)&tty) == 0 &&
1135:                 (tty.sg_flags & RAW) == 0) {
1136:                 /* was 'short' for FILEC */
1137:                 int ctpgrp;
1138: 
1139:                 if (++sincereal > 25)
1140:                     goto oops;
1141:                 if (tpgrp != -1 &&
1142:                     ioctl(FSHTTY, TIOCGPGRP, (char *)&ctpgrp) == 0 &&
1143:                     tpgrp != ctpgrp) {
1144:                     (void) ioctl(FSHTTY, TIOCSPGRP,
1145:                         (char *)&tpgrp);
1146:                     (void) killpg(ctpgrp, SIGHUP);
1147: printf("Reset tty pgrp from %d to %d\n", ctpgrp, tpgrp);
1148:                     goto reread;
1149:                 }
1150:                 if (adrof("ignoreeof")) {
1151:                     if (loginsh)
1152:                         printf("\nUse \"logout\" to logout.\n");
1153:                     else
1154:                         printf("\nUse \"exit\" to leave csh.\n");
1155:                     reset();
1156:                 }
1157:                 if (chkstop == 0)
1158:                     panystop(1);
1159:             }
1160: oops:
1161:             doneinp = 1;
1162:             reset();
1163:         }
1164:         sincereal = 0;
1165:         if (c == '\n' && onelflg)
1166:             onelflg--;
1167:     } while (c == 0);
1168:     return (c);
1169: }
1170: 
1171: bgetc()
1172: {
1173:     register int buf, off, c;
1174: #ifdef FILEC
1175:     char ttyline[BUFSIZ];
1176:     register int numleft = 0, roomleft;
1177: #endif
1178: 
1179: #ifdef TELL
1180:     if (cantell) {
1181:         if (fseekp < fbobp || fseekp > feobp) {
1182:             fbobp = feobp = fseekp;
1183:             (void) lseek(SHIN, fseekp, 0);
1184:         }
1185:         if (fseekp == feobp) {
1186:             fbobp = feobp;
1187:             do
1188:                 c = read(SHIN, fbuf[0], BUFSIZ);
1189:             while (c < 0 && errno == EINTR);
1190:             if (c <= 0)
1191:                 return (-1);
1192:             feobp += c;
1193:         }
1194:         c = fbuf[0][fseekp - fbobp];
1195:         fseekp++;
1196:         return (c & 0377);
1197:     }
1198: #endif
1199: again:
1200:     buf = (int) fseekp / BUFSIZ;
1201:     if (buf >= fblocks) {
1202:         register char **nfbuf =
1203:             (char **) calloc((unsigned) (fblocks + 2),
1204:                 sizeof (char **));
1205: 
1206:         if (fbuf) {
1207:             (void) blkcpy(nfbuf, fbuf);
1208:             xfree((char *)fbuf);
1209:         }
1210:         fbuf = nfbuf;
1211:         fbuf[fblocks] = calloc(BUFSIZ, sizeof (char));
1212:         fblocks++;
1213:         goto again;
1214:     }
1215:     if (fseekp >= feobp) {
1216:         buf = (int) feobp / BUFSIZ;
1217:         off = (int) feobp % BUFSIZ;
1218: #ifndef FILEC
1219:         for (;;) {
1220:             c = read(SHIN, fbuf[buf] + off, BUFSIZ - off);
1221: #else
1222:         roomleft = BUFSIZ - off;
1223:         for (;;) {
1224:             if (filec && intty) {
1225:                 c = numleft ? numleft : tenex(ttyline, BUFSIZ);
1226:                 if (c > roomleft) {
1227:                     /* start with fresh buffer */
1228:                     feobp = fseekp = fblocks * BUFSIZ;
1229:                     numleft = c;
1230:                     goto again;
1231:                 }
1232:                 if (c > 0)
1233:                     copy(fbuf[buf] + off, ttyline, c);
1234:                 numleft = 0;
1235:             } else
1236:                 c = read(SHIN, fbuf[buf] + off, roomleft);
1237: #endif
1238:             if (c >= 0)
1239:                 break;
1240:             if (errno == EWOULDBLOCK) {
1241:                 int off = 0;
1242: 
1243:                 (void) ioctl(SHIN, FIONBIO, (char *)&off);
1244:             } else if (errno != EINTR)
1245:                 break;
1246:         }
1247:         if (c <= 0)
1248:             return (-1);
1249:         feobp += c;
1250: #ifndef FILEC
1251:         goto again;
1252: #else
1253:         if (filec && !intty)
1254:             goto again;
1255: #endif
1256:     }
1257:     c = fbuf[buf][(int) fseekp % BUFSIZ];
1258:     fseekp++;
1259:     return (c & 0377);
1260: }
1261: 
1262: bfree()
1263: {
1264:     register int sb, i;
1265: 
1266: #ifdef TELL
1267:     if (cantell)
1268:         return;
1269: #endif
1270:     if (whyles)
1271:         return;
1272:     sb = (int) (fseekp - 1) / BUFSIZ;
1273:     if (sb > 0) {
1274:         for (i = 0; i < sb; i++)
1275:             xfree(fbuf[i]);
1276:         (void) blkcpy(fbuf, &fbuf[sb]);
1277:         fseekp -= BUFSIZ * sb;
1278:         feobp -= BUFSIZ * sb;
1279:         fblocks -= sb;
1280:     }
1281: }
1282: 
1283: bseek(l)
1284:     off_t l;
1285: {
1286:     register struct whyle *wp;
1287: 
1288:     fseekp = l;
1289: #ifdef TELL
1290:     if (!cantell) {
1291: #endif
1292:         if (!whyles)
1293:             return;
1294:         for (wp = whyles; wp->w_next; wp = wp->w_next)
1295:             continue;
1296:         if (wp->w_start > l)
1297:             l = wp->w_start;
1298: #ifdef TELL
1299:     }
1300: #endif
1301: }
1302: 
1303: /* any similarity to bell telephone is purely accidental */
1304: #ifndef btell
1305: off_t
1306: btell()
1307: {
1308: 
1309:     return (fseekp);
1310: }
1311: #endif
1312: 
1313: btoeof()
1314: {
1315: 
1316:     (void) lseek(SHIN, (off_t)0, 2);
1317:     fseekp = feobp;
1318:     wfree();
1319:     bfree();
1320: }
1321: 
1322: #ifdef TELL
1323: settell()
1324: {
1325: 
1326:     cantell = 0;
1327:     if (arginp || onelflg || intty)
1328:         return;
1329:     if (lseek(SHIN, (off_t)0, 1) < 0 || errno == ESPIPE)
1330:         return;
1331:     fbuf = (char **) calloc(2, sizeof (char **));
1332:     fblocks = 1;
1333:     fbuf[0] = calloc(BUFSIZ, sizeof (char));
1334:     fseekp = fbobp = feobp = lseek(SHIN, (off_t)0, 1);
1335:     cantell = 1;
1336: }
1337: #endif

Defined functions

addla defined in line 424; used 5 times
bfree defined in line 1262; used 1 times
bgetc defined in line 1171; used 1 times
bseek defined in line 1283; used 5 times
btell defined in line 1305; never used
btoeof defined in line 1313; used 2 times
copylex defined in line 118; used 1 times
domod defined in line 748; used 3 times
dosub defined in line 649; used 2 times
findev defined in line 999; used 3 times
getC1 defined in line 271; used 1 times
  • in line 61
getdol defined in line 325; used 1 times
getexcl defined in line 446; used 2 times
gethent defined in line 888; used 2 times
getsel defined in line 804; used 2 times
getsub defined in line 521; used 2 times
lex defined in line 65; used 6 times
matchs defined in line 795; used 1 times
noev defined in line 1042; used 2 times
prlex defined in line 103; used 7 times
readc defined in line 1065; used 8 times
setexclp defined in line 1049; used 2 times
settell defined in line 1323; used 2 times
subword defined in line 679; used 2 times
unreadc defined in line 1058; used 17 times
word defined in line 153; used 21 times

Defined variables

alvecp defined in line 49; used 5 times
exclc defined in line 48; used 5 times
exclnxt defined in line 47; used 12 times
exclp defined in line 46; used 4 times
getCtmp defined in line 60; used 2 times
  • in line 61(2)
hadhist defined in line 58; used 3 times
lhsb defined in line 441; used 23 times
peekc defined in line 43; used 5 times
peekd defined in line 43; used 3 times
peekread defined in line 44; used 3 times
quesarg defined in line 444; used 5 times
rhsb defined in line 443; used 5 times
sccsid defined in line 8; never used
slhs defined in line 442; used 3 times

Defined macros

getC defined in line 61; used 39 times
ungetC defined in line 62; used 13 times
ungetD defined in line 63; used 4 times
Last modified: 1991-08-31
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 7133
Valid CSS Valid XHTML 1.0 Strict