159243Sobrien/* 259243Sobrien * sh.lex.c: Lexical analysis into tokens 359243Sobrien */ 459243Sobrien/*- 559243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 659243Sobrien * All rights reserved. 759243Sobrien * 859243Sobrien * Redistribution and use in source and binary forms, with or without 959243Sobrien * modification, are permitted provided that the following conditions 1059243Sobrien * are met: 1159243Sobrien * 1. Redistributions of source code must retain the above copyright 1259243Sobrien * notice, this list of conditions and the following disclaimer. 1359243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1459243Sobrien * notice, this list of conditions and the following disclaimer in the 1559243Sobrien * documentation and/or other materials provided with the distribution. 16100616Smp * 3. Neither the name of the University nor the names of its contributors 1759243Sobrien * may be used to endorse or promote products derived from this software 1859243Sobrien * without specific prior written permission. 1959243Sobrien * 2059243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2159243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2259243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2359243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2459243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2559243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2659243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2759243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2859243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2959243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3059243Sobrien * SUCH DAMAGE. 3159243Sobrien */ 3259243Sobrien#include "sh.h" 3359243Sobrien#include "ed.h" 34145479Smp 35145479Smp#include <assert.h> 3659243Sobrien/* #define DEBUG_INP */ 3759243Sobrien/* #define DEBUG_SEEK */ 3859243Sobrien 3959243Sobrien/* 4059243Sobrien * C shell 4159243Sobrien */ 4259243Sobrien 43167465Smp#define FLAG_G 1 44167465Smp#define FLAG_A 2 4559243Sobrien/* 4659243Sobrien * These lexical routines read input and form lists of words. 4759243Sobrien * There is some involved processing here, because of the complications 4859243Sobrien * of input buffering, and especially because of history substitution. 4959243Sobrien */ 50167465Smpstatic Char *word (int); 51167465Smpstatic eChar getC1 (int); 52167465Smpstatic void getdol (void); 53167465Smpstatic void getexcl (Char); 54167465Smpstatic struct Hist *findev (Char *, int); 55167465Smpstatic void setexclp (Char *); 56167465Smpstatic eChar bgetc (void); 57167465Smpstatic void balloc (int); 58167465Smpstatic void bfree (void); 59167465Smpstatic struct wordent *gethent (Char); 60167465Smpstatic int matchs (const Char *, const Char *); 61167465Smpstatic int getsel (int *, int *, int); 62167465Smpstatic struct wordent *getsub (struct wordent *); 63167465Smpstatic Char *subword (Char *, Char, int *, size_t *); 64167465Smpstatic struct wordent *dosub (Char, struct wordent *, int); 6559243Sobrien 6659243Sobrien/* 6759243Sobrien * Peekc is a peek character for getC, peekread for readc. 6859243Sobrien * There is a subtlety here in many places... history routines 6959243Sobrien * will read ahead and then insert stuff into the input stream. 7059243Sobrien * If they push back a character then they must push it behind 7159243Sobrien * the text substituted by the history substitution. On the other 7259243Sobrien * hand in several places we need 2 peek characters. To make this 7359243Sobrien * all work, the history routines read with getC, and make use both 7459243Sobrien * of ungetC and unreadc. The key observation is that the state 7559243Sobrien * of getC at the call of a history reference is such that calls 7659243Sobrien * to getC from the history routines will always yield calls of 7759243Sobrien * readc, unless this peeking is involved. That is to say that during 7859243Sobrien * getexcl the variables lap, exclp, and exclnxt are all zero. 7959243Sobrien * 8059243Sobrien * Getdol invokes history substitution, hence the extra peek, peekd, 8159243Sobrien * which it can ungetD to be before history substitutions. 8259243Sobrien */ 8359243Sobrienstatic Char peekc = 0, peekd = 0; 8459243Sobrienstatic Char peekread = 0; 8559243Sobrien 8659243Sobrien/* (Tail of) current word from ! subst */ 8759243Sobrienstatic Char *exclp = NULL; 8859243Sobrien 8959243Sobrien/* The rest of the ! subst words */ 9059243Sobrienstatic struct wordent *exclnxt = NULL; 9159243Sobrien 9259243Sobrien/* Count of remaining words in ! subst */ 9359243Sobrienstatic int exclc = 0; 9459243Sobrien 9559243Sobrien/* "Globp" for alias resubstitution */ 9669408Sacheint aret = TCSH_F_SEEK; 9759243Sobrien 9859243Sobrien/* 9959243Sobrien * Labuf implements a general buffer for lookahead during lexical operations. 10059243Sobrien * Text which is to be placed in the input stream can be stuck here. 10159243Sobrien * We stick parsed ahead $ constructs during initial input, 10259243Sobrien * process id's from `$$', and modified variable values (from qualifiers 10359243Sobrien * during expansion in sh.dol.c) here. 10459243Sobrien */ 105167465Smpstruct Strbuf labuf; /* = Strbuf_INIT; */ 10659243Sobrien 10759243Sobrien/* 10859243Sobrien * Lex returns to its caller not only a wordlist (as a "var" parameter) 10959243Sobrien * but also whether a history substitution occurred. This is used in 11059243Sobrien * the main (process) routine to determine whether to echo, and also 11159243Sobrien * when called by the alias routine to determine whether to keep the 11259243Sobrien * argument list. 11359243Sobrien */ 114145479Smpstatic int hadhist = 0; 11559243Sobrien 11659243Sobrien/* 11759243Sobrien * Avoid alias expansion recursion via \!# 11859243Sobrien */ 11959243Sobrienint hleft; 12059243Sobrien 121167465Smpstruct Strbuf histline; /* = Strbuf_INIT; last line input */ 12259243Sobrien 123145479Smpint histvalid = 0; /* is histline valid */ 12459243Sobrien 12559243Sobrienstatic Char getCtmp; 12659243Sobrien 127145479Smp#define getC(f) (((getCtmp = peekc) != '\0') ? (peekc = 0, (eChar)getCtmp) : getC1(f)) 12859243Sobrien#define ungetC(c) peekc = (Char) c 12959243Sobrien#define ungetD(c) peekd = (Char) c 13059243Sobrien 13159243Sobrien/* Use Htime to store timestamps picked up from history file for enthist() 13259243Sobrien * if reading saved history (sg) 13359243Sobrien */ 13459243Sobrientime_t Htime = (time_t)0; 135167465Smpstatic time_t a2time_t (Char *); 13659243Sobrien 13759243Sobrien/* 138145479Smp * special parsing rules apply for source -h 139145479Smp */ 140145479Smpextern int enterhist; 141354195Sbrooksextern int postcmd_active; 142145479Smp 14359243Sobrienint 144167465Smplex(struct wordent *hp) 14559243Sobrien{ 14659243Sobrien struct wordent *wdp; 147145479Smp eChar c; 148145479Smp int parsehtime = enterhist; 149354195Sbrooks int toolong = 0; 15059243Sobrien 15159243Sobrien histvalid = 0; 152167465Smp histline.len = 0; 15359243Sobrien 154354195Sbrooks if (!postcmd_active) 155354195Sbrooks btell(&lineloc); 15659243Sobrien hp->next = hp->prev = hp; 15759243Sobrien hp->word = STRNULL; 15859243Sobrien hadhist = 0; 15959243Sobrien do 16059243Sobrien c = readc(0); 16159243Sobrien while (c == ' ' || c == '\t'); 162145479Smp if (c == (eChar)HISTSUB && intty) 16359243Sobrien /* ^lef^rit from tty is short !:s^lef^rit */ 16459243Sobrien getexcl(c); 16559243Sobrien else 16659243Sobrien unreadc(c); 167167465Smp cleanup_push(hp, lex_cleanup); 16859243Sobrien wdp = hp; 16959243Sobrien /* 17059243Sobrien * The following loop is written so that the links needed by freelex will 17159243Sobrien * be ready and rarin to go even if it is interrupted. 17259243Sobrien */ 17359243Sobrien do { 17459243Sobrien struct wordent *new; 17559243Sobrien 176167465Smp new = xmalloc(sizeof(*new)); 177167465Smp new->word = NULL; 17859243Sobrien new->prev = wdp; 17959243Sobrien new->next = hp; 18059243Sobrien wdp->next = new; 18159243Sobrien hp->prev = new; 18259243Sobrien wdp = new; 183145479Smp wdp->word = word(parsehtime); 184145479Smp parsehtime = 0; 185354195Sbrooks if (enterhist && toolong++ > 10 * 1024) 186354195Sbrooks stderror(ERR_LTOOLONG); 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 261316957Sdchagininitlex(struct wordent *vp) 262316957Sdchagin{ 263316957Sdchagin vp->word = STRNULL; 264316957Sdchagin vp->prev = vp; 265316957Sdchagin vp->next = vp; 266316957Sdchagin} 267316957Sdchagin 268316957Sdchaginvoid 269167465Smpfreelex(struct wordent *vp) 27059243Sobrien{ 27159243Sobrien struct wordent *fp; 27259243Sobrien 27359243Sobrien while (vp->next != vp) { 27459243Sobrien fp = vp->next; 27559243Sobrien vp->next = fp->next; 276167465Smp xfree(fp->word); 277167465Smp xfree(fp); 27859243Sobrien } 27959243Sobrien vp->prev = vp; 28059243Sobrien} 28159243Sobrien 282167465Smpvoid 283167465Smplex_cleanup(void *xvp) 284167465Smp{ 285167465Smp struct wordent *vp; 286167465Smp 287167465Smp vp = xvp; 288167465Smp freelex(vp); 289167465Smp} 290167465Smp 29159243Sobrienstatic Char * 292167465Smpword(int parsehtime) 29359243Sobrien{ 294145479Smp eChar c, c1; 295167465Smp struct Strbuf wbuf = Strbuf_INIT; 29659243Sobrien Char hbuf[12]; 29759243Sobrien int h; 298145479Smp int dolflg; 299354195Sbrooks int toolong = 0; 30059243Sobrien 301167465Smp cleanup_push(&wbuf, Strbuf_cleanup); 30259243Sobrienloop: 303354195Sbrooks if (enterhist && toolong++ > 256 * 1024) 304354195Sbrooks seterror(ERR_WTOOLONG); 30559243Sobrien while ((c = getC(DOALL)) == ' ' || c == '\t') 30659243Sobrien continue; 30759243Sobrien if (cmap(c, _META | _ESC)) 30859243Sobrien switch (c) { 30959243Sobrien case '&': 31059243Sobrien case '|': 31159243Sobrien case '<': 31259243Sobrien case '>': 313167465Smp Strbuf_append1(&wbuf, c); 31459243Sobrien c1 = getC(DOALL); 31559243Sobrien if (c1 == c) 316167465Smp Strbuf_append1(&wbuf, c1); 31759243Sobrien else 31859243Sobrien ungetC(c1); 31959243Sobrien goto ret; 32059243Sobrien 32159243Sobrien case '#': 322145479Smp if (intty || (enterhist && !parsehtime)) 32359243Sobrien break; 32459243Sobrien c = 0; 32559243Sobrien h = 0; 32659243Sobrien do { 32759243Sobrien c1 = c; 32859243Sobrien c = getC(0); 329145479Smp if (h < 11 && parsehtime) 33059243Sobrien hbuf[h++] = c; 33159243Sobrien } while (c != '\n'); 332145479Smp if (parsehtime) { 333145479Smp hbuf[11] = '\0'; 334145479Smp Htime = a2time_t(hbuf); 335145479Smp } 33659243Sobrien if (c1 == '\\') 33759243Sobrien goto loop; 33859243Sobrien /*FALLTHROUGH*/ 33959243Sobrien 34059243Sobrien case ';': 34159243Sobrien case '(': 34259243Sobrien case ')': 34359243Sobrien case '\n': 344167465Smp Strbuf_append1(&wbuf, c); 34559243Sobrien goto ret; 34659243Sobrien 34759243Sobrien case '\\': 34859243Sobrien c = getC(0); 34959243Sobrien if (c == '\n') { 35059243Sobrien if (onelflg == 1) 35159243Sobrien onelflg = 2; 35259243Sobrien goto loop; 35359243Sobrien } 354145479Smp if (c != (eChar)HIST) 355167465Smp Strbuf_append1(&wbuf, '\\'); 35659243Sobrien c |= QUOTE; 35759243Sobrien default: 35859243Sobrien break; 35959243Sobrien } 36059243Sobrien c1 = 0; 36159243Sobrien dolflg = DOALL; 36259243Sobrien for (;;) { 363354195Sbrooks if (enterhist && toolong++ > 256 * 1024) 364354195Sbrooks seterror(ERR_WTOOLONG); 36559243Sobrien if (c1) { 36659243Sobrien if (c == c1) { 36759243Sobrien c1 = 0; 36859243Sobrien dolflg = DOALL; 36959243Sobrien } 37059243Sobrien else if (c == '\\') { 37159243Sobrien c = getC(0); 37259243Sobrien/* 37359243Sobrien * PWP: this is dumb, but how all of the other shells work. If \ quotes 37459243Sobrien * a character OUTSIDE of a set of ''s, why shouldn't it quote EVERY 37559243Sobrien * following character INSIDE a set of ''s. 37659243Sobrien * 37759243Sobrien * Actually, all I really want to be able to say is 'foo\'bar' --> foo'bar 37859243Sobrien */ 379145479Smp if (c == (eChar)HIST) 38059243Sobrien c |= QUOTE; 38159243Sobrien else { 38259243Sobrien if (bslash_quote && 38359243Sobrien ((c == '\'') || (c == '"') || 384195609Smp (c == '\\') || (c == '$'))) { 38559243Sobrien c |= QUOTE; 38659243Sobrien } 38759243Sobrien else { 38859243Sobrien if (c == '\n') 38959243Sobrien /* 39059243Sobrien * if (c1 == '`') c = ' '; else 39159243Sobrien */ 39259243Sobrien c |= QUOTE; 39359243Sobrien ungetC(c); 394316957Sdchagin c = '\\' | QUOTE; 39559243Sobrien } 39659243Sobrien } 39759243Sobrien } 39859243Sobrien else if (c == '\n') { 39959243Sobrien seterror(ERR_UNMATCHED, c1); 40059243Sobrien ungetC(c); 40159243Sobrien break; 40259243Sobrien } 40359243Sobrien } 40459243Sobrien else if (cmap(c, _META | _QF | _QB | _ESC)) { 40559243Sobrien if (c == '\\') { 40659243Sobrien c = getC(0); 40759243Sobrien if (c == '\n') { 40859243Sobrien if (onelflg == 1) 40959243Sobrien onelflg = 2; 41059243Sobrien break; 41159243Sobrien } 412145479Smp if (c != (eChar)HIST) 413167465Smp Strbuf_append1(&wbuf, '\\'); 41459243Sobrien c |= QUOTE; 41559243Sobrien } 41659243Sobrien else if (cmap(c, _QF | _QB)) { /* '"` */ 41759243Sobrien c1 = c; 41859243Sobrien dolflg = c == '"' ? DOALL : DOEXCL; 41959243Sobrien } 420145479Smp else if (c != '#' || (!intty && !enterhist)) { 42159243Sobrien ungetC(c); 42259243Sobrien break; 42359243Sobrien } 42459243Sobrien } 425167465Smp Strbuf_append1(&wbuf, c); 426167465Smp c = getC(dolflg); 42759243Sobrien } 42859243Sobrienret: 429167465Smp cleanup_ignore(&wbuf); 430167465Smp cleanup_until(&wbuf); 431167465Smp return Strbuf_finish(&wbuf); 43259243Sobrien} 43359243Sobrien 434145479Smpstatic eChar 435167465SmpgetC1(int flag) 43659243Sobrien{ 437145479Smp eChar c; 43859243Sobrien 43959243Sobrien for (;;) { 44059243Sobrien if ((c = peekc) != 0) { 44159243Sobrien peekc = 0; 44259243Sobrien return (c); 44359243Sobrien } 444167465Smp if (lap < labuf.len) { 445167465Smp c = labuf.s[lap++]; 446167465Smp if (cmap(c, _META | _QF | _QB)) 447167465Smp c |= QUOTE; 448167465Smp return (c); 44959243Sobrien } 45059243Sobrien if ((c = peekd) != 0) { 45159243Sobrien peekd = 0; 45259243Sobrien return (c); 45359243Sobrien } 45459243Sobrien if (exclp) { 45559243Sobrien if ((c = *exclp++) != 0) 45659243Sobrien return (c); 45759243Sobrien if (exclnxt && --exclc >= 0) { 45859243Sobrien exclnxt = exclnxt->next; 45959243Sobrien setexclp(exclnxt->word); 46059243Sobrien return (' '); 46159243Sobrien } 46259243Sobrien exclp = 0; 46359243Sobrien exclnxt = 0; 46459243Sobrien /* this will throw away the dummy history entries */ 46559243Sobrien savehist(NULL, 0); 46659243Sobrien 46759243Sobrien } 46859243Sobrien if (exclnxt) { 46959243Sobrien exclnxt = exclnxt->next; 47059243Sobrien if (--exclc < 0) 47159243Sobrien exclnxt = 0; 47259243Sobrien else 47359243Sobrien setexclp(exclnxt->word); 47459243Sobrien continue; 47559243Sobrien } 476231990Smp c = readc(1); 477231990Smp 478231990Smp /* Catch EOF in the middle of a line. (An EOF at the beginning of 479231990Smp * a line would have been processed by the readc(0) in lex().) */ 480231990Smp if (c == CHAR_ERR) 481231990Smp c = '\n'; 482231990Smp 48359243Sobrien if (c == '$' && (flag & DODOL)) { 48459243Sobrien getdol(); 48559243Sobrien continue; 48659243Sobrien } 487145479Smp if (c == (eChar)HIST && (flag & DOEXCL)) { 48859243Sobrien getexcl(0); 48959243Sobrien continue; 49059243Sobrien } 49159243Sobrien break; 49259243Sobrien } 49359243Sobrien return (c); 49459243Sobrien} 49559243Sobrien 49659243Sobrienstatic void 497167465Smpgetdol(void) 49859243Sobrien{ 499167465Smp struct Strbuf name = Strbuf_INIT; 500145479Smp eChar c; 501145479Smp eChar sc; 502167465Smp int special = 0; 50359243Sobrien 50459243Sobrien c = sc = getC(DOEXCL); 50559243Sobrien if (any("\t \n", c)) { 50659243Sobrien ungetD(c); 50759243Sobrien ungetC('$' | QUOTE); 50859243Sobrien return; 50959243Sobrien } 510167465Smp cleanup_push(&name, Strbuf_cleanup); 511167465Smp Strbuf_append1(&name, '$'); 51259243Sobrien if (c == '{') 513167465Smp Strbuf_append1(&name, c), c = getC(DOEXCL); 51459243Sobrien if (c == '#' || c == '?' || c == '%') 515167465Smp special++, Strbuf_append1(&name, c), c = getC(DOEXCL); 516167465Smp Strbuf_append1(&name, c); 51759243Sobrien switch (c) { 51859243Sobrien 51959243Sobrien case '<': 52059243Sobrien case '$': 52159243Sobrien case '!': 52259243Sobrien if (special) 52359243Sobrien seterror(ERR_SPDOLLT); 524167465Smp goto end; 52559243Sobrien 52659243Sobrien case '\n': 52759243Sobrien ungetD(c); 528167465Smp name.len--; 52959243Sobrien if (!special) 53059243Sobrien seterror(ERR_NEWLINE); 531167465Smp goto end; 53259243Sobrien 53359243Sobrien case '*': 53459243Sobrien if (special) 53559243Sobrien seterror(ERR_SPSTAR); 536167465Smp goto end; 53759243Sobrien 53859243Sobrien default: 53959243Sobrien if (Isdigit(c)) { 54059243Sobrien#ifdef notdef 54159243Sobrien /* let $?0 pass for now */ 54259243Sobrien if (special) { 54359243Sobrien seterror(ERR_DIGIT); 544167465Smp goto end; 54559243Sobrien } 54659243Sobrien#endif 54759243Sobrien while ((c = getC(DOEXCL)) != 0) { 54859243Sobrien if (!Isdigit(c)) 54959243Sobrien break; 550167465Smp Strbuf_append1(&name, c); 55159243Sobrien } 55259243Sobrien } 55359243Sobrien else if (letter(c)) { 55459243Sobrien while ((c = getC(DOEXCL)) != 0) { 55559243Sobrien /* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */ 55659243Sobrien if (!letter(c) && !Isdigit(c)) 55759243Sobrien break; 558167465Smp Strbuf_append1(&name, c); 55959243Sobrien } 56059243Sobrien } 56159243Sobrien else { 56259243Sobrien if (!special) 56359243Sobrien seterror(ERR_VARILL); 56459243Sobrien else { 56559243Sobrien ungetD(c); 566167465Smp name.len--; 56759243Sobrien } 568167465Smp goto end; 56959243Sobrien } 57059243Sobrien break; 57159243Sobrien } 57259243Sobrien if (c == '[') { 573167465Smp Strbuf_append1(&name, c); 57459243Sobrien do { 57559243Sobrien /* 57659243Sobrien * Michael Greim: Allow $ expansion to take place in selector 57759243Sobrien * expressions. (limits the number of characters returned) 57859243Sobrien */ 57959243Sobrien c = getC(DOEXCL | DODOL); 58059243Sobrien if (c == '\n') { 58159243Sobrien ungetD(c); 582167465Smp name.len--; 58359243Sobrien seterror(ERR_NLINDEX); 584167465Smp goto end; 58559243Sobrien } 586167465Smp Strbuf_append1(&name, c); 58759243Sobrien } while (c != ']'); 58859243Sobrien c = getC(DOEXCL); 58959243Sobrien } 59059243Sobrien if (c == ':') { 59159243Sobrien /* 59259243Sobrien * if the :g modifier is followed by a newline, then error right away! 59359243Sobrien * -strike 59459243Sobrien */ 59559243Sobrien 59659243Sobrien int gmodflag = 0, amodflag = 0; 59759243Sobrien 59859243Sobrien do { 599167465Smp Strbuf_append1(&name, c), c = getC(DOEXCL); 60059243Sobrien if (c == 'g' || c == 'a') { 60159243Sobrien if (c == 'g') 60259243Sobrien gmodflag++; 60359243Sobrien else 60459243Sobrien amodflag++; 605167465Smp Strbuf_append1(&name, c); c = getC(DOEXCL); 60659243Sobrien } 60759243Sobrien if ((c == 'g' && !gmodflag) || (c == 'a' && !amodflag)) { 60859243Sobrien if (c == 'g') 60959243Sobrien gmodflag++; 61059243Sobrien else 61159243Sobrien amodflag++; 612167465Smp Strbuf_append1(&name, c); c = getC(DOEXCL); 61359243Sobrien } 614167465Smp Strbuf_append1(&name, c); 61559243Sobrien /* scan s// [eichin:19910926.0512EST] */ 61659243Sobrien if (c == 's') { 61759243Sobrien int delimcnt = 2; 618145479Smp eChar delim = getC(0); 619167465Smp 620167465Smp Strbuf_append1(&name, delim); 62159243Sobrien if (!delim || letter(delim) 62259243Sobrien || Isdigit(delim) || any(" \t\n", delim)) { 62359243Sobrien seterror(ERR_BADSUBST); 62459243Sobrien break; 625167465Smp } 626145479Smp while ((c = getC(0)) != CHAR_ERR) { 627167465Smp Strbuf_append1(&name, c); 62859243Sobrien if(c == delim) delimcnt--; 62959243Sobrien if(!delimcnt) break; 63059243Sobrien } 63159243Sobrien if(delimcnt) { 63259243Sobrien seterror(ERR_BADSUBST); 63359243Sobrien break; 63459243Sobrien } 63559243Sobrien c = 's'; 63659243Sobrien } 63759243Sobrien if (!any("htrqxesul", c)) { 63859243Sobrien if ((amodflag || gmodflag) && c == '\n') 63959243Sobrien stderror(ERR_VARSYN); /* strike */ 64059243Sobrien seterror(ERR_BADMOD, c); 641167465Smp goto end; 64259243Sobrien } 64359243Sobrien } 64459243Sobrien while ((c = getC(DOEXCL)) == ':'); 64559243Sobrien ungetD(c); 64659243Sobrien } 64759243Sobrien else 64859243Sobrien ungetD(c); 64959243Sobrien if (sc == '{') { 65059243Sobrien c = getC(DOEXCL); 65159243Sobrien if (c != '}') { 65259243Sobrien ungetD(c); 65359243Sobrien seterror(ERR_MISSING, '}'); 654167465Smp goto end; 65559243Sobrien } 656167465Smp Strbuf_append1(&name, c); 65759243Sobrien } 658167465Smp end: 659167465Smp cleanup_ignore(&name); 660167465Smp cleanup_until(&name); 661167465Smp addla(Strbuf_finish(&name)); 66259243Sobrien} 66359243Sobrien 664167465Smp/* xfree()'s its argument */ 66559243Sobrienvoid 666167465Smpaddla(Char *cp) 66759243Sobrien{ 668167465Smp static struct Strbuf buf; /* = Strbuf_INIT; */ 66959243Sobrien 670167465Smp buf.len = 0; 671167465Smp Strbuf_appendn(&buf, labuf.s + lap, labuf.len - lap); 672167465Smp labuf.len = 0; 673167465Smp Strbuf_append(&labuf, cp); 674167465Smp Strbuf_terminate(&labuf); 675167465Smp Strbuf_appendn(&labuf, buf.s, buf.len); 676167465Smp xfree(cp); 677167465Smp lap = 0; 67859243Sobrien} 67959243Sobrien 680167465Smp/* left-hand side of last :s or search string of last ?event? */ 681167465Smpstatic struct Strbuf lhsb; /* = Strbuf_INIT; */ 682167465Smpstatic struct Strbuf slhs; /* = Strbuf_INIT; left-hand side of last :s */ 683167465Smpstatic struct Strbuf rhsb; /* = Strbuf_INIT; right-hand side of last :s */ 68459243Sobrienstatic int quesarg; 68559243Sobrien 68659243Sobrienstatic void 687167465Smpgetexcl(Char sc) 68859243Sobrien{ 68959243Sobrien struct wordent *hp, *ip; 69059243Sobrien int left, right, dol; 691145479Smp eChar c; 69259243Sobrien 69359243Sobrien if (sc == 0) { 694231990Smp c = getC(0); 695231990Smp if (c == '{') 696231990Smp sc = (Char) c; 697231990Smp else 698231990Smp ungetC(c); 69959243Sobrien } 70059243Sobrien quesarg = -1; 70159243Sobrien 702167465Smp lastev = eventno; 70359243Sobrien hp = gethent(sc); 70459243Sobrien if (hp == 0) 70559243Sobrien return; 70659243Sobrien hadhist = 1; 70759243Sobrien dol = 0; 70859243Sobrien if (hp == alhistp) 70959243Sobrien for (ip = hp->next->next; ip != alhistt; ip = ip->next) 71059243Sobrien dol++; 71159243Sobrien else 71259243Sobrien for (ip = hp->next->next; ip != hp->prev; ip = ip->next) 71359243Sobrien dol++; 71459243Sobrien left = 0, right = dol; 715231990Smp if (sc == HISTSUB && HISTSUB != '\0') { 71659243Sobrien ungetC('s'), unreadc(HISTSUB), c = ':'; 71759243Sobrien goto subst; 71859243Sobrien } 71959243Sobrien c = getC(0); 72059243Sobrien if (!any(":^$*-%", c)) 72159243Sobrien goto subst; 72259243Sobrien left = right = -1; 72359243Sobrien if (c == ':') { 72459243Sobrien c = getC(0); 72559243Sobrien unreadc(c); 72659243Sobrien if (letter(c) || c == '&') { 72759243Sobrien c = ':'; 72859243Sobrien left = 0, right = dol; 72959243Sobrien goto subst; 73059243Sobrien } 73159243Sobrien } 73259243Sobrien else 73359243Sobrien ungetC(c); 73459243Sobrien if (!getsel(&left, &right, dol)) 73559243Sobrien return; 73659243Sobrien c = getC(0); 73759243Sobrien if (c == '*') 73859243Sobrien ungetC(c), c = '-'; 73959243Sobrien if (c == '-') { 74059243Sobrien if (!getsel(&left, &right, dol)) 74159243Sobrien return; 74259243Sobrien c = getC(0); 74359243Sobrien } 74459243Sobriensubst: 74559243Sobrien exclc = right - left + 1; 74659243Sobrien while (--left >= 0) 74759243Sobrien hp = hp->next; 748231990Smp if ((sc == HISTSUB && HISTSUB != '\0') || c == ':') { 74959243Sobrien do { 75059243Sobrien hp = getsub(hp); 75159243Sobrien c = getC(0); 75259243Sobrien } while (c == ':'); 75359243Sobrien } 75459243Sobrien unreadc(c); 75559243Sobrien if (sc == '{') { 75659243Sobrien c = getC(0); 75759243Sobrien if (c != '}') 75859243Sobrien seterror(ERR_BADBANG); 75959243Sobrien } 76059243Sobrien exclnxt = hp; 76159243Sobrien} 76259243Sobrien 76359243Sobrienstatic struct wordent * 764167465Smpgetsub(struct wordent *en) 76559243Sobrien{ 766145479Smp eChar delim; 767145479Smp eChar c; 768145479Smp eChar sc; 769145479Smp int global; 77059243Sobrien 77159243Sobrien do { 77259243Sobrien exclnxt = 0; 77359243Sobrien global = 0; 77459243Sobrien sc = c = getC(0); 775167465Smp while (c == 'g' || c == 'a') { 776167465Smp global |= (c == 'g') ? FLAG_G : FLAG_A; 77759243Sobrien sc = c = getC(0); 77859243Sobrien } 77959243Sobrien 78059243Sobrien switch (c) { 78159243Sobrien case 'p': 78259243Sobrien justpr++; 78359243Sobrien return (en); 78459243Sobrien 78559243Sobrien case 'x': 78659243Sobrien case 'q': 787167465Smp global |= FLAG_G; 78859243Sobrien /*FALLTHROUGH*/ 78959243Sobrien 79059243Sobrien case 'h': 79159243Sobrien case 'r': 79259243Sobrien case 't': 79359243Sobrien case 'e': 79459243Sobrien case 'u': 79559243Sobrien case 'l': 79659243Sobrien break; 79759243Sobrien 79859243Sobrien case '&': 799167465Smp if (slhs.len == 0) { 80059243Sobrien seterror(ERR_NOSUBST); 80159243Sobrien return (en); 80259243Sobrien } 803167465Smp lhsb.len = 0; 804167465Smp Strbuf_append(&lhsb, slhs.s); 805167465Smp Strbuf_terminate(&lhsb); 80659243Sobrien break; 80759243Sobrien 80859243Sobrien#ifdef notdef 80959243Sobrien case '~': 810167465Smp if (lhsb.len == 0) 81159243Sobrien goto badlhs; 81259243Sobrien break; 81359243Sobrien#endif 81459243Sobrien 81559243Sobrien case 's': 81659243Sobrien delim = getC(0); 81759243Sobrien if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) { 81859243Sobrien unreadc(delim); 819167465Smp lhsb.len = 0; 82059243Sobrien seterror(ERR_BADSUBST); 82159243Sobrien return (en); 82259243Sobrien } 823167465Smp Strbuf_terminate(&lhsb); 824167465Smp lhsb.len = 0; 82559243Sobrien for (;;) { 82659243Sobrien c = getC(0); 82759243Sobrien if (c == '\n') { 82859243Sobrien unreadc(c); 82959243Sobrien break; 83059243Sobrien } 83159243Sobrien if (c == delim) 83259243Sobrien break; 83359243Sobrien if (c == '\\') { 83459243Sobrien c = getC(0); 83559243Sobrien if (c != delim && c != '\\') 836167465Smp Strbuf_append1(&lhsb, '\\'); 83759243Sobrien } 838167465Smp Strbuf_append1(&lhsb, c); 83959243Sobrien } 840167465Smp if (lhsb.len != 0) 841167465Smp Strbuf_terminate(&lhsb); 842167465Smp else if (lhsb.s[0] == 0) { 84359243Sobrien seterror(ERR_LHS); 84459243Sobrien return (en); 845167465Smp } else 846167465Smp lhsb.len = Strlen(lhsb.s); /* lhsb.s wasn't changed */ 847167465Smp rhsb.len = 0; 84859243Sobrien for (;;) { 84959243Sobrien c = getC(0); 85059243Sobrien if (c == '\n') { 85159243Sobrien unreadc(c); 85259243Sobrien break; 85359243Sobrien } 85459243Sobrien if (c == delim) 85559243Sobrien break; 85659243Sobrien if (c == '\\') { 85759243Sobrien c = getC(0); 85859243Sobrien if (c != delim /* && c != '~' */ ) 859167465Smp Strbuf_append1(&rhsb, '\\'); 86059243Sobrien } 861167465Smp Strbuf_append1(&rhsb, c); 86259243Sobrien } 863167465Smp Strbuf_terminate(&rhsb); 86459243Sobrien break; 86559243Sobrien 86659243Sobrien default: 86759243Sobrien if (c == '\n') 86859243Sobrien unreadc(c); 869145479Smp seterror(ERR_BADBANGMOD, (int)c); 87059243Sobrien return (en); 87159243Sobrien } 872167465Smp slhs.len = 0; 873177128Sdelphij if (lhsb.s != NULL && lhsb.len != 0) 874177128Sdelphij Strbuf_append(&slhs, lhsb.s); 875167465Smp Strbuf_terminate(&slhs); 87659243Sobrien if (exclc) 87759243Sobrien en = dosub(sc, en, global); 87859243Sobrien } 87959243Sobrien while ((c = getC(0)) == ':'); 88059243Sobrien unreadc(c); 88159243Sobrien return (en); 88259243Sobrien} 88359243Sobrien 88459243Sobrien/* 88559243Sobrien * 88659243Sobrien * From Beto Appleton (beto@aixwiz.austin.ibm.com) 88759243Sobrien * 88859243Sobrien * when using history substitution, and the variable 88959243Sobrien * 'history' is set to a value higher than 1000, 89059243Sobrien * the shell might either freeze (hang) or core-dump. 89159243Sobrien * We raise the limit to 50000000 89259243Sobrien */ 89359243Sobrien 89459243Sobrien#define HIST_PURGE -50000000 89559243Sobrienstatic struct wordent * 896167465Smpdosub(Char sc, struct wordent *en, int global) 89759243Sobrien{ 89859243Sobrien struct wordent lexi; 899145479Smp int didsub = 0, didone = 0; 90059243Sobrien struct wordent *hp = &lexi; 90159243Sobrien struct wordent *wdp; 90259243Sobrien int i = exclc; 90359243Sobrien struct Hist *hst; 90459243Sobrien 90559243Sobrien wdp = hp; 90659243Sobrien while (--i >= 0) { 907167465Smp struct wordent *new = xcalloc(1, sizeof *wdp); 90859243Sobrien 90959243Sobrien new->word = 0; 91059243Sobrien new->prev = wdp; 91159243Sobrien new->next = hp; 91259243Sobrien wdp->next = new; 91359243Sobrien wdp = new; 91459243Sobrien en = en->next; 91559243Sobrien if (en->word) { 91659243Sobrien Char *tword, *otword; 91759243Sobrien 918167465Smp if ((global & FLAG_G) || didsub == 0) { 919167465Smp size_t pos; 920167465Smp 921167465Smp pos = 0; 922167465Smp tword = subword(en->word, sc, &didone, &pos); 92359243Sobrien if (didone) 92459243Sobrien didsub = 1; 925167465Smp if (global & FLAG_A) { 92659243Sobrien while (didone && tword != STRNULL) { 92759243Sobrien otword = tword; 928167465Smp tword = subword(otword, sc, &didone, &pos); 92959243Sobrien if (Strcmp(tword, otword) == 0) { 930167465Smp xfree(otword); 93159243Sobrien break; 93259243Sobrien } 93359243Sobrien else 934167465Smp xfree(otword); 93559243Sobrien } 93659243Sobrien } 93759243Sobrien } 93859243Sobrien else 93959243Sobrien tword = Strsave(en->word); 94059243Sobrien wdp->word = tword; 94159243Sobrien } 94259243Sobrien } 94359243Sobrien if (didsub == 0) 94459243Sobrien seterror(ERR_MODFAIL); 94559243Sobrien hp->prev = wdp; 94659243Sobrien /* 94759243Sobrien * ANSI mode HP/UX compiler chokes on 94859243Sobrien * return &enthist(HIST_PURGE, &lexi, 0)->Hlex; 94959243Sobrien */ 950231990Smp hst = enthist(HIST_PURGE, &lexi, 0, 0, -1); 95159243Sobrien return &(hst->Hlex); 95259243Sobrien} 95359243Sobrien 954167465Smp/* Return a newly allocated result of one modification of CP using the 955167465Smp operation TYPE. Set ADID to 1 if a modification was performed. 956167465Smp If TYPE == 's', perform substitutions only from *START_POS on and set 957167465Smp *START_POS to the position of next substitution attempt. */ 95859243Sobrienstatic Char * 959167465Smpsubword(Char *cp, Char type, int *adid, size_t *start_pos) 96059243Sobrien{ 961167465Smp Char *wp; 962167465Smp const Char *mp, *np; 96359243Sobrien 96459243Sobrien switch (type) { 96559243Sobrien 96659243Sobrien case 'r': 96759243Sobrien case 'e': 96859243Sobrien case 'h': 96959243Sobrien case 't': 97059243Sobrien case 'q': 97159243Sobrien case 'x': 97259243Sobrien case 'u': 97359243Sobrien case 'l': 97459243Sobrien wp = domod(cp, type); 975167465Smp if (wp == 0) { 976167465Smp *adid = 0; 97759243Sobrien return (Strsave(cp)); 978167465Smp } 97959243Sobrien *adid = 1; 98059243Sobrien return (wp); 98159243Sobrien 98259243Sobrien default: 983167465Smp for (mp = cp + *start_pos; *mp; mp++) { 984167465Smp if (matchs(mp, lhsb.s)) { 985167465Smp struct Strbuf wbuf = Strbuf_INIT; 986167465Smp 987167465Smp Strbuf_appendn(&wbuf, cp, mp - cp); 988167465Smp for (np = rhsb.s; *np; np++) 98959243Sobrien switch (*np) { 99059243Sobrien 99159243Sobrien case '\\': 99259243Sobrien if (np[1] == '&') 99359243Sobrien np++; 99459243Sobrien /* fall into ... */ 99559243Sobrien 99659243Sobrien default: 997167465Smp Strbuf_append1(&wbuf, *np); 99859243Sobrien continue; 99959243Sobrien 100059243Sobrien case '&': 1001167465Smp Strbuf_append(&wbuf, lhsb.s); 100259243Sobrien continue; 100359243Sobrien } 1004167465Smp *start_pos = wbuf.len; 1005167465Smp Strbuf_append(&wbuf, mp + lhsb.len); 100659243Sobrien *adid = 1; 1007167465Smp return Strbuf_finish(&wbuf); 100859243Sobrien } 1009167465Smp } 1010167465Smp *adid = 0; 101159243Sobrien return (Strsave(cp)); 101259243Sobrien } 101359243Sobrien} 101459243Sobrien 101559243SobrienChar * 1016167465Smpdomod(Char *cp, Char type) 101759243Sobrien{ 101859243Sobrien Char *wp, *xp; 101959243Sobrien int c; 102059243Sobrien 102159243Sobrien switch (type) { 102259243Sobrien 1023354195Sbrooks case 'q': 102459243Sobrien case 'x': 1025354195Sbrooks if (*cp == '\0') 1026354195Sbrooks return Strsave(STRQNULL); 102759243Sobrien wp = Strsave(cp); 102859243Sobrien for (xp = wp; (c = *xp) != 0; xp++) 102959243Sobrien if ((c != ' ' && c != '\t') || type == 'q') 103059243Sobrien *xp |= QUOTE; 103159243Sobrien return (wp); 103259243Sobrien 103359243Sobrien case 'l': 1034145479Smp wp = NLSChangeCase(cp, 1); 1035145479Smp return wp ? wp : Strsave(cp); 103659243Sobrien 103759243Sobrien case 'u': 1038145479Smp wp = NLSChangeCase(cp, 0); 1039145479Smp return wp ? wp : Strsave(cp); 104059243Sobrien 104159243Sobrien case 'h': 104259243Sobrien case 't': 104359243Sobrien if (!any(short2str(cp), '/')) 104459243Sobrien return (type == 't' ? Strsave(cp) : 0); 1045167465Smp wp = Strrchr(cp, '/'); 104659243Sobrien if (type == 'h') 1047167465Smp xp = Strnsave(cp, wp - cp); 104859243Sobrien else 104959243Sobrien xp = Strsave(wp + 1); 105059243Sobrien return (xp); 105159243Sobrien 105259243Sobrien case 'e': 105359243Sobrien case 'r': 105459243Sobrien wp = Strend(cp); 105559243Sobrien for (wp--; wp >= cp && *wp != '/'; wp--) 105659243Sobrien if (*wp == '.') { 105759243Sobrien if (type == 'e') 105859243Sobrien xp = Strsave(wp + 1); 105959243Sobrien else 1060167465Smp xp = Strnsave(cp, wp - cp); 106159243Sobrien return (xp); 106259243Sobrien } 106359243Sobrien return (Strsave(type == 'e' ? STRNULL : cp)); 106459243Sobrien default: 106559243Sobrien break; 106659243Sobrien } 106759243Sobrien return (0); 106859243Sobrien} 106959243Sobrien 107059243Sobrienstatic int 1071167465Smpmatchs(const Char *str, const Char *pat) 107259243Sobrien{ 107359243Sobrien while (*str && *pat && *str == *pat) 107459243Sobrien str++, pat++; 107559243Sobrien return (*pat == 0); 107659243Sobrien} 107759243Sobrien 107859243Sobrienstatic int 1079167465Smpgetsel(int *al, int *ar, int dol) 108059243Sobrien{ 1081145479Smp eChar c = getC(0); 108259243Sobrien int i; 1083145479Smp int first = *al < 0; 108459243Sobrien 108559243Sobrien switch (c) { 108659243Sobrien 108759243Sobrien case '%': 108859243Sobrien if (quesarg == -1) { 108959243Sobrien seterror(ERR_BADBANGARG); 109059243Sobrien return (0); 109159243Sobrien } 109259243Sobrien if (*al < 0) 109359243Sobrien *al = quesarg; 109459243Sobrien *ar = quesarg; 109559243Sobrien break; 109659243Sobrien 109759243Sobrien case '-': 109859243Sobrien if (*al < 0) { 109959243Sobrien *al = 0; 110059243Sobrien *ar = dol - 1; 110159243Sobrien unreadc(c); 110259243Sobrien } 110359243Sobrien return (1); 110459243Sobrien 110559243Sobrien case '^': 110659243Sobrien if (*al < 0) 110759243Sobrien *al = 1; 110859243Sobrien *ar = 1; 110959243Sobrien break; 111059243Sobrien 111159243Sobrien case '$': 111259243Sobrien if (*al < 0) 111359243Sobrien *al = dol; 111459243Sobrien *ar = dol; 111559243Sobrien break; 111659243Sobrien 111759243Sobrien case '*': 111859243Sobrien if (*al < 0) 111959243Sobrien *al = 1; 112059243Sobrien *ar = dol; 112159243Sobrien if (*ar < *al) { 112259243Sobrien *ar = 0; 112359243Sobrien *al = 1; 112459243Sobrien return (1); 112559243Sobrien } 112659243Sobrien break; 112759243Sobrien 112859243Sobrien default: 112959243Sobrien if (Isdigit(c)) { 113059243Sobrien i = 0; 113159243Sobrien while (Isdigit(c)) { 113259243Sobrien i = i * 10 + c - '0'; 113359243Sobrien c = getC(0); 113459243Sobrien } 113559243Sobrien if (i < 0) 113659243Sobrien i = dol + 1; 113759243Sobrien if (*al < 0) 113859243Sobrien *al = i; 113959243Sobrien *ar = i; 114059243Sobrien } 114159243Sobrien else if (*al < 0) 114259243Sobrien *al = 0, *ar = dol; 114359243Sobrien else 114459243Sobrien *ar = dol - 1; 114559243Sobrien unreadc(c); 114659243Sobrien break; 114759243Sobrien } 114859243Sobrien if (first) { 114959243Sobrien c = getC(0); 115059243Sobrien unreadc(c); 115159243Sobrien if (any("-$*", c)) 115259243Sobrien return (1); 115359243Sobrien } 115459243Sobrien if (*al > *ar || *ar > dol) { 115559243Sobrien seterror(ERR_BADBANGARG); 115659243Sobrien return (0); 115759243Sobrien } 115859243Sobrien return (1); 115959243Sobrien 116059243Sobrien} 116159243Sobrien 116259243Sobrienstatic struct wordent * 1163167465Smpgethent(Char sc) 116459243Sobrien{ 116559243Sobrien struct Hist *hp; 116659243Sobrien Char *np; 1167145479Smp eChar c; 116859243Sobrien int event; 1169145479Smp int back = 0; 117059243Sobrien 1171231990Smp c = (sc == HISTSUB && HISTSUB != '\0') ? (eChar)HIST : getC(0); 1172145479Smp if (c == (eChar)HIST) { 117359243Sobrien if (alhistp) 117459243Sobrien return (alhistp); 117559243Sobrien event = eventno; 117659243Sobrien } 117759243Sobrien else 117859243Sobrien switch (c) { 117959243Sobrien 118059243Sobrien case ':': 118159243Sobrien case '^': 118259243Sobrien case '$': 118359243Sobrien case '*': 118459243Sobrien case '%': 118559243Sobrien ungetC(c); 118659243Sobrien if (lastev == eventno && alhistp) 118759243Sobrien return (alhistp); 118859243Sobrien event = lastev; 118959243Sobrien break; 119059243Sobrien 119159243Sobrien case '#': /* !# is command being typed in (mrh) */ 119259243Sobrien if (--hleft == 0) { 119359243Sobrien seterror(ERR_HISTLOOP); 119459243Sobrien return (0); 119559243Sobrien } 119659243Sobrien else 119759243Sobrien return (¶ml); 119859243Sobrien /* NOTREACHED */ 119959243Sobrien 120059243Sobrien case '-': 120159243Sobrien back = 1; 120259243Sobrien c = getC(0); 120359243Sobrien /* FALLSTHROUGH */ 120459243Sobrien 120559243Sobrien default: 120659243Sobrien if (any("(=~", c)) { 120759243Sobrien unreadc(c); 120859243Sobrien ungetC(HIST); 120959243Sobrien return (0); 121059243Sobrien } 1211167465Smp Strbuf_terminate(&lhsb); 1212167465Smp lhsb.len = 0; 121359243Sobrien event = 0; 121459243Sobrien while (!cmap(c, _ESC | _META | _QF | _QB) && !any("^*-%${}:#", c)) { 121559243Sobrien if (event != -1 && Isdigit(c)) 121659243Sobrien event = event * 10 + c - '0'; 121759243Sobrien else 121859243Sobrien event = -1; 1219167465Smp Strbuf_append1(&lhsb, c); 122059243Sobrien c = getC(0); 122159243Sobrien } 122259243Sobrien unreadc(c); 1223167465Smp if (lhsb.len == 0) { 1224167465Smp lhsb.len = Strlen(lhsb.s); /* lhsb.s wasn't changed */ 122559243Sobrien ungetC(HIST); 122659243Sobrien return (0); 122759243Sobrien } 1228167465Smp Strbuf_terminate(&lhsb); 122959243Sobrien if (event != -1) { 123059243Sobrien /* 123159243Sobrien * History had only digits 123259243Sobrien */ 123359243Sobrien if (back) 1234167465Smp event = eventno + (alhistp == 0) - event; 123559243Sobrien break; 123659243Sobrien } 123759243Sobrien if (back) { 1238167465Smp Strbuf_append1(&lhsb, '\0'); /* Allocate space */ 1239167465Smp Strbuf_terminate(&lhsb); 1240167465Smp memmove(lhsb.s + 1, lhsb.s, (lhsb.len - 1) * sizeof (*lhsb.s)); 1241167465Smp lhsb.s[0] = '-'; 124259243Sobrien } 1243167465Smp hp = findev(lhsb.s, 0); 124459243Sobrien if (hp) 124559243Sobrien lastev = hp->Hnum; 124659243Sobrien return (&hp->Hlex); 124759243Sobrien 124859243Sobrien case '?': 1249167465Smp Strbuf_terminate(&lhsb); 1250167465Smp lhsb.len = 0; 125159243Sobrien for (;;) { 125259243Sobrien c = getC(0); 125359243Sobrien if (c == '\n') { 125459243Sobrien unreadc(c); 125559243Sobrien break; 125659243Sobrien } 125759243Sobrien if (c == '?') 125859243Sobrien break; 1259167465Smp Strbuf_append1(&lhsb, c); 126059243Sobrien } 1261167465Smp if (lhsb.len == 0) { 1262167465Smp lhsb.len = Strlen(lhsb.s); /* lhsb.s wasn't changed */ 1263167465Smp if (lhsb.len == 0) { 126459243Sobrien seterror(ERR_NOSEARCH); 126559243Sobrien return (0); 126659243Sobrien } 126759243Sobrien } 126859243Sobrien else 1269167465Smp Strbuf_terminate(&lhsb); 1270167465Smp hp = findev(lhsb.s, 1); 127159243Sobrien if (hp) 127259243Sobrien lastev = hp->Hnum; 127359243Sobrien return (&hp->Hlex); 127459243Sobrien } 127559243Sobrien 127659243Sobrien for (hp = Histlist.Hnext; hp; hp = hp->Hnext) 127759243Sobrien if (hp->Hnum == event) { 127859243Sobrien hp->Href = eventno; 127959243Sobrien lastev = hp->Hnum; 128059243Sobrien return (&hp->Hlex); 128159243Sobrien } 1282231990Smp np = putn((tcsh_number_t)event); 128359243Sobrien seterror(ERR_NOEVENT, short2str(np)); 1284167465Smp xfree(np); 128559243Sobrien return (0); 128659243Sobrien} 128759243Sobrien 128859243Sobrienstatic struct Hist * 1289167465Smpfindev(Char *cp, int anyarg) 129059243Sobrien{ 129159243Sobrien struct Hist *hp; 129259243Sobrien 129359243Sobrien for (hp = Histlist.Hnext; hp; hp = hp->Hnext) { 129459243Sobrien Char *dp; 129559243Sobrien Char *p, *q; 129659243Sobrien struct wordent *lp = hp->Hlex.next; 129759243Sobrien int argno = 0; 129859243Sobrien 129959243Sobrien /* 130059243Sobrien * The entries added by alias substitution don't have a newline but do 130159243Sobrien * have a negative event number. Savehist() trims off these entries, 130259243Sobrien * but it happens before alias expansion, too early to delete those 130359243Sobrien * from the previous command. 130459243Sobrien */ 130559243Sobrien if (hp->Hnum < 0) 130659243Sobrien continue; 130759243Sobrien if (lp->word[0] == '\n') 130859243Sobrien continue; 130959243Sobrien if (!anyarg) { 131059243Sobrien p = cp; 131159243Sobrien q = lp->word; 131259243Sobrien do 131359243Sobrien if (!*p) 131459243Sobrien return (hp); 131559243Sobrien while (*p++ == *q++); 131659243Sobrien continue; 131759243Sobrien } 131859243Sobrien do { 131959243Sobrien for (dp = lp->word; *dp; dp++) { 132059243Sobrien p = cp; 132159243Sobrien q = dp; 132259243Sobrien do 132359243Sobrien if (!*p) { 132459243Sobrien quesarg = argno; 132559243Sobrien return (hp); 132659243Sobrien } 132759243Sobrien while (*p++ == *q++); 132859243Sobrien } 132959243Sobrien lp = lp->next; 133059243Sobrien argno++; 133159243Sobrien } while (lp->word[0] != '\n'); 133259243Sobrien } 133359243Sobrien seterror(ERR_NOEVENT, short2str(cp)); 133459243Sobrien return (0); 133559243Sobrien} 133659243Sobrien 133759243Sobrien 133859243Sobrienstatic void 1339167465Smpsetexclp(Char *cp) 134059243Sobrien{ 134159243Sobrien if (cp && cp[0] == '\n') 134259243Sobrien return; 134359243Sobrien exclp = cp; 134459243Sobrien} 134559243Sobrien 134659243Sobrienvoid 1347167465Smpunreadc(Char c) 134859243Sobrien{ 134959243Sobrien peekread = (Char) c; 135059243Sobrien} 135159243Sobrien 1352145479SmpeChar 1353167465Smpreadc(int wanteof) 135459243Sobrien{ 1355145479Smp eChar c; 135659243Sobrien static int sincereal; /* Number of real EOFs we've seen */ 135759243Sobrien 135859243Sobrien#ifdef DEBUG_INP 135959243Sobrien xprintf("readc\n"); 136059243Sobrien#endif 136159243Sobrien if ((c = peekread) != 0) { 136259243Sobrien peekread = 0; 136359243Sobrien return (c); 136459243Sobrien } 136559243Sobrien 136659243Sobrientop: 136769408Sache aret = TCSH_F_SEEK; 136859243Sobrien if (alvecp) { 136959243Sobrien arun = 1; 137059243Sobrien#ifdef DEBUG_INP 137159243Sobrien xprintf("alvecp %c\n", *alvecp & 0xff); 137259243Sobrien#endif 137369408Sache aret = TCSH_A_SEEK; 137459243Sobrien if ((c = *alvecp++) != 0) 137559243Sobrien return (c); 137659243Sobrien if (alvec && *alvec) { 137759243Sobrien alvecp = *alvec++; 137859243Sobrien return (' '); 137959243Sobrien } 138059243Sobrien else { 138159243Sobrien alvecp = NULL; 138269408Sache aret = TCSH_F_SEEK; 138359243Sobrien return('\n'); 138459243Sobrien } 138559243Sobrien } 138659243Sobrien if (alvec) { 138759243Sobrien arun = 1; 138859243Sobrien if ((alvecp = *alvec) != 0) { 138959243Sobrien alvec++; 139059243Sobrien goto top; 139159243Sobrien } 139259243Sobrien /* Infinite source! */ 139359243Sobrien return ('\n'); 139459243Sobrien } 139559243Sobrien arun = 0; 139659243Sobrien if (evalp) { 139769408Sache aret = TCSH_E_SEEK; 139859243Sobrien if ((c = *evalp++) != 0) 139959243Sobrien return (c); 140059243Sobrien if (evalvec && *evalvec) { 140159243Sobrien evalp = *evalvec++; 140259243Sobrien return (' '); 140359243Sobrien } 140469408Sache aret = TCSH_F_SEEK; 140559243Sobrien evalp = 0; 140659243Sobrien } 140759243Sobrien if (evalvec) { 140859243Sobrien if (evalvec == INVPPTR) { 140959243Sobrien doneinp = 1; 141059243Sobrien reset(); 141159243Sobrien } 141259243Sobrien if ((evalp = *evalvec) != 0) { 141359243Sobrien evalvec++; 141459243Sobrien goto top; 141559243Sobrien } 141659243Sobrien evalvec = INVPPTR; 141759243Sobrien return ('\n'); 141859243Sobrien } 141959243Sobrien do { 142059243Sobrien if (arginp == INVPTR || onelflg == 1) { 142159243Sobrien if (wanteof) 1422145479Smp return CHAR_ERR; 142359243Sobrien exitstat(); 142459243Sobrien } 142559243Sobrien if (arginp) { 142659243Sobrien if ((c = *arginp++) == 0) { 142759243Sobrien arginp = INVPTR; 142859243Sobrien return ('\n'); 142959243Sobrien } 143059243Sobrien return (c); 143159243Sobrien } 143259243Sobrien#ifdef BSDJOBS 143359243Sobrienreread: 143459243Sobrien#endif /* BSDJOBS */ 143559243Sobrien c = bgetc(); 1436145479Smp if (c == CHAR_ERR) { 143769408Sache#ifndef WINNT_NATIVE 143859243Sobrien# ifndef POSIX 143959243Sobrien# ifdef TERMIO 144059243Sobrien struct termio tty; 144159243Sobrien# else /* SGTTYB */ 144259243Sobrien struct sgttyb tty; 144359243Sobrien# endif /* TERMIO */ 144459243Sobrien# else /* POSIX */ 144559243Sobrien struct termios tty; 144659243Sobrien# endif /* POSIX */ 144769408Sache#endif /* !WINNT_NATIVE */ 144859243Sobrien if (wanteof) 1449145479Smp return CHAR_ERR; 145059243Sobrien /* was isatty but raw with ignoreeof yields problems */ 145169408Sache#ifndef WINNT_NATIVE 145259243Sobrien# ifndef POSIX 145359243Sobrien# ifdef TERMIO 145459243Sobrien if (ioctl(SHIN, TCGETA, (ioctl_t) & tty) == 0 && 145559243Sobrien (tty.c_lflag & ICANON)) 145659243Sobrien# else /* GSTTYB */ 145759243Sobrien if (ioctl(SHIN, TIOCGETP, (ioctl_t) & tty) == 0 && 145859243Sobrien (tty.sg_flags & RAW) == 0) 145959243Sobrien# endif /* TERMIO */ 146059243Sobrien# else /* POSIX */ 146159243Sobrien if (tcgetattr(SHIN, &tty) == 0 && 146259243Sobrien (tty.c_lflag & ICANON)) 146359243Sobrien# endif /* POSIX */ 146469408Sache#else /* WINNT_NATIVE */ 146559243Sobrien if (isatty(SHIN)) 146669408Sache#endif /* !WINNT_NATIVE */ 146759243Sobrien { 146859243Sobrien#ifdef BSDJOBS 1469167465Smp pid_t ctpgrp; 147059243Sobrien#endif /* BSDJOBS */ 147159243Sobrien 1472100616Smp if (numeof != 0 && ++sincereal >= numeof) /* Too many EOFs? Bye! */ 147359243Sobrien goto oops; 147459243Sobrien#ifdef BSDJOBS 147559243Sobrien if (tpgrp != -1 && 147659243Sobrien (ctpgrp = tcgetpgrp(FSHTTY)) != -1 && 147759243Sobrien tpgrp != ctpgrp) { 147859243Sobrien (void) tcsetpgrp(FSHTTY, tpgrp); 147959243Sobrien# ifdef _SEQUENT_ 148059243Sobrien if (ctpgrp) 148159243Sobrien# endif /* _SEQUENT */ 1482167465Smp (void) killpg(ctpgrp, SIGHUP); 148359243Sobrien# ifdef notdef 148459243Sobrien /* 148559243Sobrien * With the walking process group fix, this message 148659243Sobrien * is now obsolete. As the foreground process group 148759243Sobrien * changes, the shell needs to adjust. Well too bad. 148859243Sobrien */ 148959243Sobrien xprintf(CGETS(16, 1, "Reset tty pgrp from %d to %d\n"), 1490167465Smp (int)ctpgrp, (int)tpgrp); 149159243Sobrien# endif /* notdef */ 149259243Sobrien goto reread; 149359243Sobrien } 149459243Sobrien#endif /* BSDJOBS */ 149559243Sobrien /* What follows is complicated EOF handling -- sterling@netcom.com */ 149659243Sobrien /* First, we check to see if we have ignoreeof set */ 149759243Sobrien if (adrof(STRignoreeof)) { 149859243Sobrien /* If so, we check for any stopped jobs only on the first EOF */ 149959243Sobrien if ((sincereal == 1) && (chkstop == 0)) { 150059243Sobrien panystop(1); 150159243Sobrien } 150259243Sobrien } else { 150359243Sobrien /* If we don't have ignoreeof set, always check for stopped jobs */ 150459243Sobrien if (chkstop == 0) { 150559243Sobrien panystop(1); 150659243Sobrien } 150759243Sobrien } 150859243Sobrien /* At this point, if there were stopped jobs, we would have already 150959243Sobrien * called reset(). If we got this far, assume we can print an 151059243Sobrien * exit/logout message if we ignoreeof, or just exit. 151159243Sobrien */ 151259243Sobrien if (adrof(STRignoreeof)) { 151359243Sobrien /* If so, tell the user to use exit or logout */ 151459243Sobrien if (loginsh) { 1515195609Smp xprintf("%s", CGETS(16, 2, 151659243Sobrien "\nUse \"logout\" to logout.\n")); 151759243Sobrien } else { 151859243Sobrien xprintf(CGETS(16, 3, 151959243Sobrien "\nUse \"exit\" to leave %s.\n"), 152059243Sobrien progname); 152159243Sobrien } 1522167465Smp reset(); 152359243Sobrien } else { 152459243Sobrien /* If we don't have ignoreeof set, just fall through */ 152559243Sobrien ; /* EMPTY */ 152659243Sobrien } 152759243Sobrien } 152859243Sobrien oops: 152959243Sobrien doneinp = 1; 153059243Sobrien reset(); 153159243Sobrien } 153259243Sobrien sincereal = 0; 153359243Sobrien if (c == '\n' && onelflg) 153459243Sobrien onelflg--; 153559243Sobrien } while (c == 0); 1536167465Smp Strbuf_append1(&histline, c); 153759243Sobrien return (c); 153859243Sobrien} 153959243Sobrien 154059243Sobrienstatic void 1541167465Smpballoc(int buf) 154259243Sobrien{ 154359243Sobrien Char **nfbuf; 154459243Sobrien 154559243Sobrien while (buf >= fblocks) { 1546167465Smp nfbuf = xcalloc(fblocks + 2, sizeof(Char **)); 154759243Sobrien if (fbuf) { 154859243Sobrien (void) blkcpy(nfbuf, fbuf); 1549167465Smp xfree(fbuf); 155059243Sobrien } 155159243Sobrien fbuf = nfbuf; 1552167465Smp fbuf[fblocks] = xcalloc(BUFSIZE, sizeof(Char)); 155359243Sobrien fblocks++; 155459243Sobrien } 155559243Sobrien} 155659243Sobrien 1557316957Sdchaginssize_t 1558167465Smpwide_read(int fildes, Char *buf, size_t nchars, int use_fclens) 1559145479Smp{ 1560145479Smp char cbuf[BUFSIZE + 1]; 1561167465Smp ssize_t res, r = 0; 1562145479Smp size_t partial; 1563167465Smp int err; 1564167465Smp 1565167465Smp if (nchars == 0) 1566167465Smp return 0; 1567167465Smp assert (nchars <= sizeof(cbuf) / sizeof(*cbuf)); 1568145479Smp USE(use_fclens); 1569145479Smp res = 0; 1570145479Smp partial = 0; 1571145479Smp do { 1572145479Smp size_t i; 1573167465Smp size_t len = nchars > partial ? nchars - partial : 1; 1574167465Smp 1575167465Smp if (partial + len >= sizeof(cbuf) / sizeof(*cbuf)) 1576167465Smp break; 1577145479Smp 1578167465Smp r = xread(fildes, cbuf + partial, len); 1579167465Smp 1580145479Smp if (partial == 0 && r <= 0) 1581145479Smp break; 1582145479Smp partial += r; 1583145479Smp i = 0; 1584167465Smp while (i < partial && nchars != 0) { 1585167465Smp int tlen; 1586145479Smp 1587167465Smp tlen = normal_mbtowc(buf + res, cbuf + i, partial - i); 1588167465Smp if (tlen == -1) { 1589145479Smp reset_mbtowc(); 1590167465Smp if ((partial - i) < MB_LEN_MAX && r > 0) 1591145479Smp /* Maybe a partial character and there is still a chance 1592145479Smp to read more */ 1593145479Smp break; 1594145479Smp buf[res] = (unsigned char)cbuf[i] | INVALID_BYTE; 1595145479Smp } 1596167465Smp if (tlen <= 0) 1597167465Smp tlen = 1; 1598145479Smp#ifdef WIDE_STRINGS 1599145479Smp if (use_fclens) 1600167465Smp fclens[res] = tlen; 1601145479Smp#endif 1602167465Smp i += tlen; 1603145479Smp res++; 1604145479Smp nchars--; 1605145479Smp } 1606145479Smp if (i != partial) 1607145479Smp memmove(cbuf, cbuf + i, partial - i); 1608145479Smp partial -= i; 1609167465Smp } while (partial != 0 && nchars > 0); 1610167465Smp /* Throwing away possible partial multibyte characters on error if the 1611167465Smp stream is not seekable */ 1612167465Smp err = errno; 1613167465Smp lseek(fildes, -(off_t)partial, L_INCR); 1614167465Smp errno = err; 1615145479Smp return res != 0 ? res : r; 1616145479Smp} 1617145479Smp 1618145479Smpstatic eChar 1619167465Smpbgetc(void) 162059243Sobrien{ 1621145479Smp Char ch; 162259243Sobrien int c, off, buf; 162359243Sobrien int numleft = 0, roomleft; 162459243Sobrien 162559243Sobrien if (cantell) { 162659243Sobrien if (fseekp < fbobp || fseekp > feobp) { 162759243Sobrien fbobp = feobp = fseekp; 162859243Sobrien (void) lseek(SHIN, fseekp, L_SET); 162959243Sobrien } 163059243Sobrien if (fseekp == feobp) { 1631167465Smp#ifdef WIDE_STRINGS 1632167465Smp off_t bytes; 1633167465Smp size_t i; 1634167465Smp 1635167465Smp bytes = fbobp; 1636167465Smp for (i = 0; i < (size_t)(feobp - fbobp); i++) 1637167465Smp bytes += fclens[i]; 1638167465Smp fseekp = feobp = bytes; 1639167465Smp#endif 164059243Sobrien fbobp = feobp; 1641167465Smp c = wide_read(SHIN, fbuf[0], BUFSIZE, 1); 164259243Sobrien#ifdef convex 164359243Sobrien if (c < 0) 164459243Sobrien stderror(ERR_SYSTEM, progname, strerror(errno)); 164559243Sobrien#endif /* convex */ 164659243Sobrien if (c <= 0) 1647145479Smp return CHAR_ERR; 164859243Sobrien feobp += c; 164959243Sobrien } 1650195609Smp#if !defined(WINNT_NATIVE) && !defined(__CYGWIN__) 1651145479Smp ch = fbuf[0][fseekp - fbobp]; 165259243Sobrien fseekp++; 165359243Sobrien#else 165459243Sobrien do { 1655145479Smp ch = fbuf[0][fseekp - fbobp]; 165659243Sobrien fseekp++; 1657145479Smp } while(ch == '\r'); 1658195609Smp#endif /* !WINNT_NATIVE && !__CYGWIN__ */ 1659145479Smp return (ch); 166059243Sobrien } 166159243Sobrien 166259243Sobrien while (fseekp >= feobp) { 1663100616Smp if ((editing 1664100616Smp#if defined(FILEC) && defined(TIOCSTI) 1665100616Smp || filec 1666100616Smp#endif /* FILEC && TIOCSTI */ 1667100616Smp ) && intty) { /* then use twenex routine */ 166859243Sobrien fseekp = feobp; /* where else? */ 1669100616Smp#if defined(FILEC) && defined(TIOCSTI) 1670100616Smp if (!editing) 1671100616Smp c = numleft = tenex(InputBuf, BUFSIZE); 1672100616Smp else 1673100616Smp#endif /* FILEC && TIOCSTI */ 167459243Sobrien c = numleft = Inputl(); /* PWP: get a line */ 167559243Sobrien while (numleft > 0) { 167659243Sobrien off = (int) feobp % BUFSIZE; 167759243Sobrien buf = (int) feobp / BUFSIZE; 167859243Sobrien balloc(buf); 167959243Sobrien roomleft = BUFSIZE - off; 168059243Sobrien if (roomleft > numleft) 168159243Sobrien roomleft = numleft; 1682167465Smp (void) memcpy(fbuf[buf] + off, InputBuf + c - numleft, 1683167465Smp roomleft * sizeof(Char)); 168459243Sobrien numleft -= roomleft; 168559243Sobrien feobp += roomleft; 168659243Sobrien } 1687100616Smp } else { 168859243Sobrien off = (int) feobp % BUFSIZE; 168959243Sobrien buf = (int) feobp / BUFSIZE; 169059243Sobrien balloc(buf); 169159243Sobrien roomleft = BUFSIZE - off; 1692167465Smp c = wide_read(SHIN, fbuf[buf] + off, roomleft, 0); 1693145479Smp if (c > 0) 169459243Sobrien feobp += c; 169559243Sobrien } 169659243Sobrien if (c == 0 || (c < 0 && fixio(SHIN, errno) == -1)) 1697145479Smp return CHAR_ERR; 169859243Sobrien } 1699145479Smp#ifdef SIG_WINDOW 1700145479Smp if (windowchg) 1701145479Smp (void) check_window_size(0); /* for window systems */ 1702145479Smp#endif /* SIG_WINDOW */ 1703195609Smp#if !defined(WINNT_NATIVE) && !defined(__CYGWIN__) 1704145479Smp ch = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE]; 170559243Sobrien fseekp++; 170659243Sobrien#else 170759243Sobrien do { 1708145479Smp ch = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE]; 170959243Sobrien fseekp++; 1710145479Smp } while(ch == '\r'); 1711195609Smp#endif /* !WINNT_NATIVE && !__CYGWIN__ */ 1712145479Smp return (ch); 171359243Sobrien} 171459243Sobrien 171559243Sobrienstatic void 1716167465Smpbfree(void) 171759243Sobrien{ 171859243Sobrien int sb, i; 171959243Sobrien 172059243Sobrien if (cantell) 172159243Sobrien return; 172259243Sobrien if (whyles) 172359243Sobrien return; 172459243Sobrien sb = (int) (fseekp - 1) / BUFSIZE; 172559243Sobrien if (sb > 0) { 172659243Sobrien for (i = 0; i < sb; i++) 1727167465Smp xfree(fbuf[i]); 172859243Sobrien (void) blkcpy(fbuf, &fbuf[sb]); 172959243Sobrien fseekp -= BUFSIZE * sb; 173059243Sobrien feobp -= BUFSIZE * sb; 173159243Sobrien fblocks -= sb; 173259243Sobrien } 173359243Sobrien} 173459243Sobrien 173559243Sobrienvoid 1736167465Smpbseek(struct Ain *l) 173759243Sobrien{ 173859243Sobrien switch (aret = l->type) { 173969408Sache case TCSH_E_SEEK: 174059243Sobrien evalvec = l->a_seek; 174159243Sobrien evalp = l->c_seek; 174259243Sobrien#ifdef DEBUG_SEEK 174359243Sobrien xprintf(CGETS(16, 4, "seek to eval %x %x\n"), evalvec, evalp); 174459243Sobrien#endif 174559243Sobrien return; 174669408Sache case TCSH_A_SEEK: 174759243Sobrien alvec = l->a_seek; 174859243Sobrien alvecp = l->c_seek; 174959243Sobrien#ifdef DEBUG_SEEK 175059243Sobrien xprintf(CGETS(16, 5, "seek to alias %x %x\n"), alvec, alvecp); 175159243Sobrien#endif 175259243Sobrien return; 175369408Sache case TCSH_F_SEEK: 175459243Sobrien#ifdef DEBUG_SEEK 175559243Sobrien xprintf(CGETS(16, 6, "seek to file %x\n"), fseekp); 175659243Sobrien#endif 175759243Sobrien fseekp = l->f_seek; 1758145479Smp#ifdef WIDE_STRINGS 1759145479Smp if (cantell) { 1760167465Smp if (fseekp >= fbobp && feobp >= fbobp) { 1761145479Smp size_t i; 1762145479Smp off_t o; 1763145479Smp 1764145479Smp o = fbobp; 1765167465Smp for (i = 0; i < (size_t)(feobp - fbobp); i++) { 1766145479Smp if (fseekp == o) { 1767145479Smp fseekp = fbobp + i; 1768145479Smp return; 1769145479Smp } 1770145479Smp o += fclens[i]; 1771145479Smp } 1772145479Smp if (fseekp == o) { 1773145479Smp fseekp = feobp; 1774145479Smp return; 1775145479Smp } 1776145479Smp } 1777145479Smp fbobp = feobp = fseekp + 1; /* To force lseek() */ 1778145479Smp } 1779145479Smp#endif 178059243Sobrien return; 178159243Sobrien default: 178259243Sobrien xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret); 178359243Sobrien abort(); 178459243Sobrien } 178559243Sobrien} 178659243Sobrien 178759243Sobrien/* any similarity to bell telephone is purely accidental */ 178859243Sobrienvoid 1789167465Smpbtell(struct Ain *l) 179059243Sobrien{ 179159243Sobrien switch (l->type = aret) { 179269408Sache case TCSH_E_SEEK: 179359243Sobrien l->a_seek = evalvec; 179459243Sobrien l->c_seek = evalp; 179559243Sobrien#ifdef DEBUG_SEEK 179659243Sobrien xprintf(CGETS(16, 8, "tell eval %x %x\n"), evalvec, evalp); 179759243Sobrien#endif 179859243Sobrien return; 179969408Sache case TCSH_A_SEEK: 180059243Sobrien l->a_seek = alvec; 180159243Sobrien l->c_seek = alvecp; 180259243Sobrien#ifdef DEBUG_SEEK 180359243Sobrien xprintf(CGETS(16, 9, "tell alias %x %x\n"), alvec, alvecp); 180459243Sobrien#endif 180559243Sobrien return; 180669408Sache case TCSH_F_SEEK: 1807145479Smp#ifdef WIDE_STRINGS 1808167465Smp if (cantell && fseekp >= fbobp && fseekp <= feobp) { 1809145479Smp size_t i; 1810167465Smp 1811145479Smp l->f_seek = fbobp; 1812167465Smp for (i = 0; i < (size_t)(fseekp - fbobp); i++) 1813145479Smp l->f_seek += fclens[i]; 1814145479Smp } else 1815145479Smp#endif 1816145479Smp /*SUPPRESS 112*/ 1817145479Smp l->f_seek = fseekp; 181859243Sobrien l->a_seek = NULL; 181959243Sobrien#ifdef DEBUG_SEEK 182059243Sobrien xprintf(CGETS(16, 10, "tell file %x\n"), fseekp); 182159243Sobrien#endif 182259243Sobrien return; 182359243Sobrien default: 182459243Sobrien xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret); 182559243Sobrien abort(); 182659243Sobrien } 182759243Sobrien} 182859243Sobrien 182959243Sobrienvoid 1830167465Smpbtoeof(void) 183159243Sobrien{ 183259243Sobrien (void) lseek(SHIN, (off_t) 0, L_XTND); 183369408Sache aret = TCSH_F_SEEK; 183459243Sobrien fseekp = feobp; 183559243Sobrien alvec = NULL; 183659243Sobrien alvecp = NULL; 183759243Sobrien evalvec = NULL; 183859243Sobrien evalp = NULL; 183959243Sobrien wfree(); 184059243Sobrien bfree(); 184159243Sobrien} 184259243Sobrien 184359243Sobrienvoid 1844167465Smpsettell(void) 184559243Sobrien{ 184659243Sobrien off_t x; 184759243Sobrien cantell = 0; 184859243Sobrien if (arginp || onelflg || intty) 184959243Sobrien return; 185059243Sobrien if ((x = lseek(SHIN, (off_t) 0, L_INCR)) == -1) 185159243Sobrien return; 1852167465Smp fbuf = xcalloc(2, sizeof(Char **)); 185359243Sobrien fblocks = 1; 1854167465Smp fbuf[0] = xcalloc(BUFSIZE, sizeof(Char)); 185559243Sobrien fseekp = fbobp = feobp = x; 185659243Sobrien cantell = 1; 185759243Sobrien} 1858