/* See LICENSE file for copyright and license details. */ #include "lib-common.h" static struct { uint_least32_t a; uint_least32_t b; uint_least32_t to; } pairs[] = { {(uint_least32_t)'?', (uint_least32_t)'!', UINT32_C(0x2048)}, {(uint_least32_t)'?', (uint_least32_t)'?', UINT32_C(0x2047)}, {(uint_least32_t)'!', (uint_least32_t)'!', UINT32_C(0x203C)}, {(uint_least32_t)'!', (uint_least32_t)'?', UINT32_C(0x2049)}, {(uint_least32_t)':', (uint_least32_t)':', UINT32_C(0x2E2C)}, {(uint_least32_t)'|', (uint_least32_t)'|', UINT32_C(0x2016)}, {UINT32_C(0x23CB), UINT32_C(0x23BE), UINT32_C(0x23C9)}, {UINT32_C(0x23CC), UINT32_C(0x23BF), UINT32_C(0x23CA)} }; enum libcharconv_result libcharconv_joined(const char *s, size_t slen, size_t *n, uint_least32_t *cp, size_t *ncp) { uint_least32_t a, b, c; size_t i, alen, blen; *n = 0; while (slen) { alen = libcharconv_decode_utf8_(s, slen, &a); if (alen > slen) { if (*n) goto no_conv; return LIBCHARCONV_INDETERMINATE; } if (!alen) { *n += 1u; slen -= 1u; s = &s[1]; continue; } if (UINT32_C(0x1681) <= a && a <= UINT32_C(0x1694)) { if (*n) goto no_conv; if (slen == alen) return LIBCHARCONV_INDETERMINATE; blen = libcharconv_decode_utf8_(&s[alen], slen - alen, &b); if (blen > slen) return LIBCHARCONV_INDETERMINATE; if (!blen) goto no_conv; if (UINT32_C(0x1681) > b || b > UINT32_C(0x1694)) goto no_conv_consume; if ((a - UINT32_C(0x1681)) / 5u != (b - UINT32_C(0x1681)) / 5u) goto no_conv_consume; c = (a - UINT32_C(0x1681)) % 5u + (b - UINT32_C(0x1681)) % 5u + 1u; if (c >= 5u) goto no_conv_consume; a = c += (a - UINT32_C(0x1681)) / 5u * 5u + UINT32_C(0x1681); alen += blen; for (;;) { if (slen == alen) goto conv_if_end_calc; blen = libcharconv_decode_utf8_(&s[alen], slen - alen, &b); if (blen > slen) return LIBCHARCONV_INDETERMINATE; if (!blen) goto conv_calc; if (UINT32_C(0x1681) > b || b > UINT32_C(0x1694)) goto conv_calc; if ((a - UINT32_C(0x1681)) / 5u != (b - UINT32_C(0x1681)) / 5u) goto conv_calc; b = (a - UINT32_C(0x1681)) % 5u + (b - UINT32_C(0x1681)) % 5u + 1u; if (b >= 5u) goto conv_calc; a = c = b + (a - UINT32_C(0x1681)) / 5u * 5u + UINT32_C(0x1681); alen += blen; } goto conv_calc; } for (i = 0u; i < sizeof(pairs) / sizeof(*pairs); i++) { if (a != pairs[i].a) continue; if (*n) goto no_conv; if (slen == alen) return LIBCHARCONV_INDETERMINATE; blen = libcharconv_decode_utf8_(&s[alen], slen - alen, &b); if (blen > slen) return LIBCHARCONV_INDETERMINATE; if (!blen) goto no_conv; if (b == pairs[i].b) goto conv; } *n += alen; s = &s[alen]; slen -= alen; } no_conv: return LIBCHARCONV_NO_CONVERT; no_conv_consume: *n += alen; return LIBCHARCONV_NO_CONVERT; conv: if (*n) goto no_conv; if (*ncp) *cp = c = pairs[i].to; *n += alen + blen; *ncp = 1u; return LIBCHARCONV_CONVERTED; conv_calc: if (*n) goto no_conv; if (*ncp) *cp = c; *n += alen; *ncp = 1u; return LIBCHARCONV_CONVERTED; conv_if_end_calc: if (*n) goto no_conv; if (*ncp) *cp = c; *n += alen; *ncp = 1u; return LIBCHARCONV_CONVERT_IF_END; }