DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download
Index: ┃ T t

⟦1efaa58ab⟧ TextFile

    Length: 21582 (0x544e)
    Types: TextFile
    Names: »ttyio.c«

Derivation

└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
    └─ ⟦this⟧ »EUUGD11/euug-87hel/sec1/micrognu/tty/amiga/ttyio.c« 

TextFile

/*
 * 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);
}