/*******************************************************************
*
*  Task PNTRPLOT
*
* CODE 0   -> EXIT AFTER PLOT
* CODE 1,2 -> DUMP PLOT
* CODE 3   -> DUMP WITHOUT FORM FEEDS
*
* 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)
*
* 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)
*                                 
* FACTOR: Data skip interval (2 = every other point, ect.)
*/
#include <bios.h>
#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 Tpnt(x) (IITA ? (W0 + W2 - (x)) : (x))    /* Reverse T Axis */
#define Ypnt(y) (IIYA ? (W1 + W3 - (y)) : (y))    /* Reverse Y Axis */

void PPUT(unsigned char);
void PIXILSET(short,short);
void MAININIT(void);
void PLOT1(void);
void PLOT2(void);
short IMLOAD(FILE *,char *,char);
void FRAMEIT(void);
void PUTLAB(void);
void PUTTICS(void);
void PLTALPHA(char *,short,short,short);
void PLTSYM(double,double);
void ROTATE(short *,short *,short);
short GETRNG(double *,double *,double *,double *,FILE *,struct FILEHDR *,int);
void DUMPIT(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);
void CHKBRK(void);
short FPEERROR(void);

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

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;
double TIME, DATA, TOTAL=0.;
short FLAG=0;
short FirstPointFlag;

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

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

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

   switch (HARDWARE.pntr)
      {
      case EPSN_pntr:
         Zencode(3,"PNTRPLOT: Dot Matrix Printer Selected.\n");
         break;
      case HPLJ_pntr:
         Zencode(3,"PNTRPLOT: HP Laser or Ink Jet Printer Selected.\n");
         break;
      default:
         Zencode(10,"PNTRPLOT: No Graphics Printer Available.\n");
         Zexit(1);
      }

   if (!strlen(DEVICE) || !strcmp(DEVICE,"LPT1") || !strcmp(DEVICE,"PRN"))
      PPORT = 0;
   else if (!strcmp(DEVICE,"LPT2"))
      PPORT = 1;
   else if (!strcmp(DEVICE,"LPT3"))
      PPORT = 2;
   else
      {
      Zencode(10,"PNTRPLOT: Invalid DEVICE Specification '%s'\n",DEVICE);
      Zexit(1);
      }

   for (UI=0;UI<55500;++UI) VIRTSCN[UI] = 0;

   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,"PNTRPLOT: 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,"PNTRPLOT: 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,"PNTRPLOT: 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,"PNTRPLOT: Invalid Output File Name '%s'\n",OUTFILE);
         Zexit(1);
         }

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

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

      Zencode(2,"PNTRPLOT: 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,"PNTRPLOT: 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 EPSN_Image:
         case HPLJ_Image:
            if (IMLOAD(IN2STR,IN2FILE,F2Header.type))
               {
               ERRFLAG = 1;
               goto EXIT;
               }
            break;
         default:
            Zencode(10,"PNTRPLOT: Invalid File Type.\n");
            ERRFLAG = 1;
            goto EXIT;
         }
      }

   Zencode(2,"PNTRPLOT: Building Raster Image\n");

   if (TRANGE[0] == TRANGE[1])
      {
      ++TRANGE[1];
      --TRANGE[0];
      }
   if (YRANGE[0] == YRANGE[1])
      {
      --YRANGE[0];
      ++YRANGE[1];
      }

   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.;
      _splitpath(pChar,Drive,Dir,Fname,Ext);
      strcpy(INNAME,Fname);
      strcpy(INCLASS,Ext);
      ZBuildFileName(M_inname,INFILE);
      Zencode(2,"PNTRPLOT: 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,"PNTRPLOT: Invalid File Type.\n");
            Zexit(1);
         }

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

     if (CODE) DUMPIT();
/*
** Plot is Now Complete.
** If OUTSTR then save the image
*/
   if (OUTSTR)
      {
      switch (HARDWARE.pntr)
         {
         case EPSN_pntr:
            FileHeader.type = EPSN_Image;
            break;
         case HPLJ_pntr:
            FileHeader.type = HPLJ_Image;
            break;
         }
      if (Zputhead(OUTSTR,&FileHeader))
         {
         ERRFLAG = 1;
         goto EXIT;
         }
      switch (HARDWARE.pntr)
         {
         case EPSN_pntr:
            for (UI=0;UI<45600;++UI)
               {
               C = VIRTSCN[UI];
               fputc(C,OUTSTR);
               }
            break;
         case HPLJ_pntr:
            for (UI=0;UI<55500;++UI) 
               {
               C = VIRTSCN[UI];
               fputc(C,OUTSTR);
               }

            break;
         }
      }
   Zencode(3,"PNTRPLOT: %G Data Points Processed\n",TOTAL);

EXIT:
   if (IN2STR) Zclose(IN2STR);
   if (OUTSTR)
      {
      Zclose(OUTSTR);
      ERRFLAG = Znameout(OUTFILE,TMPFILE,ERRFLAG);
      }
   Zexit(ERRFLAG);
   }

/************************************************************
*
* INITIALIZATION
*     This routine sets up the default values from
*     unspecified inputs.
*
*/
void MAININIT()
   {
   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.pntr)
      {
      case EPSN_pntr:
         SCLIPXH=HCLIPX = 759;
         SCLIPYH=HCLIPY = 479;
         break;
      case HPLJ_pntr:
         SCLIPXH=HCLIPX = 749;
         SCLIPYH=HCLIPY = 591;
         break;
      }

   WINDOW[0] = Max(WINDOW[0],0);
   WINDOW[2] = Max(WINDOW[2],0);
   WINDOW[1] = Min(WINDOW[1],SCLIPXH);
   WINDOW[3] = Min(WINDOW[3],SCLIPYH);

   if (WINDOW[0] >= WINDOW[2])
      {
      WINDOW[0] = 0;
      WINDOW[2] = SCLIPXH;
      }
   if (WINDOW[1] >= WINDOW[3])
      {
      WINDOW[1] = 0;
      WINDOW[3] = SCLIPYH;
      }

   if (!strlen(TFORMAT)) strcpy(TFORMAT,"%G");  /* Default output formats */
   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()
   {
   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;
      }
   ++TCNT;

   CHKBRK();            /* Test for ^C */
   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()
   {
   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 UI;

   switch (TYPE)
      {
      case HPLJ_Image: /* TISAN LASER Graphics File */
         for (UI=0;UI<55500;++UI) VIRTSCN[UI] = fgetc(IN2STR);
         break;
      case EPSN_Image: /* TISAN Low Resolution EPSON Graphics File */
         for (UI=0;UI<45600;++UI) VIRTSCN[UI] = fgetc(IN2STR);
         break;
      }
   if (ferror(IN2STR)) ERRFLAG = 1;
   return(ERRFLAG);
   }

/************************************************************
*
* 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 = PARMS[1];
      IGRID = IPARM/1000;
      IPARM %= 1000;
      IOFLG = IPARM/100;
      IPARM %= 100;
      DSFLG = IPARM/10;
      IPARM %= 10;
      TBFLGT = IPARM;
      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 = (short)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;
   {
   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 = (short)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 of 0 or 90
*
*/
void ROTATE(X,Y,ANGLE)
short *X, *Y, ANGLE;
   {
   short 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;
   }

/***************************************************************
**
** 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 {
      PIXILSET(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 PIXILSET(X,Y)
short X,Y;
   {
   unsigned short XX, YY, OFFST;
   unsigned char P;
   static short LASTX=-1, LASTY=-1;

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

   if ((X<SCLIPXL) || (Y<SCLIPYL) || (X>SCLIPXH) || (Y>SCLIPYH)) return;

   LASTX = X;
   LASTY = Y;

   if (!SLT1)              /* Line Type */
      {
      if (!SLT2)
         {
         SLT1 = LT1;
         SLT2 = LT2;
         }
      else
         {
         --SLT2;
         return;
         }
      }
   --SLT1;

   switch (HARDWARE.pntr)
      {
      case EPSN_pntr: /* EPSON */
         XX = X;
         YY = Y;
         OFFST = (XX>>3) + (YY<<6) + (YY<<5) + (YY<<2);
         P = 1<<(7 - XX + (XX & 0xFFF8));
         break;
      case HPLJ_pntr: /* LASER */
         XX = HCLIPX - X;
         YY = Y;
         OFFST = (YY>>3) + (XX<<6) + (XX<<3) + (XX<<1);
         P = 1<<(7 - YY + (YY & 0xFFF8));
         break;
      }

   VIRTSCN[OFFST] |= P;

   return;
   }

/************************************************************
*
* DUMP the virtual screen to the printer (LPT1:)
*
*/
void DUMPIT()
   {
   unsigned short K, I, J, UI=0;
   unsigned char C;

   Zencode(2,"PNTRPLOT: Printing Raster Image\n");

   switch (HARDWARE.pntr)
      {
      case EPSN_pntr: /* EPSON */
         if (CODE == 1) PPUT(12);
         PPUT(27);
         PPUT('3');PPUT(24);
         for (I=0;I<95;++I)
            {
            PPUT(27);
            PPUT('K');
            PPUT(224);
            PPUT(1);
            for (J=479;J>0;--J)
               {
               K = I + J*100;
               C = VIRTSCN[K];
               PPUT(C);
               }
            C = VIRTSCN[I];
            PPUT(C);
            }
         PPUT(12);
         PPUT(27);
         PPUT('3');PPUT(36);
         PPUT(27);
         PPUT('@');
         break;
      case HPLJ_pntr: /* LASER */
         PPUT(27);      /* Reset Printer         */
         PPUT('E');
         PPUT(27);  /* Set 75 DPI            */
         PPUT('*');
         PPUT('t');
         PPUT('7');
         PPUT('5');
         PPUT('R');
         PPUT(27);   /* Start Raster Graphics */
         PPUT('*');
         PPUT('r');
         PPUT('0');
         PPUT('A');
         for (I=0;I<750;++I)
            {
            PPUT(27);
            PPUT('*');
            PPUT('b');
            PPUT('7');
            PPUT('4');
            PPUT('W');
            for (J=0;J<74;++J)
               {
               C = VIRTSCN[UI];
               PPUT(C);
               ++UI;
               }
            }
         PPUT(27);    /* END GRAPHICS */
         PPUT('*');
         PPUT('r');
         PPUT('B');
         PPUT(27);  /* RESET */
         PPUT('E');
         break;
      }
   return;
   }

/******************************************************
*
* Put character to selected printer
*
*/
void PPUT(C)
unsigned char C;
   {
   REGISTER.x.dx = PPORT;
   REGISTER.h.ah = (char)2;
   int86(0x17,®ISTER,®ISTER);
   while ((REGISTER.h.ah ^ (char)16) & (char)56)
      {
      BEEP();
      Zencode(255,"PNTRPLOT: Printer Not Ready.\n");
      Zencode(255,"PNTRPLOT: Reset and Press Any Key...\n");
      getch();
      }
   REGISTER.x.dx = PPORT;
   REGISTER.x.ax = C;
   int86(0x17,®ISTER,®ISTER);
   if (REGISTER.h.ah & 1)
      {
      Zencode(8,"PNTRPLOT: Printer Not Responding\n");
      Zexit(1);
      }
   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);
   }