#
# GED2HTML output program -- customize to taste
#
# Copyright (c) 1998 Eugene W. Stark
# All rights reserved.
#
# Permission is hereby granted to registered users of GED2HTML to
# make copies and modifications to this code for their own personal
# use and to distribute such modified copies, provided that this
# copyright notice is retained on all modified or distributed copies.
# Any other use of this code is prohibited without written permission.
#
#---------------------------------------------------------------------
# The first several definitions in this file are entry points that
# the output processor expects to be here. Whatever changes you make,
# you must leave some sort of definitions here for these routines.
#---------------------------------------------------------------------
define do_initialize { do_initialize_ ; }
define do_index i { do_index_ i ; }
define do_surnames s { do_surnames_ s ; }
define do_individuals i { do_individuals_ i ; }
define do_families f { do_families_ f ; }
define do_sources s { do_sources_ s ; }
define do_notes n { do_notes_ n ; }
define do_gendex i { do_gendex_ i ; }
#---------------------------------------------------------------------
# The rest are auxiliary routines used by the above.
# You can change whatever you want from this point on.
#---------------------------------------------------------------------
#---------------------------------------------------------------------
# INITIALIZATION
#---------------------------------------------------------------------
# This routine runs *after* the initialization routine from an options
# file specified in the dialog box or command line, and *before* any
# GEDCOM is read.
define do_initialize_
local l
{
internationalize ;
#
# The purpose of the following silliness is to get an English-formatted
# date to put in the META elements of the HTML output, without
# affecting the previously selected language and locale.
#
set l to LANGUAGE
set LANGUAGE to "English"
set METADATE to TODAY
set LANGUAGE to l
# RJP Many thanks to BMG for help with getting started on this template
set DTD to ""
# This template has only been tested with the following settings, so force them
# Notes on the individual's page
set INLINE_NOTES to 1
# ditto sources
set INLINE_SOURCES to 1
# One person per file forced
set INDIVIDUALS_PER_FILE to 0
# No family group sheets
set FAMILY_GROUPS to 0
# No separate notes file
set GENERATE_NOTES to 0
# No separate sources file
set GENERATE_SOURCES to 0
# Surnames index all on one page
set SURNAME_WIDTH to 0
# Two extra variables are required to be set on the command line
# CSS = the file name of the Style Sheet (relative to the PATH_TO_ROOT)
# TITLE = the overall title of the database to be used on the index pages
# PRIVATE = 1 to switch on the enhanced privatisation, 0 to put out everyone
}
#---------------------------------------------------------------------
# PAGE HEADERS AND FOOTERS
#---------------------------------------------------------------------
# Output the HTML BODY tag, handling colors, images, etc.
define html_body
{
print "
" ;
}
# Produce the footer on each HTML page.
define page_footer
{
if HOMEPAGE then
# RJP customised footer
# print "
" ,
print_alternatives INDEX_OF_PERSONS_TEXT "Index of Persons" ;
print "
" ;
if ~(i.parent & i.parent.parent) then
# RJP no one is interested in this, it is always me.
# print "" ,
# header_info ;
# if HEADER.copr then
# print " " HEADER.copr ;
# end
# print "" ;
# if HEADER.note then
# print "
" ;
# print_text HEADER.note 0 ;
# print "
" ;
# end
# if HEADER.submitter then
# submitter_info HEADER.submitter ;
# end
# RJP this goes at the end
# author_contact ;
end
# RJP There is a real risk that living people will still appear on the higher
# levels of index. There is little I can do about that - they do not appear
# at the leaf level with dates of birth, nor do they have detail pages.
# The intention was to have a single level index but it came out at 250K which
# was unreasonable for a web page.
print "
" ;
# RJP print disclaimer
if PRIVATE then
print "Note that you may find people in this index which are not in the" ;
print "online database. This is a side effect of the privacy policy and was" ;
print "unavoidable.
" ;
page_footer ;
print "" ;
print "" ;
}
#
# Create UP, BACK, and NEXT pointers for navigation within a
# hierarchical index.
# The second argument is zero for persons index, nonzero for
# surnames index
#
define index_links i which
local pred succ
{
# RJP move to inside if and check for contents
# print "
" ;
# if i then
# RJP
if i & (i.parent | i.prev | i.succ) then
print "
" ;
if i.parent then
if UP_TEXT then
index_link UP_TEXT i.parent which ;
else
index_link "UP" i.parent which ;
end
end
if i.prev then
if BACK_TEXT then
index_link BACK_TEXT i.prev which ;
else
index_link "BACK" i.prev which ;
end
else
set pred to i.pred
if pred then
if BACK_TEXT then
index_link BACK_TEXT i.parent.pred which ;
else
index_link "BACK" i.parent.pred which ;
end
end
end
if i.next then
if NEXT_TEXT then
index_link NEXT_TEXT i.next which ;
else
index_link "NEXT" i.next which ;
end
else
set succ to i.succ
if succ then
if NEXT_TEXT then
index_link NEXT_TEXT i.succ which ;
else
index_link "NEXT" i.succ which ;
end
end
end
# RJP
print "
" ;
end
# RJP move to inside if
# print "" ;
}
# Output a link to a node i in the persons index,
# with d as the highlighted text of the link.
# The third argument is zero for persons index, nonzero for
# surnames index
define index_link d s which
{
print "" d "" ,
print " (" ,
if which then
emit_surname s.first.surname ;
print " - " ,
emit_surname s.last.surname ;
else
print_name s.first.name ;
print " - " ,
print_name s.last.name ;
end
print ") " ;
}
# Routine that outputs information from the GEDCOM header on
# each index page.
define header_info
{
print NUMBER_OF_INDIVIDUALS " " ,
print_alternatives INDIVIDUALS_TEXT "individuals" ;
print ", " NUMBER_OF_FAMILIES " " ,
print_alternatives FAMILIES_TEXT "families" ;
if HEADER.filename then
print " " ,
print_alternatives FROM_FILE_TEXT "from file" ;
print " " HEADER.filename ,
if HEADER.date then
print " (" HEADER.date.value ")" ;
end
end
}
# Output submitter information from the GEDCOM header
define submitter_info s
local t
{
if s.name | s.address | s.phone then
print "
" ,
print_alternatives AUTHOR_TEXT "Author" ;
print_alternatives COLON_TEXT ": " ;
print " " ,
if s.name & s.name.text then
print s.name.text ,
print " " ;
end
if s.address & s.address.text then
set t to s.address.text
while t do
print t.text ,
if t.cont then
print ", " ,
set t to t.cont
else
set t to t.conc
end
end
print " " ;
end
if s.phone & s.phone.text then
print s.phone.text ;
end
print "
" ;
end
}
#---------------------------------------------------------------------
# SURNAMES INDEX PAGES
#---------------------------------------------------------------------
# Output a single page of the surnames index.
# Parameter s is the head of a list of surname index nodes to
# be output in a single file.
define do_surnames_ s
local pred succ tabs
{
# RJP
# print "" ;
print DTD ;
# print "" ;
print "" ;
print "" ;
print "" ,
# RJP include title
print TITLE " - " ,
print_alternatives INDEX_OF_SURNAMES_TEXT "Index of Surnames" ;
print "" ;
# RJP
print "" ;
if ~OMIT_META then
print "" ;
print "" ;
print "" ;
print "" ;
if HEADER.copr then
print "" ;
end
end
print "" ;
html_body ;
# RJP include title
print "
" TITLE "
" ;
print "
" ,
print_alternatives INDEX_OF_SURNAMES_TEXT "Index of Surnames" ;
print "
" ;
# RJP print disclaimer
if PRIVATE then
print "
Note that you may find surnames in this index which are not in the online" ;
print "database. This is a side effect of the privacy policy when all the people with" ;
print "that surname are living.
" ;
end
if ~(s.parent & s.parent.parent) then
# RJP no one is interested in this, it is always me.
# print "" ,
# header_info ;
# if HEADER.copr then
# print " " HEADER.copr ;
# end
# print "" ;
# if HEADER.note then
# print "
" ;
# print_text HEADER.note 0 ;
# print "
" ;
# end
# if HEADER.submitter then
# submitter_info HEADER.submitter ;
# end
# RJP this goes at the end
# author_contact ;
end
#
# If the index consists of a single node, and we haven't been
# asked to produce a hierarchical index, then use "alphabet tab" format
#
if ~s.children & SURNAME_WIDTH = 0 & ~NO_ALPHABET_TABS then
do_alphabetical s ;
#
# Otherwise use the more general hierarchical format
#
else
print "
" ;
page_footer ;
print "" ;
print "" ;
}
# Produce an "alphabet tab" style surnames index page.
define do_alphabetical s
local tabs l n
{
set tabs to "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z"
print "
" ;
while s & s.first & (~s.first.surname | s.first.surname <= l) do
print "" ,
emit_surname s.first.surname ;
print "" ,
set n to s.succ
if n & n.first then
if n.first.surname & n.first.surname <= l then
print "," ;
else
print " " ;
end
else
print ;
end
set s to n
end
print "
" ;
end
# RJP Put some letter headings in, and fill the empty HTML element
# print "" ;
print "
" ;
end
}
# Routine for outputting a link to a node s in the surnames index,
# with d as the highlighted text of the link.
define surname_link d s
{
print "" d "" ,
print " (" ,
emit_surname s.first.surname ;
print " - " ,
emit_surname s.last.surname ;
print ") " ;
}
# Routine for outputting either ??? or a surname.
define emit_surname s
{
if s then
print s ,
else
print "???" ,
end
}
#---------------------------------------------------------------------
# INDIVIDUALS PAGES
#---------------------------------------------------------------------
# Output a page of individuals.
# Parameter i is head of a list of individuals to be output
# in a single page.
define do_individuals_ i
local ii ok
{
# If we are doing family group sheet output, then we only output
# something if there is an individual in the list who doesn't belong
# to any family group. So, scan for this first.
set ok to 0
set ii to i
if FAMILY_GROUPS then
while ii & ~ok do
if ~ii.families & ~ii.marriages then
set ok to 1
end
set ii to ii.next
end
else
set ok to 1
end
# RJP supress the whole file for living people
# It seems that if nothing is written, then no file is created - good.
# if ok then
if ok & (~PRIVATE | i.death) then
# RJP
# print "" ;
print DTD ;
# print "" ;
print "" ;
print "" ;
print "" ,
# RJP we don't want the GEDCOM ids all over the place
# print i.xref ": " ,
# RJP include title
print TITLE " - " ,
# RJP title before name
if i.title then
print i.title " " ,
end
print_name i.name ;
# if i.title then
# print " (" i.title ")" ;
# end
# RJP insert the refereence number
if i.refns then
print "#" i.refns.number ,
end
if ~i.living then
print " (" ,
birth_and_death i ;
print ")" ;
end
print "" ;
# RJP
print "" ;
if ~OMIT_META then
print "" ;
print "" ;
print "" ;
print "" ;
end
print "" ;
html_body ;
while i do
# If we are doing family-group-style output, then only output
# an individual if they don't have any family.
if ~FAMILY_GROUPS | (~i.families & ~i.marriages) then
if i.living then
do_living i ;
else
do_individual i ;
end
end
set i to i.next
end
print "" ;
print "" ;
end
}
# Routine for outputting the data on an individual page for which
# the individual is flagged as "living".
define do_living i
{
print "
" ;
}
# Routine for outputting the data on an individual page for which
# the individual is not flagged as "living".
define do_individual i
# RJP
#local br fn s e a r f c n o
local br fn s e a r f c n o nm
{
# RJP include title
print "
" TITLE "
" ;
# RJP don't need the locator
# print "
" ,
print "
" ,
# RJP move picture to a little later
# include i.xref ^ ".img"
# RJP title before name
if i.title then
print i.title " " ,
end
# RJP use do_name which includes the name source references we want
# print_name i.name ;
do_name i.name 0 ;
# if i.title then
# print " (" i.title ")" ,
# end
# RJP add reference number
if i.refns then
print "#" i.refns.number ,
end
print "
" ;
# RJP insert picture here
include INCLUDE_DIR ^ i.xref ^ ".img"
# RJP I would liked to have printed the aliases here but FTM doesn't generate the right
# GEDCOM text (i.aliases is set but there is no name field)
# RJP no references to notes are needed, they are in full below
# if i.name & i.name.notes then
# for n in i.name.notes do
# do_note n 0 ;
# end
# end
# if i.notes then
# for n in i.notes do
# do_note n 0 ;
# end
# end
for s in i.sources do
source_link s ;
end
print "
" ,
birth_and_death i;
print "
" ;
# RJP reference number removed from list
# if i.events | i.attributes | (i.names & i.names.next) | i.rfn
# | i.afn | i.refns | i.rin | i.ordinances then
if i.events | i.attributes | (i.names & i.names.next) | i.rfn
| i.afn | i.rin | i.ordinances then
print "
" ;
if i.names & i.names.next then
for n in i.names.next do
do_name n 1 ;
end
end
if i.attributes then
for a in i.attributes do
do_attr a 1 ;
end
end
if i.events then
for e in i.events do
do_event e 1 ;
end
end
if i.ordinances then
for o in i.ordinances do
do_ordn o 1 ;
end
end
if i.rfn then
do_attr i.rfn 1 ;
end
if i.afn then
do_attr i.afn 1 ;
end
# RJP already included
# if i.refns then
# for r in i.refns do
# do_refn r 1 ;
# end
# end
if i.rin then
do_attr i.rin 1 ;
end
print "
" ;
end
# RJP the code that follows does not consider the possibility of multiple parents
# (adoption, fostering etc.). The data should be available via the i.families list.
set br to 0
if i.father then
set br to 1
# RJP tidy up HTML
# print "" ,
print "
" ;
end
# RJP
# if br then
# print " " ;
# end
# RJP moved here from further down to keep them with the individual
indiv_notes i 1 ;
# RJP count marriages
set nm to 0
for f in i.marriages do
set nm to nm + 1
end
set fn to 1
for f in i.marriages do
# RJP tidy up HTML
# print "" ,
print "
" ,
print_alternatives FAMILY_TEXT "Family" ;
# RJP only if more than one
# print " " fn "
" ;
if nm > 1 then
print " " fn ,
end
print_alternatives COLON_TEXT ": " ;
# RJP
print "" ;
# RJP insert picture here
include INCLUDE_DIR ^ f.xref ^ ".img"
if i.ismale & f.wife then
# RJP omit if living
if ~PRIVATE | f.wife.death then
# RJP caption
# print "" ,
print "
" ;
end
end
# RJP refns removed from list
# if f.events | f.ordinances | f.refns | f.rin then
if f.events | f.ordinances | f.rin then
print "
" ;
for e in f.events do
do_event e 1 ;
end
for o in f.ordinances do
do_ordn o 1 ;
end
# RJP not used
# for r in f.refns do
# do_refn r 1 ;
# end
# BMG comments that this should be a for loop - I am not sure what it is anyway,
# but the documentation does not call for a list, nor does the GEDCOM specification
if f.rin then
do_attr f.rin 1 ;
end
print "
" ;
end
# RJP moved here from below to keep with relevant family
family_notes f 1 ;
if f.children then
# RJP caption
# print "" ;
print "
Children: " ,
if PRIVATE then
print " (not shown if possibly living)" ,
end
print "
" ;
for c in f.children do
# RJP omit if living (non blanking space to ensure that item number is listed)
# print "
" ;
#
# Emit all notes and sources associated with this individual.
#
# RJP these have already been done above
# indiv_notes i 1 ;
# for f in i.marriages do
# family_notes f 1 ;
# end
# RJP Heading
print "
Source references
" ;
indiv_sources i 1 ;
for f in i.marriages do
family_sources f 1 ;
end
include i.xref ^ ".inc"
page_footer ;
}
# Output birth and death information for an individual.
define birth_and_death i
{
if i.birth | i.death then
if i.birth & i.birth.date then
print i.birth.date.value ,
else
print "____" ,
end
print " - " ,
if i.death & i.death.date then
print i.death.date.value ,
else
print "____" ,
end
else
print "____ - ____" ,
end
}
# Routine for outputting a name structure
# If "item" is nonzero, then an HTML
is output,
# together with the GEDCOM tag associated with the attribute.
define do_name n item
local s nn
{
if item then
print "
" n.tagname.upper ": " ,
end
if n.fullname then
print n.fullname ;
end
for nn in n.notes do
do_note nn 0 ;
end
for s in n.sources do
source_link s ;
end
}
# Routine for outputting the full text of a name,
# if the name is non-null, and do nothing otherwise.
define print_name n
{
if n then
print n.fullname ,
end
}
# Routine to output an indication of whether family line continues
# with a given individual
define child_had_issue c
local s f
{
set s to " "
for f in c.marriages do
if f.children then
set s to "+"
end
end
print "" s "" ,
}
# Emit the proper URL to take us to the page that has the data
# for a given individual.
#
# If we aren't producing family group sheets, then just link to
# the URL for the individual.
# If we are producing family group sheets, then link to the most
# appropriate family page:
# If the individual has a marriage, then the link goes to that
# family's page.
# If the individual has no marriage, then the link goes to the first
# family in which the individual is listed as a child.
# If the individual is not a child in any family, then the link goes
# to the page for that individual.
#
# When doing family groups, the f argument specifies the particular
# family group to which the link should go.
define indiv_url i
local m
{
if FAMILY_GROUPS then
if i.marriages then
set m to i.marriages
if m then
print m.url "#" i.xref ,
end
else
set m to i.families
if m then
print m.url "#" i.xref ,
else
print i.url ,
end
end
else
print i.url ,
end
}
define indiv_family_url i f
local m notfound
{
if FAMILY_GROUPS then
set notfound to 1
if i.marriages then
for m in i.marriages do
if m = f then
print m.url "#" i.xref ,
set notfound to 0
end
end
if notfound then
print i.marriages.url "#" i.xref ,
end
elseif i.families then
for m in i.families do
if m = f then
print m.url "#" i.xref ,
set notfound to 0
end
end
if notfound then
print i.families.url "#" i.xref ,
end
else
print i.url ,
end
else
print i.url ,
end
}
#---------------------------------------------------------------------
# FAMILY GROUP PAGES
#---------------------------------------------------------------------
# Output a page of families.
# Parameter f is head of a list of families to be output
# in a single page.
define do_families_ f
{
# If we are not doing family-group-style output, then do nothing
if FAMILY_GROUPS then
print "" ;
print "" ;
print "" ;
print "" ,
if f.husband then
print_name f.husband.name ;
else
print "(Unknown)" ,
end
print " / " ,
if f.wife then
print_name f.wife.name ;
else
print "(Unknown)" ,
end
print "" ;
if ~OMIT_META then
print "" ;
print "" ;
print "" ;
end
print "" ;
html_body ;
while f do
do_family f ;
set f to f.next
end
print "" ;
print "" ;
end
}
# Routines to output a family group sheet for a given family
define do_family f
local e m c n s
{
print "
" ;
#
# Emit all notes and sources associated with this individual
#
family_notes f 1 ;
if f.husband then
indiv_notes f.husband 1 ;
end
if f.wife then
indiv_notes f.wife 1 ;
end
if f.children then
for c in f.children do
indiv_notes c 1 ;
end
end
family_sources f 1 ;
if f.husband then
indiv_sources f.husband 1 ;
end
if f.wife then
indiv_sources f.wife 1 ;
end
if f.children then
for c in f.children do
indiv_sources c 1 ;
end
end
page_footer ;
}
define do_child f c
local n s
{
print "
" ,
print "" ;
print "" ,
print_name c.name ;
print "" ;
if ~c.living then
for n in c.notes do
do_note n 0 ;
end
for s in c.sources do
source_link s ;
end
else
do_note c.living 0 ;
end
print "
" ,
born_field c ;
if c.marriages then
married_field c.marriages c ;
end
died_field c ;
spouses_field c ;
print "
" ;
}
define do_husband_or_wife f i which
local e m c n s
{
if i & (~i.living) then
born_field i ;
if which = "Husband" then
married_field f i ;
end
died_field i ;
father_field i f ;
mother_field i f ;
spouses_field i ;
if i.notes then
print "
" ,
if i.death & i.death.place & ~i.living then
print i.death.place.name ,
else
print ;
end
}
define married_field f c
local m e
{
set m to 0
if ~c.living then
for e in f.events do
if e.tagcode = "MARR" then
print "
" ,
if ~c.living then
set first to 1
for m in c.marriages do
if c.ismale & m.wife then
if ~first then
print ", " ,
else
set first to 0
end
print "" ,
print_name m.wife.name ;
print "" ;
elseif c.isfemale & m.husband then
if ~first then
print ", " ,
else
set first to 0
end
print "" ,
print_name m.husband.name ;
print "" ;
end
end
end
}
define father_field i f
{
print "
" ,
if i.mother & ~i.living then
print "" ,
print_name i.mother.name ;
print "" ;
else
print ;
end
}
#---------------------------------------------------------------------
# LINKS TO NOTES AND SOURCES
#---------------------------------------------------------------------
# Find all notes associated with a single family.
# If here is nonzero, then output the notes right now,
# otherwise output links to the notes.
define family_notes f here
local n e
{
# RJP Heading and css stuff
if f.notes then
print "
Notes
" ;
for n in f.notes do
do_note n here ;
end
for e in f.events do
event_notes e here ;
end
# RJP
print "
" ;
end
}
# Find all notes associated with a single individual
# If here is nonzero, then output the notes right now,
# otherwise output links to the notes.
define indiv_notes i here
local n e a
{
# RJP Heading and css stuff
if i.notes then
print "
Notes
" ;
if i.living then
do_note i.living here ;
else
for n in i.notes do
do_note n here ;
end
for n in i.names do
name_notes n here ;
end
for a in i.attributes do
if a.event then
event_notes a.event here ;
end
end
for e in i.events do
event_notes e here ;
end
end
# RJP
print "
" ;
end
}
# Find all notes associated with a single event
# If here is nonzero, then output the notes right now,
# otherwise output links to the notes.
define event_notes e here
local n
{
for n in e.notes do
do_note n here ;
end
}
# Find all notes associated with a single source
# If here is nonzero, then output the notes right now,
# otherwise output links to the notes.
define source_notes s here
local n
{
for n in s.notes do
do_note n here ;
end
}
# Find all notes associated with a name
# If here is nonzero, then output the notes right now,
# otherwise output links to the notes.
define name_notes n here
local nn
{
for nn in n.notes do
do_note nn here ;
end
}
# Find all sources associated with a single family group
# If here is nonzero, then output the sources right now,
# otherwise output links to the sources.
define family_sources f here
local s c e
{
for e in f.events do
event_sources e here ;
end
for s in f.sources do
if here then
do_citation s ;
else
source_link s ;
end
end
}
# Find all sources associated with a single individual
# If here is nonzero, then output the sources right now,
# otherwise output links to the sources.
define indiv_sources i here
local s e a n
{
if ~i.living then
for s in i.sources do
if here then
do_citation s ;
else
source_link s ;
end
end
for n in i.names do
name_sources n here ;
end
for a in i.attributes do
if a.event then
event_sources a.event here ;
end
end
for e in i.events do
event_sources e here ;
end
end
}
# Output all sources associated with a single event
# If here is nonzero, then output the sources right now,
# otherwise output links to the sources.
define event_sources e here
local s
{
for s in e.sources do
if here then
do_citation s ;
else
source_link s ;
end
end
}
# Find all sources associated with a name
# If here is nonzero, then output the sources right now,
# otherwise output links to the sources.
define name_sources n here
local s
{
for s in n.sources do
if here then
do_citation s ;
else
source_link s ;
end
end
}
#---------------------------------------------------------------------
# SOURCES PAGES
#---------------------------------------------------------------------
# Output a page of sources.
# Parameter s is head of a list of sources to be output
# in a single page.
define do_sources_ s
{
print "" ;
print "" ;
print "" ;
print "" ,
print_alternatives SOURCES_TEXT "Sources" ;
print "" ;
if ~OMIT_META then
print "" ;
print "" ;
print "" ;
print "" ;
end
print "" ;
html_body ;
print "