/***************************************************************************
 *                                                                         *
 *   FIOV3.C                                                               *
 *                                                                         *
 *   Copyright (c) 1997 Galacticomm, Inc.      All Rights Reserved.        *
 *                                                                         *
 *   File I/O API -- commonly used functions added for WG3, for backward   *
 *   compatibility with earlier WG versions.                               *
 *                                                                         *
 *                                           - R. Stein  5/19/91           *
 *   Unix additions                          - Mahesh Neelakanta 10/26/94  *
 *   Modified for Unity and NT version       - Ilya Minkin 01/17/96        *
 *   Backward compatibility version          - J. Alvrus    04/24/97       *
 *                                                                         *
 ***************************************************************************/

#include <utime.h>
#include <direct.h>
#include "gcomm.h"

#define FILREV "$Revision: 1.1 $"

LONG ztzone=0;                     /* Seconds between GMT and local time   */

/* from old GCOMM.H */
const CHAR *filnpart(const CHAR *filespec);
const CHAR *pathpart(const CHAR *filespec);

CHAR *                             /*   returns pointer to dstbuf or ""    */
fileparts(                         /* grab required part of a full filename*/
SHORT filpart,                     /*   part to be returned                */
const CHAR *fullname,              /*   full filename to be worked on      */
CHAR *dstbuf,                      /*   destination buffer for data        */
SHORT dstsiz)                      /*   destination buffer size            */
{
     CHAR *cp,tmpbuf[13];

     *dstbuf='\0';
     switch (filpart) {
     case GCPART_PATH:
          stlcpy(dstbuf,pathpart(fullname),dstsiz);
          break;
     case GCPART_FNAM:
          stlcpy(dstbuf,filnpart(fullname),dstsiz);
          break;
     case GCPART_FILE:
          if ((cp=strrchr(stlcpy(tmpbuf,filnpart(fullname),sizeof(tmpbuf)),'.'))
           != NULL) {
               *cp='\0';
          }
          stlcpy(dstbuf,tmpbuf,dstsiz);
          break;
     case GCPART_EXTN:
          if ((cp=strrchr(stlcpy(tmpbuf,filnpart(fullname),sizeof(tmpbuf)),'.'))
           != NULL) {
               stlcpy(dstbuf,cp+1,dstsiz);
          }
          break;
     case GCPART_DRVS:
          if ((cp=strchr(fullname,':')) != NULL) {
               stlcpy(dstbuf,fullname,min((SHORT)(cp-fullname),dstsiz));
          }
          break;
     }
     return(dstbuf);
}

FILE *                             /*   returns FILE pointer or NULL       */
gcfsopen(                          /* opens a file in shared mode          */
const CHAR *filename,              /*   file name to open                  */
const CHAR *mode,                  /*   mode to open with                  */
USHORT shflag)                     /*   shared mode flags                  */
{
     return(_fsopen(filename,mode,shflag));
}

GBOOL                              /*   return TRUE if separator character */
isvalds(                           /* is this char. a file path separator  */
CHAR c)                            /*   character to test                  */
{
     if (c == SL || c == ':') {
          return(TRUE);
     }
     return(FALSE);
}

GBOOL                              /*   returns TRUE=valid file name char  */
isvalfc(                           /* is this a valid file name character? */
CHAR c)                            /*   character to check                 */
{
     if (c < ' ' || c == '.' || c == '"' || c == '/' || c == '\\'
      || c == '[' || c == ']' || c == ':' || c == ';' || c == '|'
      || c == '<' || c == '>' || c == '+' || c == '=' || c == ',') {
          return(FALSE);
     }
     return(TRUE);
}

GBOOL                              /*   returns TRUE=valid file name       */
isvalfn(                           /* check for valid file name            */
const CHAR *filnam)                /*   string to check                    */
{
     const CHAR *cp;
     INT i;

     for (i=1,cp=filnam ; *cp != '\0' && *cp != '.' ; ++i,++cp) {
          if (i > GCMAXFILE || !isvalfc(*cp)) {
               return(FALSE);
          }
     }
     if (*cp++ == '.') {
          for (i=1 ; *cp != '\0' ; ++i,++cp) {
               if (i > GCMAXEXT || *cp == '.' || !isvalfc(*cp)) {
                    return(FALSE);
               }
          }
     }
     if (rsvnam(filnam)) {
          return(FALSE);
     }
     return(TRUE);
}

GBOOL                              /*   returns TRUE=valid directory       */
isvaldn(                           /* verify directory name is ok for OS   */
const CHAR *dirnam)                /*   directory name to check            */
{
     CHAR *cp,tmpdir[GCMAXPTH];
     INT pos;

     if (strlen(dirnam) >= GCMAXPTH) {
          return(FALSE);
     }
     normspec(tmpdir,dirnam);
     if (tmpdir[pos=strlen(tmpdir)-1] == SL) {
          tmpdir[pos]='\0';
     }
     while (strlen(tmpdir) > 2) {  /* e.g. "C:"                            */
          cp=strrchr(tmpdir,SL);
          if (cp == NULL || !isvalfn(cp+1)) {
               return(FALSE);
          }
          *cp='\0';
     }
     return(strlen(tmpdir) == 2 && isalpha(tmpdir[0]) && tmpdir[1] == ':');
}

LONG                               /*   returns # of bytes copied          */
xfrfil(                            /* copy from one open file to another   */
FILE *fromfp,                      /*   source file pointer                */
FILE *tofp,                        /*   destination file pointer           */
LONG nbytes)                       /*   max bytes to transfer              */
{
     LONG wbytes;
     INT n;
     CHAR block[BLKSIZ];
     INT fwsiz;

     for (wbytes=0L ; nbytes >= BLKSIZ ; nbytes-=BLKSIZ) {
          if ((n=(INT)fread(block,1,BLKSIZ,fromfp)) > 0) {
               if ((fwsiz=(INT)fwrite(block,1,n,tofp)) > 0) {
                    wbytes+=fwsiz;
               }
          }
          if (n < BLKSIZ) {
               return(wbytes);
          }
     }
     if (nbytes > 0L && (n=fread(block,1,(INT)nbytes,fromfp)) > 0) {
          wbytes+=fwrite(block,1,n,tofp);
     }
     return(wbytes);
}

UINT                               /*   returns size or 0 for error        */
clsize(                            /* get cluster size in bytes            */
const CHAR *path)                  /*   path to drive to check             */
{
     CHAR drivebuf[GCMAXPTH];
     INT drive;
     union REGS regs;

     fileparts(GCPART_DRVS,path,drivebuf,GCMAXPTH);
     drive=0;
     if (drivebuf[0] != '\0') {
          drive=toupper(drivebuf[0])-64; /* 'A'->1, 'B'->2, 'C'->3, etc.   */
     }
     regs.h.ah=0x1C;
     regs.h.dl=drive;
     intdos(&regs,&regs);
     return(regs.h.al*regs.x.cx);
}

VOID
getFileTm(                         /* get time and date for file           */
const CHAR *fname,                 /*   file name                          */
USHORT *dtim,                      /*   time to get                        */
USHORT *ddat)                      /*   date to get                        */
{
     struct ffblk fb;

     if (fndfile(&fb,fname,0)) {
          *dtim=fb.ff_ftime;
          *ddat=fb.ff_fdate;
     }
}

ULONG                              /*   returns time and date in GMT format*/
getFileGMT(                        /* get GMT file time and date           */
const CHAR *fname)                 /*   file name                          */
{
     USHORT dat,tim;
     ULONG mtime;

     getFileTm(fname,&tim,&dat);
     mtime=315532800L+                    /* 00:00 1/1/70 to 00:00 1/1/80   */
           cofdat(dat)*86400L+            /* 00:00 1/1/80 to 00:00 fileday  */
           dthour(tim)*3600L+             /*  \                             */
           dtmin(tim)*60L+                /*   > compute filetime since     */
           dtsec(tim)+                    /*  /  00:00 on fileday           */
           ztzone;                        /* convert from local time to GMT */
     return(mtime);
}

LONG                               /*   returns kbytes free or -1 for error*/
dskfre(                            /* number of kbytes free on a drive     */
const CHAR *path)                  /*   path on drive to check,NULL=default*/
{
     CHAR drivebuf[GCMAXPTH];
     INT drive;
     union REGS regs;

     if (path == NULL) {
          drive=0;
     }
     else {
          fileparts(GCPART_DRVS,path,drivebuf,GCMAXPTH);
          if ( drivebuf[0] == '\0') {
               drive=0;
          }
          else {
               drive=toupper(drivebuf[0])+1-'A'; /* 'A'=1,'B'=2,'C'=3 etc.*/
          }
     }
     ASSERT(drive >= 0 && drive <= 26);
     regs.h.ah=0x36;
     regs.h.dl=drive;
     intdos(&regs,&regs);
     return(((LONG)regs.x.bx/4L)*(LONG)regs.x.ax*((LONG)regs.x.cx/256L));
}

GBOOL                              /*   TRUE if dir matching dname exists  */
isdir(                             /* check whether a directory exists     */
const CHAR *dname)                 /*   directory name to search for       */
{
     struct ffblk fb;

     return(fndfile(&fb,dname,FAMDIR) && (fb.ff_attrib & FAMDIR));
}

GBOOL                              /*   TRUE if matching file exists       */
isfile(                            /* check for existence of file(s)       */
const CHAR *fname)                 /*   filename or wildcard to check      */
{
     struct ffblk fb;

     return(fndfile(&fb,fname,FAMSYS|FAMRON|FAMHID));
}
