/***************************************************************************
 *                                                                         *
 *   WGSMKWGM.C                                                            *
 *                                                                         *
 *   Copyright (c) 1994-1997 GALACTICOMM, Inc.    All rights reserved.     *
 *                                                                         *
 *   This is the utility for the Sysop to create WGM distribution disks    *
 *   and/or .ZIP files.                                                    *
 *                                                                         *                                                                         *
 *                                                - Dan Rhea               *
 *                                                - C. Dunn  11/04/94      *
 *                                                                         *
 *   Worldgroup 2.0 mods.                                                  *
 *                                                - Bill Hyatt 2/8/96      *
 *                                                                         *
 ***************************************************************************/

#ifdef GCWINNT
#include <windows.h>
#endif
#include "gcomm.h"
#include "majorbbs.h"
#include "gcsp.h"
#include "errno.h"
#include "process.h"
#include "direct.h"
#include "excphand.h"
#include "galnssf.h"

#define FILREV "$Revision: 6 $"

#define NAMSIZ 44                  /* max. length of online service name   */
#define MODEM  0                   /* using modem as connectivity method   */
#define SERIAL 1                   /* using serial as connectivity method  */
#define LAN    2                   /* using LAN as connectivity method     */
#define TELNET 3                   /* using telnet as connectivity method  */
#define DMNSIZ 44                  /* max. length of domain name           */
#define NEWUSR 1                   /* logging on as a new user             */
#define SRVSIZ 44                  /* max. length of server name           */

struct wgmrec {                    /* layout for online service info       */
     CHAR sysnam[NAMSIZ];          /*   online service name                */
     SHORT conmth;                 /*   connectivity method                */
     CHAR syspho[PHOSIZ];          /*   online service phone number        */
     CHAR srvnam[SRVSIZ];          /*   online service server name         */
     CHAR dmnnam[DMNSIZ];          /*   online service domain name         */
     SHORT newusr;                 /*   logon as new user?                 */
     CHAR lognam[UIDSIZ];          /*   user's login name                  */
     CHAR logpsw[PSWSIZ];          /*   user's password                    */
     CHAR bldwht;                  /*   F=build file, D=build disk         */
     CHAR winfnm[GCMAXFILE+1];     /*   name of Windows .EXE to create     */
};
#define INCDIR "include"           /* include directory name under WGMINST */
#define EXCDIR "exclude"           /* exclude directory name under WGMINST */
#define INCFIL "include.dir"       /* include directory "dummy" file       */
#define EXCFIL "exclude.dir"       /* exclude directory "dummy" file       */
#define LSTNAM "wgsmkwgm.lst"      /* list file for files in WGMINST       */
#define ICODIR "wgsicons"          /* name of icon directory               */
#define DISKID "wgminst" SLS "disk.?"/* fnd1st parameter for disk.? files  */
#define SAVFIL "wgsmkwgm.sav"      /* name of file to hold WGM info        */
#define INSTMP "instemp"           /* temporary directory used during build*/
#define DELIMS ", \t;"             /* valid delimiters for DLL & EXE lists */

#define NUMSUP 4                   /* number of installation support files */
#define NUMFST 10                  /* number for files forced onto 1st disk*/
#define NUMEXP 4                   /* # files which don't go in WINUPD.LST */
#define FILBLD 0                   /* attempting to build a .ZIP file      */
#define DSKBLD 1                   /* attempting to build a disk           */
#define FILSIZ 13                  /* maximum length of file name          */
#define FILSIZ2 16                 /* max length of file name + drive      */
#define CONSIZ 7                   /* max. length of temp 'conmth' var     */
#define YNSIZ  4                   /* max. length of temp 'newusr' var     */
#define BWHSIZ 5                   /* max. length of temp "build what" var */

/* edtval() field identifiers */
#define NAMFLD 0                   /* system name field identifier         */
#define CONFLD 1                   /* connect method field identifier      */
#define PHOFLD 2                   /* phone number field identifier        */
#define SRVFLD 3                   /* server name field identifier         */
#define DOMFLD 4                   /* domain name field identifier         */
#define NEWFLD 5                   /* new user logon field identifier      */
#define LNMFLD 6                   /* logon name field identifier          */
#define LPWFLD 7                   /* logon password field identifier      */
#define BLDFLD 8                   /* what to build field identifier       */
#define FNMFLD 9                   /* name of file to build                */

#ifdef GCDOS
#define FNMCASE ALLCAPS            /* file name case option flag           */
#else
#define FNMCASE 0                  /* file name case option flag           */
#endif

#define HELPX  6                   /* x-coord of field help display        */
#define HELPY3 19                  /* y-coord of fld help display - 3 lines*/
#define HELPY2 20                  /* y-coord of fld help display - 2 lines*/

#define FST 1                      /* first disk filelist                  */

#define GOTFILE 1                  /* got a valid file                     */
#define NEWDISK 0                  /* have files, but no space, new disk   */
#define ALLDONE -1                 /* all files been output                */
#define NODRIVE -1                 /* don't use any drive (zipping)        */
#define ADRIVE 1                   /* drive number associated w/ A:        */
#define BDRIVE 2                   /* drive number associated w/ B:        */

#define MINMEM 298000L             /* minimum memory req'd for zipping     */
#define REGSIZ 9                   /* maximum length of reg number         */
#define MAXINZ 800                 /* maximum files allowed in ZIP file    */
#define RECLEN sizeof(struct wgmrec) /* record length in WGSMKWGM.SAV      */

/* OSM Flags for last line in .OSG file */
#define FLGOSM 1                   /* there is a new OSM version           */
#define FLGNXT 2                   /* connect next time                    */
#define FLGICO 4                   /* custom system icon in use            */
#define FLGACN 8                   /* always connect upon invocation       */
#define FLGSER 16                  /* connection involves serial port      */
#define FLGSCS 32                  /* auto-sense client/server mode        */
#define FLGSAN 64                  /* resp. to aut-sns ANSI color in A/A   */
#define FLGIP  128                 /* if LAN connection, is it telnet?     */

#define EXTFIL ".___"              /* extension "filler" for cnv2is()      */

/* choosing module-related */
#define MCHCSZ   (MNMSIZ+2+2)      /* string size of choice in list        */
#define MODLSFIL "galinmod.lst"    /* list file for included modules       */
#define LSELCHR  16                /* "selected" char, left side of entry  */
#define LSELPOS  0                 /* string pos where LSELCHR is set      */
#define RSELCHR  17                /* "selected" char, right side of entry */
#define RSELPOS  27                /* string pos where RSELCHR is set      */
#define UNSELCHR ' '               /* char used to clear a selection       */

#define ISSEL(idx) (modlchcs[idx][LSELPOS] == LSELCHR)
                                   /* is this entry selected?              */

CHAR **ssfils=NULL;                /* list of included shared support files*/
INT nssfils=0;                     /* number of shared support files       */

typedef struct csmodrec {          /* info on a C/S module                 */
     CHAR mdffil[GCMAXFNM];        /* .MDF file name                       */
     CHAR modesc[MNMSIZ];          /* English desc of module               */
     CHAR csexenam[GCMAXFNM];      /* C/S .EXE name                        */
     CHAR *asfils;                 /* list of app-specific support files   */
} CSMODREC;

CSMODREC *csmodrecs=NULL;          /* info records for installation build  */
INT ncsmods=0;                     /* number of C/S modules                */

CHAR **modlchcs=NULL;              /* choose list for selected modules     */

struct filary {                    /* file list structure                  */
     CHAR filnam[FILSIZ];          /*   filename                           */
     LONG fsize;                   /*   file size                          */
     LONG asize;                   /*   adjusted size                      */
     INT flag;                     /*   flag (0=uncopied)                  */
} *fillst,                         /* list of files to copy                */
  *filptr,                         /* pointer to list                      */
  *fstlst,                         /* list of files for first disk         */
  *fstptr,                         /* pointer to first files list          */
  *dsknfo;                         /* special case: pass info for disk.1   */

INT numfil=0;                      /* number of entries in fillst          */
INT numfst=0;                      /* number of files forced onto 1st disk */

struct wgmrec wgmrec;              /* saved info                           */

CHAR drvchc;                       /* choice of what drive to bld dsks on  */

extern CHAR scntbl[][GVIDSCNSIZ];  /* table of screens                     */

CHAR tconmth[CONSIZ];              /* temporary string for 'conmth' var    */
CHAR tnewusr[YNSIZ];               /* temporary string for 'newusr' var    */
CHAR icofil[FILSIZ];               /* icon file to use                     */
CHAR regnum[REGSIZ];               /* system registration number           */
CHAR lstbuf[BUFSIZ];               /* file input buffer for WGSMKWGM.LST   */
CHAR bldwht[BWHSIZ];               /* what to build                        */
CHAR *dosscn=NULL;                 /* save area for DOS screen             */
CHAR *wrnscn=NULL;                 /* save area for warning screen         */
CHAR *dskscn=NULL;                 /* save area for file output fuzzy      */
CHAR *limscn=NULL;                 /* another screen save area             */

CHAR *supfil[NUMSUP]={             /* array of installation support files  */
     "setup.exe",                  /*   Windows setup executable           */
     "setup.ins",                  /*   compiled installation script       */
     "gcomm.bmp",                  /*   Gcomm logo for display             */
     "~ins0762.lib"                /*   installation script support file   */
};

CHAR *fstfil[NUMFST]={             /* array of files forced to first disk  */
     "setup.exe",                  /*   Windows setup executable           */
     "setup.ins",                  /*   compiled installation script       */
     "gcomm.bmp",                  /*   Gcomm logo for display             */
     "wgm.ver",                    /*   version info                       */
     "~ins0762.lib",               /*   installation script support file   */
     "disk.1",                     /*   first disk id                      */
     "_setup.lst",                 /*   list of installation files         */
     "_winupd.lst",                /*   list of files for \windows\system  */
     "*.ico",                      /*   system's .ICO file                 */
     "*.osg"                       /*   system's .OSG file                 */
};

CHAR *exp2win[NUMEXP]={            /* array of files not in _WINUPD.LST    */
     "gcsvcman.exe",               /*   WGM executable                     */
     "wgmupdat.exe",               /*   WGM updater executable             */
     "npwg32.dll",                 /*   32-bit Netscape plug-in .DLL       */
     "npwg16.dll"                  /*   32-bit Netscape plug-in .DLL       */
};

INT fldnum;                        /* current field being edited           */

LONG icosiz=0L;                    /* size of custom icon file             */
LONG osgsiz=0L;                    /* size of osg file                     */

FILE *savfp;                       /* file pointer to WGSMKWGM.SAV         */

VOID init(VOID);
VOID dftosm(VOID);
VOID supcsrecs(VOID);
VOID dsphlp(VOID);
VOID chkvalc(VOID);
GBOOL vsysnam(INT c);
GBOOL vconmth(INT c,CHAR *stg);
VOID clrlin(VOID);
GBOOL vsyspho(INT c);
GBOOL vsrvnam(INT c);
GBOOL vdmnnam(INT c);
GBOOL vnewusr(INT c,CHAR *stg);
GBOOL vlognam(INT c);
GBOOL vlogpsw(INT c);
GBOOL vbldwht(INT c,CHAR *stg);
GBOOL vwinfil(INT c,CHAR *stg);
GBOOL chkact(INT c);
VOID chsmods(VOID);
VOID chgchc(INT chsidx);
VOID selchc(INT idx,GBOOL selec,CHAR **modlchcs);
INT cssort(const VOID *rec1,const VOID *rec2);
GBOOL chkbld(VOID);
GBOOL ok2sav(VOID);
VOID upddsp(VOID);
VOID reqwrn(INT dskbld);
VOID dobld(VOID);
VOID cpyfil(CHAR *srcdir,CHAR *srcfil);
VOID comprfil(CHAR *srcdir,CHAR *srcfil,GBOOL incsdir);
CHAR *cnv2is(CHAR *filnam);
VOID add2ss(CHAR *fils2add);
VOID makosg(VOID);
VOID kilwht(CHAR *str);
CHAR *rnosid(CHAR *regno);
INT invser(VOID);
INT teltyp(VOID);
VOID makico(VOID);
VOID gendsk1(VOID);
VOID getlsts(VOID);
VOID fildsk(INT drvnum);
VOID srtlst(VOID);
VOID chkdrv(INT drvnum);
GBOOL wrtprt(INT drvnum);
VOID wipdsk(INT drvnum);
VOID adjlst(UINT clssiz);
VOID todsk(INT lstnum,INT dsknum);
INT getfil(CHAR *filenam,LONG *filsize,LONG dsksiz);
VOID dodsk(CHAR *filnam,INT dsknum);
VOID dsknum(INT drvnum,INT dsknum);
VOID lastfil(INT drvnum);
VOID prewrn(VOID);
VOID pstwrn(VOID);
VOID predsk(VOID);
VOID pstdsk(VOID);
VOID prelim(VOID);
VOID pstlim(VOID);
VOID wgmdwn(INT update);
LONG getdfre(INT drvnum);
INT runDos(GBOOL searchPath,CHAR *progName,CHAR *cmdstr);

INT
main(VOID)                         /* main program loop                    */
{
TRY
     GBOOL editing=TRUE;

     initvid();
     init();
     while (editing) {
          dsphlp();
          switch (fldnum) {
          case NAMFLD:
               edtval(28,5,NAMSIZ,wgmrec.sysnam,vsysnam,MULTIEX);
               break;
          case CONFLD:
               edtval(28,8,CONSIZ,tconmth,vconmth,MULTIEX|MCHOICE);
               break;
          case PHOFLD:
               edtval(28,9,PHOSIZ,wgmrec.syspho,vsyspho,MULTIEX);
               break;
          case SRVFLD:
               edtval(28,9,SRVSIZ,wgmrec.srvnam,vsrvnam,MULTIEX);
               break;
          case DOMFLD:
               edtval(28,9,DMNSIZ,wgmrec.dmnnam,vdmnnam,MULTIEX);
               break;
          case NEWFLD:
               edtval(28,11,YNSIZ,tnewusr,vnewusr,MULTIEX|MCHOICE);
               break;
          case LNMFLD:
               edtval(28,12,UIDSIZ,wgmrec.lognam,vlognam,MULTIEX);
               break;
          case LPWFLD:
               edtval(28,13,PSWSIZ,wgmrec.logpsw,vlogpsw,MULTIEX);
               break;
          case BLDFLD:
               edtval(14,15,BWHSIZ,bldwht,vbldwht,MULTIEX|MCHOICE);
               break;
          case FNMFLD:
               edtval(55,15,GCMAXFILE+1,wgmrec.winfnm,vwinfil,MULTIEX|FNMCASE);
               break;
          }
          chkvalc();
     }
     clsvid();
EXCEPT
     return(0);
}

VOID
init(VOID)                         /* initialize WGSMKWGM                  */
{
     CHAR *ptr;
     struct ffblk icofb,dskfb;

     pascrit();
     monorcol();
     cvtscn(scntbl[0]);
     cvtscn(scntbl[1]);
     cvtscn(scntbl[2]);
     cvtscn(scntbl[3]);
     cvtscn(scntbl[4]);
     cvtscn(scntbl[5]);
     cvtscn(scntbl[6]);
     scn2mem(dosscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
     cursiz(GVIDNOCURS);
     explodeto(scntbl[0],4,0,74,22,4,1);
     explodem=0;
     if (fnd1st(&dskfb,DISKID,0)) {
          do {
               unlink(spr("wgminst" SLS "%s",dskfb.ff_name));
          } while (fndnxt(&dskfb));
     }
     if ((savfp=fopen(SAVFIL,FOPRB)) == NULL) {
          dftosm();
     }
     else {
          if (fread(&wgmrec,RECLEN,1,savfp) != 1) {
               dftosm();
          }
          fclose(savfp);
     }
     stlcpy(regnum,getrno(),REGSIZ);
     setatr(0x1E);
     locate(28,5);
     printf("%s",wgmrec.sysnam);
     locate(28,6);
     setatr(0x13);
     printf("%s",regnum);
     setatr(0x1E);
     switch (wgmrec.conmth) {
     case MODEM:
          stlcpy(tconmth,"MODEM",CONSIZ);
          break;
     case SERIAL:
          stlcpy(tconmth,"SERIAL",CONSIZ);
          break;
     case LAN:
          stlcpy(tconmth,"LAN",CONSIZ);
          break;
     default:
          stlcpy(tconmth,"TELNET",CONSIZ);
          break;
     }
     locate(28,8);
     printf("%s",tconmth);
     if (wgmrec.conmth == MODEM) {
          locate(7,9);
          setatr(0x1F);
          printf("       Phone number: ");
          setatr(0x1E);
          printf("%s",wgmrec.syspho);
     }
     else if (wgmrec.conmth == LAN) {
          locate(7,9);
          setatr(0x1F);
          printf("        Server name: ");
          setatr(0x1E);
          printf("%s",wgmrec.srvnam);
     }
     else if (wgmrec.conmth == TELNET) {
          locate(7,9);
          setatr(0x1F);
          printf("        Domain name: ");
          setatr(0x1E);
          printf("%s",wgmrec.dmnnam);
     }
     switch (wgmrec.newusr) {
     case NEWUSR:
          stlcpy(tnewusr,"YES",YNSIZ);
          break;
     default:
          stlcpy(tnewusr,"NO",YNSIZ);
          break;
     }
     locate(28,11);
     printf("%s",tnewusr);
     setatr(wgmrec.newusr ? 0x13 : 0x1E);
     locate(28,12);
     printf("%s",wgmrec.lognam);
     locate(28,13);
     printf("%s",wgmrec.logpsw);
     if ((ptr=mstscan("wgsmainm.msg","aboutico",FILSIZ)) != NULL) {
          if (fnd1st(&icofb,spr("wgsicons" SLS "%s",ptr),0)) {
               stlcpy(icofil,ptr,FILSIZ);
          }
          else {
               icofil[0]='\0';
          }
     }
     else {
          icofil[0]='\0';
     }
     if (wgmrec.bldwht == 'F') {
          strcpy(bldwht,"FILE");
     }
     else {
          strcpy(bldwht,"DISK");
     }
     setatr(0x1E);
     locate(14,15);
     printf("%s",bldwht);
     locate(55,15);
     if (wgmrec.bldwht == 'F') {
          setatr(0x1E);
     }
     else {
          setatr(0x13);
     }
     printf("%s ",wgmrec.winfnm);
     fldnum=NAMFLD;
     supcsrecs();
}

VOID
dftosm(VOID)                       /* set up default settings              */
{
     setmem(&wgmrec,RECLEN,0);
     wgmrec.newusr=NEWUSR;
     wgmrec.conmth=TELNET;
     wgmrec.bldwht='F';
}

VOID
supcsrecs(VOID)                    /* get C/S module information           */
{
     GBOOL fstlin=TRUE,fsttok;
     INT mdfidx=0,i,nactvmdfs=0;
     CHAR *mdfbuf,**actvmdfs,*tokptr;
     CSMODREC *csrec;

     if (tfsopn("wgsmdfs.lst") != 1) {
          catastro("wgsmdfs.lst not found!");
     }
     while (tfsrdl() != TFSDUN) {
          switch (tfstate) {
          case TFSLIN:
               if (fstlin) {
                    nactvmdfs=atoi(tfsbuf);
                    actvmdfs=(CHAR **)alczer(nactvmdfs*sizeof(CHAR *));
                    for (i=0 ; i < nactvmdfs ; i++) {
                         actvmdfs[i]=alczer(GCMAXFNM);
                    }
                    fstlin=FALSE;
               }
               else {
                    stlcpy(actvmdfs[mdfidx],tfsbuf,GCMAXFNM);
                    mdfidx++;
               }
               break;
          }
     }
     csmodrecs=(CSMODREC *)alczer(nactvmdfs*sizeof(CSMODREC));
     for (i=0 ; i < nactvmdfs ; i++) {
          mdfbuf=scnmdf(actvmdfs[i],"Client app EXE:");
          if (strlen(mdfbuf) > 0) {
               csrec=&csmodrecs[ncsmods];
               stlcpy(csrec->csexenam,mdfbuf,GCMAXFNM);
               stlcpy(csrec->mdffil,actvmdfs[i],GCMAXFNM);
               stlcpy(csrec->modesc,gmdnam(actvmdfs[i]),MNMSIZ);
               if (tfsopn(actvmdfs[i]) != 1) {
                    catastro(spr("Error opening %s!",actvmdfs[i]));
               }
               fsttok=TRUE;
               while (tfsrdl() != TFSDUN) {
                    if (tfstate == TFSLIN
                     && tfspfx("Client app support files:")) {
                         if (csrec->asfils == NULL) {
                              csrec->asfils=alczer(strlen(tfspst)+1);
                         }
                         else {
                              csrec->asfils=alcrsz(csrec->asfils,
                                                   strlen(csrec->asfils)+1,
                                                   strlen(csrec->asfils)+
                                                            strlen(tfspst)+1+1);
                         }
                         tokptr=strtok(tfspst,DELIMS);
                         do {
                              if (!fsttok) {
                                   strcat(csrec->asfils," ");
                              }
                              else {
                                   fsttok=FALSE;
                              }
                              strcat(csrec->asfils,tokptr);
                         } while ((tokptr=strtok(NULL,DELIMS)) != NULL);
                    }
               }
               ncsmods++;
          }
     }
     csmodrecs=(CSMODREC *)alcrsz(csmodrecs,nactvmdfs*sizeof(CSMODREC),
                                  ncsmods*sizeof(CSMODREC));
     qsort((VOID *)csmodrecs,ncsmods,sizeof(CSMODREC),cssort);
     for (i=0 ; i < nactvmdfs ; i++) {
          free(actvmdfs[i]);
     }
     free(actvmdfs);
}

VOID
dsphlp(VOID)                       /* display help for an edit field       */
{
     nsexploto(scntbl[1],0,14,66,17,HELPX,HELPY3);
     switch (fldnum) {
     case NAMFLD:
          nsexploto(scntbl[1],0,0,66,2,HELPX,HELPY3);
          break;
     case CONFLD:
          nsexploto(scntbl[1],0,3,66,6,HELPX,HELPY3);
          break;
     case PHOFLD:
          nsexploto(scntbl[2],0,0,66,0,HELPX,HELPY2);
          break;
     case SRVFLD:
          nsexploto(scntbl[2],0,1,66,1,HELPX,HELPY2);
          break;
     case DOMFLD:
          nsexploto(scntbl[2],0,18,66,18,HELPX,HELPY2);
          break;
     case NEWFLD:
          nsexploto(scntbl[1],0,7,66,10,HELPX,HELPY3);
          break;
     case LNMFLD:
          nsexploto(scntbl[1],0,18,66,21,HELPX,HELPY3);
          break;
     case LPWFLD:
          nsexploto(scntbl[1],0,22,66,22,HELPX,HELPY3);
          break;
     case BLDFLD:
          nsexploto(scntbl[6],0,21,66,22,HELPX,HELPY2);
          break;
     case FNMFLD:
          nsexploto(scntbl[6],0,23,66,24,HELPX,HELPY2);
          break;
     }
}

VOID
chkvalc(VOID)                      /* determines what last edtval char was */
{
     switch (edtvalc) {
     case CRSRDN:
     case TAB:
     case 10:
     case 13:
          switch (fldnum) {
          case NAMFLD:
               fldnum=CONFLD;
               break;
          case CONFLD:
               switch (wgmrec.conmth) {
               case MODEM:
                    fldnum=PHOFLD;
                    break;
               case LAN:
                    fldnum=SRVFLD;
                    break;
               case TELNET:
                    fldnum=DOMFLD;
                    break;
               default:
                    fldnum=NEWFLD;
                    break;
               }
               break;
          case PHOFLD:
               fldnum=NEWFLD;
               break;
          case SRVFLD:
               fldnum=NEWFLD;
               break;
          case DOMFLD:
               fldnum=NEWFLD;
               break;
          case NEWFLD:
               if (wgmrec.newusr == NEWUSR) {
                    fldnum=BLDFLD;
               }
               else {
                    fldnum=LNMFLD;
               }
               break;
          case LPWFLD:
               fldnum=BLDFLD;
               break;
          case BLDFLD:
               if (bldwht[0] =='F') {
                    fldnum=FNMFLD;
               }
               else {
                    fldnum=NAMFLD;
               }
               break;
          case FNMFLD:
               fldnum=NAMFLD;
               break;
          default:
               ++fldnum;
               break;
          }
          break;
     case CRSRUP:
     case BAKTAB:
          switch (fldnum) {
          case NAMFLD:
               if (wgmrec.bldwht == 'F') {
                    fldnum=FNMFLD;
               }
               else {
                    fldnum=BLDFLD;
               }
               break;
          case CONFLD:
               fldnum=NAMFLD;
               break;
          case PHOFLD:
               fldnum=CONFLD;
               break;
          case SRVFLD:
               fldnum=CONFLD;
               break;
          case DOMFLD:
               fldnum=CONFLD;
               break;
          case NEWFLD:
               switch (wgmrec.conmth) {
               case MODEM:
                    fldnum=PHOFLD;
                    break;
               case LAN:
                    fldnum=SRVFLD;
                    break;
               case TELNET:
                    fldnum=DOMFLD;
                    break;
               default:
                    fldnum=CONFLD;
                    break;
               }
               break;
          case BLDFLD:
               if (wgmrec.newusr == NEWUSR) {
                    fldnum=NEWFLD;
               }
               else {
                    fldnum=LPWFLD;
               }
               break;
          case FNMFLD:
               fldnum=BLDFLD;
               break;
          default:
               --fldnum;
               break;
          }
          break;
     case ESC:
          wgmdwn(FALSE);
          break;
     }
}

GBOOL
vsysnam(                           /* online service name valrou           */
INT c)
{
     if (!chkact(c)) {
          return(FALSE);
     }
     if (c >= 32 && c < 127) {
          return(TRUE);
     }
     return(FALSE);
}

GBOOL
vconmth(                           /* connectivity method valrou           */
INT c,
CHAR *stg)
{
     if (!chkact(c)) {
          return(FALSE);
     }
     if (c != 32) {
          return(FALSE);
     }
     switch (wgmrec.conmth) {
     case MODEM:
          strcpy(stg,"SERIAL");
          wgmrec.conmth=SERIAL;
          break;
     case SERIAL:
          strcpy(stg,"LAN");
          wgmrec.conmth=LAN;
          break;
     case LAN:
          strcpy(stg,"TELNET");
          wgmrec.conmth=TELNET;
          break;
     default:
          strcpy(stg,"MODEM");
          wgmrec.conmth=MODEM;
          break;
     }
     switch (wgmrec.conmth) {
     case MODEM:
          setatr(0x1F);
          clrlin();
          locate(7,9);
          printf("       Phone number: ");
          setatr(0x1E);
          printf("%s",wgmrec.syspho);
          break;
     case LAN:
          setatr(0x1F);
          clrlin();
          locate(7,9);
          printf("        Server name: ");
          setatr(0x1E);
          printf("%s",wgmrec.srvnam);
          break;
     case TELNET:
          setatr(0x1F);
          clrlin();
          locate(7,9);
          printf("        Domain name: ");
          setatr(0x1E);
          printf("%s",wgmrec.dmnnam);
          break;
     default:
          setatr(0x1F);
          clrlin();
          break;
     }
     return(FALSE);
}

VOID
clrlin(VOID)                       /* clears line before printing info     */
{
     locate(7,9);
     printf("                                 ");
     printf("                                 ");
}

GBOOL
vsyspho(                           /* online service phone number valrou   */
INT c)
{
     if (!chkact(c)) {
          return(FALSE);
     }
     return((c >= '0' && c <= '9') || c == '-' || c == '('
          || c == ')' || c == '/');
}

GBOOL
vsrvnam(                           /* online service server name valrou    */
INT c)
{
     if (!chkact(c)) {
          return(FALSE);
     }
     if (c >= 32 && c < 127) {
          return(TRUE);
     }
     return(FALSE);
}

GBOOL
vdmnnam(                           /* online service domain name valrou    */
INT c)
{
     if (!chkact(c)) {
          return(FALSE);
     }
     if (c > 32 && c < 127) {
          return(TRUE);
     }
     return(FALSE);
}

GBOOL
vnewusr(                           /* log on as new user valrou            */
INT c,
CHAR *stg)
{
     if (!chkact(c)) {
          return(FALSE);
     }
     if (c != 32) {
          return(FALSE);
     }
     if (toupper(stg[0]) == 'Y') {
          strcpy(stg,"NO");
          wgmrec.newusr=!NEWUSR;
     }
     else {
          strcpy(stg,"YES");
          wgmrec.newusr=NEWUSR;
     }
     if (wgmrec.newusr == NEWUSR) {
          setatr(0x13);
     }
     else {
          setatr(0x1E);
     }
     locate(28,12);
     printf("%s",wgmrec.lognam);
     locate(28,13);
     printf("%s",wgmrec.logpsw);
     setatr(0x1E);
     return(FALSE);
}

GBOOL
vlognam(                           /* user login name valrou               */
INT c)
{
     if (!chkact(c)) {
          return(FALSE);
     }
     return(isuidc(c));
}

GBOOL
vlogpsw(                           /* user password valrou                 */
INT c)
{
     if (!chkact(c)) {
          return(FALSE);
     }
     return(c <= 255 && (isalnum(c) || ispunct(c)));
}

GBOOL
vbldwht(                           /* build what valrou                    */
INT c,
CHAR *stg)
{
     if (!chkact(c)) {
          return(FALSE);
     }
     if (c != 32) {
          return(FALSE);
     }
     if (toupper(stg[0]) == 'F') {
          strcpy(stg,"DISK");
          setatr(0x13);
     }
     else {
          strcpy(stg,"FILE");
          setatr(0x1E);
     }
     locate(55,15);
     printf("%s ",wgmrec.winfnm);
     setatr(0x1E);
     wgmrec.bldwht=stg[0];
     return(FALSE);
}

GBOOL
vwinfil(                           /* Windows .EXE file name valrou        */
INT c,
CHAR *stg)
{
     if (!chkact(c)) {
          return(FALSE);
     }
     return(strlen(stg) <= GCMAXFILE && isvalfc(c) && c != '.' && c != ' ');
}

GBOOL
chkact(                            /* check if action should be performed  */
INT c)                             /*   last value of edtvalc              */
{
     GBOOL retval=TRUE;

     switch (c) {
     case F9:
          chsmods();
          retval=FALSE;
          break;
     case F10:
          retval=chkbld();
          break;
     }
     return(retval);
}

VOID
chsmods(VOID)                      /* select modules for inclusion         */
{
     GBOOL selecting=TRUE;
     INT i,key,chsidx;
     CHAR *savscn;
     FILE *modlsfp;

     if (modlchcs == NULL) {
          modlchcs=(CHAR **)alczer(ncsmods*sizeof(CHAR *));
          for (i=0 ; i < ncsmods ; i++) {
               modlchcs[i]=alczer(MCHCSZ);
               setmem(modlchcs[i],MCHCSZ-1,' ');
               movmem(csmodrecs[i].modesc,&modlchcs[i][2],
                      strlen(csmodrecs[i].modesc));
          }
     }
     if (tfsopn("galinmod.lst") == 1) {
          while (tfsrdl() != TFSDUN) {
               switch (tfstate) {
               case TFSLIN:
                    for (i=0 ; i < ncsmods ; i++) {
                         if (sameas(tfsbuf,csmodrecs[i].mdffil)) {
                              selchc(i,TRUE,modlchcs);
                         }
                    }
                    break;
               }
          }
     }
     cursiz(GVIDNOCURS);
     scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
     proff(0,0);
     explodeto(scntbl[6],0,0,37,20,20,2);
     proff(0,0);
     supchc(ncsmods,modlchcs,25,3,52,17,TRUE);
     dspchc();
     while (selecting) {
          key=getchc();
          switch (key) {
          case F3:
               for (i=0 ; i < ncsmods ; i++) {
                    selchc(i,TRUE,modlchcs);
               }
               dspchc();
               break;
          case F4:
               for (i=0 ; i < ncsmods ; i++) {
                    selchc(i,FALSE,modlchcs);
               }
               dspchc();
               break;
          case F10:
               if ((modlsfp=fopen(MODLSFIL,FOPWA)) == NULL) {
                    catastro(spr("Error writing to %s!",MODLSFIL));
               }
               for (i=0 ; i < ncsmods ; i++) {
                    if (ISSEL(i)) {
                         fprintf(modlsfp,"%s\n",csmodrecs[i].mdffil);
                    }
               }
               fclose(modlsfp);
               selecting=FALSE;
               break;
          case ' ':
               chgchc(curchc);
               break;
          default:
               if ((chsidx=hdlchc(key)) == -ESC) {
                    selecting=FALSE;
               }
               else {
                    if (chsidx != ncsmods) {
                         chgchc(chsidx);
                    }
               }
          }
     }
     mem2scn(savscn,0,GVIDSCNSIZ);
     free(savscn);
}

VOID
chgchc(                            /* change selection choice in module lst*/
INT chsidx)                        /*   index of choice to change          */
{
     if (ISSEL(chsidx)) {
          selchc(chsidx,FALSE,modlchcs);
     }
     else {
          selchc(chsidx,TRUE,modlchcs);
     }
     dspchc();
}

VOID
selchc(                            /* select/unselect a choice in mod list */
INT idx,                           /*   choice in question                 */
GBOOL selec,                       /*   TRUE to select, FALSE to unselect  */
CHAR **modlchcs)                   /*   choose list of modules             */
{
     if (selec) {
          modlchcs[idx][LSELPOS]=LSELCHR;
          modlchcs[idx][RSELPOS]=RSELCHR;
     }
     else {
          modlchcs[idx][LSELPOS]=UNSELCHR;
          modlchcs[idx][RSELPOS]=UNSELCHR;
     }
}

INT
cssort(                            /* sort callback function for qsort()   */
const VOID *rec1,
const VOID *rec2)
{
     CSMODREC *r1,*r2;

     r1=(CSMODREC *)rec1;
     r2=(CSMODREC *)rec2;
     return(strcmp(r1->modesc,r2->modesc));
}

GBOOL
chkbld(VOID)                       /* check to see if we're gonna build    */
{
#ifdef GCDOS
     if (sizmem() < MINMEM) {
          explodeto(scntbl[5],0,0,48,9,15,6);
          do {
          } while (getchc() != 13);
          wgmdwn(TRUE);
     }
#endif
     if (!ok2sav()) {
          if (bldwht[0] == 'F') {
               reqwrn(FILBLD);
          }
          else {
               reqwrn(DSKBLD);
          }
          return(FALSE);
     }
     upddsp();
     if (bldwht[0] == 'D') {
          prewrn();
          explodeto(scntbl[3],0,4,33,7,21,7);
          do {
               if ((drvchc=getchc()) == ESC) {
                    wgmdwn(FALSE);
               }
          } while (toupper(drvchc) != 'A' && toupper(drvchc) != 'B');
          pstwrn();
     }
     dobld();
     wgmdwn(TRUE);
     return(TRUE);
}

GBOOL
ok2sav(VOID)                       /* ensure all req'd fields are filled   */
{
     INT retval=TRUE;
     CHAR tmpnam[NAMSIZ],tmpsrv[SRVSIZ];

     stlcpy(tmpnam,wgmrec.sysnam,NAMSIZ);
     stlcpy(tmpsrv,wgmrec.srvnam,SRVSIZ);
     rmvwht(tmpnam);
     rmvwht(wgmrec.syspho);
     rmvwht(tmpsrv);
     rmvwht(wgmrec.dmnnam);
     rmvwht(wgmrec.winfnm);
     if (tmpnam[0] == '\0') {
          retval=FALSE;
     }
     switch (wgmrec.conmth) {
     case MODEM:
          if (wgmrec.syspho[0] == '\0') {
               retval=FALSE;
          }
          break;
     case LAN:
          if (tmpsrv[0] == '\0') {
               retval=FALSE;
          }
          break;
     case TELNET:
          if (wgmrec.dmnnam[0] == '\0') {
               retval=FALSE;
          }
          break;
     }
     if (bldwht[0] == 'F') {
          if (wgmrec.winfnm[0] == '\0') {
               retval=FALSE;
          }
     }
     return(retval);
}

VOID
upddsp(VOID)                       /* updates display before disk/file bld */
{
     cursiz(GVIDNOCURS);
     proff(0,0);
     setatr(0x1E);
     switch (fldnum) {
     case NAMFLD:
          prat(28,5,"%-44.44s",wgmrec.sysnam);
          break;
     case CONFLD:
          prat(28,8,"%-7.7s",tconmth);
          break;
     case PHOFLD:
          prat(28,9,"%-16.16s",wgmrec.syspho);
          break;
     case SRVFLD:
          prat(28,9,"%-44.44s",wgmrec.srvnam);
          break;
     case DOMFLD:
          prat(28,9,"%-44.44s",wgmrec.dmnnam);
          break;
     case NEWFLD:
          prat(28,11,"%-4.4s",tnewusr);
          break;
     case LNMFLD:
          prat(28,12,"%-30.30s",wgmrec.lognam);
          break;
     case LPWFLD:
          prat(28,13,"%-10.10s",wgmrec.logpsw);
          break;
     case BLDFLD:
          prat(14,15,"%-4.4s",bldwht);
          break;
     case FNMFLD:
          prat(55,15,"%-8.8s",wgmrec.winfnm);
          break;
     }
}

VOID
reqwrn(                            /* not all req'd fields filled out      */
INT dskbld)                        /*   building disk or file?             */
{
     prewrn();
     printf("\7");
     if (dskbld) {
          nsexploto(scntbl[2],0,2,66,5,HELPX,HELPY3);
     }
     else {
          nsexploto(scntbl[2],0,6,66,9,HELPX,HELPY3);
     }
     do {
     } while (getchc() != 13);
     pstwrn();
}

VOID
dobld(VOID)                        /* build file/disk                      */
{
     CHAR **incmdfs=NULL,appid[AIDSIZ],incdir[GCMAXPTH],*savscn,*supsav,
          cmdlin[80];
     CHAR winexe[GCMAXFNM],filbuf[GCMAXFNM];
     INT i,j,ninc=0,nasfils,pkrc;
     GBOOL included,hasshr,addedft=FALSE,inwgm,isexp;
     CSMODREC *csrec;
     FILE *wupdfp,*fp;
     struct ffblk fb;

     scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
     proff(0,0);
     explodeto(scntbl[6],38,0,75,5,20,8);
     setatr(0x30);
     locate(35,10);
     printf("preparing files...");
     deldir(INSTMP);
     if (MKDIR(INSTMP) != 0) {
          catastro("Unable to create temporary directory %s!",INSTMP);
     }

     // copy installation support files
     for (i=0 ; i < NUMSUP ; i++) {
          cpyfil("wgminst",supfil[i]);
     }
     // end

     // get incmdfs[] ready
     if (tfsopn("galinmod.lst") == 1) {
          incmdfs=(CHAR **)alczer(ncsmods*sizeof(CHAR *));
          while (tfsrdl() != TFSDUN) {
               if (tfstate == TFSLIN) {
                    incmdfs[ninc]=alczer(GCMAXFNM);
                    stlcpy(incmdfs[ninc],tfsbuf,GCMAXFNM);
                    ninc++;
               }
          }
     }
     // end

     // prepare user screen for compression display
     scn2mem(supsav=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
     nsexploto(scntbl[0],0,22,79,22,0,18);
     scnputw(19*80*2,' ',0x07,6*80);
     // end

     // compress app-specific files contained in csmodrecs[]
     for (i=0 ; i < ncsmods ; i++) {
          csrec=&csmodrecs[i];
          for (j=0,included=FALSE ; j < ninc ; j++) {
               if (sameas(csrec->mdffil,incmdfs[j])) {
                    included=TRUE;
                    break;
               }
          }
          if (included) {
               fileparts(GCPART_FILE,csrec->mdffil,appid,AIDSIZ);
               comprfil(appid,csrec->csexenam,TRUE);
               if (csrec->asfils != NULL) {
                    nasfils=itemcntd(csrec->asfils," ");
                    for (j=0 ; j < nasfils ; j++) {
                         comprfil(appid,itemidxd(csrec->asfils,j," "),TRUE);
                    }
               }
          }
     }
     // end

     // compress baseline WGM files, add appropriate files to ssfils[]
     if (tfsopn("gcsvcman" SLS "gcsvcman.lst") != 1) {
          catastro("SUPINS: error opening gcsvcman.lst!");
     }
     while (tfsrdl() != TFSDUN) {
          if (tfstate == TFSLIN) {
               if (!sameas(tfsbuf,"wgm.ver")) {
                    comprfil("gcsvcman",tfsbuf,FALSE);
                    if (samend(tfsbuf,".dll") || samend(tfsbuf,".vbx")
                     || samend(tfsbuf,".exe")) {
                         isexp=FALSE;
                         for (i=0 ; i < NUMEXP ; i++) {
                              if (sameas(tfsbuf,exp2win[i])) {
                                   isexp=TRUE;
                                   break;
                              }
                         }
                         if (!isexp) {
                              add2ss(tfsbuf);
                         }
                    }
               }
               else {
                    cpyfil("gcsvcman",tfsbuf);
               }
          }
     }
     // end

     // add shared support files listed in incmdfs[] to ssfils[]
     for (i=0 ; i < ninc ; i++) {
          if (tfsopn(incmdfs[i]) != 1) {
               catastro("DOBLD: error opening %s!",incmdfs[i]);
          }
          hasshr=FALSE;
          while (tfsrdl() != TFSDUN) {
               if (tfstate == TFSLIN) {
                    if (sameto("Shared support files:",tfsbuf)) {
                         hasshr=TRUE;
                         tfsabt();
                    }
               }
          }
          if (hasshr) {
               if (tfsopn(incmdfs[i]) != 1) {
                    catastro("DOBLD: error opening %s for processing!",
                             incmdfs[i]);
               }
               while (tfsrdl() != TFSDUN) {
                    if (tfstate == TFSLIN) {
                         if (tfspfx("Shared support files:")) {
                              unpad(tfspst);
                              add2ss(tfspst);
                         }
                    }
               }
          }
          else {
               if (!addedft) {
                    add2ss(OLDSSFLS);
                    addedft=TRUE;
               }
          }
     }

     // now actually compress shared support files listed in ssfils[],
     //   and list them to _WINUPD.LST
     if ((wupdfp=fopen(spr("%s" SLS "_winupd.lst",INSTMP),FOPWA)) == NULL) {
          catastro("Error opening _winupd.lst for output!");
     }
     if ((fp=fopen("gcsvcman" SLS "gcsvcman.lst",FOPRA)) == NULL) {
          catastro("SUPINSTMP: error opening gcsvcman.lst!");
     }
     for (i=0 ; i < nssfils ; i++) {
          inwgm=FALSE;
          rewind(fp);
          while (fgets(filbuf,GCMAXFNM,fp) != NULL) {
               unpad(filbuf);
               if (sameas(filbuf,ssfils[i])) {
                    inwgm=TRUE;
                    break;
               }
          }
          if (!inwgm) { // already compressed from step before
               comprfil("galssf",ssfils[i],FALSE);
          }
          fprintf(wupdfp,"%s\n",ssfils[i]);
     }
     fclose(fp);
     // end

     // compress the readme file
     comprfil("wgminst","readme.wri",FALSE);
     // end

     // cleanup
     fclose(wupdfp);
     mem2scn(supsav,0,GVIDSCNSIZ);
     free(supsav);
     if (incmdfs != NULL) {
          for (i=0 ; i < ninc ; i++) {
               free(incmdfs[i]);
          }
          free(incmdfs);
     }
     // end

     // copy any files in INCLUDE subdirectory
     stlcpy(incdir,spr("wgminst" SLS "%s",INCDIR),GCMAXPTH);
     if (fnd1st(&fb,spr("%s" SLS STAR,incdir),0)) {
          do {
               if (!sameas(fb.ff_name,INCFIL)) {
                    cpyfil(incdir,fb.ff_name);
               }
          } while (fndnxt(&fb));
     }
     // end

     // generate on-the-fly files
     makosg();
     makico();
     gendsk1();
     // end

     // put it all together
     if (bldwht[0] == 'F') {
          unpad(wgmrec.winfnm);
          sprintf(winexe,"%s.exe",wgmrec.winfnm);
          fnmcse(winexe);
          setatr(0x30);
          locate(22,11);
          printf("%-30.30s"," ");
          locate(35,10);
          printf("%-22.22s",spr("making %s...",winexe));
          lastfil(NODRIVE);
          if ((fp=fopen(spr("%s" SLS "_setup.lst",INSTMP),FOPWA)) == NULL) {
               catastro("Error opening _setup.lst for output!");
          }
          if (!fnd1st(&fb,spr("%s" SLS STAR,INSTMP),0)) {
               catastro("Error generating _setup.lst - no files found!");
          }
          do {
               fprintf(fp,"%s\n",fb.ff_name);
          } while (fndnxt(&fb));
          fprintf(fp,"wgminst.exe\n");
          fclose(fp);
          if ((pkrc=runDos(FALSE,"pkzip.exe","-# " INSTMP SLS "wgminst "
                            INSTMP SLS STAR)) != 0) {
               catastro(spr("Error %d creating wgminst.zip!",pkrc));
          }
          if (system(spr("zip2exe -o %s" SLS "wgminst > nul",INSTMP)) == -1) {
               catastro(spr("Error %d creating wgminst.exe!",errno));
          }
          if (rename("wgminst.exe",spr("%s" SLS "wgminst.exe",INSTMP)) != 0) {
               catastro(spr("Error %d moving wgminst.exe!",errno));
          }
          if (fnd1st(&fb,winexe,0)) {
               unlink(winexe);
          }
          sprintf(cmdlin,
                  "copy /b wgminst" SLS "wgmistub.exe + %s" SLS
                  "wgminst.exe %s >nul",
                  INSTMP,winexe);
          if (system(cmdlin) == -1) {
               catastro(spr("Error %d creating %s!",errno,winexe));
          }
          mem2scn(savscn,0,GVIDSCNSIZ);
          free(savscn);
          explodeto(scntbl[5],0,10,37,20,20,6);
          setatr(0x30);
          locate(37,12);
          printf("%s.",winexe);
          while (getchc() != 13) {
          }
     }
     else {
          if ((fp=fopen(spr("%s" SLS "_setup.lst",INSTMP),FOPWA)) == NULL) {
               catastro("Error opening _setup.lst for output!");
          }
          if (!fnd1st(&fb,spr("%s" SLS STAR,INSTMP),0)) {
               catastro("Error generating _setup.lst - no files found!");
          }
          do {
               if (!(sameas(fb.ff_name,"wgm.ver")
                  || sameas(fb.ff_name,"setup.exe")
                  || sameas(fb.ff_name,"setup.ins")
                  || sameas(fb.ff_name,"gcomm.bmp")
                  || sameas(fb.ff_name,"_winupd.lst")
                  || sameas(fb.ff_name,"_setup.lst")
                  || sameas(fb.ff_name,"disk.1")
                  || samend(fb.ff_name,"*.ico")
                  || samend(fb.ff_name,"*.osg"))) {
                    fprintf(fp,"%s\n",fb.ff_name);
               }
          } while (fndnxt(&fb));
          fclose(fp);
          getlsts();
          mem2scn(savscn,0,GVIDSCNSIZ);
          free(savscn);
          explodeto(scntbl[4],0,16,24,21,26,9);
          while (getchc() != 13) {
          }
     }
}

VOID
cpyfil(                            /* copy file into INSTMP directory      */
CHAR *srcdir,                      /*   source directory                   */
CHAR *srcfil)                      /*   source file                        */
{
     setatr(0x30);
     locate(22,11);
     printf("%-30.30s",spr("Copying %s...",strupr(srcfil)));
     if (!copyfile(spr("%s" SLS "%s",srcdir,srcfil),
                   spr("%s" SLS "%s",INSTMP,srcfil))) {
          catastro(spr("CPYFIL: error %d copying %s",errno,srcfil));
     }
}

VOID
comprfil(                          /* compress file into INSTMP directory  */
CHAR *srcdir,                      /*   source directory                   */
CHAR *srcfil,                      /*   source file                        */
GBOOL incsdir)                     /*   include subdirectory info?         */
{
     INT comprc;
#ifdef GCDOS
     CHAR cmdbuf[128];
#endif
#ifdef GCWINNT
     CHAR cmdbuf[260];
#endif

     setatr(0x30);
     locate(22,11);
     printf("%-30.30s",spr("Compressing %s...",strupr(srcfil)));
     locate(0,19);
     if (incsdir) {
          sprintf(cmdbuf,"%s" SLS "%s " INSTMP SLS "%s %s -i",
                  srcdir,srcfil,cnv2is(srcfil),srcdir);
     }
     else {
          sprintf(cmdbuf,"%s" SLS "%s " INSTMP SLS "%s",
                  srcdir,srcfil,cnv2is(srcfil));
     }
     if ((comprc=runDos(FALSE,"wgsiscom.exe",cmdbuf)) != 0) {
          catastro(spr("COMPRFIL: error %d compressing %s" SLS "%s!",
                       comprc,srcdir,srcfil));
     }
}

CHAR *                             /*   returns ptr to converted file name */
cnv2is(                            /* convert file name to I-shield format */
CHAR *filnam)                      /*   file name to convert               */
{
     INT i,count;
     CHAR *ptr;
     static CHAR tmpnam[GCMAXFNM];

     stlcpy(tmpnam,filnam,GCMAXFNM);
     if (strchr(tmpnam,'.') == NULL) {
          return(stlcat(tmpnam,EXTFIL,GCMAXFNM));
     }
     count=strlen(tmpnam)-(GCMAXEXT-1);
     for (i=GCMAXFNM-(GCMAXEXT-1) ; i > count ; i--) {
          if (tmpnam[i] == '.') {
               break;
          }
          tmpnam[i]='_';
     }
     if (strlen(ptr=strchr(tmpnam,'.')) > GCMAXEXT+1) {
          ptr[GCMAXEXT+1]='\0';
     }
     return(tmpnam);
}

VOID
add2ss(                            /* add file(s) shared support files list*/
CHAR *fils2add)                    /*   file(s) to add                     */
{
     INT ninstg,i,j;
     GBOOL alrdyin,fsttok;
     CHAR *curfil,*filstg,*tokptr;

     filstg=alczer(strlen(fils2add)+1);
     tokptr=strtok(fils2add,DELIMS);
     fsttok=TRUE;
     do {
          if (!fsttok) {
               strcat(filstg," ");
          }
          else {
               fsttok=FALSE;
          }
          strcat(filstg,tokptr);
     } while ((tokptr=strtok(NULL,DELIMS)) != NULL);
     ninstg=itemcntd(filstg," ");
     if (nssfils == 0) {
          ssfils=(CHAR **)alczer(ninstg*sizeof(CHAR *));
          for (i=0 ; i < ninstg ; i++) {
               ssfils[i]=alczer(GCMAXFNM);
               stlcpy(ssfils[i],itemidxd(filstg,i," "),GCMAXFNM);
          }
          nssfils=ninstg;
     }
     else {
          for (i=0 ; i < ninstg ; i++) {
               curfil=itemidxd(filstg,i," ");
               for (j=0,alrdyin=FALSE ; j < nssfils ; j++) {
                    if (sameas(curfil,ssfils[j])) {
                         alrdyin=TRUE;
                         break;
                    }
               }
               if (!alrdyin) {
                    ssfils=(CHAR **)alcrsz(ssfils,nssfils*sizeof(CHAR *),
                                           (nssfils+1)*sizeof(CHAR *));
                    ssfils[nssfils]=alczer(GCMAXFNM);
                    stlcpy(ssfils[nssfils],curfil,GCMAXFNM);
                    nssfils++;
               }
          }
     }
     free(filstg);
}

VOID
makosg(VOID)                       /* build <regno>.OSG and output it      */
{
     CHAR osgfil[FILSIZ];
     FILE *osgfp;
     struct ffblk fb;

     stlcpy(osgfil,spr("%s.osg",regnum),FILSIZ);
     if ((osgfp=fopen(spr("%s" SLS "%s",INSTMP,osgfil),FOPWA)) == NULL) {
          catastro("Error opening OSG file for output.");
     }
     fprintf(osgfp,"0\n");
     fprintf(osgfp,"-1\n");
     fprintf(osgfp,"330\n");
     fprintf(osgfp,"75\n");
     kilwht(wgmrec.sysnam);
     fprintf(osgfp,"%s\n",wgmrec.sysnam);
     switch (wgmrec.conmth) {
     case MODEM:
          fprintf(osgfp,"%s\n",wgmrec.syspho);
          break;
     case LAN:
          fprintf(osgfp,"%s\n",wgmrec.srvnam);
          break;
     case TELNET:
          fprintf(osgfp,"%s\n",wgmrec.dmnnam);
          break;
     case SERIAL:
          fprintf(osgfp,"\n");
          break;
     }
     switch (wgmrec.newusr) {
     case NEWUSR:
          fprintf(osgfp,"%c\n\n",1);
          break;
     default:
          fprintf(osgfp,"%s\n%s\n",wgmrec.lognam,wgmrec.logpsw);
          break;
     }
     fprintf(osgfp,"%s\n",rnosid(regnum));
     fprintf(osgfp,"60\n");
     fprintf(osgfp,"10\n");
     fprintf(osgfp,"%d\n",FLGNXT+FLGICO+FLGACN+invser()+FLGSCS+FLGSAN+teltyp());
     fclose(osgfp);
     if (fnd1st(&fb,spr("%s" SLS "%s",INSTMP,osgfil),0)) {
          osgsiz=fb.ff_fsize;
     }
}

VOID
kilwht(                            /* kill true whitespace at end of line  */
CHAR *str)
{
     INT i,cnt;

     i=strlen(str);
     for (cnt=i-1 ; cnt > 0 ; cnt--) {
          if (str[cnt] == ' ' || str[cnt] == '\n' || str[cnt] == '\r') {
               str[cnt]='\0';
          }
          else {
               break;
          }
     }
}

CHAR *
rnosid(                            /* convert btu registration # to sysid  */
CHAR *regno)
{
     INT i;
     static CHAR retval[SIDSIZ];

     for (i=0 ; i < SIDSIZ-1 ; i++) {
          retval[i]=(((regno[i*2]-'0')*10+regno[i*2+1]-'0')|0x80);
     }
     return(retval);
}

INT
invser(VOID)                       /* if serial/modem, return FLGSER       */
{
     INT retval;

     switch (wgmrec.conmth) {
     case SERIAL:
     case MODEM:
          retval=FLGSER;
          break;
     default:
          retval=0;
          break;
     }
     return(retval);
}

INT
teltyp(VOID)                       /* if LAN type is telnet, return FLGIP  */
{
     INT retval;

     switch (wgmrec.conmth) {
     case TELNET:
          retval=FLGIP;
          break;
     default:
          retval=0;
          break;
     }
     return(retval);
}

VOID
makico(VOID)                       /* make and move <regno>.ICO and output */
{
     struct ffblk foo;
     CHAR newico[FILSIZ],cmdlin[80];

     stlcpy(newico,regnum,FILSIZ);
     stlcat(newico,".ico",FILSIZ);
     if (icofil[0] != '\0' && fnd1st(&foo,spr("%s" SLS "%s",ICODIR,icofil),0)) {
          icosiz=foo.ff_fsize;
     }
     if (icofil[0] != '\0') {
          sprintf(cmdlin,"copy %s" SLS "%s %s" SLS "%s > nul",
                  ICODIR,icofil,INSTMP,newico);
          if (system(cmdlin) == -1) {
               catastro(spr("Copy error=%d, file=%s",errno,icofil));
          }
     }
}

VOID
gendsk1(VOID)                      /* generate DISK.1                      */
{
     LONG cmpsiz=0L,icosiz,osgsiz;
     FILE *dfp;

     if ((dfp=fopen(spr("%s" SLS "disk.1",INSTMP),FOPWA)) == NULL) {
          catastro("GENDSK1: Error opening disk.1!");
     }
     cntdir(spr("%s" SLS "*.??_",INSTMP));
     cmpsiz=cmpsiz+numbyts;
     cntdir(spr("%s" SLS "*.ico",INSTMP));
     cmpsiz+=numbyts;
     icosiz=numbyts;
     cntdir(spr("%s" SLS "*.osg",INSTMP));
     cmpsiz+=numbyts;
     osgsiz=numbyts;
     fprintf(dfp,"%ld\n",cmpsiz);
     fprintf(dfp,"%ld\n",icosiz+osgsiz);
     fclose(dfp);
}

VOID
getlsts(VOID)                      /* get file lists for disk build        */
{
     INT i;
     struct ffblk fb;
     GBOOL infst,addit,bomb;

     fstlst=(struct filary *)alczer(NUMFST*sizeof(struct filary));
     for (i=0,fstptr=fstlst ; i < NUMFST ; i++) {
          addit=TRUE;
          if (!fnd1st(&fb,spr("%s" SLS "%s",INSTMP,fstfil[i]),0)) {
               if (!sameas(fstfil[i],"*.ico")) {
                    bomb=TRUE;
               }
               else {
                    if (icofil[0] == '\0') {
                         bomb=FALSE;
                         addit=FALSE;
                    }
                    else {
                         bomb=TRUE;
                    }
               }
               if (bomb) {
                    catastro("GETLSTS: unable to find %s!",fstfil[i]);
               }
          }
          if (addit) {
               stlcpy(fstptr->filnam,fb.ff_name,FILSIZ);
               fstptr->fsize=fb.ff_fsize;
               fstptr->asize=fb.ff_fsize;
               fstptr->flag=0;
               fstptr++;
               numfst++;
          }
     }
     cntdir(spr("%s" SLS STAR,INSTMP));
     fillst=(struct filary *)alczer(((INT)numfils-numfst)
                                    *sizeof(struct filary));
     if (!(fnd1st(&fb,spr("%s" SLS STAR,INSTMP),0))) {
          catastro("GETLSTS: error generating fillst - no files found!");
     }
     filptr=fillst;
     numfil=0;
     do {
          for (i=0,infst=FALSE ; i < numfst ; i++) {
               if (sameas(fb.ff_name,fstlst[i].filnam)) {
                    infst=TRUE;
                    break;
               }
          }
          if (!infst) {
               stlcpy(filptr->filnam,fb.ff_name,FILSIZ);
               filptr->fsize=fb.ff_fsize;
               filptr->asize=fb.ff_fsize;
               filptr->flag=0;
               filptr++;
               numfil++;
          }
     } while (fndnxt(&fb));
     if (toupper(drvchc) == 'A') {
          fildsk(ADRIVE);
     }
     else {
          fildsk(BDRIVE);
     }
}

VOID
fildsk(                            /* put files in list onto disks         */
INT drvnum)                        /*   drive number to output to          */
{
     INT dskcnt,done,stat,igot;
     LONG dsksiz,adjsiz;
     CHAR filenam[FILSIZ];

     predsk();
     dskcnt=1;
     adjsiz=0L;
     done=FALSE;
     prewrn();
     cursiz(GVIDNOCURS);
     explodeto(scntbl[3],0,0,45,3,15,6);
     locate(56,7);
     setatr(0x30);
     printf(drvnum == 1 ? "A:" : "B:");
     do {
          igot=getchc();
          if (igot == ESC) {
               wgmdwn(TRUE);
          }
     } while (igot != 13);
     pstwrn();
     srtlst();
     chkdrv(drvnum);
     adjlst(clsize(drvnum == 1 ? "A:" : "B:"));
     todsk(FST,drvnum);
     dsksiz=getdfre(drvnum)-512L;
     while (!done) {
          stat=getfil(filenam,&adjsiz,dsksiz);
          if (stat == GOTFILE) {
               dodsk(filenam,drvnum);
               dsksiz=getdfre(drvnum)-512L;
          }
          else if (stat == NEWDISK) {
               prewrn();
               explodeto(scntbl[3],0,8,39,11,20,9);
               locate(55,10);
               setatr(0x30);
               printf(drvnum == 1 ? "A:" : "B:");
               do {
                    igot=getchc();
                    if (igot == ESC) {
                         wgmdwn(TRUE);
                    }
               } while (igot != 13);
               pstwrn();
               prewrn();
               cursiz(GVIDNOCURS);
               explodeto(scntbl[3],0,0,45,3,15,6);
               locate(56,7);
               setatr(0x30);
               printf(drvnum == 1 ? "A:" : "B:");
               do {
                    igot=getchc();
                    if (igot == ESC) {
                         wgmdwn(TRUE);
                    }
               } while (igot != 13);
               pstwrn();
               explodeto(scntbl[3],0,12,31,16,22,8);
               dskcnt++;
               chkdrv(drvnum);
               dsksiz=getdfre(drvnum)-512L;
               dsknum(drvnum,dskcnt);
               stat=getfil(filenam,&adjsiz,dsksiz);
               if (stat == GOTFILE) {
                    dodsk(filenam,drvnum);
                    dsksiz=getdfre(drvnum)-512L;
               }
               else if (stat == NEWDISK) {
                    catastro(spr("File too large! %s",filenam));
               }
          }
          if (stat == ALLDONE) {
               lastfil(drvnum);
               done=TRUE;
          }
     }
     prewrn();
     explodeto(scntbl[3],0,8,39,11,20,9);
     locate(55,10);
     setatr(0x30);
     printf(drvnum == 1 ? "A:" : "B:");
     do {
          igot=getchc();
          if (igot == ESC) {
               wgmdwn(TRUE);
          }
     } while (igot != 13);
     pstwrn();
     pstdsk();
     free(fstlst);
     free(fillst);
}

VOID
srtlst(VOID)                       /* shell sort fillst ascending by size  */
{
     LONG tmpsiz;
     LONG tmpasiz;
     INT gap,i,j;
     INT tmpflag;
     CHAR tmpnam[FILSIZ];

     filptr=fillst;
     for (gap=numfil/2 ; gap > 0 ; gap=gap/2) {
          for (i=gap ; i < numfil ; i++) {
               for (j=i-gap ; j >= 0 ; j=j-gap) {
                    if (filptr[j].fsize > filptr[j+gap].fsize) {
                         break;
                    }
                    stlcpy(tmpnam,filptr[j].filnam,FILSIZ);
                    tmpsiz=filptr[j].fsize;
                    tmpflag=filptr[j].flag;
                    tmpasiz=filptr[j].asize;
                    stlcpy(filptr[j].filnam,filptr[j+gap].filnam,FILSIZ);
                    filptr[j].fsize=filptr[j+gap].fsize;
                    filptr[j].flag=filptr[j+gap].flag;
                    filptr[j].asize=filptr[j+gap].asize;
                    stlcpy(filptr[j+gap].filnam,tmpnam,FILSIZ);
                    filptr[j+gap].fsize=tmpsiz;
                    filptr[j+gap].flag=tmpflag;
                    filptr[j+gap].asize=tmpasiz;
               }
          }
     }
}

VOID
chkdrv(                            /* make sure this is a blank disk       */
INT drvnum)
{
     struct dfree dskfree;
     INT notgood,keyhit;

     notgood=TRUE;
     while (notgood) {
          getdfree((CHAR)drvnum,&dskfree);
          if (dskfree.df_sclus == ((UINT)-1)) {
               prelim();
               explodeto(scntbl[2],0,19,54,23,12,8);
               do {
                    keyhit=getchc();
                    if (keyhit == ESC) {
                         wgmdwn(TRUE);
                    }
               } while (keyhit != 13);
               pstlim();
          }
          else if (wrtprt(drvnum)) {
               prelim();
               explodeto(scntbl[4],39,10,75,16,22,7);
               do {
                    keyhit=getchc();
                    if (keyhit == ESC) {
                         wgmdwn(TRUE);
                    }
               } while (keyhit != 13);
               pstlim();
          }
          else {
               if (dskfree.df_avail != dskfree.df_total) {
                    prelim();
                    explodeto(scntbl[4],25,17,65,23,18,7);
                    do {
                         keyhit=getchc();
                         if (keyhit == ESC) {
                              wgmdwn(TRUE);
                         }
                         else if (toupper(keyhit) == 'D') {
                              pstlim();
                              wipdsk(drvnum);
                              keyhit=13;
                         }
                    } while (keyhit != 13);
                    pstlim();
               }
               else {
                    notgood=FALSE;
               }
          }
          if (kbhit() == ESC) {
               wgmdwn(FALSE);
          }
     }
}

GBOOL                              /*   return TRUE if disk is write prot. */
wrtprt(                            /* is disk write protected?             */
INT drvnum)                        /*   drive number (1=A:, 2=B:, etc.)    */
{
     FILE *fp;
     INT savdrv;

     ASSERT(drvnum > 0);
     savdrv=getdisk();
     setdisk(drvnum-1);
     if ((fp=fopen("test.fil",FOPWA)) == NULL) {
          setdisk(savdrv);
          return(TRUE);
     }
     fclose(fp);
     unlink("test.fil");
     setdisk(savdrv);
     return(FALSE);
}

VOID
wipdsk(                            /* wipes all contents off of a disk     */
INT drvnum)                        /*   drive number (1=A:, 2=B:, etc.)    */
{
     INT savdsk;
     struct ffblk fb;

     ASSERT(drvnum > 0);
     explodeto(scntbl[4],33,5,65,9,23,9);
     setatr(0x30);
     prat(29,2,"%s",drvnum == 1 ? "A" : "B");
     savdsk=getdisk();
     setdisk(drvnum-1);
     if (runDos(TRUE,"attrib.exe","-R -H -S " STAR " /S") != 0) {
#ifdef GCDOS
          catastro("Error spawning attrib.exe!\nBe sure your DOS "
                   "directory is in your PATH!");
#endif
#ifdef GCWINNT
          if (isWinNT()) {
               catastro("Error spawning attrib.exe!\n"
                        "Be sure your \\winnt\\system32"
                        "directory is in your PATH!");
          }
          else {
               catastro("Error spawning attrib.exe!\n"
                        "Be sure your \\windows\\command"
                        "directory is in your PATH!");
          }
#endif
     }
     if (fnd1st(&fb,STAR,FAMDIR)) {
          do {
               deldir(fb.ff_name);
          } while (fndnxt(&fb));
     }
     if (fnd1st(&fb,STAR,0)) {
          do {
               unlink(fb.ff_name);
          } while (fndnxt(&fb));
     }
     setdisk(savdsk);
}

LONG
getdfre(                           /* get amount of drive space free       */
INT drvnum)                        /*   drive number (1=A:, 2=B:, etc.)    */
{
     CHAR buf[]="A:";
     LONG f;

     buf[0]=drvnum+'A'-1;
     f=dskfre(buf);
     if (f*1024 > f) {
          f*=1024;
     }
     return(f);
}

VOID
adjlst(                            /* adjust filsiz in fillst by cluster   */
UINT clssiz)                       /*   cluster size                       */
{
     INT ctr;

     filptr=fillst;
     for (ctr=0 ; ctr < numfil ; ctr++) {
          filptr->asize=clfit(filptr->fsize,clssiz);
          filptr++;
     }
}

VOID
todsk(                             /* output a list of files to disk       */
INT lstnum,                        /*   list number                        */
INT dsknum)                        /*   drive number                       */
{
     INT numfiles,i;

     switch (lstnum) {
     case FST:
          numfiles=numfst;
          break;
     }
     for (i=0; i < numfiles ; i++) {
          switch (lstnum) {
          case FST:
               explodeto(scntbl[3],0,12,31,16,22,8);
               dodsk(fstlst[i].filnam,dsknum);
               break;
          }
     }
}

INT
getfil(                            /* pick a best fit file to copy         */
CHAR *filenam,                     /*   filename to return                 */
LONG *filsize,                     /*   filesize to return                 */
LONG dsksiz)                       /*   current free drive space           */
{
     INT cnt,i;

     filptr=fillst;
     for (cnt=0 ; cnt < numfil ; cnt++) {
          if (filptr[cnt].flag == 0) {
               if (filptr[cnt].asize <= dsksiz) {
                    stlcpy(filenam,filptr[cnt].filnam,FILSIZ);
                    *filsize=filptr[cnt].asize;
                    filptr[cnt].flag=1;
                    return(GOTFILE);
               }
          }
     }
     i=0;
     for (cnt=0 ; cnt < numfil ; cnt++) {
          if (filptr[cnt].flag == 0) {
               i++;
               break;
          }
     }
     if (i > 0) {
          return(NEWDISK);
     }
     return(ALLDONE);
}

VOID
dodsk(                             /* output a file to disk                */
CHAR *filnam,                      /*   file to output                     */
INT dsknum)                        /*   drive number                       */
{
     CHAR dest[FILSIZ2];

     switch (dsknum) {
     case ADRIVE:
          stlcpy(dest,spr("A:" SLS "%s",filnam),FILSIZ2);
          break;
     default:
          stlcpy(dest,spr("B:" SLS "%s",filnam),FILSIZ2);
          break;
     }
     locate(37,10);
     setatr(0x30);
     printf("%-15.15s",spr("%s...",strupr(filnam)));
     if (system(spr("copy %s" SLS "%s %s > nul",INSTMP,filnam,dest)) == -1) {
          catastro("DODSK: error %d copying %s!",errno,filnam);
     }
}

VOID
dsknum(                            /* put DISK.n on floppy drive           */
INT drvnum,                        /*   drive number 1 or 2                */
INT dsknum)                        /*   disk number                        */
{
     CHAR fileis[FILSIZ2],*fptr,foo[4];
     FILE *dfp;
     INT c;

     fptr=fileis;
     *fptr++='A'+(drvnum-1);
     *fptr++=':';
     *fptr++=SL;
     *fptr++='d';
     *fptr++='i';
     *fptr++='s';
     *fptr++='k';
     *fptr++='.';
     stlcpy(fptr,itoa(dsknum,foo,10),4);
     fptr=fileis;
     if ((dfp=fopen(fileis,FOPWA)) == NULL) {
          catastro(spr("DSKNUM: Error opening %s!",fptr));
     }
     c=0xFF;
     fputc(c,dfp);
     fclose(dfp);
}

VOID
lastfil(                           /* output LASTDISK.FLG file             */
INT drvnum)
{
     CHAR fileis[FILSIZ2];
     FILE *dfp;

     if (bldwht[0] == 'D') {
          stlcpy(fileis,"A:" SLS "lastdisk.flg",FILSIZ2);
          fileis[0]='A'+(drvnum-1);
          if ((dfp=fopen(fileis,FOPWA)) == NULL) {
               catastro(spr("Open error, lst %s",fileis));
          }
          fprintf(dfp,"\x01");
          fclose(dfp);
     }
     else {
          stlcpy(fileis,"lastdisk.flg",FILSIZ);
          if ((dfp=fopen(spr("%s" SLS "%s",INSTMP,fileis),FOPWB)) == NULL) {
               catastro(spr("LASTFIL: Error opening %s!",fileis));
          }
          fclose(dfp);
     }
}

VOID
prewrn(VOID)                       /* steps before displaying warning msg  */
{
     if (wrnscn == NULL) {
          wrnscn=alcmem(GVIDSCNSIZ);
     }
     scn2mem(wrnscn,0,GVIDSCNSIZ);
}

VOID
pstwrn(VOID)                       /* steps after display of warning msg   */
{
     mem2scn(wrnscn,0,GVIDSCNSIZ);
}

VOID
predsk(VOID)                       /* steps before displaying warning msg  */
{
     if (dskscn == NULL) {
          dskscn=alcmem(GVIDSCNSIZ);
     }
     scn2mem(dskscn,0,GVIDSCNSIZ);
}

VOID
pstdsk(VOID)                       /* steps after display of warning msg   */
{
     mem2scn(dskscn,0,GVIDSCNSIZ);
}

VOID
prelim(VOID)                       /* steps before displaying warning msg  */
{
     if (limscn == NULL) {
          limscn=alcmem(GVIDSCNSIZ);
     }
     scn2mem(limscn,0,GVIDSCNSIZ);
}

VOID
pstlim(VOID)                       /* steps after display of warning msg   */
{
     mem2scn(limscn,0,GVIDSCNSIZ);
}

VOID
wgmdwn(                            /* shutdown routine                     */
INT update)
{
     INT i;
     struct ffblk fb;

     for (i=0 ; i < ncsmods ; i++) {
          free(csmodrecs[i].asfils);
     }
     free(csmodrecs);
     if (modlchcs != NULL) {
          for (i=0 ; i < ncsmods ; i++) {
               free(modlchcs[i]);
          }
          free(modlchcs);
     }
     if (nssfils != 0) {
          for (i=0 ; i < nssfils ; i++) {
               free(ssfils[i]);
          }
          free(ssfils);
     }
     if (wrnscn != NULL) {
          free(wrnscn);
     }
     if (dskscn != NULL) {
          free(dskscn);
     }
     if (limscn != NULL) {
          free(limscn);
     }
     unlink("wgminst" SLS "wgminst.zip");
     rename(spr("%s" SLS "wgminst.zip",INSTMP),"wgminst" SLS "wgminst.zip");
     if (!fnd1st(&fb,"wgminst" SLS "nodel.flg",0)) {
          deldir(INSTMP);
     }
     if (update) {
          if ((savfp=fopen(SAVFIL,FOPWB)) == NULL) {
               catastro("WGMDWN: Error opening wgsmkwgm.sav for output!");
          }
          if (fwrite(&wgmrec,RECLEN,1,savfp) != 1) {
               catastro("WGMDWN: Error updating wgsmkwgm.sav!");
          }
          fclose(savfp);
     }
     mem2scn(dosscn,0,GVIDSCNSIZ);
     cursiz(GVIDLILCURS);
     exit(0);
}

INT                                /*   returns value returned by program  */
runDos(                            /* run a DOS program                    */
GBOOL searchPath,                  /*   search path for program?           */
CHAR *progName,                    /*   program file name                  */
CHAR *cmdstr)                      /*   command string to pass to program  */
{
#ifdef GCDOS
     INT i;
     CHAR *cp,argstr[128],*argarr[16];

     argarr[0]=progName;
     stlcpy(argstr,cmdstr,sizeof(argstr));
     for (i=1,cp=argstr ; cp != NULL && *cp != '\0' && i < 15 ; ++i) {
          argarr[i]=skpwht(cp);
          if ((cp=strchr(cp,' ')) != NULL) {
               *cp++='\0';
          }
     }
     argarr[i]=NULL;
     if (searchPath) {
          return(spawnvp(P_WAIT,progName,argarr));
     }
     return(spawnv(P_WAIT,progName,argarr));
#endif
#ifdef GCWINNT
     STARTUPINFO si;
     PROCESS_INFORMATION pi;
     DWORD rc;
     CHAR *prog,cmdbuf[260];

     memset(&si,0,sizeof(STARTUPINFO));
     si.cb=sizeof(STARTUPINFO);
     si.dwFlags=STARTF_USESTDHANDLES;
     prog=searchPath ? NULL : progName;
     stlcpy(cmdbuf,progName,sizeof(cmdbuf));
     stlcat(cmdbuf," ",sizeof(cmdbuf));
     stlcat(cmdbuf,cmdstr,sizeof(cmdbuf));
     if (CreateProcess(prog,cmdbuf,NULL,NULL,FALSE,CREATE_DEFAULT_ERROR_MODE,
                       NULL,NULL,&si,&pi)) {
          WaitForSingleObject(pi.hProcess,INFINITE);
          GetExitCodeProcess(pi.hProcess,&rc);
          CloseHandle(pi.hProcess);
          CloseHandle(pi.hThread);
          return((INT)rc);
     }
     rc=GetLastError();
     return((INT)rc);
#endif
}

USHORT
btuTicker(VOID)                    /* keeps pascrit happy                  */
{
     return(0);
}
