1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
/* Sentence boundaries (UAX #29, Unicode 15.1): text/text.h. Extends and
* formats fold into the character before them (SB5); the rules after a
* sentence terminal look back through closing punctuation and spaces (kept
* as the pass goes) and, for SB8, ahead to the next letter (found for
* every position by one pass from the end). */
#include "text.h"
#include <stdlib.h>
enum { OTHER = VEGA_SB_OTHER, CR = VEGA_SB_CR, LF = VEGA_SB_LF, EXTEND = VEGA_SB_EXTEND, SEP = VEGA_SB_SEP,
FORMAT = VEGA_SB_FORMAT, SP = VEGA_SB_SP, LOWER = VEGA_SB_LOWER, UPPER = VEGA_SB_UPPER, OLETTER = VEGA_SB_OLETTER,
NUMERIC = VEGA_SB_NUMERIC, ATERM = VEGA_SB_ATERM, SCONTINUE = VEGA_SB_SCONTINUE, STERM = VEGA_SB_STERM,
CLOSE = VEGA_SB_CLOSE };
static bool paragraph_end(unsigned c) { return c == SEP || c == CR || c == LF; }
static bool terminal(unsigned c) { return c == ATERM || c == STERM; }
bool vega_sentences(const uint32_t *codes, size_t count, uint8_t *breaks) {
breaks[0] = count > 0; /* SB1 */
if (!count) return true;
uint8_t *eff = malloc(3 * count);
if (!eff) return false;
uint8_t *folded = eff + count, *stop = eff + 2 * count;
for (size_t i = 0; i < count; ++i) {
unsigned c = vega_sentence(codes[i]);
folded[i] = (c == EXTEND || c == FORMAT) && i && !paragraph_end(eff[i - 1]);
eff[i] = folded[i] ? eff[i - 1] : (uint8_t)c;
}
/* SB8's look ahead: from each position, the class of the first unit
* that is a letter, a paragraph end or a terminal (OTHER when none is). */
unsigned next = OTHER;
for (size_t i = count; i--;) {
unsigned c = eff[i];
if (!folded[i] && (c == OLETTER || c == UPPER || c == LOWER || paragraph_end(c) || terminal(c))) next = c;
stop[i] = (uint8_t)next;
}
/* After each unit: the terminal the text ends in, with only closes and
* then spaces after it (OTHER when it does not end so); whether spaces
* came yet; the unit before that terminal. */
unsigned term = OTHER, before_term = OTHER, previous = OTHER;
bool spaces = false;
for (size_t i = 0; i < count; ++i) {
if (folded[i]) {
breaks[i] = 0; /* SB5 */
continue;
}
unsigned B = eff[i];
if (i) {
unsigned A = previous;
bool join;
if (A == CR && B == LF) join = true; /* SB3 */
else if (paragraph_end(A)) join = false; /* SB4 */
else if (A == ATERM && B == NUMERIC) join = true; /* SB6 */
else if (A == ATERM && (before_term == UPPER || before_term == LOWER) && B == UPPER) join = true; /* SB7 */
else if (term == ATERM && stop[i] == LOWER) join = true; /* SB8 */
else if (term != OTHER && (B == SCONTINUE || terminal(B))) join = true; /* SB8a */
else if (term != OTHER && !spaces && (B == CLOSE || B == SP || paragraph_end(B))) join = true; /* SB9 */
else if (term != OTHER && (B == SP || paragraph_end(B))) join = true; /* SB10 */
else if (term != OTHER) join = false; /* SB11 */
else join = true; /* SB998 */
breaks[i] = !join;
}
if (terminal(B)) {
before_term = previous;
term = B;
spaces = false;
} else if (term != OTHER && B == CLOSE && !spaces) {
/* still closing the sentence */
} else if (term != OTHER && B == SP) spaces = true;
else term = OTHER;
previous = B;
}
breaks[count] = 1; /* SB2 */
free(eff);
return true;
}
|