/*
** All BOOL functions return FALSE if OK or TRUE on an error
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <io.h>
#include <time.h>
#include <ctype.h>
#include <errno.h>
#include <dos.h>
#include <math.h>
#include <stdarg.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <malloc.h>

/*
** These I/O routines are called in the same way as their
** WINDOWS counterparts.  The initial definitions are needed
** to maintain WINDOWS portability by the calling functions.
**
** I/O errors can be detected by examining the iEoF structure
** element.  A Zero value indicates no problems, 1 means end of file
** and -1 means that an error has been detected.
*/
#define WORD      unsigned int
#define BYTE      unsigned char
#define HANDLE    int
#define BOOL      int
#define FALSE     0
#define TRUE      1
#define LPSTR     char far *

#define OF_READWRITE O_RDWR
#define OF_WRITE     O_WRONLY
#define OF_READ      O_RDONLY
#define OF_CREATE    O_CREAT | O_TRUNC

#define OPENERROR (HANDLE)-1
#define IOERROR   (WORD)-1

#define Min(a,b) ((a) < (b) ? (a) : (b))
#define Max(a,b) ((a) > (b) ? (a) : (b))

#define Maxbuff 2048

#define M_inname  (char)0
#define M_in2name (char)1
#define M_outname (char)2
#define M_tmpname (char)3

#define O_readb   (char)0
#define O_writeb  (char)1
#define O_appendb (char)2
#define O_readt   (char)3
#define O_writet  (char)4
#define O_appendt (char)5

#define R_Data  (char)0
#define TR_Data (char)1
#define X_Data  (char)2
#define TX_Data (char)3

#define MONO_scn (char)0
#define CGA_scn  (char)1
#define HERC_scn (char)2
#define EGA_scn  (char)3
#define PGA_scn  (char)4

#define NO_pntr   (char)0
#define EPSN_pntr (char)1
#define HPLJ_pntr (char)2

/*
** Define Structures
*/
struct RData {double y;
              short  f;};

struct TRData {double t;
               double y;};

struct XData {struct complex z;
              short f;}  XData;

struct TXData {double t;
               struct complex z;};

struct FILEHDR {char type;
                double m;
                double b;};

struct DEVICES {char scrn;
                char pntr;
                char pltr;};

struct CATSTRUCT {int N;
                  char *pList;};

struct OFSTRUCT {BYTE    szPathName[_MAX_PATH];};

struct FILESTRUCT {char *pCurrent, *pStart;
                   HANDLE hFile;
                   struct OFSTRUCT OFstruct;
                   long lBufferFilePos;
                   WORD wMemorySize, wBytesInBuffer;
                   BOOL bChanged, bWriteOnly, bReadOnly;
                   int iEoF;
                   };

/*
** Define Functions
*/
BOOL zFileOpen(struct FILESTRUCT *, char *, int, WORD);
BOOL zFileClose(struct FILESTRUCT *, BOOL);
WORD zFileGetChar(struct FILESTRUCT *);
long zFileRead(struct FILESTRUCT *, LPSTR, long);
BOOL zFilePutChar(struct FILESTRUCT *, BYTE);
long zFileWrite(struct FILESTRUCT *, LPSTR, long);
long zFileTell(struct FILESTRUCT *);
long zFileSeek(struct FILESTRUCT *, long, int);
WORD zFileGetLine(struct FILESTRUCT *, LPSTR, WORD, BYTE);
long zFileSize(struct FILESTRUCT *);

struct FILEHDR *zGetHeader(struct FILESTRUCT *, struct FILEHDR *);
BOOL   zPutHeader(struct FILESTRUCT *, struct FILEHDR *);
BOOL   zGetAdverbs(char *);
BOOL   zPutAdverbs(char *);
BOOL   zTaskInit(char *, char *);
short  zMessage(short,char *,...);
short  zTypeSize(char);
BOOL   zIndexedRead(struct FILESTRUCT *, long, char *, char);
BOOL   zIndexedWrite(struct FILESTRUCT *, long, char *, char);

struct complex cmplx(double, double);  /* R + iI */
struct complex c_add(struct complex,struct complex);  /* z1 + z2    */
struct complex c_sub(struct complex,struct complex);  /* z1 - z2    */
struct complex c_mul(struct complex,struct complex);  /* z1 * z2    */
struct complex c_div(struct complex,struct complex);  /* z1 / z2    */
struct complex c_sqrt(struct complex);                /* sqrt(z)    */
struct complex c_ln(struct complex);                  /* ln(z)      */
struct complex c_exp(struct complex);                 /* exp(z)     */
struct complex c_sin(struct complex);                 /* sin(z)     */
struct complex c_cos(struct complex);                 /* cos(z)     */
struct complex c_tan(struct complex);                 /* tan(z)     */
struct complex c_sec(struct complex);                 /* sec(z)     */
struct complex c_csc(struct complex);                 /* csc(z)     */
struct complex c_cot(struct complex);                 /* cot(z)     */
struct complex c_asin(struct complex);                /* asin(z)    */
struct complex c_acos(struct complex);                /* acos(z)    */
struct complex c_atan(struct complex);                /* atan(z)    */
struct complex c_acot(struct complex);                /* acot(z)    */
struct complex c_acsc(struct complex);                /* acsc(z)    */
struct complex c_asec(struct complex);                /* asec(z)    */
struct complex c_sinh(struct complex);                /* sinh(z)    */
struct complex c_cosh(struct complex);                /* cosh(z)    */
struct complex c_tanh(struct complex);                /* tanh(z)    */
struct complex c_sech(struct complex);                /* sech(z)    */
struct complex c_csch(struct complex);                /* csch(z)    */
struct complex c_coth(struct complex);                /* coth(z)    */
struct complex c_asinh(struct complex);               /* asinh(z)   */
struct complex c_acosh(struct complex);               /* acosh(z)   */
struct complex c_atanh(struct complex);               /* atanh(z)   */
struct complex c_acsch(struct complex);               /* acsch(z)   */
struct complex c_asech(struct complex);               /* asech(z)   */
struct complex c_acoth(struct complex);               /* acoth(z)   */
struct complex c_log10(struct complex);               /* log10(z)   */
struct complex c_pow(struct complex,struct complex);  /* pow(z1,z2) */

double asinh(double);
double acosh(double);
double atanh(double);

struct FILEHDR *Zgethead(FILE *,struct FILEHDR *);
short      Zputhead(FILE *,struct FILEHDR *);
FILE      *Zopen(char *,short);
short      Zclose(FILE *);
char      *ZBuildFileName(short,char *);
short      Zgetdat(FILE *,char *,char);
short      Zgetadv(char *);
short      Zputadv(char *);
short      Ztskinit(char *,char *);
short      Zputdat(short,FILE *,char *,char);
short      Znameout(char *,char *,short);
void       Zerror(void);
short      Zencode(short,char *,...);
char      *Zread(FILE *,char *,char);
short      Zwrite(FILE *,char *,char);
short      Zsize(char);
void       Zexit(int);

struct CATSTRUCT *ZCatFiles(char *);

void BEEP(void);

extern double TRANGE[2], YRANGE[2], ZRANGE[2];
extern double TMAJOR[2], YMAJOR[2], ZMAJOR[2];
extern double PARMS[10], POINT[2], ZFACTOR[2];
extern short WINDOW[4];
extern char TASKNAME[9];
extern char INNAME[_MAX_FNAME],  INCLASS[_MAX_EXT-1], INPATH[_MAX_DRIVE+_MAX_DIR-1];
extern char IN2NAME[_MAX_FNAME], IN2CLASS[_MAX_EXT-1], IN2PATH[_MAX_DRIVE+_MAX_DIR-1];
extern char IN3NAME[_MAX_FNAME], IN3CLASS[_MAX_EXT-1], IN3PATH[_MAX_DRIVE+_MAX_DIR-1];
extern char OUTNAME[_MAX_FNAME], OUTCLASS[_MAX_EXT-1], OUTPATH[_MAX_DRIVE+_MAX_DIR-1];
extern char TFORMAT[24], YFORMAT[24], ZFORMAT[24];
extern char PARITY[6], DEVICE[5];
extern char TLABEL[133], YLABEL[133], ZLABEL[133], TITLE[133];
extern double FACTOR;
extern short CODE, BAUD, STOPBITS, DATABITS, ITYPE;
extern short TMINOR, YMINOR, ZMINOR, FRAME, BORDER, QUIET, LogFlag;
extern long COLOR;
extern FILE *LogStream;

extern struct DEVICES HARDWARE;

extern BOOL INTERRUPT;

/******************************************
** Arrays for the Full Path for the TISAN
** Program on startup so wew know where to
** find the INPUTS and RUN files.
*/
extern char TisanDrive[];
extern char TisanDir[];

/*
** Character strings used throughout the program
*/
extern char *NullString;
extern char *Space;
extern char *CrLf;

/*********************************************************************
*
* Open a file specified by the pointer to FNAME of the
* type specified by TYPE.  TYPE must be one of the following
* 
* O_readb   :  Open for binary read
* O_writeb  :  Open for binary write
* O_appendb :  Open for binary append
* O_readt   :  Open for text read
* O_writet  :  Open for text write
* O_appendt :  Open for text append
*
* If the file is successfully opened, then a file pointer is returned
* otherwise an error message is printed and NULL is returned.
* If a file to be read cannot be found, the user is promped for
* an action.  This message allows floppy disk systems to change
* data diskettes if necessary.
*/
FILE *Zopen(FNAME,TYPE)
char *FNAME;
short TYPE;
   {
   char STAT[3], C;
   FILE *PNTR;

   switch (TYPE)
      {
      case O_readb: /* Open for binary read */
         strcpy(STAT,"r+b");
         break;
      case O_writeb: /* Open for binary write */
        strcpy(STAT,"w+b");
        break;
      case O_appendb: /* Open for binary append */
         strcpy(STAT,"a+b");
         break;
      case O_readt: /* Open for text read */
         strcpy(STAT,"r+t");
         break;
      case O_writet: /* Open for text write */
         strcpy(STAT,"w+t");
         break;
      case O_appendt: /* Open for text append */
         strcpy(STAT,"a+t");
      }

   do {
      errno = 0;
      PNTR = fopen(FNAME,STAT);
      if (errno == ENOENT)
         {
         if ((TYPE == O_writeb) || (TYPE == O_writet)) break;
         Zencode(255,"%-8s: File Not Found.\n", TASKNAME);
         Zencode(255,"%-8s: Replace Diskette and Press Any Key.\n",
                 TASKNAME);
         BEEP();
         while (kbhit()) getch();   /* Clear Buffer */
         getch();
         }
      }
   while (errno == ENOENT);
   if (!PNTR)
      {
      Zerror();
      BEEP();
      }
   return(PNTR);
   }

/*********************************************************************
*
* Close a file specified by the file pointer PNTR.
* Return 0 if no errors.
* If an error occurs it is printed and 1 is returned.
*
*/
short Zclose(PNTR)
FILE *PNTR;
     {
     short ERRFLAG=0;

     if (fclose(PNTR))   
          {
          Zencode(10,"%-8s: Error Closing File\n",TASKNAME);
          ERRFLAG=1;
          }
     return(ERRFLAG);
     }

/*********************************************************************
*
* Get Adverbs from the file name pointed to by NAMEPNTR.
* 0 is returned if no errors.
* 1 is returned otherwise and an error message is printed.
* Input file names are of the form INPUTS\filename.INP
*
*/
short Zgetadv(NAMEPNTR)
char *NAMEPNTR;
   {
   char dir[_MAX_DIR];
   char path[_MAX_PATH];
     FILE *PNTR;
     short ERRFLAG=0;

     strcpy(dir,TisanDir);
     strcat(dir,"INPUTS\\");
     _makepath(path,TisanDrive,dir,NAMEPNTR,".INP");

     PNTR = fopen(path,"rb");
     if (PNTR)
          {
/* Double Precision Arrays */
          fread(TRANGE,sizeof(double),2,PNTR);
          fread(YRANGE,sizeof(double),2,PNTR);
          fread(ZRANGE,sizeof(double),2,PNTR);
          fread(TMAJOR,sizeof(double),2,PNTR);
          fread(YMAJOR,sizeof(double),2,PNTR);
          fread(ZMAJOR,sizeof(double),2,PNTR);
          fread(PARMS,sizeof(double),10,PNTR);
          fread(POINT,sizeof(double),2,PNTR);
          fread(ZFACTOR,sizeof(double),2,PNTR);
/* Short Arrays */
          fread(WINDOW,sizeof(short),4,PNTR);
/* Character Arrays */
          fread(TASKNAME, sizeof(TASKNAME),1,PNTR);
          fread(INNAME  , sizeof(INNAME  ),1,PNTR);
          fread(INCLASS , sizeof(INCLASS ),1,PNTR);
          fread(INPATH  , sizeof(INPATH  ),1,PNTR);
          fread(IN2NAME , sizeof(IN2NAME ),1,PNTR);
          fread(IN2CLASS, sizeof(IN2CLASS),1,PNTR);
          fread(IN2PATH , sizeof(IN2PATH ),1,PNTR);
          fread(IN3NAME , sizeof(IN3NAME ),1,PNTR);
          fread(IN3CLASS, sizeof(IN3CLASS),1,PNTR);
          fread(IN3PATH , sizeof(IN3PATH ),1,PNTR);
          fread(OUTNAME , sizeof(OUTNAME ),1,PNTR);
          fread(OUTCLASS, sizeof(OUTCLASS),1,PNTR);
          fread(OUTPATH , sizeof(OUTPATH ),1,PNTR);
          fread(TFORMAT , sizeof(TFORMAT ),1,PNTR);
          fread(YFORMAT , sizeof(YFORMAT ),1,PNTR);
          fread(ZFORMAT , sizeof(ZFORMAT ),1,PNTR);
          fread(PARITY  , sizeof(PARITY  ),1,PNTR);
          fread(DEVICE  , sizeof(DEVICE  ),1,PNTR);
          fread(TLABEL  , sizeof(TLABEL  ),1,PNTR);
          fread(YLABEL  , sizeof(YLABEL  ),1,PNTR);
          fread(ZLABEL  , sizeof(ZLABEL  ),1,PNTR);
          fread(TITLE   , sizeof(TITLE   ),1,PNTR);
/* Double Precision Variables */
          fread(&FACTOR,sizeof(double),1,PNTR);
/* Short Variables */
          fread(&CODE,sizeof(short),1,PNTR);
          fread(&ITYPE,sizeof(short),1,PNTR);
          fread(&BAUD,sizeof(short),1,PNTR);
          fread(&STOPBITS,sizeof(short),1,PNTR);
          fread(&DATABITS,sizeof(short),1,PNTR);
          fread(&TMINOR,sizeof(short),1,PNTR);
          fread(&YMINOR,sizeof(short),1,PNTR);
          fread(&ZMINOR,sizeof(short),1,PNTR);
          fread(&FRAME,sizeof(short),1,PNTR);
          fread(&BORDER,sizeof(short),1,PNTR);
          fread(&COLOR,sizeof(long),1,PNTR);
          fread(&QUIET,sizeof(short),1,PNTR);
          fread(&HARDWARE,sizeof(struct DEVICES),1,PNTR);
          fread(&LogFlag,sizeof(short),1,PNTR);
          if (ferror(PNTR))
            {
            Zencode(10,"%-8s: Error Reading Inputs File '%s'\n",
                    TASKNAME,path);
            Zerror();
            ERRFLAG=1;
            }
          fclose(PNTR);
          }
     else
          {
          ERRFLAG=1;
          Zencode(10,"%-8s: Sorry, Inputs File '%s' is not available.\n",
                  TASKNAME,path);
          }
     return(ERRFLAG);
     }

/*********************************************************************
*
* Put Adverbs to the file name pointed to by NAMEPNTR.
* 0 is returned if no errors.
* 1 is returned otherwise and an error message is printed.
* Input file names are of the form INPUTS\filename.INP
*
*/
short Zputadv(NAMEPNTR)
char *NAMEPNTR;
   {
   char dir[_MAX_DIR];
   char path[_MAX_PATH];
     FILE *PNTR;
     short ERRFLAG=0;

     strcpy(dir,TisanDir);
     strcat(dir,"INPUTS\\");
     _makepath(path,TisanDrive,dir,NAMEPNTR,".INP");

     PNTR = fopen(path,"wb");
     if (PNTR)
          {
/* Double Precision Arrays */
          fwrite(TRANGE,sizeof(double),2,PNTR);
          fwrite(YRANGE,sizeof(double),2,PNTR);
          fwrite(ZRANGE,sizeof(double),2,PNTR);
          fwrite(TMAJOR,sizeof(double),2,PNTR);
          fwrite(YMAJOR,sizeof(double),2,PNTR);
          fwrite(ZMAJOR,sizeof(double),2,PNTR);
          fwrite(PARMS,sizeof(double),10,PNTR);
          fwrite(POINT,sizeof(double),2,PNTR);
          fwrite(ZFACTOR,sizeof(double),2,PNTR);
/* Short Arrays */
          fwrite(WINDOW,sizeof(short),4,PNTR);
/* Character Arrays */
          fwrite(TASKNAME, sizeof(TASKNAME),1,PNTR);
          fwrite(INNAME  , sizeof(INNAME  ),1,PNTR);
          fwrite(INCLASS , sizeof(INCLASS ),1,PNTR);
          fwrite(INPATH  , sizeof(INPATH  ),1,PNTR);
          fwrite(IN2NAME , sizeof(IN2NAME ),1,PNTR);
          fwrite(IN2CLASS, sizeof(IN2CLASS),1,PNTR);
          fwrite(IN2PATH , sizeof(IN2PATH ),1,PNTR);
          fwrite(IN3NAME , sizeof(IN3NAME ),1,PNTR);
          fwrite(IN3CLASS, sizeof(IN3CLASS),1,PNTR);
          fwrite(IN3PATH , sizeof(IN3PATH ),1,PNTR);
          fwrite(OUTNAME , sizeof(OUTNAME ),1,PNTR);
          fwrite(OUTCLASS, sizeof(OUTCLASS),1,PNTR);
          fwrite(OUTPATH , sizeof(OUTPATH ),1,PNTR);
          fwrite(TFORMAT , sizeof(TFORMAT ),1,PNTR);
          fwrite(YFORMAT , sizeof(YFORMAT ),1,PNTR);
          fwrite(ZFORMAT , sizeof(ZFORMAT ),1,PNTR);
          fwrite(PARITY  , sizeof(PARITY  ),1,PNTR);
          fwrite(DEVICE  , sizeof(DEVICE  ),1,PNTR);
          fwrite(TLABEL  , sizeof(TLABEL  ),1,PNTR);
          fwrite(YLABEL  , sizeof(YLABEL  ),1,PNTR);
          fwrite(ZLABEL  , sizeof(ZLABEL  ),1,PNTR);
          fwrite(TITLE   , sizeof(TITLE   ),1,PNTR);
/* Double Precision Variables */
          fwrite(&FACTOR,sizeof(double),1,PNTR);
/* Short Variables */
          fwrite(&CODE,sizeof(short),1,PNTR);
          fwrite(&ITYPE,sizeof(short),1,PNTR);
          fwrite(&BAUD,sizeof(short),1,PNTR);
          fwrite(&STOPBITS,sizeof(short),1,PNTR);
          fwrite(&DATABITS,sizeof(short),1,PNTR);
          fwrite(&TMINOR,sizeof(short),1,PNTR);
          fwrite(&YMINOR,sizeof(short),1,PNTR);
          fwrite(&ZMINOR,sizeof(short),1,PNTR);
          fwrite(&FRAME,sizeof(short),1,PNTR);
          fwrite(&BORDER,sizeof(short),1,PNTR);
          fwrite(&COLOR,sizeof(long),1,PNTR);
          fwrite(&QUIET,sizeof(short),1,PNTR);
          fwrite(&HARDWARE,sizeof(struct DEVICES),1,PNTR);
          fwrite(&LogFlag,sizeof(short),1,PNTR);
          if (ferror(PNTR))
            {
            Zencode(10,"%-8s: Error Writing Inputs File '%s'\n",
                    TASKNAME,path);
            Zerror();
            ERRFLAG=1;
            }
          fclose(PNTR);
          }
     else
          {
          ERRFLAG=1;
          Zencode(10,"%-8s: Error Opening Inputs File '%s'\n",
                  TASKNAME,path);
          }
     return(ERRFLAG);
     }

/*********************************************************************
*
*  Put a file header to disk.
*  Returns 0 if no errors.
*  Returns 1 on error and prints a message.
*
*/
short Zputhead(OUTSTR,HEADPNTR)
FILE *OUTSTR;
struct FILEHDR *HEADPNTR;
     {
     rewind(OUTSTR);
     fwrite(HEADPNTR,sizeof(struct FILEHDR),1,OUTSTR);
     if (ferror(OUTSTR))
        {
        Zerror();
        return(1);
        }
     return(0);
     }

/*********************************************************************
*
*  Get file header and return pointer to FILEHDR structure.
*  Returns NULL on error and prints a message.
*
*/
struct FILEHDR *Zgethead(INSTR,HeadStruct)
FILE *INSTR;
struct FILEHDR *HeadStruct;
     {
     rewind(INSTR);

     if (!HeadStruct)
        {
        fseek(INSTR, (long)sizeof(struct FILEHDR), SEEK_SET);
        HeadStruct = (struct FILEHDR *)TRUE;
        }
     else
        fread(HeadStruct,sizeof(struct FILEHDR),1,INSTR);

     if (ferror(INSTR))
        {
        Zerror();
        HeadStruct = NULL;
        }

     return(HeadStruct);
     }

/*********************************************************************
*
*  Initialize Task.
*  Gets the adverbs from the inputs file, prints a message
*  and displays the inputs.
*  Returns 0 if no errors.
*  Returns 1 on error.
*/
short Ztskinit(PNTR,Argv0)
char *PNTR, *Argv0;
     {
     short INPUTS(void);
     long LTIME;
     short ERRFLAG;
     char fname[_MAX_FNAME], ext[_MAX_EXT];

     _splitpath(Argv0,TisanDrive,TisanDir,fname,ext);

     Zencode(0,"TISAN   : Task %s Begins\n",PNTR);

     ERRFLAG = Zgetadv(PNTR);

     if (LogFlag)
        LogStream = fopen("TISAN.LOG","a");
     else
        LogStream = NULL;

     strcpy(TASKNAME,PNTR);
     if (!ERRFLAG)
          {
          time(<IME);
          Zencode(2,"%-8s: Got Inputs on %s",TASKNAME,ctime(<IME));
          INPUTS();
          }
     return(ERRFLAG);
     }

/*********************************************************************
*
*  Name the Final Output File.
*  Deletes the file OUTFILE and names the file TMPFILE to OUTFILE.
*  Returns 0 if no errors.
*  Returns 1 on error and prints a message.
*
*/
short Znameout(OUTFILE,TMPFILE,ERRFLAG)
char *OUTFILE, *TMPFILE;
short ERRFLAG;
     {
     if (ERRFLAG)
          unlink(TMPFILE);
     else
          {
          Zencode(2,"%-8s: Naming File '%s'\n",TASKNAME,OUTFILE);
          unlink(OUTFILE);
          if (rename(TMPFILE,OUTFILE))
               {
               Zerror();
               ERRFLAG = 1;
               }
          }
     return(ERRFLAG);
     }

/*********************************************************************
*
*  Use Zencode to Print a File Error.
*
*/
void Zerror()
     {
     Zencode(10,"%-8s",TASKNAME);
     Zencode(10,": %s\n",strerror(NULL));
     return;
     }

/*********************************************************************
*
*  Print a message based on its priority level and QUIET.
*
*/
short Zencode(LEVEL,FMT,...)
short LEVEL;
char *FMT;
     {
     short N;
     va_list arg_ptr;

     va_start(arg_ptr,FMT);
     LEVEL = abs(LEVEL);

     if (LEVEL>=(abs(QUIET)-1))
          {
          N = vprintf(FMT,arg_ptr);
          if (QUIET<0) vfprintf(stdprn,FMT,arg_ptr);
          if (LogStream) vfprintf(LogStream,FMT,arg_ptr);
          }

     va_end(arg_ptr);
     return(N);
     }

/*********************************************************************
*
*  Get Data from INSTR into BUFFER and return number of bytes read
*  DATATYPE is type of data;
*/
short Zgetdat(INSTR,BUFFER,DATATYPE)
FILE *INSTR;
char *BUFFER;
char DATATYPE;
     {
     short N;

     N = fread(BUFFER,Zsize(DATATYPE),Maxbuff,INSTR);
     if (ferror(INSTR))
          {
          Zerror();
          return(0);
          }
     return(N);
     }

/*********************************************************************
*
*  Write out data buffer
*  Returns 0 if no errors.
*  Returns 1 on error and prints a message.
*
*/
short Zputdat(N,OUTSTR,BUFFER,DATATYPE)
short N;
FILE *OUTSTR;
char *BUFFER;
char DATATYPE;
     {
     if (N >= 1)
        {
        fwrite(BUFFER,Zsize(DATATYPE),N,OUTSTR);
        if (ferror(OUTSTR))
           {
           Zerror();
           return(1);
           }
        }
     return(0);
     }

/*********************************************************************
*
*  Write out one data value
*  Returns 0 if no errors.
*  Returns 1 on error and prints a message.
*
*/
short Zwrite(OUTSTR,DATA,DATATYPE)
FILE *OUTSTR;
char *DATA;
char DATATYPE;
     {
     fwrite(DATA,Zsize(DATATYPE),1,OUTSTR);
     if (ferror(OUTSTR))
          {
          Zerror();
          return(1);
          }
     return(0);
     }

/*********************************************************************
*
*  Read in one data value, return NULL if EOF or ERROR
*
*/
char *Zread(INSTR,DATA,DATATYPE)
FILE *INSTR;
char *DATA;
char DATATYPE;
     {
     fread(DATA,Zsize(DATATYPE),1,INSTR);
     if (ferror(INSTR) || feof(INSTR))
          {
          if (ferror(INSTR)) Zerror();
          return(NULL);
          }
     return(DATA);
     }

/*********************************************************************
*
*  Return the size of DATATYPE
*
*/
short Zsize(DATATYPE)
char DATATYPE;
   {
   short M=0;

   switch (DATATYPE)
      {
      case R_Data:
         M = sizeof(struct RData);
         break;
      case TR_Data:
         M = sizeof(struct TRData);
         break;
      case X_Data:
         M = sizeof(struct XData);
         break;
      case TX_Data:
         M = sizeof(struct TXData);
         break;
      }
   return(M);
   }

/*********************************************************************
**
** Command to sound bell
*/
void BEEP()
   {
   printf("\a");
   return;
   }

/*********************************************************************
**
** Exit a task
*/
void Zexit(N)
int N;
   {
   if (LogStream) fclose(LogStream);
   ZCatFiles(NULL);  /* Possibly Deallocate CatFiles Memory */
   exit(N);
   }
/*
** This library defines the complex equivalents to:
**
**    addition
**    subtraction
**    multiplication
**    division
**    square root
**    natural log (ln)
**    exponentiation (exp)
**    sin
**    cos
**    tan
**    sec
**    csc
**    cot
**    arcsin
**    arccos
**    arctan
**    arcsec
**    arccsc
**    arccot
**    sinh
**    cosh
**    tanh
**    sech
**    csch
**    coth
**    arcsinh
**    arccosh
**    arctanh
**    arcsech
**    arccsch
**    arccoth
**    log10
**    pow
*/

struct complex c_add(z1,z2)
struct complex z1, z2;
   {
   struct complex zz;

   zz.x = z1.x + z2.x;
   zz.y = z1.y + z2.y;
   return(zz);
   }

struct complex c_sub(z1,z2)
struct complex z1, z2;
   {
   struct complex zz;

   zz.x = z1.x - z2.x;
   zz.y = z1.y - z2.y;
   return(zz);
   }

struct complex c_mul(z1,z2)
struct complex z1, z2;
   {
   struct complex zz;

   zz.x = (z1.x * z2.x) - (z1.y * z2.y);
   zz.y = (z1.x * z2.y) + (z1.y * z2.x);
   return(zz);
   }

struct complex c_div(z1,z2)
struct complex z1, z2;
   {
   struct complex zz;
   double mag;

   zz.x = ((z1.x * z2.x) + (z1.y * z2.y))/
          (mag = z2.x*z2.x + z2.y*z2.y);
   zz.y = ((z2.x * z1.y) - (z1.x * z2.y))/mag;
   return(zz);
   }

struct complex c_sqrt(z)
struct complex z;
   {
   struct complex zz;
   double sqrt_r, half_theta;

   zz.x = (sqrt_r = sqrt(cabs(z))) *
          cos(half_theta = atan2(z.y,z.x)/2.);
   zz.y = sqrt_r * sin(half_theta);
   return(zz);
   }

struct complex c_ln(z)
struct complex z;
   {
   struct complex zz;

   zz.x = log(cabs(z));
   zz.y = atan2(z.y,z.x);
   return(zz);
   }

struct complex c_exp(z)
struct complex z;
   {
   struct complex zz;
   double ex;

   zz.x = (ex = exp(z.x)) * cos(z.y);
   zz.y = ex * sin(z.y);
   return(zz);
   }

struct complex c_sin(z)
struct complex z;
   {
   double v1, v2;
   struct complex zz;

   zz.x =  ((v2 = exp(-z.y)) + (v1 = exp(z.y)))*sin(z.x)/2.;
   zz.y = -(v2 - v1)*cos(z.x)/2.;
   return(zz);
   }

struct complex c_cos(z)
struct complex z;
   {   
   double v1, v2;
   struct complex zz;

   zz.x =  ((v2 = exp(-z.y)) + (v1 = exp(z.y)))*cos(z.x)/2.;
   zz.y =  (v2 - v1)*sin(z.x)/2.;
   return(zz);
   }

struct complex c_tan(z)
struct complex z;
   {
   return(c_div(c_sin(z),c_cos(z)));
   }

struct complex c_sec(z)
struct complex z;
   {
   struct complex zz;

   zz.x = 1.;
   zz.y = 0.;
   return(c_div(zz,c_cos(z)));
   }

struct complex c_csc(z)
struct complex z;
   {
   struct complex zz;

   zz.x = 1.;
   zz.y = 0.;
   return(c_div(zz,c_sin(z)));
   }

struct complex c_cot(z)
struct complex z;
   {
   return(c_div(c_cos(z),c_sin(z)));
   }

struct complex c_asin(z)   /* -i*ln(iz + sqrt(1 - z^2)) */
struct complex z;
   {
   struct complex zz;
   double v;

   zz.x = 1. - (z.x*z.x - z.y*z.y);
   zz.y = -2. * z.x*z.y;
   zz = c_sqrt(zz);
   zz.x -= z.y;
   zz.y += z.x;
   zz = c_ln(zz);
   v = zz.x;
   zz.x = zz.y;
   zz.y = -v;
   return(zz);
   }

struct complex c_acos(z)     /* -i*ln(iz + sqrt(z^2 - 1)) */
struct complex z;
   {
   struct complex zz;
   double v;

   zz.x = (z.x*z.x - z.y*z.y) - 1;
   zz.y = 2. * z.x*z.y;
   zz = c_sqrt(zz);
   zz.x += z.x;
   zz.y += z.y;
   zz = c_ln(zz);
   v = zz.x;
   zz.x = zz.y;
   zz.y = -v;
   return(zz);
   }

struct complex c_atan(z)
struct complex z;
   {
   struct complex zz1, zz2, zz;
   double v;

   zz1.x = 1. - z.y;
   zz1.y =  z.x;
   zz2.x = 1. + z.y;
   zz2.y = -z.x;
   zz = c_ln(c_div(zz1,zz2));
   v = zz.x/2.;
   zz.x = zz.y/2.;
   zz.y = -v;
   return(zz);
   }

struct complex c_acot(z)
struct complex z;
   {
   struct complex zz1, zz2, zz;
   double v;

   zz1.x = z.x;
   zz1.y = z.y + 1.;
   zz2.x = z.x;
   zz2.y = z.y - 1.;
   zz = c_ln(c_div(zz1,zz2));
   v = zz.x/2.;
   zz.x = zz.y/2.;
   zz.y = -v;
   return(zz);
   }

struct complex c_acsc(z)
struct complex z;
   {
   struct complex zz;
   double v;

   zz.x = (z.x*z.x - z.y*z.y) - 1;
   zz.y = 2. * z.x*z.y;
   zz = c_sqrt(zz);
   zz.y += 1.;
   zz = c_ln(c_div(zz,z));
   v = zz.x;
   zz.x = zz.y;
   zz.y = -v;
   return(zz);
   }

struct complex c_asec(z)
struct complex z;
   {
   struct complex zz;
   double v;

   zz.x = 1. - (z.x*z.x - z.y*z.y);
   zz.y = -2. * z.x*z.y;
   zz = c_sqrt(zz);
   zz.x += 1.;
   zz = c_ln(c_div(zz,z));
   v = zz.x;
   zz.x = zz.y;
   zz.y = -v;
   return(zz);
   }

struct complex c_sinh(z)
struct complex z;
   {
   double v1, v2;
   struct complex zz;

   zz.x =  ((v1 = exp(z.x)) - (v2 = exp(-z.x)))*cos(z.y)/2.;
   zz.y =  (v1 + v2)*sin(z.y)/2.;
   return(zz);
   }

struct complex c_cosh(z)
struct complex z;
   {
   double v1, v2;
   struct complex zz;

   zz.x = ((v1 = exp(z.x)) + (v2 = exp(-z.x)))*cos(z.y)/2.;
   zz.y = (v1 - v2)*sin(z.y)/2.;
   return(zz);
   }

struct complex c_tanh(z)
struct complex z;
   {
   return(c_div(c_sinh(z),c_cosh(z)));
   }

struct complex c_sech(z)
struct complex z;
   {
   struct complex zz;

   zz.x = 1.;
   zz.y = 0.;
   return(c_div(zz,c_cosh(z)));
   }

struct complex c_csch(z)
struct complex z;
   {
   struct complex zz;

   zz.x = 1.;
   zz.y = 0.;
   return(c_div(zz,c_sinh(z)));
   }

struct complex c_coth(z)
struct complex z;
   {
   return(c_div(c_cosh(z),c_sinh(z)));
   }

struct complex c_asinh(z)
struct complex z;
   {
   struct complex zz;

   zz.x = 1. - (z.x*z.x - z.y*z.y);
   zz.y = -2. * z.x*z.y;
   zz = c_sqrt(zz);
   zz.x += z.x;
   zz.y += z.y;
   zz = c_ln(zz);
   return(zz);
   }

struct complex c_acosh(z)
struct complex z;
   {
   struct complex zz;

   zz.x = (z.x*z.x - z.y*z.y) - 1;
   zz.y = 2. * z.x*z.y;
   zz = c_sqrt(zz);
   zz.x += z.x;
   zz.y += z.y;
   zz = c_ln(zz);
   return(zz);
   }

struct complex c_atanh(z)
struct complex z;
   {
   struct complex zz1, zz2, zz;

   zz1.x = 1. + z.x;
   zz1.y =  z.y;
   zz2.x = 1. - z.x;
   zz2.y =  z.y;
   zz = c_ln(c_div(zz1,zz2));
   zz.x /= 2.;
   zz.y /= 2.;
   return(zz);
   }

struct complex c_acsch(z)
struct complex z;
   {
   struct complex zz;

   zz.x = (z.x*z.x - z.y*z.y) + 1;
   zz.y = 2. * z.x*z.y;
   zz = c_sqrt(zz);
   zz.x += 1.;
   zz = c_ln(c_div(zz,z));
   return(zz);
   }

struct complex c_asech(z)
struct complex z;
   {
   struct complex zz;

   zz.x = 1. - (z.x*z.x - z.y*z.y);
   zz.y = -2. * z.x*z.y;
   zz = c_sqrt(zz);
   zz.x += 1.;
   zz = c_ln(c_div(zz,z));
   return(zz);
   }

struct complex c_acoth(z)
struct complex z;
   {
   struct complex zz1, zz2, zz;

   zz1.x = z.x + 1.;
   zz1.y = z.y;
   zz2.x = z.x - 1.;
   zz2.y = z.y;
   zz = c_ln(c_div(zz1,zz2));
   zz.x /= 2.;
   zz.y /= 2.;
   return(zz);
   }

struct complex c_log10(z)
struct complex z;
   {
   struct complex zz;
   
   zz = c_ln(z);
   zz.x /= 2.30258509299;
   zz.y /= 2.30258509299;
   return(zz);
   }

struct complex c_pow(z1,z2)
struct complex z1, z2;
   {
   return(c_exp(c_mul(z2,c_ln(z1))));
   }


double asinh (x)
double x;
   {
   return(log(x + sqrt((x*x) + 1.)));
   }

double acosh (x)
double x;
   {
   return(log(x + sqrt((x*x) - 1.)));
   }

double atanh (x)
double x;
   {
   return(log((1.+x)/(1.-x))/2.);
   }

struct complex cmplx(r, i)  /* R + iI */
double r, i;
   {
   struct complex z;
   z.x = r;
   z.y = i;
   return(z);
   }

/*********************************************************************
*
* Get a Message From the File TISAN.IDX and Print it 
* from cloumn 44 to 80 by however-many lines
*
*/
short DisplayText(IndexTableStream)
FILE *IndexTableStream;
   {
   long PL;
   short I;
   short P;
   char C;

   if (!IndexTableStream)
      {
      Zencode(0,"\n-%8s: ",TASKNAME);
      return(0);
      }

   I=0;
   while (I<36)
      {
      C = fgetc(IndexTableStream);
      if (!C || (C == '\n')) break;
      Zencode(0,"%c",C);
      ++I;
      } /* End While */
   if (I < 36) Zencode(0,CrLf);
   return(C);
   }

/*********************************************************************
*
* Write a string to columns 22 to 41 and the message line after it
*
*/
short WriteString(StringPointer,IndexTableStream)
char *StringPointer;
FILE *IndexTableStream;
  {
  short M,N,I;
  BOOL PassFlag=FALSE;
  char C=1;

  do {
     if (!PassFlag)
        {
        N = Zencode(0,"%.19s",StringPointer);
        PassFlag = TRUE;
        M = N + 1;
        }
     else
        {
        M = N = Zencode(0,"%.20s",StringPointer);
        }

     if (M < 20)
        {
        ++M;
        PassFlag = -1;
        Zencode(0,"'");
        }

     for (I=M;I<21;++I) Zencode(0,Space);
     if (C)
        C = (char)DisplayText(IndexTableStream);
     else
        DisplayText(NULL);
     if ((M == 20) && (PassFlag > 0))
        {
        StringPointer += N;
        Zencode(0,"%13s",Space);
        }
     }
  while ((M == 20) && (PassFlag > 0));
  if (C) Zencode(0,"%34s",Space);
  return(C);
  }

/*********************************************************************
*
* Print an adverb and its value
*/
void DisplayInputs(InputsAdverbToken,IndexTableStream)
unsigned char InputsAdverbToken;
FILE *IndexTableStream;
  {
  short I;
  char C=1, BUFFER[44];

  switch (InputsAdverbToken)
     {
     case 1:
        sprintf(BUFFER,"INNAME   ... '%s'",INNAME);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 2:
        sprintf(BUFFER,"INCLASS  ... '%s'",INCLASS);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 3:
        Zencode(0,"%-8s: INPATH   ... '",TASKNAME);
        C = WriteString(INPATH,IndexTableStream);
        break;
     case 4:
        sprintf(BUFFER,"IN2NAME  ... '%s'",IN2NAME);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 5:
        sprintf(BUFFER,"IN2CLASS ... '%s'",IN2CLASS);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 6:
        Zencode(0,"%-8s: IN2PATH  ... '",TASKNAME);
        C = WriteString(IN2PATH,IndexTableStream);
        break;
     case 7:
        sprintf(BUFFER,"IN3NAME  ... '%s'",IN3NAME);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 8:
        sprintf(BUFFER,"IN3CLASS ... '%s'",IN3CLASS);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 9:
        Zencode(0,"%-8s: IN3PATH  ... '",TASKNAME);
        C = WriteString(IN3PATH,IndexTableStream);
        break;
     case 10:
        sprintf(BUFFER,"OUTNAME  ... '%s'",OUTNAME);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 11:
        sprintf(BUFFER,"OUTCLASS ... '%s'",OUTCLASS);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 12:
        Zencode(0,"%-8s: OUTPATH  ... '",TASKNAME);
        C = WriteString(OUTPATH,IndexTableStream);
        break;
     case 13:
        sprintf(BUFFER,"CODE     ... %d",CODE);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 14:
        sprintf(BUFFER,"ITYPE    ... %d",ITYPE);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 15:
        sprintf(BUFFER,"FACTOR   ... %G",FACTOR);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 16:
        sprintf(BUFFER,"TRANGE   ... %G, %G",TRANGE[0],TRANGE[1]);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 17:
        sprintf(BUFFER,"YRANGE   ... %G, %G",YRANGE[0],YRANGE[1]);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 18:
        sprintf(BUFFER,"ZRANGE   ... %G, %G",ZRANGE[0],ZRANGE[1]);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 19:
        sprintf(BUFFER,"WINDOW   ... %d, %d,",WINDOW[0],WINDOW[1]);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        C = DisplayText(IndexTableStream);
        sprintf(BUFFER,"             %d, %d",WINDOW[2],WINDOW[3]);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        if (C) C = DisplayText(IndexTableStream); else Zencode(0,CrLf);
        break;
     case 20:
        sprintf(BUFFER,"TFORMAT  ... '%s'",TFORMAT);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 21:
        sprintf(BUFFER,"YFORMAT  ... '%s'",YFORMAT);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 22:
        sprintf(BUFFER,"ZFORMAT  ... '%s'",ZFORMAT);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 23:
        sprintf(BUFFER,"DEVICE   ... '%s'",DEVICE);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 24:
        sprintf(BUFFER,"BAUD     ... %d",BAUD);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 25:
        sprintf(BUFFER,"STOPBITS ... %d",STOPBITS);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 26:
        sprintf(BUFFER,"DATABITS ... %d",DATABITS);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 27:
        sprintf(BUFFER,"PARITY   ... '%s'",PARITY);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 28:
        sprintf(BUFFER,"FRAME    ... %d",FRAME);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 29:
        sprintf(BUFFER,"BORDER   ... %d",BORDER);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 30:
        sprintf(BUFFER,"COLOR    ... %ld",COLOR);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 31:
        sprintf(BUFFER,"TMINOR   ... %d",TMINOR);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 32:
        sprintf(BUFFER,"YMINOR   ... %d",YMINOR);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 33:
        sprintf(BUFFER,"ZMINOR   ... %d",ZMINOR);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 34:
        sprintf(BUFFER,"TMAJOR   ... %G, %G",TMAJOR[0],TMAJOR[1]);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 35:
        sprintf(BUFFER,"YMAJOR   ... %G, %G",YMAJOR[0],YMAJOR[1]);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 36:
        sprintf(BUFFER,"ZMAJOR   ... %G, %G",ZMAJOR[0],ZMAJOR[1]);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 37:
        Zencode(0,"%-8s: TLABEL   ... '",TASKNAME);
        C = WriteString(TLABEL,IndexTableStream);
        break;
     case 38:
        Zencode(0,"%-8s: YLABEL   ... '",TASKNAME);
        C = WriteString(YLABEL,IndexTableStream);
        break;
     case 39:
        Zencode(0,"%-8s: ZLABEL   ... '",TASKNAME);
        C = WriteString(ZLABEL,IndexTableStream);
        break;
     case 40:
        Zencode(0,"%-8s: TITLE    ... '",TASKNAME);
        C = WriteString(TITLE,IndexTableStream);
        break;
     case 41:
        sprintf(BUFFER,"PARMS    ... %G, %G,",PARMS[0],PARMS[1]);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        C = DisplayText(IndexTableStream);
        sprintf(BUFFER,"             %G, %G,",PARMS[2],PARMS[3]);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        if (C) C = DisplayText(IndexTableStream); else Zencode(0,CrLf);
        sprintf(BUFFER,"             %G, %G,",PARMS[4],PARMS[5]);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        if (C) C = DisplayText(IndexTableStream); else Zencode(0,CrLf);
        sprintf(BUFFER,"             %G, %G,",PARMS[6],PARMS[7]);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        if (C) C = DisplayText(IndexTableStream); else Zencode(0,CrLf);
        sprintf(BUFFER,"             %G, %G",PARMS[8],PARMS[9]);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        if (C) C = DisplayText(IndexTableStream); else Zencode(0,CrLf);
        break;
     case 42:
        sprintf(BUFFER,"QUIET    ... %d",QUIET);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 43:
        sprintf(BUFFER,"POINT    ... %G, %G",POINT[0],POINT[1]);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     case 44:
        sprintf(BUFFER,"ZFACTOR  ... %G, %G",ZFACTOR[0],ZFACTOR[1]);
        Zencode(0,"%-8s: %-34s",TASKNAME,BUFFER);
        break;
     }

  while (C)
     {
     if (C = DisplayText(IndexTableStream))
        Zencode(0,"%-8s: %34s",TASKNAME,Space);
     }

  return;
  }

/*********************************************************************
* Pseudo Verb Inputs
*
* Display Adverbs on Screen for a Given TASKNAME
*
* Format for TISAN.IDX is
* TASKNAME1234TASKNAME1234....NULL0000TextTtextTtextTtext<NULL>
*
*/
short INPUTS()
   {
   char *cPointer;
   short I;
   short J;
   char C;
   FILE *IndexTableStream;
   BOOL NoMatch;
   long longP;
   unsigned char InputsAdverbToken;
   char path[_MAX_PATH], fname[_MAX_FNAME];

   _makepath(path,TisanDrive,TisanDir,"TISAN",".IDX");

   cPointer = TASKNAME;

   IndexTableStream = fopen(path,"rb");
   if (!IndexTableStream)
      {
      Zencode(0,"%-8s: Error Opening Index File for Read.\n",TASKNAME);
      return(FALSE);
      }
/*
** Locate the Current Task in the index file
**
*/
   do {
      fread(fname,1,8,IndexTableStream);
      fread(&longP,sizeof(long),1,IndexTableStream);
      fname[8] = '\0';
      if (ferror(IndexTableStream))
         {
         Zencode(0,"%-8s: Error Reading TISAN.IDX\n",TASKNAME);
         fcloseall();
         return(FALSE);
         }
      if (!longP)
         {
         Zencode(0,"%-8s: Task %s Not Found in TISAN.IDX\n",TASKNAME,cPointer);
         fcloseall();
         return(FALSE);
         }
      NoMatch = strcmp(fname,cPointer);  /* No match ?*/
      }
   while (NoMatch);

   fseek(IndexTableStream,longP,SEEK_SET);
     
   Zencode(0,"%-8s:\n",TASKNAME);
   Zencode(0,"%-8s: %s - ",TASKNAME,cPointer);
   do {
      if (C = fgetc(IndexTableStream))
         Zencode(0,"%c",C);
      else
         Zencode(0,CrLf);
      }
   while (C);

   Zencode(0,"%-8s: ---------------------------------------\
------------------------------\n",TASKNAME);
   do {
      if (!(InputsAdverbToken = fgetc(IndexTableStream))) break;
      DisplayInputs(InputsAdverbToken,IndexTableStream);
      }
   while (!INTERRUPT);
   Zencode(0,"%-8s:\n",TASKNAME);
   fclose(IndexTableStream);
   return(TRUE);
   }

/*********************************************************************
*
* ZCatFiles will count the number of files matching szPath and
* allocate memory to hold the list of null terminated file names.
* If memory has been allocated by a previous call, then it is
* first deallocated.  If szPath is NULL then only the memory
* dealocation is performed if needed.
* It is important that floating point errors be trapped if any
* memory has been allocated.
*/
struct CATSTRUCT *ZCatFiles(szPath)
char *szPath;
   {
   static struct CATSTRUCT CatList;
   struct CATSTRUCT *pCatList = NULL;
   struct find_t FileEntry;
   char *pChar;
   int NumBytes = 0;

   if (CatList.pList) free(CatList.pList);

   CatList.N = 0;
   CatList.pList = NULL;

   if (szPath)
      {
      if (!_dos_findfirst(szPath,_A_NORMAL,&FileEntry))
         {
         NumBytes = strlen(FileEntry.name) + 1;
         ++CatList.N;
         }
      while(!_dos_findnext(&FileEntry))
         {
         NumBytes += (strlen(FileEntry.name) + 1);
         ++CatList.N;
         }
      if (CatList.N)
         {
         if (pChar = CatList.pList = malloc(NumBytes))
            {
            if (!_dos_findfirst(szPath,_A_NORMAL,&FileEntry))
               {
               strcpy(pChar,FileEntry.name);
               pChar = strchr(pChar,'\0') + 1;
               }
   
            while(!_dos_findnext(&FileEntry))
               {
               strcpy(pChar,FileEntry.name);
               pChar = strchr(pChar,'\0') + 1;
               }

            pCatList = &CatList;
            }
         else
            Zencode(10,"%-8s: Memory Allocation Failure During Catalog\n",
                    TASKNAME);
         }
      else
         Zencode(10,"%-8s: No Files Matching '%s'\n",TASKNAME,szPath);
      }

   return(pCatList);
   }

/*********************************************************************
*
*  Put a file header to disk.
*  Returns FALSE if no errors.
*  Returns TRUE on error and prints a message.
*
*/
BOOL zPutHeader(pFile, pHeader)
struct FILESTRUCT *pFile;
struct FILEHDR *pHeader;
   {
   zFileSeek(pFile, 0L, SEEK_SET);
   zFileWrite(pFile, (LPSTR)pHeader,
              (long)sizeof(struct FILEHDR));
   if (pFile->iEoF)
      {
      zMessage(10,"%-8s: Error Writing Header in '%s'\n",
              TASKNAME,pFile->OFstruct.szPathName);
      return(TRUE);
      }
   return(FALSE);
   }

/*********************************************************************
*
*  Get file header and return pointer to FILEHDR structure.
*  Returns NULL on error and prints a message.
*
*/
struct FILEHDR *zGetHeader(pFile, pHeader)
struct FILESTRUCT *pFile;
struct FILEHDR *pHeader;
   {
   zFileSeek(pFile, 0L, SEEK_SET);

   if (!pHeader)
      {
      zFileSeek(pFile, (long)sizeof(struct FILEHDR), SEEK_SET);
      pHeader = (struct FILEHDR *)TRUE;
      }
   else
      zFileRead(pFile, (LPSTR)pHeader,
                (long)sizeof(struct FILEHDR));

   if (pFile->iEoF)
      {
      zMessage(10,"%-8s: Error Reading Header in '%s'\n",
              TASKNAME,pFile->OFstruct.szPathName);
      pHeader = NULL;
      }

   return(pHeader);
   }

/*********************************************************************
*
* Get Adverbs from the file name pointed to by pFileName.
* FALSE is returned if no errors.
* TRUE is returned otherwise and an error message is printed.
* Input file names are of the form INPUTS\filename.INP
*
*/
BOOL zGetAdverbs(pFileName)
char *pFileName;
   {
   char dir[_MAX_DIR];
   char path[_MAX_PATH];
   HANDLE hFile;
   BOOL bERRFLAG=FALSE;

   strcpy(dir,TisanDir);
   strcat(dir,"INPUTS\\");
   _makepath(path,TisanDrive,dir,pFileName,".INP");

   hFile = open(path, O_RDONLY | O_BINARY, S_IREAD | S_IWRITE);
   if (hFile != OPENERROR)
      {
/* Double Precision Arrays */
      read(hFile,(char *)TRANGE,sizeof(double) * 2);
      read(hFile,(char *)YRANGE,sizeof(double) * 2);
      read(hFile,(char *)ZRANGE,sizeof(double) * 2);
      read(hFile,(char *)TMAJOR,sizeof(double) * 2);
      read(hFile,(char *)YMAJOR,sizeof(double) * 2);
      read(hFile,(char *)ZMAJOR,sizeof(double) * 2);
      read(hFile,(char *)PARMS,sizeof(double) * 10);
      read(hFile,(char *)POINT,sizeof(double) * 2);
      read(hFile,(char *)ZFACTOR,sizeof(double) * 2);
/* Short Arrays */
      read(hFile,(char *)WINDOW,sizeof(short) * 4);
/* Character Arrays */
      read(hFile,TASKNAME, sizeof(TASKNAME));
      read(hFile,INNAME  , sizeof(INNAME  ));
      read(hFile,INCLASS , sizeof(INCLASS ));
      read(hFile,INPATH  , sizeof(INPATH  ));
      read(hFile,IN2NAME , sizeof(IN2NAME ));
      read(hFile,IN2CLASS, sizeof(IN2CLASS));
      read(hFile,IN2PATH , sizeof(IN2PATH ));
      read(hFile,IN3NAME , sizeof(IN3NAME ));
      read(hFile,IN3CLASS, sizeof(IN3CLASS));
      read(hFile,IN3PATH , sizeof(IN3PATH ));
      read(hFile,OUTNAME , sizeof(OUTNAME ));
      read(hFile,OUTCLASS, sizeof(OUTCLASS));
      read(hFile,OUTPATH , sizeof(OUTPATH ));
      read(hFile,TFORMAT , sizeof(TFORMAT ));
      read(hFile,YFORMAT , sizeof(YFORMAT ));
      read(hFile,ZFORMAT , sizeof(ZFORMAT ));
      read(hFile,PARITY  , sizeof(PARITY  ));
      read(hFile,DEVICE  , sizeof(DEVICE  ));
      read(hFile,TLABEL  , sizeof(TLABEL  ));
      read(hFile,YLABEL  , sizeof(YLABEL  ));
      read(hFile,ZLABEL  , sizeof(ZLABEL  ));
      read(hFile,TITLE   , sizeof(TITLE   ));
/* Double Precision Variables */
      read(hFile,(char *)&FACTOR,sizeof(double));
/* Short Variables */
      read(hFile,(char *)&CODE,sizeof(short));
      read(hFile,(char *)&ITYPE,sizeof(short));
      read(hFile,(char *)&BAUD,sizeof(short));
      read(hFile,(char *)&STOPBITS,sizeof(short));
      read(hFile,(char *)&DATABITS,sizeof(short));
      read(hFile,(char *)&TMINOR,sizeof(short));
      read(hFile,(char *)&YMINOR,sizeof(short));
      read(hFile,(char *)&ZMINOR,sizeof(short));
      read(hFile,(char *)&FRAME,sizeof(short));
      read(hFile,(char *)&BORDER,sizeof(short));
      read(hFile,(char *)&COLOR,sizeof(long));
      read(hFile,(char *)&QUIET,sizeof(short));
      read(hFile,(char *)&HARDWARE,sizeof(struct DEVICES));
      read(hFile,(char *)&LogFlag,sizeof(short));
      if (eof(hFile) < 0)
         {
         zMessage(10,"%-8s: Error Reading Inputs File '%s'\n",
                 TASKNAME,path);
         bERRFLAG=TRUE;
         }
      close(hFile);
      }
   else
      {
      bERRFLAG=TRUE;
      zMessage(10,"%-8s: Sorry, Inputs File '%s' is not available.\n",
              TASKNAME,path);
     }
   return(bERRFLAG);
   }

/*********************************************************************
*
* Put Adverbs to the file name pointed to by pFileName.
* FALSE is returned if no errors.
* TRUE is returned otherwise and an error message is printed.
* Input file names are of the form INPUTS\filename.INP
*
*/
BOOL zPutAdverbs(pFileName)
char *pFileName;
   {
   char dir[_MAX_DIR];
   char path[_MAX_PATH];
   HANDLE hFile;
   BOOL bERRFLAG=FALSE;

   strcpy(dir,TisanDir);
   strcat(dir,"INPUTS\\");
   _makepath(path,TisanDrive,dir,pFileName,".INP");

   hFile = open(path,
                O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
                S_IREAD | S_IWRITE);
   if (hFile != OPENERROR)
      {
/* Double Precision Arrays */
      write(hFile,(char *)TRANGE,sizeof(double) * 2);
      write(hFile,(char *)YRANGE,sizeof(double) * 2);
      write(hFile,(char *)ZRANGE,sizeof(double) * 2);
      write(hFile,(char *)TMAJOR,sizeof(double) * 2);
      write(hFile,(char *)YMAJOR,sizeof(double) * 2);
      write(hFile,(char *)ZMAJOR,sizeof(double) * 2);
      write(hFile,(char *)PARMS,sizeof(double) * 10);
      write(hFile,(char *)POINT,sizeof(double) * 2);
      write(hFile,(char *)ZFACTOR,sizeof(double) * 2);
/* Short Arrays */
      write(hFile,(char *)WINDOW,sizeof(short) * 4);
/* Character Arrays */
      write(hFile,TASKNAME, sizeof(TASKNAME));
      write(hFile,INNAME  , sizeof(INNAME  ));
      write(hFile,INCLASS , sizeof(INCLASS ));
      write(hFile,INPATH  , sizeof(INPATH  ));
      write(hFile,IN2NAME , sizeof(IN2NAME ));
      write(hFile,IN2CLASS, sizeof(IN2CLASS));
      write(hFile,IN2PATH , sizeof(IN2PATH ));
      write(hFile,IN3NAME , sizeof(IN3NAME ));
      write(hFile,IN3CLASS, sizeof(IN3CLASS));
      write(hFile,IN3PATH , sizeof(IN3PATH ));
      write(hFile,OUTNAME , sizeof(OUTNAME ));
      write(hFile,OUTCLASS, sizeof(OUTCLASS));
      write(hFile,OUTPATH , sizeof(OUTPATH ));
      write(hFile,TFORMAT , sizeof(TFORMAT ));
      write(hFile,YFORMAT , sizeof(YFORMAT ));
      write(hFile,ZFORMAT , sizeof(ZFORMAT ));
      write(hFile,PARITY  , sizeof(PARITY  ));
      write(hFile,DEVICE  , sizeof(DEVICE  ));
      write(hFile,TLABEL  , sizeof(TLABEL  ));
      write(hFile,YLABEL  , sizeof(YLABEL  ));
      write(hFile,ZLABEL  , sizeof(ZLABEL  ));
      write(hFile,TITLE   , sizeof(TITLE   ));
/* Double Precision Variables */
      write(hFile,(char *)&FACTOR,sizeof(double));
/* Short Variables */
      write(hFile,(char *)&CODE,sizeof(short));
      write(hFile,(char *)&ITYPE,sizeof(short));
      write(hFile,(char *)&BAUD,sizeof(short));
      write(hFile,(char *)&STOPBITS,sizeof(short));
      write(hFile,(char *)&DATABITS,sizeof(short));
      write(hFile,(char *)&TMINOR,sizeof(short));
      write(hFile,(char *)&YMINOR,sizeof(short));
      write(hFile,(char *)&ZMINOR,sizeof(short));
      write(hFile,(char *)&FRAME,sizeof(short));
      write(hFile,(char *)&BORDER,sizeof(short));
      write(hFile,(char *)&COLOR,sizeof(long));
      write(hFile,(char *)&QUIET,sizeof(short));
      write(hFile,(char *)&HARDWARE,sizeof(struct DEVICES));
      write(hFile,(char *)&LogFlag,sizeof(short));
      if (eof(hFile) < 0)
         {
         zMessage(10,"%-8s: Error Writing Inputs File '%s'\n",
                 TASKNAME,path);
         bERRFLAG=TRUE;
         }
      close(hFile);
      }
   else
      {
      bERRFLAG=TRUE;
      zMessage(10,"%-8s: Error Opening Inputs File '%s'\n",
              TASKNAME,path);
      }
   return(bERRFLAG);
   }

/*********************************************************************
*
*  Initialize Task.
*  Gets the adverbs from the inputs file, prints a message
*  and displays the inputs.
*  Returns FALSE if no errors.
*  Returns TRUE on error.
*/
BOOL zTaskInit(PNTR,Argv0)
char *PNTR, *Argv0;
   {
   short INPUTS(void);
   long lTIME;
   BOOL bERRFLAG;
   char fname[_MAX_FNAME], ext[_MAX_EXT];

   _splitpath(Argv0,TisanDrive,TisanDir,fname,ext);

   zMessage(0,"TISAN   : Task %s Begins\n",PNTR);

   bERRFLAG = zGetAdverbs(PNTR);

   if (LogFlag)
      LogStream = fopen("TISAN.LOG","a");
   else
      LogStream = NULL;

   strcpy(TASKNAME,PNTR);
   if (!bERRFLAG)
      {
      time(&lTIME);
      zMessage(2,"%-8s: Got Inputs on %s",TASKNAME,ctime(&lTIME));
      INPUTS();
      }
   return(bERRFLAG);
   }

/*********************************************************************
*
*  Make a file name and return a pointer
*  Create one of 4 types of file names
*
* M_inname  : Primary input file
* M_in2name : Secondary input file
* M_outname : Output file
* M_tmpname : Temporary scratch file
*
* The Primary file name is built from INNAME, INCLASS and INPATH directly.
* The Secondary file name is built from IN2NAME, IN2CLASS and IN2PATH if
* they are not null strings, if any one is not defined, then INNAME,
* INCLASS or INPATH is used.
* The Output file name is built from OUTNAME, OUTCLASS and OUTPATH if
* they are not null strings, if any one is not defined, then INNAME,
* INCLASS or INPATH is used.
* The Temporary file name is built from OUTPATH, an 8 character name based
* on the current process ID, the TASKNAME and the number of retries in
* building the name.  The extension .TMP is always used.
*
* If the file name can be created, a pointer is returned, otherwise
* an error message is printed and the TASK dies.
*/
char *ZBuildFileName(TYPE,cPointer)
short TYPE;
char *cPointer;
   {
   char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
   char path[_MAX_PATH];
   char *cPathPointer, *cFnamePointer, *cExtPointer;
   char PID[6];

   switch (TYPE)
      {
      case M_inname:        /* Create an INfile name */
         _splitpath(INPATH,drive,dir,fname,ext);
         strcat(dir,fname);
         _makepath(cPointer,drive,dir,INNAME,INCLASS);
         break;
      case M_in2name:        /* Create an IN2file name */
         if (*IN2PATH)
            cPathPointer = IN2PATH;
         else
            cPathPointer = INPATH;

         _splitpath(cPathPointer,drive,dir,fname,ext);
         strcat(dir,fname);

         if (*IN2NAME)
            cFnamePointer = IN2NAME;
         else
            cFnamePointer = INNAME;

         if (*IN2CLASS)
            cExtPointer = IN2CLASS;
         else
            cExtPointer = INCLASS;

         _makepath(cPointer,drive,dir,cFnamePointer,cExtPointer);
         break;
      case M_outname:        /* Create an OUTfile name */
         if (*OUTPATH)
            cPathPointer = OUTPATH;
         else
            cPathPointer = INPATH;

         _splitpath(cPathPointer,drive,dir,fname,ext);
         strcat(dir,fname);

         if (*OUTNAME)
            cFnamePointer = OUTNAME;
         else
            cFnamePointer = INNAME;

         if (*OUTCLASS)
            cExtPointer = OUTCLASS;
         else
            cExtPointer = INCLASS;

         _makepath(cPointer,drive,dir,cFnamePointer,cExtPointer);
         break;
      case M_tmpname:        /* Create a TEMPfile name */
         if (*OUTPATH)
            cPathPointer = OUTPATH;
         else
            cPathPointer = INPATH;

         _splitpath(cPathPointer,drive,dir,fname,ext);
         strcat(dir,fname);

         strcpy(fname,"DBA");
         switch (strlen(TASKNAME))  /* Grab part of TASKNAME */
            {
            case 1:
               fname[0] = fname[1] = TASKNAME[0];
               break;
            case 2:
               fname[0] = TASKNAME[0];
               fname[1] = TASKNAME[1];
            case 3:
               fname[0] = TASKNAME[1];
               fname[1] = TASKNAME[2];
               break;
            default:
               fname[0] = TASKNAME[2];
               fname[1] = TASKNAME[3];
            }

         strcat(fname,itoa(getpid(),PID,10));

         do {
            _makepath(cPointer,drive,dir,fname,".TMP");
            if (!access(cPointer,0))
               {
               zMessage(2,"%-8s: File '%s' Exists\n",TASKNAME,strupr(cPointer));
               ++fname[2];
               if (fname[2] == '[')
                  {
                  zMessage(255,"%-8s: Unable to Create Scratch File\n",TASKNAME);
                  _exit(1);   /* Kill Task */
                  }
               }
            }
         while (!access(cPointer,0));
         break;
         }
     return(strupr(cPointer));
     }

/*********************************************************************
*
*  Print a message based on its priority level and QUIET.
*
*/
short zMessage(LEVEL,FMT,...)
short LEVEL;
char *FMT;
   {
   short N;
   va_list arg_ptr;

   va_start(arg_ptr,FMT);
   LEVEL = abs(LEVEL);

   if (LEVEL>=(abs(QUIET)-1))
      {
      N = vprintf(FMT,arg_ptr);
      if (QUIET<0) vfprintf(stdprn,FMT,arg_ptr);
      if (LogStream) vfprintf(LogStream,FMT,arg_ptr);
      }

   va_end(arg_ptr);
   return(N);
   }

/*********************************************************************
*
*  Return the size of DATATYPE
*
*/
short zTypeSize(DATATYPE)
char DATATYPE;
   {
   short M=0;

   switch (DATATYPE)
      {
      case R_Data:
         M = sizeof(struct RData);
         break;
      case TR_Data:
         M = sizeof(struct TRData);
         break;
      case X_Data:
         M = sizeof(struct XData);
         break;
      case TX_Data:
         M = sizeof(struct TXData);
         break;
      }
   return(M);
   }

BOOL zIndexedRead(pFile, lIndex, pBuffer, cType)
struct FILESTRUCT *pFile;
long lIndex;
char *pBuffer;
char cType;
   {
   if (lIndex != -1L)
      {
      lIndex = (long)zTypeSize(cType) * lIndex +
               (long)sizeof(struct FILEHDR);
      if (lIndex < zFileSize(pFile))
         zFileSeek(pFile, lIndex, SEEK_SET);
      else
         {
         pFile->iEoF = 1;
         zFileSeek(pFile, 0L, SEEK_END);
         return(TRUE);
         }
      }
   zFileRead(pFile, (LPSTR)pBuffer, (long)zTypeSize(cType));
   return(pFile->iEoF ? TRUE : FALSE);
   }

BOOL zIndexedWrite(pFile, lIndex, pBuffer, cType)
struct FILESTRUCT *pFile;
long lIndex;
char *pBuffer;
char cType;
   {
   if (lIndex != -1L)
      {
      lIndex = (long)zTypeSize(cType) * lIndex +
               (long)sizeof(struct FILEHDR);
      if (lIndex < zFileSize(pFile))
         zFileSeek(pFile, lIndex, SEEK_SET);
      else
         {
         pFile->iEoF = 1;
         zFileSeek(pFile, 0L, SEEK_END);
         return(TRUE);
         }
      }
   zFileWrite(pFile, (LPSTR)pBuffer, (long)zTypeSize(cType));
   return(pFile->iEoF ? TRUE : FALSE);
   }

/* GENERAL FILE I/O ROUTINES
**
** Opens a disk file using massivly buffered I/O.
** File is a pointer to a FILESTRUCT.
** Fname is a pointer to a character string.
** iStyle is a combination of the OF_ styles
**   OF_READ
**   OF_WRITE
**   OF_READWRITE
**   OF_CREATE
** wBytes is the number of bytes to be allocated for the I/O buffer.
**   if wBytes is 0 then 32K is used.
** If the file is opened then a FALSE is returned.
** A return value of TRUE means
** that a buffer could not be allocated or the file could not
** be opened.
*/
BOOL zFileOpen(File, Fname, iStyle, wBytes)
struct FILESTRUCT *File;
char *Fname;
int iStyle;
WORD wBytes;
   {
   HANDLE hFile;
   WORD wMemSize;
   char *pStartMemory;

   File->bWriteOnly = (iStyle & (OF_READ | OF_WRITE | OF_READWRITE))
                       == OF_WRITE ? TRUE : FALSE;
   File->bReadOnly =  (iStyle & (OF_READ | OF_WRITE | OF_READWRITE))
                       == OF_READ ?  TRUE : FALSE;

   strcpy(File->OFstruct.szPathName,Fname);

   hFile = open(Fname, iStyle | O_BINARY, S_IREAD | S_IWRITE);
   if (hFile != OPENERROR)
      {
      wMemSize = wBytes ? wBytes : 32768;
      do {
         if (!(pStartMemory =
               (char *)malloc((size_t)wMemSize)))
            wMemSize /= 2;
         }
      while (!pStartMemory && wMemSize);

      if (!pStartMemory)
         {
         close(hFile);
         hFile = OPENERROR;
         Zencode(10,"%-8s: Can't Allocate Memory.\n", TASKNAME);
         }
      else
         {
         File->pCurrent = File->pStart = pStartMemory;
         File->wMemorySize = wMemSize;
         File->lBufferFilePos = 0L;
         File->wBytesInBuffer =
            File->bWriteOnly ? 0 : read(hFile, pStartMemory, wMemSize);
         if (File->wBytesInBuffer == IOERROR)
            {
            free(pStartMemory);
            close(hFile);
            hFile = OPENERROR;
            Zencode(10,"%-8s: Error Reading File.\n",TASKNAME);
            }
         else
            {
            File->hFile = hFile;
            File->bChanged = FALSE;
            }
         }
      }
   else
      Zencode(10,"%-8s: Can't Open File.\n",TASKNAME);

   if (hFile == OPENERROR)
      {
      Zencode(10,"%-8s: Error Opening File '%s'\n",
              TASKNAME,File->OFstruct.szPathName);
      return(TRUE);
      }
   else
      return(FALSE);
   }

long zFileTell(File)
struct FILESTRUCT *File;
   {
   long lPointer;
   lPointer = File->lBufferFilePos + (long)(File->pCurrent - File->pStart);
   return(lPointer);
   }

long zFileSeek(File, lOffset, iSeekOrigin)
struct FILESTRUCT *File;
long lOffset;
int iSeekOrigin;
   {
   WORD wRead;
   HANDLE hFile;
   long lStart, lEnd, lNew, lBuffer;

   File->iEoF = 0;

   lEnd = (lStart = File->lBufferFilePos) + (long)File->wBytesInBuffer;

   switch (iSeekOrigin)
      {
      case SEEK_SET:
         lNew = lOffset;
         break;
      case SEEK_CUR:
         lNew = File->lBufferFilePos +
               (long)(File->pCurrent - File->pStart) +
               lOffset;
         break;
      case SEEK_END:
         lBuffer = File->lBufferFilePos -
                  (lNew = filelength(File->hFile)) +
                   File->wBytesInBuffer;

         if (lBuffer > 0L) lNew += lBuffer;
         lNew += lOffset;
         break;
      default:
         lNew = -1L;
         File->iEoF = -1;
      }

   if ((lNew >= lStart) && (lNew < lEnd))
      File->pCurrent = File->pStart + (lNew - lStart);
   else if (lNew >= 0L)
      {
      hFile = File->hFile;
      if (hFile != OPENERROR)
         {
         if (File->bChanged)
            {
            lseek(hFile, File->lBufferFilePos, SEEK_SET);
            write(hFile, File->pStart, File->wBytesInBuffer);
            }

         File->wBytesInBuffer = 0;
         File->pCurrent = File->pStart;
         lseek(hFile, File->lBufferFilePos = lNew, SEEK_SET);

         wRead = File->bWriteOnly ?
                    0 : read(hFile, File->pStart, File->wMemorySize);
         if (wRead == IOERROR)
            {
            lNew = -1L;
            File->iEoF = -1;
            }
         else
            File->wBytesInBuffer = wRead;

         if (!File->hFile) close(hFile);

         File->bChanged = FALSE;
         }
      else
         {
         File->iEoF = -1;
         lNew = -1L;
         }
      }
   else
      {
      File->iEoF = -1;
      lNew = -1L;
      }

   return(lNew);
   }

WORD zFileGetChar(File)
struct FILESTRUCT *File;
   {
   WORD C;
   WORD wRead;
   HANDLE hFile;

   if (File->bWriteOnly)
      {
      File->iEoF = -1;
      return(0xFFFF);
      }

   File->iEoF = 0;
   if (((File->pCurrent - File->pStart) == File->wBytesInBuffer) &&
       eof(File->hFile))
      File->iEoF = eof(File->hFile);
   else
      {
      C = (WORD)*File->pCurrent;
      if (((++File->pCurrent - File->pStart) == File->wBytesInBuffer) &&
          (!eof(File->hFile)))
         {
/* Windows REOPEN
         if (!File->hFile)
            hFile = OpenFile((LPSTR)NULL,
                             (LPOFSTRUCT)&File->OFstruct,
                             OF_REOPEN | OF_READWRITE);
         else
*/
            hFile = File->hFile;
         if (hFile != OPENERROR)
            {
            if (File->bChanged)
               {
               lseek(hFile, File->lBufferFilePos, SEEK_SET);
               write(hFile, File->pStart, File->wBytesInBuffer);
               File->bChanged = FALSE;
               }
            else
               lseek(hFile,
                     File->lBufferFilePos + File->wBytesInBuffer,
                     SEEK_SET);
            File->pCurrent = File->pStart;
            File->lBufferFilePos += File->wBytesInBuffer;
            File->wBytesInBuffer = 0;
            wRead = read(hFile, File->pStart, File->wMemorySize);
            if (wRead == IOERROR)
               File->iEoF= -1;
            else
               {
               if (!(File->wBytesInBuffer = wRead)) File->iEoF = 1;
               }
            if (!File->hFile) close(hFile);
            }
         else
            File->iEoF = -1;
         }
      }
   return(C);
   }

BOOL zFilePutChar(File, C)
struct FILESTRUCT *File;
BYTE C;
   {
   WORD wRead;
   HANDLE hFile;

   if (File->bReadOnly)
      {
      File->iEoF = -1;
      return(TRUE);
      }

    File->iEoF = 0;
   *File->pCurrent = C;

   if ((++File->pCurrent - File->pStart) > File->wBytesInBuffer)
      ++File->wBytesInBuffer;

   File->bChanged = TRUE;

   if ((File->pCurrent - File->pStart) == File->wMemorySize)
      {
      File->bChanged = FALSE;
/* Windows REOPEN
      if (!File->hFile)
         hFile = OpenFile((LPSTR)NULL,
                          (LPOFSTRUCT)&File->OFstruct,
                          OF_REOPEN | OF_READWRITE);
      else
*/
         hFile = File->hFile;
      if (hFile != OPENERROR)
         {
         lseek(hFile, File->lBufferFilePos, SEEK_SET);
         write(hFile, File->pStart, File->wBytesInBuffer);
         File->lBufferFilePos += File->wBytesInBuffer;
         File->pCurrent = File->pStart;
         File->wBytesInBuffer = 0;
         wRead = File->bWriteOnly ?
                    0 : read(hFile, File->pStart, File->wMemorySize);
         if (wRead == IOERROR)
            File->iEoF = -1;
         else
            File->wBytesInBuffer = wRead;
         if (!File->hFile) close(hFile);
         }
      else
         File->iEoF = -1;
      }

   return(File->iEoF ? TRUE : FALSE);
   }

BOOL zFileClose(File, bRelease)
struct FILESTRUCT *File;
BOOL bRelease;
   {
   BOOL bReturn = FALSE;

   if (!File->pStart) return(TRUE);

   if (File->bChanged)
      {
/*
      if (!File->hFile)
         File->hFile = OpenFile((LPSTR)NULL,
                                (LPOFSTRUCT)&File->OFstruct,
                                OF_REOPEN | OF_READWRITE);
*/
      if (File->hFile != OPENERROR)
         {
         lseek(File->hFile, File->lBufferFilePos, SEEK_SET);
         write(File->hFile, File->pStart, File->wBytesInBuffer);
         }
      }
   free(File->pStart);
   if ((File->hFile != OPENERROR) && File->hFile)
      bReturn = close(File->hFile) ? TRUE : FALSE;
   else
      bReturn = TRUE;
   if (bRelease)
      {
/*
      LocalFree((HANDLE)File->pStart);
*/
      File->pStart = NULL;
      }
   File->hFile = 0;
   File->bChanged = FALSE;
   return(bReturn);
   }

long zFileRead(File, lpBuffer, lCount)
struct FILESTRUCT *File;
LPSTR lpBuffer;
long lCount;
   {
   long L;

   for (L = 0L; L < lCount; ++L, ++lpBuffer)
      {
      *lpBuffer = (char)zFileGetChar(File);
      if (File->iEoF)
         {
         if (File->iEoF == -1) L = -1L;
         break;
         }
      }
   return(L);
   }

long zFileWrite(File, lpBuffer, lCount)
struct FILESTRUCT *File;
LPSTR lpBuffer;
long lCount;
   {
   long L;

   for (L = 0L; L < lCount; ++L, ++lpBuffer)
      {
      if (zFilePutChar(File, (BYTE)*lpBuffer)) break;
      }

   return(L);
   }

/*
** FileGetLine will read at most wCount characters into
** lpBuffer upto the delimiter bChar.  The last character
** placed into lpBuffer is the null.  The number of non NULL bytes
** written into lpBuffer is returned.
** If the End of Line character is '\n' then a test
** for a '\r\n' pair is made and both are replaced
** with NULL if true.
*/
WORD zFileGetLine(File, lpBuffer, wCount, bChar)
struct FILESTRUCT *File;
LPSTR lpBuffer;
WORD wCount;
BYTE bChar;
   {
   WORD I = 0;
   WORD C;

   if (!lpBuffer) wCount = 0;

   while (((C = zFileGetChar(File)) != (WORD)bChar) && !File->iEoF)
      {
      if (I < wCount)
         {
         *(lpBuffer + I) = (char)C;
         ++I;
         }
      }
   if (lpBuffer)
      {
      if (I)
         {
         *(lpBuffer + (--I)) = '\0';
         if (I && (bChar == '\n') && (*(lpBuffer + (--I)) == '\r'))
            *(lpBuffer + I) = '\0';
         }
      else
         *lpBuffer = '\0';
      }

   return(I);
   }

long zFileSize(pFile)
struct FILESTRUCT *pFile;
   {
   long lLength, lBuffer;

   lBuffer = pFile->lBufferFilePos - (lLength = filelength(pFile->hFile)) +
             pFile->wBytesInBuffer;

   if (lBuffer > 0L) lLength += lBuffer;
   return(lLength);
   }