From: Kimmo Varis Date: Fri, 22 Aug 2003 18:30:34 +0000 (+0000) Subject: PATCH: [ 787495 ] Create diffutils class (CDiffWrapper) X-Git-Tag: 2.16.5~7844 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=ae032ec83afc1f591796ad7dca26401e155d7884;p=winmerge-jp%2Fwinmerge-jp.git PATCH: [ 787495 ] Create diffutils class (CDiffWrapper) --- diff --git a/Src/DiffWrapper.cpp b/Src/DiffWrapper.cpp new file mode 100644 index 000000000..96bd3234d --- /dev/null +++ b/Src/DiffWrapper.cpp @@ -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 *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 index 000000000..31954a282 --- /dev/null +++ b/Src/DiffWrapper.h @@ -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 *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 *m_diffs; +}; + +#endif // _DIFFWRAPPER_H \ No newline at end of file diff --git a/Src/Merge.dsp b/Src/Merge.dsp index e5596cf94..e9933984a 100644 --- a/Src/Merge.dsp +++ b/Src/Merge.dsp @@ -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 diff --git a/Src/MergeDoc.cpp b/Src/MergeDoc.cpp index bdf4a1e88..bf72f9bd6 100644 --- a/Src/MergeDoc.cpp +++ b/Src/MergeDoc.cpp @@ -18,14 +18,18 @@ // 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; diff --git a/Src/MergeDoc.h b/Src/MergeDoc.h index 3413796f5..7be93cb95 100644 --- a/Src/MergeDoc.h +++ b/Src/MergeDoc.h @@ -17,9 +17,13 @@ // 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_ @@ -31,19 +35,11 @@ #include "GhostTextBuffer.h" #include #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; diff --git a/Src/readme.txt b/Src/readme.txt index 60d272a47..978f777db 100644 --- a/Src/readme.txt +++ b/Src/readme.txt @@ -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