BEGIN {
BOM = "\357\273\277" # ByteOrderMark UTF-16/UTF-32
BOM_DISPLAY = "\\357\\273\\277"
CMD_MKDIR = "mkdir"
CMD_LINK_OR_COPY = "ln"
CMD_SHELL = "/bin/sh"
CMD_GREP = "grep"
CMD_DOIT = "_doit.sh"
if (FILE_PATTERN == "") FILE_PATTERN = "*.jpg"
if (MY_FLORA_ID == "") MY_FLORA_ID="83c7eaa3-ba10-5252-aaeb-7033c00bb1ca"
if (IN_DIR == "") IN_DIR = "."
if (OUT_DIR == "") OUT_DIR = "result"
if (system(CMD_MKDIR " " OUT_DIR))
error("Could not create output directory '" OUT_DIR "'.")
if (MODIFICATIONS_FILE == "") MODIFICATIONS_FILE = "local/modifications.csv"
if (system("test -r " MODIFICATIONS_FILE) != 0) MODIFICATIONS_FILE = ""
DATE = "date"
SCIENTIFIC_NAME = "scientific name"
NAME = "name"
NOTES = "notes"
TAGS = "tags"
UNKNOWN = "N.N."
SN_COUNT = 0
headers[1] = "lfd. Nr."
headers[2] = "wissenschaftlicher Name"
headers[3] = "Name"
headers[4] = "Zeitpunkte"
headers[5] = "Markierungen"
headers[6] = "Notizen"
headers_html[1] = "lfd. Nr."
headers_html[2] = "wissenschaftlicher Name"
headers_html[3] = "Name"
headers_html[4] = "Markierungen"
headers_html[5] = "Notizen"
SEPARATOR_INTEXT_PLAIN = "|"
SEPARATOR_INTEXT_CSV = "|"
SEPARATOR_INTEXT_HTML = " "
SEPARATOR_FIELD_PLAIN = "\t"
SEPARATOR_FIELD_CSV = ","
SEPARATOR_FIELD_HTML = ""
STARTER_FIELD_PLAIN = ""
STARTER_FIELD_CSV = "\""
STARTER_FIELD_HTML_HEAD = "
"
STARTER_FIELD_HTML_DATA = " | "
FINISHER_FIELD_PLAIN = ""
FINISHER_FIELD_CSV = "\""
FINISHER_FIELD_HTML_HEAD = ""
FINISHER_FIELD_HTML_DATA = " | "
SEPARATOR_RECORD_PLAIN = "\n"
SEPARATOR_RECORD_CSV = "\n"
SEPARATOR_RECORD_HTML = "\n"
STARTER_RECORD_PLAIN = ""
STARTER_RECORD_CSV = ""
STARTER_RECORD_HTML = ""
FINISHER_RECORD_PLAIN = ""
FINISHER_RECORD_CSV = ""
FINISHER_RECORD_HTML = "
"
SEPARATOR_TABLE_PLAIN = "\n"
SEPARATOR_TABLE_CSV = "\n"
SEPARATOR_TABLE_HTML = ""
STARTER_TABLE_PLAIN = ""
STARTER_TABLE_CSV = ""
STARTER_TABLE_HTML = "\n"
FINISHER_TABLE_PLAIN = "\n"
FINISHER_TABLE_CSV = "\n"
FINISHER_TABLE_HTML = "\n
\n"
map_field_plain["separator"] = SEPARATOR_FIELD_PLAIN
map_field_plain["starter"] = STARTER_FIELD_PLAIN
map_field_plain["finisher"] = FINISHER_FIELD_PLAIN
map_field_csv["separator"] = SEPARATOR_FIELD_CSV
map_field_csv["starter"] = STARTER_FIELD_CSV
map_field_csv["finisher"] = FINISHER_FIELD_CSV
map_field_html_head["separator"] = SEPARATOR_FIELD_HTML
map_field_html_head["starter"] = STARTER_FIELD_HTML_HEAD
map_field_html_head["finisher"] = FINISHER_FIELD_HTML_HEAD
map_field_html_data["separator"] = SEPARATOR_FIELD_HTML
map_field_html_data["starter"] = STARTER_FIELD_HTML_DATA
map_field_html_data["finisher"] = FINISHER_FIELD_HTML_DATA
map_record_plain["separator"] = SEPARATOR_RECORD_PLAIN
map_record_plain["starter"] = STARTER_RECORD_PLAIN
map_record_plain["finisher"] = FINISHER_RECORD_PLAIN
map_record_csv["separator"] = SEPARATOR_RECORD_CSV
map_record_csv["starter"] = STARTER_RECORD_CSV
map_record_csv["finisher"] = FINISHER_RECORD_CSV
map_record_html["separator"] = SEPARATOR_RECORD_HTML
map_record_html["starter"] = STARTER_RECORD_HTML
map_record_html["finisher"] = FINISHER_RECORD_HTML
map_table_plain["separator"] = SEPARATOR_TABLE_PLAIN
map_table_plain["starter"] = STARTER_TABLE_PLAIN
map_table_plain["finisher"] = FINISHER_TABLE_PLAIN
map_table_csv["separator"] = SEPARATOR_TABLE_CSV
map_table_csv["starter"] = STARTER_TABLE_CSV
map_table_csv["finisher"] = FINISHER_TABLE_CSV
map_table_html["separator"] = SEPARATOR_TABLE_HTML
map_table_html["starter"] = STARTER_TABLE_HTML
map_table_html["finisher"] = FINISHER_TABLE_HTML
PAGE_FORMAT_START = "\n" \
"\n" \
"" \
"%s\n\n"
PAGE_FORMAT_HEADLINES = "%s
\n%s
\n"
PAGE_FORMAT_END = "
\n\n\n"
IMAGE_WIDTH = 236
IMAGE_HEIGHT = 512
}
function output(outfile, s) {
printf "%s", s >> outfile
}
function check_BOMid(s) {
if (s != BOM "id") {
error("Header line does not start with field '" BOM_DISPLAY "id', but with '" s "'.")
}
}
function merge_strings(old, new) {
if (new == "") return old
if (old == "") return new
merged = old
split(new, newvalues, SEPARATOR_INTEXT_PLAIN)
split(old, oldvalues, SEPARATOR_INTEXT_PLAIN)
for (n in newvalues) {
nv = newvalues[n]
isnew = 1
for (o in oldvalues)
if (nv == oldvalues[o]) {
isnew = 0
break
}
if (isnew == 1)
merged = merged SEPARATOR_INTEXT_PLAIN nv
}
delete newvalues
delete oldvalues
return merged
}
function field2href(field, target) {
if (FORMAT != "HTML") return field
if (target == "") target = field "/index.html"
return "" field ""
}
function format_line(outfile, key, value) {
if (value != "")
output(outfile, "" key ": " value "
\n")
}
function format_navigation(outfile, array, array2, i) {
output(outfile, "\n")
}
function format_record(outfile, map_field, map_record, fields) {
output(outfile, map_record["starter"])
for (i = 1; i in fields; i++)
output(outfile, (i == 1 ? "" : map_field["separator"]) \
map_field["starter"] \
(FORMAT == "CSV" ? quote_csv(fields[i]) : fields[i]) \
map_field["finisher"])
output(outfile, map_record["finisher"])
}
function format_table(outfile, map_field_head, map_field_data, map_record_head, map_record_data, map_table, headers, master, a1, a2, a3, a4) {
output(outfile, map_table["starter"])
format_record(outfile, map_field_head, map_record_head, headers)
for (j = 1; j in master; j++) {
mstr = master[j]
data[1] = j
data[2] = field2href(mstr)
data[3] = a1[mstr]
if (FORMAT == "HTML") {
data[4] = a3[mstr]
data[5] = a4[mstr]
}
else {
data[4] = a2[mstr]
data[5] = a3[mstr]
data[6] = a4[mstr]
}
output(outfile, map_record_data["separator"])
format_record(outfile, map_field_data, map_record_data, data)
}
output(outfile, map_table["finisher"])
}
function create_subdir_cmd(outfile, outdir) {
output(outfile, CMD_MKDIR " '" outdir "'\n")
}
function collect_files_cmd(outfile, dates, pattern, outdir) {
n = split(dates, d, "\\" SEPARATOR_INTEXT_PLAIN)
for (i = 1; i <= n; i++) {
date = d[i]
output(outfile, CMD_LINK_OR_COPY " '" IN_DIR "/" date "/'" pattern " '" outdir "'\n")
}
}
function filename2datetime(filename) {
# 2025-09-07T12_20_51Z-2.jpg
d1 = substr(filename, 1, 10)
t1 = substr(filename, 12, 8)
gsub("_", ":", t1)
return d1 " " t1
}
function normalise_datetimes(datetimes) {
datecount = split(datetimes, d, SEPARATOR_INTEXT_PLAIN)
for (i = 1; i <= datecount; i++)
datelist = (i == 1 ? "" : datelist ", ") filename2datetime(d[i])
delete d
return datelist
}
function format_images(outfile, sn, files) {
output(outfile, "\n")
for (i = 1; i in files; i++) {
fn = files[i]
alt = sn " @ " filename2datetime(fn) " GMT"
output(outfile, (i == 1 ? "" : "\n") \
"" \
"
" \
"")
}
output(outfile, "\n
\n")
}
function apply_modifications(modfile) {
result = getline < modfile
if (result < 1) return result
for (i = 1; i <= NF; i++) column[$i] = i
scientific_name_field = column[SCIENTIFIC_NAME]
#date_field = column[DATE]
name_field = column[NAME]
note_field = column[NOTES]
tags_field = column[TAGS]
line_count = 1
mod_count = 0
while (getline < modfile > 0) {
line_count++
sn = $scientific_name_field
#print "line " line_count ", sn = " sn
if (sn == "")
error("Empty field \"" SCIENTIFIC_NAME \
"\" in file \"" modfile \
"\", line " line_count ".")
if (SN_COUNT == 0 || ! (sn in sns)) {
sni[++SN_COUNT] = sn
sns[sn] = SN_COUNT
# debug
print "New plant: \"" sn "\", nr. " SN_COUNT \
", in file \"" modfile \
"\", line " line_count "."
}
#sn_names[sn] = merge_strings(sn_names[sn], $name_field)
sn_names[sn] = $name_field
#sn_dates[sn] = merge_strings(sn_dates[sn], $date_field)
sn_notes[sn] = $note_field
sn_tagss[sn] = $tags_field
}
}
# Alfred V. Aho, Brian W. Kernighan, Peter J. Weinberger:
# The AWK programming language. 1988. p. 161
function qsort(A, left, right, i, last) {
if (left >= right) # do nothing if array contains
return # less than two elements
swap(A, left, left + int((right-left+1)*rand()))
last = left # A[left] is now partition element
for (i = left+1; i <= right; i++)
if (A[i] < A[left])
swap(A, ++last, i)
swap(A, left, last)
qsort(A, left, last-1)
qsort(A, last+1, right)
}
function swap(A,i,j,t) {
t = A[i]; A[i] = A[j]; A[j] = t
}
FNR == 1 {
check_BOMid($1)
for (i = 2; i <= NF; i++) column[$i] = i
scientific_name_field = column[SCIENTIFIC_NAME]
date_field = column[DATE]
name_field = column[NAME]
note_field = column[NOTES]
tags_field = column[TAGS]
}
$1 == MY_FLORA_ID {
if ($scientific_name_field == "") sn = UNKNOWN
else sn = $scientific_name_field
if (SN_COUNT == 0 || ! (sn in sns)) {
sni[++SN_COUNT] = sn
sns[sn] = SN_COUNT
}
# scientific_name[recnr] = sn
# name[recnr] = $name_field
# date[recnr] = $date_field
# notes[recnr] = $note_field
# tags[recnr] = $tags_field
sn_names[sn] = merge_strings(sn_names[sn], $name_field)
sn_dates[sn] = merge_strings(sn_dates[sn], $date_field)
sn_notes[sn] = merge_strings(sn_notes[sn], $note_field)
sn_tagss[sn] = merge_strings(sn_tagss[sn], $tags_field)
}
END {
if (MODIFICATIONS_FILE != "")
apply_modifications(MODIFICATIONS_FILE)
else print "No file with modifications to apply."
# sorting sni makes sns useless
qsort(sni, 1, SN_COUNT)
#for (c in column) print c ": " column[c]
#for (i in sni) print sni[i]
#for (sn in sn_dates)
# printf "(%i) %s: %s\t%s\t%s\t%s\n",
# sns[sn], sn, sn_names[sn], sn_dates[sn], sn_notes[sn], sn_tagss[sn]
#for (i = 1; i in sni; i++) {
# sn = sni[i]
# printf "(%i) %s: %s\t%s\t%s\t%s\n",
# sns[sn], sn, sn_names[sn], sn_dates[sn], sn_notes[sn], sn_tagss[sn]
# }
#arrays2table(headers, master, arrays) array von arrays geht nicht
#arrays2table(FORMAT, headers, sni, sn_names, sn_dates, sn_notes, sn_tagss)
fmt[1] = "plain"
fmt[2] = "CSV"
fmt[3] = "HTML"
for (i in fmt) {
FORMAT = fmt[i]
indexfile = OUT_DIR "/index." tolower(FORMAT)
printf "%s", "" > indexfile
if (fmt[i] == "plain")
format_table(indexfile, map_field_plain, map_field_plain, map_record_plain, map_record_plain, map_table_plain, headers, sni, sn_names, sn_dates, sn_tagss, sn_notes)
else if (fmt[i] == "CSV")
format_table(indexfile, map_field_csv, map_field_csv, map_record_csv, map_record_csv, map_table_csv, headers, sni, sn_names, sn_dates, sn_tagss, sn_notes)
else if (fmt[i] == "HTML")
format_table(indexfile, map_field_html_head, map_field_html_data, map_record_html, map_record_html, map_table_html, headers_html, sni, sn_names, sn_dates, sn_tagss, sn_notes)
}
# Klammern wg. mawk
close(indexfile)
delete fmt
FORMAT = "HTML"
cmdfile = OUT_DIR "/" CMD_DOIT
logfile = cmdfile ".out"
printf "%s", "" > cmdfile
for (j = 1; j in sni; j++) {
mstr = sni[j]
create_subdir_cmd(cmdfile, OUT_DIR "/" mstr)
if (sn_dates[mstr] != "")
collect_files_cmd(cmdfile, sn_dates[mstr], "*.jpg", OUT_DIR "/" mstr)
}
close(cmdfile)
if (system(CMD_SHELL " -x " cmdfile " > " logfile " 2>&1"))
error("Copying files to output directories failed. See " logfile ".")
system(CMD_GREP " -v ^+ " logfile " >> /dev/stderr")
if (OBSOLETE_SCRIPT != "")
system("[ ! -x " OBSOLETE_SCRIPT " ] || " OBSOLETE_SCRIPT)
# index.html je Spezies
for (j = 1; j in sni; j++) {
mstr = sni[j]
outdir = OUT_DIR "/" mstr
subindexfile = outdir "/index.html"
printf PAGE_FORMAT_START, mstr " - " sn_names[mstr] \
> subindexfile
format_navigation(subindexfile, sni, sn_names, j)
printf PAGE_FORMAT_HEADLINES, mstr, sn_names[mstr] \
> subindexfile
format_line(subindexfile, "Markierungen", sn_tagss[mstr])
format_line(subindexfile, "Notizen", sn_notes[mstr])
if (sn_dates[mstr] != "")
format_line(subindexfile, "Zeitpunkte (GMT)",
normalise_datetimes(sn_dates[mstr]))
i = 0
flist = ""
# string zuerst in Variable wg. mawk 1.3.4
lscmd = "( cd '" outdir "' && ls " FILE_PATTERN ")"
while ( lscmd | getline file == 1) {
files[++i] = file
flist = merge_strings(flist, file)
}
#sn_files[mstr] = flist
format_images(subindexfile, mstr, files)
format_navigation(subindexfile, sni, sn_names, j)
output(subindexfile, PAGE_FORMAT_END)
close(subindexfile)
delete files
}
}