From f2378869e1a3b1cb44b5c7973e0a9acfb2559d0f Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 26 Aug 2018 12:49:12 +0200 Subject: Fixes, more test, and add minimise_number_string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- Makefile | 2 + doubletotimespec.c | 12 ++++- doubletotimeval.c | 12 ++++- libsimple.c | 112 ++++++++++++++++++++++++++++++++++++++-- libsimple.h | 13 +++-- minimise_number_string.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++ timespectostr.c | 4 +- timevaltostr.c | 4 +- 8 files changed, 276 insertions(+), 13 deletions(-) create mode 100644 minimise_number_string.c diff --git a/Makefile b/Makefile index 42f7f4d..50b8ca9 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,7 @@ OBJ =\ memrchr.o\ memrmem.o\ memstarts.o\ + minimise_number_string.o\ multimespec.o\ multimeval.o\ rawmemchr.o\ @@ -67,6 +68,7 @@ TESTS =\ memrchr.test\ memrmem.test\ memstarts.test\ + minimise_number_string.test\ rawmemchr.test\ rawmemrchr.test\ strcaseends.test\ diff --git a/doubletotimespec.c b/doubletotimespec.c index e74f04a..a71d662 100644 --- a/doubletotimespec.c +++ b/doubletotimespec.c @@ -3,7 +3,7 @@ void -libsimple_doubletotimespec(struct timespec *ts, double d) /* TODO test */ +libsimple_doubletotimespec(struct timespec *ts, double d) { double ns = (long long int)d; long int nsi; @@ -16,7 +16,17 @@ libsimple_doubletotimespec(struct timespec *ts, double d) /* TODO test */ nsi = 0; d += 1; } + } else if (2 * (ns - (double)nsi) <= -1) { + nsi -= 1; + if (nsi == -1000000000L) { + nsi = 0; + d -= 1; + } } ts->tv_sec = (time_t)d; ts->tv_nsec = nsi; + if (ts->tv_nsec < 0) { + ts->tv_sec -= 1; + ts->tv_nsec += 1000000000L; + } } diff --git a/doubletotimeval.c b/doubletotimeval.c index c86c771..5396897 100644 --- a/doubletotimeval.c +++ b/doubletotimeval.c @@ -3,7 +3,7 @@ void -libsimple_doubletotimeval(struct timeval *tv, double d) /* TODO test */ +libsimple_doubletotimeval(struct timeval *tv, double d) { double ns = (long long int)d; long int nsi; @@ -16,7 +16,17 @@ libsimple_doubletotimeval(struct timeval *tv, double d) /* TODO test */ nsi = 0; d += 1; } + } else if (2 * (ns - (double)nsi) <= -1) { + nsi -= 1; + if (nsi == -1000000L) { + nsi = 0; + d -= 1; + } } tv->tv_sec = (time_t)d; tv->tv_usec = nsi; + if (tv->tv_usec < 0) { + tv->tv_sec -= 1; + tv->tv_usec += 1000000L; + } } diff --git a/libsimple.c b/libsimple.c index fd7f779..15326d1 100644 --- a/libsimple.c +++ b/libsimple.c @@ -9,6 +9,90 @@ int libsimple_default_failure_exit = 1; #else #include "test.h" +static int +test_timespec(double d, time_t sec, long int nsec, double rd, const char *s, const char *ss) +{ + char buf[1000], *str; + struct timespec t; + double dt; + + libsimple_doubletotimespec(&t, d); + if (t.tv_sec != sec) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + if (t.tv_nsec != nsec) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + + dt = libsimple_timespectodouble(&t); + if (dt < rd - 0.0000000001) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + if (dt > rd + 0.0000000001) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + + str = libsimple_timespectostr(buf, &t); + if (str != buf) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + if (strcmp(str, s)) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + + str = libsimple_timespectostr(NULL, &t); + if (!str) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + if (strcmp(str, s)) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + + strcpy(buf, str); + free(str); + str = libsimple_minimise_number_string(buf); + if (str != buf) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + if (strcmp(str, ss)) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + + return 1; +} + +static int +test_timeval(double d, time_t sec, long int usec, double rd, const char *s, const char *ss) +{ + char buf[1000], *str; + struct timeval t; + double dt; + + libsimple_doubletotimeval(&t, d); + if (t.tv_sec != sec) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + if (t.tv_usec != usec) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + + dt = libsimple_timevaltodouble(&t); + if (dt < rd - 0.0000001) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + if (dt > rd + 0.0000001) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + + str = libsimple_timevaltostr(buf, &t); + if (str != buf) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + if (strcmp(str, s)) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + + str = libsimple_timevaltostr(NULL, &t); + if (!str) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + if (strcmp(str, s)) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + + strcpy(buf, str); + free(str); + str = libsimple_minimise_number_string(buf); + if (str != buf) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + if (strcmp(str, ss)) + return fprintf(stderr, "Failed at %s:%i\n", __FILE__, __LINE__ - 1), 0; + + return 1; +} + int main(void) { @@ -632,11 +716,9 @@ main(void) unsetenv("X"); assert(!getenv("X")); assert(!libsimple_getenv_ne("X")); - putenv("X=xyz"); assert(!strcmpnul(getenv("X"), "xyz")); assert(!strcmpnul(libsimple_getenv_ne("X"), "xyz")); - putenv("X="); assert(!strcmpnul(getenv("X"), "")); assert(!libsimple_getenv_ne("X")); @@ -644,15 +726,37 @@ main(void) unsetenv("X"); assert(!getenv("X")); assert(!strcmpnul(libsimple_getenv_e("X"), "")); - putenv("X=xyz"); assert(!strcmpnul(getenv("X"), "xyz")); assert(!strcmpnul(libsimple_getenv_e("X"), "xyz")); - putenv("X="); assert(!strcmpnul(getenv("X"), "")); assert(!strcmpnul(libsimple_getenv_e("X"), "")); + assert(test_timespec(10.3000200010, 10, 300020001L, 10.300020001, "+10.300020001", "10.300020001")); + assert(test_timespec(10.3000200014, 10, 300020001L, 10.300020001, "+10.300020001", "10.300020001")); + assert(test_timespec(10.3000200015, 10, 300020002L, 10.300020002, "+10.300020002", "10.300020002")); + assert(test_timespec(10.9999999999, 11, 0, 11, "+11.000000000", "11")); + assert(test_timespec(-10.3000200010, -11, 699979999L, -10.300020001, "-10.300020001", "-10.300020001")); + assert(test_timespec(-10.3000200014, -11, 699979999L, -10.300020001, "-10.300020001", "-10.300020001")); + assert(test_timespec(-10.3000200015, -11, 699979998L, -10.300020002, "-10.300020002", "-10.300020002")); + assert(test_timespec(-10.9999999999, -11, 0, -11, "-11.000000000", "-11")); + assert(test_timespec(10, 10, 0, 10, "+10.000000000", "10")); + assert(test_timespec(0, 0, 0, 0, "+0.000000000", "0")); + assert(test_timespec(-10, -10, 0, -10, "-10.000000000", "-10")); + + assert(test_timeval(10.3000201000, 10, 300020L, 10.300020, "+10.300020", "10.30002")); + assert(test_timeval(10.3000204000, 10, 300020L, 10.300020, "+10.300020", "10.30002")); + assert(test_timeval(10.3000205000, 10, 300021L, 10.300021, "+10.300021", "10.300021")); + assert(test_timeval(10.9999999000, 11, 0, 11, "+11.000000", "11")); + assert(test_timeval(-10.3000201000, -11, 699980L, -10.300020, "-10.300020", "-10.30002")); + assert(test_timeval(-10.3000204000, -11, 699980L, -10.300020, "-10.300020", "-10.30002")); + assert(test_timeval(-10.3000205000, -11, 699979L, -10.300021, "-10.300021", "-10.300021")); + assert(test_timeval(-10.9999999000, -11, 0, -11, "-11.000000", "-11")); + assert(test_timeval(10, 10, 0, 10, "+10.000000", "10")); + assert(test_timeval(0, 0, 0, 0, "+0.000000", "0")); + assert(test_timeval(-10, -10, 0, -10, "-10.000000", "-10")); + return 0; } diff --git a/libsimple.h b/libsimple.h index e1ecfdb..4619eef 100644 --- a/libsimple.h +++ b/libsimple.h @@ -1157,7 +1157,7 @@ libsimple_eputenvf(const char *__fmt, ...) /* TODO test */ { va_list __ap; va_start(__ap, __fmt); - envputenvf(1, __fmt, __ap); + envputenvf(libsimple_default_failure_exit, __fmt, __ap); va_end(__ap); } #ifndef eputenvf @@ -1410,7 +1410,7 @@ char *libsimple_timevaltostr(char *restrict, const struct timeval *restrict); _LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__))) static inline double -libsimple_timespectodouble(const struct timespec *__ts) /* TODO test */ +libsimple_timespectodouble(const struct timespec *__ts) { double __ret = (double)(__ts->tv_nsec); __ret /= (double)1000000000L; @@ -1424,7 +1424,7 @@ libsimple_timespectodouble(const struct timespec *__ts) /* TODO test */ _LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__))) static inline double -libsimple_timevaltodouble(const struct timeval *__tv) /* TODO test */ +libsimple_timevaltodouble(const struct timeval *__tv) { double __ret = (double)(__tv->tv_usec); __ret /= (double)1000000L; @@ -1450,6 +1450,13 @@ void libsimple_doubletotimeval(struct timeval *, double); #endif +_LIBSIMPLE_GCC_ONLY(__attribute__((__returns_nonnull__, __nonnull__))) +char *libsimple_minimise_number_string(char *); +#ifndef minimise_number_string +# define minimise_number_string libsimple_minimise_number_string +#endif + + #define LIBSIMPLE_UNLIST(LIST, I, NP) libsimple_unlist((LIST), (I), (NP), sizeof(*(LIST))) #ifndef UNLIST # define UNLIST(LIST, I, NP) LIBSIMPLE_UNLIST((LIST), (I), (NP)) diff --git a/minimise_number_string.c b/minimise_number_string.c new file mode 100644 index 0000000..5993564 --- /dev/null +++ b/minimise_number_string.c @@ -0,0 +1,130 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_minimise_number_string(char *s) +{ + char *p, *ret = s; + size_t n; + + if (*s == '+') + memmove(s, &s[1], strlen(s)); + + p = strchr(s, '.'); + if (p) { + p = strchr(p, '\0'); + while (p[-1] == '0') + *--p = '\0'; + if (p[-1] == '.') { + if (s[0] == '.') { + s[0] = '0'; + return ret; + } else if (s[0] == '-' && s[1] == '.') { + s[1] = '0'; + return ret; + } + *--p = '\0'; + } + } + + if (*s == '-') + s = &s[1]; + + for (p = s; *p == '0'; p++); + n = (size_t)(p - s); + if (!*p || *p == '.') + n -= !!n; + memmove(s, &s[n], strlen(&s[n]) + 1); + + return ret; +} + + +#else +#include "test.h" + +int +main(void) +{ + char buf[1000]; + + /* Some aspects are tested in libsimple.c */ + + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "00100.00000")), "100")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "00100.1")), "100.1")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "00100.000001")), "100.000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "00100.1000001")), "100.1000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "00100.0")), "100")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "00100.")), "100")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "100.00000")), "100")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "100.1")), "100.1")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "100.000001")), "100.000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "100.1000001")), "100.1000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "100.0")), "100")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "100.")), "100")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "0.00000")), "0")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "0.1")), "0.1")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "0.000001")), "0.000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "0.1000001")), "0.1000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "0.0")), "0")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "0.")), "0")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, ".00000")), "0")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, ".1")), ".1")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, ".000001")), ".000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, ".1000001")), ".1000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, ".0")), "0")); + + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+00100.00000")), "100")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+00100.1")), "100.1")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+00100.000001")), "100.000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+00100.1000001")), "100.1000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+00100.0")), "100")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+00100.")), "100")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+100.00000")), "100")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+100.1")), "100.1")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+100.000001")), "100.000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+100.1000001")), "100.1000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+100.0")), "100")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+100.")), "100")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+0.00000")), "0")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+0.1")), "0.1")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+0.000001")), "0.000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+0.1000001")), "0.1000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+0.0")), "0")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+0.")), "0")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+.00000")), "0")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+.1")), ".1")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+.000001")), ".000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+.1000001")), ".1000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "+.0")), "0")); + + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-00100.00000")), "-100")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-00100.1")), "-100.1")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-00100.000001")), "-100.000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-00100.1000001")), "-100.1000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-00100.0")), "-100")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-00100.")), "-100")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-100.00000")), "-100")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-100.1")), "-100.1")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-100.000001")), "-100.000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-100.1000001")), "-100.1000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-100.0")), "-100")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-100.")), "-100")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-0.00000")), "-0")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-0.1")), "-0.1")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-0.000001")), "-0.000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-0.1000001")), "-0.1000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-0.0")), "-0")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-0.")), "-0")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-.00000")), "-0")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-.1")), "-.1")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-.000001")), "-.000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-.1000001")), "-.1000001")); + assert(!strcmp(libsimple_minimise_number_string(strcpy(buf, "-.0")), "-0")); + + return 0; +} + +#endif diff --git a/timespectostr.c b/timespectostr.c index 3eca1f6..05bcaac 100644 --- a/timespectostr.c +++ b/timespectostr.c @@ -3,13 +3,13 @@ char * -libsimple_timespectostr(char *restrict buf, const struct timespec *restrict ts) /* TODO test */ +libsimple_timespectostr(char *restrict buf, const struct timespec *restrict ts) { time_t s = ts->tv_sec; long int ns = ts->tv_nsec; char sign[2] = "+"; - if (!s) { + if (!buf) { buf = malloc(INTSTRLEN(time_t) + sizeof("-.999999999")); if (!buf) return NULL; diff --git a/timevaltostr.c b/timevaltostr.c index 4dd6b9c..5daace5 100644 --- a/timevaltostr.c +++ b/timevaltostr.c @@ -3,13 +3,13 @@ char * -libsimple_timevaltostr(char *restrict buf, const struct timeval *restrict tv) /* TODO test */ +libsimple_timevaltostr(char *restrict buf, const struct timeval *restrict tv) { time_t s = tv->tv_sec; long int us = tv->tv_usec; char sign[2] = "+"; - if (!s) { + if (!buf) { buf = malloc(INTSTRLEN(time_t) + sizeof("-.999999")); if (!buf) return NULL; -- cgit v1.2.3-70-g09d2