advgetopt 2.0.49
Parse complex command line arguments and configuration files in C++.
validator_integer.cpp
Go to the documentation of this file.
1// Copyright (c) 2006-2025 Made to Order Software Corp. All Rights Reserved
2//
3// https://snapwebsites.org/project/advgetopt
4// contact@m2osw.com
5//
6// This program is free software; you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation; either version 2 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License along
17// with this program; if not, write to the Free Software Foundation, Inc.,
18// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
44// self
45//
47
48
49// cppthread
50//
51#include <cppthread/log.h>
52
53
54// snapdev
55//
56#include <snapdev/trim_string.h>
57
58
59// last include
60//
61#include <snapdev/poison.h>
62
63
64
65
66namespace advgetopt
67{
68
69
70
71namespace
72{
73
74
75
77 : public validator_factory
78{
79public:
81 {
82 validator::register_validator(*this);
83 }
84
85 virtual std::string get_name() const override
86 {
87 return std::string("integer");
88 }
89
90 virtual std::shared_ptr<validator> create(string_list_t const & data) const override
91 {
92 return std::make_shared<validator_integer>(data);
93 }
94};
95
97
98
99
100} // no name namespace
101
102
103
104
105
152{
154 for(auto r : range_list)
155 {
156 std::string::size_type const pos(r.find("..."));
157 if(pos == std::string::npos)
158 {
159 if(!convert_string(r, range.f_minimum))
160 {
161 cppthread::log << cppthread::log_level_t::error
162 << r
163 << " is not a valid standalone value for your ranges;"
164 " it must only be digits, optionally preceeded by a sign (+ or -)"
165 " and not overflow an int64_t value."
166 << cppthread::end;
167 continue;
168 }
169 range.f_maximum = range.f_minimum;
170 }
171 else
172 {
173 std::string const min_value(snapdev::trim_string(r.substr(0, pos)));
174 if(!min_value.empty())
175 {
176 if(!convert_string(min_value, range.f_minimum))
177 {
178 cppthread::log << cppthread::log_level_t::error
179 << min_value
180 << " is not a valid value for your range's start;"
181 " it must only be digits, optionally preceeded by a sign (+ or -)"
182 " and not overflow an int64_t value."
183 << cppthread::end;
184 continue;
185 }
186 }
187
188 std::string const max_value(snapdev::trim_string(r.substr(pos + 3)));
189 if(!max_value.empty())
190 {
191 if(!convert_string(max_value, range.f_maximum))
192 {
193 cppthread::log << cppthread::log_level_t::error
194 << max_value
195 << " is not a valid value for your range's end;"
196 " it must only be digits, optionally preceeded by a sign (+ or -)"
197 " and not overflow an int64_t value."
198 << cppthread::end;
199 continue;
200 }
201 }
202
203 if(range.f_minimum > range.f_maximum)
204 {
205 cppthread::log << cppthread::log_level_t::error
206 << min_value
207 << " has to be smaller or equal to "
208 << max_value
209 << "; you have an invalid range."
210 << cppthread::end;
211 continue;
212 }
213 }
214 f_allowed_values.push_back(range);
215 }
216}
217
218
225std::string validator_integer::name() const
226{
227 return std::string("integer");
228}
229
230
250bool validator_integer::validate(std::string const & value) const
251{
252 std::int64_t result(0);
253 if(convert_string(value, result))
254 {
255 if(f_allowed_values.empty())
256 {
257 return true;
258 }
259
260 for(auto f : f_allowed_values)
261 {
262 if(result >= f.f_minimum
263 && result <= f.f_maximum)
264 {
265 return true;
266 }
267 }
268 set_error("out of range.");
269 return false;
270 }
271
272 set_error("not a valid number.");
273 return false;
274}
275
276
291bool validator_integer::convert_string(std::string const & value, std::int64_t & result)
292{
293 std::uint64_t integer(0);
294 char const * s(value.c_str());
295
296 char sign('\0');
297 if(*s == '-' || *s == '+')
298 {
299 sign = *s;
300 ++s;
301 }
302
303 int base(10);
304 if(*s == '0')
305 {
306 if(s[1] == 'b')
307 {
308 base = 2;
309 s += 2;
310 }
311 else if(s[1] == 'd')
312 {
313 //base = 10; -- this is the default
314 s += 2;
315 }
316 else if(s[1] == 'o')
317 {
318 base = 8;
319 s += 2;
320 }
321 else if(s[1] == 'x')
322 {
323 base = 16;
324 s += 2;
325 }
326 // else start from 's' (including the '0')
327 }
328
329 if(*s == '\0')
330 {
331 // empty string or just the introducer, not considered valid
332 //
333 return false;
334 }
335
336 for(;;)
337 {
338 char const c(*s++);
339 if(c == '\0')
340 {
341 // valid
342 //
343 if(sign == '-')
344 {
345 if(integer > 0x8000000000000000ULL)
346 {
347 return false;
348 }
349 result = -integer;
350 }
351 else
352 {
353 if(integer > 0x7FFFFFFFFFFFFFFFULL)
354 {
355 return false;
356 }
357 result = integer;
358 }
359 return true;
360 }
361
362 std::int64_t digit(std::numeric_limits<std::int64_t>::max());
363 if(c >= '0' && c <= '9')
364 {
365 digit = c - '0';
366 }
367 else if(c >= 'a' && c <= 'f')
368 {
369 digit = c - ('a' - 10);
370 }
371 else if(c >= 'A' && c <= 'F')
372 {
373 digit = c - ('A' - 10);
374 }
375 if(digit >= base)
376 {
377 // invalid digit
378 //
379 return false;
380 }
381
382 std::uint64_t const old(integer);
384 if(integer < old)
385 {
386 // overflow
387 //
388 return false;
389 }
390 }
391}
392
393
394
395} // namespace advgetopt
396// vim: ts=4 sw=4 et
virtual std::shared_ptr< validator > create(string_list_t const &data) const override
virtual bool validate(std::string const &value) const override
Determine whether value is an integer.
static bool convert_string(std::string const &number, std::int64_t &result)
Convert a string to an std::int64_t value.
validator_integer(string_list_t const &data)
Initialize the integer validator.
virtual std::string name() const override
Return the name of this validator.
void set_error(std::string const &msg) const
The advgetopt environment to parse command line options.
Definition version.h:37
constexpr flag_t option_flags_merge()
Definition flags.h:87
std::vector< std::string > string_list_t
Definition utils.h:41
Declaration of validators which can be used to verify the parameters.

This document is part of the Snap! Websites Project.

Copyright by Made to Order Software Corp.