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