annotate kdiff3/src/diff.cpp @ 58:8af4bb9d9a5a

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