annotate kdiff3/src/diff.cpp @ 57:023fbd76c1e3

Translating some strings to french
author friseb123
date Sat, 31 Jan 2004 14:25:47 +0000
parents 32d5cbf9db71
children 8af4bb9d9a5a
rev   line source
joachim99@8 1 /***************************************************************************
joachim99@8 2 diff.cpp - description
joachim99@8 3 -------------------
joachim99@8 4 begin : Mon Mar 18 2002
joachim99@8 5 copyright : (C) 2002 by Joachim Eibl
joachim99@8 6 email : joachim.eibl@gmx.de
joachim99@8 7 ***************************************************************************/
joachim99@8 8
joachim99@8 9 /***************************************************************************
joachim99@8 10 * *
joachim99@8 11 * This program is free software; you can redistribute it and/or modify *
joachim99@8 12 * it under the terms of the GNU General Public License as published by *
joachim99@8 13 * the Free Software Foundation; either version 2 of the License, or *
joachim99@8 14 * (at your option) any later version. *
joachim99@8 15 * *
joachim99@8 16 ***************************************************************************/
joachim99@8 17
joachim99@8 18 #include <stdio.h>
joachim99@8 19 #include <iostream>
joachim99@8 20
joachim99@8 21 #include "diff.h"
joachim99@8 22 #include "fileaccess.h"
joachim99@8 23
joachim99@8 24 #include <kmessagebox.h>
joachim99@8 25 #include <klocale.h>
joachim99@8 26 #include <qfileinfo.h>
joachim99@8 27 #include <qdir.h>
joachim99@8 28
joachim99@8 29 #include <map>
joachim99@8 30 #include <assert.h>
joachim99@8 31 #include <ctype.h>
joachim99@8 32 //using namespace std;
joachim99@8 33
joachim99@8 34
joachim99@8 35 int LineData::width()
joachim99@8 36 {
joachim99@8 37 int w=0;
joachim99@8 38 int j=0;
joachim99@8 39 for( int i=0; i<size; ++i )
joachim99@8 40 {
joachim99@8 41 if ( pLine[i]=='\t' )
joachim99@8 42 {
joachim99@8 43 for(j %= g_tabSize; j<g_tabSize; ++j)
joachim99@8 44 ++w;
joachim99@8 45 j=0;
joachim99@8 46 }
joachim99@8 47 else
joachim99@8 48 {
joachim99@8 49 ++w;
joachim99@8 50 ++j;
joachim99@8 51 }
joachim99@8 52 }
joachim99@8 53 return w;
joachim99@8 54 }
joachim99@8 55
joachim99@8 56
joachim99@8 57 // The bStrict flag is true during the test where a nonmatching area ends.
joachim99@8 58 // Then the equal()-function requires that the match has more than 2 nonwhite characters.
joachim99@8 59 // This is to avoid matches on trivial lines (e.g. with white space only).
joachim99@8 60 // This choice is good for C/C++.
joachim99@8 61 bool equal( const LineData& l1, const LineData& l2, bool bStrict )
joachim99@8 62 {
joachim99@8 63 if ( l1.pLine==0 || l2.pLine==0) return false;
joachim99@8 64
joachim99@8 65 if ( bStrict && g_bIgnoreTrivialMatches && (l1.occurances>=5 || l2.occurances>=5) )
joachim99@8 66 return false;
joachim99@8 67
joachim99@8 68 // Ignore white space diff
joachim99@8 69 const char* p1 = l1.pLine;
joachim99@8 70 const char* p1End = p1 + l1.size;
joachim99@8 71
joachim99@8 72 const char* p2 = l2.pLine;
joachim99@8 73 const char* p2End = p2 + l2.size;
joachim99@8 74
joachim99@8 75 if ( g_bIgnoreWhiteSpace )
joachim99@8 76 {
joachim99@8 77 int nonWhite = 0;
joachim99@8 78 for(;;)
joachim99@8 79 {
joachim99@8 80 while( isWhite( *p1 ) && p1!=p1End ) ++p1;
joachim99@8 81 while( isWhite( *p2 ) && p2!=p2End ) ++p2;
joachim99@8 82
joachim99@8 83 if ( p1 == p1End && p2 == p2End )
joachim99@8 84 {
joachim99@8 85 if ( bStrict && g_bIgnoreTrivialMatches )
joachim99@8 86 { // Then equality is not enough
joachim99@8 87 return nonWhite>2;
joachim99@8 88 }
joachim99@8 89 else // equality is enough
joachim99@8 90 return true;
joachim99@8 91 }
joachim99@8 92 else if ( p1 == p1End || p2 == p2End )
joachim99@8 93 return false;
joachim99@8 94
joachim99@8 95 if( *p1 != *p2 )
joachim99@8 96 return false;
joachim99@8 97 ++p1;
joachim99@8 98 ++p2;
joachim99@8 99 ++nonWhite;
joachim99@8 100 }
joachim99@8 101 }
joachim99@8 102
joachim99@8 103 else
joachim99@8 104 {
joachim99@8 105 if ( l1.size==l2.size && memcmp(p1, p2, l1.size)==0)
joachim99@8 106 return true;
joachim99@8 107 else
joachim99@8 108 return false;
joachim99@8 109 }
joachim99@8 110 }
joachim99@8 111
joachim99@8 112
joachim99@8 113 // class needed during preprocess phase
joachim99@8 114 class LineDataRef
joachim99@8 115 {
joachim99@8 116 const LineData* m_pLd;
joachim99@8 117 public:
joachim99@8 118 LineDataRef(const LineData* pLd){ m_pLd = pLd; }
joachim99@8 119
joachim99@8 120 bool operator<(const LineDataRef& ldr2) const
joachim99@8 121 {
joachim99@8 122 const LineData* pLd1 = m_pLd;
joachim99@8 123 const LineData* pLd2 = ldr2.m_pLd;
joachim99@8 124 const char* p1 = pLd1->pFirstNonWhiteChar;
joachim99@8 125 const char* p2 = pLd2->pFirstNonWhiteChar;
joachim99@8 126
joachim99@8 127 int size1=pLd1->size;
joachim99@8 128 int size2=pLd2->size;
joachim99@43 129
joachim99@43 130 int i1=min2(pLd1->pFirstNonWhiteChar - pLd1->pLine,size1);
joachim99@43 131 int i2=min2(pLd2->pFirstNonWhiteChar - pLd2->pLine,size2);
joachim99@8 132 for(;;)
joachim99@8 133 {
joachim99@8 134 while( i1<size1 && isWhite( p1[i1] ) ) ++i1;
joachim99@8 135 while( i2<size2 && isWhite( p2[i2] ) ) ++i2;
joachim99@8 136 if ( i1==size1 || i2==size2 )
joachim99@8 137 {
joachim99@8 138 if ( i1==size1 && i2==size2 ) return false; // Equal
joachim99@8 139 if ( i1==size1 ) return true; // String 1 is shorter than string 2
joachim99@8 140 if ( i2==size2 ) return false; // String 1 is longer than string 2
joachim99@8 141 }
joachim99@8 142 if ( p1[i1]==p2[i2] ) { ++i1; ++i2; continue; }
joachim99@8 143 return p1[i1]<p2[i2];
joachim99@8 144 }
joachim99@8 145 }
joachim99@8 146 };
joachim99@8 147
joachim99@8 148 void SourceData::reset()
joachim99@8 149 {
joachim99@8 150 delete (char*)m_pBuf;
joachim99@8 151 m_pBuf = 0;
joachim99@8 152 m_v.clear();
joachim99@8 153 m_size = 0;
joachim99@8 154 m_vSize = 0;
joachim99@8 155 m_bIsText = false;
joachim99@8 156 m_bPreserve = false;
joachim99@8 157 m_fileAccess = FileAccess("");
joachim99@8 158 }
joachim99@8 159
joachim99@8 160 /** Prepare the linedata vector for every input line.*/
joachim99@8 161 void SourceData::preprocess( bool bPreserveCR )
joachim99@8 162 {
joachim99@8 163 const char* p = m_pBuf;
joachim99@8 164 m_bIsText = true;
joachim99@8 165 int lines = 1;
joachim99@8 166
joachim99@8 167 int i;
joachim99@8 168 for( i=0; i<m_size; ++i )
joachim99@8 169 {
joachim99@8 170 if (p[i]=='\n')
joachim99@8 171 {
joachim99@8 172 ++lines;
joachim99@8 173 }
joachim99@8 174 if ( p[i]=='\0' )
joachim99@8 175 {
joachim99@8 176 m_bIsText = false;
joachim99@8 177 }
joachim99@8 178 }
joachim99@8 179
joachim99@8 180 m_v.resize( lines+5 );
joachim99@8 181 int lineIdx=0;
joachim99@8 182 int lineLength=0;
joachim99@8 183 bool bNonWhiteFound = false;
joachim99@8 184 int whiteLength = 0;
joachim99@8 185 for( i=0; i<=m_size; ++i )
joachim99@8 186 {
joachim99@39 187 if ( i==m_size || p[i]=='\n' ) // The last line does not end with a linefeed.
joachim99@8 188 {
joachim99@8 189 m_v[lineIdx].pLine = &p[ i-lineLength ];
joachim99@39 190 while ( !bPreserveCR && lineLength>0 && m_v[lineIdx].pLine[lineLength-1]=='\r' )
joachim99@39 191 {
joachim99@39 192 --lineLength;
joachim99@39 193 }
joachim99@43 194 m_v[lineIdx].pFirstNonWhiteChar = m_v[lineIdx].pLine + min2(whiteLength,lineLength);
joachim99@8 195 m_v[lineIdx].size = lineLength;
joachim99@8 196 lineLength = 0;
joachim99@8 197 bNonWhiteFound = false;
joachim99@8 198 whiteLength = 0;
joachim99@8 199 ++lineIdx;
joachim99@8 200 }
joachim99@8 201 else
joachim99@8 202 {
joachim99@8 203 ++lineLength;
joachim99@8 204
joachim99@8 205 if ( ! bNonWhiteFound && isWhite( p[i] ) )
joachim99@8 206 ++whiteLength;
joachim99@8 207 else
joachim99@8 208 bNonWhiteFound = true;
joachim99@8 209 }
joachim99@8 210 }
joachim99@8 211 assert( lineIdx == lines );
joachim99@8 212
joachim99@8 213 m_vSize = lines;
joachim99@8 214 }
joachim99@8 215
joachim99@51 216
joachim99@51 217 // Must not be entered, when within a comment.
joachim99@51 218 // Returns either at a newline-character p[i]=='\n' or when i==size.
joachim99@51 219 // A line that contains only comments is still "white".
joachim99@51 220 // Comments in white lines must remain, while comments in
joachim99@51 221 // non-white lines are overwritten with spaces.
joachim99@51 222 static void checkLineForComments(
joachim99@51 223 char* p, // pointer to start of buffer
joachim99@51 224 int& i, // index of current position (in, out)
joachim99@51 225 int size, // size of buffer
joachim99@51 226 bool& bWhite, // false if this line contains nonwhite characters (in, out)
joachim99@51 227 bool& bCommentInLine, // true if any comment is within this line (in, out)
joachim99@51 228 bool& bStartsOpenComment // true if the line ends within an comment (out)
joachim99@51 229 )
joachim99@8 230 {
joachim99@51 231 bStartsOpenComment = false;
joachim99@51 232 for(; i<size; ++i )
joachim99@51 233 {
joachim99@51 234 // A single apostroph ' has prio over a double apostroph " (e.g. '"')
joachim99@51 235 // (if not in a string)
joachim99@51 236 if ( p[i]=='\'' )
joachim99@51 237 {
joachim99@51 238 bWhite = false;
joachim99@51 239 ++i;
joachim99@51 240 for( ; i<size && p[i]!='\'' && p[i]!='\n'; ++i)
joachim99@51 241 ;
joachim99@51 242 if (p[i]=='\'') ++i;
joachim99@51 243 }
joachim99@51 244
joachim99@51 245 // Strings have priority over comments: e.g. "/* Not a comment, but a string. */"
joachim99@51 246 else if ( p[i]=='"' )
joachim99@51 247 {
joachim99@51 248 bWhite = false;
joachim99@51 249 ++i;
joachim99@51 250 for( ; i<size && !(p[i]=='"' && p[i-1]!='\\') && p[i]!='\n'; ++i)
joachim99@51 251 ;
joachim99@51 252 if (p[i]=='"') ++i;
joachim99@51 253 }
joachim99@51 254
joachim99@51 255 // C++-comment
joachim99@51 256 else if ( p[i]=='/' && i+1<size && p[i+1] =='/' )
joachim99@51 257 {
joachim99@51 258 int commentStart = i;
joachim99@51 259 bCommentInLine = true;
joachim99@51 260 i+=2;
joachim99@51 261 for( ; i<size && p[i]!='\n'; ++i)
joachim99@51 262 ;
joachim99@51 263 if ( !bWhite )
joachim99@51 264 {
joachim99@51 265 memset( &p[commentStart], ' ', i-commentStart );
joachim99@51 266 }
joachim99@51 267 return;
joachim99@51 268 }
joachim99@51 269
joachim99@51 270 // C-comment
joachim99@51 271 else if ( p[i]=='/' && i+1<size && p[i+1] =='*' )
joachim99@51 272 {
joachim99@51 273 int commentStart = i;
joachim99@51 274 bCommentInLine = true;
joachim99@51 275 i+=2;
joachim99@51 276 for( ; i<size && p[i]!='\n'; ++i)
joachim99@51 277 {
joachim99@51 278 if ( i+1<size && p[i]=='*' && p[i+1]=='/') // end of the comment
joachim99@51 279 {
joachim99@51 280 i+=2;
joachim99@51 281
joachim99@51 282 // More comments in the line?
joachim99@51 283 checkLineForComments( p, i, size, bWhite, bCommentInLine, bStartsOpenComment );
joachim99@51 284 if ( !bWhite )
joachim99@51 285 {
joachim99@51 286 memset( &p[commentStart], ' ', i-commentStart );
joachim99@51 287 }
joachim99@51 288 return;
joachim99@51 289 }
joachim99@51 290 }
joachim99@51 291 bStartsOpenComment = true;
joachim99@51 292 return;
joachim99@51 293 }
joachim99@51 294
joachim99@51 295
joachim99@51 296 if (p[i]=='\n' || i>=size )
joachim99@51 297 {
joachim99@51 298 return;
joachim99@51 299 }
joachim99@51 300 else if ( !isspace(p[i]) )
joachim99@51 301 {
joachim99@51 302 bWhite = false;
joachim99@51 303 }
joachim99@51 304 }
joachim99@51 305 }
joachim99@51 306
joachim99@51 307 // Modifies the input data, and replaces C/C++ comments with whitespace
joachim99@51 308 // when the line contains other data too. If the line contains only
joachim99@51 309 // a comment or white data, remember this in the flag bContainsPureComment.
joachim99@51 310 void SourceData::removeComments( LineData* pLD )
joachim99@51 311 {
joachim99@51 312 int line=0;
joachim99@51 313 char* p = (char*)m_pBuf;
joachim99@51 314 bool bWithinComment=false;
joachim99@51 315 int size = m_size;
joachim99@51 316 for(int i=0; i<size; ++i )
joachim99@51 317 {
joachim99@51 318 // std::cout << "2 " << std::string(&p[i], m_v[line].size) << std::endl;
joachim99@51 319 bool bWhite = true;
joachim99@51 320 bool bCommentInLine = false;
joachim99@51 321
joachim99@51 322 if ( bWithinComment )
joachim99@51 323 {
joachim99@51 324 int commentStart = i;
joachim99@51 325 bCommentInLine = true;
joachim99@51 326
joachim99@51 327 for( ; i<size && p[i]!='\n'; ++i)
joachim99@51 328 {
joachim99@51 329 if ( i+1<size && p[i]=='*' && p[i+1]=='/') // end of the comment
joachim99@51 330 {
joachim99@51 331 i+=2;
joachim99@51 332
joachim99@51 333 // More comments in the line?
joachim99@51 334 checkLineForComments( p, i, size, bWhite, bCommentInLine, bWithinComment );
joachim99@51 335 if ( !bWhite )
joachim99@51 336 {
joachim99@51 337 memset( &p[commentStart], ' ', i-commentStart );
joachim99@51 338 }
joachim99@51 339 break;
joachim99@51 340 }
joachim99@51 341 }
joachim99@51 342 }
joachim99@51 343 else
joachim99@51 344 {
joachim99@51 345 checkLineForComments( p, i, size, bWhite, bCommentInLine, bWithinComment );
joachim99@51 346 }
joachim99@51 347
joachim99@51 348 // end of line
joachim99@51 349 assert( i>=size || p[i]=='\n');
joachim99@51 350 pLD[line].bContainsPureComment = bCommentInLine && bWhite;
joachim99@51 351 /* std::cout << line << " : " <<
joachim99@51 352 ( bCommentInLine ? "c" : " " ) <<
joachim99@51 353 ( bWhite ? "w " : " ") <<
joachim99@51 354 std::string(pLD[line].pLine, pLD[line].size) << std::endl;*/
joachim99@51 355
joachim99@51 356 ++line;
joachim99@51 357 }
joachim99@51 358 }
joachim99@51 359
joachim99@51 360 // read and preprocess file for line matching input data
joachim99@51 361 void SourceData::readLMPPFile( SourceData* pOrigSource, const QString& ppCmd, bool bUpCase, bool bRemoveComments )
joachim99@51 362 {
joachim99@51 363 if ( ( ppCmd.isEmpty() && !bRemoveComments ) || pOrigSource->m_bPreserve )
joachim99@8 364 {
joachim99@8 365 reset();
joachim99@8 366 }
joachim99@8 367 else
joachim99@8 368 {
joachim99@51 369 setFilename( pOrigSource->m_fileAccess.absFilePath() );
joachim99@8 370 readPPFile( false, ppCmd, bUpCase );
joachim99@8 371 if ( m_vSize < pOrigSource->m_vSize )
joachim99@8 372 {
joachim99@8 373 m_v.resize( pOrigSource->m_vSize );
joachim99@8 374 m_vSize = pOrigSource->m_vSize;
joachim99@8 375 }
joachim99@8 376 }
joachim99@51 377 if ( bRemoveComments && m_vSize==pOrigSource->m_vSize )
joachim99@51 378 removeComments( &pOrigSource->m_v[0] );
joachim99@8 379 }
joachim99@8 380
joachim99@8 381
joachim99@8 382 void SourceData::readPPFile( bool bPreserveCR, const QString& ppCmd, bool bUpCase )
joachim99@8 383 {
joachim99@8 384 if ( !m_bPreserve )
joachim99@8 385 {
joachim99@8 386 if ( ! ppCmd.isEmpty() && !m_fileName.isEmpty() && FileAccess::exists( m_fileName ) )
joachim99@8 387 {
joachim99@8 388 QString fileNameOut = FileAccess::tempFileName();
joachim99@8 389 #ifdef _WIN32
joachim99@8 390 QString cmd = QString("type ") + m_fileName + " | " + ppCmd + " >" + fileNameOut;
joachim99@8 391 #else
joachim99@8 392 QString cmd = QString("cat ") + m_fileName + " | " + ppCmd + " >" + fileNameOut;
joachim99@8 393 #endif
joachim99@8 394 ::system( cmd.ascii() );
joachim99@8 395 readFile( fileNameOut, true, bUpCase );
joachim99@8 396 FileAccess::removeFile( fileNameOut );
joachim99@8 397 }
joachim99@8 398 else
joachim99@8 399 {
joachim99@8 400 readFile( m_fileAccess.absFilePath(), true, bUpCase );
joachim99@8 401 }
joachim99@8 402 }
joachim99@8 403 preprocess( bPreserveCR );
joachim99@8 404 }
joachim99@8 405
joachim99@8 406 void SourceData::readFile( const QString& filename, bool bFollowLinks, bool bUpCase )
joachim99@8 407 {
joachim99@8 408 delete (char*)m_pBuf;
joachim99@8 409 m_size = 0;
joachim99@8 410 m_pBuf = 0;
joachim99@8 411 char* pBuf = 0;
joachim99@8 412 if ( filename.isEmpty() ) { return; }
joachim99@8 413
joachim99@8 414 if ( !bFollowLinks )
joachim99@8 415 {
joachim99@8 416 FileAccess fi( filename );
joachim99@8 417 if ( fi.isSymLink() )
joachim99@8 418 {
joachim99@8 419 QString s = fi.readLink();
joachim99@8 420 m_size = s.length();
joachim99@8 421 m_pBuf = pBuf = new char[m_size+100];
joachim99@8 422 memcpy( pBuf, s.ascii(), m_size );
joachim99@8 423 return;
joachim99@8 424 }
joachim99@8 425 }
joachim99@8 426
joachim99@8 427
joachim99@8 428 FileAccess fa( filename );
joachim99@8 429 m_size = fa.sizeForReading();
joachim99@8 430 m_pBuf = pBuf = new char[m_size+100];
joachim99@8 431 bool bSuccess = fa.readFile( pBuf, m_size );
joachim99@8 432 if ( !bSuccess )
joachim99@8 433 {
joachim99@8 434 delete pBuf;
joachim99@8 435 m_pBuf = 0;
joachim99@8 436 m_size = 0;
joachim99@8 437 return;
joachim99@8 438 }
joachim99@8 439
joachim99@8 440
joachim99@8 441 if ( bUpCase )
joachim99@8 442 {
joachim99@8 443 int i;
joachim99@8 444 for(i=0; i<m_size; ++i)
joachim99@8 445 {
joachim99@8 446 pBuf[i] = toupper(pBuf[i]);
joachim99@8 447 }
joachim99@8 448 }
joachim99@8 449
joachim99@8 450 }
joachim99@8 451
joachim99@8 452 void SourceData::setData( const QString& data, bool bUpCase )
joachim99@8 453 {
joachim99@8 454 delete (char*)m_pBuf;
joachim99@8 455 m_size = data.length();
joachim99@8 456 m_pBuf = 0;
joachim99@8 457
joachim99@8 458 char* pBuf = 0;
joachim99@8 459 m_pBuf = pBuf = new char[m_size+100];
joachim99@8 460
joachim99@8 461 memcpy( pBuf, data.ascii(), m_size );
joachim99@8 462 if ( bUpCase )
joachim99@8 463 {
joachim99@8 464 int i;
joachim99@8 465 for(i=0; i<m_size; ++i)
joachim99@8 466 {
joachim99@8 467 pBuf[i] = toupper(pBuf[i]);
joachim99@8 468 }
joachim99@8 469 }
joachim99@8 470 m_bPreserve = true;
joachim99@8 471 m_fileName="";
joachim99@8 472 m_aliasName = i18n("From Clipboard");
joachim99@8 473 m_fileAccess = FileAccess("");
joachim99@8 474 }
joachim99@8 475
joachim99@8 476 void SourceData::setFilename( const QString& filename )
joachim99@8 477 {
joachim99@8 478 FileAccess fa( filename );
joachim99@8 479 setFileAccess( fa );
joachim99@8 480 }
joachim99@8 481
joachim99@8 482 QString SourceData::getFilename()
joachim99@8 483 {
joachim99@8 484 return m_fileName;
joachim99@8 485 }
joachim99@8 486
joachim99@8 487 QString SourceData::getAliasName()
joachim99@8 488 {
joachim99@8 489 return m_aliasName.isEmpty() ? m_fileAccess.prettyAbsPath() : m_aliasName;
joachim99@8 490 }
joachim99@8 491
joachim99@8 492 void SourceData::setAliasName( const QString& name )
joachim99@8 493 {
joachim99@8 494 m_aliasName = name;
joachim99@8 495 }
joachim99@8 496
joachim99@8 497 void SourceData::setFileAccess( const FileAccess& fileAccess )
joachim99@8 498 {
joachim99@8 499 m_fileAccess = fileAccess;
joachim99@8 500 m_aliasName = QString();
joachim99@8 501 m_bPreserve = false;
joachim99@8 502 m_fileName = m_fileAccess.absFilePath();
joachim99@8 503 }
joachim99@8 504
joachim99@8 505 void prepareOccurances( LineData* p, int size )
joachim99@8 506 {
joachim99@8 507 // Special analysis: Find out how often this line occurs
joachim99@8 508 // Only problem: A simple search will cost O(N^2).
joachim99@8 509 // To avoid this we will use a map. Then the cost will only be
joachim99@8 510 // O(N*log N). (A hash table would be even better.)
joachim99@8 511
joachim99@8 512 std::map<LineDataRef,int> occurancesMap;
joachim99@8 513 int i;
joachim99@8 514 for( i=0; i<size; ++i )
joachim99@8 515 {
joachim99@8 516 ++occurancesMap[ LineDataRef( &p[i] ) ];
joachim99@8 517 }
joachim99@8 518
joachim99@8 519 for( i=0; i<size; ++i )
joachim99@8 520 {
joachim99@8 521 p[i].occurances = occurancesMap[ LineDataRef( &p[i] ) ];
joachim99@8 522 }
joachim99@8 523 }
joachim99@8 524
joachim99@8 525 // First step
joachim99@8 526 void calcDiff3LineListUsingAB(
joachim99@8 527 const DiffList* pDiffListAB,
joachim99@8 528 Diff3LineList& d3ll
joachim99@8 529 )
joachim99@8 530 {
joachim99@8 531 // First make d3ll for AB (from pDiffListAB)
joachim99@8 532
joachim99@8 533 DiffList::const_iterator i=pDiffListAB->begin();
joachim99@8 534 int lineA=0;
joachim99@8 535 int lineB=0;
joachim99@8 536 Diff d(0,0,0);
joachim99@8 537
joachim99@8 538 for(;;)
joachim99@8 539 {
joachim99@8 540 if ( d.nofEquals==0 && d.diff1==0 && d.diff2==0 )
joachim99@8 541 {
joachim99@8 542 if ( i!=pDiffListAB->end() )
joachim99@8 543 {
joachim99@8 544 d=*i;
joachim99@8 545 ++i;
joachim99@8 546 }
joachim99@8 547 else
joachim99@8 548 break;
joachim99@8 549 }
joachim99@8 550
joachim99@8 551 Diff3Line d3l;
joachim99@8 552 if( d.nofEquals>0 )
joachim99@8 553 {
joachim99@8 554 d3l.bAEqB = true;
joachim99@8 555 d3l.lineA = lineA;
joachim99@8 556 d3l.lineB = lineB;
joachim99@8 557 --d.nofEquals;
joachim99@8 558 ++lineA;
joachim99@8 559 ++lineB;
joachim99@8 560 }
joachim99@8 561 else if ( d.diff1>0 && d.diff2>0 )
joachim99@8 562 {
joachim99@8 563 d3l.lineA = lineA;
joachim99@8 564 d3l.lineB = lineB;
joachim99@8 565 --d.diff1;
joachim99@8 566 --d.diff2;
joachim99@8 567 ++lineA;
joachim99@8 568 ++lineB;
joachim99@8 569 }
joachim99@8 570 else if ( d.diff1>0 )
joachim99@8 571 {
joachim99@8 572 d3l.lineA = lineA;
joachim99@8 573 --d.diff1;
joachim99@8 574 ++lineA;
joachim99@8 575 }
joachim99@8 576 else if ( d.diff2>0 )
joachim99@8 577 {
joachim99@8 578 d3l.lineB = lineB;
joachim99@8 579 --d.diff2;
joachim99@8 580 ++lineB;
joachim99@8 581 }
joachim99@8 582
joachim99@8 583 d3ll.push_back( d3l );
joachim99@8 584 }
joachim99@8 585 }
joachim99@8 586
joachim99@8 587
joachim99@8 588 // Second step
joachim99@8 589 void calcDiff3LineListUsingAC(
joachim99@8 590 const DiffList* pDiffListAC,
joachim99@8 591 Diff3LineList& d3ll
joachim99@8 592 )
joachim99@8 593 {
joachim99@8 594 ////////////////
joachim99@8 595 // Now insert data from C using pDiffListAC
joachim99@8 596
joachim99@8 597 DiffList::const_iterator i=pDiffListAC->begin();
joachim99@8 598 Diff3LineList::iterator i3 = d3ll.begin();
joachim99@8 599 int lineA=0;
joachim99@8 600 int lineC=0;
joachim99@8 601 Diff d(0,0,0);
joachim99@8 602
joachim99@8 603 for(;;)
joachim99@8 604 {
joachim99@8 605 if ( d.nofEquals==0 && d.diff1==0 && d.diff2==0 )
joachim99@8 606 {
joachim99@8 607 if ( i!=pDiffListAC->end() )
joachim99@8 608 {
joachim99@8 609 d=*i;
joachim99@8 610 ++i;
joachim99@8 611 }
joachim99@8 612 else
joachim99@8 613 break;
joachim99@8 614 }
joachim99@8 615
joachim99@8 616 Diff3Line d3l;
joachim99@8 617 if( d.nofEquals>0 )
joachim99@8 618 {
joachim99@8 619 // Find the corresponding lineA
joachim99@8 620 while( (*i3).lineA!=lineA )
joachim99@8 621
joachim99@8 622 ++i3;
joachim99@8 623 (*i3).lineC = lineC;
joachim99@8 624 (*i3).bAEqC = true;
joachim99@8 625 (*i3).bBEqC = (*i3).bAEqB;
joachim99@8 626
joachim99@8 627 --d.nofEquals;
joachim99@8 628 ++lineA;
joachim99@8 629 ++lineC;
joachim99@8 630 ++i3;
joachim99@8 631 }
joachim99@8 632 else if ( d.diff1>0 && d.diff2>0 )
joachim99@8 633 {
joachim99@8 634 d3l.lineC = lineC;
joachim99@8 635 d3ll.insert( i3, d3l );
joachim99@8 636 --d.diff1;
joachim99@8 637 --d.diff2;
joachim99@8 638 ++lineA;
joachim99@8 639 ++lineC;
joachim99@8 640 }
joachim99@8 641 else if ( d.diff1>0 )
joachim99@8 642 {
joachim99@8 643 --d.diff1;
joachim99@8 644 ++lineA;
joachim99@8 645 }
joachim99@8 646 else if ( d.diff2>0 )
joachim99@8 647
joachim99@8 648 {
joachim99@8 649 d3l.lineC = lineC;
joachim99@8 650 d3ll.insert( i3, d3l );
joachim99@8 651 --d.diff2;
joachim99@8 652 ++lineC;
joachim99@8 653 }
joachim99@8 654 }
joachim99@8 655 }
joachim99@8 656
joachim99@8 657 // Third step
joachim99@8 658 void calcDiff3LineListUsingBC(
joachim99@8 659 const DiffList* pDiffListBC,
joachim99@8 660 Diff3LineList& d3ll
joachim99@8 661 )
joachim99@8 662 {
joachim99@8 663 ////////////////
joachim99@8 664 // Now improve the position of data from C using pDiffListBC
joachim99@8 665 // If a line from C equals a line from A then it is in the
joachim99@8 666 // same Diff3Line already.
joachim99@8 667 // If a line from C equals a line from B but not A, this
joachim99@8 668 // information will be used here.
joachim99@8 669
joachim99@8 670 DiffList::const_iterator i=pDiffListBC->begin();
joachim99@8 671 Diff3LineList::iterator i3b = d3ll.begin();
joachim99@8 672 Diff3LineList::iterator i3c = d3ll.begin();
joachim99@8 673 int lineB=0;
joachim99@8 674 int lineC=0;
joachim99@8 675 Diff d(0,0,0);
joachim99@8 676
joachim99@8 677 for(;;)
joachim99@8 678 {
joachim99@8 679 if ( d.nofEquals==0 && d.diff1==0 && d.diff2==0 )
joachim99@8 680 {
joachim99@8 681 if ( i!=pDiffListBC->end() )
joachim99@8 682 {
joachim99@8 683 d=*i;
joachim99@8 684 ++i;
joachim99@8 685 }
joachim99@8 686 else
joachim99@8 687 break;
joachim99@8 688 }
joachim99@8 689
joachim99@8 690 Diff3Line d3l;
joachim99@8 691 if( d.nofEquals>0 )
joachim99@8 692 {
joachim99@8 693 // Find the corresponding lineB and lineC
joachim99@39 694 while( i3b!=d3ll.end() && (*i3b).lineB!=lineB )
joachim99@8 695 ++i3b;
joachim99@8 696
joachim99@8 697 while( i3c!=d3ll.end() && (*i3c).lineC!=lineC )
joachim99@8 698 ++i3c;
joachim99@8 699
joachim99@8 700 assert(i3b!=d3ll.end());
joachim99@8 701 assert(i3c!=d3ll.end());
joachim99@8 702
joachim99@8 703 if ( i3b==i3c )
joachim99@8 704 {
joachim99@8 705 assert( (*i3b).lineC == lineC );
joachim99@8 706 (*i3b).bBEqC = true;
joachim99@8 707 }
joachim99@8 708 else //if ( !(*i3b).bAEqB )
joachim99@8 709 {
joachim99@8 710 // Is it possible to move this line up?
joachim99@8 711 // Test if no other B's are used between i3c and i3b
joachim99@8 712
joachim99@8 713 // First test which is before: i3c or i3b ?
joachim99@8 714 Diff3LineList::iterator i3c1 = i3c;
joachim99@8 715
joachim99@8 716 Diff3LineList::iterator i3b1 = i3b;
joachim99@8 717 while( i3c1!=i3b && i3b1!=i3c )
joachim99@8 718 {
joachim99@8 719 assert(i3b1!=d3ll.end() || i3c1!=d3ll.end());
joachim99@8 720 if( i3c1!=d3ll.end() ) ++i3c1;
joachim99@8 721 if( i3b1!=d3ll.end() ) ++i3b1;
joachim99@8 722 }
joachim99@8 723
joachim99@8 724 if( i3c1==i3b && !(*i3b).bAEqB ) // i3c before i3b
joachim99@8 725 {
joachim99@8 726 Diff3LineList::iterator i3 = i3c;
joachim99@8 727 int nofDisturbingLines = 0;
joachim99@8 728 while( i3 != i3b && i3!=d3ll.end() )
joachim99@8 729
joachim99@8 730 {
joachim99@8 731 if ( (*i3).lineB != -1 )
joachim99@8 732 ++nofDisturbingLines;
joachim99@8 733 ++i3;
joachim99@8 734 }
joachim99@8 735
joachim99@8 736 if ( nofDisturbingLines>0 && nofDisturbingLines < d.nofEquals )
joachim99@8 737 {
joachim99@8 738 // Move the disturbing lines up, out of sight.
joachim99@8 739 i3 = i3c;
joachim99@8 740
joachim99@8 741 while( i3 != i3b )
joachim99@8 742 {
joachim99@8 743 if ( (*i3).lineB != -1 )
joachim99@8 744 {
joachim99@8 745 Diff3Line d3l;
joachim99@8 746 d3l.lineB = (*i3).lineB;
joachim99@8 747 (*i3).lineB = -1;
joachim99@8 748
joachim99@8 749
joachim99@8 750 (*i3).bAEqB = false;
joachim99@8 751 (*i3).bBEqC = false;
joachim99@8 752 d3ll.insert( i3c, d3l );
joachim99@8 753 }
joachim99@8 754 ++i3;
joachim99@8 755 }
joachim99@8 756 nofDisturbingLines=0;
joachim99@8 757 }
joachim99@8 758
joachim99@8 759 if ( nofDisturbingLines == 0 )
joachim99@8 760 {
joachim99@8 761 // Yes, the line from B can be moved.
joachim99@8 762 (*i3b).lineB = -1; // This might leave an empty line: removed later.
joachim99@8 763 (*i3b).bAEqB = false;
joachim99@8 764 (*i3b).bAEqC = false;
joachim99@8 765 (*i3b).bBEqC = false;
joachim99@8 766 //(*i3b).lineC = -1;
joachim99@8 767 (*i3c).lineB = lineB;
joachim99@8 768
joachim99@8 769 (*i3c).bBEqC = true;
joachim99@8 770
joachim99@8 771 }
joachim99@8 772
joachim99@8 773 }
joachim99@8 774
joachim99@8 775 else if( i3b1==i3c && !(*i3b).bAEqC)
joachim99@8 776 {
joachim99@8 777 Diff3LineList::iterator i3 = i3b;
joachim99@8 778 int nofDisturbingLines = 0;
joachim99@8 779 while( i3 != i3c && i3!=d3ll.end() )
joachim99@8 780 {
joachim99@8 781 if ( (*i3).lineC != -1 )
joachim99@8 782 ++nofDisturbingLines;
joachim99@8 783 ++i3;
joachim99@8 784 }
joachim99@8 785
joachim99@8 786 if ( nofDisturbingLines>0 && nofDisturbingLines < d.nofEquals )
joachim99@8 787 {
joachim99@8 788 // Move the disturbing lines up, out of sight.
joachim99@8 789 i3 = i3b;
joachim99@8 790 while( i3 != i3c )
joachim99@8 791 {
joachim99@8 792 if ( (*i3).lineC != -1 )
joachim99@8 793 {
joachim99@8 794 Diff3Line d3l;
joachim99@8 795 d3l.lineC = (*i3).lineC;
joachim99@8 796 (*i3).lineC = -1;
joachim99@8 797 (*i3).bAEqC = false;
joachim99@8 798 (*i3).bBEqC = false;
joachim99@8 799 d3ll.insert( i3b, d3l );
joachim99@8 800 }
joachim99@8 801 ++i3;
joachim99@8 802
joachim99@8 803 }
joachim99@8 804 nofDisturbingLines=0;
joachim99@8 805 }
joachim99@8 806
joachim99@8 807 if ( nofDisturbingLines == 0 )
joachim99@8 808 {
joachim99@8 809 // Yes, the line from C can be moved.
joachim99@8 810 (*i3c).lineC = -1; // This might leave an empty line: removed later.
joachim99@8 811 (*i3c).bAEqC = false;
joachim99@8 812 (*i3c).bBEqC = false;
joachim99@8 813 //(*i3c).lineB = -1;
joachim99@8 814 (*i3b).lineC = lineC;
joachim99@8 815 (*i3b).bBEqC = true;
joachim99@8 816 }
joachim99@8 817 }
joachim99@8 818 }
joachim99@8 819
joachim99@8 820 --d.nofEquals;
joachim99@8 821 ++lineB;
joachim99@8 822 ++lineC;
joachim99@8 823 ++i3b;
joachim99@8 824 ++i3c;
joachim99@8 825 }
joachim99@8 826 else if ( d.diff1>0 )
joachim99@8 827 {
joachim99@8 828 Diff3LineList::iterator i3 = i3b;
joachim99@39 829 while( (*i3).lineB!=lineB )
joachim99@8 830 ++i3;
joachim99@8 831 if( i3 != i3b && (*i3).bAEqB==false )
joachim99@8 832 {
joachim99@8 833 // Take this line and move it up as far as possible
joachim99@8 834 d3l.lineB = lineB;
joachim99@8 835 d3ll.insert( i3b, d3l );
joachim99@8 836 (*i3).lineB = -1;
joachim99@8 837 }
joachim99@8 838 else
joachim99@8 839 {
joachim99@8 840 i3b=i3;
joachim99@8 841 }
joachim99@8 842 --d.diff1;
joachim99@8 843 ++lineB;
joachim99@8 844 ++i3b;
joachim99@8 845
joachim99@8 846
joachim99@8 847 if( d.diff2>0 )
joachim99@8 848 {
joachim99@8 849 --d.diff2;
joachim99@8 850 ++lineC;
joachim99@8 851 }
joachim99@8 852 }
joachim99@8 853 else if ( d.diff2>0 )
joachim99@8 854 {
joachim99@8 855 --d.diff2;
joachim99@8 856 ++lineC;
joachim99@8 857 }
joachim99@8 858 }
joachim99@8 859 /*
joachim99@8 860 Diff3LineList::iterator it = d3ll.begin();
joachim99@8 861 int li=0;
joachim99@8 862 for( ; it!=d3ll.end(); ++it, ++li )
joachim99@8 863 {
joachim99@8 864 printf( "%4d %4d %4d %4d A%c=B A%c=C B%c=C\n",
joachim99@8 865 li, (*it).lineA, (*it).lineB, (*it).lineC,
joachim99@8 866 (*it).bAEqB ? '=' : '!', (*it).bAEqC ? '=' : '!', (*it).bBEqC ? '=' : '!' );
joachim99@8 867 }
joachim99@8 868 printf("\n");*/
joachim99@8 869 }
joachim99@8 870
joachim99@8 871 #ifdef _WIN32
joachim99@8 872 using ::equal;
joachim99@8 873 #endif
joachim99@8 874
joachim99@8 875 // Fourth step
joachim99@8 876 void calcDiff3LineListTrim(
joachim99@8 877 Diff3LineList& d3ll, LineData* pldA, LineData* pldB, LineData* pldC
joachim99@8 878 )
joachim99@8 879 {
joachim99@8 880 const Diff3Line d3l_empty;
joachim99@8 881 d3ll.remove( d3l_empty );
joachim99@8 882
joachim99@8 883 Diff3LineList::iterator i3 = d3ll.begin();
joachim99@8 884 Diff3LineList::iterator i3A = d3ll.begin();
joachim99@8 885 Diff3LineList::iterator i3B = d3ll.begin();
joachim99@8 886 Diff3LineList::iterator i3C = d3ll.begin();
joachim99@8 887
joachim99@8 888 int line=0;
joachim99@8 889 int lineA=0;
joachim99@8 890 int lineB=0;
joachim99@8 891 int lineC=0;
joachim99@8 892
joachim99@8 893 // The iterator i3 and the variable line look ahead.
joachim99@8 894 // The iterators i3A, i3B, i3C and corresponding lineA, lineB and lineC stop at empty lines, if found.
joachim99@8 895 // If possible, then the texts from the look ahead will be moved back to the empty places.
joachim99@8 896
joachim99@8 897 for( ; i3!=d3ll.end(); ++i3, ++line )
joachim99@8 898 {
joachim99@8 899 if( line>lineA && (*i3).lineA != -1 && (*i3A).lineB!=-1 && (*i3A).bBEqC &&
joachim99@8 900 ::equal( pldA[(*i3).lineA], pldB[(*i3A).lineB], false ))
joachim99@8 901 {
joachim99@8 902 // Empty space for A. A matches B and C in the empty line. Move it up.
joachim99@8 903 (*i3A).lineA = (*i3).lineA;
joachim99@8 904 (*i3A).bAEqB = true;
joachim99@8 905 (*i3A).bAEqC = true;
joachim99@8 906 (*i3).lineA = -1;
joachim99@8 907 (*i3).bAEqB = false;
joachim99@8 908 (*i3).bAEqC = false;
joachim99@8 909 ++i3A;
joachim99@8 910 ++lineA;
joachim99@8 911 }
joachim99@8 912
joachim99@8 913 if( line>lineB && (*i3).lineB != -1 && (*i3B).lineA!=-1 && (*i3B).bAEqC &&
joachim99@8 914 ::equal( pldB[(*i3).lineB], pldA[(*i3B).lineA], false ))
joachim99@8 915 {
joachim99@8 916 // Empty space for B. B matches A and C in the empty line. Move it up.
joachim99@8 917 (*i3B).lineB = (*i3).lineB;
joachim99@8 918 (*i3B).bAEqB = true;
joachim99@8 919 (*i3B).bBEqC = true;
joachim99@8 920 (*i3).lineB = -1;
joachim99@8 921 (*i3).bAEqB = false;
joachim99@8 922 (*i3).bBEqC = false;
joachim99@8 923 ++i3B;
joachim99@8 924 ++lineB;
joachim99@8 925 }
joachim99@8 926
joachim99@8 927 if( line>lineC && (*i3).lineC != -1 && (*i3C).lineA!=-1 && (*i3C).bAEqB &&
joachim99@8 928 ::equal( pldC[(*i3).lineC], pldA[(*i3C).lineA], false ))
joachim99@8 929 {
joachim99@8 930 // Empty space for C. C matches A and B in the empty line. Move it up.
joachim99@8 931 (*i3C).lineC = (*i3).lineC;
joachim99@8 932 (*i3C).bAEqC = true;
joachim99@8 933 (*i3C).bBEqC = true;
joachim99@8 934 (*i3).lineC = -1;
joachim99@8 935 (*i3).bAEqC = false;
joachim99@8 936 (*i3).bBEqC = false;
joachim99@8 937 ++i3C;
joachim99@8 938 ++lineC;
joachim99@8 939 }
joachim99@8 940
joachim99@8 941 if( line>lineA && (*i3).lineA != -1 && !(*i3).bAEqB && !(*i3).bAEqC )
joachim99@8 942 {
joachim99@8 943 // Empty space for A. A doesn't match B or C. Move it up.
joachim99@8 944 (*i3A).lineA = (*i3).lineA;
joachim99@8 945 (*i3).lineA = -1;
joachim99@8 946 ++i3A;
joachim99@8 947 ++lineA;
joachim99@8 948 }
joachim99@8 949
joachim99@8 950 if( line>lineB && (*i3).lineB != -1 && !(*i3).bAEqB && !(*i3).bBEqC )
joachim99@8 951 {
joachim99@8 952 // Empty space for B. B matches neither A nor C. Move B up.
joachim99@8 953 (*i3B).lineB = (*i3).lineB;
joachim99@8 954 (*i3).lineB = -1;
joachim99@8 955 ++i3B;
joachim99@8 956 ++lineB;
joachim99@8 957 }
joachim99@8 958
joachim99@8 959 if( line>lineC && (*i3).lineC != -1 && !(*i3).bAEqC && !(*i3).bBEqC )
joachim99@8 960 {
joachim99@8 961 // Empty space for C. C matches neither A nor B. Move C up.
joachim99@8 962 (*i3C).lineC = (*i3).lineC;
joachim99@8 963 (*i3).lineC = -1;
joachim99@8 964 ++i3C;
joachim99@8 965 ++lineC;
joachim99@8 966 }
joachim99@8 967
joachim99@8 968 if( line>lineA && line>lineB && (*i3).lineA != -1 && (*i3).bAEqB && !(*i3).bAEqC )
joachim99@8 969 {
joachim99@8 970 // Empty space for A and B. A matches B, but not C. Move A & B up.
joachim99@8 971 Diff3LineList::iterator i = lineA > lineB ? i3A : i3B;
joachim99@8 972 int l = lineA > lineB ? lineA : lineB;
joachim99@8 973
joachim99@8 974 (*i).lineA = (*i3).lineA;
joachim99@8 975 (*i).lineB = (*i3).lineB;
joachim99@8 976 (*i).bAEqB = true;
joachim99@8 977
joachim99@8 978 (*i3).lineA = -1;
joachim99@8 979 (*i3).lineB = -1;
joachim99@8 980 (*i3).bAEqB = false;
joachim99@8 981 i3A = i;
joachim99@8 982 i3B = i;
joachim99@8 983 ++i3A;
joachim99@8 984 ++i3B;
joachim99@8 985 lineA=l+1;
joachim99@8 986 lineB=l+1;
joachim99@8 987 }
joachim99@8 988 else if( line>lineA && line>lineC && (*i3).lineA != -1 && (*i3).bAEqC && !(*i3).bAEqB )
joachim99@8 989 {
joachim99@8 990 // Empty space for A and C. A matches C, but not B. Move A & C up.
joachim99@8 991 Diff3LineList::iterator i = lineA > lineC ? i3A : i3C;
joachim99@8 992 int l = lineA > lineC ? lineA : lineC;
joachim99@8 993 (*i).lineA = (*i3).lineA;
joachim99@8 994 (*i).lineC = (*i3).lineC;
joachim99@8 995 (*i).bAEqC = true;
joachim99@8 996
joachim99@8 997 (*i3).lineA = -1;
joachim99@8 998 (*i3).lineC = -1;
joachim99@8 999 (*i3).bAEqC = false;
joachim99@8 1000 i3A = i;
joachim99@8 1001 i3C = i;
joachim99@8 1002 ++i3A;
joachim99@8 1003 ++i3C;
joachim99@8 1004 lineA=l+1;
joachim99@8 1005 lineC=l+1;
joachim99@8 1006 }
joachim99@8 1007 else if( line>lineB && line>lineC && (*i3).lineB != -1 && (*i3).bBEqC && !(*i3).bAEqC )
joachim99@8 1008 {
joachim99@8 1009 // Empty space for B and C. B matches C, but not A. Move B & C up.
joachim99@8 1010 Diff3LineList::iterator i = lineB > lineC ? i3B : i3C;
joachim99@8 1011 int l = lineB > lineC ? lineB : lineC;
joachim99@8 1012 (*i).lineB = (*i3).lineB;
joachim99@8 1013 (*i).lineC = (*i3).lineC;
joachim99@8 1014 (*i).bBEqC = true;
joachim99@8 1015
joachim99@8 1016 (*i3).lineB = -1;
joachim99@8 1017 (*i3).lineC = -1;
joachim99@8 1018 (*i3).bBEqC = false;
joachim99@8 1019 i3B = i;
joachim99@8 1020 i3C = i;
joachim99@8 1021 ++i3B;
joachim99@8 1022 ++i3C;
joachim99@8 1023 lineB=l+1;
joachim99@8 1024 lineC=l+1;
joachim99@8 1025 }
joachim99@8 1026
joachim99@8 1027 if ( (*i3).lineA != -1 )
joachim99@8 1028 {
joachim99@8 1029 lineA = line+1;
joachim99@8 1030 i3A = i3;
joachim99@8 1031 ++i3A;
joachim99@8 1032 }
joachim99@8 1033 if ( (*i3).lineB != -1 )
joachim99@8 1034 {
joachim99@8 1035 lineB = line+1;
joachim99@8 1036 i3B = i3;
joachim99@8 1037 ++i3B;
joachim99@8 1038 }
joachim99@8 1039 if ( (*i3).lineC != -1 )
joachim99@8 1040 {
joachim99@8 1041 lineC = line+1;
joachim99@8 1042 i3C = i3;
joachim99@8 1043 ++i3C;
joachim99@8 1044 }
joachim99@8 1045 }
joachim99@8 1046
joachim99@8 1047 d3ll.remove( d3l_empty );
joachim99@8 1048
joachim99@8 1049 /*
joachim99@8 1050
joachim99@8 1051 Diff3LineList::iterator it = d3ll.begin();
joachim99@8 1052 int li=0;
joachim99@8 1053 for( ; it!=d3ll.end(); ++it, ++li )
joachim99@8 1054 {
joachim99@8 1055 printf( "%4d %4d %4d %4d A%c=B A%c=C B%c=C\n",
joachim99@8 1056 li, (*it).lineA, (*it).lineB, (*it).lineC,
joachim99@8 1057 (*it).bAEqB ? '=' : '!', (*it).bAEqC ? '=' : '!', (*it).bBEqC ? '=' : '!' );
joachim99@8 1058
joachim99@8 1059 }
joachim99@8 1060 */
joachim99@8 1061 }
joachim99@8 1062
joachim99@51 1063 void calcWhiteDiff3Lines(
joachim99@8 1064 Diff3LineList& d3ll, LineData* pldA, LineData* pldB, LineData* pldC
joachim99@8 1065 )
joachim99@8 1066 {
joachim99@8 1067 Diff3LineList::iterator i3 = d3ll.begin();
joachim99@8 1068
joachim99@8 1069 for( ; i3!=d3ll.end(); ++i3 )
joachim99@8 1070 {
joachim99@51 1071 i3->bWhiteLineA = ( (*i3).lineA == -1 || pldA[(*i3).lineA].whiteLine() || pldA[(*i3).lineA].bContainsPureComment );
joachim99@51 1072 i3->bWhiteLineB = ( (*i3).lineB == -1 || pldB[(*i3).lineB].whiteLine() || pldB[(*i3).lineB].bContainsPureComment );
joachim99@51 1073 i3->bWhiteLineC = ( (*i3).lineC == -1 || pldC[(*i3).lineC].whiteLine() || pldC[(*i3).lineC].bContainsPureComment );
joachim99@8 1074 }
joachim99@8 1075 }
joachim99@8 1076
joachim99@8 1077 // Just make sure that all input lines are in the output too, exactly once.
joachim99@8 1078 void debugLineCheck( Diff3LineList& d3ll, int size, int idx )
joachim99@8 1079 {
joachim99@8 1080 Diff3LineList::iterator it = d3ll.begin();
joachim99@8 1081 int i=0;
joachim99@8 1082
joachim99@8 1083 for ( it = d3ll.begin(); it!= d3ll.end(); ++it )
joachim99@8 1084 {
joachim99@53 1085 int l=0;
joachim99@8 1086 if (idx==1) l=(*it).lineA;
joachim99@8 1087 else if (idx==2) l=(*it).lineB;
joachim99@8 1088 else if (idx==3) l=(*it).lineC;
joachim99@8 1089 else assert(false);
joachim99@8 1090
joachim99@8 1091 if ( l!=-1 )
joachim99@8 1092 {
joachim99@8 1093 if( l!=i )
joachim99@8 1094 {
joachim99@8 1095 KMessageBox::error(0, i18n(
joachim99@8 1096 "Data loss error:\n"
joachim99@8 1097 "If it is reproducable please contact the author.\n"
joachim99@51 1098 ), i18n("Severe Internal Error") );
joachim99@8 1099 assert(false);
joachim99@8 1100 std::cerr << "Severe Internal Error.\n";
joachim99@8 1101 ::exit(-1);
joachim99@8 1102 }
joachim99@8 1103 ++i;
joachim99@8 1104 }
joachim99@8 1105 }
joachim99@8 1106
joachim99@8 1107 if( size!=i )
joachim99@8 1108 {
joachim99@8 1109 KMessageBox::error(0, i18n(
joachim99@8 1110 "Data loss error:\n"
joachim99@8 1111 "If it is reproducable please contact the author.\n"
joachim99@51 1112 ), i18n("Severe Internal Error") );
joachim99@8 1113 assert(false);
joachim99@8 1114 std::cerr << "Severe Internal Error.\n";
joachim99@8 1115 ::exit(-1);
joachim99@8 1116 }
joachim99@8 1117 }
joachim99@8 1118
joachim99@51 1119 inline bool equal( char c1, char c2, bool /*bStrict*/ )
joachim99@51 1120 {
joachim99@51 1121 // If bStrict then white space doesn't match
joachim99@51 1122
joachim99@51 1123 //if ( bStrict && ( c1==' ' || c1=='\t' ) )
joachim99@51 1124 // return false;
joachim99@51 1125
joachim99@51 1126 return c1==c2;
joachim99@51 1127 }
joachim99@51 1128
joachim99@51 1129
joachim99@51 1130 // My own diff-invention:
joachim99@51 1131 template <class T>
joachim99@51 1132 void calcDiff( const T* p1, int size1, const T* p2, int size2, DiffList& diffList, int match, int maxSearchRange )
joachim99@51 1133 {
joachim99@51 1134 diffList.clear();
joachim99@51 1135
joachim99@51 1136 const T* p1start = p1;
joachim99@51 1137 const T* p2start = p2;
joachim99@51 1138 const T* p1end=p1+size1;
joachim99@51 1139 const T* p2end=p2+size2;
joachim99@51 1140 for(;;)
joachim99@51 1141 {
joachim99@51 1142 int nofEquals = 0;
joachim99@51 1143 while( p1!=p1end && p2!=p2end && equal(*p1, *p2, false) )
joachim99@51 1144 {
joachim99@51 1145 ++p1;
joachim99@51 1146 ++p2;
joachim99@51 1147 ++nofEquals;
joachim99@51 1148 }
joachim99@51 1149
joachim99@51 1150 bool bBestValid=false;
joachim99@51 1151 int bestI1=0;
joachim99@51 1152 int bestI2=0;
joachim99@51 1153 int i1=0;
joachim99@51 1154 int i2=0;
joachim99@51 1155 for( i1=0; ; ++i1 )
joachim99@51 1156 {
joachim99@51 1157 if ( &p1[i1]==p1end || ( bBestValid && i1>= bestI1+bestI2))
joachim99@51 1158 {
joachim99@51 1159 break;
joachim99@51 1160 }
joachim99@51 1161 for(i2=0;i2<maxSearchRange;++i2)
joachim99@51 1162 {
joachim99@51 1163 if( &p2[i2]==p2end || ( bBestValid && i1+i2>=bestI1+bestI2) )
joachim99@51 1164 {
joachim99@51 1165 break;
joachim99@51 1166 }
joachim99@51 1167 else if( equal( p2[i2], p1[i1], true ) &&
joachim99@51 1168 ( match==1 || abs(i1-i2)<3 || ( &p2[i2+1]==p2end && &p1[i1+1]==p1end ) ||
joachim99@51 1169 ( &p2[i2+1]!=p2end && &p1[i1+1]!=p1end && equal( p2[i2+1], p1[i1+1], false ))
joachim99@51 1170 )
joachim99@51 1171 )
joachim99@51 1172 {
joachim99@51 1173 if ( i1+i2 < bestI1+bestI2 || bBestValid==false )
joachim99@51 1174 {
joachim99@51 1175 bestI1 = i1;
joachim99@51 1176 bestI2 = i2;
joachim99@51 1177 bBestValid = true;
joachim99@51 1178 break;
joachim99@51 1179 }
joachim99@51 1180 }
joachim99@51 1181 }
joachim99@51 1182 }
joachim99@51 1183
joachim99@51 1184 // The match was found using the strict search. Go back if there are non-strict
joachim99@51 1185 // matches.
joachim99@51 1186 while( bestI1>=1 && bestI2>=1 && equal( p1[bestI1-1], p2[bestI2-1], false ) )
joachim99@51 1187 {
joachim99@51 1188 --bestI1;
joachim99@51 1189 --bestI2;
joachim99@51 1190 }
joachim99@51 1191
joachim99@51 1192
joachim99@51 1193 bool bEndReached = false;
joachim99@51 1194 if (bBestValid)
joachim99@51 1195 {
joachim99@51 1196 // continue somehow
joachim99@51 1197 Diff d(nofEquals, bestI1, bestI2);
joachim99@51 1198 diffList.push_back( d );
joachim99@51 1199
joachim99@51 1200 p1 += bestI1;
joachim99@51 1201 p2 += bestI2;
joachim99@51 1202 }
joachim99@51 1203 else
joachim99@51 1204 {
joachim99@51 1205 // Nothing else to match.
joachim99@51 1206 Diff d(nofEquals, p1end-p1, p2end-p2);
joachim99@51 1207 diffList.push_back( d );
joachim99@51 1208
joachim99@51 1209 bEndReached = true; //break;
joachim99@51 1210 }
joachim99@51 1211
joachim99@51 1212 // Sometimes the algorithm that chooses the first match unfortunately chooses
joachim99@51 1213 // a match where later actually equal parts don't match anymore.
joachim99@51 1214 // A different match could be achieved, if we start at the end.
joachim99@51 1215 // Do it, if it would be a better match.
joachim99@51 1216 int nofUnmatched = 0;
joachim99@51 1217 const T* pu1 = p1-1;
joachim99@51 1218 const T* pu2 = p2-1;
joachim99@51 1219 while ( pu1>=p1start && pu2>=p2start && equal( *pu1, *pu2, false ) )
joachim99@51 1220 {
joachim99@51 1221 ++nofUnmatched;
joachim99@51 1222 --pu1;
joachim99@51 1223 --pu2;
joachim99@51 1224 }
joachim99@51 1225
joachim99@51 1226 Diff d = diffList.back();
joachim99@51 1227 if ( nofUnmatched > 0 )
joachim99@51 1228 {
joachim99@51 1229 // We want to go backwards the nofUnmatched elements and redo
joachim99@51 1230 // the matching
joachim99@51 1231 d = diffList.back();
joachim99@51 1232 Diff origBack = d;
joachim99@51 1233 diffList.pop_back();
joachim99@51 1234
joachim99@51 1235 while ( nofUnmatched > 0 )
joachim99@51 1236 {
joachim99@51 1237 if ( d.diff1 > 0 && d.diff2 > 0 )
joachim99@51 1238 {
joachim99@51 1239 --d.diff1;
joachim99@51 1240 --d.diff2;
joachim99@51 1241 --nofUnmatched;
joachim99@51 1242 }
joachim99@51 1243 else if ( d.nofEquals > 0 )
joachim99@51 1244 {
joachim99@51 1245 --d.nofEquals;
joachim99@51 1246 --nofUnmatched;
joachim99@51 1247 }
joachim99@51 1248
joachim99@51 1249 if ( d.nofEquals==0 && (d.diff1==0 || d.diff2==0) && nofUnmatched>0 )
joachim99@51 1250 {
joachim99@51 1251 if ( diffList.empty() )
joachim99@51 1252 break;
joachim99@51 1253 d.nofEquals += diffList.back().nofEquals;
joachim99@51 1254 d.diff1 += diffList.back().diff1;
joachim99@51 1255 d.diff2 += diffList.back().diff2;
joachim99@51 1256 diffList.pop_back();
joachim99@51 1257 bEndReached = false;
joachim99@51 1258 }
joachim99@51 1259 }
joachim99@51 1260
joachim99@51 1261 if ( bEndReached )
joachim99@51 1262 diffList.push_back( origBack );
joachim99@51 1263 else
joachim99@51 1264 {
joachim99@51 1265
joachim99@51 1266 p1 = pu1 + 1 + nofUnmatched;
joachim99@51 1267 p2 = pu2 + 1 + nofUnmatched;
joachim99@51 1268 diffList.push_back( d );
joachim99@51 1269 }
joachim99@51 1270 }
joachim99@51 1271 if ( bEndReached )
joachim99@51 1272 break;
joachim99@51 1273 }
joachim99@51 1274
joachim99@51 1275 #ifndef NDEBUG
joachim99@51 1276 // Verify difflist
joachim99@51 1277 {
joachim99@51 1278 int l1=0;
joachim99@51 1279 int l2=0;
joachim99@51 1280 DiffList::iterator i;
joachim99@51 1281 for( i = diffList.begin(); i!=diffList.end(); ++i )
joachim99@51 1282 {
joachim99@51 1283 l1+= i->nofEquals + i->diff1;
joachim99@51 1284 l2+= i->nofEquals + i->diff2;
joachim99@51 1285 }
joachim99@51 1286
joachim99@51 1287 //if( l1!=p1-p1start || l2!=p2-p2start )
joachim99@51 1288 if( l1!=size1 || l2!=size2 )
joachim99@51 1289 assert( false );
joachim99@51 1290 }
joachim99@51 1291 #endif
joachim99@51 1292 }
joachim99@8 1293
joachim99@8 1294 void fineDiff(
joachim99@8 1295 Diff3LineList& diff3LineList,
joachim99@8 1296 int selector,
joachim99@8 1297 LineData* v1,
joachim99@8 1298 LineData* v2,
joachim99@8 1299 bool& bTextsTotalEqual
joachim99@8 1300 )
joachim99@8 1301 {
joachim99@8 1302 // Finetuning: Diff each line with deltas
joachim99@51 1303 int maxSearchLength=500;
joachim99@8 1304 Diff3LineList::iterator i;
joachim99@8 1305 int k1=0;
joachim99@8 1306 int k2=0;
joachim99@8 1307 bTextsTotalEqual = true;
joachim99@8 1308 int listSize = diff3LineList.size();
joachim99@8 1309 int listIdx = 0;
joachim99@8 1310 for( i= diff3LineList.begin(); i!= diff3LineList.end(); ++i)
joachim99@8 1311 {
joachim99@8 1312 if (selector==1){ k1=i->lineA; k2=i->lineB; }
joachim99@8 1313 else if (selector==2){ k1=i->lineB; k2=i->lineC; }
joachim99@8 1314 else if (selector==3){ k1=i->lineC; k2=i->lineA; }
joachim99@8 1315 else assert(false);
joachim99@8 1316 if( k1==-1 && k2!=-1 || k1!=-1 && k2==-1 ) bTextsTotalEqual=false;
joachim99@8 1317 if( k1!=-1 && k2!=-1 )
joachim99@8 1318 {
joachim99@8 1319 if ( v1[k1].size != v2[k2].size || memcmp( v1[k1].pLine, v2[k2].pLine, v1[k1].size)!=0 )
joachim99@8 1320 {
joachim99@8 1321 bTextsTotalEqual = false;
joachim99@8 1322 DiffList* pDiffList = new DiffList;
joachim99@8 1323 // std::cout << std::string( v1[k1].pLine, v1[k1].size ) << "\n";
joachim99@8 1324 calcDiff( v1[k1].pLine, v1[k1].size, v2[k2].pLine, v2[k2].size, *pDiffList, 2, maxSearchLength );
joachim99@8 1325
joachim99@8 1326 // Optimize the diff list.
joachim99@8 1327 DiffList::iterator dli;
joachim99@8 1328 for( dli = pDiffList->begin(); dli!=pDiffList->end(); ++dli)
joachim99@8 1329 {
joachim99@8 1330 if( dli->nofEquals < 4 && (dli->diff1>0 || dli->diff2>0) )
joachim99@8 1331 {
joachim99@8 1332 dli->diff1 += dli->nofEquals;
joachim99@8 1333 dli->diff2 += dli->nofEquals;
joachim99@8 1334 dli->nofEquals = 0;
joachim99@8 1335 }
joachim99@8 1336 }
joachim99@8 1337
joachim99@8 1338 if (selector==1){ delete (*i).pFineAB; (*i).pFineAB = pDiffList; }
joachim99@8 1339 else if (selector==2){ delete (*i).pFineBC; (*i).pFineBC = pDiffList; }
joachim99@8 1340 else if (selector==3){ delete (*i).pFineCA; (*i).pFineCA = pDiffList; }
joachim99@8 1341 else assert(false);
joachim99@8 1342 }
joachim99@51 1343
joachim99@51 1344 if ( (v1[k1].bContainsPureComment || v1[k1].whiteLine()) && (v2[k2].bContainsPureComment || v2[k2].whiteLine()))
joachim99@51 1345 {
joachim99@51 1346 if (selector==1){ i->bAEqB = true; }
joachim99@51 1347 else if (selector==2){ i->bBEqC = true; }
joachim99@51 1348 else if (selector==3){ i->bAEqC = true; }
joachim99@51 1349 else assert(false);
joachim99@51 1350 }
joachim99@8 1351 }
joachim99@8 1352 ++listIdx;
joachim99@8 1353 g_pProgressDialog->setSubCurrent(double(listIdx)/listSize);
joachim99@8 1354 }
joachim99@8 1355 }
joachim99@8 1356
joachim99@8 1357
joachim99@8 1358 // Convert the list to a vector of pointers
joachim99@8 1359 void calcDiff3LineVector( const Diff3LineList& d3ll, Diff3LineVector& d3lv )
joachim99@8 1360 {
joachim99@8 1361 d3lv.resize( d3ll.size() );
joachim99@8 1362 Diff3LineList::const_iterator i;
joachim99@8 1363 int j=0;
joachim99@8 1364 for( i= d3ll.begin(); i!= d3ll.end(); ++i, ++j)
joachim99@8 1365 {
joachim99@8 1366 d3lv[j] = &(*i);
joachim99@8 1367 }
joachim99@8 1368 assert( j==(int)d3lv.size() );
joachim99@8 1369 }
joachim99@8 1370
joachim99@8 1371
joachim99@8 1372 #include "diff.moc"