1 /*
2 * biblatexout.c
3 *
4 * Copyright (c) Chris Putnam 2003-2020
5 *
6 * Program and source code released under the GPL version 2
7 *
8 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include "str.h"
14 #include "strsearch.h"
15 #include "utf8.h"
16 #include "xml.h"
17 #include "fields.h"
18 #include "generic.h"
19 #include "name.h"
20 #include "title.h"
21 #include "type.h"
22 #include "url.h"
23 #include "bibformats.h"
24
25 /*****************************************************
26 PUBLIC: int biblatexout_initparams()
27 *****************************************************/
28
29 static int biblatexout_write( fields *in, FILE *fp, param *p, unsigned long refnum );
30 static int biblatexout_assemble( fields *in, fields *out, param *pm, unsigned long refnum );
31
32 int
biblatexout_initparams(param * pm,const char * progname)33 biblatexout_initparams( param *pm, const char *progname )
34 {
35 pm->writeformat = BIBL_BIBLATEXOUT;
36 pm->format_opts = 0;
37 pm->charsetout = BIBL_CHARSET_DEFAULT;
38 pm->charsetout_src = BIBL_SRC_DEFAULT;
39 pm->latexout = 1;
40 pm->utf8out = BIBL_CHARSET_UTF8_DEFAULT;
41 pm->utf8bom = BIBL_CHARSET_BOM_DEFAULT;
42 pm->xmlout = BIBL_XMLOUT_FALSE;
43 pm->nosplittitle = 0;
44 pm->verbose = 0;
45 pm->addcount = 0;
46 pm->singlerefperfile = 0;
47
48 pm->headerf = generic_writeheader;
49 pm->footerf = NULL;
50 pm->assemblef = biblatexout_assemble;
51 pm->writef = biblatexout_write;
52
53 if ( !pm->progname ) {
54 if ( !progname ) pm->progname = NULL;
55 else {
56 pm->progname = strdup( progname );
57 if ( !pm->progname ) return BIBL_ERR_MEMERR;
58 }
59 }
60
61 return BIBL_OK;
62 }
63
64 /*****************************************************
65 PUBLIC: int biblatexout_assemble()
66 *****************************************************/
67
68 enum {
69 TYPE_UNKNOWN = 0,
70 TYPE_ARTICLE,
71 TYPE_SUPPPERIODICAL,
72 TYPE_INBOOK,
73 TYPE_INPROCEEDINGS,
74 TYPE_PROCEEDINGS,
75 TYPE_CONFERENCE, /* legacy */
76 TYPE_INCOLLECTION,
77 TYPE_COLLECTION,
78 TYPE_SUPPCOLLECTION,
79 TYPE_REFERENCE,
80 TYPE_MVREFERENCE,
81 TYPE_BOOK,
82 TYPE_BOOKLET,
83 TYPE_SUPPBOOK,
84 TYPE_PHDTHESIS, /* legacy */
85 TYPE_MASTERSTHESIS, /* legacy */
86 TYPE_DIPLOMATHESIS,
87 TYPE_REPORT,
88 TYPE_TECHREPORT,
89 TYPE_MANUAL,
90 TYPE_UNPUBLISHED,
91 TYPE_PATENT,
92 TYPE_ELECTRONIC, /* legacy */
93 TYPE_ONLINE,
94 TYPE_WWW, /* jurabib compatibility */
95 TYPE_MISC,
96 NUM_TYPES
97 };
98
99 static int
biblatexout_type(fields * in,const char * progname,const char * filename,unsigned long refnum)100 biblatexout_type( fields *in, const char *progname, const char *filename, unsigned long refnum )
101 {
102 match_type genre_matches[] = {
103 { "periodical", TYPE_ARTICLE, LEVEL_ANY },
104 { "academic journal", TYPE_ARTICLE, LEVEL_ANY },
105 { "magazine", TYPE_ARTICLE, LEVEL_ANY },
106 { "newspaper", TYPE_ARTICLE, LEVEL_ANY },
107 { "article", TYPE_ARTICLE, LEVEL_ANY },
108 { "instruction", TYPE_MANUAL, LEVEL_ANY },
109 { "book", TYPE_BOOK, LEVEL_MAIN },
110 { "booklet", TYPE_BOOKLET, LEVEL_MAIN },
111 { "book", TYPE_INBOOK, LEVEL_ANY },
112 { "book chapter", TYPE_INBOOK, LEVEL_ANY },
113 { "unpublished", TYPE_UNPUBLISHED, LEVEL_ANY },
114 { "manuscript", TYPE_UNPUBLISHED, LEVEL_ANY },
115 { "conference publication", TYPE_PROCEEDINGS, LEVEL_MAIN },
116 { "conference publication", TYPE_INPROCEEDINGS, LEVEL_ANY },
117 { "collection", TYPE_COLLECTION, LEVEL_MAIN },
118 { "collection", TYPE_INCOLLECTION, LEVEL_ANY },
119 { "report", TYPE_REPORT, LEVEL_ANY },
120 { "technical report", TYPE_TECHREPORT, LEVEL_ANY },
121 { "Masters thesis", TYPE_MASTERSTHESIS, LEVEL_ANY },
122 { "Diploma thesis", TYPE_DIPLOMATHESIS, LEVEL_ANY },
123 { "Ph.D. thesis", TYPE_PHDTHESIS, LEVEL_ANY },
124 { "Licentiate thesis", TYPE_PHDTHESIS, LEVEL_ANY },
125 { "thesis", TYPE_PHDTHESIS, LEVEL_ANY },
126 { "electronic", TYPE_ELECTRONIC, LEVEL_ANY },
127 { "patent", TYPE_PATENT, LEVEL_ANY },
128 { "miscellaneous", TYPE_MISC, LEVEL_ANY },
129 };
130 int ngenre_matches = sizeof( genre_matches ) / sizeof( genre_matches[0] );
131
132 match_type resource_matches[] = {
133 { "moving image", TYPE_ELECTRONIC, LEVEL_ANY },
134 { "software, multimedia", TYPE_ELECTRONIC, LEVEL_ANY },
135 };
136 int nresource_matches = sizeof( resource_matches ) /sizeof( resource_matches[0] );
137
138 match_type issuance_matches[] = {
139 { "monographic", TYPE_BOOK, LEVEL_MAIN },
140 { "monographic", TYPE_INBOOK, LEVEL_ANY },
141 };
142 int nissuance_matches = sizeof( issuance_matches ) / sizeof( issuance_matches[0] );
143
144 int type, maxlevel, n;
145
146 type = type_from_mods_hints( in, TYPE_FROM_GENRE, genre_matches, ngenre_matches, TYPE_UNKNOWN );
147 if ( type==TYPE_UNKNOWN ) type = type_from_mods_hints( in, TYPE_FROM_RESOURCE, resource_matches, nresource_matches, TYPE_UNKNOWN );
148 if ( type==TYPE_UNKNOWN ) type = type_from_mods_hints( in, TYPE_FROM_ISSUANCE, issuance_matches, nissuance_matches, TYPE_UNKNOWN );
149
150 /* default to TYPE_MISC */
151 if ( type==TYPE_UNKNOWN ) {
152 maxlevel = fields_maxlevel( in );
153 if ( maxlevel > 0 ) type = TYPE_MISC;
154 else {
155 if ( progname ) REprintf( "%s: ", progname );
156 REprintf( "Cannot identify TYPE in reference %lu ", refnum+1 );
157 n = fields_find( in, "REFNUM", LEVEL_ANY );
158 if ( n!=FIELDS_NOTFOUND )
159 REprintf( " %s", (char*) fields_value( in, n, FIELDS_CHRP ) );
160 REprintf( " (defaulting to @Misc)\n" );
161 type = TYPE_MISC;
162 }
163 }
164 return type;
165 }
166
167 static void
append_type(int type,fields * out,int * status)168 append_type( int type, fields *out, int *status )
169 {
170 char *typenames[ NUM_TYPES ] = {
171 [ TYPE_ARTICLE ] = "Article",
172 [ TYPE_SUPPPERIODICAL ] = "SuppPeriodical",
173 [ TYPE_INBOOK ] = "Inbook",
174 [ TYPE_PROCEEDINGS ] = "Proceedings",
175 [ TYPE_INPROCEEDINGS ] = "InProceedings",
176 [ TYPE_CONFERENCE ] = "Conference",
177 [ TYPE_BOOK ] = "Book",
178 [ TYPE_BOOKLET ] = "Booklet",
179 [ TYPE_SUPPBOOK ] = "SuppBook",
180 [ TYPE_PHDTHESIS ] = "PhdThesis",
181 [ TYPE_MASTERSTHESIS ] = "MastersThesis",
182 [ TYPE_DIPLOMATHESIS ] = "MastersThesis",
183 [ TYPE_REPORT ] = "Report",
184 [ TYPE_TECHREPORT ] = "TechReport",
185 [ TYPE_REFERENCE ] = "Reference",
186 [ TYPE_MVREFERENCE ] = "MvReference",
187 [ TYPE_MANUAL ] = "Manual",
188 [ TYPE_COLLECTION ] = "Collection",
189 [ TYPE_SUPPCOLLECTION ] = "SuppCollection",
190 [ TYPE_INCOLLECTION ] = "InCollection",
191 [ TYPE_UNPUBLISHED ] = "Unpublished",
192 [ TYPE_ELECTRONIC ] = "Electronic",
193 [ TYPE_ONLINE ] = "Online",
194 [ TYPE_WWW ] = "WWW",
195 [ TYPE_PATENT ] = "Patent",
196 [ TYPE_MISC ] = "Misc",
197 };
198 int fstatus;
199 char *s;
200
201 if ( type < 0 || type >= NUM_TYPES ) type = TYPE_MISC;
202 s = typenames[ type ];
203
204 fstatus = fields_add( out, "TYPE", s, LEVEL_MAIN );
205 if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
206 }
207
208 static void
append_citekey(fields * in,fields * out,int format_opts,int * status)209 append_citekey( fields *in, fields *out, int format_opts, int *status )
210 {
211 int n, fstatus;
212 str s;
213 char *p;
214
215 n = fields_find( in, "REFNUM", LEVEL_ANY );
216 if ( ( format_opts & BIBL_FORMAT_BIBOUT_DROPKEY ) || n==FIELDS_NOTFOUND ) {
217 fstatus = fields_add( out, "REFNUM", "", LEVEL_MAIN );
218 if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
219 }
220
221 else {
222 str_init( &s );
223 p = fields_value( in, n, FIELDS_CHRP );
224 while ( p && *p && *p!='|' ) {
225 if ( format_opts & BIBL_FORMAT_BIBOUT_STRICTKEY ) {
226 if ( isdigit((unsigned char)*p) || (*p>='A' && *p<='Z') ||
227 (*p>='a' && *p<='z' ) ) {
228 str_addchar( &s, *p );
229 }
230 }
231 else {
232 if ( *p!=' ' && *p!='\t' ) {
233 str_addchar( &s, *p );
234 }
235 }
236 p++;
237 }
238 if ( str_memerr( &s ) ) { *status = BIBL_ERR_MEMERR; str_free( &s ); return; }
239 fstatus = fields_add( out, "REFNUM", str_cstr( &s ), LEVEL_MAIN );
240 if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
241 str_free( &s );
242 }
243 }
244
245 static void
append_simple(fields * in,char * intag,char * outtag,fields * out,int * status)246 append_simple( fields *in, char *intag, char *outtag, fields *out, int *status )
247 {
248 int n, fstatus;
249
250 n = fields_find( in, intag, LEVEL_ANY );
251 if ( n!=FIELDS_NOTFOUND ) {
252 fields_set_used( in, n );
253 fstatus = fields_add( out, outtag, fields_value( in, n, FIELDS_CHRP ), LEVEL_MAIN );
254 if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
255 }
256 }
257
258 static void
append_simpleall(fields * in,char * intag,char * outtag,fields * out,int * status)259 append_simpleall( fields *in, char *intag, char *outtag, fields *out, int *status )
260 {
261 int i, fstatus;
262
263 for ( i=0; i<in->n; ++i ) {
264 if ( fields_match_tag( in, i, intag ) ) {
265 fields_set_used( in, i );
266 fstatus = fields_add( out, outtag, fields_value( in, i, FIELDS_CHRP ), LEVEL_MAIN );
267 if ( fstatus!=FIELDS_OK ) {
268 *status = BIBL_ERR_MEMERR;
269 return;
270 }
271 }
272 }
273 }
274
275 static void
append_keywords(fields * in,fields * out,int * status)276 append_keywords( fields *in, fields *out, int *status )
277 {
278 str keywords, *word;
279 vplist_index i;
280 int fstatus;
281 vplist a;
282
283 str_init( &keywords );
284 vplist_init( &a );
285
286 fields_findv_each( in, LEVEL_ANY, FIELDS_STRP, &a, "KEYWORD" );
287
288 if ( a.n ) {
289
290 for ( i=0; i<a.n; ++i ) {
291 word = vplist_get( &a, i );
292 if ( i>0 ) str_strcatc( &keywords, "; " );
293 str_strcat( &keywords, word );
294 }
295
296 if ( str_memerr( &keywords ) ) { *status = BIBL_ERR_MEMERR; goto out; }
297
298 fstatus = fields_add( out, "keywords", str_cstr( &keywords ), LEVEL_MAIN );
299 if ( fstatus!=FIELDS_OK ) {
300 *status = BIBL_ERR_MEMERR;
301 goto out;
302 }
303
304
305 }
306
307 out:
308 str_free( &keywords );
309 vplist_free( &a );
310 }
311
312 static void
append_fileattach(fields * in,fields * out,int * status)313 append_fileattach( fields *in, fields *out, int *status )
314 {
315 char *tag, *value;
316 int i, fstatus;
317 str data;
318
319 str_init( &data );
320
321 for ( i=0; i<in->n; ++i ) {
322
323 tag = fields_tag( in, i, FIELDS_CHRP );
324 if ( strcasecmp( tag, "FILEATTACH" ) ) continue;
325
326 value = fields_value( in, i, FIELDS_CHRP );
327 str_strcpyc( &data, ":" );
328 str_strcatc( &data, value );
329 if ( strsearch( value, ".pdf" ) )
330 str_strcatc( &data, ":PDF" );
331 else if ( strsearch( value, ".html" ) )
332 str_strcatc( &data, ":HTML" );
333 else str_strcatc( &data, ":TYPE" );
334
335 if ( str_memerr( &data ) ) {
336 *status = BIBL_ERR_MEMERR;
337 goto out;
338 }
339
340 fields_set_used( in, i );
341 fstatus = fields_add( out, "file", str_cstr( &data ), LEVEL_MAIN );
342 if ( fstatus!=FIELDS_OK ) {
343 *status = BIBL_ERR_MEMERR;
344 goto out;
345 }
346
347 str_empty( &data );
348 }
349 out:
350 str_free( &data );
351 }
352
353 static void
append_people(fields * in,char * tag,char * ctag,char * atag,char * bibtag,int level,fields * out,int format_opts,int latex_out,int * status)354 append_people( fields *in, char *tag, char *ctag, char *atag,
355 char *bibtag, int level, fields *out, int format_opts, int latex_out, int *status )
356 {
357 int i, npeople, person, corp, asis, fstatus;
358 str allpeople, oneperson;
359
360 strs_init( &allpeople, &oneperson, NULL );
361
362 /* primary citation authors */
363 npeople = 0;
364 for ( i=0; i<in->n; ++i ) {
365 if ( level!=LEVEL_ANY && in->level[i]!=level ) continue;
366 person = ( strcasecmp( in->tag[i].data, tag ) == 0 );
367 corp = ( strcasecmp( in->tag[i].data, ctag ) == 0 );
368 asis = ( strcasecmp( in->tag[i].data, atag ) == 0 );
369 if ( person || corp || asis ) {
370 if ( npeople>0 ) {
371 if ( format_opts & BIBL_FORMAT_BIBOUT_WHITESPACE )
372 str_strcatc( &allpeople, "\n\t\tand " );
373 else str_strcatc( &allpeople, "\nand " );
374 }
375 if ( corp ) {
376 if ( latex_out ) str_addchar( &allpeople, '{' );
377 str_strcat( &allpeople, fields_value( in, i, FIELDS_STRP ) );
378 if ( latex_out ) str_addchar( &allpeople, '}' );
379 } else if ( asis ) {
380 if ( latex_out ) str_addchar( &allpeople, '{' );
381 str_strcat( &allpeople, fields_value( in, i, FIELDS_STRP ) );
382 if ( latex_out ) str_addchar( &allpeople, '}' );
383 } else {
384 name_build_withcomma( &oneperson, fields_value( in, i, FIELDS_CHRP ) );
385 str_strcat( &allpeople, &oneperson );
386 }
387 npeople++;
388 }
389 }
390 if ( npeople ) {
391 fstatus = fields_add( out, bibtag, allpeople.data, LEVEL_MAIN );
392 if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
393 }
394
395 strs_free( &allpeople, &oneperson, NULL );
396 }
397
398 static int
append_title_chosen(fields * in,char * bibtag,fields * out,int nmainttl,int nsubttl)399 append_title_chosen( fields *in, char *bibtag, fields *out, int nmainttl, int nsubttl )
400 {
401 str fulltitle, *mainttl = NULL, *subttl = NULL;
402 int status, ret = BIBL_OK;
403
404 str_init( &fulltitle );
405
406 if ( nmainttl!=-1 ) {
407 mainttl = fields_value( in, nmainttl, FIELDS_STRP );
408 fields_set_used( in, nmainttl );
409 }
410
411 if ( nsubttl!=-1 ) {
412 subttl = fields_value( in, nsubttl, FIELDS_STRP );
413 fields_set_used( in, nsubttl );
414 }
415
416 title_combine( &fulltitle, mainttl, subttl );
417
418 if ( str_memerr( &fulltitle ) ) {
419 ret = BIBL_ERR_MEMERR;
420 goto out;
421 }
422
423 if ( str_has_value( &fulltitle ) ) {
424 status = fields_add( out, bibtag, str_cstr( &fulltitle ), LEVEL_MAIN );
425 if ( status!=FIELDS_OK ) ret = BIBL_ERR_MEMERR;
426 }
427
428 out:
429 str_free( &fulltitle );
430 return ret;
431 }
432
433 static int
append_title(fields * in,char * bibtag,int level,fields * out,int format_opts)434 append_title( fields *in, char *bibtag, int level, fields *out, int format_opts )
435 {
436 int title, short_title, subtitle, short_subtitle, use_title, use_subtitle;
437
438 title = fields_find( in, "TITLE", level );
439 short_title = fields_find( in, "SHORTTITLE", level );
440 subtitle = fields_find( in, "SUBTITLE", level );
441 short_subtitle = fields_find( in, "SHORTSUBTITLE", level );
442
443 if ( title==FIELDS_NOTFOUND || ( ( format_opts & BIBL_FORMAT_BIBOUT_SHORTTITLE ) && level==1 ) ) {
444 use_title = short_title;
445 use_subtitle = short_subtitle;
446 }
447
448 else {
449 use_title = title;
450 use_subtitle = subtitle;
451 }
452
453 return append_title_chosen( in, bibtag, out, use_title, use_subtitle );
454 }
455
456 static void
append_titles(fields * in,int type,fields * out,int format_opts,int * status)457 append_titles( fields *in, int type, fields *out, int format_opts, int *status )
458 {
459 /* item=main level title */
460 *status = append_title( in, "title", 0, out, format_opts );
461 if ( *status!=BIBL_OK ) return;
462
463 switch( type ) {
464
465 case TYPE_ARTICLE:
466 *status = append_title( in, "journal", 1, out, format_opts );
467 break;
468
469 case TYPE_INBOOK:
470 *status = append_title( in, "bookTitle", 1, out, format_opts );
471 if ( *status!=BIBL_OK ) return;
472 *status = append_title( in, "series", 2, out, format_opts );
473 break;
474
475 case TYPE_INCOLLECTION:
476 case TYPE_INPROCEEDINGS:
477 *status = append_title( in, "booktitle", 1, out, format_opts );
478 if ( *status!=BIBL_OK ) return;
479 *status = append_title( in, "series", 2, out, format_opts );
480 break;
481
482 case TYPE_PHDTHESIS:
483 case TYPE_MASTERSTHESIS:
484 *status = append_title( in, "series", 1, out, format_opts );
485 break;
486
487 case TYPE_BOOK:
488 case TYPE_REPORT:
489 case TYPE_COLLECTION:
490 case TYPE_PROCEEDINGS:
491 *status = append_title( in, "series", 1, out, format_opts );
492 if ( *status!=BIBL_OK ) return;
493 *status = append_title( in, "series", 2, out, format_opts );
494 break;
495
496 default:
497 /* do nothing */
498 break;
499
500 }
501 }
502
503 static int
find_date(fields * in,char * date_element)504 find_date( fields *in, char *date_element )
505 {
506 char date[100], partdate[100];
507 int n;
508
509 sprintf( date, "DATE:%s", date_element );
510 n = fields_find( in, date, LEVEL_ANY );
511
512 if ( n==FIELDS_NOTFOUND ) {
513 sprintf( partdate, "PARTDATE:%s", date_element );
514 n = fields_find( in, partdate, LEVEL_ANY );
515 }
516
517 return n;
518 }
519
520 static void
append_date(fields * in,fields * out,int * status)521 append_date( fields *in, fields *out, int *status )
522 {
523 char *months[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
524 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
525 int n, month, fstatus;
526
527 n = find_date( in, "YEAR" );
528 if ( n!=FIELDS_NOTFOUND ) {
529 fields_set_used( in, n );
530 fstatus = fields_add( out, "year", fields_value( in, n, FIELDS_CHRP ), LEVEL_MAIN );
531 if ( fstatus!=FIELDS_OK ) {
532 *status = BIBL_ERR_MEMERR;
533 return;
534 }
535 }
536
537 n = find_date( in, "MONTH" );
538 if ( n!=-1 ) {
539 fields_set_used( in, n );
540 month = atoi( fields_value( in, n, FIELDS_CHRP ) );
541 if ( month>0 && month<13 )
542 fstatus = fields_add( out, "month", months[month-1], LEVEL_MAIN );
543 else
544 fstatus = fields_add( out, "month", fields_value( in, n, FIELDS_CHRP ), LEVEL_MAIN );
545 if ( fstatus!=FIELDS_OK ) {
546 *status = BIBL_ERR_MEMERR;
547 return;
548 }
549 }
550
551 n = find_date( in, "DAY" );
552 if ( n!=-1 ) {
553 fields_set_used( in, n );
554 fstatus = fields_add( out, "day", fields_value( in, n, FIELDS_CHRP ), LEVEL_MAIN );
555 if ( fstatus!=FIELDS_OK ) {
556 *status = BIBL_ERR_MEMERR;
557 return;
558 }
559 }
560
561 }
562
563 static void
append_arxiv(fields * in,fields * out,int * status)564 append_arxiv( fields *in, fields *out, int *status )
565 {
566 int n, fstatus1, fstatus2;
567 str url;
568
569 n = fields_find( in, "ARXIV", LEVEL_ANY );
570 if ( n==FIELDS_NOTFOUND ) return;
571
572 fields_set_used( in, n );
573
574 /* ...write:
575 * archivePrefix = "arXiv",
576 * eprint = "#####",
577 * ...for arXiv references
578 */
579 fstatus1 = fields_add( out, "archivePrefix", "arXiv", LEVEL_MAIN );
580 fstatus2 = fields_add( out, "eprint", fields_value( in, n, FIELDS_CHRP ), LEVEL_MAIN );
581 if ( fstatus1!=FIELDS_OK || fstatus2!=FIELDS_OK ) {
582 *status = BIBL_ERR_MEMERR;
583 return;
584 }
585
586 /* ...also write:
587 * url = "http://arxiv.org/abs/####",
588 * ...to maximize compatibility
589 */
590 str_init( &url );
591 arxiv_to_url( in, n, "URL", &url );
592 if ( str_has_value( &url ) ) {
593 fstatus1 = fields_add( out, "url", str_cstr( &url ), LEVEL_MAIN );
594 if ( fstatus1!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
595 }
596 str_free( &url );
597 }
598
599 static void
append_urls(fields * in,fields * out,int * status)600 append_urls( fields *in, fields *out, int *status )
601 {
602 int lstatus;
603 slist types;
604
605 lstatus = slist_init_valuesc( &types, "URL", "DOI", "PMID", "PMC", "JSTOR", NULL );
606 if ( lstatus!=SLIST_OK ) {
607 *status = BIBL_ERR_MEMERR;
608 return;
609 }
610
611 *status = urls_merge_and_add( in, LEVEL_ANY, out, "url", LEVEL_MAIN, &types );
612
613 slist_free( &types );
614 }
615
616 static void
append_isi(fields * in,fields * out,int * status)617 append_isi( fields *in, fields *out, int *status )
618 {
619 int n, fstatus;
620
621 n = fields_find( in, "ISIREFNUM", LEVEL_ANY );
622 if ( n==FIELDS_NOTFOUND ) return;
623
624 fstatus = fields_add( out, "note", fields_value( in, n, FIELDS_CHRP ), LEVEL_MAIN );
625 if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
626 }
627
628 static void
append_articlenumber(fields * in,fields * out,int * status)629 append_articlenumber( fields *in, fields *out, int *status )
630 {
631 int n, fstatus;
632
633 n = fields_find( in, "ARTICLENUMBER", LEVEL_ANY );
634 if ( n==FIELDS_NOTFOUND ) return;
635
636 fields_set_used( in, n );
637 fstatus = fields_add( out, "pages", fields_value( in, n, FIELDS_CHRP ), LEVEL_MAIN );
638 if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
639 }
640
641 static int
pages_build_pagestr(str * pages,fields * in,int sn,int en,int format_opts)642 pages_build_pagestr( str *pages, fields *in, int sn, int en, int format_opts )
643 {
644 /* ...append if starting page number is defined */
645 if ( sn!=-1 ) {
646 str_strcat( pages, fields_value( in, sn, FIELDS_STRP ) );
647 fields_set_used( in, sn );
648 }
649
650 /* ...append dashes if both starting and ending page numbers are defined */
651 if ( sn!=-1 && en!=-1 ) {
652 if ( format_opts & BIBL_FORMAT_BIBOUT_SINGLEDASH )
653 str_strcatc( pages, "-" );
654 else
655 str_strcatc( pages, "--" );
656 }
657
658 /* ...append ending page number is defined */
659 if ( en!=-1 ) {
660 str_strcat( pages, fields_value( in, en, FIELDS_STRP ) );
661 fields_set_used( in, en );
662 }
663
664 if ( str_memerr( pages ) ) return BIBL_ERR_MEMERR;
665 else return BIBL_OK;
666 }
667
668 static int
pages_are_defined(fields * in,int * sn,int * en)669 pages_are_defined( fields *in, int *sn, int *en )
670 {
671 *sn = fields_find( in, "PAGES:START", LEVEL_ANY );
672 *en = fields_find( in, "PAGES:STOP", LEVEL_ANY );
673 if ( *sn==FIELDS_NOTFOUND && *en==FIELDS_NOTFOUND ) return 0;
674 else return 1;
675 }
676
677 static void
append_pages(fields * in,fields * out,int format_opts,int * status)678 append_pages( fields *in, fields *out, int format_opts, int *status )
679 {
680 int sn, en, fstatus;
681 str pages;
682
683 if ( !pages_are_defined( in, &sn, &en ) ) {
684 append_articlenumber( in, out, status );
685 return;
686 }
687
688 str_init( &pages );
689 *status = pages_build_pagestr( &pages, in, sn, en, format_opts );
690 if ( *status==BIBL_OK ) {
691 fstatus = fields_add( out, "pages", str_cstr( &pages ), LEVEL_MAIN );
692 if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
693 }
694 str_free( &pages );
695 }
696
697 /*
698 * from Tim Hicks:
699 * I'm no expert on bibtex, but those who know more than I on our mailing
700 * list suggest that 'issue' isn't a recognised key for bibtex and
701 * therefore that bibutils should be aliasing IS to number at some point in
702 * the conversion.
703 *
704 * Therefore prefer outputting issue/number as number and only keep
705 * a distinction if both issue and number are present for a particular
706 * reference.
707 */
708
709 static void
append_issue_number(fields * in,fields * out,int * status)710 append_issue_number( fields *in, fields *out, int *status )
711 {
712 char issue[] = "issue", number[] = "number", *use_issue = number;
713 int nissue = fields_find( in, "ISSUE", LEVEL_ANY );
714 int nnumber = fields_find( in, "NUMBER", LEVEL_ANY );
715 int fstatus;
716
717 if ( nissue!=FIELDS_NOTFOUND && nnumber!=FIELDS_NOTFOUND ) use_issue = issue;
718
719 if ( nissue!=FIELDS_NOTFOUND ) {
720 fields_set_used( in, nissue );
721 fstatus = fields_add( out, use_issue, fields_value( in, nissue, FIELDS_CHRP ), LEVEL_MAIN );
722 if ( fstatus!=FIELDS_OK ) {
723 *status = BIBL_ERR_MEMERR;
724 return;
725 }
726 }
727
728 if ( nnumber!=FIELDS_NOTFOUND ) {
729 fields_set_used( in, nnumber );
730 fstatus = fields_add( out, "number", fields_value( in, nnumber, FIELDS_CHRP ), LEVEL_MAIN );
731 if ( fstatus!=FIELDS_OK ) {
732 *status = BIBL_ERR_MEMERR;
733 return;
734 }
735 }
736 }
737
738 static void
append_howpublished(fields * in,fields * out,int * status)739 append_howpublished( fields *in, fields *out, int *status )
740 {
741 int n, fstatus;
742 char *d;
743
744 n = fields_find( in, "GENRE:BIBUTILS", LEVEL_ANY );
745 if ( n==FIELDS_NOTFOUND ) return;
746
747 d = fields_value( in, n, FIELDS_CHRP_NOUSE );
748 if ( !strcmp( d, "Habilitation thesis" ) ) {
749 fstatus = fields_add( out, "howpublised", d, LEVEL_MAIN );
750 if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
751 }
752 if ( !strcmp( d, "Licentiate thesis" ) ) {
753 fstatus = fields_add( out, "howpublised", d, LEVEL_MAIN );
754 if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
755 }
756 if ( !strcmp( d, "Diploma thesis" ) ) {
757 fstatus = fields_add( out, "howpublised", d, LEVEL_MAIN );
758 if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
759 }
760 }
761
762 static int
biblatexout_assemble(fields * in,fields * out,param * pm,unsigned long refnum)763 biblatexout_assemble( fields *in, fields *out, param *pm, unsigned long refnum )
764 {
765 int type, status = BIBL_OK;
766
767 type = biblatexout_type( in, pm->progname, "", refnum );
768
769 append_type ( type, out, &status );
770 append_citekey ( in, out, pm->format_opts, &status );
771 append_people ( in, "AUTHOR", "AUTHOR:CORP", "AUTHOR:ASIS", "author", LEVEL_MAIN, out, pm->format_opts, pm->latexout, &status );
772 append_people ( in, "AUTHOR", "AUTHOR:CORP", "AUTHOR:ASIS", "bookauthor", LEVEL_HOST, out, pm->format_opts, pm->latexout, &status );
773 append_people ( in, "EDITOR", "EDITOR:CORP", "EDITOR:ASIS", "editor", LEVEL_ANY, out, pm->format_opts, pm->latexout, &status );
774 append_people ( in, "ANNOTATOR", "ANNOTATOR:CORP", "ANNOTATOR:ASIS", "annotator", LEVEL_ANY, out, pm->format_opts, pm->latexout, &status );
775 append_people ( in, "TRANSLATOR", "TRANSLATOR:CORP", "TRANSLATOR:ASIS", "translator", LEVEL_ANY, out, pm->format_opts, pm->latexout, &status );
776 append_people ( in, "REDACTOR", "REDACTOR:CORP", "REDACTOR:ASIS", "redactor", LEVEL_ANY, out, pm->format_opts, pm->latexout, &status );
777 append_people ( in, "COMMENTATOR","COMMENTATOR:CORP","COMMENTATOR:ASIS","commentator", LEVEL_ANY, out, pm->format_opts, pm->latexout, &status );
778 append_people ( in, "INTROAUTHOR","INTROAUTHOR:CORP","INTROAUTHOR:ASIS","introduction", LEVEL_ANY, out, pm->format_opts, pm->latexout, &status );
779 append_people ( in, "AFTERAUTHOR","AFTERAUTHOR:CORP","AFTERAUTHOR:ASIS","afterword", LEVEL_ANY, out, pm->format_opts, pm->latexout, &status );
780 append_titles ( in, type, out, pm->format_opts, &status );
781 append_simple ( in, "SHORTTITLE", "shorttitle", out, &status );
782 append_date ( in, out, &status );
783 append_simple ( in, "EDITION", "edition", out, &status );
784 append_simple ( in, "PUBLISHER", "publisher", out, &status );
785 append_simple ( in, "ADDRESS", "address", out, &status );
786 append_simple ( in, "EDITION", "version", out, &status );
787 append_simple ( in, "PART", "part", out, &status );
788 append_simple ( in, "VOLUME", "volume", out, &status );
789 append_issue_number( in, out, &status );
790 append_pages ( in, out, pm->format_opts, &status );
791 append_keywords ( in, out, &status );
792 append_simple ( in, "LANGCATALOG", "hyphenation", out, &status );
793 append_simple ( in, "CONTENTS", "contents", out, &status );
794 append_simple ( in, "ABSTRACT", "abstract", out, &status );
795 append_simple ( in, "LOCATION", "location", out, &status );
796 append_simple ( in, "DEGREEGRANTOR", "school", out, &status );
797 append_simple ( in, "DEGREEGRANTOR:ASIS", "school", out, &status );
798 append_simple ( in, "DEGREEGRANTOR:CORP", "school", out, &status );
799 append_simpleall ( in, "NOTES", "note", out, &status );
800 append_simpleall ( in, "ANNOTE", "annote", out, &status );
801 append_simpleall ( in, "ANNOTATION", "annotation", out, &status );
802 append_simple ( in, "ISBN", "isbn", out, &status );
803 append_simple ( in, "ISSN", "issn", out, &status );
804 append_simple ( in, "MRNUMBER", "mrnumber", out, &status );
805 append_simple ( in, "CODEN", "coden", out, &status );
806 append_simple ( in, "DOI", "doi", out, &status );
807 append_simple ( in, "EID", "eid", out, &status );
808 append_urls ( in, out, &status );
809 append_fileattach ( in, out, &status );
810 append_arxiv ( in, out, &status );
811 append_simple ( in, "EPRINTCLASS", "primaryClass", out, &status );
812 append_isi ( in, out, &status );
813 append_simple ( in, "LANGUAGE", "language", out, &status );
814 append_howpublished( in, out, &status );
815
816 return status;
817 }
818
819 /*****************************************************
820 PUBLIC: int biblatexout_write()
821 *****************************************************/
822
823 static int
biblatexout_write(fields * out,FILE * fp,param * pm,unsigned long refnum)824 biblatexout_write( fields *out, FILE *fp, param *pm, unsigned long refnum )
825 {
826 int i, j, len, nquotes, format_opts = pm->format_opts;
827 char *tag, *value, ch;
828
829 /* ...output type information "@article{" */
830 value = ( char * ) fields_value( out, 0, FIELDS_CHRP );
831 if ( !(format_opts & BIBL_FORMAT_BIBOUT_UPPERCASE) ) fprintf( fp, "@%s{", value );
832 else {
833 len = (value) ? strlen( value ) : 0;
834 fprintf( fp, "@" );
835 for ( i=0; i<len; ++i )
836 fprintf( fp, "%c", toupper((unsigned char)value[i]) );
837 fprintf( fp, "{" );
838 }
839
840 /* ...output refnum "Smith2001" */
841 value = ( char * ) fields_value( out, 1, FIELDS_CHRP );
842 fprintf( fp, "%s", value );
843
844 /* ...rest of the references */
845 for ( j=2; j<out->n; ++j ) {
846 nquotes = 0;
847 tag = ( char * ) fields_tag( out, j, FIELDS_CHRP );
848 value = ( char * ) fields_value( out, j, FIELDS_CHRP );
849 fprintf( fp, ",\n" );
850 if ( format_opts & BIBL_FORMAT_BIBOUT_WHITESPACE ) fprintf( fp, " " );
851 if ( !(format_opts & BIBL_FORMAT_BIBOUT_UPPERCASE ) ) fprintf( fp, "%s", tag );
852 else {
853 len = strlen( tag );
854 for ( i=0; i<len; ++i )
855 fprintf( fp, "%c", toupper((unsigned char)tag[i]) );
856 }
857 if ( format_opts & BIBL_FORMAT_BIBOUT_WHITESPACE ) fprintf( fp, " = \t" );
858 else fprintf( fp, "=" );
859
860 if ( format_opts & BIBL_FORMAT_BIBOUT_BRACKETS ) fprintf( fp, "{" );
861 else fprintf( fp, "\"" );
862
863 len = strlen( value );
864 for ( i=0; i<len; ++i ) {
865 ch = value[i];
866 if ( ch!='\"' ) fprintf( fp, "%c", ch );
867 else {
868 if ( format_opts & BIBL_FORMAT_BIBOUT_BRACKETS || ( i>0 && value[i-1]=='\\' ) )
869 fprintf( fp, "\"" );
870 else {
871 if ( nquotes % 2 == 0 )
872 fprintf( fp, "``" );
873 else fprintf( fp, "\'\'" );
874 nquotes++;
875 }
876 }
877 }
878
879 if ( format_opts & BIBL_FORMAT_BIBOUT_BRACKETS ) fprintf( fp, "}" );
880 else fprintf( fp, "\"" );
881 }
882
883 /* ...finish reference */
884 if ( format_opts & BIBL_FORMAT_BIBOUT_FINALCOMMA ) fprintf( fp, "," );
885 fprintf( fp, "\n}\n\n" );
886
887 fflush( fp );
888
889 return BIBL_OK;
890 }
891