Blame


1 5e11c00c 2021-03-02 op /* Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
2 5e11c00c 2021-03-02 op *
3 5e11c00c 2021-03-02 op * Permission is hereby granted, free of charge, to any person
4 5e11c00c 2021-03-02 op * obtaining a copy of this software and associated documentation
5 5e11c00c 2021-03-02 op * files (the "Software"), to deal in the Software without
6 5e11c00c 2021-03-02 op * restriction, including without limitation the rights to use, copy,
7 5e11c00c 2021-03-02 op * modify, merge, publish, distribute, sublicense, and/or sell copies
8 5e11c00c 2021-03-02 op * of the Software, and to permit persons to whom the Software is
9 5e11c00c 2021-03-02 op * furnished to do so, subject to the following conditions:
10 5e11c00c 2021-03-02 op *
11 5e11c00c 2021-03-02 op * The above copyright notice and this permission notice shall be
12 5e11c00c 2021-03-02 op * included in all copies or substantial portions of the Software.
13 5e11c00c 2021-03-02 op *
14 5e11c00c 2021-03-02 op * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 5e11c00c 2021-03-02 op * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 5e11c00c 2021-03-02 op * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 5e11c00c 2021-03-02 op * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18 5e11c00c 2021-03-02 op * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 5e11c00c 2021-03-02 op * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 5e11c00c 2021-03-02 op * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 5e11c00c 2021-03-02 op * SOFTWARE.
22 5e11c00c 2021-03-02 op */
23 5e11c00c 2021-03-02 op
24 174b3cdf 2021-03-21 op #include <assert.h>
25 5e11c00c 2021-03-02 op #include <stddef.h>
26 5e11c00c 2021-03-02 op #include <stdint.h>
27 174b3cdf 2021-03-21 op #include <wchar.h>
28 5e11c00c 2021-03-02 op
29 5caf7d67 2021-07-12 op #include "telescope.h"
30 5caf7d67 2021-07-12 op #include "utf8.h"
31 5caf7d67 2021-07-12 op
32 5e11c00c 2021-03-02 op #define UTF8_ACCEPT 0
33 5e11c00c 2021-03-02 op #define UTF8_REJECT 1
34 5e11c00c 2021-03-02 op
35 5e11c00c 2021-03-02 op static const uint8_t utf8d[] = {
36 5e11c00c 2021-03-02 op 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
37 5e11c00c 2021-03-02 op 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
38 5e11c00c 2021-03-02 op 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
39 5e11c00c 2021-03-02 op 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
40 5e11c00c 2021-03-02 op 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
41 5e11c00c 2021-03-02 op 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
42 5e11c00c 2021-03-02 op 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
43 5e11c00c 2021-03-02 op 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
44 5e11c00c 2021-03-02 op 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
45 5e11c00c 2021-03-02 op 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
46 5e11c00c 2021-03-02 op 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
47 5e11c00c 2021-03-02 op 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
48 5e11c00c 2021-03-02 op 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
49 5e11c00c 2021-03-02 op 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
50 5e11c00c 2021-03-02 op };
51 5e11c00c 2021-03-02 op
52 a1e5a814 2021-07-15 op static inline uint32_t
53 a1e5a814 2021-07-15 op decode(uint32_t* restrict state, uint32_t* restrict codep, uint8_t byte)
54 a1e5a814 2021-07-15 op {
55 5e11c00c 2021-03-02 op uint32_t type = utf8d[byte];
56 5e11c00c 2021-03-02 op
57 5e11c00c 2021-03-02 op *codep = (*state != UTF8_ACCEPT) ?
58 5e11c00c 2021-03-02 op (byte & 0x3fu) | (*codep << 6) :
59 5e11c00c 2021-03-02 op (0xff >> type) & (byte);
60 5e11c00c 2021-03-02 op
61 5e11c00c 2021-03-02 op *state = utf8d[256 + *state*16 + type];
62 5e11c00c 2021-03-02 op return *state;
63 5e11c00c 2021-03-02 op }
64 5e11c00c 2021-03-02 op
65 174b3cdf 2021-03-21 op
66 174b3cdf 2021-03-21 op /* end of the converter, utility functions ahead */
67 5e11c00c 2021-03-02 op
68 ab2d4a19 2021-07-16 op #define ZERO_WIDTH_SPACE 0x200B
69 ab2d4a19 2021-07-16 op
70 a1e5a814 2021-07-15 op /* public version of decode */
71 a1e5a814 2021-07-15 op uint32_t
72 a1e5a814 2021-07-15 op utf8_decode(uint32_t* restrict state, uint32_t* restrict codep, uint8_t byte)
73 a1e5a814 2021-07-15 op {
74 a1e5a814 2021-07-15 op return decode(state, codep, byte);
75 a1e5a814 2021-07-15 op }
76 a1e5a814 2021-07-15 op
77 8947c1f2 2021-03-21 op /* encode cp in s. s must be at least 4 bytes wide */
78 17e5106b 2021-03-21 op size_t
79 8947c1f2 2021-03-21 op utf8_encode(uint32_t cp, char *s)
80 8947c1f2 2021-03-21 op {
81 8947c1f2 2021-03-21 op if (cp <= 0x7F) {
82 8947c1f2 2021-03-21 op *s = (uint8_t)cp;
83 17e5106b 2021-03-21 op return 1;
84 8947c1f2 2021-03-21 op } else if (cp <= 0x7FF) {
85 8947c1f2 2021-03-21 op s[1] = (uint8_t)(( cp & 0x3F ) + 0x80);
86 8947c1f2 2021-03-21 op s[0] = (uint8_t)(((cp >> 6) & 0x1F) + 0xC0);
87 17e5106b 2021-03-21 op return 2;
88 8947c1f2 2021-03-21 op } else if (cp <= 0xFFFF) {
89 8947c1f2 2021-03-21 op s[2] = (uint8_t)(( cp & 0x3F) + 0x80);
90 8947c1f2 2021-03-21 op s[1] = (uint8_t)(((cp >> 6) & 0x3F) + 0x80);
91 8947c1f2 2021-03-21 op s[0] = (uint8_t)(((cp >> 12) & 0x0F) + 0xE0);
92 17e5106b 2021-03-21 op return 3;
93 8947c1f2 2021-03-21 op } else if (cp <= 0x10FFFF) {
94 8947c1f2 2021-03-21 op s[3] = (uint8_t)(( cp & 0x3F) + 0x80);
95 8947c1f2 2021-03-21 op s[2] = (uint8_t)(((cp >> 6) & 0x3F) + 0x80);
96 8947c1f2 2021-03-21 op s[1] = (uint8_t)(((cp >> 12) & 0x3F) + 0x80);
97 8947c1f2 2021-03-21 op s[0] = (uint8_t)(((cp >> 18) & 0x07) + 0xF0);
98 17e5106b 2021-03-21 op return 4;
99 17e5106b 2021-03-21 op } else {
100 17e5106b 2021-03-21 op s[0] = '\0';
101 17e5106b 2021-03-21 op return 0;
102 17e5106b 2021-03-21 op }
103 8947c1f2 2021-03-21 op }
104 8947c1f2 2021-03-21 op
105 5e11c00c 2021-03-02 op char *
106 5e11c00c 2021-03-02 op utf8_nth(char *s, size_t n)
107 5e11c00c 2021-03-02 op {
108 5e11c00c 2021-03-02 op size_t i;
109 5e11c00c 2021-03-02 op uint32_t cp = 0, state = 0;
110 5e11c00c 2021-03-02 op
111 5e11c00c 2021-03-02 op for (i = 0; *s && i < n; ++s)
112 a1e5a814 2021-07-15 op if (!decode(&state, &cp, *s))
113 5e11c00c 2021-03-02 op ++i;
114 5e11c00c 2021-03-02 op
115 5e11c00c 2021-03-02 op if (state != UTF8_ACCEPT)
116 5e11c00c 2021-03-02 op return NULL;
117 5e11c00c 2021-03-02 op if (i == n)
118 5e11c00c 2021-03-02 op return s;
119 5e11c00c 2021-03-02 op return NULL;
120 5e11c00c 2021-03-02 op }
121 174b3cdf 2021-03-21 op
122 174b3cdf 2021-03-21 op size_t
123 174b3cdf 2021-03-21 op utf8_cplen(char *s)
124 174b3cdf 2021-03-21 op {
125 174b3cdf 2021-03-21 op uint32_t cp = 0, state = 0;
126 174b3cdf 2021-03-21 op size_t len;
127 174b3cdf 2021-03-21 op
128 174b3cdf 2021-03-21 op len = 0;
129 174b3cdf 2021-03-21 op for (; *s; ++s)
130 a1e5a814 2021-07-15 op if (!decode(&state, &cp, *s))
131 174b3cdf 2021-03-21 op len++;
132 174b3cdf 2021-03-21 op return len;
133 174b3cdf 2021-03-21 op }
134 174b3cdf 2021-03-21 op
135 421bca4a 2021-06-12 op /* returns only 0, 1, 2 or 8. assumes sizeof(wchar_t) is 4 */
136 174b3cdf 2021-03-21 op size_t
137 174b3cdf 2021-03-21 op utf8_chwidth(uint32_t cp)
138 174b3cdf 2021-03-21 op {
139 174b3cdf 2021-03-21 op /* XXX: if we're running on a platform where sizeof(wchar_t)
140 174b3cdf 2021-03-21 op * == 2 what to do? The manpage for wcwidth and wcs isn't
141 174b3cdf 2021-03-21 op * clear about the encoding, but if it's 16 bit wide I assume
142 174b3cdf 2021-03-21 op * it must use UTF-16... right? */
143 174b3cdf 2021-03-21 op assert(sizeof(wchar_t) == 4);
144 174b3cdf 2021-03-21 op
145 421bca4a 2021-06-12 op /*
146 421bca4a 2021-06-12 op * quick and dirty fix for the tabs. In the future we may
147 421bca4a 2021-06-12 op * want to expand tabs into N spaces, but for the time being
148 421bca4a 2021-06-12 op * this seems to be good enough (tm).
149 421bca4a 2021-06-12 op */
150 421bca4a 2021-06-12 op if (cp == '\t')
151 421bca4a 2021-06-12 op return 8;
152 421bca4a 2021-06-12 op
153 174b3cdf 2021-03-21 op return wcwidth((wchar_t)cp);
154 174b3cdf 2021-03-21 op }
155 174b3cdf 2021-03-21 op
156 174b3cdf 2021-03-21 op /* NOTE: n is the number of codepoints, NOT the byte length. In
157 174b3cdf 2021-03-21 op * other words, s MUST be NUL-terminated. */
158 174b3cdf 2021-03-21 op size_t
159 174b3cdf 2021-03-21 op utf8_snwidth(const char *s, size_t n)
160 174b3cdf 2021-03-21 op {
161 174b3cdf 2021-03-21 op size_t i, tot;
162 174b3cdf 2021-03-21 op uint32_t cp = 0, state = 0;
163 174b3cdf 2021-03-21 op
164 174b3cdf 2021-03-21 op tot = 0;
165 174b3cdf 2021-03-21 op for (i = 0; *s && i < n; ++s)
166 a1e5a814 2021-07-15 op if (!decode(&state, &cp, *s)) {
167 174b3cdf 2021-03-21 op i++;
168 174b3cdf 2021-03-21 op tot += utf8_chwidth(cp);
169 174b3cdf 2021-03-21 op }
170 174b3cdf 2021-03-21 op
171 174b3cdf 2021-03-21 op return tot;
172 174b3cdf 2021-03-21 op }
173 174b3cdf 2021-03-21 op
174 174b3cdf 2021-03-21 op size_t
175 174b3cdf 2021-03-21 op utf8_swidth(const char *s)
176 174b3cdf 2021-03-21 op {
177 174b3cdf 2021-03-21 op size_t tot;
178 174b3cdf 2021-03-21 op uint32_t cp = 0, state = 0;
179 174b3cdf 2021-03-21 op
180 174b3cdf 2021-03-21 op tot = 0;
181 174b3cdf 2021-03-21 op for (; *s; ++s)
182 a1e5a814 2021-07-15 op if (!decode(&state, &cp, *s))
183 174b3cdf 2021-03-21 op tot += utf8_chwidth(cp);
184 174b3cdf 2021-03-21 op
185 174b3cdf 2021-03-21 op return tot;
186 174b3cdf 2021-03-21 op }
187 17e5106b 2021-03-21 op
188 17e5106b 2021-03-21 op size_t
189 17e5106b 2021-03-21 op utf8_swidth_between(const char *str, const char *end)
190 17e5106b 2021-03-21 op {
191 17e5106b 2021-03-21 op size_t tot;
192 17e5106b 2021-03-21 op uint32_t cp = 0, state = 0;
193 17e5106b 2021-03-21 op
194 17e5106b 2021-03-21 op tot = 0;
195 17e5106b 2021-03-21 op for (; *str && str < end; ++str)
196 a1e5a814 2021-07-15 op if (!decode(&state, &cp, *str))
197 17e5106b 2021-03-21 op tot += utf8_chwidth(cp);
198 17e5106b 2021-03-21 op return tot;
199 17e5106b 2021-03-21 op }
200 17e5106b 2021-03-21 op
201 17e5106b 2021-03-21 op char *
202 2ba66cea 2021-03-22 op utf8_next_cp(const char *s)
203 17e5106b 2021-03-21 op {
204 17e5106b 2021-03-21 op uint32_t cp = 0, state = 0;
205 17e5106b 2021-03-21 op
206 17e5106b 2021-03-21 op for (; *s; ++s)
207 a1e5a814 2021-07-15 op if (!decode(&state, &cp, *s))
208 17e5106b 2021-03-21 op break;
209 2ba66cea 2021-03-22 op return (char*)s+1;
210 17e5106b 2021-03-21 op }
211 17e5106b 2021-03-21 op
212 17e5106b 2021-03-21 op char *
213 2ba66cea 2021-03-22 op utf8_prev_cp(const char *start, const char *base)
214 17e5106b 2021-03-21 op {
215 17e5106b 2021-03-21 op uint8_t c;
216 17e5106b 2021-03-21 op
217 17e5106b 2021-03-21 op for (; start > base; start--) {
218 17e5106b 2021-03-21 op c = *start;
219 17e5106b 2021-03-21 op if ((c & 0xC0) != 0x80)
220 2ba66cea 2021-03-22 op return (char*)start;
221 17e5106b 2021-03-21 op }
222 17e5106b 2021-03-21 op
223 2ba66cea 2021-03-22 op return (char*)base;
224 17e5106b 2021-03-21 op }
225 ab2d4a19 2021-07-16 op
226 ab2d4a19 2021-07-16 op int
227 ab2d4a19 2021-07-16 op emojied_line(const char *s, const char **space_ret)
228 ab2d4a19 2021-07-16 op {
229 ab2d4a19 2021-07-16 op uint32_t cp = 0, state = 0;
230 ab2d4a19 2021-07-16 op
231 ab2d4a19 2021-07-16 op for (; *s; ++s) {
232 ab2d4a19 2021-07-16 op if (!decode(&state, &cp, *s)) {
233 ab2d4a19 2021-07-16 op if (cp == ZERO_WIDTH_SPACE)
234 ab2d4a19 2021-07-16 op continue;
235 ab2d4a19 2021-07-16 op if (cp == ' ') {
236 ab2d4a19 2021-07-16 op *space_ret = s;
237 ab2d4a19 2021-07-16 op return 1;
238 ab2d4a19 2021-07-16 op }
239 ab2d4a19 2021-07-16 op if (!is_emoji(cp))
240 ab2d4a19 2021-07-16 op return 0;
241 ab2d4a19 2021-07-16 op }
242 ab2d4a19 2021-07-16 op }
243 ab2d4a19 2021-07-16 op
244 ab2d4a19 2021-07-16 op return 0;
245 ab2d4a19 2021-07-16 op }