sh.lex.c revision 167465
1167465Smp/* $Header: /p/tcsh/cvsroot/tcsh/sh.lex.c,v 3.77 2006/09/27 17:01:06 mitr 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 35167465SmpRCSID("$tcsh: sh.lex.c,v 3.77 2006/09/27 17:01:06 mitr 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 == '"') || 37159243Sobrien (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 } 46359243Sobrien c = readc(0); 46459243Sobrien if (c == '$' && (flag & DODOL)) { 46559243Sobrien getdol(); 46659243Sobrien continue; 46759243Sobrien } 468145479Smp if (c == (eChar)HIST && (flag & DOEXCL)) { 46959243Sobrien getexcl(0); 47059243Sobrien continue; 47159243Sobrien } 47259243Sobrien break; 47359243Sobrien } 47459243Sobrien return (c); 47559243Sobrien} 47659243Sobrien 47759243Sobrienstatic void 478167465Smpgetdol(void) 47959243Sobrien{ 480167465Smp struct Strbuf name = Strbuf_INIT; 481145479Smp eChar c; 482145479Smp eChar sc; 483167465Smp int special = 0; 48459243Sobrien 48559243Sobrien c = sc = getC(DOEXCL); 48659243Sobrien if (any("\t \n", c)) { 48759243Sobrien ungetD(c); 48859243Sobrien ungetC('$' | QUOTE); 48959243Sobrien return; 49059243Sobrien } 491167465Smp cleanup_push(&name, Strbuf_cleanup); 492167465Smp Strbuf_append1(&name, '$'); 49359243Sobrien if (c == '{') 494167465Smp Strbuf_append1(&name, c), c = getC(DOEXCL); 49559243Sobrien if (c == '#' || c == '?' || c == '%') 496167465Smp special++, Strbuf_append1(&name, c), c = getC(DOEXCL); 497167465Smp Strbuf_append1(&name, c); 49859243Sobrien switch (c) { 49959243Sobrien 50059243Sobrien case '<': 50159243Sobrien case '$': 50259243Sobrien case '!': 50359243Sobrien if (special) 50459243Sobrien seterror(ERR_SPDOLLT); 505167465Smp goto end; 50659243Sobrien 50759243Sobrien case '\n': 50859243Sobrien ungetD(c); 509167465Smp name.len--; 51059243Sobrien if (!special) 51159243Sobrien seterror(ERR_NEWLINE); 512167465Smp goto end; 51359243Sobrien 51459243Sobrien case '*': 51559243Sobrien if (special) 51659243Sobrien seterror(ERR_SPSTAR); 517167465Smp goto end; 51859243Sobrien 51959243Sobrien default: 52059243Sobrien if (Isdigit(c)) { 52159243Sobrien#ifdef notdef 52259243Sobrien /* let $?0 pass for now */ 52359243Sobrien if (special) { 52459243Sobrien seterror(ERR_DIGIT); 525167465Smp goto end; 52659243Sobrien } 52759243Sobrien#endif 52859243Sobrien while ((c = getC(DOEXCL)) != 0) { 52959243Sobrien if (!Isdigit(c)) 53059243Sobrien break; 531167465Smp Strbuf_append1(&name, c); 53259243Sobrien } 53359243Sobrien } 53459243Sobrien else if (letter(c)) { 53559243Sobrien while ((c = getC(DOEXCL)) != 0) { 53659243Sobrien /* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */ 53759243Sobrien if (!letter(c) && !Isdigit(c)) 53859243Sobrien break; 539167465Smp Strbuf_append1(&name, c); 54059243Sobrien } 54159243Sobrien } 54259243Sobrien else { 54359243Sobrien if (!special) 54459243Sobrien seterror(ERR_VARILL); 54559243Sobrien else { 54659243Sobrien ungetD(c); 547167465Smp name.len--; 54859243Sobrien } 549167465Smp goto end; 55059243Sobrien } 55159243Sobrien break; 55259243Sobrien } 55359243Sobrien if (c == '[') { 554167465Smp Strbuf_append1(&name, c); 55559243Sobrien do { 55659243Sobrien /* 55759243Sobrien * Michael Greim: Allow $ expansion to take place in selector 55859243Sobrien * expressions. (limits the number of characters returned) 55959243Sobrien */ 56059243Sobrien c = getC(DOEXCL | DODOL); 56159243Sobrien if (c == '\n') { 56259243Sobrien ungetD(c); 563167465Smp name.len--; 56459243Sobrien seterror(ERR_NLINDEX); 565167465Smp goto end; 56659243Sobrien } 567167465Smp Strbuf_append1(&name, c); 56859243Sobrien } while (c != ']'); 56959243Sobrien c = getC(DOEXCL); 57059243Sobrien } 57159243Sobrien if (c == ':') { 57259243Sobrien /* 57359243Sobrien * if the :g modifier is followed by a newline, then error right away! 57459243Sobrien * -strike 57559243Sobrien */ 57659243Sobrien 57759243Sobrien int gmodflag = 0, amodflag = 0; 57859243Sobrien 57959243Sobrien do { 580167465Smp Strbuf_append1(&name, c), c = getC(DOEXCL); 58159243Sobrien if (c == 'g' || c == 'a') { 58259243Sobrien if (c == 'g') 58359243Sobrien gmodflag++; 58459243Sobrien else 58559243Sobrien amodflag++; 586167465Smp Strbuf_append1(&name, c); c = getC(DOEXCL); 58759243Sobrien } 58859243Sobrien if ((c == 'g' && !gmodflag) || (c == 'a' && !amodflag)) { 58959243Sobrien if (c == 'g') 59059243Sobrien gmodflag++; 59159243Sobrien else 59259243Sobrien amodflag++; 593167465Smp Strbuf_append1(&name, c); c = getC(DOEXCL); 59459243Sobrien } 595167465Smp Strbuf_append1(&name, c); 59659243Sobrien /* scan s// [eichin:19910926.0512EST] */ 59759243Sobrien if (c == 's') { 59859243Sobrien int delimcnt = 2; 599145479Smp eChar delim = getC(0); 600167465Smp 601167465Smp Strbuf_append1(&name, delim); 60259243Sobrien if (!delim || letter(delim) 60359243Sobrien || Isdigit(delim) || any(" \t\n", delim)) { 60459243Sobrien seterror(ERR_BADSUBST); 60559243Sobrien break; 606167465Smp } 607145479Smp while ((c = getC(0)) != CHAR_ERR) { 608167465Smp Strbuf_append1(&name, c); 60959243Sobrien if(c == delim) delimcnt--; 61059243Sobrien if(!delimcnt) break; 61159243Sobrien } 61259243Sobrien if(delimcnt) { 61359243Sobrien seterror(ERR_BADSUBST); 61459243Sobrien break; 61559243Sobrien } 61659243Sobrien c = 's'; 61759243Sobrien } 61859243Sobrien if (!any("htrqxesul", c)) { 61959243Sobrien if ((amodflag || gmodflag) && c == '\n') 62059243Sobrien stderror(ERR_VARSYN); /* strike */ 62159243Sobrien seterror(ERR_BADMOD, c); 622167465Smp goto end; 62359243Sobrien } 62459243Sobrien } 62559243Sobrien while ((c = getC(DOEXCL)) == ':'); 62659243Sobrien ungetD(c); 62759243Sobrien } 62859243Sobrien else 62959243Sobrien ungetD(c); 63059243Sobrien if (sc == '{') { 63159243Sobrien c = getC(DOEXCL); 63259243Sobrien if (c != '}') { 63359243Sobrien ungetD(c); 63459243Sobrien seterror(ERR_MISSING, '}'); 635167465Smp goto end; 63659243Sobrien } 637167465Smp Strbuf_append1(&name, c); 63859243Sobrien } 639167465Smp end: 640167465Smp cleanup_ignore(&name); 641167465Smp cleanup_until(&name); 642167465Smp addla(Strbuf_finish(&name)); 64359243Sobrien} 64459243Sobrien 645167465Smp/* xfree()'s its argument */ 64659243Sobrienvoid 647167465Smpaddla(Char *cp) 64859243Sobrien{ 649167465Smp static struct Strbuf buf; /* = Strbuf_INIT; */ 65059243Sobrien 651167465Smp buf.len = 0; 652167465Smp Strbuf_appendn(&buf, labuf.s + lap, labuf.len - lap); 653167465Smp labuf.len = 0; 654167465Smp Strbuf_append(&labuf, cp); 655167465Smp Strbuf_terminate(&labuf); 656167465Smp Strbuf_appendn(&labuf, buf.s, buf.len); 657167465Smp xfree(cp); 658167465Smp lap = 0; 65959243Sobrien} 66059243Sobrien 661167465Smp/* left-hand side of last :s or search string of last ?event? */ 662167465Smpstatic struct Strbuf lhsb; /* = Strbuf_INIT; */ 663167465Smpstatic struct Strbuf slhs; /* = Strbuf_INIT; left-hand side of last :s */ 664167465Smpstatic struct Strbuf rhsb; /* = Strbuf_INIT; right-hand side of last :s */ 66559243Sobrienstatic int quesarg; 66659243Sobrien 66759243Sobrienstatic void 668167465Smpgetexcl(Char sc) 66959243Sobrien{ 67059243Sobrien struct wordent *hp, *ip; 67159243Sobrien int left, right, dol; 672145479Smp eChar c; 67359243Sobrien 67459243Sobrien if (sc == 0) { 67559243Sobrien sc = getC(0); 67659243Sobrien if (sc != '{') { 67759243Sobrien ungetC(sc); 67859243Sobrien sc = 0; 67959243Sobrien } 68059243Sobrien } 68159243Sobrien quesarg = -1; 68259243Sobrien 683167465Smp lastev = eventno; 68459243Sobrien hp = gethent(sc); 68559243Sobrien if (hp == 0) 68659243Sobrien return; 68759243Sobrien hadhist = 1; 68859243Sobrien dol = 0; 68959243Sobrien if (hp == alhistp) 69059243Sobrien for (ip = hp->next->next; ip != alhistt; ip = ip->next) 69159243Sobrien dol++; 69259243Sobrien else 69359243Sobrien for (ip = hp->next->next; ip != hp->prev; ip = ip->next) 69459243Sobrien dol++; 69559243Sobrien left = 0, right = dol; 69659243Sobrien if (sc == HISTSUB) { 69759243Sobrien ungetC('s'), unreadc(HISTSUB), c = ':'; 69859243Sobrien goto subst; 69959243Sobrien } 70059243Sobrien c = getC(0); 70159243Sobrien if (!any(":^$*-%", c)) 70259243Sobrien goto subst; 70359243Sobrien left = right = -1; 70459243Sobrien if (c == ':') { 70559243Sobrien c = getC(0); 70659243Sobrien unreadc(c); 70759243Sobrien if (letter(c) || c == '&') { 70859243Sobrien c = ':'; 70959243Sobrien left = 0, right = dol; 71059243Sobrien goto subst; 71159243Sobrien } 71259243Sobrien } 71359243Sobrien else 71459243Sobrien ungetC(c); 71559243Sobrien if (!getsel(&left, &right, dol)) 71659243Sobrien return; 71759243Sobrien c = getC(0); 71859243Sobrien if (c == '*') 71959243Sobrien ungetC(c), c = '-'; 72059243Sobrien if (c == '-') { 72159243Sobrien if (!getsel(&left, &right, dol)) 72259243Sobrien return; 72359243Sobrien c = getC(0); 72459243Sobrien } 72559243Sobriensubst: 72659243Sobrien exclc = right - left + 1; 72759243Sobrien while (--left >= 0) 72859243Sobrien hp = hp->next; 72959243Sobrien if (sc == HISTSUB || c == ':') { 73059243Sobrien do { 73159243Sobrien hp = getsub(hp); 73259243Sobrien c = getC(0); 73359243Sobrien } while (c == ':'); 73459243Sobrien } 73559243Sobrien unreadc(c); 73659243Sobrien if (sc == '{') { 73759243Sobrien c = getC(0); 73859243Sobrien if (c != '}') 73959243Sobrien seterror(ERR_BADBANG); 74059243Sobrien } 74159243Sobrien exclnxt = hp; 74259243Sobrien} 74359243Sobrien 74459243Sobrienstatic struct wordent * 745167465Smpgetsub(struct wordent *en) 74659243Sobrien{ 747145479Smp eChar delim; 748145479Smp eChar c; 749145479Smp eChar sc; 750145479Smp int global; 75159243Sobrien 75259243Sobrien do { 75359243Sobrien exclnxt = 0; 75459243Sobrien global = 0; 75559243Sobrien sc = c = getC(0); 756167465Smp while (c == 'g' || c == 'a') { 757167465Smp global |= (c == 'g') ? FLAG_G : FLAG_A; 75859243Sobrien sc = c = getC(0); 75959243Sobrien } 76059243Sobrien 76159243Sobrien switch (c) { 76259243Sobrien case 'p': 76359243Sobrien justpr++; 76459243Sobrien return (en); 76559243Sobrien 76659243Sobrien case 'x': 76759243Sobrien case 'q': 768167465Smp global |= FLAG_G; 76959243Sobrien /*FALLTHROUGH*/ 77059243Sobrien 77159243Sobrien case 'h': 77259243Sobrien case 'r': 77359243Sobrien case 't': 77459243Sobrien case 'e': 77559243Sobrien case 'u': 77659243Sobrien case 'l': 77759243Sobrien break; 77859243Sobrien 77959243Sobrien case '&': 780167465Smp if (slhs.len == 0) { 78159243Sobrien seterror(ERR_NOSUBST); 78259243Sobrien return (en); 78359243Sobrien } 784167465Smp lhsb.len = 0; 785167465Smp Strbuf_append(&lhsb, slhs.s); 786167465Smp Strbuf_terminate(&lhsb); 78759243Sobrien break; 78859243Sobrien 78959243Sobrien#ifdef notdef 79059243Sobrien case '~': 791167465Smp if (lhsb.len == 0) 79259243Sobrien goto badlhs; 79359243Sobrien break; 79459243Sobrien#endif 79559243Sobrien 79659243Sobrien case 's': 79759243Sobrien delim = getC(0); 79859243Sobrien if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) { 79959243Sobrien unreadc(delim); 800167465Smp lhsb.len = 0; 80159243Sobrien seterror(ERR_BADSUBST); 80259243Sobrien return (en); 80359243Sobrien } 804167465Smp Strbuf_terminate(&lhsb); 805167465Smp lhsb.len = 0; 80659243Sobrien for (;;) { 80759243Sobrien c = getC(0); 80859243Sobrien if (c == '\n') { 80959243Sobrien unreadc(c); 81059243Sobrien break; 81159243Sobrien } 81259243Sobrien if (c == delim) 81359243Sobrien break; 81459243Sobrien if (c == '\\') { 81559243Sobrien c = getC(0); 81659243Sobrien if (c != delim && c != '\\') 817167465Smp Strbuf_append1(&lhsb, '\\'); 81859243Sobrien } 819167465Smp Strbuf_append1(&lhsb, c); 82059243Sobrien } 821167465Smp if (lhsb.len != 0) 822167465Smp Strbuf_terminate(&lhsb); 823167465Smp else if (lhsb.s[0] == 0) { 82459243Sobrien seterror(ERR_LHS); 82559243Sobrien return (en); 826167465Smp } else 827167465Smp lhsb.len = Strlen(lhsb.s); /* lhsb.s wasn't changed */ 828167465Smp rhsb.len = 0; 82959243Sobrien for (;;) { 83059243Sobrien c = getC(0); 83159243Sobrien if (c == '\n') { 83259243Sobrien unreadc(c); 83359243Sobrien break; 83459243Sobrien } 83559243Sobrien if (c == delim) 83659243Sobrien break; 83759243Sobrien if (c == '\\') { 83859243Sobrien c = getC(0); 83959243Sobrien if (c != delim /* && c != '~' */ ) 840167465Smp Strbuf_append1(&rhsb, '\\'); 84159243Sobrien } 842167465Smp Strbuf_append1(&rhsb, c); 84359243Sobrien } 844167465Smp Strbuf_terminate(&rhsb); 84559243Sobrien break; 84659243Sobrien 84759243Sobrien default: 84859243Sobrien if (c == '\n') 84959243Sobrien unreadc(c); 850145479Smp seterror(ERR_BADBANGMOD, (int)c); 85159243Sobrien return (en); 85259243Sobrien } 853167465Smp slhs.len = 0; 854167465Smp Strbuf_append(&slhs, lhsb.s); 855167465Smp Strbuf_terminate(&slhs); 85659243Sobrien if (exclc) 85759243Sobrien en = dosub(sc, en, global); 85859243Sobrien } 85959243Sobrien while ((c = getC(0)) == ':'); 86059243Sobrien unreadc(c); 86159243Sobrien return (en); 86259243Sobrien} 86359243Sobrien 86459243Sobrien/* 86559243Sobrien * 86659243Sobrien * From Beto Appleton (beto@aixwiz.austin.ibm.com) 86759243Sobrien * 86859243Sobrien * when using history substitution, and the variable 86959243Sobrien * 'history' is set to a value higher than 1000, 87059243Sobrien * the shell might either freeze (hang) or core-dump. 87159243Sobrien * We raise the limit to 50000000 87259243Sobrien */ 87359243Sobrien 87459243Sobrien#define HIST_PURGE -50000000 87559243Sobrienstatic struct wordent * 876167465Smpdosub(Char sc, struct wordent *en, int global) 87759243Sobrien{ 87859243Sobrien struct wordent lexi; 879145479Smp int didsub = 0, didone = 0; 88059243Sobrien struct wordent *hp = &lexi; 88159243Sobrien struct wordent *wdp; 88259243Sobrien int i = exclc; 88359243Sobrien struct Hist *hst; 88459243Sobrien 88559243Sobrien wdp = hp; 88659243Sobrien while (--i >= 0) { 887167465Smp struct wordent *new = xcalloc(1, sizeof *wdp); 88859243Sobrien 88959243Sobrien new->word = 0; 89059243Sobrien new->prev = wdp; 89159243Sobrien new->next = hp; 89259243Sobrien wdp->next = new; 89359243Sobrien wdp = new; 89459243Sobrien en = en->next; 89559243Sobrien if (en->word) { 89659243Sobrien Char *tword, *otword; 89759243Sobrien 898167465Smp if ((global & FLAG_G) || didsub == 0) { 899167465Smp size_t pos; 900167465Smp 901167465Smp pos = 0; 902167465Smp tword = subword(en->word, sc, &didone, &pos); 90359243Sobrien if (didone) 90459243Sobrien didsub = 1; 905167465Smp if (global & FLAG_A) { 90659243Sobrien while (didone && tword != STRNULL) { 90759243Sobrien otword = tword; 908167465Smp tword = subword(otword, sc, &didone, &pos); 90959243Sobrien if (Strcmp(tword, otword) == 0) { 910167465Smp xfree(otword); 91159243Sobrien break; 91259243Sobrien } 91359243Sobrien else 914167465Smp xfree(otword); 91559243Sobrien } 91659243Sobrien } 91759243Sobrien } 91859243Sobrien else 91959243Sobrien tword = Strsave(en->word); 92059243Sobrien wdp->word = tword; 92159243Sobrien } 92259243Sobrien } 92359243Sobrien if (didsub == 0) 92459243Sobrien seterror(ERR_MODFAIL); 92559243Sobrien hp->prev = wdp; 92659243Sobrien /* 92759243Sobrien * ANSI mode HP/UX compiler chokes on 92859243Sobrien * return &enthist(HIST_PURGE, &lexi, 0)->Hlex; 92959243Sobrien */ 93059243Sobrien hst = enthist(HIST_PURGE, &lexi, 0, 0); 93159243Sobrien return &(hst->Hlex); 93259243Sobrien} 93359243Sobrien 934167465Smp/* Return a newly allocated result of one modification of CP using the 935167465Smp operation TYPE. Set ADID to 1 if a modification was performed. 936167465Smp If TYPE == 's', perform substitutions only from *START_POS on and set 937167465Smp *START_POS to the position of next substitution attempt. */ 93859243Sobrienstatic Char * 939167465Smpsubword(Char *cp, Char type, int *adid, size_t *start_pos) 94059243Sobrien{ 941167465Smp Char *wp; 942167465Smp const Char *mp, *np; 94359243Sobrien 94459243Sobrien switch (type) { 94559243Sobrien 94659243Sobrien case 'r': 94759243Sobrien case 'e': 94859243Sobrien case 'h': 94959243Sobrien case 't': 95059243Sobrien case 'q': 95159243Sobrien case 'x': 95259243Sobrien case 'u': 95359243Sobrien case 'l': 95459243Sobrien wp = domod(cp, type); 955167465Smp if (wp == 0) { 956167465Smp *adid = 0; 95759243Sobrien return (Strsave(cp)); 958167465Smp } 95959243Sobrien *adid = 1; 96059243Sobrien return (wp); 96159243Sobrien 96259243Sobrien default: 963167465Smp for (mp = cp + *start_pos; *mp; mp++) { 964167465Smp if (matchs(mp, lhsb.s)) { 965167465Smp struct Strbuf wbuf = Strbuf_INIT; 966167465Smp 967167465Smp Strbuf_appendn(&wbuf, cp, mp - cp); 968167465Smp for (np = rhsb.s; *np; np++) 96959243Sobrien switch (*np) { 97059243Sobrien 97159243Sobrien case '\\': 97259243Sobrien if (np[1] == '&') 97359243Sobrien np++; 97459243Sobrien /* fall into ... */ 97559243Sobrien 97659243Sobrien default: 977167465Smp Strbuf_append1(&wbuf, *np); 97859243Sobrien continue; 97959243Sobrien 98059243Sobrien case '&': 981167465Smp Strbuf_append(&wbuf, lhsb.s); 98259243Sobrien continue; 98359243Sobrien } 984167465Smp *start_pos = wbuf.len; 985167465Smp Strbuf_append(&wbuf, mp + lhsb.len); 98659243Sobrien *adid = 1; 987167465Smp return Strbuf_finish(&wbuf); 98859243Sobrien } 989167465Smp } 990167465Smp *adid = 0; 99159243Sobrien return (Strsave(cp)); 99259243Sobrien } 99359243Sobrien} 99459243Sobrien 99559243SobrienChar * 996167465Smpdomod(Char *cp, Char type) 99759243Sobrien{ 99859243Sobrien Char *wp, *xp; 99959243Sobrien int c; 100059243Sobrien 100159243Sobrien switch (type) { 100259243Sobrien 100359243Sobrien case 'x': 100459243Sobrien case 'q': 100559243Sobrien wp = Strsave(cp); 100659243Sobrien for (xp = wp; (c = *xp) != 0; xp++) 100759243Sobrien if ((c != ' ' && c != '\t') || type == 'q') 100859243Sobrien *xp |= QUOTE; 100959243Sobrien return (wp); 101059243Sobrien 101159243Sobrien case 'l': 1012145479Smp wp = NLSChangeCase(cp, 1); 1013145479Smp return wp ? wp : Strsave(cp); 101459243Sobrien 101559243Sobrien case 'u': 1016145479Smp wp = NLSChangeCase(cp, 0); 1017145479Smp return wp ? wp : Strsave(cp); 101859243Sobrien 101959243Sobrien case 'h': 102059243Sobrien case 't': 102159243Sobrien if (!any(short2str(cp), '/')) 102259243Sobrien return (type == 't' ? Strsave(cp) : 0); 1023167465Smp wp = Strrchr(cp, '/'); 102459243Sobrien if (type == 'h') 1025167465Smp xp = Strnsave(cp, wp - cp); 102659243Sobrien else 102759243Sobrien xp = Strsave(wp + 1); 102859243Sobrien return (xp); 102959243Sobrien 103059243Sobrien case 'e': 103159243Sobrien case 'r': 103259243Sobrien wp = Strend(cp); 103359243Sobrien for (wp--; wp >= cp && *wp != '/'; wp--) 103459243Sobrien if (*wp == '.') { 103559243Sobrien if (type == 'e') 103659243Sobrien xp = Strsave(wp + 1); 103759243Sobrien else 1038167465Smp xp = Strnsave(cp, wp - cp); 103959243Sobrien return (xp); 104059243Sobrien } 104159243Sobrien return (Strsave(type == 'e' ? STRNULL : cp)); 104259243Sobrien default: 104359243Sobrien break; 104459243Sobrien } 104559243Sobrien return (0); 104659243Sobrien} 104759243Sobrien 104859243Sobrienstatic int 1049167465Smpmatchs(const Char *str, const Char *pat) 105059243Sobrien{ 105159243Sobrien while (*str && *pat && *str == *pat) 105259243Sobrien str++, pat++; 105359243Sobrien return (*pat == 0); 105459243Sobrien} 105559243Sobrien 105659243Sobrienstatic int 1057167465Smpgetsel(int *al, int *ar, int dol) 105859243Sobrien{ 1059145479Smp eChar c = getC(0); 106059243Sobrien int i; 1061145479Smp int first = *al < 0; 106259243Sobrien 106359243Sobrien switch (c) { 106459243Sobrien 106559243Sobrien case '%': 106659243Sobrien if (quesarg == -1) { 106759243Sobrien seterror(ERR_BADBANGARG); 106859243Sobrien return (0); 106959243Sobrien } 107059243Sobrien if (*al < 0) 107159243Sobrien *al = quesarg; 107259243Sobrien *ar = quesarg; 107359243Sobrien break; 107459243Sobrien 107559243Sobrien case '-': 107659243Sobrien if (*al < 0) { 107759243Sobrien *al = 0; 107859243Sobrien *ar = dol - 1; 107959243Sobrien unreadc(c); 108059243Sobrien } 108159243Sobrien return (1); 108259243Sobrien 108359243Sobrien case '^': 108459243Sobrien if (*al < 0) 108559243Sobrien *al = 1; 108659243Sobrien *ar = 1; 108759243Sobrien break; 108859243Sobrien 108959243Sobrien case '$': 109059243Sobrien if (*al < 0) 109159243Sobrien *al = dol; 109259243Sobrien *ar = dol; 109359243Sobrien break; 109459243Sobrien 109559243Sobrien case '*': 109659243Sobrien if (*al < 0) 109759243Sobrien *al = 1; 109859243Sobrien *ar = dol; 109959243Sobrien if (*ar < *al) { 110059243Sobrien *ar = 0; 110159243Sobrien *al = 1; 110259243Sobrien return (1); 110359243Sobrien } 110459243Sobrien break; 110559243Sobrien 110659243Sobrien default: 110759243Sobrien if (Isdigit(c)) { 110859243Sobrien i = 0; 110959243Sobrien while (Isdigit(c)) { 111059243Sobrien i = i * 10 + c - '0'; 111159243Sobrien c = getC(0); 111259243Sobrien } 111359243Sobrien if (i < 0) 111459243Sobrien i = dol + 1; 111559243Sobrien if (*al < 0) 111659243Sobrien *al = i; 111759243Sobrien *ar = i; 111859243Sobrien } 111959243Sobrien else if (*al < 0) 112059243Sobrien *al = 0, *ar = dol; 112159243Sobrien else 112259243Sobrien *ar = dol - 1; 112359243Sobrien unreadc(c); 112459243Sobrien break; 112559243Sobrien } 112659243Sobrien if (first) { 112759243Sobrien c = getC(0); 112859243Sobrien unreadc(c); 112959243Sobrien if (any("-$*", c)) 113059243Sobrien return (1); 113159243Sobrien } 113259243Sobrien if (*al > *ar || *ar > dol) { 113359243Sobrien seterror(ERR_BADBANGARG); 113459243Sobrien return (0); 113559243Sobrien } 113659243Sobrien return (1); 113759243Sobrien 113859243Sobrien} 113959243Sobrien 114059243Sobrienstatic struct wordent * 1141167465Smpgethent(Char sc) 114259243Sobrien{ 114359243Sobrien struct Hist *hp; 114459243Sobrien Char *np; 1145145479Smp eChar c; 114659243Sobrien int event; 1147145479Smp int back = 0; 114859243Sobrien 1149145479Smp c = sc == HISTSUB ? (eChar)HIST : getC(0); 1150145479Smp if (c == (eChar)HIST) { 115159243Sobrien if (alhistp) 115259243Sobrien return (alhistp); 115359243Sobrien event = eventno; 115459243Sobrien } 115559243Sobrien else 115659243Sobrien switch (c) { 115759243Sobrien 115859243Sobrien case ':': 115959243Sobrien case '^': 116059243Sobrien case '$': 116159243Sobrien case '*': 116259243Sobrien case '%': 116359243Sobrien ungetC(c); 116459243Sobrien if (lastev == eventno && alhistp) 116559243Sobrien return (alhistp); 116659243Sobrien event = lastev; 116759243Sobrien break; 116859243Sobrien 116959243Sobrien case '#': /* !# is command being typed in (mrh) */ 117059243Sobrien if (--hleft == 0) { 117159243Sobrien seterror(ERR_HISTLOOP); 117259243Sobrien return (0); 117359243Sobrien } 117459243Sobrien else 117559243Sobrien return (¶ml); 117659243Sobrien /* NOTREACHED */ 117759243Sobrien 117859243Sobrien case '-': 117959243Sobrien back = 1; 118059243Sobrien c = getC(0); 118159243Sobrien /* FALLSTHROUGH */ 118259243Sobrien 118359243Sobrien default: 118459243Sobrien if (any("(=~", c)) { 118559243Sobrien unreadc(c); 118659243Sobrien ungetC(HIST); 118759243Sobrien return (0); 118859243Sobrien } 1189167465Smp Strbuf_terminate(&lhsb); 1190167465Smp lhsb.len = 0; 119159243Sobrien event = 0; 119259243Sobrien while (!cmap(c, _ESC | _META | _QF | _QB) && !any("^*-%${}:#", c)) { 119359243Sobrien if (event != -1 && Isdigit(c)) 119459243Sobrien event = event * 10 + c - '0'; 119559243Sobrien else 119659243Sobrien event = -1; 1197167465Smp Strbuf_append1(&lhsb, c); 119859243Sobrien c = getC(0); 119959243Sobrien } 120059243Sobrien unreadc(c); 1201167465Smp if (lhsb.len == 0) { 1202167465Smp lhsb.len = Strlen(lhsb.s); /* lhsb.s wasn't changed */ 120359243Sobrien ungetC(HIST); 120459243Sobrien return (0); 120559243Sobrien } 1206167465Smp Strbuf_terminate(&lhsb); 120759243Sobrien if (event != -1) { 120859243Sobrien /* 120959243Sobrien * History had only digits 121059243Sobrien */ 121159243Sobrien if (back) 1212167465Smp event = eventno + (alhistp == 0) - event; 121359243Sobrien break; 121459243Sobrien } 121559243Sobrien if (back) { 1216167465Smp Strbuf_append1(&lhsb, '\0'); /* Allocate space */ 1217167465Smp Strbuf_terminate(&lhsb); 1218167465Smp memmove(lhsb.s + 1, lhsb.s, (lhsb.len - 1) * sizeof (*lhsb.s)); 1219167465Smp lhsb.s[0] = '-'; 122059243Sobrien } 1221167465Smp hp = findev(lhsb.s, 0); 122259243Sobrien if (hp) 122359243Sobrien lastev = hp->Hnum; 122459243Sobrien return (&hp->Hlex); 122559243Sobrien 122659243Sobrien case '?': 1227167465Smp Strbuf_terminate(&lhsb); 1228167465Smp lhsb.len = 0; 122959243Sobrien for (;;) { 123059243Sobrien c = getC(0); 123159243Sobrien if (c == '\n') { 123259243Sobrien unreadc(c); 123359243Sobrien break; 123459243Sobrien } 123559243Sobrien if (c == '?') 123659243Sobrien break; 1237167465Smp Strbuf_append1(&lhsb, c); 123859243Sobrien } 1239167465Smp if (lhsb.len == 0) { 1240167465Smp lhsb.len = Strlen(lhsb.s); /* lhsb.s wasn't changed */ 1241167465Smp if (lhsb.len == 0) { 124259243Sobrien seterror(ERR_NOSEARCH); 124359243Sobrien return (0); 124459243Sobrien } 124559243Sobrien } 124659243Sobrien else 1247167465Smp Strbuf_terminate(&lhsb); 1248167465Smp hp = findev(lhsb.s, 1); 124959243Sobrien if (hp) 125059243Sobrien lastev = hp->Hnum; 125159243Sobrien return (&hp->Hlex); 125259243Sobrien } 125359243Sobrien 125459243Sobrien for (hp = Histlist.Hnext; hp; hp = hp->Hnext) 125559243Sobrien if (hp->Hnum == event) { 125659243Sobrien hp->Href = eventno; 125759243Sobrien lastev = hp->Hnum; 125859243Sobrien return (&hp->Hlex); 125959243Sobrien } 126059243Sobrien np = putn(event); 126159243Sobrien seterror(ERR_NOEVENT, short2str(np)); 1262167465Smp xfree(np); 126359243Sobrien return (0); 126459243Sobrien} 126559243Sobrien 126659243Sobrienstatic struct Hist * 1267167465Smpfindev(Char *cp, int anyarg) 126859243Sobrien{ 126959243Sobrien struct Hist *hp; 127059243Sobrien 127159243Sobrien for (hp = Histlist.Hnext; hp; hp = hp->Hnext) { 127259243Sobrien Char *dp; 127359243Sobrien Char *p, *q; 127459243Sobrien struct wordent *lp = hp->Hlex.next; 127559243Sobrien int argno = 0; 127659243Sobrien 127759243Sobrien /* 127859243Sobrien * The entries added by alias substitution don't have a newline but do 127959243Sobrien * have a negative event number. Savehist() trims off these entries, 128059243Sobrien * but it happens before alias expansion, too early to delete those 128159243Sobrien * from the previous command. 128259243Sobrien */ 128359243Sobrien if (hp->Hnum < 0) 128459243Sobrien continue; 128559243Sobrien if (lp->word[0] == '\n') 128659243Sobrien continue; 128759243Sobrien if (!anyarg) { 128859243Sobrien p = cp; 128959243Sobrien q = lp->word; 129059243Sobrien do 129159243Sobrien if (!*p) 129259243Sobrien return (hp); 129359243Sobrien while (*p++ == *q++); 129459243Sobrien continue; 129559243Sobrien } 129659243Sobrien do { 129759243Sobrien for (dp = lp->word; *dp; dp++) { 129859243Sobrien p = cp; 129959243Sobrien q = dp; 130059243Sobrien do 130159243Sobrien if (!*p) { 130259243Sobrien quesarg = argno; 130359243Sobrien return (hp); 130459243Sobrien } 130559243Sobrien while (*p++ == *q++); 130659243Sobrien } 130759243Sobrien lp = lp->next; 130859243Sobrien argno++; 130959243Sobrien } while (lp->word[0] != '\n'); 131059243Sobrien } 131159243Sobrien seterror(ERR_NOEVENT, short2str(cp)); 131259243Sobrien return (0); 131359243Sobrien} 131459243Sobrien 131559243Sobrien 131659243Sobrienstatic void 1317167465Smpsetexclp(Char *cp) 131859243Sobrien{ 131959243Sobrien if (cp && cp[0] == '\n') 132059243Sobrien return; 132159243Sobrien exclp = cp; 132259243Sobrien} 132359243Sobrien 132459243Sobrienvoid 1325167465Smpunreadc(Char c) 132659243Sobrien{ 132759243Sobrien peekread = (Char) c; 132859243Sobrien} 132959243Sobrien 1330145479SmpeChar 1331167465Smpreadc(int wanteof) 133259243Sobrien{ 1333145479Smp eChar c; 133459243Sobrien static int sincereal; /* Number of real EOFs we've seen */ 133559243Sobrien 133659243Sobrien#ifdef DEBUG_INP 133759243Sobrien xprintf("readc\n"); 133859243Sobrien#endif 133959243Sobrien if ((c = peekread) != 0) { 134059243Sobrien peekread = 0; 134159243Sobrien return (c); 134259243Sobrien } 134359243Sobrien 134459243Sobrientop: 134569408Sache aret = TCSH_F_SEEK; 134659243Sobrien if (alvecp) { 134759243Sobrien arun = 1; 134859243Sobrien#ifdef DEBUG_INP 134959243Sobrien xprintf("alvecp %c\n", *alvecp & 0xff); 135059243Sobrien#endif 135169408Sache aret = TCSH_A_SEEK; 135259243Sobrien if ((c = *alvecp++) != 0) 135359243Sobrien return (c); 135459243Sobrien if (alvec && *alvec) { 135559243Sobrien alvecp = *alvec++; 135659243Sobrien return (' '); 135759243Sobrien } 135859243Sobrien else { 135959243Sobrien alvecp = NULL; 136069408Sache aret = TCSH_F_SEEK; 136159243Sobrien return('\n'); 136259243Sobrien } 136359243Sobrien } 136459243Sobrien if (alvec) { 136559243Sobrien arun = 1; 136659243Sobrien if ((alvecp = *alvec) != 0) { 136759243Sobrien alvec++; 136859243Sobrien goto top; 136959243Sobrien } 137059243Sobrien /* Infinite source! */ 137159243Sobrien return ('\n'); 137259243Sobrien } 137359243Sobrien arun = 0; 137459243Sobrien if (evalp) { 137569408Sache aret = TCSH_E_SEEK; 137659243Sobrien if ((c = *evalp++) != 0) 137759243Sobrien return (c); 137859243Sobrien if (evalvec && *evalvec) { 137959243Sobrien evalp = *evalvec++; 138059243Sobrien return (' '); 138159243Sobrien } 138269408Sache aret = TCSH_F_SEEK; 138359243Sobrien evalp = 0; 138459243Sobrien } 138559243Sobrien if (evalvec) { 138659243Sobrien if (evalvec == INVPPTR) { 138759243Sobrien doneinp = 1; 138859243Sobrien reset(); 138959243Sobrien } 139059243Sobrien if ((evalp = *evalvec) != 0) { 139159243Sobrien evalvec++; 139259243Sobrien goto top; 139359243Sobrien } 139459243Sobrien evalvec = INVPPTR; 139559243Sobrien return ('\n'); 139659243Sobrien } 139759243Sobrien do { 139859243Sobrien if (arginp == INVPTR || onelflg == 1) { 139959243Sobrien if (wanteof) 1400145479Smp return CHAR_ERR; 140159243Sobrien exitstat(); 140259243Sobrien } 140359243Sobrien if (arginp) { 140459243Sobrien if ((c = *arginp++) == 0) { 140559243Sobrien arginp = INVPTR; 140659243Sobrien return ('\n'); 140759243Sobrien } 140859243Sobrien return (c); 140959243Sobrien } 141059243Sobrien#ifdef BSDJOBS 141159243Sobrienreread: 141259243Sobrien#endif /* BSDJOBS */ 141359243Sobrien c = bgetc(); 1414145479Smp if (c == CHAR_ERR) { 141569408Sache#ifndef WINNT_NATIVE 141659243Sobrien# ifndef POSIX 141759243Sobrien# ifdef TERMIO 141859243Sobrien struct termio tty; 141959243Sobrien# else /* SGTTYB */ 142059243Sobrien struct sgttyb tty; 142159243Sobrien# endif /* TERMIO */ 142259243Sobrien# else /* POSIX */ 142359243Sobrien struct termios tty; 142459243Sobrien# endif /* POSIX */ 142569408Sache#endif /* !WINNT_NATIVE */ 142659243Sobrien if (wanteof) 1427145479Smp return CHAR_ERR; 142859243Sobrien /* was isatty but raw with ignoreeof yields problems */ 142969408Sache#ifndef WINNT_NATIVE 143059243Sobrien# ifndef POSIX 143159243Sobrien# ifdef TERMIO 143259243Sobrien if (ioctl(SHIN, TCGETA, (ioctl_t) & tty) == 0 && 143359243Sobrien (tty.c_lflag & ICANON)) 143459243Sobrien# else /* GSTTYB */ 143559243Sobrien if (ioctl(SHIN, TIOCGETP, (ioctl_t) & tty) == 0 && 143659243Sobrien (tty.sg_flags & RAW) == 0) 143759243Sobrien# endif /* TERMIO */ 143859243Sobrien# else /* POSIX */ 143959243Sobrien if (tcgetattr(SHIN, &tty) == 0 && 144059243Sobrien (tty.c_lflag & ICANON)) 144159243Sobrien# endif /* POSIX */ 144269408Sache#else /* WINNT_NATIVE */ 144359243Sobrien if (isatty(SHIN)) 144469408Sache#endif /* !WINNT_NATIVE */ 144559243Sobrien { 144659243Sobrien#ifdef BSDJOBS 1447167465Smp pid_t ctpgrp; 144859243Sobrien#endif /* BSDJOBS */ 144959243Sobrien 1450100616Smp if (numeof != 0 && ++sincereal >= numeof) /* Too many EOFs? Bye! */ 145159243Sobrien goto oops; 145259243Sobrien#ifdef BSDJOBS 145359243Sobrien if (tpgrp != -1 && 145459243Sobrien (ctpgrp = tcgetpgrp(FSHTTY)) != -1 && 145559243Sobrien tpgrp != ctpgrp) { 145659243Sobrien (void) tcsetpgrp(FSHTTY, tpgrp); 145759243Sobrien# ifdef _SEQUENT_ 145859243Sobrien if (ctpgrp) 145959243Sobrien# endif /* _SEQUENT */ 1460167465Smp (void) killpg(ctpgrp, SIGHUP); 146159243Sobrien# ifdef notdef 146259243Sobrien /* 146359243Sobrien * With the walking process group fix, this message 146459243Sobrien * is now obsolete. As the foreground process group 146559243Sobrien * changes, the shell needs to adjust. Well too bad. 146659243Sobrien */ 146759243Sobrien xprintf(CGETS(16, 1, "Reset tty pgrp from %d to %d\n"), 1468167465Smp (int)ctpgrp, (int)tpgrp); 146959243Sobrien# endif /* notdef */ 147059243Sobrien goto reread; 147159243Sobrien } 147259243Sobrien#endif /* BSDJOBS */ 147359243Sobrien /* What follows is complicated EOF handling -- sterling@netcom.com */ 147459243Sobrien /* First, we check to see if we have ignoreeof set */ 147559243Sobrien if (adrof(STRignoreeof)) { 147659243Sobrien /* If so, we check for any stopped jobs only on the first EOF */ 147759243Sobrien if ((sincereal == 1) && (chkstop == 0)) { 147859243Sobrien panystop(1); 147959243Sobrien } 148059243Sobrien } else { 148159243Sobrien /* If we don't have ignoreeof set, always check for stopped jobs */ 148259243Sobrien if (chkstop == 0) { 148359243Sobrien panystop(1); 148459243Sobrien } 148559243Sobrien } 148659243Sobrien /* At this point, if there were stopped jobs, we would have already 148759243Sobrien * called reset(). If we got this far, assume we can print an 148859243Sobrien * exit/logout message if we ignoreeof, or just exit. 148959243Sobrien */ 149059243Sobrien if (adrof(STRignoreeof)) { 149159243Sobrien /* If so, tell the user to use exit or logout */ 149259243Sobrien if (loginsh) { 149359243Sobrien xprintf(CGETS(16, 2, 149459243Sobrien "\nUse \"logout\" to logout.\n")); 149559243Sobrien } else { 149659243Sobrien xprintf(CGETS(16, 3, 149759243Sobrien "\nUse \"exit\" to leave %s.\n"), 149859243Sobrien progname); 149959243Sobrien } 1500167465Smp reset(); 150159243Sobrien } else { 150259243Sobrien /* If we don't have ignoreeof set, just fall through */ 150359243Sobrien ; /* EMPTY */ 150459243Sobrien } 150559243Sobrien } 150659243Sobrien oops: 150759243Sobrien doneinp = 1; 150859243Sobrien reset(); 150959243Sobrien } 151059243Sobrien sincereal = 0; 151159243Sobrien if (c == '\n' && onelflg) 151259243Sobrien onelflg--; 151359243Sobrien } while (c == 0); 1514167465Smp Strbuf_append1(&histline, c); 151559243Sobrien return (c); 151659243Sobrien} 151759243Sobrien 151859243Sobrienstatic void 1519167465Smpballoc(int buf) 152059243Sobrien{ 152159243Sobrien Char **nfbuf; 152259243Sobrien 152359243Sobrien while (buf >= fblocks) { 1524167465Smp nfbuf = xcalloc(fblocks + 2, sizeof(Char **)); 152559243Sobrien if (fbuf) { 152659243Sobrien (void) blkcpy(nfbuf, fbuf); 1527167465Smp xfree(fbuf); 152859243Sobrien } 152959243Sobrien fbuf = nfbuf; 1530167465Smp fbuf[fblocks] = xcalloc(BUFSIZE, sizeof(Char)); 153159243Sobrien fblocks++; 153259243Sobrien } 153359243Sobrien} 153459243Sobrien 1535145479Smpstatic ssize_t 1536167465Smpwide_read(int fildes, Char *buf, size_t nchars, int use_fclens) 1537145479Smp{ 1538145479Smp char cbuf[BUFSIZE + 1]; 1539167465Smp ssize_t res, r = 0; 1540145479Smp size_t partial; 1541167465Smp int err; 1542167465Smp 1543167465Smp if (nchars == 0) 1544167465Smp return 0; 1545167465Smp assert (nchars <= sizeof(cbuf) / sizeof(*cbuf)); 1546145479Smp USE(use_fclens); 1547145479Smp res = 0; 1548145479Smp partial = 0; 1549145479Smp do { 1550145479Smp size_t i; 1551167465Smp size_t len = nchars > partial ? nchars - partial : 1; 1552167465Smp 1553167465Smp if (partial + len >= sizeof(cbuf) / sizeof(*cbuf)) 1554167465Smp break; 1555145479Smp 1556167465Smp r = xread(fildes, cbuf + partial, len); 1557167465Smp 1558145479Smp if (partial == 0 && r <= 0) 1559145479Smp break; 1560145479Smp partial += r; 1561145479Smp i = 0; 1562167465Smp while (i < partial && nchars != 0) { 1563167465Smp int tlen; 1564145479Smp 1565167465Smp tlen = normal_mbtowc(buf + res, cbuf + i, partial - i); 1566167465Smp if (tlen == -1) { 1567145479Smp reset_mbtowc(); 1568167465Smp if ((partial - i) < MB_LEN_MAX && r > 0) 1569145479Smp /* Maybe a partial character and there is still a chance 1570145479Smp to read more */ 1571145479Smp break; 1572145479Smp buf[res] = (unsigned char)cbuf[i] | INVALID_BYTE; 1573145479Smp } 1574167465Smp if (tlen <= 0) 1575167465Smp tlen = 1; 1576145479Smp#ifdef WIDE_STRINGS 1577145479Smp if (use_fclens) 1578167465Smp fclens[res] = tlen; 1579145479Smp#endif 1580167465Smp i += tlen; 1581145479Smp res++; 1582145479Smp nchars--; 1583145479Smp } 1584145479Smp if (i != partial) 1585145479Smp memmove(cbuf, cbuf + i, partial - i); 1586145479Smp partial -= i; 1587167465Smp } while (partial != 0 && nchars > 0); 1588167465Smp /* Throwing away possible partial multibyte characters on error if the 1589167465Smp stream is not seekable */ 1590167465Smp err = errno; 1591167465Smp lseek(fildes, -(off_t)partial, L_INCR); 1592167465Smp errno = err; 1593145479Smp return res != 0 ? res : r; 1594145479Smp} 1595145479Smp 1596145479Smpstatic eChar 1597167465Smpbgetc(void) 159859243Sobrien{ 1599145479Smp Char ch; 160059243Sobrien int c, off, buf; 160159243Sobrien int numleft = 0, roomleft; 160259243Sobrien 160359243Sobrien if (cantell) { 160459243Sobrien if (fseekp < fbobp || fseekp > feobp) { 160559243Sobrien fbobp = feobp = fseekp; 160659243Sobrien (void) lseek(SHIN, fseekp, L_SET); 160759243Sobrien } 160859243Sobrien if (fseekp == feobp) { 1609167465Smp#ifdef WIDE_STRINGS 1610167465Smp off_t bytes; 1611167465Smp size_t i; 1612167465Smp 1613167465Smp bytes = fbobp; 1614167465Smp for (i = 0; i < (size_t)(feobp - fbobp); i++) 1615167465Smp bytes += fclens[i]; 1616167465Smp fseekp = feobp = bytes; 1617167465Smp#endif 161859243Sobrien fbobp = feobp; 1619167465Smp c = wide_read(SHIN, fbuf[0], BUFSIZE, 1); 162059243Sobrien#ifdef convex 162159243Sobrien if (c < 0) 162259243Sobrien stderror(ERR_SYSTEM, progname, strerror(errno)); 162359243Sobrien#endif /* convex */ 162459243Sobrien if (c <= 0) 1625145479Smp return CHAR_ERR; 162659243Sobrien feobp += c; 162759243Sobrien } 162869408Sache#ifndef WINNT_NATIVE 1629145479Smp ch = fbuf[0][fseekp - fbobp]; 163059243Sobrien fseekp++; 163159243Sobrien#else 163259243Sobrien do { 1633145479Smp ch = fbuf[0][fseekp - fbobp]; 163459243Sobrien fseekp++; 1635145479Smp } while(ch == '\r'); 163669408Sache#endif /* !WINNT_NATIVE */ 1637145479Smp return (ch); 163859243Sobrien } 163959243Sobrien 164059243Sobrien while (fseekp >= feobp) { 1641100616Smp if ((editing 1642100616Smp#if defined(FILEC) && defined(TIOCSTI) 1643100616Smp || filec 1644100616Smp#endif /* FILEC && TIOCSTI */ 1645100616Smp ) && intty) { /* then use twenex routine */ 164659243Sobrien fseekp = feobp; /* where else? */ 1647100616Smp#if defined(FILEC) && defined(TIOCSTI) 1648100616Smp if (!editing) 1649100616Smp c = numleft = tenex(InputBuf, BUFSIZE); 1650100616Smp else 1651100616Smp#endif /* FILEC && TIOCSTI */ 165259243Sobrien c = numleft = Inputl(); /* PWP: get a line */ 165359243Sobrien while (numleft > 0) { 165459243Sobrien off = (int) feobp % BUFSIZE; 165559243Sobrien buf = (int) feobp / BUFSIZE; 165659243Sobrien balloc(buf); 165759243Sobrien roomleft = BUFSIZE - off; 165859243Sobrien if (roomleft > numleft) 165959243Sobrien roomleft = numleft; 1660167465Smp (void) memcpy(fbuf[buf] + off, InputBuf + c - numleft, 1661167465Smp roomleft * sizeof(Char)); 166259243Sobrien numleft -= roomleft; 166359243Sobrien feobp += roomleft; 166459243Sobrien } 1665100616Smp } else { 166659243Sobrien off = (int) feobp % BUFSIZE; 166759243Sobrien buf = (int) feobp / BUFSIZE; 166859243Sobrien balloc(buf); 166959243Sobrien roomleft = BUFSIZE - off; 1670167465Smp c = wide_read(SHIN, fbuf[buf] + off, roomleft, 0); 1671145479Smp if (c > 0) 167259243Sobrien feobp += c; 167359243Sobrien } 167459243Sobrien if (c == 0 || (c < 0 && fixio(SHIN, errno) == -1)) 1675145479Smp return CHAR_ERR; 167659243Sobrien } 1677145479Smp#ifdef SIG_WINDOW 1678145479Smp if (windowchg) 1679145479Smp (void) check_window_size(0); /* for window systems */ 1680145479Smp#endif /* SIG_WINDOW */ 168169408Sache#ifndef WINNT_NATIVE 1682145479Smp ch = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE]; 168359243Sobrien fseekp++; 168459243Sobrien#else 168559243Sobrien do { 1686145479Smp ch = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE]; 168759243Sobrien fseekp++; 1688145479Smp } while(ch == '\r'); 168969408Sache#endif /* !WINNT_NATIVE */ 1690145479Smp return (ch); 169159243Sobrien} 169259243Sobrien 169359243Sobrienstatic void 1694167465Smpbfree(void) 169559243Sobrien{ 169659243Sobrien int sb, i; 169759243Sobrien 169859243Sobrien if (cantell) 169959243Sobrien return; 170059243Sobrien if (whyles) 170159243Sobrien return; 170259243Sobrien sb = (int) (fseekp - 1) / BUFSIZE; 170359243Sobrien if (sb > 0) { 170459243Sobrien for (i = 0; i < sb; i++) 1705167465Smp xfree(fbuf[i]); 170659243Sobrien (void) blkcpy(fbuf, &fbuf[sb]); 170759243Sobrien fseekp -= BUFSIZE * sb; 170859243Sobrien feobp -= BUFSIZE * sb; 170959243Sobrien fblocks -= sb; 171059243Sobrien } 171159243Sobrien} 171259243Sobrien 171359243Sobrienvoid 1714167465Smpbseek(struct Ain *l) 171559243Sobrien{ 171659243Sobrien switch (aret = l->type) { 171769408Sache case TCSH_E_SEEK: 171859243Sobrien evalvec = l->a_seek; 171959243Sobrien evalp = l->c_seek; 172059243Sobrien#ifdef DEBUG_SEEK 172159243Sobrien xprintf(CGETS(16, 4, "seek to eval %x %x\n"), evalvec, evalp); 172259243Sobrien#endif 172359243Sobrien return; 172469408Sache case TCSH_A_SEEK: 172559243Sobrien alvec = l->a_seek; 172659243Sobrien alvecp = l->c_seek; 172759243Sobrien#ifdef DEBUG_SEEK 172859243Sobrien xprintf(CGETS(16, 5, "seek to alias %x %x\n"), alvec, alvecp); 172959243Sobrien#endif 173059243Sobrien return; 173169408Sache case TCSH_F_SEEK: 173259243Sobrien#ifdef DEBUG_SEEK 173359243Sobrien xprintf(CGETS(16, 6, "seek to file %x\n"), fseekp); 173459243Sobrien#endif 173559243Sobrien fseekp = l->f_seek; 1736145479Smp#ifdef WIDE_STRINGS 1737145479Smp if (cantell) { 1738167465Smp if (fseekp >= fbobp && feobp >= fbobp) { 1739145479Smp size_t i; 1740145479Smp off_t o; 1741145479Smp 1742145479Smp o = fbobp; 1743167465Smp for (i = 0; i < (size_t)(feobp - fbobp); i++) { 1744145479Smp if (fseekp == o) { 1745145479Smp fseekp = fbobp + i; 1746145479Smp return; 1747145479Smp } 1748145479Smp o += fclens[i]; 1749145479Smp } 1750145479Smp if (fseekp == o) { 1751145479Smp fseekp = feobp; 1752145479Smp return; 1753145479Smp } 1754145479Smp } 1755145479Smp fbobp = feobp = fseekp + 1; /* To force lseek() */ 1756145479Smp } 1757145479Smp#endif 175859243Sobrien return; 175959243Sobrien default: 176059243Sobrien xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret); 176159243Sobrien abort(); 176259243Sobrien } 176359243Sobrien} 176459243Sobrien 176559243Sobrien/* any similarity to bell telephone is purely accidental */ 176659243Sobrienvoid 1767167465Smpbtell(struct Ain *l) 176859243Sobrien{ 176959243Sobrien switch (l->type = aret) { 177069408Sache case TCSH_E_SEEK: 177159243Sobrien l->a_seek = evalvec; 177259243Sobrien l->c_seek = evalp; 177359243Sobrien#ifdef DEBUG_SEEK 177459243Sobrien xprintf(CGETS(16, 8, "tell eval %x %x\n"), evalvec, evalp); 177559243Sobrien#endif 177659243Sobrien return; 177769408Sache case TCSH_A_SEEK: 177859243Sobrien l->a_seek = alvec; 177959243Sobrien l->c_seek = alvecp; 178059243Sobrien#ifdef DEBUG_SEEK 178159243Sobrien xprintf(CGETS(16, 9, "tell alias %x %x\n"), alvec, alvecp); 178259243Sobrien#endif 178359243Sobrien return; 178469408Sache case TCSH_F_SEEK: 1785145479Smp#ifdef WIDE_STRINGS 1786167465Smp if (cantell && fseekp >= fbobp && fseekp <= feobp) { 1787145479Smp size_t i; 1788167465Smp 1789145479Smp l->f_seek = fbobp; 1790167465Smp for (i = 0; i < (size_t)(fseekp - fbobp); i++) 1791145479Smp l->f_seek += fclens[i]; 1792145479Smp } else 1793145479Smp#endif 1794145479Smp /*SUPPRESS 112*/ 1795145479Smp l->f_seek = fseekp; 179659243Sobrien l->a_seek = NULL; 179759243Sobrien#ifdef DEBUG_SEEK 179859243Sobrien xprintf(CGETS(16, 10, "tell file %x\n"), fseekp); 179959243Sobrien#endif 180059243Sobrien return; 180159243Sobrien default: 180259243Sobrien xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret); 180359243Sobrien abort(); 180459243Sobrien } 180559243Sobrien} 180659243Sobrien 180759243Sobrienvoid 1808167465Smpbtoeof(void) 180959243Sobrien{ 181059243Sobrien (void) lseek(SHIN, (off_t) 0, L_XTND); 181169408Sache aret = TCSH_F_SEEK; 181259243Sobrien fseekp = feobp; 181359243Sobrien alvec = NULL; 181459243Sobrien alvecp = NULL; 181559243Sobrien evalvec = NULL; 181659243Sobrien evalp = NULL; 181759243Sobrien wfree(); 181859243Sobrien bfree(); 181959243Sobrien} 182059243Sobrien 182159243Sobrienvoid 1822167465Smpsettell(void) 182359243Sobrien{ 182459243Sobrien off_t x; 182559243Sobrien cantell = 0; 182659243Sobrien if (arginp || onelflg || intty) 182759243Sobrien return; 182859243Sobrien if ((x = lseek(SHIN, (off_t) 0, L_INCR)) == -1) 182959243Sobrien return; 1830167465Smp fbuf = xcalloc(2, sizeof(Char **)); 183159243Sobrien fblocks = 1; 1832167465Smp fbuf[0] = xcalloc(BUFSIZE, sizeof(Char)); 183359243Sobrien fseekp = fbobp = feobp = x; 183459243Sobrien cantell = 1; 183559243Sobrien} 1836