X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=Src%2FDiffWrapper.cpp;h=300bdbfb8392d2f597d8b3dbe521dcb522937437;hb=5a478c4115f3ffeb35fb51df893912409c793bb0;hp=739f77e08f9662506a61fdd1daae9594e391ec75;hpb=c31e84698268c407b2bebde19d9b2c25ff24c143;p=winmerge-jp%2Fwinmerge-jp.git diff --git a/Src/DiffWrapper.cpp b/Src/DiffWrapper.cpp index 739f77e08..300bdbfb8 100644 --- a/Src/DiffWrapper.cpp +++ b/Src/DiffWrapper.cpp @@ -1,19 +1,4 @@ -///////////////////////////////////////////////////////////////////////////// -// 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. -///////////////////////////////////////////////////////////////////////////// +// SPDX-License-Identifier: GPL-2.0-or-later /** * @file DiffWrapper.cpp * @@ -22,12 +7,15 @@ * @date Created: 2003-08-22 */ +#include "pch.h" #define NOMINMAX #include "DiffWrapper.h" #include #include #include #include +#include +#include #include #include #include @@ -44,19 +32,22 @@ #include "FilterList.h" #include "diff.h" #include "Diff3.h" +#include "xdiff_gnudiff_compat.h" #include "FileTransform.h" #include "paths.h" #include "CompareOptions.h" #include "FileTextStats.h" #include "FolderCmp.h" -#include "FilterCommentsManager.h" #include "Environment.h" #include "PatchHTML.h" #include "UnicodeString.h" #include "unicoder.h" #include "TFile.h" #include "Exceptions.h" +#include "parsers/crystallineparser.h" +#include "SyntaxColors.h" #include "MergeApp.h" +#include "SubstitutionList.h" using Poco::Debugger; using Poco::format; @@ -65,31 +56,28 @@ using Poco::Exception; extern int recursive; -static void FreeDiffUtilsScript(struct change * & script); -static void FreeDiffUtilsScript3(struct change * & script10, struct change * & script12); static void CopyTextStats(const file_data * inf, FileTextStats * myTextStats); static void CopyDiffutilTextStats(file_data *inf, DiffFileData * diffData); /** * @brief Default constructor. - * Initializes members and creates new FilterCommentsManager. + * Initializes members. */ CDiffWrapper::CDiffWrapper() -: m_pFilterCommentsManager(nullptr) +: m_pFilterCommentsDef(nullptr) , m_bCreatePatchFile(false) , m_bUseDiffList(false) , m_bAddCmdLine(true) , m_bAppendFiles(false) , m_nDiffs(0) -, m_codepage(GetACP()) , m_infoPrediffer(nullptr) , m_pDiffList(nullptr) , m_bPathsAreTemp(false) , m_pFilterList(nullptr) +, m_pSubstitutionList{nullptr} , m_bPluginsEnabled(false) +, m_status() { - memset(&m_status, 0, sizeof(DIFFSTATUS)); - // character that ends a line. Currently this is always `\n' line_end_char = '\n'; } @@ -102,15 +90,6 @@ CDiffWrapper::~CDiffWrapper() } /** - * @brief Set plugins enabled/disabled. - * @param [in] enable if true plugins are enabled. - */ -void CDiffWrapper::EnablePlugins(bool enable) -{ - m_bPluginsEnabled = enable; -} - -/** * @brief Enables/disables patch-file creation and sets filename. * This function enables or disables patch file creation. When * @p filename is empty, patch files are disabled. @@ -127,23 +106,23 @@ void CDiffWrapper::SetCreatePatchFile(const String &filename) { m_bCreatePatchFile = true; m_sPatchFile = filename; - string_replace(m_sPatchFile, _T("/"), _T("\\")); + strutils::replace(m_sPatchFile, _T("/"), _T("\\")); } } /** * @brief Enables/disabled DiffList creation ands sets DiffList. * This function enables or disables DiffList creation. When - * @p diffList is NULL difflist is not created. When valid DiffList - * pointer is given, compare results are stored into it. + * @p diffList is `nullptr`, a difflist was not created. When valid + * DiffList pointer is given, compare results are stored into it. * @param [in] diffList Pointer to DiffList getting compare results. */ void CDiffWrapper::SetCreateDiffList(DiffList *diffList) { - if (diffList == NULL) + if (diffList == nullptr) { m_bUseDiffList = false; - m_pDiffList = NULL; + m_pDiffList = nullptr; } else { @@ -160,7 +139,7 @@ void CDiffWrapper::SetCreateDiffList(DiffList *diffList) */ void CDiffWrapper::GetOptions(DIFFOPTIONS *options) const { - assert(options); + assert(options != nullptr); DIFFOPTIONS tmpOptions = {0}; m_options.GetAsDiffOptions(tmpOptions); *options = tmpOptions; @@ -174,30 +153,18 @@ void CDiffWrapper::GetOptions(DIFFOPTIONS *options) const */ void CDiffWrapper::SetOptions(const DIFFOPTIONS *options) { - assert(options); + assert(options != nullptr); m_options.SetFromDiffOptions(*options); } -/** - * @brief Set text tested to find the prediffer automatically. - * Most probably a concatenated string of both filenames. - */ -void CDiffWrapper::SetTextForAutomaticPrediff(const String &text) -{ - m_sToFindPrediffer = text; -} -void CDiffWrapper::SetPrediffer(const PrediffingInfo * prediffer /*=NULL*/) +void CDiffWrapper::SetPrediffer(const PrediffingInfo * prediffer /*= nullptr*/) { // all flags are set correctly during the construction m_infoPrediffer.reset(new PrediffingInfo); - if (prediffer) + if (prediffer != nullptr) *m_infoPrediffer = *prediffer; } -void CDiffWrapper::GetPrediffer(PrediffingInfo * prediffer) const -{ - *prediffer = *m_infoPrediffer; -} /** * @brief Set options used for patch-file creation. @@ -205,7 +172,7 @@ void CDiffWrapper::GetPrediffer(PrediffingInfo * prediffer) const */ void CDiffWrapper::SetPatchOptions(const PATCHOPTIONS *options) { - assert(options); + assert(options != nullptr); m_options.m_contextLines = options->nContext; switch (options->outputStyle) @@ -238,7 +205,7 @@ void CDiffWrapper::SetDetectMovedBlocks(bool bDetectMovedBlocks) { if (bDetectMovedBlocks) { - if (m_pMovedLines[0] == NULL) + if (m_pMovedLines[0] == nullptr) { m_pMovedLines[0].reset(new MovedLines); m_pMovedLines[1].reset(new MovedLines); @@ -253,95 +220,74 @@ void CDiffWrapper::SetDetectMovedBlocks(bool bDetectMovedBlocks) } } -/** - * @brief Test for trivial only characters in string - * @param [in] Start - Start position in string - * @param [in] End - One character pass the end position of the string - * @param [in] filtercommentsset - For future use to determine trivial bytes - * @return Returns true if all characters are trivial - */ -bool CDiffWrapper::IsTrivialBytes(const char* Start, const char* End, - const FilterCommentsSet& filtercommentsset) const +static String convertToTString(const char* start, const char* end) { - std::string testdata(Start, End); - //@TODO: Need to replace the following trivial string with a user specified string - size_t pos = testdata.find_first_not_of(" \t\r\n"); - return (pos == std::string::npos); -} - -/** - * @brief Test for a line of trivial data - * @param [in] Line - String to test for - * @param [in] StartOfComment - - * @param [in] EndOfComment - - * @param [in] InLineComment - - * @param [in] filtercommentsset - Comment marker set used to indicate comment blocks. - * @return Returns true if entire line is trivial - */ -bool CDiffWrapper::IsTrivialLine(const std::string &Line, - const char * StartOfComment, - const char * EndOfComment, - const char * InLineComment, - const FilterCommentsSet& filtercommentsset) const -{ - //Do easy test first - if ((!StartOfComment || !EndOfComment) && !InLineComment) - return false;//In no Start and End pair, and no single in-line set, then it's not trivial - - if (StartOfComment == Line.c_str() && - ((EndOfComment + filtercommentsset.EndMarker.size()) - StartOfComment) == Line.size()) - {//If entire line is blocked by End and Start markers, then entire line is trivial - return true; + if (!ucr::CheckForInvalidUtf8(start, end - start)) + { + return ucr::toTString(std::string(start, end)); } - - if (InLineComment && InLineComment < StartOfComment) + else { - if (InLineComment == Line.c_str()) - return true;//If line starts with InLineComment marker, then entire line is trivial - - //Other wise, check if data before InLineComment marker is trivial - return IsTrivialBytes(Line.c_str(), InLineComment, filtercommentsset); + bool lossy = false; + String text; + ucr::maketstring(text, start, end - start, -1, &lossy); + return text; } +} - //Done with easy test, so now do more complex test - if (StartOfComment && - EndOfComment && - StartOfComment < EndOfComment && - IsTrivialBytes(Line.c_str(), StartOfComment, filtercommentsset) && - IsTrivialBytes(EndOfComment + filtercommentsset.EndMarker.size(), - Line.c_str()+Line.size(), filtercommentsset)) +static unsigned GetLastLineCookie(unsigned dwCookie, int startLine, int endLine, const char **linbuf, CrystalLineParser::TextDefinition* enuType) +{ + if (!enuType) + return dwCookie; + for (int i = startLine; i <= endLine; ++i) { - return true; + String text = convertToTString(linbuf[i], linbuf[i + 1]); + int nActualItems = 0; + std::vector blocks(text.length()); + dwCookie = enuType->ParseLineX(dwCookie, text.c_str(), static_cast(text.length()), blocks.data(), nActualItems); } - - return false; + return dwCookie; } -/** - * @brief Find comment marker in string, excluding portions enclosed in quotation marks or apostrophes - * @param [in] target - string to search - * @param [in] marker - marker to search for - * @return Returns position of marker, or NULL if none is present - */ -static const char *FindCommentMarker(const char *target, const char *marker) +static unsigned GetCommentsFilteredText(unsigned dwCookie, int startLine, int endLine, const char **linbuf, std::string& filtered, CrystalLineParser::TextDefinition* enuType) { - char prev = '\0'; - char quote = '\0'; - size_t marker_len = strlen(marker); - while (char c = *target) - { - if (quote == '\0' && strncmp(target, marker, marker_len) == 0) - return target; - if ((prev != '\\') && - (c == '"' || c == '\'') && - (quote == '\0' || quote == c)) + String filteredT; + for (int i = startLine; i <= endLine; ++i) + { + String text = convertToTString(linbuf[i], linbuf[i + 1]); + unsigned textlen = static_cast(text.size()); + if (!enuType) { - quote ^= c; + filteredT += text; + } + else + { + int nActualItems = 0; + std::vector blocks(textlen); + dwCookie = enuType->ParseLineX(dwCookie, text.c_str(), textlen, blocks.data(), nActualItems); + + if (nActualItems == 0) + { + filteredT += text; + } + else + { + for (int j = 0; j < nActualItems; ++j) + { + CrystalLineParser::TEXTBLOCK& block = blocks[j]; + if (block.m_nColorIndex != COLORINDEX_COMMENT) + { + unsigned blocklen = (j < nActualItems - 1) ? (blocks[j + 1].m_nCharPos - block.m_nCharPos) : textlen - block.m_nCharPos; + filteredT.append(text.c_str() + block.m_nCharPos, blocklen); + } + } + } } - prev = c; - ++target; } - return NULL; + + filtered = ucr::toUTF8(filteredT); + + return dwCookie; } /** @@ -356,138 +302,13 @@ static void ReplaceSpaces(std::string & str, const char *rep) while ((pos = str.find_first_of(" \t", pos)) != std::string::npos) { std::string::size_type posend = str.find_first_not_of(" \t", pos); - if (posend != std::string::npos) + if (posend != String::npos) str.replace(pos, posend - pos, rep); else str.replace(pos, 1, rep); pos += replen; } } - -/** - @brief Performs post-filtering, by setting comment blocks to trivial - @param [in] StartPos - First line number to read - @param [in] EndPos - The line number PASS the last line number to read - @param [in] QtyLinesInBlock - Number of lines in diff block. Not needed in backward direction. - @param [in] Direction - This should be 1 or -1, to indicate which direction to read (backward or forward) - @param [in,out] Op - This variable is set to trivial if block should be ignored. - @param [in] FileNo - Should be 0 or 1, to indicate left or right file. - @param [in] filtercommentsset - Comment marker set used to indicate comment blocks. - @return Always returns true in reverse direction. - In forward direction, returns false if none trivial data is found within QtyLinesInBlock -*/ -bool CDiffWrapper::PostFilter(int StartPos, int EndPos, int Direction, - int QtyLinesInBlock, OP_TYPE &Op, int FileNo, - FilterCommentsSet& filtercommentsset) const -{ - if (Op == OP_TRIVIAL) //If already set to trivial, then exit. - return true; - bool OpShouldBeTrivial = false; - int QtyTrivialLines = 0; - for(int i = StartPos + ((Direction == -1)?-1:0); i != EndPos;i += Direction) - { - if ((i - StartPos) == QtyLinesInBlock && - QtyLinesInBlock == QtyTrivialLines) - { - OpShouldBeTrivial = true; - break; - } - size_t len = files[FileNo].linbuf[i + 1] - files[FileNo].linbuf[i]; - const char *LineStr = files[FileNo].linbuf[i]; - std::string LineData(LineStr, linelen(LineStr, len)); - - const char * StartOfComment = FindCommentMarker(LineData.c_str(), filtercommentsset.StartMarker.c_str()); - const char * EndOfComment = FindCommentMarker(LineData.c_str(), filtercommentsset.EndMarker.c_str()); - const char * InLineComment = FindCommentMarker(LineData.c_str(), filtercommentsset.InlineMarker.c_str()); - //The following logic determines if the entire block is a comment block, and only marks it as trivial - //if all the changes are within a comment block. - if (Direction == -1) - { - if (!StartOfComment && EndOfComment) - break; - - if (StartOfComment && (!EndOfComment || EndOfComment < StartOfComment) && (!InLineComment || InLineComment > StartOfComment)) - { - OpShouldBeTrivial = true; - break; - } - } - else if (Direction == 1) - { - if (IsTrivialBytes(LineData.c_str(), LineData.c_str()+LineData.size(), filtercommentsset) || - IsTrivialLine(LineData, StartOfComment, EndOfComment, InLineComment, filtercommentsset)) - { - ++QtyTrivialLines; - } - - if (!EndOfComment && StartOfComment) - { - if (i == (StartPos + QtyTrivialLines) ) - { - if (StartOfComment == LineData.c_str()) - {//If this is at the beginning of the first line, then lets continue - continue; - } - if (IsTrivialBytes(LineData.c_str(), StartOfComment, filtercommentsset)) - {//If only trivial bytes before comment marker, then continue - continue; - } - break; - } - //If this is not the first line, then assume - //previous lines are non-trivial, and return true. - return false; - } - - if (EndOfComment && - (!StartOfComment || StartOfComment > EndOfComment) && - (!InLineComment || InLineComment > EndOfComment) ) - { - if (!IsTrivialBytes(EndOfComment+filtercommentsset.EndMarker.size(), LineData.c_str()+LineData.size(), filtercommentsset)) - { - return false; - } - - if ((i - StartPos) >= (QtyLinesInBlock-1)) - { - OpShouldBeTrivial = true; - break; - } - - //Lets check if the remaining lines only contain trivial data - bool AllRemainingLinesContainTrivialData = true; - int TrivLinePos = i+1; - for(; TrivLinePos != (StartPos + QtyLinesInBlock);++TrivLinePos) - { - size_t len = files[FileNo].linbuf[TrivLinePos + 1] - files[FileNo].linbuf[TrivLinePos]; - const char *LineStrTrvCk = files[FileNo].linbuf[TrivLinePos]; - std::string LineDataTrvCk(LineStrTrvCk, linelen(LineStrTrvCk, len)); - if (LineDataTrvCk.size() && - !IsTrivialBytes(LineDataTrvCk.c_str(), LineDataTrvCk.c_str() + LineDataTrvCk.size(), filtercommentsset)) - { - AllRemainingLinesContainTrivialData = false; - break; - } - } - if (AllRemainingLinesContainTrivialData) - { - OpShouldBeTrivial = true; - break; - } - if (TrivLinePos != (StartPos + QtyLinesInBlock) ) - { - return PostFilter(TrivLinePos, EndPos, Direction, QtyLinesInBlock - (TrivLinePos - StartPos), Op, FileNo, filtercommentsset); - } - } - } - } - if (OpShouldBeTrivial) - { - Op = OP_TRIVIAL; - } - return true; -} - /** @brief The main entry for post filtering. Performs post-filtering, by setting comment blocks to trivial @param [in] LineNumberLeft - First line number to read from left file @@ -495,147 +316,70 @@ bool CDiffWrapper::PostFilter(int StartPos, int EndPos, int Direction, @param [in] LineNumberRight - First line number to read from right file @param [in] QtyLinesRight - Number of lines in the block for right file @param [in,out] Op - This variable is set to trivial if block should be ignored. -@param [in] FileNameExt - The file name extension. Needs to be lower case string ("cpp", "java", "c") */ -void CDiffWrapper::PostFilter(int LineNumberLeft, int QtyLinesLeft, int LineNumberRight, - int QtyLinesRight, OP_TYPE &Op, const String& FileNameExt) const +void CDiffWrapper::PostFilter(PostFilterContext& ctxt, int LineNumberLeft, int QtyLinesLeft, int LineNumberRight, + int QtyLinesRight, OP_TYPE &Op, const file_data *file_data_ary) const { - if (Op == OP_TRIVIAL || !m_pFilterCommentsManager) + if (Op == OP_TRIVIAL) return; - - //First we need to get lowercase file name extension - FilterCommentsSet filtercommentsset = m_pFilterCommentsManager->GetSetForFileType(FileNameExt); - if (filtercommentsset.StartMarker.empty() && - filtercommentsset.EndMarker.empty() && - filtercommentsset.InlineMarker.empty()) + + std::string LineDataLeft, LineDataRight; + + if (m_options.m_filterCommentsLines) { - return; - } + ctxt.dwCookieLeft = GetLastLineCookie(ctxt.dwCookieLeft, + ctxt.nParsedLineEndLeft + 1, LineNumberLeft - 1, file_data_ary[0].linbuf + file_data_ary[0].linbuf_base, m_pFilterCommentsDef); + ctxt.dwCookieRight = GetLastLineCookie(ctxt.dwCookieRight, + ctxt.nParsedLineEndRight + 1, LineNumberRight - 1, file_data_ary[1].linbuf + file_data_ary[1].linbuf_base, m_pFilterCommentsDef); - OP_TYPE LeftOp = OP_NONE; - OP_TYPE RightOp = OP_NONE; + ctxt.nParsedLineEndLeft = LineNumberLeft + QtyLinesLeft - 1; + ctxt.nParsedLineEndRight = LineNumberRight + QtyLinesRight - 1;; - if (QtyLinesRight == 0) - { //Only check left side - if (PostFilter(LineNumberLeft, files[0].valid_lines, 1, QtyLinesLeft, LeftOp, 0, filtercommentsset)) - PostFilter(LineNumberLeft, -1, -1, QtyLinesLeft, LeftOp, 0, filtercommentsset); - } - else if (QtyLinesLeft == 0) - { //Only check right side - if (PostFilter(LineNumberRight, files[1].valid_lines, 1, QtyLinesRight, RightOp, 1, filtercommentsset)) - PostFilter(LineNumberRight, -1, -1, QtyLinesRight, RightOp, 1, filtercommentsset); + ctxt.dwCookieLeft = GetCommentsFilteredText(ctxt.dwCookieLeft, + LineNumberLeft, ctxt.nParsedLineEndLeft, file_data_ary[0].linbuf + file_data_ary[0].linbuf_base, LineDataLeft, m_pFilterCommentsDef); + ctxt.dwCookieRight = GetCommentsFilteredText(ctxt.dwCookieRight, + LineNumberRight, ctxt.nParsedLineEndRight, file_data_ary[1].linbuf + file_data_ary[1].linbuf_base, LineDataRight, m_pFilterCommentsDef); } else { - if (PostFilter(LineNumberLeft, files[0].valid_lines, 1, QtyLinesLeft, LeftOp, 0, filtercommentsset)) - PostFilter(LineNumberLeft, -1, -1, QtyLinesLeft, LeftOp, 0, filtercommentsset); - - if (PostFilter(LineNumberRight, files[1].valid_lines, 1, QtyLinesRight, RightOp, 1, filtercommentsset)) - PostFilter(LineNumberRight, -1, -1, QtyLinesRight, RightOp, 1, filtercommentsset); + LineDataLeft.assign(file_data_ary[0].linbuf[LineNumberLeft + file_data_ary[0].linbuf_base], + file_data_ary[0].linbuf[LineNumberLeft + QtyLinesLeft + file_data_ary[0].linbuf_base] + - file_data_ary[0].linbuf[LineNumberLeft + file_data_ary[0].linbuf_base]); + LineDataRight.assign(file_data_ary[1].linbuf[LineNumberRight + file_data_ary[1].linbuf_base], + file_data_ary[1].linbuf[LineNumberRight + QtyLinesRight + file_data_ary[1].linbuf_base] + - file_data_ary[1].linbuf[LineNumberRight + file_data_ary[1].linbuf_base]); } - std::list LeftLines, RightLines; - for (int i = 0; (i < QtyLinesLeft) || (i < QtyLinesRight); i++) + if (m_pSubstitutionList) { - //Lets test all lines if only a comment is different. - const char * LineStrLeft = ""; - const char * EndLineLeft = LineStrLeft; - const char * LineStrRight = ""; - const char * EndLineRight = LineStrRight; - if(i < QtyLinesLeft) - { - LineStrLeft = files[0].linbuf[LineNumberLeft + i]; - EndLineLeft = files[0].linbuf[LineNumberLeft + i + 1]; - } - if(i < QtyLinesRight) - { - LineStrRight = files[1].linbuf[LineNumberRight + i]; - EndLineRight = files[1].linbuf[LineNumberRight + i + 1]; - } - - if (EndLineLeft && EndLineRight) - { - std::string LineDataLeft(LineStrLeft, EndLineLeft); - std::string LineDataRight(LineStrRight, EndLineRight); - - if (!filtercommentsset.StartMarker.empty() && !filtercommentsset.EndMarker.empty()) - { - const char * CommentStrLeftStart; - const char * CommentStrLeftEnd; - const char * CommentStrRightStart; - const char * CommentStrRightEnd; - - bool bFirstLoop = true; - do { - //Lets remove block comments, and see if lines are equal - CommentStrLeftStart = FindCommentMarker(LineDataLeft.c_str(), filtercommentsset.StartMarker.c_str()); - CommentStrLeftEnd = FindCommentMarker(LineDataLeft.c_str(), filtercommentsset.EndMarker.c_str()); - CommentStrRightStart = FindCommentMarker(LineDataRight.c_str(), filtercommentsset.StartMarker.c_str()); - CommentStrRightEnd = FindCommentMarker(LineDataRight.c_str(), filtercommentsset.EndMarker.c_str()); - - if (CommentStrLeftStart != NULL && CommentStrLeftEnd != NULL && CommentStrLeftStart < CommentStrLeftEnd) - LineDataLeft.erase(CommentStrLeftStart - LineDataLeft.c_str(), CommentStrLeftEnd + filtercommentsset.EndMarker.size() - CommentStrLeftStart); - else if (CommentStrLeftEnd != NULL) - LineDataLeft.erase(0, CommentStrLeftEnd + filtercommentsset.EndMarker.size() - LineDataLeft.c_str()); - else if (CommentStrLeftStart != NULL) - LineDataLeft.erase(CommentStrLeftStart - LineDataLeft.c_str()); - else if(LeftOp == OP_TRIVIAL && bFirstLoop) - LineDataLeft.erase(0); //This line is all in block comments - - if (CommentStrRightStart != NULL && CommentStrRightEnd != NULL && CommentStrRightStart < CommentStrRightEnd) - LineDataRight.erase(CommentStrRightStart - LineDataRight.c_str(), CommentStrRightEnd + filtercommentsset.EndMarker.size() - CommentStrRightStart); - else if (CommentStrRightEnd != NULL) - LineDataRight.erase(0, CommentStrRightEnd + filtercommentsset.EndMarker.size() - LineDataRight.c_str()); - else if (CommentStrRightStart != NULL) - LineDataRight.erase(CommentStrRightStart - LineDataRight.c_str()); - else if(RightOp == OP_TRIVIAL && bFirstLoop) - LineDataRight.erase(0); //This line is all in block comments - - bFirstLoop = false; - - } while (CommentStrLeftStart != NULL || CommentStrLeftEnd != NULL - || CommentStrRightStart != NULL || CommentStrRightEnd != NULL); //Loops until all blockcomments are lost - } - - if (!filtercommentsset.InlineMarker.empty()) - { - //Lets remove line comments - const char * CommentStrLeft = FindCommentMarker(LineDataLeft.c_str(), filtercommentsset.InlineMarker.c_str()); - const char * CommentStrRight = FindCommentMarker(LineDataRight.c_str(), filtercommentsset.InlineMarker.c_str()); - - if (CommentStrLeft != NULL) - LineDataLeft.erase(CommentStrLeft - LineDataLeft.c_str()); - if (CommentStrRight != NULL) - LineDataRight.erase(CommentStrRight - LineDataRight.c_str()); - } - - if (m_options.m_ignoreWhitespace == WHITESPACE_IGNORE_ALL) - { - //Ignore character case - ReplaceSpaces(LineDataLeft, ""); - ReplaceSpaces(LineDataRight, ""); - } - else if (m_options.m_ignoreWhitespace == WHITESPACE_IGNORE_CHANGE) - { - //Ignore change in whitespace char count - ReplaceSpaces(LineDataLeft, " "); - ReplaceSpaces(LineDataRight, " "); - } - - if (m_options.m_bIgnoreCase) - { - //ignore case - std::transform(LineDataLeft.begin(), LineDataLeft.end(), LineDataLeft.begin(), ::toupper); - std::transform(LineDataRight.begin(), LineDataRight.end(), LineDataRight.begin(), ::toupper); - } + LineDataLeft = m_pSubstitutionList->Subst(LineDataLeft); + LineDataRight = m_pSubstitutionList->Subst(LineDataRight); + } - if (!LineDataLeft.empty()) - LeftLines.push_back(LineDataLeft); - if (!LineDataRight.empty()) - RightLines.push_back(LineDataRight); - } + if (m_options.m_ignoreWhitespace == WHITESPACE_IGNORE_ALL) + { + //Ignore character case + ReplaceSpaces(LineDataLeft, ""); + ReplaceSpaces(LineDataRight, ""); } - if (LeftLines != RightLines) + else if (m_options.m_ignoreWhitespace == WHITESPACE_IGNORE_CHANGE) + { + //Ignore change in whitespace char count + ReplaceSpaces(LineDataLeft, " "); + ReplaceSpaces(LineDataRight, " "); + } + + if (m_options.m_bIgnoreCase) + { + //ignore case + // std::transform(LineDataLeft.begin(), LineDataLeft.end(), LineDataLeft.begin(), ::toupper); + for (std::string::iterator pb = LineDataLeft.begin(), pe = LineDataLeft.end(); pb != pe; ++pb) + *pb = static_cast(::toupper(*pb)); + // std::transform(LineDataRight.begin(), LineDataRight.end(), LineDataRight.begin(), ::toupper); + for (std::string::iterator pb = LineDataRight.begin(), pe = LineDataRight.end(); pb != pe; ++pb) + *pb = static_cast(::toupper(*pb)); + } + if (LineDataLeft != LineDataRight) return; //only difference is trival Op = OP_TRIVIAL; @@ -649,45 +393,22 @@ void CDiffWrapper::PostFilter(int LineNumberLeft, int QtyLinesLeft, int LineNumb * @param [in] files Files to compare * @param [in] tempPaths Are given paths temporary (can be deleted)?. */ -void CDiffWrapper::SetPaths(const PathContext &files, +void CDiffWrapper::SetPaths(const PathContext &tFiles, bool tempPaths) { - m_files = files; + m_files = tFiles; m_bPathsAreTemp = tempPaths; } /** - * @brief Set source paths for original (NON-TEMP) diffing two files. - * Sets full paths to two (NON-TEMP) files we are diffing. - * @param [in] OriginalFile1 First file to compare "(NON-TEMP) file". - * @param [in] OriginalFile2 Second file to compare "(NON-TEMP) file". - */ -void CDiffWrapper::SetCompareFiles(const PathContext &originalFile) -{ - m_originalFile = originalFile; -} - -/** - * @brief Set alternative paths for compared files. - * Sets alternative paths for diff'ed files. These alternative paths might not - * be real paths. For example when creating a patch file from folder compare - * we want to use relative paths. - * @param [in] altPaths Alternative file paths. - */ -void CDiffWrapper::SetAlternativePaths(const PathContext &altPaths) -{ - m_alternativePaths = altPaths; -} - -/** * @brief Runs diff-engine. */ bool CDiffWrapper::RunFileDiff() { - PathContext files = m_files; + PathContext aFiles = m_files; int file; for (file = 0; file < m_files.GetSize(); file++) - files[file] = paths::ToWindowsPath(files[file]); + aFiles[file] = paths::ToWindowsPath(aFiles[file]); bool bRet = true; String strFileTemp[3]; @@ -698,7 +419,7 @@ bool CDiffWrapper::RunFileDiff() if (m_bUseDiffList) m_nDiffs = m_pDiffList->GetSize(); - for (file = 0; file < files.GetSize(); file++) + for (file = 0; file < aFiles.GetSize(); file++) { if (m_bPluginsEnabled) { @@ -709,34 +430,34 @@ bool CDiffWrapper::RunFileDiff() // this can only fail if the data can not be saved back (no more // place on disk ???) What to do then ?? - if (!FileTransform_Prediffing(m_infoPrediffer.get(), strFileTemp[file], m_sToFindPrediffer, m_bPathsAreTemp)) + if (!FileTransform::Prediffing(m_infoPrediffer.get(), strFileTemp[file], m_sToFindPrediffer, m_bPathsAreTemp)) { // display a message box - String sError = string_format( + String sError = strutils::format( _T("An error occurred while prediffing the file '%s' with the plugin '%s'. The prediffing is not applied any more."), strFileTemp[file].c_str(), - m_infoPrediffer->pluginName.c_str()); + m_infoPrediffer->m_PluginName.c_str()); AppErrorMessageBox(sError); // don't use any more this prediffer - m_infoPrediffer->bToBeScanned = false; - m_infoPrediffer->pluginName.erase(); + m_infoPrediffer->m_PluginOrPredifferMode = PLUGIN_MODE::PLUGIN_MANUAL; + m_infoPrediffer->m_PluginName.erase(); } // We use the same plugin for both files, so it must be defined before // second file - assert(m_infoPrediffer->bToBeScanned == false); + assert(m_infoPrediffer->m_PluginOrPredifferMode == PLUGIN_MODE::PLUGIN_MANUAL); } } - struct change *script = NULL; - struct change *script10 = NULL; - struct change *script12 = NULL; + struct change *script = nullptr; + struct change *script10 = nullptr; + struct change *script12 = nullptr; DiffFileData diffdata, diffdata10, diffdata12; int bin_flag = 0, bin_flag10 = 0, bin_flag12 = 0; - if (files.GetSize() == 2) + if (aFiles.GetSize() == 2) { - diffdata.SetDisplayFilepaths(files[0], files[1]); // store true names for diff utils patch file + diffdata.SetDisplayFilepaths(aFiles[0], aFiles[1]); // store true names for diff utils patch file // This opens & fstats both files (if it succeeds) if (!diffdata.OpenFiles(strFileTemp[0], strFileTemp[1])) { @@ -744,9 +465,9 @@ bool CDiffWrapper::RunFileDiff() } // Compare the files, if no error was found. - // Last param (bin_file) is NULL since we don't + // Last param (bin_file) is `nullptr` since we don't // (yet) need info about binary sides. - bRet = Diff2Files(&script, &diffdata, &bin_flag, NULL); + bRet = Diff2Files(&script, &diffdata, &bin_flag, nullptr); // We don't anymore create diff-files for every rescan. // User can create patch-file whenever one wants to. @@ -758,33 +479,32 @@ bool CDiffWrapper::RunFileDiff() String sTempPath = env::GetTemporaryPath(); // get path to Temp folder String path = paths::ConcatPath(sTempPath, _T("Diff.txt")); - outfile = _tfopen(path.c_str(), _T("w+")); - if (outfile != NULL) + if (_tfopen_s(&outfile, path.c_str(), _T("w+")) == 0) { print_normal_script(script); fclose(outfile); - outfile = NULL; + outfile = nullptr; } #endif } else { - diffdata10.SetDisplayFilepaths(files[1], files[0]); // store true names for diff utils patch file - diffdata12.SetDisplayFilepaths(files[1], files[2]); // store true names for diff utils patch file + diffdata10.SetDisplayFilepaths(aFiles[1], aFiles[0]); // store true names for diff utils patch file + diffdata12.SetDisplayFilepaths(aFiles[1], aFiles[2]); // store true names for diff utils patch file if (!diffdata10.OpenFiles(strFileTemp[1], strFileTemp[0])) { return false; } - bRet = Diff2Files(&script10, &diffdata10, &bin_flag10, NULL); + bRet = Diff2Files(&script10, &diffdata10, &bin_flag10, nullptr); if (!diffdata12.OpenFiles(strFileTemp[1], strFileTemp[2])) { return false; } - bRet = Diff2Files(&script12, &diffdata12, &bin_flag12, NULL); + bRet = Diff2Files(&script12, &diffdata12, &bin_flag12, nullptr); } // First determine what happened during comparison @@ -798,19 +518,19 @@ bool CDiffWrapper::RunFileDiff() file_data * inf10 = diffdata10.m_inf; file_data * inf12 = diffdata12.m_inf; - if (files.GetSize() == 2) + if (aFiles.GetSize() == 2) { if (bin_flag != 0) { m_status.bBinaries = true; if (bin_flag != -1) - m_status.Identical = IDENTLEVEL_ALL; + m_status.Identical = IDENTLEVEL::ALL; else - m_status.Identical = IDENTLEVEL_NONE; + m_status.Identical = IDENTLEVEL::NONE; } else { // text files according to diffutils, so change script exists - m_status.Identical = (script == 0) ? IDENTLEVEL_ALL : IDENTLEVEL_NONE; + m_status.Identical = (script == 0) ? IDENTLEVEL::ALL : IDENTLEVEL::NONE; m_status.bBinaries = false; } m_status.bMissingNL[0] = !!inf[0].missing_newline; @@ -818,30 +538,30 @@ bool CDiffWrapper::RunFileDiff() } else { - m_status.Identical = IDENTLEVEL_NONE; + m_status.Identical = IDENTLEVEL::NONE; if (bin_flag10 != 0 || bin_flag12 != 0) { m_status.bBinaries = true; if (bin_flag10 != -1 && bin_flag12 != -1) - m_status.Identical = IDENTLEVEL_ALL; + m_status.Identical = IDENTLEVEL::ALL; else if (bin_flag10 != -1) - m_status.Identical = IDENTLEVEL_EXCEPTRIGHT; + m_status.Identical = IDENTLEVEL::EXCEPTRIGHT; else if (bin_flag12 != -1) - m_status.Identical = IDENTLEVEL_EXCEPTLEFT; + m_status.Identical = IDENTLEVEL::EXCEPTLEFT; else - m_status.Identical = IDENTLEVEL_EXCEPTMIDDLE; + m_status.Identical = IDENTLEVEL::EXCEPTMIDDLE; } else { // text files according to diffutils, so change script exists m_status.bBinaries = false; - if (script10 == 0 && script12 == 0) - m_status.Identical = IDENTLEVEL_ALL; - else if (script10 == 0) - m_status.Identical = IDENTLEVEL_EXCEPTRIGHT; - else if (script12 == 0) - m_status.Identical = IDENTLEVEL_EXCEPTLEFT; + if (script10 == nullptr && script12 == nullptr) + m_status.Identical = IDENTLEVEL::ALL; + else if (script10 == nullptr) + m_status.Identical = IDENTLEVEL::EXCEPTRIGHT; + else if (script12 == nullptr) + m_status.Identical = IDENTLEVEL::EXCEPTLEFT; else - m_status.Identical = IDENTLEVEL_EXCEPTMIDDLE; + m_status.Identical = IDENTLEVEL::EXCEPTMIDDLE; } m_status.bMissingNL[0] = !!inf10[1].missing_newline; m_status.bMissingNL[1] = !!inf12[0].missing_newline; @@ -850,7 +570,7 @@ bool CDiffWrapper::RunFileDiff() // Create patch file - if (!m_status.bBinaries && m_bCreatePatchFile && files.GetSize() == 2) + if (!m_status.bBinaries && m_bCreatePatchFile && aFiles.GetSize() == 2) { WritePatchFile(script, &inf[0]); } @@ -859,7 +579,7 @@ bool CDiffWrapper::RunFileDiff() // This is done on every WinMerge's doc rescan! if (!m_status.bBinaries && m_bUseDiffList) { - if (files.GetSize() == 2) + if (aFiles.GetSize() == 2) LoadWinMergeDiffsFromDiffUtilsScript(script, diffdata.m_inf); else LoadWinMergeDiffsFromDiffUtilsScript3( @@ -868,13 +588,16 @@ bool CDiffWrapper::RunFileDiff() } // cleanup the script - if (files.GetSize() == 2) + if (aFiles.GetSize() == 2) FreeDiffUtilsScript(script); else - FreeDiffUtilsScript3(script10, script12); + { + FreeDiffUtilsScript(script10); + FreeDiffUtilsScript(script12); + } // Done with diffutils filedata - if (files.GetSize() == 2) + if (aFiles.GetSize() == 2) { diffdata.Close(); } @@ -887,9 +610,9 @@ bool CDiffWrapper::RunFileDiff() if (m_bPluginsEnabled) { // Delete temp files transformation functions possibly created - for (file = 0; file < files.GetSize(); file++) + for (file = 0; file < aFiles.GetSize(); file++) { - if (string_compare_nocase(files[file], strFileTemp[file]) != 0) + if (strutils::compare_nocase(aFiles[file], strFileTemp[file]) != 0) { try { @@ -947,13 +670,13 @@ void CDiffWrapper::AddDiffRange(DiffList *pDiffList, DIFFRANGE &dr) * @param [in] leftBufferLines size of array pane left * @param [in] rightBufferLines size of array pane right * @param [in] left on whitch side we have to insert - * @param [in] bIgnoreBlankLines, if true we allways add a new diff and make as trivial + * @param [in] bIgnoreBlankLines, if true we always add a new diff and mark as trivial */ void CDiffWrapper::FixLastDiffRange(int nFiles, int bufferLines[], bool bMissingNL[], bool bIgnoreBlankLines) { DIFFRANGE dr; const int count = m_pDiffList->GetSize(); - if (count > 0 && !bIgnoreBlankLines) + if (count > 0) { m_pDiffList->GetDiff(count - 1, dr); @@ -1002,50 +725,53 @@ String CDiffWrapper::FormatSwitchString() const switch (m_options.m_outputStyle) { - case OUTPUT_CONTEXT: - switches = _T(" C"); + case DIFF_OUTPUT_NORMAL: + switches = _T(" "); break; - case OUTPUT_UNIFIED: - switches = _T(" U"); + case DIFF_OUTPUT_CONTEXT: + switches = (m_options.m_contextLines > 0) ? _T(" -C ") : _T(" -c"); break; - case OUTPUT_ED: + case DIFF_OUTPUT_UNIFIED: + switches = (m_options.m_contextLines > 0) ? _T(" -U ") : _T(" -u"); + break; +#if 0 + case DIFF_OUTPUT_ED: switches = _T(" e"); break; - case OUTPUT_FORWARD_ED: + case DIFF_OUTPUT_FORWARD_ED: switches = _T(" f"); break; - case OUTPUT_RCS: + case DIFF_OUTPUT_RCS: switches = _T(" n"); break; - case OUTPUT_NORMAL: - switches = _T(" "); - break; - case OUTPUT_IFDEF: + case DIFF_OUTPUT_IFDEF: switches = _T(" D"); break; - case OUTPUT_SDIFF: + case DIFF_OUTPUT_SDIFF: switches = _T(" y"); break; +#endif } - if (m_options.m_contextLines > 0) + if ((m_options.m_outputStyle == DIFF_OUTPUT_CONTEXT || m_options.m_outputStyle == DIFF_OUTPUT_UNIFIED) && + m_options.m_contextLines > 0) { TCHAR tmpNum[5] = {0}; - _itot(m_options.m_contextLines, tmpNum, 10); + _itot_s(m_options.m_contextLines, tmpNum, 10); switches += tmpNum; } if (ignore_all_space_flag > 0) - switches += _T("w"); + switches += _T(" -w"); if (ignore_blank_lines_flag > 0) - switches += _T("B"); + switches += _T(" -B"); if (ignore_case_flag > 0) - switches += _T("i"); + switches += _T(" -i"); if (ignore_space_change_flag > 0) - switches += _T("b"); + switches += _T(" -b"); return switches; } @@ -1071,7 +797,7 @@ void CDiffWrapper::SetAppendFiles(bool bAppendFiles) * @param [in] diffData files to compare. * @param [out] bin_status used to return binary status from compare. * @param [out] bin_file Returns which file was binary file as bitmap. - So if first file is binary, first bit is set etc. Can be NULL if binary file + So if first file is binary, first bit is set etc. Can be `nullptr` if binary file info is not needed (faster compare since diffutils don't bother checking second file if first is binary). * @return true when compare succeeds, false if error happened during compare. @@ -1085,14 +811,24 @@ bool CDiffWrapper::Diff2Files(struct change ** diffs, DiffFileData *diffData, SE_Handler seh; try { - // Diff files. depth is zero because we are not 6comparing dirs - *diffs = diff_2_files (diffData->m_inf, 0, bin_status, - (m_pMovedLines[0] != NULL), bin_file); + if (m_options.m_diffAlgorithm != DIFF_ALGORITHM_DEFAULT) + { + unsigned xdl_flags = make_xdl_flags(m_options); + *diffs = diff_2_files_xdiff(diffData->m_inf, (m_pMovedLines[0] != nullptr), xdl_flags); + files[0] = diffData->m_inf[0]; + files[1] = diffData->m_inf[1]; + } + else + { + // Diff files. depth is zero because we are not comparing dirs + *diffs = diff_2_files(diffData->m_inf, 0, bin_status, + (m_pMovedLines[0] != nullptr), bin_file); + } CopyDiffutilTextStats(diffData->m_inf, diffData); } catch (SE_Exception&) { - *diffs = NULL; + *diffs = nullptr; bRet = false; } return bRet; @@ -1101,43 +837,18 @@ bool CDiffWrapper::Diff2Files(struct change ** diffs, DiffFileData *diffData, /** * @brief Free script (the diffutils linked list of differences) */ -static void -FreeDiffUtilsScript(struct change * & script) +void +CDiffWrapper::FreeDiffUtilsScript(struct change * & script) { - if (!script) return; - struct change *e=0, *p=0; + if (script == nullptr) return; + struct change *e=nullptr, *p=nullptr; // cleanup the script - for (e = script; e; e = p) + for (e = script; e != nullptr; e = p) { p = e->link; free(e); } - script = 0; -} - -/** - * @brief Free script (the diffutils linked list of differences) - */ -static void -FreeDiffUtilsScript3(struct change * & script10, struct change * & script12) -{ - struct change *e=0, *p=0; - for (e = script10; e; e = p) - { - p = e->link; - free (e); - } - for (e = script12; e; e = p) - { - p = e->link; - free (e); - } -} - -void -CDiffWrapper::FreeDiffUtilsScript3(struct change * & script10, struct change * & script12) -{ - ::FreeDiffUtilsScript3(script10, script12); + script = nullptr; } /** @@ -1150,24 +861,23 @@ CDiffWrapper::FreeDiffUtilsScript3(struct change * & script10, struct change * & * @param [in] FileNo File to match. * return true if any of the expressions matches. */ -bool CDiffWrapper::RegExpFilter(int StartPos, int EndPos, int FileNo) const +bool CDiffWrapper::RegExpFilter(int StartPos, int EndPos, const file_data *pinf) const { - if (m_pFilterList == NULL) + if (m_pFilterList == nullptr) { throw "CDiffWrapper::RegExpFilter() called when " - "filterlist doesn't exist (=NULL)"; - return false; + "filterlist doesn't exist (=nullptr)"; } bool linesMatch = true; // set to false when non-matching line is found. int line = StartPos; - while (line <= EndPos && linesMatch == true) + while (line <= EndPos && linesMatch) { - size_t len = files[FileNo].linbuf[line + 1] - files[FileNo].linbuf[line]; - const char *string = files[FileNo].linbuf[line]; + size_t len = pinf->linbuf[line + 1] - pinf->linbuf[line]; + const char *string = pinf->linbuf[line]; size_t stringlen = linelen(string, len); - if (!m_pFilterList->Match(std::string(string, stringlen), m_codepage)) + if (!m_pFilterList->Match(std::string(string, stringlen))) { linesMatch = false; @@ -1181,27 +891,14 @@ bool CDiffWrapper::RegExpFilter(int StartPos, int EndPos, int FileNo) const * @brief Walk the diff utils change script, building the WinMerge list of diff blocks */ void -CDiffWrapper::LoadWinMergeDiffsFromDiffUtilsScript(struct change * script, const file_data * inf) +CDiffWrapper::LoadWinMergeDiffsFromDiffUtilsScript(struct change * script, const file_data * file_data_ary) { //Logic needed for Ignore comment option - DIFFOPTIONS options; - GetOptions(&options); - String asLwrCaseExt; - if (options.bFilterCommentsLines) - { - String LowerCaseExt = m_originalFile.GetLeft(); - String::size_type PosOfDot = LowerCaseExt.rfind('.'); - if (PosOfDot != String::npos) - { - LowerCaseExt.erase(0, PosOfDot + 1); - std::transform(LowerCaseExt.begin(), LowerCaseExt.end(), LowerCaseExt.begin(), ::tolower); - asLwrCaseExt = LowerCaseExt; - } - } + PostFilterContext ctxt; struct change *next = script; - while (next) + while (next != nullptr) { /* Find a set of changes that belong together. */ struct change *thisob = next; @@ -1210,7 +907,7 @@ CDiffWrapper::LoadWinMergeDiffsFromDiffUtilsScript(struct change * script, const /* 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; + end->link = nullptr; #ifdef DEBUG debug_script(thisob); #endif @@ -1220,7 +917,7 @@ CDiffWrapper::LoadWinMergeDiffsFromDiffUtilsScript(struct change * script, const { /* Determine range of line numbers involved in each file. */ int first0=0, last0=0, first1=0, last1=0, deletes=0, inserts=0; - analyze_hunk (thisob, &first0, &last0, &first1, &last1, &deletes, &inserts, inf); + analyze_hunk (thisob, &first0, &last0, &first1, &last1, &deletes, &inserts, file_data_ary); if (deletes || inserts || thisob->trivial) { OP_TYPE op = OP_NONE; @@ -1233,59 +930,57 @@ CDiffWrapper::LoadWinMergeDiffsFromDiffUtilsScript(struct change * script, const /* Print the lines that the first file has. */ int trans_a0=0, trans_b0=0, trans_a1=0, trans_b1=0; - translate_range(&inf[0], first0, last0, &trans_a0, &trans_b0); - translate_range(&inf[1], first1, last1, &trans_a1, &trans_b1); + translate_range(&file_data_ary[0], first0, last0, &trans_a0, &trans_b0); + translate_range(&file_data_ary[1], first1, last1, &trans_a1, &trans_b1); // Store information about these blocks in moved line info if (GetDetectMovedBlocks()) { if (thisob->match0>=0) { - assert(thisob->inserted); + assert(thisob->inserted > 0); for (int i=0; iinserted; ++i) { int line0 = i+thisob->match0 + (trans_a0-first0-1); int line1 = i+thisob->line1 + (trans_a1-first1-1); - GetMovedLines(1)->Add(MovedLines::SIDE_LEFT, line1, line0); + GetMovedLines(1)->Add(MovedLines::SIDE::LEFT, line1, line0); } } if (thisob->match1>=0) { - assert(thisob->deleted); + assert(thisob->deleted > 0); for (int i=0; ideleted; ++i) { int line0 = i+thisob->line0 + (trans_a0-first0-1); int line1 = i+thisob->match1 + (trans_a1-first1-1); - GetMovedLines(0)->Add(MovedLines::SIDE_RIGHT, line0, line1); + GetMovedLines(0)->Add(MovedLines::SIDE::RIGHT, line0, line1); } } } + int QtyLinesLeft = (trans_b0 - trans_a0) + 1; //Determine quantity of lines in this block for left side + int QtyLinesRight = (trans_b1 - trans_a1) + 1;//Determine quantity of lines in this block for right side - if (options.bFilterCommentsLines) - { - int QtyLinesLeft = (trans_b0 - trans_a0) + 1; //Determine quantity of lines in this block for left side - int QtyLinesRight = (trans_b1 - trans_a1) + 1;//Determine quantity of lines in this block for right side - PostFilter(thisob->line0, QtyLinesLeft, thisob->line1, QtyLinesRight, op, asLwrCaseExt); - } + if (m_options.m_filterCommentsLines || + (m_pSubstitutionList && m_pSubstitutionList->HasRegExps())) + PostFilter(ctxt, trans_a0 - 1, QtyLinesLeft, trans_a1 - 1, QtyLinesRight, op, file_data_ary); - if (m_pFilterList && m_pFilterList->HasRegExps()) + if (m_pFilterList != nullptr && m_pFilterList->HasRegExps()) { - //Determine quantity of lines in this block for both sides - int QtyLinesLeft = (trans_b0 - trans_a0); - int QtyLinesRight = (trans_b1 - trans_a1); - // Match lines against regular expression filters // Our strategy is that every line in both sides must // match regexp before we mark difference as ignored. bool match2 = false; - bool match1 = RegExpFilter(thisob->line0, thisob->line0 + QtyLinesLeft, 0); + bool match1 = RegExpFilter(thisob->line0, thisob->line0 + QtyLinesLeft - 1, &file_data_ary[0]); if (match1) - match2 = RegExpFilter(thisob->line1, thisob->line1 + QtyLinesRight, 1); + match2 = RegExpFilter(thisob->line1, thisob->line1 + QtyLinesRight - 1, &file_data_ary[1]); if (match1 && match2) op = OP_TRIVIAL; } - AddDiffRange(m_pDiffList, trans_a0-1, trans_b0-1, trans_a1-1, trans_b1-1, op); + if (op == OP_TRIVIAL && m_options.m_bCompletelyBlankOutIgnoredDiffereneces) + op = OP_NONE; + if (op != OP_NONE) + AddDiffRange(m_pDiffList, trans_a0-1, trans_b0-1, trans_a1-1, trans_b1-1, op); } } @@ -1333,17 +1028,19 @@ CDiffWrapper::LoadWinMergeDiffsFromDiffUtilsScript3( const file_data * inf10, const file_data * inf12) { - DiffList diff10, diff12, *pdiff; + DiffList diff10, diff12; diff10.Clear(); diff12.Clear(); for (int file = 0; file < 2; file++) { - struct change *next; + struct change *next = nullptr; int trans_a0, trans_b0, trans_a1, trans_b1; int first0, last0, first1, last1, deletes, inserts; OP_TYPE op; - const file_data *pinf; + const file_data *pinf = nullptr; + DiffList *pdiff = nullptr; + PostFilterContext ctxt; switch (file) { @@ -1351,7 +1048,7 @@ CDiffWrapper::LoadWinMergeDiffsFromDiffUtilsScript3( case 1: next = script12; pdiff = &diff12; pinf = inf12; break; } - while (next) + while (next != nullptr) { /* Find a set of changes that belong together. */ struct change *thisob = next; @@ -1360,7 +1057,7 @@ CDiffWrapper::LoadWinMergeDiffsFromDiffUtilsScript3( /* 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; + end->link = nullptr; #ifdef DEBUG debug_script(thisob); #endif @@ -1386,29 +1083,22 @@ CDiffWrapper::LoadWinMergeDiffsFromDiffUtilsScript3( // Store information about these blocks in moved line info if (GetDetectMovedBlocks()) { - int index1 = -1; - int index2 = -1; - MovedLines::ML_SIDE side1; - MovedLines::ML_SIDE side2; - if (file == 0 /* diff10 */) - { - index1 = 0; - index2 = 1; - side1 = MovedLines::SIDE_RIGHT; - side2 = MovedLines::SIDE_LEFT; - } - else if (file == 1 /* diff12 */) + int index1 = 0; // defaults for (file == 0 /* diff10 */) + int index2 = 1; + MovedLines::SIDE side1 = MovedLines::SIDE::RIGHT; + MovedLines::SIDE side2 = MovedLines::SIDE::LEFT; + if (file == 1 /* diff12 */) { index1 = 2; index2 = 1; - side1 = MovedLines::SIDE_LEFT; - side2 = MovedLines::SIDE_RIGHT; + side1 = MovedLines::SIDE::LEFT; + side2 = MovedLines::SIDE::RIGHT; } if (index1 != -1 && index2 != -1) { if (thisob->match0>=0) { - assert(thisob->inserted); + assert(thisob->inserted > 0); for (int i=0; iinserted; ++i) { int line0 = i+thisob->match0 + (trans_a0-first0-1); @@ -1418,7 +1108,7 @@ CDiffWrapper::LoadWinMergeDiffsFromDiffUtilsScript3( } if (thisob->match1>=0) { - assert(thisob->deleted); + assert(thisob->deleted > 0); for (int i=0; ideleted; ++i) { int line0 = i+thisob->line0 + (trans_a0-first0-1); @@ -1429,6 +1119,26 @@ CDiffWrapper::LoadWinMergeDiffsFromDiffUtilsScript3( } } + int QtyLinesLeft = (trans_b0 - trans_a0) + 1; //Determine quantity of lines in this block for left side + int QtyLinesRight = (trans_b1 - trans_a1) + 1;//Determine quantity of lines in this block for right side + + if (m_options.m_filterCommentsLines || + (m_pSubstitutionList && m_pSubstitutionList->HasRegExps())) + PostFilter(ctxt, trans_a0 - 1, QtyLinesLeft, trans_a1 - 1, QtyLinesRight, op, pinf); + + if (m_pFilterList != nullptr && m_pFilterList->HasRegExps()) + { + // Match lines against regular expression filters + // Our strategy is that every line in both sides must + // match regexp before we mark difference as ignored. + bool match2 = false; + bool match1 = RegExpFilter(thisob->line0, thisob->line0 + QtyLinesLeft - 1, &pinf[0]); + if (match1) + match2 = RegExpFilter(thisob->line1, thisob->line1 + QtyLinesRight - 1, &pinf[1]); + if (match1 && match2) + op = OP_TRIVIAL; + } + AddDiffRange(pdiff, trans_a0-1, trans_b0-1, trans_a1-1, trans_b1-1, op); } } @@ -1439,35 +1149,39 @@ CDiffWrapper::LoadWinMergeDiffsFromDiffUtilsScript3( } Make3wayDiff(m_pDiffList->GetDiffRangeInfoVector(), diff10.GetDiffRangeInfoVector(), diff12.GetDiffRangeInfoVector(), - Comp02Functor(inf10, inf12), (m_pFilterList && m_pFilterList->HasRegExps())); + Comp02Functor(inf10, inf12), + (m_pFilterList != nullptr && m_pFilterList->HasRegExps()) || m_options.m_bIgnoreBlankLines || m_options.m_filterCommentsLines); } -void CDiffWrapper::WritePatchFileHeader(enum output_style output_style, bool bAppendFiles) +void CDiffWrapper::WritePatchFileHeader(enum output_style tOutput_style, bool bAppendFiles) { - outfile = NULL; + outfile = nullptr; if (!m_sPatchFile.empty()) { const TCHAR *mode = (bAppendFiles ? _T("a+") : _T("w+")); - outfile = _tfopen(m_sPatchFile.c_str(), mode); + if (_tfopen_s(&outfile, m_sPatchFile.c_str(), mode) != 0) + outfile = nullptr; } - if (!outfile) + if (outfile == nullptr) { m_status.bPatchFileFailed = true; return; } // Output patchfile - switch (output_style) + switch (tOutput_style) { + case OUTPUT_NORMAL: case OUTPUT_CONTEXT: case OUTPUT_UNIFIED: +#if 0 case OUTPUT_ED: case OUTPUT_FORWARD_ED: case OUTPUT_RCS: - case OUTPUT_NORMAL: case OUTPUT_IFDEF: case OUTPUT_SDIFF: +#endif break; case OUTPUT_HTML: print_html_header(); @@ -1475,34 +1189,37 @@ void CDiffWrapper::WritePatchFileHeader(enum output_style output_style, bool bAp } fclose(outfile); - outfile = NULL; + outfile = nullptr; } -void CDiffWrapper::WritePatchFileTerminator(enum output_style output_style) +void CDiffWrapper::WritePatchFileTerminator(enum output_style tOutput_style) { - outfile = NULL; + outfile = nullptr; if (!m_sPatchFile.empty()) { - outfile = _tfopen(m_sPatchFile.c_str(), _T("a+")); + if (_tfopen_s(&outfile, m_sPatchFile.c_str(), _T("a+")) != 0) + outfile = nullptr; } - if (!outfile) + if (outfile == nullptr) { m_status.bPatchFileFailed = true; return; } // Output patchfile - switch (output_style) + switch (tOutput_style) { + case OUTPUT_NORMAL: case OUTPUT_CONTEXT: case OUTPUT_UNIFIED: +#if 0 case OUTPUT_ED: case OUTPUT_FORWARD_ED: case OUTPUT_RCS: - case OUTPUT_NORMAL: case OUTPUT_IFDEF: case OUTPUT_SDIFF: +#endif break; case OUTPUT_HTML: print_html_terminator(); @@ -1510,7 +1227,7 @@ void CDiffWrapper::WritePatchFileTerminator(enum output_style output_style) } fclose(outfile); - outfile = NULL; + outfile = nullptr; } /** @@ -1522,9 +1239,8 @@ void CDiffWrapper::WritePatchFileTerminator(enum output_style output_style) */ void CDiffWrapper::WritePatchFile(struct change * script, file_data * inf) { - file_data inf_patch[2] = {0}; - std::memcpy(&inf_patch, inf, sizeof(file_data) * 2); - + file_data inf_patch[2] = { inf[0], inf[1] }; + // Get paths, primarily use alternative paths, only if they are empty // use full filepaths String path1(m_alternativePaths[0]); @@ -1535,8 +1251,17 @@ void CDiffWrapper::WritePatchFile(struct change * script, file_data * inf) path2 = m_files[1]; path1 = paths::ToUnixPath(path1); path2 = paths::ToUnixPath(path2); - inf_patch[0].name = strdup(ucr::toSystemCP(path1).c_str()); - inf_patch[1].name = strdup(ucr::toSystemCP(path2).c_str()); + if ((inf_patch[0].linbuf && ucr::CheckForInvalidUtf8(inf_patch[0].buffer, inf_patch[0].buffered_chars)) || + (inf_patch[1].linbuf && ucr::CheckForInvalidUtf8(inf_patch[1].buffer, inf_patch[1].buffered_chars))) + { + inf_patch[0].name = _strdup(ucr::toThreadCP(path1).c_str()); + inf_patch[1].name = _strdup(ucr::toThreadCP(path2).c_str()); + } + else + { + inf_patch[0].name = _strdup(ucr::toUTF8(path1).c_str()); + inf_patch[1].name = _strdup(ucr::toUTF8(path2).c_str()); + } // If paths in m_s1File and m_s2File point to original files, then we can use // them to fix potentially meaningless stats from potentially temporary files, @@ -1544,22 +1269,23 @@ void CDiffWrapper::WritePatchFile(struct change * script, file_data * inf) // If not, then we can't help it, and hence assert that this won't happen. if (!m_bPathsAreTemp) { - _tstat(m_files[0].c_str(), &inf_patch[0].stat); - _tstat(m_files[1].c_str(), &inf_patch[1].stat); + mywstat(m_files[0].c_str(), &inf_patch[0].stat); + mywstat(m_files[1].c_str(), &inf_patch[1].stat); } else { assert(false); } - outfile = NULL; + outfile = nullptr; if (!m_sPatchFile.empty()) { const TCHAR *mode = (m_bAppendFiles ? _T("a+") : _T("w+")); - outfile = _tfopen(m_sPatchFile.c_str(), mode); + if (_tfopen_s(&outfile, m_sPatchFile.c_str(), mode) != 0) + outfile = nullptr; } - if (!outfile) + if (outfile == nullptr) { m_status.bPatchFileFailed = true; return; @@ -1577,18 +1303,21 @@ void CDiffWrapper::WritePatchFile(struct change * script, file_data * inf) if (strcmp(inf[0].name, "NUL") == 0) { - free((void *)inf[0].name); - inf[0].name = strdup("/dev/null"); + free((void *)inf_patch[0].name); + inf_patch[0].name = _strdup("/dev/null"); } if (strcmp(inf[1].name, "NUL") == 0) { - free((void *)inf[1].name); - inf[1].name = strdup("/dev/null"); + free((void *)inf_patch[1].name); + inf_patch[1].name = _strdup("/dev/null"); } // Output patchfile switch (output_style) { + case OUTPUT_NORMAL: + print_normal_script(script); + break; case OUTPUT_CONTEXT: print_context_header(inf_patch, 0); print_context_script(script, 0); @@ -1597,6 +1326,7 @@ void CDiffWrapper::WritePatchFile(struct change * script, file_data * inf) print_context_header(inf_patch, 1); print_context_script(script, 1); break; +#if 0 case OUTPUT_ED: print_ed_script(script); break; @@ -1606,15 +1336,13 @@ void CDiffWrapper::WritePatchFile(struct change * script, file_data * inf) 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); break; +#endif case OUTPUT_HTML: print_html_diff_header(inf_patch); print_html_script(script); @@ -1622,7 +1350,7 @@ void CDiffWrapper::WritePatchFile(struct change * script, file_data * inf) } fclose(outfile); - outfile = NULL; + outfile = nullptr; free((void *)inf_patch[0].name); free((void *)inf_patch[1].name); @@ -1642,7 +1370,7 @@ void CDiffWrapper::SetFilterList(const String& filterStr) } // Adding new filter without previous filter - if (m_pFilterList == NULL) + if (m_pFilterList == nullptr) { m_pFilterList.reset(new FilterList); } @@ -1657,6 +1385,32 @@ void CDiffWrapper::SetFilterList(const String& filterStr) m_pFilterList->AddRegExp(*it); } +void CDiffWrapper::SetFilterList(const FilterList* pFilterList) +{ + if (!pFilterList) + m_pFilterList.reset(); + else + { + m_pFilterList.reset(new FilterList()); + *m_pFilterList = *pFilterList; + } +} + +const SubstitutionList* CDiffWrapper::GetSubstitutionList() const +{ + return m_pSubstitutionList.get(); +} + +void CDiffWrapper::SetSubstitutionList(std::shared_ptr pSubstitutionList) +{ + m_pSubstitutionList = pSubstitutionList; +} + +void CDiffWrapper::SetFilterCommentsSourceDef(const String& ext) +{ + m_pFilterCommentsDef = CrystalLineParser::GetTextType(ext.c_str()); +} + /** * @brief Copy text stat results from diffutils back into the FileTextStats structure */