]> git.plutz.net Git - shellwiki/blob - macros/event
2bf3b05770c50882a93756242737c8ca94ec4a4a
[shellwiki] / macros / event
1 #!/bin/sh
2
3 . $_EXEC/cgilite/cgilite.sh
4 . $_EXEC/cgilite/session.sh
5
6 _(){ printf %s\\n "$*"; }
7 [ "${LANGUAGE}" -a -r "${_EXEC}/l10n/${LANGUAGE}.sh" ] && . "${_EXEC}/l10n/${LANGUAGE}.sh"
8
9 start_date= start_time= end_date= end_time=
10 rec_freq= rec_int= error_msg= rec_end=
11 title=
12 start= end= nstart= nend=
13
14 isdate(){
15   local date="$1" y m d
16
17   if   printf %s "$date" \
18     | grep -xEq '[0-9]{4}-((01|03|05|07|08|10|12)-(0[1-9]|[12][0-9]|3[01])|(04|06|09|11)-(0[1-9]|[12][0-9]|30)|02-(0[1-9]|[12][0-9]))'
19   then  # y-m-d (ISO Date)
20     y="${date%%-*}" d="${date##*-}" m="${date%-*}" m="${m#*-}"
21   elif printf %s "$date" \
22     | grep -xEq '((0?1|0?3|0?5|0?7|0?8|10|12)/(0?[1-9]|[12][0-9]|3[01])|(0?4|0?6|0?9|11)/(0?[1-9]|[12][0-9]|30)|0?2-(0[1-9]|[12][0-9]))/([0-9]{2}|[0-9]{4})'
23   then  # m/d/y (US Date)
24     y="${date##*/}" m="${date%%/*}" d="${date%/*}" d="${d#*/}"
25   elif printf %s "$date" \
26     | grep -xEq '((0?[1-9]|[12][0-9]|3[01])[\./](0?1|0?3|0?5|0?7|0?8|10|12)|(0?[1-9]|[12][0-9]|30)[\./](0?4|0?6|0?9|11)|(0[1-9]|[12][0-9])[\./]0?2)[\./]([0-9]{2}|[0-9]{4})'
27   then  # d/m/y or d.m.y (European Date / German Date)
28     y="${date##*.}" d="${date%%.*}" m="${date%.*}" m="${m#*.}"
29   else
30     return 1
31   fi
32   [ $y -lt 100 -a $y -gt 50 ] && y=$((y + 1900))
33   [ $y -lt 100 -a $y -le 50 ] && y=$((y + 2000))
34   date="$(printf "%04i-%02i-%02i" $y ${m#0} ${d#0})"
35
36   # leap year
37   if [ "$m" -eq 2 -a "$d" -eq 29 ]; then
38     if   [ "$((y % 400))" -eq 0 ]; then
39       :
40     elif [ "$((y % 100))" -eq 0 ]; then
41       return 1
42     elif [ "$((y % 4))" -eq 0 ]; then
43       :
44     else
45       return 1
46     fi
47   fi
48
49   printf '%04i-%02i-%02i\n' "$y" "${m#0}" "${d#0}"
50   return 0
51 }
52
53 istime(){
54   time="$1" h= m=
55
56   if   printf %s "$time" | grep -xEq '(0?[1-9]|1[012])(:[0-5][0-9])? ?(am|AM)\.?'; then
57     time="${time%?[aA][mM]}" h="${time%:*}" h="$(h % 12)"
58     [ "$h" != "$time" ] && m="${time#*:}" || m=0
59   elif printf %s "$time" | grep -xEq '(0?[1-9]|1[012])(:[0-5][0-9])? ?(pm|PM)\.?'; then
60     time="${time%?[aA][mM]}" h="${time%:*}" h="$(h % 12 + 12)"
61     [ "$h" != "$time" ] && m="${time#*:}" || m=0
62   elif printf %s "$time" | grep -xEq '(0?[0-9]|1[0-9]|2[0-3]):[0-5][0-9]'; then
63     time="${time%?[aA][mM]}" h="${time%:*}" m="${time#*:}"
64   else
65     return 1
66   fi
67
68   printf '%02i:%02i\n' "${h#0}" "${m#0}"
69   return 0
70 }
71
72 while [ $# -gt 0 ]; do case $1 in
73   --from|from|--start|start)
74     if   isdate "$2" && istime "$3" ; then
75       start_date="$(isdate "$2" )" start_time="$(istime "$3")"
76       shift 3
77     elif isdate "${2%% *}" && istime "${2#* }" ; then
78       start_date="$(isdate "${2%% *}" )" start_time="$(istime "${2#* }")"
79       shift 2
80     elif isdate "$2" ; then
81       start_date="$(isdate "$2")" start_time="00:00"
82       shift 2
83     else
84       error_msg="Event start should be \"YYYY-MM-DD\" or \"YYYY-MM-DD hh:mm\""
85       shift 1
86     fi >/dev/null
87     ;;
88   --to|to|--end|end)
89     if   isdate "$2" && istime "$3"; then
90       end_date="$(isdate "$2")" end_time="$(istime "$3")"
91       shift 3
92     elif isdate "${2%% *}" && istime "${2#* }"; then
93       end_date="$(isdate "${2%% *}")" end_time="$(istime "${2#* }")"
94       shift 2
95     elif isdate "$2"; then
96       end_date="$(isdate "$2")" end_time="23:59"
97       shift 2
98     elif istime "$2"; then
99       end_time="$(istime "$2")"
100       shift 2
101     else
102       error_msg="Event end should be \"YYYY-MM-DD\" or \"YYYY-MM-DD hh:mm\" or \"hh:mm\""
103       shift 1
104     fi >/dev/null
105     ;;
106   --repeat|--recur|--recurrence|--every|every)
107     if expr "$2" : '^[0-9]\+$' &&
108        expr "$3" : '^\(days\|nights\|weeks\|months\|years\|weekday\)$'; then
109       rec_freq="$2" rec_int="$3"
110       shift 3
111     elif expr "$2" : '^[0-9]\+ \+\(days\|nights\|weeks\|months\|years\|weekday\)$'; then
112       rec_freq="${2%% *}" rec_int="${2##* }"
113       shift 2
114     elif expr "$2" : '^\(day\|daily\|night\|nightly\|week\|weekly\|month\|monthly\|year\|yearly\|annually\)$'; then
115       rec_freq="1" rec_int="$2"
116       shift 2
117     elif expr "$2" : '^last weekday$'; then
118       rec_freq="-1" rec_int="weekday"
119       shift 2
120     elif expr "$2 $3" : '^last weekday$'; then
121       rec_freq="-1" rec_int="weekday"
122       shift 3
123     elif expr "$2" : '^\(biweekly\|bimonthly\)$'; then
124       rec_freq="2" rec_int="$2"
125       shift 2
126     else
127       error_msg="Recurrence should be \"N days|weeks|months|years\" or \"N|last weekday\""
128       shift 1
129     fi >/dev/null
130     ;;
131   --until|until)
132     if isdate $2; then
133       rec_end="$(isdate "$2")"
134       shift 2
135     else
136       error_msg="Recurrence end should be \"YYYY-MM-DD\""
137       shift 1
138     fi >/dev/null
139     ;;
140   --title)
141     title="$2"
142     shift 2
143     ;;
144   *) shift 1;;
145 esac; done
146
147 if [ ! "$end_time" ]; then
148   end_time="23:59"
149 fi
150
151 if [ ! "$end_date" -a "$end_time" -a "$start_time" ]; then
152   if [ "$((${end_time%:*} * 60 + ${end_time#*:}))" -gt "$((${start_time%:*} * 60 + ${start_time#*:}))" ]; then
153     end_date="$start_date"
154   else
155     end_date="$(date -d "@$(($(date -d "$start_date" +%s) + 86400))" +%F)"
156   fi
157 fi
158
159 if [ ! "$start_date" ]; then
160   error_msg="Event needs start date, e.g. --start \"YYYY-MM-DD\""
161 fi
162
163 if [ ! "$title" ]; then
164   error_msg="Event needs title, e.g. --title \"Event Name\""
165 fi
166
167 if [ "$error_msg" ]; then
168   _ "$error_msg"
169   exit 1
170 fi
171
172 case $rec_int in
173   day|daily|days|night|nightly|nights)
174     rec_int="day";;
175   week|weeks|weekly|biweekly)
176     rec_int="week";;
177   month|monthly|months|bimonthly)
178     rec_int="month";;
179   year|yearly|years|annually)
180     rec_int="year";;
181 esac
182
183 if [ "$rec_end" ]; then
184   rec_end="$(date -d "$rec_end" +%s)"
185 fi
186
187 if [ -s './#events' ]; then
188   t1="$(stat -c %Y './#page.md')"
189   read t2 junk <"./#events"
190   if [ "$t1" -ge "$t2" ]; then
191     truncate -s 0 "./#events"
192   fi
193 fi
194
195 printf '%i      %i      %i      %i      %s      %i\n' \
196   "$_DATE" "$(date -d "$start_date $start_time" +%s)" "$(date -d "$end_date $end_time" +%s)" \
197   "${rec_freq:-0}" "${rec_int:-\\}" "${rec_end:--1}" \
198   >>'./#events'
199
200 start="$(date -d "$start_date $start_time" +%s)"
201   end="$(date -d "$end_date $end_time" +%s)"
202
203 if [ $_DATE -le $end ]; then
204   nstart="$start" nend="$end"
205 fi
206
207 [ $_DATE -gt $end ] && case $rec_int in
208   day)
209     nend=$(( rec_freq * 86400 - (_DATE - end) % (rec_freq * 86400) + _DATE ))
210     nstart=$(( start - end + nend))
211     ;;
212   week)
213     nend=$(( rec_freq * 604800 - (_DATE - end) % (rec_freq * 604800) + _DATE ))
214     nstart=$(( start - end + nend))
215     ;;
216   month)
217     { read _y _m _d; read y m d; } <<-EOF
218         $(date -d @$_DATE +"%Y %_m %_d"
219           date -d @$start +"%Y %_m %_d"
220         )
221         EOF
222     _m=$((_y * 12 + _m)) m=$((y * 12 + m))
223     while :; do
224       mod=$(( (_m - m) % rec_freq )); [ $mod -eq 0 ] && mod="$rec_freq";
225       m=$(( rec_freq - mod + _m ))
226       y=$((m / 12)) m=$((m % 12)); [ $m -eq 0 ] && y=$((y - 1)) m=12;
227       nstart="$(printf '%04i-%02i-%02i' "$y" "$m" "$d")"
228       isdate "$nstart" >/dev/null && [ $(date -d "$nstart" +%s) -ge $_DATE ] && break
229       debug loop
230       m=$((y * 12 + m)) _m="$((_m + rec_freq))"
231     done
232     nstart="$(date -d "$nstart $start_time" +%s)"
233       nend="$((end - start + nstart))"
234     ;;
235   year)
236     ;;
237   '')
238     nstart="$start" nend="$end"
239     ;;
240 esac
241
242 "$_EXEC/cgilite/html-sh.sed" <<-EOF
243   [div .macro .event
244     [label . $(HTML "$title")]
245     [dl
246       [dt $(_ Start:)][dd $(date -d @$nstart +"%F %T")]
247       [dt   $(_ End:)][dd $(date -d @$nend +"%F %T")]
248     ]
249   ]
250 EOF
251
252 # uid="$(timeid)"
253 # tzid="$(cat /etc/timezone || printf 'UTC')"
254
255 # cat >>"#events.ics" <<-EOF
256 # BEGIN:VCALENDAR
257 # VERSION:2.0
258 # PRODID:ShellWiki Event Macro
259 # BEGIN:VEVENT
260 # UID:$uid@$(HEADER Host)
261 # DTSTAMP:TZID=${tzid}:$(date +%Y%m%dT%H%M%S)
262 # DTSTART:TZID=${tzid}:$(date +%Y%m%dT%H%M%S -d "$start_date $start_time")
263 # DURATION:
264 # RRULE:FREQ=$ec_freq;INTERVAL=$rec_int;UNTIL=$(date +%Y%m%dT000000Z -d "$rec_end")
265 # SUMMARY:
266 # COMMENT:
267 # END:VEVENT
268 # END:VCARD
269 # EOF