mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-01-23 00:41:03 +01:00
07b6256d8e
add errflag test to loop over fcntl()
171 lines
4.6 KiB
Bash
171 lines
4.6 KiB
Bash
#!/bin/zsh
|
|
# All arguments are joined with spaces and inserted into the calendar
|
|
# file at the appropriate point.
|
|
#
|
|
# While the function compares the date of the new entry with dates in the
|
|
# existing calendar file, it does not do any sorting; it inserts the new
|
|
# entry before the first existing entry with a later date and time.
|
|
|
|
emulate -L zsh
|
|
setopt extendedglob
|
|
|
|
local context=":datetime:calendar_add:"
|
|
|
|
local calendar newfile REPLY lastline opt
|
|
local -a calendar_entries lockfiles reply
|
|
integer my_date done rstat nolock nobackup new_recurring old_recurring
|
|
local -A reply parse_new parse_old recurring_uids
|
|
|
|
autoload -U calendar_{parse,read,lockfiles}
|
|
|
|
while getopts "BL" opt; do
|
|
case $opt in
|
|
(B)
|
|
nobackup=1
|
|
;;
|
|
|
|
(L)
|
|
nolock=1
|
|
;;
|
|
|
|
(*)
|
|
return 1
|
|
;;
|
|
esac
|
|
done
|
|
shift $(( OPTIND - 1 ))
|
|
|
|
# Read the calendar file from the calendar-file style
|
|
zstyle -s $context calendar-file calendar ||
|
|
calendar=~/calendar
|
|
newfile=$calendar.new.$HOST.$$
|
|
|
|
local addline="$*"
|
|
if ! calendar_parse $addline; then
|
|
print "$0: failed to parse date/time" >&2
|
|
return 1
|
|
fi
|
|
parse_new=("${(@kv)reply}")
|
|
(( my_date = $parse_new[time] ))
|
|
[[ -n $parse_new[rpttime] ]] && (( new_recurring = 1 ))
|
|
if zstyle -t $context reformat-date; then
|
|
local datefmt
|
|
zstyle -s $context date-format datefmt ||
|
|
datefmt="%a %b %d %H:%M:%S %Z %Y"
|
|
strftime -s REPLY $datefmt $parse_new[time]
|
|
addline="$REPLY $parse_new[text1]"
|
|
fi
|
|
|
|
# $calendar doesn't necessarily exist yet.
|
|
|
|
local -a match mbegin mend
|
|
local my_uid their_uid
|
|
|
|
# Match a UID, a unique identifier for the entry inherited from
|
|
# text/calendar format.
|
|
local uidpat='(|*[[:space:]])UID[[:space:]]##(#b)([[:xdigit:]]##)(|[[:space:]]*)'
|
|
if [[ $addline = ${~uidpat} ]]; then
|
|
my_uid=${(U)match[1]}
|
|
fi
|
|
|
|
# start of subshell for OS file locking
|
|
(
|
|
# start of block for following always to clear up lockfiles.
|
|
# Not needed but harmless if OS file locking is used.
|
|
{
|
|
if (( ! nolock )); then
|
|
if zmodload -F zsh/system b:zsystem && zsystem supports flock; then
|
|
zsystem flock $calendar
|
|
else
|
|
calendar_lockfiles $calendar || exit 1
|
|
fi
|
|
fi
|
|
|
|
if [[ -f $calendar ]]; then
|
|
calendar_read $calendar
|
|
|
|
if [[ -n $my_uid ]]; then
|
|
# Pre-scan to find recurring events with a UID
|
|
for line in $calendar_entries; do
|
|
calendar_parse $line || continue
|
|
# Recurring with a UID?
|
|
if [[ -n $reply[rpttime] && $line = ${~uidpat} ]]; then
|
|
# Yes, so record this as a recurring event.
|
|
their_uid=${(U)match[1]}
|
|
recurring_uids[$their_uid]=$reply[time]
|
|
fi
|
|
done
|
|
fi
|
|
|
|
{
|
|
for line in $calendar_entries; do
|
|
calendar_parse $line || continue
|
|
parse_old=("${(@kv)reply}")
|
|
if (( ! done && ${parse_old[time]} > my_date )); then
|
|
print -r -- $addline
|
|
(( done = 1 ))
|
|
fi
|
|
if [[ -n $parse_old[rpttime] ]]; then
|
|
(( old_recurring = 1 ))
|
|
else
|
|
(( old_recurring = 0 ))
|
|
fi
|
|
if [[ -n $my_uid && $line = ${~uidpat} ]]; then
|
|
their_uid=${(U)match[1]}
|
|
if [[ $my_uid = $their_uid ]]; then
|
|
# Deal with recurrences, being careful in case there
|
|
# are one-off variants that don't replace recurrences.
|
|
#
|
|
# Bug 1: "calendar" still doesn't know about one-off variants.
|
|
# Bug 2: neither do I; how do we know which occurrence
|
|
# it replaces?
|
|
# Bug 3: the code for calculating recurrences is awful anyway.
|
|
|
|
if (( old_recurring && new_recurring )); then
|
|
# Replacing a recurrence; there can be only one.
|
|
continue
|
|
elif (( ! new_recurring )); then
|
|
# Not recurring. See if we have previously found
|
|
# a recurrent version
|
|
[[ -n $recurring_uids[$their_uid] ]] && (( old_recurring = 1 ))
|
|
# No, so assume this is a straightforward replacement
|
|
# of a non-recurring event.
|
|
(( ! old_recurring )) && continue
|
|
# It's recurring, but if this is a one-off at the
|
|
# same time as the previous one, replace anyway.
|
|
[[ -z $parse_old[$rpttime] ]] &&
|
|
(( ${parse_new[time]} == ${parse_old[time]} )) &&
|
|
continue
|
|
fi
|
|
fi
|
|
fi
|
|
if [[ $parse_old[time] -eq $my_date && $line = $addline ]]; then
|
|
(( done )) && continue # paranoia: shouldn't happen
|
|
(( done = 1 ))
|
|
fi
|
|
print -r -- $line
|
|
done
|
|
(( done )) || print -r -- $addline
|
|
} >$newfile
|
|
if (( ! nobackup )); then
|
|
if ! mv $calendar $calendar.old; then
|
|
print "Couldn't back up $calendar to $calendar.old.
|
|
New calendar left in $newfile." >&2
|
|
(( rstat = 1 ))
|
|
fi
|
|
fi
|
|
else
|
|
print -r -- $line >$newfile
|
|
fi
|
|
|
|
if (( !rstat )) && ! mv $newfile $calendar; then
|
|
print "Failed to rename $newfile to $calendar.
|
|
Old calendar left in $calendar.old." >&2
|
|
(( rstat = 1 ))
|
|
fi
|
|
} always {
|
|
(( ${#lockfiles} )) && rm -f $lockfiles
|
|
}
|
|
|
|
exit $rstat
|
|
)
|