File: uhr

package info (click to toggle)
mksh 54-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 1,720 kB
  • ctags: 2,386
  • sloc: ansic: 25,434; sh: 2,253; perl: 1,037; makefile: 78
file content (445 lines) | stat: -rw-r--r-- 10,367 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
#!/bin/mksh
# $MirOS: contrib/hosted/tg/uhr,v 1.17 2015/11/29 21:34:06 tg Exp $
#-
# Copyright © 2012, 2013, 2015
#	mirabilos <m@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
# are retained or reproduced in an accompanying document, permission
# is granted to deal in this work without restriction, including un‐
# limited rights to use, publicly perform, distribute, sell, modify,
# merge, give away, or sublicence.
#
# This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
# the utmost extent permitted by applicable law, neither express nor
# implied; without malicious intent or gross negligence. In no event
# may a licensor, author or contributor be held liable for indirect,
# direct, other damage, loss, or other issues arising in any way out
# of dealing in the work, even if advised of the possibility of such
# damage or existence of a defect, except proven that it results out
# of said person’s immediate fault when using the work as intended.
#-
# Analoguhr mit Digitalanzeige. Grundlegende Annahme: schnelles Ter‐
# minal, d.h. keine Voroptimierung der Darstellung durch das Skript;
# Font im Seitenverhältnis 1:2 (z.B. 9x18 aus XFree86® fixed-misc).

if [[ $KSH_VERSION != @(\@\(#\)MIRBSD KSH R)@(4[1-9]|[5-9][0-9]|[1-9][0-9]+([0-9]))\ +([0-9])/+([0-9])/+([0-9])?(\ *) ]]; then
	print -u2 Uhr requires mksh R41 or newer.
	exit 1
fi
typeset -Z6 tosleep

# stupid GNU idiots breaking everything by default… grml…
bcopt=
bc --help >/dev/null 2>&1 && bcopt=-q

# global variables used by progress bar
_cnt_progress_bar=0
_cur_progress_bar=0
isin_progress_bar=0
nlin_progress_bar=0

# args: $1 = number of draw_progress_bar calls to make up 100%
function init_progress_bar {
	global -i _cnt_progress_bar=$1 _cur_progress_bar=0
	global -i nlin_progress_bar=$LINES isin_progress_bar=1

	trap 'done_progress_bar' EXIT
	# newline; up one line (to ensure we are not in the last line);
	# save position; set scrolling region; restore position
	print -n "\\n\\e[A\\e7\\e[1;$((# nlin_progress_bar - 1))r\\e8"
}

function sigwinch_uhr {
	got_sigwinch=1
	(( isin_progress_bar )) || return 0

	# get new terminal size
	nlin_progress_bar=$LINES
	# newline; up one line (to ensure we are not in the last line);
	# save position; set scrolling region; restore position
	print -n "\\n\\e[A\\e7\\e[1;$((# nlin_progress_bar - 1))r\\e8"
}

function done_progress_bar {
	(( isin_progress_bar )) || return 0
	# save position; clear scrolling region;
	# go to last line; delete line; restore position
	print "\\e7\\e[0;0r\\e[$nlin_progress_bar;0H\\e[M\\e8"
	isin_progress_bar=0
	trap - EXIT
}

function draw_progress_bar {
	local bar num w=$COLUMNS

	((# num = (++_cur_progress_bar * w * 8) / _cnt_progress_bar ))
	while ((# num >= 8 )); do
		bar+=█
		((# num -= 8 ))
	done
	case $num {
	(7) bar+=▉ ;;
	(6) bar+=▊ ;;
	(5) bar+=▋ ;;
	(4) bar+=▌ ;;
	(3) bar+=▍ ;;
	(2) bar+=▎ ;;
	(1) bar+=▏ ;;
	}
	# fill complete line, right-align completion percentage display
	local -R$w spc="$((# _cur_progress_bar * 100 / _cnt_progress_bar))%"
	# elide percentage when it stops fitting
	((# (_cur_progress_bar * w / _cnt_progress_bar) > (w - 4) )) && spc=
	# save position; go to last line; set colours;
	# output a line full of spaces (and completion percentage);
	# jump to first column; output bar (line præfix); restore position
	print -n -- "\\e7\\e[$nlin_progress_bar;0H\\e[0;1;33;44m$spc\\r$bar\\e8"
}

function graceful {
	print -n '\033[;H\033[J'
	exit 0
}
trap graceful INT TERM HUP

trap sigwinch_uhr WINCH
while :; do
got_sigwinch=0

init_progress_bar 135
draw_progress_bar
S='Pregenerating arrays, please wait...'
if (( (r = (COLUMNS - ${%S}) / 2 - 2) < 1 )); then
	d="\\e[0m\\n$S"
else
	d=
	(( n = ${%S} + 2 ))
	while (( n-- )); do
		d+=─
	done
	d="\\e[0m\\e[$((LINES / 2 - 1));${r}H\\e7┌$d┐\\e8\\e[B│ $S │\\e8\\e[2B└$d┘"
fi
print "$d"

(( r = LINES * 2 ))
(( r = (r > COLUMNS ? COLUMNS : r) / 2 - 1))
(( n = 2 * r + 1 ))
set -A fb
integer fb

integer F_NO=0x00 M_NO=0x1F
integer F_BG=0x01 M_BG=0x1E
integer F_CC=0x02 M_CC=0x1D
integer F_HP=0x04 M_HP=0x1B
integer F_MP=0x08 M_MP=0x17
integer F_SP=0x10 M_SP=0x0F
integer B_BG=0x01 B_BLK=0x02 B_NB=0x0C B_DOT=0x10

set -U
#	-	BLK	BG	NB	DOT	NB|DOT
set -A m2c \
	0x20	1#▀	1#*	1#▀	1#·	1#░	\
	1#▄	1#█	1#█	1#█	1#▆	1#█	\
	1#*	1#█	1##	1#◘	1#⁂	1#◙	\
	1#▄	1#█	1#▆	1#█	1#▒	1#▓	\
	1#.	1#▛	1#☿	1#▛	1#:	1#▒	\
	1#▄	1#█	1#◙	1#█	1#▆	1#▓
typeset -i1 m2c[*]

set -A m2m
integer m2m

integer i=-1 j
while (( ++i <= 0x1F )); do
	(( m2m[i] = !i ? 0 : (i & B_BLK) ? 1 :
	    (i & B_NB) ? ((i & B_DOT) ? 5 : 3) : (i & B_DOT) ? 4 : 2 ))
done

function refresh {
	local -i10 i j z s c
	local t

	for i in "$@"; do
		(( z = (i / n) & 0xFFFE ))
		(( s = i % n ))
		(( i = m2m[fb[z * n + s]] ))
		(( j = m2m[fb[(z + 1) * n + s]] ))
		print -n "\e[$((z / 2 + 1));$((s + 1))H${m2c[j * 6 + i]#1#}"
	done
	print -n "\e[$((r / 2 + 1));$((r + 1))H\e[7mⓄ\e[0m"
}

# put arrayname x y
function put {
	local _x=$(($2)) _y=$(($3)) _i
	nameref _px=$1

	(( _i = (r - _y) * n + _x + r ))
	_px+=($_i)
}

# retrace arrayname maskname colourname
set -A px
function retrace {
	nameref _px=$1 _m=$2 _c=$3
	local _i

	for _i in "${_px[@]}"; do
		(( fb[_i] = (fb[_i] & _m) | _c ))
	done
	px+=("${_px[@]}")
}

draw_progress_bar

# precalculate all lines’ endpoints with bc and paths with Bresenham
integer x y dx sx dy sy e f
bc -l $bcopt |&
print -p scale=20
print -p r=$r
print -p o=r
print -p 'define p(t) {
	auto d
	d = 90 - t
	if (d < 0) d = 360 + d
	return (d * 3.1415926535897932 / 180)
}'
# minutes and seconds – full length, 60 items
i=-1
while (( ++i < 60 )); do
	draw_progress_bar
	eval set -A lms$i
	print -p "r * c(p($i * 6))"
	read -p S; [[ $S = ?(-).* ]] && S=0
	x=${S%%.*}
	print -p "r * s(p($i * 6))"
	read -p S; [[ $S = ?(-).* ]] && S=0
	y=${S%%.*}
	(( dx = x < 0 ? -x : x ))
	(( sx = x < 0 ? 1 : -1 ))
	(( dy = y < 0 ? y : -y ))
	(( sy = y < 0 ? 1 : -1 ))
	(( e = dx + dy ))
	while :; do
		put lms$i x y
		(( !x && !y )) && break
		(( f = 2 * e ))
		if (( f > dy )); then
			(( e += dy ))
			(( x += sx ))
		fi
		if (( f < dx )); then
			(( e += dx ))
			(( y += sy ))
		fi
	done
done
# hours – 2/3 length, 60 items (5 per hour)
print -p 'r = o * 2 / 3'
i=-1
while (( ++i < 60 )); do
	draw_progress_bar
	eval set -A lh$i
	print -p "r * c(p($i * 6))"
	read -p S; [[ $S = ?(-).* ]] && S=0
	x=${S%%.*}
	print -p "r * s(p($i * 6))"
	read -p S; [[ $S = ?(-).* ]] && S=0
	y=${S%%.*}
	(( dx = x < 0 ? -x : x ))
	(( sx = x < 0 ? 1 : -1 ))
	(( dy = y < 0 ? y : -y ))
	(( sy = y < 0 ? 1 : -1 ))
	(( e = dx + dy ))
	while :; do
		put lh$i x y
		(( !x && !y )) && break
		(( f = 2 * e ))
		if (( f > dy )); then
			(( e += dy ))
			(( x += sx ))
		fi
		if (( f < dx )); then
			(( e += dx ))
			(( y += sy ))
		fi
	done
done
# hour markers – 80% length, 12 items
print -p 'r = o * 8 / 10'
i=-1
set -A mkx
set -A mky
while (( ++i < 12 )); do
	draw_progress_bar
	print -p "r * c(p($i * 30))"
	read -p S; [[ $S = ?(-).* ]] && S=0
	mkx[i]=${S%%.*}
	print -p "r * s(p($i * 30))"
	read -p S; [[ $S = ?(-).* ]] && S=0
	mky[i]=${S%%.*}
done
exec 3>&p; exec 3>&-

draw_progress_bar
(( L = LINES >= (COLUMNS / 2) ? (COLUMNS / 2) : LINES ))
# fine-tuning of roman numeral position via screen size
(( ++mkx[7] ))
(( ++mkx[8] ))
case $L {
(22|23)	(( ++mkx[6] )) ;|
(23)
	(( mky[1] += 2 ))
	(( mky[2] += 2 ))
	(( mky[10] += 2 ))
	(( mky[11] += 2 ))
	;;
(24|25|29|30|31|34)
	(( mky[4] += 2 ))
	(( mky[8] += 2 ))
	;|
(27|28|29)
	(( ++mkx[10] ))
	(( mky[8] += 2 ))
	(( mky[9] += 2 ))
	(( mky[10] += 2 ))
	;|
(27|29|31)
	(( mky[0] -= 2 ))
	;|
(27)
	(( --mkx[4] ))
	(( --mkx[5] ))
	(( ++mkx[6] ))
	(( mkx[7] += 2 ))
	(( ++mkx[8] ))
	(( ++mkx[10] ))
	;;
(29)
	(( mky[5] += 2 ))
	(( mky[7] += 2 ))
	;;
(30)
	(( mky[11] -= 2 ))
	;;
}
(( mky[0] += 2 * (L & 1) ))
done_progress_bar

# clear framebuffer and screen
set -A fb
integer fb
print -n -- '\e[H\e[J'

# draw hour markers
set -A lb
integer e f=-1 k
(( L > 21 )) && while (( ++f < 12 )); do
	(( i=mkx[f] ))
	(( j = mky[f] & ~1 ))
	case $f {
	(0) e=7 S='# # # # #  # ## # # #' ;;
	(1) e=1 S='###' ;;
	(2) e=3 S='# ## ## #' ;;
	(3) e=5 S='# # ## # ## # #' ;;
	(4) e=5 S='# # ## # ##  # ' ;;
	(5) e=3 S='# ## # # ' ;;
	(6) e=5 S='# # ## # # #  #' ;;
	(7) e=7 S='# # # ## # # # #  # #' ;;
	(8) e=9 S='# # # # ## # # # # #  # # #' ;;
	(9) e=5 S='# # ##  # # # #' ;;
	(10) e=3 S='# # # # #' ;;
	(11) e=5 S='# # # #  ## # #' ;;
	}
	Y='0 1 2'
	if (( L > 26 )); then
		d='###########'
		S="${d::e+2} ${S::e}  ${S: e:e}  ${S:2*e} ${d::e+2}"
		(( e += 2 ))
		Y+=' 3 4'
		(( j += 2 ))
	fi
	(( i -= e / 2 ))
	k=0
	for y in $Y; do
		(( y = j - y * 2 + 1 + (r & 1) ))
		(( dy = y + 1 ))
		(( x = i - 1 ))
		while (( ++x < (i + e) )); do
			[[ ${S: k++:1} = ' ' ]] && continue
			put lb x y
			put lb x dy
		done
	done
done
retrace lb M_BG F_BG

# draw outer circle with Bresenham
set -A lc
integer x=r y=-1 f=r dx dy
while (( y < x )); do
	(( dy = y++ * 2 + 1 ))
	if (( y )); then
		(( f -= dy ))
		if (( f < 0 )); then
			(( dx = 1 - x-- * 2 ))
			(( f -= dx ))
		fi
	fi
	put lc x y
	put lc -x y
	put lc -x -y
	put lc x -y
	put lc y x
	put lc -y x
	put lc -y -x
	put lc y -x
done
retrace lc M_CC F_CC
refresh "${px[@]}"; set -A px

set -A do -- -1 -1 -1
isfirst=1
while (( !got_sigwinch )); do
	if (( isfirst )); then
		isfirst=0
	else
		(( tosleep = 1000000 - ${EPOCHREALTIME#*.} ))
		if (( tosleep > 999999 )); then
			sleep 0.2
			(( tosleep = 1000000 - ${EPOCHREALTIME#*.} ))
		fi
		if (( tosleep > 999999 )); then
			# huh… maybe no gettimeofday(2) here
			while :; do
				d=$(date +'%H %M %S,%d %b %Y')
				set -A dt $d
				(( dt[2] == do[2] )) || break
				sleep 0.1
			done
		else
			sleep 0.$tosleep
		fi
	fi

	d=$(date +'%H %M %S,%d %b %Y')
	S=${d#*,}
	d=${d%,*}
	set -A dt $d

	(( dt[0] = (dt[0] % 12) * 5 + (dt[1] / 12) ))
	if (( do[2] != -1 )); then
		retrace lms$((do[2])) M_SP F_NO
		(( do[1] == dt[1] )) || retrace lms$((do[1])) M_MP F_NO
		(( do[0] == dt[0] )) || retrace lh$((do[0])) M_HP F_NO
	fi
	(( do[0] == dt[0] )) || retrace lh$((dt[0])) M_HP F_HP
	(( do[1] == dt[1] )) || retrace lms$((dt[1])) M_MP F_MP
	retrace lms$((dt[2])) M_SP F_SP
	refresh "${px[@]}"; set -A px
	set -A do -- "${dt[@]}"

	print -n "\e[1;$((n - ${%S} + 1))H$S\e[1;1H${d// /:}"
done
done