1(**************************************************************************)
2(*  bibtex2html - A BibTeX to HTML translator                             *)
3(*  Copyright (C) 1997-2014 Jean-Christophe Filliâtre and Claude Marché   *)
4(*                                                                        *)
5(*  This software is free software; you can redistribute it and/or        *)
6(*  modify it under the terms of the GNU General Public                   *)
7(*  License version 2, as published by the Free Software Foundation.      *)
8(*                                                                        *)
9(*  This software is distributed in the hope that it will be useful,      *)
10(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
11(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                  *)
12(*                                                                        *)
13(*  See the GNU General Public License version 2 for more details         *)
14(*  (enclosed in the file GPL).                                           *)
15(**************************************************************************)
16
17(*s Filtering and saturating BibTeX files. *)
18
19open Printf
20open Bibtex
21
22let debug = false
23
24(*s [filter bib f] returns the list of keys of [bib] whose fields
25    satisfy the filter criterion [f] *)
26
27let filter biblio criterion =
28  Bibtex.fold
29    (fun entry keys ->
30       match entry with
31	   Entry(entry_type,key,fields)
32	     when criterion entry_type key fields ->
33	       KeySet.add key keys
34	 | _ -> keys)
35    biblio
36    KeySet.empty
37
38
39(*s [needed_keys biblio field value keys] returns the set of keys
40    [keys] augmented with the needed keys for [value] *)
41
42let rec needed_keys_for_field biblio field value keys abbrevs =
43  if field = "crossref"
44  then
45    match value with
46	[String(s)] ->
47	  if not (KeySet.mem s keys) then
48	    begin
49	      try
50		let e = find_entry s biblio
51		in
52		if debug then begin
53		  eprintf "We need additional crossref %s\n" s
54		end;
55		needed_keys_for_entry biblio (KeySet.add s keys) abbrevs e
56	      with Not_found ->
57		if not !Options.quiet then
58		  eprintf "Warning: cross-reference \"%s\" not found.\n" s;
59		if !Options.warn_error then exit 2;
60		(keys,abbrevs)
61	    end
62	  else (keys,abbrevs)
63      | _ ->
64	  if not !Options.quiet then
65	    eprintf "Warning: cross-references must be constant strings\n";
66	  if !Options.warn_error then exit 2;
67	  (keys,abbrevs)
68  else
69    List.fold_right
70      (fun a (keys,abbrevs) ->
71	 match a with
72	     Id(id) ->
73	       let id = String.lowercase_ascii id in
74	       if not (KeySet.mem id abbrevs)
75	       then
76		 try
77		   let e = find_abbrev id biblio in
78		   if debug then begin
79		     eprintf "We need additional abbrev %s\n" id
80		   end;
81		   needed_keys_for_entry biblio keys (KeySet.add id abbrevs) e
82		 with Not_found ->
83		   if abbrev_is_implicit id then (keys,abbrevs)
84		   else
85		     begin
86		       if not !Options.quiet then
87			 eprintf "Warning: string \"%s\" not found.\n" id;
88		       if !Options.warn_error then exit 2;
89		       (keys,abbrevs)
90		     end
91	       else (keys,abbrevs)
92	   | _ -> (keys,abbrevs))
93      value
94      (keys,abbrevs)
95
96and needed_keys_for_entry biblio keys abbrevs = function
97    Entry(entry_type,key,fields) ->
98      List.fold_right
99	(fun (field,value) (keys,abbrevs) ->
100           (*i eprintf "Field : %s\n" field; i*)
101	   needed_keys_for_field biblio field value keys abbrevs)
102	fields
103	(keys,abbrevs)
104  | Abbrev(field,value) ->
105      needed_keys_for_field biblio field value keys abbrevs
106  | _ -> (keys,abbrevs)
107
108
109(*s [saturate bib l] returns the smallest part of the bibliography
110    [bib] containing all the keys in l together with all the necessary
111    abbreviation strings and cross-references *)
112
113let saturate biblio s =
114  let (keys,abbrevs) =
115    Bibtex.fold
116      (fun entry (keys,abbrevs) ->
117	 match entry with
118	   | Entry(_,key,_) as e when KeySet.mem key s ->
119	       needed_keys_for_entry biblio keys abbrevs e
120	   | _ -> (keys,abbrevs))
121      biblio
122      (s,KeySet.empty)
123  in
124  KeySet.union keys abbrevs
125