summaryrefslogtreecommitdiff
path: root/timer.ha
blob: d3b5c620819ddcf4a1d47e73e662246040ea5efe (plain)
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
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;
	const tn = time::now(time::clock::MONOTONIC);
	const currentduration = time::diff(tn, t);

	// man page console_codes(4) is useful
	fmt::fprint(os::stderr, "\x1B[1K\r")!;
	fmt::fprint(os::stderr, math::ceilf64(currentduration: f64 / time::SECOND: f64): u64)!;
	if (currentduration <= 0) {
		ev::stop(loop);
	};
};

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);

	ev::timer_configure(f, 1 * time::SECOND, 1 * time::SECOND);

	for (ev::dispatch(&loop, -1)!) void;
	fmt::println()!;
};