[comp.sys.amiga] SHELL 2.04 PART 4 of 4

dillon@CORY.BERKELEY.EDU (Matt Dillon) (01/03/87)

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	main.c
#	run.c
#	set.c
#	sort.c
#	sub.c
#	c.asm
#	fexec2.asm
#	shell.h
# This archive created: Sat Jan  3 01:02:29 1987
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'main.c'" '(2695 characters)'
if test -f 'main.c'
then
	echo shar: "will not over-write existing file 'main.c'"
else
cat << \!Funky!Stuff! > 'main.c'

/*
 * MAIN.C
 *
 * (c)1986 Matthew Dillon     9 October 1986
 *
 *    Contains initialization and other stuff.  Note that there is no
 *    support for workbench startup.  This isn't simply a matter of
 *    setting up a window.... to get this baby to work from workbench we
 *    would need to simulate an entire CLI (proc->pr_CLI must be valid).
 *
 */

#include "shell.h"
#include <libraries/dosextens.h>

extern long SetSignal();

char Inline[256];

main(argc, argv)
short argc;
register char *argv[];
{
   char *prompt;
   struct Process *proc;
   register short i;

   check32();
   proc = (struct Process *)FindTask(0);
   if (proc->pr_CLI == NULL)              /* sorry, no WB startup */
      exit(1000);
   init_vars();
   init();
   seterr();
   do_cd(NULL, -1);
   for (i = 1; i < argc; ++i) {
      if (strcmp(argv[i], "-c") == 0) {
         Inline[0] = '\0';
         for (++i; i < argc; ++i) {
            if (*argv[i] == '\"') {             /* CLI quotes?   */
               strcat(Inline, argv[i]+1);       /* remove quotes */
               Inline[strlen(Inline)-1] = '\0';
            } else {
               strcat(Inline, argv[i]);
            }
            if (i + 1 < argc)
               strcat(Inline, " ");
         }
         exec_command(Inline);
         main_exit(0);
      }
      strcpy (Inline, "source ");
      strcat (Inline, argv[i]);
      av[1] = argv[i];
      do_source (Inline, 0);
   }
   for (;;) {
      if ((prompt = get_var (LEVEL_SET, V_PROMPT)) == NULL)
         prompt = "echo -n \"% \"";
      if (CHECKBREAK()) {
         while (WaitForChar(Input(), 1))
            gets(Inline);
      }
      ++H_stack;
      ++Exec_ignoreresult;
      exec_command (prompt);
      --Exec_ignoreresult;
      --H_stack;
      if (Quit || !gets(Inline))
         main_exit(0);
      breakreset();
      if (*Inline == '^')
         hat_replace(Inline);
      if (*Inline)
         exec_command(Inline);
   }
}

init_vars()
{
   if (IsInteractive(Input()))
      set_var (LEVEL_SET, V_PROMPT, "echo -n \"% \"");
   else
      set_var (LEVEL_SET, V_PROMPT, "");
   set_var (LEVEL_SET, V_HIST, "20");
   set_var (LEVEL_SET, V_PATH, "ram:,ram:c/,c:,df1:c/,df0:c/");
}

init()
{
   static char pipe1[32], pipe2[32];

   Cin = Input();
   Cout= Cerr = Output();
   Uniq= (long)pipe1;         /* address of some global variable */
   Pipe1 = pipe1;
   Pipe2 = pipe2;
   sprintf (pipe1, "ram:pipe1_%ld", Uniq);
   sprintf (pipe2, "ram:pipe2_%ld", Uniq);
}


main_exit(n)
{
   free_memory();
   exit (n);
}

breakcheck()
{
   if (SetSignal(0,0) & SIGBREAKF_CTRL_C)
      return (1);
   else
      return (0);
}

breakreset()
{
   SetSignal(0, SIGBREAKF_CTRL_C);
}


!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'run.c'" '(810 characters)'
if test -f 'run.c'
then
	echo shar: "will not over-write existing file 'run.c'"
else
cat << \!Funky!Stuff! > 'run.c'

/*
 * RUN.C
 *
 * (c)1986 Matthew Dillon     9 October 1986
 *
 *    RUN   handles running of external commands.
 *
 */

#include "shell.h"
#include "libraries/dos.h"

extern long *SysRegs;

do_run(str)
char *str;
{
   int i;

   if (fexecv(av[0], av, Cin_name, Cout_name, Cout_append) >= 0) {
      i = wait();
   } else {
      register long lock;
      char buf[128];
      register char *copy;

      lock = Lock(FindIt(av[0], ".sh", buf), ACCESS_READ);
      if (lock == NULL) {
         Eputs("Command Not Found");
         return (-1);
      }
      UnLock(lock);
      av[1] = buf;               /* particular to do_source() */
      copy = malloc(strlen(str)+3);
      strcpy(copy+2,str);
      copy[0] = 'x';
      copy[1] = ' ';
      i = do_source(copy);
      free(copy);
   }
   return (i);
}


!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'set.c'" '(3741 characters)'
if test -f 'set.c'
then
	echo shar: "will not over-write existing file 'set.c'"
else
cat << \!Funky!Stuff! > 'set.c'

/*
 * SET.C
 *
 * (c)1986 Matthew Dillon     9 October 1986
 *
 * Handles the variable lists for normal variables, aliases, and labels.
 *
 *
 */

#include "shell.h"
#define MAXLEVELS (3 + MAXSRC)

struct MASTER {
   struct MASTER *next;
   struct MASTER *last;
   char *name;
   char *text;
};

static struct MASTER *Mbase[MAXLEVELS];

char *
set_var(level, name, str)
short level;
register char *name, *str;
{
   register struct MASTER *base = Mbase[level];
   register struct MASTER *last;
   register short len;

   for (len = 0; isalphanum(name[len]); ++len);
   while (base != NULL) {
      if (strlen(base->name) == len && strncmp (name, base->name, len) == 0) {
         Free (base->text);
         goto gotit;
      }
      last = base;
      base = base->next;
   }
   if (base == Mbase[level]) {
      base = Mbase[level] = (struct MASTER *)malloc (sizeof(struct MASTER));
      base->last = NULL;
   } else {
      base = (struct MASTER *)malloc (sizeof(struct MASTER));
      base->last = last;
      last->next = base;
   }
   base->name = malloc (len + 1);
   bmov (name, base->name, len);
   base->name[len] = 0;
   base->next = NULL;
gotit:
   base->text = malloc (strlen(str) + 1);
   strcpy (base->text, str);
   return (base->text);
}

char *
get_var (level, name)
short level;
register char *name;
{
   register struct MASTER *base = Mbase[level];
   register unsigned char *scr;
   register short len;

   for (scr = name; *scr && *scr != 0x80 && *scr != ' ' && *scr != ';' && *scr != '|'; ++scr);
   len = scr - name;

   while (base != NULL) {
      if (strlen(base->name) == len && strncmp (name, base->name, len) == 0)
         return (base->text);
      base = base->next;
   }
   return (NULL);
}


unset_level(level)
short level;
{
   register struct MASTER *base = Mbase[level];

   while (base) {
      Free (base->name);
      Free (base->text);
      Free (base);
      base = base->next;
   }
   Mbase[level] = NULL;
}


unset_var(level, name)
short level;
char *name;
{
   register struct MASTER *base = Mbase[level];
   register struct MASTER *last = NULL;
   register short len;

   for (len = 0; isalphanum(name[len]); ++len);
   while (base) {
      if (strlen(base->name) == len && strncmp (name, base->name, len) == 0) {
         if (base != Mbase[level])
            last->next = base->next;
         else
            Mbase[level] = base->next;
         if (base->next != NULL)
            base->next->last = last;
         if (base == Mbase[level])
            Mbase[level] = base->next;
         Free (base->name);
         Free (base->text);
         Free (base);
         return (1);
      }
      last = base;
      base = base->next;
   }
   return (-1);
}


do_unset_var(garbage, level)
short level;
char *garbage;
{
   register short i;

   for (i = 1; i < ac; ++i)
      unset_var (level, av[i]);
   return (0);
}


do_set_var(command, level)
short level;
char *command;
{
   register struct MASTER *base = Mbase[level];
   register char *str;

   if (ac == 1) {
      while (base) {
         fprintf (Cout, "%-10s ", base->name);
         Oputs (base->text);
         base = base->next;
      }
      return (0);
   }
   if (ac == 2) {
      str = get_var (level, av[1]);
      if (str) {
         fprintf (Cout, "%-10s ", av[1]);
         Oputs(str);
      } else {
         set_var (level, av[1], "");
      }
   }
   if (ac > 2)
      set_var (level, av[1], next_word (next_word (command)));
   if (*av[1] == '_') {
      S_histlen = (str = get_var(LEVEL_SET, V_HIST))   ? atoi(str) : 0;
      Debug     = (str = get_var(LEVEL_SET, V_DEBUG))  ? atoi(str) : 0;
      Verbose   = (get_var(LEVEL_SET, V_VERBOSE)) ? 1 : 0;
      if (S_histlen < 2)   S_histlen = 2;
   }
   return (0);
}


!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'sort.c'" '(728 characters)'
if test -f 'sort.c'
then
	echo shar: "will not over-write existing file 'sort.c'"
else
cat << \!Funky!Stuff! > 'sort.c'

/*
 * SORT.C
 *
 * a QuickSort is used for speed, simplicity, and small code size.
 *
 */

extern short QSplit();


QuickSort(av, n)
char *av[];
short n;
{
   short b;

   if (n > 0) {
      b = QSplit(av, n);
      QuickSort(av, b);
      QuickSort(av+b+1, n - b - 1);
   }
}


/*
 * QSplit called as a second routine so I don't waste stack on QuickSort's
 * recursivness.
 */


short
QSplit(av, n)
register char *av[];
short n;
{
   register short i, b;
   register char *element, *scr;

   element = av[0];
   for (b = 0, i = 1; i < n; ++i) {
      if (strcmp(av[i], element) < 0) {
         ++b;
         scr = av[i]; av[i] = av[b]; av[b] = scr;
      }
   }
   scr = av[0]; av[0] = av[b]; av[b] = scr;
   return (b);
}



!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'sub.c'" '(11170 characters)'
if test -f 'sub.c'
then
	echo shar: "will not over-write existing file 'sub.c'"
else
cat << \!Funky!Stuff! > 'sub.c'

/*
 * SUB.C
 *
 * (c)1986 Matthew Dillon     9 October 1986
 *
 *    Subroutines used throughout the shell (not very descriptive, am I?)
 *
 *
 */


#include <exec/types.h>
#include <exec/exec.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include "shell.h"

#define HM_STR 0              /* various HISTORY retrieval modes */
#define HM_REL 1
#define HM_ABS 2

extern struct FileLock *Lock(), *DupLock(), *CurrentDir();
extern struct FileLock *Clock;

seterr()
{
   char buf[32];
   int stat;

   sprintf(buf, "%ld", Lastresult);
   set_var(LEVEL_SET, V_LASTERR, buf);
   stat = atoi(get_var(LEVEL_SET, V_STAT));
   if (stat < Lastresult)
      stat = Lastresult;
   sprintf(buf, "%ld", stat);
   set_var(LEVEL_SET, V_STAT, buf);
}


char *
next_word(str)
register char *str;
{
   while (*str  &&  *str != ' '  &&  *str != 9)
      ++str;
   while (*str  && (*str == ' ' || *str == 9))
      ++str;
   return (str);
}


char *
compile_av(av, start, end)
short start, end;
char **av;
{
   char *cstr;
   short i, len;

   len = 0;
   for (i = start; i < end; ++i)
      len += strlen(av[i]) + 1;
   cstr = malloc(len + 1);
   *cstr = '\0';
   for (i = start; i < end; ++i) {
      strcat (cstr, av[i]);
      strcat (cstr, " ");
   }
   return (cstr);
}

/*
 * FREE(ptr)   --frees without actually freeing, so the data is still good
 *               immediately after the free.
 */


Free(ptr)
char *ptr;
{
   static char *old_ptr;

   if (old_ptr)
      free (old_ptr);
   old_ptr = ptr;
}

/*
 * Add new string to history (H_head, H_tail, H_len,
 *  S_histlen
 */

add_history(str)
char *str;
{
   register struct HIST *hist;

   while (H_len > S_histlen)
      del_history();
   hist = (struct HIST *)malloc (sizeof(struct HIST));
   if (H_head == NULL) {
      H_head = H_tail = hist;
      hist->next = NULL;
   } else {
      hist->next = H_head;
      H_head->prev = hist;
      H_head = hist;
   }
   hist->prev = NULL;
   hist->line = malloc (strlen(str) + 1);
   strcpy (hist->line, str);
   ++H_len;
}

del_history()
{
   if (H_tail) {
      --H_len;
      ++H_tail_base;
      free (H_tail->line);
      if (H_tail->prev) {
         H_tail = H_tail->prev;
         free (H_tail->next);
         H_tail->next = NULL;
      } else {
         free (H_tail);
         H_tail = H_head = NULL;
      }
   }
}


char *
last_history_entry()
{
   if (H_head)
      return(H_head->line);
   return("");
}


char *
get_history(ptr)
char *ptr;
{
   register struct HIST *hist;
   register short len;
   short mode = HM_REL;
   long num  = 1;
   char *str;
   char *result = NULL;

   if (ptr[1] >= '0' && ptr[1] <= '9') {
      mode = HM_ABS;
      num  = atoi(&ptr[1]);
      goto skip;
   }
   switch (ptr[1]) {
   case '!':
      break;
   case '-':
      num += atoi(&ptr[2]);
      break;
   default:
      mode = HM_STR;
      str  = ptr + 1;
      break;
   }
skip:
   switch (mode) {
   case HM_STR:
      len = strlen(str);
      for (hist = H_head; hist; hist = hist->next) {
         if (strncmp(hist->line, str, len) == 0 && *hist->line != '!') {
            result = hist->line;
            break;
         }
      }
      break;
   case HM_REL:
      for (hist = H_head; hist && num--; hist = hist->next);
      if (hist)
         result = hist->line;
      break;
   case HM_ABS:
      len = H_tail_base;
      for (hist = H_tail; hist && len != num; hist = hist->prev, ++len);
      if (hist)
         result = hist->line;
      break;
   }
   if (result) {
      Eputs (result);
      return(result);
   }
   Eputs ("History substitution failed");
   return ("");
}


replace_head(str)
char *str;
{
   if (str == NULL)
      str = "";
   if (H_head) {
      free (H_head->line);
      H_head->line = malloc (strlen(str)+1);
      strcpy (H_head->line, str);
   }
}

perror(str)
char *str;
{
   ierror(str, IoErr());
}

ierror(str, err)
register char *str;
short err;
{
   register struct PERROR *per = Perror;

   if (err) {
      for (; per->errstr; ++per) {
         if (per->errnum == err) {
            fprintf (Cerr, "%s%s%s\n",
                  per->errstr,
                  (str) ? ": " : "",
                  (str) ? str : "");
            return (err);
         }
      }
      fprintf (Cerr, "Unknown DOS error %ld %s\n", err, (str) ? str : "");
   }
   return (err);
}

/*
 * Disk directory routines
 *
 * dptr = dopen(name, stat)
 *    struct DPTR *dptr;
 *    char *name;
 *    int *stat;
 *
 * dnext(dptr, name, stat)
 *    struct DPTR *dptr;
 *    char **name;
 *    int  *stat;
 *
 * dclose(dptr)                  -may be called with NULL without harm
 *
 * dopen() returns a struct DPTR, or NULL if the given file does not
 * exist.  stat will be set to 1 if the file is a directory.  If the
 * name is "", then the current directory is openned.
 *
 * dnext() returns 1 until there are no more entries.  The **name and
 * *stat are set.  *stat = 1 if the file is a directory.
 *
 * dclose() closes a directory channel.
 *
 */

struct DPTR *
dopen(name, stat)
char *name;
register int *stat;
{
   register struct DPTR *dp;

   *stat = 0;
   dp = (struct DPTR *)malloc(sizeof(struct DPTR));
   if (*name == '\0')
      dp->lock = DupLock (Clock);
   else
      dp->lock = Lock (name, ACCESS_READ);
   if (dp->lock == NULL) {
      free (dp);
      return (NULL);
   }
   dp->fib = (struct FileInfoBlock *)
         AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC);
   if (!Examine (dp->lock, dp->fib)) {
      perror (name);
      dclose (dp);
      return (NULL);
   }
   if (dp->fib->fib_DirEntryType >= 0)
      *stat = 1;
   return (dp);
}

dnext(dp, pname, stat)
register struct DPTR *dp;
char **pname;
int *stat;
{
   if (dp == NULL)
      return (0);
   if (ExNext (dp->lock, dp->fib)) {
      *stat = (dp->fib->fib_DirEntryType < 0) ? 0 : 1;
      *pname = dp->fib->fib_FileName;
      return (1);
   }
   return (0);
}


dclose(dp)
register struct DPTR *dp;
{
   if (dp == NULL)
      return (1);
   if (dp->fib)
      FreeMem (dp->fib, sizeof(*dp->fib));
   if (dp->lock)
      UnLock (dp->lock);
   free (dp);
   return (1);
}


isdir(file)
char *file;
{
   register struct DPTR *dp;
   int stat;

   stat = 0;
   if (dp = dopen (file, &stat))
      dclose(dp);
   return (stat == 1);
}


free_expand(av)
register char **av;
{
   register char **base = av;

   if (av) {
      while (*av) {
         free (*av);
         ++av;
      }
      free (base);
   }
}

/*
 * EXPAND(wild_name, pac)
 *    wild_name      - char * (example: "df0:*.c")
 *    pac            - int  *  will be set to # of arguments.
 *
 * Standalone, except in requires Clock to point to the Current-Directory
 * lock.
 */


char **
expand(base, pac)
char *base;
int *pac;
{
   register char *ptr;
   char **eav = (char **)malloc (sizeof(char *));
   short eleft, eac;
   char *name;
   char *bname, *ename, *tail;
   int stat, scr;
   register struct DPTR *dp;

   *pac = eleft = eac = 0;

   base = strcpy(malloc(strlen(base)+1), base);
   for (ptr = base; *ptr && *ptr != '?' && *ptr != '*'; ++ptr);
   for (; ptr >= base && !(*ptr == '/' || *ptr == ':'); --ptr);
   if (ptr < base) {
      bname = strcpy (malloc(1), "");
   } else {
      scr = ptr[1];
      ptr[1] = '\0';
      bname = strcpy (malloc(strlen(base)+1), base);
      ptr[1] = scr;
   }
   ename = ptr + 1;
   for (ptr = ename; *ptr && *ptr != '/'; ++ptr);
   scr = *ptr;
   *ptr = '\0';
   tail = (scr) ? ptr + 1 : NULL;

   if ((dp = dopen (bname, &stat)) == NULL  ||  stat == 0) {
      free (bname);
      free (base);
      free (eav);
      Eputs ("Could not open directory");
      return (NULL);
   }
   while (dnext (dp, &name, &stat)) {
      if (compare_ok(ename, name)) {
         if (tail) {
            int alt_ac;
            char *search, **alt_av, **scrav;
            struct FileLock *lock;

            if (!stat)           /* expect more dirs, but this not a dir */
               continue;
            lock = CurrentDir (Clock = dp->lock);
            search = malloc(strlen(name)+strlen(tail)+2);
            strcpy (search, name);
            strcat (search, "/");
            strcat (search, tail);
            scrav = alt_av = expand (search, &alt_ac);
            CurrentDir (Clock = lock);
            if (scrav) {
               while (*scrav) {
                  if (eleft < 2) {
                     char **scrav = (char **)malloc(sizeof(char *) * (eac + 10));
                     bmov (eav, scrav, (eac + 1) << 2);
                     free (eav);
                     eav = scrav;
                     eleft = 10;
                  }
                  eav[eac] = malloc(strlen(bname)+strlen(*scrav)+1);
                  strcpy(eav[eac], bname);
                  strcat(eav[eac], *scrav);
                  free (*scrav);
                  ++scrav;
                  --eleft, ++eac;
               }
               free (alt_av);
            }
         } else {
            if (eleft < 2) {
               char **scrav = (char **)malloc(sizeof(char *) * (eac + 10));
               bmov (eav, scrav, (eac + 1) << 2);
               free (eav);
               eav = scrav;
               eleft = 10;
            }
            eav[eac] = malloc (strlen(bname)+strlen(name)+1);
            eav[eac] = strcpy(eav[eac], bname);
            strcat(eav[eac], name);
            --eleft, ++eac;
         }
      }
   }
   dclose (dp);
   *pac = eac;
   eav[eac] = NULL;
   free (bname);
   free (base);
   if (eac)
      return (eav);
   free (eav);
   return (NULL);
}

/*
 * Compare a wild card name with a normal name
 */

#define MAXB   8

compare_ok(wild, name)
char *wild, *name;
{
   register char *w = wild;
   register char *n = name;
   char *back[MAXB][2];
   register char s1, s2;
   register short bi = 0;

   while (*n || *w) {
      switch (*w) {
      case '*':
         if (bi == MAXB) {
            Eputs ("Too many levels of '*'");
            return (0);
         }
         back[bi][0] = w;
         back[bi][1] = n;
         ++bi;
         ++w;
         continue;
goback:
         --bi;
         while (bi >= 0 && *back[bi][1] == '\0')
            --bi;
         if (bi < 0)
            return (0);
         w = back[bi][0] + 1;
         n = ++back[bi][1];
         ++bi;
         continue;
      case '?':
         if (!*n) {
            if (bi)
               goto goback;
            return (0);
         }
         break;
      default:
         s1 = (*n >= 'A' && *n <= 'Z') ? *n - 'A' + 'a' : *n;
         s2 = (*w >= 'A' && *w <= 'Z') ? *w - 'A' + 'a' : *w;
         if (s1 != s2) {
            if (bi)
               goto goback;
            return (0);
         }
         break;
      }
      if (*n)  ++n;
      if (*w)  ++w;
   }
   return (1);
}


Oputs(str)
char *str;
{
   Write (Cout, str, strlen(str));
   Write (Cout, "\n", 1);
}

Eputs(str)
char *str;
{
   Write (Cerr, str, strlen(str));
   Write (Cerr, "\n", 1);
}

char *
Ogets(str)
char *str;
{
   register int i = 0;

   while (Read(Cin, str + i, 1) == 1) {
      if (str[i] == '\n') {
         str[i] = 0;
         return (str);
      }
      if (++i == 255) {
         str[i] = 0;
         return (str);
      }
   }
   return (NULL);
}

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'c.asm'" '(8559 characters)'
if test -f 'c.asm'
then
	echo shar: "will not over-write existing file 'c.asm'"
else
cat << \!Funky!Stuff! > 'c.asm'

* C.ASM  (ASTARTUP.ASM with modifications)
*
*
* This is exactly Lattice's Astartup.asm with some small modificatons
* to save the BCPL register state on startup.
*
************************************************************************
*
*   C Program Startup/Exit (Combo Version: CLI and WorkBench)
*
************************************************************************
*
*   Source Control:
*
*       $Header$
*
*       $Locker$
*
*       $Log$
*
************************************************************************


******* Included Files *************************************************

   INCLUDE "exec/types.i"
   INCLUDE "exec/alerts.i"
   INCLUDE "exec/nodes.i"
   INCLUDE "exec/lists.i"
   INCLUDE "exec/ports.i"
   INCLUDE "exec/libraries.i"
   INCLUDE "exec/tasks.i"
   INCLUDE "libraries/dos.i"
   INCLUDE "libraries/dosextens.i"
   INCLUDE "workbench/startup.i"


******* Imported *******************************************************

xlib   macro
   xref   _LVO\1
   endm

   xref   _AbsExecBase
   xref   _Input
   xref   _Output

   xref   _main         ; C code entry point

   xlib   Alert
   xlib   FindTask
   xlib   Forbid
   xlib   GetMsg
   xlib   OpenLibrary
   xlib   CloseLibrary
   xlib   ReplyMsg
   xlib   Wait
   xlib   WaitPort

   xlib   CurrentDir
   xlib   Open


******* Exported *******************************************************

   xdef   _SysBase
   xdef   _DOSBase

   xdef   _errno
   xdef   _stdin
   xdef   _stdout
   xdef   _stderr

   xdef   _exit         ; standard C exit function
   xdef   _SysRegs      ; D0-D7 A0-A6 system registers on startup


callsys   macro
   CALLLIB   _LVO\1
   endm


************************************************************************
*
*   Standard Program Entry Point
*
************************************************************************
*
*   main (argc, argv)
*      int  argc;
*      char *argv[]; 
*
************************************************************************

startup:            ; reference for Wack users
      movem.l  D0-D7/A0-A6,_SysRegs
      move.l   sp,initialSP   ; initial task stack pointer
      move.l   d0,dosCmdLen
      move.l   a0,dosCmdBuf
      clr.l   returnMsg

   ;------ get Exec's library base pointer:
      move.l   _AbsExecBase,a6
      move.l   a6,_SysBase

   ;------ get the address of our task
      suba.l   a1,a1
      callsys   FindTask
      move.l   d0,a4

   ;------ are we running as a son of Workbench?
      tst.l   pr_CLI(A4)
      beq   fromWorkbench

;=======================================================================
;====== CLI Startup Code ===============================================
;=======================================================================
fromCLI:
   ;------   attempt to open DOS library:
      bsr   openDOS

   ;------ find command name:
      move.l   pr_CLI(a4),a0
      add.l   a0,a0      ; bcpl pointer conversion
      add.l   a0,a0
      move.l   cli_CommandName(a0),a0
      add.l   a0,a0      ; bcpl pointer conversion
      add.l   a0,a0

   ;------ create buffer and array:
*      link   a6,#-(100+16*4+2*4)
      movem.l   d2/a2/a3,-(sp)
      lea   argvBuffer,a2
      lea   argvArray,a3
*      move.l   a3,16(sp)   ; save 
      moveq.l   #1,d2      ; param counter

   ;------ fetch command name:
      moveq.l   #0,d0
      move.b   (a0)+,d0   ; size of command name
      move.l   a2,(a3)+   ; ptr to command name
      bra.s   1$
2$:      move.b   (a0)+,(a2)+
1$:      dbf   d0,2$
      clr.b   (a2)+

   ;------   collect parameters:
      move.l   dosCmdLen,d0
      move.l   dosCmdBuf,a0

   ;------ skip control characters and space:
3$:      move.b   (a0)+,d1
      subq.l   #1,d0
      ble.s   parmExit
      cmp.b   #' ',d1
      ble.s   3$

   ;------ copy parameter:
      addq.l   #1,d2
      move.l   a2,(a3)+
      bra.s   5$
4$:      move.b   (a0)+,d1
      subq.l   #1,d0
      cmp.b   #' ',d1
      ble.s   6$
5$:      move.b   d1,(a2)+
      bra.s   4$
6$:
      clr.b   (a2)+
      bra.s   3$
parmExit:   clr.b   (a2)+
      clr.l   (a3)+

      move.l   d2,d0
      movem.l   (sp)+,d2/a2/a3
      pea   argvArray
      move.l   d0,-(sp)


*
*  The above code relies on the end of line containing a control
*  character of any type, i.e. a valid character must not be the
*  last.  This fact is ensured by DOS.
*
      

   ;------ get standard input handle:
      jsr   _Input
      move.l   d0,_stdin

   ;------ get standard output handle:
      jsr   _Output
      move.l   d0,_stdout
      move.l   d0,_stderr

   ;------ call C main entry point
      jsr   _main

   ;------ return success code:
      moveq.l   #0,D0
      move.l   initialSP,sp   ; restore stack ptr
      rts

;=======================================================================
;====== Workbench Startup Code =========================================
;=======================================================================
fromWorkbench:
   ;------ open the DOS library:
      bsr   openDOS

   ;------ we are now set up.  wait for a message from our starter
      bsr   waitmsg

   ;------ save the message so we can return it later
      move.l   d0,returnMsg   NOTE: no GetMsg performed

   ;------ push the message on the stack for wbmain
      clr.l   -(SP)      indicate: run from Workbench
      move.l   d0,-(SP)

   ;------ get the first argument
      move.l   d0,a2
      move.l   sm_ArgList(a2),d0
      beq.s   docons

   ;------ and set the current directory to the same directory
      move.l   _DOSBase,a6
      move.l   d0,a0
      move.l   wa_Lock(a0),d1
      callsys   CurrentDir

docons:
   ;------ get the toolwindow argument
      move.l   sm_ToolWindow(A2),d1
      beq.s   domain

   ;------ open up the file
      move.l   #MODE_OLDFILE,d2
      callsys   Open

   ;------ set the C input and output descriptors
      move.l   d0,_stdin
      move.l   d0,_stdout
      move.l   d0,_stderr
      beq.s   domain

   ;------ set the console task (so Open( "*", mode ) will work
   ;   waitmsg has left the task pointer in A4 for us
      lsl.l   #2,d0
      move.l   d0,a0
      move.l   fh_Type(a0),pr_ConsoleTask(A4)

domain:
      jsr   _main
      moveq.l   #0,d0      Successful return code
      bra.s   exit2


************************************************************************
*
*   C Program Exit Function
*
************************************************************************
*
*  Warning: this function really needs to do more than this.
*
************************************************************************

_exit:
      move.l   4(SP),d0   ; extract return code
exit2:
      move.l  initialSP,SP   ; restore stack pointer
      move.l   d0,-(SP)   ; save return code

   ;------ close DOS library:
      move.l   _AbsExecBase,A6
      move.l   _DOSBase,d0
      beq.s   1$
      move.l   d0,a1
1$:      callsys   CloseLibrary

   ;------ if we ran from CLI, skip workbench cleanup:
      tst.l   returnMsg
      beq.s   exitToDOS

   ;------ return the startup message to our parent
   ;   we forbid so workbench can't UnLoadSeg() us
   ;   before we are done:
      callsys Forbid
      move.l   returnMsg,a1
      callsys   ReplyMsg

   ;------ this rts sends us back to DOS:
exitToDOS:
      move.l   (SP)+,d0
      rts


;-----------------------------------------------------------------------
noDOS:
      ALERT   (AG_OpenLib!AO_DOSLib)
      moveq.l   #100,d0
      bra.s   exit2


;-----------------------------------------------------------------------
; This routine gets the message that workbench will send to us
; called with task id in A4

waitmsg:
      lea   pr_MsgPort(A4),a0     * our process base
      callsys   WaitPort
      lea   pr_MsgPort(A4),a0     * our process base
      callsys GetMsg
      rts

;-----------------------------------------------------------------------
;  Open the DOS library:

openDOS
      clr.l   _DOSBase
      lea   DOSName,A1
      move.l   #LIBRARY_VERSION,d0
      callsys OpenLibrary
      move.l   D0,_DOSBase
      beq   noDOS
      rts


************************************************************************

   DATA

************************************************************************

VerRev      dc.w   1,0

_SysBase   dc.l   0
_DOSBase   dc.l   0

_SysRegs    ds.l  16
_errno      dc.l   0
_stdin      dc.l   0
_stdout      dc.l   0
_stderr      dc.l   0

initialSP   dc.l   0
returnMsg   dc.l   0

dosCmdLen   dc.l   0
dosCmdBuf   dc.l   0

argvArray   ds.l   32
argvBuffer   ds.b   256

DOSName      DOSNAME


   END
!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'fexec2.asm'" '(1524 characters)'
if test -f 'fexec2.asm'
then
	echo shar: "will not over-write existing file 'fexec2.asm'"
else
cat << \!Funky!Stuff! > 'fexec2.asm'

;FEXEC2.ASM
;

;  Again, this code originated from Manx, but has been heavily re-written
;

      xdef  _doexec
      xref  _LVOFreeMem
      xref  _SysRegs
      xref  _SysBase

;
;doexec(len, arg, (seg+1)<<2, stk)
;       D0    A0    A4        A7
;

_doexec:
   move.l   sp,savefp            ;save Frame Pointer
   movem.l  d2-d7/a2-a6,-(sp)    ;save Registers
   move.l   sp,savsp             ;save current SP
   movem.l  _SysRegs,D0-D7/A0-A6 ;Get System Startup Registers (BCPL stuff)
   move.l   savefp,A0            ;A0 = frame pointer
   movem.l  4(A0),d0/a0/a4/a7    ;load parameters, including new SP
   move.l   d0,12(a1)            ;set length
   move.l   a0,d1                ;copy to dreg
   lsr.l    #2,d1                ;convert to BPTR
   move.l   d1,8(a1)             ;set ptr
   jsr      (a4)                 ;call new program
   movem.l  (sp)+,d2/d3          ;get stk siz and old sp
   move.l   sp,a1                ;save current sp
   move.l   savsp,sp             ;get back our sp
   move.l   d0,-(sp)             ;save return code so we don't loose it
   sub.l    d2,a1                ;Backup from end of stack to start
   sub.l    #8,a1                ;point over header placed on stack
   move.l   (a1),d0              ;get size to free
   move.l   _SysBase,a6          ;get ExecBase
   jsr      _LVOFreeMem(a6)      ;Free memory allocated for stack
   move.l   (sp)+,d0             ;D0 = return code
   movem.l  (sp)+,D2-D7/A2-A6    ;restore Registers
   rts

savsp:   dc.l   0
savefp:  dc.l   0


!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'shell.h'" '(3258 characters)'
if test -f 'shell.h'
then
	echo shar: "will not over-write existing file 'shell.h'"
else
cat << \!Funky!Stuff! > 'shell.h'

/*
 * SHELL.H
 *
 * (c)1986 Matthew Dillon     9 October 1986
 *
 *
 * SHELL include file.. contains shell parameters and extern's
 *
 *
 */

#include <exec/types.h>

#define MAXAV        128            /* Max. # arguments             */
#define MAXSRC       5              /* Max. # of source file levels */
#define MAXIF        10             /* Max. # of if levels          */
#define MAXALIAS     20             /* Max. # of alias levels       */

#define LEVEL_SET    0              /* which variable list to use   */
#define LEVEL_ALIAS  1
#define LEVEL_LABEL  2

#define V_PROMPT     "_prompt"      /* your prompt (ascii command)   */
#define V_HIST       "_history"     /* set history depth (value)     */
#define V_HISTNUM    "_histnum"     /* set history numbering var     */
#define V_DEBUG      "_debug"       /* set debug mode                */
#define V_VERBOSE    "_verbose"     /* set verbose for source files  */
#define V_STAT       "_maxerr"      /* worst return value to date    */
#define V_LASTERR    "_lasterr"     /* return value from last comm.  */
#define V_CWD        "_cwd"         /* current directory             */
#define V_EXCEPT     "_except"      /* "nnn;command"                 */
#define V_PASSED     "_passed"      /* passed arguments to source fle*/
#define V_PATH       "_path"        /* path prefix,prefix,prefix..   */


            /* EXECOM.C defines */

#define FL_DOLLAR    0x01  /* One of the following */
#define FL_BANG      0x02
#define FL_PERCENT   0x04
#define FL_QUOTE     0x08
#define FL_IDOLLAR   0x10  /* Any or all of the following may be set */
#define FL_EOC       0x20
#define FL_EOL       0x40
#define FL_OVERIDE   0x80
#define FL_WILD      0x100
#define FL_MASK      (FL_DOLLAR|FL_BANG|FL_PERCENT|FL_QUOTE)


#define VERSION   "V2.04  (c)1986 Matthew Dillon. 22Oct86"

#ifndef NULL
#define NULL 0L
#endif

#define CHECKBREAK() ( breakcheck() ? (printf("^C\n"),1) : 0)


struct HIST {
   struct HIST *next, *prev;     /* doubly linked list */
   char *line;                   /* line in history    */
};

struct PERROR {
   short errnum;                 /* Format of global error lookup */
   char *errstr;
};

struct DPTR {                    /* Format of directory fetch pointer */
   struct FileLock *lock;        /* lock on directory   */
   struct FileInfoBlock *fib;    /* mod'd fib for entry */
};

extern struct HIST *H_head, *H_tail;
extern struct PERROR Perror[];
extern struct DPTR *dopen();
extern char *set_var(), *get_var(), *next_word();
extern char *get_history(), *compile_av();
extern char *malloc(), *strcpy(), *strcat(), *AllocMem(), *gets(), *Ogets();
extern char **expand(), *FindIt();


extern char *av[];
extern char *Current;
extern short H_len, H_tail_base, H_stack;
extern short E_stack;
extern short Src_stack, If_stack;
extern short ac;
extern short Debug, Verbose, Disable, Quit;
extern long Lastresult;
extern short Exec_abortline, Exec_ignoreresult;
extern short S_histlen;
extern long Uniq;
extern long Cin, Cout, Cerr, Cout_append;
extern char *Cin_name, *Cout_name;
extern char  Cin_type,  Cout_type;  /* these variables are in transition */
extern char *Pipe1, *Pipe2;

extern int  Src_base[MAXSRC];
extern long Src_pos[MAXSRC];
extern char If_base[MAXIF];


!Funky!Stuff!
fi  # end of overwriting check
exit 0
#	End of shell archive