(* $Id: gwb2ged.ml,v 4.12 2004/12/14 09:30:09 ddr Exp $ *)
(* Copyright (c) 1998-2005 INRIA *)
open Def;
open Gutil;
open Printf;
value ascii = ref True;
value no_notes = ref False;
value month_txt =
[| "JAN"; "FEB"; "MAR"; "APR"; "MAY"; "JUN"; "JUL"; "AUG"; "SEP"; "OCT";
"NOV"; "DEC" |]
;
value french_txt =
[| "VEND"; "BRUM"; "FRIM"; "NIVO"; "PLUV"; "VENT"; "GERM"; "FLOR"; "PRAI";
"MESS"; "THER"; "FRUC"; "COMP" |]
;
value hebrew_txt =
[| "TSH"; "CSH"; "KSL"; "TVT"; "SHV"; "ADR"; "ADS"; "NSN"; "IYR"; "SVN";
"TMZ"; "AAV"; "ELL" |]
;
value ged_month cal m =
match cal with
[ Dgregorian | Djulian ->
if m >= 1 && m <= Array.length month_txt then month_txt.(m - 1)
else failwith "ged_month"
| Dfrench ->
if m >= 1 && m <= Array.length french_txt then french_txt.(m - 1)
else failwith "ged_month"
| Dhebrew ->
if m >= 1 && m <= Array.length hebrew_txt then hebrew_txt.(m - 1)
else failwith "ged_month" ]
;
value encode s = if ascii.val then s else Ansel.of_iso_8859_1 s;
value max_len = 78;
value next_char_pair_overflows s len i =
loop False (len + 1) (i + 1) where rec loop prec_was_space len i =
if len < max_len then
if i < String.length s then
match s.[i] with
[ ' ' | '\n' -> loop True (len + 1) (i + 1)
| _ ->
if prec_was_space then loop False (len + 1) (i + 1) else False ]
else False
else True
;
value br = "
";
value rec display_note_aux oc s len i =
if i == String.length s then fprintf oc "\n"
else
let c = if s.[i] = '\n' then ' ' else s.[i] in
if i <= String.length s - String.length br &&
String.lowercase (String.sub s i (String.length br)) = br then
do {
fprintf oc "\n2 CONT ";
let i = i + String.length br in
let i = if i < String.length s && s.[i] == '\n' then i + 1 else i in
display_note_aux oc s (String.length "2 CONT ") i
}
else
if
len == max_len || c <> ' ' && next_char_pair_overflows s len i then
do {
fprintf oc "\n2 CONC %c" c;
display_note_aux oc s (String.length "2 CONC .") (i + 1)
}
else do { output_char oc c; display_note_aux oc s (len + 1) (i + 1) }
;
value display_note oc s =
do {
fprintf oc "1 NOTE ";
display_note_aux oc (encode s) (String.length "1 NOTE ") 0;
}
;
value ged_header base oc ifile ofile =
do {
fprintf oc "0 HEAD\n";
fprintf oc "1 SOUR GeneWeb\n";
fprintf oc "2 VERS %s\n" Version.txt;
fprintf oc "2 NAME %s\n" (Filename.basename Sys.argv.(0));
fprintf oc "2 CORP INRIA\n";
fprintf oc "3 ADDR Domaine de Voluceau\n";
fprintf oc "4 CONT B.P 105 - Rocquencourt\n";
fprintf oc "4 CITY Le Chesnay Cedex\n";
fprintf oc "4 POST 78153\n";
fprintf oc "4 CTRY France\n";
fprintf oc "3 PHON +33 01 39 63 55 11\n";
fprintf oc "2 DATA %s\n"
(let fname = Filename.basename ifile in
if Filename.check_suffix fname ".gwb" then fname else fname ^ ".gwb");
try
let tm = Unix.localtime (Unix.time ()) in
let mon = ged_month Dgregorian (tm.Unix.tm_mon + 1) in
do {
fprintf oc "1 DATE %02d %s %d\n" tm.Unix.tm_mday mon
(1900 + tm.Unix.tm_year);
fprintf oc "2 TIME %02d:%02d:%02d\n" tm.Unix.tm_hour
tm.Unix.tm_min tm.Unix.tm_sec;
}
with _ ->
();
if ofile <> "" then
fprintf oc "1 FILE %s\n" (Filename.basename ofile)
else ();
fprintf oc "1 GEDC\n";
fprintf oc "2 VERS 5.5\n";
fprintf oc "2 FORM LINEAGE-LINKED\n";
if ascii.val then fprintf oc "1 CHAR ASCII\n"
else fprintf oc "1 CHAR ANSEL\n";
if no_notes.val then ()
else
let s = base.data.bnotes.nread 0 in
if s = "" then () else display_note oc s;
}
;
value sub_string_index s t =
loop 0 0 where rec loop i j =
if j = String.length t then Some (i - j)
else if i = String.length s then None
else if s.[i] = t.[j] then loop (i + 1) (j + 1)
else loop (i + 1) 0
;
value ged_1st_name base p =
let fn = sou base p.first_name in
match p.first_names_aliases with
[ [n :: _] ->
let fna = sou base n in
match sub_string_index fna fn with
[ Some i ->
let j = i + String.length fn in
String.sub fna 0 i ^ "\"" ^ fn ^ "\"" ^
String.sub fna j (String.length fna - j)
| None -> fn ]
| [] -> fn ]
;
value string_of_list =
loop "" where rec loop r =
fun
[ [s :: l] -> if r = "" then loop s l else loop (r ^ "," ^ s) l
| [] -> r ]
;
value ged_name base oc per =
do {
fprintf oc "1 NAME %s /%s/\n"
(encode (Gutil.nominative (ged_1st_name base per)))
(encode (Gutil.nominative (sou base per.surname)));
let n = sou base per.public_name in
if n <> "" then fprintf oc "2 GIVN %s\n" (encode n) else ();
match per.qualifiers with
[ [nn :: _] -> fprintf oc "2 NICK %s\n" (encode (sou base nn))
| [] -> () ];
match per.surnames_aliases with
[ [] -> ()
| list ->
let list = List.map (fun n -> encode (sou base n)) list in
fprintf oc "2 SURN %s\n" (string_of_list list) ];
List.iter (fun s -> fprintf oc "1 NAME %s\n" (encode (sou base s)))
per.aliases;
}
;
value ged_sex base oc per =
match per.sex with
[ Male -> fprintf oc "1 SEX M\n"
| Female -> fprintf oc "1 SEX F\n"
| Neuter -> () ]
;
value ged_calendar oc =
fun
[ Dgregorian -> ()
| Djulian -> fprintf oc "@#DJULIAN@ "
| Dfrench -> fprintf oc "@#DFRENCH R@ "
| Dhebrew -> fprintf oc "@#DHEBREW@ " ]
;
value ged_date_dmy oc dt cal =
do {
match dt.prec with
[ Sure -> ()
| About -> fprintf oc "ABT "
| Maybe -> fprintf oc "EST "
| Before -> fprintf oc "BEF "
| After -> fprintf oc "AFT "
| OrYear i -> fprintf oc "BET "
| YearInt i -> fprintf oc "BET " ];
ged_calendar oc cal;
if dt.day <> 0 then fprintf oc "%02d " dt.day else ();
if dt.month <> 0 then fprintf oc "%s " (ged_month cal dt.month)
else ();
fprintf oc "%d" dt.year;
match dt.prec with
[ OrYear i ->
do { fprintf oc " AND "; ged_calendar oc cal; fprintf oc "%d" i; }
| YearInt i ->
do { fprintf oc " AND "; ged_calendar oc cal; fprintf oc "%d" i; }
| _ -> () ];
}
;
value ged_date oc =
fun
[ Dgreg d Dgregorian -> ged_date_dmy oc d Dgregorian
| Dgreg d Djulian ->
ged_date_dmy oc (Calendar.julian_of_gregorian d) Djulian
| Dgreg d Dfrench ->
ged_date_dmy oc (Calendar.french_of_gregorian d) Dfrench
| Dgreg d Dhebrew ->
ged_date_dmy oc (Calendar.hebrew_of_gregorian d) Dhebrew
| Dtext t -> fprintf oc "(%s)" t ]
;
value ged_ev_detail oc n typ d pl src =
do {
match (typ, d, pl) with
[ ("", None, "") -> fprintf oc " Y"
| _ -> () ];
fprintf oc "\n";
if typ = "" then () else fprintf oc "%d TYPE %s\n" n typ;
match d with
[ Some d ->
do {
fprintf oc "%d DATE " n;
ged_date oc d;
fprintf oc "\n";
}
| None -> () ];
if pl <> "" then fprintf oc "%d PLAC %s\n" n (encode pl) else ();
if src <> "" then fprintf oc "%d SOUR %s\n" n (encode src) else ();
}
;
value adop_fam_list = ref [];
value adop_fam_cnt = ref 0;
value ged_adoption base (per_sel, fam_sel) oc per r =
let sel =
match (r.r_fath, r.r_moth) with
[ (Some ip1, Some ip2) -> per_sel ip1 && per_sel ip2
| (Some ip1, _) -> per_sel ip1
| (_, Some ip2) -> per_sel ip2
| _ -> True ]
in
if sel then do {
fprintf oc "1 ADOP Y\n";
adop_fam_list.val :=
[(r.r_fath, r.r_moth, per.cle_index) :: adop_fam_list.val];
incr adop_fam_cnt;
fprintf oc "2 FAMC @F%d@\n"
(base.data.families.len + adop_fam_cnt.val);
fprintf oc "3 ADOP ";
match (r.r_fath, r.r_moth) with
[ (Some _, None) -> fprintf oc "HUSB"
| (None, Some _) -> fprintf oc "WIFE"
| (Some _, Some _) -> fprintf oc "BOTH"
| _ -> () ];
fprintf oc "\n";
}
else ()
;
value ged_fam_adop base oc i (fath, moth, child) =
do {
fprintf oc "0 @F%d@ FAM\n" i;
match fath with
[ Some i -> fprintf oc "1 HUSB @I%d@\n" (Adef.int_of_iper i + 1)
| _ -> () ];
match moth with
[ Some i -> fprintf oc "1 WIFE @I%d@\n" (Adef.int_of_iper i + 1)
| _ -> () ];
}
;
value ged_ind_ev_str base sel oc per =
do {
let pl = sou base per.birth_place in
let src = sou base per.birth_src in
match (Adef.od_of_codate per.birth, pl) with
[ (None, "") -> ()
| (None, pl) ->
do {
fprintf oc "1 BIRT"; ged_ev_detail oc 2 "" None pl src;
}
| (od, pl) ->
do {
fprintf oc "1 BIRT"; ged_ev_detail oc 2 "" od pl src;
} ];
List.iter
(fun r ->
if r.r_type = Adoption then ged_adoption base sel oc per r else ())
per.rparents;
let pl = sou base per.baptism_place in
let src = sou base per.baptism_src in
match (Adef.od_of_codate per.baptism, pl) with
[ (None, "") -> ()
| (od, pl) ->
do {
fprintf oc "1 BAPM"; ged_ev_detail oc 2 "" od pl src;
} ];
let pl = sou base per.death_place in
let src = sou base per.death_src in
match per.death with
[ NotDead -> ()
| Death dr cd ->
do {
fprintf oc "1 DEAT";
ged_ev_detail oc 2 "" (Some (Adef.date_of_cdate cd)) pl src;
}
| DeadYoung | DeadDontKnowWhen ->
do {
fprintf oc "1 DEAT"; ged_ev_detail oc 2 "" None pl src;
}
| DontKnowIfDead -> fprintf oc "1 DEAT\n" ];
let pl = sou base per.burial_place in
let src = sou base per.burial_src in
match per.burial with
[ UnknownBurial -> ()
| Buried cod ->
do {
fprintf oc "1 BURI";
ged_ev_detail oc 2 "" (Adef.od_of_codate cod) pl src;
}
| Cremated cod ->
do {
fprintf oc "1 CREM";
ged_ev_detail oc 2 "" (Adef.od_of_codate cod) pl src;
} ];
}
;
value ged_title base oc per tit =
do {
fprintf oc "1 TITL ";
fprintf oc "%s" (encode (sou base tit.t_ident));
match sou base tit.t_place with
[ "" -> ()
| pl -> fprintf oc ", %s" (encode pl) ];
if tit.t_nth <> 0 then fprintf oc ", %d" tit.t_nth else ();
fprintf oc "\n";
match
(Adef.od_of_codate tit.t_date_start, Adef.od_of_codate tit.t_date_end)
with
[ (None, None) -> ()
| (Some sd, None) ->
do {
fprintf oc "2 DATE FROM ";
ged_date oc sd;
fprintf oc "\n";
}
| (None, Some sd) ->
do {
fprintf oc "2 DATE TO ";
ged_date oc sd;
fprintf oc "\n";
}
| (Some sd1, Some sd2) ->
do {
fprintf oc "2 DATE FROM ";
ged_date oc sd1;
fprintf oc " TO ";
ged_date oc sd2;
fprintf oc "\n";
} ];
match tit.t_name with
[ Tmain ->
fprintf oc "2 NOTE %s\n" (encode (sou base per.public_name))
| Tname n -> fprintf oc "2 NOTE %s\n" (encode (sou base n))
| Tnone -> () ];
}
;
value ged_ind_attr_str base oc per =
do {
match sou base per.occupation with
[ "" -> ()
| occu -> fprintf oc "1 OCCU %s\n" (encode occu) ];
List.iter (ged_title base oc per) per.titles;
}
;
value ged_famc base (per_sel, fam_sel) oc asc =
match parents asc with
[ Some ifam ->
if fam_sel ifam then
fprintf oc "1 FAMC @F%d@\n" (Adef.int_of_ifam ifam + 1)
else ()
| None -> () ]
;
value ged_fams base (per_sel, fam_sel) oc ifam =
if fam_sel ifam then
fprintf oc "1 FAMS @F%d@\n" (Adef.int_of_ifam ifam + 1)
else ()
;
value ged_godparent per_sel oc godp =
fun
[ Some ip ->
if per_sel ip then do {
fprintf oc "1 ASSO @I%d@\n" (Adef.int_of_iper ip + 1);
fprintf oc "2 TYPE INDI\n";
fprintf oc "2 RELA %s\n" godp;
}
else ()
| None -> () ]
;
value ged_witness fam_sel oc ifam =
if fam_sel ifam then do {
fprintf oc "1 ASSO @F%d@\n" (Adef.int_of_ifam ifam + 1);
fprintf oc "2 TYPE FAM\n";
fprintf oc "2 RELA witness\n";
}
else ()
;
value ged_asso base (per_sel, fam_sel) oc per =
do {
List.iter
(fun r ->
if r.r_type = GodParent then do {
ged_godparent per_sel oc "GODF" r.r_fath;
ged_godparent per_sel oc "GODM" r.r_moth;
}
else ())
per.rparents;
List.iter
(fun ic ->
let c = poi base ic in
if c.sex = Male then
List.iter
(fun ifam ->
let fam = foi base ifam in
if array_memq per.cle_index fam.witnesses then
ged_witness fam_sel oc ifam
else ())
(Array.to_list (uoi base ic).family)
else ())
per.related;
}
;
value ged_psource base oc per =
match sou base per.psources with
[ "" -> ()
| s -> fprintf oc "1 SOUR %s\n" (encode s) ]
;
value ged_multimedia_link base oc per =
match sou base per.image with
[ "" -> ()
| s ->
do {
fprintf oc "1 OBJE\n"; fprintf oc "2 FILE %s\n" s;
} ]
;
value ged_note base oc per =
match sou base per.notes with
[ "" -> ()
| s -> display_note oc s ]
;
value ged_marriage base oc fam =
match
(Adef.od_of_codate fam.marriage, sou base fam.marriage_place,
fam.relation)
with
[ (None, "", Married | Engaged) -> ()
| (d, pl, _) ->
do {
fprintf oc "1 %s"
(if fam.relation = Engaged then "ENGA" else "MARR");
let typ = if fam.relation = NoSexesCheck then "gay" else "" in
ged_ev_detail oc 2 typ d pl (sou base fam.marriage_src);
if fam.relation = NotMarried then
fprintf oc "2 PLAC unmarried\n"
else ();
} ]
;
value ged_divorce base oc fam =
match fam.divorce with
[ NotDivorced -> ()
| Separated -> ()
| Divorced cd ->
let d = Adef.od_of_codate cd in
do { fprintf oc "1 DIV"; ged_ev_detail oc 2 "" d "" ""; } ]
;
value ged_child base (per_sel, fam_sel) oc chil =
if per_sel chil then
fprintf oc "1 CHIL @I%d@\n" (Adef.int_of_iper chil + 1)
else ()
;
value ged_fsource base oc fam =
match sou base fam.fsources with
[ "" -> ()
| s -> fprintf oc "1 SOUR %s\n" (encode s) ]
;
value ged_comment base oc fam =
match sou base fam.comment with
[ "" -> ()
| s -> fprintf oc "1 NOTE %s\n" (encode s) ]
;
value has_personal_infos base per asc =
if parents asc <> None then True
else if sou base per.first_name <> "?" then True
else if sou base per.surname <> "?" then True
else if per.birth <> Adef.codate_None then True
else if sou base per.birth_place <> "" then True
else if per.death <> NotDead && per.death <> DontKnowIfDead then True
else if sou base per.occupation <> "" then True
else if per.titles <> [] then True
else False
;
value ged_ind_record base sel oc i =
let per = base.data.persons.get i in
let asc = base.data.ascends.get i in
let uni = base.data.unions.get i in
if has_personal_infos base per asc then do {
fprintf oc "0 @I%d@ INDI\n" (i + 1);
ged_name base oc per;
ged_sex base oc per;
ged_ind_ev_str base sel oc per;
ged_ind_attr_str base oc per;
ged_famc base sel oc asc;
Array.iter (ged_fams base sel oc) uni.family;
ged_asso base sel oc per;
ged_psource base oc per;
ged_multimedia_link base oc per;
ged_note base oc per;
}
else ()
;
value ged_fam_record base ((per_sel, fam_sel) as sel) oc i =
let fam = base.data.families.get i in
if is_deleted_family fam then ()
else do {
let cpl = base.data.couples.get i in
let des = base.data.descends.get i in
fprintf oc "0 @F%d@ FAM\n" (i + 1);
ged_marriage base oc fam;
ged_divorce base oc fam;
if has_personal_infos base (poi base (father cpl)) (aoi base (father cpl)) &&
per_sel (father cpl) then
fprintf oc "1 HUSB @I%d@\n" (Adef.int_of_iper (father cpl) + 1)
else ();
if has_personal_infos base (poi base (mother cpl)) (aoi base (mother cpl)) &&
per_sel (mother cpl) then
fprintf oc "1 WIFE @I%d@\n" (Adef.int_of_iper (mother cpl) + 1)
else ();
Array.iter (ged_child base sel oc) des.children;
ged_fsource base oc fam;
ged_comment base oc fam;
}
;
value find_person base p1 po p2 =
try Gutil.person_ht_find_unique base p1 p2 po with
[ Not_found ->
do {
printf "Not found: %s%s %s\n" p1
(if po == 0 then "" else " " ^ string_of_int po) p2;
flush stdout;
exit 2
} ]
;
value surnames = ref [];
value no_spouses_parents = ref False;
value censor = ref 0;
value with_siblings = ref False;
value gwb2ged base ifile ofile anc desc mem =
let anc =
match anc with
[ Some (p1, po, p2) -> Some (find_person base p1 po p2)
| None -> None ]
in
let desc =
match desc with
[ Some (p1, po, p2) -> Some (find_person base p1 po p2)
| None -> None ]
in
do {
if not mem then
(*
let _ = base.data.persons.array () in
*)
let _ = base.data.ascends.array () in
let _ = base.data.unions.array () in
let _ = base.data.couples.array () in
(*
let _ = base.data.families.array () in
*)
let _ = base.data.descends.array () in ()
else ();
let oc = if ofile = "" then stdout else open_out ofile in
let ((per_sel, fam_sel) as sel) =
Select.functions base anc desc surnames.val None no_spouses_parents.val
censor.val with_siblings.val (-1)
in
ged_header base oc ifile ofile;
flush oc;
for i = 0 to base.data.persons.len - 1 do {
if per_sel (Adef.iper_of_int i) then ged_ind_record base sel oc i
else ()
};
for i = 0 to base.data.families.len - 1 do {
if fam_sel (Adef.ifam_of_int i) then ged_fam_record base sel oc i
else ()
};
let _ =
List.fold_right
(fun adop i -> do { ged_fam_adop base oc i adop; i + 1 })
adop_fam_list.val (base.data.families.len + 1)
in
fprintf oc "0 TRLR\n";
flush oc;
if ofile = "" then () else close_out oc;
}
;
value ifile = ref "";
value ofile = ref "a.ged";
value mem = ref False;
value anc_1st = ref "";
value anc_occ = ref 0;
value anc_2nd = ref "";
value desc_1st = ref "";
value desc_occ = ref 0;
value desc_2nd = ref "";
type arg_state =
[ ASnone | ASwaitAncOcc | ASwaitAncSurn | ASwaitDescOcc | ASwaitDescSurn ]
;
value arg_state = ref ASnone;
value errmsg =
"Usage: " ^ Sys.argv.(0) ^ " \
[options]
If both options -a and -d are used, intersection is assumed.
If several options -s are used, union is assumed.
Options are:"
;
value speclist =
[("-charset",
Arg.String
(fun x ->
do {
arg_state.val := ASnone;
match x with
[ "ASCII" -> ascii.val := True
| "ANSEL" -> ascii.val := False
| _ -> raise (Arg.Bad "bad -charset value") ]
}),
"\
[ASCII|ANSEL]:
Set charset. Default is ASCII. Warning: value ANSEL works correctly only
on iso-8859-1 encoded databases.");
("-o",
Arg.String (fun x -> do { ofile.val := x; arg_state.val := ASnone }),
": output file name (default: a.ged)");
("-mem",
Arg.Unit (fun () -> do { mem.val := True; arg_state.val := ASnone }),
": save memory space, but slower");
("-a",
Arg.String
(fun s -> do { anc_1st.val := s; arg_state.val := ASwaitAncOcc }),
"\"<1st_name>\" [num] \"\": select ancestors of");
("-d",
Arg.String
(fun s -> do { desc_1st.val := s; arg_state.val := ASwaitDescOcc }),
"\"<1st_name>\" [num] \"\": select descendants of");
("-aws",
Arg.String
(fun s ->
do {
anc_1st.val := s;
arg_state.val := ASwaitAncOcc;
with_siblings.val := True;
}),
"\"<1st_name>\" [num] \"\" : select ancestors with siblings");
("-s", Arg.String (fun x -> surnames.val := [x :: surnames.val]),
"\"\" : select this surname (option usable several times)");
("-nsp", Arg.Set no_spouses_parents,
": no spouses' parents (for options -s and -d)");
("-nn", Arg.Set no_notes, ": no (database) notes");
("-c", Arg.Int (fun i -> censor.val := i), "\
:
When a person is born less than years ago, it is not exported unless
it is Public. All the spouses and descendants are also censored.")]
;
value anonfun s =
match arg_state.val with
[ ASnone ->
if ifile.val = "" then ifile.val := s
else raise (Arg.Bad "Cannot treat several databases")
| ASwaitAncOcc ->
try
do { anc_occ.val := int_of_string s; arg_state.val := ASwaitAncSurn }
with
[ Failure _ ->
do { anc_occ.val := 0; anc_2nd.val := s; arg_state.val := ASnone } ]
| ASwaitAncSurn -> do { anc_2nd.val := s; arg_state.val := ASnone }
| ASwaitDescOcc ->
try
do {
desc_occ.val := int_of_string s; arg_state.val := ASwaitDescSurn
}
with
[ Failure _ ->
do {
desc_occ.val := 0; desc_2nd.val := s; arg_state.val := ASnone
} ]
| ASwaitDescSurn -> do { desc_2nd.val := s; arg_state.val := ASnone } ]
;
value main () =
do {
Argl.parse speclist anonfun errmsg;
Secure.set_base_dir (Filename.dirname ifile.val);
let anc =
if anc_1st.val <> "" then
if anc_2nd.val = "" then do {
printf "Misused option -a\n";
printf "Use option -help for usage\n";
flush stdout;
exit 2
}
else Some (anc_1st.val, anc_occ.val, anc_2nd.val)
else None
in
let desc =
if desc_1st.val <> "" then
if desc_2nd.val = "" then do {
printf "Misused option -d\n";
printf "Use option -help for usage\n";
flush stdout;
exit 2
}
else Some (desc_1st.val, desc_occ.val, desc_2nd.val)
else None
in
if ofile.val = "-" then ofile.val := "" else ();
if ifile.val = "" then do {
printf "Missing base name\n";
printf "Use option -help for usage\n";
flush stdout;
exit 2
}
else ();
match try Some (Iobase.input ifile.val) with [ Sys_error _ -> None ] with
[ Some base -> gwb2ged base ifile.val ofile.val anc desc mem.val
| None ->
do {
printf "Can't open base %s\n" ifile.val; flush stdout; exit 2
} ];
}
;
Printexc.catch main ();