v08i013: A Micro-Emacs variant that resembles GNU Emacs

sources-request at mirror.UUCP sources-request at mirror.UUCP
Wed Jan 28 04:22:27 AEST 1987


Submitted by: Bob Larson <seismo!usc-oberon!blarson>
Mod.sources: Volume 8, Issue 13
Archive-name: micrognu/Part06


#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	tty/amiga/ttydef.h
#	tty/amiga/console.c
#	tty/amiga/menustack.c
#	tty/amiga/tty.c
#	tty/amiga/ttyio.c
#	tty/amiga/ttymenu.c
# This archive created: Sat Nov 15 15:26:59 1986
export PATH; PATH=/bin:$PATH
if test ! -d tty/amiga
then
mkdir tty/amiga
fi
if test ! -d sys/amiga
then
mkdir sys/amiga
fi
if test -f 'tty/amiga/ttydef.h'
then
	echo shar: will not over-write existing file "'tty/amiga/ttydef.h'"
else
cat << \SHAR_EOF > 'tty/amiga/ttydef.h'
/*
 * Name:	MicroEMACS
 *		Amiga console device virtual terminal header file
 * Version:	Gnu v30
 * Last edit:	26-Aug-86
 * Created:	20-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
 */
#define	GOSLING				/* Compile in fancy display.	*/

#define	NROW	48			/* Max rows (only in interlace)	*/
#define	NCOL	80			/* Columns (borderless window)	*/

/*
 * Special keys for the default Amiga console device keymap.
 * Function key codes are in the form <CSI>v~
 * where v is a 1 or 2-digit code between 0 and 19,
 * so they comprise the first 20 entries in the key
 * table.  The next 12 entries are for the help and
 * arrow keys.
 */
#define	KF1	K01
#define	KF2	K02
#define	KF3	K03
#define	KF4	K04
#define	KF5	K05
#define	KF6	K06
#define	KF7	K07
#define	KF8	K08
#define	KF9	K09
#define	KF10	K0A
#define	KSF1	K0B
#define	KSF2	K0C
#define	KSF3	K0D
#define	KSF4	K0E
#define	KSF5	K0F
#define	KSF6	K10
#define	KSF7	K11
#define	KSF8	K12
#define	KSF9	K13
#define	KSF10	K14
#define	KUP	K15
#define	KSUP	K16
#define	KDOWN	K17
#define	KSDOWN	K18
#define	KLEFT	K19
#define	KSLEFT	K1A
#define	KRIGHT	K1B
#define	KSRIGHT	K1C
#define	KHELP	K1D

/* The 'menu' key doesn't really appear on the
 * Amiga keyboard.  When ttgetc() sees a menu
 * event, it saves the menu number and item,
 * then stuffs the sequence for KMENU into
 * the input buffer.
 */
#define	KMENU	K1E

/*
 * Intuition menu interface.  Each set of menu items
 * kept in a table of MenuBinding structures, which
 * is in turn kept in a table of MenuInfo structures.
 *
 * These tables are indexed via the menu and item
 * numbers to find the internal extended name of
 * the function associated with a certain item.
 */
struct MenuBinding {
	char *Command;
	char *Binding;
};

struct MenuInfo {
	char *Name;			/* name of menu			*/
	short NumItems;			/* # of items			*/
	struct MenuBinding *Items;	/* item name, internal binding	*/
};

#define NITEMS(arr) (sizeof(arr) / (sizeof(arr[0])))

/*
 * If either MENU, or BROWSER is defined, we need to define
 * DO_MENU to get the code for dealing with menu selections
 * compiled in.
 */

#ifdef	MENU
#define	DO_MENU
#else
#ifdef	BROWSER
#define	DO_MENU
#endif	BROWSER
#endif	MENU

/*
 * MODE_RENDITION and TEXT_RENDITION
 * determine the way the mode line and
 * text area are rendered (using the SGR
 * sequence).  TEXT_* and MODE_* set the
 * foreground (FG) and background (BG)
 * color to the specified number.  If you
 * #define CHANGE_COLOR, you can redefine
 * these dynamically.
 */

#ifndef MODE_RENDITION
#define	MODE_RENDITION 7
#endif

#ifndef TEXT_RENDITION
#define	TEXT_RENDITION 0
#endif

#ifndef	TEXT_FG
#define TEXT_FG 1
#endif

#ifndef TEXT_BG
#define TEXT_BG 0
#endif

#ifndef	MODE_FG
#define MODE_FG 1
#endif

#ifndef	MODE_BG
#define MODE_BG 0
#endif

/*
 * Return the width and height of
 * the default font for a window.
 */

#define	FontWidth(w) (w)->RPort->TxWidth
#define	FontHeight(w) (w)->RPort->TxHeight
SHAR_EOF
fi # end of overwriting check
if test -f 'tty/amiga/console.c'
then
	echo shar: will not over-write existing file "'tty/amiga/console.c'"
else
cat << \SHAR_EOF > 'tty/amiga/console.c'
/*
 * These functions are taken directly from the
 * console.device chapter in the Amiga V1.1
 * ROM Kernel Manual.
 */
#include <exec/types.h>
#include <exec/io.h>
#include <devices/console.h>
#include <libraries/dos.h>
#include <intuition/intuition.h>

extern	LONG	OpenDevice();
extern	LONG	DoIO();
extern	LONG	SendIO();

/*
 * Open a console device, given a read request
 * and a write request message.
 */

int OpenConsole(writerequest,readrequest,window)
struct IOStdReq *writerequest;
struct IOStdReq *readrequest;
struct Window *window;
{
	LONG error; 
	writerequest->io_Data = (APTR) window;
	writerequest->io_Length = (ULONG) sizeof(*window);
	error = OpenDevice("console.device", 0L, writerequest, 0L);

	/* clone required parts of the request */
	readrequest->io_Device = writerequest->io_Device;
	readrequest->io_Unit   = writerequest->io_Unit;
	return((int) error);
}

/*
 * Output a single character	
 * to a specified console
 */ 

int ConPutChar(request,character)
struct IOStdReq *request;
char character;
{
#ifdef	V11
	register int x;
#endif
	request->io_Command = CMD_WRITE;
	request->io_Data = (APTR)&character;
	request->io_Length = (ULONG)1;
	DoIO(request);
	/* caution: read comments in manual! */
	return(0);
}
 
/*
 * Output a NULL-terminated string of
 * characters to a console
 */ 

int ConPutStr(request,string)
struct IOStdReq *request;
char *string;
{
#ifdef	V11
	register int x;
#endif
	request->io_Command = CMD_WRITE;
	request->io_Data = (APTR)string;
	request->io_Length = (LONG)-1;
	DoIO(request);
	return(0);
}

/*
 * Write out a string of predetermined
 * length to the console
 */
 
int ConWrite(request,string,len)
struct IOStdReq *request;
char *string;
int len;
{
#ifdef	V11
	register int x;
#endif
	request->io_Command = CMD_WRITE;
	request->io_Data = (APTR)string;
	request->io_Length = (LONG)len;
	DoIO(request);
	return(0);
}

/*
 * Queue up a read request 
 * to a console
 */

int QueueRead(request,whereto)
struct IOStdReq *request;
char *whereto;
{
#ifdef	V11
	register int x;
#endif
	request->io_Command = CMD_READ;
	request->io_Data = (APTR)whereto;
	request->io_Length = (LONG)1;
	SendIO(request);
	return(0);
}

SHAR_EOF
fi # end of overwriting check
if test -f 'tty/amiga/menustack.c'
then
	echo shar: will not over-write existing file "'tty/amiga/menustack.c'"
else
cat << \SHAR_EOF > 'tty/amiga/menustack.c'
/*
 *  Simple menu package.  Needs lotsa work to handle some cases.
 *
 *  Copyright 1985
 *  Louis A. Mamakos
 *  Software & Stuff
 *  14813 Ashford Place
 *  Laurel, MD  20707
 *
 *  For non-commerical use only.  This program, or any modifications, may not
 *  be sold or incorporated into any product without prior permission from the
 *  author.
 *
 *  Modified by mwm to handle "stacking" menus.
 *	NB - adding item to a menu that's been "popped" back to doesn't work,
 *	and probably never will.
 */

#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/ports.h>
#include <exec/devices.h>
#include <exec/memory.h>
#include <hardware/blit.h>
#include <graphics/copper.h>
#include <graphics/regions.h>
#include <graphics/rastport.h>
#include <graphics/gfxbase.h>
#include <graphics/gels.h>
#include <intuition/intuition.h>

#define MNUM(menu,item,sub) (SHIFTMENU(menu)|SHIFTITEM(item)|SHIFTSUB(sub))
#define	Menu_Clear	DisposeMenus	/* For ttyio.c	*/

extern	char	*AllocMem();
extern	char	*AllocRemember();

struct	Mem_Node {
   struct Node mn_Node;
   struct Remember mn_Memory;
   struct Menu *mn_Menu;
   } *Top, *RemHead();

extern struct NewWindow MicroEMACS ;	/* For Screen width & Height	*/
#define SCREENHEIGHT	(MicroEMACS . MaxHeight)
#define SCREENWIDTH	(MicroEMACS . MaxWidth)

static struct List Memory;
static int Cur_Menu, Cur_MenuItem, Cur_SubItem;
static struct Menu *LastMenu;
static struct MenuItem *LastMenuItem, *LastSubItem;

struct Menu *AutoMenu;      /* menu struct being dynamically built */

char *strsave();	    /* Save a string in the remember list */

Menu_Init()
{
   Memory.lh_Head = (struct Node *) &(Memory.lh_Tail);
   Memory.lh_TailPred = (struct Node *) &(Memory.lh_Head);
   Memory.lh_Tail = NULL;
   Memory.lh_Type = NT_MEMORY;
   Top = NULL;
   Cur_Menu = Cur_MenuItem = Cur_SubItem = -1;
   AutoMenu = LastMenu = NULL;     /* no menu chain yet */
   LastMenuItem = LastSubItem = NULL;
}

Menu_Clear()
{

   while ((Top = RemHead(&Memory)) != NULL) {
      FreeRemember(&(Top->mn_Memory), (LONG)TRUE);
      FreeMem(Top, (LONG)sizeof(struct Mem_Node));
  }
  Menu_Init();			/* Just for safeties sake */
}

Menu_Pop()
{

   if ((Top = RemHead(&Memory)) == NULL) return NULL;
   FreeRemember(&(Top->mn_Memory), (LONG)TRUE);
   FreeMem(Top, (LONG)sizeof(struct Mem_Node));
   /* Now, set Top back to the real list head */
   Top = (struct Mem_Node *) Memory.lh_Head;
   LastMenu = Top->mn_Menu;
   LastMenuItem = NULL;		/* Wrong, but you can't add items here anyway */
   LastSubItem = NULL;		/*    ditto				      */
   Cur_Menu--;
}
/*
 *  Add a MENU item.  Args are the text of the menu item, and an enable
 *  flag.  Returns an Intuition type menu number, with the MenuItem and
 *  Menu SubItem being NOITEM and NOSUB.  The MENUITEM part is valid.
 */
/* dummy Intuitext used to calculate length of menu names */
static struct IntuiText itd = {
   AUTOFRONTPEN, AUTOBACKPEN, JAM2, 1, 1, NULL, NULL, NULL
};

Menu_Add(name, enabled)
   char *name;
   int enabled;
{
   register struct Menu *m;

   if ((Top = (struct Mem_Node *) AllocMem(
		 (LONG)sizeof(struct Mem_Node), MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
      return NULL;
   Top->mn_Node.ln_Type = NT_MEMORY;

   if ((m = (struct Menu *)AllocRemember(&(Top->mn_Memory),
                 (LONG)sizeof (struct Menu), MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
      return NULL;
   Top->mn_Menu = m;

   if (LastMenu == NULL)
      AutoMenu = m;     /* first menu on list */
   else
      LastMenu->NextMenu = m;      /* link it in */

   LastMenuItem = NULL;            /* end of previous MenuItem list */
   LastSubItem = NULL;
   Cur_MenuItem = Cur_SubItem = -1; /* reset item numbers */
   if (LastMenu == NULL)
      m->LeftEdge = 0;
   else
      m->LeftEdge = LastMenu->LeftEdge + LastMenu->Width;
   m->TopEdge = 0;
   itd.IText = (UBYTE *)name;
   m->Width = IntuiTextLength(&itd);
   Top->mn_Node.ln_Name = m->MenuName = strsave(name);
   m->Height = 0;
   m->Flags = enabled ? MENUENABLED : 0;
   m->FirstItem = NULL;
   LastMenu = m;

   AddHead(&Memory, Top);
   return MNUM(++Cur_Menu, NOITEM, NOSUB);
}

/*
 *  Add a menu item to the current MENU.  Note that Add_Menu *must* be
 *  called before this function.
 */
Menu_Item_Add(name, flags, mux, ch)
   char *name;       /* name of menu item */
   USHORT flags;
   LONG mux;         /* mutual exclusion mask */
   BYTE ch;        /* command sequence character, if COMMSEQ */
{
   register struct MenuItem *m, *n;
   register struct IntuiText *it;

   flags &= CHECKIT|CHECKED|COMMSEQ|MENUTOGGLE|ITEMENABLED|HIGHCOMP|HIGHBOX;
   if (LastMenu == NULL)
      return MNUM(NOMENU, NOITEM, NOSUB);

   if ((m = (struct MenuItem *) AllocRemember(&(Top->mn_Memory),
           (LONG)sizeof(struct MenuItem), MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
      return MNUM(NOMENU, NOITEM, NOSUB);

   LastSubItem = NULL;		/* terminate possible list of subitems */
   Cur_SubItem = -1;
   if (LastMenuItem == NULL)
      LastMenu->FirstItem  = m;
   else
      LastMenuItem->NextItem = m;
   m->Flags = flags | ITEMTEXT;
   /*
    *  Check for highlight mode:  if none selected, use HIGHCOMP
    */
   if ((m->Flags & (HIGHCOMP | HIGHBOX)) == 0)
      m->Flags |= HIGHCOMP;
   m->Command = ch;
   m->MutualExclude = mux;
   m->SubItem = NULL;
   m->ItemFill = (APTR) AllocRemember(&(Top->mn_Memory),
                 (LONG)sizeof(struct IntuiText), MEMF_PUBLIC | MEMF_CLEAR);
   it = (struct IntuiText *) m->ItemFill;
   it->FrontPen = AUTOFRONTPEN;
   it->BackPen = AUTOBACKPEN;
   it->DrawMode = JAM2;
   if (flags & CHECKIT)
      it->LeftEdge = CHECKWIDTH + 1;
   else
      it->LeftEdge = 1;
   it->TopEdge = 1;
   it->ITextFont = NULL;      /* default font */
   it->IText = (UBYTE *)strsave(name);
   it->NextText = NULL;
   if (LastMenuItem == NULL) {
      m->TopEdge = 2;
      m->LeftEdge = 0;
   } else if (LastMenuItem->TopEdge + 40 > SCREENHEIGHT) {
      m->TopEdge = 2;
      m->LeftEdge = LastMenuItem->LeftEdge + LastMenuItem->Width + 12;
      if (m->LeftEdge > SCREENWIDTH) {
	  LastMenuItem->NextItem = NULL;
	  LastMenuItem->Flags &= ~ITEMENABLED;
      	  return MNUM(NOMENU, NOITEM, NOSUB);
      }
   } else {
      m->TopEdge = LastMenuItem->TopEdge + 10;
      m->LeftEdge = LastMenuItem->LeftEdge;
   }
   m->Width = 0;
   if (flags & CHECKIT)
      m->Width += CHECKWIDTH;
   if (flags & COMMSEQ)
      m->Width += COMMWIDTH + 20;
   m->Width += IntuiTextLength(m->ItemFill);
   m->Height = 10;
   /*
    *  Check last menu item's width to see if it is larger than this
    *  item's.  If new item is larger, then update width of all other
    *  items.
    */
   if (LastMenuItem) {
      if (LastMenuItem->Width > m->Width)
        m->Width = LastMenuItem->Width;
      else {
         register short delta = m->Width - LastMenuItem->Width;

	 for (n = LastMenu->FirstItem; n != m; n = n->NextItem) {
	    n->Width = m->Width;
	    if (n->LeftEdge > 0) n->LeftEdge += delta;
	 }
	 if (m->LeftEdge > 0) m->LeftEdge += delta;
      }
   }
   LastMenuItem = m;
   return MNUM(Cur_Menu, ++Cur_MenuItem, NOSUB);
}



Menu_SubItem_Add(name, flags, mux, ch)
   char *name, ch;
   USHORT flags;
   LONG mux;
{
   register struct MenuItem *m, *n;
   register struct IntuiText *it;

   flags &= CHECKIT|CHECKED|COMMSEQ|MENUTOGGLE|ITEMENABLED|HIGHCOMP|HIGHBOX;
   if (LastMenuItem == NULL)
      return MNUM(NOMENU, NOITEM, NOSUB);

   if ((m = (struct MenuItem *) AllocRemember(&(Top->mn_Memory),
           (LONG)sizeof(struct MenuItem), MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
      return MNUM(NOMENU, NOITEM, NOSUB);

   if (LastSubItem == NULL)
      LastMenuItem->SubItem = m;
   else
      LastSubItem->NextItem = m;
   m->Flags = flags | ITEMTEXT;
   /*
    * check for highlight mode.  If none selected, use HIGHCOMP
    */
   if ((m->Flags & (HIGHCOMP|HIGHBOX)) == 0)
      m->Flags |= HIGHCOMP;
   m->Command = ch;
   m->MutualExclude = mux;
   m->SubItem = NULL;
   m->ItemFill = (APTR) AllocRemember(&(Top->mn_Memory),
                     (LONG)sizeof(struct IntuiText), MEMF_PUBLIC | MEMF_CLEAR);
   it = (struct IntuiText *) m->ItemFill;
   it->FrontPen = AUTOFRONTPEN;
   it->BackPen = AUTOBACKPEN;
   it->DrawMode = JAM2;
   if (flags & CHECKIT)
      it->LeftEdge = CHECKWIDTH + 1;
   else
      it->LeftEdge = 1;
   it->TopEdge = 1;
   it->ITextFont = NULL;      /* default font */
   it->IText = (UBYTE *)strsave(name);
   it->NextText = NULL;
   m->LeftEdge = LastMenuItem->Width + 10;
   m->Width = 0;
   if (LastSubItem == NULL)
      m->TopEdge = 1;
   else
      m->TopEdge = LastSubItem->TopEdge + 10;
   if (flags & CHECKIT)
      m->Width += CHECKWIDTH;
   if (flags & COMMSEQ)
      m->Width += COMMWIDTH + 20;
   m->Width += IntuiTextLength(m->ItemFill);
   m->Height = 10;
   /*
    *  Check last menu item's width to see if it is larger than this
    *  item's.  If new item is larger, then update width of all other
    *  items.
    */
   if (LastSubItem) {
	if (LastSubItem->Width > m->Width)
	    m->Width = LastSubItem->Width;
	else
	    for (n = LastMenuItem->SubItem; n != m; n = n->NextItem)
		n->Width = m->Width;
   }
   LastSubItem = m;
   return MNUM(Cur_Menu, Cur_MenuItem, ++Cur_SubItem);
}

char *
strsave(string) char *string; {
   char *out ;

   out = (char *) AllocRemember(&(Top->mn_Memory), (LONG)(strlen(string) + 1),
	MEMF_PUBLIC) ;
   if (out == NULL) return NULL ;

   (void) strcpy(out, string) ;
   return out ;
}
SHAR_EOF
fi # end of overwriting check
if test -f 'tty/amiga/tty.c'
then
	echo shar: will not over-write existing file "'tty/amiga/tty.c'"
else
cat << \SHAR_EOF > 'tty/amiga/tty.c'
/*
 * Name:	MicroEMACS
 *		Amiga console device virtual terminal display
 * Version:	GNU v30
 * Last Edit:	23-Aug-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
 * Created:	19-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
 *
 * Drives the Amiga console device display.  The code
 * is a combination of the Heath and ANSI terminal drivers,
 * plus some hacks to manage the console device colors.
 */

#include	"def.h"

#define	BEL	0x07			/* BEL character.		*/
#define	ESC	0x1B			/* ESC character.		*/

extern	int	ttrow;
extern	int	ttcol;
extern	int	tttop;
extern	int	ttbot;
extern	int	tthue;

int	tceeol	=	3;		/* Costs, ANSI display.		*/
int	tcinsl	= 	17;
int	tcdell	=	16;


#ifdef	CHANGE_COLOR
short	mode_rendition = MODE_RENDITION,	/* set standard colors */
	text_rendition = TEXT_RENDITION,
	text_fg = TEXT_FG + 30,
	text_bg = TEXT_BG + 40,
	mode_fg = MODE_FG + 30,
	mode_bg = MODE_BG + 40;
#else				/* colors are hard-coded		*/
#define mode_rendition MODE_RENDITION
#define	text_rendition TEXT_RENDITION
#define text_fg (TEXT_FG + 30)
#define text_bg (TEXT_BG + 40)
#define mode_fg (MODE_FG + 30)
#define mode_bg (MODE_BG + 40)
#endif

/*
 * Initialize the terminal when the editor
 * gets started up.  A no-op for the Amiga
 */
ttinit()
{
}

/*
 * Clean up the terminal, in anticipation of
 * a return to the command interpreter. This
 * is a no-op on the Amiga.
 */
tttidy()
{
}

/*
 * 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 last time!
 */
ttmove(row, col)
{
	if (ttrow!=row || ttcol!=col) {
		ttputc(ESC);
		ttputc('[');
		asciiparm(row+1);
		ttputc(';');
		asciiparm(col+1);
		ttputc('H');
		ttrow = row;
		ttcol = col;
	}
}

/*
 * Erase to end of line.
 */
tteeol()
{
	ttputc(ESC);
	ttputc('[');
	ttputc('K');
}

/*
 * Erase to end of page.
 */
tteeop()
{
	ttputc(ESC);	/* reinforce current color values */
	ttputc('[');
	asciiparm((tthue == CTEXT) ? text_rendition : mode_rendition);
	ttputc(';');
	asciiparm(text_fg);
	ttputc(';');
	asciiparm(text_bg);
	ttputc('m');

	ttputc(ESC);	/* clear to end of display */
	ttputc('[');
	ttputc('J');
}

/*
 * Make a noise.
 */
ttbeep()
{
	ttputc(BEL);
	ttflush();
}

/*
 * Convert a number to decimal
 * ascii, and write it out. Used to
 * deal with numeric arguments.
 */
asciiparm(n)
register int	n;
{
	if (n > 9)
		asciiparm(n/10);
	ttputc((n%10) + '0');
}

/*
 * Insert a block of blank lines onto the
 * screen, using a scrolling region that starts at row
 * "row" and extends down to row "bot".  Deal with the one
 * line case, which is a little bit special, with special
 * case code.
 *
 * Since we don't really have a scrolling region,
 * delete the block of lines that would have been deleted if
 * we'd had one, then insert blank lines to move the rest
 * of the screen back to where it belongs.  This idea from
 * the Heath driver.
 */
VOID ttinsl(row, bot, nchunk)
{
	if (row == bot) {			/* Funny case.		*/
		if (nchunk != 1)
			panic("ttinsl: nchunk != 1");
		ttmove(row, 0);
		tteeol();
		return;
	} 
	ttmove(1+bot-nchunk, 0);
	if (nchunk > 0) {		/* Delete a chunk of lines	*/
		ttputc(ESC);		/* nchunk in size.  Rest of	*/
		ttputc('[');		/* screen moves up.		*/
		asciiparm(nchunk);
		ttputc('M');
	}
	ttmove(row, 0);
	if (nchunk > 0) {		/* Insert a chunk nchunk in size*/
		ttputc(ESC);		/* before current line,	sliding	*/
		ttputc('[');		/* rest of screen down.		*/
		asciiparm(nchunk);
		ttputc('L');
	}
	ttrow = row;			/* End up on current line	*/
	ttcol = 0;
}

/*
 * Delete a block of lines, with the uppermost
 * line at row "row", in a screen slice that extends to
 * row "bot". The "nchunk" is the number of lines that have
 * to be deleted.  This is done by deleting nchunk lines at the
 * appropriate spot, then inserting nchunk lines to make up for
 * the empty space at the bottom of the virtual scrolling region.
 */
VOID ttdell(row, bot, nchunk)
{
	if (row == bot) {		/* One line special case	*/
		ttmove(row, 0);
		tteeol();
		return;
	}
	if (nchunk > 0) {
		ttmove(row, 0);
		ttputc(ESC);
		ttputc('[');
		asciiparm(nchunk);
		ttputc('M');
	}
	ttmove(1+bot-nchunk,0);
	if (nchunk > 0) {
		ttputc(ESC);		/* For all lines in chunk	*/
		ttputc('[');		/* INS line before bottom	*/
		asciiparm(nchunk);	/* Bottom of window (and rest 	*/
		ttputc('L');		/* of screen) moves down */
	}
	ttrow = HUGE;
	ttcol = HUGE;
	ttmove(bot-nchunk,0);
}

/*
 * No-op.
 */
ttwindow(top,bot)
{
}

/*
 * No-op.
 */
ttnowindow()
{
}

#ifdef	CHANGE_COLOR
/*
 * Set the rendition of the mode line by
 * selecting colors from the following:
 *	0 -- plain text
 *	1 -- bold-face
 *	3 -- italic
 *	4 -- underscore
 *	7 -- inverse video
 * Certain of these selections may be less than
 * appealing :-)
 */

ttmode(f, n, k)
{
	register int	s;
	char		buf[2];

	if (f == FALSE) {
		if ((s = ereply("Set mode line rendition (0-7): ",
				buf, sizeof(buf))) != TRUE)
			return (s);
		n = atoi(buf);
	}
	if (n < 0 || n > 7)
		return (FALSE);

	mode_rendition = n;		/* store the color	*/
	sgarbf = TRUE;
	return (TRUE);
}

/*
 * Set the rendition of the text area.
 * Most of these selections will be
 * less than appealing :-]
 */

tttext(f, n, k)
{
	register int	s;
	char		buf[2];

	if (f == FALSE) {
		if ((s = ereply("Set text rendition (0-7): ",
				buf, sizeof(buf))) != TRUE)
			return (s);
		n = atoi(buf);
	}
	if (n < 0 || n > 7)
		return (FALSE);

	text_rendition = n;		/* store the color	*/
	sgarbf = TRUE;
	return (TRUE);
}

/*
 * Set foreground color for entire window
 * to a value between 30 and 37, which
 * corresponds to the arguments 0-7.
 * This requires a total refresh, which
 * sets up the screen.
 */

textforeground(f, n, k)
{
	register int	s;
	char		buf[2];

	if (f == FALSE) {
		if ((s = ereply("Text foreground color (0-7): ",
				buf, sizeof(buf))) != TRUE)
			return (s);
		n = atoi(buf);
	}
	if (n < 0 || n > 7)
		return (FALSE);

	text_fg = n + 30;
	sgarbf = TRUE;
	return (TRUE);
}

/*
 * Set background color for entire window
 * to a value between 40 and 47 inclusive.
 */

textbackground(f, n, k)
{
	register int	s;
	char		buf[2];

	if (f == FALSE) {
		if ((s = ereply("Text background color (0-7): ",
				buf, sizeof(buf))) != TRUE)
			return (s);
		n = atoi(buf);
	}
	if (n < 0 || n > 7)
		return (FALSE);

	text_bg = n + 40;
	sgarbf = TRUE;
	return (TRUE);
}

/*
 * Set foreground color for entire the mode line
 */

modeforeground(f, n, k)
{
	register int	s;
	char		buf[2];

	if (f == FALSE) {
		if ((s = ereply("Mode line foreground color (0-7): ",
				buf, sizeof(buf))) != TRUE)
			return (s);
		n = atoi(buf);
	}
	if (n < 0 || n > 7)
		return (FALSE);

	mode_fg = n + 30;
	sgarbf = TRUE;
	return (TRUE);
}

/*
 * Set background color for the mode line
 */

modebackground(f, n, k)
{
	register int	s;
	char		buf[2];

	if (f == FALSE) {
		if ((s = ereply("Mode line background color (0-7): ",
				buf, sizeof(buf))) != TRUE)
			return (s);
		n = atoi(buf);
	}
	if (n < 0 || n > 7)
		return (FALSE);

	mode_bg = n + 40;
	sgarbf = TRUE;
	return (TRUE);
}
#endif

/*
 * Set the current writing color to the
 * specified color. Watch for color changes that are
 * not going to do anything (the color is already right)
 * and don't send anything to the display.
 */

ttcolor(color)
register int	color;
{
	if (color != tthue) {
		if (color == CTEXT) {		/* Normal video.	*/
			ttputc(ESC);		/* Reset to 0		*/
			ttputc('[');
			ttputc('m');
			ttputc(ESC);		/* Set text style	*/
			ttputc('[');
			asciiparm(text_rendition);
			ttputc(';');
			asciiparm(text_fg);
			ttputc(';');
			asciiparm(text_bg);
			ttputc('m');
		} else if (color == CMODE) {	/* Standout mode	*/
			ttputc(ESC);		/* Reset to 0		*/
			ttputc('[');
			ttputc('m');
			ttputc(ESC);		/* Set standout mode	*/
			ttputc('[');
			asciiparm(mode_rendition);
			ttputc(';');
			asciiparm(mode_fg);	/* Use mode line colors	*/
			ttputc(';');
			asciiparm(mode_bg);
			ttputc('m');
		}
		tthue = color;			/* Save the color.	*/
	}
}

/*
 * This routine is called by the
 * "refresh the screen" command to try and resize
 * the display. The new size, which must be deadstopped
 * to not exceed the NROW and NCOL limits, is stored
 * back into "nrow" and "ncol". Display can always deal
 * with a screen NROW by NCOL. Look in "window.c" to
 * see how the caller deals with a change.
 * On the Amiga, we make the Intuition terminal driver
 * do all the work.
 */

ttresize()
{
 	setttysize();
}
SHAR_EOF
fi # end of overwriting check
if test -f 'tty/amiga/ttyio.c'
then
	echo shar: will not over-write existing file "'tty/amiga/ttyio.c'"
else
cat << \SHAR_EOF > 'tty/amiga/ttyio.c'
/*
 * Name:	MicroEmacs
 *		Amiga terminal-dependent I/O (Intuition)
 * Created:	21-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
 */
 
/*
 * Lots of includes.
 */

#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/tasks.h>
#include <exec/ports.h>
#include <exec/io.h>
#include <devices/console.h>
#include <libraries/dos.h>
#include <graphics/clip.h>
#include <graphics/view.h>
#include <graphics/rastport.h>
#include <graphics/layers.h>
#include <graphics/text.h>
#include <graphics/gfxbase.h>
#include <intuition/intuition.h>
#ifdef	CHANGE_FONT
#include <libraries/diskfont.h>
#endif

#undef	TRUE			/* avoid redefinition messages 		*/
#undef	FALSE
#include "def.h"		/* includes sysdef.h and ttydef.h	*/

/*
 * External Amiga functions.  Declared explicitly
 * to avoid problems with different compilers.
 */
extern	LONG			 AbortIO();
extern	LONG			 CloseDevice();
extern	LONG			 CloseLibrary();
extern	LONG			 CloseWindow();
extern	struct	MsgPort		*CreatePort();
extern	struct	IOStdReq	*CreateStdIO();
extern	LONG			 DeletePort();
extern	LONG			 DeleteStdIO();
extern	struct	IntuiMessage	*GetMsg();
extern	int			 OpenConsole();
extern	char			*OpenLibrary();
extern	struct	Window		*OpenWindow();
#ifdef	CHANGE_FONT
extern	struct TextFont		*OpenDiskFont();
#endif
extern	LONG			 RectFill();
extern	LONG			 ReplyMsg();
extern	LONG			 SetAPen();
extern	LONG			 SetDrMd();
extern	LONG			 Wait();

#ifdef	DO_MENU
extern	LONG			 ClearMenuStrip();	/* menu functions */
extern	struct	Menu		*InitEmacsMenu();
extern	struct	MenuItem	*ItemAddress();
extern	LONG			 SetMenuStrip();
#endif

extern	int	Enable_Abort;		/* Do NOT allow abort!		*/

/*
 * External MicroEmacs functions and variables
 */
extern	int	quit();			/* Defined by "main.c"	*/
extern	char	*version;		/* Version information		*/

/*
 * Library bases (used by glue libraries)
 */
struct	IntuitionBase	*IntuitionBase;
struct	GfxBase		*GfxBase;
#ifdef	CHANGE_FONT
ULONG			DiskfontBase;
#endif

/*
 * Intuition window and menu variables
 */
#define WINDOWGADGETS (WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE)

static short	borderless = TRUE;	/* Flag for borderless window	*/
static short	leftedge = 0,		/* Last top left position	*/
		topedge = 0,
		width = 640,
		height = 200;

struct NewWindow MicroEMACS = {
	0,	0,			/* start position       	*/
	0,	0,			/* width, height (set by ttopen)*/
	0,	1,	     		/* detail pen, block pen	*/
#ifdef	DO_MENU
	MENUPICK |			/* If menu is used		*/
#endif
#ifdef	MOUSE
	MOUSEBUTTONS | 			/* If mouse is used		*/
#endif
	CLOSEWINDOW | NEWSIZE,		/* IDCMP flags			*/
	0,				/* window flags	(set by ttopen)	*/
	NULL,				/* pointer to first user gadget */
	NULL,				/* pointer to user checkmark	*/ 
	NULL,				/* title (filled in later)	*/
	NULL,				/* pointer to screen (none)	*/
	NULL,				/* pointer to superbitmap	*/
	359,101,			/* minimum size (with TOPAZ_80)	*/
	0, 0,				/* maximum size (set by ttopen)	*/
	WBENCHSCREEN			/* screen in which to open	*/ 
};

struct Window	*EmW;				/* Our window		*/
static short		toggling = FALSE;	/* Prevent menu wiping	*/

#ifdef	DO_MENU
static struct Menu	*EmacsMenu = NULL;	/* Our menu		*/
#endif
#ifdef	CHANGE_FONT
static	struct TextFont *EmFont = NULL;
#endif

/*
 * The bridge between Intuition events and Emacs' single
 * input stream...
 */
static USHORT		class,			/* Intuition event	*/
			code,			/*   information	*/
			qualifier;
static APTR		address;
static SHORT		x, y;
static LONG		intuitionMsgBit;	/* Signal bit		*/
#define INTUITION_MESSAGE ((LONG) (1L << intuitionMsgBit))

/*
 * To more thoroughly handle Intuition events, we buffer
 * them into a circular queue until other routines ask
 * for the information carried in them.
 */
#define	NIBUF	256			/* Rather roomy...		*/
#define	EVT_KBD		0
#define	EVT_MOUSE	1
#define EVT_MENU	2
#define NULLEVT	((struct event *) 0)

struct	event {
	USHORT type;			/* What is it?			*/
	union	{
		UBYTE	ch;		/* Keyboard event		*/
		struct {		/* Mouse click			*/
			SHORT row, col;	/* location in character raster	*/
			USHORT qualifier;
		} mouse;
		USHORT	code;		/* Menu event			*/
	} data;
}		ibuf[NIBUF];		/* Input buffer			*/
int		ibufo, nibuf;		/* head, # of bytes in ibuf	*/

/*
 * Console output
 */
#define	CSI	0x9b			/* Command Sequence Introducer	*/
#define	ESC	0x1b			/* Escape key			*/
#define	NOBUF	512			/* About 1/4 screen		*/

static struct MsgPort	*consoleWritePort;	/* I/O ports 		*/
static struct MsgPort	*consoleReadPort;	
static struct IOStdReq	*consoleWriteMsg;	/* I/O messages		*/
static struct IOStdReq	*consoleReadMsg;
static LONG		consoleMsgBit;		/* signal bit		*/
#define CONSOLE_MESSAGE ((LONG) (1L << consoleMsgBit))
static unsigned char	letter;			/* Console input buffer	*/

static unsigned char	obuf[NOBUF];	/* Terminal output buffer	*/
int			nobuf;		/* # of bytes in above		*/
int			nrow;		/* Terminal size, rows.		*/
int			ncol;		/* Terminal size, columns.	*/
extern int		ttrow;		/* Current cursor row		*/

/*
 * Open up the virtual terminal MicroEMACS communicates with.
 * Set up the window, console, and menu strip.
 */

ttopen()
{
	register struct Screen *s;

	Enable_Abort = 0;				/* Disable ^C	*/

	GfxBase = (struct GfxBase *)
		OpenLibrary("graphics.library", (LONG) 0);
	if (GfxBase  == NULL)				/* Graphics lib	*/
		cleanup(1);

	IntuitionBase = (struct IntuitionBase *)	/* Intuition	*/
		OpenLibrary("intuition.library", (LONG) 0);
	if (IntuitionBase == NULL)
		cleanup(2);

#ifdef	CHANGE_FONT
	DiskfontBase = (ULONG) OpenLibrary("diskfont.library", (LONG)0);
	if (DiskfontBase == NULL)
		cleanup(21);
#endif
	/*
	 * Create our window. Set window flags based on the current
	 * value of the borderless flag, and the maximum size of the
	 * window based on the size of the first screen in the screen
	 * list with screen type WBENCHSCREEN (of which there had better
	 * be *EXACTLY* one, right???...).  To avoid possible crashes
	 * if user is moving screens around, turn off multitasking
	 * during the loop.
	 */
	Forbid();	/* user might be moving screen */
	for (s = IntuitionBase->FirstScreen; s ; s = s->NextScreen)
		if ((s->Flags & SCREENTYPE) == WBENCHSCREEN)
			break;
	MicroEMACS.MaxWidth = s->Width;
	MicroEMACS.MaxHeight = s->Height;
	Permit();

	/* Set the window size based on the last one that was open,
	 * if it was borderless. Otherwise make it fill the screen.
	 * Set max/min widths based on current screen size.
	 *
	 * Set flags and window title, then open window
	 */
	if (borderless) {
		MicroEMACS.Flags = WINDOWGADGETS | ACTIVATE | BORDERLESS;
#ifdef	TOGGLE_ZOOMS
		MicroEMACS.LeftEdge = 0;
		MicroEMACS.TopEdge = 0;
		MicroEMACS.Width = MicroEMACS.MaxWidth;
		MicroEMACS.Height = MicroEMACS.MaxHeight;
#endif
	} else {
		MicroEMACS.Flags = WINDOWGADGETS | ACTIVATE | WINDOWSIZING;
#ifndef	TOGGLE_ZOOMS
	}
#endif
		MicroEMACS.LeftEdge = leftedge;
		MicroEMACS.TopEdge = topedge;
		MicroEMACS.Width = width;
		MicroEMACS.Height = height;
#ifdef	TOGGLE_ZOOMS
	}
#endif
	MicroEMACS.Title = (UBYTE *) version;	/* name for window */
	if ((EmW = OpenWindow(&MicroEMACS)) == NULL)
		cleanup(3);

#ifdef	CHANGE_FONT
	/* If the user requested a different font for the text, EmFont
	 * will be non-null, so set the font for the RastPort.  The
	 * conole device will pick this up when we open it later on.
	 */
	if (EmFont)
		SetFont(EmW->RPort, EmFont);
#endif

	/* Once the window is created, get the Intuition signal bit,
	 * set up the menu, and tell the virtual terminal how big
	 * it is.
 	 */
	intuitionMsgBit = EmW->UserPort->mp_SigBit;
#ifdef	DO_MENU
	if (toggling == FALSE)
		EmacsMenu = InitEmacsMenu(EmW);
	SetMenuStrip(EmW, EmacsMenu);
#endif
	setttysize();

	/* Set up the console device.  Create the necessary read/write
	 * ports and messages, attach the console device thus created
	 * to our window, initialize the console input buffer, and
	 * queue the first read to the console.
	 */

	consoleWritePort = CreatePort("Emacs.con.write",(LONG) 0);
	if (consoleWritePort == NULL)
		cleanup(4);
	consoleWriteMsg = CreateStdIO(consoleWritePort);
	if (consoleWriteMsg == NULL)
		cleanup(5);

	consoleReadPort = CreatePort("Emacs.con.read",(LONG) 0);
	if (consoleReadPort == NULL)
		cleanup(6);
	consoleReadMsg = CreateStdIO(consoleReadPort);
	if (consoleReadMsg == NULL)
		cleanup(7);

	if (OpenConsole(consoleWriteMsg,consoleReadMsg,EmW) != 0)
		cleanup(8);
	consoleMsgBit = consoleReadPort->mp_SigBit;

	QueueRead(consoleReadMsg,&letter);
	nibuf = ibufo = 0;

	return (0);
}

/*
 * Close the virtual terminal, aborting any
 * I/O to the console device and de-allocating
 * everything we have allocated.
 */
ttclose()
{
	ttflush();
	AbortIO(consoleReadMsg);
	CloseDevice(consoleWriteMsg);
	cleanup(0);
	Enable_Abort = 1;
}

/*
 * Toggle between a borderless window
 * and a sizeable window. This lets you
 * use the whole screen if you want.
 * Bound to "toggle-window-hack" by
 * ttykbd.c
 */

togglewindow(f, n, k)
{
	toggling = TRUE;			/* Notify the system	*/
#ifdef	TOGGLE_ZOOMS
	if (!borderless) {
#endif
		leftedge = EmW->LeftEdge;	/* save window state	*/
		topedge = EmW->TopEdge;
		width = EmW->Width;
		height = EmW->Height;
#ifdef	TOGGLE_ZOOMS
	}
#endif
	ttclose();				/* reset to zero	*/

	borderless = !borderless;		/* toggle window flag	*/
	ttopen();				/* re-open tty window	*/
	sgarbf = TRUE;				/* screen was trashed	*/
	nrow = ncol = -1;			/* trash screen size	*/
	refresh();				/* and redraw it	*/
	toggling = FALSE;			/* Ok, done		*/
	return (TRUE);
}

#ifdef	CHANGE_FONT
/*
 * Select a different font for the Emacs window.
 * This obviously does not work very well
 * with proportional fonts, so we ask the
 * user to confirm before he uses one.
 * It's available if you want to be able
 * to use your own disk font (or Topaz 15
 * under 1.2) to edit with.
 */

setfont(f, n, k)
{
	register int	s, size;
	register struct TextFont *newfont;
	char		fontname[80], fontpath[84], fontsize[3];
	struct TextAttr	ta;

	/* Get font size */
	if (f == TRUE)
		size = n;
	else {
		if ((s = ereply("Font size: ",
				fontsize, sizeof(fontsize))) != TRUE)
			return (s);
		size = atoi(fontsize);
	}

	if (size <= 0) {	/* reset to default font	*/
		if (EmFont)
			CloseFont(EmFont);
		EmFont = NULL;
	} else {		/* user wants to set a new font name */
		if ((s = ereply("Font name (e.g. topaz): ",
				fontname, sizeof(fontname))) != TRUE)
			return (s);
		strcpy(fontpath,fontname);
		strncat(fontpath,".font",sizeof(fontpath));/* make name */

		/* set up text attributes */
		ta.ta_Name = (UBYTE *)fontpath;
		ta.ta_YSize = size;
		ta.ta_Style = FS_NORMAL;
		ta.ta_Flags = 0; /* use either */

		/* Look for the font */
		ewprintf("Looking for %s %d...",fontname,size);
		if ((newfont = OpenDiskFont(&ta)) == NULL) {
			ewprintf("Can't find %s %d!",fontname,size);
			return (FALSE);
		} else { /* Found it! Check before using it. */
			if ((newfont->tf_YSize != size) && ((s = eyesno(
			   "Size unavailable - use closest"))!=TRUE)){
				CloseFont(newfont);
				return (FALSE);
			}
			if ((newfont->tf_Flags & FPF_PROPORTIONAL) &&
			    (((s = eyesno("Use proportional font")))!=TRUE)){
				CloseFont(newfont);
				return (FALSE);
			}
			/* Get rid of old font and cache the new one */
			if (EmFont)
				CloseFont(EmFont);
			EmFont = newfont;
		}
	}

	/* Now that the font is selected, close the window. */
	toggling = TRUE;			/* Notify the system	*/
	ttclose();				/* reset to zero	*/
	ttopen();				/* re-open w/new font	*/
	nrow = -1;				/* trash size		*/
	ncol = -1;				/* so refresh() works	*/
	refresh();				/* redo whole screen	*/
	if (size > 0)
		ewprintf("Now using font %s %d",fontname,EmFont->tf_YSize);
	else
		ewprintf("Now using default font");
	return (TRUE);
}
#endif

/*
 * Write a single character to the screen.
 * Buffered for extra speed, so ttflush()
 * does all the work.
 */
ttputc(c)
unsigned char c;
{
	obuf[nobuf++] = c;
	if (nobuf >= NOBUF)
		ttflush();
}

/*
 * Flush characters from the output buffer.
 * Just blast it out with a console write call.
 */
ttflush()
{
	if (nobuf > 0) {
		ConWrite(consoleWriteMsg, obuf, nobuf);
		nobuf = 0;
	}
}

/*
 * Get a character for Emacs, without echo or
 * translation.  Basically, handle Intuition
 * events until we get one that signifies
 * a character was typed in some way.
 */
ttgetc()
{
	register struct	IntuiMessage *message;	/* IDCMP message 	*/
	register LONG		wakeupmask;	/* which signals?	*/
	register int	charfound;		/* got a character yet?	*/
	unsigned char	nextchar();		/* return next char evt	*/

	if (striptochar())			/* any chars in buffer?	*/
		return (int) (nextchar() & 0xFF);

	charfound = FALSE;			/* nope -- have to wait	*/
	do {
		wakeupmask = Wait(INTUITION_MESSAGE|CONSOLE_MESSAGE);

		if (wakeupmask & CONSOLE_MESSAGE) {	/* keyboard	 */
			GetMsg(consoleReadPort);	/* free message	 */
			qchar(letter);			/* do this FIRST */
			QueueRead(consoleReadMsg, &letter);
			charfound = TRUE;
		}

		if (wakeupmask & INTUITION_MESSAGE)	/* Intuition	*/
			while(message =	GetMsg(EmW->UserPort))
				if (dispatch(message) == TRUE)
					charfound = TRUE;
	} while (charfound == FALSE);

	return (int) (nextchar() & 0xFF);		/* found a character!	*/
}

/*
 * Handle the events we handle...  The result
 * returned indicates if we've put a character
 * in the input buffer.
 */
static dispatch(msg)
register struct IntuiMessage *msg;
{
#ifdef	DO_MENU
	register struct	MenuItem	*item;
#endif
	register int			txheight, txwidth;
	register struct RastPort	*rp;
	int				dx, dy, fgpen, drmode;
			
	class =	msg->Class;		/* grab the info before we 	*/
	code = msg->Code;		/* reply to the message		*/
	qualifier = msg->Qualifier;
	address = msg->IAddress;
	x = msg->MouseX;
	y = msg->MouseY;
	ReplyMsg(msg);			/* return it to Intuition	*/

	switch(class) {			/* see what the fuss is about	*/
#ifdef	DO_MENU
	case MENUPICK:
		if (code == MENUNULL)
			return (FALSE);
		while (code != MENUNULL) {/* handle multiple selection	*/
			qmenu(code);
			item = ItemAddress(EmacsMenu,(LONG) code);
			code = item->NextSelect;
		}
		return (TRUE);		/* puts <CSI>M~ in event queue	*/
		break;
#endif

#ifdef	MOUSE
	case MOUSEBUTTONS:			/* fake the mouse key	*/
		if (code != SELECTDOWN)		/* ignore SELECTUP	*/
			return (FALSE);
		qmouse(x, y, qualifier);
		return (TRUE);
		break;
#endif
	case NEWSIZE:
		/* Sometimes when you resize the window to make it
		 * smaller, garbage is left at the right and bottom
		 * sides of the window. This code is devoted to
		 * (somehow) getting rid of this garbage.  Any
		 * suggestions?
		 */

		rp = EmW->RPort;
		fgpen = rp->FgPen;		/* save params		*/
		drmode = rp->DrawMode;
		SetDrMd(rp, (LONG) JAM1);
		SetAPen(rp, (LONG) EmW->RPort->BgPen);

		/* Check the bottom of the window
		 */
		txheight = EmW->Height - EmW->BorderTop - EmW->BorderBottom;
		if (dy = (txheight % FontHeight(EmW)))
			RectFill(rp,
				(LONG) EmW->BorderLeft,
				(LONG) EmW->BorderTop + txheight - dy - 1,
				(LONG) (EmW->Width - 1) - EmW->BorderRight,
				(LONG) (EmW->Height - 1) - EmW->BorderBottom);

		/* Check the right side
		 */
		txwidth = EmW->Width - EmW->BorderLeft - EmW->BorderRight;
		if (dx = txwidth % FontWidth(EmW))
			RectFill(rp,
				(LONG) EmW->BorderLeft + txwidth - dx - 1,
				(LONG) EmW->BorderTop,
				(LONG) (EmW->Width - 1) - EmW->BorderRight,
				(LONG) (EmW->Height - 1) - EmW->BorderBottom);

		SetDrMd(rp, (LONG) drmode);
		SetAPen(rp, (LONG) fgpen);	/* restore colors */

		/* Tell the console device to resize itself */
		ttputc(CSI);
		ttputc('t');
		ttputc(CSI);
		ttputc('u');
		ttflush();

		/* Signal the editor that a new size has occurred */
		qchar(ESC);
		qchar('\f');

		return (TRUE);			/* we done (finally)	*/
		break;

        case CLOSEWINDOW:			/* Call quit() directly	*/
		quit(FALSE, 1, KRANDOM);
		return (FALSE);
                break;
	default:
		panic("HandleMsg: unknown event!!!");
		break;
	}
	return(FALSE);
}

#ifdef	DO_MENU
/*
 * Return the next menu selection number to
 * the caller.  Used by "ttymenu.c".
 */
ttmenu(codep)
USHORT *codep;
{
	register struct event *e;
	struct event *nextevt();

	e = nextevt();
	if (e->type != EVT_MENU)
		return (FALSE);

	*codep = e->data.code;
	remevt();			/* remove event by hand	*/
	return (TRUE);
}
#endif

#ifdef	MOUSE
/*
 * Return the next mouse click values to
 * the caller.   *Rowp and *colp will contain
 * the row and column where the mouse click occured.
 * This is so that only the terminal driver has
 * to know about the size of the window's font.
 * If the flag argument f is FALSE, the mouse event
 * is *not* removed from the queue, allowing routines
 * that need to (mainly getmouse()) to peek at it.
 */
ttmouse(f, rowp,colp,qualp)
int f;
USHORT *rowp, *colp, *qualp;
{
	register struct event *e;
	struct event *nextevt();

	e = nextevt();
	if (e->type != EVT_MOUSE)
		return (FALSE);		/* next isn't mouse evt */

	*colp = e->data.mouse.col;
	*rowp = e->data.mouse.row;
	*qualp = e->data.mouse.qualifier;
	if (f)
		remevt();			/* remove the event	*/
	return (TRUE);
}
#endif

/*
 * Return the current size of the virtual
 * terminal in nrow and ncol, making sure
 * we don't go beyond the size of the internal
 * video array.
 * Assumes the current font is monospaced
 * (not always safe bet any more :-) :-).
 */
setttysize()
{
	nrow = (EmW->Height - EmW->BorderTop
			- EmW->BorderBottom) / FontHeight(EmW);
	ncol = (EmW->Width - EmW->BorderLeft
			- EmW->BorderRight) / FontWidth(EmW);
	if (nrow < 1)
		nrow = 1;
	if (nrow > NROW)
		nrow = NROW;
	if (ncol < 1)
		ncol = 1;
	if (ncol > NCOL)
		ncol = NCOL;
}

/*
 * Exit as soon as possible, after displaying
 * the message.
 */
panic(s)
char *s;
{
	ewprintf(s);		/* put message at bottom	*/
	Delay((ULONG) 90);	/* wait 1.5 seconds		*/
	ttclose();		/* get rid of window &resources	*/
	exit(10000);		/* go 'way			*/
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *			 Event buffer management		 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*
 * If the buffer's full, crap out, else
 * return a pointer to the (ibufo + nibuf)'th
 * event record (mod NIBUF).  Postincrement
 * nibuf so it points at the next record and
 * also keeps track of how many events
 * are in the buffer.
 */
static struct event *newevt()
{
	return ((nibuf < NIBUF) ? 
		(ibuf + ((ibufo + nibuf++) % NIBUF)) : NULLEVT);
}

/*
 * Return pointer to next item in queue,
 * *without* removing it.
 */
static struct event *nextevt()
{
	return (nibuf ? (ibuf + ibufo) : NULLEVT);
}

/*
 * Move buffer pointer to next item in queue.
 */
static remevt()
{
	if (nibuf <= 0)
		nibuf = 0;
	else {
		nibuf--;
		ibufo++;
		ibufo %= NIBUF;		/* wrap around in buffer	*/
	}
}

/*
 * Return true if there are some characters available
 * in the buffer.  Unlike striptochar, don't do anything
 * to the input buffer, just return a value.
 */
typeahead()
{
	register int bufp;

	for (bufp = 0; bufp < nibuf; bufp++)
		if (ibuf[(ibufo + bufp) % NIBUF].type == EVT_KBD)
			return (TRUE);
	return (FALSE);
}

/*
 * See if there are any characters queued,
 * stripping any other events that may
 * be in the way.  *Don't* remove the character
 * from the  queue.
 */
static striptochar()
{
	register struct event *e;

	while (e = nextevt())
		if (e->type == EVT_KBD)
			return (TRUE);
		else
			remevt();
	return (FALSE);
}

/*
 * Return next character in event buffer.
 */
static unsigned char nextchar()
{
	register struct event *e;

	if (e = nextevt()) {
		remevt();
		return (e->data.ch);
	}
	else
		return ((unsigned char) 0);	/* shouldn't happen	*/
}

/*
 * Add a keyboard event to the queue
 */
static qchar(c)
unsigned char c;
{
	register struct event *e;

	if (e = newevt()) {
		e->type = EVT_KBD;
		e->data.ch = c;
	}
}

#ifdef	MOUSE
/*
 * Add a mouse event to the queue, calculating
 * the row and column value from the current height
 * and width of the window's font.
 */
static qmouse(x, y, qual)
SHORT x, y;
USHORT qual;
{
	register struct event *e;

	qchar(CSI);
	qchar('P');
	qchar('~');
	if (e = newevt()) {
		e->type = EVT_MOUSE;
		e->data.mouse.col = (x - EmW->BorderLeft) / FontWidth(EmW);
		e->data.mouse.row = (y - EmW->BorderTop) / FontHeight(EmW);
		e->data.mouse.qualifier = qual;
	}
}
#endif

#ifdef	DO_MENU
/*
 * Add a menu key to queue
 */
static qmenu(code)
USHORT code;
{
	register struct event *e;

	qchar(CSI);		/* menu key sequence	*/
	qchar('M');
	qchar('~');
	if (e = newevt()) {
		e->type = EVT_MENU;
		e->data.code = code;
	}
}
#endif

/*
 * Clean up.
 *
 * Fall through all the possible cases (0 means
 * get rid of everything and start with the case
 * that fits the error situation).
 */

static cleanup(prob)
{
	switch (prob) {
	case 0:			/* just clean everything up

	case 8:			/* couldn't open console device		*/
		DeleteStdIO(consoleReadMsg);
	case 7:			/* couldn't get console read msg	*/
		DeletePort(consoleReadPort);
	case 6:			/* couldn't get console read port	*/
		DeleteStdIO(consoleWriteMsg);
	case 5:			/* couldn't get console write msg	*/
		DeletePort(consoleWritePort);
	case 4:			/* couldn't get console write port	*/
#ifdef	CHANGE_FONT
		if ((toggling == FALSE) && EmFont)
			CloseFont(EmFont);/* access_count-- */
#endif
#ifdef	DO_MENU
		if (toggling == FALSE) {
			ClearMenuStrip(EmW);
			DisposeMenus(EmacsMenu);
		}
#endif
		CloseWindow(EmW);
	case 3:			/* couldn't open window			*/
#ifdef	CHANGE_FONT
		CloseLibrary(DiskfontBase);
#endif
	case 21:		/* couldn't open DiskfontBase		*/
		CloseLibrary(IntuitionBase);
	case 2:			/* couldn't open IntuitionBase		*/
		CloseLibrary(GfxBase);
	case 1:			/* couldn't open GfxBase -- do nothing	*/
		break;
	}
        return(0);
}

SHAR_EOF
fi # end of overwriting check
if test -f 'tty/amiga/ttymenu.c'
then
	echo shar: will not over-write existing file "'tty/amiga/ttymenu.c'"
else
cat << \SHAR_EOF > 'tty/amiga/ttymenu.c'
/*
 * ttymenu.c
 *
 * Incorporates the browser, for rummaging around on disks,
 * and the usual Emacs editing command menu
 *
 *	Copyright (c) 1986, Mike Meyer
 *	Manxification and Edit menu by Mic Kaczmarczik (no charge :-)
 *
 * Permission is hereby granted to distribute this program, so long as
 * this source file is distributed with it, and this copyright notice
 * is not removed from the file.
 *
 */

#include <exec/types.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <intuition/intuition.h>
#undef	TRUE
#undef	FALSE
#include "def.h"

extern struct Menu		*AutoMenu ;
extern struct Window		*EmW ;

#define MNUM(menu,item,sub) (SHIFTMENU(menu)|SHIFTITEM(item)|SHIFTSUB(sub))

#ifdef	BROWSER
#define LONGEST_NAME	80	/* Longest file name we can deal with	*/

# ifndef	MANX
char *strchr(char *, int);
# else
char *index();			/* find first instance of c in s	*/
#define	strchr(s, c) index(s, c)
# endif

# ifdef	MENU
#define	FIRSTMENU	1
# else
#define	FIRSTMENU	0
# endif

#endif	BROWSER

#ifdef	MENU
/*
 * When ttgetc() sees a menu selection event, it stuffs
 * the sequence <CSI>M~ into the input buffer, and
 * caches the menu number and item number for later.
 * This sequence is translated into the internal key code
 * KMENU, similar to KHELP and the other function keys.
 *
 * The menu item names are chosen to be relatively close
 * to the extended function names, so a user can usually
 * figure out the key binding of a menu item by searching
 * through the "display-bindings" buffer for something
 * that's close.
 */

/*
 * Commands for managing files and buffers
 */

static struct MenuBinding FileItems[] = {
	{ "Find File         C-x C-f",	"find-file"			},
	{ "Pop To File       C-x 4 f",	"find-file-other-window"	},
	{ "Insert File       C-x i",	"insert-file"			},
	{ "Save File         C-x C-s",	"save-buffer"			},
	{ "Write File        C-x C-w",	"write-file"			},
	{ "Switch To Buffer  C-x b",	"switch-to-buffer"		},
	{ "Pop To Buffer     C-x 4 b",	"switch-to-buffer-other-window"	},
	{ "Kill Buffer       C-x k",	"kill-buffer"			},
	{ "List Buffers      C-x C-b",	"list-buffers"			},
	{ "Save Buffers      C-x s",	"save-some-buffers"		},
	{ "Save And Exit     C-x C-c",	"save-buffers-kill-emacs"	}
};

/*
 * Commands for various editing functions
 */

static struct MenuBinding EditItems[] = {
	{ "Yank                 C-y",	"yank"				},
	{ "Blank Line           C-o ",	"open-line"			},
	{ "Kill Line            C-k",	"kill-line"			},
	{ "Delete Blank Lines   C-x C-o","delete-blank-lines"		},
	{ "Delete Blanks        M-SPC",	"just-one-space"		},
	{ "Newline And Indent   C-j",	"newline-and-indent"		},
	{ "Transpose Characters C-t",	"transpose-chars"		},
	{ "Quoted Insert        C-q",	"quoted-insert"			}
};

/*
 * Movement commands
 */

static struct MenuBinding MoveItems[] = {
	{ "Scroll Up       C-v",	"scroll-up"			},
	{ "Scroll Down     M-v",	"scroll-down"			},
	{ "Start Of Line   C-a",	"beginning-of-line"		},
	{ "Start Of Buffer M-<",	"beginning-of-buffer"		},
	{ "End Of Line     C-e",	"end-of-line"			},
	{ "End Of Buffer   M->",	"end-of-buffer"			},
	{ "Goto Line",			"goto-line"			},
	{ "Show Cursor     C-x =",	"what-cursor-position"		}
};

/*
 * Commands for searching and replacing
 */

static struct MenuBinding SearchItems[] = {
	{ "I-Search Forward  C-s",	"isearch-forward"	},
	{ "I-Search Backward C-r",	"isearch-backward"	},
	{ "Search Again",		"search-again"		},
	{ "Search Forward    M-s",	"search-forward"	},
	{ "Search Backward   M-r",	"search-backward"	},
	{ "Query Replace     M-%",	"query-replace"		}
};

/*
 * Commands that manipulate words
 */
static struct MenuBinding WordItems[] = {
	{ "Forward Word       M-f",	"forward-word"			},
	{ "Backward Word      M-b",	"backward-word"			},
	{ "Kill Word          M-d",	"kill-word"	 		},
	{ "Backward Kill Word M-DEL",	"backward-kill-word" 		},
	{ "Capitalize Word    M-c",	"capitalize-word"		},
	{ "Downcase Word      M-l",	"downcase-word"			},
	{ "Upcase Word        M-u",	"upcase-word"			}
};

static struct MenuBinding ParaItems[] = {
	{ "Forward Paragraph  M-]",	"forward-paragraph"		},
	{ "Backward Paragraph M-[",	"backward-paragraph"		},
	{ "Fill Paragraph     M-q",	"fill-paragraph"		},
	{ "Set Fill Column    C-x f",	"set-fill-column"		},
	{ "Kill Paragraph",		"kill-paragraph"		},
	{ "Auto Fill Mode",		"auto-fill-mode"		}
};

/*
 * Region stuff
 */

static struct MenuBinding RegionItems[] = {
	{ "Set Mark            C-@",	"set-mark-command"		},
	{ "Exch Point And Mark C-x C-x","exchange-point-and-mark"	},
	{ "Kill Region         C-w",	"kill-region"			},
	{ "Copy Region As Kill M-w",	"copy-region-as-kill"		},
	{ "Downcase Region     C-x C-l","downcase-region"		},
	{ "Upcase Region       C-x C-u","upcase-region"			}
};

/*
 * Commands for manipulating windows
 */

static struct MenuBinding WindowItems[] = {
	{ "Split Window         C-x 2", "split-window-vertically"	},
	{ "Delete Window        C-x 0",	"delete-window"			},
	{ "Delete Other Windows C-x 1",	"delete-other-windows"		},
	{ "Down Window          C-x o",	"next-window"			},
	{ "Up Window",			"previous-window"		},
	{ "Enlarge Window       C-x ^",	"enlarge-window"		},
	{ "Shrink Window",		"shrink-window"			},
	{ "Redraw Display",		"redraw-display"		},
	{ "Recenter             C-l",	"recenter"			},
	{ "Toggle Border",		"toggle-window-hack"		},
#ifdef	CHANGE_FONT
	{ "Set Font",			"set-font"			}
#endif
};

/*
 * Miscellaneous commands
 */

static struct MenuBinding MiscItems[] = {
	{ "Start Kbd Macro   C-x (",	"start-kbd-macro"		},
	{ "End Kbd Macro     C-x )",	"end-kbd-macro"			},
	{ "Call Kbd Macro    C-x e",	"call-last-kbd-macro"		},
	{ "Execute Command   M-x",	"execute-extended-command"	},
	{ "Global Set Key",		"global-set-key"		},
	{ "Global Unset Key",		"global-unset-key"		},
	{ "Describe Key      C-h c",	"describe-key-briefly",		},
	{ "Describe Bindings C-h b",	"describe-bindings"		},
	{ "Emacs Version",		"emacs-version"			},
	{ "New CLI           C-z",	"suspend-emacs"			}
};

/*
 * The following table contains the titles, number of
 * items, and pointers to, the individual menus.
 */

static struct MenuInfo EMInfo[] = {
	{ "File  ",		NITEMS(FileItems),	&FileItems[0]	},
	{ "Edit  ",		NITEMS(EditItems),	&EditItems[0]	},
	{ "Move  ", 		NITEMS(MoveItems),	&MoveItems[0]	},
	{ "Search  ",		NITEMS(SearchItems),	&SearchItems[0] },
	{ "Word  ",		NITEMS(WordItems),	&WordItems[0]	},
	{ "Paragraph  ",	NITEMS(ParaItems),	&ParaItems[0]	},
	{ "Region  ",		NITEMS(RegionItems),	&RegionItems[0]	},
	{ "Window  ",		NITEMS(WindowItems),	&WindowItems[0] },
	{ "Miscellaneous  ",	NITEMS(MiscItems),	&MiscItems[0]	}
};

/* There are three cases to deal with; the menu alone, the Browser
 * alone, and both of them together.  We #define some things to make
 * life a little easier to deal with
 */
# ifdef	BROWSER
#  define Edit_Menu_Init() Menu_Add("Edit ", TRUE) 
#  define Edit_Menu_Add(n) Menu_Item_Add(n,(USHORT)ITEMENABLED,0L,(BYTE)0)
#  define Edit_Item_Add(n) Menu_SubItem_Add(n,(USHORT)ITEMENABLED,0L,(BYTE)0)
# else
#  define Edit_Menu_Init() cinf = NULL	/* harmless */
#  define Edit_Menu_Add(n) n[strlen(n)-1] = '\0'; Menu_Add(n, TRUE)
#  define Edit_Item_Add(n) Menu_Item_Add(n,(USHORT)ITEMENABLED,0L,(BYTE)0)
# endif	BROWSER

#endif	MENU

/*
 * Heeere we go!!!!
 */

struct Menu * InitEmacsMenu(EmW)
struct Window *EmW;
{
#ifdef	MENU
	register struct MenuInfo *cinf, *lastinfo;
	register struct MenuBinding *cb, *lastbinding;
#endif

	Menu_Init() ;			/* init the menu		*/

#ifdef	MENU

	Edit_Menu_Init() ;		/* Set up for editing menu	*/
	lastinfo = &EMInfo[NITEMS(EMInfo)];	/* loop sentinel	*/	
	for (cinf = EMInfo; cinf < lastinfo; cinf++) {
		Edit_Menu_Add(cinf->Name);
		lastbinding = &cinf->Items[cinf->NumItems];
		for (cb = cinf->Items; cb < lastbinding; cb++)
			Edit_Item_Add(cb->Command);
	}
#endif	MENU

#ifdef	BROWSER
	Menu_Add("Disks ", TRUE) ;
	Menu_Item_Add("Df0:", (USHORT) ITEMENABLED, 0L, (BYTE) 0) ;
	Menu_Item_Add("Df1:", (USHORT) ITEMENABLED, 0L, (BYTE) 0) ;
	Menu_Item_Add("Ram:", (USHORT) ITEMENABLED, 0L, (BYTE) 0) ;
#endif	BROWSER

	return 	AutoMenu ;
}

/*
 * amigamenu() -- handles a menu pick.
 */

amigamenu(f, n, k) {
	unsigned short		Menu_Number;
	char			*name;
	int			ttmenu(); /* in ttyio.c */

#ifdef	BROWSER
	register unsigned short	level, i, dirp;
	register char		*cp;
	int			stat;
	struct MenuItem		*ItemAddress() ;

	/* State variables that describe the current directory */
	static char		Dir_Name[LONGEST_NAME] ;
	static unsigned short	Menu_Level = 0 ;
#endif
#ifdef	MENU
	SYMBOL	*sp;
#endif

	if (!ttmenu(&Menu_Number)) return FALSE;	/* get menu number */

#ifndef	BROWSER
# ifdef	MENU
	name = EMInfo[MENUNUM(Menu_Number)].Items[ITEMNUM(Menu_Number)].Binding;
	if ((sp=symlookup(name)) != NULL)
		return ((*sp->s_funcp)(f, n, KRANDOM));
	panic("Unknown menu command!");	/* trouble!	*/
# endif
#else	/* we're using the Browser */
# ifdef	MENU
	/* Handle commands from the Edit menu when using the Browser */
	if (0 == MENUNUM(Menu_Number)) {
		name = EMInfo[ITEMNUM(Menu_Number)].Items[SUBNUM(Menu_Number)].Binding;
		if ((sp=symlookup(name)) != NULL)
			return ((*sp->s_funcp)(f, n, KRANDOM));
		panic("Unknown menu command!");	/* trouble!	*/
	}
# endif
	/* Here when a selection was made in a Browser menu */
	name = (char *)((struct IntuiText *)
		(ItemAddress(AutoMenu,(ULONG) Menu_Number) -> ItemFill))
		-> IText ;
	level = MENUNUM(Menu_Number) - FIRSTMENU;

	/* Got what we want, so clear the menu to avoid confusing the user */
	ClearMenuStrip(EmW) ;

	/* set dirp to FALSE if the name is not a directory or disk */
	dirp = (strchr(name, '/') != NULL || strchr(name, ':') != NULL) ;

	/* First, set the directory name right */
	if (level > Menu_Level)			/* Not possible, die */
		panic("impossible menu_level in amigamenu");
	else if (level == 0)			/* picked a new disk */
		Dir_Name[0] = '\0' ;
	else if (level < Menu_Level) {		/* Throw away some levels */
		for (i = 1, cp = strchr(Dir_Name, ':'); i < level; i++) {
			if (cp == NULL) return FALSE;
			cp = strchr(cp, '/') ;
			}
		if (cp == NULL) panic("broken file name in amigamenu");
		*++cp = '\0' ;
		}
	/* else Menu_Level == level, chose a file a current level */

	/* Now, fix up the menu and it's state variable */
	while (Menu_Level > level) {
		Menu_Level-- ;
		Menu_Pop() ;
		}

	/* If we added a directory, tack it onto the name */
	if (dirp) {
		Menu_Level++ ;
		(void) strncat(Dir_Name, name,
			LONGEST_NAME - strlen(Dir_Name) - 1) ;
		}

	/* Now, tell the user all about it */
	if (dirp) stat = Add_Dir(Dir_Name, name) ;
	else stat = Display_File(Dir_Name, name) ;
	SetMenuStrip(EmW, AutoMenu) ;
	return stat ;
#endif	BROWSER
}

#ifdef	BROWSER
/*
 * Display_File - Go fetch a the requested file into a window.
 */
Display_File(dir, file) char *dir, *file; {
	register BUFFER	*bp, *findbuffer();
	int		s;
	char		File_Name[LONGEST_NAME];

	(void) strcpy(File_Name, dir);
	(void) strncat(File_Name, file, LONGEST_NAME - strlen(File_Name) - 1) ;
	if ((bp = findbuffer(File_Name, &s)) == NULL) return s;
	curbp = bp;
	if (showbuffer(bp, curwp, WFHARD) != TRUE) return FALSE;
	if (bp->b_fname[0] == 0)
		return (readin(File_Name));		/* Read it in.	*/
	return TRUE;
	}
/*
 * Add_Dir - given a dir and a name, add the menu name with the files in
 *	dir as entries.  Use AllocMem() in order to make
 *      sure the file info block is on a longword boundary.
 */
static
Add_Dir(dir, name) char *dir, *name; {
	register char			*last_char ;
	register struct FileLock	*my_lock, *Lock() ;
	unsigned short			count ;
	int				stat = FALSE;
	static char			Name_Buf[LONGEST_NAME] ;
	char				*AllocMem();
	struct	FileInfoBlock		*File_Info;

	if ((File_Info = (struct FileInfoBlock *)
		AllocMem((LONG)sizeof(struct FileInfoBlock), 0L)) == NULL)
		return (FALSE);

	/* Fix up the trailing / if it needs it */
	last_char = &dir[strlen(dir) - 1] ;
	if (*last_char == '/') *last_char = '\0' ;

	/* Now, start on the directory */
	if ((my_lock = Lock(dir, ACCESS_READ)) == NULL) goto out;

	if (!Examine(my_lock, File_Info)) goto out;
	if (File_Info -> fib_DirEntryType < 0L)
		goto out;

	if (Menu_Add(name, TRUE) == 0) return NULL;
	for (count = 0; ExNext(my_lock, File_Info) 
			|| IoErr() != ERROR_NO_MORE_ENTRIES; count++)
		if (File_Info -> fib_DirEntryType < 0L) {
			if (Menu_Item_Add(File_Info -> fib_FileName,
				(USHORT)ITEMENABLED, 0L, (BYTE)0)
					== MNUM(NOMENU, NOITEM, NOSUB))
					break ;
			}
		else {
			(void) strcpy(Name_Buf, File_Info -> fib_FileName) ;
			(void) strcat(Name_Buf, "/") ;
			if (Menu_Item_Add(Name_Buf,
				(USHORT) ITEMENABLED, 0L, (BYTE)0)
					 == MNUM(NOMENU, NOITEM, NOSUB))
				break ;
			}
	if (count == 0) Menu_Item_Add("EMPTY", (USHORT)0, 0L, (BYTE)0) ;

	/* Put everything back */
	if (*last_char == '\0') *last_char = '/' ;
	stat = TRUE;
out:
	UnLock(my_lock) ;
	FreeMem(File_Info, (LONG) sizeof(struct FileInfoBlock));
	return stat;
	}
#endif	BROWSER
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0



More information about the Mod.sources mailing list