sh.lex.c revision 316957
1316957Sdchagin/* $Header: /p/tcsh/cvsroot/tcsh/sh.lex.c,v 3.91 2016/08/01 16:21:09 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 35316957SdchaginRCSID("$tcsh: sh.lex.c,v 3.91 2016/08/01 16:21:09 christos Exp $") 3659243Sobrien 3759243Sobrien#include "ed.h" 38145479Smp 39145479Smp#include <assert.h> 4059243Sobrien/* #define DEBUG_INP */ 4159243Sobrien/* #define DEBUG_SEEK */ 4259243Sobrien 4359243Sobrien/* 4459243Sobrien * C shell 4559243Sobrien */ 4659243Sobrien 47167465Smp#define FLAG_G 1 48167465Smp#define FLAG_A 2 4959243Sobrien/* 5059243Sobrien * These lexical routines read input and form lists of words. 5159243Sobrien * There is some involved processing here, because of the complications 5259243Sobrien * of input buffering, and especially because of history substitution. 5359243Sobrien */ 54167465Smpstatic Char *word (int); 55167465Smpstatic eChar getC1 (int); 56167465Smpstatic void getdol (void); 57167465Smpstatic void getexcl (Char); 58167465Smpstatic struct Hist *findev (Char *, int); 59167465Smpstatic void setexclp (Char *); 60167465Smpstatic eChar bgetc (void); 61167465Smpstatic void balloc (int); 62167465Smpstatic void bfree (void); 63167465Smpstatic struct wordent *gethent (Char); 64167465Smpstatic int matchs (const Char *, const Char *); 65167465Smpstatic int getsel (int *, int *, int); 66167465Smpstatic struct wordent *getsub (struct wordent *); 67167465Smpstatic Char *subword (Char *, Char, int *, size_t *); 68167465Smpstatic struct wordent *dosub (Char, struct wordent *, int); 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 */ 10069408Sacheint aret = TCSH_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 */ 109167465Smpstruct Strbuf labuf; /* = Strbuf_INIT; */ 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 */ 118145479Smpstatic int hadhist = 0; 11959243Sobrien 12059243Sobrien/* 12159243Sobrien * Avoid alias expansion recursion via \!# 12259243Sobrien */ 12359243Sobrienint hleft; 12459243Sobrien 125167465Smpstruct Strbuf histline; /* = Strbuf_INIT; last line input */ 12659243Sobrien 127145479Smpint histvalid = 0; /* is histline valid */ 12859243Sobrien 12959243Sobrienstatic Char getCtmp; 13059243Sobrien 131145479Smp#define getC(f) (((getCtmp = peekc) != '\0') ? (peekc = 0, (eChar)getCtmp) : getC1(f)) 13259243Sobrien#define ungetC(c) peekc = (Char) c 13359243Sobrien#define ungetD(c) peekd = (Char) c 13459243Sobrien 13559243Sobrien/* Use Htime to store timestamps picked up from history file for enthist() 13659243Sobrien * if reading saved history (sg) 13759243Sobrien */ 13859243Sobrientime_t Htime = (time_t)0; 139167465Smpstatic time_t a2time_t (Char *); 14059243Sobrien 14159243Sobrien/* 142145479Smp * special parsing rules apply for source -h 143145479Smp */ 144145479Smpextern int enterhist; 145145479Smp 14659243Sobrienint 147167465Smplex(struct wordent *hp) 14859243Sobrien{ 14959243Sobrien struct wordent *wdp; 150145479Smp eChar c; 151145479Smp int parsehtime = enterhist; 15259243Sobrien 15359243Sobrien histvalid = 0; 154167465Smp histline.len = 0; 15559243Sobrien 15659243Sobrien btell(&lineloc); 15759243Sobrien hp->next = hp->prev = hp; 15859243Sobrien hp->word = STRNULL; 15959243Sobrien hadhist = 0; 16059243Sobrien do 16159243Sobrien c = readc(0); 16259243Sobrien while (c == ' ' || c == '\t'); 163145479Smp if (c == (eChar)HISTSUB && intty) 16459243Sobrien /* ^lef^rit from tty is short !:s^lef^rit */ 16559243Sobrien getexcl(c); 16659243Sobrien else 16759243Sobrien unreadc(c); 168167465Smp cleanup_push(hp, lex_cleanup); 16959243Sobrien wdp = hp; 17059243Sobrien /* 17159243Sobrien * The following loop is written so that the links needed by freelex will 17259243Sobrien * be ready and rarin to go even if it is interrupted. 17359243Sobrien */ 17459243Sobrien do { 17559243Sobrien struct wordent *new; 17659243Sobrien 177167465Smp new = xmalloc(sizeof(*new)); 178167465Smp new->word = NULL; 17959243Sobrien new->prev = wdp; 18059243Sobrien new->next = hp; 18159243Sobrien wdp->next = new; 18259243Sobrien hp->prev = new; 18359243Sobrien wdp = new; 184145479Smp wdp->word = word(parsehtime); 185145479Smp parsehtime = 0; 18659243Sobrien } while (wdp->word[0] != '\n'); 187167465Smp cleanup_ignore(hp); 188167465Smp cleanup_until(hp); 189167465Smp Strbuf_terminate(&histline); 190167465Smp if (histline.len != 0 && histline.s[histline.len - 1] == '\n') 191167465Smp histline.s[histline.len - 1] = '\0'; 192167465Smp histvalid = 1; 19359243Sobrien 19459243Sobrien return (hadhist); 19559243Sobrien} 19659243Sobrien 19759243Sobrienstatic time_t 198167465Smpa2time_t(Char *wordx) 19959243Sobrien{ 20059243Sobrien /* Attempt to distinguish timestamps from other possible entries. 20159243Sobrien * Format: "+NNNNNNNNNN" (10 digits, left padded with ascii '0') */ 20259243Sobrien 20359243Sobrien time_t ret; 20459243Sobrien Char *s; 20559243Sobrien int ct; 20659243Sobrien 207145479Smp if (!wordx || *(s = wordx) != '+') 20859243Sobrien return (time_t)0; 20959243Sobrien 210167465Smp for (++s, ret = 0, ct = 0; *s; ++s, ++ct) { 21159243Sobrien if (!isdigit((unsigned char)*s)) 21259243Sobrien return (time_t)0; 21359243Sobrien ret = ret * 10 + (time_t)((unsigned char)*s - '0'); 21459243Sobrien } 21559243Sobrien 21659243Sobrien if (ct != 10) 21759243Sobrien return (time_t)0; 21859243Sobrien 21959243Sobrien return ret; 22059243Sobrien} 22159243Sobrien 22259243Sobrienvoid 223167465Smpprlex(struct wordent *sp0) 22459243Sobrien{ 22559243Sobrien struct wordent *sp = sp0->next; 22659243Sobrien 22759243Sobrien for (;;) { 22859243Sobrien xprintf("%S", sp->word); 22959243Sobrien sp = sp->next; 23059243Sobrien if (sp == sp0) 23159243Sobrien break; 23259243Sobrien if (sp->word[0] != '\n') 23359243Sobrien xputchar(' '); 23459243Sobrien } 23559243Sobrien} 23659243Sobrien 23759243Sobrienvoid 238167465Smpcopylex(struct wordent *hp, struct wordent *fp) 23959243Sobrien{ 24059243Sobrien struct wordent *wdp; 24159243Sobrien 24259243Sobrien wdp = hp; 24359243Sobrien fp = fp->next; 24459243Sobrien do { 24559243Sobrien struct wordent *new; 246167465Smp 247167465Smp new = xmalloc(sizeof(*new)); 248167465Smp new->word = NULL; 24959243Sobrien new->prev = wdp; 25059243Sobrien new->next = hp; 25159243Sobrien wdp->next = new; 25259243Sobrien hp->prev = new; 25359243Sobrien wdp = new; 25459243Sobrien wdp->word = Strsave(fp->word); 25559243Sobrien fp = fp->next; 25659243Sobrien } while (wdp->word[0] != '\n'); 25759243Sobrien} 25859243Sobrien 25959243Sobrienvoid 260316957Sdchagininitlex(struct wordent *vp) 261316957Sdchagin{ 262316957Sdchagin vp->word = STRNULL; 263316957Sdchagin vp->prev = vp; 264316957Sdchagin vp->next = vp; 265316957Sdchagin} 266316957Sdchagin 267316957Sdchaginvoid 268167465Smpfreelex(struct wordent *vp) 26959243Sobrien{ 27059243Sobrien struct wordent *fp; 27159243Sobrien 27259243Sobrien while (vp->next != vp) { 27359243Sobrien fp = vp->next; 27459243Sobrien vp->next = fp->next; 275167465Smp xfree(fp->word); 276167465Smp xfree(fp); 27759243Sobrien } 27859243Sobrien vp->prev = vp; 27959243Sobrien} 28059243Sobrien 281167465Smpvoid 282167465Smplex_cleanup(void *xvp) 283167465Smp{ 284167465Smp struct wordent *vp; 285167465Smp 286167465Smp vp = xvp; 287167465Smp freelex(vp); 288167465Smp} 289167465Smp 29059243Sobrienstatic Char * 291167465Smpword(int parsehtime) 29259243Sobrien{ 293145479Smp eChar c, c1; 294167465Smp struct Strbuf wbuf = Strbuf_INIT; 29559243Sobrien Char hbuf[12]; 29659243Sobrien int h; 297145479Smp int dolflg; 29859243Sobrien 299167465Smp cleanup_push(&wbuf, Strbuf_cleanup); 30059243Sobrienloop: 30159243Sobrien while ((c = getC(DOALL)) == ' ' || c == '\t') 30259243Sobrien continue; 30359243Sobrien if (cmap(c, _META | _ESC)) 30459243Sobrien switch (c) { 30559243Sobrien case '&': 30659243Sobrien case '|': 30759243Sobrien case '<': 30859243Sobrien case '>': 309167465Smp Strbuf_append1(&wbuf, c); 31059243Sobrien c1 = getC(DOALL); 31159243Sobrien if (c1 == c) 312167465Smp Strbuf_append1(&wbuf, c1); 31359243Sobrien else 31459243Sobrien ungetC(c1); 31559243Sobrien goto ret; 31659243Sobrien 31759243Sobrien case '#': 318145479Smp if (intty || (enterhist && !parsehtime)) 31959243Sobrien break; 32059243Sobrien c = 0; 32159243Sobrien h = 0; 32259243Sobrien do { 32359243Sobrien c1 = c; 32459243Sobrien c = getC(0); 325145479Smp if (h < 11 && parsehtime) 32659243Sobrien hbuf[h++] = c; 32759243Sobrien } while (c != '\n'); 328145479Smp if (parsehtime) { 329145479Smp hbuf[11] = '\0'; 330145479Smp Htime = a2time_t(hbuf); 331145479Smp } 33259243Sobrien if (c1 == '\\') 33359243Sobrien goto loop; 33459243Sobrien /*FALLTHROUGH*/ 33559243Sobrien 33659243Sobrien case ';': 33759243Sobrien case '(': 33859243Sobrien case ')': 33959243Sobrien case '\n': 340167465Smp Strbuf_append1(&wbuf, c); 34159243Sobrien goto ret; 34259243Sobrien 34359243Sobrien case '\\': 34459243Sobrien c = getC(0); 34559243Sobrien if (c == '\n') { 34659243Sobrien if (onelflg == 1) 34759243Sobrien onelflg = 2; 34859243Sobrien goto loop; 34959243Sobrien } 350145479Smp if (c != (eChar)HIST) 351167465Smp Strbuf_append1(&wbuf, '\\'); 35259243Sobrien c |= QUOTE; 35359243Sobrien default: 35459243Sobrien break; 35559243Sobrien } 35659243Sobrien c1 = 0; 35759243Sobrien dolflg = DOALL; 35859243Sobrien for (;;) { 35959243Sobrien if (c1) { 36059243Sobrien if (c == c1) { 36159243Sobrien c1 = 0; 36259243Sobrien dolflg = DOALL; 36359243Sobrien } 36459243Sobrien else if (c == '\\') { 36559243Sobrien c = getC(0); 36659243Sobrien/* 36759243Sobrien * PWP: this is dumb, but how all of the other shells work. If \ quotes 36859243Sobrien * a character OUTSIDE of a set of ''s, why shouldn't it quote EVERY 36959243Sobrien * following character INSIDE a set of ''s. 37059243Sobrien * 37159243Sobrien * Actually, all I really want to be able to say is 'foo\'bar' --> foo'bar 37259243Sobrien */ 373145479Smp if (c == (eChar)HIST) 37459243Sobrien c |= QUOTE; 37559243Sobrien else { 37659243Sobrien if (bslash_quote && 37759243Sobrien ((c == '\'') || (c == '"') || 378195609Smp (c == '\\') || (c == '$'))) { 37959243Sobrien c |= QUOTE; 38059243Sobrien } 38159243Sobrien else { 38259243Sobrien if (c == '\n') 38359243Sobrien /* 38459243Sobrien * if (c1 == '`') c = ' '; else 38559243Sobrien */ 38659243Sobrien c |= QUOTE; 38759243Sobrien ungetC(c); 388316957Sdchagin c = '\\' | QUOTE; 38959243Sobrien } 39059243Sobrien } 39159243Sobrien } 39259243Sobrien else if (c == '\n') { 39359243Sobrien seterror(ERR_UNMATCHED, c1); 39459243Sobrien ungetC(c); 39559243Sobrien break; 39659243Sobrien } 39759243Sobrien } 39859243Sobrien else if (cmap(c, _META | _QF | _QB | _ESC)) { 39959243Sobrien if (c == '\\') { 40059243Sobrien c = getC(0); 40159243Sobrien if (c == '\n') { 40259243Sobrien if (onelflg == 1) 40359243Sobrien onelflg = 2; 40459243Sobrien break; 40559243Sobrien } 406145479Smp if (c != (eChar)HIST) 407167465Smp Strbuf_append1(&wbuf, '\\'); 40859243Sobrien c |= QUOTE; 40959243Sobrien } 41059243Sobrien else if (cmap(c, _QF | _QB)) { /* '"` */ 41159243Sobrien c1 = c; 41259243Sobrien dolflg = c == '"' ? DOALL : DOEXCL; 41359243Sobrien } 414145479Smp else if (c != '#' || (!intty && !enterhist)) { 41559243Sobrien ungetC(c); 41659243Sobrien break; 41759243Sobrien } 41859243Sobrien } 419167465Smp Strbuf_append1(&wbuf, c); 420167465Smp c = getC(dolflg); 42159243Sobrien } 42259243Sobrienret: 423167465Smp cleanup_ignore(&wbuf); 424167465Smp cleanup_until(&wbuf); 425167465Smp return Strbuf_finish(&wbuf); 42659243Sobrien} 42759243Sobrien 428145479Smpstatic eChar 429167465SmpgetC1(int flag) 43059243Sobrien{ 431145479Smp eChar c; 43259243Sobrien 43359243Sobrien for (;;) { 43459243Sobrien if ((c = peekc) != 0) { 43559243Sobrien peekc = 0; 43659243Sobrien return (c); 43759243Sobrien } 438167465Smp if (lap < labuf.len) { 439167465Smp c = labuf.s[lap++]; 440167465Smp if (cmap(c, _META | _QF | _QB)) 441167465Smp c |= QUOTE; 442167465Smp return (c); 44359243Sobrien } 44459243Sobrien if ((c = peekd) != 0) { 44559243Sobrien peekd = 0; 44659243Sobrien return (c); 44759243Sobrien } 44859243Sobrien if (exclp) { 44959243Sobrien if ((c = *exclp++) != 0) 45059243Sobrien return (c); 45159243Sobrien if (exclnxt && --exclc >= 0) { 45259243Sobrien exclnxt = exclnxt->next; 45359243Sobrien setexclp(exclnxt->word); 45459243Sobrien return (' '); 45559243Sobrien } 45659243Sobrien exclp = 0; 45759243Sobrien exclnxt = 0; 45859243Sobrien /* this will throw away the dummy history entries */ 45959243Sobrien savehist(NULL, 0); 46059243Sobrien 46159243Sobrien } 46259243Sobrien if (exclnxt) { 46359243Sobrien exclnxt = exclnxt->next; 46459243Sobrien if (--exclc < 0) 46559243Sobrien exclnxt = 0; 46659243Sobrien else 46759243Sobrien setexclp(exclnxt->word); 46859243Sobrien continue; 46959243Sobrien } 470231990Smp c = readc(1); 471231990Smp 472231990Smp /* Catch EOF in the middle of a line. (An EOF at the beginning of 473231990Smp * a line would have been processed by the readc(0) in lex().) */ 474231990Smp if (c == CHAR_ERR) 475231990Smp c = '\n'; 476231990Smp 47759243Sobrien if (c == '$' && (flag & DODOL)) { 47859243Sobrien getdol(); 47959243Sobrien continue; 48059243Sobrien } 481145479Smp if (c == (eChar)HIST && (flag & DOEXCL)) { 48259243Sobrien getexcl(0); 48359243Sobrien continue; 48459243Sobrien } 48559243Sobrien break; 48659243Sobrien } 48759243Sobrien return (c); 48859243Sobrien} 48959243Sobrien 49059243Sobrienstatic void 491167465Smpgetdol(void) 49259243Sobrien{ 493167465Smp struct Strbuf name = Strbuf_INIT; 494145479Smp eChar c; 495145479Smp eChar sc; 496167465Smp int special = 0; 49759243Sobrien 49859243Sobrien c = sc = getC(DOEXCL); 49959243Sobrien if (any("\t \n", c)) { 50059243Sobrien ungetD(c); 50159243Sobrien ungetC('$' | QUOTE); 50259243Sobrien return; 50359243Sobrien } 504167465Smp cleanup_push(&name, Strbuf_cleanup); 505167465Smp Strbuf_append1(&name, '$'); 50659243Sobrien if (c == '{') 507167465Smp Strbuf_append1(&name, c), c = getC(DOEXCL); 50859243Sobrien if (c == '#' || c == '?' || c == '%') 509167465Smp special++, Strbuf_append1(&name, c), c = getC(DOEXCL); 510167465Smp Strbuf_append1(&name, c); 51159243Sobrien switch (c) { 51259243Sobrien 51359243Sobrien case '<': 51459243Sobrien case '$': 51559243Sobrien case '!': 51659243Sobrien if (special) 51759243Sobrien seterror(ERR_SPDOLLT); 518167465Smp goto end; 51959243Sobrien 52059243Sobrien case '\n': 52159243Sobrien ungetD(c); 522167465Smp name.len--; 52359243Sobrien if (!special) 52459243Sobrien seterror(ERR_NEWLINE); 525167465Smp goto end; 52659243Sobrien 52759243Sobrien case '*': 52859243Sobrien if (special) 52959243Sobrien seterror(ERR_SPSTAR); 530167465Smp goto end; 53159243Sobrien 53259243Sobrien default: 53359243Sobrien if (Isdigit(c)) { 53459243Sobrien#ifdef notdef 53559243Sobrien /* let $?0 pass for now */ 53659243Sobrien if (special) { 53759243Sobrien seterror(ERR_DIGIT); 538167465Smp goto end; 53959243Sobrien } 54059243Sobrien#endif 54159243Sobrien while ((c = getC(DOEXCL)) != 0) { 54259243Sobrien if (!Isdigit(c)) 54359243Sobrien break; 544167465Smp Strbuf_append1(&name, c); 54559243Sobrien } 54659243Sobrien } 54759243Sobrien else if (letter(c)) { 54859243Sobrien while ((c = getC(DOEXCL)) != 0) { 54959243Sobrien /* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */ 55059243Sobrien if (!letter(c) && !Isdigit(c)) 55159243Sobrien break; 552167465Smp Strbuf_append1(&name, c); 55359243Sobrien } 55459243Sobrien } 55559243Sobrien else { 55659243Sobrien if (!special) 55759243Sobrien seterror(ERR_VARILL); 55859243Sobrien else { 55959243Sobrien ungetD(c); 560167465Smp name.len--; 56159243Sobrien } 562167465Smp goto end; 56359243Sobrien } 56459243Sobrien break; 56559243Sobrien } 56659243Sobrien if (c == '[') { 567167465Smp Strbuf_append1(&name, c); 56859243Sobrien do { 56959243Sobrien /* 57059243Sobrien * Michael Greim: Allow $ expansion to take place in selector 57159243Sobrien * expressions. (limits the number of characters returned) 57259243Sobrien */ 57359243Sobrien c = getC(DOEXCL | DODOL); 57459243Sobrien if (c == '\n') { 57559243Sobrien ungetD(c); 576167465Smp name.len--; 57759243Sobrien seterror(ERR_NLINDEX); 578167465Smp goto end; 57959243Sobrien } 580167465Smp Strbuf_append1(&name, c); 58159243Sobrien } while (c != ']'); 58259243Sobrien c = getC(DOEXCL); 58359243Sobrien } 58459243Sobrien if (c == ':') { 58559243Sobrien /* 58659243Sobrien * if the :g modifier is followed by a newline, then error right away! 58759243Sobrien * -strike 58859243Sobrien */ 58959243Sobrien 59059243Sobrien int gmodflag = 0, amodflag = 0; 59159243Sobrien 59259243Sobrien do { 593167465Smp Strbuf_append1(&name, c), c = getC(DOEXCL); 59459243Sobrien if (c == 'g' || c == 'a') { 59559243Sobrien if (c == 'g') 59659243Sobrien gmodflag++; 59759243Sobrien else 59859243Sobrien amodflag++; 599167465Smp Strbuf_append1(&name, c); c = getC(DOEXCL); 60059243Sobrien } 60159243Sobrien if ((c == 'g' && !gmodflag) || (c == 'a' && !amodflag)) { 60259243Sobrien if (c == 'g') 60359243Sobrien gmodflag++; 60459243Sobrien else 60559243Sobrien amodflag++; 606167465Smp Strbuf_append1(&name, c); c = getC(DOEXCL); 60759243Sobrien } 608167465Smp Strbuf_append1(&name, c); 60959243Sobrien /* scan s// [eichin:19910926.0512EST] */ 61059243Sobrien if (c == 's') { 61159243Sobrien int delimcnt = 2; 612145479Smp eChar delim = getC(0); 613167465Smp 614167465Smp Strbuf_append1(&name, delim); 61559243Sobrien if (!delim || letter(delim) 61659243Sobrien || Isdigit(delim) || any(" \t\n", delim)) { 61759243Sobrien seterror(ERR_BADSUBST); 61859243Sobrien break; 619167465Smp } 620145479Smp while ((c = getC(0)) != CHAR_ERR) { 621167465Smp Strbuf_append1(&name, c); 62259243Sobrien if(c == delim) delimcnt--; 62359243Sobrien if(!delimcnt) break; 62459243Sobrien } 62559243Sobrien if(delimcnt) { 62659243Sobrien seterror(ERR_BADSUBST); 62759243Sobrien break; 62859243Sobrien } 62959243Sobrien c = 's'; 63059243Sobrien } 63159243Sobrien if (!any("htrqxesul", c)) { 63259243Sobrien if ((amodflag || gmodflag) && c == '\n') 63359243Sobrien stderror(ERR_VARSYN); /* strike */ 63459243Sobrien seterror(ERR_BADMOD, c); 635167465Smp goto end; 63659243Sobrien } 63759243Sobrien } 63859243Sobrien while ((c = getC(DOEXCL)) == ':'); 63959243Sobrien ungetD(c); 64059243Sobrien } 64159243Sobrien else 64259243Sobrien ungetD(c); 64359243Sobrien if (sc == '{') { 64459243Sobrien c = getC(DOEXCL); 64559243Sobrien if (c != '}') { 64659243Sobrien ungetD(c); 64759243Sobrien seterror(ERR_MISSING, '}'); 648167465Smp goto end; 64959243Sobrien } 650167465Smp Strbuf_append1(&name, c); 65159243Sobrien } 652167465Smp end: 653167465Smp cleanup_ignore(&name); 654167465Smp cleanup_until(&name); 655167465Smp addla(Strbuf_finish(&name)); 65659243Sobrien} 65759243Sobrien 658167465Smp/* xfree()'s its argument */ 65959243Sobrienvoid 660167465Smpaddla(Char *cp) 66159243Sobrien{ 662167465Smp static struct Strbuf buf; /* = Strbuf_INIT; */ 66359243Sobrien 664167465Smp buf.len = 0; 665167465Smp Strbuf_appendn(&buf, labuf.s + lap, labuf.len - lap); 666167465Smp labuf.len = 0; 667167465Smp Strbuf_append(&labuf, cp); 668167465Smp Strbuf_terminate(&labuf); 669167465Smp Strbuf_appendn(&labuf, buf.s, buf.len); 670167465Smp xfree(cp); 671167465Smp lap = 0; 67259243Sobrien} 67359243Sobrien 674167465Smp/* left-hand side of last :s or search string of last ?event? */ 675167465Smpstatic struct Strbuf lhsb; /* = Strbuf_INIT; */ 676167465Smpstatic struct Strbuf slhs; /* = Strbuf_INIT; left-hand side of last :s */ 677167465Smpstatic struct Strbuf rhsb; /* = Strbuf_INIT; right-hand side of last :s */ 67859243Sobrienstatic int quesarg; 67959243Sobrien 68059243Sobrienstatic void 681167465Smpgetexcl(Char sc) 68259243Sobrien{ 68359243Sobrien struct wordent *hp, *ip; 68459243Sobrien int left, right, dol; 685145479Smp eChar c; 68659243Sobrien 68759243Sobrien if (sc == 0) { 688231990Smp c = getC(0); 689231990Smp if (c == '{') 690231990Smp sc = (Char) c; 691231990Smp else 692231990Smp ungetC(c); 69359243Sobrien } 69459243Sobrien quesarg = -1; 69559243Sobrien 696167465Smp lastev = eventno; 69759243Sobrien hp = gethent(sc); 69859243Sobrien if (hp == 0) 69959243Sobrien return; 70059243Sobrien hadhist = 1; 70159243Sobrien dol = 0; 70259243Sobrien if (hp == alhistp) 70359243Sobrien for (ip = hp->next->next; ip != alhistt; ip = ip->next) 70459243Sobrien dol++; 70559243Sobrien else 70659243Sobrien for (ip = hp->next->next; ip != hp->prev; ip = ip->next) 70759243Sobrien dol++; 70859243Sobrien left = 0, right = dol; 709231990Smp if (sc == HISTSUB && HISTSUB != '\0') { 71059243Sobrien ungetC('s'), unreadc(HISTSUB), c = ':'; 71159243Sobrien goto subst; 71259243Sobrien } 71359243Sobrien c = getC(0); 71459243Sobrien if (!any(":^$*-%", c)) 71559243Sobrien goto subst; 71659243Sobrien left = right = -1; 71759243Sobrien if (c == ':') { 71859243Sobrien c = getC(0); 71959243Sobrien unreadc(c); 72059243Sobrien if (letter(c) || c == '&') { 72159243Sobrien c = ':'; 72259243Sobrien left = 0, right = dol; 72359243Sobrien goto subst; 72459243Sobrien } 72559243Sobrien } 72659243Sobrien else 72759243Sobrien ungetC(c); 72859243Sobrien if (!getsel(&left, &right, dol)) 72959243Sobrien return; 73059243Sobrien c = getC(0); 73159243Sobrien if (c == '*') 73259243Sobrien ungetC(c), c = '-'; 73359243Sobrien if (c == '-') { 73459243Sobrien if (!getsel(&left, &right, dol)) 73559243Sobrien return; 73659243Sobrien c = getC(0); 73759243Sobrien } 73859243Sobriensubst: 73959243Sobrien exclc = right - left + 1; 74059243Sobrien while (--left >= 0) 74159243Sobrien hp = hp->next; 742231990Smp if ((sc == HISTSUB && HISTSUB != '\0') || c == ':') { 74359243Sobrien do { 74459243Sobrien hp = getsub(hp); 74559243Sobrien c = getC(0); 74659243Sobrien } while (c == ':'); 74759243Sobrien } 74859243Sobrien unreadc(c); 74959243Sobrien if (sc == '{') { 75059243Sobrien c = getC(0); 75159243Sobrien if (c != '}') 75259243Sobrien seterror(ERR_BADBANG); 75359243Sobrien } 75459243Sobrien exclnxt = hp; 75559243Sobrien} 75659243Sobrien 75759243Sobrienstatic struct wordent * 758167465Smpgetsub(struct wordent *en) 75959243Sobrien{ 760145479Smp eChar delim; 761145479Smp eChar c; 762145479Smp eChar sc; 763145479Smp int global; 76459243Sobrien 76559243Sobrien do { 76659243Sobrien exclnxt = 0; 76759243Sobrien global = 0; 76859243Sobrien sc = c = getC(0); 769167465Smp while (c == 'g' || c == 'a') { 770167465Smp global |= (c == 'g') ? FLAG_G : FLAG_A; 77159243Sobrien sc = c = getC(0); 77259243Sobrien } 77359243Sobrien 77459243Sobrien switch (c) { 77559243Sobrien case 'p': 77659243Sobrien justpr++; 77759243Sobrien return (en); 77859243Sobrien 77959243Sobrien case 'x': 78059243Sobrien case 'q': 781167465Smp global |= FLAG_G; 78259243Sobrien /*FALLTHROUGH*/ 78359243Sobrien 78459243Sobrien case 'h': 78559243Sobrien case 'r': 78659243Sobrien case 't': 78759243Sobrien case 'e': 78859243Sobrien case 'u': 78959243Sobrien case 'l': 79059243Sobrien break; 79159243Sobrien 79259243Sobrien case '&': 793167465Smp if (slhs.len == 0) { 79459243Sobrien seterror(ERR_NOSUBST); 79559243Sobrien return (en); 79659243Sobrien } 797167465Smp lhsb.len = 0; 798167465Smp Strbuf_append(&lhsb, slhs.s); 799167465Smp Strbuf_terminate(&lhsb); 80059243Sobrien break; 80159243Sobrien 80259243Sobrien#ifdef notdef 80359243Sobrien case '~': 804167465Smp if (lhsb.len == 0) 80559243Sobrien goto badlhs; 80659243Sobrien break; 80759243Sobrien#endif 80859243Sobrien 80959243Sobrien case 's': 81059243Sobrien delim = getC(0); 81159243Sobrien if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) { 81259243Sobrien unreadc(delim); 813167465Smp lhsb.len = 0; 81459243Sobrien seterror(ERR_BADSUBST); 81559243Sobrien return (en); 81659243Sobrien } 817167465Smp Strbuf_terminate(&lhsb); 818167465Smp lhsb.len = 0; 81959243Sobrien for (;;) { 82059243Sobrien c = getC(0); 82159243Sobrien if (c == '\n') { 82259243Sobrien unreadc(c); 82359243Sobrien break; 82459243Sobrien } 82559243Sobrien if (c == delim) 82659243Sobrien break; 82759243Sobrien if (c == '\\') { 82859243Sobrien c = getC(0); 82959243Sobrien if (c != delim && c != '\\') 830167465Smp Strbuf_append1(&lhsb, '\\'); 83159243Sobrien } 832167465Smp Strbuf_append1(&lhsb, c); 83359243Sobrien } 834167465Smp if (lhsb.len != 0) 835167465Smp Strbuf_terminate(&lhsb); 836167465Smp else if (lhsb.s[0] == 0) { 83759243Sobrien seterror(ERR_LHS); 83859243Sobrien return (en); 839167465Smp } else 840167465Smp lhsb.len = Strlen(lhsb.s); /* lhsb.s wasn't changed */ 841167465Smp rhsb.len = 0; 84259243Sobrien for (;;) { 84359243Sobrien c = getC(0); 84459243Sobrien if (c == '\n') { 84559243Sobrien unreadc(c); 84659243Sobrien break; 84759243Sobrien } 84859243Sobrien if (c == delim) 84959243Sobrien break; 85059243Sobrien if (c == '\\') { 85159243Sobrien c = getC(0); 85259243Sobrien if (c != delim /* && c != '~' */ ) 853167465Smp Strbuf_append1(&rhsb, '\\'); 85459243Sobrien } 855167465Smp Strbuf_append1(&rhsb, c); 85659243Sobrien } 857167465Smp Strbuf_terminate(&rhsb); 85859243Sobrien break; 85959243Sobrien 86059243Sobrien default: 86159243Sobrien if (c == '\n') 86259243Sobrien unreadc(c); 863145479Smp seterror(ERR_BADBANGMOD, (int)c); 86459243Sobrien return (en); 86559243Sobrien } 866167465Smp slhs.len = 0; 867177128Sdelphij if (lhsb.s != NULL && lhsb.len != 0) 868177128Sdelphij Strbuf_append(&slhs, lhsb.s); 869167465Smp Strbuf_terminate(&slhs); 87059243Sobrien if (exclc) 87159243Sobrien en = dosub(sc, en, global); 87259243Sobrien } 87359243Sobrien while ((c = getC(0)) == ':'); 87459243Sobrien unreadc(c); 87559243Sobrien return (en); 87659243Sobrien} 87759243Sobrien 87859243Sobrien/* 87959243Sobrien * 88059243Sobrien * From Beto Appleton (beto@aixwiz.austin.ibm.com) 88159243Sobrien * 88259243Sobrien * when using history substitution, and the variable 88359243Sobrien * 'history' is set to a value higher than 1000, 88459243Sobrien * the shell might either freeze (hang) or core-dump. 88559243Sobrien * We raise the limit to 50000000 88659243Sobrien */ 88759243Sobrien 88859243Sobrien#define HIST_PURGE -50000000 88959243Sobrienstatic struct wordent * 890167465Smpdosub(Char sc, struct wordent *en, int global) 89159243Sobrien{ 89259243Sobrien struct wordent lexi; 893145479Smp int didsub = 0, didone = 0; 89459243Sobrien struct wordent *hp = &lexi; 89559243Sobrien struct wordent *wdp; 89659243Sobrien int i = exclc; 89759243Sobrien struct Hist *hst; 89859243Sobrien 89959243Sobrien wdp = hp; 90059243Sobrien while (--i >= 0) { 901167465Smp struct wordent *new = xcalloc(1, sizeof *wdp); 90259243Sobrien 90359243Sobrien new->word = 0; 90459243Sobrien new->prev = wdp; 90559243Sobrien new->next = hp; 90659243Sobrien wdp->next = new; 90759243Sobrien wdp = new; 90859243Sobrien en = en->next; 90959243Sobrien if (en->word) { 91059243Sobrien Char *tword, *otword; 91159243Sobrien 912167465Smp if ((global & FLAG_G) || didsub == 0) { 913167465Smp size_t pos; 914167465Smp 915167465Smp pos = 0; 916167465Smp tword = subword(en->word, sc, &didone, &pos); 91759243Sobrien if (didone) 91859243Sobrien didsub = 1; 919167465Smp if (global & FLAG_A) { 92059243Sobrien while (didone && tword != STRNULL) { 92159243Sobrien otword = tword; 922167465Smp tword = subword(otword, sc, &didone, &pos); 92359243Sobrien if (Strcmp(tword, otword) == 0) { 924167465Smp xfree(otword); 92559243Sobrien break; 92659243Sobrien } 92759243Sobrien else 928167465Smp xfree(otword); 92959243Sobrien } 93059243Sobrien } 93159243Sobrien } 93259243Sobrien else 93359243Sobrien tword = Strsave(en->word); 93459243Sobrien wdp->word = tword; 93559243Sobrien } 93659243Sobrien } 93759243Sobrien if (didsub == 0) 93859243Sobrien seterror(ERR_MODFAIL); 93959243Sobrien hp->prev = wdp; 94059243Sobrien /* 94159243Sobrien * ANSI mode HP/UX compiler chokes on 94259243Sobrien * return &enthist(HIST_PURGE, &lexi, 0)->Hlex; 94359243Sobrien */ 944231990Smp hst = enthist(HIST_PURGE, &lexi, 0, 0, -1); 94559243Sobrien return &(hst->Hlex); 94659243Sobrien} 94759243Sobrien 948167465Smp/* Return a newly allocated result of one modification of CP using the 949167465Smp operation TYPE. Set ADID to 1 if a modification was performed. 950167465Smp If TYPE == 's', perform substitutions only from *START_POS on and set 951167465Smp *START_POS to the position of next substitution attempt. */ 95259243Sobrienstatic Char * 953167465Smpsubword(Char *cp, Char type, int *adid, size_t *start_pos) 95459243Sobrien{ 955167465Smp Char *wp; 956167465Smp const Char *mp, *np; 95759243Sobrien 95859243Sobrien switch (type) { 95959243Sobrien 96059243Sobrien case 'r': 96159243Sobrien case 'e': 96259243Sobrien case 'h': 96359243Sobrien case 't': 96459243Sobrien case 'q': 96559243Sobrien case 'x': 96659243Sobrien case 'u': 96759243Sobrien case 'l': 96859243Sobrien wp = domod(cp, type); 969167465Smp if (wp == 0) { 970167465Smp *adid = 0; 97159243Sobrien return (Strsave(cp)); 972167465Smp } 97359243Sobrien *adid = 1; 97459243Sobrien return (wp); 97559243Sobrien 97659243Sobrien default: 977167465Smp for (mp = cp + *start_pos; *mp; mp++) { 978167465Smp if (matchs(mp, lhsb.s)) { 979167465Smp struct Strbuf wbuf = Strbuf_INIT; 980167465Smp 981167465Smp Strbuf_appendn(&wbuf, cp, mp - cp); 982167465Smp for (np = rhsb.s; *np; np++) 98359243Sobrien switch (*np) { 98459243Sobrien 98559243Sobrien case '\\': 98659243Sobrien if (np[1] == '&') 98759243Sobrien np++; 98859243Sobrien /* fall into ... */ 98959243Sobrien 99059243Sobrien default: 991167465Smp Strbuf_append1(&wbuf, *np); 99259243Sobrien continue; 99359243Sobrien 99459243Sobrien case '&': 995167465Smp Strbuf_append(&wbuf, lhsb.s); 99659243Sobrien continue; 99759243Sobrien } 998167465Smp *start_pos = wbuf.len; 999167465Smp Strbuf_append(&wbuf, mp + lhsb.len); 100059243Sobrien *adid = 1; 1001167465Smp return Strbuf_finish(&wbuf); 100259243Sobrien } 1003167465Smp } 1004167465Smp *adid = 0; 100559243Sobrien return (Strsave(cp)); 100659243Sobrien } 100759243Sobrien} 100859243Sobrien 100959243SobrienChar * 1010167465Smpdomod(Char *cp, Char type) 101159243Sobrien{ 101259243Sobrien Char *wp, *xp; 101359243Sobrien int c; 101459243Sobrien 101559243Sobrien switch (type) { 101659243Sobrien 101759243Sobrien case 'x': 101859243Sobrien case 'q': 101959243Sobrien wp = Strsave(cp); 102059243Sobrien for (xp = wp; (c = *xp) != 0; xp++) 102159243Sobrien if ((c != ' ' && c != '\t') || type == 'q') 102259243Sobrien *xp |= QUOTE; 102359243Sobrien return (wp); 102459243Sobrien 102559243Sobrien case 'l': 1026145479Smp wp = NLSChangeCase(cp, 1); 1027145479Smp return wp ? wp : Strsave(cp); 102859243Sobrien 102959243Sobrien case 'u': 1030145479Smp wp = NLSChangeCase(cp, 0); 1031145479Smp return wp ? wp : Strsave(cp); 103259243Sobrien 103359243Sobrien case 'h': 103459243Sobrien case 't': 103559243Sobrien if (!any(short2str(cp), '/')) 103659243Sobrien return (type == 't' ? Strsave(cp) : 0); 1037167465Smp wp = Strrchr(cp, '/'); 103859243Sobrien if (type == 'h') 1039167465Smp xp = Strnsave(cp, wp - cp); 104059243Sobrien else 104159243Sobrien xp = Strsave(wp + 1); 104259243Sobrien return (xp); 104359243Sobrien 104459243Sobrien case 'e': 104559243Sobrien case 'r': 104659243Sobrien wp = Strend(cp); 104759243Sobrien for (wp--; wp >= cp && *wp != '/'; wp--) 104859243Sobrien if (*wp == '.') { 104959243Sobrien if (type == 'e') 105059243Sobrien xp = Strsave(wp + 1); 105159243Sobrien else 1052167465Smp xp = Strnsave(cp, wp - cp); 105359243Sobrien return (xp); 105459243Sobrien } 105559243Sobrien return (Strsave(type == 'e' ? STRNULL : cp)); 105659243Sobrien default: 105759243Sobrien break; 105859243Sobrien } 105959243Sobrien return (0); 106059243Sobrien} 106159243Sobrien 106259243Sobrienstatic int 1063167465Smpmatchs(const Char *str, const Char *pat) 106459243Sobrien{ 106559243Sobrien while (*str && *pat && *str == *pat) 106659243Sobrien str++, pat++; 106759243Sobrien return (*pat == 0); 106859243Sobrien} 106959243Sobrien 107059243Sobrienstatic int 1071167465Smpgetsel(int *al, int *ar, int dol) 107259243Sobrien{ 1073145479Smp eChar c = getC(0); 107459243Sobrien int i; 1075145479Smp int first = *al < 0; 107659243Sobrien 107759243Sobrien switch (c) { 107859243Sobrien 107959243Sobrien case '%': 108059243Sobrien if (quesarg == -1) { 108159243Sobrien seterror(ERR_BADBANGARG); 108259243Sobrien return (0); 108359243Sobrien } 108459243Sobrien if (*al < 0) 108559243Sobrien *al = quesarg; 108659243Sobrien *ar = quesarg; 108759243Sobrien break; 108859243Sobrien 108959243Sobrien case '-': 109059243Sobrien if (*al < 0) { 109159243Sobrien *al = 0; 109259243Sobrien *ar = dol - 1; 109359243Sobrien unreadc(c); 109459243Sobrien } 109559243Sobrien return (1); 109659243Sobrien 109759243Sobrien case '^': 109859243Sobrien if (*al < 0) 109959243Sobrien *al = 1; 110059243Sobrien *ar = 1; 110159243Sobrien break; 110259243Sobrien 110359243Sobrien case '$': 110459243Sobrien if (*al < 0) 110559243Sobrien *al = dol; 110659243Sobrien *ar = dol; 110759243Sobrien break; 110859243Sobrien 110959243Sobrien case '*': 111059243Sobrien if (*al < 0) 111159243Sobrien *al = 1; 111259243Sobrien *ar = dol; 111359243Sobrien if (*ar < *al) { 111459243Sobrien *ar = 0; 111559243Sobrien *al = 1; 111659243Sobrien return (1); 111759243Sobrien } 111859243Sobrien break; 111959243Sobrien 112059243Sobrien default: 112159243Sobrien if (Isdigit(c)) { 112259243Sobrien i = 0; 112359243Sobrien while (Isdigit(c)) { 112459243Sobrien i = i * 10 + c - '0'; 112559243Sobrien c = getC(0); 112659243Sobrien } 112759243Sobrien if (i < 0) 112859243Sobrien i = dol + 1; 112959243Sobrien if (*al < 0) 113059243Sobrien *al = i; 113159243Sobrien *ar = i; 113259243Sobrien } 113359243Sobrien else if (*al < 0) 113459243Sobrien *al = 0, *ar = dol; 113559243Sobrien else 113659243Sobrien *ar = dol - 1; 113759243Sobrien unreadc(c); 113859243Sobrien break; 113959243Sobrien } 114059243Sobrien if (first) { 114159243Sobrien c = getC(0); 114259243Sobrien unreadc(c); 114359243Sobrien if (any("-$*", c)) 114459243Sobrien return (1); 114559243Sobrien } 114659243Sobrien if (*al > *ar || *ar > dol) { 114759243Sobrien seterror(ERR_BADBANGARG); 114859243Sobrien return (0); 114959243Sobrien } 115059243Sobrien return (1); 115159243Sobrien 115259243Sobrien} 115359243Sobrien 115459243Sobrienstatic struct wordent * 1155167465Smpgethent(Char sc) 115659243Sobrien{ 115759243Sobrien struct Hist *hp; 115859243Sobrien Char *np; 1159145479Smp eChar c; 116059243Sobrien int event; 1161145479Smp int back = 0; 116259243Sobrien 1163231990Smp c = (sc == HISTSUB && HISTSUB != '\0') ? (eChar)HIST : getC(0); 1164145479Smp if (c == (eChar)HIST) { 116559243Sobrien if (alhistp) 116659243Sobrien return (alhistp); 116759243Sobrien event = eventno; 116859243Sobrien } 116959243Sobrien else 117059243Sobrien switch (c) { 117159243Sobrien 117259243Sobrien case ':': 117359243Sobrien case '^': 117459243Sobrien case '$': 117559243Sobrien case '*': 117659243Sobrien case '%': 117759243Sobrien ungetC(c); 117859243Sobrien if (lastev == eventno && alhistp) 117959243Sobrien return (alhistp); 118059243Sobrien event = lastev; 118159243Sobrien break; 118259243Sobrien 118359243Sobrien case '#': /* !# is command being typed in (mrh) */ 118459243Sobrien if (--hleft == 0) { 118559243Sobrien seterror(ERR_HISTLOOP); 118659243Sobrien return (0); 118759243Sobrien } 118859243Sobrien else 118959243Sobrien return (¶ml); 119059243Sobrien /* NOTREACHED */ 119159243Sobrien 119259243Sobrien case '-': 119359243Sobrien back = 1; 119459243Sobrien c = getC(0); 119559243Sobrien /* FALLSTHROUGH */ 119659243Sobrien 119759243Sobrien default: 119859243Sobrien if (any("(=~", c)) { 119959243Sobrien unreadc(c); 120059243Sobrien ungetC(HIST); 120159243Sobrien return (0); 120259243Sobrien } 1203167465Smp Strbuf_terminate(&lhsb); 1204167465Smp lhsb.len = 0; 120559243Sobrien event = 0; 120659243Sobrien while (!cmap(c, _ESC | _META | _QF | _QB) && !any("^*-%${}:#", c)) { 120759243Sobrien if (event != -1 && Isdigit(c)) 120859243Sobrien event = event * 10 + c - '0'; 120959243Sobrien else 121059243Sobrien event = -1; 1211167465Smp Strbuf_append1(&lhsb, c); 121259243Sobrien c = getC(0); 121359243Sobrien } 121459243Sobrien unreadc(c); 1215167465Smp if (lhsb.len == 0) { 1216167465Smp lhsb.len = Strlen(lhsb.s); /* lhsb.s wasn't changed */ 121759243Sobrien ungetC(HIST); 121859243Sobrien return (0); 121959243Sobrien } 1220167465Smp Strbuf_terminate(&lhsb); 122159243Sobrien if (event != -1) { 122259243Sobrien /* 122359243Sobrien * History had only digits 122459243Sobrien */ 122559243Sobrien if (back) 1226167465Smp event = eventno + (alhistp == 0) - event; 122759243Sobrien break; 122859243Sobrien } 122959243Sobrien if (back) { 1230167465Smp Strbuf_append1(&lhsb, '\0'); /* Allocate space */ 1231167465Smp Strbuf_terminate(&lhsb); 1232167465Smp memmove(lhsb.s + 1, lhsb.s, (lhsb.len - 1) * sizeof (*lhsb.s)); 1233167465Smp lhsb.s[0] = '-'; 123459243Sobrien } 1235167465Smp hp = findev(lhsb.s, 0); 123659243Sobrien if (hp) 123759243Sobrien lastev = hp->Hnum; 123859243Sobrien return (&hp->Hlex); 123959243Sobrien 124059243Sobrien case '?': 1241167465Smp Strbuf_terminate(&lhsb); 1242167465Smp lhsb.len = 0; 124359243Sobrien for (;;) { 124459243Sobrien c = getC(0); 124559243Sobrien if (c == '\n') { 124659243Sobrien unreadc(c); 124759243Sobrien break; 124859243Sobrien } 124959243Sobrien if (c == '?') 125059243Sobrien break; 1251167465Smp Strbuf_append1(&lhsb, c); 125259243Sobrien } 1253167465Smp if (lhsb.len == 0) { 1254167465Smp lhsb.len = Strlen(lhsb.s); /* lhsb.s wasn't changed */ 1255167465Smp if (lhsb.len == 0) { 125659243Sobrien seterror(ERR_NOSEARCH); 125759243Sobrien return (0); 125859243Sobrien } 125959243Sobrien } 126059243Sobrien else 1261167465Smp Strbuf_terminate(&lhsb); 1262167465Smp hp = findev(lhsb.s, 1); 126359243Sobrien if (hp) 126459243Sobrien lastev = hp->Hnum; 126559243Sobrien return (&hp->Hlex); 126659243Sobrien } 126759243Sobrien 126859243Sobrien for (hp = Histlist.Hnext; hp; hp = hp->Hnext) 126959243Sobrien if (hp->Hnum == event) { 127059243Sobrien hp->Href = eventno; 127159243Sobrien lastev = hp->Hnum; 127259243Sobrien return (&hp->Hlex); 127359243Sobrien } 1274231990Smp np = putn((tcsh_number_t)event); 127559243Sobrien seterror(ERR_NOEVENT, short2str(np)); 1276167465Smp xfree(np); 127759243Sobrien return (0); 127859243Sobrien} 127959243Sobrien 128059243Sobrienstatic struct Hist * 1281167465Smpfindev(Char *cp, int anyarg) 128259243Sobrien{ 128359243Sobrien struct Hist *hp; 128459243Sobrien 128559243Sobrien for (hp = Histlist.Hnext; hp; hp = hp->Hnext) { 128659243Sobrien Char *dp; 128759243Sobrien Char *p, *q; 128859243Sobrien struct wordent *lp = hp->Hlex.next; 128959243Sobrien int argno = 0; 129059243Sobrien 129159243Sobrien /* 129259243Sobrien * The entries added by alias substitution don't have a newline but do 129359243Sobrien * have a negative event number. Savehist() trims off these entries, 129459243Sobrien * but it happens before alias expansion, too early to delete those 129559243Sobrien * from the previous command. 129659243Sobrien */ 129759243Sobrien if (hp->Hnum < 0) 129859243Sobrien continue; 129959243Sobrien if (lp->word[0] == '\n') 130059243Sobrien continue; 130159243Sobrien if (!anyarg) { 130259243Sobrien p = cp; 130359243Sobrien q = lp->word; 130459243Sobrien do 130559243Sobrien if (!*p) 130659243Sobrien return (hp); 130759243Sobrien while (*p++ == *q++); 130859243Sobrien continue; 130959243Sobrien } 131059243Sobrien do { 131159243Sobrien for (dp = lp->word; *dp; dp++) { 131259243Sobrien p = cp; 131359243Sobrien q = dp; 131459243Sobrien do 131559243Sobrien if (!*p) { 131659243Sobrien quesarg = argno; 131759243Sobrien return (hp); 131859243Sobrien } 131959243Sobrien while (*p++ == *q++); 132059243Sobrien } 132159243Sobrien lp = lp->next; 132259243Sobrien argno++; 132359243Sobrien } while (lp->word[0] != '\n'); 132459243Sobrien } 132559243Sobrien seterror(ERR_NOEVENT, short2str(cp)); 132659243Sobrien return (0); 132759243Sobrien} 132859243Sobrien 132959243Sobrien 133059243Sobrienstatic void 1331167465Smpsetexclp(Char *cp) 133259243Sobrien{ 133359243Sobrien if (cp && cp[0] == '\n') 133459243Sobrien return; 133559243Sobrien exclp = cp; 133659243Sobrien} 133759243Sobrien 133859243Sobrienvoid 1339167465Smpunreadc(Char c) 134059243Sobrien{ 134159243Sobrien peekread = (Char) c; 134259243Sobrien} 134359243Sobrien 1344145479SmpeChar 1345167465Smpreadc(int wanteof) 134659243Sobrien{ 1347145479Smp eChar c; 134859243Sobrien static int sincereal; /* Number of real EOFs we've seen */ 134959243Sobrien 135059243Sobrien#ifdef DEBUG_INP 135159243Sobrien xprintf("readc\n"); 135259243Sobrien#endif 135359243Sobrien if ((c = peekread) != 0) { 135459243Sobrien peekread = 0; 135559243Sobrien return (c); 135659243Sobrien } 135759243Sobrien 135859243Sobrientop: 135969408Sache aret = TCSH_F_SEEK; 136059243Sobrien if (alvecp) { 136159243Sobrien arun = 1; 136259243Sobrien#ifdef DEBUG_INP 136359243Sobrien xprintf("alvecp %c\n", *alvecp & 0xff); 136459243Sobrien#endif 136569408Sache aret = TCSH_A_SEEK; 136659243Sobrien if ((c = *alvecp++) != 0) 136759243Sobrien return (c); 136859243Sobrien if (alvec && *alvec) { 136959243Sobrien alvecp = *alvec++; 137059243Sobrien return (' '); 137159243Sobrien } 137259243Sobrien else { 137359243Sobrien alvecp = NULL; 137469408Sache aret = TCSH_F_SEEK; 137559243Sobrien return('\n'); 137659243Sobrien } 137759243Sobrien } 137859243Sobrien if (alvec) { 137959243Sobrien arun = 1; 138059243Sobrien if ((alvecp = *alvec) != 0) { 138159243Sobrien alvec++; 138259243Sobrien goto top; 138359243Sobrien } 138459243Sobrien /* Infinite source! */ 138559243Sobrien return ('\n'); 138659243Sobrien } 138759243Sobrien arun = 0; 138859243Sobrien if (evalp) { 138969408Sache aret = TCSH_E_SEEK; 139059243Sobrien if ((c = *evalp++) != 0) 139159243Sobrien return (c); 139259243Sobrien if (evalvec && *evalvec) { 139359243Sobrien evalp = *evalvec++; 139459243Sobrien return (' '); 139559243Sobrien } 139669408Sache aret = TCSH_F_SEEK; 139759243Sobrien evalp = 0; 139859243Sobrien } 139959243Sobrien if (evalvec) { 140059243Sobrien if (evalvec == INVPPTR) { 140159243Sobrien doneinp = 1; 140259243Sobrien reset(); 140359243Sobrien } 140459243Sobrien if ((evalp = *evalvec) != 0) { 140559243Sobrien evalvec++; 140659243Sobrien goto top; 140759243Sobrien } 140859243Sobrien evalvec = INVPPTR; 140959243Sobrien return ('\n'); 141059243Sobrien } 141159243Sobrien do { 141259243Sobrien if (arginp == INVPTR || onelflg == 1) { 141359243Sobrien if (wanteof) 1414145479Smp return CHAR_ERR; 141559243Sobrien exitstat(); 141659243Sobrien } 141759243Sobrien if (arginp) { 141859243Sobrien if ((c = *arginp++) == 0) { 141959243Sobrien arginp = INVPTR; 142059243Sobrien return ('\n'); 142159243Sobrien } 142259243Sobrien return (c); 142359243Sobrien } 142459243Sobrien#ifdef BSDJOBS 142559243Sobrienreread: 142659243Sobrien#endif /* BSDJOBS */ 142759243Sobrien c = bgetc(); 1428145479Smp if (c == CHAR_ERR) { 142969408Sache#ifndef WINNT_NATIVE 143059243Sobrien# ifndef POSIX 143159243Sobrien# ifdef TERMIO 143259243Sobrien struct termio tty; 143359243Sobrien# else /* SGTTYB */ 143459243Sobrien struct sgttyb tty; 143559243Sobrien# endif /* TERMIO */ 143659243Sobrien# else /* POSIX */ 143759243Sobrien struct termios tty; 143859243Sobrien# endif /* POSIX */ 143969408Sache#endif /* !WINNT_NATIVE */ 144059243Sobrien if (wanteof) 1441145479Smp return CHAR_ERR; 144259243Sobrien /* was isatty but raw with ignoreeof yields problems */ 144369408Sache#ifndef WINNT_NATIVE 144459243Sobrien# ifndef POSIX 144559243Sobrien# ifdef TERMIO 144659243Sobrien if (ioctl(SHIN, TCGETA, (ioctl_t) & tty) == 0 && 144759243Sobrien (tty.c_lflag & ICANON)) 144859243Sobrien# else /* GSTTYB */ 144959243Sobrien if (ioctl(SHIN, TIOCGETP, (ioctl_t) & tty) == 0 && 145059243Sobrien (tty.sg_flags & RAW) == 0) 145159243Sobrien# endif /* TERMIO */ 145259243Sobrien# else /* POSIX */ 145359243Sobrien if (tcgetattr(SHIN, &tty) == 0 && 145459243Sobrien (tty.c_lflag & ICANON)) 145559243Sobrien# endif /* POSIX */ 145669408Sache#else /* WINNT_NATIVE */ 145759243Sobrien if (isatty(SHIN)) 145869408Sache#endif /* !WINNT_NATIVE */ 145959243Sobrien { 146059243Sobrien#ifdef BSDJOBS 1461167465Smp pid_t ctpgrp; 146259243Sobrien#endif /* BSDJOBS */ 146359243Sobrien 1464100616Smp if (numeof != 0 && ++sincereal >= numeof) /* Too many EOFs? Bye! */ 146559243Sobrien goto oops; 146659243Sobrien#ifdef BSDJOBS 146759243Sobrien if (tpgrp != -1 && 146859243Sobrien (ctpgrp = tcgetpgrp(FSHTTY)) != -1 && 146959243Sobrien tpgrp != ctpgrp) { 147059243Sobrien (void) tcsetpgrp(FSHTTY, tpgrp); 147159243Sobrien# ifdef _SEQUENT_ 147259243Sobrien if (ctpgrp) 147359243Sobrien# endif /* _SEQUENT */ 1474167465Smp (void) killpg(ctpgrp, SIGHUP); 147559243Sobrien# ifdef notdef 147659243Sobrien /* 147759243Sobrien * With the walking process group fix, this message 147859243Sobrien * is now obsolete. As the foreground process group 147959243Sobrien * changes, the shell needs to adjust. Well too bad. 148059243Sobrien */ 148159243Sobrien xprintf(CGETS(16, 1, "Reset tty pgrp from %d to %d\n"), 1482167465Smp (int)ctpgrp, (int)tpgrp); 148359243Sobrien# endif /* notdef */ 148459243Sobrien goto reread; 148559243Sobrien } 148659243Sobrien#endif /* BSDJOBS */ 148759243Sobrien /* What follows is complicated EOF handling -- sterling@netcom.com */ 148859243Sobrien /* First, we check to see if we have ignoreeof set */ 148959243Sobrien if (adrof(STRignoreeof)) { 149059243Sobrien /* If so, we check for any stopped jobs only on the first EOF */ 149159243Sobrien if ((sincereal == 1) && (chkstop == 0)) { 149259243Sobrien panystop(1); 149359243Sobrien } 149459243Sobrien } else { 149559243Sobrien /* If we don't have ignoreeof set, always check for stopped jobs */ 149659243Sobrien if (chkstop == 0) { 149759243Sobrien panystop(1); 149859243Sobrien } 149959243Sobrien } 150059243Sobrien /* At this point, if there were stopped jobs, we would have already 150159243Sobrien * called reset(). If we got this far, assume we can print an 150259243Sobrien * exit/logout message if we ignoreeof, or just exit. 150359243Sobrien */ 150459243Sobrien if (adrof(STRignoreeof)) { 150559243Sobrien /* If so, tell the user to use exit or logout */ 150659243Sobrien if (loginsh) { 1507195609Smp xprintf("%s", CGETS(16, 2, 150859243Sobrien "\nUse \"logout\" to logout.\n")); 150959243Sobrien } else { 151059243Sobrien xprintf(CGETS(16, 3, 151159243Sobrien "\nUse \"exit\" to leave %s.\n"), 151259243Sobrien progname); 151359243Sobrien } 1514167465Smp reset(); 151559243Sobrien } else { 151659243Sobrien /* If we don't have ignoreeof set, just fall through */ 151759243Sobrien ; /* EMPTY */ 151859243Sobrien } 151959243Sobrien } 152059243Sobrien oops: 152159243Sobrien doneinp = 1; 152259243Sobrien reset(); 152359243Sobrien } 152459243Sobrien sincereal = 0; 152559243Sobrien if (c == '\n' && onelflg) 152659243Sobrien onelflg--; 152759243Sobrien } while (c == 0); 1528167465Smp Strbuf_append1(&histline, c); 152959243Sobrien return (c); 153059243Sobrien} 153159243Sobrien 153259243Sobrienstatic void 1533167465Smpballoc(int buf) 153459243Sobrien{ 153559243Sobrien Char **nfbuf; 153659243Sobrien 153759243Sobrien while (buf >= fblocks) { 1538167465Smp nfbuf = xcalloc(fblocks + 2, sizeof(Char **)); 153959243Sobrien if (fbuf) { 154059243Sobrien (void) blkcpy(nfbuf, fbuf); 1541167465Smp xfree(fbuf); 154259243Sobrien } 154359243Sobrien fbuf = nfbuf; 1544167465Smp fbuf[fblocks] = xcalloc(BUFSIZE, sizeof(Char)); 154559243Sobrien fblocks++; 154659243Sobrien } 154759243Sobrien} 154859243Sobrien 1549316957Sdchaginssize_t 1550167465Smpwide_read(int fildes, Char *buf, size_t nchars, int use_fclens) 1551145479Smp{ 1552145479Smp char cbuf[BUFSIZE + 1]; 1553167465Smp ssize_t res, r = 0; 1554145479Smp size_t partial; 1555167465Smp int err; 1556167465Smp 1557167465Smp if (nchars == 0) 1558167465Smp return 0; 1559167465Smp assert (nchars <= sizeof(cbuf) / sizeof(*cbuf)); 1560145479Smp USE(use_fclens); 1561145479Smp res = 0; 1562145479Smp partial = 0; 1563145479Smp do { 1564145479Smp size_t i; 1565167465Smp size_t len = nchars > partial ? nchars - partial : 1; 1566167465Smp 1567167465Smp if (partial + len >= sizeof(cbuf) / sizeof(*cbuf)) 1568167465Smp break; 1569145479Smp 1570167465Smp r = xread(fildes, cbuf + partial, len); 1571167465Smp 1572145479Smp if (partial == 0 && r <= 0) 1573145479Smp break; 1574145479Smp partial += r; 1575145479Smp i = 0; 1576167465Smp while (i < partial && nchars != 0) { 1577167465Smp int tlen; 1578145479Smp 1579167465Smp tlen = normal_mbtowc(buf + res, cbuf + i, partial - i); 1580167465Smp if (tlen == -1) { 1581145479Smp reset_mbtowc(); 1582167465Smp if ((partial - i) < MB_LEN_MAX && r > 0) 1583145479Smp /* Maybe a partial character and there is still a chance 1584145479Smp to read more */ 1585145479Smp break; 1586145479Smp buf[res] = (unsigned char)cbuf[i] | INVALID_BYTE; 1587145479Smp } 1588167465Smp if (tlen <= 0) 1589167465Smp tlen = 1; 1590145479Smp#ifdef WIDE_STRINGS 1591145479Smp if (use_fclens) 1592167465Smp fclens[res] = tlen; 1593145479Smp#endif 1594167465Smp i += tlen; 1595145479Smp res++; 1596145479Smp nchars--; 1597145479Smp } 1598145479Smp if (i != partial) 1599145479Smp memmove(cbuf, cbuf + i, partial - i); 1600145479Smp partial -= i; 1601167465Smp } while (partial != 0 && nchars > 0); 1602167465Smp /* Throwing away possible partial multibyte characters on error if the 1603167465Smp stream is not seekable */ 1604167465Smp err = errno; 1605167465Smp lseek(fildes, -(off_t)partial, L_INCR); 1606167465Smp errno = err; 1607145479Smp return res != 0 ? res : r; 1608145479Smp} 1609145479Smp 1610145479Smpstatic eChar 1611167465Smpbgetc(void) 161259243Sobrien{ 1613145479Smp Char ch; 161459243Sobrien int c, off, buf; 161559243Sobrien int numleft = 0, roomleft; 161659243Sobrien 161759243Sobrien if (cantell) { 161859243Sobrien if (fseekp < fbobp || fseekp > feobp) { 161959243Sobrien fbobp = feobp = fseekp; 162059243Sobrien (void) lseek(SHIN, fseekp, L_SET); 162159243Sobrien } 162259243Sobrien if (fseekp == feobp) { 1623167465Smp#ifdef WIDE_STRINGS 1624167465Smp off_t bytes; 1625167465Smp size_t i; 1626167465Smp 1627167465Smp bytes = fbobp; 1628167465Smp for (i = 0; i < (size_t)(feobp - fbobp); i++) 1629167465Smp bytes += fclens[i]; 1630167465Smp fseekp = feobp = bytes; 1631167465Smp#endif 163259243Sobrien fbobp = feobp; 1633167465Smp c = wide_read(SHIN, fbuf[0], BUFSIZE, 1); 163459243Sobrien#ifdef convex 163559243Sobrien if (c < 0) 163659243Sobrien stderror(ERR_SYSTEM, progname, strerror(errno)); 163759243Sobrien#endif /* convex */ 163859243Sobrien if (c <= 0) 1639145479Smp return CHAR_ERR; 164059243Sobrien feobp += c; 164159243Sobrien } 1642195609Smp#if !defined(WINNT_NATIVE) && !defined(__CYGWIN__) 1643145479Smp ch = fbuf[0][fseekp - fbobp]; 164459243Sobrien fseekp++; 164559243Sobrien#else 164659243Sobrien do { 1647145479Smp ch = fbuf[0][fseekp - fbobp]; 164859243Sobrien fseekp++; 1649145479Smp } while(ch == '\r'); 1650195609Smp#endif /* !WINNT_NATIVE && !__CYGWIN__ */ 1651145479Smp return (ch); 165259243Sobrien } 165359243Sobrien 165459243Sobrien while (fseekp >= feobp) { 1655100616Smp if ((editing 1656100616Smp#if defined(FILEC) && defined(TIOCSTI) 1657100616Smp || filec 1658100616Smp#endif /* FILEC && TIOCSTI */ 1659100616Smp ) && intty) { /* then use twenex routine */ 166059243Sobrien fseekp = feobp; /* where else? */ 1661100616Smp#if defined(FILEC) && defined(TIOCSTI) 1662100616Smp if (!editing) 1663100616Smp c = numleft = tenex(InputBuf, BUFSIZE); 1664100616Smp else 1665100616Smp#endif /* FILEC && TIOCSTI */ 166659243Sobrien c = numleft = Inputl(); /* PWP: get a line */ 166759243Sobrien while (numleft > 0) { 166859243Sobrien off = (int) feobp % BUFSIZE; 166959243Sobrien buf = (int) feobp / BUFSIZE; 167059243Sobrien balloc(buf); 167159243Sobrien roomleft = BUFSIZE - off; 167259243Sobrien if (roomleft > numleft) 167359243Sobrien roomleft = numleft; 1674167465Smp (void) memcpy(fbuf[buf] + off, InputBuf + c - numleft, 1675167465Smp roomleft * sizeof(Char)); 167659243Sobrien numleft -= roomleft; 167759243Sobrien feobp += roomleft; 167859243Sobrien } 1679100616Smp } else { 168059243Sobrien off = (int) feobp % BUFSIZE; 168159243Sobrien buf = (int) feobp / BUFSIZE; 168259243Sobrien balloc(buf); 168359243Sobrien roomleft = BUFSIZE - off; 1684167465Smp c = wide_read(SHIN, fbuf[buf] + off, roomleft, 0); 1685145479Smp if (c > 0) 168659243Sobrien feobp += c; 168759243Sobrien } 168859243Sobrien if (c == 0 || (c < 0 && fixio(SHIN, errno) == -1)) 1689145479Smp return CHAR_ERR; 169059243Sobrien } 1691145479Smp#ifdef SIG_WINDOW 1692145479Smp if (windowchg) 1693145479Smp (void) check_window_size(0); /* for window systems */ 1694145479Smp#endif /* SIG_WINDOW */ 1695195609Smp#if !defined(WINNT_NATIVE) && !defined(__CYGWIN__) 1696145479Smp ch = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE]; 169759243Sobrien fseekp++; 169859243Sobrien#else 169959243Sobrien do { 1700145479Smp ch = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE]; 170159243Sobrien fseekp++; 1702145479Smp } while(ch == '\r'); 1703195609Smp#endif /* !WINNT_NATIVE && !__CYGWIN__ */ 1704145479Smp return (ch); 170559243Sobrien} 170659243Sobrien 170759243Sobrienstatic void 1708167465Smpbfree(void) 170959243Sobrien{ 171059243Sobrien int sb, i; 171159243Sobrien 171259243Sobrien if (cantell) 171359243Sobrien return; 171459243Sobrien if (whyles) 171559243Sobrien return; 171659243Sobrien sb = (int) (fseekp - 1) / BUFSIZE; 171759243Sobrien if (sb > 0) { 171859243Sobrien for (i = 0; i < sb; i++) 1719167465Smp xfree(fbuf[i]); 172059243Sobrien (void) blkcpy(fbuf, &fbuf[sb]); 172159243Sobrien fseekp -= BUFSIZE * sb; 172259243Sobrien feobp -= BUFSIZE * sb; 172359243Sobrien fblocks -= sb; 172459243Sobrien } 172559243Sobrien} 172659243Sobrien 172759243Sobrienvoid 1728167465Smpbseek(struct Ain *l) 172959243Sobrien{ 173059243Sobrien switch (aret = l->type) { 173169408Sache case TCSH_E_SEEK: 173259243Sobrien evalvec = l->a_seek; 173359243Sobrien evalp = l->c_seek; 173459243Sobrien#ifdef DEBUG_SEEK 173559243Sobrien xprintf(CGETS(16, 4, "seek to eval %x %x\n"), evalvec, evalp); 173659243Sobrien#endif 173759243Sobrien return; 173869408Sache case TCSH_A_SEEK: 173959243Sobrien alvec = l->a_seek; 174059243Sobrien alvecp = l->c_seek; 174159243Sobrien#ifdef DEBUG_SEEK 174259243Sobrien xprintf(CGETS(16, 5, "seek to alias %x %x\n"), alvec, alvecp); 174359243Sobrien#endif 174459243Sobrien return; 174569408Sache case TCSH_F_SEEK: 174659243Sobrien#ifdef DEBUG_SEEK 174759243Sobrien xprintf(CGETS(16, 6, "seek to file %x\n"), fseekp); 174859243Sobrien#endif 174959243Sobrien fseekp = l->f_seek; 1750145479Smp#ifdef WIDE_STRINGS 1751145479Smp if (cantell) { 1752167465Smp if (fseekp >= fbobp && feobp >= fbobp) { 1753145479Smp size_t i; 1754145479Smp off_t o; 1755145479Smp 1756145479Smp o = fbobp; 1757167465Smp for (i = 0; i < (size_t)(feobp - fbobp); i++) { 1758145479Smp if (fseekp == o) { 1759145479Smp fseekp = fbobp + i; 1760145479Smp return; 1761145479Smp } 1762145479Smp o += fclens[i]; 1763145479Smp } 1764145479Smp if (fseekp == o) { 1765145479Smp fseekp = feobp; 1766145479Smp return; 1767145479Smp } 1768145479Smp } 1769145479Smp fbobp = feobp = fseekp + 1; /* To force lseek() */ 1770145479Smp } 1771145479Smp#endif 177259243Sobrien return; 177359243Sobrien default: 177459243Sobrien xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret); 177559243Sobrien abort(); 177659243Sobrien } 177759243Sobrien} 177859243Sobrien 177959243Sobrien/* any similarity to bell telephone is purely accidental */ 178059243Sobrienvoid 1781167465Smpbtell(struct Ain *l) 178259243Sobrien{ 178359243Sobrien switch (l->type = aret) { 178469408Sache case TCSH_E_SEEK: 178559243Sobrien l->a_seek = evalvec; 178659243Sobrien l->c_seek = evalp; 178759243Sobrien#ifdef DEBUG_SEEK 178859243Sobrien xprintf(CGETS(16, 8, "tell eval %x %x\n"), evalvec, evalp); 178959243Sobrien#endif 179059243Sobrien return; 179169408Sache case TCSH_A_SEEK: 179259243Sobrien l->a_seek = alvec; 179359243Sobrien l->c_seek = alvecp; 179459243Sobrien#ifdef DEBUG_SEEK 179559243Sobrien xprintf(CGETS(16, 9, "tell alias %x %x\n"), alvec, alvecp); 179659243Sobrien#endif 179759243Sobrien return; 179869408Sache case TCSH_F_SEEK: 1799145479Smp#ifdef WIDE_STRINGS 1800167465Smp if (cantell && fseekp >= fbobp && fseekp <= feobp) { 1801145479Smp size_t i; 1802167465Smp 1803145479Smp l->f_seek = fbobp; 1804167465Smp for (i = 0; i < (size_t)(fseekp - fbobp); i++) 1805145479Smp l->f_seek += fclens[i]; 1806145479Smp } else 1807145479Smp#endif 1808145479Smp /*SUPPRESS 112*/ 1809145479Smp l->f_seek = fseekp; 181059243Sobrien l->a_seek = NULL; 181159243Sobrien#ifdef DEBUG_SEEK 181259243Sobrien xprintf(CGETS(16, 10, "tell file %x\n"), fseekp); 181359243Sobrien#endif 181459243Sobrien return; 181559243Sobrien default: 181659243Sobrien xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret); 181759243Sobrien abort(); 181859243Sobrien } 181959243Sobrien} 182059243Sobrien 182159243Sobrienvoid 1822167465Smpbtoeof(void) 182359243Sobrien{ 182459243Sobrien (void) lseek(SHIN, (off_t) 0, L_XTND); 182569408Sache aret = TCSH_F_SEEK; 182659243Sobrien fseekp = feobp; 182759243Sobrien alvec = NULL; 182859243Sobrien alvecp = NULL; 182959243Sobrien evalvec = NULL; 183059243Sobrien evalp = NULL; 183159243Sobrien wfree(); 183259243Sobrien bfree(); 183359243Sobrien} 183459243Sobrien 183559243Sobrienvoid 1836167465Smpsettell(void) 183759243Sobrien{ 183859243Sobrien off_t x; 183959243Sobrien cantell = 0; 184059243Sobrien if (arginp || onelflg || intty) 184159243Sobrien return; 184259243Sobrien if ((x = lseek(SHIN, (off_t) 0, L_INCR)) == -1) 184359243Sobrien return; 1844167465Smp fbuf = xcalloc(2, sizeof(Char **)); 184559243Sobrien fblocks = 1; 1846167465Smp fbuf[0] = xcalloc(BUFSIZE, sizeof(Char)); 184759243Sobrien fseekp = fbobp = feobp = x; 184859243Sobrien cantell = 1; 184959243Sobrien} 1850