From a17363e992943244987dbab754b112c77d938b5d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Sat, 14 Oct 2023 17:06:51 +0200 Subject: [PATCH] common: New function scan_secondsstr. * common/gettime.c (scan_secondsstr): New. * common/t-gettime.c (test_scan_secondsstr): (main): Call it. --- common/gettime.c | 23 ++++++++++++++++++++ common/gettime.h | 1 + common/stringhelp.c | 2 +- common/t-gettime.c | 52 ++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 76 insertions(+), 2 deletions(-) diff --git a/common/gettime.c b/common/gettime.c index 2a9b71779..c3b0c6c6c 100644 --- a/common/gettime.c +++ b/common/gettime.c @@ -37,6 +37,7 @@ #ifdef HAVE_LANGINFO_H #include #endif +#include /* We use uint64_t. */ #include "util.h" #include "i18n.h" @@ -172,6 +173,28 @@ make_timestamp (void) } +/* Specialized version of atoi which returns an u32 instead of an int + * and caps the result at 2^32-2. Leading white space is skipped, + * scanning stops at at the first non-convertable byte. Note that we + * do not cap at 2^32-1 because that value is often used as error + * return. */ +u32 +scan_secondsstr (const char *string) +{ + uint64_t value = 0; + + while (*string == ' ' || *string == '\t') + string++; + for (; *string >= '0' && *string <= '9'; string++) + { + value *= 10; + value += atoi_1 (string); + if (value >= (u32)(-1)) + return (u32)(-1) - 1; + } + return (u32)value; +} + /**************** * Scan a date string and return a timestamp. diff --git a/common/gettime.h b/common/gettime.h index 4f7199f92..18f65ab1a 100644 --- a/common/gettime.h +++ b/common/gettime.h @@ -51,6 +51,7 @@ int gnupg_faked_time_p (void); u32 make_timestamp (void); char *elapsed_time_string (time_t since, time_t now); +u32 scan_secondsstr (const char *string); u32 scan_isodatestr (const char *string); int isotime_p (const char *string); int isotime_human_p (const char *string, int date_only); diff --git a/common/stringhelp.c b/common/stringhelp.c index 5407653de..9a2265258 100644 --- a/common/stringhelp.c +++ b/common/stringhelp.c @@ -725,7 +725,7 @@ compare_filenames (const char *a, const char *b) /* Convert a base-10 number in STRING into a 64 bit unsigned int * value. Leading white spaces are skipped but no error checking is - * done. Thus it is similar to atoi(). */ + * done. Thus it is similar to atoi(). See also scan_secondsstr. */ uint64_t string_to_u64 (const char *string) { diff --git a/common/t-gettime.c b/common/t-gettime.c index 13cb1a2f7..76c305204 100644 --- a/common/t-gettime.c +++ b/common/t-gettime.c @@ -43,6 +43,56 @@ static int errcount; #define INVALID ((time_t)(-1)) +static void +test_scan_secondsstr (void) +{ + struct { const char *string; u32 expected; } array [] = { + { "", 0 }, + { "0", 0 }, + { " 0", 0 }, + { " 0x", 0 }, + { " 1", 1 }, + { "-1", 0 }, + { " -1", 0 }, + { "2", 2 }, + { "11", 11 }, + { "011", 11 }, + { "3600 ", 3600 }, + { "65535", 65535 }, + { "65536", 65536 }, + { "65537", 65537 }, + { "4294967289", 4294967289 }, + { "4294967290", 4294967290 }, + { "4294967293", 4294967293 }, + { "4294967295", 4294967294 }, + { "4294967296", 4294967294 }, + { "4294967297", 4294967294 }, + { "4294967298", 4294967294 }, + { "4294967299", 4294967294 }, + { "4294967300", 4294967294 }, + { "5294967300", 4294967294 }, + { "9999999999", 4294967294 }, + { "99999999999",4294967294 }, + { NULL, 0 } + }; + int idx; + u32 val; + + for (idx=0; array[idx].string; idx++) + { + val = scan_secondsstr (array[idx].string); + if (val != array[idx].expected ) + { + fail (idx); + if (verbose) + fprintf (stderr, "string '%s' exp: %ld got: %ld\n", + array[idx].string, (unsigned long)array[idx].expected, + (unsigned long)val); + } + } +} + + static void test_isotime2epoch (void) { @@ -103,7 +153,6 @@ test_isotime2epoch (void) } - static void test_string2isotime (void) { @@ -269,6 +318,7 @@ main (int argc, char **argv) if (argc > 1 && !strcmp (argv[1], "--verbose")) verbose = 1; + test_scan_secondsstr (); test_isotime2epoch (); test_string2isotime (); test_isodate_human_to_tm ();