sh.lex.c revision 59243
1147476Sdumbbell/* $Header: /src/pub/tcsh/sh.lex.c,v 3.49 1998/04/08 13:58:54 christos Exp $ */ 2147476Sdumbbell/* 3147476Sdumbbell * sh.lex.c: Lexical analysis into tokens 4147476Sdumbbell */ 5230132Suqs/*- 6147476Sdumbbell * Copyright (c) 1980, 1991 The Regents of the University of California. 7147476Sdumbbell * All rights reserved. 8147476Sdumbbell * 9147476Sdumbbell * Redistribution and use in source and binary forms, with or without 10147476Sdumbbell * modification, are permitted provided that the following conditions 11147476Sdumbbell * are met: 12147476Sdumbbell * 1. Redistributions of source code must retain the above copyright 13147476Sdumbbell * notice, this list of conditions and the following disclaimer. 14147476Sdumbbell * 2. Redistributions in binary form must reproduce the above copyright 15147476Sdumbbell * notice, this list of conditions and the following disclaimer in the 16147476Sdumbbell * documentation and/or other materials provided with the distribution. 17147476Sdumbbell * 3. All advertising materials mentioning features or use of this software 18147476Sdumbbell * must display the following acknowledgement: 19147476Sdumbbell * This product includes software developed by the University of 20147476Sdumbbell * California, Berkeley and its contributors. 21147476Sdumbbell * 4. Neither the name of the University nor the names of its contributors 22147476Sdumbbell * may be used to endorse or promote products derived from this software 23147476Sdumbbell * without specific prior written permission. 24147476Sdumbbell * 25147476Sdumbbell * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26147476Sdumbbell * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27147476Sdumbbell * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28147476Sdumbbell * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29147476Sdumbbell * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30147476Sdumbbell * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31147476Sdumbbell * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32147476Sdumbbell * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33147476Sdumbbell * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34147476Sdumbbell * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35147476Sdumbbell * SUCH DAMAGE. 36147476Sdumbbell */ 37147476Sdumbbell#include "sh.h" 38147476Sdumbbell 39147476SdumbbellRCSID("$Id: sh.lex.c,v 3.49 1998/04/08 13:58:54 christos Exp $") 40147476Sdumbbell 41147476Sdumbbell#include "ed.h" 42147476Sdumbbell/* #define DEBUG_INP */ 43147476Sdumbbell/* #define DEBUG_SEEK */ 44147476Sdumbbell 45147476Sdumbbell/* 46147476Sdumbbell * C shell 47147476Sdumbbell */ 48147476Sdumbbell 49147476Sdumbbell/* 50147476Sdumbbell * These lexical routines read input and form lists of words. 51147476Sdumbbell * There is some involved processing here, because of the complications 52147476Sdumbbell * of input buffering, and especially because of history substitution. 53147476Sdumbbell */ 54147476Sdumbbellstatic Char *word __P((void)); 55147476Sdumbbellstatic int getC1 __P((int)); 56147476Sdumbbellstatic void getdol __P((void)); 57147476Sdumbbellstatic void getexcl __P((int)); 58147476Sdumbbellstatic struct Hist *findev __P((Char *, bool)); 59147476Sdumbbellstatic void setexclp __P((Char *)); 60147476Sdumbbellstatic int bgetc __P((void)); 61147476Sdumbbellstatic void balloc __P((int)); 62147476Sdumbbellstatic void bfree __P((void)); 63147476Sdumbbellstatic struct wordent *gethent __P((int)); 64147476Sdumbbellstatic int matchs __P((Char *, Char *)); 65147476Sdumbbellstatic int getsel __P((int *, int *, int)); 66147476Sdumbbellstatic struct wordent *getsub __P((struct wordent *)); 67147476Sdumbbellstatic Char *subword __P((Char *, int, bool *)); 68147476Sdumbbellstatic struct wordent *dosub __P((int, struct wordent *, bool)); 69147476Sdumbbell 70147476Sdumbbell/* 71147476Sdumbbell * Peekc is a peek character for getC, peekread for readc. 72147476Sdumbbell * There is a subtlety here in many places... history routines 73147476Sdumbbell * will read ahead and then insert stuff into the input stream. 74147476Sdumbbell * If they push back a character then they must push it behind 75147476Sdumbbell * the text substituted by the history substitution. On the other 76147476Sdumbbell * hand in several places we need 2 peek characters. To make this 77147476Sdumbbell * all work, the history routines read with getC, and make use both 78147476Sdumbbell * of ungetC and unreadc. The key observation is that the state 79147476Sdumbbell * of getC at the call of a history reference is such that calls 80147476Sdumbbell * to getC from the history routines will always yield calls of 81147476Sdumbbell * readc, unless this peeking is involved. That is to say that during 82147476Sdumbbell * getexcl the variables lap, exclp, and exclnxt are all zero. 83147476Sdumbbell * 84147476Sdumbbell * Getdol invokes history substitution, hence the extra peek, peekd, 85147476Sdumbbell * which it can ungetD to be before history substitutions. 86147476Sdumbbell */ 87147476Sdumbbellstatic Char peekc = 0, peekd = 0; 88147476Sdumbbellstatic Char peekread = 0; 89147476Sdumbbell 90147476Sdumbbell/* (Tail of) current word from ! subst */ 91147476Sdumbbellstatic Char *exclp = NULL; 92147476Sdumbbell 93147476Sdumbbell/* The rest of the ! subst words */ 94147476Sdumbbellstatic struct wordent *exclnxt = NULL; 95147476Sdumbbell 96147476Sdumbbell/* Count of remaining words in ! subst */ 97147476Sdumbbellstatic int exclc = 0; 98147476Sdumbbell 99147476Sdumbbell/* "Globp" for alias resubstitution */ 100147476Sdumbbellint aret = F_SEEK; 101147476Sdumbbell 102147476Sdumbbell/* 103147476Sdumbbell * Labuf implements a general buffer for lookahead during lexical operations. 104147476Sdumbbell * Text which is to be placed in the input stream can be stuck here. 105147476Sdumbbell * We stick parsed ahead $ constructs during initial input, 106147476Sdumbbell * process id's from `$$', and modified variable values (from qualifiers 107147476Sdumbbell * during expansion in sh.dol.c) here. 108147476Sdumbbell */ 109147476Sdumbbellstatic Char labuf[BUFSIZE]; 110147476Sdumbbell 111147476Sdumbbell/* 112147476Sdumbbell * Lex returns to its caller not only a wordlist (as a "var" parameter) 113147476Sdumbbell * but also whether a history substitution occurred. This is used in 114147476Sdumbbell * the main (process) routine to determine whether to echo, and also 115147476Sdumbbell * when called by the alias routine to determine whether to keep the 116147476Sdumbbell * argument list. 117147476Sdumbbell */ 118147476Sdumbbellstatic bool hadhist = 0; 119147476Sdumbbell 120147476Sdumbbell/* 121147476Sdumbbell * Avoid alias expansion recursion via \!# 122147476Sdumbbell */ 123147476Sdumbbellint hleft; 124147476Sdumbbell 125147476SdumbbellChar histline[BUFSIZE + 2]; /* last line input */ 126147476Sdumbbell 127147476Sdumbbell /* The +2 is to fool hp's optimizer */ 128147476Sdumbbellbool histvalid = 0; /* is histline valid */ 129147476Sdumbbellstatic Char *histlinep = NULL; /* current pointer into histline */ 130147476Sdumbbell 131147476Sdumbbellstatic Char getCtmp; 132147476Sdumbbell 133147476Sdumbbell#define getC(f) (((getCtmp = peekc) != '\0') ? (peekc = 0, getCtmp) : getC1(f)) 134147476Sdumbbell#define ungetC(c) peekc = (Char) c 135147476Sdumbbell#define ungetD(c) peekd = (Char) c 136147476Sdumbbell 137147476Sdumbbell/* Use Htime to store timestamps picked up from history file for enthist() 138147476Sdumbbell * if reading saved history (sg) 139147476Sdumbbell */ 140147476Sdumbbelltime_t Htime = (time_t)0; 141147476Sdumbbellstatic time_t a2time_t __P((Char *)); 142147476Sdumbbell 143147476Sdumbbell/* 144147476Sdumbbell * for history event processing 145147476Sdumbbell * in the command 'echo !?foo?:1 !$' we want the !$ to expand from the line 146147476Sdumbbell * 'foo' was found instead of the last command 147147476Sdumbbell */ 148147476Sdumbbellstatic int uselastevent = 1; 149147476Sdumbbell 150147476Sdumbbellint 151147476Sdumbbelllex(hp) 152147476Sdumbbell struct wordent *hp; 153147476Sdumbbell{ 154147476Sdumbbell struct wordent *wdp; 155147476Sdumbbell int c; 156147476Sdumbbell 157147476Sdumbbell 158147476Sdumbbell uselastevent = 1; 159147476Sdumbbell histvalid = 0; 160147476Sdumbbell histlinep = histline; 161147476Sdumbbell *histlinep = '\0'; 162147476Sdumbbell 163147476Sdumbbell btell(&lineloc); 164147476Sdumbbell hp->next = hp->prev = hp; 165147476Sdumbbell hp->word = STRNULL; 166147476Sdumbbell hadhist = 0; 167147476Sdumbbell do 168147476Sdumbbell c = readc(0); 169147476Sdumbbell while (c == ' ' || c == '\t'); 170147476Sdumbbell if (c == HISTSUB && intty) 171147476Sdumbbell /* ^lef^rit from tty is short !:s^lef^rit */ 172147476Sdumbbell getexcl(c); 173147476Sdumbbell else 174147476Sdumbbell unreadc(c); 175147476Sdumbbell wdp = hp; 176147476Sdumbbell /* 177147476Sdumbbell * The following loop is written so that the links needed by freelex will 178147476Sdumbbell * be ready and rarin to go even if it is interrupted. 179147476Sdumbbell */ 180147476Sdumbbell do { 181147476Sdumbbell struct wordent *new; 182147476Sdumbbell 183147476Sdumbbell new = (struct wordent *) xmalloc((size_t) sizeof(*wdp)); 184147476Sdumbbell new->word = STRNULL; 185147476Sdumbbell new->prev = wdp; 186147476Sdumbbell new->next = hp; 187147476Sdumbbell wdp->next = new; 188147476Sdumbbell hp->prev = new; 189147476Sdumbbell wdp = new; 190147476Sdumbbell wdp->word = word(); 191147476Sdumbbell } while (wdp->word[0] != '\n'); 192147476Sdumbbell if (histlinep < histline + BUFSIZE) { 193147476Sdumbbell *histlinep = '\0'; 194147476Sdumbbell if (histlinep > histline && histlinep[-1] == '\n') 195147476Sdumbbell histlinep[-1] = '\0'; 196147476Sdumbbell histvalid = 1; 197147476Sdumbbell } 198147476Sdumbbell else { 199147476Sdumbbell histline[BUFSIZE - 1] = '\0'; 200147476Sdumbbell } 201147476Sdumbbell 202147476Sdumbbell return (hadhist); 203147476Sdumbbell} 204147476Sdumbbell 205147476Sdumbbellstatic time_t 206147476Sdumbbella2time_t(word) 207147476Sdumbbell Char *word; 208147476Sdumbbell{ 209147476Sdumbbell /* Attempt to distinguish timestamps from other possible entries. 210147476Sdumbbell * Format: "+NNNNNNNNNN" (10 digits, left padded with ascii '0') */ 211147476Sdumbbell 212147476Sdumbbell time_t ret; 213147476Sdumbbell Char *s; 214147476Sdumbbell int ct; 215147476Sdumbbell 216147476Sdumbbell if (!word || *(s = word) != '+') 217147476Sdumbbell return (time_t)0; 218 219 for (++s, ret = 0, ct = 0; *s; ++s, ++ct) 220 { 221 if (!isdigit((unsigned char)*s)) 222 return (time_t)0; 223 ret = ret * 10 + (time_t)((unsigned char)*s - '0'); 224 } 225 226 if (ct != 10) 227 return (time_t)0; 228 229 return ret; 230} 231 232void 233prlex(sp0) 234 struct wordent *sp0; 235{ 236 struct wordent *sp = sp0->next; 237 238 for (;;) { 239 xprintf("%S", sp->word); 240 sp = sp->next; 241 if (sp == sp0) 242 break; 243 if (sp->word[0] != '\n') 244 xputchar(' '); 245 } 246} 247 248void 249copylex(hp, fp) 250 struct wordent *hp; 251 struct wordent *fp; 252{ 253 struct wordent *wdp; 254 255 wdp = hp; 256 fp = fp->next; 257 do { 258 struct wordent *new; 259 260 new = (struct wordent *) xmalloc((size_t) sizeof(*wdp)); 261 new->word = STRNULL; 262 new->prev = wdp; 263 new->next = hp; 264 wdp->next = new; 265 hp->prev = new; 266 wdp = new; 267 wdp->word = Strsave(fp->word); 268 fp = fp->next; 269 } while (wdp->word[0] != '\n'); 270} 271 272void 273freelex(vp) 274 struct wordent *vp; 275{ 276 struct wordent *fp; 277 278 while (vp->next != vp) { 279 fp = vp->next; 280 vp->next = fp->next; 281 if (fp->word != STRNULL) 282 xfree((ptr_t) fp->word); 283 xfree((ptr_t) fp); 284 } 285 vp->prev = vp; 286} 287 288static Char * 289word() 290{ 291 Char c, c1; 292 Char *wp; 293 Char wbuf[BUFSIZE]; 294 Char hbuf[12]; 295 int h; 296 bool dolflg; 297 int i; 298 299 wp = wbuf; 300 i = BUFSIZE - 4; 301loop: 302 while ((c = getC(DOALL)) == ' ' || c == '\t') 303 continue; 304 if (cmap(c, _META | _ESC)) 305 switch (c) { 306 case '&': 307 case '|': 308 case '<': 309 case '>': 310 *wp++ = c; 311 c1 = getC(DOALL); 312 if (c1 == c) 313 *wp++ = c1; 314 else 315 ungetC(c1); 316 goto ret; 317 318 case '#': 319 if (intty) 320 break; 321 c = 0; 322 h = 0; 323 do { 324 c1 = c; 325 c = getC(0); 326 if (h < 12) 327 hbuf[h++] = c; 328 } while (c != '\n'); 329 hbuf[11] = '\0'; 330 Htime = a2time_t(hbuf); 331 if (c1 == '\\') 332 goto loop; 333 /*FALLTHROUGH*/ 334 335 case ';': 336 case '(': 337 case ')': 338 case '\n': 339 *wp++ = c; 340 goto ret; 341 342 case '\\': 343 c = getC(0); 344 if (c == '\n') { 345 if (onelflg == 1) 346 onelflg = 2; 347 goto loop; 348 } 349 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