--- /dev/null
+#!/bin/sh
+
+# Copyright 2024 Paul Hänsch
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+# IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+. "$_EXEC/cgilite/cgilite.sh"
+. "$_EXEC/acl.sh"
+. "$_EXEC/tools.sh"
+. "$_EXEC/datetime.sh"
+
+tags='' ntags='' dir='' depth='' glob_system_pages=false
+label='' labeltype='' altlabel='' cnt=0
+
+set -- "$@" --
+while [ $# -gt 0 ]; do case $1 in
+ --system) glob_system_pages=true; shift 1;;
+ --depth) depth="$2" shift 2;;
+ \#*) tags="${tags}${tags:+ }${1###}"; shift 1;;
+ \!*) ntags="${ntags}${ntags:+ }${1##!}"; shift 1;;
+ --h1|--h2|--h3|--h4|--h5|--h6|--label)
+ labeltype="${1#--}" label="$2"; shift 2;;
+ --alt-label)
+ altlabel="$2"; shift 2;;
+ --) shift 1; break;;
+ *) if [ ! "$dir" ]; then
+ dir="$1"
+ set -- "$@" "$1"; shift 1;
+ elif [ ! "$depth" ]; then
+ depth="$1"; shift 1;
+ else
+ set -- "$@" "$1"; shift 1;
+ fi;;
+esac; done
+
+[ "$*" ] || set -- "*"
+[ "$depth" -ge 0 -o "$depth" -le 0 ] 2>&- || depth=0
+
+read DY DM DD <<-EOF
+ $(date +"%Y %m %d")
+ EOF
+
+dstart="$(date -d "${DY}-${DM}-01" +%s)"
+[ "$DM" -lt 12 ] \
+&& dend="$(date -d "${DY}-$(( ${DM#0} + 1))-01" +%s)" \
+|| dend="$(date -d "$(( ${DY#0} + 1))-01-01" +%s)"
+
+expand() {
+ local start="$1" end="$2" rrfreq="$3" rrint="$4" rrend="$5" evtitle="$6" evlink="$7"
+ local dstart dend
+ local nstart nend
+
+ [ "$rrend" -eq -1 ] && rrend=9999999999
+
+ case $rrint in
+ day)
+ nend=$(( rrfreq * 86400 - (dstart - end) % (rrfreq * 86400) + dstart ))
+ nstart=$(( start - end + nend))
+ debug "[ $nend -lt $dend -a $nstart -lt $rrend ]"
+ while [ "$nend" -lt "$dend" -a "$nstart" -lt "$rrend" ]; do
+ printf '%i %i %s %s\n' "$nstart" "$nend" "$evtitle" "$evlink"
+ # printf '%i %i %s\n' "$nstart" "$nend" "$evlink"
+ nstart="$((nstart + rrfreq * 86400))"
+ nend="$((nstart - start + end))"
+ done
+ ;;
+ week)
+ nend=$(( rrfreq * 604800 - (dstart - end) % (rrfreq * 604800) + dstart ))
+ nstart=$(( start - end + nend))
+ while [ "$nend" -lt "$dend" -a "$nstart" -lt "$rrend" ]; do
+ printf '%i %i %s %s\n' "$nstart" "$nend" "$evtitle" "$evlink"
+ nstart="$((nstart + rrfreq * 7 * 86400))"
+ nend="$((nstart - start + end))"
+ done
+ ;;
+ month)
+ { read _y _m _d; read y m d; } <<-EOF
+ $(date -d @$dstart +"%Y %_m %_d"
+ date -d @$start +"%Y %_m %_d"
+ )
+ EOF
+ _m=$((_y * 12 + _m)) m=$((y * 12 + m))
+ while :; do
+ m=$(( rrfreq - ((_m - m - 1) % rrfreq + 1) + _m ))
+ nstart="$(printf '%04i-%02i-%02i' "$(( (m - 1) / 12 ))" "$(( (m - 1) % 12 + 1 ))" "$d")"
+ if isdate "$nstart" && [ "$(date -d "$nstart" +%s)" -ge "$dstart" ]; then
+ break
+ fi >/dev/null
+ _m="$((_m + rrfreq))"
+ done
+ nstart="$(date -d "$nstart $start_time" +%s)"
+ nend="$((end - start + nstart))"
+ while [ "$nend" -lt "$dend" -a "$nstart" -lt "$rrend" ]; do
+ printf '%i %i %s %s\n' "$nstart" "$nend" "$evtitle" "$evlink"
+ m="$((m + rrfreq))"
+ nstart="$(printf '%04i-%02i-%02i' "$(( (m - 1) / 12 ))" "$(( (m - 1) % 12 + 1 ))" "$d")"
+ nstart="$(date -d "$nstart $start_time" +%s)"
+ nend="$((nstart - start + end))"
+ done
+ ;;
+ year)
+ { read _y _m _d; read y m d; } <<-EOF
+ $(date -d @$dstart +"%Y %_m %_d"
+ date -d @$start +"%Y %_m %_d"
+ )
+ EOF
+ while :; do
+ y=$(( rrfreq - ((_y - y - 1) % rrfreq + 1) + _y ))
+ nstart="$(printf '%04i-%02i-%02i' "$y" "$m" "$d")"
+ if isdate "$nstart" && [ "$(date -d "$nstart" +%s)" -ge "$dstart" ]; then
+ break
+ fi >/dev/null
+ _y="$((_y + rrfreq))"
+ done
+ nstart="$(date -d "$nstart $start_time" +%s)"
+ nend="$((end - start + nstart))"
+ while [ "$nend" -lt "$dend" -a "$nstart" -lt "$rrend" ]; do
+ printf '%i %i %s %s\n' "$nstart" "$nend" "$evtitle" "$evlink"
+ y="$((y + rrfreq))"
+ nstart="$(printf '%04i-%02i-%02i' "$y" "$m" "$d")"
+ nstart="$(date -d "$nstart $start_time" +%s)"
+ nend="$((nstart - start + end))"
+ done
+ ;;
+ *):
+ printf '%i %i %s %s\n' "$start" "$end" "$evtitle" "$evlink"
+ ;;
+ esac
+}
+
+events="$(
+ for dir in "$@"; do
+ page_glob "$dir" "$depth"
+ done \
+ | sort -u \
+ | while read -r page; do
+ pagedir="$(page_abs "$page")"
+ if [ -f "$_DATA/pages/${pagedir}/#events" ] \
+ && acl_read "$pagedir" \
+ && has_tags "$pagedir" $tags \
+ && ! has_tag "$pagedir" $ntags
+ then
+ cat "$_DATA/pages/${pagedir}/#events"
+ fi
+ done \
+ | while read -r junk1 tstart tend rrfreq rrint rrend evtitle evlink junk2; do
+ if [ "$tend" -gt "$dstart" -a "$tstart" -lt "$dend" ] \
+ || [ "$rrend" -gt "$dstart" -o "$rrend" -eq -1 ]; then
+ expand "$tstart" "$tend" "$rrfreq" "$rrint" "$rrend" "$evtitle" "$evlink"
+ fi
+ done \
+ | debug \
+ | sort -n
+)"
+
+lday=''
+
+printf '<ul class="macro calendar">\n'
+printf '%s\n' "${events}" \
+| while read start end name link; do
+ day="$((start / 86400))"
+ if [ "$day" != "$lday" ]; then
+ [ "$lday" ] && printf '</ul></li>'
+ date -d "@$start" +'<li><label>%A, %F</label><ul class="day">'
+ lday="$day"
+ fi
+ printf '<li>%s: <a href="%s">%s</a></li>' \
+ "$(date -d "@$start" +"%T")" "$(URL "${link%%#*}")#$(URL "${link#*#}")" "$(HTML "${name}")"
+done
+printf '</ul></li></ul>'