331 lines
8.6 KiB
C
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);
|
|
}
|