[comp.sources.misc] v03i036: mg 2a part 12 of 15

BLARSON@ECLA.USC.EDU (Bob Larson) (05/26/88)

comp.sources.misc: Volume 3, Issue 36
Submitted-By: "Bob Larson" <BLARSON@ECLA.USC.EDU>
Archive-Name: mg2a/Part12

#	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:
#	sys/atari/readme.1st
#	sys/atari/alloc.c
#	sys/atari/build.g
#	sys/atari/cinfo.c
#	sys/atari/diredsup.c
#	sys/atari/fileio.c
#	sys/atari/gemstart.s
#	sys/atari/getn.s
#	sys/atari/makesys.mwc
#	sys/atari/mg.ini
#	sys/atari/mglink.inp
#	sys/atari/misc.c
#	sys/atari/sysdef.h
#	sys/atari/term.c
#	sys/atari/ttydef.h
#	sys/atari/ttyio.c
#	sys/atari/varargs.h
# This archive created: Mon May 23 18:14:08 1988
# By:	blarson
if test -d sys
then true
else mkdir sys
fi
if test -d sys/atari
then true
else mkdir sys/atari
fi
cat << \SHAR_EOF > sys/atari/readme.1st
This file documents the Atari-specific features of MG2A.  Please refer
to the MG manual and the tutorial for more general information about
how to use MG.

This version of MG has been brought to you by....

	Sandra Loosemore (sandra@cs.utah.edu, utah-cs!sandra)
	Marion Hakanson (hakanson@cs.orst.edu, orstcs!hakanson)



Keyboard Handling:
------------------

The ALT key acts as the META key.  The command meta-key-mode can be 
used to toggle this behavior.  (On non-US keyboards, the ALT key is 
normally used as a modifier with certain other keys to produce printing 
characters.)

MG supports 8-bit characters, although since neither of us have
European keyboards we have not been able to test this thoroughly.

The function keys may be bound to commands, although there are no 
default bindings established for these keys.  F1-F10 are as on the 
keyboard, F11-F20 are the shifted F1-F10, and F21-F28 are Help, Undo, 
Insert, Up, Clr/Home, Left, Down, and Right, respectively.


Startup Files:
--------------

MG looks for its startup file first as MG.INI in the current directory,
and it then looks for the file specified by the environment variable
MGINIT if that fails.  The code to look up the environment variables
checks for all of the various environment styles that are supported
by common shells such as the MWC shell and Gulam, as well as the one
built for the desktop by GEMBOOT.


Spawning a Shell:
-----------------

The suspend-emacs command checks the SHELL environment variable to
determine what program to run.  If the environment variable is not
set, or if the attempt to execute the program fails (i.e., the program
is not found), MG will prompt for a command to execute.


Other Options:
--------------

Most of the optional features described in the MG manual are enabled,
including the GOSMACS and DIRED features.  The major piece of missing
functionality is the regular expression code, which is nonportable and
won't compile on the ST.  There is also no support for backup files yet.


Rebuilding MG:
--------------

MG has been developed using both the Alcyon (v4.14) and Mark Williams 
(v2.0) C compilers.  Makefiles (maketop.mwc and makesys.mwc) are provided 
for MWC, and a Gulam shell script (build.g, also mglink.inp) for Alcyon.  
You may need to tweak these files if you have moved things around.

Here is a list of the ST-specific source files:

	chrdef.h	Character macro definition file
	sysdef.h	ST-specific definitions
	ttydef.h	More ST-specific definitions
	varargs.h       Definitions for varargs macros
	alloc.c		New "malloc" for Alcyon C, also used by MWC.
	cinfo.c		Character functions.
	diredsup.c	Functions to support the "cd" and "dired" features.
	fileio.c	File i/o functions.
	misc.c		Functions to support "spawn", etc.
	term.c		High-level screen manipulation functions.
	ttyio.c		Low-level terminal i/o functions.
	getn.s		Functions to determine screen resolution.
	gemstart.s      Needed for Alcyon C


Changes since MG1B:
-------------------

File and terminal i/o have been completely rewritten to use low-level
GemDOS functions instead of their C equivalents.  It's now much faster.

Improved memory management (new implementation of "malloc" and friends
for Alcyon C) makes the "spawn" command more useful.

The use of the ALT key as a meta key and support for 8-bit characters is
new.

The old "dirlist" function has been replaced by dired mode.

Environment variables are now used to specify the startup file and the
shell to run for suspend-emacs.

A few minor cleanups and optimizations, some of which speed things
up markedly.


Bugs
----

There is a bug in TOS that may result in MG creating multiple copies of
files with the same name.  It only seems to happen with very short files.

There has been some question raised about the use of the "conterm"
system variable on the "new" (Mega-ST) TOS ROMs, even though such use
is documented in the MWC manual, and elsewhere.  Perhaps someone can
test this code on such a system and let us know if there are problems.
A workaround would be to use Getshifts() separately, instead of having
the kbshift value returned by Bconin().

SHAR_EOF
cat << \SHAR_EOF > sys/atari/alloc.c
/* alloc.c -- replacement malloc and friends
 *
 * author :  Sandra Loosemore
 * date   :  24 Oct 1987
 *
 * This file is a replacement for the usual definitions of malloc and free.
 * The ST Malloc routine is called to get more memory from the system.
 * Note that the memory that is Malloc'ed is never Mfree'd.
 *
 */


#include <osbind.h>
#define NULL 0L


/* This is the default size for grabbing memory from the system with Malloc.
 *	If you try to malloc a piece bigger than this, it will Malloc a
 *	piece exactly the right size.  Ideally, it should be quite a bit
 *	larger than the average size of things you are allocating (assuming
 *	you are going to allocate lots of them).
 */

static long mchunk = 16384L;           /* Size for grabbing memory */


/* Each call to malloc returns a chunk; freeing it puts the chunk on
 *	the free list.  The "next" field is only used for freed blocks.
 *      The "nbytes" field is the size of the body of the chunk, not
 *	the entire chunk.
 */

typedef struct chunk {
    long nbytes;
    union {
        struct chunk *next;
        char body[1];
        } info;
    } CHUNK;

#define Nbytes(c) (c)->nbytes
#define Next(c) (c)->info.next
#define Body(c) (c)->info.body

static CHUNK *freelist = NULL;


/* Return a block at least "size" bytes long.  Grab more memory if there
 * 	isn't anything on the free list that big.  If the block is just big
 * 	enough, remove it from the free list and return the whole thing.
 *	Otherwise, carve a piece off the front.
 * Note that the size is rounded up to make it an even number, and it must
 *	also be at least big enough to hold the next pointer when the block
 *	is freed.
 */

char *alloc (size)
    long size;
{   register CHUNK *this, *last, *new;
    long temp;
    size = (size + 1) & 0xfffe;			           /* Word alignment */
    if (size < sizeof(CHUNK *))  size = sizeof(CHUNK *);   /* Minimum size */
    this = freelist;
    last = NULL;
    while (this != NULL)  {
        if (Nbytes(this) >= size)  break;
        last = this;
        this = Next(this);
        }
    if (this == NULL)  {
        temp = ((size < mchunk) ? mchunk : size);
        this = (CHUNK *) Malloc (temp + sizeof(long));
        if (!this)  return(NULL);
        Nbytes(this) = temp;
	free(Body(this));
        this = freelist;
	last = NULL;
	while (this != NULL)  {
            if (Nbytes(this) >= size)  break;
            last = this;
            this = Next(this);
	    }
        }
    temp = Nbytes(this) - size - sizeof(long);
    if (temp <= sizeof(CHUNK))  {               /* Use the whole thing */
        if (last)
	    Next(last) = Next(this);
	else
	    freelist = Next(this);
        return(Body(this));
        }
    else  {                                         /* Grab some off end */
        new = (CHUNK *) ((char *)this + size + sizeof(long));
	Nbytes(new) = temp;
	Next(new) = Next(this);
	if (last)
	    Next(last) = new;
	else
	    freelist = new;
	Nbytes(this) = size;
	return(Body(this));
        }
    }



/* These are the user-accessible entry points */

char *malloc (size)
    unsigned size;
{   return (alloc((long)size));
    }

#if 0	/* calloc not used in mg */
char *calloc (number, size)
    unsigned number, size;
{   return (alloc ((long)number*size));
    }
#endif

char *realloc (oldptr, newsize)
    register char *oldptr;
    unsigned newsize;
{   long oldsize;
    register char *newptr;
    register unsigned i;
    CHUNK *block;
    block = (CHUNK *) (oldptr - sizeof(long));
    oldsize = Nbytes(block);
    if (newsize > oldsize)  {
        newptr = alloc((long)newsize);
        for (i=0; i<oldsize; i++)
	    newptr[i] = oldptr[i];
        free(oldptr);	    
	return(newptr);
        }
    else
        return(oldptr);
    }

    
/* Free a pointer.  The freelist is maintained in sorted order, so loop
 *	through until we find the block on either side of the one we're
 *	freeing.  Then see if we can merge this block with either one.
 */

free (ptr)
    char *ptr;
{   register CHUNK *last, *this, *block;

	/* Find where to insert the block in the free list. */

    block = (CHUNK *)(ptr - sizeof(long));
    this = freelist;
    last = NULL;
    while (this && (this < block))  {
        last = this;
	this = Next(this);
	}

	/* Can we merge it with the next block?  */

    if (this && ((ptr + Nbytes(block)) == this))  {
        Nbytes(block) = Nbytes(block) + Nbytes(this) + sizeof(long);
	Next(block) = Next(this);
	}
    else
        Next(block) = this;

	/* Can we merge it with the previous block?  */

    if (last && ((Body(last) + Nbytes(last)) == block))  {
        Nbytes(last) = Nbytes(last) + Nbytes(block) + sizeof(long);
	Next(last) = Next(block);
        }
    else if (last)
        Next(last) = block;
    else
        freelist = block;
    }


/* A debug routine to help me make sure that the freelist is compacted
 *	properly.
 */

#ifdef DEBUG

dumpfree ()
{   CHUNK *junk;
    printf ("Dump of free list:\n");
    junk = freelist;
    while (junk)  {
        printf ("    Base %ld, size %ld\n", (long)(Body(junk)), Nbytes(junk));
	junk = Next(junk);
	}
    }
#endif
SHAR_EOF
cat << \SHAR_EOF > sys/atari/build.g
# build file for MG using Alcyon C and the GULAM shell
# execute this from the directory sys\atari 
#
#
# First make sure that there are stubs for the include files at top level 
# 
cd ..\..  
if { -e chrdef.h } == 0
    echo '#include "sys\atari\chrdef.h"' > chrdef.h
    endif
if { -e sysdef.h } == 0
    echo '#include "sys\atari\sysdef.h"' > sysdef.h
    endif
if { -e ttydef.h } == 0
    echo '#include "sys\atari\ttydef.h"' > ttydef.h
    endif
if { -e varargs.h } == 0
    echo '#include "sys\atari\varargs.h"' > varargs.h
    endif
#
#
# Recompile all the top-level files
#
cc basic
cc buffer
cc dir
cc dired
cc display
cc echo
cc extend
cc file
cc help
cc kbd
cc keymap
cc line
cc macro
cc main
cc match
cc modes
cc paragrap
cc random
cc re_searc
cc regex
cc region
cc search
cc version
cc window
cc word
#
#
# Now do all of the system-specific ones
#
cd sys\atari
cc alloc
cc cinfo
cc diredsup
cc fileio
cc misc
cc term
cc ttyio
as68 -l -u -s c: gemstart.s
as68 -l -u -s c: getn.s
#
#
# Now do the link
#
aln -c mglink.inp
SHAR_EOF
cat << \SHAR_EOF > sys/atari/cinfo.c
/* cinfo.c -- character class tables for the Atari ST 8-bit character set
 *
 * author :  Sandra Loosemore
 * date   :  26 Oct 1987
 *
 */

#include	"..\..\def.h"

/*
 * This table, indexed by a character drawn
 * from the 256 member character set, is used by my
 * own character type macros to answer questions about the
 * type of a character. It handles the full multinational
 * character set, and lets me ask some questions that the
 * standard "ctype" macros cannot ask.
 */

char cinfo[256] = {
	_C,		_C,		_C,		_C,	/* 0x0X */
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,	/* 0x1X */
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,
	_C,		_C,		_C,		_C,
	0,		_P,		0,		0,	/* 0x2X */
	_W,		_W,		0,		_W,
	0,		0,		0,		0,
	0,		0,		_P,		0,
	_W,		_W,		_W,		_W,	/* 0x3X */
	_W,		_W,		_W,		_W,
	_W,		_W,		0,		0,
	0,		0,		0,		_P,
	0,		_U|_W,		_U|_W,		_U|_W,	/* 0x4X */
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		_U|_W,		_U|_W,	/* 0x5X */
	_U|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		_U|_W,		_U|_W,		0,
	0,		0,		0,		0,
	0,		_L|_W,		_L|_W,		_L|_W,	/* 0x6X */
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		_L|_W,	/* 0x7X */
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		0,
	0,		0,		0,		_C,
	_U|_W,		_L|_W,		_L|_W,		_L|_W,	/* 0x8X */
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_L|_W,		_U|_W,		_U|_W,
	_U|_W,		_L|_W,		_U|_W,		_L|_W,	/* 0x9X */
	_L|_W,		_L|_W,		_L|_W,		_L|_W,
	_L|_W,		_U|_W,		_U|_W,		0,
	0,		0,		_L|_W,		0,
	_L|_W,		_L|_W,		_L|_W,		_L|_W,	/* 0xAX */
	_L|_W,		_U|_W,		_L|_W,		_L|_W,
	0,		0,		0,		0,
	0,		0,		0,		0,
	_L|_W,		_L|_W,		_U|_W,		_L|_W,	/* 0xBX */
	_L|_W,		_U|_W,		_U|_W,		_U|_W,
	_U|_W,		0,		0,		0,
	0,		0,		0,		0,
	_L|_W,		_U|_W,		0,		0,	/* 0xCX */
	0,		0,		0,		0,
	0,		0,		0,		0,
	0,		0,		0,		0,
	0,		0,		0,		0,	/* 0xDX */
	0,		0,		0,		0,
	0,		0,		0,		0,
	0,		0,		0,		0,
	0,		0,		0,		0,	/* 0xEX */
	0,		0,		0,		0,
	0,		0,		0,		0,
	0,		0,		0,		0,
	0,		0,		0,		0,	/* 0xFX */
	0,		0,		0,		0,
	0,		0,		0,		0,
	0,		0,		0,		0
};


/* Convert upper to lower and vice versa.  This is borrowed from
 * Bernhard Nebel.
 */

char cupper[256] = {
	0x00,	0x01,	0x02,	0x03,	0x04,	0x05,	0x06,	0x07,
	0x08,	0x09,	0x0a,	0x0b,	0x0c,	0x0d,	0x0e,	0x0f,
	0x10,	0x11,	0x12,	0x13,	0x14,	0x15,	0x16,	0x17,
	0x18,	0x19,	0x1a,	0x1b,	0x1c,	0x1d,	0x1e,	0x1f,
	0x20,	0x21,	0x22,	0x23,	0x24,	0x25,	0x26,	0x27,
	0x28,	0x29,	0x2a,	0x2b,	0x2c,	0x2d,	0x2e,	0x2f,
	0x30,	0x31,	0x32,	0x33,	0x34,	0x35,	0x36,	0x37,
	0x38,	0x39,	0x3a,	0x3b,	0x3c,	0x3d,	0x3e,	0x3f,
	0x40,	0x41,	0x42,	0x43,	0x44,	0x45,	0x46,	0x47,
	0x48,	0x49,	0x4a,	0x4b,	0x4c,	0x4d,	0x4e,	0x4f,
	0x50,	0x51,	0x52,	0x53,	0x54,	0x55,	0x56,	0x57,
	0x58,	0x59,	0x5a,	0x5b,	0x5c,	0x5d,	0x5e,	0x5f,
	0x40,	0x41,	0x42,	0x43,	0x44,	0x45,	0x46,	0x47,
	0x48,	0x49,	0x4a,	0x4b,	0x4c,	0x4d,	0x4e,	0x4f,
	0x50,	0x51,	0x52,	0x53,	0x54,	0x55,	0x56,	0x57,
	0x58,	0x59,	0x5a,	0x7b,	0x7c,	0x7d,	0x7e,	0x7f,
	0x80,	0x9a,	0x90,	0x41,	0x8e,	0xb6,	0x8f,	0x80,
	0x45,	0x45,	0x45,	0x49,	0x49,	0x49,	0x8e,	0x8f,
	0x90,	0x92,	0x92,	0x4f,	0x99,	0x4f,	0x55,	0x55,
	0x59,	0x99,	0x9a,	0x9b,	0x9c,	0x9d,	0x9e,	0x9f,
	0x41,	0x49,	0x4f,	0x55, 	0xa5,	0xa5,	0x41,	0x4f,
	0xa8,	0xa9,	0xaa,	0xab,	0xac,	0xad,	0xae,	0xaf,
	0xb7,	0xb8,	0xb2,	0xb2,	0xb5,	0xb5,	0xb6,	0xb7,
	0xb8,	0xb9,	0xba,	0xbb,	0xbc,	0xbd,	0xbe,	0xbf,
	0xc1,	0xc1,	0xc2,	0xc3,	0xc4,	0xc5,	0xc6,	0xc7,
	0xc8,	0xc9,	0xca,	0xcb,	0xcc,	0xcd,	0xce,	0xcf,
	0xd0,	0xd1,	0xd2,	0xd3,	0xd4,	0xd5,	0xd6,	0xd7,
	0xd8,	0xd9,	0xda,	0xdb,	0xdc,	0xdd,	0xde,	0xdf,
	0xe0,	0xe1,	0xe2,	0xe3,	0xe4,	0xe5,	0xe6,	0xe7,
	0xe8,	0xe9,	0xea,	0xeb,	0xec,	0xed,	0xee,	0xef,
	0xf0,	0xf1,	0xf2,	0xf3,	0xf4,	0xf5,	0xf6,	0xf7,
	0xf8,	0xf9,	0xfa,	0xfb,	0xfc,	0xfd,	0xfe,	0xff
	};

char clower[256] = {
	0x00,	0x01,	0x02,	0x03,	0x04,	0x05,	0x06,	0x07,
	0x08,	0x09,	0x0a,	0x0b,	0x0c,	0x0d,	0x0e,	0x0f,
	0x10,	0x11,	0x12,	0x13,	0x14,	0x15,	0x16,	0x17,
	0x18,	0x19,	0x1a,	0x1b,	0x1c,	0x1d,	0x1e,	0x1f,
	0x20,	0x21,	0x22,	0x23,	0x24,	0x25,	0x26,	0x27,
	0x28,	0x29,	0x2a,	0x2b,	0x2c,	0x2d,	0x2e,	0x2f,
	0x30,	0x31,	0x32,	0x33,	0x34,	0x35,	0x36,	0x37,
	0x38,	0x39,	0x3a,	0x3b,	0x3c,	0x3d,	0x3e,	0x3f,
	0x60,	0x61,	0x62,	0x63,	0x64,	0x65,	0x66,	0x67,
	0x68,	0x69,	0x6a,	0x6b,	0x6c,	0x6d,	0x6e,	0x6f,
	0x70,	0x71,	0x72,	0x73,	0x74,	0x75,	0x76,	0x77,
	0x78,	0x79,	0x7a,	0x5b,	0x5c,	0x5d,	0x5e,	0x5f,
	0x60,	0x61,	0x62,	0x63,	0x64,	0x65,	0x66,	0x67,
	0x68,	0x69,	0x6a,	0x6b,	0x6c,	0x6d,	0x6e,	0x6f,
	0x70,	0x71,	0x72,	0x73,	0x74,	0x75,	0x76,	0x77,
	0x78,	0x79,	0x7a,	0x7b,	0x7c,	0x7d,	0x7e,	0x7f,
	0x87,	0x81,	0x82,	0x83,	0x84,	0x85,	0x86,	0x87,
	0x88,	0x89,	0x8a,	0x8b,	0x8c,	0x8d,	0x84,	0x86,
	0x82,	0x91,	0x91,	0x93,	0x94,	0x95,	0x96,	0x97,
	0x98,	0x94,	0x81,	0x9b,	0x9c,	0x9d,	0x9e,	0x9f,
	0xa0,	0xa1,	0xa2,	0xa3,	0xa4,	0xa4,	0xa6,	0xa7,
	0xa8,	0xa9,	0xaa,	0xab,	0xac,	0xad,	0xae,	0xaf,
	0xb0,	0xb1,	0xb1,	0xb3,	0xb4,	0xb4,	0x85,	0xb0,
	0xb1,	0xb9,	0xba,	0xbb,	0xbc,	0xbd,	0xbe,	0xbf,
	0xc0,	0xc0,	0xc2,	0xc3,	0xc4,	0xc5,	0xc6,	0xc7,
	0xc8,	0xc9,	0xca,	0xcb,	0xcc,	0xcd,	0xce,	0xcf,
	0xd0,	0xd1,	0xd2,	0xd3,	0xd4,	0xd5,	0xd6,	0xd7,
	0xd8,	0xd9,	0xda,	0xdb,	0xdc,	0xdd,	0xde,	0xdf,
	0xe0,	0xe1,	0xe2,	0xe3,	0xe4,	0xe5,	0xe6,	0xe7,
	0xe8,	0xe9,	0xea,	0xeb,	0xec,	0xed,	0xee,	0xef,
	0xf0,	0xf1,	0xf2,	0xf3,	0xf4,	0xf5,	0xf6,	0xf7,
	0xf8,	0xf9,	0xfa,	0xfb,	0xfc,	0xfd,	0xfe,	0xff
	};
	

/*
 * Find the name of a keystroke.  Needs to be changed to handle 8-bit printing
 * characters and function keys better.	 Returns a pointer to the terminating
 * '\0'.
 */

char *keyname(cp, k)
register char *cp;
register int k;
{
    register char *np;
#ifdef	FKEYS
    extern char *keystrings[];
#endif /* FKEYS */

    if(k<0) k &= 0377;			   /* if char was sign extened */
    switch(k) {
	case CCHR('@'): np = "NUL"; break;
	case CCHR('I'): np = "TAB"; break;
	case CCHR('J'): np = "LFD"; break; /* yuck, but that's what GNU calls it */
	case CCHR('M'): np = "RET"; break;
	case CCHR('['): np = "ESC"; break;
	case ' ':	np = "SPC"; break; /* yuck again */
	case CCHR('?'): np = "DEL"; break;
	default:
#ifdef	FKEYS
	    if(k >= KFIRST && k <= KLAST &&
		    (np = keystrings[k - KFIRST]) != NULL)
		break;
#endif /* FKEYS */
	    if(k > CCHR('?') || k < CCHR('@')) {
		*cp++ = '0';
		*cp++ = ((k>>6)&7) + '0';
		*cp++ = ((k>>3)&7) + '0';
		*cp++ = (k&7) + '0';
		*cp = '\0';
		return cp;
	    }
	    if(k < ' ') {
		*cp++ = 'C';
		*cp++ = '-';
		k += '@';
		if(ISUPPER(k)) k = TOLOWER(k);
	    }
	    *cp++ = k;
	    *cp = '\0';
	    return cp;
    }
    (VOID) strcpy(cp, np);
    return cp + strlen(cp);
}
SHAR_EOF
cat << \SHAR_EOF > sys/atari/diredsup.c
/* diredsup.c -- Atari ST functions for handling DIR and DIRED features
 *
 * author :  Sandra Loosemore
 * date   :  20 Dec 1987
 *
 */

#include "..\..\def.h"


/* ST-specific code to support the DIR features in dir.c
 */

#ifndef NO_DIR

char *getwd (buffer)
    char *buffer;
{   int drive, i;
    drive = Dgetdrv();
    buffer[0] = (char)drive + 'a';
    buffer[1] = ':';
    Dgetpath (&buffer[2], drive+1);
    for (i=2; buffer[i] != '\0'; i++)
        buffer[i] = TOLOWER(buffer[i]);
    return(buffer);
    }

int chdir (buffer)
    char *buffer;
{   int drive;
    if (buffer[1] == ':')  {
        drive = TOLOWER(buffer[0]) - 'a';
	(VOID) Dsetdrv (drive);
	buffer = buffer + 2;
        }
    return ((int)Dsetpath (buffer));
    }

#endif


/* ST-specific code to support the DIRED features in dired.c.
 */

#ifndef NO_DIRED

#include "..\..\kbd.h"


/* Various file manipulation functions.  */

int rename (fromname, toname)
    char *fromname, *toname;
{   if (Frename(0, fromname, toname) == 0)
        return(0);
    else  {
        ewprintf ("Rename failed.");
        return(-1);
	}
    }

int copy (fromname, toname)
    char *fromname, *toname;
{   int from, to, count;
    char buffer[256];
    if ((from = Fopen (fromname, 0)) < 0)  {
        ewprintf ("Could not open input file %s.", fromname);
        return(-1);
        }
    (VOID) Fdelete (toname);
    if ((to = (Fcreate (toname, 0))) < 0)  {
        ewprintf ("Could not open output file %s.", toname);
        Fclose(from);
	return(-1);
        }
    while ((count = Fread(from, (long)256, buffer)) > 0)
        (VOID) Fwrite (to, (long)count, buffer);
    (VOID) Fclose(from);
    (VOID) Fclose(to);
    return(0);
    }

int unlink (fname)
    char *fname;
{   if (Fdelete(fname) == 0)
        return(0);
    else
        return(-1);
    }

int unlinkdir (fname)
    char *fname;
{   if (Ddelete(fname) == 0)
        return(0);
    else
        return(-1);
    }


/* Create a dired buffer for the given directory name.  */

BUFFER *dired_(dirname)
char *dirname;
{
    register BUFFER *bp;
    BUFFER *findbuffer();

	/* Create the dired buffer */

    if ((dirname = adjustname(dirname)) == NULL) {
	ewprintf("Bad directory name");
	return NULL;
        }
    if ((bp = findbuffer(dirname)) == NULL) {
	ewprintf("Could not create buffer");
	return NULL;
        }
    if (bclear(bp) != TRUE) return FALSE;

	/* Now fill it in.  */

    if (!dirlist (bp, dirname))  {
    	ewprintf("Could not read directory");
        return FALSE;
        }

	/* Clean up and return */

    bp->b_dotp = lforw(bp->b_linep);		/* go to first line */
    (VOID) strncpy(bp->b_fname, dirname, NFILEN);
    if((bp->b_modes[0] = name_mode("dired")) == NULL) {
	bp->b_modes[0] = &map_table[0];
	ewprintf("Could not find mode dired");
	return NULL;
        }
    return bp;
    }


/* Take the name from the line in the buffer and make a filename out of it.
 */

d_makename(lp, fn)
register LINE *lp;
register char *fn;
{
    register char *cp;
    register char ch;
    int i;

    if(llength(lp) < 55) return ABORT;
    (VOID) strcpy (fn, curbp->b_fname);
    cp = fn + strlen(fn);
    *cp++ = '\\';
    i = 2;
    while ((ch = lgetc(lp,i)) != ' ')  {
        *cp++ = ch;
	i++;
	}
    *cp = '\0';
    return lgetc(lp, 52) == 'd';
}


/* Here is all the messy code for getting a directory listing.
 *    It is printed out like
 *
 * 0         1         2         3         4         5
 * 01234567890123456789012345678901234567890123456789012345
 *   name----------><-----size  dd-mmm-yyyy  hh:mm:ss  drw
 *
 */

typedef struct dta {
    char junk[21];
    char attrib;
    unsigned int timestamp;
    unsigned int datestamp;
    long filesize;
    char name[14];
    } DTA;

static char* months[] = {
    "???", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", 
    "Aug", "Sep", "Oct", "Nov", "Dec"};


/* Print a number into the character buffer, bumping up the pointer */

static char* printit (str, number, width, fill, zero)
    char* str;
    long number;
    int width;
    char fill;
{   int i;
    if (number == 0)   {
        for (i=1; i<width; i++)
	    *str++ = fill;
        if (width == 0)
            ;
        else if (zero) 
	    *str++ = '0';
        else
	    *str++ = fill;
        return (str);
        }
    else  {
        str = printit (str, (number/10), width-1, fill, FALSE);
        *str++ = (char) ((number%10) + (int) '0');
        return (str);
        }
    }


/* Print a null-terminated string into the buffer */

static char* copyit (to, from, width, fill)
    char *from, *to;
    int width;
    char fill;
{   int i;
    char ch;
    i = 0;
    while (*from != '\0')  {
        ch = *from++;
        *to++ = TOLOWER(ch);
        i++;
	}
    while (i < width)  {
        *to++ = fill;
        i++;
        }
    return (to);
    }


static char* getdate (datestamp, buffer)
    unsigned int datestamp;
    char* buffer;
{   int date, month, year;

    date = datestamp & 31;
    month = (datestamp >> 5) & 15;
    year = (datestamp >> 9) + 1980;
    *buffer++ = ' ';
    *buffer++ = ' ';
    buffer = printit (buffer, (long) date, 2, '0', TRUE);
    *buffer++ = '-';
    buffer = copyit (buffer, months[month], 3, ' ');
    *buffer++ = '-';
    buffer = printit (buffer, (long) year, 4, ' ', TRUE);
    return (buffer);
    }


static char* gettime (timestamp, buffer)
    unsigned int timestamp;
    char* buffer;
{   int second, minute, hour;

    second = (timestamp & 31) * 2;
    minute = (timestamp >> 5) & 63;
    hour = (timestamp >> 11);
    *buffer++ = ' ';
    *buffer++ = ' ';
    buffer = printit (buffer, (long) hour, 2, '0', TRUE);
    *buffer++ = ':';
    buffer = printit (buffer, (long) minute, 2, '0', TRUE);
    *buffer++ = ':';
    buffer = printit (buffer, (long) second, 2, '0', TRUE);
    return (buffer);
    }


static dirlist (bp, dirname)
    BUFFER *bp;
    char *dirname;
{   
    char fname[NFILEN], buf[NFILEN];
    int status;
    DTA my_dta, *old_dta;
    char *bufptr;

    (VOID) strcpy (fname, dirname);
    (VOID) strcat (fname, "\\*.*");
    old_dta = (DTA *) Fgetdta ();
    Fsetdta (&my_dta);
    status = Fsfirst (fname, 0x11);
    while (status == 0)  {
        bufptr = buf;
	*bufptr++ = ' ';
	*bufptr++ = ' ';
        bufptr = copyit (bufptr, my_dta.name, 15, ' ');
        bufptr = printit (bufptr, my_dta.filesize, 10, ' ', TRUE);
        bufptr = getdate (my_dta.datestamp, bufptr);
        bufptr = gettime (my_dta.timestamp, bufptr);
	*bufptr++ = ' ';
	*bufptr++ = ' ';
        *bufptr++ = (my_dta.attrib) ? 'd' : '-';  /* directory */
	*bufptr++ = 'r';
        *bufptr++ = (my_dta.attrib) ? '-' : 'w';  /* read-only */
        *bufptr = '\0';
        if (addline(bp, buf) == FALSE)  {
            Fsetdta (old_dta);
            return (FALSE);
            }
        status = Fsnext ();
        }
    Fsetdta (old_dta);
    return (TRUE);
    }

#endif
SHAR_EOF
cat << \SHAR_EOF > sys/atari/fileio.c
/* fileio.c -- Atari ST file system interface for MG
 *
 * author :  Sandra Loosemore (from an earlier version by dec-rex!conroy)
 * date   :  24 Oct 1987
 * changes:  Marion Hakanson -- Jan 1988
 *
 */
#include	"..\..\def.h"


/* Adjustname regularizes a filename.  This fills in the current drive
 *	and directory onto the front if they are not already provided, and
 *	also lowercases it so a case-sensitive string compare can be used
 *	on filenames.
 * This doesn't do the right things with collapsing "..\" and ".\" -- it
 *      doesn't check for them being embedded in pathnames, only at the
 *	front.  Sigh.
 */

static char adbuffer[128];

char* adjustname (fname)
    char *fname;
{   int i, j, k;
    char pathbuf[128];

    if (fname[1] == ':')  {
        j = 2;
        adbuffer[0] = TOLOWER(fname[0]);
	}
    else  {
        adbuffer[0] = (char)Dgetdrv() + 'a';
        j = 0;
        }
    adbuffer[1] = ':';
    i = 2;
    if (fname[j] != '\\')  {
        Dgetpath(pathbuf, (int)(adbuffer[0] - 'a' + 1));
        for (k=0; pathbuf[k] != '\0'; k++)  {
	    adbuffer[i] = TOLOWER(pathbuf[k]);
	    i++;
	    }
        adbuffer[i] = '\\';
	i++;
        }
    if (fname[j] == '.')  {
        if (fname[j+1] == '.')  {
            i = i - 2;
            while (adbuffer[i] != '\\')  i--;
            j = j + 2;
            }
        else  {
            j = j + 1;
            i = i - 1;
	    }
        }
    while (fname[j] != '\0')  {
        adbuffer[i] = TOLOWER(fname[j]);
        i++;
        j++;
        }
    adbuffer[i] = '\0';
    return(adbuffer);
    }


/* Define some things used later on */

static int handle;
#define RBUFSIZE 512
static char rbuffer[RBUFSIZE];
static int rbufmax, rbufnext, rbufcr;
static int rbufeof;


/* Open and close files.  Store the file handle in "handle".  We'll use 
 *	it later in the routines that read and write to the file.
 */


ffropen (fn)
    char *fn;
{   handle = Fopen(fn, 0);
    if (handle < 0)
        return(FIOFNF);
    else  {
        rbufmax = 0;
        rbufnext = 0;
	rbufcr = FALSE;
	rbufeof = FALSE;
        return(FIOSUC);
	}
    }


ffwopen (fn)
    char *fn;
{   (VOID) Fdelete(fn);
    handle = Fcreate(fn, 0);
    if (handle < 0)  {
	ewprintf("Open of %s failed with error code %d.", fn, handle);
	return (FIOERR);
	}
    else
	return (FIOSUC);
    }
 
ffclose ()
{   (VOID) Fclose(handle);
    return (FIOSUC);
    }


/* Write an entire buffer to the already open file.  The last line of 
 * 	the buffer does not have an implied newline.
 */

static char *crlf = "\r\n";

ffputbuf (buf)
    BUFFER *buf;
{   LINE *line, *last;

    last = buf->b_linep;       /* Header line is empty */
    line = last->l_fp;         /* The first real line */

    while (line->l_fp != last)  {
        if ((Fwrite (handle, (long)line->l_used, line->l_text) < 0) ||
	    (Fwrite (handle, 2l, crlf) < 0))  {
		ewprintf("File write error");
		return (FIOERR);
                }
        line = line->l_fp;
        }
    if (line->l_used > 0)  {
        if (Fwrite (handle, (long)line->l_used, line->l_text) < 0)  {
		ewprintf("File write error");
		return (FIOERR);
                }
        }
    return(FIOSUC);
    }


/* Read a line from the file up to nbuf long.  Set *nbytes to the actual
 *    count read (excluding the end-of-line marker).  Returns:
 *        FIOSUC if all is well.
 *        FIOLONG if no newline was found yet.
 *        FIOEOF on end-of-file.
 *        FIOERR if any random errors happened.
 * The GemDos routine Fread does not break on end-of-line; it will read
 *    however many characters you tell it to.  So we do a little buffering.
 *    Remember that crlf is the line terminator.  Cr's and lf's that appear
 *    by themselves are passed on.
 */


ffgetline (buf, nbuf, nbytes)
    char buf[];
    int nbuf;
    int *nbytes;
{   register int i;
    register char ch;

    for (i=0; i<nbuf; i++)  {
        if (rbufmax == rbufnext)  {
	    if (rbufeof || 
	          ((rbufmax = Fread(handle, (long)RBUFSIZE, rbuffer)) == 0))  {
                (*nbytes) = i;
                return (FIOEOF);
                }
            else if (rbufmax < 0)  {
 	        ewprintf("File read error");
	        return (FIOERR);
                }
	    else  {
		if (rbufmax < RBUFSIZE)  rbufeof = TRUE;
                rbufnext = 0;
		}
            }
        ch = rbuffer[rbufnext];
        rbufnext++;
        if (rbufcr && (ch == '\n'))  {
	    rbufcr = FALSE;
	    (*nbytes) = i-1;
            return (FIOSUC);
            }
        else  {
	    buf[i] = ch;
	    rbufcr = (ch == '\r');
            }
	}
    return (FIOLONG);
    }


#ifndef NO_BACKUP
 
/*
 * Finish this routine when you decide
 * what the right thing to do when renaming a
 * file for backup purposes.
 */

fbackupfile(fname)
char	*fname;
{
	return (TRUE);
}

#endif



#ifndef NO_STARTUP

/* Look for a startup file as MG.INI in the current directory, then for
 *    the file specified by the environment variable MGINIT.
 */

char* startupfile (ignore)
    char *ignore;
{   int handle;
    char *foo;
    extern char *getenv();

    if ((handle = Fopen ("MG.INI", 0)) >= 0)  {
        (VOID) Fclose (handle);
        return("MG.INI");
        }
    else if (((foo = getenv("MGINIT")) != NULL) &&
             ((handle = Fopen (foo, 0)) >= 0))  {
        (VOID) Fclose (handle);
        return(foo);
        }
    else
        return(NULL);
    }

#endif

SHAR_EOF
cat << \SHAR_EOF > sys/atari/gemstart.s
******************************************************************************
*
*	C runtime startup for CP/M-68k.
*
******************************************************************************
*
ltpa=0			* Low TPA address
htpa=4			* High TPA address
lcode=8			* Code segment start
codelen=12		* Code segment length
ldata=16		* Data segment start
datalen=20		* Data segment length
lbss=24			* Bss  segment start
bsslen=28		* Bss  segment length
freelen=32		* free segment length
resvd=36		* Reserved
fcb2=56			* 2nd parsed fcb
fcb1=92			* 1st parsed fcb
command=128		* Command tail
prtstr=9		* Print string BDOS Call
exit=0			* BDOS exit call
.globl	__main
.globl	__exit
.globl	__break
.globl	___cpmrv
.globl	__base
.globl  _sw_
.globl	__sovf


	.globl	_crystal
	.globl	_ctrl_cnts


		.text


*
*  Must be first object file in link statement
*
	move.l	a7,a5		* save a7 so we can get the base page address
	move.l	4(a5),a5	* a5=basepage address
	move.l	a5,__base	* save for C startup
	move.l	$c(a5),d0
	add.l	$14(a5),d0
	add.l	$1c(a5),d0
	add.l	#$2000,d0	* d0=basepage+textlen+datalen+bsslen
*				  (plus room for user stack)
	move.l	d0,d1
	add.l	a5,d1		* compute stack top
	and.l	#-2,d1		* ensure even byte boundary
	move.l	d1,a7		* setup user stack, 1K above end of BSS

	move.l	d0,-(sp)
	move.l	a5,-(sp)
	clr.w	-(sp)		* junk word
	move	#$4a,-(sp)	* return excess storage
	trap	#1
	add.l	#12,sp


		move.l	__base,a0		*	Load C external
		move.l	lbss(a0),a1		*	a1 -> bss region
		adda.l	bsslen(a0),a1		*	a1 -> 1st heap loc

		move.l	a1,__break		*	Put in "break" loc
		lea.l	command(a0),a2		*	a2 -> command line
		move.b	(a2)+,d0		*	d0 = byte count
		andi.l	#$ff,d0			*	clear junk
		move.w	d0,-(a7)		*	push length
		move.l	a2,-(a7)		*	Push commnd
		clr.l	a6			*	Clear frame pointer
		jsr	__main			*	call main routine
		jmp	__exit			*	call "exit"

*
*	For GEMAES calls from AESBIND.ARC or cryslib.o
*
_crystal:
	move.l	4(a7),d1
	move.w	#200,d0
	trap	#2
	rts

*
*	control array for vdibind
*
	.data
    	.even
_ctrl_cnts:			 	*	Application Manager
	.dc.b	0, 1, 0			* func 010		
    	.dc.b	2, 1, 1			* func 011		
    	.dc.b	2, 1, 1 		* func 012		
	.dc.b	0, 1, 1			* func 013		
	.dc.b	2, 1, 1			* func 014		
	.dc.b	1, 1, 1			* func 015		
	.dc.b	0, 0, 0			* func 016		
	.dc.b	0, 0, 0			* func 017		
	.dc.b	0, 0, 0			* func 008		
	.dc.b	0, 1, 0			* func 019		
*							 Event Manager
	.dc.b	0, 1, 0			* func 020		
	.dc.b	3, 5, 0			* func 021		
	.dc.b	5, 5, 0			* func 022		
	.dc.b	0, 1, 1			* func 023		
	.dc.b	2, 1, 0			* func 024		
	.dc.b	16, 7, 1 		* func 025		
	.dc.b	2, 1, 0			* func 026		
	.dc.b	0, 0, 0			* func 027		
	.dc.b	0, 0, 0			* func 028		
	.dc.b	0, 0, 0			* func 009		
*							 Menu Manager
	.dc.b	1, 1, 1			* func 030		
	.dc.b	2, 1, 1			* func 031		
	.dc.b	2, 1, 1			* func 032		
	.dc.b	2, 1, 1			* func 033		
	.dc.b	1, 1, 2			* func 034		
	.dc.b	1, 1, 1			* func 005		
	.dc.b	0, 0, 0			* func 006		
	.dc.b	0, 0, 0			* func 007		
	.dc.b	0, 0, 0			* func 008		
	.dc.b	0, 0, 0			* func 009		
*							 Object Manager
	.dc.b	2, 1, 1			* func 040		
	.dc.b	1, 1, 1			* func 041		
  	.dc.b	6, 1, 1			* func 042		
	.dc.b	4, 1, 1			* func 043		
	.dc.b	1, 3, 1			* func 044		
	.dc.b	2, 1, 1			* func 045		
	.dc.b	4, 2, 1			* func 046		
	.dc.b	8, 1, 1			* func 047		
	.dc.b	0, 0, 0			* func 048		
	.dc.b	0, 0, 0			* func 049		
*							 Form Manager
	.dc.b	1, 1, 1			* func 050		
	.dc.b	9, 1, 1			* func 051		
	.dc.b	1, 1, 1			* func 002		
	.dc.b	1, 1, 0			* func 003		
	.dc.b	0, 5, 1			* func 004		
	.dc.b	0, 0, 0			* func 005		
	.dc.b	0, 0, 0			* func 006		
	.dc.b	0, 0, 0			* func 007		
	.dc.b	0, 0, 0			* func 008		
	.dc.b	0, 0, 0			* func 009		
*							 Dialog Manager
	.dc.b	0, 0, 0			* func 060		
	.dc.b	0, 0, 0			* func 061		
	.dc.b	0, 0, 0			* func 062		
	.dc.b	0, 0, 0			* func 003		
	.dc.b	0, 0, 0			* func 004		
	.dc.b	0, 0, 0			* func 005		
	.dc.b	0, 0, 0			* func 006		
	.dc.b	0, 0, 0			* func 007		
	.dc.b	0, 0, 0			* func 008		
	.dc.b	0, 0, 0			* func 009		
*							Graphics Manager
	.dc.b	4, 3, 0			* func 070		
	.dc.b	8, 3, 0			* func 071		
	.dc.b	6, 1, 0			* func 072		
	.dc.b	8, 1, 0			* func 073		
	.dc.b	8, 1, 0			* func 074		
	.dc.b	4, 1, 1			* func 075		
	.dc.b	3, 1, 1			* func 076		
	.dc.b	0, 5, 0			* func 077		
	.dc.b	1, 1, 1			* func 078		
	.dc.b	0, 5, 0			* func 009		
*							Scrap Manager
	.dc.b	0, 1, 1			* func 080		
	.dc.b	0, 1, 1			* func 081		
	.dc.b	0, 0, 0			* func 082		
	.dc.b	0, 0, 0			* func 083		
	.dc.b	0, 0, 0			* func 084		
	.dc.b	0, 0, 0			* func 005		
	.dc.b	0, 0, 0			* func 006		
	.dc.b	0, 0, 0			* func 007		
	.dc.b	0, 0, 0			* func 008		
	.dc.b	0, 0, 0			* func 009		
*							fseler Manager
	.dc.b	0, 2, 2			* func 090		
	.dc.b	0, 0, 0			* func 091		
	.dc.b	0, 0, 0			* func 092		
	.dc.b	0, 0, 0			* func 003		
	.dc.b	0, 0, 0			* func 004		
	.dc.b	0, 0, 0			* func 005		
	.dc.b	0, 0, 0			* func 006		
	.dc.b	0, 0, 0			* func 007		
	.dc.b	0, 0, 0			* func 008		
	.dc.b	0, 0, 0 		* func 009		
*							Window Manager
	.dc.b	5, 1, 0			* func 100		
	.dc.b	5, 1, 0			* func 101		
	.dc.b	1, 1, 0			* func 102		
	.dc.b	1, 1, 0			* func 103		
	.dc.b	2, 5, 0			* func 104		
	.dc.b	6, 1, 0			* func 105		
	.dc.b	2, 1, 0			* func 106		
	.dc.b	1, 1, 0			* func 107		
	.dc.b	6, 5, 0			* func 108		
	.dc.b	0, 0, 0 		* func 009		
*							Resource Manger
	.dc.b	0, 1, 1			* func 110		
	.dc.b	0, 1, 0			* func 111		
	.dc.b	2, 1, 0			* func 112		
	.dc.b	2, 1, 1			* func 113		
	.dc.b	1, 1, 1			* func 114		
	.dc.b	0, 0, 0			* func 115		
	.dc.b	0, 0, 0			* func 006
	.dc.b	0, 0, 0			* func 007
	.dc.b	0, 0, 0			* func 008
	.dc.b	0, 0, 0			* func 009
*							Shell Manager
	.dc.b	0, 1, 2			* func 120
	.dc.b	3, 1, 2			* func 121
	.dc.b	1, 1, 1			* func 122
	.dc.b	1, 1, 1			* func 123
	.dc.b	0, 1, 1			* func 124
	.dc.b	0, 1, 2			* func 125

	.bss
	.even
__base:		.ds.l	1			*	-> Base Page
__break:	.ds.l	1			*	Break function
___cpmrv:	.ds.w	1			*	Last CP/M return val



*
*
.globl	_brk
		.text
_brk:		
		movea.l	4(sp),a0		*	New break?
		move.l 	a0,d0
		lea	$100(a0),a0		*	Chicken factor
		cmpa.l	a0,sp			*	Compare
		bhis	brkok			*	OK, continue
		move.l	#-1,d0			*	Load return reg
		rts				*	Return
brkok:
		move.l	d0,__break		*	Save the break
		clr.l	d0			*	Set OK return
		rts				*	return
		
.globl	___BDOS
___BDOS:	link	a6,#0			*	link
		move.w	8(sp),d0		*	Load func code
		move.l	10(sp),d1		*	Load Paramter
		trap	#2			*	Enter BDOS
		cmpa.l	__break,sp		*	Check for stack ovf
		bhis	noovf			*	NO overflow, continue
__sovf:		move.w	#prtstr,d0		*	String print
		lea	ovf,a0			*	a0-> message
		move.l	a0,d1			*	load proper reg
		trap	#2			*	Issue message
__exit:		move.w	#exit,d0		*	Exit
		trap	#2			*		now
noovf:						*	Here if all OK
		unlk	a6			*
		rts				*	Back to caller
*
*	Block Fill function:
*
*	blkfill(dest,char,cnt);
*
*	BYTE	*dest;		/* -> area to be filled	*/
*	BYTE	char;		/* =  char to fill	*/
*	WORD	cnt;		/* =  # bytes to fill   */
*
	.globl	_blkfill
_blkfill:
	move.l	4(a7),a0			*	-> Output area
	move.w	8(a7),d1			*	=  output char
	move.w	10(a7),d0			*	=  output count
	ext.l	d0				*	make it long
	subq.l	#1,d0				*	decrement
	ble	filldone			*	Done if le
fillit:	move.b	d1,(a0)+			*	move a byte
	dbra	d0,fillit			*	Continue
filldone: clr.l	d0				*	always return 0
	rts					*

*
*	Index function to find out if a particular character is in a string.
*
	.globl	_index
	.globl	_strchr
_index:
_strchr:
	move.l	4(a7),a0			*	a0 -> String
	move.w	8(a7),d0			*	D0 = desired character
xindex:	tst.b	(a0)				*	EOS?
	bne	notend				*	No, continue to look
	clr.l	d0				*	Not found
	rts					*	Quit
notend:	cmp.b	(a0)+,d0			*	check for character
	bne	xindex				*	
	move.l	a0,d0				*	Found it
	subq.l	#1,d0				*	set return pointer
	rts					*
*
*	Data area
*
		.data
		.globl	___pname		*	Program Name
		.globl	___tname		*	Terminal Name
		.globl	___lname		*	List device name
		.globl	___xeof			*	^Z byte
ovf:		.dc.b	'Stack Overflow$'	*	Error message
___pname:	.dc.b	'C runtime',0		*	Program name
___tname:	.dc.b	'CON:',0		*	Console name
___lname:	.dc.b	'LST:',0		*	List device name
___xeof:	.dc.b	$1a			*	Control-Z
		.end
SHAR_EOF
cat << \SHAR_EOF > sys/atari/getn.s
* Routines to read the size of the display.
* MicroEMACS works even on a screen that has been blessed
* by the "hi50" program.
* MicroEMACS version 30, for the Atari.
 
	.text
 
* getnrow() -- get number of rows.
 
	.globl	_getnrow
 
_getnrow:
 
	move.l	a2, -(sp)
	move.l	d2, -(sp)
	dc.w	$A000
	move.l	(sp)+, d2
	movea.l	(sp)+, a2
 
	move.w	-42(a0), d0
	addq.w	#1, d0
	ext.l	d0
 
	rts
 
* getncol() -- get number of columns.
 
	.globl	_getncol
 
_getncol:
	move.l	a2, -(sp)
	move.l	d2, -(sp)
	dc.w	$A000
	move.l	(sp)+, d2
	movea.l	(sp)+, a2
 
	move.w	-44(a0), d0
	addq.w	#1, d0
	ext.l	d0
 
	rts
SHAR_EOF
cat << \SHAR_EOF > sys/atari/makesys.mwc
#
# MWC Makefile for MG (Atari ST) -- system library
#
#	Marion Hakanson		Jan '88

# Note that this Makefile expects the sources to be in ..\..\,
# as do the source files here.

# SYSLIB and CFLAGS should be defined by the top level Makefile.
# These are defaults in case this Makefile is called manually.
SYSLIB	= libsys.a

CDEFS	= -DPREFIXREGION
CFLAGS	= -O -DMWC $(CDEFS)

OBJ	= cinfo.o fileio.o misc.o term.o ttyio.o
IND	= diredsup.o alloc.o getn.o
OBJS	= $(OBJ) $(IND)
INC	= ..\..\def.h
OINC	= chrdef.h sysdef.h ttydef.h


all:	$(SYSLIB)
	@echo $(SYSLIB) completed.

$(SYSLIB): $(OBJS)
	ar rcv $@ $?


$(OBJ):		$(INC) $(OINC)

diredsup.o:	$(INC) $(OINC) ..\..\kbd.h

getn.o:		getn.s
	as68toas < $? > tmp.s; $(AS) $(ASFLAGS) -o $@ tmp.s; rm tmp.s


clean:
	-rm $(OBJS) tmp.s $(SYSLIB)

SHAR_EOF
cat << \SHAR_EOF > sys/atari/mg.ini
(bsmap-mode 1)	; enable
; auto-indent globally
(global-set-key "\^J" newline)
(global-set-key "\^M" newline-and-indent)
; blink-matching-paren globally
(global-set-key ")" blink-matching-paren-hack)
(global-set-key "}" blink-matching-paren-hack)
(global-set-key "]" blink-matching-paren-hack)
; set up special keys (ST)
(global-set-key "\F21" help)
(global-set-key "\F21\F21" help-help)
(global-set-key "\F22" keyboard-quit)
(global-set-key "\F24" previous-line)
(global-set-key "\F26" backward-char)
(global-set-key "\F27" next-line)
(global-set-key "\F28" forward-char)
SHAR_EOF
cat << \SHAR_EOF > sys/atari/mglink.inp
-u -o ..\..\mg.ttp gemstart.o
	..\..\basic.o
	..\..\buffer.o
	..\..\dir.o
	..\..\dired.o
	..\..\display.o
	..\..\echo.o
	..\..\extend.o
	..\..\file.o
	..\..\help.o
	..\..\kbd.o
	..\..\keymap.o
	..\..\line.o
	..\..\macro.o
	..\..\main.o
	..\..\match.o
	..\..\modes.o
	..\..\paragrap.o
	..\..\random.o
	..\..\re_searc.o
	..\..\regex.o
	..\..\region.o
	..\..\search.o
	..\..\version.o
	..\..\window.o
	..\..\word.o
	alloc.o
	cinfo.o
	diredsup.o
	fileio.o
	misc.o
	term.o
	ttyio.o
	getn.o
	C:osbind.o c:gemlib c:libf
SHAR_EOF
cat << \SHAR_EOF > sys/atari/misc.c
/* misc.c -- Miscellaneous ST-specific code for MG.
 *
 * author :  Sandra Loosemore
 * date   :  24 Oct 1987
 * changes:  Marion Hakanson -- Jan 1988
 *
 */


#include	"..\..\def.h"

#ifdef MWC
static char *
mwc_cpr="Portions of this program, copyright 1984, Mark Williams Co.";
#endif /* MWC */


/* Exit as quickly as possible.  */

VOID panic (s)
    char* s;
{   Cconws (s);
    Pterm (-1);
    }


#ifdef MWC
extern char **environ;
#else
typedef struct
	{
	char	*p_lowtpa;
	char	*p_hitpa;
	char	*p_tbase;
	long	p_tlen;
	char	*p_dbase;
	long	p_dlen;
	char	*p_bbase;
	long	p_blen;
	char	*p_dta;
	char	*p_parent;
	char	*p_reserved;
	char	*p_env;
	long	p_undefined[20];
	char	p_cmdlin[128];
	}
	BASEPAGE;

extern BASEPAGE *_base;
#endif /* MWC */


/*
 * The environment code here is borrowed from Dale Schumacher.
 */

static char *findenv(var)
	register char *var;
/*
 *	INTERNAL FUNCTION.  This functions attempts to locate <var> in
 *	the environment.  If <var> is not found, NULL is returned.  If
 *	the environment is NULL, NULL is returned.  If <var> is found,
 *	a pointer to the beginning of <var> in the environment is returned.
 *	BOTH MS-DOS AND TOS ENVIRONMENT FORMATS ARE ACCOMODATED.
 */
	{
	register char *p;
	register int len;

#ifdef MWC
	if((p = *environ) == NULL)
#else
	if((p = _base->p_env) == NULL)
#endif /* MWC */
		return(NULL);
	len = strlen(var);
	while(*p)
		{
		if(!strncmp(p, var, len) && (p[len] == '='))
			return(p);
		while(*p++)		/* move to next arg */
			;
		}
	return(NULL);
	}


char *getenv(var)
	register char *var;
/*
 *	Search for <var> in the environment.  If <var> is found, a pointer
 *	to it's value is returned.  NULL is returned if <var> is not found.
 *	WARNING:  The returned pointer points into the environment and
 *	must not be modified!
 */
	{
	register char *p, *q;
	register int len;

	len = strlen(var);
	if(p = findenv(var))
		{
		p += (len + 1);
		if(*p == '\0')		/* TOS env format or empty value */
			{
			q = p+1;
			if(*q == '\0')		/* empty value + end of env */
				return(p);
			while(*q && (*q != '='))
				++q;
			if(*q)			/* empty value */
				return(p);
			else			/* TOS env format */
				return(p+1);
			}
		}
	return(p);
	}


/* Spawn a command.  You can run anything from this; it prompts you for
 *	the command to run.
 * I check for the two most common problems with Pexec:  not finding the
 *    file, and not having enough memory.  Otherwise, I assume bad status
 *    codes were the fault of the program, not Pexec, and that the program
 *    would have told the user what is wrong.
 */

spawncli(f, n)
{   register int s;
    char fname[NFILEN];
    char tail[NFILEN];
    char *shell = getenv("SHELL");
    extern VOID splitcmd();
   
    if (shell && *shell) {
        (VOID) strcpy(fname, shell);
        goto tryit;
	}
    else
        shell = NULL;
	
askfor:
    if ((s = ereply("Run program: ", fname, NFILEN)) != TRUE)
        return (s);
tryit:
    ttcolor (CTEXT);
    ttmove (nrow-1, 0);
    tteeol ();
    splitcmd (fname, tail);
    ttclose ();
    s = Pexec(0, fname, tail, 0L);
    ttopen ();
    if (s == -33) {
        if (shell) {
	    shell = NULL;
            ewprintf ("Could not find shell.");
            sleep(1);
            goto askfor;
	    }
        ewprintf ("Could not find file.");
        return (FALSE);
	}
    else if (s == -39) {
        if (shell) {
	    shell = NULL;
            ewprintf ("Not enough memory to run shell!");
            sleep(1);
            goto askfor;
	    }
        ewprintf ("Not enough memory to run this program!");
        return (FALSE);
	}
    else {
        sgarbf = TRUE;          /* Force repaint */
        Cconws ("Hit any key to return to MG:");
        (VOID) Crawcin ();
        return (TRUE);
        }
}


/* Pexec wants the command tail to have a byte count as the first
 *    character.  This function separates the program name from the command
 *    tail and adds the byte count.
 */

static VOID splitcmd (cmd, tail)
    char* cmd;
    char* tail;
{   int i, j;
    i = 0;
    j = 0;
    while (cmd[i] != '\0') {
        if (j != 0)  { 
	    tail[j] = cmd[i]; 
	    j++;
            }
        else if (cmd[i] == ' ')  {
            cmd[i] = '\0';
            tail[1] = ' ';
            j = 2;
	    }
        i++;
        }
    if (j == 0)  {
        tail[0] = (char) 1;
        tail[1] = ' ';
        tail[2] = '\0';
        }
    else {
        tail[j+1] = '\0';
        tail[0] = (char) (j-1);
        }
    }




/*
 * copy 'count' bytes from 'src' to 'dst'. (optimized)
 */
VOID bcopy(src, dst, count)
register char *src, *dst;
register count;
{
    register c1;

    /*
    ** The magic number 8 comes from:
    **   1   max. bytes before a word boundary
    **   4   min. bytes in a block of long-words
    **   3   max. bytes after the last long-word in the block
    */
    if (count >= 8) {
        /*
        ** Advance dst pointer to word boundary.
        */
        if (1 & (short)dst) {
	        *dst++ = *src++;
                count--;
	}
        /*
        ** If src pointer is (also) aligned, use long-word copy.
        */
        if ((1 & (short)src) == 0) {
            c1 = ((unsigned)count >> 2);
            while (--c1 >= 0)
                *((long *)dst)++ = *((long *)src)++;
            count &= 3;		/* There are 0,1,2, or 3 bytes left */
        }
    }
    /*
    ** Copy whatever is left.
    */
    while (--count >= 0)
	*dst++ = *src++;
}

/* Busy waiting to fake out sleep.  Thanks to Rich Sansom for the routine
 *    to poll the system clock.
 */

static long *hz_200 = (long *)0x000004ba;	/* system 200 hz clock		*/

#ifdef NO_DPROMPT
static long read200hz()
#else
long read200hz()
#endif /* NO_DPROMPT */
{   return(*hz_200);
    }


/* Sleep (busily) for n seconds */

sleep (n)
    int n;
{   register long waitfor = (n * 200) + Supexec(read200hz);

    while (Supexec(read200hz) < waitfor);
    }

SHAR_EOF
cat << \SHAR_EOF > sys/atari/sysdef.h
/* sysdef.h --  MG header file for Atari ST
 *
 * author :  Sandra Loosemore
 * date   :  24 Oct 1987
 *
 */

#define	NULL	0L			/* So who needs stdio.h?	*/
#include	<osbind.h>

/* This definition might be missing from your osbind.h */

#ifndef Supexec
#define Supexec(a)  xbios(38,a)
#endif


#define	KBLOCK		512		/* Kill grow.			*/
#define	GOOD		0		/* Good exit status.		*/
#define NO_VOID_TYPE	1		/* "void" is not a builtin type */
#ifdef MWC
#undef	NO_VOID_TYPE
#define	ZEROARRAY			/* See def.h			*/
    /*
     * Using the MWC shell, ARGV is always the last environment entry
     * (if ARGV is not defined, the program was not started from the
     * MWC shell).  The last environment variable is followed by
     * the string pointed to by argv[0], then argv[1], etc.  This
     * means that the non-MWC getenv() in misc.c will take command line
     * args as environment variables.  It also means that if spawn()
     * (misc.c) runs the MWC shell, the shell takes this program's args
     * as its own.  So here we truncate the environment by zeroing out
     * the first character of argv[0], thus working around both problems.
     */
#define SYSINIT (*(argv[0]) = 0)	/* run in main() 		*/
#endif /* MWC */

#define MALLOCROUND(m) ((m)+=1,(m)&=~1)	/* 2-byte blocks (see alloc.c)	*/
#define LOCAL_VARARGS	1		/* For echo.c			*/
#define RSIZE long			/* Type for file/region sizes   */
#define KCHAR int                       /* 16 bits for keystrokes       */


/* Enable various things */

#define DO_METAKEY	1		/* Meta key code */
#define METABIT		0x200
#define FKEYS		1		/* Enable fkey code */
#define GOSMACS 	1		/* Goslings compatibility functions */
#define PREFIXREGION	1		/* Enable prefix-region function */
#define BSMAP		FALSE		/* BSMAP code, default to off */

/* Disable some features for now. */

#define NO_BACKUP	1


/* Alcyon thinks subtracting two pointers gives a long.  Cast it to int.
 */

#define OFFSET(type,member) ((int)((char *)&(((type *)0)->member)-(char *)((type *)0)))
#ifdef MWC
#undef	OFFSET
#endif /* MWC */

/*
 * Macros used by the buffer name making code.
 * Start at the end of the file name, scan to the left
 * until BDC1 (or BDC2, if defined) is reached. The buffer
 * name starts just to the right of that location, and
 * stops at end of string (or at the next BDC3 character,
 * if defined). BDC2 and BDC3 are mainly for VMS.
 */

#define	BDC1	'\\'			/* Buffer names.		*/
#define	BDC2	':'


#define fncmp strcmp			/* All filenames are lowercased */
extern char *strncpy();

SHAR_EOF
cat << \SHAR_EOF > sys/atari/term.c
/* term.c -- screen output code for Atari ST terminal
 *
 * author :  Sandra Loosemore (based on an earlier version by dec-rec!conroy)
 * date   :  24 Oct 1987
 * changes:  Marion Hakanson -- Jan 1988
 *
 * This code simulates scrolling regions by using the
 * insert line and delete line functions. Should display
 * handling be taught about this. Based on Rich's code
 * for the Heath H19.
 */

#include	"..\..\def.h"
 
#define	BEL	0x07			/* BEL character.		*/
#define	ESC	0x1B			/* ESC character.		*/
#define	LF	0x0A			/* Line feed.			*/
 
extern int ttrow;
extern int ttcol;
extern int tttop;
extern int ttbot;
extern int tthue;

int	tceeol	=	2;		/* Costs.			*/
int	tcinsl, tcdell;			/* Set in ttyio.c:ttopen()	*/

 
/* Move the cursor to the specified origin 0 row and column position.  Try
 *	to optimize out extra moves; redisplay may have left the cursor in 
 *	the right location on the screen last time.
 */

VOID ttmove(row, col)
{   if (ttrow!=row || ttcol!=col) {
	if (row > nrow)
	    row = nrow;
	if (col > ncol)
	    col = ncol;
	ttputc(ESC);
	ttputc('Y');
	ttputc(row+' ');
	ttputc(col+' ');
	ttrow = row;
	ttcol = col;
	}
    }

 
/* Erase to end of line. */

VOID tteeol()
{   ttputc(ESC);
    ttputc('K');
    }

 
/* Erase to end of page. */

VOID tteeop()
{   ttputc(ESC);
    ttputc('J');
    }

 
/* Make a noise.  */

VOID ttbeep()
{   ttputc(BEL);
    ttflush();
    }

 
/* Insert nchunk blank line(s) onto the screen, scrolling the last line on
 *	the screen off the bottom. This is done with a cluster of clever 
 *	insert and delete commands, because there are no scroll regions.
 */

VOID ttinsl(row, bot, nchunk)
{   register int	i;
    if (row == bot) {
	ttmove(row, 0);
	tteeol();
	return;
    }
    ttmove(1+bot-nchunk, 0);
    for (i=0; i<nchunk; i++) {
	ttputc(ESC);
	ttputc('M');
    }
    ttmove(row, 0);
    for (i=0; i<nchunk; i++) {
	ttputc(ESC);
	ttputc('L');
    }
    ttrow = row;
    ttcol = 0;
    }

 
/* Delete nchunk line(s) at "row", replacing the bottom line on the screen
 *	with a blank line. This is done with a crafty sequences of insert 
 *	and delete line sequences since there is no scroll region.  The
 * 	presence of the echo area makes a boundary condition go away.
 */

VOID ttdell(row, bot, nchunk)
{   register int	i;
    if (row == bot) {
	ttmove(row, 0);
	tteeol();
	return;
    }
    ttmove(row, 0);
    for (i=0; i<nchunk; i++) {
	ttputc(ESC);
	ttputc('M');
    }
    ttmove(1+bot-nchunk,0);
    for (i=0; i<nchunk; i++) {
	ttputc(ESC);
	ttputc('L');
    }
    ttrow = 1+bot-nchunk;
    ttcol = 0;
    }

 
/* Set display color.  Normal video is text color.  Reverse video is used
 * 	for the mode line.
 */

VOID ttcolor(color)
    register int color;
{   if (color != tthue) {
	if (color == CTEXT) {		/* Normal video.	*/
	    ttputc(ESC);
	    ttputc('q');
	    } 
	else if (color == CMODE) {	/* Reverse video.	*/
	    ttputc(ESC);
	    ttputc('p');
	    }
	tthue = color;
	}
    }
SHAR_EOF
cat << \SHAR_EOF > sys/atari/ttydef.h
/*
 * Name:	MicroEMACS
 *		Atari 520ST header file.
 * Version:	30
 * Last edit:	22-Feb-86
 * By:		rex::conroy
 *		decvax!decwrl!dec-rhea!dec-rex!conroy
 */
#define	GOSLING	1			/* Use fancy redisplay.		*/
 
#define	NROW	50			/* The "50" is big enough to	*/
#define	NCOL	80			/* deal with the "hi50" screen.	*/
 
/*
 * Special keys.
 */

#define KFIRST	256
#define KLAST   284


/* These i/o functions are NOP's or direct equivalents of BIOS calls.
 *	Make them #define's so we don't have to go through a useless
 *	level of indirection.
 */

#define ttinit()
#define tttidy()
#define ttwindow(top,bot) (top, bot)
#define ttresize()
#define ttnowindow()
#define ttputc(c) Bconout(2, c)		/* Primitive output function	*/
#define ttflush()	                /* A NOP			*/
#define typeahead() ((int)Bconstat(2))	/* Check if there is input	*/
SHAR_EOF
cat << \SHAR_EOF > sys/atari/ttyio.c
/* ttyio.c -- Low-level Atari ST terminal input/output handling
 *
 * author :  Sandra Loosemore (from an earlier version by dec-rex!conroy)
 * date   :  24 Oct 1987
 * changes:  Marion Hakanson -- Jan 1988
 *
 */

#include	"..\..\def.h"

int	nrow;				/* Terminal size, rows.		*/
int	ncol;				/* Terminal size, columns.	*/

#ifdef DO_METAKEY
#define RSHIFT   (0x01)
#define LSHIFT	 (0x02)
#define CTRL	 (0x04)
#define ALTKEY	 (0x08)
#define CAPSLOCK (0x10)

static struct keytab {
    char *unshift;
    char *shift;
    char *capslock;
    } *keytable;


/* Mess with the bit that controls whether we get back all the shift keys
 *	on each keystroke.
 */

static unsigned char oldconterm;
static unsigned char *conterm = (char *)0x00000484;
 
static savect ()
{   oldconterm = *conterm;
    *conterm = (oldconterm | 0x8);
    }

static restct ()
{   *conterm = oldconterm;
    }
#endif /* DO_METAKEY */


/* Setup routines.  "getnrow" and "getncol" are assembly language routines.
 */

VOID ttopen()
{   nrow = getnrow();
    if (nrow > NROW)
	nrow = NROW;
    ncol = getncol();
    if (ncol > NCOL)
	ncol = NCOL;
    tcinsl = tcdell = (nrow * 2) + (ncol / 10);
#ifdef DO_METAKEY
    (VOID) Supexec(savect);
    keytable = (struct keytab *)Keytbl(-1L,-1L,-1L);
#endif /* DO_METAKEY */
    }

VOID ttclose()
{
#ifdef DO_METAKEY
    (VOID) Supexec(restct);
#endif /* DO_METAKEY */
    }


/* Keystrokes are returned as 10-bit quantities.
 *
 * Codes 0-255 are used for the usual character set.
 * Codes 256-511 are used for function keys.
 * Bit 10 (0x200) is the meta bit.
 *
 */
#ifdef FKEYS

static int keycodes[] = {
	0x00,	/* dummy for F0 entry */
	0x3b,	0x3c,	0x3d,	0x3e,	0x3f,
	0x40,	0x41,	0x42,	0x43,	0x44,
	0x54,	0x55,	0x56,	0x57,	0x58,
	0x59,	0x5a,	0x5b,	0x5c,	0x5d,
	0x62,	0x61,	0x52,	0x48,	0x47,
	0x4b,	0x50,	0x4d
        };

char *keystrings[] = {
"",		/* dummy for F0 entry */
"F1",		"F2",		"F3",		"F4",		"F5",
"F6",		"F7",		"F8",		"F9",		"F10",
"F11",		"F12",		"F13",		"F14",		"F15",
"F16",		"F17",		"F18",		"F19",		"F20",
"Help",		"Undo",		"Insert",	"Up",		"Clr/Home",
"Left",		"Down",		"Right"
};
#endif /* FKEYS */

/* Use the ALT key as a meta key.  The problem with this is that it
 *	appears to trash the ascii key code in the low order byte.
 *	Therefore, we have to resort to looking up the key in the
 *	system keystroke translation table.
 * Some non-US keyboards apparently use some ALT combinations to
 *	get real, printing characters.  If you've got one of these
 *	beasts you can use meta-key-mode to turn off recognition
 *	of the ALT key, in which case this routine just returns
 *	whatever BIOS gave as the key value.  If that approach is
 *	distasteful, you can also bind a function key to return
 *	the ALT characters usurped by the meta key mode.
 */

KCHAR getkbd()
{   register int code, bchar;
#ifdef FKEYS
    register int i;
#endif /* FKEYS */
#ifdef DO_METAKEY
    register int shifts;
    extern int use_metakey;		/* set in the generic kbd.c */
#endif /* DO_METAKEY */
    union {
        unsigned long k_rawkey;
        struct {
            unsigned char kb_shifts;	/* shift bits */
            unsigned char kb_code;	/* scan code */
            unsigned char kb_notused;
            unsigned char kb_bchar;	/* bios char */
        } k_break;
    } keyval;
 
    keyval.k_rawkey = Bconin(2);
    code   = keyval.k_break.kb_code;

#ifdef FKEYS
    for (i=KFIRST; i<=KLAST; i++) 	  	 /* Was it an Fkey? */
        if (code == keycodes[i-KFIRST])
	    return((KCHAR)i);
#endif /* FKEYS */

    bchar  = keyval.k_break.kb_bchar;
#ifdef DO_METAKEY
    shifts = keyval.k_break.kb_shifts;

    /*
     * Rule out the case where some shift bit other than what
     * we're interested in is set (if such a beast ever exists).
     * If otherwise, just forget about any special handling here.
     */
    if (use_metakey == TRUE &&
            (shifts & ~(CTRL|LSHIFT|RSHIFT|CAPSLOCK)) == ALTKEY)
        if ((shifts & (CTRL|LSHIFT|RSHIFT|CAPSLOCK)) == 0) /* ALTKEY only */
	    return ((KCHAR)(keytable->unshift[code] | METABIT));
        else if (shifts & CTRL)
	    return ((KCHAR)(bchar | METABIT));
        else if (shifts & (LSHIFT|RSHIFT))
	    return ((KCHAR)(keytable->shift[code] | METABIT));
        else /* (shifts & CAPSLOCK) */
	    return ((KCHAR)(keytable->capslock[code] | METABIT));
    else
        return ((KCHAR)bchar);
#else
    return ((KCHAR)bchar);
#endif
    }
 
/* Establish default keypad bindings.  I've only done the arrow keys
 *	here.
 */


VOID ttykeymapinit() { 
/*  excline("global-set-key f13 previous-line"); */	/* Up arrow */
/*  excline("global-set-key f15 backward-char"); */ 	/* Left arrow */  
/*  excline("global-set-key f16 next-line"); */		/* Down arrow */
/*  excline("global-set-key f17 forward-char"); */		/* Right arrow */
    }


#ifndef NO_DPROMPT
/*
 * Return TRUE if we busy-wait for 2 seconds without any keystrokes;
 * otherwise return FALSE.  See sleep() in misc.c for details.
 */

ttwait() {
    extern long read200hz();
    register keyhit;
    register long waitfor = 400L + Supexec(read200hz);

    while ((keyhit = typeahead()) == 0 && Supexec(read200hz) < waitfor);
    if (keyhit)
        return FALSE;

    return TRUE;
    }
#endif /* NO_DPROMPT */


SHAR_EOF
cat << \SHAR_EOF > sys/atari/varargs.h
/*
 * Varargs, for use on Atari ST (works with MWC, probably others).
 *	Came from AmigaDOS version, which was borrowed from 4BSD.
 */

typedef char		*va_list;
#define va_dcl		int va_alist;
#define va_start(pv)	pv = (char *) &va_alist
#define va_end(pv)	/* Naught to do... */
#define va_arg(pv, t)	((t *) (pv += sizeof(t)))[-1]
SHAR_EOF
#	End of shell archive
exit 0
-------