aboutsummaryrefslogtreecommitdiffstats
path: root/strtotimespec.c
diff options
context:
space:
mode:
Diffstat (limited to 'strtotimespec.c')
-rw-r--r--strtotimespec.c307
1 files changed, 296 insertions, 11 deletions
diff --git a/strtotimespec.c b/strtotimespec.c
index bd28260..9c6a6e0 100644
--- a/strtotimespec.c
+++ b/strtotimespec.c
@@ -4,7 +4,7 @@
int
-libsimple_strtotimespec(struct timespec *restrict ts, const char *restrict s, char **restrict end) /* TODO test */
+libsimple_strtotimespec(struct timespec *restrict ts, const char *restrict s, char **restrict end)
{
int neg = 0, bracket = 0;
time_t sec = 0;
@@ -18,11 +18,6 @@ libsimple_strtotimespec(struct timespec *restrict ts, const char *restrict s, ch
while (isspace(*s))
s++;
- if (!isdigit(s) && *s != '+' && *s != '-' && *s != '.') {
- errno = EINVAL;
- return -1;
- }
-
if (*s == '-') {
neg = 1;
s++;
@@ -30,6 +25,11 @@ libsimple_strtotimespec(struct timespec *restrict ts, const char *restrict s, ch
s++;
}
+ if (!isdigit(*s) && *s != '.') {
+ errno = EINVAL;
+ return -1;
+ }
+
if (*s == '.') {
if (s[1] == '.' || s[1] == '(') {
if (!isdigit(s[2])) {
@@ -44,16 +44,16 @@ libsimple_strtotimespec(struct timespec *restrict ts, const char *restrict s, ch
for (; isdigit(*s); s++) {
if (sec < TIME_MIN / 10)
- goto overflow;
+ goto overflow_integer;
sec *= 10;
if (sec < TIME_MIN + (*s & 15))
- goto overflow;
+ goto overflow_integer;
sec -= *s & 15;
}
if (!neg) {
if (TIME_MIN != -TIME_MAX && sec == TIME_MIN)
- goto overflow;
+ goto overflow_integer;
sec = -sec;
}
@@ -101,7 +101,7 @@ libsimple_strtotimespec(struct timespec *restrict ts, const char *restrict s, ch
nsec += 1;
if (nsec == 1000000000L) {
if (sec == TIME_MAX)
- goto overflow;
+ goto overflow_periodic;
sec += 1;
nsec = 0;
}
@@ -112,7 +112,7 @@ libsimple_strtotimespec(struct timespec *restrict ts, const char *restrict s, ch
nsec += 1;
if (nsec == 1000000000L) {
if (sec == TIME_MAX)
- goto overflow;
+ goto overflow_fraction;
sec += 1;
nsec = 0;
}
@@ -131,8 +131,43 @@ libsimple_strtotimespec(struct timespec *restrict ts, const char *restrict s, ch
sec -= 1;
}
+ ts->tv_sec = sec;
+ ts->tv_nsec = nsec;
return 0;
+
+overflow_integer:
+ while (isdigit(*s)) s++;
+ if (*s != '.')
+ goto overflow;
+ s++;
+
+overflow_fraction:
+ while (isdigit(*s)) s++;
+ if (*s == '(')
+ bracket = 1;
+ else if (*s != '.')
+ goto overflow;
+ s++;
+ if (!isdigit(*s)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+overflow_periodic:
+ if (bracket) {
+ while (isdigit(*s)) s++;
+ if (*s != ')') {
+ errno = EINVAL;
+ return -1;
+ }
+ s++;
+ } else {
+ while (isdigit(*s)) s++;
+ }
+
overflow:
+ if (end)
+ *end = (void *)s;
if (neg) {
ts->tv_sec = TIME_MIN;
ts->tv_nsec = 0;
@@ -148,9 +183,259 @@ overflow:
#else
#include "test.h"
+#define MS(N) N##000000L
+
+#define INVAL(S)\
+ do {\
+ errno = 0;\
+ assert(libsimple_strtotimespec(&t, (S), &end) == -1 && errno == EINVAL);\
+ errno = 0;\
+ } while (0)
+
int
main(void)
{
+ char s[1024];
+ struct timespec t;
+ char *end;
+
+ INVAL(""); INVAL("x"); INVAL("."); INVAL("("); INVAL(")"); INVAL(" "); INVAL(" x");
+ INVAL(" ."); INVAL(" ("); INVAL(" )"); INVAL("1.(1"); INVAL("1...1"); INVAL("1.()"); INVAL("1..");
+ INVAL("+"); INVAL("+x"); INVAL("+."); INVAL("+("); INVAL("+)"); INVAL("+ "); INVAL("+ x");
+ INVAL("+ ."); INVAL("+ ("); INVAL("+ )"); INVAL("+1.(1"); INVAL("+1...1"); INVAL("+1.()"); INVAL("+1..");
+ INVAL("-"); INVAL("-x"); INVAL("-."); INVAL("-("); INVAL("-)"); INVAL("- "); INVAL("- x");
+ INVAL("- ."); INVAL("- ("); INVAL("- )"); INVAL("-1.(1"); INVAL("-1...1"); INVAL("-1.()"); INVAL("-1..");
+ INVAL("++"); INVAL("++x"); INVAL("++."); INVAL("++("); INVAL("++)"); INVAL("++ "); INVAL("++ x");
+ INVAL("++ ."); INVAL("++ ("); INVAL("++ )"); INVAL("++1.(1"); INVAL("++1...1"); INVAL("++1.()"); INVAL("++1..");
+ INVAL("+-"); INVAL("+-x"); INVAL("+-."); INVAL("+-("); INVAL("+-)"); INVAL("+- "); INVAL("+- x");
+ INVAL("+- ."); INVAL("+- ("); INVAL("+- )"); INVAL("+-1.(1"); INVAL("+-1...1"); INVAL("+-1.()"); INVAL("+-1..");
+ INVAL("-+"); INVAL("-+x"); INVAL("-+."); INVAL("-+("); INVAL("-+)"); INVAL("-+ "); INVAL("-+ x");
+ INVAL("-+ ."); INVAL("-+ ("); INVAL("-+ )"); INVAL("-+1.(1"); INVAL("-+1...1"); INVAL("-+1.()"); INVAL("-+1..");
+ INVAL("--"); INVAL("--x"); INVAL("--."); INVAL("--("); INVAL("--)"); INVAL("-- "); INVAL("-- x");
+ INVAL("-- ."); INVAL("-- ("); INVAL("-- )"); INVAL("--1.(1"); INVAL("--1...1"); INVAL("--1.()"); INVAL("--1..");
+
+ assert(!libsimple_strtotimespec(&t, "0xyz", &end));
+ assert(t.tv_sec == 0);
+ assert(t.tv_nsec == 0L);
+ assert(!strcmp(end, "xyz"));
+
+ assert(!libsimple_strtotimespec(&t, "1 xyz", &end));
+ assert(t.tv_sec == 1);
+ assert(t.tv_nsec == 0L);
+ assert(!strcmp(end, " xyz"));
+
+ assert(!libsimple_strtotimespec(&t, " 0.1-", &end));
+ assert(t.tv_sec == 0);
+ assert(t.tv_nsec == MS(100));
+ assert(!strcmp(end, "-"));
+
+ assert(!libsimple_strtotimespec(&t, ".100", &end));
+ assert(t.tv_sec == 0);
+ assert(t.tv_nsec == MS(100));
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "0010.", &end));
+ assert(t.tv_sec == 10);
+ assert(t.tv_nsec == 0L);
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "0020.300", NULL));
+ assert(t.tv_sec == 20);
+ assert(t.tv_nsec == MS(300));
+
+ assert(!libsimple_strtotimespec(&t, "98.1002003004", &end));
+ assert(t.tv_sec == 98);
+ assert(t.tv_nsec == 100200300L);
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "99.1002003005", &end));
+ assert(t.tv_sec == 99);
+ assert(t.tv_nsec == 100200301L);
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "100.9999999991", &end));
+ assert(t.tv_sec == 100);
+ assert(t.tv_nsec == 999999999L);
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "101.9999999995x", &end));
+ assert(t.tv_sec == 102);
+ assert(t.tv_nsec == 0L);
+ assert(!strcmp(end, "x"));
+
+ assert(!libsimple_strtotimespec(&t, "9..1", &end));
+ assert(t.tv_sec == 9);
+ assert(t.tv_nsec == 111111111L);
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "8..2", &end));
+ assert(t.tv_sec == 8);
+ assert(t.tv_nsec == 222222222L);
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "7.(3)", &end));
+ assert(t.tv_sec == 7);
+ assert(t.tv_nsec == 333333333L);
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "6.(5)", &end));
+ assert(t.tv_sec == 6);
+ assert(t.tv_nsec == 555555556L);
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "4.(9)", &end));
+ assert(t.tv_sec == 5);
+ assert(t.tv_nsec == 0L);
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "3..9", &end));
+ assert(t.tv_sec == 4);
+ assert(t.tv_nsec == 0L);
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "2..0", &end));
+ assert(t.tv_sec == 2);
+ assert(t.tv_nsec == 0L);
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "2.(0)", &end));
+ assert(t.tv_sec == 2);
+ assert(t.tv_nsec == 0L);
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "11.22.33", &end));
+ assert(t.tv_sec == 11);
+ assert(t.tv_nsec == 223333333L);
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "22.333333333(4)", &end));
+ assert(t.tv_sec == 22);
+ assert(t.tv_nsec == 333333333L);
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "22.333333333(5)", &end));
+ assert(t.tv_sec == 22);
+ assert(t.tv_nsec == 333333334L);
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "22.333333333.4", &end));
+ assert(t.tv_sec == 22);
+ assert(t.tv_nsec == 333333333L);
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "22.333333333.5", &end));
+ assert(t.tv_sec == 22);
+ assert(t.tv_nsec == 333333334L);
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "+11.22.33", &end));
+ assert(t.tv_sec == 11);
+ assert(t.tv_nsec == 223333333L);
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "-11.22.33", &end));
+ assert(t.tv_sec == -12);
+ assert(t.tv_nsec == 1000000000L - 223333333L);
+ assert(!strcmp(end, ""));
+
+ assert(!libsimple_strtotimespec(&t, "-11", &end));
+ assert(t.tv_sec == -11);
+ assert(t.tv_nsec == 0L);
+ assert(!strcmp(end, ""));
+
+ sprintf(s, "%ji", (intmax_t)TIME_MIN);
+ errno = 0;
+ assert(!libsimple_strtotimespec(&t, s, &end));
+ errno = 0;
+ assert(t.tv_sec == TIME_MIN);
+ assert(t.tv_nsec == 0L);
+ assert(!strcmp(end, ""));
+
+ sprintf(s, "%ji.5", (intmax_t)TIME_MIN + (intmax_t)1);
+ errno = 0;
+ assert(!libsimple_strtotimespec(&t, s, &end));
+ errno = 0;
+ assert(t.tv_sec == TIME_MIN);
+ assert(t.tv_nsec == MS(500));
+ assert(!strcmp(end, ""));
+
+ sprintf(s, "%ji", (intmax_t)TIME_MAX);
+ assert(!libsimple_strtotimespec(&t, s, &end));
+ assert(t.tv_sec == TIME_MAX);
+ assert(t.tv_nsec == 0L);
+ assert(!strcmp(end, ""));
+
+ sprintf(s, "%ji.999999999", (intmax_t)TIME_MAX);
+ assert(!libsimple_strtotimespec(&t, s, &end));
+ assert(t.tv_sec == TIME_MAX);
+ assert(t.tv_nsec == 999999999L);
+ assert(!strcmp(end, ""));
+
+ sprintf(s, "%ji.5w", (intmax_t)TIME_MIN);
+ errno = 0;
+ assert(libsimple_strtotimespec(&t, s, &end) == -1 && errno == ERANGE);
+ errno = 0;
+ assert(t.tv_sec == TIME_MIN);
+ assert(t.tv_nsec == 0);
+ assert(!strcmp(end, "w"));
+
+ sprintf(s, "%ji0y", (intmax_t)TIME_MAX);
+ errno = 0;
+ assert(libsimple_strtotimespec(&t, s, &end) == -1 && errno == ERANGE);
+ errno = 0;
+ assert(t.tv_sec == TIME_MAX);
+ assert(t.tv_nsec == 999999999L);
+ assert(!strcmp(end, "y"));
+
+ sprintf(s, "%ji.9999999999999z", (intmax_t)TIME_MAX);
+ errno = 0;
+ assert(libsimple_strtotimespec(&t, s, &end) == -1 && errno == ERANGE);
+ errno = 0;
+ assert(t.tv_sec == TIME_MAX);
+ assert(t.tv_nsec == 999999999L);
+ assert(!strcmp(end, "z"));
+
+ sprintf(s, "%ji.9999999999999.999e", (intmax_t)TIME_MAX);
+ errno = 0;
+ assert(libsimple_strtotimespec(&t, s, &end) == -1 && errno == ERANGE);
+ errno = 0;
+ assert(t.tv_sec == TIME_MAX);
+ assert(t.tv_nsec == 999999999L);
+ assert(!strcmp(end, "e"));
+
+ sprintf(s, "%ji.9999999999999(999)r", (intmax_t)TIME_MAX);
+ errno = 0;
+ assert(libsimple_strtotimespec(&t, s, &end) == -1 && errno == ERANGE);
+ errno = 0;
+ assert(t.tv_sec == TIME_MAX);
+ assert(t.tv_nsec == 999999999L);
+ assert(!strcmp(end, "r"));
+
+ sprintf(s, "%ji0.(0)t", (intmax_t)TIME_MIN);
+ errno = 0;
+ assert(libsimple_strtotimespec(&t, s, &end) == -1 && errno == ERANGE);
+ errno = 0;
+ assert(t.tv_sec == TIME_MIN);
+ assert(t.tv_nsec == 0);
+ assert(!strcmp(end, "t"));
+
+ sprintf(s, "%ji0.()", (intmax_t)TIME_MIN);
+ INVAL(s);
+
+ sprintf(s, "%ji0.(s)", (intmax_t)TIME_MIN);
+ INVAL(s);
+
+ sprintf(s, "%ji0.0t", (intmax_t)TIME_MIN);
+ errno = 0;
+ assert(libsimple_strtotimespec(&t, s, &end) == -1 && errno == ERANGE);
+ errno = 0;
+ assert(t.tv_sec == TIME_MIN);
+ assert(t.tv_nsec == 0);
+ assert(!strcmp(end, "t"));
+
+ sprintf(s, "%ji0..", (intmax_t)TIME_MIN);
+ INVAL(s);
+
return 0;
}