zsh-users
 help / color / mirror / code / Atom feed
* Functions using zsh/datetime
@ 2005-12-02 11:37 Peter Stephenson
  0 siblings, 0 replies; only message in thread
From: Peter Stephenson @ 2005-12-02 11:37 UTC (permalink / raw)
  To: Zsh users list

[-- Attachment #1: Type: text/plain, Size: 1203 bytes --]

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@csr.com>                  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

[-- Attachment #2: asched function --]
[-- Type: text/plain, Size: 2247 bytes --]

# 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"

[-- Attachment #3: matchtime function --]
[-- Type: text/plain, Size: 2479 bytes --]

# 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

[-- Attachment #4: calendar function --]
[-- Type: text/plain, Size: 1785 bytes --]

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

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2005-12-02 11:40 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-12-02 11:37 Functions using zsh/datetime Peter Stephenson

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).