aboutsummaryrefslogtreecommitdiffstats
path: root/libcharconv_marchen.c
diff options
context:
space:
mode:
Diffstat (limited to 'libcharconv_marchen.c')
-rw-r--r--libcharconv_marchen.c134
1 files changed, 134 insertions, 0 deletions
diff --git a/libcharconv_marchen.c b/libcharconv_marchen.c
new file mode 100644
index 0000000..12fc414
--- /dev/null
+++ b/libcharconv_marchen.c
@@ -0,0 +1,134 @@
+/* See LICENSE file for copyright and license details. */
+#include "lib-common.h"
+
+
+enum libcharconv_result
+libcharconv_marchen(const char *s, size_t slen, size_t *n, uint_least32_t *cp, size_t *ncp)
+{
+ static const char *const letters = "kKgGcCjYtTdnpPbmxXDwZz-yrlSsh";
+ uint_least32_t c, c2, c3;
+ size_t i;
+ *n = 0;
+ for (; slen--; s++) {
+ PLAIN_SELECT(letters, 0x11C72);
+ switch (s[0]) {
+ case 'a': c = UINT32_C(0x11C8F); goto conv1_subjoinable;
+ case 'A': c = UINT32_C(0x11CB0); goto conv_vowel;
+ case 'i': c = UINT32_C(0x11CB1); goto conv_vowel;
+ case 'u': c = UINT32_C(0x11CB2); goto conv_vowel;
+ case 'e': c = UINT32_C(0x11CB3); goto conv_vowel;
+ case 'o': c = UINT32_C(0x11CB4); goto conv_vowel;
+ case '\'': c = UINT32_C(0x11CB5); goto conv1;
+ case '\"': c = UINT32_C(0x11CB6); goto conv1;
+ case '.': c = UINT32_C(0x11C70); goto conv1;
+ case ':': c = UINT32_C(0x11C71); goto conv1;
+ case '^':
+ if (!slen)
+ return LIBCHARCONV_INDETERMINATE;
+ switch (s[1]) {
+ case 'A': c = UINT32_C(0x11CB0); goto conv2;
+ case 'i': c = UINT32_C(0x11CB1); goto conv2;
+ case 'u': c = UINT32_C(0x11CB2); goto conv2;
+ case 'e': c = UINT32_C(0x11CB3); goto conv2;
+ case 'o': c = UINT32_C(0x11CB4); goto conv2;
+ default:
+ goto no_match;
+ }
+ case '_':
+ if (*n)
+ goto no_conv;
+ *n += 1u;
+ break;
+ default:
+ no_match:
+ *n += 1u;
+ break;
+ }
+ }
+no_conv:
+ return LIBCHARCONV_NO_CONVERT;
+
+conv:
+ if (*n == 1u && s[-1] == '_' && c != UINT32_C(0x11C88)) {
+ c += 0x20u;
+ goto conv1_prechecked;
+ }
+ if (*n)
+ goto no_conv;
+ if (!slen)
+ return LIBCHARCONV_INDETERMINATE;
+ for (i = 0u; letters[i]; i++)
+ if (letters[i] == s[1])
+ break;
+ c3 = (letters[i] && letters[i] != '-') ? (uint_least32_t)(UINT32_C(0x11C92) + i) : 0u;
+ if (c3 && slen == 1u)
+ return LIBCHARCONV_INDETERMINATE;
+ switch (s[c3 ? 2 : 1]) {
+ case 'a':
+ if (c3)
+ goto conv3_prechecked;
+ else
+ goto conv2_prechecked;
+ case 'A': c2 = UINT32_C(0x11CB0); break;
+ case 'i': c2 = UINT32_C(0x11CB1); break;
+ case 'u': c2 = UINT32_C(0x11CB2); break;
+ case 'e': c2 = UINT32_C(0x11CB3); break;
+ case 'o': c2 = UINT32_C(0x11CB4); break;
+ default:
+ goto no_match;
+ }
+ if (*ncp >= 1u)
+ cp[0] = c;
+ if (*ncp >= 2u)
+ cp[1] = c2;
+ if (c3 && *ncp >= 3u)
+ cp[2] = c3;
+ *n += c3 ? 3u : 2u;
+ *ncp = c3 ? 3u : 2u;
+ return LIBCHARCONV_CONVERTED;
+
+conv1_subjoinable:
+ if (*n == 1u && s[-1] == '_') {
+ c += 0x20u;
+ } else {
+ conv1:
+ if (*n)
+ goto no_conv;
+ }
+conv1_prechecked:
+ if (*ncp)
+ *cp = c;
+ *n += 1u;
+ *ncp = 1u;
+ return LIBCHARCONV_CONVERTED;
+
+conv2:
+ if (*n)
+ goto no_conv;
+conv2_prechecked:
+ if (*ncp)
+ cp[0] = c;
+ *n += 2u;
+ *ncp = 1u;
+ return LIBCHARCONV_CONVERTED;
+
+conv_vowel:
+ if (*n)
+ goto no_conv;
+ if (*ncp >= 1u)
+ cp[0] = UINT32_C(0x11C8F) + (s[-1] == '_' ? 0x20u : 0u);
+ if (*ncp >= 2u)
+ cp[1] = c;
+ *n += 1u;
+ *ncp = 2u;
+ return LIBCHARCONV_CONVERTED;
+
+conv3_prechecked:
+ if (*ncp >= 1u)
+ cp[0] = c;
+ if (*ncp >= 2u)
+ cp[1] = c3;
+ *n += 3u;
+ *ncp = 2u;
+ return LIBCHARCONV_CONVERTED;
+}