(* * 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: bib2bib.ml,v 1.23 2006-11-02 11:58:40 filliatr Exp $ i*) open Printf open Bibtex (* command-line arguments *) let input_file_names = ref ([] : string list) let bib_output_file_name = ref "" let cite_output_file_name = ref "" let get_input_file_name f = input_file_names := f :: !input_file_names let condition = ref Condition.True let add_condition c = try let c = Parse_condition.condition c in condition := if !condition = Condition.True then c else Condition.And(!condition,c) with Condition_lexer.Lex_error msg -> prerr_endline ("Lexical error in condition: "^msg); exit 1 | Parsing.Parse_error -> prerr_endline "Syntax error in condition"; exit 1 let expand_abbrevs = ref false let sort_criteria = ref [] let reverse_sort = ref false let args_spec = [ ("-ob", Arg.String (fun f -> bib_output_file_name := f), "bib output file name"); ("-oc", Arg.String (fun f -> cite_output_file_name := f), "citations output file name"); ("-c", Arg.String (add_condition),"filter condition"); ("-w", Arg.Set Options.warn_error, "stop on warning"); ("-d", Arg.Set Options.debug, "debug flag"); ("-q", Arg.Set Options.quiet, "quiet flag"); ("-s", Arg.String (fun s -> sort_criteria := (String.uppercase s):: !sort_criteria), "sort with respect to keys or a given field"); ("-r", Arg.Set reverse_sort, "reverse the sort order"); ("--expand", Arg.Unit (fun () -> expand_abbrevs := true), "expand the abbreviations"); ("--version", Arg.Unit (fun () -> Copying.banner "bib2bib"; exit 0), "print version and exit"); ("--warranty", Arg.Unit (fun () -> Copying.banner "bib2bib"; Copying.copying(); exit 0), "display software warranty") ] let output_cite_file keys = if !cite_output_file_name = "" then prerr_endline "No citation file output (no file name specified)" else try let ch = open_out !cite_output_file_name in KeySet.iter (fun k -> output_string ch (k ^ "\n")) keys; close_out ch with Sys_error msg -> prerr_endline ("Cannot write output citations file (" ^ msg ^ ")"); exit 1 let output_bib_file biblio keys = try let ch = if !bib_output_file_name = "" then stdout else open_out !bib_output_file_name in let cmd = List.fold_right (fun s t -> if String.contains s ' ' then if String.contains s '\'' then " \"" ^ s ^ "\"" ^ t else " '" ^ s ^ "'" ^ t else " " ^ s ^ t) (Array.to_list Sys.argv) "" in let comments = add_new_entry (Comment ("Command line:" ^ cmd)) (add_new_entry (Comment ("This file has been generated by bib2bib " ^ Version.version)) empty_biblio) in let biblio = merge_biblios comments biblio in Biboutput.output_bib ~html:false ch biblio keys; if !bib_output_file_name <> "" then close_out ch with Sys_error msg -> prerr_endline ("Cannot write output bib file (" ^ msg ^ ")"); exit 1 let rec make_compare_fun criteria c1 c2 = match criteria with | [] -> 0 | field :: rem -> let comp = match field with | "$KEY" -> begin match (c1,c2) with | (Abbrev(s1,_),Abbrev(s2,_)) | (Entry(_,s1,_),Entry(_,s2,_)) -> compare s1 s2 | _ -> 0 end | "$TYPE" -> begin match (c1,c2) with | (Entry(s1,_,_),Entry(s2,_,_)) -> compare s1 s2 | _ -> 0 end | _ -> begin match (c1,c2) with | (Entry(_,_,l1),Entry(_,_,l2)) -> let s1 = try match List.assoc field l1 with | [Bibtex.String(s)] -> s | [Bibtex.Id(s)] -> s | _ -> "" with Not_found -> "" and s2 = try match List.assoc field l2 with | [Bibtex.String(s)] -> s | [Bibtex.Id(s)] -> s | _ -> "" with Not_found -> "" in compare s1 s2 | _ -> 0 end in if comp = 0 then make_compare_fun rem c1 c2 else if !reverse_sort then -comp else comp ;; let usage = "Usage: bib2bib [options] \nOptions are:" let main () = Arg.parse args_spec get_input_file_name usage; Copying.banner "bib2bib"; if !Options.debug then begin eprintf "command line:\n"; for i = 0 to pred (Array.length Sys.argv) do eprintf "%s\n" Sys.argv.(i) done; end; if !input_file_names = [] then input_file_names := [""]; if !Options.debug then begin Condition.print !condition; printf "\n" end; let all_entries = List.fold_right (fun file accu -> merge_biblios accu (Readbib.read_entries_from_file file)) !input_file_names empty_biblio in let expanded = Bibtex.expand_abbrevs all_entries in let matching_keys = Bibfilter.filter (Bibtex.expand_crossrefs expanded) (fun e k f -> Condition.evaluate_cond e k f !condition) in if KeySet.cardinal matching_keys = 0 then begin eprintf "Warning: no matching reference found.\n"; if !Options.warn_error then exit 2; end; let user_expanded = if !expand_abbrevs then expanded else all_entries in let needed_keys = Bibfilter.saturate user_expanded matching_keys in (* this should be to right place to sort the output bibliography *) let final_bib = if !sort_criteria = [] then user_expanded else let comp = make_compare_fun (List.rev !sort_criteria) in eprintf "Sorting..."; let b = Bibtex.sort comp user_expanded in eprintf "done.\n"; b in output_cite_file matching_keys; output_bib_file final_bib (Some needed_keys) let _ = Printexc.catch main ()