OSDN Git Service

crystaledit: Use GetProfile*()/WriteProfile*() to read and write the registry wheneve...
[winmerge-jp/winmerge-jp.git] / Src / DirScan.cpp
index c4f98f3..4f45623 100644 (file)
@@ -4,6 +4,7 @@
  *  @brief Implementation of DirScan (q.v.) and helper functions
  */ 
 
+#include "pch.h"
 #include "DirScan.h"
 #include <cassert>
 #include <memory>
@@ -26,7 +27,6 @@
 #include "FolderCmp.h"
 #include "FileFilterHelper.h"
 #include "IAbortable.h"
-#include "FolderCmp.h"
 #include "DirItem.h"
 #include "DirTravel.h"
 #include "paths.h"
@@ -34,6 +34,8 @@
 #include "MergeApp.h"
 #include "OptionsDef.h"
 #include "OptionsMgr.h"
+#include "PathContext.h"
+#include "DebugNew.h"
 
 using Poco::NotificationQueue;
 using Poco::Notification;
@@ -45,15 +47,13 @@ using Poco::Environment;
 using Poco::Stopwatch;
 
 // Static functions (ie, functions only used locally)
-void CompareDiffItem(DIFFITEM &di, CDiffContext * pCtxt);
-static void StoreDiffData(DIFFITEM &di, CDiffContext * pCtxt,
-               const FolderCmp * pCmpData);
-static DIFFITEM *AddToList(const String& sLeftDir, const String& sRightDir, const DirItem * lent, const DirItem * rent,
+static void CompareDiffItem(FolderCmp &fc, DIFFITEM &di);
+static DIFFITEM *AddToList(const String &sLeftDir, const String &sRightDir, const DirItem *lent, const DirItem *rent,
        unsigned code, DiffFuncStruct *myStruct, DIFFITEM *parent);
-static DIFFITEM *AddToList(const String& sDir1, const String& sDir2, const String& sDir3, const DirItem * ent1, const DirItem * ent2, const DirItem * ent3,
+static DIFFITEM *AddToList(const String &sDir1, const String &sDir2, const String &sDir3, const DirItem *ent1, const DirItem *ent2, const DirItem *ent3,
        unsigned code, DiffFuncStruct *myStruct, DIFFITEM *parent, int nItems = 3);
-static void UpdateDiffItem(DIFFITEM & di, bool & bExists, CDiffContext *pCtxt);
-static int CompareItems(NotificationQueue& queue, DiffFuncStruct *myStruct, uintptr_t parentdiffpos);
+static void UpdateDiffItem(DIFFITEM &di, bool &bExists, CDiffContext *pCtxt);
+static int CompareItems(NotificationQueue &queue, DiffFuncStruct *myStruct, DIFFITEM *parentdiffpos);
 
 class WorkNotification: public Poco::Notification
 {
@@ -83,6 +83,7 @@ public:
 
        void run()
        {
+               FolderCmp fc(m_pCtxt);
                // keep the scripts alive during the Rescan
                // when we exit the thread, we delete this and release the scripts
                CAssureScriptsForThread scriptsForRescan;
@@ -94,7 +95,7 @@ public:
                        if (pWorkNf != nullptr) {
                                m_pCtxt->m_pCompareStats->BeginCompare(&pWorkNf->data(), m_id);
                                if (!m_pCtxt->ShouldAbort())
-                                       CompareDiffItem(pWorkNf->data(), m_pCtxt);
+                                       CompareDiffItem(fc, pWorkNf->data());
                                pWorkNf->queueResult().enqueueNotification(new WorkCompletedNotification(pWorkNf->data()));
                        }
                        pNf = m_queue.waitDequeueNotification();
@@ -113,7 +114,7 @@ typedef std::shared_ptr<DiffWorker> DiffWorkerPtr;
  * @brief Collect file- and folder-names to list.
  * This function walks given folders and adds found subfolders and files into
  * lists. There are two modes, determined by the @p depth:
- * - in non-recursive mode we walk only given folders, and add files.
+ * - in non-recursive mode we walk only given folders, and add files
  *   contained. Subfolders are added as folder items, not walked into.
  * - in recursive mode we walk all subfolders and add the files they
  *   contain into list.
@@ -126,7 +127,7 @@ typedef std::shared_ptr<DiffWorker> DiffWorkerPtr;
  * @param [in] rightsubdir Right side subdirectory under root path
  * @param [in] bRightUniq Is right-side folder unique folder?
  * @param [in] myStruct Compare-related data, like context etc.
- * @param [in] casesensitive Is filename compare casesensitive?
+ * @param [in] casesensitive Is filename compare case sensitive?
  * @param [in] depth Levels of subdirectories to scan, -1 scans all
  * @param [in] parent Folder diff item to be scanned
  * @param [in] bUniques If true, walk into unique folders.
@@ -143,12 +144,11 @@ int DirScan_GetItems(const PathContext &paths, const String subdir[],
        String sDir[3];
        String subprefix[3];
 
-       int nIndex;
        std::copy(paths.begin(), paths.end(), sDir);
 
        if (!subdir[0].empty())
        {
-               for (nIndex = 0; nIndex < paths.GetSize(); nIndex++)
+               for (int nIndex = 0; nIndex < paths.GetSize(); nIndex++)
                {
                        sDir[nIndex] = paths::ConcatPath(sDir[nIndex], subdir[nIndex]);
                        subprefix[nIndex] = subdir[nIndex] + backslash;
@@ -156,7 +156,7 @@ int DirScan_GetItems(const PathContext &paths, const String subdir[],
        }
 
        DirItemArray dirs[3], aFiles[3];
-       for (nIndex = 0; nIndex < nDirs; nIndex++)
+       for (int nIndex = 0; nIndex < nDirs; nIndex++)
                LoadAndSortFiles(sDir[nIndex], &dirs[nIndex], &aFiles[nIndex], casesensitive);
 
        // Allow user to abort scanning
@@ -167,10 +167,13 @@ int DirScan_GetItems(const PathContext &paths, const String subdir[],
        // i points to current directory in left list (leftDirs)
        // j points to current directory in right list (rightDirs)
 
-       for (nIndex = 0; nIndex < nDirs; nIndex++)
-               if (dirs[nIndex].size() != 0 || aFiles[nIndex].size() != 0) break;
-       if (nIndex == nDirs)
-               return 0;
+       {
+               int nIndex;
+               for (nIndex = 0; nIndex < nDirs; nIndex++)
+                       if (dirs[nIndex].size() != 0 || aFiles[nIndex].size() != 0) break;
+               if (nIndex == nDirs)
+                       return 0;
+       }
 
        DirItemArray::size_type i=0, j=0, k=0;
        while (true)
@@ -439,6 +442,25 @@ int DirScan_GetItems(const PathContext &paths, const String subdir[],
                }
                break;
        }
+
+       if (parent != nullptr)
+       {
+               for (int nIndex = 0; nIndex < nDirs; ++nIndex)
+                       if (parent->diffcode.exists(nIndex) && parent->diffFileInfo[nIndex].size == DirItem::FILE_SIZE_NONE)
+                               parent->diffFileInfo[nIndex].size = 0;
+       
+               DIFFITEM *dic = parent->GetFirstChild();
+               while (dic)
+               {
+                       for (int nIndex = 0; nIndex < nDirs; ++nIndex)
+                       {
+                               if (dic->diffFileInfo[nIndex].size != DirItem::FILE_SIZE_NONE)
+                                       parent->diffFileInfo[nIndex].size += dic->diffFileInfo[nIndex].size;
+                       }
+                       dic = dic->GetFwdSiblingLink();
+               }
+       }
+
        return 1;
 }
 
@@ -449,7 +471,7 @@ int DirScan_GetItems(const PathContext &paths, const String subdir[],
  * @param parentdiffpos [in] Position of parent diff item 
  * @return >= 0 number of diff items, -1 if compare was aborted
  */
-int DirScan_CompareItems(DiffFuncStruct *myStruct, uintptr_t parentdiffpos)
+int DirScan_CompareItems(DiffFuncStruct *myStruct, DIFFITEM *parentdiffpos)
 {
        const int compareMethod = myStruct->context->GetCompareMethod();
        int nworkers = 1;
@@ -484,7 +506,7 @@ int DirScan_CompareItems(DiffFuncStruct *myStruct, uintptr_t parentdiffpos)
        return res;
 }
 
-static int CompareItems(NotificationQueue& queue, DiffFuncStruct *myStruct, uintptr_t parentdiffpos)
+static int CompareItems(NotificationQueue& queue, DiffFuncStruct *myStruct, DIFFITEM *parentdiffpos)
 {
        NotificationQueue queueResult;
        Stopwatch stopwatch;
@@ -492,11 +514,11 @@ static int CompareItems(NotificationQueue& queue, DiffFuncStruct *myStruct, uint
        int res = 0;
        int count = 0;
        bool bCompareFailure = false;
-       if (parentdiffpos == 0)
+       if (parentdiffpos == nullptr)
                myStruct->pSemaphore->wait();
        stopwatch.start();
-       uintptr_t pos = pCtxt->GetFirstChildDiffPosition(parentdiffpos);
-       while (pos != 0)
+       DIFFITEM *pos = pCtxt->GetFirstChildDiffPosition(parentdiffpos);
+       while (pos != nullptr)
        {
                if (pCtxt->ShouldAbort())
                        break;
@@ -508,7 +530,7 @@ static int CompareItems(NotificationQueue& queue, DiffFuncStruct *myStruct, uint
                        stopwatch.restart();
                }
                myStruct->pSemaphore->wait();
-               uintptr_t curpos = pos;
+               DIFFITEM *curpos = pos;
                DIFFITEM &di = pCtxt->GetNextSiblingDiffRefPosition(pos);
                bool existsalldirs = di.diffcode.existAll();
                if (di.diffcode.isDirectory() && pCtxt->m_bRecursive)
@@ -556,7 +578,8 @@ static int CompareItems(NotificationQueue& queue, DiffFuncStruct *myStruct, uint
                if (pWorkCompletedNf != nullptr) {
                        DIFFITEM &di = pWorkCompletedNf->data();
                        if (di.diffcode.isResultError()) { 
-                               DIFFITEM *diParent = di.parent;
+                               DIFFITEM *diParent = di.GetParentLink();
+                               assert(diParent != nullptr);
                                if (diParent != nullptr)
                                {
                                        diParent->diffcode.diffcode |= DIFFCODE::CMPERR;
@@ -581,13 +604,16 @@ static int CompareItems(NotificationQueue& queue, DiffFuncStruct *myStruct, uint
  * @param parentdiffpos [in] Position of parent diff item 
  * @return >= 0 number of diff items, -1 if compare was aborted
  */
-static int CompareRequestedItems(DiffFuncStruct *myStruct, uintptr_t parentdiffpos)
+static int CompareRequestedItems(DiffFuncStruct *myStruct, DIFFITEM *parentdiffpos)
 {
        CDiffContext *pCtxt = myStruct->context;
+       FolderCmp fc(pCtxt);
        int res = 0;
-       uintptr_t pos = pCtxt->GetFirstChildDiffPosition(parentdiffpos);
-       
-       while (pos != NULL)
+       bool bCompareFailure = false;
+       if (parentdiffpos == nullptr)
+               myStruct->pSemaphore->wait();
+       DIFFITEM *pos = pCtxt->GetFirstChildDiffPosition(parentdiffpos);
+       while (pos != nullptr)
        {
                if (pCtxt->ShouldAbort())
                {
@@ -595,7 +621,7 @@ static int CompareRequestedItems(DiffFuncStruct *myStruct, uintptr_t parentdiffp
                        break;
                }
 
-               uintptr_t curpos = pos;
+               DIFFITEM *curpos = pos;
                DIFFITEM &di = pCtxt->GetNextSiblingDiffRefPosition(pos);
                bool existsalldirs = di.diffcode.existAll();
                if (di.diffcode.isDirectory())
@@ -610,38 +636,56 @@ static int CompareRequestedItems(DiffFuncStruct *myStruct, uintptr_t parentdiffp
                                                di.diffcode.diffcode |= DIFFCODE::DIFF;
                                        res += ndiff;
                                }
-                               else if (ndiff == 0)
+                               else 
+                               if (ndiff == 0)
                                {
                                        if (existsalldirs)
                                                di.diffcode.diffcode |= DIFFCODE::SAME;
+                               } 
+                               else
+                               if (ndiff == -1)
+                               {       // There were file IO-errors during sub-directory comparison.
+                                       di.diffcode.diffcode |= DIFFCODE::CMPERR;
+                                       bCompareFailure = true;
                                }
                        }
                }
                else
                {
                        if (di.diffcode.isScanNeeded())
-                               CompareDiffItem(di, pCtxt);
+                       {
+                               CompareDiffItem(fc, di);
+                               if (di.diffcode.isResultError()) { 
+                                       DIFFITEM *diParent = di.GetParentLink();
+                                       assert(diParent != nullptr);
+                                       if (diParent != nullptr)
+                                       {
+                                               diParent->diffcode.diffcode |= DIFFCODE::CMPERR;
+                                               bCompareFailure = true;
+                                       }
+                       }
+                               
+                       }
                }
                if (di.diffcode.isResultDiff() ||
                        (!existsalldirs && !di.diffcode.isResultFiltered()))
                        res++;
        }
-       return res;
+       return bCompareFailure ? -1 : res;;
 }
 
-int DirScan_CompareRequestedItems(DiffFuncStruct *myStruct, uintptr_t parentdiffpos)
+int DirScan_CompareRequestedItems(DiffFuncStruct *myStruct, DIFFITEM *parentdiffpos)
 {
-       CAssureScriptsForThread scriptsForRescan;
        return CompareRequestedItems(myStruct, parentdiffpos);
 }
 
-static int markChildrenForRescan(CDiffContext *pCtxt, uintptr_t parentdiffpos)
+static int markChildrenForRescan(CDiffContext *pCtxt, DIFFITEM *parentdiffpos)
 {
        int ncount = 0;
-       uintptr_t pos = pCtxt->GetFirstChildDiffPosition(parentdiffpos);
-       while (pos != NULL)
+       DIFFITEM *pos = pCtxt->GetFirstChildDiffPosition(parentdiffpos);
+       while (pos != nullptr)
        {
-               uintptr_t curpos = pos;
+               DIFFITEM *curpos = pos;
                DIFFITEM &di = pCtxt->GetNextSiblingDiffRefPosition(pos);
                if (di.diffcode.isDirectory())
                        ncount += markChildrenForRescan(pCtxt, curpos);
@@ -654,29 +698,36 @@ static int markChildrenForRescan(CDiffContext *pCtxt, uintptr_t parentdiffpos)
        return ncount;
 }
 
-int DirScan_UpdateMarkedItems(DiffFuncStruct *myStruct, uintptr_t parentdiffpos)
+int DirScan_UpdateMarkedItems(DiffFuncStruct *myStruct, DIFFITEM *parentdiffpos)
 {
        CDiffContext *pCtxt = myStruct->context;
-       uintptr_t pos = pCtxt->GetFirstChildDiffPosition(parentdiffpos);
+       DIFFITEM *pos = pCtxt->GetFirstChildDiffPosition(parentdiffpos);
        int ncount = 0;
-       
-       while (pos != NULL)
+
+       while (pos != nullptr)
        {
                if (pCtxt->ShouldAbort())
                        break;
-               uintptr_t curpos = pos;
+               DIFFITEM *curpos = pos;
                DIFFITEM &di = pCtxt->GetNextSiblingDiffRefPosition(pos);
-               bool bItemsExist = true;
                if (di.diffcode.isScanNeeded())
                {
+                       bool bItemsExist = true;
                        UpdateDiffItem(di, bItemsExist, pCtxt);
                        if (!bItemsExist)
-                               di.RemoveSelf();
-                       else if (!di.diffcode.isDirectory())
+                       { 
+                               di.DelinkFromSiblings();        // delink from list of Siblings
+                               delete &di;                                     // Also delete all Children items
+                               continue;                                       // (... because `di` is now invalid)
+                       }
+                       if (!di.diffcode.isDirectory())
                                ++ncount;
                }
-               if (bItemsExist && di.diffcode.isDirectory() && pCtxt->m_bRecursive)
+               if (di.diffcode.isDirectory() && pCtxt->m_bRecursive)
                {
+                       for (int i = 0; i < pCtxt->GetCompareDirs(); ++i)
+                               if (di.diffcode.exists(i))
+                                       di.diffFileInfo[i].size = 0;
                        if (di.diffcode.isScanNeeded() && !di.diffcode.isResultFiltered())
                        {
                                di.RemoveChildren();
@@ -697,6 +748,12 @@ int DirScan_UpdateMarkedItems(DiffFuncStruct *myStruct, uintptr_t parentdiffpos)
                                ncount += DirScan_UpdateMarkedItems(myStruct, curpos);
                        }
                }
+               if (parentdiffpos != nullptr && pCtxt->m_bRecursive)
+               {
+                       for (int nIndex = 0; nIndex < pCtxt->GetCompareDirs(); ++nIndex)
+                               if (curpos->diffFileInfo[nIndex].size != DirItem::FILE_SIZE_NONE)
+                                       parentdiffpos->diffFileInfo[nIndex].size += curpos->diffFileInfo[nIndex].size;
+               }
        }
        return ncount;
 }
@@ -714,7 +771,7 @@ int DirScan_UpdateMarkedItems(DiffFuncStruct *myStruct, uintptr_t parentdiffpos)
  *  - false if items were deleted, so diffitem is not valid
  * @param [in] pCtxt Compare context
  */
-static void UpdateDiffItem(DIFFITEM & di, bool & bExists, CDiffContext *pCtxt)
+static void UpdateDiffItem(DIFFITEM &di, bool & bExists, CDiffContext *pCtxt)
 {
        bExists = false;
        di.diffcode.setSideNone();
@@ -734,9 +791,9 @@ static void UpdateDiffItem(DIFFITEM & di, bool & bExists, CDiffContext *pCtxt)
  *
  * This function does the actual compare for previously gathered list of
  * items. Basically we:
- * - ignore items matching filefilters
+ * - ignore items matching file filters
  * - add non-ignored directories (no compare for directory items)
- * - add  unique files
+ * - add unique files
  * - compare files
  *
  * @param [in] di DiffItem to compare
@@ -744,8 +801,9 @@ static void UpdateDiffItem(DIFFITEM & di, bool & bExists, CDiffContext *pCtxt)
  * @todo For date compare, maybe we should use creation date if modification
  * date is missing?
  */
-void CompareDiffItem(DIFFITEM &di, CDiffContext * pCtxt)
+static void CompareDiffItem(FolderCmp &fc, DIFFITEM &di)
 {
+       CDiffContext *const pCtxt = fc.m_pCtxt;
        int nDirs = pCtxt->GetCompareDirs();
        // Clear rescan-request flag (not set by all codepaths)
        di.diffcode.diffcode &= ~DIFFCODE::NEEDSCAN;
@@ -754,7 +812,6 @@ void CompareDiffItem(DIFFITEM &di, CDiffContext * pCtxt)
        {
                // We don't actually 'compare' directories, just add non-ignored
                // directories to list.
-               StoreDiffData(di, pCtxt, nullptr);
        }
        else
        {
@@ -765,45 +822,26 @@ void CompareDiffItem(DIFFITEM &di, CDiffContext * pCtxt)
                        )
                {
                        di.diffcode.diffcode |= DIFFCODE::INCLUDED;
-                       FolderCmp folderCmp;
-                       di.diffcode.diffcode |= folderCmp.prepAndCompareFiles(pCtxt, di);
-                       StoreDiffData(di, pCtxt, &folderCmp);
+                       di.diffcode.diffcode |= fc.prepAndCompareFiles(di);
+                       di.nsdiffs = fc.m_ndiffs;
+                       di.nidiffs = fc.m_ntrivialdiffs;
+
+                       for (int i = 0; i < nDirs; ++i)
+                       {
+                               // Set text statistics
+                               if (di.diffcode.exists(i))
+                               {
+                                       di.diffFileInfo[i].m_textStats = fc.m_diffFileData.m_textStats[i];
+                                       di.diffFileInfo[i].encoding = fc.m_diffFileData.m_FileLocation[i].encoding;
+                               }
+                       }
                }
                else
                {
                        di.diffcode.diffcode |= DIFFCODE::SKIPPED;
-                       StoreDiffData(di, pCtxt, nullptr);
-               }
-       }
-}
-
-/**
- * @brief Send one file or directory result back through the diff context.
- * @param [in] di Data to store.
- * @param [in] pCtxt Compare context.
- * @param [in] pCmpData Folder compare data.
- */
-static void StoreDiffData(DIFFITEM &di, CDiffContext * pCtxt,
-               const FolderCmp * pCmpData)
-{
-       if (pCmpData != nullptr)
-       {
-               di.nsdiffs = pCmpData->m_ndiffs;
-               di.nidiffs = pCmpData->m_ntrivialdiffs;
-
-               for (int i = 0; i < pCtxt->GetCompareDirs(); ++i)
-               {
-                       // Set text statistics
-                       if (di.diffcode.exists(i))
-                       {
-                               di.diffFileInfo[i].m_textStats = pCmpData->m_diffFileData.m_textStats[i];
-                               di.diffFileInfo[i].encoding = pCmpData->m_diffFileData.m_FileLocation[i].encoding;
-                       }
                }
        }
-
        pCtxt->m_pCompareStats->AddItem(di.diffcode.diffcode);
-       //pCtxt->AddDiff(di);
 }
 
 /**
@@ -826,15 +864,14 @@ static DIFFITEM *AddToList(const String& sLeftDir, const String& sRightDir,
  * @brief Add one compare item to list.
  */
 static DIFFITEM *AddToList(const String& sDir1, const String& sDir2, const String& sDir3,
-       const DirItem * ent1, const DirItem * ent2, const DirItem * ent3,
-       unsigned code, DiffFuncStruct *myStruct, DIFFITEM *parent, int nItems)
+       const DirItem *ent1, const DirItem *ent2, const DirItem *ent3,
+       unsigned code, DiffFuncStruct *myStruct, DIFFITEM *parent, int nItems /*= 3*/)
 {
        // We must store both paths - we cannot get paths later
        // and we need unique item paths for example when items
        // change to identical
-       DIFFITEM *di = myStruct->context->AddDiff(parent);
+       DIFFITEM *di = myStruct->context->AddNewDiff(parent);
 
-       di->parent = parent;
        di->diffFileInfo[0].path = sDir1;
        di->diffFileInfo[1].path = sDir2;
        di->diffFileInfo[2].path = sDir3;
@@ -895,7 +932,10 @@ static DIFFITEM *AddToList(const String& sDir1, const String& sDir2, const Strin
        else
                di->diffcode.diffcode = code | DIFFCODE::THREEWAY;
 
-       myStruct->context->m_pCompareStats->IncreaseTotalItems();
-       myStruct->pSemaphore->set();
+       if (myStruct->m_fncCollect)
+       {
+               myStruct->context->m_pCompareStats->IncreaseTotalItems();
+               myStruct->pSemaphore->set();
+       }
        return di;
 }