OSDN Git Service

PATCH: [ 787495 ] Create diffutils class (CDiffWrapper)
authorKimmo Varis <kimmov@gmail.com>
Fri, 22 Aug 2003 18:30:34 +0000 (18:30 +0000)
committerKimmo Varis <kimmov@gmail.com>
Fri, 22 Aug 2003 18:30:34 +0000 (18:30 +0000)
Src/DiffWrapper.cpp [new file with mode: 0644]
Src/DiffWrapper.h [new file with mode: 0644]
Src/Merge.dsp
Src/MergeDoc.cpp
Src/MergeDoc.h
Src/readme.txt

diff --git a/Src/DiffWrapper.cpp b/Src/DiffWrapper.cpp
new file mode 100644 (file)
index 0000000..96bd323
--- /dev/null
@@ -0,0 +1,574 @@
+/////////////////////////////////////////////////////////////////////////////
+//    License (GPLv2+):
+//    This program is free software; you can redistribute it and/or modify
+//    it under the terms of the GNU General Public License as published by
+//    the Free Software Foundation; either version 2 of the License, or (at
+//    your option) any later version.
+//    
+//    This program is distributed in the hope that it will be useful, but
+//    WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License
+//    along with this program; if not, write to the Free Software
+//    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+/////////////////////////////////////////////////////////////////////////////
+/** 
+ * @file  DiffWrapper.cpp
+ *
+ * @brief Code for DiffWrapper class
+ *
+ * @date  Created: 2003-08-22
+ */
+// RCS ID line follows -- this is updated by CVS
+// $Id$
+
+#include "stdafx.h"
+#include "coretools.h"
+#include "diffwrapper.h"
+#include "diff.h"
+
+extern int recursive;
+
+CDiffWrapper::CDiffWrapper()
+{
+       ZeroMemory(&m_status, sizeof(DIFFSTATUS));
+       m_bCreatePatchFile = FALSE;
+       m_bUseDiffList = FALSE;
+       m_bAddCmdLine = TRUE;
+       m_bAppendFiles = FALSE;
+       m_nDiffs = 0;
+}
+
+/**
+ * @brief Sets files to compare
+ */
+void CDiffWrapper::SetCompareFiles(CString file1, CString file2)
+{
+       m_sFile1 = file1;
+       m_sFile2 = file2;
+       m_sFile1.Replace('/', '\\');
+       m_sFile2.Replace('/', '\\');
+}
+
+/**
+ * @brief Sets filename of produced patch-file
+ */
+void CDiffWrapper::SetPatchFile(CString file)
+{
+       m_sPatchFile = file;
+       m_sPatchFile.Replace('/', '\\');
+}
+
+/**
+ * @brief Sets pointer to external diff-list filled when analysing files
+ */
+void CDiffWrapper::SetDiffList(CArray<DIFFRANGE,DIFFRANGE> *diffs)
+{
+       ASSERT(diffs);
+       m_diffs = diffs;
+}
+
+/**
+ * @brief Returns current set of options used by diff-engine
+ */
+void CDiffWrapper::GetOptions(DIFFSETTINGS *options)
+{
+       ASSERT(options);
+       CopyMemory(options, &m_options, sizeof(DIFFSETTINGS));
+}
+
+/**
+ * @brief Set options used by diff-engine
+ */
+void CDiffWrapper::SetOptions(DIFFSETTINGS *options)
+{
+       ASSERT(options);
+       CopyMemory(&m_options, options, sizeof(DIFFSETTINGS));
+}
+
+/**
+ * @brief Determines if external diff-list is used
+ */
+BOOL CDiffWrapper::GetUseDiffList() const
+{
+       return m_bUseDiffList;
+}
+
+/**
+ * @brief Enables/disables external diff-list usage
+ */
+BOOL CDiffWrapper::SetUseDiffList(BOOL bUseDiffList)
+{
+       BOOL temp = m_bUseDiffList;
+       m_bUseDiffList = bUseDiffList;
+       return temp;
+}
+
+/**
+ * @brief Determines if patch-file is created
+ */
+BOOL CDiffWrapper::GetCreatePatchFile() const 
+{
+       return m_bCreatePatchFile;
+}
+
+/**
+ * @brief Enables/disables creation of patch-file
+ */
+BOOL CDiffWrapper::SetCreatePatchFile(BOOL bCreatePatchFile)
+{
+       BOOL temp = m_bCreatePatchFile;
+       m_bCreatePatchFile = bCreatePatchFile;
+       return temp;
+}
+
+/**
+ * @brief Runs diff-engine
+ */
+BOOL CDiffWrapper::RunFileDiff()
+{
+       BOOL bRetStatus = FALSE;
+       SwapToInternalOptions();
+
+       if (m_bUseDiffList)
+               m_nDiffs = m_diffs->GetSize();
+
+       // perform rescan
+       struct file_data inf[2] = {0};
+       char *free0 = NULL,*free1 = NULL;
+       CString sdir0, sdir1, sname0, sname1, sext0, sext1;
+       int val,failed=0, depth=0;
+       bool same_files = FALSE;
+       struct change *e, *p;
+       struct change *script = NULL;
+
+       SplitFilename(m_sFile1, &sdir0, &sname0, NULL);
+       SplitFilename(m_sFile2, &sdir1, &sname1, NULL);
+       ZeroMemory(&inf[0], sizeof(inf[0]));
+       ZeroMemory(&inf[1], sizeof(inf[1]));
+
+       /* Both exist and neither is a directory.  */
+       int o_binary = always_text_flag ? 0:O_BINARY;
+
+       /* Open the files and record their descriptors.  */
+       if (sdir0.IsEmpty())
+               inf[0].name = sname0;
+       else
+               inf[0].name = free0 = dir_file_pathname (sdir0, sname0);
+       inf[0].desc = -2;
+       if (sdir1.IsEmpty())
+               inf[1].name = sname1;
+       else
+               inf[1].name = free1 = dir_file_pathname (sdir1, sname1);
+       inf[1].desc = -2;
+       if (inf[0].desc == -2)
+       {
+               if ((inf[0].desc = open (inf[0].name, O_RDONLY|o_binary, 0)) < 0)
+               {
+                       perror_with_name (inf[0].name);
+                       failed = 1;
+               }
+               if (inf[1].desc == -2)
+               {
+                       if (same_files)
+                               inf[1].desc = inf[0].desc;
+                       else if ((inf[1].desc = open (inf[1].name, O_RDONLY|o_binary, 0)) < 0)
+                       {
+                               perror_with_name (inf[1].name);
+                               failed = 1;
+                       }
+                       
+                       /* Compare the files, if no error was found.  */
+                       int diff_flag = 0;
+
+                       // Diff files. depth is zero because we are not comparind dirs
+                       script = diff_2_files (inf, 0, &diff_flag);
+
+                       // We don't anymore create diff-files for every rescan.
+                       // User can create patch-file whenever one wants to.
+                       // We don't need to waste time. But lets keep this as
+                       // debugging aid. Sometimes it is very useful to see
+                       // what differences diff-engine sees!
+#ifdef _DEBUG
+                       // throw the diff into a temp file
+                       char lpBuffer[MAX_PATH] = {0};       // path buffer
+                       GetTempPath(MAX_PATH,lpBuffer);         // get path to Temp folder
+                       CString path = CString(lpBuffer) + _T("Diff.txt");
+
+                       outfile = fopen(path, "w+");
+                       if (outfile != NULL)
+                       {
+                               print_normal_script(script);
+                               fclose(outfile);
+                               outfile=NULL;
+                       }
+#endif
+                       // Create patch file
+                       if (m_bCreatePatchFile)
+                       {
+                               outfile = fopen(m_sPatchFile, "w+");
+
+                               if (outfile != NULL)
+                               {
+                                       // Print "command line"
+                                       if (m_bAddCmdLine)
+                                       {
+                                               CString switches = FormatSwitchString();
+                                               fprintf(outfile, "diff%s %s %s\n", 
+                                                       switches, inf[0].name , inf[1].name);
+                                       }
+
+                                       // Output patchfile
+                                       switch (output_style)
+                                       {
+                                       case OUTPUT_CONTEXT:
+                                               print_context_header(files, 0);
+                                               print_context_script(script, 0);
+                                               break;
+                                               
+                                       case OUTPUT_UNIFIED:
+                                               print_context_header(files, 1);
+                                               print_context_script(script, 1);
+                                               break;
+                                               
+                                       case OUTPUT_ED:
+                                               print_ed_script(script);
+                                               break;
+                                               
+                                       case OUTPUT_FORWARD_ED:
+                                               pr_forward_ed_script(script);
+                                               break;
+                                               
+                                       case OUTPUT_RCS:
+                                               print_rcs_script(script);
+                                               break;
+                                               
+                                       case OUTPUT_NORMAL:
+                                               print_normal_script(script);
+                                               break;
+                                               
+                                       case OUTPUT_IFDEF:
+                                               print_ifdef_script(script);
+                                               break;
+                                               
+                                       case OUTPUT_SDIFF:
+                                               print_sdiff_script(script);
+                                       }
+                                       
+                                       fclose(outfile);
+                                       outfile = NULL;
+                               }
+                               else
+                                       m_status.bPatchFileFailed = TRUE;
+                       }
+                       
+                       // Go through diffs adding them to WinMerge's diff list
+                       // This is done on every WinMerge's doc rescan!
+                       if (m_bUseDiffList)
+                       {
+                               struct change *next = script;
+                               int trans_a0, trans_b0, trans_a1, trans_b1;
+                               int first0, last0, first1, last1, deletes, inserts, op;
+                               struct change *thisob, *end;
+                               
+                               while (next)
+                               {
+                                       /* Find a set of changes that belong together.  */
+                                       thisob = next;
+                                       end = find_change(next);
+                                       
+                                       /* Disconnect them from the rest of the changes,
+                                       making them a hunk, and remember the rest for next iteration.  */
+                                       next = end->link;
+                                       end->link = 0;
+#ifdef DEBUG
+                                       debug_script(thisob);
+#endif
+
+                                       /* Print thisob hunk.  */
+                                       //(*printfun) (thisob);
+                                       {                                       
+                                               /* Determine range of line numbers involved in each file.  */
+                                               analyze_hunk (thisob, &first0, &last0, &first1, &last1, &deletes, &inserts);
+                                               if (!(!deletes && !inserts))
+                                               {
+                                                       if (deletes && inserts)
+                                                               op = OP_DIFF;
+                                                       else if (deletes)
+                                                               op = OP_LEFTONLY;
+                                                       else
+                                                               op = OP_RIGHTONLY;
+                                                       
+                                                       /* Print the lines that the first file has.  */
+                                                       translate_range (&inf[0], first0, last0, &trans_a0, &trans_b0);
+                                                       translate_range (&inf[1], first1, last1, &trans_a1, &trans_b1);
+                                                       AddDiffRange(trans_a0-1, trans_b0-1, trans_a1-1, trans_b1-1, (BYTE)op);
+                                                       TRACE("left=%d,%d   right=%d,%d   op=%d\n",trans_a0-1, trans_b0-1, trans_a1-1, trans_b1-1, op);
+                                               }
+                                       }
+                                       
+                                       /* Reconnect the script so it will all be freed properly.  */
+                                       end->link = next;
+                               }
+                       }                       
+
+                       // cleanup the script
+                       for (e = script; e; e = p)
+                       {
+                               p = e->link;
+                               free (e);
+                       }
+
+                       cleanup_file_buffers(inf);
+                       
+                       /* Close the file descriptors.  */
+                       if (inf[0].desc >= 0 && close (inf[0].desc) != 0)
+                       {
+                               perror_with_name (inf[0].name);
+                               val = 2;
+                       }
+                       if (inf[1].desc >= 0 && inf[0].desc != inf[1].desc
+                               && close (inf[1].desc) != 0)
+                       {
+                               perror_with_name (inf[1].name);
+                               val = 2;
+                       }
+
+                       m_status.bBinaries = diff_flag > 0;
+                       m_status.bLeftMissingNL = inf[0].missing_newline;
+                       m_status.bRightMissingNL = inf[1].missing_newline;
+               }
+       }
+       
+       if (free0)
+               free (free0);
+       if (free1)
+               free (free1);
+
+       SwapToGlobalOptions();
+
+       bRetStatus = !failed;
+       if (failed)
+       {
+               // Do not return error status when binary file is found, as we
+               // return binary status in status struct
+               if (m_status.bBinaries)
+                       bRetStatus = TRUE;
+       }
+
+       return bRetStatus;
+}
+
+/**
+ * @brief Replaces global options used by diff-engine with options in diff-wrapper
+ */
+void CDiffWrapper::SwapToInternalOptions()
+{
+       // Save current settings to temp variables
+       m_globalOptions.outputStyle = output_style;
+       output_style = m_options.outputStyle;
+       
+       m_globalOptions.context = context;
+       context = m_options.context;
+       
+       m_globalOptions.alwaysText = always_text_flag;
+       always_text_flag = m_options.alwaysText;
+
+       m_globalOptions.horizLines = horizon_lines;
+       horizon_lines = m_options.horizLines;
+
+       m_globalOptions.ignoreSpaceChange = ignore_space_change_flag;
+       ignore_space_change_flag = m_options.ignoreSpaceChange;
+
+       m_globalOptions.ignoreAllSpace = ignore_all_space_flag;
+       ignore_all_space_flag = m_options.ignoreAllSpace;
+
+       m_globalOptions.ignoreBlankLines = ignore_blank_lines_flag;
+       ignore_blank_lines_flag = m_options.ignoreBlankLines;
+
+       m_globalOptions.ignoreCase = ignore_case_flag;
+       ignore_case_flag = m_options.ignoreCase;
+
+       m_globalOptions.heuristic = heuristic;
+       heuristic = m_options.heuristic;
+
+       m_globalOptions.recursive = recursive;
+       recursive = m_options.recursive;
+}
+
+/**
+ * @brief Resumes global options as they were before calling SwapToInternalOptions()
+ */
+void CDiffWrapper::SwapToGlobalOptions()
+{
+       // Resume values
+       output_style = m_globalOptions.outputStyle;
+       context = m_globalOptions.context;
+       always_text_flag = m_globalOptions.alwaysText;
+       horizon_lines = m_globalOptions.horizLines;
+       ignore_space_change_flag = m_globalOptions.ignoreSpaceChange;
+       ignore_all_space_flag = m_globalOptions.ignoreAllSpace;
+       ignore_blank_lines_flag = m_globalOptions.ignoreBlankLines;
+       ignore_case_flag = m_globalOptions.ignoreCase;
+       heuristic = m_globalOptions.heuristic;
+       recursive = m_globalOptions.recursive;
+}
+
+/**
+ * @brief Add diff to external diff-list
+ */
+void CDiffWrapper::AddDiffRange(UINT begin0, UINT end0, UINT begin1, UINT end1, BYTE op)
+{
+       TRY {
+               DIFFRANGE dr = {0};
+               dr.begin0 = begin0;
+               dr.end0 = end0;
+               dr.begin1 = begin1;
+               dr.end1 = end1;
+               dr.op = op;
+               dr.blank0 = dr.blank1 = -1;
+               m_diffs->SetAtGrow(m_nDiffs, dr);
+               m_nDiffs++;
+       }
+       CATCH_ALL(e)
+       {
+               TCHAR msg[1024] = {0};
+               e->GetErrorMessage(msg, 1024);
+               AfxMessageBox(msg, MB_ICONSTOP);
+       }
+       END_CATCH_ALL;
+}
+
+/**
+ * @brief Expand last DIFFRANGE of file by one line to contain last line after EOL.
+ */
+void CDiffWrapper::FixLastDiffRange(int leftBufferLines, int rightBufferLines, BOOL left)
+{
+       DIFFRANGE dr = {0};
+       int count = m_diffs->GetSize();
+       if (count > 0)
+       {
+               dr = m_diffs->GetAt(count - 1);
+
+               if (left)
+               {
+                       if (dr.op == OP_RIGHTONLY)
+                               dr.op = OP_DIFF;
+                       dr.end0++;
+               }
+               else
+               {
+                       if (dr.op == OP_LEFTONLY)
+                               dr.op = OP_DIFF;
+                       dr.end1++;
+               }
+
+               m_diffs->SetAt(count - 1, dr); 
+       }
+       else 
+       {
+               // we have to create the DIFF
+               dr.end0 = leftBufferLines - 1;
+               dr.end1 = rightBufferLines - 1;
+               if (left)
+               {
+                       dr.begin0 = dr.end0;
+                       dr.begin1 = dr.end1 + 1;
+                       dr.op = OP_LEFTONLY;
+               }
+               else
+               {
+                       dr.begin0 = dr.end0 + 1;
+                       dr.begin1 = dr.end1;
+                       dr.op = OP_RIGHTONLY;
+               }
+               ASSERT(dr.begin0 == dr.begin1);
+
+               AddDiffRange(dr.begin0, dr.end0, dr.begin1, dr.end1, dr.op); 
+       }
+}
+
+/**
+ * @brief Returns status-data from diff-engine last run
+ */
+void CDiffWrapper::GetDiffStatus(DIFFSTATUS *status)
+{
+       CopyMemory(status, &m_status, sizeof(DIFFSTATUS));
+}
+
+/**
+ * @brief Formats command-line for diff-engine last run (like it was called from command-line)
+ */
+CString CDiffWrapper::FormatSwitchString()
+{
+       CString switches;
+       TCHAR tmpNum[5] = {0};
+       
+       switch (m_options.outputStyle)
+       {
+       case OUTPUT_CONTEXT:
+               switches = _T(" C");
+               break;
+       case OUTPUT_UNIFIED:
+               switches = _T(" U");
+               break;
+       case OUTPUT_ED:
+               switches = _T(" e");
+               break;
+       case OUTPUT_FORWARD_ED:
+               switches = _T(" f");
+               break;
+       case OUTPUT_RCS:
+               switches = _T(" n");
+               break;
+       case OUTPUT_NORMAL:
+               switches = _T(" ");
+               break;
+       case OUTPUT_IFDEF:
+               switches = _T(" D");
+               break;
+       case OUTPUT_SDIFF:
+               switches = _T(" y");
+               break;
+       }
+
+       if (m_options.context > 0)
+       {
+               _itot(m_options.context, tmpNum, 10);
+               switches += tmpNum;
+       }
+
+       if (m_options.ignoreAllSpace > 0)
+               switches += _T("w");
+
+       if (m_options.ignoreBlankLines > 0)
+               switches += _T("B");
+
+       if (m_options.ignoreCase > 0)
+               switches += _T("i");
+
+       if (m_options.ignoreSpaceChange > 0)
+               switches += _T("b");
+
+       return switches;
+}
+
+/**
+ * @brief Determines if patch-files are appended (not overwritten)
+ */
+BOOL CDiffWrapper::GetAppendFiles() const
+{
+       return m_bAppendFiles;
+}
+
+/**
+ * @brief Enables/disables patch-file appending (files with same filename are appended)
+ */
+BOOL CDiffWrapper::SetAppendFiles(BOOL bAppendFiles)
+{
+       BOOL temp = m_bAppendFiles;
+       m_bAppendFiles = bAppendFiles;
+       return temp;
+}
diff --git a/Src/DiffWrapper.h b/Src/DiffWrapper.h
new file mode 100644 (file)
index 0000000..31954a2
--- /dev/null
@@ -0,0 +1,126 @@
+/////////////////////////////////////////////////////////////////////////////
+//    License (GPLv2+):
+//    This program is free software; you can redistribute it and/or modify
+//    it under the terms of the GNU General Public License as published by
+//    the Free Software Foundation; either version 2 of the License, or
+//    (at your option) any later version.
+//
+//    This program is distributed in the hope that it will be useful, but
+//    WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//    General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License
+//    along with this program; if not, write to the Free Software
+//    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+/////////////////////////////////////////////////////////////////////////////
+/** 
+ * @file  DiffWrapper.h
+ *
+ * @brief Declaration file for CDirColsDlg
+ *
+ * @date  Created: 2003-08-22
+ */
+// RCS ID line follows -- this is updated by CVS
+// $Id$
+
+#ifndef _DIFFWRAPPER_H
+#define _DIFFWRAPPER_H
+
+/**
+ * @brief Operations in diffranges.
+ * DIFFRANGE structs op-member can have these values
+ */
+enum
+{
+       OP_NONE = 0,
+       OP_LEFTONLY,
+       OP_DIFF,
+       OP_RIGHTONLY
+};
+
+/**
+ * @brief One difference defined by linenumbers
+ * @note xxxx1 values are calculated in CMergeDoc::PrimeTextBuffers()
+ */
+typedef struct tagDIFFRANGE
+{
+       UINT begin0,end0,begin1,end1;
+       UINT dbegin0,dend0,dbegin1,dend1;
+       int blank0,blank1;
+       BYTE op;
+} DIFFRANGE;
+
+/**
+ * @brief Diffutils options
+ * @note DO NOT add diff-unrelated data here!
+ */
+typedef struct tagDIFFSETTINGS
+{
+       enum output_style outputStyle;
+       int context;
+       int alwaysText;
+       int horizLines;
+       int ignoreSpaceChange;
+       int ignoreAllSpace;
+       int ignoreBlankLines;
+       int ignoreCase;
+       int heuristic;
+       int recursive;
+} DIFFSETTINGS;
+
+/**
+ * @brief Diffutils returns this statusdata about files compared
+ */
+typedef struct tagDIFFSTATUS
+{
+       BOOL bLeftMissingNL;
+       BOOL bRightMissingNL;
+       BOOL bBinaries;
+       BOOL bPatchFileFailed;
+} DIFFSTATUS;
+
+/**
+ * @brief Wrapper class for GNU/diffutils
+ */
+class CDiffWrapper
+{
+public:
+       CDiffWrapper();
+       void SetCompareFiles(CString file1, CString file2);
+       void SetPatchFile(CString file);
+       void SetDiffList(CArray<DIFFRANGE,DIFFRANGE> *diffs);
+       void GetOptions(DIFFSETTINGS *options);
+       void SetOptions(DIFFSETTINGS *options);
+       BOOL GetUseDiffList() const;
+       BOOL SetUseDiffList(BOOL bUseDiffList);
+       BOOL GetAppendFiles() const;
+       BOOL SetAppendFiles(BOOL bAppendFiles);
+       BOOL GetCreatePatchFile() const;
+       BOOL SetCreatePatchFile(BOOL bCreatePatchFile);
+       BOOL RunFileDiff();
+       void GetDiffStatus(DIFFSTATUS *status);
+       void AddDiffRange(UINT begin0, UINT end0, UINT begin1, UINT end1, BYTE op);
+       void FixLastDiffRange(int leftBufferLines, int rightBufferLines, BOOL left);
+
+protected:
+       void SwapToInternalOptions();
+       void SwapToGlobalOptions();
+       CString FormatSwitchString();
+
+private:
+       DIFFSETTINGS m_options;
+       DIFFSETTINGS m_globalOptions;   // Temp for storing globals
+       DIFFSTATUS m_status;
+       CString m_sFile1;
+       CString m_sFile2;
+       CString m_sPatchFile;
+       BOOL m_bUseDiffList;
+       BOOL m_bCreatePatchFile;
+       BOOL m_bAddCmdLine;
+       BOOL m_bAppendFiles;
+       int m_nDiffs;
+       CArray<DIFFRANGE,DIFFRANGE> *m_diffs;
+};
+
+#endif // _DIFFWRAPPER_H
\ No newline at end of file
index e5596cf..e993398 100644 (file)
@@ -196,6 +196,10 @@ SOURCE=.\DiffThread.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=.\DiffWrapper.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\DirActions.cpp
 # End Source File
 # Begin Source File
@@ -672,6 +676,10 @@ SOURCE=.\DiffThread.h
 # End Source File
 # Begin Source File
 
+SOURCE=.\DiffWrapper.h
+# End Source File
+# Begin Source File
+
 SOURCE=.\DirDoc.h
 # End Source File
 # Begin Source File
index bdf4a1e..bf72f9b 100644 (file)
 //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 //
 /////////////////////////////////////////////////////////////////////////////
-// MergeDoc.cpp : implementation of the CMergeDoc class
-//
+/** 
+ * @file  MergeDoc.cpp
+ *
+ * @brief Implementation file for CMergeDoc
+ *
+ */
+// RCS ID line follows -- this is updated by CVS
 // $Id$
 
 #include "stdafx.h"
 #include "Merge.h"
 #include "direct.h"
-
 #include "MainFrm.h"
 
 #include "diff.h"
@@ -48,6 +52,9 @@ static char THIS_FILE[] = __FILE__;
 #endif
 
 
+/**
+ * @brief EOL types
+ */
 static LPCTSTR crlfs[] =
 {
        _T ("\x0d\x0a"), //  DOS/Windows style
@@ -175,7 +182,6 @@ BOOL CMergeDoc::OnNewDocument()
        CString s;
        VERIFY(s.LoadString(IDS_FILE_COMPARISON_TITLE));
        SetTitle(s);
-
        
        m_ltBuf.InitNew ();
        m_rtBuf.InitNew ();
@@ -217,11 +223,26 @@ void CMergeDoc::Dump(CDumpContext& dc) const
 /////////////////////////////////////////////////////////////////////////////
 // CMergeDoc commands
 
-
-
-// Save files under edit to temp files & compare again, to update diffs on screen
+/**
+* @brief Save files to temp files & compare again.
+*
+* @param bForced If TRUE, suppressing is ignored and rescan is done always
+*
+* @return Tells status of rescan done (OK, suppressed, etc)
+*
+* @note Rescan() ALWAYS compares temp files. Actual user files are not
+* touched by Rescan().
+*
+* @sa CDiffWrapper::RunFileDiff()
+*
+*/
 int CMergeDoc::Rescan(BOOL bForced /* =FALSE */)
 {
+       DIFFSETTINGS diffSettings;
+       DIFFSTATUS status;
+       BOOL diffSuccess;
+       int nResult = RESCAN_OK;
+
        if (!bForced)
        {
                if (!m_bEnableRescan)
@@ -253,281 +274,69 @@ int CMergeDoc::Rescan(BOOL bForced /* =FALSE */)
        m_ltBuf.SaveToFile(m_strTempLeftFile, TRUE, CRLF_STYLE_AUTOMATIC, FALSE);
        m_rtBuf.SaveToFile(m_strTempRightFile, TRUE, CRLF_STYLE_AUTOMATIC, FALSE);
 
-       // perform rescan
-       struct file_data inf[2];
-       char *free0=NULL,*free1=NULL;
-       CString sdir0, sdir1, sname0, sname1, sext0, sext1;
-       int val,failed=0, depth=0;
-       bool same_files=FALSE;
-       struct change *e, *p;
-       struct change *script=NULL;
-       int nResult = RESCAN_OK;
-
-       m_diffs.RemoveAll();
-       m_nDiffs=0;
-       m_nCurDiff=-1;
+       // Set up DiffWrapper
+       m_diffWrapper.SetCompareFiles(m_strTempLeftFile, m_strTempRightFile);
+       m_diffWrapper.SetDiffList(&m_diffs);
+       m_diffWrapper.SetUseDiffList(TRUE);             // Add diffs to list
        
-       SplitFilename(m_strTempLeftFile, &sdir0, &sname0, 0);
-       SplitFilename(m_strTempRightFile, &sdir1, &sname1, 0);
-       ZeroMemory(&inf[0], sizeof(inf[0]));
-       ZeroMemory(&inf[1], sizeof(inf[1]));
-       
-       /* Both exist and neither is a directory.  */
-       int o_binary = always_text_flag ? 0:O_BINARY;
-       
-       /* Open the files and record their descriptors.  */
-       if (sdir0.IsEmpty())
-               inf[0].name = sname0;
-       else
-               inf[0].name = free0 = dir_file_pathname (sdir0, sname0);
-       inf[0].desc = -2;
-       if (sdir1.IsEmpty())
-               inf[1].name = sname1;
-       else
-               inf[1].name = free1 = dir_file_pathname (sdir1, sname1);
-       inf[1].desc = -2;
-       if (inf[0].desc == -2)
-       {
-               if ((inf[0].desc = open (inf[0].name, O_RDONLY|o_binary, 0)) < 0)
-               {
-                       perror_with_name (inf[0].name);
-                       failed = 1;
-               }
-               if (inf[1].desc == -2)
-               {
-                       if (same_files)
-                               inf[1].desc = inf[0].desc;
-                       else if ((inf[1].desc = open (inf[1].name, O_RDONLY|o_binary, 0)) < 0)
-                       {
-                               perror_with_name (inf[1].name);
-                               failed = 1;
-                       }
-                       
-                       /* Compare the files, if no error was found.  */
-                       int diff_flag=0;
-
-                       script = diff_2_files (inf, depth, &diff_flag);
-
-                       // throw the diff into a temp file
-                       char lpBuffer[MAX_PATH];       // path buffer
-                       GetTempPath(MAX_PATH,lpBuffer);         // get path to Temp folder
-                       CString path = CString(lpBuffer) + _T("Diff.txt");
-
-                       outfile = fopen(path, "w+");
-                       if (outfile != NULL)
-                       {
-                               print_normal_script(script);
-                               fclose(outfile);
-                               outfile=NULL;
-                       }
-                       
-                       struct change *next = script;
-                       int trans_a0, trans_b0, trans_a1, trans_b1;
-                       int first0, last0, first1, last1, deletes, inserts, op;
-                       struct change *thisob, *end;
-                       
-                       while (next)
-                       {
-                               /* Find a set of changes that belong together.  */
-                               thisob = next;
-                               end = find_change(next);
-                               
-                               /* Disconnect them from the rest of the changes,
-                               making them a hunk, and remember the rest for next iteration.  */
-                               next = end->link;
-                               end->link = 0;
-#ifdef DEBUG
-                               debug_script (thisob);
-#endif
-                               
-                               /* Print thisob hunk.  */
-                               //(*printfun) (thisob);
-                               {                                       
-                                       /* Determine range of line numbers involved in each file.  */
-                                       analyze_hunk (thisob, &first0, &last0, &first1, &last1, &deletes, &inserts);
-                                       if (!(!deletes && !inserts))
-                                       {
-                                               if (deletes && inserts)
-                                                       op = OP_DIFF;
-                                               else if (deletes)
-                                                       op = OP_LEFTONLY;
-                                               else
-                                                       op = OP_RIGHTONLY;
-                                               
-                                               /* Print the lines that the first file has.  */
-                                               translate_range (&inf[0], first0, last0, &trans_a0, &trans_b0);
-                                               translate_range (&inf[1], first1, last1, &trans_a1, &trans_b1);
-                                               AddDiffRange(trans_a0-1, trans_b0-1, trans_a1-1, trans_b1-1, (BYTE)op);
-                                               TRACE("left=%d,%d   right=%d,%d   op=%d\n",trans_a0-1, trans_b0-1, trans_a1-1, trans_b1-1, op);
-                                       }
-                               }
-                               
-                               /* Reconnect the script so it will all be freed properly.  */
-                               end->link = next;
-                       }
-                       
-                       // cleanup the script
-                       for (e = script; e; e = p)
-                       {
-                               p = e->link;
-                               free (e);
-                       }
-
-                       // If comparing whitespaces and
-                       // other file has EOL before EOF and other not...
-                       if (inf[0].missing_newline != inf[1].missing_newline &&
-                               !mf->m_nIgnoreWhitespace)
-                       {
-                               // ..lasf DIFFRANGE of file which has EOL must be
-                               // fixed to contain last line too
-                               FixLastDiffRange(inf[1].missing_newline);
-                       }
-                       
-                       cleanup_file_buffers(inf);
-                       
-                       /* Close the file descriptors.  */
-                       if (inf[0].desc >= 0 && close (inf[0].desc) != 0)
-                       {
-                               perror_with_name (inf[0].name);
-                               val = 2;
-                       }
-                       if (inf[1].desc >= 0 && inf[0].desc != inf[1].desc
-                               && close (inf[1].desc) != 0)
-                       {
-                               perror_with_name (inf[1].name);
-                               val = 2;
-                       }
-                       
-                       // Binary files or errors?
-                       if (diff_flag > 0)
-                               nResult = RESCAN_BINARIES;
-                       else if (failed)
-                               nResult = RESCAN_FILE_ERR;
-                       else
-                       {
-                               // Identical files are also updated
-                               if (m_nDiffs == 0)
-                                       nResult = RESCAN_IDENTICAL;
-
-                               // display the files
-                               PrimeTextBuffers();
-                               m_pLeftView->PrimeListWithFile();
-                               m_pRightView->PrimeListWithFile();
-
-                               // PrimeListWithFile will call resetview which resets tabs
-//                             mf->m_pLeft->SetTabSize(mf->m_nTabSize);
-//                             mf->m_pRight->SetTabSize(mf->m_nTabSize);
-
-                               /*TODO: int lcnt = m_ltBuf.GetLineCount();
-                               int rcnt = m_rtBuf.GetLineCount();
-                               if (lcnt < rcnt)
-                               {
-                                       m_diffs[m_nDiffs-1].dbegin0 = lcnt;
-                                       m_diffs[m_nDiffs-1].dend0 = rcnt;
-                                       m_diffs[m_nDiffs-1].blank0 = lcnt;
-                               }
-                               else if (rcnt < lcnt)
-                               {
-                                       m_diffs[m_nDiffs-1].dbegin1 = rcnt;
-                                       m_diffs[m_nDiffs-1].dend1 = lcnt;
-                                       m_diffs[m_nDiffs-1].blank1 = rcnt;
-                               }
+       // Global diff-options
+       diffSettings.outputStyle = output_style;
+       diffSettings.context = context;
+       diffSettings.alwaysText = always_text_flag;
+       diffSettings.horizLines = horizon_lines;
+       diffSettings.ignoreSpaceChange = ignore_space_change_flag;
+       diffSettings.ignoreAllSpace = ignore_all_space_flag;
+       diffSettings.ignoreBlankLines = ignore_blank_lines_flag;
+       diffSettings.ignoreCase = ignore_case_flag;
+       diffSettings.heuristic = heuristic;
+       diffSettings.recursive = 0;             // File scan is always non-recursive!
+       m_diffWrapper.SetOptions(&diffSettings);
+
+       // Clear diff list
+       m_diffs.RemoveAll();
+       m_nDiffs = 0;
+       m_nCurDiff = -1;
 
-                               while (lcnt < rcnt)
-                               {
-                                       mf->m_pLeft->AddItem(lcnt, 0, "");
-                                       mf->m_pLeft->m_pList->SetItemData(lcnt, 1);
-                                       lcnt++;
-                               }
-                               while (rcnt < lcnt)
-                               {
-                                       mf->m_pRight->AddItem(rcnt, 0, "");
-                                       mf->m_pRight->m_pList->SetItemData(rcnt, 1);
-                                       rcnt++;
-                               }*/
-                       }
-               }
-       }
-       
-       if (free0)
-               free (free0);
-       if (free1)
-               free (free1);
+       // Run diff
+       diffSuccess = m_diffWrapper.RunFileDiff();
 
-       return nResult;
-}
+       // Read diff-status
+       m_diffWrapper.GetDiffStatus(&status);
+       m_nDiffs = m_diffs.GetSize();
 
-void CMergeDoc::AddDiffRange(UINT begin0, UINT end0, UINT begin1, UINT end1, BYTE op)
-{
-       TRY {
-               DIFFRANGE dr = {0};
-               dr.begin0 = begin0;
-               dr.end0 = end0;
-               dr.begin1 = begin1;
-               dr.end1 = end1;
-               dr.op = op;
-               dr.blank0 = dr.blank1 = -1;
-               m_diffs.SetAtGrow(m_nDiffs, dr);
-               m_nDiffs++;
-       }
-       CATCH_ALL(e)
+       // If comparing whitespaces and
+       // other file has EOL before EOF and other not...
+       if (status.bLeftMissingNL != status.bRightMissingNL &&
+               !mf->m_nIgnoreWhitespace)
        {
-               TCHAR msg[1024] = {0};
-               e->GetErrorMessage(msg, 1024);
-               AfxMessageBox(msg, MB_ICONSTOP);
+               // ..lasf DIFFRANGE of file which has EOL must be
+               // fixed to contain last line too
+               m_diffWrapper.FixLastDiffRange(m_ltBuf.GetLineCount(), m_rtBuf.GetLineCount(),
+                               status.bRightMissingNL);
        }
-       END_CATCH_ALL;
-}
 
-// Expand last DIFFRANGE of file by one line to contain last line
-// after EOL
-void CMergeDoc::FixLastDiffRange(BOOL left)
-{
-       DIFFRANGE dr = {0};
-       int count = m_diffs.GetSize();
-       if (count > 0)
-       {
-               dr = m_diffs.GetAt(count - 1);
-
-               if (left)
-               {
-                       if (dr.op == OP_RIGHTONLY)
-                               dr.op = OP_DIFF;
-                       dr.end0++;
-               }
-               else
-               {
-                       if (dr.op == OP_LEFTONLY)
-                               dr.op = OP_DIFF;
-                       dr.end1++;
-               }
-
-               m_diffs.SetAt(count - 1, dr); 
-       }
-       else 
+       // Determine errors and binary file compares
+       if (!diffSuccess)
+               nResult = RESCAN_FILE_ERR;
+       else if (status.bBinaries)
+               nResult = RESCAN_BINARIES;
+       else
        {
-               // we have to create the DIFF
-               dr.end0   = m_ltBuf.GetLineCount() - 1;
-               dr.end1   = m_rtBuf.GetLineCount() - 1;
-               if (left)
-               {
-                       dr.begin0 = dr.end0;
-                       dr.begin1 = dr.end1 + 1;
-                       dr.op = OP_LEFTONLY;
-               }
-               else
-               {
-                       dr.begin0 = dr.end0 + 1;
-                       dr.begin1 = dr.end1;
-                       dr.op = OP_RIGHTONLY;
-               }
-               ASSERT(dr.begin0 == dr.begin1);
+               // Identical files are also updated
+               if (m_nDiffs == 0)
+                       nResult = RESCAN_IDENTICAL;
 
-               AddDiffRange (dr.begin0, dr.end0, dr.begin1, dr.end1, dr.op); 
+               // Analyse diff-list (updating real line-numbers)
+               PrimeTextBuffers();
+               
+               // Display files
+               m_pLeftView->PrimeListWithFile();
+               m_pRightView->PrimeListWithFile();
        }
+       return nResult;
 }
 
-
+/// Prints (error) message by rescan resultcode
 void CMergeDoc::ShowRescanError(int nRescanResult)
 {
        CString s;
@@ -663,13 +472,13 @@ private:
        BOOL m_bSuppress;
 };
 
-// Copy all diffs from one side to the other (as specified by caller)
+/// Copy all diffs from one side to the other (as specified by caller)
 void CMergeDoc::CopyAllList(bool bSrcLeft)
 {
        RescanSuppress suppressRescan(*this);
        
-       // Note we don't care about m_nDiff count to become zero,
-       // because we don't rescan() it does not change
+       // Note we don't care about m_nDiffs count to become zero,
+       // because we don't rescan() so it does not change
 
        // copy from bottom up is more efficient
        for(int i = m_nDiffs-1; i>=0; --i)
@@ -681,6 +490,7 @@ void CMergeDoc::CopyAllList(bool bSrcLeft)
        FlushAndRescan();
 }
 
+/// Copies selected (=current) diff to another side
 void CMergeDoc::ListCopy(bool bSrcLeft)
 {
        // suppress Rescan during this method
@@ -965,7 +775,7 @@ CString CMergeDoc::Tabify(LPCTSTR szText)
        return strResult;
 }*/
 
-// Checks if line is inside diff
+/// Checks if line is inside diff
 BOOL CMergeDoc::LineInDiff(UINT nLine, UINT nDiff)
 {
        ASSERT(nDiff >= 0 && nDiff <= m_nDiffs);
@@ -976,7 +786,7 @@ BOOL CMergeDoc::LineInDiff(UINT nLine, UINT nDiff)
                return FALSE;
 }
 
-// Returns order num of diff for given line
+/// Returns order num of diff for given line
 int CMergeDoc::LineToDiff(UINT nLine)
 {
        for (UINT i = 0; i < m_nDiffs; i++)
@@ -1083,7 +893,7 @@ void CMergeDoc::CDiffTextBuffer::OnNotifyLineHasBeenEdited(int nLine)
 
 
 
-// Try to determine current CRLF mode based on first line
+/// Try to determine current CRLF mode based on first line
 int CMergeDoc::CDiffTextBuffer::DetermineCRLFStyle(LPVOID lpBuf, DWORD dwLength)
 {
        WORD wLoopSize = 0xffff;
@@ -1118,7 +928,7 @@ int CMergeDoc::CDiffTextBuffer::DetermineCRLFStyle(LPVOID lpBuf, DWORD dwLength)
        return nCrlfStyle;
 }
 
-// Reads one line from filebuffer and inserts to textbuffer
+/// Reads one line from filebuffer and inserts to textbuffer
 void CMergeDoc::CDiffTextBuffer::ReadLineFromBuffer(TCHAR *lpLineBegin, DWORD dwLineLen /* =0 */)
 {
        if (m_nSourceEncoding >= 0)
@@ -1126,11 +936,13 @@ void CMergeDoc::CDiffTextBuffer::ReadLineFromBuffer(TCHAR *lpLineBegin, DWORD dw
        InsertLine(lpLineBegin, dwLineLen);
 }
 
+/// Sets path for temporary files
 void CMergeDoc::CDiffTextBuffer::SetTempPath(CString path)
 {
        m_strTempPath = path;
 }
 
+/// Loads file from disk to buffer
 int CMergeDoc::CDiffTextBuffer::LoadFromFile(LPCTSTR pszFileName,
                int nCrlfStyle /*= CRLF_STYLE_AUTOMATIC*/)
 {
@@ -1231,6 +1043,7 @@ int CMergeDoc::CDiffTextBuffer::LoadFromFile(LPCTSTR pszFileName,
        return nRetVal;
 }
 
+/// Saves file from buffer to disk
 // NOTE: bTempFile is FALSE if we are saving user files and
 // TRUE if we are saving workin-temp-files for diff-engine
 BOOL CMergeDoc::CDiffTextBuffer::SaveToFile (LPCTSTR pszFileName,
@@ -1332,7 +1145,7 @@ BOOL CMergeDoc::CDiffTextBuffer::SaveToFile (LPCTSTR pszFileName,
        return bSaveSuccess;
 }
 
-// Replace text of line (no change to eol)
+/// Replace text of line (no change to eol)
 void CMergeDoc::CDiffTextBuffer::ReplaceLine(CCrystalTextView * pSource, int nLine, const CString &strText)
 {
        if (GetLineLength(nLine)>0)
@@ -1341,7 +1154,8 @@ void CMergeDoc::CDiffTextBuffer::ReplaceLine(CCrystalTextView * pSource, int nLi
        if (! strText.IsEmpty())
                InsertText(pSource, nLine, 0, strText, endl,endc);
 }
-// return pointer to the eol chars of this string, or pointer to empty string if none
+
+/// Return pointer to the eol chars of this string, or pointer to empty string if none
 LPCTSTR getEol(const CString &str)
 {
        if (str.GetLength()>1 && str[str.GetLength()-2]=='\r' && str[str.GetLength()-1]=='\n')
@@ -1351,7 +1165,7 @@ LPCTSTR getEol(const CString &str)
        return _T("");
 }
 
-// Replace line (removing any eol, and only including one if in strText)
+/// Replace line (removing any eol, and only including one if in strText)
 void CMergeDoc::CDiffTextBuffer::ReplaceFullLine(CCrystalTextView * pSource, int nLine, const CString &strText)
 {
        if (_tcscmp(GetLineEol(nLine), getEol(strText)) == 0)
@@ -1375,6 +1189,7 @@ void CMergeDoc::CDiffTextBuffer::ReplaceFullLine(CCrystalTextView * pSource, int
                InsertText(pSource, nLine, 0, strText, endl,endc);
 }
 
+/// Determine path for temporary files and init those files
 BOOL CMergeDoc::InitTempFiles(const CString& srcPathL, const CString& strPathR)
 {
        TCHAR strTempPath[MAX_PATH] = {0};
@@ -1411,6 +1226,7 @@ BOOL CMergeDoc::InitTempFiles(const CString& srcPathL, const CString& strPathR)
        return TRUE;
 }
 
+/// Remove temporary files
 void CMergeDoc::CleanupTempFiles()
 {
        if (!m_strTempLeftFile.IsEmpty())
@@ -1532,8 +1348,6 @@ bool CMergeDoc::CDiffTextBuffer::curUndoGroup()
        return (m_aUndoBuf.GetSize()!=0 && m_aUndoBuf[0].m_dwFlags&UNDO_BEGINGROUP);
 }
 
-
-
 void CMergeDoc::PrimeTextBuffers()
 {
        CStdioFile file;
index 3413796..7be93cb 100644 (file)
 //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 //
 /////////////////////////////////////////////////////////////////////////////
-// MergeDoc.h : interface of the CMergeDoc class
-//
-/////////////////////////////////////////////////////////////////////////////
+/** 
+ * @file  MergeDoc.h
+ *
+ * @brief Declaration of CMergeDoc class
+ */
+// RCS ID line follows -- this is updated by CVS
+// $Id$
 
 #if !defined(AFX_MERGEDOC_H__BBCD4F90_34E4_11D1_BAA6_00A024706EDC__INCLUDED_)
 #define AFX_MERGEDOC_H__BBCD4F90_34E4_11D1_BAA6_00A024706EDC__INCLUDED_
 #include "GhostTextBuffer.h"
 #include <vector>
 #include "afxtempl.h"
+#include "DiffWrapper.h"
 
-#define OP_NONE                        0
-#define OP_LEFTONLY            1
-#define OP_DIFF                        2
-#define OP_RIGHTONLY   3
-
-typedef struct tagDIFFRANGE {
-       UINT begin0,end0,begin1,end1;
-       UINT dbegin0,dend0,dbegin1,dend1;
-       int blank0,blank1;
-       BYTE op;
-}DIFFRANGE;
-
+/**
+ * @brief Return statuses of file rescan
+ */
 enum
 {
        RESCAN_OK = 0,
@@ -176,8 +172,6 @@ public:
 
        void RescanIfNeeded(float timeOutInSecond);
        int Rescan(BOOL bForced = FALSE);
-       void AddDiffRange(UINT begin0, UINT end0, UINT begin1, UINT end1, BYTE op);
-       void FixLastDiffRange(BOOL left);
        void ShowRescanError(int nRescanResult);
        void AddUndoAction(UINT nBegin, UINT nEnd, UINT nDiff, int nBlanks, BOOL bInsert, CMergeEditView *pList);
        BOOL Undo();
@@ -241,6 +235,7 @@ protected:
        CDirDoc * m_pDirDoc;
        BOOL m_bEnableRescan;
        COleDateTime m_LastRescan;
+       CDiffWrapper m_diffWrapper;
 
 // friend access
        friend class RescanSuppress;
index 60d272a..978f777 100644 (file)
@@ -1,3 +1,8 @@
+2003-08-22 Kimmo
+ PATCH: [ 787495 ] Create diffutils class (CDiffWrapper)
+  WinMerge: Merge.dsp MergeDoc.h MergeDoc.cpp
+   Added: DiffWrapper.h DiffWrapper.cpp
+
 2003-08-20 Perry
  PATCH: [ 791924 ] Fix sorting when columns are reordered
   WinMerge: DirView.cpp