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"
|