Success build TortoiseMerge.
[TortoiseGit.git] / src / TortoiseMerge / DiffData.cpp
blob8c0b143e4c09e575554cb83c571d86b80958dc8e
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.
19 #include "StdAfx.h"
20 #include "svn_version.h"
21 #include "svn_io.h"
22 #include "diff.h"
23 #include "TempFiles.h"
24 #include "registry.h"
25 #include "Resource.h"
26 #include "Diffdata.h"
27 #include "UnicodeUtils.h"
28 #include "GitAdminDir.h"
29 #include "svn_dso.h"
31 #pragma warning(push)
32 #pragma warning(disable: 4702) // unreachable code
33 int CDiffData::abort_on_pool_failure (int /*retcode*/)
35 abort ();
36 return -1;
38 #pragma warning(pop)
40 CDiffData::CDiffData(void)
42 apr_initialize();
43 svn_dso_initialize2();
44 g_GitAdminDir.Init();
46 m_bBlame = false;
48 m_sPatchOriginal = _T(": original");
49 m_sPatchPatched = _T(": patched");
52 CDiffData::~CDiffData(void)
54 g_GitAdminDir.Close();
55 apr_terminate();
58 int CDiffData::GetLineCount()
60 int count = 0;
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());
64 return count;
67 int CDiffData::GetLineActualLength(int index)
69 int count = 0;
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());
76 return count;
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);
87 return NULL;
90 BOOL CDiffData::Load()
92 CString sConvertedBaseFilename, sConvertedTheirFilename, sConvertedYourFilename;
93 apr_pool_t * pool;
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();
109 m_Diff3.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();
136 return FALSE;
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();
153 return FALSE;
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();
170 return FALSE;
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();
202 return FALSE;
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
211 return FALSE;
215 if (IsBaseFileInUse() && IsTheirFileInUse() && !IsYourFileInUse())
217 ASSERT(FALSE);
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
227 return FALSE;
231 apr_pool_destroy (pool); // free the allocated memory
232 return TRUE;
236 bool
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;
248 switch (dwIgnoreWS)
250 case 0:
251 options->ignore_space = svn_diff_file_ignore_space_none;
252 break;
253 case 1:
254 options->ignore_space = svn_diff_file_ignore_space_all;
255 break;
256 case 2:
257 options->ignore_space = svn_diff_file_ignore_space_change;
258 break;
261 svnerr = svn_diff_file_diff_2(&diffYourBase, sBaseFilenameUtf8, sYourFilenameUtf8, options, pool);
262 if (svnerr)
264 TRACE(_T("diff-error in CDiffData::Load()\n"));
265 CString sMsg = CString(svnerr->message);
266 while (svnerr->child)
268 svnerr = svnerr->child;
269 sMsg += _T("\n");
270 sMsg += CString(svnerr->message);
272 m_sError.Format(IDS_ERR_DIFF_DIFF, (LPCTSTR)sMsg);
273 svn_error_clear(svnerr);
274 return false;
276 svn_diff_t * tempdiff = diffYourBase;
277 LONG baseline = 0;
278 LONG yourline = 0;
280 while (tempdiff)
282 for (int i=0; i<tempdiff->original_length; i++)
284 if (baseline >= m_arBaseFile.GetCount())
286 m_sError.LoadString(IDS_ERR_DIFF_NEWLINES);
287 return false;
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);
296 return false;
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"));
312 else
314 s1.TrimRight(_T(" \t"));
315 s2.TrimRight(_T(" \t"));
318 if (s1 != s2)
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);
324 else
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);
334 else
336 m_YourBaseBoth.AddData(sCurrentBaseLine, DIFFSTATE_NORMAL, yourline, endingBase);
339 else
341 m_YourBaseBoth.AddData(sCurrentBaseLine, DIFFSTATE_NORMAL, yourline, endingBase);
343 yourline++; //in both files
345 else
347 m_YourBaseBoth.AddData(sCurrentBaseLine, DIFFSTATE_REMOVED, yourline, endingBase);
349 baseline++;
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));
359 yourline++;
362 tempdiff = tempdiff->next;
365 tempdiff = diffYourBase;
366 baseline = 0;
367 yourline = 0;
368 while (tempdiff)
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"));
389 else
391 s1 = s1.TrimRight(_T(" \t"));
392 s2 = s2.TrimRight(_T(" \t"));
395 if (s1 != s2)
397 m_YourBaseLeft.AddData(sCurrentBaseLine, DIFFSTATE_WHITESPACE, baseline, endingBase);
398 m_YourBaseRight.AddData(sCurrentYourLine, DIFFSTATE_WHITESPACE, yourline, endingYours);
400 else
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);
411 else
413 m_YourBaseLeft.AddData(sCurrentBaseLine, DIFFSTATE_NORMAL, baseline, endingBase);
414 m_YourBaseRight.AddData(sCurrentYourLine, DIFFSTATE_NORMAL, yourline, endingYours);
417 else
419 m_YourBaseLeft.AddData(sCurrentBaseLine, DIFFSTATE_NORMAL, baseline, endingBase);
420 m_YourBaseRight.AddData(sCurrentYourLine, DIFFSTATE_NORMAL, yourline, endingYours);
422 baseline++;
423 yourline++;
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);
439 else
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);
444 baseline++;
446 yourline++;
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);
459 baseline++;
464 tempdiff = tempdiff->next;
466 TRACE(_T("done with 2-way diff\n"));
468 return true;
471 bool
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;
482 switch (dwIgnoreWS)
484 case 0:
485 options->ignore_space = svn_diff_file_ignore_space_none;
486 break;
487 case 1:
488 options->ignore_space = svn_diff_file_ignore_space_all;
489 break;
490 case 2:
491 options->ignore_space = svn_diff_file_ignore_space_change;
492 break;
494 svn_error_t * svnerr = svn_diff_file_diff3_2(&diffTheirYourBase, sBaseFilenameUtf8, sTheirFilenameUtf8, sYourFilenameUtf8, options, pool);
495 if (svnerr)
497 TRACE(_T("diff-error in CDiffData::Load()\n"));
498 CString sMsg = CString(svnerr->message);
499 while (svnerr->child)
501 svnerr = svnerr->child;
502 sMsg += _T("\n");
503 sMsg += CString(svnerr->message);
505 m_sError.Format(IDS_ERR_DIFF_DIFF, (LPCTSTR)sMsg);
506 svn_error_clear(svnerr);
507 return false;
510 svn_diff_t * tempdiff = diffTheirYourBase;
511 LONG baseline = 0;
512 LONG yourline = 0;
513 LONG theirline = 0;
514 LONG resline = 0;
515 while (tempdiff)
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));
533 baseline++;
534 yourline++;
535 theirline++;
536 resline++;
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);
557 baseline++;
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));
573 yourline++;
574 theirline++;
575 resline++;
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++)
602 if (original)
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));
629 else
631 if (original)
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));
650 else
652 if (original)
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);
664 if (original)
666 original--;
667 baseline++;
669 if (originalresolved)
670 originalresolved--;
672 if (modified)
674 modified--;
675 theirline++;
677 if (modifiedresolved)
678 modifiedresolved--;
679 if (latest)
681 latest--;
682 yourline++;
684 if (latestresolved)
685 latestresolved--;
687 original = tempdiff->original_length;
688 modified = tempdiff->modified_length;
689 latest = tempdiff->latest_length;
690 baseline = base;
691 yourline = your;
692 theirline = their;
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);
709 resline++;
712 if (latest)
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);
723 if (modified)
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);
734 if (original)
736 original--;
737 baseline++;
739 if (originalresolved)
740 originalresolved--;
741 if (modified)
743 modified--;
744 theirline++;
746 if (modifiedresolved)
747 modifiedresolved--;
748 if (latest)
750 latest--;
751 yourline++;
753 if (latestresolved)
754 latestresolved--;
757 else if (tempdiff->type == svn_diff__type_diff_modified)
759 //deleted!
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);
772 baseline++;
773 yourline++;
776 //added
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));
790 theirline++;
791 resline++;
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));
812 baseline++;
813 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);
829 yourline++;
830 resline++;
834 else
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"));
882 return true;