commit 7224752
uint
·
2026-10-18 21:51:27 +0000 UTC
parent 9e845cc
UTF: Implement uleutf_codepoint* functions
2 files changed,
+205,
-8
+19,
-8
1@@ -12,18 +12,32 @@ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
3 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
4
5-/* uleutf is based on utf8.h from */
6+/* uleutf is based on utf8.h on https://github.com/sheredom/utf8.h
7+ Implementations are their work, not mine. This is just an ANSI C rewrite */
8
9 #ifndef ULEUTF_H
10 #define ULEUTF_H
11
12 #include "uletypes.h"
13
14-typedef char utf8_int8_t;
15-typedef ule_i32 utf8_int32_t;
16-
17 /* Implemented */
18
19+/* Sets out_codepoint to the current utf8 codepoint in str, and returns the
20+ address of the next utf8 codepoint after the current one in str */
21+char* uleutf_codepoint(const char* str, ule_i32* out_codepoint);
22+
23+/* Calculates the size of the next utf8 codepoint in str */
24+size_t uleutf_codepointcalcsize(const char* str);
25+
26+/* Returns the size of the given codepoint in bytes */
27+size_t uleutf_codepointsize(ule_i32 chr);
28+
29+/* Returns the number of terminal columns the given codepoint occupies when
30+ printed with a fixed-width font: 0 for zero-width codepoints (the null
31+ codepoint and combining marks), 2 for wide (double-width) codepoints, 1 for
32+ ordinary codepoints, and -1 for non-printable control codepoints */
33+int uleutf_codepointvisualwidth(ule_i32 chr);
34+
35 /* TODO */
36 int uleutf_casecmp(const char* src1, const char* src2);
37 char* uleutf_cat(char* dst, const char* src);
38@@ -50,10 +64,6 @@ char* uleutf_casestr(const char* haystack, const char* needle);
39 char* uleutf_valid(const char* str);
40 char* uleutf_nvalid(const char* str, size_t n);
41 int uleutf_makevalid(char* str, ule_i32 replacement);
42-char* uleutf_codepoint(const char* str, ule_i32* out_codepoint);
43-size_t uleutf_codepointcalcsize(const char* str);
44-size_t uleutf_codepointsize(ule_i32 chr);
45-int uleutf_codepointvisualwidth(ule_i32 chr);
46 char* uleutf_catcodepoint(char* str, ule_i32 chr, size_t n);
47 int uleutf_islower(ule_i32 chr);
48 int uleutf_isupper(ule_i32 chr);
49@@ -66,3 +76,4 @@ char* uleutf_dup_ex(const char* src, char* (*alloc_func_ptr)(char*, size_t), cha
50 char* uleutf_ndup_ex(const char* src, size_t n, char* (*alloc_func_ptr)(char*, size_t), char* user_data);
51
52 #endif /* ULEUTF_H */
53+
+186,
-0
1@@ -1,3 +1,189 @@
2 #include <stddef.h>
3
4 #include "uleutf.h"
5+
6+char* uleutf_codepoint(const char* str, ule_i32* out_codepoint)
7+{
8+ size_t n = 1;
9+ size_t i = 1;
10+ ule_i32 cp = (ule_i32)str[0];
11+
12+ if (0xf0 == (0xf8 & str[0])) {
13+ /* 4 byte utf8 codepoint */
14+ n = 4;
15+ cp = 0x07 & str[0];
16+ }
17+ else if (0xe0 == (0xf0 & str[0])) {
18+ /* 3 byte utf8 codepoint */
19+ n = 3;
20+ cp = 0x0f & str[0];
21+ }
22+ else if (0xc0 == (0xe0 & str[0])) {
23+ /* 2 byte utf8 codepoint */
24+ n = 2;
25+ cp = 0x1f & str[0];
26+ }
27+
28+ /* stop at the NUL if the sequence is truncated */
29+ for (i = 1; i < n && '\0' != str[i]; i++)
30+ cp = (cp << 6) | (0x3f & str[i]);
31+
32+ *out_codepoint = cp;
33+ return (char*)(str + i);
34+}
35+
36+size_t uleutf_codepointcalcsize(const char* str)
37+{
38+ if (0xf0 == (0xf8 & str[0]))
39+ return 4; /* 4 byte utf8 codepoint */
40+ else if (0xe0 == (0xf0 & str[0]))
41+ return 3; /* 3 byte utf8 codepoint */
42+ else if (0xc0 == (0xe0 & str[0]))
43+ return 2; /* 2 byte utf8 codepoint */
44+
45+ return 1; /* 1 byte utf8 codepoint otherwise */
46+}
47+
48+size_t uleutf_codepointsize(ule_i32 chr)
49+{
50+ if (0 == ((ule_i32)0xffffff80 & chr))
51+ return 1;
52+ else if (0 == ((ule_i32)0xfffff800 & chr))
53+ return 2;
54+ else if (0 == ((ule_i32)0xffff0000 & chr))
55+ return 3;
56+ else /* if (0 == ((int)0xffe00000 & chr)) */
57+ return 4;
58+}
59+
60+int uleutf_codepointvisualwidth(ule_i32 chr)
61+{
62+ /* the null codepoint takes up no visual space */
63+ if (0 == chr)
64+ return 0;
65+
66+ /* C0 and C1 control codepoints have no printable representation. */
67+ if ((chr < 0x20) || ((0x7f <= chr) && (chr < 0xa0)))
68+ return -1;
69+
70+ /* zero-width combining marks and format codepoints. the ranges follow the
71+ widely used wcwidth() tables and cover Unicode general categories Mn, Me
72+ and Cf that do not advance the cursor */
73+ if (((0x0300 <= chr) && (0x036f >= chr)) ||
74+ ((0x0483 <= chr) && (0x0486 >= chr)) ||
75+ ((0x0488 <= chr) && (0x0489 >= chr)) ||
76+ ((0x0591 <= chr) && (0x05bd >= chr)) || (0x05bf == chr) ||
77+ ((0x05c1 <= chr) && (0x05c2 >= chr)) ||
78+ ((0x05c4 <= chr) && (0x05c5 >= chr)) || (0x05c7 == chr) ||
79+ ((0x0600 <= chr) && (0x0603 >= chr)) ||
80+ ((0x0610 <= chr) && (0x0615 >= chr)) ||
81+ ((0x064b <= chr) && (0x065e >= chr)) || (0x0670 == chr) ||
82+ ((0x06d6 <= chr) && (0x06e4 >= chr)) ||
83+ ((0x06e7 <= chr) && (0x06e8 >= chr)) ||
84+ ((0x06ea <= chr) && (0x06ed >= chr)) || (0x070f == chr) ||
85+ (0x0711 == chr) || ((0x0730 <= chr) && (0x074a >= chr)) ||
86+ ((0x07a6 <= chr) && (0x07b0 >= chr)) ||
87+ ((0x07eb <= chr) && (0x07f3 >= chr)) ||
88+ ((0x0901 <= chr) && (0x0902 >= chr)) || (0x093c == chr) ||
89+ ((0x0941 <= chr) && (0x0948 >= chr)) || (0x094d == chr) ||
90+ ((0x0951 <= chr) && (0x0954 >= chr)) ||
91+ ((0x0962 <= chr) && (0x0963 >= chr)) || (0x0981 == chr) ||
92+ (0x09bc == chr) || ((0x09c1 <= chr) && (0x09c4 >= chr)) ||
93+ (0x09cd == chr) || ((0x09e2 <= chr) && (0x09e3 >= chr)) ||
94+ ((0x0a01 <= chr) && (0x0a02 >= chr)) || (0x0a3c == chr) ||
95+ ((0x0a41 <= chr) && (0x0a42 >= chr)) ||
96+ ((0x0a47 <= chr) && (0x0a48 >= chr)) ||
97+ ((0x0a4b <= chr) && (0x0a4d >= chr)) ||
98+ ((0x0a70 <= chr) && (0x0a71 >= chr)) ||
99+ ((0x0a81 <= chr) && (0x0a82 >= chr)) || (0x0abc == chr) ||
100+ ((0x0ac1 <= chr) && (0x0ac5 >= chr)) ||
101+ ((0x0ac7 <= chr) && (0x0ac8 >= chr)) || (0x0acd == chr) ||
102+ ((0x0ae2 <= chr) && (0x0ae3 >= chr)) || (0x0b01 == chr) ||
103+ (0x0b3c == chr) || (0x0b3f == chr) ||
104+ ((0x0b41 <= chr) && (0x0b43 >= chr)) || (0x0b4d == chr) ||
105+ (0x0b56 == chr) || (0x0b82 == chr) || (0x0bc0 == chr) ||
106+ (0x0bcd == chr) || ((0x0c3e <= chr) && (0x0c40 >= chr)) ||
107+ ((0x0c46 <= chr) && (0x0c48 >= chr)) ||
108+ ((0x0c4a <= chr) && (0x0c4d >= chr)) ||
109+ ((0x0c55 <= chr) && (0x0c56 >= chr)) || (0x0cbc == chr) ||
110+ (0x0cbf == chr) || (0x0cc6 == chr) ||
111+ ((0x0ccc <= chr) && (0x0ccd >= chr)) ||
112+ ((0x0ce2 <= chr) && (0x0ce3 >= chr)) ||
113+ ((0x0d41 <= chr) && (0x0d43 >= chr)) || (0x0d4d == chr) ||
114+ (0x0dca == chr) || ((0x0dd2 <= chr) && (0x0dd4 >= chr)) ||
115+ (0x0dd6 == chr) || (0x0e31 == chr) ||
116+ ((0x0e34 <= chr) && (0x0e3a >= chr)) ||
117+ ((0x0e47 <= chr) && (0x0e4e >= chr)) || (0x0eb1 == chr) ||
118+ ((0x0eb4 <= chr) && (0x0eb9 >= chr)) ||
119+ ((0x0ebb <= chr) && (0x0ebc >= chr)) ||
120+ ((0x0ec8 <= chr) && (0x0ecd >= chr)) ||
121+ ((0x0f18 <= chr) && (0x0f19 >= chr)) || (0x0f35 == chr) ||
122+ (0x0f37 == chr) || (0x0f39 == chr) ||
123+ ((0x0f71 <= chr) && (0x0f7e >= chr)) ||
124+ ((0x0f80 <= chr) && (0x0f84 >= chr)) ||
125+ ((0x0f86 <= chr) && (0x0f87 >= chr)) ||
126+ ((0x0f90 <= chr) && (0x0f97 >= chr)) ||
127+ ((0x0f99 <= chr) && (0x0fbc >= chr)) || (0x0fc6 == chr) ||
128+ ((0x102d <= chr) && (0x1030 >= chr)) || (0x1032 == chr) ||
129+ ((0x1036 <= chr) && (0x1037 >= chr)) || (0x1039 == chr) ||
130+ ((0x1058 <= chr) && (0x1059 >= chr)) ||
131+ ((0x1160 <= chr) && (0x11ff >= chr)) || (0x135f == chr) ||
132+ ((0x1712 <= chr) && (0x1714 >= chr)) ||
133+ ((0x1732 <= chr) && (0x1734 >= chr)) ||
134+ ((0x1752 <= chr) && (0x1753 >= chr)) ||
135+ ((0x1772 <= chr) && (0x1773 >= chr)) ||
136+ ((0x17b4 <= chr) && (0x17b5 >= chr)) ||
137+ ((0x17b7 <= chr) && (0x17bd >= chr)) || (0x17c6 == chr) ||
138+ ((0x17c9 <= chr) && (0x17d3 >= chr)) || (0x17dd == chr) ||
139+ ((0x180b <= chr) && (0x180d >= chr)) || (0x18a9 == chr) ||
140+ ((0x1920 <= chr) && (0x1922 >= chr)) ||
141+ ((0x1927 <= chr) && (0x1928 >= chr)) || (0x1932 == chr) ||
142+ ((0x1939 <= chr) && (0x193b >= chr)) ||
143+ ((0x1a17 <= chr) && (0x1a18 >= chr)) ||
144+ ((0x1b00 <= chr) && (0x1b03 >= chr)) || (0x1b34 == chr) ||
145+ ((0x1b36 <= chr) && (0x1b3a >= chr)) || (0x1b3c == chr) ||
146+ (0x1b42 == chr) || ((0x1b6b <= chr) && (0x1b73 >= chr)) ||
147+ ((0x1dc0 <= chr) && (0x1dca >= chr)) ||
148+ ((0x1dfe <= chr) && (0x1dff >= chr)) ||
149+ ((0x200b <= chr) && (0x200f >= chr)) ||
150+ ((0x202a <= chr) && (0x202e >= chr)) ||
151+ ((0x2060 <= chr) && (0x2063 >= chr)) ||
152+ ((0x206a <= chr) && (0x206f >= chr)) ||
153+ ((0x20d0 <= chr) && (0x20ef >= chr)) ||
154+ ((0x302a <= chr) && (0x302f >= chr)) ||
155+ ((0x3099 <= chr) && (0x309a >= chr)) || (0xa806 == chr) ||
156+ (0xa80b == chr) || ((0xa825 <= chr) && (0xa826 >= chr)) ||
157+ (0xfb1e == chr) || ((0xfe00 <= chr) && (0xfe0f >= chr)) ||
158+ ((0xfe20 <= chr) && (0xfe23 >= chr)) || (0xfeff == chr) ||
159+ ((0xfff9 <= chr) && (0xfffb >= chr)) ||
160+ ((0x10a01 <= chr) && (0x10a03 >= chr)) ||
161+ ((0x10a05 <= chr) && (0x10a06 >= chr)) ||
162+ ((0x10a0c <= chr) && (0x10a0f >= chr)) ||
163+ ((0x10a38 <= chr) && (0x10a3a >= chr)) || (0x10a3f == chr) ||
164+ ((0x1d167 <= chr) && (0x1d169 >= chr)) ||
165+ ((0x1d173 <= chr) && (0x1d182 >= chr)) ||
166+ ((0x1d185 <= chr) && (0x1d18b >= chr)) ||
167+ ((0x1d1aa <= chr) && (0x1d1ad >= chr)) ||
168+ ((0x1d242 <= chr) && (0x1d244 >= chr)) || (0xe0001 == chr) ||
169+ ((0xe0020 <= chr) && (0xe007f >= chr)) ||
170+ ((0xe0100 <= chr) && (0xe01ef >= chr)))
171+ return 0;
172+
173+ /* wide (double-width) codepoints, mostly East Asian scripts */
174+ if ((0x1100 <= chr) &&
175+ (((0x1100 <= chr) && (0x115f >= chr)) || (0x2329 == chr) ||
176+ (0x232a == chr) ||
177+ (((0x2e80 <= chr) && (0xa4cf >= chr)) && (0x303f != chr)) ||
178+ ((0xac00 <= chr) && (0xd7a3 >= chr)) ||
179+ ((0xf900 <= chr) && (0xfaff >= chr)) ||
180+ ((0xfe10 <= chr) && (0xfe19 >= chr)) ||
181+ ((0xfe30 <= chr) && (0xfe6f >= chr)) ||
182+ ((0xff00 <= chr) && (0xff60 >= chr)) ||
183+ ((0xffe0 <= chr) && (0xffe6 >= chr)) ||
184+ ((0x20000 <= chr) && (0x2fffd >= chr)) ||
185+ ((0x30000 <= chr) && (0x3fffd >= chr))))
186+ return 2;
187+
188+ return 1;
189+}
190+