|
|
/*
* subcycle.c - Subtree cycle detection routines module. */
/* Headers
**********/
#include "project.h"
#pragma hdrstop
#include "stub.h"
#include "subcycle.h"
/* Constants
************/
/* pointer array allocation constants */
#define NUM_CYCLE_PTRS_TO_ADD (16)
/***************************** Private Functions *****************************/
/* Module Prototypes
********************/
PRIVATE_CODE TWINRESULT CheckHalfForSubtreeCycle(HPTRARRAY, HPATH, HPATH, LPCTSTR);
/*
** CheckHalfForSubtreeCycle() ** ** Checks to see if half of a proposed new folder subtree twin would create one ** or more cycles of folder subtree twins. ** ** Arguments: hpaFolderPairs - handle to PTRARRAY containing pointers to ** folder pairs ** hpathStartFolder - root folder of initial half of proposed ** new folder pair ** hpathEndFolder - root folder of other half of proposed new ** folder pair ** pcszName - name specification of matching objects to be ** included in proposed new folder subtree pair ** ** Returns: TWINRESULT ** ** Side Effects: none ** ** N.b., this function should be called twice for each proposed new folder ** subtree pair. */ PRIVATE_CODE TWINRESULT CheckHalfForSubtreeCycle(HPTRARRAY hpaFolderPairs, HPATH hpathStartFolder, HPATH hpathEndFolder, LPCTSTR pcszName) { TWINRESULT tr; ARRAYINDEX aicFolderPairs; NEWPTRARRAY npa; HPTRARRAY hpaFolders;
ASSERT(IS_VALID_HANDLE(hpaFolderPairs, PTRARRAY)); ASSERT(IS_VALID_HANDLE(hpathStartFolder, PATH)); ASSERT(IS_VALID_HANDLE(hpathEndFolder, PATH)); ASSERT(IS_VALID_STRING_PTR(pcszName, CSTR));
aicFolderPairs = GetPtrCount(hpaFolderPairs);
/*
* Try to create an unsorted pointer array to be used in checking for * cycles. */
npa.aicInitialPtrs = aicFolderPairs; npa.aicAllocGranularity = NUM_CYCLE_PTRS_TO_ADD; npa.dwFlags = 0;
if (CreatePtrArray(&npa, &hpaFolders)) { ARRAYINDEX aicFolders; ARRAYINDEX aiCurFolder; HPATH hpathCurFolderRoot;
/* Search all folder pairs connected to the first new folder twin. */
/*
* Mark all folder twins unused. A "used" folder twin is one that has * already been visited while searching for subtree cycles. I.e., a * used folder subtree pair half intersected the first folder of the * proposed new folder twin, and its other half was added to the list for * later comparison. */
ClearFlagInArrayOfStubs(hpaFolderPairs, STUB_FL_USED);
/*
* Loop to process entire graph of folder subtree twins connected to the * first new folder twin. Folder twins are only added to the hpaFolders * array if they don't already intersect the second of the two proposed * new folder subtree twins. */
tr = TR_SUCCESS; aicFolders = 0; aiCurFolder = 0;
/* Begin with start folder. */
hpathCurFolderRoot = hpathStartFolder;
FOREVER { ARRAYINDEX aiCheckFolderRoot;
/*
* Loop to find all subtree folder pairs that intersect * hpaFolders[aiCurFolder]'s subtree. */
for (aiCheckFolderRoot = 0; aiCheckFolderRoot < aicFolderPairs; aiCheckFolderRoot++) { PFOLDERPAIR pfpCheck;
/* Get this subtree folder pair's root folder. */
pfpCheck = GetPtr(hpaFolderPairs, aiCheckFolderRoot);
ASSERT(IS_VALID_STRUCT_PTR(pfpCheck, CFOLDERPAIR));
/* Have we already visited this folder pair? */
if (IsStubFlagSet(&(pfpCheck->stub), STUB_FL_SUBTREE) && IsStubFlagClear(&(pfpCheck->stub), STUB_FL_BEING_TRANSLATED) && IsStubFlagClear(&(pfpCheck->stub), STUB_FL_USED) && IsStubFlagClear(&(pfpCheck->pfpOther->stub), STUB_FL_USED)) { /*
* No. Does this subtree folder pair intersect the current * folder pair node's subtree, and the objects named in the * proposed new folder subtree twin? */
ASSERT(IsStubFlagSet(&(pfpCheck->pfpOther->stub), STUB_FL_SUBTREE)); ASSERT(IsStubFlagClear(&(pfpCheck->pfpOther->stub), STUB_FL_BEING_TRANSLATED));
if (SubtreesIntersect(hpathCurFolderRoot, pfpCheck->hpath) && NamesIntersect(GetString(pfpCheck->pfpd->hsName), pcszName)) { HPATH hpathOtherCheckFolderRoot;
/* Yes. Get the other side of the folder subtree pair. */
hpathOtherCheckFolderRoot = pfpCheck->pfpOther->hpath;
/*
* Does this pair connect back to the other side of the * proposed new folder pair? */
if (SubtreesIntersect(hpathOtherCheckFolderRoot, hpathEndFolder)) { /*
* Yes. Are the roots different parts of the common * subtree? */
if (ComparePaths(hpathEndFolder, hpathOtherCheckFolderRoot) != CR_EQUAL) { /* Yes. Found a cycle. Bail out. */
WARNING_OUT((TEXT("CheckHalfForSubtreeCycle(): Subtree cycle found connecting folders %s and %s."), DebugGetPathString(hpathStartFolder), DebugGetPathString(hpathEndFolder)));
tr = TR_SUBTREE_CYCLE_FOUND; break; }
/*
* We don't need to include this root in the search if it * is the same as the other side of the proposed new * folder pair since it will be covered during the other * call to CheckHalfForSubtreeCycle(). */ } else { /* Add this subtree as another node to be examined. */
if (! InsertPtr(hpaFolders, NULL, aicFolders++, (PCVOID)(pfpCheck->pfpOther))) tr = TR_OUT_OF_MEMORY; }
/* Mark this folder twin as already visited. */
if (tr == TR_SUCCESS) SetStubFlag(&(pfpCheck->stub), STUB_FL_USED); else break; } } }
/* Any folder subtree twins left to investigate? */
if (aiCurFolder < aicFolders) { PFOLDERPAIR pfpCur;
/* Yes. */
pfpCur = GetPtr(hpaFolders, aiCurFolder++);
hpathCurFolderRoot = pfpCur->hpath; } else /* No. */ break; }
DestroyPtrArray(hpaFolders); } else tr = TR_OUT_OF_MEMORY;
return(tr); }
/****************************** Public Functions *****************************/
/*
** BeginTranslateFolder() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE void BeginTranslateFolder(PFOLDERPAIR pfp) { ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
ASSERT(IsStubFlagClear(&(pfp->stub), STUB_FL_BEING_TRANSLATED)); ASSERT(IsStubFlagClear(&(pfp->pfpOther->stub), STUB_FL_BEING_TRANSLATED));
SetStubFlag(&(pfp->stub), STUB_FL_BEING_TRANSLATED); SetStubFlag(&(pfp->pfpOther->stub), STUB_FL_BEING_TRANSLATED);
return; }
/*
** EndTranslateFolder() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE void EndTranslateFolder(PFOLDERPAIR pfp) { ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
ASSERT(IsStubFlagSet(&(pfp->stub), STUB_FL_BEING_TRANSLATED)); ASSERT(IsStubFlagSet(&(pfp->pfpOther->stub), STUB_FL_BEING_TRANSLATED));
ClearStubFlag(&(pfp->stub), STUB_FL_BEING_TRANSLATED); ClearStubFlag(&(pfp->pfpOther->stub), STUB_FL_BEING_TRANSLATED);
return; }
/*
** CheckForSubtreeCycles() ** ** Checks to see if a proposed new folder subtree twin would create one or more ** cycles of folder subtree twins. ** ** Arguments: ** ** Returns: TWINRESULT ** ** Side Effects: none ** ** N.b., TR_SUBTREE_CYCLE_FOUND is returned if the folder subtree roots of the ** proposed new folder subtree twin are the same. */ PUBLIC_CODE TWINRESULT CheckForSubtreeCycles(HPTRARRAY hpaFolderPairs, HPATH hpathFirstFolder, HPATH hpathSecondFolder, HSTRING hsName) { TWINRESULT tr;
ASSERT(IS_VALID_HANDLE(hpaFolderPairs, PTRARRAY)); ASSERT(IS_VALID_HANDLE(hpathFirstFolder, PATH)); ASSERT(IS_VALID_HANDLE(hpathSecondFolder, PATH)); ASSERT(IS_VALID_HANDLE(hsName, STRING));
/* Are the folder twins cyclical on their own? */
if (SubtreesIntersect(hpathFirstFolder, hpathSecondFolder)) { /* Yes. */
tr = TR_SUBTREE_CYCLE_FOUND;
WARNING_OUT((TEXT("CheckForSubtreeCycles(): Subtree cycle found connecting folders %s and %s."), DebugGetPathString(hpathFirstFolder), DebugGetPathString(hpathSecondFolder))); } else { LPCTSTR pcszName;
/* No. Check for any indirect subtree cycle. */
pcszName = GetString(hsName);
tr = CheckHalfForSubtreeCycle(hpaFolderPairs, hpathFirstFolder, hpathSecondFolder, pcszName);
if (tr == TR_SUCCESS) tr = CheckHalfForSubtreeCycle(hpaFolderPairs, hpathSecondFolder, hpathFirstFolder, pcszName); }
return(tr); }
|