Yet Another Shell (part 10 of 11)

Dave Clemans dclemans.falcon at mntgfx.mentor.com
Thu Mar 16 08:41:08 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 10 (of 11)."
# Contents:  exec.c
# Wrapped by dclemans at dclemans on Wed Mar 15 14:04:01 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'exec.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'exec.c'\"
else
echo shar: Extracting \"'exec.c'\" \(45883 characters\)
sed "s/^X//" >'exec.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 * Command Execution
X *
X * $Id: exec.c,v 1.11 89/03/05 15:38:22 dclemans Exp $
X *
X * $Log:	exec.c,v $
X * Revision 1.11  89/03/05  15:38:22  dclemans
X * more fixes
X * 
X * Revision 1.10  89/02/25  17:40:03  dclemans
X * miscellaneous bug fixes/speedups
X * 
X * Revision 1.9  89/02/22  21:31:56  dclemans
X * Implement simple background job monitoring facility
X * 
X * Revision 1.8  89/02/22  13:19:03  dclemans
X * Implement $!
X * 
X * Revision 1.7  89/02/22  10:16:05  dclemans
X * Fix bugs with process waiting, pid reporting, parsing of &
X * 
X * Revision 1.6  89/02/21  20:29:52  dclemans
X * Fix bug with shell variable references in history lists.
X * 
X * Revision 1.5  89/02/21  08:36:36  dclemans
X * Implement pseudo-signals ERR, EXIT, DEBUG
X * 
X * Revision 1.4  89/02/20  20:14:25  dclemans
X * Add RCS identifiers
X * 
X */
X#include <stdio.h>
X#include "shell.h"
X#ifndef GEMDOS
X#include <errno.h>
X#include <sys/types.h>
X#ifndef USG
X#include <sys/wait.h>
X#include <sys/time.h>
X#include <sys/resource.h>
X#include <sys/file.h>
X#else
X#include <time.h>
X#include <fcntl.h>
X#endif  /* USG */
X#endif  /* GEMDOS */
X
X#ifdef  MWC_ARGV
Xstatic char mwc_iovec[] = "????????????????????????????";
X#endif  /* MWC_ARGV */
X
X#ifndef GEMDOS
Xstatic struct procs *waitStack = (struct procs *)NULL;
Xstatic struct procs *pipeStack = (struct procs *)NULL;
Xstatic struct procs *pipeStack_end;
Xstatic struct procs *bgJobs = (struct procs *)NULL;
X#endif  /* GEMDOS */
X
Xint exec_builtin(cmd,pp,iosetup)
Xchar *cmd;
Xstruct phrase *pp;
Xint iosetup;
X{
X    register int i,rc;
X
X    if (pp->body == (struct token *)NULL)
X        return -1;
X    for (i = 0; cmd_builtin[i].name != (char *)NULL; i++)
X    {   /* is this a builtin command? */
X        rc = strcmp(cmd,cmd_builtin[i].name);
X        if (rc > 0)
X            continue;
X        if (rc < 0)
X            return 0;
X        if (!iosetup)
X        {   /* make our own environment? */
X            if (main_iopush() < 0)
X            {   /* if couldn't save i/o env */
X                /* message already printed */
X                main_iopop();
X                cmd_lastrc = -1;
X                return -1;
X            }
X        }
X        cmd_lastrc = (*cmd_builtin[i].cmd)(pp);
X        if (!iosetup)
X            main_iopop();
X        return 1;
X    }
X    return 0;
X}   /* end of exec_builtin */
X
Xstruct function *func_get(name)
Xchar *name;
X{
X    register struct function *sfp;
X    register int rc;
X
X    for (sfp = base_env.func_table; sfp != (struct function *)NULL; )
X    {   /* look for where to put the function */
X        rc = strcmp(name,sfp->name);
X        if (rc == 0)
X        {   /* found it */
X            return sfp;
X        }
X        else if (rc < 0)
X        {   /* go down the left side? */
X            if (sfp->left == (struct function *)NULL)
X                break;
X            sfp = sfp->left;
X        }
X        else
X        {   /* go down right side */
X            if (sfp->right == (struct function *)NULL)
X                break;
X            sfp = sfp->right;
X        }
X    }
X    return (struct function *)NULL;
X}   /* end of func_get */
X
Xint exec_function(cmd,fpp)
Xchar *cmd;
Xstruct phrase *fpp;
X{
X    register struct function *sfp;
X    register struct phrase *pp,*cpp;
X    struct phrase *lpp;
X
X    sfp = func_get(cmd);
X    if (sfp != (struct function *)NULL)
X    {   /* if the function was found */
X        if (main_iopush() < 0)
X        {   /* if couldn't save i/o env */
X            /* message already printed */
X            main_iopop();
X            cmd_lastrc = -1;
X            return -1;
X        }
X        if (main_varpush() < 0)
X        {   /* if couldn't save var env */
X            /* message already printed */
X            main_iopop();
X            cmd_lastrc = -1;
X            return -1;
X        }
X        if (main_argspush(fpp) < 0)
X        {   /* if couldn't save args env */
X            /* message already printed */
X            main_iopop();
X            main_varpop();
X            cmd_lastrc = -1;
X            return -1;
X        }
X
X        if (sfp->code != (struct phrase *)NULL)
X        for (pp = sfp->code->group; pp != (struct phrase *)NULL; )
X        {   /* execute the sentence */
X            cpp = copy_phrase(pp,1,0,1);
X            lpp = pp;
X            pp = pp->next;
X            if (cpp == (struct phrase *)NULL)
X            {   /* enough memory? */
X                /* message already printed */
X                main_iopop();
X                main_varpop();
X                main_argspop();
X                cmd_lastrc = -1;
X                return -1;
X            }
X            if (flag_echoexec)
X                phrase_dump(cpp,0,0);
X            exec_phrase(cpp,0);
X            if (cpp->body != (struct token *)NULL)
X                var_define0("_",cpp->body_end->name,0);
X            phrase_free(cpp);
X            if (cmd_returnexit)
X                break;
X
X            if (lpp->type != (struct token *)NULL) switch (lpp->type->type)
X            {   /* any special handling? */
X                case SYM_ANDIF:
X                    if (cmd_lastrc != 0 && pp != (struct phrase *)NULL)
X                        pp = pp->next;
X                    break;
X                case SYM_ORIF:
X                    if (cmd_lastrc == 0 && pp != (struct phrase *)NULL)
X                        pp = pp->next;
X                    break;
X            }
X            if (pp == (struct phrase *)NULL)
X                break;
X        }
X        cmd_returnexit = 0;
X        main_iopop();
X        main_varpop();
X        main_argspop();
X        force_signal("EXIT");
X        return 1;
X    }
X    return 0;
X}   /* end of exec_function */
X
Xvoid exec_alias(name,path)
Xchar *name;
Xregister char *path;
X{
X    register char *newpath;
X    register int plen;
X
X    plen = strlen(path);
X    if (strchr(path,DIR_SEPARATOR) == (char *)NULL
X#ifdef  GEMDOS
X        || strchr(path,':') == (char *)NULL
X#endif  /* GEMDOS */
X                            )
X    {   /* if only a partial path name, add on currdir */
X        plen += strlen(base_env.dir->current)+1;
X    }
X    if (flag_cmdhash || alias_tracked(name))
X    {   /* if hashing commands */
X        newpath = new_string(plen+1);
X        if (newpath == (char *)NULL)
X        {   /* enough memory? */
X            errmsg(SHERR_NOMEM,LOC("exec_alias"));
X            return;
X        }
X        if (plen != strlen(path))
X            sprintf(newpath,"%s%c%s",base_env.dir->current,DIR_SEPARATOR,path);
X        else    strcpy(newpath,path);
X        alias_sdefine(name,newpath,TYPE_TRACKED);
X        free(newpath);
X    }
X}   /* end of exec_alias */
X
X#ifndef GEMDOS
Xstatic int savepid(pp,pid)
Xregister struct phrase *pp;
Xint pid;
X{
X    register struct procs *newWait,*ws;
X    char buffer[64];
X
X    if (pp == (struct phrase *)NULL)
X        return;
X    if (pp->type != (struct token *)NULL && pp->type->type != SYM_BACK && pp->type->type != SYM_PIPE)
X    {   /* if need to wait for this job */
X        for (ws = pipeStack; ws != (struct procs *)NULL; )
X        {   /* this job included some previous pipe stuff */
X            newWait = ws;
X            ws = ws->next;
X            newWait->next = waitStack;
X            waitStack = newWait;
X        }
X        pipeStack = pipeStack_end = (struct procs *)NULL;
X        newWait = (struct procs *)malloc(sizeof(*newWait));
X        if (newWait == (struct procs *)NULL)
X        {   /* enough memory? */
X            errmsg(SHERR_NOMEM,LOC("exec_real"));
X            return -1;
X        }
X        newWait->pid = pid;
X        newWait->next = waitStack;
X        waitStack = newWait;
X    }
X    else if (pp->type != (struct token *)NULL && pp->type->type == SYM_PIPE)
X    {   /* save a pipe pid for later reference */
X        newWait = (struct procs *)malloc(sizeof(*newWait));
X        if (newWait == (struct procs *)NULL)
X        {   /* enough memory? */
X            errmsg(SHERR_NOMEM,LOC("exec_real"));
X            return -1;
X        }
X        newWait->pid = pid;
X        newWait->next = (struct procs *)NULL;
X        if (pipeStack == (struct procs *)NULL)
X            pipeStack = pipeStack_end = newWait;
X        else
X        {   /* tack onto end */
X            pipeStack_end->next = newWait;
X            pipeStack_end = newWait;
X        }
X    }
X    else if (pp->type != (struct token *)NULL && pp->type->type == SYM_BACK)
X    {   /* say what we did */
X        for (ws = pipeStack; ws != (struct procs *)NULL; ws = ws->next)
X        {   /* this background job included some previous pipe stuff */
X            sprintf(buffer,"%d ",ws->pid);
X            io_writestring(0,buffer);
X        }
X        bgJobs = pipeStack;
X        pipeStack = pipeStack_end = (struct procs *)NULL;
X        newWait = (struct procs *)malloc(sizeof(*newWait));
X        if (newWait == (struct procs *)NULL)
X        {   /* enough memory? */
X            errmsg(SHERR_NOMEM,LOC("exec_real"));
X            return -1;
X        }
X        newWait->pid = pid;
X        newWait->next = bgJobs;
X        bgJobs = newWait;
X        base_env.background_pid = pid;
X        sprintf(buffer,"%d\n",pid);
X        io_writestring(0,buffer);
X    }
X}   /* end of savepid */
X#endif  /* GEMDOS */
X
X#ifdef  GEMDOS
Xint exec_real(cmd,pp)
Xchar *cmd;
Xstruct phrase *pp;
X{
X    char cmdtail[128];
X    struct token *tp;
X    char *arg,*env,*newenv,*envp;
X    int length,rlength;
X    int warn127;
X
X    var_define0("_",cmd,0);
X    warn127 = 0;
X    cmdtail[1] = '\0';
X    for (tp = pp->body->next; tp != (struct token *)NULL; tp = tp->next)
X    {   /* build a GEMDOS command tail */
X        arg = strcopy(tp->name);
X        if (arg == (char *)NULL)
X        {   /* enough memory? */
X            /* message already printed */
X            return -1;
X        }
X        stripquotes(arg);
X        if (!warn127 && ((strlen(&cmdtail[1])+strlen(arg)+1) > 127))
X        {   /* will it fit? */
X            errmsg(0,LOC("exec_real"),"warning: command args > 127 chars, command may not work");
X            warn127++;
X            break;
X        }
X        if (cmdtail[1] != '\0')
X            strcat(&cmdtail[1]," ");
X        strcat(&cmdtail[1],arg);
X        free(arg);
X    }
X    cmdtail[0] = strlen(&cmdtail[1]);
X    /* build environment variables */
X    env = var_makeenv();
X#ifdef  MWC_ARGV
X    /* add in MWC ARGV */
X    /* iovector: C=console, A=aux, P=printer, F=file */
X    length = 2;
X    if (env != (char *)NULL)
X    {   /* find out how big the environment is */
X        for (envp = env; ; envp++)
X        {   /* until we reach the end */
X            if (envp[0] == '\0' && envp[1] == '\0')
X                break;
X            length++;
X        }
X    }
X    rlength = length;
X    length += 34;       /* add in ARGV=<iovector> */
X    for (tp = pp->body; tp != (struct token *)NULL; tp = tp->next)
X    {   /* get total length of args */
X        length += strlen(tp->name)+1;
X    }
X    newenv = new_string(length);
X    if (newenv == (char *)NULL)
X    {   /* enough memory? */
X        errmsg(SHERR_NOMEM,LOC("exec_real"));
X        if (env != (char *)NULL)
X            free(env);
X        return -1;
X    }
X    newenv[0] = newenv[1] = '\0';
X    if (env != (char *)NULL)
X        memcpy(newenv,env,rlength);
X    for (envp = newenv; ; envp++)
X    {   /* scan for end */
X        if (envp[0] == '\0' && envp[1] == '\0')
X            break;
X    }
X    if (envp != newenv)
X        envp++;
X    sprintf(envp,"ARGV=%s",mwc_iovec);
X    while (*envp)
X        envp++;
X    *envp++;
X    for (tp = pp->body; tp != (struct token *)NULL; tp = tp->next)
X    {   /* now put the args in */
X        strcpy(envp,tp->name);
X        stripquotes(envp);
X        while (*envp)
X            envp++;
X        envp++;
X    }
X    *envp = '\0';
X    if (env != (char *)NULL)
X        free(env);
X    env = newenv;
X#endif  /* MWC_ARGV */
X
X    cmd_lastrc = Pexec(0,cmd,cmdtail,env);
X    if (env != (char *)NULL)
X        free(env);
X    if (NO_FILE(cmd_lastrc))
X        return 0;
X    if (NOT_EXEC(cmd_lastrc) && base_env.shellname != (char *)NULL && strlen(base_env.shellname) != 0)
X    {   /* try as shell file */
X        if (strcmp(pp->body->name,base_env.shellname) == 0)
X            return 0;
X        tp = new_token(strlen(base_env.shellname));
X        if (tp == (struct token *)NULL)
X        {   /* enough memory? */
X            errmsg(SHERR_NOMEM,LOC("exec_real"));
X            return 0;
X        }
X        tp->type = SYM_WORD;
X        strcpy(tp->name,base_env.shellname);
X        tp->next = pp->body;
X        pp->body = tp;
X        length = exec_phrase(pp,1);
X        if (pp->body != (struct token *)NULL)
X            var_define0("_",pp->body_end->name,0);
X        return length;
X    }
X    return 1;
X}   /* end of exec_real */
X#else
Xint exec_real(cmd,pp)
Xchar *cmd;
Xstruct phrase *pp;
X{
X    register struct token *tp;
X    register char *cp;
X    int pid;
X    char *envp,*first;
X    char **arg_vector,**env_vector;
X    int arg_count;
X
X    arg_count = 0;
X    for (tp = pp->body; tp != (struct token *)NULL; tp = tp->next)
X        arg_count++;
X    arg_vector = new_argv(arg_count);
X    if (arg_vector == (char **)NULL)
X    {   /* enough memory? */
X        errmsg(SHERR_NOMEM,LOC("exec_real"));
X        return -1;
X    }
X    arg_count = 0;
X    for (tp = pp->body; tp != (struct token *)NULL; tp = tp->next)
X    {   /* copy in args */
X        stripquotes(tp->name);
X        arg_vector[arg_count++] = tp->name;
X    }
X    arg_vector[arg_count] = (char *)NULL;
X
X    arg_count = 0;
X    envp = var_makeenv();
X    for (cp = envp; ; cp++)
X    {   /* until double null is found */
X        if (*cp == '\0')
X        {   /* found end of one env string */
X            arg_count++;
X            if (*(cp+1) == '\0')
X                break;
X        }
X    }
X    env_vector = new_argv(arg_count);
X    if (env_vector == (char **)NULL)
X    {   /* enough memory? */
X        errmsg(SHERR_NOMEM,LOC("exec_real"));
X        free(arg_vector);
X        return -1;
X    }
X    arg_count = 0;
X    first = envp;
X    for (cp = envp; ; cp++)
X    {   /* until double null is found */
X        if (*cp == '\0')
X        {   /* found end of one env string */
X            env_vector[arg_count++] = first;
X            first = cp+1;
X            if (*first == '\0')
X                break;
X        }
X    }
X    env_vector[arg_count] = (char *)NULL;
X
X    /* exec cmd */
X    pid = fork();
X    if (pid < 0)
X    {   /* can we get a child process? */
X        errmsg(0,LOC("exec_real"),"can't fork to run command");
X        free(env_vector);
X        if (envp != (char *)NULL)
X            free(envp);
X        free(arg_vector);
X        return -1;
X    }
X    if (pid == 0)
X    {   /* this is the child; run the command */
X        cmd_lastrc = execve(cmd,arg_vector,env_vector);
X        if (NO_FILE(cmd_lastrc))
X            exit(-1);
X        if (NOT_EXEC(cmd_lastrc) && base_env.shellname != (char *)NULL && strlen(base_env.shellname) != 0)
X        {   /* try as shell file */
X            if (strcmp(pp->body->name,base_env.shellname) == 0)
X                return 0;
X            tp = pp->body;
X            pp->body = tp->next;
X            free(tp);
X            tp = new_token(strlen(cmd));
X            if (tp == (struct token *)NULL)
X            {   /* enough memory? */
X                errmsg(SHERR_NOMEM,LOC("exec_real"));
X                exit(-1);
X            }
X            tp->type = SYM_WORD;
X            strcpy(tp->name,cmd);
X            tp->next = pp->body;
X            pp->body = tp;
X            tp = new_token(strlen(base_env.shellname));
X            if (tp == (struct token *)NULL)
X            {   /* enough memory? */
X                errmsg(SHERR_NOMEM,LOC("exec_real"));
X                exit(-1);
X            }
X            tp->type = SYM_WORD;
X            strcpy(tp->name,base_env.shellname);
X            tp->next = pp->body;
X            pp->body = tp;
X            pid = exec_phrase(pp,1);
X            if (pp->body != (struct token *)NULL)
X                var_define0("_",pp->body_end->name,0);
X            exit(pid);
X        }
X        exit(-1);
X    }
X
X    free(env_vector);
X    if (envp != (char *)NULL)
X        free(envp);
X    free(arg_vector);
X    savepid(pp,pid);
X
X    return pid;
X}   /* end of exec_real */
X#endif  /* GEMDOS */
X
Xchar *exec_pathsearch(name)
Xchar *name;
X{
X    register char *pf,*pl,*p;
X    char sep;
X#ifdef  GEMDOS
X    char *spf,*spl,*lp;
X#endif  /* GEMDOS */
X    char buffer[BUFSIZ];
X
X#ifdef  GEMDOS
X    sep = ',';
X    spf = spl = base_env.exec_suff;
X#else
X    sep = ':';
X#endif  /* GEMDOS */
X    if (isfullpath(name))
X    {   /* if don't need a path search */
X        strcpy(buffer,name);
X#ifdef  GEMDOS
X        if (strchr(name,'.') == (char *)NULL)
X        {   /* need to add a suffix? */
X            for (lp = buffer; *lp; lp++)
X                /* do nothing */;
X            for (;;)
X            {   /* while there are suffixes */
X                if (*spl != ',' && *spl != '\0')
X                {   /* not there yet? */
X                    spl++;
X                    continue;
X                }
X                strncpy(lp,spf,(int)(spl - spf));
X                lp[(int)(spl - spf)] = '\0';
X                if (isexec(buffer))
X                    return strcopy(buffer);
X                if (*spl == '\0')
X                    break;
X                spl++;
X                spf = spl;
X            }
X        }
X        else if (isexec(buffer))
X            return strcopy(buffer);
X#else
X        if (isexec(buffer))
X            return strcopy(buffer);
X#endif  /* GEMDOS */
X    }
X    pf = pl = base_env.exec_path;
X    for (;;)
X    {   /* look through the path options... */
X        if (*pl != sep && *pl != '\0')
X        {   /* keep going? */
X            pl++;
X            continue;
X        }
X        strncpy(buffer,pf,(int)(pl - pf));
X        buffer[(int)(pl - pf)] = '\0';
X        if ((int)(pl - pf) != 0)
X        {   /* need a dir separator? */
X            for (p = buffer; *p; p++)
X                /* do nothing */;
X            if (p[-1] != DIR_SEPARATOR)
X                *p++ = DIR_SEPARATOR;
X            *p = '\0';
X        }
X        strcat(buffer,name);
X#ifdef  GEMDOS
X        if (strchr(name,'.') == (char *)NULL)
X        {   /* need to add a suffix? */
X            for (lp = buffer; *lp; lp++)
X                /* do nothing */;
X            for (;;)
X            {   /* while there are suffixes */
X                if (*spl != ',' && *spl != '\0')
X                {   /* not there yet? */
X                    spl++;
X                    continue;
X                }
X                strncpy(lp,spf,(int)(spl - spf));
X                lp[(int)(spl - spf)] = '\0';
X                if (isexec(buffer))
X                {   /* if it apparently worked */
X                    exec_alias(name,buffer);
X                    return strcopy(buffer);
X                }
X                if (*spl == '\0')
X                    break;
X                spl++;
X                spf = spl;
X            }
X        }
X        else if (isexec(buffer))
X        {   /* if it apparently worked */
X            exec_alias(name,buffer);
X            return strcopy(buffer);
X        }
X#else
X        if (isexec(buffer))
X        {   /* if it apparently worked */
X            exec_alias(name,buffer);
X            return strcopy(buffer);
X        }
X#endif  /* GEMDOS */
X        if (*pl == '\0')
X            break;
X        pl++;
X        pf = pl;
X#ifdef  GEMDOS
X        spf = spl = base_env.exec_suff;
X#endif  /* GEMDOS */
X    }
X    return (char *)NULL;
X}   /* end of exec_pathsearch */
X
Xint exec_normal(cmd,pp)
Xchar *cmd;
Xstruct phrase *pp;
X{
X    register char *command;
X    int rc;
X
X    command = exec_pathsearch(cmd);
X    if (command == (char *)NULL)
X        return 0;
X    rc = exec_real(command,pp);
X    free(command);
X    return rc;
X}   /* end of exec_normal */
X
X#ifdef  GEMDOS
Xint exec_open(file,type,fd)
Xregister char *file;
Xint type;
Xint fd;
X{
X    int rc,rc1;
X
X    if (strcmp(file,"tty:") == 0 ||
X        strcmp(file,"TTY:") == 0 ||
X        strcmp(file,"CON:") == 0 ||
X        strcmp(file,"con:") == 0)
X    {   /* get console? */
X        rc = Fforce(fd,base_env.fd_con);
X        if (rc < 0)
X            errmsg(SHERR_PERROR,LOC("exec_open"),"can't setup %d<->con:",fd);
X#ifdef  MWC_ARGV
X        else mwc_iovec[fd] = 'C';
X#endif  /* MWC_ARGV */
X        return rc;
X    }
X    if (strcmp(file,"aux:") == 0 ||
X        strcmp(file,"AUX:") == 0)
X    {   /* get aux port */
X        rc = Fforce(fd,base_env.fd_aux);
X        if (rc < 0)
X            errmsg(SHERR_PERROR,LOC("exec_open"),"can't setup %d<->aux:",fd);
X#ifdef  MWC_ARGV
X        else mwc_iovec[fd] = 'A';
X#endif  /* MWC_ARGV */
X        return rc;
X    }
X    if (strcmp(file,"prn:") == 0 ||
X        strcmp(file,"PRN:") == 0 ||
X        strcmp(file,"prt:") == 0 ||
X        strcmp(file,"PRT:") == 0)
X    {   /* get printer */
X        rc = Fforce(fd,base_env.fd_prn);
X        if (rc < 0)
X            errmsg(SHERR_PERROR,LOC("exec_open"),"can't setup %d<->prn:",fd);
X#ifdef  MWC_ARGV
X        else mwc_iovec[fd] = 'P';
X#endif  /* MWC_ARGV */
X        return rc;
X    }
X    rc = -1;
X    switch (type)
X    {   /* what kind of open? */
X        case 0:
X            rc = Fopen(file,0);
X            break;
X        case 1:
X            Fdelete(file);
X            rc = Fcreate(file,0);
X            break;
X        case 2:
X            rc = Fopen(file,1);
X            break;
X    }
X    if (rc < 0)
X    {   /* if didn't work */
X        errmsg(SHERR_PERROR,LOC("exec_open"),"can't open %s",file);
X        return rc;
X    }
X    rc1 = Fforce(fd,rc);
X    if (rc1 < 0)
X    {   /* if didn't work */
X        Fclose(rc);
X        errmsg(SHERR_PERROR,LOC("exec_open"),"can't associate %d<->%s",fd,file);
X        return rc1;
X    }
X    Fclose(rc);
X#ifdef  MWC_ARGV
X    mwc_iovec[fd] = 'F';
X#endif  /* MWC_ARGV */
X    return 0;
X}   /* end of exec_open */
X#endif  /* GEMDOS */
X
Xstatic long fds_opened = 0;
X
Xint exec_ioredir(io)
Xstruct iotoken *io;
X{
X    register struct iotoken *iop;
X
X#ifdef  GEMDOS
X    int rc,tfd,sfd;
X
X    for (iop = io; iop != (struct iotoken *)NULL; iop = iop->next)
X    {   /* for each thing we need to switch */
X        if (iop->fd > MAXUFD)
X            continue;
X        switch (iop->type)
X        {   /* what kind of redirection? */
X            case SYM_LT:
X            case SYM_PIPER:
X                rc = exec_open(iop->file,0,iop->fd);
X                break;
X            case SYM_LLT:
X            case SYM_LLTL:
X                rc = exec_open(iop->tempfile,0,iop->fd);
X                break;
X            case SYM_LBT:
X            case SYM_RBT:
X                tfd = atoi(iop->file);
X                if (tfd > MAXUFD)
X                    continue;
X                rc = Fdup(tfd);
X                if (rc < 0)
X                {   /* did it work? */
X                    errmsg(SHERR_PERROR,LOC("exec_ioredir"),"can't duplicate %d",tfd);
X                    break;
X                }
X                sfd = rc;
X                rc = Fforce(iop->fd,sfd);
X                Fclose(sfd);
X                if (rc < 0)
X                    errmsg(SHERR_PERROR,LOC("exec_ioredir"),"can't associate %d<->%d",iop->fd,tfd);
X                break;
X            case SYM_RT:
X            case SYM_PIPE:
X                rc = exec_open(iop->file,1,iop->fd);
X                if (iop->type == SYM_PIPE)
X                    delete_later(iop->file);
X                break;
X            case SYM_RRT:
X                rc = exec_open(iop->file,2,iop->fd);
X                if (rc >= 0)
X                    rc = Fseek(0L,iop->fd,2);
X                break;
X        }
X        if (rc < 0)
X        {   /* couldn't set up the io */
X            /* message already printed */
X            return rc;
X        }
X        fds_opened |= (1L << (long)iop->fd);
X    }
X    if (!(fds_opened & (1L<<0L)))
X    {   /* was stdin setup */
X        rc = Fforce(0,base_env.io->input);
X        if (rc < 0)
X        {   /* did it work? */
X            errmsg(SHERR_PERROR,LOC("exec_ioredir"),"can't set default stdin");
X            return rc;
X        }
X#ifdef  MWC_ARGV
X        else mwc_iovec[0] = 'C';
X#endif  /* MWC_ARGV */
X        fds_opened |= (1L<<0L);
X    }
X    if (!(fds_opened & (1L<<1L)))
X    {   /* was stdout setup */
X        rc = Fforce(1,base_env.io->output);
X        if (rc < 0)
X        {   /* did it work? */
X            errmsg(SHERR_PERROR,LOC("exec_ioredir"),"can't set default stdout");
X            return rc;
X        }
X#ifdef  MWC_ARGV
X        else mwc_iovec[1] = 'C';
X#endif  /* MWC_ARGV */
X        fds_opened |= (1L<<1L);
X    }
X    if (!(fds_opened & (1L<<2L)))
X    {   /* was stderr setup */
X        rc = Fforce(2,base_env.io->errout);
X        if (rc < 0)
X        {   /* did it work? */
X            errmsg(SHERR_PERROR,LOC("exec_ioredir"),"can't set default stderr");
X            return rc;
X        }
X#ifdef  MWC_ARGV
X        else mwc_iovec[2] = 'C';
X#endif  /* MWC_ARGV */
X        fds_opened |= (1L<<2L);
X    }
X    return 0;
X#else
X    int rc,tfd;
X    static int pipefds[2];
X
X    for (iop = io; iop != (struct iotoken *)NULL; iop = iop->next)
X    {   /* for each thing we need to switch */
X        if (iop->fd > MAXUFD)
X            continue;
X        switch (iop->type)
X        {   /* what kind of redirection? */
X            case SYM_PIPER:
X                rc = 0;
X                if (pipefds[0] < 0)
X                {   /* pipe not created? */
X                    errmsg(0,LOC("exec_ioredir"),"no pipe created to read from");
X                    rc = -1;
X                    break;
X                }
X                if (pipefds[0] != iop->fd)
X                {   /* if need to move fd */
X                    rc = dup2(pipefds[0],iop->fd);
X                    close(pipefds[0]);
X                    main_fdput(pipefds[0]);
X                }
X                pipefds[0] = pipefds[1] = -1;
X                break;
X            case SYM_PIPE:
X                rc = pipe(pipefds);
X                if (rc < 0)
X                {   /* can't set up pipe? */
X                    errmsg(0,LOC("exec_ioredir"),"can't create pipe");
X                    pipefds[0] = pipefds[1] = -1;
X                    break;
X                }
X                if (pipefds[1] != iop->fd)
X                {   /* if need to move fd */
X                    rc = dup2(pipefds[1],iop->fd);
X                    close(pipefds[1]);
X                }
X                if (rc >= 0)
X                {   /* if successful so far, move pipefds[0] out of harms way */
X                    tfd = main_fdget();
X                    rc = dup2(pipefds[0],tfd);
X                    close(pipefds[0]);
X                    if (rc >= 0)
X                    {   /* if everything worked */
X                        pipefds[0] = tfd;
X                        pipefds[1] = iop->fd;
X                    }
X                    else
X                    {   /* it didn't work... */
X                        errmsg(0,LOC("exec_ioredir"),"can't finish off pipe");
X                        pipefds[0] = pipefds[1] = -1;
X                        main_fdput(tfd);
X                        break;
X                    }
X                }
X                break;
X            case SYM_LT:
X                rc = tfd = open(iop->file,O_RDONLY);
X                if (rc >= 0 && rc != iop->fd)
X                {   /* move to correct fd */
X                    rc = dup2(rc,iop->fd);
X                    close(tfd);
X                }
X                if (rc < 0)
X                    errmsg(0,LOC("exec_ioredir"),"can't open file %s",iop->file);
X                break;
X            case SYM_LLT:
X            case SYM_LLTL:
X                rc = tfd = open(iop->tempfile,O_RDONLY);
X                if (rc >= 0 && rc != iop->fd)
X                {   /* move to correct fd */
X                    rc = dup2(rc,iop->fd);
X                    close(tfd);
X                }
X                if (rc < 0)
X                    errmsg(0,LOC("exec_ioredir"),"can't open tempfile %s",iop->tempfile);
X                break;
X            case SYM_LBT:
X            case SYM_RBT:
X                tfd = atoi(iop->file);
X                if (tfd > MAXUFD)
X                    continue;
X                rc = dup2(tfd,iop->fd);
X                if (rc < 0)
X                    errmsg(SHERR_PERROR,LOC("exec_ioredir"),"can't associate %d<->%d",iop->fd,tfd);
X                break;
X            case SYM_RT:
X                rc = tfd = open(iop->file,O_WRONLY|O_CREAT|O_TRUNC,0666);
X                if (rc >= 0 && rc != iop->fd)
X                {   /* move to correct fd */
X                    rc = dup2(rc,iop->fd);
X                    close(tfd);
X                }
X                if (rc < 0)
X                    errmsg(0,LOC("exec_ioredir"),"can't create %s",iop->file);
X                break;
X            case SYM_RRT:
X                rc = tfd = open(iop->file,O_WRONLY|O_CREAT,0666);
X                if (rc >= 0 && rc != iop->fd)
X                {   /* move to correct fd */
X                    rc = dup2(rc,iop->fd);
X                    close(tfd);
X                }
X                if (rc >= 0)
X                    rc = lseek(iop->fd,0L,2);
X                if (rc < 0)
X                    errmsg(0,LOC("exec_ioredir"),"can't create %s",iop->file);
X                break;
X        }
X        if (rc < 0)
X        {   /* couldn't set up the io */
X            /* message already printed */
X            return rc;
X        }
X        fds_opened |= (1L << (long)iop->fd);
X    }
X    if (!(fds_opened & (1L<<0L)))
X    {   /* was stdin setup */
X        rc = dup2(base_env.io->input,0);
X        if (rc < 0)
X        {   /* did it work? */
X            errmsg(SHERR_PERROR,LOC("exec_ioredir"),"can't set default stdin");
X            return rc;
X        }
X        fds_opened |= (1L<<0L);
X    }
X    if (!(fds_opened & (1L<<1L)))
X    {   /* was stdout setup */
X        rc = dup2(base_env.io->output,1);
X        if (rc < 0)
X        {   /* did it work? */
X            errmsg(SHERR_PERROR,LOC("exec_ioredir"),"can't set default stdout");
X            return rc;
X        }
X        fds_opened |= (1L<<1L);
X    }
X    if (!(fds_opened & (1L<<2L)))
X    {   /* was stderr setup */
X        rc = dup2(base_env.io->errout,2);
X        if (rc < 0)
X        {   /* did it work? */
X            errmsg(SHERR_PERROR,LOC("exec_ioredir"),"can't set default stderr");
X            return rc;
X        }
X        fds_opened |= (1L<<2L);
X    }
X    return 0;
X#endif  /* GEMDOS */
X}   /* end of exec_ioredir */
X
Xstatic void exec_iodone()
X{
X    register int i;
X
X    for (i = 0; i <= MAXUFD; i++)
X    {   /* get back to known state */
X        if (fds_opened & (1L<<(long)i))
X        {   /* if it was opened */
X#ifdef  GEMDOS
X#ifdef  MWC_ARGV
X            mwc_iovec[i] = '?';
X#endif  /* MWC_ARGV */
X            Fclose(i);
X#else
X            close(i);
X#endif  /* GEMDOS */
X        }
X    }
X    fds_opened = 0;
X}   /* end of exec_iodone */
X
X#ifndef GEMDOS
Xint exec_waitfor()
X{
X    register int i;
X    int pid;
X    register struct procs *wp,*owp;
X    struct bg_job *jb,*ojb,*ljb;
X#ifndef USG
X    union wait status;
X    struct rusage usage;
X#else
X    int status;
X#endif  /* USG */
X
X    while (waitStack != (struct procs *)NULL)
X    {   /* wait for running jobs that need waiting for */
X#ifndef USG
X        pid = wait3(&status,0,&usage);
X        cmd_lastrc = status.w_T.w_Retcode;
X#else
X        pid = wait(&status);
X        cmd_lastrc = (status >> 8) & 0xFF;
X#endif  /* USG */
X        if (pid <= 0)
X            break;
X        owp = (struct procs *)NULL;
X        for (wp = waitStack; wp != (struct procs *)NULL; )
X        {   /* anything we can delete? */
X            if (wp->pid == pid)
X            {   /* then can delete this entry */
X                if (owp != (struct procs *)NULL)
X                    owp->next = wp->next;
X                else waitStack = wp->next;
X                free(wp);
X                break;
X            }
X            owp = wp;
X            wp = wp->next;
X        }
X        i = 1;
X        for (jb = base_env.jobs; jb != (struct bg_job *)NULL; )
X        {   /* or any background stuff to delete? */
X            ojb = jb;
X            jb = jb->next;
X            owp = (struct procs *)NULL;
X            for (wp = ojb->cmds; wp != (struct procs *)NULL; )
X            {   /* anything we can delete? */
X                if (wp->pid == pid)
X                {   /* then can delete this entry */
X                    if (owp != (struct procs *)NULL)
X                        owp->next = wp->next;
X                    else ojb->cmds = wp->next;
X                    free(wp);
X                    break;
X                }
X                owp = wp;
X                wp = wp->next;
X            }
X            if (ojb->cmds == (struct procs *)NULL)
X            {   /* if this job completely finished */
X                if (flag_monitor)
X                    cmd_jobs_dump(ojb->job,i,"Done");
X                phrase_free(ojb->job);
X                for (ljb = base_env.jobs; ljb != (struct bg_job *)NULL && ljb->next != ojb; ljb = ljb->next)
X                    /* do nothing */;
X                if (ljb != (struct bg_job *)NULL && ljb->next == ojb)
X                    ljb->next = ojb->next;
X                free(ojb);
X                if (ojb == base_env.jobs)
X                    base_env.jobs = jb;
X            }
X            i++;
X        }
X    }
X    return 0;
X}   /* end of exec_waitfor */
X#endif  /* GEMDOS */
X
Xint exec_phrase(pp,iosetup)
Xstruct phrase *pp;
Xint iosetup;
X{
X    int rc,pid,i;
X    char *cmd;
X    register struct token *tp,*ltp,*new;
X    struct token *ftp;
X    struct aliases *ap;
X    struct phrase *lpp,*llpp;
X    int sf,sr;
X
X    for (tp = pp->var; tp != (struct token *)NULL; tp = tp->next)
X    {   /* do any pending var definitions */
X        var_define(tp->name,0,0);
X    }
X    if (!iosetup)
X    {   /* if need redirection */
X        fds_opened = 0;
X        rc = exec_ioredir(pp->io);
X        if (rc != 0)
X        {   /* if the redirection didn't work */
X            /* message already printed */
X            return 1;
X        }
X    }
X    /* Alias expansion */
X    if (pp->body != (struct token *)NULL)
X    {   /* is this an alias */
X        ap = alias_get(pp->body->name);
X        if (ap != (struct aliases *)NULL && ap->tp != (struct token *)NULL)
X        {   /* it is an alias; do the replacement */
X            ftp = ltp = (struct token *)NULL;
X            for (tp = ap->tp; tp != (struct token *)NULL; tp = tp->next)
X            {   /* first make copy of tokens */
X                new = new_token(strlen(tp->name));
X                if (new == (struct token *)NULL)
X                {   /* enough memory? */
X                    errmsg(SHERR_NOMEM,LOC("exec_phrase"));
X                    tokens_free(ftp);
X                    return -1;
X                }
X                new->type = tp->type;
X                strcpy(new->name,tp->name);
X                if (ftp == (struct token *)NULL)
X                    ftp = ltp = new;
X                else
X                {   /* tack onto end */
X                    ltp->next = new;
X                    ltp = new;
X                }
X            }
X            if (ltp != (struct token *)NULL)
X            {   /* if something to substitute with */
X                ltp->next = pp->body->next;
X                tp = pp->body;
X                pp->body = ftp;
X                free(tp);
X            }
X        }
X    }
X    /* Wild card expansion */
X    if (flag_noglob == 0 && pp->body != (struct token *)NULL)
X    {   /* walk through the phrase */
X        tp = pp->body;
X        ltp = (struct token *)NULL;
X        for (tp = tp->next; tp != (struct token *)NULL; tp = tp->next)
X        {   /* do expansion */
X            new = wild_search(tp->name,(struct token **)NULL);
X            if (new == (struct token *)NULL)
X            {   /* if no expansion */
X                ltp = tp;
X                continue;
X            }
X            if (ltp == (struct token *)NULL)
X                pp->body->next = new;
X            else ltp->next = new;
X            ltp = tp;
X            while (new->next != (struct token *)NULL)
X                new = new->next;
X            tp = new;
X            tp->next = ltp->next;
X            free(ltp);
X            ltp = tp;
X        }
X    }
X    if (pp->body != (struct token *)NULL && pp->type != (struct token *)NULL)
X    {   /* if something to run */
X        cmd = strcopy(pp->body->name);
X        if (cmd == (char *)NULL)
X        {   /* enough memory? */
X            /* message already printed */
X            return -1;
X        }
X        rc = exec_function(cmd,pp);
X        if (rc <= 0)
X        {   /* if to try other places */
X            stripquotes(cmd);
X            rc = exec_builtin(cmd,pp,iosetup);
X            if (rc <= 0)
X            {   /* if not builtin, try normal execution */
X                rc = exec_normal(cmd,pp);
X            }
X        }
X        if (rc <= 0)
X        {   /* the command didn't work */
X            errmsg(SHERR_PERROR,LOC("exec_phrase"),"%s: command not found",cmd);
X            cmd_lastrc = 1;
X        }
X        free(cmd);
X    }
X    else    rc = 0;
X    if (pp->type != (struct token *)NULL && pp->type->type == SYM_LPAREN)
X    {   /* exec the contents of the parenthized group */
X#ifdef  GEMDOS
X        if (main_iopush() < 0)
X        {   /* if couldn't save i/o env */
X            /* message already printed */
X            main_iopop();
X            cmd_lastrc = -1;
X            return -1;
X        }
X        if (main_varpush() < 0)
X        {   /* if couldn't save var env */
X            /* message already printed */
X            main_iopop();
X            cmd_lastrc = -1;
X            return -1;
X        }
X        sf = cmd_forceexit;
X        sr = cmd_returnexit;
X        cmd_forceexit = cmd_returnexit = 0;
X        for (lpp = pp->group; lpp != (struct phrase *)NULL; )
X        {   /* exec the contents of the parenthized group */
X            llpp = lpp;
X            lpp = lpp->next;
X            exec_phrase(llpp,0);
X            if (cmd_forceexit || cmd_returnexit)
X                break;
X            if (llpp->body != (struct token *)NULL)
X                var_define0("_",llpp->body_end->name,0);
X        }
X        cmd_forceexit = sf;
X        cmd_returnexit = sr;
X        main_iopop();
X        main_varpop();
X#else
X        pid = fork();
X        if (pid < 0)
X        {   /* can't fork -> can't run */
X            errmsg(0,LOC("exec_phrase"),"can't fork to run parenthesized group of commands");
X        }
X        else if (pid == 0)
X        {   /* run the commands */
X            for (lpp = pp->group; lpp != (struct phrase *)NULL; )
X            {   /* exec the contents of the parenthized group */
X                llpp = lpp;
X                lpp = lpp->next;
X                exec_phrase(llpp,0);
X                if (cmd_forceexit || cmd_returnexit)
X                    break;
X                if (llpp->body != (struct token *)NULL)
X                    var_define0("_",llpp->body_end->name,0);
X            }
X            cmd_forceexit = 1;
X        }
X        else
X        {   /* set up to wait for completion if necessary */
X            for (lpp = pp->group; lpp != (struct phrase *)NULL && lpp->next != (struct phrase *)NULL;
X                lpp = lpp->next)
X                /* do nothing */;
X            savepid(lpp,pid);
X        }
X#endif  /* GEMDOS */
X    }
X    if (!iosetup)
X        exec_iodone();
X#ifndef GEMDOS
X    exec_waitfor();
X#endif  /* GEMDOS */
X    if (cmd_lastrc != 0)
X        force_signal("ERR");
X    force_signal("DEBUG");
X    return rc;
X}   /* end of exec_phrase */
X
Xstatic int empty_sentence(sp)
Xregister struct phrase *sp;
X{
X    if (sp->group == (struct phrase *)NULL)
X        return 1;
X    if (sp->group != (struct phrase *)NULL &&
X        sp->group == sp->group_end &&
X        sp->group->io == (struct iotoken *)NULL &&
X        sp->group->body == (struct token *)NULL &&
X        sp->group->var == (struct token *)NULL &&
X        sp->group->type != (struct token *)NULL &&
X        sp->group->type->type == SYM_EOL)
X        return 1;
X    return 0;
X}   /* end of empty_sentence */
X
Xint exec_sentence(sp,iosetup)
Xstruct phrase *sp;
Xint iosetup;
X{
X    register struct phrase *pp,*lpp;
X#ifndef GEMDOS
X    struct procs *wp,*owp;
X    struct bg_job *job,*jl;
X#endif  /* GEMDOS */
X    int rc;
X
X#ifndef GEMDOS
X    for (wp = bgJobs; wp != (struct procs *)NULL; )
X    {   /* delete any current stuff */
X        owp = wp;
X        wp = wp->next;
X        free(owp);
X    }
X    bgJobs = (struct procs *)NULL;
X#endif  /* GEMDOS */
X
X    if (empty_sentence(sp))
X        return 0;
X    if (flag_echoexec)
X        sentence_dump(sp);
X    base_env.break_level = base_env.continue_level = 0;
X    for (pp = sp->group; pp != (struct phrase *)NULL; )
X    {   /* for each part of sentence */
X        lpp = pp;
X        pp = pp->next;
X        if (flag_noexec)
X            continue;
X        lpp = copy_phrase(lpp,1,0,1);
X        if (lpp == (struct phrase *)NULL)
X        {   /* enough memory? */
X            /* message already printed */
X            continue;
X        }
X        if (lpp->type != (struct token *)NULL &&
X            lpp->type->type == SYM_SEMI &&
X            lpp->type->name[0] == '\0')
X            rc = exec_sentence(lpp,iosetup);
X        else rc = exec_phrase(lpp,iosetup);
X        if (lpp->body != (struct token *)NULL)
X            var_define0("_",lpp->body_end->name,0);
X        if (rc < 0)
X        {   /* abort this sentence? */
X            phrase_free(lpp);
X            continue;
X        }
X        if (base_env.break_level > 0 || base_env.continue_level > 0)
X        {   /* break out of sentence? */
X            phrase_free(lpp);
X            break;
X        }
X
X        if (lpp->type != (struct token *)NULL) switch (lpp->type->type)
X        {   /* any special handling? */
X            case SYM_ANDIF:
X                if (cmd_lastrc != 0 && pp != (struct phrase *)NULL)
X                    pp = pp->next;
X                break;
X            case SYM_ORIF:
X                if (cmd_lastrc == 0 && pp != (struct phrase *)NULL)
X                    pp = pp->next;
X                break;
X        }
X        phrase_free(lpp);
X        if (pp == (struct phrase *)NULL)
X            break;
X    }
X#ifndef GEMDOS
X    if (bgJobs != (struct procs *)NULL)
X    {   /* if part of this sentence is running in the background */
X        for (jl = base_env.jobs; jl != (struct bg_job *)NULL && jl->next != (struct bg_job *)NULL; jl = jl->next)
X            /* do nothing */;
X        job = (struct bg_job *)malloc(sizeof(*job));
X        if (job != (struct bg_job *)NULL)
X        {   /* enough memory? */
X            job->next = (struct bg_job *)NULL;
X            job->cmds = bgJobs;
X            bgJobs = (struct procs *)NULL;
X            job->job = copy_group(sp,0,0,1);
X            if (base_env.jobs == (struct bg_job *)NULL)
X                base_env.jobs = job;
X            else
X            {   /* tack onto end */
X                jl->next = job;
X            }
X        }
X        else
X        {   /* out of memory */
X            errmsg(SHERR_NOMEM,LOC("exec_sentence"));
X        }
X    }
X#endif  /* GEMDOS */
X    if (cmd_forceexit || cmd_returnexit)
X        return 1;
X    return 0;
X}   /* end of exec_sentence */
X
Xvoid phrase_dump(pp,printbody,pad)
Xstruct phrase *pp;
Xint printbody;
Xint pad;
X{
X    register struct token *tp;
X    register struct iotoken *iop;
X    register struct phrase *cpp;
X    char buffer[16];
X    int i,flag;
X
X    if (pp == (struct phrase *)NULL)
X        return;
X    flag = 0;
X    for (tp = pp->var; tp != (struct token *)NULL; tp = tp->next)
X    {
X        io_writestring(0,tp->name);
X        if (tp->next != (struct token *)NULL)
X            io_writestring(0," ");
X        flag++;
X    }
X    for (tp = pp->body; tp != (struct token *)NULL; tp = tp->next)
X    {
X        io_writestring(0,tp->name);
X        if (tp->next != (struct token *)NULL)
X            io_writestring(0," ");
X        flag++;
X    }
X    for (iop = pp->io; iop != (struct iotoken *)NULL; iop = iop->next)
X    {   /* io redirections? */
X        if (iop->type != SYM_PIPE && iop->type != SYM_PIPER)
X        {   /* what fd is used? */
X            sprintf(buffer," %d",iop->fd);
X            io_writestring(0,buffer);
X            flag++;
X        }
X        switch (iop->type)
X        {   /* what action? */
X            case SYM_LT:
X                io_writestring(0,"<");
X                flag++;
X                break;
X            case SYM_LLT:
X                io_writestring(0,"<<");
X                flag++;
X                break;
X            case SYM_LLTL:
X                io_writestring(0,"<<-");
X                flag++;
X                break;
X            case SYM_LBT:
X                io_writestring(0,"<&");
X                flag++;
X                break;
X            case SYM_RT:
X                io_writestring(0,">");
X                flag++;
X                break;
X            case SYM_RRT:
X                io_writestring(0,">>");
X                flag++;
X                break;
X            case SYM_RBT:
X                io_writestring(0,">&");
X                flag++;
X                break;
X            case SYM_PIPE:
X            case SYM_PIPER:
X                break;
X        }
X        if (iop->type != SYM_PIPE && iop->type != SYM_PIPER)
X        {   /* file being accessed */
X            io_writestring(0,iop->file);
X            if (strlen(iop->file) > 0)
X                flag++;
X        }
X    }
X    if (pp->type != (struct token *)NULL && pp->type->type != SYM_BQUOTE &&
X        strlen(pp->type->name) > 0 && pp->type->type != SYM_EOL)
X    {   /* if phrase type printable, print it */
X        if (flag)
X            io_writestring(0," ");
X        io_writestring(0,pp->type->name);
X    }
X    else if (pp->type != (struct token *)NULL && pp->type->type == SYM_EOL)
X    {   /* add in eol if needed */
X        io_writestring(0,"\n");
X    }
X    for (cpp = pp->group; printbody && cpp != (struct phrase *)NULL; cpp = cpp->next)
X    {   /* dump out contents of group */
X        for (i = 0; flag && i < pad; i++)
X            io_writestring(0," ");
X        phrase_dump(cpp,printbody,pad);
X    }
X}   /* end of phrase_dump */
X
Xvoid sentence_dump(sp)
Xstruct phrase *sp;
X{
X    register struct phrase *pp;
X    register struct phrase *fsp;
X    int len;
X
X    for (fsp = sp; fsp != (struct phrase *)NULL; fsp = fsp->next)
X    {
X        len = io_prompt(3);
X        for (pp = fsp->group; pp != (struct phrase *)NULL; pp = pp->next)
X        {
X            phrase_dump(pp,1,len);
X        }
X    }
X}   /* end of sentence_dump */
END_OF_FILE
if test 45883 -ne `wc -c <'exec.c'`; then
    echo shar: \"'exec.c'\" unpacked with wrong size!
fi
# end of 'exec.c'
fi
echo shar: End of archive 10 \(of 11\).
cp /dev/null ark10isdone
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