1 /*
2  * endout.c
3  *
4  * Copyright (c) Chris Putnam 2004-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 "utf8.h"
14 #include "str.h"
15 #include "strsearch.h"
16 #include "fields.h"
17 #include "generic.h"
18 #include "name.h"
19 #include "title.h"
20 #include "type.h"
21 #include "url.h"
22 #include "bibformats.h"
23 
24 /*****************************************************
25  PUBLIC: int endout_initparams()
26 *****************************************************/
27 
28 static int endout_write( fields *in, FILE *fp, param *p, unsigned long refnum );
29 static int endout_assemble( fields *in, fields *out, param *pm, unsigned long refnum );
30 
31 int
endout_initparams(param * pm,const char * progname)32 endout_initparams( param *pm, const char *progname )
33 {
34 	pm->writeformat      = BIBL_ENDNOTEOUT;
35 	pm->format_opts      = 0;
36 	pm->charsetout       = BIBL_CHARSET_DEFAULT;
37 	pm->charsetout_src   = BIBL_SRC_DEFAULT;
38 	pm->latexout         = 0;
39 	pm->utf8out          = BIBL_CHARSET_UTF8_DEFAULT;
40 	pm->utf8bom          = BIBL_CHARSET_BOM_DEFAULT;
41 	pm->xmlout           = BIBL_XMLOUT_FALSE;
42 	pm->nosplittitle     = 0;
43 	pm->verbose          = 0;
44 	pm->addcount         = 0;
45 	pm->singlerefperfile = 0;
46 
47 	if ( pm->charsetout == BIBL_CHARSET_UNICODE ) {
48 		pm->utf8out = pm->utf8bom = 1;
49 	}
50 
51 	pm->headerf   = generic_writeheader;
52 	pm->footerf   = NULL;
53 	pm->assemblef = endout_assemble;
54 	pm->writef    = endout_write;
55 
56 	if ( !pm->progname ) {
57 		if ( !progname ) pm->progname = NULL;
58 		else {
59 			pm->progname = strdup( progname );
60 			if ( !pm->progname ) return BIBL_ERR_MEMERR;
61 		}
62 	}
63 
64 	return BIBL_OK;
65 }
66 
67 /*****************************************************
68  PUBLIC: int endout_assemble()
69 *****************************************************/
70 
71 enum {
72 	TYPE_UNKNOWN = 0,
73 	TYPE_GENERIC,                     /* Generic */
74 	TYPE_ARTWORK,                     /* Artwork */
75 	TYPE_AUDIOVISUAL,                 /* Audiovisual Material */
76 	TYPE_BILL,                        /* Bill */
77 	TYPE_BOOK,                        /* Book */
78 	TYPE_INBOOK,                      /* Book Section */
79 	TYPE_CASE,                        /* Case */
80 	TYPE_CHARTTABLE,                  /* Chart or Table */
81 	TYPE_CLASSICALWORK,               /* Classical Work */
82 	TYPE_PROGRAM,                     /* Computer Program */
83 	TYPE_INPROCEEDINGS,               /* Conference Paper */
84 	TYPE_PROCEEDINGS,                 /* Conference Proceedings */
85 	TYPE_EDITEDBOOK,                  /* Edited Book */
86 	TYPE_EQUATION,                    /* Equation */
87 	TYPE_ELECTRONICARTICLE,           /* Electronic Article */
88 	TYPE_ELECTRONICBOOK,              /* Electronic Book */
89 	TYPE_ELECTRONIC,                  /* Electronic Source */
90 	TYPE_FIGURE,                      /* Figure */
91 	TYPE_FILMBROADCAST,               /* Film or Broadcast */
92 	TYPE_GOVERNMENT,                  /* Government Document */
93 	TYPE_HEARING,                     /* Hearing */
94 	TYPE_ARTICLE,                     /* Journal Article */
95 	TYPE_LEGALRULE,                   /* Legal Rule/Regulation */
96 	TYPE_MAGARTICLE,                  /* Magazine Article */
97 	TYPE_MANUSCRIPT,                  /* Manuscript */
98 	TYPE_MAP,                         /* Map */
99 	TYPE_NEWSARTICLE,                 /* Newspaper Article */
100 	TYPE_ONLINEDATABASE,              /* Online Database */
101 	TYPE_ONLINEMULTIMEDIA,            /* Online Multimedia */
102 	TYPE_PATENT,                      /* Patent */
103 	TYPE_COMMUNICATION,               /* Personal Communication */
104 	TYPE_REPORT,                      /* Report */
105 	TYPE_STATUTE,                     /* Statute */
106 	TYPE_THESIS,                      /* Thesis */
107 	TYPE_MASTERSTHESIS,               /* Thesis */
108 	TYPE_PHDTHESIS,                   /* Thesis */
109 	TYPE_DIPLOMATHESIS,               /* Thesis */
110 	TYPE_DOCTORALTHESIS,              /* Thesis */
111 	TYPE_HABILITATIONTHESIS,          /* Thesis */
112 	TYPE_LICENTIATETHESIS,            /* Thesis */
113 	TYPE_UNPUBLISHED,                 /* Unpublished Work */
114 };
115 
116 static void
write_type(FILE * fp,int type)117 write_type( FILE *fp, int type )
118 {
119 	switch( type ) {
120 	case TYPE_UNKNOWN:           fprintf( fp, "TYPE_UNKNOWN" );            break;
121 	case TYPE_GENERIC:           fprintf( fp, "TYPE_GENERIC" );            break;
122 	case TYPE_ARTWORK:           fprintf( fp, "TYPE_ARTWORK" );            break;
123 	case TYPE_AUDIOVISUAL:       fprintf( fp, "TYPE_AUDIOVISUAL" );        break;
124 	case TYPE_BILL:              fprintf( fp, "TYPE_BILL" );               break;
125 	case TYPE_BOOK:              fprintf( fp, "TYPE_BOOK" );               break;
126 	case TYPE_INBOOK:            fprintf( fp, "TYPE_INBOOK" );             break;
127 	case TYPE_CASE:              fprintf( fp, "TYPE_CASE" );               break;
128 	case TYPE_CHARTTABLE:        fprintf( fp, "TYPE_CHARITABLE" );         break;
129 	case TYPE_CLASSICALWORK:     fprintf( fp, "TYPE_CLASSICALWORK" );      break;
130 	case TYPE_PROGRAM:           fprintf( fp, "TYPE_PROGRAM" );            break;
131 	case TYPE_INPROCEEDINGS:     fprintf( fp, "TYPE_INPROCEEDINGS" );      break;
132 	case TYPE_PROCEEDINGS:       fprintf( fp, "TYPE_PROCEEDINGS" );        break;
133 	case TYPE_EDITEDBOOK:        fprintf( fp, "TYPE_EDITEDBOOK" );         break;
134 	case TYPE_EQUATION:          fprintf( fp, "TYPE_EQUATION" );           break;
135 	case TYPE_ELECTRONICARTICLE: fprintf( fp, "TYPE_ELECTRONICARTICLE" );  break;
136 	case TYPE_ELECTRONICBOOK:    fprintf( fp, "TYPE_ELECTRONICBOOK" );     break;
137 	case TYPE_ELECTRONIC:        fprintf( fp, "TYPE_ELECTRONIC" );         break;
138 	case TYPE_FIGURE:            fprintf( fp, "TYPE_FIGURE" );             break;
139 	case TYPE_FILMBROADCAST:     fprintf( fp, "TYPE_FILMBROADCAST" );      break;
140 	case TYPE_GOVERNMENT:        fprintf( fp, "TYPE_GOVERNMENT" );         break;
141 	case TYPE_HEARING:           fprintf( fp, "TYPE_HEARING" );            break;
142 	case TYPE_ARTICLE:           fprintf( fp, "TYPE_ARTICLE" );            break;
143 	case TYPE_LEGALRULE:         fprintf( fp, "TYPE_LEGALRULE" );          break;
144 	case TYPE_MAGARTICLE:        fprintf( fp, "TYPE_MAGARTICLE" );         break;
145 	case TYPE_MANUSCRIPT:        fprintf( fp, "TYPE_MANUSCRIPT" );         break;
146 	case TYPE_MAP:               fprintf( fp, "TYPE_MAP" );                break;
147 	case TYPE_NEWSARTICLE:       fprintf( fp, "TYPE_NEWSARTICLE" );        break;
148 	case TYPE_ONLINEDATABASE:    fprintf( fp, "TYPE_ONLINEDATABASE" );     break;
149 	case TYPE_ONLINEMULTIMEDIA:  fprintf( fp, "TYPE_ONLINEMULTIMEDIA" );   break;
150 	case TYPE_PATENT:            fprintf( fp, "TYPE_PATENT" );             break;
151 	case TYPE_COMMUNICATION:     fprintf( fp, "TYPE_COMMUNICATION" );      break;
152 	case TYPE_REPORT:            fprintf( fp, "TYPE_REPORT" );             break;
153 	case TYPE_STATUTE:           fprintf( fp, "TYPE_STATUTE" );            break;
154 	case TYPE_THESIS:            fprintf( fp, "TYPE_THESIS" );             break;
155 	case TYPE_MASTERSTHESIS:     fprintf( fp, "TYPE_MASTERSTHESIS" );      break;
156 	case TYPE_PHDTHESIS:         fprintf( fp, "TYPE_PHDTHESIS" );          break;
157 	case TYPE_DIPLOMATHESIS:     fprintf( fp, "TYPE_DIPLOMATHESIS" );      break;
158 	case TYPE_DOCTORALTHESIS:    fprintf( fp, "TYPE_DOCTORALTHESIS" );     break;
159 	case TYPE_HABILITATIONTHESIS:fprintf( fp, "TYPE_HABILITATIONTHESIS" ); break;
160 	case TYPE_UNPUBLISHED:       fprintf( fp, "TYPE_UNPUBLISHED" );        break;
161 	default:                     fprintf( fp, "Error - type not in enum" );break;
162 	}
163 }
164 
165 static void
type_report_progress(param * p,const char * element_type,int type,unsigned long refnum)166 type_report_progress( param *p, const char *element_type, int type, unsigned long refnum )
167 {
168 	// Patch: Disable output logging
169 }
170 
171 static int
type_from_default(fields * in,param * p,unsigned long refnum)172 type_from_default( fields *in, param *p, unsigned long refnum )
173 {
174 	int n, type;
175 
176 	/* default to chapter if host terms */
177 	if ( fields_maxlevel( in ) > 0 ) type = TYPE_INBOOK;
178 
179 	/* default to generic if no host terms */
180 	else type = TYPE_GENERIC;
181 
182 	// Patch: Disable output logging
183 	n = fields_find( in, "REFNUM", LEVEL_ANY );
184 	return type;
185 }
186 
187 static int
get_type(fields * in,param * p,unsigned long refnum)188 get_type( fields *in, param *p, unsigned long refnum )
189 {
190 	/* Comment out TYPE_GENERIC entries as that is default, but
191          * keep in source as record of mapping decision. */
192 	match_type genre_matches[] = {
193 		/* MARC Authority elements */
194 		{ "art original",              TYPE_ARTWORK,            LEVEL_ANY  },
195 		{ "art reproduction",          TYPE_ARTWORK,            LEVEL_ANY  },
196 		{ "article",                   TYPE_ARTICLE,            LEVEL_ANY  },
197 		{ "atlas",                     TYPE_MAP,                LEVEL_ANY  },
198 		{ "autobiography",             TYPE_BOOK,               LEVEL_ANY  },
199 /*		{ "bibliography",              TYPE_GENERIC,            LEVEL_ANY  },*/
200 		{ "biography",                 TYPE_BOOK,               LEVEL_ANY  },
201 		{ "book",                      TYPE_BOOK,               LEVEL_MAIN },
202 		{ "book",                      TYPE_INBOOK,             LEVEL_ANY  },
203 /*		{ "calendar",                  TYPE_GENERIC,            LEVEL_ANY  },*/
204 /*		{ "catalog",                   TYPE_GENERIC,            LEVEL_ANY  },*/
205 		{ "chart",                     TYPE_CHARTTABLE,         LEVEL_ANY  },
206 /*		{ "comic or graphic novel",    TYPE_GENERIC,            LEVEL_ANY  },*/
207 /*		{ "comic strip",               TYPE_GENERIC,            LEVEL_ANY  },*/
208 		{ "conference publication",    TYPE_PROCEEDINGS,        LEVEL_ANY  },
209 		{ "database",                  TYPE_ONLINEDATABASE,     LEVEL_ANY  },
210 /*		{ "dictionary",                TYPE_GENERIC,            LEVEL_ANY  },*/
211 		{ "diorama",                   TYPE_ARTWORK,            LEVEL_ANY  },
212 /*		{ "directory",                 TYPE_GENERIC,            LEVEL_ANY  },*/
213 		{ "discography",               TYPE_AUDIOVISUAL,        LEVEL_ANY  },
214 /*		{ "drama",                     TYPE_GENERIC,            LEVEL_ANY  },*/
215 		{ "encyclopedia",              TYPE_BOOK,               LEVEL_ANY  },
216 /*		{ "essay",                     TYPE_GENERIC,            LEVEL_ANY  }, */
217 		{ "festschrift",               TYPE_BOOK,               LEVEL_MAIN },
218 		{ "festschrift",               TYPE_INBOOK,             LEVEL_ANY  },
219 		{ "fiction",                   TYPE_BOOK,               LEVEL_ANY  },
220 		{ "filmography",               TYPE_FILMBROADCAST,      LEVEL_ANY  },
221 		{ "filmstrip",                 TYPE_FILMBROADCAST,      LEVEL_ANY  },
222 /*		{ "finding aid",               TYPE_GENERIC,            LEVEL_ANY  },*/
223 /*		{ "flash card",                TYPE_GENERIC,            LEVEL_ANY  },*/
224 		{ "folktale",                  TYPE_CLASSICALWORK,      LEVEL_ANY  },
225 		{ "font",                      TYPE_ELECTRONIC,         LEVEL_ANY  },
226 /*		{ "game",                      TYPE_GENERIC,            LEVEL_ANY  },*/
227 		{ "government publication",    TYPE_GOVERNMENT,         LEVEL_ANY  },
228 		{ "graphic",                   TYPE_FIGURE,             LEVEL_ANY  },
229 		{ "globe",                     TYPE_MAP,                LEVEL_ANY  },
230 /*		{ "handbook",                  TYPE_GENERIC,            LEVEL_ANY  },*/
231 		{ "history",                   TYPE_BOOK,               LEVEL_ANY  },
232 		{ "hymnal",                    TYPE_BOOK,               LEVEL_MAIN },
233 		{ "hymnal",                    TYPE_INBOOK,             LEVEL_ANY  },
234 /*		{ "humor, satire",             TYPE_GENERIC,            LEVEL_ANY  },*/
235 /*		{ "index",                     TYPE_GENERIC,            LEVEL_ANY  },*/
236 /*		{ "instruction",               TYPE_GENERIC,            LEVEL_ANY  },*/
237 /*		{ "interview",                 TYPE_GENERIC,            LEVEL_ANY  },*/
238 		{ "issue",                     TYPE_ARTICLE,            LEVEL_ANY  },
239 		{ "journal",                   TYPE_ARTICLE,            LEVEL_ANY  },
240 /*		{ "kit",                       TYPE_GENERIC,            LEVEL_ANY  },*/
241 /*		{ "language instruction",      TYPE_GENERIC,            LEVEL_ANY  },*/
242 /*		{ "law report or digest",      TYPE_GENERIC,            LEVEL_ANY  },*/
243 /*		{ "legal article",             TYPE_GENERIC,            LEVEL_ANY  },*/
244 		{ "legal case and case notes", TYPE_CASE,               LEVEL_ANY  },
245 		{ "legislation",               TYPE_BILL,               LEVEL_ANY  },
246 		{ "letter",                    TYPE_COMMUNICATION,      LEVEL_ANY  },
247 		{ "loose-leaf",                TYPE_GENERIC,            LEVEL_ANY  },
248 		{ "map",                       TYPE_MAP,                LEVEL_ANY  },
249 /*		{ "memoir",                    TYPE_GENERIC,            LEVEL_ANY  },*/
250 /*		{ "microscope slide",          TYPE_GENERIC,            LEVEL_ANY  },*/
251 /*		{ "model",                     TYPE_GENERIC,            LEVEL_ANY  },*/
252 		{ "motion picture",            TYPE_AUDIOVISUAL,        LEVEL_ANY  },
253 		{ "multivolume monograph",     TYPE_BOOK,               LEVEL_ANY  },
254 		{ "newspaper",                 TYPE_NEWSARTICLE,        LEVEL_ANY  },
255 		{ "novel",                     TYPE_BOOK,               LEVEL_ANY  },
256 /*		{ "numeric data",              TYPE_GENERIC,            LEVEL_ANY  },*/
257 /*		{ "offprint",                  TYPE_GENERIC,            LEVEL_ANY  },*/
258 		{ "online system or service",  TYPE_ELECTRONIC,         LEVEL_ANY  },
259 		{ "patent",                    TYPE_PATENT,             LEVEL_ANY  },
260 		{ "picture",                   TYPE_ARTWORK,            LEVEL_ANY  },
261 /*		{ "poetry",                    TYPE_GENERIC,            LEVEL_ANY  },*/
262 		{ "programmed text",           TYPE_PROGRAM,            LEVEL_ANY  },
263 /*		{ "realia",                    TYPE_GENERIC,            LEVEL_ANY  },*/
264 		{ "rehearsal",                 TYPE_AUDIOVISUAL,        LEVEL_ANY  },
265 /*		{ "remote sensing image",      TYPE_GENERIC,            LEVEL_ANY  },*/
266 /*		{ "reporting",                 TYPE_GENERIC,            LEVEL_ANY  },*/
267 		{ "report",                    TYPE_REPORT,             LEVEL_ANY  },
268 /*		{ "review",                    TYPE_GENERIC,            LEVEL_ANY  },*/
269 /*		{ "script",                    TYPE_GENERIC,            LEVEL_ANY  },*/
270 /*		{ "series",                    TYPE_GENERIC,            LEVEL_ANY  },*/
271 /*		{ "short story",               TYPE_GENERIC,            LEVEL_ANY  },*/
272 /*		{ "slide",                     TYPE_GENERIC,            LEVEL_ANY  },*/
273 		{ "sound",                     TYPE_AUDIOVISUAL,        LEVEL_ANY  },
274 /*		{ "speech",                    TYPE_GENERIC,            LEVEL_ANY  },*/
275 /*		{ "standard or specification", TYPE_GENERIC,            LEVEL_ANY  },*/
276 /*		{ "statistics",                TYPE_GENERIC,            LEVEL_ANY  },*/
277 /*		{ "survey of literature",      TYPE_GENERIC,            LEVEL_ANY  },*/
278 		{ "technical drawing",         TYPE_ARTWORK,            LEVEL_ANY  },
279 		{ "technical report",          TYPE_REPORT,             LEVEL_ANY  },
280 /*		{ "toy",                       TYPE_GENERIC,            LEVEL_ANY  },*/
281 /*		{ "transparency",              TYPE_GENERIC,            LEVEL_ANY  },*/
282 /*		{ "treaty",                    TYPE_GENERIC,            LEVEL_ANY  },*/
283 		{ "videorecording",            TYPE_AUDIOVISUAL,        LEVEL_ANY  },
284 		{ "web site",                  TYPE_ELECTRONIC,         LEVEL_ANY  },
285 		/* Non-MARC Authority elements */
286 		{ "academic journal",          TYPE_ARTICLE,            LEVEL_ANY  },
287 		{ "collection",                TYPE_BOOK,               LEVEL_MAIN },
288 		{ "collection",                TYPE_INBOOK,             LEVEL_ANY  },
289 		{ "magazine",                  TYPE_MAGARTICLE,         LEVEL_ANY  },
290 		{ "hearing",                   TYPE_HEARING,            LEVEL_ANY  },
291 		{ "Ph.D. thesis",              TYPE_PHDTHESIS,          LEVEL_ANY  },
292 		{ "Masters thesis",            TYPE_MASTERSTHESIS,      LEVEL_ANY  },
293 		{ "Diploma thesis",            TYPE_DIPLOMATHESIS,      LEVEL_ANY  },
294 		{ "Doctoral thesis",           TYPE_DOCTORALTHESIS,     LEVEL_ANY  },
295 		{ "Habilitation thesis",       TYPE_HABILITATIONTHESIS, LEVEL_ANY  },
296 		{ "Licentiate thesis",         TYPE_LICENTIATETHESIS,   LEVEL_ANY  },
297 		{ "communication",             TYPE_COMMUNICATION,      LEVEL_ANY  },
298 		{ "manuscript",                TYPE_MANUSCRIPT,         LEVEL_ANY  },
299 		{ "unpublished",               TYPE_UNPUBLISHED,        LEVEL_ANY  },
300 		/* Delayed MARC Authority elements */
301 		{ "thesis",                    TYPE_THESIS,             LEVEL_ANY  },
302 		{ "periodical",                TYPE_MAGARTICLE,         LEVEL_ANY  },
303 	};
304 	int ngenre_matches = sizeof( genre_matches ) / sizeof( genre_matches[0] );
305 
306 	match_type resource_matches[] = {
307 		{ "moving image",              TYPE_FILMBROADCAST,      LEVEL_ANY  },
308 		{ "software, multimedia",      TYPE_PROGRAM,            LEVEL_ANY  },
309 	};
310 	int nresource_matches = sizeof( resource_matches ) / sizeof( resource_matches[0] );
311 
312 	match_type issuance_matches[] = {
313 		{ "monographic",               TYPE_BOOK,               LEVEL_MAIN },
314 		{ "monographic",               TYPE_INBOOK,             LEVEL_ANY  },
315 	};
316 	int nissuance_matches = sizeof( issuance_matches ) / sizeof( issuance_matches[0] );
317 
318 	int type;
319 
320 	type = type_from_mods_hints( in, TYPE_FROM_GENRE, genre_matches, ngenre_matches, TYPE_UNKNOWN );
321 	type_report_progress( p, "genre", type, refnum );
322 	if ( type!=TYPE_UNKNOWN ) return type;
323 
324 	type = type_from_mods_hints( in, TYPE_FROM_RESOURCE, resource_matches, nresource_matches, TYPE_UNKNOWN );
325 	type_report_progress( p, "resource", type, refnum );
326 	if ( type!=TYPE_UNKNOWN ) return type;
327 
328 	type = type_from_mods_hints( in, TYPE_FROM_ISSUANCE, issuance_matches, nissuance_matches, TYPE_UNKNOWN );
329 	type_report_progress( p, "issuance", type, refnum );
330 	if ( type!=TYPE_UNKNOWN ) return type;
331 
332 	return type_from_default( in, p, refnum );
333 }
334 
335 static void
append_type(int type,fields * out,param * p,int * status)336 append_type( int type, fields *out, param *p, int *status )
337 {
338 	/* These are restricted to Endnote-defined types */
339 	match_type genrenames[] = {
340 		{ "Generic",                TYPE_GENERIC },
341 		{ "Artwork",                TYPE_ARTWORK },
342 		{ "Audiovisual Material",   TYPE_AUDIOVISUAL },
343 		{ "Bill",                   TYPE_BILL },
344 		{ "Book",                   TYPE_BOOK },
345 		{ "Book Section",           TYPE_INBOOK },
346 		{ "Case",                   TYPE_CASE },
347 		{ "Chart or Table",         TYPE_CHARTTABLE },
348 		{ "Classical Work",         TYPE_CLASSICALWORK },
349 		{ "Computer Program",       TYPE_PROGRAM },
350 		{ "Conference Paper",       TYPE_INPROCEEDINGS },
351 		{ "Conference Proceedings", TYPE_PROCEEDINGS },
352 		{ "Edited Book",            TYPE_EDITEDBOOK },
353 		{ "Equation",               TYPE_EQUATION },
354 		{ "Electronic Article",     TYPE_ELECTRONICARTICLE },
355 		{ "Electronic Book",        TYPE_ELECTRONICBOOK },
356 		{ "Electronic Source",      TYPE_ELECTRONIC },
357 		{ "Figure",                 TYPE_FIGURE },
358 		{ "Film or Broadcast",      TYPE_FILMBROADCAST },
359 		{ "Government Document",    TYPE_GOVERNMENT },
360 		{ "Hearing",                TYPE_HEARING },
361 		{ "Journal Article",        TYPE_ARTICLE },
362 		{ "Legal Rule/Regulation",  TYPE_LEGALRULE },
363 		{ "Magazine Article",       TYPE_MAGARTICLE },
364 		{ "Manuscript",             TYPE_MANUSCRIPT },
365 		{ "Map",                    TYPE_MAP },
366 		{ "Newspaper Article",      TYPE_NEWSARTICLE },
367 		{ "Online Database",        TYPE_ONLINEDATABASE },
368 		{ "Online Multimedia",      TYPE_ONLINEMULTIMEDIA },
369 		{ "Patent",                 TYPE_PATENT },
370 		{ "Personal Communication", TYPE_COMMUNICATION },
371 		{ "Report",                 TYPE_REPORT },
372 		{ "Statute",                TYPE_STATUTE },
373 		{ "Thesis",                 TYPE_THESIS },
374 		{ "Thesis",                 TYPE_PHDTHESIS },
375 		{ "Thesis",                 TYPE_MASTERSTHESIS },
376 		{ "Thesis",                 TYPE_DIPLOMATHESIS },
377 		{ "Thesis",                 TYPE_DOCTORALTHESIS },
378 		{ "Thesis",                 TYPE_HABILITATIONTHESIS },
379 		{ "Unpublished Work",       TYPE_UNPUBLISHED },
380 	};
381 	int ngenrenames = sizeof( genrenames ) / sizeof( genrenames[0] );
382 	int i, fstatus, found = 0;
383 	for ( i=0; i<ngenrenames && !found; ++i ) {
384 		if ( genrenames[i].type == type ) {
385 			fstatus = fields_add( out, "%0", genrenames[i].name, LEVEL_MAIN );
386 			if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
387 			found = 1;
388 		}
389 	}
390 	if ( !found ) {
391 		fstatus = fields_add( out, "%0", "Generic", LEVEL_MAIN );
392 		if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
393 		// Patch: Disable output logging
394 	}
395 }
396 
397 static int
append_title(fields * in,char * full,char * sub,char * endtag,int level,fields * out,int * status)398 append_title( fields *in, char *full, char *sub, char *endtag,
399 		int level, fields *out, int *status )
400 {
401 	str *mainttl = fields_findv( in, level, FIELDS_STRP, full );
402 	str *subttl  = fields_findv( in, level, FIELDS_STRP, sub );
403 	str fullttl;
404 	int fstatus;
405 
406 	str_init( &fullttl );
407 	title_combine( &fullttl, mainttl, subttl );
408 
409 	if ( str_memerr( &fullttl ) ) {
410 		*status = BIBL_ERR_MEMERR;
411 		goto out;
412 	}
413 
414 	if ( str_has_value( &fullttl ) ) {
415 		fstatus = fields_add( out, endtag, str_cstr( &fullttl ), LEVEL_MAIN );
416 		if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
417 	}
418 out:
419 	str_free( &fullttl );
420 	return 1;
421 }
422 
423 static void
append_people(fields * in,char * tag,char * entag,int level,fields * out,int * status)424 append_people( fields *in, char *tag, char *entag, int level, fields *out, int *status )
425 {
426 	int i, n, flvl, fstatus;
427 	str oneperson;
428 	char *ftag;
429 
430 	str_init( &oneperson );
431 	n = fields_num( in );
432 	for ( i=0; i<n; ++i ) {
433 		flvl = fields_level( in, i );
434 		if ( level!=LEVEL_ANY && flvl!=level ) continue;
435 		ftag = fields_tag( in, i, FIELDS_CHRP );
436 		if ( !strcasecmp( ftag, tag ) ) {
437 			name_build_withcomma( &oneperson, fields_value( in, i, FIELDS_CHRP ) );
438 			fstatus = fields_add_can_dup( out, entag, str_cstr( &oneperson ), LEVEL_MAIN );
439 			if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
440 		}
441 	}
442 	str_free( &oneperson );
443 }
444 
445 static void
append_pages(fields * in,fields * out,int * status)446 append_pages( fields *in, fields *out, int *status )
447 {
448 	str *sn, *en;
449 	int fstatus;
450 	str pages;
451 	char *ar;
452 
453 	sn = fields_findv( in, LEVEL_ANY, FIELDS_STRP, "PAGES:START" );
454 	en = fields_findv( in, LEVEL_ANY, FIELDS_STRP, "PAGES:STOP" );
455 	if ( sn || en ) {
456 		str_init( &pages );
457 		if ( sn ) str_strcpy( &pages, sn );
458 		if ( sn && en ) str_strcatc( &pages, "-" );
459 		if ( en ) str_strcat( &pages, en );
460 		if ( str_memerr( &pages ) ) { *status = BIBL_ERR_MEMERR; str_free( &pages ); return; }
461 		fstatus = fields_add( out, "%P", str_cstr( &pages ), LEVEL_MAIN );
462 		if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
463 		str_free( &pages );
464 	} else {
465 		ar = fields_findv( in, LEVEL_ANY, FIELDS_CHRP, "ARTICLENUMBER" );
466 		if ( ar ) {
467 			fstatus = fields_add( out, "%P", ar, LEVEL_MAIN );
468 			if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
469 		}
470 	}
471 }
472 
473 static void
append_urls(fields * in,fields * out,int * status)474 append_urls( fields *in, fields *out, int *status )
475 {
476 	int lstatus;
477 	slist types;
478 
479 	lstatus = slist_init_valuesc( &types, "URL", "DOI", "PMID", "PMC", "ARXIV", "JSTOR", "MRNUMBER", NULL );
480 	if ( lstatus!=SLIST_OK ) {
481 		*status = BIBL_ERR_MEMERR;
482 		return;
483 	}
484 
485 	*status = urls_merge_and_add( in, LEVEL_ANY, out, "%U", LEVEL_MAIN, &types );
486 
487 	slist_free( &types );
488 }
489 
490 static void
append_year(fields * in,fields * out,int * status)491 append_year( fields *in, fields *out, int *status )
492 {
493 	int fstatus;
494 	char *year;
495 
496 	year = fields_findv_firstof( in, LEVEL_ANY, FIELDS_CHRP, "DATE:YEAR", "PARTDATE:YEAR", NULL );
497 	if ( year ) {
498 		fstatus = fields_add( out, "%D", year, LEVEL_MAIN );
499 		if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
500 	}
501 }
502 
503 static void
append_monthday(fields * in,fields * out,int * status)504 append_monthday( fields *in, fields *out, int *status )
505 {
506 	char *months[12] = { "January", "February", "March", "April",
507 		"May", "June", "July", "August", "September", "October",
508 		"November", "December" };
509 	char *month, *day;
510 	int m, fstatus;
511 	str monday;
512 
513 	str_init( &monday );
514 	month = fields_findv_firstof( in, LEVEL_ANY, FIELDS_CHRP, "DATE:MONTH", "PARTDATE:MONTH", NULL );
515 	day   = fields_findv_firstof( in, LEVEL_ANY, FIELDS_CHRP, "DATE:DAY",   "PARTDATE:DAY",   NULL );
516 	if ( month || day ) {
517 		if ( month ) {
518 			m = atoi( month );
519 			if ( m>0 && m<13 ) str_strcpyc( &monday, months[m-1] );
520 			else str_strcpyc( &monday, month );
521 		}
522 		if ( month && day ) str_strcatc( &monday, " " );
523 		if ( day ) str_strcatc( &monday, day );
524 		fstatus = fields_add( out, "%8", str_cstr( &monday ), LEVEL_MAIN );
525 		if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
526 	}
527 	str_free( &monday );
528 }
529 
530 static void
append_genrehint(int type,fields * out,vplist * a,int * status)531 append_genrehint( int type, fields *out, vplist *a, int *status )
532 {
533 	vplist_index i;
534 	int fstatus;
535 	char *g;
536 
537 	for ( i=0; i<a->n; ++i ) {
538 		g = ( char * ) vplist_get( a, i );
539 		if ( !strcmp( g, "journal article" ) && type==TYPE_ARTICLE ) continue;
540 		if ( !strcmp( g, "academic journal" ) && type==TYPE_ARTICLE ) continue;
541 		if ( !strcmp( g, "collection" ) && type==TYPE_INBOOK ) continue;
542 		if ( !strcmp( g, "television broadcast" ) && type==TYPE_FILMBROADCAST ) continue;
543 		if ( !strcmp( g, "electronic" ) && type==TYPE_PROGRAM ) continue;
544 		if ( !strcmp( g, "magazine" ) && type==TYPE_MAGARTICLE ) continue;
545 		if ( !strcmp( g, "miscellaneous" ) && type==TYPE_GENERIC ) continue;
546 		if ( !strcmp( g, "hearing" ) && type==TYPE_HEARING ) continue;
547 		if ( !strcmp( g, "communication" ) && type==TYPE_COMMUNICATION ) continue;
548 		if ( !strcmp( g, "report" ) && type==TYPE_REPORT ) continue;
549 		if ( !strcmp( g, "book chapter" ) && type==TYPE_INBOOK ) continue;
550 		fstatus = fields_add( out, "%9", g, LEVEL_MAIN );
551 		if ( fstatus!=FIELDS_OK ) {
552 			*status = BIBL_ERR_MEMERR;
553 			return;
554 		}
555 	}
556 }
557 
558 static void
append_all_genrehint(int type,fields * in,fields * out,int * status)559 append_all_genrehint( int type, fields *in, fields *out, int *status )
560 {
561 	vplist a;
562 
563 	vplist_init( &a );
564 
565 	fields_findv_each( in, LEVEL_ANY, FIELDS_CHRP, &a, "GENRE:BIBUTILS" );
566 	append_genrehint( type, out, &a, status );
567 
568 	vplist_empty( &a );
569 
570 	fields_findv_each( in, LEVEL_ANY, FIELDS_CHRP, &a, "GENRE:UNKNOWN" );
571 	append_genrehint( type, out, &a, status );
572 
573 	vplist_free( &a );
574 }
575 
576 static void
append_thesishint(int type,fields * out,int * status)577 append_thesishint( int type, fields *out, int *status )
578 {
579 	int fstatus;
580 
581 	if ( type==TYPE_MASTERSTHESIS ) {
582 		fstatus = fields_add( out, "%9", "Masters thesis", LEVEL_MAIN );
583 		if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
584 	}
585 	else if ( type==TYPE_PHDTHESIS ) {
586 		fstatus = fields_add( out, "%9", "Ph.D. thesis", LEVEL_MAIN );
587 		if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
588 	}
589 	else if ( type==TYPE_DIPLOMATHESIS ) {
590 		fstatus = fields_add( out, "%9", "Diploma thesis", LEVEL_MAIN );
591 		if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
592 	}
593 	else if ( type==TYPE_DOCTORALTHESIS ) {
594 		fstatus = fields_add( out, "%9", "Doctoral thesis", LEVEL_MAIN );
595 		if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
596 	}
597 	else if ( type==TYPE_HABILITATIONTHESIS ) {
598 		fstatus = fields_add( out, "%9", "Habilitation thesis", LEVEL_MAIN );
599 		if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
600 	}
601 	else if ( type==TYPE_LICENTIATETHESIS ) {
602 		fstatus = fields_add( out, "%9", "Licentiate thesis", LEVEL_MAIN );
603 		if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
604 	}
605 }
606 
607 static void
append_easyall(fields * in,char * tag,char * entag,int level,fields * out,int * status)608 append_easyall( fields *in, char *tag, char *entag, int level, fields *out, int *status )
609 {
610 	vplist_index i;
611 	int fstatus;
612 	vplist a;
613 	vplist_init( &a );
614 	fields_findv_each( in, level, FIELDS_CHRP, &a, tag );
615 	for ( i=0; i<a.n; ++i ) {
616 		fstatus = fields_add( out, entag, (char *) vplist_get( &a, i ), LEVEL_MAIN );
617 		if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
618 	}
619 	vplist_free( &a );
620 }
621 
622 static void
append_easy(fields * in,char * tag,char * entag,int level,fields * out,int * status)623 append_easy( fields *in, char *tag, char *entag, int level, fields *out, int *status )
624 {
625 	char *value;
626 	int fstatus;
627 
628 	value = fields_findv( in, level, FIELDS_CHRP, tag );
629 	if ( value ) {
630 		fstatus = fields_add( out, entag, value, LEVEL_MAIN );
631 		if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
632 	}
633 }
634 
635 static int
endout_assemble(fields * in,fields * out,param * pm,unsigned long refnum)636 endout_assemble( fields *in, fields *out, param *pm, unsigned long refnum )
637 {
638 	int added, type, status = BIBL_OK;
639 
640 	fields_clear_used( in );
641 
642 	type = get_type( in, pm, refnum );
643 
644 	append_type( type, out, pm, &status );
645 
646 	added = append_title( in, "TITLE",      "SUBTITLE",      "%T", LEVEL_MAIN, out, &status );
647 	if ( added==0 ) append_title( in, "SHORTTITLE", "SHORTSUBTITLE", "%T", LEVEL_MAIN, out, &status );
648 	else            append_title( in, "SHORTTITLE", "SHORTSUBTITLE", "%!", LEVEL_MAIN, out, &status );
649 
650 	append_people( in, "AUTHOR",     "%A", LEVEL_MAIN, out, &status );
651 	append_people( in, "EDITOR",     "%E", LEVEL_MAIN, out, &status );
652 	if ( type==TYPE_ARTICLE || type==TYPE_MAGARTICLE || type==TYPE_ELECTRONICARTICLE || type==TYPE_NEWSARTICLE )
653 		append_people( in, "EDITOR", "%E", LEVEL_HOST, out, &status );
654 	else if ( type==TYPE_INBOOK || type==TYPE_INPROCEEDINGS ) {
655 		append_people( in, "EDITOR", "%E", LEVEL_HOST, out, &status );
656 	} else {
657 		append_people( in, "EDITOR", "%Y", LEVEL_HOST, out, &status );
658 	}
659 	append_people( in, "TRANSLATOR", "%H", LEVEL_ANY,    out, &status  );
660 
661 	append_people( in, "AUTHOR",     "%Y", LEVEL_SERIES, out, &status );
662 	append_people( in, "EDITOR",     "%Y", LEVEL_SERIES, out, &status );
663 
664 	if ( type==TYPE_CASE ) {
665 		append_easy(    in, "AUTHOR:CORP", "%I", LEVEL_MAIN, out, &status );
666 		append_easy(    in, "AUTHOR:ASIS", "%I", LEVEL_MAIN, out, &status );
667 	}
668 	else if ( type==TYPE_HEARING ) {
669 		append_easyall( in, "AUTHOR:CORP", "%S", LEVEL_MAIN, out, &status );
670 		append_easyall( in, "AUTHOR:ASIS", "%S", LEVEL_MAIN, out, &status );
671 	}
672 	else if ( type==TYPE_NEWSARTICLE ) {
673 		append_people(  in, "REPORTER",        "%A", LEVEL_MAIN, out, &status );
674 		append_people(  in, "REPORTER:CORP",   "%A", LEVEL_MAIN, out, &status );
675 		append_people(  in, "REPORTER:ASIS",   "%A", LEVEL_MAIN, out, &status );
676 	}
677 	else if ( type==TYPE_COMMUNICATION ) {
678 		append_people(  in, "ADDRESSEE",       "%E", LEVEL_ANY,  out, &status  );
679 		append_people(  in, "ADDRESSEE:CORP",  "%E", LEVEL_ANY,  out, &status  );
680 		append_people(  in, "ADDRESSEE:ASIS",  "%E", LEVEL_ANY,  out, &status  );
681 	}
682 	else {
683 		append_easyall( in, "AUTHOR:CORP",     "%A", LEVEL_MAIN, out, &status );
684 		append_easyall( in, "AUTHOR:ASIS",     "%A", LEVEL_MAIN, out, &status );
685 		append_easyall( in, "EDITOR:CORP",     "%E", LEVEL_ANY,  out, &status  );
686 		append_easyall( in, "EDITOR:ASIS",     "%E", LEVEL_ANY,  out, &status  );
687 		append_easyall( in, "TRANSLATOR:CORP", "%H", LEVEL_ANY,  out, &status  );
688 		append_easyall( in, "TRANSLATOR:ASIS", "%H", LEVEL_ANY,  out, &status  );
689 	}
690 
691 	if ( type==TYPE_ARTICLE || type==TYPE_MAGARTICLE || type==TYPE_ELECTRONICARTICLE || type==TYPE_NEWSARTICLE ) {
692 		added = append_title( in, "TITLE", "SUBTITLE", "%J", LEVEL_HOST, out, &status );
693 		if ( added==0 ) append_title( in, "SHORTTITLE", "SHORTSUBTITLE", "%J", LEVEL_HOST, out, &status );
694 	}
695 
696 	else if ( type==TYPE_INBOOK || type==TYPE_INPROCEEDINGS ) {
697 		added = append_title( in, "TITLE", "SUBTITLE", "%B", LEVEL_HOST, out, &status );
698 		if ( added==0 ) append_title( in, "SHORTTITLE", "SHORTSUBTITLE", "%B", LEVEL_HOST, out, &status );
699 	}
700 
701 	else {
702 		added = append_title( in, "TITLE", "SUBTITLE", "%S", LEVEL_HOST, out, &status );
703 		if ( added==0 ) append_title( in, "SHORTTITLE", "SHORTSUBTITLE", "%S", LEVEL_HOST, out, &status );
704 	}
705 
706 	if ( type!=TYPE_CASE && type!=TYPE_HEARING ) {
707 		append_title( in, "TITLE", "SUBTITLE", "%S", LEVEL_SERIES, out, &status );
708 	}
709 
710 	append_year    ( in, out, &status );
711 	append_monthday( in, out, &status );
712 
713 	append_easy    ( in, "VOLUME",             "%V", LEVEL_ANY, out, &status );
714 	append_easy    ( in, "ISSUE",              "%N", LEVEL_ANY, out, &status );
715 	append_easy    ( in, "NUMBER",             "%N", LEVEL_ANY, out, &status );
716 	append_easy    ( in, "EDITION",            "%7", LEVEL_ANY, out, &status );
717 	append_easy    ( in, "PUBLISHER",          "%I", LEVEL_ANY, out, &status );
718 	append_easy    ( in, "ADDRESS",            "%C", LEVEL_ANY, out, &status );
719 	append_easy    ( in, "DEGREEGRANTOR",      "%C", LEVEL_ANY, out, &status );
720 	append_easy    ( in, "DEGREEGRANTOR:CORP", "%C", LEVEL_ANY, out, &status );
721 	append_easy    ( in, "DEGREEGRANTOR:ASIS", "%C", LEVEL_ANY, out, &status );
722 	append_easy    ( in, "SERIALNUMBER",       "%@", LEVEL_ANY, out, &status );
723 	append_easy    ( in, "ISSN",               "%@", LEVEL_ANY, out, &status );
724 	append_easy    ( in, "ISBN",               "%@", LEVEL_ANY, out, &status );
725 	append_easy    ( in, "LANGUAGE",           "%G", LEVEL_ANY, out, &status );
726 	append_easy    ( in, "REFNUM",             "%F", LEVEL_ANY, out, &status );
727 	append_easyall ( in, "NOTES",              "%O", LEVEL_ANY, out, &status );
728 	append_easy    ( in, "ABSTRACT",           "%X", LEVEL_ANY, out, &status );
729 	append_easy    ( in, "CLASSIFICATION"   ,  "%L", LEVEL_ANY, out, &status );
730 	append_easyall ( in, "KEYWORD",            "%K", LEVEL_ANY, out, &status );
731 	append_all_genrehint(  type, in, out, &status );
732 	append_thesishint( type, out, &status );
733 	append_easyall ( in, "DOI",                "%R", LEVEL_ANY, out, &status );
734 	append_easyall ( in, "URL",                "%U", LEVEL_ANY, out, &status );
735 	append_easyall ( in, "FILEATTACH",         "%U", LEVEL_ANY, out, &status );
736 	append_urls    ( in, out, &status );
737 	append_pages   ( in, out, &status );
738 
739 	return status;
740 }
741 
742 /*****************************************************
743  PUBLIC: int endout_write()
744 *****************************************************/
745 
746 static int
endout_write(fields * out,FILE * fp,param * pm,unsigned long refnum)747 endout_write( fields *out, FILE *fp, param *pm, unsigned long refnum )
748 {
749 	int i;
750 
751 	for ( i=0; i<out->n; ++i ) {
752 		fprintf( fp, "%s %s\n",
753 			(char*) fields_tag( out, i, FIELDS_CHRP ),
754 			(char*) fields_value( out, i, FIELDS_CHRP )
755 		);
756 	}
757 
758 	fprintf( fp, "\n" );
759 	fflush( fp );
760 	return BIBL_OK;
761 }
762