summary refs log tree commit diff
path: root/Functions/Calendar/calendar_parse
blob: e53e975160a0a5d9c5ad4da3d7ef951855eb346e (plain) (blame)
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