Yet Another Shell (part 8 of 11)

Dave Clemans dclemans.falcon at mntgfx.mentor.com
Thu Mar 16 08:37:24 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 8 (of 11)."
# Contents:  cmd2.c
# Wrapped by dclemans at dclemans on Wed Mar 15 14:03:59 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'cmd2.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cmd2.c'\"
else
echo shar: Extracting \"'cmd2.c'\" \(36160 characters\)
sed "s/^X//" >'cmd2.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 * Built-in Commands (part 2)
X *
X * $Id: cmd2.c,v 1.8 89/03/05 15:37:54 dclemans Exp $
X *
X * $Log:	cmd2.c,v $
X * Revision 1.8  89/03/05  15:37:54  dclemans
X * more fixes
X * 
X * Revision 1.7  89/02/25  17:39:55  dclemans
X * miscellaneous bug fixes/speedups
X * 
X * Revision 1.6  89/02/22  21:31:52  dclemans
X * Implement simple background job monitoring facility
X * 
X * Revision 1.5  89/02/21  20:29:10  dclemans
X * Fix bug with shell variable references in history lists.
X * 
X * Revision 1.4  89/02/20  20:14:18  dclemans
X * Add RCS identifiers
X * 
X */
X#include <stdio.h>
X#ifndef GEMDOS
X#include <sys/types.h>
X#endif  /* GEMDOS */
X#include <time.h>
X#include "shell.h"
X
Xstatic int run_phrase(pp)
Xstruct phrase *pp;
X{
X    register struct phrase *cpp;
X
X    cpp = copy_phrase(pp,1,0,1);
X    if (cpp == (struct phrase *)NULL)
X    {   /* enough memory? */
X        /* message already printed */
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    return 0;
X}   /* end of run_phrase */
X
Xstatic int run_args(pp)
Xstruct phrase *pp;
X{
X    register struct phrase *cpp;
X    register struct token *tp;
X    register struct iotoken *iop;
X
X    tp = pp->body;
X    pp->body = tp->next;
X    iop = pp->io;
X    pp->io = (struct iotoken *)NULL;
X
X    cpp = copy_phrase(pp,1,1,0);
X    if (cpp == (struct phrase *)NULL)
X    {   /* enough memory? */
X        /* message already printed */
X        pp->body = tp;
X        pp->io = iop;
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    pp->body = tp;
X    pp->io = iop;
X    return 0;
X}   /* end of run_args */
X
Xstatic int run_group(npp)
Xregister struct phrase *npp;
X{
X    for (; npp != (struct phrase *)NULL; npp = npp->next)
X    {   /* finally, do the execution */
X        if (run_phrase(npp))
X            return 1;
X        if (npp->type != (struct token *)NULL) switch (npp->type->type)
X        {   /* any special handling? */
X            case SYM_ANDIF:
X                if (cmd_lastrc != 0 && npp != (struct phrase *)NULL)
X                    npp = npp->next;
X                break;
X            case SYM_ORIF:
X                if (cmd_lastrc == 0 && npp != (struct phrase *)NULL)
X                    npp = npp->next;
X                break;
X        }
X        if (npp == (struct phrase *)NULL)
X            break;
X        if (cmd_returnexit)
X            break;
X        if (base_env.break_level > 0)
X            break;
X        if (base_env.continue_level > 0)
X            break;
X    }
X    return 0;
X}   /* end of run_group */
X
Xint cmd_for(pp)
Xregister struct phrase *pp;
X{
X    register struct token *tp,*args;
X    int ctr;
X
X    if (pp->body->next == (struct token *)NULL)
X    {   /* missing operands? */
X        errmsg(0,LOC("cmd_for"),"no operands to iterate over");
X        return 1;
X    }
X    tp = pp->body->next;
X    if (tp->next == (struct token *)NULL)
X    {   /* iterate over positional args? */
X        for (ctr = 1; ctr < var_argc; ctr++)
X        {   /* for each known arg */
X            var_define0(tp->name,var_argv[ctr],0);
X            if (run_group(pp->group))
X                break;
X            if (cmd_returnexit)
X                break;
X            if (base_env.break_level > 0)
X            {   /* if breaking */
X                base_env.break_level--;
X                break;
X            }
X            if (base_env.continue_level > 0)
X            {   /* if continuing */
X                base_env.continue_level--;
X                if (base_env.continue_level > 0)
X                    break;
X            }
X        }
X        return cmd_lastrc;
X    }
X    if (strcmp(tp->next->name,"in") != 0)
X    {   /* good separator? */
X        errmsg(0,LOC("cmd_for"),"bad for usage: for <var> in <args>");
X        return 1;
X    }
X    args = lex_reparse_tokens(tp->next->next,1);
X    while (args != (struct token *)NULL)
X    {   /* while there are args to iterate over */
X        var_define0(tp->name,args->name,0);
X        if (run_group(pp->group))
X            break;
X        args = args->next;
X        if (cmd_returnexit)
X            break;
X        if (base_env.break_level > 0)
X        {   /* if breaking */
X            base_env.break_level--;
X            break;
X        }
X        if (base_env.continue_level > 0)
X        {   /* if continuing */
X            base_env.continue_level--;
X            if (base_env.continue_level > 0)
X                break;
X        }
X    }
X    if (args != (struct token *)NULL)
X        tokens_free(args);
X    return cmd_lastrc;
X}   /* end of cmd_for */
X
Xstatic int select_menu(atp)
Xstruct token *atp;
X{
X    register int ctr,i;
X    int options,maxlength,ncol;
X    register struct token *tp;
X    char **args;
X    char *p,*savep;
X    char buffer[BUFSIZ];
X
X    maxlength = 0;
X    if (atp == (struct token *)NULL)
X    {   /* look at positional args */
X        options = var_argc-1;
X        for (ctr = 1; ctr <= options; ctr++)
X            if (strlen(var_argv[ctr]) > maxlength)
X                maxlength = strlen(var_argv[ctr]);
X        args = var_argv;
X    }
X    else
X    {   /* look at token args */
X        options = 0;
X        for (tp = atp; tp != (struct token *)NULL; tp = tp->next)
X        {   /* count, check max length */
X            options++;
X            if (strlen(tp->name) > maxlength)
X                maxlength = strlen(tp->name);
X        }
X        ctr = 1;
X        args = new_argv(options+1);
X        if (args == (char **)NULL)
X        {   /* enough memory? */
X            errmsg(SHERR_NOMEM,LOC("select_menu"));
X            return -1;
X        }
X        for (tp = atp; tp != (struct token *)NULL; tp = tp->next)
X        {   /* build a fake argv */
X            args[ctr] = tp->name;
X            ctr++;
X        }
X    }
X    maxlength += 7;     /* space for menu #, column separation */
X
X    for (;;)
X    {   /* until we get eof or a good menu response */
X        ncol = base_env.columns / maxlength;
X        if ((options < (base_env.lines*2/3)) || (ncol < 1))
X        {   /* just a single list? */
X            for (ctr = 1; ctr <= options; ctr++)
X            {   /* print the menu */
X                sprintf(buffer,"%d) %s\n",ctr,args[ctr]);
X                io_writestring(0,buffer);
X            }
X        }
X        else
X        {   /* a multi-column list? */
X            for (ctr = 1; ctr <= options; )
X            {   /* build lines... */
X                p = buffer;
X                *p = '\0';
X                for (i = 0; i < ncol && (ctr+i) <= options; i++)
X                {   /* for each column */
X                    sprintf(p,"%d) %s",ctr+i,args[ctr+i]);
X                    savep = p;
X                    while (*p)
X                        p++;
X                    while ((int)(p - savep) < maxlength)
X                        *p++ = ' ';
X                    *p = '\0';
X                }
X                ctr += ncol;
X                strcpy(p,"\n");
X                io_writestring(0,buffer);
X            }
X        }
X        io_prompt(2);
X        ctr = read(base_env.io->input,buffer,sizeof buffer);
X        if (ctr <= 0)
X        {   /* eof yet? */
X            if (atp != (struct token *)NULL)
X                free(args);
X            return ctr;
X        }
X        buffer[ctr] = '\0';
X        for (p = buffer; *p; p++)
X#ifdef  GEMDOS
X            if (*p == '\n' || *p == '\r')
X#else
X            if (*p == '\n')
X#endif  /* GEMDOS */
X                *p = '\0';
X        for (p = buffer; *p && isspace(*p); p++)
X            /* do nothing */;
X        ctr = atoi(p);
X        if (ctr > 0 && ctr <= options)
X        {   /* a selection made? */
X            if (atp != (struct token *)NULL)
X                free(args);
X            return ctr;
X        }
X    }
X}   /* end of select_menu */
X
Xint cmd_select(pp)
Xregister struct phrase *pp;
X{
X    register struct token *tp,*args;
X    struct token *atp;
X    int ctr;
X
X    if (pp->body->next == (struct token *)NULL)
X    {   /* missing operands? */
X        errmsg(0,LOC("cmd_select"),"no operands to iterate over");
X        return 1;
X    }
X    tp = pp->body->next;
X    if (tp->next == (struct token *)NULL)
X    {   /* iterate over positional args? */
X        while ((ctr = select_menu((struct token *)NULL)) > 0)
X        {   /* for each known arg */
X            var_define0(tp->name,var_argv[ctr],0);
X            if (run_group(pp->group))
X                break;
X            if (cmd_returnexit)
X                break;
X        }
X        return cmd_lastrc;
X    }
X    if (strcmp(tp->next->name,"in") != 0)
X    {   /* good separator? */
X        errmsg(0,LOC("cmd_select"),"bad select usage: select <var> in <args>");
X        return 1;
X    }
X    args = lex_reparse_tokens(tp->next->next,1);
X    while (args != (struct token *)NULL && (ctr = select_menu(args)) > 0)
X    {   /* while there are args to iterate over */
X        for (atp = args; ctr > 1; ctr--)
X            atp = atp->next;
X        var_define0(tp->name,atp->name,0);
X        var_define0("REPLY",atp->name,0);
X        if (run_group(pp->group))
X            break;
X        if (cmd_returnexit)
X            break;
X    }
X    if (args != (struct token *)NULL)
X        tokens_free(args);
X    return cmd_lastrc;
X}   /* end of cmd_select */
X
Xint cmd_while(pp)
Xregister struct phrase *pp;
X{
X    register char *cmd;
X    int until;
X
X    until = 0;
X    cmd = strcopy(pp->body->name);
X    if (cmd != (char *)NULL)
X    {   /* if we got the copy */
X        stripquotes(cmd);
X        if (strcmp(cmd,"until") == 0)
X            until = 1;
X        free(cmd);
X    }
X    if (pp->body->next == (struct token *)NULL)
X    {   /* missing operands? */
X        errmsg(0,LOC("cmd_while"),"no operands to loop over");
X        return 1;
X    }
X
X    for (;;)
X    {   /* while we have to loop */
X        if (run_args(pp))
X            return 1;
X        if (!until && cmd_lastrc != 0)
X            break;
X        if (until && cmd_lastrc == 0)
X            break;
X
X        if (run_group(pp->group))
X            break;
X        if (cmd_returnexit)
X            break;
X        if (base_env.break_level > 0)
X        {   /* if breaking */
X            base_env.break_level--;
X            break;
X        }
X        if (base_env.continue_level > 0)
X        {   /* if continuing */
X            base_env.continue_level--;
X            if (base_env.continue_level > 0)
X                break;
X        }
X    }
X    return cmd_lastrc;
X}   /* end of cmd_while */
X
Xint cmd_if(pp)
Xstruct phrase *pp;
X{
X    register struct phrase *npp;
X    int condition;
X
X    if (pp->body->next == (struct token *)NULL)
X    {   /* missing operands? */
X        errmsg(0,LOC("cmd_if"),"no condition to test");
X        return 1;
X    }
X    if (run_args(pp))
X        return 1;
X    condition = cmd_lastrc;
X
X    for (npp = pp->group; npp != (struct phrase *)NULL; npp = npp->next)
X    {   /* finally execute the sentence */
X        if (npp->body != (struct token *)NULL)
X        {   /* check for else, etc. */
X            if (strcmp(npp->body->name,"else") == 0)
X                condition = !condition;
X            else if (strcmp(npp->body->name,"elif") == 0)
X            {   /* an else-if test... */
X                if (npp->body->next == (struct token *)NULL)
X                {   /* missing operands? */
X                    errmsg(0,LOC("cmd_if"),"no condition to test");
X                    return 1;
X                }
X                if (run_args(npp))
X                    return 1;
X                condition = cmd_lastrc;
X            }
X        }
X        if (condition)
X            continue;
X        if (run_phrase(npp))
X            return 1;
X    }
X    return cmd_lastrc;
X}   /* end of cmd_if */
X
Xint cmd_function(pp)
Xstruct phrase *pp;
X{
X    register struct function *fp,*sfp;
X    register struct token *tp;
X    int rc;
X
X    tp = pp->body->next;
X    if (tp == (struct token *)NULL)
X    {   /* if no name, just dump table */
X        errmsg(0,LOC("cmd_function"),"unnamed functions are illegal");
X        return 1;
X    }
X
X    fp = new_function();
X    if (fp == (struct function *)NULL)
X    {   /* enough memory? */
X        errmsg(SHERR_NOMEM,LOC("cmd_function"));
X        return -1;
X    }
X    fp->code = copy_phrase(pp,0,0,1);
X    if (fp->code == (struct phrase *)NULL)
X    {   /* enough memory? */
X        /* message already printed */
X        free(fp);
X        return -1;
X    }
X
X    for (sfp = base_env.func_table; sfp != (struct function *)NULL; )
X    {   /* look for where to put the function */
X        rc = strcmp(tp->name,sfp->name);
X        if (rc == 0)
X        {   /* replace existing value */
X            if (sfp->code != (struct phrase *)NULL)
X                phrase_free(sfp->code);
X            sfp->code = fp->code;
X            free(fp);
X            return 0;
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    fp->name = strcopy(tp->name);
X    if (fp->name == (char *)NULL)
X    {   /* enough memory? */
X        /* message already printed */
X        phrase_free(fp->code);
X        free(fp);
X        return -1;
X    }
X    if (base_env.func_table == (struct function *)NULL)
X        base_env.func_table = fp;
X    else if (rc < 0)
X        sfp->left = fp;
X    else
X        sfp->right = fp;
X    return 0;
X}   /* end of cmd_function */
X
Xint cmd_case(pp)
Xstruct phrase *pp;
X{
X    register struct token *tp;
X    register struct phrase *npp,*cpp;
X    char *exp;
X    int match,state;
X
X    tp = pp->body->next;
X    if (tp == (struct token *)NULL)
X    {   /* if no operand to switch on */
X        errmsg(0,LOC("cmd_case"),"no operands for comparison");
X        return -1;
X    }
X    exp = tp->name;
X
X    match = state = 0;
X    cpp = (struct phrase *)NULL;
X    for (npp = pp->group; npp != (struct phrase *)NULL; )
X    {   /* step through the case */
X        if (cpp != (struct phrase *)NULL)
X            phrase_free(cpp);
X        if (npp->next == (struct phrase *)NULL)
X            break;
X        cpp = copy_phrase(npp,1,0,1);
X        npp = npp->next;
X        if (state == 0)
X        {   /* if looking for case match */
X            if (cpp->type == (struct token *)NULL)
X                continue;
X            if (cpp->type->type == SYM_EOL &&
X                cpp->body == (struct token *)NULL &&
X                cpp->io == (struct iotoken *)NULL)
X                continue;
X            if (cpp->type->type != SYM_PIPE && cpp->type->type != SYM_RPAREN)
X            {   /* bad syntax... */
X                errmsg(0,LOC("cmd_case"),"bad case argument");
X                return -1;
X            }
X            if (!match)
X            {   /* a case match? */
X                if (cpp->body != (struct token *)NULL)
X                {   /* try a wild-card match */
X                    match = wild_match(exp,cpp->body->name);
X                }
X            }
X            if (cpp->type->type == SYM_RPAREN)
X            {   /* end of match stuff */
X                if (match)
X                    state = 1;
X                else state = -1;
X                continue;
X            }
X        }
X        if (state == 0)
X        {   /* if still looking */
X            continue;
X        }
X        if (state < 0)
X        {   /* if skipping some sentences */
X            if (cpp->type == (struct token *)NULL)
X                continue;
X            if (cpp->type->type == SYM_DSEMI)
X            {   /* end of group? */
X                state = 0;
X            }
X            continue;
X        }
X        /* else actually exec some sentences */
X        if (cpp->type == (struct token *)NULL)
X            continue;
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        if (cmd_returnexit)
X            break;
X        if (base_env.break_level > 0)
X        {   /* if breaking */
X            base_env.break_level--;
X            break;
X        }
X        if (base_env.continue_level > 0)
X        {   /* if continuing */
X            base_env.continue_level--;
X            if (base_env.continue_level > 0)
X                break;
X        }
X        if (cpp->type->type == SYM_DSEMI)
X        {   /* end of group? */
X            phrase_free(cpp);
X            return cmd_lastrc;
X        }
X    }
X
X    return cmd_lastrc;
X}   /* end of cmd_case */
X
Xint cmd_break(pp)
Xstruct phrase *pp;
X{
X    if (pp->body->next == (struct token *)NULL)
X        base_env.break_level = 1;
X    else    base_env.break_level = atoi(pp->body->next->name);
X    return 0;
X}   /* end of cmd_break */
X
Xint cmd_continue(pp)
Xstruct phrase *pp;
X{
X    if (pp->body->next == (struct token *)NULL)
X        base_env.continue_level = 1;
X    else    base_env.continue_level = atoi(pp->body->next->name);
X    return 0;
X}   /* end of cmd_continue */
X
Xint cmd_return(pp)
Xstruct phrase *pp;
X{
X    if (pp->body->next != (struct token *)NULL)
X        cmd_lastrc = atoi(pp->body->next->name);
X    cmd_returnexit = 1;
X}   /* end of cmd_return */
X
Xstatic void cmd_fc_dump(curr,nonum)
Xstruct hist_phrase *curr;
Xint nonum;
X{
X    char buffer[16];
X    register struct phrase *pp;
X
X    if (curr->cmd == (struct phrase *)NULL)
X        return;
X    if (!nonum)
X    {   /* print out the command number? */
X        sprintf(buffer,"%-5d",curr->number);
X        io_writestring(0,buffer);
X    }
X    for (pp = curr->cmd; pp != (struct phrase *)NULL; pp = pp->next)
X    {   /* dump out the lines */
X        phrase_dump(pp,1,5);
X        if (pp->next != (struct phrase *)NULL)
X            io_writestring(0,"\n     ");
X    }
X}   /* end of cmd_fc_dump */
X
Xstatic struct phrase *cmd_fc_edit(first,last,edit)
Xstruct hist_phrase *first;
Xstruct hist_phrase *last;
Xchar *edit;
X{
X    register struct hist_phrase *curr;
X    int save_output;
X    char *editor;
X    register struct phrase *torun,*toend;
X    struct phrase *pp;
X    struct token *tp;
X
X    editor = edit;
X    if (editor == (char *)NULL)
X        editor = var_normal("$FCEDIT");
X    if (editor == (char *)NULL)
X        editor = var_normal("$VISUAL");
X    if (editor == (char *)NULL)
X        editor = var_normal("$EDITOR");
X    if (editor == (char *)NULL)
X    {   /* any editor selected? */
X        errmsg(0,LOC("cmd_fc_edit"),"no editor available to edit commands");
X        return (struct phrase *)NULL;
X    }
X    torun = new_phrase();
X    if (torun == (struct phrase *)NULL)
X    {   /* enough memory? */
X        errmsg(SHERR_NOMEM,LOC("cmd_fc_edit"));
X        return (struct phrase *)NULL;
X    }
X    tp = new_token(1);
X    if (tp == (struct token *)NULL)
X    {   /* enough memory? */
X        errmsg(SHERR_NOMEM,LOC("cmd_fc_edit"));
X        free(torun);
X        return (struct phrase *)NULL;
X    }
X    tp->type = SYM_EOL;
X    strcpy(tp->name,"\n");
X    torun->type = tp;
X    tp = new_token(strlen(editor));
X    if (tp == (struct token *)NULL)
X    {   /* enough memory? */
X        errmsg(SHERR_NOMEM,LOC("cmd_fc_edit"));
X        phrase_free(torun);
X        return (struct phrase *)NULL;
X    }
X    tp->type = SYM_WORD;
X    strcpy(tp->name,editor);
X    torun->body = torun->body_end = tp;
X    tp = new_token(16
X#ifdef  GEMDOS
X                     +strlen(base_env.tmpdir)
X#endif  /* GEMDOS */
X                                             );
X    if (tp == (struct token *)NULL)
X    {   /* enough memory? */
X        errmsg(SHERR_NOMEM,LOC("cmd_fc_edit"));
X        phrase_free(torun);
X        return (struct phrase *)NULL;
X    }
X    tp->type = SYM_WORD;
X#ifdef  GEMDOS
X    sprintf(tp->name,"%stemp%d.tmp",base_env.tmpdir,base_env.temp_count++);
X#else
X    sprintf(tp->name,"/tmp/sh%d.temp",base_env.temp_count++);
X#endif  /* GEMDOS */
X    torun->body_end->next = tp;
X    torun->body_end = tp;
X    if (edit == (char *)NULL)
X        free(editor);
X
X    save_output = base_env.io->output;
X    base_env.io->output = creat(tp->name,0666);
X    if (base_env.io->output < 0)
X    {   /* did we get a temporary file? */
X        errmsg(0,LOC("cmd_fc_edit"),"unable to open tempfile");
X        phrase_free(torun);
X        return (struct phrase *)NULL;
X    }
X    if (first < last) for (curr = first; curr <= last; curr++)
X        cmd_fc_dump(curr,1);
X    else for (curr = last; curr >= first; curr--)
X        cmd_fc_dump(curr,1);
X    close(base_env.io->output);
X    base_env.io->output = save_output;
X
X    phrase_dump(torun,1,0);
X    exec_phrase(torun,1);
X    phrase_free(torun);
X
X    if (io_pushfile(tp->name,1,0,1) < 0)
X    {   /* if saving the file failed */
X        errmsg(0,LOC("cmd_fc_edit"),"unable to put tempfile into input stream");
X        delete_later(tp->name);
X        return (struct phrase *)NULL;
X    }
X    torun = toend = (struct phrase *)NULL;
X    while ((pp = lex_phrase(1,0)) != (struct phrase *)NULL)
X    {   /* get back contents of file */
X        if (pp->type != (struct token *)NULL && pp->type->type == SYM_MARKER)
X        {   /* reached end of file */
X            phrase_free(pp);
X            break;
X        }
X        if (torun == (struct phrase *)NULL)
X            torun = toend = pp;
X        else
X        {   /* tack onto end */
X            toend->next = pp;
X            toend = pp;
X        }
X    }
X    return torun;
X}   /* end of cmd_fc_edit */
X
Xstatic int cmd_fc_copy(curr,cpp,lcpp)
Xstruct hist_phrase *curr;
Xstruct phrase **cpp;
Xstruct phrase **lcpp;
X{
X    register struct phrase *pp,*np;
X
X    if (curr->cmd == (struct phrase *)NULL)
X        return 0;
X    for (pp = curr->cmd; pp != (struct phrase *)NULL; pp = pp->next)
X    {   /* copy block of phrases */
X        np = copy_phrase(pp,0,0,1);
X        if (np == (struct phrase *)NULL)
X        {   /* enough memory? */
X            /* message already printed */
X            sentence_free(*cpp);
X            return 1;
X        }
X        if (*cpp == (struct phrase *)NULL)
X            *cpp = *lcpp = np;
X        else
X        {   /* tack onto end */
X            (*lcpp)->next = np;
X            *lcpp = np;
X        }
X    }
X    return 0;
X}   /* end of cmd_fc_copy */
X
Xstatic char *cmd_fc_substr(s1,s2,l)
Xchar *s1;
Xregister char *s2;
Xregister int l;
X{
X    register char *s;
X
X    for (s = s1; *s; s++)
X    {   /* scan the string */
X        if (strncmp(s,s2,l) == 0)
X            return(s);
X    }
X    return (char *)NULL;
X}   /* end of cmd_fc_substr */
X
Xint cmd_fc_smatch(hp,num,pfx)
Xstruct hist_phrase *hp;
Xint num;
Xchar *pfx;
X{
X    struct phrase *pp;
X    struct token *tp;
X    register char *p,*q;
X    register int rc;
X    int len;
X
X    pp = hp->cmd;
X    if (pp == (struct phrase *)NULL)
X        return 0;
X    if (num < 0 || num >= base_env.history_size)
X    {   /* if to do string selection */
X        tp = pp->body;
X        if (tp == (struct token *)NULL)
X            return 0;
X        p = strcopy(tp->name);
X        if (p == (char *)NULL)
X            return 0;
X        stripquotes(p);
X        q = strrchr(p,DIR_SEPARATOR);
X        if (q == (char *)NULL)
X            q = p;
X        else q++;
X        len = strlen(pfx);
X        rc = strncmp(q,pfx,len);
X        if (rc != 0)
X            rc = strncmp(p,pfx,len);
X        free(p);
X        return (rc == 0);
X    }
X    else return (hp->number == num);
X}   /* end of cmd_fc_smatch */
X
Xint cmd_fc(pp)
Xstruct phrase *pp;
X{
X    register struct token *tp;
X    register int ctr;
X    register char *p;
X    char *localEd;
X    char *rStart,*rEnd,*q;
X    int list,nonum,reverse,rKey;
X    struct hist_phrase *first,*last,*curr;
X    struct phrase *np,*cpp,*lcpp;
X    struct token *ntp,*lntp;
X    int iFirst,iLast;
X
X    localEd = rStart = rEnd = (char *)NULL;
X    iFirst = iLast = -1;
X    rKey = list = nonum = reverse = 0;
X    for (tp = pp->body->next; tp != (struct token *)NULL; tp = tp->next)
X    {   /* look for options / range start & end */
X        if (tp->name[0] == '-')
X        {   /* if an option */
X            stripquotes(tp->name);
X            for (p = &tp->name[1]; *p; p++)
X            {   /* for each option char */
X                switch (*p)
X                {   /* which option? */
X                    case 'e':
X                        if (tp->next != (struct token *)NULL &&
X                            (tp->next->name[0] != '-' ||
X                            strcmp(tp->next->name,"-") == 0))
X                        {   /* get the arg if there */
X                            localEd = tp->next->name;
X                            stripquotes(localEd);
X                            tp = tp->next;
X                        }
X                        else if (tp->next != (struct token *)NULL &&
X                            tp->next->name[0] == '-')
X                        {   /* use FCEDIT */
X                            localEd = "";
X                        }
X                        else
X                        {   /* no editor name... */
X                            errmsg(0,LOC("cmd_fc"),"no editor name supplied for -e");
X                            return -1;
X                        }
X                        break;
X                    case 'l':
X                        list = 1;
X                        break;
X                    case 'r':
X                        reverse = 1;
X                        break;
X                    case 'n':
X                        nonum = 1;
X                        break;
X                    default:
X                        errmsg(0,LOC("cmd_fc"),"unknown option in arg: %s",p);
X                        return -1;
X                }
X            }
X        }
X        else
X        {   /* range start & end */
X            rStart = tp->name;
X            stripquotes(rStart);
X            if (strchr(rStart,'=') != (char *)NULL)
X                rKey = 1;
X            else rKey = 0;
X            if (tp->type == SYM_NUMBER)
X                iFirst = atoi(rStart);
X            if (tp->next != (struct token *)NULL)
X            {   /* end of range marker */
X                rEnd = tp->next->name;
X                stripquotes(rEnd);
X                if (tp->next->type == SYM_NUMBER)
X                    iLast = atoi(rEnd);
X            }
X            break;
X        }
X    }
X
X    first = last = curr = (struct hist_phrase *)NULL;
X    if (rStart == (char *)NULL && rEnd == (char *)NULL)
X    {   /* select whole range */
X        if (list)
X        {   /* if listing, default to full table */
X            first = &base_env.history_list[1];
X            last = &base_env.history_list[base_env.history_size-1];
X        }
X        else
X        {   /* default to last used entry */
X            first = last = &base_env.history_list[1];
X        }
X    }
X    else if (rStart != (char *)NULL && rEnd == (char *)NULL)
X    {   /* select just one */
X        rKey = 0;
X        for (ctr = 1; ctr < base_env.history_size; ctr++)
X        {   /* look for a leading match */
X            if (cmd_fc_smatch(&base_env.history_list[ctr],iFirst,rStart))
X            {   /* found a match */
X                first = last = &base_env.history_list[ctr];
X                break;
X            }
X        }
X    }
X    else if (!rKey && rStart != (char *)NULL && rEnd != (char *)NULL)
X    {   /* select a whole range */
X        for (ctr = 1; ctr < base_env.history_size; ctr++)
X        {   /* look for a leading match */
X            if (first == (struct hist_phrase *)NULL)
X            {   /* looking for 1st phrase? */
X                if (cmd_fc_smatch(&base_env.history_list[ctr],iFirst,rStart))
X                {   /* found a match */
X                    first = &base_env.history_list[ctr];
X                }
X            }
X            else
X            {   /* find end of match */
X                if (cmd_fc_smatch(&base_env.history_list[ctr],iLast,rEnd))
X                {   /* found a match */
X                    last = &base_env.history_list[ctr];
X                    break;
X                }
X            }
X        }
X    }
X    else if (rKey && rStart != (char *)NULL && rEnd != (char *)NULL)
X    {   /* select just one, but do a string substitution */
X        for (ctr = 1; ctr < base_env.history_size; ctr++)
X        {   /* look for a leading match */
X            if (cmd_fc_smatch(&base_env.history_list[ctr],iLast,rEnd))
X            {   /* found a match */
X                first = last = &base_env.history_list[ctr];
X                break;
X            }
X        }
X    }
X    else
X    {   /* illegal condition */
X        errmsg(0,LOC("cmd_fc"),"reached illegal state in command");
X        return 1;
X    }
X    if (first == (struct hist_phrase *)NULL || last == (struct hist_phrase *)NULL)
X    {   /* anything selected? */
X        errmsg(0,LOC("cmd_fc"),"nothing selected for fc to operate on");
X        return 1;
X    }
X
X    if (list)
X    {   /* if just want to dump out the lines */
X        if (reverse) for (curr = first; curr <= last; curr++)
X        {   /* step through the selected part of the array */
X            cmd_fc_dump(curr,nonum);
X        }
X        else for (curr = last; curr >= first; curr--)
X        {   /* reverse step through the selected part of the array */
X            cmd_fc_dump(curr,nonum);
X        }
X        return 0;
X    }
X
X    if (localEd == (char *)NULL ||
X        (localEd != (char *)NULL && strcmp(localEd,"-") != 0))
X    {   /* edit the commands in a real editor */
X        cpp = cmd_fc_edit(first,last,localEd);
X        if (cpp == (struct phrase *)NULL)
X        {   /* did it work? */
X            /* error message already printed */
X            return 1;
X        }
X    }
X    else
X    {   /* just make a copy of the sentences to execute */
X        cpp = lcpp = (struct phrase *)NULL;
X        if (!reverse) for (curr = first; curr <= last; curr++)
X        {   /* step through the selected part of the array */
X            if (cmd_fc_copy(curr,&cpp,&lcpp))
X            {   /* if copy didn't work */
X                /* message already printed */
X                return 1;
X            }
X        }
X        else for (curr = last; curr >= first; curr--)
X        {   /* reverse step through the selected part of the array */
X            if (cmd_fc_copy(curr,&cpp,&lcpp))
X            {   /* if copy didn't work */
X                /* message already printed */
X                return 1;
X            }
X        }
X        if (rKey)
X        {   /* if need to do a string substitution */
X            p = strchr(rStart,'=');
X            /* ASSERT that p != NULL */
X            for (np = cpp; np != (struct phrase *)NULL; np = np->next)
X            {   /* for each selected sentence */
X                for (lcpp = np; lcpp != (struct phrase *)NULL; lcpp = lcpp->next)
X                {   /* for base contents of each sentence */
X                    lntp = (struct token *)NULL;
X                    for (ntp = lcpp->body; ntp != (struct token *)NULL; ntp = ntp->next)
X                    {   /* look at words in phrase */
X                        q = cmd_fc_substr(ntp->name,rStart,(int)(p-rStart));
X                        if (q != (char *)NULL)
X                        {   /* if need to do token replacement */
X                            tp = new_token(strlen(ntp->name)-(int)(p-rStart)+strlen(&p[1]));
X                            if (tp == (struct token *)NULL)
X                            {   /* enough memory? */
X                                errmsg(SHERR_NOMEM,LOC("cmd_fc"));
X                                sentence_free(cpp);
X                                return 1;
X                            }
X                            tp->next = ntp->next;
X                            tp->type = ntp->type;
X                            strcpy(tp->name,ntp->name);
X                            strcpy(&tp->name[(int)(q-ntp->name)],&p[1]);
X                            strcat(tp->name,&ntp->name[(int)(q-ntp->name)+(int)(p-rStart)]);
X                            if (lntp != (struct token *)NULL)
X                                lntp->next = tp;
X                            else lcpp->body = tp;
X                            free(ntp);
X                            break;
X                        }
X                        lntp = ntp;
X                    }
X                    if (ntp != (struct token *)NULL)
X                        break;
X                }
X                if (lcpp != (struct phrase *)NULL)
X                    break;
X            }
X        }
X    }
X
X    if (base_env.history_size > 0)
X    {   /* if saving history of executed lines */
X        phrase_free(base_env.history_list[0].cmd);
X        base_env.history_list[0].cmd = copy_group(cpp,0,0,1);
X    }
X    for (np = cpp; np != (struct phrase *)NULL; np = np->next)
X    {   /* finally run the finished phrases */
X        phrase_dump(np,1,0);
X        lcpp = copy_phrase(np,1,0,1);
X        if (lcpp == (struct phrase *)NULL)
X        {   /* enough memory? */
X            /* message already printed */
X            continue;
X        }
X        exec_phrase(lcpp,0);
X        phrase_free(lcpp);
X        if (cmd_forceexit || cmd_returnexit)
X            break;
X    }
X    sentence_free(cpp);
X    return 0;
X}   /* end of cmd_fc */
X
Xint cmd_eval(pp)
Xstruct phrase *pp;
X{
X    register struct phrase *torun,*toend,*np;
X    struct token *tp;
X    char tempfile[32];
X    int save_output;
X
X    if (pp->body->next == (struct token *)NULL)
X    {   /* anything to eval? */
X        return 1;
X    }
X    np = copy_phrase(pp,1,1,1);
X    if (np == (struct phrase *)NULL)
X    {   /* enough memory? */
X        /* message already printed */
X        return 1;
X    }
X    tp = np->body;
X    np->body = tp->next;
X    free(tp);		/* free "eval" word */
X
X#ifdef  GEMDOS
X    sprintf(tempfile,"%stemp%d.tmp",base_env.tmpdir,base_env.temp_count++);
X#else
X    sprintf(tempfile,"/tmp/sh%d.temp",base_env.temp_count++);
X#endif  /* GEMDOS */
X    save_output = base_env.io->output;
X    base_env.io->output = creat(tempfile,0666);
X    if (base_env.io->output < 0)
X    {   /* did we get a temporary file? */
X        errmsg(0,LOC("cmd_eval"),"unable to open tempfile");
X        phrase_free(np);
X        return 1;
X    }
X    phrase_dump(np,1,0);
X    close(base_env.io->output);
X    base_env.io->output = save_output;
X    phrase_free(np);
X
X    if (io_pushfile(tempfile,1,0,1) < 0)
X    {   /* if saving the file failed */
X        errmsg(0,LOC("cmd_eval"),"unable to put tempfile into input stream");
X        delete_later(tempfile);
X        return 1;
X    }
X    torun = toend = (struct phrase *)NULL;
X    while ((np = lex_phrase(1,0)) != (struct phrase *)NULL)
X    {   /* get back contents of file */
X        if (np->type != (struct token *)NULL && np->type->type == SYM_MARKER)
X        {   /* reached end of file */
X            phrase_free(np);
X            break;
X        }
X        if (torun == (struct phrase *)NULL)
X            torun = toend = np;
X        else
X        {   /* tack onto end */
X            toend->next = np;
X            toend = np;
X        }
X    }
X    for (np = torun; np != (struct phrase *)NULL; np = np->next)
X    {   /* finally run the finished phrases */
X        exec_phrase(np,0);
X        if (cmd_forceexit || cmd_returnexit)
X            break;
X    }
X    return 0;
X}   /* end of cmd_eval */
X
Xint cmd_exec(pp)
Xstruct phrase *pp;
X{
X    if (pp->body->next == (struct token *)NULL)
X        return 0;
X    run_args(pp);
X    cmd_forceexit = 1;
X    return 0;
X}   /* end of cmd_exec */
X
Xint cmd_time(pp)
Xstruct phrase *pp;
X{
X    time_t tstart,tend;
X    long min,sec;
X    char buffer[256];
X
X    if (pp->body->next == (struct token *)NULL)
X        return 0;
X    tstart = time(0L);
X    run_args(pp);
X    tend = time(0L);
X    tend -= tstart;
X    min = tend / 60L;
X    sec = tend % 60L;
X    if (min == 0)
X    {   /* only seconds to worry about? */
X        if (sec == 1)
X            sprintf(buffer,"1 second");
X        else sprintf(buffer,"%ld seconds",sec);
X    }
X    else
X    {   /* both minutes and seconds */
X        if (min == 1 && sec == 1)
X            sprintf(buffer,"1 minute, 1 second");
X        else if (sec == 1)
X            sprintf(buffer,"%ld minutes, 1 second",min);
X        else if (min == 1)
X            sprintf(buffer,"1 minute, %ld seconds",sec);
X        else sprintf(buffer,"%ld minutes, %ld seconds",min,sec);
X    }
X    strcat(buffer,"\n");
X    io_writestring(1,buffer);
X    return 0;
X}   /* end of cmd_time */
END_OF_FILE
if test 36160 -ne `wc -c <'cmd2.c'`; then
    echo shar: \"'cmd2.c'\" unpacked with wrong size!
fi
# end of 'cmd2.c'
fi
echo shar: End of archive 8 \(of 11\).
cp /dev/null ark8isdone
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