summaryrefslogtreecommitdiffstats
path: root/kfile-plugins/diff/kfile_diff.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kfile-plugins/diff/kfile_diff.cpp')
-rw-r--r--kfile-plugins/diff/kfile_diff.cpp610
1 files changed, 610 insertions, 0 deletions
diff --git a/kfile-plugins/diff/kfile_diff.cpp b/kfile-plugins/diff/kfile_diff.cpp
new file mode 100644
index 00000000..0f2fa02d
--- /dev/null
+++ b/kfile-plugins/diff/kfile_diff.cpp
@@ -0,0 +1,610 @@
+/**************************************************************************
+** kfile_diff.cpp
+** -------------------
+** begin : Sun Jan 20 23:25:44 2002
+** copyright : (C) 2002-2003 by Otto Bruggeman
+** email : [email protected]
+**
+***************************************************************************/
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+***************************************************************************/
+
+/*
+** Patch by Volker Augustin for empty diff files. Februari 8, 2002
+**
+** Patched to work with CVS from after February 26, 2002 Otto
+**
+** Patched to work with CVS from after March 24, 2002 Otto
+**
+** Added support for Perforce diffs, April 26, 2003 Otto Bruggeman
+**
+** Added support for Subversion diffs, September 11, 2003 Otto Bruggeman
+*/
+
+#include <qcstring.h>
+#include <qdatetime.h>
+#include <qdict.h>
+#include <qfile.h>
+#include <qregexp.h>
+#include <qvalidator.h>
+
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <klocale.h>
+#include <kprocess.h>
+#include <kurl.h>
+
+#include "kfile_diff.h"
+
+K_EXPORT_COMPONENT_FACTORY(kfile_diff, KGenericFactory<KDiffPlugin>("kfile_diff"))
+
+KDiffPlugin::KDiffPlugin(QObject *parent, const char *name,
+ const QStringList &preferredItems)
+ : KFilePlugin(parent, name, preferredItems)
+{
+ kdDebug(7034) << "diff plugin" << endl;
+
+ KFileMimeTypeInfo* info = addMimeTypeInfo( "text/x-diff" );
+
+ KFileMimeTypeInfo::GroupInfo* group;
+ group = addGroupInfo( info, "General", i18n( "General" ) );
+ addItemInfo( group, "Files", i18n( "Files" ), QVariant::UInt );
+ addItemInfo( group, "First", i18n( "First File" ), QVariant::String );
+ addItemInfo( group, "Format", i18n( "Format" ), QVariant::String );
+ addItemInfo( group, "DiffProgram", i18n( "Diff Program" ), QVariant::String );
+ addItemInfo( group, "Hunks", i18n( "Hunks" ), QVariant::UInt );
+ group = addGroupInfo( info, "Statistics", i18n( "Statistics" ) );
+ addItemInfo( group, "Insert", i18n( "Insertions" ), QVariant::UInt );
+ addItemInfo( group, "Modify", i18n( "Changes" ), QVariant::UInt );
+ addItemInfo( group, "Delete", i18n( "Deletions" ), QVariant::UInt );
+}
+
+bool KDiffPlugin::readInfo( KFileMetaInfo& info, uint what )
+{
+ // This is a hack to avoid using the what stuff, since it is not yet implemented
+ what = 0;
+
+ // Used to determine if false or true should be returned
+ bool dataSet = false;
+
+ KFileMetaInfoGroup group;
+
+ QFile file( info.path() );
+ QStringList lines;
+
+ if( file.open( IO_ReadOnly ) )
+ {
+ QTextStream stream( &file );
+ while (!stream.eof())
+ {
+ lines.append( stream.readLine() );
+ }
+ file.close();
+ }
+
+ QString format;
+ QString program;
+
+ enum KDiffPlugin::Format diffFormat;
+ enum KDiffPlugin::DiffProgram diffProgram;
+
+ diffFormat = determineDiffFormat ( lines );
+
+ format = determineI18nedFormat( diffFormat );
+
+ diffProgram = determineDiffProgram( lines );
+
+ program = determineI18nedProgram( diffProgram );
+
+ int numberOfAdditions = 0;
+ int numberOfDeletions = 0;
+ int numberOfChanges = 0;
+ int numberOfHunks = 0;
+ int numberOfFiles = 0;
+
+
+ if ( what != KFileMetaInfo::Fastest )
+ {
+ determineDiffInfo( lines, diffFormat, &numberOfFiles, &numberOfHunks, &numberOfAdditions, &numberOfChanges, &numberOfDeletions );
+ }
+
+ QString filename;
+ QRegExp firstFile( "^Index: (.*)" );
+ QStringList::ConstIterator it = lines.begin();
+
+ it = lines.begin();
+ while ( it != lines.end() )
+ {
+ if ( firstFile.exactMatch( (*it) ) )
+ {
+ filename = firstFile.cap(1);
+ // only interested in the first filename
+ break;
+ }
+ ++it;
+ }
+
+ kdDebug(7034) << "Diff Format : " << format << endl; // i18n-ed but that is not a problem unless i get i18n-ed debug output ah well, we'll figure something out when then happens
+
+ if (what != KFileMetaInfo::Fastest )
+ {
+ // These dont get calculated in fastest mode...
+ kdDebug(7034) << "Number of additions : " << numberOfAdditions << endl;
+ kdDebug(7034) << "Number of deletions : " << numberOfDeletions << endl;
+ kdDebug(7034) << "Number of changes : " << numberOfChanges << endl;
+ kdDebug(7034) << "Number of hunks : " << numberOfHunks << endl;
+ }
+
+ group = appendGroup( info, "General" );
+
+ if ( numberOfFiles != 0 && what != KFileMetaInfo::Fastest )
+ {
+ appendItem( group, "Files", numberOfFiles );
+ dataSet = true;
+ }
+
+ if ( !filename.isEmpty() )
+ {
+ appendItem( group, "First", filename );
+ dataSet = true;
+ }
+
+ if ( !format.isEmpty() )
+ {
+ appendItem( group, "Format", format );
+ dataSet = true;
+ }
+
+ if ( !program.isEmpty() )
+ {
+ appendItem( group, "DiffProgram", program );
+ dataSet = true;
+ }
+
+ if ( numberOfHunks != 0 && what != KFileMetaInfo::Fastest )
+ {
+ appendItem( group, "Hunks", numberOfHunks );
+ dataSet = true;
+ }
+
+ group = appendGroup( info, "Statistics" );
+
+ if ( numberOfAdditions != 0 && what != KFileMetaInfo::Fastest )
+ {
+ appendItem( group, "Insert", numberOfAdditions );
+ dataSet = true;
+ }
+
+ if ( numberOfChanges != 0 && what != KFileMetaInfo::Fastest )
+ {
+ appendItem( group, "Modify", numberOfChanges );
+ dataSet = true;
+ }
+
+ if ( numberOfDeletions != 0 && what != KFileMetaInfo::Fastest )
+ {
+ appendItem( group, "Delete", numberOfDeletions );
+ dataSet = true;
+ }
+
+ return dataSet;
+}
+
+enum KDiffPlugin::Format KDiffPlugin::determineDiffFormat( const QStringList lines ) const
+{
+ QString line;
+
+ if ( lines.count() == 0 )
+ {
+ return KDiffPlugin::Empty;
+ }
+
+ QStringList::ConstIterator it = lines.begin();
+
+ while ( it != lines.end() )
+ {
+ line = (*it);
+ if ( line.find( QRegExp( "^[0-9]+[0-9,]*[acd][0-9]+[0-9,]*$" ), 0 ) == 0 )
+ {
+ return KDiffPlugin::Normal;
+ }
+ else if ( line.find( QRegExp( "^--- " ), 0 ) == 0 )
+ {
+ // unified has first a '^--- ' line, then a '^+++ ' line
+ return KDiffPlugin::Unified;
+ }
+ else if ( line.find( QRegExp( "^\\*\\*\\* [^\\t]+\\t" ), 0 ) == 0 )
+ {
+ // context has first a '^*** ' line, then a '^--- ' line
+ return KDiffPlugin::Context;
+ }
+ else if ( line.find( QRegExp( "^[acd][0-9]+ [0-9]+" ), 0 ) == 0 )
+ {
+ return KDiffPlugin::RCS;
+ }
+ else if ( line.find( QRegExp( "^[0-9]+[0-9,]*[acd]" ), 0 ) == 0 )
+ {
+ return KDiffPlugin::Ed;
+ }
+ ++it;
+ }
+ return KDiffPlugin::Unknown;
+}
+
+enum KDiffPlugin::DiffProgram KDiffPlugin::determineDiffProgram( const QStringList lines ) const
+{
+ if ( lines.count() == 0 )
+ {
+ return KDiffPlugin::Undeterminable;
+ }
+
+ QStringList::ConstIterator it = lines.begin();
+ // very crude, might need some more refining
+ QRegExp diffRE( "^diff .*" );
+ QRegExp p4sRE("^==== ");
+
+ bool indexFound = false;
+
+ while ( it != lines.end() )
+ {
+ if ( (*it).startsWith( "Index:" ) )
+ indexFound = true;
+ else if ( (*it).startsWith( "retrieving revision") )
+ return KDiffPlugin::CVSDiff;
+ else if ( diffRE.exactMatch( *it ) )
+ return KDiffPlugin::Diff;
+ else if ( p4sRE.exactMatch( *it ) )
+ return KDiffPlugin::Perforce;
+
+ ++it;
+ }
+
+ if ( indexFound ) // but no "retrieving revision" found like only cvs diff adds.
+ return KDiffPlugin::SubVersion;
+
+ return KDiffPlugin::Undeterminable;
+}
+
+const QString KDiffPlugin::determineI18nedFormat( enum KDiffPlugin::Format diffFormat ) const
+{
+ QString format;
+ switch( diffFormat )
+ {
+ case KDiffPlugin::Context:
+ format = i18n( "Context" );
+ break;
+ case KDiffPlugin::Ed:
+ format = i18n( "Ed" );
+ break;
+ case KDiffPlugin::Normal:
+ format = i18n( "Normal" );
+ break;
+ case KDiffPlugin::RCS:
+ format = i18n( "RCS" );
+ break;
+ case KDiffPlugin::Unified:
+ format = i18n( "Unified" );
+ break;
+ case KDiffPlugin::Empty:
+ format = i18n( "Not Available (file empty)" );
+ break;
+ case KDiffPlugin::Unknown:
+ format = i18n( "Unknown" );
+ break;
+ case KDiffPlugin::SideBySide:
+ format = i18n( "Side by Side" );
+ }
+ return format;
+}
+
+const QString KDiffPlugin::determineI18nedProgram( enum KDiffPlugin::DiffProgram diffProgram ) const
+{
+ QString program;
+
+ switch( diffProgram )
+ {
+ case KDiffPlugin::CVSDiff:
+ program = i18n( "CVSDiff" );
+ break;
+ case KDiffPlugin::Diff:
+ program = i18n( "Diff" );
+ break;
+ case KDiffPlugin::Diff3:
+ program = i18n( "Diff3" );
+ break;
+ case KDiffPlugin::Perforce:
+ program = i18n( "Perforce" );
+ break;
+ case KDiffPlugin::SubVersion:
+ program = i18n( "SubVersion" );
+ break;
+ case KDiffPlugin::Undeterminable:
+ program = i18n( "Unknown" );
+ break;
+ }
+ return program;
+}
+
+void KDiffPlugin::determineDiffInfo( const QStringList lines,
+ enum KDiffPlugin::Format diffFormat,
+ int* numberOfFiles,
+ int* numberOfHunks,
+ int* numberOfAdditions,
+ int* numberOfChanges,
+ int* numberOfDeletions )
+{
+ QString line;
+
+ QRegExp edAdd( "([0-9]+)(|,([0-9]+))a" );
+ QRegExp edDel( "([0-9]+)(|,([0-9]+))d" );
+ QRegExp edMod( "([0-9]+)(|,([0-9]+))c" );
+
+ QRegExp normalAdd( "[0-9]+a([0-9]+)(|,([0-9]+))" );
+ QRegExp normalDel( "([0-9]+)(|,([0-9]+))d(|[0-9]+)" );
+ QRegExp normalMod( "([0-9]+)(|,([0-9]+))c([0-9]+)(|,([0-9]+))" );
+
+ QRegExp rcsAdd( "a[0-9]+ ([0-9]+)" );
+ QRegExp rcsDel( "d[0-9]+ ([0-9]+)" );
+
+ QStringList::ConstIterator it = lines.begin();
+
+ switch( diffFormat )
+ {
+ case KDiffPlugin::Context:
+ while ( it != lines.end() )
+ {
+ if ( (*it).startsWith("***************") )
+ {
+ (*numberOfHunks)++;
+// kdDebug(7034) << "Context Hunk : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith("***") )
+ {
+ (*numberOfFiles)++;
+// kdDebug(7034) << "Context File : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith("---") ) {} // ignore
+ else if ( (*it).startsWith("+") )
+ {
+ (*numberOfAdditions)++;
+// kdDebug(7034) << "Context Insertion : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith("-") )
+ {
+ (*numberOfDeletions)++;
+// kdDebug(7034) << "Context Deletion : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith("!") )
+ {
+ (*numberOfChanges)++;
+// kdDebug(7034) << "Context Modified : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith(" ") )
+ {
+// kdDebug(7034) << "Context Context : " << (*it) << endl;
+ }
+ else
+ {
+// kdDebug(7034) << "Context Unknown : " << (*it) << endl;
+ }
+
+ ++it;
+ }
+ (*numberOfChanges) /= 2; // changes are in both parts of the hunks
+ (*numberOfFiles) -= (*numberOfHunks); // it counts old parts of a hunk as files :(
+ break;
+ case KDiffPlugin::Ed:
+ while ( it != lines.end() )
+ {
+ if ( (*it).startsWith( "diff" ) )
+ {
+ (*numberOfFiles)++;
+// kdDebug(7034) << "Ed File : " << (*it) << endl;
+ }
+ else if ( edAdd.exactMatch( (*it) ) )
+ {
+// kdDebug(7034) << "Ed Insertion : " << (*it) << endl;
+ (*numberOfHunks)++;
+ ++it;
+ while( it != lines.end() && !(*it).startsWith(".") )
+ {
+ (*numberOfAdditions)++;
+// kdDebug(7034) << "Ed Insertion : " << (*it) << endl;
+ ++it;
+ }
+ }
+ else if ( edDel.exactMatch( (*it) ) )
+ {
+// kdDebug(7034) << "Ed Deletion : " << (*it) << endl;
+ (*numberOfHunks)++;
+ (*numberOfDeletions) += (edDel.cap(3).isEmpty() ? 1 : edDel.cap(3).toInt() - edDel.cap(1).toInt() + 1);
+// kdDebug(7034) << "Ed noOfLines : " << (edDel.cap(3).isEmpty() ? 1 : edDel.cap(3).toInt() - edDel.cap(1).toInt() + 1) << endl;
+ }
+ else if ( edMod.exactMatch( (*it) ) )
+ {
+// kdDebug(7034) << "Ed Modification : " << (*it) << endl;
+ if ( edMod.cap(3).isEmpty() )
+ (*numberOfDeletions)++;
+ else
+ (*numberOfDeletions) += edMod.cap(3).toInt() - edMod.cap(1).toInt() + 1;
+ (*numberOfHunks)++;
+ ++it;
+ while( it != lines.end() && !(*it).startsWith(".") )
+ {
+ (*numberOfAdditions)++;
+// kdDebug(7034) << "Ed Modification : " << (*it) << endl;
+ ++it;
+ }
+ }
+ else
+ {
+// kdDebug(7034) << "Ed Unknown : " << (*it) << endl;
+ }
+
+ ++it;
+ }
+ break;
+ case KDiffPlugin::Normal:
+ while ( it != lines.end() )
+ {
+ if ( (*it).startsWith( "diff" ) )
+ {
+ (*numberOfFiles)++;
+// kdDebug(7034) << "Normal File : " << (*it) << endl;
+ }
+ else if ( normalAdd.exactMatch( *it ) )
+ {
+// kdDebug(7034) << "Normal Insertion : " << (*it) << endl;
+ (*numberOfHunks)++;
+ if ( normalAdd.cap(3).isEmpty() )
+ {
+ (*numberOfAdditions)++;
+// kdDebug(7034) << "Normal Addition : " << 1 << endl;
+ }
+ else
+ {
+ (*numberOfAdditions) += normalAdd.cap(3).toInt() - normalAdd.cap(1).toInt() + 1;
+// kdDebug(7034) << "Normal Addition : " << normalAdd.cap(3).toInt() - normalAdd.cap(1).toInt() + 1 << endl;
+ }
+ }
+ else if ( normalDel.exactMatch( *it ) )
+ {
+// kdDebug(7034) << "Normal Deletion : " << (*it) << endl;
+ (*numberOfHunks)++;
+ if ( normalDel.cap(3).isEmpty() )
+ {
+ (*numberOfDeletions)++;
+// kdDebug(7034) << "Normal Deletion : " << 1 << endl;
+ }
+ else
+ {
+ (*numberOfDeletions) += normalDel.cap(3).toInt() - normalDel.cap(1).toInt() + 1;
+// kdDebug(7034) << "Normal Deletion : " << normalDel.cap(3).toInt() - normalDel.cap(1).toInt() + 1 << endl;
+ }
+ }
+ else if ( normalMod.exactMatch( *it ) )
+ {
+// kdDebug(7034) << "Normal Modification : " << (*it) << endl;
+ (*numberOfHunks)++;
+ if ( normalMod.cap(3).isEmpty() )
+ {
+ (*numberOfDeletions)++;
+// kdDebug(7034) << "Normal Deletion : " << 1 << endl;
+ }
+ else
+ {
+ (*numberOfDeletions) += normalMod.cap(3).toInt() - normalMod.cap(1).toInt() + 1;
+// kdDebug(7034) << "Normal Deletion : " << normalMod.cap(3).toInt() - normalMod.cap(1).toInt() + 1 << endl;
+ }
+ if ( normalMod.cap(6).isEmpty() )
+ {
+ (*numberOfAdditions)++;
+// kdDebug(7034) << "Normal Addition : " << 1 << endl;
+ }
+ else
+ {
+ (*numberOfAdditions) += normalMod.cap(6).toInt() - normalMod.cap(4).toInt() + 1;
+// kdDebug(7034) << "Normal Addition : " << normalMod.cap(6).toInt() - normalMod.cap(4).toInt() + 1 << endl;
+ }
+ }
+ else if ( (*it).startsWith(">") )
+ {
+// numberOfAdditions++;
+// kdDebug(7034) << "Normal Insertion : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith("<") )
+ {
+// numberOfDeletions++;
+// kdDebug(7034) << "Normal Deletion : " << (*it) << endl;
+ }
+ else
+ {
+// kdDebug(7034) << "Normal Unknown : " << (*it) << endl;
+ }
+
+ ++it;
+ }
+ break;
+ case KDiffPlugin::RCS:
+ while ( it != lines.end() )
+ {
+ if ( (*it).startsWith( "diff" ) ) // works for cvs diff, have to test for normal diff
+ {
+// kdDebug(7034) << "RCS File : " << (*it) << endl;
+ (*numberOfFiles)++;
+ }
+ else if ( rcsAdd.exactMatch( *it ) )
+ {
+// kdDebug(7034) << "RCS Insertion : " << (*it) << endl;
+ (*numberOfHunks)++;
+ (*numberOfAdditions) += rcsAdd.cap(1).toInt();
+// kdDebug(7034) << "RCS noOfLines : " << rcsAdd.cap(1).toInt() << endl;
+ }
+ else if ( rcsDel.exactMatch( *it ) )
+ {
+// kdDebug(7034) << "RCS Deletion : " << (*it) << endl;
+ (*numberOfHunks)++;
+ (*numberOfDeletions) += rcsDel.cap(1).toInt();
+// kdDebug(7034) << "RCS noOfLines : " << rcsDel.cap(1).toInt() << endl;
+ }
+ else
+ {
+// kdDebug(7034) << "RCS Unknown : " << (*it) << endl;
+ }
+
+ ++it;
+ }
+ break;
+ case KDiffPlugin::Unified:
+ while ( it != lines.end() )
+ {
+ if ( (*it).startsWith("@@ ") )
+ {
+ (*numberOfHunks)++;
+// kdDebug(7034) << "Unified Hunk : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith("---") )
+ {
+ (*numberOfFiles)++;
+// kdDebug(7034) << "Unified File : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith("+++") ) {} // ignore (dont count as insertion)
+ else if ( (*it).startsWith("+") )
+ {
+ (*numberOfAdditions)++;
+// kdDebug(7034) << "Unified Insertion : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith("-") )
+ {
+ (*numberOfDeletions)++;
+// kdDebug(7034) << "Unified Deletion : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith(" ") )
+ {
+// kdDebug(7034) << "Unified Context : " << (*it) << endl;
+ }
+ else
+ {
+// kdDebug(7034) << "Unified Unknown : " << (*it) << endl;
+ }
+
+ ++it;
+ }
+ break;
+ case KDiffPlugin::Empty:
+ case KDiffPlugin::Unknown:
+ case KDiffPlugin::SideBySide:
+ break;
+ }
+}
+
+#include "kfile_diff.moc"
+
+/* vim: set ts=4 sw=4 noet: */
+