/***************************************************************************
 *                                                                         *
 *   GALPRLST.C                                                            *
 *                                                                         *
 *   Copyright (c) 1994-1997 Galacticomm, Inc.    All rights reserved.     *
 *                                                                         *
 *   This is the source to the GALPRLST utility, which processes list      *
 *   files created by GALMKLST.                                            *
 *                                                                         *
 *                                                - W. Muharsky 07/21/97   *
 *                                                                         *
 ***************************************************************************/
#include "gcomm.h"
#include "errno.h"
#include "direct.h"

#define FILREV "$Revision: 4 $"

VOID inicmd(VOID);
VOID prcfil(INT lmode);
VOID runcmd(CHAR *cmd,CHAR *path,CHAR *file);
VOID usage(VOID);
VOID addsfx(VOID);
CHAR *kilwht(CHAR *str);
GBOOL inlist(CHAR *path);
VOID ad2lst(CHAR *path);
VOID prppth(CHAR *filnam,CHAR *path);
VOID opnfil(CHAR *path);
VOID dofils(VOID);
VOID chkabt(VOID);
VOID rstdir(VOID);
INT cdrdi(CHAR *);
VOID repenv(CHAR *,UINT,CHAR *,CHAR *);

#define PFXSIZE 70                 /* Maximum length of command prefix     */
#define SFXSIZE 40                 /* Maximum length of command suffix     */
#define PERLINE 0                  /* Are we processing list line-by-line? */
#define PERLIST 1                  /* Or are we zooming through the list?  */
#define FILENG 13                  /* Maximum length of file name          */
#define ERRBUF 50                  /* Maximum length of error message      */
#define PLISIZ 10                  /* Path list increment size for resize  */
#define MAXINL 200                 /* Max. number if files in PRCLIST?.LST */
#define MAXCMD 127                 /* Maximum command length               */

INT lmode;                         /* Launch mode flag: 1=list 0=line      */
INT plhdl;                         /* Handle to path list array            */
INT pmode=FALSE;                   /* Force path out and no CD \x if set   */
INT savlst=FALSE;
GBOOL addsls=FALSE;                /* add slash to command line?           */
UINT dpres=0;                      /* number of directories to preserve    */

CHAR syscmd[MAXCMD];               /* Buffer for system command            */
CHAR filnam[FILENG];               /* File name passed on command line     */
CHAR lstbuf[BUFSIZ];               /* Line read in from list file          */
CHAR cmdpfx[PFXSIZE];              /* Command line prefix                  */
CHAR cmdsfx[SFXSIZE];              /* Command line suffix (if any)         */
CHAR retdir[GCMAXPTH];             /* Directory to change to upon exit     */
CHAR naminc;                       /* PRCLIST?.LST name increment variable */

FILE *lstfil;                      /* File pointer to list file            */
FILE *pthfp;                       /* File pointer to PRCLIST?.LST file(s) */

INT
main(                              /* Main program loop                    */
INT argc,                          /*   Number of command line arguments   */
CHAR *argv[])                      /*   List of command line arguments     */
{
     INT i;
     CHAR c;

     initvid();
     setatr(0x0A);
     printf("\n");
     if (argc < 4 || argc > 8) {
          usage();
          clsvid();
          return(0);
     }
     for (i=1 ; i < argc ; i++) {
          c=argv[i][0];
          if (c == '/' || c == '-') {
               c=toupper(argv[i][1]);
               if (c == 'P') {
                    pmode=TRUE;
               }
               else if (c == 'S') {
                    savlst=TRUE;
               }
               else if (c == 'A') {
                    addsls=TRUE;
               }
               else if (c == 'D') {
                    dpres=atoi(&argv[i][2]);
                    if (dpres > 9) {
                         dpres=0;
                    }
               }
               else {
                    break;
               }
          }
          else {
               break;
          }
     }
     stzcpy(filnam,argv[i],FILENG);
     printf("GALPRLST - Processing files in %s...\n",strupr(filnam));
     printf("          (Hit Esc to abort)\n\n");
     setmem(cmdsfx,SFXSIZE,0);
     if ((lstfil=fopen(filnam,FOPRA)) == NULL) {
          catastro(spr("Cannot open file \"%s\" for input.",strupr(filnam)));
     }
     stzcpy(cmdpfx,argv[1+i],PFXSIZE);
     if (addsls) {
          stlcat(cmdpfx,"\\",PFXSIZE);
     }
     if (sameas(argv[2+i],"@F")) {
          lmode=PERLIST;
     }
     else if (sameas(argv[2+i],"F")) {
          lmode=PERLINE;
     }
     else {
          catastro(spr("Invalid launch flag: \"%s\"",strupr(argv[2+i])));
     }
     if (argc == 4+i) {
          stzcpy(cmdsfx,argv[3+i],SFXSIZE);
     }
     getcwd(retdir,GCMAXPTH);
     plhdl=newarr(PLISIZ,GCMAXPTH);
     naminc='A';
     prcfil(lmode);
     rstdir();
     fclose(lstfil);
     if (!savlst) {
          if ((unlink(filnam)) == -1) {
               setatr(0x0C);
               printf("\nError deleting list file!\n");
          }
     }
     setatr(0x0A);
     printf("\nGALPRLST finished.\n");
     setatr(0x07);
     printf("\r");
     clsvid();
     return(0);
}

VOID
inicmd(VOID)                       /* Initializes system command           */
{
     setmem(syscmd,MAXCMD,0);
     stzcpy(syscmd,cmdpfx,PFXSIZE);
}

VOID
prcfil(                            /* Process the list file                */
INT lmode)                         /*   Launch mode (0=line, 1=list)       */
{
     CHAR tmppth[GCMAXPTH],tmpbuf[GCMAXPTH],tmpfil[GCMAXPTH],filnam[GCSTRFNM];
     INT catlines=0;
     CHAR *s;
     UINT i;

     while ((fgets(lstbuf,BUFSIZ,lstfil)) != NULL) {
          if ((++catlines%100) == 0) {
               printf(" %d   \r",catlines);
          }
          chkabt();
          inicmd();
          fileparts(GCPART_PATH,lstbuf,tmppth,GCMAXPTH);
          s=&tmppth[strlen(tmppth)-1];
          if (*s == '\\' || *s == '/') {
               *s='\0';
          }
          repenv(tmppth,GCMAXPTH,"WGNT","\\wgservnt");
          repenv(tmppth,GCMAXPTH,"WGDOS","\\wgserv");
          repenv(tmppth,GCMAXPTH,"WGDEV","\\wgdev");
          repenv(tmppth,GCMAXPTH,"WGMAN","\\wgman");
          if (tmppth[0] == '\\') {
               stzcpy(tmppth,spr("C:%s",tmppth),GCMAXPTH);
          }
          fileparts(GCPART_FNAM,lstbuf,tmpfil,GCMAXPTH);
          for (i=0 ; i < dpres ; i++) {
               fileparts(GCPART_FNAM,tmppth,filnam,GCSTRFNM);
               stzcpy(tmpfil,spr("%s\\%s",filnam,tmpfil),GCMAXPTH);
               fileparts(GCPART_PATH,tmppth,tmppth,GCMAXPTH);
               s=&tmppth[strlen(tmppth)-1];
               if (*s == '\\' || *s == '/') {
                    *s='\0';
               }
          }
          if (pmode == FALSE) {
               cdrdi(tmppth);
          }
          stzcpy(tmpbuf,kilwht(pmode ? lstbuf : tmpfil), GCMAXPTH);
          strcat(syscmd,tmpbuf);
          addsfx();
          switch (lmode) {
          case PERLINE:
               /* printf("\n%s\n",syscmd); */
               runcmd(syscmd,tmppth,tmpbuf);
               break;
          default:
               prppth(tmpbuf,tmppth);
               break;
          }
     }
     if (lmode == PERLIST) {
          printf(" %d   \r",catlines);
          dofils();
     }
}

VOID
usage(VOID)
{
     printf("\7");
     printf("Usage: GALPRLST [/Dx] [/A] [/P] [/S] ListFile \"Command\" {@F|F} ");
     printf("[\"Text\"]\n\n");
     printf("       /Dx       - Respect x subdirectory levels for SI\n");
     printf("       /A        - Add trailing backslash to command prefix\n");
     printf("       /P        - Always output Path, Never change directory\n");
     printf("       /S        - Inhibit ListFile delete\n");
     printf("       ListFile  - List file to process (from GETLST)\n");
     printf("       \"Command\" - DOS command prefix\n");
     printf("       @F or F   - @F tells GALPRLST to pass the file list\n");
     printf("                   as the argument to the DOS command.  F\n");
     printf("                   tells GALPRLST to pass individual files\n");
     printf("                   from the file list.\n");
     printf("       \"Text\"    - Optional suffix to DOS command above.\n\n");
}

VOID
runcmd(                            /* Run the blasted command              */
CHAR *cmd,                         /*   Command line to run                */
CHAR *path,
CHAR *file)
{
     CHAR errmsg[ERRBUF];
     struct ffblk fb;

     if ((system(cmd)) == -1) {
          switch (errno) {
          case ENOENT:
               stzcpy(errmsg,"No such file or directory",ERRBUF);
               break;
          case ENOMEM:
               stzcpy(errmsg,"Not enough memory",ERRBUF);
               break;
          case E2BIG:
               stzcpy(errmsg,"Argument list too long",ERRBUF);
               break;
          case ENOEXEC:
               stzcpy(errmsg,"Exec format error",ERRBUF);
               break;
          default:
               stzcpy(errmsg,"Unknown/Undefined error",ERRBUF);
               break;
          }
          catastro(spr("Error in system call!\n(%-20s)",errmsg));
     }
     if (fndfile(&fb,"gcerr.err",0)) {
          unlink("gcerr.err");
#undef printf
          printf("\7\7Unable to build %s\\%s\n",path,file);
#define printf gprintf
          clsvid();
          exit(1);
     }
}


VOID
addsfx(VOID)                       /* Add suffix to cmd. line (if needed)  */
{
     if (cmdsfx[0] != '\0') {
           strcat(syscmd,cmdsfx);
     }
}

CHAR *
kilwht(                            /* Kill whitespace at end of line       */
CHAR *str)                         /*   String to kill whitespace in       */
{
     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;
          }
     }
     return(str);
}

GBOOL
inlist(                            /* Is this path already in the list?    */
CHAR *path)                        /*   Path to look up                    */
{
     INT i;
     CHAR *pinlst;

     for (i=0 ; i < ninarr(plhdl) ; i++) {
          pinlst=arrelem(plhdl,i);
          if (sameas(path,pinlst)) {
               return(TRUE);
          }
     }
     return(FALSE);
}

VOID
ad2lst(                            /* Add path to path list array          */
CHAR *path)                        /*   Path to add                        */
{
     CHAR *newpth;

     add2arr(plhdl,NULL);
     newpth=arrelem(plhdl,ninarr(plhdl)-1);
     stlcpy(newpth,path,GCMAXPTH);
}

VOID
prppth(                            /* Prepare path for list processing     */
CHAR *filnam,                      /*   File name to write to list         */
CHAR *path)                        /*   Path to prepare                    */
{
     struct ffblk pathb;
     static INT filcnt=0;

     if (!fnd1st(&pathb,path,FAMDIR)) {
          gmkdir(path);
     }
     cdrdi(path);
     if (filcnt == MAXINL) {
          if (naminc == 'Z') {
               catastro("Too many files to process!!!");
          }
          ++naminc;
          filcnt=0;
     }
     opnfil(path);
     fprintf(pthfp,"%s\n",filnam);
     ++filcnt;
     fclose(pthfp);
}

VOID
opnfil(                            /* Opens PRCLIST?.LST file              */
CHAR *path)                        /*   Path to open file in               */
{
     if (inlist(path)) {
          if ((pthfp=fopen(spr("PRCLIST%c.LST",naminc),FOPAA)) == NULL) {
               catastro(spr("Error opening PRCLIST%c.LST for update.",
                             naminc));
          }
     }
     else {
          if ((pthfp=fopen(spr("PRCLIST%c.LST",naminc),FOPWA)) == NULL) {
               catastro(spr("Error opening PRCLIST%c.LST for writing.",naminc));
          }
          ad2lst(path);
     }
}

VOID
dofils(VOID)                       /* Process all PRCLIST?.LST files       */
{
     struct ffblk prcfb;
     INT loop;
     CHAR tmppth[GCMAXPTH];

     for (loop=0 ; loop < ninarr(plhdl) ; loop++) {
          stzcpy(tmppth,arrelem(plhdl,loop),GCMAXPTH);
          repenv(tmppth,GCMAXPTH,"WGNT","\\wgservnt");
          repenv(tmppth,GCMAXPTH,"WGDOS","\\wgserv");
          repenv(tmppth,GCMAXPTH,"WGDEV","\\wgdev");
          repenv(tmppth,GCMAXPTH,"WGMAN","\\wgman");
          if (tmppth[0] == '\\') {
               stzcpy(tmppth,spr("C:%s",tmppth),GCMAXPTH);
          }
          if (pmode == FALSE) {
               cdrdi(tmppth);
               printf("Switching to %s...\n\n",tmppth);
          }
          if (fnd1st(&prcfb,"PRCLIST?.LST",0)) {
               do {
                    inicmd();
                    strcat(syscmd,prcfb.ff_name);
                    addsfx();
                    chkabt();
                    /* printf("\n%s\n",syscmd); */
                    runcmd(syscmd,tmppth,prcfb.ff_name);
                    unlink(prcfb.ff_name);
               } while (fndnxt(&prcfb));
          }
     }
}

VOID
chkabt(VOID)                       /* Check to see if user wants to abort  */
{
     if (kbhit()) {
          if (getchc() == ESC) {
               setatr(0x0C);
               printf("\nGALPRLST: User abort!\n");
               setatr(0x07);
               printf("\r");
               rstdir();
               clsvid();
               exit(0);
          }
     }
}

VOID
rstdir(VOID)                       /* Restore original working directory   */
{
     if ((cdrdi(retdir)) == -1) {
          catastro("Error returning to original directory.");
     }
}

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));
}

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);
          }
     }
}
