############################################################################### # Generate Macky Family Genealogy Tree -- Ian Macky, Feb 2009 # # Data files are named after the genealogy code (e.g. B1d1.dat) and # have one datum per line. Format is: # [details] # # where is one of: # n name # b birth-date # d death-date # a arrival-date # = marriage-date # # number of children # # for example: # n Samuel Cochrane MACKY # b 7/11/1844 # d 11/2/1914 # = 1865 # # 1 # = 1868 # n Janet (Jessie) SHAW NEE WALLACE # # 3 # # $Id: gentree.awk,v 1.14 2009/06/02 15:33:32 ian Exp $ ############################################################################### BEGIN { public_levels = 3 # of top levels which are public cell_spacing = 5 # spacing around child cells max_kids_row = 6 # max number children per row spouse_spacer = 10 # horizontal space between spouses body_color = "white" # background page color text_color = "black" link_color = "black" # un-visited links vlink_color = "#333333" # visited-links color code_color = "red" # color for genealogy code checker_color = "#CCCCCC" # color alternating child cells hr_color = "#666666" # color nav_current = "red" # current place in nav bar nav_border = "#666666" # navigation box border nav_bg = "#CCCCFF" # navigation box background up_icon = "up.gif" # icon for up-arrow right_icon = "right.gif" # icon for right-arrow left_icon = "left.gif" # icon for left-arrow icon_size = 33 # width & height of square icons root_name = "James MACKY" # top_level name root_spouse = "Dorcas" private_subdir = "table/" # private HTML goes here table_boiler1 = "tables0" # first boilerplate for master tables table_boiler2 = "tables1" # second boilerplate ditto html_doctype = "" html_lang = "en-US" html_ext = ".html" data_subdir = "data/" data_ext = ".dat" Upper_AZ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" Lower_AZ = "abcdefghijklmnopqrstuvwxyz" title = "The Macky Family in New Zealand" TITLE = toupper(title) name[""] = "Tables" ###################################################################### print "Generating \"" title "\" genealogy files..." print " Loading data..." load_data("", 0) print " Writing HTML..." write_page(start) print master_count " descendents" print "Done" } # recursively load genealogy data files ### function load_data(code, level, k, tk) { level_of[code] = level undotted[code] = undottify(code) # public files are top-level and named table_CODE; private files # are just named CODE and live in ### if (!level) filename_of[code] = "tables" html_ext else if (level > public_levels) filename_of[code] = undotted[code] html_ext else filename_of[code] = "table_" undotted[code] html_ext ns = 0 data_file = data_subdir undotted[code] data_ext for (n = 0; getline < data_file > 0; n++) { if ($1 == "=") marriage_date[code, ++ns] = rest() else if (ns) { if ($1 == "n") spouse_name[code, ns] = rest() else if ($1 == "b") spouse_birth[code, ns] = $2 else if ($1 == "d") spouse_death[code, ns] = $2 else if ($1 == "#") { spouse_kids[code, ns] = $2 total_kids[code] += $2 } else fatal_error("UNKNOWN SPOUSE LINE FOR CODE " code ": " $0) } else { if ($1 == "n") name[code] = rest() else if ($1 == "a") arrival[code] = rest() else if ($1 == "b") birth[code] = $2 else if ($1 == "d") death[code] = $2 else if ($1 == "w") website[code] = $2 else if ($1 == "#") { kids[code] = $2 total_kids[code] += $2 } else fatal_error("UNKNOWN MAIN LINE FOR CODE " code ": " $0) } } close(file) if (!n) fatal_error("MISSING " file) n_spouse[code] = ns # load children ### tk = total_kids[code] for (k = 1; k <= tk; k++) { kid = child_code(code, k) child_of[code, k] = kid load_data(kid, level + 1) } # set up children's parent/previous/next linkages ### last_kid = "" for (k = 1; k <= tk; k++) { kid = child_of[code, k] parent_of[kid] = code if (total_kids[kid]) { if (k > 1) { prev_of[kid] = last_kid next_of[last_kid] = kid } last_kid = kid } } } # write master tree of direct descendents ### function write_master(code, k, tk) { master_count++ if (website[code]) nm = "" name[code] "" else nm = name[code] tk = total_kids[code] if (tk) { print "
  • " code " " nm > path print "
      " > path for (k = 1; k <= tk; k++) write_master(child_of[code, k]) print "
    " > path } else print "
  • " code " " nm > path } # write page for a person with children ### function write_page(code, k) { if (!name[code]) fatal_error("UNKNOWN CODE " code) if (!total_kids[code]) fatal_error(code " HAS NO CHILDREN") path = path_to("", code) filename_of[code] print html_doctype > path print "" > path print "" > path print "" > path if (code) print "" title " · Table " code " · " name[code] "" > path else print "" title " · Tables of Descent" > path print "" > path print "" > path print "" > path print "" > path print "
    " > path write_nav(code) print "
    " > path if (code) write_up(code) else { copy_file(table_boiler1) print "
    " > path } write_who(code) if (!code) { print "

    " > path copy_file(table_boiler2) } print "
    " > path if (!code) { print "
      " > path print "
    • " root_name > path print "
        " > path write_master("") print "
      " > path print "
    " > path } print "" > path print "" > path close(path) # each child which in turn has children gets its own page for (k = 1; k <= total_kids[code]; k++) { kid = child_of[code, k] if (total_kids[kid]) write_page(kid) } } # write page navigation (nav bar and up, left, right) ### function write_nav(code) { top_dir = path_to(code, "") print "
    " > path print "" > path print "" > path if (!code) print "" > path else { left_code = prev_of[code] if (left_code) print "" > path else print "" > path } print "" > path if (!code) print "" > path else { right_code = next_of[code] if (right_code) print "" > path else print "" > path } print "" > path print "
    PreviousPreviousPrevious" TITLE "
    " > path print "About |" > path print "History |" > path print "Origin |" > path print "Letters |" > path if (code) print "Tables |" > path else print "Tables |" > path print "Deltas |" > path print "Gallery |" > path print "What's New" > path print "
    NextPreviousPrevious
    " > path print "
    " > path } # write "up" pointer ### function write_up(code) { if (level_of[code] == 1) { parent_code = "" up = "tables" html_ext } else { parent_code = parent_of[code] up = filename_of[parent_code] } top_dir = path_to(code, "") up_dir = path_to(code, parent_code) if (!parent_code) up_name = "Tables" else up_name = name[parent_code] " [" parent_code "]" print "Up
    " > path } # write special root entry for JAMES MACKY ### function write_root(path) { print "" > path print "" > path print "" > path print "" > path print "
    " root_name "
    " > path print "=
    " > path print root_spouse "

    " > path } # write main body of person's page: their data & children ### function write_who(code, tk) { if (!total_kids[code]) return level = level_of[code] if (code) print "
    " code "
    " > path else write_root(path) print "
    " name[code] "
    " > path write_bd(code) arr = arrival[code] if (arr) print "arr. " arr "
    " > path # if more than max_kids_row children, they go on multiple rows ### tk = total_kids[code] n_rows = int((tk - 1) / max_kids_row) + 1 per_row = round(tk / n_rows) max_row_cols = 0 nsp = n_spouse[code] if (!nsp) nsp = 1 cols_spouse = round(per_row / nsp) # figure how many columns are needed for each spouse ### for (si = 1; si <= nsp; si++) { sc = spouse_kids[code, si] if (n_rows > 1) if (sc > cols_spouse) sc = cols_spouse if (!sc) sc = 1 spouse_cols[si] = sc } n_cols = n_spouse[code] if (total_kids[code] > n_cols) n_cols = total_kids[code] print "" > path # output marrage dates, names, birth & death dates for all spouses ### print "" > path if (n_spouse[code]) { for (si = 1; si <= n_spouse[code]; si++) { if (si > 1) print "" > path } } else print "" > path print "" > path # output the children (possibly on several rows) ### ki = 1 for (ri = 1; ri <= n_rows; ri++) { print "" > path row_count = per_row for (si = 1; si <= nsp; si++) { ncols = spouse_cols[si] for (ci = 1; ci <= ncols; ci++) { sk = spouse_kids[code, si] if (!sk) { sk = kids[code] if (!sk) { print "" > path ki++ } } print "" > path } print "
    " > path ncols = spouse_cols[si] print "" > path # if multiple spouses, show spouse# in paren after = ### if (n_spouse[code] > 1) print "= (" si ") " marriage_date[code, si] "
    " > path else print "= " marriage_date[code, si] "
    " > path print "" spouse_name[code, si] "
    " > path write_spouse_bd(code, si) # always draw
    so valign-bottom works; but if no kids, # hr's in bg-color so it's effectively invisible ### hr = ((si == 1) && kids[code]) || spouse_kids[code, si] ? hr_color : body_color print "
    " > path print "

    " > path continue } } if (ci > sk) break kid_code = child_of[code, ki] if (!kid_code || !name[kid_code]) { print "" > path continue } # color alternating cells (checkerboard) ### ti = (ki > per_row) ? ((ki % (per_row + 1)) + 1) : ki if (((ti + ri) % 2) == 0) print "" > path else print "" > path if (total_kids[kid_code]) { down_dir = path_to(code, kid_code) print "" kid_code "
    " > path } else print "" kid_code "
    " > path print name[kid_code] "
    " > path write_bd(kid_code) ns = n_spouse[kid_code] if (ns == 1) { print "= " marriage_date[kid_code, 1] "
    " > path print spouse_name[kid_code, 1] "
    " > path if (!spouse_kids[kid_code, 1]) write_spouse_bd(kid_code, 1) } else if (ns > 1) { print " " > path for (sp = 1; sp <= ns; sp++) { print " " > path if (!spouse_kids[kid_code, sp]) write_spouse_bd(kid_code, sp) } print "
    = (" sp ") " marriage_date[kid_code, sp] "
    " > path print spouse_name[kid_code, sp] "
    " > path } print "
    " > path } # write birth & death line ### function write_bd(code) { return write_bd0(birth[code], death[code]) } function write_spouse_bd(code, si) { return write_bd0(spouse_birth[code, si], spouse_death[code, si]) } function write_bd0(b, d) { if (b && d) print "b." b " d." d "
    " > path else if (b) print "b." b "
    " > path else if (d) print "d." d "
    " > path } # return "rest of line" after first word ### function rest() { s = $2 for (i = 3; i <= NF; i++) s = s " " $i return s } # return ith child of code (e.g., A.1 child#2 is A.1.b) ### function child_code(code, i) { if (!code) return substr(Upper_AZ, i, 1) # start w/A B C... level = level_of[code] if (level % 2 == 1) return code "." i # add 1... if (level % 4 == 0) return code "." substr(Upper_AZ, i, 1) # add A else return code "." substr(Lower_AZ, i, 1) # add a } # replace the last part of a code ### function code_suffix(parts, n, new_last) { if (n == 1) return new_last code = parts[1] for (i = 2; i < n; i++) code = code "." parts[i] return code "." new_last } # remove all the dots from a code (e.g. B.1.d.1 -> B1d1) ### function undottify(code) { if (!code) return "0" n = split(code, parts, /\./) short = parts[1] for (i = 2; i <= n; i++) short = short parts[i] return short } # return path from one code to another. the top levels # are in the public top-level directory; lower levels in a password- # protected private subdirectory ### function path_to(from, to) { if ((level_of[from] <= public_levels) && (level_of[to] > public_levels)) return private_subdir if ((level_of[from] > public_levels) && (level_of[to] <= public_levels)) return "../" return "" } # copy file contents to path ### function copy_file(file) { while (getline < file) print $0 > path close(file) } # round up a positive floating-point number ### function round(i) { return int(i + 0.5) } # emit fatal error message and quit ### function fatal_error(msg) { print "!!! " msg " !!!" exit(1) } # EOF ###############################################################################