/* ====================================================================
* 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 "Diff3.h"
#include "LineTokenizer.h"
#include "DiffBaton.h"
#include "DiffInfoTarget.h"
#include "DiffInfoModelImpl.h"
#include "sublib/Line.h"
#include "sublib/LineTarget.h"
#include "sublib/ConflictType.h"
#include "sublib/TextModelImpl.h"
#include "sublib/NullTextModel.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>
// TODO fix code duplication with OutBaton
class OutBaton3 : public svn::OutputBaton
{
public:
enum Source
{
srcOriginal = svn::Diff::srcOriginal,
srcModified = svn::Diff::srcModified,
srcLatest = svn::Diff::srcLatest,
srcAncestor = svn::Diff::srcAncestor,
srcMax = srcAncestor + 1
};
OutBaton3( Tokenizer** tokenizer, LineTarget** targets,
DiffInfoTarget* infos, apr_pool_t *pool = 0 )
: _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 );
}
~OutBaton3()
{
apr_pool_destroy(_pool);
}
// common lines in all datasources
sc::Error* common( const svn::DiffOffsets& offs )
{
for( svn::Offset i = 1; i <= offs._originalLength; i++ )
{
addTextLine( srcOriginal, ctCommon );
addTextLine( srcModified, ctCommon );
addTextLine( srcLatest, ctCommon );
}
_infos->addDiffInfo( DiffInfo(ctCommon,_blockCnt,createOffsets(offs._originalLength)) );
_blockCnt++;
return 0;
}
// original = latest != modified
sc::Error* diffModified( const svn::DiffOffsets& offs )
{
bool originalConflictEmpty = offs._originalLength == 0;
bool modifiedConflictEmpty = offs._modifiedLength == 0;
bool latestConflictEmpty = offs._latestLength == 0;
assert( offs._originalLength == offs._latestLength );
svn::Offset max = 0;
if( offs._originalLength > max ) max = offs._originalLength;
if( offs._modifiedLength > max ) max = offs._modifiedLength;
for( svn::Offset i = 1; i <= max; i++ )
{
if( i <= offs._originalLength )
{
addTextLine( srcOriginal, ctConflictLatestModified );
}
else
{
addControlLine( srcOriginal, ctConflictLatestModifiedEmpty, originalConflictEmpty );
originalConflictEmpty = false;
}
if( i <= offs._modifiedLength )
{
addTextLine( srcModified, ctConflictAll );
}
else
{
addControlLine( srcModified, ctConflictAllEmpty, modifiedConflictEmpty );
modifiedConflictEmpty = false;
}
if( i <= offs._latestLength )
{
addTextLine( srcLatest, ctConflictLatestModified );
}
else
{
addControlLine( srcLatest, ctConflictLatestModifiedEmpty, latestConflictEmpty );
latestConflictEmpty = false;
}
}
_infos->addDiffInfo( DiffInfo(ctConflictLatestModified,_blockCnt,createOffsets(max)) );
_blockCnt++;
return 0;
}
// original = modified != latest
sc::Error* diffLatest( const svn::DiffOffsets& offs )
{
assert( offs._originalLength == offs._modifiedLength );
bool originalConflictEmpty = offs._originalLength == 0;
bool modifiedConflictEmpty = offs._modifiedLength == 0;
bool latestConflictEmpty = offs._latestLength == 0;
svn::Offset max = 0;
if( offs._originalLength > max ) max = offs._originalLength;
if( offs._latestLength > max ) max = offs._latestLength;
for( svn::Offset i = 1; i <= max; i++ )
{
if( i <= offs._originalLength )
{
addTextLine( srcOriginal, ctConflictModifiedLatest );
}
else
{
addControlLine( srcOriginal, ctConflictModifiedLatestEmpty, originalConflictEmpty );
originalConflictEmpty = false;
}
if( i <= offs._modifiedLength )
{
addTextLine( srcModified, ctConflictModifiedLatest );
}
else
{
addControlLine( srcModified, ctConflictModifiedLatestEmpty, modifiedConflictEmpty );
modifiedConflictEmpty = false;
}
if( i <= offs._latestLength )
{
addTextLine( srcLatest, ctConflictAll );
}
else
{
addControlLine( srcLatest, ctConflictAllEmpty, latestConflictEmpty );
latestConflictEmpty = false;
}
}
_infos->addDiffInfo( DiffInfo(ctConflictModifiedLatest,_blockCnt,createOffsets(max)) );
_blockCnt++;
return 0;
}
// original != lastest = modified
sc::Error* diffCommon( const svn::DiffOffsets& offs )
{
assert( offs._modifiedLength == offs._latestLength );
bool originalConflictEmpty = offs._originalLength == 0;
bool modifiedConflictEmpty = offs._modifiedLength == 0;
bool latestConflictEmpty = offs._latestLength == 0;
svn::Offset max = 0;
if( offs._originalLength > max ) max = offs._originalLength;
if( offs._modifiedLength > max ) max = offs._modifiedLength;
for( svn::Offset i = 1; i <= max; i++ )
{
if( i <= offs._originalLength )
{
addTextLine( srcOriginal, ctConflictAll );
}
else
{
addControlLine( srcOriginal, ctConflictAllEmpty, originalConflictEmpty );
originalConflictEmpty = false;
}
if( i <= offs._modifiedLength )
{
addTextLine( srcModified, ctConflictOriginal );
}
else
{
addControlLine( srcModified, ctConflictOriginalEmpty, modifiedConflictEmpty );
modifiedConflictEmpty = false;
}
if( i <= offs._latestLength )
{
addTextLine( srcLatest, ctConflictOriginal );
}
else
{
addControlLine( srcLatest, ctConflictOriginalEmpty, latestConflictEmpty );
latestConflictEmpty = false;
}
}
_infos->addDiffInfo( DiffInfo(ctConflictOriginal,_blockCnt,createOffsets(max)) );
_blockCnt++;
return 0;
}
// original != latest != modified
sc::Error* conflict( const svn::DiffOffsets& offs, svn::DiffData* resolvedDiff )
{
bool originalConflictEmpty = offs._originalLength == 0;
bool modifiedConflictEmpty = offs._modifiedLength == 0;
bool latestConflictEmpty = offs._latestLength == 0;
svn::Offset max = 0;
if( offs._originalLength > max ) max = offs._originalLength;
if( offs._modifiedLength > max ) max = offs._modifiedLength;
if( offs._latestLength > max ) max = offs._latestLength;
for( svn::Offset i = 1; i <= max; i++ )
{
if( i <= offs._originalLength )
{
addTextLine( srcOriginal, ctConflictAll );
}
else
{
addControlLine( srcOriginal, ctConflictAllEmpty, originalConflictEmpty );
originalConflictEmpty = false;
}
if( i <= offs._modifiedLength )
{
addTextLine( srcModified, ctConflictAll );
}
else
{
addControlLine( srcModified, ctConflictAllEmpty, modifiedConflictEmpty );
modifiedConflictEmpty = false;
}
if( i <= offs._latestLength )
{
addTextLine( srcLatest, ctConflictAll );
}
else
{
addControlLine( srcLatest, ctConflictAllEmpty, latestConflictEmpty );
latestConflictEmpty = false;
}
}
_infos->addDiffInfo( DiffInfo(ctConflictAll,_blockCnt,createOffsets(max)) );
_blockCnt++;
return 0;
}
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, ConflictType cType, bool hasConflictEmpty )
{
ConflictType type = ctNop;
if( hasConflictEmpty )
{
type = cType;
}
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;
};
///////////////////////////////////////////////////////////////////////////////
Diff3::Diff3( const FileDataPtr original, const FileDataPtr modified,
const FileDataPtr latest, const sc::String& merged )
: _original(original), _modified(modified), _latest(latest), _merged(merged),
_diffInfo(0)
{
}
Diff3::~Diff3()
{
}
const sc::Error* Diff3::diff3( bool ignoreWhitespace )
{
svn::Diff diff;
svn::DiffData* diffData = 0;
sc::Error* err;
{
LineTokenizer orgTokenizer( _original->getBuffer(), _original->getBufferSize() );
LineTokenizer modTokenizer( _modified->getBuffer(), _modified->getBufferSize() );
LineTokenizer latTokenizer( _latest->getBuffer(), _latest->getBufferSize() );
Tokenizer* tokenizer[OutBaton3::srcMax];
tokenizer[OutBaton3::srcOriginal] = &orgTokenizer;
tokenizer[OutBaton3::srcModified] = &modTokenizer;
tokenizer[OutBaton3::srcLatest] = &latTokenizer;
DiffBaton diffBaton( tokenizer, ignoreWhitespace );
err = diff.diff3( &diffData, &diffBaton );
SC_ERR(err);
}
{
TextModelImpl* orgModel = new TextModelImpl( _original->getName() );
TextModelImpl* modModel = new TextModelImpl( _modified->getName() );
TextModelImpl* latModel = new TextModelImpl( _latest->getName() );
TextModelImpl* merModel = new TextModelImpl(
_merged.isEmpty() ? _modified->getName() : _merged );
DiffInfoModelImpl* diffInfoImpl = new DiffInfoModelImpl();
LineTokenizer orgTokenizer( _original->getBuffer(), _original->getBufferSize() );
LineTokenizer modTokenizer( _modified->getBuffer(), _modified->getBufferSize() );
LineTokenizer latTokenizer( _latest->getBuffer(), _latest->getBufferSize() );
Tokenizer* tokenizer[OutBaton3::srcMax];
tokenizer[OutBaton3::srcOriginal] = &orgTokenizer;
tokenizer[OutBaton3::srcModified] = &modTokenizer;
tokenizer[OutBaton3::srcLatest] = &latTokenizer;
LineTarget* targets[OutBaton3::srcMax];
targets[OutBaton3::srcOriginal] = orgModel;
targets[OutBaton3::srcModified] = modModel;
targets[OutBaton3::srcLatest] = latModel;
OutBaton3 outBaton( tokenizer, targets, diffInfoImpl );
err = diffData->output( &outBaton );
SC_ERR(err);
diffInfoImpl->setModel( DiffInfoModel::dmOriginal, orgModel );
diffInfoImpl->setModel( DiffInfoModel::dmModified, modModel );
diffInfoImpl->setModel( DiffInfoModel::dmLatest, latModel );
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;
}
//
#if 0
{
apr_file_t* file;
apr_status_t status = apr_file_open( &file, "out.txt", APR_WRITE, APR_OS_DEFAULT, pool );
svn_error_t* error = svn_diff_file_output_merge(
file, diffData->_diff,
"org.txt", "new.txt", "new2.txt", 0, 0, 0, 0, false, true, pool );
}
#endif
//
syntax highlighted by Code2HTML, v. 0.9.1