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)
43 svn_dso_initialize2();
48 m_sPatchOriginal
= _T(": original");
49 m_sPatchPatched
= _T(": patched");
52 CDiffData::~CDiffData(void)
54 g_GitAdminDir
.Close();
58 int CDiffData::GetLineCount()
61 count
= (int)m_arBaseFile
.GetCount();
62 count
= (int)(count
> m_arTheirFile
.GetCount() ? count
: m_arTheirFile
.GetCount());
63 count
= (int)(count
> m_arYourFile
.GetCount() ? count
: m_arYourFile
.GetCount());
67 int CDiffData::GetLineActualLength(int index
)
70 if (index
< m_arBaseFile
.GetCount())
71 count
= (count
> m_arBaseFile
.GetAt(index
).GetLength() ? count
: m_arBaseFile
.GetAt(index
).GetLength());
72 if (index
< m_arTheirFile
.GetCount())
73 count
= (count
> m_arTheirFile
.GetAt(index
).GetLength() ? count
: m_arTheirFile
.GetAt(index
).GetLength());
74 if (index
< m_arYourFile
.GetCount())
75 count
= (count
> m_arYourFile
.GetAt(index
).GetLength() ? count
: m_arYourFile
.GetAt(index
).GetLength());
79 LPCTSTR
CDiffData::GetLineChars(int index
)
81 if (index
< m_arBaseFile
.GetCount())
82 return m_arBaseFile
.GetAt(index
);
83 if (index
< m_arTheirFile
.GetCount())
84 return m_arTheirFile
.GetAt(index
);
85 if (index
< m_arYourFile
.GetCount())
86 return m_arYourFile
.GetAt(index
);
90 BOOL
CDiffData::Load()
92 CString sConvertedBaseFilename
, sConvertedTheirFilename
, sConvertedYourFilename
;
95 apr_pool_create_ex (&pool
, NULL
, abort_on_pool_failure
, NULL
);
97 m_arBaseFile
.RemoveAll();
98 m_arYourFile
.RemoveAll();
99 m_arTheirFile
.RemoveAll();
101 m_YourBaseBoth
.Clear();
102 m_YourBaseLeft
.Clear();
103 m_YourBaseRight
.Clear();
105 m_TheirBaseBoth
.Clear();
106 m_TheirBaseLeft
.Clear();
107 m_TheirBaseRight
.Clear();
111 m_arDiff3LinesBase
.RemoveAll();
112 m_arDiff3LinesYour
.RemoveAll();
113 m_arDiff3LinesTheir
.RemoveAll();
115 CTempFiles tempfiles
;
116 CRegDWORD regIgnoreWS
= CRegDWORD(_T("Software\\TortoiseMerge\\IgnoreWS"));
117 CRegDWORD regIgnoreEOL
= CRegDWORD(_T("Software\\TortoiseMerge\\IgnoreEOL"), TRUE
);
118 CRegDWORD regIgnoreCase
= CRegDWORD(_T("Software\\TortoiseMerge\\CaseInsensitive"), FALSE
);
119 DWORD dwIgnoreWS
= regIgnoreWS
;
120 bool bIgnoreEOL
= ((DWORD
)regIgnoreEOL
)!=0;
121 BOOL bIgnoreCase
= ((DWORD
)regIgnoreCase
)!=0;
123 // The Subversion diff API only can ignore whitespaces and eol styles.
124 // It also can only handle one-byte charsets.
125 // To ignore case changes or to handle UTF-16 files, we have to
126 // save the original file in UTF-8 and/or the letters changed to lowercase
127 // so the Subversion diff can handle those.
128 sConvertedBaseFilename
= m_baseFile
.GetFilename();
129 sConvertedYourFilename
= m_yourFile
.GetFilename();
130 sConvertedTheirFilename
= m_theirFile
.GetFilename();
131 if (IsBaseFileInUse())
133 if (!m_arBaseFile
.Load(m_baseFile
.GetFilename()))
135 m_sError
= m_arBaseFile
.GetErrorString();
138 if ((bIgnoreCase
)||(m_arBaseFile
.GetUnicodeType() == CFileTextLines::UNICODE_LE
))
140 CFileTextLines
converted(m_arBaseFile
);
141 sConvertedBaseFilename
= tempfiles
.GetTempFilePath();
142 converted
.Save(sConvertedBaseFilename
, m_arBaseFile
.GetUnicodeType() == CFileTextLines::UNICODE_LE
, dwIgnoreWS
, bIgnoreCase
, m_bBlame
);
146 if (IsTheirFileInUse())
148 // m_arBaseFile.GetCount() is passed as a hint for the number of lines in this file
149 // It's a fair guess that the files will be roughly the same size
150 if (!m_arTheirFile
.Load(m_theirFile
.GetFilename(),m_arBaseFile
.GetCount()))
152 m_sError
= m_arTheirFile
.GetErrorString();
155 if ((bIgnoreCase
)||(m_arTheirFile
.GetUnicodeType() == CFileTextLines::UNICODE_LE
))
157 CFileTextLines
converted(m_arTheirFile
);
158 sConvertedTheirFilename
= tempfiles
.GetTempFilePath();
159 converted
.Save(sConvertedTheirFilename
, m_arTheirFile
.GetUnicodeType() == CFileTextLines::UNICODE_LE
, dwIgnoreWS
, bIgnoreCase
, m_bBlame
);
163 if (IsYourFileInUse())
165 // m_arBaseFile.GetCount() is passed as a hint for the number of lines in this file
166 // It's a fair guess that the files will be roughly the same size
167 if (!m_arYourFile
.Load(m_yourFile
.GetFilename(),m_arBaseFile
.GetCount()))
169 m_sError
= m_arYourFile
.GetErrorString();
172 if ((bIgnoreCase
)||(m_arYourFile
.GetUnicodeType() == CFileTextLines::UNICODE_LE
))
174 CFileTextLines
converted(m_arYourFile
);
175 sConvertedYourFilename
= tempfiles
.GetTempFilePath();
176 converted
.Save(sConvertedYourFilename
, m_arYourFile
.GetUnicodeType() == CFileTextLines::UNICODE_LE
, dwIgnoreWS
, bIgnoreCase
, m_bBlame
);
180 // Calculate the number of lines in the largest of the three files
181 int lengthHint
= max(m_arBaseFile
.GetCount(), m_arTheirFile
.GetCount());
182 lengthHint
= max(lengthHint
, m_arYourFile
.GetCount());
186 m_YourBaseBoth
.Reserve(lengthHint
);
187 m_YourBaseLeft
.Reserve(lengthHint
);
188 m_YourBaseRight
.Reserve(lengthHint
);
190 m_TheirBaseBoth
.Reserve(lengthHint
);
191 m_TheirBaseLeft
.Reserve(lengthHint
);
192 m_TheirBaseRight
.Reserve(lengthHint
);
194 m_arDiff3LinesBase
.Reserve(lengthHint
);
195 m_arDiff3LinesYour
.Reserve(lengthHint
);
196 m_arDiff3LinesTheir
.Reserve(lengthHint
);
198 catch (CMemoryException
* e
)
200 e
->GetErrorMessage(m_sError
.GetBuffer(255), 255);
201 m_sError
.ReleaseBuffer();
205 // Is this a two-way diff?
206 if (IsBaseFileInUse() && IsYourFileInUse() && !IsTheirFileInUse())
208 if (!DoTwoWayDiff(sConvertedBaseFilename
, sConvertedYourFilename
, dwIgnoreWS
, bIgnoreEOL
, pool
))
210 apr_pool_destroy (pool
); // free the allocated memory
215 if (IsBaseFileInUse() && IsTheirFileInUse() && !IsYourFileInUse())
220 if (IsBaseFileInUse() && IsTheirFileInUse() && IsYourFileInUse())
222 m_Diff3
.Reserve(lengthHint
);
224 if (!DoThreeWayDiff(sConvertedBaseFilename
, sConvertedYourFilename
, sConvertedTheirFilename
, dwIgnoreWS
, bIgnoreEOL
, !!bIgnoreCase
, pool
))
226 apr_pool_destroy (pool
); // free the allocated memory
231 apr_pool_destroy (pool
); // free the allocated memory
237 CDiffData::DoTwoWayDiff(const CString
& sBaseFilename
, const CString
& sYourFilename
, DWORD dwIgnoreWS
, bool bIgnoreEOL
, apr_pool_t
* pool
)
239 // convert CString filenames (UTF-16 or ANSI) to UTF-8
240 CStringA sBaseFilenameUtf8
= CUnicodeUtils::GetUTF8(sBaseFilename
);
241 CStringA sYourFilenameUtf8
= CUnicodeUtils::GetUTF8(sYourFilename
);
243 svn_diff_t
* diffYourBase
= NULL
;
244 svn_error_t
* svnerr
= NULL
;
245 svn_diff_file_options_t
* options
= svn_diff_file_options_create(pool
);
246 options
->ignore_eol_style
= bIgnoreEOL
;
247 options
->ignore_space
= svn_diff_file_ignore_space_none
;
251 options
->ignore_space
= svn_diff_file_ignore_space_none
;
254 options
->ignore_space
= svn_diff_file_ignore_space_all
;
257 options
->ignore_space
= svn_diff_file_ignore_space_change
;
261 svnerr
= svn_diff_file_diff_2(&diffYourBase
, sBaseFilenameUtf8
, sYourFilenameUtf8
, options
, pool
);
264 TRACE(_T("diff-error in CDiffData::Load()\n"));
265 CString sMsg
= CString(svnerr
->message
);
266 while (svnerr
->child
)
268 svnerr
= svnerr
->child
;
270 sMsg
+= CString(svnerr
->message
);
272 m_sError
.Format(IDS_ERR_DIFF_DIFF
, (LPCTSTR
)sMsg
);
273 svn_error_clear(svnerr
);
276 svn_diff_t
* tempdiff
= diffYourBase
;
282 for (int i
=0; i
<tempdiff
->original_length
; i
++)
284 if (baseline
>= m_arBaseFile
.GetCount())
286 m_sError
.LoadString(IDS_ERR_DIFF_NEWLINES
);
289 const CString
& sCurrentBaseLine
= m_arBaseFile
.GetAt(baseline
);
290 EOL endingBase
= m_arBaseFile
.GetLineEnding(baseline
);
291 if (tempdiff
->type
== svn_diff__type_common
)
293 if (yourline
>= m_arYourFile
.GetCount())
295 m_sError
.LoadString(IDS_ERR_DIFF_NEWLINES
);
298 const CString
& sCurrentYourLine
= m_arYourFile
.GetAt(yourline
);
299 EOL endingYours
= m_arYourFile
.GetLineEnding(yourline
);
300 if (sCurrentBaseLine
!= sCurrentYourLine
)
302 if (dwIgnoreWS
== 2 || dwIgnoreWS
== 3)
304 CString s1
= m_arBaseFile
.GetAt(baseline
);
305 CString s2
= sCurrentYourLine
;
307 if ( dwIgnoreWS
== 2 )
309 s1
.TrimLeft(_T(" \t"));
310 s2
.TrimLeft(_T(" \t"));
314 s1
.TrimRight(_T(" \t"));
315 s2
.TrimRight(_T(" \t"));
320 // one-pane view: two lines, one 'removed' and one 'added'
321 m_YourBaseBoth
.AddData(sCurrentBaseLine
, DIFFSTATE_REMOVEDWHITESPACE
, yourline
, endingBase
);
322 m_YourBaseBoth
.AddData(sCurrentYourLine
, DIFFSTATE_ADDEDWHITESPACE
, yourline
, endingYours
);
326 m_YourBaseBoth
.AddData(sCurrentBaseLine
, DIFFSTATE_NORMAL
, yourline
, endingBase
);
329 else if (dwIgnoreWS
== 0)
331 m_YourBaseBoth
.AddData(sCurrentBaseLine
, DIFFSTATE_REMOVEDWHITESPACE
, yourline
, endingBase
);
332 m_YourBaseBoth
.AddData(sCurrentYourLine
, DIFFSTATE_ADDEDWHITESPACE
, yourline
, endingYours
);
336 m_YourBaseBoth
.AddData(sCurrentBaseLine
, DIFFSTATE_NORMAL
, yourline
, endingBase
);
341 m_YourBaseBoth
.AddData(sCurrentBaseLine
, DIFFSTATE_NORMAL
, yourline
, endingBase
);
343 yourline
++; //in both files
347 m_YourBaseBoth
.AddData(sCurrentBaseLine
, DIFFSTATE_REMOVED
, yourline
, endingBase
);
351 if (tempdiff
->type
== svn_diff__type_diff_modified
)
353 for (int i
=0; i
<tempdiff
->modified_length
; i
++)
355 if (m_arYourFile
.GetCount() > yourline
)
357 m_YourBaseBoth
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_ADDED
, yourline
, m_arYourFile
.GetLineEnding(yourline
));
362 tempdiff
= tempdiff
->next
;
365 tempdiff
= diffYourBase
;
370 if (tempdiff
->type
== svn_diff__type_common
)
372 for (int i
=0; i
<tempdiff
->original_length
; i
++)
374 const CString
& sCurrentYourLine
= m_arYourFile
.GetAt(yourline
);
375 EOL endingYours
= m_arYourFile
.GetLineEnding(yourline
);
376 const CString
& sCurrentBaseLine
= m_arBaseFile
.GetAt(baseline
);
377 EOL endingBase
= m_arBaseFile
.GetLineEnding(baseline
);
378 if (sCurrentBaseLine
!= sCurrentYourLine
)
380 if (dwIgnoreWS
== 2 || dwIgnoreWS
== 3)
382 CString s1
= sCurrentBaseLine
;
383 CString s2
= sCurrentYourLine
;
384 if ( dwIgnoreWS
== 2 )
386 s1
= s1
.TrimLeft(_T(" \t"));
387 s2
= s2
.TrimLeft(_T(" \t"));
391 s1
= s1
.TrimRight(_T(" \t"));
392 s2
= s2
.TrimRight(_T(" \t"));
397 m_YourBaseLeft
.AddData(sCurrentBaseLine
, DIFFSTATE_WHITESPACE
, baseline
, endingBase
);
398 m_YourBaseRight
.AddData(sCurrentYourLine
, DIFFSTATE_WHITESPACE
, yourline
, endingYours
);
402 m_YourBaseLeft
.AddData(sCurrentBaseLine
, DIFFSTATE_NORMAL
, baseline
, endingBase
);
403 m_YourBaseRight
.AddData(sCurrentYourLine
, DIFFSTATE_NORMAL
, yourline
, endingYours
);
406 else if (dwIgnoreWS
== 0)
408 m_YourBaseLeft
.AddData(sCurrentBaseLine
, DIFFSTATE_WHITESPACE
, baseline
, endingBase
);
409 m_YourBaseRight
.AddData(sCurrentYourLine
, DIFFSTATE_WHITESPACE
, yourline
, endingYours
);
413 m_YourBaseLeft
.AddData(sCurrentBaseLine
, DIFFSTATE_NORMAL
, baseline
, endingBase
);
414 m_YourBaseRight
.AddData(sCurrentYourLine
, DIFFSTATE_NORMAL
, yourline
, endingYours
);
419 m_YourBaseLeft
.AddData(sCurrentBaseLine
, DIFFSTATE_NORMAL
, baseline
, endingBase
);
420 m_YourBaseRight
.AddData(sCurrentYourLine
, DIFFSTATE_NORMAL
, yourline
, endingYours
);
426 if (tempdiff
->type
== svn_diff__type_diff_modified
)
428 apr_off_t original_length
= tempdiff
->original_length
;
429 for (int i
=0; i
<tempdiff
->modified_length
; i
++)
431 if (m_arYourFile
.GetCount() > yourline
)
433 EOL endingYours
= m_arYourFile
.GetLineEnding(yourline
);
434 if (original_length
-- <= 0)
436 m_YourBaseLeft
.AddData(_T(""), DIFFSTATE_EMPTY
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
437 m_YourBaseRight
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_ADDED
, yourline
, endingYours
);
441 EOL endingBase
= m_arBaseFile
.GetLineEnding(baseline
);
442 m_YourBaseLeft
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_REMOVED
, baseline
, endingBase
);
443 m_YourBaseRight
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_ADDED
, yourline
, endingYours
);
449 apr_off_t modified_length
= tempdiff
->modified_length
;
450 for (int i
=0; i
<tempdiff
->original_length
; i
++)
452 if (modified_length
-- <= 0)
454 if (m_arBaseFile
.GetCount() > baseline
)
456 EOL endingBase
= m_arBaseFile
.GetLineEnding(baseline
);
457 m_YourBaseLeft
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_REMOVED
, baseline
, endingBase
);
458 m_YourBaseRight
.AddData(_T(""), DIFFSTATE_EMPTY
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
464 tempdiff
= tempdiff
->next
;
466 TRACE(_T("done with 2-way diff\n"));
472 CDiffData::DoThreeWayDiff(const CString
& sBaseFilename
, const CString
& sYourFilename
, const CString
& sTheirFilename
, DWORD dwIgnoreWS
, bool bIgnoreEOL
, bool bIgnoreCase
, apr_pool_t
* pool
)
474 // convert CString filenames (UTF-16 or ANSI) to UTF-8
475 CStringA sBaseFilenameUtf8
= CUnicodeUtils::GetUTF8(sBaseFilename
);
476 CStringA sYourFilenameUtf8
= CUnicodeUtils::GetUTF8(sYourFilename
);
477 CStringA sTheirFilenameUtf8
= CUnicodeUtils::GetUTF8(sTheirFilename
);
478 svn_diff_t
* diffTheirYourBase
= NULL
;
479 svn_diff_file_options_t
* options
= svn_diff_file_options_create(pool
);
480 options
->ignore_eol_style
= bIgnoreEOL
;
481 options
->ignore_space
= svn_diff_file_ignore_space_none
;
485 options
->ignore_space
= svn_diff_file_ignore_space_none
;
488 options
->ignore_space
= svn_diff_file_ignore_space_all
;
491 options
->ignore_space
= svn_diff_file_ignore_space_change
;
494 svn_error_t
* svnerr
= svn_diff_file_diff3_2(&diffTheirYourBase
, sBaseFilenameUtf8
, sTheirFilenameUtf8
, sYourFilenameUtf8
, options
, pool
);
497 TRACE(_T("diff-error in CDiffData::Load()\n"));
498 CString sMsg
= CString(svnerr
->message
);
499 while (svnerr
->child
)
501 svnerr
= svnerr
->child
;
503 sMsg
+= CString(svnerr
->message
);
505 m_sError
.Format(IDS_ERR_DIFF_DIFF
, (LPCTSTR
)sMsg
);
506 svn_error_clear(svnerr
);
510 svn_diff_t
* tempdiff
= diffTheirYourBase
;
517 if (tempdiff
->type
== svn_diff__type_common
)
519 ASSERT((tempdiff
->latest_length
== tempdiff
->modified_length
) && (tempdiff
->modified_length
== tempdiff
->original_length
));
520 for (int i
=0; i
<tempdiff
->original_length
; i
++)
522 if ((m_arYourFile
.GetCount() > yourline
)&&(m_arTheirFile
.GetCount() > theirline
))
524 m_Diff3
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_NORMAL
, resline
, m_arYourFile
.GetLineEnding(yourline
));
526 m_arDiff3LinesBase
.Add(baseline
);
527 m_arDiff3LinesYour
.Add(yourline
);
528 m_arDiff3LinesTheir
.Add(theirline
);
530 m_YourBaseBoth
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_NORMAL
, yourline
, m_arYourFile
.GetLineEnding(yourline
));
531 m_TheirBaseBoth
.AddData(m_arTheirFile
.GetAt(theirline
), DIFFSTATE_NORMAL
, theirline
, m_arTheirFile
.GetLineEnding(theirline
));
540 else if (tempdiff
->type
== svn_diff__type_diff_common
)
542 ASSERT(tempdiff
->latest_length
== tempdiff
->modified_length
);
543 //both theirs and yours have lines replaced
544 for (int i
=0; i
<tempdiff
->original_length
; i
++)
546 if (m_arBaseFile
.GetCount() > baseline
)
548 m_Diff3
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, m_arBaseFile
.GetLineEnding(baseline
));
550 m_arDiff3LinesBase
.Add(baseline
);
551 m_arDiff3LinesYour
.Add(yourline
);
552 m_arDiff3LinesTheir
.Add(theirline
);
554 m_YourBaseBoth
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
555 m_TheirBaseBoth
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
560 for (int i
=0; i
<tempdiff
->modified_length
; i
++)
562 if ((m_arYourFile
.GetCount() > yourline
)&&(m_arTheirFile
.GetCount() > theirline
))
564 m_Diff3
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_IDENTICALADDED
, resline
, m_arYourFile
.GetLineEnding(yourline
));
566 m_arDiff3LinesBase
.Add(baseline
);
567 m_arDiff3LinesYour
.Add(yourline
);
568 m_arDiff3LinesTheir
.Add(theirline
);
570 m_YourBaseBoth
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_IDENTICALADDED
, yourline
, m_arYourFile
.GetLineEnding(yourline
));
571 m_TheirBaseBoth
.AddData(m_arTheirFile
.GetAt(theirline
), DIFFSTATE_IDENTICALADDED
, resline
, m_arTheirFile
.GetLineEnding(theirline
));
579 else if (tempdiff
->type
== svn_diff__type_conflict
)
581 apr_off_t length
= max(tempdiff
->original_length
, tempdiff
->modified_length
);
582 length
= max(tempdiff
->latest_length
, length
);
583 apr_off_t original
= tempdiff
->original_length
;
584 apr_off_t modified
= tempdiff
->modified_length
;
585 apr_off_t latest
= tempdiff
->latest_length
;
587 apr_off_t originalresolved
= 0;
588 apr_off_t modifiedresolved
= 0;
589 apr_off_t latestresolved
= 0;
591 LONG base
= baseline
;
592 LONG your
= yourline
;
593 LONG their
= theirline
;
594 if (tempdiff
->resolved_diff
)
596 originalresolved
= tempdiff
->resolved_diff
->original_length
;
597 modifiedresolved
= tempdiff
->resolved_diff
->modified_length
;
598 latestresolved
= tempdiff
->resolved_diff
->latest_length
;
600 for (int i
=0; i
<length
; i
++)
604 if (m_arBaseFile
.GetCount() > baseline
)
606 m_Diff3
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, m_arBaseFile
.GetLineEnding(baseline
));
608 m_arDiff3LinesBase
.Add(baseline
);
609 m_arDiff3LinesYour
.Add(yourline
);
610 m_arDiff3LinesTheir
.Add(theirline
);
613 else if ((originalresolved
)||((modifiedresolved
)&&(latestresolved
)))
615 m_Diff3
.AddData(_T(""), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
617 m_arDiff3LinesBase
.Add(baseline
);
618 m_arDiff3LinesYour
.Add(yourline
);
619 m_arDiff3LinesTheir
.Add(theirline
);
622 if ((latest
)&&(original
))
624 if (m_arBaseFile
.GetCount() > baseline
)
626 m_YourBaseBoth
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, m_arBaseFile
.GetLineEnding(baseline
));
633 if (m_arBaseFile
.GetCount() > baseline
)
635 m_YourBaseBoth
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, m_arBaseFile
.GetLineEnding(baseline
));
638 else if ((latestresolved
)&&(modifiedresolved
))
640 m_YourBaseBoth
.AddData(_T(""), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
643 if ((modified
)&&(original
))
645 if (m_arBaseFile
.GetCount() > baseline
)
647 m_TheirBaseBoth
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, m_arBaseFile
.GetLineEnding(baseline
));
654 if (m_arBaseFile
.GetCount() > baseline
)
656 m_TheirBaseBoth
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, m_arBaseFile
.GetLineEnding(baseline
));
659 else if ((modifiedresolved
)&&(latestresolved
))
661 m_TheirBaseBoth
.AddData(_T(""), DIFFSTATE_IDENTICALREMOVED
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
669 if (originalresolved
)
677 if (modifiedresolved
)
687 original
= tempdiff
->original_length
;
688 modified
= tempdiff
->modified_length
;
689 latest
= tempdiff
->latest_length
;
693 if (tempdiff
->resolved_diff
)
695 originalresolved
= tempdiff
->resolved_diff
->original_length
;
696 modifiedresolved
= tempdiff
->resolved_diff
->modified_length
;
697 latestresolved
= tempdiff
->resolved_diff
->latest_length
;
699 for (int i
=0; i
<length
; i
++)
701 if ((latest
)||(modified
))
703 m_Diff3
.AddData(_T(""), DIFFSTATE_CONFLICTED
, resline
, EOL_NOENDING
);
705 m_arDiff3LinesBase
.Add(baseline
);
706 m_arDiff3LinesYour
.Add(yourline
);
707 m_arDiff3LinesTheir
.Add(theirline
);
714 if (m_arYourFile
.GetCount() > yourline
)
716 m_YourBaseBoth
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_CONFLICTADDED
, yourline
, m_arYourFile
.GetLineEnding(yourline
));
719 else if ((latestresolved
)||(modified
)||(modifiedresolved
))
721 m_YourBaseBoth
.AddData(_T(""), DIFFSTATE_CONFLICTEMPTY
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
725 if (m_arTheirFile
.GetCount() > theirline
)
727 m_TheirBaseBoth
.AddData(m_arTheirFile
.GetAt(theirline
), DIFFSTATE_CONFLICTADDED
, theirline
, m_arTheirFile
.GetLineEnding(theirline
));
730 else if ((modifiedresolved
)||(latest
)||(latestresolved
))
732 m_TheirBaseBoth
.AddData(_T(""), DIFFSTATE_CONFLICTEMPTY
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
739 if (originalresolved
)
746 if (modifiedresolved
)
757 else if (tempdiff
->type
== svn_diff__type_diff_modified
)
760 for (int i
=0; i
<tempdiff
->original_length
; i
++)
762 if ((m_arBaseFile
.GetCount() > baseline
)&&(m_arYourFile
.GetCount() > yourline
))
764 m_Diff3
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_THEIRSREMOVED
, DIFF_EMPTYLINENUMBER
, m_arBaseFile
.GetLineEnding(baseline
));
766 m_arDiff3LinesBase
.Add(baseline
);
767 m_arDiff3LinesYour
.Add(yourline
);
768 m_arDiff3LinesTheir
.Add(theirline
);
770 m_YourBaseBoth
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_NORMAL
, yourline
, m_arYourFile
.GetLineEnding(yourline
));
771 m_TheirBaseBoth
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_THEIRSREMOVED
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
777 for (int i
=0; i
<tempdiff
->modified_length
; i
++)
779 if (m_arTheirFile
.GetCount() > theirline
)
781 m_Diff3
.AddData(m_arTheirFile
.GetAt(theirline
), DIFFSTATE_THEIRSADDED
, resline
, m_arTheirFile
.GetLineEnding(theirline
));
783 m_arDiff3LinesBase
.Add(baseline
);
784 m_arDiff3LinesYour
.Add(yourline
);
785 m_arDiff3LinesTheir
.Add(theirline
);
787 m_YourBaseBoth
.AddData(_T(""), DIFFSTATE_EMPTY
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
788 m_TheirBaseBoth
.AddData(m_arTheirFile
.GetAt(theirline
), DIFFSTATE_THEIRSADDED
, theirline
, m_arTheirFile
.GetLineEnding(theirline
));
795 else if (tempdiff
->type
== svn_diff__type_diff_latest
)
797 //YOURS differs from base
799 for (int i
=0; i
<tempdiff
->original_length
; i
++)
801 if ((m_arBaseFile
.GetCount() > baseline
)&&(m_arTheirFile
.GetCount() > theirline
))
803 m_Diff3
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_YOURSREMOVED
, DIFF_EMPTYLINENUMBER
, m_arBaseFile
.GetLineEnding(baseline
));
805 m_arDiff3LinesBase
.Add(baseline
);
806 m_arDiff3LinesYour
.Add(yourline
);
807 m_arDiff3LinesTheir
.Add(theirline
);
809 m_YourBaseBoth
.AddData(m_arBaseFile
.GetAt(baseline
), DIFFSTATE_YOURSREMOVED
, DIFF_EMPTYLINENUMBER
, m_arBaseFile
.GetLineEnding(baseline
));
810 m_TheirBaseBoth
.AddData(m_arTheirFile
.GetAt(theirline
), DIFFSTATE_NORMAL
, theirline
, m_arTheirFile
.GetLineEnding(theirline
));
816 for (int i
=0; i
<tempdiff
->latest_length
; i
++)
818 if (m_arYourFile
.GetCount() > yourline
)
820 m_Diff3
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_YOURSADDED
, resline
, m_arYourFile
.GetLineEnding(yourline
));
822 m_arDiff3LinesBase
.Add(baseline
);
823 m_arDiff3LinesYour
.Add(yourline
);
824 m_arDiff3LinesTheir
.Add(theirline
);
826 m_YourBaseBoth
.AddData(m_arYourFile
.GetAt(yourline
), DIFFSTATE_IDENTICALADDED
, yourline
, m_arYourFile
.GetLineEnding(yourline
));
827 m_TheirBaseBoth
.AddData(_T(""), DIFFSTATE_EMPTY
, DIFF_EMPTYLINENUMBER
, EOL_NOENDING
);
836 TRACE(_T("something bad happened during diff!\n"));
838 tempdiff
= tempdiff
->next
;
840 } // while (tempdiff)
842 if ((options
->ignore_space
!= svn_diff_file_ignore_space_none
)||(bIgnoreCase
)||(bIgnoreEOL
))
844 // If whitespaces are ignored, a conflict could have been missed
845 // We now go through all lines again and check if they're identical.
846 // If they're not, then that means it is a conflict, and we
847 // mark the conflict with the proper colors.
848 for (long i
=0; i
<m_Diff3
.GetCount(); ++i
)
850 DiffStates state1
= m_YourBaseBoth
.GetState(i
);
851 DiffStates state2
= m_TheirBaseBoth
.GetState(i
);
853 if (((state1
== DIFFSTATE_IDENTICALADDED
)||(state1
== DIFFSTATE_NORMAL
))&&
854 ((state2
== DIFFSTATE_IDENTICALADDED
)||(state2
== DIFFSTATE_NORMAL
)))
856 LONG lineyour
= m_arDiff3LinesYour
.GetAt(i
);
857 LONG linetheir
= m_arDiff3LinesTheir
.GetAt(i
);
858 LONG linebase
= m_arDiff3LinesBase
.GetAt(i
);
859 if ((lineyour
< m_arYourFile
.GetCount()) &&
860 (linetheir
< m_arTheirFile
.GetCount()) &&
861 (linebase
< m_arBaseFile
.GetCount()))
863 if (((m_arYourFile
.GetLineEnding(lineyour
)!=m_arBaseFile
.GetLineEnding(linebase
))&&
864 (m_arTheirFile
.GetLineEnding(linetheir
)!=m_arBaseFile
.GetLineEnding(linebase
))&&
865 (m_arYourFile
.GetLineEnding(lineyour
)!=m_arTheirFile
.GetLineEnding(linetheir
))) ||
866 ((m_arYourFile
.GetAt(lineyour
).Compare(m_arBaseFile
.GetAt(linebase
))!=0)&&
867 (m_arTheirFile
.GetAt(linetheir
).Compare(m_arBaseFile
.GetAt(linebase
))!=0)&&
868 (m_arYourFile
.GetAt(lineyour
).Compare(m_arTheirFile
.GetAt(linetheir
))!=0)))
870 m_Diff3
.SetState(i
, DIFFSTATE_CONFLICTED_IGNORED
);
871 m_YourBaseBoth
.SetState(i
, DIFFSTATE_CONFLICTADDED
);
872 m_TheirBaseBoth
.SetState(i
, DIFFSTATE_CONFLICTADDED
);
878 ASSERT(m_Diff3
.GetCount() == m_YourBaseBoth
.GetCount());
879 ASSERT(m_TheirBaseBoth
.GetCount() == m_YourBaseBoth
.GetCount());
881 TRACE(_T("done with 3-way diff\n"));