Initial Commit
This commit is contained in:
510
libs/libgrapheme-2.0.2/src/line.c
Normal file
510
libs/libgrapheme-2.0.2/src/line.c
Normal file
@@ -0,0 +1,510 @@
|
||||
/* See LICENSE file for copyright and license details. */
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "../gen/line.h"
|
||||
#include "../grapheme.h"
|
||||
#include "util.h"
|
||||
|
||||
static inline enum line_break_property
|
||||
get_break_prop(uint_least32_t cp)
|
||||
{
|
||||
if (likely(cp <= UINT32_C(0x10FFFF))) {
|
||||
return (enum line_break_property)
|
||||
line_break_minor[line_break_major[cp >> 8] + (cp & 0xff)];
|
||||
} else {
|
||||
return LINE_BREAK_PROP_AL;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t
|
||||
next_line_break(HERODOTUS_READER *r)
|
||||
{
|
||||
HERODOTUS_READER tmp;
|
||||
enum line_break_property cp0_prop, cp1_prop, last_non_cm_or_zwj_prop,
|
||||
last_non_sp_prop, last_non_sp_cm_or_zwj_prop;
|
||||
uint_least32_t cp;
|
||||
uint_least8_t lb25_level = 0;
|
||||
bool lb21a_flag = false, ri_even = true;
|
||||
|
||||
/*
|
||||
* Apply line breaking algorithm (UAX #14), see
|
||||
* https://unicode.org/reports/tr14/#Algorithm and tailoring
|
||||
* https://unicode.org/reports/tr14/#Examples (example 7),
|
||||
* given the automatic test-cases implement this example for
|
||||
* better number handling.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initialize the different properties such that we have
|
||||
* a good state after the state-update in the loop
|
||||
*/
|
||||
last_non_cm_or_zwj_prop = LINE_BREAK_PROP_AL; /* according to LB10 */
|
||||
last_non_sp_prop = last_non_sp_cm_or_zwj_prop = NUM_LINE_BREAK_PROPS;
|
||||
|
||||
for (herodotus_read_codepoint(r, true, &cp), cp0_prop = get_break_prop(cp);
|
||||
herodotus_read_codepoint(r, false, &cp) == HERODOTUS_STATUS_SUCCESS;
|
||||
herodotus_read_codepoint(r, true, &cp), cp0_prop = cp1_prop) {
|
||||
/* get property of the right codepoint */
|
||||
cp1_prop = get_break_prop(cp);
|
||||
|
||||
/* update retention-states */
|
||||
|
||||
/*
|
||||
* store the last observed non-CM-or-ZWJ-property for
|
||||
* LB9 and following.
|
||||
*/
|
||||
if (cp0_prop != LINE_BREAK_PROP_CM &&
|
||||
cp0_prop != LINE_BREAK_PROP_ZWJ) {
|
||||
/*
|
||||
* check if the property we are overwriting now is an
|
||||
* HL. If so, we set the LB21a-flag which depends on this
|
||||
* knowledge.
|
||||
*/
|
||||
lb21a_flag = (last_non_cm_or_zwj_prop == LINE_BREAK_PROP_HL);
|
||||
|
||||
/* check regional indicator state */
|
||||
if (cp0_prop == LINE_BREAK_PROP_RI) {
|
||||
/*
|
||||
* The property we just shifted in is
|
||||
* a regional indicator, increasing the
|
||||
* number of consecutive RIs on the left
|
||||
* side of the breakpoint by one, changing
|
||||
* the oddness.
|
||||
*
|
||||
*/
|
||||
ri_even = !ri_even;
|
||||
} else {
|
||||
/*
|
||||
* We saw no regional indicator, so the
|
||||
* number of consecutive RIs on the left
|
||||
* side of the breakpoint is zero, which
|
||||
* is an even number.
|
||||
*
|
||||
*/
|
||||
ri_even = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Here comes a bit of magic. The tailored rule
|
||||
* LB25 (using example 7) has a very complicated
|
||||
* left-hand-side-rule of the form
|
||||
*
|
||||
* NU (NU | SY | IS)* (CL | CP)?
|
||||
*
|
||||
* but instead of backtracking, we keep the state
|
||||
* as some kind of "power level" in the variable
|
||||
*
|
||||
* lb25_level
|
||||
*
|
||||
* that goes from 0 to 3
|
||||
*
|
||||
* 0: we are not in the sequence
|
||||
* 1: we have one NU to the left of the middle
|
||||
* spot
|
||||
* 2: we have one NU and one or more (NU | SY | IS)
|
||||
* to the left of the middle spot
|
||||
* 3: we have one NU, zero or more (NU | SY | IS)
|
||||
* and one (CL | CP) to the left of the middle
|
||||
* spot
|
||||
*/
|
||||
if ((lb25_level == 0 ||
|
||||
lb25_level == 1) &&
|
||||
cp0_prop == LINE_BREAK_PROP_NU) {
|
||||
/* sequence has begun */
|
||||
lb25_level = 1;
|
||||
} else if ((lb25_level == 1 || lb25_level == 2) &&
|
||||
(cp0_prop == LINE_BREAK_PROP_NU ||
|
||||
cp0_prop == LINE_BREAK_PROP_SY ||
|
||||
cp0_prop == LINE_BREAK_PROP_IS)) {
|
||||
/* (NU | SY | IS) sequence begins or continued */
|
||||
lb25_level = 2;
|
||||
} else if ((lb25_level == 1 || lb25_level == 2) &&
|
||||
(cp0_prop == LINE_BREAK_PROP_CL ||
|
||||
cp0_prop == LINE_BREAK_PROP_CP_WITHOUT_EAW_HWF ||
|
||||
cp0_prop == LINE_BREAK_PROP_CP_WITH_EAW_HWF)) {
|
||||
/* CL or CP at the end of the sequence */
|
||||
lb25_level = 3;
|
||||
} else {
|
||||
/* sequence broke */
|
||||
lb25_level = 0;
|
||||
}
|
||||
|
||||
last_non_cm_or_zwj_prop = cp0_prop;
|
||||
}
|
||||
|
||||
/*
|
||||
* store the last observed non-SP-property for LB8, LB14,
|
||||
* LB15, LB16 and LB17. LB8 gets its own unskipped property,
|
||||
* whereas the others build on top of the CM-ZWJ-skipped
|
||||
* properties as they come after LB9
|
||||
*/
|
||||
if (cp0_prop != LINE_BREAK_PROP_SP) {
|
||||
last_non_sp_prop = cp0_prop;
|
||||
}
|
||||
if (last_non_cm_or_zwj_prop != LINE_BREAK_PROP_SP) {
|
||||
last_non_sp_cm_or_zwj_prop = last_non_cm_or_zwj_prop;
|
||||
}
|
||||
|
||||
/* apply the algorithm */
|
||||
|
||||
/* LB4 */
|
||||
if (cp0_prop == LINE_BREAK_PROP_BK) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* LB5 */
|
||||
if (cp0_prop == LINE_BREAK_PROP_CR &&
|
||||
cp1_prop == LINE_BREAK_PROP_LF) {
|
||||
continue;
|
||||
}
|
||||
if (cp0_prop == LINE_BREAK_PROP_CR ||
|
||||
cp0_prop == LINE_BREAK_PROP_LF ||
|
||||
cp0_prop == LINE_BREAK_PROP_NL) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* LB6 */
|
||||
if (cp1_prop == LINE_BREAK_PROP_BK ||
|
||||
cp1_prop == LINE_BREAK_PROP_CR ||
|
||||
cp1_prop == LINE_BREAK_PROP_LF ||
|
||||
cp1_prop == LINE_BREAK_PROP_NL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB7 */
|
||||
if (cp1_prop == LINE_BREAK_PROP_SP ||
|
||||
cp1_prop == LINE_BREAK_PROP_ZW) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB8 */
|
||||
if (last_non_sp_prop == LINE_BREAK_PROP_ZW) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* LB8a */
|
||||
if (cp0_prop == LINE_BREAK_PROP_ZWJ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB9 */
|
||||
if ((cp0_prop != LINE_BREAK_PROP_BK &&
|
||||
cp0_prop != LINE_BREAK_PROP_CR &&
|
||||
cp0_prop != LINE_BREAK_PROP_LF &&
|
||||
cp0_prop != LINE_BREAK_PROP_NL &&
|
||||
cp0_prop != LINE_BREAK_PROP_SP &&
|
||||
cp0_prop != LINE_BREAK_PROP_ZW) &&
|
||||
(cp1_prop == LINE_BREAK_PROP_CM ||
|
||||
cp1_prop == LINE_BREAK_PROP_ZWJ)) {
|
||||
/*
|
||||
* given we skip them, we don't break in such
|
||||
* a sequence
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB10 is baked into the following rules */
|
||||
|
||||
/* LB11 */
|
||||
if (last_non_cm_or_zwj_prop == LINE_BREAK_PROP_WJ ||
|
||||
cp1_prop == LINE_BREAK_PROP_WJ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB12 */
|
||||
if (last_non_cm_or_zwj_prop == LINE_BREAK_PROP_GL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB12a */
|
||||
if ((last_non_cm_or_zwj_prop != LINE_BREAK_PROP_SP &&
|
||||
last_non_cm_or_zwj_prop != LINE_BREAK_PROP_BA &&
|
||||
last_non_cm_or_zwj_prop != LINE_BREAK_PROP_HY) &&
|
||||
cp1_prop == LINE_BREAK_PROP_GL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB13 (affected by tailoring for LB25, see example 7) */
|
||||
if (cp1_prop == LINE_BREAK_PROP_EX ||
|
||||
(last_non_cm_or_zwj_prop != LINE_BREAK_PROP_NU &&
|
||||
(cp1_prop == LINE_BREAK_PROP_CL ||
|
||||
cp1_prop == LINE_BREAK_PROP_CP_WITHOUT_EAW_HWF ||
|
||||
cp1_prop == LINE_BREAK_PROP_CP_WITH_EAW_HWF ||
|
||||
cp1_prop == LINE_BREAK_PROP_IS ||
|
||||
cp1_prop == LINE_BREAK_PROP_SY))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB14 */
|
||||
if (last_non_sp_cm_or_zwj_prop == LINE_BREAK_PROP_OP_WITHOUT_EAW_HWF ||
|
||||
last_non_sp_cm_or_zwj_prop == LINE_BREAK_PROP_OP_WITH_EAW_HWF) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB15 */
|
||||
if (last_non_sp_cm_or_zwj_prop == LINE_BREAK_PROP_QU &&
|
||||
(cp1_prop == LINE_BREAK_PROP_OP_WITHOUT_EAW_HWF ||
|
||||
cp1_prop == LINE_BREAK_PROP_OP_WITH_EAW_HWF)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB16 */
|
||||
if ((last_non_sp_cm_or_zwj_prop == LINE_BREAK_PROP_CL ||
|
||||
last_non_sp_cm_or_zwj_prop == LINE_BREAK_PROP_CP_WITHOUT_EAW_HWF ||
|
||||
last_non_sp_cm_or_zwj_prop == LINE_BREAK_PROP_CP_WITH_EAW_HWF) &&
|
||||
cp1_prop == LINE_BREAK_PROP_NS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB17 */
|
||||
if (last_non_sp_cm_or_zwj_prop == LINE_BREAK_PROP_B2 &&
|
||||
cp1_prop == LINE_BREAK_PROP_B2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB18 */
|
||||
if (last_non_cm_or_zwj_prop == LINE_BREAK_PROP_SP) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* LB19 */
|
||||
if (last_non_cm_or_zwj_prop == LINE_BREAK_PROP_QU ||
|
||||
cp1_prop == LINE_BREAK_PROP_QU) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB20 */
|
||||
if (last_non_cm_or_zwj_prop == LINE_BREAK_PROP_CB ||
|
||||
cp1_prop == LINE_BREAK_PROP_CB) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* LB21 */
|
||||
if (cp1_prop == LINE_BREAK_PROP_BA ||
|
||||
cp1_prop == LINE_BREAK_PROP_HY ||
|
||||
cp1_prop == LINE_BREAK_PROP_NS ||
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_BB) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB21a */
|
||||
if (lb21a_flag &&
|
||||
(last_non_cm_or_zwj_prop == LINE_BREAK_PROP_HY ||
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_BA)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB21b */
|
||||
if (last_non_cm_or_zwj_prop == LINE_BREAK_PROP_SY &&
|
||||
cp1_prop == LINE_BREAK_PROP_HL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB22 */
|
||||
if (cp1_prop == LINE_BREAK_PROP_IN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB23 */
|
||||
if ((last_non_cm_or_zwj_prop == LINE_BREAK_PROP_AL ||
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_HL) &&
|
||||
cp1_prop == LINE_BREAK_PROP_NU) {
|
||||
continue;
|
||||
}
|
||||
if (last_non_cm_or_zwj_prop == LINE_BREAK_PROP_NU &&
|
||||
(cp1_prop == LINE_BREAK_PROP_AL ||
|
||||
cp1_prop == LINE_BREAK_PROP_HL)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB23a */
|
||||
if (last_non_cm_or_zwj_prop == LINE_BREAK_PROP_PR &&
|
||||
(cp1_prop == LINE_BREAK_PROP_ID ||
|
||||
cp1_prop == LINE_BREAK_PROP_EB ||
|
||||
cp1_prop == LINE_BREAK_PROP_EM)) {
|
||||
continue;
|
||||
}
|
||||
if ((last_non_cm_or_zwj_prop == LINE_BREAK_PROP_ID ||
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_EB ||
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_EM) &&
|
||||
cp1_prop == LINE_BREAK_PROP_PO) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB24 */
|
||||
if ((last_non_cm_or_zwj_prop == LINE_BREAK_PROP_PR ||
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_PO) &&
|
||||
(cp1_prop == LINE_BREAK_PROP_AL ||
|
||||
cp1_prop == LINE_BREAK_PROP_HL)) {
|
||||
continue;
|
||||
}
|
||||
if ((last_non_cm_or_zwj_prop == LINE_BREAK_PROP_AL ||
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_HL) &&
|
||||
(cp1_prop == LINE_BREAK_PROP_PR ||
|
||||
cp1_prop == LINE_BREAK_PROP_PO)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB25 (tailored with example 7) */
|
||||
if ((last_non_cm_or_zwj_prop == LINE_BREAK_PROP_PR ||
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_PO)) {
|
||||
if (cp1_prop == LINE_BREAK_PROP_NU) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* this stupid rule is the reason why we cannot
|
||||
* simply have a stateful break-detection between
|
||||
* two adjacent codepoints as we have it with
|
||||
* characters.
|
||||
*/
|
||||
herodotus_reader_copy(r, &tmp);
|
||||
herodotus_read_codepoint(&tmp, true, &cp);
|
||||
if (herodotus_read_codepoint(&tmp, true, &cp) ==
|
||||
HERODOTUS_STATUS_SUCCESS &&
|
||||
(cp1_prop == LINE_BREAK_PROP_OP_WITHOUT_EAW_HWF ||
|
||||
cp1_prop == LINE_BREAK_PROP_OP_WITH_EAW_HWF ||
|
||||
cp1_prop == LINE_BREAK_PROP_HY)) {
|
||||
if (get_break_prop(cp) == LINE_BREAK_PROP_NU) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((last_non_cm_or_zwj_prop == LINE_BREAK_PROP_OP_WITHOUT_EAW_HWF ||
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_OP_WITH_EAW_HWF ||
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_HY) &&
|
||||
cp1_prop == LINE_BREAK_PROP_NU) {
|
||||
continue;
|
||||
}
|
||||
if (lb25_level == 1 &&
|
||||
(cp1_prop == LINE_BREAK_PROP_NU ||
|
||||
cp1_prop == LINE_BREAK_PROP_SY ||
|
||||
cp1_prop == LINE_BREAK_PROP_IS)) {
|
||||
continue;
|
||||
}
|
||||
if ((lb25_level == 1 || lb25_level == 2) &&
|
||||
(cp1_prop == LINE_BREAK_PROP_NU ||
|
||||
cp1_prop == LINE_BREAK_PROP_SY ||
|
||||
cp1_prop == LINE_BREAK_PROP_IS ||
|
||||
cp1_prop == LINE_BREAK_PROP_CL ||
|
||||
cp1_prop == LINE_BREAK_PROP_CP_WITHOUT_EAW_HWF ||
|
||||
cp1_prop == LINE_BREAK_PROP_CP_WITH_EAW_HWF)) {
|
||||
continue;
|
||||
}
|
||||
if ((lb25_level == 1 || lb25_level == 2 || lb25_level == 3) &&
|
||||
(cp1_prop == LINE_BREAK_PROP_PO ||
|
||||
cp1_prop == LINE_BREAK_PROP_PR)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB26 */
|
||||
if (last_non_cm_or_zwj_prop == LINE_BREAK_PROP_JL &&
|
||||
(cp1_prop == LINE_BREAK_PROP_JL ||
|
||||
cp1_prop == LINE_BREAK_PROP_JV ||
|
||||
cp1_prop == LINE_BREAK_PROP_H2 ||
|
||||
cp1_prop == LINE_BREAK_PROP_H3)) {
|
||||
continue;
|
||||
}
|
||||
if ((last_non_cm_or_zwj_prop == LINE_BREAK_PROP_JV ||
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_H2) &&
|
||||
(cp1_prop == LINE_BREAK_PROP_JV ||
|
||||
cp1_prop == LINE_BREAK_PROP_JT)) {
|
||||
continue;
|
||||
}
|
||||
if ((last_non_cm_or_zwj_prop == LINE_BREAK_PROP_JT ||
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_H3) &&
|
||||
cp1_prop == LINE_BREAK_PROP_JT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB27 */
|
||||
if ((last_non_cm_or_zwj_prop == LINE_BREAK_PROP_JL ||
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_JV ||
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_JT ||
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_H2 ||
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_H3) &&
|
||||
cp1_prop == LINE_BREAK_PROP_PO) {
|
||||
continue;
|
||||
}
|
||||
if (last_non_cm_or_zwj_prop == LINE_BREAK_PROP_PR &&
|
||||
(cp1_prop == LINE_BREAK_PROP_JL ||
|
||||
cp1_prop == LINE_BREAK_PROP_JV ||
|
||||
cp1_prop == LINE_BREAK_PROP_JT ||
|
||||
cp1_prop == LINE_BREAK_PROP_H2 ||
|
||||
cp1_prop == LINE_BREAK_PROP_H3)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB28 */
|
||||
if ((last_non_cm_or_zwj_prop == LINE_BREAK_PROP_AL ||
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_HL) &&
|
||||
(cp1_prop == LINE_BREAK_PROP_AL ||
|
||||
cp1_prop == LINE_BREAK_PROP_HL)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB29 */
|
||||
if (last_non_cm_or_zwj_prop == LINE_BREAK_PROP_IS &&
|
||||
(cp1_prop == LINE_BREAK_PROP_AL ||
|
||||
cp1_prop == LINE_BREAK_PROP_HL)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB30 */
|
||||
if ((last_non_cm_or_zwj_prop == LINE_BREAK_PROP_AL ||
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_HL ||
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_NU) &&
|
||||
cp1_prop == LINE_BREAK_PROP_OP_WITHOUT_EAW_HWF) {
|
||||
continue;
|
||||
}
|
||||
if (last_non_cm_or_zwj_prop == LINE_BREAK_PROP_CP_WITHOUT_EAW_HWF &&
|
||||
(cp1_prop == LINE_BREAK_PROP_AL ||
|
||||
cp1_prop == LINE_BREAK_PROP_HL ||
|
||||
cp1_prop == LINE_BREAK_PROP_NU)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB30a */
|
||||
if (!ri_even &&
|
||||
last_non_cm_or_zwj_prop == LINE_BREAK_PROP_RI &&
|
||||
cp1_prop == LINE_BREAK_PROP_RI) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB30b */
|
||||
if (last_non_cm_or_zwj_prop == LINE_BREAK_PROP_EB &&
|
||||
cp1_prop == LINE_BREAK_PROP_EM) {
|
||||
continue;
|
||||
}
|
||||
if (last_non_cm_or_zwj_prop == LINE_BREAK_PROP_BOTH_CN_EXTPICT &&
|
||||
cp1_prop == LINE_BREAK_PROP_EM) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* LB31 */
|
||||
break;
|
||||
}
|
||||
|
||||
return herodotus_reader_number_read(r);
|
||||
}
|
||||
|
||||
size_t
|
||||
grapheme_next_line_break(const uint_least32_t *str, size_t len)
|
||||
{
|
||||
HERODOTUS_READER r;
|
||||
|
||||
herodotus_reader_init(&r, HERODOTUS_TYPE_CODEPOINT, str, len);
|
||||
|
||||
return next_line_break(&r);
|
||||
}
|
||||
|
||||
size_t
|
||||
grapheme_next_line_break_utf8(const char *str, size_t len)
|
||||
{
|
||||
HERODOTUS_READER r;
|
||||
|
||||
herodotus_reader_init(&r, HERODOTUS_TYPE_UTF8, str, len);
|
||||
|
||||
return next_line_break(&r);
|
||||
}
|
Reference in New Issue
Block a user