From e8a7e1c358caec60751460d337f634ff6957ff9d Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Mon, 19 Nov 2018 21:39:11 +0100 Subject: Add a bunch of function and macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- Makefile | 78 ++++-- README | 66 +++++ difftimespec.c | 60 ++--- difftimeval.c | 40 ++- libsimple.h | 2 + libsimple/mem.h | 571 +++++++++++++++++++++++++++++++++++++++++- libsimple/overflow.h | 406 ++++++++++++++++++++++++++++++ libsimple/str.h | 287 ++++++++++++++++++++- libsimple/strn.h | 314 ++++++++++++++++++++++- man3/libsimple_difftimespec.3 | 9 + man3/libsimple_multimespec.3 | 7 + man3/libsimple_sumtimespec.3 | 9 + memcasechr_inv.c | 31 +++ memcasescan_inv.c | 31 +++ memchr_inv.c | 30 +++ memcmove.c | 42 ++++ memelem.c | 5 +- memelem_inv.c | 68 +++++ memelemscan.c | 7 +- memelemscan_inv.c | 60 +++++ memptolower.c | 60 +++++ memptoupper.c | 60 +++++ memrcasechr_inv.c | 26 ++ memrchr_inv.c | 25 ++ memrelem.c | 5 +- memrelem_inv.c | 76 ++++++ memreplaceelem.c | 83 ++++++ memscan_inv.c | 30 +++ multimespec.c | 6 +- rawmemcasechr_inv.c | 27 ++ rawmemchr_inv.c | 27 ++ rawmemelem.c | 68 +++++ rawmemelem_inv.c | 58 +++++ rawmemrcasechr_inv.c | 25 ++ rawmemrchr_inv.c | 24 ++ rawmemrelem.c | 74 ++++++ rawmemrelem_inv.c | 65 +++++ stpntolower.c | 115 +++++++++ stpntoupper.c | 115 +++++++++ stptolower.c | 61 +++++ stptoupper.c | 61 +++++ strcasechr_inv.c | 32 +++ strcasechrnul_inv.c | 32 +++ strchr_inv.c | 29 +++ strchrnul_inv.c | 29 +++ strcmove.c | 39 +++ strncasechr_inv.c | 55 ++++ strncasechrnul_inv.c | 55 ++++ strnchr_inv.c | 54 ++++ strnchrnul_inv.c | 54 ++++ strncmove.c | 42 ++++ strrcasechr_inv.c | 32 +++ strrchr_inv.c | 26 ++ strrncasechr_inv.c | 31 +++ strrnchr_inv.c | 30 +++ strtotimespec.c | 6 +- sumtimespec.c | 60 ++--- sumtimeval.c | 40 ++- timespec2timeval.c | 7 +- vmemalloc.c | 14 +- 60 files changed, 3715 insertions(+), 166 deletions(-) create mode 100644 libsimple/overflow.h create mode 100644 memcasechr_inv.c create mode 100644 memcasescan_inv.c create mode 100644 memchr_inv.c create mode 100644 memcmove.c create mode 100644 memelem_inv.c create mode 100644 memelemscan_inv.c create mode 100644 memptolower.c create mode 100644 memptoupper.c create mode 100644 memrcasechr_inv.c create mode 100644 memrchr_inv.c create mode 100644 memrelem_inv.c create mode 100644 memreplaceelem.c create mode 100644 memscan_inv.c create mode 100644 rawmemcasechr_inv.c create mode 100644 rawmemchr_inv.c create mode 100644 rawmemelem.c create mode 100644 rawmemelem_inv.c create mode 100644 rawmemrcasechr_inv.c create mode 100644 rawmemrchr_inv.c create mode 100644 rawmemrelem.c create mode 100644 rawmemrelem_inv.c create mode 100644 stpntolower.c create mode 100644 stpntoupper.c create mode 100644 stptolower.c create mode 100644 stptoupper.c create mode 100644 strcasechr_inv.c create mode 100644 strcasechrnul_inv.c create mode 100644 strchr_inv.c create mode 100644 strchrnul_inv.c create mode 100644 strcmove.c create mode 100644 strncasechr_inv.c create mode 100644 strncasechrnul_inv.c create mode 100644 strnchr_inv.c create mode 100644 strnchrnul_inv.c create mode 100644 strncmove.c create mode 100644 strrcasechr_inv.c create mode 100644 strrchr_inv.c create mode 100644 strrncasechr_inv.c create mode 100644 strrnchr_inv.c diff --git a/Makefile b/Makefile index 5944817..73360c1 100644 --- a/Makefile +++ b/Makefile @@ -4,32 +4,33 @@ CONFIGFILE = config.mk include $(CONFIGFILE) SUBHDR =\ - libsimple/definitions.h\ - libsimple/memalloc.h\ - libsimple/strdup.h\ - libsimple/strndup.h\ - libsimple/memdup.h\ + libsimple/aligned_alloc.h\ + libsimple/aligned_allocz.h\ libsimple/aligned_memdup.h\ - libsimple/mallocz.h\ - libsimple/malloc.h\ libsimple/calloc.h\ - libsimple/realloc.h\ - libsimple/memalignz.h\ + libsimple/definitions.h\ + libsimple/env.h\ + libsimple/malloc.h\ + libsimple/mallocz.h\ + libsimple/mem.h\ libsimple/memalign.h\ - libsimple/vallocz.h\ - libsimple/valloc.h\ - libsimple/pvallocz.h\ - libsimple/pvalloc.h\ - libsimple/aligned_allocz.h\ - libsimple/aligned_alloc.h\ - libsimple/posix_memalignz.h\ + libsimple/memalignz.h\ + libsimple/memalloc.h\ + libsimple/memdup.h\ + libsimple/overflow.h\ libsimple/posix_memalign.h\ - libsimple/env.h\ - libsimple/time.h\ + libsimple/posix_memalignz.h\ libsimple/printf.h\ + libsimple/pvalloc.h\ + libsimple/pvallocz.h\ + libsimple/realloc.h\ libsimple/str.h\ + libsimple/strdup.h\ libsimple/strn.h\ - libsimple/mem.h + libsimple/strndup.h\ + libsimple/time.h\ + libsimple/valloc.h\ + libsimple/vallocz.h HDR =\ $(SUBHDR)\ @@ -59,62 +60,101 @@ OBJ =\ envputenvf.o\ envreallocn.o\ memcasechr.o\ + memcasechr_inv.o\ memcasecmp.o\ memcaseends.o\ memcaseeqlen.o\ memcasemem.o\ memcasescan.o\ + memcasescan_inv.o\ memcasestarts.o\ + memchr_inv.o\ + memcmove.o\ memdup.o\ memelem.o\ + memelem_inv.o\ memelemscan.o\ + memelemscan_inv.o\ memends.o\ memeqlen.o\ memisutf8.o\ memmem.o\ mempsetelem.o\ + memptolower.o\ + memptoupper.o\ memrcasechr.o\ + memrcasechr_inv.o\ memrcaseeqlen.o\ memrcasemem.o\ memrchr.o\ + memrchr_inv.o\ memrelem.o\ + memrelem_inv.o\ + memreplaceelem.o\ memreqlen.o\ memrmem.o\ memscan.o\ + memscan_inv.o\ memstarts.o\ minimise_number_string.o\ multimespec.o\ multimeval.o\ rawmemcasechr.o\ + rawmemcasechr_inv.o\ rawmemchr.o\ + rawmemchr_inv.o\ + rawmemelem.o\ + rawmemelem_inv.o\ rawmemrcasechr.o\ + rawmemrcasechr_inv.o\ rawmemrchr.o\ + rawmemrchr_inv.o\ + rawmemrelem.o\ + rawmemrelem_inv.o\ + stpntolower.o\ + stpntoupper.o\ + stptolower.o\ + stptoupper.o\ strcasechr.o\ + strcasechr_inv.o\ strcasechrnul.o\ + strcasechrnul_inv.o\ strcaseends.o\ strcaseeqlen.o\ strcasestr.o\ + strchr_inv.o\ strchrnul.o\ + strchrnul_inv.o\ + strcmove.o\ strends.o\ streqlen.o\ strncasechr.o\ + strncasechr_inv.o\ strncasechrnul.o\ + strncasechrnul_inv.o\ strncaseends.o\ strncaseeqlen.o\ strncasestarts.o\ strncasestr.o\ strnchr.o\ + strnchr_inv.o\ strnchrnul.o\ + strnchrnul_inv.o\ + strncmove.o\ strnend.o\ strnends.o\ strneqlen.o\ strnstarts.o\ strnstr.o\ strrcasechr.o\ + strrcasechr_inv.o\ strrcasestr.o\ + strrchr_inv.o\ strrncasechr.o\ + strrncasechr_inv.o\ strrncasestr.o\ strrnchr.o\ + strrnchr_inv.o\ strrnstr.o\ strrstr.o\ strstarts.o\ diff --git a/README b/README index 19ba924..0effbc4 100644 --- a/README +++ b/README @@ -10,3 +10,69 @@ have unnamespaced. Programs using this library should define `char *argv0` and set it to the 0:th command line argument. + +libsimple include a number of functions complementing those in +and , the naming scheme of these functions is: + + = str for NUL-terminated byte strings + = strn for byte strings that may not be NUL-terminated + = mem for byte arrays + = wcs for NUL-terminated wide-character strings + = wcsn for wide-character strings that may not be NUL-terminated + = wmem for wide-character arrays + + = str if is str, wsc, strn, or wscn + = mem if is mem or wmem + + = chrnul if is str, wsc, strn, or wscn + = scan if is mem or wmem + + [case] = if case-sensitive + = case if case-insensitive, the name may also end with + _l if there is a locale parameter + + [_inv] = for normal search + = _inv for search of anything else (skipping) + + [r] = for left-to-right search/comparison + = r for right-to-left search/comparison + + [p] = return beginning of destination + = p return end of destination + + [raw] = sought data may not exist + = raw sought data does exist (only = mem, wmem) + + [r] = strrn if is strn + = wcsrn if is wcsn + = r otherwise + + [p] = stp if is str + = stpn if is strn + = wcp if is wcs + = wcpn if is wcsn + = p otherwise + + [raw][r][case]chr[_inv] find character + [case][_inv] find character or end + [r][case] find substring + [case]cmp alphabetically compare, without NULL support + [case]cmpnul alphabetically compare, with NULL support + [case]ends verify end + [case]starts verify beginning + [case]eq ![case]cmp + [case]eqnul ![case]cmpnul + [r][case]eqlen check length of commonality + end find end of string (not = mem, wmem) + [p]cpy copy data (to external array) + [p]move move data (within array or to external array) + [p]set fill data + [p]toupper like [p]move but convert text to upper case + [p]tolower like [p]move but convert text to lower case + [raw]ccpy like pcpy, but stop after a character is found + [raw]cmove like pmove, but stop after a character is found + replace replace all instance of a character, end is returned + mem[p]setelem fill data with elements of custom length + [raw]mem[r]elem[_inv] find element with custom length + memelemscan[_inv] find element with custom length or end + memreplaceelem replace all instance of an element of custom length, end is returned diff --git a/difftimespec.c b/difftimespec.c index 07f46c9..86d3441 100644 --- a/difftimespec.c +++ b/difftimespec.c @@ -6,48 +6,36 @@ int libsimple_difftimespec(struct timespec *diff, const struct timespec *minuend, const struct timespec *subtrahend) { - long int ns = minuend->tv_nsec - subtrahend->tv_nsec; time_t s; - int ret = 0; - - s = minuend->tv_sec - subtrahend->tv_sec; - if ((minuend->tv_sec <= 0) != (subtrahend->tv_sec <= 0)) { - if (minuend->tv_sec < 0 && minuend->tv_sec < TIME_MIN + subtrahend->tv_sec) { - s = TIME_MIN; - ns = 0; - errno = ERANGE; - ret = -1; - } else if (minuend->tv_sec >= 0 && minuend->tv_sec > TIME_MAX + subtrahend->tv_sec) { - s = TIME_MAX; - ns = 999999999L; - errno = ERANGE; - ret = -1; - } + + if (LIBSIMPLE_SSUB_OVERFLOW(minuend->tv_sec, subtrahend->tv_sec, &s, TIME_MIN, TIME_MAX)) { + if (subtrahend->tv_sec < 0) + goto too_large; + else + goto too_small; } - if (ns < 0) { - if (s == TIME_MIN) { - ns = 0L; - errno = ERANGE; - ret = -1; - } else { - s -= 1; - ns += 1000000000L; - } - } else if (ns >= 1000000000L) { - if (s == TIME_MAX) { - ns = 999999999L; - errno = ERANGE; - ret = -1; - } else { - s += 1; - ns -= 1000000000L; - } + diff->tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec; + if (diff->tv_nsec < 0) { + if (LIBSIMPLE_SDECR_OVERFLOW(&s, TIME_MIN)) + goto too_small; + diff->tv_nsec += 1000000000L; } diff->tv_sec = s; - diff->tv_nsec = ns; - return ret; + return 0; + +too_large: + diff->tv_sec = TIME_MAX; + diff->tv_nsec = 999999999L; + errno = ERANGE; + return -1; + +too_small: + diff->tv_sec = TIME_MIN; + diff->tv_nsec = 0; + errno = ERANGE; + return -1; } diff --git a/difftimeval.c b/difftimeval.c index 0cd8cda..2f633a2 100644 --- a/difftimeval.c +++ b/difftimeval.c @@ -6,16 +6,36 @@ int libsimple_difftimeval(struct timeval *diff, const struct timeval *minuend, const struct timeval *subtrahend) { - struct timespec a, b, d; - int r; - libsimple_timeval2timespec(&a, minuend); - libsimple_timeval2timespec(&b, subtrahend); - r = libsimple_difftimespec(&d, &a, &b); - if (r && errno != ERANGE) - return r; - if (libsimple_timespec2timeval(diff, &d) && r) - errno = ERANGE; - return r; + time_t s; + + if (LIBSIMPLE_SSUB_OVERFLOW(minuend->tv_sec, subtrahend->tv_sec, &s, TIME_MIN, TIME_MAX)) { + if (subtrahend->tv_sec < 0) + goto too_large; + else + goto too_small; + } + + diff->tv_usec = minuend->tv_usec - subtrahend->tv_usec; + if (diff->tv_usec < 0) { + if (LIBSIMPLE_SDECR_OVERFLOW(&s, TIME_MIN)) + goto too_small; + diff->tv_usec += 1000000L; + } + + diff->tv_sec = s; + return 0; + +too_large: + diff->tv_sec = TIME_MAX; + diff->tv_usec = 999999L; + errno = ERANGE; + return -1; + +too_small: + diff->tv_sec = TIME_MIN; + diff->tv_usec = 0; + errno = ERANGE; + return -1; } diff --git a/libsimple.h b/libsimple.h index 4663eb4..6fd226e 100644 --- a/libsimple.h +++ b/libsimple.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -73,6 +74,7 @@ #include "libsimple/mem.h" #include "libsimple/str.h" #include "libsimple/strn.h" +#include "libsimple/overflow.h" /** diff --git a/libsimple/mem.h b/libsimple/mem.h index 67834bc..4c98b29 100644 --- a/libsimple/mem.h +++ b/libsimple/mem.h @@ -60,9 +60,9 @@ void *libsimple_memcasescan(const void *, int, size_t); * the comparison is case-sensitive * * This function is optimised for instances where it is already - * known that there is at least one occurence; if is no occurence - * of the specified byte value in the specified byte array, this - * behaviour is undefined + * known that there is at least one occurence; if there is no + * occurence of the specified byte value in the specified byte + * array, its behaviour is undefined * * @param s The array of bytes to search * @param c The byte value to search for @@ -81,9 +81,9 @@ void *libsimple_rawmemchr(const void *, int); * the comparison is case-insensitive * * This function is optimised for instances where it is already - * known that there is at least one occurence; if is no occurence - * of the specified byte value in the specified byte array, this - * behaviour is undefined + * known that there is at least one occurence; if there is no + * occurence of the specified byte value in the specified byte + * array, its behaviour is undefined * * @param s The array of bytes to search * @param c The byte value to search for @@ -138,9 +138,9 @@ void *libsimple_memrcasechr(const void *, int, size_t); * the comparison is case-sensitive * * This function is optimised for instances where it is already - * known that there is at least one occurence; if is no occurence - * of the specified byte value in the specified byte array, this - * behaviour is undefined + * known that there is at least one occurence; if there is no + * occurence of the specified byte value in the specified byte + * array, its behaviour is undefined * * @param s The array of bytes to search * @param c The byte value to search for @@ -160,9 +160,9 @@ void *libsimple_rawmemrchr(const void *, int, size_t); * the comparison is case-insensitive * * This function is optimised for instances where it is already - * known that there is at least one occurence; if is no occurence - * of the specified byte value in the specified byte array, this - * behaviour is undefined + * known that there is at least one occurence; if there is no + * occurence of the specified byte value in the specified byte + * array, its behaviour is undefined * * @param s The array of bytes to search * @param c The byte value to search for @@ -177,6 +177,200 @@ void *libsimple_rawmemrcasechr(const void *, int, size_t); #endif +/** + * Finds the first occurence of a byte value in an array of bytes, + * other than specified byte value, the comparison is case-sensitive + * + * @param s The array of bytes to search + * @param c The byte value to search for + * @param n The number of bytes in the byte array + * @return `s` with a minimal offset such that `*r != c`, + * where `r` is the returned pointer, `NULL` if + * no such offset exists within [s, &s[n]) + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__))) +void *libsimple_memchr_inv(const void *, int, size_t); +#ifndef memchr_inv +# define memchr_inv libsimple_memchr_inv +#endif + + +/** + * Finds the first occurence of a byte value in an array of bytes, + * other than specified byte value, the comparison is case-sensitive + * + * @param s The array of bytes to search + * @param c The byte value to search for + * @param n The number of bytes in the byte array + * @return `s` with a minimal offset such that `*r != c`, + * where `r` is the returned pointer, `&s[n]` if + * no such offset exists within [s, &s[n]) + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __returns_nonnull__, __warn_unused_result__))) +void *libsimple_memscan_inv(const void *, int, size_t); +#ifndef memscan_inv +# define memscan_inv libsimple_memscan_inv +#endif + + +/** + * Finds the first occurence of a byte value in an array of bytes, + * other than specified byte value, the comparison is case-insensitive + * + * @param s The array of bytes to search + * @param c The byte value to search for + * @param n The number of bytes in the byte array + * @return `s` with a minimal offset such that `tolower(*r) != tolower(c)`, + * where `r` is the returned pointer, `NULL` if + * no such offset exists within [s, &s[n]) + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__))) +void *libsimple_memcasechr_inv(const void *, int, size_t); +#ifndef memcasechr_inv +# define memcasechr_inv libsimple_memcasechr_inv +#endif + + +/** + * Finds the first occurence of a byte value in an array of bytes, + * other than specified byte value, the comparison is case-insensitive + * + * @param s The array of bytes to search + * @param c The byte value to search for + * @param n The number of bytes in the byte array + * @return `s` with a minimal offset such that `tolower(*r) != tolower(c)`, + * where `r` is the returned pointer, `&s[n]` if + * no such offset exists within [s, &s[n]) + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __returns_nonnull__, __warn_unused_result__))) +void *libsimple_memcasescan_inv(const void *, int, size_t); +#ifndef memcasescan_inv +# define memcasescan_inv libsimple_memcasescan_inv +#endif + + +/** + * Finds the first occurence of a byte value in an array of bytes, + * other than specified byte value, the comparison is case-sensitive + * + * This function is optimised for instances where it is already + * known that there is at least one occurence; if there is no + * occurence of any byte value than the specified byte value in + * the specified byte array, its behaviour is undefined + * + * @param s The array of bytes to search + * @param c The byte value to search for + * @return `s` with a miminal offset such that `*r != c`, + * where `r` is the returned pointer + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __returns_nonnull__, __warn_unused_result__))) +void *libsimple_rawmemchr_inv(const void *, int); +#ifndef rawmemchr_inv +# define rawmemchr_inv libsimple_rawmemchr_inv +#endif + + +/** + * Finds the first occurence of a byte value in an array of bytes, + * other than specified byte value, the comparison is case-insensitive + * + * This function is optimised for instances where it is already + * known that there is at least one occurence; if there is no + * occurence of any byte value than the specified byte value in + * the specified byte array, its behaviour is undefined + * + * @param s The array of bytes to search + * @param c The byte value to search for + * @return `s` with a miminal offset such that `tolower(*r) != tolower(c)`, + * where `r` is the returned pointer + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __returns_nonnull__, __warn_unused_result__))) +void *libsimple_rawmemcasechr_inv(const void *, int); +#ifndef rawmemcasechr_inv +# define rawmemcasechr_inv libsimple_rawmemcasechr_inv +#endif + + +/** + * Finds the last occurence of a byte value in an array of bytes, + * other than specified byte value, the comparison is case-sensitive + * + * @param s The array of bytes to search + * @param c The byte value to search for + * @param n The number of bytes in the byte array + * @return `s` with a maximal offset such that `*r != c`, + * where `r` is the returned pointer `NULL` if no + * such offset exists within [s, &s[n]) + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__))) +void *libsimple_memrchr_inv(const void *, int, size_t); +#ifndef memrchr_inv +# define memrchr_inv libsimple_memrchr_inv +#endif + + +/** + * Finds the last occurence of a byte value in an array of bytes, + * other than specified byte value, the comparison is case-insensitive + * + * @param s The array of bytes to search + * @param c The byte value to search for + * @param n The number of bytes in the byte array + * @return `s` with a maximal offset such that `tolower(*r) != tolower(c)`, + * where `r` is the returned pointer `NULL` if no + * such offset exists within [s, &s[n]) + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__))) +void *libsimple_memrcasechr_inv(const void *, int, size_t); +#ifndef memrcasechr_inv +# define memrcasechr_inv libsimple_memrcasechr_inv +#endif + + +/** + * Finds the last occurence of a byte value in an array of bytes, + * other than specified byte value, the comparison is case-sensitive + * + * This function is optimised for instances where it is already + * known that there is at least one occurence; if there is no + * occurence of any byte value than the specified byte value in + * the specified byte array, its behaviour is undefined + * + * @param s The array of bytes to search + * @param c The byte value to search for + * @param n The number of bytes in the byte array + * @return `s` with a maximal offset such that `*r != c`, + * where `r` is the returned pointer + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __returns_nonnull__, __warn_unused_result__))) +void *libsimple_rawmemrchr_inv(const void *, int, size_t); +#ifndef rawmemrchr_inv +# define rawmemrchr_inv libsimple_rawmemrchr_inv +#endif + + +/** + * Finds the last occurence of a byte value in an array of bytes, + * other than specified byte value, the comparison is case-insensitive + * + * This function is optimised for instances where it is already + * known that there is at least one occurence; if there is no + * occurence of any byte value than the specified byte value in + * the specified byte array, its behaviour is undefined + * + * @param s The array of bytes to search + * @param c The byte value to search for + * @param n The number of bytes in the byte array + * @return `s` with a maximal offset such that `tolower(*r) != tolower(c)`, + * where `r` is the returned pointer + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __returns_nonnull__, __warn_unused_result__))) +void *libsimple_rawmemrcasechr_inv(const void *, int, size_t); +#ifndef rawmemrcasechr_inv +# define rawmemrcasechr_inv libsimple_rawmemrcasechr_inv +#endif + + /** * Finds the first substring in an array of bytes, the comparison is case-sensitive * @@ -268,6 +462,28 @@ void *libsimple_memelem(const void *, size_t, const void *, size_t); #endif +/** + * Finds the first element in an array, the comparison is case-sensitive + * + * This function is optimised for instances where it is already + * known that there is at least one occurence; if there is no + * occurence of the specified value in the specified array, its + * behaviour is undefined + * + * @param haystack The array of bytes to search + * @param needle The substring to search for + * @param nneedle The length of `needle` + * @return `haystack` with a minimal offset such that, + * `!memcmp(r, needle, nneedle)` where `r` is the + * returned pointer and such that `(r - haystack) % nneedle == 0` + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __returns_nonnull__, __warn_unused_result__))) +void *libsimple_rawmemelem(const void *, const void *, size_t); /* TODO man */ +#ifndef rawmemelem +# define rawmemelem libsimple_rawmemelem +#endif + + /** * Finds the first element in an array, the comparison is case-sensitive * @@ -307,6 +523,137 @@ void *libsimple_memrelem(const void *, size_t, const void *, size_t); #endif +/** + * Finds the last element in an array, the comparison is case-sensitive + * + * This function is optimised for instances where it is already + * known that there is at least one occurence; if there is no + * occurence of the specified value in the specified array, its + * behaviour is undefined + * + * @param haystack The array of bytes to search + * @param nhaystack The length of `haystack`, divided by `needle` + * @param needle The substring to search for + * @param nneedle The length of `needle` + * @return `haystack` with a maximal offset such that, + * `!memcmp(r, needle, nneedle)` where `r` is the + * returned pointer and such that `(r - haystack) % nneedle == 0` + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __returns_nonnull__, __warn_unused_result__))) +void *libsimple_rawmemrelem(const void *, size_t, const void *, size_t); /* TODO man */ +#ifndef rawmemrelem +# define rawmemrelem libsimple_rawmemrelem +#endif + + +/** + * Finds the first element in an array that is different from + * the specified element, the comparison is case-sensitive + * + * @param haystack The array of bytes to search + * @param nhaystack The length of `haystack`, divided by `needle` + * @param needle The substring to skip over + * @param nneedle The length of `needle` + * @return `haystack` with a minimal offset such that, + * `memcmp(r, needle, nneedle)` where `r` is the + * returned pointer and such that `(r - haystack) % nneedle == 0`, + * `NULL` if no such offset exists + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__))) +void *libsimple_memelem_inv(const void *, size_t, const void *, size_t); +#ifndef memelem_inv +# define memelem_inv libsimple_memelem_inv +#endif + + +/** + * Finds the first element in an array that is different from + * the specified element, the comparison is case-sensitive + * + * This function is optimised for instances where it is already + * known that there is at least one occurence; if there is no + * occurence of any value other than the specified value in the + * specified array, its behaviour is undefined + * + * @param haystack The array of bytes to search + * @param needle The substring to skip over + * @param nneedle The length of `needle` + * @return `haystack` with a minimal offset such that, + * `memcmp(r, needle, nneedle)` where `r` is the + * returned pointer and such that `(r - haystack) % nneedle == 0` + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __returns_nonnull__, __warn_unused_result__))) +void *libsimple_rawmemelem_inv(const void *, const void *, size_t); +#ifndef rawmemelem_inv +# define rawmemelem_inv libsimple_rawmemelem_inv +#endif + + +/** + * Finds the first element in an array that is different from + * the specified element, the comparison is case-sensitive + * + * @param haystack The array of bytes to search + * @param nhaystack The length of `haystack`, divided by `needle` + * @param needle The substring to skip over + * @param nneedle The length of `needle` + * @return `haystack` with a minimal offset such that, + * `memcmp(r, needle, nneedle)` where `r` is the + * returned pointer and such that `(r - haystack) % nneedle == 0`, + * `(void *)&((char *)haystack)[nhaystack * nneedle]` + * if no such offset exists + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__))) +void *libsimple_memelemscan_inv(const void *, size_t, const void *, size_t); +#ifndef memelemscan_inv +# define memelemscan_inv libsimple_memelemscan_inv +#endif + + +/** + * Finds the last element in an array that is different from + * the specified element, the comparison is case-sensitive + * + * @param haystack The array of bytes to search + * @param nhaystack The length of `haystack`, divided by `needle` + * @param needle The substring to skip over + * @param nneedle The length of `needle` + * @return `haystack` with a maximal offset such that, + * `memcmp(r, needle, nneedle)` where `r` is the + * returned pointer and such that `(r - haystack) % nneedle == 0`, + * `NULL` if no such offset exists + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__))) +void *libsimple_memrelem_inv(const void *, size_t, const void *, size_t); +#ifndef memrelem_inv +# define memrelem_inv libsimple_memrelem_inv +#endif + + +/** + * Finds the last element in an array that is different from + * the specified element, the comparison is case-sensitive + * + * This function is optimised for instances where it is already + * known that there is at least one occurence; if there is no + * occurence of any value other than the specified value in the + * specified array, its behaviour is undefined + * + * @param haystack The array of bytes to search + * @param nhaystack The length of `haystack`, divided by `needle` + * @param needle The substring to skip over + * @param nneedle The length of `needle` + * @return `haystack` with a maximal offset such that, + * `memcmp(r, needle, nneedle)` where `r` is the + * returned pointer and such that `(r - haystack) % nneedle == 0` + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __returns_nonnull__, __warn_unused_result__))) +void *libsimple_rawmemrelem_inv(const void *, size_t, const void *, size_t); +#ifndef rawmemrelem_inv +# define rawmemrelem_inv libsimple_rawmemrelem_inv +#endif + + /** * Checks the beginning of an array of bytes, the comparison is case-sensitive * @@ -496,6 +843,206 @@ static inline void *libsimple_memsetelem(void *__buf, const void *__item, size_t #endif +/** + * Copy an array of bytes, but stop after a specific byte + * + * This function is optimised for instances where it is already + * known that there is at least one occurence; if there is no + * occurence of the specified byte value in the specified byte + * array, its behaviour is undefined + * + * @param d The location the byt array shall be copied to + * @param s The byte array to copy + * @param c The byte that stops the copying + * @param `&rawmemchr(d, c)[1]` (after copying) + */ +static inline void * +libsimple_rawmemccpy(void *restrict __d_, const void *restrict __s_, int __c_) /* TODO test, man */ +{ + char __c = (char)__c_, *restrict __d = __d_; + const char *restrict __s = __s_; + for (; (*__d++ = *__s) != __c; __s++); + return __d; +} +#ifndef rawmemccpy +# define rawmemccpy libsimple_rawmemccpy +#endif + + +/** + * Move a string, but stop after a specific character + * + * @param d The location the byt array shall be copied to + * @param s The byte array to copy + * @param c The byte that stops the copying + * @param n The length of `s` + * @param `&rawmemchr(d, c)[1]` (after copying) if `c` can + * be found within the first `n` bytes of `s` (before + * copying), `NULL` otherwise + */ +void *libsimple_memcmove(void *__d_, const void *__s_, int __c_, size_t __n); +#ifndef memcmove +# define memcmove libsimple_memcmove +#endif + + +/** + * Move a string, but stop after a specific character + * + * This function is optimised for instances where it is already + * known that there is at least one occurence; if there is no + * occurence of the specified byte value in the specified byte + * array, its behaviour is undefined + * + * @param d The location the byt array shall be copied to + * @param s The byte array to copy + * @param c The byte that stops the copying + * @param `&rawmemchr(d, c)[1]` (after copying) + */ +static inline void * +libsimple_rawmemcmove(void *__d_, const void *__s_, int __c_) /* TODO test, man */ +{ + char *__d = __d_, *__p, __c = (char)__c_; + const char *__s = __s_; + size_t __n; + if (__d < __s) { + for (; (*__d++ = *__s) != __c; __s++); + return __d; + } else { + for (__p = *(char **)(void *)&__s; *__p++ != __c;); + __n = (size_t)(__p - __s); + __p = &__d[__n]; + while (__n) { + __n--; + __d[__n] = __s[__n]; + } + return __p; + } +} +#ifndef rawmemcmove +# define rawmemcmove libsimple_rawmemcmove +#endif + + +/** + * Replace all instances of a byte in an array of byte with another byte + * + * @param s The byte array + * @param old The value of the bytes to replace + * @param new The value to replace the bytes with + * @param n The length of `s` + * @return `(void *)&((char *)s)[n]` + */ +static inline void * +libsimple_memreplace(void *__s_, int __old_, int __new_, size_t __n) /* TODO test, man */ +{ + char __old = (char)__old_, __new = (char)__new_, *__s = __s_; + char *__ret = &__s[__n]; + while (__n) + if (__s[--__n] == __old) + __s[__n] = __new; + return __ret; +} +#ifndef memreplace +# define memreplace libsimple_memreplace +#endif + + +/** + * Replace all instances of an element in an array of + * elements with another element + * + * @param s The array + * @param old The value of the elements to replace + * @param new The value to replace the elements with + * @param n The length of `s`, measured in elements + * @param width The size of each element + * @return `(void *)&((char *)s)[n * width]` + */ +void *libsimple_memreplaceelem(void *restrict __s_, const void *__old_, const void *__new_, size_t __n, size_t __width); +#ifndef memreplaceelem +# define memreplaceelem libsimple_memreplaceelem +#endif + + +/** + * Copy an array of bytes but convert to lower case + * + * `d` and `s` may overlap; the function has an + * optimisation for when `d == s` + * + * `d` will be `s` but in lower case + * + * @param d The location the array shall be copied to + * @param s The byte array to copy + * @param n The number of bytes to copy or covert + * @return `&d[n]` + */ +void *libsimple_memptolower(void *__d, const void *__s, size_t __n); +#ifndef memptolower +# define memptolower libsimple_memptolower +#endif + + +/** + * Copy an array of bytes but convert to upper case + * + * `d` and `s` may overlap; the function has an + * optimisation for when `d == s` + * + * `d` will be `s` but in upper case + * + * @param d The location the array shall be copied to + * @param s The byte array to copy + * @param n The number of bytes to copy or covert + * @return `&d[n]` + */ +void *libsimple_memptoupper(void *__d, const void *__s, size_t __n); +#ifndef memptoupper +# define memptoupper libsimple_memptoupper +#endif + + +/** + * Copy an array of bytes but convert to lower case + * + * `d` and `s` may overlap; the function has an + * optimisation for when `d == s` + * + * `d` will be `s` but in lower case + * + * @param d The location the array shall be copied to + * @param s The byte array to copy + * @param n The number of bytes to copy or covert + * @return `d` + */ +static inline void *libsimple_memtolower(void *__d, const void *__s, size_t __n) /* TODO man */ +{ libsimple_memptolower(__d, __s, __n); return __d; } +#ifndef memtolower +# define memtolower libsimple_memtolower +#endif + + +/** + * Copy an array of bytes but convert to upper case + * + * `d` and `s` may overlap; the function has an + * optimisation for when `d == s` + * + * `d` will be `s` but in upper case + * + * @param d The location the array shall be copied to + * @param s The byte array to copy + * @param n The number of bytes to copy or covert + * @return `d` + */ +static inline void *libsimple_memtoupper(void *__d, const void *__s, size_t __n) /* TODO man */ +{ libsimple_memptoupper(__d, __s, __n); return __d; } +#ifndef memtoupper +# define memtoupper libsimple_memtoupper +#endif + + /** * Compares the beginning of two memory segments, the comparison is case-sensitive * diff --git a/libsimple/overflow.h b/libsimple/overflow.h new file mode 100644 index 0000000..66ea6fa --- /dev/null +++ b/libsimple/overflow.h @@ -0,0 +1,406 @@ +/* See LICENSE file for copyright and license details. */ + +/* TODO test, doc, man */ + +#if defined(__GNUC__) + +# define LIBSIMPLE_UADD_WOULD_OVERFLOW(A, B, MAX) (__builtin_add_overflow_p(A, B, &(A))) +# define LIBSIMPLE_USUB_WOULD_OVERFLOW(A, B) (__builtin_sub_overflow_p(A, B, &(A))) +# define LIBSIMPLE_UMUL_WOULD_OVERFLOW(A, B, MAX) (__builtin_mul_overflow_p(A, B, &(A))) +# define LIBSIMPLE_UMUL_WOULD_OVERFLOW_NONZERO(A, B, MAX) (__builtin_mul_overflow_p(A, B, &(A))) +# define LIBSIMPLE_UINCR_WOULD_OVERFLOW(A, MAX) (__builtin_add_overflow_p(A, 1, &(A))) +# define LIBSIMPLE_UDECR_WOULD_OVERFLOW(A) (__builtin_sub_overflow_p(A, 1, &(A))) + +# define LIBSIMPLE_UADD_OVERFLOW(A, B, RES, MAX) (__builtin_add_overflow(A, B, RES)) +# define LIBSIMPLE_USUB_OVERFLOW(A, B, RES) (__builtin_sub_overflow(A, B, RES)) +# define LIBSIMPLE_UMUL_OVERFLOW(A, B, RES, MAX) (__builtin_mul_overflow(A, B, RES)) +# define LIBSIMPLE_UMUL_OVERFLOW_NONZERO(A, B, RES, MAX) (__builtin_mul_overflow(A, B, RES)) +# define LIBSIMPLE_UINCR_OVERFLOW(AP, MAX) (__builtin_add_overflow(*(AP), 1, AP)) +# define LIBSIMPLE_UDECR_OVERFLOW(AP) (__builtin_sub_overflow(*(AP), 1, AP)) + +# define LIBSIMPLE_SADD_WOULD_OVERFLOW(A, B, MIN, MAX) (__builtin_add_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SADD_WOULD_OVERFLOW_A_NEG(A, B, MIN, MAX) (__builtin_add_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SADD_WOULD_OVERFLOW_B_NEG(A, B, MIN, MAX) (__builtin_add_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SADD_WOULD_OVERFLOW_NONNEG(A, B, MIN, MAX) (__builtin_add_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SSUB_WOULD_OVERFLOW(A, B, MIN, MAX) (__builtin_sub_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SSUB_WOULD_OVERFLOW_B_NEG(A, B, MIN, MAX) (__builtin_sub_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SSUB_WOULD_OVERFLOW_B_POS(A, B, MIN, MAX) (__builtin_sub_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW(A, B, MIN, MAX) (__builtin_mul_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_NONZERO(A, B, MIN, MAX) (__builtin_mul_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN(A, B, MIN, MAX) (__builtin_mul_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN_BNZ(A, B, MIN, MAX) (__builtin_mul_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN_BN(A, B, MIN, MAX) (__builtin_mul_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN_BP(A, B, MIN, MAX) (__builtin_mul_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP(A, B, MIN, MAX) (__builtin_mul_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP_BNZ(A, B, MIN, MAX) (__builtin_mul_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP_BN(A, B, MIN, MAX) (__builtin_mul_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP_BP(A, B, MIN, MAX) (__builtin_mul_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_BN(A, B, MIN, MAX) (__builtin_mul_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_ANZ_BN(A, B, MIN, MAX) (__builtin_mul_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_BP(A, B, MIN, MAX) (__builtin_mul_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_ANZ_BP(A, B, MIN, MAX) (__builtin_mul_overflow_p(A, B, &(A))) +# define LIBSIMPLE_SDIV_WOULD_OVERFLOW(A, B, MIN, MAX) ((A) == (MAX) && (B) == -1 && -(MAX) == (MIN)) +# define LIBSIMPLE_SINCR_WOULD_OVERFLOW(A, MAX) (__builtin_add_overflow_p(A, 1, &(A))) +# define LIBSIMPLE_SDECR_WOULD_OVERFLOW(A, MIN) (__builtin_sub_overflow_p(A, 1, &(A))) + +# define LIBSIMPLE_SADD_OVERFLOW(A, B, RES, MIN, MAX) (__builtin_add_overflow(A, B, RES)) +# define LIBSIMPLE_SADD_OVERFLOW_A_NEG(A, B, RES, MIN, MAX) (__builtin_add_overflow(A, B, RES)) +# define LIBSIMPLE_SADD_OVERFLOW_B_NEG(A, B, RES, MIN, MAX) (__builtin_add_overflow(A, B, RES)) +# define LIBSIMPLE_SADD_OVERFLOW_NONNEG(A, B, RES, MIN, MAX) (__builtin_add_overflow(A, B, RES)) +# define LIBSIMPLE_SSUB_OVERFLOW(A, B, RES, MIN, MAX) (__builtin_sub_overflow(A, B, RES)) +# define LIBSIMPLE_SSUB_OVERFLOW_B_NEG(A, B, RES, MIN, MAX) (__builtin_sub_overflow(A, B, RES)) +# define LIBSIMPLE_SSUB_OVERFLOW_B_POS(A, B, RES, MIN, MAX) (__builtin_sub_overflow(A, B, RES)) +# define LIBSIMPLE_SMUL_OVERFLOW(A, B, RES, MIN, MAX) (__builtin_mul_overflow(A, B, RES)) +# define LIBSIMPLE_SMUL_OVERFLOW_NONZERO(A, B, RES, MIN, MAX) (__builtin_mul_overflow(A, B, RES)) +# define LIBSIMPLE_SMUL_OVERFLOW_AN(A, B, RES, MIN, MAX) (__builtin_mul_overflow(A, B, RES)) +# define LIBSIMPLE_SMUL_OVERFLOW_AN_BNZ(A, B, RES, MIN, MAX) (__builtin_mul_overflow(A, B, RES)) +# define LIBSIMPLE_SMUL_OVERFLOW_AN_BN(A, B, RES, MIN, MAX) (__builtin_mul_overflow(A, B, RES)) +# define LIBSIMPLE_SMUL_OVERFLOW_AN_BP(A, B, RES, MIN, MAX) (__builtin_mul_overflow(A, B, RES)) +# define LIBSIMPLE_SMUL_OVERFLOW_AP(A, B, RES, MIN, MAX) (__builtin_mul_overflow(A, B, RES)) +# define LIBSIMPLE_SMUL_OVERFLOW_AP_BNZ(A, B, RES, MIN, MAX) (__builtin_mul_overflow(A, B, RES)) +# define LIBSIMPLE_SMUL_OVERFLOW_AP_BN(A, B, RES, MIN, MAX) (__builtin_mul_overflow(A, B, RES)) +# define LIBSIMPLE_SMUL_OVERFLOW_AP_BP(A, B, RES, MIN, MAX) (__builtin_mul_overflow(A, B, RES)) +# define LIBSIMPLE_SMUL_OVERFLOW_BN(A, B, RES, MIN, MAX) (__builtin_mul_overflow(A, B, RES)) +# define LIBSIMPLE_SMUL_OVERFLOW_ANZ_BN(A, B, RES, MIN, MAX) (__builtin_mul_overflow(A, B, RES)) +# define LIBSIMPLE_SMUL_OVERFLOW_BP(A, B, RES, MIN, MAX) (__builtin_mul_overflow(A, B, RES)) +# define LIBSIMPLE_SMUL_OVERFLOW_ANZ_BP(A, B, RES, MIN, MAX) (__builtin_mul_overflow(A, B, RES)) +# define LIBSIMPLE_SDIV_OVERFLOW(A, B, RES, MIN, MAX) (LIBSIMPLE_SDIV_WOULD_OVERFLOW(A, B, MIN, MAX) ? 1 : (*(RES) = (A) / (B), 0)) +# define LIBSIMPLE_SINCR_OVERFLOW(AP, MAX) (__builtin_add_overflow(*(AP), 1, AP)) +# define LIBSIMPLE_SDECR_OVERFLOW(AP, MIN) (__builtin_sub_overflow(*(AP), 1, AP)) + +# define LIBSIMPLE_INCR_WOULD_OVERFLOW(A, MAX) (__builtin_add_overflow_p(A, 1, &(A))) +# define LIBSIMPLE_DECR_WOULD_OVERFLOW(A, MIN) (__builtin_sub_overflow_p(A, 1, &(A))) + +# define LIBSIMPLE_INCR_OVERFLOW(AP, MAX) (__builtin_add_overflow(*(AP), 1, AP)) +# define LIBSIMPLE_DECR_OVERFLOW(AP, MIN) (__builtin_sub_overflow(*(AP), 1, AP)) + +#else + +# define LIBSIMPLE_UADD_WOULD_OVERFLOW(A, B, MAX) ((A) > (MAX) - (B)) +# define LIBSIMPLE_USUB_WOULD_OVERFLOW(A, B) ((A) < (B)) +# define LIBSIMPLE_UMUL_WOULD_OVERFLOW(A, B, MAX) ((A) && (B) && (A) > (MAX) / (B)) +# define LIBSIMPLE_UMUL_WOULD_OVERFLOW_NONZERO(A, B, MAX) ((A) > (MAX) / (B)) +# define LIBSIMPLE_UINCR_WOULD_OVERFLOW(A, MAX) ((A) == (MAX)) +# define LIBSIMPLE_UDECR_WOULD_OVERFLOW(A) (!(A)) + +# define LIBSIMPLE_UADD_OVERFLOW(A, B, RES, MAX) (LIBSIMPLE_UADD_WOULD_OVERFLOW(A, B, MAX) ? 1 : (*(RES) = (A) + (B), 0)) +# define LIBSIMPLE_USUB_OVERFLOW(A, B, RES) (LIBSIMPLE_USUB_WOULD_OVERFLOW(A, B) ? 1 : (*(RES) = (A) - (B), 0)) +# define LIBSIMPLE_UMUL_OVERFLOW(A, B, RES, MAX) (LIBSIMPLE_UMUL_WOULD_OVERFLOW(A, B, MAX) ? 1 : (*(RES) = (A) * (B), 0)) +# define LIBSIMPLE_UMUL_OVERFLOW_NONZERO(A, B, RES, MAX) (LIBSIMPLE_UMUL_WOULD_OVERFLOW_NONZERO(A, B, MAX) ? 1 : (*(RES) = (A) * (B), 0)) +# define LIBSIMPLE_UINCR_OVERFLOW(AP, MAX) ((*(AP))++ == (MAX)) +# define LIBSIMPLE_UDECR_OVERFLOW(AP) (!(*(AP))--) + +# define LIBSIMPLE_SADD_WOULD_OVERFLOW(A, B, MIN, MAX) ((B) <= 0 ? (A) < (MIN) - (B) : (A) <= 0 ? (B) < (MIN) - (A) : (A) > (MAX) - (B)) +# define LIBSIMPLE_SADD_WOULD_OVERFLOW_A_NEG(A, B, MIN, MAX) ((B) < (MIN) - (A)) +# define LIBSIMPLE_SADD_WOULD_OVERFLOW_B_NEG(A, B, MIN, MAX) ((A) < (MIN) - (B)) +# define LIBSIMPLE_SADD_WOULD_OVERFLOW_NONNEG(A, B, MIN, MAX) ((A) > (MAX) - (B)) +# define LIBSIMPLE_SSUB_WOULD_OVERFLOW(A, B, MIN, MAX) ((B) <= 0 ? (A) > (MAX) + (B) : (A) < (MIN) + (B)) +# define LIBSIMPLE_SSUB_WOULD_OVERFLOW_B_NEG(A, B, MIN, MAX) ((A) > (MAX) + (B)) +# define LIBSIMPLE_SSUB_WOULD_OVERFLOW_B_POS(A, B, MIN, MAX) ((A) < (MIN) + (B)) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW(A, B, MIN, MAX) ((A) && (B) && LIBSIMPLE_SMUL_WOULD_OVERFLOW_NONZERO(A, B, MIN, MAX)) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_NONZERO(A, B, MIN, MAX) ((A) < 0 ? LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN_BNZ(A, B, MIN, MAX) : LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP_BNZ(A, B, MIN, MAX)) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN(A, B, MIN, MAX) ((B) && LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN_BNZ(A, B, MIN, MAX)) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN_BNZ(A, B, MIN, MAX) ((B) < 0 ? LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN_BN(A, B, MIN, MAX) : LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN_BP(A, B, MIN, MAX)) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN_BN(A, B, MIN, MAX) ((A) < -(MAX) / (B)) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN_BP(A, B, MIN, MAX) ((A) < (MIN) / (B)) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP(A, B, MIN, MAX) ((B) && LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP_BNZ(A, B, MIN, MAX)) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP_BNZ(A, B, MIN, MAX) ((B) < 0 ? LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP_BN(A, B, MIN, MAX) : LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP_BP(A, B, MIN, MAX)) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP_BN(A, B, MIN, MAX) ((B) < (MIN) / (A)) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP_BP(A, B, MIN, MAX) ((A) > (MAX) / (B)) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_BN(A, B, MIN, MAX) ((A) && LIBSIMPLE_SMUL_WOULD_OVERFLOW_ANZ_BN(A, B, MIN, MAX)) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_ANZ_BN(A, B, MIN, MAX) ((A) < 0 ? LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN_BN(A, B, MIN, MAX) : LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP_BN(A, B, MIN, MAX)) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_BP(A, B, MIN, MAX) ((A) && LIBSIMPLE_SMUL_WOULD_OVERFLOW_ANZ_BP(A, B, MIN, MAX)) +# define LIBSIMPLE_SMUL_WOULD_OVERFLOW_ANZ_BP(A, B, MIN, MAX) ((A) < 0 ? LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN_BP(A, B, MIN, MAX) : LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP_BP(A, B, MIN, MAX)) +# define LIBSIMPLE_SDIV_WOULD_OVERFLOW(A, B, MIN, MAX) ((A) == (MAX) && (B) == -1 && -(MAX) == (MIN)) +# define LIBSIMPLE_SINCR_WOULD_OVERFLOW(A, MAX) ((A) == (MAX)) +# define LIBSIMPLE_SDECR_WOULD_OVERFLOW(A, MIN) ((A) == (MIN)) + +# define LIBSIMPLE_SADD_OVERFLOW(A, B, RES, MIN, MAX) (LIBSIMPLE_SADD_WOULD_OVERFLOW(A, B, MIN, MAX) ? 1 : (*(RES) = (A) + (B), 0)) +# define LIBSIMPLE_SADD_OVERFLOW_A_NEG(A, B, RES, MIN, MAX) (LIBSIMPLE_SADD_WOULD_OVERFLOW_A_NEG(A, B, MIN, MAX) ? 1 : (*(RES) = (A) - (B), 0)) +# define LIBSIMPLE_SADD_OVERFLOW_B_NEG(A, B, RES, MIN, MAX) (LIBSIMPLE_SADD_WOULD_OVERFLOW_B_NEG(A, B, MIN, MAX) ? 1 : (*(RES) = (A) - (B), 0)) +# define LIBSIMPLE_SADD_OVERFLOW_NONNEG(A, B, RES, MIN, MAX) (LIBSIMPLE_SADD_WOULD_OVERFLOW_NONNEG(A, B, MIN, MAX) ? 1 : (*(RES) = (A) - (B), 0)) +# define LIBSIMPLE_SSUB_OVERFLOW(A, B, RES, MIN, MAX) (LIBSIMPLE_SSUB_WOULD_OVERFLOW(A, B, MIN, MAX) ? 1 : (*(RES) = (A) - (B), 0)) +# define LIBSIMPLE_SSUB_OVERFLOW_B_NEG(A, B, RES, MIN, MAX) (LIBSIMPLE_SSUB_WOULD_OVERFLOW_B_NEG(A, B, MIN, MAX) ? 1 : (*(RES) = (A) - (B), 0)) +# define LIBSIMPLE_SSUB_OVERFLOW_B_POS(A, B, RES, MIN, MAX) (LIBSIMPLE_SSUB_WOULD_OVERFLOW_B_POS(A, B, MIN, MAX) ? 1 : (*(RES) = (A) - (B), 0)) +# define LIBSIMPLE_SMUL_OVERFLOW(A, B, RES, MIN, MAX) (LIBSIMPLE_SMUL_WOULD_OVERFLOW(A, B, MIN, MAX) ? 1 : (*(RES) = (A) * (B), 0)) +# define LIBSIMPLE_SMUL_OVERFLOW_NONZERO(A, B, RES, MIN, MAX) (LIBSIMPLE_SMUL_WOULD_OVERFLOW_NONZERO(A, B, MIN, MAX) ? 1 : (*(RES) = (A) * (B), 0)) +# define LIBSIMPLE_SMUL_OVERFLOW_AN(A, B, RES, MIN, MAX) (LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN(A, B, MIN, MAX) ? 1 : (*(RES) = (A) * (B), 0)) +# define LIBSIMPLE_SMUL_OVERFLOW_AN_BNZ(A, B, RES, MIN, MAX) (LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN_BNZ(A, B, MIN, MAX) ? 1 : (*(RES) = (A) * (B), 0)) +# define LIBSIMPLE_SMUL_OVERFLOW_AN_BN(A, B, RES, MIN, MAX) (LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN_BN(A, B, MIN, MAX) ? 1 : (*(RES) = (A) * (B), 0)) +# define LIBSIMPLE_SMUL_OVERFLOW_AN_BP(A, B, RES, MIN, MAX) (LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN_BP(A, B, MIN, MAX) ? 1 : (*(RES) = (A) * (B), 0)) +# define LIBSIMPLE_SMUL_OVERFLOW_AP(A, B, RES, MIN, MAX) (LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP(A, B, MIN, MAX) ? 1 : (*(RES) = (A) * (B), 0)) +# define LIBSIMPLE_SMUL_OVERFLOW_AP_BNZ(A, B, RES, MIN, MAX) (LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP_BNZ(A, B, MIN, MAX) ? 1 : (*(RES) = (A) * (B), 0)) +# define LIBSIMPLE_SMUL_OVERFLOW_AP_BN(A, B, RES, MIN, MAX) (LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP_BN(A, B, MIN, MAX) ? 1 : (*(RES) = (A) * (B), 0)) +# define LIBSIMPLE_SMUL_OVERFLOW_AP_BP(A, B, RES, MIN, MAX) (LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP_BP(A, B, MIN, MAX) ? 1 : (*(RES) = (A) * (B), 0)) +# define LIBSIMPLE_SMUL_OVERFLOW_BN(A, B, RES, MIN, MAX) (LIBSIMPLE_SMUL_WOULD_OVERFLOW_BN(A, B, MIN, MAX) ? 1 : (*(RES) = (A) * (B), 0)) +# define LIBSIMPLE_SMUL_OVERFLOW_ANZ_BN(A, B, RES, MIN, MAX) (LIBSIMPLE_SMUL_WOULD_OVERFLOW_ANZ_BN(A, B, MIN, MAX) ? 1 : (*(RES) = (A) * (B), 0)) +# define LIBSIMPLE_SMUL_OVERFLOW_BP(A, B, RES, MIN, MAX) (LIBSIMPLE_SMUL_WOULD_OVERFLOW_BP(A, B, MIN, MAX) ? 1 : (*(RES) = (A) * (B), 0)) +# define LIBSIMPLE_SMUL_OVERFLOW_ANZ_BP(A, B, RES, MIN, MAX) (LIBSIMPLE_SMUL_WOULD_OVERFLOW_ANZ_BP(A, B, MIN, MAX) ? 1 : (*(RES) = (A) * (B), 0)) +# define LIBSIMPLE_SDIV_OVERFLOW(A, B, RES, MIN, MAX) (LIBSIMPLE_SDIV_WOULD_OVERFLOW(A, B, MIN, MAX) ? 1 : (*(RES) = (A) / (B), 0)) +# define LIBSIMPLE_SINCR_OVERFLOW(AP, MAX) ((*(AP))++ == (MAX)) +# define LIBSIMPLE_SDECR_OVERFLOW(AP, MIN) ((*(AP))-- == (MIN)) + +# define LIBSIMPLE_INCR_WOULD_OVERFLOW(A, MAX) ((A) == (MAX)) +# define LIBSIMPLE_DECR_WOULD_OVERFLOW(A, MIN) ((A) == (MIN)) + +# define LIBSIMPLE_INCR_OVERFLOW(AP, MAX) ((*(AP))++ == (MAX)) +# define LIBSIMPLE_DECR_OVERFLOW(AP, MIN) ((*(AP))-- == (MIN)) + +#endif + + +#ifndef UADD_WOULD_OVERFLOW +# define UADD_WOULD_OVERFLOW(A, B, MAX) LIBSIMPLE_UADD_WOULD_OVERFLOW(A, B, MAX) +#endif + +#ifndef USUB_WOULD_OVERFLOW +# define USUB_WOULD_OVERFLOW(A, B) LIBSIMPLE_USUB_WOULD_OVERFLOW(A, B) +#endif + +#ifndef UMUL_WOULD_OVERFLOW +# define UMUL_WOULD_OVERFLOW(A, B, MAX) LIBSIMPLE_UMUL_WOULD_OVERFLOW(A, B, MAX) +#endif + +#ifndef UMUL_WOULD_OVERFLOW_NONZERO +# define UMUL_WOULD_OVERFLOW_NONZERO(A, B, MAX) LIBSIMPLE_UMUL_WOULD_OVERFLOW_NONZERO(A, B, MAX) +#endif + +#ifndef UINCR_WOULD_OVERFLOW +# define UINCR_WOULD_OVERFLOW(A, MAX) LIBSIMPLE_UINCR_WOULD_OVERFLOW(A, MAX) +#endif + +#ifndef UDECR_WOULD_OVERFLOW +# define UDECR_WOULD_OVERFLOW(A) LIBSIMPLE_UDECR_WOULD_OVERFLOW(A) +#endif + +#ifndef UADD_OVERFLOW +# define UADD_OVERFLOW(A, B, RES, MAX) LIBSIMPLE_UADD_OVERFLOW(A, B, RES, MAX) +#endif + +#ifndef USUB_OVERFLOW +# define USUB_OVERFLOW(A, B, RES) LIBSIMPLE_USUB_OVERFLOW(A, B, RES) +#endif + +#ifndef UMUL_OVERFLOW +# define UMUL_OVERFLOW(A, B, RES, MAX) LIBSIMPLE_UMUL_OVERFLOW(A, B, RES, MAX) +#endif + +#ifndef UMUL_OVERFLOW_NONZERO +# define UMUL_OVERFLOW_NONZERO(A, B, RES, MAX) LIBSIMPLE_UMUL_OVERFLOW_NONZERO(A, B, RES, MAX) +#endif + +#ifndef UINCR_OVERFLOW +# define UINCR_OVERFLOW(AP, MAX) LIBSIMPLE_UINCR_OVERFLOW(AP, MAX) +#endif + +#ifndef UDECR_OVERFLOW +# define UDECR_OVERFLOW(AP) LIBSIMPLE_UDECR_OVERFLOW(AP) +#endif + +#ifndef SADD_WOULD_OVERFLOW +# define SADD_WOULD_OVERFLOW(A, B, MIN, MAX) LIBSIMPLE_SADD_WOULD_OVERFLOW(A, B, MIN, MAX) +#endif + +#ifndef SADD_WOULD_OVERFLOW_A_NEG +# define SADD_WOULD_OVERFLOW_A_NEG(A, B, MIN, MAX) LIBSIMPLE_SADD_WOULD_OVERFLOW_A_NEG(A, B, MIN, MAX) +#endif + +#ifndef SADD_WOULD_OVERFLOW_B_NEG +# define SADD_WOULD_OVERFLOW_B_NEG(A, B, MIN, MAX) LIBSIMPLE_SADD_WOULD_OVERFLOW_B_NEG(A, B, MIN, MAX) +#endif + +#ifndef SADD_WOULD_OVERFLOW_NONNEG +# define SADD_WOULD_OVERFLOW_NONNEG(A, B, MIN, MAX) LIBSIMPLE_SADD_WOULD_OVERFLOW_NONNEG(A, B, MIN, MAX) +#endif + +#ifndef SSUB_WOULD_OVERFLOW +# define SSUB_WOULD_OVERFLOW(A, B, MIN, MAX) LIBSIMPLE_SSUB_WOULD_OVERFLOW(A, B, MIN, MAX) +#endif + +#ifndef SSUB_WOULD_OVERFLOW_B_NEG +# define SSUB_WOULD_OVERFLOW_B_NEG(A, B, MIN, MAX) LIBSIMPLE_SSUB_WOULD_OVERFLOW_B_NEG(A, B, MIN, MAX) +#endif + +#ifndef SSUB_WOULD_OVERFLOW_B_POS +# define SSUB_WOULD_OVERFLOW_B_POS(A, B, MIN, MAX) LIBSIMPLE_SSUB_WOULD_OVERFLOW_B_POS(A, B, MIN, MAX) +#endif + +#ifndef SMUL_WOULD_OVERFLOW +# define SMUL_WOULD_OVERFLOW(A, B, MIN, MAX) LIBSIMPLE_SMUL_WOULD_OVERFLOW(A, B, MIN, MAX) +#endif + +#ifndef SMUL_WOULD_OVERFLOW_NONZERO +# define SMUL_WOULD_OVERFLOW_NONZERO(A, B, MIN, MAX) LIBSIMPLE_SMUL_WOULD_OVERFLOW_NONZERO(A, B, MIN, MAX) +#endif + +#ifndef SMUL_WOULD_OVERFLOW_AN +# define SMUL_WOULD_OVERFLOW_AN(A, B, MIN, MAX) LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN(A, B, MIN, MAX) +#endif + +#ifndef SMUL_WOULD_OVERFLOW_AN_BNZ +# define SMUL_WOULD_OVERFLOW_AN_BNZ(A, B, MIN, MAX) LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN_BNZ(A, B, MIN, MAX) +#endif + +#ifndef SMUL_WOULD_OVERFLOW_AN_BN +# define SMUL_WOULD_OVERFLOW_AN_BN(A, B, MIN, MAX) LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN_BN(A, B, MIN, MAX) +#endif + +#ifndef SMUL_WOULD_OVERFLOW_AN_BP +# define SMUL_WOULD_OVERFLOW_AN_BP(A, B, MIN, MAX) LIBSIMPLE_SMUL_WOULD_OVERFLOW_AN_BP(A, B, MIN, MAX) +#endif + +#ifndef SMUL_WOULD_OVERFLOW_AP +# define SMUL_WOULD_OVERFLOW_AP(A, B, MIN, MAX) LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP(A, B, MIN, MAX) +#endif + +#ifndef SMUL_WOULD_OVERFLOW_AP_BNZ +# define SMUL_WOULD_OVERFLOW_AP_BNZ(A, B, MIN, MAX) LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP_BNZ(A, B, MIN, MAX) +#endif + +#ifndef SMUL_WOULD_OVERFLOW_AP_BN +# define SMUL_WOULD_OVERFLOW_AP_BN(A, B, MIN, MAX) LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP_BN(A, B, MIN, MAX) +#endif + +#ifndef SMUL_WOULD_OVERFLOW_AP_BP +# define SMUL_WOULD_OVERFLOW_AP_BP(A, B, MIN, MAX) LIBSIMPLE_SMUL_WOULD_OVERFLOW_AP_BP(A, B, MIN, MAX) +#endif + +#ifndef SMUL_WOULD_OVERFLOW_BN +# define SMUL_WOULD_OVERFLOW_BN(A, B, MIN, MAX) LIBSIMPLE_SMUL_WOULD_OVERFLOW_BN(A, B, MIN, MAX) +#endif + +#ifndef SMUL_WOULD_OVERFLOW_ANZ_BN +# define SMUL_WOULD_OVERFLOW_ANZ_BN(A, B, MIN, MAX) LIBSIMPLE_SMUL_WOULD_OVERFLOW_ANZ_BN(A, B, MIN, MAX) +#endif + +#ifndef SMUL_WOULD_OVERFLOW_BP +# define SMUL_WOULD_OVERFLOW_BP(A, B, MIN, MAX) LIBSIMPLE_SMUL_WOULD_OVERFLOW_BP(A, B, MIN, MAX) +#endif + +#ifndef SMUL_WOULD_OVERFLOW_ANZ_BP +# define SMUL_WOULD_OVERFLOW_ANZ_BP(A, B, MIN, MAX) LIBSIMPLE_SMUL_WOULD_OVERFLOW_ANZ_BP(A, B, MIN, MAX) +#endif + +#ifndef SDIV_WOULD_OVERFLOW +# define SDIV_WOULD_OVERFLOW(A, B, MIN, MAX) LIBSIMPLE_SDIV_WOULD_OVERFLOW(A, B, MIN, MAX) +#endif + +#ifndef SINCR_WOULD_OVERFLOW +# define SINCR_WOULD_OVERFLOW(A, MAX) LIBSIMPLE_SINCR_WOULD_OVERFLOW(A, MAX) +#endif + +#ifndef SDECR_WOULD_OVERFLOW +# define SDECR_WOULD_OVERFLOW(A, MIN) LIBSIMPLE_SDECR_WOULD_OVERFLOW(A, MIN) +#endif + +#ifndef SADD_OVERFLOW +# define SADD_OVERFLOW(A, B, RES, MIN, MAX) LIBSIMPLE_SADD_OVERFLOW(A, B, RES, MIN, MAX) +#endif + +#ifndef SADD_OVERFLOW_A_NEG +# define SADD_OVERFLOW_A_NEG(A, B, RES, MIN, MAX) LIBSIMPLE_SADD_OVERFLOW_A_NEG(A, B, RES, MIN, MAX) +#endif + +#ifndef SADD_OVERFLOW_B_NEG +# define SADD_OVERFLOW_B_NEG(A, B, RES, MIN, MAX) LIBSIMPLE_SADD_OVERFLOW_B_NEG(A, B, RES, MIN, MAX) +#endif + +#ifndef SADD_OVERFLOW_NONNEG +# define SADD_OVERFLOW_NONNEG(A, B, RES, MIN, MAX) LIBSIMPLE_SADD_OVERFLOW_NONNEG(A, B, RES, MIN, MAX) +#endif + +#ifndef SSUB_OVERFLOW +# define SSUB_OVERFLOW(A, B, RES, MIN, MAX) LIBSIMPLE_SSUB_OVERFLOW(A, B, RES, MIN, MAX) +#endif + +#ifndef SSUB_OVERFLOW_B_NEG +# define SSUB_OVERFLOW_B_NEG(A, B, RES, MIN, MAX) LIBSIMPLE_SSUB_OVERFLOW_B_NEG(A, B, RES, MIN, MAX) +#endif + +#ifndef SSUB_OVERFLOW_B_POS +# define SSUB_OVERFLOW_B_POS(A, B, RES, MIN, MAX) LIBSIMPLE_SSUB_OVERFLOW_B_POS(A, B, RES, MIN, MAX) +#endif + +#ifndef SMUL_OVERFLOW +# define SMUL_OVERFLOW(A, B, RES, MIN, MAX) LIBSIMPLE_SMUL_OVERFLOW(A, B, RES, MIN, MAX) +#endif + +#ifndef SMUL_OVERFLOW_NONZERO +# define SMUL_OVERFLOW_NONZERO(A, B, RES, MIN, MAX) LIBSIMPLE_SMUL_OVERFLOW_NONZERO(A, B, RES, MIN, MAX) +#endif + +#ifndef SMUL_OVERFLOW_AN +# define SMUL_OVERFLOW_AN(A, B, RES, MIN, MAX) LIBSIMPLE_SMUL_OVERFLOW_AN(A, B, RES, MIN, MAX) +#endif + +#ifndef SMUL_OVERFLOW_AN_BNZ +# define SMUL_OVERFLOW_AN_BNZ(A, B, RES, MIN, MAX) LIBSIMPLE_SMUL_OVERFLOW_AN_BNZ(A, B, RES, MIN, MAX) +#endif + +#ifndef SMUL_OVERFLOW_AN_BN +# define SMUL_OVERFLOW_AN_BN(A, B, RES, MIN, MAX) LIBSIMPLE_SMUL_OVERFLOW_AN_BN(A, B, RES, MIN, MAX) +#endif + +#ifndef SMUL_OVERFLOW_AN_BP +# define SMUL_OVERFLOW_AN_BP(A, B, RES, MIN, MAX) LIBSIMPLE_SMUL_OVERFLOW_AN_BP(A, B, RES, MIN, MAX) +#endif + +#ifndef SMUL_OVERFLOW_AP +# define SMUL_OVERFLOW_AP(A, B, RES, MIN, MAX) LIBSIMPLE_SMUL_OVERFLOW_AP(A, B, RES, MIN, MAX) +#endif + +#ifndef SMUL_OVERFLOW_AP_BNZ +# define SMUL_OVERFLOW_AP_BNZ(A, B, RES, MIN, MAX) LIBSIMPLE_SMUL_OVERFLOW_AP_BNZ(A, B, RES, MIN, MAX) +#endif + +#ifndef SMUL_OVERFLOW_AP_BN +# define SMUL_OVERFLOW_AP_BN(A, B, RES, MIN, MAX) LIBSIMPLE_SMUL_OVERFLOW_AP_BN(A, B, RES, MIN, MAX) +#endif + +#ifndef SMUL_OVERFLOW_AP_BP +# define SMUL_OVERFLOW_AP_BP(A, B, RES, MIN, MAX) LIBSIMPLE_SMUL_OVERFLOW_AP_BP(A, B, RES, MIN, MAX) +#endif + +#ifndef SMUL_OVERFLOW_BN +# define SMUL_OVERFLOW_BN(A, B, RES, MIN, MAX) LIBSIMPLE_SMUL_OVERFLOW_BN(A, B, RES, MIN, MAX) +#endif + +#ifndef SMUL_OVERFLOW_ANZ_BN +# define SMUL_OVERFLOW_ANZ_BN(A, B, RES, MIN, MAX) LIBSIMPLE_SMUL_OVERFLOW_ANZ_BN(A, B, RES, MIN, MAX) +#endif + +#ifndef SMUL_OVERFLOW_BP +# define SMUL_OVERFLOW_BP(A, B, RES, MIN, MAX) LIBSIMPLE_SMUL_OVERFLOW_BP(A, B, RES, MIN, MAX) +#endif + +#ifndef SMUL_OVERFLOW_ANZ_BP +# define SMUL_OVERFLOW_ANZ_BP(A, B, RES, MIN, MAX) LIBSIMPLE_SMUL_OVERFLOW_ANZ_BP(A, B, RES, MIN, MAX) +#endif + +#ifndef SDIV_OVERFLOW +# define SDIV_OVERFLOW(A, B, RES, MIN, MAX) LIBSIMPLE_SDIV_OVERFLOW(A, B, RES, MIN, MAX) +#endif + +#ifndef SINCR_OVERFLOW +# define SINCR_OVERFLOW(AP, MAX) LIBSIMPLE_SINCR_OVERFLOW(AP, MAX) +#endif + +#ifndef SDECR_OVERFLOW +# define SDECR_OVERFLOW(AP, MIN) LIBSIMPLE_SDECR_OVERFLOW(AP, MIN) +#endif + +#ifndef INCR_WOULD_OVERFLOW +# define INCR_WOULD_OVERFLOW(A, MAX) LIBSIMPLE_INCR_WOULD_OVERFLOW(A, MAX) +#endif + +#ifndef DECR_WOULD_OVERFLOW +# define DECR_WOULD_OVERFLOW(A, MIN) LIBSIMPLE_DECR_WOULD_OVERFLOW(A, MIN) +#endif + +#ifndef INCR_OVERFLOW +# define INCR_OVERFLOW(AP, MAX) LIBSIMPLE_INCR_OVERFLOW(AP, MAX) +#endif + +#ifndef DECR_OVERFLOW +# define DECR_OVERFLOW(AP, MIN) LIBSIMPLE_DECR_OVERFLOW(AP, MIN) +#endif diff --git a/libsimple/str.h b/libsimple/str.h index c52b2c8..7120fb5 100644 --- a/libsimple/str.h +++ b/libsimple/str.h @@ -5,7 +5,7 @@ * Scans for a character in a string, the scan is case-sensitive * * @param s The string to scan - * @param c The character for scan for + * @param c The character to scan for * @return `s` with a minimal offset such that `*r == c || !*r`, * where `r` is the returned pointer */ @@ -20,7 +20,7 @@ char *libsimple_strchrnul(const char *, int); * Scans for a character in a string, the scan is case-insensitive * * @param s The string to scan - * @param c The character for scan for + * @param c The character to scan for * @return `s` with a minimal offset such that `tolower(*r) == tolower(c)`, * where `r` is the returned pointer, `NULL` if no such offset exists */ @@ -35,7 +35,7 @@ char *libsimple_strcasechr(const char *, int); * Scans for a character in a string, the scan is case-insensitive * * @param s The string to scan - * @param c The character for scan for + * @param c The character to scan for * @return `s` with a minimal offset such that `tolower(*r) == tolower(c) || !*r`, * where `r` is the returned pointer */ @@ -50,7 +50,7 @@ char *libsimple_strcasechrnul(const char *, int); * Scans for a character in a string, the scan is case-insensitive * * @param s The string to scan - * @param c The character for scan for + * @param c The character to scan for * @return `s` with a maximal offset such that `tolower(*r) == tolower(c)`, * where `r` is the returned pointer, `NULL` if no such offset exists */ @@ -61,6 +61,102 @@ char *libsimple_strrcasechr(const char *, int); #endif +/** + * Scans for a character in a string with any other value that the + * specified value, the scan is case-sensitive + * + * @param s The string to scan + * @param c The character to skip over + * @return `s` with a minimal offset such that `*r != c`, where `r` + * is the returned pointer, `NULL` if no such offset exists + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__))) +char *libsimple_strchr_inv(const char *, int); +#ifndef strchr_inv +# define strchr_inv libsimple_strchr_inv +#endif + + +/** + * Scans for a character in a string with any other value that the + * specified value, the scan is case-sensitive + * + * @param s The string to scan + * @param c The character to skip over + * @return `s` with a minimal offset such that `*r != c || !*r`, + * where `r` is the returned pointer + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __returns_nonnull__, __warn_unused_result__))) +char *libsimple_strchrnul_inv(const char *, int); +#ifndef strchrnul_inv +# define strchrnul_inv libsimple_strchrnul_inv +#endif + + +/** + * Scans for a character in a string with any other value that the + * specified value, the scan is case-insensitive + * + * @param s The string to scan + * @param c The character to skip over + * @return `s` with a minimal offset such that `tolower(*r) != tolower(c)`, + * where `r` is the returned pointer, `NULL` if no such offset exists + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__))) +char *libsimple_strcasechr_inv(const char *, int); +#ifndef strcasechr_inv +# define strcasechr_inv libsimple_strcasechr_inv +#endif + + +/** + * Scans for a character in a string with any other value that the + * specified value, the scan is case-insensitive + * + * @param s The string to scan + * @param c The character to skip over + * @return `s` with a minimal offset such that `tolower(*r) != tolower(c) || !*r`, + * where `r` is the returned pointer + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __returns_nonnull__, __warn_unused_result__))) +char *libsimple_strcasechrnul_inv(const char *, int); +#ifndef strcasechrnul_inv +# define strcasechrnul_inv libsimple_strcasechrnul_inv +#endif + + +/** + * Scans for a character in a string with any other value that the + * specified value, the scan is case-sensitive + * + * @param s The string to scan + * @param c The character to skip over + * @return `s` with a maximal offset such that `*r != c`, where `r` + * is the returned pointer, `NULL` if no such offset exists + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__))) +char *libsimple_strrchr_inv(const char *, int); +#ifndef strrchr_inv +# define strrchr_inv libsimple_strrchr_inv +#endif + + +/** + * Scans for a character in a string with any other value that the + * specified value, the scan is case-insensitive + * + * @param s The string to scan + * @param c The character to skip over + * @return `s` with a maximal offset such that `tolower(*r) != tolower(c)`, + * where `r` is the returned pointer, `NULL` if no such offset exists + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__))) +char *libsimple_strrcasechr_inv(const char *, int); +#ifndef strrcasechr_inv +# define strrcasechr_inv libsimple_strrcasechr_inv +#endif + + /** * Scans for the end of a string * @@ -406,6 +502,189 @@ static inline char *libsimple_stpmove(char *__d, const char *__s) /* TODO test * #endif +/** + * Fill a string with a character + * + * @param s The string to fill + * @param c The byte to replace all bytes in `s` with + * @return `s` + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__))) +static inline char * +libsimple_strset(char *__s, int __c_) /* TODO test, man */ +{ + char __c = (char)__c_, *__r = __s; + while (*__s) *__s++ = __c; + return __r; +} +#ifndef strset +# define strset libsimple_strset +#endif + + +/** + * Fill a string with a character + * + * @param s The string to fill + * @param c The byte to replace all bytes in `s` with + * @return `&s[strlen(s)]` + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__))) +static inline char * +libsimple_stpset(char *__s, int __c_) /* TODO test, man */ +{ + char __c = (char)__c_; + while (*__s) *__s++ = __c; + return __s; +} +#ifndef stpset +# define stpset libsimple_stpset +#endif + + +/** + * Copy a string, but stop after a specific character + * + * @param d The location the string shall be copied to + * @param s The string to copy + * @param c The character that stops the copying + * @param `&strchr(d, c)[1]` (after copying) if `c` can be + * found in `s`, `NULL` otherwise + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__))) +static inline char * +libsimple_strccpy(char *restrict __d, const char *restrict __s, int __c_) /* TODO test, man */ +{ + char __c = (char)__c_; + do { + if ((*__d++ = *__s) == __c) + return __d; + } while (*__s++); + return NULL; +} +#ifndef strccpy +# define strccpy libsimple_strccpy +#endif + + +/** + * Move a string, but stop after a specific character + * + * @param d The location the string shall be moved to + * @param s The string to copy + * @param c The character that stops the copying + * @param `&strchr(d, c)[1]` (after copying) if `c` can be + * found in `s` (before copying), `NULL` otherwise + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__))) +char *libsimple_strcmove(char *, const char *, int); +#ifndef strcmove +# define strcmove libsimple_strcmove +#endif + + +/** + * Replace all instances of a character in an string with + * another character + * + * @param s The string + * @param old The value of the characters to replace + * @param new The value to replace the characters with + * @return `strchr(s, '\0')` + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __returns_nonnull__))) +static inline char * +libsimple_strreplace(char *__s, int __old_, int __new_) /* TODO test, man */ +{ + char __old = (char)__old_, __new = (char)__new_; + for (; *__s; __s++) + if (*__s == __old) + *__s = __new; + return __s; +} +#ifndef strreplace +# define strreplace libsimple_strreplace +#endif + + +/** + * Copy a string but convert to lower case + * + * `d` and `s` may overlap; the function has + * an optimisation for when `d == s` + * + * `d` will be `s` but in lower case + * + * @param d The location the string shall be copied to + * @param s The string to copy + * @return `strchr(d, '\0')` (after copying) + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __returns_nonnull__))) +char *libsimple_stptolower(char *__d, const char *__s); +#ifndef stptolower +# define stptolower libsimple_stptolower +#endif + + +/** + * Copy a string but convert to upper case + * + * `d` and `s` may overlap; the function has + * an optimisation for when `d == s` + * + * `d` will be `s` but in upper case + * + * @param d The location the string shall be copied to + * @param s The string to copy + * @return `strchr(d, '\0')` (after copying) + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __returns_nonnull__))) +char *libsimple_stptoupper(char *__d, const char *__s); +#ifndef stptoupper +# define stptoupper libsimple_stptoupper +#endif + + +/** + * Copy a string but convert to lower case + * + * `d` and `s` may overlap; the function has + * an optimisation for when `d == s` + * + * `d` will be `s` but in lower case + * + * @param d The location the string shall be copied to + * @param s The string to copy + * @return `d` + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __returns_nonnull__))) +static inline char *libsimple_strtolower(char *__d, const char *__s) /* TODO man */ +{ libsimple_stptolower(__d, __s); return __d; } +#ifndef strtolower +# define strtolower libsimple_strtolower +#endif + + +/** + * Copy a string but convert to upper case + * + * `d` and `s` may overlap; the function has + * an optimisation for when `d == s` + * + * `d` will be `s` but in upper case + * + * @param d The location the string shall be copied to + * @param s The string to copy + * @return `d` + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __returns_nonnull__))) +static inline char *libsimple_strtoupper(char *__d, const char *__s) /* TODO man */ +{ libsimple_stptoupper(__d, __s); return __d; } +#ifndef strtoupper +# define strtoupper libsimple_strtoupper +#endif + + /** * Check whether a NUL-terminated string is encoded in UTF-8 * diff --git a/libsimple/strn.h b/libsimple/strn.h index 28a2917..5c23e3e 100644 --- a/libsimple/strn.h +++ b/libsimple/strn.h @@ -5,7 +5,7 @@ * Scans for a character in a string, the scan is case-insensitive * * @param s The string to scan - * @param c The character for scan for + * @param c The character to scan for * @param n Truncate `s` to this length if it is longer * @return `s` with a minimal offset such that `*r == c`, * where `r` is the returned pointer, `NULL` if no such offset exists @@ -22,7 +22,7 @@ char *libsimple_strnchr(const char *, int, size_t); * Scans for a character in a string, the scan is case-insensitive * * @param s The string to scan - * @param c The character for scan for + * @param c The character to scan for * @param n Truncate `s` to this length if it is longer * @return `s` with a minimal offset such that `tolower(*r) == tolower(c)`, * where `r` is the returned pointer, `NULL` if no such offset exists @@ -39,7 +39,7 @@ char *libsimple_strncasechr(const char *, int, size_t); * Scans for a character in a string, the scan is case-sensitive * * @param s The string to scan - * @param c The character for scan for + * @param c The character to scan for * @param n Truncate `s` to this length if it is longer * @return `s` with a minimal offset such that `*r == c || !*r`, * where `r` is the returned pointer, however if no such @@ -56,7 +56,7 @@ char *libsimple_strnchrnul(const char *, int, size_t); * Scans for a character in a string, the scan is case-insensitive * * @param s The string to scan - * @param c The character for scan for + * @param c The character to scan for * @param n Truncate `s` to this length if it is longer * @return `s` with a minimal offset such that `tolower(*r) == tolower(c) || !*r`, * where `r` is the returned pointer, however if no such offset @@ -73,7 +73,7 @@ char *libsimple_strncasechrnul(const char *, int, size_t); * Scans for a character in a string, the scan is case-sensitive * * @param s The string to scan - * @param c The character for scan for + * @param c The character to scan for * @param n Truncate `s` to this length if it is longer * @return `s` with a maximal offset such that `*r == c`, * where `r` is the returned pointer, `NULL` if no such offset exists @@ -86,10 +86,11 @@ char *libsimple_strrnchr(const char *, int, size_t); /** - * Scans for a character in a string, the scan is case-insensitive + * Scans for a character in a string with any other value that the + * specified value, the scan is case-insensitive * * @param s The string to scan - * @param c The character for scan for + * @param c The character to scan for * @param n Truncate `s` to this length if it is longer * @return `s` with a maximal offset such that `tolower(*r) == tolower(c)`, * where `r` is the returned pointer, `NULL` if no such offset exists @@ -101,6 +102,112 @@ char *libsimple_strrncasechr(const char *, int, size_t); #endif +/** + * Scans for a character in a string with any other value that the + * specified value, the scan is case-insensitive + * + * @param s The string to scan + * @param c The character to skip over + * @param n Truncate `s` to this length if it is longer + * @return `s` with a minimal offset such that `*r != c`, + * where `r` is the returned pointer, `NULL` if no such offset exists + * within the first `n` bytes + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__))) +char *libsimple_strnchr_inv(const char *, int, size_t); +#ifndef strnchr_inv +# define strnchr_inv libsimple_strnchr_inv +#endif + + +/** + * Scans for a character in a string with any other value that the + * specified value, the scan is case-insensitive + * + * @param s The string to scan + * @param c The character to skip over + * @param n Truncate `s` to this length if it is longer + * @return `s` with a minimal offset such that `tolower(*r) != tolower(c)`, + * where `r` is the returned pointer, `NULL` if no such offset exists + * within the first `n` bytes + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__))) +char *libsimple_strncasechr_inv(const char *, int, size_t); +#ifndef strncasechr_inv +# define strncasechr_inv libsimple_strncasechr_inv +#endif + + +/** + * Scans for a character in a string with any other value that the + * specified value, the scan is case-sensitive + * + * @param s The string to scan + * @param c The character to skip over + * @param n Truncate `s` to this length if it is longer + * @return `s` with a minimal offset such that `*r != c || !*r`, + * where `r` is the returned pointer, however if no such + * offset exists within the first `n` bytes, `&s[n]` is returned + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __returns_nonnull__, __warn_unused_result__))) +char *libsimple_strnchrnul_inv(const char *, int, size_t); +#ifndef strnchrnul_inv +# define strnchrnul_inv libsimple_strnchrnul_inv +#endif + + +/** + * Scans for a character in a string with any other value that the + * specified value, the scan is case-insensitive + * + * @param s The string to scan + * @param c The character to skip over + * @param n Truncate `s` to this length if it is longer + * @return `s` with a minimal offset such that `tolower(*r) != tolower(c) || !*r`, + * where `r` is the returned pointer, however if no such offset + * exists within the first `n` bytes, `&s[n]` is returned + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __returns_nonnull__, __warn_unused_result__))) +char *libsimple_strncasechrnul_inv(const char *, int, size_t); +#ifndef strncasechrnul_inv +# define strncasechrnul_inv libsimple_strncasechrnul_inv +#endif + + +/** + * Scans for a character in a string with any other value that the + * specified value, the scan is case-sensitive + * + * @param s The string to scan + * @param c The character to skip over + * @param n Truncate `s` to this length if it is longer + * @return `s` with a maximal offset such that `*r != c`, + * where `r` is the returned pointer, `NULL` if no such offset exists + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__))) +char *libsimple_strrnchr_inv(const char *, int, size_t); +#ifndef strrnchr_inv +# define strrnchr_inv libsimple_strrnchr_inv +#endif + + +/** + * Scans for a character in a string with any other value that the + * specified value, the scan is case-insensitive + * + * @param s The string to scan + * @param c The character to skip over + * @param n Truncate `s` to this length if it is longer + * @return `s` with a maximal offset such that `tolower(*r) != tolower(c)`, + * where `r` is the returned pointer, `NULL` if no such offset exists + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__))) +char *libsimple_strrncasechr_inv(const char *, int, size_t); +#ifndef strrncasechr_inv +# define strrncasechr_inv libsimple_strrncasechr_inv +#endif + + /** * Scans for the end of a string * @@ -467,6 +574,199 @@ libsimple_stpnmove(char *__d, const char *__s, size_t __n) /* TODO test */ #endif +/** + * Fill a string with a character + * + * @param s The string to fill + * @param c The byte to replace all bytes in `s` with + * @param n The maximum number of bytes to write + * @return `s` + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__))) +static inline char * +libsimple_strnset(char *__s, int __c_, size_t __n) /* TODO test, man */ +{ + char __c = (char)__c_, *__r = __s; + while (__n-- && *__s) *__s++ = __c; + return __r; +} +#ifndef strnset +# define strnset libsimple_strnset +#endif + + +/** + * Fill a string with a character + * + * @param s The string to fill + * @param c The byte to replace all bytes in `s` with + * @param n The maximum number of bytes to write + * @return `&s[strnlen(s, n)]` + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__))) +static inline char * +libsimple_stpnset(char *__s, int __c_, size_t __n) /* TODO test, man */ +{ + char __c = (char)__c_; + while (__n-- && *__s) *__s++ = __c; + return __s; +} +#ifndef stpnset +# define stpnset libsimple_stpnset +#endif + + +/** + * Copy a string, but stop after a specific character + * + * @param d The location the string shall be copied to + * @param s The string to copy + * @param c The character that stops the copying + * @param n The maximum number of bytes to copy + * @param `&strchr(d, c)[1]` (after copying) if `c` can be + * found in `s`, `NULL` otherwise + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__))) +static inline char * +libsimple_strnccpy(char *restrict __d, const char *restrict __s, int __c_, size_t __n) /* TODO test, man */ +{ + char __c = (char)__c_; + do { + if ((*__d++ = *__s) == __c) + return __d; + } while (*__s++ && __n--); + return NULL; +} +#ifndef strnccpy +# define strnccpy libsimple_strnccpy +#endif + + +/** + * Move a string, but stop after a specific character + * + * @param d The location the string shall be moved to + * @param s The string to copy + * @param c The character that stops the copying + * @param n The maximum number of bytes to move + * @param `&strchr(d, c)[1]` (after copying) if `c` can be + * found within the first `n` bytes of `s` (before + * copying), `NULL` otherwise + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__))) +char *libsimple_strncmove(char *, const char *, int, size_t); +#ifndef strncmove +# define strncmove libsimple_strncmove +#endif + + +/** + * Replace all instances of a character in an string with + * another character + * + * @param s The string + * @param old The value of the characters to replace + * @param new The value to replace the characters with + * @param n The maximum length of `s` + * @return `strnchr(s, '\0', n)` + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __returns_nonnull__))) +static inline char * +libsimple_strnreplace(char *__s, int __old_, int __new_, size_t __n) /* TODO test, man */ +{ + char __old = (char)__old_, __new = (char)__new_; + for (; __n && *__s; __s++, __n--) + if (*__s == __old) + *__s = __new; + return __s; +} +#ifndef strnreplace +# define strnreplace libsimple_strnreplace +#endif + + +/** + * Copy a string but convert to lower case + * + * `d` and `s` may overlap; the function has + * an optimisation for when `d == s` + * + * `d` will be `s` but in lower case + * + * @param d The location the string shall be copied to + * @param s The string to copy + * @param n The maximum number of bytes to copy or convert + * @return `strnchrnul(d, '\0', n)` (after copying) + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __returns_nonnull__))) +char *libsimple_stpntolower(char *__d, const char *__s, size_t __n); +#ifndef stpntolower +# define stpntolower libsimple_stpntolower +#endif + + +/** + * Copy a string but convert to upper case + * + * `d` and `s` may overlap; the function has + * an optimisation for when `d == s` + * + * `d` will be `s` but in upper case + * + * @param d The location the string shall be copied to + * @param s The string to copy + * @param n The maximum number of bytes to copy or convert + * @return `strnchrnul(d, '\0', n)` (after copying) + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __returns_nonnull__))) +char *libsimple_stpntoupper(char *__d, const char *__s, size_t __n); +#ifndef stpntoupper +# define stpntoupper libsimple_stpntoupper +#endif + + +/** + * Copy a string but convert to lower case + * + * `d` and `s` may overlap; the function has + * an optimisation for when `d == s` + * + * `d` will be `s` but in lower case + * + * @param d The location the string shall be copied to + * @param s The string to copy + * @param n The maximum number of bytes to copy or convert + * @return `d` + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __returns_nonnull__))) +static inline char *libsimple_strntolower(char *__d, const char *__s, size_t __n) /* TODO man */ +{ libsimple_stpntolower(__d, __s, __n); return __d; } +#ifndef strntolower +# define strntolower libsimple_strntolower +#endif + + +/** + * Copy a string but convert to upper case + * + * `d` and `s` may overlap; the function has + * an optimisation for when `d == s` + * + * `d` will be `s` but in upper case + * + * @param d The location the string shall be copied to + * @param s The string to copy + * @param n The maximum number of bytes to copy or convert + * @return `d` + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __returns_nonnull__))) +static inline char *libsimple_strntoupper(char *__d, const char *__s, size_t __n) /* TODO man */ +{ libsimple_stpntoupper(__d, __s, __n); return __d; } +#ifndef strntoupper +# define strntoupper libsimple_strntoupper +#endif + + /** * Check whether a string, that may be or may not be NUL-terminated, * is encoded in UTF-8 diff --git a/man3/libsimple_difftimespec.3 b/man3/libsimple_difftimespec.3 index 49d4faa..bf26446 100644 --- a/man3/libsimple_difftimespec.3 +++ b/man3/libsimple_difftimespec.3 @@ -32,6 +32,15 @@ is subtracted by .IR subtrahend ) and stores the result in .IR diff . +.PP +These functions assume that +.I minuend->tv_nsec +and +.I subtrahend->tv_nsec +are in thier valid range ([0, 1000000000) for +.BR libsimple_sumtimespec () +and [0, 1000000) for +.BR libsimple_sumtimeval ()) .SH RETURN VALUE The .BR libsimple_difftimespec () diff --git a/man3/libsimple_multimespec.3 b/man3/libsimple_multimespec.3 index a55b7a2..34b352d 100644 --- a/man3/libsimple_multimespec.3 +++ b/man3/libsimple_multimespec.3 @@ -29,6 +29,13 @@ and .I multiplier and stores the result in .IR prod . +.PP +These functions assume that +.I multiplicand->tv_nsec +is in its valid range ([0, 1000000000) for +.BR libsimple_multimespec () +and [0, 1000000) for +.BR libsimple_multimeval ()). .SH RETURN VALUE The .BR libsimple_multimespec () diff --git a/man3/libsimple_sumtimespec.3 b/man3/libsimple_sumtimespec.3 index 81632b8..7d587e0 100644 --- a/man3/libsimple_sumtimespec.3 +++ b/man3/libsimple_sumtimespec.3 @@ -38,6 +38,15 @@ functions return 0 on successful completion; otherwise, \-1 is returned and .I errno is set to indicate the error. +.PP +These functions assume that +.I augend->tv_nsec +and +.I addend->tv_nsec +are in thier valid range ([0, 1000000000) for +.BR libsimple_sumtimespec () +and [0, 1000000) for +.BR libsimple_sumtimeval ()). .SH ERRORS The .BR libsimple_sumtimespec () diff --git a/memcasechr_inv.c b/memcasechr_inv.c new file mode 100644 index 0000000..82268d8 --- /dev/null +++ b/memcasechr_inv.c @@ -0,0 +1,31 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_memcasechr_inv(const void *s_, int c, size_t n) /* TODO man */ +{ + char *s = *(char **)(void *)&s_; + size_t i = 0; + c = tolower(c); + for (; i < n && tolower(s[i]) == c; i++); + return i < n ? &s[i] : NULL; +} + + +#else +#include "test.h" + +int +main(void) +{ + assert(!strcmpnul(libsimple_memcasechr_inv("xxoxx", 'x', 5), "oxx")); + assert(!strcmpnul(libsimple_memcasechr_inv("xxXxx", 'x', 5), NULL)); + assert(!strcmpnul(libsimple_memcasechr_inv("XXoxx", 'x', 5), "oxx")); + assert(!strcmpnul(libsimple_memcasechr_inv("zzzzz", 'z', 5), NULL)); + assert(!strcmpnul(libsimple_memcasechr_inv("zzzzx", 'z', 3), NULL)); + return 0; +} + +#endif diff --git a/memcasescan_inv.c b/memcasescan_inv.c new file mode 100644 index 0000000..207c62d --- /dev/null +++ b/memcasescan_inv.c @@ -0,0 +1,31 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_memcasescan_inv(const void *s_, int c, size_t n) /* TODO man */ +{ + char *s = *(char **)(void *)&s_; + size_t i = 0; + c = tolower(c); + for (; i < n && tolower(s[i]) == c; i++); + return &s[i]; +} + + +#else +#include "test.h" + +int +main(void) +{ + assert(!strcmpnul(libsimple_memcasescan_inv("xxoxx", 'x', 5), "oxx")); + assert(!strcmpnul(libsimple_memcasescan_inv("xxXxx", 'x', 5), "")); + assert(!strcmpnul(libsimple_memcasescan_inv("XXoxx", 'x', 5), "oxx")); + assert(!strcmpnul(libsimple_memcasescan_inv("zzzzz", 'z', 5), "")); + assert(!strcmpnul(libsimple_memcasescan_inv("zzzzx", 'z', 3), "zx")); + return 0; +} + +#endif diff --git a/memchr_inv.c b/memchr_inv.c new file mode 100644 index 0000000..45885fb --- /dev/null +++ b/memchr_inv.c @@ -0,0 +1,30 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_memchr_inv(const void *s_, int c_, size_t n) /* TODO man */ +{ + char *s = *(char **)(void *)&s_, c = (char)c_; + size_t i = 0; + for (; i < n && s[i] == c; i++); + return i < n ? &s[i] : NULL; +} + + +#else +#include "test.h" + +int +main(void) +{ + assert(!strcmpnul(libsimple_memchr_inv("xxoxx", 'x', 5), "oxx")); + assert(!strcmpnul(libsimple_memchr_inv("xxXxx", 'x', 5), "Xxx")); + assert(!strcmpnul(libsimple_memchr_inv("XXoxx", 'x', 5), "XXoxx")); + assert(!strcmpnul(libsimple_memchr_inv("zzzzz", 'z', 5), NULL)); + assert(!strcmpnul(libsimple_memchr_inv("zzzzx", 'z', 3), NULL)); + return 0; +} + +#endif diff --git a/memcmove.c b/memcmove.c new file mode 100644 index 0000000..3592445 --- /dev/null +++ b/memcmove.c @@ -0,0 +1,42 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_memcmove(void *d_, const void *s_, int c_, size_t n) /* TODO test, man */ +{ + char *d = d_, c = (char)c_, *p; + const char *s = s_; + if (d < s) { + for (; n; n--, s++) + if ((*d++ = *s) == c) + return d; + } else { + for (p = *(char **)(void *)&s; n; n--, p++) { + if (*p == c) { + n = (size_t)(p - s); + p = &d[n + 1]; + do { d[n] = s[n]; } while (n--); + return p; + } + } + for (n = (size_t)(p - s); n;) { + n--; + d[n] = s[n]; + } + } + return NULL; +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/memelem.c b/memelem.c index 3881832..fbd16d7 100644 --- a/memelem.c +++ b/memelem.c @@ -6,10 +6,9 @@ void * libsimple_memelem(const void *hay_, size_t hayn, const void *sub_, size_t subn) { - if (!subn) - return (void *)hay_; - switch (subn) { + case 0: + return (void *)hay_; case 1: return memchr(hay_, *(char *)sub_, hayn); case 2: diff --git a/memelem_inv.c b/memelem_inv.c new file mode 100644 index 0000000..6c1d432 --- /dev/null +++ b/memelem_inv.c @@ -0,0 +1,68 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_memelem_inv(const void *hay_, size_t hayn, const void *sub_, size_t subn) /* TODO test, man */ +{ + switch (subn) { + case 0: + return NULL; + case 1: + return libsimple_memchr_inv(hay_, *(char *)sub_, hayn); + case 2: + { + uint16_t *hay = (void *)hay_; + uint16_t sub = *(uint16_t *)sub_; + for (; hayn--; hay++) + if (*hay != sub) + return hay; + break; + } + case 4: + { + uint32_t *hay = (void *)hay_; + uint32_t sub = *(uint32_t *)sub_; + for (; hayn--; hay++) + if (*hay != sub) + return hay; + break; + } + case 8: + { + uint64_t *hay = (void *)hay_; + uint64_t sub = *(uint64_t *)sub_; + for (; hayn--; hay++) + if (*hay != sub) + return hay; + break; + } + default: + { + char *hay = (void *)hay_; + const char *sub = sub_; + size_t i; + for (; hayn--; hay += subn) { + for (i = 0; i < subn; i++) + if (hay[i] != sub[i]) + return hay; + } + break; + } + } + + return NULL; +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/memelemscan.c b/memelemscan.c index 744989b..48e490b 100644 --- a/memelemscan.c +++ b/memelemscan.c @@ -6,10 +6,9 @@ void * libsimple_memelemscan(const void *hay_, size_t hayn, const void *sub_, size_t subn) { - if (!subn) - return (void *)hay_; - switch (subn) { + case 0: + return (void *)hay_; case 1: return libsimple_memscan(hay_, *(char *)sub_, hayn); case 2: @@ -48,8 +47,6 @@ libsimple_memelemscan(const void *hay_, size_t hayn, const void *sub_, size_t su return hay; } } - - return NULL; } diff --git a/memelemscan_inv.c b/memelemscan_inv.c new file mode 100644 index 0000000..778ef8b --- /dev/null +++ b/memelemscan_inv.c @@ -0,0 +1,60 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_memelemscan_inv(const void *hay_, size_t hayn, const void *sub_, size_t subn) /* TODO test, man */ +{ + switch (subn) { + case 0: + return (void *)hay_; + case 1: + return libsimple_memscan_inv(hay_, *(char *)sub_, hayn); + case 2: + { + uint16_t *hay = (void *)hay_; + uint16_t sub = *(uint16_t *)sub_; + for (; hayn-- && *hay == sub; hay++); + return hay; + } + case 4: + { + uint32_t *hay = (void *)hay_; + uint32_t sub = *(uint32_t *)sub_; + for (; hayn-- && *hay == sub; hay++); + return hay; + } + case 8: + { + uint64_t *hay = (void *)hay_; + uint64_t sub = *(uint64_t *)sub_; + for (; hayn-- && *hay == sub; hay++); + return hay; + } + default: + { + char *hay = (void *)hay_; + const char *sub = sub_; + size_t i; + for (; hayn--; hay += subn) { + for (i = 0; i < subn; i++) + if (hay[i] != sub[i]) + return hay; + } + return hay; + } + } +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/memptolower.c b/memptolower.c new file mode 100644 index 0000000..de813e5 --- /dev/null +++ b/memptolower.c @@ -0,0 +1,60 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_memptolower(void *d_, const void *s_, size_t n) /* TODO man */ +{ + char *ret, *d = d_; + const char *s = s_; + if (d == s) { + for (; n; d++, n--) + *d = tolower(*d); + return d; + } else if (d < s) { + for (; n; d++, s++, n--) + *d = tolower(*s); + return d; + } else { + ret = &d[n]; + while (n) { + n--; + d[n] = tolower(s[n]); + } + return ret; + } +} + + +#else +#include "test.h" + +int +main(void) +{ + char buf[100]; + + stpcpy(buf, "ABCDEabcde12345"); + assert(libsimple_memptolower(&buf[3], &buf[0], 16) == &buf[19]); + assert(!strcmp(buf, "ABCabcdeabcde12345")); + stpcpy(buf, "ABCDEabcde12345"); + assert(libsimple_memptolower(&buf[0], &buf[3], 13) == &buf[13]); + assert(!strcmp(buf, "deabcde12345")); + stpcpy(buf, "ABCDEabcde12345"); + assert(libsimple_memptolower(&buf[0], &buf[0], 16) == &buf[16]); + assert(!strcmp(buf, "abcdeabcde12345")); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_memtolower(&buf[3], &buf[0], 16), "abcdeabcde12345")); + assert(!strcmp(buf, "ABCabcdeabcde12345")); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_memtolower(&buf[0], &buf[3], 13), "deabcde12345")); + assert(!strcmp(buf, "deabcde12345")); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_memtolower(&buf[0], &buf[0], 16), "abcdeabcde12345")); + assert(!strcmp(buf, "abcdeabcde12345")); + + return 0; +} + +#endif diff --git a/memptoupper.c b/memptoupper.c new file mode 100644 index 0000000..55d5e45 --- /dev/null +++ b/memptoupper.c @@ -0,0 +1,60 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_memptoupper(void *d_, const void *s_, size_t n) /* TODO man */ +{ + char *ret, *d = d_; + const char *s = s_; + if (d == s) { + for (; n; d++, n--) + *d = toupper(*d); + return d; + } else if (d < s) { + for (; n; d++, s++, n--) + *d = toupper(*s); + return d; + } else { + ret = &d[n]; + while (n) { + n--; + d[n] = toupper(s[n]); + } + return ret; + } +} + + +#else +#include "test.h" + +int +main(void) +{ + char buf[100]; + + stpcpy(buf, "abcdeABCDE12345"); + assert(libsimple_memptoupper(&buf[3], &buf[0], 16) == &buf[19]); + assert(!strcmp(buf, "abcABCDEABCDE12345")); + stpcpy(buf, "abcdeABCDE12345"); + assert(libsimple_memptoupper(&buf[0], &buf[3], 13) == &buf[13]); + assert(!strcmp(buf, "DEABCDE12345")); + stpcpy(buf, "abcdeABCDE12345"); + assert(libsimple_memptoupper(&buf[0], &buf[0], 16) == &buf[16]); + assert(!strcmp(buf, "ABCDEABCDE12345")); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_memtoupper(&buf[3], &buf[0], 16), "ABCDEABCDE12345")); + assert(!strcmp(buf, "abcABCDEABCDE12345")); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_memtoupper(&buf[0], &buf[3], 13), "DEABCDE12345")); + assert(!strcmp(buf, "DEABCDE12345")); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_memtoupper(&buf[0], &buf[0], 16), "ABCDEABCDE12345")); + assert(!strcmp(buf, "ABCDEABCDE12345")); + + return 0; +} + +#endif diff --git a/memrcasechr_inv.c b/memrcasechr_inv.c new file mode 100644 index 0000000..f6c16e7 --- /dev/null +++ b/memrcasechr_inv.c @@ -0,0 +1,26 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_memrcasechr_inv(const void *s_, int c, size_t n_) /* TODO test, man */ +{ + char *s = *(char **)(void *)&s_; + ssize_t n = n_; + c = tolower(c); + while (n-- && tolower(s[n]) == c); + return n < 0 ? NULL : &s[n]; +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/memrchr_inv.c b/memrchr_inv.c new file mode 100644 index 0000000..d7239b3 --- /dev/null +++ b/memrchr_inv.c @@ -0,0 +1,25 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_memrchr_inv(const void *s_, int c_, size_t n_) /* TODO test, man */ +{ + char *s = *(char **)(void *)&s_, c = (char)c_; + ssize_t n = n_; + while (n-- && s[n] == c); + return n < 0 ? NULL : &s[n]; +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/memrelem.c b/memrelem.c index 8317e8e..8121423 100644 --- a/memrelem.c +++ b/memrelem.c @@ -6,10 +6,9 @@ void * libsimple_memrelem(const void *hay_, size_t hayn, const void *sub_, size_t subn) { - if (!subn) - return (void *)hay_; - switch (subn) { + case 0: + return (void *)hay_; case 1: { uint8_t *hay = (void *)hay_; diff --git a/memrelem_inv.c b/memrelem_inv.c new file mode 100644 index 0000000..5cadab1 --- /dev/null +++ b/memrelem_inv.c @@ -0,0 +1,76 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_memrelem_inv(const void *hay_, size_t hayn, const void *sub_, size_t subn) /* TODO test, man */ +{ + switch (subn) { + case 0: + return NULL; + case 1: + { + uint8_t *hay = (void *)hay_; + uint8_t sub = *(uint8_t *)sub_; + for (hay += hayn; hayn--;) + if (*--hay != sub) + return hay; + break; + } + case 2: + { + uint16_t *hay = (void *)hay_; + uint16_t sub = *(uint16_t *)sub_; + for (hay += hayn; hayn--;) + if (*--hay != sub) + return hay; + break; + } + case 4: + { + uint32_t *hay = (void *)hay_; + uint32_t sub = *(uint32_t *)sub_; + for (hay += hayn; hayn--;) + if (*--hay != sub) + return hay; + break; + } + case 8: + { + uint64_t *hay = (void *)hay_; + uint64_t sub = *(uint64_t *)sub_; + for (hay += hayn; hayn--;) + if (*--hay != sub) + return hay; + break; + } + default: + { + char *hay = (void *)hay_; + const char *sub = sub_; + size_t i; + for (hay += hayn * subn; hayn--;) { + hay -= subn; + for (i = 0; i < subn; i++) + if (hay[i] != sub[i]) + return hay; + } + break; + } + } + + return NULL; +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/memreplaceelem.c b/memreplaceelem.c new file mode 100644 index 0000000..1620d5c --- /dev/null +++ b/memreplaceelem.c @@ -0,0 +1,83 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_memreplaceelem(void *restrict s_, const void *old_, const void *new_, size_t n, size_t width) /* TODO test, man */ +{ + switch (width) { + case 0: + return s_; + case 1: + { + uint8_t *restrict s = s_; + uint8_t old = *(const uint8_t *)old_; + uint8_t new = *(const uint8_t *)new_; + for (; n; s++, n--) + if (*s == old) + *s = new; + return s; + } + case 2: + { + uint16_t *restrict s = s_; + uint16_t old = *(const uint16_t *)old_; + uint16_t new = *(const uint16_t *)new_; + for (; n; s++, n--) + if (*s == old) + *s = new; + return s; + } + case 4: + { + uint32_t *restrict s = s_; + uint32_t old = *(const uint32_t *)old_; + uint32_t new = *(const uint32_t *)new_; + for (; n; s++, n--) + if (*s == old) + *s = new; + return s; + } + case 8: + { + uint64_t *restrict s = s_; + uint64_t old = *(const uint64_t *)old_; + uint64_t new = *(const uint64_t *)new_; + for (; n; s++, n--) + if (*s == old) + *s = new; + return s; + } + default: + { + char *restrict s = s_; + const char *old = old_; + const char *new = new_; + size_t i; + for (; n; s += width, n--) { + if (*s == *old) { + for (i = 0; i < width; i++) + if (s[i] != old[i]) + goto next; + for (i = 0; i < width; i++) + s[i] = new[i]; + } + next:; + } + return s; + } + } +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/memscan_inv.c b/memscan_inv.c new file mode 100644 index 0000000..7c3c935 --- /dev/null +++ b/memscan_inv.c @@ -0,0 +1,30 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_memscan_inv(const void *s_, int c_, size_t n) /* TODO man */ +{ + char *s = *(char **)(void *)&s_, c = (char)c_; + size_t i = 0; + for (; i < n && s[i] == c; i++); + return &s[i]; +} + + +#else +#include "test.h" + +int +main(void) +{ + assert(!strcmpnul(libsimple_memscan_inv("xxoxx", 'x', 5), "oxx")); + assert(!strcmpnul(libsimple_memscan_inv("xxXxx", 'x', 5), "Xxx")); + assert(!strcmpnul(libsimple_memscan_inv("XXoxx", 'x', 5), "XXoxx")); + assert(!strcmpnul(libsimple_memscan_inv("zzzzz", 'z', 5), "")); + assert(!strcmpnul(libsimple_memscan_inv("zzzzx", 'z', 3), "zx")); + return 0; +} + +#endif diff --git a/multimespec.c b/multimespec.c index c2a58c1..bc73055 100644 --- a/multimespec.c +++ b/multimespec.c @@ -31,13 +31,11 @@ libsimple_multimespec(struct timespec *prod, const struct timespec *multiplicand xs = ns / 1000000000L; ns %= 1000000000L; - if (s > TIME_MAX / multiplier) + if (LIBSIMPLE_SMUL_OVERFLOW_AP_BP(s, multiplier, &s, TIME_MIN, TIME_MAX)) goto overflow; - s *= multiplier; - if (s > TIME_MAX - (time_t)xs) + if (LIBSIMPLE_SADD_OVERFLOW_NONNEG(s, (time_t)xs, &s, TIME_MIN, TIME_MAX)) goto overflow; - s += (time_t)xs; if (neg) { s = -s; diff --git a/rawmemcasechr_inv.c b/rawmemcasechr_inv.c new file mode 100644 index 0000000..9f53fda --- /dev/null +++ b/rawmemcasechr_inv.c @@ -0,0 +1,27 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_rawmemcasechr_inv(const void *s_, int c) /* TODO man */ +{ + char *s = *(char **)(void *)&s_; + c = tolower(c); + for (; tolower(*s) == c; s++); + return s; +} + + +#else +#include "test.h" + +int +main(void) +{ + assert(!strcmpnul(libsimple_rawmemcasechr_inv("xxoxx", 'x'), "oxx")); + assert(!strcmpnul(libsimple_rawmemcasechr_inv("XXoxx", 'x'), "oxx")); + return 0; +} + +#endif diff --git a/rawmemchr_inv.c b/rawmemchr_inv.c new file mode 100644 index 0000000..1df5817 --- /dev/null +++ b/rawmemchr_inv.c @@ -0,0 +1,27 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_rawmemchr_inv(const void *s_, int c_) /* TODO man */ +{ + char *s = *(char **)(void *)&s_, c = (char)c_; + while (*s++ == c); + return &s[-1]; +} + + +#else +#include "test.h" + +int +main(void) +{ + assert(!strcmpnul(libsimple_rawmemchr_inv("xxoxx", 'x'), "oxx")); + assert(!strcmpnul(libsimple_rawmemchr_inv("xxXxx", 'x'), "Xxx")); + assert(!strcmpnul(libsimple_rawmemchr_inv("XXoxx", 'x'), "XXoxx")); + return 0; +} + +#endif diff --git a/rawmemelem.c b/rawmemelem.c new file mode 100644 index 0000000..ba21a32 --- /dev/null +++ b/rawmemelem.c @@ -0,0 +1,68 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_rawmemelem(const void *hay_, const void *sub_, size_t subn) +{ + switch (subn) { + case 0: + return (void *)hay_; + case 1: + return rawmemchr(hay_, *(char *)sub_); + case 2: + { + uint16_t *hay = (void *)hay_; + uint16_t sub = *(uint16_t *)sub_; + for (; *hay != sub; hay++); + return hay; + } + case 4: + { + uint32_t *hay = (void *)hay_; + uint32_t sub = *(uint32_t *)sub_; + for (; *hay != sub; hay++); + return hay; + } + case 8: + { + uint64_t *hay = (void *)hay_; + uint64_t sub = *(uint64_t *)sub_; + for (; *hay != sub; hay++); + return hay; + } + default: + { + char *hay = (void *)hay_; + const char *sub = sub_; + size_t i; + for (;; hay += subn) { + for (i = 0; i < subn; i++) + if (hay[i] != sub[i]) + goto next; + return hay; + next:; + } + } + } +} + + +#else +#include "test.h" + +int +main(void) +{ + assert(!strcmpnul(libsimple_rawmemelem("12345634", "", 0), "12345634")); + assert(!strcmpnul(libsimple_rawmemelem("12345634", "3", 1), "345634")); + assert(!strcmpnul(libsimple_rawmemelem("13456342", "3", 1), "3456342")); + assert(!strcmpnul(libsimple_rawmemelem("12345634", "34", 2), "345634")); + assert(!strcmpnul(libsimple_rawmemelem("abcd1234abcd1234", "1234", 4), "1234abcd1234")); + assert(!strcmpnul(libsimple_rawmemelem("abcdefgh12345678abcdefgh12345678", "12345678", 8), "12345678abcdefgh12345678")); + assert(!strcmpnul(libsimple_rawmemelem("abc123abc123", "123", 3), "123abc123")); + return 0; +} + +#endif diff --git a/rawmemelem_inv.c b/rawmemelem_inv.c new file mode 100644 index 0000000..aeb20d2 --- /dev/null +++ b/rawmemelem_inv.c @@ -0,0 +1,58 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_rawmemelem_inv(const void *hay_, const void *sub_, size_t subn) /* TODO test, man */ +{ + switch (subn) { + case 0: + abort(); + case 1: + return rawmemchr_inv(hay_, *(char *)sub_); + case 2: + { + uint16_t *hay = (void *)hay_; + uint16_t sub = *(uint16_t *)sub_; + for (; *hay == sub; hay++); + return hay; + } + case 4: + { + uint32_t *hay = (void *)hay_; + uint32_t sub = *(uint32_t *)sub_; + for (; *hay == sub; hay++); + return hay; + } + case 8: + { + uint64_t *hay = (void *)hay_; + uint64_t sub = *(uint64_t *)sub_; + for (; *hay == sub; hay++); + return hay; + } + default: + { + char *hay = (void *)hay_; + const char *sub = sub_; + size_t i; + for (;; hay += subn) + for (i = 0; i < subn; i++) + if (hay[i] != sub[i]) + return hay; + } + } +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/rawmemrcasechr_inv.c b/rawmemrcasechr_inv.c new file mode 100644 index 0000000..847bdea --- /dev/null +++ b/rawmemrcasechr_inv.c @@ -0,0 +1,25 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_rawmemrcasechr_inv(const void *s_, int c, size_t n) /* TODO test, man */ +{ + char *s = *(char **)(void *)&s_; + c = tolower(c); + while (--n, tolower(s[n]) == c); + return &s[n]; +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/rawmemrchr_inv.c b/rawmemrchr_inv.c new file mode 100644 index 0000000..b60a4fe --- /dev/null +++ b/rawmemrchr_inv.c @@ -0,0 +1,24 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_rawmemrchr_inv(const void *s_, int c_, size_t n) /* TODO test, man */ +{ + char *s = *(char **)(void *)&s_, c = (char)c_; + while (s[--n] == c); + return &s[n]; +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/rawmemrelem.c b/rawmemrelem.c new file mode 100644 index 0000000..75a15a9 --- /dev/null +++ b/rawmemrelem.c @@ -0,0 +1,74 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_rawmemrelem(const void *hay_, size_t hayn, const void *sub_, size_t subn) +{ + switch (subn) { + case 0: + return (void *)hay_; + case 1: + { + uint8_t *hay = (void *)hay_; + uint8_t sub = *(uint8_t *)sub_; + for (hay += hayn; *--hay != sub;); + return hay; + } + case 2: + { + uint16_t *hay = (void *)hay_; + uint16_t sub = *(uint16_t *)sub_; + for (hay += hayn; *--hay != sub;); + return hay; + } + case 4: + { + uint32_t *hay = (void *)hay_; + uint32_t sub = *(uint32_t *)sub_; + for (hay += hayn; *--hay != sub;); + return hay; + } + case 8: + { + uint64_t *hay = (void *)hay_; + uint64_t sub = *(uint64_t *)sub_; + for (hay += hayn; *--hay != sub;); + return hay; + } + default: + { + char *hay = (void *)hay_; + const char *sub = sub_; + size_t i; + for (hay += hayn * subn;;) { + hay -= subn; + for (i = 0; i < subn; i++) + if (hay[i] != sub[i]) + goto next; + return hay; + next:; + } + } + } +} + + +#else +#include "test.h" + +int +main(void) +{ + assert(!strcmpnul(libsimple_rawmemrelem("12345634", 8, "", 0), "12345634")); + assert(!strcmpnul(libsimple_rawmemrelem("12345634", 8, "3", 1), "34")); + assert(!strcmpnul(libsimple_rawmemrelem("13456342", 8, "3", 1), "342")); + assert(!strcmpnul(libsimple_rawmemrelem("12345634", 4, "34", 2), "34")); + assert(!strcmpnul(libsimple_rawmemrelem("abcd1234abcd1234", 4, "1234", 4), "1234")); + assert(!strcmpnul(libsimple_rawmemrelem("abcdefgh12345678abcdefgh12345678", 4, "12345678", 8), "12345678")); + assert(!strcmpnul(libsimple_rawmemrelem("abc123abc123", 4, "123", 3), "123")); + return 0; +} + +#endif diff --git a/rawmemrelem_inv.c b/rawmemrelem_inv.c new file mode 100644 index 0000000..6c714cf --- /dev/null +++ b/rawmemrelem_inv.c @@ -0,0 +1,65 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_rawmemrelem_inv(const void *hay_, size_t hayn, const void *sub_, size_t subn) /* TODO test, man */ +{ + switch (subn) { + case 0: + abort(); + case 1: + { + uint8_t *hay = (void *)hay_; + uint8_t sub = *(uint8_t *)sub_; + for (hay += hayn; *--hay == sub;); + return hay; + } + case 2: + { + uint16_t *hay = (void *)hay_; + uint16_t sub = *(uint16_t *)sub_; + for (hay += hayn; *--hay == sub;); + return hay; + } + case 4: + { + uint32_t *hay = (void *)hay_; + uint32_t sub = *(uint32_t *)sub_; + for (hay += hayn; *--hay == sub;); + return hay; + } + case 8: + { + uint64_t *hay = (void *)hay_; + uint64_t sub = *(uint64_t *)sub_; + for (hay += hayn; *--hay == sub;); + return hay; + } + default: + { + char *hay = (void *)hay_; + const char *sub = sub_; + size_t i; + for (hay += hayn * subn;;) { + hay -= subn; + for (i = 0; i < subn; i++) + if (hay[i] != sub[i]) + return hay; + } + } + } +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/stpntolower.c b/stpntolower.c new file mode 100644 index 0000000..9fc4466 --- /dev/null +++ b/stpntolower.c @@ -0,0 +1,115 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_stpntolower(char *d, const char *s, size_t n) /* TODO man */ +{ + size_t i; + char *ret; + if (d == s) { + for (; n && *d; d++, n--) + *d = tolower(*d); + return d; + } else if (d < s) { + for (; n && *s; d++, s++, n--) + *d = tolower(*s); + if (n) + *d = '\0'; + return d; + } else { + for (i = 0; i < n && s[i]; i++); + ret = &d[i]; + if (i != n) + d[i] = tolower(s[i]); + while (i--) + d[i] = tolower(s[i]); + return ret; + } +} + + +#else +#include "test.h" + +int +main(void) +{ + char buf[100]; + + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_stpntolower(&buf[3], &buf[0], SIZE_MAX), "")); + assert(!strcmp(buf, "ABCabcdeabcde12345")); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_stpntolower(&buf[0], &buf[3], SIZE_MAX), "")); + assert(!strcmp(buf, "deabcde12345")); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_stpntolower(&buf[0], &buf[0], SIZE_MAX), "")); + assert(!strcmp(buf, "abcdeabcde12345")); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_strntolower(&buf[3], &buf[0], SIZE_MAX), "abcdeabcde12345")); + assert(!strcmp(buf, "ABCabcdeabcde12345")); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_strntolower(&buf[0], &buf[3], SIZE_MAX), "deabcde12345")); + assert(!strcmp(buf, "deabcde12345")); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_strntolower(&buf[0], &buf[0], SIZE_MAX), "abcdeabcde12345")); + assert(!strcmp(buf, "abcdeabcde12345")); + + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "ABCDEabcde12345"); + buf[18] = 'X'; + assert(!strcmpnul(libsimple_stpntolower(&buf[3], &buf[0], 15), "X")); + assert(!strcmp(buf, "ABCabcdeabcde12345X")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_stpntolower(&buf[0], &buf[3], 12), "345")); + assert(!strcmp(buf, "deabcde12345345")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "ABCDEabcde12345X"); + assert(!strcmpnul(libsimple_stpntolower(&buf[0], &buf[0], 15), "X")); + assert(!strcmp(buf, "abcdeabcde12345X")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "ABCDEabcde12345"); + buf[18] = 'X'; + assert(!strcmpnul(libsimple_strntolower(&buf[3], &buf[0], 15), "abcdeabcde12345X")); + assert(!strcmp(buf, "ABCabcdeabcde12345X")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_strntolower(&buf[0], &buf[3], 12), "deabcde12345345")); + assert(!strcmp(buf, "deabcde12345345")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "ABCDEabcde12345X"); + assert(!strcmpnul(libsimple_strntolower(&buf[0], &buf[0], 15), "abcdeabcde12345X")); + assert(!strcmp(buf, "abcdeabcde12345X")); + + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_stpntolower(&buf[3], &buf[0], 0), "DEabcde12345")); + assert(!strcmp(buf, "ABCDEabcde12345")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_stpntolower(&buf[0], &buf[3], 0), "ABCDEabcde12345")); + assert(!strcmp(buf, "ABCDEabcde12345")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_stpntolower(&buf[0], &buf[0], 0), "ABCDEabcde12345")); + assert(!strcmp(buf, "ABCDEabcde12345")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_strntolower(&buf[3], &buf[0], 0), "DEabcde12345")); + assert(!strcmp(buf, "ABCDEabcde12345")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_strntolower(&buf[0], &buf[3], 0), "ABCDEabcde12345")); + assert(!strcmp(buf, "ABCDEabcde12345")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_strntolower(&buf[0], &buf[0], 0), "ABCDEabcde12345")); + assert(!strcmp(buf, "ABCDEabcde12345")); + + return 0; +} + +#endif diff --git a/stpntoupper.c b/stpntoupper.c new file mode 100644 index 0000000..588cb89 --- /dev/null +++ b/stpntoupper.c @@ -0,0 +1,115 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_stpntoupper(char *d, const char *s, size_t n) /* TODO man */ +{ + size_t i; + char *ret; + if (d == s) { + for (; n && *d; d++, n--) + *d = toupper(*d); + return d; + } else if (d < s) { + for (; n && *s; d++, s++, n--) + *d = toupper(*s); + if (n) + *d = '\0'; + return d; + } else { + for (i = 0; i < n && s[i]; i++); + ret = &d[i]; + if (i != n) + d[i] = toupper(s[i]); + while (i--) + d[i] = toupper(s[i]); + return ret; + } +} + + +#else +#include "test.h" + +int +main(void) +{ + char buf[100]; + + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_stpntoupper(&buf[3], &buf[0], SIZE_MAX), "")); + assert(!strcmp(buf, "abcABCDEABCDE12345")); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_stpntoupper(&buf[0], &buf[3], SIZE_MAX), "")); + assert(!strcmp(buf, "DEABCDE12345")); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_stpntoupper(&buf[0], &buf[0], SIZE_MAX), "")); + assert(!strcmp(buf, "ABCDEABCDE12345")); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_strntoupper(&buf[3], &buf[0], SIZE_MAX), "ABCDEABCDE12345")); + assert(!strcmp(buf, "abcABCDEABCDE12345")); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_strntoupper(&buf[0], &buf[3], SIZE_MAX), "DEABCDE12345")); + assert(!strcmp(buf, "DEABCDE12345")); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_strntoupper(&buf[0], &buf[0], SIZE_MAX), "ABCDEABCDE12345")); + assert(!strcmp(buf, "ABCDEABCDE12345")); + + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "abcdeABCDE12345"); + buf[18] = 'x'; + assert(!strcmpnul(libsimple_stpntoupper(&buf[3], &buf[0], 15), "x")); + assert(!strcmp(buf, "abcABCDEABCDE12345x")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_stpntoupper(&buf[0], &buf[3], 12), "345")); + assert(!strcmp(buf, "DEABCDE12345345")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "abcdeABCDE12345x"); + assert(!strcmpnul(libsimple_stpntoupper(&buf[0], &buf[0], 15), "x")); + assert(!strcmp(buf, "ABCDEABCDE12345x")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "abcdeABCDE12345"); + buf[18] = 'x'; + assert(!strcmpnul(libsimple_strntoupper(&buf[3], &buf[0], 15), "ABCDEABCDE12345x")); + assert(!strcmp(buf, "abcABCDEABCDE12345x")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_strntoupper(&buf[0], &buf[3], 12), "DEABCDE12345345")); + assert(!strcmp(buf, "DEABCDE12345345")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "abcdeABCDE12345x"); + assert(!strcmpnul(libsimple_strntoupper(&buf[0], &buf[0], 15), "ABCDEABCDE12345x")); + assert(!strcmp(buf, "ABCDEABCDE12345x")); + + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_stpntoupper(&buf[3], &buf[0], 0), "deABCDE12345")); + assert(!strcmp(buf, "abcdeABCDE12345")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_stpntoupper(&buf[0], &buf[3], 0), "abcdeABCDE12345")); + assert(!strcmp(buf, "abcdeABCDE12345")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_stpntoupper(&buf[0], &buf[0], 0), "abcdeABCDE12345")); + assert(!strcmp(buf, "abcdeABCDE12345")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_strntoupper(&buf[3], &buf[0], 0), "deABCDE12345")); + assert(!strcmp(buf, "abcdeABCDE12345")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_strntoupper(&buf[0], &buf[3], 0), "abcdeABCDE12345")); + assert(!strcmp(buf, "abcdeABCDE12345")); + memset(buf, 0, sizeof(buf)); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_strntoupper(&buf[0], &buf[0], 0), "abcdeABCDE12345")); + assert(!strcmp(buf, "abcdeABCDE12345")); + + return 0; +} + +#endif diff --git a/stptolower.c b/stptolower.c new file mode 100644 index 0000000..ce9dbf8 --- /dev/null +++ b/stptolower.c @@ -0,0 +1,61 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_stptolower(char *d, const char *s) /* TODO man */ +{ + size_t n; + char *ret; + if (d == s) { + for (; *d; d++) + *d = tolower(*d); + return d; + } else if (d < s) { + for (; *s; d++, s++) + *d = tolower(*s); + *d = '\0'; + return d; + } else { + for (n = 0; s[n]; n++); + ret = &d[n]; + do { + d[n] = tolower(s[n]); + } while (n--); + return ret; + } +} + + +#else +#include "test.h" + +int +main(void) +{ + char buf[100]; + + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_stptolower(&buf[3], &buf[0]), "")); + assert(!strcmp(buf, "ABCabcdeabcde12345")); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_stptolower(&buf[0], &buf[3]), "")); + assert(!strcmp(buf, "deabcde12345")); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_stptolower(&buf[0], &buf[0]), "")); + assert(!strcmp(buf, "abcdeabcde12345")); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_strtolower(&buf[3], &buf[0]), "abcdeabcde12345")); + assert(!strcmp(buf, "ABCabcdeabcde12345")); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_strtolower(&buf[0], &buf[3]), "deabcde12345")); + assert(!strcmp(buf, "deabcde12345")); + stpcpy(buf, "ABCDEabcde12345"); + assert(!strcmpnul(libsimple_strtolower(&buf[0], &buf[0]), "abcdeabcde12345")); + assert(!strcmp(buf, "abcdeabcde12345")); + + return 0; +} + +#endif diff --git a/stptoupper.c b/stptoupper.c new file mode 100644 index 0000000..fca38ce --- /dev/null +++ b/stptoupper.c @@ -0,0 +1,61 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_stptoupper(char *d, const char *s) /* TODO man */ +{ + size_t n; + char *ret; + if (d == s) { + for (; *d; d++) + *d = toupper(*d); + return d; + } else if (d < s) { + for (; *s; d++, s++) + *d = toupper(*s); + *d = '\0'; + return d; + } else { + for (n = 0; s[n]; n++); + ret = &d[n]; + do { + d[n] = toupper(s[n]); + } while (n--); + return ret; + } +} + + +#else +#include "test.h" + +int +main(void) +{ + char buf[100]; + + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_stptoupper(&buf[3], &buf[0]), "")); + assert(!strcmp(buf, "abcABCDEABCDE12345")); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_stptoupper(&buf[0], &buf[3]), "")); + assert(!strcmp(buf, "DEABCDE12345")); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_stptoupper(&buf[0], &buf[0]), "")); + assert(!strcmp(buf, "ABCDEABCDE12345")); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_strtoupper(&buf[3], &buf[0]), "ABCDEABCDE12345")); + assert(!strcmp(buf, "abcABCDEABCDE12345")); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_strtoupper(&buf[0], &buf[3]), "DEABCDE12345")); + assert(!strcmp(buf, "DEABCDE12345")); + stpcpy(buf, "abcdeABCDE12345"); + assert(!strcmpnul(libsimple_strtoupper(&buf[0], &buf[0]), "ABCDEABCDE12345")); + assert(!strcmp(buf, "ABCDEABCDE12345")); + + return 0; +} + +#endif diff --git a/strcasechr_inv.c b/strcasechr_inv.c new file mode 100644 index 0000000..c5ff521 --- /dev/null +++ b/strcasechr_inv.c @@ -0,0 +1,32 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_strcasechr_inv(const char *s_, int c) /* TODO man */ +{ + char *s = *(char **)(void *)&s_, lc = (char)tolower(c), uc = (char)toupper(c); + if (lc != uc) + for (; *s && (*s == lc || *s == uc); s++); + else + for (; *s && *s == lc; s++); + return *s ? s : NULL; +} + + +#else +#include "test.h" + +int +main(void) +{ + assert(!strcmpnul(libsimple_strcasechr_inv("xxoxx", 'x'), "oxx")); + assert(!strcmpnul(libsimple_strcasechr_inv("xxXxx", 'x'), NULL)); + assert(!strcmpnul(libsimple_strcasechr_inv("XXoxx", 'x'), "oxx")); + assert(!strcmpnul(libsimple_strcasechr_inv("zzzzz", 'z'), NULL)); + assert(!strcmpnul(libsimple_strcasechr_inv("", '\0'), NULL)); + return 0; +} + +#endif diff --git a/strcasechrnul_inv.c b/strcasechrnul_inv.c new file mode 100644 index 0000000..b2cbf56 --- /dev/null +++ b/strcasechrnul_inv.c @@ -0,0 +1,32 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_strcasechrnul_inv(const char *s_, int c) /* TODO man */ +{ + char *s = *(char **)(void *)&s_, lc = (char)tolower(c), uc = (char)toupper(c); + if (lc != uc) + for (; *s && (*s == lc || *s == uc); s++); + else + for (; *s && *s == lc; s++); + return s; +} + + +#else +#include "test.h" + +int +main(void) +{ + assert(!strcmpnul(libsimple_strcasechrnul_inv("xxoxx", 'x'), "oxx")); + assert(!strcmpnul(libsimple_strcasechrnul_inv("xxXxx", 'x'), "")); + assert(!strcmpnul(libsimple_strcasechrnul_inv("XXoxx", 'x'), "oxx")); + assert(!strcmpnul(libsimple_strcasechrnul_inv("zzzzz", 'z'), "")); + assert(!strcmpnul(libsimple_strcasechrnul_inv("", '\0'), "")); + return 0; +} + +#endif diff --git a/strchr_inv.c b/strchr_inv.c new file mode 100644 index 0000000..d9fecf6 --- /dev/null +++ b/strchr_inv.c @@ -0,0 +1,29 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_strchr_inv(const char *s_, int c_) /* TODO man */ +{ + char *s = *(char **)(void *)&s_, c = (char)c_; + for (; *s && *s == c; s++); + return *s ? s : NULL; +} + + +#else +#include "test.h" + +int +main(void) +{ + assert(!strcmpnul(libsimple_strchr_inv("xxoxx", 'x'), "oxx")); + assert(!strcmpnul(libsimple_strchr_inv("xxXxx", 'x'), "Xxx")); + assert(!strcmpnul(libsimple_strchr_inv("XXoxx", 'x'), "XXoxx")); + assert(!strcmpnul(libsimple_strchr_inv("zzzzz", 'z'), NULL)); + assert(!strcmpnul(libsimple_strchr_inv("", '\0'), NULL)); + return 0; +} + +#endif diff --git a/strchrnul_inv.c b/strchrnul_inv.c new file mode 100644 index 0000000..c045623 --- /dev/null +++ b/strchrnul_inv.c @@ -0,0 +1,29 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_strchrnul_inv(const char *s_, int c_) /* TODO man */ +{ + char *s = *(char **)(void *)&s_, c = (char)c_; + for (; *s && *s == c; s++); + return s; +} + + +#else +#include "test.h" + +int +main(void) +{ + assert(!strcmpnul(libsimple_strchrnul_inv("xxoxx", 'x'), "oxx")); + assert(!strcmpnul(libsimple_strchrnul_inv("xxXxx", 'x'), "Xxx")); + assert(!strcmpnul(libsimple_strchrnul_inv("XXoxx", 'x'), "XXoxx")); + assert(!strcmpnul(libsimple_strchrnul_inv("zzzzz", 'z'), "")); + assert(!strcmpnul(libsimple_strchrnul_inv("", '\0'), "")); + return 0; +} + +#endif diff --git a/strcmove.c b/strcmove.c new file mode 100644 index 0000000..2adc49d --- /dev/null +++ b/strcmove.c @@ -0,0 +1,39 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_strcmove(char *d, const char *s, int c_) /* TODO test, man */ +{ + char c = (char)c_, *p; + size_t n; + if (d < s) { + do { + if ((*d++ = *s) == c) + return d; + } while (*s++); + } else { + for (p = *(char **)(void *)&s;; p++) { + if (*p == c || *p) { + n = (size_t)(p - s); + p = &d[n]; + do { d[n] = s[n]; } while (n--); + return *p == c ? &p[1] : NULL; + } + } + } + return NULL; +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/strncasechr_inv.c b/strncasechr_inv.c new file mode 100644 index 0000000..e6c0581 --- /dev/null +++ b/strncasechr_inv.c @@ -0,0 +1,55 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_strncasechr_inv(const char *s_, int c, size_t n) /* TODO man */ +{ + char *s = *(char **)(void *)&s_; + char *end = &s[n]; + c = tolower(c); + for (; s != end && *s && tolower(*s) == c; s++); + return (s == end || !*s || tolower(*s) == c) ? NULL : s; +} + + +#else +#include "test.h" + +int +main(void) +{ + assert(!strcmpnul(libsimple_strncasechr_inv("xxoxx", 'x', SIZE_MAX), "oxx")); + assert(!strcmpnul(libsimple_strncasechr_inv("xxXxx", 'x', SIZE_MAX), NULL)); + assert(!strcmpnul(libsimple_strncasechr_inv("XXoxx", 'x', SIZE_MAX), "oxx")); + assert(!strcmpnul(libsimple_strncasechr_inv("zzzzz", 'z', SIZE_MAX), NULL)); + assert(!strcmpnul(libsimple_strncasechr_inv("", '\0', SIZE_MAX), NULL)); + + assert(!strcmpnul(libsimple_strncasechr_inv("xxoxx", 'x', 6), "oxx")); + assert(!strcmpnul(libsimple_strncasechr_inv("xxXxx", 'x', 6), NULL)); + assert(!strcmpnul(libsimple_strncasechr_inv("XXoxx", 'x', 6), "oxx")); + assert(!strcmpnul(libsimple_strncasechr_inv("zzzzz", 'z', 6), NULL)); + assert(!strcmpnul(libsimple_strncasechr_inv("", '\0', 6), NULL)); + + assert(!strcmpnul(libsimple_strncasechr_inv("xxoxx", 'x', 5), "oxx")); + assert(!strcmpnul(libsimple_strncasechr_inv("xxXxx", 'x', 5), NULL)); + assert(!strcmpnul(libsimple_strncasechr_inv("XXoxx", 'x', 5), "oxx")); + assert(!strcmpnul(libsimple_strncasechr_inv("zzzzz", 'z', 5), NULL)); + assert(!strcmpnul(libsimple_strncasechr_inv("", '\0', 5), NULL)); + + assert(!strcmpnul(libsimple_strncasechr_inv("xxoxx", 'x', 3), "oxx")); + assert(!strcmpnul(libsimple_strncasechr_inv("xxXxx", 'x', 3), NULL)); + assert(!strcmpnul(libsimple_strncasechr_inv("XXoxx", 'x', 3), "oxx")); + assert(!strcmpnul(libsimple_strncasechr_inv("zzzzz", 'z', 3), NULL)); + assert(!strcmpnul(libsimple_strncasechr_inv("", '\0', 3), NULL)); + + assert(!strcmpnul(libsimple_strncasechr_inv("xxoxx", 'x', 2), NULL)); + assert(!strcmpnul(libsimple_strncasechr_inv("xxXxx", 'x', 2), NULL)); + assert(!strcmpnul(libsimple_strncasechr_inv("XXoxx", 'x', 2), NULL)); + assert(!strcmpnul(libsimple_strncasechr_inv("zzzzz", 'z', 2), NULL)); + assert(!strcmpnul(libsimple_strncasechr_inv("", '\0', 2), NULL)); + return 0; +} + +#endif diff --git a/strncasechrnul_inv.c b/strncasechrnul_inv.c new file mode 100644 index 0000000..bcf8eaa --- /dev/null +++ b/strncasechrnul_inv.c @@ -0,0 +1,55 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_strncasechrnul_inv(const char *s_, int c, size_t n) /* TODO man */ +{ + char *s = *(char **)(void *)&s_; + char *end = &s[n]; + c = tolower(c); + for (; s != end && *s && tolower(*s) == c; s++); + return s; +} + + +#else +#include "test.h" + +int +main(void) +{ + assert(!strcmpnul(libsimple_strncasechrnul_inv("xxoxx", 'x', SIZE_MAX), "oxx")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("xxXxx", 'x', SIZE_MAX), "")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("XXoxx", 'x', SIZE_MAX), "oxx")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("zzzzz", 'z', SIZE_MAX), "")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("", '\0', SIZE_MAX), "")); + + assert(!strcmpnul(libsimple_strncasechrnul_inv("xxoxx", 'x', 6), "oxx")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("xxXxx", 'x', 6), "")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("XXoxx", 'x', 6), "oxx")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("zzzzz", 'z', 6), "")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("", '\0', 6), "")); + + assert(!strcmpnul(libsimple_strncasechrnul_inv("xxoxx", 'x', 5), "oxx")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("xxXxx", 'x', 5), "")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("XXoxx", 'x', 5), "oxx")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("zzzzz", 'z', 5), "")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("", '\0', 5), "")); + + assert(!strcmpnul(libsimple_strncasechrnul_inv("xxoxx", 'x', 3), "oxx")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("xxXxx", 'x', 3), "xx")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("XXoxx", 'x', 3), "oxx")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("zzzzz", 'z', 3), "zz")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("", '\0', 3), "")); + + assert(!strcmpnul(libsimple_strncasechrnul_inv("xxoxx", 'x', 2), "oxx")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("xxXxx", 'x', 2), "Xxx")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("XXoxx", 'x', 2), "oxx")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("zzzzz", 'z', 2), "zzz")); + assert(!strcmpnul(libsimple_strncasechrnul_inv("", '\0', 2), "")); + return 0; +} + +#endif diff --git a/strnchr_inv.c b/strnchr_inv.c new file mode 100644 index 0000000..3dd3c43 --- /dev/null +++ b/strnchr_inv.c @@ -0,0 +1,54 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_strnchr_inv(const char *s_, int c_, size_t n) /* TODO man */ +{ + char *s = *(char **)(void *)&s_, c = (char)c_; + char *end = &s[n]; + for (; s != end && *s && *s == c; s++); + return (s == end || !*s || *s == c) ? NULL : s; +} + + +#else +#include "test.h" + +int +main(void) +{ + assert(!strcmpnul(libsimple_strnchr_inv("xxoxx", 'x', SIZE_MAX), "oxx")); + assert(!strcmpnul(libsimple_strnchr_inv("xxXxx", 'x', SIZE_MAX), "Xxx")); + assert(!strcmpnul(libsimple_strnchr_inv("XXoxx", 'x', SIZE_MAX), "XXoxx")); + assert(!strcmpnul(libsimple_strnchr_inv("zzzzz", 'z', SIZE_MAX), NULL)); + assert(!strcmpnul(libsimple_strnchr_inv("", '\0', SIZE_MAX), NULL)); + + assert(!strcmpnul(libsimple_strnchr_inv("xxoxx", 'x', 6), "oxx")); + assert(!strcmpnul(libsimple_strnchr_inv("xxXxx", 'x', 6), "Xxx")); + assert(!strcmpnul(libsimple_strnchr_inv("XXoxx", 'x', 6), "XXoxx")); + assert(!strcmpnul(libsimple_strnchr_inv("zzzzz", 'z', 6), NULL)); + assert(!strcmpnul(libsimple_strnchr_inv("", '\0', 6), NULL)); + + assert(!strcmpnul(libsimple_strnchr_inv("xxoxx", 'x', 5), "oxx")); + assert(!strcmpnul(libsimple_strnchr_inv("xxXxx", 'x', 5), "Xxx")); + assert(!strcmpnul(libsimple_strnchr_inv("XXoxx", 'x', 5), "XXoxx")); + assert(!strcmpnul(libsimple_strnchr_inv("zzzzz", 'z', 5), NULL)); + assert(!strcmpnul(libsimple_strnchr_inv("", '\0', 5), NULL)); + + assert(!strcmpnul(libsimple_strnchr_inv("xxoxx", 'x', 3), "oxx")); + assert(!strcmpnul(libsimple_strnchr_inv("xxXxx", 'x', 3), "Xxx")); + assert(!strcmpnul(libsimple_strnchr_inv("XXoxx", 'x', 3), "XXoxx")); + assert(!strcmpnul(libsimple_strnchr_inv("zzzzz", 'z', 3), NULL)); + assert(!strcmpnul(libsimple_strnchr_inv("", '\0', 3), NULL)); + + assert(!strcmpnul(libsimple_strnchr_inv("xxoxx", 'x', 2), NULL)); + assert(!strcmpnul(libsimple_strnchr_inv("xxXxx", 'x', 2), NULL)); + assert(!strcmpnul(libsimple_strnchr_inv("XXoxx", 'x', 2), "XXoxx")); + assert(!strcmpnul(libsimple_strnchr_inv("zzzzz", 'z', 2), NULL)); + assert(!strcmpnul(libsimple_strnchr_inv("", '\0', 2), NULL)); + return 0; +} + +#endif diff --git a/strnchrnul_inv.c b/strnchrnul_inv.c new file mode 100644 index 0000000..142b9c7 --- /dev/null +++ b/strnchrnul_inv.c @@ -0,0 +1,54 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_strnchrnul_inv(const char *s_, int c_, size_t n) /* TODO man */ +{ + char *s = *(char **)(void *)&s_, c = (char)c_; + char *end = &s[n]; + for (; s != end && *s && *s == c; s++); + return s; +} + + +#else +#include "test.h" + +int +main(void) +{ + assert(!strcmpnul(libsimple_strnchrnul_inv("xxoxx", 'x', SIZE_MAX), "oxx")); + assert(!strcmpnul(libsimple_strnchrnul_inv("xxXxx", 'x', SIZE_MAX), "Xxx")); + assert(!strcmpnul(libsimple_strnchrnul_inv("XXoxx", 'x', SIZE_MAX), "XXoxx")); + assert(!strcmpnul(libsimple_strnchrnul_inv("zzzzz", 'z', SIZE_MAX), "")); + assert(!strcmpnul(libsimple_strnchrnul_inv("", '\0', SIZE_MAX), "")); + + assert(!strcmpnul(libsimple_strnchrnul_inv("xxoxx", 'x', 6), "oxx")); + assert(!strcmpnul(libsimple_strnchrnul_inv("xxXxx", 'x', 6), "Xxx")); + assert(!strcmpnul(libsimple_strnchrnul_inv("XXoxx", 'x', 6), "XXoxx")); + assert(!strcmpnul(libsimple_strnchrnul_inv("zzzzz", 'z', 6), "")); + assert(!strcmpnul(libsimple_strnchrnul_inv("", '\0', 6), "")); + + assert(!strcmpnul(libsimple_strnchrnul_inv("xxoxx", 'x', 5), "oxx")); + assert(!strcmpnul(libsimple_strnchrnul_inv("xxXxx", 'x', 5), "Xxx")); + assert(!strcmpnul(libsimple_strnchrnul_inv("XXoxx", 'x', 5), "XXoxx")); + assert(!strcmpnul(libsimple_strnchrnul_inv("zzzzz", 'z', 5), "")); + assert(!strcmpnul(libsimple_strnchrnul_inv("", '\0', 5), "")); + + assert(!strcmpnul(libsimple_strnchrnul_inv("xxoxx", 'x', 3), "oxx")); + assert(!strcmpnul(libsimple_strnchrnul_inv("xxXxx", 'x', 3), "Xxx")); + assert(!strcmpnul(libsimple_strnchrnul_inv("XXoxx", 'x', 3), "XXoxx")); + assert(!strcmpnul(libsimple_strnchrnul_inv("zzzzz", 'z', 3), "zz")); + assert(!strcmpnul(libsimple_strnchrnul_inv("", '\0', 3), "")); + + assert(!strcmpnul(libsimple_strnchrnul_inv("xxoxx", 'x', 2), "oxx")); + assert(!strcmpnul(libsimple_strnchrnul_inv("xxXxx", 'x', 2), "Xxx")); + assert(!strcmpnul(libsimple_strnchrnul_inv("XXoxx", 'x', 2), "XXoxx")); + assert(!strcmpnul(libsimple_strnchrnul_inv("zzzzz", 'z', 2), "zzz")); + assert(!strcmpnul(libsimple_strnchrnul_inv("", '\0', 2), "")); + return 0; +} + +#endif diff --git a/strncmove.c b/strncmove.c new file mode 100644 index 0000000..ce53ed5 --- /dev/null +++ b/strncmove.c @@ -0,0 +1,42 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_strncmove(char *d, const char *s, int c_, size_t n) /* TODO test, man */ +{ + char c = (char)c_, *p; + if (d < s) { + do { + if ((*d++ = *s) == c) + return d; + } while (*s++ && n--); + } else { + for (p = *(char **)(void *)&s; n; n--, p++) { + if (*p == c || *p) { + n = (size_t)(p - s); + p = &d[n]; + do { d[n] = s[n]; } while (n--); + return *p == c ? &p[1] : NULL; + } + } + for (n = (size_t)(p - s); n;) { + n--; + d[n] = s[n]; + } + } + return NULL; +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/strrcasechr_inv.c b/strrcasechr_inv.c new file mode 100644 index 0000000..fea9f21 --- /dev/null +++ b/strrcasechr_inv.c @@ -0,0 +1,32 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_strrcasechr_inv(const char *s_, int c) /* TODO test, man */ +{ + char *s = *(char **)(void *)&s_, lc = (char)tolower(c), uc = (char)toupper(c), *r = NULL; + if (lc != uc) { + for (; *s; s++) + if (*s != lc && *s != uc) + r = s; + } else { + for (; *s; s++) + if (*s != lc) + r = s; + } + return r; +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/strrchr_inv.c b/strrchr_inv.c new file mode 100644 index 0000000..2b57fdf --- /dev/null +++ b/strrchr_inv.c @@ -0,0 +1,26 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_strrchr_inv(const char *s_, int c_) /* TODO test, man */ +{ + char *s = *(char **)(void *)&s_, c = (char)c_, *r = NULL; + for (; *s; s++) + if (*s != c) + r = s; + return r; +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/strrncasechr_inv.c b/strrncasechr_inv.c new file mode 100644 index 0000000..c300c43 --- /dev/null +++ b/strrncasechr_inv.c @@ -0,0 +1,31 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_strrncasechr_inv(const char *s_, int c, size_t n) /* TODO test, man */ +{ + char *s = *(char **)(void *)&s_; + char *end = &s[n], *r = NULL; + c = tolower(c); + for (; s != end; s++) { + if (tolower(*s) != c) + r = s; + if (!*s) + break; + } + return r; +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/strrnchr_inv.c b/strrnchr_inv.c new file mode 100644 index 0000000..8ab9965 --- /dev/null +++ b/strrnchr_inv.c @@ -0,0 +1,30 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +char * +libsimple_strrnchr_inv(const char *s_, int c_, size_t n) /* TODO test, man */ +{ + char *s = *(char **)(void *)&s_, c = (char)c_; + char *end = &s[n], *r = NULL; + for (; s != end; s++) { + if (*s != c) + r = s; + if (!*s) + break; + } + return r; +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/strtotimespec.c b/strtotimespec.c index 9c6a6e0..d6bd64c 100644 --- a/strtotimespec.c +++ b/strtotimespec.c @@ -43,12 +43,10 @@ libsimple_strtotimespec(struct timespec *restrict ts, const char *restrict s, ch } for (; isdigit(*s); s++) { - if (sec < TIME_MIN / 10) + if (LIBSIMPLE_SMUL_OVERFLOW_AN_BP(sec, 10, &sec, TIME_MIN, TIME_MAX)) goto overflow_integer; - sec *= 10; - if (sec < TIME_MIN + (*s & 15)) + if (LIBSIMPLE_SSUB_OVERFLOW_B_POS(sec, (time_t)(*s & 15), &sec, TIME_MIN, TIME_MAX)) goto overflow_integer; - sec -= *s & 15; } if (!neg) { diff --git a/sumtimespec.c b/sumtimespec.c index a359971..2b2e935 100644 --- a/sumtimespec.c +++ b/sumtimespec.c @@ -6,48 +6,36 @@ int libsimple_sumtimespec(struct timespec *sum, const struct timespec *augend, const struct timespec *addend) { - long int ns = augend->tv_nsec + addend->tv_nsec; time_t s; - int ret = 0; - - s = augend->tv_sec + addend->tv_sec; - if ((augend->tv_sec < 0) == (addend->tv_sec < 0)) { - if (augend->tv_sec >= 0 && augend->tv_sec > TIME_MAX - addend->tv_sec) { - s = TIME_MAX; - ns = 999999999L; - errno = ERANGE; - ret = -1; - } else if (augend->tv_sec < 0 && augend->tv_sec < TIME_MIN - addend->tv_sec) { - s = TIME_MIN; - ns = 0; - errno = ERANGE; - ret = -1; - } + + if (LIBSIMPLE_SADD_OVERFLOW(augend->tv_sec, addend->tv_sec, &s, TIME_MIN, TIME_MAX)) { + if (addend->tv_sec > 0) + goto too_large; + else + goto too_small; } - if (ns < 0) { - if (s == TIME_MIN) { - ns = 0L; - errno = ERANGE; - ret = -1; - } else { - s -= 1; - ns += 1000000000L; - } - } else if (ns >= 1000000000L) { - if (s == TIME_MAX) { - ns = 999999999L; - errno = ERANGE; - ret = -1; - } else { - s += 1; - ns -= 1000000000L; - } + sum->tv_nsec = augend->tv_nsec + addend->tv_nsec; + if (sum->tv_nsec >= 1000000000L) { + if (LIBSIMPLE_SINCR_OVERFLOW(&s, TIME_MAX)) + goto too_large; + sum->tv_nsec -= 1000000000L; } sum->tv_sec = s; - sum->tv_nsec = ns; - return ret; + return 0; + +too_large: + sum->tv_sec = TIME_MAX; + sum->tv_nsec = 999999999L; + errno = ERANGE; + return -1; + +too_small: + sum->tv_sec = TIME_MIN; + sum->tv_nsec = 0; + errno = ERANGE; + return -1; } diff --git a/sumtimeval.c b/sumtimeval.c index 47ef705..e52d58f 100644 --- a/sumtimeval.c +++ b/sumtimeval.c @@ -6,16 +6,36 @@ int libsimple_sumtimeval(struct timeval *sum, const struct timeval *augend, const struct timeval *addend) { - struct timespec a, b, s; - int r; - libsimple_timeval2timespec(&a, augend); - libsimple_timeval2timespec(&b, addend); - r = libsimple_sumtimespec(&s, &a, &b); - if (r && errno != ERANGE) - return r; - if (libsimple_timespec2timeval(sum, &s) && r) - errno = ERANGE; - return r; + time_t s; + + if (LIBSIMPLE_SADD_OVERFLOW(augend->tv_sec, addend->tv_sec, &s, TIME_MIN, TIME_MAX)) { + if (addend->tv_sec > 0) + goto too_large; + else + goto too_small; + } + + sum->tv_usec = augend->tv_usec + addend->tv_usec; + if (sum->tv_usec >= 1000000L) { + if (LIBSIMPLE_SINCR_OVERFLOW(&s, TIME_MAX)) + goto too_large; + sum->tv_usec -= 1000000L; + } + + sum->tv_sec = s; + return 0; + +too_large: + sum->tv_sec = TIME_MAX; + sum->tv_usec = 999999L; + errno = ERANGE; + return -1; + +too_small: + sum->tv_sec = TIME_MIN; + sum->tv_usec = 0; + errno = ERANGE; + return -1; } diff --git a/timespec2timeval.c b/timespec2timeval.c index 92c9b3e..e71585a 100644 --- a/timespec2timeval.c +++ b/timespec2timeval.c @@ -10,14 +10,13 @@ libsimple_timespec2timeval(struct timeval *restrict tv, const struct timespec *r tv->tv_usec = ts->tv_nsec / 1000L; if ((ts->tv_nsec % 1000L) >= 500L) { if (++(tv->tv_usec) == 1000000L) { - tv->tv_usec = 0; - if (tv->tv_sec == TIME_MAX) { + if (LIBSIMPLE_SINCR_OVERFLOW(&tv->tv_sec, TIME_MAX)) { + tv->tv_sec = TIME_MAX; tv->tv_usec = 999999L; errno = EOVERFLOW; return -1; - } else { - tv->tv_sec += 1; } + tv->tv_usec = 0; } } return 0; diff --git a/vmemalloc.c b/vmemalloc.c index 0f26cbc..b4e4ed9 100644 --- a/vmemalloc.c +++ b/vmemalloc.c @@ -24,15 +24,14 @@ vmemalloc_parse_size_prod(struct memalloc_state *state, size_t n, size_t arg, va goto inval; state->elem_size = arg; if (n) { - for (n--; n--;) { + while (--n) { arg = va_arg(ap, size_t); if (!state->elem_size) continue; - if (arg > SIZE_MAX / state->elem_size) { + if (LIBSIMPLE_UMUL_OVERFLOW_NONZERO(arg, state->elem_size, &state->elem_size, SIZE_MAX)) { errno = ENOMEM; return -1; } - state->elem_size *= arg; } } else { if (!arg) @@ -41,11 +40,10 @@ vmemalloc_parse_size_prod(struct memalloc_state *state, size_t n, size_t arg, va arg = va_arg(ap, size_t); if (!arg) break; - if (arg > SIZE_MAX / state->elem_size) { + if (LIBSIMPLE_UMUL_OVERFLOW_NONZERO(arg, state->elem_size, &state->elem_size, SIZE_MAX)) { errno = ENOMEM; return -1; } - state->elem_size *= arg; } } @@ -207,11 +205,10 @@ libsimple_vmemalloc(size_t n, va_list ap) /* TODO test ([v]{mem,array}alloc) */ state.zero_init = state.zero_init >= 0 ? state.zero_init : 0; n = state.have_size ? state.size_prod : n; if (state.elem_size > 1) { - if (n > SIZE_MAX / state.elem_size) { + if (LIBSIMPLE_UMUL_OVERFLOW_NONZERO(n, state.elem_size, &n, SIZE_MAX)) { errno = ENOMEM; return NULL; } - n *= state.elem_size; } if (state.round_up_size) { if (!state.alignment) { @@ -240,11 +237,10 @@ libsimple_vmemalloc(size_t n, va_list ap) /* TODO test ([v]{mem,array}alloc) */ min = MIN(state.alignment, cacheline); max = MAX(state.alignment, cacheline); size = max / gcd(state.alignment, cacheline); - if (size > SIZE_MAX / min) { + if (LIBSIMPLE_UMUL_OVERFLOW_NONZERO(size, min, &state.alignment, SIZE_MAX)) { errno = ENOMEM; return NULL; } - state.alignment = size = min; } } else if (!state.cache_split) { if (!state.alignment) -- cgit v1.2.3-70-g09d2