/***************************************************************************
 *                                                                         *
 *   SMFILE.C                                                              *
 *                                                                         *
 *   Copyright (c) 1997      Galacticomm, Inc.      All Rights Reserved.   *
 *                                                                         *
 *   Swap file API for searchable memory block API.                        *
 *                                                                         *
 *                                           - J. Alvrus    5/21/97        *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "smbapi.h"
#include "smfile.h"

#define FILREV "$Revision: 3 $"

CHAR swapFilePath[GCMAXPTH];

MARKSOURCE(smfile)

VOID
smfInit(                           /* initialize swap file API             */
const CHAR *swapPath)              /*   location for swap files            */
{
     INT i;
     CHAR tmpPath[GCMAXPTH];
     struct ffblk fb;
     GBOOL fnd;

     stlcpy(swapFilePath,swapPath,GCMAXPTH);
     while ((i=strlen(swapFilePath)-1) != 0 && isvalds(swapFilePath[i])) {
          swapFilePath[i]='\0';
     }
     gmkdir(swapFilePath);
     fixpth(swapFilePath);
     stlcat(stlcpy(tmpPath,swapFilePath,GCMAXPTH),"SMB*.*",GCMAXPTH);
     for (fnd=fnd1st(&fb,tmpPath,0) ; fnd ; fnd=fndnxt(&fb)) {
          stlcat(stlcpy(tmpPath,swapFilePath,GCMAXPTH),fb.ff_name,GCMAXPTH);
          unlink(tmpPath);
     }
}

SMFILE *                           /*   pointer to control info            */
smfOpen(                           /* open a swap file                     */
size_t blockSize)                  /*   size of blocks                     */
{
     SMFILE *smf;

     smf=alcmem(sizeof(SMFILE));
     stlcat(stlcpy(smf->fileName,swapFilePath,GCMAXPTH),"SMBXXXXXX",GCMAXPTH);
     mktemp(smf->fileName);
     if ((smf->fp=fopen(smf->fileName,FOPWRB)) == NULL) {
          catastro("Unable to open swap file: %s",smf->fileName);
     }
     smf->freeList=SMBNULL;
     smf->blockSize=blockSize;
     return(smf);
}

VOID
smfClose(                          /* close a swap file                    */
SMFILE *smf)                       /*   swap file to close                 */
{
     fclose(smf->fp);
     unlink(smf->fileName);
     free(smf);
}

SMBPTR                             /*   pointer to allocated block         */
smfAlloc(                          /* allocate a block in swap file        */
SMFILE *smf)                       /*   swap file control info             */
{
     SMBPTR ref;
     INT i,c;

     if (smf->freeList == SMBNULL) {     // no free records
          fseek(smf->fp,0,SEEK_END);
          ref=smfTell(smf);
          for (c=i=0 ; i < smf->blockSize ; ++i) {
               if (fputc(c,smf->fp) == EOF) {
                    return(SMBNULL);
               }
          }
     }
     else {
          ref=smf->freeList;
          if (!smfSeek(smf,ref)
           || fread(&smf->freeList,1,sizeof(SMBPTR),smf->fp) != sizeof(SMBPTR)) {
               return(SMBNULL);
          }
     }
     return(ref);
}

GBOOL                              /*   returns TRUE if successful         */
smfFree(                           /* free a block in swap file            */
SMFILE *smf,                       /*   swap file control info             */
SMBPTR ref)                        /*   block to free                      */
{
     if (!smfSeek(smf,ref)
      || fwrite(&smf->freeList,1,sizeof(SMBPTR),smf->fp) != sizeof(SMBPTR)) {
          return(FALSE);
     }
     smf->freeList=ref;
     return(TRUE);
}

GBOOL                              /*   returns TRUE if successful         */
smfRead(                           /* read a block from swap file          */
SMFILE *smf,                       /*   swap file control info             */
VOID *buf,                         /*   buffer to read into                */
SMBPTR ref)                        /*   block to read                      */
{
     return(smfSeek(smf,ref)
         && fread(buf,1,smf->blockSize,smf->fp) == smf->blockSize);
}

GBOOL                              /*   returns TRUE if successful         */
smfWrite(                          /* write a block to swap file           */
SMFILE *smf,                       /*   swap file control info             */
const VOID *src,                   /*   pointer to block to write          */
SMBPTR ref)                        /*   position to write block to         */
{
     return(smfSeek(smf,ref)
         && fwrite(src,1,smf->blockSize,smf->fp) == smf->blockSize);
}

GBOOL                              /*   returns TRUE if successful         */
smfSeek(                           /* set position in swap file            */
SMFILE *smf,                       /*   swap file control info             */
SMBPTR ref)                        /*   block to point to                  */
{
     return(fseek(smf->fp,ref-1,SEEK_SET) == 0);
}

SMBPTR                             /*   returns pointer to current block   */
smfTell(                           /* get position in swap file            */
SMFILE *smf)                       /*   swap file control info             */
{
     return(ftell(smf->fp)+1);
}

#ifdef DEBUG

GBOOL
smfIsValidBlock(                   // is this a valid block pointer?
SMFILE *smf,                       //   swap file control info
SMBPTR ref)                        //   block to check
{
     SMBPTR tmpref;

     if (ref == SMBNULL) {
          return(FALSE);
     }
     fseek(smf->fp,0,SEEK_END);
     if ((ref-1) >= ftell(smf->fp) || (ref-1)%smf->blockSize != 0) {
          return(FALSE);
     }
     tmpref=smf->freeList;
     while (tmpref != SMBNULL) {
          if (tmpref == ref) {
               return(FALSE);
          }
          if (!smfSeek(smf,tmpref)
           || fread(&tmpref,1,sizeof(SMBPTR),smf->fp) != sizeof(SMBPTR)) {
               catastro("smfIsValidBlock:  Can't read item from free list");
          }
     }
     return(TRUE);
}

#endif // DEBUG
