1 // TortoiseMerge - a Diff/Patch program
3 // Copyright (C) 2006-2009 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "svn_version.h"
23 #include "TempFiles.h"
27 #include "UnicodeUtils.h"
28 #include "GitAdminDir.h"
32 #pragma warning(disable: 4702) // unreachable code
33 int CDiffData::abort_on_pool_failure (int /*retcode*/)
40 CDiffData::CDiffData(void)
44 svn_dso_initialize2();
46 m_sPatchOriginal
= _T(": original");
47 m_sPatchPatched
= _T(": patched");
50 CDiffData::~CDiffData(void)
55 int CDiffData::GetLineCount()
58 count
= (int)m_arBaseFile
.GetCount();
59 count
= (int)(count
> m_arTheirFile
.GetCount() ? count
: m_arTheirFile
.GetCount());
60 count
= (int)(count
> m_arYourFile
.GetCount() ? count
: m_arYourFile
.GetCount());
64 int CDiffData::GetLineActualLength(int index
)
67 if (index
< m_arBaseFile
.GetCount())
68 count
= (count
> m_arBaseFile
.GetAt(index
).GetLength() ? count
: m_arBaseFile
.GetAt(index
).GetLength());
69 if (index
< m_arTheirFile
.GetCount())
70 count
= (count
> m_arTheirFile
.GetAt(index
).GetLength() ? count
: m_arTheirFile
.GetAt(index
).GetLength());
71 if (index
< m_arYourFile
.GetCount())
72 count
= (count
> m_arYourFile
.GetAt(index
).GetLength() ? count
: m_arYourFile
.GetAt(index
).GetLength());
76 LPCTSTR
CDiffData::GetLineChars(int index
)
78 if (index
< m_arBaseFile
.GetCount())
79 return m_arBaseFile
.GetAt(index
);
80 if (index
< m_arTheirFile
.GetCount())
81 return m_arTheirFile
.GetAt(index
);
82 if (index
< m_arYourFile
.GetCount())
83 return m_arYourFile
.GetAt(index
);
87 BOOL
CDiffData::Load()
89 CString sConvertedBaseFilename
, sConvertedTheirFilename
, sConvertedYourFilename
;
92 apr_pool_create_ex (&pool
, NULL
, abort_on_pool_failure
, NULL
);
94 m_arBaseFile
.RemoveAll();
95 m_arYourFile
.RemoveAll();
96 m_arTheirFile
.RemoveAll();
98 m_YourBaseBoth
.Clear();
99 m_YourBaseLeft
.Clear();
100 m_YourBaseRight
.Clear();
102 m_TheirBaseBoth
.Clear();
103 m_TheirBaseLeft
.Clear();
104 m_TheirBaseRight
.Clear();
108 m_arDiff3LinesBase
.RemoveAll();
109 m_arDiff3LinesYour
.RemoveAll();
110 m_arDiff3LinesTheir
.RemoveAll();
112 CTempFiles tempfiles
;
113 CRegDWORD regIgnoreWS
= CRegDWORD(_T("Software\\TortoiseMerge\\IgnoreWS"));
114 CRegDWORD regIgnoreEOL
= CRegDWORD(_T("Software\\TortoiseMerge\\IgnoreEOL"), TRUE
);
115 CRegDWORD regIgnoreCase
= CRegDWORD(_T("Software\\TortoiseMerge\\CaseInsensitive"), FALSE
);
116 DWORD dwIgnoreWS
= regIgnoreWS
;
117 bool bIgnoreEOL
= ((DWORD
)regIgnoreEOL
)!=0;
118 BOOL bIgnoreCase
= ((DWORD
)regIgnoreCase
)!=0;
120 // The Subversion diff API only can ignore whitespaces and eol styles.
121 // It also can only handle one-byte charsets.
122 // To ignore case changes or to handle UTF-16 files, we have to
123 // save the original file in UTF-8 and/or the letters changed to lowercase
124 // so the Subversion diff can handle those.
125 sConvertedBaseFilename
= m_baseFile
.GetFilename();
126 sConvertedYourFilename
= m_yourFile
.GetFilename();
127 sConvertedTheirFilename
= m_theirFile
.GetFilename();
128 if (IsBaseFileInUse())
130 if (!m_arBaseFile
.Load(m_baseFile
.GetFilename()))
132 m_sError
= m_arBaseFile
.GetErrorString();
135 if ((bIgnoreCase
)||(m_arBaseFile
.GetUnicodeType() == CFileTextLines::UNICODE_LE
)||(m_arBaseFile
.GetUnicodeType() == CFileTextLines::UNICODE_BE
))
137 CFileTextLines
converted(m_arBaseFile
);
138 sConvertedBaseFilename
= tempfiles
.GetTempFilePath();
139 converted
.Save(sConvertedBaseFilename
, m_arBaseFile
.GetUnicodeType() == CFileTextLines::UNICODE_LE
|| m_arBaseFile
.GetUnicodeType() == CFileTextLines::UNICODE_BE
, dwIgnoreWS
, bIgnoreCase
, m_bBlame
);
143 if (IsTheirFileInUse())
145 // m_arBaseFile.GetCount() is passed as a hint for the number of lines in this file
146 // It's a fair guess that the files will be roughly the same size
147 if (!m_arTheirFile
.Load(m_theirFile
.GetFilename(),m_arBaseFile
.GetCount()))
149 m_sError
= m_arTheirFile
.GetErrorString();
152 if ((bIgnoreCase
)||(m_arTheirFile
.GetUnicodeType() == CFileTextLines::UNICODE_LE
)||(m_arTheirFile
.GetUnicodeType() == CFileTextLines::UNICODE_BE
))
154 CFileTextLines
converted(m_arTheirFile
);
155 sConvertedTheirFilename
= tempfiles
.GetTempFilePath();
156 converted
.Save(sConvertedTheirFilename
, m_arTheirFile
.GetUnicodeType() == CFileTextLines::UNICODE_LE
|| m_arTheirFile
.GetUnicodeType() == CFileTextLines::UNICODE_BE
, dwIgnoreWS
, bIgnoreCase
, m_bBlame
);
160 if (IsYourFileInUse())
162 // m_arBaseFile.GetCount() is passed as a hint for the number of lines in this file
163 // It's a fair guess that the files will be roughly the same size
164 if (!m_arYourFile
.Load(m_yourFile
.GetFilename(),m_arBaseFile
.GetCount()))
166 m_sError
= m_arYourFile
.GetErrorString();
169 if ((bIgnoreCase
)||(m_arYourFile
.GetUnicodeType() == CFileTextLines::UNICODE_LE
)||(m_arYourFile
.GetUnicodeType() == CFileTextLines::UNICODE_BE
))
171 CFileTextLines
converted(m_arYourFile
);
172 sConvertedYourFilename
= tempfiles
.GetTempFilePath();
173 converted
.Save(sConvertedYourFilename
, m_arYourFile
.GetUnicodeType() == CFileTextLines::UNICODE_LE
|| m_arYourFile
.GetUnicodeType() == CFileTextLines::UNICODE_BE
, dwIgnoreWS
, bIgnoreCase
, m_bBlame
);
177 // Calculate the number of lines in the largest of the three files
178 int lengthHint
= max(m_arBaseFile
.GetCount(), m_arTheirFile
.GetCount());
179 lengthHint
= max(lengthHint
, m_arYourFile
.GetCount());
183 m_YourBaseBoth
.Reserve(lengthHint
);
184 m_YourBaseLeft
.Reserve(lengthHint
);
185 m_YourBaseRight
.Reserve(lengthHint
);
187 m_TheirBaseBoth
.Reserve(lengthHint
);
188 m_TheirBaseLeft
.Reserve(lengthHint
);
189 m_TheirBaseRight
.Reserve(lengthHint
);
191 m_arDiff3LinesBase
.Reserve(lengthHint
);
192 m_arDiff3LinesYour
.Reserve(lengthHint
);
193 m_arDiff3LinesTheir
.Reserve(lengthHint
);
195 catch (CMemoryException
* e
)
197 e
->GetErrorMessage(m_sError
.GetBuffer(255), 255);
198 m_sError
.ReleaseBuffer();
202 // Is this a two-way diff?
203 if (IsBaseFileInUse() && IsYourFileInUse() && !IsTheirFileInUse())
205 if (!DoTwoWayDiff(sConvertedBaseFilename
, sConvertedYourFilename
, dwIgnoreWS
, bIgnoreEOL
, pool
))
207 apr_pool_destroy (pool
); // free the allocated memory
212 if (IsBaseFileInUse() && IsTheirFileInUse() && !IsYourFileInUse())
217 if (IsBaseFileInUse() && IsTheirFileInUse() && IsYourFileInUse())
219 m_Diff3
.Reserve(lengthHint
);
221 if (!DoThreeWayDiff(sConvertedBaseFilename
, sConvertedYourFilename
, sConvertedTheirFilename
, dwIgnoreWS
, bIgnoreEOL
, !!bIgnoreCase
, pool
))
223 apr_pool_destroy (pool
); // free the allocated memory
228 apr_pool_destroy (pool
); // free the allocated memory
234 CDiffData::DoTwoWayDiff(const CString
& sBaseFilename
, const CString
& sYourFilename
, DWORD dwIgnoreWS
, bool bIgnoreEOL
, apr_pool_t
* pool
)
236 // convert CString filenames (UTF-16 or ANSI) to UTF-8
237 CStringA sBaseFilenameUtf8
= CUnicodeUtils::GetUTF8(sBaseFilename
);
238 CStringA sYourFilenameUtf8
= CUnicodeUtils::GetUTF8(sYourFilename
);
240 svn_diff_t
* diffYourBase
= NULL
;
241 svn_error_t
* svnerr
= NULL
;
242 svn_diff_file_options_t
* options
= svn_diff_file_options_create(pool
);
243 options
->ignore_eol_style
= bIgnoreEOL
;
244 options
->ignore_space
= svn_diff_file_ignore_space_none
;
248 options
->ignore_space
= svn_diff_file_ignore_space_none
;
251 options
->ignore_space
= svn_diff_file_ignore_space_all
;
254 options
->ignore_space
= svn_diff_file_ignore_space_change
;
258 svnerr
= svn_diff_file_diff_2(&diffYourBase
, sBaseFilenameUtf8
, sYourFilenameUtf8
, options
, pool
);
261 TRACE(_T("diff-error in CDiffData::Load()\n"));
262 CStringA sMsg
= CStringA(svnerr
->message
);
263 while (svnerr
->child
)
265 svnerr
= svnerr
->child
;
267 sMsg
+= CStringA(svnerr
->message
);
269 CString readableMsg
= CUnicodeUtils::GetUnicode(sMsg
);
270 m_sError
.Format(IDS_ERR_DIFF_DIFF
, (LPCTSTR
)readableMsg
);
271 svn_error_clear(svnerr
);
274 svn_diff_t
* tempdiff
= diffYourBase
;
280 for (int i
=0; i
<tempdiff
->original_length
; i
++)
282 if (baseline
>= m_arBaseFile
.GetCount())
284 m_sError
.LoadString(IDS_ERR_DIFF_NEWLINES
);
287 const CString
& sCurrentBaseLine
= m_arBaseFile
.GetAt(baseline
);
288 EOL endingBase
= m_arBaseFile
.GetLineEnding(baseline
);
289 if (tempdiff
->type
== svn_diff__type_common
)
291 if (yourline
>= m_arYourFile
.GetCount())
293 m_sError
.LoadString(IDS_ERR_DIFF_NEWLINES
);
296 const CString
& sCurrentYourLine
= m_arYourFile
.GetAt(yourline
);
297 EOL endingYours
= m_arYourFile
.GetLineEnding(yourline
);
298 if (sCurrentBaseLine
!= sCurrentYourLine
)
300 if (dwIgnoreWS
== 2 || dwIgnoreWS
== 3)
302 CString s1
= m_arBaseFile
.GetAt(baseline
);
303 CString s2
= sCurrentYourLine
;
305 if ( dwIgnoreWS
== 2 )
307 s1
.TrimLeft(_T(" \t"));
308 s2
.TrimLeft(_T(" \t"));
312 s1
.TrimRight(_T(" \t"));
313 s2
.TrimRight(_T(" \t"));
318 // one-pane view: two lines, one 'removed' and one 'added'
319 m_YourBaseBoth
.AddData(sCurrentBaseLine
, DIFFSTATE_REMOVEDWHITESPACE
, yourline
, endingBase
);
320 m_YourBaseBoth
.AddData(sCurrentYourLine
, DIFFSTATE_ADDEDWHITESPACE
, yourline
, endingYours
);
324 m_YourBaseBoth
.AddData(sCurrentBaseLine
, DIFFSTATE_NORMAL
, yourline
, endingBase
);
327 else if (dwIgnoreWS
== 0)
329 m_YourBaseBoth
.AddData(sCurrentBaseLine
, DIFFSTATE_REMOVEDWHITESPACE
, yourline
, endingBase
);
330 m_YourBaseBoth
.AddData(sCurrentYourLine
, DIFFSTATE_ADDEDWHITESPACE
, yourline
, endingYours
);
334 m_YourBaseBoth
.AddData(sCurrentBaseLine
, DIFFSTATE_NORMAL
, yourline
, endingBase
);
339 m_YourBaseBoth
.AddData(sCurrentBaseLine
, DIFFSTATE_NORMAL
, yourline
, endingBase
);
341 yourline
++; //in both files
345 m_YourBaseBoth
.AddData(sCurrentBaseLine
, DIFFSTATE_REMOVED
, yourline
, endingBase
);
349 if (tempdiff
->type
== svn_diff__type_diff_modified
)
351 for (int i
=0; i
<tempdiff
->modified_length
; i
++)
353 if (m_arYourFile
.GetCount() > yourline
)
355 m_YourBaseBoth
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_ADDED
, yourline
, m_arYourFile
.GetLineEnding(yourline
));
360 tempdiff
= tempdiff
->next
;
363 tempdiff
= diffYourBase
;
368 if (tempdiff
->type
== svn_diff__type_common
)
370 for (int i
=0; i
<tempdiff
->original_length
; i
++)
372 const CString
& sCurrentYourLine
= m_arYourFile
.GetAt(yourline
);
373 EOL endingYours
= m_arYourFile
.GetLineEnding(yourline
);
374 const CString
& sCurrentBaseLine
= m_arBaseFile
.GetAt(baseline
);
375 EOL endingBase
= m_arBaseFile
.GetLineEnding(baseline
);
376 if (sCurrentBaseLine
!= sCurrentYourLine
)
378 if (dwIgnoreWS
== 2 || dwIgnoreWS
== 3)
380 CString s1
= sCurrentBaseLine
;
381 CString s2
= sCurrentYourLine
;
382 if ( dwIgnoreWS
== 2 )
384 s1
= s1
.TrimLeft(_T(" \t"));
385 s2
= s2
.TrimLeft(_T(" \t"));
389 s1
= s1
.TrimRight(_T(" \t"));
390 s2
= s2
.TrimRight(_T(" \t"));
395 m_YourBaseLeft
.AddData(sCurrentBaseLine
, DIFFSTATE_WHITESPACE
, baseline
, endingBase
);
396 m_YourBaseRight
.AddData(sCurrentYourLine
, DIFFSTATE_WHITESPACE
, yourline
, endingYours
);
400 m_YourBaseLeft
.AddData(sCurrentBaseLine
, DIFFSTATE_NORMAL
, baseline
, endingBase
);
401 m_YourBaseRight
.AddData(sCurrentYourLine
, DIFFSTATE_NORMAL
, yourline
, endingYours
);
404 else if (dwIgnoreWS
== 0)
406 m_YourBaseLeft
.AddData(sCurrentBaseLine
, DIFFSTATE_WHITESPACE
, baseline
, endingBase
);
407 m_YourBaseRight
.AddData(sCurrentYourLine
, DIFFSTATE_WHITESPACE
, yourline
, endingYours
);
411 m_YourBaseLeft
.AddData(sCurrentBaseLine
, DIFFSTATE_NORMAL
, baseline
, endingBase
);
412 m_YourBaseRight
.AddData(sCurrentYourLine
, DIFFSTATE_NORMAL
, yourline
, endingYours
);
417 m_YourBaseLeft
.AddData(sCurrentBaseLine
, DIFFSTATE_NORMAL
, baseline
, endingBase
);
418 m_YourBaseRight
.AddData(sCurrentYourLine
, DIFFSTATE_NORMAL
, yourline
, endingYours
);
424 if (tempdiff
->type
== svn_diff__type_diff_modified
)
426 apr_off_t original_length
= tempdiff
->original_length
;
427 for (int i
=0; i
<tempdiff
->modified_length
; i
++)
429 if (m_arYourFile
.GetCount() > yourline
)
431 EOL endingYours
= m_arYourFile
.GetLineEnding(yourline
);
432 if (original_length
-- <= 0)
434 m_YourBaseLeft
.AddData(_T(""), DIFFSTATE_EMPTY
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
435 m_YourBaseRight
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_ADDED
, yourline
, endingYours
);
439 EOL endingBase
= m_arBaseFile
.GetLineEnding(baseline
);
440 m_YourBaseLeft
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_REMOVED
, baseline
, endingBase
);
441 m_YourBaseRight
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_ADDED
, yourline
, endingYours
);
447 apr_off_t modified_length
= tempdiff
->modified_length
;
448 for (int i
=0; i
<tempdiff
->original_length
; i
++)
450 if (modified_length
-- <= 0)
452 if (m_arBaseFile
.GetCount() > baseline
)
454 EOL endingBase
= m_arBaseFile
.GetLineEnding(baseline
);
455 m_YourBaseLeft
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_REMOVED
, baseline
, endingBase
);
456 m_YourBaseRight
.AddData(_T(""), DIFFSTATE_EMPTY
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
462 tempdiff
= tempdiff
->next
;
464 TRACE(_T("done with 2-way diff\n"));
470 CDiffData::DoThreeWayDiff(const CString
& sBaseFilename
, const CString
& sYourFilename
, const CString
& sTheirFilename
, DWORD dwIgnoreWS
, bool bIgnoreEOL
, bool bIgnoreCase
, apr_pool_t
* pool
)
472 // convert CString filenames (UTF-16 or ANSI) to UTF-8
473 CStringA sBaseFilenameUtf8
= CUnicodeUtils::GetUTF8(sBaseFilename
);
474 CStringA sYourFilenameUtf8
= CUnicodeUtils::GetUTF8(sYourFilename
);
475 CStringA sTheirFilenameUtf8
= CUnicodeUtils::GetUTF8(sTheirFilename
);
476 svn_diff_t
* diffTheirYourBase
= NULL
;
477 svn_diff_file_options_t
* options
= svn_diff_file_options_create(pool
);
478 options
->ignore_eol_style
= bIgnoreEOL
;
479 options
->ignore_space
= svn_diff_file_ignore_space_none
;
483 options
->ignore_space
= svn_diff_file_ignore_space_none
;
486 options
->ignore_space
= svn_diff_file_ignore_space_all
;
489 options
->ignore_space
= svn_diff_file_ignore_space_change
;
492 svn_error_t
* svnerr
= svn_diff_file_diff3_2(&diffTheirYourBase
, sBaseFilenameUtf8
, sTheirFilenameUtf8
, sYourFilenameUtf8
, options
, pool
);
495 TRACE(_T("diff-error in CDiffData::Load()\n"));
496 CStringA sMsg
= CStringA(svnerr
->message
);
497 while (svnerr
->child
)
499 svnerr
= svnerr
->child
;
501 sMsg
+= CStringA(svnerr
->message
);
503 CString readableMsg
= CUnicodeUtils::GetUnicode(sMsg
);
504 m_sError
.Format(IDS_ERR_DIFF_DIFF
, (LPCTSTR
)readableMsg
);
505 svn_error_clear(svnerr
);
509 svn_diff_t
* tempdiff
= diffTheirYourBase
;
516 if (tempdiff
->type
== svn_diff__type_common
)
518 ASSERT((tempdiff
->latest_length
== tempdiff
->modified_length
) && (tempdiff
->modified_length
== tempdiff
->original_length
));
519 for (int i
=0; i
<tempdiff
->original_length
; i
++)
521 if ((m_arYourFile
.GetCount() > yourline
)&&(m_arTheirFile
.GetCount() > theirline
))
523 m_Diff3
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_NORMAL
, resline
, m_arYourFile
.GetLineEnding(yourline
));
525 m_arDiff3LinesBase
.Add(baseline
);
526 m_arDiff3LinesYour
.Add(yourline
);
527 m_arDiff3LinesTheir
.Add(theirline
);
529 m_YourBaseBoth
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_NORMAL
, yourline
, m_arYourFile
.GetLineEnding(yourline
));
530 m_TheirBaseBoth
.AddData(m_arTheirFile
.GetAt(theirline
), DIFFSTATE_NORMAL
, theirline
, m_arTheirFile
.GetLineEnding(theirline
));
539 else if (tempdiff
->type
== svn_diff__type_diff_common
)
541 ASSERT(tempdiff
->latest_length
== tempdiff
->modified_length
);
542 //both theirs and yours have lines replaced
543 for (int i
=0; i
<tempdiff
->original_length
; i
++)
545 if (m_arBaseFile
.GetCount() > baseline
)
547 m_Diff3
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, m_arBaseFile
.GetLineEnding(baseline
));
549 m_arDiff3LinesBase
.Add(baseline
);
550 m_arDiff3LinesYour
.Add(yourline
);
551 m_arDiff3LinesTheir
.Add(theirline
);
553 m_YourBaseBoth
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
554 m_TheirBaseBoth
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
559 for (int i
=0; i
<tempdiff
->modified_length
; i
++)
561 if ((m_arYourFile
.GetCount() > yourline
)&&(m_arTheirFile
.GetCount() > theirline
))
563 m_Diff3
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_IDENTICALADDED
, resline
, m_arYourFile
.GetLineEnding(yourline
));
565 m_arDiff3LinesBase
.Add(baseline
);
566 m_arDiff3LinesYour
.Add(yourline
);
567 m_arDiff3LinesTheir
.Add(theirline
);
569 m_YourBaseBoth
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_IDENTICALADDED
, yourline
, m_arYourFile
.GetLineEnding(yourline
));
570 m_TheirBaseBoth
.AddData(m_arTheirFile
.GetAt(theirline
), DIFFSTATE_IDENTICALADDED
, resline
, m_arTheirFile
.GetLineEnding(theirline
));
578 else if (tempdiff
->type
== svn_diff__type_conflict
)
580 apr_off_t length
= max(tempdiff
->original_length
, tempdiff
->modified_length
);
581 length
= max(tempdiff
->latest_length
, length
);
582 apr_off_t original
= tempdiff
->original_length
;
583 apr_off_t modified
= tempdiff
->modified_length
;
584 apr_off_t latest
= tempdiff
->latest_length
;
586 apr_off_t originalresolved
= 0;
587 apr_off_t modifiedresolved
= 0;
588 apr_off_t latestresolved
= 0;
590 LONG base
= baseline
;
591 LONG your
= yourline
;
592 LONG their
= theirline
;
593 if (tempdiff
->resolved_diff
)
595 originalresolved
= tempdiff
->resolved_diff
->original_length
;
596 modifiedresolved
= tempdiff
->resolved_diff
->modified_length
;
597 latestresolved
= tempdiff
->resolved_diff
->latest_length
;
599 for (int i
=0; i
<length
; i
++)
603 if (m_arBaseFile
.GetCount() > baseline
)
605 m_Diff3
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, m_arBaseFile
.GetLineEnding(baseline
));
607 m_arDiff3LinesBase
.Add(baseline
);
608 m_arDiff3LinesYour
.Add(yourline
);
609 m_arDiff3LinesTheir
.Add(theirline
);
612 else if ((originalresolved
)||((modifiedresolved
)&&(latestresolved
)))
614 m_Diff3
.AddData(_T(""), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
616 m_arDiff3LinesBase
.Add(baseline
);
617 m_arDiff3LinesYour
.Add(yourline
);
618 m_arDiff3LinesTheir
.Add(theirline
);
621 if ((latest
)&&(original
))
623 if (m_arBaseFile
.GetCount() > baseline
)
625 m_YourBaseBoth
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, m_arBaseFile
.GetLineEnding(baseline
));
632 if (m_arBaseFile
.GetCount() > baseline
)
634 m_YourBaseBoth
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, m_arBaseFile
.GetLineEnding(baseline
));
637 else if ((latestresolved
)&&(modifiedresolved
))
639 m_YourBaseBoth
.AddData(_T(""), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
642 if ((modified
)&&(original
))
644 if (m_arBaseFile
.GetCount() > baseline
)
646 m_TheirBaseBoth
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, m_arBaseFile
.GetLineEnding(baseline
));
653 if (m_arBaseFile
.GetCount() > baseline
)
655 m_TheirBaseBoth
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, m_arBaseFile
.GetLineEnding(baseline
));
658 else if ((modifiedresolved
)&&(latestresolved
))
660 m_TheirBaseBoth
.AddData(_T(""), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
668 if (originalresolved
)
676 if (modifiedresolved
)
686 original
= tempdiff
->original_length
;
687 modified
= tempdiff
->modified_length
;
688 latest
= tempdiff
->latest_length
;
692 if (tempdiff
->resolved_diff
)
694 originalresolved
= tempdiff
->resolved_diff
->original_length
;
695 modifiedresolved
= tempdiff
->resolved_diff
->modified_length
;
696 latestresolved
= tempdiff
->resolved_diff
->latest_length
;
698 for (int i
=0; i
<length
; i
++)
700 if ((latest
)||(modified
))
702 m_Diff3
.AddData(_T(""), DIFFSTATE_CONFLICTED
, resline
, EOL_NOENDING
);
704 m_arDiff3LinesBase
.Add(baseline
);
705 m_arDiff3LinesYour
.Add(yourline
);
706 m_arDiff3LinesTheir
.Add(theirline
);
713 if (m_arYourFile
.GetCount() > yourline
)
715 m_YourBaseBoth
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_CONFLICTADDED
, yourline
, m_arYourFile
.GetLineEnding(yourline
));
718 else if ((latestresolved
)||(modified
)||(modifiedresolved
))
720 m_YourBaseBoth
.AddData(_T(""), DIFFSTATE_CONFLICTEMPTY
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
724 if (m_arTheirFile
.GetCount() > theirline
)
726 m_TheirBaseBoth
.AddData(m_arTheirFile
.GetAt(theirline
), DIFFSTATE_CONFLICTADDED
, theirline
, m_arTheirFile
.GetLineEnding(theirline
));
729 else if ((modifiedresolved
)||(latest
)||(latestresolved
))
731 m_TheirBaseBoth
.AddData(_T(""), DIFFSTATE_CONFLICTEMPTY
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
738 if (originalresolved
)
745 if (modifiedresolved
)
756 else if (tempdiff
->type
== svn_diff__type_diff_modified
)
759 for (int i
=0; i
<tempdiff
->original_length
; i
++)
761 if ((m_arBaseFile
.GetCount() > baseline
)&&(m_arYourFile
.GetCount() > yourline
))
763 m_Diff3
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_THEIRSREMOVED
, DIFF_EMPTYLINENUMBER
, m_arBaseFile
.GetLineEnding(baseline
));
765 m_arDiff3LinesBase
.Add(baseline
);
766 m_arDiff3LinesYour
.Add(yourline
);
767 m_arDiff3LinesTheir
.Add(theirline
);
769 m_YourBaseBoth
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_NORMAL
, yourline
, m_arYourFile
.GetLineEnding(yourline
));
770 m_TheirBaseBoth
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_THEIRSREMOVED
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
776 for (int i
=0; i
<tempdiff
->modified_length
; i
++)
778 if (m_arTheirFile
.GetCount() > theirline
)
780 m_Diff3
.AddData(m_arTheirFile
.GetAt(theirline
), DIFFSTATE_THEIRSADDED
, resline
, m_arTheirFile
.GetLineEnding(theirline
));
782 m_arDiff3LinesBase
.Add(baseline
);
783 m_arDiff3LinesYour
.Add(yourline
);
784 m_arDiff3LinesTheir
.Add(theirline
);
786 m_YourBaseBoth
.AddData(_T(""), DIFFSTATE_EMPTY
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
787 m_TheirBaseBoth
.AddData(m_arTheirFile
.GetAt(theirline
), DIFFSTATE_THEIRSADDED
, theirline
, m_arTheirFile
.GetLineEnding(theirline
));
794 else if (tempdiff
->type
== svn_diff__type_diff_latest
)
796 //YOURS differs from base
798 for (int i
=0; i
<tempdiff
->original_length
; i
++)
800 if ((m_arBaseFile
.GetCount() > baseline
)&&(m_arTheirFile
.GetCount() > theirline
))
802 m_Diff3
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_YOURSREMOVED
, DIFF_EMPTYLINENUMBER
, m_arBaseFile
.GetLineEnding(baseline
));
804 m_arDiff3LinesBase
.Add(baseline
);
805 m_arDiff3LinesYour
.Add(yourline
);
806 m_arDiff3LinesTheir
.Add(theirline
);
808 m_YourBaseBoth
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_YOURSREMOVED
, DIFF_EMPTYLINENUMBER
, m_arBaseFile
.GetLineEnding(baseline
));
809 m_TheirBaseBoth
.AddData(m_arTheirFile
.GetAt(theirline
), DIFFSTATE_NORMAL
, theirline
, m_arTheirFile
.GetLineEnding(theirline
));
815 for (int i
=0; i
<tempdiff
->latest_length
; i
++)
817 if (m_arYourFile
.GetCount() > yourline
)
819 m_Diff3
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_YOURSADDED
, resline
, m_arYourFile
.GetLineEnding(yourline
));
821 m_arDiff3LinesBase
.Add(baseline
);
822 m_arDiff3LinesYour
.Add(yourline
);
823 m_arDiff3LinesTheir
.Add(theirline
);
825 m_YourBaseBoth
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_IDENTICALADDED
, yourline
, m_arYourFile
.GetLineEnding(yourline
));
826 m_TheirBaseBoth
.AddData(_T(""), DIFFSTATE_EMPTY
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
835 TRACE(_T("something bad happened during diff!\n"));
837 tempdiff
= tempdiff
->next
;
839 } // while (tempdiff)
841 if ((options
->ignore_space
!= svn_diff_file_ignore_space_none
)||(bIgnoreCase
)||(bIgnoreEOL
))
843 // If whitespaces are ignored, a conflict could have been missed
844 // We now go through all lines again and check if they're identical.
845 // If they're not, then that means it is a conflict, and we
846 // mark the conflict with the proper colors.
847 for (long i
=0; i
<m_Diff3
.GetCount(); ++i
)
849 DiffStates state1
= m_YourBaseBoth
.GetState(i
);
850 DiffStates state2
= m_TheirBaseBoth
.GetState(i
);
852 if (((state1
== DIFFSTATE_IDENTICALADDED
)||(state1
== DIFFSTATE_NORMAL
))&&
853 ((state2
== DIFFSTATE_IDENTICALADDED
)||(state2
== DIFFSTATE_NORMAL
)))
855 LONG lineyour
= m_arDiff3LinesYour
.GetAt(i
);
856 LONG linetheir
= m_arDiff3LinesTheir
.GetAt(i
);
857 LONG linebase
= m_arDiff3LinesBase
.GetAt(i
);
858 if ((lineyour
< m_arYourFile
.GetCount()) &&
859 (linetheir
< m_arTheirFile
.GetCount()) &&
860 (linebase
< m_arBaseFile
.GetCount()))
862 if (((m_arYourFile
.GetLineEnding(lineyour
)!=m_arBaseFile
.GetLineEnding(linebase
))&&
863 (m_arTheirFile
.GetLineEnding(linetheir
)!=m_arBaseFile
.GetLineEnding(linebase
))&&
864 (m_arYourFile
.GetLineEnding(lineyour
)!=m_arTheirFile
.GetLineEnding(linetheir
))) ||
865 ((m_arYourFile
.GetAt(lineyour
).Compare(m_arBaseFile
.GetAt(linebase
))!=0)&&
866 (m_arTheirFile
.GetAt(linetheir
).Compare(m_arBaseFile
.GetAt(linebase
))!=0)&&
867 (m_arYourFile
.GetAt(lineyour
).Compare(m_arTheirFile
.GetAt(linetheir
))!=0)))
869 m_Diff3
.SetState(i
, DIFFSTATE_CONFLICTED_IGNORED
);
870 m_YourBaseBoth
.SetState(i
, DIFFSTATE_CONFLICTADDED
);
871 m_TheirBaseBoth
.SetState(i
, DIFFSTATE_CONFLICTADDED
);
877 ASSERT(m_Diff3
.GetCount() == m_YourBaseBoth
.GetCount());
878 ASSERT(m_TheirBaseBoth
.GetCount() == m_YourBaseBoth
.GetCount());
880 TRACE(_T("done with 3-way diff\n"));