/* ==================================================================== * Copyright (c) 2003-2006, Martin Hauner * http://subcommander.tigris.org * * Subcommander is licensed as described in the file doc/COPYING, which * you should have received as part of this distribution. * ==================================================================== */ // sc #include "Diff.h" #include "sublib/Line.h" #include "sublib/LineTarget.h" #include "LineTokenizer.h" #include "sublib/ConflictType.h" #include "DiffInfoTarget.h" #include "DiffBaton.h" #include "sublib/TextModelImpl.h" #include "sublib/NullTextModel.h" #include "DiffInfoModelImpl.h" #include "Merge.h" #include "svn/Diff.h" #include "svn/Error.h" #include "util/iconvstream.h" #include "util/Error.h" // apr #include // sys #include #include class OutBaton : public svn::OutputBaton { public: enum Source { srcOriginal = svn::Diff::srcOriginal, srcModified = svn::Diff::srcModified, srcMax = srcModified + 1 }; OutBaton( Tokenizer** tokenizer, LineTarget** targets, DiffInfoTarget* infos, apr_pool_t *pool ) : _tokenizer(tokenizer), _targets(targets), _infos(infos), _blockCnt(1), _blockStart(0) { assert(_tokenizer); assert(_targets); apr_status_t status = apr_pool_create(&_pool,pool); assert( status == APR_SUCCESS ); } ~OutBaton() { apr_pool_destroy(_pool); } sc::Error* common( const svn::DiffOffsets& offs ) { // add common lines for( svn::Offset i = 1; i <= offs._originalLength; i++ ) { addTextLine( srcOriginal, ctCommon ); addTextLine( srcModified, ctCommon ); } _infos->addDiffInfo( DiffInfo(ctCommon,_blockCnt,createOffsets(offs._originalLength)) ); _blockCnt++; return sc::Success; } sc::Error* diffModified( const svn::DiffOffsets& offs ) { bool originalConflictEmpty = offs._originalLength == 0; bool modifiedConflictEmpty = offs._modifiedLength == 0; svn::Offset max = 0; max < offs._originalLength ? max = offs._originalLength : max += 0; max < offs._modifiedLength ? max = offs._modifiedLength : max += 0; for( svn::Offset i = 1; i <= max; i++ ) { if( i <= offs._originalLength ) { addTextLine( srcOriginal, ctConflictAll ); } else { addControlLine( srcOriginal, originalConflictEmpty ); originalConflictEmpty = false; } if( i <= offs._modifiedLength ) { addTextLine( srcModified, ctConflictAll ); } else { addControlLine( srcModified, modifiedConflictEmpty ); modifiedConflictEmpty = false; } } _infos->addDiffInfo( DiffInfo(ctConflictAll,_blockCnt,createOffsets(max)) ); _blockCnt++; return sc::Success; } sc::Error* diffLatest( const svn::DiffOffsets& offs ) { return sc::Success; } sc::Error* diffCommon( const svn::DiffOffsets& offs ) { return sc::Success; } sc::Error* conflict( const svn::DiffOffsets& offs, svn::DiffData* resolvedDiff ) { return sc::Success; } private: void addTextLine( Source src, ConflictType type ) { char *token; size_t size; bool b; b = _tokenizer[src]->nextToken( &token, &size ); assert(b); Line line( sc::String(token,size), _blockCnt, type ); b = _targets[src]->addLine( line ); assert(b); } void addControlLine( Source src, bool conflictMark ) { ConflictType type = ctNop; if( conflictMark ) { type = ctConflictAllEmpty; } Line line( sc::String(""), _blockCnt, type ); bool b = _targets[src]->addLine( line ); assert(b); } BlockInfo createOffsets( svn::Offset length ) { BlockInfo info(_blockStart,length); _blockStart += length; return info; } private: Tokenizer** _tokenizer; LineTarget** _targets; DiffInfoTarget* _infos; int _blockCnt; svn::Offset _blockStart; apr_pool_t* _pool; }; /////////////////////////////////////////////////////////////////////////////// Diff::Diff( const FileDataPtr original, const FileDataPtr modified ) : _original(original), _modified(modified), _diffInfo(0) { } Diff::~Diff() { } const sc::Error* Diff::diff( bool ignoreWhitespace ) { sc::Error* err; svn::Diff diff; svn::DiffData* diffData = 0; { LineTokenizer orgTokenizer( _original->getBuffer(), _original->getBufferSize() ); LineTokenizer modTokenizer( _modified->getBuffer(), _modified->getBufferSize() ); Tokenizer* tokenizer[OutBaton::srcMax]; tokenizer[OutBaton::srcOriginal] = &orgTokenizer; tokenizer[OutBaton::srcModified] = &modTokenizer; DiffBaton diffBaton( tokenizer, ignoreWhitespace ); err = diff.diff( &diffData, &diffBaton ); SC_ERR(err); } { TextModelImpl* orgModel = new TextModelImpl( _original->getName() ); TextModelImpl* modModel = new TextModelImpl( _modified->getName() ); TextModelImpl* merModel = new TextModelImpl( _modified->getName() ); DiffInfoModelImpl* diffInfoImpl = new DiffInfoModelImpl(); LineTokenizer orgTokenizer( _original->getBuffer(), _original->getBufferSize() ); LineTokenizer modTokenizer( _modified->getBuffer(), _modified->getBufferSize() ); Tokenizer* tokenizer[OutBaton::srcMax]; tokenizer[OutBaton::srcOriginal] = &orgTokenizer; tokenizer[OutBaton::srcModified] = &modTokenizer; LineTarget* targets[OutBaton::srcMax]; targets[OutBaton::srcOriginal] = orgModel; targets[OutBaton::srcModified] = modModel; OutBaton outBaton( tokenizer, targets, diffInfoImpl, 0 ); err = diffData->output( &outBaton ); SC_ERR(err); diffInfoImpl->setModel( DiffInfoModel::dmOriginal, orgModel ); diffInfoImpl->setModel( DiffInfoModel::dmModified, modModel ); diffInfoImpl->setModel( DiffInfoModel::dmLatest, new NullTextModel() ); diffInfoImpl->setModel( DiffInfoModel::dmMerged, merModel ); _diffInfo = diffInfoImpl; // automatically merge where possible... Merge m( merModel, _diffInfo ); m.merge(); diffInfoImpl->setConflictCnt( m.getNotMergedCnt() ); } delete diffData; return sc::Success; }