/**********************************************************************

     Read V2.0   Read Text File From WorkBench       By Tom Beale

**********************************************************************/

#include <stdio.h>
#include <dos.h>
#include <string.h>
#include <error.h>
#include <ctype.h>
#include <exec/types.h>

#include <graphics/gfxmacros.h>
#include <intuition/intuition.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>
#include <workbench/icon.h>

#include <devices/console.h>
#include <devices/keymap.h>

#define MAXSIZE 2000
#define UP 1
#define PROP 2
#define DOWN 3
#define PRINT 4

struct GfxBase *GfxBase;
struct IntuitionBase *IntuitionBase;
struct Window *OpenWindow();
struct IntuiMessage *GetMsg();

extern struct IOStdReq *CreateStdIO();
extern struct MsgPort *CreatePort();
extern struct WBStartup *WBenchMsg;
struct IntuiMessage *message;

struct WBArg *arg;
struct DiskObject *DO;
struct IconBase *IconBase;

struct IOStdReq *CWM;
struct Port *CWP;
struct IOStdReq *CRM;
struct Port *CRP;

/*
   ----------------------------------------------------- Set Up Gadgets
*/

struct Image bogus;                     /* filled out by Intuition */


USHORT updata[] =                       /* Image Data for Up Arrow */
   {
   0xFFFF,  0xFFFF,
   0xFC7F,  0xF83F,
   0xF01F,  0xE00F,
   0xC007,  0x87C3,
   0xFFFF,  0xFFFF,
   };

USHORT downdata[] =                     /* Image Data for Down Arrow */
   {
   0xFFFF,  0xFFFF,
   0x87C3,  0xC007,
   0xE00F,  0xF01F,
   0xF83F,  0xFC7F,
   0xFFFF,  0xFFFF,
   };

struct Image uparrow =                 /* Up Arrow Image Structure    */
   {
   0, 0,
   16,  10,  1,
   &updata[0],
   0x1, 0x0,
   NULL
   };

struct Image downarrow =               /* Down Arrow Image Structure  */
   {
   0, 0,
   16,  10,  1,
   &downdata[0],
   0x1, 0x0,
   NULL
   };

struct PropInfo sliderinfo =           /* Slider Special Info Structure */
   {
   AUTOKNOB | FREEVERT,
   0x00,
   0x00,
   0xFFFF,
   0xFFFF,
   };

struct Gadget slider =                 /* Slider Gadget Structure       */
   {
   NULL,
   -15,  20,
    16,  -39,
   GADGHCOMP | GADGIMAGE | GRELRIGHT | GRELHEIGHT,
   RELVERIFY | RIGHTBORDER,
   PROPGADGET,
   (APTR)&bogus,
   NULL,
   NULL,
   NULL,
   (APTR)&sliderinfo,
   2,
   NULL
   };

struct Gadget scup =                   /* Up Button Gadget Structure   */
   {
   &slider,
   -15, 10,
    16, 10,
   GADGHCOMP | GADGIMAGE | GRELRIGHT,
   GADGIMMEDIATE | RELVERIFY | RIGHTBORDER,
   BOOLGADGET,
   (APTR)&uparrow,
   NULL,
   NULL,
   NULL,
   NULL,
   UP,
   NULL
   };

struct Gadget scdown =                 /* Down Button Gadget Structure  */
   {
   &scup,
   -15,-18,
    16, 10,
   GADGHCOMP | GADGIMAGE | GRELRIGHT | GRELBOTTOM,
   GADGIMMEDIATE | RELVERIFY | RIGHTBORDER,
   BOOLGADGET,
   (APTR)&downarrow,
   NULL,
   NULL,
   NULL,
   NULL,
   DOWN,
   NULL
   };



/*
   -------------------------------------  Set up Window Structure
*/

struct NewWindow newwindow = {
        1,    0,                      /* left,       Top          */
      639,  200,                      /* Width,      Height       */
        0,    1,                      /* DetailPen,  BlockPen     */
      CLOSEWINDOW   |                 /* IDCMP Flags              */
      GADGETDOWN    |
      NEWSIZE       |
      RAWKEY        |
      GADGETUP,
      SIZEBRIGHT    |                 /* More Flags               */
      WINDOWDEPTH   |
      WINDOWCLOSE   |
      WINDOWSIZING  |
      WINDOWDRAG    |
      SMART_REFRESH |
      ACTIVATE      ,
   &scdown,                           /* First Gadget             */
   NULL,                              /* CheckMark                */
   "         ",                       /* Title                    */
   NULL,                              /* Screen (Fill in Later)   */
   NULL,                              /* BitMap                   */
   130,  50,  640,  200,              /* Min & Max Width & Height */
   WBENCHSCREEN
   };
/*
   --------------------- Initialize Structures for Printout Requester
*/
struct IntuiText rtitle =
   {
   4,1,                     /* Front Pen, Back Pen */
   JAM1,                    /* Draw Mode           */
   10,5,                    /* Upper Left Corner   */
   NULL,                    /* Define Font         */
   "  Send File to Printer:",
   NULL
   };

struct IntuiText ryes =
   {
   4,1,
   JAM1,
   5,3,
   NULL,
   "Print It",
   NULL
   };

struct IntuiText rno =
   {
   4,1,
   JAM1,
   5,3,
   NULL,
   "Cancel",
   NULL
   };

struct Window *window;

extern int errno;
extern int sys_nerr;
extern char *sys_errlist[];

int MAXDEPTH  = 23;
int   maxlen  = 76;
int  tabs []  = { 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104};
int controls  = 0;
int colors    = 0;
char fg = '1';
char bg = '0';
char cflag = NULL;

char *name, *line[MAXSIZE], ccount[MAXSIZE], linebuf[90], *ncopt;

/*
   ------------------------------------- Define Terminal Control Strings
*/

char cls[]  = { 12, 00 };                 /* Clear Screen          */
char lf[]   = { 10, 00 };                 /* Line Feed             */
char ceol[] = { 0x9B, 0x4B, 00 };         /* Clear to End of Line  */
char ceof[] = { 0x9B, 0x4A, 00 };         /* Clear to End of Line  */
char home[] = { 0x9B, 0x31,               /* Upper Left            */
                0x3B, 0x31,
                0x48, 0
              };
char bot[]  = { 0x9B, 0x32, 0x33,   /* Bottom Left           */      
                0x3B, 0x31,
                0x48, 0
              };
char up[]   = { 0x0B, 00 };               /* Tab Up                */
char dn[]   = { 0x9B, 0x53, 00};          /* Scroll Down           */
char coff[] = { 0x9B, 0x30,               /* Turn Cursor Off       */
                0x20, 0x70, 00
              };
char norm[] = { 0x9B, 0x30,               /* White on Blue         */
                0x3B, 0x33, 0x31,
                0x3B, 0x34, 0x30,
                0x6D, 00
              };

char init[] = { 0x9B, 0x30,               /* Default Colors        */
                0x3B, 0x33, 0x31,
                0x3B, 0x34, 0x30,
                0x6D, 00
              };

char blk[]  = { 0x9B, 0x30,               /* Black on Blue         */
                0x3B, 0x33, 0x32,
                0x3B, 0x34, 0x30,
                0x6D, 00
              };

char orng[] = { 0x9B, 0x30,               /* Orange on Blue         */
                0x3B, 0x33, 0x33,
                0x3B, 0x34, 0x30,
                0x6D, 00
              };

char resize[] = { 0x9B, 0x32, 0x33, 0x74, 00};
char resiz[]  = { 0x9B, 0x74, 00};
char wsflag   = 0;
char ccpad    = 0;

int lineno;                          /* Top Line of Screen display */
int linecount;                       /* Last line of file          */
int lastline;                        /* Top line of last screen    */

ULONG class;

/*
   ---------------------------------------------------- Begin Main Loop
*/
void main(argc, argv)
   int argc;
   char *argv[];
      {
      FILE *fp;
      char *mode, *msg, *temp;
      char string[200];
      int c, ret, opt, count, start, contflag, tb, ch[2];
      int lastspace, breakflag, i1, i2;
      USHORT id;
      char key;
      struct Gadget *gadget;

      msg = "\nIn case you're wondering... \n This is Read's Executable file\n\n";

      mode   = "r";
      opt    = 0;
      count  = 1;
      ncopt  = "nc";
      ret = 169;

      printf("\n\n          %s ---%s READ V2.0 %s---\n\n",blk,orng,blk);
      printf("           %s%c%s Tom Beale  1989%s\n\n",norm,ret,orng,norm);

      switch (argc)
         {
         case 3:
            if (stricmp(argv[2],ncopt)==0) controls = 1;
         case 2:
            name = strdup(argv[1]);
            break;
         case 0:
            ret = WBArgFN(WBenchMsg);
            if (ret) 
                {
                printf("\n\nFilename? ");
                scanf("%s",&name);
                }
            break;
         default:
            xxerr("\n\n      Syntax:    READ <filename>\n");
         }

      fp = fopen(name,mode);
      if (fp == NULL)
         {
         printf("Error Opening File: %s\n ",sys_errlist[errno]);
         ret = fclose(fp);
         if (ret == -1) xxerr("\nFile did not close properly.\n");
         }
/*
      --------------------------------------------- Read File Into Array
*/
      linecount = 0;
      contflag  = 0;

      for(;;)
         {
         lastspace = 0;
         breakflag = 0;
         start     = 0;
         ccount[linecount] = 0;

         if (contflag != 0)
            {
            start = contflag;
            contflag = 0;
            }


         for(count=start;;count++)
            {
            c = fgetc(fp);
            switch(c)
               {
               case EOF:                      /* End of File?       */
                  string[count] = '\0';
                  line[linecount] = strdup(string);
                  breakflag = 1;
                  break;
               case 13:                       /* Linefeed or CR     */
               case 10:
                  string[count] = '\0';
                  breakflag = 1;
                  line[linecount] = strdup(string);
                  break;
               case 9:                            /* Tab character      */
                  for(tb=0;tb<10,tabs[tb]<count;tb++);
                  c = ' ';
                  for(;count<=tabs[tb];count++)
                     {
                     string[count] = ' ';
                     }
                  lastspace = count;
                  break;
               case ' ':
                  lastspace = count;
               }
            if (breakflag == 1) break;
            if ((colors==2)&&(count==1))     /*  JumpDisk Color Option  */
              {
              if ((c==']') && (string[0]>0x30) && (string[0]<0x35))
                 {
                 if (string[0]>'3') string[0]=string[0]-4;
                 string[4]=string[0];            
                 string[0]=0x9B;
                 string[1]='0';            
                 string[2]=';';            
                 string[3]='3';            
                 string[5]=';';            
                 string[6]='4';            
                 string[7]= bg;            
                 c = 0x6D;
                 count = 8;
                 }
              else
                 {
                 string[9]=string[0];            
                 string[0]=0x9B;
                 string[1]='0';
                 string[2]=';';            
                 string[3]='3';
                 string[4]= fg;         
                 string[5]=';';
                 string[6]='4';
                 string[7]= bg;
                 string[8]=0x6D;
                 count = 10;
                 }
               }
            if ((colors==1)&&(c==cflag))      /*  Read Color Option  */
               {
               ret = fgetc(fp);
               if ((ret>='0') && (ret<='3')) fg = ret;
               ret = fgetc(fp);
               if ((ret>='0') && (ret<='3')) bg = ret;
               string[count  ]=0x9B;
               string[count+1]='0';            
               string[count+2]=';';            
               string[count+3]='3';            
               string[count+4]= fg;            
               string[count+5]=';';            
               string[count+6]='4';            
               string[count+7]= bg;            
               c = 0x6D;
               count = count + 8;
               ccount[linecount] = ccount[linecount] +9;
               }
            string[count] = c;
            if (iscntrl(c) && controls) count--;
            if (count >= maxlen+ccount[linecount])
               {
               breakflag = 1;
               if (lastspace != 0)
                  {
                  string[lastspace] = '\0';
                  line[linecount]=strdup(string);
                  lastspace++;
                  for (i1=lastspace,i2=0; i1<=count; i1++,i2++)
                     string[i2]=string[i1];
                  contflag = i2++;
                  }
               else
                  {
                  string[count+1]=0;
                  line[linecount] = strdup(string);
                  }
               }
            if (breakflag == 1) break;
            }
         linecount++;
         if (c==EOF) break;
         if (linecount > MAXSIZE) break;
         }
/*
    -------------------------------- Open Console and Set Up Read Window
*/
ShowIt:
      lastline = linecount - MAXDEPTH;
          ret = (linecount/(MAXDEPTH-2));
	  if (ret < 1) ret = 1;
          sliderinfo.VertBody = 0xFFFF / ret;

      openlibs();

      CWP = CreatePort("mycon.write",0);
         if (CWP == 0) xxerr("Write port didn't open");
      CWM = CreateStdIO(CWP);
         if (CWM == 0) xxerr("Write message request not created");

      CRP = CreatePort("mycon.read",0);
         if (CRP == 0) xxerr("Read port didn't open");
      CRM = CreateStdIO(CWP);
         if (CRM == 0) xxerr("Read message request not created");

      ret = OpenConsole(CWM,CRM,window);
         if (ret != 0) xxerr("Console Device didn't Open"); 


      ret = sprintf(temp," Read: %s   ",name);

      SetWindowTitles(window,temp,-1);
      if (wsflag)
          {
          MAXDEPTH = resized();
          lastline = linecount - MAXDEPTH;
          }     
      lineno = 0;
      cputs(CWM,coff);
      CRefresh(lineno);
cont:
      /*  ---------------------------------------------------- Main Loop
      */
      for(;;)
         {
         Wait(1<<window->UserPort->mp_SigBit);
         while(message = GetMsg(window->UserPort))
            {
            class = message->Class;
            gadget = message->IAddress;
            ReplyMsg(message);
            switch (class)
               {
               case CLOSEWINDOW:
                  xxerr(NULL);
               case GADGETUP:
               case GADGETDOWN:
                  id = gadget->GadgetID;
                  handlegadget(id);
                  break;
               case NEWSIZE:
                  ret = MAXDEPTH;
                  MAXDEPTH = resized();
                  lastline = linecount - MAXDEPTH;
                  if (ret < MAXDEPTH) cputs(CWM,cls);
                  CRefresh(lineno);
                  break;
               case RAWKEY:
                  key = message->Code;
                  switch (key)
                     {
                     case 25: printout();
                              break;
	             case 76: upone();
                              break; 
                     case 77: downone();
                              break;
                     }
                  update();
               }
            }
         }

      xxerr(NULL);
      }
/*
    ------ End of Main
*/
/*
    ---------------------------------------- Handle Resized Window
*/
int resized()
      {
      int ret, temp;
      ret    = window->Height;      /* Extract New Window depth      */
      maxlen = window->Width;       /*                ... width      */
      maxlen = (maxlen/8) - 4;
      maxlen = maxlen + ccpad;
      ret = ret - 4;
      ret = ret - (ret % 8);        /* Calculate Depth in Characters */
      ret = (ret / 8) -1;

      temp = ret/10;                /* Get ASCII val of Left Digit   */
      bot[1] = 0x30 + temp;
      resize[1] = 0x30 + temp;

      temp = ret % 10;              /* ... Right Digit               */
      bot[2] = 0x30 + temp;
      resize[2] = 0x30 + temp;
      cputs(CWM,resize);
      return(ret);   
      }

/*
    ---------------------------------------- Handle Gadgets
*/
handlegadget(id)
   USHORT id;
   {
   LONG temp;
   switch (id)
      {
      case UP:
      case DOWN:
         while(message != GetMsg(window->UserPort))
            {
            if (class == GADGETUP) break;
            if (id == UP) upone();
            if (id == DOWN) downone();
            }
         if (linecount-MAXDEPTH != 0)
            sliderinfo.VertPot = (lineno * 0xFFFF) / (linecount-MAXDEPTH);
         RefreshGadgets(&slider,window,NULL);
         break;
      case PROP:
         temp = sliderinfo.VertPot;
         lineno = ((linecount-MAXDEPTH) * temp) / 0xFFFF;
         CRefresh(lineno);
         break;
      case PRINT:
         printout();
      }
   }

update()
   {
   if (linecount-MAXDEPTH != 0)
     sliderinfo.VertPot = (lineno * 0xFFFF) / (linecount-MAXDEPTH);
   RefreshGadgets(&slider,window,NULL);
   CRefresh(lineno);
   }

/*
    ---------------------------------------- Send File To Printer
*/

printout()
   {
   int ret, index;
   FILE *fp;

   ret = AutoRequest(window,&rtitle,&ryes,&rno,NULL,NULL,250,50);
   if (ret == 0) return;

   fp = fopen("PRT:","w");
   if (fp == NULL)
      {
      printf("Problem with Printer: %s\n ",sys_errlist[errno]);
      ret = fclose(fp);
      if (ret == -1) xxerr("\nPrinter Not Properly Closed.\n");
      }
   for (ret=0;ret<=linecount;ret++)
      {
      index=0;
      if (colors==2) index=9;
      for(;;)
         {
         if(message = GetMsg(window->UserPort)) goto closeprt;
         /* 
            ---------------------------------------- Filter out Color Coding
         */
         if(line[ret][index]==0) fprintf(fp,"\n");
         if(line[ret][index]==0) break;
         if(index > strlen(line[ret])) fprintf(fp,"\n");
         if(index > strlen(line[ret])) break;
         fprintf(fp,"%c",line[ret][index]);
         index++;
         }
      }
closeprt:
      ret = fclose(fp);
      if (ret == -1) xxerr("\nPrinter Not Properly Closed.\n");
   }

/*
    ---------------------------------------- Refresh Screen
*/
CRefresh(first)
      int first;
      {
      int last;
      cputs(CWM,home);
      if (cflag!=NULL)
          {
          init[4] = fg;
          init[7] = bg;
          cputs(CWM,init);
          }

      last = first + MAXDEPTH;

      for(;first < last; first++)
         {
         if (first > MAXSIZE) break;
         cputsl(CWM, line[first],first);
         cputs(CWM, ceol);
         if (first<last-1)
            cputs(CWM,lf);
         }
      cputs(CWM,ceof);
      }
/*
   ---------------------------------------------------- Scroll Up 1 Line
*/

upone()
   {
   lineno--;
   if (lineno >= 0)
      {
      cputs(CWM,home);
      cputs(CWM,up);
      cputsl(CWM,line[lineno],lineno);
      }
   else lineno = 0;
   }

/*
   ------------------------------------------------------ Down 1 Line
*/

downone()
   {
   int last;

   lineno++;
   last = lineno + MAXDEPTH - 1;
   if (lineno <= lastline)
      {
      cputs(CWM,dn);
      cputs(CWM,bot);
      cputsl(CWM,line[last],last);
      }
   else lineno = lastline;
   }
/*
   ------------------------------------------------------ WBArg FileName
*/

WBArgFN(msg)
   struct WBStartup *msg;
      {
      struct WBArg *arg;
      int args, ret, i, ttab, ws[4];
      char tname[100], *temp, *ttname, **tool;
      
 
      IconBase = OpenLibrary("icon.library",0);
          if (IconBase == NULL) xxerr("Can't Open Icon Library");

      arg = msg->sm_ArgList;        /* Extract WBArguments          */
      args = msg->sm_NumArgs;       /* How Many were there?         */

      arg++;                        /* Incriment arg (who knows?)   */

      CurrentDir(arg->wa_Lock);     /* Set CD to where Icon resides */
      name = arg->wa_Name;          /* Get Name of File             */
      if (name==NULL) return(1);    /*     Check for errors         */
      ret = strcpy(tname,name);
      DO = GetDiskObject(tname);    /* Get Icon Structure           */
      tool = DO->do_ToolTypes;      /* Extract ToolTypes Array      */

      /* ------------------------------------------ Tool Types Args
      */
      ttname = FindToolType(tool,"controls");         /* Control Chars */
            if (stricmp(ttname,"NC") ==0) controls = 1;
            if (stricmp(ttname,"OFF")==0) controls = 1;
            if (stricmp(ttname,"ON") ==0) controls = 0;

         ttname = FindToolType(tool,"colors");      /* Color Options */
         if (ttname)
            {
            ret=0;
            if (stricmp(ttname,"OFF")==0)
                {
                colors = 0;
                ret    = 1;
                }
            if ((ttname[0]=='l') ||(ttname[0]=='L'))
                {                
                switch (strlen(ttname))
                  {
                  case 3:
                     if ((ttname[2]<'8')&&(ttname[2]>'3')) 
                          ttname[2]=ttname[2]-4;
                     bg = ttname[2];
                  case 2:
                     if ((ttname[1]<'8')&&(ttname[1]>'3')) 
                          ttname[1]=ttname[1]-4;
                     fg = ttname[1];
                  }
                colors = 2;
                ccpad  = 9;
                maxlen = maxlen + ccpad;
                ret    = 1; 
                }
            if (ret==0)
                {
                switch (strlen(ttname))
                  {
                  case 3:
                     bg = ttname[2];
                  case 2:
                     fg = ttname[1];
                  case 1:
                     cflag  = ttname[0];
                     colors = 1;
                  }
                  if ((fg<0x30)||(fg>0x33)) fg = 0x31;
                  if ((bg<0x30)||(bg>0x33)) bg = 0x30;
               } 
            }

      ttname = FindToolType(tool,"tabs");             /*      Set Tabs */            
            if (ttname!=NULL)
            {
            temp = strtok(ttname,"|, ");
            for (i=0;i<10,temp!=NULL;i++)
                {
                ret = stcd_i(temp,&ttab);
                if (ret==NULL) break;
                tabs[i]=ttab;
                temp = strtok(NULL,"|, ");
                }
             }

      ttname = FindToolType(tool,"window");          /* Specify Window Size*/
            if (ttname!=NULL)
            {
            temp = strtok(ttname,"|, ");
            for (i=0;i<4,temp!=NULL;i++)
                {
                ret = stcd_i(temp,&ttab);
                if (ret==NULL) break;
                ws[i]=ttab;
                temp = strtok(NULL,"|, ");
                }
            if (ws[0]!=NULL) newwindow.LeftEdge = ws[0];
            if (ws[1]!=NULL) newwindow.TopEdge  = ws[1];
            if (ws[2]!=NULL) newwindow.Width    = ws[2];
            if (ws[3]!=NULL) newwindow.Height   = ws[3];
            wsflag = 1;
            }

      FreeDiskObject(DO);
      if (IconBase) CloseLibrary(IconBase);
      return(0);
      }

   /*
     ------------------------------------------------- Open Libraries
   */
int openlibs()
   {
   if ((IntuitionBase =
      (struct IntuitionBase *)OpenLibrary("intuition.library",1)) == NULL)
         xxerr("Intuition Library not Open");

   if ((GfxBase =
      (struct GfxBase *)OpenLibrary("graphics.library",1)) == NULL)
         xxerr("Graphics Library not Open");

   window = OpenWindow(&newwindow);
   if (window == NULL) xxerr("Window Did Not Open");
   }

/*
  ----------------------------------------------------- Open Console Device
*/
OpenConsole(writerequest,readrequest,window)
   struct IOStdReq *writerequest;
   struct IOStdReq *readrequest;
   struct Window *window;
      {
      int error;
      writerequest->io_Data = (APTR) window;
      writerequest->io_Length = sizeof(*window);
         error = OpenDevice("console.device",0,writerequest,0);
      readrequest->io_Device = writerequest->io_Device;
      readrequest->io_Unit = writerequest->io_Unit;
      return(error);
      }

/*
   ----------------------------------------------- Print String to Window
*/
int cputs(request,string)
   struct IOStdReq *request;
   char *string;
      {
      request->io_Command = CMD_WRITE;
      request->io_Data = string;
      request->io_Length = -1;
 
      DoIO(request);
      return(0);
      }

/*
   ------------------------------------ Print Length-limited String to Window
*/
int cputsl(request,string,line)
   struct IOStdReq *request;
   char *string;
   int line;
      {
      int ret;
      char *tstring; 
      char tbuff[200];
      tstring = &tbuff[0];
      ret = sprintf(tstring,"%s",string);

      ret = strlen(tstring);                /* If string is Greater than */
                                             /* window width, cut it     */
      if (ret > maxlen+ccount[line]) tbuff[maxlen+ccount[line]+1] = 0; 
      request->io_Command = CMD_WRITE;
      request->io_Data = tstring;
      request->io_Length = -1;
 
      DoIO(request);
      return(0);
      }


/*
  -------------------------------- Check Keyboard for Console Reports 
*/

int get(pport,request,whereto)
   struct Port *pport;
   struct IOStdReq *request;
   char *whereto;
      {
      register temp;

      if (GetMsg(pport) == NULL) return(-1);
      temp = *whereto;
      QueueRead(request,whereto);
      return(temp);
      }
/*
    ----------------------------------------- Queue up a Read Request
*/
int QueueRead(request,whereto)
   struct IOStdReq *request;
   char *whereto;
      {
      request->io_Command = CMD_READ;
      request->io_Data = whereto;
      request->io_Length = 1;
 
      SendIO(request);
      return(0);
      }

/*
  --------------------------------------------------- Graceful Exit
*/
xxerr(msg)
   char *msg;
   {
   if (CWM) CloseDevice(CWM);

   if (window) CloseWindow(window);
   if (CRM) DeleteStdIO(CRM);
   if (CRP) DeletePort(CRP);
   if (CWM) DeleteStdIO(CWM);
   if (CWP) DeletePort(CWP);
   if (GfxBase) CloseLibrary(GfxBase);
   if (IntuitionBase) CloseLibrary(IntuitionBase);
   if (msg) printf("    -%s\n",msg);
   exit(0);
   }
