]> granicus.if.org Git - strace/commitdiff
util.c: add parse_ts
authorEugene Syromyatnikov <evgsyr@gmail.com>
Sun, 2 Sep 2018 18:04:27 +0000 (20:04 +0200)
committerDmitry V. Levin <ldv@altlinux.org>
Tue, 6 Aug 2019 13:38:20 +0000 (13:38 +0000)
* defs.h (parse_ts): New declaration.
* util.c (parse_ts): New function.

defs.h
util.c

diff --git a/defs.h b/defs.h
index a9ef361a11837004046de9afadbcfa90938f7345..9c025b2747cc7739dae39940738be5ddd48e8a23 100644 (file)
--- 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 814f78c4cb4c35f42e4e789d8d9438cfa89a4c9a..1d2c621ffdde21fc841723d4ff7731ee3f7e2de8 100644 (file)
--- 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)