1 /*
2 * bibcore.c
3 *
4 * Copyright (c) Chris Putnam 2005-2020
5 *
6 * Source code released under the GPL version 2
7 *
8 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include "bibutils.h"
12
13 /* internal includes */
14 #include "reftypes.h"
15 #include "charsets.h"
16 #include "str_conv.h"
17 #include "is_ws.h"
18
19 /* illegal modes to pass in, but use internally for consistency */
20 #define BIBL_INTERNALIN (BIBL_LASTIN+1)
21 #define BIBL_INTERNALOUT (BIBL_LASTOUT+1)
22
23 #define debug_set( p ) ( (p)->verbose > 1 )
24 #define verbose_set( p ) ( (p)->verbose )
25
26 static void
report_params(FILE * fp,const char * f,param * p)27 report_params( FILE *fp, const char *f, param *p )
28 {
29 fflush( NULL );
30
31 fprintf( fp, "-------------------params start for %s\n", f );
32 fprintf( fp, "\tprogname='%s'\n\n", p->progname );
33
34 fprintf( fp, "\treadformat=%d", p->readformat );
35 switch ( p->readformat ) {
36 case BIBL_INTERNALIN: fprintf( fp, " (BIBL_INTERNALIN)\n" ); break;
37 case BIBL_MODSIN: fprintf( fp, " (BIBL_MODSIN)\n" ); break;
38 case BIBL_BIBTEXIN: fprintf( fp, " (BIBL_BIBTEXIN)\n" ); break;
39 case BIBL_RISIN: fprintf( fp, " (BIBL_RISIN)\n" ); break;
40 case BIBL_ENDNOTEIN: fprintf( fp, " (BIBL_ENDNOTEIN)\n" ); break;
41 case BIBL_COPACIN: fprintf( fp, " (BIBL_COPACIN)\n" ); break;
42 case BIBL_ISIIN: fprintf( fp, " (BIBL_ISIIN)\n" ); break;
43 case BIBL_MEDLINEIN: fprintf( fp, " (BIBL_MEDLINEIN)\n" ); break;
44 case BIBL_ENDNOTEXMLIN: fprintf( fp, " (BIBL_ENDNOTEXMLIN)\n" ); break;
45 case BIBL_BIBLATEXIN: fprintf( fp, " (BIBL_BIBLATEXIN)\n" ); break;
46 case BIBL_EBIIN: fprintf( fp, " (BIBL_EBIIN)\n" ); break;
47 case BIBL_WORDIN: fprintf( fp, " (BIBL_WORDIN)\n" ); break;
48 case BIBL_NBIBIN: fprintf( fp, " (BIBL_NBIBIN)\n" ); break;
49 default: fprintf( fp, " (Illegal value)\n" ); break;
50 }
51 fprintf( fp, "\tcharsetin=%d\n", p->charsetin );
52 fprintf( fp, "\tcharsetin_src=%d", p->charsetin_src );
53 switch ( p->charsetin_src ) {
54 case BIBL_SRC_DEFAULT: fprintf( fp, " (BIBL_SRC_DEFAULT)\n" ); break;
55 case BIBL_SRC_FILE: fprintf( fp, " (BIBL_SRC_FILE)\n" ); break;
56 case BIBL_SRC_USER: fprintf( fp, " (BIBL_SRC_USER)\n" ); break;
57 default: fprintf( fp, " (Illegal value)\n" ); break;
58 }
59 fprintf( fp, "\tutf8in=%d\n", p->utf8in );
60 fprintf( fp, "\tlatexin=%d\n", p->latexin );
61 fprintf( fp, "\txmlin=%d\n\n", p->xmlin );
62
63 fprintf( fp, "\twriteformat=%d", p->writeformat );
64 switch ( p->writeformat ) {
65 case BIBL_INTERNALOUT: fprintf( fp, " (BIBL_INTERNALOUT)\n" ); break;
66 case BIBL_ADSABSOUT: fprintf( fp, " (BIBL_ADSABSOUT)\n" ); break;
67 case BIBL_BIBTEXOUT: fprintf( fp, " (BIBL_BIBTEXOUT)\n" ); break;
68 case BIBL_ENDNOTEOUT: fprintf( fp, " (BIBL_ENDNOTEOUT)\n" ); break;
69 case BIBL_ISIOUT: fprintf( fp, " (BIBL_ISIOUT)\n" ); break;
70 case BIBL_MODSOUT: fprintf( fp, " (BIBL_MODSOUT)\n" ); break;
71 case BIBL_NBIBOUT: fprintf( fp, " (BIBL_NBIBOUT)\n" ); break;
72 case BIBL_RISOUT: fprintf( fp, " (BIBL_RISOUT)\n" ); break;
73 case BIBL_WORD2007OUT: fprintf( fp, " (BIBL_WORD2007OUT)\n" ); break;
74 default: fprintf( fp, " (Illegal value)\n"); break;
75 }
76 fprintf( fp, "\tcharsetout=%d\n", p->charsetout );
77 fprintf( fp, "\tcharsetout_src=%d", p->charsetout_src );
78 switch ( p->charsetout_src ) {
79 case BIBL_SRC_DEFAULT: fprintf( fp, " (BIBL_SRC_DEFAULT)\n" ); break;
80 case BIBL_SRC_FILE: fprintf( fp, " (BIBL_SRC_FILE)\n" ); break;
81 case BIBL_SRC_USER: fprintf( fp, " (BIBL_SRC_USER)\n" ); break;
82 default: fprintf( fp, " (Illegal value)\n" ); break;
83 }
84 fprintf( fp, "\tutf8out=%d\n", p->utf8out );
85 fprintf( fp, "\tutf8bom=%d\n", p->utf8bom );
86 fprintf( fp, "\tlatexout=%d\n", p->latexout );
87 fprintf( fp, "\txmlout=%d\n", p->xmlout );
88 fprintf( fp, "-------------------params end for %s\n", f );
89
90 fflush( fp );
91 }
92
93 /* bibl_duplicateparams()
94 *
95 * Returns status of BIBL_OK or BIBL_ERR_MEMERR
96 */
97 static int
bibl_duplicateparams(param * np,param * op)98 bibl_duplicateparams( param *np, param *op )
99 {
100 int status;
101
102 slist_init( &(np->asis) );
103 status = slist_copy( &(np->asis), &(op->asis ) );
104 if ( status!=SLIST_OK ) return BIBL_ERR_MEMERR;
105
106 slist_init( &(np->corps) );
107 status = slist_copy( &(np->corps), &(op->corps ) );
108 if ( status!=SLIST_OK ) return BIBL_ERR_MEMERR;
109
110 if ( !op->progname ) np->progname = NULL;
111 else {
112 np->progname = strdup( op->progname );
113 if ( !np->progname ) return BIBL_ERR_MEMERR;
114 }
115
116 np->readformat = op->readformat;
117 np->charsetin = op->charsetin;
118 np->charsetin_src = op->charsetin_src;
119 np->utf8in = op->utf8in;
120 np->latexin = op->latexin;
121 np->xmlin = op->xmlin;
122
123 np->writeformat = op->writeformat;
124 np->charsetout = op->charsetout;
125 np->charsetout_src = op->charsetout_src;
126 np->utf8out = op->utf8out;
127 np->utf8bom = op->utf8bom;
128 np->latexout = op->latexout;
129 np->xmlout = op->xmlout;
130 np->nosplittitle = op->nosplittitle;
131
132 np->verbose = op->verbose;
133 np->format_opts = op->format_opts;
134 np->addcount = op->addcount;
135 np->output_raw = op->output_raw;
136 np->singlerefperfile = op->singlerefperfile;
137
138 np->readf = op->readf;
139 np->processf = op->processf;
140 np->cleanf = op->cleanf;
141 np->typef = op->typef;
142 np->convertf = op->convertf;
143 np->headerf = op->headerf;
144 np->footerf = op->footerf;
145 np->assemblef = op->assemblef;
146 np->writef = op->writef;
147
148 np->all = op->all;
149 np->nall = op->nall;
150
151 return BIBL_OK;
152 }
153
154 /* bibl_setreadparams()
155 *
156 * Returns status of BIBL_OK or BIBL_ERR_MEMERR
157 */
158 static int
bibl_setreadparams(param * np,param * op)159 bibl_setreadparams( param *np, param *op )
160 {
161 int status;
162 status = bibl_duplicateparams( np, op );
163 if ( status == BIBL_OK ) {
164 np->utf8out = 1;
165 np->charsetout = BIBL_CHARSET_UNICODE;
166 np->charsetout_src = BIBL_SRC_DEFAULT;
167 np->xmlout = BIBL_XMLOUT_FALSE;
168 np->latexout = 0;
169 np->writeformat = BIBL_INTERNALOUT;
170 }
171 return status;
172 }
173
174 /* bibl_setwriteparams()
175 *
176 * Returns status of BIBL_OK or BIBL_ERR_MEMERR
177 */
178 static int
bibl_setwriteparams(param * np,param * op)179 bibl_setwriteparams( param *np, param *op )
180 {
181 int status;
182 status = bibl_duplicateparams( np, op );
183 if ( status == BIBL_OK ) {
184 np->xmlin = 0;
185 np->latexin = 0;
186 np->utf8in = 1;
187 np->charsetin = BIBL_CHARSET_UNICODE;
188 np->charsetin_src = BIBL_SRC_DEFAULT;
189 np->readformat = BIBL_INTERNALIN;
190 }
191 return status;
192 }
193
194 void
bibl_freeparams(param * p)195 bibl_freeparams( param *p )
196 {
197 if ( p ) {
198 slist_free( &(p->asis) );
199 slist_free( &(p->corps) );
200 if ( p->progname ) free( p->progname );
201 }
202 }
203
204 int
bibl_readasis(param * p,char * f)205 bibl_readasis( param *p, char *f )
206 {
207 int status;
208
209 if ( !p ) return BIBL_ERR_BADINPUT;
210 if ( !f ) return BIBL_ERR_BADINPUT;
211
212 status = slist_fill( &(p->asis), f, 1 );
213
214 if ( status == SLIST_ERR_CANTOPEN ) return BIBL_ERR_CANTOPEN;
215 else if ( status == SLIST_ERR_MEMERR ) return BIBL_ERR_MEMERR;
216 return BIBL_OK;
217 }
218
219 int
bibl_readcorps(param * p,char * f)220 bibl_readcorps( param *p, char *f )
221 {
222 int status;
223
224 if ( !p ) return BIBL_ERR_BADINPUT;
225 if ( !f ) return BIBL_ERR_BADINPUT;
226
227 status = slist_fill( &(p->corps), f, 1 );
228
229 if ( status == SLIST_ERR_CANTOPEN ) return BIBL_ERR_CANTOPEN;
230 else if ( status == 0 ) return BIBL_ERR_MEMERR;
231 return BIBL_OK;
232 }
233
234 /* bibl_addtoasis()
235 *
236 * Returns BIBL_OK or BIBL_ERR_MEMERR
237 */
238 int
bibl_addtoasis(param * p,char * d)239 bibl_addtoasis( param *p, char *d )
240 {
241 int status;
242
243 if ( !p ) return BIBL_ERR_BADINPUT;
244 if ( !d ) return BIBL_ERR_BADINPUT;
245
246 status = slist_addc( &(p->asis), d );
247
248 return ( status==SLIST_OK )? BIBL_OK : BIBL_ERR_MEMERR;
249 }
250
251 /* bibl_addtocorps()
252 *
253 * Returns BIBL_OK or BIBL_ERR_MEMERR
254 */
255 int
bibl_addtocorps(param * p,char * d)256 bibl_addtocorps( param *p, char *d )
257 {
258 int status;
259
260 if ( !p ) return BIBL_ERR_BADINPUT;
261 if ( !d ) return BIBL_ERR_BADINPUT;
262
263 status = slist_addc( &(p->corps), d );
264
265 return ( status==SLIST_OK )? BIBL_OK : BIBL_ERR_MEMERR;
266 }
267
268 void
bibl_reporterr(int err)269 bibl_reporterr( int err )
270 {
271 // Patch: Disable output logging
272 }
273
274 static int
bibl_illegalinmode(int mode)275 bibl_illegalinmode( int mode )
276 {
277 if ( mode < BIBL_FIRSTIN || mode > BIBL_LASTIN ) return 1;
278 else return 0;
279 }
280
281 static int
bibl_illegaloutmode(int mode)282 bibl_illegaloutmode( int mode )
283 {
284 if ( mode < BIBL_FIRSTOUT || mode > BIBL_LASTOUT ) return 1;
285 else return 0;
286 }
287
288 static void
bibl_verbose_reference(fields * f,char * filename,long refnum)289 bibl_verbose_reference( fields *f, char *filename, long refnum )
290 {
291 // Patch: Disable output logging
292 }
293
294 static void
bibl_verbose(bibl * bin,const char * msg1,const char * msg2)295 bibl_verbose( bibl *bin, const char *msg1, const char *msg2 )
296 {
297 // Patch: Disable output logging
298 }
299
300
301 /* extract_tag_value
302 *
303 * Extract the tag and the value for ALWAYS/DEFAULT
304 * entries like: "GENRE:BIBUTILS|Masters thesis"
305 *
306 * tag = "GENRE:BIBUTILS"
307 * value = "Masters thesis"
308 */
309 static int
extract_tag_value(str * tag,str * value,char * p)310 extract_tag_value( str *tag, str *value, char *p )
311 {
312 str_empty( tag );
313 while ( p && *p && *p!='|' ) {
314 str_addchar( tag, *p );
315 p++;
316 }
317 if ( str_memerr( tag ) ) return BIBL_ERR_MEMERR;
318
319 if ( p && *p=='|' ) p++;
320
321 str_empty( value );
322 while ( p && *p ) {
323 str_addchar( value, *p );
324 p++;
325 }
326 if ( str_memerr( tag ) ) return BIBL_ERR_MEMERR;
327
328 return BIBL_OK;
329 }
330
331 /* process_defaultadd()
332 *
333 * Add tag/value pairs that have "DEFAULT" processing
334 * unless a tag/value pair with the same tag has already
335 * been adding during reference processing.
336 */
337 static int
process_defaultadd(fields * f,int reftype,param * r)338 process_defaultadd( fields *f, int reftype, param *r )
339 {
340 int i, n, process, level, status, ret = BIBL_OK;
341 str tag, value;
342 char *p;
343
344 strs_init( &tag, &value, NULL );
345
346 for ( i=0; i<r->all[reftype].ntags; ++i ) {
347
348 process = ((r->all[reftype]).tags[i]).processingtype;
349 if ( process!=DEFAULT ) continue;
350
351 level = ((r->all[reftype]).tags[i]).level;
352 p = ((r->all[reftype]).tags[i]).newstr;
353
354 status = extract_tag_value( &tag, &value, p );
355 if ( status!=BIBL_OK ) {
356 ret = status;
357 goto out;
358 }
359
360 n = fields_find( f, tag.data, level );
361 if ( n==FIELDS_NOTFOUND ) {
362 status = fields_add( f, tag.data, value.data, level );
363 if ( status!=FIELDS_OK ) {
364 ret = BIBL_ERR_MEMERR;
365 goto out;
366 }
367 }
368
369 }
370 out:
371 strs_free( &tag, &value, NULL );
372
373 return ret;
374 }
375
376 /* process_alwaysadd()
377 *
378 * Add tag/value pair to reference from the ALWAYS
379 * processing type without exception (the difference from
380 * DEFAULT processing).
381 */
382 static int
process_alwaysadd(fields * f,int reftype,param * r)383 process_alwaysadd( fields *f, int reftype, param *r )
384 {
385 int i, process, level, status, ret = BIBL_OK;
386 str tag, value;
387 char *p;
388
389 strs_init( &tag, &value, NULL );
390
391 for ( i=0; i<r->all[reftype].ntags; ++i ) {
392
393 process = ((r->all[reftype]).tags[i]).processingtype;
394 if ( process!=ALWAYS ) continue;
395
396 level = ((r->all[reftype]).tags[i]).level;
397 p = ((r->all[reftype]).tags[i]).newstr;
398
399 status = extract_tag_value( &tag, &value, p );
400 if ( status!=BIBL_OK ) {
401 ret = status;
402 goto out;
403 }
404
405 status = fields_add( f, tag.data, value.data, level );
406 if ( status!=FIELDS_OK ) {
407 ret = BIBL_ERR_MEMERR;
408 goto out;
409 }
410 }
411
412 out:
413 strs_free( &tag, &value, NULL );
414
415 return ret;
416 }
417
418 static int
read_refs(FILE * fp,bibl * bin,char * filename,param * p)419 read_refs( FILE *fp, bibl *bin, char *filename, param *p )
420 {
421 int refnum = 0, bufpos = 0, ret=BIBL_OK, fcharset;/* = CHARSET_UNKNOWN;*/
422 str reference, line;
423 char buf[256]="";
424 fields *ref;
425
426 str_init( &reference );
427 str_init( &line );
428 while ( p->readf( fp, buf, sizeof(buf), &bufpos, &line, &reference, &fcharset ) ) {
429 if ( reference.len==0 ) continue;
430 ref = fields_new();
431 if ( !ref ) {
432 ret = BIBL_ERR_MEMERR;
433 bibl_free( bin );
434 goto out;
435 }
436 if ( p->processf( ref, reference.data, filename, refnum+1, p )){
437 ret = bibl_addref( bin, ref );
438 if ( ret!=BIBL_OK ) {
439 bibl_free( bin );
440 fields_delete( ref );
441 goto out;
442 }
443 refnum += 1;
444 } else {
445 fields_delete( ref );
446 }
447 str_empty( &reference );
448 if ( fcharset!=CHARSET_UNKNOWN ) {
449 /* charset from file takes priority over default, but
450 * not user-specified */
451 if ( p->charsetin_src!=BIBL_SRC_USER ) {
452 p->charsetin_src = BIBL_SRC_FILE;
453 p->charsetin = fcharset;
454 if ( fcharset!=CHARSET_UNICODE ) p->utf8in = 0;
455 }
456 }
457 }
458 if ( p->charsetin==CHARSET_UNICODE ) p->utf8in = 1;
459 out:
460 str_free( &line );
461 str_free( &reference );
462 return ret;
463 }
464
465 /* Don't manipulate latex for URL's and the like */
466 static int
bibl_notexify(char * tag)467 bibl_notexify( char *tag )
468 {
469 char *protected[] = { "DOI", "URL", "REFNUM", "FILEATTACH", "FILE" };
470 int i, nprotected = sizeof( protected ) / sizeof( protected[0] );
471 for ( i=0; i<nprotected; ++i )
472 if ( !strcasecmp( tag, protected[i] ) ) return 1;
473 return 0;
474 }
475
476 /* bibl_fixcharsetdata()
477 *
478 * returns BIBL_OK or BIBL_ERR_MEMERR
479 */
480 static int
bibl_fixcharsetdata(fields * ref,param * p)481 bibl_fixcharsetdata( fields *ref, param *p )
482 {
483 str *data;
484 char *tag;
485 long i, n;
486 int ok;
487
488 n = fields_num( ref );
489
490 for ( i=0; i<n; ++i ) {
491
492 tag = fields_tag( ref, i, FIELDS_CHRP_NOUSE );
493 data = fields_value( ref, i, FIELDS_STRP_NOUSE );
494
495 if ( bibl_notexify( tag ) ) {
496 ok = str_convert( data,
497 p->charsetin, 0, p->utf8in, p->xmlin,
498 p->charsetout, 0, p->utf8out, p->xmlout );
499 } else {
500 ok = str_convert( data,
501 p->charsetin, p->latexin, p->utf8in, p->xmlin,
502 p->charsetout, p->latexout, p->utf8out, p->xmlout );
503 }
504
505 if ( !ok ) return BIBL_ERR_MEMERR;
506 }
507
508 return BIBL_OK;
509 }
510
511 /* bibl_fixcharsets()
512 *
513 * returns BIBL_OK or BIBL_ERR_MEMERR
514 */
515 static int
bibl_fixcharsets(bibl * b,param * p)516 bibl_fixcharsets( bibl *b, param *p )
517 {
518 int status;
519 long i;
520
521 for ( i=0; i<b->n; ++i ) {
522 status = bibl_fixcharsetdata( b->ref[i], p );
523 if ( status!=BIBL_OK ) return status;
524 }
525
526 return BIBL_OK;
527 }
528
529 static int
bibl_addcount(bibl * b)530 bibl_addcount( bibl *b )
531 {
532 char buf[512];
533 fields *ref;
534 long i;
535 int n;
536
537 for ( i=0; i<b->n; ++i ) {
538
539 ref = b->ref[i];
540
541 n = fields_find( ref, "REFNUM", LEVEL_MAIN );
542 if ( n==FIELDS_NOTFOUND ) continue;
543
544 sprintf( buf, "_%ld", i+1 );
545 str_strcatc( fields_value( ref, n, FIELDS_STRP_NOUSE ), buf );
546 if ( str_memerr( fields_value( ref, n, FIELDS_STRP_NOUSE ) ) ) {
547 return BIBL_ERR_MEMERR;
548 }
549
550 }
551
552 return BIBL_OK;
553 }
554
555 static int
generate_citekey(fields * f,long nref)556 generate_citekey( fields *f, long nref )
557 {
558 int n1, n2, status, ret;
559 char *p, buf[100];
560 str citekey;
561
562 str_init( &citekey );
563
564 n1 = fields_find( f, "AUTHOR", LEVEL_MAIN );
565 if ( n1==FIELDS_NOTFOUND ) n1 = fields_find( f, "AUTHOR:ASIS", LEVEL_MAIN );
566 if ( n1==FIELDS_NOTFOUND ) n1 = fields_find( f, "AUTHOR:CORP", LEVEL_MAIN );
567 if ( n1==FIELDS_NOTFOUND ) n1 = fields_find( f, "AUTHOR", LEVEL_ANY );
568 if ( n1==FIELDS_NOTFOUND ) n1 = fields_find( f, "AUTHOR:ASIS", LEVEL_ANY );
569 if ( n1==FIELDS_NOTFOUND ) n1 = fields_find( f, "AUTHOR:CORP", LEVEL_ANY );
570
571 n2 = fields_find( f, "DATE:YEAR", LEVEL_MAIN );
572 if ( n2==FIELDS_NOTFOUND ) n2 = fields_find( f, "DATE:YEAR", LEVEL_ANY );
573 if ( n2==FIELDS_NOTFOUND ) n2 = fields_find( f, "PARTDATE:YEAR", LEVEL_MAIN );
574 if ( n2==FIELDS_NOTFOUND ) n2 = fields_find( f, "PARTDATE:YEAR", LEVEL_ANY );
575
576 if ( n1!=FIELDS_NOTFOUND && n2!=FIELDS_NOTFOUND ) {
577
578 p = fields_value( f, n1, FIELDS_CHRP_NOUSE );
579 while ( p && *p && *p!='|' ) {
580 if ( !is_ws( *p ) ) str_addchar( &citekey, *p );
581 p++;
582 }
583
584 p = fields_value( f, n2, FIELDS_CHRP_NOUSE );
585 while ( p && *p ) {
586 if ( !is_ws( *p ) ) str_addchar( &citekey, *p );
587 p++;
588 }
589
590 }
591
592 else {
593 sprintf( buf, "ref%ld", nref );
594 str_strcpyc( &citekey, buf );
595 }
596
597 if ( str_memerr( &citekey ) ) {
598 ret = -1;
599 goto out;
600 }
601
602 status = fields_add( f, "REFNUM", str_cstr( &citekey ), LEVEL_MAIN );
603 if ( status!=FIELDS_OK ) {
604 ret = -1;
605 goto out;
606 }
607
608 ret = fields_find( f, "REFNUM", LEVEL_MAIN );
609 out:
610 str_free( &citekey );
611 return ret;
612 }
613
614 static int
get_citekeys(bibl * bin,slist * citekeys)615 get_citekeys( bibl *bin, slist *citekeys )
616 {
617 int n, status;
618 fields *f;
619 long i;
620
621 for ( i=0; i<bin->n; ++i ) {
622 f = bin->ref[i];
623 n = fields_find( f, "REFNUM", LEVEL_ANY );
624 if ( n==FIELDS_NOTFOUND ) n = generate_citekey( f, i+1 );
625 if ( n!=FIELDS_NOTFOUND && fields_has_value( f, n ) ) {
626 status = slist_add( citekeys, fields_value( f, n, FIELDS_STRP_NOUSE ) );
627 if ( status!=SLIST_OK ) return BIBL_ERR_MEMERR;
628 } else {
629 status = slist_addc( citekeys, "" );
630 if ( status!=SLIST_OK ) return BIBL_ERR_MEMERR;
631 }
632 }
633
634 return BIBL_OK;
635 }
636
637 static int
identify_duplicates(bibl * b,slist * citekeys,int * dup)638 identify_duplicates( bibl *b, slist *citekeys, int *dup )
639 {
640 int i, j, ndup = 0;
641
642 for ( i=0; i<citekeys->n-1; ++i ) {
643 if ( dup[i]!=-1 ) continue;
644 for ( j=i+1; j<citekeys->n; ++j ) {
645 if ( !strcmp( slist_cstr( citekeys, i ),
646 slist_cstr( citekeys, j ) ) ) {
647 dup[i] = i;
648 dup[j] = i;
649 ndup++;
650 }
651 }
652 }
653
654 return ndup;
655 }
656
657 static int
build_new_citekey(int nsame,str * old_citekey,str * new_citekey)658 build_new_citekey( int nsame, str *old_citekey, str *new_citekey )
659 {
660 const char abc[]="abcdefghijklmnopqrstuvwxyz";
661
662 str_strcpy( new_citekey, old_citekey );
663
664 while ( nsame >= 26 ) {
665 str_addchar( new_citekey, 'a' );
666 nsame -= 26;
667 }
668
669 if ( nsame>=0 ) str_addchar( new_citekey, abc[nsame] );
670
671 return ( str_memerr( new_citekey ) ) ? BIBL_ERR_MEMERR : BIBL_OK;
672 }
673
674 static int
resolve_duplicates(bibl * b,slist * citekeys,int * dup)675 resolve_duplicates( bibl *b, slist *citekeys, int *dup )
676 {
677 int nsame, n, i, j, status = BIBL_OK;
678 str new_citekey, *ref_citekey;
679
680 str_init( &new_citekey );
681
682 for ( i=0; i<citekeys->n; ++i ) {
683
684 if ( dup[i]==-1 ) continue;
685
686 nsame = 0;
687
688 for ( j=i; j<citekeys->n; ++j ) {
689
690 if ( dup[j]!=i ) continue;
691
692 dup[j] = -1;
693
694 status = build_new_citekey( nsame, slist_str( citekeys, j ), &new_citekey );
695 if ( status!=BIBL_OK ) goto out;
696
697 n = fields_find( b->ref[j], "REFNUM", LEVEL_ANY );
698 if ( n==FIELDS_NOTFOUND ) continue;
699
700 ref_citekey = fields_value( b->ref[j], n, FIELDS_STRP_NOUSE );
701
702 str_strcpy( ref_citekey, &new_citekey );
703 if ( str_memerr( ref_citekey ) ) { status = BIBL_ERR_MEMERR; goto out; }
704
705 nsame++;
706 }
707 }
708 out:
709 str_free( &new_citekey );
710 return status;
711 }
712
713 static int
identify_and_resolve_duplicate_citekeys(bibl * b,slist * citekeys)714 identify_and_resolve_duplicate_citekeys( bibl *b, slist *citekeys )
715 {
716 int i, *dup, ndup, status=BIBL_OK;
717
718 dup = ( int * ) malloc( sizeof( int ) * citekeys->n );
719 if ( !dup ) return BIBL_ERR_MEMERR;
720 for ( i=0; i<citekeys->n; ++i ) dup[i] = -1;
721
722 ndup = identify_duplicates( b, citekeys, dup );
723
724 if ( ndup ) status = resolve_duplicates( b, citekeys, dup );
725
726 free( dup );
727 return status;
728 }
729
730 static int
uniqueify_citekeys(bibl * bin)731 uniqueify_citekeys( bibl *bin )
732 {
733 slist citekeys;
734 int status;
735
736 slist_init( &citekeys );
737
738 status = get_citekeys( bin, &citekeys );
739 if ( status!=BIBL_OK ) goto out;
740
741 status = identify_and_resolve_duplicate_citekeys( bin, &citekeys );
742 out:
743 slist_free( &citekeys );
744 return status;
745 }
746
747 static int
clean_refs(bibl * bin,param * p)748 clean_refs( bibl *bin, param *p )
749 {
750 if ( p->cleanf ) return p->cleanf( bin, p );
751 else return BIBL_OK;
752 }
753
754 static int
convert_refs(bibl * bin,char * fname,bibl * bout,param * p)755 convert_refs( bibl *bin, char *fname, bibl *bout, param *p )
756 {
757 int reftype = 0, status;
758 fields *rin, *rout;
759 long i;
760
761 for ( i=0; i<bin->n; ++i ) {
762
763 rin = bin->ref[i];
764
765 rout = fields_new();
766 if ( !rout ) return BIBL_ERR_MEMERR;
767
768 if ( p->typef ) reftype = p->typef( rin, fname, i+1, p );
769
770 status = p->convertf( rin, rout, reftype, p );
771 if ( status!=BIBL_OK ) return status;
772
773 if ( p->all ) {
774 status = process_alwaysadd( rout, reftype, p );
775 if ( status!=BIBL_OK ) return status;
776 status = process_defaultadd( rout, reftype, p );
777 if ( status!=BIBL_OK ) return status;
778 }
779
780 status = bibl_addref( bout, rout );
781 if ( status!=BIBL_OK ) return status;
782 }
783
784 return BIBL_OK;
785 }
786
787 int
bibl_read(bibl * b,FILE * fp,char * filename,param * p)788 bibl_read( bibl *b, FILE *fp, char *filename, param *p )
789 {
790 // Patch: Disable output logging
791 int status = BIBL_OK;
792 param read_params;
793 bibl bin;
794
795 if ( !b ) return BIBL_ERR_BADINPUT;
796 if ( !fp ) return BIBL_ERR_BADINPUT;
797 if ( !p ) return BIBL_ERR_BADINPUT;
798
799 if ( bibl_illegalinmode( p->readformat ) ) {
800 return BIBL_ERR_BADINPUT;
801 }
802
803 status = bibl_setreadparams( &read_params, p );
804 if ( status!=BIBL_OK ) {
805 return status;
806 }
807
808 bibl_init( &bin );
809
810 status = read_refs( fp, &bin, filename, &read_params );
811 if ( status!=BIBL_OK ) {
812 bibl_freeparams( &read_params );
813 return status;
814 }
815
816 if ( debug_set( &read_params ) ) {
817 bibl_verbose( &bin, "raw_input", "for bibl_read" );
818 }
819
820 if ( !read_params.output_raw ) {
821 status = clean_refs( &bin, &read_params );
822 if ( status!=BIBL_OK ) goto out;
823 if ( debug_set( &read_params ) ) bibl_verbose( &bin, "post_clean_refs", "for bibl_read" );
824 }
825
826 if ( ( !read_params.output_raw ) || ( read_params.output_raw & BIBL_RAW_WITHCHARCONVERT ) ) {
827 status = bibl_fixcharsets( &bin, &read_params );
828 if ( status!=BIBL_OK ) goto out;
829 if ( debug_set( &read_params ) ) bibl_verbose( &bin, "post_fixcharsets", "for bibl_read" );
830 }
831
832 if ( !read_params.output_raw ) {
833 status = convert_refs( &bin, filename, b, &read_params );
834 if ( status!=BIBL_OK ) goto out;
835 if ( debug_set( &read_params ) ) bibl_verbose( b, "post_convert_refs", "for bibl_read" );
836 }
837
838 else {
839 status = bibl_copy( b, &bin );
840 if ( status!=BIBL_OK ) goto out;
841 if ( debug_set( &read_params ) ) bibl_verbose( b, "post_bibl_copy", "for bibl_read" );
842 }
843
844 if ( ( !read_params.output_raw ) || ( read_params.output_raw & BIBL_RAW_WITHMAKEREFID ) ) {
845 status = uniqueify_citekeys( b );
846 if ( status!=BIBL_OK ) goto out;
847 if ( read_params.addcount ) {
848 status = bibl_addcount( b );
849 if ( status!=BIBL_OK ) goto out;
850 }
851 if ( debug_set( &read_params ) ) bibl_verbose( &bin, "post_uniqueify_citekeys", "for bibl_read" );
852 }
853
854 out:
855 bibl_free( &bin );
856 bibl_freeparams( &read_params );
857
858 return status;
859 }
860
861 static FILE *
singlerefname(fields * reffields,long nref,int mode)862 singlerefname( fields *reffields, long nref, int mode )
863 {
864 char outfile[2048];
865 char suffix[5] = "xml";
866 FILE *fp;
867 long count;
868 int found;
869 if ( mode==BIBL_ADSABSOUT ) strcpy( suffix, "ads" );
870 else if ( mode==BIBL_BIBTEXOUT ) strcpy( suffix, "bib" );
871 else if ( mode==BIBL_ENDNOTEOUT ) strcpy( suffix, "end" );
872 else if ( mode==BIBL_ISIOUT ) strcpy( suffix, "isi" );
873 else if ( mode==BIBL_MODSOUT ) strcpy( suffix, "xml" );
874 else if ( mode==BIBL_RISOUT ) strcpy( suffix, "ris" );
875 else if ( mode==BIBL_WORD2007OUT ) strcpy( suffix, "xml" );
876 found = fields_find( reffields, "REFNUM", LEVEL_MAIN );
877 /* find new filename based on reference */
878 if ( found!=-1 ) {
879 sprintf( outfile,"%s.%s",(char*)fields_value(reffields,found,FIELDS_CHRP_NOUSE), suffix );
880 } else sprintf( outfile,"%ld.%s",nref, suffix );
881 count = 0;
882 fp = fopen( outfile, "r" );
883 while ( fp ) {
884 fclose(fp);
885 count++;
886 if ( count==60000 ) return NULL;
887 if ( found!=-1 )
888 sprintf( outfile, "%s_%ld.%s", (char*)fields_value( reffields, found, FIELDS_CHRP_NOUSE ), count, suffix );
889 else sprintf( outfile,"%ld_%ld.%s", nref, count, suffix );
890 fp = fopen( outfile, "r" );
891 }
892 return fopen( outfile, "w" );
893 }
894
895 static int
bibl_writeeachfp(FILE * fp,bibl * b,param * p)896 bibl_writeeachfp( FILE *fp, bibl *b, param *p )
897 {
898 fields out, *use = &out;
899 int status;
900 long i;
901
902 fields_init( &out );
903
904 for ( i=0; i<b->n; ++i ) {
905
906 fp = singlerefname( b->ref[i], i, p->writeformat );
907 if ( !fp ) return BIBL_ERR_CANTOPEN;
908
909 if ( p->headerf ) p->headerf( fp, p );
910
911 if ( p->assemblef ) {
912 fields_free( &out );
913 status = p->assemblef( b->ref[i], &out, p, i );
914 if ( status!=BIBL_OK ) break;
915 } else {
916 use = b->ref[i];
917 }
918
919 status = p->writef( use, fp, p, i );
920
921 if ( p->footerf ) p->footerf( fp );
922 fclose( fp );
923
924 if ( status!=BIBL_OK ) return status;
925 }
926
927 return BIBL_OK;
928 }
929
930 static int
bibl_writefp(FILE * fp,bibl * b,param * p)931 bibl_writefp( FILE *fp, bibl *b, param *p )
932 {
933 // Patch: Disable output logging
934 int status = BIBL_OK;
935 fields out, *use = &out;
936 long i;
937
938 fields_init( &out );
939
940 if ( p->headerf ) p->headerf( fp, p );
941 for ( i=0; i<b->n; ++i ) {
942
943 if ( p->assemblef ) {
944 fields_free( &out );
945 status = p->assemblef( b->ref[i], &out, p, i );
946 if ( status!=BIBL_OK ) break;
947 if ( debug_set( p ) ) bibl_verbose_reference( &out, "", i+1 );
948 } else {
949 use = b->ref[i];
950 }
951
952 status = p->writef( use, fp, p, i );
953 if ( status!=BIBL_OK ) break;
954
955 }
956
957 if ( p->footerf ) p->footerf( fp );
958 return status;
959 }
960
961 int
bibl_write(bibl * b,FILE * fp,param * p)962 bibl_write( bibl *b, FILE *fp, param *p )
963 {
964 // Patch: Disable output logging
965 int status;
966 param lp;
967
968 if ( !b ) return BIBL_ERR_BADINPUT;
969 if ( !p ) return BIBL_ERR_BADINPUT;
970 if ( bibl_illegaloutmode( p->writeformat ) ) return BIBL_ERR_BADINPUT;
971 if ( !fp && !p->singlerefperfile ) return BIBL_ERR_BADINPUT;
972
973 status = bibl_setwriteparams( &lp, p );
974 if ( status!=BIBL_OK ) return status;
975
976 if ( debug_set( p ) ) bibl_verbose( b, "raw_input", "for bibl_write" );
977
978 status = bibl_fixcharsets( b, &lp );
979 if ( status!=BIBL_OK ) goto out;
980
981 if ( debug_set( p ) ) bibl_verbose( b, "post-fixcharsets", "for bibl_write" );
982
983 if ( p->singlerefperfile ) status = bibl_writeeachfp( fp, b, &lp );
984 else status = bibl_writefp( fp, b, &lp );
985
986 out:
987 bibl_freeparams( &lp );
988 return status;
989 }
990