diff --git a/test/misc.c b/test/misc.c index 03834cc..cacd46b 100644 --- a/test/misc.c +++ b/test/misc.c @@ -87,12 +87,31 @@ static void issue288(void) /* #288 */ printf("PASSED: utf8proc_normalize_utf32 preserves uninterpretable codepoints\n"); } +/* UTF8PROC_CHARBOUND must still mark grapheme breaks around Hangul + syllables that are decomposed by UTF8PROC_COMPOSE or UTF8PROC_DECOMPOSE */ +static void hangul_charbound(void) +{ + utf8proc_uint8_t input[] = {0x0d, 0xea, 0xb0, 0x80, 0xea, 0xb0, 0x81, 0x0a, 0x00}; /* "\r가각\n" */ + utf8proc_uint8_t charbound[] = {0xff, 0x0d, 0xff, 0xea, 0xb0, 0x80, 0xff, 0xea, 0xb0, 0x81, 0xff, 0x0a, 0x00}; + utf8proc_uint8_t nfd[] = {0xff, 0x0d, 0xff, 0xe1, 0x84, 0x80, 0xe1, 0x85, 0xa1, + 0xff, 0xe1, 0x84, 0x80, 0xe1, 0x85, 0xa1, 0xe1, 0x86, 0xa8, 0xff, 0x0a, 0x00}; + utf8proc_uint8_t *output; + + utf8proc_map(input, 0, &output, UTF8PROC_NULLTERM | UTF8PROC_CHARBOUND); + check_compare("CHARBOUND", input, charbound, output, 1); + utf8proc_map(input, 0, &output, UTF8PROC_NULLTERM | UTF8PROC_STABLE | UTF8PROC_COMPOSE | UTF8PROC_CHARBOUND); + check_compare("NFC+CHARBOUND", input, charbound, output, 1); + utf8proc_map(input, 0, &output, UTF8PROC_NULLTERM | UTF8PROC_STABLE | UTF8PROC_DECOMPOSE | UTF8PROC_CHARBOUND); + check_compare("NFD+CHARBOUND", input, nfd, output, 1); +} + int main(void) { issue128(); issue102(); issue317(); issue288(); + hangul_charbound(); #ifdef UNICODE_VERSION printf("Unicode version: Makefile has %s, has API %s\n", UNICODE_VERSION, utf8proc_unicode_version()); check(!strcmp(UNICODE_VERSION, utf8proc_unicode_version()), "utf8proc_unicode_version mismatch"); diff --git a/utf8proc.c b/utf8proc.c index 87091ba..6b4522f 100644 --- a/utf8proc.c +++ b/utf8proc.c @@ -453,6 +453,16 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc, if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) { if (hangul_sindex >= 0 && hangul_sindex < UTF8PROC_HANGUL_SCOUNT) { utf8proc_int32_t hangul_tindex; + /* the jamo never break among themselves (GB6-GB8), and the syllable's + LV/LVT boundclass breaks and updates the state just like they do */ + if ((options & UTF8PROC_CHARBOUND) && + grapheme_break_extended(0, property->boundclass, 0, property->indic_conjunct_break, + last_boundclass)) { + if (bufsize >= 1) dst[0] = -1; /* sentinel value for grapheme break */ + return 1 + utf8proc_decompose_char(uc, (bufsize >= 1) ? dst+1 : dst, + (bufsize >= 1) ? bufsize-1 : 0, options & ~(unsigned int)UTF8PROC_CHARBOUND, + last_boundclass); + } if (bufsize >= 1) { dst[0] = UTF8PROC_HANGUL_LBASE + hangul_sindex / UTF8PROC_HANGUL_NCOUNT;