/* ====================================================================
* 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 <apr_pools.h>
// sys
#include <assert.h>
#include <fstream>
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;
}
syntax highlighted by Code2HTML, v. 0.9.1