+end
+let is_nil t = t == nil
+
+let is_node t = t != nil
+let is_root t = t == root
+
+let node_of_t t =
+ let _ = Tag.init (Obj.magic t) in
+ let c,n,d,f = collect_tags t
+ in
+ { doc= t;
+ children = c;
+ siblings = n;
+ descendants = d;
+ followings = f
+
+ }
+
+let finalize _ = Printf.eprintf "Release the string list !\n%!"
+;;
+
+let parse f str =
+ node_of_t
+ (f str
+ !Options.sample_factor
+ !Options.index_empty_texts
+ !Options.disable_text_collection)
+
+let parse_xml_uri str = parse parse_xml_uri str
+let parse_xml_string str = parse parse_xml_string str
+
+let size t = tree_size t.doc;;
+
+external pool : tree -> Tag.pool = "%identity"
+
+let magic_string = "SXSI_INDEX"
+let version_string = "3"
+
+let pos fd =
+ Unix.lseek fd 0 Unix.SEEK_CUR
+
+let pr_pos fd = Printf.eprintf "At position %i\n%!" (pos fd)
+
+let write fd s =
+ let sl = String.length s in
+ let ssl = Printf.sprintf "%020i" sl in
+ ignore (Unix.write fd ssl 0 20);
+ ignore (Unix.write fd s 0 (String.length s))
+
+let rec really_read fd buffer start length =
+ if length <= 0 then () else
+ match Unix.read fd buffer start length with
+ 0 -> raise End_of_file
+ | r -> really_read fd buffer (start + r) (length - r);;
+
+let read fd =
+ let buffer = String.create 20 in
+ let _ = really_read fd buffer 0 20 in
+ let size = int_of_string buffer in
+ let buffer = String.create size in
+ let _ = really_read fd buffer 0 size in
+ buffer
+
+let save_tag_table channel t =
+ let t = Array.map (fun s -> Array.of_list (Ptset.Int.elements s)) t in
+ Marshal.to_channel channel t []
+
+let save t str =
+ let fd = Unix.openfile str [ Unix.O_WRONLY;Unix.O_TRUNC;Unix.O_CREAT] 0o644 in
+ let out_c = Unix.out_channel_of_descr fd in
+ let _ = set_binary_mode_out out_c true in
+ output_string out_c magic_string;
+ output_char out_c '\n';
+ output_string out_c version_string;
+ output_char out_c '\n';
+ save_tag_table out_c t.children;
+ save_tag_table out_c t.siblings;
+ save_tag_table out_c t.descendants;
+ save_tag_table out_c t.followings;
+ (* we need to move the fd to the correct position *)
+ flush out_c;
+ ignore (Unix.lseek fd (pos_out out_c) Unix.SEEK_SET);
+ tree_save t.doc fd str;
+ close_out out_c
+;;
+let load_tag_table channel =
+ let table : int array array = Marshal.from_channel channel in
+ Array.map (fun a -> Ptset.Int.from_list (Array.to_list a)) table
+
+let load ?(sample=64) ?(load_text=true) str =
+ let fd = Unix.openfile str [ Unix.O_RDONLY ] 0o644 in
+ let in_c = Unix.in_channel_of_descr fd in
+ let _ = set_binary_mode_in in_c true in
+ let load_table () =
+ (let ms = input_line in_c in if ms <> magic_string then failwith "Invalid index file");
+ (let vs = input_line in_c in if vs <> version_string then failwith "Invalid version file");
+ let c = load_tag_table in_c in
+ let s = load_tag_table in_c in
+ let d = load_tag_table in_c in
+ let f = load_tag_table in_c in
+ c,s,d,f
+ in
+ let _ = Printf.eprintf "\nLoading tag table : " in
+ let c,s,d,f = time (load_table) () in
+ ignore(Unix.lseek fd (pos_in in_c) Unix.SEEK_SET);
+ let tree = { doc = tree_load fd str load_text sample;
+ children = c;
+ siblings = s;
+ descendants = d;
+ followings = f
+ }
+ in close_in in_c;
+ tree
+
+
+
+
+let tag_pool t = pool t.doc
+
+let compare = compare_node
+
+let equal a b = a == b
+
+let nts = function
+ -1 -> "Nil"
+ | i -> Printf.sprintf "Node (%i)" i
+
+let dump_node t = nts (inode t)
+
+let is_left t n = tree_is_first_child t.doc n
+
+
+
+let is_below_right t n1 n2 =
+ tree_is_ancestor t.doc (tree_parent t.doc n1) n2
+ && not (tree_is_ancestor t.doc n1 n2)
+
+let is_binary_ancestor t n1 n2 =
+ let p = tree_parent t.doc n1 in
+ let fin = tree_closing t.doc p in
+ n2 > n1 && n2 < fin
+(* (is_below_right t n1 n2) ||
+ (tree_is_ancestor t.doc n1 n2) *)
+
+let parent t n = tree_parent t.doc n
+
+let first_child t = let doc = t.doc in ();fun n -> tree_first_child doc n
+let first_element t = let doc = t.doc in (); fun n -> tree_first_element doc n
+let first_element t n = tree_first_element t.doc n
+(* these function will be called in two times: first partial application
+ on the tag, then application of the tag and the tree, then application of
+ the other arguments. We use the trick to let the compiler optimize application
+*)
+
+let tagged_child t tag = () ; fun n -> tree_tagged_child t.doc n tag
+
+let select_child t = fun ts ->
+ let v = ptset_to_vector ts in ();
+ fun n -> tree_select_child t.doc n v
+
+let next_sibling t = let doc = t.doc in (); fun n -> tree_next_sibling doc n
+let next_element t = let doc = t.doc in (); fun n -> tree_next_element doc n
+let next_element t n = tree_next_element t.doc n
+
+let tagged_following_sibling t tag = (); fun n -> tree_tagged_following_sibling t.doc n tag
+
+let select_following_sibling t = fun ts ->
+ let v = (ptset_to_vector ts) in ();
+ fun n -> tree_select_following_sibling t.doc n v
+
+let next_sibling_below t = (); fun n _ -> tree_next_sibling t.doc n
+let next_element_below t = (); fun n _ -> tree_next_element t.doc n
+
+let tagged_following_sibling_below t tag = (); fun n _ -> tree_tagged_following_sibling t.doc n tag
+
+let select_following_sibling_below t = fun ts ->
+ let v = (ptset_to_vector ts) in ();
+ fun n _ -> tree_select_following_sibling t.doc n v
+
+let id t n = tree_node_xml_id t.doc n
+
+let tag t n = if n == nil then Tag.nullt else tree_tag t.doc n
+
+let tagged_descendant t tag =
+ let doc = t.doc in (); fun n -> tree_tagged_descendant doc n tag
+
+let select_descendant t = fun ts ->
+ let v = (ptset_to_vector ts) in ();
+ fun n -> tree_select_descendant t.doc n v
+
+let tagged_following_below t tag =
+ let doc = t.doc in
+ (); fun n ctx -> tree_tagged_following_below doc n tag ctx
+
+let select_following_below t = fun ts ->
+ let v = (ptset_to_vector ts) in ();
+ fun n ctx -> tree_select_following_below t.doc n v ctx
+
+let closing t n = tree_closing t.doc n
+let is_open t n = tree_is_open t.doc n
+let get_text_id t n = tree_my_text t.doc n
+
+let last_idx = ref 0
+let array_find a i j =
+ let l = Array.length a in
+ let rec loop idx x y =
+ if x > y || idx >= l then nil