709 lines
19 KiB
C
709 lines
19 KiB
C
|
/************************************************************/
|
|||
|
/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
|
|||
|
/************************************************************/
|
|||
|
|
|||
|
/* cache.c -- Paragraph attribute fetching and caching for WRITE */
|
|||
|
|
|||
|
#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 NOCREATESTRUCT
|
|||
|
#define NOATOM
|
|||
|
#define NOMETAFILE
|
|||
|
#define NOGDI
|
|||
|
#define NOFONT
|
|||
|
#define NOBRUSH
|
|||
|
#define NOPEN
|
|||
|
#define NOBITMAP
|
|||
|
#define NOCOLOR
|
|||
|
#define NODRAWTEXT
|
|||
|
#define NOWNDCLASS
|
|||
|
#define NOSOUND
|
|||
|
#define NOCOMM
|
|||
|
#define NOMB
|
|||
|
#define NOMSG
|
|||
|
#define NOOPENFILE
|
|||
|
#define NORESOURCE
|
|||
|
#define NOPOINT
|
|||
|
#define NORECT
|
|||
|
#define NOREGION
|
|||
|
#define NOSCROLL
|
|||
|
#define NOTEXTMETRIC
|
|||
|
#define NOWH
|
|||
|
#define NOWINOFFSETS
|
|||
|
#include <windows.h>
|
|||
|
|
|||
|
#include "mw.h"
|
|||
|
#include "docdefs.h"
|
|||
|
#include "editdefs.h"
|
|||
|
#include "cmddefs.h"
|
|||
|
#include "propdefs.h"
|
|||
|
#include "filedefs.h"
|
|||
|
#include "fkpdefs.h"
|
|||
|
#include "fmtdefs.h"
|
|||
|
#define NOKCCODES
|
|||
|
#include "ch.h"
|
|||
|
#include "prmdefs.h"
|
|||
|
#include "debug.h"
|
|||
|
|
|||
|
extern int vfDiskError;
|
|||
|
extern typeCP vcpFirstParaCache;
|
|||
|
extern typeCP vcpLimParaCache;
|
|||
|
extern typeFC fcMacPapIns;
|
|||
|
extern struct FCB (**hpfnfcb)[];
|
|||
|
extern struct FKPD vfkpdParaIns;
|
|||
|
extern int ichInsert;
|
|||
|
extern CHAR rgchInsert[];
|
|||
|
extern int vdocExpFetch;
|
|||
|
extern int vdocSectCache;
|
|||
|
extern typeCP vcpFirstSectCache;
|
|||
|
extern typeCP vcpLimSectCache;
|
|||
|
extern int vdocPageCache;
|
|||
|
extern typeCP vcpMinPageCache;
|
|||
|
extern typeCP vcpMacPageCache;
|
|||
|
extern typeCP cpMinCur;
|
|||
|
|
|||
|
extern struct PAP vpapAbs;
|
|||
|
extern struct PAP *vppapNormal;
|
|||
|
extern struct DOD (**hpdocdod)[];
|
|||
|
extern struct FLI vfli;
|
|||
|
extern int vdxaPaper;
|
|||
|
extern int vdyaPaper;
|
|||
|
extern typePN PnFkpFromFcScr();
|
|||
|
|
|||
|
|
|||
|
extern int vdocParaCache;
|
|||
|
extern int visedCache;
|
|||
|
extern int vdocPageCache;
|
|||
|
|
|||
|
extern struct SEP vsepAbs;
|
|||
|
extern struct SEP vsepPage;
|
|||
|
extern struct SEP vsepNormal;
|
|||
|
|
|||
|
extern int ctrCache;
|
|||
|
extern int itrFirstCache;
|
|||
|
extern int itrLimCache;
|
|||
|
extern typeCP cpCacheHint;
|
|||
|
|
|||
|
CHAR *PchFromFc();
|
|||
|
CHAR *PchGetPn();
|
|||
|
|
|||
|
CachePara(doc, cp)
|
|||
|
int doc;
|
|||
|
typeCP cp;
|
|||
|
{ /* Make the para containing <doc, cp> the currently cached para */
|
|||
|
struct PCD *ppcd, *ppcdBase;
|
|||
|
typeCP cpMac, cpGuess;
|
|||
|
struct DOD *pdod;
|
|||
|
int dty;
|
|||
|
struct PCTB *ppctb;
|
|||
|
|
|||
|
if (vdocParaCache == doc && vcpFirstParaCache <= cp &&
|
|||
|
cp < vcpLimParaCache)
|
|||
|
return; /* That's what the cache is for */
|
|||
|
|
|||
|
Assert(cp >= cp0);
|
|||
|
|
|||
|
pdod = &(**hpdocdod)[doc];
|
|||
|
dty = pdod->dty;
|
|||
|
if (cp >= pdod->cpMac)
|
|||
|
{ /* Use normal para for end mark and beyond */
|
|||
|
#ifdef ENABLE /* Occasionally this is not true (but it should be) */
|
|||
|
Assert( cp == pdod->cpMac );
|
|||
|
#endif
|
|||
|
|
|||
|
if (cp > cpMinCur)
|
|||
|
{ /* this piece of code treats the case when the whole document
|
|||
|
is a non-empty semi-paragraph (chars but no EOL's) */
|
|||
|
CachePara( doc, cp - 1 ); /* Recursion will not happen */
|
|||
|
if ( vcpLimParaCache > cp )
|
|||
|
{
|
|||
|
vcpLimParaCache = pdod->cpMac + ccpEol;
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
vdocParaCache = doc;
|
|||
|
vcpLimParaCache = (vcpFirstParaCache = pdod->cpMac) + ccpEol;
|
|||
|
DefaultPaps( doc );
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
FreezeHp();
|
|||
|
ppctb = *pdod->hpctb;
|
|||
|
ppcdBase = &ppctb->rgpcd [ IpcdFromCp( ppctb, cpGuess = cp ) ];
|
|||
|
|
|||
|
if (vdocParaCache == doc && cp == vcpLimParaCache)
|
|||
|
vcpFirstParaCache = cp;
|
|||
|
else
|
|||
|
{ /* Search backward to find para start */
|
|||
|
for (ppcd = ppcdBase; ; --ppcd)
|
|||
|
{ /* Beware heap movement! */
|
|||
|
typeCP cpMin = ppcd->cpMin;
|
|||
|
int fn = ppcd->fn;
|
|||
|
if (! ppcd->fNoParaLast)
|
|||
|
{ /* Don't check if we know there's no para end */
|
|||
|
typeFC fcMin = ppcd->fc;
|
|||
|
typeFC fc;
|
|||
|
|
|||
|
if ((fc = FcParaFirst(fn,
|
|||
|
fcMin + cpGuess - cpMin, fcMin)) != fcNil)
|
|||
|
{ /* Found para begin */
|
|||
|
vcpFirstParaCache = cpMin + (fc - fcMin);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
/* Now we know there's no para end from cpMin to cpGuess. */
|
|||
|
/* If original piece, may be one after cp */
|
|||
|
#ifdef BOGUSBL
|
|||
|
/* vfInsertMode protects against a critical section in insert */
|
|||
|
/* when the CR is already inserted but the supporting PAP structure */
|
|||
|
/* is not in place yet */
|
|||
|
|
|||
|
if (cp != cpGuess && fn != fnInsert && !vfInsertMode)
|
|||
|
#else /* Insert CR works differently now, above test slows us down
|
|||
|
by forcing many calls to FcParaLim */
|
|||
|
if (cp != cpGuess)
|
|||
|
#endif
|
|||
|
ppcd->fNoParaLast = true; /* Save some work next time */
|
|||
|
if (cpMin == cp0)
|
|||
|
{ /* Beginning of doc is beginning of para */
|
|||
|
vcpFirstParaCache = cpMinCur;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
/** Some low memory error conditions may cause ppctb to be
|
|||
|
messed up **/
|
|||
|
if (ppcd == ppctb->rgpcd)
|
|||
|
{
|
|||
|
Assert(0);
|
|||
|
vcpFirstParaCache = cp0; // hope for divine grace
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
cpGuess = cpMin;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
vdocParaCache = doc;
|
|||
|
/* Now go forward to find the cpLimPara */
|
|||
|
cpMac = pdod->cpMac;
|
|||
|
cpGuess = cp;
|
|||
|
|
|||
|
for (ppcd = ppcdBase; ; ++ppcd)
|
|||
|
{
|
|||
|
typeCP cpMin = ppcd->cpMin;
|
|||
|
typeCP cpLim = (ppcd + 1)->cpMin;
|
|||
|
typeFC fc;
|
|||
|
int fn = ppcd->fn;
|
|||
|
|
|||
|
if (! ppcd->fNoParaLast)
|
|||
|
{ /* Don't check if we know there's no para end */
|
|||
|
typeFC fcMin = ppcd->fc;
|
|||
|
if ((fc = FcParaLim(fn, fcMin + cpGuess - cpMin,
|
|||
|
fcMin + (cpLim - cpMin), &vpapAbs)) != fcNil)
|
|||
|
{ /* Found para end */
|
|||
|
vcpLimParaCache = cpMin + (fc - fcMin);
|
|||
|
/* Under Write, FcParaLim can't set the correct rgtbd */
|
|||
|
/* That's because tabs are a DOCUMENT property */
|
|||
|
/* We set it here instead */
|
|||
|
GetTabsForDoc( doc );
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
/* Now we know there's no para end. */
|
|||
|
#ifdef BOGUSBL
|
|||
|
/* The check for vfInsertMode is necessary because of a critical */
|
|||
|
/* section in insertion between the insertion of a CR and the call */
|
|||
|
/* to AddRunScratch */
|
|||
|
if (cp != cpGuess && fn != fnInsert && !vfInsertMode)
|
|||
|
#else /* Insert CR has changed, we no longer try to pretend that
|
|||
|
the CR is not in the scratch file piece before the run is
|
|||
|
added. This new approach gains us speed, especially during backspace */
|
|||
|
if (cp != cpGuess)
|
|||
|
#endif
|
|||
|
ppcd->fNoParaLast = true; /* Save some work next time */
|
|||
|
if (cpLim == cpMac)
|
|||
|
{ /* No EOL at end of doc */
|
|||
|
vcpLimParaCache = cpMac + ccpEol;
|
|||
|
MeltHp();
|
|||
|
DefaultPaps( doc );
|
|||
|
return;
|
|||
|
}
|
|||
|
/** Some low memory error conditions may cause ppctb to be
|
|||
|
messed up **/
|
|||
|
else if ((cpLim > cpMac) || (ppcd == (ppctb->rgpcd + ppctb->ipcdMac - 1)))
|
|||
|
{
|
|||
|
Assert(0);
|
|||
|
vcpLimParaCache = cpMac + ccpEol; // hope for divine grace
|
|||
|
MeltHp();
|
|||
|
DefaultPaps( doc );
|
|||
|
return;
|
|||
|
}
|
|||
|
cpGuess = cpLim;
|
|||
|
}
|
|||
|
|
|||
|
/* Don't bother with properties for buffers */
|
|||
|
#ifdef ENABLE /* No buffers or styles in MEMO */
|
|||
|
if (dty != dtyBuffer || pdod->docSsht != docNil)
|
|||
|
#endif
|
|||
|
{
|
|||
|
struct PRM prm = ppcd->prm;
|
|||
|
if (!bPRMNIL(prm))
|
|||
|
DoPrm((struct CHP *) 0, &vpapAbs, prm);
|
|||
|
#ifdef STYLES
|
|||
|
blt(vpapCache.fStyled ? PpropXlate(doc, &vpapCache, &vpapCache) :
|
|||
|
&vpapCache, &vpapAbs, cwPAP);
|
|||
|
#endif /* STYLES */
|
|||
|
}
|
|||
|
|
|||
|
/* This little piece of code is necessary to provide compatibility between Word
|
|||
|
and Memo documents. It compresses the entire range of line spacing into single
|
|||
|
spacing, one and one-half spacing, and double spacing. */
|
|||
|
if (vpapAbs.dyaLine <= czaLine)
|
|||
|
{
|
|||
|
vpapAbs.dyaLine = czaLine;
|
|||
|
}
|
|||
|
else if (vpapAbs.dyaLine >= 2 * czaLine)
|
|||
|
{
|
|||
|
vpapAbs.dyaLine = 2 * czaLine;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
vpapAbs.dyaLine = (vpapAbs.dyaLine + czaLine / 4) / (czaLine / 2) *
|
|||
|
(czaLine / 2);
|
|||
|
}
|
|||
|
|
|||
|
MeltHp();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DefaultPaps( doc )
|
|||
|
int doc;
|
|||
|
{
|
|||
|
typeCP cpFirstSave, cpLimSave;
|
|||
|
struct TBD (**hgtbd)[];
|
|||
|
|
|||
|
if (vcpFirstParaCache > cpMinCur)
|
|||
|
{ /* Get pap from previous paragraph */
|
|||
|
cpFirstSave = vcpFirstParaCache;
|
|||
|
cpLimSave = vcpLimParaCache;
|
|||
|
CachePara(doc, cpFirstSave - 1); /* Recursion should not happen */
|
|||
|
vpapAbs.fGraphics = false; /* Don't make last para a picture */
|
|||
|
vpapAbs.rhc = 0; /* Don't make last para a running head */
|
|||
|
vcpLimParaCache = cpLimSave;
|
|||
|
vcpFirstParaCache = cpFirstSave;
|
|||
|
return;
|
|||
|
}
|
|||
|
#ifdef CASHMERE
|
|||
|
blt(vppapNormal, &vpapAbs, cwPAPBase+cwTBD);
|
|||
|
#else /* For MEMO, the default PAPS have the document's tab table */
|
|||
|
blt(vppapNormal, &vpapAbs, cwPAPBase);
|
|||
|
GetTabsForDoc( doc );
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef STYLES
|
|||
|
blt(&vpapNormal, &vpapCache, cwPAP);
|
|||
|
blt(PpropXlate(doc, &vpapNormal, &vpapStd), &vpapAbs, cwPAP);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
GetTabsForDoc( doc )
|
|||
|
int doc;
|
|||
|
{ /* Get tab table for passed document into vpapAbs.rgtbd */
|
|||
|
struct TBD (**hgtbd)[];
|
|||
|
|
|||
|
hgtbd = (**hpdocdod)[doc].hgtbd;
|
|||
|
if (hgtbd==0)
|
|||
|
bltc( vpapAbs.rgtbd, 0, cwTBD * itbdMax );
|
|||
|
else
|
|||
|
blt( *hgtbd, vpapAbs.rgtbd, cwTBD * itbdMax );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#ifdef CASHMERE
|
|||
|
CacheSect(doc, cp)
|
|||
|
int doc;
|
|||
|
typeCP cp;
|
|||
|
{
|
|||
|
struct SETB **hsetb, *psetb;
|
|||
|
struct SED *psed;
|
|||
|
CHAR *pchFprop;
|
|||
|
int cchT;
|
|||
|
struct DOD *pdod;
|
|||
|
|
|||
|
if (doc == vdocSectCache && cp >= vcpFirstSectCache && cp < vcpLimSectCache)
|
|||
|
return;
|
|||
|
|
|||
|
if ( vdocSectCache != doc && cp != cp0 )
|
|||
|
CacheSect( doc, cp0 ); /* Changing docs, assure vsepPage is accurate */
|
|||
|
|
|||
|
vdocSectCache = doc;
|
|||
|
visedCache = iNil;
|
|||
|
blt(&vsepNormal, &vsepAbs, cwSEP);
|
|||
|
|
|||
|
if ((hsetb = HsetbGet(doc)) == 0)
|
|||
|
{
|
|||
|
vcpFirstSectCache = cp0;
|
|||
|
vcpLimSectCache = (pdod = &(**hpdocdod)[doc])->cpMac + 1;
|
|||
|
blt(&vsepAbs, &vsepPage, cwSEP); /* set up page info */
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
psetb = *hsetb;
|
|||
|
psed = psetb->rgsed;
|
|||
|
|
|||
|
FreezeHp();
|
|||
|
psed += (visedCache = IcpSearch(cp + 1, psed, cchSED, bcpSED, psetb->csed));
|
|||
|
|
|||
|
Assert( (visedCache >= 0) && (visedCache < psetb->csed) );
|
|||
|
|
|||
|
vcpFirstSectCache = (visedCache == 0) ? cp0 : (psed - 1)->cp;
|
|||
|
vcpLimSectCache = psed->cp;
|
|||
|
|
|||
|
if (psed->fc != fcNil)
|
|||
|
{
|
|||
|
pchFprop = PchFromFc(psed->fn, psed->fc, &cchT);
|
|||
|
if (*pchFprop != 0)
|
|||
|
bltbyte(pchFprop + 1, &vsepAbs, *pchFprop);
|
|||
|
}
|
|||
|
|
|||
|
if (vcpFirstSectCache == cp0)
|
|||
|
blt(&vsepAbs, &vsepPage, cwSEP);
|
|||
|
else
|
|||
|
RecalcSepText(); /* Since this is not the first section of a document,
|
|||
|
the margins could be wrong and must be recalculated */
|
|||
|
MeltHp();
|
|||
|
}
|
|||
|
#endif /* CASHMERE */
|
|||
|
|
|||
|
|
|||
|
|
|||
|
CacheSect(doc, cp)
|
|||
|
int doc;
|
|||
|
typeCP cp;
|
|||
|
{ /* Get current section properties into vsepAbs; section
|
|||
|
limits into vcpFirstSectCache, vcpLimSectCache
|
|||
|
MEMO VERSION: one section per document */
|
|||
|
struct DOD *pdod;
|
|||
|
|
|||
|
if (doc == vdocSectCache)
|
|||
|
return;
|
|||
|
|
|||
|
vdocSectCache = doc;
|
|||
|
pdod = &(**hpdocdod)[doc];
|
|||
|
|
|||
|
if ( pdod->hsep )
|
|||
|
blt( *pdod->hsep, &vsepAbs, cwSEP );
|
|||
|
else
|
|||
|
blt( &vsepNormal, &vsepAbs, cwSEP );
|
|||
|
|
|||
|
vcpFirstSectCache = cp0;
|
|||
|
vcpLimSectCache = pdod->cpMac;
|
|||
|
blt(&vsepAbs, &vsepPage, cwSEP);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
RecalcSepText()
|
|||
|
{
|
|||
|
/* calculate value to be changed because of change in page dimensions */
|
|||
|
int xaRight, dxaText, cColumns;
|
|||
|
int yaBottom, dyaText;
|
|||
|
|
|||
|
xaRight = vsepPage.xaMac - vsepPage.cColumns * vsepPage.dxaText -
|
|||
|
vsepPage.xaLeft - vsepPage.dxaGutter -
|
|||
|
(vsepPage.cColumns - 1) * vsepPage.dxaColumns;
|
|||
|
dxaText = vdxaPaper - xaRight - vsepPage.xaLeft;
|
|||
|
cColumns = vsepAbs.cColumns;
|
|||
|
vsepAbs.dxaText = max(dxaMinUseful,
|
|||
|
((dxaText-vsepPage.dxaGutter-(cColumns-1)*vsepAbs.dxaColumns)/cColumns));
|
|||
|
vsepAbs.xaMac = vdxaPaper;
|
|||
|
|
|||
|
/* Calculate bottom margin, correct */
|
|||
|
yaBottom = vsepPage.yaMac - vsepPage.yaTop - vsepPage.dyaText;
|
|||
|
vsepAbs.dyaText = max(dyaMinUseful, vdyaPaper - vsepPage.yaTop - yaBottom);
|
|||
|
vsepAbs.yaMac = vdyaPaper;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
InvalidateCaches(doc)
|
|||
|
int doc;
|
|||
|
{
|
|||
|
if (doc == vfli.doc) /* Invalidate current formatted line */
|
|||
|
vfli.doc = docNil;
|
|||
|
if (doc == vdocExpFetch)
|
|||
|
vdocExpFetch = docNil;
|
|||
|
if (doc == vdocParaCache)
|
|||
|
vdocParaCache = docNil;
|
|||
|
if (doc == vdocSectCache)
|
|||
|
vdocSectCache = docNil;
|
|||
|
|
|||
|
/* When the current doc is equal to the cached doc, it is unnecessary */
|
|||
|
/* to invalidate the page cache when the vcpMinPageCache is 0 and the */
|
|||
|
/* vcpMacPageCache is cpMax, since this indicates that all characters in */
|
|||
|
/* the document are on page 1. */
|
|||
|
if ((doc == vdocPageCache) &&
|
|||
|
(!(vcpMinPageCache == cp0 && vcpMacPageCache == cpMax)))
|
|||
|
vdocPageCache = docNil;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
TrashCache()
|
|||
|
{ /* Invalidate scrolling cache */
|
|||
|
ctrCache = 0;
|
|||
|
cpCacheHint = cp0;
|
|||
|
itrFirstCache = itrLimCache = 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
typeFC FcParaFirst(fn, fc, fcMin)
|
|||
|
int fn;
|
|||
|
typeFC fc, fcMin;
|
|||
|
{ /* Return the fc after the latest para end before fc.
|
|||
|
if there is no para end in [fcMin, fc), return fcNil. */
|
|||
|
struct FCB *pfcb;
|
|||
|
|
|||
|
if ((fn == fnInsert) || (fc == fcMin))
|
|||
|
return fcNil;
|
|||
|
|
|||
|
if (fn == fnScratch && fc >= fcMacPapIns)
|
|||
|
return (fcMin <= fcMacPapIns) ? fcMacPapIns : fcNil;
|
|||
|
|
|||
|
pfcb = &(**hpfnfcb)[fn];
|
|||
|
if (!pfcb->fFormatted)
|
|||
|
{ /* Unformatted file; scan for an EOL */
|
|||
|
typePN pn;
|
|||
|
typeFC fcFirstPage;
|
|||
|
|
|||
|
#ifdef p2bSector
|
|||
|
fcFirstPage = (fc - 1) & ~(cfcPage - 1);
|
|||
|
pn = fcFirstPage / cfcPage;
|
|||
|
#else
|
|||
|
pn = (fc - 1) / cfcPage;
|
|||
|
fcFirstPage = pn * cfcPage;
|
|||
|
#endif
|
|||
|
|
|||
|
while (fc > fcMin)
|
|||
|
{
|
|||
|
CHAR *pch;
|
|||
|
int cchT;
|
|||
|
|
|||
|
pch = PchGetPn( fn, pn--, &cchT, false ) + (fc - fcFirstPage);
|
|||
|
if (fcMin > fcFirstPage)
|
|||
|
fcFirstPage = fcMin;
|
|||
|
while (fc > fcFirstPage)
|
|||
|
{
|
|||
|
if (*(--pch) == chEol)
|
|||
|
{
|
|||
|
return fc;
|
|||
|
}
|
|||
|
fc--;
|
|||
|
}
|
|||
|
fcFirstPage -= cfcPage;
|
|||
|
}
|
|||
|
return fcNil;
|
|||
|
}
|
|||
|
else
|
|||
|
{ /* Formatted file; get info from para run */
|
|||
|
struct FKP *pfkp;
|
|||
|
typeFC fcFirst, fcLim;
|
|||
|
int cchT;
|
|||
|
|
|||
|
pfkp = (struct FKP *) PchGetPn(fn, fn == fnScratch ?
|
|||
|
PnFkpFromFcScr(&vfkpdParaIns, fc) :
|
|||
|
pfcb->pnPara + IFromFc(**pfcb->hgfcPap, fc), &cchT, false);
|
|||
|
if (vfDiskError)
|
|||
|
return fcNil;
|
|||
|
BFromFc(pfkp, fc, &fcFirst, &fcLim);
|
|||
|
return (fcMin < fcFirst) ? fcFirst : fcNil;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
typeFC FcParaLim(fn, fc, fcMac, ppap)
|
|||
|
int fn;
|
|||
|
typeFC fc, fcMac;
|
|||
|
struct PAP *ppap;
|
|||
|
{ /* Return the fc after the first para end after or at fc.
|
|||
|
if there is no para end in [fc, fcMac), return fcNil. */
|
|||
|
/* Also return paragraph properties in ppap */
|
|||
|
struct FCB *pfcb;
|
|||
|
|
|||
|
/* Start out by feeding caller the normal pap */
|
|||
|
#ifdef CASHMERE
|
|||
|
blt(vppapNormal, ppap, cwPAPBase + cwTBD);
|
|||
|
#else
|
|||
|
blt(vppapNormal, ppap, cwPAPBase);
|
|||
|
#endif
|
|||
|
|
|||
|
if ( (fn == fnInsert) || ((fn == fnScratch) && (fc >= fcMacPapIns)) )
|
|||
|
return fcNil;
|
|||
|
|
|||
|
if (!(pfcb = &(**hpfnfcb) [fn])->fFormatted)
|
|||
|
{ /* Unformatted file; scan for EOL */
|
|||
|
typePN pn;
|
|||
|
typeFC fcFirstPage;
|
|||
|
|
|||
|
#ifdef p2bSector
|
|||
|
fcFirstPage = fc & ~(cfcPage - 1);
|
|||
|
pn = fcFirstPage / cfcPage;
|
|||
|
#else
|
|||
|
pn = fc / cfcPage;
|
|||
|
fcFirstPage = pn * cfcPage;
|
|||
|
#endif
|
|||
|
|
|||
|
while (fc < fcMac)
|
|||
|
{
|
|||
|
CHAR *pch;
|
|||
|
int cchT;
|
|||
|
|
|||
|
pch = PchGetPn( fn, pn++, &cchT, false ) + (fc - fcFirstPage);
|
|||
|
|
|||
|
if ((fcFirstPage += cfcPage) > fcMac)
|
|||
|
fcFirstPage = fcMac;
|
|||
|
while (fc < fcFirstPage)
|
|||
|
{
|
|||
|
fc++;
|
|||
|
if (*pch++ == chEol)
|
|||
|
return fc;
|
|||
|
}
|
|||
|
}
|
|||
|
return fcNil;
|
|||
|
}
|
|||
|
else
|
|||
|
{ /* Formatted file; get info from para run */
|
|||
|
struct FKP *pfkp;
|
|||
|
struct FPAP *pfpap;
|
|||
|
int bfpap;
|
|||
|
typeFC fcLim;
|
|||
|
int cchT;
|
|||
|
|
|||
|
pfkp = (struct FKP *) PchGetPn(fn, fn == fnScratch ?
|
|||
|
PnFkpFromFcScr(&vfkpdParaIns, fc) :
|
|||
|
pfcb->pnPara + IFromFc(**pfcb->hgfcPap, fc), &cchT, false);
|
|||
|
if (vfDiskError)
|
|||
|
{ /* Recover from severe disk error reading formatting info */
|
|||
|
blt(vppapNormal, ppap, cwPAP);
|
|||
|
return (fcMac == pfcb->fcMac) ? fcMac : fcNil;
|
|||
|
}
|
|||
|
|
|||
|
{ /* In-line, fast substitute for BFromFc */
|
|||
|
register struct RUN *prun = (struct RUN *) pfkp->rgb;
|
|||
|
|
|||
|
while (prun->fcLim <= fc)
|
|||
|
prun++;
|
|||
|
|
|||
|
fcLim = prun->fcLim;
|
|||
|
bfpap = prun->b;
|
|||
|
}
|
|||
|
|
|||
|
if (fcLim <= fcMac)
|
|||
|
{
|
|||
|
if (bfpap != bNil)
|
|||
|
{ /* Non-standard para */
|
|||
|
pfpap = (struct FPAP *) &pfkp->rgb[bfpap];
|
|||
|
bltbyte(pfpap->rgchPap, ppap, pfpap->cch);
|
|||
|
}
|
|||
|
return fcLim;
|
|||
|
}
|
|||
|
return fcNil;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* B F R O M FC */
|
|||
|
int BFromFc( pfkp, fc, pfcFirst, pfcLim )
|
|||
|
struct FKP *pfkp;
|
|||
|
typeFC fc;
|
|||
|
typeFC *pfcFirst, *pfcLim;
|
|||
|
{ /* Return the base offset & bounds for the first run with fcLim > fc. */
|
|||
|
/* Short table, linear search */
|
|||
|
register struct RUN *prun = (struct RUN *) pfkp->rgb;
|
|||
|
|
|||
|
while (prun->fcLim <= fc)
|
|||
|
prun++;
|
|||
|
|
|||
|
*pfcFirst = ((prun == (struct RUN *)pfkp->rgb) ?
|
|||
|
pfkp->fcFirst : (prun - 1)->fcLim);
|
|||
|
*pfcLim = prun->fcLim;
|
|||
|
return prun->b;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* I F R O M F C */
|
|||
|
int IFromFc(pfcLim, fc)
|
|||
|
register typeFC *pfcLim;
|
|||
|
typeFC fc;
|
|||
|
{ /* Return the index of the first fcLim > fc. */
|
|||
|
int ifc = 0;
|
|||
|
|
|||
|
/* Probably a small table, so linear search? */
|
|||
|
while (*pfcLim++ <= fc)
|
|||
|
++ifc;
|
|||
|
return ifc;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#ifdef BOGUSBL
|
|||
|
/* B F R O M F C */
|
|||
|
int BFromFc(pfkp, fc, pfcFirst, pfcLim)
|
|||
|
struct FKP *pfkp;
|
|||
|
typeFC fc;
|
|||
|
typeFC *pfcFirst, *pfcLim;
|
|||
|
{ /* Return the base offset & bounds for the first run with fcLim > fc. */
|
|||
|
struct RUN *prun, *rgrun;
|
|||
|
int ifcMin, ifcLim;
|
|||
|
|
|||
|
ifcMin = 0;
|
|||
|
ifcLim = pfkp->crun;
|
|||
|
rgrun = (struct RUN *)pfkp->rgb;
|
|||
|
|
|||
|
#ifdef INEFFICIENT
|
|||
|
ifc = IcpSearch(fc + 1, pfkp->rgb, cchRUN, bfcRUN, pfkp->crun);
|
|||
|
#endif
|
|||
|
|
|||
|
while (ifcMin + 1 < ifcLim)
|
|||
|
{
|
|||
|
int ifcGuess = (ifcMin + ifcLim - 1) >> 1;
|
|||
|
if (rgrun[ifcGuess].fcLim <= fc)
|
|||
|
ifcMin = ifcGuess + 1;
|
|||
|
else
|
|||
|
ifcLim = ifcGuess + 1;
|
|||
|
}
|
|||
|
|
|||
|
prun = &rgrun[ifcMin];
|
|||
|
*pfcLim = prun->fcLim;
|
|||
|
*pfcFirst = (ifcMin == 0 ? pfkp->fcFirst : (prun - 1)->fcLim);
|
|||
|
return prun->b;
|
|||
|
}
|
|||
|
#endif /* BOGUSBL */
|
|||
|
|