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.
387 lines
11 KiB
387 lines
11 KiB
#include "precomp.h"
|
|
#pragma hdrstop
|
|
EnableAssert
|
|
|
|
private void TidyBase(P1(AD *));
|
|
private void TidyFi(P1(AD *));
|
|
private void SortEd(P1(AD *));
|
|
private void CheckEd(P1(AD *));
|
|
|
|
F FTidyInit(pad)
|
|
AD *pad;
|
|
{
|
|
if (pad->flags&flagTidyCheckEd && !(pad->flags&(flagAll|flagRecursive)))
|
|
{
|
|
Error("-c should be specified with -a or -r\n");
|
|
return fFalse;
|
|
}
|
|
|
|
if (pad->flags&flagAll || pad->pecmd->gl&fglAll)
|
|
CreatePeekThread(pad);
|
|
|
|
Unreferenced(pad);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
F FTidyDir(pad)
|
|
AD *pad;
|
|
{
|
|
if (!FLoadStatus(pad, lckAll, flsNone))
|
|
return fFalse;
|
|
|
|
if (fVerbose)
|
|
PrErr("Tidy %&P/C\n", pad);
|
|
|
|
TidyBase(pad);
|
|
TidyFi(pad);
|
|
if (!FIsFreeEdValid(pad->psh)) {
|
|
SortEd(pad);
|
|
}
|
|
|
|
if (pad->flags&flagTidyCheckEd)
|
|
CheckEd(pad);
|
|
|
|
OpenLog(pad, fTrue);
|
|
AppendLog(pad, (FI far *)0, (char *)0, pad->szComment);
|
|
CloseLog();
|
|
|
|
FlushStatus(pad);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
private void TidyBase(pad)
|
|
/* This function removes unreferenced base files */
|
|
AD *pad;
|
|
{
|
|
char *pch;
|
|
short fFound;
|
|
int bi; // needs to be int to pass to PchGetW
|
|
IED ied;
|
|
FS far *rgfs;
|
|
register IFS ifs;
|
|
IFS ifsMac = pad->psh->ifiMac;
|
|
DE de;
|
|
FA fa;
|
|
char szFile[cchFileMax + 1];
|
|
PTH pthDir[cchPthMax], pthT[cchPthMax];
|
|
|
|
if (fVerbose)
|
|
PrErr("Removing unreferenced base files\n");
|
|
|
|
|
|
OpenDir(&de, SzPrint(pthDir, szEtcPZ, pad, (char *)NULL), faFiles);
|
|
while (FGetDirSz(&de, szFile, &fa) && *szFile == 'B')
|
|
{
|
|
pch = szFile + 1;
|
|
pch = PchGetW(pch, &bi);
|
|
|
|
/* check for legal file name */
|
|
if (szFile[0] == 'B' && *pch == '\0')
|
|
{
|
|
/* look for bi in rgfs */
|
|
fFound = fFalse;
|
|
for (ied = 0; !fFound && ied < pad->psh->iedMac; ied++)
|
|
{
|
|
rgfs = pad->mpiedrgfs[ied];
|
|
for (ifs = 0; ifs < ifsMac; ifs++)
|
|
{
|
|
if ((int)rgfs[ifs].bi == bi && rgfs[ifs].fm == fmMerge)
|
|
{
|
|
fFound = fTrue;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!fFound)
|
|
/* remove file */
|
|
UnlinkPth(PthForBase(pad, bi, pthT), fxGlobal);
|
|
}
|
|
}
|
|
CloseDir(&de);
|
|
}
|
|
|
|
|
|
void TidyFi(pad)
|
|
/* This function will remove all FI for all files (not dirs) which are
|
|
* deleted. If someone is not ssynced it says who, and asks if it should
|
|
* delete anyway.
|
|
*/
|
|
AD *pad;
|
|
{
|
|
IFI ifi;
|
|
IED ied, iedMac = pad->psh->iedMac;
|
|
FI far *pfi;
|
|
char *sz = "N";
|
|
|
|
if (fVerbose)
|
|
PrErr("Compacting status file by removing unused file slots\n");
|
|
|
|
for (ifi = 0; ifi < pad->psh->ifiMac; ifi++)
|
|
{
|
|
pfi = pad->rgfi + ifi;
|
|
if (pfi->fDeleted && pfi->fk != fkDir)
|
|
{
|
|
int fUnSync = fFalse;
|
|
|
|
for (ied = 0; ied < iedMac; ied++)
|
|
{
|
|
if (PfsForPfi(pad, ied, pfi)->fm != fmNonExistent)
|
|
{
|
|
if (!fUnSync)
|
|
{
|
|
PrErr("The following directories are not in sync with %&C/F:\n", pad, pfi);
|
|
fUnSync = fTrue;
|
|
}
|
|
PrErr("\t%&E\n", pad, ied);
|
|
}
|
|
}
|
|
if (!fUnSync ||
|
|
(FCanPrompt() &&
|
|
(*(sz=SzQuery("Delete anyway (Y or N; ? = list again; CR = stop)? ")) == 'y' || *sz == 'Y')))
|
|
{
|
|
PurgeFi(pad, ifi);
|
|
ifi--; /* counteract next ++ */
|
|
}
|
|
else if (*sz == '?')
|
|
ifi--; /* to display the same one again */
|
|
else if (*sz == '\0')
|
|
/* user typed CR to prompt */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void PurgeFi(AD *pad, IFI ifiToGo)
|
|
/* Remove indicated FI, and log removal */
|
|
{
|
|
IFI ifi, ifiMac = pad->psh->ifiMac;
|
|
IED ied, iedMac = pad->psh->iedMac;
|
|
FI far *rgfi = pad->rgfi;
|
|
FS far * far *mpiedrgfs = pad->mpiedrgfs;
|
|
char szComment[150];
|
|
|
|
AssertLoaded(pad);
|
|
|
|
SzPrint(szComment, "Removed file %&F", pad, rgfi + ifiToGo);
|
|
if (fVerbose)
|
|
PrErr("%s from %&P/C\n", szComment, pad);
|
|
|
|
pad->psh->ifiMac--;
|
|
|
|
for (ifi = ifiToGo; ifi < (IFI)(ifiMac-1); ifi++)
|
|
{
|
|
rgfi[ifi] = rgfi[ifi + 1];
|
|
for (ied = 0; ied < iedMac; ied++)
|
|
mpiedrgfs[ied][ifi] = mpiedrgfs[ied][ifi + 1];
|
|
}
|
|
|
|
/* write out to log */
|
|
OpenLog(pad, fTrue);
|
|
AppendLog(pad, (FI far *)0, (char *)0, szComment);
|
|
CloseLog();
|
|
}
|
|
|
|
|
|
private int CmpEd(P2(ED far *, ED far *));
|
|
|
|
private int CmpEd(ped1, ped2)
|
|
/* Return -1,0,1 if *ped1 <,=,> *ped2, where directories are ordered
|
|
* by nmOwner then by pthEd.
|
|
*/
|
|
ED far *ped1;
|
|
ED far *ped2;
|
|
{
|
|
int wCmp = NmCmpi(ped1->nmOwner, ped2->nmOwner, cchUserMax);
|
|
|
|
return (wCmp != 0) ? wCmp : NmCmpi(ped1->pthEd, ped2->pthEd, cchPthMax);
|
|
}
|
|
|
|
|
|
private void SortEd(pad)
|
|
/* use insertion sort to sort the ED by owner from:
|
|
page 65 of "Writing Efficient Programs," by Jon Bentley.
|
|
|
|
changed to used pointers and 0 based arrays. Mpiedrgfs array is sorted
|
|
sympathetically.
|
|
|
|
Why? I'm sure it ran quickly enough before, and would have been
|
|
a lot more readable! -Jan
|
|
*/
|
|
AD *pad;
|
|
{
|
|
register ED far *pedI;
|
|
register FS far * far *prgfsI;
|
|
FS far * far *prgfsJ, far *rgfsT;
|
|
ED far *pedJ, edT;
|
|
ED far *rged, far *pedMac;
|
|
|
|
if (fVerbose)
|
|
PrErr("Sorting ED\n");
|
|
|
|
AssertLoaded(pad);
|
|
|
|
rged = pad->rged;
|
|
pedMac = rged + pad->psh->iedMac;
|
|
for (pedI = &rged[1], prgfsI = &pad->mpiedrgfs[1]; pedI < pedMac; pedI++, prgfsI++)
|
|
{
|
|
pedJ = pedI;
|
|
prgfsJ = prgfsI;
|
|
edT = *pedJ;
|
|
rgfsT = *prgfsJ;
|
|
while (pedJ > rged && CmpEd(&edT, pedJ-1) < 0)
|
|
{
|
|
*pedJ = *(pedJ-1);
|
|
*prgfsJ = *(prgfsJ-1);
|
|
pedJ--;
|
|
prgfsJ--;
|
|
}
|
|
*pedJ = edT;
|
|
*prgfsJ = rgfsT;
|
|
}
|
|
}
|
|
|
|
static ED far *rgedPar = 0; /* parent directory's rged */
|
|
static IED iedParMac = 0; /* parent directory's ied. */
|
|
|
|
private void CheckEd(pad)
|
|
/* Check that subdirectories' rged conform to their parents'.
|
|
*
|
|
* The first time this routine is called, it saves a copy of the current
|
|
* directories' rged. Subsequent calls check the subdirectory's rged against
|
|
* the saved copy.
|
|
*/
|
|
AD *pad;
|
|
{
|
|
IED iedPar;
|
|
IED ied;
|
|
IED iedMac;
|
|
|
|
AssertLoaded(pad);
|
|
|
|
if (!rgedPar)
|
|
{
|
|
if (fVerbose)
|
|
PrErr("Checking ed (saving ed in %&P/C)\n", pad);
|
|
|
|
iedParMac = pad->psh->iedMac;
|
|
rgedPar = (ED far *)LpbAllocCb(sizeof(ED) * iedParMac, fFalse);
|
|
for (iedPar = 0; iedPar < iedParMac; iedPar++)
|
|
rgedPar[iedPar] = pad->rged[iedPar];
|
|
return;
|
|
}
|
|
|
|
if (fVerbose)
|
|
PrErr("Checking ed in %&P/C\n", pad);
|
|
|
|
/* Merge rgedPar and pad->rged together, discarding duplicates. */
|
|
|
|
ied = 0;
|
|
iedMac = pad->psh->iedMac;
|
|
|
|
iedPar = 0;
|
|
|
|
while (ied < iedMac || iedPar < iedParMac)
|
|
{
|
|
int wCmp; /* -1 if ed, 1 if edPar */
|
|
|
|
if (!(ied < iedMac))
|
|
wCmp = 1;
|
|
else if (!(iedPar < iedParMac))
|
|
wCmp = -1;
|
|
else
|
|
wCmp = CmpEd(pad->rged + ied, rgedPar + iedPar);
|
|
|
|
if (wCmp < 0)
|
|
PrErr("%&P/C extra ED (nmOwner=%&O, pthEd=%&E)\n",
|
|
pad, pad, ied, pad, ied);
|
|
|
|
else if (wCmp > 0)
|
|
{
|
|
char szOwner[cchUserMax + 1];
|
|
char szPthEd[cchPthMax + 1];
|
|
|
|
SzCopyNm(szOwner, rgedPar[iedPar].nmOwner, cchUserMax);
|
|
SzCopyNm(szPthEd, rgedPar[iedPar].pthEd, cchPthMax);
|
|
Error("%&P/C missing ED (nmOwner=%s, pthEd=%s)\n",
|
|
pad, szOwner, szPthEd);
|
|
}
|
|
|
|
ied += wCmp <= 0;
|
|
iedPar += wCmp >= 0;
|
|
}
|
|
}
|
|
|
|
private void LowerPth(P1(PTH far *));
|
|
private void LowerLpch(P2(char far *, int));
|
|
|
|
|
|
F FLowerInit(pad)
|
|
AD *pad;
|
|
{
|
|
if (pad->flags&flagAll || pad->pecmd->gl&fglAll)
|
|
CreatePeekThread(pad);
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
F FLowerDir(pad)
|
|
/* Convert all paths and names in this dir's status file to lower case */
|
|
AD *pad;
|
|
{
|
|
IFI ifi, ifiMac;
|
|
IED ied, iedMac;
|
|
|
|
if (!FLoadStatus(pad, lckAll, flsNone))
|
|
return fFalse;
|
|
|
|
if (fVerbose)
|
|
PrErr("Change %&P/C to lowercase\n", pad);
|
|
|
|
for (ifi = 0, ifiMac = pad->psh->ifiMac; ifi < ifiMac; ifi++)
|
|
LowerLpch(pad->rgfi[ifi].nmFile, cchFileMax);
|
|
|
|
for (ied = 0, iedMac = pad->psh->iedMac; ied < iedMac; ied++) {
|
|
if (!FIsFreeEdValid(pad->psh) || !pad->rged[ied].fFreeEd) {
|
|
LowerPth(pad->rged[ied].pthEd);
|
|
LowerLpch(pad->rged[ied].nmOwner, cchUserMax);
|
|
}
|
|
}
|
|
|
|
/* Leave a log entry */
|
|
OpenLog(pad, fTrue);
|
|
AppendLog(pad, (FI far *)0, (char *)0, pad->szComment);
|
|
CloseLog();
|
|
|
|
FlushStatus(pad);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
private void LowerPth(pth)
|
|
/* converts pth to lower case */
|
|
PTH far *pth;
|
|
{
|
|
while (*pth)
|
|
{
|
|
if (isupper(*pth))
|
|
*pth = (PTH)tolower(*pth);
|
|
pth++;
|
|
}
|
|
}
|
|
|
|
|
|
private void LowerLpch(lpch, cchMac)
|
|
char far *lpch;
|
|
register int cchMac;
|
|
{
|
|
while (cchMac--)
|
|
{
|
|
if (isupper(*lpch))
|
|
*lpch = (char)tolower(*lpch);
|
|
++lpch;
|
|
}
|
|
}
|