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.
479 lines
15 KiB
479 lines
15 KiB
#include "precomp.h"
|
|
#pragma hdrstop
|
|
EnableAssert
|
|
|
|
private void ScanTimeRange(P4(AD *, NE *, PFNL, SM));
|
|
private void ScanCountRange(P4(AD *, NE *, PFNL, SM));
|
|
private F FMoreNe(P1(NE *));
|
|
private F FUseLe(P5(AD *, NE *, F, LE *, NE **));
|
|
private char *SzComPne(P3(NE *pneFiles, char *sz, unsigned ichMax));
|
|
|
|
MF *pmfNewLog = 0; /* mf of new copy of log file */
|
|
|
|
void ScanLog(pad, pneFiles, pfnl, sm)
|
|
/* Scan items in log, calling *pfnl for log entries occuring between the two
|
|
* specified time or count ranges. Actions are modified by the scan mode flags:
|
|
* fsmInOnly - Only use in, addfile, or delfile events.
|
|
* fsmUseAll - Call pfn for every le, with fTrue if in range.
|
|
*/
|
|
AD *pad;
|
|
NE *pneFiles;
|
|
PFNL pfnl;
|
|
SM sm;
|
|
{
|
|
/* Open log read-only, initially scanning backwards from end of log. */
|
|
OpenLog(pad, fFalse);
|
|
|
|
if (pad->tdMin.tdt != tdtNone)
|
|
ScanTimeRange(pad, pneFiles, pfnl, sm);
|
|
else
|
|
ScanCountRange(pad, pneFiles, pfnl, sm);
|
|
|
|
CloseLog();
|
|
}
|
|
|
|
|
|
private void ScanTimeRange(pad, pneFiles, pfnl, sm)
|
|
/* Scan for log entries between pad->tdMin and pad->tdMac. */
|
|
AD *pad;
|
|
NE *pneFiles;
|
|
PFNL pfnl;
|
|
SM sm;
|
|
{
|
|
LE le;
|
|
F fGotLe;
|
|
POS posMin;
|
|
POS posMac;
|
|
NE *pne;
|
|
F fFirst = fTrue;
|
|
FV fvDummy;
|
|
|
|
/* Scan for end of range. */
|
|
posMac = PosScanTd(pad, pad->tdMac, (char *)0, (PFNL)0, &fvDummy);
|
|
|
|
/* Scan for beginning of range. */
|
|
SetLogPos(posMac, fFalse);
|
|
posMin = PosScanTd(pad, pad->tdMin, (char *)0, (PFNL)0, &fvDummy);
|
|
|
|
/* If fsmUseAll, rewind and do early entries. */
|
|
if (sm&fsmUseAll)
|
|
{
|
|
SetLogPos((POS)0, fTrue);
|
|
|
|
while ((fGotLe = FGetLe(&le)) && le.posLog < posMin)
|
|
{
|
|
(*pfnl)(pad, &le, fFirst, fFalse);
|
|
FreeLe(&le);
|
|
}
|
|
|
|
if (fGotLe)
|
|
FreeLe(&le);
|
|
}
|
|
|
|
SetLogPos(posMin, fTrue);
|
|
|
|
/* Do log entries between posMin and posMac. */
|
|
while ((fGotLe = FGetLe(&le)) && le.posLog < posMac)
|
|
{
|
|
if (FUseLe(pad, pneFiles, (sm&fsmInOnly) != 0, &le, &pne))
|
|
{
|
|
(*pfnl)(pad, &le, fFirst, fTrue);
|
|
fFirst = fFalse;
|
|
}
|
|
else if (sm&fsmUseAll)
|
|
(*pfnl)(pad, &le, fFirst, fFalse);
|
|
|
|
FreeLe(&le);
|
|
}
|
|
|
|
/* If fsmUseAll, do remaining entries. */
|
|
if (sm&fsmUseAll && fGotLe)
|
|
{
|
|
do
|
|
{
|
|
(*pfnl)(pad, &le, fFirst, fFalse);
|
|
FreeLe(&le);
|
|
}
|
|
while (FGetLe(&le));
|
|
}
|
|
}
|
|
|
|
|
|
POS PosScanTd(pad, td, szFile, pfnl, pfv)
|
|
/* Scan log entries (presumably in reverse) until we reach an entry whose
|
|
* td is less than or equal to the specified td. Return the position of
|
|
* the last le greater than or equal to the td. This routine factors code
|
|
* out of ScanLog and UnmergeSrc.
|
|
*/
|
|
AD *pad;
|
|
TD td;
|
|
char *szFile;
|
|
PFNL pfnl;
|
|
FV *pfv; /* earliest fv found for this file */
|
|
{
|
|
POS pos = PosOfLog(); /* in case we fail to find any */
|
|
int cLe = 0; /* count of le's for "file@v-3" */
|
|
TD tdLe;
|
|
char szPv[cchPvMax];
|
|
char szPv2[cchPvMax];
|
|
LE le;
|
|
F fGotLe;
|
|
PV pv;
|
|
|
|
*pfv = 0; /* no fv found yet */
|
|
|
|
/* Check if scanning for current version, issue warning if desired
|
|
* version is actually higher than current version.
|
|
*/
|
|
pv = (pad->iedCur != iedNil) ? PvLocal(pad, pad->iedCur): PvGlobal(pad);
|
|
if (td.tdt == tdtPV && CmpPv(td.u.pv, pv) >= 0)
|
|
{
|
|
SzForPv(szPv, td.u.pv, fFalse);
|
|
SzForPv(szPv2, pv, fFalse);
|
|
if (CmpPv(td.u.pv, pv) > 0)
|
|
Warn("%s is higher than current version (%s); using %s\n", szPv, szPv2, szPv2);
|
|
return pos;
|
|
}
|
|
|
|
/* Examine each log entry until we find one which occured no later than
|
|
* the time we are scanning for.
|
|
*/
|
|
while ((fGotLe = FGetLe(&le)) == fTrue)
|
|
{
|
|
/* If this is a file we've been looking for, save its fv. */
|
|
if (szFile && FSameSzFile(&le, szFile))
|
|
*pfv = le.fv;
|
|
|
|
/* Break if this le's pv-number or pv-name is less or equal
|
|
* to the desired one...
|
|
*/
|
|
if (strcmp(le.szLogOp, "release") == 0)
|
|
{
|
|
F fBreak = fFalse;
|
|
char *pchSemi;
|
|
char *pchSp;
|
|
|
|
/* Format of szComLog is: "#.#[.#][ name];comment". */
|
|
|
|
if ((pchSemi = index(le.szComLog, ';')) == 0)
|
|
continue;
|
|
*pchSemi = 0;
|
|
if ((pchSp = index(le.szComLog, ' ')) != 0)
|
|
*pchSp = 0;
|
|
|
|
if (td.tdt == tdtPV && FParsPv(&tdLe, le.szComLog) &&
|
|
CmpPv(tdLe.u.pv, td.u.pv) <= 0)
|
|
{
|
|
fBreak = fTrue;
|
|
|
|
/* Issue a warning if they aren't equal. */
|
|
if (CmpPv(tdLe.u.pv, td.u.pv) != 0)
|
|
Warn("version %s not found (using version %s)\n",
|
|
SzForPv(szPv, td.u.pv, fFalse),
|
|
SzForPv(szPv2, tdLe.u.pv, fFalse));
|
|
}
|
|
|
|
else if (td.tdt == tdtPN && pchSp &&
|
|
strcmp(pchSp + 1, td.u.pv.szName) == 0)
|
|
fBreak = fTrue;
|
|
|
|
/* Restore comment. */
|
|
if (pchSp)
|
|
*pchSp = ' ';
|
|
if (pchSemi)
|
|
*pchSemi = ';';
|
|
|
|
if (fBreak)
|
|
{
|
|
pos = le.posLog;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* ... or if this le's file@fv <= the desired one... */
|
|
else if (td.tdt == tdtFV && szFile &&
|
|
FSameSzFile(&le, szFile) &&
|
|
(td.u.fv >= 0 ? le.fv <= td.u.fv : ++cLe > -td.u.fv))
|
|
{
|
|
if (td.u.fv >= 0 && le.fv < td.u.fv)
|
|
Warn("%s v%d not found (using %s v%d)\n",
|
|
szFile, td.u.fv, szFile, le.fv);
|
|
pos = le.posLog;
|
|
break;
|
|
}
|
|
|
|
/* ... or if this le's time is < the desired one. */
|
|
if (td.tdt == tdtTime)
|
|
{
|
|
/* Save the le position. */
|
|
if (le.timeLog >= td.u.time)
|
|
pos = le.posLog;
|
|
|
|
/* If the times are equal, we unfortunately run into
|
|
* a conflict of interest between UnmergeSrc and
|
|
* ScanLog.
|
|
*
|
|
* If called from UnmergeSrc, we don't want to unmerge
|
|
* this entry; we'd like to break here.
|
|
*
|
|
* If called from ScanLog, we want to keep going, we
|
|
* might find other entries with the same time.
|
|
*/
|
|
if (le.timeLog < td.u.time ||
|
|
(pfnl && le.timeLog == td.u.time)) /* kludge */
|
|
break;
|
|
}
|
|
|
|
/* (For "FUnmergeSrc":) If pfnl defined and this is an
|
|
* appropriate log entry, call pfnl; break if it returns false.
|
|
*/
|
|
if ((strcmp(le.szLogOp, "addfile") == 0 ||
|
|
strcmp(le.szLogOp, "delfile") == 0 ||
|
|
strcmp(le.szLogOp, "in") == 0 ||
|
|
strcmp(le.szLogOp, "rename") == 0) &&
|
|
(szFile == 0 || FSameSzFile(&le, szFile)) &&
|
|
pfnl != 0 &&
|
|
!(*pfnl)(pad, &le, fFalse, fFalse))
|
|
break;
|
|
|
|
FreeLe(&le);
|
|
}
|
|
|
|
if (fGotLe)
|
|
FreeLe(&le);
|
|
else
|
|
{
|
|
/* Didn't find it, issue diagnostic. */
|
|
if (td.tdt == tdtPV)
|
|
Error("version %s not found\n",
|
|
SzForPv(szPv, td.u.pv, fFalse));
|
|
else if (td.tdt == tdtPN)
|
|
FatalError("version %s not found\n", td.u.pv.szName);
|
|
else if (td.tdt == tdtFV)
|
|
Error("version %s v%d not found\n", szFile, td.u.fv);
|
|
else if (td.tdt == tdtTime)
|
|
;
|
|
else
|
|
AssertF(fFalse);
|
|
}
|
|
|
|
return pos;
|
|
}
|
|
|
|
|
|
F FSameSzFile(ple, szFile)
|
|
/* Return fTrue if the log entry applies to the same file as szFile; this is
|
|
* true if szFile matches le.szFile, or if the log entry is a rename and the
|
|
* szFile matches the new name found in le.szComLog.
|
|
*/
|
|
LE *ple;
|
|
char *szFile;
|
|
{
|
|
AssertF(ple != 0 && szFile != 0);
|
|
|
|
return (SzCmp(ple->szFile, szFile) == 0 ||
|
|
(strcmp(ple->szLogOp, "rename") == 0 &&
|
|
NmCmpSz(ple->szComLog, szFile, strlen(szFile)) == 0));
|
|
}
|
|
|
|
|
|
private void ScanCountRange(pad, pneFiles, pfnl, sm)
|
|
/* Scan for log entries between pad->ileMin and pad->ileMac. */
|
|
AD *pad;
|
|
NE *pneFiles;
|
|
PFNL pfnl;
|
|
SM sm;
|
|
{
|
|
F fFreeNe = fFalse;
|
|
NE *pne;
|
|
LE le;
|
|
POS pos;
|
|
F fGotLe;
|
|
int clePrint;
|
|
F fFirst = fTrue;
|
|
|
|
pos = (POS) 0 ;
|
|
if (pneFiles == 0)
|
|
{
|
|
/* If !fsmNoneToAll, will match all names. We use a special
|
|
* name, "*", to indicate this, and to provide a place
|
|
* to store the count.
|
|
*/
|
|
pneFiles = PneNewNm((NM far *)"*", 1, faNormal);
|
|
fFreeNe = fTrue;
|
|
}
|
|
|
|
/* set count to # of earliest record */
|
|
ForEachNe(pne, pneFiles)
|
|
pne->u.cleNe = (short)(pad->ileMac-1);
|
|
|
|
while (FMoreNe(pneFiles) && FGetLe(&le))
|
|
{
|
|
if (FUseLe(pad, pneFiles, ((sm&fsmInOnly) != 0), &le, &pne))
|
|
{
|
|
pne->u.cleNe--;
|
|
pos = le.posLog;
|
|
}
|
|
FreeLe(&le);
|
|
}
|
|
|
|
/* for each ne, we found (ileMac-1)-cleNe records */
|
|
|
|
if (sm&fsmUseAll)
|
|
{
|
|
SetLogPos((POS)0, fTrue);
|
|
|
|
while ((fGotLe = FGetLe(&le)) && le.posLog < pos)
|
|
{
|
|
(*pfnl)(pad, &le, fFirst, fFalse);
|
|
FreeLe(&le);
|
|
}
|
|
|
|
if (fGotLe)
|
|
FreeLe(&le);
|
|
}
|
|
|
|
/* reset for forward movement */
|
|
SetLogPos(pos, fTrue);
|
|
|
|
/* set # to print; may be <= 0 if we did not find any;
|
|
may be > clePrint for some ne if we found more than
|
|
the amount desired.
|
|
*/
|
|
clePrint = pad->ileMac - pad->ileMin;
|
|
ForEachNe(pne, pneFiles)
|
|
pne->u.cleNe = (short)clePrint - pne->u.cleNe;
|
|
|
|
while ((fGotLe = FGetLe(&le)) && FMoreNe(pneFiles))
|
|
{
|
|
if (FUseLe(pad, pneFiles, (sm&fsmInOnly), &le, &pne))
|
|
{
|
|
if (pne->u.cleNe > 0 &&
|
|
(int)(--pne->u.cleNe) < clePrint)
|
|
{
|
|
(*pfnl)(pad, &le, fFirst, fTrue);
|
|
fFirst = fFalse;
|
|
}
|
|
else if (sm&fsmUseAll)
|
|
(*pfnl)(pad, &le, fFirst, fFalse);
|
|
}
|
|
else if (sm&fsmUseAll)
|
|
(*pfnl)(pad, &le, fFirst, fFalse);
|
|
|
|
FreeLe(&le);
|
|
}
|
|
|
|
if (sm&fsmUseAll && fGotLe)
|
|
{
|
|
do
|
|
{
|
|
(*pfnl)(pad, &le, fFirst, fFalse);
|
|
FreeLe(&le);
|
|
}
|
|
while (FGetLe(&le));
|
|
}
|
|
|
|
if (fFreeNe)
|
|
FreeNe(pneFiles);
|
|
}
|
|
|
|
|
|
private F FMoreNe(pneList)
|
|
/* return true if any ne has count > 0 */
|
|
NE *pneList;
|
|
{
|
|
NE *pne;
|
|
|
|
ForEachNe(pne, pneList)
|
|
{
|
|
if (pne->u.cleNe > 0)
|
|
return fTrue;
|
|
}
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
private F FUseLe(pad, pneFiles, fInOnly, ple, ppne)
|
|
register AD *pad;
|
|
F fInOnly;
|
|
NE *pneFiles;
|
|
register LE *ple;
|
|
NE **ppne; /* set to pne found, if any */
|
|
{
|
|
if (pneFiles != 0)
|
|
*ppne = (*SzOfNe(pneFiles) == '*') ? pneFiles : PneLookup(pneFiles, ple->szFile);
|
|
|
|
return (!fInOnly ||
|
|
SzCmp(ple->szLogOp, "addfile") == 0 ||
|
|
SzCmp(ple->szLogOp, "in") == 0 ||
|
|
SzCmp(ple->szLogOp, "delfile") == 0 ||
|
|
SzCmp(ple->szLogOp, "rename") == 0 ||
|
|
SzCmp(ple->szLogOp, "release") == 0) &&
|
|
(pneFiles == 0 || *ppne != 0) &&
|
|
(FEmptyNm(pad->nmUser) ||
|
|
NmCmpSz(pad->nmUser, ple->szUser, cchUserMax) == 0);
|
|
}
|
|
|
|
private F FCopyLog(pad, pneFiles, pfnl, sm)
|
|
AD *pad;
|
|
NE *pneFiles;
|
|
PFNL pfnl;
|
|
SM sm;
|
|
{
|
|
PTH pthNewLog[cchPthMax];
|
|
|
|
pmfNewLog = PmfCreate(PthForLog(pad, pthNewLog), permSysFiles, fFalse,
|
|
fxGlobal);
|
|
|
|
ScanLog(pad, pneFiles, pfnl, sm);
|
|
|
|
CloseMf(pmfNewLog);
|
|
|
|
LogOpPne(pad, pneFiles);
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
void LogOpPne(pad, pneFiles)
|
|
/* Log the operation */
|
|
AD *pad;
|
|
NE *pneFiles;
|
|
{
|
|
char szComment[150];
|
|
|
|
OpenLog(pad, fTrue);
|
|
AppendLog(pad, (FI far *)0, (char *)0,
|
|
SzComPne(pneFiles, szComment, sizeof szComment));
|
|
CloseLog();
|
|
}
|
|
|
|
|
|
private char *SzComPne(pneFiles, sz, ichMax)
|
|
/* Store the szOp and the list of filenames into the sz.
|
|
* e.g. "exfile files: foo baz bar ook"
|
|
*/
|
|
NE *pneFiles;
|
|
char *sz;
|
|
unsigned ichMax;
|
|
{
|
|
NE *pne;
|
|
|
|
if (pneFiles == 0)
|
|
{
|
|
SzPrint(sz, "%s all files", szOp);
|
|
return sz;
|
|
}
|
|
|
|
SzPrint(sz, "%s files:", szOp);
|
|
ForEachNe(pne, pneFiles)
|
|
{
|
|
if (strlen(sz) + strlen(SzOfNe(pne)) + 4 >= ichMax)
|
|
{
|
|
strcat(sz, "...");
|
|
break;
|
|
}
|
|
strcat(sz, " ");
|
|
strcat(sz, SzOfNe(pne));
|
|
}
|
|
return sz;
|
|
}
|