/* * endout.c * * Copyright (c) Chris Putnam 2004-2010 * * Program and source code released under the GPL * */ #include #include #include #include #include "utf8.h" #include "newstr.h" #include "strsearch.h" #include "fields.h" #include "doi.h" #include "endout.h" void endout_initparams( param *p, const char *progname ) { p->writeformat = BIBL_ENDNOTEOUT; p->format_opts = 0; p->charsetout = BIBL_CHARSET_DEFAULT; p->charsetout_src = BIBL_SRC_DEFAULT; p->latexout = 0; p->utf8out = 0; p->utf8bom = 0; p->xmlout = 0; p->nosplittitle = 0; p->verbose = 0; p->addcount = 0; p->singlerefperfile = 0; p->headerf = endout_writeheader; p->footerf = NULL; p->writef = endout_write; } enum { TYPE_UNKNOWN = 0, TYPE_GENERIC, /* Generic */ TYPE_ARTWORK, /* Artwork */ TYPE_AUDIOVISUAL, /* Audiovisual Material */ TYPE_BILL, /* Bill */ TYPE_BOOK, /* Book */ TYPE_INBOOK, /* Book Section */ TYPE_CASE, /* Case */ TYPE_CHARTTABLE, /* Chart or Table */ TYPE_CLASSICALWORK, /* Classical Work */ TYPE_PROGRAM, /* Computer Program */ TYPE_INPROCEEDINGS, /* Conference Paper */ TYPE_PROCEEDINGS, /* Conference Proceedings */ TYPE_EDITEDBOOK, /* Edited Book */ TYPE_EQUATION, /* Equation */ TYPE_ELECTRONICARTICLE, /* Electronic Article */ TYPE_ELECTRONICBOOK, /* Electronic Book */ TYPE_ELECTRONIC, /* Electronic Source */ TYPE_FIGURE, /* Figure */ TYPE_FILMBROADCAST, /* Film or Broadcast */ TYPE_GOVERNMENT, /* Government Document */ TYPE_HEARING, /* Hearing */ TYPE_ARTICLE, /* Journal Article */ TYPE_LEGALRULE, /* Legal Rule/Regulation */ TYPE_MAGARTICLE, /* Magazine Article */ TYPE_MANUSCRIPT, /* Manuscript */ TYPE_MAP, /* Map */ TYPE_NEWSARTICLE, /* Newspaper Article */ TYPE_ONLINEDATABASE, /* Online Database */ TYPE_ONLINEMULTIMEDIA, /* Online Multimedia */ TYPE_PATENT, /* Patent */ TYPE_COMMUNICATION, /* Personal Communication */ TYPE_REPORT, /* Report */ TYPE_STATUTE, /* Statute */ TYPE_THESIS, /* Thesis */ TYPE_MASTERSTHESIS, /* Thesis */ TYPE_PHDTHESIS, /* Thesis */ TYPE_DIPLOMATHESIS, /* Thesis */ TYPE_DOCTORALTHESIS, /* Thesis */ TYPE_HABILITATIONTHESIS, /* Thesis */ TYPE_UNPUBLISHED, /* Unpublished Work */ }; typedef struct match_type { char *name; int type; } match_type; static int get_type( fields *info ) { /* Comment out TYPE_GENERIC entries as that is default, but * keep in source as record of mapping decision. */ match_type match_genres[] = { /* MARC Authority elements */ { "art original", TYPE_ARTWORK }, { "art reproduction", TYPE_ARTWORK }, { "article", TYPE_ARTICLE }, { "atlas", TYPE_MAP }, { "autobiography", TYPE_BOOK }, /* { "bibliography", TYPE_GENERIC },*/ { "biography", TYPE_BOOK }, { "book", TYPE_BOOK }, /* { "catalog", TYPE_GENERIC },*/ { "chart", TYPE_CHARTTABLE }, /* { "comic strip", TYPE_GENERIC },*/ { "conference publication", TYPE_PROCEEDINGS }, { "database", TYPE_ONLINEDATABASE }, /* { "dictionary", TYPE_GENERIC },*/ { "diorama", TYPE_ARTWORK }, /* { "directory", TYPE_GENERIC },*/ { "discography", TYPE_AUDIOVISUAL }, /* { "drama", TYPE_GENERIC },*/ { "encyclopedia", TYPE_BOOK }, /* { "essay", TYPE_GENERIC }, */ /* { "festschrift", TYPE_GENERIC },*/ { "fiction", TYPE_BOOK }, { "filmography", TYPE_FILMBROADCAST }, { "filmstrip", TYPE_FILMBROADCAST }, /* { "finding aid", TYPE_GENERIC },*/ /* { "flash card", TYPE_GENERIC },*/ { "folktale", TYPE_CLASSICALWORK }, { "font", TYPE_ELECTRONIC }, /* { "game", TYPE_GENERIC },*/ { "government publication", TYPE_GOVERNMENT }, { "graphic", TYPE_FIGURE }, { "globe", TYPE_MAP }, /* { "handbook", TYPE_GENERIC },*/ { "history", TYPE_BOOK }, { "hymnal", TYPE_BOOK }, /* { "humor, satire", TYPE_GENERIC },*/ /* { "index", TYPE_GENERIC },*/ /* { "instruction", TYPE_GENERIC },*/ /* { "interview", TYPE_GENERIC },*/ { "issue", TYPE_ARTICLE }, { "journal", TYPE_ARTICLE }, /* { "kit", TYPE_GENERIC },*/ /* { "language instruction", TYPE_GENERIC },*/ /* { "law report or digest", TYPE_GENERIC },*/ /* { "legal article", TYPE_GENERIC },*/ { "legal case and case notes", TYPE_CASE }, { "legislation", TYPE_BILL }, { "letter", TYPE_COMMUNICATION }, { "loose-leaf", TYPE_GENERIC }, { "map", TYPE_MAP }, /* { "memoir", TYPE_GENERIC },*/ /* { "microscope slide", TYPE_GENERIC },*/ /* { "model", TYPE_GENERIC },*/ { "motion picture", TYPE_AUDIOVISUAL }, { "multivolume monograph", TYPE_BOOK }, { "newspaper", TYPE_NEWSARTICLE }, { "novel", TYPE_BOOK }, /* { "numeric data", TYPE_GENERIC },*/ /* { "offprint", TYPE_GENERIC },*/ { "online system or service", TYPE_ELECTRONIC }, { "patent", TYPE_PATENT }, { "periodical", TYPE_MAGARTICLE }, { "picture", TYPE_ARTWORK }, /* { "poetry", TYPE_GENERIC },*/ { "programmed text", TYPE_PROGRAM }, /* { "realia", TYPE_GENERIC },*/ { "rehearsal", TYPE_AUDIOVISUAL }, /* { "remote sensing image", TYPE_GENERIC },*/ /* { "reporting", TYPE_GENERIC },*/ /* { "review", TYPE_GENERIC },*/ /* { "script", TYPE_GENERIC },*/ /* { "series", TYPE_GENERIC },*/ /* { "short story", TYPE_GENERIC },*/ /* { "slide", TYPE_GENERIC },*/ { "sound", TYPE_AUDIOVISUAL }, /* { "speech", TYPE_GENERIC },*/ /* { "statistics", TYPE_GENERIC },*/ /* { "survey of literature", TYPE_GENERIC },*/ { "technical drawing", TYPE_ARTWORK }, { "techincal report", TYPE_REPORT }, { "thesis", TYPE_THESIS }, /* { "toy", TYPE_GENERIC },*/ /* { "transparency", TYPE_GENERIC },*/ /* { "treaty", TYPE_GENERIC },*/ { "videorecording", TYPE_AUDIOVISUAL }, { "web site", TYPE_ELECTRONIC }, /* Non-MARC Authority elements */ { "academic journal", TYPE_ARTICLE }, { "magazine", TYPE_MAGARTICLE }, { "hearing", TYPE_HEARING }, { "Ph.D. thesis", TYPE_PHDTHESIS }, { "Masters thesis", TYPE_MASTERSTHESIS }, { "Diploma thesis", TYPE_DIPLOMATHESIS }, { "Doctoral thesis", TYPE_DOCTORALTHESIS }, { "Habilitation thesis", TYPE_HABILITATIONTHESIS }, { "communication", TYPE_COMMUNICATION }, { "manuscript", TYPE_MANUSCRIPT }, { "report", TYPE_REPORT }, { "unpublished", TYPE_UNPUBLISHED }, }; int nmatch_genres = sizeof( match_genres ) / sizeof( match_genres[0] ); char *tag, *data; int i, j, type = TYPE_UNKNOWN; for ( i=0; infields; ++i ) { tag = info->tag[i].data; if ( strcasecmp( tag, "GENRE" )!=0 && strcasecmp( tag, "NGENRE" )!=0 ) continue; data = info->data[i].data; for ( j=0; jlevel[i]==0 ) type = TYPE_BOOK; else type = TYPE_INBOOK; } else if ( !strcasecmp( data, "collection" ) ) { if ( info->level[i]==0 ) type = TYPE_BOOK; else type = TYPE_INBOOK; } if ( type!=TYPE_UNKNOWN ) fields_setused( info, i ); } /* the inbook type should be defined if 'book' in host */ if ( type==TYPE_BOOK && info->level[i]!=0 ) type = TYPE_INBOOK; /* the article types should be defined if it's the host */ if ( ( type==TYPE_ARTICLE || type==TYPE_MAGARTICLE || type==TYPE_NEWSARTICLE ) && info->level[i]<1 ) type=TYPE_UNKNOWN; } if ( type==TYPE_UNKNOWN ) { for ( i=0; infields; ++i ) { if ( strcasecmp( info->tag[i].data, "RESOURCE" ) ) continue; data = info->data[i].data; if ( !strcasecmp( data, "moving image" ) ) type = TYPE_FILMBROADCAST; else if ( !strcasecmp( data, "software, multimedia" ) ) type = TYPE_PROGRAM; if ( type!=TYPE_UNKNOWN ) fields_setused( info, i ); } } /* default to generic */ if ( type==TYPE_UNKNOWN ) type = TYPE_GENERIC; return type; } static void output_type( FILE *fp, int type, param *p ) { /* These are restricted to Endnote-defined types */ match_type genrenames[] = { { "Generic", TYPE_GENERIC }, { "Artwork", TYPE_ARTWORK }, { "Audiovisual Material", TYPE_AUDIOVISUAL }, { "Bill", TYPE_BILL }, { "Book", TYPE_BOOK }, { "Book Section", TYPE_INBOOK }, { "Case", TYPE_CASE }, { "Chart or Table", TYPE_CHARTTABLE }, { "Classical Work", TYPE_CLASSICALWORK }, { "Computer Program", TYPE_PROGRAM }, { "Conference Paper", TYPE_INPROCEEDINGS }, { "Conference Proceedings", TYPE_PROCEEDINGS }, { "Edited Book", TYPE_EDITEDBOOK }, { "Equation", TYPE_EQUATION }, { "Electronic Article", TYPE_ELECTRONICARTICLE }, { "Electronic Book", TYPE_ELECTRONICBOOK }, { "Electronic Source", TYPE_ELECTRONIC }, { "Figure", TYPE_FIGURE }, { "Film or Broadcast", TYPE_FILMBROADCAST }, { "Government Document", TYPE_GOVERNMENT }, { "Hearing", TYPE_HEARING }, { "Journal Article", TYPE_ARTICLE }, { "Legal Rule/Regulation", TYPE_LEGALRULE }, { "Magazine Article", TYPE_MAGARTICLE }, { "Manuscript", TYPE_MANUSCRIPT }, { "Map", TYPE_MAP }, { "Newspaper Article", TYPE_NEWSARTICLE }, { "Online Database", TYPE_ONLINEDATABASE }, { "Online Multimedia", TYPE_ONLINEMULTIMEDIA }, { "Patent", TYPE_PATENT }, { "Personal Communication", TYPE_COMMUNICATION }, { "Report", TYPE_REPORT }, { "Statute", TYPE_STATUTE }, { "Thesis", TYPE_THESIS }, { "Thesis", TYPE_PHDTHESIS }, { "Thesis", TYPE_MASTERSTHESIS }, { "Thesis", TYPE_DIPLOMATHESIS }, { "Thesis", TYPE_DOCTORALTHESIS }, { "Thesis", TYPE_HABILITATIONTHESIS }, { "Unpublished Work", TYPE_UNPUBLISHED }, }; int ngenrenames = sizeof( genrenames ) / sizeof( genrenames[0] ); int i, found = 0; fprintf( fp, "%%0 "); for ( i=0; iprogname ) fprintf( stderr, "%s: ", p->progname ); fprintf( stderr, "Cannot identify type %d\n", type ); } fprintf( fp, "\n" ); } static void output_title( FILE *fp, fields *info, char *full, char *sub, char *endtag, int level ) { int n1 = fields_find( info, full, level ); int n2 = fields_find( info, sub, level ); if ( n1!=-1 ) { fprintf( fp, "%s %s", endtag, info->data[n1].data ); fields_setused( info, n1 ); if ( n2!=-1 ) { if ( info->data[n1].data[info->data[n1].len]!='?' ) fprintf( fp, ": " ); else fprintf( fp, " " ); fprintf( fp, "%s", info->data[n2].data ); fields_setused( info, n2 ); } fprintf( fp, "\n" ); } } static void output_person( FILE *fp, char *p ) { int nseps = 0, nch; while ( *p ) { nch = 0; if ( nseps==1 ) fprintf( fp, "," ); if ( nseps ) fprintf( fp, " " ); while ( *p && *p!='|' ) { fprintf( fp, "%c", *p++ ); nch++; } if ( *p=='|' ) p++; if ( nseps!=0 && nch==1 ) fprintf( fp, "." ); nseps++; } } static void output_people( FILE *fp, fields *info, char *tag, char *entag, int level ) { int i; for ( i=0; infields; ++i ) { if ( level!=-1 && info->level[i]!=level ) continue; if ( !strcasecmp( info->tag[i].data, tag ) ) { fprintf( fp, "%s ", entag ); output_person( fp, info->data[i].data ); fprintf( fp, "\n" ); } } } static void output_pages( FILE *fp, fields *info ) { int sn = fields_find( info, "PAGESTART", -1 ); int en = fields_find( info, "PAGEEND", -1 ); int ar = fields_find( info, "ARTICLENUMBER", -1 ); if ( sn!=-1 || en!=-1 ) { fprintf( fp, "%%P "); if ( sn!=-1 ) fprintf( fp, "%s", info->data[sn].data ); if ( sn!=-1 && en!=-1 ) fprintf( fp, "-" ); if ( en!=-1 ) fprintf( fp, "%s", info->data[en].data ); fprintf( fp, "\n"); } else if ( ar!=-1 ) { fprintf( fp, "%%P %s\n", info->data[ar].data ); } } static void output_doi( FILE *fp, fields *info ) { newstr doi_url; int i; newstr_init( &doi_url ); for ( i=0; infields; ++i ) { if ( strcmp( info->tag[i].data, "DOI" ) ) continue; doi_to_url( info, i, "URL", &doi_url ); if ( doi_url.len ) fprintf( fp, "%%U %s\n", doi_url.data ); } newstr_free( &doi_url ); } static void output_pmid( FILE *fp, fields *info ) { newstr pmid_url; int i; newstr_init( &pmid_url ); for ( i=0; infields; ++i ) { if ( strcmp( info->tag[i].data, "PMID" ) ) continue; pmid_to_url( info, i, "URL", &pmid_url ); if ( pmid_url.len ) fprintf( fp, "%%U %s\n", pmid_url.data ); } newstr_free( &pmid_url ); } static void output_arxiv( FILE *fp, fields *info ) { newstr arxiv_url; int i; newstr_init( &arxiv_url ); for ( i=0; infields; ++i ) { if ( strcmp( info->tag[i].data, "ARXIV" ) ) continue; arxiv_to_url( info, i, "URL", &arxiv_url ); if ( arxiv_url.len ) fprintf( fp, "%%U %s\n", arxiv_url.data ); } newstr_free( &arxiv_url ); } static void output_jstor( FILE *fp, fields *info ) { newstr jstor_url; int i; newstr_init( &jstor_url ); for ( i=0; infields; ++i ) { if ( strcmp( info->tag[i].data, "JSTOR" ) ) continue; jstor_to_url( info, i, "URL", &jstor_url ); if ( jstor_url.len ) fprintf( fp, "%%U %s\n", jstor_url.data ); } newstr_free( &jstor_url ); } static void output_year( FILE *fp, fields *info, int level ) { int year = fields_find( info, "YEAR", level ); if ( year==-1 ) year = fields_find( info, "PARTYEAR", level ); if ( year!=-1 ) fprintf( fp, "%%D %s\n", info->data[year].data ); } static void output_monthday( FILE *fp, fields *info, int level ) { char *months[12] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; int m; int month = fields_find( info, "MONTH", level ); int day = fields_find( info, "DAY", level ); if ( month==-1 ) month = fields_find( info, "PARTMONTH", level ); if ( day==-1 ) day = fields_find( info, "PARTDAY", level ); if ( month!=-1 || day!=-1 ) { fprintf( fp, "%%8 " ); if ( month!=-1 ) { m = atoi( info->data[month].data ); if ( m>0 && m<13 ) fprintf( fp, "%s", months[m-1] ); else fprintf( fp, "%s", info->data[month].data ); } if ( month!=-1 && day!=-1 ) fprintf( fp, " " ); if ( day!=-1 ) fprintf( fp, "%s", info->data[day].data ); fprintf( fp, "\n" ); } } static void output_thesishint( FILE *fp, int type ) { if ( type==TYPE_MASTERSTHESIS ) fprintf( fp, "%%9 Masters thesis\n" ); else if ( type==TYPE_PHDTHESIS ) fprintf( fp, "%%9 Ph.D. thesis\n" ); else if ( type==TYPE_DIPLOMATHESIS ) fprintf( fp, "%%9 Diploma thesis\n" ); else if ( type==TYPE_DOCTORALTHESIS ) fprintf( fp, "%%9 Doctoral thesis\n" ); else if ( type==TYPE_HABILITATIONTHESIS ) fprintf( fp, "%%9 Habilitation thesis\n" ); } static void output_easyall( FILE *fp, fields *info, char *tag, char *entag, int level ) { int i; for ( i=0; infields; ++i ) { if ( level!=-1 && info->level[i]!=level ) continue; if ( !strcmp( info->tag[i].data, tag ) ) fprintf( fp, "%s %s\n", entag, info->data[i].data ); } } static void output_easy( FILE *fp, fields *info, char *tag, char *entag, int level ) { int n = fields_find( info, tag, level ); if ( n!=-1 ) fprintf( fp, "%s %s\n", entag, info->data[n].data ); } void endout_write( fields *info, FILE *fp, param *p, unsigned long refnum ) { int type; fields_clearused( info ); type = get_type( info ); output_type( fp, type, p ); output_title( fp, info, "TITLE", "SUBTITLE", "%T", 0 ); output_title( fp, info, "SHORTTITLE", "SHORTSUBTITLE", "%!", 0 ); output_people( fp, info, "AUTHOR", "%A", 0 ); output_people( fp, info, "EDITOR", "%E", -1 ); output_people( fp, info, "TRANSLATOR", "%H", -1 ); if ( type==TYPE_CASE ) output_easy( fp, info, "AUTHOR:CORP", "%I", 0 ); else if ( type==TYPE_HEARING ) output_easyall( fp, info, "AUTHOR:CORP", "%S", 0 ); else if ( type==TYPE_NEWSARTICLE ) output_people( fp, info, "REPORTER", "%A", 0 ); else if ( type==TYPE_COMMUNICATION ) output_people( fp, info, "RECIPIENT", "%E", -1 ); else { output_easyall( fp, info, "AUTHOR:CORP", "%A", 0 ); output_easyall( fp, info, "AUTHOR:ASIS", "%A", 0 ); output_easyall( fp, info, "EDITOR:CORP", "%E", -1 ); output_easyall( fp, info, "EDITOR:ASIS", "%E", -1 ); } if ( type==TYPE_ARTICLE || type==TYPE_MAGARTICLE ) output_title( fp, info, "TITLE", "SUBTITLE", "%J", 1 ); else output_title( fp, info, "TITLE", "SUBTITLE", "%B", 1 ); output_year( fp, info, -1 ); output_monthday( fp, info, -1 ); output_easy( fp, info, "VOLUME", "%V", -1 ); output_easy( fp, info, "ISSUE", "%N", -1 ); output_easy( fp, info, "NUMBER", "%N", -1 ); output_easy( fp, info, "EDITION", "%7", -1 ); output_easy( fp, info, "PUBLISHER", "%I", -1 ); output_easy( fp, info, "ADDRESS", "%C", -1 ); output_easy( fp, info, "DEGREEGRANTOR", "%C", -1 ); output_easy( fp, info, "DEGREEGRANTOR:CORP", "%C", -1 ); output_easy( fp, info, "DEGREEGRANTOR:ASIS", "%C", -1 ); output_easy( fp, info, "SERIALNUMBER", "%@", -1 ); output_easy( fp, info, "ISSN", "%@", -1 ); output_easy( fp, info, "ISBN", "%@", -1 ); output_easy( fp, info, "LANGUAGE", "%G", -1 ); output_easy( fp, info, "REFNUM", "%F", -1 ); output_easyall( fp, info, "NOTES", "%O", -1 ); output_easy( fp, info, "ABSTRACT", "%X", -1 ); output_easy( fp, info, "CLASSIFICATION", "%L", -1 ); output_easyall( fp, info, "KEYWORD", "%K", -1 ); output_easyall( fp, info, "NGENRE", "%9", -1 ); output_thesishint( fp, type ); output_easyall( fp, info, "URL", "%U", -1 ); output_easyall( fp, info, "FILEATTACH", "%U", -1 ); output_doi( fp, info ); output_pmid( fp, info ); output_arxiv( fp, info ); output_jstor( fp, info ); output_pages( fp, info ); fprintf( fp, "\n" ); fflush( fp ); } void endout_writeheader( FILE *outptr, param *p ) { if ( p->utf8bom ) utf8_writebom( outptr ); }