aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2018-11-19 21:39:11 +0100
committerMattias Andrée <maandree@kth.se>2018-11-19 21:39:11 +0100
commite8a7e1c358caec60751460d337f634ff6957ff9d (patch)
treeb0fe92173edbf210d2890ecd35141cc39decf8dc
parentAdd memelemscan (diff)
downloadlibsimple-e8a7e1c358caec60751460d337f634ff6957ff9d.tar.gz
libsimple-e8a7e1c358caec60751460d337f634ff6957ff9d.tar.bz2
libsimple-e8a7e1c358caec60751460d337f634ff6957ff9d.tar.xz
Add a bunch of function and macros
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to '')
-rw-r--r--Makefile78
-rw-r--r--README66
-rw-r--r--difftimespec.c60
-rw-r--r--difftimeval.c40
-rw-r--r--libsimple.h2
-rw-r--r--libsimple/mem.h571
-rw-r--r--libsimple/overflow.h406
-rw-r--r--libsimple/str.h287
-rw-r--r--libsimple/strn.h314
-rw-r--r--man3/libsimple_difftimespec.39
-rw-r--r--man3/libsimple_multimespec.37
-rw-r--r--man3/libsimple_sumtimespec.39
-rw-r--r--memcasechr_inv.c31
-rw-r--r--memcasescan_inv.c31
-rw-r--r--memchr_inv.c30
-rw-r--r--memcmove.c42
-rw-r--r--memelem.c5
-rw-r--r--memelem_inv.c68
-rw-r--r--memelemscan.c7
-rw-r--r--memelemscan_inv.c60
-rw-r--r--memptolower.c60
-rw-r--r--memptoupper.c60
-rw-r--r--memrcasechr_inv.c26
-rw-r--r--memrchr_inv.c25
-rw-r--r--memrelem.c5
-rw-r--r--memrelem_inv.c76
-rw-r--r--memreplaceelem.c83
-rw-r--r--memscan_inv.c30
-rw-r--r--multimespec.c6
-rw-r--r--rawmemcasechr_inv.c27
-rw-r--r--rawmemchr_inv.c27
-rw-r--r--rawmemelem.c68
-rw-r--r--rawmemelem_inv.c58
-rw-r--r--rawmemrcasechr_inv.c25
-rw-r--r--rawmemrchr_inv.c24
-rw-r--r--rawmemrelem.c74
-rw-r--r--rawmemrelem_inv.c65
-rw-r--r--stpntolower.c115
-rw-r--r--stpntoupper.c115
-rw-r--r--stptolower.c61
-rw-r--r--stptoupper.c61
-rw-r--r--strcasechr_inv.c32
-rw-r--r--strcasechrnul_inv.c32
-rw-r--r--strchr_inv.c29
-rw-r--r--strchrnul_inv.c29
-rw-r--r--strcmove.c39
-rw-r--r--strncasechr_inv.c55
-rw-r--r--strncasechrnul_inv.c55
-rw-r--r--strnchr_inv.c54
-rw-r--r--strnchrnul_inv.c54
-rw-r--r--strncmove.c42
-rw-r--r--strrcasechr_inv.c32
-rw-r--r--strrchr_inv.c26
-rw-r--r--strrncasechr_inv.c31
-rw-r--r--strrnchr_inv.c30
-rw-r--r--strtotimespec.c6
-rw-r--r--sumtimespec.c60
-rw-r--r--sumtimeval.c40
-rw-r--r--timespec2timeval.c7
-rw-r--r--vmemalloc.c14
60 files changed, 3715 insertions, 166 deletions
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 <string.h>
+and <strings.h>, the naming scheme of these functions is:
+
+ <base> = 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> = str if <base> is str, wsc, strn, or wscn
+ = mem if <base> is mem or wmem
+
+ <scan> = chrnul if <base> is str, wsc, strn, or wscn
+ = scan if <base> 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 <base> = mem, wmem)
+
+ <base>[r] = strrn if <base> is strn
+ = wcsrn if <base> is wcsn
+ = <base>r otherwise
+
+ <base>[p] = stp if <base> is str
+ = stpn if <base> is strn
+ = wcp if <base> is wcs
+ = wcpn if <base> is wcsn
+ = <base>p otherwise
+
+ [raw]<base>[r][case]chr[_inv] find character
+ <base>[case]<scan>[_inv] find character or end
+ <base>[r][case]<str> find substring
+ <base>[case]cmp alphabetically compare, without NULL support
+ <base>[case]cmpnul alphabetically compare, with NULL support
+ <base>[case]ends verify end
+ <base>[case]starts verify beginning
+ <base>[case]eq !<base>[case]cmp
+ <base>[case]eqnul !<base>[case]cmpnul
+ <base>[r][case]eqlen check length of commonality
+ <base>end find end of string (not <base> = mem, wmem)
+ <base>[p]cpy copy data (to external array)
+ <base>[p]move move data (within array or to external array)
+ <base>[p]set fill data
+ <base>[p]toupper like <base>[p]move but convert text to upper case
+ <base>[p]tolower like <base>[p]move but convert text to lower case
+ [raw]<base>ccpy like <base>pcpy, but stop after a character is found
+ [raw]<base>cmove like <base>pmove, but stop after a character is found
+ <base>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 <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
+#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <sys/socket.h>
@@ -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
@@ -178,6 +178,200 @@ void *libsimple_rawmemrcasechr(const void *, int, size_t);
/**
+ * 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
*
* @param haystack The array of bytes to search
@@ -271,6 +465,28 @@ void *libsimple_memelem(const void *, size_t, const void *, size_t);
/**
* 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
+ *
* @param haystack The array of bytes to search
* @param nhaystack The length of `haystack`, divided by `needle`
* @param needle The substring to search for
@@ -308,6 +524,137 @@ void *libsimple_memrelem(const void *, size_t, const void *, size_t);
/**
+ * 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
*
* @param s The array of bytes to check
@@ -497,6 +844,206 @@ static inline void *libsimple_memsetelem(void *__buf, const void *__item, size_t
/**
+ * 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
*
* @param a One of the arrays
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
*/
@@ -62,6 +62,102 @@ char *libsimple_strrcasechr(const char *, int);
/**
+ * 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
*
* @param s The string
@@ -407,6 +503,189 @@ static inline char *libsimple_stpmove(char *__d, const char *__s) /* TODO test *
/**
+ * 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
*
* @param string The string
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
@@ -102,6 +103,112 @@ char *libsimple_strrncasechr(const char *, int, size_t);
/**
+ * 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
*
* @param s The string
@@ -468,6 +575,199 @@ libsimple_stpnmove(char *__d, const char *__s, size_t __n) /* TODO test */
/**
+ * 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)