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+