/***************************************************************************
 *                                                                         *
 *   WGSUSRV.C                                                             *
 *                                                                         *
 *   Copyright (c) 1995-1997 Galacticomm, Inc.  All rights reserved.       *
 *                                                                         *
 *   This is the utility to copy server side applications into their       *
 *   proper app-id directory, and, if necessary, prepare them for          *
 *   inclusion into the client distribution package.                       *
 *                                                                         *
 *                                                - C. Dunn 1/7/95         *
 *                                                                         *
 ***************************************************************************/
#include "gcomm.h"
#include "majorbbs.h"
#include "process.h"
#include "excphand.h"
#include "direct.h"

#define FILREV "$Revision: 6 $"

#define VCDSIZ 5                   /* max length of version code string    */
#define MAXFIL 200                 /* max number of exe/sup files per MDF  */
#define MAXLST 200                 /* max number of files in LSTNAM        */
#define MAXCPY 200                 /* max number of files to copy (update) */
#define MAXAPP 200                 /* max number of apps in app list       */
#define GCSDIR "GCSVCMAN"          /* name of WGM app-id directory         */
#define GCLDIR "WGMAN"             /* name of WGM home directory           */
#define LSTNAM "GCSVCMAN.LST"      /* name of WGM list file                */
#define WGMVER "WGM.VER"           /* name of WGM version control file     */
#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 CLISSF "Shared support files:" /* MDF prefix: shared support files */
#define WRKFIL "WGSUSRV.$$$"       /* temporary work file name             */
#define VERPRG "WGSUVER.EXE"       /* version control program file name    */
#define INCDIR "WGMINST\\INCLUDE"  /* "include" directory for apps         */
#define DELIMS ", \t;"             /* valid delimiters for DLL & EXE lists */

CHAR vercod[VCDSIZ];               /* specified version to update to       */
CHAR wrkbuf[MAXTFS];               /* work buffer for tfsbuf               */
CHAR lstfil[FNEXSZ];               /* list file name specified on cmd line */
CHAR lstbuf[BUFSIZ];               /* list file input buffer               */
CHAR **gcslst;                     /* dynamic array of files in LSTNAM     */
CHAR **mdflst;                     /* dynamic array of files in MDF file   */
CHAR **ssflst;                     /* dynamic array of ssfiles in MDF file */
CHAR **cpylst;                     /* dynamic array of files to update     */
CHAR **applst;                     /* dynamic array of app-ids             */
CHAR *cpybuf;                      /* cpyfil() copy buffer                 */
CHAR *todir=NULL;                  /* Directory to copy files into         */
CHAR *tdir=NULL;                   /* Pointer to current directory         */

GBOOL updgcs;                      /* are we updating GCSVCMAN?            */

INT numlfls;                       /* number of files in LSTNAM            */
INT nummfls;                       /* number of files in MDF file          */
INT numssfs;                       /* number of ssfiles in MDF file        */
INT numcpy;                        /* number of files to copy (update)     */
INT numapp;                        /* number of apps in app list           */

FILE *lstfp;                       /* file pointer to passed list file     */

static VOID cpyalc(VOID);
static VOID prplst(VOID);
static VOID prpmdf(CHAR *appid);
static CHAR *getover(VOID);
static VOID cpyfil(CHAR *srcfil,CHAR *appid);
static VOID movfil(CHAR *srcfil,CHAR *dstfil);
static GBOOL valsfmt(CHAR *filnam);
static VOID updmdf(CHAR *filnam,CHAR *appid);
static GBOOL ismatch(CHAR *newfil,CHAR *oldfil);
static GBOOL inmdf(CHAR *filnam);
static GBOOL inssf(CHAR *filnam);
static GBOOL ingcs(CHAR *filnam);
static CHAR *mkwild(CHAR *filnam);
static VOID logbuf(CHAR *logstr);
static VOID prclst(VOID);
static CHAR *gappid(CHAR *buf);
static GBOOL inapplst(CHAR *appid,INT appno);
static VOID repenv(CHAR *,UINT,CHAR *,CHAR *);
static INT cdrdi(CHAR *path);

INT
main(                              /* main program loop                    */
INT argc,                          /*   number of command line arguments   */
CHAR *argv[])                      /*   array of command line arguments    */
{
TRY
     INT loop;
     CHAR *path,tmppath[GCMAXPTH];
     struct ffblk fb;
     CHAR spath[GCMAXPTH];
     
     initvid();
     setatr(0x0A);
     printf("\n");
     printf("WGSUSRV - Server Update Utility\n");
     printf("Copyright (c) 1995-1997 Galacticomm, Inc.  All rights reserved.\n\n");
     cpyalc();
     mdflst=(CHAR **)alcmem(MAXFIL*sizeof(CHAR *));
     ssflst=(CHAR **)alcmem(MAXFIL*sizeof(CHAR *));
     for (loop=0 ; loop < MAXFIL ; loop++) {
          mdflst[loop]=alcmem(GCMAXPTH);
          ssflst[loop]=alcmem(GCMAXPTH);
     }
     if (argc == 2 && argv[1][0] == '@') {
          stzcpy(lstfil,&argv[1][1],FNEXSZ);
          if ((lstfp=fopen(lstfil,FOPRA)) == NULL) {
               catastro(spr("Error opening list file %s for input!",
                        strupr(lstfil)));
          }
          while (numcpy < MAXCPY && fgets(lstbuf,BUFSIZ,lstfp) != NULL) {
               depad(lstbuf);
               stzcpy(cpylst[numcpy++],strupr(lstbuf),GCMAXPTH);
          }
          numapp=0;
          applst=(CHAR **)alcmem(MAXAPP*sizeof(CHAR *));
          for (loop=0 ; loop < MAXAPP ; loop++) {
               applst[numapp++]=alcmem(MAXFILE);
          }
          fclose(lstfp);
          prplst();
          prclst();
     }
     else if (argc != 3 && argc != 4) {
          belper(800);
          printf("\7");
          setatr(0x0D);
          printf("     Usage: WGSUSRV <path and file name> <App-ID> [server directory]\n\n");
          setatr(0x0E);
          printf("     Path and file name may contain wildcards.\n\n");
          printf("     Example: WGSUSRV A:*.* GALFIL\n");
          printf("              or\n");
          printf("              WGSUSRV A:*.* GALFIL C:\WGSERVNT\n");
          setatr(0x07);
          printf("\r");
          return(1);
     }
     if (sameas(argv[2],GCSDIR)) {
          updgcs=TRUE;
     }
     else {
          updgcs=FALSE;
     }
     if (argc == 4) {
          tdir=getcwd(NULL,GCMAXPTH);
          cdrdi(argv[3]);
     }
     if (updgcs) {
          prplst();
     }
     else {
          stzcpy(vercod,scnmdf(strupr(spr("%s.MDF",argv[2])),APPVER),VCDSIZ);
          prpmdf(argv[2]);
     }
     stlcpy(spath,argv[1],GCMAXPTH);
     if (tdir != NULL) {
          if (strlen(argv[1]) >= 3) {
               if (argv[1][1] != ':' && argv[1][0] != '\\') {
                    stlcpy(spath,tdir,GCMAXPTH);
                    if (tdir[strlen(tdir)-1] != '\\') {
                         stlcat(spath,"\\",GCMAXPTH);
                    }
                    stlcat(spath,argv[1],GCMAXPTH);
                    printf("Directory to find: %s\n",spath);
               }
          }
     }
     if (fnd1st(&fb,spath,0)) {
          path=fileparts(GCPART_PATH,spath,tmppath,sizeof(tmppath));
          do {
               stzcpy(cpylst[numcpy++],spr("%s%s",path,fb.ff_name),GCMAXPTH);
          } while (fndnxt(&fb) && numcpy < MAXCPY);
     }
     else {
          catastro("No files found to process!");
     }
     setatr(0x0E);
     for (loop=0 ; loop < numcpy ; loop++) {
          fileparts(GCPART_FNAM,cpylst[loop],tmppath,sizeof(tmppath));
          printf("Processing file %s ... ",fnmcse(tmppath));
          if (updgcs) {
               if (ingcs(tmppath)) {
                    repenv(cpylst[loop],GCMAXPTH,"WGMAN","\\wgman");
                    repenv(cpylst[loop],GCMAXPTH,"MBBS","\\wgserv");
                    cpyfil(cpylst[loop],argv[2]);
                    printf("done.\n");
               }
               else {
                    printf("not in list file...skipping.\n");
               }
          }
          else {
               if (inmdf(tmppath)) {
                    repenv(cpylst[loop],GCMAXPTH,"WGMAN","\\wgman");
                    repenv(cpylst[loop],GCMAXPTH,"MBBS","\\wgserv");
                    cpyfil(cpylst[loop],argv[2]);
               }
               else if (inssf(tmppath)) {
                    repenv(cpylst[loop],GCMAXPTH,"WGMAN","\\wgman");
                    repenv(cpylst[loop],GCMAXPTH,"MBBS","\\wgserv");
                    cpyfil(cpylst[loop],argv[2]);
               }
               else {
                    printf("not in .MDF file...skipping.\n");
               }
               if (valsfmt(tmppath)) {
                    updmdf(cpylst[loop],argv[2]);
               }
               printf("done.\n");
          }
     }
     if (!updgcs) {
          if (system(spr("%s %s %s",VERPRG,argv[2],vercod)) == -1) {
               catastro("Error running WGSUVER.EXE!");
          }
     }
     setatr(0x0E);
     printf("\nWGSUSRV Finished.\n");
     setatr(0x07);
     printf("\r");
EXCEPT
     if (tdir != NULL) {
          cdrdi(tdir);
     }
     return(0);
}

static VOID
cpyalc(VOID)                       /* allocates memory for copy list/util  */
{
     INT loop;

     numcpy=0;
     cpybuf=alcmem(CPBSIZ);
     cpylst=(CHAR **)alcmem(MAXCPY*sizeof(CHAR *));
     for (loop=0 ; loop < MAXCPY ; loop++) {
          cpylst[loop]=alcmem(GCMAXPTH);
     }
}

static VOID
prplst(VOID)                       /* creates in-memory table of LSTNAM    */
{
     FILE *lstfp;
     INT loop;
     CHAR tmppath[GCMAXPTH];

     gcslst=(CHAR **)alcmem(MAXLST*sizeof(CHAR *));
     for (loop=0 ; loop < MAXLST ; loop++) {
          gcslst[loop]=alcmem(GCMAXPTH);
     }
     if ((lstfp=fopen(spr("%s\\%s",GCSDIR,LSTNAM),FOPRA)) == NULL) {
          catastro("PRPLST: Cannot open GCSVCMAN.LST for input!");
     }
     numlfls=0;
     while (numlfls < MAXLST && fgets(lstbuf,BUFSIZ,lstfp) != NULL) {
          depad(lstbuf);
          fileparts(GCPART_FNAM,lstbuf,tmppath,sizeof(tmppath));
          stzcpy(gcslst[numlfls++],tmppath,GCMAXPTH);
     }
     fclose(lstfp);
     stzcpy(vercod,firstwd(getover()),VCDSIZ);
}

static VOID
prpmdf(                            /* creates table of MDF contents        */
CHAR *appid)
{
     INT loop;
     CHAR *ptr;

     for (loop=0 ; loop < MAXFIL ; loop++) {
          setmem(mdflst[loop],GCMAXPTH,0);
          setmem(ssflst[loop],GCMAXPTH,0);
     }
     nummfls=numssfs=0;
     if (tfsopn(spr("%s.MDF",strupr(appid))) > 0) {
          while (tfsrdl() != TFSDUN) {
               switch (tfstate) {
               case TFSLIN:
                    if (tfspfx(CLIEXE)) {
                         stzcpy(mdflst[nummfls++],tfspst,FNEXSZ);
                    }
                    else if (tfspfx(CLISUP)) {
                         if ((ptr=strtok(tfspst,DELIMS)) != NULL) {
                              do {
                                   stzcpy(mdflst[nummfls++],ptr,FNEXSZ);
                              } while ((ptr=strtok(NULL,DELIMS)) != NULL);
                         }
                    }
                    else if (tfspfx(CLISSF)) {
                         if ((ptr=strtok(tfspst,DELIMS)) != NULL) {
                              do {
                                   stzcpy(ssflst[numssfs++],ptr,FNEXSZ);
                              } while ((ptr=strtok(NULL,DELIMS)) != NULL);
                         }
                    }
                    break;
               }
          }
     }
}

static CHAR *
getover(VOID)                      /* reads version code in WGM.VER        */
{
     FILE *wgmfp;
     static CHAR wgmver[VCDSIZ];

     if ((wgmfp=fopen(spr("%s\\%s",GCSDIR,WGMVER),FOPRA)) == NULL) {
          catastro("GETOVER: Cannot open WGM.VER for input!");
     }
     if (fscanf(wgmfp,"%s",wgmver) != 1) {
          catastro("GETOVER: Error reading version from WGM.VER!");
     }
     fclose(wgmfp);
     return(wgmver);
}

static VOID
cpyfil(                            /* our own copy file utility            */
CHAR *srcfil,                      /*   source file name                   */
CHAR *appid)                       /*   app-id this file is part of        */
{
     CHAR tmppath[GCMAXPTH];
     CHAR *dst;
     struct ffblk fb;
     
     gmkdir(appid);

     fileparts(GCPART_FNAM,srcfil,tmppath,sizeof(tmppath));
     while (fnd1st(&fb,spr("%s\\%s",appid,mkwild(tmppath)),0)) {
          if (unlink(spr("%s\\%s",appid,fb.ff_name)) == -1) {
               catastro("CPYFIL: Error deleting old version file!");
          }
     }

     dst=spr("%s\\%s",appid,tmppath);
     if (!cpyutl(srcfil,dst,FOPRB,FOPWB)) {
          catastro("CPYFIL: Error copying from %s to %s!",srcfil,dst);
     }
}

static VOID
movfil(                            /* our own file move utility            */
CHAR *srcfil,                      /*   source file name                   */
CHAR *dstfil)                      /*   destination file name              */
{
     unlink(dstfil);
     if (rename(srcfil,dstfil) != 0) {
          catastro("MOVFIL: Error renaming temporary work file!");
     }
}

static GBOOL
valsfmt(                           /* is "special" file valid format?      */
CHAR *filnam)
{
     CHAR *ptr;
     GBOOL retval=FALSE;

     if ((ptr=strrchr(filnam,'.')) != NULL) {
          *ptr='\0';
     }
     switch (strlen(filnam)) {
     case 4:
     case 5:
     case 6:
     case 7:
     case 8:
          if (isalpha(filnam[0]) && isalpha(filnam[1]) && isalpha(filnam[2])
           && isdigit(filnam[3])) {
               retval=TRUE;
          }
          break;
     }
     if (ptr != NULL) {
          *ptr='.';
     }
     return(retval);
}

static VOID
updmdf(                            /* updates MDF file with special file   */
CHAR *filnam,
CHAR *appid)
{
     CHAR *token;
     CHAR tmppath[GCMAXPTH];

     setmem(wrkbuf,MAXTFS,0);
     if (tfsopn(spr("%s.MDF",appid)) > 0) {
          while (tfsrdl() != TFSDUN) {
               switch (tfstate) {
               case TFSLIN:
                    if (tfspfx(CLISUP)) {
                         stzcpy(wrkbuf,CLISUP,MAXTFS);
                         if ((token=strtok(tfspst,DELIMS)) != NULL) {
                              do {
                                   fileparts(GCPART_FNAM,filnam,tmppath,
                                                         sizeof(tmppath));
                                   if (ismatch(tmppath,token)) {
                                        token=fileparts(GCPART_FNAM,filnam,
                                                      tmppath,sizeof(tmppath));
                                   }
                                   strcat(wrkbuf,spr(" %s",token));
                              } while ((token=strtok(NULL,DELIMS)) != NULL);
                         }
                         stzcpy(tfsbuf,wrkbuf,MAXTFS);
                    }
                    logbuf(tfsbuf);
                    break;
               case TFSEOF:
                    movfil(WRKFIL,tfsfb.ff_name);
                    break;
               }
          }
     }
}

static GBOOL
ismatch(                           /* do file names match?                 */
CHAR *newfil,
CHAR *oldfil)
{
     GBOOL retval=TRUE;
     CHAR *oldptr,*newptr;

     if ((oldptr=strrchr(oldfil,'.')) != NULL) {
          *oldptr='\0';
     }
     if ((newptr=strrchr(newfil,'.')) != NULL) {
          *newptr='\0';
     }
     if (strlen(oldfil) != strlen(newfil)) {
          retval=FALSE;
     }
     if ((newfil[0] != oldfil[0]) || (newfil[1] != oldfil[1])
      || (newfil[2] != oldfil[2])) {
          if (oldptr != NULL) {
               *oldptr='.';
          }
          if (newptr != NULL) {
               *newptr='.';
          }
          retval=FALSE;
     }
     switch (strlen(newfil)) {
     case 4:
          if (isdigit(newfil[3])) {
               if (!isdigit(oldfil[3])) {
                    retval=FALSE;
               }
          }
          break;
     case 5:
          if (isdigit(newfil[3])) {
               if (!isdigit(oldfil[3])) {
                    retval=FALSE;
               }
          }
          if (isdigit(newfil[4])) {
               if (!isdigit(oldfil[4])) {
                    retval=FALSE;
               }
          }
          else if (oldfil[4] != newfil[4]) {
               retval=FALSE;
          }
          break;
     case 6:
          if (isdigit(newfil[3])) {
               if (!isdigit(oldfil[3])) {
                    retval=FALSE;
               }
          }
          if (isdigit(newfil[4])) {
               if (!isdigit(oldfil[4])) {
                    retval=FALSE;
               }
          }
          else if (oldfil[4] != newfil[4]) {
               retval=FALSE;
          }
          if (isdigit(newfil[5])) {
               if (!isdigit(oldfil[5])) {
                    retval=FALSE;
               }
          }
          else if (oldfil[5] != newfil[5]) {
               retval=FALSE;
          }
          break;
     case 7:
          if (isdigit(newfil[3])) {
               if (!isdigit(oldfil[3])) {
                    retval=FALSE;
               }
          }
          if (isdigit(newfil[4])) {
               if (!isdigit(oldfil[4])) {
                    retval=FALSE;
               }
          }
          else if (oldfil[4] != newfil[4]) {
               retval=FALSE;
          }
          if (isdigit(newfil[5])) {
               if (!isdigit(oldfil[5])) {
                    retval=FALSE;
               }
          }
          else if (oldfil[5] != newfil[5]) {
               retval=FALSE;
          }
          if (oldfil[6] != newfil[6]) {
               retval=FALSE;
          }
          break;
     case 8:
          if (isdigit(newfil[3])) {
               if (!isdigit(oldfil[3])) {
                    retval=FALSE;
               }
          }
          if (isdigit(newfil[4])) {
               if (!isdigit(oldfil[4])) {
                    retval=FALSE;
               }
          }
          else if (oldfil[4] != newfil[4]) {
               retval=FALSE;
          }
          if (isdigit(newfil[5])) {
               if (!isdigit(oldfil[5])) {
                    retval=FALSE;
               }
          }
          else if (oldfil[5] != newfil[5]) {
               retval=FALSE;
          }
          if (oldfil[6] != newfil[6]) {
               retval=FALSE;
          }
          if (oldfil[7] != newfil[7]) {
               retval=FALSE;
          }
          break;
     }
     if (oldptr != NULL) {
          *oldptr='.';
     }
     if (newptr != NULL) {
          *newptr='.';
     }
     return(retval);
}

static GBOOL
inmdf(                             /* is file name in .MDF file?           */
CHAR *filnam)
{
     INT i;
     CHAR filptr[FNEXSZ];

     stzcpy(filptr,mkwild(filnam),FNEXSZ);
     for (i=0 ; i < nummfls ; i++) {
          if (sameas(filptr,mkwild(mdflst[i]))) {
               return(TRUE);
          }
     }
     return(FALSE);
}

static GBOOL
inssf(                             /* is file name in .MDF file?           */
CHAR *filnam)
{
     INT i;

     for (i=0 ; i < numssfs ; i++) {
          if (sameas(filnam,ssflst[i])) {
               return(TRUE);
          }
     }
     return(FALSE);
}

static GBOOL
ingcs(                             /* is file name part of GCSVCMAN.LST?   */
CHAR *filnam)
{
     INT i;

     for (i=0 ; i < numlfls ; i++) {
          if (sameas(filnam,gcslst[i])) {
               return(TRUE);
          }
     }
     return(FALSE);
}

static CHAR *
mkwild(                            /* make file name version code wildcard */
CHAR *filnam)
{
     CHAR *ptr;
     static CHAR wldfil[FNEXSZ];

     stzcpy(wldfil,filnam,FNEXSZ);
     if ((ptr=strrchr(wldfil,'.')) != NULL) {
          *ptr='\0';
     }
     switch (strlen(wldfil)) {
     case 4:
          if (isdigit(wldfil[3])) {
               wldfil[3]='?';
          }
          break;
     case 5:
          if (isdigit(wldfil[3])) {
               wldfil[3]='?';
          }
          if (isdigit(wldfil[4])) {
               wldfil[4]='?';
          }
          break;
     case 6:
     case 7:
          if (isdigit(wldfil[3])) {
               wldfil[3]='?';
          }
          if (isdigit(wldfil[4])) {
               wldfil[4]='?';
          }
          if (isdigit(wldfil[5])) {
               wldfil[5]='?';
          }
          break;
     case 8:
          if (valsfmt(wldfil)) {
               if (isdigit(wldfil[3])) {
                    wldfil[3]='?';
               }
               if (isdigit(wldfil[4])) {
                    wldfil[4]='?';
               }
               if (isdigit(wldfil[5])) {
                    wldfil[5]='?';
               }
          }
          else {
               if (isdigit(wldfil[5])) {
                    wldfil[5]='?';
               }
               if (isdigit(wldfil[6])) {
                    wldfil[6]='?';
               }
               if (isdigit(wldfil[7])) {
                    wldfil[7]='?';
               }
          }
          break;
     }
     *ptr='.';
     return(wldfil);
}

static VOID
logbuf(
CHAR *logstr)
{
     FILE *fp;

     if ((fp=fopen(WRKFIL,FOPAA)) == NULL) {
          catastro("Error opening temporary work file!");
     }
     fprintf(fp,"%s\n",logstr);
     fclose(fp);
}

static VOID
prclst(VOID)                       /* process list file                    */
{
     INT i,appno=0;
     CHAR *appid;
     CHAR tmppath[GCMAXPTH];

     setatr(0x0E);
     for (i=0 ; i < numcpy ; i++) {
          fileparts(GCPART_FNAM,cpylst[i],tmppath,sizeof(tmppath));
          printf("Processing file %s ... ",fnmcse(tmppath));
          if (sameas((appid=gappid(cpylst[i])),GCSDIR)) {
               updgcs=TRUE;
          }
          else {
               updgcs=FALSE;
          }
          if (updgcs) {
               if (ingcs(tmppath)) {
                    repenv(cpylst[i],GCMAXPTH,"WGMAN","\\wgman");
                    repenv(cpylst[i],GCMAXPTH,"MBBS","\\wgserv");
                    cpyfil(cpylst[i],GCSDIR);
                    printf("done.\n");
               }
               else {
                    printf("not in list file...skipping.\n");
               }
          }
          else {
               stzcpy(vercod,scnmdf(strupr(spr("%s.MDF",appid)),APPVER),
                      VCDSIZ);
               prpmdf(appid);
               if (!inapplst(appid,appno)) {
                    if (appno == MAXAPP) {
                         catastro("PRCLST: Too many applications!");
                    }
                    stzcpy(applst[appno++],appid,MAXFILE);
               }
               if (inmdf(tmppath)) {
                    repenv(cpylst[i],GCMAXPTH,"WGMAN","\\wgman");
                    repenv(cpylst[i],GCMAXPTH,"MBBS","\\wgserv");
                    if (isfile(cpylst[i])) {
                         cpyfil(cpylst[i],appid);
                    }
               }
               else if (inssf(tmppath)) {
                    repenv(cpylst[i],GCMAXPTH,"WGMAN","\\wgman");
                    repenv(cpylst[i],GCMAXPTH,"MBBS","\\wgserv");
                    if (isfile(cpylst[i])) {
                         cpyfil(cpylst[i],appid);
                    }
               }
               else {
                    printf("not in .MDF file...skipping.\n");
               }
               if (valsfmt(tmppath)) {
                    updmdf(cpylst[i],appid);
               }
               printf("done.\n");
          }
     }
     if (appno > 0) {
          for (i=0 ; i < appno ; i++) {
               stzcpy(vercod,scnmdf(strupr(spr("%s.MDF",applst[i])),APPVER),
                      VCDSIZ);
               if (vercod[0] != '\0') {
                    if (system(spr("%s %s %s",VERPRG,applst[i],vercod)) == -1) {
                         catastro("PRCLST: Error running WGSUVER.EXE!");
                    }
               }
          }
     }
     printf("\nWGSUSRV Finished.\n");
     setatr(0x07);
     printf("\r");
     exit(0);
}

static CHAR *                      /*   returns pointer to app-id          */
gappid(                            /* gets app-id for current file         */
CHAR *buf)
{
     CHAR *ptr,*pthptr,ch;
     static CHAR retval[MAXFILE];
     CHAR tmppath[GCMAXPTH];

     ptr=fileparts(GCPART_PATH,buf,tmppath,sizeof(tmppath));
     if ((ch=(ptr[strlen(ptr)-1])) == '\\' || ch == ':') {
          ptr[strlen(ptr)-1]='\0';
     }
     pthptr=strrchr(ptr,'\\');
     if (sameas(++pthptr,GCLDIR)) {
          return(stzcpy(retval,GCSDIR,MAXFILE));
     }
     return(stzcpy(retval,pthptr,MAXFILE));
}

static GBOOL
inapplst(                          /* is app already in dynamic list?      */
CHAR *appid,
INT appno)
{
     INT i;

     for (i=0 ; i < appno ; i++) {
          if (sameas(appid,applst[i])) {
               return(TRUE);
          }
     }
     return(FALSE);
}

static VOID
repenv(                            /* replace path beginning               */
CHAR *path,                        /*   path to check                      */
UINT maxplen,                      /*   max path length incl. NUL          */
CHAR *envar,                       /*   env. variable holding replacemnt   */
CHAR *begpath)                     /*   path portion to replace            */
{
     CHAR *e;

     e=getenv(envar);
     if (e != NULL) {
          if (sameto(begpath,path)) {
               stzcpy(path,spr("%s%s",e,&path[strlen(begpath)]),maxplen);
          }
     }
     else if (sameto("\\wgman",path)) {
          stzcpy(path,spr("C:%s",path),maxplen);
     }
}

static INT
cdrdi(                             /* Change DRive and DIrectory           */
CHAR *path)
{
     CHAR dl,tmppth[GCMAXPTH];

     if (path[1] == ':') {
          dl=path[0];
          if (dl >= 'a' && dl <= 'z') {
               dl+='A'-'a';
          }
          if (dl >= 'A' && dl <= 'Z') {
               _chdrive(dl-'A'+1);
          }
     }
     fileparts(GCPART_PATH,path,tmppth,GCMAXPTH);
     gmkdir(tmppth);
     return(chdir(path));
}

