Yet Another Shell (part 9 of 11)

Dave Clemans dclemans.falcon at mntgfx.mentor.com
Thu Mar 16 08:39:05 AEST 1989


With all the talk about shells that has been going on recently...

Here's an early pre-release of a "Korn"-like shell for anyone
who might want to experiment.  It is definitely NOT complete,
but it starting to be usable.  It does use some GNU code (for
expression evaluation), so it presumably comes under their
"copyleft".

It basically runs on BSD/USG Unix systems, and on the Atari ST.
I'm currently working on a port to the Amiga.  It is NOT yet
bug free; I am VERY interested in fixes; enhancements, etc.

dgc

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 9 (of 11)."
# Contents:  lex.c
# Wrapped by dclemans at dclemans on Wed Mar 15 14:04:00 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'lex.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lex.c'\"
else
echo shar: Extracting \"'lex.c'\" \(37330 characters\)
sed "s/^X//" >'lex.c' <<'END_OF_FILE'
X/*
X * Command Input Shell
X * Dave Clemans
X * 12/88-1/89
X *
X * "spiritually" based on Bourne, Korn shells
X *
X * Input Lexer
X *
X * $Id: lex.c,v 1.11 89/03/05 15:38:27 dclemans Exp $
X *
X * $Log:	lex.c,v $
X * Revision 1.11  89/03/05  15:38:27  dclemans
X * more fixes
X * 
X * Revision 1.10  89/02/25  17:40:08  dclemans
X * miscellaneous bug fixes/speedups
X * 
X * Revision 1.9  89/02/22  21:47:25  dclemans
X * bug fix ] vs ]]
X * 
X * Revision 1.8  89/02/22  16:26:54  dclemans
X * Implement [[, ]] brackets
X * 
X * Revision 1.7  89/02/22  13:12:27  dclemans
X * Fix bug with null tokens
X * 
X * Revision 1.6  89/02/22  10:16:35  dclemans
X * Fix bugs with process waiting, pid reporting, parsing of &
X * 
X * Revision 1.5  89/02/21  20:29:56  dclemans
X * Fix bug with shell variable references in history lists.
X * 
X * Revision 1.4  89/02/20  20:11:56  dclemans
X * Add RCS identifiers
X * 
X */
X#include <stdio.h>
X#include "shell.h"
X
Xstatic int dont_expand = 0;
X
Xint lex_heredoc_do(iop)
Xstruct iotoken *iop;
X{
X    int ofd,len,next_char;
X    char buffer[BUFSIZ];
X
X    if (iop->type != SYM_LLT && iop->type != SYM_LLTL)
X        return -1;
X    len = 16;
X#ifdef  GEMDOS
X    len += strlen(base_env.tmpdir);
X#endif  /* GEMDOS */
X    iop->tempfile = new_string(len+1);
X    if (iop->tempfile == (char *)NULL)
X    {   /* enough memory? */
X        errmsg(SHERR_NOMEM,LOC("io_heredoc"));
X        return -1;
X    }
X#ifdef  GEMDOS
X    sprintf(iop->tempfile,"%stemp%d.tmp",base_env.tmpdir,base_env.temp_count++);
X#else
X    sprintf(iop->tempfile,"/tmp/sh%d.temp",base_env.temp_count++);
X#endif  /* GEMDOS */
X    ofd = creat(iop->tempfile,0666);
X    if (ofd < 0)
X    {   /* was it created? */
X        errmsg(0,LOC("io_heredoc"),"couldn't create %s",iop->tempfile);
X        free(iop->tempfile);
X        iop->tempfile = (char *)NULL;
X        return -1;
X    }
X    len = 0;
X    if (iop->file[0] == ESCAPE_CHAR ||
X        iop->file[0] == '\'' || iop->file[0] == '"')
X        dont_expand = 1;
X    stripquotes(iop->file);
X    while ((next_char = io_getchar(1)) != SYM_EOF)
X    {   /* get chars to fill up heredoc */
X        buffer[len++] = next_char;
X        if (next_char == '\n' || len >= sizeof buffer)
X        {   /* end of line? */
X#ifdef  GEMDOS
X            if (next_char == '\n')
X                buffer[len-1] = '\r';
X#endif  /* GEMDOS */
X            while (iop->type == SYM_LLTL && isspace(buffer[0]) && len > 0)
X            {   /* strip leading white space? */
X                len--;
X                strncpy(buffer,&buffer[1],len);
X            }
X            if (len == 0)
X                continue;
X            if (strncmp(iop->file,buffer,strlen(iop->file)) == 0)
X            {   /* heredoc end of file? */
X                break;
X            }
X            write(ofd,buffer,len);
X            len = 0;
X#ifdef  GEMDOS
X            if (next_char == '\n')
X                write(ofd,"\n",1);
X#endif  /* GEMDOS */
X        }
X    }
X    dont_expand = 0;
X    close(ofd);
X    return 0;
X}   /* end of lex_heredoc_do */
X
Xint lex_heredoc()
X{
X    struct herestack *hs,*hsp,*ohsp;
X
X    hs = base_env.pending_heredocs;
X    base_env.pending_heredocs = (struct herestack *)NULL;
X    if (hs == (struct herestack *)NULL)
X        return 0;
X    for (hsp = hs; hsp != (struct herestack *)NULL; )
X    {   /* for each pending heredoc */
X        ohsp = hsp;
X        hsp = hsp->next;
X        lex_heredoc_do(ohsp->doc);
X        free(ohsp);
X    }
X    return 0;
X}   /* end of lex_heredoc */
X
Xint lex_heredoc_save(iop)
Xstruct iotoken *iop;
X{
X    struct herestack *hs,*hsp;
X
X    hsp = (struct herestack *)malloc(sizeof(*hsp));
X    if (hsp == (struct herestack *)NULL)
X    {   /* enough memory */
X        errmsg(SHERR_NOMEM,LOC("lex_heredoc_save"));
X        return -1;
X    }
X    hsp->next = (struct herestack *)NULL;
X    hsp->doc = iop;
X
X    if (base_env.pending_heredocs == (struct herestack *)NULL)
X        base_env.pending_heredocs = hsp;
X    else
X    {   /* tack onto end */
X        for (hs = base_env.pending_heredocs; hs->next != (struct herestack *)NULL; hs = hs->next)
X            /* do nothing */;
X        hs->next = hsp;
X    }
X    return 0;
X}   /* end of lex_heredoc_save */
X
Xstatic int typeof(word)
Xregister char *word;
X{
X    register char *p;
X    int flag;
X
X    if (isdigit(*word) || *word == '-' || *word == '+')
X    {   /* is the whole word numeric? */
X        flag = SYM_NUMBER;
X        for (p = &word[1]; *p; p++)
X            if (!isdigit(*p))
X                flag = SYM_WORD;
X        return flag;
X    }
X    switch (*word)
X    {   /* what kind of word? */
X        case '`':
X            return SYM_BQUOTE;
X        case ';':
X            if (word[1] == ';')
X                return SYM_DSEMI;
X            return SYM_SEMI;
X        case '<':
X            if (word[1] == '&')
X                return SYM_LBT;
X            else if (word[1] == '<')
X            {   /* if a here doc */
X                if (word[2] == '-')
X                    return SYM_LLTL;
X                return SYM_LLT;
X            }
X            else    return SYM_LT;
X        case '>':
X            if (word[1] == '&')
X                return SYM_RBT;
X            else if (word[1] == '>')
X                return SYM_RRT;
X            else    return SYM_RT;
X        case '{':
X            return SYM_LBRACE;
X        case '}':
X            return SYM_RBRACE;
X        case '(':
X            if (word[1] == '(')
X                return SYM_DLPAREN;
X            else return SYM_LPAREN;
X        case ')':
X            if (word[1] == ')')
X                return SYM_DRPAREN;
X            return SYM_RPAREN;
X        case '&':
X            if (word[1] == '&')
X                return SYM_ANDIF;
X            else    return SYM_BACK;
X        case '|':
X            if (word[1] == '|')
X                return SYM_ORIF;
X            else    return SYM_PIPE;
X        case '[':
X            if (word[1] == '[')
X                return SYM_DLBRACK;
X            else    return SYM_WORD;
X        case ']':
X            if (word[1] == ']')
X                return SYM_DRBRACK;
X            else    return SYM_DRBRACK;
X        case '\n':
X        case '\r':
X            return SYM_EOL;
X        default:
X            return SYM_WORD;
X    }
X    /* NOT REACHED */
X}   /* end of typeof */
X
Xstruct token *lex_token(level)
Xint level;
X{
X    char workbuf[BUFSIZ];
X    register char *first,*ptr;
X    int keepgoing,keyword,next_char,la_char;
X    register struct token *tp;
X    struct phrase *sp;
X    char *result;
X#define APPEND(c) ((first<&workbuf[sizeof workbuf])?*first++ = c:errmsg(0,LOC("lex_token"),"word too long"))
X
X    while ((next_char = io_getchar(level)) != SYM_EOF)
X    {   /* skip leading blanks */
X        if (strchr(base_env.separators,next_char) == (char *)NULL)
X            break;
X    }
X    if (next_char == SYM_EOF)
X        return (struct token *)NULL;
X    keyword = 0;
X    keepgoing = 1;
X    first = workbuf;
X    while (next_char != SYM_EOF && keepgoing && strchr(base_env.separators,next_char) == (char *)NULL)
X    {   /* go pick off a word */
X        switch (next_char)
X        {   /* look for quoting, etc. */
X            case '#':   /* rest of line a comment? */
X                while (next_char != '\r' && next_char != '\n')
X                {   /* scan til end of line */
X                    next_char = io_getchar(level);
X                    if (next_char == SYM_EOF)
X                        break;
X                }
X                io_pushback(next_char);
X                break;
X            case '`':   /* `` expansion string */
X                if (level == 0)
X                {   /* starting string? */
X                    sp = lex_sentence(1);
X                    exec_sentence(sp,0);
X                    io_pushfile(sp->group_end->io->file,1,1,0);
X                    sentence_free(sp);
X                }
X                else
X                {   /* end of string */
X                    keepgoing = 0;
X                    if (first != workbuf)
X                        io_pushback(next_char);
X                    else APPEND(next_char);
X                }
X                break;
X            case ESCAPE_CHAR:
X                APPEND(next_char);
X                next_char = io_getchar(1);
X                APPEND(next_char);
X                break;
X            case '"':   /* double quote; allow variables */
X                APPEND('"');
X                while ((next_char = io_getchar(1)) != '"')
X                {   /* until end of string */
X                    if (next_char == SYM_EOF)
X                        break;
X                    if (next_char == ESCAPE_CHAR)
X                    {   /* grab next char */
X                        APPEND(next_char);
X                        next_char = io_getchar(1);
X                    }
X                    else if (next_char == '$')
X                    {   /* expand out a variable */
X                        result = var_reference(dont_expand);
X                        if (result != (char *)NULL)
X                        {   /* stick in expansion */
X                            for (ptr = result; *ptr; ptr++)
X                                APPEND(*ptr);
X                            free(result);
X                        }
X                        continue;
X                    }
X                    else if (next_char == '`')
X                    {   /* substituted command */
X                        if (level == 0)
X                        {   /* starting string? */
X                            sp = lex_sentence(1);
X                            exec_sentence(sp,0);
X                            io_pushfile(sp->group_end->io->file,1,1,0);
X                            sentence_free(sp);
X                        }
X                        else
X                        {   /* end of string */
X                            keepgoing = 0;
X                            if (first != workbuf)
X                                io_pushback(next_char);
X                            else APPEND(next_char);
X                        }
X                        continue;
X                    }
X                    APPEND(next_char);
X                }
X                if (next_char == SYM_EOF)
X                {   /* bad end-of-string */
X                    errmsg(0,LOC("lex_token"),"end of string not found");
X                    break;
X                }
X                APPEND('"');
X                break;
X            case '\'':  /* single quote */
X                APPEND('\'');
X                while ((next_char = io_getchar(1)) != '\'')
X                {   /* until end of string */
X                    if (next_char == SYM_EOF)
X                        break;
X                    APPEND(next_char);
X                }
X                if (next_char == SYM_EOF)
X                {   /* bad end-of-string? */
X                    errmsg(0,LOC("lex_token"),"missing end of string");
X                    break;
X                }
X                APPEND('\'');
X                break;
X            case '[':
X            case ']':
X                la_char = io_getchar(level);
X                if (next_char != la_char)
X                {   /* if not a double [[ or ]] */
X                    io_pushback(la_char);
X                    APPEND(next_char);
X                    break;
X                }
X                if (first != workbuf)
X                {   /* ending current token? */
X                    io_pushback(la_char);
X                    io_pushback(next_char);
X                    keepgoing = 0;
X                    break;
X                }
X                APPEND(next_char);
X                APPEND(la_char);
X                keepgoing = 0;
X                break;
X            case ';':   /* end of phrase */
X            case '(':   /* start of group */
X            case ')':   /* end of group */
X                if (first != workbuf)
X                {   /* ending current token? */
X                    io_pushback(next_char);
X                    keepgoing = 0;
X                    break;
X                }
X                APPEND(next_char);
X                next_char = io_getchar(level);
X                if (next_char != SYM_EOF && first[-1] == next_char)
X                {   /* a two character symbol? */
X                    APPEND(next_char);
X                }
X                else
X                {   /* a one character symbol */
X                    io_pushback(next_char);
X                }
X                keepgoing = 0;
X                break;
X            case SYM_MARKER:
X                keepgoing = 0;
X                workbuf[0] = '\0';
X                first = workbuf;
X                break;
X            case '\n':  /* end of line */
X            case '\r':
X                lex_heredoc();
X                /* FALL THROUGH! */
X            case '{':   /* left brace */
X            case '}':   /* right brace */
X                if (first != workbuf)
X                {   /* ending current token? */
X                    io_pushback(next_char);
X                    keepgoing = 0;
X                    break;
X                }
X                APPEND(next_char);
X                keepgoing = 0;
X                break;
X            case '|':   /* a pipe? */
X            case '&':   /* background? */
X            case '<':   /* I/O? */
X            case '>':   /* I/O? */
X                if (first != workbuf)
X                {   /* ending current token? */
X                    io_pushback(next_char);
X                    keepgoing = 0;
X                    break;
X                }
X                APPEND(next_char);
X                keepgoing = 0;
X                next_char = io_getchar(level);
X                if ((next_char != SYM_EOF) &&
X                    (first[-1] == next_char ||
X                    (first[-1] == '<' && next_char == '&') ||
X                    (first[-1] == '>' && next_char == '&')))
X                {   /* a two character symbol? */
X                    APPEND(next_char);
X                    if (next_char == '<')
X                    {   /* three character (<<-)? */
X                        next_char = io_getchar(level);
X                        if (next_char == '-')
X                            APPEND(next_char);
X                        else io_pushback(next_char);
X                    }
X                }
X                else
X                {   /* a one character symbol */
X                    io_pushback(next_char);
X                }
X                break;
X            case '=':   /* possible assignment? */
X                keyword = 1;
X                /* FALL THROUGH */
X            default:    /* and everything else */
X                if (next_char == '$')
X                {   /* expand a variable? */
X                    result = var_reference(dont_expand);
X                    if (result != (char *)NULL)
X                    {   /* stick in expansion */
X                        for (ptr = result; *ptr; ptr++)
X                            APPEND(*ptr);
X                        free(result);
X                    }
X                    break;
X                }
X                APPEND(next_char);
X                break;
X        }
X        if (!keepgoing)
X            break;
X        if (next_char != SYM_EOF)
X            next_char = io_getchar(level);
X    }
X    if (first == workbuf && next_char != SYM_EOF && keepgoing && strchr(base_env.separators,next_char) != (char *)NULL)
X    {   /* reject this as useless token? */
X        return lex_token(level);
X    }
X    tp = new_token((int)(first-workbuf));
X    if (tp == (struct token *)NULL)
X    {   /* enough memory? */
X        errmsg(SHERR_NOMEM,LOC("lex_token"));
X        return tp;
X    }
X    strncpy(tp->name,workbuf,(int)(first-workbuf));
X    tp->name[(int)(first-workbuf)] = '\0';
X    if (next_char == SYM_MARKER)
X        tp->type = SYM_MARKER;
X    else tp->type = typeof(tp->name);
X    if (keyword && tp->type == SYM_WORD)
X        tp->type = SYM_KEYWORD;
X    return tp;
X#undef  APPEND
X}   /* end of lex_token */
X
Xstruct brackets
X{
X    char    *name;
X    char    *start;
X    char    *end;
X};
Xstatic struct brackets cmd_brackets[] =
X{
X    { "case",       "",         "esac"  },
X    { "if",         "then",     "fi"    },
X    { "for",        "do",       "done"  },
X    { "for",        "{",        "}"     },
X    { "function",   "{",        "}"     },
X    { "select",     "do",       "done"  },
X    { "select",     "{",        "}"     },
X    { "until",      "do",       "done"  },
X    { "until",      "{",        "}"     },
X    { "while",      "do",       "done"  },
X    { "while",      "{",        "}"     },
X    { (char *)NULL, (char *)NULL,   (char *)NULL }
X};
X
Xint reserved_word(word)
Xchar *word;
X{
X    register int ctr;
X
X    for (ctr = 0; cmd_brackets[ctr].name != (char *)NULL; ctr++)
X    {   /* check each bracket set */
X        if (strcmp(cmd_brackets[ctr].name,word) == 0)
X            return 1;
X        if (strcmp(cmd_brackets[ctr].start,word) == 0)
X            return 1;
X        if (strcmp(cmd_brackets[ctr].end,word) == 0)
X            return 1;
X    }
X    if (strcmp("else",word) == 0)
X        return 1;
X    if (strcmp("elif",word) == 0)
X        return 1;
X    return 0;
X}   /* end of reserved_word */
X
Xstruct phrase *lex_paragraph(level,fpp)
Xint level;
Xstruct phrase *fpp;
X{
X    register struct phrase *pp;
X    struct token *tp,*stp,*etp;
X    register int ctr;
X
X    if (fpp == (struct phrase *)NULL)
X        return fpp;
X    tp = fpp->body;
X    if (tp == (struct token *)NULL)
X        return fpp;
X    for (ctr = 0; cmd_brackets[ctr].name != (char *)NULL; ctr++)
X    {   /* start of a paragraph? */
X        if (strcmp(tp->name,cmd_brackets[ctr].name) == 0)
X            break;
X    }
X    if (cmd_brackets[ctr].name == (char *)NULL)
X        return fpp;
X    if (strlen(cmd_brackets[ctr].start) != 0)
X    {   /* if need a starting bracket */
X        stp = lex_token(1);
X        if (stp == (struct token *)NULL)
X        {   /* no paragraph start? */
X            errmsg(0,LOC("lex_paragraph"),"missing start of paragraph");
X            return fpp;
X        }
X        if (stp->type == SYM_EOL && strcmp(stp->name,"\n") == 0)
X        {   /* skip empty token */
X            free(stp);
X            stp = lex_token(1);
X            if (stp == (struct token *)NULL)
X            {   /* no paragraph start? */
X                errmsg(0,LOC("lex_paragraph"),"missing start of paragraph");
X                return fpp;
X            }
X        }
X        for (ctr = 0; cmd_brackets[ctr].name != (char *)NULL; ctr++)
X        {   /* now can find "correct" brackets */
X            if (strcmp(tp->name,cmd_brackets[ctr].name) == 0 &&
X                strcmp(stp->name,cmd_brackets[ctr].start) == 0)
X                break;
X        }
X        if (cmd_brackets[ctr].name == (char *)NULL)
X        {   /* unknown combo? */
X            errmsg(0,LOC("lex_paragraph"),"unexpected paragraph tokens: %s,%s",
X                tp->name,stp->name);
X            io_pushtoken(stp->name,0);
X            free(stp);
X            return fpp;
X        }
X        pp = new_phrase();
X        if (pp == (struct phrase *)NULL)
X        {   /* enough memory? */
X            free(stp);
X            errmsg(SHERR_NOMEM,LOC("lex_paragraph"));
X            return fpp;
X        }
X        pp->body = pp->body_end = stp;
X        pp->type = new_token(1);
X        if (pp->type == (struct token *)NULL)
X        {   /* enough memory? */
X            free(pp);
X            free(stp);
X            errmsg(SHERR_NOMEM,LOC("lex_paragraph"));
X            return fpp;
X        }
X        pp->type->type = SYM_EOL;
X        strcpy(pp->type->name,"\n");
X        fpp->group = fpp->group_end = pp;
X    }
X
X    while (dont_expand = 1,(pp = lex_phrase(1,1)) != (struct phrase *)NULL)
X    {   /* loop til eof or end of paragraph */
X        if (pp->type == (struct token *)NULL)
X            break;
X        if (pp->io == (struct iotoken *)NULL &&
X            pp->group == (struct phrase *)NULL &&
X            pp->var == (struct token *)NULL &&
X            pp->type->type == SYM_EOL && pp->body == (struct token *)NULL)
X        {   /* ignore leading empty phrase */
X            phrase_free(pp);
X            continue;
X        }
X        if (fpp->group == (struct phrase *)NULL)
X            fpp->group = fpp->group_end = pp;
X        else
X        {   /* tack onto end */
X            fpp->group_end->next = pp;
X            fpp->group_end = pp;
X        }
X        etp = pp->body;
X        if (etp == (struct token *)NULL)
X            etp = pp->type;
X        if (etp == (struct token *)NULL)
X            continue;
X        if (strcmp(etp->name,cmd_brackets[ctr].end) == 0)
X        {   /* got end of paragraph? */
X            dont_expand = 0;
X            if (fpp->io == (struct iotoken *)NULL &&
X                pp->io != (struct iotoken *)NULL)
X            {   /* move io redirection to good place */
X                fpp->io = pp->io;
X                fpp->io_end = pp->io_end;
X                pp->io = pp->io_end = (struct iotoken *)NULL;
X            }
X            return fpp;
X        }
X    }
X    errmsg(0,LOC("lex_paragraph"),"end of paragraph missing");
X
X    if (pp != (struct phrase *)NULL)
X        phrase_free(pp);
X    dont_expand = 0;
X    return lex_phrase(level,1);
X}   /* end of lex_paragraph */
X
Xvoid lex_parens(level,fpp)
Xint level;
Xstruct phrase *fpp;
X{
X    register struct phrase *pp;
X    int doneflag;
X
X    if (fpp->type == (struct token *)NULL || fpp->type->type != SYM_LPAREN)
X        return;
X    doneflag = 0;
X    while ((pp = lex_phrase(level,1)) != (struct phrase *)NULL)
X    {   /* get the parenthized phrases */
X        if (pp->type == (struct token *)NULL)
X            break;
X        if (fpp->group == (struct phrase *)NULL)
X            fpp->group = fpp->group_end = pp;
X        else
X        {   /* tack onto end */
X            fpp->group_end->next = pp;
X            fpp->group_end = pp;
X        }
X        if (doneflag)
X            break;
X        if (pp->type->type == SYM_RPAREN)
X            doneflag++;
X    }
X    if (doneflag)
X    {   /* if a parenthized group was found */
X        if (pp->io != (struct iotoken *)NULL)
X        {   /* move group i/o to front */
X            if (fpp->io == (struct iotoken *)NULL)
X            {   /* just move it */
X                fpp->io = pp->io;
X                fpp->io_end = pp->io_end;
X            }
X            else
X            {   /* tack onto end */
X                fpp->io_end->next = pp->io;
X                fpp->io_end = pp->io_end;
X            }
X            pp->io = pp->io_end = (struct iotoken *)NULL;
X        }
X    }
X}   /* end of lex_parens */
X
Xstruct phrase *lex_phrase(level,expflag)
Xint level;
Xint expflag;
X{
X    register struct phrase *pp;
X    register struct token *tp,*tp1;
X    struct token *tp2;
X    struct iotoken *iop;
X    int save_expflag;
X
X    pp = new_phrase();
X    if (pp == (struct phrase *)NULL)
X        return pp;
X
X    save_expflag = dont_expand;
X    dont_expand = expflag;
X    while ((tp = lex_token(level)) != (struct token *)NULL)
X    {   /* get token until end of phrase is reached */
X        switch (tp->type)
X        {   /* check for end of phrase or other special tokens */
X            case SYM_DLPAREN:   /* start of arithmetic expression */
X                do
X                {   /* fill out rest of expression */
X                    if (pp->body == (struct token *)NULL)
X                    {   /* at start of list */
X                        pp->body = pp->body_end = tp;
X                    }
X                    else
X                    {   /* tack onto end */
X                        pp->body_end->next = tp;
X                        pp->body_end = tp;
X                    }
X                    if (tp->type == SYM_DRPAREN)
X                        break;
X                } while ((tp = lex_token(1)) != (struct token *)NULL);
X                break;
X            case SYM_DLBRACK:   /* start of conditional expression */
X                do
X                {   /* fill out rest of expression */
X                    if (pp->body == (struct token *)NULL)
X                    {   /* at start of list */
X                        pp->body = pp->body_end = tp;
X                    }
X                    else
X                    {   /* tack onto end */
X                        pp->body_end->next = tp;
X                        pp->body_end = tp;
X                    }
X                    if (tp->type == SYM_DRBRACK)
X                        break;
X                } while ((tp = lex_token(1)) != (struct token *)NULL);
X                break;
X            case SYM_LT:    /* various I/O redirection tokens */
X            case SYM_LLT:
X            case SYM_LLTL:
X            case SYM_LBT:
X            case SYM_RT:
X            case SYM_RRT:
X            case SYM_RBT:
X                for (tp1 = pp->body; tp1 != (struct token *)NULL && tp1->next != pp->body_end; tp1 = tp1->next)
X                    /* do nothing */;
X                if (pp->body != (struct token *)NULL && pp->body_end->type == SYM_NUMBER)
X                {   /* pick up file descriptor? */
X                    tp2 = pp->body_end;
X                    if (tp1 != (struct token *)NULL)
X                    {   /* remove tail of list */
X                        tp1->next = (struct token *)NULL;
X                        pp->body_end = tp1;
X                    }
X                    else    pp->body = pp->body_end = (struct token *)NULL;
X                }
X                else    tp2 = (struct token *)NULL;
X                tp1 = lex_token(level);
X                if (tp1 == (struct token *)NULL)
X                {   /* EOF or no memory? */
X                    errmsg(0,LOC("lex_phrase"),"incomplete I/O redirection");
X                    tp = tp1;
X                    break;
X                }
X                iop = new_iotoken(strlen(tp1->name));
X                if (iop == (struct iotoken *)NULL)
X                {   /* enough memory */
X                    errmsg(SHERR_NOMEM,LOC("lex_phrase"));
X                }
X                else
X                {   /* fill in the ioblock */
X                    iop->tempfile = (char *)NULL;
X                    iop->type = tp->type;
X                    strcpy(iop->file,tp1->name);
X                    if (iop->type == SYM_RT ||
X                        iop->type == SYM_RRT ||
X                        iop->type == SYM_RBT)
X                        iop->fd = 1;
X                    else    iop->fd = 0;
X                    if (tp2 != (struct token *)NULL)
X                        iop->fd = atoi(tp2->name);
X                    if (pp->io == (struct iotoken *)NULL)
X                        pp->io = pp->io_end = iop;
X                    else
X                    {   /* tack onto end */
X                        pp->io_end->next = iop;
X                        pp->io_end = iop;
X                    }
X                    if (iop->type == SYM_LLT || iop->type == SYM_LLTL)
X                        lex_heredoc_save(iop);
X                }
X                if (tp2 != (struct token *)NULL)
X                    free(tp2);
X                free(tp1);
X                free(tp);
X#ifdef  GEMDOS
X                if (iop->fd > MAXUFD ||
X                    ((iop->type == SYM_LBT || iop->type == SYM_RBT) &&
X                    atoi(iop->file) > MAXUFD))
X                {   /* are fds too big? */
X                    errmsg(0,LOC("lex_phrase"),"can't redirect fds > %d in GEMDOS",MAXUFD);
X                }
X#endif  /* GEMDOS */
X                break;
X            case SYM_MARKER:    /* special boundary marker */
X                pp->type = tp;
X                dont_expand = save_expflag;
X                return pp;
X            case SYM_EOL:       /* end of line */
X            case SYM_DSEMI:     /* double semicolon */
X            case SYM_SEMI:      /* semicolon */
X            case SYM_BACK:      /* background */
X            case SYM_PIPE:      /* piping together */
X            case SYM_ORIF:      /* or conditional */
X            case SYM_ANDIF:     /* and conditional */
X            case SYM_LPAREN:    /* start of group */
X            case SYM_RPAREN:    /* end of group */
X            case SYM_BQUOTE:    /* end of substitute group */
X                pp->type = tp;
X                if (tp->type == SYM_LPAREN)
X                    lex_parens(level,pp);
X                dont_expand = save_expflag;
X                return lex_paragraph(level,pp);
X            default:
X                if (tp->type == SYM_KEYWORD &&
X                   (pp->body == (struct token *)NULL || flag_keywords))
X                {   /* define a variable? */
X                    if (dont_expand)
X                    {   /* save for later? */
X                        if (pp->var == (struct token *)NULL)
X                            pp->var = pp->var_end = tp;
X                        else
X                        {   /* tack onto end */
X                            pp->var_end->next = tp;
X                            pp->var_end = tp;
X                        }
X                    }
X                    else
X                    {   /* expand the variable */
X                        var_define(tp->name,0,0);
X                        free(tp);
X                    }
X                    break;
X                }
X                if (pp->body == (struct token *)NULL)
X                {   /* at start of list */
X                    pp->body = pp->body_end = tp;
X                }
X                else
X                {   /* tack onto end */
X                    pp->body_end->next = tp;
X                    pp->body_end = tp;
X                }
X                break;
X        }
X        if (tp == (struct token *)NULL)
X            break;
X    }
X    dont_expand = save_expflag;
X    return pp;
X}   /* end of lex_phrase */
X
Xstruct phrase *lex_sentence(level)
Xint level;
X{
X    register struct phrase *sp;
X    struct phrase *pp,*xpp;
X    struct iotoken *iop;
X    int pcount;
X
X    sp = new_phrase();
X    if (sp == (struct phrase *)NULL)
X    {   /* enough memory? */
X        errmsg(SHERR_NOMEM,LOC("lex_sentence"));
X        return sp;
X    }
X    while ((pp = lex_phrase(level,1)) != (struct phrase *)NULL)
X    {   /* fill out the sentence */
X        if (sp->group == (struct phrase *)NULL &&
X            pp->type != (struct token *)NULL &&
X            pp->type->type == SYM_EOL &&
X            pp->io == (struct iotoken *)NULL &&
X            pp->var == (struct token *)NULL &&
X            pp->body == (struct token *)NULL)
X        {   /* ignore empty line */
X            phrase_free(pp);
X            continue;
X        }
X        if (sp->group_end != (struct phrase *)NULL &&
X            sp->group_end->type != (struct token *)NULL &&
X            sp->group_end->type->type == SYM_PIPE &&
X            pp->type != (struct token *)NULL &&
X            pp->type->type == SYM_EOL &&
X            pp->body == (struct token *)NULL)
X        {   /* reject this phrase, to finish pipe */
X            level = 1;
X            phrase_free(pp);
X            continue;
X        }
X        if (sp->group == (struct phrase *)NULL)
X            sp->group = sp->group_end = pp;
X        else
X        {   /* tack onto end */
X            sp->group_end->next = pp;
X            sp->group_end = pp;
X        }
X        if (pp->group != (struct phrase *)NULL)
X            xpp = pp->group_end;
X        else xpp = pp;
X        if (xpp->type == (struct token *)NULL ||
X            xpp->type->type == SYM_MARKER ||
X            xpp->type->type == SYM_BQUOTE ||
X            xpp->type->type == SYM_EOL)
X        {   /* end of sentence? */
X            pcount = 0;
X            for (pp = sp->group; pp != (struct phrase *)NULL; pp = pp->next)
X            {   /* look for, set up pipes */
X                if ((pp->type != (struct token *)NULL &&
X                    pp->type->type == SYM_PIPE) ||
X                   (pp->group != (struct phrase *)NULL &&
X                    pp->group_end->type != (struct token *)NULL &&
X                    pp->group_end->type->type == SYM_PIPE))
X                {   /* found a pipe */
X                    iop = new_iotoken(16
X#ifdef  GEMDOS
X                                        +strlen(base_env.tmpdir)
X#endif  /* GEMDOS */
X                                                                                 );
X                    if (iop == (struct iotoken *)NULL)
X                    {   /* enough memory */
X                        errmsg(SHERR_NOMEM,LOC("lex_sentence"));
X                        break;
X                    }
X                    iop->fd = 1;
X#ifdef  GEMDOS
X                    sprintf(iop->file,"%spipe%d.tmp",base_env.tmpdir,pcount);
X#else
X                    sprintf(iop->file,"pipe%d",pcount);
X#endif  /* GEMDOS */
X                    iop->type = SYM_PIPE;
X                    if (pp->io == (struct iotoken *)NULL)
X                        pp->io = pp->io_end = iop;
X                    else
X                    {   /* stick on front */
X                        iop->next = pp->io;
X                        pp->io = iop;
X                    }
X                    if (pp->next == (struct phrase *)NULL)
X                    {   /* something to pipe to */
X                        errmsg(0,LOC("lex_sentence"),"missing pipe destination");
X                        continue;
X                    }
X                    iop = new_iotoken(16
X#ifdef  GEMDOS
X                                                                  +strlen(base_env.tmpdir)
X#endif  /* GEMDOS */
X                                                                                 );
X                    if (iop == (struct iotoken *)NULL)
X                    {   /* enough memory */
X                        errmsg(SHERR_NOMEM,LOC("lex_sentence"));
X                        break;
X                    }
X                    iop->fd = 0;
X#ifdef  GEMDOS
X                    sprintf(iop->file,"%spipe%d.tmp",base_env.tmpdir,pcount);
X#else
X                    sprintf(iop->file,"pipe%d",pcount);
X#endif  /* GEMDOS */
X                    iop->type = SYM_PIPER;
X                    if (pp->next->io == (struct iotoken *)NULL)
X                        pp->next->io = pp->next->io_end = iop;
X                    else
X                    {   /* stick on front */
X                        iop->next = pp->next->io;
X                        pp->next->io = iop;
X                    }
X                }
X                pcount++;
X            }
X            pp = sp->group_end;
X            if (pp->type != (struct token *)NULL &&
X                pp->type->type == SYM_BQUOTE)
X            {   /* need to capture output? */
X                iop = new_iotoken(16
X#ifdef  GEMDOS
X                                                              +strlen(base_env.tmpdir)
X#endif  /* GEMDOS */
X                                                                             );
X                if (iop == (struct iotoken *)NULL)
X                {   /* enough memory? */
X                    errmsg(SHERR_NOMEM,LOC("lex_sentence"));
X                }
X                else
X                {   /* fill out, tack on io block */
X                    iop->fd = 1;
X                    iop->type = SYM_RT;
X#ifdef  GEMDOS
X                    sprintf(iop->file,"%stemp%d.tmp",base_env.tmpdir,base_env.temp_count++);
X#else
X                    sprintf(iop->file,"/tmp/sh%d.temp",base_env.temp_count++);
X#endif  /* GEMDOS */
X                    if (pp->io == (struct iotoken *)NULL)
X                        pp->io = pp->io_end = iop;
X                    else
X                    {   /* push onto front */
X                        iop->next = pp->io;
X                        pp->io = iop;
X                    }
X                }
X            }
X            return sp;
X        }
X    }
X    free(sp);
X    return (struct phrase *)NULL;
X}   /* end of lex_sentence */
X
Xint lex_sempty(savep)
Xregister struct strsave *savep;
X{
X    if (strings == (struct strsave *)NULL || strings == savep)
X        return 1;
X    if (strings->next == (struct strsave *)NULL && strings->ptr[0] == ' ' && strings->ptr[1] == '\0')
X        return 1;
X    if (strings->next == savep && strings->ptr[0] == ' ' && strings->ptr[1] == '\0')
X        return 1;
X    return 0;
X}   /* end of lex_sempty */
X
Xstruct token *lex_reparse_tokens(ftp,strip)
Xstruct token *ftp;
Xint strip;
X{
X    register struct token *tp,*stp;
X    struct token *ltp;
X    register struct strsave *sp;
X    struct strsave *savep,*osp,*lsp;
X
X    savep = strings;
X    for (tp = ftp; tp != (struct token *)NULL; tp = tp->next)
X    {   /* go down initial token chain */
X        if (io_pushtoken(tp->name,strip) < 0)
X        {   /* did it work? */
X            for (sp = strings; sp != savep; )
X            {   /* eliminate any junk */
X                osp = sp;
X                sp = sp->next;
X                if (osp->string != (char *)NULL)
X                    free(osp->string);
X                free(osp);
X                strings = savep;
X            }
X            errmsg(0,LOC("lex_reparse_tokens"),"bad return");
X            return (struct token *)NULL;
X        }
X    }
X    osp = (struct strsave *)NULL;
X    for (sp = strings; strings != savep && sp != (struct strsave *)NULL; )
X    {   /* reverse leading part of list */
X        lsp = sp;
X        sp = sp->next;
X        lsp->next = osp;
X        osp = lsp;
X        if (sp == savep)
X            break;
X    }
X    if (osp != (struct strsave *)NULL)
X    {   /* if some items were reversed */
X        strings = osp;
X        for (lsp = osp; lsp->next != (struct strsave *)NULL; lsp = lsp->next)
X            /* do nothing */;
X        lsp->next = savep;
X    }
X
X    stp = ltp = (struct token *)NULL;
X    while (!lex_sempty(savep) && ((tp = lex_token(1)) != (struct token *)NULL))
X    {   /* build the new chain */
X        if (stp == (struct token *)NULL)
X            stp = ltp = tp;
X        else
X        {   /* tack onto end */
X            ltp->next = tp;
X            ltp = tp;
X        }
X    }
X    return stp;
X}   /* end of lex_reparse_tokens */
END_OF_FILE
if test 37330 -ne `wc -c <'lex.c'`; then
    echo shar: \"'lex.c'\" unpacked with wrong size!
fi
# end of 'lex.c'
fi
echo shar: End of archive 9 \(of 11\).
cp /dev/null ark9isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 11 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0



More information about the Alt.sources mailing list