/***************************************************************************
 *                                                                         *
 *   SRCPRP.C                                                              *
 *                                                                         *
 *   Copyright (C) 1996-1997 Galacticomm, Inc.  All rights reserved.       *
 *                                                                         *
 *   This is the GCOMM.LIB routine for preparing a source file (or any     *
 *   other text file) for use with a specific platform.  It also contains  *
 *   all low-level functions for use by other external programs.           *
 *                                                                         *
 *                                           - C. Dunn 3/11/96             *
 *                                                                         *
 ***************************************************************************/
#include "gcomm.h"
#include "psrcprp.h"

#define FILREV "$Revision: 6 $"

static struct prdefines {          /*  internal #define info               */
     CHAR *define;                 /*  #define to search for               */
     CHAR *print;                  /*  What to replace it with             */
} *prdefines=NULL;

static INT Defines=0;              /*  Number of internal defines          */

static VOID
AddDefine(                         /*  Add a define to define table        */
CHAR *stg);                        /*  String (past define) to add         */

GBOOL
prpFile(                           /* prepare source file for make         */
const CHAR *srcfil,                /*   source (input) file name           */
const CHAR *dstfil,                /*   destination (output) file name     */
CHAR *tags)                        /*   comma-delimited list of tags       */
{
     INT pstatus;
     static struct prpblk prpblk;
     static INT recurs=0;

     if (recurs == 0 && !prpInit(srcfil,dstfil,tags,&prpblk)) {
          catastro("prpFile(): Unable to initialize!");
     }
     recurs++;
     while ((pstatus=prpReadLine(&prpblk)) != ENDFILE) {
          if (pstatus == PROCESS) {
               fprintf(prpblk.dstfp,"%s\n",prpblk.inbuf);
          }
     }
     recurs--;
     if (recurs == 0) {
          prpShutdown(&prpblk);
     }
     return(TRUE);
}

GBOOL                              /*   returns TRUE on successful init    */
prpInit(                           /* source preparation initialization    */
const CHAR *srcfil,                /*   source (input) file name           */
const CHAR *dstfil,                /*   destination (output) file name     */
CHAR *tags,                       /*   comma-delimited list of tags       */
struct prpblk *prpblk)             /*   preparation information block      */
{
     CHAR *ptr;

     setmem(prpblk,sizeof(struct prpblk),0);
     prpblk->output[prpblk->nstlvl]=TRUE;
     stlcpy(prpblk->srcfil,srcfil,MAXPATH);
     stlcpy(prpblk->dstfil,dstfil,MAXPATH);
     prpblk->stags=tags;
     if (sameas(prpblk->srcfil,prpblk->dstfil)) {
          return(FALSE);
     }
     if (tags == NULL) {
          return(FALSE);
     }
     if ((ptr=strtok(tags,",")) != NULL) {
          do {
               CHAR* cmdadd=alczer((strlen(ptr)*2)+2);
               sprintf(cmdadd,"%s %s",ptr,ptr);
               AddDefine(cmdadd);
               free(cmdadd);
          } while ((ptr=strtok(NULL,",")) != NULL);
     }
     if ((prpblk->srcfp=fopen(prpblk->srcfil,FOPRA)) == NULL
      || (prpblk->dstfp=fopen(prpblk->dstfil,FOPWA)) == NULL) {
          if (prpblk->srcfp != NULL) {
               fclose(prpblk->srcfp);
          }
          return(FALSE);
     }
     return(TRUE);
}

INT                                /*   return status codes                */
prpReadLine(                       /* read line from source file           */
struct prpblk *prpblk)             /*   preparation information block      */
{
     CHAR *ptr;
     FILE *savfil;
     CHAR tmp[BUFSIZ];

     setmem(tmp,BUFSIZ,0);
     if (fgets(tmp,BUFSIZ,prpblk->srcfp) == NULL) {
          return(ENDFILE);
     }
     depad(tmp);

     stlcpy(prpblk->inbuf,tmp,BUFSIZ);
     if (prpblk->inbuf[0] == '#') {
          if ((ptr=strstr(prpblk->inbuf,"ifdef")) != NULL) {
               ptr=skptwht(ptr+=strlen("ifdef"));
               prpblk->nstlvl++;
               if (prpblk->nstlvl == MAXNST) {
                    catastro("prpReadLine(): Too many nests!");
               }
               prpblk->output[prpblk->nstlvl]=
                (prpCheckTag(ptr) && prpblk->output[prpblk->nstlvl-1]);
               return(NOTMINE);
          }
          else if ((ptr=strstr(prpblk->inbuf,"ifndef")) != NULL) {
               ptr=skptwht(ptr+=strlen("ifndef"));
               prpblk->nstlvl++;
               if (prpblk->nstlvl == MAXNST) {
                    catastro("prpReadLine(): Too many nests!");
               }
               prpblk->output[prpblk->nstlvl]=(!(prpCheckTag(ptr)) &&
                prpblk->output[prpblk->nstlvl-1]);
               return(NOTMINE);
          }
     }

     // Now translate the #defines
     stlcpy(prpblk->inbuf,prpXlatEnv(tmp),BUFSIZ);
     if (prpblk->inbuf[0] == '#') {
          if ((ptr=strstr(prpblk->inbuf,"include")) != NULL) {
               ptr=skptwht(ptr+=strlen("include"));
               if (*ptr == '\"') {
                    ptr++;
               }
               if (strlen(ptr) > 0 && ptr[strlen(ptr)-1] == '\"') {
                    ptr[strlen(ptr)-1]='\0';
               }
               savfil=prpblk->srcfp;
               if ((prpblk->srcfp=fopen(ptr,FOPRA)) == NULL) {
                    catastro("Unable to open include file %s",ptr);
               }
               prpFile("","","");
               prpblk->srcfp=savfil;
               return(NOTMINE);
          }
          if ((ptr=strstr(prpblk->inbuf,"define")) != NULL) {
               if (prpblk->output[prpblk->nstlvl]) {
                    ptr=skptwht(ptr+=strlen("define"));
                    AddDefine(ptr);
               }
               return(NOTMINE);
          }
          else if ((ptr=strstr(prpblk->inbuf,"else")) != NULL) {
               prpblk->output[prpblk->nstlvl]=
                  (!(prpblk->output[prpblk->nstlvl])
                && prpblk->output[prpblk->nstlvl-1]);
               return(NOTMINE);
          }
          else if ((ptr=strstr(prpblk->inbuf,"endif")) != NULL) {
               prpblk->nstlvl--;
               return(NOTMINE);
          }
     }
     return(prpblk->output[prpblk->nstlvl] ? PROCESS : NOTMINE);
}

GBOOL                              /*   return TRUE if tag is ours         */
prpCheckTag(                       /* check to see if tag is in our list   */
const CHAR *tag)                   /*   tag to check                       */
{
     INT i;

     for (i=0; i < Defines; i ++) {
          if (sameas(prdefines[i].define,tag)) {
               return(TRUE);
          }
     }
     return(FALSE);
}

GBOOL                              /*   return FALSE if ifdef not endif'ed */
prpShutdown(                       /* source preparation shutdown          */
struct prpblk *prpblk)             /*   preparation information block      */
{
     fclose(prpblk->srcfp);
     fclose(prpblk->dstfp);
     if (prpblk->nstlvl != 0) {
          return(FALSE);
     }
     return(TRUE);
}

static VOID
AddDefine(                         /*  Add a define to define table        */
CHAR *stg)                         /*  String (past define) to add         */
{
     CHAR *replace;
     GBOOL newone=TRUE;
     UINT count;

     replace=itemidxd(stg,0," ");
     for (count=0; count < Defines; count ++) {
          if (sameas(prdefines[count].define,replace)) {
               newone=FALSE;
               break;
          }
     }

     if (newone) {
          prdefines=alcrsz(prdefines,sizeof(struct prdefines)*Defines,
           sizeof(struct prdefines)*(Defines+1));
          prdefines[Defines].define=strdup(itemidxd(stg,0," "));
     }
     else {
          free(prdefines[count].print);
     }

     replace=skpwht(skpwrd(stg));
     prdefines[Defines].print=strdup(replace);
     if (newone) {
          Defines++;
     }
}

CHAR *                             /*   returns converted buffer           */
prpXlatEnv(                        /* translate environment variables      */
CHAR *buffer)                      /*   buffer to translate                */
{
     CHAR *ptr,*begptr;
     CHAR cnvbuf[BUFSIZ];
     static CHAR savbuf[BUFSIZ];
     INT count;

     setmem(savbuf,BUFSIZ,0);
     setmem(cnvbuf,BUFSIZ,0);
     stlcpy(savbuf,buffer,BUFSIZ);
     ptr=savbuf;
     for (count=0; count < Defines; count ++) {
          while ((begptr=strstr(ptr,prdefines[count].define)) != NULL) {
               strncat(cnvbuf,ptr,(INT)(begptr-ptr));
               stlcat(cnvbuf,prdefines[count].print,BUFSIZ);
               ptr=begptr+strlen(prdefines[count].define);
          }
          stlcat(cnvbuf,ptr,BUFSIZ);
          stlcpy(savbuf,cnvbuf,BUFSIZ);
          setmem(cnvbuf,BUFSIZ,0);
          ptr=savbuf;
     }
     return(savbuf);
}

