advgetopt 2.0.50
Parse complex command line arguments and configuration files in C++.
validator_duration.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
31// self
32//
34
36
37
38// cppthread
39//
40#include <cppthread/log.h>
41
42
43// snapdev
44//
45#include <snapdev/trim_string.h>
46
47
48// last include
49//
50#include <snapdev/poison.h>
51
52
53
54namespace advgetopt
55{
56
57
58
59namespace
60{
61
62
63
65 : public validator_factory
66{
67public:
69 {
70 validator::register_validator(*this);
71 }
72
73 virtual std::string get_name() const override
74 {
75 return std::string("duration");
76 }
77
78 virtual std::shared_ptr<validator> create(string_list_t const & data) const override
79 {
80 return std::make_shared<validator_duration>(data);
81 }
82};
83
85
86
87
88} // no name namespace
89
90
91
92
93
178{
179 for(auto r : flag_list)
180 {
181 if(r == "small")
182 {
184 }
185 else if(r == "large")
186 {
188 }
189 else if(!r.empty() && (r[0] | 0x20) >= 'a' && (r[0] | 0x20) <= 'z')
190 {
191 double const factor(suffix_to_factor(r, f_flags, -1.0));
192 if(factor < 0.0)
193 {
194 cppthread::log << cppthread::log_level_t::error
195 << r
196 << " is not a valid duration suffix or flag."
197 << cppthread::end;
198 continue;
199 }
201 }
202 else
203 {
205 std::string::size_type const pos(r.find("..."));
206 if(pos == std::string::npos)
207 {
209 {
210 cppthread::log << cppthread::log_level_t::error
211 << r
212 << " is not a valid duration."
213 << cppthread::end;
214 continue;
215 }
216 range.f_maximum = range.f_minimum;
217 }
218 else
219 {
220 std::string const min_value(snapdev::trim_string(r.substr(0, pos)));
221 if(!min_value.empty())
222 {
224 {
225 cppthread::log << cppthread::log_level_t::error
226 << min_value
227 << " is not a valid value for your range's start;"
228 " it must be a valid duration,"
229 " optionally preceded by a sign (+ or -)."
230 << cppthread::end;
231 continue;
232 }
233 }
234
235 std::string const max_value(snapdev::trim_string(r.substr(pos + 3)));
236 if(!max_value.empty())
237 {
239 {
240 cppthread::log << cppthread::log_level_t::error
241 << max_value
242 << " is not a valid value for your range's end;"
243 " it must be a valid duration,"
244 " optionally preceded by a sign (+ or -)."
245 << cppthread::end;
246 continue;
247 }
248 }
249
250 if(range.f_minimum > range.f_maximum)
251 {
252 cppthread::log << cppthread::log_level_t::error
253 << min_value
254 << " has to be smaller or equal to "
255 << max_value
256 << "; you have an invalid duration range."
257 << cppthread::end;
258 continue;
259 }
260 }
261 f_allowed_values.push_back(range);
262 }
263 }
264}
265
266
273std::string validator_duration::name() const
274{
275 return std::string("duration");
276}
277
278
291bool validator_duration::validate(std::string const & value) const
292{
293 double result(0);
295 {
296 set_error("not a valid duration.");
297 return false;
298 }
299
300 if(f_allowed_values.empty())
301 {
302 return true;
303 }
304
305 for(auto f : f_allowed_values)
306 {
307 if(result >= f.f_minimum
308 && result <= f.f_maximum)
309 {
310 return true;
311 }
312 }
313
314 set_error("out of range.");
315 return false;
316}
317
318
371 std::string const & value
372 , flag_t flags
373 , double suffix_default_factor
374 , double & result)
375{
376 result = 0.0;
377
378 // TODO: use libutf8 to walk the string and skip all UTF-8 spaces
379 //
380 char const * s(value.c_str());
381 while(isspace(*s))
382 {
383 ++s;
384 }
385 if(*s == '\0')
386 {
387 return false;
388 }
389
390 double r(0.0);
391 while(*s != '\0')
392 {
393 // get the number
394 //
395 char const * number(s);
396 if(*s == '+'
397 || *s == '-')
398 {
399 ++s;
400 }
401 while(*s >= '0' && *s <= '9')
402 {
403 ++s;
404 }
405 if(*s == '.')
406 {
407 do
408 {
409 ++s;
410 }
411 while(*s >= '0' && *s <= '9');
412 if(*s == '.')
413 {
414 // this would otherwise allow "2..8 year" which is probably
415 // a mistake (i.e. not "2.s" and ".8 year")
416 //
417 return false;
418 }
419 }
420 double n(0.0);
422 (*number == '.' ? "0" : "") + std::string(number, s - number)
423 , n))
424 {
425 return false;
426 }
427
428 while(isspace(*s))
429 {
430 ++s;
431 }
432
433 // get the suffix
434 //
435 std::string suffix;
436 for(;; ++s)
437 {
438 if(*s >= 'A'
439 && *s <= 'Z')
440 {
441 // make lowercase as we're at it
442 //
443 suffix += *s + 0x20;
444 }
445 else if(*s >= 'a'
446 && *s <= 'z')
447 {
448 suffix += *s;
449 }
450 else
451 {
452 break;
453 }
454 }
455
457 if(factor < 0.0)
458 {
459 return false;
460 }
461
462 // TODO: catch ERANGE errors
463 //
464 r += n * factor;
465
466 while(isspace(*s))
467 {
468 ++s;
469 }
470 }
471
472 result = r;
473
474 return true;
475}
476
477
494 std::string const & suffix
495 , flag_t flags
496 , double suffix_default_factor)
497{
498 // if empty use default
499 //
500 if(suffix.empty())
501 {
503 }
504
505 switch(suffix[0])
506 {
507 case 'd':
508 if(suffix == "d"
509 || suffix == "day"
510 || suffix == "days")
511 {
512 return 86400.0;
513 }
514 break;
515
516 case 'h':
517 if(suffix == "h"
518 || suffix == "hour"
519 || suffix == "hours")
520 {
521 return 3600.0;
522 }
523 break;
524
525 case 'm':
526 if(suffix == "m")
527 {
528 if((flags & VALIDATOR_DURATION_LONG) != 0)
529 {
530 return 86400.0 * 30.0; // 1 month
531 }
532 else
533 {
534 return 60.0; // 1 minute
535 }
536 }
537 else if(suffix == "minute"
538 || suffix == "minutes")
539 {
540 return 60.0;
541 }
542 else if(suffix == "month"
543 || suffix == "months")
544 {
545 return 86400.0 * 30.0;
546 }
547 else if(suffix == "mi"
548 || suffix == "microsecond"
549 || suffix == "microseconds")
550 {
551 return 0.000001;
552 }
553 else if(suffix == "ms"
554 || suffix == "millisecond"
555 || suffix == "milliseconds")
556 {
557 return 0.001;
558 }
559 break;
560
561 case 'n':
562 if(suffix == "ns"
563 || suffix == "nanosecond"
564 || suffix == "nanoseconds")
565 {
566 return 0.000000001;
567 }
568 break;
569
570 case 's':
571 if(suffix == "s"
572 || suffix == "second"
573 || suffix == "seconds")
574 {
575 return 1.0;
576 }
577 break;
578
579 case 'w':
580 if(suffix == "w"
581 || suffix == "week"
582 || suffix == "weeks")
583 {
584 return 86400.0 * 7.0;
585 }
586 break;
587
588 case 'y':
589 if(suffix == "y"
590 || suffix == "year"
591 || suffix == "years")
592 {
593 return 86400.0 * 365.0;
594 }
595 break;
596
597 }
598
599 return -1.0;
600}
601
602
603
604} // namespace advgetopt
605// vim: ts=4 sw=4 et
virtual std::shared_ptr< validator > create(string_list_t const &data) const override
static bool convert_string(std::string const &number, double &result)
Convert a string to a double value.
virtual std::string name() const override
Return the name of this validator.
virtual bool validate(std::string const &value) const override
Determine whether value is a valid duration.
validator_duration(string_list_t const &data)
Initialize the duration validator.
static bool convert_string(std::string const &duration, flag_t flags, double suffix_default_factor, double &result)
Convert a string to a double value representing a duration.
static double suffix_to_factor(std::string const &suffix, flag_t flags, double suffix_default_factor)
Convert a duration suffix in a factor.
static constexpr flag_t VALIDATOR_DURATION_LONG
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.
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.