## -*-Tcl-*- # ################################################################### # Vince's Additions - an extension package for Alpha # # FILE: "bibConvert.tcl" # created: 6/8/95 {4:23:31 pm} # last update: 21/3/1999 {3:24:37 pm} # Author: Vince Darley # E-mail: # mail: Division of Applied Sciences, Harvard University # Oxford Street, Cambridge MA 02138, USA # www: # # Description: # # proc bibConvert {} # # First attempt at parsing various records into bibtex entries. # It now copes with hollis records, the horrible form of inspec # record our firstsearch interface gives us, and a nicer # form of inspec record produced by another interface. # # Bibliography Formats Handled: # # Hollis: (Harvard University Library System) # # The basic idea is that records are outlined by "%START:" and # "%END:" tags, each field label is of the form "%FIELDNAME:" # so we can easily separate things out. # # Inspec: (File capture of 'FirstSearch' interface output) # # It's a bit harder here, and we have to remove a lot of # garbage, however, we basically only accept lines beginning # with '|', and parse the record names appropriately. # # Inspec2: # # This is much easier: each record starts with 'Document N' and # ends with a long line of dashes. # # Inspec3: # # This is much easier: each record starts with 'Citation N'. # Now copes with two variants of this record type (Aug'96) # # Inspec4: # # This is much easier: each record starts with ' Doc Type:'. # # Inspec5: # # I've forgotten what this one looks like (Record No. or so) # # Inspec6: # # Something from Berkeley: 'N. (Inspec Result)' # # ISI: (Institute of Scientific Information; Science Citation Index) # # The basic idea is that records are outlined by "PT" and # "ER" tags, each field label is of the form "FF " # so we can easily separate things out. # # Features: # # The only clever bits are as follows: # 1) Automatically try and extract an author surname, # concatenate it with the year and use it as the bibtex # citation label. # 2) Replace '\' in author lists by 'and' (hollis) # 3) Replace ';' in author lists by 'and' (inspec) # 4) Uses editor 'Alpha' on the mac for some interaction # 5) Automatic bib type recognition via file extensions # 6) Can automatically convert an Alpha window, and # integrate with the bibtex mode. # 7) Will extract and separate journal entries containing # name, vol., number and pages together. # 8) Plus lots more clever stuff now.... # ######################################################################### # # Please send any improvements: # # This code snippet is copyright (C) Vince Darley 1997, # although you may freely copy and modify it provided this # copyright notice remains intact. I will maintain and add to # it over time, and will accomodate your improvements if you send # them to me. # ######################################################################### # # All procedures and global variables begin with 'bibconv::' # except the main one, which is called 'bibConvert'. # # If you're interested in self-organisation, complex systems # and stuff like that, check out the follwing URL for some # bibliographies which are the results of this code: # # # ######################################################################### # # Usage: # must be sourced into a Tcl interpreter, e.g.: # # >tclsh # % source bibAdditions.tcl # % source bibConvert.tcl # % bibConvert myfile.inspec # % bibConvert otherfile.inspec # % exit # > more myfile.bib # > ... # # Detailed usage: # # 'bibConvert input-file [output-file] [hollis | inspec]' # # If the output file exists it will be overwritten, except on a # Mac, running under Alpha, in which case the user is asked first # # Simple usage: # 'bibConvert foo' # will look for files "foo.[inspec|insp|hollis|hol]" # If one exists, the appropriate conversion will take place, and # the converted bibliography saved in file "foo.bib". # # Personalisation: # There are a few variables whose values you can modify to tailor # the output to your personal needs. See the start of the code # section for details. # # Usage via a shell script: remove the leading '#' on each of the seven # lines below and put the rest into a script file 'bibConvert' # # ---------------bibConvert---------------cut here --------- # #!/bin/sh # # the next line restarts using tclsh, as long as it's in the path \ # exec tclsh7.6 "$0" "$@" # # source ~/bin/bibAdditions.tcl # source ~/bin/bibConvert.tcl # eval bibConvert $argv # --------------------------------------- cut here --------- # ######################################################################### # # Usage under the editor 'Alpha': # # You may have got this file as part of "Vince's Additions", a # set of Tcl files which I've built up to personalise Alpha for # various purposes. Use the readme to install this package for Alpha. # # Now open a '.hollis' or '.inspec' file # and Alpha automatically switches to bibtex mode, with a new item # at the bottom of the bibtex menu 'bibConvert', also bound to the # key combination '-b'. Select it and Alpha converts the open # window, saving it in a new file (with extension '.bib'), which it # then opens for you to examine! # ######################################################################### # # To Do: # Better handling of record types: currently all hollis records # are 'book' and inspec records are 'article' or 'inproceedings' # # Add ability to append to a given bibliography. # # Add ability to convert a text selection under Alpha # ##################################################################### # History # # modified by rev reason # -------- --- --- ----------- # May95 VMD 0.1 original, hollis->bibtex converter # May95 VMD 0.2 added rudimentary inspec support # May95 VMD 0.3 code more robust, and handles inspec well # May95 VMD 0.4 looks at command line extensions to determine # bib type. # May95 VMD 0.5 Will convert windows of the Alpha editor # May95 VMD 0.6 Integrates with bibtex mode under Alpha # May95 VMD 0.7 Now dependent upon some utility code in # 'bibAdditions.tcl' # May95 VMD 0.8 Tries to generate correct record type, and # splits journal entries into pieces. # Jun95 VMD 0.9 Handles a new inspec format plus few extras # Aug96 VMD 0.91 More formats # 5/3/97 VMD 1.0 Prettier output, more user control over format # 6/5/97 VMD 1.01 Fixed two minor bugs # 17/2/98 VMD 1.05 Various improvements and new inspec type # 4/16/98 JEG 1.06 Added ISI conversion # 16/4/98 VMD 1.07 Modernised a few things. # 21/2/99 fp 1.12 Added OVID support # ################################################################### ## # use a single tab to indent the body of an item. # change this if you prefer something else set _bibIndent "\t" # if an item covers multiple lines, indent lines 2-n by the amount set _bibMultiIndent "\t\t" # max line width set _bibMaxWidth 72 # the types we recognise, with file extension mappings namespace eval bibconv {} set bibconv::types { hollis inspec isi ovid } set bibconv::extensions(insp) inspec set bibconv::extensions(inspec) inspec set bibconv::extensions(hol) hollis set bibconv::extensions(hollis) hollis set bibconv::extensions(isi) isi set bibconv::extensions(ovid) ovid # just so we can use this file without Alpha. namespace eval alpha {} if {[info commands alpha::feature] == ""} { proc alpha::feature {args} {} } # MODIFY BELOW AT YOUR OWN RISK. alpha::feature bibConvert 1.13 "Bib" { alpha::package require Bib 3.1 } { menu::insert bibtexMenu items end "/B } help { "bibConvert.tcl" This package will convert bibliography windows from 'hollis' and 'inspec' formats to bibtex, saving the result in a new file, and opening it in a new window for your perusal. This may not be of any use to you, but is very useful to me. Here 'hollis' is the format used by the Harvard University library system, and 'inspec' is a commercial scientific bibliography, interfaced either by the 'firstsearch' system or another standard inspec interface (whose output is handled by this Tcl code). This code currently handles no less than 7 different inspec formats! Also, flip (flip@skidmore.edu) added ovid support. "bibAdditions.tcl" Various common utility functions utilised by the rest of the code; also allows 'bibConvert' to work under a general Tcl interpreter (e.g. under Unix tclsh). } # make sure we've got my code loaded if {[catch {dummyBibAdditions}]} { puts "You must first source 'bibAdditions.tcl'" } namespace eval Bib {} proc Bib::convertToBib {args} { eval bibConvert $args } proc bibConvert { { fin "" } { fout default } { bibtype unknown } } { global vince_usingAlpha bibconv::using_window if { $fin == "" } { set fin [vince_getFile "Please select a bibliography to convert" ] } set args [bibconv::parse_args $fin $fout $bibtype] set fin [lindex $args 0] set fout [lindex $args 1] set bibtype [lindex $args 2] if { $bibtype == -1 } { return } if {$vince_usingAlpha && ([info tclversion] < 8.0)} { if {![catch {getWinInfo -w $fin alphawin}]} { if {$alphawin(platform) != "mac"} { alertnote "Windows to be converted must have MacOS eol's.\ I'll correct this for you." setWinInfo -w $fin dirty 1 setWinInfo -w $fin platform mac save } } } set fi [open $fin] # make sure it's the correct type set bibtype [bibconv::confirm_type $fi $bibtype] if { $bibtype == "" } { return } if {[file exists $fout]} { if { [vince_askyesno \ "File '$fout' exists. Do you want to overwrite it?" ] \ != "yes" } { return "bibliography conversion cancelled" } } set fo [open $fout w] set count 0 while {![eof $fi]} { vince_print "converting: [incr count]" bibconv::read_record $fi $fo $bibtype } close $fi close $fo vince_edit $fout } proc bibconv::confirm_type { fi bibtype } { switch -- $bibtype { "hollis" { return $bibtype } "inspec" { while { ![eof $fi] } { gets $fi rline if { [string range $rline 0 14] == "| RECORD NO.:" } { set returnval "inspec" break } elseif { [string range $rline 0 7] == "Document" } { set returnval "inspec2" break } elseif { [string range $rline 0 7] == "Citation" } { set returnval "inspec3" break } elseif { [string range $rline 0 8] == " Doc Type" } { set returnval "inspec4" break } elseif { [string range $rline 0 13] == " RECORD NO.:" } { set returnval "inspec5" break } elseif { [string range $rline 0 20] == " COPYRIGHT:" } { set returnval "inspec5" break } elseif { [string range $rline 0 17] == "1. (INSPEC result)" } { set returnval "inspec6" break } elseif { [regexp {^<[0-9]+>} $rline]} { set returnval "inspec7" break } } seek $fi 0 start if { ![info exists returnval] } { vince_print "Sorry I don't recognise this inspec format. Please contact darley@fas.harvard.edu" return "" } return $returnval } "isi" { return $bibtype } "ovid" { # peel this off gets $fi rline seek $fi 0 start if { [regexp {^<[0-9]+>} $rline]} { return "ovid" } else { vince_print "Sorry I don't recognise this ovid format." return "" } } } } # called by the main bibConvert function proc bibconv::parse_args { fin fout bibtype } { global vince_usingAlpha bibconv::types bibconv::extensions if { $bibtype == "unknown" || [lsearch -exact ${bibconv::types} $bibtype ] == -1 } { set bibtype "" } set f [vince_parseFileNames $fin "bib" ${bibconv::types} $fout bibconv::extensions ] set bibtype [lindex $f 2] if { [lsearch ${bibconv::types} $bibtype ] == -1 } { # pick one from a list set bibtype .[listpick \ -p "Please select a bibliography type to read from:" \ ${bibconv::types}] set f [lreplace $f 2 2 $bibtype] } return $f } ## # Some fields extend over multiple lines, in which # case we don't start a new field entry. This # procedure returns '1' if we have a continuation. ## proc bibconv::not_new_item { line bibtype } { switch -- $bibtype { "hollis" { if { [string index $line 0] != "%" } { return 1 } else { return 0 } } "inspec" { # is there a colon at position 14, and it starts with "|" if { [string index $line 14] != ":" || [string index $line 0] != "|" } { return 1 } else { return 0 } } "ovid" - "inspec7" - "isi" { # does the line start with whitespace return [regexp {^[ \t]+[^ \t]} $line] } "inspec2" - "inspec6" { # is the first portion of the line blank? if { [string range $line 0 14] == " " } { return 1 } else { return 0 } } "inspec3" - "inspec4" { # is the first portion of the line blank? if { [string range $line 0 2] == " " } { return 1 } else { return 0 } } "inspec5" { # is there a colon at position 13, if { [string index $line 13] != ":" && [string index $line 20] != ":" } { return 1 } else { return 0 } } } } ## # Some interfaces intersperse records with garbage # lines ("press 'f' for another page"). This procedure # ignores them. ## proc bibconv::throw_away { fi l1 bibtype } { gets $fi rline2 switch -- $bibtype { "hollis" { return $rline2 } "inspec" { while { ![eof $fi] } { # do away with identical lines # (caused by paging through data) if { $l1 != $rline2 \ && [string range $rline2 0 1] != "|_" \ && $rline2 != "|" \ && [string index $rline2 0] == "|" } { return $rline2 } else { gets $fi rline2 } } return "" } "ovid" - "inspec2" - "inspec7" - "inspec3" - "inspec4" { return $rline2 } "inspec6" { set tr [string trim $rline2] if {$tr == "CONFERENCE PAPER" || $tr == ""} { gets $fi rline2 } return $rline2 } "inspec5" { if { [string range $rline2 0 11] == " Next Record" } { gets $fi rline2 } return $rline2 } "isi" { return $rline2 } } } ## # Parse a line and extract the # category and actual item text: ## proc bibconv::extract_item { rline bibtype } { switch -- $bibtype { "hollis" { set itempos [string first : $rline ] set itemtype [string range $rline 1 [expr {$itempos - 1}] ] set itemtype [string trimleft [string trimright $itemtype] ] set itemtype [join $itemtype _] set itemtext [string range $rline [expr {$itempos +1}] end] set itemtext [string trimleft [string trimright $itemtext] ] return [list $itemtype $itemtext] } "inspec" { set itemtype [string range $rline 1 13] set itemtype [string trimleft [string trimright $itemtype] ] set itemtype [join $itemtype _] set itemtext [string range $rline 16 end] return [list $itemtype $itemtext] } "inspec2" { set itemtype [string range $rline 0 14] set itemtype [string trimright $itemtype " :" ] set itemtype [join $itemtype _] set itemtext [string range $rline 15 end] return [list $itemtype $itemtext] } "inspec3" - "inspec4" - "inspec5" - "inspec6" { set itemtype [lindex [split "$rline" ":"] 0] set itemtext [string range $rline [expr {1+[string length $itemtype]}] end] set itemtype [join [string trim $itemtype] _] return [list $itemtype $itemtext] } "inspec7" { set itemtype [lindex [split "$rline" "\n"] 0] set itemtext [string trim [string range $rline [expr {1+[string length $itemtype]}] end]] set itemtype [join [string trim $itemtype] _] return [list $itemtype $itemtext] } "isi" { set itemtype [lindex [split "$rline" " "] 0] set itemtext [string trim [string range $rline [expr {1+[string length $itemtype]}] end]] set itemtype [join [string trim $itemtype] _] return [list $itemtype $itemtext] } "ovid" { set itemtype [lindex [split "$rline" "\n"] 0] set itemtext [string trim [string range $rline [expr {1+[string length $itemtype]}] end]] set itemtype [join [string trim $itemtype] _] return [list $itemtype $itemtext] } } } ## # The main procedure which grabs a whole # bibtex record ## proc bibconv::read_record { fi fo bibtype } { global bibconv::last_item set rline [bibconv::find_start $fi ${bibconv::last_item} $bibtype] if { $rline == 0 } { return } catch {unset new_record} while { [bibconv::not_at_end $rline $bibtype] && ![eof $fi] } { #gets $fi rline2 set rline2 [bibconv::throw_away $fi $rline $bibtype] # get all of a single item while { [bibconv::not_new_item $rline2 $bibtype] && ![eof $fi] } { append rline [bibconv::append_item $rline2 $bibtype] set rline2 [bibconv::throw_away $fi $rline2 $bibtype] } set item [bibconv::extract_item $rline $bibtype] eval bibconv::make_item new_record $item $bibtype set rline $rline2 } # all items are in the array 'new_record' set bibconv::last_item $rline set tag "" if {[info exists new_record(author) ]} { set author [bibconv::parse_author $new_record(author) $bibtype] append tag [lindex $author 0] set new_record(author) [lindex $author 1] } # parse year out (ignoring months) and append to the tag if {[info exists new_record(year) ]} { set y $new_record(year) set year "" regexp {[0-9][0-9][0-9][0-9]} $y year set new_record(year) $year } # remove spaces to give the citation tag set tag [join [split $tag " "] ""] #set bibt [bibconv::citation_type [array names new_record] $bibtype ] # returns the type of citation set bibt [bibconv::reformat_records new_record $bibtype] if {[info exists new_record(year) ]} { # fp did this since I like this format better... though it might make it Y2K non-compliant append tag [string range $new_record(year) 2 3] } puts $fo "@$bibt\{$tag," bibconv::clever_printing new_record $fo foreach item [array names new_record] { if { $new_record($item) != "" } { bibconv::print new_record $item $fo } } puts $fo "\}\n" } proc bibconv::make_item { rec itemtype itemtext bibtype } { upvar $rec a global bibconv::${bibtype}_map bibconv::${bibtype}_kill set maps bibconv::${bibtype}_map set kills bibconv::${bibtype}_kill if {[info exists ${kills}($itemtype) ]} { switch -- [set ${kills}($itemtype)] { "always" {} "remember" {lappend a(kill) $itemtype} } } elseif {[info exists ${maps}($itemtype) ]} { if { $itemtext != "" } { set a([set ${maps}($itemtype)]) $itemtext } } else { vince_print "No such item $itemtype" } } ## # print out author, title and year first, then the return # for the rest in any order ## proc bibconv::clever_printing { rec fo } { upvar $rec a global _bibIndent _bibMultiIndent foreach item { author title year } { bibconv::print a $item $fo } } proc bibconv::print { rec item fo } { upvar $rec a global _bibIndent _bibMultiIndent if {[info exists a($item) ]} { set text [bibconv::convertfunnytcharstolatex $a($item)] if { $text != "" } { set pref [string range "$item = \{" 0 3] set t [string range "$item = \{" 4 end] set text "${t}$a($item)\}," regsub -all "\[ \t\r\n]+" [string trim $text] " " text regsub -all {(([^A-Z@]|\\@)[.?!]("|'|'')?([])])?) } $text {\1 } text regsub -all {\&} $text {\\\&} text bibconv::breakintolines text puts $fo "${_bibIndent}${pref}$text" } unset a($item) } } proc bibconv::convertfunnytcharstolatex {t} { # convert formatting information. regsub -all {/sub ([^/]+)/} $t "_\{\\1\}" t regsub -all {/sup ([^/]+)/} $t "^\{\\1\}" t return $t } proc bibconv::breakintolines {t} { global vince_usingAlpha global _bibIndent _bibMultiIndent _bibMaxWidth set fc [expr {$_bibMaxWidth - 8}] upvar $t text # what if it's really big? if {[string length $text] > $fc} { if {$vince_usingAlpha} { global leftFillColumn fillColumn # temporarily adjust the fillColumns set ol $leftFillColumn set or $fillColumn set leftFillColumn 0 set fillColumn $fc # break and indent the paragraph regsub -all "\[\n\r\]" "[string trimright [breakIntoLines $text]]" "\r${_bibMultiIndent}" text set leftFillColumn $ol set fillColumn $or } else { # do it by hand! while {[string length $text] > $fc} { set f [string last " " [string range $text 0 $fc]] if {$f == -1} { vince_print "Have a word > $fc letters long. It will be broken." set f $fc } append a "[string range $text 0 $f]\n${_bibMultiIndent}" set text [string range $text [incr f] end] } append a $text set text $a } } } ## # We kill any records we don't want, and maybe split some which # are given in sets. ## proc bibconv::reformat_records { rec bibtype } { upvar $rec a # get rid of empty entries - but there shouldn't be any ## # foreach v [array names a] { # if { $a($v) == "" } { # unset a($v) # } # } ## switch -- $bibtype { "hollis" { set a(kill) "" unset a(kill) return "book" } "inspec" - "inspec2" - "inspec3" - "inspec5" - "inspec6" - "inspec7" { # if it's in a journal, we need to extract vol, number and pages if {[info exists a(journal)]} { regsub -all "\[ \t\r\n\]+" $a(journal) " " a(journal) regsub -all {\([^0-9]+\)} $a(journal) "" a(journal) # we split it with 'vol.' and 'p.' and grab the # smaller start of the two set p1 [string first " vol." $a(journal)] if {$p1 < 0} { set p1 [string first " vol " $a(journal)] } set p2 [string first " p." $a(journal)] if {$p2 < 0} { set p2 [string first " pp." $a(journal)] } if { $p2 < 0 } { set p2 1000 } if { $p1 == $p2 } { # both not found; currently do nothing } else { if {$p1 == -1} { set p $p2 set j [string range $a(journal) [expr {$p +1}] end] set a(journal) [string range $a(journal) 0 [expr $p -2]] set j [split $j ,] } else { if { $p1 < $p2 } { set p $p1 } else { set p $p2 } set j [string range $a(journal) [expr $p +1] end] set a(journal) [string range $a(journal) 0 [expr $p -2]] set j [split $j ,] } #alertnote $j set l [llength $j] # sometimes we aren't given a number so we insert a blank if { $l == 2 } { set j [linsert $j 1 "." ] incr l set p [lindex $j 2] if { [string first "p." $p ] < 0 } { set j [lreplace $j 2 2 p.${p} ] } } # now extract vol, number and page from the last three #set j [lrange $j [expr $l -2] $l] if { ![info exists a(volume)] } { set a(volume) [bibconv::extract_vnp [lindex $j 0] "."] } if { ![info exists a(number)] } { set a(number) [bibconv::extract_vnp [lindex $j 1] "."] } if { ![info exists a(pages)] } { set a(pages) [bibconv::extract_vnp [lindex $j 2] "p."] } #now journal may end in a month and year! (esp Inspec 3,6) set a(journal) [string trim $a(journal)] if { [set jj [string first "(" $a(journal)]] != -1 } { set rest [string range $a(journal) $jj end] set a(journal) [string range $a(journal) 0 [expr $jj -1]] set rest [string trim $rest "() "] if {[string match {*[1-9][0-9][0-9][0-9]} $rest]} { set lrest [llength $rest] set a(year) [lindex $rest [expr $lrest -1]] set a(month) [lindex $rest [expr $lrest -2]] } } else { set l [string length $a(journal)] set e [string range $a(journal) [expr $l -4] end ] if {[string match {[1-9][0-9][0-9][0-9]} $e ]} { # it ends in a year set a(year) $e set p [string last "," $a(journal)] set my [string range $a(journal) $p end] set a(journal) [string range $a(journal) 0 [expr $p -1]] set l [string length $my] set a(month) [string trim [string range $my 1 [expr $l -5]]] } else { # 'j' above may end in a year set j [string trim [lindex $j end] " ."] regsub -all {[ .]+} $j " " j regexp {(([1-9][0-9]* )?[A-Za-z]+) ([1-9][0-9][0-9][0-9])$} $j \ "" a(month) "" a(year) } } } } # we're only interested if it's a conference proceedings or not if {[info exists a(kill)]} { unset a(kill) return "inproceedings" } else { return "article" } } "inspec4" { # if it's in a journal, we need to extract vol, number and pages if {[info exists a(journal)]} { # we split it with 'vol.' and 'p.' and grab the # smaller start of the two set s [split $a(journal) "\n"] set a(journal) [lindex $s 0] for { set i 1 } { $i <= [llength $s] } { incr i } { set l [bibconv::extract_item [lindex $s $i] $bibtype] eval bibconv::make_item a $l $bibtype } } if {[info exists a(volume)]} { set p [string first "Iss:" $a(volume)] if { $p > 0 } { set a(number) [string range $a(volume) [expr $p +4] end] set a(volume) [string range $a(volume) 0 [expr $p -1]] } } if {[info exists a(number)]} { set p [string first "p." $a(number)] if { $p > 0 } { set a(pages) [string range $a(number) [expr $p +2] end] set a(number) [string range $a(number) 0 [expr $p -1]] } } # we're only interested if it's a conference proceedings or not if {[info exists a(kill)]} { unset a(kill) return "inproceedings" } else { return "article" } } "isi" { if {[info exists a(EP)]} { if {[info exists a(pages)]} { set a(EP) [string trim $a(EP)] set a(pages) [string trim $a(pages)] if {$a(pages) != $a(EP)} { set a(pages) "$a(pages)--$a(EP)" } } else { # I know of no reason for this to ever happen, but... set a(pages) $a(EP) } unset a(EP) } if {[info exists a(DE)]} { if {[info exists a(key)]} { append a(key) ";\n\t\t$a(DE)" } else { set a(key) $a(DE) } unset a(DE) } if {[info exists a(DT)]} { set type [string tolower $a(DT)] unset a(DT) } else { set type "article" } return $type } "ovid" { # if it's in a journal, we need to extract vol, number and pages if {[info exists a(journal)]} { regsub -all "\[ \t\r\n\]+" $a(journal) " " a(journal) regsub -all {\([^0-9]+\)} $a(journal) "" a(journal) # split into journal name and volume info set js [split $a(journal) .] #split volume info into chunks set j [split [lindex $js 1] ,] # Apa kindof looks like this: # Name. Vol vol(num), month year, pages. set a(journal) [string trim [lindex $js 0]] #alertnote $j # the chunks and how many of 'em. set l [llength $j] set v [string trim [lindex $j 0]] set e [string trim [lindex $j 1]] if {$l == 3} {set pp [string trim [lindex $j 2]]} #first is the volume field, tends to be in one of three formats # raw number: 62 # vol indica: Vol 32 # no indica: No 43 # vol no: Vol 43(2) # # yes, yes, i'm not entirely sure what is up here... ok, ok, yes # stop tortureing me. i'm sorry, can't that just be enough for you? # if { ![info exists a(volume)] || ![info exists a(number)] } { switch -regexp $v { {([0-9]+)\(([0-9]+)\)} {regexp {([0-9]+)\(([0-9]+)\)} $v poo a(volume) a(number)} {[Vv].*} {regexp {([0-9]+)} $v poo a(volume)} {[Nn].*} {regexp {([0-9]+)} $v poo a(number)} default {regexp {([0-9]+)} $v poo a(number)} } } if { ![info exists a(pages)] && $l == 3} { set a(pages) $pp } if {[string match {[1-9][0-9][0-9][0-9]} $e ]} { # it ends in a year set a(year) $e } else { # 'j' above may end in a year regexp {(([1-9][0-9]* )?[A-Za-z]+) ([1-9][0-9][0-9][0-9])$} $e \ "" a(month) "" a(year) } } # we're only interested if it's a conference proceedings or not if {[info exists a(kill)]} { unset a(kill) return "inproceedings" } else { return "article" } } } } ## # Utility procedure used by the above ## proc bibconv::extract_vnp { str prefix } { set p [string first $prefix $str] if { $p == -1 } { return "" } else { return [string range $str [expr $p + [string length $prefix]] end] } } ## # Try and do something intelligent with lists # of multiple authors. Returns a list containing # the surname of the first author (for the bibtex tag) # followed by the actual bibtex author entry. ## proc bibconv::parse_author { author bibtype } { switch -- $bibtype { "hollis" { return [list [lindex [split $author ,] 0] \ [join [split $author \\ ] and] ] } "ovid" - "inspec" - "inspec3" - "inspec4" - "inspec5" - "inspec6" - "inspec7" { # remove anything in '()' (usually an address) regsub -all {\([^\(\)]*\)} $author {} auth return [list [lindex [split $auth ",;.:" ] 0] \ [join [split $auth ";" ] " and"] ] } "inspec2" { set first [lindex [split $author "-" ] 0] set alist "" foreach a [split $author "."] { if { $a != "" } { set l [split $a "-"] append alist "[lindex $l 0], " foreach i [lrange $l 1 end] { append alist "$i." } append alist " and " } } set l [string length $alist] set alist [string range $alist 0 [expr $l -5 ] ] return [list $first $alist] } "isi" { regsub -all "\t\t" $author "" author set first [lindex [split $author ",\n"] 0] set alist "" foreach a [split $author "\n"] { if {$a != ""} { set l [split $a ","] append alist "[lindex $l 0]" if {[llength $l] == 2} { append alist "," set ii [string trim [lindex $l 1]] regsub -all {[A-Z]} $ii { \0.} ii append alist $ii } append alist " and " } } # clip last " and " set l [string length $alist] set alist [string range $alist 0 [expr $l -6 ] ] return [list $first $alist] } } } ## # We had a multiple line field and wish # to add the subsequent lines ## proc bibconv::append_item { rline2 bibtype } { switch -- $bibtype { "hollis" { return "\n\t\t[string trimleft $rline2]" } "inspec" { if { $rline2 != "|" } { if { [string index $rline2 0] == "|" } { return "\n[string range $rline2 1 end]" } else { return "\n$rline2" } } else { return "" } } "ovid" - "inspec2" - "inspec3" - "inspec4" - "inspec5" - "inspec6" - "inspec7" - "isi" { return "\n\t\t[string trimleft $rline2]" } } } ## # Find the start of a new bibtex record ## proc bibconv::find_start { fi rline bibtype } { if { $rline == "" } { gets $fi rline } switch -- $bibtype { "hollis" { while {![eof $fi] } { if { $rline == "%START:" } { gets $fi rline return $rline } gets $fi rline } return 0 } "inspec" { while {![eof $fi] } { if { [string range $rline 0 14] == "| RECORD NO.:" } { gets $fi rline return $rline } gets $fi rline } return 0 } "inspec2" { while {![eof $fi] } { if { [string range $rline 0 7] == "Document" } { gets $fi rline return $rline } gets $fi rline } return 0 } "inspec3" { while {![eof $fi] } { if { [string range $rline 0 7] == "Citation" } { gets $fi rline return $rline } gets $fi rline } return 0 } "inspec4" { while {![eof $fi] } { if { [string range $rline 0 8] == " Doc Type" } { gets $fi rline return $rline } #gets $fi rline } return 0 } "inspec5" { while {![eof $fi] } { if { [string range $rline 0 13] == " RECORD NO.:" \ || [string range $rline 0 20] == " RECORD NO.:"} { gets $fi rline return $rline } gets $fi rline } return 0 } "inspec6" { while {![eof $fi] } { if { [string trim [lindex [split $rline "."] 1]] == "(INSPEC result)" } { gets $fi rline if { [string trim $rline] == "CONFERENCE PAPER"} { gets $fi rline } return $rline } gets $fi rline } return 0 } "ovid" - "inspec7" { while {![eof $fi] } { if { [regexp {^<[0-9]+>} $rline] } { gets $fi rline return $rline } gets $fi rline } return 0 } "isi" { while {![eof $fi] } { if { [string range $rline 0 1] == "PT" } { gets $fi rline return $rline } gets $fi rline } return 0 } } } ## # Have we reached the end of the last # bibtex field? ## proc bibconv::not_at_end { line bibtype } { switch -- $bibtype { "hollis" { if { $line != "%END:" } { return 1 } else { return 0 } } "inspec" { set st [string range $line 0 14] if { $st != "| CLASS CODES:" && $st != "| RECORD NO.:" } { return 1 } else { return 0 } } "inspec2" { set st [string range $line 0 7] if { $st != "--------" && $st != "UW Load " } { return 1 } else { return 0 } } "inspec3" { if { [string range $line 0 7] != "Citation" } { return 1 } else { return 0 } } "inspec4" { if { [string range $line 0 8] != " Doc Type" } { return 1 } else { return 0 } } "inspec5" { set st [string range $line 0 13] if { $st != " CLASS CODES:" && $st != " RECORD NO.:" } { return 1 } else { set st [string range $line 0 20] if { $st != " CLASS CODES:" && $st != " RECORD NO.:" } { return 1 } else { return 0 } } } "inspec6" { set st [string trim [lindex [split $line "."] 1]] if { $st != "(INSPEC result)" } { return 1 } else { return 0 } } "ovid" - "inspec7" { if { [string trim $line] == "" } { return 0 } else { return 1 } } "isi" { if { $line != "ER" } { return 1 } else { return 0 } } } } set bibconv::last_item "" set bibconv::using_window 0 ######################################################## # # # Record field name mappings for different formats # # # ######################################################## # spaces are replaced by underscores in array entries ######################## # # # Hollis mappings: # # # ######################## set bibconv::hollis_map(AUTHORS) author set bibconv::hollis_map(YEAR) year set bibconv::hollis_map(TITLE) title set bibconv::hollis_map(PUB._INFO) publisher set bibconv::hollis_map(EDITION) edition set bibconv::hollis_map(SUMMARY) annote set bibconv::hollis_map(NOTES) note set bibconv::hollis_map(LOCATION) customField set bibconv::hollis_map(SERIES) series set bibconv::hollis_map(SUBJECTS) key set bibconv::hollis_map(PUBLISHED_IN) howPublished set bibconv::hollis_map(NUMBERS) isbn set bibconv::hollis_kill(HOLLIS#) always set bibconv::hollis_kill(DESCRIPTION) always set bibconv::hollis_kill(FORMAT) always set bibconv::hollis_kill(FREQUENCY) always set bibconv::hollis_kill(AUTHOR) always ####################### # # # Inspec mappings # # # ####################### set bibconv::inspec_map(AUTHOR) author set bibconv::inspec_map(TITLE) title set bibconv::inspec_map(YEAR) year set bibconv::inspec_map(LANGUAGE) language set bibconv::inspec_map(ABSTRACT) annote set bibconv::inspec_map(PLACE_OF_PUBL) howPublished set bibconv::inspec_map(DESCRIPTORS) key set bibconv::inspec_map(IDENTIFIERS) key set bibconv::inspec_map(CORP_SOURCE) institution set bibconv::inspec_map(ISSN) issn set bibconv::inspec_map(ISBN) isbn set bibconv::inspec_map(CONF_TITLE) organization set bibconv::inspec_map(SOURCE) journal set bibconv::inspec_map(PUBLISHER) publisher set bibconv::inspec_map(EDITOR) editor set bibconv::inspec_map(SPONSOR_ORG) organization set bibconv::inspec_kill(COPYRIGHT) always set bibconv::inspec_kill(COPYRIGHT_NO) always set bibconv::inspec_kill(COUNTRY) always set bibconv::inspec_kill(CLASS_CODES) always set bibconv::inspec_kill(RECORD_NO.) always set bibconv::inspec_kill(CODEN) always set bibconv::inspec_kill(CONF_LOCATION) remember set bibconv::inspec_kill(TREATMENT) always set bibconv::inspec_kill(TRANSLATED_IN) always set bibconv::inspec_kill(LIBRARIES) always ## # Inspec 2 mappings # These are for inspec files started # with 'Document ...' and 'Accession No.' ## set bibconv::inspec2_map(Author) author set bibconv::inspec2_map(Title) title set bibconv::inspec2_map(Source) journal set bibconv::inspec2_kill(References) always set bibconv::inspec2_map(ISSN) issn set bibconv::inspec2_map(Subject) note set bibconv::inspec2_map(Identifiers) key set bibconv::inspec2_map(Abstract) annote set bibconv::inspec2_map(Language) language set bibconv::inspec2_map(Year) year set bibconv::inspec2_kill(Pub._Type) always set bibconv::inspec2_kill(CODEN) always set bibconv::inspec2_kill(Accession_No.) always set bibconv::inspec2_kill(Author_Affil.) always set bibconv::inspec2_kill(Treatment) always set bibconv::inspec2_kill(Num._Indexing) always set bibconv::inspec2_kill(Report_No.) always set bibconv::inspec2_kill(Pub._Country) always set bibconv::inspec2_kill(Class._Code) always set bibconv::inspec2_kill(Sub./Material) always set bibconv::inspec2_kill(UW_Load_Date) always ## # Inspec 3 mappings # These are for inspec files started # with 'Citation ...' and ## set bibconv::inspec3_map(AUTHOR) author set bibconv::inspec3_map(TITLE) title set bibconv::inspec3_map(YEAR) year set bibconv::inspec3_kill(DOCUMENT_TYPE) always set bibconv::inspec3_map(LANGUAGE) language set bibconv::inspec3_map(LOCATION) location set bibconv::inspec3_map(ABSTRACT) annote set bibconv::inspec3_map(PLACE_OF_PUBL) howPublished set bibconv::inspec3_map(DESCRIPTORS) key set bibconv::inspec3_map(IDENTIFIERS) key set bibconv::inspec3_map(THESAURUS) key set bibconv::inspec3_map(CORP_SOURCE) institution set bibconv::inspec3_map(ISSN) issn set bibconv::inspec3_map(ISBN) isbn set bibconv::inspec3_map(CONF_TITLE) organization set bibconv::inspec3_map(PUBLICATION) journal set bibconv::inspec3_map(NOTES) note set bibconv::inspec3_map(OTHER_SUBJECTS) annote set bibconv::inspec3_map(PUBLISHER) publisher set bibconv::inspec3_map(EDITOR) editor set bibconv::inspec3_map(SPONSOR_ORG) organization set bibconv::inspec3_kill(COPYRIGHT) always set bibconv::inspec3_kill(COPYRIGHT_NO) always set bibconv::inspec3_kill(COUNTRY) always set bibconv::inspec3_kill(CLASS_CODES) always set bibconv::inspec3_kill(RECORD_NO.) always set bibconv::inspec3_kill(CODEN) always set bibconv::inspec3_kill(CONF_LOCATION) remember set bibconv::inspec3_kill(TREATMENT) always set bibconv::inspec3_kill(TRANSLATED_IN) always set bibconv::inspec3_kill(LIBRARIES) always set bibconv::inspec3_kill(CHEMICAL_INDEXING) always ## # Inspec 4 mappings # These are for inspec files started # with 'Doc Type: ...' and ## set bibconv::inspec4_map(Language) language set bibconv::inspec4_map(Authors) author set bibconv::inspec4_map(Title) title set bibconv::inspec4_map(Vol) volume set bibconv::inspec4_map(Date) year set bibconv::inspec4_map(Country_of_Publication) howPublished set bibconv::inspec4_map(ISSN) issn set bibconv::inspec4_kill(CCC) always set bibconv::inspec4_map(Affiliation) organization set bibconv::inspec4_map(Journal) journal set bibconv::inspec4_map(Free_Terms) key set bibconv::inspec4_map(Abstract) annote set bibconv::inspec4_map(Classification) key set bibconv::inspec4_map(Thesaurus) key set bibconv::inspec4_kill(Treatment) always set bibconv::inspec4_kill(Doc_Type) always ## # Inspec 5 mappings # These are for inspec files started # with 'Record No: ...' and ## set bibconv::inspec5_map(AUTHOR) author set bibconv::inspec5_map(TITLE) title set bibconv::inspec5_map(YEAR) year set bibconv::inspec5_map(LANGUAGE) language set bibconv::inspec5_map(ABSTRACT) annote set bibconv::inspec5_map(PLACE_OF_PUBL) howPublished set bibconv::inspec5_map(DESCRIPTORS) key set bibconv::inspec5_map(IDENTIFIERS) key set bibconv::inspec5_map(CORP_SOURCE) institution set bibconv::inspec5_map(ISSN) issn set bibconv::inspec5_map(ISBN) isbn set bibconv::inspec5_map(CONF_TITLE) organization set bibconv::inspec5_map(SOURCE) journal set bibconv::inspec5_map(PUBLISHER) publisher set bibconv::inspec5_map(EDITOR) editor set bibconv::inspec5_map(SPONSOR_ORG) organization set bibconv::inspec5_kill(COPYRIGHT) always set bibconv::inspec5_kill(RECORD_TYPE) always set bibconv::inspec5_kill(COPYRIGHT_NO) always set bibconv::inspec5_kill(COUNTRY) always set bibconv::inspec5_kill(CLASS_CODES) always set bibconv::inspec5_kill(RECORD_NO.) always set bibconv::inspec5_kill(CODEN) always set bibconv::inspec5_kill(CONF_LOCATION) remember set bibconv::inspec5_kill(TREATMENT) always set bibconv::inspec5_kill(TRANSLATED_IN) always set bibconv::inspec5_kill(LIBRARIES) always ## # Inspec 6 mappings # These are for inspec files started # with 'N. (INSPEC result)' ## set bibconv::inspec6_map(Author) author set bibconv::inspec6_map(Title) title set bibconv::inspec6_map(Language) language set bibconv::inspec6_map(Text) annote set bibconv::inspec6_map(Subject) key set bibconv::inspec6_map(Affiliation) institution set bibconv::inspec6_map(Source) journal set bibconv::inspec6_map(Conference) organization set bibconv::inspec6_kill(Chem_Indexing) always set bibconv::inspec6_kill(Pub_type) always set bibconv::inspec6_kill(Subfile) always ## # Inspec 7 mappings # These are for inspec files started # with , and each article with an accession number ## set bibconv::inspec7_map(Author) author set bibconv::inspec7_map(Title) title set bibconv::inspec7_map(Source) journal set bibconv::inspec7_kill(References) always set bibconv::inspec7_map(ISSN,ISBN,SBN) issn set bibconv::inspec7_map(Subject) note set bibconv::inspec7_map(Identifiers) key set bibconv::inspec7_map(Descriptors) key set bibconv::inspec7_map(Abstract) annote set bibconv::inspec7_map(Language) language set bibconv::inspec7_map(Year) year set bibconv::inspec7_kill(Publication_Type) always set bibconv::inspec7_kill(CODEN) always set bibconv::inspec7_kill(Accession_Number) always set bibconv::inspec7_kill(Abstract_Number) always set bibconv::inspec7_kill(Conference_Title) always set bibconv::inspec7_kill(Author_Affiliation) always set bibconv::inspec7_kill(Treatment_Code) always set bibconv::inspec7_kill(Num._Indexing) always set bibconv::inspec7_kill(Report_Number) always set bibconv::inspec7_kill(Country_of_Publication) always set bibconv::inspec7_kill(Classification_Codes) always set bibconv::inspec7_kill(Substance_Material) always set bibconv::inspec7_kill(Update_Code) always set bibconv::inspec7_kill(Numeric_Indexing) always ######################## # # # ISI mappings: # # # ######################## set bibconv::isi_map(AU) author set bibconv::isi_map(TI) title set bibconv::isi_map(SO) journal set bibconv::isi_map(PU) publisher set bibconv::isi_map(C1) institution set bibconv::isi_map(ID) key # post-processed into key set bibconv::isi_map(DE) DE set bibconv::isi_map(AB) annote set bibconv::isi_map(BP) pages # post-processed into pages set bibconv::isi_map(EP) EP set bibconv::isi_map(PY) year set bibconv::isi_map(PD) month set bibconv::isi_map(VL) volume set bibconv::isi_map(IS) number set bibconv::isi_map(SE) series # post-processed into entry type set bibconv::isi_map(DT) DT set bibconv::isi_kill(PT) always set bibconv::isi_kill(SN) always set bibconv::isi_kill(PG) always set bibconv::isi_kill(JI) always set bibconv::isi_kill(GA) always set bibconv::isi_kill(PI) always set bibconv::isi_kill(RP) always set bibconv::isi_kill(J9) always set bibconv::isi_kill(PA) always set bibconv::isi_kill(PN) always ## # Ovid mappings # These are for inspec files started # with , and each article with an accession number ## set bibconv::ovid_map(Author) author set bibconv::ovid_map(Title) title set bibconv::ovid_map(Source) journal set bibconv::ovid_kill(References) always set bibconv::ovid_map(ISSN) issn set bibconv::ovid_map(ISBN) issn set bibconv::ovid_map(SBN) issn set bibconv::ovid_map(Subject_Headings) note set bibconv::ovid_map(Key_Phrase_Identifiers) key set bibconv::ovid_map(Descriptors) key set bibconv::ovid_map(Abstract) annote set bibconv::ovid_map(Language) language set bibconv::ovid_map(Publication_Year) year set bibconv::ovid_map(Institution) institution set bibconv::ovid_map(Conference_Information) conference set bibconv::ovid_map(Chapter_Title) chapter set bibconv::ovid_kill(Publication_Type) always set bibconv::ovid_kill(CODEN) always set bibconv::ovid_kill(Accession_Number) always set bibconv::ovid_kill(Abstract_Number) always set bibconv::ovid_kill(Conference_Title) always set bibconv::ovid_kill(Author_Affiliation) always set bibconv::ovid_kill(Treatment_Code) always set bibconv::ovid_kill(Num._Indexing) always set bibconv::ovid_kill(Report_Number) always set bibconv::ovid_kill(Country_of_Publication) always set bibconv::ovid_kill(Classification_Codes) always set bibconv::ovid_kill(Classification_Code) always set bibconv::ovid_kill(Substance_Material) always set bibconv::ovid_kill(Update_Code) always set bibconv::ovid_kill(Numeric_Indexing) always set bibconv::ovid_kill(Local_Messages) always set bibconv::ovid_kill(Population_Group) always set bibconv::ovid_kill(Form/Content_Type) always set bibconv::ovid_kill(Special_Feature) always set bibconv::ovid_kill(Population_Location) always .