Yet Another Shell (part 1 of 11)

Dave Clemans dclemans.falcon at mntgfx.mentor.com
Thu Mar 16 08:16:27 AEST 1989


With all the talk about shells that has been going on recently...

Here's an early pre-release of a "Korn"-like shell for anyone
who might want to experiment.  It is definitely NOT complete,
but it starting to be usable.  It does use some GNU code (for
expression evaluation), so it presumably comes under their
"copyleft".

It basically runs on BSD/USG Unix systems, and on the Atari ST.
I'm currently working on a port to the Amiga.

dgc

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 11)."
# Contents:  README alias.c alloca.c makefile.st makefile.unx malloc.c
#   ndir.c ndir.h reader reader/emacs.c reader/history.h
#   reader/killring.c reader/makefile.st reader/makefile.unx
#   reader/tester.c version.c
# Wrapped by dclemans at dclemans on Wed Mar 15 14:03:50 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(2986 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XShell				Dave Clemans
X				12/89 <-> 1/89
X
XA command line interpreter whose syntax is based on the
XUnix "Korn" shell.  While not guaranteeing complete
Xsyntactical and semantic compatibility with the "Korn"
Xshell, the intention is that this shell will be close
Xenough to run most "Korn" shell scripts transparently
X(after accounting for the difference in filename syntax
Xbetween Unix and other systems).
X
XDocumentation: (until I come up with some)
X    The Korn SHell Command and Programming Language
X        Morris I. Bolsky & David G. Korn
X    The KSH Reference Card (correct title?)
X        (author?)
X
XCompiling:
X	Atari ST
X		Mark Williams C V3.0
X			supports Mark Williams C method for passing
X			more than 127 argument characters to executed
X			programs
X		use makefile.st with "make"
X        Only tested on TOS 1.4; might not work on earlier versions
X
X		-DGEMDOS=1 -DMWC -DMWC_ARGV -DMYMALLOC=1
X
X	Unix
X		use makefile.unx
X
X		(BSD systems) -Dunix=1
X		(SYSV systems) -Dunix=1 -DUSG=1
X
XVersion 0.0:			1/23/89
X
X	basic shell functionality
X	version builtin command gives current version
X	memory builtin command gives info about memory usage
X	pipelines
X	backquoted substitution in commands
X	aliases (including tracked aliases)
X	shell variables
X	compound statements (for, if, case, while, until, select)
X	parenthesized commands
X	shell functions
X	"emacs" and "vi" input modes
X	Tenex-like command and file-name completion
X	etc.
X
XVersion 0.1:			2/5/89
X
X	shell command history; HISTSIZE variable
X	sleep builtin command
X	time builtin command
X	eval builtin command
X	exec builtin command
X	fc builtin command
X	memory builtin command gives more information
X	sizes of stack and dynamic memory have been
X	made more realistic
X        fix shell aliases so that they work more like
X	what would be "expected"
X	fix bug in compound statements that lets
X	commands like the following work.
X
X		for i in h:\cm*.arc
X		do
X			j=${i##*\}
X			k=${j%%.*}
X			echo $k
X		done
X
X	fix bug in the history list manager used by the
X	"emacs" and "vi" line editors so that the size of
X	the list can be changed dynamically.  The default
X	size of the list is 32 lines; changing the HISTSIZE
X	shell variable changes the size of both the line
X	list used by the editors, and the statement list
X	used by the fc command.
X
XVersion 0.2:            2/20/89
X
X	initial steps to get this running under Unix
X	(i.e. no job control yet)
X	many bug fixes (too many to mention)
X	full expression support (using code from GNU cccp)
X	the emacs&vi code doesn't seem to work at the moment under Unix
X
XVersion 0.3:            3/7/89
X
X	initial coding of trap and kill builtin commands
X    Build RCS structure containing all released past versions;
X    all future development will be recorded here
X    RANDOM and SECONDS shell variable implemented
X    more typeset attributes implemented (basically everything is
X        there now except non-base 10 numbers)
X    [[ and ]] brackets implemented
X    the emacs&vi code now should work on bsd4.3 (but not on Sys V)
END_OF_FILE
if test 2986 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'alias.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'alias.c'\"
else
echo shar: Extracting \"'alias.c'\" \(5902 characters\)
sed "s/^X//" >'alias.c' <<'END_OF_FILE'
X/*
X * Command Input Shell
X * Dave Clemans
X * 12/88-1/89
X *
X * "spiritually" based on Bourne, Korn shells
X *
X * Command Aliasing
X *
X * $Id: alias.c,v 1.4 89/02/20 20:15:24 dclemans Exp $
X *
X * $Log:	alias.c,v $
X * Revision 1.4  89/02/20  20:15:24  dclemans
X * Add RCS identifiers
X * 
X */
X#include <stdio.h>
X#include "shell.h"
X
Xstatic char *def_aliases[] =
X{
X    "autoload",         "typeset -fu",
X    "echo",             "print -",
X    "false",            "let 0",   
X    "functions",        "typeset -f",
X    "hash",             "alias -t",
X    "history",          "fc -l",
X    "integer",          "typeset -i",
X    "r",                "fc -e -",
X    "source",           ".",
X    "true",             ":",
X    "type",             "whence -v",
X    (char *)NULL,       (char *)NULL
X};
X
Xstatic void dump_alias(svp)
Xstruct aliases *svp;
X{
X    register struct token *tp;
X
X    io_writestring(0,svp->name);
X    io_writestring(0,"=");
X    for (tp = svp->tp; tp != (struct token *)NULL; tp = tp->next)
X    {   /* dump each token */
X        io_writestring(0,tp->name);
X        if (tp->next != (struct token *)NULL)
X            io_writestring(0," ");
X    }
X    io_writestring(0,"\n");
X}   /* end of dump_alias */
X
Xstruct aliases *alias_get(name)
Xregister char *name;
X{
X    register struct aliases *svp;
X    register int rc;
X
X    for (svp = base_env.alias_table; svp != (struct aliases *)NULL; )
X    {   /* look for where to put the variable */
X        rc = strcmp(name,svp->name);
X        if (rc == 0)
X        {   /* found it */
X            return svp;
X        }
X        else if (rc < 0)
X        {   /* go down the left side? */
X            if (svp->left == (struct aliases *)NULL)
X                break;
X            svp = svp->left;
X        }
X        else
X        {   /* go down right side */
X            if (svp->right == (struct aliases *)NULL)
X                break;
X            svp = svp->right;
X        }
X    }
X    return (struct aliases *)NULL;
X}   /* end of alias_get */
X
Xvoid alias_define(name,value,type)
Xchar *name;
Xstruct token *value;
Xint type;
X{
X    register struct aliases *vp,*svp;
X    register struct token *tp;
X    struct token *otp,*last;
X    int rc;
X
X    vp = new_alias();
X    if (vp == (struct aliases *)NULL)
X    {   /* enough memory */
X        errmsg(SHERR_NOMEM,LOC("alias_define"));
X        return;
X    }
X    last = (struct token *)NULL;
X    for (tp = value; tp != (struct token *)NULL; tp = tp->next)
X    {   /* for each value token */
X        otp = new_token(strlen(tp->name));
X        if (otp == (struct token *)NULL)
X        {   /* enough memory? */
X            errmsg(SHERR_NOMEM,LOC("alias_define"));
X            tokens_free(vp->tp);
X            free(vp);
X            return;
X        }
X        otp->type = tp->type;
X        strcpy(otp->name,tp->name);
X        if (vp->tp == (struct token *)NULL)
X            vp->tp = last = otp;
X        else
X        {   /* tack onto end */
X            last->next = otp;
X            last = otp;
X        }
X    }
X
X    rc = 0;
X    for (svp = base_env.alias_table; svp != (struct aliases *)NULL; )
X    {   /* look for where to put the variable */
X        rc = strcmp(name,svp->name);
X        if (rc == 0)
X        {   /* replace existing value */
X            tokens_free(svp->tp);
X            svp->tp = vp->tp;
X            svp->type = type;
X            free(vp);
X            return;
X        }
X        else if (rc < 0)
X        {   /* go down the left side? */
X            if (svp->left == (struct aliases *)NULL)
X                break;
X            svp = svp->left;
X        }
X        else
X        {   /* go down right side */
X            if (svp->right == (struct aliases *)NULL)
X                break;
X            svp = svp->right;
X        }
X    }
X
X    vp->name = strcopy(name);
X    vp->type = type;
X    if (base_env.alias_table == (struct aliases *)NULL)
X        base_env.alias_table = vp;
X    else if (rc < 0)
X        svp->left = vp;
X    else
X        svp->right = vp;
X}   /* end of alias_define */
X
Xvoid alias_sdefine(name,value,type)
Xchar *name;
Xchar *value;
Xint type;
X{
X    register struct token *tp,*ftp,*ltp;
X    struct strsave *savep;
X
X    savep = strings;
X    io_pushtoken(value,1);
X    ftp = ltp = (struct token *)NULL;
X    while (!lex_sempty(savep))
X    {   /* lex the alias value into tokens */
X        tp = lex_token(1);
X        if (tp == (struct token *)NULL)
X            break;
X        if (ftp == (struct token *)NULL)
X            ftp = ltp = tp;
X        else
X        {   /* tack onto end */
X            ltp->next = tp;
X            ltp = tp;
X        }
X    }
X    alias_define(name,ftp,type);
X    tokens_free(ftp);
X}   /* end of alias_sdefine */
X
Xint alias_tracked(name)
Xchar *name;
X{
X    register struct aliases *svp;
X
X    svp = alias_get(name);
X    if (svp != (struct aliases *)NULL)
X    {   /* if the alias was found */
X        return svp->type & TYPE_TRACKED;
X    }
X    return 0;
X}   /* end of alias_tracked */
X
Xint alias_print(name)
Xchar *name;
X{
X    register struct aliases *svp;
X
X    svp = alias_get(name);
X    if (svp != (struct aliases *)NULL)
X    {   /* if variable was found */
X        if (svp->tp != (struct token *)NULL)
X            dump_alias(svp);
X        return 0;
X    }
X    return 1;
X}   /* end of alias_print */
X
Xvoid alias_dump(vp,type)
Xregister struct aliases *vp;
Xint type;
X{
X    if (vp == (struct aliases *)NULL)
X        return;
X    if (vp->left != (struct aliases *)NULL)
X        alias_dump(vp->left,type);
X    if (vp->tp != (struct token *)NULL &&
X        ((type == 0) || (vp->type & type)))
X    {   /* if the alias is really defined and type matches */
X        dump_alias(vp);
X    }
X    if (vp->right != (struct aliases *)NULL)
X        alias_dump(vp->right,type);
X}   /* end of alias_dump */
X
Xvoid alias_init()
X{
X    register int i;
X
X    for (i = 0; def_aliases[i] != (char *)NULL; i += 2)
X    {   /* for each default alias */
X        alias_sdefine(def_aliases[i],def_aliases[i+1],0);
X    }
X}   /* end of alias_init */
END_OF_FILE
if test 5902 -ne `wc -c <'alias.c'`; then
    echo shar: \"'alias.c'\" unpacked with wrong size!
fi
# end of 'alias.c'
fi
if test -f 'alloca.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'alloca.c'\"
else
echo shar: Extracting \"'alloca.c'\" \(5656 characters\)
sed "s/^X//" >'alloca.c' <<'END_OF_FILE'
X/*
X	alloca -- (mostly) portable public-domain implementation -- D A Gwyn
X	last edit:	86/05/30	rms
X	   include config.h, since on VMS it renames some symbols.
X	   Use xmalloc instead of malloc.
XCBARRON:
X	xmalloc is just malloc with a error message if malloc
X	fails because of being out of memory.Use malloc instead
X
X	 David
X
X	This implementation of the PWB library alloca() function,
X	which is used to allocate space off the run-time stack so
X	that it is automatically reclaimed upon procedure exit,
X	was inspired by discussions with J. Q. Johnson of Cornell.
X	It should work under any C implementation that uses an
X	actual procedure stack (as opposed to a linked list of
X	frames).  There are some preprocessor constants that can
X	be defined when compiling for your specific system, for
X	improved efficiency; however, the defaults should be okay.
X	The general concept of this implementation is to keep
X	track of all alloca()-allocated blocks, and reclaim any
X	that are found to be deeper in the stack than the current
X	invocation.  This heuristic does not reclaim storage as
X	soon as it becomes invalid, but it will do so eventually.
X	As a special case, alloca(0) reclaims storage without
X	allocating any.  It is a good idea to use alloca(0) in
X	your main control loop, etc. to force garbage collection.
X *
X * $Id: alloca.c,v 1.2 89/02/20 20:15:36 dclemans Exp $
X *
X * $Log:	alloca.c,v $
X * Revision 1.2  89/02/20  20:15:36  dclemans
X * Add RCS identifiers
X * 
X*/
X#ifdef MWC
X#undef lint
X#undef emacs
X#undef XJ311
X#endif
X
X#ifndef lint
Xstatic char	SCCSid[] = "@(#)alloca.c	1.1";	/* for the "what" utilit
Xy */
X#endif
X#ifdef emacs
X#include "config.h"
X#ifdef static
X/* actually, only want this if static is defined as ""
X   -- this is for usg, in which emacs must undefine static
X   in order to make unexec workable
X   */
X#ifndef STACK_DIRECTION
Xyou
Xlose
X-- must know STACK_DIRECTION at compile-time
X#endif /* STACK_DIRECTION undefined */
X#endif static
X#endif emacs
X#ifdef X3J11
Xtypedef void	*pointer;		/* generic pointer type */
X#else
Xtypedef char	*pointer;		/* generic pointer type */
X#endif
X#define	NULL	0			/* null pointer constant */
Xextern void	free();
X#ifndef MWC
Xextern pointer	xmalloc();
X#else
Xextern char *malloc();
X#define xmalloc malloc
X#endif
X/*
X	Define STACK_DIRECTION if you know the direction of stack
X	growth for your system; otherwise it will be automatically
X	deduced at run-time.
X	STACK_DIRECTION > 0 => grows toward higher addresses
X	STACK_DIRECTION < 0 => grows toward lower addresses
X	STACK_DIRECTION = 0 => direction of growth unknown */
X#ifdef MWC
X#define STACK_DIRECTION 0
X#define pointer char *
X#endif
X#ifndef STACK_DIRECTION
X#define	STACK_DIRECTION	0		/* direction unknown */
X#endif
X#if STACK_DIRECTION != 0
X#define	STACK_DIR	STACK_DIRECTION	/* known at compile-time */
X#else	/* STACK_DIRECTION == 0; need run-time code */
Xstatic int	stack_dir;		/* 1 or -1 once known */
X#define	STACK_DIR	stack_dir
Xstatic void
Xfind_stack_direction (/* void */)
X{
X  static char	*addr = NULL;	/* address of first
X				   `dummy', once known */
X  auto char	dummy;		/* to get stack address */
X  if (addr == NULL)
X    {				/* initial entry */
X      addr = &dummy;
X      find_stack_direction ();	/* recurse once */
X    }
X  else				/* second entry */
X    if (&dummy > addr)
X      stack_dir = 1;		/* stack grew upward */
X    else
X      stack_dir = -1;		/* stack grew downward */
X}
X#endif	/* STACK_DIRECTION == 0 */
X/*
X	An "alloca header" is used to:
X	(a) chain together all alloca()ed blocks;
X	(b) keep track of stack depth.
X	It is very important that sizeof(header) agree with malloc()
X	alignment chunk size.  The following default should work okay.*/
X#ifndef	ALIGN_SIZE
X#define	ALIGN_SIZE	sizeof(double)
X#endif
Xtypedef union hdr
X{
X  char	align[ALIGN_SIZE];	/* to force sizeof(header) */
X  struct
X    {
X      union hdr *next;		/* for chaining headers */
X      char *deep;		/* for stack depth measure */
X    } h;
X} header;
X/*
X	alloca( size ) returns a pointer to at least `size' bytes of
X	storage which will be automatically reclaimed upon exit from
X	the procedure that called alloca().  Originally, this space
X	was supposed to be taken from the current stack frame of the
X	caller, but that method cannot be made to work for some
X	implementations of C, for example under Gould's UTX/32. */
Xstatic header *last_alloca_header = NULL; /* -> last alloca header */
Xpointer
Xalloca (size)			/* returns pointer to storage */
X     unsigned	size;		/* # bytes to allocate */
X{
X  auto char	probe;		/* probes stack depth: */
X  register char	*depth = &probe;
X#if STACK_DIRECTION == 0
X  if (STACK_DIR == 0)		/* unknown growth direction */
X    find_stack_direction ();
X#endif
X				/* Reclaim garbage, defined as all alloca()ed st
Xorage that
X				   was allocated from deeper in the stack than c
Xurrently. */
X  {
X    register header	*hp;	/* traverses linked list */
X    for (hp = last_alloca_header; hp != NULL;)
X      if (STACK_DIR > 0 && hp->h.deep > depth
X	  || STACK_DIR < 0 && hp->h.deep < depth)
X	{
X	  register header	*np = hp->h.next;
X	  free ((pointer) hp);	/* collect garbage */
X	  hp = np;		/* -> next header */
X	}
X      else
X	break;			/* rest are not deeper */
X    last_alloca_header = hp;	/* -> last valid storage */
X  }
X  if (size == 0)
X    return NULL;		/* no allocation required */
X  /* Allocate combined header + user data storage. */
X  {
X    register pointer	new = xmalloc (sizeof (header) + size);
X    /* address of header */
X    ((header *)new)->h.next = last_alloca_header;
X    ((header *)new)->h.deep = depth;
X    last_alloca_header = (header *)new;
X    /* User storage begins just after header. */
X    return (pointer)((char *)new + sizeof(header));
X  }
X}
END_OF_FILE
if test 5656 -ne `wc -c <'alloca.c'`; then
    echo shar: \"'alloca.c'\" unpacked with wrong size!
fi
# end of 'alloca.c'
fi
if test -f 'makefile.st' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makefile.st'\"
else
echo shar: Extracting \"'makefile.st'\" \(1349 characters\)
sed "s/^X//" >'makefile.st' <<'END_OF_FILE'
X#
X# Command Input Shell
X# Dave Clemans
X# 12/88-1/89
X#
X# Makefile
X#
X# $Id: makefile.st,v 1.6 89/02/25 17:40:14 dclemans Exp $
X#
X# $Log:	makefile.st,v $
X# Revision 1.6  89/02/25  17:40:14  dclemans
X# miscellaneous bug fixes/speedups
X# 
X# Revision 1.5  89/02/20  22:35:39  dclemans
X# Add a "clean" action
X# 
X# Revision 1.4  89/02/20  22:32:09  dclemans
X# Add in new file that defines traps
X# 
X# Revision 1.3  89/02/20  20:12:02  dclemans
X# Add RCS identifiers
X# 
XCFLAGS	= -O -VPEEP -VPSTR -DGEMDOS=1 -DMWC_ARGV=1 -DMWC=1 -DMYMALLOC=1 -DLINED=1
XLFLAGS	= -VPSTR
XOFILES	= main.o version.o lex.o exec.o var.o cexp_tab.o alias.o io.o \
X	cmd1.o cmd2.o cmd3.o trap.o wild.o util.o ndir.o alloca.o malloc.o
X
Xshell.ttp: $(OFILES) reader\libreader.a
X	$(CC) $(LFLAGS) $(OFILES) reader\libreader.a -o $@
X
Xcexp_tab.c:	cexp.y
X	f:\gnu\bison\bison.prg cexp.y
X
Xcexp_tab.o:	cexp_tab.c shell.h
Xmain.o:		main.c shell.h
Xversion.o:	version.c shell.h
Xlex.o:		lex.c shell.h
Xexec.o:		exec.c shell.h
Xvar.o:		var.c shell.h
Xexp.o:		exp.c shell.h
Xalias.o:	alias.c shell.h
Xio.o:		io.c shell.h
Xcmd1.o:		cmd1.c shell.h
Xcmd2.o:		cmd2.c shell.h
Xcmd3.o:		cmd3.c shell.h
Xtrap.o:		trap.c shell.h
Xwild.o:		wild.c shell.h ndir.h
Xndir.o:		ndir.c ndir.h
Xutil.o:		util.c shell.h
Xalloca.o:	alloca.c
Xmalloc.o:	malloc.c
X
Xreader\libreader.a:
X	cd reader;make
X
Xclean:
X	rm -f shell.ttp *.o cexp_tab.c
END_OF_FILE
if test 1349 -ne `wc -c <'makefile.st'`; then
    echo shar: \"'makefile.st'\" unpacked with wrong size!
fi
# end of 'makefile.st'
fi
if test -f 'makefile.unx' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makefile.unx'\"
else
echo shar: Extracting \"'makefile.unx'\" \(1239 characters\)
sed "s/^X//" >'makefile.unx' <<'END_OF_FILE'
X#
X# Command Input Shell
X# Dave Clemans
X# 12/88-1/89
X#
X# Makefile
X#
X# $Id: makefile.unx,v 1.5 89/02/25 17:40:18 dclemans Exp $
X#
X# $Log:	makefile.unx,v $
X# Revision 1.5  89/02/25  17:40:18  dclemans
X# miscellaneous bug fixes/speedups
X# 
X# Revision 1.4  89/02/20  22:35:45  dclemans
X# Add a "clean" action
X# 
X# Revision 1.3  89/02/20  22:32:21  dclemans
X# Add in new file that defines traps
X# 
X# Revision 1.2  89/02/20  20:09:34  dclemans
X# Add RCS identifiers
X# 
XCFLAGS	= -O
XLFLAGS	= 
XOFILES	= main.o version.o lex.o exec.o var.o cexp.tab.o alias.o io.o \
X	cmd1.o cmd2.o cmd3.o trap.o wild.o util.o
X
X#shell.ttp: $(OFILES) reader/libreader.a
X#	$(CC) $(LFLAGS) $(OFILES) reader/libreader.a -o $@
Xshell: $(OFILES)
X	$(CC) $(LFLAGS) $(OFILES) -o $@
X
Xcexp.tab.c: cexp.y
X	bison cexp.y
Xcexp.tab.o: cexp.tab.c shell.h
X	$(CC) $(CFLAGS) -c -Dconst= cexp.tab.c
X
Xmain.o:		main.c shell.h
Xversion.o:	version.c shell.h
Xlex.o:		lex.c shell.h
Xexec.o:		exec.c shell.h
Xvar.o:		var.c shell.h
Xalias.o:	alias.c shell.h
Xio.o:		io.c shell.h
Xcmd1.o:		cmd1.c shell.h
Xcmd2.o:		cmd2.c shell.h
Xcmd3.o:		cmd3.c shell.h
Xtrap.o:		trap.c shell.h
Xwild.o:		wild.c shell.h ndir.h
Xutil.o:		util.c shell.h
X
Xreader/libreader.a:
X	cd reader;make
X
Xclean:
X	rm -f shell *.o cexp.tab.c
END_OF_FILE
if test 1239 -ne `wc -c <'makefile.unx'`; then
    echo shar: \"'makefile.unx'\" unpacked with wrong size!
fi
# end of 'makefile.unx'
fi
if test -f 'malloc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'malloc.c'\"
else
echo shar: Extracting \"'malloc.c'\" \(8160 characters\)
sed "s/^X//" >'malloc.c' <<'END_OF_FILE'
X/*
X * Dynamic Memory Allocation Routines
X *
X *  malloc  - allocate a block of memory
X *      char *malloc(unsigned size);
X *  char *lmalloc(unsigned long size);
X *
X *  calloc  - allocate a block of memory, clearing it to zero first
X *      char *calloc(unsigned unitsize,unsigned nunits);
X *  char *lcalloc(unsigned long unitsize,unsigned long nunits);
X *
X *  realloc - reallocate a block of memory, making it smaller or larger
X *  char *realloc(char *ptr,unsigned size);
X *  char *lrealloc(char *ptr,unsigned long size);
X *
X *  free    - free a block of memory
X *      free(char *ptr);
X *
X * Dave Clemans, 1/88
X *
X * $Id: malloc.c,v 1.3 89/02/20 20:09:31 dclemans Exp $
X *
X * $Log:	malloc.c,v $
X * Revision 1.3  89/02/20  20:09:31  dclemans
X * Add RCS identifiers
X * 
X */
X#include <stdio.h>
X#ifndef unix
X#include <osbind.h>
X#endif
X
X#ifdef  unix
Xextern char *sbrk();
X#endif
X
Xextern char *malloc(),*lmalloc();
Xextern char *calloc(),*lcalloc();
Xextern char *realloc(),*lrealloc();
Xextern free();
X
X/*
X * Set up the arena we work in
X */
X#define HUNK    (18L*1024L)         /* basic hunk size for allocation */
X
Xstruct memblock
X{
X    long    size;
X    struct memblock *next;
X};
X
Xstatic struct memblock *arena = (struct memblock *)NULL;
Xstatic struct memblock *arenaTail = (struct memblock *)NULL;
Xlong poolSize = 0;
Xlong mallocTotal = 0;
Xlong mallocHighWater = 0;
X
X/*
X * The user-visible routines are merely shells; they get memory
X * by calling the following routines.  They are declared as
X * "long *" because they guarantee returning a memory block
X * with a starting address suitable for storing a long.
X */
Xstatic long *memget();
Xstatic memput();
X
X/*
X * Get a block of memory
X */
Xchar *malloc(size)
Xunsigned size;
X{
X    return lmalloc((unsigned long)size);
X}   /* end of malloc */
X
Xchar *lmalloc(size)
Xunsigned long size;
X{
X    register long *mem;
X    register long rsize;
X
X    rsize = size + sizeof(long);
X    rsize = ((rsize + (long)sizeof(long) - 1L) / (long)sizeof(long)) * (long)sizeof(long);
X    mem = memget(rsize);
X    if (mem == (long *)NULL)
X        return (char *)NULL;
X    *mem++ = rsize;
X    mallocTotal += rsize;
X    if (mallocTotal > mallocHighWater)
X        mallocHighWater = mallocTotal;
X    return (char *)mem;
X}   /* end of lmalloc */
X
X/*
X * Get a block of memory, clearing it to nulls
X */
Xchar *calloc(unitsize,nunits)
Xunsigned unitsize;
Xunsigned nunits;
X{
X    return lcalloc((unsigned long)unitsize,(unsigned long)nunits);
X}   /* end of calloc */
X
Xchar *lcalloc(unitsize,nunits)
Xunsigned long unitsize;
Xunsigned long nunits;
X{
X    register long rsize,size;
X    register char *ptr;
X    register long *mem;
X
X    size = (long)unitsize * (long)nunits;
X    rsize = size + sizeof(long);
X    rsize = ((rsize + (long)sizeof(long) - 1L) / (long)sizeof(long)) * (long)sizeof(long);
X    mem = memget(rsize);
X    ptr = (char *)mem;
X    if (mem == (long *)NULL)
X        return (char *)NULL;
X    while (size--)
X        *ptr++ = '\0';
X    *mem++ = rsize;
X    mallocTotal += rsize;
X    if (mallocTotal > mallocHighWater)
X        mallocHighWater = mallocTotal;
X    return (char *)mem;
X}   /* end of lcalloc */
X
X/*
X * Reallocate a block of memory
X */
Xchar *realloc(ptr,size)
Xchar *ptr;
Xunsigned size;
X{
X    return lrealloc(ptr,(unsigned long)size);
X}   /* end of realloc */
X
Xchar *lrealloc(ptr,size)
Xchar *ptr;
Xunsigned long size;
X{
X    long *mem;
X    register long actual_size;
X    register char *newptr;
X    register char *to,*from;
X
X    mem = (long *)ptr;
X    size = ((size + (long)sizeof(long) - 1L) / (long)sizeof(long)) * (long)sizeof(long);
X    actual_size = *--mem;
X
X    if ((size + sizeof(long) + sizeof(struct memblock)) < actual_size)
X    {   /* if the block is being shrunk */
X        newptr = ptr + size;
X        memput(newptr,actual_size - size - sizeof(long));
X        mallocTotal -= (actual_size - size - sizeof(long));
X        *mem = size + sizeof(long);
X    }
X    else
X    {   /* the block is being expanded */
X        newptr = (char *)memget(size + (long)sizeof(long));
X        if (newptr == (char *)NULL)
X            return newptr;
X        mallocTotal += size + sizeof(long);
X        if (mallocTotal > mallocHighWater)
X            mallocHighWater = mallocTotal;
X        actual_size -= sizeof(long);
X        to = newptr;
X        from = ptr;
X        while (actual_size--)
X            *to++ = *from++;
X        free(ptr);
X    }
X    return newptr;
X}   /* end of lrealloc */
X
X/*
X * Free a block of memory
X */
Xfree(ptr)
Xchar *ptr;
X{
X    register long *mem;
X    register long size;
X
X    mem = (long *)ptr;
X    size = *--mem;
X    memput((long *)mem,size);
X    mallocTotal -= size;
X}   /* end of free */
X
X/*
X * Finally! we reach the heart of this memory allocation package
X */
X
X/*
X * Allocate a block of memory
X */
Xstatic long *memget(size)
Xlong size;
X{
X    register struct memblock *mem,*memp;
X    register char *fptr;
X    register long toAlloc;
X    long *ptr;
X
X    if (size < sizeof(struct memblock))
X        size = sizeof(struct memblock);
X
X    memp = (struct memblock *)NULL;
X    for (mem = arena; mem != (struct memblock *)NULL; mem = mem->next)
X    {   /* look for a block with enough space */
X        if (mem->size == size || mem->size >= (size + sizeof(struct memblock)))
X        {   /* we've found some memory; unlink and return it */
X            if (memp == (struct memblock *)NULL)
X                arena = mem->next;
X            else
X                memp->next = mem->next;
X            if (mem == arenaTail)
X                arenaTail = memp;
X            if (mem->size > size)
X            {   /* if we need to split this block */
X                fptr = (char *)mem;
X                fptr += size;
X                memput((long *)fptr,mem->size - size);
X            }
X            return (long *)mem;
X        }
X        memp = mem;
X    }
X
X    /* no block with enough space; try to get more memory from system */
X    /* if that fails, we signal no memory */
X
X    toAlloc = (size < HUNK) ? HUNK : (((size + HUNK - 1L) / HUNK) * HUNK);
X#ifdef  unix
X    ptr = (long *)sbrk(toAlloc);
X#else
X    ptr = (long *)Malloc(toAlloc);
X#endif
X    if (ptr == (long *)NULL)
X        return (long *)NULL;
X    poolSize += toAlloc;
X    memput(ptr,toAlloc);
X    return memget(size);
X}   /* end of memget */
X
X/*
X * Free a block of memory
X */
Xstatic memput(ptr,size)
Xlong *ptr;
Xlong size;
X{
X    register struct memblock *mem,*memp;
X    register struct memblock *new;
X
X    if (size < sizeof(struct memblock))
X        size = sizeof(struct memblock);
X
X    memp = (struct memblock *)NULL;
X    for (mem = arena; mem != (struct memblock *)NULL; mem = mem->next)
X    {   /* look for place to put this freed block */
X        if (ptr < (long *)mem)
X        {   /* then we put the block before this block */
X            new = (struct memblock *)ptr;
X            new->size = size;
X            new->next = mem;
X            if (mem == arena)
X                arena = new;
X            else
X                memp->next = new;
X            /* now try to compact new block backwards and forwards */
X            if ((char *)new + size == (char *)mem)
X            {   /* forwards compaction */
X                new->size += mem->size;
X                new->next = mem->next;
X        if (arenaTail == mem)
X            arenaTail = new;
X            }
X            if (memp != (struct memblock *)NULL &&
X               ((char *)memp + memp->size == (char *)new))
X            {   /* backwards compaction */
X                memp->size += new->size;
X                memp->next = new->next;
X                if (arenaTail == new)
X                    arenaTail = memp;
X            }
X            return;
X        }
X        memp = mem;
X    }
X
X    /* if reach here, just tack block to end of list */
X    mem = (struct memblock *)ptr;
X    mem->size = size;
X    mem->next = (struct memblock *)NULL;
X    if (arena == (struct memblock *)NULL)
X        arena = arenaTail = mem;
X    else
X    {   /* tack onto end */
X        /* try compacting first */
X        if ((char *)arenaTail + arenaTail->size == (char *)mem)
X            arenaTail->size += mem->size;
X        else
X        {   /* really tack onto end */
X            arenaTail->next = mem;
X            arenaTail = mem;
X        }
X    }
X}   /* end of memput */
END_OF_FILE
if test 8160 -ne `wc -c <'malloc.c'`; then
    echo shar: \"'malloc.c'\" unpacked with wrong size!
fi
# end of 'malloc.c'
fi
if test -f 'ndir.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'ndir.c'\"
else
echo shar: Extracting \"'ndir.c'\" \(5609 characters\)
sed "s/^X//" >'ndir.c' <<'END_OF_FILE'
X/*
X * @(#)msd_dir.c 1.4 87/11/06   Public Domain.
X *
X *  A public domain implementation of BSD directory routines for
X *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael at garfield),
X *  August 1987
X *
X *  GEMDOS (Atari ST) mods by Dave Clemans, November 1988
X *
X * $Id: ndir.c,v 1.2 89/02/20 20:09:22 dclemans Exp $
X *
X * $Log:	ndir.c,v $
X * Revision 1.2  89/02/20  20:09:22  dclemans
X * Add RCS identifiers
X * 
X */
X
X#ifndef GEMDOS
X#include    <sys/types.h>
X#include    <sys/stat.h>
X#include    <sys/dir.h>
X#else
X#include    "ndir.h"
X#endif  GEMDOS
X#include    <strings.h>
X#ifndef GEMDOS
X#include    <malloc.h>
X#include    <dos.h>
X#else
X#include    <osbind.h>
Xextern char *malloc(),*calloc();
X#endif  GEMDOS
X
X#ifndef NULL
X# define    NULL    0
X#endif  /* NULL */
X
X#ifndef MAXPATHLEN
X# define    MAXPATHLEN  255
X#endif  /* MAXPATHLEN */
X
X/* attribute stuff */
X#define A_RONLY     0x01
X#define A_HIDDEN    0x02
X#define A_SYSTEM    0x04
X#define A_LABEL     0x08
X#define A_DIR       0x10
X#define A_ARCHIVE   0x20
X
X/* dos call values */
X#define DOSI_FINDF  0x4e
X#define DOSI_FINDN  0x4f
X#define DOSI_SDTA   0x1a
X
X#define Newisnull(a, t)     ((a = (t *) malloc(sizeof(t))) == (t *) NULL)
X#define ATTRIBUTES      (A_DIR | A_HIDDEN | A_SYSTEM)
X
X/* what find first/next calls look use */
Xtypedef struct {
X    char        d_buf[21];
X    char        d_attribute;
X    unsigned short  d_time;
X    unsigned short  d_date;
X    long        d_size;
X    char        d_name[13];
X} Dta_buf;
X
Xstatic  char    *getdirent();
Xstatic  void    setdta();
Xstatic  void    free_dircontents();
X
Xstatic  Dta_buf     dtabuf;
Xstatic  Dta_buf     *dtapnt = &dtabuf;
X#ifndef GEMDOS
Xstatic  union REGS  reg, nreg;
X
X#if defined(M_I86LM)
Xstatic  struct SREGS    sreg;
X#endif
X#endif  GEMDOS
X
XDIR *
Xopendir(name)
X    char    *name;
X{
X#ifndef GEMDOS
X    struct  stat        statb;
X#endif  GEMDOS
X    register DIR         *dirp;
X    char            c;
X    char            *s;
X    register struct _dircontents *dp;
X    char            nbuf[MAXPATHLEN + 1];
X
X#ifndef GEMDOS
X    if (stat(name, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR)
X        return (DIR *) NULL;
X#endif  GEMDOS
X    if (Newisnull(dirp, DIR))
X        return (DIR *) NULL;
X    if (*name && (c = name[strlen(name) - 1]) != '\\' && c != '/')
X        (void) strcat(strcpy(nbuf, name), "\\*.*");
X    else 
X        (void) strcat(strcpy(nbuf, name), "*.*");
X    dirp->dd_loc = 0;
X#ifndef GEMDOS
X    setdta();
X#else
X    Fsetdta(&dtabuf);
X#endif  GEMDOS
X    dirp->dd_contents = dirp->dd_cp = (struct _dircontents *) NULL;
X    if ((s = getdirent(nbuf)) == (char *) NULL)
X        return dirp;
X    do {
X        if (Newisnull(dp, struct _dircontents) || (dp->_d_entry =
X            malloc((unsigned) (strlen(s) + 1))) == (char *) NULL)
X        {
X            if (dp)
X                free((char *) dp);
X            free_dircontents(dirp->dd_contents);
X            return (DIR *) NULL;
X        }
X        if (dirp->dd_contents)
X            dirp->dd_cp = dirp->dd_cp->_d_next = dp;
X        else
X            dirp->dd_contents = dirp->dd_cp = dp;
X        (void) strcpy(dp->_d_entry, s);
X        dp->_d_next = (struct _dircontents *) NULL;
X    } while ((s = getdirent((char *) NULL)) != (char *) NULL);
X    dirp->dd_cp = dirp->dd_contents;
X
X    return dirp;
X}
X
Xvoid
Xclosedir(dirp)
X    DIR *dirp;
X{
X    free_dircontents(dirp->dd_contents);
X    free((char *) dirp);
X}
X
Xstruct direct   *
Xreaddir(dirp)
X    register DIR *dirp;
X{
X    static  struct direct   dp;
X    
X    if (dirp->dd_cp == (struct _dircontents *) NULL)
X        return (struct direct *) NULL;
X    dp.d_namlen = dp.d_reclen =
X        strlen(strcpy(dp.d_name, dirp->dd_cp->_d_entry));
X    dp.d_ino = 0;
X    dirp->dd_cp = dirp->dd_cp->_d_next;
X    dirp->dd_loc++;
X
X    return &dp;
X}
X
Xvoid
Xseekdir(dirp, off)
X    register DIR *dirp;
X    long    off;
X{
X    long            i = off;
X    struct _dircontents *dp;
X
X    if (off < 0)
X        return;
X    for (dp = dirp->dd_contents ; --i >= 0 && dp ; dp = dp->_d_next)
X        ;
X    dirp->dd_loc = off - (i + 1);
X    dirp->dd_cp = dp;
X}
X
Xlong
Xtelldir(dirp)
X    DIR *dirp;
X{
X    return dirp->dd_loc;
X}
X
Xstatic  void
Xfree_dircontents(dp)
X    register struct  _dircontents    *dp;
X{
X    register struct _dircontents *odp;
X
X    while (dp) {
X        if (dp->_d_entry)
X            free(dp->_d_entry);
X        dp = (odp = dp)->_d_next;
X        free((char *) odp);
X    }
X}
X
Xstatic  char    *
Xgetdirent(dir)
X    register char    *dir;
X{
X#ifndef GEMDOS
X    if (dir != (char *) NULL) {     /* get first entry */
X        reg.h.ah = DOSI_FINDF;
X        reg.h.cl = ATTRIBUTES;
X#if defined(M_I86LM)
X        reg.x.dx = FP_OFF(dir);
X        sreg.ds = FP_SEG(dir);
X#else
X        reg.x.dx = (unsigned) dir;
X#endif
X    } else {                /* get next entry */
X        reg.h.ah = DOSI_FINDN;
X#if defined(M_I86LM)
X        reg.x.dx = FP_OFF(dtapnt);
X        sreg.ds = FP_SEG(dtapnt);
X#else
X        reg.x.dx = (unsigned) dtapnt;
X#endif
X    }
X#if defined(M_I86LM)
X    intdosx(&reg, &nreg, &sreg);
X#else
X    intdos(&reg, &nreg);
X#endif
X    if (nreg.x.cflag)
X        return (char *) NULL;
X
X#else
X    int status;
X
X    if (dir != (char *) NULL) {     /* get first entry */
X        status = Fsfirst(dir,A_DIR);
X    } else {
X        status = Fsnext();
X    }
X    if (status != 0)
X        return (char *)NULL;
X#endif  GEMDOS
X    return dtabuf.d_name;
X}
X
X#ifndef GEMDOS
Xstatic  void
Xsetdta()
X{
X    reg.h.ah = DOSI_SDTA;
X#if defined(M_I86LM)
X    reg.x.dx = FP_OFF(dtapnt);
X    sreg.ds = FP_SEG(dtapnt);
X    intdosx(&reg, &nreg, &sreg);
X#else
X    reg.x.dx = (int) dtapnt;
X    intdos(&reg, &nreg);
X#endif
X}
X#endif  GEMDOS
END_OF_FILE
if test 5609 -ne `wc -c <'ndir.c'`; then
    echo shar: \"'ndir.c'\" unpacked with wrong size!
fi
# end of 'ndir.c'
fi
if test -f 'ndir.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'ndir.h'\"
else
echo shar: Extracting \"'ndir.h'\" \(1265 characters\)
sed "s/^X//" >'ndir.h' <<'END_OF_FILE'
X/*
X * @(#)msd_dir.h 1.4 87/11/06   Public Domain.
X *
X *  A public domain implementation of BSD directory routines for
X *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael at garfield),
X *  August 1987
X *
X * Gemdos mods by Dave Clemans
X *
X * $Id: ndir.h,v 1.2 89/02/20 20:09:29 dclemans Exp $
X *
X * $Log:	ndir.h,v $
X * Revision 1.2  89/02/20  20:09:29  dclemans
X * Add RCS identifiers
X * 
X */
X
Xtypedef long ino_t;
X
X#define rewinddir(dirp) seekdir(dirp, 0L)
X
X#define MAXNAMLEN   12
X
Xstruct direct {
X    ino_t   d_ino;          /* a bit of a farce */
X    int d_reclen;       /* more farce */
X    int d_namlen;       /* length of d_name */
X    char    d_name[MAXNAMLEN + 1];      /* garentee null termination */
X};
X
Xstruct _dircontents {
X    char    *_d_entry;
X    struct _dircontents *_d_next;
X};
X
Xtypedef struct _dirdesc {
X    int     dd_id;  /* uniquely identify each open directory */
X    long        dd_loc; /* where we are in directory entry is this */
X    struct _dircontents *dd_contents;   /* pointer to contents of dir */
X    struct _dircontents *dd_cp; /* pointer to current position */
X} DIR;
X
Xextern  DIR     *opendir();
Xextern  struct direct   *readdir();
Xextern  void        seekdir();
Xextern  long        telldir();
Xextern  void        closedir();
END_OF_FILE
if test 1265 -ne `wc -c <'ndir.h'`; then
    echo shar: \"'ndir.h'\" unpacked with wrong size!
fi
# end of 'ndir.h'
fi
if test ! -d 'reader' ; then
    echo shar: Creating directory \"'reader'\"
    mkdir 'reader'
fi
if test -f 'reader/emacs.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'reader/emacs.c'\"
else
echo shar: Extracting \"'reader/emacs.c'\" \(7822 characters\)
sed "s/^X//" >'reader/emacs.c' <<'END_OF_FILE'
X/*
X * emacs		- an "emacs" style single line editor for reader
X *
X * Dave Clemans, 4/84 (initial version); 1/89 (more generality)
X *
X * Commands supported:
X *	kill line	users kill character
X *	erase char	users erase character
X *	next line	^N
X *	prev line	^P
X *	forward		^F
X *	backward	^B
X *	delete		^D
X *	beginning line	^A
X *	end of line	^E
X *	retype line	^L
X *	uppercase char	^C
X *	transpose chars	^T
X *	reverse search	^R
X *	forwards search	^S
X *	kill to end	^K
X *	mark		^@
X *	delete region	^W
X *	yank region	^Y
X *	quote char	^Q
X *	erase char	DEL
X *	kill next word	ESC d
X *	kill prev word	ESC ^H
X *	kill prev word	ESC DEL
X *	expand name	ESC ESC
X *	next word	ESC f
X *	prev word	ESC b
X *	uppercase char	ESC c
X *	uppercase word	ESC C
X *	list expand	ESC ^L
X *	mark		ESC SPACE
X *	copy region	ESC p
X *	yank region	ESC y
X *	delete line	ESC ^K
X *	delete line	ESC ^U
X *	switch mark	^X^X
X *	arg mult	^U
X *	set arg		ESC digits
X *
X * If we return 0, we did not handle the input character; it should be
X * handled by the standard editor.
X * If we return <0, signal end-of-file.
X * Otherwise the character has been
X * handled and the next character can be read.
X *
X * $Id: emacs.c,v 1.2 89/02/20 20:20:12 dclemans Exp $
X *
X * $Log:	emacs.c,v $
X * Revision 1.2  89/02/20  20:20:12  dclemans
X * Add RCS identifiers
X * 
X */
X#include <ctype.h>
X#ifndef GEMDOS
X#include <sgtty.h>
X#endif  GEMDOS
X
X#include "history.h"
X
X/*
X * A marked point in a line; corresponds to a cursor position
X */
Xstatic short int markedPoint = -1;
X
X/*
X * For numerical arguments
X */
Xstatic int argument = 1;
Xstatic int argumentMultiplier = 1;
X
X/*
X * Check for "emacs" style commands
X */
Xint _doEmacs(c)
Xregister char c;
X{
X	register int counter,saveCursor;
X
X#ifndef GEMDOS
X	if (c == _savedState.basicAttributes.sg_erase)
X	{	/* erase character */
X		for (counter = 0; counter < argument*argumentMultiplier; counter++)
X			_doStandardErase(c);
X		argument = argumentMultiplier = 1;
X		return(1);
X	}
X#endif  GEMDOS
X	switch(c)
X	{	/* check to see if we know this command */
X#ifdef  GEMDOS
X            case '\010':
X#endif  GEMDOS
X	    case '\177':	/* erase character */
X		_doStandardErase(c);
X		break;
X	    case '\000':	/* mark current position */
X		markedPoint = History.currentLine->cursor;
X		break;
X	    case '\016':	/* next line */
X		for (counter = 0; counter < argument*argumentMultiplier; counter++)
X			_doStandardNextLine(c);
X		break;
X	    case '\020':	/* prev line */
X		for (counter = 0; counter < argument*argumentMultiplier; counter++)
X			_doStandardPrevLine(c);
X		break;
X	    case '\006':	/* forward */
X		for (counter = 0; counter < argument*argumentMultiplier; counter++)
X			_doStandardSpace(c);
X		break;
X	    case '\002':	/* backward */
X		for (counter = 0; counter < argument*argumentMultiplier; counter++)
X			_doStandardBackspace(c);
X		break;
X	    case '\004':	/* delete */
X		for (counter = 0; counter < argument*argumentMultiplier; counter++)
X			_doStandardDelete(c);
X		break;
X	    case '\001':	/* beginning of line */
X		_doStandardStartLine(c);
X		break;
X	    case '\005':	/* end of line */
X		_doStandardEndLine(c);
X		break;
X	    case '\014':	/* retype line */
X		_doStandardRetype(c);
X		break;
X	    case '\003':	/* capitalize character */
X		_doStandardCapitalize(c);
X		break;
X	    case '\024':	/* transpose characters */
X		_doStandardTranspose(c);
X		break;
X	    case '\022':	/* backwards search */
X		_doStandardSrchPrevLine(c,0);
X		break;
X	    case '\023':	/* forwards search */
X		_doStandardSearchNextLine(c,0);
X		break;
X	    case '\013':	/* kill to end of line */
X		_doStandardDelEndLine(c);
X		break;
X	    case '\027':	/* delete region */
X		doEmacsDeleteRegion();
X		break;
X	    case '\031':	/* yank region */
X		_popOffKillRing();
X		break;
X	    case '\021':	/* quote character */
X		if (_savedState.stream < 0)
X			return(0);
X		c = _readchar(_savedState.stream);
X		if (c == EOF)
X			return(-1);
X		_doStandardCharacter(c);
X		break;
X	    case '\025':	/* set arg multiplier to 4 */
X		argumentMultiplier = 4;
X		return(1);
X	    case '\033':	/* prefix character */
X		if (_savedState.stream < 0)
X			return(0);
X		c = _readchar(_savedState.stream);
X		if (c == EOF)
X			return(-1);
X		if (isdigit(c))
X		{	/* supplying argument? */
X			argument = 0;
X			for (; isdigit(c); c = _readchar(_savedState.stream))
X			{	/* build argument value */
X				argument *= 10;
X				argument += (int)((int)c - (int)'0');
X			}
X			if (c == EOF)
X				return(-1);
X			_savechar(c);
X			return(1);
X		}
X		switch (c)
X		{		/* a meta command? */
X		    case 'd':	/* delete next word */
X			_deleteNextStdWord();
X			break;
X		    case 'C':	/* capitalize next word */
X			_capitalizeStdWord();
X			break;
X		    case 'c':	/* capitalize next char */
X			_doStandardCapitalize(c);
X			break;
X		    case '\010': /* delete previous word */
X		    case '\177': /* delete previous word */
X			_deletePrevStdWord();
X			break;
X		    case '\033': /* expand command or filename */
X			_doStandardExpand(c);
X			break;
X		    case 'f':	/* space forward over a word */
X			_spaceNextStdWord();
X			break;
X		    case 'b':	/* space backward over a word */
X			_spacePrevStdWord();
X			break;
X		    case '\014': /* list command or filename expansion possibilities */
X			ExpandAName(History.currentLine->contents,
X				sizeof(History.currentLine->contents)-1,
X				History.currentLine->size, 0);
X			break;
X		    case ' ':	/* mark point */
X			markedPoint = History.currentLine->cursor;
X			break;
X		    case 'p':	/* copy region */
X			if (!isMarkValid())
X			{	/* a good mark? */
X				_writechar('\007');
X				break;
X			}
X			_pushOnKillRing(markedPoint,History.currentLine->cursor);
X			markedPoint = -1;
X			break;
X		    case 'y':	/* yank region */
X			_popOffKillRing();
X			break;
X		    case '\013': /* kill line */
X		    case '\025': /* kill line */
X			_doStandardKill(c);
X			break;
X		    default:	/* unknown */
X			_writechar('\007');
X			break;
X		}
X		break;
X	    case '\030':	/* other prefix character */
X		if (_savedState.stream < 0)
X			return(0);
X		c = _readchar(_savedState.stream);
X		if (c == EOF)
X			return(-1);
X		switch (c)
X		{		/* a prefix command? */
X		    case '\030':/* switch mark and point */
X			if ((markedPoint < 0) || (markedPoint > History.currentLine->size))
X			{	/* no mark */
X				_writechar('\007');
X				break;
X			}
X			saveCursor = History.currentLine->cursor;
X			if (saveCursor < markedPoint)
X			{	/* need to move forward */
X				while (History.currentLine->cursor < markedPoint)
X					_doStandardSpace('\000');
X			}
X			else if (saveCursor > markedPoint)
X			{	/* need to move backward */
X				while (History.currentLine->cursor > markedPoint)
X					_doStandardBackspace('\000');
X			}
X			markedPoint = saveCursor;
X			break;
X		    default:	/* unknown */
X			_writechar('\007');
X			break;
X		}
X		break;
X	    default:		/* we don't know this command */
X		return(0);
X	}
X	argument = argumentMultiplier = 1;
X	return(1);
X};	/* end of _doEmacs */
X
X/*
X * Delete region from mark to point
X */
Xstatic doEmacsDeleteRegion()
X{
X	register int counter,size;
X
X	if (!isMarkValid())
X	{	/* not marked */
X		_writechar('\007');
X		return;
X	}
X
X	_pushOnKillRing(markedPoint,History.currentLine->cursor);
X
X	if (markedPoint < History.currentLine->cursor)
X	{	/* a normal region */
X		size = History.currentLine->cursor - markedPoint + 1;
X		while (History.currentLine->cursor > markedPoint)
X			_doStandardBackspace('\000');
X		for (counter = 0; counter < size; counter++)
X			_doStandardDelete('\000');
X		markedPoint = -1;
X		return;
X	}
X
X	size = markedPoint - History.currentLine->cursor + 1;
X	for (counter = 0; counter < size; counter++)
X		_doStandardDelete('\000');
X	markedPoint = -1;
X};	/* end of doEmacsDeleteRegion */
X
X/*
X * Is the current mark valid? (i.e., does it exist and within the current
X * line?)
X */
Xstatic int isMarkValid()
X{
X	if (markedPoint < 0)
X		return(0);
X	if (History.currentLine->size < markedPoint)
X		return(0);
X	return(1);
X};	/* end of isMarkValid */
END_OF_FILE
if test 7822 -ne `wc -c <'reader/emacs.c'`; then
    echo shar: \"'reader/emacs.c'\" unpacked with wrong size!
fi
# end of 'reader/emacs.c'
fi
if test -f 'reader/history.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'reader/history.h'\"
else
echo shar: Extracting \"'reader/history.h'\" \(2057 characters\)
sed "s/^X//" >'reader/history.h' <<'END_OF_FILE'
X/*
X * Data structures for keeping and referencing a "history" of lines
X * input from a user.
X *
X * Dave Clemans, 4/84 (initial version); 1/89 (more generality)
X *
X * Interesting globals:
X *	History:		general structure for "history" information
X *	History.maxSize		maximum number of lines in history list
X *	History.currentSize	current number of lines in history list
X *	History.listTop		top of list of history lines
X *	History.listBottom	bottom of list of history lines
X *	History.currentLine	current entry in history list
X *				if reader is called, a copy of what it
X *				returns will be pointed at by this
X *
X * $Id: history.h,v 1.5 89/02/20 20:20:14 dclemans Exp $
X *
X * $Log:	history.h,v $
X * Revision 1.5  89/02/20  20:20:14  dclemans
X * Add RCS identifiers
X * 
X */
X#ifndef DEFAULT_MAXSIZE
X#define	DEFAULT_MAXSIZE		16	/* Default History.maxSize */
X#endif  DEFAULT_MAXSIZE
X#define	HISTORY_BUFFER		512	/* Sizeof a history line */
X
X#include <stdio.h>
X
Xstruct historyLine
X{
X	char contents[HISTORY_BUFFER];
X	short int size;
X	short int cursor;
X	short int ttycursor;
X	int command;
X	struct historyLine *next;
X};
X
Xextern struct History
X{
X	int maxSize;
X	int currentSize;
X	int currentCommand;
X	struct historyLine *listTop;
X	struct historyLine *listBottom;
X	struct historyLine *listPointer;
X	struct historyLine *currentLine;
X} History;
X
X/*
X * The users "state"; tty attributes, control characters, etc.
X */
Xextern struct	savedState
X{
X	short int stream;
X#ifndef GEMDOS
X	struct sgttyb basicAttributes;
X	struct tchars basicCharacters;
X#endif  GEMDOS
X	short int localAttributes;
X#ifndef GEMDOS
X	struct ltchars localCharacters;
X#endif  GEMDOS
X	char *localEditor;
X	short int isEmacs;
X	short int isVi;
X	int sigint;
X	int sigquit;
X	int sigtstp;
X} _savedState;
Xextern struct	newState
X{
X#ifndef GEMDOS
X	struct sgttyb basicAttributes;
X	struct tchars basicCharacters;
X#endif  GEMDOS
X	short int localAttributes;
X#ifndef GEMDOS
X	struct ltchars localCharacters;
X#endif  GEMDOS
X} _newState;
X
X#define	EOF	(-1)		/* end of file */
X#define	TTY	2		/* file descriptor for tty access */
END_OF_FILE
if test 2057 -ne `wc -c <'reader/history.h'`; then
    echo shar: \"'reader/history.h'\" unpacked with wrong size!
fi
# end of 'reader/history.h'
fi
if test -f 'reader/killring.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'reader/killring.c'\"
else
echo shar: Extracting \"'reader/killring.c'\" \(2265 characters\)
sed "s/^X//" >'reader/killring.c' <<'END_OF_FILE'
X/*
X * killring		- implement a simple kill ring for reader
X *
X * Dave Clemans, 4/84 (initial version); 1/89 (more generality)
X *
X * Entry points:
X *	_pushOnKillRing		push string on kill ring
X *	_popOffKillRing		pull string off onto pendingInput buffer
X *
X * $Id: killring.c,v 1.2 89/02/20 20:20:16 dclemans Exp $
X *
X * $Log:	killring.c,v $
X * Revision 1.2  89/02/20  20:20:16  dclemans
X * Add RCS identifiers
X * 
X */
X#ifndef GEMDOS
X#include <sgtty.h>
X#endif  GEMDOS
X#ifndef LOC
X#define LOC(r)  __FILE__,r,__LINE__
X#endif  LOC
X
X#include "history.h"
X
X/*
X * The kill ring
X */
X#define	MAX_RING	4
Xstruct	killRingElement
X{
X	char *contents;
X	short int size;
X};
Xstatic struct killRingElement killRing[MAX_RING];
Xstatic int nextKillRing;
X
X/*
X * Push a string onto the kill ring
X *
X * The string body comes from the global History.currentLine
X */
X_pushOnKillRing(first,last)
Xint first;
Xint last;
X{
X	register int temp;
X	register char *in,*out;
X
X	if (killRing[nextKillRing].contents)
X	{	/* re-using an old element */
X		free(killRing[nextKillRing].contents);
X		killRing[nextKillRing].contents = (char *)NULL;
X	}
X	if (first > last)
X	{	/* given in wrong order; swap around to be nice */
X		temp = last;
X		last = first;
X		first = temp;
X	}
X	killRing[nextKillRing].size = last - first + 1;
X	killRing[nextKillRing].contents =
X		(char *)malloc(killRing[nextKillRing].size+1);
X	if (!killRing[nextKillRing].contents)
X	{	/* out of core */
X		errmsg(-1,LOC("pushOnKillRing"));
X		exit(-1);
X	}
X	temp = killRing[nextKillRing].size;
X	in = &History.currentLine->contents[first];
X	out = killRing[nextKillRing].contents;
X	while (temp--)
X		*out++ = *in++;
X	nextKillRing++;
X	if (nextKillRing >= MAX_RING)
X		nextKillRing = 0;
X};	/* end of _pushOnKillRing */
X
X/*
X * Pop the top string off the kill ring into the pending input buffer
X */
X_popOffKillRing()
X{
X	register int counter,size;
X	register char *p;
X
X	nextKillRing--;
X	if (nextKillRing < 0)
X		nextKillRing = MAX_RING - 1;
X	p = killRing[nextKillRing].contents;
X	if (!p)
X	{	/* nothing there */
X		_writechar('\007');
X		return;
X	}
X	size = killRing[nextKillRing].size;
X	for (counter = 0; counter < size; counter++)
X		_savechar(*p++);
X	free(killRing[nextKillRing].contents);
X	killRing[nextKillRing].contents = (char *)NULL;
X};	/* end of popOffKillRing */
END_OF_FILE
if test 2265 -ne `wc -c <'reader/killring.c'`; then
    echo shar: \"'reader/killring.c'\" unpacked with wrong size!
fi
# end of 'reader/killring.c'
fi
if test -f 'reader/makefile.st' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'reader/makefile.st'\"
else
echo shar: Extracting \"'reader/makefile.st'\" \(751 characters\)
sed "s/^X//" >'reader/makefile.st' <<'END_OF_FILE'
X#
X# Makefile for the "reader" "get a line with editing" package
X#
X# $Id: makefile.st,v 1.2 89/02/20 20:20:19 dclemans Exp $
X#
X# $Log:	makefile.st,v $
X# Revision 1.2  89/02/20  20:20:19  dclemans
X# Add RCS identifiers
X# 
X
XCFLAGS	= -O -VPEEP -VPSTR -DGEMDOS=1 -I..
X
XOBJS	= reader.o editing.o tenex.o emacs.o vi.o killring.o words.o
X
Xtester.tos: libreader.a tester.o
X	$(CC) -o $@ tester.o libreader.a ..\ndir.o ..\wild.o
X
Xlibreader.a: $(OBJS)
X	ar rv $@ $(OBJS)
X
Xclean:
X	rm -f $(OBJS) make.log tester tester.o
X
Xdistribution: clean
X	rm -f libreader.a
X
Xtester.o:	tester.c history.h
X
Xreader.o:	reader.c history.h
X
Xediting.o:	editing.c history.h
X
Xemacs.o:	emacs.c history.h
X
Xvi.o:		vi.c history.h
X
Xkillring.o:	killring.c history.h
X
Xwords.o:	words.c history.h
END_OF_FILE
if test 751 -ne `wc -c <'reader/makefile.st'`; then
    echo shar: \"'reader/makefile.st'\" unpacked with wrong size!
fi
# end of 'reader/makefile.st'
fi
if test -f 'reader/makefile.unx' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'reader/makefile.unx'\"
else
echo shar: Extracting \"'reader/makefile.unx'\" \(714 characters\)
sed "s/^X//" >'reader/makefile.unx' <<'END_OF_FILE'
X#
X# Makefile for the "reader" "get a line with editing" package
X#
X# $Id: makefile.unx,v 1.2 89/02/20 20:20:21 dclemans Exp $
X#
X# $Log:	makefile.unx,v $
X# Revision 1.2  89/02/20  20:20:21  dclemans
X# Add RCS identifiers
X# 
X
XCFLAGS	= -O -I..
X
XOBJS	= reader.o editing.o tenex.o emacs.o vi.o killring.o words.o
X
Xtester: libreader.a tester.o
X	$(CC) -o $@ tester.o libreader.a ../wild.o
X
Xlibreader.a: $(OBJS)
X	ar rv $@ $(OBJS)
X
Xclean:
X	rm -f $(OBJS) make.log tester tester.o
X
Xdistribution: clean
X	rm -f libreader.a
X
Xtester.o:	tester.c history.h
X
Xreader.o:	reader.c history.h
X
Xediting.o:	editing.c history.h
X
Xemacs.o:	emacs.c history.h
X
Xvi.o:		vi.c history.h
X
Xkillring.o:	killring.c history.h
X
Xwords.o:	words.c history.h
END_OF_FILE
if test 714 -ne `wc -c <'reader/makefile.unx'`; then
    echo shar: \"'reader/makefile.unx'\" unpacked with wrong size!
fi
# end of 'reader/makefile.unx'
fi
if test -f 'reader/tester.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'reader/tester.c'\"
else
echo shar: Extracting \"'reader/tester.c'\" \(3781 characters\)
sed "s/^X//" >'reader/tester.c' <<'END_OF_FILE'
X/*
X * $Id: tester.c,v 1.6 89/03/07 19:37:46 dclemans Exp $
X *
X * $Log:	tester.c,v $
X * Revision 1.6  89/03/07  19:37:46  dclemans
X * make work on bsd systems
X * 
X * Revision 1.5  89/02/20  20:20:28  dclemans
X * Add RCS identifiers
X * 
X */
X#ifndef GEMDOS
X#include <sgtty.h>
X#endif  GEMDOS
X
X#include "history.h"
X
Xmain()
X{
X	char buffer[1024];
X	int rc;
X	int count;
X	struct historyLine *hp;
X
X	for (count = 1; ; count++)
X	{
X		printf("%d-> ",count);
X		fflush(stdout);
X		rc = Reader(fileno(stdin),buffer,sizeof buffer - 1);
X		if (rc <= 0)
X		{	/* check for error or eof */
X            printf("\r\n");
X			break;
X		}
X		printf("\r\nline %d: %s\n",count,buffer);
X		printf("History list:\r\n");
X		for (hp = History.listTop; hp; hp = hp->next)
X			if (hp->command)
X				printf("\t%d:\t%s\n",hp->command,hp->contents);
X	}
X};
X
X#ifdef  GEMDOS
X#define	ESCAPE_CHAR	'@'
X#else
X#define ESCAPE_CHAR '\\'
X#endif  /* GEMDOS */
X#define	SHERR_NOMEM	-1
X#ifndef LOC
X#define LOC(r)  __FILE__,r,__LINE__
X#endif  LOC
X
Xlong io_savestring()
X{
X	return 0L;
X}
X
Xlong phrase_free()
X{
X	return 0L;
X}
X
Xlong lex_token()
X{
X	return 0L;
X}
X
Xchar *var_arg0 = "tester";
X
Xstruct token
X{
X    int type;
X    struct token *next;
X    char name[4];
X};
X
Xstruct token *new_token(len)
Xint len;
X{
X    register struct token *tp;
X
X    tp = (struct token *)malloc(sizeof(*tp)+len);
X    if (tp == (struct token *)NULL)
X        return (struct token *)NULL;
X    tp->next = (struct token *)NULL;
X    tp->type = -1;
X    tp->name[0] = '\0';
X
X    return tp;
X}   /* end of new_token */
X
Xint errmsg(code,file,routine,line,fmt,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9)
Xint code;
Xchar *file;
Xchar *routine;
Xint line;
Xchar *fmt;
X{
X    extern int errno;
X    char buffer[BUFSIZ];
X    char *p;
X    int fd;
X
X    fd = 1;
X    sprintf(buffer,"%s: %s(%s,%d): ",var_arg0,file,routine,line);
X    for (p = buffer; *p; p++)
X        /* do nothing */;
X    switch (code)
X    {   /* check for common err messages; else do normal one */
X        case -1:
X            strcpy(p,"out of memory");
X            break;
X        default:
X            sprintf(p,fmt,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9);
X            break;
X    }
X    while (*p)
X        p++;
X#ifdef  GEMDOS
X    *p++ = '\r';
X#endif  GEMDOS
X    *p++ = '\n';
X    *p = '\0';
X    write(fd,buffer,(unsigned)strlen(buffer));
X    return 0;
X}   /* end of errmsg */
X
Xchar *strcopy(s)
Xchar *s;
X{
X    char *ns;
X
X    ns = (char *)malloc(strlen(s)+1);
X    if (ns == (char *)NULL)
X    {   /* enough memory? */
X        errmsg(SHERR_NOMEM,LOC("strcopy"));
X        return ns;
X    }
X    strcpy(ns,s);
X    return ns;
X}   /* end of strcopy */
X
Xchar *new_string(len)
Xint len;
X{
X    register char *cp;
X
X    cp = (char *)malloc(len);
X    if (cp == (char *)NULL)
X        return (char *)NULL;
X    *cp = '\0';
X
X    return cp;
X}   /* end of new_string */
X
Xvoid stripquotes(s)
Xchar *s;
X{
X    char *p;
X
X    for (p = s; *p != '\0'; p++)
X    {   /* check for special chars */
X        switch (*p)
X        {   /* a special char? */
X            case '\'':
X            strcpy(p,p+1);
X            while (*p && *p != '\'')
X                p++;
X            if (*p == '\'')
X                strcpy(p,p+1);
X            break;
X            case '"':
X            strcpy(p,p+1);
X            while (*p && *p != '"')
X            {   /* scan the string */
X                if (*p == ESCAPE_CHAR)
X                    strcpy(p,p+1);
X                p++;
X            }
X            if (*p == '"')
X                strcpy(p,p+1);
X            break;
X            case ESCAPE_CHAR:
X            strcpy(p,p+1);
X            break;
X            default:
X            break;
X        }
X    }
X}   /* end of stripquotes */
X
Xchar *var_normal(name)
Xchar *name;
X{
X	char *p;
X	extern char *getenv();
X
X	p = getenv(&name[1]);
X	if (p == (char *)NULL)
X		return p;
X	return strcopy(p);
X}
X
Xstruct
X{
X	long x;
X} base_env;
END_OF_FILE
if test 3781 -ne `wc -c <'reader/tester.c'`; then
    echo shar: \"'reader/tester.c'\" unpacked with wrong size!
fi
# end of 'reader/tester.c'
fi
if test -f 'version.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'version.c'\"
else
echo shar: Extracting \"'version.c'\" \(638 characters\)
sed "s/^X//" >'version.c' <<'END_OF_FILE'
X/*
X * Command Input Shell
X * Dave Clemans
X * 12/88-1/89
X *
X * "spiritually" based on Bourne, Korn shells
X *
X * What version is this...
X *
X * $Id: version.c,v 1.7 89/03/07 19:39:00 dclemans Exp $
X *
X * $Log:	version.c,v $
X * Revision 1.7  89/03/07  19:39:00  dclemans
X * bump date
X * 
X * Revision 1.6  89/02/20  22:33:46  dclemans
X * Bump to next version number.
X * 
X * Revision 1.5  89/02/20  20:30:21  dclemans
X * More RCS ID additions
X * 
X * Revision 1.4  89/02/20  20:05:55  dclemans
X * Add RCS identifiers
X * 
X */
X#include <stdio.h>
X#include "shell.h"
X
Xchar    shell_version[] = "Shell Version 0.3 (dgc); $Date: 89/03/07 19:39:00 $";
END_OF_FILE
if test 638 -ne `wc -c <'version.c'`; then
    echo shar: \"'version.c'\" unpacked with wrong size!
fi
# end of 'version.c'
fi
echo shar: End of archive 1 \(of 11\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 11 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0



More information about the Alt.sources mailing list