|
|
/*****************************************************************************
* * 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); }
|