1
/**************************************************************************
4
** begin : Sun Aug 4 15:05:35 2002
5
** copyright : (C) 2002-2003 by Otto Bruggeman
6
** email : otto.bruggeman@home.nl
8
***************************************************************************/
9
/***************************************************************************
11
** This program is free software; you can redistribute it and/or modify
12
** it under the terms of the GNU General Public License as published by
13
** the Free Software Foundation; either version 2 of the License, or
14
** ( at your option ) any later version.
16
***************************************************************************/
18
//#include <qstring.h>
22
#include "diffmodel.h"
24
#include "difference.h"
26
#include "parserbase.h"
28
using namespace Diff2;
30
ParserBase::ParserBase( const QStringList& diff ) :
34
m_diffIterator( m_diffLines.begin() ),
38
// kdDebug(8101) << diff << endl;
39
// kdDebug(8101) << m_diffLines << endl;
40
m_models = new QPtrList<DiffModel>;
42
// used in contexthunkheader
43
m_contextHunkHeader1.setPattern( "^\\*{15} ?(.*)$" ); // capture is for function name
44
m_contextHunkHeader2.setPattern( "^\\*\\*\\* ([0-9]+),([0-9]+) \\*\\*\\*\\*$" );
45
// used in contexthunkbody
46
m_contextHunkHeader3.setPattern( "^--- ([0-9]+),([0-9]+) ----$" );
48
m_contextHunkBodyRemoved.setPattern( "^- (.*)$" );
49
m_contextHunkBodyAdded.setPattern ( "^\\+ (.*)$" );
50
m_contextHunkBodyChanged.setPattern( "^! (.*)$" );
51
m_contextHunkBodyContext.setPattern( "^ (.*)$" );
52
m_contextHunkBodyLine.setPattern ( "^[-\\+! ] (.*)$" );
54
// This regexp sucks... i'll see what happens
55
m_normalDiffHeader.setPattern( "^diff (?:(?:-|--)[a-zA-Z0-9=\\\"]+ )*(?:|-- +)(.*) +(.*)$" );
57
m_normalHunkHeaderAdded.setPattern ( "^([0-9]+)a([0-9]+)(|,[0-9]+)(.*)$" );
58
m_normalHunkHeaderRemoved.setPattern( "^([0-9]+)(|,[0-9]+)d([0-9]+)(.*)$" );
59
m_normalHunkHeaderChanged.setPattern( "^([0-9]+)(|,[0-9]+)c([0-9]+)(|,[0-9]+)(.*)$" );
61
m_normalHunkBodyRemoved.setPattern ( "^< (.*)$" );
62
m_normalHunkBodyAdded.setPattern ( "^> (.*)$" );
63
m_normalHunkBodyDivider.setPattern ( "^---$" );
65
m_unifiedDiffHeader1.setPattern ( "^--- ([^\\t]+)\\t([^\\t]+)(?:\\t?)(.*)$" );
66
m_unifiedDiffHeader2.setPattern ( "^\\+\\+\\+ ([^\\t]+)\\t([^\\t]+)(?:\\t?)(.*)$" );
67
m_unifiedHunkHeader.setPattern ( "^@@ -([0-9]+)(|,([0-9]+)) \\+([0-9]+)(|,([0-9]+)) @@(?: ?)(.*)$" );
68
m_unifiedHunkBodyAdded.setPattern ( "^\\+(.*)$" );
69
m_unifiedHunkBodyRemoved.setPattern( "^-(.*)$" );
70
m_unifiedHunkBodyContext.setPattern( "^ (.*)$" );
71
m_unifiedHunkBodyLine.setPattern ( "^([-+ ])(.*)$" );
74
ParserBase::~ParserBase()
78
enum Kompare::Format ParserBase::determineFormat()
80
// Write your own format detection routine damn it :)
81
return Kompare::UnknownFormat;
84
QPtrList<DiffModel>* ParserBase::parse()
86
switch( determineFormat() )
88
case Kompare::Context :
89
return parseContext();
92
case Kompare::Normal :
96
case Kompare::Unified :
97
return parseUnified();
98
default: // Unknown and SideBySide for now
103
bool ParserBase::parseContextDiffHeader()
105
kdDebug(8101) << "ParserBase::parseContextDiffHeader()" << endl;
108
while ( m_diffIterator != m_diffLines.end() )
110
if ( !m_contextDiffHeader1.exactMatch( *(m_diffIterator)++ ) )
114
kdDebug(8101) << "Matched length Header1 = " << m_contextDiffHeader1.matchedLength() << endl;
115
kdDebug(8101) << "Matched string Header1 = " << m_contextDiffHeader1.cap( 0 ) << endl;
116
if ( m_diffIterator != m_diffLines.end() && m_contextDiffHeader2.exactMatch( *m_diffIterator ) )
118
kdDebug(8101) << "Matched length Header2 = " << m_contextDiffHeader2.matchedLength() << endl;
119
kdDebug(8101) << "Matched string Header2 = " << m_contextDiffHeader2.cap( 0 ) << endl;
121
m_currentModel = new DiffModel();
122
m_currentModel->setSourceFile ( m_contextDiffHeader1.cap( 1 ) );
123
m_currentModel->setSourceTimestamp ( m_contextDiffHeader1.cap( 2 ) );
124
m_currentModel->setSourceRevision ( m_contextDiffHeader1.cap( 4 ) );
125
m_currentModel->setDestinationFile ( m_contextDiffHeader2.cap( 1 ) );
126
m_currentModel->setDestinationTimestamp( m_contextDiffHeader2.cap( 2 ) );
127
m_currentModel->setDestinationRevision ( m_contextDiffHeader2.cap( 4 ) );
128
m_currentModel->setIndex( m_modelIndex++ );
138
// We're screwed, second line does not match or is not there...
141
// Dont inc the Iterator because the second line might be the first line of
142
// the context header and the first hit was a fluke (impossible imo)
143
// maybe we should return false here because the diff is broken ?
149
bool ParserBase::parseEdDiffHeader()
154
bool ParserBase::parseNormalDiffHeader()
156
kdDebug(8101) << "ParserBase::parseNormalDiffHeader()" << endl;
159
while ( m_diffIterator != m_diffLines.end() )
161
if ( m_normalDiffHeader.exactMatch( *(m_diffIterator)++ ) )
163
// kdDebug(8101) << "Matched length Header = " << m_normalDiffHeader.matchedLength() << endl;
164
// kdDebug(8101) << "Matched string Header = " << m_normalDiffHeader.cap( 0 ) << endl;
166
m_currentModel = new DiffModel();
167
m_currentModel->setSourceFile ( m_normalDiffHeader.cap( 1 ) );
168
m_currentModel->setDestinationFile ( m_normalDiffHeader.cap( 2 ) );
169
m_currentModel->setIndex( m_modelIndex++ );
181
bool ParserBase::parseRCSDiffHeader()
186
bool ParserBase::parseUnifiedDiffHeader()
188
kdDebug(8101) << "ParserBase::parseUnifiedDiffHeader()" << endl;
191
while ( m_diffIterator != m_diffLines.end() ) // dont assume we start with the diffheader1 line
193
if ( !m_unifiedDiffHeader1.exactMatch( *(m_diffIterator)++ ) )
197
kdDebug(8101) << "Matched length Header1 = " << m_unifiedDiffHeader1.matchedLength() << endl;
198
kdDebug(8101) << "Matched string Header1 = " << m_unifiedDiffHeader1.cap( 0 ) << endl;
199
if ( m_diffIterator != m_diffLines.end() && m_unifiedDiffHeader2.exactMatch( *m_diffIterator ) )
201
m_currentModel = new DiffModel();
202
m_currentModel->setSourceFile( m_unifiedDiffHeader1.cap( 1 ) );
203
m_currentModel->setSourceTimestamp( m_unifiedDiffHeader1.cap( 2 ) );
204
m_currentModel->setSourceRevision( m_unifiedDiffHeader1.cap( 4 ) );
205
m_currentModel->setDestinationFile( m_unifiedDiffHeader2.cap( 1 ) );
206
m_currentModel->setDestinationTimestamp( m_unifiedDiffHeader2.cap( 2 ) );
207
m_currentModel->setDestinationRevision( m_unifiedDiffHeader2.cap( 4 ) );
208
m_currentModel->setIndex( m_modelIndex++ );
218
// We're screwed, second line does not match or is not there...
226
bool ParserBase::parseContextHunkHeader()
228
kdDebug(8101) << "ParserBase::parseContextHunkHeader()" << endl;
230
if ( m_diffIterator == m_diffLines.end() )
233
if ( !m_contextHunkHeader1.exactMatch( *(m_diffIterator) ) )
234
return false; // big fat trouble, aborting...
238
if ( m_diffIterator == m_diffLines.end() )
241
if ( !m_contextHunkHeader2.exactMatch( *(m_diffIterator) ) )
242
return false; // big fat trouble, aborting...
249
bool ParserBase::parseEdHunkHeader()
254
bool ParserBase::parseNormalHunkHeader()
256
// kdDebug(8101) << "ParserBase::parseNormalHunkHeader()" << endl;
257
if ( m_diffIterator != m_diffLines.end() )
259
// kdDebug(8101) << "Header = " << *m_diffIterator << endl;
260
if ( m_normalHunkHeaderAdded.exactMatch( *m_diffIterator ) )
262
m_normalDiffType = Difference::Insert;
264
else if ( m_normalHunkHeaderRemoved.exactMatch( *m_diffIterator ) )
266
m_normalDiffType = Difference::Delete;
268
else if ( m_normalHunkHeaderChanged.exactMatch( *m_diffIterator ) )
270
m_normalDiffType = Difference::Change;
282
bool ParserBase::parseRCSHunkHeader()
287
bool ParserBase::parseUnifiedHunkHeader()
289
kdDebug(8101) << "ParserBase::parseUnifiedHunkHeader()" << endl;
291
if ( m_unifiedHunkHeader.exactMatch( *m_diffIterator ) )
298
kdDebug(8101) << "This is not a unified hunk header : " << (*m_diffIterator) << endl;
304
bool ParserBase::parseContextHunkBody()
306
kdDebug(8101) << "ParserBase::parseContextHunkBody()" << endl;
308
// Storing the src part of the hunk for later use
309
QStringList oldLines;
310
for( ; m_diffIterator != m_diffLines.end() && m_contextHunkBodyLine.exactMatch( *m_diffIterator ); ++m_diffIterator ) {
311
oldLines.append( *m_diffIterator );
314
if( !m_contextHunkHeader3.exactMatch( *(m_diffIterator)++ ) )
317
// Storing the dest part of the hunk for later use
318
QStringList newLines;
319
for( ; m_diffIterator != m_diffLines.end() && m_contextHunkBodyLine.exactMatch( *m_diffIterator ); ++m_diffIterator ) {
320
newLines.append( *m_diffIterator );
323
QString function = m_contextHunkHeader1.cap( 1 );
324
kdDebug() << "Captured function: " << function << endl;
325
int linenoA = m_contextHunkHeader2.cap( 1 ).toInt();
326
kdDebug() << "Source line number: " << linenoA << endl;
327
int linenoB = m_contextHunkHeader3.cap( 1 ).toInt();
328
kdDebug() << "Dest line number: " << linenoB << endl;
330
DiffHunk* hunk = new DiffHunk( linenoA, linenoB, function );
332
m_currentModel->addHunk( hunk );
334
QStringList::Iterator oldIt = oldLines.begin();
335
QStringList::Iterator newIt = newLines.begin();
338
while( oldIt != oldLines.end() || newIt != newLines.end() )
340
if( oldIt != oldLines.end() && m_contextHunkBodyRemoved.exactMatch( *oldIt ) )
342
kdDebug(8101) << "Delete: " << endl;
343
diff = new Difference( linenoA, linenoB );
344
diff->setType( Difference::Delete );
345
diff->setIndex( m_diffIndex++ );
346
m_currentModel->addDiff( diff );
347
kdDebug(8101) << "Difference added" << endl;
349
for( ; oldIt != oldLines.end() && m_contextHunkBodyRemoved.exactMatch( *oldIt ); ++oldIt )
351
kdDebug(8101) << " " << m_contextHunkBodyRemoved.cap( 1 ) << endl;
352
diff->addSourceLine( m_contextHunkBodyRemoved.cap( 1 ) );
357
else if( newIt != newLines.end() && m_contextHunkBodyAdded.exactMatch( *newIt ) )
359
kdDebug(8101) << "Insert: " << endl;
360
diff = new Difference( linenoA, linenoB );
361
diff->setType( Difference::Insert );
362
diff->setIndex( m_diffIndex++ );
363
m_currentModel->addDiff( diff );
364
kdDebug(8101) << "Difference added" << endl;
366
for( ; newIt != newLines.end() && m_contextHunkBodyAdded.exactMatch( *newIt ); ++newIt )
368
kdDebug(8101) << " " << m_contextHunkBodyAdded.cap( 1 ) << endl;
369
diff->addDestinationLine( m_contextHunkBodyAdded.cap( 1 ) );
374
else if( ( oldIt != oldLines.end() && m_contextHunkBodyContext.exactMatch( *oldIt ) ) ||
375
( newIt != newLines.end() && m_contextHunkBodyContext.exactMatch( *newIt ) ) )
377
kdDebug(8101) << "Unchanged: " << endl;
378
diff = new Difference( linenoA, linenoB );
379
// Dont add this diff with addDiff to the model... no unchanged differences allowed in there...
380
diff->setType( Difference::Unchanged );
382
while( ( oldIt != oldLines.end() && m_contextHunkBodyContext.exactMatch( *oldIt ) ) &&
383
( newIt != newLines.end() && m_contextHunkBodyContext.exactMatch( *newIt ) ) )
386
if( oldIt != oldLines.end() )
388
l = m_contextHunkBodyContext.cap( 1 );
389
kdDebug(8101) << "old: " << l << endl;
392
if( newIt != newLines.end() )
394
l = m_contextHunkBodyContext.cap( 1 );
395
kdDebug(8101) << "new: " << l << endl;
398
diff->addSourceLine( l );
399
diff->addDestinationLine( l );
405
else if( ( oldIt != oldLines.end() && m_contextHunkBodyChanged.exactMatch( *oldIt ) ) ||
406
( newIt != newLines.end() && m_contextHunkBodyChanged.exactMatch( *newIt ) ) )
408
kdDebug(8101) << "Changed: " << endl;
409
diff = new Difference( linenoA, linenoB );
410
diff->setType( Difference::Change );
411
diff->setIndex( m_diffIndex++ );
412
m_currentModel->addDiff( diff );
413
kdDebug(8101) << "Difference added" << endl;
415
while( oldIt != oldLines.end() && m_contextHunkBodyChanged.exactMatch( *oldIt ) )
417
kdDebug(8101) << " " << m_contextHunkBodyChanged.cap( 1 ) << endl;
418
diff->addSourceLine( m_contextHunkBodyChanged.cap( 1 ) );
422
while( newIt != newLines.end() && m_contextHunkBodyChanged.exactMatch( *newIt ) )
424
kdDebug(8101) << " " << m_contextHunkBodyChanged.cap( 1 ) << endl;
425
diff->addDestinationLine( m_contextHunkBodyChanged.cap( 1 ) );
437
bool ParserBase::parseEdHunkBody()
442
bool ParserBase::parseNormalHunkBody()
444
// kdDebug(8101) << "ParserBase::parseNormalHunkBody" << endl;
446
QString type = QString::null;
448
int linenoA = 0, linenoB = 0;
450
if ( m_normalDiffType == Difference::Insert )
452
linenoA = m_normalHunkHeaderAdded.cap( 1 ).toInt();
453
linenoB = m_normalHunkHeaderAdded.cap( 2 ).toInt();
455
else if ( m_normalDiffType == Difference::Delete )
457
linenoA = m_normalHunkHeaderRemoved.cap( 1 ).toInt();
458
linenoB = m_normalHunkHeaderRemoved.cap( 3 ).toInt();
460
else if ( m_normalDiffType == Difference::Change )
462
linenoA = m_normalHunkHeaderChanged.cap( 1 ).toInt();
463
linenoB = m_normalHunkHeaderChanged.cap( 3 ).toInt();
466
DiffHunk* hunk = new DiffHunk( linenoA, linenoB );
467
m_currentModel->addHunk( hunk );
468
Difference* diff = new Difference( linenoA, linenoB );
469
diff->setIndex( m_diffIndex++ );
471
m_currentModel->addDiff( diff );
473
diff->setType( m_normalDiffType );
475
if ( m_normalDiffType == Difference::Change || m_normalDiffType == Difference::Delete )
476
for( ; m_diffIterator != m_diffLines.end() && m_normalHunkBodyRemoved.exactMatch( *m_diffIterator ); ++m_diffIterator )
478
// kdDebug(8101) << "Line = " << *m_diffIterator << endl;
479
diff->addSourceLine( m_normalHunkBodyRemoved.cap( 1 ) );
481
if ( m_normalDiffType == Difference::Change )
482
if( m_diffIterator != m_diffLines.end() && m_normalHunkBodyDivider.exactMatch( *m_diffIterator ) )
484
// kdDebug(8101) << "Line = " << *m_diffIterator << endl;
489
if ( m_normalDiffType == Difference::Insert || m_normalDiffType == Difference::Change )
490
for( ; m_diffIterator != m_diffLines.end() && m_normalHunkBodyAdded.exactMatch( *m_diffIterator ); ++m_diffIterator )
492
// kdDebug(8101) << "Line = " << *m_diffIterator << endl;
493
diff->addDestinationLine( m_normalHunkBodyAdded.cap( 1 ) );
499
bool ParserBase::parseRCSHunkBody()
504
bool ParserBase::parseUnifiedHunkBody()
506
kdDebug(8101) << "ParserBase::parseUnifiedHunkBody" << endl;
508
int linenoA = 0, linenoB = 0;
510
// Fetching the stuff we need from the hunkheader regexp that was parsed in parseUnifiedHunkHeader();
511
linenoA = m_unifiedHunkHeader.cap( 1 ).toInt();
512
linenoB = m_unifiedHunkHeader.cap( 4 ).toInt();
513
QString function = m_unifiedHunkHeader.cap( 7 );
514
for ( int i = 0; i < 9; i++ )
516
kdDebug(8101) << "Capture " << i << ": " << m_unifiedHunkHeader.cap( i ) << endl;
519
DiffHunk* hunk = new DiffHunk( linenoA, linenoB, function );
520
m_currentModel->addHunk( hunk );
522
while( m_diffIterator != m_diffLines.end() && m_unifiedHunkBodyLine.exactMatch( *m_diffIterator ) )
524
Difference* diff = new Difference( linenoA, linenoB );
525
diff->setIndex( m_diffIndex++ );
528
if( m_unifiedHunkBodyLine.cap( 1 ) == " " )
530
for( ; m_diffIterator != m_diffLines.end() && m_unifiedHunkBodyContext.exactMatch( *m_diffIterator ); ++m_diffIterator ) {
531
diff->addSourceLine( m_unifiedHunkBodyContext.cap( 1 ) );
532
diff->addDestinationLine( m_unifiedHunkBodyContext.cap( 1 ) );
538
{ // This is a real difference, not context
539
for( ; m_diffIterator != m_diffLines.end() && m_unifiedHunkBodyRemoved.exactMatch( *m_diffIterator ); ++m_diffIterator ) {
540
diff->addSourceLine( m_unifiedHunkBodyRemoved.cap( 1 ) );
543
if ( (*m_diffIterator).startsWith( "\\ " ) )
545
for( ; m_diffIterator != m_diffLines.end() && m_unifiedHunkBodyAdded.exactMatch( *m_diffIterator ); ++m_diffIterator ) {
546
diff->addDestinationLine( m_unifiedHunkBodyAdded.cap( 1 ) );
549
if ( (*m_diffIterator).startsWith( "\\ " ) )
551
if ( diff->sourceLineCount() == 0 )
553
diff->setType( Difference::Insert );
554
kdDebug(8101) << "Insert difference" << endl;
556
else if ( diff->destinationLineCount() == 0 )
558
diff->setType( Difference::Delete );
559
kdDebug(8101) << "Delete difference" << endl;
563
diff->setType( Difference::Change );
564
kdDebug(8101) << "Change difference" << endl;
566
// Dont move this up, leave it somewhere in this else part. We dont want to
567
// add context differences to the differences list...
568
m_currentModel->addDiff( diff );
575
QPtrList<DiffModel>* ParserBase::parseContext()
577
while ( parseContextDiffHeader() )
579
while ( parseContextHunkHeader() )
580
parseContextHunkBody();
581
if ( m_currentModel->differenceCount() > 0 )
582
m_models->append( m_currentModel );
585
if ( m_models->count() > 0 )
596
QPtrList<DiffModel>* ParserBase::parseEd()
598
while ( parseEdDiffHeader() )
600
while ( parseEdHunkHeader() )
602
m_models->append( m_currentModel );
605
if ( m_models->count() > 0 )
616
QPtrList<DiffModel>* ParserBase::parseNormal()
618
while ( parseNormalDiffHeader() )
620
while ( parseNormalHunkHeader() )
621
parseNormalHunkBody();
622
m_models->append( m_currentModel );
625
if ( m_models->count() > 0 )
636
QPtrList<DiffModel>* ParserBase::parseRCS()
638
while ( parseRCSDiffHeader() )
640
while ( parseRCSHunkHeader() )
642
m_models->append( m_currentModel );
645
if ( m_models->count() > 0 )
656
QPtrList<DiffModel>* ParserBase::parseUnified()
658
while ( parseUnifiedDiffHeader() )
660
while ( parseUnifiedHunkHeader() )
661
parseUnifiedHunkBody();
662
m_models->append( m_currentModel );
665
if ( m_models->count() > 0 )