/************************************************************/
/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
/************************************************************/

/* fileres.c -- functions from file.c that are usually resident */

#define NOCLIPBOARD
#define NOGDICAPMASKS
#define NOCTLMGR
#define NOVIRTUALKEYCODES
#define NOWINMESSAGES
#define NOWINSTYLES
#define NOSYSMETRICS
#define NOMENUS
#define NOICON
#define NOKEYSTATE
#define NORASTEROPS
#define NOSHOWWINDOW
#define NOSYSCOMMANDS
#define NOATOM
#define NOCOLOR
#define NOCREATESTRUCT
#define NOCTLMGR
#define NODRAWTEXT
#define NOMETAFILE
#define NOMSG
#define NOHDC
#define NOGDI
#define NOMB
#define NOFONT
#define NOPEN
#define NOBRUSH
#define NOWNDCLASS
#define NOSOUND
#define NOCOMM
#define NOPOINT
#define NORECT
#define NOREGION
#define NOSCROLL
#define NOTEXTMETRIC
#define NOWH
#define NOWINOFFSETS
#include <windows.h>

#include "mw.h"
#include "doslib.h"
#define NOUAC
#include "cmddefs.h"
#include "docdefs.h"
#include "filedefs.h"
#include "str.h"
#include "debug.h"


extern int                      vfDiskFull;
extern int                      vfSysFull;
extern int                      vfnWriting;
extern CHAR                     (*rgbp)[cbSector];
extern typeTS                   tsMruRfn;
extern struct BPS               *mpibpbps;
extern int                      ibpMax;
extern struct FCB               (**hpfnfcb)[];
extern typeTS                   tsMruBps;
extern struct ERFN              dnrfn[rfnMax];
extern int                      iibpHashMax;
extern CHAR                     *rgibpHash;
extern int                      rfnMac;
extern int                      ferror;
extern CHAR                     szWriteDocPrompt[];
extern CHAR                     szScratchFilePrompt[];
extern CHAR                     szSaveFilePrompt[];


#define IibpHash(fn,pn) ((int) ((fn + 1) * (pn + 1)) & 077777) % iibpHashMax


#ifdef DEBUG
#define STATIC
#else
#define STATIC static
#define ErrorWithMsg( idpmt, szModule )         Error( idpmt )
#define DiskErrorWithMsg( idpmt, szModule )     DiskError( idpmt )
#endif

#define osfnNil (-1)


CHAR *PchFromFc(fn, fc, pcch)
int fn;
typeFC fc;
int *pcch;
{ /*
        Description:    Reads from a file, starting at virtual character
                        position fc.  Reads until end of buffer page.
        Returns:        Pointer to char buffer starting at fc.
                        The number of characters read is returned in *pcch.
  */
int dfc;
CHAR *pch;
typePN pn;
int ibp;
struct BPS *pbps;

        dfc = (int) (fc % cfcPage);
        pn = (typePN) (fc / cfcPage);

        ibp = IbpEnsureValid(fn, pn);
        pbps = &mpibpbps[ibp];
        *pcch = pbps->cch - dfc;
        return &rgbp[ibp][dfc];
}
/* end of  P c h F r o m F c  */




/***        PchGetPn - Assure file page loaded, return pointer
 *
 */

CHAR *PchGetPn(fn, pn, pcch, fWrite)
int fn;
typePN pn;
int *pcch;
BOOL fWrite; // missing before?? (2.11.91) D. Kent
{ /*
        Description:    Get char pointer to page buffer, option to mark
                        page as dirty.
        Returns:        Pointer to buffer.
                        cch in *pcch
  */

        int ibp = IbpEnsureValid(fn, pn);
        struct BPS *pbps = &mpibpbps[ibp];

        *pcch = pbps->cch;
        pbps->fDirty |= fWrite;
        return rgbp[ibp];
} /* end of  P c h G e t P n  */




int IbpEnsureValid(fn, pn)
int fn;
typePN pn;
{ /*
        Description:    Get page pn of file fn into memory.
                        If already in memory, return.
        Returns:        Bp index (buffer slot #) where the page resides
                        in memory.
  */

int ibp;
register struct BPS *pbps;

#ifdef DEBUG
 CheckIbp();
#endif /* DEBUG */

/* Is the page currently in memory? */
 ibp = rgibpHash[IibpHash(fn,pn)];
 /* ibp is the first in a linked list of possible matches */
 /* resident in memory */

 Scribble(3,'V');

 while (ibp != ibpNil)    /* while not end of linked list */
    {                   /* check if any buffers in memory match */
    pbps = &mpibpbps[ibp];
    if (pbps->fn == fn && pbps->pn == pn)
        { /* Found it */
        pbps->ts = ++tsMruBps;      /* mark page as MRUsed */
        Scribble(3,' ');
        return ibp;
        }
    ibp = pbps->ibpHashNext;
    }

/* page is not currently in memory */

 return IbpMakeValid( fn, pn );
} /* end of I b p E n s u r e V a l i d  */




CloseEveryRfn( fHardToo )
{   /* Close all files we have open. Close only files on removable media
       if fHardToo is FALSE; ALL files if fHardToo is TRUE */
int rfn;

for (rfn = 0; rfn < rfnMac; rfn++)
    {
    int fn = dnrfn [rfn].fn;

    if (fn != fnNil)
        if ( fHardToo ||
             !((POFSTRUCT)((**hpfnfcb)[fn].rgbOpenFileBuf))->fFixedDisk )
            {
            CloseRfn( rfn );
            }
    }
}



typeFC FcWScratch(pch, cch)
CHAR *pch;
int cch;
{ /*
        Description:    Write chars at end of scratch file.
        Returns:        first fc written.
 */
        typeFC fc = (**hpfnfcb)[fnScratch].fcMac;
#if 0
        extern BOOL  bNo64KLimit;

        if ((!bNo64KLimit) && (((long) fc) + ((long) cch) > 65536L))  /* scratch file to big */
        {
        DiskErrorWithMsg(IDPMTSFER, " FcWScratch"); /* session too long */

        vfSysFull = fTrue;
                /* recovery is accomplished: all that happens is that a few
                   characters do not get written to the scratch file - the
                   user loses only a little bit of his work. */
        }
        else
#endif
                WriteRgch(fnScratch, pch, cch);
        return fc;
}




WriteRgch(fn, pch, cch)
int fn;
CHAR *pch;
int cch;
{ /*
        Description:    Writes char string pch, length cch, to end of
                        file fn.
        Returns:        nothing
 */
 extern vfDiskError;
 struct FCB *pfcb = &(**hpfnfcb)[fn];
 typePN pn = (typePN) (pfcb->fcMac / cfcPage);
#ifdef WIN30
 /* Error checking was horrendous in these early days, right?
    Ha.  It still is.  In any case, don't know WHAT we can do
    if the page number has gotten too large, so just fake a 
    disk error so that IbpEnsureValid() doesn't go off into 
    never-never land!  This catch effectively limits us to 
    4M files ..pault 11/1/89 */

 if (pn > pgnMax)
#ifdef DEBUG
    DiskErrorWithMsg(IDPMTSDE2, "writergch");
#else    
    DiskError(IDPMTSDE2);
#endif
 else
#endif

        while (cch > 0)
                { /* One page at a time */
                int ibp = IbpEnsureValid(fn, pn++);
                struct BPS *pbps = &mpibpbps[ibp];
                int cchBp = pbps->cch;
                int cchBlt = min((int)cfcPage - cchBp, cch);

                Assert( vfDiskError ||
                        cchBp == pfcb->fcMac - (pn - 1) * cfcPage);

                bltbyte(pch, &rgbp[ibp][cchBp], cchBlt);
                pbps->cch += cchBlt;
                pbps->fDirty = true;
                pfcb->fcMac += cchBlt;
                pfcb->pnMac = pn;
                pch += cchBlt;
                cch -= cchBlt;
                }
} /* end of  W r i t e R g c h  */




CloseRfn( rfn )
int rfn;
{/*
        Description:    Close a file and delete its Rfn entry
        Returns:        nothing
 */
        struct ERFN *perfn = &dnrfn[rfn];
        int fn = perfn->fn;

        Assert (rfn >= 0 &&
                rfn < rfnMac &&
                perfn->osfn != osfnNil &&
                fn != fnNil);

#ifdef DEBUG
#ifdef DFILE
        CommSzSz( "Closing file: ", &(**(**hpfnfcb)[fn].hszFile)[0] );
#endif
#endif
        /* Close may fail if windows already closed the file for us,
           but that's OK */
        FCloseDoshnd( perfn->osfn );

        {   /* Just like the statement below, but 28 bytes less
               under CMERGE V13 */
        REG1    struct FCB *pfcb = &(**hpfnfcb) [fn];
        pfcb->rfn = rfnNil;
        }
        /* (**hpfnfcb)[fn].rfn = rfnNil; */


        perfn->fn = fnNil;
}
