[gforth] / gforth / utf-8.fs  

gforth: gforth/utf-8.fs


1 : pazsan 1.1 \ UTF-8 handling 12dec04py
2 :    
3 : anton 1.25 \ Copyright (C) 2004,2005,2006 Free Software Foundation, Inc.
4 : pazsan 1.1
5 :     \ This file is part of Gforth.
6 :    
7 :     \ Gforth is free software; you can redistribute it and/or
8 :     \ modify it under the terms of the GNU General Public License
9 :     \ as published by the Free Software Foundation; either version 2
10 :     \ of the License, or (at your option) any later version.
11 :    
12 :     \ This program is distributed in the hope that it will be useful,
13 :     \ but WITHOUT ANY WARRANTY; without even the implied warranty of
14 :     \ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 :     \ GNU General Public License for more details.
16 :    
17 :     \ You should have received a copy of the GNU General Public License
18 :     \ along with this program; if not, write to the Free Software
19 :     \ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
20 :    
21 :     \ short: u8 means utf-8 encoded address
22 :    
23 : pazsan 1.7 s" malformed UTF-8 character" exception Constant UTF-8-err
24 :    
25 : anton 1.13 $80 Value max-single-byte
26 : pazsan 1.10
27 : pazsan 1.4 : u8len ( u8 -- n )
28 : anton 1.13 dup max-single-byte u< IF drop 1 EXIT THEN \ special case ASCII
29 : pazsan 1.1 $800 2 >r
30 : pazsan 1.17 BEGIN 2dup u>= WHILE 5 lshift r> 1+ >r dup 0= UNTIL THEN
31 : pazsan 1.1 2drop r> ;
32 :    
33 :     : u8@+ ( u8addr -- u8addr' u )
34 : anton 1.13 count dup max-single-byte u< ?EXIT \ special case ASCII
35 : pazsan 1.17 dup $C2 u< IF UTF-8-err throw THEN \ malformed character
36 : pazsan 1.1 $7F and $40 >r
37 :     BEGIN dup r@ and WHILE r@ xor
38 :     6 lshift r> 5 lshift >r >r count
39 : pazsan 1.7 dup $C0 and $80 <> IF UTF-8-err throw THEN
40 : pazsan 1.1 $3F and r> or
41 :     REPEAT rdrop ;
42 :    
43 :     : u8!+ ( u u8addr -- u8addr' )
44 : anton 1.13 over max-single-byte u< IF tuck c! 1+ EXIT THEN \ special case ASCII
45 : pazsan 1.1 >r 0 swap $3F
46 :     BEGIN 2dup u> WHILE
47 :     2/ >r dup $3F and $80 or swap 6 rshift r>
48 :     REPEAT $7F xor 2* or r>
49 :     BEGIN over $80 u>= WHILE tuck c! 1+ REPEAT nip ;
50 :    
51 : pazsan 1.8 \ plug-in so that char and '<char> work for UTF-8
52 :    
53 : anton 1.9 [ifundef] char@ \ !! bootstrapping help
54 :     Defer char@ ( addr u -- char addr' u' )
55 :     :noname over c@ -rot 1 /string ; IS char@
56 :     [then]
57 :    
58 : pazsan 1.8 :noname ( addr u -- char addr' u' )
59 : anton 1.9 \ !! the if here seems to work around some breakage, but not
60 : pazsan 1.24 \ entirely; e.g., try 'รง' with LANG=C.
61 : anton 1.9 dup 1 u<= IF defers char@ EXIT THEN
62 : pazsan 1.8 over + >r u8@+ swap r> over - ; IS char@
63 :    
64 : pazsan 1.1 \ scan to next/previous character
65 :    
66 : anton 1.13 \ alternative names: u8char+ u8char-
67 :    
68 : pazsan 1.12 : u8>> ( u8addr -- u8addr' ) u8@+ drop ;
69 : pazsan 1.1 : u8<< ( u8addr -- u8addr' )
70 : anton 1.13 BEGIN 1- dup c@ $C0 and max-single-byte <> UNTIL ;
71 : pazsan 1.1
72 :     \ utf key and emit
73 :    
74 :     : u8key ( -- u )
75 : anton 1.13 defers key dup max-single-byte u< ?EXIT \ special case ASCII
76 : pazsan 1.17 dup $C2 u< IF UTF-8-err throw THEN \ malformed character
77 : pazsan 1.1 $7F and $40 >r
78 :     BEGIN dup r@ and WHILE r@ xor
79 :     6 lshift r> 5 lshift >r >r defers key
80 : pazsan 1.7 dup $C0 and $80 <> IF UTF-8-err throw THEN
81 : pazsan 1.1 $3F and r> or
82 :     REPEAT rdrop ;
83 :    
84 :     : u8emit ( u -- )
85 : anton 1.13 dup max-single-byte u< IF defers emit EXIT THEN \ special case ASCII
86 : pazsan 1.1 0 swap $3F
87 :     BEGIN 2dup u> WHILE
88 :     2/ >r dup $3F and $80 or swap 6 rshift r>
89 :     REPEAT $7F xor 2* or
90 :     BEGIN dup $80 u>= WHILE defers emit REPEAT drop ;
91 : anton 1.13
92 :     \ utf-8 stuff for xchars
93 :    
94 :     : +u8/string ( c-addr1 u1 -- c-addr2 u2 )
95 :     over dup u8>> swap - /string ;
96 :    
97 :     : -u8/string ( c-addr1 u1 -- c-addr2 u2 )
98 :     over dup u8<< swap - /string ;
99 :    
100 :     : u8@ ( c-addr -- u )
101 :     u8@+ nip ;
102 :    
103 :     : u8!+? ( xc xc-addr1 u1 -- xc-addr2 u2 f )
104 :     >r over u8len r@ over u< if ( xc xc-addr1 len r: u1 )
105 :     \ not enough space
106 :     drop nip r> false
107 :     else
108 :     >r u8!+ r> r> swap - true
109 :     then ;
110 :    
111 :     : u8addrlen ( u8-addr -- u )
112 :     \ length of UTF-8 char starting at u8-addr (accesses only u8-addr)
113 :     c@
114 :     dup $80 u< if drop 1 exit endif
115 :     dup $c0 u< if UTF-8-err throw endif
116 :     dup $e0 u< if drop 2 exit endif
117 :     dup $f0 u< if drop 3 exit endif
118 :     dup $f8 u< if drop 4 exit endif
119 :     dup $fc u< if drop 5 exit endif
120 :     dup $fe u< if drop 6 exit endif
121 :     UTF-8-err throw ;
122 :    
123 :     : -u8trailing-garbage ( addr u1 -- addr u2 )
124 :     2dup + dup u8<< ( addr u1 end1 end2 )
125 :     2dup dup u8addrlen + = if \ last character ok
126 :     2drop
127 :     else
128 :     nip nip over -
129 :     then ;
130 :    
131 : anton 1.22 [IFUNDEF] wcwidth
132 : pazsan 1.24 : wc,3 ( n low high -- ) 1+ , , , ;
133 :    
134 :     Create wc-table \ derived from wcwidth source code, for UCS32
135 :     0 0300 0357 wc,3
136 :     0 035D 036F wc,3
137 :     0 0483 0486 wc,3
138 :     0 0488 0489 wc,3
139 :     0 0591 05A1 wc,3
140 :     0 05A3 05B9 wc,3
141 :     0 05BB 05BD wc,3
142 :     0 05BF 05BF wc,3
143 :     0 05C1 05C2 wc,3
144 :     0 05C4 05C4 wc,3
145 :     0 0600 0603 wc,3
146 :     0 0610 0615 wc,3
147 :     0 064B 0658 wc,3
148 :     0 0670 0670 wc,3
149 :     0 06D6 06E4 wc,3
150 :     0 06E7 06E8 wc,3
151 :     0 06EA 06ED wc,3
152 :     0 070F 070F wc,3
153 :     0 0711 0711 wc,3
154 :     0 0730 074A wc,3
155 :     0 07A6 07B0 wc,3
156 :     0 0901 0902 wc,3
157 :     0 093C 093C wc,3
158 :     0 0941 0948 wc,3
159 :     0 094D 094D wc,3
160 :     0 0951 0954 wc,3
161 :     0 0962 0963 wc,3
162 :     0 0981 0981 wc,3
163 :     0 09BC 09BC wc,3
164 :     0 09C1 09C4 wc,3
165 :     0 09CD 09CD wc,3
166 :     0 09E2 09E3 wc,3
167 :     0 0A01 0A02 wc,3
168 :     0 0A3C 0A3C wc,3
169 :     0 0A41 0A42 wc,3
170 :     0 0A47 0A48 wc,3
171 :     0 0A4B 0A4D wc,3
172 :     0 0A70 0A71 wc,3
173 :     0 0A81 0A82 wc,3
174 :     0 0ABC 0ABC wc,3
175 :     0 0AC1 0AC5 wc,3
176 :     0 0AC7 0AC8 wc,3
177 :     0 0ACD 0ACD wc,3
178 :     0 0AE2 0AE3 wc,3
179 :     0 0B01 0B01 wc,3
180 :     0 0B3C 0B3C wc,3
181 :     0 0B3F 0B3F wc,3
182 :     0 0B41 0B43 wc,3
183 :     0 0B4D 0B4D wc,3
184 :     0 0B56 0B56 wc,3
185 :     0 0B82 0B82 wc,3
186 :     0 0BC0 0BC0 wc,3
187 :     0 0BCD 0BCD wc,3
188 :     0 0C3E 0C40 wc,3
189 :     0 0C46 0C48 wc,3
190 :     0 0C4A 0C4D wc,3
191 :     0 0C55 0C56 wc,3
192 :     0 0CBC 0CBC wc,3
193 :     0 0CBF 0CBF wc,3
194 :     0 0CC6 0CC6 wc,3
195 :     0 0CCC 0CCD wc,3
196 :     0 0D41 0D43 wc,3
197 :     0 0D4D 0D4D wc,3
198 :     0 0DCA 0DCA wc,3
199 :     0 0DD2 0DD4 wc,3
200 :     0 0DD6 0DD6 wc,3
201 :     0 0E31 0E31 wc,3
202 :     0 0E34 0E3A wc,3
203 :     0 0E47 0E4E wc,3
204 :     0 0EB1 0EB1 wc,3
205 :     0 0EB4 0EB9 wc,3
206 :     0 0EBB 0EBC wc,3
207 :     0 0EC8 0ECD wc,3
208 :     0 0F18 0F19 wc,3
209 :     0 0F35 0F35 wc,3
210 :     0 0F37 0F37 wc,3
211 :     0 0F39 0F39 wc,3
212 :     0 0F71 0F7E wc,3
213 :     0 0F80 0F84 wc,3
214 :     0 0F86 0F87 wc,3
215 :     0 0F90 0F97 wc,3
216 :     0 0F99 0FBC wc,3
217 :     0 0FC6 0FC6 wc,3
218 :     0 102D 1030 wc,3
219 :     0 1032 1032 wc,3
220 :     0 1036 1037 wc,3
221 :     0 1039 1039 wc,3
222 :     0 1058 1059 wc,3
223 :     1 0000 1100 wc,3
224 :     2 1100 115f wc,3
225 :     0 1160 11FF wc,3
226 :     0 1712 1714 wc,3
227 :     0 1732 1734 wc,3
228 :     0 1752 1753 wc,3
229 :     0 1772 1773 wc,3
230 :     0 17B4 17B5 wc,3
231 :     0 17B7 17BD wc,3
232 :     0 17C6 17C6 wc,3
233 :     0 17C9 17D3 wc,3
234 :     0 17DD 17DD wc,3
235 :     0 180B 180D wc,3
236 :     0 18A9 18A9 wc,3
237 :     0 1920 1922 wc,3
238 :     0 1927 1928 wc,3
239 :     0 1932 1932 wc,3
240 :     0 1939 193B wc,3
241 :     0 200B 200F wc,3
242 :     0 202A 202E wc,3
243 :     0 2060 2063 wc,3
244 :     0 206A 206F wc,3
245 :     0 20D0 20EA wc,3
246 :     2 2329 232A wc,3
247 :     0 302A 302F wc,3
248 :     2 2E80 303E wc,3
249 :     0 3099 309A wc,3
250 :     2 3040 A4CF wc,3
251 :     2 AC00 D7A3 wc,3
252 :     2 F900 FAFF wc,3
253 :     0 FB1E FB1E wc,3
254 :     0 FE00 FE0F wc,3
255 :     0 FE20 FE23 wc,3
256 :     2 FE30 FE6F wc,3
257 :     0 FEFF FEFF wc,3
258 :     2 FF00 FF60 wc,3
259 :     2 FFE0 FFE6 wc,3
260 :     0 FFF9 FFFB wc,3
261 :     0 1D167 1D169 wc,3
262 :     0 1D173 1D182 wc,3
263 :     0 1D185 1D18B wc,3
264 :     0 1D1AA 1D1AD wc,3
265 :     2 20000 2FFFD wc,3
266 :     2 30000 3FFFD wc,3
267 :     0 E0001 E0001 wc,3
268 :     0 E0020 E007F wc,3
269 :     0 E0100 E01EF wc,3
270 :     here wc-table - Constant #wc-table
271 :    
272 :     \ inefficient table walk:
273 :    
274 :     : wcwidth ( xc -- n )
275 :     wc-table #wc-table over + swap ?DO
276 :     dup I 2@ within IF I 2 cells + @ UNLOOP EXIT THEN
277 :     3 cells +LOOP 1 ;
278 : anton 1.22 [THEN]
279 :    
280 : pazsan 1.19 : u8width ( xcaddr u -- n )
281 :     0 rot rot over + swap ?DO
282 : anton 1.22 I xc@+ swap >r wcwidth +
283 : pazsan 1.19 r> I - +LOOP ;
284 :    
285 : anton 1.13 : set-encoding-utf-8 ( -- )
286 :     ['] u8emit is xemit
287 :     ['] u8key is xkey
288 :     ['] u8>> is xchar+
289 :     ['] u8<< is xchar-
290 :     ['] +u8/string is +x/string
291 :     ['] -u8/string is -x/string
292 :     ['] u8@ is xc@
293 :     ['] u8!+? is xc!+?
294 :     ['] u8@+ is xc@+
295 :     ['] u8len is xc-size
296 : pazsan 1.20 [ [IFDEF] x-width ]
297 : pazsan 1.19 ['] u8width is x-width
298 : pazsan 1.20 [ [THEN] ]
299 : anton 1.13 ['] -u8trailing-garbage is -trailing-garbage
300 :     ;
301 : pazsan 1.1
302 : anton 1.15 : utf-8-cold ( -- )
303 : pazsan 1.16 s" LC_ALL" getenv 2dup d0= IF 2drop
304 :     s" LC_CTYPE" getenv 2dup d0= IF 2drop
305 :     s" LANG" getenv 2dup d0= IF 2drop
306 :     s" C" THEN THEN THEN
307 :     s" UTF-8" search nip nip
308 : anton 1.15 IF set-encoding-utf-8 ELSE set-encoding-fixed-width THEN ;
309 :    
310 : anton 1.23 :noname ( -- )
311 :     defers 'cold
312 :     utf-8-cold
313 :     ; is 'cold
314 : anton 1.15
315 :     utf-8-cold

CVS Admin

Powered by ViewCVS 1.0-dev
(Powered by ViewCVS)

ViewCVS and CVS Help