1232633Smp/* $Header: /p/tcsh/cvsroot/tcsh/sh.lex.c,v 3.87 2011/01/24 17:48:15 christos Exp $ */ 259243Sobrien/* 359243Sobrien * sh.lex.c: Lexical analysis into tokens 459243Sobrien */ 559243Sobrien/*- 659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 759243Sobrien * All rights reserved. 859243Sobrien * 959243Sobrien * Redistribution and use in source and binary forms, with or without 1059243Sobrien * modification, are permitted provided that the following conditions 1159243Sobrien * are met: 1259243Sobrien * 1. Redistributions of source code must retain the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer. 1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1559243Sobrien * notice, this list of conditions and the following disclaimer in the 1659243Sobrien * documentation and/or other materials provided with the distribution. 17100616Smp * 3. Neither the name of the University nor the names of its contributors 1859243Sobrien * may be used to endorse or promote products derived from this software 1959243Sobrien * without specific prior written permission. 2059243Sobrien * 2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2459243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3159243Sobrien * SUCH DAMAGE. 3259243Sobrien */ 3359243Sobrien#include "sh.h" 3459243Sobrien 35232633SmpRCSID("$tcsh: sh.lex.c,v 3.87 2011/01/24 17:48:15 christos Exp $") 3659243Sobrien 3759243Sobrien#include "ed.h" 38145479Smp 39145479Smp#include <assert.h> 4059243Sobrien/* #define DEBUG_INP */ 4159243Sobrien/* #define DEBUG_SEEK */ 4259243Sobrien 4359243Sobrien/* 4459243Sobrien * C shell 4559243Sobrien */ 4659243Sobrien 47167465Smp#define FLAG_G 1 48167465Smp#define FLAG_A 2 4959243Sobrien/* 5059243Sobrien * These lexical routines read input and form lists of words. 5159243Sobrien * There is some involved processing here, because of the complications 5259243Sobrien * of input buffering, and especially because of history substitution. 5359243Sobrien */ 54167465Smpstatic Char *word (int); 55167465Smpstatic eChar getC1 (int); 56167465Smpstatic void getdol (void); 57167465Smpstatic void getexcl (Char); 58167465Smpstatic struct Hist *findev (Char *, int); 59167465Smpstatic void setexclp (Char *); 60167465Smpstatic eChar bgetc (void); 61167465Smpstatic void balloc (int); 62167465Smpstatic void bfree (void); 63167465Smpstatic struct wordent *gethent (Char); 64167465Smpstatic int matchs (const Char *, const Char *); 65167465Smpstatic int getsel (int *, int *, int); 66167465Smpstatic struct wordent *getsub (struct wordent *); 67167465Smpstatic Char *subword (Char *, Char, int *, size_t *); 68167465Smpstatic struct wordent *dosub (Char, struct wordent *, int); 69167465Smpstatic ssize_t wide_read (int, Char *, size_t, int); 7059243Sobrien 7159243Sobrien/* 7259243Sobrien * Peekc is a peek character for getC, peekread for readc. 7359243Sobrien * There is a subtlety here in many places... history routines 7459243Sobrien * will read ahead and then insert stuff into the input stream. 7559243Sobrien * If they push back a character then they must push it behind 7659243Sobrien * the text substituted by the history substitution. On the other 7759243Sobrien * hand in several places we need 2 peek characters. To make this 7859243Sobrien * all work, the history routines read with getC, and make use both 7959243Sobrien * of ungetC and unreadc. The key observation is that the state 8059243Sobrien * of getC at the call of a history reference is such that calls 8159243Sobrien * to getC from the history routines will always yield calls of 8259243Sobrien * readc, unless this peeking is involved. That is to say that during 8359243Sobrien * getexcl the variables lap, exclp, and exclnxt are all zero. 8459243Sobrien * 8559243Sobrien * Getdol invokes history substitution, hence the extra peek, peekd, 8659243Sobrien * which it can ungetD to be before history substitutions. 8759243Sobrien */ 8859243Sobrienstatic Char peekc = 0, peekd = 0; 8959243Sobrienstatic Char peekread = 0; 9059243Sobrien 9159243Sobrien/* (Tail of) current word from ! subst */ 9259243Sobrienstatic Char *exclp = NULL; 9359243Sobrien 9459243Sobrien/* The rest of the ! subst words */ 9559243Sobrienstatic struct wordent *exclnxt = NULL; 9659243Sobrien 9759243Sobrien/* Count of remaining words in ! subst */ 9859243Sobrienstatic int exclc = 0; 9959243Sobrien 10059243Sobrien/* "Globp" for alias resubstitution */ 10169408Sacheint aret = TCSH_F_SEEK; 10259243Sobrien 10359243Sobrien/* 10459243Sobrien * Labuf implements a general buffer for lookahead during lexical operations. 10559243Sobrien * Text which is to be placed in the input stream can be stuck here. 10659243Sobrien * We stick parsed ahead $ constructs during initial input, 10759243Sobrien * process id's from `$$', and modified variable values (from qualifiers 10859243Sobrien * during expansion in sh.dol.c) here. 10959243Sobrien */ 110167465Smpstruct Strbuf labuf; /* = Strbuf_INIT; */ 11159243Sobrien 11259243Sobrien/* 11359243Sobrien * Lex returns to its caller not only a wordlist (as a "var" parameter) 11459243Sobrien * but also whether a history substitution occurred. This is used in 11559243Sobrien * the main (process) routine to determine whether to echo, and also 11659243Sobrien * when called by the alias routine to determine whether to keep the 11759243Sobrien * argument list. 11859243Sobrien */ 119145479Smpstatic int hadhist = 0; 12059243Sobrien 12159243Sobrien/* 12259243Sobrien * Avoid alias expansion recursion via \!# 12359243Sobrien */ 12459243Sobrienint hleft; 12559243Sobrien 126167465Smpstruct Strbuf histline; /* = Strbuf_INIT; last line input */ 12759243Sobrien 128145479Smpint histvalid = 0; /* is histline valid */ 12959243Sobrien 13059243Sobrienstatic Char getCtmp; 13159243Sobrien 132145479Smp#define getC(f) (((getCtmp = peekc) != '\0') ? (peekc = 0, (eChar)getCtmp) : getC1(f)) 13359243Sobrien#define ungetC(c) peekc = (Char) c 13459243Sobrien#define ungetD(c) peekd = (Char) c 13559243Sobrien 13659243Sobrien/* Use Htime to store timestamps picked up from history file for enthist() 13759243Sobrien * if reading saved history (sg) 13859243Sobrien */ 13959243Sobrientime_t Htime = (time_t)0; 140167465Smpstatic time_t a2time_t (Char *); 14159243Sobrien 14259243Sobrien/* 143145479Smp * special parsing rules apply for source -h 144145479Smp */ 145145479Smpextern int enterhist; 146145479Smp 14759243Sobrienint 148167465Smplex(struct wordent *hp) 14959243Sobrien{ 15059243Sobrien struct wordent *wdp; 151145479Smp eChar c; 152145479Smp int parsehtime = enterhist; 15359243Sobrien 15459243Sobrien histvalid = 0; 155167465Smp histline.len = 0; 15659243Sobrien 15759243Sobrien btell(&lineloc); 15859243Sobrien hp->next = hp->prev = hp; 15959243Sobrien hp->word = STRNULL; 16059243Sobrien hadhist = 0; 16159243Sobrien do 16259243Sobrien c = readc(0); 16359243Sobrien while (c == ' ' || c == '\t'); 164145479Smp if (c == (eChar)HISTSUB && intty) 16559243Sobrien /* ^lef^rit from tty is short !:s^lef^rit */ 16659243Sobrien getexcl(c); 16759243Sobrien else 16859243Sobrien unreadc(c); 169167465Smp cleanup_push(hp, lex_cleanup); 17059243Sobrien wdp = hp; 17159243Sobrien /* 17259243Sobrien * The following loop is written so that the links needed by freelex will 17359243Sobrien * be ready and rarin to go even if it is interrupted. 17459243Sobrien */ 17559243Sobrien do { 17659243Sobrien struct wordent *new; 17759243Sobrien 178167465Smp new = xmalloc(sizeof(*new)); 179167465Smp new->word = NULL; 18059243Sobrien new->prev = wdp; 18159243Sobrien new->next = hp; 18259243Sobrien wdp->next = new; 18359243Sobrien hp->prev = new; 18459243Sobrien wdp = new; 185145479Smp wdp->word = word(parsehtime); 186145479Smp parsehtime = 0; 18759243Sobrien } while (wdp->word[0] != '\n'); 188167465Smp cleanup_ignore(hp); 189167465Smp cleanup_until(hp); 190167465Smp Strbuf_terminate(&histline); 191167465Smp if (histline.len != 0 && histline.s[histline.len - 1] == '\n') 192167465Smp histline.s[histline.len - 1] = '\0'; 193167465Smp histvalid = 1; 19459243Sobrien 19559243Sobrien return (hadhist); 19659243Sobrien} 19759243Sobrien 19859243Sobrienstatic time_t 199167465Smpa2time_t(Char *wordx) 20059243Sobrien{ 20159243Sobrien /* Attempt to distinguish timestamps from other possible entries. 20259243Sobrien * Format: "+NNNNNNNNNN" (10 digits, left padded with ascii '0') */ 20359243Sobrien 20459243Sobrien time_t ret; 20559243Sobrien Char *s; 20659243Sobrien int ct; 20759243Sobrien 208145479Smp if (!wordx || *(s = wordx) != '+') 20959243Sobrien return (time_t)0; 21059243Sobrien 211167465Smp for (++s, ret = 0, ct = 0; *s; ++s, ++ct) { 21259243Sobrien if (!isdigit((unsigned char)*s)) 21359243Sobrien return (time_t)0; 21459243Sobrien ret = ret * 10 + (time_t)((unsigned char)*s - '0'); 21559243Sobrien } 21659243Sobrien 21759243Sobrien if (ct != 10) 21859243Sobrien return (time_t)0; 21959243Sobrien 22059243Sobrien return ret; 22159243Sobrien} 22259243Sobrien 22359243Sobrienvoid 224167465Smpprlex(struct wordent *sp0) 22559243Sobrien{ 22659243Sobrien struct wordent *sp = sp0->next; 22759243Sobrien 22859243Sobrien for (;;) { 22959243Sobrien xprintf("%S", sp->word); 23059243Sobrien sp = sp->next; 23159243Sobrien if (sp == sp0) 23259243Sobrien break; 23359243Sobrien if (sp->word[0] != '\n') 23459243Sobrien xputchar(' '); 23559243Sobrien } 23659243Sobrien} 23759243Sobrien 23859243Sobrienvoid 239167465Smpcopylex(struct wordent *hp, struct wordent *fp) 24059243Sobrien{ 24159243Sobrien struct wordent *wdp; 24259243Sobrien 24359243Sobrien wdp = hp; 24459243Sobrien fp = fp->next; 24559243Sobrien do { 24659243Sobrien struct wordent *new; 247167465Smp 248167465Smp new = xmalloc(sizeof(*new)); 249167465Smp new->word = NULL; 25059243Sobrien new->prev = wdp; 25159243Sobrien new->next = hp; 25259243Sobrien wdp->next = new; 25359243Sobrien hp->prev = new; 25459243Sobrien wdp = new; 25559243Sobrien wdp->word = Strsave(fp->word); 25659243Sobrien fp = fp->next; 25759243Sobrien } while (wdp->word[0] != '\n'); 25859243Sobrien} 25959243Sobrien 26059243Sobrienvoid 261167465Smpfreelex(struct wordent *vp) 26259243Sobrien{ 26359243Sobrien struct wordent *fp; 26459243Sobrien 26559243Sobrien while (vp->next != vp) { 26659243Sobrien fp = vp->next; 26759243Sobrien vp->next = fp->next; 268167465Smp xfree(fp->word); 269167465Smp xfree(fp); 27059243Sobrien } 27159243Sobrien vp->prev = vp; 27259243Sobrien} 27359243Sobrien 274167465Smpvoid 275167465Smplex_cleanup(void *xvp) 276167465Smp{ 277167465Smp struct wordent *vp; 278167465Smp 279167465Smp vp = xvp; 280167465Smp freelex(vp); 281167465Smp} 282167465Smp 28359243Sobrienstatic Char * 284167465Smpword(int parsehtime) 28559243Sobrien{ 286145479Smp eChar c, c1; 287167465Smp struct Strbuf wbuf = Strbuf_INIT; 28859243Sobrien Char hbuf[12]; 28959243Sobrien int h; 290145479Smp int dolflg; 29159243Sobrien 292167465Smp cleanup_push(&wbuf, Strbuf_cleanup); 29359243Sobrienloop: 29459243Sobrien while ((c = getC(DOALL)) == ' ' || c == '\t') 29559243Sobrien continue; 29659243Sobrien if (cmap(c, _META | _ESC)) 29759243Sobrien switch (c) { 29859243Sobrien case '&': 29959243Sobrien case '|': 30059243Sobrien case '<': 30159243Sobrien case '>': 302167465Smp Strbuf_append1(&wbuf, c); 30359243Sobrien c1 = getC(DOALL); 30459243Sobrien if (c1 == c) 305167465Smp Strbuf_append1(&wbuf, c1); 30659243Sobrien else 30759243Sobrien ungetC(c1); 30859243Sobrien goto ret; 30959243Sobrien 31059243Sobrien case '#': 311145479Smp if (intty || (enterhist && !parsehtime)) 31259243Sobrien break; 31359243Sobrien c = 0; 31459243Sobrien h = 0; 31559243Sobrien do { 31659243Sobrien c1 = c; 31759243Sobrien c = getC(0); 318145479Smp if (h < 11 && parsehtime) 31959243Sobrien hbuf[h++] = c; 32059243Sobrien } while (c != '\n'); 321145479Smp if (parsehtime) { 322145479Smp hbuf[11] = '\0'; 323145479Smp Htime = a2time_t(hbuf); 324145479Smp } 32559243Sobrien if (c1 == '\\') 32659243Sobrien goto loop; 32759243Sobrien /*FALLTHROUGH*/ 32859243Sobrien 32959243Sobrien case ';': 33059243Sobrien case '(': 33159243Sobrien case ')': 33259243Sobrien case '\n': 333167465Smp Strbuf_append1(&wbuf, c); 33459243Sobrien goto ret; 33559243Sobrien 33659243Sobrien case '\\': 33759243Sobrien c = getC(0); 33859243Sobrien if (c == '\n') { 33959243Sobrien if (onelflg == 1) 34059243Sobrien onelflg = 2; 34159243Sobrien goto loop; 34259243Sobrien } 343145479Smp if (c != (eChar)HIST) 344167465Smp Strbuf_append1(&wbuf, '\\'); 34559243Sobrien c |= QUOTE; 34659243Sobrien default: 34759243Sobrien break; 34859243Sobrien } 34959243Sobrien c1 = 0; 35059243Sobrien dolflg = DOALL; 35159243Sobrien for (;;) { 35259243Sobrien if (c1) { 35359243Sobrien if (c == c1) { 35459243Sobrien c1 = 0; 35559243Sobrien dolflg = DOALL; 35659243Sobrien } 35759243Sobrien else if (c == '\\') { 35859243Sobrien c = getC(0); 35959243Sobrien/* 36059243Sobrien * PWP: this is dumb, but how all of the other shells work. If \ quotes 36159243Sobrien * a character OUTSIDE of a set of ''s, why shouldn't it quote EVERY 36259243Sobrien * following character INSIDE a set of ''s. 36359243Sobrien * 36459243Sobrien * Actually, all I really want to be able to say is 'foo\'bar' --> foo'bar 36559243Sobrien */ 366145479Smp if (c == (eChar)HIST) 36759243Sobrien c |= QUOTE; 36859243Sobrien else { 36959243Sobrien if (bslash_quote && 37059243Sobrien ((c == '\'') || (c == '"') || 371195609Smp (c == '\\') || (c == '$'))) { 37259243Sobrien c |= QUOTE; 37359243Sobrien } 37459243Sobrien else { 37559243Sobrien if (c == '\n') 37659243Sobrien /* 37759243Sobrien * if (c1 == '`') c = ' '; else 37859243Sobrien */ 37959243Sobrien c |= QUOTE; 38059243Sobrien ungetC(c); 38159243Sobrien c = '\\'; 38259243Sobrien } 38359243Sobrien } 38459243Sobrien } 38559243Sobrien else if (c == '\n') { 38659243Sobrien seterror(ERR_UNMATCHED, c1); 38759243Sobrien ungetC(c); 38859243Sobrien break; 38959243Sobrien } 39059243Sobrien } 39159243Sobrien else if (cmap(c, _META | _QF | _QB | _ESC)) { 39259243Sobrien if (c == '\\') { 39359243Sobrien c = getC(0); 39459243Sobrien if (c == '\n') { 39559243Sobrien if (onelflg == 1) 39659243Sobrien onelflg = 2; 39759243Sobrien break; 39859243Sobrien } 399145479Smp if (c != (eChar)HIST) 400167465Smp Strbuf_append1(&wbuf, '\\'); 40159243Sobrien c |= QUOTE; 40259243Sobrien } 40359243Sobrien else if (cmap(c, _QF | _QB)) { /* '"` */ 40459243Sobrien c1 = c; 40559243Sobrien dolflg = c == '"' ? DOALL : DOEXCL; 40659243Sobrien } 407145479Smp else if (c != '#' || (!intty && !enterhist)) { 40859243Sobrien ungetC(c); 40959243Sobrien break; 41059243Sobrien } 41159243Sobrien } 412167465Smp Strbuf_append1(&wbuf, c); 413167465Smp c = getC(dolflg); 41459243Sobrien } 41559243Sobrienret: 416167465Smp cleanup_ignore(&wbuf); 417167465Smp cleanup_until(&wbuf); 418167465Smp return Strbuf_finish(&wbuf); 41959243Sobrien} 42059243Sobrien 421145479Smpstatic eChar 422167465SmpgetC1(int flag) 42359243Sobrien{ 424145479Smp eChar c; 42559243Sobrien 42659243Sobrien for (;;) { 42759243Sobrien if ((c = peekc) != 0) { 42859243Sobrien peekc = 0; 42959243Sobrien return (c); 43059243Sobrien } 431167465Smp if (lap < labuf.len) { 432167465Smp c = labuf.s[lap++]; 433167465Smp if (cmap(c, _META | _QF | _QB)) 434167465Smp c |= QUOTE; 435167465Smp return (c); 43659243Sobrien } 43759243Sobrien if ((c = peekd) != 0) { 43859243Sobrien peekd = 0; 43959243Sobrien return (c); 44059243Sobrien } 44159243Sobrien if (exclp) { 44259243Sobrien if ((c = *exclp++) != 0) 44359243Sobrien return (c); 44459243Sobrien if (exclnxt && --exclc >= 0) { 44559243Sobrien exclnxt = exclnxt->next; 44659243Sobrien setexclp(exclnxt->word); 44759243Sobrien return (' '); 44859243Sobrien } 44959243Sobrien exclp = 0; 45059243Sobrien exclnxt = 0; 45159243Sobrien /* this will throw away the dummy history entries */ 45259243Sobrien savehist(NULL, 0); 45359243Sobrien 45459243Sobrien } 45559243Sobrien if (exclnxt) { 45659243Sobrien exclnxt = exclnxt->next; 45759243Sobrien if (--exclc < 0) 45859243Sobrien exclnxt = 0; 45959243Sobrien else 46059243Sobrien setexclp(exclnxt->word); 46159243Sobrien continue; 46259243Sobrien } 463232633Smp c = readc(1); 464232633Smp 465232633Smp /* Catch EOF in the middle of a line. (An EOF at the beginning of 466232633Smp * a line would have been processed by the readc(0) in lex().) */ 467232633Smp if (c == CHAR_ERR) 468232633Smp c = '\n'; 469232633Smp 47059243Sobrien if (c == '$' && (flag & DODOL)) { 47159243Sobrien getdol(); 47259243Sobrien continue; 47359243Sobrien } 474145479Smp if (c == (eChar)HIST && (flag & DOEXCL)) { 47559243Sobrien getexcl(0); 47659243Sobrien continue; 47759243Sobrien } 47859243Sobrien break; 47959243Sobrien } 48059243Sobrien return (c); 48159243Sobrien} 48259243Sobrien 48359243Sobrienstatic void 484167465Smpgetdol(void) 48559243Sobrien{ 486167465Smp struct Strbuf name = Strbuf_INIT; 487145479Smp eChar c; 488145479Smp eChar sc; 489167465Smp int special = 0; 49059243Sobrien 49159243Sobrien c = sc = getC(DOEXCL); 49259243Sobrien if (any("\t \n", c)) { 49359243Sobrien ungetD(c); 49459243Sobrien ungetC('$' | QUOTE); 49559243Sobrien return; 49659243Sobrien } 497167465Smp cleanup_push(&name, Strbuf_cleanup); 498167465Smp Strbuf_append1(&name, '$'); 49959243Sobrien if (c == '{') 500167465Smp Strbuf_append1(&name, c), c = getC(DOEXCL); 50159243Sobrien if (c == '#' || c == '?' || c == '%') 502167465Smp special++, Strbuf_append1(&name, c), c = getC(DOEXCL); 503167465Smp Strbuf_append1(&name, c); 50459243Sobrien switch (c) { 50559243Sobrien 50659243Sobrien case '<': 50759243Sobrien case '$': 50859243Sobrien case '!': 50959243Sobrien if (special) 51059243Sobrien seterror(ERR_SPDOLLT); 511167465Smp goto end; 51259243Sobrien 51359243Sobrien case '\n': 51459243Sobrien ungetD(c); 515167465Smp name.len--; 51659243Sobrien if (!special) 51759243Sobrien seterror(ERR_NEWLINE); 518167465Smp goto end; 51959243Sobrien 52059243Sobrien case '*': 52159243Sobrien if (special) 52259243Sobrien seterror(ERR_SPSTAR); 523167465Smp goto end; 52459243Sobrien 52559243Sobrien default: 52659243Sobrien if (Isdigit(c)) { 52759243Sobrien#ifdef notdef 52859243Sobrien /* let $?0 pass for now */ 52959243Sobrien if (special) { 53059243Sobrien seterror(ERR_DIGIT); 531167465Smp goto end; 53259243Sobrien } 53359243Sobrien#endif 53459243Sobrien while ((c = getC(DOEXCL)) != 0) { 53559243Sobrien if (!Isdigit(c)) 53659243Sobrien break; 537167465Smp Strbuf_append1(&name, c); 53859243Sobrien } 53959243Sobrien } 54059243Sobrien else if (letter(c)) { 54159243Sobrien while ((c = getC(DOEXCL)) != 0) { 54259243Sobrien /* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */ 54359243Sobrien if (!letter(c) && !Isdigit(c)) 54459243Sobrien break; 545167465Smp Strbuf_append1(&name, c); 54659243Sobrien } 54759243Sobrien } 54859243Sobrien else { 54959243Sobrien if (!special) 55059243Sobrien seterror(ERR_VARILL); 55159243Sobrien else { 55259243Sobrien ungetD(c); 553167465Smp name.len--; 55459243Sobrien } 555167465Smp goto end; 55659243Sobrien } 55759243Sobrien break; 55859243Sobrien } 55959243Sobrien if (c == '[') { 560167465Smp Strbuf_append1(&name, c); 56159243Sobrien do { 56259243Sobrien /* 56359243Sobrien * Michael Greim: Allow $ expansion to take place in selector 56459243Sobrien * expressions. (limits the number of characters returned) 56559243Sobrien */ 56659243Sobrien c = getC(DOEXCL | DODOL); 56759243Sobrien if (c == '\n') { 56859243Sobrien ungetD(c); 569167465Smp name.len--; 57059243Sobrien seterror(ERR_NLINDEX); 571167465Smp goto end; 57259243Sobrien } 573167465Smp Strbuf_append1(&name, c); 57459243Sobrien } while (c != ']'); 57559243Sobrien c = getC(DOEXCL); 57659243Sobrien } 57759243Sobrien if (c == ':') { 57859243Sobrien /* 57959243Sobrien * if the :g modifier is followed by a newline, then error right away! 58059243Sobrien * -strike 58159243Sobrien */ 58259243Sobrien 58359243Sobrien int gmodflag = 0, amodflag = 0; 58459243Sobrien 58559243Sobrien do { 586167465Smp Strbuf_append1(&name, c), c = getC(DOEXCL); 58759243Sobrien if (c == 'g' || c == 'a') { 58859243Sobrien if (c == 'g') 58959243Sobrien gmodflag++; 59059243Sobrien else 59159243Sobrien amodflag++; 592167465Smp Strbuf_append1(&name, c); c = getC(DOEXCL); 59359243Sobrien } 59459243Sobrien if ((c == 'g' && !gmodflag) || (c == 'a' && !amodflag)) { 59559243Sobrien if (c == 'g') 59659243Sobrien gmodflag++; 59759243Sobrien else 59859243Sobrien amodflag++; 599167465Smp Strbuf_append1(&name, c); c = getC(DOEXCL); 60059243Sobrien } 601167465Smp Strbuf_append1(&name, c); 60259243Sobrien /* scan s// [eichin:19910926.0512EST] */ 60359243Sobrien if (c == 's') { 60459243Sobrien int delimcnt = 2; 605145479Smp eChar delim = getC(0); 606167465Smp 607167465Smp Strbuf_append1(&name, delim); 60859243Sobrien if (!delim || letter(delim) 60959243Sobrien || Isdigit(delim) || any(" \t\n", delim)) { 61059243Sobrien seterror(ERR_BADSUBST); 61159243Sobrien break; 612167465Smp } 613145479Smp while ((c = getC(0)) != CHAR_ERR) { 614167465Smp Strbuf_append1(&name, c); 61559243Sobrien if(c == delim) delimcnt--; 61659243Sobrien if(!delimcnt) break; 61759243Sobrien } 61859243Sobrien if(delimcnt) { 61959243Sobrien seterror(ERR_BADSUBST); 62059243Sobrien break; 62159243Sobrien } 62259243Sobrien c = 's'; 62359243Sobrien } 62459243Sobrien if (!any("htrqxesul", c)) { 62559243Sobrien if ((amodflag || gmodflag) && c == '\n') 62659243Sobrien stderror(ERR_VARSYN); /* strike */ 62759243Sobrien seterror(ERR_BADMOD, c); 628167465Smp goto end; 62959243Sobrien } 63059243Sobrien } 63159243Sobrien while ((c = getC(DOEXCL)) == ':'); 63259243Sobrien ungetD(c); 63359243Sobrien } 63459243Sobrien else 63559243Sobrien ungetD(c); 63659243Sobrien if (sc == '{') { 63759243Sobrien c = getC(DOEXCL); 63859243Sobrien if (c != '}') { 63959243Sobrien ungetD(c); 64059243Sobrien seterror(ERR_MISSING, '}'); 641167465Smp goto end; 64259243Sobrien } 643167465Smp Strbuf_append1(&name, c); 64459243Sobrien } 645167465Smp end: 646167465Smp cleanup_ignore(&name); 647167465Smp cleanup_until(&name); 648167465Smp addla(Strbuf_finish(&name)); 64959243Sobrien} 65059243Sobrien 651167465Smp/* xfree()'s its argument */ 65259243Sobrienvoid 653167465Smpaddla(Char *cp) 65459243Sobrien{ 655167465Smp static struct Strbuf buf; /* = Strbuf_INIT; */ 65659243Sobrien 657167465Smp buf.len = 0; 658167465Smp Strbuf_appendn(&buf, labuf.s + lap, labuf.len - lap); 659167465Smp labuf.len = 0; 660167465Smp Strbuf_append(&labuf, cp); 661167465Smp Strbuf_terminate(&labuf); 662167465Smp Strbuf_appendn(&labuf, buf.s, buf.len); 663167465Smp xfree(cp); 664167465Smp lap = 0; 66559243Sobrien} 66659243Sobrien 667167465Smp/* left-hand side of last :s or search string of last ?event? */ 668167465Smpstatic struct Strbuf lhsb; /* = Strbuf_INIT; */ 669167465Smpstatic struct Strbuf slhs; /* = Strbuf_INIT; left-hand side of last :s */ 670167465Smpstatic struct Strbuf rhsb; /* = Strbuf_INIT; right-hand side of last :s */ 67159243Sobrienstatic int quesarg; 67259243Sobrien 67359243Sobrienstatic void 674167465Smpgetexcl(Char sc) 67559243Sobrien{ 67659243Sobrien struct wordent *hp, *ip; 67759243Sobrien int left, right, dol; 678145479Smp eChar c; 67959243Sobrien 68059243Sobrien if (sc == 0) { 681232633Smp c = getC(0); 682232633Smp if (c == '{') 683232633Smp sc = (Char) c; 684232633Smp else 685232633Smp ungetC(c); 68659243Sobrien } 68759243Sobrien quesarg = -1; 68859243Sobrien 689167465Smp lastev = eventno; 69059243Sobrien hp = gethent(sc); 69159243Sobrien if (hp == 0) 69259243Sobrien return; 69359243Sobrien hadhist = 1; 69459243Sobrien dol = 0; 69559243Sobrien if (hp == alhistp) 69659243Sobrien for (ip = hp->next->next; ip != alhistt; ip = ip->next) 69759243Sobrien dol++; 69859243Sobrien else 69959243Sobrien for (ip = hp->next->next; ip != hp->prev; ip = ip->next) 70059243Sobrien dol++; 70159243Sobrien left = 0, right = dol; 702232633Smp if (sc == HISTSUB && HISTSUB != '\0') { 70359243Sobrien ungetC('s'), unreadc(HISTSUB), c = ':'; 70459243Sobrien goto subst; 70559243Sobrien } 70659243Sobrien c = getC(0); 70759243Sobrien if (!any(":^$*-%", c)) 70859243Sobrien goto subst; 70959243Sobrien left = right = -1; 71059243Sobrien if (c == ':') { 71159243Sobrien c = getC(0); 71259243Sobrien unreadc(c); 71359243Sobrien if (letter(c) || c == '&') { 71459243Sobrien c = ':'; 71559243Sobrien left = 0, right = dol; 71659243Sobrien goto subst; 71759243Sobrien } 71859243Sobrien } 71959243Sobrien else 72059243Sobrien ungetC(c); 72159243Sobrien if (!getsel(&left, &right, dol)) 72259243Sobrien return; 72359243Sobrien c = getC(0); 72459243Sobrien if (c == '*') 72559243Sobrien ungetC(c), c = '-'; 72659243Sobrien if (c == '-') { 72759243Sobrien if (!getsel(&left, &right, dol)) 72859243Sobrien return; 72959243Sobrien c = getC(0); 73059243Sobrien } 73159243Sobriensubst: 73259243Sobrien exclc = right - left + 1; 73359243Sobrien while (--left >= 0) 73459243Sobrien hp = hp->next; 735232633Smp if ((sc == HISTSUB && HISTSUB != '\0') || c == ':') { 73659243Sobrien do { 73759243Sobrien hp = getsub(hp); 73859243Sobrien c = getC(0); 73959243Sobrien } while (c == ':'); 74059243Sobrien } 74159243Sobrien unreadc(c); 74259243Sobrien if (sc == '{') { 74359243Sobrien c = getC(0); 74459243Sobrien if (c != '}') 74559243Sobrien seterror(ERR_BADBANG); 74659243Sobrien } 74759243Sobrien exclnxt = hp; 74859243Sobrien} 74959243Sobrien 75059243Sobrienstatic struct wordent * 751167465Smpgetsub(struct wordent *en) 75259243Sobrien{ 753145479Smp eChar delim; 754145479Smp eChar c; 755145479Smp eChar sc; 756145479Smp int global; 75759243Sobrien 75859243Sobrien do { 75959243Sobrien exclnxt = 0; 76059243Sobrien global = 0; 76159243Sobrien sc = c = getC(0); 762167465Smp while (c == 'g' || c == 'a') { 763167465Smp global |= (c == 'g') ? FLAG_G : FLAG_A; 76459243Sobrien sc = c = getC(0); 76559243Sobrien } 76659243Sobrien 76759243Sobrien switch (c) { 76859243Sobrien case 'p': 76959243Sobrien justpr++; 77059243Sobrien return (en); 77159243Sobrien 77259243Sobrien case 'x': 77359243Sobrien case 'q': 774167465Smp global |= FLAG_G; 77559243Sobrien /*FALLTHROUGH*/ 77659243Sobrien 77759243Sobrien case 'h': 77859243Sobrien case 'r': 77959243Sobrien case 't': 78059243Sobrien case 'e': 78159243Sobrien case 'u': 78259243Sobrien case 'l': 78359243Sobrien break; 78459243Sobrien 78559243Sobrien case '&': 786167465Smp if (slhs.len == 0) { 78759243Sobrien seterror(ERR_NOSUBST); 78859243Sobrien return (en); 78959243Sobrien } 790167465Smp lhsb.len = 0; 791167465Smp Strbuf_append(&lhsb, slhs.s); 792167465Smp Strbuf_terminate(&lhsb); 79359243Sobrien break; 79459243Sobrien 79559243Sobrien#ifdef notdef 79659243Sobrien case '~': 797167465Smp if (lhsb.len == 0) 79859243Sobrien goto badlhs; 79959243Sobrien break; 80059243Sobrien#endif 80159243Sobrien 80259243Sobrien case 's': 80359243Sobrien delim = getC(0); 80459243Sobrien if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) { 80559243Sobrien unreadc(delim); 806167465Smp lhsb.len = 0; 80759243Sobrien seterror(ERR_BADSUBST); 80859243Sobrien return (en); 80959243Sobrien } 810167465Smp Strbuf_terminate(&lhsb); 811167465Smp lhsb.len = 0; 81259243Sobrien for (;;) { 81359243Sobrien c = getC(0); 81459243Sobrien if (c == '\n') { 81559243Sobrien unreadc(c); 81659243Sobrien break; 81759243Sobrien } 81859243Sobrien if (c == delim) 81959243Sobrien break; 82059243Sobrien if (c == '\\') { 82159243Sobrien c = getC(0); 82259243Sobrien if (c != delim && c != '\\') 823167465Smp Strbuf_append1(&lhsb, '\\'); 82459243Sobrien } 825167465Smp Strbuf_append1(&lhsb, c); 82659243Sobrien } 827167465Smp if (lhsb.len != 0) 828167465Smp Strbuf_terminate(&lhsb); 829167465Smp else if (lhsb.s[0] == 0) { 83059243Sobrien seterror(ERR_LHS); 83159243Sobrien return (en); 832167465Smp } else 833167465Smp lhsb.len = Strlen(lhsb.s); /* lhsb.s wasn't changed */ 834167465Smp rhsb.len = 0; 83559243Sobrien for (;;) { 83659243Sobrien c = getC(0); 83759243Sobrien if (c == '\n') { 83859243Sobrien unreadc(c); 83959243Sobrien break; 84059243Sobrien } 84159243Sobrien if (c == delim) 84259243Sobrien break; 84359243Sobrien if (c == '\\') { 84459243Sobrien c = getC(0); 84559243Sobrien if (c != delim /* && c != '~' */ ) 846167465Smp Strbuf_append1(&rhsb, '\\'); 84759243Sobrien } 848167465Smp Strbuf_append1(&rhsb, c); 84959243Sobrien } 850167465Smp Strbuf_terminate(&rhsb); 85159243Sobrien break; 85259243Sobrien 85359243Sobrien default: 85459243Sobrien if (c == '\n') 85559243Sobrien unreadc(c); 856145479Smp seterror(ERR_BADBANGMOD, (int)c); 85759243Sobrien return (en); 85859243Sobrien } 859167465Smp slhs.len = 0; 860177128Sdelphij if (lhsb.s != NULL && lhsb.len != 0) 861177128Sdelphij Strbuf_append(&slhs, lhsb.s); 862167465Smp Strbuf_terminate(&slhs); 86359243Sobrien if (exclc) 86459243Sobrien en = dosub(sc, en, global); 86559243Sobrien } 86659243Sobrien while ((c = getC(0)) == ':'); 86759243Sobrien unreadc(c); 86859243Sobrien return (en); 86959243Sobrien} 87059243Sobrien 87159243Sobrien/* 87259243Sobrien * 87359243Sobrien * From Beto Appleton (beto@aixwiz.austin.ibm.com) 87459243Sobrien * 87559243Sobrien * when using history substitution, and the variable 87659243Sobrien * 'history' is set to a value higher than 1000, 87759243Sobrien * the shell might either freeze (hang) or core-dump. 87859243Sobrien * We raise the limit to 50000000 87959243Sobrien */ 88059243Sobrien 88159243Sobrien#define HIST_PURGE -50000000 88259243Sobrienstatic struct wordent * 883167465Smpdosub(Char sc, struct wordent *en, int global) 88459243Sobrien{ 88559243Sobrien struct wordent lexi; 886145479Smp int didsub = 0, didone = 0; 88759243Sobrien struct wordent *hp = &lexi; 88859243Sobrien struct wordent *wdp; 88959243Sobrien int i = exclc; 89059243Sobrien struct Hist *hst; 89159243Sobrien 89259243Sobrien wdp = hp; 89359243Sobrien while (--i >= 0) { 894167465Smp struct wordent *new = xcalloc(1, sizeof *wdp); 89559243Sobrien 89659243Sobrien new->word = 0; 89759243Sobrien new->prev = wdp; 89859243Sobrien new->next = hp; 89959243Sobrien wdp->next = new; 90059243Sobrien wdp = new; 90159243Sobrien en = en->next; 90259243Sobrien if (en->word) { 90359243Sobrien Char *tword, *otword; 90459243Sobrien 905167465Smp if ((global & FLAG_G) || didsub == 0) { 906167465Smp size_t pos; 907167465Smp 908167465Smp pos = 0; 909167465Smp tword = subword(en->word, sc, &didone, &pos); 91059243Sobrien if (didone) 91159243Sobrien didsub = 1; 912167465Smp if (global & FLAG_A) { 91359243Sobrien while (didone && tword != STRNULL) { 91459243Sobrien otword = tword; 915167465Smp tword = subword(otword, sc, &didone, &pos); 91659243Sobrien if (Strcmp(tword, otword) == 0) { 917167465Smp xfree(otword); 91859243Sobrien break; 91959243Sobrien } 92059243Sobrien else 921167465Smp xfree(otword); 92259243Sobrien } 92359243Sobrien } 92459243Sobrien } 92559243Sobrien else 92659243Sobrien tword = Strsave(en->word); 92759243Sobrien wdp->word = tword; 92859243Sobrien } 92959243Sobrien } 93059243Sobrien if (didsub == 0) 93159243Sobrien seterror(ERR_MODFAIL); 93259243Sobrien hp->prev = wdp; 93359243Sobrien /* 93459243Sobrien * ANSI mode HP/UX compiler chokes on 93559243Sobrien * return &enthist(HIST_PURGE, &lexi, 0)->Hlex; 93659243Sobrien */ 937232633Smp hst = enthist(HIST_PURGE, &lexi, 0, 0, -1); 93859243Sobrien return &(hst->Hlex); 93959243Sobrien} 94059243Sobrien 941167465Smp/* Return a newly allocated result of one modification of CP using the 942167465Smp operation TYPE. Set ADID to 1 if a modification was performed. 943167465Smp If TYPE == 's', perform substitutions only from *START_POS on and set 944167465Smp *START_POS to the position of next substitution attempt. */ 94559243Sobrienstatic Char * 946167465Smpsubword(Char *cp, Char type, int *adid, size_t *start_pos) 94759243Sobrien{ 948167465Smp Char *wp; 949167465Smp const Char *mp, *np; 95059243Sobrien 95159243Sobrien switch (type) { 95259243Sobrien 95359243Sobrien case 'r': 95459243Sobrien case 'e': 95559243Sobrien case 'h': 95659243Sobrien case 't': 95759243Sobrien case 'q': 95859243Sobrien case 'x': 95959243Sobrien case 'u': 96059243Sobrien case 'l': 96159243Sobrien wp = domod(cp, type); 962167465Smp if (wp == 0) { 963167465Smp *adid = 0; 96459243Sobrien return (Strsave(cp)); 965167465Smp } 96659243Sobrien *adid = 1; 96759243Sobrien return (wp); 96859243Sobrien 96959243Sobrien default: 970167465Smp for (mp = cp + *start_pos; *mp; mp++) { 971167465Smp if (matchs(mp, lhsb.s)) { 972167465Smp struct Strbuf wbuf = Strbuf_INIT; 973167465Smp 974167465Smp Strbuf_appendn(&wbuf, cp, mp - cp); 975167465Smp for (np = rhsb.s; *np; np++) 97659243Sobrien switch (*np) { 97759243Sobrien 97859243Sobrien case '\\': 97959243Sobrien if (np[1] == '&') 98059243Sobrien np++; 98159243Sobrien /* fall into ... */ 98259243Sobrien 98359243Sobrien default: 984167465Smp Strbuf_append1(&wbuf, *np); 98559243Sobrien continue; 98659243Sobrien 98759243Sobrien case '&': 988167465Smp Strbuf_append(&wbuf, lhsb.s); 98959243Sobrien continue; 99059243Sobrien } 991167465Smp *start_pos = wbuf.len; 992167465Smp Strbuf_append(&wbuf, mp + lhsb.len); 99359243Sobrien *adid = 1; 994167465Smp return Strbuf_finish(&wbuf); 99559243Sobrien } 996167465Smp } 997167465Smp *adid = 0; 99859243Sobrien return (Strsave(cp)); 99959243Sobrien } 100059243Sobrien} 100159243Sobrien 100259243SobrienChar * 1003167465Smpdomod(Char *cp, Char type) 100459243Sobrien{ 100559243Sobrien Char *wp, *xp; 100659243Sobrien int c; 100759243Sobrien 100859243Sobrien switch (type) { 100959243Sobrien 101059243Sobrien case 'x': 101159243Sobrien case 'q': 101259243Sobrien wp = Strsave(cp); 101359243Sobrien for (xp = wp; (c = *xp) != 0; xp++) 101459243Sobrien if ((c != ' ' && c != '\t') || type == 'q') 101559243Sobrien *xp |= QUOTE; 101659243Sobrien return (wp); 101759243Sobrien 101859243Sobrien case 'l': 1019145479Smp wp = NLSChangeCase(cp, 1); 1020145479Smp return wp ? wp : Strsave(cp); 102159243Sobrien 102259243Sobrien case 'u': 1023145479Smp wp = NLSChangeCase(cp, 0); 1024145479Smp return wp ? wp : Strsave(cp); 102559243Sobrien 102659243Sobrien case 'h': 102759243Sobrien case 't': 102859243Sobrien if (!any(short2str(cp), '/')) 102959243Sobrien return (type == 't' ? Strsave(cp) : 0); 1030167465Smp wp = Strrchr(cp, '/'); 103159243Sobrien if (type == 'h') 1032167465Smp xp = Strnsave(cp, wp - cp); 103359243Sobrien else 103459243Sobrien xp = Strsave(wp + 1); 103559243Sobrien return (xp); 103659243Sobrien 103759243Sobrien case 'e': 103859243Sobrien case 'r': 103959243Sobrien wp = Strend(cp); 104059243Sobrien for (wp--; wp >= cp && *wp != '/'; wp--) 104159243Sobrien if (*wp == '.') { 104259243Sobrien if (type == 'e') 104359243Sobrien xp = Strsave(wp + 1); 104459243Sobrien else 1045167465Smp xp = Strnsave(cp, wp - cp); 104659243Sobrien return (xp); 104759243Sobrien } 104859243Sobrien return (Strsave(type == 'e' ? STRNULL : cp)); 104959243Sobrien default: 105059243Sobrien break; 105159243Sobrien } 105259243Sobrien return (0); 105359243Sobrien} 105459243Sobrien 105559243Sobrienstatic int 1056167465Smpmatchs(const Char *str, const Char *pat) 105759243Sobrien{ 105859243Sobrien while (*str && *pat && *str == *pat) 105959243Sobrien str++, pat++; 106059243Sobrien return (*pat == 0); 106159243Sobrien} 106259243Sobrien 106359243Sobrienstatic int 1064167465Smpgetsel(int *al, int *ar, int dol) 106559243Sobrien{ 1066145479Smp eChar c = getC(0); 106759243Sobrien int i; 1068145479Smp int first = *al < 0; 106959243Sobrien 107059243Sobrien switch (c) { 107159243Sobrien 107259243Sobrien case '%': 107359243Sobrien if (quesarg == -1) { 107459243Sobrien seterror(ERR_BADBANGARG); 107559243Sobrien return (0); 107659243Sobrien } 107759243Sobrien if (*al < 0) 107859243Sobrien *al = quesarg; 107959243Sobrien *ar = quesarg; 108059243Sobrien break; 108159243Sobrien 108259243Sobrien case '-': 108359243Sobrien if (*al < 0) { 108459243Sobrien *al = 0; 108559243Sobrien *ar = dol - 1; 108659243Sobrien unreadc(c); 108759243Sobrien } 108859243Sobrien return (1); 108959243Sobrien 109059243Sobrien case '^': 109159243Sobrien if (*al < 0) 109259243Sobrien *al = 1; 109359243Sobrien *ar = 1; 109459243Sobrien break; 109559243Sobrien 109659243Sobrien case '$': 109759243Sobrien if (*al < 0) 109859243Sobrien *al = dol; 109959243Sobrien *ar = dol; 110059243Sobrien break; 110159243Sobrien 110259243Sobrien case '*': 110359243Sobrien if (*al < 0) 110459243Sobrien *al = 1; 110559243Sobrien *ar = dol; 110659243Sobrien if (*ar < *al) { 110759243Sobrien *ar = 0; 110859243Sobrien *al = 1; 110959243Sobrien return (1); 111059243Sobrien } 111159243Sobrien break; 111259243Sobrien 111359243Sobrien default: 111459243Sobrien if (Isdigit(c)) { 111559243Sobrien i = 0; 111659243Sobrien while (Isdigit(c)) { 111759243Sobrien i = i * 10 + c - '0'; 111859243Sobrien c = getC(0); 111959243Sobrien } 112059243Sobrien if (i < 0) 112159243Sobrien i = dol + 1; 112259243Sobrien if (*al < 0) 112359243Sobrien *al = i; 112459243Sobrien *ar = i; 112559243Sobrien } 112659243Sobrien else if (*al < 0) 112759243Sobrien *al = 0, *ar = dol; 112859243Sobrien else 112959243Sobrien *ar = dol - 1; 113059243Sobrien unreadc(c); 113159243Sobrien break; 113259243Sobrien } 113359243Sobrien if (first) { 113459243Sobrien c = getC(0); 113559243Sobrien unreadc(c); 113659243Sobrien if (any("-$*", c)) 113759243Sobrien return (1); 113859243Sobrien } 113959243Sobrien if (*al > *ar || *ar > dol) { 114059243Sobrien seterror(ERR_BADBANGARG); 114159243Sobrien return (0); 114259243Sobrien } 114359243Sobrien return (1); 114459243Sobrien 114559243Sobrien} 114659243Sobrien 114759243Sobrienstatic struct wordent * 1148167465Smpgethent(Char sc) 114959243Sobrien{ 115059243Sobrien struct Hist *hp; 115159243Sobrien Char *np; 1152145479Smp eChar c; 115359243Sobrien int event; 1154145479Smp int back = 0; 115559243Sobrien 1156232633Smp c = (sc == HISTSUB && HISTSUB != '\0') ? (eChar)HIST : getC(0); 1157145479Smp if (c == (eChar)HIST) { 115859243Sobrien if (alhistp) 115959243Sobrien return (alhistp); 116059243Sobrien event = eventno; 116159243Sobrien } 116259243Sobrien else 116359243Sobrien switch (c) { 116459243Sobrien 116559243Sobrien case ':': 116659243Sobrien case '^': 116759243Sobrien case '$': 116859243Sobrien case '*': 116959243Sobrien case '%': 117059243Sobrien ungetC(c); 117159243Sobrien if (lastev == eventno && alhistp) 117259243Sobrien return (alhistp); 117359243Sobrien event = lastev; 117459243Sobrien break; 117559243Sobrien 117659243Sobrien case '#': /* !# is command being typed in (mrh) */ 117759243Sobrien if (--hleft == 0) { 117859243Sobrien seterror(ERR_HISTLOOP); 117959243Sobrien return (0); 118059243Sobrien } 118159243Sobrien else 118259243Sobrien return (¶ml); 118359243Sobrien /* NOTREACHED */ 118459243Sobrien 118559243Sobrien case '-': 118659243Sobrien back = 1; 118759243Sobrien c = getC(0); 118859243Sobrien /* FALLSTHROUGH */ 118959243Sobrien 119059243Sobrien default: 119159243Sobrien if (any("(=~", c)) { 119259243Sobrien unreadc(c); 119359243Sobrien ungetC(HIST); 119459243Sobrien return (0); 119559243Sobrien } 1196167465Smp Strbuf_terminate(&lhsb); 1197167465Smp lhsb.len = 0; 119859243Sobrien event = 0; 119959243Sobrien while (!cmap(c, _ESC | _META | _QF | _QB) && !any("^*-%${}:#", c)) { 120059243Sobrien if (event != -1 && Isdigit(c)) 120159243Sobrien event = event * 10 + c - '0'; 120259243Sobrien else 120359243Sobrien event = -1; 1204167465Smp Strbuf_append1(&lhsb, c); 120559243Sobrien c = getC(0); 120659243Sobrien } 120759243Sobrien unreadc(c); 1208167465Smp if (lhsb.len == 0) { 1209167465Smp lhsb.len = Strlen(lhsb.s); /* lhsb.s wasn't changed */ 121059243Sobrien ungetC(HIST); 121159243Sobrien return (0); 121259243Sobrien } 1213167465Smp Strbuf_terminate(&lhsb); 121459243Sobrien if (event != -1) { 121559243Sobrien /* 121659243Sobrien * History had only digits 121759243Sobrien */ 121859243Sobrien if (back) 1219167465Smp event = eventno + (alhistp == 0) - event; 122059243Sobrien break; 122159243Sobrien } 122259243Sobrien if (back) { 1223167465Smp Strbuf_append1(&lhsb, '\0'); /* Allocate space */ 1224167465Smp Strbuf_terminate(&lhsb); 1225167465Smp memmove(lhsb.s + 1, lhsb.s, (lhsb.len - 1) * sizeof (*lhsb.s)); 1226167465Smp lhsb.s[0] = '-'; 122759243Sobrien } 1228167465Smp hp = findev(lhsb.s, 0); 122959243Sobrien if (hp) 123059243Sobrien lastev = hp->Hnum; 123159243Sobrien return (&hp->Hlex); 123259243Sobrien 123359243Sobrien case '?': 1234167465Smp Strbuf_terminate(&lhsb); 1235167465Smp lhsb.len = 0; 123659243Sobrien for (;;) { 123759243Sobrien c = getC(0); 123859243Sobrien if (c == '\n') { 123959243Sobrien unreadc(c); 124059243Sobrien break; 124159243Sobrien } 124259243Sobrien if (c == '?') 124359243Sobrien break; 1244167465Smp Strbuf_append1(&lhsb, c); 124559243Sobrien } 1246167465Smp if (lhsb.len == 0) { 1247167465Smp lhsb.len = Strlen(lhsb.s); /* lhsb.s wasn't changed */ 1248167465Smp if (lhsb.len == 0) { 124959243Sobrien seterror(ERR_NOSEARCH); 125059243Sobrien return (0); 125159243Sobrien } 125259243Sobrien } 125359243Sobrien else 1254167465Smp Strbuf_terminate(&lhsb); 1255167465Smp hp = findev(lhsb.s, 1); 125659243Sobrien if (hp) 125759243Sobrien lastev = hp->Hnum; 125859243Sobrien return (&hp->Hlex); 125959243Sobrien } 126059243Sobrien 126159243Sobrien for (hp = Histlist.Hnext; hp; hp = hp->Hnext) 126259243Sobrien if (hp->Hnum == event) { 126359243Sobrien hp->Href = eventno; 126459243Sobrien lastev = hp->Hnum; 126559243Sobrien return (&hp->Hlex); 126659243Sobrien } 1267232633Smp np = putn((tcsh_number_t)event); 126859243Sobrien seterror(ERR_NOEVENT, short2str(np)); 1269167465Smp xfree(np); 127059243Sobrien return (0); 127159243Sobrien} 127259243Sobrien 127359243Sobrienstatic struct Hist * 1274167465Smpfindev(Char *cp, int anyarg) 127559243Sobrien{ 127659243Sobrien struct Hist *hp; 127759243Sobrien 127859243Sobrien for (hp = Histlist.Hnext; hp; hp = hp->Hnext) { 127959243Sobrien Char *dp; 128059243Sobrien Char *p, *q; 128159243Sobrien struct wordent *lp = hp->Hlex.next; 128259243Sobrien int argno = 0; 128359243Sobrien 128459243Sobrien /* 128559243Sobrien * The entries added by alias substitution don't have a newline but do 128659243Sobrien * have a negative event number. Savehist() trims off these entries, 128759243Sobrien * but it happens before alias expansion, too early to delete those 128859243Sobrien * from the previous command. 128959243Sobrien */ 129059243Sobrien if (hp->Hnum < 0) 129159243Sobrien continue; 129259243Sobrien if (lp->word[0] == '\n') 129359243Sobrien continue; 129459243Sobrien if (!anyarg) { 129559243Sobrien p = cp; 129659243Sobrien q = lp->word; 129759243Sobrien do 129859243Sobrien if (!*p) 129959243Sobrien return (hp); 130059243Sobrien while (*p++ == *q++); 130159243Sobrien continue; 130259243Sobrien } 130359243Sobrien do { 130459243Sobrien for (dp = lp->word; *dp; dp++) { 130559243Sobrien p = cp; 130659243Sobrien q = dp; 130759243Sobrien do 130859243Sobrien if (!*p) { 130959243Sobrien quesarg = argno; 131059243Sobrien return (hp); 131159243Sobrien } 131259243Sobrien while (*p++ == *q++); 131359243Sobrien } 131459243Sobrien lp = lp->next; 131559243Sobrien argno++; 131659243Sobrien } while (lp->word[0] != '\n'); 131759243Sobrien } 131859243Sobrien seterror(ERR_NOEVENT, short2str(cp)); 131959243Sobrien return (0); 132059243Sobrien} 132159243Sobrien 132259243Sobrien 132359243Sobrienstatic void 1324167465Smpsetexclp(Char *cp) 132559243Sobrien{ 132659243Sobrien if (cp && cp[0] == '\n') 132759243Sobrien return; 132859243Sobrien exclp = cp; 132959243Sobrien} 133059243Sobrien 133159243Sobrienvoid 1332167465Smpunreadc(Char c) 133359243Sobrien{ 133459243Sobrien peekread = (Char) c; 133559243Sobrien} 133659243Sobrien 1337145479SmpeChar 1338167465Smpreadc(int wanteof) 133959243Sobrien{ 1340145479Smp eChar c; 134159243Sobrien static int sincereal; /* Number of real EOFs we've seen */ 134259243Sobrien 134359243Sobrien#ifdef DEBUG_INP 134459243Sobrien xprintf("readc\n"); 134559243Sobrien#endif 134659243Sobrien if ((c = peekread) != 0) { 134759243Sobrien peekread = 0; 134859243Sobrien return (c); 134959243Sobrien } 135059243Sobrien 135159243Sobrientop: 135269408Sache aret = TCSH_F_SEEK; 135359243Sobrien if (alvecp) { 135459243Sobrien arun = 1; 135559243Sobrien#ifdef DEBUG_INP 135659243Sobrien xprintf("alvecp %c\n", *alvecp & 0xff); 135759243Sobrien#endif 135869408Sache aret = TCSH_A_SEEK; 135959243Sobrien if ((c = *alvecp++) != 0) 136059243Sobrien return (c); 136159243Sobrien if (alvec && *alvec) { 136259243Sobrien alvecp = *alvec++; 136359243Sobrien return (' '); 136459243Sobrien } 136559243Sobrien else { 136659243Sobrien alvecp = NULL; 136769408Sache aret = TCSH_F_SEEK; 136859243Sobrien return('\n'); 136959243Sobrien } 137059243Sobrien } 137159243Sobrien if (alvec) { 137259243Sobrien arun = 1; 137359243Sobrien if ((alvecp = *alvec) != 0) { 137459243Sobrien alvec++; 137559243Sobrien goto top; 137659243Sobrien } 137759243Sobrien /* Infinite source! */ 137859243Sobrien return ('\n'); 137959243Sobrien } 138059243Sobrien arun = 0; 138159243Sobrien if (evalp) { 138269408Sache aret = TCSH_E_SEEK; 138359243Sobrien if ((c = *evalp++) != 0) 138459243Sobrien return (c); 138559243Sobrien if (evalvec && *evalvec) { 138659243Sobrien evalp = *evalvec++; 138759243Sobrien return (' '); 138859243Sobrien } 138969408Sache aret = TCSH_F_SEEK; 139059243Sobrien evalp = 0; 139159243Sobrien } 139259243Sobrien if (evalvec) { 139359243Sobrien if (evalvec == INVPPTR) { 139459243Sobrien doneinp = 1; 139559243Sobrien reset(); 139659243Sobrien } 139759243Sobrien if ((evalp = *evalvec) != 0) { 139859243Sobrien evalvec++; 139959243Sobrien goto top; 140059243Sobrien } 140159243Sobrien evalvec = INVPPTR; 140259243Sobrien return ('\n'); 140359243Sobrien } 140459243Sobrien do { 140559243Sobrien if (arginp == INVPTR || onelflg == 1) { 140659243Sobrien if (wanteof) 1407145479Smp return CHAR_ERR; 140859243Sobrien exitstat(); 140959243Sobrien } 141059243Sobrien if (arginp) { 141159243Sobrien if ((c = *arginp++) == 0) { 141259243Sobrien arginp = INVPTR; 141359243Sobrien return ('\n'); 141459243Sobrien } 141559243Sobrien return (c); 141659243Sobrien } 141759243Sobrien#ifdef BSDJOBS 141859243Sobrienreread: 141959243Sobrien#endif /* BSDJOBS */ 142059243Sobrien c = bgetc(); 1421145479Smp if (c == CHAR_ERR) { 142269408Sache#ifndef WINNT_NATIVE 142359243Sobrien# ifndef POSIX 142459243Sobrien# ifdef TERMIO 142559243Sobrien struct termio tty; 142659243Sobrien# else /* SGTTYB */ 142759243Sobrien struct sgttyb tty; 142859243Sobrien# endif /* TERMIO */ 142959243Sobrien# else /* POSIX */ 143059243Sobrien struct termios tty; 143159243Sobrien# endif /* POSIX */ 143269408Sache#endif /* !WINNT_NATIVE */ 143359243Sobrien if (wanteof) 1434145479Smp return CHAR_ERR; 143559243Sobrien /* was isatty but raw with ignoreeof yields problems */ 143669408Sache#ifndef WINNT_NATIVE 143759243Sobrien# ifndef POSIX 143859243Sobrien# ifdef TERMIO 143959243Sobrien if (ioctl(SHIN, TCGETA, (ioctl_t) & tty) == 0 && 144059243Sobrien (tty.c_lflag & ICANON)) 144159243Sobrien# else /* GSTTYB */ 144259243Sobrien if (ioctl(SHIN, TIOCGETP, (ioctl_t) & tty) == 0 && 144359243Sobrien (tty.sg_flags & RAW) == 0) 144459243Sobrien# endif /* TERMIO */ 144559243Sobrien# else /* POSIX */ 144659243Sobrien if (tcgetattr(SHIN, &tty) == 0 && 144759243Sobrien (tty.c_lflag & ICANON)) 144859243Sobrien# endif /* POSIX */ 144969408Sache#else /* WINNT_NATIVE */ 145059243Sobrien if (isatty(SHIN)) 145169408Sache#endif /* !WINNT_NATIVE */ 145259243Sobrien { 145359243Sobrien#ifdef BSDJOBS 1454167465Smp pid_t ctpgrp; 145559243Sobrien#endif /* BSDJOBS */ 145659243Sobrien 1457100616Smp if (numeof != 0 && ++sincereal >= numeof) /* Too many EOFs? Bye! */ 145859243Sobrien goto oops; 145959243Sobrien#ifdef BSDJOBS 146059243Sobrien if (tpgrp != -1 && 146159243Sobrien (ctpgrp = tcgetpgrp(FSHTTY)) != -1 && 146259243Sobrien tpgrp != ctpgrp) { 146359243Sobrien (void) tcsetpgrp(FSHTTY, tpgrp); 146459243Sobrien# ifdef _SEQUENT_ 146559243Sobrien if (ctpgrp) 146659243Sobrien# endif /* _SEQUENT */ 1467167465Smp (void) killpg(ctpgrp, SIGHUP); 146859243Sobrien# ifdef notdef 146959243Sobrien /* 147059243Sobrien * With the walking process group fix, this message 147159243Sobrien * is now obsolete. As the foreground process group 147259243Sobrien * changes, the shell needs to adjust. Well too bad. 147359243Sobrien */ 147459243Sobrien xprintf(CGETS(16, 1, "Reset tty pgrp from %d to %d\n"), 1475167465Smp (int)ctpgrp, (int)tpgrp); 147659243Sobrien# endif /* notdef */ 147759243Sobrien goto reread; 147859243Sobrien } 147959243Sobrien#endif /* BSDJOBS */ 148059243Sobrien /* What follows is complicated EOF handling -- sterling@netcom.com */ 148159243Sobrien /* First, we check to see if we have ignoreeof set */ 148259243Sobrien if (adrof(STRignoreeof)) { 148359243Sobrien /* If so, we check for any stopped jobs only on the first EOF */ 148459243Sobrien if ((sincereal == 1) && (chkstop == 0)) { 148559243Sobrien panystop(1); 148659243Sobrien } 148759243Sobrien } else { 148859243Sobrien /* If we don't have ignoreeof set, always check for stopped jobs */ 148959243Sobrien if (chkstop == 0) { 149059243Sobrien panystop(1); 149159243Sobrien } 149259243Sobrien } 149359243Sobrien /* At this point, if there were stopped jobs, we would have already 149459243Sobrien * called reset(). If we got this far, assume we can print an 149559243Sobrien * exit/logout message if we ignoreeof, or just exit. 149659243Sobrien */ 149759243Sobrien if (adrof(STRignoreeof)) { 149859243Sobrien /* If so, tell the user to use exit or logout */ 149959243Sobrien if (loginsh) { 1500195609Smp xprintf("%s", CGETS(16, 2, 150159243Sobrien "\nUse \"logout\" to logout.\n")); 150259243Sobrien } else { 150359243Sobrien xprintf(CGETS(16, 3, 150459243Sobrien "\nUse \"exit\" to leave %s.\n"), 150559243Sobrien progname); 150659243Sobrien } 1507167465Smp reset(); 150859243Sobrien } else { 150959243Sobrien /* If we don't have ignoreeof set, just fall through */ 151059243Sobrien ; /* EMPTY */ 151159243Sobrien } 151259243Sobrien } 151359243Sobrien oops: 151459243Sobrien doneinp = 1; 151559243Sobrien reset(); 151659243Sobrien } 151759243Sobrien sincereal = 0; 151859243Sobrien if (c == '\n' && onelflg) 151959243Sobrien onelflg--; 152059243Sobrien } while (c == 0); 1521167465Smp Strbuf_append1(&histline, c); 152259243Sobrien return (c); 152359243Sobrien} 152459243Sobrien 152559243Sobrienstatic void 1526167465Smpballoc(int buf) 152759243Sobrien{ 152859243Sobrien Char **nfbuf; 152959243Sobrien 153059243Sobrien while (buf >= fblocks) { 1531167465Smp nfbuf = xcalloc(fblocks + 2, sizeof(Char **)); 153259243Sobrien if (fbuf) { 153359243Sobrien (void) blkcpy(nfbuf, fbuf); 1534167465Smp xfree(fbuf); 153559243Sobrien } 153659243Sobrien fbuf = nfbuf; 1537167465Smp fbuf[fblocks] = xcalloc(BUFSIZE, sizeof(Char)); 153859243Sobrien fblocks++; 153959243Sobrien } 154059243Sobrien} 154159243Sobrien 1542145479Smpstatic ssize_t 1543167465Smpwide_read(int fildes, Char *buf, size_t nchars, int use_fclens) 1544145479Smp{ 1545145479Smp char cbuf[BUFSIZE + 1]; 1546167465Smp ssize_t res, r = 0; 1547145479Smp size_t partial; 1548167465Smp int err; 1549167465Smp 1550167465Smp if (nchars == 0) 1551167465Smp return 0; 1552167465Smp assert (nchars <= sizeof(cbuf) / sizeof(*cbuf)); 1553145479Smp USE(use_fclens); 1554145479Smp res = 0; 1555145479Smp partial = 0; 1556145479Smp do { 1557145479Smp size_t i; 1558167465Smp size_t len = nchars > partial ? nchars - partial : 1; 1559167465Smp 1560167465Smp if (partial + len >= sizeof(cbuf) / sizeof(*cbuf)) 1561167465Smp break; 1562145479Smp 1563167465Smp r = xread(fildes, cbuf + partial, len); 1564167465Smp 1565145479Smp if (partial == 0 && r <= 0) 1566145479Smp break; 1567145479Smp partial += r; 1568145479Smp i = 0; 1569167465Smp while (i < partial && nchars != 0) { 1570167465Smp int tlen; 1571145479Smp 1572167465Smp tlen = normal_mbtowc(buf + res, cbuf + i, partial - i); 1573167465Smp if (tlen == -1) { 1574145479Smp reset_mbtowc(); 1575167465Smp if ((partial - i) < MB_LEN_MAX && r > 0) 1576145479Smp /* Maybe a partial character and there is still a chance 1577145479Smp to read more */ 1578145479Smp break; 1579145479Smp buf[res] = (unsigned char)cbuf[i] | INVALID_BYTE; 1580145479Smp } 1581167465Smp if (tlen <= 0) 1582167465Smp tlen = 1; 1583145479Smp#ifdef WIDE_STRINGS 1584145479Smp if (use_fclens) 1585167465Smp fclens[res] = tlen; 1586145479Smp#endif 1587167465Smp i += tlen; 1588145479Smp res++; 1589145479Smp nchars--; 1590145479Smp } 1591145479Smp if (i != partial) 1592145479Smp memmove(cbuf, cbuf + i, partial - i); 1593145479Smp partial -= i; 1594167465Smp } while (partial != 0 && nchars > 0); 1595167465Smp /* Throwing away possible partial multibyte characters on error if the 1596167465Smp stream is not seekable */ 1597167465Smp err = errno; 1598167465Smp lseek(fildes, -(off_t)partial, L_INCR); 1599167465Smp errno = err; 1600145479Smp return res != 0 ? res : r; 1601145479Smp} 1602145479Smp 1603145479Smpstatic eChar 1604167465Smpbgetc(void) 160559243Sobrien{ 1606145479Smp Char ch; 160759243Sobrien int c, off, buf; 160859243Sobrien int numleft = 0, roomleft; 160959243Sobrien 161059243Sobrien if (cantell) { 161159243Sobrien if (fseekp < fbobp || fseekp > feobp) { 161259243Sobrien fbobp = feobp = fseekp; 161359243Sobrien (void) lseek(SHIN, fseekp, L_SET); 161459243Sobrien } 161559243Sobrien if (fseekp == feobp) { 1616167465Smp#ifdef WIDE_STRINGS 1617167465Smp off_t bytes; 1618167465Smp size_t i; 1619167465Smp 1620167465Smp bytes = fbobp; 1621167465Smp for (i = 0; i < (size_t)(feobp - fbobp); i++) 1622167465Smp bytes += fclens[i]; 1623167465Smp fseekp = feobp = bytes; 1624167465Smp#endif 162559243Sobrien fbobp = feobp; 1626167465Smp c = wide_read(SHIN, fbuf[0], BUFSIZE, 1); 162759243Sobrien#ifdef convex 162859243Sobrien if (c < 0) 162959243Sobrien stderror(ERR_SYSTEM, progname, strerror(errno)); 163059243Sobrien#endif /* convex */ 163159243Sobrien if (c <= 0) 1632145479Smp return CHAR_ERR; 163359243Sobrien feobp += c; 163459243Sobrien } 1635195609Smp#if !defined(WINNT_NATIVE) && !defined(__CYGWIN__) 1636145479Smp ch = fbuf[0][fseekp - fbobp]; 163759243Sobrien fseekp++; 163859243Sobrien#else 163959243Sobrien do { 1640145479Smp ch = fbuf[0][fseekp - fbobp]; 164159243Sobrien fseekp++; 1642145479Smp } while(ch == '\r'); 1643195609Smp#endif /* !WINNT_NATIVE && !__CYGWIN__ */ 1644145479Smp return (ch); 164559243Sobrien } 164659243Sobrien 164759243Sobrien while (fseekp >= feobp) { 1648100616Smp if ((editing 1649100616Smp#if defined(FILEC) && defined(TIOCSTI) 1650100616Smp || filec 1651100616Smp#endif /* FILEC && TIOCSTI */ 1652100616Smp ) && intty) { /* then use twenex routine */ 165359243Sobrien fseekp = feobp; /* where else? */ 1654100616Smp#if defined(FILEC) && defined(TIOCSTI) 1655100616Smp if (!editing) 1656100616Smp c = numleft = tenex(InputBuf, BUFSIZE); 1657100616Smp else 1658100616Smp#endif /* FILEC && TIOCSTI */ 165959243Sobrien c = numleft = Inputl(); /* PWP: get a line */ 166059243Sobrien while (numleft > 0) { 166159243Sobrien off = (int) feobp % BUFSIZE; 166259243Sobrien buf = (int) feobp / BUFSIZE; 166359243Sobrien balloc(buf); 166459243Sobrien roomleft = BUFSIZE - off; 166559243Sobrien if (roomleft > numleft) 166659243Sobrien roomleft = numleft; 1667167465Smp (void) memcpy(fbuf[buf] + off, InputBuf + c - numleft, 1668167465Smp roomleft * sizeof(Char)); 166959243Sobrien numleft -= roomleft; 167059243Sobrien feobp += roomleft; 167159243Sobrien } 1672100616Smp } else { 167359243Sobrien off = (int) feobp % BUFSIZE; 167459243Sobrien buf = (int) feobp / BUFSIZE; 167559243Sobrien balloc(buf); 167659243Sobrien roomleft = BUFSIZE - off; 1677167465Smp c = wide_read(SHIN, fbuf[buf] + off, roomleft, 0); 1678145479Smp if (c > 0) 167959243Sobrien feobp += c; 168059243Sobrien } 168159243Sobrien if (c == 0 || (c < 0 && fixio(SHIN, errno) == -1)) 1682145479Smp return CHAR_ERR; 168359243Sobrien } 1684145479Smp#ifdef SIG_WINDOW 1685145479Smp if (windowchg) 1686145479Smp (void) check_window_size(0); /* for window systems */ 1687145479Smp#endif /* SIG_WINDOW */ 1688195609Smp#if !defined(WINNT_NATIVE) && !defined(__CYGWIN__) 1689145479Smp ch = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE]; 169059243Sobrien fseekp++; 169159243Sobrien#else 169259243Sobrien do { 1693145479Smp ch = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE]; 169459243Sobrien fseekp++; 1695145479Smp } while(ch == '\r'); 1696195609Smp#endif /* !WINNT_NATIVE && !__CYGWIN__ */ 1697145479Smp return (ch); 169859243Sobrien} 169959243Sobrien 170059243Sobrienstatic void 1701167465Smpbfree(void) 170259243Sobrien{ 170359243Sobrien int sb, i; 170459243Sobrien 170559243Sobrien if (cantell) 170659243Sobrien return; 170759243Sobrien if (whyles) 170859243Sobrien return; 170959243Sobrien sb = (int) (fseekp - 1) / BUFSIZE; 171059243Sobrien if (sb > 0) { 171159243Sobrien for (i = 0; i < sb; i++) 1712167465Smp xfree(fbuf[i]); 171359243Sobrien (void) blkcpy(fbuf, &fbuf[sb]); 171459243Sobrien fseekp -= BUFSIZE * sb; 171559243Sobrien feobp -= BUFSIZE * sb; 171659243Sobrien fblocks -= sb; 171759243Sobrien } 171859243Sobrien} 171959243Sobrien 172059243Sobrienvoid 1721167465Smpbseek(struct Ain *l) 172259243Sobrien{ 172359243Sobrien switch (aret = l->type) { 172469408Sache case TCSH_E_SEEK: 172559243Sobrien evalvec = l->a_seek; 172659243Sobrien evalp = l->c_seek; 172759243Sobrien#ifdef DEBUG_SEEK 172859243Sobrien xprintf(CGETS(16, 4, "seek to eval %x %x\n"), evalvec, evalp); 172959243Sobrien#endif 173059243Sobrien return; 173169408Sache case TCSH_A_SEEK: 173259243Sobrien alvec = l->a_seek; 173359243Sobrien alvecp = l->c_seek; 173459243Sobrien#ifdef DEBUG_SEEK 173559243Sobrien xprintf(CGETS(16, 5, "seek to alias %x %x\n"), alvec, alvecp); 173659243Sobrien#endif 173759243Sobrien return; 173869408Sache case TCSH_F_SEEK: 173959243Sobrien#ifdef DEBUG_SEEK 174059243Sobrien xprintf(CGETS(16, 6, "seek to file %x\n"), fseekp); 174159243Sobrien#endif 174259243Sobrien fseekp = l->f_seek; 1743145479Smp#ifdef WIDE_STRINGS 1744145479Smp if (cantell) { 1745167465Smp if (fseekp >= fbobp && feobp >= fbobp) { 1746145479Smp size_t i; 1747145479Smp off_t o; 1748145479Smp 1749145479Smp o = fbobp; 1750167465Smp for (i = 0; i < (size_t)(feobp - fbobp); i++) { 1751145479Smp if (fseekp == o) { 1752145479Smp fseekp = fbobp + i; 1753145479Smp return; 1754145479Smp } 1755145479Smp o += fclens[i]; 1756145479Smp } 1757145479Smp if (fseekp == o) { 1758145479Smp fseekp = feobp; 1759145479Smp return; 1760145479Smp } 1761145479Smp } 1762145479Smp fbobp = feobp = fseekp + 1; /* To force lseek() */ 1763145479Smp } 1764145479Smp#endif 176559243Sobrien return; 176659243Sobrien default: 176759243Sobrien xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret); 176859243Sobrien abort(); 176959243Sobrien } 177059243Sobrien} 177159243Sobrien 177259243Sobrien/* any similarity to bell telephone is purely accidental */ 177359243Sobrienvoid 1774167465Smpbtell(struct Ain *l) 177559243Sobrien{ 177659243Sobrien switch (l->type = aret) { 177769408Sache case TCSH_E_SEEK: 177859243Sobrien l->a_seek = evalvec; 177959243Sobrien l->c_seek = evalp; 178059243Sobrien#ifdef DEBUG_SEEK 178159243Sobrien xprintf(CGETS(16, 8, "tell eval %x %x\n"), evalvec, evalp); 178259243Sobrien#endif 178359243Sobrien return; 178469408Sache case TCSH_A_SEEK: 178559243Sobrien l->a_seek = alvec; 178659243Sobrien l->c_seek = alvecp; 178759243Sobrien#ifdef DEBUG_SEEK 178859243Sobrien xprintf(CGETS(16, 9, "tell alias %x %x\n"), alvec, alvecp); 178959243Sobrien#endif 179059243Sobrien return; 179169408Sache case TCSH_F_SEEK: 1792145479Smp#ifdef WIDE_STRINGS 1793167465Smp if (cantell && fseekp >= fbobp && fseekp <= feobp) { 1794145479Smp size_t i; 1795167465Smp 1796145479Smp l->f_seek = fbobp; 1797167465Smp for (i = 0; i < (size_t)(fseekp - fbobp); i++) 1798145479Smp l->f_seek += fclens[i]; 1799145479Smp } else 1800145479Smp#endif 1801145479Smp /*SUPPRESS 112*/ 1802145479Smp l->f_seek = fseekp; 180359243Sobrien l->a_seek = NULL; 180459243Sobrien#ifdef DEBUG_SEEK 180559243Sobrien xprintf(CGETS(16, 10, "tell file %x\n"), fseekp); 180659243Sobrien#endif 180759243Sobrien return; 180859243Sobrien default: 180959243Sobrien xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret); 181059243Sobrien abort(); 181159243Sobrien } 181259243Sobrien} 181359243Sobrien 181459243Sobrienvoid 1815167465Smpbtoeof(void) 181659243Sobrien{ 181759243Sobrien (void) lseek(SHIN, (off_t) 0, L_XTND); 181869408Sache aret = TCSH_F_SEEK; 181959243Sobrien fseekp = feobp; 182059243Sobrien alvec = NULL; 182159243Sobrien alvecp = NULL; 182259243Sobrien evalvec = NULL; 182359243Sobrien evalp = NULL; 182459243Sobrien wfree(); 182559243Sobrien bfree(); 182659243Sobrien} 182759243Sobrien 182859243Sobrienvoid 1829167465Smpsettell(void) 183059243Sobrien{ 183159243Sobrien off_t x; 183259243Sobrien cantell = 0; 183359243Sobrien if (arginp || onelflg || intty) 183459243Sobrien return; 183559243Sobrien if ((x = lseek(SHIN, (off_t) 0, L_INCR)) == -1) 183659243Sobrien return; 1837167465Smp fbuf = xcalloc(2, sizeof(Char **)); 183859243Sobrien fblocks = 1; 1839167465Smp fbuf[0] = xcalloc(BUFSIZE, sizeof(Char)); 184059243Sobrien fseekp = fbobp = feobp = x; 184159243Sobrien cantell = 1; 184259243Sobrien} 1843