/* * bibutils.c * * Copyright (c) Chris Putnam 2005-2009 * * Source code released under the GPL * */ #include #include #include "bibutils.h" /* internal includes */ #include "reftypes.h" #include "bibtexin.h" #include "biblatexin.h" #include "bibtexout.h" #include "copacin.h" #include "endin.h" #include "endxmlin.h" #include "endout.h" #include "isiin.h" #include "isiout.h" #include "medin.h" #include "modsin.h" #include "risin.h" #include "wordin.h" #include "risout.h" #include "modsout.h" #include "wordout.h" #include "adsout.h" #include "newstr_conv.h" #include "is_ws.h" #include "ebiin.h" typedef struct convert_rules { int (*readf)(FILE*,char*,int,int*,newstr*,newstr*,int*); int (*processf)(fields*,char*,char*,long); void (*cleanf)(bibl*,param*); int (*typef) (fields*,char*,int,param*,variants*,int); void (*convertf)(fields*,fields*,int,param*,variants*,int); void (*headerf)(FILE*,param*); void (*footerf)(FILE*); void (*writef)(fields*,FILE*,param*,unsigned long); variants *all; int nall; } convert_rules; void bibl_initparams( param *p, int readmode, int writemode, char *progname ) { p->readformat = readmode; p->writeformat = writemode; p->format_opts = 0; p->charsetin = BIBL_CHARSET_DEFAULT; p->charsetin_src = BIBL_SRC_DEFAULT; p->charsetout = BIBL_CHARSET_DEFAULT; p->charsetout_src = BIBL_SRC_DEFAULT; p->latexin = 0; p->latexout = 0; p->utf8in = 0; p->utf8out = 0; p->utf8bom = 0; p->xmlout = 0; p->nosplittitle = 0; p->verbose = 0; p->addcount = 0; p->singlerefperfile = 0; p->output_raw = 0; /* keep MODS tags for output filter */ list_init( &(p->asis) ); list_init( &(p->corps) ); if ( !progname ) p->progname = NULL; else p->progname = strdup( progname ); if ( readmode == BIBL_BIBTEXIN || readmode == BIBL_BIBLATEXIN ) { p->latexin = 1; } else if ( readmode == BIBL_MODSIN ) { p->xmlin = 1; p->utf8in = 1; p->output_raw = BIBL_RAW_WITHMAKEREFID | BIBL_RAW_WITHCHARCONVERT; p->charsetin = BIBL_CHARSET_UNICODE; } else if ( readmode == BIBL_WORDIN ) { p->xmlin = 1; p->utf8in = 1; p->output_raw = BIBL_RAW_WITHMAKEREFID | BIBL_RAW_WITHCHARCONVERT; p->charsetin = BIBL_CHARSET_UNICODE; } else if ( readmode == BIBL_MEDLINEIN ) { /* default medline to UTF8 Unicode */ p->charsetin = BIBL_CHARSET_UNICODE; p->utf8in = 1; p->xmlin = 1; p->output_raw = BIBL_RAW_WITHMAKEREFID | BIBL_RAW_WITHCHARCONVERT; } else if ( readmode == BIBL_EBIIN ) { /* default medline to UTF8 Unicode */ p->charsetin = BIBL_CHARSET_UNICODE; p->utf8in = 1; p->xmlin = 1; p->output_raw = BIBL_RAW_WITHMAKEREFID | BIBL_RAW_WITHCHARCONVERT; } else if ( readmode == BIBL_ENDNOTEXMLIN ) { p->xmlin = 1; p->utf8in = 1; } if ( writemode == BIBL_BIBTEXOUT ) { p->latexout = 1; } else if ( writemode == BIBL_MODSOUT ) { /* default to UTF8 Unicode with BOM written */ p->charsetout = BIBL_CHARSET_UNICODE; p->utf8out = 1; p->utf8bom = 1; p->xmlout = 1; } else if ( writemode == BIBL_WORD2007OUT ) { if ( !p->utf8out ) p->xmlout = 3; else p->xmlout = 1; p->charsetout = BIBL_CHARSET_UNICODE; } else p->xmlout = 0; } void bibl_freeparams( param *p ) { list_free( &(p->asis) ); list_free( &(p->corps) ); if ( p->progname ) free( p->progname ); } static void bibl_readlist( list *pl, char *progname, char *filename ) { if ( !list_fill( pl, filename ) ) { fprintf( stderr, "%s: warning problems reading '%s' " "obtained %d elements\n", progname, filename, pl->n ); } } void bibl_readasis( param *p, char *filename ) { bibl_readlist( &(p->asis), p->progname, filename ); } void bibl_readcorps( param *p, char *filename ) { bibl_readlist( &(p->corps), p->progname, filename ); } static void bibl_addtolist( list *pl, char *entry ) { list_add( pl, entry ); } void bibl_addtoasis( param *p, char *entry ) { bibl_addtolist( &(p->asis), entry ); } void bibl_addtocorps( param *p, char *entry ) { bibl_addtolist( &(p->corps), entry ); } static void bibl_duplicateparams( param *np, param *op ) { list_init( &(np->asis) ); list_init( &(np->corps) ); list_copy( &(np->asis), &(op->asis ) ); list_copy( &(np->corps), &(op->corps ) ); if ( !op->progname ) np->progname = NULL; else np->progname = strdup( op->progname ); 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; } 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."); 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; } void bibl_verbose2( fields *info, char *filename, long nrefs ) { int i; fprintf( stderr, "======== %s %ld : converted\n", filename, nrefs ); for ( i=0; infields; ++i ) { fprintf( stderr, "'%s'='%s' level=%d\n", info->tag[i].data, info->data[i].data , info->level[i]); } fprintf( stderr, "\n" ); fflush( stderr ); } void bibl_verbose1( fields *info, fields *orig, char *filename, long nrefs ) { int i; fprintf( stderr, "======== %s %ld : processed\n", filename, nrefs ); for ( i=0; infields; ++i ) { fprintf( stderr, "'%s'='%s' level=%d\n", orig->tag[i].data, orig->data[i].data , orig->level[i]); } if ( info ) bibl_verbose2( info, filename, nrefs ); } void bibl_verbose0( bibl *bin ) { int i; for ( i=0; inrefs; ++i ) bibl_verbose2( bin->ref[i], "", i+1 ); } static void process_alwaysadd( fields *info, int reftype, convert_rules *r ) { char tag[512], data[512], *p, *q; int i, process, level; for ( i=0; iall[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; q = tag; while ( p && *p && *p!='|' ) { *q = *p; q++; p++; } *q = '\0'; q = data; if ( p && *p=='|' ) p++; while ( p && *p ) { *q = *p; q++; p++; } *q = '\0'; fields_add( info, tag, data, level ); } } static int read_ref( FILE *fp, bibl *bin, char *filename, convert_rules *r, param *p ) { newstr reference, line; fields *ref; char buf[256]=""; int nrefs = 0, bufpos = 0, fcharset;/* = CHARSET_UNKNOWN;*/ newstr_init( &reference ); newstr_init( &line ); while ( r->readf( fp, buf, sizeof(buf), &bufpos, &line, &reference, &fcharset ) ) { if ( reference.len==0 ) continue; ref = fields_new(); if ( !ref ) return BIBL_ERR_MEMERR; if ( r->processf( ref, reference.data, filename, nrefs+1 )){ bibl_addref( bin, ref ); } else { fields_free( ref ); free( ref ); } newstr_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; newstr_free( &line ); newstr_free( &reference ); return BIBL_OK; } static void bibl_fixcharsets( bibl *b, param *p ) { fields *ref; long i, j; int swap = 0; int latexout = p->latexout; int latexin = p->latexin; for ( i=0; inrefs; ++i ) { ref = b->ref[i]; for ( j=0; jnfields; ++j ) { if ( latexin || latexout ) { /* don't texify/detexify URL's and the like */ if ( !strcasecmp( ref->tag[j].data, "DOI" ) || !strcasecmp( ref->tag[j].data, "URL" ) || !strcasecmp( ref->tag[j].data, "REFNUM" )){ latexin = 0; latexout = 0; swap = 1; } } newstr_convert( &(ref->data[j]), p->charsetin, latexin, p->utf8in, p->xmlin, p->charsetout, latexout, p->utf8out, p->xmlout ); if ( swap ) { swap = 0; latexin = p->latexin; latexout = p->latexout; } } } } static int build_refnum( fields *info, long nrefs ) { newstr refnum; char *p, num[512]; int y, a; newstr_init( &refnum ); y = fields_find( info, "YEAR", 0 ); if ( y==-1 ) y = fields_find( info, "YEAR", -1 ); if ( y==-1 ) y = fields_find( info, "PARTYEAR", -1 ); a = fields_find( info, "AUTHOR", 0 ); if ( a==-1 ) a = fields_find( info, "AUTHOR", -1 ); if ( a==-1 ) a = fields_find( info, "AUTHOR:CORP", -1 ); if ( a==-1 ) a = fields_find( info, "AUTHOR:ASIS", -1 ); if ( a!=-1 && y!=-1 ) { p = info->data[a].data; while ( p && *p && *p!='|' ) newstr_addchar( &refnum, *p++ ); p = info->data[y].data; while ( p && *p && *p!=' ' && *p!='\t' ) newstr_addchar( &refnum, *p++ ); } else { sprintf( num, "%ld", nrefs ); newstr_strcpy( &refnum, "ref" ); newstr_strcat( &refnum, num ); } fields_add( info, "REFNUM", refnum.data, 0 ); newstr_free( &refnum ); return fields_find( info, "REFNUM", 0 ); } static void bibl_checkrefid( bibl *b, param *p ) { fields *ref; long i; char buf[512]; int n; for ( i=0; inrefs; ++i ) { ref = b->ref[i]; n = fields_find( ref, "REFNUM", 0 ); if ( n==-1 ) n = build_refnum( ref, i+1 ); if ( p->addcount ) { sprintf( buf, "_%ld", i+1 ); newstr_strcat( &(ref->data[n]), buf ); } } } static int generate_citekey( fields *info, int nref ) { newstr citekey; int n1, n2; char *p, buf[100]; newstr_init( &citekey ); n1 = fields_find( info, "AUTHOR", 0 ); if ( n1==-1 ) n1 = fields_find( info, "AUTHOR", -1 ); n2 = fields_find( info, "YEAR", 0 ); if ( n2==-1 ) n2 = fields_find( info, "YEAR", -1 ); if ( n2==-1 ) n2 = fields_find( info, "PARTYEAR", 0 ); if ( n2==-1 ) n2 = fields_find( info, "PARTYEAR", -1 ); if ( n1!=-1 && n2!=-1 ) { p = info->data[n1].data; while ( p && *p && *p!='|' ) { if ( !is_ws( *p ) ) newstr_addchar( &citekey, *p ); p++; } p = info->data[n2].data; while ( p && *p ) { if ( !is_ws( *p ) ) newstr_addchar( &citekey, *p ); p++; } fields_add( info, "REFNUM", citekey.data, 0 ); } else { sprintf( buf, "ref%d\n", nref ); newstr_strcpy( &citekey, buf ); } newstr_free( &citekey ); return fields_find( info, "REFNUM", -1 ); } static void resolve_citekeys( bibl *b, list *citekeys, int *dup ) { char abc[]="abcdefghijklmnopqrstuvwxyz"; newstr tmp; int nsame, ntmp, n, i, j; newstr_init( &tmp ); for ( i=0; in; ++i ) { if ( dup[i]==-1 ) continue; nsame = 0; for ( j=i; jn; ++j ) { if ( dup[j]!=i ) continue; newstr_newstrcpy( &tmp, &(citekeys->str[j]) ); ntmp = nsame; while ( ntmp >= 26 ) { newstr_addchar( &tmp, 'a' ); ntmp -= 26; } if ( ntmp<26 && ntmp>=0 ) newstr_addchar( &tmp, abc[ntmp] ); nsame++; dup[j] = -1; n = fields_find( b->ref[j], "REFNUM", -1 ); if ( n!=-1 ) newstr_newstrcpy(&((b->ref[j])->data[n]),&tmp); } } newstr_free( &tmp ); } static void get_citekeys( bibl *b, list *citekeys ) { fields *info; int i, n; for ( i=0; inrefs; ++i ) { info = b->ref[i]; n = fields_find( info, "REFNUM", -1 ); if ( n==-1 ) n = generate_citekey( info, i ); if ( n!=-1 && info->data[n].data ) list_add( citekeys, info->data[n].data ); else list_add( citekeys, "" ); } } static int dup_citekeys( bibl *b, list *citekeys ) { int i, j, *dup, ndup=0; dup = ( int * ) malloc( sizeof( int ) * citekeys->n ); if ( !dup ) return 0; for ( i=0; in; ++i ) dup[i] = -1; for ( i=0; in-1; ++i ) { if ( dup[i]!=-1 ) continue; for ( j=i+1; jn; ++j ) { if ( !strcmp( citekeys->str[i].data, citekeys->str[j].data ) ) { dup[i] = i; dup[j] = i; ndup++; } } } if ( ndup ) resolve_citekeys( b, citekeys, dup ); free( dup ); return ndup; } static void uniqueify_citekeys( bibl *b ) { list citekeys; list_init( &citekeys ); get_citekeys( b, &citekeys ); dup_citekeys( b, &citekeys ); list_free( &citekeys ); } static int convert_ref( bibl *bin, char *fname, bibl *bout, convert_rules *r, param *p ) { fields *rin, *rout; long i; int reftype; if ( r->cleanf ) r->cleanf( bin, p ); for ( i=0; inrefs; ++i ) { rin = bin->ref[i]; rout = fields_new(); if ( !rout ) return BIBL_ERR_MEMERR; if ( r->typef ) reftype = r->typef( rin, fname, i+1, p, r->all, r->nall ); else reftype = 0; r->convertf( rin, rout, reftype, p, r->all, r->nall ); if ( r->all ) process_alwaysadd( rout, reftype, r ); if ( p->verbose ) bibl_verbose1( rout, rin, fname, i+1 ); bibl_addref( bout, rout ); } uniqueify_citekeys( bout ); return BIBL_OK; } static void rules_init( convert_rules *r, int mode ) { switch ( mode ) { case BIBL_BIBTEXIN: r->readf = bibtexin_readf; r->processf = bibtexin_processf; r->cleanf = bibtexin_cleanf; r->typef = bibtexin_typef; r->convertf = bibtexin_convertf; r->all = bibtex_all; r->nall = bibtex_nall; break; case BIBL_BIBTEXOUT: r->headerf = bibtexout_writeheader; r->footerf = NULL; r->writef = bibtexout_write; break; case BIBL_BIBLATEXIN: r->readf = biblatexin_readf; r->processf = biblatexin_processf; r->cleanf = biblatexin_cleanf; r->typef = biblatexin_typef; r->convertf = biblatexin_convertf; r->all = biblatex_all; r->nall = biblatex_nall; break; case BIBL_ENDNOTEIN: r->readf = endin_readf; r->cleanf = endin_cleanf; r->processf = endin_processf; r->typef = endin_typef; r->convertf = endin_convertf; r->all = end_all; r->nall = end_nall; break; case BIBL_ENDNOTEXMLIN: r->readf = endxmlin_readf; r->cleanf = NULL; r->processf = endxmlin_processf; r->typef = endin_typef; r->convertf = endin_convertf; r->all = end_all; r->nall = end_nall; break; case BIBL_ENDNOTEOUT: r->headerf = endout_writeheader; r->footerf = NULL; r->writef = endout_write; break; case BIBL_ADSABSOUT: r->headerf = adsout_writeheader; r->footerf = NULL; r->writef = adsout_write; break; case BIBL_RISIN: r->readf = risin_readf; r->cleanf = NULL; r->processf = risin_processf; r->typef = risin_typef; r->convertf = risin_convertf; r->all = ris_all; r->nall = ris_nall; break; case BIBL_RISOUT: r->headerf = risout_writeheader; r->footerf = NULL; r->writef = risout_write; break; case BIBL_ISIIN: r->readf = isiin_readf; r->cleanf = NULL; r->processf = isiin_processf; r->typef = isiin_typef; r->convertf = isiin_convertf; r->all = isi_all; r->nall = isi_nall; break; case BIBL_ISIOUT: r->headerf = isiout_writeheader; r->footerf = NULL; r->writef = isiout_write; break; case BIBL_COPACIN: r->readf = copacin_readf; r->cleanf = NULL; r->processf = copacin_processf; r->typef = NULL; r->convertf = copacin_convertf; r->all = copac_all; r->nall = copac_nall; break; case BIBL_MEDLINEIN: r->readf = medin_readf; r->cleanf = NULL; r->processf = medin_processf; r->typef = NULL; r->convertf = NULL; r->all = NULL; r->nall = 0; break; case BIBL_WORDIN: r->readf = wordin_readf; r->cleanf = NULL; r->processf = wordin_processf; r->typef = NULL; r->convertf = NULL; r->all = NULL; r->nall = 0; break; case BIBL_EBIIN: r->readf = ebiin_readf; r->cleanf = NULL; r->processf = ebiin_processf; r->typef = NULL; r->convertf = NULL; r->all = NULL; r->nall = 0; break; case BIBL_MODSIN: r->readf = modsin_readf; r->cleanf = NULL; r->processf = modsin_processf; r->typef = NULL; r->convertf = NULL; r->all = NULL; r->nall = 0; break; case BIBL_MODSOUT: r->headerf = modsout_writeheader; r->footerf = modsout_writefooter; r->writef = modsout_write; break; case BIBL_WORD2007OUT: r->headerf = wordout_writeheader; r->footerf = wordout_writefooter; r->writef = wordout_write; break; default: break; } } static void bibl_setreadparams( param *np, param *op ) { bibl_duplicateparams( np, op ); /* list_init( &(np->asis) ); list_init( &(np->corps) ); if ( !op->progname ) np->progname = NULL; else np->progname = strdup( op->progname ); np->readformat = op->readformat; np->writeformat = op->writeformat; np->latexin = op->latexin; np->utf8in = op->utf8in; np->xmlin = op->xmlin; np->charsetin = op->charsetin; np->charsetin_src = op->charsetin_src; np->verbose = op->verbose; np->format_opts = op->format_opts; np->addcount = op->addcount; np->output_raw = op->output_raw; list_copy( &(np->asis), &(op->asis) ); list_copy( &(np->corps), &(op->corps) );*/ np->utf8out = 1; np->charsetout = BIBL_CHARSET_UNICODE; np->charsetout_src = BIBL_SRC_DEFAULT; np->xmlout = 0; np->latexout = 0; } int bibl_read( bibl *b, FILE *fp, char *filename, param *p ) { convert_rules r; 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 ) ) return BIBL_ERR_BADINPUT; bibl_setreadparams( &lp, p ); bibl_init( &bin ); rules_init( &r, p->readformat ); read_ref( fp, &bin, filename, &r, &lp ); if ( !lp.output_raw || ( lp.output_raw & BIBL_RAW_WITHCHARCONVERT ) ) bibl_fixcharsets( &bin, &lp ); if ( !lp.output_raw ) convert_ref( &bin, filename, b, &r, &lp ); else { if ( p->verbose > 1 ) bibl_verbose0( &bin ); bibl_copy( b, &bin ); } if ( !lp.output_raw || ( lp.output_raw & BIBL_RAW_WITHMAKEREFID ) ) bibl_checkrefid( b, &lp ); bibl_free( &bin ); 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_BIBTEXOUT ) strcpy( suffix, "bib" ); else if ( mode==BIBL_RISOUT ) strcpy( suffix, "ris" ); else if ( mode==BIBL_ENDNOTEOUT ) strcpy( suffix, "end" ); else if ( mode==BIBL_ADSABSOUT ) strcpy( suffix, "ads" ); found = fields_find( reffields, "REFNUM", 0 ); /* 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 output_bibl( FILE *fp, bibl *b, convert_rules *r, param *p ) { long i; if ( !p->singlerefperfile && r->headerf ) r->headerf( fp, p ); for ( i=0; inrefs; ++i ) { if ( p->singlerefperfile ) { fp = singlerefname( b->ref[i], i, p->writeformat ); if ( fp ) { if ( r->headerf ) r->headerf( fp, p ); } else return BIBL_ERR_CANTOPEN; } r->writef( b->ref[i], fp, p, i ); if ( p->singlerefperfile ) { if ( r->footerf ) r->footerf( fp ); fclose( fp ); } } if ( !p->singlerefperfile && r->footerf ) r->footerf( fp ); return 1; } static void bibl_setwriteparams( param *np, param *op ) { bibl_duplicateparams( np, op ); /* list_init( &(np->asis) ); list_init( &(np->corps) ); list_copy( &(np->asis), &(op->asis ) ); list_copy( &(np->corps), &(op->corps ) ); if ( !op->progname ) np->progname = NULL; else np->progname = strdup( op->progname ); np->readformat = op->readformat; np->writeformat = op->writeformat; np->utf8out = op->utf8out; np->utf8bom = op->utf8bom; np->charsetout = op->charsetout; np->charsetout_src = op->charsetout_src; np->latexout = op->latexout; np->xmlout = op->xmlout; 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->xmlin = 0; np->latexin = 0; np->utf8in = 1; np->charsetin = BIBL_CHARSET_UNICODE; np->charsetin_src = BIBL_SRC_DEFAULT; } int bibl_write( bibl *b, FILE *fp, param *p ) { convert_rules r; 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 || !p->singlerefperfile ) ) return BIBL_ERR_BADINPUT; rules_init( &r, p->writeformat ); bibl_setwriteparams( &lp, p ); bibl_fixcharsets( b, &lp ); output_bibl( fp, b, &r, &lp ); return BIBL_OK; }