|
| 1 | +open Geneweb |
| 2 | +open Def |
| 3 | +open Dbdisk |
| 4 | + |
| 5 | +let fast = ref true |
| 6 | +let step_strings = ref false |
| 7 | +let step_persons = ref false |
| 8 | +let step_families = ref false |
| 9 | + |
| 10 | +let load_array a = if !fast then a.load_array () |
| 11 | +let clear_array a = a.clear_array () |
| 12 | + |
| 13 | +let split_sname base i = Mutil.split_sname @@ base.data.strings.get i |
| 14 | +let split_fname base i = Mutil.split_fname @@ base.data.strings.get i |
| 15 | + |
| 16 | +let scan base string person family = |
| 17 | + let mark t i = try t.(i) <- true with _ -> failwith @@ string_of_int i in |
| 18 | + if !step_strings then begin |
| 19 | + load_array base.data.strings ; |
| 20 | + let rev = Hashtbl.create base.data.strings.len in |
| 21 | + for i = 0 to base.data.strings.len - 1 do |
| 22 | + Hashtbl.add rev (base.data.strings.get i) i |
| 23 | + done ; |
| 24 | + let opt_mark t s = match Hashtbl.find_opt rev s with Some x -> mark t x | None -> () in |
| 25 | + let t = Array.make base.data.strings.len false in |
| 26 | + load_array base.data.persons ; |
| 27 | + for i = 0 to base.data.persons.len - 1 do |
| 28 | + let p = base.data.persons.get i in |
| 29 | + mark t p.first_name ; |
| 30 | + List.iter (opt_mark t) (split_fname base p.first_name) ; |
| 31 | + mark t p.surname ; |
| 32 | + List.iter (opt_mark t) (split_sname base p.surname) ; |
| 33 | + opt_mark t @@ Name.concat (base.data.strings.get p.first_name) (base.data.strings.get p.surname) ; |
| 34 | + mark t p.image ; |
| 35 | + mark t p.public_name ; |
| 36 | + List.iter (mark t) p.qualifiers ; |
| 37 | + List.iter (mark t) p.aliases ; |
| 38 | + List.iter (mark t) p.first_names_aliases ; |
| 39 | + List.iter (mark t) p.surnames_aliases ; |
| 40 | + List.iter begin fun {t_name;t_ident;t_place; _ } -> |
| 41 | + mark t t_ident ; |
| 42 | + mark t t_place ; |
| 43 | + (match t_name with Tname i -> mark t i | _ -> ()) ; |
| 44 | + end p.titles ; |
| 45 | + mark t p.occupation ; |
| 46 | + mark t p.birth_place ; |
| 47 | + mark t p.birth_note ; |
| 48 | + mark t p.birth_src ; |
| 49 | + mark t p.baptism_place ; |
| 50 | + mark t p.baptism_note ; |
| 51 | + mark t p.baptism_src ; |
| 52 | + mark t p.death_place ; |
| 53 | + mark t p.death_note ; |
| 54 | + mark t p.death_src ; |
| 55 | + mark t p.burial_place ; |
| 56 | + mark t p.burial_note ; |
| 57 | + mark t p.burial_src ; |
| 58 | + mark t p.notes ; |
| 59 | + mark t p.psources ; |
| 60 | + List.iter (fun {r_sources;_} -> mark t r_sources) p.rparents ; |
| 61 | + List.iter begin fun {epers_name;epers_place;epers_reason;epers_note;epers_src;_} -> |
| 62 | + (match epers_name with Epers_Name i -> mark t i | _ -> ()) ; |
| 63 | + mark t epers_place ; |
| 64 | + mark t epers_reason ; |
| 65 | + mark t epers_note ; |
| 66 | + mark t epers_src ; |
| 67 | + end p.pevents |
| 68 | + done ; |
| 69 | + clear_array base.data.persons ; |
| 70 | + load_array base.data.families ; |
| 71 | + for i = 0 to base.data.families.len - 1 do |
| 72 | + let f = base.data.families.get i in |
| 73 | + mark t f.marriage_place ; |
| 74 | + mark t f.marriage_note ; |
| 75 | + mark t f.marriage_src ; |
| 76 | + mark t f.comment ; |
| 77 | + mark t f.origin_file ; |
| 78 | + mark t f.fsources ; |
| 79 | + List.iter begin fun {efam_name;efam_place;efam_reason;efam_note;efam_src;_} -> |
| 80 | + (match efam_name with Efam_Name i -> mark t i | _ -> ()) ; |
| 81 | + mark t efam_place ; |
| 82 | + mark t efam_reason ; |
| 83 | + mark t efam_note ; |
| 84 | + mark t efam_src ; |
| 85 | + end f.fevents |
| 86 | + done ; |
| 87 | + clear_array base.data.families ; |
| 88 | + clear_array base.data.strings ; |
| 89 | + string base t |
| 90 | + end ; |
| 91 | + if !step_persons then begin |
| 92 | + load_array base.data.persons ; |
| 93 | + let t = Array.make base.data.persons.len false in |
| 94 | + for i = 0 to base.data.persons.len - 1 do |
| 95 | + if (base.data.persons.get i).key_index <> Gwdb1.dummy_iper then mark t i |
| 96 | + done ; |
| 97 | + clear_array base.data.persons ; |
| 98 | + person base t |
| 99 | + end ; |
| 100 | + if !step_families then begin |
| 101 | + load_array base.data.families ; |
| 102 | + let t = Array.make base.data.families.len false in |
| 103 | + for i = 0 to base.data.families.len - 1 do |
| 104 | + if (base.data.families.get i).fam_index <> Gwdb1.dummy_ifam then mark t i |
| 105 | + done ; |
| 106 | + clear_array base.data.families ; |
| 107 | + family base t |
| 108 | + end |
| 109 | + |
| 110 | +let report base = |
| 111 | + let aux fn _base t = |
| 112 | + let cnt = ref 0 in |
| 113 | + for i = 0 to Array.length t - 1 do if not t.(i) then incr cnt done ; |
| 114 | + fn !cnt |
| 115 | + in |
| 116 | + scan |
| 117 | + base |
| 118 | + (aux @@ fun c -> Printf.printf "Number of unused strings: %d\n" c) |
| 119 | + (aux @@ fun c -> Printf.printf "Number of ghost persons: %d\n" c) |
| 120 | + (aux @@ fun c -> Printf.printf "Number of ghost families: %d\n" c) |
| 121 | + |
| 122 | +let dump base = |
| 123 | + let dump_istr base t = |
| 124 | + for i = 0 to Array.length t - 1 do |
| 125 | + if not t.(i) then begin |
| 126 | + Printf.printf "=== [START ISTR %d] ===\n%s\n=== [END ISTR %d] ===\n\n" i (base.data.strings.get i) i |
| 127 | + end |
| 128 | + done |
| 129 | + in |
| 130 | + let dump_iper _base t = |
| 131 | + for i = 0 to Array.length t - 1 do |
| 132 | + if not t.(i) then begin Printf.printf "Ghost person: %d\n" i end |
| 133 | + done |
| 134 | + in |
| 135 | + let dump_ifam _base t = |
| 136 | + for i = 0 to Array.length t - 1 do |
| 137 | + if not t.(i) then begin Printf.printf "Ghost family: %d\n" i end |
| 138 | + done |
| 139 | + in |
| 140 | + scan base dump_istr dump_iper dump_ifam |
| 141 | + |
| 142 | +let steps = ref "strings,persons,families" |
| 143 | +let bname = ref "" |
| 144 | +let action = ref None |
| 145 | +let usage = "Usage: " ^ Sys.argv.(0) ^ " [OPTION] ACTIOn base" |
| 146 | + |
| 147 | +let speclist = |
| 148 | + [ ( "-mem" |
| 149 | + , Arg.Clear fast |
| 150 | + , " slower, but use less memory" ) |
| 151 | + ; ( "-step" |
| 152 | + , Arg.Set_string steps |
| 153 | + , " STEPS steps to perform. Default is " ^ !steps ) |
| 154 | + ; ( "-report" |
| 155 | + , Arg.Unit (fun () -> action := Some `report) |
| 156 | + , " only report number of unused values" ) |
| 157 | + ; ( "-dump" |
| 158 | + , Arg.Unit (fun () -> action := Some `dump) |
| 159 | + , " dump unuse values" ) |
| 160 | + ] |
| 161 | + |
| 162 | +let _ = |
| 163 | + Arg.parse speclist (fun s -> bname := s) usage ; |
| 164 | + Secure.set_base_dir (Filename.dirname !bname) ; |
| 165 | + if !bname = "" then begin Arg.usage speclist usage ; exit 2 end; |
| 166 | + List.iter begin function |
| 167 | + | "strings" -> step_strings := true |
| 168 | + | "persons" -> step_persons := true |
| 169 | + | "families" -> step_families := true |
| 170 | + | _ -> Arg.usage speclist usage ; exit 2 |
| 171 | + end (String.split_on_char ',' !steps) ; |
| 172 | + Lock.control (Mutil.lock_file !bname) false ~onerror:Lock.print_try_again @@ fun () -> |
| 173 | + let base = Gwdb1.OfGwdb.base (Gwdb.open_base !bname) in |
| 174 | + match !action with |
| 175 | + | None -> Arg.usage speclist usage ; exit 2 |
| 176 | + | Some `dump -> dump base |
| 177 | + | Some `report -> report base |
0 commit comments