1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
# Parse the line passed down in the first argument as a calendar entry.
# Sets the values parsed into the associative array reply, consisting of:
# time The time as an integer (as per EPOCHSECONDS)
# text1 The text from the the line not including the date/time, but
# including any WARN or RPT text. This is useful for rescheduling
# events, since the keywords need to be retained in this case.
# warntime Any warning time (WARN keyword) as an integer, else an empty
# string. This is the time of the warning in units of EPOCHSECONDS,
# not the parsed version of the original number (which was a time
# difference).
# warnstr Any warning time as the original string (e.g. "5 mins"), not
# including the WARN keyword.
# rpttime Any repeat/recurrence time (RPT keyword) as an integer, else empty.
# This is the time of the recurrence itself in EPOCHSECONDS units
# (as with a warning---not the difference between the events).
# rptstr Any repeat/recurrence time as the original string.
# text2 The text from the line with the date and keywords and values removed.
#
# Note that here an "integer" is a string of digits, not an internally
# formatted integer.
#
# Return status 1 if parsing failed. reply is set to an empty
# in this case. Note the caller is responsible for
# making reply local.
emulate -L zsh
setopt extendedglob
local REPLY REPLY2
local -a match mbegin mend
integer now
autoload -U calendar_scandate
typeset -gA reply
reply=()
if (( $# != 1 )); then
print "Usage: $0 calendar-entry" >&2
return 2
fi
# This call sets REPLY to the date and time in seconds since the epoch,
# REPLY2 to the line with the date and time removed.
calendar_scandate -as $1 || return 1
reply[time]=$(( REPLY ))
reply[text1]=${REPLY2##[[:space:]]#}
reply[text2]=$reply[text1]
integer changed=1
while (( changed )); do
(( changed = 0 ))
# Look for specific warn time.
if [[ $reply[text2] = (#b)(|*[[:space:],])WARN[[:space:]](*) ]]; then
if calendar_scandate -asm -R $reply[time] $match[2]; then
reply[warntime]=$REPLY
reply[warnstr]=${match[2]%%"$REPLY2"}
reply[text2]="${match[1]}${REPLY2##[[:space:]]#}"
else
# Just remove the keyword for further parsing
reply[text2]="${match[1]}${match[2]##[[:space:]]#}"
fi
(( changed = 1 ))
elif [[ $reply[text2] = (#b)(|*[[:space:],])RPT[[:space:]](*) ]]; then
if calendar_scandate -a -R $reply[time] $match[2]; then
reply[rpttime]=$REPLY
reply[rptstr]=${match[2]%%"$REPLY2"}
reply[text2]="${match[1]}${REPLY2##[[:space:]]#}"
(( now = EPOCHSECONDS ))
while (( ${reply[rpttime]} < now )); do
# let's hope the original appointment wasn't in 44 B.C.
if calendar_scandate -a -R ${reply[rpttime]} ${reply[rptstr]}; then
if (( REPLY <= ${reply[rpttime]} )); then
# pathological case
break;
fi
reply[rpttime]=$REPLY
fi
done
else
# Just remove the keyword for further parsing
reply[text2]="${match[1]}${match[2]##[[:space:]]#}"
fi
(( changed = 1 ))
fi
done
reply[text2]="${reply[text2]##[[:space:],]#}"
return 0
|