/***************************************************************************
 *                                                                         *
 *   DFCVERIF.C                                                            *
 *                                                                         *
 *   Copyright (c) 1996-1997 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   Conversion file template verify routines.                             *
 *                                                                         *
 *                                           - Wally Muharsky 10/20/97     *
 *                                                                         *
 ***************************************************************************/
#include "gcomm.h"
#include "dfcverif.h"
#include "dfcapi2.h"

#define TYPSEP                "="

//Header information
#define DFCTMP_DESCRIPTION    "Description"
#define DFCTMP_DEVELOPER      "Developer"
#define DFCTMP_BEGINFILE      "BeginFile"
#define DFCTMP_ENDFILE        "EndFile"
#define DFCTMP_CONVERSION     "CustomConversion"
#define DFCTMP_ENDSTRUCT      "EndStruct"
#define DFCTMP_GENERIC        "Generic"
#define DFCTMP_MODULENAME     "ModuleName"
#define GENERIC_USERID        "GDBUIDFLD"
#define GENERIC_MODULE        "GDBMNMFLD"

/***************************************************************************
 * Global Variables                                                        *
 ***************************************************************************/

//  This structure should match up with the #define for
//  the DFC_ #defines for platforms in DFCAPI2.H
CHAR *Platforms[]={
     "DOS",
     "WNT"
};

struct cnvTypes ConversionTypes[]={
     {"CHAR",       DFCFLD_CHAR},
     {"SHORT",      DFCFLD_SHORT},
     {"LONG",       DFCFLD_LONG},
     {"FLOAT",      DFCFLD_FLOAT},
     {"DOUBLE",     DFCFLD_DOUBLE},
     {"OPAQUE",     DFCFLD_OPAQUE},
     {"STRUCT",     DFCFLD_STRUCT},
};

typedef struct tagPLATFORM {       /* Platform information holder          */
     INT Platform;                 /*  Specific platform holding for       */
     UINT nPlatformFiles;          /*  Number of files for platform        */
     GBOOL *Finished;              /*  Finished with each platform?        */
     pDFCFILE PlatformFiles;       /*  Pointer to platform files           */
     DFCFIELDINFO ** FieldInfo;    /*  Field info pointers for each file   */
} PLATFORM,*pPLATFORM;

static pPLATFORM pf=NULL;          /*  Pointer to platforms                */
static pDFCDATAFIELDS cdf;         /*  Pointer to current datafields       */
static pDFCFIELDINFO cfi;          /*  Pointer to current field info stuct */

static UINT npf=0;                 /*  Number of platforms                 */
static UINT ncfi=0;                /*  Number of current field info's      */

CHAR dfcbuf[DFCBUFSIZ];            /*  Internal buffer for reading file    */

INT LinesRead;                     /*  Number of lines read in file        */

/***************************************************************************
 * Variable Declarations                                                   *
 ***************************************************************************/
static GBOOL CanFree=FALSE;        /*  Can we free memory?                 */
static VOID **FreeList=NULL;       /*  Free pointer list                   */

static UINT nFreeList=0;           /*  Number of things in list            */

static FILE *filptr;               /*  Pointer to open template            */

DFCCVTFILE cf;                     /*  Current conversion file             */
static struct ffblk fbptr;         /*  Temporary fndblk pointer            */

/***************************************************************************
 * Function Declarations                                                   *
 ***************************************************************************/
static VOID
FlushFreeList(VOID);               /*  Flush the free pointer list         */

static VOID
AddToFreeList(                     /*  Add pointer to free list            */
VOID *ptr);                        /*  Pointer to add to list              */

static VOID
FreeCVT(VOID);                     /*  Free the DFCCVTFILE structure       */

static VOID
FreePlatform(VOID);                /*  Free current platform info          */

static GBOOL                       /*  TRUE/FALSE                          */
FreeAlready(                       /* Has this been freed already?         */
VOID *ptr);                        /*  Pointer to check on                 */

static INT                         /*  New data type                       */
ConvertToVariable(                 /* Convert data to variable format      */
INT CurrentType);                  /*  Current type of data                */

static GBOOL                       /*  TRUE if name exists                 */
NameExists(                        /* Check if name field exists           */
const CHAR *Name);                 /*  Name to check for                   */

static VOID
AddNewField(                       /*  Add new field information           */
const CHAR *Name,                  /*  Name of variable to add             */
INT Flags,                         /*  Flags for variable (#defines)       */
LONG MaxElems,                     /*  Maximum elements                    */
CHAR Pad);                         /*  Character to pad with               */

static VOID
AddNewFieldInfo(VOID);             /*  Adds a new field info structure     */

static VOID
MarkFinished(VOID);                /*  Mark files datafields as done       */

static VOID
CreateFileList(VOID);              /*  Create the files list               */

static VOID
FreeFileFields(                    /*  Free file fields                    */
pDFCFILE ff);                      /*  Pointer to file fields to free      */

static VOID
FreeDataFields(                    /*  Free all fields allocated           */
pDFCDATAFIELDS df);                /*  Pointer to datafield                */

static INT                         /*  Error number                        */
dfcErrorSet(                       /* Set Error with text                  */
INT Error,                         /*  Error number to return              */
const CHAR *stg);                  /*  Pointer to string to set or NULL    */

static VOID
ResizeFields(                      /* Resize the number of fields          */
DFCDATAFIELDS **cptr,              /*  Pointer to add datafields to        */
INT cnvs);                         /*  Number of elements in field now     */

static INT                         /*  DFC_SUCCESS or an error             */
ReadDataFields(                    /* Read all of the datafields           */
DFCDATAFIELDS **cptr,              /*  Pointer to add datafields to        */
GBOOL Structure);                  /*  Loading part of a structure?        */

static INT                         /*  DFC_SUCCESS or error                */
ReadPlatform(VOID);                /*  Read platform and file names        */

static GBOOL                       /*  TRUE if current line begins with    */
LineBegin(                         /* Check current line                   */
const CHAR *stg);                  /*  String to check against             */

static INT                         /*  Return codes                        */
CreateDFC(VOID);                   /* Create file DFC (if possible)        */

static INT                         /*  DFC_SUCCESS on success              */
ReadLine(VOID);                    /* Read a line from the template file   */

static INT                         /*  DFC_SUCCESS on success              */
ReadHeader(VOID);                  /*  Read the header                     */

static VOID
CheckAndFree(                      /* Check pointer for NULL and free      */
VOID **ptr);                       /*  Pointer to check                    */

static INT                         /*  Platform number or -1               */
PlatformNumber(                    /* Get platform number (if exists)      */
const CHAR *pstg);                 /*  Platform in string form             */

static VOID
AddToList(                         /*  Add to internal list of files       */
INT Platform,                      /*  Platform to add it to               */
const CHAR *File);                 /*  File to assign                      */

static INT                         /*  Type number or -1                   */
TypeNumber(                        /* Get type number given string         */
const CHAR *Type);                 /*  Pointer to type to find             */

/***************************************************************************
 * Source Code                                                             *
 ***************************************************************************/
MARKSOURCE(dfcverif);

static VOID
CheckAndFree(                      /* Check pointer for NULL and free      */
VOID **ptr)                        /*  Pointer to check                    */
{
     if (*ptr != NULL && !FreeAlready(*ptr)) {
          free(*ptr);
          AddToFreeList(*ptr);
          *ptr=NULL;
     }
}

INT                                /*  0 on success, other #defines on err */
dfcVerifyFile(                     /* Verify conversion template file      */
const CHAR *File)                  /*  File to verify                      */
{
     INT ans;

     if (CanFree) {
          return(dfcErrorSet(DFC_INITIALIZED,""));
     }
     CanFree=TRUE;
     if (!fndfile(&fbptr,File,0)) {
          return(dfcErrorSet(DFC_NOFILE,File));
     }
     if ((filptr=fopen(File,FOPRA)) == NULL) {
          return(dfcErrorSet(DFC_FILEOPEN,File));
     }
     setmem(&cf,sizeof(DFCCVTFILE),0);
     LinesRead=0;
     npf=0;
     ncfi=0;
     nFreeList=0;
     ans=CreateDFC();
     fclose(filptr);
     return(ans);
}

static INT                         /*  DFC_SUCCESS on success              */
ReadHeader(VOID)                   /*  Read the header                     */
{
     INT ans;

     while ((ans=ReadLine()) == DFC_SUCCESS) {
          if (LineBegin(DFCTMP_DESCRIPTION)) {
               if (cf.Description != NULL) {
                    return(dfcErrorSet(DFC_TWODESCRIPTIONS,""));
               }
               cf.Description=strdup(skpwht(skpwrd(dfcbuf)));
               continue;
          }
          if (LineBegin(DFCTMP_GENERIC)) {
               cf.Generic=TRUE;
               continue;
          }
          if (LineBegin(DFCTMP_MODULENAME)) {
               if (cf.ModuleName != NULL) {
                    return(dfcErrorSet(DFC_TWOMODULENAMES,""));
               }
               cf.ModuleName=strdup(skpwht(skpwrd(dfcbuf)));
               cf.Generic=TRUE;
               continue;
          }
          if (LineBegin(DFCTMP_DEVELOPER)) {
               if (cf.Developer != NULL) {
                    return(dfcErrorSet(DFC_TWODEVELOPERS,""));
               }
               cf.Developer=strdup(skpwht(skpwrd(dfcbuf)));
               continue;
          }
          if (LineBegin(DFCTMP_CONVERSION)) {
               if (cf.CustomProgram != NULL) {
                    return(dfcErrorSet(DFC_TWOCUSTOMCONVERTS,""));
               }
               cf.CustomProgram=strdup(skpwht(skpwrd(dfcbuf)));
               continue;
          }
          if (LineBegin(DFCTMP_BEGINFILE)) {
               break;
          }
          return(dfcErrorSet(DFC_UNKNOWNTEXT,NULL));
     }
     if (ans == DFC_ENDOFFILE) {
          ans=DFC_NOBEGINFILE;
     }
     return(ans);
}

static GBOOL                       /*  TRUE if current line begins with    */
LineBegin(                         /* Check current line                   */
const CHAR *stg)                   /*  String to check against             */
{
     return(sameto(stg,dfcbuf));
}

static INT                         /*  DFC_SUCCESS on success              */
ReadLine(VOID)                     /* Read a line from the template file   */
{
     CHAR *ptr;

     while (TRUE) {
          setmem(dfcbuf,DFCBUFSIZ,0);
          if (fgets(dfcbuf,DFCBUFSIZ,filptr) == NULL) {
               return(dfcErrorSet(DFC_ENDOFFILE,""));
          }
          if (strlen(dfcbuf) >= DFCBUFSIZ-1) {
               return(dfcErrorSet(DFC_BUFFERSIZE,""));
          }
          if ((ptr=strchr(dfcbuf,DFC_REMARK)) != NULL) {
               *ptr='\0';
          }
          depad(dfcbuf);
          LinesRead++;
          ptr=skpwht(dfcbuf);
          if (strlen(ptr) == 0) {
               continue;
          }
          movmem(ptr,dfcbuf,strlen(ptr)+1);
          break;
     }
     return(dfcErrorSet(DFC_SUCCESS,""));
}

static INT                         /*  DFC_SUCCESS or error                */
ReadPlatform(VOID)                 /*  Read platform and file names        */
{
     INT count;
     CHAR *ptr;
     INT Platform;
     CHAR *ptr2;

     ptr=skpwht(skpwrd(dfcbuf));
     if (itemcntd(ptr,",")%2 != 0) {
          return(dfcErrorSet(DFC_BEGINARGS,NULL));
     }
     for (count=0; count < itemcntd(ptr,","); count+=2) {
          ptr2=itemidxd(ptr,count,",");
          if ((Platform=PlatformNumber(ptr2)) == DFC_END) {
               return(dfcErrorSet(DFC_INVALIDPLATFORM,ptr2));
          }
          ptr2=itemidxd(ptr,count+1,",");
          if (!isvalfn(ptr2)) {
               return(dfcErrorSet(DFC_INVALIDFILENAME,ptr2));
          }
          if (samein(".",ptr2)) {
               return(dfcErrorSet(DFC_INVALIDFILEFORMAT,ptr2));
          }
          AddToList(Platform,ptr2);
     }
     return(dfcErrorSet(DFC_SUCCESS,""));
}

static VOID
AddToList(                         /*  Add to internal list of files       */
INT Platform,                      /*  Platform to add it to               */
const CHAR *File)                  /*  File to assign                      */
{
     INT count;
     INT tolist=-1;
     pDFCFILE pd;

     for (count=0; count < npf; count ++) {
          if (pf[count].Platform == Platform) {
               tolist=count;
               break;
          }
     }
     if (tolist == -1) {
          pf=(pPLATFORM)alcrsz(pf,(npf*sizeof(PLATFORM)),
           ((npf+1)*sizeof(PLATFORM)));
          tolist=npf;
          setmem(&pf[tolist],sizeof(PLATFORM),0);
          npf++;
     }
     pf[tolist].Platform=Platform;
     pf[tolist].PlatformFiles=(pDFCFILE)alcrsz(pf[tolist].PlatformFiles,
      (pf[tolist].nPlatformFiles*sizeof(DFCFILE)),
      ((pf[tolist].nPlatformFiles+1)*sizeof(DFCFILE)));

     pf[tolist].Finished=(GBOOL *)alcrsz(pf[tolist].Finished,
      (pf[tolist].nPlatformFiles*sizeof(GBOOL)),
      ((pf[tolist].nPlatformFiles+1)*sizeof(GBOOL)));

     pf[tolist].FieldInfo=(DFCFIELDINFO**)alcrsz(pf[tolist].FieldInfo,
      (pf[tolist].nPlatformFiles*sizeof(pDFCFIELDINFO)),
      ((pf[tolist].nPlatformFiles+1)*sizeof(pDFCFIELDINFO)));

     pf[tolist].Finished[pf[tolist].nPlatformFiles]=FALSE;
     pd=&pf[tolist].PlatformFiles[pf[tolist].nPlatformFiles];
     setmem(pd,sizeof(DFCFILE),0);
     stlcpy(pd->Name,File,GCMAXPTH);
     pd->cnvfunc=NULL;
     pd->cnvfields=NULL;
     cdf=pd->cnvfields;
     cfi=pf[tolist].FieldInfo[pf[tolist].nPlatformFiles]=NULL;
     ncfi=0;
     pf[tolist].nPlatformFiles++;
}

static INT                         /*  Platform number or -1               */
PlatformNumber(                    /* Get platform number (if exists)      */
const CHAR *pstg)                  /*  Platform in string form             */
{
     INT count;

     for (count=0; count < DFC_PLATFORMS; count++) {
          if (sameas(Platforms[count],pstg)) {
               return(count);
          }
     }
     return(DFC_END);
}

static INT                         /*  Return codes                        */
CreateDFC(VOID)                    /* Create file DFC (if possible)        */
{
     INT ans;

     if ((ans=ReadHeader()) != DFC_SUCCESS) {
          if (cf.Developer == NULL) {
               return(dfcErrorSet(DFC_NODEVELOPER,""));
          }
          if (cf.Description == NULL) {
               return(dfcErrorSet(DFC_NODESCRIPTION,""));
          }
          if (ans == DFC_NOBEGINFILE && cf.CustomProgram != NULL) {
               if (!fndfile(&fbptr,cf.CustomProgram,0)) {
                    return(dfcErrorSet(DFC_CUSTOMNOTFOUND,cf.CustomProgram));
               }
               return(dfcErrorSet(DFC_SUCCESS,""));
          }
          return(ans);
     }
     while (TRUE) {
          if ((ans=ReadPlatform()) != DFC_SUCCESS) {
               return(ans);
          }
          if ((ans=ReadDataFields(&cdf,FALSE)) != DFC_SUCCESS) {
               return(ans);
          }
          MarkFinished();
          while ((ans=ReadLine()) == DFC_SUCCESS) {
               if (LineBegin(DFCTMP_BEGINFILE)) {
                    break;
               }
               return(dfcErrorSet(DFC_UNKNOWNTEXT,NULL));
          }
          if (ans == DFC_ENDOFFILE) {
               CreateFileList();
               return(dfcErrorSet(DFC_SUCCESS,""));
          }
     }
}

static INT                         /*  DFC_SUCCESS or an error             */
ReadDataFields(                    /* Read all of the datafields           */
DFCDATAFIELDS **cptr,              /*  Pointer to add datafields to        */
GBOOL Structure)                   /*  Loading part of a structure?        */
{
     INT ans;
     CHAR *ptr;
     CHAR *ptr2;
     INT cnvs=0;
     INT Flags;
     pDFCDATAFIELDS df=NULL;
     CHAR Pad;
     LONG MaxElems;

     if (!Structure && cf.Generic) {
          ResizeFields(cptr,cnvs);
          stlcpy((*cptr)[cnvs].Name,GENERIC_USERID,DFC_NAMSIZ);
          (*cptr)[cnvs].Type=DFCFLD_CHAR;
          (*cptr)[cnvs].nelems=30;
          AddNewField(GENERIC_USERID,0,0,0);
          cnvs++;
          ResizeFields(cptr,cnvs);
          stlcpy((*cptr)[cnvs].Name,GENERIC_MODULE,DFC_NAMSIZ);
          (*cptr)[cnvs].Type=DFCFLD_CHAR;
          (*cptr)[cnvs].nelems=25;
          AddNewField(GENERIC_MODULE,0,0,0);
          cnvs++;
     }
     ResizeFields(cptr,cnvs);
     (*cptr)[cnvs].Type=DFCFLD_END;

     while ((ans=ReadLine()) == DFC_SUCCESS) {
          Flags=0;
          Pad=0;
          MaxElems=0;
          if (LineBegin(DFCTMP_ENDFILE)) {
               if (Structure) {
                    return(dfcErrorSet(DFC_NOENDSTRUCTURE,""));
               }
               break;
          }
          if (Structure && LineBegin(DFCTMP_ENDSTRUCT)) {
               break;
          }
          ResizeFields(cptr,cnvs+1);
          movmem(&((*cptr)[cnvs]),&((*cptr)[cnvs+1]),sizeof(DFCDATAFIELDS));
          (*cptr)[cnvs].Type=(UINT)-1;

          ptr=firstwd(dfcbuf);
          if (strlen(ptr) == 0 || strlen(ptr) >= DFC_NAMSIZ) {
               return(dfcErrorSet(DFC_INVALIDFIELDNAME,ptr));
          }
          if (NameExists(ptr)) {
               return(dfcErrorSet(DFC_FIELDNAMEEXISTS,ptr));
          }
          stlcpy((*cptr)[cnvs].Name,ptr,DFC_NAMSIZ);

          for (ptr=nextwd(); *ptr != '\0'; ptr=nextwd()) {
               if (!sameas(ptr,"VARIABLE") && itemcntd(ptr,TYPSEP) != 2) {
                    return(dfcErrorSet(DFC_INVALIDPARAMATER,ptr));
               }
               ptr2=itemidxd(ptr,0,TYPSEP);
               if (sameas(ptr2,"TYPE")) {
                    if ((*cptr)[cnvs].Type != (UINT)-1) {
                         return(dfcErrorSet(DFC_TYPEDEFINED,NULL));
                    }
                    ptr2=itemidxd(ptr,1,TYPSEP);
                    if (((*cptr)[cnvs].Type=TypeNumber(ptr2)) == (UINT)-1) {
                         return(dfcErrorSet(DFC_INVALIDTYPE,ptr2));
                    }
                    continue;
               }
               if ((*cptr)[cnvs].Type == (UINT)-1) {
                    return(dfcErrorSet(DFC_PARAMBEFORETYPE,NULL));
               }
               if (sameas(ptr,"VARIABLE")) {
                    Flags|=DFCFIELD_VARIABLE;
/*                    if ((*cptr)[cnvs].Type == DFCFLD_STRUCT) {
                         return(dfcErrorSet(DFC_VARIABLE_STRUCT,dfcbuf));
                    }*/
                    if ((*cptr)[cnvs].nelems == 0) {
                         return(dfcErrorSet(DFC_VARIABLE_LAST,dfcbuf));
                    }
                    MaxElems=(*cptr)[cnvs].nelems;
                    (*cptr)[cnvs].Type=ConvertToVariable((*cptr)[cnvs].Type);
                    continue;
               }
               if (sameas(ptr2,"ELEMS")) {
                    if ((*cptr)[cnvs].nelems != 0) {
                         return(dfcErrorSet(DFC_ELEMENTSDEFINED,NULL));
                    }
                    ptr2=itemidxd(ptr,1,TYPSEP);
                    if (((*cptr)[cnvs].nelems=atoi(ptr2)) < 1) {
                         return(dfcErrorSet(DFC_INVALIDELEMENTS,NULL));
                    }
                    continue;
               }
               if ((*cptr)[cnvs].Type == DFCFLD_CHAR ||
                (*cptr)[cnvs].Type == DFCFLD_OPAQUE) {
                    if (sameas(ptr2,"JUSTIFY")) {
                         if (Flags&DFCFIELD_JUSTIFY_RIGHT ||
                             Flags&DFCFIELD_JUSTIFY_LEFT) {
                              return(dfcErrorSet(DFC_JUSTIFYSET,dfcbuf));
                         }
                         if (Flags&DFCFIELD_TRUNCATE_LEFT ||
                             Flags&DFCFIELD_TRUNCATE_RIGHT) {
                              return(dfcErrorSet(DFC_JUSTIFYTRUNCATE,dfcbuf));
                         }
                         ptr2=itemidxd(ptr,1,TYPSEP);
                         if (sameas(ptr2,"LEFT")) {
                              Flags|=DFCFIELD_JUSTIFY_LEFT;
                              continue;
                         }
                         if (sameas(ptr2,"RIGHT")) {
                              Flags|=DFCFIELD_JUSTIFY_RIGHT;
                              continue;
                         }
                         return(dfcErrorSet(DFC_UNKNOWNJUSTIFY,ptr2));
                    }
                    if (sameas(ptr2,"TRUNCATE")) {
                         if (Flags&DFCFIELD_TRUNCATE_RIGHT ||
                             Flags&DFCFIELD_TRUNCATE_LEFT) {
                              return(dfcErrorSet(DFC_TRUNCATESET,dfcbuf));
                         }
                         if (Flags&DFCFIELD_JUSTIFY_LEFT ||
                             Flags&DFCFIELD_JUSTIFY_RIGHT) {
                              return(dfcErrorSet(DFC_JUSTIFYTRUNCATE,dfcbuf));
                         }
                         ptr2=itemidxd(ptr,1,TYPSEP);
                         if (sameas(ptr2,"LEFT")) {
                              Flags|=DFCFIELD_TRUNCATE_LEFT;
                              continue;
                         }
                         if (sameas(ptr2,"RIGHT")) {
                              Flags|=DFCFIELD_TRUNCATE_RIGHT;
                              continue;
                         }
                         return(dfcErrorSet(DFC_UNKNOWNTRUNCATE,ptr2));
                    }
                    if (sameas(ptr2,"PAD")) {
                         if (!(Flags&DFCFIELD_JUSTIFY_RIGHT) ||
                          !(Flags&DFCFIELD_JUSTIFY_LEFT)) {
                              return(dfcErrorSet(DFC_PADBEFOREJUSTIFY,dfcbuf));
                         }
                         ptr2=itemidxd(ptr,1,TYPSEP);
                         if (atoi(ptr2) < 0 || atoi(ptr2) > 255) {
                              return(dfcErrorSet(DFC_INVALIDPADVALUE,dfcbuf));
                         }
                         Pad=atoi(ptr2);
                         continue;
                    }
               }
               return(dfcErrorSet(DFC_INVALIDPARAMATER,ptr2));
          }
          if ((*cptr)[cnvs].Type == (UINT)-1) {
               return(dfcErrorSet(DFC_NOTYPEDEFINED,NULL));
          }
          if ((*cptr)[cnvs].nelems == 0) {
               (*cptr)[cnvs].nelems=1;
          }
          AddNewField((*cptr)[cnvs].Name,Flags,MaxElems,Pad);
          if ((*cptr)[cnvs].Type == DFCFLD_STRUCT ||
           (*cptr)[cnvs].Type == DFCFLD_VSTRUCT) {
               ans=ReadDataFields(&df,TRUE);
               if (ans != DFC_SUCCESS) {
                    return(ans);
               }
               (*cptr)[cnvs].substruct=df;
          }
          cnvs++;
     }
     if (cnvs == 0) {
          return(dfcErrorSet((Structure == TRUE ? DFC_NULLSTRUCT : DFC_NULLFILE),""));
     }
     if (ans != DFC_SUCCESS) {
          return(ans);
     }
     if (!Structure) {
          AddNewField("",0,0,0);
     }
     return(dfcErrorSet(DFC_SUCCESS,""));
}

static VOID
ResizeFields(                      /* Resize the number of fields          */
DFCDATAFIELDS **cptr,              /*  Pointer to add datafields to        */
INT cnvs)                          /*  Number of elements in field now     */
{
     (*cptr)=(pDFCDATAFIELDS)alcrsz((*cptr),(cnvs*sizeof(DFCDATAFIELDS)),
      ((cnvs+1)*sizeof(DFCDATAFIELDS)));

     setmem(&((*cptr)[cnvs]),sizeof(DFCDATAFIELDS),0);
     (*cptr)[cnvs].Type=(UINT)-1;
}

static INT                         /*  Type number or -1                   */
TypeNumber(                        /* Get type number given string         */
const CHAR *Type)                  /*  Pointer to type to find             */
{
     INT count;

     for (count=0; count < CNV_TYPES; count ++) {
          if (sameas(ConversionTypes[count].Type,Type)) {
               return(ConversionTypes[count].cnvType);
          }
     }
     return(-1);
}

CHAR *                             /*  Pointer to error string             */
dfcErrorStg(                       /* Get meaning given error number       */
INT ErrorNumber)                   /*  Error number to search for          */
{
     switch (ErrorNumber) {
     case DFC_SUCCESS:
          return("Conversion template ok");
     case DFC_NOFILE:
          return("File not found");
     case DFC_FILEOPEN:
          return("Unable to open file");
     case DFC_ENDOFFILE:
          return("End of file error");
     case DFC_BUFFERSIZE:
          return("Line greater than 2000 bytes");
     case DFC_TWODESCRIPTIONS:
          return("Template has 2 \"Description:\" lines");
     case DFC_TWOCUSTOMCONVERTS:
          return("Template has 2 \"CustomProgram:\" lines");
     case DFC_TWODEVELOPERS:
          return("Template has 2 \"Developer:\" lines");
     case DFC_NOBEGINFILE:
          return("No \"BeginFile:\" found");
     case DFC_UNKNOWNTEXT:
          return("Unknown text");
     case DFC_CUSTOMNOTFOUND:
          return("Custom program not found");
     case DFC_BEGINARGS:
          return("Invalid amount of arguments on \"BeginFile:\" line.\n"
           "Arguments must be divisible by 2");
     case DFC_INVALIDPLATFORM:
          return("Invalid platform type on \"BeginFile:\" line");
     case DFC_INVALIDFILENAME:
          return("Invalid file name on \"BeginFile:\" line");
     case DFC_INVALIDFILEFORMAT:
          return("Filename should not have a \".\".  "
           "\".DAT\" and \".VIR\" are assumed");
     case DFC_INVALIDFIELDNAME:
          return("Field name error. Size must be > 0 and < 20");
     case DFC_FIELDNAMEEXISTS:
          return("Field name exists more than once");
     case DFC_INVALIDTYPE:
          return("Field name has invalid type");
     case DFC_INVALIDPARAMATER:
          return("Unrecognized field paramater");
     case DFC_TYPEDEFINED:
          return("Two \"TYPE=\" paramaters encountered for one field");
     case DFC_PARAMBEFORETYPE:
          return("Paramater encountered before \"TYPE=\"");
     case DFC_ELEMENTSDEFINED:
          return("Field type defined more than once");
     case DFC_INVALIDELEMENTS:
          return("Number of elements has to be > 0");
     case DFC_NOENDSTRUCTURE:
          return("\"TYPE=STRUCT\" Encountered with no \"EndStruct\"");
     case DFC_NODEVELOPER:
          return("\"Developer:\" not found");
     case DFC_NODESCRIPTION:
          return("\"Description:\" not found");
     case DFC_NULLFILE:
          return("No elements between \"BeginFile\" and \"EndFile\"");
     case DFC_NULLSTRUCT:
          return("No elements between \"TYPE=STRUCT\" and \"EndStruct\"");
     case DFC_NOTYPEDEFINED:
          return("No TYPE= for data field");
     case DFC_INITIALIZED:
          return("dfcVerifyFree() was never called"); 
     case DFC_JUSTIFYTRUNCATE:
          return("TRUNCATE and JUSTIFY can not both be used for a field");
     case DFC_JUSTIFYSET:
          return("JUSTIFY already set");
     case DFC_TRUNCATESET:
          return("TRUNCATE already set");
     case DFC_UNKNOWNJUSTIFY:
          return("JUSTIFY command unknown");
     case DFC_UNKNOWNTRUNCATE:
          return("TRUNCATE command unknown");
     case DFC_PADBEFOREJUSTIFY:
          return("PAD field encountered before JUSTIFY");
     case DFC_INVALIDPADVALUE:
          return("Invalid pad value");
     case DFC_VARIABLE_LAST:
          return("VARIABLE needs to be after ELEMS");
     case DFC_VARIABLE_STRUCT:
          return("Can not have VARIABLE structures");
     case DFC_TWOMODULENAMES:
          return("Two ModuleNames defined");
     default:
          return(spr("Unknown error #%d",ErrorNumber));
     }
}

static INT                         /*  Error number                        */
dfcErrorSet(                       /* Set Error with text                  */
INT Error,                         /*  Error number to return              */
const CHAR *stg)                   /*  Pointer to string to set or NULL    */
{
     if (Error != DFC_SUCCESS && stg != NULL) {
          stlcpy(dfcbuf,stg,DFCBUFSIZ);
     }
     return(Error);
}

static VOID
CreateFileList(VOID)               /*  Create the files list               */
{
     UINT count;

     cf.fillst=(pDFCLIST)alczer(sizeof(DFCLIST)*(npf+1));
     for (count=0; count < npf; count++) {
          cf.fillst[count].Platform=pf[count].Platform;
          AddToList(cf.fillst[count].Platform,"");
          cf.fillst[count].file=pf[count].PlatformFiles;
     }
     cf.fillst[npf].Platform=DFC_END;
}

static VOID
MarkFinished(VOID)                 /*  Mark files datafields as done       */
{
     UINT count;
     UINT count2;
     for (count=0; count < npf; count++) {
          for (count2=0; count2 < pf[count].nPlatformFiles; count2++) {
               if (!pf[count].Finished[count2]) {
                    pf[count].Finished[count2]=TRUE;
                    pf[count].PlatformFiles[count2].cnvfields=cdf;
                    pf[count].FieldInfo[count2]=cfi;
               }
          }
     }
     cfi=NULL;
     cdf=NULL;
}

static VOID
AddNewFieldInfo(VOID)              /*  Adds a new field info structure     */
{
     cfi=(pDFCFIELDINFO)alcrsz(cfi,ncfi*sizeof(DFCFIELDINFO),
      (ncfi+1)*sizeof(DFCFIELDINFO));
     setmem(&cfi[ncfi],sizeof(DFCFIELDINFO),0);
     ncfi++;
}

static VOID
AddNewField(                       /*  Add new field information           */
const CHAR *Name,                  /*  Name of variable to add             */
INT Flags,                         /*  Flags for variable (#defines)       */
LONG MaxElems,                     /*  Maximum elements                    */
CHAR Pad)                          /*  Character to pad with               */
{
     AddNewFieldInfo();
     stlcpy(cfi[ncfi-1].Name,Name,DFC_NAMSIZ);
     cfi[ncfi-1].Flags=Flags;
     cfi[ncfi-1].MaxElems=MaxElems;
     cfi[ncfi-1].Pad=Pad;
}

static GBOOL                       /*  TRUE if name exists                 */
NameExists(                        /* Check if name field exists           */
const CHAR *Name)                  /*  Name to check for                   */
{
     INT count;

     for (count=0; count < ncfi; count ++) {
          if (sameas(cfi[count].Name,Name)) {
               return(TRUE);
          }
     }
     return(FALSE);
}

pDFCFIELDINFO                      /*  Pointer to datafield                */
dfcGetFieldInfo(                   /* Get field information                */
INT Platform,                      /*  Platform (DOS/WNT)                  */
const CHAR *FileName,              /*  Name of the datafile                */
const CHAR *ItemName)              /*  Name of the item to search for      */
{
     INT count;
     INT count2;
     INT count3;

     for (count=0; count < npf; count++) {
          if (Platform == pf[count].Platform) {
               for (count2=0; count2 < pf[count].nPlatformFiles; count2++) {
                    if (sameas(pf[count].PlatformFiles[count2].Name,FileName)) {
                         count3=0;
                         while (strlen((pf[count].FieldInfo[count2])[count3].Name) > 0) {
                              if (sameas((pf[count].FieldInfo[count2])[count3].Name,ItemName)) {
                                   return(&((pf[count].FieldInfo[count2])[count3]));
                              }
                              count3++;
                         }
                    }
               }
          }
     }
     return(NULL);
}

static INT                         /*  New data type                       */
ConvertToVariable(                 /* Convert data to variable format      */
INT CurrentType)                   /*  Current type of data                */
{
     if (CurrentType == DFCFLD_CHAR)    return(DFCFLD_VCHAR);
     if (CurrentType == DFCFLD_SHORT)   return(DFCFLD_VSHORT);
     if (CurrentType == DFCFLD_LONG)    return(DFCFLD_VLONG);
     if (CurrentType == DFCFLD_FLOAT)   return(DFCFLD_VFLOAT);
     if (CurrentType == DFCFLD_DOUBLE)  return(DFCFLD_VDOUBLE);
     if (CurrentType == DFCFLD_OPAQUE)  return(DFCFLD_VOPAQUE);
     if (CurrentType == DFCFLD_STRUCT)  return(DFCFLD_VSTRUCT);
     return(0);     //  This can not happen
}


VOID
dfcVerifyFree(VOID)                /*  Free up everything allocated        */
{
     if (!CanFree) {
          return;
     }
     CanFree=FALSE;
     FreePlatform();
     FreeCVT();
     FlushFreeList();
}

static VOID
FreeCVT(VOID)                      /*  Free the DFCCVTFILE structure       */
{
     CheckAndFree((VOID**)&cf.Description);
     CheckAndFree((VOID**)&cf.Developer);
     CheckAndFree((VOID**)&cf.CustomProgram);
     CheckAndFree((VOID**)&cf.fillst);
     CheckAndFree((VOID**)&cf.ModuleName);
     setmem(&cf,sizeof(DFCCVTFILE),0);
}

static VOID
FreePlatform(VOID)                 /*  Free current platform info          */
{
     INT count;

     if (npf == 0) {
          return;
     }
     for (count=0; count < npf; count ++) {
          CheckAndFree((VOID**)&pf[count].Finished);
          CheckAndFree((VOID**)&pf[count].FieldInfo);
          if (!FreeAlready(pf[count].PlatformFiles)) {
               FreeFileFields(pf[count].PlatformFiles);
          }
     }
     CheckAndFree((VOID**)&pf);
}

static VOID
AddToFreeList(                     /*  Add pointer to free list            */
VOID *ptr)                         /*  Pointer to add to list              */
{
     FreeList=(VOID**)alcrsz(FreeList,nFreeList*sizeof(VOID*),
      (nFreeList+1)*sizeof(VOID*));
     FreeList[nFreeList]=ptr;
     nFreeList++;
}

static GBOOL                       /*  TRUE/FALSE                          */
FreeAlready(                       /* Has this been freed already?         */
VOID *ptr)                         /*  Pointer to check on                 */
{
     INT count;

     for (count=0; count < nFreeList; count++) {
          if (FreeList[count] == ptr) {
               return(TRUE);
          }
     }
     return(FALSE);
}

static VOID
FreeFileFields(                    /*  Free file fields                    */
pDFCFILE ff)                       /*  Pointer to file fields to free      */
{
     pDFCFILE curf=ff;

     while (strlen(ff->Name) != 0) {
          if (ff->cnvfields != NULL && !FreeAlready(ff->cnvfields)) {
               FreeDataFields(ff->cnvfields);
          }
          ff++;
     }
     CheckAndFree((VOID**)&curf);
}

static VOID
FlushFreeList(VOID)                /*  Flush the free pointer list         */
{
     if (FreeList != NULL) {
          free(FreeList);
          FreeList=NULL;
     }
}

static VOID
FreeDataFields(                    /*  Free all fields allocated           */
pDFCDATAFIELDS df)                 /*  Pointer to datafield                */
{
     pDFCDATAFIELDS curdf=df;

     while (df->Type != DFCFLD_END) {
          if (df->substruct != NULL && !FreeAlready(df->substruct)) {
               FreeDataFields(df->substruct);
          }
          df++;
     }
     CheckAndFree((VOID**)&curdf);
}

