diff options
Diffstat (limited to 'support/texlab/crates/bibutils_sys/src/bibcore.c')
-rw-r--r-- | support/texlab/crates/bibutils_sys/src/bibcore.c | 1079 |
1 files changed, 1079 insertions, 0 deletions
diff --git a/support/texlab/crates/bibutils_sys/src/bibcore.c b/support/texlab/crates/bibutils_sys/src/bibcore.c new file mode 100644 index 0000000000..eeab581941 --- /dev/null +++ b/support/texlab/crates/bibutils_sys/src/bibcore.c @@ -0,0 +1,1079 @@ +/* + * bibcore.c + * + * Copyright (c) Chris Putnam 2005-2019 + * + * Source code released under the GPL version 2 + * + */ +#include <stdio.h> +#include <stdlib.h> +#include "bibutils.h" + +/* internal includes */ +#include "reftypes.h" +#include "charsets.h" +#include "str_conv.h" +#include "is_ws.h" +#include "msvc_fix.h" + +/* illegal modes to pass in, but use internally for consistency */ +#define BIBL_INTERNALIN (BIBL_LASTIN+1) +#define BIBL_INTERNALOUT (BIBL_LASTOUT+1) + +#define debug_set( p ) ( p->verbose > 1 ) +#define verbose_set( p ) ( p->verbose ) + +static void +report_params( FILE *fp, const char *f, param *p ) +{ + fprintf( fp, "-------------------params start for %s\n", f ); + fprintf( fp, "\tprogname='%s'\n\n", p->progname ); + + fprintf( fp, "\treadformat=%d", p->readformat ); + switch ( p->readformat ) { + case BIBL_INTERNALIN: fprintf( fp, " (BIBL_INTERNALIN)\n" ); break; + case BIBL_MODSIN: fprintf( fp, " (BIBL_MODSIN)\n" ); break; + case BIBL_BIBTEXIN: fprintf( fp, " (BIBL_BIBTEXIN)\n" ); break; + case BIBL_RISIN: fprintf( fp, " (BIBL_RISIN)\n" ); break; + case BIBL_ENDNOTEIN: fprintf( fp, " (BIBL_ENDNOTEIN)\n" ); break; + case BIBL_COPACIN: fprintf( fp, " (BIBL_COPACIN)\n" ); break; + case BIBL_ISIIN: fprintf( fp, " (BIBL_ISIIN)\n" ); break; + case BIBL_MEDLINEIN: fprintf( fp, " (BIBL_MEDLINEIN)\n" ); break; + case BIBL_ENDNOTEXMLIN: fprintf( fp, " (BIBL_ENDNOTEXMLIN)\n" ); break; + case BIBL_BIBLATEXIN: fprintf( fp, " (BIBL_BIBLATEXIN)\n" ); break; + case BIBL_EBIIN: fprintf( fp, " (BIBL_EBIIN)\n" ); break; + case BIBL_WORDIN: fprintf( fp, " (BIBL_WORDIN)\n" ); break; + case BIBL_NBIBIN: fprintf( fp, " (BIBL_NBIBIN)\n" ); break; + default: fprintf( fp, " (Illegal value)\n" ); break; + } + fprintf( fp, "\tcharsetin=%d\n", p->charsetin ); + fprintf( fp, "\tcharsetin_src=%d", p->charsetin_src ); + switch ( p->charsetin_src ) { + case BIBL_SRC_DEFAULT: fprintf( fp, " (BIBL_SRC_DEFAULT)\n" ); break; + case BIBL_SRC_FILE: fprintf( fp, " (BIBL_SRC_FILE)\n" ); break; + case BIBL_SRC_USER: fprintf( fp, " (BIBL_SRC_USER)\n" ); break; + default: fprintf( fp, " (Illegal value)\n" ); break; + } + fprintf( fp, "\tutf8in=%d\n", p->utf8in ); + fprintf( fp, "\tlatexin=%d\n", p->latexin ); + fprintf( fp, "\txmlin=%d\n\n", p->xmlin ); + + fprintf( fp, "\twriteformat=%d", p->writeformat ); + switch ( p->writeformat ) { + case BIBL_INTERNALOUT: fprintf( fp, " (BIBL_INTERNALOUT)\n" ); break; + case BIBL_ADSABSOUT: fprintf( fp, " (BIBL_ADSABSOUT)\n" ); break; + case BIBL_BIBTEXOUT: fprintf( fp, " (BIBL_BIBTEXOUT)\n" ); break; + case BIBL_ENDNOTEOUT: fprintf( fp, " (BIBL_ENDNOTEOUT)\n" ); break; + case BIBL_ISIOUT: fprintf( fp, " (BIBL_ISIOUT)\n" ); break; + case BIBL_MODSOUT: fprintf( fp, " (BIBL_MODSOUT)\n" ); break; + case BIBL_NBIBOUT: fprintf( fp, " (BIBL_NBIBOUT)\n" ); break; + case BIBL_RISOUT: fprintf( fp, " (BIBL_RISOUT)\n" ); break; + case BIBL_WORD2007OUT: fprintf( fp, " (BIBL_WORD2007OUT)\n" ); break; + default: fprintf( fp, " (Illegal value)\n"); break; + } + fprintf( fp, "\tcharsetout=%d\n", p->charsetout ); + fprintf( fp, "\tcharsetout_src=%d", p->charsetout_src ); + switch ( p->charsetout_src ) { + case BIBL_SRC_DEFAULT: fprintf( fp, " (BIBL_SRC_DEFAULT)\n" ); break; + case BIBL_SRC_FILE: fprintf( fp, " (BIBL_SRC_FILE)\n" ); break; + case BIBL_SRC_USER: fprintf( fp, " (BIBL_SRC_USER)\n" ); break; + default: fprintf( fp, " (Illegal value)\n" ); break; + } + fprintf( fp, "\tutf8out=%d\n", p->utf8out ); + fprintf( fp, "\tutf8bom=%d\n", p->utf8bom ); + fprintf( fp, "\tlatexout=%d\n", p->latexout ); + fprintf( fp, "\txmlout=%d\n", p->xmlout ); + fprintf( fp, "-------------------params end for %s\n", f ); + + fflush( fp ); +} + +/* bibl_duplicateparams() + * + * Returns status of BIBL_OK or BIBL_ERR_MEMERR + */ +static int +bibl_duplicateparams( param *np, param *op ) +{ + int status; + slist_init( &(np->asis) ); + slist_init( &(np->corps) ); + status = slist_copy( &(np->asis), &(op->asis ) ); + if ( status!=SLIST_OK ) return BIBL_ERR_MEMERR; + status = slist_copy( &(np->corps), &(op->corps ) ); + if ( status!=SLIST_OK ) return BIBL_ERR_MEMERR; + + if ( !op->progname ) np->progname = NULL; + else { + np->progname = strdup( op->progname ); + if ( !np->progname ) return BIBL_ERR_MEMERR; + } + + np->readformat = op->readformat; + np->writeformat = op->writeformat; + + np->charsetin = op->charsetin; + np->charsetin_src = op->charsetin_src; + np->utf8in = op->utf8in; + np->latexin = op->latexin; + np->xmlin = op->xmlin; + + np->charsetout = op->charsetout; + np->charsetout_src = op->charsetout_src; + np->utf8out = op->utf8out; + np->utf8bom = op->utf8bom; + np->latexout = op->latexout; + np->xmlout = op->xmlout; + np->nosplittitle = op->nosplittitle; + + np->verbose = op->verbose; + np->format_opts = op->format_opts; + np->addcount = op->addcount; + np->output_raw = op->output_raw; + np->singlerefperfile = op->singlerefperfile; + + np->readf = op->readf; + np->processf = op->processf; + np->cleanf = op->cleanf; + np->typef = op->typef; + np->convertf = op->convertf; + np->headerf = op->headerf; + np->footerf = op->footerf; + np->assemblef = op->assemblef; + np->writef = op->writef; + np->all = op->all; + np->nall = op->nall; + + return BIBL_OK; +} + +/* bibl_setreadparams() + * + * Returns status of BIBL_OK or BIBL_ERR_MEMERR + */ +static int +bibl_setreadparams( param *np, param *op ) +{ + int status; + status = bibl_duplicateparams( np, op ); + if ( status == BIBL_OK ) { + np->utf8out = 1; + np->charsetout = BIBL_CHARSET_UNICODE; + np->charsetout_src = BIBL_SRC_DEFAULT; + np->xmlout = BIBL_XMLOUT_FALSE; + np->latexout = 0; + np->writeformat = BIBL_INTERNALOUT; + } + return status; +} + +/* bibl_setwriteparams() + * + * Returns status of BIBL_OK or BIBL_ERR_MEMERR + */ +static int +bibl_setwriteparams( param *np, param *op ) +{ + int status; + status = bibl_duplicateparams( np, op ); + if ( status == BIBL_OK ) { + np->xmlin = 0; + np->latexin = 0; + np->utf8in = 1; + np->charsetin = BIBL_CHARSET_UNICODE; + np->charsetin_src = BIBL_SRC_DEFAULT; + np->readformat = BIBL_INTERNALIN; + } + return status; +} + +void +bibl_freeparams( param *p ) +{ + if ( p ) { + slist_free( &(p->asis) ); + slist_free( &(p->corps) ); + if ( p->progname ) free( p->progname ); + } +} + +int +bibl_readasis( param *p, char *f ) +{ + int status; + + if ( !p ) return BIBL_ERR_BADINPUT; + if ( !f ) return BIBL_ERR_BADINPUT; + + status = slist_fill( &(p->asis), f, 1 ); + + if ( status == SLIST_ERR_CANTOPEN ) return BIBL_ERR_CANTOPEN; + else if ( status == SLIST_ERR_MEMERR ) return BIBL_ERR_MEMERR; + return BIBL_OK; +} + +int +bibl_readcorps( param *p, char *f ) +{ + int status; + + if ( !p ) return BIBL_ERR_BADINPUT; + if ( !f ) return BIBL_ERR_BADINPUT; + + status = slist_fill( &(p->corps), f, 1 ); + + if ( status == SLIST_ERR_CANTOPEN ) return BIBL_ERR_CANTOPEN; + else if ( status == 0 ) return BIBL_ERR_MEMERR; + return BIBL_OK; +} + +/* bibl_addtoasis() + * + * Returns BIBL_OK or BIBL_ERR_MEMERR + */ +int +bibl_addtoasis( param *p, char *d ) +{ + int status; + + if ( !p ) return BIBL_ERR_BADINPUT; + if ( !d ) return BIBL_ERR_BADINPUT; + + status = slist_addc( &(p->asis), d ); + + return ( status==SLIST_OK )? BIBL_OK : BIBL_ERR_MEMERR; +} + +/* bibl_addtocorps() + * + * Returns BIBL_OK or BIBL_ERR_MEMERR + */ +int +bibl_addtocorps( param *p, char *d ) +{ + int status; + + if ( !p ) return BIBL_ERR_BADINPUT; + if ( !d ) return BIBL_ERR_BADINPUT; + + status = slist_addc( &(p->corps), d ); + + return ( status==SLIST_OK )? BIBL_OK : BIBL_ERR_MEMERR; +} + +void +bibl_reporterr( int err ) +{ + fprintf( stderr, "Bibutils: " ); + switch( err ) { + case BIBL_OK: + fprintf( stderr, "No error." ); break; + case BIBL_ERR_BADINPUT: + fprintf( stderr, "Bad input." ); break; + case BIBL_ERR_MEMERR: + fprintf( stderr, "Memory error." ); break; + case BIBL_ERR_CANTOPEN: + fprintf( stderr, "Can't open." ); break; + default: + fprintf( stderr, "Cannot identify error code %d.", err ); break; + } + fprintf( stderr, "\n" ); +} + +static int +bibl_illegalinmode( int mode ) +{ + if ( mode < BIBL_FIRSTIN || mode > BIBL_LASTIN ) return 1; + else return 0; +} + +static int +bibl_illegaloutmode( int mode ) +{ + if ( mode < BIBL_FIRSTOUT || mode > BIBL_LASTOUT ) return 1; + else return 0; +} + +static void +bibl_verbose2( fields *f, char *filename, long nrefs ) +{ + int i, n; + n = fields_num( f ); + fprintf( stderr, "======== %s %ld : converted\n", filename, nrefs ); + for ( i=0; i<n; ++i ) { + fprintf( stderr, "'%s'='%s' level=%d\n", + (char*) fields_tag( f, i, FIELDS_CHRP_NOUSE ), + (char*) fields_value( f, i, FIELDS_CHRP_NOUSE ), + fields_level( f, i ) ); + } + fprintf( stderr, "\n" ); + fflush( stderr ); +} + +#if 0 +static void +bibl_verbose1( fields *f, fields *orig, char *filename, long nrefs ) +{ + int i, n; + n = fields_num( orig ); + fprintf( stderr, "======== %s %ld : processed\n", filename, nrefs ); + for ( i=0; i<n; ++i ) { + fprintf( stderr, "'%s'='%s' level=%d\n", + (char*) fields_tag( orig, i, FIELDS_CHRP_NOUSE ), + (char*) fields_value( orig, i, FIELDS_CHRP_NOUSE ), + fields_level( orig, i ) ); + } + if ( f ) bibl_verbose2( f, filename, nrefs ); +} +#endif + +static void +bibl_verbose0( bibl *bin ) +{ + int i; + for ( i=0; i<bin->nrefs; ++i ) + bibl_verbose2( bin->ref[i], "", i+1 ); +} + +/* extract_tag_value + * + * Extract the tag and the value for ALWAYS/DEFAULT + * entries like: "GENRE:BIBUTILS|Masters thesis" + * + * tag = "GENRE:BIBUTILS" + * value = "Masters thesis" + */ +static int +extract_tag_value( str *tag, str *value, char *p ) +{ + str_empty( tag ); + while ( p && *p && *p!='|' ) { + str_addchar( tag, *p ); + p++; + } + if ( str_memerr( tag ) ) return BIBL_ERR_MEMERR; + + if ( p && *p=='|' ) p++; + + str_empty( value ); + while ( p && *p ) { + str_addchar( value, *p ); + p++; + } + if ( str_memerr( tag ) ) return BIBL_ERR_MEMERR; + + return BIBL_OK; +} + +/* process_defaultadd() + * + * Add tag/value pairs that have "DEFAULT" processing + * unless a tag/value pair with the same tag has already + * been adding during reference processing. + */ +static int +process_defaultadd( fields *f, int reftype, param *r ) +{ + int i, n, process, level, status, ret = BIBL_OK; + str tag, value; + char *p; + + strs_init( &tag, &value, NULL ); + + for ( i=0; i<r->all[reftype].ntags; ++i ) { + + process = ((r->all[reftype]).tags[i]).processingtype; + if ( process!=DEFAULT ) continue; + + level = ((r->all[reftype]).tags[i]).level; + p = ((r->all[reftype]).tags[i]).newstr; + + status = extract_tag_value( &tag, &value, p ); + if ( status!=BIBL_OK ) { + ret = status; + goto out; + } + + n = fields_find( f, tag.data, level ); + if ( n==FIELDS_NOTFOUND ) { + status = fields_add( f, tag.data, value.data, level ); + if ( status!=FIELDS_OK ) { + ret = BIBL_ERR_MEMERR; + goto out; + } + } + + } +out: + strs_free( &tag, &value, NULL ); + + return ret; +} + +/* process_alwaysadd() + * + * Add tag/value pair to reference from the ALWAYS + * processing type without exception (the difference from + * DEFAULT processing). + */ +static int +process_alwaysadd( fields *f, int reftype, param *r ) +{ + int i, process, level, status, ret = BIBL_OK; + str tag, value; + char *p; + + strs_init( &tag, &value, NULL ); + + for ( i=0; i<r->all[reftype].ntags; ++i ) { + + process = ((r->all[reftype]).tags[i]).processingtype; + if ( process!=ALWAYS ) continue; + + level = ((r->all[reftype]).tags[i]).level; + p = ((r->all[reftype]).tags[i]).newstr; + + status = extract_tag_value( &tag, &value, p ); + if ( status!=BIBL_OK ) { + ret = status; + goto out; + } + + status = fields_add( f, tag.data, value.data, level ); + if ( status!=FIELDS_OK ) { + ret = BIBL_ERR_MEMERR; + goto out; + } + } + +out: + strs_free( &tag, &value, NULL ); + + return ret; +} + +static int +read_ref( FILE *fp, bibl *bin, char *filename, param *p ) +{ + int nrefs = 0, bufpos = 0, ok, ret=BIBL_OK, fcharset;/* = CHARSET_UNKNOWN;*/ + str reference, line; + char buf[256]=""; + fields *ref; + str_init( &reference ); + str_init( &line ); + while ( p->readf( fp, buf, sizeof(buf), &bufpos, &line, &reference, &fcharset ) ) { + if ( reference.len==0 ) continue; + ref = fields_new(); + if ( !ref ) { + ret = BIBL_ERR_MEMERR; + bibl_free( bin ); + goto out; + } + if ( p->processf( ref, reference.data, filename, nrefs+1, p )){ + ok = bibl_addref( bin, ref ); + if ( !ok ) { + ret = BIBL_ERR_MEMERR; + bibl_free( bin ); + fields_delete( ref ); + goto out; + } + } else { + fields_delete( ref ); + } + str_empty( &reference ); + if ( fcharset!=CHARSET_UNKNOWN ) { + /* charset from file takes priority over default, but + * not user-specified */ + if ( p->charsetin_src!=BIBL_SRC_USER ) { + p->charsetin_src = BIBL_SRC_FILE; + p->charsetin = fcharset; + if ( fcharset!=CHARSET_UNICODE ) p->utf8in = 0; + } + } + } + if ( p->charsetin==CHARSET_UNICODE ) p->utf8in = 1; +out: + str_free( &line ); + str_free( &reference ); + return ret; +} + +/* Don't manipulate latex for URL's and the like */ +static int +bibl_notexify( char *tag ) +{ + char *protected[] = { "DOI", "URL", "REFNUM", "FILEATTACH" }; + int i, nprotected = sizeof( protected ) / sizeof( protected[0] ); + for ( i=0; i<nprotected; ++i ) + if ( !strcasecmp( tag, protected[i] ) ) return 1; + return 0; +} + +/* bibl_fixcharsetdata() + * + * returns BIBL_OK or BIBL_ERR_MEMERR + */ +static int +bibl_fixcharsetdata( fields *ref, param *p ) +{ + str *data; + char *tag; + long i, n; + int ok; + + n = fields_num( ref ); + + for ( i=0; i<n; ++i ) { + + tag = fields_tag( ref, i, FIELDS_CHRP_NOUSE ); + data = fields_value( ref, i, FIELDS_STRP_NOUSE ); + + if ( bibl_notexify( tag ) ) { + ok = str_convert( data, + p->charsetin, 0, p->utf8in, p->xmlin, + p->charsetout, 0, p->utf8out, p->xmlout ); + } else { + ok = str_convert( data, + p->charsetin, p->latexin, p->utf8in, p->xmlin, + p->charsetout, p->latexout, p->utf8out, p->xmlout ); + } + + if ( !ok ) return BIBL_ERR_MEMERR; + } + + return BIBL_OK; +} + +/* bibl_fixcharsets() + * + * returns BIBL_OK or BIBL_ERR_MEMERR + */ +static int +bibl_fixcharsets( bibl *b, param *p ) +{ + int status = BIBL_OK; + long i; + for ( i=0; i<b->nrefs && status==BIBL_OK; ++i ) + status = bibl_fixcharsetdata( b->ref[i], p ); + return status; +} + +static int +build_refnum( fields *f, long nrefs, int *n ) +{ + char *year, *author, *p, num[512]; + int status, ret = BIBL_OK; + str refnum; + + *n = -1; + + str_init( &refnum ); + + year = fields_findv( f, LEVEL_MAIN, FIELDS_CHRP_NOUSE, "DATE:YEAR" ); + if ( !year ) + year = fields_findv_firstof( f, LEVEL_ANY, FIELDS_CHRP_NOUSE, + "DATE:YEAR", "PARTDATE:YEAR", NULL ); + + author = fields_findv( f, LEVEL_MAIN, FIELDS_CHRP_NOUSE, "AUTHOR" ); + if ( !author ) + author = fields_findv_firstof( f, LEVEL_ANY, FIELDS_CHRP_NOUSE, + "AUTHOR", "AUTHOR:CORP", "AUTHOR:ASIS", NULL ); + + if ( year && author ) { + p = author; + while ( *p && *p!='|' ) + str_addchar( &refnum, *p++ ); + p = year; + while ( *p && *p!=' ' && *p!='\t' ) + str_addchar( &refnum, *p++ ); + } else { + sprintf( num, "%ld", nrefs ); + str_mergestrs( &refnum, "ref", num, NULL ); + } + if ( str_memerr( &refnum ) ) { + ret = BIBL_ERR_MEMERR; + goto out; + } + + status = fields_add( f, "REFNUM", refnum.data, LEVEL_MAIN ); + if ( status!=FIELDS_OK ) ret = BIBL_ERR_MEMERR; + else *n = fields_find( f, "REFNUM", LEVEL_MAIN ); + +out: + str_free( &refnum ); + + return ret; +} + +static int +bibl_checkrefid( bibl *b, param *p ) +{ + char buf[512]; + int n, status; + fields *ref; + long i; + + for ( i=0; i<b->nrefs; ++i ) { + ref = b->ref[i]; + n = fields_find( ref, "REFNUM", LEVEL_MAIN ); + if ( n==FIELDS_NOTFOUND ) { + status = build_refnum( ref, i+1, &n ); + if ( status!=BIBL_OK ) return status; + } + if ( p->addcount ) { + sprintf( buf, "_%ld", i+1 ); + str_strcatc( &(ref->data[n]), buf ); + if ( str_memerr( &(ref->data[n]) ) ) + return BIBL_ERR_MEMERR; + } + } + + return BIBL_OK; +} + +static int +generate_citekey( fields *f, int nref ) +{ + int n1, n2, status, ret; + char *p, buf[100]; + str citekey; + + str_init( &citekey ); + + n1 = fields_find( f, "AUTHOR", LEVEL_MAIN ); + if ( n1==FIELDS_NOTFOUND ) n1 = fields_find( f, "AUTHOR", LEVEL_ANY ); + n2 = fields_find( f, "DATE:YEAR", LEVEL_MAIN ); + if ( n2==FIELDS_NOTFOUND ) n2 = fields_find( f, "DATE:YEAR", LEVEL_ANY ); + if ( n2==FIELDS_NOTFOUND ) n2 = fields_find( f, "PARTDATE:YEAR", LEVEL_MAIN ); + if ( n2==FIELDS_NOTFOUND ) n2 = fields_find( f, "PARTDATE:YEAR", LEVEL_ANY ); + if ( n1!=FIELDS_NOTFOUND && n2!=FIELDS_NOTFOUND ) { + p = f->data[n1].data; + while ( p && *p && *p!='|' ) { + if ( !is_ws( *p ) ) str_addchar( &citekey, *p ); + p++; + } + p = f->data[n2].data; + while ( p && *p ) { + if ( !is_ws( *p ) ) str_addchar( &citekey, *p ); + p++; + } + if ( str_memerr( &citekey ) ) { + ret = -1; + goto out; + } + status = fields_add( f, "REFNUM", citekey.data, 0 ); + if ( status!=FIELDS_OK ) { + ret = -1; + goto out; + } + } else { + sprintf( buf, "ref%d\n", nref ); + str_strcpyc( &citekey, buf ); + } + ret = fields_find( f, "REFNUM", LEVEL_ANY ); +out: + str_free( &citekey ); + return ret; +} + +static int +resolve_citekeys( bibl *b, slist *citekeys, int *dup ) +{ + const char abc[]="abcdefghijklmnopqrstuvwxyz"; + int nsame, ntmp, n, i, j, status = BIBL_OK; + str tmp; + + str_init( &tmp ); + + for ( i=0; i<citekeys->n; ++i ) { + if ( dup[i]==-1 ) continue; + nsame = 0; + for ( j=i; j<citekeys->n; ++j ) { + if ( dup[j]!=i ) continue; + str_strcpy( &tmp, slist_str( citekeys, j ) ); + if ( str_memerr( &tmp ) ) { + status = BIBL_ERR_MEMERR; + goto out; + } + ntmp = nsame; + while ( ntmp >= 26 ) { + str_addchar( &tmp, 'a' ); + ntmp -= 26; + } + if ( ntmp<26 && ntmp>=0 ) + str_addchar( &tmp, abc[ntmp] ); + if ( str_memerr( &tmp ) ) { + status = BIBL_ERR_MEMERR; + goto out; + } + nsame++; + dup[j] = -1; + n = fields_find( b->ref[j], "REFNUM", LEVEL_ANY ); + if ( n!=FIELDS_NOTFOUND ) { + str_strcpy(&((b->ref[j])->data[n]),&tmp); + if ( str_memerr( &((b->ref[j])->data[n]) ) ) { + status = BIBL_ERR_MEMERR; + goto out; + } + } + } + } +out: + str_free( &tmp ); + return status; +} + +static int +get_citekeys( bibl *b, slist *citekeys ) +{ + int i, n, status; + fields *f; + + for ( i=0; i<b->nrefs; ++i ) { + f = b->ref[i]; + n = fields_find( f, "REFNUM", LEVEL_ANY ); + if ( n==FIELDS_NOTFOUND ) n = generate_citekey( f, i ); + if ( n!=FIELDS_NOTFOUND && f->data[n].data ) { + status = slist_add( citekeys, &(f->data[n]) ); + if ( status!=SLIST_OK ) return BIBL_ERR_MEMERR; + } else { + status = slist_addc( citekeys, "" ); + if ( status!=SLIST_OK ) return BIBL_ERR_MEMERR; + } + } + + return BIBL_OK; +} + +static int +dup_citekeys( bibl *b, slist *citekeys ) +{ + int i, j, status = BIBL_OK, *dup, ndup=0; + + dup = ( int * ) malloc( sizeof( int ) * citekeys->n ); + if ( !dup ) return BIBL_ERR_MEMERR; + + for ( i=0; i<citekeys->n; ++i ) dup[i] = -1; + for ( i=0; i<citekeys->n-1; ++i ) { + if ( dup[i]!=-1 ) continue; + for ( j=i+1; j<citekeys->n; ++j ) { + if ( !strcmp( slist_cstr( citekeys, i ), + slist_cstr( citekeys, j ) ) ) { + dup[i] = i; + dup[j] = i; + ndup++; + } + } + } + if ( ndup ) status = resolve_citekeys( b, citekeys, dup ); + free( dup ); + return status; +} + +static int +uniqueify_citekeys( bibl *b ) +{ + slist citekeys; + int status; + slist_init( &citekeys ); + status = get_citekeys( b, &citekeys ); + if ( status!=BIBL_OK ) goto out; + status = dup_citekeys( b, &citekeys ); +out: + slist_free( &citekeys ); + return status; +} + +static int +clean_ref( bibl *bin, param *p ) +{ + if ( p->cleanf ) return p->cleanf( bin, p ); + else return BIBL_OK; +} + +static int +convert_ref( bibl *bin, char *fname, bibl *bout, param *p ) +{ + fields *rin, *rout; + int reftype = 0, ok, status; + long i; + + for ( i=0; i<bin->nrefs; ++i ) { + rin = bin->ref[i]; + rout = fields_new(); + if ( !rout ) return BIBL_ERR_MEMERR; + if ( p->typef ) + reftype = p->typef( rin, fname, i+1, p ); + status = p->convertf( rin, rout, reftype, p ); + if ( status!=BIBL_OK ) return status; + if ( p->all ) { + status = process_alwaysadd( rout, reftype, p ); + if ( status!=BIBL_OK ) return status; + status = process_defaultadd( rout, reftype, p ); + if ( status!=BIBL_OK ) return status; + } + ok = bibl_addref( bout, rout ); + if ( !ok ) return BIBL_ERR_MEMERR; + } + if ( debug_set( p ) ) { + fflush( stdout ); + fprintf( stderr, "-------------------start for convert_ref\n"); + bibl_verbose0( bout ); + fprintf( stderr, "-------------------end for convert_ref\n" ); + fflush( stderr ); + } + status = uniqueify_citekeys( bout ); + return status; +} + +int +bibl_read( bibl *b, FILE *fp, char *filename, param *p ) +{ + int ok, status; + param lp; + bibl bin; + + if ( !b ) return BIBL_ERR_BADINPUT; + if ( !fp ) return BIBL_ERR_BADINPUT; + if ( !p ) return BIBL_ERR_BADINPUT; + + if ( bibl_illegalinmode( p->readformat ) ) { + if ( debug_set( p ) ) { + fflush( stdout ); + report_params( stderr, "bibl_read", p ); + } + return BIBL_ERR_BADINPUT; + } + + status = bibl_setreadparams( &lp, p ); + if ( status!=BIBL_OK ) { + if ( debug_set( p ) ) { + fflush( stdout ); + report_params( stderr, "bibl_read", p ); + } + return status; + } + + bibl_init( &bin ); + + status = read_ref( fp, &bin, filename, &lp ); + if ( status!=BIBL_OK ) { + if ( debug_set( p ) ) { + fflush( stdout ); + report_params( stderr, "bibl_read", &lp ); + } + bibl_freeparams( &lp ); + return status; + } + + if ( debug_set( p ) ) { + fflush( stdout ); + report_params( stderr, "bibl_read", &lp ); + fprintf( stderr, "-------------------raw_input start for bibl_read\n"); + bibl_verbose0( &bin ); + fprintf( stderr, "-------------------raw_input end for bibl_read\n" ); + fflush( stderr ); + } + + if ( !lp.output_raw || ( lp.output_raw & BIBL_RAW_WITHCHARCONVERT ) ) { + status = bibl_fixcharsets( &bin, &lp ); + if ( status!=BIBL_OK ) return status; + if ( debug_set( p ) ) { + fprintf( stderr, "-------------------post_fixcharsets start for bibl_read\n"); + bibl_verbose0( &bin ); + fprintf( stderr, "-------------------post_fixcharsets end for bibl_read\n" ); + fflush( stderr ); + } + } + if ( !lp.output_raw ) { + status = clean_ref( &bin, &lp ); + if ( status!=BIBL_OK ) return status; + if ( debug_set( p ) ) { + fprintf( stderr, "-------------------post_clean_ref start for bibl_read\n"); + bibl_verbose0( &bin ); + fprintf( stderr, "-------------------post_clean_ref end for bibl_read\n" ); + fflush( stderr ); + } + ok = convert_ref( &bin, filename, b, &lp ); + if ( ok!=BIBL_OK ) return ok; + if ( debug_set( p ) ) { + fprintf( stderr, "-------------------post_convert_ref start for bibl_read\n"); + bibl_verbose0( &bin ); + fprintf( stderr, "-------------------post_convert_ref end for bibl_read\n" ); + fflush( stderr ); + } + } else { + if ( debug_set( p ) ) { + fprintf( stderr, "-------------------here1 start for bibl_read\n"); + bibl_verbose0( &bin ); + fprintf( stderr, "-------------------here1 end for bibl_read\n" ); + fflush( stderr ); + } + ok = bibl_copy( b, &bin ); + if ( !ok ) { + bibl_freeparams( &lp ); + return BIBL_ERR_MEMERR; + } + } + if ( !lp.output_raw || ( lp.output_raw & BIBL_RAW_WITHMAKEREFID ) ) + bibl_checkrefid( b, &lp ); + + bibl_free( &bin ); + + bibl_freeparams( &lp ); + + return BIBL_OK; +} + +static FILE * +singlerefname( fields *reffields, long nref, int mode ) +{ + char outfile[2048]; + char suffix[5] = "xml"; + FILE *fp; + long count; + int found; + if ( mode==BIBL_ADSABSOUT ) strcpy( suffix, "ads" ); + else if ( mode==BIBL_BIBTEXOUT ) strcpy( suffix, "bib" ); + else if ( mode==BIBL_ENDNOTEOUT ) strcpy( suffix, "end" ); + else if ( mode==BIBL_ISIOUT ) strcpy( suffix, "isi" ); + else if ( mode==BIBL_MODSOUT ) strcpy( suffix, "xml" ); + else if ( mode==BIBL_RISOUT ) strcpy( suffix, "ris" ); + else if ( mode==BIBL_WORD2007OUT ) strcpy( suffix, "xml" ); + found = fields_find( reffields, "REFNUM", LEVEL_MAIN ); + /* find new filename based on reference */ + if ( found!=-1 ) { + sprintf( outfile,"%s.%s",reffields->data[found].data, suffix ); + } else sprintf( outfile,"%ld.%s",nref, suffix ); + count = 0; + fp = fopen( outfile, "r" ); + while ( fp ) { + fclose(fp); + count++; + if ( count==60000 ) return NULL; + if ( found!=-1 ) + sprintf( outfile, "%s_%ld.%s", + reffields->data[found].data, count, suffix ); + else sprintf( outfile,"%ld_%ld.%s",nref, count, suffix ); + fp = fopen( outfile, "r" ); + } + return fopen( outfile, "w" ); +} + +static int +bibl_writeeachfp( FILE *fp, bibl *b, param *p ) +{ + fields out, *use = &out; + int status; + long i; + + fields_init( &out ); + + for ( i=0; i<b->nrefs; ++i ) { + + fp = singlerefname( b->ref[i], i, p->writeformat ); + if ( !fp ) return BIBL_ERR_CANTOPEN; + + if ( p->headerf ) p->headerf( fp, p ); + + if ( p->assemblef ) { + fields_free( &out ); + status = p->assemblef( b->ref[i], &out, p, i ); + if ( status!=BIBL_OK ) break; + } else { + use = b->ref[i]; + } + + status = p->writef( use, fp, p, i ); + + if ( p->footerf ) p->footerf( fp ); + fclose( fp ); + + if ( status!=BIBL_OK ) return status; + } + + return BIBL_OK; +} + +static int +bibl_writefp( FILE *fp, bibl *b, param *p ) +{ + int status = BIBL_OK; + fields out, *use = &out; + long i; + + fields_init( &out ); + + if ( debug_set( p ) && p->assemblef ) { + fprintf( stderr, "-------------------assemblef start for bibl_write\n"); + } + + if ( p->headerf ) p->headerf( fp, p ); + for ( i=0; i<b->nrefs; ++i ) { + + if ( p->assemblef ) { + fields_free( &out ); + status = p->assemblef( b->ref[i], &out, p, i ); + if ( status!=BIBL_OK ) break; + if ( debug_set( p ) ) bibl_verbose2( &out, "", i+1 ); + } else { + use = b->ref[i]; + } + + status = p->writef( use, fp, p, i ); + if ( status!=BIBL_OK ) break; + + } + + if ( debug_set( p ) && p->assemblef ) { + fprintf( stderr, "-------------------assemblef end for bibl_write\n"); + } + + if ( p->footerf ) p->footerf( fp ); + return status; +} + +int +bibl_write( bibl *b, FILE *fp, param *p ) +{ + int status; + param lp; + + if ( !b ) return BIBL_ERR_BADINPUT; + if ( !p ) return BIBL_ERR_BADINPUT; + if ( bibl_illegaloutmode( p->writeformat ) ) return BIBL_ERR_BADINPUT; + if ( !fp && !p->singlerefperfile ) return BIBL_ERR_BADINPUT; + + status = bibl_setwriteparams( &lp, p ); + if ( status!=BIBL_OK ) return status; + + if ( debug_set( p ) ) { + report_params( stderr, "bibl_write", &lp ); + fflush( stdout ); + } + + if ( debug_set( p ) ) { + fprintf( stderr, "-------------------raw input start for bibl_write\n"); + bibl_verbose0( b ); + fprintf( stderr, "-------------------raw input end for bibl_write\n" ); + fflush( stderr ); + } + + status = bibl_fixcharsets( b, &lp ); + if ( status!=BIBL_OK ) goto out; + + if ( debug_set( p ) ) { + fprintf( stderr, "-------------------post-fixcharsets start for bibl_write\n"); + bibl_verbose0( b ); + fprintf( stderr, "-------------------post-fixcharsets end for bibl_write\n" ); + fflush( stderr ); + } + + if ( p->singlerefperfile ) status = bibl_writeeachfp( fp, b, &lp ); + else status = bibl_writefp( fp, b, &lp ); + +out: + bibl_freeparams( &lp ); + return status; +} |