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
|
use fmt;
use ev;
use getopt;
use os;
use time;
use strings;
use strconv;
use math;
type uniterror = !void;
fn timer_handler(file: *ev::file) void = {
const loop = ev::getloop(file);
const t = ev::getuser(file): *time::instant;
const t = *t;
if (print_countdown(t)) {
ev::stop(loop);
};
};
fn print_countdown(instant: time::instant) bool = {
const tn = time::now(time::clock::MONOTONIC);
const currentduration = time::diff(tn, instant);
// man page console_codes(4) is useful
fmt::fprint(os::stderr, "\x1B[1K\r")!;
const count = human_readable(currentduration);
defer free(count);
fmt::fprint(os::stderr, count)!;
return currentduration <= 0;
};
// Transform a duration to a human readable string representation.
fn human_readable(duration: time::duration) str = {
const hours = if (duration > time::HOUR) {
let hours = math::floorf64(duration: f64 / time::HOUR: f64): u64;
duration = (duration % time::HOUR);
yield hours;
} else {
yield 0u64;
};
const mins = if (duration > time::MINUTE) {
let mins = math::floorf64(duration: f64 / time::MINUTE: f64): u64;
duration = (duration % time::MINUTE);
yield mins;
} else {
yield 0u64;
};
const secs = if (duration > time::SECOND) {
yield math::floorf64(duration: f64 / time::SECOND: f64): u64;
} else {
yield 0u64;
};
const mods = &fmt::mods {
pad = '0',
width = 2,
...
};
return fmt::asprintf("{%}:{%}:{%}", hours, mods, mins, mods, secs, mods);
};
fn parse_duration(duration: const str) (time::duration | uniterror | strconv::invalid | strconv::overflow) = {
const s = strings::toutf8(duration);
const unit = s[len(s)-1];
const unit = switch (unit) {
case 's' =>
yield time::SECOND;
case 'm' =>
yield time::MINUTE;
case 'h' =>
yield time::HOUR;
case =>
return uniterror;
};
const d = strconv::stoi(strings::sub(duration, 0, len(duration) - 1))?;
return d * unit;
};
export fn main() void = {
const cmd = getopt::parse(os::args,
"timer for alarms",
"duration",
);
defer getopt::finish(&cmd);
if (len(cmd.args) != 1) {
getopt::printusage(os::stderr, os::args[0], cmd.help)!;
os::exit(os::status::FAILURE);
};
const duration = cmd.args[0];
const duration = parse_duration(duration)!;
const loop = ev::newloop()!;
const t = time::now(time::clock::MONOTONIC);
const t = time::add(t, duration);
defer ev::finish(&loop);
const f = ev::newtimer(&loop, &timer_handler, time::clock::MONOTONIC)!;
ev::setuser(f, &t);
print_countdown(t);
ev::timer_configure(f, 1 * time::SECOND, 1 * time::SECOND);
for (ev::dispatch(&loop, -1)!) void;
fmt::println()!;
};
|