1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * @brief Declaration file for CDiffWrapper.
7 * @date Created: 2003-08-22
13 #include "FileLocation.h"
14 #include "PathContext.h"
15 #include "CompareOptions.h"
17 #include "UnicodeString.h"
18 #include "FileTransform.h"
27 class SubstitutionList;
28 namespace CrystalLineParser { struct TextDefinition; };
30 /** @enum COMPARE_TYPE
31 * @brief Different foldercompare methods.
32 * These values are the foldercompare methods WinMerge supports.
36 * @brief Normal by content compare.
37 * This compare type is first, default and all-seeing compare type.
38 * diffutils is used for producing compare results. So all limitations
39 * of diffutils (like buffering) apply to this compare method. But this
40 * is also currently only compare method that produces difference lists
41 * we can use in file compare.
44 /** @var CMP_QUICK_CONTENT
45 * @brief Faster byte per byte -compare.
46 * This type of compare was a response for needing faster compare results
47 * in folder compare. It independent from diffutils, and fully customised
48 * for WinMerge. It basically does byte-per-byte compare, still implementing
49 * different whitespace ignore options.
51 * Optionally this compare type can be stopped when first difference is found.
52 * Which gets compare as fast as possible. But misses sometimes binary files
53 * if zero bytes aren't found before first difference. Also difference counts
54 * are not useful with that option.
58 * @brief Compare by modified date.
59 * This compare type was added after requests and realization that in some
60 * situations difference in file's timestamps is enough to judge them
61 * different. E.g. when modifying files in local machine, file timestamps
62 * are certainly different after modifying them. This method doesn't even
63 * open files for reading them. It only reads file's infos for timestamps
66 * This is no doubt fastest way to compare files.
69 /** @var CMP_DATE_SIZE
70 * @brief Compare by date and then by size.
71 * This method is basically same than CMP_DATE, but it adds check for file
72 * sizes if timestamps are identical. This is because there are situations
73 * timestamps can't be trusted alone, especially with network shares. Adding
74 * checking for file sizes adds some more reliability for results with
75 * minimal increase in compare time.
79 * @brief Compare by file size.
80 * This compare method compares file sizes. This isn't quite accurate method,
81 * other than it can detect files that certainly differ. But it can show lot of
82 * different files as identical too. Advantage is in some use cases where different
83 * size always means files are different. E.g. automatically created logs - when
84 * more data is added size increases.
98 * @brief Additional options for creating patch files
102 enum output_style outputStyle; /**< Patch file style. */
103 int nContext; /**< Number of context lines. */
104 bool bAddCommandline; /**< Add diff-style commandline to patch file. */
107 enum class IDENTLEVEL {
115 * @brief Diffutils returns this statusdata about files compared
119 bool bMissingNL[3] {}; /**< file is missing EOL before EOF */
120 bool bBinaries = false; /**< Files are binaries */
121 IDENTLEVEL Identical = IDENTLEVEL::NONE; /**< diffutils said files are identical */
122 bool bPatchFileFailed = false; /**< Creating patch file failed */
125 void MergeStatus(const DIFFSTATUS& other)
127 if (Identical == IDENTLEVEL::ALL)
128 Identical = other.Identical;
130 (Identical == IDENTLEVEL::EXCEPTLEFT && other.Identical != IDENTLEVEL::EXCEPTLEFT) ||
131 (Identical == IDENTLEVEL::EXCEPTRIGHT && other.Identical != IDENTLEVEL::EXCEPTRIGHT) ||
132 (Identical == IDENTLEVEL::EXCEPTMIDDLE && other.Identical != IDENTLEVEL::EXCEPTMIDDLE))
133 Identical = IDENTLEVEL::NONE;
134 if (other.bPatchFileFailed)
135 bPatchFileFailed = true;
138 std::copy_n(other.bMissingNL, 3, bMissingNL);
142 struct PostFilterContext
144 int nParsedLineEndLeft = -1;
145 int nParsedLineEndRight = -1;
146 unsigned dwCookieLeft = 0;
147 unsigned dwCookieRight = 0;
151 * @brief Wrapper class for diffengine (diffutils and ByteComparator).
152 * Diffwappre class is used to run selected diffengine. For folder compare
153 * there are several methods (COMPARE_TYPE), but for file compare diffutils
154 * is used always. For file compare diffutils can output results to external
155 * DiffList or to patch file. Output type must be selected with member
156 * functions SetCreatePatchFile() and SetCreateDiffList().
163 void SetCreatePatchFile(const String &filename);
164 void SetCreateDiffList(DiffList *diffList);
165 void GetOptions(DIFFOPTIONS *options) const;
166 void SetOptions(const DIFFOPTIONS *options);
167 void SetTextForAutomaticPrediff(const String &text);
168 void SetPrediffer(const PrediffingInfo * prediffer = nullptr);
169 void GetPrediffer(PrediffingInfo * prediffer) const;
170 void SetPatchOptions(const PATCHOPTIONS *options);
171 void SetDetectMovedBlocks(bool bDetectMovedBlocks);
172 bool GetDetectMovedBlocks() const { return (m_pMovedLines[0] != nullptr); }
173 void SetAppendFiles(bool bAppendFiles);
174 void SetPaths(const PathContext &files, bool tempPaths);
175 void SetAlternativePaths(const PathContext &altPaths);
177 void GetDiffStatus(DIFFSTATUS *status) const;
178 void AddDiffRange(DiffList *pDiffList, unsigned begin0, unsigned end0, unsigned begin1, unsigned end1, OP_TYPE op);
179 void AddDiffRange(DiffList *pDiffList, DIFFRANGE &dr);
180 void FixLastDiffRange(int nFiles, int bufferLines[], bool bMissingNL[], bool bIgnoreBlankLines);
181 MovedLines * GetMovedLines(int index) { return m_pMovedLines[index].get(); }
182 void SetCompareFiles(const PathContext &originalFile);
183 void WritePatchFileHeader(enum output_style output_style, bool bAppendFiles);
184 void WritePatchFileTerminator(enum output_style output_style);
185 void SetFilterList(const String& filterStr);
186 void SetFilterList(const FilterList *pFilterList);
187 const SubstitutionList* GetSubstitutionList() const;
188 void SetSubstitutionList(std::shared_ptr<SubstitutionList> pSubstitutionFiltersList);
189 void SetFilterCommentsSourceDef(CrystalLineParser::TextDefinition *def) { m_pFilterCommentsDef = def; };
190 void SetFilterCommentsSourceDef(const String& ext);
191 void EnablePlugins(bool enable);
192 void PostFilter(PostFilterContext& ctxt, int LineNumberLeft, int QtyLinesLeft, int LineNumberRight,
193 int QtyLinesRight, OP_TYPE &Op, const file_data *file_data_ary) const;
196 String FormatSwitchString() const;
197 bool Diff2Files(struct change ** diffs, DiffFileData *diffData,
198 int * bin_status, int * bin_file) const;
199 void LoadWinMergeDiffsFromDiffUtilsScript(struct change * script, const file_data * inf);
200 void WritePatchFile(struct change * script, file_data * inf);
202 void LoadWinMergeDiffsFromDiffUtilsScript3(
203 struct change * script10, struct change * script12,
204 const file_data * inf10, const file_data * inf12);
205 static void FreeDiffUtilsScript(struct change * & script);
206 bool RegExpFilter(int StartPos, int EndPos, const file_data * pinf) const;
209 DiffutilsOptions m_options;
210 DIFFSTATUS m_status; /**< Status of last compare */
211 std::unique_ptr<FilterList> m_pFilterList; /**< List of linefilters. */
212 std::shared_ptr<SubstitutionList> m_pSubstitutionList;
214 PathContext m_files; /**< Full path to diff'ed file. */
215 PathContext m_alternativePaths; /**< file's alternative path (may be relative). */
216 PathContext m_originalFile; /**< file's original (NON-TEMP) path. */
218 String m_sPatchFile; /**< Full path to created patch file. */
219 bool m_bPathsAreTemp; /**< Are compared paths temporary? */
220 /// prediffer info are stored only for MergeDoc
221 std::unique_ptr<PrediffingInfo> m_infoPrediffer;
222 /// prediffer info are stored only for MergeDoc
223 String m_sToFindPrediffer;
224 bool m_bUseDiffList; /**< Are results returned in difflist? */
225 bool m_bCreatePatchFile; /**< Do we create a patch file? */
226 bool m_bAddCmdLine; /**< Do we add commandline to patch file? */
227 bool m_bAppendFiles; /**< Do we append to existing patch file? */
228 int m_nDiffs; /**< Difference count */
229 DiffList *m_pDiffList; /**< Pointer to external DiffList */
230 std::unique_ptr<MovedLines> m_pMovedLines[3];
231 CrystalLineParser::TextDefinition *m_pFilterCommentsDef; /**< Text definition for Comments filter */
232 bool m_bPluginsEnabled; /**< Are plugins enabled? */
236 * @brief Set text tested to find the prediffer automatically.
237 * Most probably a concatenated string of both filenames.
239 inline void CDiffWrapper::SetTextForAutomaticPrediff(const String &text)
241 m_sToFindPrediffer = text;
244 inline void CDiffWrapper::GetPrediffer(PrediffingInfo * prediffer) const
246 *prediffer = *m_infoPrediffer;
250 * @brief Set plugins enabled/disabled.
251 * @param [in] enable if true plugins are enabled.
253 inline void CDiffWrapper::EnablePlugins(bool enable)
255 m_bPluginsEnabled = enable;
259 * @brief Set source paths for original (NON-TEMP) diffing two files.
260 * Sets full paths to two (NON-TEMP) files we are diffing.
261 * @param [in] OriginalFile1 First file to compare "(NON-TEMP) file".
262 * @param [in] OriginalFile2 Second file to compare "(NON-TEMP) file".
264 inline void CDiffWrapper::SetCompareFiles(const PathContext &originalFile)
266 m_originalFile = originalFile;
270 * @brief Set alternative paths for compared files.
271 * Sets alternative paths for diff'ed files. These alternative paths might not
272 * be real paths. For example when creating a patch file from folder compare
273 * we want to use relative paths.
274 * @param [in] altPaths Alternative file paths.
276 inline void CDiffWrapper::SetAlternativePaths(const PathContext &altPaths)
278 m_alternativePaths = altPaths;