source: trunk/third/tcsh/sh.lex.c @ 12039

Revision 12039, 36.3 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12038, which included commits to RCS files with non-trunk default branches.
Line 
1/* $Header: /afs/dev.mit.edu/source/repository/third/tcsh/sh.lex.c,v 1.1.1.2 1998-10-03 21:10:04 danw Exp $ */
2/*
3 * sh.lex.c: Lexical analysis into tokens
4 */
5/*-
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *      This product includes software developed by the University of
20 *      California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37#include "sh.h"
38
39RCSID("$Id: sh.lex.c,v 1.1.1.2 1998-10-03 21:10:04 danw Exp $")
40
41#include "ed.h"
42/* #define DEBUG_INP */
43/* #define DEBUG_SEEK */
44
45/*
46 * C shell
47 */
48
49/*
50 * These lexical routines read input and form lists of words.
51 * There is some involved processing here, because of the complications
52 * of input buffering, and especially because of history substitution.
53 */
54static  Char            *word           __P((void));
55static  int              getC1          __P((int));
56static  void             getdol         __P((void));
57static  void             getexcl        __P((int));
58static  struct Hist     *findev         __P((Char *, bool));
59static  void             setexclp       __P((Char *));
60static  int              bgetc          __P((void));
61static  void             balloc         __P((int));
62static  void             bfree          __P((void));
63static  struct wordent  *gethent        __P((int));
64static  int              matchs         __P((Char *, Char *));
65static  int              getsel         __P((int *, int *, int));
66static  struct wordent  *getsub         __P((struct wordent *));
67static  Char            *subword        __P((Char *, int, bool *));
68static  struct wordent  *dosub          __P((int, struct wordent *, bool));
69
70/*
71 * Peekc is a peek character for getC, peekread for readc.
72 * There is a subtlety here in many places... history routines
73 * will read ahead and then insert stuff into the input stream.
74 * If they push back a character then they must push it behind
75 * the text substituted by the history substitution.  On the other
76 * hand in several places we need 2 peek characters.  To make this
77 * all work, the history routines read with getC, and make use both
78 * of ungetC and unreadc.  The key observation is that the state
79 * of getC at the call of a history reference is such that calls
80 * to getC from the history routines will always yield calls of
81 * readc, unless this peeking is involved.  That is to say that during
82 * getexcl the variables lap, exclp, and exclnxt are all zero.
83 *
84 * Getdol invokes history substitution, hence the extra peek, peekd,
85 * which it can ungetD to be before history substitutions.
86 */
87static Char peekc = 0, peekd = 0;
88static Char peekread = 0;
89
90/* (Tail of) current word from ! subst */
91static Char *exclp = NULL;
92
93/* The rest of the ! subst words */
94static struct wordent *exclnxt = NULL;
95
96/* Count of remaining words in ! subst */
97static int exclc = 0;
98
99/* "Globp" for alias resubstitution */
100int aret = F_SEEK;
101
102/*
103 * Labuf implements a general buffer for lookahead during lexical operations.
104 * Text which is to be placed in the input stream can be stuck here.
105 * We stick parsed ahead $ constructs during initial input,
106 * process id's from `$$', and modified variable values (from qualifiers
107 * during expansion in sh.dol.c) here.
108 */
109static Char labuf[BUFSIZE];
110
111/*
112 * Lex returns to its caller not only a wordlist (as a "var" parameter)
113 * but also whether a history substitution occurred.  This is used in
114 * the main (process) routine to determine whether to echo, and also
115 * when called by the alias routine to determine whether to keep the
116 * argument list.
117 */
118static bool hadhist = 0;
119
120/*
121 * Avoid alias expansion recursion via \!#
122 */
123int     hleft;
124
125Char    histline[BUFSIZE + 2];  /* last line input */
126
127 /* The +2 is to fool hp's optimizer */
128bool    histvalid = 0;          /* is histline valid */
129static Char *histlinep = NULL;  /* current pointer into histline */
130
131static Char getCtmp;
132
133#define getC(f)         (((getCtmp = peekc) != '\0') ? (peekc = 0, getCtmp) : getC1(f))
134#define ungetC(c)       peekc = (Char) c
135#define ungetD(c)       peekd = (Char) c
136
137/* Use Htime to store timestamps picked up from history file for enthist()
138 * if reading saved history (sg)
139 */
140time_t Htime = (time_t)0;
141static time_t a2time_t __P((Char *));
142
143/*
144 * for history event processing
145 * in the command 'echo !?foo?:1 !$' we want the !$ to expand from the line
146 * 'foo' was found instead of the last command
147 */
148static int uselastevent = 1;
149
150int
151lex(hp)
152    struct wordent *hp;
153{
154    struct wordent *wdp;
155    int     c;
156
157
158    uselastevent = 1;
159    histvalid = 0;
160    histlinep = histline;
161    *histlinep = '\0';
162
163    btell(&lineloc);
164    hp->next = hp->prev = hp;
165    hp->word = STRNULL;
166    hadhist = 0;
167    do
168        c = readc(0);
169    while (c == ' ' || c == '\t');
170    if (c == HISTSUB && intty)
171        /* ^lef^rit     from tty is short !:s^lef^rit */
172        getexcl(c);
173    else
174        unreadc(c);
175    wdp = hp;
176    /*
177     * The following loop is written so that the links needed by freelex will
178     * be ready and rarin to go even if it is interrupted.
179     */
180    do {
181        struct wordent *new;
182
183        new = (struct wordent *) xmalloc((size_t) sizeof(*wdp));
184        new->word = STRNULL;
185        new->prev = wdp;
186        new->next = hp;
187        wdp->next = new;
188        hp->prev = new;
189        wdp = new;
190        wdp->word = word();
191    } while (wdp->word[0] != '\n');
192    if (histlinep < histline + BUFSIZE) {
193        *histlinep = '\0';
194        if (histlinep > histline && histlinep[-1] == '\n')
195            histlinep[-1] = '\0';
196        histvalid = 1;
197    }
198    else {
199        histline[BUFSIZE - 1] = '\0';
200    }
201
202    return (hadhist);
203}
204
205static time_t
206a2time_t(word)
207    Char *word;
208{
209    /* Attempt to distinguish timestamps from other possible entries.
210     * Format: "+NNNNNNNNNN" (10 digits, left padded with ascii '0') */
211
212    time_t ret;
213    Char *s;
214    int ct;
215
216    if (!word || *(s = word) != '+')
217        return (time_t)0;
218
219    for (++s, ret = 0, ct = 0; *s; ++s, ++ct)
220    {
221        if (!isdigit((unsigned char)*s))
222            return (time_t)0;
223        ret = ret * 10 + (time_t)((unsigned char)*s - '0');
224    }
225
226    if (ct != 10)
227        return (time_t)0;
228
229    return ret;
230}
231
232void
233prlex(sp0)
234    struct wordent *sp0;
235{
236    struct wordent *sp = sp0->next;
237
238    for (;;) {
239        xprintf("%S", sp->word);
240        sp = sp->next;
241        if (sp == sp0)
242            break;
243        if (sp->word[0] != '\n')
244            xputchar(' ');
245    }
246}
247
248void
249copylex(hp, fp)
250    struct wordent *hp;
251    struct wordent *fp;
252{
253    struct wordent *wdp;
254
255    wdp = hp;
256    fp = fp->next;
257    do {
258        struct wordent *new;
259       
260        new = (struct wordent *) xmalloc((size_t) sizeof(*wdp));
261        new->word = STRNULL;
262        new->prev = wdp;
263        new->next = hp;
264        wdp->next = new;
265        hp->prev = new;
266        wdp = new;
267        wdp->word = Strsave(fp->word);
268        fp = fp->next;
269    } while (wdp->word[0] != '\n');
270}
271
272void
273freelex(vp)
274    struct wordent *vp;
275{
276    struct wordent *fp;
277
278    while (vp->next != vp) {
279        fp = vp->next;
280        vp->next = fp->next;
281        if (fp->word != STRNULL)
282            xfree((ptr_t) fp->word);
283        xfree((ptr_t) fp);
284    }
285    vp->prev = vp;
286}
287
288static Char *
289word()
290{
291    Char c, c1;
292    Char *wp;
293    Char    wbuf[BUFSIZE];
294    Char    hbuf[12];
295    int     h;
296    bool dolflg;
297    int i;
298
299    wp = wbuf;
300    i = BUFSIZE - 4;
301loop:
302    while ((c = getC(DOALL)) == ' ' || c == '\t')
303        continue;
304    if (cmap(c, _META | _ESC))
305        switch (c) {
306        case '&':
307        case '|':
308        case '<':
309        case '>':
310            *wp++ = c;
311            c1 = getC(DOALL);
312            if (c1 == c)
313                *wp++ = c1;
314            else
315                ungetC(c1);
316            goto ret;
317
318        case '#':
319            if (intty)
320                break;
321            c = 0;
322            h = 0;
323            do {
324                c1 = c;
325                c = getC(0);
326                if (h < 12)
327                    hbuf[h++] = c;
328            } while (c != '\n');
329            hbuf[11] = '\0';
330            Htime = a2time_t(hbuf);
331            if (c1 == '\\')
332                goto loop;
333            /*FALLTHROUGH*/
334
335        case ';':
336        case '(':
337        case ')':
338        case '\n':
339            *wp++ = c;
340            goto ret;
341
342        case '\\':
343            c = getC(0);
344            if (c == '\n') {
345                if (onelflg == 1)
346                    onelflg = 2;
347                goto loop;
348            }
349            if (c != HIST)
350                *wp++ = '\\', --i;
351            c |= QUOTE;
352        default:
353            break;
354        }
355    c1 = 0;
356    dolflg = DOALL;
357    for (;;) {
358        if (c1) {
359            if (c == c1) {
360                c1 = 0;
361                dolflg = DOALL;
362            }
363            else if (c == '\\') {
364                c = getC(0);
365/*
366 * PWP: this is dumb, but how all of the other shells work.  If \ quotes
367 * a character OUTSIDE of a set of ''s, why shouldn't it quote EVERY
368 * following character INSIDE a set of ''s.
369 *
370 * Actually, all I really want to be able to say is 'foo\'bar' --> foo'bar
371 */
372                if (c == HIST)
373                    c |= QUOTE;
374                else {
375                    if (bslash_quote &&
376                        ((c == '\'') || (c == '"') ||
377                         (c == '\\'))) {
378                        c |= QUOTE;
379                    }
380                    else {
381                        if (c == '\n')
382                            /*
383                             * if (c1 == '`') c = ' '; else
384                             */
385                            c |= QUOTE;
386                        ungetC(c);
387                        c = '\\';
388                    }
389                }
390            }
391            else if (c == '\n') {
392                seterror(ERR_UNMATCHED, c1);
393                ungetC(c);
394                break;
395            }
396        }
397        else if (cmap(c, _META | _QF | _QB | _ESC)) {
398            if (c == '\\') {
399                c = getC(0);
400                if (c == '\n') {
401                    if (onelflg == 1)
402                        onelflg = 2;
403                    break;
404                }
405                if (c != HIST)
406                    *wp++ = '\\', --i;
407                c |= QUOTE;
408            }
409            else if (cmap(c, _QF | _QB)) {      /* '"` */
410                c1 = c;
411                dolflg = c == '"' ? DOALL : DOEXCL;
412            }
413            else if (c != '#' || !intty) {
414                ungetC(c);
415                break;
416            }
417        }
418        if (--i > 0) {
419            *wp++ = c;
420            c = getC(dolflg);
421        }
422        else {
423            seterror(ERR_WTOOLONG);
424            wp = &wbuf[1];
425            break;
426        }
427    }
428ret:
429    *wp = 0;
430    return (Strsave(wbuf));
431}
432
433static int
434getC1(flag)
435    int flag;
436{
437    Char c;
438
439    for (;;) {
440        if ((c = peekc) != 0) {
441            peekc = 0;
442            return (c);
443        }
444        if (lap) {
445            if ((c = *lap++) == 0)
446                lap = 0;
447            else {
448                if (cmap(c, _META | _QF | _QB))
449                    c |= QUOTE;
450                return (c);
451            }
452        }
453        if ((c = peekd) != 0) {
454            peekd = 0;
455            return (c);
456        }
457        if (exclp) {
458            if ((c = *exclp++) != 0)
459                return (c);
460            if (exclnxt && --exclc >= 0) {
461                exclnxt = exclnxt->next;
462                setexclp(exclnxt->word);
463                return (' ');
464            }
465            exclp = 0;
466            exclnxt = 0;
467            /* this will throw away the dummy history entries */
468            savehist(NULL, 0);
469
470        }
471        if (exclnxt) {
472            exclnxt = exclnxt->next;
473            if (--exclc < 0)
474                exclnxt = 0;
475            else
476                setexclp(exclnxt->word);
477            continue;
478        }
479        c = readc(0);
480        if (c == '$' && (flag & DODOL)) {
481            getdol();
482            continue;
483        }
484        if (c == HIST && (flag & DOEXCL)) {
485            getexcl(0);
486            continue;
487        }
488        break;
489    }
490    return (c);
491}
492
493static void
494getdol()
495{
496    Char *np, *ep;
497    Char    name[4 * MAXVARLEN + 1];
498    int c;
499    int     sc;
500    bool    special = 0, toolong;
501
502    np = name, *np++ = '$';
503    c = sc = getC(DOEXCL);
504    if (any("\t \n", c)) {
505        ungetD(c);
506        ungetC('$' | QUOTE);
507        return;
508    }
509    if (c == '{')
510        *np++ = (Char) c, c = getC(DOEXCL);
511    if (c == '#' || c == '?' || c == '%')
512        special++, *np++ = (Char) c, c = getC(DOEXCL);
513    *np++ = (Char) c;
514    switch (c) {
515
516    case '<':
517    case '$':
518    case '!':
519        if (special)
520            seterror(ERR_SPDOLLT);
521        *np = 0;
522        addla(name);
523        return;
524
525    case '\n':
526        ungetD(c);
527        np--;
528        if (!special)
529            seterror(ERR_NEWLINE);
530        *np = 0;
531        addla(name);
532        return;
533
534    case '*':
535        if (special)
536            seterror(ERR_SPSTAR);
537        *np = 0;
538        addla(name);
539        return;
540
541    default:
542        toolong = 0;
543        if (Isdigit(c)) {
544#ifdef notdef
545            /* let $?0 pass for now */
546            if (special) {
547                seterror(ERR_DIGIT);
548                *np = 0;
549                addla(name);
550                return;
551            }
552#endif
553            /* we know that np < &name[4] */
554            ep = &np[MAXVARLEN];
555            while ((c = getC(DOEXCL)) != 0) {
556                if (!Isdigit(c))
557                    break;
558                if (np < ep)
559                    *np++ = (Char) c;
560                else
561                    toolong = 1;
562            }
563        }
564        else if (letter(c)) {
565            /* we know that np < &name[4] */
566            ep = &np[MAXVARLEN];
567            toolong = 0;
568            while ((c = getC(DOEXCL)) != 0) {
569                /* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */
570                if (!letter(c) && !Isdigit(c))
571                    break;
572                if (np < ep)
573                    *np++ = (Char) c;
574                else
575                    toolong = 1;
576            }
577        }
578        else {
579            if (!special)
580                seterror(ERR_VARILL);
581            else {
582                ungetD(c);
583                --np;
584            }
585            *np = 0;
586            addla(name);
587            return;
588        }
589        if (toolong) {
590            seterror(ERR_VARTOOLONG);
591            *np = 0;
592            addla(name);
593            return;
594        }
595        break;
596    }
597    if (c == '[') {
598        *np++ = (Char) c;
599        /*
600         * Name up to here is a max of MAXVARLEN + 8.
601         */
602        ep = &np[2 * MAXVARLEN + 8];
603        do {
604            /*
605             * Michael Greim: Allow $ expansion to take place in selector
606             * expressions. (limits the number of characters returned)
607             */
608            c = getC(DOEXCL | DODOL);
609            if (c == '\n') {
610                ungetD(c);
611                np--;
612                seterror(ERR_NLINDEX);
613                *np = 0;
614                addla(name);
615                return;
616            }
617            if (np < ep)
618                *np++ = (Char) c;
619        } while (c != ']');
620        *np = '\0';
621        if (np >= ep) {
622            seterror(ERR_SELOVFL);
623            addla(name);
624            return;
625        }
626        c = getC(DOEXCL);
627    }
628    /*
629     * Name up to here is a max of 2 * MAXVARLEN + 8.
630     */
631    if (c == ':') {
632        /*
633         * if the :g modifier is followed by a newline, then error right away!
634         * -strike
635         */
636
637        int     gmodflag = 0, amodflag = 0;
638
639#ifndef COMPAT
640        do {
641#endif /* COMPAT */
642            *np++ = (Char) c, c = getC(DOEXCL);
643            if (c == 'g' || c == 'a') {
644                if (c == 'g')
645                    gmodflag++;
646                else
647                    amodflag++;
648                *np++ = (Char) c; c = getC(DOEXCL);
649            }
650            if ((c == 'g' && !gmodflag) || (c == 'a' && !amodflag)) {
651                if (c == 'g')
652                    gmodflag++;
653                else
654                    amodflag++;
655                *np++ = (Char) c; c = getC(DOEXCL);
656            }
657            *np++ = (Char) c;
658            /* scan s// [eichin:19910926.0512EST] */
659            if (c == 's') {
660                int delimcnt = 2;
661                int delim = getC(0);
662                *np++ = (Char) delim;
663               
664                if (!delim || letter(delim)
665                    || Isdigit(delim) || any(" \t\n", delim)) {
666                    seterror(ERR_BADSUBST);
667                    break;
668                }       
669                while ((c = getC(0)) != (-1)) {
670                    *np++ = (Char) c;
671                    if(c == delim) delimcnt--;
672                    if(!delimcnt) break;
673                }
674                if(delimcnt) {
675                    seterror(ERR_BADSUBST);
676                    break;
677                }
678                c = 's';
679            }
680            if (!any("htrqxesul", c)) {
681                if ((amodflag || gmodflag) && c == '\n')
682                    stderror(ERR_VARSYN);       /* strike */
683                seterror(ERR_BADMOD, c);
684                *np = 0;
685                addla(name);
686                return;
687            }
688#ifndef COMPAT
689        }
690        while ((c = getC(DOEXCL)) == ':');
691        ungetD(c);
692#endif /* COMPAT */
693    }
694    else
695        ungetD(c);
696    if (sc == '{') {
697        c = getC(DOEXCL);
698        if (c != '}') {
699            ungetD(c);
700            seterror(ERR_MISSING, '}');
701            *np = 0;
702            addla(name);
703            return;
704        }
705        *np++ = (Char) c;
706    }
707    *np = 0;
708    addla(name);
709    return;
710}
711
712void
713addla(cp)
714    Char   *cp;
715{
716    Char    buf[BUFSIZE];
717
718    if (Strlen(cp) + (lap ? Strlen(lap) : 0) >=
719        (sizeof(labuf) - 4) / sizeof(Char)) {
720        seterror(ERR_EXPOVFL);
721        return;
722    }
723    if (lap)
724        (void) Strcpy(buf, lap);
725    (void) Strcpy(labuf, cp);
726    if (lap)
727        (void) Strcat(labuf, buf);
728    lap = labuf;
729}
730
731static Char lhsb[32];
732static Char slhs[32];
733static Char rhsb[64];
734static int quesarg;
735
736static void
737getexcl(sc)
738    int    sc;
739{
740    struct wordent *hp, *ip;
741    int     left, right, dol;
742    int c;
743
744    if (sc == 0) {
745        sc = getC(0);
746        if (sc != '{') {
747            ungetC(sc);
748            sc = 0;
749        }
750    }
751    quesarg = -1;
752
753    if (uselastevent) {
754        uselastevent = 0;
755        lastev = eventno;
756    }
757    else
758        lastev = eventno;
759    hp = gethent(sc);
760    if (hp == 0)
761        return;
762    hadhist = 1;
763    dol = 0;
764    if (hp == alhistp)
765        for (ip = hp->next->next; ip != alhistt; ip = ip->next)
766            dol++;
767    else
768        for (ip = hp->next->next; ip != hp->prev; ip = ip->next)
769            dol++;
770    left = 0, right = dol;
771    if (sc == HISTSUB) {
772        ungetC('s'), unreadc(HISTSUB), c = ':';
773        goto subst;
774    }
775    c = getC(0);
776    if (!any(":^$*-%", c))
777        goto subst;
778    left = right = -1;
779    if (c == ':') {
780        c = getC(0);
781        unreadc(c);
782        if (letter(c) || c == '&') {
783            c = ':';
784            left = 0, right = dol;
785            goto subst;
786        }
787    }
788    else
789        ungetC(c);
790    if (!getsel(&left, &right, dol))
791        return;
792    c = getC(0);
793    if (c == '*')
794        ungetC(c), c = '-';
795    if (c == '-') {
796        if (!getsel(&left, &right, dol))
797            return;
798        c = getC(0);
799    }
800subst:
801    exclc = right - left + 1;
802    while (--left >= 0)
803        hp = hp->next;
804    if (sc == HISTSUB || c == ':') {
805        do {
806            hp = getsub(hp);
807            c = getC(0);
808        } while (c == ':');
809    }
810    unreadc(c);
811    if (sc == '{') {
812        c = getC(0);
813        if (c != '}')
814            seterror(ERR_BADBANG);
815    }
816    exclnxt = hp;
817}
818
819static struct wordent *
820getsub(en)
821    struct wordent *en;
822{
823    Char *cp;
824    int     delim;
825    int c;
826    int     sc;
827    bool global;
828    Char    orhsb[sizeof(rhsb) / sizeof(Char)];
829
830#ifndef COMPAT
831    do {
832#endif /* COMPAT */
833        exclnxt = 0;
834        global = 0;
835        sc = c = getC(0);
836        if (c == 'g' || c == 'a') {
837            global |= (c == 'g') ? 1 : 2;
838            sc = c = getC(0);
839        }
840        if (((c =='g') && !(global & 1)) || ((c == 'a') && !(global & 2))) {
841            global |= (c == 'g') ? 1 : 2;
842            sc = c = getC(0);
843        }
844
845        switch (c) {
846        case 'p':
847            justpr++;
848            return (en);
849
850        case 'x':
851        case 'q':
852            global |= 1;
853            /*FALLTHROUGH*/
854
855        case 'h':
856        case 'r':
857        case 't':
858        case 'e':
859        case 'u':
860        case 'l':
861            break;
862
863        case '&':
864            if (slhs[0] == 0) {
865                seterror(ERR_NOSUBST);
866                return (en);
867            }
868            (void) Strcpy(lhsb, slhs);
869            break;
870
871#ifdef notdef
872        case '~':
873            if (lhsb[0] == 0)
874                goto badlhs;
875            break;
876#endif
877
878        case 's':
879            delim = getC(0);
880            if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) {
881                unreadc(delim);
882                lhsb[0] = 0;
883                seterror(ERR_BADSUBST);
884                return (en);
885            }
886            cp = lhsb;
887            for (;;) {
888                c = getC(0);
889                if (c == '\n') {
890                    unreadc(c);
891                    break;
892                }
893                if (c == delim)
894                    break;
895                if (cp > &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) {
896                    lhsb[0] = 0;
897                    seterror(ERR_BADSUBST);
898                    return (en);
899                }
900                if (c == '\\') {
901                    c = getC(0);
902                    if (c != delim && c != '\\')
903                        *cp++ = '\\';
904                }
905                *cp++ = (Char) c;
906            }
907            if (cp != lhsb)
908                *cp++ = 0;
909            else if (lhsb[0] == 0) {
910                seterror(ERR_LHS);
911                return (en);
912            }
913            cp = rhsb;
914            (void) Strcpy(orhsb, cp);
915            for (;;) {
916                c = getC(0);
917                if (c == '\n') {
918                    unreadc(c);
919                    break;
920                }
921                if (c == delim)
922                    break;
923#ifdef notdef
924                if (c == '~') {
925                    if (&cp[Strlen(orhsb)] > &rhsb[sizeof(rhsb) /
926                                                   sizeof(Char) - 2])
927                        goto toorhs;
928                    (void) Strcpy(cp, orhsb);
929                    cp = Strend(cp);
930                    continue;
931                }
932#endif
933                if (cp > &rhsb[sizeof(rhsb) / sizeof(Char) - 2]) {
934                    seterror(ERR_RHSLONG);
935                    return (en);
936                }
937                if (c == '\\') {
938                    c = getC(0);
939                    if (c != delim /* && c != '~' */ )
940                        *cp++ = '\\';
941                }
942                *cp++ = (Char) c;
943            }
944            *cp++ = 0;
945            break;
946
947        default:
948            if (c == '\n')
949                unreadc(c);
950            seterror(ERR_BADBANGMOD, c);
951            return (en);
952        }
953        (void) Strcpy(slhs, lhsb);
954        if (exclc)
955            en = dosub(sc, en, global);
956#ifndef COMPAT
957    }
958    while ((c = getC(0)) == ':');
959    unreadc(c);
960#endif /* COMPAT */
961    return (en);
962}
963
964/*
965 *
966 * From Beto Appleton (beto@aixwiz.austin.ibm.com)
967 *
968 * when using history substitution, and the variable
969 * 'history' is set to a value higher than 1000,
970 * the shell might either freeze (hang) or core-dump.
971 * We raise the limit to 50000000
972 */
973
974#define HIST_PURGE -50000000
975static struct wordent *
976dosub(sc, en, global)
977    int     sc;
978    struct wordent *en;
979    bool global;
980{
981    struct wordent lexi;
982    bool    didsub = 0, didone = 0;
983    struct wordent *hp = &lexi;
984    struct wordent *wdp;
985    int i = exclc;
986    struct Hist *hst;
987
988    wdp = hp;
989    while (--i >= 0) {
990        struct wordent *new =
991                (struct wordent *) xcalloc(1, sizeof *wdp);
992
993        new->word = 0;
994        new->prev = wdp;
995        new->next = hp;
996        wdp->next = new;
997        wdp = new;
998        en = en->next;
999        if (en->word) {
1000            Char *tword, *otword;
1001
1002            if ((global & 1) || didsub == 0) {
1003                tword = subword(en->word, sc, &didone);
1004                if (didone)
1005                    didsub = 1;
1006                if (global & 2) {
1007                    while (didone && tword != STRNULL) {
1008                        otword = tword;
1009                        tword = subword(otword, sc, &didone);
1010                        if (Strcmp(tword, otword) == 0) {
1011                            xfree((ptr_t) otword);
1012                            break;
1013                        }
1014                        else
1015                            xfree((ptr_t) otword);
1016                    }
1017                }
1018            }
1019            else
1020                tword = Strsave(en->word);
1021            wdp->word = tword;
1022        }
1023    }
1024    if (didsub == 0)
1025        seterror(ERR_MODFAIL);
1026    hp->prev = wdp;
1027    /*
1028     * ANSI mode HP/UX compiler chokes on
1029     * return &enthist(HIST_PURGE, &lexi, 0)->Hlex;
1030     */
1031    hst = enthist(HIST_PURGE, &lexi, 0, 0);
1032    return &(hst->Hlex);
1033}
1034
1035static Char *
1036subword(cp, type, adid)
1037    Char   *cp;
1038    int     type;
1039    bool   *adid;
1040{
1041    Char    wbuf[BUFSIZE];
1042    Char *wp, *mp, *np;
1043    int i;
1044
1045    *adid = 0;
1046    switch (type) {
1047
1048    case 'r':
1049    case 'e':
1050    case 'h':
1051    case 't':
1052    case 'q':
1053    case 'x':
1054    case 'u':
1055    case 'l':
1056        wp = domod(cp, type);
1057        if (wp == 0)
1058            return (Strsave(cp));
1059        *adid = 1;
1060        return (wp);
1061
1062    default:
1063        wp = wbuf;
1064        i = BUFSIZE - 4;
1065        for (mp = cp; *mp; mp++)
1066            if (matchs(mp, lhsb)) {
1067                for (np = cp; np < mp;)
1068                    *wp++ = *np++, --i;
1069                for (np = rhsb; *np; np++)
1070                    switch (*np) {
1071
1072                    case '\\':
1073                        if (np[1] == '&')
1074                            np++;
1075                        /* fall into ... */
1076
1077                    default:
1078                        if (--i < 0) {
1079                            seterror(ERR_SUBOVFL);
1080                            return (STRNULL);
1081                        }
1082                        *wp++ = *np;
1083                        continue;
1084
1085                    case '&':
1086                        i -= Strlen(lhsb);
1087                        if (i < 0) {
1088                            seterror(ERR_SUBOVFL);
1089                            return (STRNULL);
1090                        }
1091                        *wp = 0;
1092                        (void) Strcat(wp, lhsb);
1093                        wp = Strend(wp);
1094                        continue;
1095                    }
1096                mp += Strlen(lhsb);
1097                i -= Strlen(mp);
1098                if (i < 0) {
1099                    seterror(ERR_SUBOVFL);
1100                    return (STRNULL);
1101                }
1102                *wp = 0;
1103                (void) Strcat(wp, mp);
1104                *adid = 1;
1105                return (Strsave(wbuf));
1106            }
1107        return (Strsave(cp));
1108    }
1109}
1110
1111Char   *
1112domod(cp, type)
1113    Char   *cp;
1114    int     type;
1115{
1116    Char *wp, *xp;
1117    int c;
1118
1119    switch (type) {
1120
1121    case 'x':
1122    case 'q':
1123        wp = Strsave(cp);
1124        for (xp = wp; (c = *xp) != 0; xp++)
1125            if ((c != ' ' && c != '\t') || type == 'q')
1126                *xp |= QUOTE;
1127        return (wp);
1128
1129    case 'l':
1130        wp = Strsave(cp);
1131        for (cp = wp; *cp; cp++)
1132            if (Isupper(*cp)) {
1133                *cp = Tolower(*cp);
1134                return wp;
1135            }
1136        return wp;
1137
1138    case 'u':
1139        wp = Strsave(cp);
1140        for (cp = wp; *cp; cp++)
1141            if (Islower(*cp)) {
1142                *cp = Toupper(*cp);
1143                return wp;
1144            }
1145        return wp;
1146
1147    case 'h':
1148    case 't':
1149        if (!any(short2str(cp), '/'))
1150            return (type == 't' ? Strsave(cp) : 0);
1151        wp = Strend(cp);
1152        while (*--wp != '/')
1153            continue;
1154        if (type == 'h')
1155            xp = Strsave(cp), xp[wp - cp] = 0;
1156        else
1157            xp = Strsave(wp + 1);
1158        return (xp);
1159
1160    case 'e':
1161    case 'r':
1162        wp = Strend(cp);
1163        for (wp--; wp >= cp && *wp != '/'; wp--)
1164            if (*wp == '.') {
1165                if (type == 'e')
1166                    xp = Strsave(wp + 1);
1167                else
1168                    xp = Strsave(cp), xp[wp - cp] = 0;
1169                return (xp);
1170            }
1171        return (Strsave(type == 'e' ? STRNULL : cp));
1172    default:
1173        break;
1174    }
1175    return (0);
1176}
1177
1178static int
1179matchs(str, pat)
1180    Char *str, *pat;
1181{
1182    while (*str && *pat && *str == *pat)
1183        str++, pat++;
1184    return (*pat == 0);
1185}
1186
1187static int
1188getsel(al, ar, dol)
1189    int *al, *ar;
1190    int     dol;
1191{
1192    int c = getC(0);
1193    int i;
1194    bool    first = *al < 0;
1195
1196    switch (c) {
1197
1198    case '%':
1199        if (quesarg == -1) {
1200            seterror(ERR_BADBANGARG);
1201            return (0);
1202        }
1203        if (*al < 0)
1204            *al = quesarg;
1205        *ar = quesarg;
1206        break;
1207
1208    case '-':
1209        if (*al < 0) {
1210            *al = 0;
1211            *ar = dol - 1;
1212            unreadc(c);
1213        }
1214        return (1);
1215
1216    case '^':
1217        if (*al < 0)
1218            *al = 1;
1219        *ar = 1;
1220        break;
1221
1222    case '$':
1223        if (*al < 0)
1224            *al = dol;
1225        *ar = dol;
1226        break;
1227
1228    case '*':
1229        if (*al < 0)
1230            *al = 1;
1231        *ar = dol;
1232        if (*ar < *al) {
1233            *ar = 0;
1234            *al = 1;
1235            return (1);
1236        }
1237        break;
1238
1239    default:
1240        if (Isdigit(c)) {
1241            i = 0;
1242            while (Isdigit(c)) {
1243                i = i * 10 + c - '0';
1244                c = getC(0);
1245            }
1246            if (i < 0)
1247                i = dol + 1;
1248            if (*al < 0)
1249                *al = i;
1250            *ar = i;
1251        }
1252        else if (*al < 0)
1253            *al = 0, *ar = dol;
1254        else
1255            *ar = dol - 1;
1256        unreadc(c);
1257        break;
1258    }
1259    if (first) {
1260        c = getC(0);
1261        unreadc(c);
1262        if (any("-$*", c))
1263            return (1);
1264    }
1265    if (*al > *ar || *ar > dol) {
1266        seterror(ERR_BADBANGARG);
1267        return (0);
1268    }
1269    return (1);
1270
1271}
1272
1273static struct wordent *
1274gethent(sc)
1275    int     sc;
1276{
1277    struct Hist *hp;
1278    Char *np;
1279    int c;
1280    int     event;
1281    bool    back = 0;
1282
1283    c = sc == HISTSUB ? HIST : getC(0);
1284    if (c == HIST) {
1285        if (alhistp)
1286            return (alhistp);
1287        event = eventno;
1288    }
1289    else
1290        switch (c) {
1291
1292        case ':':
1293        case '^':
1294        case '$':
1295        case '*':
1296        case '%':
1297            ungetC(c);
1298            if (lastev == eventno && alhistp)
1299                return (alhistp);
1300            event = lastev;
1301            break;
1302
1303        case '#':               /* !# is command being typed in (mrh) */
1304            if (--hleft == 0) {
1305                seterror(ERR_HISTLOOP);
1306                return (0);
1307            }
1308            else
1309                return (&paraml);
1310            /* NOTREACHED */
1311
1312        case '-':
1313            back = 1;
1314            c = getC(0);
1315            /* FALLSTHROUGH */
1316
1317        default:
1318            if (any("(=~", c)) {
1319                unreadc(c);
1320                ungetC(HIST);
1321                return (0);
1322            }
1323            np = lhsb;
1324            event = 0;
1325            while (!cmap(c, _ESC | _META | _QF | _QB) && !any("^*-%${}:#", c)) {
1326                if (event != -1 && Isdigit(c))
1327                    event = event * 10 + c - '0';
1328                else
1329                    event = -1;
1330                if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2])
1331                    *np++ = (Char) c;
1332                c = getC(0);
1333            }
1334            unreadc(c);
1335            if (np == lhsb) {
1336                ungetC(HIST);
1337                return (0);
1338            }
1339            *np++ = 0;
1340            if (event != -1) {
1341                /*
1342                 * History had only digits
1343                 */
1344                if (back)
1345                    event = eventno + (alhistp == 0) - (event ? event : 0);
1346                break;
1347            }
1348            if (back) {
1349                event = sizeof(lhsb) / sizeof(lhsb[0]);
1350                np = &lhsb[--event];
1351                *np-- = '\0';
1352                for (event--; np > lhsb; *np-- = lhsb[--event])
1353                    continue;
1354                *np = '-';
1355            }
1356            hp = findev(lhsb, 0);
1357            if (hp)
1358                lastev = hp->Hnum;
1359            return (&hp->Hlex);
1360
1361        case '?':
1362            np = lhsb;
1363            for (;;) {
1364                c = getC(0);
1365                if (c == '\n') {
1366                    unreadc(c);
1367                    break;
1368                }
1369                if (c == '?')
1370                    break;
1371                if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2])
1372                    *np++ = (Char) c;
1373            }
1374            if (np == lhsb) {
1375                if (lhsb[0] == 0) {
1376                    seterror(ERR_NOSEARCH);
1377                    return (0);
1378                }
1379            }
1380            else
1381                *np++ = 0;
1382            hp = findev(lhsb, 1);
1383            if (hp)
1384                lastev = hp->Hnum;
1385            return (&hp->Hlex);
1386        }
1387
1388    for (hp = Histlist.Hnext; hp; hp = hp->Hnext)
1389        if (hp->Hnum == event) {
1390            hp->Href = eventno;
1391            lastev = hp->Hnum;
1392            return (&hp->Hlex);
1393        }
1394    np = putn(event);
1395    seterror(ERR_NOEVENT, short2str(np));
1396    return (0);
1397}
1398
1399static struct Hist *
1400findev(cp, anyarg)
1401    Char   *cp;
1402    bool    anyarg;
1403{
1404    struct Hist *hp;
1405
1406    for (hp = Histlist.Hnext; hp; hp = hp->Hnext) {
1407        Char   *dp;
1408        Char *p, *q;
1409        struct wordent *lp = hp->Hlex.next;
1410        int     argno = 0;
1411
1412        /*
1413         * The entries added by alias substitution don't have a newline but do
1414         * have a negative event number. Savehist() trims off these entries,
1415         * but it happens before alias expansion, too early to delete those
1416         * from the previous command.
1417         */
1418        if (hp->Hnum < 0)
1419            continue;
1420        if (lp->word[0] == '\n')
1421            continue;
1422        if (!anyarg) {
1423            p = cp;
1424            q = lp->word;
1425            do
1426                if (!*p)
1427                    return (hp);
1428            while (*p++ == *q++);
1429            continue;
1430        }
1431        do {
1432            for (dp = lp->word; *dp; dp++) {
1433                p = cp;
1434                q = dp;
1435                do
1436                    if (!*p) {
1437                        quesarg = argno;
1438                        return (hp);
1439                    }
1440                while (*p++ == *q++);
1441            }
1442            lp = lp->next;
1443            argno++;
1444        } while (lp->word[0] != '\n');
1445    }
1446    seterror(ERR_NOEVENT, short2str(cp));
1447    return (0);
1448}
1449
1450
1451static void
1452setexclp(cp)
1453    Char *cp;
1454{
1455    if (cp && cp[0] == '\n')
1456        return;
1457    exclp = cp;
1458}
1459
1460void
1461unreadc(c)
1462    int    c;
1463{
1464    peekread = (Char) c;
1465}
1466
1467int
1468readc(wanteof)
1469    bool    wanteof;
1470{
1471    int c;
1472    static  int sincereal;      /* Number of real EOFs we've seen */
1473    Char *ptr;                  /* For STRignoreeof */
1474    int numeof = 0;             /* Value of STRignoreeof */
1475
1476#ifdef DEBUG_INP
1477    xprintf("readc\n");
1478#endif
1479    if ((c = peekread) != 0) {
1480        peekread = 0;
1481        return (c);
1482    }
1483
1484    /* Compute the value of EOFs */
1485    if ((ptr = varval(STRignoreeof)) != STRNULL) {
1486        while (*ptr) {
1487            if (!Isdigit(*ptr)) {
1488                numeof = 0;
1489                break;
1490            }
1491            numeof = numeof * 10 + *ptr++ - '0';
1492        }
1493    }
1494    if (numeof < 1) numeof = 26;        /* Sanity check */
1495
1496top:
1497    aret = F_SEEK;
1498    if (alvecp) {
1499        arun = 1;
1500#ifdef DEBUG_INP
1501        xprintf("alvecp %c\n", *alvecp & 0xff);
1502#endif
1503        aret = A_SEEK;
1504        if ((c = *alvecp++) != 0)
1505            return (c);
1506        if (alvec && *alvec) {
1507                alvecp = *alvec++;
1508                return (' ');
1509        }
1510        else {
1511            alvecp = NULL;
1512            aret = F_SEEK;
1513            return('\n');
1514        }
1515    }
1516    if (alvec) {
1517        arun = 1;
1518        if ((alvecp = *alvec) != 0) {
1519            alvec++;
1520            goto top;
1521        }
1522        /* Infinite source! */
1523        return ('\n');
1524    }
1525    arun = 0;
1526    if (evalp) {
1527        aret = E_SEEK;
1528        if ((c = *evalp++) != 0)
1529            return (c);
1530        if (evalvec && *evalvec) {
1531            evalp = *evalvec++;
1532            return (' ');
1533        }
1534        aret = F_SEEK;
1535        evalp = 0;
1536    }
1537    if (evalvec) {
1538        if (evalvec == INVPPTR) {
1539            doneinp = 1;
1540            reset();
1541        }
1542        if ((evalp = *evalvec) != 0) {
1543            evalvec++;
1544            goto top;
1545        }
1546        evalvec = INVPPTR;
1547        return ('\n');
1548    }
1549    do {
1550        if (arginp == INVPTR || onelflg == 1) {
1551            if (wanteof)
1552                return (-1);
1553            exitstat();
1554        }
1555        if (arginp) {
1556            if ((c = *arginp++) == 0) {
1557                arginp = INVPTR;
1558                return ('\n');
1559            }
1560            return (c);
1561        }
1562#ifdef BSDJOBS
1563reread:
1564#endif /* BSDJOBS */
1565        c = bgetc();
1566        if (c < 0) {
1567#ifndef WINNT
1568# ifndef POSIX
1569#  ifdef TERMIO
1570            struct termio tty;
1571#  else /* SGTTYB */
1572            struct sgttyb tty;
1573#  endif /* TERMIO */
1574# else /* POSIX */
1575            struct termios tty;
1576# endif /* POSIX */
1577#endif /* !WINNT */
1578            if (wanteof)
1579                return (-1);
1580            /* was isatty but raw with ignoreeof yields problems */
1581#ifndef WINNT
1582# ifndef POSIX
1583#  ifdef TERMIO
1584            if (ioctl(SHIN, TCGETA, (ioctl_t) & tty) == 0 &&
1585                (tty.c_lflag & ICANON))
1586#  else /* GSTTYB */
1587            if (ioctl(SHIN, TIOCGETP, (ioctl_t) & tty) == 0 &&
1588                (tty.sg_flags & RAW) == 0)
1589#  endif /* TERMIO */
1590# else /* POSIX */
1591            if (tcgetattr(SHIN, &tty) == 0 &&
1592                (tty.c_lflag & ICANON))
1593# endif /* POSIX */
1594#else /* WINNT */
1595            if (isatty(SHIN))
1596#endif /* !WINNT */
1597            {
1598                /* was 'short' for FILEC */
1599#ifdef BSDJOBS
1600                int     ctpgrp;
1601#endif /* BSDJOBS */
1602
1603                if (++sincereal >= numeof)      /* Too many EOFs?  Bye! */
1604                    goto oops;
1605#ifdef BSDJOBS
1606                if (tpgrp != -1 &&
1607                    (ctpgrp = tcgetpgrp(FSHTTY)) != -1 &&
1608                    tpgrp != ctpgrp) {
1609                    (void) tcsetpgrp(FSHTTY, tpgrp);
1610# ifdef _SEQUENT_
1611                    if (ctpgrp)
1612# endif /* _SEQUENT */
1613                    (void) killpg((pid_t) ctpgrp, SIGHUP);
1614# ifdef notdef
1615                    /*
1616                     * With the walking process group fix, this message
1617                     * is now obsolete. As the foreground process group
1618                     * changes, the shell needs to adjust. Well too bad.
1619                     */
1620                    xprintf(CGETS(16, 1, "Reset tty pgrp from %d to %d\n"),
1621                            ctpgrp, tpgrp);
1622# endif /* notdef */
1623                    goto reread;
1624                }
1625#endif /* BSDJOBS */
1626                /* What follows is complicated EOF handling -- sterling@netcom.com */
1627                /* First, we check to see if we have ignoreeof set */
1628                if (adrof(STRignoreeof)) {
1629                        /* If so, we check for any stopped jobs only on the first EOF */
1630                        if ((sincereal == 1) && (chkstop == 0)) {
1631                                panystop(1);
1632                        }
1633                } else {
1634                        /* If we don't have ignoreeof set, always check for stopped jobs */
1635                        if (chkstop == 0) {
1636                                panystop(1);
1637                        }
1638                }
1639                /* At this point, if there were stopped jobs, we would have already
1640                 * called reset().  If we got this far, assume we can print an
1641                 * exit/logout message if we ignoreeof, or just exit.
1642                 */
1643                if (adrof(STRignoreeof)) {
1644                        /* If so, tell the user to use exit or logout */
1645                    if (loginsh) {
1646                                xprintf(CGETS(16, 2,
1647                                        "\nUse \"logout\" to logout.\n"));
1648                        } else {
1649                                xprintf(CGETS(16, 3,
1650                                        "\nUse \"exit\" to leave %s.\n"),
1651                                        progname);
1652                        }
1653                        reset();
1654                } else {
1655                        /* If we don't have ignoreeof set, just fall through */
1656                        ;       /* EMPTY */
1657                }
1658            }
1659    oops:
1660            doneinp = 1;
1661            reset();
1662        }
1663        sincereal = 0;
1664        if (c == '\n' && onelflg)
1665            onelflg--;
1666    } while (c == 0);
1667    if (histlinep < histline + BUFSIZE)
1668        *histlinep++ = (Char) c;
1669    return (c);
1670}
1671
1672static void
1673balloc(buf)
1674    int buf;
1675{
1676    Char **nfbuf;
1677
1678    while (buf >= fblocks) {
1679        nfbuf = (Char **) xcalloc((size_t) (fblocks + 2),
1680                          sizeof(Char **));
1681        if (fbuf) {
1682            (void) blkcpy(nfbuf, fbuf);
1683            xfree((ptr_t) fbuf);
1684        }
1685        fbuf = nfbuf;
1686        fbuf[fblocks] = (Char *) xcalloc(BUFSIZE, sizeof(Char));
1687        fblocks++;
1688    }
1689}
1690
1691static int
1692bgetc()
1693{
1694    int c, off, buf;
1695    int numleft = 0, roomleft;
1696    char    tbuf[BUFSIZE + 1];
1697
1698    if (cantell) {
1699        if (fseekp < fbobp || fseekp > feobp) {
1700            fbobp = feobp = fseekp;
1701            (void) lseek(SHIN, fseekp, L_SET);
1702        }
1703        if (fseekp == feobp) {
1704            int     i;
1705
1706            fbobp = feobp;
1707            do
1708                c = read(SHIN, tbuf, BUFSIZE);
1709            while (c < 0 && errno == EINTR);
1710#ifdef convex
1711            if (c < 0)
1712                stderror(ERR_SYSTEM, progname, strerror(errno));
1713#endif /* convex */
1714            if (c <= 0)
1715                return (-1);
1716            for (i = 0; i < c; i++)
1717                fbuf[0][i] = (unsigned char) tbuf[i];
1718            feobp += c;
1719        }
1720#ifndef WINNT
1721        c = fbuf[0][fseekp - fbobp];
1722        fseekp++;
1723#else
1724        do {
1725            c = fbuf[0][fseekp - fbobp];
1726            fseekp++;
1727        } while(c == '\r');
1728#endif /* !WINNT */
1729        return (c);
1730    }
1731
1732    while (fseekp >= feobp) {
1733        if (editing && intty) {         /* then use twenex routine */
1734            fseekp = feobp;             /* where else? */
1735            c = numleft = Inputl();     /* PWP: get a line */
1736            while (numleft > 0) {
1737                off = (int) feobp % BUFSIZE;
1738                buf = (int) feobp / BUFSIZE;
1739                balloc(buf);
1740                roomleft = BUFSIZE - off;
1741                if (roomleft > numleft)
1742                    roomleft = numleft;
1743                (void) memmove((ptr_t) (fbuf[buf] + off), (ptr_t) (InputBuf + c - numleft), (size_t) (roomleft * sizeof(Char)));
1744                numleft -= roomleft;
1745                feobp += roomleft;
1746            }
1747        }
1748        else {
1749            off = (int) feobp % BUFSIZE;
1750            buf = (int) feobp / BUFSIZE;
1751            balloc(buf);
1752            roomleft = BUFSIZE - off;
1753            c = read(SHIN, tbuf, (size_t) roomleft);
1754            if (c > 0) {
1755                int     i;
1756                Char   *ptr = fbuf[buf] + off;
1757
1758                for (i = 0; i < c; i++)
1759                    ptr[i] = (unsigned char) tbuf[i];
1760                feobp += c;
1761            }
1762        }
1763        if (c == 0 || (c < 0 && fixio(SHIN, errno) == -1))
1764            return (-1);
1765    }
1766#ifndef WINNT
1767    c = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE];
1768    fseekp++;
1769#else
1770    do {
1771        c = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE];
1772        fseekp++;
1773    } while(c == '\r');
1774#endif /* !WINNT */
1775    return (c);
1776}
1777
1778static void
1779bfree()
1780{
1781    int sb, i;
1782
1783    if (cantell)
1784        return;
1785    if (whyles)
1786        return;
1787    sb = (int) (fseekp - 1) / BUFSIZE;
1788    if (sb > 0) {
1789        for (i = 0; i < sb; i++)
1790            xfree((ptr_t) fbuf[i]);
1791        (void) blkcpy(fbuf, &fbuf[sb]);
1792        fseekp -= BUFSIZE * sb;
1793        feobp -= BUFSIZE * sb;
1794        fblocks -= sb;
1795    }
1796}
1797
1798void
1799bseek(l)
1800    struct Ain   *l;
1801{
1802    switch (aret = l->type) {
1803    case E_SEEK:
1804        evalvec = l->a_seek;
1805        evalp = l->c_seek;
1806#ifdef DEBUG_SEEK
1807        xprintf(CGETS(16, 4, "seek to eval %x %x\n"), evalvec, evalp);
1808#endif
1809        return;
1810    case A_SEEK:
1811        alvec = l->a_seek;
1812        alvecp = l->c_seek;
1813#ifdef DEBUG_SEEK
1814        xprintf(CGETS(16, 5, "seek to alias %x %x\n"), alvec, alvecp);
1815#endif
1816        return;
1817    case F_SEEK:       
1818#ifdef DEBUG_SEEK
1819        xprintf(CGETS(16, 6, "seek to file %x\n"), fseekp);
1820#endif
1821        fseekp = l->f_seek;
1822        return;
1823    default:
1824        xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret);
1825        abort();
1826    }
1827}
1828
1829/* any similarity to bell telephone is purely accidental */
1830void
1831btell(l)
1832struct Ain *l;
1833{
1834    switch (l->type = aret) {
1835    case E_SEEK:
1836        l->a_seek = evalvec;
1837        l->c_seek = evalp;
1838#ifdef DEBUG_SEEK
1839        xprintf(CGETS(16, 8, "tell eval %x %x\n"), evalvec, evalp);
1840#endif
1841        return;
1842    case A_SEEK:
1843        l->a_seek = alvec;
1844        l->c_seek = alvecp;
1845#ifdef DEBUG_SEEK
1846        xprintf(CGETS(16, 9, "tell alias %x %x\n"), alvec, alvecp);
1847#endif
1848        return;
1849    case F_SEEK:
1850        /*SUPPRESS 112*/
1851        l->f_seek = fseekp;
1852        l->a_seek = NULL;
1853#ifdef DEBUG_SEEK
1854        xprintf(CGETS(16, 10, "tell file %x\n"), fseekp);
1855#endif
1856        return;
1857    default:
1858        xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret);
1859        abort();
1860    }
1861}
1862
1863void
1864btoeof()
1865{
1866    (void) lseek(SHIN, (off_t) 0, L_XTND);
1867    aret = F_SEEK;
1868    fseekp = feobp;
1869    alvec = NULL;
1870    alvecp = NULL;
1871    evalvec = NULL;
1872    evalp = NULL;
1873    wfree();
1874    bfree();
1875}
1876
1877void
1878settell()
1879{
1880    off_t x;
1881    cantell = 0;
1882    if (arginp || onelflg || intty)
1883        return;
1884    if ((x = lseek(SHIN, (off_t) 0, L_INCR)) == -1)
1885        return;
1886    fbuf = (Char **) xcalloc(2, sizeof(Char **));
1887    fblocks = 1;
1888    fbuf[0] = (Char *) xcalloc(BUFSIZE, sizeof(Char));
1889    fseekp = fbobp = feobp = x;
1890    cantell = 1;
1891}
Note: See TracBrowser for help on using the repository browser.