
/*  A simple terminal emulator.  Does ANSI/DEC VT-100 emulation in
    80 cols by 25 lines.

    by  Michael J. McInerny   21-Feb-86 version 1.21

*/

#define INTUITION_MESSAGE (1<<intuitionMsgBit)
#define TYPED_CHARACTER (1<<consoleReadBit)
#define INPUT_CHARACTER (1<<serReadBit)

#define CloseConsole(x) CloseDevice(x)

#include "term.h"

/* GLOBALS ****************************************************** */
long IntuitionBase=0;
long GfxBase=0;

struct Window *TerminalWindow;           /* "Public" window handle     */
struct Menu *MenuHead;
struct NewWindow nw = {
   0, 0,             /* start position                  */
   640, 200,         /* width, height                   */
   -1, -1,           /* detail pen, block pen           */
   MENUPICK,
                     /* IDCMP flags                     */
   ACTIVATE | BORDERLESS,
                     /* window flags                    */
   NULL,             /* pointer to first user gadget    */
   NULL,             /* pointer to user checkmark       */
   NULL,             /* window title                    */
   NULL,             /* pointer to screen    (later)    */
   NULL,             /* pointer to superbitmap          */
   50,40,640,200,    /* sizing limits min and max       */
   WBENCHSCREEN      /* type of screen in which to open */
   };

struct MsgPort *consoleWritePort;
struct MsgPort *consoleReadPort;
struct MsgPort *serReadPort;
struct MsgPort *serWritePort;
struct IOStdReq *ConWriteReq;
struct IOStdReq *ConReadReq;
struct IOExtSer *SerReadReq;
struct IOExtSer *SerWriteReq;

char letter;            /* one letter at a time from console */
char serin;            /* one letter at a time from serial */

InitWindow()
{
   GfxBase = OpenLibrary("graphics.library", 0);
   if (GfxBase == NULL) Cleanup(1);
   IntuitionBase = OpenLibrary("intuition.library", 0);
   if (IntuitionBase == NULL) Cleanup(2);
   TerminalWindow = OpenWindow(&nw);
   if ( TerminalWindow == NULL ) Cleanup(3);
}

InitMenus()
{
   struct Menu *CurrentMenu, *NewMenu(), *AddMenu();
   struct MenuItem *CurrentItem, *SubItem,
                   *AddNewMenuItem(), *AddItem(), *AddNewSubItem();

   CurrentMenu    = NewMenu("Project", 60, 10);
   MenuHead       = CurrentMenu;
      CurrentItem = AddNewMenuItem(CurrentMenu, "About PDTerm",100,11);
      CurrentItem = AddItem(CurrentItem, "Window");
         SubItem  = AddNewSubItem(CurrentItem, "to Back",68,11);
         SubItem  = AddItem(SubItem,"to Front");
      CurrentItem = AddItem(CurrentItem, "Quit");
   CurrentMenu    = AddMenu(CurrentMenu, "Settings",68,10);
      CurrentItem = AddNewMenuItem(CurrentMenu,"Baud",52,11);
         SubItem  = AddNewSubItem(CurrentItem, "   300   ",76,11);
         SubItem->MutualExclude = (~(1 << 0));
         SubItem->Flags |= CHECKIT;
         SubItem  = AddItem(SubItem,"  1200   ");
         SubItem->MutualExclude = (~(1 << 1));
         SubItem->Flags |= CHECKIT | CHECKED;
         SubItem  = AddItem(SubItem,"  2400   ");
         SubItem->MutualExclude = (~(1 << 2));
         SubItem->Flags |= CHECKIT;
         SubItem  = AddItem(SubItem,"  4800   ");
         SubItem->MutualExclude = (~(1 << 3));
         SubItem->Flags |= CHECKIT;
         SubItem  = AddItem(SubItem,"  9600   ");
         SubItem->MutualExclude = (~(1 << 4));
         SubItem->Flags |= CHECKIT;
      CurrentItem = AddItem(CurrentItem,"Length");
         SubItem  = AddNewSubItem(CurrentItem,"   7 bits   ",100,11);
         SubItem->MutualExclude = (~(1 << 0));
         SubItem->Flags |= CHECKIT | CHECKED;
         SubItem  = AddItem(SubItem,"   8 bits   ");
         SubItem->MutualExclude = (~(1 << 1));
         SubItem->Flags |= CHECKIT;

   SetMenuStrip( TerminalWindow, MenuHead);
}

InitReqs()
{
   consoleWritePort = CreatePort("my.con.write",0);
   if(consoleWritePort == 0) Cleanup(4);
   ConWriteReq = CreateStdIO(consoleWritePort);
   if(ConWriteReq == 0) Cleanup(5);
   consoleReadPort = CreatePort("my.con.read",0);
   if(consoleReadPort == 0) Cleanup(6);
   ConReadReq =  CreateStdIO(consoleReadPort);
   if(ConReadReq == 0) Cleanup(7);
   if((OpenConsole(ConWriteReq,ConReadReq,TerminalWindow)) != 0)
      Cleanup(8);

   serReadPort = CreatePort("my.ser.read",0);
   if (serReadPort == NULL) Cleanup(9);
   SerReadReq = (struct IOExtSer *)CreateExtIO(serReadPort,
                                               sizeof(struct IOExtSer));
   if (SerReadReq == NULL) Cleanup(10);
   serWritePort = CreatePort("my.ser.write",0);
   if (serWritePort == NULL) Cleanup(11);
   SerWriteReq = (struct IOExtSer *)CreateExtIO(serWritePort,
                                               sizeof(struct IOExtSer));
   if (SerWriteReq == NULL) Cleanup(12);
   if ((OpenSerial(SerReadReq, SerWriteReq)) != 0) Cleanup(13);
   if ((SetParams( SerReadReq, 4096, 0x07, 0x07, 750000,
                           1200, NULL, 0x51040303, 0x03030303)) != 0)
      Cleanup(14);
}

main()
{
   USHORT class, code, qualifier;
   int problem, wakeupmask, consoleReadBit, intuitionMsgBit, serReadBit;
   struct IntuiMessage *message; /* the message the IDCMP sends us */

   InitWindow();
   InitMenus();
   InitReqs();

   QueueRead(ConReadReq,&letter);
   QueueSerRead(SerReadReq, &serin);

   consoleReadBit = ConReadReq->io_Message.mn_ReplyPort->mp_SigBit;
   intuitionMsgBit = TerminalWindow->UserPort->mp_SigBit;
   serReadBit = SerReadReq->IOSer.io_Message.mn_ReplyPort->mp_SigBit;

   do
   {
      wakeupmask = Wait( INTUITION_MESSAGE |
                         TYPED_CHARACTER |
                         INPUT_CHARACTER);

      while(CheckIO(ConReadReq))
         {
            WaitIO(ConReadReq);
            SerPutChar(SerWriteReq,letter);
            QueueRead(ConReadReq, &letter);
         }
      while(CheckIO(SerReadReq))
         {
            WaitIO(SerReadReq);
            ConPutChar(ConWriteReq,serin);
            QueueSerRead(SerReadReq, &serin);
         }
      if(wakeupmask & INTUITION_MESSAGE)
         {
            while((message = (struct IntuiMessage *)
                  GetMsg(TerminalWindow->UserPort) ) != NULL)
               {
                  class     = message->Class;
                  code      = message->Code;
                  qualifier = message->Qualifier;
                  ReplyMsg(message);
                  problem = HandleEvent(class,code,qualifier);
                  if(problem == FALSE) break;
               }
         }
   } while (problem); /* keep going as long as HandleEvent returns nonzero */
   AbortIO(ConReadReq);      /* cancel the last queued read */
   AbortIO(SerReadReq);
   Cleanup(0);
}

Cleanup(problem)
int problem;
{
   if ((problem >= 14) || (problem == 0)) CloseDevice(SerReadReq);
   if ((problem >= 13) || (problem == 0))
      DeleteExtIO(SerWriteReq,sizeof(struct IOExtSer));
   if ((problem >= 12) || (problem == 0)) DeletePort(serWritePort);
   if ((problem >= 11) || (problem == 0))
      DeleteExtIO(SerReadReq,sizeof(struct IOExtSer));
   if ((problem >= 10) || (problem == 0)) DeletePort(serReadPort);
   if ((problem >= 9) || (problem == 0)) CloseConsole(ConWriteReq);
   if ((problem >= 8) || (problem == 0)) DeleteStdIO(ConReadReq);
   if ((problem >= 7) || (problem == 0)) DeletePort(consoleReadPort);
   if ((problem >= 6) || (problem == 0)) DeleteStdIO(ConWriteReq);
   if ((problem >= 5) || (problem == 0)) DeletePort(consoleWritePort);
   if ((problem >= 4) || (problem == 0)) {
      ClearMenuStrip(TerminalWindow);
      DisposeMenus(MenuHead);
      CloseWindow(TerminalWindow);
      }
   if ((problem >= 3) || (problem == 0)) CloseLibrary(IntuitionBase);
   if ((problem >= 2) || (problem == 0)) CloseLibrary(GfxBase);
   if(problem > 0)
         exit(problem+1000);
   else
         return(0);
}

HandleEvent(class,code,qualifier)
USHORT class;
USHORT code;
USHORT qualifier;
{
      switch(class) {
         case MENUPICK:
            return(MenuSwitch(code));
            break;
      } /* end of switch( class ) */
      return(TRUE);
} /* end of HandleEvent */

MenuSwitch(code)
USHORT code;
{
   USHORT menunum;
   struct MenuItem *item;
   int error;

   error = TRUE;
   while(code != MENUNULL ) {
      item = (struct MenuItem *)ItemAddress(MenuHead, code);
      menunum = MENUNUM( code );
      switch( menunum ) {
         case 0:
            error &= ProjectMenu(code);
            break;
         case 1:
            error &= SettingsMenu(code);
            break;
      } /* end of switch ( menunum ) */
      code = item->NextSelect;
   } /* end of while (code != MENUNULL) */
   return(error);
} /* end of MenuSwitch */


ProjectMenu(code)
USHORT code;
{
   USHORT itemnum;
   struct IntuiText *InfoText, *OKText, *NewIText(), *AddIText();
   itemnum = ITEMNUM( code );
   switch( itemnum ) {
      case 0:  /* About PDTerm */
         InfoText = NewIText("Public Domain Terminal Emulator",12,5);
         AddIText(InfoText, "    by Michael McInerny  ");
         OKText = NewIText("Okay",6,3);
         AutoRequest(TerminalWindow,
                     InfoText,
                     NULL, OKText,
                     NULL, NULL,
                     296, 65);
         DisposeIText(InfoText);
         DisposeIText(OKText);
         return(TRUE);
      case 1:  /* Window */
         return(ArrangeMenu(code));
         break;
      case 2: /* Quit */
         return( FALSE );
         break;
   } /* end of switch ( itemnum ) */
   return( TRUE );
} /* end of ProjectMenu */

ArrangeMenu(code)
USHORT code;
{
   USHORT subitem;
   subitem = SUBNUM( code );
   switch( subitem ) {
      case 0:
         WindowToBack( TerminalWindow );
         break;
      case 1:
         WindowToFront( TerminalWindow );
         break;
   } /* end of switch ( subitem ) */
   return( TRUE );
} /* end of ArrangeMenu */

SettingsMenu(code)
USHORT code;
{
   USHORT itemnum;
   itemnum = ITEMNUM( code );
   AbortIO(SerReadReq);
   switch ( itemnum ) {
      case 0:
         BaudMenu(code);
         break;
      case 1:
         LengthMenu(code);
         break;
   } /* end of switch ( itemnum ) */
   SerReadReq->IOSer.io_Command = SDCMD_SETPARAMS;
   DoIO(SerReadReq);
   QueueSerRead(SerReadReq, &serin);
   return( TRUE );
} /* end of SettingsMenu */

BaudMenu(code)
USHORT code;
{
   USHORT subitem;
   subitem = SUBNUM( code );
   switch( subitem ) {
      case 0:
         SerReadReq->io_Baud = 300;
         break;
      case 1:
         SerReadReq->io_Baud = 1200;
         break;
      case 2:
         SerReadReq->io_Baud = 2400;
         break;
      case 3:
         SerReadReq->io_Baud = 4800;
         break;
      case 4:
         SerReadReq->io_Baud = 9600;
         break;
   } /* end of switch ( subitem ) */
} /* end of BaudMenu */

LengthMenu(code)
USHORT code;
{
   USHORT subitem;
   subitem = SUBNUM( code );
   switch( subitem ) {
      case 0:
         SerReadReq->io_ReadLen = 0x07;
         SerReadReq->io_WriteLen = 0x07;
         break;
      case 1:
         SerReadReq->io_ReadLen = 0x08;
         SerReadReq->io_WriteLen = 0x08;
         break;
   } /* end of switch ( subitem ) */
} /* end of LengthMenu */
