mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
756 lines
18 KiB
756 lines
18 KiB
/* catsrc - print current or older versions the source files */
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include "messages.h"
|
|
EnableAssert
|
|
|
|
private F FAnyDotDot(NE *);
|
|
private F FCatFiles(AD *, PTH *);
|
|
private F FCatLe(AD *, LE *, F, F);
|
|
private void RenameLe(AD *pad, LE *ple);
|
|
private void AddHistory(AD *pad, NE **ppneList, LE *ple);
|
|
private F FCatXFiles(AD *, PTH *);
|
|
private void SourceFi(AD *, FI far *);
|
|
private F FCatXLe(AD *, LE *, F, F);
|
|
private void EmptyNe(NE **);
|
|
private void InsNeForDiff(NE **, char *, TDFF, int);
|
|
private F FUndoNe(AD *, char *, NE *, int, PTH *);
|
|
private NE **PpneForSzFile(char *);
|
|
private F FNextSzFile(char *);
|
|
private void ResetSzFiles(void);
|
|
|
|
F
|
|
FCatInit(
|
|
AD *pad)
|
|
{
|
|
if (pad->flags&flagCatX)
|
|
{
|
|
if (FAnyFileTimes(pad->pneFiles) || pad->szPattern)
|
|
{
|
|
Error("-x can't be specified with @<time> or -[ar] <pattern> arguments\n");
|
|
Usage(pad);
|
|
}
|
|
if (pad->tdMin.tdt == tdtNone)
|
|
{
|
|
Error("specify a time (-t) with -x\n");
|
|
Usage(pad);
|
|
}
|
|
/* Clear fFiles flag, we'll extract file names by scanning
|
|
* through the log.
|
|
*/
|
|
pad->pecmd->gl &= ~fglFiles;
|
|
}
|
|
|
|
if (pad->flags&flagCatOutDir)
|
|
{
|
|
if (FAnyDotDot(pad->pneArgs))
|
|
{
|
|
Error("can't use '..' in pathnames with -d\n");
|
|
Usage(pad);
|
|
}
|
|
}
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/* return fTrue if any of the names contain ".." */
|
|
private F
|
|
FAnyDotDot(
|
|
NE *pneList)
|
|
{
|
|
NE *pne;
|
|
char *pch;
|
|
|
|
ForEachNe(pne, pneList)
|
|
{
|
|
pch = SzOfNe(pne);
|
|
while ((pch = index(pch, '.')) != 0)
|
|
if (*++pch == '.')
|
|
return fTrue;
|
|
}
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/* perform Cat operation for this directory */
|
|
F
|
|
FCatDir(
|
|
AD *pad)
|
|
{
|
|
PTH pthDir[cchPthMax];
|
|
|
|
if (pad->flags&flagCatOutDir)
|
|
{
|
|
/* Append new part of pthUSubDir to pthODir to get path to
|
|
* output directory. Create new output directory.
|
|
*/
|
|
if (*pad->pthGlobSubDir)
|
|
SzPrint(pthDir, "%s/%s", pad->pthODir, pad->pthGlobSubDir);
|
|
else
|
|
PthCopy(pthDir, pad->pthODir);
|
|
|
|
if (!FEnsurePth(pthDir))
|
|
{
|
|
Error("can't create output directory \"%s\"\n", pthDir);
|
|
return fFalse;
|
|
}
|
|
}
|
|
|
|
if (!FLoadStatus(pad, lckNil, flsNone))
|
|
return fFalse;
|
|
|
|
/* need script so that we delete temp files generated during unmerge. */
|
|
if (!FInitScript(pad, lckNil))
|
|
{
|
|
Abort();
|
|
return fFalse;
|
|
}
|
|
|
|
if (pad->flags&flagCatX)
|
|
FCatXFiles(pad, pthDir);
|
|
else
|
|
FCatFiles(pad, pthDir);
|
|
|
|
FlushStatus(pad);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/* FCatFiles differs from FCatXFiles in these ways:
|
|
* 1. Filetimes (i.e. "file@v7") are permitted.
|
|
* 2. Rename operations are interpreted differently:
|
|
* If foo@v1 was renamed to baz@v2, then
|
|
* "catsrc -t (before rename) baz"
|
|
* would recreate foo@v1, whereas
|
|
* "catsrc -t (before rename) -x baz"
|
|
* would not create anything.
|
|
*/
|
|
private F
|
|
FCatFiles(
|
|
AD *pad,
|
|
PTH *pthDir)
|
|
{
|
|
NE *pne;
|
|
TD td;
|
|
FI far *pfi;
|
|
F fExists;
|
|
PTH pthFile[cchPthMax];
|
|
PTH *pthOut = (pad->flags&flagCatOutDir) ? pthFile : 0;
|
|
F fTitle = Cne(pad->pneFiles) != 1 && pthOut == 0;
|
|
FV fvDummy;
|
|
|
|
ForEachNe(pne, pad->pneFiles)
|
|
{
|
|
td.tdt = tdtNone;
|
|
|
|
if (pne->u.tdNe.tdt != tdtNone)
|
|
td = pne->u.tdNe;
|
|
else if (pad->tdMin.tdt != tdtNone)
|
|
td = pad->tdMin;
|
|
|
|
SzPrint(pthFile, "%s/%s", pthDir, SzOfNe(pne));
|
|
|
|
if (td.tdt == tdtNone)
|
|
{
|
|
PTH pthSFile[cchPthMax];
|
|
|
|
/* Retrieve current version of file. */
|
|
|
|
if (!FLookupSz(pad, SzOfNe(pne), &pfi, &fExists))
|
|
{
|
|
Error("%s is not a file of %&P/C\n",
|
|
SzOfNe(pne), pad);
|
|
continue;
|
|
}
|
|
|
|
/* Can't be a directory (glob). */
|
|
AssertF(pfi->fk != fkDir);
|
|
|
|
if (fTitle)
|
|
PrOut("---------- %&C/F next ----------\n", pad, pfi);
|
|
CopyFile(pthOut, PthForCachedSFile(pad, pfi, pthSFile),
|
|
permRW, fFalse, fxLocal);
|
|
}
|
|
else
|
|
{
|
|
if (fTitle)
|
|
PrOut("---------- %s next ----------\n", SzOfNe(pne));
|
|
FUnmergeSrc(pad, SzOfNe(pne), td, &fvDummy, permRW, pthOut);
|
|
}
|
|
}
|
|
|
|
/* Keep going even if there were problems. */
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/* SzScanFile is used to kludge PosScanTd into searching for a different
|
|
* filename if a rename operation is seen.
|
|
*/
|
|
static char szScanFile[cchFileMax + 1];
|
|
static NE *pneList;
|
|
|
|
/* Unravel one file to time specified in td, copy the result to pthResult.
|
|
* Called from FCatFiles and FOutOldFiles.
|
|
*/
|
|
F
|
|
FUnmergeSrc(
|
|
AD *pad,
|
|
char *szFile,
|
|
TD td,
|
|
FV *pfv,
|
|
int mode,
|
|
PTH *pthResult)
|
|
{
|
|
FI far *pfi;
|
|
F fExists;
|
|
F fOk;
|
|
|
|
AssertLoaded(pad);
|
|
|
|
pneList = 0;
|
|
|
|
if (FLookupSz(pad, szFile, &pfi, &fExists))
|
|
{
|
|
char szFile[cchFileMax + 1];
|
|
|
|
/* Can't be a directory (glob). */
|
|
AssertF(pfi->fk != fkDir);
|
|
|
|
/* Start with a special "source" diff file. */
|
|
SzPrint(szFile, "%&F", pad, pfi);
|
|
InsNeForDiff(&pneList, szFile, tdffSrcFile, 0);
|
|
}
|
|
|
|
OpenLog(pad, fFalse);
|
|
|
|
strcpy(szScanFile, szFile); /* I'm just sick about it. */
|
|
PosScanTd(pad, td, szScanFile, FCatLe, pfv);
|
|
|
|
CloseLog();
|
|
|
|
pneList = PneReverse(pneList);
|
|
fOk = FUndoNe(pad, szFile, pneList, mode, pthResult);
|
|
|
|
FreeNe(pneList);
|
|
pneList = 0;
|
|
|
|
return fOk;
|
|
}
|
|
|
|
|
|
/* Called from PosScanTd (from FUnmergeSrc), FCatLe notes the effect of one
|
|
* log entry upon its file.
|
|
*/
|
|
private F
|
|
FCatLe(
|
|
AD *pad,
|
|
LE *ple,
|
|
F fIgn1,
|
|
F fIgn2)
|
|
{
|
|
Unreferenced(pad);
|
|
Unreferenced(fIgn1);
|
|
Unreferenced(fIgn2);
|
|
|
|
switch (*ple->szLogOp)
|
|
{
|
|
case 'a': /* addfile */
|
|
EmptyNe(&pneList);
|
|
break;
|
|
|
|
case 'r': /* rename */
|
|
RenameLe(pad, ple);
|
|
break;
|
|
|
|
case 'd': /* delfile */
|
|
case 'i': /* check in */
|
|
AddHistory(pad, &pneList, ple);
|
|
break;
|
|
}
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/* Handle this rename log entry. */
|
|
private void
|
|
RenameLe(
|
|
AD *pad,
|
|
LE *ple)
|
|
{
|
|
char *pchSemi;
|
|
|
|
if (SzCmp(szScanFile, ple->szFile) == 0)
|
|
{
|
|
/* rename old new, szScanFile matches old. Example:
|
|
* rename old new; catsrc old@v-2.
|
|
* In this case we shouldn't have a current history for old,
|
|
* and will create one using the diff referenced by the le.
|
|
*/
|
|
AssertF(pneList == 0);
|
|
AddHistory(pad, &pneList, ple);
|
|
}
|
|
|
|
else if (SzCmpNm(szScanFile, ple->szComLog, strlen(szScanFile)) == 0)
|
|
{
|
|
/* rename old new, szScanFile matches new. Example:
|
|
* rename old new; catsrc new@v-2.
|
|
* In this case we should have a current history for new, and
|
|
* will ignore the diff found in szDiff of the log entry. Make
|
|
* PosScanTd look for "old" instead of "new" entries. Kludgy.
|
|
*
|
|
* Note that we can't assert that we have a current history
|
|
* (pneList != 0); the file might have been unrecoverable.
|
|
*/
|
|
pchSemi = index(ple->szComLog, ';');
|
|
AssertF(pchSemi != 0);
|
|
|
|
*pchSemi = 0;
|
|
SzCopyNm(szScanFile, ple->szFile, cchFileMax);
|
|
*pchSemi = ';';
|
|
}
|
|
|
|
else
|
|
AssertF(fFalse);
|
|
}
|
|
|
|
|
|
/* Append this log entry's change history (if any) to the list. */
|
|
private void
|
|
AddHistory(
|
|
AD *pad,
|
|
NE **ppneList,
|
|
LE *ple)
|
|
{
|
|
TDFF tdff = tdffNil;
|
|
int idae = 0;
|
|
char szFile[cchFileMax + 1];
|
|
|
|
/* Extract the diff file reference if present. */
|
|
if (*ple->szDiFile != 0)
|
|
GetTdffIdaeFromSzDiFile(pad, ple->szDiFile, &tdff, &idae);
|
|
|
|
/* Clear the current history if the diff isn't an incremental change. */
|
|
if (tdff != tdffDiff && tdff != tdffDiffFile)
|
|
EmptyNe(ppneList);
|
|
|
|
SzCopy(szFile, ple->szFile);
|
|
|
|
/* Canonicalize the file name. */
|
|
LowerLsz((char far *)szFile);
|
|
|
|
InsNeForDiff(ppneList, szFile, tdff, idae);
|
|
}
|
|
|
|
|
|
/* Unmerge szFile using the history stored by pneList. If pthResult is
|
|
* non-null, immediately store the result in pthResult, otherwise write
|
|
* it to stdout.
|
|
*/
|
|
private F
|
|
FUndoNe(
|
|
AD *pad,
|
|
char *szFile,
|
|
NE *pneList,
|
|
int mode,
|
|
PTH *pthResult)
|
|
{
|
|
NE *pne;
|
|
PTH pthLocal[cchPthMax];
|
|
PTH pthFile[cchPthMax];
|
|
PTH pth[cchPthMax];
|
|
MF *pmf = 0;
|
|
F fOk = fTrue;
|
|
int cDiffFiles = 0;
|
|
|
|
if (!pneList)
|
|
{
|
|
Error("%s didn't exist at that time.\n", szFile);
|
|
return fFalse;
|
|
}
|
|
|
|
if (TdffOfNe(pneList) == tdffNil)
|
|
{
|
|
/* tdffNil indicates an incomplete change history. */
|
|
Error("can't retrieve %s, incomplete change history\n", szFile);
|
|
return fFalse;
|
|
}
|
|
|
|
SzPrint(pthLocal, "%&/U/Q/Z/", pad, (char *)NULL);
|
|
|
|
/* Unmerge against each diff file. */
|
|
ForEachNe(pne, pneList)
|
|
{
|
|
PTH pthDiff[cchPthMax];
|
|
PTH pthCur[cchPthMax];
|
|
char szDiff[cchPthMax];
|
|
char szCur[cchPthMax];
|
|
int w;
|
|
MF *pmfT;
|
|
char *sz = SzOfNe(pne);
|
|
TDFF tdff = TdffOfNe(pne);
|
|
int idae = IdaeOfNe(pne);
|
|
|
|
AssertF(FValidTdff(tdff));
|
|
|
|
if (tdff == tdffSrcFile || tdff == tdffCkpt)
|
|
{
|
|
/* A source or checkpoint file can only occur as the
|
|
* first file in the list.
|
|
*/
|
|
AssertF(pne == pneList);
|
|
|
|
if (tdff == tdffSrcFile)
|
|
SzPrint(pthFile, "%&/S/src/P/C/%s", pad, sz);
|
|
else
|
|
ExtractDiff(pad, sz, idae, pthFile);
|
|
|
|
pmf = PmfAlloc(pthFile, (char *)0, fxNil);
|
|
continue;
|
|
}
|
|
|
|
AssertF(tdff == tdffDiff || tdff == tdffDiffFile);
|
|
|
|
if (pmf == 0)
|
|
{
|
|
/* Start with empty local temp file. */
|
|
pmf = PmfMkTemp(pthLocal, permRW, fxLocal);
|
|
CloseOnly(pmf);
|
|
}
|
|
|
|
/* Unmerge pmf and diff into pmfT, then replace pmf with pmfT.
|
|
*
|
|
* We have to convert to physical path names.
|
|
*/
|
|
if (tdff == tdffDiffFile)
|
|
SzPrint(pthDiff, "%&/S/diff/P/C/%c%d", pad,
|
|
ChForTdff(tdffDiffFile), idae);
|
|
else
|
|
ExtractDiff(pad, sz, idae, pthDiff);
|
|
|
|
SzPhysPath(szDiff, pthDiff);
|
|
SzPhysTMf(szCur, pmf);
|
|
|
|
pmfT = PmfMkTemp(pthLocal, permRW, fxLocal);
|
|
|
|
/* Unmerge szCur and szDiff > pmfT. */
|
|
if ((w = RunSz("unmerge", pmfT,
|
|
szCur,
|
|
szDiff,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0,
|
|
(char *)0)) != 0)
|
|
{
|
|
if (-1 == w)
|
|
Error(szCantExecute, "unmerge.exe",
|
|
SzForEn(errno));
|
|
else
|
|
Error("unmerge failed (%d)\n", w);
|
|
CloseMf(pmfT);
|
|
fOk = fFalse;
|
|
break;
|
|
}
|
|
CloseOnly(pmfT);
|
|
|
|
if (tdff == tdffDiff)
|
|
UnlinkNow(pthDiff, fFalse);
|
|
|
|
FreeMf(pmf);
|
|
pmf = pmfT;
|
|
|
|
/* delete the now no longer needed unmerged temporary file
|
|
* HERE instead of waiting for the running of the script file
|
|
* to delete it - large CATSRC's would fill up the disk with
|
|
* intermediate unmerge temporary files otherwise. NOTE: We
|
|
* have to NOT do this the first time through because the
|
|
* first szCur used is the master source!
|
|
*/
|
|
if (cDiffFiles++ > 1)
|
|
{
|
|
FPthLogicalSz(pthCur, szCur);
|
|
UnlinkNow(pthCur, fFalse);
|
|
}
|
|
}
|
|
|
|
PthForTMf(pmf, pth);
|
|
FreeMf(pmf);
|
|
|
|
if (fOk)
|
|
{
|
|
if (pthResult)
|
|
CopyNow(pthResult, pth, mode, fxLocal);
|
|
else
|
|
CopyFile((PTH *)0, pth, 0, 0, 0); /* copies to stdout */
|
|
}
|
|
|
|
return fOk;
|
|
}
|
|
|
|
|
|
/* For -x, we may not know which files were in existence at the specified time
|
|
* in history. Thus we must scan the log file at least once just to see what
|
|
* was what. Rather than just building a list of names and then rescanning the
|
|
* log once for each file, we build a list of names and their diff or checkpoint
|
|
* files in a single pass.
|
|
*
|
|
* Before we scan the log, we must first build a representation of files as
|
|
* they currently exist, by scanning through the rgfi. We use the special name
|
|
* Sfilename to identify the current source file.
|
|
*/
|
|
private F
|
|
FCatXFiles(
|
|
AD *pad,
|
|
PTH *pthDir)
|
|
{
|
|
char szFile[cchFileMax + 1];
|
|
PTH pthFile[cchPthMax];
|
|
PTH *pthOut = (pad->flags&flagCatOutDir) ? pthFile : 0;
|
|
NE **ppneList;
|
|
F fTitle;
|
|
FV fvDummy;
|
|
|
|
AssertLoaded(pad);
|
|
|
|
if (pad->pneFiles)
|
|
{
|
|
NE *pne;
|
|
FI far *pfi;
|
|
F fExists;
|
|
|
|
ForEachNe(pne, pad->pneFiles)
|
|
{
|
|
if (FLookupSz(pad, SzOfNe(pne), &pfi, &fExists))
|
|
{
|
|
/* Can't be a directory (glob) */
|
|
AssertF(pfi->fk != fkDir);
|
|
|
|
SourceFi(pad, pfi);
|
|
}
|
|
else
|
|
{
|
|
/* Make a reference to the file; this ensures
|
|
* that we will issue an error message if we
|
|
* don't find the file.
|
|
*/
|
|
PpneForSzFile(SzOfNe(pne));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FI far *pfi;
|
|
FI far *pfiMac = pad->rgfi + pad->psh->ifiMac;
|
|
|
|
for (pfi = pad->rgfi; pfi < pfiMac; pfi++)
|
|
if (!pfi->fDeleted && pfi->fk != fkDir)
|
|
SourceFi(pad, pfi);
|
|
}
|
|
|
|
OpenLog(pad, fFalse);
|
|
PosScanTd(pad, pad->tdMin, (char *)0, FCatXLe, &fvDummy);
|
|
CloseLog();
|
|
|
|
/* The mapping is now complete. For each szFile with a non-empty
|
|
* pneList, unmerge each sz in turn, and store the final result in the
|
|
* specified output file (or stdout).
|
|
*/
|
|
/* Print a title line we are writing to stdout and there is any doubt
|
|
* as to which file we are printing.
|
|
*/
|
|
fTitle = Cne(pad->pneFiles) != 1 && pthOut == 0;
|
|
while (FNextSzFile(szFile))
|
|
{
|
|
if (pad->flags&flagCatOutDir)
|
|
SzPrint(pthFile, "%s/%s", pthDir, szFile);
|
|
|
|
ppneList = PpneForSzFile(szFile);
|
|
|
|
if (fTitle && *ppneList != 0)
|
|
PrOut("---------- %s next ----------\n", szFile);
|
|
|
|
/* Unmerge the file if the list is non-empty, or if the
|
|
* user explicitly specified the file (will issue error).
|
|
*/
|
|
if (*ppneList != 0 || pad->pneFiles != 0)
|
|
{
|
|
*ppneList = PneReverse(*ppneList);
|
|
FUndoNe(pad, szFile, *ppneList, permRW, pthOut);
|
|
}
|
|
}
|
|
ResetSzFiles();
|
|
|
|
/* Keep going even if there were errors. */
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/* Leave a special tdffSrcFile diff entry for this source file. */
|
|
private void
|
|
SourceFi(
|
|
AD *pad,
|
|
FI far *pfi)
|
|
{
|
|
char szFile[cchFileMax + 1];
|
|
|
|
SzPrint(szFile, "%&F", pad, pfi);
|
|
InsNeForDiff(PpneForSzFile(szFile), szFile, tdffSrcFile, 0);
|
|
}
|
|
|
|
|
|
/* Called from PosScanTd (from CatX), FCatXLe notes the effect of one log
|
|
* entry upon the state of the files in the project.
|
|
*/
|
|
private F
|
|
FCatXLe(
|
|
AD *pad,
|
|
LE *ple,
|
|
F fIgn1,
|
|
F fIgn2)
|
|
{
|
|
Unreferenced(fIgn1);
|
|
Unreferenced(fIgn2);
|
|
|
|
if (!pad->pneFiles || PneLookup(pad->pneFiles, ple->szFile))
|
|
{
|
|
NE **ppneList = PpneForSzFile(ple->szFile);
|
|
switch (*ple->szLogOp)
|
|
{
|
|
case 'a': /* addfile */
|
|
EmptyNe(ppneList);
|
|
break;
|
|
|
|
case 'r': /* rename */
|
|
case 'd': /* delfile */
|
|
case 'i': /* check in */
|
|
AddHistory(pad, ppneList, ple);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (*ple->szLogOp == 'r') /* rename */
|
|
{
|
|
char *pchSemi;
|
|
|
|
/* For rename operations (szFile=old name, szComLog=new name;),
|
|
* we treat it as an addfile of the new name, and a delfile
|
|
* of the old name.
|
|
*/
|
|
|
|
pchSemi = index(ple->szComLog, ';');
|
|
AssertF(pchSemi != 0);
|
|
*pchSemi = 0;
|
|
|
|
/* See if the new file name is in pad->pneFiles. */
|
|
if (!pad->pneFiles || PneLookup(pad->pneFiles, ple->szComLog))
|
|
{
|
|
/* Pretend we have an addfile operation. */
|
|
EmptyNe(PpneForSzFile(ple->szComLog));
|
|
}
|
|
|
|
*pchSemi = ';';
|
|
}
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
private void
|
|
EmptyNe(
|
|
NE **ppneList)
|
|
{
|
|
if (*ppneList)
|
|
FreeNe(*ppneList);
|
|
*ppneList = 0;
|
|
}
|
|
|
|
|
|
private void
|
|
InsNeForDiff(
|
|
NE **ppneList,
|
|
char *szFile,
|
|
TDFF tdff,
|
|
int idae)
|
|
{
|
|
NE *pne = PneNewNm(szFile, strlen(szFile), faNormal);
|
|
|
|
TdffOfNe(pne) = tdff;
|
|
IdaeOfNe(pne) = idae;
|
|
|
|
InsertNe(ppneList, pne);
|
|
}
|
|
|
|
/* This module associates a pneList with a file name. */
|
|
|
|
typedef struct
|
|
{
|
|
char *szFile; /* name of file */
|
|
NE *pneList; /* associated pneList */
|
|
} ZL; /* sZ, List pair */
|
|
|
|
static int izlCur = 0;
|
|
static ZL *rgzl = 0;
|
|
static int izlMac = 0;
|
|
|
|
/* Lookup the ppneList corresponding to this file, install a new one if not
|
|
* found.
|
|
*/
|
|
private NE **
|
|
PpneForSzFile(
|
|
char *szFile)
|
|
{
|
|
int izl;
|
|
|
|
/* Lookup szFile in rgzl[].szFile. */
|
|
for (izl = 0; izl < izlMac; izl++)
|
|
if (SzCmp(rgzl[izl].szFile, szFile) == 0)
|
|
return &rgzl[izl].pneList;
|
|
|
|
/* Grow rgzl, init new zl slot. */
|
|
rgzl = (ZL *)PbReallocPbCb((char *)rgzl, ++izlMac * sizeof(ZL));
|
|
rgzl[izl].szFile = SzDup(szFile);
|
|
rgzl[izl].pneList = 0;
|
|
return &rgzl[izl].pneList;
|
|
}
|
|
|
|
|
|
/* Return the next unprocessed szFile and its pneList. */
|
|
private F
|
|
FNextSzFile(
|
|
char *szFile)
|
|
{
|
|
if (izlCur < izlMac)
|
|
{
|
|
strcpy(szFile, rgzl[izlCur++].szFile);
|
|
return fTrue;
|
|
}
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/* Reset this module to its initial state. */
|
|
private void
|
|
ResetSzFiles(
|
|
void)
|
|
{
|
|
if (rgzl)
|
|
{
|
|
int izl;
|
|
|
|
for (izl = 0; izl < izlMac; izl++)
|
|
{
|
|
AssertF(rgzl[izl].szFile != 0);
|
|
free(rgzl[izl].szFile);
|
|
FreeNe(rgzl[izl].pneList);
|
|
}
|
|
free((char *)rgzl);
|
|
}
|
|
rgzl = 0;
|
|
izlCur = 0;
|
|
izlMac = 0;
|
|
}
|