1(* camlp5r ./pa_html.cmo *)
2(* $Id: perso.ml,v 5.82 2007-09-12 09:58:44 ddr Exp $ *)
3(* Copyright (c) 1998-2007 INRIA *)
4
5open Config;
6open Def;
7open Gutil;
8open Gwdb;
9open Mutil;
10open TemplAst;
11open Util;
12
13value max_im_wid = 240;
14value max_im_hei = 240;
15value round_2_dec x = floor (x *. 100.0 +. 0.5) /. 100.0;
16
17value has_children base u =
18  List.exists
19    (fun ifam ->
20       let des = foi base ifam in
21       Array.length (get_children des) > 0)
22    (Array.to_list (get_family u))
23;
24
25value string_of_marriage_text conf base fam =
26  let marriage = Adef.od_of_codate (get_marriage fam) in
27  let marriage_place = sou base (get_marriage_place fam) in
28  let s =
29    match marriage with
30    [ Some d -> " " ^ Date.string_of_ondate conf d
31    | _ -> "" ]
32  in
33  match marriage_place with
34  [ "" -> s
35  | _ -> s ^ ", " ^ string_with_macros conf [] marriage_place ^ "," ]
36;
37
38value string_of_title conf base and_txt p (nth, name, title, places, dates) =
39  let href =
40    "m=TT;sm=S;t=" ^ code_varenv (sou base title) ^ ";p=" ^
41      code_varenv (sou base (List.hd places))
42  in
43  let (tit, est) = (sou base title, sou base (List.hd places)) in
44  let s = tit ^ " " ^ est in
45  let b = Buffer.create 50 in
46  do {
47    Buffer.add_string b (geneweb_link conf href s);
48    let rec loop places =
49      do {
50        match places with
51        [ [] -> ()
52        | [_] -> Printf.bprintf b "\n%s " and_txt
53        | _ -> Buffer.add_string b ",\n" ];
54        match places with
55        [ [place :: places] ->
56            let href =
57              "m=TT;sm=S;t=" ^ code_varenv (sou base title) ^ ";p=" ^
58                code_varenv (sou base place)
59            in
60            let est = sou base place in
61            do {
62              Buffer.add_string b (geneweb_link conf href est);
63              loop places
64            }
65        | _ -> () ]
66      }
67    in
68    loop (List.tl places);
69    let paren =
70      match (nth, dates, name) with
71      [ (n, _, _) when n > 0 -> True
72      | (_, _, Tname _) -> True
73      | (_, [(Some _, _) :: _], _) -> authorized_age conf base p
74      | _ -> False ]
75    in
76    if paren then Buffer.add_string b "\n(" else ();
77    let first =
78      if nth > 0 then do {
79        Buffer.add_string b
80          (if nth >= 100 then string_of_int nth
81           else transl_nth conf "nth" nth);
82        False
83      }
84      else True
85    in
86    let first =
87      match name with
88      [ Tname n ->
89          do {
90            if not first then Buffer.add_string b " ," else ();
91            Buffer.add_string b (sou base n);
92            False
93          }
94      | _ -> first ]
95    in
96    if authorized_age conf base p && dates <> [(None, None)] then
97      let _ =
98        List.fold_left
99          (fun first (date_start, date_end) ->
100             do {
101               if not first then Buffer.add_string b ",\n" else ();
102               match date_start with
103               [ Some d -> Buffer.add_string b (Date.string_of_date conf d)
104               | None -> () ];
105               match date_end with
106               [ Some (Dgreg d _) ->
107                   if d.month <> 0 then Buffer.add_string b " - "
108                   else Buffer.add_string b "-"
109               | _ -> () ];
110               match date_end with
111               [ Some d -> Buffer.add_string b (Date.string_of_date conf d)
112               | None -> () ];
113               False
114             })
115          first dates
116      in
117      ()
118    else ();
119    if paren then Buffer.add_string b ")" else ();
120    Buffer.contents b
121  }
122;
123
124value name_equiv n1 n2 =
125  Futil.eq_title_names eq_istr n1 n2 || n1 = Tmain && n2 = Tnone ||
126  n1 = Tnone && n2 = Tmain
127;
128
129value nobility_titles_list conf base p =
130  let titles =
131    List.fold_right
132      (fun t l ->
133         let t_date_start = Adef.od_of_codate t.t_date_start in
134         let t_date_end = Adef.od_of_codate t.t_date_end in
135         match l with
136         [ [(nth, name, title, place, dates) :: rl]
137           when
138             not conf.is_rtl && nth = t.t_nth && name_equiv name t.t_name &&
139             eq_istr title t.t_ident && eq_istr place t.t_place ->
140             [(nth, name, title, place,
141               [(t_date_start, t_date_end) :: dates]) ::
142              rl]
143         | _ ->
144             [(t.t_nth, t.t_name, t.t_ident, t.t_place,
145               [(t_date_start, t_date_end)]) ::
146              l] ])
147      (Util.nobtit conf base p) []
148  in
149  List.fold_right
150    (fun (t_nth, t_name, t_ident, t_place, t_dates) l ->
151       match l with
152       [ [(nth, name, title, places, dates) :: rl]
153         when
154           not conf.is_rtl && nth = t_nth && name_equiv name t_name &&
155           eq_istr title t_ident && dates = t_dates ->
156           [(nth, name, title, [t_place :: places], dates) :: rl]
157       | _ -> [(t_nth, t_name, t_ident, [t_place], t_dates) :: l] ])
158    titles []
159;
160
161(* obsolete; should be removed one day *)
162
163value string_of_titles conf base cap and_txt p =
164  let titles = nobility_titles_list conf base p in
165  List.fold_left
166    (fun s t ->
167       s ^ (if s = "" then "" else ",") ^ "\n" ^
168       string_of_title conf base and_txt p t)
169    "" titles
170;
171
172value string_of_num sep num =
173  let len = ref 0 in
174  do {
175    Num.print (fun x -> len.val := Buff.mstore len.val x) sep num;
176    Buff.get len.val
177  }
178;
179
180value print_base_loop conf base p =
181  do {
182    Wserver.wprint
183      (fcapitale
184         (ftransl conf "loop in database: %s is his/her own ancestor"))
185      (Util.update_family_loop conf base p (designation base p));
186    Wserver.wprint ".\n";
187    Hutil.trailer conf;
188    exit 2
189  }
190;
191
192(* This is the old version, the new one has few optimisations *)
193(* Version matching the Sosa number of the "ancestor" pages *)
194(*
195value find_sosa_aux conf base a p =
196  let tstab =
197    try Util.create_topological_sort conf base with
198    [ Consang.TopologicalSortError p -> print_base_loop conf base p ]
199  in
200  let mark = Array.make (nb_of_persons base) False in
201  let rec gene_find =
202    fun
203    [ [] -> Left []
204    | [(z, ip) :: zil] ->
205        if ip = get_key_index a then Right z
206        else if mark.(Adef.int_of_iper ip) then gene_find zil
207        else do {
208          mark.(Adef.int_of_iper ip) := True;
209          if tstab.(Adef.int_of_iper (get_key_index a)) <=
210               tstab.(Adef.int_of_iper ip) then
211            gene_find zil
212          else
213            let asc = pget conf base ip in
214            match get_parents asc with
215            [ Some ifam ->
216                let cpl = foi base ifam in
217                let z = Num.twice z in
218                match gene_find zil with
219                [ Left zil ->
220                    Left
221                      [(z, get_father cpl); (Num.inc z 1, (get_mother cpl)) ::
222                       zil]
223                | Right z -> Right z ]
224            | None -> gene_find zil ]
225        } ]
226  in
227  let rec find zil =
228    match gene_find zil with
229    [ Left [] -> None
230    | Left zil -> find zil
231    | Right z -> Some (z, p) ]
232  in
233  find [(Num.one, get_key_index p)]
234;
235(* Male version
236value find_sosa_aux conf base a p =
237  let mark = Array.make base.data.persons.len False in
238  let rec find z ip =
239    if ip = a.key_index then Some z
240    else if mark.(Adef.int_of_iper ip) then None
241    else do {
242      mark.(Adef.int_of_iper ip) := True;
243      let asc = aget conf base ip in
244      match asc.parents with
245      [ Some ifam ->
246          let cpl = coi base ifam in
247          let z = Num.twice z in
248          match find z (father cpl) with
249          [ Some z -> Some z
250          | None -> find (Num.inc z 1) (mother cpl) ]
251      | None -> None ]
252    }
253  in
254  find Num.one (get_key_index p)
255;
256*)
257
258value find_sosa conf base a sosa_ref_l =
259  match Lazy.force sosa_ref_l with
260  [ Some p ->
261      if get_key_index a = get_key_index p then Some (Num.one, p)
262      else
263        let u = pget conf base (get_key_index a) in
264        if has_children base u then find_sosa_aux conf base a p else None
265  | None -> None ]
266;
267*)
268
269(* Optimisation de find_sosa_aux :                                           *)
270(* - ajout d'un cache pour conserver les descendants du sosa que l'on calcul *)
271(* - on sauvegarde la dernière génération où l'on a arrêté le calcul pour    *)
272(*   ne pas reprendre le calcul depuis la racine                             *)
273
274(* Type pour ne pas créer à chaque fois un tableau tstab et mark *)
275type sosa_t =
276  { tstab : array int;
277    mark : array bool;
278    last_zil : mutable list (Def.iper * Num.t);
279    sosa_ht : Hashtbl.t Def.iper (option (Num.t * Gwdb.person))
280  }
281;
282
283value init_sosa_t conf base sosa_ref =
284  let tstab =
285    try Util.create_topological_sort conf base with
286    [ Consang.TopologicalSortError p ->
287      (* Avec la nouvelle implementation du calcul de sosa, si à    *)
288      (* l'init il y a une boucle, alors on a pas encore interprété *)
289      (* le template, donc on n'a pas de header.                    *)
290      (* Il faut trouver aussi un algo de suppression de boucle parce  *)
291      (* que si la boucle n'est pas à une génération d'écart, alors on *)
292      (* boucle sur l'interprétation du template.                      *)
293      do {
294        let title _ = Wserver.wprint "%s" (capitale (transl conf "error")) in
295        Hutil.rheader conf title;
296        print_base_loop conf base p
297      } ]
298  in
299  let mark = Array.make (nb_of_persons base) False in
300  let last_zil = [(get_key_index sosa_ref, Num.one)] in
301  let sosa_ht = Hashtbl.create 5003 in
302  let () =
303    Hashtbl.add sosa_ht (get_key_index sosa_ref) (Some (Num.one, sosa_ref))
304  in
305  let t_sosa =
306    { tstab = tstab;
307      mark = mark;
308      last_zil = last_zil;
309      sosa_ht = sosa_ht
310    }
311  in
312  t_sosa
313;
314
315value find_sosa_aux conf base a p t_sosa =
316  let cache = ref [] in
317  let has_ignore = ref False in
318  let ht_add ht k v new_sosa =
319    match try Hashtbl.find ht k with [ Not_found -> v ] with
320    [ Some (z, _) ->
321        if not (Num.gt new_sosa z) then Hashtbl.replace ht k v
322        else ()
323    | _ -> () ]
324  in
325  let rec gene_find =
326    fun
327    [ [] -> Left []
328    | [(ip, z) :: zil] ->
329        let _ = cache.val := [(ip, z) :: cache.val] in
330        if ip = get_key_index a then Right z
331        else if t_sosa.mark.(Adef.int_of_iper ip) then gene_find zil
332        else do {
333          t_sosa.mark.(Adef.int_of_iper ip) := True;
334          if t_sosa.tstab.(Adef.int_of_iper (get_key_index a)) <=
335               t_sosa.tstab.(Adef.int_of_iper ip) then
336            let _ = has_ignore.val := True in
337            gene_find zil
338          else
339            let asc = pget conf base ip in
340            match get_parents asc with
341            [ Some ifam ->
342                let cpl = foi base ifam in
343                let z = Num.twice z in
344                match gene_find zil with
345                [ Left zil ->
346                    Left
347                      [(get_father cpl, z); (get_mother cpl, Num.inc z 1) ::
348                       zil]
349                | Right z -> Right z ]
350            | None -> gene_find zil ]
351        } ]
352  in
353  let rec find zil =
354    match
355      (* Dans le cas ou le fichier tstab n'est plus à jour, on supprime *)
356      (* le fichier pour qu'il se régénère la prochaine fois.           *)
357      try gene_find zil with
358      [ Invalid_argument "index out of bounds" ->
359          do {
360            Update.delete_topological_sort conf base;
361            Left []
362          } ]
363    with
364    [ Left [] ->
365        let _ =
366          List.iter
367            (fun (ip, _) -> Array.set t_sosa.mark (Adef.int_of_iper ip) False)
368            cache.val
369        in
370        None
371    | Left zil ->
372        let _ =
373          if has_ignore.val then ()
374          else do {
375            List.iter
376              (fun (ip, z) -> ht_add t_sosa.sosa_ht ip (Some (z, p)) z)
377              zil;
378            t_sosa.last_zil := zil }
379        in
380        find zil
381    | Right z ->
382        let _ =
383          List.iter
384            (fun (ip, _) -> Array.set t_sosa.mark (Adef.int_of_iper ip) False)
385            cache.val
386        in
387        Some (z, p) ]
388  in
389  find t_sosa.last_zil
390;
391
392value find_sosa conf base a sosa_ref_l t_sosa =
393  match Lazy.force sosa_ref_l with
394  [ Some p ->
395      if get_key_index a = get_key_index p then Some (Num.one, p)
396      else
397        let u = pget conf base (get_key_index a) in
398        if has_children base u then
399          try Hashtbl.find t_sosa.sosa_ht (get_key_index a) with
400          [ Not_found -> find_sosa_aux conf base a p t_sosa ]
401        else None
402  | None -> None ]
403;
404
405
406(* [Type]: (Def.iper, Num.t) Hashtbl.t *)
407value sosa_ht = Hashtbl.create 5003;
408
409
410(* ************************************************************************ *)
411(*  [Fonc] build_sosa_ht : config -> base -> unit                           *)
412(** [Description] : Construit à partir du sosa de référence de la base, la
413      liste de tous ces ancêtres directs et la stocke dans une hashtbl. La
414      clé de la table est l'iper de la personne et on lui associe son numéro
415      de sosa. Les sosa multiples ne sont représentés qu'une seule fois par
416      leur plus petit numéro sosa.
417    [Args] :
418      - conf : configuration de la base
419      - base : base de donnée
420    [Retour] :
421      - unit
422    [Rem] : Exporté en clair hors de ce module.                             *)
423(* ************************************************************************ *)
424value build_sosa_ht conf base =
425  let () = load_ascends_array base in
426  let () = load_couples_array base in
427  match Util.find_sosa_ref conf base with
428  [ Some sosa_ref ->
429      let nb_persons = nb_of_persons base in
430      let mark = Array.make nb_persons False in
431      (* Tableau qui va socker au fur et à mesure les ancêtres du sosa_ref. *)
432      (* Attention, on créé un tableau de la longueur de la base + 1 car on *)
433      (* commence à l'indice 1 !                                            *)
434      let sosa_accu =
435        Array.make (nb_persons + 1) (Num.zero, Adef.iper_of_int 0)
436      in
437      let () = Array.set sosa_accu 1 (Num.one, get_key_index sosa_ref) in
438      let rec loop i len =
439        if i > nb_persons then ()
440        else
441          let (sosa_num, ip) = Array.get sosa_accu i in
442          (* Si la personne courante n'a pas de numéro de sosa, alors il n'y *)
443          (* a plus d'ancêtres car ils ont été ajoutés par ordre croissant.  *)
444          if Num.eq sosa_num Num.zero then ()
445          else do {
446            Hashtbl.add sosa_ht ip sosa_num;
447            let asc = pget conf base ip in
448            (* Ajoute les nouveaux ascendants au tableau des ancêtres. *)
449            match get_parents asc with
450            [ Some ifam ->
451                let cpl = foi base ifam in
452                let z = Num.twice sosa_num in
453                let len =
454                  if not mark.(Adef.int_of_iper (get_father cpl)) then do {
455                    Array.set sosa_accu (len + 1) (z, get_father cpl) ;
456                    mark.(Adef.int_of_iper (get_father cpl)) := True ;
457                    len + 1 }
458                  else len
459                in
460                let len =
461                  if not mark.(Adef.int_of_iper (get_mother cpl)) then do {
462                    Array.set sosa_accu (len + 1) (Num.inc z 1, get_mother cpl);
463                    mark.(Adef.int_of_iper (get_mother cpl)) := True ;
464                    len + 1 }
465                else len
466                in
467                loop (i + 1) len
468            | None -> loop (i + 1) len ]
469          }
470      in
471      loop 1 1
472   | None -> () ]
473;
474
475
476(* ******************************************************************** *)
477(*  [Fonc] get_sosa_person : config -> base -> person -> Num.t          *)
478(** [Description] : Recherche si la personne passée en argument a un
479                    numéro de sosa.
480    [Args] :
481      - conf : configuration de la base
482      - base : base de donnée
483      - p    : personne dont on cherche si elle a un numéro sosa
484    [Retour] :
485      - Num.t : retourne Num.zero si la personne n'a pas de numéro de
486                sosa, ou retourne son numéro de sosa sinon
487    [Rem] : Exporté en clair hors de ce module.                         *)
488(* ******************************************************************** *)
489value get_sosa_person conf base p =
490  try Hashtbl.find sosa_ht (get_key_index p) with
491  [ Not_found -> Num.zero ]
492;
493
494
495(* ******************************************************************** *)
496(*  [Fonc] get_single_sosa : config -> base -> person -> Num.t          *)
497(** [Description] : Recherche si la personne passée en argument a un
498                    numéro de sosa.
499    [Args] :
500      - conf : configuration de la base
501      - base : base de donnée
502      - p    : personne dont on cherche si elle a un numéro sosa
503    [Retour] :
504      - Num.t : retourne Num.zero si la personne n'a pas de numéro de
505                sosa, ou retourne son numéro de sosa sinon
506    [Rem] : Exporté en clair hors de ce module.                         *)
507(* ******************************************************************** *)
508value get_single_sosa conf base p =
509  let sosa_ref = Util.find_sosa_ref conf base in
510  match sosa_ref with
511  [ Some p_sosa ->
512      let sosa_ref_l =
513        let sosa_ref () = sosa_ref in
514        Lazy.from_fun sosa_ref
515      in
516      let t_sosa = init_sosa_t conf base p_sosa in
517      match find_sosa conf base p sosa_ref_l t_sosa with
518      [ Some (z, p) -> z
519      | None -> Num.zero ]
520  | None -> Num.zero ]
521;
522
523
524(* ************************************************************************ *)
525(*  [Fonc] print_sosa : config -> base -> person -> bool -> unit            *)
526(** [Description] : Affiche le picto sosa ainsi que le lien de calcul de
527      relation entre la personne et le sosa 1 (si l'option cancel_link
528      n'est pas activée).
529    [Args] :
530      - conf : configuration de la base
531      - base : base de donnée
532      - p    : la personne que l'on veut afficher
533      - link : ce booléen permet d'afficher ou non le lien sur le picto
534               sosa. Il n'est pas nécessaire de mettre le lien si on a
535               déjà affiché cette personne.
536    [Retour] :
537      - unit
538    [Rem] : Exporté en clair hors de ce module.                             *)
539(* ************************************************************************ *)
540value print_sosa conf base p link =
541  let sosa_num = get_sosa_person conf base p in
542  if Num.gt sosa_num Num.zero then
543    match Util.find_sosa_ref conf base with
544    [ Some ref ->
545        do {
546          if conf.cancel_links || not link then ()
547          else
548            let sosa_link =
549              let i1 = string_of_int (Adef.int_of_iper (get_key_index p)) in
550              let i2 = string_of_int (Adef.int_of_iper (get_key_index ref)) in
551              let b2 = Num.to_string sosa_num in
552              "m=RL;i1=" ^ i1 ^ ";i2=" ^ i2 ^ ";b1=1;b2=" ^ b2
553            in
554            Wserver.wprint "<a href=\"%s%s\" style=\"text-decoration:none\">"
555              (commd conf) sosa_link;
556          let title =
557            if (is_hide_names conf ref) && not (fast_auth_age conf ref) then ""
558            else
559              let direct_ancestor =
560                Name.strip_c (p_first_name base ref) '"' ^ " "
561                ^ Name.strip_c (p_surname base ref) '"'
562              in
563              Printf.sprintf
564                (fcapitale
565                   (ftransl conf "direct ancestor of %s")) direct_ancestor ^
566                Printf.sprintf ", Sosa: %s"
567                  (string_of_num (transl conf "(thousand separator)") sosa_num)
568          in
569          Wserver.wprint "<img src=\"%s/sosa.png\" alt=\"sosa\" title=\"%s\"/>"
570            (image_prefix conf) title;
571          if conf.cancel_links || not link then ()
572          else  Wserver.wprint "</a> ";
573        }
574    | None -> () ]
575  else ()
576;
577
578
579value max_ancestor_level conf base ip max_lev =
580  let x = ref 0 in
581  let mark = Array.make (nb_of_persons base) False in
582  let rec loop level ip =
583    if mark.(Adef.int_of_iper ip) then ()
584    else do {
585      mark.(Adef.int_of_iper ip) := True;
586      x.val := max x.val level;
587      if x.val = max_lev then ()
588      else
589        match get_parents (pget conf base ip) with
590        [ Some ifam ->
591            let cpl = foi base ifam in
592            do {
593              loop (succ level) (get_father cpl);
594              loop (succ level) (get_mother cpl)
595            }
596        | _ -> () ]
597    }
598  in
599  do { loop 0 ip; x.val }
600;
601
602value default_max_cousin_lev = 5;
603
604value max_cousin_level conf base p =
605  let max_lev =
606    try int_of_string (List.assoc "max_cousins_level" conf.base_env) with
607    [ Not_found | Failure _ -> default_max_cousin_lev ]
608  in
609  max_ancestor_level conf base (get_key_index p) max_lev + 1
610;
611
612value limit_anc_by_tree conf =
613  match p_getint conf.base_env "max_anc_tree" with
614  [ Some x -> max 1 x
615  | None -> 7 ]
616;
617
618value limit_desc conf =
619  match p_getint conf.base_env "max_desc_level" with
620  [ Some x -> max 1 x
621  | None -> 12 ]
622;
623
624value infinite = 10000;
625
626value make_desc_level_table conf base max_level p = do {
627  let line =
628    match p_getenv conf.env "t" with
629    [ Some "M" -> Male
630    | Some "F" -> Female
631    | Some _ | None -> Neuter ]
632  in
633  (* the table 'levt' may be not necessary, since I added 'flevt'; kept
634     because '%max_desc_level;' is still used... *)
635  let levt = Array.make (nb_of_persons base) infinite in
636  let flevt = Array.make (nb_of_families base) infinite in
637  let get = pget conf base in
638  let ini_ip = get_key_index p in
639  let rec fill lev =
640    fun
641    [ [] -> ()
642    | ipl ->
643        let new_ipl =
644          List.fold_left
645            (fun ipl ip ->
646               if levt.(Adef.int_of_iper ip) <= lev then ipl
647               else if lev <= max_level then do {
648                 levt.(Adef.int_of_iper ip) := lev;
649                 let down =
650                   if ip = ini_ip then True
651                   else
652                     match line with
653                     [ Male -> get_sex (pget conf base ip) <> Female
654                     | Female -> get_sex (pget conf base ip) <> Male
655                     | Neuter -> True ]
656                 in
657                 if down then
658                   Array.fold_left
659                     (fun ipl ifam -> do {
660                        if flevt.(Adef.int_of_ifam ifam) <= lev then ()
661                        else flevt.(Adef.int_of_ifam ifam) := lev;
662                        let ipa = get_children (foi base ifam) in
663                        Array.fold_left (fun ipl ip -> [ip :: ipl]) ipl ipa
664                      })
665                     ipl (get_family (get ip))
666                  else ipl
667               }
668               else ipl)
669            [] ipl
670        in
671        fill (succ lev) new_ipl ]
672  in
673  fill 0 [ini_ip];
674  (levt, flevt)
675};
676
677value desc_level_max conf base desc_level_table_l =
678  let (levt, _) = Lazy.force desc_level_table_l in
679  let x = ref 0 in
680  do {
681    for i = 0 to Array.length levt - 1 do {
682      let lev = levt.(i) in
683      if lev != infinite && x.val < lev then x.val := lev else ()
684    };
685    x.val
686  }
687;
688
689value max_descendant_level conf base desc_level_table_l =
690(*
691  min (limit_desc conf)
692*)
693    (desc_level_max conf base desc_level_table_l)
694;
695
696(* ancestors by list *)
697
698type generation_person =
699  [ GP_person of Num.t and iper and option ifam
700  | GP_same of Num.t and Num.t and iper
701  | GP_interv of option (Num.t * Num.t * option (Num.t * Num.t))
702  | GP_missing of Num.t and iper ]
703;
704
705value next_generation conf base mark gpl =
706  let gpl =
707    List.fold_right
708      (fun gp gpl ->
709         match gp with
710         [ GP_person n ip _ ->
711             let n_fath = Num.twice n in
712             let n_moth = Num.inc n_fath 1 in
713             let a = pget conf base ip in
714             match get_parents a with
715             [ Some ifam ->
716                 let cpl = foi base ifam in
717                 [GP_person n_fath (get_father cpl) (Some ifam);
718                  GP_person n_moth (get_mother cpl) (Some ifam) :: gpl]
719             | None -> [GP_missing n ip :: gpl] ]
720         | GP_interv None -> [gp :: gpl]
721         | GP_interv (Some (n1, n2, x)) ->
722             let x =
723               match x with
724               [ Some (m1, m2) -> Some (Num.twice m1, Num.twice m2)
725               | None -> None ]
726             in
727             let gp = GP_interv (Some (Num.twice n1, Num.twice n2, x)) in
728             [gp :: gpl]
729         | _ -> gpl ])
730      gpl []
731  in
732  let gpl =
733    List.fold_left
734      (fun gpl gp ->
735         match gp with
736         [ GP_person n ip _ ->
737             let i = Adef.int_of_iper ip in
738             let m = mark.(i) in
739             if Num.eq m Num.zero then do { mark.(i) := n; [gp :: gpl] }
740             else [GP_same n m ip :: gpl]
741         | _ -> [gp :: gpl] ])
742      [] gpl
743  in
744  List.rev gpl
745;
746
747value next_generation2 conf base mark gpl =
748  let gpl =
749    List.map
750      (fun gp ->
751         match gp with
752         [ GP_same n m ip ->
753             GP_interv (Some (n, Num.inc n 1, Some (m, Num.inc m 1)))
754         | _ -> gp ])
755      gpl
756  in
757  let gpl = next_generation conf base mark gpl in
758  List.fold_right
759    (fun gp gpl ->
760       match (gp, gpl) with
761       [ (GP_interv (Some (n1, n2, x)),
762          [GP_interv (Some (n3, n4, y)) :: gpl1]) ->
763           if Num.eq n2 n3 then
764             let z =
765               match (x, y) with
766               [ (Some (m1, m2), Some (m3, m4)) ->
767                   if Num.eq m2 m3 then Some (m1, m4) else None
768               | _ -> None ]
769             in
770             [GP_interv (Some (n1, n4, z)) :: gpl1]
771           else [GP_interv None :: gpl1]
772       | (GP_interv _, [GP_interv _ :: gpl]) ->
773           [GP_interv None :: gpl]
774       | (GP_missing _ _, gpl) -> gpl
775       | _ -> [gp :: gpl] ])
776    gpl []
777;
778
779value sosa_is_present all_gp n1 =
780  loop all_gp where rec loop =
781    fun
782    [ [GP_person n _ _ :: gpl]
783    | [GP_same n _ _ :: gpl] -> if Num.eq n n1 then True else loop gpl
784    | [gp :: gpl] -> loop gpl
785    | [] -> False ]
786;
787
788value get_link all_gp ip =
789  loop all_gp where rec loop =
790    fun
791    [ [(GP_person n ip0 _ as gp) :: gpl] ->
792         if ip = ip0 then Some gp else loop gpl
793    | [gp :: gpl] -> loop gpl
794    | [] -> None ]
795;
796
797value parent_sosa conf base ip all_gp n parent =
798  if sosa_is_present all_gp n then Num.to_string n
799  else
800    match get_parents (pget conf base ip) with
801    [ Some ifam ->
802        match get_link all_gp (parent (foi base ifam)) with
803        [ Some (GP_person n _ _) -> Num.to_string n
804        | _ -> "" ]
805    | None -> "" ]
806;
807
808value will_print =
809  fun
810  [ GP_person _ _ _ -> True
811  | GP_same _ _ _ -> True
812  | _ -> False ]
813;
814
815value get_all_generations conf base p =
816  let max_level =
817    match p_getint conf.env "v" with
818    [ Some v -> v (* + 1 *)
819    | None -> 0 ]
820  in
821  let mark = Array.make (nb_of_persons base) Num.zero in
822  let rec get_generations level gpll gpl =
823    let gpll = [gpl :: gpll] in
824    if level < max_level then
825      let next_gpl = next_generation conf base mark gpl in
826      if List.exists will_print next_gpl then
827        get_generations (level + 1) gpll next_gpl
828      else gpll
829    else gpll
830  in
831  let gpll =
832    get_generations 1 [] [GP_person Num.one (get_key_index p) None]
833  in
834  let gpll = List.rev gpll in
835  List.flatten gpll
836;
837
838(* Ancestors by tree:
839
840  8 ? ? ? ? ? ? ?
841   4   5   ?   7
842     2       3
843         1
844
8451) Build list of levels (t1 = True for parents flag, size 1)
846   => [ [8At1 E E] [4Lt1 5Rt1 7At1] [2Lt1 3Rt1] [1Ct1] ]
847
8482) Enrich list of levels (parents flag, sizing)
849   => [ [8At1 E E] [4Lt1 5Rf1 7Af1] [2Lt3 3Rt1] [1Ct5] ]
850
8513) Display it
852    For each cell:
853      Top vertical bar if parents flag (not on top line)
854      Person
855      Person tree link (vertical bar) ) not on bottom line
856      Horizontal line                 )
857
858*)
859
860type pos = [ Left | Right | Center | Alone ];
861type cell =
862  [ Cell of person and option ifam and pos and bool and int
863  | Empty ]
864;
865
866value rec enrich lst1 lst2 =
867  match (lst1, lst2) with
868  [ (_, []) -> []
869  | ([], lst) -> lst
870  | ([Cell _ _ Right _ s1 :: l1], [Cell p f d u s2 :: l2]) ->
871      [Cell p f d u (s1 + s2 + 1) :: enrich l1 l2]
872  | ([Cell _ _ Left _ s :: l1], [Cell p f d u _ :: l2]) ->
873      enrich l1 [Cell p f d u s :: l2]
874  | ([Cell _ _ _ _ s :: l1], [Cell p f d u _ :: l2]) ->
875     [Cell p f d u s :: enrich l1 l2]
876  | ([Empty :: l1], [Cell p f d _ s :: l2]) ->
877     [Cell p f d False s :: enrich l1 l2]
878  | ([_ :: l1], [Empty :: l2]) -> [Empty :: enrich l1 l2] ]
879;
880
881value is_empty = List.for_all (\= Empty);
882
883value rec enrich_tree lst =
884  match lst with
885  [ [] -> []
886  | [head :: tail] ->
887      if is_empty head then enrich_tree tail
888      else
889        match tail with
890        [ [] -> [head]
891        | [thead :: ttail] ->
892            [head :: enrich_tree [enrich head thead :: ttail]] ] ]
893;
894
895(* tree_generation_list
896    conf: configuration parameters
897    base: base name
898    gv: number of generations
899    p: person *)
900value tree_generation_list conf base gv p =
901  let next_gen pol =
902    List.fold_right
903      (fun po list ->
904         match po with
905         [ Empty -> [Empty :: list]
906         | Cell p _ _ _ _ ->
907             match get_parents p with
908             [ Some ifam ->
909                 let cpl = foi base ifam in
910                 let fath =
911                   let p = pget conf base (get_father cpl) in
912                   if know base p then Some p else None
913                 in
914                 let moth =
915                   let p = pget conf base (get_mother cpl) in
916                   if know base p then Some p else None
917                 in
918                 let fo = Some ifam in
919                 match (fath, moth) with
920                 [ (Some f, Some m) ->
921                     [Cell f fo Left True 1; Cell m fo Right True 1 :: list]
922                 | (Some f, None) -> [Cell f fo Alone True 1 :: list]
923                 | (None, Some m) -> [Cell m fo Alone True 1 :: list]
924                 | (None, None) -> [Empty :: list] ]
925             | _ -> [Empty :: list] ] ])
926      pol []
927  in
928  let gen =
929    loop (gv - 1) [Cell p None Center True 1] [] where rec loop i gen list =
930      if i = 0 then [gen :: list]
931      else loop (i - 1) (next_gen gen) [gen :: list]
932  in
933  enrich_tree gen
934;
935
936(* Ancestors surnames list *)
937
938value get_date_place conf base auth_for_all_anc p =
939  if auth_for_all_anc || authorized_age conf base p then
940    let d1 =
941      match Adef.od_of_codate (get_birth p) with
942      [ None -> Adef.od_of_codate (get_baptism p)
943      | x -> x ]
944    in
945    let d1 =
946      if d1 <> None then d1
947      else
948        List.fold_left
949          (fun d ifam ->
950             if d <> None then d
951             else Adef.od_of_codate (get_marriage (foi base ifam)))
952          d1 (Array.to_list (get_family p))
953    in
954    let d2 =
955      match get_death p with
956      [ Death _ cd -> Some (Adef.date_of_cdate cd)
957      | _ ->
958          match get_burial p with
959          [ Buried cod -> Adef.od_of_codate cod
960          | Cremated cod -> Adef.od_of_codate cod
961          | _ -> None ] ]
962    in
963    let auth_for_all_anc =
964      if auth_for_all_anc then True
965      else
966        match d2 with
967        [ Some (Dgreg d _) ->
968            let a = CheckItem.time_elapsed d conf.today in
969            Util.strictly_after_private_years conf a
970        | _ -> False ]
971    in
972    let pl =
973      let pl = "" in
974      let pl = if pl <> "" then pl else sou base (get_birth_place p) in
975      let pl = if pl <> "" then pl else sou base (get_baptism_place p) in
976      let pl = if pl <> "" then pl else sou base (get_death_place p) in
977      let pl = if pl <> "" then pl else sou base (get_burial_place p) in
978      let pl =
979        if pl <> "" then pl
980        else
981          List.fold_left
982            (fun pl ifam ->
983               if pl <> "" then pl
984               else sou base (get_marriage_place (foi base ifam)))
985            pl (Array.to_list (get_family p))
986      in
987      pl
988    in
989    ((d1, d2, pl), auth_for_all_anc)
990  else ((None, None, ""), False)
991;
992
993(* duplications proposed for merging *)
994
995type dup = [ DupFam of ifam and ifam | DupInd of iper and iper | NoDup ];
996type excl_dup = (list (Adef.iper * Adef.iper) * list (Adef.ifam * Adef.ifam));
997
998value gen_excluded_possible_duplications conf s i_of_int =
999  match p_getenv conf.env s with
1000  [ Some s ->
1001      loop [] 0 where rec loop ipl i =
1002        if i >= String.length s then ipl
1003        else
1004          let j =
1005            try String.index_from s i ',' with
1006            [ Not_found -> String.length s ]
1007          in
1008          if j = String.length s then ipl
1009          else
1010            let k =
1011              try String.index_from s (j + 1) ',' with
1012              [ Not_found -> String.length s ]
1013            in
1014            let s1 = String.sub s i (j - i) in
1015            let s2 = String.sub s (j + 1) (k - j - 1) in
1016            let ipl =
1017              match
1018                try Some (int_of_string s1, int_of_string s2) with
1019                [ Failure _ -> None ]
1020              with
1021              [ Some (i1, i2) -> [(i_of_int i1, i_of_int i2) :: ipl]
1022              | None -> ipl ]
1023            in
1024            loop ipl (k + 1)
1025  | None -> [] ]
1026;
1027
1028value excluded_possible_duplications conf =
1029  (gen_excluded_possible_duplications conf "iexcl" Adef.iper_of_int,
1030   gen_excluded_possible_duplications conf "fexcl" Adef.ifam_of_int)
1031;
1032
1033value first_possible_duplication base ip (iexcl, fexcl) =
1034  let ifaml = Array.to_list (get_family (poi base ip)) in
1035  let cand_spouse =
1036    loop_spouse ifaml where rec loop_spouse =
1037      fun
1038      [ [ifam1 :: ifaml1] ->
1039          let isp1 = Gutil.spouse ip (foi base ifam1) in
1040          let sp1 = poi base isp1 in
1041          let fn1 = get_first_name sp1 in
1042          let sn1 = get_surname sp1 in
1043          loop_same ifaml1 where rec loop_same =
1044            fun
1045            [ [ifam2 :: ifaml2] ->
1046                let isp2 = Gutil.spouse ip (foi base ifam2) in
1047                if isp2 = isp1 then
1048                  if not (List.mem (ifam1, ifam2) fexcl) then
1049                    DupFam ifam1 ifam2
1050                  else loop_same ifaml2
1051                else
1052                  let sp2 = poi base isp2 in
1053                  if List.mem (isp1, isp2) iexcl then loop_same ifaml2
1054                  else if eq_istr (get_first_name sp2) fn1 &&
1055                     eq_istr (get_surname sp2) sn1
1056                  then
1057                    DupInd isp1 isp2
1058                  else loop_same ifaml2
1059            | [] -> loop_spouse ifaml1 ]
1060      | [] -> NoDup ]
1061  in
1062  if cand_spouse <> NoDup then cand_spouse
1063  else
1064    let ipl =
1065      loop ifaml where rec loop =
1066        fun
1067        [ [ifam :: ifaml] ->
1068            let ipl = Array.to_list (get_children (foi base ifam)) in
1069            ipl @ loop ifaml
1070        | [] -> [] ]
1071    in
1072    loop_chil ipl where rec loop_chil =
1073      fun
1074      [ [ip1 :: ipl1] ->
1075          let p1 = poi base ip1 in
1076          let fn1 = get_first_name p1 in
1077          loop_same ipl1 where rec loop_same =
1078            fun
1079            [ [ip2 :: ipl2] ->
1080                let p2 = poi base ip2 in
1081                if List.mem (ip1, ip2) iexcl then loop_same ipl2
1082                else if eq_istr (get_first_name p2) fn1 then
1083                  DupInd ip1 ip2
1084                else loop_same ipl2
1085            | [] -> loop_chil ipl1 ]
1086      | [] -> NoDup ]
1087;
1088
1089value has_possible_duplications conf base p =
1090  let ip = get_key_index p in
1091  let excl = excluded_possible_duplications conf in
1092  first_possible_duplication base ip excl <> NoDup
1093;
1094
1095value merge_date_place conf base surn ((d1, d2, pl), auth) p =
1096  let ((pd1, pd2, ppl), auth) = get_date_place conf base auth p in
1097  let nd1 =
1098    if pd1 <> None then pd1
1099    else if eq_istr (get_surname p) surn then if pd2 <> None then pd2 else d1
1100    else None
1101  in
1102  let nd2 =
1103    if eq_istr (get_surname p) surn then
1104      if d2 <> None then d2
1105      else if d1 <> None then d1
1106      else if pd1 <> None then pd2
1107      else pd1
1108    else if pd2 <> None then pd2
1109    else if pd1 <> None then pd1
1110    else d1
1111  in
1112  let pl =
1113    if ppl <> "" then ppl else if eq_istr (get_surname p) surn then pl
1114    else ""
1115  in
1116  ((nd1, nd2, pl), auth)
1117;
1118
1119value build_surnames_list conf base v p =
1120  let ht = Hashtbl.create 701 in
1121  let mark = Array.make (nb_of_persons base) 5 in
1122  let auth = conf.wizard || conf.friend in
1123  let add_surname sosa p surn dp =
1124    let r =
1125      try Hashtbl.find ht surn with
1126      [ Not_found ->
1127          let r = ref ((fst dp, p), []) in
1128          do { Hashtbl.add ht surn r; r } ]
1129    in
1130    r.val := (fst r.val, [sosa :: snd r.val])
1131  in
1132  let rec loop lev sosa p surn dp =
1133    if mark.(Adef.int_of_iper (get_key_index p)) = 0 then ()
1134    else if lev = v then
1135      if (is_hide_names conf p) && not (fast_auth_age conf p) then ()
1136      else add_surname sosa p surn dp
1137    else do {
1138      mark.(Adef.int_of_iper (get_key_index p)) :=
1139        mark.(Adef.int_of_iper (get_key_index p)) - 1;
1140      match get_parents p with
1141      [ Some ifam ->
1142          let cpl = foi base ifam in
1143          let fath = pget conf base (get_father cpl) in
1144          let moth = pget conf base (get_mother cpl) in
1145          do {
1146            if not (eq_istr surn (get_surname fath)) &&
1147               not (eq_istr surn (get_surname moth))
1148            then
1149              add_surname sosa p surn dp
1150            else ();
1151            let sosa = Num.twice sosa in
1152            if not (is_hidden fath) then
1153              let dp1 = merge_date_place conf base surn dp fath in
1154              loop (lev + 1) sosa fath (get_surname fath) dp1
1155            else ();
1156            let sosa = Num.inc sosa 1 in
1157            if not (is_hidden moth) then
1158              let dp2 = merge_date_place conf base surn dp moth in
1159              loop (lev + 1) sosa moth (get_surname moth) dp2
1160            else ();
1161          }
1162      | None -> add_surname sosa p surn dp ]
1163    }
1164  in
1165  do {
1166    loop 1 Num.one p (get_surname p) (get_date_place conf base auth p);
1167    let list = ref [] in
1168    Hashtbl.iter
1169      (fun i dp ->
1170         let surn = sou base i in
1171         if surn <> "?" then list.val := [(surn, dp.val) :: list.val] else ())
1172      ht;
1173    List.sort
1174      (fun (s1, _) (s2, _) ->
1175         match
1176           Gutil.alphabetic_order (surname_end base s1) (surname_end base s2)
1177         with
1178         [ 0 ->
1179             Gutil.alphabetic_order (surname_begin base s1)
1180               (surname_begin base s2)
1181         | x -> x ])
1182      list.val
1183  }
1184;
1185
1186
1187(* ************************************************************************* *)
1188(*  [Fonc] build_list_eclair :
1189      config -> base -> int -> person ->
1190        list
1191          (string * string * option date * option date * person * list iper) *)
1192(** [Description] : Construit la liste éclair des ascendants de p jusqu'à la
1193                    génération v.
1194    [Args] :
1195      - conf : configuration de la base
1196      - base : base de donnée
1197      - v    : le nombre de génération
1198      - p    : person
1199    [Retour] : (surname * place * date begin * date end * person * list iper)
1200    [Rem] : Exporté en clair hors de ce module.                              *)
1201(* ************************************************************************* *)
1202value build_list_eclair conf base v p =
1203  let ht = Hashtbl.create 701 in
1204  let mark = Array.make (nb_of_persons base) False in
1205  (* Fonction d'ajout dans la Hashtbl. A la clé (surname, place) on associe *)
1206  (* la personne (pour l'interprétation dans le template), la possible date *)
1207  (* de début, la possible date de fin, la liste des personnes/évènements.  *)
1208  (* Astuce: le nombre d'élément de la liste correspond au nombre             *)
1209  (* d'évènements et le nombre d'iper unique correspond au nombre d'individu. *)
1210  let add_surname p surn pl d =
1211    if not (is_empty_string pl) then
1212      (* On utilise la string du lieu, parce qu'en gwc2, les adresses des *)
1213      (* lieux sont différentes selon l'évènement.                        *)
1214      (* On fait un string_of_place à cause des éventuels crochets, pour  *)
1215      (* avoir l'unicité du lieu et le trie alphabétique.                 *)
1216      let pl = Util.string_of_place conf (sou base pl) in
1217      let r =
1218        try Hashtbl.find ht (surn, pl) with
1219        [ Not_found ->
1220            let r = ref (p, None, None, []) in
1221            do { Hashtbl.add ht (surn, pl) r; r } ]
1222      in
1223      (* Met la jour le binding : dates et liste des iper. *)
1224      r.val :=
1225        (fun p (pp, db, de, l) ->
1226          let db =
1227            match db with
1228            [ Some dd ->
1229                match d with
1230                [ Some d ->
1231                  if Date.compare_date d dd < 0 then Some d
1232                  else db
1233                | None -> db ]
1234            | None -> d ]
1235          in
1236          let de =
1237            match de with
1238            [ Some dd ->
1239                match d with
1240                [ Some d ->
1241                  if Date.compare_date d dd > 0 then Some d
1242                  else de
1243                | None -> de ]
1244            | None -> d ]
1245          in
1246          (pp, db, de, [(get_key_index p) :: l]))
1247        p r.val
1248    else ()
1249  in
1250  (* Fonction d'ajout de tous les évènements d'une personne (birth, bapt...). *)
1251  let add_person p surn =
1252    if mark.(Adef.int_of_iper (get_key_index p)) then ()
1253    else do {
1254      mark.(Adef.int_of_iper (get_key_index p)) := True;
1255      add_surname p surn (get_birth_place p) (Adef.od_of_codate (get_birth p));
1256      add_surname p surn (get_baptism_place p)
1257        (Adef.od_of_codate (get_baptism p));
1258      let death =
1259        match get_death p with
1260        [ Death _ cd -> Some (Adef.date_of_cdate cd)
1261        | _ -> None ]
1262      in
1263      add_surname p surn (get_death_place p) death;
1264      let burial =
1265        match get_burial p with
1266        [ Buried cod | Cremated cod -> Adef.od_of_codate cod
1267        | _ -> None ]
1268      in
1269      add_surname p surn (get_burial_place p) burial;
1270      List.iter
1271        (fun ifam ->
1272          let fam = foi base ifam in
1273          add_surname p surn (get_marriage_place fam)
1274            (Adef.od_of_codate (get_marriage fam)))
1275        (Array.to_list (get_family p))
1276    }
1277  in
1278  (* Parcours les ascendants de p et les ajoute dans la Hashtbl. *)
1279  let rec loop lev p surn =
1280    if lev = v then
1281      if (is_hide_names conf p) && not (fast_auth_age conf p) then ()
1282      else add_person p surn
1283    else do {
1284      add_person p surn;
1285      match get_parents p with
1286      [ Some ifam ->
1287          let cpl = foi base ifam in
1288          let fath = pget conf base (get_father cpl) in
1289          let moth = pget conf base (get_mother cpl) in
1290          do {
1291            if not (is_hidden fath) then loop (lev + 1) fath (get_surname fath)
1292            else ();
1293            if not (is_hidden moth) then loop (lev + 1) moth (get_surname moth)
1294            else ();
1295          }
1296      | None -> () ]
1297    }
1298  in
1299  do {
1300    (* Construction de la Hashtbl. *)
1301    loop 1 p (get_surname p);
1302    (* On parcours la Hashtbl, et on élimine les noms vide (=?) *)
1303    let list = ref [] in
1304    Hashtbl.iter
1305      (fun (istr, place) ht_val ->
1306         let surn = sou base istr in
1307         if surn <> "?" then
1308           let (p, db, de, pl) = (fun x -> x) ht_val.val in
1309           list.val := [(surn, place, db, de, p, pl) :: list.val]
1310         else ())
1311      ht;
1312    (* On trie la liste par nom, puis lieu. *)
1313    List.sort
1314      (fun (s1, pl1, _, _, _, _) (s2, pl2, _, _, _, _) ->
1315         match
1316           Gutil.alphabetic_order (surname_end base s1) (surname_end base s2)
1317         with
1318         [ 0 ->
1319             match Gutil.alphabetic_order (surname_begin base s1)
1320               (surname_begin base s2)
1321             with
1322             [ 0 -> Gutil.alphabetic_order pl1 pl2
1323             | x -> x ]
1324         | x -> x ])
1325      list.val
1326  }
1327;
1328
1329value linked_page_text conf base p s key str (pg, (_, il)) =
1330  match pg with
1331  [ NotesLinks.PgMisc pg ->
1332      let list = List.map snd (List.filter (fun (k, _) -> k = key) il) in
1333      List.fold_right
1334        (fun text str ->
1335           try
1336             let (nenv, _) = Notes.read_notes base pg in
1337             let v =
1338               let v = List.assoc s nenv in
1339               if v = "" then raise Not_found
1340               else Util.nth_field v (Util.index_of_sex (get_sex p))
1341             in
1342             match text.NotesLinks.lnTxt with
1343             [ Some "" -> str
1344             | _ ->
1345                 let str1 =
1346                   let v =
1347                     let text = text.NotesLinks.lnTxt in
1348                     match text with
1349                     [ Some text ->
1350                         loop 0 0 where rec loop i len =
1351                           if i = String.length text then Buff.get len
1352                           else if text.[i] = '*' then
1353                             loop (i + 1) (Buff.mstore len v)
1354                           else loop (i + 1) (Buff.store len text.[i])
1355                     | None -> v ]
1356                   in
1357                   let (a, b, c) =
1358                     try
1359                       let i = String.index v '{' in
1360                       let j = String.index v '}' in
1361                       let a = String.sub v 0 i in
1362                       let b = String.sub v (i + 1) (j - i - 1) in
1363                       let c =
1364                         String.sub v (j + 1) (String.length v - j - 1)
1365                       in
1366                       (a, b, c)
1367                     with
1368                     [ Not_found -> ("", v, "") ]
1369                   in
1370                   Printf.sprintf
1371                     "%s<a href=\"%sm=NOTES;f=%s#p_%d\">%s</a>%s" a
1372                     (commd conf) pg text.NotesLinks.lnPos b c
1373                 in
1374                 if str = "" then str1 else str ^ ", " ^ str1 ]
1375           with
1376           [ Not_found -> str ])
1377        list str
1378  | _ -> str ]
1379;
1380
1381value links_to_ind conf base db key =
1382  let list =
1383    List.fold_left
1384      (fun pgl (pg, (_, il)) ->
1385         let record_it =
1386           match pg with
1387           [ NotesLinks.PgInd ip -> authorized_age conf base (pget conf base ip)
1388           | NotesLinks.PgFam ifam ->
1389               let fam = foi base ifam in
1390               if is_deleted_family fam then False
1391               else authorized_age conf base (pget conf base (get_father fam))
1392           | NotesLinks.PgNotes | NotesLinks.PgMisc _
1393           | NotesLinks.PgWizard _ -> True ]
1394         in
1395         if record_it then
1396           List.fold_left
1397             (fun pgl (k, _) -> if k = key then [pg :: pgl] else pgl)
1398             pgl il
1399         else pgl)
1400      [] db
1401  in
1402  list_uniq (List.sort compare list)
1403;
1404
1405(* Interpretation of template file *)
1406
1407value rec compare_ls sl1 sl2 =
1408  match (sl1, sl2) with
1409  [ ([s1 :: sl1], [s2 :: sl2]) ->
1410      (* Je ne sais pas s'il y a des effets de bords, mais on  *)
1411      (* essaie de convertir s1 s2 en int pour éviter que "10" *)
1412      (* soit plus petit que "2". J'espère qu'on ne casse pas  *)
1413      (* les performances à cause du try..with.                *)
1414      let c =
1415        try Pervasives.compare (int_of_string s1) (int_of_string s2)
1416        with [ Failure "int_of_string" -> Gutil.alphabetic_order s1 s2 ]
1417      in
1418      if c = 0 then compare_ls sl1 sl2 else c
1419  | ([_ :: _], []) -> 1
1420  | ([], [_ :: _]) -> -1
1421  | ([], []) -> 0 ]
1422;
1423
1424module SortedList =
1425  Set.Make (struct type t = list string; value compare = compare_ls; end)
1426;
1427
1428module IperSet =
1429  Set.Make
1430    (struct
1431      type t = iper;
1432      value compare i1 i2 =
1433        Pervasives.compare (Adef.int_of_iper i1) (Adef.int_of_iper i2);
1434     end)
1435;
1436
1437
1438(*
1439   Type pour représenté soit :
1440     - la liste des branches patronymique
1441       (surname * date begin * date end * place * person * list sosa * loc)
1442     - la liste éclair
1443       (surname * place * date begin * date end * person * list iper * loc)
1444*)
1445type ancestor_surname_info =
1446  [ Branch of
1447      (string * option date * option date * string * person * list Num.t * loc)
1448  | Eclair of
1449      (string * string * option date * option date * person * list iper * loc) ]
1450;
1451
1452type env 'a =
1453  [ Vallgp of list generation_person
1454  | Vanc of generation_person
1455  | Vanc_surn of ancestor_surname_info
1456  | Vcell of cell
1457  | Vcelll of list cell
1458  | Vcnt of ref int
1459  | Vdesclevtab of Lazy.t (array int * array int)
1460  | Vdmark of ref (array bool)
1461  | Vslist of ref SortedList.t
1462  | Vslistlm of list (list string)
1463  | Vind of person
1464  | Vfam of ifam and family and (iper * iper * iper) and bool
1465  | Vrel of relation and option person
1466  | Vbool of bool
1467  | Vint of int
1468  | Vgpl of list generation_person
1469  | Vnldb of NotesLinks.notes_links_db
1470  | Vstring of string
1471  | Vsosa_ref of Lazy.t (option person)
1472  | Vsosa of ref (list (iper * option (Num.t * person)))
1473  | Vt_sosa of sosa_t
1474  | Vtitle of person and title_item
1475  | Vlazyp of ref (option string)
1476  | Vlazy of Lazy.t (env 'a)
1477  | Vother of 'a
1478  | Vnone ]
1479and title_item =
1480  (int * gen_title_name istr * istr * list istr *
1481   list (option date * option date))
1482;
1483
1484value get_env v env =
1485  try
1486    match List.assoc v env with
1487    [ Vlazy l -> Lazy.force l
1488    | x -> x ]
1489  with
1490  [ Not_found -> Vnone ]
1491;
1492value get_vother = fun [ Vother x -> Some x | _ -> None ];
1493value set_vother x = Vother x;
1494
1495value not_impl func x =
1496  let desc =
1497    if Obj.is_block (Obj.repr x) then
1498      "tag = " ^ string_of_int (Obj.\tag (Obj.repr x))
1499    else "int_val = " ^ string_of_int (Obj.magic x)
1500  in
1501  ">Perso." ^ func ^ ": not impl " ^ desc ^ "<p>\n"
1502;
1503
1504value extract_var sini s =
1505  let len = String.length sini in
1506  if String.length s > len && String.sub s 0 (String.length sini) = sini then
1507    String.sub s len (String.length s - len)
1508  else ""
1509;
1510
1511value template_file = ref "perso.txt";
1512
1513value warning_use_has_parents_before_parent (bp, ep) var r =
1514  IFDEF UNIX THEN do {
1515    Printf.eprintf "*** <W> %s" template_file.val;
1516    Printf.eprintf ", chars %d-%d" bp ep;
1517    Printf.eprintf "\
1518: since v5.00, must test \"has_parents\" before using \"%s\"\n"
1519      var;
1520    flush stderr;
1521    r
1522  }
1523  ELSE r END
1524;
1525
1526value obsolete_list = ref [];
1527
1528value obsolete (bp, ep) version var new_var r =
1529  if List.mem var obsolete_list.val then r
1530  else IFDEF UNIX THEN do {
1531    Printf.eprintf "*** <W> %s, chars %d-%d:" template_file.val bp ep;
1532    Printf.eprintf " \"%s\" obsolete since v%s%s\n" var version
1533      (if new_var = "" then "" else "; rather use \"" ^ new_var ^ "\"");
1534    flush stderr;
1535    obsolete_list.val := [var :: obsolete_list.val];
1536    r
1537  }
1538  ELSE r END
1539;
1540
1541
1542value bool_val x = VVbool x;
1543value str_val x = VVstring x;
1544
1545value gen_string_of_img_sz max_wid max_hei conf base env (p, p_auth) =
1546  if p_auth then
1547    let v = image_and_size conf base p (limited_image_size max_wid max_hei) in
1548    match v with
1549    [ Some (_, _, Some (width, height)) ->
1550        Format.sprintf " width=\"%d\" height=\"%d\"" width height
1551    | Some (_, _, None) -> Format.sprintf " height=\"%d\"" max_hei
1552    | None -> "" ]
1553  else ""
1554;
1555value string_of_image_size = gen_string_of_img_sz max_im_wid max_im_wid;
1556value string_of_image_medium_size = gen_string_of_img_sz 160 120;
1557value string_of_image_small_size = gen_string_of_img_sz 100 75;
1558
1559value get_sosa conf base env r p =
1560  try List.assoc (get_key_index p) r.val with
1561  [ Not_found -> do {
1562      let s =
1563        match get_env "sosa_ref" env with
1564        [ Vsosa_ref v ->
1565          match get_env "t_sosa" env with
1566          [ Vt_sosa t_sosa -> find_sosa conf base p v t_sosa
1567          | _ -> None ]
1568        | _ -> None ]
1569      in
1570      r.val := [(get_key_index p, s) :: r.val];
1571      s
1572    } ]
1573;
1574
1575value make_ep conf base ip =
1576  let p = pget conf base ip in
1577  let p_auth = authorized_age conf base p in (p, p_auth)
1578;
1579
1580value make_efam conf base ip ifam =
1581  let fam = foi base ifam in
1582  let ifath = get_father fam in
1583  let imoth = get_mother fam in
1584  let ispouse = if ip = ifath then imoth else ifath in
1585  let cpl = (ifath, imoth, ispouse) in
1586  let m_auth =
1587    authorized_age conf base (pget conf base ifath) &&
1588    authorized_age conf base (pget conf base imoth)
1589  in
1590  (fam, cpl, m_auth)
1591;
1592
1593value rec eval_var conf base env ep loc sl =
1594  try eval_simple_var conf base env ep sl with
1595  [ Not_found -> eval_compound_var conf base env ep loc sl ]
1596and eval_simple_var conf base env ep =
1597  fun
1598  [ [s] ->
1599      try bool_val (eval_simple_bool_var conf base env ep s) with
1600      [ Not_found -> str_val (eval_simple_str_var conf base env ep s) ]
1601  | _ -> raise Not_found ]
1602and eval_simple_bool_var conf base env (_, p_auth) =
1603  fun
1604  [ "are_divorced" ->
1605      match get_env "fam" env with
1606      [ Vfam _ fam _ _ ->
1607          match get_divorce fam with
1608          [ Divorced _ -> True
1609          | _ -> False ]
1610      | _ -> raise Not_found ]
1611  | "are_engaged" ->
1612      match get_env "fam" env with
1613      [ Vfam _ fam _ _ -> get_relation fam = Engaged
1614      | _ -> raise Not_found ]
1615  | "are_married" ->
1616      match get_env "fam" env with
1617      [ Vfam _ fam _ _ ->
1618          get_relation fam = Married || get_relation fam = NoSexesCheckMarried
1619      | _ -> raise Not_found ]
1620  | "are_not_married" ->
1621      match get_env "fam" env with
1622      [ Vfam _ fam _ _ ->
1623          get_relation fam = NotMarried ||
1624          get_relation fam = NoSexesCheckNotMarried
1625      | _ -> raise Not_found ]
1626  | "are_separated" ->
1627      match get_env "fam" env with
1628      [ Vfam _ fam _ _ ->
1629          match get_divorce fam with
1630          [ Separated -> True
1631          | _ -> False ]
1632      | _ -> raise Not_found ]
1633  | "browsing_with_sosa_ref" ->
1634      match get_env "sosa_ref" env with
1635      [ Vsosa_ref v -> Lazy.force v <> None
1636      | _ -> raise Not_found ]
1637  | "has_comment" ->
1638      match get_env "fam" env with
1639      [ Vfam _ fam _ m_auth ->
1640          m_auth && not conf.no_note && sou base (get_comment fam) <> ""
1641      | _ -> raise Not_found ]
1642  | "has_relation_her" ->
1643      match get_env "rel" env with
1644      [ Vrel {r_moth = Some _} None -> True
1645      | _ -> False ]
1646  | "has_relation_him" ->
1647      match get_env "rel" env with
1648      [ Vrel {r_fath = Some _} None -> True
1649      | _ -> False ]
1650  | "has_witnesses" ->
1651      match get_env "fam" env with
1652      [ Vfam _ fam _ m_auth ->
1653          m_auth && Array.length (get_witnesses fam) > 0
1654      | _ -> raise Not_found ]
1655  | "is_first" ->
1656      match get_env "first" env with
1657      [ Vbool x -> x
1658      | _ -> raise Not_found ]
1659  | "is_last" ->
1660      match get_env "last" env with
1661      [ Vbool x -> x
1662      | _ -> raise Not_found ]
1663  | "is_no_mention" ->
1664      match get_env "fam" env with
1665      [ Vfam _ fam _ _ -> get_relation fam = NoMention
1666      | _ -> raise Not_found ]
1667  | "is_no_sexes_check" ->
1668      match get_env "fam" env with
1669      [ Vfam _ fam _ _ ->
1670          get_relation fam = NoSexesCheckNotMarried ||
1671          get_relation fam = NoSexesCheckMarried
1672      | _ -> raise Not_found ]
1673  | "is_self" -> get_env "pos" env = Vstring "self"
1674  | "is_sibling_after" -> get_env "pos" env = Vstring "next"
1675  | "is_sibling_before" -> get_env "pos" env = Vstring "prev"
1676  | "lazy_printed" ->
1677      match get_env "lazy_print" env with
1678      [ Vlazyp r -> r.val = None
1679      | _ -> raise Not_found ]
1680  | s ->
1681      let v = extract_var "file_exists_" s in
1682      if v <> "" then
1683        let v = code_varenv v in
1684        let s = Srcfile.source_file_name conf v in
1685        Sys.file_exists s
1686      else raise Not_found ]
1687and eval_simple_str_var conf base env (_, p_auth) =
1688  fun
1689  [ "alias" ->
1690      match get_env "alias" env with
1691      [ Vstring s -> s
1692      | _ -> raise Not_found ]
1693  | "child_cnt" -> string_of_int_env "child_cnt" env
1694  | "comment" ->
1695      match get_env "fam" env with
1696      [ Vfam _ fam _ m_auth ->
1697          if m_auth && not conf.no_note then
1698            let s = sou base (get_comment fam) in
1699            let s = string_with_macros conf [] s in
1700            let lines = Wiki.html_of_tlsw conf s in
1701            let wi =
1702              {Wiki.wi_mode = "NOTES";
1703               Wiki.wi_cancel_links = conf.cancel_links;
1704               Wiki.wi_file_path = Notes.file_path conf base;
1705               Wiki.wi_person_exists = person_exists conf base;
1706               Wiki.wi_always_show_link = conf.wizard || conf.friend}
1707            in
1708            let s = Wiki.syntax_links conf wi (String.concat "\n" lines) in
1709            if conf.pure_xhtml then Util.check_xhtml s else s
1710          else ""
1711      | _ -> raise Not_found ]
1712  | "count" ->
1713      match get_env "count" env with
1714      [ Vcnt c -> string_of_int c.val
1715      | _ -> "" ]
1716  | "divorce_date" ->
1717      match get_env "fam" env with
1718      [ Vfam _ fam (_, _, isp) m_auth ->
1719          match get_divorce fam with
1720          [ Divorced d ->
1721              let d = Adef.od_of_codate d in
1722              match d with
1723              [ Some d when m_auth ->
1724                match p_getenv conf.base_env "long_date" with
1725                [ Some "yes" -> " <em>" ^ (Date.string_of_ondate conf d)
1726                                ^ (Date.get_wday conf d) ^ "</em>"
1727                | _ -> " <em>" ^ Date.string_of_ondate conf d ^ "</em>" ]
1728              | _ -> "" ]
1729          | _ -> raise Not_found ]
1730      | _ -> raise Not_found ]
1731  | "slash_divorce_date" ->
1732      match get_env "fam" env with
1733      [ Vfam _ fam (_, _, isp) m_auth ->
1734          match get_divorce fam with
1735          [ Divorced d ->
1736              let d = Adef.od_of_codate d in
1737              match d with
1738              [ Some d when m_auth -> Date.string_slash_of_date conf d
1739              | _ -> "" ]
1740          | _ -> raise Not_found ]
1741      | _ -> raise Not_found ]
1742  | "empty_sorted_list" ->
1743      match get_env "list" env with
1744      [ Vslist l -> do { l.val := SortedList.empty; "" }
1745      | _ -> raise Not_found ]
1746  | "family_cnt" -> string_of_int_env "family_cnt" env
1747  | "first_name_alias" ->
1748      match get_env "first_name_alias" env with
1749      [ Vstring s -> s
1750      | _ -> "" ]
1751  | "incr_count" ->
1752      match get_env "count" env with
1753      [ Vcnt c -> do { incr c; "" }
1754      | _ -> "" ]
1755  | "lazy_force" ->
1756      match get_env "lazy_print" env with
1757      [ Vlazyp r ->
1758          match r.val with
1759          [ Some s -> do { r.val := None; s }
1760          | None -> "" ]
1761      | _ -> raise Not_found ]
1762  | "level" ->
1763      match get_env "level" env with
1764      [ Vint i -> string_of_int i
1765      | _ -> "" ]
1766  | "marriage_place" ->
1767      match get_env "fam" env with
1768      [ Vfam _ fam _ m_auth ->
1769          if m_auth then
1770            Util.string_of_place conf (sou base (get_marriage_place fam))
1771          else ""
1772      | _ -> raise Not_found ]
1773  | "max_anc_level" ->
1774      match get_env "max_anc_level" env with
1775      [ Vint i -> string_of_int i
1776      | _ -> "" ]
1777  | "max_cous_level" ->
1778      match get_env "max_cous_level" env with
1779      [ Vint i -> string_of_int i
1780      | _ -> "" ]
1781  | "max_desc_level" ->
1782      match get_env "max_desc_level" env with
1783      [ Vint i -> string_of_int i
1784      | _ -> "" ]
1785  | "nobility_title" ->
1786      match get_env "nobility_title" env with
1787      [ Vtitle p t ->
1788          if p_auth then
1789            string_of_title conf base (transl_nth conf "and" 0) p t
1790          else ""
1791      | _ -> raise Not_found ]
1792  | "number_of_subitems" ->
1793      match get_env "item" env with
1794      [ Vslistlm [[s :: _] :: sll] ->
1795          let n =
1796            loop 1 sll where rec loop n =
1797              fun
1798              [ [[s1 :: _] :: sll] -> if s = s1 then loop (n + 1) sll else n
1799              | _ -> n ]
1800          in
1801          string_of_int n
1802      | _ -> raise Not_found ]
1803  | "on_marriage_date" ->
1804      match get_env "fam" env with
1805      [ Vfam _ fam _ m_auth ->
1806          match (m_auth, Adef.od_of_codate (get_marriage fam)) with
1807          [ (True, Some s) ->
1808            match p_getenv conf.base_env "long_date" with
1809            [ Some "yes" -> (Date.string_of_ondate conf s) ^ (Date.get_wday conf s)
1810            | _ -> Date.string_of_ondate conf s ]
1811          | _ -> "" ]
1812      | _ -> raise Not_found ]
1813  | "slash_marriage_date" ->
1814      match get_env "fam" env with
1815      [ Vfam _ fam _ m_auth ->
1816          match (m_auth, Adef.od_of_codate (get_marriage fam)) with
1817          [ (True, Some s) -> Date.string_slash_of_date conf s
1818          | _ -> "" ]
1819      | _ -> raise Not_found ]
1820  | "origin_file" ->
1821      if conf.wizard then
1822        match get_env "fam" env with
1823        [ Vfam _ fam _ _ -> sou base (get_origin_file fam)
1824        | _ -> "" ]
1825      else raise Not_found
1826  | "qualifier" ->
1827      match get_env "qualifier" env with
1828      [ Vstring nn -> nn
1829      | _ -> raise Not_found ]
1830  | "related_type" ->
1831      match get_env "rel" env with
1832      [ Vrel r (Some c) ->
1833          rchild_type_text conf r.r_type (index_of_sex (get_sex c))
1834      | _ -> raise Not_found ]
1835  | "relation_type" ->
1836      match get_env "rel" env with
1837      [ Vrel r None ->
1838          match (r.r_fath, r.r_moth) with
1839          [ (Some ip, None) -> relation_type_text conf r.r_type 0
1840          | (None, Some ip) -> relation_type_text conf r.r_type 1
1841          | (Some ip1, Some ip2) -> relation_type_text conf r.r_type 2
1842          | _ -> raise Not_found ]
1843      | _ -> raise Not_found ]
1844  | "reset_count" ->
1845      match get_env "count" env with
1846      [ Vcnt c -> do { c.val := 0; "" }
1847      | _ -> "" ]
1848  | "reset_desc_level" ->
1849      let flevt_save =
1850        match get_env "desc_level_table_save" env with
1851        [ Vdesclevtab levt ->
1852            let (_, flevt) = Lazy.force levt in
1853            flevt
1854        | _ -> raise Not_found ]
1855      in
1856      match get_env "desc_level_table" env with
1857      [ Vdesclevtab levt -> do {
1858          let (_, flevt) = Lazy.force levt in
1859          for i = 0 to Array.length flevt - 1 do {
1860            flevt.(i) := flevt_save.(i);
1861          };
1862          ""
1863        }
1864      | _ -> raise Not_found ]
1865  | "source_type" ->
1866       match get_env "src_typ" env with
1867       [ Vstring s -> s
1868       | _ -> raise Not_found ]
1869  | "surname_alias" ->
1870      match get_env "surname_alias" env with
1871      [ Vstring s -> s
1872      | _ -> raise Not_found ]
1873  | s ->
1874      loop
1875        [("evar_",
1876          fun v ->
1877            match p_getenv (conf.env @ conf.henv) v with
1878            [ Some vv -> quote_escaped vv
1879            | None -> "" ]);
1880         (* warning: "cvar_" deprecated since 5.00; use "bvar." *)
1881         ("cvar_",
1882          fun v -> try List.assoc v conf.base_env with [ Not_found -> "" ])]
1883      where rec loop =
1884        fun
1885        [ [(pfx, f) :: pfx_list] ->
1886            let v = extract_var pfx s in
1887            if v <> "" then f v
1888            else loop pfx_list
1889        | [] -> raise Not_found ] ]
1890and eval_compound_var conf base env ((a, _) as ep) loc =
1891  fun
1892  [ ["ancestor" :: sl] ->
1893      match get_env "ancestor" env with
1894      [ Vanc gp -> eval_ancestor_field_var conf base env gp loc sl
1895      | Vanc_surn info -> eval_anc_by_surnl_field_var conf base env ep info sl
1896      | _ -> raise Not_found ]
1897  | ["base"; "name"] -> VVstring conf.bname
1898  | ["base"; "nb_persons"] ->
1899      VVstring
1900        (string_of_num (Util.transl conf "(thousand separator)")
1901           (Num.of_int (nb_of_persons base)))
1902  | ["cell" :: sl] ->
1903      match get_env "cell" env with
1904      [ Vcell cell -> eval_cell_field_var conf base env ep cell loc sl
1905      | _ -> raise Not_found ]
1906  | ["child" :: sl] ->
1907      match get_env "child" env with
1908      [ Vind p ->
1909          let auth = authorized_age conf base p in
1910          let ep = (p, auth) in
1911          eval_person_field_var conf base env ep loc sl
1912      | _ -> raise Not_found ]
1913  | ["enclosing" :: sl] ->
1914      let rec loop =
1915        fun
1916        [ [("#loop", _) :: env] ->
1917            eval_person_field_var conf base env ep loc sl
1918        | [_ :: env] -> loop env
1919        | [] -> raise Not_found ]
1920      in
1921      loop env
1922  | ["family" :: sl] ->
1923      match get_env "fam" env with
1924      [ Vfam i f c m ->
1925          eval_family_field_var conf base env (i, f, c, m) loc sl
1926      | _ -> raise Not_found ]
1927  | ["father" :: sl] ->
1928      match get_parents a with
1929      [ Some ifam ->
1930          let cpl = foi base ifam in
1931          let ep = make_ep conf base (get_father cpl) in
1932          eval_person_field_var conf base env ep loc sl
1933      | None ->
1934          warning_use_has_parents_before_parent loc "father" (str_val "") ]
1935  | ["item" :: sl] ->
1936      match get_env "item" env with
1937      [ Vslistlm ell -> eval_item_field_var env ell sl
1938      | _ -> raise Not_found ]
1939  | ["mother" :: sl] ->
1940      match get_parents a with
1941      [ Some ifam ->
1942          let cpl = foi base ifam in
1943          let ep = make_ep conf base (get_mother cpl) in
1944          eval_person_field_var conf base env ep loc sl
1945      | None ->
1946          warning_use_has_parents_before_parent loc "mother" (str_val "") ]
1947  | ["next_item" :: sl] ->
1948      match get_env "item" env with
1949      [ Vslistlm [_ :: ell] -> eval_item_field_var env ell sl
1950      | _ -> raise Not_found ]
1951  | ["number_of_ancestors" :: sl] ->
1952      match get_env "n" env with
1953      [ Vint n -> VVstring (eval_num conf (Num.of_int (n - 1)) sl)
1954      | _ -> raise Not_found ]
1955  | ["number_of_descendants" :: sl] ->
1956      match get_env "level" env with
1957      [ Vint i ->
1958          match get_env "desc_level_table" env with
1959          [ Vdesclevtab t ->
1960              let cnt =
1961                Array.fold_left (fun cnt v -> if v <= i then cnt + 1 else cnt)
1962                  0 (fst (Lazy.force t))
1963              in
1964              VVstring (eval_num conf (Num.of_int (cnt - 1)) sl)
1965          | _ -> raise Not_found ]
1966      | _ -> raise Not_found ]
1967  | ["parent" :: sl] ->
1968      match get_env "parent" env with
1969      [ Vind p ->
1970          let ep = (p, authorized_age conf base p) in
1971          eval_person_field_var conf base env ep loc sl
1972      | _ -> raise Not_found ]
1973  | ["prev_item" :: sl] ->
1974      match get_env "prev_item" env with
1975      [ Vslistlm ell -> eval_item_field_var env ell sl
1976      | _ -> raise Not_found ]
1977  | ["prev_family" :: sl] ->
1978      match get_env "prev_fam" env with
1979      [ Vfam i f c m ->
1980          eval_family_field_var conf base env (i, f, c, m) loc sl
1981      | _ -> raise Not_found ]
1982  | ["pvar"; v :: sl] ->
1983      match find_person_in_env conf base v with
1984      [ Some p ->
1985          let ep = make_ep conf base (get_key_index p) in
1986          eval_person_field_var conf base env ep loc sl
1987      | None -> raise Not_found ]
1988  | ["related" :: sl] ->
1989      match get_env "rel" env with
1990      [ Vrel {r_type = rt} (Some p) ->
1991          eval_relation_field_var conf base env
1992            (index_of_sex (get_sex p), rt, get_key_index p, False) loc sl
1993      | _ -> raise Not_found ]
1994  | ["relation_her" :: sl] ->
1995      match get_env "rel" env with
1996      [ Vrel {r_moth = Some ip; r_type = rt} None ->
1997          eval_relation_field_var conf base env (1, rt, ip, True) loc sl
1998      | _ -> raise Not_found ]
1999  | ["relation_him" :: sl] ->
2000      match get_env "rel" env with
2001      [ Vrel {r_fath = Some ip; r_type = rt} None ->
2002          eval_relation_field_var conf base env (0, rt, ip, True) loc sl
2003      | _ -> raise Not_found ]
2004  | ["self" :: sl] -> eval_person_field_var conf base env ep loc sl
2005  | ["sosa_ref" :: sl] ->
2006      match get_env "sosa_ref" env with
2007      [ Vsosa_ref v ->
2008          match Lazy.force v with
2009          [ Some p ->
2010              let ep = make_ep conf base (get_key_index p) in
2011              eval_person_field_var conf base env ep loc sl
2012          | None -> raise Not_found ]
2013      | _ -> raise Not_found ]
2014  | ["spouse" :: sl] ->
2015      match get_env "fam" env with
2016      [ Vfam _ _ (_, _, ip) _ ->
2017          let ep = make_ep conf base ip in
2018          eval_person_field_var conf base env ep loc sl
2019      | _ -> raise Not_found ]
2020  | ["witness" :: sl] ->
2021      match get_env "witness" env with
2022      [ Vind p ->
2023          let ep = (p, authorized_age conf base p) in
2024          eval_person_field_var conf base env ep loc sl
2025      | _ -> raise Not_found ]
2026  | ["witness_relation" :: sl] ->
2027      match get_env "fam" env with
2028      [ Vfam i f c m ->
2029          eval_witness_relation_var conf base env (i, f, c, m) loc sl
2030      | _ -> raise Not_found ]
2031  | sl -> eval_person_field_var conf base env ep loc sl ]
2032and eval_item_field_var env ell =
2033  fun
2034  [ [s] ->
2035      try
2036        match ell with
2037        [ [el :: _] ->
2038            let v = int_of_string s in
2039            let r = try List.nth el (v - 1) with [ Failure _ -> "" ] in
2040            VVstring r
2041        | [] -> VVstring "" ]
2042      with
2043      [ Failure _ -> raise Not_found ]
2044  | _ -> raise Not_found ]
2045and eval_relation_field_var conf base env (i, rt, ip, is_relation) loc =
2046  fun
2047  [ ["type"] ->
2048       if is_relation then VVstring (relation_type_text conf rt i)
2049       else VVstring (rchild_type_text conf rt i)
2050  | sl ->
2051      let ep = make_ep conf base ip in
2052      eval_person_field_var conf base env ep loc sl ]
2053and eval_cell_field_var conf base env ep cell loc =
2054  fun
2055  [ ["colspan"] ->
2056      match cell with
2057      [ Empty -> VVstring "1"
2058      | Cell _ _ _ _ s -> VVstring (string_of_int s) ]
2059  | ["family" :: sl] ->
2060      match cell with
2061      [ Cell p (Some ifam) _ _ _ ->
2062          let (f, c, a) = make_efam conf base (get_key_index p) ifam in
2063          eval_family_field_var conf base env (ifam, f, c, a) loc sl
2064      | _ -> VVstring "" ]
2065  | ["is_center"] ->
2066      match cell with
2067      [ Cell _ _ Center _ _ -> VVbool True
2068      | _ -> VVbool False ]
2069  | ["is_empty"] ->
2070      match cell with
2071      [ Empty -> VVbool True
2072      | _ -> VVbool False ]
2073  | ["is_left"] ->
2074      match cell with
2075      [ Cell _ _ Left _ _ -> VVbool True
2076      | _ -> VVbool False ]
2077  | ["is_right"] ->
2078      match cell with
2079      [ Cell _ _ Right _ _ -> VVbool True
2080      | _ -> VVbool False ]
2081  | ["is_top"] ->
2082      match cell with
2083      [ Cell _ _ _ False _ -> VVbool True
2084      | _ -> VVbool False ]
2085  | ["person" :: sl] ->
2086      match cell with
2087      [ Cell p _ _ _ _ ->
2088          let ep = make_ep conf base (get_key_index p) in
2089          eval_person_field_var conf base env ep loc sl
2090      | _ -> raise Not_found ]
2091  | _ -> raise Not_found ]
2092and eval_ancestor_field_var conf base env gp loc =
2093  fun
2094  [ ["family" :: sl] ->
2095      match gp with
2096      [ GP_person _ ip (Some ifam) ->
2097          let f = foi base ifam in
2098          let ifath = get_father f in
2099          let imoth = get_mother f in
2100          let ispouse = if ip = ifath then imoth else ifath in
2101          let c = (ifath, imoth, ispouse) in
2102          let m_auth =
2103            authorized_age conf base (pget conf base ifath) &&
2104            authorized_age conf base (pget conf base imoth)
2105          in
2106          eval_family_field_var conf base env (ifam, f, c, m_auth) loc sl
2107      | _ -> raise Not_found ]
2108  | ["father" :: sl] ->
2109      match gp with
2110      [ GP_person _ ip _ ->
2111          match (get_parents (pget conf base ip), get_env "all_gp" env) with
2112          [ (Some ifam, Vallgp all_gp) ->
2113              let cpl = foi base ifam in
2114              match get_link all_gp (get_father cpl) with
2115              [ Some gp -> eval_ancestor_field_var conf base env gp loc sl
2116              | None ->
2117                  let ep = make_ep conf base (get_father cpl) in
2118                  eval_person_field_var conf base env ep loc sl ]
2119          | (_, _) -> raise Not_found ]
2120      | GP_same _ _ ip ->
2121          match get_parents (pget conf base ip) with
2122          [ Some ifam ->
2123            let cpl = foi base ifam in
2124            let ep = make_ep conf base (get_father cpl) in
2125            eval_person_field_var conf base env ep loc sl
2126          | _ -> raise Not_found ]
2127      | _ -> raise Not_found ]
2128  | ["father_sosa"] ->
2129      match (gp, get_env "all_gp" env) with
2130      [ (GP_person n ip _ | GP_same n _ ip, Vallgp all_gp) ->
2131          let n = Num.twice n in
2132          VVstring (parent_sosa conf base ip all_gp n get_father)
2133      | _ -> VVstring "" ]
2134  | ["interval"] ->
2135      match gp with
2136      [ GP_interv (Some (n1, n2, Some (n3, n4))) ->
2137          let n2 = Num.sub n2 Num.one in
2138          let n4 = Num.sub n4 Num.one in
2139          let sep = transl conf "(thousand separator)" in
2140          let r =
2141            Num.to_string_sep sep n1 ^ "-" ^ Num.to_string_sep sep n2 ^ " = " ^
2142            Num.to_string_sep sep n3 ^ "-" ^ Num.to_string_sep sep n4
2143          in
2144          VVstring r
2145      | GP_interv (Some (n1, n2, None)) ->
2146          let n2 = Num.sub n2 Num.one in
2147          let sep = transl conf "(thousand separator)" in
2148          let r =
2149            Num.to_string_sep sep n1 ^ "-" ^ Num.to_string_sep sep n2 ^
2150            " = ..."
2151          in
2152          VVstring r
2153      | GP_interv None -> VVstring "..."
2154      | _ -> VVstring "" ]
2155  | ["mother_sosa"] ->
2156      match (gp, get_env "all_gp" env) with
2157      [ (GP_person n ip _ | GP_same n _ ip, Vallgp all_gp) ->
2158          let n = Num.inc (Num.twice n) 1 in
2159          VVstring (parent_sosa conf base ip all_gp n get_mother)
2160      | _ -> VVstring "" ]
2161  | ["same" :: sl] ->
2162      match gp with
2163      [ GP_same _ n _ -> VVstring (eval_num conf n sl)
2164      | _ -> VVstring "" ]
2165  | ["anc_sosa" :: sl] ->
2166      match gp with
2167      [ GP_person n _ _ | GP_same n _ _ -> VVstring (eval_num conf n sl)
2168      | _ -> VVstring "" ]
2169  | ["spouse" :: sl] ->
2170      match gp with
2171      [ GP_person _ ip (Some ifam) ->
2172          let ip = Gutil.spouse ip (foi base ifam) in
2173          let ep = make_ep conf base ip in
2174          eval_person_field_var conf base env ep loc sl
2175      | _ -> raise Not_found ]
2176  | sl ->
2177      match gp with
2178      [ GP_person _ ip _ | GP_same _ _ ip ->
2179          let ep = make_ep conf base ip in
2180          eval_person_field_var conf base env ep loc sl
2181      | _ -> raise Not_found ] ]
2182and eval_anc_by_surnl_field_var conf base env ep info =
2183  match info with
2184  [ Branch (s, db, de, place, p, sosa_list, loc) ->
2185      fun
2186      [ ["date_begin" :: sl] ->
2187          match db with
2188          [ Some d -> eval_date_field_var conf d sl
2189          | None -> VVstring "" ]
2190      | ["date_end" :: sl] ->
2191          match de with
2192          [ Some d -> eval_date_field_var conf d sl
2193          | None -> VVstring "" ]
2194      | ["nb_times"] -> VVstring (string_of_int (List.length sosa_list))
2195      | ["place"] -> VVstring (Util.string_of_place conf place)
2196      | ["sosa_access"] ->
2197          let (str, _) =
2198            List.fold_right
2199              (fun sosa (str, n) ->
2200                 let str =
2201                   str ^ ";s" ^ string_of_int n ^ "=" ^ Num.to_string sosa
2202                 in
2203                 (str, n + 1))
2204              sosa_list ("", 1)
2205          in
2206          let (p, _) = ep in
2207          VVstring (acces_n conf base "1" p ^ str)
2208      | sl ->
2209          let ep = make_ep conf base (get_key_index p) in
2210          eval_person_field_var conf base env ep loc sl ]
2211  | Eclair (s, place, db, de, p, persl, loc) ->
2212      fun
2213      [ ["date_begin" :: sl] ->
2214          match db with
2215          [ Some d -> eval_date_field_var conf d sl
2216          | None -> VVstring "" ]
2217      | ["date_end" :: sl] ->
2218          match de with
2219          [ Some d -> eval_date_field_var conf d sl
2220          | None -> VVstring "" ]
2221      | ["nb_events"] -> VVstring (string_of_int (List.length persl))
2222      | ["nb_ind"] ->
2223          let list =
2224            IperSet.elements
2225              (List.fold_right IperSet.add persl IperSet.empty)
2226          in
2227          VVstring (string_of_int (List.length list))
2228      | ["place"] -> VVstring place
2229      | sl ->
2230          let ep = make_ep conf base (get_key_index p) in
2231          eval_person_field_var conf base env ep loc sl ] ]
2232and eval_num conf n =
2233  fun
2234  [ ["hexa"] -> "0x" ^ Num.to_string_sep_base "" 16 n
2235  | ["octal"] -> "0o" ^ Num.to_string_sep_base "" 8 n
2236  | ["v"] -> Num.to_string n
2237  | [] -> Num.to_string_sep (transl conf "(thousand separator)") n
2238  | _ -> raise Not_found ]
2239and eval_person_field_var conf base env ((p, p_auth) as ep) loc =
2240  fun
2241  [ ["baptism_date" :: sl] ->
2242      match Adef.od_of_codate (get_baptism p) with
2243      [ Some d when p_auth -> eval_date_field_var conf d sl
2244      | _ -> VVstring "" ]
2245  | ["birth_date" :: sl] ->
2246      match Adef.od_of_codate (get_birth p) with
2247      [ Some d when p_auth -> eval_date_field_var conf d sl
2248      | _ -> VVstring "" ]
2249  | ["burial_date" :: sl] ->
2250      match get_burial p with
2251      [ Buried cod when p_auth ->
2252          match Adef.od_of_codate cod with
2253          [ Some d -> eval_date_field_var conf d sl
2254          | None -> VVstring "" ]
2255      | _ -> VVstring "" ]
2256  | ["cremated_date" :: sl] ->
2257      match get_burial p with
2258      [ Cremated cod when p_auth ->
2259          match Adef.od_of_codate cod with
2260          [ Some d -> eval_date_field_var conf d sl
2261          | None -> VVstring "" ]
2262      | _ -> VVstring "" ]
2263  | ["death_date" :: sl] ->
2264      match get_death p with
2265      [ Death _ cd when p_auth ->
2266          eval_date_field_var conf (Adef.date_of_cdate cd) sl
2267      | _ -> VVstring "" ]
2268  | ["father" :: sl] ->
2269      match get_parents p with
2270      [ Some ifam ->
2271          let cpl = foi base ifam in
2272          let ep = make_ep conf base (get_father cpl) in
2273          eval_person_field_var conf base env ep loc sl
2274      | None ->
2275          warning_use_has_parents_before_parent loc "father" (str_val "") ]
2276  | ["has_linked_page"; s] ->
2277      match get_env "nldb" env with
2278      [ Vnldb db ->
2279          let key =
2280            let fn = Name.lower (sou base (get_first_name p)) in
2281            let sn = Name.lower (sou base (get_surname p)) in
2282            (fn, sn, get_occ p)
2283          in
2284          let r =
2285            List.exists
2286              (fun (pg, (_, il)) ->
2287                 match pg with
2288                 [ NotesLinks.PgMisc pg ->
2289                     if List.mem_assoc key il then
2290                       let (nenv, _) = Notes.read_notes base pg in
2291                       List.mem_assoc s nenv
2292                     else False
2293                 | _ -> False ])
2294              db
2295          in
2296          VVbool r
2297      | _ -> raise Not_found ]
2298  | ["has_linked_pages"] ->
2299      match get_env "nldb" env with
2300      [ Vnldb db ->
2301          let r =
2302            if p_auth then
2303              let key =
2304                let fn = Name.lower (sou base (get_first_name p)) in
2305                let sn = Name.lower (sou base (get_surname p)) in
2306                (fn, sn, get_occ p)
2307              in
2308              links_to_ind conf base db key <> []
2309            else False
2310          in
2311          VVbool r
2312      | _ -> raise Not_found ]
2313  | ["has_sosa"] ->
2314      match get_env "sosa" env with
2315      [ Vsosa r -> VVbool (get_sosa conf base env r p <> None)
2316      | _ -> VVbool False ]
2317  | ["linked_page"; s] ->
2318      match get_env "nldb" env with
2319      [ Vnldb db ->
2320          let key =
2321            let fn = Name.lower (sou base (get_first_name p)) in
2322            let sn = Name.lower (sou base (get_surname p)) in
2323            (fn, sn, get_occ p)
2324          in
2325          let s = List.fold_left (linked_page_text conf base p s key) "" db in
2326          VVstring s
2327      | _ -> raise Not_found ]
2328  | ["marriage_date" :: sl] ->
2329      match get_env "fam" env with
2330      [ Vfam _ fam _ True ->
2331          match Adef.od_of_codate (get_marriage fam) with
2332          [ Some d -> eval_date_field_var conf d sl
2333          | None -> VVstring "" ]
2334      | _ -> raise Not_found ]
2335  | ["mother" :: sl] ->
2336      match get_parents p with
2337      [ Some ifam ->
2338          let cpl = foi base ifam in
2339          let ep = make_ep conf base (get_mother cpl) in
2340          eval_person_field_var conf base env ep loc sl
2341      | None ->
2342          warning_use_has_parents_before_parent loc "mother" (str_val "") ]
2343  | ["nobility_title" :: sl] ->
2344      match Util.main_title conf base p with
2345      [ Some t when p_auth ->
2346          let id = sou base t.t_ident in
2347          let pl = sou base t.t_place in
2348          eval_nobility_title_field_var (id, pl) sl
2349      | _ -> VVstring "" ]
2350  | ["self" :: sl] ->
2351      eval_person_field_var conf base env ep loc sl
2352  | ["sosa" :: sl] ->
2353      match get_env "sosa" env with
2354      [ Vsosa x ->
2355          match get_sosa conf base env x p with
2356          [ Some (n, p) -> VVstring (eval_num conf n sl)
2357          | None -> VVstring "" ]
2358      | _ -> raise Not_found ]
2359  | ["spouse" :: sl] ->
2360      match get_env "fam" env with
2361      [ Vfam ifam fam _ _ ->
2362          let cpl = foi base ifam in
2363          let ip = Gutil.spouse (get_key_index p) cpl in
2364          let ep = make_ep conf base ip in
2365          eval_person_field_var conf base env ep loc sl
2366      | _ -> raise Not_found ]
2367  | ["var"] -> VVother (eval_person_field_var conf base env ep loc)
2368  | [s] ->
2369      try bool_val (eval_bool_person_field conf base env ep s) with
2370      [ Not_found ->
2371          try str_val (eval_str_person_field conf base env ep s) with
2372          [ Not_found -> obsolete_eval conf base env ep loc s ] ]
2373  | [] -> str_val (simple_person_text conf base p p_auth)
2374  | _ -> raise Not_found ]
2375and eval_date_field_var conf d =
2376  fun
2377  [ ["prec"] ->
2378      match d with
2379      [ Dgreg dmy  _ -> VVstring (quote_escaped (Date.prec_text conf dmy))
2380      | _ -> VVstring "" ]
2381  | ["day"] ->
2382      match d with
2383      [ Dgreg dmy _ -> VVstring (Date.day_text dmy)
2384      | _ -> VVstring "" ]
2385  | ["month"] ->
2386      match d with
2387      [ Dgreg dmy _ -> VVstring (Date.month_text dmy)
2388      | _ -> VVstring "" ]
2389  | ["year"] ->
2390      match d with
2391      [ Dgreg dmy _ -> VVstring (Date.year_text dmy)
2392      | _ -> VVstring "" ]
2393  | _ -> raise Not_found ]
2394and eval_nobility_title_field_var (id, pl) =
2395  fun
2396  [ ["ident_key"] -> VVstring (code_varenv id)
2397  | ["place_key"] -> VVstring (code_varenv pl)
2398  | [] -> VVstring (if pl = "" then id else id ^ " " ^ pl)
2399  | _ -> raise Not_found ]
2400and eval_bool_person_field conf base env (p, p_auth) =
2401  fun
2402  [ "access_by_key" ->
2403      Util.accessible_by_key conf base p (p_first_name base p)
2404        (p_surname base p)
2405  | "birthday" ->
2406      match (p_auth, Adef.od_of_codate (get_birth p)) with
2407      [ (True, Some (Dgreg d _)) ->
2408          if d.prec = Sure && get_death p = NotDead then
2409            d.day = conf.today.day && d.month = conf.today.month &&
2410            d.year < conf.today.year ||
2411            not (CheckItem.leap_year conf.today.year) &&
2412              d.day = 29 && d.month = 2 &&
2413            conf.today.day = 1 && conf.today.month = 3
2414          else False
2415      | _ -> False ]
2416  | "wedding_birthday" ->
2417      match get_env "fam" env with
2418      [ Vfam _ fam _ m_auth ->
2419          match (get_relation fam, get_divorce fam) with
2420          [ (Married | NoSexesCheckMarried, NotDivorced) ->
2421              match (m_auth, Adef.od_of_codate (get_marriage fam)) with
2422              [ (True, Some (Dgreg d _)) ->
2423                let father = pget conf base (get_father fam) in
2424                let mother = pget conf base (get_mother fam) in
2425                if d.prec = Sure && authorized_age conf base father
2426                  && get_death father = NotDead
2427                  && authorized_age conf base mother
2428                  && get_death mother = NotDead then
2429                    (d.day = conf.today.day && d.month = conf.today.month &&
2430                    d.year < conf.today.year) ||
2431                    (not (CheckItem.leap_year conf.today.year) &&
2432                    d.day = 29 && d.month = 2 &&
2433                    conf.today.day = 1 && conf.today.month = 3)
2434                else False
2435              | _ -> False ]
2436          | _ -> False ]
2437      | _ -> False ]
2438  | "computable_age" ->
2439      if p_auth then
2440        match (Adef.od_of_codate (get_birth p), get_death p) with
2441        [ (Some (Dgreg d _), NotDead) ->
2442            not (d.day = 0 && d.month = 0 && d.prec <> Sure)
2443        | _ -> False ]
2444      else False
2445  | "computable_death_age" ->
2446      if p_auth then
2447        match Date.get_birth_death_date p with
2448        [ (Some (Dgreg ({prec = Sure | About | Maybe} as d1) _),
2449           Some (Dgreg ({prec = Sure | About | Maybe} as d2) _), approx)
2450          when d1 <> d2 ->
2451            let a = CheckItem.time_elapsed d1 d2 in
2452            a.year > 0 ||
2453            a.year = 0 && (a.month > 0 || a.month = 0 && a.day > 0)
2454        | _ -> False ]
2455      else False
2456  | "computable_marriage_age" ->
2457      match get_env "fam" env with
2458      [ Vfam _ fam _ m_auth ->
2459          if m_auth then
2460            match (Adef.od_of_codate (get_birth p),
2461                   Adef.od_of_codate (get_marriage fam))
2462            with
2463            [ (Some (Dgreg ({prec = Sure | About | Maybe} as d1) _),
2464               Some (Dgreg ({prec = Sure | About | Maybe} as d2) _)) ->
2465                let a = CheckItem.time_elapsed d1 d2 in
2466                (a.year > 0 ||
2467                   a.year = 0 && (a.month > 0 || a.month = 0 && a.day > 0))
2468            | _ -> False ]
2469          else False
2470      | _ -> raise Not_found ]
2471  | "has_aliases" ->
2472      if not p_auth && (is_hide_names conf p) then False
2473      else get_aliases p <> []
2474  | "has_baptism_date" -> p_auth && get_baptism p <> Adef.codate_None
2475  | "has_baptism_place" -> p_auth && sou base (get_baptism_place p) <> ""
2476  | "has_birth_date" -> p_auth && get_birth p <> Adef.codate_None
2477  | "has_birth_place" -> p_auth && sou base (get_birth_place p) <> ""
2478  | "has_burial_date" ->
2479      if p_auth then
2480        match get_burial p with
2481        [ Buried cod -> Adef.od_of_codate cod <> None
2482        | _ -> False ]
2483      else False
2484  | "has_burial_place" -> p_auth && sou base (get_burial_place p) <> ""
2485  | "has_children" ->
2486      match get_env "fam" env with
2487      [ Vfam _ fam _ _ -> Array.length (get_children fam) > 0
2488      | _ ->
2489          List.exists
2490            (fun ifam ->
2491             let des = foi base ifam in Array.length (get_children des) > 0)
2492          (Array.to_list (get_family p)) ]
2493  | "has_consanguinity" ->
2494      p_auth && get_consang p != Adef.fix (-1) &&
2495        get_consang p >= Adef.fix_of_float 0.0001
2496  | "has_cremation_date" ->
2497      if p_auth then
2498        match get_burial p with
2499        [ Cremated cod -> Adef.od_of_codate cod <> None
2500        | _ -> False ]
2501      else False
2502  | "has_cremation_place" -> p_auth && sou base (get_burial_place p) <> ""
2503  | "has_death_date" ->
2504      match get_death p with
2505      [ Death _ _ -> p_auth
2506      | _ -> False ]
2507  | "has_death_place" -> p_auth && sou base (get_death_place p) <> ""
2508  | "has_families" -> Array.length (get_family p) > 0
2509  | "has_first_names_aliases" ->
2510      if not p_auth && (is_hide_names conf p) then False
2511      else get_first_names_aliases p <> []
2512  | "has_history" ->
2513      let fn = sou base (get_first_name p) in
2514      let sn = sou base (get_surname p) in
2515      let occ = get_occ p in
2516      let person_file = History_diff.history_file fn sn occ in
2517      p_auth && (Sys.file_exists (History_diff.history_path conf person_file))
2518  | "has_image" -> Util.has_image conf base p
2519  | "has_nephews_or_nieces" -> has_nephews_or_nieces conf base p
2520  | "has_nobility_titles" -> p_auth && nobtit conf base p <> []
2521  | "has_notes" -> p_auth && not conf.no_note && sou base (get_notes p) <> ""
2522  | "has_occupation" -> p_auth && sou base (get_occupation p) <> ""
2523  | "has_parents" -> get_parents p <> None
2524  | "has_possible_duplications" -> has_possible_duplications conf base p
2525  | "has_public_name" ->
2526      if not p_auth && (is_hide_names conf p) then False
2527      else sou base (get_public_name p) <> ""
2528  | "has_qualifiers" ->
2529      if not p_auth && (is_hide_names conf p) then False
2530      else get_qualifiers p <> []
2531  | "has_relations" ->
2532      if p_auth && conf.use_restrict then
2533        let related =
2534          List.fold_left
2535            (fun l ip ->
2536               let rp = pget conf base ip in
2537               if is_hidden rp then l else [ip :: l])
2538          [] (get_related p)
2539        in
2540        get_rparents p <> [] || related <> []
2541      else p_auth && (get_rparents p <> [] || get_related p <> [])
2542  | "has_siblings" ->
2543      match get_parents p with
2544      [ Some ifam -> Array.length (get_children (foi base ifam)) > 1
2545      | None -> False ]
2546  | "has_sources" ->
2547      p_auth &&
2548      (sou base (get_psources p) <> "" ||
2549       sou base (get_birth_src p) <> "" ||
2550       sou base (get_baptism_src p) <> "" ||
2551       sou base (get_death_src p) <> "" ||
2552       sou base (get_burial_src p) <> "" ||
2553       List.exists
2554         (fun ifam ->
2555           let fam = foi base ifam in
2556           let isp = Gutil.spouse (get_key_index p) fam in
2557           let sp = poi base isp in
2558           (* On sait que p_auth vaut vrai. *)
2559           let m_auth = authorized_age conf base sp in
2560           m_auth &&
2561           (sou base (get_marriage_src fam) <> "" ||
2562           sou base (get_fsources fam) <> ""))
2563         (Array.to_list (get_family p)))
2564  | "has_surnames_aliases" ->
2565      if not p_auth && (is_hide_names conf p) then False
2566      else get_surnames_aliases p <> []
2567  | "is_buried" ->
2568      match get_burial p with
2569      [ Buried _ -> p_auth
2570      | _ -> False ]
2571  | "is_cremated" ->
2572      match get_burial p with
2573      [ Cremated _ -> p_auth
2574      | _ -> False ]
2575  | "is_dead" ->
2576      match get_death p with
2577      [ Death _ _ | DeadYoung | DeadDontKnowWhen -> p_auth
2578      | _ -> False ]
2579  | "is_descendant" ->
2580      match get_env "desc_mark" env with
2581      [ Vdmark r -> r.val.(Adef.int_of_iper (get_key_index p))
2582      | _ -> raise Not_found ]
2583  | "is_female" -> get_sex p = Female
2584  | "is_invisible" ->
2585      let conf = {(conf) with wizard = False; friend = False} in
2586      not (authorized_age conf base p)
2587  | "is_male" -> get_sex p = Male
2588  | "is_private" -> get_access p = Private
2589  | "is_public" -> get_access p = Public
2590  | "is_restricted" -> is_hidden p
2591  | _ -> raise Not_found ]
2592and eval_str_person_field conf base env ((p, p_auth) as ep) =
2593  fun
2594  [ "access" -> acces conf base p
2595  | "age" ->
2596      match (p_auth, Adef.od_of_codate (get_birth p), get_death p) with
2597      [ (True, Some (Dgreg d _), NotDead) ->
2598          let a = CheckItem.time_elapsed d conf.today in
2599          Date.string_of_age conf a
2600      | _ -> "" ]
2601  | "alias" ->
2602      match get_aliases p with
2603      [ [nn :: _] ->
2604          if not p_auth && (is_hide_names conf p) then ""
2605          else sou base nn
2606      | _ -> "" ]
2607  | "auto_image_file_name" ->
2608      match auto_image_file conf base p with
2609      [ Some s when p_auth -> s
2610      | _ -> "" ]
2611  | "birth_place" ->
2612      if p_auth then Util.string_of_place conf (sou base (get_birth_place p))
2613      else ""
2614  | "baptism_place" ->
2615      if p_auth then Util.string_of_place conf (sou base (get_baptism_place p))
2616      else ""
2617  | "burial_place" ->
2618      if p_auth then Util.string_of_place conf (sou base(get_burial_place p))
2619      else ""
2620  | "child_name" ->
2621      let force_surname =
2622        match get_parents p with
2623        [ None -> False
2624        | Some ifam ->
2625            p_surname base (pget conf base (get_father (foi base ifam))) <>
2626              p_surname base p ]
2627      in
2628      if not p_auth && (is_hide_names conf p) then "x x"
2629      else if force_surname then person_text conf base p
2630      else person_text_no_surn_no_acc_chk conf base p
2631  | "consanguinity" ->
2632      if p_auth then
2633        string_of_decimal_num conf
2634          (round_2_dec (Adef.float_of_fix (get_consang p) *. 100.0)) ^ "%"
2635      else ""
2636  | "cremation_place" ->
2637      if p_auth then Util.string_of_place conf (sou base (get_burial_place p))
2638      else ""
2639  | "dates" ->
2640      if p_auth then Date.short_dates_text conf base p else ""
2641  | "death_age" ->
2642      if p_auth then
2643        match Date.get_birth_death_date p with
2644        [ (Some (Dgreg ({prec = Sure | About | Maybe} as d1) _),
2645           Some (Dgreg ({prec = Sure | About | Maybe} as d2) _), approx)
2646          when d1 <> d2 ->
2647            let a = CheckItem.time_elapsed d1 d2 in
2648            let s =
2649              if not approx && d1.prec = Sure && d2.prec = Sure then ""
2650              else transl_decline conf "possibly (date)" "" ^ " "
2651            in
2652            s ^ Date.string_of_age conf a
2653        | _ -> "" ]
2654      else ""
2655  | "death_place" ->
2656      if p_auth then Util.string_of_place conf (sou base (get_death_place p))
2657      else ""
2658  | "died" -> string_of_died conf base env p p_auth
2659  | "fam_access" ->
2660      (* deprecated since 5.00: rather use "i=%family.index;;ip=%index;" *)
2661      match get_env "fam" env with
2662      [ Vfam ifam _ _ _ ->
2663          Printf.sprintf "i=%d;ip=%d" (Adef.int_of_ifam ifam)
2664            (Adef.int_of_iper (get_key_index p))
2665      | _ -> raise Not_found ]
2666  | "father_age_at_birth" -> string_of_parent_age conf base ep get_father
2667  | "first_name" ->
2668      if not p_auth && (is_hide_names conf p) then "x" else p_first_name base p
2669  | "first_name_key" ->
2670      if (is_hide_names conf p) && not p_auth then ""
2671      else code_varenv (Name.lower (p_first_name base p))
2672  | "first_name_key_val" ->
2673      if (is_hide_names conf p) && not p_auth then ""
2674      else Name.lower (p_first_name base p)
2675  | "first_name_key_strip" ->
2676      if (is_hide_names conf p) && not p_auth then ""
2677      else Name.strip_c (p_first_name base p) '"'
2678  | "history_file" ->
2679      if not p_auth then ""
2680      else
2681        let fn = sou base (get_first_name p) in
2682        let sn = sou base (get_surname p) in
2683        let occ = get_occ p in
2684        History_diff.history_file fn sn occ
2685  | "image" -> if not p_auth then "" else sou base (get_image p)
2686  | "image_html_url" -> string_of_image_url conf base env ep True
2687  | "image_size" -> string_of_image_size conf base env ep
2688  | "image_medium_size" -> string_of_image_medium_size conf base env ep
2689  | "image_small_size" -> string_of_image_small_size conf base env ep
2690  | "image_url" -> string_of_image_url conf base env ep False
2691  | "ind_access" ->
2692      (* deprecated since 5.00: rather use "i=%index;" *)
2693      "i=" ^ string_of_int (Adef.int_of_iper (get_key_index p))
2694  | "index" -> string_of_int (Adef.int_of_iper (get_key_index p))
2695  | "mark_descendants" ->
2696      match get_env "desc_mark" env with
2697      [ Vdmark r ->
2698          let tab = Array.make (nb_of_persons base) False in
2699          let rec mark_descendants len p =
2700            let i = Adef.int_of_iper (get_key_index p) in
2701            if tab.(i) then ()
2702            else do {
2703              tab.(i) := True;
2704              let u = p in
2705              for i = 0 to Array.length (get_family u) - 1 do {
2706                let des = foi base (get_family u).(i) in
2707                for i = 0 to Array.length (get_children des) - 1 do {
2708                  mark_descendants (len + 1)
2709                  (pget conf base (get_children des).(i))
2710                }
2711              }
2712            }
2713          in
2714          do {
2715            mark_descendants 0 p;
2716            r.val := tab;
2717            "";
2718          }
2719      | _ -> raise Not_found ]
2720  | "marriage_age" ->
2721      match get_env "fam" env with
2722      [ Vfam _ fam _ m_auth ->
2723          if m_auth then
2724            match (Adef.od_of_codate (get_birth p),
2725                   Adef.od_of_codate (get_marriage fam))
2726            with
2727            [ (Some (Dgreg ({prec = Sure | About | Maybe} as d1) _),
2728               Some (Dgreg ({prec = Sure | About | Maybe} as d2) _)) ->
2729                let a = CheckItem.time_elapsed d1 d2 in
2730                Date.string_of_age conf a
2731            | _ -> "" ]
2732          else ""
2733      | _ -> raise Not_found ]
2734  | "mother_age_at_birth" -> string_of_parent_age conf base ep get_mother
2735  | "misc_names" ->
2736      if p_auth then
2737        let list = Gwdb.person_misc_names base p (Util.nobtit conf base) in
2738        let list =
2739          let first_name = p_first_name base p in
2740          let surname = p_surname base p in
2741          if first_name <> "?" && surname <> "?" then
2742            [Name.lower (first_name ^ " " ^ surname) :: list]
2743          else list
2744        in
2745        if list <> [] then
2746          "<ul>\n" ^
2747          List.fold_left (fun s n -> s ^ "<li>" ^ n ^ "</li>\n") "" list ^
2748          "</ul>\n"
2749        else ""
2750      else ""
2751  | "nb_children" ->
2752      match get_env "fam" env with
2753      [ Vfam _ fam _ _ -> string_of_int (Array.length (get_children fam))
2754      | _ ->
2755          let n =
2756            List.fold_left
2757              (fun n ifam ->
2758                 n + Array.length (get_children (foi base ifam)))
2759              0 (Array.to_list (get_family p))
2760          in
2761          string_of_int n ]
2762  | "nb_families" -> string_of_int (Array.length (get_family p))
2763  | "notes" ->
2764      if p_auth && not conf.no_note then
2765        let env = [('i', fun () -> Util.default_image_name base p)] in
2766        let s = sou base (get_notes p) in
2767        let s = string_with_macros conf env s in
2768        let lines = Wiki.html_of_tlsw conf s in
2769        let wi =
2770          {Wiki.wi_mode = "NOTES"; Wiki.wi_cancel_links = conf.cancel_links;
2771           Wiki.wi_file_path = Notes.file_path conf base;
2772           Wiki.wi_person_exists = person_exists conf base;
2773           Wiki.wi_always_show_link = conf.wizard || conf.friend}
2774        in
2775        let s = Wiki.syntax_links conf wi (String.concat "\n" lines) in
2776        if conf.pure_xhtml then Util.check_xhtml s else s
2777      else ""
2778  | "occ" ->
2779      if (is_hide_names conf p) && not p_auth then ""
2780      else string_of_int (get_occ p)
2781  | "occupation" ->
2782      if p_auth then
2783        let s = sou base (get_occupation p) in
2784        let s =
2785          let wi =
2786            {Wiki.wi_mode = "NOTES"; Wiki.wi_cancel_links = conf.cancel_links;
2787             Wiki.wi_file_path = Notes.file_path conf base;
2788             Wiki.wi_person_exists = person_exists conf base;
2789             Wiki.wi_always_show_link = conf.wizard || conf.friend}
2790          in
2791          Wiki.syntax_links conf wi s
2792        in
2793        string_with_macros conf [] s
2794      else ""
2795  | "on_baptism_date" ->
2796      match (p_auth, Adef.od_of_codate (get_baptism p)) with
2797      [ (True, Some d) ->
2798          match p_getenv conf.base_env "long_date" with
2799          [ Some "yes" -> (Date.string_of_ondate conf d) ^ (Date.get_wday conf d)
2800          | _ -> Date.string_of_ondate conf d ]
2801      | _ -> "" ]
2802  | "slash_baptism_date" ->
2803      match (p_auth, Adef.od_of_codate (get_baptism p)) with
2804      [ (True, Some d) -> Date.string_slash_of_date conf d
2805      | _ -> "" ]
2806  | "on_birth_date" ->
2807      match (p_auth, Adef.od_of_codate (get_birth p)) with
2808      [ (True, Some d) ->
2809          match p_getenv conf.base_env "long_date" with
2810          [ Some "yes" -> (Date.string_of_ondate conf d) ^ (Date.get_wday conf d)
2811          | _ -> Date.string_of_ondate conf d ]
2812      | _ -> "" ]
2813  | "slash_birth_date" ->
2814      match (p_auth, Adef.od_of_codate (get_birth p)) with
2815      [ (True, Some d) -> Date.string_slash_of_date conf d
2816      | _ -> "" ]
2817  | "on_burial_date" ->
2818      match get_burial p with
2819      [ Buried cod ->
2820          match (p_auth, Adef.od_of_codate cod) with
2821          [ (True, Some d) ->
2822              match p_getenv conf.base_env "long_date" with
2823              [ Some "yes" -> (Date.string_of_ondate conf d) ^ (Date.get_wday conf d)
2824              | _ -> Date.string_of_ondate conf d ]
2825          | _ -> "" ]
2826      | _ -> raise Not_found ]
2827  | "slash_burial_date" ->
2828      match get_burial p with
2829      [ Buried cod ->
2830          match (p_auth, Adef.od_of_codate cod) with
2831          [ (True, Some d) -> Date.string_slash_of_date conf d
2832          | _ -> "" ]
2833      | _ -> raise Not_found ]
2834  | "on_cremation_date" ->
2835      match get_burial p with
2836      [ Cremated cod ->
2837          match (p_auth, Adef.od_of_codate cod) with
2838          [ (True, Some d) ->
2839              match p_getenv conf.base_env "long_date" with
2840              [ Some "yes" -> (Date.string_of_ondate conf d) ^ (Date.get_wday conf d)
2841              | _ -> Date.string_of_ondate conf d ]
2842          | _ -> "" ]
2843      | _ -> raise Not_found ]
2844  | "slash_cremation_date" ->
2845      match get_burial p with
2846      [ Cremated cod ->
2847          match (p_auth, Adef.od_of_codate cod) with
2848          [ (True, Some d) -> Date.string_slash_of_date conf d
2849          | _ -> "" ]
2850      | _ -> raise Not_found ]
2851  | "on_death_date" ->
2852      match (p_auth, get_death p) with
2853      [ (True, Death _ d) ->
2854          let d = Adef.date_of_cdate d in
2855          match p_getenv conf.base_env "long_date" with
2856          [ Some "yes" -> (Date.string_of_ondate conf d) ^ (Date.get_wday conf d)
2857          | _ -> Date.string_of_ondate conf d ]
2858      | _ -> "" ]
2859  | "slash_death_date" ->
2860      match (p_auth, get_death p) with
2861      [ (True, Death _ d) ->
2862          let d = Adef.date_of_cdate d in
2863          Date.string_slash_of_date conf d
2864      | _ -> "" ]
2865  | "prev_fam_father" ->
2866      match get_env "prev_fam" env with
2867      [ Vfam _ fam (ifath, _, _) _ -> string_of_int (Adef.int_of_iper ifath)
2868      | _ -> raise Not_found ]
2869  | "prev_fam_index" ->
2870      match get_env "prev_fam" env with
2871      [ Vfam ifam _ _ _ -> string_of_int (Adef.int_of_ifam ifam)
2872      | _ -> raise Not_found ]
2873  | "prev_fam_mother" ->
2874      match get_env "prev_fam" env with
2875      [ Vfam _ fam (_, imoth, _) _ -> string_of_int (Adef.int_of_iper imoth)
2876      | _ -> raise Not_found ]
2877  | "public_name" ->
2878      if not p_auth && (is_hide_names conf p) then ""
2879      else sou base (get_public_name p)
2880  | "qualifier" ->
2881      match get_qualifiers p with
2882      [ [nn :: _] ->
2883          if not p_auth && (is_hide_names conf p) then ""
2884          else sou base nn
2885      | _ -> "" ]
2886  | "sex" ->
2887      (* Pour éviter les traductions bizarre, on ne teste pas p_auth. *)
2888      string_of_int (index_of_sex (get_sex p))
2889  | "sosa_in_list" ->
2890      match get_env "all_gp" env with
2891      [ Vallgp all_gp ->
2892          match get_link all_gp (get_key_index p) with
2893          [ Some (GP_person s _ _) -> Num.to_string s
2894          | _ -> "" ]
2895      | _ -> raise Not_found ]
2896  | "sosa_link" ->
2897      match get_env "sosa" env with
2898      [ Vsosa x ->
2899          match get_sosa conf base env x p with
2900          [ Some (n, q) ->
2901              Printf.sprintf "m=RL;i1=%d;i2=%d;b1=1;b2=%s"
2902                (Adef.int_of_iper (get_key_index p))
2903                (Adef.int_of_iper (get_key_index q))
2904                (Num.to_string n)
2905          | None -> "" ]
2906      | _ -> raise Not_found ]
2907  | "source" ->
2908      match get_env "src" env with
2909      [ Vstring s ->
2910          let env = [('i', fun () -> Util.default_image_name base p)] in
2911          let s =
2912            let wi =
2913              {Wiki.wi_mode = "NOTES";
2914               Wiki.wi_cancel_links = conf.cancel_links;
2915               Wiki.wi_file_path = Notes.file_path conf base;
2916               Wiki.wi_person_exists = person_exists conf base;
2917               Wiki.wi_always_show_link = conf.wizard || conf.friend}
2918            in
2919            Wiki.syntax_links conf wi s
2920          in
2921          string_with_macros conf env s
2922      | _ -> raise Not_found ]
2923  | "surname" ->
2924      if not p_auth && (is_hide_names conf p) then "x" else p_surname base p
2925  | "surname_begin" ->
2926      if not p_auth && (is_hide_names conf p) then ""
2927      else surname_begin base (p_surname base p)
2928  | "surname_end" ->
2929      if not p_auth && (is_hide_names conf p) then "x"
2930      else surname_end base (p_surname base p)
2931  | "surname_key" ->
2932      if (is_hide_names conf p) && not p_auth then ""
2933      else code_varenv (Name.lower (p_surname base p))
2934  | "surname_key_val" ->
2935      if (is_hide_names conf p) && not p_auth then ""
2936      else Name.lower (p_surname base p)
2937  | "surname_key_strip" ->
2938      if (is_hide_names conf p) && not p_auth then ""
2939      else Name.strip_c (p_surname base p) '"'
2940  | "title" -> person_title conf base p
2941  | _ -> raise Not_found ]
2942and eval_witness_relation_var conf base env
2943  ((_, fam, (ip1, ip2, _), m_auth) as fcd) loc =
2944  fun
2945  [ [] ->
2946      if not m_auth then VVstring ""
2947      else
2948        let s =
2949          Printf.sprintf
2950            (ftransl conf "witness at marriage of %s and %s")
2951            (referenced_person_title_text conf base (pget conf base ip1))
2952            (referenced_person_title_text conf base (pget conf base ip2))
2953        in
2954        VVstring s
2955  | sl -> eval_family_field_var conf base env fcd loc sl ]
2956and eval_family_field_var conf base env
2957  ((ifam, fam, (ifath, imoth, _), m_auth) as fcd) loc
2958=
2959  fun
2960  [ ["father" :: sl] ->
2961      let ep = make_ep conf base ifath in
2962      eval_person_field_var conf base env ep loc sl
2963  | ["marriage_date" :: sl] ->
2964      match Adef.od_of_codate (get_marriage fam) with
2965      [ Some d when m_auth -> eval_date_field_var conf d sl
2966      | _ -> VVstring "" ]
2967  | ["mother" :: sl] ->
2968      let ep = make_ep conf base imoth in
2969      eval_person_field_var conf base env ep loc sl
2970  | [s] -> str_val (eval_str_family_field conf base env fcd loc s)
2971  | _ -> raise Not_found ]
2972and eval_str_family_field conf base env (ifam, _, _, _) loc =
2973  fun
2974  [ "desc_level" ->
2975      match get_env "desc_level_table" env with
2976      [ Vdesclevtab levt ->
2977          let (_, flevt) = Lazy.force levt in
2978          string_of_int (flevt.(Adef.int_of_ifam ifam))
2979      | _ -> raise Not_found ]
2980  | "index" -> string_of_int (Adef.int_of_ifam ifam)
2981  | "set_infinite_desc_level" ->
2982      match get_env "desc_level_table" env with
2983      [ Vdesclevtab levt -> do {
2984          let (_, flevt) = Lazy.force levt in
2985          flevt.(Adef.int_of_ifam ifam) := infinite;
2986          ""
2987        }
2988      | _ -> raise Not_found ]
2989  | _ -> raise Not_found ]
2990and simple_person_text conf base p p_auth =
2991  if p_auth then
2992    match main_title conf base p with
2993    [ Some t -> titled_person_text conf base p t
2994    | None -> person_text conf base p ]
2995  else if (is_hide_names conf p) then "x x"
2996  else person_text conf base p
2997and string_of_died conf base env p p_auth =
2998  if p_auth then
2999    let is = index_of_sex (get_sex p) in
3000    match get_death p with
3001    [ Death dr _ ->
3002        match dr with
3003        [ Unspecified -> transl_nth conf "died" is
3004        | Murdered -> transl_nth conf "murdered" is
3005        | Killed -> transl_nth conf "killed (in action)" is
3006        | Executed -> transl_nth conf "executed (legally killed)" is
3007        | Disappeared -> transl_nth conf "disappeared" is ]
3008    | DeadYoung -> transl_nth conf "died young" is
3009    | DeadDontKnowWhen -> transl_nth conf "died" is
3010    | _ -> "" ]
3011  else ""
3012and string_of_image_url conf base env (p, p_auth) html =
3013  if p_auth then
3014    let v =
3015      image_and_size conf base p (limited_image_size max_im_wid max_im_wid)
3016    in
3017    match v with
3018    [ Some (True, fname, _) ->
3019        let s = Unix.stat fname in
3020        let b = acces conf base p in
3021        let k = default_image_name base p in
3022        Format.sprintf "%sm=IM%s;d=%d;%s;k=/%s" (commd conf)
3023          (if html then "H" else "")
3024          (int_of_float
3025             (mod_float s.Unix.st_mtime (float_of_int max_int)))
3026          b k
3027    | Some (False, link, _) -> link
3028    | None -> "" ]
3029  else ""
3030and string_of_parent_age conf base (p, p_auth) parent =
3031  match get_parents p with
3032  [ Some ifam ->
3033      let cpl = foi base ifam in
3034      let pp = pget conf base (parent cpl) in
3035      if p_auth && authorized_age conf base pp then
3036        match
3037          (Adef.od_of_codate (get_birth pp), Adef.od_of_codate (get_birth p))
3038        with
3039        [ (Some (Dgreg d1 _), Some (Dgreg d2 _)) ->
3040            Date.string_of_age conf (CheckItem.time_elapsed d1 d2)
3041        | _ -> "" ]
3042      else ""
3043  | None -> raise Not_found ]
3044and string_of_int_env var env =
3045  match get_env var env with
3046  [ Vint x -> string_of_int x
3047  | _ -> raise Not_found ]
3048and obsolete_eval conf base env (p, p_auth) loc =
3049  fun
3050  [ "married_to" ->
3051      let s =
3052        match get_env "fam" env with
3053        [ Vfam _ fam (_, _, ispouse) m_auth ->
3054           let format = relation_txt conf (get_sex p) fam in
3055           Printf.sprintf (fcapitale format)
3056             (fun _ ->
3057                if m_auth then string_of_marriage_text conf base fam else "")
3058        | _ -> raise Not_found ]
3059      in
3060      obsolete loc "4.08" "married_to" "" (str_val s)
3061  | _ -> raise Not_found ]
3062;
3063
3064value eval_transl conf env upp s c =
3065  match c with
3066  [ "n" | "s" | "w" ->
3067      let n =
3068        match c with
3069        [ "n" ->
3070            (* replaced by %apply;nth([...],sex) *)
3071            match get_env "p" env with
3072            [ Vind p -> 1 - index_of_sex (get_sex p)
3073            | _ -> 2 ]
3074        | "s" ->
3075            match get_env "child" env with
3076            [ Vind p -> index_of_sex (get_sex p)
3077            | _ ->
3078                match get_env "p" env with
3079                [ Vind p -> index_of_sex (get_sex p)
3080                | _ -> 2 ] ]
3081        | "w" ->
3082            match get_env "fam" env with
3083            [ Vfam _ fam _ _ ->
3084                if Array.length (get_witnesses fam) = 1 then 0 else 1
3085            | _ -> 0 ]
3086        | _ -> assert False ]
3087      in
3088      let r = Util.translate_eval (Util.transl_nth conf s n) in
3089      if upp then capitale r else r
3090  | _ ->
3091      Templ.eval_transl conf upp s c ]
3092;
3093
3094value print_foreach conf base print_ast eval_expr =
3095  let eval_int_expr env ep e =
3096    let s = eval_expr env ep e in
3097    try int_of_string s with [ Failure _ -> raise Not_found ]
3098  in
3099  let rec print_foreach env ini_ep loc s sl ell al =
3100    let rec loop ((a, _) as ep) efam =
3101      fun
3102      [ [s] -> print_simple_foreach env ell al ini_ep ep efam loc s
3103      | ["ancestor" :: sl] ->
3104          let ip_ifamo =
3105            match get_env "ancestor" env with
3106            [ Vanc (GP_person _ ip ifamo) -> Some (ip, ifamo)
3107            | Vanc (GP_same _ _ ip) -> Some (ip, None)
3108            | _ -> None ]
3109          in
3110          match ip_ifamo with
3111          [ Some (ip, ifamo) ->
3112              let ep = make_ep conf base ip in
3113              let efam =
3114                match ifamo with
3115                [ Some ifam ->
3116                    let (f, c, a) = make_efam conf base ip ifam in
3117                    Vfam ifam f c a
3118                | None -> efam ]
3119              in
3120              loop ep efam sl
3121          | _ -> raise Not_found ]
3122      | ["child" :: sl] ->
3123          match get_env "child" env with
3124          [ Vind p ->
3125              let auth = authorized_age conf base p in
3126              let ep = (p, auth) in
3127              loop ep efam sl
3128          | _ -> raise Not_found ]
3129      | ["father" :: sl] ->
3130          match get_parents a with
3131          [ Some ifam ->
3132              let cpl = foi base ifam in
3133              let ((_, p_auth) as ep) = make_ep conf base (get_father cpl) in
3134              let ifath = get_father cpl in
3135              let cpl = (ifath, get_mother cpl, ifath) in
3136              let m_auth =
3137                p_auth && authorized_age conf base (pget conf base ifath)
3138              in
3139              let efam = Vfam ifam (foi base ifam) cpl m_auth in
3140              loop ep efam sl
3141          | None ->
3142              warning_use_has_parents_before_parent loc "father" () ]
3143      | ["mother" :: sl] ->
3144          match get_parents a with
3145          [ Some ifam ->
3146              let cpl = foi base ifam in
3147              let ((_, p_auth) as ep) = make_ep conf base (get_mother cpl) in
3148              let ifath = get_father cpl in
3149              let cpl = (ifath, get_mother cpl, ifath) in
3150              let m_auth =
3151                p_auth && authorized_age conf base (pget conf base ifath)
3152              in
3153              let efam = Vfam ifam (foi base ifam) cpl m_auth in
3154              loop ep efam sl
3155          | None ->
3156              warning_use_has_parents_before_parent loc "mother" () ]
3157      | ["self" :: sl] -> loop ep efam sl
3158      | ["spouse" :: sl] ->
3159          match efam with
3160          [ Vfam _ _ (_, _, ip) _ ->
3161              let ep = make_ep conf base ip in
3162              loop ep efam sl
3163          | _ -> raise Not_found ]
3164      | _ -> raise Not_found ]
3165    in
3166    let efam = get_env "fam" env in
3167    loop ini_ep efam [s :: sl]
3168  and print_simple_foreach env el al ini_ep ep efam loc =
3169    fun
3170    [ "alias" -> print_foreach_alias env al ep
3171    | "ancestor" -> print_foreach_ancestor env al ep
3172    | "ancestor_level" -> print_foreach_ancestor_level env el al ep
3173    | "ancestor_level2" -> print_foreach_ancestor_level2 env al ep
3174    | "ancestor_surname" -> print_foreach_anc_surn env el al loc ep
3175    | "ancestor_tree_line" -> print_foreach_ancestor_tree env el al ep
3176    | "cell" -> print_foreach_cell env el al ep
3177    | "child" -> print_foreach_child env al ep efam
3178    | "cousin_level" -> print_foreach_level "max_cous_level" env al ep
3179    | "descendant_level" -> print_foreach_descendant_level env al ep
3180    | "family" -> print_foreach_family env al ini_ep ep
3181    | "first_name_alias" -> print_foreach_first_name_alias env al ep
3182    | "nobility_title" -> print_foreach_nobility_title env al ep
3183    | "parent" -> print_foreach_parent env al ep
3184    | "qualifier" -> print_foreach_qualifier env al ep
3185    | "related" -> print_foreach_related env al ep
3186    | "relation" -> print_foreach_relation env al ep
3187    | "sorted_list_item" -> print_foreach_sorted_list_item env al ep
3188    | "source" -> print_foreach_source env al ep
3189    | "surname_alias" -> print_foreach_surname_alias env al ep
3190    | "witness" -> print_foreach_witness env al ep efam
3191    | "witness_relation" -> print_foreach_witness_relation env al ep
3192    | _ -> raise Not_found ]
3193  and print_foreach_alias env al ((p, p_auth) as ep) =
3194    if not p_auth && (is_hide_names conf p) then ()
3195    else
3196      list_iter_first
3197        (fun first a ->
3198           let env = [("alias", Vstring (sou base a)) :: env] in
3199           let env = [("first", Vbool first) :: env] in
3200           List.iter (print_ast env ep) al)
3201        (get_aliases p)
3202  and print_foreach_ancestor env al ((p, p_auth) as ep) =
3203    match get_env "gpl" env with
3204    [ Vgpl gpl ->
3205        let rec loop first gpl =
3206          match gpl with
3207          [ [] -> ()
3208          | [gp :: gl] -> do {
3209              match gp with
3210              [ GP_missing _ _ -> ()
3211              | _ ->
3212                  let env =
3213                    [("ancestor", Vanc gp);
3214                     ("first", Vbool first); ("last", Vbool (gl = [])) :: env]
3215                  in
3216                  List.iter (print_ast env ep) al ];
3217              loop False gl } ]
3218        in loop True gpl
3219    | _ -> () ]
3220  and print_foreach_ancestor_level env el al ((p, _) as ep) =
3221    let max_level =
3222      match el with
3223      [ [[e]] -> eval_int_expr env ep e
3224      | [] ->
3225          match get_env "max_anc_level" env with
3226          [ Vint n -> n
3227          | _ -> 0 ]
3228      | _ -> raise Not_found ]
3229    in
3230    let mark = Array.make (nb_of_persons base) Num.zero in
3231    loop [GP_person Num.one (get_key_index p) None] 1 0 where rec loop gpl i n =
3232      if i > max_level then ()
3233      else
3234        let n =
3235          List.fold_left
3236            (fun n gp ->
3237               match gp with
3238               [ GP_person _ _ _ -> n + 1
3239               | _ -> n ])
3240            n gpl
3241        in
3242        let env =
3243          [("gpl", Vgpl gpl); ("level", Vint i); ("n", Vint n) :: env]
3244        in
3245        do {
3246          List.iter (print_ast env ep) al;
3247          let gpl = next_generation conf base mark gpl in
3248          loop gpl (succ i) n
3249        }
3250  and print_foreach_ancestor_level2 env al ((p, _) as ep) =
3251    let max_lev = "max_anc_level" in
3252    let max_level =
3253      match get_env max_lev env with
3254      [ Vint n -> n
3255      | _ -> 0 ]
3256    in
3257    let mark = Array.make (nb_of_persons base) Num.zero in
3258    loop [GP_person Num.one (get_key_index p) None] 1 where rec loop gpl i =
3259      if i > max_level then ()
3260      else
3261        let env = [("gpl", Vgpl gpl); ("level", Vint i) :: env] in
3262        do {
3263          List.iter (print_ast env ep) al;
3264          for i = 0 to nb_of_persons base - 1 do { mark.(i) := Num.zero };
3265          let gpl = next_generation2 conf base mark gpl in
3266          loop gpl (succ i)
3267        }
3268  and print_foreach_anc_surn env el al loc ((p, _) as ep) =
3269    let max_level =
3270      match el with
3271      [ [[e]] -> eval_int_expr env ep e
3272      | [] ->
3273          match get_env "max_anc_level" env with
3274          [ Vint n -> n
3275          | _ -> 0 ]
3276      | _ -> raise Not_found ]
3277    in
3278    (* En fonction du type de sortie demandé, on construit *)
3279    (* soit la liste des branches soit la liste éclair.    *)
3280    match p_getenv conf.env "t" with
3281    [ Some "E" ->
3282        let list = build_list_eclair conf base max_level p in
3283        List.iter
3284          (fun (a, b, c, d, e, f) ->
3285             let env =
3286               [("ancestor", Vanc_surn (Eclair (a, b, c, d, e, f, loc))) :: env]
3287             in
3288             List.iter (print_ast env ep) al)
3289          list
3290    | Some "F" ->
3291        let list = build_surnames_list conf base max_level p in
3292        List.iter
3293          (fun (a, (((b, c, d), e), f)) ->
3294             let env =
3295               [("ancestor", Vanc_surn (Branch (a, b, c, d, e, f, loc))) :: env]
3296             in
3297             List.iter (print_ast env ep) al)
3298          list
3299    | _ -> () ]
3300  and print_foreach_ancestor_tree env el al ((p, _) as ep) =
3301    let (p, max_level) =
3302      match el with
3303      [ [[e1]; [e2]] ->
3304          let ip = eval_int_expr env ep e1 in
3305          let max_level = eval_int_expr env ep e2 in
3306          (pget conf base (Adef.iper_of_int ip), max_level)
3307      | [[e]] ->
3308          (p, eval_int_expr env ep e)
3309      | [] ->
3310          match get_env "max_anc_level" env with
3311          [ Vint n -> (p, n)
3312          | _ -> (p, 0) ]
3313      | _ -> raise Not_found ]
3314    in
3315    let gen = tree_generation_list conf base max_level p in
3316    loop True gen where rec loop first =
3317      fun
3318      [ [g :: gl] ->
3319          let env =
3320            [("celll", Vcelll g); ("first", Vbool first);
3321             ("last", Vbool (gl = [])) :: env]
3322          in
3323          do {
3324            List.iter (print_ast env ep) al;
3325            loop False gl
3326          }
3327      | [] -> () ]
3328  and print_foreach_cell env el al ((p, _) as ep) =
3329    let celll =
3330      match get_env "celll" env with
3331      [ Vcelll celll -> celll
3332      | _ -> raise Not_found ]
3333    in
3334    list_iter_first
3335      (fun first cell ->
3336         let env = [("cell", Vcell cell); ("first", Vbool first) :: env] in
3337         List.iter (print_ast env ep) al)
3338      celll
3339  and print_foreach_child env al ep =
3340    fun
3341    [ Vfam _ fam _ _ ->
3342        let auth =
3343          List.for_all
3344            (fun ip -> authorized_age conf base (pget conf base ip))
3345            (Array.to_list (get_children fam))
3346        in
3347        let env = [("auth", Vbool auth) :: env] in
3348        let n =
3349          let p =
3350            match get_env "p" env with
3351            [ Vind p -> p
3352            | _ -> assert False ]
3353          in
3354          let rec loop i =
3355            if i = Array.length (get_children fam) then -2
3356            else if (get_children fam).(i) = get_key_index p then i
3357            else loop (i + 1)
3358          in
3359          loop 0
3360        in
3361        Array.iteri
3362          (fun i ip ->
3363             let p = pget conf base ip in
3364             let env = [("#loop", Vint 0) :: env] in
3365             let env = [("child", Vind p) :: env] in
3366             let env = [("child_cnt", Vint (i + 1)) :: env] in
3367             let env =
3368               if i = n - 1 && not (is_hidden p) then
3369                 [("pos", Vstring "prev") :: env]
3370               else if i = n then [("pos", Vstring "self") :: env]
3371               else if i = n + 1 && not (is_hidden p) then
3372                 [("pos", Vstring "next") :: env]
3373               else env
3374             in
3375             let ep = (p, authorized_age conf base p) in
3376             List.iter (print_ast env ep) al)
3377          (get_children fam)
3378    | _ -> () ]
3379  and print_foreach_descendant_level env al ep =
3380    let max_level =
3381      match get_env "max_desc_level" env with
3382      [ Vint n -> n
3383      | _ -> 0 ]
3384    in
3385    loop 0 where rec loop i =
3386      if i > max_level then ()
3387      else
3388        let env = [("level", Vint i) :: env] in
3389        do {
3390          List.iter (print_ast env ep) al;
3391          loop (succ i)
3392        }
3393  and print_foreach_family env al ini_ep (p, _) =
3394    loop None 0 where rec loop prev i =
3395      if i = Array.length (get_family p) then ()
3396      else
3397        let ifam = (get_family p).(i) in
3398        let fam = foi base ifam in
3399        let ifath = get_father fam in
3400        let imoth = get_mother fam in
3401        let ispouse = spouse (get_key_index p) fam in
3402        let cpl = (ifath, imoth, ispouse) in
3403        let m_auth =
3404           authorized_age conf base (pget conf base ifath) &&
3405           authorized_age conf base (pget conf base imoth)
3406        in
3407        let vfam = Vfam ifam fam cpl m_auth in
3408        let env = [("#loop", Vint 0) :: env] in
3409        let env = [("fam", vfam) :: env] in
3410        let env = [("family_cnt", Vint (i + 1)) :: env] in
3411        let env =
3412          match prev with
3413          [ Some vfam -> [("prev_fam", vfam) :: env]
3414          | None -> env ]
3415        in
3416        do {
3417          List.iter (print_ast env ini_ep) al;
3418          loop (Some vfam) (i + 1);
3419        }
3420  and print_foreach_first_name_alias env al ((p, p_auth) as ep) =
3421    if not p_auth && (is_hide_names conf p) then ()
3422    else
3423      List.iter
3424        (fun s ->
3425           let env = [("first_name_alias", Vstring (sou base s)) :: env] in
3426           List.iter (print_ast env ep) al)
3427        (get_first_names_aliases p)
3428  and print_foreach_level max_lev env al ((p, _) as ep) =
3429    let max_level =
3430      match get_env max_lev env with
3431      [ Vint n -> n
3432      | _ -> 0 ]
3433    in
3434    loop 1 where rec loop i =
3435      if i > max_level then ()
3436      else
3437        let env = [("level", Vint i) :: env] in
3438        do {
3439          List.iter (print_ast env ep) al;
3440          loop (succ i)
3441        }
3442  and print_foreach_nobility_title env al ((p, p_auth) as ep) =
3443    if p_auth then
3444      let titles = nobility_titles_list conf base p in
3445      list_iter_first
3446        (fun first x ->
3447           let env = [("nobility_title", Vtitle p x) :: env] in
3448           let env = [("first", Vbool first) :: env] in
3449           List.iter (print_ast env ep) al)
3450        titles
3451    else ()
3452  and print_foreach_parent env al ((a, _) as ep) =
3453    match get_parents a with
3454    [ Some ifam ->
3455        let cpl = foi base ifam in
3456        Array.iter
3457          (fun iper ->
3458             let p = pget conf base iper in
3459             let env = [("parent", Vind p) :: env] in
3460             List.iter (print_ast env ep) al)
3461          (get_parent_array cpl)
3462    | None -> () ]
3463  and print_foreach_qualifier env al ((p, p_auth) as ep) =
3464    if not p_auth && (is_hide_names conf p) then ()
3465    else
3466      list_iter_first
3467        (fun first nn ->
3468           let env = [("qualifier", Vstring (sou base nn)) :: env] in
3469           let env = [("first", Vbool first) :: env] in
3470           List.iter (print_ast env ep) al)
3471        (get_qualifiers p)
3472  and print_foreach_relation env al ((p, p_auth) as ep) =
3473    if p_auth then
3474      list_iter_first
3475        (fun first r ->
3476           let env = [("rel", Vrel r None) :: env] in
3477           let env = [("first", Vbool first) :: env] in
3478           List.iter (print_ast env ep) al)
3479        (get_rparents p)
3480    else ()
3481  and print_foreach_related env al ((p, p_auth) as ep) =
3482    if p_auth then
3483      let list =
3484        let list = list_uniq (List.sort compare (get_related p)) in
3485        List.fold_left
3486          (fun list ic ->
3487             let c = pget conf base ic in
3488             loop list (get_rparents c) where rec loop list =
3489               fun
3490               [ [r :: rl] ->
3491                   match r.r_fath with
3492                   [ Some ip when ip = get_key_index p ->
3493                       loop [(c, r) :: list] rl
3494                   | _ ->
3495                       match r.r_moth with
3496                       [ Some ip when ip = get_key_index p ->
3497                           loop [(c, r) :: list] rl
3498                       | _ -> loop list rl ] ]
3499               | [] -> list ])
3500          [] list
3501      in
3502      let list =
3503        List.sort
3504          (fun (c1, _) (c2, _) ->
3505             let d1 =
3506               match Adef.od_of_codate (get_baptism c1) with
3507               [ None -> Adef.od_of_codate (get_birth c1)
3508               | x -> x ]
3509             in
3510             let d2 =
3511               match Adef.od_of_codate (get_baptism c2) with
3512               [ None -> Adef.od_of_codate (get_birth c2)
3513               | x -> x ]
3514             in
3515             match (d1, d2) with
3516             [ (Some d1, Some d2) ->
3517                 if CheckItem.strictly_before d1 d2 then -1 else 1
3518             | _ -> -1 ])
3519        (List.rev list)
3520      in
3521      List.iter
3522        (fun (c, r) ->
3523           let env = [("rel", Vrel r (Some c)) :: env] in
3524           List.iter (print_ast env ep) al)
3525        list
3526    else ()
3527  and print_foreach_sorted_list_item env al ep =
3528    let list =
3529      match get_env "list" env with
3530      [ Vslist l -> SortedList.elements l.val
3531      | _ -> [] ]
3532    in
3533    loop (Vslistlm []) list where rec loop prev_item =
3534      fun
3535      [ [_ :: sll] as gsll ->
3536           let item = Vslistlm gsll in
3537           let env = [("item", item); ("prev_item", prev_item) :: env] in
3538           do {
3539             List.iter (print_ast env ep) al;
3540             loop item sll
3541           }
3542      | [] -> () ]
3543  and print_foreach_source env al ((p, p_auth) as ep) =
3544    let rec insert_loop typ src =
3545      fun
3546      [ [(typ1, src1) :: srcl] ->
3547          if src = src1 then [(typ1 ^ ", " ^ typ, src1) :: srcl]
3548          else [(typ1, src1) :: insert_loop typ src srcl]
3549      | [] -> [(typ, src)] ]
3550    in
3551    let insert typ src srcl =
3552      if src = "" then srcl
3553      else insert_loop (Util.translate_eval typ) src srcl
3554    in
3555    let srcl =
3556      if p_auth then
3557        (* On ajoute les source dans cet ordre :                             *)
3558        (* psource, naissance, baptême, mariage, fsource, décès, inhumation. *)
3559        let srcl = [] in
3560        let srcl =
3561          insert (transl_nth conf "person/persons" 0)
3562            (sou base (get_psources p)) srcl
3563        in
3564        let srcl =
3565          insert (transl_nth conf "birth" 0) (sou base (get_birth_src p)) srcl
3566        in
3567        let srcl =
3568          insert
3569            (transl_nth conf "baptism" 0) (sou base (get_baptism_src p)) srcl
3570        in
3571        let (srcl, _) =
3572          Array.fold_left
3573            (fun (srcl, i) ifam ->
3574               let fam = foi base ifam in
3575               let isp = Gutil.spouse (get_key_index p) fam in
3576               let sp = poi base isp in
3577               (* On sait que p_auth vaut vrai. *)
3578               let m_auth = authorized_age conf base sp in
3579               if m_auth then
3580                 let lab =
3581                   if Array.length (get_family p) = 1 then ""
3582                   else " " ^ string_of_int i
3583                 in
3584                 let srcl =
3585                   let src_typ = transl_nth conf "marriage/marriages" 0 in
3586                   insert (src_typ ^ lab) (sou base (get_marriage_src fam)) srcl
3587                 in
3588                 let src_typ = transl_nth conf "family/families" 0 in
3589                 (insert (src_typ ^ lab) (sou base (get_fsources fam)) srcl, i + 1)
3590               else (srcl, i + 1))
3591            (srcl, 1) (get_family p)
3592        in
3593        let srcl =
3594          insert (transl_nth conf "death" 0) (sou base (get_death_src p)) srcl
3595        in
3596        let srcl =
3597          insert (transl_nth conf "burial" 0) (sou base (get_burial_src p)) srcl
3598        in
3599        srcl
3600      else []
3601    in
3602    (* Affiche les sources et met à jour les variables "first" et "last". *)
3603    let rec loop first =
3604      fun
3605      [ [(src_typ, src) :: srcl] ->
3606          let env =
3607            [("first", Vbool first); ("last", Vbool (srcl = []));
3608             ("src_typ", Vstring src_typ); ("src", Vstring src) :: env]
3609          in
3610          do {
3611            List.iter (print_ast env ep) al;
3612            loop False srcl
3613          }
3614      | [] -> () ]
3615    in loop True srcl
3616  and print_foreach_surname_alias env al ((p, p_auth) as ep) =
3617    if not p_auth && (is_hide_names conf p) then ()
3618    else
3619      List.iter
3620        (fun s ->
3621           let env = [("surname_alias", Vstring (sou base s)) :: env] in
3622           List.iter (print_ast env ep) al)
3623        (get_surnames_aliases p)
3624  and print_foreach_witness env al ep =
3625    fun
3626    [ Vfam _ fam _ True ->
3627        list_iter_first
3628          (fun first ip ->
3629             let p = pget conf base ip in
3630             let env = [("witness", Vind p) :: env] in
3631             let env = [("first", Vbool first) :: env] in
3632             List.iter (print_ast env ep) al)
3633          (Array.to_list (get_witnesses fam))
3634    | _ -> () ]
3635  and print_foreach_witness_relation env al ((p, _) as ep) =
3636    let list = do {
3637      let list = ref [] in
3638      let related = list_uniq (List.sort compare (get_related p)) in
3639      make_list related where rec make_list =
3640        fun
3641        [ [ic :: icl] -> do {
3642            let c = pget conf base ic in
3643            if get_sex c = Male then
3644              Array.iter
3645                (fun ifam ->
3646                   let fam = foi base ifam in
3647                   if array_mem (get_key_index p) (get_witnesses fam)
3648                   then
3649                     list.val := [(ifam, fam) :: list.val]
3650                   else ())
3651                (get_family (pget conf base ic))
3652            else ();
3653            make_list icl
3654          }
3655        | [] -> () ];
3656      list.val
3657    }
3658    in
3659    let list =
3660      List.sort
3661        (fun (_, fam1) (_, fam2) ->
3662           match
3663             (Adef.od_of_codate (get_marriage fam1),
3664              Adef.od_of_codate (get_marriage fam2))
3665           with
3666           [ (Some d1, Some d2) ->
3667               if CheckItem.strictly_before d1 d2 then -1
3668               else if CheckItem.strictly_before d2 d1 then 1
3669               else 0
3670           | _ -> 0 ])
3671        list
3672    in
3673    List.iter
3674      (fun (ifam, fam) ->
3675         let ifath = get_father fam in
3676         let imoth = get_mother fam in
3677         let cpl = (ifath, imoth, imoth) in
3678         let m_auth =
3679           authorized_age conf base (pget conf base ifath) &&
3680           authorized_age conf base (pget conf base imoth)
3681         in
3682         if m_auth then
3683           let env = [("fam", Vfam ifam fam cpl True) :: env] in
3684           List.iter (print_ast env ep) al
3685         else ())
3686      list
3687  in
3688  print_foreach
3689;
3690
3691value eval_predefined_apply conf env f vl =
3692  let vl = List.map (fun [ VVstring s -> s | _ -> raise Not_found ]) vl in
3693  match (f, vl) with
3694  [ ("a_of_b", [s1; s2]) -> Util.translate_eval (transl_a_of_b conf s1 s2)
3695  | ("a_of_b_gr_eq_lev", [s1; s2]) ->
3696       Util.translate_eval (transl_a_of_gr_eq_gen_lev conf s1 s2)
3697  | ("add_in_sorted_list", sl) ->
3698      match get_env "list" env with
3699      [ Vslist l -> do { l.val := SortedList.add sl l.val; "" }
3700      | _ -> raise Not_found ]
3701  | ("hexa", [s]) -> Util.hexa_string s
3702  | ("initial", [s]) ->
3703      if String.length s = 0 then ""
3704      else String.sub s 0 (Util.index_of_next_char s 0)
3705  | ("lazy_print", [v]) ->
3706      match get_env "lazy_print" env with
3707      [ Vlazyp r -> do { r.val := Some v; "" }
3708      | _ -> raise Not_found ]
3709  | ("min", [s :: sl]) ->
3710      try
3711        let m =
3712          List.fold_right (fun s -> min (int_of_string s)) sl (int_of_string s)
3713        in
3714        string_of_int m
3715      with
3716      [ Failure _ -> raise Not_found ]
3717  | ("clean_html_tags", [s]) ->
3718      (* On supprime surtout les balises qui peuvent casser la mise en page. *)
3719      Util.clean_html_tags s
3720        ["<br */?>"; "</?p>"; "</?div>"; "</?span>"; "</?pre>"]
3721  | _ -> raise Not_found ]
3722;
3723
3724value gen_interp_templ menu title templ_fname conf base p = do {
3725  template_file.val := templ_fname ^ ".txt";
3726  let ep = (p, authorized_age conf base p) in
3727  let emal =
3728    match p_getint conf.env "v" with
3729    [ Some i -> i
3730    | None -> 120 ]
3731  in
3732  let env =
3733    let sosa_ref = Util.find_sosa_ref conf base in
3734    let sosa_ref_l =
3735      let sosa_ref () = sosa_ref in
3736      Lazy.from_fun sosa_ref
3737    in
3738    let t_sosa =
3739      match sosa_ref with
3740      [ Some p -> init_sosa_t conf base p
3741      | _ ->
3742          { tstab = [| |];
3743            mark = [| |];
3744            last_zil = [];
3745            sosa_ht = Hashtbl.create 1} ]
3746    in
3747    let desc_level_table_l =
3748      let dlt () = make_desc_level_table conf base emal p in
3749      Lazy.from_fun dlt
3750    in
3751    let desc_level_table_l_save =
3752      let dlt () = make_desc_level_table conf base emal p in
3753      Lazy.from_fun dlt
3754    in
3755    let mal () =
3756      Vint (max_ancestor_level conf base (get_key_index p) emal + 1)
3757    in
3758    let mcl () = Vint (max_cousin_level conf base p) in
3759    let mdl () = Vint (max_descendant_level conf base desc_level_table_l) in
3760    let nldb () =
3761      let bdir = Util.base_path [] (conf.bname ^ ".gwb") in
3762      let fname = Filename.concat bdir "notes_links" in
3763      let db = NotesLinks.read_db_from_file fname in
3764      let db = Notes.merge_possible_aliases conf db in
3765      Vnldb db
3766    in
3767    let all_gp () = Vallgp (get_all_generations conf base p) in
3768    [("p", Vind p);
3769     ("p_auth", Vbool (authorized_age conf base p));
3770     ("count", Vcnt (ref 0));
3771     ("list", Vslist (ref SortedList.empty));
3772     ("desc_mark", Vdmark (ref [| |]));
3773     ("lazy_print", Vlazyp (ref None));
3774     ("sosa",  Vsosa (ref []));
3775     ("sosa_ref", Vsosa_ref sosa_ref_l);
3776     ("t_sosa", Vt_sosa t_sosa);
3777     ("max_anc_level", Vlazy (Lazy.from_fun mal));
3778     ("max_cous_level", Vlazy (Lazy.from_fun mcl));
3779     ("max_desc_level", Vlazy (Lazy.from_fun mdl));
3780     ("desc_level_table", Vdesclevtab desc_level_table_l);
3781     ("desc_level_table_save", Vdesclevtab desc_level_table_l_save);
3782     ("nldb", Vlazy (Lazy.from_fun nldb));
3783     ("all_gp", Vlazy (Lazy.from_fun all_gp))]
3784  in
3785  if menu then
3786    (* Petit calcul pour voir si le fichier est vide => on   *)
3787    (* ne veut pas utiliser le header avec la barre de menu. *)
3788    let size =
3789      match Util.open_templ conf templ_fname with
3790      [ Some ic -> do {
3791          let fd = Unix.descr_of_in_channel ic in
3792          let stats = Unix.fstat fd in
3793          close_in ic;
3794          stats.Unix.st_size
3795        }
3796      | None -> 0 ]
3797    in
3798    if size = 0 then Hutil.header conf title
3799    else
3800      Hutil.interp_no_header conf base templ_fname
3801        {Templ.eval_var = eval_var conf base;
3802         Templ.eval_transl = eval_transl conf;
3803         Templ.eval_predefined_apply = eval_predefined_apply conf;
3804         Templ.get_vother = get_vother; Templ.set_vother = set_vother;
3805         Templ.print_foreach = print_foreach conf base}
3806        env ep
3807  else
3808    Hutil.interp conf base templ_fname
3809      {Templ.eval_var = eval_var conf base;
3810       Templ.eval_transl = eval_transl conf;
3811       Templ.eval_predefined_apply = eval_predefined_apply conf;
3812       Templ.get_vother = get_vother; Templ.set_vother = set_vother;
3813       Templ.print_foreach = print_foreach conf base}
3814      env ep
3815};
3816
3817value interp_templ = gen_interp_templ False (fun _ -> ());
3818value interp_templ_with_menu = gen_interp_templ True;
3819value interp_notempl_with_menu title templ_fname conf base p = do {
3820  (* On envoie le header car on n'est pas dans un template (exple: merge). *)
3821  Hutil.header_without_page_title conf title;
3822  gen_interp_templ True title templ_fname conf base p;
3823};
3824
3825(* Main *)
3826
3827value print conf base p =
3828  let passwd =
3829    if conf.wizard || conf.friend then None
3830    else
3831      let src =
3832        match get_parents p with
3833        [ Some ifam -> sou base (get_origin_file (foi base ifam))
3834        | None -> "" ]
3835      in
3836      try Some (src, List.assoc ("passwd_" ^ src) conf.base_env) with
3837      [ Not_found -> None ]
3838  in
3839  match passwd with
3840  [ Some (src, passwd)
3841    when is_that_user_and_password conf.auth_scheme "" passwd = False ->
3842      Util.unauthorized conf src
3843  | _ ->
3844      interp_templ "perso" conf base p ]
3845;
3846
3847value limit_by_tree conf =
3848  match p_getint conf.base_env "max_anc_tree" with
3849  [ Some x -> max 1 x
3850  | None -> 7 ]
3851;
3852
3853value print_ancestors_dag conf base v p =
3854  let v = min (limit_by_tree conf) v in
3855  let set =
3856    loop Dag.Pset.empty v (get_key_index p) where rec loop set lev ip =
3857      let set = Dag.Pset.add ip set in
3858      if lev <= 1 then set
3859      else
3860        match get_parents (pget conf base ip) with
3861        [ Some ifam ->
3862            let cpl = foi base ifam in
3863            let set = loop set (lev - 1) (get_mother cpl) in
3864            loop set (lev - 1) (get_father cpl)
3865        | None -> set ]
3866  in
3867  let elem_txt p = Dag.Item p "" in
3868  (* Récupère les options d'affichage. *)
3869  let options = Util.display_options conf in
3870  let vbar_txt ip =
3871    let p = pget conf base ip in
3872    Printf.sprintf "%sm=A;t=T;v=%d;%s;dag=on;%s" (commd conf) v options
3873      (acces conf base p)
3874  in
3875  let page_title = Util.capitale (Util.transl conf "tree") in
3876  Dag.make_and_print_dag conf base elem_txt vbar_txt True set [] page_title ""
3877;
3878
3879value print_ascend conf base p =
3880  match
3881    (p_getenv conf.env "t", p_getenv conf.env "dag", p_getint conf.env "v")
3882  with
3883  [ (Some "T", Some "on", Some v) -> print_ancestors_dag conf base v p
3884  | _ ->
3885      let templ =
3886        match p_getenv conf.env "t" with
3887        [ Some ("E" | "F" | "H" | "L") -> "anclist"
3888        | Some ("D" | "G" | "M" | "N" | "P" | "Z") -> "ancsosa"
3889        | Some ("A" | "C" | "T") -> "anctree"
3890        | _ -> "ancmenu" ]
3891      in
3892      interp_templ templ conf base p ]
3893;
3894
3895value print_what_links conf base p =
3896  if authorized_age conf base p then do {
3897    let key =
3898      let fn = Name.lower (sou base (get_first_name p)) in
3899      let sn = Name.lower (sou base (get_surname p)) in
3900      (fn, sn, get_occ p)
3901    in
3902    let bdir = Util.base_path [] (conf.bname ^ ".gwb") in
3903    let fname = Filename.concat bdir "notes_links" in
3904    let db = NotesLinks.read_db_from_file fname in
3905    let db = Notes.merge_possible_aliases conf db in
3906    let pgl = links_to_ind conf base db key in
3907    let title h = do {
3908      Wserver.wprint "%s: " (capitale (transl conf "linked pages"));
3909      if h then Wserver.wprint "%s" (simple_person_text conf base p True)
3910      else
3911        Wserver.wprint "<a href=\"%s%s\">%s</a>" (commd conf)
3912          (acces conf base p) (simple_person_text conf base p True)
3913    }
3914    in
3915    Hutil.header conf title;
3916    Hutil.print_link_to_welcome conf True;
3917    Notes.print_linked_list conf base pgl;
3918    Hutil.trailer conf;
3919  }
3920  else Hutil.incorrect_request conf
3921;
3922