From f875a746f5dae1e395a3df83f05aebc28ae00d81 Mon Sep 17 00:00:00 2001 From: Eugene Syromyatnikov Date: Sun, 2 Sep 2018 20:04:27 +0200 Subject: [PATCH] util.c: add parse_ts * defs.h (parse_ts): New declaration. * util.c (parse_ts): New function. --- defs.h | 1 + util.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/defs.h b/defs.h index a9ef361a..9c025b27 100644 --- a/defs.h +++ b/defs.h @@ -969,6 +969,7 @@ extern void ts_add(struct timespec *, const struct timespec *, const struct time extern void ts_sub(struct timespec *, const struct timespec *, const struct timespec *); extern void ts_mul(struct timespec *, const struct timespec *, int); extern void ts_div(struct timespec *, const struct timespec *, int); +extern int parse_ts(const char *s, struct timespec *t); # ifdef ENABLE_STACKTRACE extern void unwind_init(void); diff --git a/util.c b/util.c index 814f78c4..1d2c621f 100644 --- a/util.c +++ b/util.c @@ -26,6 +26,7 @@ #include "largefile_wrappers.h" #include "print_utils.h" #include "static_assert.h" +#include "string_to_uint.h" #include "xlat.h" #include "xstring.h" @@ -91,6 +92,71 @@ ts_mul(struct timespec *tv, const struct timespec *a, int n) tv->tv_nsec = nsec % 1000000000; } +int +parse_ts(const char *s, struct timespec *t) +{ + enum { NS_IN_S = 1000000000 }; + + static const struct time_unit { + const char *s; + unsigned int mul; + } units[] = { + { "", 1000 }, /* default is microseconds */ + { "s", 1000000000 }, + { "ms", 1000000 }, + { "us", 1000 }, + { "ns", 1 }, + }; + static const char float_accept[] = "eE.-+0123456789"; + static const char int_accept[] = "+0123456789"; + + size_t float_len = strspn(s, float_accept); + size_t int_len = strspn(s, int_accept); + const struct time_unit *unit = NULL; + char *endptr = NULL; + double float_val = -1; + long long int_val = -1; + + if (float_len > int_len) { + errno = 0; + + float_val = strtod(s, &endptr); + + if (endptr == s || errno) + return -1; + if (float_val < 0) + return -1; + } else { + int_val = string_to_uint_ex(s, &endptr, LLONG_MAX, "smun"); + + if (int_val < 0) + return -1; + } + + for (size_t i = 0; i < ARRAY_SIZE(units); i++) { + if (strcmp(endptr, units[i].s)) + continue; + + unit = units + i; + break; + } + + if (!unit) + return -1; + + if (float_len > int_len) { + t->tv_sec = float_val / (NS_IN_S / unit->mul); + t->tv_nsec = ((uint64_t) ((float_val - + (t->tv_sec * (NS_IN_S / unit->mul))) + * unit->mul)) % NS_IN_S; + } else { + t->tv_sec = int_val / (NS_IN_S / unit->mul); + t->tv_nsec = (int_val % (NS_IN_S / unit->mul)) * unit->mul; + } + + return 0; +} + #if !defined HAVE_STPCPY char * stpcpy(char *dst, const char *src) -- 2.40.0