/***************************************************************************
 *                                                                         *
 *   WGSUVER.C                                                             *
 *                                                                         *
 *   Copyright (c) 1995-1997 Galacticomm, Inc.  All rights reserved.       *
 *                                                                         *
 *   This utility updates the version codes for specified apps in .MDF     *
 *   files, as well as updating any and all related support files.         *
 *                                                                         *
 *                                                - C. Dunn 1/4/95         *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "majorbbs.h"
#include "math.h"
#include "process.h"
#include "excphand.h"

#define FILREV "$Revision: 3 $"

#define VCDSIZ 5                   /* maximum length of version code       */
#define MINSTR "MINOR"             /* minor upgrade version string         */
#define MAJSTR "MAJOR"             /* major upgrade version string         */
#define APPVER "Client app version:" /* MDF file prefix for app version    */
#define CLIEXE "Client app EXE:"   /* MDF file prefix for app file name    */
#define CLISUP "Client app support files:" /* MDF prefix for support files */
#define WRKFIL "WGSUVER.$$$"       /* temporary work file name             */
#define CMPPRG "WGSINCCF.EXE"      /* compress program file name           */
#define INCDIR "WGMINST\\INCLUDE"  /* "include" directory for apps         */
#define DELIMS ", \t;"             /* valid delimiters for DLL & EXE lists */

                                   /* version update control codes         */
#define MINOR  0                   /*   minor upgrade                      */
#define MAJOR  1                   /*   major upgrade                      */
#define MANUAL 2                   /*   manual (specified) upgrade         */

CHAR vercod[VCDSIZ];               /* specified version to update to       */
CHAR wrkbuf[MAXTFS];               /* work buffer for tfsbuf               */

GBOOL cmpfil;                      /* compress updated file?               */

INT updmth;                        /* version update method                */

CHAR *cnv2is(CHAR *filnam);
static VOID updapp(CHAR *appnam);
static GBOOL valver(CHAR *ver);
static GBOOL valfmt(CHAR *filnam);
static VOID updver(VOID);
static VOID updfver(CHAR *filnam);
static VOID updsver(CHAR *filnms);
static VOID fixver(CHAR *ver,GBOOL remove);
static VOID movfil(CHAR *srcfil,CHAR *dstfil);
static VOID prcfil(CHAR *filnam);
static VOID fmtver(CHAR *curver);
static CHAR *makwld(CHAR *filnam);

INT
main(                              /* main program loop                    */
INT argc,                          /*   number of command line arguments   */
CHAR *argv[])                      /*   array of command line arguments    */
{
TRY

     initvid();
     setatr(0x0A);
     printf("\n");
     printf("WGSUVER - Client App Version Control Utility\n");
     printf("Copyright (c) 1995-1997 Galacticomm, Inc.  All rights reserved.\n\n");
     if (argc != 3) {
          belper(800);
          setatr(0x0D);
          printf("\7");
          printf("     Usage: WGSUVER App-ID <version>|MINOR|MAJOR\n\n");
          setatr(0x0E);
          printf("     App-ID    - Application to update.\n");
          printf("     <version> - Specified new version code.\n");
          printf("     MINOR     - Minor upgrade (adds .01)\n");
          printf("     MAJOR     - Major upgrade (round to next .1)\n\n");
          printf("     Example: WGSUVER GALFIL 1.00\n");
          setatr(0x07);
          printf("\r");
          return(1);
     }
     if (sameas(argv[2],MINSTR)) {
          updmth=MINOR;
          fmtver(scnmdf(spr("%s.MDF",fnmcse(argv[1])),APPVER));
     }
     else if (sameas(argv[2],MAJSTR)) {
          updmth=MAJOR;
          fmtver(scnmdf(spr("%s.MDF",fnmcse(argv[1])),APPVER));
     }
     else {
          if (!valver(argv[2])) {
               catastro(spr("Illegal version code format!  Format must be x.xx,"
                            "\nwhere x is a digit from 0-9."));
          }
          stzcpy(vercod,argv[2],VCDSIZ);
          updmth=MANUAL;
     }
     cursiz(GVIDNOCURS);
     setatr(0x0E);
     printf("Updating client app .EXE and support files in %s.MDF ",
            fnmcse(argv[1]));
     printf("to version %s.\n",vercod);
     updapp(argv[1]);
     printf("\nWGSUVER Finished.\n");
     cursiz(GVIDLILCURS);
     setatr(0x07);
     printf("\r");
EXCEPT
     return(0);
}

static VOID
updapp(                            /* updates application(s)               */
CHAR *appnam)                      /*   application name to update         */
{
     FILE *tmpfp=NULL;
     GBOOL appupd=FALSE,exeupd=FALSE;
     static CHAR filespec[FNEXSZ];

     stzcpy(filespec,spr("%s.MDF",appnam),FNEXSZ);
     if (tfsopn(filespec) > 0) {
          while (tfsrdl() != TFSDUN) {
               switch (tfstate) {
               case TFSLIN:
                    if (tmpfp == NULL) {
                         if ((tmpfp=fopen(WRKFIL,FOPWA)) == NULL) {
                              catastro("Cannot open work file for writing!");
                         }
                    }
                    if (tfspfx(APPVER)) {
                         if (!appupd) {
                              if (valver(tfspst)) {
                                   updver();
                                   appupd=TRUE;
                              }
                              else {
                                   catastro(spr("Illegal client app version in "
                                                "\"%s\"!",fnmcse(tfsfb.ff_name)));
                              }
                         }
                         else {
                              catastro("Illegal .MDF format: APPVER");
                         }
                    }
                    else if (tfspfx(CLIEXE)) {
                         if (!exeupd) {
                              if (valfmt(tfspst)) {
                                   updfver(tfspst);
                                   exeupd=TRUE;
                              }
                              else {
                                   catastro(spr("Illegal client app EXE name "
                                    "format in \"%s\"!",fnmcse(tfsfb.ff_name)));
                              }
                         }
                         else {
                              catastro("Illegal .MDF format: CLIEXE");
                         }
                    }
                    else if (tfspfx(CLISUP)) {
                         updsver(tfspst);
                    }
                    fprintf(tmpfp,"%s\n",tfsbuf);
                    break;
               case TFSEOF:
                    fclose(tmpfp);
                    tmpfp=NULL;
                    appupd=exeupd=FALSE;
                    movfil(WRKFIL,tfsfb.ff_name);
                    break;
               }
          }
     }
     else {
          catastro("WGSUVER: No files found to process!");
     }
}

static GBOOL                       /*   return TRUE if valid version code  */
valver(                            /* checks validity of version code      */
CHAR *ver)
{
     return(strlen(ver) == 4 && ver[1] == '.' && isdigit(ver[0])
         && isdigit(ver[2]) && isdigit(ver[3]));
}

static GBOOL                       /*   return TRUE if proper format       */
valfmt(                            /* is file name valid format?           */
CHAR *filnam)
{
     CHAR *ptr;

     if ((ptr=strrchr(filnam,'.')) != NULL) {
          *ptr='\0';
     }
     if (strlen(filnam) != 8) {
          *ptr='.';
          return(FALSE);
     }
     *ptr='.';
     return(isdigit(filnam[5]) && isdigit(filnam[6]) && isdigit(filnam[7]));
}

static VOID
updver(VOID)                       /* updates actual version code          */
{
     CHAR *ptr;

     ptr=strchr(tfsbuf,':');
     *ptr='\0';
     strcat(tfsbuf,spr(": %s",vercod));
}

static VOID
updfver(                           /* updates client EXE file name         */
CHAR *filnam)
{
     struct ffblk fb;

     fixver(vercod,TRUE);
     filnam[5]=vercod[0];
     filnam[6]=vercod[1];
     filnam[7]=vercod[2];
     if (fndfile(&fb,spr("%s\\%s",INCDIR,makwld(cnv2is(filnam))),0)) {
          if (unlink(spr("%s\\%s",INCDIR,fb.ff_name)) == -1) {
               catastro("UPDFVER: Error deleting old version!");
          }
          cmpfil=TRUE;
     }
     else {
          cmpfil=FALSE;
     }
     prcfil(filnam);
     fixver(vercod,FALSE);
}

static VOID
updsver(                           /* updates support files (as needed)    */
CHAR *filnms)
{
     CHAR *ptr,*tptr;

     stzcpy(wrkbuf,tfsbuf,MAXTFS);
     tptr=strchr(wrkbuf,':');
     *++tptr='\0';
     if ((ptr=strtok(filnms,DELIMS)) != NULL) {
          do {
               if (valfmt(ptr)) {
                    updfver(ptr);
               }
               strcat(wrkbuf,spr(" %s",ptr));
          } while ((ptr=strtok(NULL,DELIMS)) != NULL);
     }
     depad(wrkbuf);
     stzcpy(tfsbuf,wrkbuf,MAXTFS);
}

static VOID
fixver(                            /* fixes up version code for file names */
CHAR *ver,                         /*   version code                       */
GBOOL remove)                      /*   are we adding or removing '.'      */
{
     if (remove) {
          movmem(&ver[2],&ver[1],2);
          ver[3]='\0';
     }
     else {
          movmem(&ver[1],&ver[2],2);
          ver[1]='.';
          ver[4]='\0';
     }
}

static VOID
movfil(                            /* our own file move utility            */
CHAR *srcfil,                      /*   source file name                   */
CHAR *dstfil)                      /*   destination file name              */
{
     FILE *srcfp,*dstfp;
     INT bytes;
     static CHAR movbuf[BUFSIZ];

     if ((srcfp=fopen(srcfil,FOPRB)) == NULL) {
          catastro(spr("MOVFIL: Cannot open source file %s!",fnmcse(srcfil)));
     }
     if ((dstfp=fopen(dstfil,FOPWB)) == NULL) {
          catastro("MOVFIL: Cannot open destination file!");
     }
     while ((bytes=fread(movbuf,1,BUFSIZ,srcfp)) > 0) {
          fwrite(movbuf,1,bytes,dstfp);
     }
     fclose(srcfp);
     fclose(dstfp);
     if (unlink(srcfil) == -1) {
          catastro("MOVFIL: Error deleting source file!");
     }
}

static VOID
prcfil(                            /* process client app EXE file          */
CHAR *filnam)
{
     CHAR *ptr;
     CHAR tmppath[GCMAXPTH];
     struct ffblk fb;

     ptr=fileparts(GCPART_FILE,tfsfb.ff_name,tmppath,sizeof(tmppath));
     if (fndfile(&fb,spr("%s\\%s",ptr,makwld(filnam)),0)) {
          rename(spr("%s\\%s",ptr,fb.ff_name),spr("%s\\%s",ptr,filnam));
          if (cmpfil) {
               if (system(spr("%s %s\\%s",CMPPRG,ptr,filnam)) == -1) {
                    catastro("PRCFIL: Error running WGSINCCF!");
               }
          }
     }
}

static VOID
fmtver(                            /* formats new version code (vercod)    */
CHAR *curver)
{
     FLOAT ver;

     setmem(vercod,sizeof(vercod),0);
     ver=atof(curver);
     switch (updmth) {
     case MINOR:
          ver+=.01;
          sprintf(vercod,"%.2f",ver);
          break;
     case MAJOR:
          ver+=.1;
          sprintf(vercod,"%.2f",ver);
          vercod[3]='0';
          break;
     }
}

static CHAR *
makwld(                            /* convert file version code to wild    */
CHAR *filnam)
{
     static CHAR tmpnam[FNEXSZ];

     stzcpy(tmpnam,filnam,FNEXSZ);
     tmpnam[5]='?';
     tmpnam[6]='?';
     tmpnam[7]='?';
     return(tmpnam);
}
