sh.lex.c revision 59243
167754Smsmith/* $Header: /src/pub/tcsh/sh.lex.c,v 3.49 1998/04/08 13:58:54 christos Exp $ */ 267754Smsmith/* 377424Smsmith * sh.lex.c: Lexical analysis into tokens 467754Smsmith */ 567754Smsmith/*- 667754Smsmith * Copyright (c) 1980, 1991 The Regents of the University of California. 7217365Sjkim * All rights reserved. 8306536Sjkim * 970243Smsmith * Redistribution and use in source and binary forms, with or without 1067754Smsmith * modification, are permitted provided that the following conditions 11217365Sjkim * are met: 12217365Sjkim * 1. Redistributions of source code must retain the above copyright 13217365Sjkim * notice, this list of conditions and the following disclaimer. 14217365Sjkim * 2. Redistributions in binary form must reproduce the above copyright 15217365Sjkim * notice, this list of conditions and the following disclaimer in the 16217365Sjkim * documentation and/or other materials provided with the distribution. 17217365Sjkim * 3. All advertising materials mentioning features or use of this software 18217365Sjkim * must display the following acknowledgement: 19217365Sjkim * This product includes software developed by the University of 20217365Sjkim * California, Berkeley and its contributors. 21217365Sjkim * 4. Neither the name of the University nor the names of its contributors 22217365Sjkim * may be used to endorse or promote products derived from this software 23217365Sjkim * without specific prior written permission. 24217365Sjkim * 2567754Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26217365Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27217365Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28217365Sjkim * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2967754Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33217365Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34217365Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35217365Sjkim * SUCH DAMAGE. 36217365Sjkim */ 37217365Sjkim#include "sh.h" 38217365Sjkim 39217365SjkimRCSID("$Id: sh.lex.c,v 3.49 1998/04/08 13:58:54 christos Exp $") 40217365Sjkim 41217365Sjkim#include "ed.h" 42217365Sjkim/* #define DEBUG_INP */ 4367754Smsmith/* #define DEBUG_SEEK */ 44193341Sjkim 45193341Sjkim/* 46193341Sjkim * C shell 4767754Smsmith */ 4877424Smsmith 4991116Smsmith/* 5067754Smsmith * These lexical routines read input and form lists of words. 5167754Smsmith * There is some involved processing here, because of the complications 5267754Smsmith * of input buffering, and especially because of history substitution. 5367754Smsmith */ 5477424Smsmithstatic Char *word __P((void)); 5567754Smsmithstatic int getC1 __P((int)); 56151937Sjkimstatic void getdol __P((void)); 57151937Sjkimstatic void getexcl __P((int)); 5867754Smsmithstatic struct Hist *findev __P((Char *, bool)); 5967754Smsmithstatic void setexclp __P((Char *)); 6067754Smsmithstatic int bgetc __P((void)); 6167754Smsmithstatic void balloc __P((int)); 62241973Sjkimstatic void bfree __P((void)); 63167802Sjkimstatic struct wordent *gethent __P((int)); 6467754Smsmithstatic int matchs __P((Char *, Char *)); 6567754Smsmithstatic int getsel __P((int *, int *, int)); 6667754Smsmithstatic struct wordent *getsub __P((struct wordent *)); 6767754Smsmithstatic Char *subword __P((Char *, int, bool *)); 6877424Smsmithstatic struct wordent *dosub __P((int, struct wordent *, bool)); 69167802Sjkim 70107325Siwasaki/* 7167754Smsmith * Peekc is a peek character for getC, peekread for readc. 7267754Smsmith * There is a subtlety here in many places... history routines 7367754Smsmith * will read ahead and then insert stuff into the input stream. 7467754Smsmith * If they push back a character then they must push it behind 75167802Sjkim * the text substituted by the history substitution. On the other 7667754Smsmith * hand in several places we need 2 peek characters. To make this 7783174Smsmith * all work, the history routines read with getC, and make use both 78167802Sjkim * of ungetC and unreadc. The key observation is that the state 7967754Smsmith * of getC at the call of a history reference is such that calls 8067754Smsmith * to getC from the history routines will always yield calls of 8167754Smsmith * readc, unless this peeking is involved. That is to say that during 8267754Smsmith * getexcl the variables lap, exclp, and exclnxt are all zero. 8367754Smsmith * 8467754Smsmith * Getdol invokes history substitution, hence the extra peek, peekd, 8567754Smsmith * which it can ungetD to be before history substitutions. 8667754Smsmith */ 8767754Smsmithstatic Char peekc = 0, peekd = 0; 88281075Sdimstatic Char peekread = 0; 8967754Smsmith 9067754Smsmith/* (Tail of) current word from ! subst */ 91151937Sjkimstatic Char *exclp = NULL; 92151937Sjkim 9380062Smsmith/* The rest of the ! subst words */ 9477424Smsmithstatic struct wordent *exclnxt = NULL; 9567754Smsmith 9667754Smsmith/* Count of remaining words in ! subst */ 97306536Sjkimstatic int exclc = 0; 98167802Sjkim 9967754Smsmith/* "Globp" for alias resubstitution */ 100167802Sjkimint aret = F_SEEK; 101167802Sjkim 102167802Sjkim/* 103167802Sjkim * Labuf implements a general buffer for lookahead during lexical operations. 104167802Sjkim * Text which is to be placed in the input stream can be stuck here. 105167802Sjkim * We stick parsed ahead $ constructs during initial input, 106167802Sjkim * process id's from `$$', and modified variable values (from qualifiers 107167802Sjkim * during expansion in sh.dol.c) here. 108167802Sjkim */ 109167802Sjkimstatic Char labuf[BUFSIZE]; 110167802Sjkim 111167802Sjkim/* 112167802Sjkim * Lex returns to its caller not only a wordlist (as a "var" parameter) 113167802Sjkim * but also whether a history substitution occurred. This is used in 114241973Sjkim * the main (process) routine to determine whether to echo, and also 115167802Sjkim * when called by the alias routine to determine whether to keep the 116167802Sjkim * argument list. 117167802Sjkim */ 118167802Sjkimstatic bool hadhist = 0; 119167802Sjkim 120167802Sjkim/* 121167802Sjkim * Avoid alias expansion recursion via \!# 122167802Sjkim */ 123167802Sjkimint hleft; 124167802Sjkim 125167802SjkimChar histline[BUFSIZE + 2]; /* last line input */ 126167802Sjkim 127167802Sjkim /* The +2 is to fool hp's optimizer */ 128167802Sjkimbool histvalid = 0; /* is histline valid */ 129167802Sjkimstatic Char *histlinep = NULL; /* current pointer into histline */ 130167802Sjkim 131167802Sjkimstatic Char getCtmp; 132167802Sjkim 133167802Sjkim#define getC(f) (((getCtmp = peekc) != '\0') ? (peekc = 0, getCtmp) : getC1(f)) 13467754Smsmith#define ungetC(c) peekc = (Char) c 13567754Smsmith#define ungetD(c) peekd = (Char) c 136167802Sjkim 137167802Sjkim/* Use Htime to store timestamps picked up from history file for enthist() 138167802Sjkim * if reading saved history (sg) 139167802Sjkim */ 140281075Sdimtime_t Htime = (time_t)0; 141167802Sjkimstatic time_t a2time_t __P((Char *)); 142167802Sjkim 143167802Sjkim/* 144167802Sjkim * for history event processing 145167802Sjkim * in the command 'echo !?foo?:1 !$' we want the !$ to expand from the line 146167802Sjkim * 'foo' was found instead of the last command 147167802Sjkim */ 148167802Sjkimstatic int uselastevent = 1; 149281075Sdim 150167802Sjkimint 151167802Sjkimlex(hp) 15267754Smsmith struct wordent *hp; 15367754Smsmith{ 15467754Smsmith struct wordent *wdp; 15567754Smsmith int c; 15667754Smsmith 15767754Smsmith 15877424Smsmith uselastevent = 1; 15967754Smsmith histvalid = 0; 160151937Sjkim histlinep = histline; 161151937Sjkim *histlinep = '\0'; 16267754Smsmith 16391116Smsmith btell(&lineloc); 16467754Smsmith hp->next = hp->prev = hp; 16567754Smsmith hp->word = STRNULL; 166123315Snjl hadhist = 0; 167123315Snjl do 168241973Sjkim c = readc(0); 169123315Snjl while (c == ' ' || c == '\t'); 17067754Smsmith if (c == HISTSUB && intty) 17167754Smsmith /* ^lef^rit from tty is short !:s^lef^rit */ 17267754Smsmith getexcl(c); 17391116Smsmith else 17477424Smsmith unreadc(c); 17567754Smsmith wdp = hp; 17667754Smsmith /* 17791116Smsmith * The following loop is written so that the links needed by freelex will 17867754Smsmith * be ready and rarin to go even if it is interrupted. 17983174Smsmith */ 18091116Smsmith do { 18191116Smsmith struct wordent *new; 18291116Smsmith 183123315Snjl new = (struct wordent *) xmalloc((size_t) sizeof(*wdp)); 18467754Smsmith new->word = STRNULL; 185123315Snjl new->prev = wdp; 186123315Snjl new->next = hp; 187123315Snjl wdp->next = new; 188123315Snjl hp->prev = new; 189123315Snjl wdp = new; 190123315Snjl wdp->word = word(); 191306536Sjkim } while (wdp->word[0] != '\n'); 192306536Sjkim if (histlinep < histline + BUFSIZE) { 193123315Snjl *histlinep = '\0'; 19467754Smsmith if (histlinep > histline && histlinep[-1] == '\n') 19567754Smsmith histlinep[-1] = '\0'; 19667754Smsmith histvalid = 1; 197117521Snjl } 19867754Smsmith else { 19991116Smsmith histline[BUFSIZE - 1] = '\0'; 20091116Smsmith } 20167754Smsmith 20267754Smsmith return (hadhist); 20367754Smsmith} 20467754Smsmith 20567754Smsmithstatic time_t 206207344Sjkima2time_t(word) 20767754Smsmith Char *word; 208207344Sjkim{ 209151937Sjkim /* Attempt to distinguish timestamps from other possible entries. 21067754Smsmith * Format: "+NNNNNNNNNN" (10 digits, left padded with ascii '0') */ 21167754Smsmith 21267754Smsmith time_t ret; 213207344Sjkim Char *s; 21467754Smsmith int ct; 21567754Smsmith 21667754Smsmith if (!word || *(s = word) != '+') 21791116Smsmith return (time_t)0; 218207344Sjkim 219202771Sjkim for (++s, ret = 0, ct = 0; *s; ++s, ++ct) 22067754Smsmith { 22191116Smsmith if (!isdigit((unsigned char)*s)) 22283174Smsmith return (time_t)0; 22391116Smsmith ret = ret * 10 + (time_t)((unsigned char)*s - '0'); 22467754Smsmith } 22567754Smsmith 226281075Sdim if (ct != 10) 22767754Smsmith return (time_t)0; 228209746Sjkim 229209746Sjkim return ret; 230209746Sjkim} 231209746Sjkim 232209746Sjkimvoid 233209746Sjkimprlex(sp0) 234209746Sjkim struct wordent *sp0; 235209746Sjkim{ 236209746Sjkim struct wordent *sp = sp0->next; 237138287Smarks 23867754Smsmith for (;;) { 23967754Smsmith xprintf("%S", sp->word); 24067754Smsmith sp = sp->next; 241281075Sdim if (sp == sp0) 242167802Sjkim break; 24367754Smsmith if (sp->word[0] != '\n') 24467754Smsmith xputchar(' '); 24567754Smsmith } 24667754Smsmith} 24767754Smsmith 24877424Smsmithvoid 24967754Smsmithcopylex(hp, fp) 250151937Sjkim struct wordent *hp; 25167754Smsmith struct wordent *fp; 252151937Sjkim{ 25367754Smsmith struct wordent *wdp; 25467754Smsmith 25567754Smsmith wdp = hp; 25667754Smsmith fp = fp->next; 25767754Smsmith do { 25867754Smsmith struct wordent *new; 25967754Smsmith 26077424Smsmith new = (struct wordent *) xmalloc((size_t) sizeof(*wdp)); 26167754Smsmith new->word = STRNULL; 26267754Smsmith new->prev = wdp; 26367754Smsmith new->next = hp; 26467754Smsmith wdp->next = new; 26567754Smsmith hp->prev = new; 266167802Sjkim wdp = new; 26767754Smsmith wdp->word = Strsave(fp->word); 26867754Smsmith fp = fp->next; 26967754Smsmith } while (wdp->word[0] != '\n'); 27067754Smsmith} 271167802Sjkim 27267754Smsmithvoid 27367754Smsmithfreelex(vp) 27467754Smsmith struct wordent *vp; 27567754Smsmith{ 27667754Smsmith struct wordent *fp; 27767754Smsmith 27867754Smsmith while (vp->next != vp) { 27967754Smsmith fp = vp->next; 28077424Smsmith vp->next = fp->next; 28167754Smsmith if (fp->word != STRNULL) 282151937Sjkim xfree((ptr_t) fp->word); 283151937Sjkim xfree((ptr_t) fp); 28467754Smsmith } 28567754Smsmith vp->prev = vp; 28667754Smsmith} 28767754Smsmith 288241973Sjkimstatic Char * 28967754Smsmithword() 29067754Smsmith{ 29167754Smsmith Char c, c1; 29267754Smsmith Char *wp; 29367754Smsmith Char wbuf[BUFSIZE]; 29477424Smsmith Char hbuf[12]; 29567754Smsmith int h; 29667754Smsmith bool dolflg; 29767754Smsmith int i; 29867754Smsmith 29967754Smsmith wp = wbuf; 30067754Smsmith i = BUFSIZE - 4; 301167802Sjkimloop: 30267754Smsmith while ((c = getC(DOALL)) == ' ' || c == '\t') 30367754Smsmith continue; 30467754Smsmith if (cmap(c, _META | _ESC)) 30567754Smsmith switch (c) { 306167802Sjkim case '&': 307306536Sjkim case '|': 30867754Smsmith case '<': 30967754Smsmith case '>': 31067754Smsmith *wp++ = c; 31167754Smsmith c1 = getC(DOALL); 31267754Smsmith if (c1 == c) 31367754Smsmith *wp++ = c1; 31467754Smsmith else 31567754Smsmith ungetC(c1); 31677424Smsmith goto ret; 31767754Smsmith 318151937Sjkim case '#': 31967754Smsmith if (intty) 32067754Smsmith break; 32167754Smsmith c = 0; 32277424Smsmith h = 0; 32367754Smsmith do { 32467754Smsmith c1 = c; 32567754Smsmith c = getC(0); 32667754Smsmith if (h < 12) 32777424Smsmith hbuf[h++] = c; 32867754Smsmith } while (c != '\n'); 32967754Smsmith hbuf[11] = '\0'; 33067754Smsmith Htime = a2time_t(hbuf); 331167802Sjkim if (c1 == '\\') 33267754Smsmith goto loop; 33367754Smsmith /*FALLTHROUGH*/ 33491116Smsmith 33583174Smsmith case ';': 33683174Smsmith case '(': 33767754Smsmith case ')': 33867754Smsmith case '\n': 33967754Smsmith *wp++ = c; 34067754Smsmith goto ret; 34167754Smsmith 34267754Smsmith case '\\': 34367754Smsmith c = getC(0); 344167802Sjkim if (c == '\n') { 345167802Sjkim if (onelflg == 1) 34667754Smsmith onelflg = 2; 34767754Smsmith goto loop; 34867754Smsmith } 34967754Smsmith if (c != HIST) 350 *wp++ = '\\', --i; 351 c |= QUOTE; 352 default: 353 break; 354 } 355 c1 = 0; 356 dolflg = DOALL; 357 for (;;) { 358 if (c1) { 359 if (c == c1) { 360 c1 = 0; 361 dolflg = DOALL; 362 } 363 else if (c == '\\') { 364 c = getC(0); 365/* 366 * PWP: this is dumb, but how all of the other shells work. If \ quotes 367 * a character OUTSIDE of a set of ''s, why shouldn't it quote EVERY 368 * following character INSIDE a set of ''s. 369 * 370 * Actually, all I really want to be able to say is 'foo\'bar' --> foo'bar 371 */ 372 if (c == HIST) 373 c |= QUOTE; 374 else { 375 if (bslash_quote && 376 ((c == '\'') || (c == '"') || 377 (c == '\\'))) { 378 c |= QUOTE; 379 } 380 else { 381 if (c == '\n') 382 /* 383 * if (c1 == '`') c = ' '; else 384 */ 385 c |= QUOTE; 386 ungetC(c); 387 c = '\\'; 388 } 389 } 390 } 391 else if (c == '\n') { 392 seterror(ERR_UNMATCHED, c1); 393 ungetC(c); 394 break; 395 } 396 } 397 else if (cmap(c, _META | _QF | _QB | _ESC)) { 398 if (c == '\\') { 399 c = getC(0); 400 if (c == '\n') { 401 if (onelflg == 1) 402 onelflg = 2; 403 break; 404 } 405 if (c != HIST) 406 *wp++ = '\\', --i; 407 c |= QUOTE; 408 } 409 else if (cmap(c, _QF | _QB)) { /* '"` */ 410 c1 = c; 411 dolflg = c == '"' ? DOALL : DOEXCL; 412 } 413 else if (c != '#' || !intty) { 414 ungetC(c); 415 break; 416 } 417 } 418 if (--i > 0) { 419 *wp++ = c; 420 c = getC(dolflg); 421 } 422 else { 423 seterror(ERR_WTOOLONG); 424 wp = &wbuf[1]; 425 break; 426 } 427 } 428ret: 429 *wp = 0; 430 return (Strsave(wbuf)); 431} 432 433static int 434getC1(flag) 435 int flag; 436{ 437 Char c; 438 439 for (;;) { 440 if ((c = peekc) != 0) { 441 peekc = 0; 442 return (c); 443 } 444 if (lap) { 445 if ((c = *lap++) == 0) 446 lap = 0; 447 else { 448 if (cmap(c, _META | _QF | _QB)) 449 c |= QUOTE; 450 return (c); 451 } 452 } 453 if ((c = peekd) != 0) { 454 peekd = 0; 455 return (c); 456 } 457 if (exclp) { 458 if ((c = *exclp++) != 0) 459 return (c); 460 if (exclnxt && --exclc >= 0) { 461 exclnxt = exclnxt->next; 462 setexclp(exclnxt->word); 463 return (' '); 464 } 465 exclp = 0; 466 exclnxt = 0; 467 /* this will throw away the dummy history entries */ 468 savehist(NULL, 0); 469 470 } 471 if (exclnxt) { 472 exclnxt = exclnxt->next; 473 if (--exclc < 0) 474 exclnxt = 0; 475 else 476 setexclp(exclnxt->word); 477 continue; 478 } 479 c = readc(0); 480 if (c == '$' && (flag & DODOL)) { 481 getdol(); 482 continue; 483 } 484 if (c == HIST && (flag & DOEXCL)) { 485 getexcl(0); 486 continue; 487 } 488 break; 489 } 490 return (c); 491} 492 493static void 494getdol() 495{ 496 Char *np, *ep; 497 Char name[4 * MAXVARLEN + 1]; 498 int c; 499 int sc; 500 bool special = 0, toolong; 501 502 np = name, *np++ = '$'; 503 c = sc = getC(DOEXCL); 504 if (any("\t \n", c)) { 505 ungetD(c); 506 ungetC('$' | QUOTE); 507 return; 508 } 509 if (c == '{') 510 *np++ = (Char) c, c = getC(DOEXCL); 511 if (c == '#' || c == '?' || c == '%') 512 special++, *np++ = (Char) c, c = getC(DOEXCL); 513 *np++ = (Char) c; 514 switch (c) { 515 516 case '<': 517 case '$': 518 case '!': 519 if (special) 520 seterror(ERR_SPDOLLT); 521 *np = 0; 522 addla(name); 523 return; 524 525 case '\n': 526 ungetD(c); 527 np--; 528 if (!special) 529 seterror(ERR_NEWLINE); 530 *np = 0; 531 addla(name); 532 return; 533 534 case '*': 535 if (special) 536 seterror(ERR_SPSTAR); 537 *np = 0; 538 addla(name); 539 return; 540 541 default: 542 toolong = 0; 543 if (Isdigit(c)) { 544#ifdef notdef 545 /* let $?0 pass for now */ 546 if (special) { 547 seterror(ERR_DIGIT); 548 *np = 0; 549 addla(name); 550 return; 551 } 552#endif 553 /* we know that np < &name[4] */ 554 ep = &np[MAXVARLEN]; 555 while ((c = getC(DOEXCL)) != 0) { 556 if (!Isdigit(c)) 557 break; 558 if (np < ep) 559 *np++ = (Char) c; 560 else 561 toolong = 1; 562 } 563 } 564 else if (letter(c)) { 565 /* we know that np < &name[4] */ 566 ep = &np[MAXVARLEN]; 567 toolong = 0; 568 while ((c = getC(DOEXCL)) != 0) { 569 /* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */ 570 if (!letter(c) && !Isdigit(c)) 571 break; 572 if (np < ep) 573 *np++ = (Char) c; 574 else 575 toolong = 1; 576 } 577 } 578 else { 579 if (!special) 580 seterror(ERR_VARILL); 581 else { 582 ungetD(c); 583 --np; 584 } 585 *np = 0; 586 addla(name); 587 return; 588 } 589 if (toolong) { 590 seterror(ERR_VARTOOLONG); 591 *np = 0; 592 addla(name); 593 return; 594 } 595 break; 596 } 597 if (c == '[') { 598 *np++ = (Char) c; 599 /* 600 * Name up to here is a max of MAXVARLEN + 8. 601 */ 602 ep = &np[2 * MAXVARLEN + 8]; 603 do { 604 /* 605 * Michael Greim: Allow $ expansion to take place in selector 606 * expressions. (limits the number of characters returned) 607 */ 608 c = getC(DOEXCL | DODOL); 609 if (c == '\n') { 610 ungetD(c); 611 np--; 612 seterror(ERR_NLINDEX); 613 *np = 0; 614 addla(name); 615 return; 616 } 617 if (np < ep) 618 *np++ = (Char) c; 619 } while (c != ']'); 620 *np = '\0'; 621 if (np >= ep) { 622 seterror(ERR_SELOVFL); 623 addla(name); 624 return; 625 } 626 c = getC(DOEXCL); 627 } 628 /* 629 * Name up to here is a max of 2 * MAXVARLEN + 8. 630 */ 631 if (c == ':') { 632 /* 633 * if the :g modifier is followed by a newline, then error right away! 634 * -strike 635 */ 636 637 int gmodflag = 0, amodflag = 0; 638 639#ifndef COMPAT 640 do { 641#endif /* COMPAT */ 642 *np++ = (Char) c, c = getC(DOEXCL); 643 if (c == 'g' || c == 'a') { 644 if (c == 'g') 645 gmodflag++; 646 else 647 amodflag++; 648 *np++ = (Char) c; c = getC(DOEXCL); 649 } 650 if ((c == 'g' && !gmodflag) || (c == 'a' && !amodflag)) { 651 if (c == 'g') 652 gmodflag++; 653 else 654 amodflag++; 655 *np++ = (Char) c; c = getC(DOEXCL); 656 } 657 *np++ = (Char) c; 658 /* scan s// [eichin:19910926.0512EST] */ 659 if (c == 's') { 660 int delimcnt = 2; 661 int delim = getC(0); 662 *np++ = (Char) delim; 663 664 if (!delim || letter(delim) 665 || Isdigit(delim) || any(" \t\n", delim)) { 666 seterror(ERR_BADSUBST); 667 break; 668 } 669 while ((c = getC(0)) != (-1)) { 670 *np++ = (Char) c; 671 if(c == delim) delimcnt--; 672 if(!delimcnt) break; 673 } 674 if(delimcnt) { 675 seterror(ERR_BADSUBST); 676 break; 677 } 678 c = 's'; 679 } 680 if (!any("htrqxesul", c)) { 681 if ((amodflag || gmodflag) && c == '\n') 682 stderror(ERR_VARSYN); /* strike */ 683 seterror(ERR_BADMOD, c); 684 *np = 0; 685 addla(name); 686 return; 687 } 688#ifndef COMPAT 689 } 690 while ((c = getC(DOEXCL)) == ':'); 691 ungetD(c); 692#endif /* COMPAT */ 693 } 694 else 695 ungetD(c); 696 if (sc == '{') { 697 c = getC(DOEXCL); 698 if (c != '}') { 699 ungetD(c); 700 seterror(ERR_MISSING, '}'); 701 *np = 0; 702 addla(name); 703 return; 704 } 705 *np++ = (Char) c; 706 } 707 *np = 0; 708 addla(name); 709 return; 710} 711 712void 713addla(cp) 714 Char *cp; 715{ 716 Char buf[BUFSIZE]; 717 718 if (Strlen(cp) + (lap ? Strlen(lap) : 0) >= 719 (sizeof(labuf) - 4) / sizeof(Char)) { 720 seterror(ERR_EXPOVFL); 721 return; 722 } 723 if (lap) 724 (void) Strcpy(buf, lap); 725 (void) Strcpy(labuf, cp); 726 if (lap) 727 (void) Strcat(labuf, buf); 728 lap = labuf; 729} 730 731static Char lhsb[32]; 732static Char slhs[32]; 733static Char rhsb[64]; 734static int quesarg; 735 736static void 737getexcl(sc) 738 int sc; 739{ 740 struct wordent *hp, *ip; 741 int left, right, dol; 742 int c; 743 744 if (sc == 0) { 745 sc = getC(0); 746 if (sc != '{') { 747 ungetC(sc); 748 sc = 0; 749 } 750 } 751 quesarg = -1; 752 753 if (uselastevent) { 754 uselastevent = 0; 755 lastev = eventno; 756 } 757 else 758 lastev = eventno; 759 hp = gethent(sc); 760 if (hp == 0) 761 return; 762 hadhist = 1; 763 dol = 0; 764 if (hp == alhistp) 765 for (ip = hp->next->next; ip != alhistt; ip = ip->next) 766 dol++; 767 else 768 for (ip = hp->next->next; ip != hp->prev; ip = ip->next) 769 dol++; 770 left = 0, right = dol; 771 if (sc == HISTSUB) { 772 ungetC('s'), unreadc(HISTSUB), c = ':'; 773 goto subst; 774 } 775 c = getC(0); 776 if (!any(":^$*-%", c)) 777 goto subst; 778 left = right = -1; 779 if (c == ':') { 780 c = getC(0); 781 unreadc(c); 782 if (letter(c) || c == '&') { 783 c = ':'; 784 left = 0, right = dol; 785 goto subst; 786 } 787 } 788 else 789 ungetC(c); 790 if (!getsel(&left, &right, dol)) 791 return; 792 c = getC(0); 793 if (c == '*') 794 ungetC(c), c = '-'; 795 if (c == '-') { 796 if (!getsel(&left, &right, dol)) 797 return; 798 c = getC(0); 799 } 800subst: 801 exclc = right - left + 1; 802 while (--left >= 0) 803 hp = hp->next; 804 if (sc == HISTSUB || c == ':') { 805 do { 806 hp = getsub(hp); 807 c = getC(0); 808 } while (c == ':'); 809 } 810 unreadc(c); 811 if (sc == '{') { 812 c = getC(0); 813 if (c != '}') 814 seterror(ERR_BADBANG); 815 } 816 exclnxt = hp; 817} 818 819static struct wordent * 820getsub(en) 821 struct wordent *en; 822{ 823 Char *cp; 824 int delim; 825 int c; 826 int sc; 827 bool global; 828 Char orhsb[sizeof(rhsb) / sizeof(Char)]; 829 830#ifndef COMPAT 831 do { 832#endif /* COMPAT */ 833 exclnxt = 0; 834 global = 0; 835 sc = c = getC(0); 836 if (c == 'g' || c == 'a') { 837 global |= (c == 'g') ? 1 : 2; 838 sc = c = getC(0); 839 } 840 if (((c =='g') && !(global & 1)) || ((c == 'a') && !(global & 2))) { 841 global |= (c == 'g') ? 1 : 2; 842 sc = c = getC(0); 843 } 844 845 switch (c) { 846 case 'p': 847 justpr++; 848 return (en); 849 850 case 'x': 851 case 'q': 852 global |= 1; 853 /*FALLTHROUGH*/ 854 855 case 'h': 856 case 'r': 857 case 't': 858 case 'e': 859 case 'u': 860 case 'l': 861 break; 862 863 case '&': 864 if (slhs[0] == 0) { 865 seterror(ERR_NOSUBST); 866 return (en); 867 } 868 (void) Strcpy(lhsb, slhs); 869 break; 870 871#ifdef notdef 872 case '~': 873 if (lhsb[0] == 0) 874 goto badlhs; 875 break; 876#endif 877 878 case 's': 879 delim = getC(0); 880 if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) { 881 unreadc(delim); 882 lhsb[0] = 0; 883 seterror(ERR_BADSUBST); 884 return (en); 885 } 886 cp = lhsb; 887 for (;;) { 888 c = getC(0); 889 if (c == '\n') { 890 unreadc(c); 891 break; 892 } 893 if (c == delim) 894 break; 895 if (cp > &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) { 896 lhsb[0] = 0; 897 seterror(ERR_BADSUBST); 898 return (en); 899 } 900 if (c == '\\') { 901 c = getC(0); 902 if (c != delim && c != '\\') 903 *cp++ = '\\'; 904 } 905 *cp++ = (Char) c; 906 } 907 if (cp != lhsb) 908 *cp++ = 0; 909 else if (lhsb[0] == 0) { 910 seterror(ERR_LHS); 911 return (en); 912 } 913 cp = rhsb; 914 (void) Strcpy(orhsb, cp); 915 for (;;) { 916 c = getC(0); 917 if (c == '\n') { 918 unreadc(c); 919 break; 920 } 921 if (c == delim) 922 break; 923#ifdef notdef 924 if (c == '~') { 925 if (&cp[Strlen(orhsb)] > &rhsb[sizeof(rhsb) / 926 sizeof(Char) - 2]) 927 goto toorhs; 928 (void) Strcpy(cp, orhsb); 929 cp = Strend(cp); 930 continue; 931 } 932#endif 933 if (cp > &rhsb[sizeof(rhsb) / sizeof(Char) - 2]) { 934 seterror(ERR_RHSLONG); 935 return (en); 936 } 937 if (c == '\\') { 938 c = getC(0); 939 if (c != delim /* && c != '~' */ ) 940 *cp++ = '\\'; 941 } 942 *cp++ = (Char) c; 943 } 944 *cp++ = 0; 945 break; 946 947 default: 948 if (c == '\n') 949 unreadc(c); 950 seterror(ERR_BADBANGMOD, c); 951 return (en); 952 } 953 (void) Strcpy(slhs, lhsb); 954 if (exclc) 955 en = dosub(sc, en, global); 956#ifndef COMPAT 957 } 958 while ((c = getC(0)) == ':'); 959 unreadc(c); 960#endif /* COMPAT */ 961 return (en); 962} 963 964/* 965 * 966 * From Beto Appleton (beto@aixwiz.austin.ibm.com) 967 * 968 * when using history substitution, and the variable 969 * 'history' is set to a value higher than 1000, 970 * the shell might either freeze (hang) or core-dump. 971 * We raise the limit to 50000000 972 */ 973 974#define HIST_PURGE -50000000 975static struct wordent * 976dosub(sc, en, global) 977 int sc; 978 struct wordent *en; 979 bool global; 980{ 981 struct wordent lexi; 982 bool didsub = 0, didone = 0; 983 struct wordent *hp = &lexi; 984 struct wordent *wdp; 985 int i = exclc; 986 struct Hist *hst; 987 988 wdp = hp; 989 while (--i >= 0) { 990 struct wordent *new = 991 (struct wordent *) xcalloc(1, sizeof *wdp); 992 993 new->word = 0; 994 new->prev = wdp; 995 new->next = hp; 996 wdp->next = new; 997 wdp = new; 998 en = en->next; 999 if (en->word) { 1000 Char *tword, *otword; 1001 1002 if ((global & 1) || didsub == 0) { 1003 tword = subword(en->word, sc, &didone); 1004 if (didone) 1005 didsub = 1; 1006 if (global & 2) { 1007 while (didone && tword != STRNULL) { 1008 otword = tword; 1009 tword = subword(otword, sc, &didone); 1010 if (Strcmp(tword, otword) == 0) { 1011 xfree((ptr_t) otword); 1012 break; 1013 } 1014 else 1015 xfree((ptr_t) otword); 1016 } 1017 } 1018 } 1019 else 1020 tword = Strsave(en->word); 1021 wdp->word = tword; 1022 } 1023 } 1024 if (didsub == 0) 1025 seterror(ERR_MODFAIL); 1026 hp->prev = wdp; 1027 /* 1028 * ANSI mode HP/UX compiler chokes on 1029 * return &enthist(HIST_PURGE, &lexi, 0)->Hlex; 1030 */ 1031 hst = enthist(HIST_PURGE, &lexi, 0, 0); 1032 return &(hst->Hlex); 1033} 1034 1035static Char * 1036subword(cp, type, adid) 1037 Char *cp; 1038 int type; 1039 bool *adid; 1040{ 1041 Char wbuf[BUFSIZE]; 1042 Char *wp, *mp, *np; 1043 int i; 1044 1045 *adid = 0; 1046 switch (type) { 1047 1048 case 'r': 1049 case 'e': 1050 case 'h': 1051 case 't': 1052 case 'q': 1053 case 'x': 1054 case 'u': 1055 case 'l': 1056 wp = domod(cp, type); 1057 if (wp == 0) 1058 return (Strsave(cp)); 1059 *adid = 1; 1060 return (wp); 1061 1062 default: 1063 wp = wbuf; 1064 i = BUFSIZE - 4; 1065 for (mp = cp; *mp; mp++) 1066 if (matchs(mp, lhsb)) { 1067 for (np = cp; np < mp;) 1068 *wp++ = *np++, --i; 1069 for (np = rhsb; *np; np++) 1070 switch (*np) { 1071 1072 case '\\': 1073 if (np[1] == '&') 1074 np++; 1075 /* fall into ... */ 1076 1077 default: 1078 if (--i < 0) { 1079 seterror(ERR_SUBOVFL); 1080 return (STRNULL); 1081 } 1082 *wp++ = *np; 1083 continue; 1084 1085 case '&': 1086 i -= Strlen(lhsb); 1087 if (i < 0) { 1088 seterror(ERR_SUBOVFL); 1089 return (STRNULL); 1090 } 1091 *wp = 0; 1092 (void) Strcat(wp, lhsb); 1093 wp = Strend(wp); 1094 continue; 1095 } 1096 mp += Strlen(lhsb); 1097 i -= Strlen(mp); 1098 if (i < 0) { 1099 seterror(ERR_SUBOVFL); 1100 return (STRNULL); 1101 } 1102 *wp = 0; 1103 (void) Strcat(wp, mp); 1104 *adid = 1; 1105 return (Strsave(wbuf)); 1106 } 1107 return (Strsave(cp)); 1108 } 1109} 1110 1111Char * 1112domod(cp, type) 1113 Char *cp; 1114 int type; 1115{ 1116 Char *wp, *xp; 1117 int c; 1118 1119 switch (type) { 1120 1121 case 'x': 1122 case 'q': 1123 wp = Strsave(cp); 1124 for (xp = wp; (c = *xp) != 0; xp++) 1125 if ((c != ' ' && c != '\t') || type == 'q') 1126 *xp |= QUOTE; 1127 return (wp); 1128 1129 case 'l': 1130 wp = Strsave(cp); 1131 for (cp = wp; *cp; cp++) 1132 if (Isupper(*cp)) { 1133 *cp = Tolower(*cp); 1134 return wp; 1135 } 1136 return wp; 1137 1138 case 'u': 1139 wp = Strsave(cp); 1140 for (cp = wp; *cp; cp++) 1141 if (Islower(*cp)) { 1142 *cp = Toupper(*cp); 1143 return wp; 1144 } 1145 return wp; 1146 1147 case 'h': 1148 case 't': 1149 if (!any(short2str(cp), '/')) 1150 return (type == 't' ? Strsave(cp) : 0); 1151 wp = Strend(cp); 1152 while (*--wp != '/') 1153 continue; 1154 if (type == 'h') 1155 xp = Strsave(cp), xp[wp - cp] = 0; 1156 else 1157 xp = Strsave(wp + 1); 1158 return (xp); 1159 1160 case 'e': 1161 case 'r': 1162 wp = Strend(cp); 1163 for (wp--; wp >= cp && *wp != '/'; wp--) 1164 if (*wp == '.') { 1165 if (type == 'e') 1166 xp = Strsave(wp + 1); 1167 else 1168 xp = Strsave(cp), xp[wp - cp] = 0; 1169 return (xp); 1170 } 1171 return (Strsave(type == 'e' ? STRNULL : cp)); 1172 default: 1173 break; 1174 } 1175 return (0); 1176} 1177 1178static int 1179matchs(str, pat) 1180 Char *str, *pat; 1181{ 1182 while (*str && *pat && *str == *pat) 1183 str++, pat++; 1184 return (*pat == 0); 1185} 1186 1187static int 1188getsel(al, ar, dol) 1189 int *al, *ar; 1190 int dol; 1191{ 1192 int c = getC(0); 1193 int i; 1194 bool first = *al < 0; 1195 1196 switch (c) { 1197 1198 case '%': 1199 if (quesarg == -1) { 1200 seterror(ERR_BADBANGARG); 1201 return (0); 1202 } 1203 if (*al < 0) 1204 *al = quesarg; 1205 *ar = quesarg; 1206 break; 1207 1208 case '-': 1209 if (*al < 0) { 1210 *al = 0; 1211 *ar = dol - 1; 1212 unreadc(c); 1213 } 1214 return (1); 1215 1216 case '^': 1217 if (*al < 0) 1218 *al = 1; 1219 *ar = 1; 1220 break; 1221 1222 case '$': 1223 if (*al < 0) 1224 *al = dol; 1225 *ar = dol; 1226 break; 1227 1228 case '*': 1229 if (*al < 0) 1230 *al = 1; 1231 *ar = dol; 1232 if (*ar < *al) { 1233 *ar = 0; 1234 *al = 1; 1235 return (1); 1236 } 1237 break; 1238 1239 default: 1240 if (Isdigit(c)) { 1241 i = 0; 1242 while (Isdigit(c)) { 1243 i = i * 10 + c - '0'; 1244 c = getC(0); 1245 } 1246 if (i < 0) 1247 i = dol + 1; 1248 if (*al < 0) 1249 *al = i; 1250 *ar = i; 1251 } 1252 else if (*al < 0) 1253 *al = 0, *ar = dol; 1254 else 1255 *ar = dol - 1; 1256 unreadc(c); 1257 break; 1258 } 1259 if (first) { 1260 c = getC(0); 1261 unreadc(c); 1262 if (any("-$*", c)) 1263 return (1); 1264 } 1265 if (*al > *ar || *ar > dol) { 1266 seterror(ERR_BADBANGARG); 1267 return (0); 1268 } 1269 return (1); 1270 1271} 1272 1273static struct wordent * 1274gethent(sc) 1275 int sc; 1276{ 1277 struct Hist *hp; 1278 Char *np; 1279 int c; 1280 int event; 1281 bool back = 0; 1282 1283 c = sc == HISTSUB ? HIST : getC(0); 1284 if (c == HIST) { 1285 if (alhistp) 1286 return (alhistp); 1287 event = eventno; 1288 } 1289 else 1290 switch (c) { 1291 1292 case ':': 1293 case '^': 1294 case '$': 1295 case '*': 1296 case '%': 1297 ungetC(c); 1298 if (lastev == eventno && alhistp) 1299 return (alhistp); 1300 event = lastev; 1301 break; 1302 1303 case '#': /* !# is command being typed in (mrh) */ 1304 if (--hleft == 0) { 1305 seterror(ERR_HISTLOOP); 1306 return (0); 1307 } 1308 else 1309 return (¶ml); 1310 /* NOTREACHED */ 1311 1312 case '-': 1313 back = 1; 1314 c = getC(0); 1315 /* FALLSTHROUGH */ 1316 1317 default: 1318 if (any("(=~", c)) { 1319 unreadc(c); 1320 ungetC(HIST); 1321 return (0); 1322 } 1323 np = lhsb; 1324 event = 0; 1325 while (!cmap(c, _ESC | _META | _QF | _QB) && !any("^*-%${}:#", c)) { 1326 if (event != -1 && Isdigit(c)) 1327 event = event * 10 + c - '0'; 1328 else 1329 event = -1; 1330 if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) 1331 *np++ = (Char) c; 1332 c = getC(0); 1333 } 1334 unreadc(c); 1335 if (np == lhsb) { 1336 ungetC(HIST); 1337 return (0); 1338 } 1339 *np++ = 0; 1340 if (event != -1) { 1341 /* 1342 * History had only digits 1343 */ 1344 if (back) 1345 event = eventno + (alhistp == 0) - (event ? event : 0); 1346 break; 1347 } 1348 if (back) { 1349 event = sizeof(lhsb) / sizeof(lhsb[0]); 1350 np = &lhsb[--event]; 1351 *np-- = '\0'; 1352 for (event--; np > lhsb; *np-- = lhsb[--event]) 1353 continue; 1354 *np = '-'; 1355 } 1356 hp = findev(lhsb, 0); 1357 if (hp) 1358 lastev = hp->Hnum; 1359 return (&hp->Hlex); 1360 1361 case '?': 1362 np = lhsb; 1363 for (;;) { 1364 c = getC(0); 1365 if (c == '\n') { 1366 unreadc(c); 1367 break; 1368 } 1369 if (c == '?') 1370 break; 1371 if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) 1372 *np++ = (Char) c; 1373 } 1374 if (np == lhsb) { 1375 if (lhsb[0] == 0) { 1376 seterror(ERR_NOSEARCH); 1377 return (0); 1378 } 1379 } 1380 else 1381 *np++ = 0; 1382 hp = findev(lhsb, 1); 1383 if (hp) 1384 lastev = hp->Hnum; 1385 return (&hp->Hlex); 1386 } 1387 1388 for (hp = Histlist.Hnext; hp; hp = hp->Hnext) 1389 if (hp->Hnum == event) { 1390 hp->Href = eventno; 1391 lastev = hp->Hnum; 1392 return (&hp->Hlex); 1393 } 1394 np = putn(event); 1395 seterror(ERR_NOEVENT, short2str(np)); 1396 return (0); 1397} 1398 1399static struct Hist * 1400findev(cp, anyarg) 1401 Char *cp; 1402 bool anyarg; 1403{ 1404 struct Hist *hp; 1405 1406 for (hp = Histlist.Hnext; hp; hp = hp->Hnext) { 1407 Char *dp; 1408 Char *p, *q; 1409 struct wordent *lp = hp->Hlex.next; 1410 int argno = 0; 1411 1412 /* 1413 * The entries added by alias substitution don't have a newline but do 1414 * have a negative event number. Savehist() trims off these entries, 1415 * but it happens before alias expansion, too early to delete those 1416 * from the previous command. 1417 */ 1418 if (hp->Hnum < 0) 1419 continue; 1420 if (lp->word[0] == '\n') 1421 continue; 1422 if (!anyarg) { 1423 p = cp; 1424 q = lp->word; 1425 do 1426 if (!*p) 1427 return (hp); 1428 while (*p++ == *q++); 1429 continue; 1430 } 1431 do { 1432 for (dp = lp->word; *dp; dp++) { 1433 p = cp; 1434 q = dp; 1435 do 1436 if (!*p) { 1437 quesarg = argno; 1438 return (hp); 1439 } 1440 while (*p++ == *q++); 1441 } 1442 lp = lp->next; 1443 argno++; 1444 } while (lp->word[0] != '\n'); 1445 } 1446 seterror(ERR_NOEVENT, short2str(cp)); 1447 return (0); 1448} 1449 1450 1451static void 1452setexclp(cp) 1453 Char *cp; 1454{ 1455 if (cp && cp[0] == '\n') 1456 return; 1457 exclp = cp; 1458} 1459 1460void 1461unreadc(c) 1462 int c; 1463{ 1464 peekread = (Char) c; 1465} 1466 1467int 1468readc(wanteof) 1469 bool wanteof; 1470{ 1471 int c; 1472 static int sincereal; /* Number of real EOFs we've seen */ 1473 Char *ptr; /* For STRignoreeof */ 1474 int numeof = 0; /* Value of STRignoreeof */ 1475 1476#ifdef DEBUG_INP 1477 xprintf("readc\n"); 1478#endif 1479 if ((c = peekread) != 0) { 1480 peekread = 0; 1481 return (c); 1482 } 1483 1484 /* Compute the value of EOFs */ 1485 if ((ptr = varval(STRignoreeof)) != STRNULL) { 1486 while (*ptr) { 1487 if (!Isdigit(*ptr)) { 1488 numeof = 0; 1489 break; 1490 } 1491 numeof = numeof * 10 + *ptr++ - '0'; 1492 } 1493 } 1494 if (numeof < 1) numeof = 26; /* Sanity check */ 1495 1496top: 1497 aret = F_SEEK; 1498 if (alvecp) { 1499 arun = 1; 1500#ifdef DEBUG_INP 1501 xprintf("alvecp %c\n", *alvecp & 0xff); 1502#endif 1503 aret = A_SEEK; 1504 if ((c = *alvecp++) != 0) 1505 return (c); 1506 if (alvec && *alvec) { 1507 alvecp = *alvec++; 1508 return (' '); 1509 } 1510 else { 1511 alvecp = NULL; 1512 aret = F_SEEK; 1513 return('\n'); 1514 } 1515 } 1516 if (alvec) { 1517 arun = 1; 1518 if ((alvecp = *alvec) != 0) { 1519 alvec++; 1520 goto top; 1521 } 1522 /* Infinite source! */ 1523 return ('\n'); 1524 } 1525 arun = 0; 1526 if (evalp) { 1527 aret = E_SEEK; 1528 if ((c = *evalp++) != 0) 1529 return (c); 1530 if (evalvec && *evalvec) { 1531 evalp = *evalvec++; 1532 return (' '); 1533 } 1534 aret = F_SEEK; 1535 evalp = 0; 1536 } 1537 if (evalvec) { 1538 if (evalvec == INVPPTR) { 1539 doneinp = 1; 1540 reset(); 1541 } 1542 if ((evalp = *evalvec) != 0) { 1543 evalvec++; 1544 goto top; 1545 } 1546 evalvec = INVPPTR; 1547 return ('\n'); 1548 } 1549 do { 1550 if (arginp == INVPTR || onelflg == 1) { 1551 if (wanteof) 1552 return (-1); 1553 exitstat(); 1554 } 1555 if (arginp) { 1556 if ((c = *arginp++) == 0) { 1557 arginp = INVPTR; 1558 return ('\n'); 1559 } 1560 return (c); 1561 } 1562#ifdef BSDJOBS 1563reread: 1564#endif /* BSDJOBS */ 1565 c = bgetc(); 1566 if (c < 0) { 1567#ifndef WINNT 1568# ifndef POSIX 1569# ifdef TERMIO 1570 struct termio tty; 1571# else /* SGTTYB */ 1572 struct sgttyb tty; 1573# endif /* TERMIO */ 1574# else /* POSIX */ 1575 struct termios tty; 1576# endif /* POSIX */ 1577#endif /* !WINNT */ 1578 if (wanteof) 1579 return (-1); 1580 /* was isatty but raw with ignoreeof yields problems */ 1581#ifndef WINNT 1582# ifndef POSIX 1583# ifdef TERMIO 1584 if (ioctl(SHIN, TCGETA, (ioctl_t) & tty) == 0 && 1585 (tty.c_lflag & ICANON)) 1586# else /* GSTTYB */ 1587 if (ioctl(SHIN, TIOCGETP, (ioctl_t) & tty) == 0 && 1588 (tty.sg_flags & RAW) == 0) 1589# endif /* TERMIO */ 1590# else /* POSIX */ 1591 if (tcgetattr(SHIN, &tty) == 0 && 1592 (tty.c_lflag & ICANON)) 1593# endif /* POSIX */ 1594#else /* WINNT */ 1595 if (isatty(SHIN)) 1596#endif /* !WINNT */ 1597 { 1598 /* was 'short' for FILEC */ 1599#ifdef BSDJOBS 1600 int ctpgrp; 1601#endif /* BSDJOBS */ 1602 1603 if (++sincereal >= numeof) /* Too many EOFs? Bye! */ 1604 goto oops; 1605#ifdef BSDJOBS 1606 if (tpgrp != -1 && 1607 (ctpgrp = tcgetpgrp(FSHTTY)) != -1 && 1608 tpgrp != ctpgrp) { 1609 (void) tcsetpgrp(FSHTTY, tpgrp); 1610# ifdef _SEQUENT_ 1611 if (ctpgrp) 1612# endif /* _SEQUENT */ 1613 (void) killpg((pid_t) ctpgrp, SIGHUP); 1614# ifdef notdef 1615 /* 1616 * With the walking process group fix, this message 1617 * is now obsolete. As the foreground process group 1618 * changes, the shell needs to adjust. Well too bad. 1619 */ 1620 xprintf(CGETS(16, 1, "Reset tty pgrp from %d to %d\n"), 1621 ctpgrp, tpgrp); 1622# endif /* notdef */ 1623 goto reread; 1624 } 1625#endif /* BSDJOBS */ 1626 /* What follows is complicated EOF handling -- sterling@netcom.com */ 1627 /* First, we check to see if we have ignoreeof set */ 1628 if (adrof(STRignoreeof)) { 1629 /* If so, we check for any stopped jobs only on the first EOF */ 1630 if ((sincereal == 1) && (chkstop == 0)) { 1631 panystop(1); 1632 } 1633 } else { 1634 /* If we don't have ignoreeof set, always check for stopped jobs */ 1635 if (chkstop == 0) { 1636 panystop(1); 1637 } 1638 } 1639 /* At this point, if there were stopped jobs, we would have already 1640 * called reset(). If we got this far, assume we can print an 1641 * exit/logout message if we ignoreeof, or just exit. 1642 */ 1643 if (adrof(STRignoreeof)) { 1644 /* If so, tell the user to use exit or logout */ 1645 if (loginsh) { 1646 xprintf(CGETS(16, 2, 1647 "\nUse \"logout\" to logout.\n")); 1648 } else { 1649 xprintf(CGETS(16, 3, 1650 "\nUse \"exit\" to leave %s.\n"), 1651 progname); 1652 } 1653 reset(); 1654 } else { 1655 /* If we don't have ignoreeof set, just fall through */ 1656 ; /* EMPTY */ 1657 } 1658 } 1659 oops: 1660 doneinp = 1; 1661 reset(); 1662 } 1663 sincereal = 0; 1664 if (c == '\n' && onelflg) 1665 onelflg--; 1666 } while (c == 0); 1667 if (histlinep < histline + BUFSIZE) 1668 *histlinep++ = (Char) c; 1669 return (c); 1670} 1671 1672static void 1673balloc(buf) 1674 int buf; 1675{ 1676 Char **nfbuf; 1677 1678 while (buf >= fblocks) { 1679 nfbuf = (Char **) xcalloc((size_t) (fblocks + 2), 1680 sizeof(Char **)); 1681 if (fbuf) { 1682 (void) blkcpy(nfbuf, fbuf); 1683 xfree((ptr_t) fbuf); 1684 } 1685 fbuf = nfbuf; 1686 fbuf[fblocks] = (Char *) xcalloc(BUFSIZE, sizeof(Char)); 1687 fblocks++; 1688 } 1689} 1690 1691static int 1692bgetc() 1693{ 1694 int c, off, buf; 1695 int numleft = 0, roomleft; 1696 char tbuf[BUFSIZE + 1]; 1697 1698 if (cantell) { 1699 if (fseekp < fbobp || fseekp > feobp) { 1700 fbobp = feobp = fseekp; 1701 (void) lseek(SHIN, fseekp, L_SET); 1702 } 1703 if (fseekp == feobp) { 1704 int i; 1705 1706 fbobp = feobp; 1707 do 1708 c = read(SHIN, tbuf, BUFSIZE); 1709 while (c < 0 && errno == EINTR); 1710#ifdef convex 1711 if (c < 0) 1712 stderror(ERR_SYSTEM, progname, strerror(errno)); 1713#endif /* convex */ 1714 if (c <= 0) 1715 return (-1); 1716 for (i = 0; i < c; i++) 1717 fbuf[0][i] = (unsigned char) tbuf[i]; 1718 feobp += c; 1719 } 1720#ifndef WINNT 1721 c = fbuf[0][fseekp - fbobp]; 1722 fseekp++; 1723#else 1724 do { 1725 c = fbuf[0][fseekp - fbobp]; 1726 fseekp++; 1727 } while(c == '\r'); 1728#endif /* !WINNT */ 1729 return (c); 1730 } 1731 1732 while (fseekp >= feobp) { 1733 if (editing && intty) { /* then use twenex routine */ 1734 fseekp = feobp; /* where else? */ 1735 c = numleft = Inputl(); /* PWP: get a line */ 1736 while (numleft > 0) { 1737 off = (int) feobp % BUFSIZE; 1738 buf = (int) feobp / BUFSIZE; 1739 balloc(buf); 1740 roomleft = BUFSIZE - off; 1741 if (roomleft > numleft) 1742 roomleft = numleft; 1743 (void) memmove((ptr_t) (fbuf[buf] + off), (ptr_t) (InputBuf + c - numleft), (size_t) (roomleft * sizeof(Char))); 1744 numleft -= roomleft; 1745 feobp += roomleft; 1746 } 1747 } 1748 else { 1749 off = (int) feobp % BUFSIZE; 1750 buf = (int) feobp / BUFSIZE; 1751 balloc(buf); 1752 roomleft = BUFSIZE - off; 1753 c = read(SHIN, tbuf, (size_t) roomleft); 1754 if (c > 0) { 1755 int i; 1756 Char *ptr = fbuf[buf] + off; 1757 1758 for (i = 0; i < c; i++) 1759 ptr[i] = (unsigned char) tbuf[i]; 1760 feobp += c; 1761 } 1762 } 1763 if (c == 0 || (c < 0 && fixio(SHIN, errno) == -1)) 1764 return (-1); 1765 } 1766#ifndef WINNT 1767 c = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE]; 1768 fseekp++; 1769#else 1770 do { 1771 c = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE]; 1772 fseekp++; 1773 } while(c == '\r'); 1774#endif /* !WINNT */ 1775 return (c); 1776} 1777 1778static void 1779bfree() 1780{ 1781 int sb, i; 1782 1783 if (cantell) 1784 return; 1785 if (whyles) 1786 return; 1787 sb = (int) (fseekp - 1) / BUFSIZE; 1788 if (sb > 0) { 1789 for (i = 0; i < sb; i++) 1790 xfree((ptr_t) fbuf[i]); 1791 (void) blkcpy(fbuf, &fbuf[sb]); 1792 fseekp -= BUFSIZE * sb; 1793 feobp -= BUFSIZE * sb; 1794 fblocks -= sb; 1795 } 1796} 1797 1798void 1799bseek(l) 1800 struct Ain *l; 1801{ 1802 switch (aret = l->type) { 1803 case E_SEEK: 1804 evalvec = l->a_seek; 1805 evalp = l->c_seek; 1806#ifdef DEBUG_SEEK 1807 xprintf(CGETS(16, 4, "seek to eval %x %x\n"), evalvec, evalp); 1808#endif 1809 return; 1810 case A_SEEK: 1811 alvec = l->a_seek; 1812 alvecp = l->c_seek; 1813#ifdef DEBUG_SEEK 1814 xprintf(CGETS(16, 5, "seek to alias %x %x\n"), alvec, alvecp); 1815#endif 1816 return; 1817 case F_SEEK: 1818#ifdef DEBUG_SEEK 1819 xprintf(CGETS(16, 6, "seek to file %x\n"), fseekp); 1820#endif 1821 fseekp = l->f_seek; 1822 return; 1823 default: 1824 xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret); 1825 abort(); 1826 } 1827} 1828 1829/* any similarity to bell telephone is purely accidental */ 1830void 1831btell(l) 1832struct Ain *l; 1833{ 1834 switch (l->type = aret) { 1835 case E_SEEK: 1836 l->a_seek = evalvec; 1837 l->c_seek = evalp; 1838#ifdef DEBUG_SEEK 1839 xprintf(CGETS(16, 8, "tell eval %x %x\n"), evalvec, evalp); 1840#endif 1841 return; 1842 case A_SEEK: 1843 l->a_seek = alvec; 1844 l->c_seek = alvecp; 1845#ifdef DEBUG_SEEK 1846 xprintf(CGETS(16, 9, "tell alias %x %x\n"), alvec, alvecp); 1847#endif 1848 return; 1849 case F_SEEK: 1850 /*SUPPRESS 112*/ 1851 l->f_seek = fseekp; 1852 l->a_seek = NULL; 1853#ifdef DEBUG_SEEK 1854 xprintf(CGETS(16, 10, "tell file %x\n"), fseekp); 1855#endif 1856 return; 1857 default: 1858 xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret); 1859 abort(); 1860 } 1861} 1862 1863void 1864btoeof() 1865{ 1866 (void) lseek(SHIN, (off_t) 0, L_XTND); 1867 aret = F_SEEK; 1868 fseekp = feobp; 1869 alvec = NULL; 1870 alvecp = NULL; 1871 evalvec = NULL; 1872 evalp = NULL; 1873 wfree(); 1874 bfree(); 1875} 1876 1877void 1878settell() 1879{ 1880 off_t x; 1881 cantell = 0; 1882 if (arginp || onelflg || intty) 1883 return; 1884 if ((x = lseek(SHIN, (off_t) 0, L_INCR)) == -1) 1885 return; 1886 fbuf = (Char **) xcalloc(2, sizeof(Char **)); 1887 fblocks = 1; 1888 fbuf[0] = (Char *) xcalloc(BUFSIZE, sizeof(Char)); 1889 fseekp = fbobp = feobp = x; 1890 cantell = 1; 1891} 1892