(* Copyright (c) 1998-2007 INRIA *) open Geneweb open Def type person = (int, int, int) Def.gen_person type ascend = int Def.gen_ascend type union = int Def.gen_union type family = (int, int, int) Def.gen_family type couple = int Def.gen_couple type descend = int Def.gen_descend let log_oc = ref stdout type record = { rlab : string; rval : string; rcont : string; rsons : record list; rpos : int; mutable rused : bool } type ('a, 'b, 'c, 'd) choice3 = Left3 of 'a | Right3 of 'b * 'c * 'd type month_number_dates = MonthDayDates | DayMonthDates | NoMonthNumberDates | MonthNumberHappened of string type charset = Ansel | Ansi | Ascii | Msdos | MacIntosh | Utf8 type case = NoCase | LowerCase | UpperCase let lowercase_first_names = ref false let track_ged2gw_id = ref false let case_surnames = ref NoCase let extract_first_names = ref false let extract_public_names = ref true let charset_option = ref None let charset = ref Ascii let alive_years = ref 80 let dead_years = ref 120 let try_negative_dates = ref false let no_negative_dates = ref false let month_number_dates = ref NoMonthNumberDates let no_public_if_titles = ref false let first_names_brackets = ref None let untreated_in_notes = ref false let force = ref false let default_source = ref "" let relation_status = ref Married let no_picture = ref false let do_check = ref true let particles = ref Mutil.default_particles (* Reading input *) let line_cnt = ref 1 let in_file = ref "" let print_location pos = Printf.fprintf !log_oc "File \"%s\", line %d:\n" !in_file pos let rec skip_eol = parser | [< ''\010' | '\013'; _ = skip_eol >] -> () | [< >] -> () let rec get_to_eoln len = parser | [< ''\010' | '\013'; _ = skip_eol >] -> Buff.get len | [< ''\t'; s >] -> get_to_eoln (Buff.store len ' ') s | [< 'c; s >] -> get_to_eoln (Buff.store len c) s | [< >] -> Buff.get len let rec skip_to_eoln = parser | [< ''\010' | '\013'; _ = skip_eol >] -> () | [< '_; s >] -> skip_to_eoln s | [< >] -> () let eol_chars = ['\010'; '\013'] let rec get_ident len = parser | [< '' ' | '\t' >] -> Buff.get len | [< 'c when not (List.mem c eol_chars); s >] -> get_ident (Buff.store len c) s | [< >] -> Buff.get len let skip_space = parser | [< '' ' | '\t' >] -> () | [< >] -> () let rec line_start num = parser | [< '' '; s >] -> line_start num s | [< 'x when x = num >] -> () let ascii_of_msdos s = let conv_char i = let cc = match Char.code s.[i] with 0o200 -> 0o307 | 0o201 -> 0o374 | 0o202 -> 0o351 | 0o203 -> 0o342 | 0o204 -> 0o344 | 0o205 -> 0o340 | 0o206 -> 0o345 | 0o207 -> 0o347 | 0o210 -> 0o352 | 0o211 -> 0o353 | 0o212 -> 0o350 | 0o213 -> 0o357 | 0o214 -> 0o356 | 0o215 -> 0o354 | 0o216 -> 0o304 | 0o217 -> 0o305 | 0o220 -> 0o311 | 0o221 -> 0o346 | 0o222 -> 0o306 | 0o223 -> 0o364 | 0o224 -> 0o366 | 0o225 -> 0o362 | 0o226 -> 0o373 | 0o227 -> 0o371 | 0o230 -> 0o377 | 0o231 -> 0o326 | 0o232 -> 0o334 | 0o233 -> 0o242 | 0o234 -> 0o243 | 0o235 -> 0o245 | 0o240 -> 0o341 | 0o241 -> 0o355 | 0o242 -> 0o363 | 0o243 -> 0o372 | 0o244 -> 0o361 | 0o245 -> 0o321 | 0o246 -> 0o252 | 0o247 -> 0o272 | 0o250 -> 0o277 | 0o252 -> 0o254 | 0o253 -> 0o275 | 0o254 -> 0o274 | 0o255 -> 0o241 | 0o256 -> 0o253 | 0o257 -> 0o273 | 0o346 -> 0o265 | 0o361 -> 0o261 | 0o366 -> 0o367 | 0o370 -> 0o260 | 0o372 -> 0o267 | 0o375 -> 0o262 | c -> c in Char.chr cc in String.init (String.length s) conv_char let ascii_of_macintosh s = let conv_char i = let cc = match Char.code s.[i] with 0o200 -> 0o304 | 0o201 -> 0o305 | 0o202 -> 0o307 | 0o203 -> 0o311 | 0o204 -> 0o321 | 0o205 -> 0o326 | 0o206 -> 0o334 | 0o207 -> 0o341 | 0o210 -> 0o340 | 0o211 -> 0o342 | 0o212 -> 0o344 | 0o213 -> 0o343 | 0o214 -> 0o345 | 0o215 -> 0o347 | 0o216 -> 0o351 | 0o217 -> 0o350 | 0o220 -> 0o352 | 0o221 -> 0o353 | 0o222 -> 0o355 | 0o223 -> 0o354 | 0o224 -> 0o356 | 0o225 -> 0o357 | 0o226 -> 0o361 | 0o227 -> 0o363 | 0o230 -> 0o362 | 0o231 -> 0o364 | 0o232 -> 0o366 | 0o233 -> 0o365 | 0o234 -> 0o372 | 0o235 -> 0o371 | 0o236 -> 0o373 | 0o237 -> 0o374 | 0o241 -> 0o260 | 0o244 -> 0o247 | 0o245 -> 0o267 | 0o246 -> 0o266 | 0o247 -> 0o337 | 0o250 -> 0o256 | 0o256 -> 0o306 | 0o257 -> 0o330 | 0o264 -> 0o245 | 0o273 -> 0o252 | 0o274 -> 0o272 | 0o276 -> 0o346 | 0o277 -> 0o370 | 0o300 -> 0o277 | 0o301 -> 0o241 | 0o302 -> 0o254 | 0o307 -> 0o253 | 0o310 -> 0o273 | 0o312 -> 0o040 | 0o313 -> 0o300 | 0o314 -> 0o303 | 0o315 -> 0o325 | 0o320 -> 0o255 | 0o326 -> 0o367 | 0o330 -> 0o377 | 0o345 -> 0o302 | 0o346 -> 0o312 | 0o347 -> 0o301 | 0o350 -> 0o313 | 0o351 -> 0o310 | 0o352 -> 0o315 | 0o353 -> 0o316 | 0o354 -> 0o317 | 0o355 -> 0o314 | 0o356 -> 0o323 | 0o357 -> 0o324 | 0o361 -> 0o322 | 0o362 -> 0o332 | 0o363 -> 0o333 | 0o364 -> 0o331 | c -> c in Char.chr cc in String.init (String.length s) conv_char let utf8_of_string s = match !charset with | Ansel -> Mutil.utf_8_of_iso_8859_1 (Ansel.to_iso_8859_1 s) | Ansi -> Mutil.utf_8_of_iso_8859_1 s | Ascii -> Mutil.utf_8_of_iso_8859_1 s | Msdos -> Mutil.utf_8_of_iso_8859_1 (ascii_of_msdos s) | MacIntosh -> Mutil.utf_8_of_iso_8859_1 (ascii_of_macintosh s) | Utf8 -> s let rec get_lev n = parser [< _ = line_start n; _ = skip_space; r1 = get_ident 0; strm >] -> let (rlab, rval, rcont, l) = if String.length r1 > 0 && r1.[0] = '@' then parse_address n r1 strm else parse_text n r1 strm in {rlab = rlab; rval = utf8_of_string rval; rcont = utf8_of_string rcont; rsons = List.rev l; rpos = !line_cnt; rused = false} and parse_address n r1 = parser [< r2 = get_ident 0; r3 = get_to_eoln 0 (* ? "get to eoln" *); l = get_lev_list [] (Char.chr (Char.code n + 1)) (* ? "get lev list" *) >] -> (r2, r1, r3, l) and parse_text n r1 = parser [< r2 = get_to_eoln 0; l = get_lev_list [] (Char.chr (Char.code n + 1)) (* ? "get lev list" *) >] -> (r1, r2, "", l) and get_lev_list l n = parser | [< x = get_lev n; s >] -> get_lev_list (x :: l) n s | [< >] -> l (* Error *) let bad_dates_warned = ref false let print_bad_date pos d = if !bad_dates_warned then () else begin bad_dates_warned := true; print_location pos; Printf.fprintf !log_oc "Can't decode date %s\n" d; flush !log_oc end let check_month m = if m < 1 || m > 12 then begin Printf.fprintf !log_oc "Bad (numbered) month in date: %d\n" m; flush !log_oc end let warning_month_number_dates () = match !month_number_dates with MonthNumberHappened s -> Printf.fprintf !log_oc " Warning: the file holds dates with numbered months (like: 12/05/1912).\n \ \n \ GEDCOM standard *requires* that months in dates be identifiers. The\n \ correct form for this example would be 12 MAY 1912 or 5 DEC 1912.\n \ \n \ Consider restarting with option \"-dates_dm\" or \"-dates_md\".\n \ Use option -help to see what they do.\n \ \n \ (example found in gedcom: \"%s\")" s; flush !log_oc | _ -> () (* Decoding fields *) let rec skip_spaces = parser | [< '' '; s >] -> skip_spaces s | [< >] -> () let rec ident_slash len = parser | [< ''/' >] -> Buff.get len | [< ''\t'; a = ident_slash (Buff.store len ' ') >] -> a | [< 'c; a = ident_slash (Buff.store len c) >] -> a | [< >] -> Buff.get len let strip c str = let start = let rec loop i = if i = String.length str then i else if str.[i] = c then loop (i + 1) else i in loop 0 in let stop = let rec loop i = if i = -1 then i + 1 else if str.[i] = c then loop (i - 1) else i + 1 in loop (String.length str - 1) in if start = 0 && stop = String.length str then str else if start >= stop then "" else String.sub str start (stop - start) let strip_spaces = strip ' ' let strip_newlines = strip '\n' let less_greater_escaped s = let rec need_code i = if i < String.length s then match s.[i] with '<' | '>' -> true | _ -> need_code (succ i) else false in let rec compute_len i i1 = if i < String.length s then let i1 = match s.[i] with '<' | '>' -> i1 + 4 | _ -> succ i1 in compute_len (succ i) i1 else i1 in let rec copy_code_in s1 i i1 = if i < String.length s then let i1 = match s.[i] with '<' -> String.blit "<" 0 s1 i1 4; i1 + 4 | '>' -> String.blit ">" 0 s1 i1 4; i1 + 4 | c -> Bytes.set s1 i1 c; succ i1 in copy_code_in s1 (succ i) i1 else Bytes.unsafe_to_string s1 in if need_code 0 then let len = compute_len 0 0 in copy_code_in (Bytes.create len) 0 0 else s let parse_name = parser [< _ = skip_spaces; invert = (parser | [< ''/' >] -> true | [< >] -> false) ; f = ident_slash 0; _ = skip_spaces; s = ident_slash 0 >] -> let (f, s) = if invert then (s, f) else (f, s) in let f = strip_spaces f in let s = strip_spaces s in ((if f = "" then "x" else f), (if s = "" then "?" else s)) let rec find_field lab = function r :: rl -> if r.rlab = lab then begin r.rused <- true; Some r end else find_field lab rl | [] -> None let rec find_all_fields lab = function r :: rl -> if r.rlab = lab then begin r.rused <- true; r :: find_all_fields lab rl end else find_all_fields lab rl | [] -> [] let rec find_field_with_value lab v = function r :: rl -> if r.rlab = lab && r.rval = v then begin r.rused <- true; true end else find_field_with_value lab v rl | [] -> false let rec lexing_date = parser | [< ''0'..'9' as c; n = number (Buff.store 0 c) >] -> ("INT", n) | [< ''A'..'Z' as c; i = ident (Buff.store 0 c) >] -> ("ID", i) | [< ''('; len = text 0 >] -> ("TEXT", Buff.get len) | [< ''.' >] -> ("", ".") | [< '' ' | '\t' | '\013'; s >] -> lexing_date s | [< _ = Stream.empty >] -> ("EOI", "") | [< 'x >] -> ("", String.make 1 x) and number len = parser | [< ''0'..'9' as c; a = number (Buff.store len c) >] -> a | [< >] -> Buff.get len and ident len = parser | [< ''A'..'Z' as c; a = ident (Buff.store len c) >] -> a | [< >] -> Buff.get len and text len = parser | [< '')' >] -> len | [< ''('; len = text (Buff.store len '('); s >] -> text (Buff.store len ')') s | [< 'c; s >] -> text (Buff.store len c) s | [< >] -> len let make_date_lexing s = Stream.from (fun _ -> Some (lexing_date s)) let tparse = Token.default_match let using_token (p_con, _) = match p_con with "" | "INT" | "ID" | "TEXT" | "EOI" -> () | _ -> raise (Token.Error ("the constructor \"" ^ p_con ^ "\" is not recognized by the lexer")) let date_lexer = { Token.tok_func = (fun s -> make_date_lexing s , { Plexing.Locations.locations = ref [||] ; overflow = ref true } ) ; Token.tok_using = using_token ; Token.tok_removing = (fun _ -> ()) ; Token.tok_match = tparse ; Token.tok_text = (fun _ -> "") ; Token.tok_comm = None } type 'a range = Begin of 'a | End of 'a | BeginEnd of 'a * 'a let date_g = Grammar.gcreate date_lexer let date_value = Grammar.Entry.create date_g "date value" let date_interval = Grammar.Entry.create date_g "date interval" let date_value_recover = Grammar.Entry.create date_g "date value" let is_roman_int x = try let _ = Mutil.arabian_of_roman x in true with Not_found -> false let start_with_int x = try let s = String.sub x 0 1 in let _ = int_of_string s in true with _ -> false let roman_int = let p = parser [< '("ID", x) when is_roman_int x >] -> Mutil.arabian_of_roman x in Grammar.Entry.of_parser date_g "roman int" p let date_str = ref "" let make_date n1 n2 n3 = let n3 = if !no_negative_dates then match n3 with Some n3 -> Some (abs n3) | None -> None else n3 in match n1, n2, n3 with Some d, Some m, Some y -> let (d, m) = match m with Right m -> d, m | Left m -> match !month_number_dates with DayMonthDates -> check_month m; d, m | MonthDayDates -> check_month d; m, d | _ -> if d >= 1 && m >= 1 && d <= 31 && m <= 31 then if d > 13 && m <= 13 then d, m else if m > 13 && d <= 13 then m, d else if d > 13 && m > 13 then 0, 0 else begin month_number_dates := MonthNumberHappened !date_str; 0, 0 end else 0, 0 in let (d, m) = if m < 1 || m > 13 then 0, 0 else d, m in {day = d; month = m; year = y; prec = Sure; delta = 0} | None, Some m, Some y -> let m = match m with Right m -> m | Left m -> m in {day = 0; month = m; year = y; prec = Sure; delta = 0} | None, None, Some y -> {day = 0; month = 0; year = y; prec = Sure; delta = 0} | Some y, None, None -> {day = 0; month = 0; year = y; prec = Sure; delta = 0} | _ -> raise (Stream.Error "bad date") let recover_date cal = function | Dgreg (d, Dgregorian) -> let d = match cal with | Dgregorian -> d | Djulian -> Calendar.gregorian_of_julian d | Dfrench -> Calendar.gregorian_of_french d | Dhebrew -> Calendar.gregorian_of_hebrew d in Dgreg (d, cal) | d -> d [@@@ocaml.warning "-27"] EXTEND GLOBAL: date_value date_interval date_value_recover; date_value: [ [ d = date_or_text; EOI -> d ] ] ; date_value_recover: [ [ "@"; "#"; ID "DGREGORIAN"; "@"; d = date_value -> recover_date Dgregorian d | "@"; "#"; ID "DJULIAN"; "@"; d = date_value -> recover_date Djulian d | "@"; "#"; ID "DFRENCH"; ID "R"; "@"; d = date_value -> recover_date Dfrench d | "@"; "#"; ID "DHEBREW"; "@"; d = date_value -> recover_date Dhebrew d ] ] ; date_interval: [ [ ID "BEF"; dt = date_or_text; EOI -> End dt | ID "AFT"; dt = date_or_text; EOI -> Begin dt | ID "BET"; dt = date_or_text; ID "AND"; dt1 = date_or_text; EOI -> BeginEnd (dt, dt1) | ID "TO"; dt = date_or_text; EOI -> End dt | ID "FROM"; dt = date_or_text; EOI -> Begin dt | ID "FROM"; dt = date_or_text; ID "TO"; dt1 = date_or_text; EOI -> BeginEnd (dt, dt1) | dt = date_or_text; EOI -> Begin dt ] ] ; date_or_text: [ [ dr = date_range -> begin match dr with | Begin (d, cal) -> Dgreg ({d with prec = After}, cal) | End (d, cal) -> Dgreg ({d with prec = Before}, cal) | BeginEnd ((d1, cal1), (d2, cal2)) -> let dmy2 = match cal2 with | Dgregorian -> {day2 = d2.day; month2 = d2.month; year2 = d2.year; delta2 = 0} | Djulian -> let dmy2 = Calendar.julian_of_gregorian d2 in {day2 = dmy2.day; month2 = dmy2.month; year2 = dmy2.year; delta2 = 0} | Dfrench -> let dmy2 = Calendar.french_of_gregorian d2 in {day2 = dmy2.day; month2 = dmy2.month; year2 = dmy2.year; delta2 = 0} | Dhebrew -> let dmy2 = Calendar.hebrew_of_gregorian d2 in {day2 = dmy2.day; month2 = dmy2.month; year2 = dmy2.year; delta2 = 0} in Dgreg ({d1 with prec = YearInt dmy2}, cal1) end | (d, cal) = date -> Dgreg (d, cal) | s = TEXT -> Dtext s ] ] ; date_range: [ [ ID "BEF"; dt = date -> End dt | ID "AFT"; dt = date -> Begin dt | ID "BET"; dt = date; ID "AND"; dt1 = date -> BeginEnd (dt, dt1) | ID "TO"; dt = date -> End dt | ID "FROM"; dt = date -> Begin dt | ID "FROM"; dt = date; ID "TO"; dt1 = date -> BeginEnd (dt, dt1) ] ] ; date: [ [ ID "ABT"; (d, cal) = date_calendar -> ({(d) with prec = About}, cal) | ID "ENV"; (d, cal) = date_calendar -> ({(d) with prec = About}, cal) | ID "EST"; (d, cal) = date_calendar -> ({(d) with prec = Maybe}, cal) | ID "AFT"; (d, cal) = date_calendar -> ({(d) with prec = Before}, cal) | ID "BEF"; (d, cal) = date_calendar -> ({(d) with prec = After}, cal) | (d, cal) = date_calendar -> (d, cal) ] ] ; date_calendar: [ [ "@"; "#"; ID "DGREGORIAN"; "@"; d = date_greg -> (d, Dgregorian) | "@"; "#"; ID "DJULIAN"; "@"; d = date_greg -> (Calendar.gregorian_of_julian d, Djulian) | "@"; "#"; ID "DFRENCH"; ID "R"; "@"; d = date_fren -> (Calendar.gregorian_of_french d, Dfrench) | "@"; "#"; ID "DHEBREW"; "@"; d = date_hebr -> (Calendar.gregorian_of_hebrew d, Dhebrew) | d = date_greg -> (d, Dgregorian) ] ] ; date_greg: [ [ LIST0 "."; n1 = OPT int; LIST0 [ "." | "/" ]; n2 = OPT gen_month; LIST0 [ "." | "/" ]; n3 = OPT int; LIST0 "." -> make_date n1 n2 n3 ] ] ; date_fren: [ [ LIST0 "."; n1 = int; (n2, n3) = date_fren_kont -> make_date (Some n1) n2 n3 | LIST0 "."; n1 = year_fren -> make_date (Some n1) None None | LIST0 "."; (n2, n3) = date_fren_kont -> make_date None n2 n3 ] ] ; date_fren_kont: [ [ LIST0 [ "." | "/" ]; n2 = OPT gen_french; LIST0 [ "." | "/" ]; n3 = OPT year_fren; LIST0 "." -> (n2, n3) ] ] ; date_hebr: [ [ LIST0 "."; n1 = OPT int; LIST0 [ "." | "/" ]; n2 = OPT gen_hebr; LIST0 [ "." | "/" ]; n3 = OPT int; LIST0 "." -> make_date n1 n2 n3 ] ] ; gen_month: [ [ i = int -> Left (abs i) | m = month -> Right m ] ] ; month: [ [ ID "JAN" -> 1 | ID "FEB" -> 2 | ID "MAR" -> 3 | ID "APR" -> 4 | ID "MAY" -> 5 | ID "JUN" -> 6 | ID "JUL" -> 7 | ID "AUG" -> 8 | ID "SEP" -> 9 | ID "OCT" -> 10 | ID "NOV" -> 11 | ID "DEC" -> 12 ] ] ; gen_french: [ [ m = french -> Right m ] ] ; french: [ [ ID "VEND" -> 1 | ID "BRUM" -> 2 | ID "FRIM" -> 3 | ID "NIVO" -> 4 | ID "PLUV" -> 5 | ID "VENT" -> 6 | ID "GERM" -> 7 | ID "FLOR" -> 8 | ID "PRAI" -> 9 | ID "MESS" -> 10 | ID "THER" -> 11 | ID "FRUC" -> 12 | ID "COMP" -> 13 ] ] ; year_fren: [ [ i = int -> i | ID "AN"; i = roman_int -> i | i = roman_int -> i ] ] ; gen_hebr: [ [ m = hebr -> Right m ] ] ; hebr: [ [ ID "TSH" -> 1 | ID "CSH" -> 2 | ID "KSL" -> 3 | ID "TVT" -> 4 | ID "SHV" -> 5 | ID "ADR" -> 6 | ID "ADS" -> 7 | ID "NSN" -> 8 | ID "IYR" -> 9 | ID "SVN" -> 10 | ID "TMZ" -> 11 | ID "AAV" -> 12 | ID "ELL" -> 13 ] ] ; int: [ [ i = INT -> (try int_of_string i with Failure _ -> raise Stream.Failure) | "-"; i = INT -> (try (- int_of_string i) with Failure _ -> raise Stream.Failure) ] ] ; END [@@@ocaml.warning "+27"] (* Perform a regular expression match. *) let preg_match pattern subject = let re = Str.regexp pattern in try ignore (Str.search_forward re subject 0); true with Not_found -> false let date_of_field d = if d = "" then None else if preg_match "^[0-9]+$" d && String.length d > 8 then Some (Dtext d) else let s = Stream.of_string (String.uppercase_ascii d) in date_str := d; try Some (Grammar.Entry.parse date_value s) with Ploc.Exc (_, Stream.Error _) -> let s = Stream.of_string (String.uppercase_ascii d) in try Some (Grammar.Entry.parse date_value_recover s) with Ploc.Exc (_, Stream.Error _) -> Some (Dtext d) (* Creating base *) type 'a tab = { mutable arr : 'a array ; mutable tlen : int } type gen = { g_per : (string, person, ascend, union) choice3 tab ; g_fam : (string, family, couple, descend) choice3 tab ; g_str : string tab ; mutable g_bnot : string ; g_ic : in_channel ; g_not : (string, int) Hashtbl.t ; g_src : (string, int) Hashtbl.t ; g_hper : (string, int) Hashtbl.t ; g_hfam : (string, int) Hashtbl.t ; g_hstr : (string, int) Hashtbl.t ; g_hnam : (string, int ref) Hashtbl.t ; g_adop : (string, int * string) Hashtbl.t ; mutable g_godp : (int * int) list ; mutable g_prelated : (int * int) list ; mutable g_frelated : (int * int) list ; mutable g_witn : (int * int) list } let assume_tab tab none = if tab.tlen = Array.length tab.arr then let new_len = 2 * Array.length tab.arr + 1 in let new_arr = Array.make new_len none in Array.blit tab.arr 0 new_arr 0 (Array.length tab.arr) ; tab.arr <- new_arr let add_string gen s = try Hashtbl.find gen.g_hstr s with Not_found -> let i = gen.g_str.tlen in assume_tab gen.g_str ""; gen.g_str.arr.(i) <- s; gen.g_str.tlen <- gen.g_str.tlen + 1; Hashtbl.add gen.g_hstr s i; i let extract_addr addr = if String.length addr > 0 && addr.[0] = '@' then try let r = String.index_from addr 1 '@' in String.sub addr 0 (r + 1) with Not_found -> addr else addr (* Output Pindex in file *) let output_pindex i str = if !track_ged2gw_id then Printf.printf "IDGED2IDPERS %i %s\n" i str let per_index gen lab = let lab = extract_addr lab in try Hashtbl.find gen.g_hper lab with Not_found -> let i = gen.g_per.tlen in assume_tab gen.g_per (Left3 ""); gen.g_per.arr.(i) <- Left3 lab; gen.g_per.tlen <- gen.g_per.tlen + 1; Hashtbl.add gen.g_hper lab i; output_pindex i lab; i let fam_index gen lab = let lab = extract_addr lab in try Hashtbl.find gen.g_hfam lab with Not_found -> let i = gen.g_fam.tlen in assume_tab gen.g_fam (Left3 ""); gen.g_fam.arr.(i) <- Left3 lab; gen.g_fam.tlen <- gen.g_fam.tlen + 1; Hashtbl.add gen.g_hfam lab i; i let string_empty = 0 let string_quest = 1 let string_x = 2 let unknown_per i sex = let p = { (Mutil.empty_person string_empty string_quest) with sex ; occ = i ; key_index = i } and a = {parents = None; consang = Adef.fix (-1)} and u = {family = [| |]} in p, a, u let phony_per gen sex = let i = gen.g_per.tlen in let (person, ascend, union) = unknown_per i sex in assume_tab gen.g_per (Left3 ""); gen.g_per.tlen <- gen.g_per.tlen + 1; gen.g_per.arr.(i) <- Right3 (person, ascend, union); i let unknown_fam gen i = let father = phony_per gen Male in let mother = phony_per gen Female in let f = { (Mutil.empty_family string_empty) with fam_index = i } and c = Adef.couple father mother and d = {children = [| |]} in f, c, d let phony_fam gen = let i = gen.g_fam.tlen in let (fam, cpl, des) = unknown_fam gen i in assume_tab gen.g_fam (Left3 ""); gen.g_fam.tlen <- gen.g_fam.tlen + 1; gen.g_fam.arr.(i) <- Right3 (fam, cpl, des); i let this_year = let tm = Unix.localtime (Unix.time ()) in tm.Unix.tm_year + 1900 let infer_death birth bapt = match birth, bapt with | Some (Dgreg (d, _)), _ -> let a = this_year - d.year in if a > !dead_years then DeadDontKnowWhen else if a < !alive_years then NotDead else DontKnowIfDead | _, Some (Dgreg (d, _)) -> let a = this_year - d.year in if a > !dead_years then DeadDontKnowWhen else if a < !alive_years then NotDead else DontKnowIfDead | _ -> DontKnowIfDead (* Fonctions utiles pour la mise en forme des noms. *) let string_ini_eq s1 i s2 = let rec loop i j = if j = String.length s2 then true else if i = String.length s1 then false else if s1.[i] = s2.[j] then loop (i + 1) (j + 1) else false in loop i 0 let particle s i = List.exists (string_ini_eq s i) !particles let look_like_a_number s = let rec loop i = if i < 0 then assert false else if i >= String.length s then true else match s.[i] with '0'..'9' -> loop (i + 1) | _ -> false in loop 0 let is_a_name_char = function 'A'..'Z' | 'a'..'z' | '0'..'9' | '-' | '\'' -> true | c -> Char.code c > 127 let rec next_word_pos s i = if i >= String.length s then i else if is_a_name_char s.[i] then i else next_word_pos s (i + 1) let rec next_sep_pos s i = if i >= String.length s then String.length s else if is_a_name_char s.[i] then next_sep_pos s (i + 1) else i let public_name_word = ["Ier"; "Ière"; "der"; "den"; "die"; "el"; "le"; "la"; "the"] let rec is_a_public_name s i = let i = next_word_pos s i in i < String.length s && (let j = next_sep_pos s i in j > i && (let w = String.sub s i (j - i) in look_like_a_number w || is_roman_int w && j < String.length s && s.[j] <> '.' || List.mem w public_name_word || is_a_public_name s j)) module Buff2 = Buff.Make (struct end)[@@ocaml.warning "-73"] let aux fn s = (* On initialise le buffer à la valeur de s. *) let _ = Buff2.mstore 0 s in let rec loop len k = let i = next_word_pos s k in if i = String.length s then Buff2.get (String.length s) else let j = next_sep_pos s i in if j > i then let w = String.sub s i (j - i) in let w = if is_roman_int w || particle s i || List.mem w public_name_word || start_with_int w then w else fn w in let len = let rec loop len k = if k = i then len else loop (Buff2.store len s.[k]) (k + 1) in loop len k in loop (Buff2.mstore len w) j else Buff2.get len in loop 0 0 let capitalize_name = aux Name.title let uppercase_name = aux Utf8.uppercase let get_lev0 (strm__ : _ Stream.t) = let _ = line_start '0' strm__ in let _ = try skip_space strm__ with Stream.Failure -> raise (Stream.Error "") in let r1 = try get_ident 0 strm__ with Stream.Failure -> raise (Stream.Error "") in let r2 = try get_ident 0 strm__ with Stream.Failure -> raise (Stream.Error "") in let r3 = try get_to_eoln 0 strm__ with Stream.Failure -> raise (Stream.Error "") in let l = try get_lev_list [] '1' strm__ with Stream.Failure -> raise (Stream.Error "") in let (rlab, rval) = if r2 = "" then r1, "" else r2, r1 in let rval = utf8_of_string rval in let rcont = utf8_of_string r3 in {rlab = rlab; rval = rval; rcont = rcont; rsons = List.rev l; rpos = !line_cnt; rused = false} let find_notes_record gen addr = match try Some (Hashtbl.find gen.g_not addr) with Not_found -> None with Some i -> seek_in gen.g_ic i; begin try Some (get_lev0 (Stream.of_channel gen.g_ic)) with Stream.Failure | Stream.Error _ -> None end | None -> None let find_sources_record gen addr = match try Some (Hashtbl.find gen.g_src addr) with Not_found -> None with Some i -> seek_in gen.g_ic i; begin try Some (get_lev '0' (Stream.of_channel gen.g_ic)) with Stream.Failure | Stream.Error _ -> None end | None -> None let rec flatten_notes = function r :: rl -> let n = flatten_notes rl in begin match r.rlab with "CONC" | "CONT" | "NOTE" -> (r.rlab, r.rval) :: (flatten_notes r.rsons @ n) | _ -> n end | [] -> [] let extract_notes gen rl = List.fold_right (fun r lines -> List.fold_right (fun r lines -> r.rused <- true; if r.rlab = "NOTE" && r.rval <> "" && r.rval.[0] = '@' then let addr = extract_addr r.rval in match find_notes_record gen addr with Some r -> let l = flatten_notes r.rsons in ("NOTE", r.rcont) :: (l @ lines) | None -> print_location r.rpos; Printf.fprintf !log_oc "Note %s not found\n" addr; flush !log_oc; lines else (r.rlab, r.rval) :: lines) (r :: r.rsons) lines) rl [] let rebuild_text r = let s = strip_spaces r.rval in List.fold_left (fun s e -> let _ = e.rused <- true in let n = e.rval in let end_spc = if String.length n > 1 && n.[String.length n - 1] = ' ' then " " else "" in let n = strip_spaces n in match e.rlab with "CONC" -> s ^ n ^ end_spc | "CONT" -> s ^ "
\n" ^ n ^ end_spc | _ -> s) s r.rsons let notes_from_source_record rl = let title = match find_field "TITL" rl with Some l -> let s = rebuild_text l in if s = "" then "" else "" ^ s ^ "" | None -> "" in let text = match find_field "TEXT" rl with Some l -> let s = rebuild_text l in if title = "" then s else "
\n" ^ s | None -> "" in title ^ text let treat_notes gen rl = let lines = extract_notes gen rl in let buf = Buffer.create (List.length lines) in let () = List.iter (fun (lab, n) -> let spc = String.length n > 0 && n.[0] = ' ' in let end_spc = String.length n > 1 && n.[String.length n - 1] = ' ' in let n = strip_spaces n in if Buffer.length buf = 0 then begin Buffer.add_string buf n; Buffer.add_string buf (if end_spc then " " else "") end else if lab = "CONT" || lab = "NOTE" then begin Buffer.add_string buf "
\n"; Buffer.add_string buf n; Buffer.add_string buf (if end_spc then " " else "") end else if n = "" then () else begin Buffer.add_string buf (if spc then "\n" else ""); Buffer.add_string buf n; Buffer.add_string buf (if end_spc then " " else "") end) lines in strip_newlines (Buffer.contents buf) let note gen r = match find_field "NOTE" r.rsons with Some r -> if String.length r.rval > 0 && r.rval.[0] = '@' then match find_notes_record gen r.rval with Some v -> strip_spaces v.rcont, v.rsons | None -> print_location r.rpos; Printf.fprintf !log_oc "Note %s not found\n" r.rval; flush !log_oc; "", [] else strip_spaces r.rval, r.rsons | _ -> "", [] let treat_source gen r = if String.length r.rval > 0 && r.rval.[0] = '@' then match find_sources_record gen r.rval with Some v -> strip_spaces v.rcont, v.rsons | None -> print_location r.rpos; Printf.fprintf !log_oc "Source %s not found\n" r.rval; flush !log_oc; "", [] else strip_spaces r.rval, r.rsons let source gen r = match find_field "SOUR" r.rsons with Some r -> treat_source gen r | _ -> "", [] let p_index_from s i c = if i >= String.length s then String.length s else try String.index_from s i c with Not_found -> String.length s let strip_sub s beg len = strip_spaces (String.sub s beg len) let decode_title s = let i1 = p_index_from s 0 ',' in let i2 = p_index_from s (i1 + 1) ',' in let title = strip_sub s 0 i1 in let (place, nth) = if i1 = String.length s then "", 0 else if i2 = String.length s then let s1 = strip_sub s (i1 + 1) (i2 - i1 - 1) in try "", int_of_string s1 with Failure _ -> s1, 0 else let s1 = strip_sub s (i1 + 1) (i2 - i1 - 1) in let s2 = strip_sub s (i2 + 1) (String.length s - i2 - 1) in try s1, int_of_string s2 with Failure _ -> strip_sub s i1 (String.length s - i1), 0 in title, place, nth let list_of_string s = let rec loop i len list = if i = String.length s then List.rev (Buff.get len :: list) else match s.[i] with ',' -> loop (i + 1) 0 (Buff.get len :: list) | c -> loop (i + 1) (Buff.store len c) list in loop 0 0 [] let purge_list list = List.fold_right (fun s list -> match strip_spaces s with "" -> list | s -> s :: list) list [] let decode_date_interval pos s = let strm = Stream.of_string s in try match Grammar.Entry.parse date_interval strm with BeginEnd (d1, d2) -> Some d1, Some d2 | Begin d -> Some d, None | End d -> None, Some d with Ploc.Exc (_, _) | Not_found -> print_bad_date pos s; None, None let treat_indi_title gen public_name r = let (title, place, nth) = decode_title r.rval in let (date_start, date_end) = match find_field "DATE" r.rsons with Some r -> decode_date_interval r.rpos r.rval | None -> None, None in let (name, title, place) = match find_field "NOTE" r.rsons with Some r -> if title = "" then Tnone, strip_spaces r.rval, "" else if r.rval = public_name then Tmain, title, place else Tname (add_string gen (strip_spaces r.rval)), title, place | None -> Tnone, title, place in {t_name = name; t_ident = add_string gen title; t_place = add_string gen place; t_date_start = Date.cdate_of_od date_start; t_date_end = Date.cdate_of_od date_end; t_nth = nth} let forward_adop gen ip lab which_parent = Hashtbl.add gen.g_adop lab (ip, match which_parent with Some r when r.rval <> "" -> r.rval | _ -> "BOTH") let adop_parent gen ip r = let i = per_index gen r.rval in match gen.g_per.arr.(i) with | Left3 _ -> None | Right3 (p, a, u) -> if List.mem ip p.related then () else begin let p = { p with related = ip :: p.related } in gen.g_per.arr.(i) <- Right3 (p, a, u) end; Some p.key_index let set_adop_fam gen ip which_parent fath moth = match gen.g_per.arr.(ip) with | Left3 _ -> () | Right3 (per, asc, uni) -> let r_fath = match which_parent, fath with ("HUSB" | "BOTH"), Some r -> adop_parent gen ip r | _ -> None in let r_moth = match which_parent, moth with ("WIFE" | "BOTH"), Some r -> adop_parent gen ip r | _ -> None in let r = {r_type = Adoption; r_fath = r_fath; r_moth = r_moth; r_sources = string_empty} in let per = { per with rparents = r :: per.rparents } in gen.g_per.arr.(ip) <- Right3 (per, asc, uni) let forward_godp gen ip rval = let ipp = per_index gen rval in gen.g_godp <- (ipp, ip) :: gen.g_godp; ipp let forward_witn gen ip rval = let ifam = fam_index gen rval in gen.g_witn <- (ifam, ip) :: gen.g_witn; ifam let forward_pevent_witn gen ip rval = let ipp = per_index gen rval in gen.g_prelated <- (ipp, ip) :: gen.g_prelated; ipp let forward_fevent_witn gen ip rval = let ipp = per_index gen rval in gen.g_frelated <- (ipp, ip) :: gen.g_frelated; ipp let glop = ref [] let indi_lab = function "ADOP" | "ASSO" | "BAPM" | "BIRT" | "BURI" | "CHR" | "CREM" | "DEAT" | "FAMC" | "FAMS" | "NAME" | "NOTE" | "OBJE" | "OCCU" | "SEX" | "SOUR" | "TITL" -> true | c -> if List.mem c !glop then () else begin glop := c :: !glop; Printf.eprintf "untreated tag %s -> in notes\n" c; flush stderr end; false let html_text_of_tags text rl = let rec tot len lev r = let len = Buff.mstore len (string_of_int lev) in let len = Buff.store len ' ' in let len = Buff.mstore len r.rlab in let len = if r.rval = "" then len else Buff.mstore (Buff.store len ' ') r.rval in let len = if r.rcont = "" then len else Buff.mstore (Buff.store len ' ') r.rcont in totl len (lev + 1) r.rsons and totl len lev rl = List.fold_left (fun len r -> let len = Buff.store len '\n' in tot len lev r) len rl in let title = if text = "" then "-- GEDCOM --" else "-- GEDCOM (" ^ text ^ ") --" in let len = 0 in let len = Buff.mstore len title in let len = totl len 1 rl in Buff.get len let rec find_all_rela nl = function [] -> [] | r :: rl -> match find_field "RELA" r.rsons with Some r1 -> let rec loop = function n :: nl1 -> let len = String.length n in if String.length r1.rval >= len && String.lowercase_ascii (String.sub r1.rval 0 len) = n then (n, r.rval) :: find_all_rela nl rl else loop nl1 | [] -> find_all_rela nl rl in loop nl | None -> find_all_rela nl rl let witness_kind_of_rval rval = match rval with | "GODP" -> Witness_GodParent | "officer" | "Civil officer" | "Registry officer" -> Witness_CivilOfficer | "Religious officer" | "Officiating priest" -> Witness_ReligiousOfficer | "Informant" -> Witness_Informant | "Attending" -> Witness_Attending | "Mentioned" -> Witness_Mentioned | "Other" -> Witness_Other | _ -> Witness let find_event_witness gen tag ip r = let rec find_witnesses = function [] -> [] | r :: asso_l -> if find_field_with_value "TYPE" tag r.rsons then let witness = forward_pevent_witn gen ip (strip_spaces r.rval) in let witness_kind = match find_field "RELA" r.rsons with Some rr -> witness_kind_of_rval rr.rval | _ -> Witness in (witness, witness_kind) :: find_witnesses asso_l else let witness = forward_pevent_witn gen ip (strip_spaces r.rval) in let witness_kind = match find_field "RELA" r.rsons with Some rr -> witness_kind_of_rval rr.rval | _ -> Witness in (witness, witness_kind) :: find_witnesses asso_l in let witnesses = match find_all_fields "ASSO" r.rsons with [] -> [] | wl -> find_witnesses wl in Array.of_list witnesses let find_fevent_witness gen tag ifath r = let rec find_witnesses = function [] -> [] | r :: asso_l -> if find_field_with_value "TYPE" tag r.rsons then let witness = forward_fevent_witn gen ifath (strip_spaces r.rval) in let witness_kind = match find_field "RELA" r.rsons with Some rr -> witness_kind_of_rval rr.rval | _ -> Witness in (witness, witness_kind) :: find_witnesses asso_l else let witness = forward_fevent_witn gen ifath (strip_spaces r.rval) in let witness_kind = match find_field "RELA" r.rsons with Some rr -> witness_kind_of_rval rr.rval | _ -> Witness in (witness, witness_kind) :: find_witnesses asso_l in let witnesses = match find_all_fields "ASSO" r.rsons with [] -> [] | wl -> find_witnesses wl in Array.of_list witnesses let find_pevent_name_from_tag gen tag tagv = match tag with "BIRT" -> Epers_Birth | "BAPM" | "CHR" -> Epers_Baptism | "DEAT" -> Epers_Death | "BURI" -> Epers_Burial | "CREM" -> Epers_Cremation | "accomplishment" -> Epers_Accomplishment | "acquisition" -> Epers_Acquisition | "award" | "distinction" -> Epers_Distinction | "BAPL" | "lds baptism" -> Epers_BaptismLDS | "BARM" -> Epers_BarMitzvah | "BASM" -> Epers_BatMitzvah | "BLES" -> Epers_Benediction | "CENS" -> Epers_Recensement | "circumcision" -> Epers_Circumcision | "CONF" -> Epers_Confirmation | "CONL" | "lds confirmation" -> Epers_ConfirmationLDS | "degree" -> Epers_Diploma | "DECO" -> Epers_Decoration | "lds dotation" | "lds endowment" -> Epers_DotationLDS | "EDUC" -> Epers_Education | "election" -> Epers_Election | "EMIG" -> Epers_Emigration | "ENDL" -> Epers_Dotation | "excommunication" -> Epers_Excommunication | "family link lds" -> Epers_FamilyLinkLDS | "FCOM" -> Epers_FirstCommunion | "funeral" -> Epers_Funeral | "GRAD" -> Epers_Graduate | "hospitalization" -> Epers_Hospitalisation | "illness" -> Epers_Illness | "IMMI" -> Epers_Immigration | "membership" -> Epers_Adhesion | "military discharge" -> Epers_DemobilisationMilitaire | "military distinction" -> Epers_MilitaryDistinction | "military promotion" -> Epers_MilitaryPromotion | "military service" -> Epers_MilitaryService | "military mobilization" -> Epers_MobilisationMilitaire | "change name" -> Epers_ChangeName | "NATU" -> Epers_Naturalisation | "OCCU" | "occupation" -> Epers_Occupation | "ORDN" -> Epers_Ordination | "passenger list" -> Epers_ListePassenger | "PROP" -> Epers_Property | "RESI" | "residence" -> Epers_Residence | "RETI" -> Epers_Retired | "scellent parent lds" -> Epers_ScellentParentLDS | "SLGC" | "lds sealing child" -> Epers_ScellentChildLDS | "SLGS" | "lds sealing spouse" -> Epers_ScellentSpouseLDS | "property sale" -> Epers_VenteBien | "WILL" -> Epers_Will | _ -> Epers_Name (add_string gen (strip_spaces tagv)) let primary_pevents = ["BAPM"; "CHR"; "BAPL"; "BARM"; "BASM"; "BIRT"; "BLES"; "BURI"; "CENS"; "CONF"; "CONL"; "CREM"; "DEAT"; "DECO"; "EDUC"; "EMIG"; "ENDL"; "FCOM"; "GRAD"; "IMMI"; "NATU"; "OCCU"; "ORDN"; "PROP"; "RETI"; "RESI"; "SLGS"; "SLGC"; "WILL"] let treat_indi_pevent gen ip r = let prim_events = List.fold_left (fun events tag -> List.fold_left (fun events r -> let name = find_pevent_name_from_tag gen tag tag in let date = match find_field "DATE" r.rsons with Some r -> date_of_field r.rval | None -> None in let place = match find_field "PLAC" r.rsons with Some r -> strip_spaces r.rval | _ -> "" in let reason = "" in let note = match find_all_fields "NOTE" r.rsons with [] -> "" | rl -> treat_notes gen rl in (* Si le tag 1 XXX a des infos, on les ajoutes. *) let note = let name_info = strip_spaces r.rval in if name_info = "" || r.rval = "Y" then note else name_info ^ "
\n" ^ note in let src = match find_all_fields "SOUR" r.rsons with [] -> "" | rl -> let rec loop first src rl = match rl with [] -> src | r :: rl -> let (src_cont, _) = treat_source gen r in let src = if first then src ^ src_cont else src ^ " " ^ src_cont in loop false src rl in loop true "" rl in let witnesses = find_event_witness gen "INDI" ip r in let evt = {epers_name = name; epers_date = Date.cdate_of_od date; epers_place = add_string gen place; epers_reason = add_string gen reason; epers_note = add_string gen note; epers_src = add_string gen src; epers_witnesses = witnesses} in (* On ajoute que les évènements non vides, sauf *) (* s'il est spécifié qu'il faut l'ajouter. *) if date <> None || place <> "" || note <> "" || src <> "" || witnesses <> [| |] || r.rval = "Y" then if name = Epers_Occupation then if r.rsons <> [] then evt :: events else events else evt :: events else events) events (find_all_fields tag r.rsons)) [] primary_pevents in let second_events = List.fold_left (fun events r -> match find_field "TYPE" r.rsons with Some rr -> if rr.rval <> "" then let name = if List.mem rr.rval primary_pevents then find_pevent_name_from_tag gen rr.rval rr.rval else find_pevent_name_from_tag gen (String.lowercase_ascii rr.rval) rr.rval in let date = match find_field "DATE" r.rsons with Some r -> date_of_field r.rval | None -> None in let place = match find_field "PLAC" r.rsons with Some r -> strip_spaces r.rval | _ -> "" in let reason = "" in let note = match find_all_fields "NOTE" r.rsons with [] -> "" | rl -> treat_notes gen rl in (* Si le tag 1 XXX a des infos, on les ajoutes. *) let note = let name_info = strip_spaces r.rval in if name_info = "" || r.rval = "Y" then note else name_info ^ "
\n" ^ note in let src = match find_all_fields "SOUR" r.rsons with [] -> "" | rl -> let rec loop first src rl = match rl with [] -> src | r :: rl -> let (src_cont, _) = treat_source gen r in let src = if first then src ^ src_cont else src ^ " " ^ src_cont in loop false src rl in loop true "" rl in let witnesses = find_event_witness gen "INDI" ip r in let evt = {epers_name = name; epers_date = Date.cdate_of_od date; epers_place = add_string gen place; epers_reason = add_string gen reason; epers_note = add_string gen note; epers_src = add_string gen src; epers_witnesses = witnesses} in (* On ajoute que les évènements non vides, *) (* sauf si évènement personnalisé ! *) let has_epers_name = match name with Epers_Name n -> n <> string_empty | _ -> false in if has_epers_name || date <> None || place <> "" || note <> "" || src <> "" || witnesses <> [| |] then evt :: events else events else events | None -> events) [] (find_all_fields "EVEN" r.rsons) in List.rev_append prim_events second_events let rec build_remain_tags = function [] -> [] | r :: rest -> let rsons = if indi_lab r.rlab then [] else build_remain_tags r.rsons in let rest = build_remain_tags rest in if r.rused = true && rsons = [] then rest else {rlab = r.rlab; rval = r.rval; rcont = r.rcont; rsons = rsons; rpos = r.rpos; rused = r.rused} :: rest let applycase_surname s = match !case_surnames with NoCase -> s | LowerCase -> capitalize_name s | UpperCase -> if !charset = Utf8 then uppercase_name s else String.uppercase_ascii s let reconstitute_from_pevents pevents bi bp de bu = let found_birth = ref false in let found_baptism = ref false in let found_death = ref false in let found_burial = ref false in let rec loop pevents bi bp de bu = match pevents with [] -> bi, bp, de, bu | evt :: l -> match evt.epers_name with Epers_Birth -> if !found_birth then loop l bi bp de bu else let bi = evt.epers_date, evt.epers_place, evt.epers_note, evt.epers_src in let () = found_birth := true in loop l bi bp de bu | Epers_Baptism -> if !found_baptism then loop l bi bp de bu else let bp = evt.epers_date, evt.epers_place, evt.epers_note, evt.epers_src in let () = found_baptism := true in loop l bi bp de bu | Epers_Death -> if !found_death then loop l bi bp de bu else let death = match Date.od_of_cdate evt.epers_date with | Some d -> Death (Unspecified, Date.cdate_of_date d) | None -> DeadDontKnowWhen in let de = death, evt.epers_place, evt.epers_note, evt.epers_src in let () = found_death := true in loop l bi bp de bu | Epers_Burial -> if !found_burial then loop l bi bp de bu else let bu = Buried evt.epers_date, evt.epers_place, evt.epers_note, evt.epers_src in let () = found_burial := true in loop l bi bp de bu | Epers_Cremation -> if !found_burial then loop l bi bp de bu else let bu = Cremated evt.epers_date, evt.epers_place, evt.epers_note, evt.epers_src in let () = found_burial := true in loop l bi bp de bu | _ -> loop l bi bp de bu in loop pevents bi bp de bu let add_indi gen r = let ip = per_index gen r.rval in let name_sons = find_field "NAME" r.rsons in let givn = match name_sons with Some n -> begin match find_field "GIVN" n.rsons with Some r -> r.rval | None -> "" end | None -> "" in let (first_name, surname, occ, public_name, first_names_aliases) = match name_sons with | Some n -> let (f, s) = parse_name (Stream.of_string n.rval) in let pn = "" in let fal = if givn = f then [] else [givn] in let (f, fal) = match !first_names_brackets with Some (bb, eb) -> let first_enclosed f = let i = String.index f bb in let j = if i + 2 >= String.length f then raise Not_found else String.index_from f (i + 2) eb in let fn = String.sub f (i + 1) (j - i - 1) in let fa = String.sub f 0 i ^ fn ^ String.sub f (j + 1) (String.length f - j - 1) in fn, fa in let rec loop first ff accu = try let (fn, fa) = first_enclosed ff in let accu = if first then fn else if fn <> "" then accu ^ " " ^ fn else accu in loop false fa accu with Not_found -> if f = ff then f, fal else accu, ff :: fal in loop true f "" | None -> f, fal in let (f, pn, fal) = if !extract_public_names || !extract_first_names then let i = next_word_pos f 0 in let j = next_sep_pos f i in if j = String.length f then f, pn, fal else let fn = String.sub f i (j - i) in if pn = "" && !extract_public_names then if is_a_public_name f j then fn, f, fal else if !extract_first_names then fn, "", f :: fal else f, "", fal else fn, pn, f :: fal else f, pn, fal in let f = if !lowercase_first_names then capitalize_name f else f in let fal = if !lowercase_first_names then List.map capitalize_name fal else fal in let pn = if capitalize_name pn = f then "" else pn in let pn = if !lowercase_first_names then capitalize_name pn else pn in let fal = List.fold_right (fun fa fal -> if fa = pn then fal else fa :: fal) fal [] in let s = applycase_surname s in let r = let key = Name.strip_lower (Mutil.nominative f ^ " " ^ Mutil.nominative s) in try Hashtbl.find gen.g_hnam key with Not_found -> let r = ref (-1) in Hashtbl.add gen.g_hnam key r ; r in incr r; f, s, !r, pn, fal | None -> "?", "?", ip, givn, [] in (* S'il y a des caractères interdits, on les supprime *) let (first_name, surname) = Name.strip_c first_name ':', Name.strip_c surname ':' in let qualifier = match name_sons with Some n -> begin match find_field "NICK" n.rsons with Some r -> r.rval | None -> "" end | None -> "" in let surname_aliases = match name_sons with Some n -> begin match find_field "SURN" n.rsons with Some r -> let list = purge_list (list_of_string r.rval) in List.fold_right (fun x list -> let x = applycase_surname x in if x <> surname then x :: list else list) list [] | _ -> [] end | None -> [] in let aliases = match find_all_fields "NAME" r.rsons with _ :: l -> List.map (fun r -> r.rval) l | _ -> [] in let sex = match find_field "SEX" r.rsons with Some {rval = "M"} -> Male | Some {rval = "F"} -> Female | _ -> Neuter in let image = match find_field "OBJE" r.rsons with Some r -> begin match find_field "FILE" r.rsons with Some r -> if !no_picture then "" else r.rval | None -> "" end | None -> "" in let parents = match find_field "FAMC" r.rsons with Some r -> Some (fam_index gen r.rval) | None -> None in (* On ne prend que les professions sans info supplémentaires. *) let occupation = let l = List.fold_right (fun r l -> if r.rsons = [] then strip_spaces r.rval :: l else l) (find_all_fields "OCCU" r.rsons) [] in String.concat ", " l in let notes = match find_all_fields "NOTE" r.rsons with [] -> "" | rl -> treat_notes gen rl in let titles = List.map (treat_indi_title gen public_name) (find_all_fields "TITL" r.rsons) in let pevents = treat_indi_pevent gen ip r in let family = let rl = find_all_fields "FAMS" r.rsons in let rvl = List.fold_right (fun r rvl -> if List.mem r.rval rvl then rvl else r.rval :: rvl) rl [] in List.map (fun r -> fam_index gen r) rvl in let rasso = find_all_fields "ASSO" r.rsons in let rparents = let godparents = find_all_rela ["godf"; "godm"; "godp"] rasso in let godparents = if godparents = [] then let ro = match find_field "BAPM" r.rsons with None -> find_field "CHR" r.rsons | x -> x in if ro <> None then find_all_rela ["godf"; "godm"; "godp"] rasso else [] else godparents in let rec loop rl = if rl <> [] then let (r_fath, rl) = match rl with ("godf", r) :: rl -> Some (forward_godp gen ip r), rl | _ -> None, rl in let (r_moth, rl) = match rl with ("godm", r) :: rl -> Some (forward_godp gen ip r), rl | _ -> None, rl in let (r_fath, r_moth, rl) = if r_fath <> None || r_moth <> None then r_fath, r_moth, rl else let (r_fath, rl) = match rl with ("godp", r) :: rl -> Some (forward_godp gen ip r), rl | _ -> None, rl in r_fath, None, rl in let r = {r_type = GodParent; r_fath = r_fath; r_moth = r_moth; r_sources = string_empty} in r :: loop rl else [] in loop godparents in let witn = find_all_rela ["witness"] rasso in let () = List.iter (fun (_, rval) -> (@@) ignore (forward_witn gen ip rval)) witn in let (birth, birth_place, (birth_note, _), (birth_src, birth_nt)) = match find_field "BIRT" r.rsons with Some r -> let d = match find_field "DATE" r.rsons with Some r -> date_of_field r.rval | _ -> None in let p = match find_field "PLAC" r.rsons with Some r -> strip_spaces r.rval | _ -> "" in let note = match find_all_fields "NOTE" r.rsons with [] -> "" | rl -> treat_notes gen rl in d, p, (note, []), source gen r | None -> None, "", ("", []), ("", []) in let (bapt, bapt_place, (bapt_note, _), (bapt_src, bapt_nt)) = let ro = match find_field "BAPM" r.rsons with None -> find_field "CHR" r.rsons | x -> x in match ro with Some r -> let d = match find_field "DATE" r.rsons with Some r -> date_of_field r.rval | _ -> None in let p = match find_field "PLAC" r.rsons with Some r -> strip_spaces r.rval | _ -> "" in let note = match find_all_fields "NOTE" r.rsons with [] -> "" | rl -> treat_notes gen rl in d, p, (note, []), source gen r | None -> None, "", ("", []), ("", []) in let (death, death_place, (death_note, _), (death_src, death_nt)) = match find_field "DEAT" r.rsons with | Some r -> if r.rsons = [] then if r.rval = "Y" then DeadDontKnowWhen, "", ("", []), ("", []) else infer_death birth bapt, "", ("", []), ("", []) else let d = match find_field "DATE" r.rsons with Some r -> begin match date_of_field r.rval with | Some d -> Death (Unspecified, Date.cdate_of_date d) | None -> DeadDontKnowWhen end | _ -> DeadDontKnowWhen in let p = match find_field "PLAC" r.rsons with | Some r -> strip_spaces r.rval | None -> "" in let note = match find_all_fields "NOTE" r.rsons with | [] -> "" | rl -> treat_notes gen rl in d, p, (note, []), source gen r | None -> infer_death birth bapt, "", ("", []), ("", []) in let (burial, burial_place, (burial_note, _), (burial_src, burial_nt)) = let (buri, buri_place, (buri_note, _), (buri_src, buri_nt)) = match find_field "BURI" r.rsons with Some r -> if r.rsons = [] then if r.rval = "Y" then Buried Date.cdate_None, "", ("", []), ("", []) else UnknownBurial, "", ("", []), ("", []) else let d = match find_field "DATE" r.rsons with Some r -> date_of_field r.rval | _ -> None in let p = match find_field "PLAC" r.rsons with Some r -> strip_spaces r.rval | _ -> "" in let note = match find_all_fields "NOTE" r.rsons with [] -> "" | rl -> treat_notes gen rl in Buried (Date.cdate_of_od d), p, (note, []), source gen r | None -> UnknownBurial, "", ("", []), ("", []) in let (crem, crem_place, (crem_note, _), (crem_src, crem_nt)) = match find_field "CREM" r.rsons with Some r -> if r.rsons = [] then if r.rval = "Y" then Cremated Date.cdate_None, "", ("", []), ("", []) else UnknownBurial, "", ("", []), ("", []) else let d = match find_field "DATE" r.rsons with Some r -> date_of_field r.rval | _ -> None in let p = match find_field "PLAC" r.rsons with Some r -> strip_spaces r.rval | _ -> "" in let note = match find_all_fields "NOTE" r.rsons with [] -> "" | rl -> treat_notes gen rl in Cremated (Date.cdate_of_od d), p, (note, []), source gen r | None -> UnknownBurial, "", ("", []), ("", []) in match buri, crem with UnknownBurial, Cremated _ -> crem, crem_place, (crem_note, []), (crem_src, crem_nt) | _ -> buri, buri_place, (buri_note, []), (buri_src, buri_nt) in let birth =Date.cdate_of_od birth in let bapt =Date.cdate_of_od bapt in let (psources, psources_nt) = let (s, s_nt) = source gen r in if s = "" then !default_source, s_nt else s, s_nt in let ext_notes = let concat_text s1 s2 s_sep = let s = if s1 = "" && notes = "" || s2 = "" then "" else s_sep in s1 ^ s ^ s2 in let text = concat_text "" (notes_from_source_record birth_nt) "
\n" in let text = concat_text text (notes_from_source_record bapt_nt) "
\n" in let text = concat_text text (notes_from_source_record death_nt) "
\n" in let text = concat_text text (notes_from_source_record burial_nt) "
\n" in let text = concat_text text (notes_from_source_record psources_nt) "
\n" in if !untreated_in_notes then let remain_tags_in_notes text init rtl = let rtl = build_remain_tags rtl in if rtl = [] then init else concat_text init (html_text_of_tags text rtl) "\n" in let nt = remain_tags_in_notes "INDI" "" r.rsons in let nt = remain_tags_in_notes "BIRT SOUR" nt birth_nt in let nt = remain_tags_in_notes "BAPT SOUR" nt bapt_nt in let nt = remain_tags_in_notes "DEAT SOUR" nt death_nt in let nt = remain_tags_in_notes "BURI/CREM SOUR" nt burial_nt in let nt = remain_tags_in_notes "SOUR SOUR" nt psources_nt in if nt = "" then text else text ^ "
\n" ^ nt ^ "\n
" else text in (* Mise à jour des évènements principaux. *) let (birth_place, birth_note, birth_src) = add_string gen birth_place, add_string gen birth_note, add_string gen birth_src in let (bapt_place, bapt_note, bapt_src) = add_string gen bapt_place, add_string gen bapt_note, add_string gen bapt_src in let (death_place, death_note, death_src) = add_string gen death_place, add_string gen death_note, add_string gen death_src in let (burial_place, burial_note, burial_src) = add_string gen burial_place, add_string gen burial_note, add_string gen burial_src in (* On tri les évènements pour être sûr. *) let pevents = Event.sort_events (fun evt -> Event.Pevent evt.epers_name) (fun evt -> evt.epers_date) pevents in let (bi, bp, de, bu) = reconstitute_from_pevents pevents (birth, birth_place, birth_note, birth_src) (bapt, bapt_place, bapt_note, bapt_src) (death, death_place, death_note, death_src) (burial, burial_place, burial_note, burial_src) in let (birth, birth_place, birth_note, birth_src) = bi in let (bapt, bapt_place, bapt_note, bapt_src) = bp in let (death, death_place, death_note, death_src) = de in let (burial, burial_place, burial_note, burial_src) = bu in let person = {first_name = add_string gen first_name; surname = add_string gen surname; occ = occ; public_name = add_string gen public_name; image = add_string gen image; qualifiers = if qualifier <> "" then [add_string gen qualifier] else []; aliases = List.map (add_string gen) aliases; first_names_aliases = List.map (add_string gen) first_names_aliases; surnames_aliases = List.map (add_string gen) surname_aliases; titles = titles; rparents = rparents; related = []; occupation = add_string gen occupation; sex = sex; access = if !no_public_if_titles && titles = [] then Private else IfTitles; birth = birth; birth_place = birth_place; birth_note = birth_note; birth_src = birth_src; baptism = bapt; baptism_place = bapt_place; baptism_note = bapt_note; baptism_src = bapt_src; death = death; death_place = death_place; death_note = death_note; death_src = death_src; burial = burial; burial_place = burial_place; burial_note = burial_note; burial_src = burial_src; pevents = pevents; notes = add_string gen (notes ^ ext_notes); psources = add_string gen psources; key_index = ip} in let ascend = {parents = parents; consang = Adef.fix (-1)} in let union = {family = Array.of_list family} in gen.g_per.arr.(ip) <- Right3 (person, ascend, union); begin match find_field "ADOP" r.rsons with | Some r -> begin match find_field "FAMC" r.rsons with | Some r -> forward_adop gen ip r.rval (find_field "ADOP" r.rsons) | _ -> () end | _ -> () end; r.rused <- true let find_fevent_name_from_tag gen tag tagv = match tag with "MARR" -> Efam_Marriage | "unmarried" -> Efam_NoMarriage | "nomen" -> Efam_NoMention | "ENGA" -> Efam_Engage | "DIV" -> Efam_Divorce | "SEP" | "separation" -> Efam_Separated | "ANUL" -> Efam_Annulation | "MARB" -> Efam_MarriageBann | "MARC" -> Efam_MarriageContract | "MARL" -> Efam_MarriageLicense | "pacs" -> Efam_PACS | "RESI" | "residence" -> Efam_Residence | _ -> Efam_Name (add_string gen (strip_spaces tagv)) let primary_fevents = ["ANUL"; "DIV"; "ENGA"; "MARR"; "MARB"; "MARC"; "MARL"; "RESI"; "SEP"] (* Types d'évènement présents seulement dans les tags de niveau 2 (2 TYPE). *) let secondary_fevent_types = [Efam_NoMarriage; Efam_NoMention] let treat_fam_fevent gen ifath r = let check_place_unmarried efam_name place r = match find_all_fields "PLAC" r.rsons with r :: rl -> if String.uncapitalize_ascii r.rval = "unmarried" then Efam_NoMarriage, "" else let place = strip_spaces r.rval in let rec loop = function r :: rl -> if String.uncapitalize_ascii r.rval = "unmarried" then Efam_NoMarriage, place else loop rl | [] -> efam_name, place in loop rl | [] -> efam_name, place in let prim_events = List.fold_left (fun events tag -> List.fold_left (fun events r -> let name = find_fevent_name_from_tag gen tag tag in let date = match find_field "DATE" r.rsons with Some r -> date_of_field r.rval | None -> None in let place = match find_field "PLAC" r.rsons with Some r -> strip_spaces r.rval | _ -> "" in let reason = "" in let note = match find_all_fields "NOTE" r.rsons with [] -> "" | rl -> treat_notes gen rl in (* Si le tag 1 XXX a des infos, on les ajoutes. *) let note = let name_info = strip_spaces r.rval in if name_info = "" || r.rval = "Y" then note else name_info ^ "
\n" ^ note in let src = match find_all_fields "SOUR" r.rsons with [] -> "" | rl -> let rec loop first src rl = match rl with [] -> src | r :: rl -> let (src_cont, _) = treat_source gen r in let src = if first then src ^ src_cont else src ^ " " ^ src_cont in loop false src rl in loop true "" rl in let witnesses = find_fevent_witness gen "INDI" ifath r in (* Vérification du mariage. *) let (name, place) = match name with Efam_Marriage -> begin match find_field "TYPE" r.rsons with Some r -> if String.uncapitalize_ascii r.rval = "unmarried" then Efam_NoMarriage, place else check_place_unmarried name place r | None -> check_place_unmarried name place r end | _ -> name, place in let evt = {efam_name = name; efam_date = Date.cdate_of_od date; efam_place = add_string gen place; efam_reason = add_string gen reason; efam_note = add_string gen note; efam_src = add_string gen src; efam_witnesses = witnesses} in (* On ajoute toujours les évènements principaux liés à la *) (* famille, sinon, on peut avoir un problème si on supprime *) (* l'évènement, celui ci sera remplacé par la relation par *) (* défaut. *) evt :: events) events (find_all_fields tag r.rsons)) [] primary_fevents in let second_events = List.fold_left (fun events r -> match find_field "TYPE" r.rsons with Some rr -> if rr.rval <> "" then let name = if List.mem rr.rval primary_fevents then find_fevent_name_from_tag gen rr.rval rr.rval else find_fevent_name_from_tag gen (String.lowercase_ascii rr.rval) rr.rval in let date = match find_field "DATE" r.rsons with Some r -> date_of_field r.rval | None -> None in let place = match find_field "PLAC" r.rsons with Some r -> strip_spaces r.rval | _ -> "" in let reason = "" in let note = match find_all_fields "NOTE" r.rsons with [] -> "" | rl -> treat_notes gen rl in (* Si le tag 1 XXX a des infos, on les ajoutes. *) let note = let name_info = strip_spaces r.rval in if name_info = "" || r.rval = "Y" then note else name_info ^ "
\n" ^ note in let src = match find_all_fields "SOUR" r.rsons with [] -> "" | rl -> let rec loop first src rl = match rl with [] -> src | r :: rl -> let (src_cont, _) = treat_source gen r in let src = if first then src ^ src_cont else src ^ " " ^ src_cont in loop false src rl in loop true "" rl in let witnesses = find_fevent_witness gen "INDI" ifath r in let evt = {efam_name = name; efam_date = Date.cdate_of_od date; efam_place = add_string gen place; efam_reason = add_string gen reason; efam_note = add_string gen note; efam_src = add_string gen src; efam_witnesses = witnesses} in (* On n'ajoute que les évènements non vides, *) (* sauf si évènement personnalisé et les évènements *) (* des tags de niveau 2 (qui peuvent être vides). *) let has_efam_name = match name with Efam_Name n -> n <> string_empty | _ -> false in if has_efam_name || date <> None || place <> "" || note <> "" || src <> "" || witnesses <> [| |] || List.mem name secondary_fevent_types then evt :: events else events else events | None -> events) [] (find_all_fields "EVEN" r.rsons) in List.rev_append prim_events second_events let reconstitute_from_fevents gen gay fevents marr witn div = let found_marriage = ref false in let found_divorce = ref false in (* On veut cette fois ci que ce soit le dernier évènement *) (* qui soit mis dans les évènements principaux. *) let rec loop fevents marr witn div = match fevents with [] -> marr, witn, div | evt :: l -> match evt.efam_name with Efam_Engage -> if !found_marriage then loop l marr witn div else let witn = Array.map fst evt.efam_witnesses in let marr = Engaged, evt.efam_date, evt.efam_place, evt.efam_note, evt.efam_src in let () = found_marriage := true in loop l marr witn div | Efam_Marriage -> let witn = Array.map fst evt.efam_witnesses in let marr = Married, evt.efam_date, evt.efam_place, evt.efam_note, evt.efam_src in let () = found_marriage := true in marr, witn, div | Efam_MarriageContract -> if !found_marriage then loop l marr witn div else let witn = Array.map fst evt.efam_witnesses in (* Pour différencier le fait qu'on recopie le *) (* mariage, on met une précision "vers". *) let date = match Date.od_of_cdate evt.efam_date with | Some (Dgreg (dmy, cal)) -> let dmy = {dmy with prec = About} in Date.cdate_of_od (Some (Dgreg (dmy, cal))) | _ -> evt.efam_date in (* Pour différencier le fait qu'on recopie le *) (* mariage, on ne met pas de lieu. *) let place = add_string gen "" in let marr = Married, date, place, evt.efam_note, evt.efam_src in let () = found_marriage := true in loop l marr witn div | Efam_NoMention | Efam_MarriageBann | Efam_MarriageLicense | Efam_Annulation | Efam_PACS -> if !found_marriage then loop l marr witn div else let witn = Array.map fst evt.efam_witnesses in let marr = NoMention, evt.efam_date, evt.efam_place, evt.efam_note, evt.efam_src in let () = found_marriage := true in loop l marr witn div | Efam_NoMarriage -> if !found_marriage then loop l marr witn div else let witn = Array.map fst evt.efam_witnesses in let marr = NotMarried, evt.efam_date, evt.efam_place, evt.efam_note, evt.efam_src in let () = found_marriage := true in loop l marr witn div | Efam_Divorce -> if !found_divorce then loop l marr witn div else let div = Divorced evt.efam_date in let () = found_divorce := true in loop l marr witn div | Efam_Separated -> if !found_divorce then loop l marr witn div else let div = Separated in let () = found_divorce := true in loop l marr witn div | _ -> loop l marr witn div in let (marr, witn, div) = loop (List.rev fevents) marr witn div in (* Parents de même sexe. *) if gay then let (relation, date, place, note, src) = marr in let relation = match relation with Married | NoSexesCheckMarried -> NoSexesCheckMarried | _ -> NoSexesCheckNotMarried in let marr = relation, date, place, note, src in marr, witn, div else marr, witn, div let add_fam_norm gen r adop_list = let i = fam_index gen r.rval in let (fath, moth, gay) = match find_all_fields "HUSB" r.rsons, find_all_fields "WIFE" r.rsons with | [f1], [m1] -> per_index gen f1.rval, per_index gen m1.rval, false | [f1; f2], [] -> per_index gen f1.rval, per_index gen f2.rval, true | [], [m1; m2] -> per_index gen m1.rval, per_index gen m2.rval, true | _ -> let fath = match find_field "HUSB" r.rsons with Some r -> per_index gen r.rval | None -> phony_per gen Male in let moth = match find_field "WIFE" r.rsons with Some r -> per_index gen r.rval | None -> phony_per gen Female in fath, moth, false in begin match gen.g_per.arr.(fath) with | Left3 _ -> () | Right3 (p, a, u) -> let u = if not (Array.mem i u.family) then { family = Array.append u.family [| i |] } else u in let p = if p.sex = Neuter then { p with sex = Male } else p in gen.g_per.arr.(fath) <- Right3 (p, a, u) end ; begin match gen.g_per.arr.(moth) with | Left3 _ -> () | Right3 (p, a, u) -> let u = if not (Array.mem i u.family) then { family = Array.append u.family [| i |] } else u in let p = if p.sex = Neuter then { p with sex = Female } else p in gen.g_per.arr.(moth) <- Right3 (p, a, u) end; let children = let rl = find_all_fields "CHIL" r.rsons in List.fold_right begin fun r ipl -> let ip = per_index gen r.rval in if List.mem_assoc ip adop_list then match gen.g_per.arr.(ip) with | Right3 (p, a, u) -> begin match a.parents with | Some ifam when ifam = i -> let a = { a with parents = None } in gen.g_per.arr.(ip) <- Right3 (p, a, u) ; ipl | _ -> ip :: ipl end | _ -> ip :: ipl else ip :: ipl end rl [] in let (relation, marr, marr_place, (marr_note, _), (marr_src, marr_nt), witnesses) = let (relation, sons) = match find_field "MARR" r.rsons with | Some r -> if gay then NoSexesCheckMarried, Some r else Married, Some r | None -> match find_field "ENGA" r.rsons with | Some r -> Engaged, Some r | None -> !relation_status, None in match sons with Some r -> let (u, p) = match find_all_fields "PLAC" r.rsons with r :: rl -> if String.uncapitalize_ascii r.rval = "unmarried" then NotMarried, "" else let p = strip_spaces r.rval in let rec loop = function r :: rl -> if String.uncapitalize_ascii r.rval = "unmarried" then NotMarried, p else loop rl | [] -> relation, p in loop rl | [] -> relation, "" in let u = match find_field "TYPE" r.rsons with Some r -> if String.uncapitalize_ascii r.rval = "gay" then NoSexesCheckNotMarried else u | None -> u in let d = match find_field "DATE" r.rsons with Some r -> date_of_field r.rval | _ -> None in let rec heredis_witnesses = function [] -> [] | r :: asso_l -> if find_field_with_value "RELA" "Witness" r.rsons && find_field_with_value "TYPE" "INDI" r.rsons then let witness = per_index gen r.rval in witness :: heredis_witnesses asso_l else begin r.rused <- false; heredis_witnesses asso_l end in let witnesses = match find_all_fields "ASSO" r.rsons with [] -> [] | wl -> heredis_witnesses wl in let note = match find_all_fields "NOTE" r.rsons with [] -> "" | rl -> treat_notes gen rl in u, d, p, (note, []), source gen r, witnesses | None -> relation, None, "", ("", []), ("", []), [] in let witnesses = Array.of_list witnesses in let div = match find_field "DIV" r.rsons with Some r -> begin match find_field "DATE" r.rsons with Some d -> Divorced (Date.cdate_of_od (date_of_field d.rval)) | _ -> match find_field "PLAC" r.rsons with Some _ -> Divorced Date.cdate_None | _ -> if r.rval = "Y" then Divorced Date.cdate_None else NotDivorced end | None -> NotDivorced in let fevents = treat_fam_fevent gen fath r in let comment = match find_all_fields "NOTE" r.rsons with [] -> "" | rl -> treat_notes gen rl in let (fsources, fsources_nt) = let (s, s_nt) = source gen r in if s = "" then !default_source, s_nt else s, s_nt in let concat_text s1 s2 s_sep = let s = if s1 = "" then "" else s_sep in s1 ^ s ^ s2 in let ext_sources = let text = concat_text "" (notes_from_source_record marr_nt) "
\n" in concat_text text (notes_from_source_record fsources_nt) "
\n" in let ext_notes = if !untreated_in_notes then let remain_tags_in_notes text init rtl = let rtl = build_remain_tags rtl in if rtl = [] then init else concat_text init (html_text_of_tags text rtl) "\n" in let nt = remain_tags_in_notes "FAM" "" r.rsons in let nt = remain_tags_in_notes "MARR SOUR" nt marr_nt in let nt = remain_tags_in_notes "SOUR SOUR" nt fsources_nt in if nt = "" then "" else "
\n" ^ nt ^ "\n
" else "" in let add_in_person_notes iper = match gen.g_per.arr.(iper) with | Left3 _ -> () | Right3 (p, a, u) -> let notes = gen.g_str.arr.(p.notes) in let notes = if notes = "" then ext_sources ^ ext_notes else if ext_sources = "" then notes ^ "\n" ^ ext_notes else notes ^ "
\n" ^ ext_sources ^ ext_notes in let new_notes = add_string gen notes in let p = { p with notes = new_notes } in gen.g_per.arr.(iper) <- Right3 (p, a, u) in let _ = if ext_notes = "" then () else begin add_in_person_notes fath; add_in_person_notes moth end in (* Mise à jour des évènements principaux. *) let (marr, marr_place, marr_note, marr_src) = Date.cdate_of_od marr, add_string gen marr_place, add_string gen marr_note, add_string gen marr_src in (* On tri les évènements pour être sûr. *) let fevents = Event.sort_events (fun evt -> Event.Fevent evt.efam_name) (fun evt -> evt.efam_date) fevents in let (marr, witn, div) = reconstitute_from_fevents gen gay fevents (relation, marr, marr_place, marr_note, marr_src) witnesses div in let (relation, marr, marr_place, marr_note, marr_src) = marr in let witnesses = witn in let div = div in let fam = {marriage = marr; marriage_place = marr_place; marriage_note = marr_note; marriage_src = marr_src; witnesses = witnesses; relation = relation; divorce = div; fevents = fevents; comment = add_string gen comment; origin_file = string_empty; fsources = add_string gen fsources; fam_index = i} and cpl = Adef.couple fath moth and des = {children = Array.of_list children} in gen.g_fam.arr.(i) <- Right3 (fam, cpl, des) let add_fam gen r = let list = Hashtbl.find_all gen.g_adop r.rval in match list with [] -> add_fam_norm gen r [] | list -> let husb = find_field "HUSB" r.rsons in let wife = find_field "WIFE" r.rsons in List.iter (fun (ip, which_parent) -> set_adop_fam gen ip which_parent husb wife) list; match find_field "CHIL" r.rsons with Some _ -> add_fam_norm gen r list | _ -> () let treat_header2 r = begin match !charset_option with Some v -> charset := v | None -> match find_field "CHAR" r.rsons with Some r -> begin match r.rval with "ANSEL" -> charset := Ansel | "ASCII" | "IBMPC" -> charset := Ascii | "MACINTOSH" -> charset := MacIntosh | "UTF-8" -> charset := Utf8 | _ -> charset := Ascii end | None -> () end; match find_field "PLAC" r.rsons with Some rr -> begin match find_field "FORM" rr.rsons with Some rrr -> if rrr.rval <> "" then () | None -> () end | None -> () let treat_header3 gen r = match find_all_fields "NOTE" r.rsons with [] -> () | rl -> gen.g_bnot <- treat_notes gen rl let turn_around_genealogos_bug r = if String.length r.rlab > 0 && r.rlab.[0] = '@' then {r with rlab = r.rval; rval = r.rlab} else r let make_gen2 gen r = let r = turn_around_genealogos_bug r in match r.rlab with "HEAD" -> treat_header2 r | "INDI" -> add_indi gen r | _ -> () let make_gen3 gen r = let r = turn_around_genealogos_bug r in match r.rlab with "HEAD" -> treat_header3 gen r | "SUBM" -> () | "INDI" -> () | "FAM" -> add_fam gen r | "NOTE" -> () | "SOUR" -> () | "TRLR" -> Printf.eprintf "*** Trailer ok\n"; flush stderr | s -> Printf.fprintf !log_oc "Not implemented typ = %s\n" s; flush !log_oc let sortable_by_date proj = Array.for_all begin fun e -> proj e <> None end let sort_by_date proj array = if sortable_by_date proj array then Array.stable_sort begin fun e1 e2 -> match proj e1, proj e2 with | Some d1, Some d2 -> Date.compare_date d1 d2 | _ -> 1 end array let find_lev0 (strm__ : _ Stream.t) = let bp = Stream.count strm__ in let _ = line_start '0' strm__ in let _ = try skip_space strm__ with Stream.Failure -> raise (Stream.Error "") in let r1 = try get_ident 0 strm__ with Stream.Failure -> raise (Stream.Error "") in let r2 = try get_ident 0 strm__ with Stream.Failure -> raise (Stream.Error "") in let _ = try skip_to_eoln strm__ with Stream.Failure -> raise (Stream.Error "") in bp, r1, r2 let pass1 gen fname = let ic = open_in_bin fname in let strm = Stream.of_channel ic in let rec loop () = match try Some (find_lev0 strm) with Stream.Failure -> None with Some (bp, r1, r2) -> begin match r2 with "NOTE" -> Hashtbl.add gen.g_not r1 bp | "SOUR" -> Hashtbl.add gen.g_src r1 bp | _ -> () end; loop () | None -> let (strm__ : _ Stream.t) = strm in match Stream.peek strm__ with Some _ -> Stream.junk strm__; skip_to_eoln strm; loop () | _ -> () in loop (); close_in ic let fill_g_per gen list = List.iter begin fun (ipp, ip) -> match gen.g_per.arr.(ipp) with | Right3 (p, a, u) when not @@ List.mem ip p.related -> let p = { p with related = ip :: p.related } in gen.g_per.arr.(ipp) <- Right3 (p, a, u) | _ -> () end list let pass2 gen fname = let ic = open_in_bin fname in line_cnt := 0; let strm = Stream.from (fun _ -> try let c = input_char ic in if c = '\n' then incr line_cnt; Some c with End_of_file -> None) in let rec loop () = match try Some (get_lev0 strm) with Stream.Failure -> None with Some r -> make_gen2 gen r; loop () | None -> let (strm__ : _ Stream.t) = strm in match Stream.peek strm__ with Some ('1'..'9') -> Stream.junk strm__; let (_ : string) = get_to_eoln 0 strm in loop () | Some _ -> Stream.junk strm__; let (_ : string) = get_to_eoln 0 strm in loop () | _ -> () in loop () ; fill_g_per gen gen.g_godp ; fill_g_per gen gen.g_prelated ; close_in ic let pass3 gen fname = let ic = open_in_bin fname in line_cnt := 0; let strm = Stream.from (fun _ -> try let c = input_char ic in if c = '\n' then incr line_cnt; Some c with End_of_file -> None) in let rec loop () = match try Some (get_lev0 strm) with Stream.Failure -> None with Some r -> make_gen3 gen r; loop () | None -> let (strm__ : _ Stream.t) = strm in match Stream.peek strm__ with Some ('1'..'9') -> Stream.junk strm__; let (_ : string) = get_to_eoln 0 strm in loop () | Some c -> Stream.junk strm__; print_location !line_cnt; Printf.fprintf !log_oc "Strange input '%c' (%i).\n" c (Char.code c); flush !log_oc; let (_ : string) = get_to_eoln 0 strm in loop () | _ -> () in loop (); List.iter begin fun (ifam, ip) -> match gen.g_fam.arr.(ifam) with | Right3 (fam, cpl, des) -> begin match gen.g_per.arr.(Adef.father cpl), gen.g_per.arr.(ip) with | Right3 _, Right3 (p, a, u) -> if List.mem (Adef.father cpl) p.related then () else begin let p = { p with related = Adef.father cpl :: p.related } in gen.g_per.arr.(ip) <- Right3 (p, a, u) end ; if Array.mem ip fam.witnesses then () else let fam = { fam with witnesses = Array.append fam.witnesses [| ip |] } in gen.g_fam.arr.(ifam) <- Right3 (fam, cpl, des) | _ -> () end | _ -> () end gen.g_witn ; fill_g_per gen gen.g_frelated ; close_in ic let check_undefined gen = for i = 0 to gen.g_per.tlen - 1 do match gen.g_per.arr.(i) with | Right3 (_, _, _) -> () | Left3 lab -> let (p, a, u) = unknown_per i Neuter in Printf.fprintf !log_oc "Warning: undefined person %s\n" lab; gen.g_per.arr.(i) <- Right3 (p, a, u) done; for i = 0 to gen.g_fam.tlen - 1 do match gen.g_fam.arr.(i) with | Right3 (_, _, _) -> () | Left3 lab -> let (f, c, d) = unknown_fam gen i in Printf.fprintf !log_oc "Warning: undefined family %s\n" lab; gen.g_fam.arr.(i) <- Right3 (f, c, d) done let add_parents_to_isolated gen = let ht_missing_children = Hashtbl.create 1001 in (* Parfois, l'enfant n'a pas de tag FAMC, mais il est bien présent dans la famille. Du coup, si on lui ajoute des parents tout de suite, lors du finish base, on va se rendre compte qu'il est en trop dans sa "vraie" famille et on va le supprimer, alors qu'on veut re-créer la liaison. *) let () = let rec loop i = if i = gen.g_fam.tlen then () else match gen.g_fam.arr.(i) with | Right3 (_, _, des) -> Array.iter (fun ip -> Hashtbl.add ht_missing_children ip true) des.children ; loop (i + 1) | Left3 _ -> loop (i + 1) in loop 0 in for i = 0 to gen.g_per.tlen - 1 do match gen.g_per.arr.(i) with | Right3 (p, a, u) -> if a.parents = None && Array.length u.family = 0 && p.rparents = [] && p.related = [] && not (Hashtbl.mem ht_missing_children p.key_index) then let fn = gen.g_str.arr.(p.first_name) in let sn = gen.g_str.arr.(p.surname) in if fn = "?" && sn = "?" then () else begin Printf.fprintf !log_oc "Adding parents to isolated person: %s.%d %s\n" fn p.occ sn ; let ifam = phony_fam gen in match gen.g_fam.arr.(ifam) with | Right3 (fam, cpl, _) -> let des = { children = [| p.key_index |] } in gen.g_fam.arr.(ifam) <- Right3 (fam, cpl, des); let a = { a with parents = Some ifam } in gen.g_per.arr.(i) <- Right3 (p, a, u) | _ -> () end | Left3 _ -> () done let make_arrays in_file = let fname = if Filename.check_suffix in_file ".ged" then in_file else if Filename.check_suffix in_file ".GED" then in_file else in_file ^ ".ged" in let gen = {g_per = {arr = [| |]; tlen = 0}; g_fam = {arr = [| |]; tlen = 0}; g_str = {arr = [| |]; tlen = 0}; g_bnot = ""; g_ic = open_in_bin fname; g_not = Hashtbl.create 3001; g_src = Hashtbl.create 3001; g_hper = Hashtbl.create 3001; g_hfam = Hashtbl.create 3001; g_hstr = Hashtbl.create 3001; g_hnam = Hashtbl.create 3001; g_adop = Hashtbl.create 3001; g_godp = []; g_prelated = []; g_frelated = []; g_witn = []} in assert (add_string gen "" = string_empty); assert (add_string gen "?" = string_quest); assert (add_string gen "x" = string_x); Printf.eprintf "*** pass 1 (note)\n"; flush stderr; pass1 gen fname; Printf.eprintf "*** pass 2 (indi)\n"; flush stderr; pass2 gen fname; Printf.eprintf "*** pass 3 (fam)\n"; flush stderr; pass3 gen fname; close_in gen.g_ic; check_undefined gen; add_parents_to_isolated gen; gen.g_per, gen.g_fam, gen.g_str, gen.g_bnot let make_subarrays (g_per, g_fam, g_str, g_bnot) = let persons = let pa = Array.make g_per.tlen (Obj.magic 0) in let aa = Array.make g_per.tlen (Obj.magic 0) in let ua = Array.make g_per.tlen (Obj.magic 0) in for i = 0 to g_per.tlen - 1 do match g_per.arr.(i) with | Right3 (p, a, u) -> pa.(i) <- p; aa.(i) <- a; ua.(i) <- u | Left3 lab -> failwith ("undefined person " ^ lab) done; pa, aa, ua in let families = let fa = Array.make g_fam.tlen (Obj.magic 0) in let ca = Array.make g_fam.tlen (Obj.magic 0) in let da = Array.make g_fam.tlen (Obj.magic 0) in for i = 0 to g_fam.tlen - 1 do match g_fam.arr.(i) with Right3 (f, c, d) -> fa.(i) <- f; ca.(i) <- c; da.(i) <- d | Left3 lab -> failwith ("undefined family " ^ lab) done; fa, ca, da in let strings = Array.sub g_str.arr 0 g_str.tlen in let bnotes = {nread = (fun s _ -> if s = "" then g_bnot else ""); norigin_file = ""; efiles = fun _ -> []} in persons, families, strings, bnotes let designation strings p = let fn = Mutil.nominative strings.(p.first_name) in let sn = Mutil.nominative strings.(p.surname) in fn ^ "." ^ string_of_int p.occ ^ " " ^ sn let check_parents_children persons ascends unions families couples descends strings = let prints = Printf.fprintf !log_oc in let print = Printf.fprintf !log_oc in let designation = designation strings in for i = 0 to Array.length ascends - 1 do let a = ascends.(i) in begin match a.parents with | Some ifam -> let fam = families.(ifam) in if fam.fam_index = -1 then ascends.(i) <- { a with parents = None } else let cpl = couples.(ifam) in let des = descends.(ifam) in if Array.memq i des.children then () else let p = persons.(i) in prints "%s is not the child of his/her parents\n" (designation p) ; prints "- %s\n" (designation persons.(Adef.father cpl)) ; prints "- %s\n" (designation persons.(Adef.mother cpl)) ; print "=> no more parents for him/her\n" ; print "\n" ; flush !log_oc ; ascends.(i) <- { a with parents = None } | None -> () end; let u = unions.(i) in let fam_to_delete = Array.fold_left begin fun acc ifam -> let cpl = couples.(ifam) in if i <> Adef.father cpl && i <> Adef.mother cpl then begin let acc = prints "%s is spouse in this family but neither husband nor wife:\n" (designation persons.(i)) ; prints "- %s\n" (designation persons.(Adef.father cpl)) ; prints "- %s\n" (designation persons.(Adef.mother cpl)) ; let fath = persons.(Adef.father cpl) in let moth = persons.(Adef.mother cpl) in let ffn = strings.(fath.first_name) in let fsn = strings.(fath.surname) in let mfn = strings.(moth.first_name) in let msn = strings.(moth.surname) in if ffn = "?" && fsn = "?" && mfn <> "?" && msn <> "?" then begin print "However, the husband is unknown, I set him as husband\n" ; unions.(Adef.father cpl) <- {family = [| |]}; couples.(ifam) <- Adef.couple i (Adef.mother cpl) ; acc end else if mfn = "?" && msn = "?" && ffn <> "?" && fsn <> "?" then begin print "However, the wife is unknown, I set her as wife\n" ; unions.(Adef.mother cpl) <- {family = [| |]} ; couples.(ifam) <- Adef.couple (Adef.father cpl) i ; acc end else begin print "=> deleted this family for him/her\n" ; ifam :: acc end in print "\n"; flush !log_oc ; acc end else acc end [] u.family in if fam_to_delete <> [] then let list = Array.fold_right begin fun x acc -> if List.mem x fam_to_delete then acc else x :: acc end u.family [] in unions.(i) <- { family = Array.of_list list } done ; for i = 0 to Array.length families - 1 do let to_delete = ref [] in let fam = families.(i) in let cpl = couples.(i) in let des = descends.(i) in Array.iter begin fun ip -> let a = ascends.(ip) in let p = persons.(ip) in match a.parents with | Some ifam -> if ifam <> i then begin prints "Other parents for %s\n" (designation p); prints "- %s\n" (designation persons.(Adef.father cpl)) ; prints "- %s\n" (designation persons.(Adef.mother cpl)) ; print "=> deleted in this family\n" ; print "\n" ; flush !log_oc ; to_delete := p.key_index :: !to_delete end | None -> prints "%s has no parents but is the child of\n" (designation p) ; prints "- %s\n" (designation persons.(Adef.father cpl)) ; prints "- %s\n" (designation persons.(Adef.mother cpl)) ; print "=> added parents\n" ; print "\n" ; flush !log_oc ; let a = { a with parents = Some fam.fam_index } in ascends.(ip) <- a end des.children ; if !to_delete <> [] then let l = Array.fold_right begin fun ip acc -> if List.mem ip !to_delete then acc else ip :: acc end des.children [] in descends.(i) <- { children = Array.of_list l } done let check_parents_sex persons families couples strings = for i = 0 to Array.length couples - 1 do let cpl = couples.(i) in let fam = families.(i) in let ifath = Adef.father cpl in let imoth = Adef.mother cpl in let fath = persons.(ifath) in let moth = persons.(imoth) in if fam.relation = NoSexesCheckNotMarried || fam.relation = NoSexesCheckMarried then () else if fath.sex = Female || moth.sex = Male then begin if fath.sex = Female then Printf.fprintf !log_oc "Warning - husband with female sex: %s\n" (designation strings fath) ; if moth.sex = Male then Printf.fprintf !log_oc "Warning - wife with male sex: %s\n" (designation strings moth) ; flush !log_oc ; families.(i) <- { fam with relation = NoSexesCheckNotMarried } end else begin persons.(ifath) <- { fath with sex = Male } ; persons.(imoth) <- { moth with sex = Female } end done let neg_year_dmy = function | {day = d; month = m; year = y; prec = OrYear dmy2} -> let dmy2 = {dmy2 with year2 = -abs dmy2.year2} in {day = d; month = m; year = -abs y; prec = OrYear dmy2; delta = 0} | {day = d; month = m; year = y; prec = YearInt dmy2} -> let dmy2 = {dmy2 with year2 = -abs dmy2.year2} in {day = d; month = m; year = -abs y; prec = YearInt dmy2; delta = 0} | {day = d; month = m; year = y; prec = p} -> {day = d; month = m; year = -abs y; prec = p; delta = 0} let neg_year = function | Dgreg (d, cal) -> Dgreg (neg_year_dmy d, cal) | x -> x let neg_year_cdate cd = Date.cdate_of_date (neg_year (Date.date_of_cdate cd)) let rec negative_date_ancestors persons ascends unions families couples i = let p = persons.(i) in let p = { p with birth = begin match Date.od_of_cdate p.birth with | Some d1 -> Date.cdate_of_od (Some (neg_year d1)) | None -> p.birth end ; death = match p.death with | Death (dr, cd2) -> Death (dr, neg_year_cdate cd2) | _ -> p.death } in persons.(i) <- p; let u = unions.(i) in for i = 0 to Array.length u.family - 1 do let j = u.family.(i) in let fam = families.(j) in match Date.od_of_cdate fam.marriage with | None -> () | Some d -> let fam = { fam with marriage = Date.cdate_of_od (Some (neg_year d)) } in families.(j) <- fam done ; let a = ascends.(i) in match a.parents with | None -> () | Some ifam -> let cpl = couples.(ifam) in negative_date_ancestors persons ascends unions families couples (Adef.father cpl) ; negative_date_ancestors persons ascends unions families couples (Adef.mother cpl) let negative_dates persons ascends unions families couples = for i = 0 to Array.length persons - 1 do let p = persons.(i) in match Date.cdate_to_dmy_opt p.birth, Date.dmy_of_death p.death with | Some d1, Some d2 -> if d1.year > 0 && d2.year > 0 && Date.compare_dmy d2 d1 < 0 then negative_date_ancestors persons ascends unions families couples i | _ -> () done let finish_base (persons, families, strings, _) = let (persons, ascends, unions) = persons in let (families, couples, descends) = families in for i = 0 to Array.length descends - 1 do let des = descends.(i) in let children = des.children in sort_by_date (fun i -> Date.od_of_cdate persons.(i).birth) children ; descends.(i) <- { children } done ; for i = 0 to Array.length unions - 1 do let u = unions.(i) in let family = u.family in sort_by_date (fun i -> Date.od_of_cdate families.(i).marriage) family ; unions.(i) <- { family } done ; for i = 0 to Array.length persons - 1 do let p = persons.(i) in let a = ascends.(i) in let u = unions.(i) in if a.parents <> None && Array.length u.family != 0 || p.notes <> string_empty then let (fn, occ) = if strings.(p.first_name) = "?" then string_x, i else p.first_name, p.occ in let (sn, occ) = if strings.(p.surname) = "?" then string_x, i else p.surname, occ in persons.(i) <- { p with first_name = fn; surname = sn; occ } done; check_parents_sex persons families couples strings ; check_parents_children persons ascends unions families couples descends strings ; if !try_negative_dates then negative_dates persons ascends unions families couples (* Main *) let out_file = ref "a" let speclist = [ ( "-o", Arg.String (fun s -> out_file := s) , " Output database (default: \"a\")." ) ; ( "-f", Arg.Set force , "Remove database if already existing" ) ; ( "-log", Arg.String (fun s -> log_oc := open_out s) , " Redirect log trace to this file." ) ; ( "-lf", Arg.Set lowercase_first_names , "Convert first names to lowercase letters, with initials in uppercase." ) ; ( "-trackid", Arg.Set track_ged2gw_id, "Print gedcom id to gw id matches." ) ; ( "-ls", Arg.Unit (fun () -> case_surnames := LowerCase) , "Convert surnames to lowercase letters, with initials in uppercase. \ Try to keep lowercase particles." ) ; ( "-us", Arg.Unit (fun () -> case_surnames := UpperCase) , "Convert surnames to uppercase letters." ) ; ( "-fne" , Arg.String begin fun s -> if String.length s = 2 then first_names_brackets := Some (s.[0], s.[1]) else raise (Arg.Bad "-fne option must be followed by a 2 characters string") end , " When creating a person, if the GEDCOM first name part holds \ a part between 'b' (any character) and 'e' (any character), it \ is considered to be the usual first name: e.g. -fne '\"\"' or \ -fne \"()\"." ) ; ( "-efn", Arg.Set extract_first_names , "When creating a person, if the GEDCOM first name part holds several \ names, the first of this names becomes the person \"first name\" and \ the complete GEDCOM first name part a \"first name alias\"." ) ; ( "-no_efn", Arg.Clear extract_first_names, "Cancels the previous option." ) ; ( "-epn", Arg.Set extract_public_names , "When creating a person, if the GEDCOM first name part looks like a \ public name, i.e. holds:\n\ * a number or a roman number, supposed to be a number of a nobility title,\n\ * one of the words: \"der\", \"den\", \"die\", \"el\", \"le\", \"la\", \"the\", \ supposed to be the beginning of a qualifier, \ then the GEDCOM first name part becomes the person \"public name\" \ and its first word his \"first name\"." ) ; ( "-no_epn", Arg.Clear extract_public_names , "Cancels the previous option." ) ; ( "-no_pit", Arg.Set no_public_if_titles , "Do not consider persons having titles as public") ; ( "-tnd", Arg.Set try_negative_dates , "Set negative dates when inconsistency (e.g. birth after death)" ) ; ( "-no_nd", Arg.Set no_negative_dates , "Don't interpret a year preceded by a minus sign as a negative year" ) ; ( "-nc", Arg.Clear do_check, "No consistency check" ) ; ( "-nopicture", Arg.Set no_picture, "Don't extract individual picture." ) ; ( "-udi" , Arg.String begin fun s -> match String.index_opt s '-' with | Some i -> let a = String.sub s 0 i in let b = String.sub s (i + 1) (String.length s - i - 1) in let a = if a = "" then !alive_years else int_of_string a in let b = max a (if b = "" then !dead_years else int_of_string b) in alive_years := a ; dead_years := b ; | None -> raise (Arg.Bad "bad parameter for -udi") end , "x-y Set the interval for persons whose death part is undefined:\n\ - if before x years, they are considered as alive\n\ - if after y year, they are considered as death\n\ - between x and y year, they are considered as \"don't know\"\n\ Default x is " ^ string_of_int !alive_years ^ " and y is " ^ string_of_int !dead_years) ; ( "-uin", Arg.Set untreated_in_notes , "Put untreated GEDCOM tags in notes" ) ; ( "-ds", Arg.Set_string default_source , "Set the source field for persons and families without source data" ) ; ( "-dates_dm", Arg.Unit (fun () -> month_number_dates := DayMonthDates) ,"Interpret months-numbered dates as day/month/year" ) ; ( "-dates_md", Arg.Unit (fun () -> month_number_dates := MonthDayDates) , "Interpret months-numbered dates as month/day/year" ) ; ( "-rs_no_mention", Arg.Unit (fun () -> relation_status := NoMention) , "Force relation status to NoMention (default is Married)" ) ; ( "-charset" , Arg.String begin function | "ANSEL" -> charset_option := Some Ansel | "ASCII" -> charset_option := Some Ascii | "MSDOS" -> charset_option := Some Msdos | _ -> raise (Arg.Bad "bad -charset value") end , "[ANSEL|ASCII|MSDOS] Force given charset decoding, \ overriding the possible setting in GEDCOM" ) ; ( "-particles" , Arg.String (fun s -> particles := Mutil.input_particles s) , " Use the given file as list of particles" ) ] |> List.sort compare |> Arg.align let anonfun s = if !in_file = "" then in_file := s else raise (Arg.Bad "Cannot treat several GEDCOM files") let errmsg = "Usage: ged2gwb [] [options] where options are:" let main () = Arg.parse speclist anonfun errmsg; Secure.set_base_dir (Filename.dirname !out_file); let arrays = make_arrays !in_file in Gc.compact (); let arrays = make_subarrays arrays in finish_base arrays ; let base = Gwdb.make !out_file !particles arrays in warning_month_number_dates (); if !do_check then begin let base_error x = Check.print_base_error !log_oc base x; Printf.fprintf !log_oc "\n" in let base_warning = function | UndefinedSex _ -> () | x -> Check.print_base_warning !log_oc base x; Printf.fprintf !log_oc "\n" in Check.check_base base base_error base_warning ignore; flush !log_oc end ; if !log_oc != stdout then close_out !log_oc let _ = try main () with e -> let e = match e with Ploc.Exc (_, e) -> e | _ -> e in Printf.fprintf !log_oc "Uncaught exception: %s\n" (Printexc.to_string e); if !log_oc != stdout then close_out !log_oc; exit 2