diff --git a/src/crypt_openssl.c b/src/crypt_openssl.c
index 7d757f6..3bec272 100644
--- a/src/crypt_openssl.c
+++ b/src/crypt_openssl.c
@@ -48,7 +48,7 @@ NTLM_INLINE(void) HMAC_CTX_free(HMAC_CTX *ctx)
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x03050000fL) || \
defined(CRYPT_OPENSSL_DYNAMIC)
-static inline void HMAC_CTX_cleanup(HMAC_CTX *ctx)
+NTLM_INLINE(void) HMAC_CTX_cleanup(HMAC_CTX *ctx)
{
NTLM_UNUSED(ctx);
}
diff --git a/src/utf8.h b/src/utf8.h
index dd0bce8..495e259 100644
--- a/src/utf8.h
+++ b/src/utf8.h
@@ -1,8 +1,7 @@
-/*
- * The latest version of this library is available on GitHub;
- * https://github.com/sheredom/utf8.h
- *
- * This is free and unencumbered software released into the public domain.
+/* The latest version of this library is available on GitHub;
+ * https://github.com/sheredom/utf8.h */
+
+/* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
@@ -25,8 +24,7 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
- * For more information, please refer to
- */
+ * For more information, please refer to */
#ifndef SHEREDOM_UTF8_H_INCLUDED
#define SHEREDOM_UTF8_H_INCLUDED
@@ -34,10 +32,25 @@
#if defined(_MSC_VER)
#pragma warning(push)
-// disable 'bytes padding added after construct' warning
+/* disable warning: no function prototype given: converting '()' to '(void)' */
+#pragma warning(disable : 4255)
+
+/* disable warning: '__cplusplus' is not defined as a preprocessor macro,
+ * replacing with '0' for '#if/#elif' */
+#pragma warning(disable : 4668)
+
+/* disable warning: bytes padding added after construct */
#pragma warning(disable : 4820)
#endif
+#if defined(__cplusplus)
+#if defined(_MSC_VER)
+#define utf8_cplusplus _MSVC_LANG
+#else
+#define utf8_cplusplus __cplusplus
+#endif
+#endif
+
#include
#include
@@ -45,7 +58,7 @@
#pragma warning(pop)
#endif
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && (_MSC_VER < 1920)
typedef __int32 utf8_int32_t;
#else
#include
@@ -56,411 +69,516 @@ typedef int32_t utf8_int32_t;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wold-style-cast"
#pragma clang diagnostic ignored "-Wcast-qual"
+
+#if __has_warning("-Wunsafe-buffer-usage")
+#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
+#endif
#endif
-#ifdef __cplusplus
+#ifdef utf8_cplusplus
extern "C" {
#endif
-#if defined(__clang__) || defined(__GNUC__)
-#define utf8_nonnull __attribute__((nonnull))
-#define utf8_pure __attribute__((pure))
-#define utf8_restrict __restrict__
-#define utf8_weak __attribute__((weak))
-#elif defined(_MSC_VER)
+#if defined(__TINYC__)
+#define UTF8_ATTRIBUTE(a) __attribute((a))
+#else
+#define UTF8_ATTRIBUTE(a) __attribute__((a))
+#endif
+
+#if defined(_MSC_VER)
#define utf8_nonnull
#define utf8_pure
#define utf8_restrict __restrict
#define utf8_weak __inline
+#elif defined(__clang__) || defined(__GNUC__)
+#define utf8_nonnull UTF8_ATTRIBUTE(nonnull)
+#define utf8_pure UTF8_ATTRIBUTE(pure)
+#define utf8_restrict __restrict__
+#define utf8_weak UTF8_ATTRIBUTE(weak)
+#elif defined(__TINYC__)
+#define utf8_nonnull UTF8_ATTRIBUTE(nonnull)
+#define utf8_pure UTF8_ATTRIBUTE(pure)
+#define utf8_restrict
+#define utf8_weak UTF8_ATTRIBUTE(weak)
#else
-#error Non clang, non gcc, non MSVC compiler found!
+#error Non clang, non gcc, non MSVC, non tcc compiler found!
#endif
-#ifdef __cplusplus
+#ifdef utf8_cplusplus
#define utf8_null NULL
#else
#define utf8_null 0
#endif
-// Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 >
-// src2 respectively, case insensitive.
-utf8_nonnull utf8_pure utf8_weak int utf8casecmp(const void *src1,
- const void *src2);
-
-// Append the utf8 string src onto the utf8 string dst.
-utf8_nonnull utf8_weak void *utf8cat(void *utf8_restrict dst,
- const void *utf8_restrict src);
-
-// Find the first match of the utf8 codepoint chr in the utf8 string src.
-utf8_nonnull utf8_pure utf8_weak void *utf8chr(const void *src,
- utf8_int32_t chr);
-
-// Return less than 0, 0, greater than 0 if src1 < src2,
-// src1 == src2, src1 > src2 respectively.
-utf8_nonnull utf8_pure utf8_weak int utf8cmp(const void *src1,
- const void *src2);
-
-// Copy the utf8 string src onto the memory allocated in dst.
-utf8_nonnull utf8_weak void *utf8cpy(void *utf8_restrict dst,
- const void *utf8_restrict src);
-
-// Number of utf8 codepoints in the utf8 string src that consists entirely
-// of utf8 codepoints not from the utf8 string reject.
-utf8_nonnull utf8_pure utf8_weak size_t utf8cspn(const void *src,
- const void *reject);
-
-// Duplicate the utf8 string src by getting its size, malloc'ing a new buffer
-// copying over the data, and returning that. Or 0 if malloc failed.
-utf8_nonnull utf8_weak void *utf8dup(const void *src);
-
-// Number of utf8 codepoints in the utf8 string str,
-// excluding the null terminating byte.
-utf8_nonnull utf8_pure utf8_weak size_t utf8len(const void *str);
-
-// Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 >
-// src2 respectively, case insensitive. Checking at most n bytes of each utf8
-// string.
-utf8_nonnull utf8_pure utf8_weak int utf8ncasecmp(const void *src1,
- const void *src2, size_t n);
-
-// Append the utf8 string src onto the utf8 string dst,
-// writing at most n+1 bytes. Can produce an invalid utf8
-// string if n falls partway through a utf8 codepoint.
-utf8_nonnull utf8_weak void *utf8ncat(void *utf8_restrict dst,
- const void *utf8_restrict src, size_t n);
-
-// Return less than 0, 0, greater than 0 if src1 < src2,
-// src1 == src2, src1 > src2 respectively. Checking at most n
-// bytes of each utf8 string.
-utf8_nonnull utf8_pure utf8_weak int utf8ncmp(const void *src1,
- const void *src2, size_t n);
-
-// Copy the utf8 string src onto the memory allocated in dst.
-// Copies at most n bytes. If there is no terminating null byte in
-// the first n bytes of src, the string placed into dst will not be
-// null-terminated. If the size (in bytes) of src is less than n,
-// extra null terminating bytes are appended to dst such that at
-// total of n bytes are written. Can produce an invalid utf8
-// string if n falls partway through a utf8 codepoint.
-utf8_nonnull utf8_weak void *utf8ncpy(void *utf8_restrict dst,
- const void *utf8_restrict src, size_t n);
-
-// Similar to utf8dup, except that at most n bytes of src are copied. If src is
-// longer than n, only n bytes are copied and a null byte is added.
-//
-// Returns a new string if successful, 0 otherwise
-utf8_nonnull utf8_weak void *utf8ndup(const void *src, size_t n);
-
-// Locates the first occurence in the utf8 string str of any byte in the
-// utf8 string accept, or 0 if no match was found.
-utf8_nonnull utf8_pure utf8_weak void *utf8pbrk(const void *str,
- const void *accept);
-
-// Find the last match of the utf8 codepoint chr in the utf8 string src.
-utf8_nonnull utf8_pure utf8_weak void *utf8rchr(const void *src, int chr);
-
-// Number of bytes in the utf8 string str,
-// including the null terminating byte.
-utf8_nonnull utf8_pure utf8_weak size_t utf8size(const void *str);
-
-// Number of utf8 codepoints in the utf8 string src that consists entirely
-// of utf8 codepoints from the utf8 string accept.
-utf8_nonnull utf8_pure utf8_weak size_t utf8spn(const void *src,
- const void *accept);
-
-// The position of the utf8 string needle in the utf8 string haystack.
-utf8_nonnull utf8_pure utf8_weak void *utf8str(const void *haystack,
- const void *needle);
-
-// The position of the utf8 string needle in the utf8 string haystack, case
-// insensitive.
-utf8_nonnull utf8_pure utf8_weak void *utf8casestr(const void *haystack,
- const void *needle);
-
-// Return 0 on success, or the position of the invalid
-// utf8 codepoint on failure.
-utf8_nonnull utf8_pure utf8_weak void *utf8valid(const void *str);
-
-// Sets out_codepoint to the next utf8 codepoint in str, and returns the address
-// of the utf8 codepoint after the current one in str.
-utf8_nonnull utf8_weak void *
-utf8codepoint(const void *utf8_restrict str,
+#if defined(utf8_cplusplus) && utf8_cplusplus >= 201402L && (!defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER >= 1910))
+#define utf8_constexpr14 constexpr
+#define utf8_constexpr14_impl constexpr
+#else
+/* constexpr and weak are incompatible. so only enable one of them */
+#define utf8_constexpr14 utf8_weak
+#define utf8_constexpr14_impl
+#endif
+
+#if defined(utf8_cplusplus) && utf8_cplusplus >= 202002L
+using utf8_int8_t = char8_t; /* Introduced in C++20 */
+#else
+typedef char utf8_int8_t;
+#endif
+
+/* Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 >
+ * src2 respectively, case insensitive. */
+utf8_constexpr14 utf8_nonnull utf8_pure int
+utf8casecmp(const utf8_int8_t *src1, const utf8_int8_t *src2);
+
+/* Append the utf8 string src onto the utf8 string dst. */
+utf8_nonnull utf8_weak utf8_int8_t *
+utf8cat(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src);
+
+/* Find the first match of the utf8 codepoint chr in the utf8 string src. */
+utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
+utf8chr(const utf8_int8_t *src, utf8_int32_t chr);
+
+/* Return less than 0, 0, greater than 0 if src1 < src2,
+ * src1 == src2, src1 > src2 respectively. */
+utf8_constexpr14 utf8_nonnull utf8_pure int utf8cmp(const utf8_int8_t *src1,
+ const utf8_int8_t *src2);
+
+/* Copy the utf8 string src onto the memory allocated in dst. */
+utf8_nonnull utf8_weak utf8_int8_t *
+utf8cpy(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src);
+
+/* Number of utf8 codepoints in the utf8 string src that consists entirely
+ * of utf8 codepoints not from the utf8 string reject. */
+utf8_constexpr14 utf8_nonnull utf8_pure size_t
+utf8cspn(const utf8_int8_t *src, const utf8_int8_t *reject);
+
+/* Duplicate the utf8 string src by getting its size, malloc'ing a new buffer
+ * copying over the data, and returning that. Or 0 if malloc failed. */
+utf8_weak utf8_int8_t *utf8dup(const utf8_int8_t *src);
+
+/* Number of utf8 codepoints in the utf8 string str,
+ * excluding the null terminating byte. */
+utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8len(const utf8_int8_t *str);
+
+/* Similar to utf8len, except that only at most n bytes of src are looked. */
+utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8nlen(const utf8_int8_t *str,
+ size_t n);
+
+/* Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 >
+ * src2 respectively, case insensitive. Checking at most n bytes of each utf8
+ * string. */
+utf8_constexpr14 utf8_nonnull utf8_pure int
+utf8ncasecmp(const utf8_int8_t *src1, const utf8_int8_t *src2, size_t n);
+
+/* Append the utf8 string src onto the utf8 string dst,
+ * writing at most n+1 bytes. Can produce an invalid utf8
+ * string if n falls partway through a utf8 codepoint. */
+utf8_nonnull utf8_weak utf8_int8_t *
+utf8ncat(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src,
+ size_t n);
+
+/* Return less than 0, 0, greater than 0 if src1 < src2,
+ * src1 == src2, src1 > src2 respectively. Checking at most n
+ * bytes of each utf8 string. */
+utf8_constexpr14 utf8_nonnull utf8_pure int
+utf8ncmp(const utf8_int8_t *src1, const utf8_int8_t *src2, size_t n);
+
+/* Copy the utf8 string src onto the memory allocated in dst.
+ * Copies at most n bytes. If n falls partway through a utf8
+ * codepoint, or if dst doesn't have enough room for a null
+ * terminator, the final string will be cut short to preserve
+ * utf8 validity. */
+
+utf8_nonnull utf8_weak utf8_int8_t *
+utf8ncpy(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src,
+ size_t n);
+
+/* Similar to utf8dup, except that at most n bytes of src are copied. If src is
+ * longer than n, only n bytes are copied and a null byte is added.
+ *
+ * Returns a new string if successful, 0 otherwise */
+utf8_weak utf8_int8_t *utf8ndup(const utf8_int8_t *src, size_t n);
+
+/* Locates the first occurrence in the utf8 string str of any byte in the
+ * utf8 string accept, or 0 if no match was found. */
+utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
+utf8pbrk(const utf8_int8_t *str, const utf8_int8_t *accept);
+
+/* Find the last match of the utf8 codepoint chr in the utf8 string src. */
+utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
+utf8rchr(const utf8_int8_t *src, int chr);
+
+/* Number of bytes in the utf8 string str,
+ * including the null terminating byte. */
+utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8size(const utf8_int8_t *str);
+
+/* Similar to utf8size, except that the null terminating byte is excluded. */
+utf8_constexpr14 utf8_nonnull utf8_pure size_t
+utf8size_lazy(const utf8_int8_t *str);
+
+/* Similar to utf8size, except that only at most n bytes of src are looked and
+ * the null terminating byte is excluded. */
+utf8_constexpr14 utf8_nonnull utf8_pure size_t
+utf8nsize_lazy(const utf8_int8_t *str, size_t n);
+
+/* Number of utf8 codepoints in the utf8 string src that consists entirely
+ * of utf8 codepoints from the utf8 string accept. */
+utf8_constexpr14 utf8_nonnull utf8_pure size_t
+utf8spn(const utf8_int8_t *src, const utf8_int8_t *accept);
+
+/* The position of the utf8 string needle in the utf8 string haystack. */
+utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
+utf8str(const utf8_int8_t *haystack, const utf8_int8_t *needle);
+
+/* The position of the utf8 string needle in the utf8 string haystack, case
+ * insensitive. */
+utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
+utf8casestr(const utf8_int8_t *haystack, const utf8_int8_t *needle);
+
+/* Return 0 on success, or the position of the invalid
+ * utf8 codepoint on failure. */
+utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
+utf8valid(const utf8_int8_t *str);
+
+/* Similar to utf8valid, except that only at most n bytes of src are looked. */
+utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t *
+utf8nvalid(const utf8_int8_t *str, size_t n);
+
+/* Given a null-terminated string, makes the string valid by replacing invalid
+ * codepoints with a 1-byte replacement. Returns 0 on success. */
+utf8_nonnull utf8_weak int utf8makevalid(utf8_int8_t *str,
+ const utf8_int32_t replacement);
+
+/* Sets out_codepoint to the current utf8 codepoint in str, and returns the
+ * address of the next utf8 codepoint after the current one in str. */
+utf8_constexpr14 utf8_nonnull utf8_int8_t *
+utf8codepoint(const utf8_int8_t *utf8_restrict str,
utf8_int32_t *utf8_restrict out_codepoint);
-// Returns the size of the given codepoint in bytes.
-utf8_weak size_t utf8codepointsize(utf8_int32_t chr);
+/* Calculates the size of the next utf8 codepoint in str. */
+utf8_constexpr14 utf8_nonnull size_t
+utf8codepointcalcsize(const utf8_int8_t *str);
-// Write a codepoint to the given string, and return the address to the next
-// place after the written codepoint. Pass how many bytes left in the buffer to
-// n. If there is not enough space for the codepoint, this function returns
-// null.
-utf8_nonnull utf8_weak void *utf8catcodepoint(void *utf8_restrict str,
- utf8_int32_t chr, size_t n);
+/* Returns the size of the given codepoint in bytes. */
+utf8_constexpr14 size_t utf8codepointsize(utf8_int32_t chr);
-// Returns 1 if the given character is lowercase, or 0 if it is not.
-utf8_weak int utf8islower(utf8_int32_t chr);
+/* Write a codepoint to the given string, and return the address to the next
+ * place after the written codepoint. Pass how many bytes left in the buffer to
+ * n. If there is not enough space for the codepoint, this function returns
+ * null. */
+utf8_nonnull utf8_weak utf8_int8_t *
+utf8catcodepoint(utf8_int8_t *str, utf8_int32_t chr, size_t n);
-// Returns 1 if the given character is uppercase, or 0 if it is not.
-utf8_weak int utf8isupper(utf8_int32_t chr);
+/* Returns 1 if the given character is lowercase, or 0 if it is not. */
+utf8_constexpr14 int utf8islower(utf8_int32_t chr);
-// Transform the given string into all lowercase codepoints.
-utf8_nonnull utf8_weak void utf8lwr(void *utf8_restrict str);
+/* Returns 1 if the given character is uppercase, or 0 if it is not. */
+utf8_constexpr14 int utf8isupper(utf8_int32_t chr);
-// Transform the given string into all uppercase codepoints.
-utf8_nonnull utf8_weak void utf8upr(void *utf8_restrict str);
+/* Transform the given string into all lowercase codepoints. */
+utf8_nonnull utf8_weak void utf8lwr(utf8_int8_t *utf8_restrict str);
-// Make a codepoint lower case if possible.
-utf8_weak utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp);
+/* Transform the given string into all uppercase codepoints. */
+utf8_nonnull utf8_weak void utf8upr(utf8_int8_t *utf8_restrict str);
-// Make a codepoint upper case if possible.
-utf8_weak utf8_int32_t utf8uprcodepoint(utf8_int32_t cp);
+/* Make a codepoint lower case if possible. */
+utf8_constexpr14 utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp);
+
+/* Make a codepoint upper case if possible. */
+utf8_constexpr14 utf8_int32_t utf8uprcodepoint(utf8_int32_t cp);
+
+/* Sets out_codepoint to the current utf8 codepoint in str, and returns the
+ * address of the previous utf8 codepoint before the current one in str. */
+utf8_constexpr14 utf8_nonnull utf8_int8_t *
+utf8rcodepoint(const utf8_int8_t *utf8_restrict str,
+ utf8_int32_t *utf8_restrict out_codepoint);
+
+/* Duplicate the utf8 string src by getting its size, calling alloc_func_ptr to
+ * copy over data to a new buffer, and returning that. Or 0 if alloc_func_ptr
+ * returned null. */
+utf8_weak utf8_int8_t *utf8dup_ex(const utf8_int8_t *src,
+ utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *,
+ size_t),
+ utf8_int8_t *user_data);
+
+/* Similar to utf8dup, except that at most n bytes of src are copied. If src is
+ * longer than n, only n bytes are copied and a null byte is added.
+ *
+ * Returns a new string if successful, 0 otherwise. */
+utf8_weak utf8_int8_t *utf8ndup_ex(const utf8_int8_t *src, size_t n,
+ utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *,
+ size_t),
+ utf8_int8_t *user_data);
#undef utf8_weak
#undef utf8_pure
#undef utf8_nonnull
-int utf8casecmp(const void *src1, const void *src2) {
- utf8_int32_t src1_cp, src2_cp, src1_orig_cp, src2_orig_cp;
+utf8_constexpr14_impl int utf8casecmp(const utf8_int8_t *src1,
+ const utf8_int8_t *src2) {
+ utf8_int32_t src1_lwr_cp = 0, src2_lwr_cp = 0, src1_upr_cp = 0,
+ src2_upr_cp = 0, src1_orig_cp = 0, src2_orig_cp = 0;
for (;;) {
- src1 = utf8codepoint(src1, &src1_cp);
- src2 = utf8codepoint(src2, &src2_cp);
+ src1 = utf8codepoint(src1, &src1_orig_cp);
+ src2 = utf8codepoint(src2, &src2_orig_cp);
- // Take a copy of src1 & src2
- src1_orig_cp = src1_cp;
- src2_orig_cp = src2_cp;
+ /* lower the srcs if required */
+ src1_lwr_cp = utf8lwrcodepoint(src1_orig_cp);
+ src2_lwr_cp = utf8lwrcodepoint(src2_orig_cp);
- // Lower the srcs if required
- src1_cp = utf8lwrcodepoint(src1_cp);
- src2_cp = utf8lwrcodepoint(src2_cp);
+ /* lower the srcs if required */
+ src1_upr_cp = utf8uprcodepoint(src1_orig_cp);
+ src2_upr_cp = utf8uprcodepoint(src2_orig_cp);
- // Check if the lowered codepoints match
+ /* check if the lowered codepoints match */
if ((0 == src1_orig_cp) && (0 == src2_orig_cp)) {
return 0;
- } else if (src1_cp == src2_cp) {
+ } else if ((src1_lwr_cp == src2_lwr_cp) || (src1_upr_cp == src2_upr_cp)) {
continue;
}
- // If they don't match, then we return which of the original's are less
- if (src1_orig_cp < src2_orig_cp) {
- return -1;
- } else if (src1_orig_cp > src2_orig_cp) {
- return 1;
- }
+ /* if they don't match, then we return the difference between the characters
+ */
+ return src1_lwr_cp - src2_lwr_cp;
}
}
-void *utf8cat(void *utf8_restrict dst, const void *utf8_restrict src) {
- char *d = (char *)dst;
- const char *s = (const char *)src;
-
- // find the null terminating byte in dst
+utf8_int8_t *utf8cat(utf8_int8_t *utf8_restrict dst,
+ const utf8_int8_t *utf8_restrict src) {
+ utf8_int8_t *d = dst;
+ /* find the null terminating byte in dst */
while ('\0' != *d) {
d++;
}
- // overwriting the null terminating byte in dst, append src byte-by-byte
- while ('\0' != *s) {
- *d++ = *s++;
+ /* overwriting the null terminating byte in dst, append src byte-by-byte */
+ while ('\0' != *src) {
+ *d++ = *src++;
}
- // write out a new null terminating byte into dst
+ /* write out a new null terminating byte into dst */
*d = '\0';
return dst;
}
-void *utf8chr(const void *src, utf8_int32_t chr) {
- char c[5] = {'\0', '\0', '\0', '\0', '\0'};
+utf8_constexpr14_impl utf8_int8_t *utf8chr(const utf8_int8_t *src,
+ utf8_int32_t chr) {
+ utf8_int8_t c[5] = {'\0', '\0', '\0', '\0', '\0'};
if (0 == chr) {
- // being asked to return position of null terminating byte, so
- // just run s to the end, and return!
- const char *s = (const char *)src;
- while ('\0' != *s) {
- s++;
+ /* being asked to return position of null terminating byte, so
+ * just run s to the end, and return! */
+ while ('\0' != *src) {
+ src++;
}
- return (void *)s;
+ return (utf8_int8_t *)src;
} else if (0 == ((utf8_int32_t)0xffffff80 & chr)) {
- // 1-byte/7-bit ascii
- // (0b0xxxxxxx)
- c[0] = (char)chr;
+ /* 1-byte/7-bit ascii
+ * (0b0xxxxxxx) */
+ c[0] = (utf8_int8_t)chr;
} else if (0 == ((utf8_int32_t)0xfffff800 & chr)) {
- // 2-byte/11-bit utf8 code point
- // (0b110xxxxx 0b10xxxxxx)
- c[0] = 0xc0 | (char)(chr >> 6);
- c[1] = 0x80 | (char)(chr & 0x3f);
+ /* 2-byte/11-bit utf8 code point
+ * (0b110xxxxx 0b10xxxxxx) */
+ c[0] = (utf8_int8_t)(0xc0 | (utf8_int8_t)(chr >> 6));
+ c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
} else if (0 == ((utf8_int32_t)0xffff0000 & chr)) {
- // 3-byte/16-bit utf8 code point
- // (0b1110xxxx 0b10xxxxxx 0b10xxxxxx)
- c[0] = 0xe0 | (char)(chr >> 12);
- c[1] = 0x80 | (char)((chr >> 6) & 0x3f);
- c[2] = 0x80 | (char)(chr & 0x3f);
- } else { // if (0 == ((int)0xffe00000 & chr)) {
- // 4-byte/21-bit utf8 code point
- // (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx)
- c[0] = 0xf0 | (char)(chr >> 18);
- c[1] = 0x80 | (char)((chr >> 12) & 0x3f);
- c[2] = 0x80 | (char)((chr >> 6) & 0x3f);
- c[3] = 0x80 | (char)(chr & 0x3f);
+ /* 3-byte/16-bit utf8 code point
+ * (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) */
+ c[0] = (utf8_int8_t)(0xe0 | (utf8_int8_t)(chr >> 12));
+ c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f));
+ c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
+ } else { /* if (0 == ((int)0xffe00000 & chr)) { */
+ /* 4-byte/21-bit utf8 code point
+ * (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) */
+ c[0] = (utf8_int8_t)(0xf0 | (utf8_int8_t)(chr >> 18));
+ c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 12) & 0x3f));
+ c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f));
+ c[3] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
}
- // we've made c into a 2 utf8 codepoint string, one for the chr we are
- // seeking, another for the null terminating byte. Now use utf8str to
- // search
+ /* we've made c into a 2 utf8 codepoint string, one for the chr we are
+ * seeking, another for the null terminating byte. Now use utf8str to
+ * search */
return utf8str(src, c);
}
-int utf8cmp(const void *src1, const void *src2) {
- const unsigned char *s1 = (const unsigned char *)src1;
- const unsigned char *s2 = (const unsigned char *)src2;
-
- while (('\0' != *s1) || ('\0' != *s2)) {
- if (*s1 < *s2) {
+utf8_constexpr14_impl int utf8cmp(const utf8_int8_t *src1,
+ const utf8_int8_t *src2) {
+ while (('\0' != *src1) || ('\0' != *src2)) {
+ if (*src1 < *src2) {
return -1;
- } else if (*s1 > *s2) {
+ } else if (*src1 > *src2) {
return 1;
}
- s1++;
- s2++;
+ src1++;
+ src2++;
}
- // both utf8 strings matched
+ /* both utf8 strings matched */
return 0;
}
-int utf8coll(const void *src1, const void *src2);
+utf8_constexpr14_impl int utf8coll(const utf8_int8_t *src1,
+ const utf8_int8_t *src2);
-void *utf8cpy(void *utf8_restrict dst, const void *utf8_restrict src) {
- char *d = (char *)dst;
- const char *s = (const char *)src;
+utf8_int8_t *utf8cpy(utf8_int8_t *utf8_restrict dst,
+ const utf8_int8_t *utf8_restrict src) {
+ utf8_int8_t *d = dst;
- // overwriting anything previously in dst, write byte-by-byte
- // from src
- while ('\0' != *s) {
- *d++ = *s++;
+ /* overwriting anything previously in dst, write byte-by-byte
+ * from src */
+ while ('\0' != *src) {
+ *d++ = *src++;
}
- // append null terminating byte
+ /* append null terminating byte */
*d = '\0';
return dst;
}
-size_t utf8cspn(const void *src, const void *reject) {
- const char *s = (const char *)src;
+utf8_constexpr14_impl size_t utf8cspn(const utf8_int8_t *src,
+ const utf8_int8_t *reject) {
size_t chars = 0;
- while ('\0' != *s) {
- const char *r = (const char *)reject;
+ while ('\0' != *src) {
+ const utf8_int8_t *r = reject;
size_t offset = 0;
while ('\0' != *r) {
- // checking that if *r is the start of a utf8 codepoint
- // (it is not 0b10xxxxxx) and we have successfully matched
- // a previous character (0 < offset) - we found a match
+ /* checking that if *r is the start of a utf8 codepoint
+ * (it is not 0b10xxxxxx) and we have successfully matched
+ * a previous character (0 < offset) - we found a match */
if ((0x80 != (0xc0 & *r)) && (0 < offset)) {
return chars;
} else {
- if (*r == s[offset]) {
- // part of a utf8 codepoint matched, so move our checking
- // onwards to the next byte
+ if (*r == src[offset]) {
+ /* part of a utf8 codepoint matched, so move our checking
+ * onwards to the next byte */
offset++;
r++;
} else {
- // r could be in the middle of an unmatching utf8 code point,
- // so we need to march it on to the next character beginning,
+ /* r could be in the middle of an unmatching utf8 code point,
+ * so we need to march it on to the next character beginning, */
do {
r++;
} while (0x80 == (0xc0 & *r));
- // reset offset too as we found a mismatch
+ /* reset offset too as we found a mismatch */
offset = 0;
}
}
}
- // the current utf8 codepoint in src did not match reject, but src
- // could have been partway through a utf8 codepoint, so we need to
- // march it onto the next utf8 codepoint starting byte
+ /* found a match at the end of *r, so didn't get a chance to test it */
+ if (0 < offset) {
+ return chars;
+ }
+
+ /* the current utf8 codepoint in src did not match reject, but src
+ * could have been partway through a utf8 codepoint, so we need to
+ * march it onto the next utf8 codepoint starting byte */
do {
- s++;
- } while ((0x80 == (0xc0 & *s)));
+ src++;
+ } while ((0x80 == (0xc0 & *src)));
chars++;
}
return chars;
}
-size_t utf8size(const void *str);
+utf8_int8_t *utf8dup(const utf8_int8_t *src) {
+ return utf8dup_ex(src, utf8_null, utf8_null);
+}
-void *utf8dup(const void *src) {
- const char *s = (const char *)src;
- char *n = utf8_null;
+utf8_int8_t *utf8dup_ex(const utf8_int8_t *src,
+ utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *, size_t),
+ utf8_int8_t *user_data) {
+ utf8_int8_t *n = utf8_null;
- // figure out how many bytes (including the terminator) we need to copy first
+ /* figure out how many bytes (including the terminator) we need to copy first
+ */
size_t bytes = utf8size(src);
- n = (char *)malloc(bytes);
+ if (alloc_func_ptr) {
+ n = alloc_func_ptr(user_data, bytes);
+ } else {
+#if !defined(UTF8_NO_STD_MALLOC)
+ n = (utf8_int8_t *)malloc(bytes);
+#else
+ return utf8_null;
+#endif
+ }
if (utf8_null == n) {
- // out of memory so we bail
+ /* out of memory so we bail */
return utf8_null;
} else {
bytes = 0;
- // copy src byte-by-byte into our new utf8 string
- while ('\0' != s[bytes]) {
- n[bytes] = s[bytes];
+ /* copy src byte-by-byte into our new utf8 string */
+ while ('\0' != src[bytes]) {
+ n[bytes] = src[bytes];
bytes++;
}
- // append null terminating byte
+ /* append null terminating byte */
n[bytes] = '\0';
return n;
}
}
-void *utf8fry(const void *str);
+utf8_constexpr14_impl utf8_int8_t *utf8fry(const utf8_int8_t *str);
+
+utf8_constexpr14_impl size_t utf8len(const utf8_int8_t *str) {
+ return utf8nlen(str, SIZE_MAX);
+}
-size_t utf8len(const void *str) {
- const unsigned char *s = (const unsigned char *)str;
+utf8_constexpr14_impl size_t utf8nlen(const utf8_int8_t *str, size_t n) {
+ const utf8_int8_t *t = str;
size_t length = 0;
- while ('\0' != *s) {
- if (0xf0 == (0xf8 & *s)) {
- // 4-byte utf8 code point (began with 0b11110xxx)
- s += 4;
- } else if (0xe0 == (0xf0 & *s)) {
- // 3-byte utf8 code point (began with 0b1110xxxx)
- s += 3;
- } else if (0xc0 == (0xe0 & *s)) {
- // 2-byte utf8 code point (began with 0b110xxxxx)
- s += 2;
- } else { // if (0x00 == (0x80 & *s)) {
- // 1-byte ascii (began with 0b0xxxxxxx)
- s += 1;
+ while ((size_t)(str - t) < n && '\0' != *str) {
+ if (0xf0 == (0xf8 & *str)) {
+ /* 4-byte utf8 code point (began with 0b11110xxx) */
+ str += 4;
+ } else if (0xe0 == (0xf0 & *str)) {
+ /* 3-byte utf8 code point (began with 0b1110xxxx) */
+ str += 3;
+ } else if (0xc0 == (0xe0 & *str)) {
+ /* 2-byte utf8 code point (began with 0b110xxxxx) */
+ str += 2;
+ } else { /* if (0x00 == (0x80 & *s)) { */
+ /* 1-byte ascii (began with 0b0xxxxxxx) */
+ str += 1;
}
- // no matter the bytes we marched s forward by, it was
- // only 1 utf8 codepoint
+ /* no matter the bytes we marched s forward by, it was
+ * only 1 utf8 codepoint */
length++;
}
+ if ((size_t)(str - t) > n) {
+ length--;
+ }
return length;
}
-int utf8ncasecmp(const void *src1, const void *src2, size_t n) {
- utf8_int32_t src1_cp, src2_cp, src1_orig_cp, src2_orig_cp;
+utf8_constexpr14_impl int utf8ncasecmp(const utf8_int8_t *src1,
+ const utf8_int8_t *src2, size_t n) {
+ utf8_int32_t src1_lwr_cp = 0, src2_lwr_cp = 0, src1_upr_cp = 0,
+ src2_upr_cp = 0, src1_orig_cp = 0, src2_orig_cp = 0;
do {
- const unsigned char *const s1 = (const unsigned char *)src1;
- const unsigned char *const s2 = (const unsigned char *)src2;
+ const utf8_int8_t *const s1 = src1;
+ const utf8_int8_t *const s2 = src2;
- // first check that we have enough bytes left in n to contain an entire
- // codepoint
+ /* first check that we have enough bytes left in n to contain an entire
+ * codepoint */
if (0 == n) {
return 0;
}
@@ -469,10 +587,8 @@ int utf8ncasecmp(const void *src1, const void *src2, size_t n) {
const utf8_int32_t c1 = (0xe0 & *s1);
const utf8_int32_t c2 = (0xe0 & *s2);
- if (c1 < c2) {
- return -1;
- } else if (c1 > c2) {
- return 1;
+ if (c1 != c2) {
+ return c1 - c2;
} else {
return 0;
}
@@ -482,10 +598,8 @@ int utf8ncasecmp(const void *src1, const void *src2, size_t n) {
const utf8_int32_t c1 = (0xf0 & *s1);
const utf8_int32_t c2 = (0xf0 & *s2);
- if (c1 < c2) {
- return -1;
- } else if (c1 > c2) {
- return 1;
+ if (c1 != c2) {
+ return c1 - c2;
} else {
return 0;
}
@@ -495,307 +609,343 @@ int utf8ncasecmp(const void *src1, const void *src2, size_t n) {
const utf8_int32_t c1 = (0xf8 & *s1);
const utf8_int32_t c2 = (0xf8 & *s2);
- if (c1 < c2) {
- return -1;
- } else if (c1 > c2) {
- return 1;
+ if (c1 != c2) {
+ return c1 - c2;
} else {
return 0;
}
}
- src1 = utf8codepoint(src1, &src1_cp);
- src2 = utf8codepoint(src2, &src2_cp);
- n -= utf8codepointsize(src1_cp);
+ src1 = utf8codepoint(src1, &src1_orig_cp);
+ src2 = utf8codepoint(src2, &src2_orig_cp);
+ n -= utf8codepointsize(src1_orig_cp);
- // Take a copy of src1 & src2
- src1_orig_cp = src1_cp;
- src2_orig_cp = src2_cp;
+ src1_lwr_cp = utf8lwrcodepoint(src1_orig_cp);
+ src2_lwr_cp = utf8lwrcodepoint(src2_orig_cp);
- // Lower srcs if required
- src1_cp = utf8lwrcodepoint(src1_cp);
- src2_cp = utf8lwrcodepoint(src2_cp);
+ src1_upr_cp = utf8uprcodepoint(src1_orig_cp);
+ src2_upr_cp = utf8uprcodepoint(src2_orig_cp);
- // Check if the lowered codepoints match
+ /* check if the lowered codepoints match */
if ((0 == src1_orig_cp) && (0 == src2_orig_cp)) {
return 0;
- } else if (src1_cp == src2_cp) {
+ } else if ((src1_lwr_cp == src2_lwr_cp) || (src1_upr_cp == src2_upr_cp)) {
continue;
}
- // If they don't match, then we return which of the original's are less
- if (src1_orig_cp < src2_orig_cp) {
- return -1;
- } else if (src1_orig_cp > src2_orig_cp) {
- return 1;
- }
+ /* if they don't match, then we return the difference between the characters
+ */
+ return src1_lwr_cp - src2_lwr_cp;
} while (0 < n);
- // both utf8 strings matched
+ /* both utf8 strings matched */
return 0;
}
-void *utf8ncat(void *utf8_restrict dst, const void *utf8_restrict src,
- size_t n) {
- char *d = (char *)dst;
- const char *s = (const char *)src;
+utf8_int8_t *utf8ncat(utf8_int8_t *utf8_restrict dst,
+ const utf8_int8_t *utf8_restrict src, size_t n) {
+ utf8_int8_t *d = dst;
- // find the null terminating byte in dst
+ /* find the null terminating byte in dst */
while ('\0' != *d) {
d++;
}
- // overwriting the null terminating byte in dst, append src byte-by-byte
- // stopping if we run out of space
- do {
- *d++ = *s++;
- } while (('\0' != *s) && (0 != --n));
+ /* overwriting the null terminating byte in dst, append src byte-by-byte
+ * stopping if we run out of space */
+ while (('\0' != *src) && (0 != n--)) {
+ *d++ = *src++;
+ }
- // write out a new null terminating byte into dst
+ /* write out a new null terminating byte into dst */
*d = '\0';
return dst;
}
-int utf8ncmp(const void *src1, const void *src2, size_t n) {
- const unsigned char *s1 = (const unsigned char *)src1;
- const unsigned char *s2 = (const unsigned char *)src2;
-
- while ((('\0' != *s1) || ('\0' != *s2)) && (0 != n--)) {
- if (*s1 < *s2) {
+utf8_constexpr14_impl int utf8ncmp(const utf8_int8_t *src1,
+ const utf8_int8_t *src2, size_t n) {
+ while ((0 != n--) && (('\0' != *src1) || ('\0' != *src2))) {
+ if (*src1 < *src2) {
return -1;
- } else if (*s1 > *s2) {
+ } else if (*src1 > *src2) {
return 1;
}
- s1++;
- s2++;
+ src1++;
+ src2++;
}
- // both utf8 strings matched
+ /* both utf8 strings matched */
return 0;
}
-void *utf8ncpy(void *utf8_restrict dst, const void *utf8_restrict src,
- size_t n) {
- char *d = (char *)dst;
- const char *s = (const char *)src;
+utf8_int8_t *utf8ncpy(utf8_int8_t *utf8_restrict dst,
+ const utf8_int8_t *utf8_restrict src, size_t n) {
+ utf8_int8_t *d = dst;
+ size_t index = 0, check_index = 0;
- // overwriting anything previously in dst, write byte-by-byte
- // from src
- do {
- *d++ = *s++;
- } while (('\0' != *s) && (0 != --n));
+ if (n == 0) {
+ return dst;
+ }
+
+ /* overwriting anything previously in dst, write byte-by-byte
+ * from src */
+ for (index = 0; index < n; index++) {
+ d[index] = src[index];
+ if ('\0' == src[index]) {
+ break;
+ }
+ }
+
+ for (check_index = index - 1;
+ check_index > 0 && 0x80 == (0xc0 & d[check_index]); check_index--) {
+ /* just moving the index */
+ }
+
+ if (check_index < index &&
+ ((index - check_index) < utf8codepointcalcsize(&d[check_index]) ||
+ (index - check_index) == n)) {
+ index = check_index;
+ }
- // append null terminating byte
- while (0 != n) {
- *d++ = '\0';
- n--;
+ /* append null terminating byte */
+ for (; index < n; index++) {
+ d[index] = 0;
}
return dst;
}
-void *utf8ndup(const void *src, size_t n) {
- const char *s = (const char *)src;
- char *c = utf8_null;
+utf8_int8_t *utf8ndup(const utf8_int8_t *src, size_t n) {
+ return utf8ndup_ex(src, n, utf8_null, utf8_null);
+}
+
+utf8_int8_t *utf8ndup_ex(const utf8_int8_t *src, size_t n,
+ utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *, size_t),
+ utf8_int8_t *user_data) {
+ utf8_int8_t *c = utf8_null;
size_t bytes = 0;
- // Find the end of the string or stop when n is reached
- while ('\0' != s[bytes] && bytes < n) {
+ /* Find the end of the string or stop when n is reached */
+ while ('\0' != src[bytes] && bytes < n) {
bytes++;
}
- // In case bytes is actually less than n, we need to set it
- // to be used later in the copy byte by byte.
+ /* In case bytes is actually less than n, we need to set it
+ * to be used later in the copy byte by byte. */
n = bytes;
- c = (char *)malloc(bytes + 1);
+ if (alloc_func_ptr) {
+ c = alloc_func_ptr(user_data, bytes + 1);
+ } else {
+#if !defined(UTF8_NO_STD_MALLOC)
+ c = (utf8_int8_t *)malloc(bytes + 1);
+#else
+ c = utf8_null;
+#endif
+ }
+
if (utf8_null == c) {
- // out of memory so we bail
+ /* out of memory so we bail */
return utf8_null;
}
bytes = 0;
- // copy src byte-by-byte into our new utf8 string
- while ('\0' != s[bytes] && bytes < n) {
- c[bytes] = s[bytes];
+ /* copy src byte-by-byte into our new utf8 string */
+ while ('\0' != src[bytes] && bytes < n) {
+ c[bytes] = src[bytes];
bytes++;
}
- // append null terminating byte
+ /* append null terminating byte */
c[bytes] = '\0';
return c;
}
-void *utf8rchr(const void *src, int chr) {
- const char *s = (const char *)src;
- const char *match = utf8_null;
- char c[5] = {'\0', '\0', '\0', '\0', '\0'};
+utf8_constexpr14_impl utf8_int8_t *utf8rchr(const utf8_int8_t *src, int chr) {
+
+ utf8_int8_t *match = utf8_null;
+ utf8_int8_t c[5] = {'\0', '\0', '\0', '\0', '\0'};
if (0 == chr) {
- // being asked to return position of null terminating byte, so
- // just run s to the end, and return!
- while ('\0' != *s) {
- s++;
+ /* being asked to return position of null terminating byte, so
+ * just run s to the end, and return! */
+ while ('\0' != *src) {
+ src++;
}
- return (void *)s;
+ return (utf8_int8_t *)src;
} else if (0 == ((int)0xffffff80 & chr)) {
- // 1-byte/7-bit ascii
- // (0b0xxxxxxx)
- c[0] = (char)chr;
+ /* 1-byte/7-bit ascii
+ * (0b0xxxxxxx) */
+ c[0] = (utf8_int8_t)chr;
} else if (0 == ((int)0xfffff800 & chr)) {
- // 2-byte/11-bit utf8 code point
- // (0b110xxxxx 0b10xxxxxx)
- c[0] = 0xc0 | (char)(chr >> 6);
- c[1] = 0x80 | (char)(chr & 0x3f);
+ /* 2-byte/11-bit utf8 code point
+ * (0b110xxxxx 0b10xxxxxx) */
+ c[0] = (utf8_int8_t)(0xc0 | (utf8_int8_t)(chr >> 6));
+ c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
} else if (0 == ((int)0xffff0000 & chr)) {
- // 3-byte/16-bit utf8 code point
- // (0b1110xxxx 0b10xxxxxx 0b10xxxxxx)
- c[0] = 0xe0 | (char)(chr >> 12);
- c[1] = 0x80 | (char)((chr >> 6) & 0x3f);
- c[2] = 0x80 | (char)(chr & 0x3f);
- } else { // if (0 == ((int)0xffe00000 & chr)) {
- // 4-byte/21-bit utf8 code point
- // (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx)
- c[0] = 0xf0 | (char)(chr >> 18);
- c[1] = 0x80 | (char)((chr >> 12) & 0x3f);
- c[2] = 0x80 | (char)((chr >> 6) & 0x3f);
- c[3] = 0x80 | (char)(chr & 0x3f);
+ /* 3-byte/16-bit utf8 code point
+ * (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) */
+ c[0] = (utf8_int8_t)(0xe0 | (utf8_int8_t)(chr >> 12));
+ c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f));
+ c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
+ } else { /* if (0 == ((int)0xffe00000 & chr)) { */
+ /* 4-byte/21-bit utf8 code point
+ * (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) */
+ c[0] = (utf8_int8_t)(0xf0 | (utf8_int8_t)(chr >> 18));
+ c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 12) & 0x3f));
+ c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f));
+ c[3] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
}
- // we've created a 2 utf8 codepoint string in c that is
- // the utf8 character asked for by chr, and a null
- // terminating byte
+ /* we've created a 2 utf8 codepoint string in c that is
+ * the utf8 character asked for by chr, and a null
+ * terminating byte */
- while ('\0' != *s) {
+ while ('\0' != *src) {
size_t offset = 0;
- while (s[offset] == c[offset]) {
+ while ((src[offset] == c[offset]) && ('\0' != src[offset])) {
offset++;
}
if ('\0' == c[offset]) {
- // we found a matching utf8 code point
- match = s;
- s += offset;
+ /* we found a matching utf8 code point */
+ match = (utf8_int8_t *)src;
+ src += offset;
+
+ if ('\0' == *src) {
+ break;
+ }
} else {
- s += offset;
+ src += offset;
- // need to march s along to next utf8 codepoint start
- // (the next byte that doesn't match 0b10xxxxxx)
- if ('\0' != *s) {
+ /* need to march s along to next utf8 codepoint start
+ * (the next byte that doesn't match 0b10xxxxxx) */
+ if ('\0' != *src) {
do {
- s++;
- } while (0x80 == (0xc0 & *s));
+ src++;
+ } while (0x80 == (0xc0 & *src));
}
}
}
- // return the last match we found (or 0 if no match was found)
- return (void *)match;
+ /* return the last match we found (or 0 if no match was found) */
+ return match;
}
-void *utf8pbrk(const void *str, const void *accept) {
- const char *s = (const char *)str;
-
- while ('\0' != *s) {
- const char *a = (const char *)accept;
+utf8_constexpr14_impl utf8_int8_t *utf8pbrk(const utf8_int8_t *str,
+ const utf8_int8_t *accept) {
+ while ('\0' != *str) {
+ const utf8_int8_t *a = accept;
size_t offset = 0;
while ('\0' != *a) {
- // checking that if *a is the start of a utf8 codepoint
- // (it is not 0b10xxxxxx) and we have successfully matched
- // a previous character (0 < offset) - we found a match
+ /* checking that if *a is the start of a utf8 codepoint
+ * (it is not 0b10xxxxxx) and we have successfully matched
+ * a previous character (0 < offset) - we found a match */
if ((0x80 != (0xc0 & *a)) && (0 < offset)) {
- return (void *)s;
+ return (utf8_int8_t *)str;
} else {
- if (*a == s[offset]) {
- // part of a utf8 codepoint matched, so move our checking
- // onwards to the next byte
+ if (*a == str[offset]) {
+ /* part of a utf8 codepoint matched, so move our checking
+ * onwards to the next byte */
offset++;
a++;
} else {
- // r could be in the middle of an unmatching utf8 code point,
- // so we need to march it on to the next character beginning,
+ /* r could be in the middle of an unmatching utf8 code point,
+ * so we need to march it on to the next character beginning, */
do {
a++;
} while (0x80 == (0xc0 & *a));
- // reset offset too as we found a mismatch
+ /* reset offset too as we found a mismatch */
offset = 0;
}
}
}
- // we found a match on the last utf8 codepoint
+ /* we found a match on the last utf8 codepoint */
if (0 < offset) {
- return (void *)s;
+ return (utf8_int8_t *)str;
}
- // the current utf8 codepoint in src did not match accept, but src
- // could have been partway through a utf8 codepoint, so we need to
- // march it onto the next utf8 codepoint starting byte
+ /* the current utf8 codepoint in src did not match accept, but src
+ * could have been partway through a utf8 codepoint, so we need to
+ * march it onto the next utf8 codepoint starting byte */
do {
- s++;
- } while ((0x80 == (0xc0 & *s)));
+ str++;
+ } while ((0x80 == (0xc0 & *str)));
}
return utf8_null;
}
-size_t utf8size(const void *str) {
- const char *s = (const char *)str;
+utf8_constexpr14_impl size_t utf8size(const utf8_int8_t *str) {
+ return utf8size_lazy(str) + 1;
+}
+
+utf8_constexpr14_impl size_t utf8size_lazy(const utf8_int8_t *str) {
+ return utf8nsize_lazy(str, SIZE_MAX);
+}
+
+utf8_constexpr14_impl size_t utf8nsize_lazy(const utf8_int8_t *str, size_t n) {
size_t size = 0;
- while ('\0' != s[size]) {
+ while (size < n && '\0' != str[size]) {
size++;
}
-
- // we are including the null terminating byte in the size calculation
- size++;
return size;
}
-size_t utf8spn(const void *src, const void *accept) {
- const char *s = (const char *)src;
+utf8_constexpr14_impl size_t utf8spn(const utf8_int8_t *src,
+ const utf8_int8_t *accept) {
size_t chars = 0;
- while ('\0' != *s) {
- const char *a = (const char *)accept;
+ while ('\0' != *src) {
+ const utf8_int8_t *a = accept;
size_t offset = 0;
while ('\0' != *a) {
- // checking that if *r is the start of a utf8 codepoint
- // (it is not 0b10xxxxxx) and we have successfully matched
- // a previous character (0 < offset) - we found a match
+ /* checking that if *r is the start of a utf8 codepoint
+ * (it is not 0b10xxxxxx) and we have successfully matched
+ * a previous character (0 < offset) - we found a match */
if ((0x80 != (0xc0 & *a)) && (0 < offset)) {
- // found a match, so increment the number of utf8 codepoints
- // that have matched and stop checking whether any other utf8
- // codepoints in a match
+ /* found a match, so increment the number of utf8 codepoints
+ * that have matched and stop checking whether any other utf8
+ * codepoints in a match */
chars++;
- s += offset;
+ src += offset;
+ offset = 0;
break;
} else {
- if (*a == s[offset]) {
+ if (*a == src[offset]) {
offset++;
a++;
} else {
- // a could be in the middle of an unmatching utf8 codepoint,
- // so we need to march it on to the next character beginning,
+ /* a could be in the middle of an unmatching utf8 codepoint,
+ * so we need to march it on to the next character beginning, */
do {
a++;
} while (0x80 == (0xc0 & *a));
- // reset offset too as we found a mismatch
+ /* reset offset too as we found a mismatch */
offset = 0;
}
}
}
- // if a got to its terminating null byte, then we didn't find a match.
- // Return the current number of matched utf8 codepoints
+ /* found a match at the end of *a, so didn't get a chance to test it */
+ if (0 < offset) {
+ chars++;
+ src += offset;
+ continue;
+ }
+
+ /* if a got to its terminating null byte, then we didn't find a match.
+ * Return the current number of matched utf8 codepoints */
if ('\0' == *a) {
return chars;
}
@@ -804,302 +954,405 @@ size_t utf8spn(const void *src, const void *accept) {
return chars;
}
-void *utf8str(const void *haystack, const void *needle) {
- const char *h = (const char *)haystack;
+utf8_constexpr14_impl utf8_int8_t *utf8str(const utf8_int8_t *haystack,
+ const utf8_int8_t *needle) {
+ utf8_int32_t throwaway_codepoint = 0;
- // if needle has no utf8 codepoints before the null terminating
- // byte then return haystack
- if ('\0' == *((const char *)needle)) {
- return (void *)haystack;
+ /* if needle has no utf8 codepoints before the null terminating
+ * byte then return haystack */
+ if ('\0' == *needle) {
+ return (utf8_int8_t *)haystack;
}
- while ('\0' != *h) {
- const char *maybeMatch = h;
- const char *n = (const char *)needle;
+ while ('\0' != *haystack) {
+ const utf8_int8_t *maybeMatch = haystack;
+ const utf8_int8_t *n = needle;
- while (*h == *n && (*h != '\0' && *n != '\0')) {
+ while (*haystack == *n && (*haystack != '\0' && *n != '\0')) {
n++;
- h++;
+ haystack++;
}
if ('\0' == *n) {
- // we found the whole utf8 string for needle in haystack at
- // maybeMatch, so return it
- return (void *)maybeMatch;
+ /* we found the whole utf8 string for needle in haystack at
+ * maybeMatch, so return it */
+ return (utf8_int8_t *)maybeMatch;
} else {
- // h could be in the middle of an unmatching utf8 codepoint,
- // so we need to march it on to the next character beginning,
- if ('\0' != *h) {
- do {
- h++;
- } while (0x80 == (0xc0 & *h));
- }
+ /* h could be in the middle of an unmatching utf8 codepoint,
+ * so we need to march it on to the next character beginning
+ * starting from the current character */
+ haystack = utf8codepoint(maybeMatch, &throwaway_codepoint);
}
}
- // no match
+ /* no match */
return utf8_null;
}
-void *utf8casestr(const void *haystack, const void *needle) {
- const void *h = haystack;
-
- // if needle has no utf8 codepoints before the null terminating
- // byte then return haystack
- if ('\0' == *((const char *)needle)) {
- return (void *)haystack;
+utf8_constexpr14_impl utf8_int8_t *utf8casestr(const utf8_int8_t *haystack,
+ const utf8_int8_t *needle) {
+ /* if needle has no utf8 codepoints before the null terminating
+ * byte then return haystack */
+ if ('\0' == *needle) {
+ return (utf8_int8_t *)haystack;
}
for (;;) {
- const void *maybeMatch = h;
- const void *n = needle;
- utf8_int32_t h_cp, n_cp;
+ const utf8_int8_t *maybeMatch = haystack;
+ const utf8_int8_t *n = needle;
+ utf8_int32_t h_cp = 0, n_cp = 0;
- h = utf8codepoint(h, &h_cp);
+ /* Get the next code point and track it */
+ const utf8_int8_t *nextH = haystack = utf8codepoint(haystack, &h_cp);
n = utf8codepoint(n, &n_cp);
while ((0 != h_cp) && (0 != n_cp)) {
h_cp = utf8lwrcodepoint(h_cp);
n_cp = utf8lwrcodepoint(n_cp);
- // if we find a mismatch, bail out!
+ /* if we find a mismatch, bail out! */
if (h_cp != n_cp) {
break;
}
- h = utf8codepoint(h, &h_cp);
+ haystack = utf8codepoint(haystack, &h_cp);
n = utf8codepoint(n, &n_cp);
}
if (0 == n_cp) {
- // we found the whole utf8 string for needle in haystack at
- // maybeMatch, so return it
- return (void *)maybeMatch;
+ /* we found the whole utf8 string for needle in haystack at
+ * maybeMatch, so return it */
+ return (utf8_int8_t *)maybeMatch;
}
if (0 == h_cp) {
- // no match
+ /* no match */
return utf8_null;
}
+
+ /* Roll back to the next code point in the haystack to test */
+ haystack = nextH;
}
}
-void *utf8valid(const void *str) {
- const char *s = (const char *)str;
+utf8_constexpr14_impl utf8_int8_t *utf8valid(const utf8_int8_t *str) {
+ return utf8nvalid(str, SIZE_MAX);
+}
+
+utf8_constexpr14_impl utf8_int8_t *utf8nvalid(const utf8_int8_t *str,
+ size_t n) {
+ const utf8_int8_t *t = str;
+ size_t consumed = 0;
+
+ while ((void)(consumed = (size_t)(str - t)), consumed < n && '\0' != *str) {
+ const size_t remaining = n - consumed;
+
+ if (0xf0 == (0xf8 & *str)) {
+ /* ensure that there's 4 bytes or more remaining */
+ if (remaining < 4) {
+ return (utf8_int8_t *)str;
+ }
+
+ /* ensure each of the 3 following bytes in this 4-byte
+ * utf8 codepoint began with 0b10xxxxxx */
+ if ((0x80 != (0xc0 & str[1])) || (0x80 != (0xc0 & str[2])) ||
+ (0x80 != (0xc0 & str[3]))) {
+ return (utf8_int8_t *)str;
+ }
+
+ /* ensure that our utf8 codepoint ended after 4 bytes */
+ if ((remaining != 4) && (0x80 == (0xc0 & str[4]))) {
+ return (utf8_int8_t *)str;
+ }
- while ('\0' != *s) {
- if (0xf0 == (0xf8 & *s)) {
- // ensure each of the 3 following bytes in this 4-byte
- // utf8 codepoint began with 0b10xxxxxx
- if ((0x80 != (0xc0 & s[1])) || (0x80 != (0xc0 & s[2])) ||
- (0x80 != (0xc0 & s[3]))) {
- return (void *)s;
+ /* ensure that the top 5 bits of this 4-byte utf8
+ * codepoint were not 0, as then we could have used
+ * one of the smaller encodings */
+ if ((0 == (0x07 & str[0])) && (0 == (0x30 & str[1]))) {
+ return (utf8_int8_t *)str;
}
- // ensure that our utf8 codepoint ended after 4 bytes
- if (0x80 == (0xc0 & s[4])) {
- return (void *)s;
+ /* 4-byte utf8 code point (began with 0b11110xxx) */
+ str += 4;
+ } else if (0xe0 == (0xf0 & *str)) {
+ /* ensure that there's 3 bytes or more remaining */
+ if (remaining < 3) {
+ return (utf8_int8_t *)str;
}
- // ensure that the top 5 bits of this 4-byte utf8
- // codepoint were not 0, as then we could have used
- // one of the smaller encodings
- if ((0 == (0x07 & s[0])) && (0 == (0x30 & s[1]))) {
- return (void *)s;
+ /* ensure each of the 2 following bytes in this 3-byte
+ * utf8 codepoint began with 0b10xxxxxx */
+ if ((0x80 != (0xc0 & str[1])) || (0x80 != (0xc0 & str[2]))) {
+ return (utf8_int8_t *)str;
}
- // 4-byte utf8 code point (began with 0b11110xxx)
- s += 4;
- } else if (0xe0 == (0xf0 & *s)) {
- // ensure each of the 2 following bytes in this 3-byte
- // utf8 codepoint began with 0b10xxxxxx
- if ((0x80 != (0xc0 & s[1])) || (0x80 != (0xc0 & s[2]))) {
- return (void *)s;
+ /* ensure that our utf8 codepoint ended after 3 bytes */
+ if ((remaining != 3) && (0x80 == (0xc0 & str[3]))) {
+ return (utf8_int8_t *)str;
}
- // ensure that our utf8 codepoint ended after 3 bytes
- if (0x80 == (0xc0 & s[3])) {
- return (void *)s;
+ /* ensure that the top 5 bits of this 3-byte utf8
+ * codepoint were not 0, as then we could have used
+ * one of the smaller encodings */
+ if ((0 == (0x0f & str[0])) && (0 == (0x20 & str[1]))) {
+ return (utf8_int8_t *)str;
}
- // ensure that the top 5 bits of this 3-byte utf8
- // codepoint were not 0, as then we could have used
- // one of the smaller encodings
- if ((0 == (0x0f & s[0])) && (0 == (0x20 & s[1]))) {
- return (void *)s;
+ /* 3-byte utf8 code point (began with 0b1110xxxx) */
+ str += 3;
+ } else if (0xc0 == (0xe0 & *str)) {
+ /* ensure that there's 2 bytes or more remaining */
+ if (remaining < 2) {
+ return (utf8_int8_t *)str;
}
- // 3-byte utf8 code point (began with 0b1110xxxx)
- s += 3;
- } else if (0xc0 == (0xe0 & *s)) {
- // ensure the 1 following byte in this 2-byte
- // utf8 codepoint began with 0b10xxxxxx
- if (0x80 != (0xc0 & s[1])) {
- return (void *)s;
+ /* ensure the 1 following byte in this 2-byte
+ * utf8 codepoint began with 0b10xxxxxx */
+ if (0x80 != (0xc0 & str[1])) {
+ return (utf8_int8_t *)str;
}
- // ensure that our utf8 codepoint ended after 2 bytes
- if (0x80 == (0xc0 & s[2])) {
- return (void *)s;
+ /* ensure that our utf8 codepoint ended after 2 bytes */
+ if ((remaining != 2) && (0x80 == (0xc0 & str[2]))) {
+ return (utf8_int8_t *)str;
}
- // ensure that the top 4 bits of this 2-byte utf8
- // codepoint were not 0, as then we could have used
- // one of the smaller encodings
- if (0 == (0x1e & s[0])) {
- return (void *)s;
+ /* ensure that the top 4 bits of this 2-byte utf8
+ * codepoint were not 0, as then we could have used
+ * one of the smaller encodings */
+ if (0 == (0x1e & str[0])) {
+ return (utf8_int8_t *)str;
}
- // 2-byte utf8 code point (began with 0b110xxxxx)
- s += 2;
- } else if (0x00 == (0x80 & *s)) {
- // 1-byte ascii (began with 0b0xxxxxxx)
- s += 1;
+ /* 2-byte utf8 code point (began with 0b110xxxxx) */
+ str += 2;
+ } else if (0x00 == (0x80 & *str)) {
+ /* 1-byte ascii (began with 0b0xxxxxxx) */
+ str += 1;
} else {
- // we have an invalid 0b1xxxxxxx utf8 code point entry
- return (void *)s;
+ /* we have an invalid 0b1xxxxxxx utf8 code point entry */
+ return (utf8_int8_t *)str;
}
}
return utf8_null;
}
-void *utf8codepoint(const void *utf8_restrict str,
- utf8_int32_t *utf8_restrict out_codepoint) {
- const char *s = (const char *)str;
+int utf8makevalid(utf8_int8_t *str, const utf8_int32_t replacement) {
+ utf8_int8_t *read = str;
+ utf8_int8_t *write = read;
+ const utf8_int8_t r = (utf8_int8_t)replacement;
+ utf8_int32_t codepoint = 0;
- if (0xf0 == (0xf8 & s[0])) {
- // 4 byte utf8 codepoint
- *out_codepoint = ((0x07 & s[0]) << 18) | ((0x3f & s[1]) << 12) |
- ((0x3f & s[2]) << 6) | (0x3f & s[3]);
- s += 4;
- } else if (0xe0 == (0xf0 & s[0])) {
- // 3 byte utf8 codepoint
+ if (replacement > 0x7f) {
+ return -1;
+ }
+
+ while ('\0' != *read) {
+ if (0xf0 == (0xf8 & *read)) {
+ /* ensure each of the 3 following bytes in this 4-byte
+ * utf8 codepoint began with 0b10xxxxxx */
+ if ((0x80 != (0xc0 & read[1])) || (0x80 != (0xc0 & read[2])) ||
+ (0x80 != (0xc0 & read[3]))) {
+ *write++ = r;
+ read++;
+ continue;
+ }
+
+ /* 4-byte utf8 code point (began with 0b11110xxx) */
+ read = utf8codepoint(read, &codepoint);
+ write = utf8catcodepoint(write, codepoint, 4);
+ } else if (0xe0 == (0xf0 & *read)) {
+ /* ensure each of the 2 following bytes in this 3-byte
+ * utf8 codepoint began with 0b10xxxxxx */
+ if ((0x80 != (0xc0 & read[1])) || (0x80 != (0xc0 & read[2]))) {
+ *write++ = r;
+ read++;
+ continue;
+ }
+
+ /* 3-byte utf8 code point (began with 0b1110xxxx) */
+ read = utf8codepoint(read, &codepoint);
+ write = utf8catcodepoint(write, codepoint, 3);
+ } else if (0xc0 == (0xe0 & *read)) {
+ /* ensure the 1 following byte in this 2-byte
+ * utf8 codepoint began with 0b10xxxxxx */
+ if (0x80 != (0xc0 & read[1])) {
+ *write++ = r;
+ read++;
+ continue;
+ }
+
+ /* 2-byte utf8 code point (began with 0b110xxxxx) */
+ read = utf8codepoint(read, &codepoint);
+ write = utf8catcodepoint(write, codepoint, 2);
+ } else if (0x00 == (0x80 & *read)) {
+ /* 1-byte ascii (began with 0b0xxxxxxx) */
+ read = utf8codepoint(read, &codepoint);
+ write = utf8catcodepoint(write, codepoint, 1);
+ } else {
+ /* if we got here then we've got a dangling continuation (0b10xxxxxx) */
+ *write++ = r;
+ read++;
+ continue;
+ }
+ }
+
+ *write = '\0';
+
+ return 0;
+}
+
+utf8_constexpr14_impl utf8_int8_t *
+utf8codepoint(const utf8_int8_t *utf8_restrict str,
+ utf8_int32_t *utf8_restrict out_codepoint) {
+ if (0xf0 == (0xf8 & str[0])) {
+ /* 4 byte utf8 codepoint */
+ *out_codepoint = ((0x07 & str[0]) << 18) | ((0x3f & str[1]) << 12) |
+ ((0x3f & str[2]) << 6) | (0x3f & str[3]);
+ str += 4;
+ } else if (0xe0 == (0xf0 & str[0])) {
+ /* 3 byte utf8 codepoint */
*out_codepoint =
- ((0x0f & s[0]) << 12) | ((0x3f & s[1]) << 6) | (0x3f & s[2]);
- s += 3;
- } else if (0xc0 == (0xe0 & s[0])) {
- // 2 byte utf8 codepoint
- *out_codepoint = ((0x1f & s[0]) << 6) | (0x3f & s[1]);
- s += 2;
+ ((0x0f & str[0]) << 12) | ((0x3f & str[1]) << 6) | (0x3f & str[2]);
+ str += 3;
+ } else if (0xc0 == (0xe0 & str[0])) {
+ /* 2 byte utf8 codepoint */
+ *out_codepoint = ((0x1f & str[0]) << 6) | (0x3f & str[1]);
+ str += 2;
} else {
- // 1 byte utf8 codepoint otherwise
- *out_codepoint = s[0];
- s += 1;
+ /* 1 byte utf8 codepoint otherwise */
+ *out_codepoint = str[0];
+ str += 1;
}
- return (void *)s;
+ return (utf8_int8_t *)str;
}
-size_t utf8codepointsize(utf8_int32_t chr) {
+utf8_constexpr14_impl size_t utf8codepointcalcsize(const utf8_int8_t *str) {
+ if (0xf0 == (0xf8 & str[0])) {
+ /* 4 byte utf8 codepoint */
+ return 4;
+ } else if (0xe0 == (0xf0 & str[0])) {
+ /* 3 byte utf8 codepoint */
+ return 3;
+ } else if (0xc0 == (0xe0 & str[0])) {
+ /* 2 byte utf8 codepoint */
+ return 2;
+ }
+
+ /* 1 byte utf8 codepoint otherwise */
+ return 1;
+}
+
+utf8_constexpr14_impl size_t utf8codepointsize(utf8_int32_t chr) {
if (0 == ((utf8_int32_t)0xffffff80 & chr)) {
return 1;
} else if (0 == ((utf8_int32_t)0xfffff800 & chr)) {
return 2;
} else if (0 == ((utf8_int32_t)0xffff0000 & chr)) {
return 3;
- } else { // if (0 == ((int)0xffe00000 & chr)) {
+ } else { /* if (0 == ((int)0xffe00000 & chr)) { */
return 4;
}
}
-void *utf8catcodepoint(void *utf8_restrict str, utf8_int32_t chr, size_t n) {
- char *s = (char *)str;
-
+utf8_int8_t *utf8catcodepoint(utf8_int8_t *str, utf8_int32_t chr, size_t n) {
if (0 == ((utf8_int32_t)0xffffff80 & chr)) {
- // 1-byte/7-bit ascii
- // (0b0xxxxxxx)
+ /* 1-byte/7-bit ascii
+ * (0b0xxxxxxx) */
if (n < 1) {
return utf8_null;
}
- s[0] = (char)chr;
- s += 1;
+ str[0] = (utf8_int8_t)chr;
+ str += 1;
} else if (0 == ((utf8_int32_t)0xfffff800 & chr)) {
- // 2-byte/11-bit utf8 code point
- // (0b110xxxxx 0b10xxxxxx)
+ /* 2-byte/11-bit utf8 code point
+ * (0b110xxxxx 0b10xxxxxx) */
if (n < 2) {
return utf8_null;
}
- s[0] = 0xc0 | (char)(chr >> 6);
- s[1] = 0x80 | (char)(chr & 0x3f);
- s += 2;
+ str[0] = (utf8_int8_t)(0xc0 | (utf8_int8_t)((chr >> 6) & 0x1f));
+ str[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
+ str += 2;
} else if (0 == ((utf8_int32_t)0xffff0000 & chr)) {
- // 3-byte/16-bit utf8 code point
- // (0b1110xxxx 0b10xxxxxx 0b10xxxxxx)
+ /* 3-byte/16-bit utf8 code point
+ * (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) */
if (n < 3) {
return utf8_null;
}
- s[0] = 0xe0 | (char)(chr >> 12);
- s[1] = 0x80 | (char)((chr >> 6) & 0x3f);
- s[2] = 0x80 | (char)(chr & 0x3f);
- s += 3;
- } else { // if (0 == ((int)0xffe00000 & chr)) {
- // 4-byte/21-bit utf8 code point
- // (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx)
+ str[0] = (utf8_int8_t)(0xe0 | (utf8_int8_t)((chr >> 12) & 0x0f));
+ str[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f));
+ str[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
+ str += 3;
+ } else { /* if (0 == ((int)0xffe00000 & chr)) { */
+ /* 4-byte/21-bit utf8 code point
+ * (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) */
if (n < 4) {
return utf8_null;
}
- s[0] = 0xf0 | (char)(chr >> 18);
- s[1] = 0x80 | (char)((chr >> 12) & 0x3f);
- s[2] = 0x80 | (char)((chr >> 6) & 0x3f);
- s[3] = 0x80 | (char)(chr & 0x3f);
- s += 4;
+ str[0] = (utf8_int8_t)(0xf0 | (utf8_int8_t)((chr >> 18) & 0x07));
+ str[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 12) & 0x3f));
+ str[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f));
+ str[3] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f));
+ str += 4;
}
- return s;
+ return str;
}
-int utf8islower(utf8_int32_t chr) { return chr != utf8uprcodepoint(chr); }
-
-int utf8isupper(utf8_int32_t chr) { return chr != utf8lwrcodepoint(chr); }
+utf8_constexpr14_impl int utf8islower(utf8_int32_t chr) {
+ return chr != utf8uprcodepoint(chr);
+}
-void utf8lwr(void *utf8_restrict str) {
- void *p, *pn;
- utf8_int32_t cp;
+utf8_constexpr14_impl int utf8isupper(utf8_int32_t chr) {
+ return chr != utf8lwrcodepoint(chr);
+}
- p = (char *)str;
- pn = utf8codepoint(p, &cp);
+void utf8lwr(utf8_int8_t *utf8_restrict str) {
+ utf8_int32_t cp = 0;
+ utf8_int8_t *pn = utf8codepoint(str, &cp);
while (cp != 0) {
const utf8_int32_t lwr_cp = utf8lwrcodepoint(cp);
const size_t size = utf8codepointsize(lwr_cp);
if (lwr_cp != cp) {
- utf8catcodepoint(p, lwr_cp, size);
+ utf8catcodepoint(str, lwr_cp, size);
}
- p = pn;
- pn = utf8codepoint(p, &cp);
+ str = pn;
+ pn = utf8codepoint(str, &cp);
}
}
-void utf8upr(void *utf8_restrict str) {
- void *p, *pn;
- utf8_int32_t cp;
-
- p = (char *)str;
- pn = utf8codepoint(p, &cp);
+void utf8upr(utf8_int8_t *utf8_restrict str) {
+ utf8_int32_t cp = 0;
+ utf8_int8_t *pn = utf8codepoint(str, &cp);
while (cp != 0) {
const utf8_int32_t lwr_cp = utf8uprcodepoint(cp);
const size_t size = utf8codepointsize(lwr_cp);
if (lwr_cp != cp) {
- utf8catcodepoint(p, lwr_cp, size);
+ utf8catcodepoint(str, lwr_cp, size);
}
- p = pn;
- pn = utf8codepoint(p, &cp);
+ str = pn;
+ pn = utf8codepoint(str, &cp);
}
}
-utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp) {
+utf8_constexpr14_impl utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp) {
if (((0x0041 <= cp) && (0x005a >= cp)) ||
((0x00c0 <= cp) && (0x00d6 >= cp)) ||
((0x00d8 <= cp) && (0x00de >= cp)) ||
((0x0391 <= cp) && (0x03a1 >= cp)) ||
- ((0x03a3 <= cp) && (0x03ab >= cp))) {
+ ((0x03a3 <= cp) && (0x03ab >= cp)) ||
+ ((0x0410 <= cp) && (0x042f >= cp))) {
cp += 32;
+ } else if ((0x0400 <= cp) && (0x040f >= cp)) {
+ cp += 80;
} else if (((0x0100 <= cp) && (0x012f >= cp)) ||
((0x0132 <= cp) && (0x0137 >= cp)) ||
((0x014a <= cp) && (0x0177 >= cp)) ||
@@ -1109,7 +1362,9 @@ utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp) {
((0x01f8 <= cp) && (0x021f >= cp)) ||
((0x0222 <= cp) && (0x0233 >= cp)) ||
((0x0246 <= cp) && (0x024f >= cp)) ||
- ((0x03d8 <= cp) && (0x03ef >= cp))) {
+ ((0x03d8 <= cp) && (0x03ef >= cp)) ||
+ ((0x0460 <= cp) && (0x0481 >= cp)) ||
+ ((0x048a <= cp) && (0x04ff >= cp))) {
cp |= 0x1;
} else if (((0x0139 <= cp) && (0x0148 >= cp)) ||
((0x0179 <= cp) && (0x017e >= cp)) ||
@@ -1120,62 +1375,147 @@ utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp) {
cp &= ~0x1;
} else {
switch (cp) {
- default: break;
- case 0x0178: cp = 0x00ff; break;
- case 0x0243: cp = 0x0180; break;
- case 0x018e: cp = 0x01dd; break;
- case 0x023d: cp = 0x019a; break;
- case 0x0220: cp = 0x019e; break;
- case 0x01b7: cp = 0x0292; break;
- case 0x01c4: cp = 0x01c6; break;
- case 0x01c7: cp = 0x01c9; break;
- case 0x01ca: cp = 0x01cc; break;
- case 0x01f1: cp = 0x01f3; break;
- case 0x01f7: cp = 0x01bf; break;
- case 0x0187: cp = 0x0188; break;
- case 0x018b: cp = 0x018c; break;
- case 0x0191: cp = 0x0192; break;
- case 0x0198: cp = 0x0199; break;
- case 0x01a7: cp = 0x01a8; break;
- case 0x01ac: cp = 0x01ad; break;
- case 0x01af: cp = 0x01b0; break;
- case 0x01b8: cp = 0x01b9; break;
- case 0x01bc: cp = 0x01bd; break;
- case 0x01f4: cp = 0x01f5; break;
- case 0x023b: cp = 0x023c; break;
- case 0x0241: cp = 0x0242; break;
- case 0x03fd: cp = 0x037b; break;
- case 0x03fe: cp = 0x037c; break;
- case 0x03ff: cp = 0x037d; break;
- case 0x037f: cp = 0x03f3; break;
- case 0x0386: cp = 0x03ac; break;
- case 0x0388: cp = 0x03ad; break;
- case 0x0389: cp = 0x03ae; break;
- case 0x038a: cp = 0x03af; break;
- case 0x038c: cp = 0x03cc; break;
- case 0x038e: cp = 0x03cd; break;
- case 0x038f: cp = 0x03ce; break;
- case 0x0370: cp = 0x0371; break;
- case 0x0372: cp = 0x0373; break;
- case 0x0376: cp = 0x0377; break;
- case 0x03f4: cp = 0x03d1; break;
- case 0x03cf: cp = 0x03d7; break;
- case 0x03f9: cp = 0x03f2; break;
- case 0x03f7: cp = 0x03f8; break;
- case 0x03fa: cp = 0x03fb; break;
- };
+ default:
+ break;
+ case 0x0178:
+ cp = 0x00ff;
+ break;
+ case 0x0243:
+ cp = 0x0180;
+ break;
+ case 0x018e:
+ cp = 0x01dd;
+ break;
+ case 0x023d:
+ cp = 0x019a;
+ break;
+ case 0x0220:
+ cp = 0x019e;
+ break;
+ case 0x01b7:
+ cp = 0x0292;
+ break;
+ case 0x01c4:
+ cp = 0x01c6;
+ break;
+ case 0x01c7:
+ cp = 0x01c9;
+ break;
+ case 0x01ca:
+ cp = 0x01cc;
+ break;
+ case 0x01f1:
+ cp = 0x01f3;
+ break;
+ case 0x01f7:
+ cp = 0x01bf;
+ break;
+ case 0x0187:
+ cp = 0x0188;
+ break;
+ case 0x018b:
+ cp = 0x018c;
+ break;
+ case 0x0191:
+ cp = 0x0192;
+ break;
+ case 0x0198:
+ cp = 0x0199;
+ break;
+ case 0x01a7:
+ cp = 0x01a8;
+ break;
+ case 0x01ac:
+ cp = 0x01ad;
+ break;
+ case 0x01b8:
+ cp = 0x01b9;
+ break;
+ case 0x01bc:
+ cp = 0x01bd;
+ break;
+ case 0x01f4:
+ cp = 0x01f5;
+ break;
+ case 0x023b:
+ cp = 0x023c;
+ break;
+ case 0x0241:
+ cp = 0x0242;
+ break;
+ case 0x03fd:
+ cp = 0x037b;
+ break;
+ case 0x03fe:
+ cp = 0x037c;
+ break;
+ case 0x03ff:
+ cp = 0x037d;
+ break;
+ case 0x037f:
+ cp = 0x03f3;
+ break;
+ case 0x0386:
+ cp = 0x03ac;
+ break;
+ case 0x0388:
+ cp = 0x03ad;
+ break;
+ case 0x0389:
+ cp = 0x03ae;
+ break;
+ case 0x038a:
+ cp = 0x03af;
+ break;
+ case 0x038c:
+ cp = 0x03cc;
+ break;
+ case 0x038e:
+ cp = 0x03cd;
+ break;
+ case 0x038f:
+ cp = 0x03ce;
+ break;
+ case 0x0370:
+ cp = 0x0371;
+ break;
+ case 0x0372:
+ cp = 0x0373;
+ break;
+ case 0x0376:
+ cp = 0x0377;
+ break;
+ case 0x03f4:
+ cp = 0x03b8;
+ break;
+ case 0x03cf:
+ cp = 0x03d7;
+ break;
+ case 0x03f9:
+ cp = 0x03f2;
+ break;
+ case 0x03f7:
+ cp = 0x03f8;
+ break;
+ case 0x03fa:
+ cp = 0x03fb;
+ break;
+ }
}
return cp;
}
-utf8_int32_t utf8uprcodepoint(utf8_int32_t cp) {
+utf8_constexpr14_impl utf8_int32_t utf8uprcodepoint(utf8_int32_t cp) {
if (((0x0061 <= cp) && (0x007a >= cp)) ||
((0x00e0 <= cp) && (0x00f6 >= cp)) ||
((0x00f8 <= cp) && (0x00fe >= cp)) ||
((0x03b1 <= cp) && (0x03c1 >= cp)) ||
- ((0x03c3 <= cp) && (0x03cb >= cp))) {
+ ((0x03c3 <= cp) && (0x03cb >= cp)) ||
+ ((0x0430 <= cp) && (0x044f >= cp))) {
cp -= 32;
+ } else if ((0x0450 <= cp) && (0x045f >= cp)) {
+ cp -= 80;
} else if (((0x0100 <= cp) && (0x012f >= cp)) ||
((0x0132 <= cp) && (0x0137 >= cp)) ||
((0x014a <= cp) && (0x0177 >= cp)) ||
@@ -1185,7 +1525,9 @@ utf8_int32_t utf8uprcodepoint(utf8_int32_t cp) {
((0x01f8 <= cp) && (0x021f >= cp)) ||
((0x0222 <= cp) && (0x0233 >= cp)) ||
((0x0246 <= cp) && (0x024f >= cp)) ||
- ((0x03d8 <= cp) && (0x03ef >= cp))) {
+ ((0x03d8 <= cp) && (0x03ef >= cp)) ||
+ ((0x0460 <= cp) && (0x0481 >= cp)) ||
+ ((0x048a <= cp) && (0x04ff >= cp))) {
cp &= ~0x1;
} else if (((0x0139 <= cp) && (0x0148 >= cp)) ||
((0x0179 <= cp) && (0x017e >= cp)) ||
@@ -1196,64 +1538,175 @@ utf8_int32_t utf8uprcodepoint(utf8_int32_t cp) {
cp |= 0x1;
} else {
switch (cp) {
- default: break;
- case 0x00ff: cp = 0x0178; break;
- case 0x0180: cp = 0x0243; break;
- case 0x01dd: cp = 0x018e; break;
- case 0x019a: cp = 0x023d; break;
- case 0x019e: cp = 0x0220; break;
- case 0x0292: cp = 0x01b7; break;
- case 0x01c6: cp = 0x01c4; break;
- case 0x01c9: cp = 0x01c7; break;
- case 0x01cc: cp = 0x01ca; break;
- case 0x01f3: cp = 0x01f1; break;
- case 0x01bf: cp = 0x01f7; break;
- case 0x0188: cp = 0x0187; break;
- case 0x018c: cp = 0x018b; break;
- case 0x0192: cp = 0x0191; break;
- case 0x0199: cp = 0x0198; break;
- case 0x01a8: cp = 0x01a7; break;
- case 0x01ad: cp = 0x01ac; break;
- case 0x01b0: cp = 0x01af; break;
- case 0x01b9: cp = 0x01b8; break;
- case 0x01bd: cp = 0x01bc; break;
- case 0x01f5: cp = 0x01f4; break;
- case 0x023c: cp = 0x023b; break;
- case 0x0242: cp = 0x0241; break;
- case 0x037b: cp = 0x03fd; break;
- case 0x037c: cp = 0x03fe; break;
- case 0x037d: cp = 0x03ff; break;
- case 0x03f3: cp = 0x037f; break;
- case 0x03ac: cp = 0x0386; break;
- case 0x03ad: cp = 0x0388; break;
- case 0x03ae: cp = 0x0389; break;
- case 0x03af: cp = 0x038a; break;
- case 0x03cc: cp = 0x038c; break;
- case 0x03cd: cp = 0x038e; break;
- case 0x03ce: cp = 0x038f; break;
- case 0x0371: cp = 0x0370; break;
- case 0x0373: cp = 0x0372; break;
- case 0x0377: cp = 0x0376; break;
- case 0x03d1: cp = 0x03f4; break;
- case 0x03d7: cp = 0x03cf; break;
- case 0x03f2: cp = 0x03f9; break;
- case 0x03f8: cp = 0x03f7; break;
- case 0x03fb: cp = 0x03fa; break;
- };
+ default:
+ break;
+ case 0x00ff:
+ cp = 0x0178;
+ break;
+ case 0x0180:
+ cp = 0x0243;
+ break;
+ case 0x01dd:
+ cp = 0x018e;
+ break;
+ case 0x019a:
+ cp = 0x023d;
+ break;
+ case 0x019e:
+ cp = 0x0220;
+ break;
+ case 0x0292:
+ cp = 0x01b7;
+ break;
+ case 0x01c6:
+ cp = 0x01c4;
+ break;
+ case 0x01c9:
+ cp = 0x01c7;
+ break;
+ case 0x01cc:
+ cp = 0x01ca;
+ break;
+ case 0x01f3:
+ cp = 0x01f1;
+ break;
+ case 0x01bf:
+ cp = 0x01f7;
+ break;
+ case 0x0188:
+ cp = 0x0187;
+ break;
+ case 0x018c:
+ cp = 0x018b;
+ break;
+ case 0x0192:
+ cp = 0x0191;
+ break;
+ case 0x0199:
+ cp = 0x0198;
+ break;
+ case 0x01a8:
+ cp = 0x01a7;
+ break;
+ case 0x01ad:
+ cp = 0x01ac;
+ break;
+ case 0x01b9:
+ cp = 0x01b8;
+ break;
+ case 0x01bd:
+ cp = 0x01bc;
+ break;
+ case 0x01f5:
+ cp = 0x01f4;
+ break;
+ case 0x023c:
+ cp = 0x023b;
+ break;
+ case 0x0242:
+ cp = 0x0241;
+ break;
+ case 0x037b:
+ cp = 0x03fd;
+ break;
+ case 0x037c:
+ cp = 0x03fe;
+ break;
+ case 0x037d:
+ cp = 0x03ff;
+ break;
+ case 0x03f3:
+ cp = 0x037f;
+ break;
+ case 0x03ac:
+ cp = 0x0386;
+ break;
+ case 0x03ad:
+ cp = 0x0388;
+ break;
+ case 0x03ae:
+ cp = 0x0389;
+ break;
+ case 0x03af:
+ cp = 0x038a;
+ break;
+ case 0x03cc:
+ cp = 0x038c;
+ break;
+ case 0x03cd:
+ cp = 0x038e;
+ break;
+ case 0x03ce:
+ cp = 0x038f;
+ break;
+ case 0x0371:
+ cp = 0x0370;
+ break;
+ case 0x0373:
+ cp = 0x0372;
+ break;
+ case 0x0377:
+ cp = 0x0376;
+ break;
+ case 0x03d1:
+ cp = 0x0398;
+ break;
+ case 0x03d7:
+ cp = 0x03cf;
+ break;
+ case 0x03f2:
+ cp = 0x03f9;
+ break;
+ case 0x03f8:
+ cp = 0x03f7;
+ break;
+ case 0x03fb:
+ cp = 0x03fa;
+ break;
+ }
}
return cp;
}
+utf8_constexpr14_impl utf8_int8_t *
+utf8rcodepoint(const utf8_int8_t *utf8_restrict str,
+ utf8_int32_t *utf8_restrict out_codepoint) {
+ const utf8_int8_t *s = (const utf8_int8_t *)str;
+
+ if (0xf0 == (0xf8 & s[0])) {
+ /* 4 byte utf8 codepoint */
+ *out_codepoint = ((0x07 & s[0]) << 18) | ((0x3f & s[1]) << 12) |
+ ((0x3f & s[2]) << 6) | (0x3f & s[3]);
+ } else if (0xe0 == (0xf0 & s[0])) {
+ /* 3 byte utf8 codepoint */
+ *out_codepoint =
+ ((0x0f & s[0]) << 12) | ((0x3f & s[1]) << 6) | (0x3f & s[2]);
+ } else if (0xc0 == (0xe0 & s[0])) {
+ /* 2 byte utf8 codepoint */
+ *out_codepoint = ((0x1f & s[0]) << 6) | (0x3f & s[1]);
+ } else {
+ /* 1 byte utf8 codepoint otherwise */
+ *out_codepoint = s[0];
+ }
+
+ do {
+ s--;
+ } while ((0 != (0x80 & s[0])) && (0x80 == (0xc0 & s[0])));
+
+ return (utf8_int8_t *)s;
+}
+
#undef utf8_restrict
+#undef utf8_constexpr14
#undef utf8_null
-#ifdef __cplusplus
-} // extern "C"
+#ifdef utf8_cplusplus
+} /* extern "C" */
#endif
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
-#endif // SHEREDOM_UTF8_H_INCLUDED
+#endif /* SHEREDOM_UTF8_H_INCLUDED */