/* See LICENSE file for copyright and license details. */ #include "common.h" #ifndef TEST int libsimple_strtotimespec(struct timespec *restrict ts, const char *restrict s, char **restrict end) { int neg = 0, bracket = 0; time_t sec = 0; long int nsec = 0; long int mul = 100000000L; const char *p; const char *end_s; if (end) { end_s = s; *end = REMOVE_CONST(end_s, char *); } while (isspace(*s)) s++; if (*s == '-') { neg = 1; s++; } else if (*s == '+') { s++; } if (!isdigit(*s) && *s != '.') { errno = EINVAL; return -1; } if (*s == '.') { if (s[1] == '.' || s[1] == '(') { if (!isdigit(s[2])) { errno = EINVAL; return -1; } } else if (!isdigit(s[1])) { errno = EINVAL; return -1; } } for (; isdigit(*s); s++) { if (LIBSIMPLE_SMUL_OVERFLOW_AN_BP(sec, 10, &sec, TIME_MIN, TIME_MAX)) goto overflow_integer; if (LIBSIMPLE_SSUB_OVERFLOW_B_POS(sec, (time_t)(*s & 15), &sec, TIME_MIN, TIME_MAX)) goto overflow_integer; } if (!neg) { if (TIME_MIN != -TIME_MAX && sec == TIME_MIN) goto overflow_integer; sec = -sec; } if (*s != '.') { ts->tv_sec = sec; ts->tv_nsec = 0; if (end) { end_s = s; *end = REMOVE_CONST(end_s, char *); } return 0; } for (s++; mul && isdigit(*s); s++) { nsec += (*s & 15) * mul; mul /= 10; } if (*s == '.' || *s == '(') { bracket = *s++ == '('; p = s; if (!isdigit(*s)) { errno = EINVAL; return -1; } for (p = s; isdigit(*p); p++); if (bracket) { if (*p == ')') { p++; } else { errno = EINVAL; return -1; } } if (end) *end = REMOVE_CONST(p, char *); p = s; while (mul) { for (s = p; mul && isdigit(*s); s++) { nsec += (*s & 15) * mul; mul /= 10; } } if (!isdigit(*s)) s = p; if (*s >= '5') { nsec += 1; if (nsec == 1000000000L) { if (sec == TIME_MAX) goto overflow_periodic; sec += 1; nsec = 0; } } } else { if (isdigit(*s)) { if (*s >= '5') { nsec += 1; if (nsec == 1000000000L) { if (sec == TIME_MAX) goto overflow_fraction; sec += 1; nsec = 0; } } while (isdigit(*s)) s++; } if (end) { end_s = s; *end = REMOVE_CONST(end_s, char *); } } if (neg && nsec) { if (sec == TIME_MIN) goto overflow; nsec = 1000000000L - nsec; 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_s = s; *end = REMOVE_CONST(end_s, char *); } if (neg) { ts->tv_sec = TIME_MIN; ts->tv_nsec = 0; } else { ts->tv_sec = TIME_MAX; ts->tv_nsec = 999999999L; } errno = ERANGE; return -1; } #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; } #endif