home *** CD-ROM | disk | FTP | other *** search
- /*
- * Name: MicroEmacs
- * Amiga terminal-dependent I/O (Intuition)
- * Strategy and much code borrowed from the Lattice C
- * example in the ROM Kernel manual.
- * Version: 31
- * Last edit: 21-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
- * 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 <intuition/intuition.h>
- #undef TRUE
- #undef FALSE
- #include "def.h" /* includes sysdef.h */
-
- /*
- * External functions. Declared explicitly
- * to avoid problems with different compilers.
- */
-
- extern char *OpenLibrary();
- extern int OpenConsole();
- extern struct Window *OpenWindow();
- extern struct MsgPort *CreatePort();
- extern struct IOStdReq *CreateStdIO();
- extern struct Menu *InitEmacsMenu();
- extern struct IntuiMessage *GetMsg();
- extern LONG AbortIO();
- extern LONG CloseDevice();
- extern LONG ReplyMsg();
- extern LONG SetMenuStrip();
- extern LONG Wait();
-
- /*
- * Terminal I/O global variables
- */
-
- #define NIBUF 128 /* Probably excessive. */
- #define NOBUF 512 /* Not too big for 750/730. */
-
- unsigned char obuf[NOBUF]; /* Output buffer */
- int nobuf; /* # of bytes in above */
- unsigned char ibuf[NIBUF]; /* Input buffer */
- int ibufo, nibuf; /* head, # of bytes in ibuf */
- int nrow; /* Terminal size, rows. */
- int ncol; /* Terminal size, columns. */
- extern char *version[]; /* Version information */
- /* (I cheat and use it for */
- /* the window title) */
- /*
- * Intuition global variables
- */
-
- #define WINDOWGADGETS (WINDOWSIZING | WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE)
-
- struct NewWindow MicroEMACS = {
- 0, 0, /* start position */
- 640, 200, /* width, height */
- 0, 1, /* detail pen, block pen */
- MENUPICK | CLOSEWINDOW | /* IDCMP flags */
- MOUSEBUTTONS | NEWSIZE,
- WINDOWGADGETS | ACTIVATE, /* window flags */
- 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 */
- 360,99,639,199, /* sizing limits min and max */
- WBENCHSCREEN /* screen in which to open */
- };
-
- struct IntuitionBase *IntuitionBase; /* library bases */
- struct GfxBase *GfxBase;
- struct Window *EmacsWindow; /* Our window */
- struct Menu *EmacsMenu; /* Our menu */
- struct MsgPort *consoleWritePort; /* I/O ports */
- struct MsgPort *consoleReadPort;
- int intuitionMsgBit, /* Signal bits */
- consoleMsgBit;
- struct IOStdReq *consoleWriteMsg; /* I/O messages */
- struct IOStdReq *consoleReadMsg;
- unsigned char letter; /* Console 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 number until the
- * menu execution function can ask for it.
- */
-
- int LastMenuNum; /* Menu number for KMENU `key' */
- int LastItemNum; /* Menu item for KMENU `key' */
- int LastSubItem; /* Subitem number (for completeness) */
-
- #define CSI 0x9b /* Amiga command sequence introducer */
-
- static DoMenu()
- {
- struct MenuItem *item, *ItemAddress();
-
- while (code != MENUNULL) {
- item = ItemAddress(EmacsMenu,(LONG) code);
- LastMenuNum = MENUNUM(code); /* number of menu */
- LastItemNum = ITEMNUM(code); /* item number */
- LastSubItem = SUBNUM(code); /* subitem code */
- code = item->NextSelect;
- }
- TypeInChar(CSI); /* fake the MENU key */
- TypeInChar('M');
- TypeInChar('~');
- return (TRUE); /* found a character! */
- }
-
- /*
- * Return the last menu selection numbers to
- * the caller. Used by "ttymenu.c".
- */
-
- ttmenu(menu,item,subitem)
- int *menu, *item, *subitem;
- {
- *menu = LastMenuNum;
- *item = LastItemNum;
- *subitem = LastSubItem;
- LastMenuNum = (USHORT)-1; /* Forget the values */
- LastItemNum = (USHORT)-1; /* so they don't get re-used */
- LastSubItem = (USHORT)-1;
- }
-
-
- /*
- * Handle a mouse selection by inserting
- * a "MOUSE key" (teer) sequence into the
- * input buffer and saving the x, y and
- * qualifier values for later.
- */
-
- SHORT LastMouseX, LastMouseY; /* Position of mouse */
- USHORT LastQualifier; /* Qualifier (shift key?) */
-
- static DoMouse()
- {
- /* Save last mouse position */
- if (code != SELECTDOWN)
- return (FALSE);
- LastMouseX = x - EmacsWindow->BorderLeft;
- LastMouseY = y - EmacsWindow->BorderTop;
- LastQualifier = qualifier;
-
- TypeInChar(CSI); /* fake the MOUSE key */
- TypeInChar('P'); /* P for Pointer */
- TypeInChar('~');
- return (TRUE); /* found a character! */
- }
-
- /*
- * Return the last mouse click values to
- * the caller. X and Y are translated
- * so that (0,0) is at the edge of the
- * top and left borders. Used by "ttymouse.c".
- */
-
- ttmouse(x,y,qualifier)
- SHORT *x, *y;
- USHORT *qualifier;
- {
- *x = LastMouseX;
- *y = LastMouseY;
- *qualifier = LastQualifier;
- LastMouseX = (SHORT)-1;
- LastMouseY = (SHORT)-1;
- LastQualifier = (USHORT)-1;
- }
-
- /*
- * Return the current size of the virtual
- * terminal to the caller. Placed in
- * ttyio.c because it uses information
- * that is only available to the virtual
- * terminal handler.
- *
- * Assumes the WorkBench screen default
- * font is TOPAZ_EIGHTY (8 wide by 8 high).
- */
-
- ttsize(rows,cols)
- int *rows, *cols;
- {
- *rows = (EmacsWindow->Height - /* have to take borders */
- EmacsWindow->BorderTop - /* into account. */
- EmacsWindow->BorderBottom) / 8;
- *cols = (EmacsWindow->Width -
- EmacsWindow->BorderLeft -
- EmacsWindow->BorderRight) / 8;
- }
-
- /*
- * Clean up.
- * Fall through all the possible cases (0 means
- * get rid of everything and start with the case
- * that fits the error situation.
- */
-
- extern LONG ClearMenuStrip();
- extern LONG DeleteStdIO();
- extern LONG DeletePort();
- extern LONG CloseWindow();
- extern LONG CloseLibrary();
-
- static cleanup(prob)
- {
-
- switch (prob) {
- case 0:
- ClearMenuStrip(EmacsWindow);
- DisposeMenus(EmacsMenu);
- case 10:
- case 8:
- DeleteStdIO(consoleReadMsg);
- case 7:
- DeletePort(consoleReadPort);
- case 6:
- DeleteStdIO(consoleWriteMsg);
- case 5:
- DeletePort(consoleWritePort);
- case 4:
- CloseWindow(EmacsWindow);
- case 2:
- if (GfxBase != NULL) CloseLibrary(GfxBase);
- case 1:
- if (IntuitionBase != NULL) CloseLibrary(IntuitionBase);
- break;
- }
- return(0);
- }
-
-