#include <stdio.h>
#include <stdlib.h>
#include "bibutils.h"
#include "intlist.h"
#include "args.h"
char progname[] = "bibdiff";
int
find_tag_level_matches( fields *f, char *tag, int level, intlist *matchs )
{
int i, n = 0;
char *ftag;
for ( i=0; i<f->n; ++i )
intlist_set( matchs, i, 0 );
for ( i=0; i<f->n; ++i ) {
if ( fields_level( f, i ) != level ) continue;
ftag = fields_tag( f, i, FIELDS_CHRP_NOLEN );
if ( !strcmp( tag, ftag ) ) {
intlist_set( matchs, i, 1 );
n++;
}
}
return n;
}
int
compare_references( fields *f1, const char *fname1, fields *f2, const char *fname2, long n )
{
int i, j, cnt, cnt1, cnt2, level, diff = 0;
intlist found1, found2, matches;
char *tag, *data;
intlist_init_fill( &found1, f1->n, -1 );
intlist_init_fill( &found2, f2->n, -1 );
intlist_init_fill( &matches, f2->n, 0 );
for ( i=0; i<f1->n; ++i ) {
tag = fields_tag( f1, i, FIELDS_CHRP_NOLEN );
data = fields_value( f1, i, FIELDS_CHRP_NOLEN );
level = fields_level( f1, i );
cnt = find_tag_level_matches( f2, tag, level, &matches );
if ( cnt==0 ) continue;
for ( j=0; j<f2->n; ++j ) {
if ( intlist_get( &matches, j ) == 0 ) continue;
if ( intlist_get( &found2, j ) != -1 ) continue;
if ( strcmp( data, fields_value( f2, j, FIELDS_CHRP_NOLEN ) ) ) continue;
intlist_set( &found1, i, j );
intlist_set( &found2, j, i );
break;
}
}
cnt1 = 0;
for ( i=0; i<f1->n; ++i )
if ( intlist_get( &found1, i ) != -1 ) cnt1++;
cnt2 = 0;
for ( i=0; i<f2->n; ++i )
if ( intlist_get( &found2, i ) != -1 ) cnt2++;
if ( cnt1!=f1->n || cnt2!=f2->n ) {
printf( "reference %ld < %s > %s\n", n, fname1, fname2 );
for ( i=0; i<f1->n; ++i ) {
if ( intlist_get( &found1, i ) != -1 ) continue;
tag = fields_tag( f1, i, FIELDS_CHRP_NOLEN );
data = fields_value( f1, i, FIELDS_CHRP_NOLEN );
level = fields_level( f1, i );
printf( "< '%s' '%s' %d\n", tag, data, level );
}
for ( i=0; i<f2->n; ++i ) {
if ( intlist_get( &found2, i ) != -1 ) continue;
tag = fields_tag( f2, i, FIELDS_CHRP_NOLEN );
data = fields_value( f2, i, FIELDS_CHRP_NOLEN );
level = fields_level( f2, i );
printf( "> '%s' '%s' %d\n", tag, data, level );
}
}
intlist_free( &found1 );
intlist_free( &found2 );
intlist_free( &matches );
return diff;
}
int
compare_bibliographies( bibl *b1, const char *fname1, bibl *b2, const char *fname2 )
{
fields *f1, *f2;
long i;
if ( b1->n != b2->n ) {
printf( "%s: %s has %ld references and %s has %ld references\n", progname,
fname1, b1->n, fname2, b2->n );
return 1;
}
for ( i=0; i<b1->n; ++i ) {
f1 = b1->ref[i];
f2 = b2->ref[i];
if ( compare_references( f1, fname1, f2, fname2, i+1 ) ) return 1;
}
return 0;
}
void
version( void )
{
args_tellversion( progname );
exit( EXIT_FAILURE );
}
void
help( void )
{
args_tellversion( progname );
fprintf( stderr, "Compares references after reading them from their native formats\n\n" );
fprintf( stderr, "usage: %s ref1_file ref2_file\n\n", progname );
fprintf( stderr, "-h, --help display this help\n" );
fprintf( stderr, "-v, --version display version\n" );
fprintf( stderr, "-f1, --format1 FORMAT specify input format for ref1_file\n" );
fprintf( stderr, "-f2, --format2 FORMAT specify input format for ref1_file\n" );
fprintf( stderr, "\n" );
fprintf( stderr, "Valid format specifiers are 'bibtex', 'biblatex', 'copac', 'ebi', "
"'endnote', 'endnote-xml', 'medline', 'mods', 'nbib', 'ris', 'word2007'\n\n" );
exit( EXIT_FAILURE );
}
int
lookup_format( const char *format )
{
typedef struct flist_t { char *name; int code; } flist_t;
flist_t formats[] = {
{ "bibtex", BIBL_BIBTEXIN },
{ "biblatex", BIBL_BIBLATEXIN },
{ "copac", BIBL_COPACIN },
{ "ebi", BIBL_EBIIN },
{ "endnote", BIBL_ENDNOTEIN },
{ "endnote-xml", BIBL_ENDNOTEXMLIN },
{ "medline", BIBL_MEDLINEIN },
{ "mods", BIBL_MODSIN },
{ "nbib", BIBL_NBIBIN },
{ "ris", BIBL_RISIN },
{ "word2007", BIBL_WORDIN },
};
int i, nformats = sizeof( formats ) / sizeof( formats[0] );
for ( i=0; i<nformats; ++i ) {
if ( !strcasecmp( format, formats[i].name ) ) return formats[i].code;
}
fprintf( stderr, "%s: Cannot recognize format '%s'.\n", progname, format );
fprintf( stderr, "%s: Valid format specifiers are 'bibtex', 'biblatex', 'copac', 'ebi', "
"'endnote', 'endnote-xml', 'medline', 'mods', 'nbib', 'ris', 'word2007'\n", progname );
fprintf( stderr, "%s: Exiting.\n", progname );
exit( EXIT_FAILURE );
}
void
process_args( int *argc, char *argv[], int *format1, int *format2 )
{
int i, j, done, subtract;
char *f1, *f2;
for ( i=0; i<*argc; ++i )
if ( args_match( argv[i], "-h", "--help" ) ) help();
for ( i=0; i<*argc; ++i )
if ( args_match( argv[i], "-v", "--version" ) ) version();
done = 0;
i = 1;
while ( i < *argc && !done ) {
subtract = 0;
if ( args_match( argv[i], "-f1", "--format1" ) ) {
f1 = args_next( *argc, argv, i, progname, "-f1", "--format1" );
*format1 = lookup_format( f1 );
subtract = 2;
}
else if ( args_match( argv[i], "-f2", "--format2" ) ) {
f2 = args_next( *argc, argv, i, progname, "-f1", "--format1" );
*format2 = lookup_format( f2 );
subtract = 2;
}
else if ( !strcmp( argv[i], "--" ) ) {
done = 1;
subtract = 1;
}
else if ( !strncmp( argv[i], "-", 1 ) ) {
fprintf( stderr, "%s: Unrecognized command-line switch '%s'. Exiting.\n", progname, argv[i] );
exit( EXIT_FAILURE );
}
if ( subtract ) {
for ( j=i+subtract; j<*argc; ++j )
argv[j-subtract] = argv[j];
*argc -= subtract;
} else i++;
}
}
int
main( int argc, char *argv[] )
{
int format1 = BIBL_MODSIN;
int format2 = BIBL_MODSIN;
param p1, p2;
bibl b1, b2;
int status;
FILE *fp;
process_args( &argc, argv, &format1, &format2 );
if ( argc < 2 ) help();
bibl_initparams( &p1, format1, BIBL_MODSOUT, progname );
bibl_initparams( &p2, format2, BIBL_MODSOUT, progname );
fp = fopen( argv[1], "r" );
if ( !fp ) {
fprintf( stderr, "%s: Cannot open %s\n", progname, argv[1] );
return EXIT_SUCCESS;
}
bibl_init( &b1 );
status = bibl_read( &b1, fp, argv[1], &p1 );
fclose( fp );
if ( status!=BIBL_OK ) {
bibl_reporterr( status );
return EXIT_FAILURE;
}
fp = fopen( argv[2], "r" );
if ( !fp ) {
fprintf( stderr, "%s: Cannot open %s\n", progname, argv[2] );
return EXIT_SUCCESS;
}
bibl_init( &b2 );
status = bibl_read( &b2, fp, argv[2], &p2 );
fclose( fp );
if ( status!=BIBL_OK ) {
bibl_reporterr( status );
return EXIT_FAILURE;
}
compare_bibliographies( &b1, argv[1], &b2, argv[2] );
bibl_freeparams( &p1 );
bibl_freeparams( &p2 );
return EXIT_SUCCESS;
}