/*
 * This file contains all the console I/O stuff, most of which is cribbed
 * from the ROM Kernel Manual. Some of the routines here are not used, like
 * clear_screen() and the cursor movement defines.  The idea behind the
 * apparently redundant routines Amiga_putchar(), Amiga_getchar(), etc, is
 * to avoid having external pointers to windows and message ports in all the
 * other files.
 */

#include <exec/types.h>
#include <exec/io.h>
#include <exec/exec.h>
#include <exec/memory.h>
#include <graphics/gfx.h>
#include <hardware/dmabits.h>
#include <hardware/custom.h>
#include <hardware/blit.h>
#include <graphics/gfxmacros.h>
#include <graphics/copper.h>
#include <graphics/view.h>
#include <graphics/gels.h>
#include <graphics/regions.h>
#include <graphics/clip.h>
#include <graphics/text.h>
#include <graphics/gfxbase.h>
#include <libraries/dos.h>
#include <devices/console.h>
#include <devices/keymap.h>
#include <intuition/intuition.h>

#define HELPKEY   '?'

struct TextAttr MyFont =
{
            "topaz.font", TOPAZ_EIGHTY,
             FS_NORMAL,FPF_ROMFONT
};

struct NewWindow nw =
{
            0, 0, 640, 200, 3, 1, CLOSEWINDOW|MENUPICK|GADGETUP|GADGETDOWN,
            WINDOWCLOSE|SMART_REFRESH|ACTIVATE|GIMMEZEROZERO|BORDERLESS,
            0, NULL,"Ogre 2.0 by Hobie Orris", NULL, NULL, 100, 45,
            640, 200, CUSTOMSCREEN
};

struct NewScreen ns =
{
            0, 0, 640, 200, 2, 0, 1, HIRES, CUSTOMSCREEN,
            &MyFont, NULL, 0, 0
};



extern struct MsgPort *CreatePort();
extern struct IOStdReq *CreateStdIO();

struct Screen *scrn;
struct Window *w;
struct RastPort *rp;
struct IOStdReq *WriteMsg, *ReadMsg;
struct MsgPort *WritePort, *ReadPort;
struct IntuiMessage *Imsg;

ULONG DosBase, GfxBase, IntuitionBase;

/************************************************************************/
/*                                                                      */
/*                            Gadget Stuff                              */
/*                                                                      */
/************************************************************************/

/* The gadgets look like this:
 *
 *                            Gadget0     Gadget1
 *                      Gadget2     Gadget6     Gadget3
 *                            Gadget4     Gadget5
 *
 * All have plane 0 as below, and plane 1 as zeroes.
 */

/* offsets of gadget 0 from the window top left */

#define BASEPTX   450      /* x offset */
#define BASEPTY   123      /* y offset */

/* the pictures themselves */

USHORT Imgadget0[36] =
{
   0xffff, 0xf000,
   0x8000, 0x1000,
   0xbff0, 0x1000,
   0xbfe0, 0x1000,
   0xbfc0, 0x1000,
   0xbf80, 0x1000,
   0xbfc0, 0x1000,
   0xbfe0, 0x1000,
   0xbbf0, 0x1000,
   0xb1f8, 0x1000,
   0xa0fc, 0x1000,
   0x807e, 0x1000,
   0x803f, 0x1000,
   0x801f, 0x9000,
   0x800f, 0x1000,
   0x8006, 0x1000,
   0x8000, 0x1000,
   0xffff, 0xf000
};

USHORT Imgadget1[36] =
{
   0xffff, 0xf000,
   0x8000, 0x1000,
   0x80ff, 0xd000,
   0x807f, 0xd000,
   0x803f, 0xd000,
   0x801f, 0xd000,
   0x803f, 0xd000,
   0x807f, 0xd000,
   0x80fd, 0xd000,
   0x81f8, 0xd000,
   0x83f0, 0x5000,
   0x87e0, 0x1000,
   0x8fc0, 0x1000,
   0x9f80, 0x1000,
   0x8f00, 0x1000,
   0x8600, 0x1000,
   0x8000, 0x1000,
   0xffff, 0xf000
};

USHORT Imgadget2[36] =
{
   0xffff, 0xf000,
   0x8000, 0x1000,
   0x8080, 0x1000,
   0x8180, 0x1000,
   0x8380, 0x1000,
   0x8700, 0x1000,
   0x8fff, 0xd000,
   0x9fff, 0xd000,
   0xbfff, 0xd000,
   0x9fff, 0xd000,
   0x8fff, 0xd000,
   0x8700, 0x1000,
   0x8380, 0x1000,
   0x8180, 0x1000,
   0x8080, 0x1000,
   0x8000, 0x1000,
   0x8000, 0x1000,
   0xffff, 0xf000
};

USHORT Imgadget3[36] =
{
   0xffff, 0xf000,
   0x8000, 0x1000,
   0x8010, 0x1000,
   0x8018, 0x1000,
   0x801c, 0x1000,
   0x801e, 0x1000,
   0xbfff, 0x1000,
   0xbfff, 0x9000,
   0xbfff, 0xd000,
   0xbfff, 0x9000,
   0xbfff, 0x1000,
   0x801e, 0x1000,
   0x801c, 0x1000,
   0x8018, 0x1000,
   0x8010, 0x1000,
   0x8000, 0x1000,
   0x8000, 0x1000,
   0xffff, 0xf000,
};

USHORT Imgadget4[36] =
{
   0xffff, 0xf000,
   0x8000, 0x1000,
   0x8006, 0x1000,
   0x800f, 0x1000,
   0x801f, 0x9000,
   0x803f, 0x1000,
   0x807e, 0x1000,
   0xa0fc, 0x1000,
   0xb1f8, 0x1000,
   0xbbf0, 0x1000,
   0xbfe0, 0x1000,
   0xbfc0, 0x1000,
   0xbf80, 0x1000,
   0xbfc0, 0x1000,
   0xbfe0, 0x1000,
   0xbff0, 0x1000,
   0x8000, 0x1000,
   0xffff, 0xf000
};

USHORT Imgadget5[36] =
{
   0xffff, 0xf000,
   0x8000, 0x1000,
   0x8600, 0x1000,
   0x8f00, 0x1000,
   0x9f80, 0x1000,
   0x8fc0, 0x1000,
   0x87e0, 0x1000,
   0x83f0, 0x5000,
   0x81f8, 0xd000,
   0x80fd, 0xd000,
   0x807f, 0xd000,
   0x803f, 0xd000,
   0x801f, 0xd000,
   0x803f, 0xd000,
   0x807f, 0xd000,
   0x80ff, 0xd000,
   0x8000, 0x1000,
   0xffff, 0xf000
};

USHORT Imgadget6[36] =
{
   0xffff, 0xf000,
   0x8000, 0x1000,
   0x81fc, 0x1000,
   0x83fe, 0x1000,
   0x8706, 0x1000,
   0x8e00, 0x1000,
   0x8c00, 0x1000,
   0x8e00, 0x1000,
   0x87fc, 0x1000,
   0x83fe, 0x1000,
   0x8007, 0x1000,
   0x8003, 0x1000,
   0x8007, 0x1000,
   0x860e, 0x1000,
   0x87fc, 0x1000,
   0x83f8, 0x1000,
   0x8000, 0x1000,
   0xffff, 0xf000
};

#define PLNUM  0x01  /* number of planes in image */
#define PLPICK 0x02  /* display in plane 1 */
#define PLOFF  0x01  /* plane 0 turned on */

struct Image Gadgpic[7] =
{
   /* image 0 */
   0, 0, 20, 18, PLNUM, &Imgadget0[0], PLPICK, PLOFF, NULL,

   /* image 1 */
   0, 0, 20, 18, PLNUM, &Imgadget1[0], PLPICK, PLOFF, NULL,

   /* image 2 */
   0, 0, 20, 18, PLNUM, &Imgadget2[0], PLPICK, PLOFF, NULL,

   /* image 3 */
   0, 0 , 20, 18, PLNUM, &Imgadget3[0], PLPICK, PLOFF, NULL,

   /* image 4 */
   0, 0, 20, 18, PLNUM, &Imgadget4[0], PLPICK, PLOFF, NULL,

   /* image 5 */
   0, 0, 20, 18, PLNUM, &Imgadget5[0], PLPICK, PLOFF, NULL,

   /* image 6 */
   0, 0, 20, 18, PLNUM, &Imgadget6[0], PLPICK, PLOFF, NULL
};


struct Gadget Arrow[7] =
{
   /* Up left arrow 0 */
   NULL, BASEPTX, BASEPTY, 20, 18,
   GADGHCOMP|GADGIMAGE, GADGIMMEDIATE|RELVERIFY,
   BOOLGADGET, &Gadgpic[0], NULL, NULL, NULL, NULL, NULL, NULL,

   /* Up right arrow 1 */
   NULL, BASEPTX + 20, BASEPTY, 20, 18,
   GADGHCOMP|GADGIMAGE, RELVERIFY|GADGIMMEDIATE,
   BOOLGADGET, &Gadgpic[1], NULL, NULL, NULL, NULL, NULL, NULL,


   /* left arrow 2 */
   NULL, BASEPTX - 10, BASEPTY + 18, 20, 18,
   GADGHCOMP|GADGIMAGE, RELVERIFY|GADGIMMEDIATE,
   BOOLGADGET, &Gadgpic[2], NULL, NULL, NULL, NULL, NULL, NULL,

   /* right arrow 3 */
   NULL, BASEPTX + 30, BASEPTY + 18, 20, 18,
   GADGHCOMP|GADGIMAGE, RELVERIFY|GADGIMMEDIATE,
   BOOLGADGET, &Gadgpic[3], NULL, NULL, NULL, NULL, NULL, NULL,

   /* down left arrow 4 */
   NULL, BASEPTX, BASEPTY + 36, 20, 18,
   GADGHCOMP|GADGIMAGE, RELVERIFY|GADGIMMEDIATE,
   BOOLGADGET, &Gadgpic[4], NULL, NULL, NULL, NULL, NULL, NULL,

   /* down right arrow 5 */
   NULL, BASEPTX + 20, BASEPTY + 36, 20, 18,
   GADGHCOMP|GADGIMAGE, RELVERIFY|GADGIMMEDIATE,
   BOOLGADGET, &Gadgpic[5], NULL, NULL, NULL, NULL, NULL, NULL,

   /* sit 6 */
   NULL, BASEPTX + 10, BASEPTY + 18, 20, 18,
   GADGHCOMP|GADGIMAGE, RELVERIFY|GADGIMMEDIATE,
   BOOLGADGET, &Gadgpic[6], NULL, NULL, NULL, NULL, NULL, NULL,
};

/*  These are the command characters returned to Amiga_getchar()
 *  when a gadget is selected.
 */

char Gadtbl[] =
{
               'w', 'e', 'a', 'd', 'z', 'x', 's', '\0'
};

/*************************************************************************/
/*                                                                       */
/*                           Menu Stuff                                  */
/*                                                                       */
/*************************************************************************/

/* Main menu structure which has three entries: Deploy, Target and Help */

#define WID  112
#define WID2 130

struct Menu mymenu[3] = { NULL, 1, 0, WID, 0, MENUENABLED, NULL, NULL,
                          0, 0, 0, 0,
                          NULL, WID + 1, 0, WID, 0, MENUENABLED, NULL, NULL,
                          0, 0, 0, 0,
                          NULL, WID * 2 + 2, 0, WID, 0, MENUENABLED, NULL,
                          NULL, 0, 0, 0, 0
};

/* Menu entries for the Deploy menu */

struct MenuItem Menu1[6] = { /* 1st item */
                             NULL, 0, 0, WID, 8,
                             ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0, 0,

                             /* 2nd item */
                             NULL, 0, 10, WID, 8,
                             ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0, 0,

                             /* 3rd item */
                             NULL, 0, 20, WID, 8,
                             ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0,0,

                             /* 4th item */
                             NULL, 0, 30, WID, 8,
                             ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0, 0,

                             /* 5th item */
                             NULL, 0, 40, WID, 8,
                             ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0,0,

                             /* 6th item */
                             NULL, 0, 50, WID, 8,
                             ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0, 0
                        };


struct MenuItem Menu2[7] = { NULL, 0, 0, WID2, 8,
                             ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0, 0,

                             /* 2nd item */
                             NULL, 0, 10, WID2, 8,
                             ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0,0,0,

                             /* 3rd item */
                             NULL, 0, 20, WID2, 8,
                             ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0, 0,

                             /* 4th item */
                             NULL, 0, 30, WID2, 8,
                             ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0,0,

                             /* 5th item */
                             NULL, 0, 40, WID2, 8,
                             ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0,0,

                             /* 6th item */
                             NULL, 0, 50, WID2, 8,
                             ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0,0,

                             /* 7th item */
                             NULL, 0, 60, WID2, 8,
                             ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0, 0
};

struct MenuItem Menu3[1] = {
                             /* 1st item */
                             NULL, 0, 0, WID2, 8,
                             ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0, 0
                           };

/* deploy menu titles */

UBYTE *Depstr[6] = { "C Command Post",
                     "H Howitzer",
                     "T Heavy Tank",
                     "M Missile Tank",
                     "G GEV",
                     "I Infantry"
                   };

/* target menu titles */

UBYTE *Tarstr[7] = { "t Treads",
                     "b Main Battery",
                     "s Secondary Batt",
                     "m Missile",
                     "a Anti-Personnel",
                     "p Pass now",
                     "r Resolve now"
                    };

/* help menu title */

UBYTE *Helpstr = "? Instructions";

/* Menu strip titles */

UBYTE *Titles[] = { "Deploy", "Target", "Help" };

/* Menu item text message descriptors */

struct IntuiText MenuText[14] = {3, 0, JAM1, 0, 0, &MyFont, 0, 0,
                                 3, 0, JAM1, 0, 0, &MyFont, 0, 0,
                                 3, 0, JAM1, 0, 0, &MyFont, 0, 0,
                                 3, 0, JAM1, 0, 0, &MyFont, 0, 0,
                                 3, 0, JAM1, 0, 0, &MyFont, 0, 0,
                                 3, 0, JAM1, 0, 0, &MyFont, 0, 0,
                                 3, 0, JAM1, 0, 0, &MyFont, 0, 0,
                                 3, 0, JAM1, 0, 0, &MyFont, 0, 0,
                                 3, 0, JAM1, 0, 0, &MyFont, 0, 0,
                                 3, 0, JAM1, 0, 0, &MyFont, 0, 0,
                                 3, 0, JAM1, 0, 0, &MyFont, 0, 0,
                                 3, 0, JAM1, 0, 0, &MyFont, 0, 0,
                                 3, 0, JAM1, 0, 0, &MyFont, 0, 0,
                                 3, 0, JAM1, 0, 0, &MyFont, 0, 0 };

/* These are the command characters associated with menu selections */

char Mentbl[3][7] =
{               {'C', 'H', 'T', 'M', 'G', 'I', '\0'},  /* deploy cmds */
                {'t', 'b', 's', 'm', 'a', 'p', 'r'},   /* target cmds */
                {'?', '\0', '\0', '\0', '\0', '\0', '\0'} /* help */
};

/***********************************************************************/
/*                                                                     */
/*                         Requester Stuff                             */
/*                                                                     */
/***********************************************************************/


char BodyText[] = "Choose an Ogre type";
char PosText[] = "Mark III";
char NegText[] = "Mark V";

struct IntuiText Body =
{
   3, 1, JAM1, 60, 10, NULL, &BodyText[0], NULL
};

struct IntuiText Pos =
{
   3, 1, JAM1, 7, 4, NULL, &PosText[0], NULL
};

struct IntuiText Neg =
{
   3, 1, JAM1, 7, 4, NULL, &NegText[0], NULL
};


/***********************************************************************/
/*                                                                     */
/*                            Toys Code                                */
/*                                                                     */
/***********************************************************************/


/* getevent pulls a message off the program's message queue and checks if
 * it's a menu-related or gadget-related message.  If it is, the appropriate
 * handler is called.
 */

char getevent()
{
   char GadgetServe(), MenuServe(), result;
   struct IntuiMessage  *GetMsg(), Tmpmsg;

   /* check queue for incoming messages */

   Imsg = GetMsg(w->UserPort);
   if (Imsg == NULL)
      return('\0');
   else
      Tmpmsg = *Imsg;
   ReplyMsg(Imsg);

   /* if message available, decode it */

   if (Tmpmsg.Class != 0)
   {
      switch (Tmpmsg.Class)
      {
         /* could be a close window event */

         case CLOSEWINDOW:
            endit();
            break;

      /* or a menu selection */

         case MENUPICK:
            result = MenuServe(&Tmpmsg);
            return(result);
            break;

         case GADGETUP:
            result = GadgetServe(&Tmpmsg);
            return (result);
            break;

      /* if no selection was made, return a null */

         default:
            return('\0');
            break;
      }
   }
}     /* checkmenu */

/* This routine invokes the requester that asks for Ogre type
 */

int get_mark()
{
   int x;

   x = AutoRequest(w, &Body, &Pos, &Neg, 0L, 0L, 300L, 60L);
   if (x)
      x = 3;
   else
      x = 5;
   return(x);
}

/* Initmenu sets up the menus at the start of the program.
 * Nobody said this would be easy.
 */

InitMenu()
{
   int i;

   /* link the three menus */

   mymenu[0].NextMenu = &mymenu[1];
   mymenu[1].NextMenu = &mymenu[2];
   mymenu[2].NextMenu = NULL;

   /* point to first items on the menus */

   mymenu[0].FirstItem = &Menu1[0];
   mymenu[1].FirstItem = &Menu2[0];
   mymenu[2].FirstItem = &Menu3[0];

   /* initialize titles */

   mymenu[0].MenuName = Titles[0];
   mymenu[1].MenuName = Titles[1];
   mymenu[2].MenuName = Titles[2];

   /* link menu items */

   for (i = 0; i < 6; ++i)
      Menu1[i].NextItem = &Menu1[i + 1];
   Menu1[5].NextItem = NULL;

   for (i = 0; i < 7; ++i)
      Menu2[i].NextItem = &Menu2[i + 1];
   Menu2[6].NextItem = NULL;

   Menu3[0].NextItem = NULL;

   /* link item names to text descriptors */

   for (i = 0; i < 6; ++i)
      MenuText[i].IText = Depstr[i];
   for (i = 0; i < 7; ++i)
      MenuText[6 + i].IText = Tarstr[i];
   MenuText[13].IText = Helpstr;

   /* link text descriptors to item structures */

   for (i = 0; i < 6; ++i)
      Menu1[i].ItemFill = &MenuText[i];
   for (i = 0; i < 7; ++i)
      Menu2[i].ItemFill = &MenuText[6 + i];
   Menu3[0].ItemFill = &MenuText[13];

   SetMenuStrip(w, &mymenu[0]);
}

/*  InitGad sets up the gadgets before the game starts
 */

InitGad()
{
   int i;

   /* link Image structures to Gadget structures */

   for (i = 0; i < 6; ++i)
      Arrow[i].GadgetRender = (APTR) &Gadgpic[i];

   /* link image data to Image structures */

   Gadgpic[0].ImageData = &Imgadget0[0];
   Gadgpic[1].ImageData = &Imgadget1[0];
   Gadgpic[2].ImageData = &Imgadget2[0];
   Gadgpic[3].ImageData = &Imgadget3[0];
   Gadgpic[4].ImageData = &Imgadget4[0];
   Gadgpic[5].ImageData = &Imgadget5[0];
   Gadgpic[6].ImageData = &Imgadget6[0];

   Arrow[6].NextGadget = NULL;

}


refresh()
{
   int i;

   RefreshGadgets(&Arrow[0], w, NULL);

   /* Add the gadgets to the window's gadget list and activate them */
   for (i = 0; i < 7; ++i)
   {
      AddGadget(w, &Arrow[i], -1);
      OnGadget(&Arrow[i], w, NULL);
   }
}

/* MenuServe decodes menu request messages and translates them into the
 * proper character to hand to main program.
 */

char MenuServe(Menmsg)
struct IntuiMessage *Menmsg;
{
   USHORT menusel, itemsel;      /* menu and item selected */
   char selection;

   /* extract the menu and item numbers */

   menusel = MENUNUM(Menmsg->Code);
   itemsel = ITEMNUM(Menmsg->Code);
   if (menusel == MENUNULL)
      return(NULL);

   /* get the command character from the table */

   selection = Mentbl[menusel][itemsel];
   return(selection);
}

/* GadgetServe translates a gadget selection into a command character
 * and returns that character.
 */

char GadgetServe(GadMsg)
struct IntuiMessage *GadMsg;
{
   int i;

   for (i = 0; i < 7; ++i)
      if (GadMsg->IAddress == (APTR) &Arrow[i])
         break;
   return (Gadtbl[i]);
}

/*
 * These are the calls known to the rest of the Ogre program
 */

tc_setup()
{
   make_console();
}

/* This is not a true erase to end of line routine, since we want
 * to preserve the gadget display.  It erases to column 55.
 */

eeol(row)
int row;
{
   static char s[55] =
   {"                                                      "};

   movecur(row,0);
   Amiga_puts(s);
   movecur(row,0);
}

clear_screen()
{
   static char ff = 0x0c;

   ConPutChar(WriteMsg,&ff);
}

/*
 *    Move the cursor to row, col by building a CSI sequence
 */

movecur(row, col)
int row, col;
{
   char seq[8];
   int n,i;

   row += 1;  /* Kludge city! The Amiga display is shorter than a terminal */

   /* CSI character */

   seq[0] = 0x9b;

   /* convert row to ASCII */

   n = stci_d(&seq[1], row, 4);
   i = n + 1;

   /* field separator */

   seq[i] = 0x3b;
   i++;

   /* convert column to ASCII */

   n = stci_d(&seq[i], col, 4);
   i += n;

   /* terminator */

   seq[i] = 0x48;
   seq[i+1] = '\0';
   ConPutStr(WriteMsg, &seq[0]);
}

set_term()
{
   cursoff(WriteMsg);
}

reset_term()
{
   endit();
}

/*
 * These are mine. They insulate the rest of the files from knowing anything
 * about message ports and other messy stuff.
 */

Amiga_puts(s)
char *s;
{
   ConPutStr(WriteMsg, s);
}

/* Put a single char out.  This is weird: take away the static, and it no
 * longer works!
 */

Amiga_putchar(c)
char c;
{
   static char x;

   x = c;
   ConPutChar(WriteMsg, &x);
}

/*    Get a character from the keyboard or a close window event from the
 *    mouse. A close window event ends the program.
 *    If you want to add menus then this is the place to do it.
 */

char Amiga_getchar()
{
   static char c;
   BYTE MayGetChar();
   struct IntuiMessage *GetMsg();
   char checkmenu(), event;
   BYTE ret;

   FOREVER
   {
      ret = 0;

      /* first, check for keyboard input */

      ret = MayGetChar(ReadPort, ReadMsg, &c);
      if (ret != -1)
      {
         /* Trap help requests here, so that help can be obtained
          * from anywhere in the program.
          */

         if (ret == HELPKEY)
            ret = get_help();
         else
            return((char) ret);
      }

      /* if no keyboard chars are ready, check our message port for
       * menus and gadgets.
       */

      if ((event = getevent()) != '\0')
      {
         if (event == HELPKEY)
            ret = get_help();
         else
            return(event);
      }
   }
}

endit()
{
   err(7);
   exit(0);
}

/*
 * This stuff is from the ROM Kernel Manual
 */
make_console()
{
   int error;
   UBYTE c;

   if ((DosBase = OpenLibrary("dos.library", 0)) == NULL)
      err(1);
   if ((IntuitionBase = OpenLibrary("intuition.library", 0)) == NULL)
      err(2);
   if ((GfxBase = OpenLibrary("graphics.library", 0)) == NULL)
      err(3);

   WritePort = CreatePort("con1.write", 0);
   if (WritePort == 0)
      err(4);
   WriteMsg = CreateStdIO(WritePort);
   if (WriteMsg == 0)
      err(19);

   ReadPort = CreatePort("con1.read", 0);
   if (ReadPort == 0)
      err(5);

   ReadMsg = CreateStdIO(ReadPort);
   if (ReadMsg == 0)
      err(12);

   scrn = (struct Screen *) OpenScreen(&ns);
   if (scrn == NULL)
   {
      printf("Can't open window");
      exit(20);
   }

   nw.Screen = scrn;

   w = (struct Window *) OpenWindow(&nw);
   if (w == NULL)
      err(6);

   /* link gadgets into window */

   InitGad();

   /* link menus into window */

   InitMenu();

   error = OpenConsole(WriteMsg, ReadMsg, w);
   if (error != 0)
      err(7);

   QueueRead(ReadMsg, &c);

   c = CheckIO(ReadMsg);
   if (c == FALSE) AbortIO(ReadMsg);
   else GetMsg(ReadPort);

}

/*
 * This routine is ugly. Please fix it.
 */

static err(n)
int n;
{
   switch (n)
   {
      case 7: CloseDevice(WriteMsg);
      case 6: CloseWindow(w);
      case 10: CloseScreen(scrn);
      case 5: DeletePort(ReadPort);
      case 12: DeleteStdIO(ReadMsg);
      case 4: DeletePort(WritePort);
      case 19: DeleteStdIO(WriteMsg);
      case 3: CloseLibrary(GfxBase);
      case 2: CloseLibrary(IntuitionBase);
      case 1: CloseLibrary(DosBase);
   }
   exit(n);                                  /* return error code to CLI */
}


OpenConsole(wreq, rreq, win)
struct IOStdReq *wreq, *rreq;
struct Window *win;
{
   int error;
   wreq->io_Data = (APTR) win;
   wreq->io_Length = sizeof(*win);
   error = OpenDevice("console.device", 0, wreq, 0);
   rreq->io_Device = wreq->io_Device;
   rreq->io_Unit = wreq->io_Unit;
   return(error);
}


ConPutChar(request, ch)
struct IOStdReq *request;
char *ch;
{
   request->io_Command = CMD_WRITE;
   request->io_Data = ch;
   request->io_Length = 1;
   DoIO(request);
   return(0);
}


ConWrite(request, string, len)
struct IOStdReq *request;
char *string;
int len;
{
   request->io_Command = CMD_WRITE;
   request->io_Data = (APTR) string;
   request->io_Length = len;
   DoIO(request);
   return(0);
}


ConPutStr(request, string)
struct IOStdReq *request;
char *string;
{
   request->io_Command = CMD_WRITE;
   request->io_Data = (APTR) string;
   request->io_Length = -1;
   DoIO(request);
   return(0);
}


QueueRead(request, buf)
struct IOStdReq *request;
UBYTE *buf;
{
   request->io_Command = CMD_READ;
   request->io_Data = (APTR)buf;
   request->io_Length = 1;
   SendIO(request);
   return(0);
}


char ConGetChar(console, request, buf)
struct IOStdReq *request;
struct MsgPort *console;
char *buf;
{
   char temp;

   while ((GetMsg(console) == NULL)) WaitPort(console);
   QueueRead(request, buf);
   temp = *buf;
   return(temp);
}

BYTE MayGetChar(console,rreq, buf)
struct IOStdReq *rreq;
struct MsgPort *console;
char *buf;
{
   register BYTE *temp;

   if (GetMsg(console) == NULL) return(-1);
   temp = (char *) rreq->io_Data;
   QueueRead(rreq, buf);
   return(*temp);
}
