8354 sync regcomp(3C) with upstream (fix make catalog)
[unleashed/tickless.git] / usr / src / lib / libshell / common / scripts / termclock.sh
blobc1c4cb809231d02d96f9cc40e5b16637989b3c69
1 #!/usr/bin/ksh93
4 # CDDL HEADER START
6 # The contents of this file are subject to the terms of the
7 # Common Development and Distribution License (the "License").
8 # You may not use this file except in compliance with the License.
10 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11 # or http://www.opensolaris.org/os/licensing.
12 # See the License for the specific language governing permissions
13 # and limitations under the License.
15 # When distributing Covered Code, include this CDDL HEADER in each
16 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17 # If applicable, add the following below this CDDL HEADER, with the
18 # fields enclosed by brackets "[]" replaced with your own identifying
19 # information: Portions Copyright [yyyy] [name of copyright owner]
21 # CDDL HEADER END
25 # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
29 # termclock - a simple analog clock for terminals
32 # Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant
33 export PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin
35 # Make sure all math stuff runs in the "C" locale to avoid problems
36 # with alternative # radix point representations (e.g. ',' instead of
37 # '.' in de_DE.*-locales). This needs to be set _before_ any
38 # floating-point constants are defined in this script).
39 if [[ "${LC_ALL}" != "" ]] ; then
40 export \
41 LC_MONETARY="${LC_ALL}" \
42 LC_MESSAGES="${LC_ALL}" \
43 LC_COLLATE="${LC_ALL}" \
44 LC_CTYPE="${LC_ALL}"
45 unset LC_ALL
47 export LC_NUMERIC=C
49 function fatal_error
51 print -u2 "${progname}: $*"
52 exit 1
55 # cache tput values (to avoid |fork()|'ing a "tput" child every second)
56 function tput_cup
58 # static variable as cache for "tput_cup"
59 typeset -S -A tput_cup_cache
61 integer y="$1" x="$2"
62 nameref c="tput_cup_cache[\"${y}_${x}\"]"
64 if [[ "$c" == "" ]] ; then
65 # fast path for known terminal types
66 if [[ ${TERM} == ~(Elr)(vt100|vt220|xterm|xterm-color|dtterm) ]] ; then
67 c="${ printf "\E[%d;%dH" y+1 x+1 ; }"
68 else
69 c="${ tput cup $y $x ; }"
73 print -r -n -- "$c"
74 return 0
77 # Get terminal size and put values into a compound variable with the integer
78 # members "columns" and "lines"
79 function get_term_size
81 nameref rect=$1
83 rect.columns=${ tput cols ; } || return 1
84 rect.lines=${ tput lines ; } || return 1
86 return 0
89 function draw_clock
91 float angle a
92 float x y
93 integer i=1
95 for(( angle=0.0 ; angle < 360. ; angle+=6 )) ; do
97 a=angle/360.*(2*M_PI) ,
99 x=clock.len_x*cos(a) ,
100 y=clock.len_y*sin(a)
103 tput_cup $(( y+clock.middle_y )) $(( x+clock.middle_x ))
105 # add "mark" every 30 degrees
106 if (( int(angle)%30 == 0 )) ; then
107 print -r -n "$(((++i)%12+1))"
108 else
109 print -r -n "x"
111 done
112 return 0
115 function draw_hand
117 float angle="$1" a
118 typeset ch="$2"
119 float length="$3"
120 float x y
122 (( a=angle/360.*(2*M_PI) ))
124 for (( s=0.0 ; s < 10. ; s+=0.5 )) ; do
126 x=(clock.len_x*(s/10.)*(length/100.))*cos(a) ,
127 y=(clock.len_y*(s/10.)*(length/100.))*sin(a)
130 tput_cup $(( y+clock.middle_y )) $(( x+clock.middle_x ))
131 print -r -n -- "${ch}"
132 done
133 return 0
136 function draw_clock_hand
138 nameref hand=$1
139 draw_hand $(( 360.*(hand.val/hand.scale)-90. )) "${hand.ch}" ${hand.length}
140 return 0
143 function clear_clock_hand
145 nameref hand=$1
146 draw_hand $(( 360.*(hand.val/hand.scale)-90. )) " " ${hand.length}
147 return 0
150 function main_loop
152 typeset c
154 # note: we can't use subshells when writing to the double-buffer file because this
155 # will render the tput value cache useless
156 while true ; do
157 if ${init_screen} ; then
158 init_screen="false"
160 get_term_size termsize || fatal_error $"Couldn't get terminal size."
163 clock.middle_x=termsize.columns/2.-.5 ,
164 clock.middle_y=termsize.lines/2.-.5 ,
165 clock.len_x=termsize.columns/2-2 ,
166 clock.len_y=termsize.lines/2-2 ,
170 clear
171 draw_clock
172 } >&6
176 (( ${ date +"hours.val=%H , minutes.val=%M , seconds.val=%S" ; } ))
178 # small trick to get a smooth "analog" flair
180 hours.val+=minutes.val/60. ,
181 minutes.val+=seconds.val/60.
184 draw_clock_hand seconds
185 draw_clock_hand minutes
186 draw_clock_hand hours
188 # move cursor to home position
189 tput_cup 0 0
190 } >&6
192 6<#((0))
193 cat <&6
195 redirect 6<&- ; rm -f "${scratchfile}" ; redirect 6<> "${scratchfile}"
197 c="" ; read -r -t ${update_interval} -N 1 c
198 if [[ "$c" != "" ]] ; then
199 case "$c" in
200 ~(Fi)q | $'\E') return 0 ;;
201 esac
205 clear_clock_hand hours
206 clear_clock_hand minutes
207 clear_clock_hand seconds
208 } >&6
209 done
212 function usage
214 OPTIND=0
215 getopts -a "${progname}" "${termclock_usage}" OPT '-?'
216 exit 2
219 # program start
220 builtin basename
221 builtin cat
222 builtin date
223 builtin mktemp
224 builtin rm
226 typeset progname="${ basename "${0}" ; }"
228 float -r M_PI=3.14159265358979323846
230 # terminal size rect
231 compound termsize=(
232 integer columns=-1
233 integer lines=-1
236 typeset init_screen="true"
238 compound clock=(
239 float middle_x
240 float middle_y
241 integer len_x
242 integer len_y
246 # set clock properties
247 compound seconds=(
248 float val
249 typeset ch
250 float scale
251 integer length )
252 compound minutes=(
253 float val
254 typeset ch
255 float scale
256 integer length )
257 compound hours=(
258 float val
259 typeset ch
260 float scale
261 integer length )
263 seconds.length=90 seconds.scale=60 seconds.ch=$"s"
264 minutes.length=75 minutes.scale=60 minutes.ch=$"m"
265 hours.length=50 hours.scale=12 hours.ch=$"h"
267 float update_interval=0.9
269 typeset -r termclock_usage=$'+
270 [-?\n@(#)\$Id: termclock (Roland Mainz) 2009-12-02 \$\n]
271 [-author?Roland Mainz <roland.mainz@nrubsig.org>]
272 [-author?David Korn <dgk@research.att.com>]
273 [+NAME?termclock - analog clock for terminals]
274 [+DESCRIPTION?\btermclock\b is an analog clock for terminals.
275 The termclock program displays the time in analog or digital
276 form. The time is continuously updated at a frequency which
277 may be specified by the user.]
278 [u:update?Update interval (defaults to 0.9 seconds).]:[interval]
279 [+SEE ALSO?\bksh93\b(1), \bxclock\b(1)]
282 while getopts -a "${progname}" "${termclock_usage}" OPT ; do
283 # printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|"
284 case ${OPT} in
285 u) update_interval=${OPTARG} ;;
286 *) usage ;;
287 esac
288 done
289 shift $((OPTIND-1))
291 # prechecks
292 which tput >/dev/null || fatal_error $"tput not found."
293 (( update_interval >= 0. && update_interval <= 7200. )) || fatal_error $"invalid update_interval value."
295 # create temporary file for double-buffering and register an EXIT trap
296 # to remove this file when the shell interpreter exits
297 scratchfile="${ mktemp -t "termclock.ppid${PPID}_pid$$.XXXXXX" ; }"
298 [[ "${scratchfile}" != "" ]] || fatal_error $"Could not create temporary file name."
299 trap 'rm -f "${scratchfile}"' EXIT
300 rm -f "${scratchfile}" ; redirect 6<> "${scratchfile}" || fatal_error $"Could not create temporary file."
302 # register trap to handle window size changes
303 trap 'init_screen="true"' WINCH
305 main_loop
307 # exiting - put cursor below clock
308 tput_cup $((termsize.lines-2)) 0
310 exit 0
311 # EOF.