advgetopt 2.0.50
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 preceded 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 preceded 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 preceded 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 switch(s[1])
307 {
308 case 'B':
309 case 'b':
310 base = 2;
311 s += 2;
312 break;
313
314 case 'D':
315 case 'd':
316 //base = 10; -- this is the default
317 s += 2;
318 break;
319
320 case 'O':
321 case 'o':
322 base = 8;
323 s += 2;
324 break;
325
326 case 'X':
327 case 'x':
328 base = 16;
329 s += 2;
330 break;
331
332 // default: start from 's' (including the '0')
333 }
334 }
335
336 if(*s == '\0')
337 {
338 // empty string or just the introducer, not considered valid
339 //
340 return false;
341 }
342
343 for(;;)
344 {
345 char const c(*s++);
346 if(c == '\0')
347 {
348 // valid
349 //
350 if(sign == '-')
351 {
352 if(integer > 0x8000000000000000ULL)
353 {
354 return false;
355 }
356 result = -integer;
357 }
358 else
359 {
360 if(integer > 0x7FFFFFFFFFFFFFFFULL)
361 {
362 return false;
363 }
364 result = integer;
365 }
366 return true;
367 }
368
369 std::int64_t digit(std::numeric_limits<std::int64_t>::max());
370 if(c >= '0' && c <= '9')
371 {
372 digit = c - '0';
373 }
374 else if(c >= 'a' && c <= 'f')
375 {
376 digit = c - ('a' - 10);
377 }
378 else if(c >= 'A' && c <= 'F')
379 {
380 digit = c - ('A' - 10);
381 }
382 if(digit >= base)
383 {
384 // invalid digit
385 //
386 return false;
387 }
388
389 std::uint64_t const old(integer);
391 if(integer < old)
392 {
393 // overflow
394 //
395 return false;
396 }
397 }
398}
399
400
401
402} // namespace advgetopt
403// 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:89
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.