[net.micro.amiga] Here it is: Shell 2.01A for Manx C

drew@cgfsv1.dec.com (Steve Drew) (10/03/86)

	As promised.	Tried to mail to moderator for mod.sources
	but got bumped back with error's from his system.?

	Anyway, at the moment it will only run under 32 bits.
	But should be easy to modify for 16 bits.
	(READ the DOC file.)

Enjoy,

Steve Drew.


#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	shell.doc
#	makefile
#	shell.h
#	comm2.c
#	set.c
#	sub.c
#	main.c
#	globals.c
#	comm1.c
#	run.c
#	execom.c
# This archive created: Fri Oct  3 12:02:16 1986
echo shar: extracting shell.doc
cat << \SHAR_EOF > shell.doc
		Matt Dillons Shell program.
		--------------------------

INSTRUCTIONS FOR 2.01A (A = AZTEC/MANX only) by Steve Drew
----------------------------------------------------------

    	Steve Drew at	ENET:    CGFSV1::DREW
    	(Calgary,Ab.)	ARPA:    drew%cfgsv1.dec.com@decwrl.dec.com
    			USENET:  {decvax|decwrl}!cgfsv1.dec.com!drew    
			

VERSION RELEASES:
----------------
	2.01A	27-sep-86 Steve Drew  :Major conversion from Lattice > MANX
				      :and added more commands/features.


Background:
----------

	This shell program was written by Matt Dillon and provided for
	public domain. I have added the 'A' varient on the end of the
	version to distinguish between Matt's version's and my modified
	version for Manx C. This is actually equivalent to Matt's version
	2.01 with additional commands/features and will work only on
	Manx C.
	To compile:
		   Make (return).
		   should be about 28500 bytes.
	Enjoy.


Version 2.01A notes:
	
	Differences between Matt Dillons original version and this version
	specifically for Manx C. All of the functionality that Matt Dillon
	so well provided is still there plus many more goodies.

	- All external commands are executed via fexecv() rather than
	  Execute() function. This allows for ^C capability and faster
	  loading. (since run command not needed to load first).	

	  NOTE:
		since I have heard that there maybe problems with
		fexecv() under 1.2 I have include a symbol in shell.h
		to allow the use of Execute() rather than fexecv().
		(Until fexecv() is fixed.)

		set USE_EXECUTE to a 1
		and USE_FEXEC	to a 0  to switch to Execute()
		
		By default it is set to use fexecv().
		
		A couple of disadvantages of using fexec:
			- question marks to ask for prompt
			  on bcpl programs gets ignored.
			- execute (the C: command) a script file
			  will not work. this will: 'run execute file'
	
	- Changed all i/o routines that used MY.LIB written by Matt to
	  use standard i/o or Amiga routines, since Manx is so efficeint
	  with standard i/o routines compiling all those library functions
	  did'nt gain anything as it does with Lattice.
	
	- Dir command rewritten to allow options:
		-s short mutil(4) collum display of files
		-d directorys only
		-f files only
		
		also added date and time stamp for files, and
		for wild carded directories always tells you what
		directory you are listing.
		
	  the directory command will also not expand files that are
 	  directories if as result of a wildcard expansion. eg:
	  'dir df0:*'  and 'dir df0:' will give same results
	  expect previously if df0:* was specified all subdirectories
	  of df0: were expanded also.
	  (to list the subdirectories: 'dir df0:*/*')
				
	- Wildcarding now matches upper or lower case.	
	
	- Command will no longer abort if one of the arguments which
	  has wild card does not expand.

	- run program >redir will work properly with Shell 2.01A, as
	  long as you run command is called 'run'. With the lattice 
	  version the command got parsed like run >redir program, so
   	  all you got in you redir file was [CLI n].
	
	- CD command rewritten. Will change any input such as cd df0:work
	  to be Disklabel:work, this makes it real easy when switching
	  disks arround. Also checks if file is a directory.
	  Note: if you for some reason do a CD dir (note upper case so
	  	will run c:CD command) it will change you current dir
		and will be handled properly.

	   some examples
		cd df0:sub/sub2		
		cd /	   will set you to parent directory
		cd //	   two levels up
		cd /progs  one level up and back down in progs
	
	- On startup you current directory is determined and set.
	
	- Added %full and volume name to devinfo.

	- copy command added. (faster that COPY under 1.1 workbench)
	  format:
		copy dir/file		copies file to current dir
		copy work/* [to] new    copies all files from directory work
					  to directory new
		copy foo foo2		copies foo to foo2
		copy >nil: * [to] df1:  copies all files in current directory
					  to df1: & logs it to nil:
	  (at present it will not create directorys or do a ALL option like
	   c:COPY does).
	
	- ps command added. gives the folling info:
	  
	  Proc Command Name         CLI Type    Pri.  Address  Directory
 	   1   SHELL                Initial CLI   0      97b0  Stuff:shell
	   2   sys:c/clockmem       Background  -10    2101a8  Workdisk:
	   3   c:emacs              Background    0    212f58  Stuff:shell
	   4   sys:c/VT100          Background    0    227328  Workdisk:
	
	   Address is the addres of the task, directory is the process
	   currently set directory.

	- New special symbol '_lasterror' is set to a non zero function
	  when a command fails. Set to -1 when an iternal command fails
	  or to the value of the return code if an external command fails.

   What follow are Matt's instructions for version 2.01. Which is
   still the same for 2.01A.
	
============================================================================ 


INSTRUCTIONS FOR SHELL 2.01
 
 
      (A)   Compiling
      (B)   Overview
      (C)   Quicky tech notes on implimentation.
 
      (D)   Command pre-processor
      (E)   Command-list
      (F)   special SET variables
 
      (G)   example .login file.
 
 
(A) COMPILING:

	see notes on 2.01A above.
 
(B) OVERVIEW:
 
   overview of the major features:
 
   -simple history
   -redirection
   -piping
   -aliases
   -variables & variable handling
   -file name expansion via '?' and '*'
   -conditionals
   -source files  (w/ gotos and labels)
   -many built in commands to speed things up
 
 
   changes from V1.02:
 
   -you can now redirect through internal commands as well as external.
   -piping has been added.  You can pipe from/to internal commands.
   -you can now embed strings ( charlie/$var/ben ), making the shell more
    flexible.
   -history substitution displays line to be executed.
   -verbose mode for debugging source files
   -break handled a little better (still can't send break to external
    commands)
   -some new commands
 
 
 
   sorry, I still havent figured out how to get the return value from
   external commands.
 
 
(C) QUICK TECH NOTES:
 
   PIPES have been implimented using temporary RAM: files.  Thus, you
   should be careful when specifying a 'ram:*' expansion as it might
   include the temp. files.  These files are deleted on completion of
   the pipe segment.
 
   My favorite new feature is the fact that you can now redirect to and
   from, and pipe internal commands.  'echo charlie >ram:x', for
   instance.  Another favorite:
 
      echo "echo mem | shell" | shell
 
   To accomplish these new features, I completely re-wrote the command
   parser in execom.c
 
 
(D) COMMAND LINE PRE-PROCESSING:
 
   preprocessing is done on the command line before it is passed on to
   an internal or external routine:
 
   ^c       where c is a character is converted to that control character.
            Thus, say '^l' for control-l.
 
   $name    where name is a variable name.  Variable names can consist of
            0-9, a-z, A-Z, and underscore (_).  The contents of the
            specified variable is used.  If the variable doesn't exist,
            the specifier is used.  That is, if the variable 'i' contains
            'charlie', then '$i' -> 'charlie'.  If the variable 'i' doesn't
            exist, then '$i'->'$i' .
 
   ;        delimits commands.   echo charlie ; echo ben.
 
   ' '      (a space). delimits arguments.
 
   "string" a quoted string.  For instance, if you want to echo five spaces
            and an 'a':
 
            echo      a       -> a
            echo "    a"      ->      a
 
   \c       overide the meaning of special characters.  '\^a' is a
            circumflex and an a rather than control-a.  To get a backslash,
            you must say '\\'.
 
   >file    specify output redirection.  All output from the command is
            placed in the specified file.
 
   <file    specify input redirection.  The command takes input from the
            file rather than the keyboard (note: not all commands require
            input).  It makes no sense to say  'echo <charlie' since
            the 'echo' command only outputs its arguments.
 
   |        PIPE specifier.  The output from the command on the left becomes
            the input to the command on the right.  The current SHELL
            implimentation uses temporary files to store the data.
 
   !!       execute the previously executed command.
   !nn      (nn is a number).  Insert the history command numbered n (see
            the HISTORY command)
   !partial search backwards through the history list for a command which
            looks the same as 'partial', and execute it.
 
 
 
(E)  COMMAND LIST:
 
   The first argument is the command-name... if it doesn't exist in the
   list below and isn't an alias, it is assumed to be an external (disk)
   command.
 
   NOTE: Many CLI specific external commands, such as 'path', and 'cd' will
   have no effect on the shell.  However, you can execute these commands
   from the initial CLI (startup script) BEFORE you run the shell.
 
 
   HELP
 
      simply displays all the available commands.
 
 
   QUIT
 
      quit my SHELL (awww!).  End, El-Zappo, Kapow. Done, Finis
 
 
   SET
   SET name
   SET name string
 
      The first method lists all current variable settings.
      The second method lists the setting for that particular variable,
      or creates the variable if it doesn't exist (to "")
      The last method sets a variable to a string.
 
 
   UNSET name name name....
 
      unset one or more variables.  Deletes them entirely.
 
 
   ALIAS
   ALIAS name
   ALIAS name string
 
      same as SET, but applies to the alias list.  You can alias a single
      name to a set of commands.  For instance:
 
      alias hi "echo a; echo b"
 
      then you can simply say 'hi'.  Aliases come in two forms the second
      form allows you to place the arguments after an alias in a variable
      for retrieval:
 
      alias xxx "%i echo this $i is a test"
 
      % xxx charlie
      this charlie is a test
 
      The rest of the command line is placed in the specified variable
      for the duration of the alias.  This is especially useful when used
      in conjunction with the 'FOREACH' command.
 
 
   UNALIAS name name name...
 
      delete aliases..
 
 
   ECHO string
   ECHO -n string
 
      echo the string to the screen.  If '-n' is specified, no newline is
      output.
 
 
   STRHEAD  varname breakchar string
 
      remove everything after and including the breakchar in 'string' and
      place in variable 'varname':
 
         % strhead j . aaa.bbb
         % echo $j
         aaa
         %
 
 
   STRTAIL  varname breakchar string
 
      remove everything before and including the breakchar in 'string' and
      place in variable 'varname':
 
         % strtail j . aaa.bbb
         % echo $j
         bbb
         %
 
 
   SOURCE file
 
      execute commands from a file.  You can create SHELL programs in
      a file and then execute them with this command.  Source'd files
      have the added advantage that you can have loops in your command
      files (see GOTO and LABEL)
 
 
   MV from to
 
      Exactly the Rename() call.  Allows you to rename files or move them
      around within a disk.
 
 
   CD ..
   CD path
 
      Change your current working directory.  You may specify '/' to go
      back one directory.
 
 
   RM file file file...
 
      DeleteFile().  Remove the specified files.
 
 
   MKDIR name name name...
 
      create the following directories.
 
 
   HISTORY [partial string]
 
      Displays the enumerated history list.  The size of the list is
      controlled by the _history variable.  If you specify a partial-
      string, only those entries matching that string are displayed.
 
 
   MEM
 
      Display current memory statistics.
 
 
   CAT [file file....]
 
      Type the specified files onto the screen.  If no file is specified,
      STDIN in used.
 
 
   DIR [path path ... ]
 
      Get a directory listing of the current directory or specified
      directories.
 
 
   DEVINFO [device: device:... ]
 
      Display Device statistics for the current device (CD base), or
      specified devices.
 
 
   FOREACH varname ( strings ) command
 
      'strings' is broken up into arguments.  Each argument is placed in
      the variable 'varname' in turn and 'command' executed.  To execute
      multiple commands, place them in quotes:
 
      % foreach i ( a b c d ) "echo -n $i;echo \" ha\""
      a ha
      b ha
      c ha
      d ha
 
 
   RETURN [value]
 
      return from a source file.  The rest of the source file is
      discarded.  Currently, the optional value is thrown away.
 
 
   IF argument conditional argument ;
   IF argument
 
      If a single argument is something to another argument.  Conditional
      clauses allowed:
 
      <, >, =, and combinations (wire or).  Thus <> is not-equal, >=
      larger or equal, etc...
 
      If the left argument is numeric, both arguments are treated as
      numeric.
 
      usually the argument is either a constant or a variable ($varname).
 
      The second form if IF is conditional on the existance of the argument.
      If the argument is a "" string, then false , else TRUE.
 
 
   ELSE ;
 
      else clause.
 
 
   ENDIF ;
 
      the end of an if statement.
 
 
   LABEL name
 
      create a program label right here.
 
 
 
   GOTO label
 
      goto the specified label name.  You can only use this command from a
      source file.
 
 
 
   FAILAT
   CHECKBREAK
 
      not implimented yet.
 
 
   DEC var
   INC var
 
      decrement or increment the numerical equivalent of the variable and
      place the ascii-string result back into that variable.
 
 
 
   INPUT varname
 
      input from STDIN (or a redirection, or a pipe) to a variable.  The
      next input line is placed in the variable.
 
 
   VER
 
      display my name and the version number.
 
 
   SLEEP timeout
 
      Sleep for 'timeout' seconds.
 
 
 
(F) SPECIAL SET VARIABLES
 
   _prompt
         This variable is set to the command you wish executed that will
         create your prompt.
 
   _history
         This variable is set to a numerical value, and specifies how far
         back your history should extend.
 
   _debug
         Debug mode... use it if you dare.
 
   _verbose
         Verbose mode (for source files).  display commands as they are
         executed.
 
 
 
(G) EXAMPLE .login file.
 
   from a CLI or the startup-script say 'SHELL filename'.  That file
   is sourced first.  thus, 'SHELL .login' will set up your favorite
   aliases:
 
   ------------------------------ example source file -----------------
 
echo "shells, Matt"
alias l     "%var if $var;echo $var;else;echo *;endif"
alias c     "echo ^l"
alias cc    "assign c: cb:c  ;cd ram:"
alias wb    "assign c: sys:c ;cd ram:"
alias ram   "cp c:run ram:; cp c:assign ram:; cp c:cp ram:; assign c: ram:"
alias ram2  "assign c: ram:"
alias ed    "run ED"
alias c1    "%z foreach y ( $z ) \"echo $y;lc1 -o$temp -i$incdir/ -i$incdir/lattice/ $y\";echo DONE"
alias c2    "%z foreach y ( $z ) \"echo $y;lc2 -s -v $temp$y\";echo DONE"
alias ld    "%var alink faster $libdir/lstartup.obj+$var library $libdir/lc.lib+$libdir/amiga.lib to $dest"
alias lds   "%var alink faster $libdir/Astartup.obj+$var library $libdir/my.lib+$libdir/amiga.lib+$libs to $dest"
set dest ram:a
set temp ram:
set libdir cb:clib
set incdir cb:include
set libs $libdir/lc.lib
cd ram:
 
   --------------------------------------------------------------------
SHAR_EOF
if test 15641 -ne "`wc -c shell.doc`"
then
echo shar: error transmitting shell.doc '(should have been 15641 characters)'
fi
echo shar: extracting makefile
cat << \SHAR_EOF > makefile
######################################################################
#
# Makefile to build Shell 2.01a
# by Steve Drew 27-sep-86
#
######################################################################

OBJS	= comm1.o comm2.o main.o run.o execom.o set.o sub.o globals.o 


INCL	= shell.h


Shell	: $(OBJS)
	ln   -o Shell $(OBJS) -lc32
	@Echo "Done Building Shell"

comm1.o	: comm1.c $(INCL)
	cc  +L  +HShell.syms comm1.c

comm2.o	: comm2.c $(INCL)
	cc  +L  +IShell.syms comm2.c

main.o  : main.c $(INCL)
	cc  +L  +IShell.syms main.c

run.o   : run.c $(INCL)
	cc  +L  +IShell.syms run.c

set.o	: set.c $(INCL)
	cc  +L  +IShell.syms set.c

sub.o	: sub.c $(INCL)
	cc  +L  +IShell.syms sub.c

globals.o : globals.c $(INCL)
	cc  +L  +IShell.syms globals.c

execom.o : execom.c $(INCL)
	cc  +L  +IShell.syms execom.c

SHAR_EOF
if test 814 -ne "`wc -c makefile`"
then
echo shar: error transmitting makefile '(should have been 814 characters)'
fi
echo shar: extracting shell.h
cat << \SHAR_EOF > shell.h
 
/*
 * SHELL.H
 *
 * Matthew Dillon, 24 Feb 1986
 * version 2.01A (Manx ver) by Steve Drew 27 Sep 1986
 *
 */

/* set one of these two symbols depending on to use dos Execute() func.
 * or manx fexecv() function. This flexibility provided because of
 * rumors that fexecv() doesnt work under 1.2 so can be a temporary
 * workaround. 
 */

#define USE_FEXEC   1			/* best way to go */
#define USE_EXECUTE 0


#include <stdio.h>
#include <time.h> 
#include <exec/types.h>
#include <exec/exec.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <exec/memory.h>
#include <exec/tasks.h>

#define bmov   movmem
 
#define MAXAV        200            /* Max. # arguments             */
#define MAXSRC       5              /* Max. # of source file levels */
#define MAXIF        10             /* Max. # of if levels          */
 
#define LEVEL_SET    0
#define LEVEL_ALIAS  1
#define LEVEL_LABEL  2
 
#define M_RESET      0
#define M_CONT       1
 
#define V_PROMPT     "_prompt"      /* Special variable names */
#define V_HIST       "_history"
#define V_DEBUG      "_debug"
#define V_VERBOSE    "_verbose"
#define V_LASTERROR  "_lasterror"
 
#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.01A  (c)1986 Matthew Dillon. Manx ver(A) By Steve Drew"
 
#undef NULL
#define NULL ((void *)0)

 
#define CHECKBREAK() ( breakcheck() ? (printf("^C\n"),1) : 0)
 
 
struct HIST {
   struct HIST *next, *prev;     /* doubly linked list */
   char *line;                   /* line in history    */
};
 
struct PERROR {
   int 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();
char *malloc(), *strcpy(), *AllocMem();
extern char **expand();
 
extern char *av[];
extern char *Current;
extern int  H_len, H_tail_base, H_stack;
extern int  Src_stack, If_stack;
extern int  ac;
extern int  Debug, Rval, Verbose, Disable, Faillevel, Quit;
extern int  S_histlen;
extern long Uniq;
extern struct Process *Myprocess;
extern long Cin, Cout;
extern char *Cin_name, *Cout_name;
extern char *Pipe1, *Pipe2;
 
extern long Src_base[MAXSRC];
extern long Src_pos[MAXSRC];
extern char If_base[MAXIF];



SHAR_EOF
if test 2853 -ne "`wc -c shell.h`"
then
echo shar: error transmitting shell.h '(should have been 2853 characters)'
fi
echo shar: extracting comm2.c
cat << \SHAR_EOF > comm2.c
/*
 * MORE commands
 * Matt Dillon
 * version 2.01A (Manx ver) by Steve Drew 27 Sep 1986
 */
 
#include "shell.h"

#define BPTR_TO_C(strtag, var)  ((struct strtag *)(BADDR( (ULONG) var)))

#define TO_ASC(n)       ((n) + '0')             /* make it printable! */

/* Casting conveniences */
#define PROC(task)              ((struct Process *)task)
#define ROOTNODE                ((struct RootNode *)DOSBase->dl_Root)
#define CLI(proc)               (BPTR_TO_C(CommandLineInterface, proc->pr_CLI))

/* Externs */
extern struct DosLibrary *DOSBase;      /* dos library base pointer */
 
do_return()
{
   if (Src_stack) {
      fseek (Src_base[Src_stack - 1], 0, 2);  /* ch to 2 fr 1 */
      Rval = (ac < 2) ? 1 : atoi(av[1]);
      return (-1);
   } else {
      main_exit ((ac < 2) ? 1 : atoi(av[1]));
   }
}
 
/*
 * STRHEAD
 *
 * place a string into a variable removing everything after and including
 * the 'break' character or until a space is found in the string.
 *
 * strhead varname breakchar string
 *
 */
 
do_strhead()
{
   register char *str = av[3];
   char bc = *av[2];
 
   while (*str && *str != bc)
      ++str;
   *str = '\0';
   set_var (LEVEL_SET, av[1], av[3]);
}
 
do_strtail()
{
   register char *str = av[3];
   char bc = *av[2];
 
   while (*str && *str != bc)
      ++str;
   if (*str)
      ++str;
   set_var (LEVEL_SET, av[1], str);
}
 
 
 
/*
 * if A < B   <, >, =, <=, >=, !=, where A and B are either:
 * nothing
 * a string
 * a value (begins w/ number)
 */
 
do_if(garbage, com)
char *garbage;
{
   char *v1, *v2, *v3, result, num;
   int n1, n2;
 
   switch (com) {
   case 0:
      if (If_stack && If_base[If_stack - 1]) {
         If_base[If_stack++] = 1;
         break;
      }
      result = num = 0;
      if (ac <= 2) {       /* if $var; */
         if (ac == 1 || strlen(av[1]) == 0 || (strlen(av[1]) == 1 && *av[1] == ' '))
            goto do_result;
         result = 1;
         goto do_result;
      }
      if (ac != 4) {
         ierror(NULL, 500);
         break;
      }
      v1 = av[1]; v2 = av[2]; v3 = av[3];
      while (*v1 == ' ')
         ++v1;
      while (*v2 == ' ')
         ++v2;
      while (*v3 == ' ')
         ++v3;
      if (*v1 >= '0' && *v1 <= '9') {
         num = 1;
         n1 = atoi(v1);
         n2 = atoi(v3);
      }
      while (*v2) {
         switch (*v2++) {
         case '>':
            result |= (num) ? (n1 >  n2) : (strcmp(v1, v3) > 0);
            break;
         case '<':
            result |= (num) ? (n1 <  n2) : (strcmp(v1, v3) < 0);
            break;
         case '=':
            result |= (num) ? (n1 == n2) : (strcmp(v1, v3) ==0);
            break;
         default:
            ierror (NULL, 503);
            break;
         }
      }
do_result:
      If_base[If_stack++] = !result;
      break;
   case 1:
      if (If_stack > 1 && If_base[If_stack - 2])
         break;
      if (If_stack)
         If_base[If_stack - 1] ^= 1;
      break;
   case 2:
      if (If_stack)
         --If_stack;
      break;
   }
   Disable = (If_stack) ? If_base[If_stack - 1] : 0;
   return (0);
}
 
do_label()
{
   char aseek[32];
 
   if (Src_stack == 0) {
      ierror (NULL, 502);
      return (-1);
   }
   sprintf (aseek, "%ld %ld", Src_pos[Src_stack-1], If_stack);
   set_var (LEVEL_LABEL + Src_stack - 1, av[1], aseek);
   return (0);
}
 
do_goto()
{
   int new;
   long pos;
   char *lab;
 
   if (Src_stack == 0) {
      ierror (NULL, 502);
   } else {
      lab = get_var (LEVEL_LABEL + Src_stack - 1, av[1]);
      if (lab == '\0') {
         ierror (NULL, 501);
      } else {
         pos = atoi(lab);
         fseek (Src_base[Src_stack - 1], pos, 0);
         Src_pos[Src_stack - 1] = pos;
         new = atoi(next_word(lab));
         for (; If_stack < new; ++If_stack)
            If_base[If_stack] = 0;
         If_stack = new;
      }
   }
   return (-1);      /* Don't execute reset of this line */
}
 
 
do_failat()
{
   Faillevel = 1;
   fprintf (stderr, "NOT IMPLIMENTED YET\n");
}
 
do_checkbrk()
{
   fprintf (stderr,"NOT IMPLIMENTED YET\n");
}
 
do_inc(garbage, com)
char *garbage;
{
   char *var;
   char num[32];
 
   if (ac == 3)
      com = atoi(av[2]);
   var = get_var (LEVEL_SET, av[1]);
   if (var) {
      sprintf (num, "%d", atoi(var)+com);
      set_var (LEVEL_SET, av[1], num);
   }
}
 
do_input()
{
   char in[256];
 
   if ((gets(in)) != 0)
      set_var (LEVEL_SET, av[1], in);
   return (0);
}
 
do_ver()
{
   puts (VERSION);
   return (0);
}
 
 

do_ps()
{
	/* this code fragment based on ps.c command by Dewi Williams */

        register ULONG   *tt;           /* References TaskArray         */
        register int     count;         /* loop variable                */
        register UBYTE   *port;         /* msgport & ptr arith          */
        register struct Task *task;     /* EXEC descriptor              */
        char             strbuf[64];   /* scratch for btocstr()        */
        char             *btocstr();    /* BCPL BSTR to ASCIIZ          */

        tt = (unsigned long *)(BADDR(ROOTNODE->rn_TaskArray));

        printf("Proc Command Name         CLI Type    Pri.  Address  Directory\n");
        Forbid();               /* need linked list consistency */
        
        for (count = 1; count <= (int)tt[0] ; count++) {/* or just assume 20?*/
                if (tt[count] == 0) continue;           /* nobody home */

                /* Start by pulling out MsgPort addresses from the TaskArray
                 * area. By making unwarranted assumptions about the layout
                 * of Process and Task structures, we can derive these
                 * descriptors. Every task has an associated process, since
                 * this loop drives off a CLI data area.
                 */

                port = (UBYTE *)tt[count];
                task = (struct Task *)(port - sizeof(struct Task));

                /* Sanity check just in case */
                if (PROC(task)->pr_TaskNum == 0 || PROC(task)->pr_CLI == 0)
                        continue;               /* or complain? */

                        btocstr(CLI(PROC(task))->cli_CommandName, strbuf);
			printf("%2ld   %-21s",count,strbuf);
			strcpy(strbuf,task->tc_Node.ln_Name);
                        strbuf[11] = '\0';
                        printf("%s",strbuf);
                        printf(" %3ld  %8lx  %s\n",
                           task->tc_Node.ln_Pri,task,
                           btocstr(CLI(PROC(task))->cli_SetName, strbuf));
        }
        Permit();               /* outside critical region */
        return(0);
}


char *
btocstr(b, buf)
ULONG   b;
char    *buf;
{
        register char   *s;

        s = (char *)BADDR(b);   /* Shift & get length-prefixed str */
        bmov(s +1, buf, s[0]);
        buf[s[0]] = '\0';
        return buf;
}

SHAR_EOF
if test 6813 -ne "`wc -c comm2.c`"
then
echo shar: error transmitting comm2.c '(should have been 6813 characters)'
fi
echo shar: extracting set.c
cat << \SHAR_EOF > set.c
/*
 * SET.C
 *
 * Matthew Dillon, July 1986
 * version 2.01A (Manx ver) by Steve Drew 27 Sep 1986
 *
 */
 
#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)
register char *name, *str;
{
   register struct MASTER *base = Mbase[level];
   register struct MASTER *last;
   register int 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)
register char *name;
{
   register struct MASTER *base = Mbase[level];
   register unsigned char *scr;
   register int len;
 
   for (scr = (unsigned char *)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)
{
   register struct MASTER *base = Mbase[level];
 
   while (base) {
      Free (base->name);
      Free (base->text);
      Free (base);
      base = base->next;
   }
   Mbase[level] = '\0';
}
 
unset_var(level, name)
char *name;
{
   register struct MASTER *base = Mbase[level];
   register struct MASTER *last = '\0';
   register int 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 (0);
      }
      last = base;
      base = base->next;
   }
   return (-1);
}
 
 
do_unset_var(str, level)
char *str;
{
   register int i;
 
   for (i = 1; i < ac; ++i)
      unset_var (level, av[i]);
   return (0);
}
 
do_set_var(command, level)
char *command;
{
   register struct MASTER *base = Mbase[level];
   register char *str;
 
   if (ac == 1) {
      while (base) {
         printf ("%-10s ", base->name);
         puts (base->text);
         base = base->next;
      }
      return (0);
   }
   if (ac == 2) {
      str = get_var (level, av[1]);
      if (str) {
         printf ("%-10s ", av[1]);
         puts(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);
}
 
 
SHAR_EOF
if test 3622 -ne "`wc -c set.c`"
then
echo shar: error transmitting set.c '(should have been 3622 characters)'
fi
echo shar: extracting sub.c
cat << \SHAR_EOF > sub.c
/*
 * SUB.C
 *
 * Matthew Dillon, 24 Feb 1986
 * version 2.01A (Manx ver) by Steve Drew 27 Sep 1986
 *
 */
 
#include "shell.h"
 
#define HM_STR 0
#define HM_REL 1
#define HM_ABS 2
 
extern struct FileLock *Lock(), *DupLock(), *CurrentDir();
extern struct FileLock *Clock;
 
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)
char **av;
{
   char *cstr;
   int 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)
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 = '\0';
   } else {
      hist->next = H_head;
      H_head->prev = hist;
      H_head = hist;
   }
   hist->prev = '\0';
   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 = '\0';
      } else {
         free (H_tail);
         H_tail = H_head = '\0';
      }
   }
}
 
char *
get_history(ptr)
char *ptr;
{
   register struct HIST *hist;
   register int len;
   int mode = HM_REL;
   int num  = 1;
   char *str;
   char *result = '\0';
 
   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) {
            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)
      fprintf (stderr, "%s\n",result);
   return (result);
}
 
 
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;
{
   int ierr = (long)IoErr();
   ierror(str, ierr);
}
 
ierror(str, err)
register char *str;
{
   register struct PERROR *per = Perror;
 
   if (err) {
      for (; per->errstr; ++per) {
         if (per->errnum == err) {
            fprintf (stderr,"%s%s%s\n",
                  per->errstr,
                  (str) ? ": " : "",
                  (str) ? str : "");
            return (err);
         }
      }
      fprintf (stderr, "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;
int *stat;
{
   struct DPTR *dp;
   int namelen, endslash = 0;
   getcd();			/* incase someone CD'd with c:CD dir */
   namelen = strlen(name);
/*   if (namelen && name[namelen - 1] == '/') { 
      name[namelen - 1] = '\0';           
      endslash = 1;
   } */
   *stat = 0;
   dp = (struct DPTR *)malloc(sizeof(struct DPTR));
   if (*name == '\0')
      dp->lock = DupLock (Clock);
   else
      dp->lock = Lock (name, ACCESS_READ);
   if (endslash)
      name[namelen - 1] = '/';
   if (dp->lock == '\0') {
      free (dp);
      return (NULL);
   }
   dp->fib = (struct FileInfoBlock *)
         AllocMem((long)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)
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)
struct DPTR *dp;
{
   if (dp == NULL)
      return (1);
   if (dp->fib)
      FreeMem (dp->fib, (long)sizeof(*dp->fib));
   if (dp->lock)
      UnLock (dp->lock);
   free (dp);
   return (1);
}
 
free_expand(av)
char **av;
{
   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;
{
   char **eav = (char **)malloc (sizeof(char *));
   int  eleft, eac;
 
   char *ptr, *name;
   char *bname, *ename, *tail;
   int stat, scr;
   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);
      fprintf (stderr,"Could not open directory\n");
      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] = '\0';
   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;
{
   char *w = wild;
   char *n = name;
   char *back[MAXB][2];
   int  bi = 0;
 
   while (*n || *w) {
      switch (*w) {
      case '*':
         if (bi == MAXB) {
            fprintf (stderr,"Too many levels of '*'\n");
            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:
         if (tolower(*n) != tolower(*w)) {
            if (bi)
               goto goback;
            return (0);
         }
         break;
      }
      if (*n)  ++n;
      if (*w)  ++w;
   }
   return (1);
}
 
SHAR_EOF
if test 9889 -ne "`wc -c sub.c`"
then
echo shar: error transmitting sub.c '(should have been 9889 characters)'
fi
echo shar: extracting main.c
cat << \SHAR_EOF > main.c
 
/*
 * MAIN.C
 *
 * Matthew Dillon, 24 Feb 1986
 *
 * el main routine.
 */
 
#include "shell.h"

#define STDBUF 256

extern long SetSignal();
extern char *btocstr();
extern char Dir_name[];
extern struct FileLock *Clock; 

char Inline[256];
char stdin_buff[STDBUF];
char stdout_buff[STDBUF]; 
main(argc, argv)
register char *argv[];
{
   char *prompt;
   register int i;
   extern int Enable_Abort;
   init_vars();
   init();
   getcd();
   
   Enable_Abort = 0;
     
   for (i = 1; i < argc; ++i) {
      strcpy (Inline, "source ");
      strcat (Inline, argv[i]);
      do_source (Inline, 0);
   }
   for (;;) {
      if ((prompt = get_var (LEVEL_SET, V_PROMPT)) == NULL)
         prompt = "echo -n \"$ \"";
      if (breakcheck()) {
         while (WaitForChar(Input(), 1L))
            gets(Inline);
      }
      ++H_stack;
      exec_command (prompt);
      --H_stack;
      if (Quit || !gets(Inline))
         main_exit(0);
      breakreset();
      if (*Inline)
         exec_command(Inline);
      fflush(stdout);
   }
}
 
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_LASTERROR, "0");
}
 
init()
{
   static char pipe1[32], pipe2[32];
   struct Process *FindTask();

   Myprocess = FindTask(0L); 
   stdin->_buff = stdin_buff;
   stdin->_buflen = STDBUF;
   stdout->_buff = stdout_buff;
   stdout->_buflen = STDBUF; 

   Uniq  = (long)Myprocess;
   Pipe1 = pipe1;
   Pipe2 = pipe2;
   sprintf (pipe1, "ram:pipe1_%ld", Uniq);
   sprintf (pipe2, "ram:pipe2_%ld", Uniq);
}
 
 
main_exit(n)
{
   exit (n);
}
 
breakcheck()
{
   if (SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
      return (1);
   else
      return (0);
}
 
breakreset()
{
   SetSignal(0L, SIGBREAKF_CTRL_C);
}

   /* set the current lock and extract the cd'd string  */
   
getcd()
{

   Clock = (struct FileLock *)( (ULONG)Myprocess->pr_CurrentDir);
   if (!Clock) exec_command("cd DF0:"); /* must be boot device */
   btocstr(
        ((struct CommandLineInterface *)BADDR(Myprocess->pr_CLI))->cli_SetName,
   	Dir_name);
}


/* this routine causes manx to use this Chk_Abort() rather than it's own */
/* otherwise it resets our ^C when doing any I/O (even when Enable_Abort */
/* is zero).  Since we want to check for our own ^C's 			 */

Chk_Abort()
{
return(0);
}


SHAR_EOF
if test 2407 -ne "`wc -c main.c`"
then
echo shar: error transmitting main.c '(should have been 2407 characters)'
fi
echo shar: extracting globals.c
cat << \SHAR_EOF > globals.c
 
/*
 * GLOBALS.C
 *
 * Matthew Dillon, 24 Feb 1986
 *
 */
 
 
#include "shell.h"
 
struct HIST *H_head, *H_tail;
 
struct PERROR Perror[] = {
   103,  "insufficient free storage",
   105,  "task table full",
   120,  "argument line invalid or too long",
   121,  "file is not an object module",
   122,  "invalid resident library during load",
   201,  "no default directory",
   202,  "object in use",
   203,  "object already exists",
   204,  "directory not found",
   205,  "object not found",
   206,  "bad stream name",
   207,  "object too large",
   209,  "action not known",
   210,  "invalid stream component name",
   211,  "invalid object lock",
   212,  "object not of required type",
   213,  "disk not validated",
   214,  "disk write protected",
   215,  "rename across devices",
   216,  "directory not empty",
   217,  "too many levels",
   218,  "device not mounted",
   219,  "seek error",
   220,  "comment too long",
   221,  "disk full",
   222,  "file delete protected",
   223,  "file write protected",
   224,  "file read protected",
   225,  "not a DOS disk",
   226,  "no disk",
   232,  "no more entries in directory",
 
   /* custom error messages */
 
   500,  "bad arguments",
   501,  "label not found",
   502,  "must be within source file",
   503,  "Syntax Error",
   504,  "redirection error",
   505,  "pipe error",
   506,  "too many arguments",
     0,  NULL
};
 
char  *av[MAXAV];
long  Src_base[MAXSRC];
long  Src_pos[MAXSRC];
char  If_base[MAXIF];
int   H_len, H_tail_base, H_stack;
int   Src_stack, If_stack;
int   ac;
int   Debug, Rval, Disable, Faillevel, Verbose;
int   Quit;
long  Cout, Cin;              /* current input and output file handles */
long  Uniq;                   /* unique value */
struct Process *Myprocess;    
char  *Cin_name, *Cout_name;  /* redirection input/output name or NULL */
char  *Pipe1, *Pipe2;         /* the two pipe temp. files              */
 
int   S_histlen = 20;



SHAR_EOF
if test 1953 -ne "`wc -c globals.c`"
then
echo shar: error transmitting globals.c '(should have been 1953 characters)'
fi
echo shar: extracting comm1.c
cat << \SHAR_EOF > comm1.c
/*
 * COMM1.C
 *
 * Matthew Dillon, August 1986
 * version 2.01A (Manx ver) by Steve Drew 27 Sep 1986
 *
 *
 *
 */

#include "shell.h"
 
#define DIR_SHORT 0x01
#define DIR_FILES 0x02
#define DIR_DIRS  0x04

#define BPTR_TO_C(strtag, var)  ((struct strtag *)(BADDR( (ULONG) var)))
#define C_TO_BPTR(strtag, var)  ((struct strtag *)(((ULONG)var)>>2))

extern struct FileLock  *CreateDir(), *CurrentDir(), *ParentDir();
extern struct FileLock  *Lock(), *DupLock();
extern char *AllocMem();
extern struct FileHandle *Open();
extern char *btocstr();
extern int has_wild;
char Dir_name[60];
struct FileLock *Clock;
  
do_sleep()
{
   register int i;
 
   if (ac == 2) {
      i = atoi(av[1]);
      while (i > 0) {
         Delay ((long)50*2);
         i -= 2;
         if (CHECKBREAK())
            break;
      }
   }
   return (0);
}
 
 
do_number()
{
   return (0);
}
 
do_cat()
{
   FILE *fopen(), *fi;
   int i;
   char buf[256];

   if (ac == 1) {
      while (gets(buf)) {
      	 if (CHECKBREAK()) break;
         puts(buf);
         }
      clearerr(stdin);
      return (0);
   }

   for (i = 1; i < ac; ++i) {
      if ((fi = fopen (av[i], "r")) != 0) {
           while (fgets(buf,256,fi)) {
            fputs(buf,stdout);
            fflush(stdout); 
            if (CHECKBREAK())
               break;
         }
         fclose (fi);
      } else {
         fprintf (stderr, "could not open %s\n", av[i]);
      }
   }
   return (0);
}

/* things shared with disp_entry */

int   filecount, col; 
long  bytes, blocks;

do_dir(garbage, com)
char *garbage;
{
   void   		disp_entry();
   struct DPTR          *dp;
   struct InfoData      *info;
   char                 *name;
   int                  i = 0, stat, clen, more;
   char                 options = 0;
   char                 *c;
   char                 lspec[60];
   char                 volume[40];
   char                 *volname();
   char			*dates();
  
   col = filecount = 0;
   bytes = blocks = 0L;
   
   while((++i < ac) && (av[i][0] == '-')) {
   	for (c = av[i]+1; *c ; c++) {
   		switch(*c) {
   			case 's':
   				options |= DIR_SHORT;
   				break;
   			case 'f':
   				options |= DIR_FILES;
   				break;
   			case 'd':
   				options |= DIR_DIRS;
   				break;
   			default:
   				break;
   		}
   	}
   }
   
   if (ac == i) {
      ++ac;
      av[i] = "";
   if (has_wild)
      return(0);
   }
   if (!(options & (DIR_FILES | DIR_DIRS)))  options |= (DIR_FILES | DIR_DIRS);
   
   for (; i < ac; ++i) {
      if (!(dp = dopen (av[i], &stat)))
         continue;
      if (com < 0) {
         info = (struct InfoData *)AllocMem((long)sizeof(struct InfoData), MEMF_PUBLIC);
         if (Info (dp->lock, info)) {
            printf ("Unit:%2ld  Errs:%3ld  Used: %-4ld %3ld%% Free: %-4ld  Volume: %s\n",
                  info->id_UnitNumber,
                  info->id_NumSoftErrors,
                  info->id_NumBlocksUsed,
                  (info->id_NumBlocksUsed * 100)/ info->id_NumBlocks,
                  (info->id_NumBlocks - info->id_NumBlocksUsed),
                  volname(dp->lock,volume));

         } else {
            perror (av[i]);
         }
         FreeMem (info,(long) sizeof(*info));
         dclose(dp);
         continue;
         return(0);
      } 
 
     /* start of directory routine */
      
            c = av[i];
            clen = strlen(c);
            if (!stat || has_wild) {    /* if not wild and is a dir don't */
                                         /* extract dir from file name     */
               while (clen && c[clen] != '/' && c[clen] != ':') clen--;
               if (c[clen] == ':' || c[clen] == '/') clen++;
               c[clen] = '\0';
            }
            if (!clen)  c = Dir_name;
            if (strcmp (c, &lspec) != 0)  {
               strcpy(lspec, c);
               if (col)    printf("\n");
               printf ("Directory of %s\n", lspec);
               fflush(stdout);
               col = 0;
            } 
            more = stat;
            do {
            	if (more && !has_wild) {
            		*lspec = '\0';
            		if (!(more = dnext(dp, &name, &stat)))
            		break;
            	}
                if (CHECKBREAK()) {
              	   i = ac;
              	   break;
                }
                disp_entry (dp->fib, options);
      } while(more && !has_wild);     
      dclose(dp); 
    }                /* end for */
   if (col)  printf("\n");    
   if (filecount > 1) {
       blocks += filecount;     /* account for dir blocks */
       printf (" %ld Blocks, %ld Bytes used in %ld files\n", blocks, bytes, filecount);
   }
   return (0);
}

char *
volname(lock,buf)
struct FileLock *lock;
char *buf;
{

        struct    DeviceList    *dl;
        char                    *p;

     Forbid();
                /* Only way I know to get Volume label since InfoData  */
                /* seems to always have NULL for this string           */

        lock = BPTR_TO_C(FileLock, lock);
        dl = BPTR_TO_C(DeviceList, lock->fl_Volume);
        p = btocstr(dl->dl_Name,buf);

     Permit();
     return p;
}

void
disp_entry(fib, options)
char options;
register struct FileInfoBlock *fib;
{

   char str[5];
   int italics;
   
   
   if (!(((options & DIR_FILES) && (fib->fib_DirEntryType < 0)) || 
         ((options & DIR_DIRS)  && (fib->fib_DirEntryType > 0))))
                return;
                
 if (!(options & DIR_SHORT)) { 
   str[4] = '\0';
   str[0] = (fib->fib_Protection & FIBF_READ) ? '-' : 'r';
   str[1] = (fib->fib_Protection & FIBF_WRITE) ? '-' : 'w';
   str[2] = (fib->fib_Protection & FIBF_EXECUTE) ? '-' : 'e';
   str[3] = (fib->fib_Protection & FIBF_DELETE) ? '-' : 'd';

   printf ("   %-24s  %s  ", fib->fib_FileName, str);
   if (fib->fib_DirEntryType < 0) printf("%6ld %4ld", (long)fib->fib_Size, (long)fib->fib_NumBlocks);
    else printf("   Dir     ");
   printf("  %s", dates(&fib->fib_Date));
   fflush(stdout);
   } 
   else {
   
        if ((col == 2) && strlen(fib->fib_FileName)>18) {
        	printf("\n");
        	col = 0;
        } 
        if (fib->fib_DirEntryType > 0)  {
        	  printf ("\033[3m");
        	  italics = 1;
               }
               if (strlen(fib->fib_FileName)>18) {
        	printf(" %-37s",fib->fib_FileName);
        	col += 2;
        } 
        else { 
        	printf(" %-18s",fib->fib_FileName);
        	col++;
        } 
        if (col > 3) {
        	printf("\n");
        	col = 0;
        }
        if (italics) printf("\033[0m");
   }
   fflush(stdout);
   blocks += fib->fib_NumBlocks;
   bytes  += fib->fib_Size;
   filecount++;
   return;
}

/* converts dos date stamp to a time string of form dd-mmm-yy  */

char *
dates(dss)
struct DateStamp *dss;
{
   register struct tm tm;
   register long time, t;
   register int i;
   static char timestr[20];
   static char months[12][4] = {
   	"Jan","Feb","Mar","Apr","May","Jun",
   	"Jul","Aug","Sep","Oct","Nov","Dec"
   };
   static char days[12] = {
   	31,28,31,30,31,30,31,31,30,31,30,31
   };
   time = dss->ds_Days * 24 * 60 * 60 + dss->ds_Minute * 60 +
   				       dss->ds_Tick/TICKS_PER_SECOND;
   tm.tm_sec = time % 60; time /= 60;
   tm.tm_min = time % 60; time /= 60;
   tm.tm_hour= time % 24; time /= 24;
   tm.tm_wday= time %  7;
   tm.tm_year= 78 + (time/(4*365+1)) * 4; time %= 4 * 365 + 1;
   while (time) {
   	t = 365;
   	if ((tm.tm_year&3) == 0) t++;
   	if (time < t) break;
   	time -= t;
   	tm.tm_year++;
   }
   tm.tm_yday = ++time;
   for (i=0;i<12;i++) {
   	t = days[i];
   	if (i == 1 && (tm.tm_year&3) == 0) t++;
   	if (time <= t) break;
   	time -= t;
   }  
   tm.tm_mon = i;
   tm.tm_mday = time;
   
   sprintf(timestr,"%02d-%s-%2d %02d:%02d:%02d\n",tm.tm_mday,
   		months[tm.tm_mon],tm.tm_year,
   		tm.tm_hour,tm.tm_min,tm.tm_sec);
   return(timestr);
   
}
 
date()
{
   struct   DateStamp   dss;
   char *s, *dates();

   DateStamp(&dss);
   s = dates(&dss);
   printf("%s",s);
}
 
do_quit()
{
   if (Src_stack) {
      Quit = 1;
      return(do_return());
   }
   main_exit (0);
}
 
 
do_echo(str)
char *str;
{
   register char *ptr;
   char nl = 1;
 
   for (ptr = str; *ptr && *ptr != ' '; ++ptr);
   if (*ptr == ' ')
      ++ptr;
   if (av[1] && strcmp (av[1], "-n") == 0) {
      nl = 0;
      ptr += 2;
      if (*ptr == ' ')
         ++ptr;
   }
   printf("%s",ptr);
   fflush(stdout);
   if (nl)
      printf("\n");
   return (0);
}
 
 
do_source(str)
char *str;
{

   register int;
   register FILE *fi;
   char buf[256];
 
   if (Src_stack == MAXSRC) {
      fprintf (stderr,"Too many source levels\n");
      return(-1);
   }
   if ((fi = fopen (next_word(str), "r")) == 0) {
      fprintf (stderr,"Cannot open %s\n", next_word(str));
      return(-1);
   }
   ++H_stack;
   Src_pos[Src_stack] = 0;
   Src_base[Src_stack] = (long)fi;
   ++Src_stack;
   while (fgets (buf, 256, fi)) {
      buf[strlen(buf)-1] = '\0';
      Src_pos[Src_stack - 1] += 1+strlen(buf);
      if (Verbose)
         fprintf(stderr,"%s\n",buf);
      exec_command (buf);
      if (CHECKBREAK())
         break;
   }
   --H_stack;
   --Src_stack;
   unset_level(LEVEL_LABEL + Src_stack);
   fclose (fi);
   return (0);
}

do_cd()
{
   register 	char 		*s;
   		int		i;
   struct 	FileLock 	*tmplock;
   struct	FileInfoBlock   fib;
		char		temp[60];
   		char		*index();
    
   if (Clock) getcd();		/* in case someone did a C:CD dir */
   
   strcpy(temp, Dir_name);
   if (ac != 2) puts(Dir_name);
   else {
       s = av[1];
       if (*s == '/') {
           while (*s == '/') {
               s++;
     	       for (i=strlen(Dir_name)-2; 
     	           Dir_name[i] != '/' && Dir_name[i] != ':' && i; i--);
               Dir_name[i+1] = '\0';
           }
           strcat(Dir_name, s);
       }
       else if (index(s, ':') == 0) {
           if (Dir_name[strlen(Dir_name)-1] != ':')
               strcat(Dir_name, "/");
           strcat(Dir_name, s);
       }
       else strcpy(Dir_name, s);
       tmplock = Lock(Dir_name, ACCESS_READ);
       if (tmplock == 0) {
           fprintf (stderr,"not found\n");
           strcpy(Dir_name, temp);
           return(-1);
       } else {
           if (Examine(tmplock,&fib)) {
               if (fib.fib_DirEntryType > 0) {
	           Clock = tmplock;
          	   if (tmplock = CurrentDir(Clock)) 
          	       UnLock(tmplock);
           	   if (Dir_name[strlen(Dir_name)-1] == '/')
                       Dir_name[strlen(Dir_name)-1] = '\0';
	           if (s = index(Dir_name,':')) 
                       strcpy(Dir_name, strcat(volname(Clock,temp),s));
            
	    	/* put the current dir name in our CLI task structure */

           	   s = (char *)((ULONG)((struct CommandLineInterface *)
   	  	       BADDR(Myprocess->pr_CLI))->cli_SetName << 2);
                   s[0] = strlen(Dir_name);   
                   movmem(Dir_name,s+1,(int)s[0]);
               }  
               else {
	           fprintf(stderr,"not a directory\n");            
                   return(-1);
               }
           }
           else return(-1);
       }
   }
   return(0);
}

do_mkdir()
{
   register int i;
   register struct FileLock *lock;
 
   for (i = 1; i < ac; ++i) {
      if (lock = CreateDir (av[i])) {
         UnLock (lock);
         continue;
      }
      perror (av[i]);
   }
   return (0);
}
 
 
do_mv()
{
   if (Rename (av[1], av[2]))
      return (0);
   perror (NULL);
   return (-1);
}
 
do_rm()
{
   register int i;

   for (i = 1; i < ac; ++i) {
      if (ac !=2) printf("  %s...",av[i]);
      fflush(stdout);
      if (CHECKBREAK()) break;
      if (!DeleteFile(av[i]))
         perror (av[i]);
     else {
        if (ac !=2) printf("Deleted\n");
          }
   }
   return (0);
}
 
 
do_history()
{
   register struct HIST *hist;
   register int i = H_tail_base;
   register int len = (av[1]) ? strlen(av[1]) : 0;
 
   for (hist = H_tail; hist; hist = hist->prev) {
      if (len == 0 || strncmp(av[1], hist->line, len) == 0) {
         printf ("%3ld ", i);
         puts (hist->line);
      }
      ++i;
      if (CHECKBREAK())
         break;
   }
   return (0);
}
 
do_mem()
{
   long cfree, ffree;
   extern long AvailMem();

   Forbid();
   cfree = AvailMem (MEMF_CHIP);
   ffree = AvailMem (MEMF_FAST);
   Permit();

   if (ffree)       {
   printf ("FAST memory: %ld\n", ffree);  
   printf ("CHIP memory: %ld\n", cfree);   
   }
   printf ("Total  Free: %ld\n", cfree + ffree);
}

/*
 * foreach var_name  ( str str str str... str ) commands
 * spacing is important (unfortunetly)
 *
 * ac=0    1 2 3 4 5 6 7
 * foreach i ( a b c ) echo $i
 * foreach i ( *.c )   "echo -n "file ->";echo $i"
 */
 
do_foreach()
{
   register int i, cstart, cend, old;
   register char *cstr, *vname, *ptr, *scr, *args;
 
   cstart = i = (*av[2] == '(') ? 3 : 2;
   while (i < ac) {
      if (*av[i] == ')')
         break;
      ++i;
   }
   if (i == ac) {
      fprintf (stderr,"')' expected\n");
      return (-1);
   }
   ++H_stack;
   cend = i;
   vname = strcpy(malloc(strlen(av[1])+1), av[1]);
   cstr = compile_av (av, cend + 1, ac);
   ptr = args = compile_av (av, cstart, cend);
   while (*ptr) {
      while (*ptr == ' ' || *ptr == 9)
         ++ptr;
      scr = ptr;
      if (*scr == '\0')
         break;
      while (*ptr && *ptr != ' ' && *ptr != 9)
         ++ptr;
      old = *ptr;
      *ptr = '\0';
      set_var (LEVEL_SET, vname, scr);
      if (CHECKBREAK())
         break;
      exec_command (cstr);
      *ptr = old;
   }
   --H_stack;
   free (args);
   free (cstr);
   unset_var (LEVEL_SET, vname);
   free (vname);
   return (0);
}
 
 

do_copy()
{
   struct DPTR    *dp;
   char tofile[60],todir[60];
   int i, stat, fstat;
   char *p;

   todir[0] = '\0';
   --ac;
   if (ac == 1)
         strcpy(todir, Dir_name);
   else if (ac == 2) {
         strcpy(todir, av[ac]);
         }
   else  {
         strcpy (todir,av[ac]);
         --ac;
         if (strcmp(av[ac],"to") && strcmp(av[ac],"TO"))  ++ac;
        }
   stat = 0;
   if (ac == 1) ++ac;

      dp = dopen (todir, &stat);
      dclose(dp);



   for (i = 1;i < ac; ++i) {
      if (stat)  {
        if (todir[strlen(todir)-1] != '/' && todir[strlen(todir)-1] != ':')
                     strcat(todir,"/");
        strcpy(tofile, todir);
        p = &av[i][strlen(av[i])-1];
        while (p != av[i] && *p != ':' && *p != '/')
           p--;
        if (*p == ':' || *p == '/')
           p++;
        strcat(tofile, p);
        }
      else   {
        strcpy(tofile, todir);
        if (ac > 2) {
          fprintf (stderr,"Copy error: %s is not a directory\n", todir);
          return(0);
          }
      }

   /* if from file is a dir name don't copy     */

   dp = dopen(av[i], &fstat);
   dclose(dp);
   if (fstat) continue;

   printf("copying %s to %s....", av[i], tofile);
   fflush(stdout);
   if (!file_copy(av[i], tofile)) printf("[ok]\n");
   if (CHECKBREAK()) {
      return(0);
      }
 }

}

file_copy(s, tofile)
char  *s, *tofile;
{
   struct      FileHandle  *copyin;
   struct      FileHandle  *copyout;
   long        size;
   long        actual;
   int         ok = 1;
   char        *copybuf;
 
      copyin = Open(s, MODE_OLDFILE);
   if (copyin == 0L)
      perror(s);

 else {
        copyout = Open(tofile, MODE_NEWFILE);

      if (copyout == 0) {
         perror(tofile);
         Close(copyin);
         }
      else {

         size = Seek(copyin, 0L, OFFSET_END);
         size = Seek(copyin, 0L, OFFSET_BEGINING);
 
       if (size != 0L) {                     /* if zero length close em */
         do {
            copybuf = AllocMem(size, MEMF_PUBLIC|MEMF_CLEAR);
            if (copybuf == 0L)
               size = size/2;
            }
         while (copybuf == 0L & size > 512);
         if (copybuf == 0L) {
           fprintf(stderr,"Copy Error: Not Enough Memory\n");
            }
         else
            do {
               ok = 0;
               actual = Read(copyin, copybuf, size);
               if (Write(copyout, copybuf, actual) != actual) {
                  ok = perror(NULL);
                  break;
                  }
               }
            while (actual == size);
          }
            Close(copyin);
            Close(copyout);
         FreeMem(copybuf, size);
         if (size == 0L) ok = 0;
         }
     }
return(ok);
}

SHAR_EOF
if test 16361 -ne "`wc -c comm1.c`"
then
echo shar: error transmitting comm1.c '(should have been 16361 characters)'
fi
echo shar: extracting run.c
cat << \SHAR_EOF > run.c
/*
 * RUN.C
 *
 * Steve Drew 24-sep-86
 *
 */
 
#include "shell.h"
 
do_run(str)
char *str;
{
   int i;

#if USE_FEXEC

   struct CommandLineInterface *cli;

   av[ac] = '\0';
   i = fexecv(av[0],&av[0]);
   
   	/* the next few lines solve a bug with fexecv and bcpl programs */
   	/* that muck up the input/output streams  which causes GURUs	*/
   	
   	cli = (struct CommandLineInterface *)((long)Myprocess->pr_CLI << 2);
   	Myprocess->pr_CIS = cli->cli_StandardInput;
   	Myprocess->pr_COS = cli->cli_StandardOutput;
   	
   if (i) { 
        fprintf(stderr,"Command not found :%s\n",av[0]); 
        return(-1);
        }
   return(wait());
#endif

#if USE_EXECUTE

   i = Execute(str, 0L, 0L);
   return ((i) ? 0 : -1);
   
#endif
}

SHAR_EOF
if test 742 -ne "`wc -c run.c`"
then
echo shar: error transmitting run.c '(should have been 742 characters)'
fi
echo shar: extracting execom.c
cat << \SHAR_EOF > execom.c
/*
 * EXECOM.C
 *
 * Matthew Dillon, 10 August 1986
 *    Finally re-written.
 *
 * version 2.01A (Manx ver) by Steve Drew 27 Sep 1986
 *
 */
 
#include "shell.h"
 
#define F_EXACT 0
#define F_ABBR  1
 
#define ST_COND   0x01
#define ST_NAME   0x02
 
int has_wild = 0;                 /* set if any arg has wild card */

struct _dev	 {
		long  fd;
		short mode;
	};
 
struct COMMAND {
   int (*func)();
   short minargs;
   short stat;
   int   val;
   char *name;
};
 
extern char *format_insert_string();
extern char *mpush(), *exarg();
 
extern int do_run(), do_number();
extern int do_quit(), do_set_var(), do_unset_var();
extern int do_echo(), do_source(), do_mv();
extern int do_cd(), do_rm(), do_mkdir(), do_history();
extern int do_mem(), do_cat(), do_dir();
extern int do_foreach(), do_return(), do_if(), do_label(), do_goto();
extern int do_failat(), do_checkbrk(), do_inc();
extern int do_input(), do_ver(), do_sleep(), do_help();
extern int do_strhead(), do_strtail();
extern int do_copy(), date(),  do_ps();

 
static struct COMMAND Command[] = {

#if USE_FEXEC
   do_run      , 0,  0,		 0 ,   "\001",
#endif

#if USE_EXECUTE
   do_run      , 0,  ST_NAME,	 0 ,   "\001",
#endif

   do_number   , 0,  0,          0 ,   "\001",

#if USE_FEXEC
   do_run      , 0,  ST_NAME,    0 ,   "run",
#endif

   do_quit     , 0,  0,          0 ,   "quit",
   do_set_var  , 0,  0, LEVEL_SET  ,   "set",
   do_unset_var, 0,  0, LEVEL_SET  ,   "unset",
   do_set_var  , 0,  0, LEVEL_ALIAS,   "alias",
   do_unset_var, 0,  0, LEVEL_ALIAS,   "unalias",
   do_echo     , 0,  0,          0 ,   "echo",
   do_source   , 0,  0,          0 ,   "source",
   do_mv       , 2,  0,          0 ,   "mv",
   do_cd       , 0,  0,          0 ,   "cd",
   do_rm       , 0,  0,          0 ,   "rm",
   do_mkdir    , 0,  0,          0 ,   "mkdir",
   do_history  , 0,  0,          0 ,   "history",
   do_mem      , 0,  0,          0 ,   "mem",
   do_cat      , 0,  0,          0 ,   "cat",
   do_dir      , 0,  0,          0 ,   "dir",
   do_dir      , 0,  0,         -1 ,   "devinfo",
   do_foreach  , 3,  0,          0 ,   "foreach",
   do_return   , 0,  0,          0 ,   "return",
   do_if       , 1,  ST_COND,    0 ,   "if",
   do_if       , 0,  ST_COND,    1 ,   "else",
   do_if       , 0,  ST_COND,    2 ,   "endif",
   do_label    , 1,  ST_COND,    0 ,   "label",
   do_goto     , 1,  0,          0 ,   "goto",
   do_failat   , 1,  0,          0 ,   "failat",
   do_checkbrk , 0,  0,          0 ,   "checkbreak",
   do_strhead  , 3,  0,          0 ,   "strhead",
   do_strtail  , 3,  0,          0 ,   "strtail",
   do_inc      , 1,  0,          1 ,   "inc",
   do_inc      , 1,  0,          -1,   "dec",
   do_input    , 1,  0,          0,    "input",
   do_ver      , 0,  0,          0,    "version",
   do_sleep    , 0,  0,          0,    "sleep",
   do_help     , 0,  0,          0,    "help",
   do_copy     , 1,  0,          0,    "copy",
   date        , 0,  0,          0,    "date",
   do_ps       , 0,  0,          0,    "ps",
   '\0'        , 0,  0,          0 ,   NULL
};
 

 
static unsigned char elast;          /* last end delimeter */
static char Cin_ispipe, Cout_ispipe;
 
exec_command(base)
char *base;
{
   register char *scr;
   register int i;
 
   if (!H_stack)
      add_history(base);
   scr = malloc((strlen(base) << 2) + 2);    /* 4X */
   preformat(base, scr);
   i = fcomm(scr, 1);
   return ((i) ? -1 : 1);
}
 
isalphanum(c)
{
   if (c >= '0' && c <= '9')
      return (1);
   if (c >= 'a' && c <= 'z')
      return (1);
   if (c >= 'A' && c <= 'Z')
      return (1);
   if (c == '_')
      return (1);
   return (0);
}
 
preformat(s, d)
register char *s, *d;
{
   register int si, di, qm;
 
   si = di = qm = 0;
   while (s[si] == ' ' || s[si] == 9)
      ++si;
   while (s[si]) {
      if (qm && s[si] != '\"' && s[si] != '\\') {
         d[di++] = s[si++] | 0x80;
         continue;
      }
      switch (s[si]) {
      case ' ':
      case 9:
         d[di++] = ' ';
         while (s[si] == ' ' || s[si] == 9)
            ++si;
         if (s[si] == 0 || s[si] == '|' || s[si] == ';')
            --di;
         break;
      case '*':
      case '?':
         d[di++] = 0x80;
      case '!':
         d[di++] = s[si++];
         break;
      case ';':
      case '|':
         d[di++] = s[si++];
         while (s[si] == ' ' || s[si] == 9)
            ++si;
         break;
      case '\\':
         d[di++] = s[++si] | 0x80;
         if (s[si]) ++si;
         break;
      case '\"':
         qm = 1 - qm;
         ++si;
         break;
      case '^':
         d[di++] = s[++si] & 0x1F;
         if (s[si]) ++si;
         break;
      case '$':         /* search end of var name and place false space */
         d[di++] = 0x80;
         d[di++] = s[si++];
         while (isalphanum(s[si]))
            d[di++] = s[si++];
         d[di++] = 0x80;
         break;
      default:
         d[di++] = s[si++];
         break;
      }
   }
   d[di++] = 0;
   d[di]   = 0;
   if (Debug & 0x01) {
      fprintf (stderr,"PREFORMAT: %ld :%s:\n", strlen(d), d);
   }
}
 
/*
 * process formatted string.  ' ' is the delimeter.
 *
 *    0: check '\0': no more, stop, done.
 *    1: check $.     if so, extract, format, insert
 *    2: check alias. if so, extract, format, insert. goto 1
 *    3: check history or substitution, extract, format, insert. goto 1
 *
 *    4: assume first element now internal or disk based command.
 *
 *    5: extract each ' ' or 0x80 delimited argument and process, placing
 *       in av[] list (except 0x80 args appended).  check in order:
 *
 *             '$'         insert string straight
 *             '>'         setup stdout
 *             '<'         setup stdin
 *             '*' or '?'  do directory search and insert as separate args.
 *
 *             ';' 0 '|'   end of command.  if '|' setup stdout
 *                          -execute command, fix stdin and out (|) sets
 *                           up stdin for next guy.
 */
 
 
fcomm(str, freeok)
register char *str;
{
   register char *istr;
   char *nextstr;
   char *command;
   char *pend_alias = '\0';      /* pending alias                 */
   char err = 0;
   
   mpush_base();
   if (*str == 0)
      goto done1;
step1:
   if (*str == '$') {
      if (istr = get_var (LEVEL_SET, str + 1))
         str = format_insert_string(str, istr, &freeok);
   }
   istr = get_var (LEVEL_ALIAS, str);
   if (istr) {
      if (*istr == '%') {
         pend_alias = istr;
      } else {
         str = format_insert_string(str, istr, &freeok);
         goto step1;
      }
   }
   if (*str == '!') {
      istr = get_history(str);
      replace_head(istr);
      str = format_insert_string(str, istr, &freeok);
      goto step1;
   }
   nextstr = str;
   command = exarg(&nextstr);
   if (*command == 0)
      goto done0;
   if (pend_alias == 0) {
      register int ccno;
      ccno = find_command(command);
      if (Command[ccno].stat & ST_COND)
         goto skipgood;
   }
   if (Disable)
      goto done0;
skipgood:
   {
      register char *arg, *ptr, *scr;
      short redir;
      short doexpand;
      short cont;
      short inc;
 
      ac = 1;
      av[0] = command;
step5:                                          /* ac = nextac */
      if (!elast || elast == ';' || elast == '|')
         goto stepdone;
 
      av[ac] = '\0';
      cont = 1;
      doexpand = redir = inc = has_wild = 0;
 
      while (cont && elast) {
         ptr = exarg(&nextstr);
         inc = 1;
         arg = "";
         cont = (elast == 0x80);
         switch (*ptr) {
         case '<':
            redir = -2;
         case '>':
            if ((Command[find_command(command)].stat & ST_NAME) != 0) { 
            						/* don't extract   */
            	redir = 0;				/* <> stuff if its */
            	arg = ptr;				/* external cmd.   */
            	break;	
            }
            ++redir;
            arg = ptr + 1;
            cont = 1;
            break;
         case '$':
            if ((arg = get_var(LEVEL_SET, ptr + 1)) == NULL)
               arg = ptr;
            break;
         case '*':
         case '?':
            doexpand = 1;
            arg = ptr;
            break;
         default:
            arg = ptr;
            break;
         }
 
         /* Append arg to av[ac] */
 
         for (scr = arg; *scr; ++scr)
            *scr &= 0x7F;
         if (av[ac]) {
            register char *old = av[ac];
            av[ac] = mpush(strlen(arg)+1+strlen(av[ac]));
            strcpy(av[ac], old);
            strcat(av[ac], arg);
         } else {
            av[ac] = mpush(strlen(arg)+1);
            strcpy(av[ac], arg);
         }
         if (elast != 0x80)
            break;
      }
 
      /* process expansion */
 
      if (doexpand) {
         char **eav, **ebase;
         int eac;
 	 has_wild = 1;
         eav = ebase = expand(av[ac], &eac);
         if (eav) {
            inc = 0;
            if (ac + eac + 2 > MAXAV) {
               ierror (NULL, 506);
               err = 1;
            } else {
               for (; eac; --eac, ++eav)
                  av[ac++] = strcpy(mpush(strlen(*eav)+1), *eav);
            }
            free_expand (ebase);
         } /* else  {
            fprintf (stderr,"null expansion\n");
            err = 1;
         } */
      }
 
      /* process redirection  */
 
      if (redir && !err) {
         register char *file = (doexpand) ? av[--ac] : av[ac];
 
         if (redir < 0)
            Cin_name = file;
         else
            Cout_name = file;
         inc = 0;
      }
 
      /* check elast for space */
 
      if (inc) {
         ++ac;
         if (ac + 2 > MAXAV) {
            ierror (NULL, 506);
            err = 1;                /* error condition */
            elast = 0;              /* don't process any more arguemnts */
         }
      }
      if (elast == ' ')
         goto step5;
   }
stepdone:
   av[ac] = '\0';
 
   /* process pipes via files */
 
   if (elast == '|' && !err) {
      static int which;             /* 0 or 1 in case of multiple pipes */
      which = 1 - which;
      Cout_name = (which) ? Pipe1 : Pipe2;
      Cout_ispipe = 1;
   }
 
   /* DO COMMAND HERE! */
 
   if (err)
      goto done0;
 
   {
      register int i, len;
      char save_elast;
      char *avline;
 
      save_elast = elast;
      for (i = len = 0; i < ac; ++i)
         len += strlen(av[i]) + 1;
      avline = malloc(len+1);
      for (len = 0, i = ((pend_alias) ? 1 : 0); i < ac; ++i) {
         if (Debug & 0x02) { 
             fprintf (stderr, "AV[%2ld] %ld :%s:\n", i, strlen(av[i]), av[i]);
         }
         strcpy(avline + len, av[i]);
         len += strlen(av[i]);
         if (i + 1 < ac)
            avline[len++] = ' ';
      }
      avline[len] = 0;
      if (pend_alias) {                               /* special % alias */
         register char *ptr, *scr;
         for (ptr = pend_alias; *ptr && *ptr != ' '; ++ptr);
         set_var (LEVEL_SET, pend_alias + 1, avline);
         free (avline);
 
         scr = malloc((strlen(ptr) << 2) + 2);
         preformat (ptr, scr);
         fcomm (scr, 1);
         unset_var (LEVEL_SET, pend_alias + 1);
      } else {                                        /* normal command  */
         register int ccno;
 	 long oldcin, oldcout, oldstdout, oldstdin;
	 extern struct _dev _devtab[];
	 char retcode[12];
	 struct _dev *stdfp;
	 
	 fflush(stdout);
         ccno = find_command (command);
         if ((Command[ccno].stat & ST_NAME) == 0) {
            if (Cin_name) {
               if ((Cin = (long)Open(Cin_name,1005)) == 0L) {
                  ierror (NULL, 504);
                  err = 1;
                  Cin_name = '\0';
               } else {
                  oldcin = (long)Input();
                  Myprocess->pr_CIS = Cin;
 	          _devtab[stdin->_unit].fd = Cin;
               }
            }
            if (Cout_name) {               
               if ((Cout = (long)Open(Cout_name,1006)) == 0L) {
                  err = 1;
                  ierror (NULL, 504);
                  Cout_name = '\0';
               } else {
	          oldcout = (long)Output();
                  Myprocess->pr_COS = Cout;
                  _devtab[stdout->_unit].fd = Cout;
               }
            }
         }
         if (ac < Command[ccno].minargs + 1) {
            ierror (NULL, 500);
            err = 1;
         } else if (!err) {
	    if (Debug & 0x01) {
	        fprintf(stderr,"Command = :%s:\n",avline);
	    }
            err = (*Command[ccno].func)(avline, Command[ccno].val);
            if (err != 0) {
                sprintf(retcode,"%d",err);
                set_var (LEVEL_SET, V_LASTERROR, retcode);
            }
         }
         free (avline);
         if ((Command[ccno].stat & ST_NAME) == 0) {
            if (Cin_name) {
               fflush(stdin);               
	       clearerr(stdin);
	       Close(Cin);
	       Myprocess->pr_CIS =  _devtab[stdin->_unit].fd = oldcin;
            }
            if (Cout_name) {
               fflush(stdout);
               clearerr(stdout);
               Close(Cout);
	       Myprocess->pr_COS =  _devtab[stdout->_unit].fd = oldcout;
            }
         }
      }
      if (Cin_ispipe && Cin_name)
         DeleteFile(Cin_name);
      if (Cout_ispipe) {
         Cin_name = Cout_name;         /* ok to assign.. static name */
         Cin_ispipe = 1;
      } else {
         Cin_name = '\0';
      }
      Cout_name = '\0';
      Cout_ispipe = 0;
      elast = save_elast;
   }
   mpop_tobase();                      /* free arguments   */
   mpush_base();                       /* push dummy base  */
 
done0:
   if (elast != 0 && !err)             /* done? or more? */
      err = fcomm(nextstr, 0);         /* do next command ';' or '|' sep. */
 
   if (Cin_name)                       /* pipe segment complete   */
      DeleteFile(Cin_name);
   Cin_name = '\0';
   Cin_ispipe = 0;
 
done1:
   mpop_tobase();
   if (freeok)
      free(str);
   return ((int)err);                  /* TRUE = error occured    */
}
 
 
char *
exarg(ptr)
unsigned char **ptr;
{
   register unsigned char *end;
   register unsigned char *start;
 
   start = end = *ptr;
   while (*end && *end != 0x80 && *end != ';' && *end != '|' && *end != ' ')
      ++end;
   elast = *end;
   *end = '\0';
   *ptr = end + 1;
   return ((char *)start);
}
 
static char **Mlist;
 
mpush_base()
{
   char *str;
 
   str = malloc(5);
   *(char ***)str = Mlist;
   str[4] = 0;
   Mlist = (char **)str;
}
 
char *
mpush(bytes)
{
   char *str;
 
   str = malloc(5 + bytes);
   *(char ***)str = Mlist;
   str[4] = 1;
   Mlist = (char **)str;
   return (str + 5);
}
 
mpop_tobase()
{
   register char *next;
   while (Mlist) {
      next = *Mlist;
      if (((char *)Mlist)[4] == 0) {
         free (Mlist);
         Mlist = (char **)next;
         break;
      }
      free (Mlist);
      Mlist = (char **)next;
   }
}
 
 
/*
 * Insert 'from' string in front of 'str' while deleting the
 * first entry in 'str'.  if freeok is set, then 'str' will be
 * free'd
 */
 
 
 
char *
format_insert_string(str, from, freeok)
char *str;
char *from;
int *freeok;
{
   register char *new1, *new2;
   register unsigned char *strskip;
   int len;
 
   for (strskip = (unsigned char *)str; *strskip != '\0' && *strskip != ' ' && *strskip != ';' && *strskip != '|' && *strskip != 0x80; ++strskip);
   len = strlen(from);
   new1 = malloc((len << 2) + 2);
   preformat(from, new1);
   len = strlen(new1) + strlen(strskip);
   new2 = malloc(len+2);
   strcpy(new2, new1);
   strcat(new2, strskip);
   new2[len+1] = 0;
   free (new1);
   if (*freeok)
      free (str);
   *freeok = 1;
   return (new2);
}
 
find_command(str)
char *str;
{
   int i;
   int len = strlen(str);
 
   if (*str >= '0'  &&  *str <= '9')
      return (1);
   for (i = 0; Command[i].func; ++i) {
      if (strncmp (str, Command[i].name, len) == 0) {
        return (i);
	} 
   }
   return (0);
}
 
do_help()
{
   register struct COMMAND *com;
   int i= 0;

    
   for (com = &Command[2]; com->func; ++com) {
      printf ("%-12s", com->name);
      if (++i  % 6 == 0) printf("\n");
   }
   printf("\n");
   return(0);
}



    
SHAR_EOF
if test 16212 -ne "`wc -c execom.c`"
then
echo shar: error transmitting execom.c '(should have been 16212 characters)'
fi
#	End of shell archive
exit 0