sh.lex.c revision 145479
1145479Smp/* $Header: /src/pub/tcsh/sh.lex.c,v 3.62 2004/12/25 21:15:07 christos Exp $ */ 259243Sobrien/* 359243Sobrien * sh.lex.c: Lexical analysis into tokens 459243Sobrien */ 559243Sobrien/*- 659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 759243Sobrien * All rights reserved. 859243Sobrien * 959243Sobrien * Redistribution and use in source and binary forms, with or without 1059243Sobrien * modification, are permitted provided that the following conditions 1159243Sobrien * are met: 1259243Sobrien * 1. Redistributions of source code must retain the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer. 1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1559243Sobrien * notice, this list of conditions and the following disclaimer in the 1659243Sobrien * documentation and/or other materials provided with the distribution. 17100616Smp * 3. Neither the name of the University nor the names of its contributors 1859243Sobrien * may be used to endorse or promote products derived from this software 1959243Sobrien * without specific prior written permission. 2059243Sobrien * 2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2459243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3159243Sobrien * SUCH DAMAGE. 3259243Sobrien */ 3359243Sobrien#include "sh.h" 3459243Sobrien 35145479SmpRCSID("$Id: sh.lex.c,v 3.62 2004/12/25 21:15:07 christos Exp $") 3659243Sobrien 3759243Sobrien#include "ed.h" 38145479Smp 39145479Smp#include <assert.h> 4059243Sobrien/* #define DEBUG_INP */ 4159243Sobrien/* #define DEBUG_SEEK */ 4259243Sobrien 4359243Sobrien/* 4459243Sobrien * C shell 4559243Sobrien */ 4659243Sobrien 4759243Sobrien/* 4859243Sobrien * These lexical routines read input and form lists of words. 4959243Sobrien * There is some involved processing here, because of the complications 5059243Sobrien * of input buffering, and especially because of history substitution. 5159243Sobrien */ 52145479Smpstatic Char *word __P((int)); 53145479Smpstatic eChar getC1 __P((int)); 5459243Sobrienstatic void getdol __P((void)); 55145479Smpstatic void getexcl __P((Char)); 56145479Smpstatic struct Hist *findev __P((Char *, int)); 5759243Sobrienstatic void setexclp __P((Char *)); 58145479Smpstatic eChar bgetc __P((void)); 5959243Sobrienstatic void balloc __P((int)); 6059243Sobrienstatic void bfree __P((void)); 61145479Smpstatic struct wordent *gethent __P((Char)); 6259243Sobrienstatic int matchs __P((Char *, Char *)); 6359243Sobrienstatic int getsel __P((int *, int *, int)); 6459243Sobrienstatic struct wordent *getsub __P((struct wordent *)); 65145479Smpstatic Char *subword __P((Char *, Char, int *)); 66145479Smpstatic struct wordent *dosub __P((Char, struct wordent *, int)); 67145479Smpstatic ssize_t wide_read __P((int, Char *, size_t, int)); 6859243Sobrien 6959243Sobrien/* 7059243Sobrien * Peekc is a peek character for getC, peekread for readc. 7159243Sobrien * There is a subtlety here in many places... history routines 7259243Sobrien * will read ahead and then insert stuff into the input stream. 7359243Sobrien * If they push back a character then they must push it behind 7459243Sobrien * the text substituted by the history substitution. On the other 7559243Sobrien * hand in several places we need 2 peek characters. To make this 7659243Sobrien * all work, the history routines read with getC, and make use both 7759243Sobrien * of ungetC and unreadc. The key observation is that the state 7859243Sobrien * of getC at the call of a history reference is such that calls 7959243Sobrien * to getC from the history routines will always yield calls of 8059243Sobrien * readc, unless this peeking is involved. That is to say that during 8159243Sobrien * getexcl the variables lap, exclp, and exclnxt are all zero. 8259243Sobrien * 8359243Sobrien * Getdol invokes history substitution, hence the extra peek, peekd, 8459243Sobrien * which it can ungetD to be before history substitutions. 8559243Sobrien */ 8659243Sobrienstatic Char peekc = 0, peekd = 0; 8759243Sobrienstatic Char peekread = 0; 8859243Sobrien 8959243Sobrien/* (Tail of) current word from ! subst */ 9059243Sobrienstatic Char *exclp = NULL; 9159243Sobrien 9259243Sobrien/* The rest of the ! subst words */ 9359243Sobrienstatic struct wordent *exclnxt = NULL; 9459243Sobrien 9559243Sobrien/* Count of remaining words in ! subst */ 9659243Sobrienstatic int exclc = 0; 9759243Sobrien 9859243Sobrien/* "Globp" for alias resubstitution */ 9969408Sacheint aret = TCSH_F_SEEK; 10059243Sobrien 10159243Sobrien/* 10259243Sobrien * Labuf implements a general buffer for lookahead during lexical operations. 10359243Sobrien * Text which is to be placed in the input stream can be stuck here. 10459243Sobrien * We stick parsed ahead $ constructs during initial input, 10559243Sobrien * process id's from `$$', and modified variable values (from qualifiers 10659243Sobrien * during expansion in sh.dol.c) here. 10759243Sobrien */ 10859243Sobrienstatic Char labuf[BUFSIZE]; 10959243Sobrien 11059243Sobrien/* 11159243Sobrien * Lex returns to its caller not only a wordlist (as a "var" parameter) 11259243Sobrien * but also whether a history substitution occurred. This is used in 11359243Sobrien * the main (process) routine to determine whether to echo, and also 11459243Sobrien * when called by the alias routine to determine whether to keep the 11559243Sobrien * argument list. 11659243Sobrien */ 117145479Smpstatic int hadhist = 0; 11859243Sobrien 11959243Sobrien/* 12059243Sobrien * Avoid alias expansion recursion via \!# 12159243Sobrien */ 12259243Sobrienint hleft; 12359243Sobrien 12459243SobrienChar histline[BUFSIZE + 2]; /* last line input */ 12559243Sobrien 12659243Sobrien /* The +2 is to fool hp's optimizer */ 127145479Smpint histvalid = 0; /* is histline valid */ 12859243Sobrienstatic Char *histlinep = NULL; /* current pointer into histline */ 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; 14059243Sobrienstatic time_t a2time_t __P((Char *)); 14159243Sobrien 14259243Sobrien/* 143145479Smp * special parsing rules apply for source -h 144145479Smp */ 145145479Smpextern int enterhist; 146145479Smp 147145479Smp/* 14859243Sobrien * for history event processing 14959243Sobrien * in the command 'echo !?foo?:1 !$' we want the !$ to expand from the line 15059243Sobrien * 'foo' was found instead of the last command 15159243Sobrien */ 15259243Sobrienstatic int uselastevent = 1; 15359243Sobrien 15459243Sobrienint 15559243Sobrienlex(hp) 15659243Sobrien struct wordent *hp; 15759243Sobrien{ 15859243Sobrien struct wordent *wdp; 159145479Smp eChar c; 160145479Smp int parsehtime = enterhist; 16159243Sobrien 16259243Sobrien 16359243Sobrien uselastevent = 1; 16459243Sobrien histvalid = 0; 16559243Sobrien histlinep = histline; 16659243Sobrien *histlinep = '\0'; 16759243Sobrien 16859243Sobrien btell(&lineloc); 16959243Sobrien hp->next = hp->prev = hp; 17059243Sobrien hp->word = STRNULL; 17159243Sobrien hadhist = 0; 17259243Sobrien do 17359243Sobrien c = readc(0); 17459243Sobrien while (c == ' ' || c == '\t'); 175145479Smp if (c == (eChar)HISTSUB && intty) 17659243Sobrien /* ^lef^rit from tty is short !:s^lef^rit */ 17759243Sobrien getexcl(c); 17859243Sobrien else 17959243Sobrien unreadc(c); 18059243Sobrien wdp = hp; 18159243Sobrien /* 18259243Sobrien * The following loop is written so that the links needed by freelex will 18359243Sobrien * be ready and rarin to go even if it is interrupted. 18459243Sobrien */ 18559243Sobrien do { 18659243Sobrien struct wordent *new; 18759243Sobrien 18859243Sobrien new = (struct wordent *) xmalloc((size_t) sizeof(*wdp)); 18959243Sobrien new->word = STRNULL; 19059243Sobrien new->prev = wdp; 19159243Sobrien new->next = hp; 19259243Sobrien wdp->next = new; 19359243Sobrien hp->prev = new; 19459243Sobrien wdp = new; 195145479Smp wdp->word = word(parsehtime); 196145479Smp parsehtime = 0; 19759243Sobrien } while (wdp->word[0] != '\n'); 19859243Sobrien if (histlinep < histline + BUFSIZE) { 19959243Sobrien *histlinep = '\0'; 20059243Sobrien if (histlinep > histline && histlinep[-1] == '\n') 20159243Sobrien histlinep[-1] = '\0'; 20259243Sobrien histvalid = 1; 20359243Sobrien } 20459243Sobrien else { 20559243Sobrien histline[BUFSIZE - 1] = '\0'; 20659243Sobrien } 20759243Sobrien 20859243Sobrien return (hadhist); 20959243Sobrien} 21059243Sobrien 21159243Sobrienstatic time_t 212145479Smpa2time_t(wordx) 213145479Smp Char *wordx; 21459243Sobrien{ 21559243Sobrien /* Attempt to distinguish timestamps from other possible entries. 21659243Sobrien * Format: "+NNNNNNNNNN" (10 digits, left padded with ascii '0') */ 21759243Sobrien 21859243Sobrien time_t ret; 21959243Sobrien Char *s; 22059243Sobrien int ct; 22159243Sobrien 222145479Smp if (!wordx || *(s = wordx) != '+') 22359243Sobrien return (time_t)0; 22459243Sobrien 22559243Sobrien for (++s, ret = 0, ct = 0; *s; ++s, ++ct) 22659243Sobrien { 22759243Sobrien if (!isdigit((unsigned char)*s)) 22859243Sobrien return (time_t)0; 22959243Sobrien ret = ret * 10 + (time_t)((unsigned char)*s - '0'); 23059243Sobrien } 23159243Sobrien 23259243Sobrien if (ct != 10) 23359243Sobrien return (time_t)0; 23459243Sobrien 23559243Sobrien return ret; 23659243Sobrien} 23759243Sobrien 23859243Sobrienvoid 23959243Sobrienprlex(sp0) 24059243Sobrien struct wordent *sp0; 24159243Sobrien{ 24259243Sobrien struct wordent *sp = sp0->next; 24359243Sobrien 24459243Sobrien for (;;) { 24559243Sobrien xprintf("%S", sp->word); 24659243Sobrien sp = sp->next; 24759243Sobrien if (sp == sp0) 24859243Sobrien break; 24959243Sobrien if (sp->word[0] != '\n') 25059243Sobrien xputchar(' '); 25159243Sobrien } 25259243Sobrien} 25359243Sobrien 25459243Sobrienvoid 25559243Sobriencopylex(hp, fp) 25659243Sobrien struct wordent *hp; 25759243Sobrien struct wordent *fp; 25859243Sobrien{ 25959243Sobrien struct wordent *wdp; 26059243Sobrien 26159243Sobrien wdp = hp; 26259243Sobrien fp = fp->next; 26359243Sobrien do { 26459243Sobrien struct wordent *new; 26559243Sobrien 26659243Sobrien new = (struct wordent *) xmalloc((size_t) sizeof(*wdp)); 26759243Sobrien new->word = STRNULL; 26859243Sobrien new->prev = wdp; 26959243Sobrien new->next = hp; 27059243Sobrien wdp->next = new; 27159243Sobrien hp->prev = new; 27259243Sobrien wdp = new; 27359243Sobrien wdp->word = Strsave(fp->word); 27459243Sobrien fp = fp->next; 27559243Sobrien } while (wdp->word[0] != '\n'); 27659243Sobrien} 27759243Sobrien 27859243Sobrienvoid 27959243Sobrienfreelex(vp) 28059243Sobrien struct wordent *vp; 28159243Sobrien{ 28259243Sobrien struct wordent *fp; 28359243Sobrien 28459243Sobrien while (vp->next != vp) { 28559243Sobrien fp = vp->next; 28659243Sobrien vp->next = fp->next; 28759243Sobrien if (fp->word != STRNULL) 28859243Sobrien xfree((ptr_t) fp->word); 28959243Sobrien xfree((ptr_t) fp); 29059243Sobrien } 29159243Sobrien vp->prev = vp; 29259243Sobrien} 29359243Sobrien 29459243Sobrienstatic Char * 295145479Smpword(parsehtime) 296145479Smp int parsehtime; 29759243Sobrien{ 298145479Smp eChar c, c1; 299145479Smp Char *wp, *unfinished = 0; 30059243Sobrien Char wbuf[BUFSIZE]; 30159243Sobrien Char hbuf[12]; 30259243Sobrien int h; 303145479Smp int dolflg; 30459243Sobrien int i; 30559243Sobrien 30659243Sobrien wp = wbuf; 30759243Sobrien i = BUFSIZE - 4; 30859243Sobrienloop: 30959243Sobrien while ((c = getC(DOALL)) == ' ' || c == '\t') 31059243Sobrien continue; 31159243Sobrien if (cmap(c, _META | _ESC)) 31259243Sobrien switch (c) { 31359243Sobrien case '&': 31459243Sobrien case '|': 31559243Sobrien case '<': 31659243Sobrien case '>': 31759243Sobrien *wp++ = c; 31859243Sobrien c1 = getC(DOALL); 31959243Sobrien if (c1 == c) 32059243Sobrien *wp++ = c1; 32159243Sobrien else 32259243Sobrien ungetC(c1); 32359243Sobrien goto ret; 32459243Sobrien 32559243Sobrien case '#': 326145479Smp if (intty || (enterhist && !parsehtime)) 32759243Sobrien break; 32859243Sobrien c = 0; 32959243Sobrien h = 0; 33059243Sobrien do { 33159243Sobrien c1 = c; 33259243Sobrien c = getC(0); 333145479Smp if (h < 11 && parsehtime) 33459243Sobrien hbuf[h++] = c; 33559243Sobrien } while (c != '\n'); 336145479Smp if (parsehtime) { 337145479Smp hbuf[11] = '\0'; 338145479Smp Htime = a2time_t(hbuf); 339145479Smp } 34059243Sobrien if (c1 == '\\') 34159243Sobrien goto loop; 34259243Sobrien /*FALLTHROUGH*/ 34359243Sobrien 34459243Sobrien case ';': 34559243Sobrien case '(': 34659243Sobrien case ')': 34759243Sobrien case '\n': 34859243Sobrien *wp++ = c; 34959243Sobrien goto ret; 35059243Sobrien 35159243Sobrien case '\\': 35259243Sobrien c = getC(0); 35359243Sobrien if (c == '\n') { 35459243Sobrien if (onelflg == 1) 35559243Sobrien onelflg = 2; 35659243Sobrien goto loop; 35759243Sobrien } 358145479Smp if (c != (eChar)HIST) 35959243Sobrien *wp++ = '\\', --i; 36059243Sobrien c |= QUOTE; 36159243Sobrien default: 36259243Sobrien break; 36359243Sobrien } 36459243Sobrien c1 = 0; 36559243Sobrien dolflg = DOALL; 36659243Sobrien for (;;) { 36759243Sobrien if (c1) { 36859243Sobrien if (c == c1) { 36959243Sobrien c1 = 0; 37059243Sobrien dolflg = DOALL; 37159243Sobrien } 37259243Sobrien else if (c == '\\') { 37359243Sobrien c = getC(0); 37459243Sobrien/* 37559243Sobrien * PWP: this is dumb, but how all of the other shells work. If \ quotes 37659243Sobrien * a character OUTSIDE of a set of ''s, why shouldn't it quote EVERY 37759243Sobrien * following character INSIDE a set of ''s. 37859243Sobrien * 37959243Sobrien * Actually, all I really want to be able to say is 'foo\'bar' --> foo'bar 38059243Sobrien */ 381145479Smp if (c == (eChar)HIST) 38259243Sobrien c |= QUOTE; 38359243Sobrien else { 38459243Sobrien if (bslash_quote && 38559243Sobrien ((c == '\'') || (c == '"') || 38659243Sobrien (c == '\\'))) { 38759243Sobrien c |= QUOTE; 38859243Sobrien } 38959243Sobrien else { 39059243Sobrien if (c == '\n') 39159243Sobrien /* 39259243Sobrien * if (c1 == '`') c = ' '; else 39359243Sobrien */ 39459243Sobrien c |= QUOTE; 39559243Sobrien ungetC(c); 39659243Sobrien c = '\\'; 39759243Sobrien } 39859243Sobrien } 39959243Sobrien } 40059243Sobrien else if (c == '\n') { 40159243Sobrien seterror(ERR_UNMATCHED, c1); 40259243Sobrien ungetC(c); 40359243Sobrien break; 40459243Sobrien } 40559243Sobrien } 40659243Sobrien else if (cmap(c, _META | _QF | _QB | _ESC)) { 40759243Sobrien if (c == '\\') { 40859243Sobrien c = getC(0); 40959243Sobrien if (c == '\n') { 41059243Sobrien if (onelflg == 1) 41159243Sobrien onelflg = 2; 41259243Sobrien break; 41359243Sobrien } 414145479Smp if (c != (eChar)HIST) 41559243Sobrien *wp++ = '\\', --i; 41659243Sobrien c |= QUOTE; 41759243Sobrien } 41859243Sobrien else if (cmap(c, _QF | _QB)) { /* '"` */ 41959243Sobrien c1 = c; 42059243Sobrien dolflg = c == '"' ? DOALL : DOEXCL; 42159243Sobrien } 422145479Smp else if (c != '#' || (!intty && !enterhist)) { 42359243Sobrien ungetC(c); 42459243Sobrien break; 42559243Sobrien } 42659243Sobrien } 42759243Sobrien if (--i > 0) { 42859243Sobrien *wp++ = c; 42959243Sobrien c = getC(dolflg); 430145479Smp if (!unfinished) 431145479Smp unfinished = wp - 1; 432145479Smp switch (NLSFinished(unfinished, wp - unfinished, c)) { 433145479Smp case 1: 434145479Smp case 0: 435145479Smp c |= QUOTE; 436145479Smp break; 437145479Smp default: 438145479Smp unfinished = 0; 439145479Smp break; 440145479Smp } 44159243Sobrien } 44259243Sobrien else { 44359243Sobrien seterror(ERR_WTOOLONG); 44459243Sobrien wp = &wbuf[1]; 44559243Sobrien break; 44659243Sobrien } 44759243Sobrien } 44859243Sobrienret: 44959243Sobrien *wp = 0; 45059243Sobrien return (Strsave(wbuf)); 45159243Sobrien} 45259243Sobrien 453145479Smpstatic eChar 45459243SobriengetC1(flag) 45559243Sobrien int flag; 45659243Sobrien{ 457145479Smp eChar c; 45859243Sobrien 45959243Sobrien for (;;) { 46059243Sobrien if ((c = peekc) != 0) { 46159243Sobrien peekc = 0; 46259243Sobrien return (c); 46359243Sobrien } 46459243Sobrien if (lap) { 46559243Sobrien if ((c = *lap++) == 0) 46659243Sobrien lap = 0; 46759243Sobrien else { 46859243Sobrien if (cmap(c, _META | _QF | _QB)) 46959243Sobrien c |= QUOTE; 47059243Sobrien return (c); 47159243Sobrien } 47259243Sobrien } 47359243Sobrien if ((c = peekd) != 0) { 47459243Sobrien peekd = 0; 47559243Sobrien return (c); 47659243Sobrien } 47759243Sobrien if (exclp) { 47859243Sobrien if ((c = *exclp++) != 0) 47959243Sobrien return (c); 48059243Sobrien if (exclnxt && --exclc >= 0) { 48159243Sobrien exclnxt = exclnxt->next; 48259243Sobrien setexclp(exclnxt->word); 48359243Sobrien return (' '); 48459243Sobrien } 48559243Sobrien exclp = 0; 48659243Sobrien exclnxt = 0; 48759243Sobrien /* this will throw away the dummy history entries */ 48859243Sobrien savehist(NULL, 0); 48959243Sobrien 49059243Sobrien } 49159243Sobrien if (exclnxt) { 49259243Sobrien exclnxt = exclnxt->next; 49359243Sobrien if (--exclc < 0) 49459243Sobrien exclnxt = 0; 49559243Sobrien else 49659243Sobrien setexclp(exclnxt->word); 49759243Sobrien continue; 49859243Sobrien } 49959243Sobrien c = readc(0); 50059243Sobrien if (c == '$' && (flag & DODOL)) { 50159243Sobrien getdol(); 50259243Sobrien continue; 50359243Sobrien } 504145479Smp if (c == (eChar)HIST && (flag & DOEXCL)) { 50559243Sobrien getexcl(0); 50659243Sobrien continue; 50759243Sobrien } 50859243Sobrien break; 50959243Sobrien } 51059243Sobrien return (c); 51159243Sobrien} 51259243Sobrien 51359243Sobrienstatic void 51459243Sobriengetdol() 51559243Sobrien{ 51659243Sobrien Char *np, *ep; 51759243Sobrien Char name[4 * MAXVARLEN + 1]; 518145479Smp eChar c; 519145479Smp eChar sc; 520145479Smp int special = 0, toolong; 52159243Sobrien 52259243Sobrien np = name, *np++ = '$'; 52359243Sobrien c = sc = getC(DOEXCL); 52459243Sobrien if (any("\t \n", c)) { 52559243Sobrien ungetD(c); 52659243Sobrien ungetC('$' | QUOTE); 52759243Sobrien return; 52859243Sobrien } 52959243Sobrien if (c == '{') 53059243Sobrien *np++ = (Char) c, c = getC(DOEXCL); 53159243Sobrien if (c == '#' || c == '?' || c == '%') 53259243Sobrien special++, *np++ = (Char) c, c = getC(DOEXCL); 53359243Sobrien *np++ = (Char) c; 53459243Sobrien switch (c) { 53559243Sobrien 53659243Sobrien case '<': 53759243Sobrien case '$': 53859243Sobrien case '!': 53959243Sobrien if (special) 54059243Sobrien seterror(ERR_SPDOLLT); 54159243Sobrien *np = 0; 54259243Sobrien addla(name); 54359243Sobrien return; 54459243Sobrien 54559243Sobrien case '\n': 54659243Sobrien ungetD(c); 54759243Sobrien np--; 54859243Sobrien if (!special) 54959243Sobrien seterror(ERR_NEWLINE); 55059243Sobrien *np = 0; 55159243Sobrien addla(name); 55259243Sobrien return; 55359243Sobrien 55459243Sobrien case '*': 55559243Sobrien if (special) 55659243Sobrien seterror(ERR_SPSTAR); 55759243Sobrien *np = 0; 55859243Sobrien addla(name); 55959243Sobrien return; 56059243Sobrien 56159243Sobrien default: 56259243Sobrien toolong = 0; 56359243Sobrien if (Isdigit(c)) { 56459243Sobrien#ifdef notdef 56559243Sobrien /* let $?0 pass for now */ 56659243Sobrien if (special) { 56759243Sobrien seterror(ERR_DIGIT); 56859243Sobrien *np = 0; 56959243Sobrien addla(name); 57059243Sobrien return; 57159243Sobrien } 57259243Sobrien#endif 57359243Sobrien /* we know that np < &name[4] */ 57459243Sobrien ep = &np[MAXVARLEN]; 57559243Sobrien while ((c = getC(DOEXCL)) != 0) { 57659243Sobrien if (!Isdigit(c)) 57759243Sobrien break; 57859243Sobrien if (np < ep) 57959243Sobrien *np++ = (Char) c; 58059243Sobrien else 58159243Sobrien toolong = 1; 58259243Sobrien } 58359243Sobrien } 58459243Sobrien else if (letter(c)) { 58559243Sobrien /* we know that np < &name[4] */ 58659243Sobrien ep = &np[MAXVARLEN]; 58759243Sobrien toolong = 0; 58859243Sobrien while ((c = getC(DOEXCL)) != 0) { 58959243Sobrien /* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */ 59059243Sobrien if (!letter(c) && !Isdigit(c)) 59159243Sobrien break; 59259243Sobrien if (np < ep) 59359243Sobrien *np++ = (Char) c; 59459243Sobrien else 59559243Sobrien toolong = 1; 59659243Sobrien } 59759243Sobrien } 59859243Sobrien else { 59959243Sobrien if (!special) 60059243Sobrien seterror(ERR_VARILL); 60159243Sobrien else { 60259243Sobrien ungetD(c); 60359243Sobrien --np; 60459243Sobrien } 60559243Sobrien *np = 0; 60659243Sobrien addla(name); 60759243Sobrien return; 60859243Sobrien } 60959243Sobrien if (toolong) { 61059243Sobrien seterror(ERR_VARTOOLONG); 61159243Sobrien *np = 0; 61259243Sobrien addla(name); 61359243Sobrien return; 61459243Sobrien } 61559243Sobrien break; 61659243Sobrien } 61759243Sobrien if (c == '[') { 61859243Sobrien *np++ = (Char) c; 61959243Sobrien /* 62059243Sobrien * Name up to here is a max of MAXVARLEN + 8. 62159243Sobrien */ 62259243Sobrien ep = &np[2 * MAXVARLEN + 8]; 62359243Sobrien do { 62459243Sobrien /* 62559243Sobrien * Michael Greim: Allow $ expansion to take place in selector 62659243Sobrien * expressions. (limits the number of characters returned) 62759243Sobrien */ 62859243Sobrien c = getC(DOEXCL | DODOL); 62959243Sobrien if (c == '\n') { 63059243Sobrien ungetD(c); 63159243Sobrien np--; 63259243Sobrien seterror(ERR_NLINDEX); 63359243Sobrien *np = 0; 63459243Sobrien addla(name); 63559243Sobrien return; 63659243Sobrien } 63759243Sobrien if (np < ep) 63859243Sobrien *np++ = (Char) c; 63959243Sobrien } while (c != ']'); 64059243Sobrien *np = '\0'; 64159243Sobrien if (np >= ep) { 64259243Sobrien seterror(ERR_SELOVFL); 64359243Sobrien addla(name); 64459243Sobrien return; 64559243Sobrien } 64659243Sobrien c = getC(DOEXCL); 64759243Sobrien } 64859243Sobrien /* 64959243Sobrien * Name up to here is a max of 2 * MAXVARLEN + 8. 65059243Sobrien */ 65159243Sobrien if (c == ':') { 65259243Sobrien /* 65359243Sobrien * if the :g modifier is followed by a newline, then error right away! 65459243Sobrien * -strike 65559243Sobrien */ 65659243Sobrien 65759243Sobrien int gmodflag = 0, amodflag = 0; 65859243Sobrien 65959243Sobrien#ifndef COMPAT 66059243Sobrien do { 66159243Sobrien#endif /* COMPAT */ 66259243Sobrien *np++ = (Char) c, c = getC(DOEXCL); 66359243Sobrien if (c == 'g' || c == 'a') { 66459243Sobrien if (c == 'g') 66559243Sobrien gmodflag++; 66659243Sobrien else 66759243Sobrien amodflag++; 66859243Sobrien *np++ = (Char) c; c = getC(DOEXCL); 66959243Sobrien } 67059243Sobrien if ((c == 'g' && !gmodflag) || (c == 'a' && !amodflag)) { 67159243Sobrien if (c == 'g') 67259243Sobrien gmodflag++; 67359243Sobrien else 67459243Sobrien amodflag++; 67559243Sobrien *np++ = (Char) c; c = getC(DOEXCL); 67659243Sobrien } 67759243Sobrien *np++ = (Char) c; 67859243Sobrien /* scan s// [eichin:19910926.0512EST] */ 67959243Sobrien if (c == 's') { 68059243Sobrien int delimcnt = 2; 681145479Smp eChar delim = getC(0); 68259243Sobrien *np++ = (Char) delim; 68359243Sobrien 68459243Sobrien if (!delim || letter(delim) 68559243Sobrien || Isdigit(delim) || any(" \t\n", delim)) { 68659243Sobrien seterror(ERR_BADSUBST); 68759243Sobrien break; 68859243Sobrien } 689145479Smp while ((c = getC(0)) != CHAR_ERR) { 69059243Sobrien *np++ = (Char) c; 69159243Sobrien if(c == delim) delimcnt--; 69259243Sobrien if(!delimcnt) break; 69359243Sobrien } 69459243Sobrien if(delimcnt) { 69559243Sobrien seterror(ERR_BADSUBST); 69659243Sobrien break; 69759243Sobrien } 69859243Sobrien c = 's'; 69959243Sobrien } 70059243Sobrien if (!any("htrqxesul", c)) { 70159243Sobrien if ((amodflag || gmodflag) && c == '\n') 70259243Sobrien stderror(ERR_VARSYN); /* strike */ 70359243Sobrien seterror(ERR_BADMOD, c); 70459243Sobrien *np = 0; 70559243Sobrien addla(name); 70659243Sobrien return; 70759243Sobrien } 70859243Sobrien#ifndef COMPAT 70959243Sobrien } 71059243Sobrien while ((c = getC(DOEXCL)) == ':'); 71159243Sobrien ungetD(c); 71259243Sobrien#endif /* COMPAT */ 71359243Sobrien } 71459243Sobrien else 71559243Sobrien ungetD(c); 71659243Sobrien if (sc == '{') { 71759243Sobrien c = getC(DOEXCL); 71859243Sobrien if (c != '}') { 71959243Sobrien ungetD(c); 72059243Sobrien seterror(ERR_MISSING, '}'); 72159243Sobrien *np = 0; 72259243Sobrien addla(name); 72359243Sobrien return; 72459243Sobrien } 72559243Sobrien *np++ = (Char) c; 72659243Sobrien } 72759243Sobrien *np = 0; 72859243Sobrien addla(name); 72959243Sobrien return; 73059243Sobrien} 73159243Sobrien 73259243Sobrienvoid 73359243Sobrienaddla(cp) 73459243Sobrien Char *cp; 73559243Sobrien{ 73659243Sobrien Char buf[BUFSIZE]; 73759243Sobrien 73859243Sobrien if (Strlen(cp) + (lap ? Strlen(lap) : 0) >= 73959243Sobrien (sizeof(labuf) - 4) / sizeof(Char)) { 74059243Sobrien seterror(ERR_EXPOVFL); 74159243Sobrien return; 74259243Sobrien } 74359243Sobrien if (lap) 74459243Sobrien (void) Strcpy(buf, lap); 74559243Sobrien (void) Strcpy(labuf, cp); 746145479Smp NLSQuote(labuf); 74759243Sobrien if (lap) 74859243Sobrien (void) Strcat(labuf, buf); 74959243Sobrien lap = labuf; 75059243Sobrien} 75159243Sobrien 75259243Sobrienstatic Char lhsb[32]; 75359243Sobrienstatic Char slhs[32]; 75459243Sobrienstatic Char rhsb[64]; 75559243Sobrienstatic int quesarg; 75659243Sobrien 75759243Sobrienstatic void 75859243Sobriengetexcl(sc) 759145479Smp Char sc; 76059243Sobrien{ 76159243Sobrien struct wordent *hp, *ip; 76259243Sobrien int left, right, dol; 763145479Smp eChar c; 76459243Sobrien 76559243Sobrien if (sc == 0) { 76659243Sobrien sc = getC(0); 76759243Sobrien if (sc != '{') { 76859243Sobrien ungetC(sc); 76959243Sobrien sc = 0; 77059243Sobrien } 77159243Sobrien } 77259243Sobrien quesarg = -1; 77359243Sobrien 77459243Sobrien if (uselastevent) { 77559243Sobrien uselastevent = 0; 77659243Sobrien lastev = eventno; 77759243Sobrien } 77859243Sobrien else 77959243Sobrien lastev = eventno; 78059243Sobrien hp = gethent(sc); 78159243Sobrien if (hp == 0) 78259243Sobrien return; 78359243Sobrien hadhist = 1; 78459243Sobrien dol = 0; 78559243Sobrien if (hp == alhistp) 78659243Sobrien for (ip = hp->next->next; ip != alhistt; ip = ip->next) 78759243Sobrien dol++; 78859243Sobrien else 78959243Sobrien for (ip = hp->next->next; ip != hp->prev; ip = ip->next) 79059243Sobrien dol++; 79159243Sobrien left = 0, right = dol; 79259243Sobrien if (sc == HISTSUB) { 79359243Sobrien ungetC('s'), unreadc(HISTSUB), c = ':'; 79459243Sobrien goto subst; 79559243Sobrien } 79659243Sobrien c = getC(0); 79759243Sobrien if (!any(":^$*-%", c)) 79859243Sobrien goto subst; 79959243Sobrien left = right = -1; 80059243Sobrien if (c == ':') { 80159243Sobrien c = getC(0); 80259243Sobrien unreadc(c); 80359243Sobrien if (letter(c) || c == '&') { 80459243Sobrien c = ':'; 80559243Sobrien left = 0, right = dol; 80659243Sobrien goto subst; 80759243Sobrien } 80859243Sobrien } 80959243Sobrien else 81059243Sobrien ungetC(c); 81159243Sobrien if (!getsel(&left, &right, dol)) 81259243Sobrien return; 81359243Sobrien c = getC(0); 81459243Sobrien if (c == '*') 81559243Sobrien ungetC(c), c = '-'; 81659243Sobrien if (c == '-') { 81759243Sobrien if (!getsel(&left, &right, dol)) 81859243Sobrien return; 81959243Sobrien c = getC(0); 82059243Sobrien } 82159243Sobriensubst: 82259243Sobrien exclc = right - left + 1; 82359243Sobrien while (--left >= 0) 82459243Sobrien hp = hp->next; 82559243Sobrien if (sc == HISTSUB || c == ':') { 82659243Sobrien do { 82759243Sobrien hp = getsub(hp); 82859243Sobrien c = getC(0); 82959243Sobrien } while (c == ':'); 83059243Sobrien } 83159243Sobrien unreadc(c); 83259243Sobrien if (sc == '{') { 83359243Sobrien c = getC(0); 83459243Sobrien if (c != '}') 83559243Sobrien seterror(ERR_BADBANG); 83659243Sobrien } 83759243Sobrien exclnxt = hp; 83859243Sobrien} 83959243Sobrien 84059243Sobrienstatic struct wordent * 84159243Sobriengetsub(en) 84259243Sobrien struct wordent *en; 84359243Sobrien{ 84459243Sobrien Char *cp; 845145479Smp eChar delim; 846145479Smp eChar c; 847145479Smp eChar sc; 848145479Smp int global; 84959243Sobrien Char orhsb[sizeof(rhsb) / sizeof(Char)]; 85059243Sobrien 85159243Sobrien#ifndef COMPAT 85259243Sobrien do { 85359243Sobrien#endif /* COMPAT */ 85459243Sobrien exclnxt = 0; 85559243Sobrien global = 0; 85659243Sobrien sc = c = getC(0); 85759243Sobrien if (c == 'g' || c == 'a') { 85859243Sobrien global |= (c == 'g') ? 1 : 2; 85959243Sobrien sc = c = getC(0); 86059243Sobrien } 86159243Sobrien if (((c =='g') && !(global & 1)) || ((c == 'a') && !(global & 2))) { 86259243Sobrien global |= (c == 'g') ? 1 : 2; 86359243Sobrien sc = c = getC(0); 86459243Sobrien } 86559243Sobrien 86659243Sobrien switch (c) { 86759243Sobrien case 'p': 86859243Sobrien justpr++; 86959243Sobrien return (en); 87059243Sobrien 87159243Sobrien case 'x': 87259243Sobrien case 'q': 87359243Sobrien global |= 1; 87459243Sobrien /*FALLTHROUGH*/ 87559243Sobrien 87659243Sobrien case 'h': 87759243Sobrien case 'r': 87859243Sobrien case 't': 87959243Sobrien case 'e': 88059243Sobrien case 'u': 88159243Sobrien case 'l': 88259243Sobrien break; 88359243Sobrien 88459243Sobrien case '&': 88559243Sobrien if (slhs[0] == 0) { 88659243Sobrien seterror(ERR_NOSUBST); 88759243Sobrien return (en); 88859243Sobrien } 88959243Sobrien (void) Strcpy(lhsb, slhs); 89059243Sobrien break; 89159243Sobrien 89259243Sobrien#ifdef notdef 89359243Sobrien case '~': 89459243Sobrien if (lhsb[0] == 0) 89559243Sobrien goto badlhs; 89659243Sobrien break; 89759243Sobrien#endif 89859243Sobrien 89959243Sobrien case 's': 90059243Sobrien delim = getC(0); 90159243Sobrien if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) { 90259243Sobrien unreadc(delim); 90359243Sobrien lhsb[0] = 0; 90459243Sobrien seterror(ERR_BADSUBST); 90559243Sobrien return (en); 90659243Sobrien } 90759243Sobrien cp = lhsb; 90859243Sobrien for (;;) { 90959243Sobrien c = getC(0); 91059243Sobrien if (c == '\n') { 91159243Sobrien unreadc(c); 91259243Sobrien break; 91359243Sobrien } 91459243Sobrien if (c == delim) 91559243Sobrien break; 91659243Sobrien if (cp > &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) { 91759243Sobrien lhsb[0] = 0; 91859243Sobrien seterror(ERR_BADSUBST); 91959243Sobrien return (en); 92059243Sobrien } 92159243Sobrien if (c == '\\') { 92259243Sobrien c = getC(0); 92359243Sobrien if (c != delim && c != '\\') 92459243Sobrien *cp++ = '\\'; 92559243Sobrien } 92659243Sobrien *cp++ = (Char) c; 92759243Sobrien } 92859243Sobrien if (cp != lhsb) 92959243Sobrien *cp++ = 0; 93059243Sobrien else if (lhsb[0] == 0) { 93159243Sobrien seterror(ERR_LHS); 93259243Sobrien return (en); 93359243Sobrien } 93459243Sobrien cp = rhsb; 93559243Sobrien (void) Strcpy(orhsb, cp); 93659243Sobrien for (;;) { 93759243Sobrien c = getC(0); 93859243Sobrien if (c == '\n') { 93959243Sobrien unreadc(c); 94059243Sobrien break; 94159243Sobrien } 94259243Sobrien if (c == delim) 94359243Sobrien break; 94459243Sobrien#ifdef notdef 94559243Sobrien if (c == '~') { 94659243Sobrien if (&cp[Strlen(orhsb)] > &rhsb[sizeof(rhsb) / 94759243Sobrien sizeof(Char) - 2]) 94859243Sobrien goto toorhs; 94959243Sobrien (void) Strcpy(cp, orhsb); 95059243Sobrien cp = Strend(cp); 95159243Sobrien continue; 95259243Sobrien } 95359243Sobrien#endif 95459243Sobrien if (cp > &rhsb[sizeof(rhsb) / sizeof(Char) - 2]) { 95559243Sobrien seterror(ERR_RHSLONG); 95659243Sobrien return (en); 95759243Sobrien } 95859243Sobrien if (c == '\\') { 95959243Sobrien c = getC(0); 96059243Sobrien if (c != delim /* && c != '~' */ ) 96159243Sobrien *cp++ = '\\'; 96259243Sobrien } 96359243Sobrien *cp++ = (Char) c; 96459243Sobrien } 96559243Sobrien *cp++ = 0; 96659243Sobrien break; 96759243Sobrien 96859243Sobrien default: 96959243Sobrien if (c == '\n') 97059243Sobrien unreadc(c); 971145479Smp seterror(ERR_BADBANGMOD, (int)c); 97259243Sobrien return (en); 97359243Sobrien } 97459243Sobrien (void) Strcpy(slhs, lhsb); 97559243Sobrien if (exclc) 97659243Sobrien en = dosub(sc, en, global); 97759243Sobrien#ifndef COMPAT 97859243Sobrien } 97959243Sobrien while ((c = getC(0)) == ':'); 98059243Sobrien unreadc(c); 98159243Sobrien#endif /* COMPAT */ 98259243Sobrien return (en); 98359243Sobrien} 98459243Sobrien 98559243Sobrien/* 98659243Sobrien * 98759243Sobrien * From Beto Appleton (beto@aixwiz.austin.ibm.com) 98859243Sobrien * 98959243Sobrien * when using history substitution, and the variable 99059243Sobrien * 'history' is set to a value higher than 1000, 99159243Sobrien * the shell might either freeze (hang) or core-dump. 99259243Sobrien * We raise the limit to 50000000 99359243Sobrien */ 99459243Sobrien 99559243Sobrien#define HIST_PURGE -50000000 99659243Sobrienstatic struct wordent * 99759243Sobriendosub(sc, en, global) 998145479Smp Char sc; 99959243Sobrien struct wordent *en; 1000145479Smp int global; 100159243Sobrien{ 100259243Sobrien struct wordent lexi; 1003145479Smp int didsub = 0, didone = 0; 100459243Sobrien struct wordent *hp = &lexi; 100559243Sobrien struct wordent *wdp; 100659243Sobrien int i = exclc; 100759243Sobrien struct Hist *hst; 100859243Sobrien 100959243Sobrien wdp = hp; 101059243Sobrien while (--i >= 0) { 101159243Sobrien struct wordent *new = 101259243Sobrien (struct wordent *) xcalloc(1, sizeof *wdp); 101359243Sobrien 101459243Sobrien new->word = 0; 101559243Sobrien new->prev = wdp; 101659243Sobrien new->next = hp; 101759243Sobrien wdp->next = new; 101859243Sobrien wdp = new; 101959243Sobrien en = en->next; 102059243Sobrien if (en->word) { 102159243Sobrien Char *tword, *otword; 102259243Sobrien 102359243Sobrien if ((global & 1) || didsub == 0) { 102459243Sobrien tword = subword(en->word, sc, &didone); 102559243Sobrien if (didone) 102659243Sobrien didsub = 1; 102759243Sobrien if (global & 2) { 102859243Sobrien while (didone && tword != STRNULL) { 102959243Sobrien otword = tword; 103059243Sobrien tword = subword(otword, sc, &didone); 103159243Sobrien if (Strcmp(tword, otword) == 0) { 103259243Sobrien xfree((ptr_t) otword); 103359243Sobrien break; 103459243Sobrien } 103559243Sobrien else 103659243Sobrien xfree((ptr_t) otword); 103759243Sobrien } 103859243Sobrien } 103959243Sobrien } 104059243Sobrien else 104159243Sobrien tword = Strsave(en->word); 104259243Sobrien wdp->word = tword; 104359243Sobrien } 104459243Sobrien } 104559243Sobrien if (didsub == 0) 104659243Sobrien seterror(ERR_MODFAIL); 104759243Sobrien hp->prev = wdp; 104859243Sobrien /* 104959243Sobrien * ANSI mode HP/UX compiler chokes on 105059243Sobrien * return &enthist(HIST_PURGE, &lexi, 0)->Hlex; 105159243Sobrien */ 105259243Sobrien hst = enthist(HIST_PURGE, &lexi, 0, 0); 105359243Sobrien return &(hst->Hlex); 105459243Sobrien} 105559243Sobrien 105659243Sobrienstatic Char * 105759243Sobriensubword(cp, type, adid) 105859243Sobrien Char *cp; 1059145479Smp Char type; 1060145479Smp int *adid; 106159243Sobrien{ 106259243Sobrien Char wbuf[BUFSIZE]; 106359243Sobrien Char *wp, *mp, *np; 106459243Sobrien int i; 106559243Sobrien 106659243Sobrien *adid = 0; 106759243Sobrien switch (type) { 106859243Sobrien 106959243Sobrien case 'r': 107059243Sobrien case 'e': 107159243Sobrien case 'h': 107259243Sobrien case 't': 107359243Sobrien case 'q': 107459243Sobrien case 'x': 107559243Sobrien case 'u': 107659243Sobrien case 'l': 107759243Sobrien wp = domod(cp, type); 107859243Sobrien if (wp == 0) 107959243Sobrien return (Strsave(cp)); 108059243Sobrien *adid = 1; 108159243Sobrien return (wp); 108259243Sobrien 108359243Sobrien default: 108459243Sobrien wp = wbuf; 108559243Sobrien i = BUFSIZE - 4; 108659243Sobrien for (mp = cp; *mp; mp++) 108759243Sobrien if (matchs(mp, lhsb)) { 108859243Sobrien for (np = cp; np < mp;) 108959243Sobrien *wp++ = *np++, --i; 109059243Sobrien for (np = rhsb; *np; np++) 109159243Sobrien switch (*np) { 109259243Sobrien 109359243Sobrien case '\\': 109459243Sobrien if (np[1] == '&') 109559243Sobrien np++; 109659243Sobrien /* fall into ... */ 109759243Sobrien 109859243Sobrien default: 109959243Sobrien if (--i < 0) { 110059243Sobrien seterror(ERR_SUBOVFL); 110159243Sobrien return (STRNULL); 110259243Sobrien } 110359243Sobrien *wp++ = *np; 110459243Sobrien continue; 110559243Sobrien 110659243Sobrien case '&': 110759243Sobrien i -= Strlen(lhsb); 110859243Sobrien if (i < 0) { 110959243Sobrien seterror(ERR_SUBOVFL); 111059243Sobrien return (STRNULL); 111159243Sobrien } 111259243Sobrien *wp = 0; 111359243Sobrien (void) Strcat(wp, lhsb); 111459243Sobrien wp = Strend(wp); 111559243Sobrien continue; 111659243Sobrien } 111759243Sobrien mp += Strlen(lhsb); 111859243Sobrien i -= Strlen(mp); 111959243Sobrien if (i < 0) { 112059243Sobrien seterror(ERR_SUBOVFL); 112159243Sobrien return (STRNULL); 112259243Sobrien } 112359243Sobrien *wp = 0; 112459243Sobrien (void) Strcat(wp, mp); 112559243Sobrien *adid = 1; 112659243Sobrien return (Strsave(wbuf)); 112759243Sobrien } 112859243Sobrien return (Strsave(cp)); 112959243Sobrien } 113059243Sobrien} 113159243Sobrien 113259243SobrienChar * 113359243Sobriendomod(cp, type) 113459243Sobrien Char *cp; 1135145479Smp Char type; 113659243Sobrien{ 113759243Sobrien Char *wp, *xp; 113859243Sobrien int c; 113959243Sobrien 114059243Sobrien switch (type) { 114159243Sobrien 114259243Sobrien case 'x': 114359243Sobrien case 'q': 114459243Sobrien wp = Strsave(cp); 114559243Sobrien for (xp = wp; (c = *xp) != 0; xp++) 114659243Sobrien if ((c != ' ' && c != '\t') || type == 'q') 114759243Sobrien *xp |= QUOTE; 114859243Sobrien return (wp); 114959243Sobrien 115059243Sobrien case 'l': 1151145479Smp wp = NLSChangeCase(cp, 1); 1152145479Smp return wp ? wp : Strsave(cp); 115359243Sobrien 115459243Sobrien case 'u': 1155145479Smp wp = NLSChangeCase(cp, 0); 1156145479Smp return wp ? wp : Strsave(cp); 115759243Sobrien 115859243Sobrien case 'h': 115959243Sobrien case 't': 116059243Sobrien if (!any(short2str(cp), '/')) 116159243Sobrien return (type == 't' ? Strsave(cp) : 0); 116259243Sobrien wp = Strend(cp); 116359243Sobrien while (*--wp != '/') 116459243Sobrien continue; 116559243Sobrien if (type == 'h') 116659243Sobrien xp = Strsave(cp), xp[wp - cp] = 0; 116759243Sobrien else 116859243Sobrien xp = Strsave(wp + 1); 116959243Sobrien return (xp); 117059243Sobrien 117159243Sobrien case 'e': 117259243Sobrien case 'r': 117359243Sobrien wp = Strend(cp); 117459243Sobrien for (wp--; wp >= cp && *wp != '/'; wp--) 117559243Sobrien if (*wp == '.') { 117659243Sobrien if (type == 'e') 117759243Sobrien xp = Strsave(wp + 1); 117859243Sobrien else 117959243Sobrien xp = Strsave(cp), xp[wp - cp] = 0; 118059243Sobrien return (xp); 118159243Sobrien } 118259243Sobrien return (Strsave(type == 'e' ? STRNULL : cp)); 118359243Sobrien default: 118459243Sobrien break; 118559243Sobrien } 118659243Sobrien return (0); 118759243Sobrien} 118859243Sobrien 118959243Sobrienstatic int 119059243Sobrienmatchs(str, pat) 119159243Sobrien Char *str, *pat; 119259243Sobrien{ 119359243Sobrien while (*str && *pat && *str == *pat) 119459243Sobrien str++, pat++; 119559243Sobrien return (*pat == 0); 119659243Sobrien} 119759243Sobrien 119859243Sobrienstatic int 119959243Sobriengetsel(al, ar, dol) 120059243Sobrien int *al, *ar; 120159243Sobrien int dol; 120259243Sobrien{ 1203145479Smp eChar c = getC(0); 120459243Sobrien int i; 1205145479Smp int first = *al < 0; 120659243Sobrien 120759243Sobrien switch (c) { 120859243Sobrien 120959243Sobrien case '%': 121059243Sobrien if (quesarg == -1) { 121159243Sobrien seterror(ERR_BADBANGARG); 121259243Sobrien return (0); 121359243Sobrien } 121459243Sobrien if (*al < 0) 121559243Sobrien *al = quesarg; 121659243Sobrien *ar = quesarg; 121759243Sobrien break; 121859243Sobrien 121959243Sobrien case '-': 122059243Sobrien if (*al < 0) { 122159243Sobrien *al = 0; 122259243Sobrien *ar = dol - 1; 122359243Sobrien unreadc(c); 122459243Sobrien } 122559243Sobrien return (1); 122659243Sobrien 122759243Sobrien case '^': 122859243Sobrien if (*al < 0) 122959243Sobrien *al = 1; 123059243Sobrien *ar = 1; 123159243Sobrien break; 123259243Sobrien 123359243Sobrien case '$': 123459243Sobrien if (*al < 0) 123559243Sobrien *al = dol; 123659243Sobrien *ar = dol; 123759243Sobrien break; 123859243Sobrien 123959243Sobrien case '*': 124059243Sobrien if (*al < 0) 124159243Sobrien *al = 1; 124259243Sobrien *ar = dol; 124359243Sobrien if (*ar < *al) { 124459243Sobrien *ar = 0; 124559243Sobrien *al = 1; 124659243Sobrien return (1); 124759243Sobrien } 124859243Sobrien break; 124959243Sobrien 125059243Sobrien default: 125159243Sobrien if (Isdigit(c)) { 125259243Sobrien i = 0; 125359243Sobrien while (Isdigit(c)) { 125459243Sobrien i = i * 10 + c - '0'; 125559243Sobrien c = getC(0); 125659243Sobrien } 125759243Sobrien if (i < 0) 125859243Sobrien i = dol + 1; 125959243Sobrien if (*al < 0) 126059243Sobrien *al = i; 126159243Sobrien *ar = i; 126259243Sobrien } 126359243Sobrien else if (*al < 0) 126459243Sobrien *al = 0, *ar = dol; 126559243Sobrien else 126659243Sobrien *ar = dol - 1; 126759243Sobrien unreadc(c); 126859243Sobrien break; 126959243Sobrien } 127059243Sobrien if (first) { 127159243Sobrien c = getC(0); 127259243Sobrien unreadc(c); 127359243Sobrien if (any("-$*", c)) 127459243Sobrien return (1); 127559243Sobrien } 127659243Sobrien if (*al > *ar || *ar > dol) { 127759243Sobrien seterror(ERR_BADBANGARG); 127859243Sobrien return (0); 127959243Sobrien } 128059243Sobrien return (1); 128159243Sobrien 128259243Sobrien} 128359243Sobrien 128459243Sobrienstatic struct wordent * 128559243Sobriengethent(sc) 1286145479Smp Char sc; 128759243Sobrien{ 128859243Sobrien struct Hist *hp; 128959243Sobrien Char *np; 1290145479Smp eChar c; 129159243Sobrien int event; 1292145479Smp int back = 0; 129359243Sobrien 1294145479Smp c = sc == HISTSUB ? (eChar)HIST : getC(0); 1295145479Smp if (c == (eChar)HIST) { 129659243Sobrien if (alhistp) 129759243Sobrien return (alhistp); 129859243Sobrien event = eventno; 129959243Sobrien } 130059243Sobrien else 130159243Sobrien switch (c) { 130259243Sobrien 130359243Sobrien case ':': 130459243Sobrien case '^': 130559243Sobrien case '$': 130659243Sobrien case '*': 130759243Sobrien case '%': 130859243Sobrien ungetC(c); 130959243Sobrien if (lastev == eventno && alhistp) 131059243Sobrien return (alhistp); 131159243Sobrien event = lastev; 131259243Sobrien break; 131359243Sobrien 131459243Sobrien case '#': /* !# is command being typed in (mrh) */ 131559243Sobrien if (--hleft == 0) { 131659243Sobrien seterror(ERR_HISTLOOP); 131759243Sobrien return (0); 131859243Sobrien } 131959243Sobrien else 132059243Sobrien return (¶ml); 132159243Sobrien /* NOTREACHED */ 132259243Sobrien 132359243Sobrien case '-': 132459243Sobrien back = 1; 132559243Sobrien c = getC(0); 132659243Sobrien /* FALLSTHROUGH */ 132759243Sobrien 132859243Sobrien default: 132959243Sobrien if (any("(=~", c)) { 133059243Sobrien unreadc(c); 133159243Sobrien ungetC(HIST); 133259243Sobrien return (0); 133359243Sobrien } 133459243Sobrien np = lhsb; 133559243Sobrien event = 0; 133659243Sobrien while (!cmap(c, _ESC | _META | _QF | _QB) && !any("^*-%${}:#", c)) { 133759243Sobrien if (event != -1 && Isdigit(c)) 133859243Sobrien event = event * 10 + c - '0'; 133959243Sobrien else 134059243Sobrien event = -1; 134159243Sobrien if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) 134259243Sobrien *np++ = (Char) c; 134359243Sobrien c = getC(0); 134459243Sobrien } 134559243Sobrien unreadc(c); 134659243Sobrien if (np == lhsb) { 134759243Sobrien ungetC(HIST); 134859243Sobrien return (0); 134959243Sobrien } 135059243Sobrien *np++ = 0; 135159243Sobrien if (event != -1) { 135259243Sobrien /* 135359243Sobrien * History had only digits 135459243Sobrien */ 135559243Sobrien if (back) 135659243Sobrien event = eventno + (alhistp == 0) - (event ? event : 0); 135759243Sobrien break; 135859243Sobrien } 135959243Sobrien if (back) { 136059243Sobrien event = sizeof(lhsb) / sizeof(lhsb[0]); 136159243Sobrien np = &lhsb[--event]; 136259243Sobrien *np-- = '\0'; 136359243Sobrien for (event--; np > lhsb; *np-- = lhsb[--event]) 136459243Sobrien continue; 136559243Sobrien *np = '-'; 136659243Sobrien } 136759243Sobrien hp = findev(lhsb, 0); 136859243Sobrien if (hp) 136959243Sobrien lastev = hp->Hnum; 137059243Sobrien return (&hp->Hlex); 137159243Sobrien 137259243Sobrien case '?': 137359243Sobrien np = lhsb; 137459243Sobrien for (;;) { 137559243Sobrien c = getC(0); 137659243Sobrien if (c == '\n') { 137759243Sobrien unreadc(c); 137859243Sobrien break; 137959243Sobrien } 138059243Sobrien if (c == '?') 138159243Sobrien break; 138259243Sobrien if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) 138359243Sobrien *np++ = (Char) c; 138459243Sobrien } 138559243Sobrien if (np == lhsb) { 138659243Sobrien if (lhsb[0] == 0) { 138759243Sobrien seterror(ERR_NOSEARCH); 138859243Sobrien return (0); 138959243Sobrien } 139059243Sobrien } 139159243Sobrien else 139259243Sobrien *np++ = 0; 139359243Sobrien hp = findev(lhsb, 1); 139459243Sobrien if (hp) 139559243Sobrien lastev = hp->Hnum; 139659243Sobrien return (&hp->Hlex); 139759243Sobrien } 139859243Sobrien 139959243Sobrien for (hp = Histlist.Hnext; hp; hp = hp->Hnext) 140059243Sobrien if (hp->Hnum == event) { 140159243Sobrien hp->Href = eventno; 140259243Sobrien lastev = hp->Hnum; 140359243Sobrien return (&hp->Hlex); 140459243Sobrien } 140559243Sobrien np = putn(event); 140659243Sobrien seterror(ERR_NOEVENT, short2str(np)); 140759243Sobrien return (0); 140859243Sobrien} 140959243Sobrien 141059243Sobrienstatic struct Hist * 141159243Sobrienfindev(cp, anyarg) 141259243Sobrien Char *cp; 1413145479Smp int anyarg; 141459243Sobrien{ 141559243Sobrien struct Hist *hp; 141659243Sobrien 141759243Sobrien for (hp = Histlist.Hnext; hp; hp = hp->Hnext) { 141859243Sobrien Char *dp; 141959243Sobrien Char *p, *q; 142059243Sobrien struct wordent *lp = hp->Hlex.next; 142159243Sobrien int argno = 0; 142259243Sobrien 142359243Sobrien /* 142459243Sobrien * The entries added by alias substitution don't have a newline but do 142559243Sobrien * have a negative event number. Savehist() trims off these entries, 142659243Sobrien * but it happens before alias expansion, too early to delete those 142759243Sobrien * from the previous command. 142859243Sobrien */ 142959243Sobrien if (hp->Hnum < 0) 143059243Sobrien continue; 143159243Sobrien if (lp->word[0] == '\n') 143259243Sobrien continue; 143359243Sobrien if (!anyarg) { 143459243Sobrien p = cp; 143559243Sobrien q = lp->word; 143659243Sobrien do 143759243Sobrien if (!*p) 143859243Sobrien return (hp); 143959243Sobrien while (*p++ == *q++); 144059243Sobrien continue; 144159243Sobrien } 144259243Sobrien do { 144359243Sobrien for (dp = lp->word; *dp; dp++) { 144459243Sobrien p = cp; 144559243Sobrien q = dp; 144659243Sobrien do 144759243Sobrien if (!*p) { 144859243Sobrien quesarg = argno; 144959243Sobrien return (hp); 145059243Sobrien } 145159243Sobrien while (*p++ == *q++); 145259243Sobrien } 145359243Sobrien lp = lp->next; 145459243Sobrien argno++; 145559243Sobrien } while (lp->word[0] != '\n'); 145659243Sobrien } 145759243Sobrien seterror(ERR_NOEVENT, short2str(cp)); 145859243Sobrien return (0); 145959243Sobrien} 146059243Sobrien 146159243Sobrien 146259243Sobrienstatic void 146359243Sobriensetexclp(cp) 146459243Sobrien Char *cp; 146559243Sobrien{ 146659243Sobrien if (cp && cp[0] == '\n') 146759243Sobrien return; 146859243Sobrien exclp = cp; 146959243Sobrien} 147059243Sobrien 147159243Sobrienvoid 147259243Sobrienunreadc(c) 1473145479Smp Char c; 147459243Sobrien{ 147559243Sobrien peekread = (Char) c; 147659243Sobrien} 147759243Sobrien 1478145479SmpeChar 147959243Sobrienreadc(wanteof) 1480145479Smp int wanteof; 148159243Sobrien{ 1482145479Smp eChar c; 148359243Sobrien static int sincereal; /* Number of real EOFs we've seen */ 148459243Sobrien 148559243Sobrien#ifdef DEBUG_INP 148659243Sobrien xprintf("readc\n"); 148759243Sobrien#endif 148859243Sobrien if ((c = peekread) != 0) { 148959243Sobrien peekread = 0; 149059243Sobrien return (c); 149159243Sobrien } 149259243Sobrien 149359243Sobrientop: 149469408Sache aret = TCSH_F_SEEK; 149559243Sobrien if (alvecp) { 149659243Sobrien arun = 1; 149759243Sobrien#ifdef DEBUG_INP 149859243Sobrien xprintf("alvecp %c\n", *alvecp & 0xff); 149959243Sobrien#endif 150069408Sache aret = TCSH_A_SEEK; 150159243Sobrien if ((c = *alvecp++) != 0) 150259243Sobrien return (c); 150359243Sobrien if (alvec && *alvec) { 150459243Sobrien alvecp = *alvec++; 150559243Sobrien return (' '); 150659243Sobrien } 150759243Sobrien else { 150859243Sobrien alvecp = NULL; 150969408Sache aret = TCSH_F_SEEK; 151059243Sobrien return('\n'); 151159243Sobrien } 151259243Sobrien } 151359243Sobrien if (alvec) { 151459243Sobrien arun = 1; 151559243Sobrien if ((alvecp = *alvec) != 0) { 151659243Sobrien alvec++; 151759243Sobrien goto top; 151859243Sobrien } 151959243Sobrien /* Infinite source! */ 152059243Sobrien return ('\n'); 152159243Sobrien } 152259243Sobrien arun = 0; 152359243Sobrien if (evalp) { 152469408Sache aret = TCSH_E_SEEK; 152559243Sobrien if ((c = *evalp++) != 0) 152659243Sobrien return (c); 152759243Sobrien if (evalvec && *evalvec) { 152859243Sobrien evalp = *evalvec++; 152959243Sobrien return (' '); 153059243Sobrien } 153169408Sache aret = TCSH_F_SEEK; 153259243Sobrien evalp = 0; 153359243Sobrien } 153459243Sobrien if (evalvec) { 153559243Sobrien if (evalvec == INVPPTR) { 153659243Sobrien doneinp = 1; 153759243Sobrien reset(); 153859243Sobrien } 153959243Sobrien if ((evalp = *evalvec) != 0) { 154059243Sobrien evalvec++; 154159243Sobrien goto top; 154259243Sobrien } 154359243Sobrien evalvec = INVPPTR; 154459243Sobrien return ('\n'); 154559243Sobrien } 154659243Sobrien do { 154759243Sobrien if (arginp == INVPTR || onelflg == 1) { 154859243Sobrien if (wanteof) 1549145479Smp return CHAR_ERR; 155059243Sobrien exitstat(); 155159243Sobrien } 155259243Sobrien if (arginp) { 155359243Sobrien if ((c = *arginp++) == 0) { 155459243Sobrien arginp = INVPTR; 155559243Sobrien return ('\n'); 155659243Sobrien } 155759243Sobrien return (c); 155859243Sobrien } 155959243Sobrien#ifdef BSDJOBS 156059243Sobrienreread: 156159243Sobrien#endif /* BSDJOBS */ 156259243Sobrien c = bgetc(); 1563145479Smp if (c == CHAR_ERR) { 156469408Sache#ifndef WINNT_NATIVE 156559243Sobrien# ifndef POSIX 156659243Sobrien# ifdef TERMIO 156759243Sobrien struct termio tty; 156859243Sobrien# else /* SGTTYB */ 156959243Sobrien struct sgttyb tty; 157059243Sobrien# endif /* TERMIO */ 157159243Sobrien# else /* POSIX */ 157259243Sobrien struct termios tty; 157359243Sobrien# endif /* POSIX */ 157469408Sache#endif /* !WINNT_NATIVE */ 157559243Sobrien if (wanteof) 1576145479Smp return CHAR_ERR; 157759243Sobrien /* was isatty but raw with ignoreeof yields problems */ 157869408Sache#ifndef WINNT_NATIVE 157959243Sobrien# ifndef POSIX 158059243Sobrien# ifdef TERMIO 158159243Sobrien if (ioctl(SHIN, TCGETA, (ioctl_t) & tty) == 0 && 158259243Sobrien (tty.c_lflag & ICANON)) 158359243Sobrien# else /* GSTTYB */ 158459243Sobrien if (ioctl(SHIN, TIOCGETP, (ioctl_t) & tty) == 0 && 158559243Sobrien (tty.sg_flags & RAW) == 0) 158659243Sobrien# endif /* TERMIO */ 158759243Sobrien# else /* POSIX */ 158859243Sobrien if (tcgetattr(SHIN, &tty) == 0 && 158959243Sobrien (tty.c_lflag & ICANON)) 159059243Sobrien# endif /* POSIX */ 159169408Sache#else /* WINNT_NATIVE */ 159259243Sobrien if (isatty(SHIN)) 159369408Sache#endif /* !WINNT_NATIVE */ 159459243Sobrien { 159559243Sobrien#ifdef BSDJOBS 159659243Sobrien int ctpgrp; 159759243Sobrien#endif /* BSDJOBS */ 159859243Sobrien 1599100616Smp if (numeof != 0 && ++sincereal >= numeof) /* Too many EOFs? Bye! */ 160059243Sobrien goto oops; 160159243Sobrien#ifdef BSDJOBS 160259243Sobrien if (tpgrp != -1 && 160359243Sobrien (ctpgrp = tcgetpgrp(FSHTTY)) != -1 && 160459243Sobrien tpgrp != ctpgrp) { 160559243Sobrien (void) tcsetpgrp(FSHTTY, tpgrp); 160659243Sobrien# ifdef _SEQUENT_ 160759243Sobrien if (ctpgrp) 160859243Sobrien# endif /* _SEQUENT */ 160959243Sobrien (void) killpg((pid_t) ctpgrp, SIGHUP); 161059243Sobrien# ifdef notdef 161159243Sobrien /* 161259243Sobrien * With the walking process group fix, this message 161359243Sobrien * is now obsolete. As the foreground process group 161459243Sobrien * changes, the shell needs to adjust. Well too bad. 161559243Sobrien */ 161659243Sobrien xprintf(CGETS(16, 1, "Reset tty pgrp from %d to %d\n"), 161759243Sobrien ctpgrp, tpgrp); 161859243Sobrien# endif /* notdef */ 161959243Sobrien goto reread; 162059243Sobrien } 162159243Sobrien#endif /* BSDJOBS */ 162259243Sobrien /* What follows is complicated EOF handling -- sterling@netcom.com */ 162359243Sobrien /* First, we check to see if we have ignoreeof set */ 162459243Sobrien if (adrof(STRignoreeof)) { 162559243Sobrien /* If so, we check for any stopped jobs only on the first EOF */ 162659243Sobrien if ((sincereal == 1) && (chkstop == 0)) { 162759243Sobrien panystop(1); 162859243Sobrien } 162959243Sobrien } else { 163059243Sobrien /* If we don't have ignoreeof set, always check for stopped jobs */ 163159243Sobrien if (chkstop == 0) { 163259243Sobrien panystop(1); 163359243Sobrien } 163459243Sobrien } 163559243Sobrien /* At this point, if there were stopped jobs, we would have already 163659243Sobrien * called reset(). If we got this far, assume we can print an 163759243Sobrien * exit/logout message if we ignoreeof, or just exit. 163859243Sobrien */ 163959243Sobrien if (adrof(STRignoreeof)) { 164059243Sobrien /* If so, tell the user to use exit or logout */ 164159243Sobrien if (loginsh) { 164259243Sobrien xprintf(CGETS(16, 2, 164359243Sobrien "\nUse \"logout\" to logout.\n")); 164459243Sobrien } else { 164559243Sobrien xprintf(CGETS(16, 3, 164659243Sobrien "\nUse \"exit\" to leave %s.\n"), 164759243Sobrien progname); 164859243Sobrien } 164959243Sobrien reset(); 165059243Sobrien } else { 165159243Sobrien /* If we don't have ignoreeof set, just fall through */ 165259243Sobrien ; /* EMPTY */ 165359243Sobrien } 165459243Sobrien } 165559243Sobrien oops: 165659243Sobrien doneinp = 1; 165759243Sobrien reset(); 165859243Sobrien } 165959243Sobrien sincereal = 0; 166059243Sobrien if (c == '\n' && onelflg) 166159243Sobrien onelflg--; 166259243Sobrien } while (c == 0); 166359243Sobrien if (histlinep < histline + BUFSIZE) 166459243Sobrien *histlinep++ = (Char) c; 166559243Sobrien return (c); 166659243Sobrien} 166759243Sobrien 166859243Sobrienstatic void 166959243Sobrienballoc(buf) 167059243Sobrien int buf; 167159243Sobrien{ 167259243Sobrien Char **nfbuf; 167359243Sobrien 167459243Sobrien while (buf >= fblocks) { 167559243Sobrien nfbuf = (Char **) xcalloc((size_t) (fblocks + 2), 167659243Sobrien sizeof(Char **)); 167759243Sobrien if (fbuf) { 167859243Sobrien (void) blkcpy(nfbuf, fbuf); 167959243Sobrien xfree((ptr_t) fbuf); 168059243Sobrien } 168159243Sobrien fbuf = nfbuf; 168259243Sobrien fbuf[fblocks] = (Char *) xcalloc(BUFSIZE, sizeof(Char)); 168359243Sobrien fblocks++; 168459243Sobrien } 168559243Sobrien} 168659243Sobrien 1687145479Smpstatic ssize_t 1688145479Smpwide_read(fildes, buf, nchars, use_fclens) 1689145479Smp int fildes; 1690145479Smp Char *buf; 1691145479Smp size_t nchars; 1692145479Smp int use_fclens; 1693145479Smp{ 1694145479Smp char cbuf[BUFSIZE + 1]; 1695145479Smp ssize_t res, r; 1696145479Smp size_t partial; 1697145479Smp 1698145479Smp assert (nchars <= sizeof(cbuf)/sizeof(*cbuf)); 1699145479Smp USE(use_fclens); 1700145479Smp res = 0; 1701145479Smp partial = 0; 1702145479Smp do { 1703145479Smp size_t i; 1704145479Smp 1705145479Smp do 1706145479Smp r = read(fildes, cbuf + partial, 1707145479Smp nchars > partial ? nchars - partial : 1); 1708145479Smp while (partial != 0 && r < 0 && errno == EINTR); 1709145479Smp if (partial == 0 && r <= 0) 1710145479Smp break; 1711145479Smp partial += r; 1712145479Smp i = 0; 1713145479Smp while (i < partial) { 1714145479Smp int len; 1715145479Smp 1716145479Smp len = normal_mbtowc(buf + res, cbuf + i, partial - i); 1717145479Smp if (len == -1) { 1718145479Smp reset_mbtowc(); 1719145479Smp if (partial < MB_LEN_MAX && r > 0) 1720145479Smp /* Maybe a partial character and there is still a chance 1721145479Smp to read more */ 1722145479Smp break; 1723145479Smp buf[res] = (unsigned char)cbuf[i] | INVALID_BYTE; 1724145479Smp } 1725145479Smp if (len <= 0) 1726145479Smp len = 1; 1727145479Smp#ifdef WIDE_STRINGS 1728145479Smp if (use_fclens) 1729145479Smp fclens[res] = len; 1730145479Smp#endif 1731145479Smp i += len; 1732145479Smp res++; 1733145479Smp nchars--; 1734145479Smp } 1735145479Smp if (i != partial) 1736145479Smp memmove(cbuf, cbuf + i, partial - i); 1737145479Smp partial -= i; 1738145479Smp } while (partial != 0); 1739145479Smp /* Throwing away possible partial multibyte characters on error */ 1740145479Smp return res != 0 ? res : r; 1741145479Smp} 1742145479Smp 1743145479Smpstatic eChar 174459243Sobrienbgetc() 174559243Sobrien{ 1746145479Smp Char ch; 174759243Sobrien int c, off, buf; 174859243Sobrien int numleft = 0, roomleft; 174959243Sobrien 175059243Sobrien if (cantell) { 175159243Sobrien if (fseekp < fbobp || fseekp > feobp) { 175259243Sobrien fbobp = feobp = fseekp; 175359243Sobrien (void) lseek(SHIN, fseekp, L_SET); 175459243Sobrien } 175559243Sobrien if (fseekp == feobp) { 175659243Sobrien fbobp = feobp; 175759243Sobrien do 1758145479Smp c = wide_read(SHIN, fbuf[0], BUFSIZE, 1); 175959243Sobrien while (c < 0 && errno == EINTR); 176059243Sobrien#ifdef convex 176159243Sobrien if (c < 0) 176259243Sobrien stderror(ERR_SYSTEM, progname, strerror(errno)); 176359243Sobrien#endif /* convex */ 176459243Sobrien if (c <= 0) 1765145479Smp return CHAR_ERR; 176659243Sobrien feobp += c; 176759243Sobrien } 176869408Sache#ifndef WINNT_NATIVE 1769145479Smp ch = fbuf[0][fseekp - fbobp]; 177059243Sobrien fseekp++; 177159243Sobrien#else 177259243Sobrien do { 1773145479Smp ch = fbuf[0][fseekp - fbobp]; 177459243Sobrien fseekp++; 1775145479Smp } while(ch == '\r'); 177669408Sache#endif /* !WINNT_NATIVE */ 1777145479Smp return (ch); 177859243Sobrien } 177959243Sobrien 178059243Sobrien while (fseekp >= feobp) { 1781100616Smp if ((editing 1782100616Smp#if defined(FILEC) && defined(TIOCSTI) 1783100616Smp || filec 1784100616Smp#endif /* FILEC && TIOCSTI */ 1785100616Smp ) && intty) { /* then use twenex routine */ 178659243Sobrien fseekp = feobp; /* where else? */ 1787100616Smp#if defined(FILEC) && defined(TIOCSTI) 1788100616Smp if (!editing) 1789100616Smp c = numleft = tenex(InputBuf, BUFSIZE); 1790100616Smp else 1791100616Smp#endif /* FILEC && TIOCSTI */ 179259243Sobrien c = numleft = Inputl(); /* PWP: get a line */ 179359243Sobrien while (numleft > 0) { 179459243Sobrien off = (int) feobp % BUFSIZE; 179559243Sobrien buf = (int) feobp / BUFSIZE; 179659243Sobrien balloc(buf); 179759243Sobrien roomleft = BUFSIZE - off; 179859243Sobrien if (roomleft > numleft) 179959243Sobrien roomleft = numleft; 1800100616Smp (void) memmove((ptr_t) (fbuf[buf] + off), 1801100616Smp (ptr_t) (InputBuf + c - numleft), 1802100616Smp (size_t) (roomleft * sizeof(Char))); 180359243Sobrien numleft -= roomleft; 180459243Sobrien feobp += roomleft; 180559243Sobrien } 1806100616Smp } else { 180759243Sobrien off = (int) feobp % BUFSIZE; 180859243Sobrien buf = (int) feobp / BUFSIZE; 180959243Sobrien balloc(buf); 181059243Sobrien roomleft = BUFSIZE - off; 1811145479Smp c = wide_read(SHIN, fbuf[buf] + off, (size_t) roomleft, 0); 1812145479Smp if (c > 0) 181359243Sobrien feobp += c; 181459243Sobrien } 181559243Sobrien if (c == 0 || (c < 0 && fixio(SHIN, errno) == -1)) 1816145479Smp return CHAR_ERR; 181759243Sobrien } 1818145479Smp#ifdef SIG_WINDOW 1819145479Smp if (windowchg) 1820145479Smp (void) check_window_size(0); /* for window systems */ 1821145479Smp#endif /* SIG_WINDOW */ 182269408Sache#ifndef WINNT_NATIVE 1823145479Smp ch = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE]; 182459243Sobrien fseekp++; 182559243Sobrien#else 182659243Sobrien do { 1827145479Smp ch = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE]; 182859243Sobrien fseekp++; 1829145479Smp } while(ch == '\r'); 183069408Sache#endif /* !WINNT_NATIVE */ 1831145479Smp return (ch); 183259243Sobrien} 183359243Sobrien 183459243Sobrienstatic void 183559243Sobrienbfree() 183659243Sobrien{ 183759243Sobrien int sb, i; 183859243Sobrien 183959243Sobrien if (cantell) 184059243Sobrien return; 184159243Sobrien if (whyles) 184259243Sobrien return; 184359243Sobrien sb = (int) (fseekp - 1) / BUFSIZE; 184459243Sobrien if (sb > 0) { 184559243Sobrien for (i = 0; i < sb; i++) 184659243Sobrien xfree((ptr_t) fbuf[i]); 184759243Sobrien (void) blkcpy(fbuf, &fbuf[sb]); 184859243Sobrien fseekp -= BUFSIZE * sb; 184959243Sobrien feobp -= BUFSIZE * sb; 185059243Sobrien fblocks -= sb; 185159243Sobrien } 185259243Sobrien} 185359243Sobrien 185459243Sobrienvoid 185559243Sobrienbseek(l) 185659243Sobrien struct Ain *l; 185759243Sobrien{ 185859243Sobrien switch (aret = l->type) { 185969408Sache case TCSH_E_SEEK: 186059243Sobrien evalvec = l->a_seek; 186159243Sobrien evalp = l->c_seek; 186259243Sobrien#ifdef DEBUG_SEEK 186359243Sobrien xprintf(CGETS(16, 4, "seek to eval %x %x\n"), evalvec, evalp); 186459243Sobrien#endif 186559243Sobrien return; 186669408Sache case TCSH_A_SEEK: 186759243Sobrien alvec = l->a_seek; 186859243Sobrien alvecp = l->c_seek; 186959243Sobrien#ifdef DEBUG_SEEK 187059243Sobrien xprintf(CGETS(16, 5, "seek to alias %x %x\n"), alvec, alvecp); 187159243Sobrien#endif 187259243Sobrien return; 187369408Sache case TCSH_F_SEEK: 187459243Sobrien#ifdef DEBUG_SEEK 187559243Sobrien xprintf(CGETS(16, 6, "seek to file %x\n"), fseekp); 187659243Sobrien#endif 187759243Sobrien fseekp = l->f_seek; 1878145479Smp#ifdef WIDE_STRINGS 1879145479Smp if (cantell) { 1880145479Smp if (fseekp >= fbobp) { 1881145479Smp size_t i; 1882145479Smp off_t o; 1883145479Smp 1884145479Smp o = fbobp; 1885145479Smp for (i = 0; i < feobp - fbobp; i++) { 1886145479Smp if (fseekp == o) { 1887145479Smp fseekp = fbobp + i; 1888145479Smp return; 1889145479Smp } 1890145479Smp o += fclens[i]; 1891145479Smp } 1892145479Smp if (fseekp == o) { 1893145479Smp fseekp = feobp; 1894145479Smp return; 1895145479Smp } 1896145479Smp } 1897145479Smp fbobp = feobp = fseekp + 1; /* To force lseek() */ 1898145479Smp } 1899145479Smp#endif 190059243Sobrien return; 190159243Sobrien default: 190259243Sobrien xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret); 190359243Sobrien abort(); 190459243Sobrien } 190559243Sobrien} 190659243Sobrien 190759243Sobrien/* any similarity to bell telephone is purely accidental */ 190859243Sobrienvoid 190959243Sobrienbtell(l) 191059243Sobrienstruct Ain *l; 191159243Sobrien{ 191259243Sobrien switch (l->type = aret) { 191369408Sache case TCSH_E_SEEK: 191459243Sobrien l->a_seek = evalvec; 191559243Sobrien l->c_seek = evalp; 191659243Sobrien#ifdef DEBUG_SEEK 191759243Sobrien xprintf(CGETS(16, 8, "tell eval %x %x\n"), evalvec, evalp); 191859243Sobrien#endif 191959243Sobrien return; 192069408Sache case TCSH_A_SEEK: 192159243Sobrien l->a_seek = alvec; 192259243Sobrien l->c_seek = alvecp; 192359243Sobrien#ifdef DEBUG_SEEK 192459243Sobrien xprintf(CGETS(16, 9, "tell alias %x %x\n"), alvec, alvecp); 192559243Sobrien#endif 192659243Sobrien return; 192769408Sache case TCSH_F_SEEK: 1928145479Smp#ifdef WIDE_STRINGS 1929145479Smp if (cantell && fseekp >= fbobp && fseekp < feobp) { 1930145479Smp size_t i; 1931145479Smp 1932145479Smp l->f_seek = fbobp; 1933145479Smp for (i = 0; i < fseekp - fbobp; i++) 1934145479Smp l->f_seek += fclens[i]; 1935145479Smp } else 1936145479Smp#endif 1937145479Smp /*SUPPRESS 112*/ 1938145479Smp l->f_seek = fseekp; 193959243Sobrien l->a_seek = NULL; 194059243Sobrien#ifdef DEBUG_SEEK 194159243Sobrien xprintf(CGETS(16, 10, "tell file %x\n"), fseekp); 194259243Sobrien#endif 194359243Sobrien return; 194459243Sobrien default: 194559243Sobrien xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret); 194659243Sobrien abort(); 194759243Sobrien } 194859243Sobrien} 194959243Sobrien 195059243Sobrienvoid 195159243Sobrienbtoeof() 195259243Sobrien{ 195359243Sobrien (void) lseek(SHIN, (off_t) 0, L_XTND); 195469408Sache aret = TCSH_F_SEEK; 195559243Sobrien fseekp = feobp; 195659243Sobrien alvec = NULL; 195759243Sobrien alvecp = NULL; 195859243Sobrien evalvec = NULL; 195959243Sobrien evalp = NULL; 196059243Sobrien wfree(); 196159243Sobrien bfree(); 196259243Sobrien} 196359243Sobrien 196459243Sobrienvoid 196559243Sobriensettell() 196659243Sobrien{ 196759243Sobrien off_t x; 196859243Sobrien cantell = 0; 196959243Sobrien if (arginp || onelflg || intty) 197059243Sobrien return; 197159243Sobrien if ((x = lseek(SHIN, (off_t) 0, L_INCR)) == -1) 197259243Sobrien return; 197359243Sobrien fbuf = (Char **) xcalloc(2, sizeof(Char **)); 197459243Sobrien fblocks = 1; 197559243Sobrien fbuf[0] = (Char *) xcalloc(BUFSIZE, sizeof(Char)); 197659243Sobrien fseekp = fbobp = feobp = x; 197759243Sobrien cantell = 1; 197859243Sobrien} 1979