17c2fbfb3SApril Chin#!/usr/bin/ksh93 27c2fbfb3SApril Chin 37c2fbfb3SApril Chin# 47c2fbfb3SApril Chin# CDDL HEADER START 57c2fbfb3SApril Chin# 67c2fbfb3SApril Chin# The contents of this file are subject to the terms of the 77c2fbfb3SApril Chin# Common Development and Distribution License (the "License"). 87c2fbfb3SApril Chin# You may not use this file except in compliance with the License. 97c2fbfb3SApril Chin# 107c2fbfb3SApril Chin# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 117c2fbfb3SApril Chin# or http://www.opensolaris.org/os/licensing. 127c2fbfb3SApril Chin# See the License for the specific language governing permissions 137c2fbfb3SApril Chin# and limitations under the License. 147c2fbfb3SApril Chin# 157c2fbfb3SApril Chin# When distributing Covered Code, include this CDDL HEADER in each 167c2fbfb3SApril Chin# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 177c2fbfb3SApril Chin# If applicable, add the following below this CDDL HEADER, with the 187c2fbfb3SApril Chin# fields enclosed by brackets "[]" replaced with your own identifying 197c2fbfb3SApril Chin# information: Portions Copyright [yyyy] [name of copyright owner] 207c2fbfb3SApril Chin# 217c2fbfb3SApril Chin# CDDL HEADER END 227c2fbfb3SApril Chin# 237c2fbfb3SApril Chin 247c2fbfb3SApril Chin# 25*3e14f97fSRoger A. Faulkner# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 267c2fbfb3SApril Chin# 277c2fbfb3SApril Chin 287c2fbfb3SApril Chin# 297c2fbfb3SApril Chin# termclock - a simple analog clock for terminals 307c2fbfb3SApril Chin# 317c2fbfb3SApril Chin 327c2fbfb3SApril Chin# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant 337c2fbfb3SApril Chinexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin 347c2fbfb3SApril Chin 357c2fbfb3SApril Chin# Make sure all math stuff runs in the "C" locale to avoid problems 367c2fbfb3SApril Chin# with alternative # radix point representations (e.g. ',' instead of 377c2fbfb3SApril Chin# '.' in de_DE.*-locales). This needs to be set _before_ any 387c2fbfb3SApril Chin# floating-point constants are defined in this script). 397c2fbfb3SApril Chinif [[ "${LC_ALL}" != "" ]] ; then 407c2fbfb3SApril Chin export \ 417c2fbfb3SApril Chin LC_MONETARY="${LC_ALL}" \ 427c2fbfb3SApril Chin LC_MESSAGES="${LC_ALL}" \ 437c2fbfb3SApril Chin LC_COLLATE="${LC_ALL}" \ 447c2fbfb3SApril Chin LC_CTYPE="${LC_ALL}" 457c2fbfb3SApril Chin unset LC_ALL 467c2fbfb3SApril Chinfi 477c2fbfb3SApril Chinexport LC_NUMERIC=C 487c2fbfb3SApril Chin 497c2fbfb3SApril Chinfunction fatal_error 507c2fbfb3SApril Chin{ 517c2fbfb3SApril Chin print -u2 "${progname}: $*" 527c2fbfb3SApril Chin exit 1 537c2fbfb3SApril Chin} 547c2fbfb3SApril Chin 557c2fbfb3SApril Chin# cache tput values (to avoid |fork()|'ing a "tput" child every second) 567c2fbfb3SApril Chinfunction tput_cup 577c2fbfb3SApril Chin{ 587c2fbfb3SApril Chin # static variable as cache for "tput_cup" 597c2fbfb3SApril Chin typeset -S -A tput_cup_cache 607c2fbfb3SApril Chin 617c2fbfb3SApril Chin integer y="$1" x="$2" 627c2fbfb3SApril Chin nameref c="tput_cup_cache[\"${y}_${x}\"]" 637c2fbfb3SApril Chin 647c2fbfb3SApril Chin if [[ "$c" == "" ]] ; then 657c2fbfb3SApril Chin # fast path for known terminal types 667c2fbfb3SApril Chin if [[ ${TERM} == ~(Elr)(vt100|vt220|xterm|xterm-color|dtterm) ]] ; then 677c2fbfb3SApril Chin c="${ printf "\E[%d;%dH" y+1 x+1 ; }" 687c2fbfb3SApril Chin else 697c2fbfb3SApril Chin c="${ tput cup $y $x ; }" 707c2fbfb3SApril Chin fi 717c2fbfb3SApril Chin fi 727c2fbfb3SApril Chin 737c2fbfb3SApril Chin print -r -n -- "$c" 747c2fbfb3SApril Chin return 0 757c2fbfb3SApril Chin} 767c2fbfb3SApril Chin 777c2fbfb3SApril Chin# Get terminal size and put values into a compound variable with the integer 787c2fbfb3SApril Chin# members "columns" and "lines" 797c2fbfb3SApril Chinfunction get_term_size 807c2fbfb3SApril Chin{ 817c2fbfb3SApril Chin nameref rect=$1 827c2fbfb3SApril Chin 837c2fbfb3SApril Chin rect.columns=${ tput cols ; } || return 1 847c2fbfb3SApril Chin rect.lines=${ tput lines ; } || return 1 857c2fbfb3SApril Chin 867c2fbfb3SApril Chin return 0 877c2fbfb3SApril Chin} 887c2fbfb3SApril Chin 897c2fbfb3SApril Chinfunction draw_clock 907c2fbfb3SApril Chin{ 917c2fbfb3SApril Chin float angle a 927c2fbfb3SApril Chin float x y 937c2fbfb3SApril Chin integer i=1 947c2fbfb3SApril Chin 957c2fbfb3SApril Chin for(( angle=0.0 ; angle < 360. ; angle+=6 )) ; do 967c2fbfb3SApril Chin (( 977c2fbfb3SApril Chin a=angle/360.*(2*M_PI) , 987c2fbfb3SApril Chin 997c2fbfb3SApril Chin x=clock.len_x*cos(a) , 1007c2fbfb3SApril Chin y=clock.len_y*sin(a) 1017c2fbfb3SApril Chin )) 1027c2fbfb3SApril Chin 1037c2fbfb3SApril Chin tput_cup $(( y+clock.middle_y )) $(( x+clock.middle_x )) 1047c2fbfb3SApril Chin 1057c2fbfb3SApril Chin # add "mark" every 30 degrees 1067c2fbfb3SApril Chin if (( int(angle)%30 == 0 )) ; then 1077c2fbfb3SApril Chin print -r -n "$(((++i)%12+1))" 1087c2fbfb3SApril Chin else 1097c2fbfb3SApril Chin print -r -n "x" 1107c2fbfb3SApril Chin fi 1117c2fbfb3SApril Chin done 1127c2fbfb3SApril Chin return 0 1137c2fbfb3SApril Chin} 1147c2fbfb3SApril Chin 1157c2fbfb3SApril Chinfunction draw_hand 1167c2fbfb3SApril Chin{ 1177c2fbfb3SApril Chin float angle="$1" a 1187c2fbfb3SApril Chin typeset ch="$2" 1197c2fbfb3SApril Chin float length="$3" 1207c2fbfb3SApril Chin float x y 1217c2fbfb3SApril Chin 1227c2fbfb3SApril Chin (( a=angle/360.*(2*M_PI) )) 1237c2fbfb3SApril Chin 1247c2fbfb3SApril Chin for (( s=0.0 ; s < 10. ; s+=0.5 )) ; do 1257c2fbfb3SApril Chin (( 1267c2fbfb3SApril Chin x=(clock.len_x*(s/10.)*(length/100.))*cos(a) , 1277c2fbfb3SApril Chin y=(clock.len_y*(s/10.)*(length/100.))*sin(a) 1287c2fbfb3SApril Chin )) 1297c2fbfb3SApril Chin 1307c2fbfb3SApril Chin tput_cup $(( y+clock.middle_y )) $(( x+clock.middle_x )) 1317c2fbfb3SApril Chin print -r -n -- "${ch}" 1327c2fbfb3SApril Chin done 1337c2fbfb3SApril Chin return 0 1347c2fbfb3SApril Chin} 1357c2fbfb3SApril Chin 1367c2fbfb3SApril Chinfunction draw_clock_hand 1377c2fbfb3SApril Chin{ 1387c2fbfb3SApril Chin nameref hand=$1 1397c2fbfb3SApril Chin draw_hand $(( 360.*(hand.val/hand.scale)-90. )) "${hand.ch}" ${hand.length} 1407c2fbfb3SApril Chin return 0 1417c2fbfb3SApril Chin} 1427c2fbfb3SApril Chin 1437c2fbfb3SApril Chinfunction clear_clock_hand 1447c2fbfb3SApril Chin{ 1457c2fbfb3SApril Chin nameref hand=$1 1467c2fbfb3SApril Chin draw_hand $(( 360.*(hand.val/hand.scale)-90. )) " " ${hand.length} 1477c2fbfb3SApril Chin return 0 1487c2fbfb3SApril Chin} 1497c2fbfb3SApril Chin 1507c2fbfb3SApril Chinfunction main_loop 1517c2fbfb3SApril Chin{ 1527c2fbfb3SApril Chin typeset c 1537c2fbfb3SApril Chin 1547c2fbfb3SApril Chin # note: we can't use subshells when writing to the double-buffer file because this 1557c2fbfb3SApril Chin # will render the tput value cache useless 1567c2fbfb3SApril Chin while true ; do 1577c2fbfb3SApril Chin if ${init_screen} ; then 1587c2fbfb3SApril Chin init_screen="false" 1597c2fbfb3SApril Chin 1607c2fbfb3SApril Chin get_term_size termsize || fatal_error $"Couldn't get terminal size." 1617c2fbfb3SApril Chin 1627c2fbfb3SApril Chin (( 1637c2fbfb3SApril Chin clock.middle_x=termsize.columns/2.-.5 , 1647c2fbfb3SApril Chin clock.middle_y=termsize.lines/2.-.5 , 1657c2fbfb3SApril Chin clock.len_x=termsize.columns/2-2 , 1667c2fbfb3SApril Chin clock.len_y=termsize.lines/2-2 , 1677c2fbfb3SApril Chin )) 1687c2fbfb3SApril Chin 1697c2fbfb3SApril Chin { 1707c2fbfb3SApril Chin clear 1717c2fbfb3SApril Chin draw_clock 1727c2fbfb3SApril Chin } >&6 1737c2fbfb3SApril Chin fi 1747c2fbfb3SApril Chin 1757c2fbfb3SApril Chin { 1767c2fbfb3SApril Chin (( ${ date +"hours.val=%H , minutes.val=%M , seconds.val=%S" ; } )) 1777c2fbfb3SApril Chin 1787c2fbfb3SApril Chin # small trick to get a smooth "analog" flair 1797c2fbfb3SApril Chin (( 1807c2fbfb3SApril Chin hours.val+=minutes.val/60. , 1817c2fbfb3SApril Chin minutes.val+=seconds.val/60. 1827c2fbfb3SApril Chin )) 1837c2fbfb3SApril Chin 1847c2fbfb3SApril Chin draw_clock_hand seconds 1857c2fbfb3SApril Chin draw_clock_hand minutes 1867c2fbfb3SApril Chin draw_clock_hand hours 1877c2fbfb3SApril Chin 1887c2fbfb3SApril Chin # move cursor to home position 1897c2fbfb3SApril Chin tput_cup 0 0 1907c2fbfb3SApril Chin } >&6 1917c2fbfb3SApril Chin 1927c2fbfb3SApril Chin 6<#((0)) 1937c2fbfb3SApril Chin cat <&6 1947c2fbfb3SApril Chin 1957c2fbfb3SApril Chin redirect 6<&- ; rm -f "${scratchfile}" ; redirect 6<> "${scratchfile}" 1967c2fbfb3SApril Chin 1977c2fbfb3SApril Chin c="" ; read -r -t ${update_interval} -N 1 c 1987c2fbfb3SApril Chin if [[ "$c" != "" ]] ; then 1997c2fbfb3SApril Chin case "$c" in 2007c2fbfb3SApril Chin ~(Fi)q | $'\E') return 0 ;; 2017c2fbfb3SApril Chin esac 2027c2fbfb3SApril Chin fi 2037c2fbfb3SApril Chin 2047c2fbfb3SApril Chin { 2057c2fbfb3SApril Chin clear_clock_hand hours 2067c2fbfb3SApril Chin clear_clock_hand minutes 2077c2fbfb3SApril Chin clear_clock_hand seconds 2087c2fbfb3SApril Chin } >&6 2097c2fbfb3SApril Chin done 2107c2fbfb3SApril Chin} 2117c2fbfb3SApril Chin 2127c2fbfb3SApril Chinfunction usage 2137c2fbfb3SApril Chin{ 2147c2fbfb3SApril Chin OPTIND=0 2157c2fbfb3SApril Chin getopts -a "${progname}" "${termclock_usage}" OPT '-?' 2167c2fbfb3SApril Chin exit 2 2177c2fbfb3SApril Chin} 2187c2fbfb3SApril Chin 2197c2fbfb3SApril Chin# program start 2207c2fbfb3SApril Chinbuiltin basename 2217c2fbfb3SApril Chinbuiltin cat 2227c2fbfb3SApril Chinbuiltin date 22334f9b3eeSRoland Mainzbuiltin mktemp 2247c2fbfb3SApril Chinbuiltin rm 2257c2fbfb3SApril Chin 2267c2fbfb3SApril Chintypeset progname="${ basename "${0}" ; }" 2277c2fbfb3SApril Chin 2287c2fbfb3SApril Chinfloat -r M_PI=3.14159265358979323846 2297c2fbfb3SApril Chin 2307c2fbfb3SApril Chin# terminal size rect 23134f9b3eeSRoland Mainzcompound termsize=( 2327c2fbfb3SApril Chin integer columns=-1 2337c2fbfb3SApril Chin integer lines=-1 2347c2fbfb3SApril Chin) 2357c2fbfb3SApril Chin 2367c2fbfb3SApril Chintypeset init_screen="true" 2377c2fbfb3SApril Chin 23834f9b3eeSRoland Mainzcompound clock=( 2397c2fbfb3SApril Chin float middle_x 2407c2fbfb3SApril Chin float middle_y 2417c2fbfb3SApril Chin integer len_x 2427c2fbfb3SApril Chin integer len_y 2437c2fbfb3SApril Chin) 2447c2fbfb3SApril Chin 2457c2fbfb3SApril Chin 2467c2fbfb3SApril Chin# set clock properties 24734f9b3eeSRoland Mainzcompound seconds=( 2487c2fbfb3SApril Chin float val 2497c2fbfb3SApril Chin typeset ch 2507c2fbfb3SApril Chin float scale 2517c2fbfb3SApril Chin integer length ) 25234f9b3eeSRoland Mainzcompound minutes=( 2537c2fbfb3SApril Chin float val 2547c2fbfb3SApril Chin typeset ch 2557c2fbfb3SApril Chin float scale 2567c2fbfb3SApril Chin integer length ) 25734f9b3eeSRoland Mainzcompound hours=( 2587c2fbfb3SApril Chin float val 2597c2fbfb3SApril Chin typeset ch 2607c2fbfb3SApril Chin float scale 2617c2fbfb3SApril Chin integer length ) 2627c2fbfb3SApril Chin 2637c2fbfb3SApril Chinseconds.length=90 seconds.scale=60 seconds.ch=$"s" 2647c2fbfb3SApril Chinminutes.length=75 minutes.scale=60 minutes.ch=$"m" 2657c2fbfb3SApril Chinhours.length=50 hours.scale=12 hours.ch=$"h" 2667c2fbfb3SApril Chin 2677c2fbfb3SApril Chinfloat update_interval=0.9 2687c2fbfb3SApril Chin 2697c2fbfb3SApril Chintypeset -r termclock_usage=$'+ 270*3e14f97fSRoger A. Faulkner[-?\n@(#)\$Id: termclock (Roland Mainz) 2009-12-02 \$\n] 2717c2fbfb3SApril Chin[-author?Roland Mainz <roland.mainz@nrubsig.org>] 2727c2fbfb3SApril Chin[-author?David Korn <dgk@research.att.com>] 2737c2fbfb3SApril Chin[+NAME?termclock - analog clock for terminals] 2747c2fbfb3SApril Chin[+DESCRIPTION?\btermclock\b is an analog clock for terminals. 2757c2fbfb3SApril Chin The termclock program displays the time in analog or digital 2767c2fbfb3SApril Chin form. The time is continuously updated at a frequency which 2777c2fbfb3SApril Chin may be specified by the user.] 2787c2fbfb3SApril Chin[u:update?Update interval (defaults to 0.9 seconds).]:[interval] 2797c2fbfb3SApril Chin[+SEE ALSO?\bksh93\b(1), \bxclock\b(1)] 2807c2fbfb3SApril Chin' 2817c2fbfb3SApril Chin 2827c2fbfb3SApril Chinwhile getopts -a "${progname}" "${termclock_usage}" OPT ; do 2837c2fbfb3SApril Chin# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" 2847c2fbfb3SApril Chin case ${OPT} in 2857c2fbfb3SApril Chin u) update_interval=${OPTARG} ;; 2867c2fbfb3SApril Chin *) usage ;; 2877c2fbfb3SApril Chin esac 2887c2fbfb3SApril Chindone 2897c2fbfb3SApril Chinshift $((OPTIND-1)) 2907c2fbfb3SApril Chin 2917c2fbfb3SApril Chin# prechecks 2927c2fbfb3SApril Chinwhich tput >/dev/null || fatal_error $"tput not found." 2937c2fbfb3SApril Chin(( update_interval >= 0. && update_interval <= 7200. )) || fatal_error $"invalid update_interval value." 2947c2fbfb3SApril Chin 2957c2fbfb3SApril Chin# create temporary file for double-buffering and register an EXIT trap 2967c2fbfb3SApril Chin# to remove this file when the shell interpreter exits 297*3e14f97fSRoger A. Faulknerscratchfile="${ mktemp -t "termclock.ppid${PPID}_pid$$.XXXXXX" ; }" 2987c2fbfb3SApril Chin[[ "${scratchfile}" != "" ]] || fatal_error $"Could not create temporary file name." 2997c2fbfb3SApril Chintrap 'rm -f "${scratchfile}"' EXIT 3007c2fbfb3SApril Chinrm -f "${scratchfile}" ; redirect 6<> "${scratchfile}" || fatal_error $"Could not create temporary file." 3017c2fbfb3SApril Chin 3027c2fbfb3SApril Chin# register trap to handle window size changes 3037c2fbfb3SApril Chintrap 'init_screen="true"' WINCH 3047c2fbfb3SApril Chin 3057c2fbfb3SApril Chinmain_loop 3067c2fbfb3SApril Chin 3077c2fbfb3SApril Chin# exiting - put cursor below clock 3087c2fbfb3SApril Chintput_cup $((termsize.lines-2)) 0 3097c2fbfb3SApril Chin 3107c2fbfb3SApril Chinexit 0 3117c2fbfb3SApril Chin# EOF. 312