(*
* 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: expand.ml,v 1.15 2006/05/15 09:45:53 filliatr Exp $ i*)
(*s Expansion of abbreviations in BibTeX databases. *)
open Format
open Bibtex
type fields = (string * string) list
type entry = entry_type * key * fields
let abbrev_table = Hashtbl.create 97
let add_abbrev a s = Hashtbl.add abbrev_table a s
let find_abbrev s = Hashtbl.find abbrev_table s
(* months are predefined abbreviations *)
let () =
List.iter (fun (id,m) -> add_abbrev id m)
[ "JAN", "January" ;
"FEB", "February" ;
"MAR", "March" ;
"APR", "April" ;
"MAY", "May" ;
"JUN", "June" ;
"JUL", "July" ;
"AUG", "August" ;
"SEP", "September" ;
"OCT", "October" ;
"NOV", "November" ;
"DEC", "December" ]
let rec expand_list = function
| [] ->
""
| (Id s) :: rem ->
(try find_abbrev s with Not_found -> s) ^ (expand_list rem)
| (String s) :: rem ->
s ^ (expand_list rem)
let rec expand_fields = function
| [] ->
[]
| (n,l) :: rem ->
(n,expand_list l) :: (expand_fields rem)
let macros_in_preamble s =
try
let lb = Lexing.from_string s in Latexscan.read_macros lb
with _ -> ()
let rec expand biblio =
Bibtex.fold
(fun command accu ->
match command with
| Abbrev (a,l) ->
let s = expand_list l in
add_abbrev a s;
accu
| Entry (t,k,f) ->
(t,k,expand_fields f) :: accu
| Preamble l ->
let s = expand_list l in
macros_in_preamble s;
accu
| Comment _ -> accu)
biblio
[]
(*s Sort BibTeX entries by decreasing dates. *)
let int_of_month = function
| "Janvier" | "January" -> 0
| "Février" | "February" -> 1
| "Mars" | "March" -> 2
| "Avril" | "April" -> 3
| "Mai" | "May" -> 4
| "Juin" | "June" -> 5
| "Juillet" | "July" -> 6
| "Août" | "August" -> 7
| "Septembre" | "September" -> 8
| "Octobre" | "October" -> 9
| "Novembre" | "November" -> 10
| "Décembre" | "December" -> 11
| _ -> invalid_arg "int_of_month"
let month_day_re1 = Str.regexp "\\([a-zA-Z]+\\)\\( \\|~\\)\\([0-9]+\\)"
let month_day_re2 = Str.regexp "\\([0-9]+\\)\\( \\|~\\)\\([a-zA-Z]+\\)"
let month_anything = Str.regexp "\\([a-zA-Z]+\\)"
let parse_month m =
if Str.string_match month_day_re1 m 0 then
int_of_month (Str.matched_group 1 m), int_of_string (Str.matched_group 3 m)
else if Str.string_match month_day_re2 m 0 then
int_of_month (Str.matched_group 3 m), int_of_string (Str.matched_group 1 m)
else if Str.string_match month_anything m 0 then
int_of_month (Str.matched_group 1 m), 1
else
int_of_month m, 1
type date = { year : int; month : int; day : int }
let dummy_date = { year = 0; month = 0; day = 0 }
let extract_year k f =
try
int_of_string (List.assoc "YEAR" f)
with Failure "int_of_string" ->
if not !Options.quiet then
eprintf "Warning: incorrect year in entry %s@." k;
if !Options.warn_error then exit 2;
0
let extract_month k f =
try
parse_month (List.assoc "MONTH" f)
with
| Not_found ->
0,1
| _ ->
if not !Options.quiet then
eprintf "Warning: incorrect month in entry %s\n" k;
if !Options.warn_error then exit 2;
0,1
let rec find_entry k = function
| [] -> raise Not_found
| (_,k',_) as e :: r -> if k = k' then e else find_entry k r
let rec extract_date el (_,k,f) =
try
let y = extract_year k f in
let m,d = extract_month k f in
(* eprintf "extract_date: year = %d month = %d day = %d@." y m d; *)
{ year = y; month = m; day = d }
with Not_found ->
try extract_date el (find_entry (List.assoc "CROSSREF" f) el)
with Not_found -> dummy_date
let date_order el e1 e2 =
let d1 = extract_date el e1 in
let d2 = extract_date el e2 in
(d1.year < d2.year) ||
(d1.year == d2.year && d1.month < d2.month) ||
(d1.year == d2.year && d1.month == d2.month && d1.day < d2.day)
(*s Access to the fields. *)
let get_field (_,_,f) s = List.assoc (String.uppercase s) f
let get_uppercase_field (_,_,f) s = List.assoc s f
let get_title e = get_uppercase_field e "TITLE"
let get_year e = get_uppercase_field e "YEAR"
let get_month e = get_uppercase_field e "MONTH"
let get_author e = get_uppercase_field e "AUTHOR"