(*
* bibtex2html - A BibTeX to HTML translator
* Copyright (C) 1997-2000 Jean-Christophe Filliātre and Claude Marché
*
* This software is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License version 2 for more details
* (enclosed in the file GPL).
*)
(*i $Id: main.ml,v 1.64 2006-11-02 11:58:41 filliatr Exp $ i*)
(*s Main module of bibtex2html. *)
open Printf
open Translate
(* Options. *)
let excluded = ref ([] : string list)
let add_exclude k = excluded := k :: !excluded
let style = ref "plain"
let command = ref "bibtex -min-crossrefs=1000"
type sort = Unsorted | By_date | By_author
let sort = ref Unsorted
let reverse_sort = ref false
let ignore_bibtex_errors = ref false
let expand_abbrev_in_bib_output = ref true
(* Optional citation file. *)
let use_cite_file = ref false
let citations = ref ([] : string list)
let add_citations file =
try
let chan = open_in file
and buf = Buffer.create 1024 in
try
while true do Buffer.add_char buf (input_char chan) done
with End_of_file ->
close_in chan;
citations :=
(Str.split (Str.regexp "[ \t\n]+") (Buffer.contents buf)) @
!citations
with Sys_error msg ->
prerr_endline ("Cannot open citation file (" ^ msg ^ ")");
exit 1
(*s Sorting the entries. *)
module KeyMap = Map.Make(struct type t = string let compare = compare end)
let keep_combine combine l1 l2 =
let map =
List.fold_left (fun m ((_,k,_) as e) -> KeyMap.add k e m) KeyMap.empty l2
in
let rec keep_rec = function
| [] ->
[]
| ((_,k,_) as x)::rem ->
if not (List.mem k !excluded) then
try
let y = KeyMap.find k map in (combine x y) :: (keep_rec rem)
with Not_found -> keep_rec rem
else
keep_rec rem
in
keep_rec l1
let combine_f (c,_,b) e = c,b,e
let rev_combine_f x y = combine_f y x
let sort_entries entries bibitems =
if not !Options.quiet then begin eprintf "Sorting..."; flush stderr end;
let el =
if !sort = By_author then
keep_combine combine_f bibitems entries
else
keep_combine rev_combine_f entries bibitems
in
let sl =
if !sort = By_date then
Sort.list (fun (_,_,e1) (_,_,e2) -> Expand.date_order entries e1 e2) el
else
el
in
if not !Options.quiet then begin eprintf "ok.\n"; flush stderr end;
if !reverse_sort then List.rev sl else sl
(* We use BibTeX itself to format the entries. Operations:
\begin{enumerate}
\item create an auxiliary file tmp.aux
\item call bibtex on it
\item read the resulting tmp.bbl file to get the formatted entries
\end{enumerate} *)
let create_aux_file fbib tmp =
let ch = open_out (tmp ^ ".aux") in
output_string ch "\\relax\n\\bibstyle{";
output_string ch !style;
output_string ch "}\n";
if !use_cite_file then
List.iter
(fun k -> output_string ch ("\\citation{" ^ k ^ "}\n"))
!citations
else
output_string ch "\\citation{*}\n";
output_string ch "\\bibdata{";
output_string ch (Filename.chop_suffix fbib ".bib");
output_string ch "}\n";
close_out ch
let rm f = try Sys.remove f with _ -> ()
let clean tmp =
if not !Options.debug then begin
rm (tmp ^ ".aux");
rm (tmp ^ ".blg");
rm (tmp ^ ".bbl");
rm tmp
end
let call_bibtex tmp =
if not !Options.quiet then begin
eprintf "calling BibTeX..."; flush stderr
end;
match
let redir =
if !output_file = "" || !Options.quiet then
match Sys.os_type with
| "Win32" -> "> nul 2>&1"
| _ -> "> /dev/null 2>&1"
else
""
in
Sys.command (sprintf "%s %s %s" !command tmp redir)
with
| 0 ->
if not !Options.quiet then begin eprintf "\n"; flush stderr end
| n ->
if !ignore_bibtex_errors then begin
if not !Options.quiet then begin
eprintf "error %d (ignored)\n" n;
flush stderr
end
end else begin
eprintf "error %d while running bibtex\n" n;
exit n
end
let read_one_biblio lb =
let rec read_items acc lb =
try
let (_,k,_) as item = Bbl_lexer.bibitem lb in
if !Options.debug then begin eprintf "[%s]" k; flush stderr end;
read_items (item::acc) lb
with Bbl_lexer.End_of_biblio ->
List.rev acc
in
let name = Bbl_lexer.biblio_header lb in
let items = read_items [] lb in
(name,items)
let read_biblios lb =
let rec read acc lb =
try
let b = read_one_biblio lb in
read (b::acc) lb
with
End_of_file -> List.rev acc
in
read [] lb
let read_bbl tmp =
let fbbl = tmp ^ ".bbl" in
if not !Options.quiet then begin
eprintf "Reading %s..." fbbl; flush stderr
end;
let ch = open_in fbbl in
let lexbuf = Lexing.from_channel ch in
let biblios = read_biblios lexbuf in
close_in ch;
clean tmp;
if not !Options.quiet then begin
eprintf "ok ";
List.iter
(fun (_,items) -> eprintf "(%d entries)" (List.length items))
biblios;
eprintf "\n"; flush stderr
end;
biblios
let get_biblios fbib =
let tmp = Filename.temp_file "bib2html" "" in
try
create_aux_file fbib tmp;
call_bibtex tmp;
read_bbl tmp
with
e -> clean tmp; raise e
(*i
let insert_title_url bib =
let rec remove_assoc x = function
| [] ->
raise Not_found
| ((y,v) as p) :: l ->
if x = y then
(v,l)
else
let (v',l') = remove_assoc x l in (v', p :: l')
in
let url_value = function
| [Bibtex.Id u] -> u
| [Bibtex.String u] -> u
| _ -> raise Not_found
in
let modify_entry f =
try
let t,f' = remove_assoc "TITLE" f in
let u,f'' = remove_assoc "URL" f' in
let u' = Html.normalize_url (url_value u) in
let nt =
(Bibtex.String
(sprintf "\\begin{rawhtml}\\end{rawhtml}" u'))
:: t @ [Bibtex.String "\\begin{rawhtml}\\end{rawhtml}"]
in
("TITLE",nt) :: f''
with Not_found ->
f
in
Bibtex.fold
(fun com bib' -> match com with
| Bibtex.Entry (ty,k,f) ->
Bibtex.add_new_entry (Bibtex.Entry (ty,k,modify_entry f)) bib'
| _ ->
Bibtex.add_new_entry com bib')
bib Bibtex.empty_biblio
i*)
let parse_only = ref false
let print_keys = ref false
let translate fullname =
let input_bib = Readbib.read_entries_from_file fullname in
if !parse_only then exit 0;
let entries = List.rev (Expand.expand input_bib) in
let biblios =
if fullname = "" then begin
let tmp = Filename.temp_file "bibtex2htmlinput" ".bib" in
let ch = open_out tmp in
Biboutput.output_bib ~html:false ch input_bib None;
close_out ch;
let bbl = get_biblios tmp in
Sys.remove tmp;
bbl
end else
get_biblios fullname
in
let sb =
List.map
(fun (name,bibitems) -> (name,sort_entries entries bibitems))
biblios
in
if !print_keys then begin
List.iter
(fun (_,bibitems) ->
List.iter (fun (_,_,(_,k,_)) -> printf "%s\n" k) bibitems)
sb;
flush stdout;
exit 0
end;
format_list
(if !expand_abbrev_in_bib_output then
Bibtex.expand_abbrevs input_bib
else input_bib)
sb
(if !use_cite_file then
let keys =
List.fold_right
(fun s e -> Bibtex.KeySet.add s e) !citations Bibtex.KeySet.empty in
let keys =
List.fold_right
(fun s e -> Bibtex.KeySet.remove s e) !excluded keys in
Some (Bibfilter.saturate input_bib keys)
else None)
(*s Reading macros in a file. *)
let read_macros f =
let chan = open_in f in
let lb = Lexing.from_channel chan in
Latexscan.read_macros lb;
close_in chan
(*s Command line parsing. *)
let usage ?(error=true) () =
if error then prerr_endline "bibtex2html: bad command line syntax";
(if error then prerr_endline else print_endline) "
Usage: bibtex2html [filename]
-s style BibTeX style (plain, alpha, ...)
-c command BibTeX command (otherwise bibtex is searched in your path)
-d sort by date
-a sort as BibTeX (usually by author)
-u unsorted i.e. same order as in .bib file (default)
-r reverse the sort
-t title title of the HTML file (default is the filename)
-bg color background color of the HTML file (default is none)
-css file specify a style sheet file
-o file redirect the output
-footer additional footer in the HTML file
-i ignore BibTeX errors
-both produce versions with and without abstracts
-multiple produce one file per entry
-single produce a single page (with BibTeX input and output)
-nodoc only produces the body of the HTML documents
-nokeys do not print the BibTeX keys
-nolinks do not print any web link
-nobiblinks
do not add web links in the BibTeX output
-rawurl print URL instead of file type
-heveaurl use HeVeA's \\url macro
-noabstract
do not print the abstracts (if any)
-nokeywords
do not print the keywords (if any)
-nodoi do not insert the DOI links
-doi-prefix url
set the DOI links prefix (default is http://dx.doi.org/)
-linebreak add a linebreak between an entry and its links
-noheader do not print the header (bibtex2html command)
-nofooter do not print the footer (bibtex2html web link)
-noexpand do not expand abbreviations in the BibTeX output
-nobibsource
do not produce the BibTeX entries file
-fsuffix give an alternate suffix for HTML files
-lsuffix give an alternate suffix for HTML links
-suffix s give an alternate suffix for HTML files and links
-citefile f
read keys to include from file f
-e key exclude an entry
-m file read (La)TeX macros in file
-f field add a web link for that BibTeX field
-nf field name
add a web link for that BibTeX field, with the supplied name
-note field
declare a note field
-dl use DL lists instead of TABLEs
-labelname use the label name when inserting a link
--print-keys
print the sorted bibtex keys and exit
-debug verbose mode (to find incorrect BibTeX entries)
-q quiet mode
-w stop on warning
-v print version and exit
On-line documentation at http://www.lri.fr/~filliatr/bibtex2html/
";
exit (if error then 1 else 0)
let parse () =
let rec parse_rec = function
(* General aspect of the web page *)
| ("-t" | "-title" | "--title") :: s :: rem ->
title := s; title_spec := true; parse_rec rem
| ("-t" | "-title" | "--title") :: [] ->
usage()
| ("-bg" | "-background" | "--background") :: s :: rem ->
Html.bgcolor := Some s; parse_rec rem
| ("-bg" | "-background" | "--background") :: [] ->
usage()
| ("-css" | "-style-sheet" | "--style-sheet") :: f :: rem ->
Html.css := Some f; parse_rec rem
| ("-css" | "-style-sheet" | "--style-sheet") :: [] ->
usage()
| ("-footer" | "--footer") :: s :: rem ->
user_footer := s; parse_rec rem
| ("-footer" | "--footer") :: [] ->
usage()
| ("-s" | "-style" | "--style") :: s :: rem ->
style := s; parse_rec rem
| ("-s" | "-style" | "--style") :: [] ->
usage()
| ("-noabstract" | "-no-abstract" | "--no-abstract") :: rem ->
print_abstract := false; parse_rec rem
| ("-nodoi" | "-no-doi" | "--no-doi") :: rem ->
doi := false; parse_rec rem
| ("-doi-prefix" | "--doi-prefix") :: s :: rem ->
doi_prefix := s; parse_rec rem
| ("-doi-prefix" | "--doi-prefix") :: [] ->
usage ()
| ("-nokeywords" | "-no-keywords" | "--no-keywords") :: rem ->
print_keywords := false; parse_rec rem
| ("-nolinks" | "-no-links" | "--no-links") :: rem ->
print_links := false; parse_rec rem
| ("-nobiblinks" | "-no-bib-links" | "--no-bib-links") :: rem ->
links_in_bib_file := false; parse_rec rem
| ("-nokeys" | "-no-keys" | "--no-keys") :: rem ->
nokeys := true; table := NoTable; parse_rec rem
| ("-use-table" | "--use-table") :: rem ->
table := Table; parse_rec rem
| ("-usekeys" | "-use-keys" | "--use-keys") :: rem ->
use_keys := true; parse_rec rem
| ("-rawurl" | "-raw-url" | "--raw-url") :: rem ->
raw_url := true; parse_rec rem
(*i
| ("-tu" | "-titleurl" | "--title-url") :: rem ->
title_url := true; parse_rec rem
i*)
| ("-heveaurl" | "-hevea-url" | "--hevea-url") :: rem ->
Latexscan.hevea_url := true; parse_rec rem
| ("-linebreak" | "--linebreak") :: rem ->
linebreak := true; parse_rec rem
| ("-noheader" | "-no-header" | "--no-header") :: rem ->
print_header := false; parse_rec rem
| ("-nofooter" | "-no-footer" | "--no-footer") :: rem ->
print_footer := false; parse_rec rem
| ("-f" | "-field" | "--field") :: s :: rem ->
add_field s; parse_rec rem
| ("-f" | "-field" | "--field") :: [] ->
usage()
| ("-nf" | "-named-field" | "--named-field") :: s :: name :: rem ->
add_named_field s name; parse_rec rem
| ("-nf" | "-named-field" | "--named-field") :: ([_] | []) ->
usage()
| ("-note" | "--note") :: s :: rem ->
add_note_field s; parse_rec rem
| ("-note" | "--note") :: [] ->
usage()
| ("-ln" | "-labelname" | "--labelname" | "--label-name") :: rem ->
use_label_name := true; parse_rec rem
| ("-multiple" | "--multiple") :: rem ->
multiple := true; parse_rec rem
| ("-single" | "--single") :: rem ->
multiple := false; both := false; print_keywords := false;
bib_entries := false; single := true; parse_rec rem
| ("-both" | "--both") :: rem ->
both := true; parse_rec rem
| ("-dl" | "--dl") :: rem ->
table := DL; parse_rec rem
(* Controlling the translation *)
| ("-m" | "-macros-from" | "--macros-from") :: f :: rem ->
read_macros f; parse_rec rem
| ("-m" | "-macros-from" | "--macros-from") :: [] ->
usage()
(* Sorting the entries *)
| ("-d" | "-sort-by-date" | "--sort-by-date") :: rem ->
sort := By_date; parse_rec rem
| ("-a" | "-sort-as-bibtex" | "--sort-as-bibtex") :: rem ->
sort := By_author; parse_rec rem
| ("-u" | "-unsorted" | "--unsorted") :: rem ->
sort := Unsorted; parse_rec rem
| ("-r" | "-reverse-sort" | "--reverse-sort") :: rem ->
reverse_sort := true; parse_rec rem
(* Options for selecting keys *)
| ("-citefile" | "--citefile") :: f :: rem ->
use_cite_file := true;
add_citations f;
parse_rec rem
| ("-citefile" | "--citefile") :: [] ->
usage()
| ("-e" | "-exclude" | "--exclude") :: k :: rem ->
add_exclude k; parse_rec rem
| ("-e" | "-exclude" | "--exclude") :: [] ->
usage()
(* Miscellaneous options *)
| ("-o" | "-output" | "--output") :: f :: rem ->
output_file := f;
parse_rec rem
| ("-o" | "-output" | "--output") :: [] ->
usage()
| ("-nobibsource" | "--nobibsource") :: rem ->
bib_entries := false; parse_rec rem
| ("-nodoc" | "--nodoc" | "-no-doc" | "--no-doc") :: rem ->
nodoc := true; parse_rec rem
| ("-noexpand" | "-no-expand" | "--no-expand") :: rem ->
expand_abbrev_in_bib_output := false; parse_rec rem
| ("-i" | "-ignore-errors" | "--ignore-errors") :: rem ->
ignore_bibtex_errors := true; parse_rec rem
| ("-suffix" | "--suffix") :: s :: rem ->
file_suffix := s; link_suffix := s; parse_rec rem
| ("-fsuffix" | "-file-suffix" | "--file-suffix") :: s :: rem ->
file_suffix := s; parse_rec rem
| ("-lsuffix" | "-link-suffix" | "--link-suffix") :: s :: rem ->
link_suffix := s; parse_rec rem
| ("-suffix" | "--suffix" | "-fsuffix" | "--file-suffix" | "-file-suffix" |
"-lsuffix" | "-link-suffix" | "--link-suffix") :: [] ->
usage()
| ("-c" | "-command" | "--command") :: s :: rem ->
command := s; parse_rec rem
| ("-c" | "-command" | "--command") :: [] ->
usage()
| ("-h" | "-help" | "-?" | "--help") :: rem ->
usage ~error:false ()
| ("-v" | "-version" | "--version") :: _ ->
Copying.banner "bibtex2html"; exit 0
| ("-warranty" | "--warranty") :: _ ->
Copying.banner "bibtex2html"; Copying.copying(); exit 0
| ("-w" | "-warn-error" | "--warn-error") :: rem ->
Options.warn_error := true; parse_rec rem
| ("-q" | "-quiet" | "--quiet") :: rem ->
Options.quiet := true; parse_rec rem
| ("-debug" | "--debug") :: rem ->
Options.debug := true; parse_rec rem
| "-parse-only" :: rem ->
parse_only := true; parse_rec rem
| ("-print-keys" | "--print-keys") :: rem ->
print_keys := true; parse_rec rem
| [fbib] ->
if not (Sys.file_exists fbib) then begin
eprintf "%s: no such file\n" fbib;
exit 1
end;
let basename = Filename.basename fbib in
if Filename.check_suffix basename ".bib" then
(fbib, Filename.chop_suffix basename ".bib")
else begin
prerr_endline "bibtex2html: BibTeX file must have suffix .bib";
exit 1
end
| [] ->
("","")
| _ -> usage ()
in
parse_rec (List.tl (Array.to_list Sys.argv))
(*s Main function. *)
let main () =
let (fbib,f) = parse () in
Copying.banner "bibtex2html";
if fbib = "" then begin
if not !title_spec then title := "bibtex2html output";
begin match !output_file with
| "" -> bib_entries := false
| "-" -> output_file := ""; bib_entries := false
| _ -> ()
end
end else begin
input_file := f ^ ".bib";
begin match !output_file with
| "" -> output_file := f;
| "-" -> output_file := ""; bib_entries := false
| _ -> ()
end;
if not !title_spec then title := f
end;
Latexmacros.init_style_macros !style;
(* producing the documents *)
translate fbib
let _ = Printexc.catch main ()