207 lines
7.2 KiB
OCaml
207 lines
7.2 KiB
OCaml
(* Copyright (c) 1998-2007 INRIA *)
|
|
|
|
open Gwcomp
|
|
|
|
(** Checks a .gwo header and prints fails if header is absent or not compatible. *)
|
|
let check_magic fname ic =
|
|
let b = really_input_string ic (String.length magic_gwo) in
|
|
if b <> magic_gwo then
|
|
if String.sub magic_gwo 0 4 = String.sub b 0 4 then
|
|
failwith ("\"" ^ fname ^ "\" is a GeneWeb object file, but not compatible")
|
|
else
|
|
failwith
|
|
("\"" ^ fname
|
|
^ "\" is not a GeneWeb object file, or it is a very old version")
|
|
|
|
(** [next_family_fun_templ gwo_list fi] creates a function that read
|
|
sucessivly a [Gwcomp.gw_syntax] for all .gwo files. In details it does :
|
|
|
|
- Switch to the next element in the [gwo_list] if reached the end
|
|
of the current file. Each element is [(gwo,separate, bnotes, shift)]
|
|
where [gwo] is .gwo filename and [separate], [bnotes], [shift] are
|
|
captured options from command line related to the giving file.
|
|
- Modify [fi] with mentioned previusly information if needed.
|
|
- Start/continue to read current .gwo file content and return
|
|
[Gwcomp.gw_syntax]. [None] is returned when reading of the last
|
|
.gwo file reaches end of file *)
|
|
let next_family_fun_templ gwo_list fi =
|
|
let ngwo = List.length gwo_list in
|
|
let run =
|
|
if ngwo < 10 || not !Mutil.verbose then fun () -> ()
|
|
else if ngwo < 60 then (fun () ->
|
|
Printf.eprintf ".";
|
|
flush stderr)
|
|
else
|
|
let bar_cnt = ref 0 in
|
|
let run () =
|
|
ProgrBar.run !bar_cnt ngwo;
|
|
incr bar_cnt
|
|
in
|
|
ProgrBar.empty := 'o';
|
|
ProgrBar.full := '*';
|
|
ProgrBar.start ();
|
|
run
|
|
in
|
|
let ic_opt = ref None in
|
|
let gwo_list = ref gwo_list in
|
|
fun () ->
|
|
let rec loop () =
|
|
let r =
|
|
match !ic_opt with
|
|
| Some ic -> (
|
|
match
|
|
try Some (input_value ic : gw_syntax) with End_of_file -> None
|
|
with
|
|
| Some fam -> Some fam
|
|
| None ->
|
|
close_in ic;
|
|
ic_opt := None;
|
|
None)
|
|
| None -> None
|
|
in
|
|
let bnotes_of_string = function
|
|
| "merge" -> `merge
|
|
| "erase" -> `erase
|
|
| "first" -> `first
|
|
| "drop" -> `drop
|
|
| _ -> assert false
|
|
in
|
|
match r with
|
|
| Some fam -> Some fam
|
|
| None -> (
|
|
(* switch to the next .gwo file *)
|
|
match !gwo_list with
|
|
| (x, separate, bnotes, shift) :: rest ->
|
|
run ();
|
|
gwo_list := rest;
|
|
let ic = open_in_bin x in
|
|
check_magic x ic;
|
|
fi.Db1link.f_curr_src_file <- input_value ic;
|
|
fi.Db1link.f_curr_gwo_file <- x;
|
|
fi.Db1link.f_separate <- separate;
|
|
fi.Db1link.f_bnotes <- bnotes_of_string bnotes;
|
|
fi.Db1link.f_shift <- shift;
|
|
Hashtbl.clear fi.Db1link.f_local_names;
|
|
ic_opt := Some ic;
|
|
loop ()
|
|
| [] ->
|
|
if ngwo < 10 || not !Mutil.verbose then ()
|
|
else if ngwo < 60 then (
|
|
Printf.eprintf "\n";
|
|
flush stderr)
|
|
else ProgrBar.finish ();
|
|
None)
|
|
in
|
|
loop ()
|
|
|
|
let just_comp = ref false
|
|
let out_file = ref (Filename.concat Filename.current_dir_name "a")
|
|
let force = ref false
|
|
let separate = ref false
|
|
let bnotes = ref "merge"
|
|
let shift = ref 0
|
|
let files = ref []
|
|
|
|
let speclist =
|
|
[
|
|
( "-bnotes",
|
|
Arg.Set_string bnotes,
|
|
"[drop|erase|first|merge] Behavior for base notes of the next file. \
|
|
[drop]: dropped. [erase]: erase the current content. [first]: dropped \
|
|
if current content is not empty. [merge]: concatenated to the current \
|
|
content. Default: " ^ !bnotes ^ "" );
|
|
("-c", Arg.Set just_comp, " Only compiling");
|
|
("-cg", Arg.Set Db1link.do_consang, " Compute consanguinity");
|
|
( "-ds",
|
|
Arg.Set_string Db1link.default_source,
|
|
"<str> Set the source field for persons and families without source data"
|
|
);
|
|
("-f", Arg.Set force, " Remove database if already existing");
|
|
("-mem", Arg.Set Outbase.save_mem, " Save memory, but slower");
|
|
("-nc", Arg.Clear Db1link.do_check, " No consistency check");
|
|
("-nofail", Arg.Set Gwcomp.no_fail, " No failure in case of error");
|
|
("-nolock", Arg.Set Lock.no_lock_flag, " Do not lock database");
|
|
( "-nopicture",
|
|
Arg.Set Gwcomp.no_picture,
|
|
" Do not create associative pictures" );
|
|
( "-o",
|
|
Arg.Set_string out_file,
|
|
"<file> Output database (default: a.gwb). Alphanumerics and -" );
|
|
( "-particles",
|
|
Arg.Set_string Db1link.particules_file,
|
|
"<file> Particles file (default = predefined particles)" );
|
|
("-q", Arg.Clear Mutil.verbose, " Quiet");
|
|
("-sep", Arg.Set separate, " Separate all persons in next file");
|
|
("-sh", Arg.Set_int shift, "<int> Shift all persons numbers in next files");
|
|
("-stats", Arg.Set Db1link.pr_stats, " Print statistics");
|
|
("-v", Arg.Set Mutil.verbose, " Verbose");
|
|
]
|
|
|> List.sort compare |> Arg.align
|
|
|
|
let anonfun x =
|
|
let bn = !bnotes in
|
|
let sep = !separate in
|
|
if Filename.check_suffix x ".gw" then ()
|
|
else if Filename.check_suffix x ".gwo" then ()
|
|
else raise (Arg.Bad ("Don't know what to do with \"" ^ x ^ "\""));
|
|
separate := false;
|
|
bnotes := "merge";
|
|
files := (x, sep, bn, !shift) :: !files
|
|
|
|
let errmsg =
|
|
"Usage: gwc [options] [files]\n\
|
|
where [files] are a list of files:\n\
|
|
\ source files end with .gw\n\
|
|
\ object files end with .gwo\n\
|
|
and [options] are:"
|
|
|
|
let main () =
|
|
Mutil.verbose := false;
|
|
Arg.parse speclist anonfun errmsg;
|
|
if not (Mutil.good_name (Filename.basename !out_file)) then (
|
|
(* Util.transl conf not available !*)
|
|
Printf.eprintf "The database name \"%s\" contains a forbidden character./n"
|
|
!out_file;
|
|
Printf.eprintf "Allowed characters: a..z, A..Z, 0..9, -";
|
|
flush stdout;
|
|
exit 2);
|
|
Secure.set_base_dir (Filename.dirname !out_file);
|
|
let gwo = ref [] in
|
|
List.iter
|
|
(fun (x, separate, bnotes, shift) ->
|
|
if Filename.check_suffix x ".gw" then (
|
|
(try Gwcomp.comp_families x
|
|
with e ->
|
|
Printf.eprintf "File \"%s\", line %d:\n" x !line_cnt;
|
|
raise e);
|
|
gwo := (x ^ "o", separate, bnotes, shift) :: !gwo)
|
|
else if Filename.check_suffix x ".gwo" then
|
|
gwo := (x, separate, bnotes, shift) :: !gwo
|
|
else raise (Arg.Bad ("Don't know what to do with \"" ^ x ^ "\"")))
|
|
(List.rev !files);
|
|
if not !just_comp then (
|
|
let bdir =
|
|
if Filename.check_suffix !out_file ".gwb" then !out_file
|
|
else !out_file ^ ".gwb"
|
|
in
|
|
if (not !force) && Sys.file_exists bdir then (
|
|
Printf.eprintf
|
|
"The database \"%s\" already exists. Use option -f to overwrite it."
|
|
!out_file;
|
|
flush stdout;
|
|
exit 2);
|
|
Lock.control (Mutil.lock_file !out_file)
|
|
false ~onerror:Lock.print_error_and_exit (fun () ->
|
|
let bdir =
|
|
if Filename.check_suffix !out_file ".gwb" then !out_file
|
|
else !out_file ^ ".gwb"
|
|
in
|
|
let next_family_fun = next_family_fun_templ (List.rev !gwo) in
|
|
if Db1link.link next_family_fun bdir then ()
|
|
else (
|
|
Printf.eprintf "*** database not created\n";
|
|
flush stderr;
|
|
exit 2)))
|
|
|
|
let _ = main ()
|