 (TRUE);
}

	while (n-- && lback(lp)!=curbp->b_linep)
		lp = lback(lp);
	curwp->w_linep = lp;
	curwp->w_dotp  = lp;
	curwp->w_doto  = 0;
	curwp->w_flag |= WFHARD;
	return (TRUE);
}

/*
 * Set the mark in the current window
 * to the value of dot. A message is written to
 * the echo line unless we are running in a keyboard
 * macro, when it would be silly.
 */
setmark(f, n, k)
{
	isetmark();
	if (kbdmop == NULL)
		eprintf("[Mark set]");
	return (TRUE);
}

/* 
 * So other commands can /*
 * Name:	MicroEMACS
 *		Version stamp.
 * Version:	30
 * Last edit:	14-Feb-86
 * By:		rex::conroy
 *		decvax!decwrl!dec-rhea!dec-rex!conroy
 *
 * This file contains the string(s)
 * that get written out by the show version command.
 * Rich had it generated by a command file. I do
 * it manually, until I can figure out a way to get
 * the MicroEMACS version number generated in a
 * reasonable (automatic) manner. Perhaps a program
 * that reads "things2do.txt".
 */
#include	"def.h"

char	*version[] = {
	"MicroEMACS version 30",
	"Source from REX::USER$A:[CONROY.HACKING.MINIEMACS]",
	NULL
}; 
 curwp->w_marko;
	curwp->w_markp = odotp;
	curwp->w_marko = odoto;
	curwp->w_flag |= WFMOVE;
	return (TRUE);
}

/*
 * Go to a specific line, mostly for
 * looking up errors in C programs, which give the
 * error a line number. If an argument is present, then
 * it is the line number, else prompt for a line number
 * to use.
 */
gotoline(f, n, k)
register int	n;
{
	register                    s                 "           @           
=  R                  1   -                         i     =  ^         1            j               h   )                 N                    6         +         U           	                                           1      E            p                                           A                             (                                S                                          [                     0           (                      "                                 	                                        x                                              6               #                E   a          <              !           (     s#   @#   D H~*@,y   #   ,#   <B   8N(@#    $J g    #   a b |    BN   0X @ h "h  9   @r #   LЁRBgR@UBw   9   @ y   D$ Sԁ    SQ    S    Q"O/	N    p `f# :   a  a  #   8/ $@ * $g,y   0 @"(  N"*  g$<  N#   Hg
 @)h  Hy    N    p ` / / N   J   8g,"9   (gN"9   HgN,y   N|"y   8N .y   <L~NuH.< ,x NL`pd`A \NA \NNuC   Pp N#   0gNu              V            ~  r  \  P  H  ,                       x   L   8   (   "                  ^      }  B           2                                input buffer	*/
USHORT			class,			/* Intuition event	*/
			code,			/*   information	*/
			qualifier;
APTR			address;
SHORT			x, y;

/*
 * Some definitions
 */

#define INTUITION_MESSAGE ((LONG) 1 << intuitionMsgBit)
#define CONSOLE_MESSAGE ((LONG) 1 << consoleMsgBit)

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

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

ttopen()
{
	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);

	/* Create our window */
	MicroEMACS.Title = (UBYTE *) version[0];
	EmacsWindow = OpenWindow(&MicroEMACS);
	if (EmacsWindow == NULL)
		cleanup(2);

	/* Ports for reading and writing */
	consoleWritePort = CreatePort("Emacs.con.write",(LONG) 0);
	if (consoleWritePort == NULL)
		cleanup(5);
	consoleWriteMsg = CreateStdIO(consoleWritePort);
	if (consoleWriteMsg == NULL)
		cleanup(6);

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

	/* attach the console device to our window */
	if (OpenConsole(consoleWriteMsg,consoleReadMsg,EmacsWindow) != 0)
		cleanup(10);

	/* attach a menu strip to the window */
	EmacsMenu = InitEmacsMenu();
	SetMenuStrip(EmacsWindow, EmacsMenu);

	/* determine signal bit #'s	*/
	intuitionMsgBit = EmacsWindow->UserPort->mp_SigBit;
	consoleMsgBit = consoleReadPort->mp_SigBit;

	/* initialize console read and input buffer */
	QueueRead(consoleReadMsg,&letter);
	nibuf = ibufo = 0;

	/* Determine initial size of virtual terminal.	*/
	ttsize(&nrow,&ncol);
	return (0);
}

/*
 * Close the virtual terminal, de-allocating
 * everything we have allocated.
 */

ttclose()
{
	ttflush();
	AbortIO(consoleReadMsg);
	CloseDevice(consoleWriteMsg);
	cleanup(0);
	Enable_Abort = 1;
}

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

/*
 * Input buffer management.
 *
 * The input buffer is a circular queue of characters
 * that is updated and manipulated by the macros and
 * functions below.   This allows multiple Intuition
 * events (menus, console input, etc.) to be buffered
 * up until Emacs asks for them.
 */

#define CharsBuffered()  (nibuf > 0 )
#define TypeInChar(c)  if (nibuf < (NIBUF - 1))\
				ibuf[(ibufo + nibuf++) % NIBUF] = c;

/*
 * Return the next character in the input buffer.
 */
static GetInputChar()
{
	unsigned char ch;

	if (nibuf <= 0)			/* this shouldn't happen.	*/
		return 0;
	ch = ibuf[ibufo++];
	ibufo %= NIBUF;
	nibuf--;
	return (int) ch;
}

/*
 * 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;
	register int	charfound;	/* have we got a character yet?	*/


	if (CharsBuffered())		/* check input buffer		*/
		return GetInputChar();	/* return immediately have one	*/

	charfound = FALSE;
	do {
		wakeupmask = Wait(INTUITION_MESSAGE|CONSOLE_MESSAGE);

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

		if (wakeupmask & INTUITION_MESSAGE) {	/* Intuition	*/
			while(message =	GetMsg(EmacsWindow->UserPort)) {
				class =	message->Class;
				code = message->Code;
				qualifier = message->Qualifier;
				address = message->IAddress;
				x = message->MouseX;
				y = message->MouseY;

				ReplyMsg(message);
				/* Need ||= here because next event may */
				/* not result in a character... */
				charfound = charfound || HandleEvent();
			} /* while (GetMsg()) */
		} /* if Intuition event */
	} while (charfound == FALSE);

	return GetInputChar();		/* finally got a character.	*/
}

/*
 * Handle the events we handle...
 * The result indicates if we've
 * put a character in the input buffer.
 * All the event information is global,
 * because there's a lot of it...
 */

extern	int	quit();				/* Defined by "main.c"	*/

static HandleEvent()
{
	switch(class) {
	case MENUPICK:				/* fake the menu key	*/
		if (code != MENUNULL)
			return (DoMenu());
		else
			return (FALSE);		/* No character found	*/
		break;
	case MOUSEBUTTONS:			/* fake the mouse key */
		return (DoMouse());
		break;
        case CLOSEWINDOW:			/* Call quit() directly	*/
		quit(FALSE, 1, KRANDOM);	/* This loses if in a 	*/
		return (FALSE);			/*   dialogue...	*/
                break;
	}
	return(FALSE);				/* No char found	*/
}

/*
 * Handle a menu selection by hand-crafting
 * an escape sequence that looks like a function
 * key to the terminal driver.  Save the
 * menu number and item numbe. The
 * value is from the ITS EMACS manual. The
 * hard update is done because the top line in
 * the window is zapped.
 */
backpage(f, n, k)
register int	n;
{
	register LINE	*lp;

	if (f == FALSE) {
		n = curwp->w_ntrows - 2;	/* Default scroll.	*/
		if (n <= 0)			/* Don't blow up if the	*/
			n = 1;			/* window is tiny.	*/
	} else if (n < 0)
		return (forwpage(f, -n, KRANDOM));
#if	CVMVAS
	else					/* Convert from pages	*/
		n *= curwp->w_ntrows;		/* to lines.		*/
#endif
	lp = curwp->w_linep;
	while (n-- && lback(lp)!=curbp->b_linep)
		lp = lback(lp);
	curwp->w_linep = lp;
	curwp->w_dotp  = lp;
	curwp->w_doto  = 0;
	curwp->w_flag |= WFHARD;
	return (TRUE);
}

/*
 * Set the mark in the current window
 * to the value of dot. A message is written to
 * the echo line unless we are running in a keyboard
 * macro, when it would be silly.
 */
setmark(f, n, k)
{
	isetmark();
	if (kbdmop == NULL)
		eprintf("[Mark set]");
	return (TRUE);
}

/* 
 * So other commands can set the mark easily.  (daveb)
 */
isetmark()
{
	curwp->w_markp = curwp->w_dotp;
	curwp->w_marko = curwp->w_doto;
}


/*
 * Swap the values of "dot" and "mark" in
 * the current window. This is pretty easy, because
 * all of the hard work gets done by the standard routine
 * that moves the mark about. The only possible
 * error is "no mark".
 */
swapmark(f, n, k)
{
	register LINE	*odotp;
	register int	odoto;

	if (curwp->w_markp == NULL) {
		eprintf("No mark in this window");
		return (FALSE);
	}
	odotp = curwp->w_dotp;
	odoto = curwp->w_doto;
	curwp->w_dotp  = curwp->w_markp;
	curwp->w_doto  = curwp->w_marko;
	curwp->w_markp = odotp;
	curwp->w_marko = odoto;
	curwp->w_flag |= WFMOVE;
	return (TRUE);
}

/*
 * Go to a specific line, mostly for
 * looking up errors in C programs, which give the
 * error a line number. If an argument is present, then
 * it is the line number, else prompt for a line number
 * to use.
 */
gotoline(f, n, k)
register int	n;
{
	register LINE	*clp;
	register int	s;
	char		buf[32];

	if (f == FALSE) {
		if ((s=ereply("Goto line: ", buf, sizeof(buf))) != TRUE)
			return (s);
		n = atoi(buf);
	}
	if (n <= 0) {
		eprintf("Bad line");
		return (FALSE);
	}
	clp = lforw(curbp->b_linep);		/* "clp" is first line	*/
	while (n != 1) {
		if (clp == curbp->b_linep) {
			eprintf("Line number too large");
			return (FALSE);
		}
		clp = lforw(clp);
		--n;
	}
	curwp->w_dotp = clp;
	curwp->w_doto = 0;
	curwp->w_flag |= WFMOVE;
	return (TRUE);
}

	while (n-- && lback(lp)!=curbp->b_linep)
		lp = lback(lp);
	curwp->w_linep = lp;
	curwp->w_dotp  = lp;
	curwp->w_doto  = 0;
	curwp->w_flag |= WFHARD;
	return (TRUE);
}

/*
 * Set the mark in the current window
 * to the value of dot. A message is written to
 * the echo line unless we are running in a keyboard
 * macro, when it would be silly.
 */
setmark(f, n, k)
{
	isetmark();
	if (kbdmop == NULL)
		eprintf("[Mark set]");
	return (TRUE);
}

/* 
 * So other commands can /*
 * Name:	MicroEMACS
 *		Version stamp.
 * Version:	30
 * Last edit:	14-Feb-86
 * By:		rex::conroy
 *		decvax!decwrl!dec-rhea!dec-rex!conroy
 *
 * This file contains the string(s)
 * that get written out by the show version command.
 * Rich had it generated by a command file. I do
 * it manually, until I can figure out a way to get
 * the MicroEMACS version number generated in a
 * reasonable (automatic) manner. Perhaps a program
 * that reads "things2do.txt".
 */
#include	"d