-/////////////////////////////////////////////////////////////////////////////
-// 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
*
* @date Created: 2003-08-22
*/
+#include "pch.h"
#define NOMINMAX
#include "DiffWrapper.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <algorithm>
#include <string>
+#include <cctype>
+#include <cwctype>
#include <map>
#include <cassert>
#include <exception>
#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;
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';
}
}
/**
- * @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.
{
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
{
*/
void CDiffWrapper::GetOptions(DIFFOPTIONS *options) const
{
- assert(options);
+ assert(options != nullptr);
DIFFOPTIONS tmpOptions = {0};
m_options.GetAsDiffOptions(tmpOptions);
*options = tmpOptions;
*/
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.
*/
void CDiffWrapper::SetPatchOptions(const PATCHOPTIONS *options)
{
- assert(options);
+ assert(options != nullptr);
m_options.m_contextLines = options->nContext;
switch (options->outputStyle)
{
if (bDetectMovedBlocks)
{
- if (m_pMovedLines[0] == NULL)
+ if (m_pMovedLines[0] == nullptr)
{
m_pMovedLines[0].reset(new MovedLines);
m_pMovedLines[1].reset(new MovedLines);
}
}
-/**
- * @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<CrystalLineParser::TEXTBLOCK> blocks(text.length());
+ dwCookie = enuType->ParseLineX(dwCookie, text.c_str(), static_cast<int>(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<unsigned>(text.size());
+ if (!enuType)
{
- quote ^= c;
+ filteredT += text;
+ }
+ else
+ {
+ int nActualItems = 0;
+ std::vector<CrystalLineParser::TEXTBLOCK> 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;
}
/**
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
@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<std::string> 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<char>(::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<char>(::toupper(*pb));
+ }
+ if (LineDataLeft != LineDataRight)
return;
//only difference is trival
Op = OP_TRIVIAL;
* @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];
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)
{
// 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]))
{
}
// 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.
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
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;
}
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;
// 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]);
}
// 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(
}
// 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();
}
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
{
* @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);
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;
}
* @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.
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;
/**
* @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;
}
/**
* @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;
* @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;
/* 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
{
/* 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;
/* 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; i<thisob->inserted; ++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; i<thisob->deleted; ++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);
}
}
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)
{
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;
/* 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
// 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; i<thisob->inserted; ++i)
{
int line0 = i+thisob->match0 + (trans_a0-first0-1);
}
if (thisob->match1>=0)
{
- assert(thisob->deleted);
+ assert(thisob->deleted > 0);
for (int i=0; i<thisob->deleted; ++i)
{
int line0 = i+thisob->line0 + (trans_a0-first0-1);
}
}
+ 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);
}
}
}
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();
}
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();
}
fclose(outfile);
- outfile = NULL;
+ outfile = nullptr;
}
/**
*/
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]);
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,
// 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;
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);
print_context_header(inf_patch, 1);
print_context_script(script, 1);
break;
+#if 0
case OUTPUT_ED:
print_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);
break;
+#endif
case OUTPUT_HTML:
print_html_diff_header(inf_patch);
print_html_script(script);
}
fclose(outfile);
- outfile = NULL;
+ outfile = nullptr;
free((void *)inf_patch[0].name);
free((void *)inf_patch[1].name);
}
// Adding new filter without previous filter
- if (m_pFilterList == NULL)
+ if (m_pFilterList == nullptr)
{
m_pFilterList.reset(new FilterList);
}
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<SubstitutionList> 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
*/