sh.lex.c revision 59243
159243Sobrien/* $Header: /src/pub/tcsh/sh.lex.c,v 3.49 1998/04/08 13:58:54 christos Exp $ */ 259243Sobrien/* 359243Sobrien * sh.lex.c: Lexical analysis into tokens 459243Sobrien */ 559243Sobrien/*- 659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 759243Sobrien * All rights reserved. 859243Sobrien * 959243Sobrien * Redistribution and use in source and binary forms, with or without 1059243Sobrien * modification, are permitted provided that the following conditions 1159243Sobrien * are met: 1259243Sobrien * 1. Redistributions of source code must retain the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer. 1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1559243Sobrien * notice, this list of conditions and the following disclaimer in the 1659243Sobrien * documentation and/or other materials provided with the distribution. 1759243Sobrien * 3. All advertising materials mentioning features or use of this software 1859243Sobrien * must display the following acknowledgement: 1959243Sobrien * This product includes software developed by the University of 2059243Sobrien * California, Berkeley and its contributors. 2159243Sobrien * 4. Neither the name of the University nor the names of its contributors 2259243Sobrien * may be used to endorse or promote products derived from this software 2359243Sobrien * without specific prior written permission. 2459243Sobrien * 2559243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2659243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2759243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2859243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2959243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3059243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3159243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3259243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3359243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3459243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3559243Sobrien * SUCH DAMAGE. 3659243Sobrien */ 3759243Sobrien#include "sh.h" 3859243Sobrien 3959243SobrienRCSID("$Id: sh.lex.c,v 3.49 1998/04/08 13:58:54 christos Exp $") 4059243Sobrien 4159243Sobrien#include "ed.h" 4259243Sobrien/* #define DEBUG_INP */ 4359243Sobrien/* #define DEBUG_SEEK */ 4459243Sobrien 4559243Sobrien/* 4659243Sobrien * C shell 4759243Sobrien */ 4859243Sobrien 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 */ 5459243Sobrienstatic Char *word __P((void)); 5559243Sobrienstatic int getC1 __P((int)); 5659243Sobrienstatic void getdol __P((void)); 5759243Sobrienstatic void getexcl __P((int)); 5859243Sobrienstatic struct Hist *findev __P((Char *, bool)); 5959243Sobrienstatic void setexclp __P((Char *)); 6059243Sobrienstatic int bgetc __P((void)); 6159243Sobrienstatic void balloc __P((int)); 6259243Sobrienstatic void bfree __P((void)); 6359243Sobrienstatic struct wordent *gethent __P((int)); 6459243Sobrienstatic int matchs __P((Char *, Char *)); 6559243Sobrienstatic int getsel __P((int *, int *, int)); 6659243Sobrienstatic struct wordent *getsub __P((struct wordent *)); 6759243Sobrienstatic Char *subword __P((Char *, int, bool *)); 6859243Sobrienstatic struct wordent *dosub __P((int, struct wordent *, bool)); 6959243Sobrien 7059243Sobrien/* 7159243Sobrien * Peekc is a peek character for getC, peekread for readc. 7259243Sobrien * There is a subtlety here in many places... history routines 7359243Sobrien * will read ahead and then insert stuff into the input stream. 7459243Sobrien * If they push back a character then they must push it behind 7559243Sobrien * the text substituted by the history substitution. On the other 7659243Sobrien * hand in several places we need 2 peek characters. To make this 7759243Sobrien * all work, the history routines read with getC, and make use both 7859243Sobrien * of ungetC and unreadc. The key observation is that the state 7959243Sobrien * of getC at the call of a history reference is such that calls 8059243Sobrien * to getC from the history routines will always yield calls of 8159243Sobrien * readc, unless this peeking is involved. That is to say that during 8259243Sobrien * getexcl the variables lap, exclp, and exclnxt are all zero. 8359243Sobrien * 8459243Sobrien * Getdol invokes history substitution, hence the extra peek, peekd, 8559243Sobrien * which it can ungetD to be before history substitutions. 8659243Sobrien */ 8759243Sobrienstatic Char peekc = 0, peekd = 0; 8859243Sobrienstatic Char peekread = 0; 8959243Sobrien 9059243Sobrien/* (Tail of) current word from ! subst */ 9159243Sobrienstatic Char *exclp = NULL; 9259243Sobrien 9359243Sobrien/* The rest of the ! subst words */ 9459243Sobrienstatic struct wordent *exclnxt = NULL; 9559243Sobrien 9659243Sobrien/* Count of remaining words in ! subst */ 9759243Sobrienstatic int exclc = 0; 9859243Sobrien 9959243Sobrien/* "Globp" for alias resubstitution */ 10059243Sobrienint aret = F_SEEK; 10159243Sobrien 10259243Sobrien/* 10359243Sobrien * Labuf implements a general buffer for lookahead during lexical operations. 10459243Sobrien * Text which is to be placed in the input stream can be stuck here. 10559243Sobrien * We stick parsed ahead $ constructs during initial input, 10659243Sobrien * process id's from `$$', and modified variable values (from qualifiers 10759243Sobrien * during expansion in sh.dol.c) here. 10859243Sobrien */ 10959243Sobrienstatic Char labuf[BUFSIZE]; 11059243Sobrien 11159243Sobrien/* 11259243Sobrien * Lex returns to its caller not only a wordlist (as a "var" parameter) 11359243Sobrien * but also whether a history substitution occurred. This is used in 11459243Sobrien * the main (process) routine to determine whether to echo, and also 11559243Sobrien * when called by the alias routine to determine whether to keep the 11659243Sobrien * argument list. 11759243Sobrien */ 11859243Sobrienstatic bool hadhist = 0; 11959243Sobrien 12059243Sobrien/* 12159243Sobrien * Avoid alias expansion recursion via \!# 12259243Sobrien */ 12359243Sobrienint hleft; 12459243Sobrien 12559243SobrienChar histline[BUFSIZE + 2]; /* last line input */ 12659243Sobrien 12759243Sobrien /* The +2 is to fool hp's optimizer */ 12859243Sobrienbool histvalid = 0; /* is histline valid */ 12959243Sobrienstatic Char *histlinep = NULL; /* current pointer into histline */ 13059243Sobrien 13159243Sobrienstatic Char getCtmp; 13259243Sobrien 13359243Sobrien#define getC(f) (((getCtmp = peekc) != '\0') ? (peekc = 0, getCtmp) : getC1(f)) 13459243Sobrien#define ungetC(c) peekc = (Char) c 13559243Sobrien#define ungetD(c) peekd = (Char) c 13659243Sobrien 13759243Sobrien/* Use Htime to store timestamps picked up from history file for enthist() 13859243Sobrien * if reading saved history (sg) 13959243Sobrien */ 14059243Sobrientime_t Htime = (time_t)0; 14159243Sobrienstatic time_t a2time_t __P((Char *)); 14259243Sobrien 14359243Sobrien/* 14459243Sobrien * for history event processing 14559243Sobrien * in the command 'echo !?foo?:1 !$' we want the !$ to expand from the line 14659243Sobrien * 'foo' was found instead of the last command 14759243Sobrien */ 14859243Sobrienstatic int uselastevent = 1; 14959243Sobrien 15059243Sobrienint 15159243Sobrienlex(hp) 15259243Sobrien struct wordent *hp; 15359243Sobrien{ 15459243Sobrien struct wordent *wdp; 15559243Sobrien int c; 15659243Sobrien 15759243Sobrien 15859243Sobrien uselastevent = 1; 15959243Sobrien histvalid = 0; 16059243Sobrien histlinep = histline; 16159243Sobrien *histlinep = '\0'; 16259243Sobrien 16359243Sobrien btell(&lineloc); 16459243Sobrien hp->next = hp->prev = hp; 16559243Sobrien hp->word = STRNULL; 16659243Sobrien hadhist = 0; 16759243Sobrien do 16859243Sobrien c = readc(0); 16959243Sobrien while (c == ' ' || c == '\t'); 17059243Sobrien if (c == HISTSUB && intty) 17159243Sobrien /* ^lef^rit from tty is short !:s^lef^rit */ 17259243Sobrien getexcl(c); 17359243Sobrien else 17459243Sobrien unreadc(c); 17559243Sobrien wdp = hp; 17659243Sobrien /* 17759243Sobrien * The following loop is written so that the links needed by freelex will 17859243Sobrien * be ready and rarin to go even if it is interrupted. 17959243Sobrien */ 18059243Sobrien do { 18159243Sobrien struct wordent *new; 18259243Sobrien 18359243Sobrien new = (struct wordent *) xmalloc((size_t) sizeof(*wdp)); 18459243Sobrien new->word = STRNULL; 18559243Sobrien new->prev = wdp; 18659243Sobrien new->next = hp; 18759243Sobrien wdp->next = new; 18859243Sobrien hp->prev = new; 18959243Sobrien wdp = new; 19059243Sobrien wdp->word = word(); 19159243Sobrien } while (wdp->word[0] != '\n'); 19259243Sobrien if (histlinep < histline + BUFSIZE) { 19359243Sobrien *histlinep = '\0'; 19459243Sobrien if (histlinep > histline && histlinep[-1] == '\n') 19559243Sobrien histlinep[-1] = '\0'; 19659243Sobrien histvalid = 1; 19759243Sobrien } 19859243Sobrien else { 19959243Sobrien histline[BUFSIZE - 1] = '\0'; 20059243Sobrien } 20159243Sobrien 20259243Sobrien return (hadhist); 20359243Sobrien} 20459243Sobrien 20559243Sobrienstatic time_t 20659243Sobriena2time_t(word) 20759243Sobrien Char *word; 20859243Sobrien{ 20959243Sobrien /* Attempt to distinguish timestamps from other possible entries. 21059243Sobrien * Format: "+NNNNNNNNNN" (10 digits, left padded with ascii '0') */ 21159243Sobrien 21259243Sobrien time_t ret; 21359243Sobrien Char *s; 21459243Sobrien int ct; 21559243Sobrien 21659243Sobrien if (!word || *(s = word) != '+') 21759243Sobrien return (time_t)0; 21859243Sobrien 21959243Sobrien for (++s, ret = 0, ct = 0; *s; ++s, ++ct) 22059243Sobrien { 22159243Sobrien if (!isdigit((unsigned char)*s)) 22259243Sobrien return (time_t)0; 22359243Sobrien ret = ret * 10 + (time_t)((unsigned char)*s - '0'); 22459243Sobrien } 22559243Sobrien 22659243Sobrien if (ct != 10) 22759243Sobrien return (time_t)0; 22859243Sobrien 22959243Sobrien return ret; 23059243Sobrien} 23159243Sobrien 23259243Sobrienvoid 23359243Sobrienprlex(sp0) 23459243Sobrien struct wordent *sp0; 23559243Sobrien{ 23659243Sobrien struct wordent *sp = sp0->next; 23759243Sobrien 23859243Sobrien for (;;) { 23959243Sobrien xprintf("%S", sp->word); 24059243Sobrien sp = sp->next; 24159243Sobrien if (sp == sp0) 24259243Sobrien break; 24359243Sobrien if (sp->word[0] != '\n') 24459243Sobrien xputchar(' '); 24559243Sobrien } 24659243Sobrien} 24759243Sobrien 24859243Sobrienvoid 24959243Sobriencopylex(hp, fp) 25059243Sobrien struct wordent *hp; 25159243Sobrien struct wordent *fp; 25259243Sobrien{ 25359243Sobrien struct wordent *wdp; 25459243Sobrien 25559243Sobrien wdp = hp; 25659243Sobrien fp = fp->next; 25759243Sobrien do { 25859243Sobrien struct wordent *new; 25959243Sobrien 26059243Sobrien new = (struct wordent *) xmalloc((size_t) sizeof(*wdp)); 26159243Sobrien new->word = STRNULL; 26259243Sobrien new->prev = wdp; 26359243Sobrien new->next = hp; 26459243Sobrien wdp->next = new; 26559243Sobrien hp->prev = new; 26659243Sobrien wdp = new; 26759243Sobrien wdp->word = Strsave(fp->word); 26859243Sobrien fp = fp->next; 26959243Sobrien } while (wdp->word[0] != '\n'); 27059243Sobrien} 27159243Sobrien 27259243Sobrienvoid 27359243Sobrienfreelex(vp) 27459243Sobrien struct wordent *vp; 27559243Sobrien{ 27659243Sobrien struct wordent *fp; 27759243Sobrien 27859243Sobrien while (vp->next != vp) { 27959243Sobrien fp = vp->next; 28059243Sobrien vp->next = fp->next; 28159243Sobrien if (fp->word != STRNULL) 28259243Sobrien xfree((ptr_t) fp->word); 28359243Sobrien xfree((ptr_t) fp); 28459243Sobrien } 28559243Sobrien vp->prev = vp; 28659243Sobrien} 28759243Sobrien 28859243Sobrienstatic Char * 28959243Sobrienword() 29059243Sobrien{ 29159243Sobrien Char c, c1; 29259243Sobrien Char *wp; 29359243Sobrien Char wbuf[BUFSIZE]; 29459243Sobrien Char hbuf[12]; 29559243Sobrien int h; 29659243Sobrien bool dolflg; 29759243Sobrien int i; 29859243Sobrien 29959243Sobrien wp = wbuf; 30059243Sobrien i = BUFSIZE - 4; 30159243Sobrienloop: 30259243Sobrien while ((c = getC(DOALL)) == ' ' || c == '\t') 30359243Sobrien continue; 30459243Sobrien if (cmap(c, _META | _ESC)) 30559243Sobrien switch (c) { 30659243Sobrien case '&': 30759243Sobrien case '|': 30859243Sobrien case '<': 30959243Sobrien case '>': 31059243Sobrien *wp++ = c; 31159243Sobrien c1 = getC(DOALL); 31259243Sobrien if (c1 == c) 31359243Sobrien *wp++ = c1; 31459243Sobrien else 31559243Sobrien ungetC(c1); 31659243Sobrien goto ret; 31759243Sobrien 31859243Sobrien case '#': 31959243Sobrien if (intty) 32059243Sobrien break; 32159243Sobrien c = 0; 32259243Sobrien h = 0; 32359243Sobrien do { 32459243Sobrien c1 = c; 32559243Sobrien c = getC(0); 32659243Sobrien if (h < 12) 32759243Sobrien hbuf[h++] = c; 32859243Sobrien } while (c != '\n'); 32959243Sobrien hbuf[11] = '\0'; 33059243Sobrien Htime = a2time_t(hbuf); 33159243Sobrien if (c1 == '\\') 33259243Sobrien goto loop; 33359243Sobrien /*FALLTHROUGH*/ 33459243Sobrien 33559243Sobrien case ';': 33659243Sobrien case '(': 33759243Sobrien case ')': 33859243Sobrien case '\n': 33959243Sobrien *wp++ = c; 34059243Sobrien goto ret; 34159243Sobrien 34259243Sobrien case '\\': 34359243Sobrien c = getC(0); 34459243Sobrien if (c == '\n') { 34559243Sobrien if (onelflg == 1) 34659243Sobrien onelflg = 2; 34759243Sobrien goto loop; 34859243Sobrien } 34959243Sobrien if (c != HIST) 35059243Sobrien *wp++ = '\\', --i; 35159243Sobrien c |= QUOTE; 35259243Sobrien default: 35359243Sobrien break; 35459243Sobrien } 35559243Sobrien c1 = 0; 35659243Sobrien dolflg = DOALL; 35759243Sobrien for (;;) { 35859243Sobrien if (c1) { 35959243Sobrien if (c == c1) { 36059243Sobrien c1 = 0; 36159243Sobrien dolflg = DOALL; 36259243Sobrien } 36359243Sobrien else if (c == '\\') { 36459243Sobrien c = getC(0); 36559243Sobrien/* 36659243Sobrien * PWP: this is dumb, but how all of the other shells work. If \ quotes 36759243Sobrien * a character OUTSIDE of a set of ''s, why shouldn't it quote EVERY 36859243Sobrien * following character INSIDE a set of ''s. 36959243Sobrien * 37059243Sobrien * Actually, all I really want to be able to say is 'foo\'bar' --> foo'bar 37159243Sobrien */ 37259243Sobrien if (c == HIST) 37359243Sobrien c |= QUOTE; 37459243Sobrien else { 37559243Sobrien if (bslash_quote && 37659243Sobrien ((c == '\'') || (c == '"') || 37759243Sobrien (c == '\\'))) { 37859243Sobrien c |= QUOTE; 37959243Sobrien } 38059243Sobrien else { 38159243Sobrien if (c == '\n') 38259243Sobrien /* 38359243Sobrien * if (c1 == '`') c = ' '; else 38459243Sobrien */ 38559243Sobrien c |= QUOTE; 38659243Sobrien ungetC(c); 38759243Sobrien c = '\\'; 38859243Sobrien } 38959243Sobrien } 39059243Sobrien } 39159243Sobrien else if (c == '\n') { 39259243Sobrien seterror(ERR_UNMATCHED, c1); 39359243Sobrien ungetC(c); 39459243Sobrien break; 39559243Sobrien } 39659243Sobrien } 39759243Sobrien else if (cmap(c, _META | _QF | _QB | _ESC)) { 39859243Sobrien if (c == '\\') { 39959243Sobrien c = getC(0); 40059243Sobrien if (c == '\n') { 40159243Sobrien if (onelflg == 1) 40259243Sobrien onelflg = 2; 40359243Sobrien break; 40459243Sobrien } 40559243Sobrien if (c != HIST) 40659243Sobrien *wp++ = '\\', --i; 40759243Sobrien c |= QUOTE; 40859243Sobrien } 40959243Sobrien else if (cmap(c, _QF | _QB)) { /* '"` */ 41059243Sobrien c1 = c; 41159243Sobrien dolflg = c == '"' ? DOALL : DOEXCL; 41259243Sobrien } 41359243Sobrien else if (c != '#' || !intty) { 41459243Sobrien ungetC(c); 41559243Sobrien break; 41659243Sobrien } 41759243Sobrien } 41859243Sobrien if (--i > 0) { 41959243Sobrien *wp++ = c; 42059243Sobrien c = getC(dolflg); 42159243Sobrien } 42259243Sobrien else { 42359243Sobrien seterror(ERR_WTOOLONG); 42459243Sobrien wp = &wbuf[1]; 42559243Sobrien break; 42659243Sobrien } 42759243Sobrien } 42859243Sobrienret: 42959243Sobrien *wp = 0; 43059243Sobrien return (Strsave(wbuf)); 43159243Sobrien} 43259243Sobrien 43359243Sobrienstatic int 43459243SobriengetC1(flag) 43559243Sobrien int flag; 43659243Sobrien{ 43759243Sobrien Char c; 43859243Sobrien 43959243Sobrien for (;;) { 44059243Sobrien if ((c = peekc) != 0) { 44159243Sobrien peekc = 0; 44259243Sobrien return (c); 44359243Sobrien } 44459243Sobrien if (lap) { 44559243Sobrien if ((c = *lap++) == 0) 44659243Sobrien lap = 0; 44759243Sobrien else { 44859243Sobrien if (cmap(c, _META | _QF | _QB)) 44959243Sobrien c |= QUOTE; 45059243Sobrien return (c); 45159243Sobrien } 45259243Sobrien } 45359243Sobrien if ((c = peekd) != 0) { 45459243Sobrien peekd = 0; 45559243Sobrien return (c); 45659243Sobrien } 45759243Sobrien if (exclp) { 45859243Sobrien if ((c = *exclp++) != 0) 45959243Sobrien return (c); 46059243Sobrien if (exclnxt && --exclc >= 0) { 46159243Sobrien exclnxt = exclnxt->next; 46259243Sobrien setexclp(exclnxt->word); 46359243Sobrien return (' '); 46459243Sobrien } 46559243Sobrien exclp = 0; 46659243Sobrien exclnxt = 0; 46759243Sobrien /* this will throw away the dummy history entries */ 46859243Sobrien savehist(NULL, 0); 46959243Sobrien 47059243Sobrien } 47159243Sobrien if (exclnxt) { 47259243Sobrien exclnxt = exclnxt->next; 47359243Sobrien if (--exclc < 0) 47459243Sobrien exclnxt = 0; 47559243Sobrien else 47659243Sobrien setexclp(exclnxt->word); 47759243Sobrien continue; 47859243Sobrien } 47959243Sobrien c = readc(0); 48059243Sobrien if (c == '$' && (flag & DODOL)) { 48159243Sobrien getdol(); 48259243Sobrien continue; 48359243Sobrien } 48459243Sobrien if (c == HIST && (flag & DOEXCL)) { 48559243Sobrien getexcl(0); 48659243Sobrien continue; 48759243Sobrien } 48859243Sobrien break; 48959243Sobrien } 49059243Sobrien return (c); 49159243Sobrien} 49259243Sobrien 49359243Sobrienstatic void 49459243Sobriengetdol() 49559243Sobrien{ 49659243Sobrien Char *np, *ep; 49759243Sobrien Char name[4 * MAXVARLEN + 1]; 49859243Sobrien int c; 49959243Sobrien int sc; 50059243Sobrien bool special = 0, toolong; 50159243Sobrien 50259243Sobrien np = name, *np++ = '$'; 50359243Sobrien c = sc = getC(DOEXCL); 50459243Sobrien if (any("\t \n", c)) { 50559243Sobrien ungetD(c); 50659243Sobrien ungetC('$' | QUOTE); 50759243Sobrien return; 50859243Sobrien } 50959243Sobrien if (c == '{') 51059243Sobrien *np++ = (Char) c, c = getC(DOEXCL); 51159243Sobrien if (c == '#' || c == '?' || c == '%') 51259243Sobrien special++, *np++ = (Char) c, c = getC(DOEXCL); 51359243Sobrien *np++ = (Char) c; 51459243Sobrien switch (c) { 51559243Sobrien 51659243Sobrien case '<': 51759243Sobrien case '$': 51859243Sobrien case '!': 51959243Sobrien if (special) 52059243Sobrien seterror(ERR_SPDOLLT); 52159243Sobrien *np = 0; 52259243Sobrien addla(name); 52359243Sobrien return; 52459243Sobrien 52559243Sobrien case '\n': 52659243Sobrien ungetD(c); 52759243Sobrien np--; 52859243Sobrien if (!special) 52959243Sobrien seterror(ERR_NEWLINE); 53059243Sobrien *np = 0; 53159243Sobrien addla(name); 53259243Sobrien return; 53359243Sobrien 53459243Sobrien case '*': 53559243Sobrien if (special) 53659243Sobrien seterror(ERR_SPSTAR); 53759243Sobrien *np = 0; 53859243Sobrien addla(name); 53959243Sobrien return; 54059243Sobrien 54159243Sobrien default: 54259243Sobrien toolong = 0; 54359243Sobrien if (Isdigit(c)) { 54459243Sobrien#ifdef notdef 54559243Sobrien /* let $?0 pass for now */ 54659243Sobrien if (special) { 54759243Sobrien seterror(ERR_DIGIT); 54859243Sobrien *np = 0; 54959243Sobrien addla(name); 55059243Sobrien return; 55159243Sobrien } 55259243Sobrien#endif 55359243Sobrien /* we know that np < &name[4] */ 55459243Sobrien ep = &np[MAXVARLEN]; 55559243Sobrien while ((c = getC(DOEXCL)) != 0) { 55659243Sobrien if (!Isdigit(c)) 55759243Sobrien break; 55859243Sobrien if (np < ep) 55959243Sobrien *np++ = (Char) c; 56059243Sobrien else 56159243Sobrien toolong = 1; 56259243Sobrien } 56359243Sobrien } 56459243Sobrien else if (letter(c)) { 56559243Sobrien /* we know that np < &name[4] */ 56659243Sobrien ep = &np[MAXVARLEN]; 56759243Sobrien toolong = 0; 56859243Sobrien while ((c = getC(DOEXCL)) != 0) { 56959243Sobrien /* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */ 57059243Sobrien if (!letter(c) && !Isdigit(c)) 57159243Sobrien break; 57259243Sobrien if (np < ep) 57359243Sobrien *np++ = (Char) c; 57459243Sobrien else 57559243Sobrien toolong = 1; 57659243Sobrien } 57759243Sobrien } 57859243Sobrien else { 57959243Sobrien if (!special) 58059243Sobrien seterror(ERR_VARILL); 58159243Sobrien else { 58259243Sobrien ungetD(c); 58359243Sobrien --np; 58459243Sobrien } 58559243Sobrien *np = 0; 58659243Sobrien addla(name); 58759243Sobrien return; 58859243Sobrien } 58959243Sobrien if (toolong) { 59059243Sobrien seterror(ERR_VARTOOLONG); 59159243Sobrien *np = 0; 59259243Sobrien addla(name); 59359243Sobrien return; 59459243Sobrien } 59559243Sobrien break; 59659243Sobrien } 59759243Sobrien if (c == '[') { 59859243Sobrien *np++ = (Char) c; 59959243Sobrien /* 60059243Sobrien * Name up to here is a max of MAXVARLEN + 8. 60159243Sobrien */ 60259243Sobrien ep = &np[2 * MAXVARLEN + 8]; 60359243Sobrien do { 60459243Sobrien /* 60559243Sobrien * Michael Greim: Allow $ expansion to take place in selector 60659243Sobrien * expressions. (limits the number of characters returned) 60759243Sobrien */ 60859243Sobrien c = getC(DOEXCL | DODOL); 60959243Sobrien if (c == '\n') { 61059243Sobrien ungetD(c); 61159243Sobrien np--; 61259243Sobrien seterror(ERR_NLINDEX); 61359243Sobrien *np = 0; 61459243Sobrien addla(name); 61559243Sobrien return; 61659243Sobrien } 61759243Sobrien if (np < ep) 61859243Sobrien *np++ = (Char) c; 61959243Sobrien } while (c != ']'); 62059243Sobrien *np = '\0'; 62159243Sobrien if (np >= ep) { 62259243Sobrien seterror(ERR_SELOVFL); 62359243Sobrien addla(name); 62459243Sobrien return; 62559243Sobrien } 62659243Sobrien c = getC(DOEXCL); 62759243Sobrien } 62859243Sobrien /* 62959243Sobrien * Name up to here is a max of 2 * MAXVARLEN + 8. 63059243Sobrien */ 63159243Sobrien if (c == ':') { 63259243Sobrien /* 63359243Sobrien * if the :g modifier is followed by a newline, then error right away! 63459243Sobrien * -strike 63559243Sobrien */ 63659243Sobrien 63759243Sobrien int gmodflag = 0, amodflag = 0; 63859243Sobrien 63959243Sobrien#ifndef COMPAT 64059243Sobrien do { 64159243Sobrien#endif /* COMPAT */ 64259243Sobrien *np++ = (Char) c, c = getC(DOEXCL); 64359243Sobrien if (c == 'g' || c == 'a') { 64459243Sobrien if (c == 'g') 64559243Sobrien gmodflag++; 64659243Sobrien else 64759243Sobrien amodflag++; 64859243Sobrien *np++ = (Char) c; c = getC(DOEXCL); 64959243Sobrien } 65059243Sobrien if ((c == 'g' && !gmodflag) || (c == 'a' && !amodflag)) { 65159243Sobrien if (c == 'g') 65259243Sobrien gmodflag++; 65359243Sobrien else 65459243Sobrien amodflag++; 65559243Sobrien *np++ = (Char) c; c = getC(DOEXCL); 65659243Sobrien } 65759243Sobrien *np++ = (Char) c; 65859243Sobrien /* scan s// [eichin:19910926.0512EST] */ 65959243Sobrien if (c == 's') { 66059243Sobrien int delimcnt = 2; 66159243Sobrien int delim = getC(0); 66259243Sobrien *np++ = (Char) delim; 66359243Sobrien 66459243Sobrien if (!delim || letter(delim) 66559243Sobrien || Isdigit(delim) || any(" \t\n", delim)) { 66659243Sobrien seterror(ERR_BADSUBST); 66759243Sobrien break; 66859243Sobrien } 66959243Sobrien while ((c = getC(0)) != (-1)) { 67059243Sobrien *np++ = (Char) c; 67159243Sobrien if(c == delim) delimcnt--; 67259243Sobrien if(!delimcnt) break; 67359243Sobrien } 67459243Sobrien if(delimcnt) { 67559243Sobrien seterror(ERR_BADSUBST); 67659243Sobrien break; 67759243Sobrien } 67859243Sobrien c = 's'; 67959243Sobrien } 68059243Sobrien if (!any("htrqxesul", c)) { 68159243Sobrien if ((amodflag || gmodflag) && c == '\n') 68259243Sobrien stderror(ERR_VARSYN); /* strike */ 68359243Sobrien seterror(ERR_BADMOD, c); 68459243Sobrien *np = 0; 68559243Sobrien addla(name); 68659243Sobrien return; 68759243Sobrien } 68859243Sobrien#ifndef COMPAT 68959243Sobrien } 69059243Sobrien while ((c = getC(DOEXCL)) == ':'); 69159243Sobrien ungetD(c); 69259243Sobrien#endif /* COMPAT */ 69359243Sobrien } 69459243Sobrien else 69559243Sobrien ungetD(c); 69659243Sobrien if (sc == '{') { 69759243Sobrien c = getC(DOEXCL); 69859243Sobrien if (c != '}') { 69959243Sobrien ungetD(c); 70059243Sobrien seterror(ERR_MISSING, '}'); 70159243Sobrien *np = 0; 70259243Sobrien addla(name); 70359243Sobrien return; 70459243Sobrien } 70559243Sobrien *np++ = (Char) c; 70659243Sobrien } 70759243Sobrien *np = 0; 70859243Sobrien addla(name); 70959243Sobrien return; 71059243Sobrien} 71159243Sobrien 71259243Sobrienvoid 71359243Sobrienaddla(cp) 71459243Sobrien Char *cp; 71559243Sobrien{ 71659243Sobrien Char buf[BUFSIZE]; 71759243Sobrien 71859243Sobrien if (Strlen(cp) + (lap ? Strlen(lap) : 0) >= 71959243Sobrien (sizeof(labuf) - 4) / sizeof(Char)) { 72059243Sobrien seterror(ERR_EXPOVFL); 72159243Sobrien return; 72259243Sobrien } 72359243Sobrien if (lap) 72459243Sobrien (void) Strcpy(buf, lap); 72559243Sobrien (void) Strcpy(labuf, cp); 72659243Sobrien if (lap) 72759243Sobrien (void) Strcat(labuf, buf); 72859243Sobrien lap = labuf; 72959243Sobrien} 73059243Sobrien 73159243Sobrienstatic Char lhsb[32]; 73259243Sobrienstatic Char slhs[32]; 73359243Sobrienstatic Char rhsb[64]; 73459243Sobrienstatic int quesarg; 73559243Sobrien 73659243Sobrienstatic void 73759243Sobriengetexcl(sc) 73859243Sobrien int sc; 73959243Sobrien{ 74059243Sobrien struct wordent *hp, *ip; 74159243Sobrien int left, right, dol; 74259243Sobrien int c; 74359243Sobrien 74459243Sobrien if (sc == 0) { 74559243Sobrien sc = getC(0); 74659243Sobrien if (sc != '{') { 74759243Sobrien ungetC(sc); 74859243Sobrien sc = 0; 74959243Sobrien } 75059243Sobrien } 75159243Sobrien quesarg = -1; 75259243Sobrien 75359243Sobrien if (uselastevent) { 75459243Sobrien uselastevent = 0; 75559243Sobrien lastev = eventno; 75659243Sobrien } 75759243Sobrien else 75859243Sobrien lastev = eventno; 75959243Sobrien hp = gethent(sc); 76059243Sobrien if (hp == 0) 76159243Sobrien return; 76259243Sobrien hadhist = 1; 76359243Sobrien dol = 0; 76459243Sobrien if (hp == alhistp) 76559243Sobrien for (ip = hp->next->next; ip != alhistt; ip = ip->next) 76659243Sobrien dol++; 76759243Sobrien else 76859243Sobrien for (ip = hp->next->next; ip != hp->prev; ip = ip->next) 76959243Sobrien dol++; 77059243Sobrien left = 0, right = dol; 77159243Sobrien if (sc == HISTSUB) { 77259243Sobrien ungetC('s'), unreadc(HISTSUB), c = ':'; 77359243Sobrien goto subst; 77459243Sobrien } 77559243Sobrien c = getC(0); 77659243Sobrien if (!any(":^$*-%", c)) 77759243Sobrien goto subst; 77859243Sobrien left = right = -1; 77959243Sobrien if (c == ':') { 78059243Sobrien c = getC(0); 78159243Sobrien unreadc(c); 78259243Sobrien if (letter(c) || c == '&') { 78359243Sobrien c = ':'; 78459243Sobrien left = 0, right = dol; 78559243Sobrien goto subst; 78659243Sobrien } 78759243Sobrien } 78859243Sobrien else 78959243Sobrien ungetC(c); 79059243Sobrien if (!getsel(&left, &right, dol)) 79159243Sobrien return; 79259243Sobrien c = getC(0); 79359243Sobrien if (c == '*') 79459243Sobrien ungetC(c), c = '-'; 79559243Sobrien if (c == '-') { 79659243Sobrien if (!getsel(&left, &right, dol)) 79759243Sobrien return; 79859243Sobrien c = getC(0); 79959243Sobrien } 80059243Sobriensubst: 80159243Sobrien exclc = right - left + 1; 80259243Sobrien while (--left >= 0) 80359243Sobrien hp = hp->next; 80459243Sobrien if (sc == HISTSUB || c == ':') { 80559243Sobrien do { 80659243Sobrien hp = getsub(hp); 80759243Sobrien c = getC(0); 80859243Sobrien } while (c == ':'); 80959243Sobrien } 81059243Sobrien unreadc(c); 81159243Sobrien if (sc == '{') { 81259243Sobrien c = getC(0); 81359243Sobrien if (c != '}') 81459243Sobrien seterror(ERR_BADBANG); 81559243Sobrien } 81659243Sobrien exclnxt = hp; 81759243Sobrien} 81859243Sobrien 81959243Sobrienstatic struct wordent * 82059243Sobriengetsub(en) 82159243Sobrien struct wordent *en; 82259243Sobrien{ 82359243Sobrien Char *cp; 82459243Sobrien int delim; 82559243Sobrien int c; 82659243Sobrien int sc; 82759243Sobrien bool global; 82859243Sobrien Char orhsb[sizeof(rhsb) / sizeof(Char)]; 82959243Sobrien 83059243Sobrien#ifndef COMPAT 83159243Sobrien do { 83259243Sobrien#endif /* COMPAT */ 83359243Sobrien exclnxt = 0; 83459243Sobrien global = 0; 83559243Sobrien sc = c = getC(0); 83659243Sobrien if (c == 'g' || c == 'a') { 83759243Sobrien global |= (c == 'g') ? 1 : 2; 83859243Sobrien sc = c = getC(0); 83959243Sobrien } 84059243Sobrien if (((c =='g') && !(global & 1)) || ((c == 'a') && !(global & 2))) { 84159243Sobrien global |= (c == 'g') ? 1 : 2; 84259243Sobrien sc = c = getC(0); 84359243Sobrien } 84459243Sobrien 84559243Sobrien switch (c) { 84659243Sobrien case 'p': 84759243Sobrien justpr++; 84859243Sobrien return (en); 84959243Sobrien 85059243Sobrien case 'x': 85159243Sobrien case 'q': 85259243Sobrien global |= 1; 85359243Sobrien /*FALLTHROUGH*/ 85459243Sobrien 85559243Sobrien case 'h': 85659243Sobrien case 'r': 85759243Sobrien case 't': 85859243Sobrien case 'e': 85959243Sobrien case 'u': 86059243Sobrien case 'l': 86159243Sobrien break; 86259243Sobrien 86359243Sobrien case '&': 86459243Sobrien if (slhs[0] == 0) { 86559243Sobrien seterror(ERR_NOSUBST); 86659243Sobrien return (en); 86759243Sobrien } 86859243Sobrien (void) Strcpy(lhsb, slhs); 86959243Sobrien break; 87059243Sobrien 87159243Sobrien#ifdef notdef 87259243Sobrien case '~': 87359243Sobrien if (lhsb[0] == 0) 87459243Sobrien goto badlhs; 87559243Sobrien break; 87659243Sobrien#endif 87759243Sobrien 87859243Sobrien case 's': 87959243Sobrien delim = getC(0); 88059243Sobrien if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) { 88159243Sobrien unreadc(delim); 88259243Sobrien lhsb[0] = 0; 88359243Sobrien seterror(ERR_BADSUBST); 88459243Sobrien return (en); 88559243Sobrien } 88659243Sobrien cp = lhsb; 88759243Sobrien for (;;) { 88859243Sobrien c = getC(0); 88959243Sobrien if (c == '\n') { 89059243Sobrien unreadc(c); 89159243Sobrien break; 89259243Sobrien } 89359243Sobrien if (c == delim) 89459243Sobrien break; 89559243Sobrien if (cp > &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) { 89659243Sobrien lhsb[0] = 0; 89759243Sobrien seterror(ERR_BADSUBST); 89859243Sobrien return (en); 89959243Sobrien } 90059243Sobrien if (c == '\\') { 90159243Sobrien c = getC(0); 90259243Sobrien if (c != delim && c != '\\') 90359243Sobrien *cp++ = '\\'; 90459243Sobrien } 90559243Sobrien *cp++ = (Char) c; 90659243Sobrien } 90759243Sobrien if (cp != lhsb) 90859243Sobrien *cp++ = 0; 90959243Sobrien else if (lhsb[0] == 0) { 91059243Sobrien seterror(ERR_LHS); 91159243Sobrien return (en); 91259243Sobrien } 91359243Sobrien cp = rhsb; 91459243Sobrien (void) Strcpy(orhsb, cp); 91559243Sobrien for (;;) { 91659243Sobrien c = getC(0); 91759243Sobrien if (c == '\n') { 91859243Sobrien unreadc(c); 91959243Sobrien break; 92059243Sobrien } 92159243Sobrien if (c == delim) 92259243Sobrien break; 92359243Sobrien#ifdef notdef 92459243Sobrien if (c == '~') { 92559243Sobrien if (&cp[Strlen(orhsb)] > &rhsb[sizeof(rhsb) / 92659243Sobrien sizeof(Char) - 2]) 92759243Sobrien goto toorhs; 92859243Sobrien (void) Strcpy(cp, orhsb); 92959243Sobrien cp = Strend(cp); 93059243Sobrien continue; 93159243Sobrien } 93259243Sobrien#endif 93359243Sobrien if (cp > &rhsb[sizeof(rhsb) / sizeof(Char) - 2]) { 93459243Sobrien seterror(ERR_RHSLONG); 93559243Sobrien return (en); 93659243Sobrien } 93759243Sobrien if (c == '\\') { 93859243Sobrien c = getC(0); 93959243Sobrien if (c != delim /* && c != '~' */ ) 94059243Sobrien *cp++ = '\\'; 94159243Sobrien } 94259243Sobrien *cp++ = (Char) c; 94359243Sobrien } 94459243Sobrien *cp++ = 0; 94559243Sobrien break; 94659243Sobrien 94759243Sobrien default: 94859243Sobrien if (c == '\n') 94959243Sobrien unreadc(c); 95059243Sobrien seterror(ERR_BADBANGMOD, c); 95159243Sobrien return (en); 95259243Sobrien } 95359243Sobrien (void) Strcpy(slhs, lhsb); 95459243Sobrien if (exclc) 95559243Sobrien en = dosub(sc, en, global); 95659243Sobrien#ifndef COMPAT 95759243Sobrien } 95859243Sobrien while ((c = getC(0)) == ':'); 95959243Sobrien unreadc(c); 96059243Sobrien#endif /* COMPAT */ 96159243Sobrien return (en); 96259243Sobrien} 96359243Sobrien 96459243Sobrien/* 96559243Sobrien * 96659243Sobrien * From Beto Appleton (beto@aixwiz.austin.ibm.com) 96759243Sobrien * 96859243Sobrien * when using history substitution, and the variable 96959243Sobrien * 'history' is set to a value higher than 1000, 97059243Sobrien * the shell might either freeze (hang) or core-dump. 97159243Sobrien * We raise the limit to 50000000 97259243Sobrien */ 97359243Sobrien 97459243Sobrien#define HIST_PURGE -50000000 97559243Sobrienstatic struct wordent * 97659243Sobriendosub(sc, en, global) 97759243Sobrien int sc; 97859243Sobrien struct wordent *en; 97959243Sobrien bool global; 98059243Sobrien{ 98159243Sobrien struct wordent lexi; 98259243Sobrien bool didsub = 0, didone = 0; 98359243Sobrien struct wordent *hp = &lexi; 98459243Sobrien struct wordent *wdp; 98559243Sobrien int i = exclc; 98659243Sobrien struct Hist *hst; 98759243Sobrien 98859243Sobrien wdp = hp; 98959243Sobrien while (--i >= 0) { 99059243Sobrien struct wordent *new = 99159243Sobrien (struct wordent *) xcalloc(1, sizeof *wdp); 99259243Sobrien 99359243Sobrien new->word = 0; 99459243Sobrien new->prev = wdp; 99559243Sobrien new->next = hp; 99659243Sobrien wdp->next = new; 99759243Sobrien wdp = new; 99859243Sobrien en = en->next; 99959243Sobrien if (en->word) { 100059243Sobrien Char *tword, *otword; 100159243Sobrien 100259243Sobrien if ((global & 1) || didsub == 0) { 100359243Sobrien tword = subword(en->word, sc, &didone); 100459243Sobrien if (didone) 100559243Sobrien didsub = 1; 100659243Sobrien if (global & 2) { 100759243Sobrien while (didone && tword != STRNULL) { 100859243Sobrien otword = tword; 100959243Sobrien tword = subword(otword, sc, &didone); 101059243Sobrien if (Strcmp(tword, otword) == 0) { 101159243Sobrien xfree((ptr_t) otword); 101259243Sobrien break; 101359243Sobrien } 101459243Sobrien else 101559243Sobrien xfree((ptr_t) otword); 101659243Sobrien } 101759243Sobrien } 101859243Sobrien } 101959243Sobrien else 102059243Sobrien tword = Strsave(en->word); 102159243Sobrien wdp->word = tword; 102259243Sobrien } 102359243Sobrien } 102459243Sobrien if (didsub == 0) 102559243Sobrien seterror(ERR_MODFAIL); 102659243Sobrien hp->prev = wdp; 102759243Sobrien /* 102859243Sobrien * ANSI mode HP/UX compiler chokes on 102959243Sobrien * return &enthist(HIST_PURGE, &lexi, 0)->Hlex; 103059243Sobrien */ 103159243Sobrien hst = enthist(HIST_PURGE, &lexi, 0, 0); 103259243Sobrien return &(hst->Hlex); 103359243Sobrien} 103459243Sobrien 103559243Sobrienstatic Char * 103659243Sobriensubword(cp, type, adid) 103759243Sobrien Char *cp; 103859243Sobrien int type; 103959243Sobrien bool *adid; 104059243Sobrien{ 104159243Sobrien Char wbuf[BUFSIZE]; 104259243Sobrien Char *wp, *mp, *np; 104359243Sobrien int i; 104459243Sobrien 104559243Sobrien *adid = 0; 104659243Sobrien switch (type) { 104759243Sobrien 104859243Sobrien case 'r': 104959243Sobrien case 'e': 105059243Sobrien case 'h': 105159243Sobrien case 't': 105259243Sobrien case 'q': 105359243Sobrien case 'x': 105459243Sobrien case 'u': 105559243Sobrien case 'l': 105659243Sobrien wp = domod(cp, type); 105759243Sobrien if (wp == 0) 105859243Sobrien return (Strsave(cp)); 105959243Sobrien *adid = 1; 106059243Sobrien return (wp); 106159243Sobrien 106259243Sobrien default: 106359243Sobrien wp = wbuf; 106459243Sobrien i = BUFSIZE - 4; 106559243Sobrien for (mp = cp; *mp; mp++) 106659243Sobrien if (matchs(mp, lhsb)) { 106759243Sobrien for (np = cp; np < mp;) 106859243Sobrien *wp++ = *np++, --i; 106959243Sobrien for (np = rhsb; *np; np++) 107059243Sobrien switch (*np) { 107159243Sobrien 107259243Sobrien case '\\': 107359243Sobrien if (np[1] == '&') 107459243Sobrien np++; 107559243Sobrien /* fall into ... */ 107659243Sobrien 107759243Sobrien default: 107859243Sobrien if (--i < 0) { 107959243Sobrien seterror(ERR_SUBOVFL); 108059243Sobrien return (STRNULL); 108159243Sobrien } 108259243Sobrien *wp++ = *np; 108359243Sobrien continue; 108459243Sobrien 108559243Sobrien case '&': 108659243Sobrien i -= Strlen(lhsb); 108759243Sobrien if (i < 0) { 108859243Sobrien seterror(ERR_SUBOVFL); 108959243Sobrien return (STRNULL); 109059243Sobrien } 109159243Sobrien *wp = 0; 109259243Sobrien (void) Strcat(wp, lhsb); 109359243Sobrien wp = Strend(wp); 109459243Sobrien continue; 109559243Sobrien } 109659243Sobrien mp += Strlen(lhsb); 109759243Sobrien i -= Strlen(mp); 109859243Sobrien if (i < 0) { 109959243Sobrien seterror(ERR_SUBOVFL); 110059243Sobrien return (STRNULL); 110159243Sobrien } 110259243Sobrien *wp = 0; 110359243Sobrien (void) Strcat(wp, mp); 110459243Sobrien *adid = 1; 110559243Sobrien return (Strsave(wbuf)); 110659243Sobrien } 110759243Sobrien return (Strsave(cp)); 110859243Sobrien } 110959243Sobrien} 111059243Sobrien 111159243SobrienChar * 111259243Sobriendomod(cp, type) 111359243Sobrien Char *cp; 111459243Sobrien int type; 111559243Sobrien{ 111659243Sobrien Char *wp, *xp; 111759243Sobrien int c; 111859243Sobrien 111959243Sobrien switch (type) { 112059243Sobrien 112159243Sobrien case 'x': 112259243Sobrien case 'q': 112359243Sobrien wp = Strsave(cp); 112459243Sobrien for (xp = wp; (c = *xp) != 0; xp++) 112559243Sobrien if ((c != ' ' && c != '\t') || type == 'q') 112659243Sobrien *xp |= QUOTE; 112759243Sobrien return (wp); 112859243Sobrien 112959243Sobrien case 'l': 113059243Sobrien wp = Strsave(cp); 113159243Sobrien for (cp = wp; *cp; cp++) 113259243Sobrien if (Isupper(*cp)) { 113359243Sobrien *cp = Tolower(*cp); 113459243Sobrien return wp; 113559243Sobrien } 113659243Sobrien return wp; 113759243Sobrien 113859243Sobrien case 'u': 113959243Sobrien wp = Strsave(cp); 114059243Sobrien for (cp = wp; *cp; cp++) 114159243Sobrien if (Islower(*cp)) { 114259243Sobrien *cp = Toupper(*cp); 114359243Sobrien return wp; 114459243Sobrien } 114559243Sobrien return wp; 114659243Sobrien 114759243Sobrien case 'h': 114859243Sobrien case 't': 114959243Sobrien if (!any(short2str(cp), '/')) 115059243Sobrien return (type == 't' ? Strsave(cp) : 0); 115159243Sobrien wp = Strend(cp); 115259243Sobrien while (*--wp != '/') 115359243Sobrien continue; 115459243Sobrien if (type == 'h') 115559243Sobrien xp = Strsave(cp), xp[wp - cp] = 0; 115659243Sobrien else 115759243Sobrien xp = Strsave(wp + 1); 115859243Sobrien return (xp); 115959243Sobrien 116059243Sobrien case 'e': 116159243Sobrien case 'r': 116259243Sobrien wp = Strend(cp); 116359243Sobrien for (wp--; wp >= cp && *wp != '/'; wp--) 116459243Sobrien if (*wp == '.') { 116559243Sobrien if (type == 'e') 116659243Sobrien xp = Strsave(wp + 1); 116759243Sobrien else 116859243Sobrien xp = Strsave(cp), xp[wp - cp] = 0; 116959243Sobrien return (xp); 117059243Sobrien } 117159243Sobrien return (Strsave(type == 'e' ? STRNULL : cp)); 117259243Sobrien default: 117359243Sobrien break; 117459243Sobrien } 117559243Sobrien return (0); 117659243Sobrien} 117759243Sobrien 117859243Sobrienstatic int 117959243Sobrienmatchs(str, pat) 118059243Sobrien Char *str, *pat; 118159243Sobrien{ 118259243Sobrien while (*str && *pat && *str == *pat) 118359243Sobrien str++, pat++; 118459243Sobrien return (*pat == 0); 118559243Sobrien} 118659243Sobrien 118759243Sobrienstatic int 118859243Sobriengetsel(al, ar, dol) 118959243Sobrien int *al, *ar; 119059243Sobrien int dol; 119159243Sobrien{ 119259243Sobrien int c = getC(0); 119359243Sobrien int i; 119459243Sobrien bool first = *al < 0; 119559243Sobrien 119659243Sobrien switch (c) { 119759243Sobrien 119859243Sobrien case '%': 119959243Sobrien if (quesarg == -1) { 120059243Sobrien seterror(ERR_BADBANGARG); 120159243Sobrien return (0); 120259243Sobrien } 120359243Sobrien if (*al < 0) 120459243Sobrien *al = quesarg; 120559243Sobrien *ar = quesarg; 120659243Sobrien break; 120759243Sobrien 120859243Sobrien case '-': 120959243Sobrien if (*al < 0) { 121059243Sobrien *al = 0; 121159243Sobrien *ar = dol - 1; 121259243Sobrien unreadc(c); 121359243Sobrien } 121459243Sobrien return (1); 121559243Sobrien 121659243Sobrien case '^': 121759243Sobrien if (*al < 0) 121859243Sobrien *al = 1; 121959243Sobrien *ar = 1; 122059243Sobrien break; 122159243Sobrien 122259243Sobrien case '$': 122359243Sobrien if (*al < 0) 122459243Sobrien *al = dol; 122559243Sobrien *ar = dol; 122659243Sobrien break; 122759243Sobrien 122859243Sobrien case '*': 122959243Sobrien if (*al < 0) 123059243Sobrien *al = 1; 123159243Sobrien *ar = dol; 123259243Sobrien if (*ar < *al) { 123359243Sobrien *ar = 0; 123459243Sobrien *al = 1; 123559243Sobrien return (1); 123659243Sobrien } 123759243Sobrien break; 123859243Sobrien 123959243Sobrien default: 124059243Sobrien if (Isdigit(c)) { 124159243Sobrien i = 0; 124259243Sobrien while (Isdigit(c)) { 124359243Sobrien i = i * 10 + c - '0'; 124459243Sobrien c = getC(0); 124559243Sobrien } 124659243Sobrien if (i < 0) 124759243Sobrien i = dol + 1; 124859243Sobrien if (*al < 0) 124959243Sobrien *al = i; 125059243Sobrien *ar = i; 125159243Sobrien } 125259243Sobrien else if (*al < 0) 125359243Sobrien *al = 0, *ar = dol; 125459243Sobrien else 125559243Sobrien *ar = dol - 1; 125659243Sobrien unreadc(c); 125759243Sobrien break; 125859243Sobrien } 125959243Sobrien if (first) { 126059243Sobrien c = getC(0); 126159243Sobrien unreadc(c); 126259243Sobrien if (any("-$*", c)) 126359243Sobrien return (1); 126459243Sobrien } 126559243Sobrien if (*al > *ar || *ar > dol) { 126659243Sobrien seterror(ERR_BADBANGARG); 126759243Sobrien return (0); 126859243Sobrien } 126959243Sobrien return (1); 127059243Sobrien 127159243Sobrien} 127259243Sobrien 127359243Sobrienstatic struct wordent * 127459243Sobriengethent(sc) 127559243Sobrien int sc; 127659243Sobrien{ 127759243Sobrien struct Hist *hp; 127859243Sobrien Char *np; 127959243Sobrien int c; 128059243Sobrien int event; 128159243Sobrien bool back = 0; 128259243Sobrien 128359243Sobrien c = sc == HISTSUB ? HIST : getC(0); 128459243Sobrien if (c == HIST) { 128559243Sobrien if (alhistp) 128659243Sobrien return (alhistp); 128759243Sobrien event = eventno; 128859243Sobrien } 128959243Sobrien else 129059243Sobrien switch (c) { 129159243Sobrien 129259243Sobrien case ':': 129359243Sobrien case '^': 129459243Sobrien case '$': 129559243Sobrien case '*': 129659243Sobrien case '%': 129759243Sobrien ungetC(c); 129859243Sobrien if (lastev == eventno && alhistp) 129959243Sobrien return (alhistp); 130059243Sobrien event = lastev; 130159243Sobrien break; 130259243Sobrien 130359243Sobrien case '#': /* !# is command being typed in (mrh) */ 130459243Sobrien if (--hleft == 0) { 130559243Sobrien seterror(ERR_HISTLOOP); 130659243Sobrien return (0); 130759243Sobrien } 130859243Sobrien else 130959243Sobrien return (¶ml); 131059243Sobrien /* NOTREACHED */ 131159243Sobrien 131259243Sobrien case '-': 131359243Sobrien back = 1; 131459243Sobrien c = getC(0); 131559243Sobrien /* FALLSTHROUGH */ 131659243Sobrien 131759243Sobrien default: 131859243Sobrien if (any("(=~", c)) { 131959243Sobrien unreadc(c); 132059243Sobrien ungetC(HIST); 132159243Sobrien return (0); 132259243Sobrien } 132359243Sobrien np = lhsb; 132459243Sobrien event = 0; 132559243Sobrien while (!cmap(c, _ESC | _META | _QF | _QB) && !any("^*-%${}:#", c)) { 132659243Sobrien if (event != -1 && Isdigit(c)) 132759243Sobrien event = event * 10 + c - '0'; 132859243Sobrien else 132959243Sobrien event = -1; 133059243Sobrien if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) 133159243Sobrien *np++ = (Char) c; 133259243Sobrien c = getC(0); 133359243Sobrien } 133459243Sobrien unreadc(c); 133559243Sobrien if (np == lhsb) { 133659243Sobrien ungetC(HIST); 133759243Sobrien return (0); 133859243Sobrien } 133959243Sobrien *np++ = 0; 134059243Sobrien if (event != -1) { 134159243Sobrien /* 134259243Sobrien * History had only digits 134359243Sobrien */ 134459243Sobrien if (back) 134559243Sobrien event = eventno + (alhistp == 0) - (event ? event : 0); 134659243Sobrien break; 134759243Sobrien } 134859243Sobrien if (back) { 134959243Sobrien event = sizeof(lhsb) / sizeof(lhsb[0]); 135059243Sobrien np = &lhsb[--event]; 135159243Sobrien *np-- = '\0'; 135259243Sobrien for (event--; np > lhsb; *np-- = lhsb[--event]) 135359243Sobrien continue; 135459243Sobrien *np = '-'; 135559243Sobrien } 135659243Sobrien hp = findev(lhsb, 0); 135759243Sobrien if (hp) 135859243Sobrien lastev = hp->Hnum; 135959243Sobrien return (&hp->Hlex); 136059243Sobrien 136159243Sobrien case '?': 136259243Sobrien np = lhsb; 136359243Sobrien for (;;) { 136459243Sobrien c = getC(0); 136559243Sobrien if (c == '\n') { 136659243Sobrien unreadc(c); 136759243Sobrien break; 136859243Sobrien } 136959243Sobrien if (c == '?') 137059243Sobrien break; 137159243Sobrien if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) 137259243Sobrien *np++ = (Char) c; 137359243Sobrien } 137459243Sobrien if (np == lhsb) { 137559243Sobrien if (lhsb[0] == 0) { 137659243Sobrien seterror(ERR_NOSEARCH); 137759243Sobrien return (0); 137859243Sobrien } 137959243Sobrien } 138059243Sobrien else 138159243Sobrien *np++ = 0; 138259243Sobrien hp = findev(lhsb, 1); 138359243Sobrien if (hp) 138459243Sobrien lastev = hp->Hnum; 138559243Sobrien return (&hp->Hlex); 138659243Sobrien } 138759243Sobrien 138859243Sobrien for (hp = Histlist.Hnext; hp; hp = hp->Hnext) 138959243Sobrien if (hp->Hnum == event) { 139059243Sobrien hp->Href = eventno; 139159243Sobrien lastev = hp->Hnum; 139259243Sobrien return (&hp->Hlex); 139359243Sobrien } 139459243Sobrien np = putn(event); 139559243Sobrien seterror(ERR_NOEVENT, short2str(np)); 139659243Sobrien return (0); 139759243Sobrien} 139859243Sobrien 139959243Sobrienstatic struct Hist * 140059243Sobrienfindev(cp, anyarg) 140159243Sobrien Char *cp; 140259243Sobrien bool anyarg; 140359243Sobrien{ 140459243Sobrien struct Hist *hp; 140559243Sobrien 140659243Sobrien for (hp = Histlist.Hnext; hp; hp = hp->Hnext) { 140759243Sobrien Char *dp; 140859243Sobrien Char *p, *q; 140959243Sobrien struct wordent *lp = hp->Hlex.next; 141059243Sobrien int argno = 0; 141159243Sobrien 141259243Sobrien /* 141359243Sobrien * The entries added by alias substitution don't have a newline but do 141459243Sobrien * have a negative event number. Savehist() trims off these entries, 141559243Sobrien * but it happens before alias expansion, too early to delete those 141659243Sobrien * from the previous command. 141759243Sobrien */ 141859243Sobrien if (hp->Hnum < 0) 141959243Sobrien continue; 142059243Sobrien if (lp->word[0] == '\n') 142159243Sobrien continue; 142259243Sobrien if (!anyarg) { 142359243Sobrien p = cp; 142459243Sobrien q = lp->word; 142559243Sobrien do 142659243Sobrien if (!*p) 142759243Sobrien return (hp); 142859243Sobrien while (*p++ == *q++); 142959243Sobrien continue; 143059243Sobrien } 143159243Sobrien do { 143259243Sobrien for (dp = lp->word; *dp; dp++) { 143359243Sobrien p = cp; 143459243Sobrien q = dp; 143559243Sobrien do 143659243Sobrien if (!*p) { 143759243Sobrien quesarg = argno; 143859243Sobrien return (hp); 143959243Sobrien } 144059243Sobrien while (*p++ == *q++); 144159243Sobrien } 144259243Sobrien lp = lp->next; 144359243Sobrien argno++; 144459243Sobrien } while (lp->word[0] != '\n'); 144559243Sobrien } 144659243Sobrien seterror(ERR_NOEVENT, short2str(cp)); 144759243Sobrien return (0); 144859243Sobrien} 144959243Sobrien 145059243Sobrien 145159243Sobrienstatic void 145259243Sobriensetexclp(cp) 145359243Sobrien Char *cp; 145459243Sobrien{ 145559243Sobrien if (cp && cp[0] == '\n') 145659243Sobrien return; 145759243Sobrien exclp = cp; 145859243Sobrien} 145959243Sobrien 146059243Sobrienvoid 146159243Sobrienunreadc(c) 146259243Sobrien int c; 146359243Sobrien{ 146459243Sobrien peekread = (Char) c; 146559243Sobrien} 146659243Sobrien 146759243Sobrienint 146859243Sobrienreadc(wanteof) 146959243Sobrien bool wanteof; 147059243Sobrien{ 147159243Sobrien int c; 147259243Sobrien static int sincereal; /* Number of real EOFs we've seen */ 147359243Sobrien Char *ptr; /* For STRignoreeof */ 147459243Sobrien int numeof = 0; /* Value of STRignoreeof */ 147559243Sobrien 147659243Sobrien#ifdef DEBUG_INP 147759243Sobrien xprintf("readc\n"); 147859243Sobrien#endif 147959243Sobrien if ((c = peekread) != 0) { 148059243Sobrien peekread = 0; 148159243Sobrien return (c); 148259243Sobrien } 148359243Sobrien 148459243Sobrien /* Compute the value of EOFs */ 148559243Sobrien if ((ptr = varval(STRignoreeof)) != STRNULL) { 148659243Sobrien while (*ptr) { 148759243Sobrien if (!Isdigit(*ptr)) { 148859243Sobrien numeof = 0; 148959243Sobrien break; 149059243Sobrien } 149159243Sobrien numeof = numeof * 10 + *ptr++ - '0'; 149259243Sobrien } 149359243Sobrien } 149459243Sobrien if (numeof < 1) numeof = 26; /* Sanity check */ 149559243Sobrien 149659243Sobrientop: 149759243Sobrien aret = F_SEEK; 149859243Sobrien if (alvecp) { 149959243Sobrien arun = 1; 150059243Sobrien#ifdef DEBUG_INP 150159243Sobrien xprintf("alvecp %c\n", *alvecp & 0xff); 150259243Sobrien#endif 150359243Sobrien aret = A_SEEK; 150459243Sobrien if ((c = *alvecp++) != 0) 150559243Sobrien return (c); 150659243Sobrien if (alvec && *alvec) { 150759243Sobrien alvecp = *alvec++; 150859243Sobrien return (' '); 150959243Sobrien } 151059243Sobrien else { 151159243Sobrien alvecp = NULL; 151259243Sobrien aret = F_SEEK; 151359243Sobrien return('\n'); 151459243Sobrien } 151559243Sobrien } 151659243Sobrien if (alvec) { 151759243Sobrien arun = 1; 151859243Sobrien if ((alvecp = *alvec) != 0) { 151959243Sobrien alvec++; 152059243Sobrien goto top; 152159243Sobrien } 152259243Sobrien /* Infinite source! */ 152359243Sobrien return ('\n'); 152459243Sobrien } 152559243Sobrien arun = 0; 152659243Sobrien if (evalp) { 152759243Sobrien aret = E_SEEK; 152859243Sobrien if ((c = *evalp++) != 0) 152959243Sobrien return (c); 153059243Sobrien if (evalvec && *evalvec) { 153159243Sobrien evalp = *evalvec++; 153259243Sobrien return (' '); 153359243Sobrien } 153459243Sobrien aret = F_SEEK; 153559243Sobrien evalp = 0; 153659243Sobrien } 153759243Sobrien if (evalvec) { 153859243Sobrien if (evalvec == INVPPTR) { 153959243Sobrien doneinp = 1; 154059243Sobrien reset(); 154159243Sobrien } 154259243Sobrien if ((evalp = *evalvec) != 0) { 154359243Sobrien evalvec++; 154459243Sobrien goto top; 154559243Sobrien } 154659243Sobrien evalvec = INVPPTR; 154759243Sobrien return ('\n'); 154859243Sobrien } 154959243Sobrien do { 155059243Sobrien if (arginp == INVPTR || onelflg == 1) { 155159243Sobrien if (wanteof) 155259243Sobrien return (-1); 155359243Sobrien exitstat(); 155459243Sobrien } 155559243Sobrien if (arginp) { 155659243Sobrien if ((c = *arginp++) == 0) { 155759243Sobrien arginp = INVPTR; 155859243Sobrien return ('\n'); 155959243Sobrien } 156059243Sobrien return (c); 156159243Sobrien } 156259243Sobrien#ifdef BSDJOBS 156359243Sobrienreread: 156459243Sobrien#endif /* BSDJOBS */ 156559243Sobrien c = bgetc(); 156659243Sobrien if (c < 0) { 156759243Sobrien#ifndef WINNT 156859243Sobrien# ifndef POSIX 156959243Sobrien# ifdef TERMIO 157059243Sobrien struct termio tty; 157159243Sobrien# else /* SGTTYB */ 157259243Sobrien struct sgttyb tty; 157359243Sobrien# endif /* TERMIO */ 157459243Sobrien# else /* POSIX */ 157559243Sobrien struct termios tty; 157659243Sobrien# endif /* POSIX */ 157759243Sobrien#endif /* !WINNT */ 157859243Sobrien if (wanteof) 157959243Sobrien return (-1); 158059243Sobrien /* was isatty but raw with ignoreeof yields problems */ 158159243Sobrien#ifndef WINNT 158259243Sobrien# ifndef POSIX 158359243Sobrien# ifdef TERMIO 158459243Sobrien if (ioctl(SHIN, TCGETA, (ioctl_t) & tty) == 0 && 158559243Sobrien (tty.c_lflag & ICANON)) 158659243Sobrien# else /* GSTTYB */ 158759243Sobrien if (ioctl(SHIN, TIOCGETP, (ioctl_t) & tty) == 0 && 158859243Sobrien (tty.sg_flags & RAW) == 0) 158959243Sobrien# endif /* TERMIO */ 159059243Sobrien# else /* POSIX */ 159159243Sobrien if (tcgetattr(SHIN, &tty) == 0 && 159259243Sobrien (tty.c_lflag & ICANON)) 159359243Sobrien# endif /* POSIX */ 159459243Sobrien#else /* WINNT */ 159559243Sobrien if (isatty(SHIN)) 159659243Sobrien#endif /* !WINNT */ 159759243Sobrien { 159859243Sobrien /* was 'short' for FILEC */ 159959243Sobrien#ifdef BSDJOBS 160059243Sobrien int ctpgrp; 160159243Sobrien#endif /* BSDJOBS */ 160259243Sobrien 160359243Sobrien if (++sincereal >= numeof) /* Too many EOFs? Bye! */ 160459243Sobrien goto oops; 160559243Sobrien#ifdef BSDJOBS 160659243Sobrien if (tpgrp != -1 && 160759243Sobrien (ctpgrp = tcgetpgrp(FSHTTY)) != -1 && 160859243Sobrien tpgrp != ctpgrp) { 160959243Sobrien (void) tcsetpgrp(FSHTTY, tpgrp); 161059243Sobrien# ifdef _SEQUENT_ 161159243Sobrien if (ctpgrp) 161259243Sobrien# endif /* _SEQUENT */ 161359243Sobrien (void) killpg((pid_t) ctpgrp, SIGHUP); 161459243Sobrien# ifdef notdef 161559243Sobrien /* 161659243Sobrien * With the walking process group fix, this message 161759243Sobrien * is now obsolete. As the foreground process group 161859243Sobrien * changes, the shell needs to adjust. Well too bad. 161959243Sobrien */ 162059243Sobrien xprintf(CGETS(16, 1, "Reset tty pgrp from %d to %d\n"), 162159243Sobrien ctpgrp, tpgrp); 162259243Sobrien# endif /* notdef */ 162359243Sobrien goto reread; 162459243Sobrien } 162559243Sobrien#endif /* BSDJOBS */ 162659243Sobrien /* What follows is complicated EOF handling -- sterling@netcom.com */ 162759243Sobrien /* First, we check to see if we have ignoreeof set */ 162859243Sobrien if (adrof(STRignoreeof)) { 162959243Sobrien /* If so, we check for any stopped jobs only on the first EOF */ 163059243Sobrien if ((sincereal == 1) && (chkstop == 0)) { 163159243Sobrien panystop(1); 163259243Sobrien } 163359243Sobrien } else { 163459243Sobrien /* If we don't have ignoreeof set, always check for stopped jobs */ 163559243Sobrien if (chkstop == 0) { 163659243Sobrien panystop(1); 163759243Sobrien } 163859243Sobrien } 163959243Sobrien /* At this point, if there were stopped jobs, we would have already 164059243Sobrien * called reset(). If we got this far, assume we can print an 164159243Sobrien * exit/logout message if we ignoreeof, or just exit. 164259243Sobrien */ 164359243Sobrien if (adrof(STRignoreeof)) { 164459243Sobrien /* If so, tell the user to use exit or logout */ 164559243Sobrien if (loginsh) { 164659243Sobrien xprintf(CGETS(16, 2, 164759243Sobrien "\nUse \"logout\" to logout.\n")); 164859243Sobrien } else { 164959243Sobrien xprintf(CGETS(16, 3, 165059243Sobrien "\nUse \"exit\" to leave %s.\n"), 165159243Sobrien progname); 165259243Sobrien } 165359243Sobrien reset(); 165459243Sobrien } else { 165559243Sobrien /* If we don't have ignoreeof set, just fall through */ 165659243Sobrien ; /* EMPTY */ 165759243Sobrien } 165859243Sobrien } 165959243Sobrien oops: 166059243Sobrien doneinp = 1; 166159243Sobrien reset(); 166259243Sobrien } 166359243Sobrien sincereal = 0; 166459243Sobrien if (c == '\n' && onelflg) 166559243Sobrien onelflg--; 166659243Sobrien } while (c == 0); 166759243Sobrien if (histlinep < histline + BUFSIZE) 166859243Sobrien *histlinep++ = (Char) c; 166959243Sobrien return (c); 167059243Sobrien} 167159243Sobrien 167259243Sobrienstatic void 167359243Sobrienballoc(buf) 167459243Sobrien int buf; 167559243Sobrien{ 167659243Sobrien Char **nfbuf; 167759243Sobrien 167859243Sobrien while (buf >= fblocks) { 167959243Sobrien nfbuf = (Char **) xcalloc((size_t) (fblocks + 2), 168059243Sobrien sizeof(Char **)); 168159243Sobrien if (fbuf) { 168259243Sobrien (void) blkcpy(nfbuf, fbuf); 168359243Sobrien xfree((ptr_t) fbuf); 168459243Sobrien } 168559243Sobrien fbuf = nfbuf; 168659243Sobrien fbuf[fblocks] = (Char *) xcalloc(BUFSIZE, sizeof(Char)); 168759243Sobrien fblocks++; 168859243Sobrien } 168959243Sobrien} 169059243Sobrien 169159243Sobrienstatic int 169259243Sobrienbgetc() 169359243Sobrien{ 169459243Sobrien int c, off, buf; 169559243Sobrien int numleft = 0, roomleft; 169659243Sobrien char tbuf[BUFSIZE + 1]; 169759243Sobrien 169859243Sobrien if (cantell) { 169959243Sobrien if (fseekp < fbobp || fseekp > feobp) { 170059243Sobrien fbobp = feobp = fseekp; 170159243Sobrien (void) lseek(SHIN, fseekp, L_SET); 170259243Sobrien } 170359243Sobrien if (fseekp == feobp) { 170459243Sobrien int i; 170559243Sobrien 170659243Sobrien fbobp = feobp; 170759243Sobrien do 170859243Sobrien c = read(SHIN, tbuf, BUFSIZE); 170959243Sobrien while (c < 0 && errno == EINTR); 171059243Sobrien#ifdef convex 171159243Sobrien if (c < 0) 171259243Sobrien stderror(ERR_SYSTEM, progname, strerror(errno)); 171359243Sobrien#endif /* convex */ 171459243Sobrien if (c <= 0) 171559243Sobrien return (-1); 171659243Sobrien for (i = 0; i < c; i++) 171759243Sobrien fbuf[0][i] = (unsigned char) tbuf[i]; 171859243Sobrien feobp += c; 171959243Sobrien } 172059243Sobrien#ifndef WINNT 172159243Sobrien c = fbuf[0][fseekp - fbobp]; 172259243Sobrien fseekp++; 172359243Sobrien#else 172459243Sobrien do { 172559243Sobrien c = fbuf[0][fseekp - fbobp]; 172659243Sobrien fseekp++; 172759243Sobrien } while(c == '\r'); 172859243Sobrien#endif /* !WINNT */ 172959243Sobrien return (c); 173059243Sobrien } 173159243Sobrien 173259243Sobrien while (fseekp >= feobp) { 173359243Sobrien if (editing && intty) { /* then use twenex routine */ 173459243Sobrien fseekp = feobp; /* where else? */ 173559243Sobrien c = numleft = Inputl(); /* PWP: get a line */ 173659243Sobrien while (numleft > 0) { 173759243Sobrien off = (int) feobp % BUFSIZE; 173859243Sobrien buf = (int) feobp / BUFSIZE; 173959243Sobrien balloc(buf); 174059243Sobrien roomleft = BUFSIZE - off; 174159243Sobrien if (roomleft > numleft) 174259243Sobrien roomleft = numleft; 174359243Sobrien (void) memmove((ptr_t) (fbuf[buf] + off), (ptr_t) (InputBuf + c - numleft), (size_t) (roomleft * sizeof(Char))); 174459243Sobrien numleft -= roomleft; 174559243Sobrien feobp += roomleft; 174659243Sobrien } 174759243Sobrien } 174859243Sobrien else { 174959243Sobrien off = (int) feobp % BUFSIZE; 175059243Sobrien buf = (int) feobp / BUFSIZE; 175159243Sobrien balloc(buf); 175259243Sobrien roomleft = BUFSIZE - off; 175359243Sobrien c = read(SHIN, tbuf, (size_t) roomleft); 175459243Sobrien if (c > 0) { 175559243Sobrien int i; 175659243Sobrien Char *ptr = fbuf[buf] + off; 175759243Sobrien 175859243Sobrien for (i = 0; i < c; i++) 175959243Sobrien ptr[i] = (unsigned char) tbuf[i]; 176059243Sobrien feobp += c; 176159243Sobrien } 176259243Sobrien } 176359243Sobrien if (c == 0 || (c < 0 && fixio(SHIN, errno) == -1)) 176459243Sobrien return (-1); 176559243Sobrien } 176659243Sobrien#ifndef WINNT 176759243Sobrien c = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE]; 176859243Sobrien fseekp++; 176959243Sobrien#else 177059243Sobrien do { 177159243Sobrien c = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE]; 177259243Sobrien fseekp++; 177359243Sobrien } while(c == '\r'); 177459243Sobrien#endif /* !WINNT */ 177559243Sobrien return (c); 177659243Sobrien} 177759243Sobrien 177859243Sobrienstatic void 177959243Sobrienbfree() 178059243Sobrien{ 178159243Sobrien int sb, i; 178259243Sobrien 178359243Sobrien if (cantell) 178459243Sobrien return; 178559243Sobrien if (whyles) 178659243Sobrien return; 178759243Sobrien sb = (int) (fseekp - 1) / BUFSIZE; 178859243Sobrien if (sb > 0) { 178959243Sobrien for (i = 0; i < sb; i++) 179059243Sobrien xfree((ptr_t) fbuf[i]); 179159243Sobrien (void) blkcpy(fbuf, &fbuf[sb]); 179259243Sobrien fseekp -= BUFSIZE * sb; 179359243Sobrien feobp -= BUFSIZE * sb; 179459243Sobrien fblocks -= sb; 179559243Sobrien } 179659243Sobrien} 179759243Sobrien 179859243Sobrienvoid 179959243Sobrienbseek(l) 180059243Sobrien struct Ain *l; 180159243Sobrien{ 180259243Sobrien switch (aret = l->type) { 180359243Sobrien case E_SEEK: 180459243Sobrien evalvec = l->a_seek; 180559243Sobrien evalp = l->c_seek; 180659243Sobrien#ifdef DEBUG_SEEK 180759243Sobrien xprintf(CGETS(16, 4, "seek to eval %x %x\n"), evalvec, evalp); 180859243Sobrien#endif 180959243Sobrien return; 181059243Sobrien case A_SEEK: 181159243Sobrien alvec = l->a_seek; 181259243Sobrien alvecp = l->c_seek; 181359243Sobrien#ifdef DEBUG_SEEK 181459243Sobrien xprintf(CGETS(16, 5, "seek to alias %x %x\n"), alvec, alvecp); 181559243Sobrien#endif 181659243Sobrien return; 181759243Sobrien case F_SEEK: 181859243Sobrien#ifdef DEBUG_SEEK 181959243Sobrien xprintf(CGETS(16, 6, "seek to file %x\n"), fseekp); 182059243Sobrien#endif 182159243Sobrien fseekp = l->f_seek; 182259243Sobrien return; 182359243Sobrien default: 182459243Sobrien xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret); 182559243Sobrien abort(); 182659243Sobrien } 182759243Sobrien} 182859243Sobrien 182959243Sobrien/* any similarity to bell telephone is purely accidental */ 183059243Sobrienvoid 183159243Sobrienbtell(l) 183259243Sobrienstruct Ain *l; 183359243Sobrien{ 183459243Sobrien switch (l->type = aret) { 183559243Sobrien case E_SEEK: 183659243Sobrien l->a_seek = evalvec; 183759243Sobrien l->c_seek = evalp; 183859243Sobrien#ifdef DEBUG_SEEK 183959243Sobrien xprintf(CGETS(16, 8, "tell eval %x %x\n"), evalvec, evalp); 184059243Sobrien#endif 184159243Sobrien return; 184259243Sobrien case A_SEEK: 184359243Sobrien l->a_seek = alvec; 184459243Sobrien l->c_seek = alvecp; 184559243Sobrien#ifdef DEBUG_SEEK 184659243Sobrien xprintf(CGETS(16, 9, "tell alias %x %x\n"), alvec, alvecp); 184759243Sobrien#endif 184859243Sobrien return; 184959243Sobrien case F_SEEK: 185059243Sobrien /*SUPPRESS 112*/ 185159243Sobrien l->f_seek = fseekp; 185259243Sobrien l->a_seek = NULL; 185359243Sobrien#ifdef DEBUG_SEEK 185459243Sobrien xprintf(CGETS(16, 10, "tell file %x\n"), fseekp); 185559243Sobrien#endif 185659243Sobrien return; 185759243Sobrien default: 185859243Sobrien xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret); 185959243Sobrien abort(); 186059243Sobrien } 186159243Sobrien} 186259243Sobrien 186359243Sobrienvoid 186459243Sobrienbtoeof() 186559243Sobrien{ 186659243Sobrien (void) lseek(SHIN, (off_t) 0, L_XTND); 186759243Sobrien aret = F_SEEK; 186859243Sobrien fseekp = feobp; 186959243Sobrien alvec = NULL; 187059243Sobrien alvecp = NULL; 187159243Sobrien evalvec = NULL; 187259243Sobrien evalp = NULL; 187359243Sobrien wfree(); 187459243Sobrien bfree(); 187559243Sobrien} 187659243Sobrien 187759243Sobrienvoid 187859243Sobriensettell() 187959243Sobrien{ 188059243Sobrien off_t x; 188159243Sobrien cantell = 0; 188259243Sobrien if (arginp || onelflg || intty) 188359243Sobrien return; 188459243Sobrien if ((x = lseek(SHIN, (off_t) 0, L_INCR)) == -1) 188559243Sobrien return; 188659243Sobrien fbuf = (Char **) xcalloc(2, sizeof(Char **)); 188759243Sobrien fblocks = 1; 188859243Sobrien fbuf[0] = (Char *) xcalloc(BUFSIZE, sizeof(Char)); 188959243Sobrien fseekp = fbobp = feobp = x; 189059243Sobrien cantell = 1; 189159243Sobrien} 1892