~nabijaczleweli/voreutils

ref: 8252842e7ff74305e5642881658959dc00307d44 voreutils/cmd/sleep.cpp -rw-r--r-- 1.9 KiB
8252842eнаб Add echo a month ago
                                                                                
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
// SPDX-License-Identifier: 0BSD


#include <cmath>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <limits>
#include <string>
#include <unistd.h>
#include <vore-optarg>


int main(int, char * const * argv) {
	if(!argv[0] || !argv[1]) {
		std::fprintf(stderr, "usage: %s delay[smhdwy]...\n", argv[0]);
		return 1;
	}

	for(std::string_view delay : vore::opt::args{argv + 1}) {
		double mult = 1;
		if(!delay.empty() && !isdigit(delay.back())) {
			switch(delay.back()) {
				case 'y':
					mult *= 365.25 / 7.;
				case 'w':
					mult *= 7;
				case 'd':
					mult *= 24;
				case 'h':
					mult *= 60;
				case 'm':
					mult *= 60;
				case 's':
					break;
				default:
					std::fprintf(stderr, "Unrecognised suffix %c; must be one of: smhdwy\n", delay.back());
					return 1;
			}

			delay = delay.substr(0, delay.size() - 1);
		}

		// libstdc++ in Buster doesn't have std::from_chars for floating-point types! Very cool!
		std::string delay_s{delay};
		char * delay_se{};
		double base = std::strtod(delay_s.c_str(), &delay_se);
		if(base == 0 && delay_se == delay_s.c_str()) {
			std::fprintf(stderr, "Invalid delay: %s\n", delay_s.c_str());
			return 1;
		}
		if(std::isnan(base)) {
			std::fprintf(stderr, "Invalid delay: %s: not a number\n", delay_s.c_str());
			return 1;
		}

		if(base <= 0)
			continue;

		double tosleep = base * mult;
		double waited  = 0;
		while(tosleep > waited + static_cast<double>(std::numeric_limits<std::time_t>::max())) {
			const struct timespec del { std::numeric_limits<std::time_t>::max(), 0 };
			(void)nanosleep(&del, nullptr);
			waited += static_cast<double>(std::numeric_limits<std::time_t>::max());
		}

		double seconds{};
		double subsec = std::modf(tosleep - waited, &seconds);
		const struct timespec del { static_cast<time_t>(seconds), static_cast<long>(subsec * 1000 * 1000 * 1000) };
		(void)nanosleep(&del, nullptr);
	}
}