]> git.plutz.net Git - shellwiki/blob - macros/calendar
type in calendar links
[shellwiki] / macros / calendar
1 #!/bin/sh
2 # vi:syntax=bash
3
4 # Copyright 2024 Paul Hänsch
5
6 # Permission to use, copy, modify, and/or distribute this software for any
7 # purpose with or without fee is hereby granted, provided that the above
8 # copyright notice and this permission notice appear in all copies.
9
10 # THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 # SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
16 # IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18
19 . "$_EXEC/cgilite/cgilite.sh"
20 . "$_EXEC/acl.sh"
21 . "$_EXEC/tools.sh"
22 . "$_EXEC/datetime.sh"
23
24 tags='' ntags='' dir='' depth='' glob_system_pages=false
25 label='' labeltype='' altlabel='' cnt=0
26
27 set -- "$@" --
28 while [ $# -gt 0 ]; do case $1 in
29   --system) glob_system_pages=true; shift 1;;
30   --depth)  depth="$2" shift 2;;
31   \#*) tags="${tags}${tags:+ }${1###}"; shift 1;;
32   \!*) ntags="${ntags}${ntags:+ }${1##!}"; shift 1;;
33   --date|--from) fromdate="$2"; shift 2;;
34   --weekstart|--ws|-ws) ws="$2"; shift 2;;
35   --) shift 1; break;;
36   *) if [ ! "$dir" ]; then
37       dir="$1"
38       set -- "$@" "$1"; shift 1;
39     elif [ ! "$depth" ]; then
40       depth="$1"; shift 1;
41     else
42       set -- "$@" "$1"; shift 1;
43     fi;;
44 esac; done
45
46 [ "$*" ] || set -- "."
47 [ "$depth" -ge 0 -o "$depth" -le 0 ] 2>&- || depth=0
48
49 read DY DM DD <<-EOF
50         $(isdate "$fromdate" \
51           && date -ud "$fromdate" +"%Y %m %d" \
52           || date -u +"%Y %m %d"
53         )
54         EOF
55
56 case $ws in
57   0|[sS]*) ws=0;;
58   1|[mM]*) ws=1;;
59   *) ws=0;;
60 esac
61
62 rrexpand() {
63   # Recurrence Expansion
64   # read recurring event specifications and expand them to a list of
65   # single events within the specified time frame
66
67   local dstart="$1" dend="$2"
68   local junk1 start end rrfreq rrint rrend evtitle evlink junk2
69
70   while read -r junk1 start end rrfreq rrint rrend evtitle evlink junk2; do
71     [ ! "$start" ] && continue  # empty line
72     [ "$rrend" -eq -1 ] && rrend=9999999999
73
74     if [ "$start" -lt "$dend" ] &&
75        [ "$end" -gt "$dstart" -o "$rrend" -gt "$dstart" ]; then
76       case $rrint in
77         day) rrex_day;;
78         week) rrex_week;;
79         month) rrex_month;;
80         year) rrex_year;;
81         weekday)
82           [ "$rrfreq" -ge 0 ] && rrex_weekday \
83                               || rrex_lastweekday
84           ;;
85         *):
86           printf '%i    %i      %s      %s\n' "$start" "$end" "$evtitle" "$evlink"
87           ;;
88       esac
89     fi
90   done
91 }
92
93 rrex_day() {
94   # helper for rrexpand daily/N-day expansion
95   local nstart nend
96
97   nend=$(( rrfreq * 86400 - (dstart - end) % (rrfreq * 86400) + dstart ))
98   nstart=$(( start - end + nend))
99   while [ "$nstart" -lt "$rrend" -a "$nstart" -lt "$dend" ]; do
100     [ "$nstart" -ge "$start" ] \
101     && printf '%i       %i      %s      %s\n' "$nstart" "$nend" "$evtitle" "$evlink"
102     nstart="$((nstart + rrfreq * 86400))"
103       nend="$((nstart - start + end))"
104   done
105 }
106
107 rrex_week() {
108   # helper for rrexpand weekly/N-week expansion
109   local nstart nend
110
111   nend=$(( 0 * 604800 - (dstart - end) % (rrfreq * 604800) + dstart ))
112   nstart=$(( start - end + nend))
113   while [ "$nstart" -lt "$rrend" -a "$nstart" -lt "$dend" ]; do
114     [ "$nstart" -ge "$start" -a "$nstart" -ge "$dstart" ] \
115     && printf '%i       %i      %s      %s\n' "$nstart" "$nend" "$evtitle" "$evlink"
116     nstart="$((nstart + rrfreq * 7 * 86400))"
117       nend="$((nstart - start + end))"
118   done
119 }
120
121 rrex_month() {
122   # helper for rrexpand monthly/N-month expansion
123   local nstart nend
124
125   { read _y _m _d; read y m d start_time; } <<-EOF
126         $(date -ud @$dstart +"%Y %_m %_d"
127           date -ud @$start  +"%Y %_m %_d %T"
128         )
129         EOF
130   _m=$((_y * 12 + _m)) m=$((y * 12 + m))
131   while :; do
132     m=$(( rrfreq - ((_m - m - 1) % rrfreq + 1) + _m ))
133     nstart="$(printf '%04i-%02i-%02i' "$(( (m - 1) / 12 ))" "$(( (m - 1) % 12 + 1 ))" "$d")"
134     if isdate "$nstart" && [ "$(date -ud "$nstart" +%s)" -ge "$dstart" ]; then
135       break
136     fi >/dev/null
137     _m="$((_m + rrfreq))"
138   done
139   nstart="$(date -ud "$nstart $start_time" +%s)"
140     nend="$((end - start + nstart))"
141   while [ "$nstart" -lt "$rrend" -a "$nstart" -lt "$dend" ]; do
142     [ "$nstart" -ge "$start" ] \
143     && printf '%i       %i      %s      %s\n' "$nstart" "$nend" "$evtitle" "$evlink"
144     m="$((m + rrfreq))"
145     nstart="$(printf '%04i-%02i-%02i' "$(( (m - 1) / 12 ))" "$(( (m - 1) % 12 + 1 ))" "$d")"
146     nstart="$(date -ud "$nstart $start_time" +%s)"
147       nend="$((nstart - start + end))"
148   done
149 }
150
151 rrex_year() {
152   # helper for rrexpand yearly/N-year expansion
153   local nstart nend
154
155   { read _y _m _d; read y m d start_time; } <<-EOF
156         $(date -ud @$dstart +"%Y %_m %_d"
157           date -ud @$start  +"%Y %_m %_d %T"
158         )
159         EOF
160   while :; do
161     y=$(( rrfreq - ((_y - y - 1) % rrfreq + 1) + _y ))
162     nstart="$(printf '%04i-%02i-%02i' "$y" "$m" "$d")"
163     if isdate "$nstart" && [ "$(date -ud "$nstart" +%s)" -ge "$dstart" ]; then
164       break
165     fi >/dev/null
166     _y="$((_y + rrfreq))"
167   done
168   nstart="$(date -ud "$nstart $start_time" +%s)"
169     nend="$((end - start + nstart))"
170   while [ "$nstart" -lt "$rrend" -a "$nstart" -lt "$dend" ]; do
171     [ "$nstart" -ge "$start" ] \
172     && printf '%i       %i      %s      %s\n' "$nstart" "$nend" "$evtitle" "$evlink"
173     y="$((y + rrfreq))"
174     nstart="$(printf '%04i-%02i-%02i' "$y" "$m" "$d")"
175     nstart="$(date -ud "$nstart $start_time" +%s)"
176       nend="$((nstart - start + end))"
177   done
178 }
179
180 rrex_weekday() {
181   # helper for rrexpand: Nth weekday of a month (e.g. 2nd tuesday, etc.)
182   local nstart nend
183
184   nth=$(( ( $(date -ud @$start +%_d) - 1) / 7))
185
186   nend=$(( 0 * 604800 - (dstart - end) % 604800 + dstart ))
187   nstart=$(( start - end + nend))
188
189   while [ "$nstart" -lt "$rrend" -a "$nstart" -lt "$dend" ]; do
190     [ "$nstart" -ge "$start" -a "$nstart" -ge "$dstart" ] \
191     && [ "$(( ( $(date -ud @$nstart +%_d) -1) / 7 ))" -eq "$nth" ] \
192     && printf '%i       %i      %s      %s\n' "$nstart" "$nend" "$evtitle" "$evlink"
193     nstart="$((nstart + 7 * 86400))"
194       nend="$((nstart - start + end))"
195   done
196 }
197
198 rrex_lastweekday() {
199   # helper for rrexpand: Nth last weekday of a month (e.g. 2nd last tuesday, etc.)
200   local nstart nend Y m d nth
201
202   read Y m d <<-EOF
203         $(date -ud @$start +"%Y %_m %_d")
204         EOF
205   nth=$(( ( $(numdays $Y $m) - d ) / 7))
206
207   nend=$(( 0 * 604800 - (dstart - end) % 604800 + dstart ))
208   nstart=$(( start - end + nend))
209
210   while [ "$nstart" -lt "$rrend" -a "$nstart" -lt "$dend" ]; do
211     read Y m d <<-EOF
212         $(date -ud @$nstart +"%Y %_m %_d")
213         EOF
214     [ "$nstart" -ge "$start" -a "$nstart" -ge "$dstart" ] \
215     && [ "$(( ( $(numdays $Y $m) - d ) / 7 ))" -eq "$nth" ] \
216     && printf '%i       %i      %s      %s\n' "$nstart" "$nend" "$evtitle" "$evlink"
217     nstart="$((nstart + 7 * 86400))"
218       nend="$((nstart - start + end))"
219   done
220 }
221
222 events="$(
223   for dir in "$@"; do
224     page_glob "$dir" "$depth"
225   done \
226   | sort -u \
227   | while read -r page; do
228     pagedir="$(page_abs "$page")"
229     if [ -f "$_DATA/pages/${pagedir}/#events" ] \
230        && acl_read "$pagedir" \
231        && has_tags "$pagedir" $tags \
232        && ! has_tag "$pagedir" $ntags
233     then
234       cat "$_DATA/pages/${pagedir}/#events"
235     fi
236   done
237 )"
238
239 cal_list() {
240   # Print list view for upcoming events
241   local lday='' events sdate=$(date -ud "${DY}-${DM}-${DD}" +%s)
242
243   events="$(
244     printf %s\\n "$events" \
245     | rrexpand "$sdate" "$((sdate + 42 * 86400))" \
246     | sort -n
247   )"
248   
249   printf '<ul class="macro calendar cal_list">\n'
250   printf '%s\n' "${events}" \
251   | while read start end name link; do
252     day="$((start / 86400))"
253     if [ "$day" != "$lday" ]; then
254       [ "$lday" ] && printf '</ul></li>'
255       date -ud "@$start" +'<li><label>%A, %F</label><ul class="day">'
256       lday="$day"
257     fi
258     printf '<li>%s - <a href="%s">%s</a></li>' \
259            "$(date -ud "@$start" +"%H:%M")" "$(URL "${link%%#*}")#$(URL "${link#*#}")" "$(HTML "${name}")"
260   done
261   printf '</ul></li></ul>'
262 }
263
264 cal_month() {
265   local ws events calmonth
266   local iday idow mname dcnt dow dcal start end title link n
267
268   calmonth="$(GET calmonth || printf %i "$((DY * 12 + DM))")"
269   DY="$(( (calmonth - 1) / 12 ))"
270   DM="$(( (calmonth - 1) % 12 + 1 ))"
271
272   read -r iday idow mname <<-EOF
273         $(date -ud "${DY}-${DM}-01" +"%s        %u      %B")
274         EOF
275   dcnt=$((iday - idow * 86400 + ws * 86400))
276    dow=$ws
277   dcal="$(date -ud @"$dcnt" +%d)"
278   events="$(
279     printf %s\\n "$events" \
280     | rrexpand "$dcnt" "$((dcnt + 42 * 86400))" \
281     | sort -n
282   )"
283
284   printf '<table class="macro calendar cal_month">'
285   printf '<thead><tr><th><a href="%s">&lt;</a></th><th colspan=5>%s</th><th><a href="%s">&gt;</a></th></tr><tr>' \
286     "./?calmonth=$((DY * 12 + DM -1))" "$mname" "./?calmonth=$((DY * 12 + DM + 1))"
287   for n in 0 1 2 3 4 5 6; do date -ud @"$((dcnt + n * 86400))" +'<th>%a</th>'; done
288   printf '</tr></thead><tbody>'
289   while :; do
290     [ $dow = $ws ] && printf '<tr>'
291     printf '<td><label>%02i</label>' "$dcal"
292
293     evlist="$(
294       printf %s "${events}${events:+${BR}}" \
295       | while read start end title link; do
296         if [ "$((start / 86400))" -lt "$((dcnt / 86400))" -a "$end" -gt "$dcnt" ]; then
297           printf '<li><a href="%s\#%s">%s</a></li>' \
298             "$(UNSTRING "${link%%#*}" |URL)" \
299             "$(UNSTRING "${link#*#}" |URL)" \
300             "$(UNSTRING "$title" |HTML)"
301         elif [ "$((start / 86400))" -eq "$((dcnt / 86400))" ]; then
302           printf '<li>%s - <a href="%s#%s">%s</a></li>' \
303             "$(date -ud @"$start" +%H:%M)" \
304             "$(UNSTRING "${link%%#*}" |URL)" \
305             "$(UNSTRING "${link#*#}" |URL)" \
306             "$(UNSTRING "$title" |HTML)"
307         fi
308       done
309     )"
310     [ "$evlist" ] && printf '<ul>%s</ul>' "$evlist"
311
312     printf '</td>\n'
313     [ $dow = $(( (ws + 6) % 7)) ] && printf '</tr>\n'
314
315     dcnt=$(( dcnt + 86400 ))
316      dow=$(( (dow + 1) % 7 ))
317     [ $dcal -lt 28 ] \
318     && dcal=$((dcal + 1)) \
319     || dcal=$(date -ud @"$dcnt" +%d)
320     [ $dcnt -gt $((iday + 28 * 86400)) -a $dcal -le 7 -a $dow = $ws ] \
321     && break
322   done
323   printf '</tbody></table>'
324 }
325
326 # cal_list
327 cal_month