/* 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; }