1 /*
2  * isiout.c
3  *
4  * Copyright (c) Chris Putnam 2008-2020
5  *
6  * Source code released under the GPL version 2
7  *
8  */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include "bibformats.h"
13 #include "bibutils.h"
14 #include "fields.h"
15 #include "generic.h"
16 #include "str.h"
17 #include "title.h"
18 #include "type.h"
19 #include "utf8.h"
20 
21 /*****************************************************
22  PUBLIC: int isiout_initparams()
23 *****************************************************/
24 
25 static int  isiout_write( fields *info, FILE *fp, param *p, unsigned long refnum );
26 static int  isiout_assemble( fields *in, fields *out, param *pm, unsigned long refnum );
27 
28 int
isiout_initparams(param * pm,const char * progname)29 isiout_initparams( param *pm, const char *progname )
30 {
31 	pm->writeformat      = BIBL_ISIOUT;
32 	pm->format_opts      = 0;
33 	pm->charsetout       = BIBL_CHARSET_DEFAULT;
34 	pm->charsetout_src   = BIBL_SRC_DEFAULT;
35 	pm->latexout         = 0;
36 	pm->utf8out          = BIBL_CHARSET_UTF8_DEFAULT;
37 	pm->utf8bom          = BIBL_CHARSET_BOM_DEFAULT;
38 	pm->xmlout           = BIBL_XMLOUT_FALSE;
39 	pm->nosplittitle     = 0;
40 	pm->verbose          = 0;
41 	pm->addcount         = 0;
42 	pm->singlerefperfile = 0;
43 
44 	if ( pm->charsetout == BIBL_CHARSET_UNICODE ) {
45 		pm->utf8out = pm->utf8bom = 1;
46 	}
47 
48 	pm->headerf   = generic_writeheader;
49 	pm->footerf   = NULL;
50 	pm->assemblef = isiout_assemble;
51 	pm->writef    = isiout_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 isiout_assemble()
66 *****************************************************/
67 
68 enum {
69         TYPE_UNKNOWN = 0,
70         TYPE_ARTICLE = 1,
71         TYPE_INBOOK  = 2,
72         TYPE_BOOK    = 3,
73 };
74 
75 static int
get_type(fields * in)76 get_type( fields *in )
77 {
78 	match_type genre_matches[] = {
79 		{ "periodical",         TYPE_ARTICLE,        LEVEL_ANY  },
80 		{ "academic journal",   TYPE_ARTICLE,        LEVEL_ANY  },
81 		{ "journal article",    TYPE_ARTICLE,        LEVEL_ANY  },
82 		{ "book",               TYPE_BOOK,           LEVEL_MAIN },
83 		{ "book",               TYPE_INBOOK,         LEVEL_ANY  },
84 		{ "book chapter",       TYPE_INBOOK,         LEVEL_ANY  },
85 		{ "collection",         TYPE_BOOK,           LEVEL_MAIN },
86 		{ "collection",         TYPE_INBOOK,         LEVEL_ANY  },
87 	};
88 
89 	int ngenre_matches = sizeof( genre_matches ) / sizeof( genre_matches[0] );
90 
91 	match_type issuance_matches[] = {
92 		{ "monographic",        TYPE_BOOK,           LEVEL_MAIN },
93 		{ "monographic",        TYPE_INBOOK,         LEVEL_ANY  },
94 	};
95 	int nissuance_matches = sizeof( issuance_matches ) / sizeof( issuance_matches[0] );
96 
97 	int type;
98 
99 	type = type_from_mods_hints( in, TYPE_FROM_GENRE, genre_matches, ngenre_matches, TYPE_UNKNOWN );
100 	if ( type!=TYPE_UNKNOWN ) return type;
101 
102 	return type_from_mods_hints( in, TYPE_FROM_ISSUANCE, issuance_matches, nissuance_matches, TYPE_UNKNOWN );
103 }
104 
105 static void
append_type(int type,fields * out,int * status)106 append_type( int type, fields *out, int *status )
107 {
108 	int fstatus;
109 	char *s;
110 
111 	switch( type ) {
112 		case TYPE_ARTICLE: s = "Journal"; break;
113 		case TYPE_INBOOK:  s = "Chapter"; break;
114 		case TYPE_BOOK:    s = "Book";    break;
115 		default:           s = "Unknown"; break;
116 	}
117 
118 	fstatus = fields_add( out, "PT", s, LEVEL_MAIN );
119 	if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
120 }
121 
122 static void
append_titlecore(fields * in,char * isitag,int level,char * maintag,char * subtag,fields * out,int * status)123 append_titlecore( fields *in, char *isitag, int level, char *maintag, char *subtag, fields *out, int *status )
124 {
125 	str *mainttl = fields_findv( in, level, FIELDS_STRP, maintag );
126 	str *subttl  = fields_findv( in, level, FIELDS_STRP, subtag );
127 	str fullttl;
128 	int fstatus;
129 
130 	str_init( &fullttl );
131 	title_combine( &fullttl, mainttl, subttl );
132 
133 	if ( str_memerr( &fullttl ) ) {
134 		*status = BIBL_ERR_MEMERR;
135 		goto out;
136 	}
137 
138 	if ( str_has_value( &fullttl ) ) {
139 		fstatus = fields_add( out, isitag, str_cstr( &fullttl ), LEVEL_MAIN );
140 		if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
141 	}
142 out:
143 	str_free( &fullttl );
144 }
145 
146 static void
append_title(fields * in,char * isitag,int level,fields * out,int * status)147 append_title( fields *in, char *isitag, int level, fields *out, int *status )
148 {
149 	append_titlecore( in, isitag, level, "TITLE", "SUBTITLE", out, status );
150 }
151 
152 static void
append_abbrtitle(fields * in,char * isitag,int level,fields * out,int * status)153 append_abbrtitle( fields *in, char *isitag, int level, fields *out, int *status )
154 {
155 	append_titlecore( in, isitag, level, "SHORTTITLE", "SHORTSUBTITLE", out, status );
156 }
157 
158 static void
append_keywords(fields * in,fields * out,int * status)159 append_keywords( fields *in, fields *out, int *status )
160 {
161 	vplist_index i;
162 	str keywords;
163 	int fstatus;
164 	vplist kw;
165 
166 	str_init( &keywords );
167 	vplist_init( &kw );
168 
169 	fields_findv_each( in, LEVEL_ANY, FIELDS_STRP, &kw, "KEYWORD" );
170 	if ( kw.n ) {
171 		for ( i=0; i<kw.n; ++i ) {
172 			if ( i>0 ) str_strcatc( &keywords, "; " );
173 			str_strcat( &keywords, (str *) vplist_get( &kw, i ) );
174 		}
175 		if ( str_memerr( &keywords ) ) { *status = BIBL_ERR_MEMERR; goto out; }
176 		fstatus = fields_add( out, "DE", str_cstr( &keywords ), LEVEL_MAIN );
177 		if ( fstatus!=FIELDS_OK ) { *status = BIBL_ERR_MEMERR; goto out; }
178 	}
179 out:
180 	vplist_free( &kw );
181 	str_free( &keywords );
182 }
183 
184 static void
process_person(str * person,char * name)185 process_person( str *person, char *name )
186 {
187 	str family, given, suffix;
188 	char *p = name;
189 
190 	str_empty( person );
191 
192 	strs_init( &family, &given, &suffix, NULL );
193 
194 	while ( *p && *p!='|' )
195 		str_addchar( &family, *p++ );
196 
197 	while ( *p=='|' && *(p+1)!='|' ) {
198 		p++;
199 		// 2021-12-06 :TODO: Georgi
200 		//    so, only the first letter of the given name is kept, the rest skipped;
201 		// see Org/isiout_bug.txt for details.
202                 //
203                 // Crude patch, was:
204 		//     if ( *p!='|' ) str_addchar( &given, *p++ );
205 		//     while ( *p && *p!='|' ) p++;
206 		if ( *p!='|' ) {
207 		  if( (*p & 128) == 0) { // ascii
208 		    str_addchar( &given, *p++);
209 		  } else { // not ascii
210 		    // Georgi TODO: do this properly.
211 		    //
212 		    // this will be ok if the following character is ascii
213 		    // but it will emit all char's up to the first ascii one
214 		    while ( *p && (*p & 128) ) str_addchar( &given, *p++);
215 		  }
216 		  while ( *p && *p!='|' ) p++;
217 		}
218 
219 	}
220 
221 	if ( *p=='|' && *(p+1)=='|' ) {
222 		p += 2;
223 		while ( *p && *p!='|' ) str_addchar( &suffix, *p++ );
224 	}
225 
226 	if ( str_has_value( &family ) ) str_strcat( person, &family );
227 	if ( str_has_value( &suffix ) ) {
228 		if ( str_has_value( &family ) ) str_strcatc( person, " " );
229 		str_strcat( person, &suffix );
230 	}
231 	if ( str_has_value( &given ) ) {
232 		if ( str_has_value( person ) ) str_strcatc( person, ", " );
233 		str_strcat( person, &given );
234 	}
235 
236 	strs_free( &family, &given, &suffix, NULL );
237 }
238 
239 static void
append_people(fields * f,char * tag,char * isitag,int level,fields * out,int * status)240 append_people( fields *f, char *tag, char *isitag, int level, fields *out, int *status )
241 {
242 	vplist_index i;
243 	vplist people;
244 	str person;
245 	int fstatus;
246 
247 	str_init( &person );
248 	vplist_init( &people );
249 
250 	fields_findv_each( f, level, FIELDS_CHRP, &people, tag );
251 	for ( i=0; i<people.n; ++i ) {
252 		process_person( &person, (char *)vplist_get( &people, i ) );
253 		if ( str_memerr( &person ) ) { *status = BIBL_ERR_MEMERR; goto out; }
254 		if ( i==0 ) fstatus = fields_add_can_dup( out, isitag, str_cstr( &person ), LEVEL_MAIN );
255 		else        fstatus = fields_add_can_dup( out, "  ",   str_cstr( &person ), LEVEL_MAIN );
256 		if ( fstatus!=FIELDS_OK ) { *status = BIBL_ERR_MEMERR; goto out; }
257 	}
258 
259 out:
260 	vplist_free( &people );
261 	str_free( &person );
262 }
263 
264 static void
append_easy(fields * in,char * tag,char * isitag,int level,fields * out,int * status)265 append_easy( fields *in, char *tag, char *isitag, int level, fields *out, int *status )
266 {
267 	char *value;
268 	int fstatus;
269 
270 	value = fields_findv( in, level, FIELDS_CHRP, tag );
271 	if ( value ) {
272 		fstatus = fields_add( out, isitag, value, LEVEL_MAIN );
273 		if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
274 	}
275 }
276 
277 static void
append_easyall(fields * in,char * tag,char * isitag,int level,fields * out,int * status)278 append_easyall( fields *in, char *tag, char *isitag, int level, fields *out, int *status )
279 {
280 	vplist_index i;
281 	int fstatus;
282 	vplist a;
283 
284 	vplist_init( &a );
285 	fields_findv_each( in, level, FIELDS_CHRP, &a, tag );
286 	for ( i=0; i<a.n; ++i ) {
287 		fstatus = fields_add( out, isitag, (char *) vplist_get( &a, i ), LEVEL_MAIN );
288 		if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
289 	}
290 	vplist_free( &a );
291 }
292 
293 static void
append_date(fields * in,fields * out,int * status)294 append_date( fields *in, fields *out, int *status )
295 {
296 	char *month, *year;
297 	int fstatus;
298 
299 	month = fields_findv_firstof( in, LEVEL_ANY, FIELDS_CHRP, "PARTDATE:MONTH", "DATE:MONTH", NULL );
300 	if ( month ) {
301 		fstatus = fields_add( out, "PD", month, LEVEL_MAIN );
302 		if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
303 	}
304 	year  = fields_findv_firstof( in, LEVEL_ANY, FIELDS_CHRP, "PARTDATE:YEAR",  "DATE:YEAR",  NULL );
305 	if ( year ) {
306 		fstatus = fields_add( out, "PY", year, LEVEL_MAIN );
307 		if ( fstatus!=FIELDS_OK ) *status = BIBL_ERR_MEMERR;
308 	}
309 }
310 
311 static int
isiout_assemble(fields * in,fields * out,param * pm,unsigned long refnum)312 isiout_assemble( fields *in, fields *out, param *pm, unsigned long refnum )
313 {
314 	int type, status = BIBL_OK;
315 
316 	type = get_type( in );
317 
318 	append_type   ( type, out, &status );
319 	append_people ( in, "AUTHOR",      "AU", LEVEL_MAIN, out, &status );
320 	append_easyall( in, "AUTHOR:CORP", "AU", LEVEL_MAIN, out, &status );
321 	append_easyall( in, "AUTHOR:ASIS", "AU", LEVEL_MAIN, out, &status );
322 
323 	append_title  ( in, "TI", LEVEL_MAIN, out, &status );
324 	if ( type==TYPE_ARTICLE ) {
325 		append_title    ( in, "SO", LEVEL_HOST,   out, &status );
326 		append_abbrtitle( in, "JI", LEVEL_HOST,   out, &status );
327 		append_title    ( in, "SE", LEVEL_SERIES, out, &status );
328 	} else if ( type==TYPE_INBOOK ) {
329 		append_title    ( in, "BT", LEVEL_HOST,   out, &status );
330 		append_title    ( in, "SE", LEVEL_SERIES, out, &status );
331 	} else { /* type==BOOK */
332 		append_title    ( in, "SE", LEVEL_HOST,   out, &status );
333 	}
334 
335 	append_date( in, out, &status );
336 
337 	append_easy( in, "PAGES:START",       "BP", LEVEL_ANY, out, &status );
338 	append_easy( in, "PAGES:STOP",        "EP", LEVEL_ANY, out, &status );
339 	append_easy( in, "ARTICLENUMBER",     "AR", LEVEL_ANY, out, &status );
340 	append_easy( in, "PAGES:TOTAL",       "PG", LEVEL_ANY, out, &status );
341 
342 	append_easy( in, "VOLUME",            "VL", LEVEL_ANY, out, &status );
343 	append_easy( in, "ISSUE",             "IS", LEVEL_ANY, out, &status );
344 	append_easy( in, "NUMBER",            "IS", LEVEL_ANY, out, &status );
345 	append_easy( in, "PUBLISHER",         "PU", LEVEL_ANY, out, &status );
346 	append_easy( in, "ADDRESS:PUBLISHER", "PA", LEVEL_ANY, out, &status );
347 	append_easy( in, "DOI",               "DI", LEVEL_ANY, out, &status );
348 	append_easy( in, "URL",               "WP", LEVEL_ANY, out, &status );
349 	append_easy( in, "ISIREFNUM",         "UT", LEVEL_ANY, out, &status );
350 	append_easy( in, "LANGUAGE",          "LA", LEVEL_ANY, out, &status );
351 	append_easy( in, "ISIDELIVERNUM",     "GA", LEVEL_ANY, out, &status );
352 	append_keywords( in, out, &status );
353 	append_easy( in, "ISBN",              "SN", LEVEL_ANY, out, &status );
354 	append_easy( in, "ISSN",              "SN", LEVEL_ANY, out, &status );
355 	append_easy( in, "ABSTRACT",          "AB", LEVEL_ANY, out, &status );
356 	append_easy( in, "TIMESCITED",        "TC", LEVEL_ANY, out, &status );
357 	append_easy( in, "NUMBERREFS",        "NR", LEVEL_ANY, out, &status );
358 	append_easy( in, "CITEDREFS",         "CR", LEVEL_ANY, out, &status );
359 	append_easy( in, "ADDRESS",           "PI", LEVEL_ANY, out, &status );
360 
361 	return status;
362 }
363 
364 /*****************************************************
365  PUBLIC: int isiout_write()
366 *****************************************************/
367 
368 static int
isiout_write(fields * out,FILE * fp,param * p,unsigned long refnum)369 isiout_write( fields *out, FILE *fp, param *p, unsigned long refnum )
370 {
371 	int i;
372 
373 	for ( i=0; i<out->n; ++i ) {
374 		fprintf( fp, "%s %s\n",
375 			( char * ) fields_tag  ( out, i, FIELDS_CHRP ),
376 			( char * ) fields_value( out, i, FIELDS_CHRP )
377 		);
378 	}
379         fprintf( fp, "ER\n\n" );
380         fflush( fp );
381 	return BIBL_OK;
382 }
383