[comp.sources.amiga] v90i016: CShell 4.00A - alternative command interface, Part03/04

Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator) (01/16/90)

Submitted-by: PERUGIA@ICNUCEVM.CNUCE.CNR.IT (Carlo & Cesare)
Posting-number: Volume 90, Issue 016
Archive-name: unix/cshell-4.00a/part03

#! /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 3 (of 4)."
# Contents:  execom.c
# Wrapped by tadguy@xanth on Mon Jan 15 11:28:11 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'execom.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'execom.c'\"
else
echo shar: Extracting \"'execom.c'\" \(19280 characters\)
sed "s/^X//" >'execom.c' <<'END_OF_FILE'
X/*
X * EXECOM.C
X *
X * Matthew Dillon, 10 August 1986
X *    Finally re-written.
X *
X * Version 2.07M by Steve Drew 10-Sep-87
X *
X * Version 4.00A by Carlo Borreo & Cesare Dieni 13-Jan-90
X *
X */
X
X#define F_EXACT 0
X#define F_ABBR  1
X
X#define ST_COND   0x01
X#define ST_NORED  0x02
X#define ST_NOEXP  0x04
X#define ST_AV     0x08 /* delimit args within a variable */
X
Xint has_wild = 0;                 /* set if any arg has wild card */
X
Xstruct COMMAND {
X	int (*func)();
X	short minargs;
X	short stat;
X	int val;
X	char *name;
X};
X
Xextern char *format_insert_string();
Xextern char *mpush(), *exarg();
X
Xextern int do_basename(), do_tackon();
Xextern int do_fltupper(), do_fltlower();
Xextern int do_strleft(), do_strright(), do_strmid(), do_strlen();
Xextern int do_fornum(), do_forline(), do_exec();
Xextern int do_diskchange(), do_stack(), do_fault(), do_path(), do_pri();
Xextern int do_rpn(), do_resident(), do_truerun(), do_aset(), do_howmany();
Xextern int do_open(), do_close(), do_fileslist(), do_htype();
Xextern int do_run(), do_number(), do_assign(), do_join();
Xextern int do_quit(), do_set_var(), do_unset_var();
Xextern int do_echo(), do_source(), do_mv(), do_addbuffers();
Xextern int do_cd(), do_pwd(), do_rm(), do_mkdir(), do_history();
Xextern int do_mem(), do_cat(), do_dir(), do_info(), do_inc();
Xextern int do_foreach(), do_return(), do_if(), do_label(), do_goto();
Xextern int do_input(), do_ver(), do_sleep(), do_help();
Xextern int do_strhead(), do_strtail(), do_relabel();
Xextern int do_copy(), do_date(), do_protect(), do_ps();
Xextern int do_forever(), do_abortline(), do_strings(), do_touch();
Xextern int do_window(), do_search(), do_filenote(), do_rxrec(), do_rxsend();
Xchar *push_cpy();
X
Xstatic struct COMMAND Command[] = {
Xdo_run,		0, ST_AV,	0,	"\001",   /* may call do_source */
Xdo_abortline,	0, 0,		0,	"abortline",
Xdo_addbuffers,	2, 0,		0,	"addbuffers",
Xdo_set_var,	0, 0, LEVEL_ALIAS,	"alias",  /* uses avline */
Xdo_aset,	1, 0,		0,	"aset",
Xdo_assign,	0, 0,		0,	"assign",
Xdo_basename,	2, 0,		0,	"basename",
Xdo_cat,		0, 0,		0,	"cat",
Xdo_cd,		0, 0,		0,	"cd",
Xdo_close,	0, 0,		0,	"close",
Xdo_copy,	1, 0,		0,	"copy",
Xdo_copy,	1, 0,		0,	"cp",
Xdo_date,	0, 0,		0,	"date",
Xdo_inc,		1, 0,		-1,	"dec",
Xdo_rm,		0, 0,		0,	"delete",
Xdo_dir,		0, ST_NOEXP,	0,	"dir",
Xdo_diskchange,	1, 0,		0,	"diskchange",
Xdo_echo,	0, 0,		0,	"echo", /* uses avline */
Xdo_if,		0, ST_COND,	1,	"else",
Xdo_if,		0, ST_COND,	2,	"endif",
Xdo_exec,	1, 0,		0,	"exec",
Xdo_fault,	1, 0,		0,	"fault",
Xdo_filenote,	2, 0,		0,	"filenote",
Xdo_fileslist,	0, 0,		0,	"flist",
Xdo_fltlower,	0, 0,		0,	"fltlower",
Xdo_fltupper,	0, 0,		0,	"fltupper",
Xdo_foreach,	3, ST_NORED,	0,	"foreach",
Xdo_forever,	1, ST_NORED,	0,	"forever",
Xdo_forline,	3, ST_NORED,	0,	"forline",
Xdo_fornum,	4, ST_NORED,	0,	"fornum",
Xdo_goto,	1, 0,		0,	"goto",
Xdo_help,	0, 0,		0,	"help",
Xdo_history,	0, 0,		0,	"history",
Xdo_howmany,	0, 0,		0,	"howmany",
Xdo_htype,	1, 0,		0,	"htype",
Xdo_if,		1, ST_COND|ST_NORED,0,	"if",
Xdo_inc,		1, 0,		1,	"inc",
Xdo_info,	0, 0,		0,	"info",
Xdo_input,	1, 0,		0,	"input",
Xdo_join,	2, 0,		1,	"join",
Xdo_label,	1, ST_COND,	0,	"label",
Xdo_dir,		0, ST_NOEXP,	0,	"ls",
Xdo_mkdir,	0, 0,		0,	"md",
Xdo_mem,		0, 0,		0,	"mem",
Xdo_mkdir,	0, 0,		0,	"mkdir",
Xdo_mv,		2, 0,		0,	"mv",
Xdo_open,	3, 0,		0,	"open",
Xdo_path,	0, 0,		0,	"path",
Xdo_pri,		2, 0,		0,	"pri",
Xdo_protect,	2, 0,		0,	"protect",
Xdo_ps,		0, 0,		0,	"ps",
Xdo_pwd,		0, 0,		0,	"pwd",
Xdo_quit,	0, ST_NORED,	0,	"quit",
Xdo_truerun,	1, ST_NORED,	1,	"rback",
Xdo_mv,		2, 0,		0,	"rename",
Xdo_relabel,	2, 0,		0,	"relabel",
Xdo_resident,	0, 0,		0,	"resident",
Xdo_return,	0, 0,		0,	"return",
Xdo_rm,		0, 0,		0,	"rm",
Xdo_rpn,		0, ST_NOEXP|ST_NORED,0,	"rpn",
Xdo_rxrec,	1, 0,		0,	"rxrec",
Xdo_rxsend,	2, 0,		0,	"rxsend",
Xdo_truerun,	1, ST_NORED,	0,	"run",
Xdo_search,	2, 0,		0,	"search",
Xdo_set_var,	0, ST_AV, LEVEL_SET,	"set",
Xdo_sleep,	0, 0,		0,	"sleep",
Xdo_source,	0, ST_NORED|ST_AV, 0,	"source", /* uses avline */
Xdo_stack,	0, 0,		0,	"stack",
Xdo_strhead,	3, 0,		0,	"strhead",
Xdo_strings,	1, 0,		0,	"strings",
Xdo_strleft,	3, 0,		0,	"strleft",
Xdo_strlen,	2, 0,		0,	"strlen",
Xdo_strmid,	3, 0,		0,	"strmid",
Xdo_strright,	3, 0,		0,	"strright",
Xdo_strtail,	3, 0,		0,	"strtail",
Xdo_tackon,	3, 0,		0,	"tackon",
Xdo_touch,	0, 0,		0,	"touch",
Xdo_cat,		0, 0,		0,	"type",
Xdo_unset_var,	0, 0, LEVEL_ALIAS,	"unalias",
Xdo_unset_var,	0, 0, LEVEL_SET  ,	"unset",
Xdo_ver,		0, 0,		0,	"version",
Xdo_window,	0, ST_NOEXP,	0,	"window",
X'\0',		0, 0,		0,	NULL
X};
X
Xstatic unsigned char elast;		/* last end delimeter */
Xstatic char Cin_ispipe, Cout_ispipe;
X
Xexec_command(base)
Xchar *base;
X{
Xregister char *scr;
Xchar buf[32];
X
Xif (!H_stack) {
X	add_history(base);
X	sprintf(buf, "%d", H_tail_base + H_len);
X	set_var(LEVEL_SET, v_histnum, buf);
X	}
Xscr = malloc((strlen(base) << 2) + 2);
Xpreformat(base, scr);
Xreturn (fcomm(scr, 1) ? -1 : 1);
X}
X
Xisalphanum(c)
Xregister char c;
X{
Xreturn (
X	(c >= '0' && c <= '9') ||
X	(c >= 'a' && c <= 'z') ||
X	(c >= 'A' && c <= 'Z') ||
X	(c == '_')
X	);
X}
X
Xpreformat(s, d)
Xregister char *s, *d;
X{
Xregister int si, di, qm;
X
Xsi = di = qm = 0;
Xwhile (s[si] == ' ' || s[si] == 9) ++si;
Xwhile (s[si]) {
X	if (qm && s[si] != '\"' && s[si] != '\\') {
X		d[di++] = s[si++] | 0x80;
X		continue;
X		}
X	switch (s[si]) {
X		case ' ':
X		case 9:
X			d[di++] = ' ';
X			while (s[si] == ' ' || s[si] == 9) ++si;
X			if (s[si] == 0 || s[si] == '|' || s[si] == ';') --di;
X			break;
X		case '*':
X		case '?':
X			d[di++] = 0x80;
X		case '!':
X			d[di++] = s[si++];
X			break;
X		case '#':
X			d[di++] = '\0';
X			while (s[si]) ++si;
X			break;
X		case ';':
X		case '|':
X			d[di++] = s[si++];
X			while (s[si] == ' ' || s[si] == 9) ++si;
X			break;
X		case '\\':
X			d[di++] = s[++si] | 0x80;
X			if (s[si]) ++si;
X			break;
X		case '\"':
X			qm = 1 - qm;
X			++si;
X			break;
X		case '^':
X			d[di++] = s[++si] & 0x1F;
X			if (s[si]) ++si;
X			break;
X		case '$': /* search end of var name and place false space */
X			d[di++] = 0x80;
X			d[di++] = s[si++];
X			while (isalphanum(s[si])) d[di++] = s[si++];
X			d[di++] = 0x80;
X			break;
X		default:
X			d[di++] = s[si++];
X			break;
X		}
X	}
Xd[di++]=0;
Xd[di]=0;
Xif (debug) fprintf (stderr,"PREFORMAT: %d :%s:\n", strlen(d), d);
X}
X
Xextern BPTR extOpen();
X
X/*
X * process formatted string.  ' ' is the delimeter.
X *
X *    0: check '\0': no more, stop, done.
X *    1: check $.     if so, extract, format, insert
X *    2: check alias. if so, extract, format, insert. goto 1
X *    3: check history or substitution, extract, format, insert. goto 1
X *
X *    4: assume first element now internal or disk based command.
X *
X *    5: extract each ' ' or 0x80 delimited argument and process, placing
X *       in av[] list (except 0x80 args appended).  check in order:
X *
X *             '$'         insert string straight
X *             '>'         setup stdout
X *             '>>'        setup stdout flag for append
X *             '<'         setup stdin
X *             '*' or '?'  do directory search and insert as separate args.
X *
X *             ';' 0 '|'   end of command.  if '|' setup stdout
X *                          -execute command, fix stdin and out (|) sets
X *                           up stdin for next guy.
X */
X
X
Xfcomm(str, freeok)
Xregister char *str;
X{
X   static int alias_count;
X   int p_alias_count = 0;
X   char *istr;
X   char *nextstr;
X   char *command;
X   char *pend_alias = NULL;
X   char err = 0;
X   has_wild = 0;
X
X   ++alias_count;
X
X   mpush_base();
X   if (*str == 0)
X      goto done1;
Xstep1:
X   if (alias_count == MAXALIAS || ++p_alias_count == MAXALIAS) {
X      fprintf(stderr,"Alias Loop\n");
X      err = 20;
X      goto done1;
X   }
X/*
X   if (str[1] == '$') {
X      if (istr = get_var (LEVEL_SET, str + 2))
X         str = format_insert_string(str, istr, &freeok);
X   }
X*/
X   istr = NULL;
X   if (*(unsigned char *)str < 0x80)
X      istr = get_var (LEVEL_ALIAS, str);  /* only if not \command */
X   *str &= 0x7F;                          /* remove \ teltail     */
X   if (istr) {
X      if (*istr == '%') {
X         pend_alias = istr;
X      } else {
X         str = format_insert_string(str, istr, &freeok);
X         goto step1;
X      }
X   }
X   if (*str == '!') {
X      char *p, c;                     /* fix to allow !cmd1;!cmd2 */
X      for(p = str; *p && *p != ';' ; ++p);
X      c = *p;
X      *p = '\0';
X      istr = get_history(str);
X      *p = c;
X      replace_head(istr);
X      str = format_insert_string(str, istr, &freeok);
X      goto step1;
X   }
X   nextstr = str;
X   command = exarg(&nextstr);
X   if (*command == 0)
X      goto done0;
X   if (pend_alias == 0) {
X      if (cmd_stat(command) & ST_COND)
X         goto skipgood;
X   }
X   if (disable || forward_goto) {
X      while (elast && elast != ';' && elast != '|')
X         exarg(&nextstr);
X      goto done0;
X   }
Xskipgood:
X   {
X      register char *arg, *ptr, *scr;
X      short redir;
X      short doexpand;
X      short cont;
X      short inc;
X
X      ac = 1;
X      av[0] = command;
Xstep5:                                          /* ac = nextac */
X      if (!elast || elast == ';' || elast == '|')
X         goto stepdone;
X
X      av[ac] = '\0';
X      cont = 1;
X      doexpand = redir = inc = 0;
X
X      while (cont && elast) {
X         int cstat = cmd_stat(command);
X
X         ptr = exarg(&nextstr);
X         inc = 1;
X         arg = "";
X         cont = (elast == 0x80);
X         switch (*ptr) {
X         case '<':
X            redir = -2;
X         case '>':
X            if (cstat & (ST_NORED | ST_COND)) {
X                                                        /* don't extract   */
X                redir = 0;                              /* <> stuff if its */
X                arg = ptr;                              /* external cmd.   */
X                break;
X            }
X            ++redir;
X            arg = ptr + 1;
X            if (*arg == '>') {
X               redir = 2;        /* append >> */
X               ++arg;
X            }
X            cont = 1;
X            break;
X         case '$':
X            /* restore args if from set command or pend_alias */
X            if ((arg = get_var(LEVEL_SET, ptr + 1)) != NULL) {
X               if (cstat & ST_COND) {
X                  char *tp;
X                  tp = push_cpy(arg);
X                  arg = tp;
X               }
X               else {
X                  char *pe, sv;
X                  while (pe = index(arg,0xA0)) {
X                     sv = *pe;
X                     *pe = '\0';
X                     av[ac++] = push_cpy(arg);
X                     *pe = sv;
X                     av[ac] = '\0';
X                     arg = pe+1;
X                  }
X               }
X            }
X            else
X               arg = ptr;
X            break;
X         case '*':
X         case '?':
X            if ((cstat & ST_NOEXP) == 0)
X               doexpand = 1;
X            arg = ptr;
X            break;
X         default:
X            arg = ptr;
X            break;
X         }
X
X         /* Append arg to av[ac] */
X
X         for (scr = arg; *scr; ++scr)
X            *scr &= 0x7F;
X         if (av[ac]) {
X            register char *old = av[ac];
X            av[ac] = mpush(strlen(arg)+strlen(av[ac]));
X            strcpy(av[ac], old);
X            strcat(av[ac], arg);
X         } else {
X            av[ac] = push_cpy(arg);
X         }
X         if (elast != 0x80)
X            break;
X      }
X
X      /* process expansion */
X
X      if (doexpand) {
X         char **eav, **ebase;
X         int eac;
X         has_wild = 1;
X         eav = ebase = expand(av[ac], &eac);
X         inc = 0;
X         if (eav) {
X            if (ac + eac + 2 > MAXAV) {
X               ierror (NULL, 506);
X               err = 1;
X            } else {
X               QuickSort(eav, eac);
X               for (; eac; --eac, ++eav)
X                  av[ac++] = push_cpy(*eav);
X            }
X            free_expand (ebase);
X         }
X      }
X
X      /* process redirection  */
X
X      if (redir && !err) {
X         register char *file = (doexpand) ? av[--ac] : av[ac];
X
X         if (redir < 0)
X            Cin_name = file;
X         else {
X            Cout_name = file;
X            Cout_append = (redir == 2);
X         }
X         inc = 0;
X      }
X
X      /* check elast for space */
X
X      if (inc) {
X         ++ac;
X         if (ac + 2 > MAXAV) {
X            ierror (NULL, 506);
X            err = 1;                /* error condition */
X            elast = 0;              /* don't process any more arguemnts */
X         }
X      }
X      if (elast == ' ')
X         goto step5;
X   }
Xstepdone:
X   av[ac] = '\0';
X
X   /* process pipes via files */
X
X   if (elast == '|' && !err) {
X      static int which;             /* 0 or 1 in case of multiple pipes */
X      which = 1 - which;
X      Cout_name = (which) ? Pipe1 : Pipe2;
X      Cout_ispipe = 1;
X   }
X
X
X   if (err)
X      goto done0;
X
X   {
X      register int i;
X      char save_elast;
X      char *compile_av();
X      register char *avline;
X      unsigned char delim = ' ';
X
X      save_elast = elast;
X      if (pend_alias || (cmd_stat(command) & ST_AV))
X         delim = 0xA0;
X      avline = compile_av(av,((pend_alias) ? 1 : 0), ac, delim, 0);
X
X      if (pend_alias) {                               /* special % alias */
X         register char *ptr, *scr;
X         for (ptr = pend_alias; *ptr && *ptr != ' '; ++ptr);
X         set_var (LEVEL_SET, pend_alias + 1, avline);
X         free (avline);
X
X         scr = malloc((strlen(ptr) << 2) + 2);
X         preformat (ptr, scr);
X         fcomm (scr, 1);
X         unset_var (LEVEL_SET, pend_alias + 1);
X      } else {                                        /* normal command  */
X         register int ccno;
X         long  oldcin  = Myprocess->pr_CIS;
X         long  oldcout = Myprocess->pr_COS;
X         char *Cin_buf;
X         struct FileHandle *ci;
X         long oldbuf;
X
X         fflush(stdout);
X         ccno = find_command (command);
X         if ((Command[ccno].stat & (ST_NORED | ST_COND)) == 0) {
X            if (Cin_name) {
X               if ((Cin = (long)extOpen(Cin_name,1005L)) == 0L) {
X                  ierror (NULL, 504);
X                  err = 1;
X                  Cin_name = '\0';
X               } else {
X                  Myprocess->pr_CIS = _devtab[stdin->_unit].fd = Cin;
X                  ci = (struct FileHandle *)(((long)Cin)<<2);
X                  Cin_buf = (char *)AllocMem(202L, MEMF_PUBLIC);
X                  oldbuf = ci->fh_Buf;
X                  if (ci->fh_Buf == 0) /* fexec expects a CIS buffer */
X                     ci->fh_Buf = (long)Cin_buf>>2;
X               }
X            }
X            if (Cout_name) {
X               if (Cout_append && (Cout =(long)extOpen(Cout_name, 1005L)) ) {
X                     Seek(Cout, 0L, 1L);
X               } else {
X                  Cout = (long)extOpen(Cout_name,1006L);
X               }
X               if (Cout == NULL) {
X                  err = 1;
X                  ierror (NULL, 504);
X                  Cout_name = '\0';
X                  Cout_append = 0;
X               } else {
X                  Myprocess->pr_COS = _devtab[stdout->_unit].fd = Cout;
X               }
X            }
X         }
X         if (ac < Command[ccno].minargs + 1) {
X            ierror (NULL, 500);
X            err = -1;
X         } else if (!err) {
X            i = (*Command[ccno].func)(avline, Command[ccno].val);
X            if (i < 0)
X               i = 20;
X            err = i;
X         }
X         free (avline);
X         if (E_stack == 0 && Lastresult != err) {
X            Lastresult = err;
X            seterr();
X         }
X         if ((Command[ccno].stat & (ST_NORED | ST_COND)) == 0) {
X            if (Cin_name) {
X               fflush(stdin);
X               clearerr(stdin);
X               ci->fh_Buf = oldbuf;
X               extClose(Cin);
X               FreeMem(Cin_buf, 202L);
X            }
X            if (Cout_name) {
X               fflush(stdout);
X               clearerr(stdout);
X               stdout->_flags &= ~_DIRTY;    /* because of nil: device */
X               extClose(Cout);
X               Cout_append = 0;
X            }
X         }
X         Myprocess->pr_CIS =  _devtab[stdin->_unit].fd  = oldcin;
X         Myprocess->pr_COS =  _devtab[stdout->_unit].fd = oldcout;
X      }
X
X      if (Cin_ispipe && Cin_name)
X         DeleteFile(Cin_name);
X      if (Cout_ispipe) {
X         Cin_name = Cout_name;         /* ok to assign.. static name */
X         Cin_ispipe = 1;
X      } else {
X         Cin_name = '\0';
X      }
X      Cout_name = '\0';
X      Cout_ispipe = 0;
X      elast = save_elast;
X   }
X   mpop_tobase();                      /* free arguments   */
X   mpush_base();                       /* push dummy base  */
X
Xdone0:
X   {
X      char *str;
X      if (err && E_stack == 0) {
X         str = get_var(LEVEL_SET, v_except);
X         if (err >= ((str)?atoi(str):1)) {
X            if (str) {
X               ++H_stack;
X               ++E_stack;
X               exec_command(str);
X               --E_stack;
X               --H_stack;
X            } else {
X               Exec_abortline = 1;
X            }
X         }
X      }
X      if (elast != 0 && Exec_abortline == 0)
X         err = fcomm(nextstr, 0);
X      Exec_abortline = 0;
X      if (Cin_name)
X         DeleteFile(Cin_name);
X      Cin_name = NULL;
X      Cin_ispipe = 0;
X   }
Xdone1:
X   mpop_tobase();
X   if (freeok)
X      free(str);
X   --alias_count;
X   return ((int)err);                  /* TRUE = error occured    */
X}
X
X
Xchar *
Xexarg(ptr)
Xunsigned char **ptr;
X{
X   register unsigned char *end;
X   register unsigned char *start;
X
X   start = end = *ptr;
X   while (*end && *end != 0x80 && *end != ';' && *end != '|' && *end != ' ')
X      ++end;
X   elast = *end;
X   *end = '\0';
X   *ptr = end + 1;
X   return ((char *)start);
X}
X
Xstatic char **Mlist;
X
Xmpush_base()
X{
X   char *str;
X
X   str = malloc(5);
X   *(char ***)str = Mlist;
X   str[4] = 0;
X   Mlist = (char **)str;
X}
X
Xchar *
Xmpush(bytes)
X{
X   char *str;
X
X   str = malloc(6 + bytes + 2);   /* may need extra 2 bytes in do_run() */
X   *(char ***)str = Mlist;
X   str[4] = 1;
X   Mlist = (char **)str;
X   return (str + 5);
X}
X
Xmpop_tobase()
X{
X   register char *next;
X   while (Mlist) {
X      next = *Mlist;
X      if (((char *)Mlist)[4] == 0) {
X         free (Mlist);
X         Mlist = (char **)next;
X         break;
X      }
X      free (Mlist);
X      Mlist = (char **)next;
X   }
X}
X
X
X/*
X * Insert 'from' string in front of 'str' while deleting the
X * first entry in 'str'.  if freeok is set, then 'str' will be
X * free'd
X */
X
Xchar *format_insert_string(str, from, freeok)
Xchar *str;
Xchar *from;
Xint *freeok;
X{
Xregister char *new1, *new2;
Xregister unsigned char *strskip;
Xint len;
X
Xfor (strskip = (unsigned char *)str;
X		*strskip && *strskip != ' ' 
X		&& *strskip != ';' && *strskip != '|'
X		&& *strskip != 0x80; ++strskip);
Xlen = strlen(from);
Xnew1 = malloc((len << 2) + 2);
Xpreformat(from, new1);
Xlen = strlen(new1) + strlen(strskip);
Xnew2 = malloc(len+2);
Xstrcpy(new2, new1);
Xstrcat(new2, strskip);
Xnew2[len+1] = 0;
Xfree (new1);
Xif (*freeok) free (str);
X*freeok = 1;
Xreturn new2;
X}
X
Xcmd_stat(str)
Xchar *str;
X{
Xreturn(Command[find_command(str)].stat);
X}
X
Xfind_command(str)
Xchar *str;
X{
Xregister unsigned short i;
Xint len = strlen(str);
X
Xfor (i = 0; Command[i].func; ++i)
X	if ( ! strncmp(str, Command[i].name, len)) return (int)i;
Xreturn 0;
X}
X
Xdo_help()
X{
Xregister struct COMMAND *com;
Xint i=0;
X
Xfor (com = &Command[1]; com->func; ++com) {
X	printf ("%-12s", com->name);
X	if (++i % 6 == 0) printf("\n");
X	}
Xprintf("\n");
Xreturn 0;
X}
X
Xchar *push_cpy(s)
Xchar *s;
X{
Xreturn strcpy(mpush(strlen(s)), s);
X}
END_OF_FILE
if test 19280 -ne `wc -c <'execom.c'`; then
    echo shar: \"'execom.c'\" unpacked with wrong size!
fi
# end of 'execom.c'
fi
echo shar: End of archive 3 \(of 4\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 4 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Submissions to comp.sources.amiga and comp.binaries.amiga should be sent to:
	amiga@cs.odu.edu	
or	amiga@xanth.cs.odu.edu	( obsolescent mailers may need this address )
or	...!uunet!xanth!amiga	( very obsolescent mailers need this address )

Comments, questions, and suggestions s should be addressed to ``amiga-request''
(only use ``amiga'' for submissions) at the above addresses.