~nabijaczleweli/klapki.deb

ref: 50de836242adb578bc1bb6c288ddc450c4a4765c klapki.deb/src/ops.cpp -rw-r--r-- 4.8 KiB
50de8362наб Fix upstream homepage link 1 year, 2 months 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
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
// The MIT License (MIT)

// Copyright (c) 2020 наб <nabijaczleweli@nabijaczleweli.xyz>

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


#include "ops.hpp"
#include <cstring>
#include <limits>


template <class T, class N>
static std::variant<klapki::ops::op_t, std::string> pos_op(const char * argv0, const char **& argv, const char * name) {
	char * end;
	// strtoul(3): In particular, if *nptr is not '\0' but **endptr is '\0' on return, the entire string is valid.
	if(!argv[0] || argv[0][0] == '\0')
		return fmt::format("{}: {} requires a position", argv0, name);
	errno               = 0;
	const auto position = argv[0];
	++argv;
	const auto num = std::strtoull(position, &end, 0);
	if(num > std::numeric_limits<N>::max())
		return fmt::format("{}: {} position {} must fit in {} bits", argv0, name, position, sizeof(N) * 8);
	if(*end != '\0')
		return fmt::format("{}: {} position {}: {}", argv0, name, position, errno ? strerror(errno) : "not a number");

	return T{static_cast<N>(num)};
}

template <class T>
static std::variant<klapki::ops::op_t, std::string> oneval_op(const char * argv0, const char **& argv, const char * name, const char * aname) {
	if(!argv[0])
		return fmt::format("{}: {} needs {}", argv0, name, aname);
	return T{argv++[0]};
}

static std::variant<klapki::ops::op_t, std::string> addkernel_op(const char * argv0, const char **& argv) {
	klapki::ops::addkernel ret;

	if(!argv[0])
		return fmt::format("{}: addkernel needs <version> <image> [initrd…] <\"\">", argv0);
	ret.version = argv[0];
	++argv;

	if(!argv[0])
		return fmt::format("{}: addkernel {} needs <image> [initrd…] <\"\">", argv0, ret.version);
	if(argv[0][0] == '\0')
		return fmt::format("{}: addkernel {} image can't be empty", argv0, ret.version);
	ret.image = argv[0];
	++argv;

	while(argv[0]) {
		const auto initrd = argv[0];
		++argv;
		if(initrd[0] == '\0')
			break;
		ret.initrds.emplace_back(initrd);
	}
	if(argv[-1][0] != '\0')
		return fmt::format("{}: addkernel {} {} initrd list needs to end with empty argument", argv0, ret.version, ret.image);

	return ret;
}


std::variant<klapki::ops::op_t, std::string> klapki::op::from_cmdline(const char * argv0, const char **& argv) {
	if(!*argv)
		return "Parser error: klapki::op::from_cmdline() invoked with no arguments left to parse";

	const auto opname = argv[0];
	++argv;
	if(!std::strcmp(opname, "dump"))
		return ops::dump{};
	else if(!std::strcmp(opname, "bootpos"))
		return pos_op<ops::bootpos, std::uint16_t>(argv0, argv, "bootpos");
	else if(!std::strcmp(opname, "addkernel"))
		return addkernel_op(argv0, argv);
	else if(!std::strcmp(opname, "delkernel"))
		return oneval_op<ops::delkernel>(argv0, argv, "delkernel", "version");
	else if(!std::strcmp(opname, "addvariant"))
		return oneval_op<ops::addvariant>(argv0, argv, "addvariant", "variant");
	else if(!std::strcmp(opname, "delvariant"))
		return oneval_op<ops::delvariant>(argv0, argv, "delvariant", "variant");
	else
		return fmt::format("{}: unknown op {}", argv0, opname);
}


std::optional<std::string> klapki::op::execute(const klapki::ops::op_t & op, const config & cfg, state::state & state, context::context & context) {
	return std::visit(klapki::overload{
	                      [&](const klapki::ops::dump & d) { return ops::execute(d, cfg, state, context); },
	                      [&](const klapki::ops::bootpos & bp) { return ops::execute(bp, cfg, state, context); },
	                      [&](const klapki::ops::addkernel & ak) { return ops::execute(ak, cfg, state, context); },
	                      [&](const klapki::ops::delkernel & dk) { return ops::execute(dk, cfg, state, context); },
	                      [&](const klapki::ops::addvariant & av) { return ops::execute(av, cfg, state, context); },
	                      [&](const klapki::ops::delvariant & dv) { return ops::execute(dv, cfg, state, context); },
	                  },
	                  op);
}