windows-nt/Source/XPSP1/NT/sdktools/m4/divert.c
2020-09-26 16:20:57 +08:00

331 lines
8.6 KiB
C

/*****************************************************************************
*
* divert.c
*
* Diversions.
*
*****************************************************************************/
#include "m4.h"
/*****************************************************************************
*
* fFlushPdiv
*
* Flush a file diversion.
*
*****************************************************************************/
TCH ptszTmpDir[MAX_PATH];
void STDCALL
FlushPdiv(PDIV pdiv)
{
AssertPdiv(pdiv);
Assert(fFilePdiv(pdiv));
if (pdiv->hf == hfNil) {
pdiv->ptchName = ptchAllocCtch(MAX_PATH);
if (GetTempFileName(ptszTmpDir, TEXT("m4-"), 0, pdiv->ptchName)) {
pdiv->hf = hfCreatPtch(pdiv->ptchName);
if (pdiv->hf == hfNil) {
Die("cannot create temp file");
}
} else {
Die("cannot create temp file");
}
}
WriteHfPtchCtch(pdiv->hf, pdiv->ptchMin, ctchPdiv(pdiv));
pdiv->ptchCur = pdiv->ptchMin;
}
#if 0
cbCtch(pdiv->ptchMax - pdiv->ptchMin));
if (cb == cbErr || cb != cbCtch(pdiv->ptchMax - pdiv->ptchMin)) {
Die("error writing file");
}
#endif
/*****************************************************************************
*
* UnbufferPdiv
*
* Make a diversion unbuffered. This is done to stdout when input
* is coming from an interactive device.
*
*****************************************************************************/
void STDCALL
UnbufferPdiv(PDIV pdiv)
{
AssertPdiv(pdiv);
Assert(fFilePdiv(pdiv));
FreePv(pdiv->ptchMin);
pdiv->ptchMin = 0;
pdiv->ptchCur = 0;
pdiv->ptchMax = 0;
}
/*****************************************************************************
*
* GrowPdivCtch
*
* Extend a hold to have at least ctch free characters.
*
*****************************************************************************/
void STDCALL
GrowPdivCtch(PDIV pdiv, CTCH ctch)
{
PTCH ptch;
AssertPdiv(pdiv);
Assert(pdiv->ptchCur >= pdiv->ptchMin);
Assert(pdiv->ptchCur <= pdiv->ptchMax);
ctch = (CTCH)ROUNDUP(((UINT_PTR)(pdiv->ptchMax - pdiv->ptchMin)) + ctch, ctchGrow);
ptch = ptchReallocPtchCtch(pdiv->ptchMin, ctch);
pdiv->ptchCur = (pdiv->ptchCur - pdiv->ptchMin) + ptch;
pdiv->ptchMax = ptch + ctch;
pdiv->ptchMin = ptch;
}
/*****************************************************************************
*
* RoomifyPdivCtch
*
* Try to make room in a diversion for ctch characters, either by
* extending it or by flushing it.
*
* File diversions are flushed to make room, but if that proves
* not enough, we return even though the required amount of space
* is not available. It is the caller's duty to check for this
* case and recover accordingly.
*
* Memory diversions are reallocated.
*
*****************************************************************************/
void STDCALL
RoomifyPdivCtch(PDIV pdiv, CTCH ctch)
{
AssertPdiv(pdiv);
if (fFilePdiv(pdiv)) {
FlushPdiv(pdiv);
} else {
GrowPdivCtch(pdiv, ctch);
}
}
/*****************************************************************************
*
* pdivAlloc
*
*****************************************************************************/
PDIV STDCALL
pdivAlloc(void)
{
PDIV pdiv = pvAllocCb(sizeof(DIV));
pdiv->ptchMin = ptchAllocCtch(ctchGrow);
pdiv->ptchCur = pdiv->ptchMin;
pdiv->ptchMax = pdiv->ptchMin + ctchGrow;
pdiv->ptchName = 0;
pdiv->hf = hfNil;
D(pdiv->cSnap = 0);
D(pdiv->sig = sigDiv);
return pdiv;
}
/*****************************************************************************
*
* OpenPdivPtok
*
* Prepare to load a new token into the diversion. The ptok is
* partially initialized to record the point at which it began.
*
* The diversion must be unsnapped and must be a memory diversion.
* (Data in file diversion buffers can go away when the diversion
* is flushed.)
*
*****************************************************************************/
void STDCALL
OpenPdivPtok(PDIV pdiv, PTOK ptok)
{
#ifdef DEBUG
AssertPdiv(pdiv);
Assert(!pdiv->cSnap);
Assert(!fFilePdiv(pdiv));
D(ptok->sig = sigUPtok);
ptok->tsfl = 0;
ptok->ctch = (CTCH)-1; /* Keep people honest */
#endif
SetPtokItch(ptok, ctchPdiv(pdiv));
}
/*****************************************************************************
*
* AddPdivPtok
* AddPdivTch
*
* Append a (snapped) token or character to the diversion.
*
* Note that in the file diversion case, we need to watch out
* for tokens which are larger than our diversion buffer.
*
*****************************************************************************/
void STDCALL
AddPdivPtok(PDIV pdiv, PTOK ptok)
{
AssertPdiv(pdiv);
AssertSPtok(ptok);
if (ctchSPtok(ptok) > ctchAvailPdiv(pdiv)) {
RoomifyPdivCtch(pdiv, ctchSPtok(ptok));
if (ctchSPtok(ptok) > ctchAvailPdiv(pdiv)) {
Assert(fFilePdiv(pdiv));
WriteHfPtchCtch(pdiv->hf, ptchPtok(ptok), ctchSPtok(ptok));
return;
}
}
CopyPtchPtchCtch(pdiv->ptchCur, ptchPtok(ptok), ctchSPtok(ptok));
pdiv->ptchCur += ctchSPtok(ptok);
Assert(pdiv->ptchCur <= pdiv->ptchMax);
}
void STDCALL
AddPdivTch(PDIV pdiv, TCHAR tch)
{
AssertPdiv(pdiv);
if (pdiv->ptchCur >= pdiv->ptchMax) {
RoomifyPdivCtch(pdiv, 1);
}
*pdiv->ptchCur++ = tch;
Assert(pdiv->ptchCur <= pdiv->ptchMax);
}
/*****************************************************************************
*
* ClosePdivPtok
*
* Conclude the collection of a token in a diversion. The token
* that is returned is not snapped.
*
*****************************************************************************/
void STDCALL
ClosePdivPtok(PDIV pdiv, PTOK ptok)
{
AssertPdiv(pdiv);
AssertUPtok(ptok);
Assert(!fClosedPtok(ptok));
SetPtokCtch(ptok, ctchPdiv(pdiv) - itchPtok(ptok));
}
/*****************************************************************************
*
* PopPdivPtok
*
* Pop a snapped token off a memory diversion. Anything snapped after
* the token is also popped away.
*
* Note that if the token has been modified, this will not necessarily
* pop off everything.
*
*****************************************************************************/
void STDCALL
PopPdivPtok(PDIV pdiv, PTOK ptok)
{
AssertPdiv(pdiv);
AssertSPtok(ptok);
Assert(!fHeapPtok(ptok));
Assert(ptchPtok(ptok) >= pdiv->ptchMin);
Assert(ptchPtok(ptok) <= pdiv->ptchCur);
pdiv->ptchCur = ptchPtok(ptok);
D(pdiv->cSnap = 0);
}
/*****************************************************************************
*
* ptchPdivPtok
*
* Return a pointer to the first character of a diversion-relative
* unsnapped token.
*
*****************************************************************************/
PTCH STDCALL
ptchPdivPtok(PDIV pdiv, PTOK ptok)
{
AssertPdiv(pdiv);
AssertUPtok(ptok);
return pdiv->ptchMin + itchPtok(ptok);
}
/*****************************************************************************
*
* SnapPdivPtok
*
* Convert an unsnapped hold-relative token to a snapped token.
*
*****************************************************************************/
void STDCALL
SnapPdivPtok(PDIV pdiv, PTOK ptok)
{
AssertPdiv(pdiv);
AssertUPtok(ptok);
SetPtokPtch(ptok, ptchPdivPtok(pdiv, ptok));
D(pdiv->cSnap++);
}
/*****************************************************************************
*
* UnsnapPdivPtok
*
* Convert a snapped token back to an unsnapped hold-relative token.
*
*****************************************************************************/
void STDCALL
UnsnapPdivPtok(PDIV pdiv, PTOK ptok)
{
ITCH itch;
AssertPdiv(pdiv);
AssertSPtok(ptok);
itch = (ITCH)(ptchPtok(ptok) - pdiv->ptchMin);
D(ptok->sig = sigUPtok);
SetPtokItch(ptok, itch);
D(pdiv->cSnap--);
}
/*****************************************************************************
*
* CsopPdivDopPdivPtok
*
* A common idiom is
*
* CloseXxxPtok(ptok);
* SnapXxxPtok(&tok);
* Op(Yyy, &tok);
* PopXxxPtok(&tok);
*
* so the Csop (csop = close, snap, op, pop) function does it all for you.
*
*****************************************************************************/
void STDCALL
CsopPdivDopPdivPtok(PDIV pdivSrc, DIVOP op, PDIV pdivDst, PTOK ptok)
{
AssertPdiv(pdivSrc);
AssertUPtok(ptok);
ClosePdivPtok(pdivSrc, ptok);
SnapPdivPtok(pdivSrc, ptok);
op(pdivDst, ptok);
PopPdivPtok(pdivSrc, ptok);
}