Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Functions using zsh/datetime
- X-seq: zsh-users 9735
- From: Peter Stephenson <pws@xxxxxxx>
- To: zsh-users@xxxxxxxxxx (Zsh users list)
- Subject: Functions using zsh/datetime
- Date: Fri, 02 Dec 2005 11:37:56 +0000
- Mailing-list: contact zsh-users-help@xxxxxxxxxx; run by ezmlm
Here are three functions that use the zsh/datetime module; one day they
may appear in Functions/Datetime but just in case I abandon them I
thought I'd better post them in the current fairly rough and not very
well documented state.
asched is an asynchronous version of the sched builtin. The syntax is
the same. It doesn't make use of jobs at the moment (jobs get created
anyway in a shell with the monitor option set, but the function uses
PIDs) since they're not that easy to access from a function (there's no
way to get the last job started in the background, unlike the last
process).
matchtime attempts to match a date string against a number of seconds
since the epoch (as returned by zsh/datetime's $EPOCHSECONDS).
calendar uses matchtime to implement the decreasingly standard
external command of the same name, with a few extensions including the
ability to use asched to create messages.
--
Peter Stephenson <pws@xxxxxxx> Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK Tel: +44 (0)1223 692070
This message has been scanned for viruses by BlackSpider MailControl - www.blackspider.com
# Asynchronous variant of sched.
# The syntax is the same.
#
# TODO: would be better if we could use job handling directly
# but the programming interface to that isn't great, so currently
# it uses processes (though these will be in jobs if the monitor
# option is set).
emulate -L zsh
setopt extendedglob
zmodload -i zsh/datetime || return 1
integer -g ASCHED_JOB
typeset -ga asched_processes
local strtime proc
integer now=$EPOCHSECONDS hhour hour mminute minute diff time i procwid
local -a match mbegin mend
# Use guesswork to decide whether the process has been run.
for (( i = 1; i <= ${#asched_processes}; i++ )); do
time=${${asched_processes[$i]##<-> #}%% *}
if (( now > time )); then
# it's all over
asched_processes[$i]=
fi
done
if [[ $1 = -(#b)(<->) ]]; then
local killproc="${asched_processes[$match[1]]%% *}"
if [[ -n $killproc ]]; then
kill $killproc
asched_processes[$match[1]]=
else
print -r "asched: no such asched job or time already past"
fi
elif (( $# == 0 )); then
# the width of the length of the array, for padding...
procwid=${#:-${#asched_processes}}
for (( i = 1; i <= ${#asched_processes}; i++ )); do
proc=${asched_processes[$i]}
if [[ -n $proc ]]; then
print "${(l.$procwid.)i} ${proc##<-> #<-> #}"
fi
done
return 0
elif [[ $1 != (#b)(+|)(<->):(<->) || $# -lt 2 ]]; then
print "Usage: asched [+]HH:MM job
asched [ -<item> ]" >&2
return 1
fi
shift
local job="$*"
hhour=$match[2]
mminute=$match[3]
if [[ -n $match[1] ]]; then
# relative
(( diff = (hhour * 60 + mminute) * 60 ))
else
# absolute, so work out when now is.
# assume today, so if it's in the past run job immediately.
strftime -s hour %H $now
strftime -s minute %M $now
(( diff = ((hhour - hour) * 60 + mminute - minute) * 60 ))
if (( diff < 0 )); then
# do it in subshell since user expects this not to affect main shell
(eval $job)
return 0
fi
fi
(( ASCHED_JOB++ ))
(( time = now + diff ))
strftime -s strtime "%a %b %d %H:%M:%S" $time
eval "(: asched job $ASCHED_JOB
sleep $diff; $job) &"
# Format: background task, Epoch time, string time, job name.
# The last two are for human consumption.
asched_processes[$ASCHED_JOB]="$! $time $strtime $job"
# Input: a line and an epoch time, which defaults to now.
# Returns: 0 if the line contains today's date, else 1.
# Tries various date formats: see comments below.
# (Should really be called matchdate, in fact.)
#
# TODO: can get confused about DAY MONTH YEAR and MONTH DAY YEAR,
# could use locale as some kind of hint. (User can help by using
# 1st, 2nd, 3rd, 4th, ... for day, or by using ISOesque
# 2005-12-02.)
#
# If -t is passed, look for a time in the format HH:MM (must be in the 24-hour
# clock at the moment) attached to the date. If it's greater than or equal
# to the epoch time, set REPLY to HH:MM. This is intended to be used
# to set a job for the given time.
emulate -L zsh
setopt extendedglob
zmodload -i zsh/datetime || return 1
integer checktime
local opt
while getopts "t" opt; do
case $opt in
(t)
checktime=1
;;
esac
done
shift $(( OPTIND - 1 ))
local line=$1
integer now=${2:-$EPOCHSECONDS} stat=1 patstart patend
local -a match mbegin mend
local year monthnum monthname day hour minute hhour mminute
strftime -s year %Y $now
strftime -s monthnum %m $now
monthnum=${monthnum##0}
strftime -s monthname %b $now
strftime -s day %d $now
day=${day##0}
strftime -s hour %H $now
strftime -s minute %M $now
case $line in
# Look for DAY[th/st/rd] MONTH[,] YEAR
(*(#b)((#i)((#s)|[[:blank:]])0#${day}(|rd|st|th)[[:blank:]]##(${monthname}[a-z]#|0#${monthnum})[,[:blank:]]##(${year}|${year[-2,-1]})([[:blank:],\;:.]|(#e)))*)
stat=0
;;
# Look for MONTH DAY[th/st/rd][,] YEAR
(*(#b)((#i)((#s)|[[:blank:]])(${monthname}[a-z]#|0#${monthnum})[[:blank:]]##0#${day}(|rd|st|th)[,[:blank:]]##(${year}|${year[-2,-1]})([[:blank:],\;:.]|(#e)))*)
stat=0
;;
# Look for YEAR[-]MONTH[-]DAY
(*(#b)((#i)((#s)|[[:blank:]])(${year}|${year[-2,-1]})[-]#(${monthname}[a-z]#|0#${monthnum})[-]#0#${day}([[:blank:],\;:.]|(#e)))*)
stat=0
;;
esac
(( stat != 0 )) && return 1
if (( checktime )); then
REPLY=
patstart=$mbegin[1]
patend=$mend[1]
if [[ $patstart -gt 1 && $line[1,$patstart-1] = *((#s)|[[:blank:]])(#b)(<->):(<->)[[:blank:],\;:.]# ]]; then
hhour=$match[1]
mminute=$match[2]
elif [[ $patend -lt ${#line} && $line[$patend+1,-1] = [[:blank:],\;:.]#(#b)(<->):(<->)(|[[:blank:]]*) ]]; then
hhour=$match[1]
mminute=$match[2]
fi
# assume 24-hour clock for now
if [[ -n $hhour$mminute ]] && (( hour < hhour || (hour == hhour && minute <= mminute ) )); then
REPLY=${hhour}:${mminute}
fi
fi
return 0
emulate -L zsh
setopt extendedglob
local line opt REPLY
local calendar sched showprog
integer time
local -a times
zmodload -i zsh/datetime || return 1
zmodload -i zsh/zutil || return 1
# Read the calendar file from the calendar-file style
zstyle -s ':datetime:calendar:' calendar-file calendar || calendar=~/calendar
# Read the programme to show the message from the show-prog style.
# (Requires option -a or -s to be useful.)
zstyle -s ':datetime:calendar:' show-prog showprog || showprog="print -r"
[[ -f $calendar ]] || return 1
while getopts "aC:sS:x" opt; do
case $opt in
# Use the "asched" function to generate a message asynchronously.
(a)
sched=asched
;;
(C)
# Pick the calendar file, overriding style and default.
calendar=$OPTARG
;;
(s)
# Use the "sched" builtin to generate a message before a prompt.
sched=sched
;;
(S)
# Explicitly specify a show programme, overriding style and default.
showprog=$OPTARG
;;
(x)
# Use xmessage as the show programme. Best used with -a.
showprog=xmessage
;;
(*)
return 1
;;
esac
done
shift $(( OPTIND - 1 ))
time=$EPOCHSECONDS
# search today and tomorrow
times=($time $(( time + 24*60*60 )))
autoload -Uz matchtime
while read -r line; do
if matchtime -t $line $times[1]; then
print -r $line
if [[ -n $sched && -n $REPLY ]]; then
# eval needed in place of closures on REPLY and line.
# i like perl.
eval "function sched_$REPLY {
unfunction sched_$REPLY
$showprog \"Calendar entry is now due: \" ${(q)line} >&$TTY
}"
$sched $REPLY sched_$REPLY
fi
else
for time in ${times[2,-1]}; do
matchtime -t $line $time && print -r $line && break
done
fi
done <$calendar
return 0
Messages sorted by:
Reverse Date,
Date,
Thread,
Author