/*******************************************************************
*
*  Task SCRNPLOT
*
* CODE 0    -> EXIT AFTER PLOT
* CODE != 0 -> ENTER INTERACTIVE MODE AFTER PLOT
*
* PARMS[0]: LABEL LOCATIONS <0 NO LABELS
*              100's TITLE,  0-> TOP
*              10's  XLABEL, 0-> BOTTOM
*              1's   YLABEL, 0-> LEFT SIDE
*
* PARMS[1]: X TICS <0 NO TICS
*              100's=0 Inside, 100's >0 Outside
*              10's=0 Double Marks, 10's>0 Single Marks
*              1's=0 BOTTOM, 1's>0 TOP
*
* PARMS[2]: Y TICS <0 NO TICS
*              100's=0 Inside, 100's >0 Outside
*              10's=0 Double Marks, 10's>0 Single Marks
*              1's=0 LEFT, 1's>0 RIGHT
*
* PARMS[3]: <= 0 ->PLOT LINES else PLOT POINTS abs(PARMS[3]) is SYMBOL
* PARMS[4]: LINETYPE TO USE(<= 0 -> SOLID)
* These controls are incremented by 1, if set, for each file plotted.
*
* PARMS[5]: T LOG BASE
* PARMS[6]: Y LOG BASE
* 
* PARMS[7]: T-AXIS END POINT LABELING (1's LOWER, 10's HIGHER)
* PARMS[8]: Y-AXIS END POINT LABELING (1's LOWER, 10's HIGHER)
*
* PARMS[9]: NUMERIC LABEL CONTROL (1's  Y AXIS HORIZONTAL NUMBERS DEFAULT)
*                                 (10's T AXIS HORIZONTAL NUMBERS DEFAULT)]
*                                 (100's INVERT Y AXIS IF SET)
*                                 (1000's INVERT T AXIS IF SET)
*                                 
* COLOR: 10's SET BACKGROUND (0-15)
*        1's  SET POINT COLOR (1-6)
*
* FACTOR: Data skip interval (2 = every other point, ect.)
*/
#include <malloc.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <io.h>
#include <time.h>
#include <dos.h>
#include <process.h>
#include <ctype.h>
#include <signal.h>

#include "TISAN.H"
#include "TISANFNT.H"

#define CGASpos(X,Y) (((Y>>1)<<6)+((Y>>1)<<4)+((Y&1)<<13) + (X>>GF1))
#define CGAPel(X) (1<<((GF2 - (X - ((X>>GF1)<<GF1)))<<GF3))
#define HERCSpos(X,Y) (0x2000*((Y)%4)) + 90*((Y)>>2) + ((X)>>3)
#define HERCPel(X) (1<<(7 - ((X)%8)))

#define Tpnt(x) (IITA ? (W0 + W2 - (x)) : (x))    /* Reverse T Axis */
#define Ypnt(y) (IIYA ? (W1 + W3 - (y)) : (y))    /* Reverse Y Axis */

void MAININIT(void);
void PLOT1(FILE *);
void PLOT2(FILE *,FILE *);
short IMLOAD(FILE *,char *,char);
short SETMODE(short);
void FRAMEIT(void);
void PUTLAB(void);
void PUTTICS(void);
void PLTALPHA(char *,short,short,short);
void PLTSYM(double,double);
void ROTATE(short *,short *,double);
short GETRNG(double *,double *,double *,double *,FILE *,struct FILEHDR *,int);
short INTERACT(FILE *,FILE *);
void SETCOLOR(void);
void CURSOR(short,short);
short GTEXT(short *,short *);
short XMOVE(short *,short *);
void LINECLR(void);
void LINEPUT(void);
void LINEGET(void);
double PLOG(double,short);
void PTXTICS(short,short);
void PTYTICS(short,short);
void PTSETUP(short *,short *);
void LINE(short,short,short,short);
void VECTOR(double,double,double,double,short);
extern void THERCMODE(void);
extern void GHERCMODE(void);
void CHKBRK(void);
short FPEERROR(void);

void PSET(short,short);     /* Pointers to Pixel Setting Functions */
void XPSET(short,short);

short CWIDTH=8, CHEIGHT=8, XTICBASE=6, YTICBASE=8;
short SCLIPXL,SCLIPYL,SCLIPXH,SCLIPYH,HCLIPX,HCLIPY,NOCLIP=0;
short LT1=0, LT2=0, SLT1=0, SLT2=0, IYV, ITV, IIYA, IITA;
short W0, W1, W2, W3, T2FLAG=0;
short GF1, GF2, GF3, CS1, CS2;
char BUFFER[256];
char far *SCREEN;
char SBUFF[1280], TMPFILE[_MAX_PATH];
double TSLOPE, TINTER, YSLOPE, YINTER, T0, T1, TCNT, TIME;
double TPL1, TPL2, YPL1, YPL2, XROT, YROT, YSLOPE, YINTER, YDELTA;
double TDELTA, YVT, TVT;
union REGS REGISTER;
short LUTABLE[] = {1,2,4,5,8,10,10,15,15,20,25};

struct FILEHDR FileHeader, F1Header, F2Header;
char BUFFER1[sizeof(struct TXData)];
char BUFFER2[sizeof(struct TXData)];
struct RData   *RDataPntr1,  *RDataPntr2;
struct TRData *TRDataPntr1, *TRDataPntr2;
struct TXData *TXDataPntr1, *TXDataPntr2;
struct XData   *XDataPntr1,  *XDataPntr2;
long LFPS1, LFPE1;  /* Long File Pointer Start and End */
double TCNTS, TCNTE;
double TIME, DATA;
short FLAG=0, CGMODE;
double TOTAL=0.;
short FirstPointFlag;

main(argc,argv)
short argc;
char *argv[];
   {
   FILE *INSTR, *IN2STR=0, *OUTSTR=0;
   double YMAX, YMIN, TMIN ,TMAX;
   double TR1, TR2, YR1, YR2;
   short NOTSET=1, I, N;
   unsigned short UI, UN;
   short ERRFLAG=0;
   struct CATSTRUCT *CatList;
   char *pChar;
   char Drive[_MAX_DRIVE], Dir[_MAX_DIR], Fname[_MAX_FNAME], Ext[_MAX_EXT];
   char INFILE[_MAX_PATH], IN2FILE[_MAX_PATH], OUTFILE[_MAX_PATH], C;
   int AutoAmpScale = 0, AutoTimeScale = 0, SecondFile = 0, OutPutFile = 0;

   signal(SIGINT,BREAKREQ);
   signal(SIGFPE,FPEERROR);  /* Setup Floating Point Error Trap */

   if (Ztskinit("SCRNPLOT",argv[0])) Zexit(1);

   switch (HARDWARE.scrn)
      {
      case CGA_scrn:    /* Only CGA and HERC are currently supported */
      case HERC_scrn:
      case DUAL_scrn:
         break;
      default:
         Zencode(10,"SCRNPLOT: No Graphics Display Device Available.\n");
         Zexit(1);
      }

   T0 = TRANGE[0];
   T1 = TRANGE[1];

   MAININIT();

   if (YRANGE[0] >= YRANGE[1]) AutoAmpScale = 1;
   if (TRANGE[0] >= TRANGE[1]) AutoTimeScale = 1;

   ZBuildFileName(M_inname,INFILE);
   ZBuildFileName(M_in2name,IN2FILE);
   ZBuildFileName(M_tmpname,TMPFILE);
   ZBuildFileName(M_outname,OUTFILE);

   if (strcmp(INFILE,IN2FILE)) SecondFile = 1;
   if (strcmp(INFILE,OUTFILE)) OutPutFile = 1;

   if (!(CatList = ZCatFiles(INFILE))) Zexit(1); /* Find Matching Files */

   if (AutoAmpScale || AutoTimeScale)
      {
      Zencode(3,"SCRNPLOT: Determining Primary File Scale(s)\n");
      for (I = 0, pChar = CatList->pList;
           (I < CatList->N) && !ERRFLAG;
           ++I, pChar = strchr(pChar,'\0') + 1)
         {
         _splitpath(pChar,Drive,Dir,Fname,Ext);
         strcpy(INNAME,Fname);
         strcpy(INCLASS,Ext);
         ZBuildFileName(M_inname,INFILE);
         Zencode(2,"SCRNPLOT: Opening Input File '%s'\n",INFILE);
         if (((INSTR = Zopen(INFILE,O_readb)) == NULL) ||
           (!Zgethead(INSTR,&F1Header))) Zexit(1);
         switch (F1Header.type)
            {
            case R_Data:
            case TR_Data:
            case X_Data:
            case TX_Data:
               break;
            default:
               Zencode(10,"SCRNPLOT: Invalid File Type.\n");
               Zexit(1);
            }
         if (GETRNG(&YMAX,&YMIN,&TMAX,&TMIN,INSTR,&F1Header,I))
            {
            ERRFLAG = 1;
            goto EXIT;
            }
         Zclose(INSTR);
         }
      if (AutoAmpScale) /* Find Scale */
         {
         YRANGE[0] = YMIN;
         YRANGE[1] = YMAX;
         }
      if (AutoTimeScale)
         {
         TRANGE[0] = TMIN;
         TRANGE[1] = TMAX;
         }
      }

   if (OutPutFile)
      {
      if (strchr(OUTFILE,'*') || strchr(OUTFILE,'?'))
         {
         Zencode(10,"SCRNPLOT: Invalid Output File Name '%s'\n",OUTFILE);
         Zexit(1);
         }

      Zencode(2,"SCRNPLOT: Opening Scratch File '%s'\n",TMPFILE);
      if ((OUTSTR = Zopen(TMPFILE,O_writeb)) == NULL) Zexit(1);
      }

   if (SecondFile)
      {
      if (strchr(IN2FILE,'*') || strchr(IN2FILE,'?'))
         {
         Zencode(10,"SCRNPLOT: Invalid Secondary File Name '%s'\n",IN2FILE);
         Zexit(1);
         }

      Zencode(2,"SCRNPLOT: Opening Secondary Input File '%s'\n",IN2FILE);
      if (((IN2STR = Zopen(IN2FILE,O_readb)) == NULL) ||
          (!Zgethead(IN2STR,&F2Header)))
         {
         ERRFLAG = 1;
         goto EXIT;
         }

      switch (F2Header.type)
         {
         case R_Data:
         case TR_Data:
         case X_Data:
         case TX_Data:
            T2FLAG=1;
            if (T0 >= T1) /* Find Scale */
               {
               Zencode(3,"SCRNPLOT: Determining Secondary File Scale\n");
               if (GETRNG(&YMAX,&YMIN,&TMAX,&TMIN,IN2STR,&F2Header,0))
                  {
                  ERRFLAG = 1;
                  goto EXIT;
                  }
               TRANGE[0] = YMIN;
               TRANGE[1] = YMAX;
               }
            break;
         case CGA_HiResImage:
         case CGA_LoResImage:
         case HERC_MonoImage:
            if (IMLOAD(IN2STR,IN2FILE,F2Header.type))
               {
               ERRFLAG = 1;
               goto EXIT;
               }
            NOTSET = 0;
            break;
         default:
            Zencode(10,"SCRNPLOT: Invalid File Type.\n");
            ERRFLAG = 1;
            goto EXIT;
         }
      }
/*
** From This Point On, Only Terminal Messages Can be Printed
*/
   if (TRANGE[0] == TRANGE[1])
      {
      ++TRANGE[1];
      --TRANGE[0];
      }
   if (YRANGE[0] == YRANGE[1])
      {
      --YRANGE[0];
      ++YRANGE[1];
      }
   if (NOTSET)
      {
      SETMODE(CGMODE);
      SETCOLOR();
      }

   WINDOW[1] = HCLIPY - WINDOW[1];
   WINDOW[3] = HCLIPY - WINDOW[3];
   if (FRAME) FRAMEIT();
   W0 = WINDOW[0];
   W1 = WINDOW[1];
   W2 = WINDOW[2];
   W3 = WINDOW[3];

   PUTLAB();
   PUTTICS();

   SCLIPXL = WINDOW[0] = W0;
   SCLIPXH = WINDOW[2] = W2;
   SCLIPYL = WINDOW[3] = W3;
   SCLIPYH = WINDOW[1] = W1;

   if (BORDER) FRAMEIT();

   if (PARMS[5])
      {
      TR1 = PLOG(TRANGE[0],5);
      TR2 = PLOG(TRANGE[1],5);
      }
   else
      {
      TR1 = TRANGE[0];
      TR2 = TRANGE[1];
      }
   if (PARMS[6])
      {
      YR1 = PLOG(YRANGE[0],6);
      YR2 = PLOG(YRANGE[1],6);
      }
   else
      {
      YR1 = YRANGE[0];
      YR2 = YRANGE[1];
      }

   TSLOPE = ((double)(WINDOW[2] - WINDOW[0]))/(TR2 - TR1);
   TINTER = (double)WINDOW[0] - TSLOPE*TR1;
   YSLOPE = ((double)(WINDOW[3] - WINDOW[1]))/(YR2 - YR1);
   YINTER = (double)WINDOW[1] - YSLOPE*YR1;

   SLT2 = LT2 = PARMS[4]/10;
   SLT1 = LT1 = (short)PARMS[4]%10;
   YPL1 = YRANGE[0];
   YPL2 = YRANGE[1];
   TPL1 = TRANGE[0];
   TPL2 = TRANGE[1];

   for (I = 0, pChar = CatList->pList;
        (I < CatList->N) && !ERRFLAG;
        ++I, pChar = strchr(pChar,'\0') + 1)
      {
      FirstPointFlag = 0;
      TCNT = 0.;
      LFPS1 = LFPE1 = 0L;  /* Long File Pointer Start and End */
      _splitpath(pChar,Drive,Dir,Fname,Ext);
      strcpy(INNAME,Fname);
      strcpy(INCLASS,Ext);
      ZBuildFileName(M_inname,INFILE);
      if (((INSTR = Zopen(INFILE,O_readb)) == NULL) ||
           (!Zgethead(INSTR,&F1Header)))
         {
         Zencode(10,"SCRNPLOT: Error Reading Input File '%s'\n",INFILE);
         Zexit(1);
         }
      switch (F1Header.type)
         {
         case R_Data:
         case TR_Data:
         case X_Data:
         case TX_Data:
            break;
         default:
            Zencode(10,"SCRNPLOT: Invalid File Type.\n");
            Zexit(1);
         }

      if (!T2FLAG)
         {
         while (Zread(INSTR,BUFFER1,F1Header.type)) PLOT1(INSTR);
         if (ferror(INSTR)) ERRFLAG=1;
         }
      else /* Plot 2 Files Against One Another */
         {
         while (Zread(INSTR,BUFFER1,F1Header.type) &&
                Zread(IN2STR,BUFFER2,F2Header.type)) PLOT2(INSTR,IN2STR);
         if (ferror(INSTR) || ferror(IN2STR)) ERRFLAG=1;
         }
      Zclose(INSTR);
/*
      (PARMS[3] < 0) ? --PARMS[3] : (PARMS[3] ? ++PARMS[3] : 0);
      if (PARMS[4]) ++PARMS[4];
*/
      }

   NOCLIP=1;
   if (COLOR) CGMODE=4;
/*
** CODE specifies how the program terminates.
**   CODE = 0 (default)
** Exit without entering interactive mode
**
**   CODE = 1
** Now Enter the Routine to Display Time and Values
** Interactively.  Pressing the ESCAPE key will gracefully Zexit
** the program.  Use Arrows (Right and UP) or (Left and Down)
** to move one pixil at a time.  Use ATL Arrows to move 10 at a 
** time.
**
*/
   if (CODE)
      {
      if (((INSTR = Zopen(INFILE,O_readb)) == NULL) ||
           (!Zgethead(INSTR,&F1Header)))
         {
         Zencode(10,"SCRNPLOT: Error Reading Input File '%s'\n",INFILE);
         Zexit(1);
         }
      ERRFLAG = INTERACT(INSTR,IN2STR);
      Zgetadv("SCRNPLOT");
      TRANGE[0] = T0;
      TRANGE[1] = T1;
      Zputadv("SCRNPLOT");
      }
/*
** Plot is Now Complete.
** If OUTSTR then save the image
*/
   switch (HARDWARE.scrn)
      {
      case CGA_scrn:
      case DUAL_scrn:
         UN=0x4000;
         switch(CGMODE)
            {  
            case 6:  /* HiRes Plot */
               FileHeader.type = CGA_HiResImage;
               break;
            case 4:  /* LoRes Plot */
               FileHeader.type = CGA_LoResImage;
               break;
            }
         break;
      case HERC_scrn:
         FileHeader.type = HERC_MonoImage;
         UN=0x8000;
         break;
      }

   if (OUTSTR)
      {
      if (Zputhead(OUTSTR,&FileHeader))
         ERRFLAG = 1;
      else
         {
         FP_OFF(SCREEN) = 0;
         for (UI=0;UI<UN;++UI,++SCREEN) fputc(*SCREEN,OUTSTR);
         }
      }

   SETMODE(3);
   if (!ERRFLAG)
      {
      Zencode(3,"SCRNPLOT: %G Data Points Processed\n",TOTAL);
      Zencode(3,"SCRNPLOT: T Range Displayed %G, %G\n",TPL1,TPL2);
      Zencode(3,"SCRNPLOT: Y Range Displayed %G, %G\n",YPL1,YPL2);
      }
EXIT:
   if (IN2STR) Zclose(IN2STR);
   if (OUTSTR)
      {
      Zclose(OUTSTR);
      ERRFLAG = Znameout(OUTFILE,TMPFILE,ERRFLAG);
      }
   Zexit(ERRFLAG);
   }

/************************************************************
*
* INITIALIZATION
*
*/
void MAININIT()
   {
   short I;

   if ((PARMS[4] <0) || (PARMS[4] > 99)) PARMS[4] = 0;
   if (PARMS[5]) TMINOR = Max(TMINOR,2);
   if (PARMS[6]) YMINOR = Max(YMINOR,2);
   if ((PARMS[5] <=0) || (PARMS[5] == 1))
      PARMS[5] = 0;
   else
      PARMS[5] = log(PARMS[5]);
   if ((PARMS[6] <=0) || (PARMS[6] == 1))
      PARMS[6] = 0;
   else
      PARMS[6] = log(PARMS[6]);
   if (PARMS[7] <0) PARMS[7] = 0;
   if (PARMS[8] <0) PARMS[8] = 0;

   SCLIPXL=SCLIPYL=0;
   switch (HARDWARE.scrn)
      {
      case CGA_scrn:
      case DUAL_scrn:
         if (COLOR > 0) /* LoRes */
            {
            CGMODE = 4;
            SCLIPXH=HCLIPX = 319;
            SCLIPYH=HCLIPY = 199;
            FP_SEG(SCREEN) = 0xB800;
            }
         else
            {
            CGMODE = 6; /* HiRes */
            SCLIPXH=HCLIPX = 639;
            SCLIPYH=HCLIPY = 199;
            COLOR = 0;
            FP_SEG(SCREEN) = 0xB800;
            }
         break;
      case HERC_scrn:
         CGMODE = 7;
         SCLIPXH=HCLIPX = 719;
         SCLIPYH=HCLIPY = 347;
         FP_SEG(SCREEN) = 0xB000;
         COLOR = 0;
         break;
      }
 
   WINDOW[0] = Max(WINDOW[0],0);
   WINDOW[2] = Max(WINDOW[2],0);
   WINDOW[1] = Min(WINDOW[1],HCLIPX);
   WINDOW[3] = Min(WINDOW[3],HCLIPY);
   if (WINDOW[0] >= WINDOW[2])
      {
      WINDOW[0] = 0;
      WINDOW[2] = HCLIPX;
      }
   if (WINDOW[1] >= WINDOW[3])
      {
      WINDOW[1] = 0;
      WINDOW[3] = HCLIPY;
      }
   if (!strlen(TFORMAT)) strcpy(TFORMAT,"%G");
   if (!strlen(YFORMAT)) strcpy(YFORMAT,"%G");

   RDataPntr1 =  (struct RData *)BUFFER1;     /* Initialize pointers */
   RDataPntr2 =  (struct RData *)BUFFER2;
   TRDataPntr1 = (struct TRData *)BUFFER1;
   TRDataPntr2 = (struct TRData *)BUFFER2;
   XDataPntr1 =  (struct XData *)BUFFER1;
   XDataPntr2 =  (struct XData *)BUFFER2;
   TXDataPntr1 = (struct TXData *)BUFFER1;
   TXDataPntr2 = (struct TXData *)BUFFER2;
   return;
   }

/************************************************************
*
* PLOT1
*     Plot a single file.
*
*/
void PLOT1(INSTR)
FILE *INSTR;
   {
   double XLOC, YLOC;

   ++TOTAL;
   switch (F1Header.type)
      {
      case R_Data:
         TIME = TCNT * F1Header.m + F1Header.b;
         DATA = RDataPntr1->y;
         FLAG = RDataPntr1->f;
         break;
      case TR_Data:
         TIME = TRDataPntr1->t;
         DATA = TRDataPntr1->y;
         break;
      case X_Data:
         TIME = TCNT * F1Header.m + F1Header.b;
         DATA = cabs(XDataPntr1->z);
         FLAG = XDataPntr1->f;
         break;
      case TX_Data:
         TIME = TXDataPntr1->t;
         DATA = cabs(TXDataPntr1->z);
         break;
      }

   CHKBRK();            /* Test for ^C */

   if (!LFPS1 && ((TIME>=TRANGE[0]) || (TRANGE[1]<=TRANGE[0])))
      {
      LFPS1 = ftell(INSTR); /* First Value Plotted */
      TCNTS = TCNT;
      }

   if ((TRANGE[1]<=TRANGE[0]) || (TIME<=TRANGE[1]))
      {
      LFPE1 = ftell(INSTR); /* Last Value in File */
      TCNTE = TCNT;
      }
   ++TCNT;

   if (!FLAG)           /* Only plot good data */
      {
      if (PARMS[5]) TIME = PLOG(TIME,5);
      if (PARMS[6]) DATA = PLOG(DATA,6);
      XLOC = Tpnt(TSLOPE*TIME + TINTER);
      YLOC = Ypnt(YSLOPE*DATA + YINTER);
      if (PARMS[3]>0)
         PLTSYM(XLOC,YLOC);
      else if (!FirstPointFlag)                     /* First point */
         {
         if (PARMS[3]) PLTSYM(XLOC,YLOC);
         VECTOR(XLOC,YLOC,XLOC,YLOC,0);
         FirstPointFlag = 1;
         }
      else                                /* Rest of points */
         {
         VECTOR(0.,0.,XLOC,YLOC,1);
         if (PARMS[3]) PLTSYM(XLOC,YLOC);
         }
      }
   return;
   }

/************************************************************
*
* PLOT2
*
*/
void PLOT2(INSTR,IN2STR)
FILE *INSTR, *IN2STR;
   {
   double XLOC, YLOC;

   ++TOTAL;
   switch (F1Header.type)    /* Data is Y Axis */
      {
      case R_Data:
         DATA = RDataPntr1->y;
         FLAG = RDataPntr1->f;
         break;
      case TR_Data:
         DATA = TRDataPntr1->y;
         break;
      case X_Data:
         DATA = cabs(XDataPntr1->z);
         FLAG = XDataPntr1->f;
         break;
      case TX_Data:
         DATA = cabs(TXDataPntr1->z);
         break;
      }

   switch (F2Header.type)    /* Data is TIME Axis */
      {
      case R_Data:
         TIME = RDataPntr2->y;
         FLAG += RDataPntr2->f;
         break;
      case TR_Data:
         TIME = TRDataPntr2->y;
         break;
      case X_Data:
         TIME = cabs(XDataPntr2->z);
         FLAG += XDataPntr2->f;
         break;
      case TX_Data:
         TIME = cabs(TXDataPntr2->z);
         break;
      }

   CHKBRK();

   if (!FLAG)
      {
      if (PARMS[5]) TIME = PLOG(TIME,5);
      if (PARMS[6]) DATA = PLOG(DATA,6);
      XLOC = Tpnt(TSLOPE*TIME + TINTER);
      YLOC = Ypnt(YSLOPE*DATA + YINTER);
      if (PARMS[3]>0)
         PLTSYM(XLOC,YLOC);
      else if (!FirstPointFlag)
         {
         if (PARMS[3]) PLTSYM(XLOC,YLOC);
         VECTOR(XLOC,YLOC,XLOC,YLOC,0);
         FirstPointFlag = 1;
         }
      else
         {
         VECTOR(0.,0.,XLOC,YLOC,1);
         if (PARMS[3]) PLTSYM(XLOC,YLOC);
         }
      }
     return;
     }

/************************************************************
*
* Function to load an image or open read the secondary file
*
*/
short IMLOAD(IN2STR,IN2FILE,TYPE)
FILE *IN2STR;
char *IN2FILE;
char TYPE;
   {
   short ERRFLAG = 0;
   unsigned short I;

   switch (TYPE)
      {
      case CGA_HiResImage:
         if (COLOR)
            {
            Zencode(8,"SCRNPLOT: NOTICE... ");
            Zencode(8,"'%s' is not a Color Plot\n",IN2FILE);
            }
         SETMODE(6);
         COLOR = 0;
         SETCOLOR();
         FP_OFF(SCREEN) = 0;
         for (I=0;I<0x4000;++I,++SCREEN) *SCREEN = fgetc(IN2STR);
         break;
      case CGA_LoResImage:
         if (!COLOR)
            {
            Zencode(8,"SCRNPLOT: NOTICE... ");
            Zencode(8,"'%s' is a Color Plot\n",IN2FILE);
            }
         SETMODE(4);
         COLOR = Max(1,COLOR);
         SETCOLOR();
         FP_OFF(SCREEN) = 0;
         for (I=0;I<0x4000;++I,++SCREEN) *SCREEN = fgetc(IN2STR);
         break;
      case HERC_MonoImage:
         SETMODE(7);
         COLOR=0;
         FP_OFF(SCREEN) = 0;
         for (I=0;I<0x8000;++I,++SCREEN) *SCREEN = fgetc(IN2STR);
         break;
      }
   if (ferror(IN2STR)) ERRFLAG = 1;
   return(ERRFLAG);
   }

/***************************************************************
**
**  Subroutine to Set the Mode of the Graphics Screen
**
**        case 0:  40x25 bw
**        case 1:  40x25 color
**        case 2:  80x25 bw
**        case 3:  80x25 color
**        case 4:  320x200 color
**        case 5:  320x200 bw
**        case 6:  640x200
**        case 7:  Hercules Monochrome Graphics
*/
short SETMODE(MODE)
short MODE;
   {
   char far *ZEROP;

   FP_OFF(ZEROP) = 0x410;
   FP_SEG(ZEROP) = 0;

   if (HARDWARE.scrn == DUAL_scrn) /* Dual Display */
      {
      if (MODE > 3) /* Switch to Graphics */
         {
         *ZEROP &= 0xCF;
         *ZEROP |= 0x20;
          }
      else
         *ZEROP |= 0x30; /* Switch to Monochrome */
      }

   if (HARDWARE.scrn == HERC_scrn)    /* Hercules */
      {
      if (MODE != 7)
         {
         THERCMODE();
         REGISTER.x.ax = 3;
         int86(0x10,®ISTER,®ISTER);
         }
      else
         GHERCMODE();
      }
   else
      {
      REGISTER.h.al = (char)MODE;
      REGISTER.h.ah = (char)0;
      int86(0x10,®ISTER,®ISTER);
      }
   return(0);
   }

/************************************************************
*
* Subroutine to Frame the Current Window
*
*/
void FRAMEIT()
   {
   LINE(WINDOW[0],WINDOW[1],WINDOW[0],WINDOW[3]);
   LINE(WINDOW[0],WINDOW[3],WINDOW[2],WINDOW[3]);
   LINE(WINDOW[2],WINDOW[3],WINDOW[2],WINDOW[1]);
   LINE(WINDOW[2],WINDOW[1],WINDOW[0],WINDOW[1]);
   return;
   }

/************************************************************
*
* Subroutine to Title the Plot and update WINDOW
*
*/
void PUTLAB()
     {
     short XLOC, YLOC;
     short VAL, IPARM;
     char C;
/*
*
* Center the Title at the top or bottom and update WINDOW
*
*/
     if (PARMS[0] < 0) return;
     IPARM = PARMS[0];
     VAL = IPARM/100;
     IPARM %= 100;
     if (strlen(TITLE))
          {
          XLOC =  (W2 + W0 + 1 - strlen(TITLE)*CWIDTH)/2;
          if (VAL)
               {
               YLOC = W1; 
               W1 -= (CHEIGHT + CHEIGHT/8);
               if (FRAME)
                    {
                    --YLOC;
                    --W1;
                    }
               }
          else
               {
               YLOC = (W3 += CHEIGHT);
               W3 += CHEIGHT/8;
               if (FRAME)
                    {
                    ++YLOC;
                    ++W3;
                    }
               }
          CHKBRK();
          PLTALPHA(TITLE,XLOC,YLOC,0);
          }
     VAL = IPARM/10;
     IPARM %= 10;
     if (strlen(TLABEL))
          {
          XLOC =  (W2 + W0 + 1 - strlen(TLABEL)*CWIDTH)/2;
          if (VAL)
               {
               YLOC = (W3 += CHEIGHT);
               W3 += CHEIGHT/8;
               if (FRAME)
                    {
                    ++YLOC;
                    ++W3;
                    }
               }
          else
               {
               YLOC = W1; 
               W1 -= (CHEIGHT + CHEIGHT/8);
               if (FRAME)
                    {
                    --YLOC;
                    --W1;
                    }
               }
          CHKBRK();
          PLTALPHA(TLABEL,XLOC,YLOC,0);
          }

     if (strlen(YLABEL))
          {
          YLOC =  (W1 + W3 + 1 + strlen(YLABEL)*CWIDTH)/2;
          if (IPARM)
               {
               XLOC = W2; 
               W2 -= (CHEIGHT + CHEIGHT/4);
               if (FRAME)
                    {
                    --XLOC;
                    --W2;
                    }
               }
          else
               {
               XLOC = (W0 += CHEIGHT);
               W0 += CHEIGHT/4;
               if (FRAME)
                    {
                    ++XLOC;
                    ++W0;
                    }
               }
          CHKBRK();
          PLTALPHA(YLABEL,XLOC,YLOC,90);
          }
     return;
     }

/************************************************************
*
* Subroutine to Plot Tic Marks and Numeric Labels
*
*/
void PUTTICS()
     {
     short XLOC, YLOC;

     PTSETUP(&XLOC,&YLOC);
     PTXTICS(XLOC,YLOC);
     PTYTICS(XLOC,YLOC);
     return;
     }

/************************************************************
*
* Function for setting up values for tic marks
*
*/
void PTSETUP(X,Y)
short *X, *Y;
     {
     double N, XP, YP;
     short IPARM, ILFLG, DSFLG, TBFLGY, TBFLGT, IOFLG, IGRID;
     short XLOC, YLOC, I;
     double YY, DELTA, V1T, V2T, V1Y, V2Y, V, XX;
     short BLENY=0, BLENT=0;
     short IDAT;

     I = fabs(PARMS[9]);
     IITA = I/1000;
     I %= 1000;
     IIYA = I/100;
     I %= 100;
     ITV = I/10;
     IYV = I%10;

     if (TMAJOR[1] < 0.)
          {
          N = floor(log10(TRANGE[1] - TRANGE[0]));
          N = pow(10.,N);
          I = ((TRANGE[1] - TRANGE[0])/N + .5);
          TMAJOR[1] = LUTABLE[I]*N/10.;
          TMAJOR[0] = TRANGE[1] - fabs(fmod(TRANGE[1],TMAJOR[1]));
          if (PARMS[5])
               {
               TMAJOR[1] = 1.;
               TMAJOR[0] = pow(10.,floor(PLOG(TMAJOR[0],5)));
               }
          }

     if (YMAJOR[1] < 0.)
          {
          N = floor(log10(YRANGE[1] - YRANGE[0]));
          N = pow(10.,N);
          I = ((YRANGE[1] - YRANGE[0])/N + .5);
          YMAJOR[1] = LUTABLE[I]*N/10.;
          YMAJOR[0] = YRANGE[1] - fabs(fmod(YRANGE[1],YMAJOR[1]));
          if (PARMS[6])
               {
               YMAJOR[1] = 1.;
               YMAJOR[0] = pow(10.,floor(PLOG(YMAJOR[0],6)));
               }
          }

     if ((TMAJOR[0] < TRANGE[0]) || (TMAJOR[0] > TRANGE[1]))
          TMAJOR[1] = 0.;

     if ((YMAJOR[0] < YRANGE[0]) || (YMAJOR[0] > YRANGE[1]))
          YMAJOR[1] = 0.;

     XROT = 90.;
     if (PARMS[1] >= 0.)
          {
          IPARM = (short)PARMS[1];
          IGRID = IPARM/1000;           /* Grid Flag */
          IPARM %= 1000;
          IOFLG =  IPARM/100;           /* Outside Tics */
          IPARM %= 100;
          DSFLG = IPARM/10;             /* Double Sided Tics 0 -> Yes */
          IPARM %= 10;
          TBFLGT = IPARM;               /* Top/Bottom Exchange */
          if (TMAJOR[1])
               {
               if (!TBFLGT) /* Set WINDOW According to the Side Chosen */
                    {
                    YLOC = W1; 
                    if (!ITV) W1 -= (CHEIGHT + CHEIGHT/8);
                    if (IOFLG)
                         {
                         W1 -= XTICBASE;
                         if (!DSFLG) W3 += XTICBASE;
                         }
                    }
               else
                    {
                    if (!ITV)
                         {
                         YLOC = (W3 += CHEIGHT);
                         W3 += CHEIGHT/8;
                         }
                    if (IOFLG)
                         {
                         W3 += XTICBASE;
                         if (!DSFLG) W1 -= XTICBASE;
                         }
                    }
               }

          if (PARMS[5])       /* Log T Axis */
               {
               V1T = PLOG(TRANGE[0],5);
               V2T = PLOG(TRANGE[1],5);
               if (TMAJOR[0] > 0) TVT = PLOG(TMAJOR[0],5);
/*
* TMAJOR[1] now represents an exponent which is
* the seperation of the major tic marks in log space.
* NOTE: PARMS[5] is now log(P5)
*/
               TDELTA = exp(PARMS[5]*TMAJOR[1])/(double)(TMINOR);
               TMINOR -= 2;
               }
          else
               {
               V1T = TRANGE[0];
               V2T = TRANGE[1];
               TVT = TMAJOR[0];
               TDELTA = TMAJOR[1]/(double)(TMINOR+1);
               }

          if (TMAJOR[1] && ITV)
               {
               for (XX=TVT;XX >= V1T;XX-=TMAJOR[1])
                    {
                    CHKBRK();
                    if (PARMS[5]) XP = exp(XX*PARMS[5]); else XP = XX;
                    sprintf(BUFFER,TFORMAT,XP);
                    BLENT = Max(strlen(BUFFER)*CWIDTH,BLENT);
                    }
               for (XX=TVT;XX <= V2T;XX+=TMAJOR[1])
                    {
                    CHKBRK();
                    if (PARMS[5]) XP = exp(XX*PARMS[5]); else XP = XX;
                    sprintf(BUFFER,TFORMAT,XP);
                    BLENT = Max(strlen(BUFFER)*CWIDTH,BLENT);
                    }
               }
          else
               XROT = 0.;
          }

     YROT = 0.;
     if (PARMS[2] >= 0)
          {
          IPARM = PARMS[2];
          IGRID = IPARM/1000;
          IPARM %= 1000;
          IOFLG = IPARM/100;
          IPARM %= 100;
          DSFLG = IPARM/10;
          IPARM %= 10;
          TBFLGY = IPARM;
          if (YMAJOR[1])
               {
               if (!TBFLGY)
                    {
                    XLOC = W0;
                    if (IYV)
                         {
                         XLOC = (W0 += CHEIGHT);
                         W0 += CHEIGHT/4;
                         }
                    if (IOFLG)
                         {
                         W0 += YTICBASE;
                         if (!DSFLG) W2 -= YTICBASE;
                         }
                    }
               else
                    {
                    XLOC = W2;
                    if (IYV) W2 -= (CHEIGHT + CHEIGHT/4);
                    if (IOFLG)
                         {
                         W2 -= YTICBASE;
                         if (!DSFLG) W0 += YTICBASE;
                         }
                    }
               }
          if (PARMS[6])
               {
               V1Y = PLOG(YRANGE[0],6);
               V2Y = PLOG(YRANGE[1],6);
               if (YMAJOR[0] > 0) YVT = PLOG(YMAJOR[0],6);
               YDELTA = exp(PARMS[6]*YMAJOR[1])/(double)(YMINOR);
               YMINOR -= 2;
               }
          else
               {
               V1Y = YRANGE[0];
               V2Y = YRANGE[1];
               YVT = YMAJOR[0];
               YDELTA = YMAJOR[1]/(double)(YMINOR+1);
               }

          if (YMAJOR[1] && !IYV)
               {
               for (YY=YVT;YY >= V1Y;YY-=YMAJOR[1])
                    {
                    CHKBRK();
                    if (PARMS[6]) YP = exp(YY*PARMS[6]); else YP = YY;
                    sprintf(BUFFER,YFORMAT,YP);
                    BLENY = Max(strlen(BUFFER)*CWIDTH,BLENY);
                    }
               for (YY=YVT;YY <= V2Y;YY+=YMAJOR[1])
                    {
                    CHKBRK();
                    if (PARMS[6]) YP = exp(YY*PARMS[6]); else YP = YY;
                    sprintf(BUFFER,YFORMAT,YP);
                    BLENY = Max(strlen(BUFFER)*CWIDTH,BLENY);
                    }
               }
          else
               YROT = 90.;
          }

     if (TBFLGT && ITV)
          {
          YLOC = (W3 += BLENT);
          W3 += CHEIGHT/4;
          }
     else
          W1 -= BLENT;

     if (TBFLGY && !IYV)
          {
          XLOC = (W2 -= BLENY);
          W2 -= CHEIGHT/4;
          }
     else
          W0 += BLENY;

     TSLOPE = ((double)(W2 - W0))/(V2T - V1T);
     TINTER = (double)W0 - TSLOPE*V1T;

     YSLOPE = ((double)(W3 - W1))/(V2Y - V1Y);
     YINTER = (double)W1 - YSLOPE*V1Y;

     *X = XLOC;
     *Y = YLOC;

     return;
     }

/************************************************************
*
* X tic Marks
*
*/
void PTXTICS(XLOC,YLOC)
short XLOC,YLOC;
     {
     double X, V1, V2, XP, V;
     short XL, TBFLG, DSFLG, IOFLG, IPARM, I, BLEN;
     short IDAT, HILAB, LOLAB, IGRID;
     char C;

     if (PARMS[1] >= 0)
          {
          IPARM = PARMS[1];
          IGRID = IPARM/1000;
          IPARM %= 1000;
          IOFLG = IPARM/100;
          IPARM %= 100;
          DSFLG = IPARM/10;
          IPARM %= 10;
          TBFLG = IPARM;
          HILAB = PARMS[7]/10;
          LOLAB = (short)PARMS[7]%10;
          if ((DSFLG) && (!TBFLG)) DSFLG = 1;
          else if ((DSFLG) && (TBFLG)) DSFLG = -1;
          if (!IOFLG) IOFLG = XTICBASE; else IOFLG = -XTICBASE;

          if (TMAJOR[1])
               {
               for (X=TVT,XL=X*TSLOPE+TINTER;XL <= W2;
                    X+=TMAJOR[1],XL=X*TSLOPE+TINTER)
                    {
                    CHKBRK();
                    if (PARMS[5]) XP = exp(X*PARMS[5]); else XP = X;
                    if (DSFLG >= 0)
                         LINE(Tpnt(XL),W1,Tpnt(XL),W1-IOFLG);
                    if (DSFLG <= 0)
                         LINE(Tpnt(XL),W3,Tpnt(XL),W3+IOFLG);
                    if (IGRID)
                         LINE(Tpnt(XL),W1,Tpnt(XL),W3);
                    sprintf(BUFFER,TFORMAT,XP);
                    if (!ITV)
                         BLEN = strlen(BUFFER)*CWIDTH/2;
                    else
                         BLEN = CHEIGHT/2;
                    if (
                          (((abs(XL-W2)<BLEN) && (HILAB))
                       ||   (abs(XL-W2)>BLEN))
                       && (((abs(XL-W0)<BLEN) && (LOLAB))
                       ||   (abs(XL-W0)>BLEN))
                       )
                         {
                         PLTALPHA(BUFFER,
                                  (ITV ? Tpnt(XL) + BLEN : Tpnt(XL) - BLEN),
                                  YLOC,XROT);
                         }
                    for (I=1;I<=TMINOR;++I)
                         {
                         if (PARMS[5])
                              XL = PLOG(XP*(1+I*TDELTA),5)*TSLOPE+TINTER;
                         else XL = (X+I*TDELTA)*TSLOPE+TINTER;
                         if (XL > W2) break;
                         if (DSFLG >= 0)
                              LINE(Tpnt(XL),W1,Tpnt(XL),W1-IOFLG/2);
                         if (DSFLG <= 0)
                              LINE(Tpnt(XL),W3,Tpnt(XL),W3+IOFLG/2);
                         if (IGRID)
                              LINE(Tpnt(XL),W1,Tpnt(XL),W3);
                         }
                    }
               for (X=TVT,XL=X*TSLOPE+TINTER;XL >= W0;
                    X-=TMAJOR[1],XL=X*TSLOPE+TINTER)
                    {
                    CHKBRK();
                    if (PARMS[5]) XP = exp(X*PARMS[5]); else XP = X;
                    if (DSFLG >= 0)
                         LINE(Tpnt(XL),W1,Tpnt(XL),W1-IOFLG);
                    if (DSFLG <= 0)
                         LINE(Tpnt(XL),W3,Tpnt(XL),W3+IOFLG);
                    if (IGRID)
                         LINE(Tpnt(XL),W1,Tpnt(XL),W3);
                    sprintf(BUFFER,TFORMAT,XP);
                    if (!ITV)
                         BLEN = strlen(BUFFER)*CWIDTH/2;
                    else
                         BLEN = CHEIGHT/2;
                    if (
                          (((abs(XL-W2)<BLEN) && (HILAB))
                       ||   (abs(XL-W2)>BLEN))
                       && (((abs(XL-W0)<BLEN) && (LOLAB))
                       ||   (abs(XL-W0)>BLEN))
                       )
                         {
                         PLTALPHA(BUFFER,
                                  (ITV ? Tpnt(XL) + BLEN : Tpnt(XL) - BLEN),
                                  YLOC,XROT);
                         }
                    for (I=1;I<=TMINOR;++I)
                         {
                         if (PARMS[5])  /* Start at one down from X*/
                              {
                              V = (exp(PARMS[5]*(X-TMAJOR[1])))*(1+I*TDELTA);
                              XL = PLOG(V,5)*TSLOPE+TINTER;
                              }
                         else XL = (X-I*TDELTA)*TSLOPE+TINTER;
                         if (XL > W0) /* Decades come in back door */
                              {
                              if (DSFLG >= 0)
                                   LINE(Tpnt(XL),W1,Tpnt(XL),W1-IOFLG/2);
                              if (DSFLG <= 0)
                                   LINE(Tpnt(XL),W3,Tpnt(XL),W3+IOFLG/2);
                              if (IGRID)
                                   LINE(Tpnt(XL),W1,Tpnt(XL),W3);
                              }
                         }
                    }
               }
          }
     return;
     }

/************************************************************
*
* Y tic Marks
*
*/
void PTYTICS(XLOC,YLOC)
short XLOC,YLOC;
     {
     extern short W0, W1, W2, W3;
     double Y, YP, V, ROTATION;
     short YL, TBFLG, DSFLG, IOFLG, IPARM, I, BLEN;
     short IDAT, HILAB, LOLAB, IGRID;
     char C;

     if (PARMS[2] >= 0)
          {
          IPARM = PARMS[2];
          IGRID = IPARM/1000;
          IPARM %= 1000;
          IOFLG = IPARM/100;
          IPARM %= 100;
          DSFLG = IPARM/10;
          IPARM %= 10;
          TBFLG = IPARM;
          HILAB = PARMS[8]/10;
          LOLAB = (short)PARMS[8]%10;
          if ((DSFLG) && (!TBFLG)) DSFLG = 1;
          else if ((DSFLG) && (TBFLG)) DSFLG = -1;
          if (!IOFLG) IOFLG = YTICBASE; else IOFLG = -YTICBASE;

          if (YMAJOR[1])
               {
               for (Y=YVT,YL=Y*YSLOPE+YINTER;YL >= W3;
                    Y+=YMAJOR[1],YL=Y*YSLOPE+YINTER)
                    {
                    CHKBRK();
                    if (PARMS[6]) YP = exp(Y*PARMS[6]); else YP = Y;
                    if (DSFLG >= 0)
                         LINE(W0,Ypnt(YL),W0+IOFLG,Ypnt(YL));
                    if (DSFLG <= 0)
                         LINE(W2,Ypnt(YL),W2-IOFLG,Ypnt(YL));
                    if (IGRID)
                         LINE(W0,Ypnt(YL),W2,Ypnt(YL));
                    sprintf(BUFFER,YFORMAT,YP);
                    if (IYV)
                         BLEN = strlen(BUFFER)*CWIDTH/2;
                    else
                         BLEN = CHEIGHT/2;
                    if (
                          (((abs(YL-W3)<BLEN) && (HILAB))
                       ||   (abs(YL-W3)>BLEN))
                       && (((abs(YL-W1)<BLEN) && (LOLAB))
                       ||   (abs(YL-W1)>BLEN))
                       )
                         {
                         PLTALPHA(BUFFER,XLOC,Ypnt(YL) + BLEN,YROT);
                         }
                    for (I=1;I<=YMINOR;++I)
                         {
                         if (PARMS[6])
                              YL = PLOG(YP*(1+I*YDELTA),6)*YSLOPE+YINTER;
                         else YL = (Y+I*YDELTA)*YSLOPE+YINTER;
                         if (YL < W3) break;
                         if (DSFLG >= 0)
                              LINE(W0,Ypnt(YL),W0+IOFLG/2,Ypnt(YL));
                         if (DSFLG <= 0)
                              LINE(W2,Ypnt(YL),W2-IOFLG/2,Ypnt(YL));
                         if (IGRID)
                              LINE(W0,Ypnt(YL),W2,Ypnt(YL));
                         }
                    }
               for (Y=YVT,YL=Y*YSLOPE+YINTER;YL <= W1;
                    Y-=YMAJOR[1],YL=Y*YSLOPE+YINTER)
                    {
                    CHKBRK();
                    if (PARMS[6]) YP = exp(Y*PARMS[6]); else YP = Y;
                    if (DSFLG >= 0)
                         LINE(W0,Ypnt(YL),W0+IOFLG,Ypnt(YL));
                    if (DSFLG <= 0)
                         LINE(W2,Ypnt(YL),W2-IOFLG,Ypnt(YL));
                    if (IGRID)
                         LINE(W0,Ypnt(YL),W2,Ypnt(YL));
                    sprintf(BUFFER,YFORMAT,YP);
                    if (IYV)
                         BLEN = strlen(BUFFER)*CWIDTH/2;
                    else
                         BLEN = CHEIGHT/2;
                    if (
                          (((abs(YL-W3)<BLEN) && (HILAB))
                       ||   (abs(YL-W3)>BLEN))
                       && (((abs(YL-W1)<BLEN) && (LOLAB))
                       ||   (abs(YL-W1)>BLEN))
                       )
                         {
                         PLTALPHA(BUFFER,XLOC,Ypnt(YL) + BLEN,YROT);
                         }
                    for (I=1;I<=YMINOR;++I)
                         {
                         if (PARMS[6])
                              {
                              V = (exp(PARMS[6]*(Y-YMAJOR[1])))*(1+I*YDELTA);
                              YL = PLOG(V,6)*YSLOPE+YINTER;
                              }
                         else YL = (Y-I*YDELTA)*YSLOPE+YINTER;
                         if (YL < W1) /* Decades come in back door */
                              {
                              if (DSFLG >= 0)
                                   LINE(W0,Ypnt(YL),W0+IOFLG/2,Ypnt(YL));
                              if (DSFLG <= 0)
                                   LINE(W2,Ypnt(YL),W2-IOFLG/2,Ypnt(YL));
                              if (IGRID)
                                   LINE(W0,Ypnt(YL),W2,Ypnt(YL));
                              }
                         }
                    }
               }
          }
     return;
     }

/************************************************************
*
* Subroutine to Plot Alpha Numberics
* Characters are in FONT[]
* format is <X><Y><PEN>
* if <PEN> = '\0' then end of character definition.
* All X,Y Values are defined for the 1st quad only
*
*/
void PLTALPHA(LABEL,XLOC,YLOC,ANGLE)
char *LABEL;
short XLOC, YLOC, ANGLE;
   {
   short X0, Y0, X1, Y1;
   char *PNTR;
   char PEN;

   if (!strlen(LABEL)) return;
   while (*LABEL)
      {
      PNTR = FONT[*LABEL];
      ++LABEL;
      X0 =  *PNTR & 15;
      Y0 = -(*(++PNTR) & 15);
      PEN =  *(++PNTR);
      ROTATE(&X0,&Y0,ANGLE);

      while (PEN)
         {
         X1 =  *(++PNTR) & 15;
         Y1 = -(*(++PNTR) & 15);
         PEN = *(++PNTR);
         ROTATE(&X1,&Y1,ANGLE);
         switch (PEN)
            {
            case '1':
               LINE(XLOC+X0,YLOC+Y0,XLOC+X1,YLOC+Y1);
            case '0':
            case '\0':
               X0 = X1;
               Y0 = Y1;
            }
         }
      XLOC += X0;
      YLOC += Y0;
      }
   return;
   }

/************************************************************
*
* Rotate X, Y through ANGLE
*
*/
void ROTATE(X,Y,ANGLE)
short *X, *Y;
double ANGLE;
   {
   double XP, YP;

   if (ANGLE)
      {
      XP = *Y;
      YP = -(*X);
      *X = XP;
      *Y = YP;
      }
   return;
   }

/************************************************************
*
* Find the MAX, MIN of a File
*
*/
short GETRNG(YMAX,YMIN,TMAX,TMIN,INSTR,FHP,NotFirstCall)
double *YMAX, *YMIN, *TMIN, *TMAX;
FILE *INSTR;
struct FILEHDR *FHP;
int NotFirstCall;
   {
   short ERRFLAG=0;

   TCNT = 0.;
   while (Zread(INSTR,BUFFER1,FHP->type))
      {
      switch (FHP->type)
         {
         case R_Data:
            TIME = TCNT * FHP->m + FHP->b;
            ++TCNT;
            DATA = RDataPntr1->y;
            FLAG = RDataPntr1->f;
            break;
         case TR_Data:
            TIME = TRDataPntr1->t;
            DATA = TRDataPntr1->y;
            break;
         case X_Data:
            TIME = TCNT * FHP->m + FHP->b;
            ++TCNT;
            DATA = cabs(XDataPntr1->z);
            FLAG = XDataPntr1->f;
            break;
         case TX_Data:
            TIME = TXDataPntr1->t;
            DATA = cabs(TXDataPntr1->z);
            break;
         }

      if (((TIME >= TRANGE[0]) && (TIME <= TRANGE[1])) ||
           (TRANGE[0] >= TRANGE[1]))
         {
         if (!FLAG)
            {
            if (!NotFirstCall)
               {
               *YMIN = *YMAX = DATA;
               *TMAX = *TMIN = TIME;
               NotFirstCall = 1;
               }
            else
               {
               *YMAX = Max(DATA,*YMAX);
               *YMIN = Min(DATA,*YMIN);
               *TMAX = Max(TIME,*TMAX);
               *TMIN = Min(TIME,*TMIN);
               }
            }
         }
      }

   if (ferror(INSTR))
      {
      Zerror();
      ERRFLAG = 1;
      }

   return(ERRFLAG);
   }

/************************************************************
*
* Plot a Symbol
*
*/
void PLTSYM(FXLOC,FYLOC)
double FXLOC, FYLOC;
     {
     char C[2];
     short XLOC, YLOC;

     if ((FXLOC < (double)SCLIPXL) ||
         (FYLOC < (double)SCLIPYL) ||
         (FXLOC > (double)SCLIPXH) ||
         (FYLOC > (double)SCLIPYH)) return;

     XLOC = (short)FXLOC;
     YLOC = (short)FYLOC;
     C[0] = (char)fabs(PARMS[3]);
     C[1] = (char)0;
     if (C[0] != (char)255)
          PLTALPHA(C,XLOC-CWIDTH/2,YLOC+CHEIGHT/2,0);
     else
          LINE(XLOC,YLOC,XLOC,YLOC);
     return;
     }

/************************************************************
*
* Set Screen Colors
*
*/
void SETCOLOR()
   {
   CS1 = 0;
   CS2 = 0;
   if (COLOR)
      {
      GF1 = 2;
      GF2 = 3;
      GF3 = 1;
      COLOR = Min(COLOR,156);
      REGISTER.h.ah = (char)11;
      REGISTER.h.bh = (char)0; /* Set Back Ground */
      REGISTER.h.bl = (char)(COLOR/10);
      int86(0x10,®ISTER,®ISTER);
      COLOR = COLOR - 10*(COLOR/10);
      COLOR = Min(COLOR,6);
      COLOR = Max(COLOR,1);
      REGISTER.h.ah = (char)11;
      REGISTER.h.bh = (char)1; /* Set Palet */
      if (COLOR < 4)
         REGISTER.h.bl = (char)(0);
      else
         {
         REGISTER.h.bl = (char)(1);
         COLOR -= 3;
         }
      int86(0x10,®ISTER,®ISTER);
      if (COLOR > 1) CS1 = 1;
      if (COLOR > 2) CS2 = 255;
      }
   else
      {
      COLOR = 0;
      GF1 = 3;
      GF2 = 7;
      GF3 = 0;
      }
   return;
   }

/*********************************************************************
*
* User interaction with graphics screen
*
*/
short INTERACT(INSTR,IN2STR)
FILE *INSTR, *IN2STR;
   {
   short XLOC, YLOC;
   long XP, COUNT, CPOSL, DEL;
   char C;

   if (T2FLAG)   /* Can only scan single files at present */
      {
      BEEP();
      getch();
      return(0);
      }

   SLT1 = LT1 = 0;
   SLT2 = LT2 = 0;

   WINDOW[0] = 0;
   WINDOW[1] = HCLIPY;
   WINDOW[2] = HCLIPX;
   WINDOW[3] = 0;

   LFPS1 -= (long)Zsize(F1Header.type);
   LFPE1 -= (long)Zsize(F1Header.type);

   TCNT = TCNTS;

   clearerr(INSTR);
   if (fseek(INSTR,LFPS1,SEEK_SET)) return(1);

   LINEPUT();
   LINECLR();

   XP = 0L;

   if (!Zread(INSTR,BUFFER1,F1Header.type)) return(1);
   DEL = ftell(INSTR) - LFPS1;
   COUNT = Max((long)FACTOR*DEL,DEL);
   DEL = -DEL;
   switch (F1Header.type)    /* Data is Y Axis */
      {
      case R_Data:
         DATA = RDataPntr1->y;
         TIME = TCNT * F1Header.m + F1Header.b;
         FLAG = RDataPntr1->f;
         break;
      case TR_Data:
         DATA = TRDataPntr1->y;
         TIME = TRDataPntr1->t;
         break;
      case X_Data:
         DATA = cabs(XDataPntr1->z);
         TIME = TCNT * F1Header.m + F1Header.b;
         FLAG = XDataPntr1->f;
         break;
      case TX_Data:
         DATA = cabs(TXDataPntr1->z);
         TIME = TXDataPntr1->t;
         break;
      }

   if (PARMS[5])
      XLOC = TSLOPE*PLOG(TIME,5) + TINTER;
   else
      XLOC = TSLOPE*TIME + TINTER;

   if (PARMS[6])
      YLOC = YSLOPE*PLOG(DATA,6) + YINTER;
   else 
      YLOC = YSLOPE*DATA + YINTER;

   PLTALPHA("F9 set T1, F10 set T2",0,7,0);
   BEEP();
   fseek(INSTR,DEL,SEEK_CUR);
   CURSOR(Tpnt(XLOC),Ypnt(YLOC));
   while (1)
      {
      C = getch();
      if (!C) C = getch();
      CURSOR(Tpnt(XLOC),Ypnt(YLOC));

      CPOSL = ftell(INSTR);

      switch (C)
         {
         case (char)54: /* Move Right 10*/
            XP = 10L*COUNT;
            break;
         case (char)52: /* Move Left 10*/
            XP = -10L*COUNT;
            break;
         case (char)77: /* Move Right 1*/
            XP = COUNT;
            break;
         case (char)75: /* Move Left 1*/
            XP = -COUNT;
            break;
         case (char)27:
            LINEGET();
            return(0);
            break;
         case (char)32:
            XP = 0L;
            LINEGET();
            break;
         case (char)67: /* f9 */
            XP = 0L;
            T0 = TIME;
            LINECLR();
            sprintf(BUFFER,"TRANGE[1] Set to %G",T0);
            PLTALPHA(BUFFER,0,7,0);
            BEEP();
            break;
         case (char)68: /* f10 */
            XP = 0L;
            T1 = TIME;
            LINECLR();
            sprintf(BUFFER,"TRANGE[2] Set to %G",T1);
            PLTALPHA(BUFFER,0,7,0);
            BEEP();
            break;
         default: /* Clear Top Line and Print Status */
            XP = 0L;
            LINECLR();
            sprintf(BUFFER,"T = %G, Y = %G, N = %G",TIME,DATA,TCNT);
            PLTALPHA(BUFFER,0,7,0);
         }

      CPOSL += XP;
      if (CPOSL < LFPS1)
         {
         TCNT = TCNTE;
         if (fseek(INSTR,LFPE1,SEEK_SET)) return(1);
         }
      else if (CPOSL > LFPE1)
         {
         TCNT = TCNTS;
         if (fseek(INSTR,LFPS1,SEEK_SET)) return(1);
         }
      else
         {
         TCNT += (double)(XP/COUNT);
         if (fseek(INSTR,CPOSL,SEEK_SET)) return(1);
         }          

      clearerr(INSTR);
      if (!Zread(INSTR,BUFFER1,F1Header.type)) return(1);
      switch (F1Header.type)
         {
         case R_Data:
            DATA = RDataPntr1->y;
            TIME = TCNT* F1Header.m + F1Header.b;
            FLAG = RDataPntr1->f;
            break;
         case TR_Data:
            DATA = TRDataPntr1->y;
            TIME = TRDataPntr1->t;
            break;
         case X_Data:
            DATA = cabs(XDataPntr1->z);
            TIME = TCNT* F1Header.m + F1Header.b;
            FLAG = XDataPntr1->f;
            break;
         case TX_Data:
            DATA = cabs(TXDataPntr1->z);
            TIME = TXDataPntr1->t;
            break;
         }

      if (PARMS[5])
         XLOC = TSLOPE*PLOG(TIME,5) + TINTER;
      else
         XLOC = TSLOPE*TIME + TINTER;

      if (PARMS[6])
         YLOC = YSLOPE*PLOG(DATA,6) + YINTER;
      else 
         YLOC = YSLOPE*DATA + YINTER;

      fseek(INSTR,DEL,SEEK_CUR);
      CURSOR(Tpnt(XLOC),Ypnt(YLOC));
      }
   }

/***************************************************************
**
** Function to draw 1 of 2  cursors
*/
void CURSOR(XLOC,YLOC)
short XLOC, YLOC;
   {
   short X,Y,XP1,XP2,YP1,YP2;
   char P;

   YLOC = Min(SCLIPYH,Max(SCLIPYL,YLOC));
   XP1 = Max(0,XLOC - 8);
   XP2 = Min(HCLIPX,XLOC+8);
   YP1 = Max(0,YLOC - 4);
   YP2 = Min(HCLIPY,YLOC+4);
   for (X=XP1;X<=XP2;++X) XPSET(X,YLOC);
   XPSET(XLOC,YLOC);
   for (Y=YP1;Y<=YP2;++Y) XPSET(XLOC,Y);
   return;
   }

/***************************************************************
**
** Clear top Graphics Line
*/
void LINECLR()
   {
   short I;

   FP_OFF(SCREEN) = 0;
   switch (HARDWARE.scrn)
      {
      case HERC_scrn:
         for (I=0;I<180;++I,++SCREEN)
            {
            *SCREEN = 0;;
            *(SCREEN+0x2000) = 0;
            *(SCREEN+0x4000) = 0;
            *(SCREEN+0x6000) = 0;
            }
         break;
      case CGA_scrn:
      case DUAL_scrn:
         for (I=0;I<320;++I,++SCREEN)
            {
            *SCREEN = 0;
            *(SCREEN+0x2000) = 0;
            }
         break;
      }

   return;
   }

/***************************************************************
**
** Save Top Graphics Line
*/
void LINEPUT()
   {
   short I;

   FP_OFF(SCREEN) = 0;
   switch (HARDWARE.scrn)
      {
      case HERC_scrn:
         for (I=0;I<180;++I,++SCREEN)
            {
            SBUFF[I] = *SCREEN;
            SBUFF[I+180] = *(SCREEN+0x2000);
            SBUFF[I+360] = *(SCREEN+0x4000);
            SBUFF[I+540] = *(SCREEN+0x6000);
            }
         break;
      case CGA_scrn:
      case DUAL_scrn:
         for (I=0;I<320;++I,++SCREEN)
            {
            SBUFF[I] = *SCREEN;
            SBUFF[I+320] = *(SCREEN+0x2000);
            }
         break;
      }
   return;
   }

/***************************************************************
**
** Get Top Graphics Line
*/
void LINEGET()
   {
   short I;

   FP_OFF(SCREEN) = 0;
   switch (HARDWARE.scrn)
      {
      case HERC_scrn:
         for (I=0;I<180;++I,++SCREEN)
            {
            *SCREEN= SBUFF[I];
            *(SCREEN+0x2000) = SBUFF[I+180];
            *(SCREEN+0x4000) = SBUFF[I+360];
            *(SCREEN+0x6000) = SBUFF[I+540] ;
            }
         break;
      case CGA_scrn:
      case DUAL_scrn:
         for (I=0;I<320;++I,++SCREEN)
            {
            *SCREEN = SBUFF[I];
            *(SCREEN+0x2000) = SBUFF[I+320];
            }
         break;
      }
   return;
   }

/***************************************************************
**
** Take LOG base PRAMS[5] or PARMS[6]
*/
double PLOG(V,B)
double V;
short B;
   {
   V = log(V)/PARMS[B];
   return(V);
   }

/***************************************************************
**
** Vector Clipping Routine
*/
void VECTOR(X1,Y1,X2,Y2,F)
double X1, X2, Y1, Y2;
short F;
   {
   short VFLAG=0, HFLAG=0, FL=0;
   double M, B, ZXL, ZXH, ZYL, ZYH;
   static double LASTX, LASTY;

   if (F)
      {
      X1=LASTX;
      Y1=LASTY;
      }

   LASTX = X2;
   LASTY = Y2;

   if ((X2 != X1) && (Y2 != Y1))
      {
      M = (Y2-Y1)/(X2-X1);
      B = Y1 - M*X1;
      ZXL=M*(double)SCLIPXL+B;
      ZXH=M*(double)SCLIPXH+B;
      ZYL=((double)SCLIPYL-B)/M;
      ZYH=((double)SCLIPYH-B)/M;
      }

   if (X2 == X1) VFLAG = 1;

   if (Y2 == Y1) HFLAG = 1;

   if (X1 < (double)SCLIPXL)
      {
      if (VFLAG) return;
      X1 = (double)SCLIPXL;
      if (!HFLAG) Y1 = ZXL;
      FL=1;
      }
   else if (X1 > (double)SCLIPXH)
      {
      if (VFLAG) return;
      X1 = (double)SCLIPXH;
      if (!HFLAG) Y1 = ZXH;
      FL=1;
      }
   if (X2 < (double)SCLIPXL)
      {
      X2 = (double)SCLIPXL;
      if (!HFLAG) Y2 = ZXL;
      FL=1;
      }
   else if (X2 > (double)SCLIPXH)
      {
      X2 = (double)SCLIPXH;
      if (!HFLAG) Y2 = ZXH;
      FL=1;
      }

   if (Y1 < (double)SCLIPYL)
      {
      if (HFLAG) return;
      Y1 = (double)SCLIPYL;
      if (!VFLAG) X1 = ZYL;
      FL=1;
      }
   else if (Y1 > (double)SCLIPYH)
      {
      if (HFLAG) return;
      Y1 = (double)SCLIPYH;
      if (!VFLAG) X1 = ZYH;
      FL=1;
      }
   if (Y2 < (double)SCLIPYL)
      {
      Y2 = (double)SCLIPYL;
      if (!VFLAG) X2 = ZYL;
      FL=1;
      }
   else if (Y2 > (double)SCLIPYH)
      {
      Y2 = (double)SCLIPYH;
      if (!VFLAG) X2 = ZYH;
      FL=1;
      }

   if (((X1<(double)SCLIPXL) || (X1>(double)SCLIPXH)  ||
        (X2<(double)SCLIPXL) || (X2>(double)SCLIPXH)  ||
        (Y1<(double)SCLIPYL) || (Y1>(double)SCLIPYH)  ||
        (Y2<(double)SCLIPYL) || (Y2>(double)SCLIPYH)) ||
       ((X1 == X2) && (Y1 == Y2) && (FL == 1))) return;

   LINE((short)X1,(short)Y1,(short)X2,(short)Y2);

   return;
   }

/********************************************
*
* Line drawing Primitive
*/
void LINE(X1,Y1,X2,Y2)
short X1,Y1,X2,Y2;
   {
   short DELX, DELY, DXI, DYI, SXI, SYI, SHRTDIS, LNGDIS;
   short SC, DC, TF;

   DELY = Y2-Y1;
   if (DELY < 0)
      {
      DELY = -DELY;
      DYI = -1;
      }
   else DYI = 1;

   DELX = X2-X1;
   if (DELX < 0)
      {
      DELX = -DELX;
      DXI = -1;
      }
   else DXI = 1;

   if (DELY > DELX)
      {
      SXI = 0;
      SYI = DYI;
      SHRTDIS = DELX;
      LNGDIS = DELY;
      }
   else
      {
      SXI = DXI;
      SYI = 0;
      SHRTDIS = DELY;
      LNGDIS = DELX;
      }

   SC = SHRTDIS<<1;
   TF = SC - LNGDIS;
   DC = TF - LNGDIS;
   ++LNGDIS;

   do {
      PSET(X1,Y1);
      if (TF<0)
         {
         X1 += SXI;
         Y1 += SYI;
         TF += SC;
         }
      else
         {
         X1 += DXI;
         Y1 += DYI;
         TF += DC;
         }
      }
   while (--LNGDIS);

   return;
   }

/********************************************
*
* Pixel Setting Routine
*
*/
void PSET(X,Y)
short X,Y;
   {
   char P;
   static short LASTX=-1, LASTY=-1;

   if ((X==LASTX) && (Y==LASTY)) return;

   if ((!NOCLIP &&
       ((X<SCLIPXL) || (Y<SCLIPYL) || (X>SCLIPXH) || (Y>SCLIPYH))) ||
        ((X<0) || (Y<0) || (X>HCLIPX) || (Y>HCLIPY))) return;

   LASTX = X;
   LASTY = Y;

   if (!SLT1)              /* Line Type */
      {
      if (!SLT2)
         {
         SLT1 = LT1;
         SLT2 = LT2;
         }
      else
         {
         --SLT2;
         return;
         }
      }
   --SLT1;
   switch (HARDWARE.scrn)
      {
      case HERC_scrn:
         FP_OFF(SCREEN) = HERCSpos(X,Y);
         *SCREEN |= HERCPel(X);
         break;
      case CGA_scrn:
      case DUAL_scrn:
          FP_OFF(SCREEN) = CGASpos(X,Y);
          P = CGAPel(X);
          *SCREEN |= ((P<<CS1) + (P & CS2));
         break;
      }

     return;
     }

/********************************************
*
* Pixel Setting Routine XOR
*
*/
void XPSET(X,Y)
short X,Y;
   {
   char P;

   if ((X<0) || (Y<0) || (X>HCLIPX) || (Y>HCLIPY)) return;

   switch (HARDWARE.scrn)
      {
      case HERC_scrn:
         FP_OFF(SCREEN) = HERCSpos(X,Y);
         *SCREEN ^= HERCPel(X);
         break;
      case CGA_scrn:
      case DUAL_scrn:
         FP_OFF(SCREEN) = CGASpos(X,Y);
         P = CGAPel(X);
         *SCREEN ^= ((P<<CS1) + (P & CS2));
         break;
      }

   return;
   }

/***************************************************************
**
** Check the ^C Interrupt Flag
*/
void CHKBRK()
   {
   if (kbhit()) getch();
   return;
   }

/*
**
** Process ^C Interrupt
*/
short BREAKREQ()
   {
   fcloseall();
   unlink(TMPFILE);
   Zexit(3);
   }

/*
** Trap Floating Point Error
*/
short FPEERROR()
   {
   fcloseall();
   unlink(TMPFILE);
   Zexit(1);
   }