[comp.sources.amiga] v89i060: shell - csh-like command interpreter v3.02a, Part03/03

page@swan.ulowell.edu (Bob Page) (03/16/89)

Submitted-by: PERUGIA@ICNUCEVM.BITNET (Cesare Dieni)
Posting-number: Volume 89, Issue 60
Archive-name: unix/shell302a.3

#	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:
#	sub.c
#	shell.doc
# This archive created: Wed Mar 15 14:15:32 1989
cat << \SHAR_EOF > sub.c

/*
 * SUB.C
 *
 * (c)1986 Matthew Dillon     9 October 1986
 *
 * Version 2.07M by Steve Drew 10-Sep-87
 *
 * Version 3.02A by Carlo Borreo & Cesare Dieni 20-Dec-88
 *
 */

extern char *v_lasterr, *v_stat;

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

/* extern BPTR Clock; */

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

sprintf(buf, "%d", Lastresult);
set_var(LEVEL_SET, v_lasterr, buf);
stat = atoi(get_var(LEVEL_SET, v_stat));
if (stat < Lastresult) stat = Lastresult;
sprintf(buf, "%d", stat);
set_var(LEVEL_SET, v_stat, buf);
}


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

char *
compile_av(av, start, end, delim)
char **av;
unsigned char delim;
{
char *cstr;
int len;
register unsigned int i;

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) {
	if (debug) fprintf (stderr, "AV[%2d] :%s:\n", i, av[i]);
	strcat (cstr, av[i]);
	if (i + 1 < end) strncat(cstr, &delim, 1);
	}
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;

   if (H_head != NULL && strcmp(H_head->line, str) == 0)
       return(0);
   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 *
get_history(ptr)
char *ptr;
{
   register struct HIST *hist;
   register int len;
   int mode = HM_REL;
   int 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) {
      fprintf(stderr,"%s\n",result);
      return(result);
   }
   printf("History failed\n");
   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;
{
   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 ((short)err);
         }
      }
      fprintf (stderr, "Unknown DOS error %d %s\n", err, (str) ? str : "");
   }
   return ((short)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;

   *stat = 0;
   dp = (struct DPTR *)malloc(sizeof(struct DPTR));
   if (*name == '\0')
      dp->lock = DupLock(Myprocess->pr_CurrentDir);
   else
      dp->lock = Lock (name,ACCESS_READ);
   if (dp->lock == NULL) {
      free (dp);
      return (NULL);
   }
   dp->fib = (FIB *)AllocMem((long)sizeof(FIB), 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);
}


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;
{
   char **base = av;

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

/*
 * EXPAND(base,pac)
 *    base           - char * (example: "df0:*.c")
 *    pac            - int  *  will be set to # of arguments.
 *
 * 22-May-87 SJD.  Heavily modified to allow recursive wild carding and
 *                 simple directory/file lookups. Returns a pointer to
 *                 an array of pointers that contains the full file spec
 *                 eg. 'df0:c/sear*' would result in : 'df0:C/Search'
 *
 *                 Now no longer necessary to Examine the files a second time
 *                 in do_dir since expand will return the full file info
 *                 appended to the file name. Set by formatfile().
 *                 eg. fullfilename'\0'rwed  NNNNNN NNNN  DD-MMM-YY HH:MM:SS
 *
 *                 Caller must call free_expand when done with the array.
 *
 * base             bname =       ename =
 * ------           -------       -------
 *  "*"               ""            "*"
 *  "!*.info"         ""            "*.info" (wild_exclude set)
 *  "su*d/*"          ""            "*"      (tail set)
 *  "file.*"          ""            "file.*"
 *  "df0:c/*"         "df0:c"       "*"
 *  ""                ""            "*"
 *  "df0:.../*"       "df0:"        "*"      (recur set)
 *  "df0:sub/.../*"   "df0:sub"     "*"      (recur set)
 *
 * ---the above base would be provided by execom.c or do_dir().
 * ---the below base would only be called from do_dir().
 *
 *  "file.c"          "file.c"      ""       if (dp == 0) fail else get file.c
 *  "df0:"            "df0:"        "*"
 *  "file/file"       "file/file"   ""       (dp == 0) so fail
 *  "df0:.../"        "df0:"        "*"      (recur set)
 *
 */


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

   *pac = recur = eleft = eac = 0;

   base = strcpy(malloc(strlen(base)+1), base);
   for (ptr = base; *ptr && *ptr != '?' && *ptr != '*'; ++ptr);

   if (!*ptr)   /* no wild cards */
      --ptr;
   else
      for (; ptr >= base && !(*ptr == '/' || *ptr == ':'); --ptr);

   if (ptr < base) {
      bname = strcpy (malloc(1), "");
   } else {
      scr = ptr[1];
      ptr[1] = '\0';
      if (!strcmp(ptr-3,".../")) {
         recur = 1;
         *(ptr-3) = '\0';
      }
      bname = strcpy (malloc(strlen(base)+2), base);
      ptr[1] = scr;
   }
   bl = strlen(bname);
   ename = ++ptr;
   for (; *ptr && *ptr != '/'; ++ptr);
   scr = *ptr;
   *ptr = '\0';
   if (scr) ++ptr;
   tail = ptr;

   if ((dp = dopen (bname, &stat)) == NULL || (stat == 0 && *ename)) {
      free (bname);
      free (base);
      free (eav);
      return (NULL);
   }

   if (!stat) {                /* eg. 'dir file' */
      char *p,*s;
      for(s = p = bname; *p; ++p) if (*p == '/' || *p == ':') s = p;
      if (s != bname) ++s;
      *s ='\0';
      eav[eac++] = svfile(bname,dp->fib->fib_FileName,dp->fib);
      goto done;
   }
   if (!*ename) ename = "*";    /* eg. dir df0: */
   if (*bname && bname[bl-1] != ':' && bname[bl-1] != '/') { /* dir df0:c */
      bname[bl] = '/';
      bname[++bl] = '\0';
   }
   while ((dnext (dp, &name, &stat)) && !breakcheck()) {
        int match = compare_ok(ename,name);
      if (match && !(!recur && *tail)) {
         if (eleft < 2) {
               char **scrav = (char **)malloc(sizeof(char *) * (eac + 10));
               movmem (eav, scrav, (eac + 1) << 2);
               free (eav);
               eav = scrav;
               eleft = 10;
         }
         eav[eac++] = svfile(bname,name,dp->fib);
         --eleft;
      }
      if ((*tail && match) || recur) {
         int alt_ac;
         char *search, **alt_av, **scrav;
         BPTR lock;

         if (!stat)           /* expect more dirs, but this not a dir */
            continue;
         lock = CurrentDir (dp->lock);
         search = malloc(strlen(ename)+strlen(name)+strlen(tail)+5);
         strcpy (search, name);
         strcat (search, "/");
         if (recur) {
            strcat(search, ".../");
            strcat(search, ename);
         }
         strcat (search, tail);
         scrav = alt_av = expand (search, &alt_ac);
         /* free(search); */
         CurrentDir (lock);
         if (scrav) {
            while (*scrav) {
               int l;
               if (eleft < 2) {
                  char **scrav = (char **)malloc(sizeof(char *) * (eac + 10));
                  movmem (eav, scrav, (eac + 1) << 2);
                  free (eav);
                  eav = scrav;
                  eleft = 10;
               }

               l = strlen(*scrav);
               scrav[0][l] = ' ';
               eav[eac] = malloc(bl+l+45);
               strcpy(eav[eac], bname);
               strcat(eav[eac], *scrav);
               eav[eac][l+bl] = '\0';

               free (*scrav);
               ++scrav;
               --eleft, ++eac;
            }
            free (alt_av);
         }
      }
   }
done:
   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 *back0[MAXB], *back1[MAXB];
int bi=0, queryflag;

if (*w=='!') return !compare_ok(wild+1,name);
if (queryflag=(*w=='&')) w++;
while (*n || *w) {
   switch (*w) {
      case '*':
       if (bi==MAXB) { printf(stderr,"Too many levels of '*'\n"); return 0; }
       back0[bi] = w;
       back1[bi] = n;
       ++bi;
       ++w;
       continue;
goback:
       --bi;
       while (bi >= 0 && *back1[bi] == '\0') --bi;
       if (bi < 0) return 0;
       w = back0[bi] + 1;
       n = ++back1[bi];
       ++bi;
       continue;
      case '?':
       if (!*n) goto goback;
       break;
      default:
       if (Toupper(*n)!=Toupper(*w)) goto goback;
       break;
      }
   if (*n) ++n;
   if (*w) ++w;
   }
if (queryflag) {
	char in[256];
	printf("Select \23337m%-16s\2330m [y/n] ? ",name);
	gets(in);
	return (Toupper(*in)=='Y');
	}
return 1;
}

char *svfile(s1,s2,fib)
char *s1,*s2;
FIB *fib;
{
char *p = malloc (strlen(s1)+strlen(s2)+45);
strcpy(p, s1);
strcat(p, s2);
formatfile(p,fib);
return p;
}

/* will have either of these formats:
 *
 *    fullfilename'\0'hsparwed   <Dir>       DD-MMM-YY HH:MM:SS\n'\0'
 *    fullfilename'\0'hsparwed  NNNNNN NNNN  DD-MMM-YY HH:MM:SS\n'\0'
 *                              1111111111222222222233333333334 4  4
 *                    01234567890123456789012345678901234567890 1  2
 */
formatfile(str,fib)
char *str;
FIB *fib;
{
char *dates();
int i;
while(*str++);
for (i=7; i>=0; i--)
    *str++ = ((fib->fib_Protection & (1L<<i)) ? "hspa----" : "----rwed")[7-i];
if (fib->fib_DirEntryType < 0)
  sprintf(str,"  %6ld %4ld  ", (long)fib->fib_Size, (long)fib->fib_NumBlocks);
else strcpy(str,"   <Dir>       ");
strcat(str,dates(&fib->fib_Date));
}

/* Sort routines */

long cmp(s1, s2)
char **s1, **s2;
{
return (long)Strcmp(*s1, *s2);
}

Cmp() {
#asm
	public	_geta4
	movem.l	d2-d3/a4/a6,-(sp)
	movem.l	a0/a1,-(sp)
	bsr	_geta4
	bsr	_cmp
	addq.l	#8,sp
	movem.l	(sp)+,d2-d3/a4/a6
#endasm
}

QuickSort(av, n)
char *av[];
int n;
{
QSort(av, (long)n, 4L, Cmp);
}
SHAR_EOF
cat << \SHAR_EOF > shell.doc

		INSTRUCTIONS FOR SHELL Version: 3.02A 20-Dec-88
		===============================================

  Contents
  --------

    O.    Changes over old versions
    I.    Description
    II.   Overview of Major features
    III.  Restrictions
    IV.   PIPES
    V.    Command Pre-processor
    VI.   Command Line Editing
    VII.  Function Keys
    VIII. Shell Commands
    IX.   Special Set Variables
    X.    Advanced Topics
    XI.   Example login file
    XII.  Example script file
    XIII. Default values
    XIV.  Why ARP ?

O.  Changes over old version
    ------------------------

New to 3.02A:

- New commands: fornum, forline, strleft, strright, strmid, strlen, exec.
- Improved commands: foreach, pri.
- New system variable _clinumber.
- You can now split long lines in source files (see source for details).
- window -q now lists also position of screens/windows, not only dimension.
- Since strings are handled directly from Shell with new commands,
  rpn is now used only for calculations; string commands are gone.
  However, now RPN is really usable.
- Changed rawgets() to fix some problems with function keys, multi-line
  editing and window resizing; also, fixed bug with ^E.
- cat now warns you if it can't find any file matching your pattern.
- Now uses DOS packets to get ptr to CLI window; this fixes a bug that
  caused problems if Shell was run on unactive windows.
- Fixed minor bugs (htype printed some more ASCII bytes, some commands
  returned random values, history didn't print CR's).
- Heavy mods to this file.

New to 3.01A:

- Fixed bug with strings: before it printed strings with lenght 1 more
  than specified lenght.
- Made some additions and corrected many errors in Shell.doc (this file).
- Modified handler of external commands to allow things like DATE "?"
  (always use quotes).
- Corrected cat: it didn't work with STDIN before.

I.  Description
    -----------

This version of Shell is the follow of:
	Shell V2.04 (C)Copyright 1986, Matthew Dillon, All Rights Reserved
	Shell V2.04M-V2.07M by Steve Drew
	Shell V2.08MI and V3.xxA by Carlo Borreo & Cesare Dieni

Send suggestions/criticism/anything else to Carlo Borreo or Cesare Dieni at:

	BITNET:  PERUGIA@ICNUCEVM.BITNET	

or
	Carlo Borreo		Cesare Dieni
	Via G. Berio 34		Via G. Taddei 3
	I-18100 Imperia		I-56100 Pisa
	Italy			Italy

For older version: Steve Drew at:

        ENET:    CGFSV1::DREW
        ARPA:    drew%cfgsv1.dec.com@decwrl.dec.com
        USENET:  {decvax|decwrl}!cgfsv1.dec.com!drew

or
        52 Castledale Cres N.E.
        Calgary, Alberta
        Canada

You may distribute this program for non-profit only.


II. OVERVIEW
    --------

Shell provides a convient AmigaDos alternative command interface.
All its commands are internal and thus does not rely on the c:
commands for any functionality.

Major features include:

	-command line editing
	-shell & Amigados search path support
	-simple history
	-redirection of any command
	-piping
	-aliases
	-variables & variable handling (embedded variables)
	-file name expansion via conventional wild carding ('?', '*' and more)
	-conditionals (if/else ect..)
	-source files  (w/ gotos and labels)
	-many built in commands to speed things up


III. RESTRICTIONS
     ------------

    o AmigaDos execute command will not work. Alternative is to use shell
      own script language (which is more powerful) or to do a 'run execute'.
    o This version runs UNDER WORKBENCH 1.2 or 1.3.
    o VDK handler has a bug with setting file dates so when using the copy
      command and VDK you should use the -d switch otherwise your file date
      in vdk: will be bad. (This is not a bug with shell)
    o If using with conman it may be best to start shell with the -a switch
      (shell -a .login) to turn off shell's command line editing and use
      conmans instead.


IV. NOTES ON PIPES
    --------------

    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.

    The file names used are completely unique, even with multiple shell
    running simultaniously.

    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

    NO BCPL program should be output-append redirected (>>).


V.  COMMAND PRE-PROCESSOR
    ---------------------

    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). Spaces delimit 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 '\\'.

		also used to overide alias searching for commands.

	>file	specify output redirection.  All output from the command is
		placed in the specified file.

	>>file	specify append redirection (Does not work with BCPL programs).

	<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.

	#	Enter comment.  The rest of the line is discarded (note: \#
		will, of course, overide the comment character's special
		meaning)


VI. COMMAND LINE EDITING
    --------------------

    o Command line can be upto 255 chars.
    o Inserts and deletes are handled correctly over multiple screen lines.
    o Shell will keep track of the line width should the window get resized.

	KEY DEFINITIONS:
		Up Arrow    Recal previous commands
		Down Arrow  Recal commands
		Left Arrow  Move cursor about command line.
		Right Arrow  "     "      "      "      "
		Shift-Up Arrow    Get start of history
		Shift-Down Arrow   "  end   "     "
		Shift-Left Arrow  Moves cursor a bit left
		Shift-Right Arrow   "     "    "  "  right
		^A		Toggle insert/overtype mode.
		^D		EOF
		^E		Put cursor at end of text.
		^K		Delete to end of line.
		^R		Retype current line.
		^U		Erase entire line.
		^X		Erase entire line.
		^Z		Put cursor at start of text.
		f1 - f10	Execute command if variable exists.
		F1 - F10	More commands (Shifted f keys).
		Help		Invokes help command


VII. FUNCTION KEYS
     -------------

    Function keys now insert text to the current position on the command
    line. They maybe terminated with a ^M (return). f1 would be non shifted
    where as F1 is shifted.
    Most of functions key have a default definition, but it may be changed.

      $ set f1 dir df0:^M

	will add the text 'dir df0:<return>' to the current line.

      $ set f1 dir

	would only add 'dir' you could then enter ' df0:<return>'


VIII. SHELL COMMANDS
      ---------------

   First to start shell from a CLI

   shell [-a] [-c command;command]

   where:
	-a disables all command line editing features. This is useful for
	when running shell over AUX:, and necessary if you are running
	CONMAN.

	-c allows execution of one command line and then exits out of shell.
	This is useful for running a internal shell commands in the
	background or from an external application. eg:

		Run shell -c dir df0:; copy -r df0: df1: >nil:; echo "Done"

	If you 'Run' shell in the background without the -c switch shell
	will detect this and imediatley exit.

   Command execution:

   Internal shell commands maybe abreviated.

   The first argument is the command-name... here is (in order) how Shell
   tries to execute it:

	1) Alias list is searched for an alias exactly matching name.
	2) Internal commands list is scanned for a command even partially
	   matching name (so you can, for instance, say resi for resident;
	   however, you should specify enough of a command to be unique).
	3) ARP resident list is scanned (you can use Shell's resident
	   command to add/remove a file in this list).
	4) At this point, command is supposed to be external (disk), and
	   is searched before in current directory, then in Shell's
	   path, and finally in AmigaDOS path.
	5) As a last chance, AUTOMATIC SOURCING is tried.

   AUTOMATIC SOURCING may be accomplished by naming shell scripts with a
   .sh suffix.  Thus, if you say 'stuff' and the file 'stuff.sh' exists in
   your current or C: directory or anywhere in Shell search path, it will
   be SOURCED with any arguments you have placed in the $_passed variable.
   This is equivalent to typing 'source stuff.sh'

   Wild card expansions:
	Most shell commands will accept multiple arguments that can
	be as a result of wild card expansion. Also when the calling
	an external command shell will first expand any wild cards
	to seperate arguments. If you wish to have the external command
	handle it's own wild carding you will need to insert quotes
	around the special wild card characters ? and *.

	eg.
		arc a new.arc *.txt	- shell will expand and pass to arc
		arc a new.arc "*.txt"	- let arc expand the wild cards.

    Wild card expansions:

	?	match any single character
	*	match any string
	.../*	recursive search down ALL sub directories from current level
	!	Exclude pattern matching specifier
	&	prefixed to patterns, ask confirmation for each file

    Examples:

	df0:.../*		all files in all directories on df0:
	df0:.../!*.info 	full directory tree of df0: but exclude
				any ugly .info files.
	!*.o !*.c		will result in ALL files matching since what
				doesn't match the !*.o will match the !*.c
	df1:&*			all files in root of df1:, but ask 
				confirmation for each

    LIST OF COMMANDS:
    -----------------

    ABORTLINE
	Usage	: abortline
	Example	: echo a;abort;echo b
	Results	: a

	Causes the rest of the line to be aborted. Intended for use in
	conjunction with exception handling.

    ADDBUFFERS
	Usage	: addbuffers drive buffers
	Example	: addbuffers df0: 24

	Just like AmigaDOS addbuffer command, causes new buffers to be
	allocated for disk I/O. Each buffer costs 512 bytes of CHIP memory.

    ALIAS
	Usage	: alias [name [command string] ]
	Example	: alias vt "echo Starting VT100;run sys:tools/vt100"

	Sets a name to be a string. You can alias a single name to a set
	of commands if you enclose them in quotes as above. By simply
	typing vt, the command line above would be executed.

	Argument Passing to an Alias:

	Usage	: alias name "%var [command string]"
	Example	: alias xx "%q echo hi $q, how are ya."
		  xx Steve
	Results	: hi Steve, how are ya.

	The second form of the alias command allows passing of arguments
	to any position within the command string via use of a variable
	name. To pass arguments to the end of a command string this method
	is actually not necessary.

	Typing "alias name" you will get the alias for that name, while with
	"alias" you get a list of all alias.

    ASET
	Usage	: aset name value
	Example	: aset INCLUDE include:

	Set a variable in a way that is compatible with Aztec SET command;
	this is completely different from Shell variable.
	May even be used to set ARP variables.

    ASSIGN
	Usage	: assign [logical [physical] ]
	Example	: assign C: df1:c

	Use it like AmigaDOS assign command to set, remove or list
	assignments of logical names to directories.

    CAT
	Usage	: cat [-n][file file....]
	Example	: cat foo.txt

	Type the specified files onto the screen.  If no file is specified,
	STDIN in used.  CAT is meant to output text files only.
	Specifying -n option you will get numbered lines.

    CD
	Usage	: cd [path]
	Example	: cd df0:devs/printers

	Change your current working directory.  You may specify '..' to go
	back one directory (this is a CD specific feature, and does not
	work with normal path specifications).

	CD without any arguments displays the path of the directory you
	are currently in.

    CLOSE
	Usage	: close filenumber

	Close the specified file opened by open.
	See open and flist for more info.

    COPY
    (CP)
	Usage	: copy [-u][-d] file file
	or	: copy [-u][-d] file1 file2...fileN dir
	or	: copy [-r][-u][-d] dir1 dir2...dirN dir
	options	:
		-r	recursive, copy all subdirectories as well.
		-u	update, if newer version exist on dest, don't copy
		-d	don't set destination file date to that of source.

	Example	: copy -r df0: df1:

	Copy files or directories. When copying directories, the -r option
	must be specified to copy subdirectories as well.  Otherwise, only
	top level files in the source directory are copied.

	All files will be displayed as they are copied and directory's
	displayed as they are created. This output can be suppessed by
	redirecting to nil: eg. copy -r >nil: df0: df1:

	Copy will abort after current file on Control-C.

	Copy by default sets the date of the destination file to that of
	the source file. To overide this feature use the -d switch.

	Another useful option is the -u (update) mode were copy will not
	copy any files which exists already in the destination directory
	if the destination file is newer or equal to the source file.
	This is useful when developing code say in ram: eg. 'copy *.c ram:'
	when done you can copy -u ram: df1: and only those modules you have
	modified will be copied back.

	Copy command will now create the destination directory if it does
	not exist when specified as 'copy [-r] dir dir'. If you specify
	copy file file file dir, then 'dir' must already exist.

    CP
	Equivalent to copy.

    DATE
	Usage	: date [new date and/or time]
	Example	: date Wednesday  # this refers to NEXT wed, of course

	Used to read or set system date and/or time. All standard options
	may be used (yesterday, tomorrow, monday, etc.).
	Leading zero's are not necessary.
	Without parameters shows Dddddd DD-MMM-YY HH:MM:SS.

    DEC
	Usage	: dec varname [value]
	Example	: dec abc

	Decrement the numerical equivalent of the variable with specified
	value (default: 1) and place the ASCII-string result back into
	that variable.

    DELETE
    (RM)
	Usage	: delete [-p][-r] file file file...
	Example	: delete foo.txt test.c

	Remove (delete) the specified files.  Remove always returns
	errorcode 0.  You can remove empty directories.  The '-r' option
	will remove non-empty directories by recursively removing all sub
	directories.
	You can remove delete-protected files specifying -p option.
	If you specify any wildcard deletes the files will be listed as
	they are deleted. This can be suppressed by redirecting to nil:

    DIR
    (LS)
	Usage	: dir [-sdf] [path path ... ]
	Example	: dir df0:
	options	:
		-s  short multi(4) column display.
		-d  list directories only
		-f  list files only

	Displays a directory of specified files. Default output shows
	date, protection, block size, byte size and total space used.
	Protections flags include new 1.2/1.3 flags (see under protect).
	Files are alphabetically sorted, without case sensitivity, and
	directories are always in red pen.

    DISKCHANGE
	Usage	: diskchange drive

	Like AmigaDOS diskchange.

    ECHO
	Usage	: echo [-n] string
	Example	: echo hi there
	Results	: hi there

	Echo the string given. If -n switch given no newline is
	appended.

    ELSE ;
	Usage	: else ; command
	Usage	: if -f foo.c ; else ; echo "Not there" ; endif

	Else clause, must follow an IF statement.

    ENDIF
	Usage	: endif

	The end of an if statement.

	Note: if you return from a script file with unterminated IF's
	and the last IF was false, prompt will be changed to an
	underscore ('_') and no commands will be executed until
	'endif' is typed.

    EXEC
	Usage	: exec command
	Example	: set util SYS:sytem/utilities
		  exec $util/make	# would not work without exec

	Execute the command specified; exec command is equivalent to
	command, only you can use variables to specify command name.

    FAULT
	Usage	: fault error1 .. errorN
	Example	: fault 205 212

	Like AmigaDOS fault, prints specified error messages.

    FILENOTE
	Usage: filenote file1 .. filen  note

	Set AMIGADOS comment of the specified file. This is not very useful,
	since in current implementation of Shell file comments are not listed
	in directory, but it was so easy to implement...

    FLIST
	Usage	: flist

	Lists the filenumbers of files opened by open.
	See open and close for more info.

    FOREACH
	Usage	: foreach [-v] varname ( strings ) command
	Example	: foreach i ( a b c d ) "echo -n $i;echo \" ha\""
	Result	: a ha
		  b ha
		  c ha
		  d ha

	'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 is especially useful when interpreting passed arguments in
	an alias.

	eg.
		foreach i ( *.pic ) viewilbm $i
	assuming a.pic and b.pic in current directory the following commands
	will occur:
		viewilbm a.pic
		viewilbm b.pic

	Flag -v causes arguments to be displayed every time command is
	executed.

    FOREVER
	Usage	: forever command
	or	: forever "command;command;command..."

	The specified commands are executed over and over again forever.

	-Execution stops if you hit ^C
	-If the commands return with an error code.

   FORLINE
	Usage	: forline var filename command
	or	: forline var filename "command;command..."
	Example	: forline i RAM:temp "echo line $_linenum=$i"

	For each ASCII line of file specified commands are executed and
	var points to line content. You can check system variable _linenum
	to find the number of the line currently read.

   FORNUM
	Usage	: fornum var n1 n2 command
	or	: fornum var n1 n2 "command;command..."
	Example	: fornum x 1 10 echo $1

	Executes command(s) for all numerical values of x between n1 and n2.

   GOTO
	Usage	: goto label
	Example	:
		  label start
			echo "At start"
			dir ram:
			goto start

	Goto the specified label name.  You can only use this command from a
	source file. Labels may now be forward or reverse from current
	position.

    HELP
	Usage	: help
	Example	: help

	Simply displays all the available commands.  The commands are
	displayed in search-order.  That is, if you give a partial name
	the first command that matches that name in this list is the one
	executed.  Generally, you should specify enough of a command so that
	it is completely unique.

    HISTORY
	Usage	: history [partial_string]
	Example	: history

	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.

    HOWMANY
	Usage	: howmany

	This command tells you how many instances of Shell are running
	in your system.

    HTYPE
	Usage	: htype file1 .. filen

	Displays the specified files in hex and ASCII, just like the system
	command Type file opt h. Especially suitable for binary files.

    IF
	Usage	: if [-n] argument conditional argument ;
	or	: if [-n] argument
	or	: if [-n] -f file
	or	: if [-n] -d file/dir
	or	: if [-n] -m
	or	: if [-n] -t file file1 .. fileN
	or	: if [-n] -r rpnexpression

	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 arguments are not numeric, they are compared as strings.

	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.

	The third form of IF used by -f switch checks for existance of
	the specified file.

	Switch -d tests the type of the object specified: if it is a
	directory, then TRUE; if it is a file (or it doesn't exist)
	then FALSE.

	Switch -m is used to test if FAST memory is present, i.e. wheter
	more than 512K RAM are available.
	Example (to be included in a login.sh file):
	if -m; resident -a as ln cc; endif

	Using -t form compares the date and time of the first file with
	all the others; if the first is younger than ALL the others, then
	FALSE, else TRUE. If a file doesn't exists, it is considered as
	being older.
	This feature is especially useful for building makefiles without
	using any MAKE utility.
	Example:
	if -t test.o test.asm test.i ; asm -o test.o test.asm ; endif

	Option -r evaluates a given RPN expression (see under RPN for more
	info): if value on top of stack is 0, then FALSE, else TRUE.

	Switch -n (NOT) reverses the result.

	When using 'IF' command interactively if you are entering commands
	following an 'IF' that was false, the prompt will be set to a
	underscore '_ ' to indicate all commands will be ignored until
	an 'ELSE' or 'ENDIF' command is seen.

    INC
	Usage	: inc varname [value]
	Example	: inc abc 5

	Increment the numerical equivalent of the variable with specified
	value (default: 1) and place the ascii-string result back into
	that variable.

    INFO
	Usage	: info

	Display Device statistics for all the disk-type devices in system
	(DFk:, HDk, JHk:, RAM:, RDk: ...), just like the system command
	info. Gives block used/free, % used, errs, status and volume name.

    INPUT
	Usage	: input var var ... var
	Example	: input abc

	Input from STDIN (or a redirection, or a pipe) to a variable.  The
	next input line is placed in the variable.

    JOIN
	Usage	: join [-r] file1..fileN destfile
	Example	: join part1 part2 part3 total

	Joins the specified files to get destfile. If destfile already
	exists, an error message is generated and operation is aborted,
	unless you specify -r (replace) option.

    LABEL
	Usage	: label name

	Create a program label right here. Used in source files, can then
	GOTO a label.

    LS
	Equivalent to dir.

    MD
	Equivalent to mkdir.

    MEM
	Usage	: mem

	Display current memory statistics for CHIP memory and
	FAST memory (if any installed).

    MKDIR
    (MD)
	Usage	: mkdir name name name...
	Example	: mkdir df0:stuff

	Create the specified directories.

    MV
	Equivalent to rename.

    OPEN
	Usage	: open filename filemode filenumber
	Example	: open RAM:data w 1

	This allows you to open a file, redirect to it as many commands
	as you like, then close it.
	Filename is any valid AmigaDOS filename, filemode is either r
	for read or w for write, filenumber is a number between 1 and 10.
	To redirect a program to or from an open file, use as your redir
	filename a dot followed by the filenumber.
	Here is a complete example:

		open RAM:data w 1
		echo -n 2+2= >.1
		rpn 2 2 + . CR >.1
		close 1
		type RAM:data	# will display 2+2=4
	See also close, flist.

    PATH
	Usage	: path

	Used to list AmigaDOS path. In current version can't be used to
	set it.

    PRI
	Usage	: pri clinumber pri
	Example	: pri 3 5	# set priority of cli #3 to 5

	Change the priority of the specified task (use PS command to
	determine clinumber). If you specify 0 as clinumber you can
	change priority of "this" task (the one executing shell).

    PROTECT
	Usage	: protect file1 ... filen [flags]
	Example	: protect myfile rwe

	Set AMIGADOS file protection flags for the file specified. Valid
	flags are h, s, p, a, r, w, e, d.
	If you don't specify the flags, all flags are cleared.
	Bit 'a' is new to WorkBench 1.2, while 'h', 's', 'p' are new to 1.3.

    PS
	Usage	: ps

	Gives status of DOS processes.  eg:

	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 CD'd directory.

    PWD
	Usage	: pwd

	Rebuild _cwd by backtracing from your current directory.

    QUIT
	Usage	: quit

	Quit out of Shell back to CLI.

    RBACK
	Usage	: rback command

	Start a new process executing the specified command, but can't do
	input/output. Equivalent to 'run command >NIL: <NIL:'.
	This command is not fully reliable: use at your own risk.

    RENAME
    (MV)
	Usage	: rename from to
	or	: rename from from from ... from todir

	Allows you to rename a file or move it around within a disk.
	Allows you to move 1 or more files into a single directory.

    RESIDENT
	Usage	: resident [-a][-r] [files]

	This is ARP resident. Commands are searched by Shell in resident
	list BEFORE of searching on any external device.
	Option -a loads RESIDENT programs, -r removes them.
	Resident with no args lists resident programs.
	Not all programs can run as resident, see ARP docs for more info.

    RETURN
	Usage	: return [n]
	Example	: return 10

	Exit from a script file, or quit from shell with optional
	exit code.

    RM
	Equivalent to delete.

    RPN
	Usage	: rpn expression
	Example	: rpn 3 7 *	# Prints the value 21

	Evaluate an RPN expression, using 32-bit values. In older versions
	of Shell RPN contained string functions too, but now that strings
	are handled by specifical commands, these are no more needed.
	At end of evaluation, RPN prints values on stack, so you can
	say for instance "rpn $x 2 * | input x" to double the value of
	variable x.
	Functions implemented are:

	    + - * /	Obvious meaning; / means integer division, of course
	    %		Module operator e.g. "rpn 7 3 %" answers 1
	    & | ~	Bitwise and, or, not operators
	    > < ==	Tests for greater-than, lower-than, equal. To get
			a test for >= (or <=), you can use < ! (or > !)
	    !		Logical not operator
	    DUP		Duplicate value on top of stack
	    DROP	Drop value on top of stack
	    SWAP	Swap two values on top of stack

    RUN
	Usage	: run prgm args
	Example	: run emacs test.c

	Start a new process executing the specified command.
	In current implementation run command can't be redirected.
	This command is not fully reliable: use at your own risk.
	See also rback.

    SEARCH
	Usage	: search [-w][-c][-n][-r][-e][-q] filelist string

	Search specified files for a string. Only lines containing the
	specified strings are displayed.

	If you specify any directory in filelist, and use the -r (recurse)
	switch, all files in directory are recursively searched.

	Lines are numbered for default; use -n (number) switch to turn off
	line numbering.

	Search is normally not case sensitive; use -c (case) flag to turn ON
	case sensitivity.

	By specifying -e (exclude) switch, only lines NOT containing the
	specified string are listed.

	Using -w (wild) flag, only the lines matching with the string are
	listed.
	Notes to wild card matching;
	- Uses Shell standard matching.
	- Wild cards allowed are *, ?, !.
	- Matching is not case sensitive (even if you use -c flag).
	- The WHOLE line must match the string, not only a substring.
	- String MUST be enclosed in quotes to avoid wildcard expansion

	Flag -q (quiet) suppresses printing of file names.

	Examples:
		search -c -r df0:include ACCESS
	Find all occurrencies of ACCESS (in uppercase) in all files
	contained in include directory.
		search -w shell.h "#define*"
	Lists only lines of file beginning with (not simply containing)
	#define.

    SET
	Usage	: set [name] [string]
	Example	: set abc hello

	Set with no args lists all current variable settings.
	Set with one arg lists the setting for that particular variable.
	Specifying name and string, stores the string into variable name.

	Also See the section on special _variables.


    SLEEP
	Usage	: sleep timeout
	Example	: sleep 10

	Sleep for 'timeout' seconds, or until ^C typed.

    STACK
	Usage	: stack [number]
	Example	: stack 8000

	Changes the default stack for this CLI. Without arguments, prints
	it.

    STRHEAD
	Usage	: strhead varname breakchar string
	Example	: strhead j . foobar.bas
		  echo $j
	Result	: foobar

	Remove everything after and including the breakchar in 'string' and
	place in variable 'varname'.

    STRINGS
	Usage	: strings file1..fileN minlenght
	Example	: strings c:dir c:list shell 7

	Prints strings contained in specified files (usually binary)
	with lenght >= minlenght.

    STRLEFT
	Usage	: strleft varname string n
	Example	: strleft x LongString 5	# Will set x to "LongS"

	Place leftmost n chars of string in variable varname.

    STRLEN
	Usage	: strlen varname string
	Example	: strlen x Hello	# Will set x to "5"

	Puts len of string in variable varname.

    STRMID
	Usage	: strmid varname string n1 [n2]
	Example	: strmid x LongString 5 3	# Will set x to "Str"

	Places n2 chars from string, starting at n1, in variable varname.
	By omitting n2, you get all chars from n1 to end of string.

    STRRIGHT
	Usage	: strright varname string n
	Example	: strright x LongString 5	# Will set x to "tring"

	Place rightmost n chars of string in variable varname.

    STRTAIL
	Usage	: strtail varname breakchar string
	Example	: strtail j . foobar.bas ; echo $j
	Result	: bas

	Remove everything before and including the breakchar in 'string' and
	place in variable 'varname'.

    SOURCE
	Usage	: source file [arguments]
	Example	: source mymake.sh all
	Result	: source file 'mymake.sh' called with var _passed = 'all'

	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).  You can pass SOURCE files arguments
	by specifying arguments after the file name.  Arguments are passed
	via the _passed variable (as a single string).

	Long lines may be split by appending a backslash (\) at end of
	first half. However, even joined lines cannot be longer than
	~255 chars. See example of source files.

	Automatic 'sourcing' is accomplished by placing a .sh extension on
	the file and executing it as you would a C program:

	--------- file hello.sh ---------
	foreach i ( $_passed ) "echo yo $i"
	---------------------------------

	$ hello a b c
	yo a
	yo b
	yo c

    TYPE
	Equivalent to CAT.

    TOUCH
	Usage	: touch file1 .. fileN

	Sets DateStamp on the specified files to the current date and time.

    UNALIAS
	Usage	: unalias name .. name
	Example	: unalias vt

	Delete aliases..

    UNSET
	Usage	: unset name .. name
	Example	: unset abc

	Unset one or more variables.  Deletes them entirely.

    VER
	Usage	: ver

	Show current version name, & authors.

    WINDOW
	Usage	: window [-q][-f][-b][-l][-s] [dimensions]
	Options	:
		-f	(front) Window to front
		-b	(back)  Window to back
		-l	(large) Window to maximum size
		-s	(small) Window to minimum size
		-a	(activate)
		-q	(query) Lists screens and windows open

	Various operations on CLI window. If dimensions are specified,
	they must be in the form x y width height, with values separated
	by spaces.
	The command "window -l" may be very useful on PAL machines to
	get a full PAL window from your login sequence, or if you use
	overscan WorkBench.
	Option -q gives, for each Screen and Window currently open,
	title, left edge, top edge, width, height.


IX. SPECIAL SET VARIABLES
    ---------------------

    _prompt
	This variable is set to the string you wish printed as your
	prompt. This can contain escape sequences if you wish, or
	you can include a %p in path definition to get CD in your
	prompt.
	Default prompt shows path specification in red pen, followed by
	a greater (>) sign and a space.
	The if command will set the prompt to a '_ ' if commands are
	disabled while waiting for a 'endif' or 'else' command. Interactive
	mode only.

    _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.  must be set to some value

    _verbose
	Verbose mode (for source files).  display commands as they are
	executed.

    _maxerr
	The worst (highest) return value to date.  To use this, you usually
	set it to '0', then do some set of commands, then check it.

    _lasterr
	Return code of last command executed.  This includes internal
	commands as well as external comands, so to use this variables
	you must check it IMMEDIATELY after the command in question.

    _cwd
	Holds a string representing the current directory we are in from
	root.  The SHELL can get confused as to its current directory if
	some external program changes the directory.  Use PWD to rebuild
	the _cwd variable in these cases.

    _passed
	This variable contains the passed arguments when you SOURCE a file
	or execute a .sh file.  For instance:

	test a b c d

	-------- file test.sh ----------
	echo $_passed
	foreach i ( $_passed ) "echo YO $i"
	--------------------------------

    _path
	This variable contains the search path when the shell is looking
	for external commands.  The format is:  DIR,DIR,DIR  Each DIR must
	have a trailing ':' or '/'.  The current directory is always
	searched first.  The entire path will be searched first for the
	<command>, then for <command>.sh (automatic shell script sourcing).

	The default _path is set to
		ram:,ram:c/,df0:c/,df1:c/,df0:,df1:,sys:system/

    _insert
	Sets the default for insert/overtype mode for command line
	editing. ^A toggles between, but after <RET> the default is
	set back as indicated by this variable. By default _insert is 1
	indicating insert mode on setting to zero will make overtype
	the default.

    _titlebar
	Used to set window's title bar.

    _clinumber
	Contains the number (1-20) of current CLI.

X.  ADVANCED TOPICS
    ---------------

    EXCEPTION_PROCESSING:

    if no _except variable exists, any command which fails causes the
    rest of the line to abort as if an ABORTLINE had been executed.  If
    the _except variable exists, it is of the form:

    "nnn;commands..."

    where nnn is some value representing the minimum return code required
    to cause an error.  Whenever a command returns a code which is
    larger or equal to nnn, the commands in _except are executed before
    anything.  WHEN _except EXISTS, THE COMMAND LINE DOES NOT ABORT
    AUTOMATICALLY.  Thus, if you want the current line being executed
    to be aborted, the last command in _except should be an "abortline".

    exception handling is disabled while in the exception handling routine
    (thus you can't get into any infinite loops this way).

    Thus if _except = ";", return codes are completely ignored.

    example:

    set _except "20;abortline"

XI. EXAMPLE LOGIN FILE
    ------------------

If from a CLI or the startup-script you say 'SHELL filename', that file is
sourced first.
If you are a CLI user, your startup-sequence may be as simple as:

	C:Shell S:login.sh

Here is, my startup code:

### Example S:login.sh ###

window -l	# if you are on a PAL machine, or use overscan

set _prompt ^[[33m[$_clinumber].%p>" "

set F5 "cdir WORK:"^M
set f9 "ed s:login.sh"^M
set F9 "ed df0:s/startup-sequence"^M
alias toram  "%q foreach i ( $q ) \"cp -r $i: ram:$i >NIL:;\
	assign $i: ram:$i\""
alias ramop  "md RAM:op; assign OP: ram:op"
alias noop   "assign OP: ; rm -r ram:op"
alias newop  "rm -r OP:*"
alias dc     "dfc df0: to df1:"
alias go     "%q assign WORK: Boot:$q; cd WORK:; source startme.sh"
alias get    "%q cp $q RAM: >NIL:"

assign LC:	Stuff:c
assign INCLUDE:	Stuff:include
assign LIB:	Boot:lib
assign QUAD:	RAM:

rback C:FaccII; sleep 1
	# after spawning a process, it is always better to allow it
	# to load the command, to avoid excessive drive head movement

C:REZ Blink CC LC1 LC2 >NIL:

C:PopCli 300 C:Newcli
C:FF -1 Siesta.font >NIL:
C:Patch_1 >NIL:
stack 8000	# lc1 and lc2 need this

source S:setdate.sh	# this is listed in next chapter

### End of example login.sh ###


XII.  Example Source file
      -------------------

The following is an example source file to set date and time; it may be
used at startup if you don't have an internal clock.

### setdate.sh ###

open CON:200/100/440/80/SetDate write 1
echo >.1 -n "Current date is "
date >.1
echo >.1 -n "Please enter date: "
input <.1 d
close 1
strlen len $d
if -r $len 1 > ; date $d ; endif
echo -n "New date: " ; date

### End of setdate.sh ###

Next comes a makefile that needs no Make program: may be executed from
Shell directely!!!

### make.sh ###

if -t Shell.syms Shell.h; cc +HShell.syms Shell.h; rm shell.o; endif
if -t RAM:Shell.syms Shell.syms; cp -d Shell.syms RAM:; endif

foreach i ( main comm1 comm2 comm3 execom globals rawconsole run set \
 sub ) "if -t $i.o $i.c; echo Compile $i...;cc +IRAM:shell.syms $i.c; endif"

if -t Shell run.o main.o comm1.o comm2.o comm3.o execom.o \
set.o sub.o globals.o rawconsole.o
        	ln  +q -m -o Shell run.o main.o comm1.o comm2.o comm3.o\
		execom.o set.o sub.o globals.o rawconsole.o -la -lc
endif

### End of make.sh ###


XIII.  Default Values
       --------------

To make things easier, some aliases are predefined whenever you start a
new Shell. These are:

    - cls
	Simply clear the screen.

    - cdir
	Use "cdir directory" to clear the screen, set CD to directory,
	and list it.

    - kr
	Deletes everything on RAM:. If you think this is dangerous,
	you can remove this alias.

    - exit
	Leave Shell and exit CLI.

Moreover, many variables have default values, and many function keys are
predefined. You can use set command to determine all of these.

XIV.  Why ARP ?
      ---------

For those of you curious enough, the A in "3.xxA" means ARP. The most
recent versions of Shell use ARP.library. This has been very useful in:

 - Implementing commands like ASET, ASSIGN, INFO, RESIDENT, RBACK, RUN.
 - Keeping executable code small.

ARP.library is really public domain, so one can include it in any package,
both commercial or public domain, like I am doing with Shell.
The ARP team is trying to wipe out the BCPL from AMIGA. This is a very
good idea, I think. And there is a lot of people hoping that Commodore
will put ARP.library in ROM, before or after. This would  make the AMIGA
a very mory friendly computer to use and program.
I encourage programmers to get ARP development package: you can find it
on many BBS, and is really public domain. Users can look for a replacement
of C: commands from ARP (but, of course, if you use this Shell you won't
need them anymore, except for ARUN).
SHAR_EOF
#	End of shell archive
exit 0
-- 
Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
Have five nice days.