Skip to content

Commit 4e895dc

Browse files
committed
Add read_value function for improved parameter parsing
1 parent 898dabd commit 4e895dc

1 file changed

Lines changed: 51 additions & 17 deletions

File tree

include/mdcomp/options_lib.hh

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include <string_view>
4141
#include <system_error>
4242
#include <tuple>
43+
#include <type_traits>
4344
#include <utility>
4445

4546
enum class argument : uint8_t {
@@ -127,6 +128,47 @@ namespace detail {
127128
throw 5;
128129
}
129130

131+
template <std::integral T>
132+
inline void read_value(std::string_view parameter, T& value) {
133+
bool const starts_with_minus = parameter.starts_with('-');
134+
if (starts_with_minus || parameter.starts_with('+')) {
135+
parameter.remove_prefix(1);
136+
}
137+
138+
if constexpr (std::is_unsigned_v<T>) {
139+
if (starts_with_minus) {
140+
std::cerr << "Cannot parse negative value for unsigned type!\n";
141+
throw 5;
142+
}
143+
}
144+
size_t const base = [&]() {
145+
if (parameter.starts_with("0x") || parameter.starts_with("0X")) {
146+
parameter.remove_prefix(2);
147+
return 16U;
148+
}
149+
if (parameter.starts_with("0b") || parameter.starts_with("0B")) {
150+
parameter.remove_prefix(2);
151+
return 2U;
152+
}
153+
if (parameter.starts_with("0o") || parameter.starts_with("0O")) {
154+
parameter.remove_prefix(2);
155+
return 8U;
156+
}
157+
return 10U;
158+
}();
159+
auto [ptr, ec] = std::from_chars(
160+
std::ranges::cbegin(parameter), std::ranges::cend(parameter), value,
161+
base);
162+
if (ec != std::errc{} || ptr != std::ranges::cend(parameter)) {
163+
print_error(ec, "value", parameter.data());
164+
}
165+
if constexpr (std::is_signed_v<T>) {
166+
if (starts_with_minus) {
167+
value = -value;
168+
}
169+
}
170+
}
171+
130172
template <typename options_t>
131173
concept has_crunch = requires(options_t opt) {
132174
{ opt.crunch } -> std::same_as<bool&>;
@@ -220,13 +262,11 @@ namespace detail {
220262
inline void parse_extract(options_t& options, char const* parameter_in) {
221263
options.extract = true;
222264
if (parameter_in != nullptr) {
223-
std::string_view const parameter(parameter_in);
224-
auto [ptr, ec] = std::from_chars(
225-
std::ranges::cbegin(parameter), std::ranges::cend(parameter),
226-
options.pointer);
227-
if (ec != std::errc{}) {
228-
print_error(ec, "pointer", parameter_in);
229-
}
265+
read_value({parameter_in}, options.pointer);
266+
}
267+
if (options.pointer < 0) {
268+
std::cerr << "Error: specified file offset must be a positive number.\n";
269+
throw 4;
230270
}
231271
}
232272

@@ -248,13 +288,7 @@ namespace detail {
248288
inline void parse_padding(options_t& options, char const* parameter_in) {
249289
if constexpr (has_padding<options_t>) {
250290
if (parameter_in != nullptr) {
251-
std::string_view const parameter(parameter_in);
252-
auto [ptr, ec] = std::from_chars(
253-
std::ranges::cbegin(parameter), std::ranges::cend(parameter),
254-
options.padding);
255-
if (ec != std::errc{}) {
256-
print_error(ec, "padding", optarg);
257-
}
291+
read_value({parameter_in}, options.padding);
258292
}
259293
if ((options.padding == 0U) || !std::has_single_bit(options.padding)) {
260294
options.padding = options_t::format_t::MODULE_PADDING;
@@ -270,10 +304,10 @@ namespace detail {
270304
}
271305

272306
template <typename options_t>
273-
inline void parse_size(options_t& options, char const* parameter) {
307+
inline void parse_size(options_t& options, char const* parameter_in) {
274308
if constexpr (has_size<options_t>) {
275-
if (parameter != nullptr) {
276-
options.size = strtoul(parameter, nullptr, 0);
309+
if (parameter_in != nullptr) {
310+
read_value({parameter_in}, options.size);
277311
}
278312
if (options.size == 0) {
279313
std::cerr << "Error: specified size must be a positive number.\n";

0 commit comments

Comments
 (0)