[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 : pazsan 1.27 Defer check-xy ' noop IS check-xy
75 :    
76 : pazsan 1.1 : u8key ( -- u )
77 : anton 1.13 defers key dup max-single-byte u< ?EXIT \ special case ASCII
78 : pazsan 1.27 dup $FF = ?EXIT \ special resize character
79 : pazsan 1.17 dup $C2 u< IF UTF-8-err throw THEN \ malformed character
80 : pazsan 1.1 $7F and $40 >r
81 :     BEGIN dup r@ and WHILE r@ xor
82 :     6 lshift r> 5 lshift >r >r defers key
83 : pazsan 1.7 dup $C0 and $80 <> IF UTF-8-err throw THEN
84 : pazsan 1.1 $3F and r> or
85 :     REPEAT rdrop ;
86 :    
87 :     : u8emit ( u -- )
88 : anton 1.13 dup max-single-byte u< IF defers emit EXIT THEN \ special case ASCII
89 : pazsan 1.1 0 swap $3F
90 :     BEGIN 2dup u> WHILE
91 :     2/ >r dup $3F and $80 or swap 6 rshift r>
92 :     REPEAT $7F xor 2* or
93 :     BEGIN dup $80 u>= WHILE defers emit REPEAT drop ;
94 : anton 1.13
95 :     \ utf-8 stuff for xchars
96 :    
97 : pazsan 1.26 : u8string+ ( xcaddr u -- xcaddr u' )
98 :     over + u8>> over - ;
99 :     : u8string- ( xcaddr u -- xcaddr u' )
100 :     over + u8<< over - ;
101 :    
102 :     : +u8string ( xc-addr1 u1 -- xc-addr2 u2 )
103 : anton 1.13 over dup u8>> swap - /string ;
104 : pazsan 1.26 : -u8string ( xc-addr1 u1 -- xc-addr2 u2 )
105 : anton 1.13 over dup u8<< swap - /string ;
106 :    
107 :     : u8@ ( c-addr -- u )
108 :     u8@+ nip ;
109 :    
110 :     : u8!+? ( xc xc-addr1 u1 -- xc-addr2 u2 f )
111 :     >r over u8len r@ over u< if ( xc xc-addr1 len r: u1 )
112 :     \ not enough space
113 :     drop nip r> false
114 :     else
115 :     >r u8!+ r> r> swap - true
116 :     then ;
117 :    
118 : pazsan 1.28 : u8addrlen ( u8-addr u -- u ) drop
119 : anton 1.13 \ length of UTF-8 char starting at u8-addr (accesses only u8-addr)
120 :     c@
121 :     dup $80 u< if drop 1 exit endif
122 :     dup $c0 u< if UTF-8-err throw endif
123 :     dup $e0 u< if drop 2 exit endif
124 :     dup $f0 u< if drop 3 exit endif
125 :     dup $f8 u< if drop 4 exit endif
126 :     dup $fc u< if drop 5 exit endif
127 :     dup $fe u< if drop 6 exit endif
128 :     UTF-8-err throw ;
129 :    
130 :     : -u8trailing-garbage ( addr u1 -- addr u2 )
131 :     2dup + dup u8<< ( addr u1 end1 end2 )
132 : pazsan 1.28 2dup dup over over - u8addrlen + = if \ last character ok
133 : anton 1.13 2drop
134 :     else
135 :     nip nip over -
136 :     then ;
137 :    
138 : anton 1.22 [IFUNDEF] wcwidth
139 : pazsan 1.24 : wc,3 ( n low high -- ) 1+ , , , ;
140 :    
141 :     Create wc-table \ derived from wcwidth source code, for UCS32
142 :     0 0300 0357 wc,3
143 :     0 035D 036F wc,3
144 :     0 0483 0486 wc,3
145 :     0 0488 0489 wc,3
146 :     0 0591 05A1 wc,3
147 :     0 05A3 05B9 wc,3
148 :     0 05BB 05BD wc,3
149 :     0 05BF 05BF wc,3
150 :     0 05C1 05C2 wc,3
151 :     0 05C4 05C4 wc,3
152 :     0 0600 0603 wc,3
153 :     0 0610 0615 wc,3
154 :     0 064B 0658 wc,3
155 :     0 0670 0670 wc,3
156 :     0 06D6 06E4 wc,3
157 :     0 06E7 06E8 wc,3
158 :     0 06EA 06ED wc,3
159 :     0 070F 070F wc,3
160 :     0 0711 0711 wc,3
161 :     0 0730 074A wc,3
162 :     0 07A6 07B0 wc,3
163 :     0 0901 0902 wc,3
164 :     0 093C 093C wc,3
165 :     0 0941 0948 wc,3
166 :     0 094D 094D wc,3
167 :     0 0951 0954 wc,3
168 :     0 0962 0963 wc,3
169 :     0 0981 0981 wc,3
170 :     0 09BC 09BC wc,3
171 :     0 09C1 09C4 wc,3
172 :     0 09CD 09CD wc,3
173 :     0 09E2 09E3 wc,3
174 :     0 0A01 0A02 wc,3
175 :     0 0A3C 0A3C wc,3
176 :     0 0A41 0A42 wc,3
177 :     0 0A47 0A48 wc,3
178 :     0 0A4B 0A4D wc,3
179 :     0 0A70 0A71 wc,3
180 :     0 0A81 0A82 wc,3
181 :     0 0ABC 0ABC wc,3
182 :     0 0AC1 0AC5 wc,3
183 :     0 0AC7 0AC8 wc,3
184 :     0 0ACD 0ACD wc,3
185 :     0 0AE2 0AE3 wc,3
186 :     0 0B01 0B01 wc,3
187 :     0 0B3C 0B3C wc,3
188 :     0 0B3F 0B3F wc,3
189 :     0 0B41 0B43 wc,3
190 :     0 0B4D 0B4D wc,3
191 :     0 0B56 0B56 wc,3
192 :     0 0B82 0B82 wc,3
193 :     0 0BC0 0BC0 wc,3
194 :     0 0BCD 0BCD wc,3
195 :     0 0C3E 0C40 wc,3
196 :     0 0C46 0C48 wc,3
197 :     0 0C4A 0C4D wc,3
198 :     0 0C55 0C56 wc,3
199 :     0 0CBC 0CBC wc,3
200 :     0 0CBF 0CBF wc,3
201 :     0 0CC6 0CC6 wc,3
202 :     0 0CCC 0CCD wc,3
203 :     0 0D41 0D43 wc,3
204 :     0 0D4D 0D4D wc,3
205 :     0 0DCA 0DCA wc,3
206 :     0 0DD2 0DD4 wc,3
207 :     0 0DD6 0DD6 wc,3
208 :     0 0E31 0E31 wc,3
209 :     0 0E34 0E3A wc,3
210 :     0 0E47 0E4E wc,3
211 :     0 0EB1 0EB1 wc,3
212 :     0 0EB4 0EB9 wc,3
213 :     0 0EBB 0EBC wc,3
214 :     0 0EC8 0ECD wc,3
215 :     0 0F18 0F19 wc,3
216 :     0 0F35 0F35 wc,3
217 :     0 0F37 0F37 wc,3
218 :     0 0F39 0F39 wc,3
219 :     0 0F71 0F7E wc,3
220 :     0 0F80 0F84 wc,3
221 :     0 0F86 0F87 wc,3
222 :     0 0F90 0F97 wc,3
223 :     0 0F99 0FBC wc,3
224 :     0 0FC6 0FC6 wc,3
225 :     0 102D 1030 wc,3
226 :     0 1032 1032 wc,3
227 :     0 1036 1037 wc,3
228 :     0 1039 1039 wc,3
229 :     0 1058 1059 wc,3
230 :     1 0000 1100 wc,3
231 :     2 1100 115f wc,3
232 :     0 1160 11FF wc,3
233 :     0 1712 1714 wc,3
234 :     0 1732 1734 wc,3
235 :     0 1752 1753 wc,3
236 :     0 1772 1773 wc,3
237 :     0 17B4 17B5 wc,3
238 :     0 17B7 17BD wc,3
239 :     0 17C6 17C6 wc,3
240 :     0 17C9 17D3 wc,3
241 :     0 17DD 17DD wc,3
242 :     0 180B 180D wc,3
243 :     0 18A9 18A9 wc,3
244 :     0 1920 1922 wc,3
245 :     0 1927 1928 wc,3
246 :     0 1932 1932 wc,3
247 :     0 1939 193B wc,3
248 :     0 200B 200F wc,3
249 :     0 202A 202E wc,3
250 :     0 2060 2063 wc,3
251 :     0 206A 206F wc,3
252 :     0 20D0 20EA wc,3
253 :     2 2329 232A wc,3
254 :     0 302A 302F wc,3
255 :     2 2E80 303E wc,3
256 :     0 3099 309A wc,3
257 :     2 3040 A4CF wc,3
258 :     2 AC00 D7A3 wc,3
259 :     2 F900 FAFF wc,3
260 :     0 FB1E FB1E wc,3
261 :     0 FE00 FE0F wc,3
262 :     0 FE20 FE23 wc,3
263 :     2 FE30 FE6F wc,3
264 :     0 FEFF FEFF wc,3
265 :     2 FF00 FF60 wc,3
266 :     2 FFE0 FFE6 wc,3
267 :     0 FFF9 FFFB wc,3
268 :     0 1D167 1D169 wc,3
269 :     0 1D173 1D182 wc,3
270 :     0 1D185 1D18B wc,3
271 :     0 1D1AA 1D1AD wc,3
272 :     2 20000 2FFFD wc,3
273 :     2 30000 3FFFD wc,3
274 :     0 E0001 E0001 wc,3
275 :     0 E0020 E007F wc,3
276 :     0 E0100 E01EF wc,3
277 :     here wc-table - Constant #wc-table
278 :    
279 :     \ inefficient table walk:
280 :    
281 :     : wcwidth ( xc -- n )
282 :     wc-table #wc-table over + swap ?DO
283 :     dup I 2@ within IF I 2 cells + @ UNLOOP EXIT THEN
284 :     3 cells +LOOP 1 ;
285 : anton 1.22 [THEN]
286 :    
287 : pazsan 1.19 : u8width ( xcaddr u -- n )
288 :     0 rot rot over + swap ?DO
289 : anton 1.22 I xc@+ swap >r wcwidth +
290 : pazsan 1.19 r> I - +LOOP ;
291 :    
292 : anton 1.13 : set-encoding-utf-8 ( -- )
293 :     ['] u8emit is xemit
294 :     ['] u8key is xkey
295 :     ['] u8>> is xchar+
296 :     ['] u8<< is xchar-
297 : pazsan 1.26 [ [IFDEF] xstring+ ]
298 :     ['] u8string+ is xstring+
299 :     ['] u8string- is xstring-
300 :     ['] +u8string is +xstring
301 :     ['] -u8string is -xstring
302 :     [ [THEN] ]
303 : anton 1.13 ['] u8@ is xc@
304 :     ['] u8!+? is xc!+?
305 :     ['] u8@+ is xc@+
306 :     ['] u8len is xc-size
307 : pazsan 1.20 [ [IFDEF] x-width ]
308 : pazsan 1.19 ['] u8width is x-width
309 : pazsan 1.20 [ [THEN] ]
310 : pazsan 1.28 [ [IFDEF] x-size ]
311 :     ['] u8addrlen is x-size
312 :     [ [THEN] ]
313 : anton 1.13 ['] -u8trailing-garbage is -trailing-garbage
314 :     ;
315 : pazsan 1.1
316 : anton 1.15 : utf-8-cold ( -- )
317 : pazsan 1.16 s" LC_ALL" getenv 2dup d0= IF 2drop
318 :     s" LC_CTYPE" getenv 2dup d0= IF 2drop
319 :     s" LANG" getenv 2dup d0= IF 2drop
320 :     s" C" THEN THEN THEN
321 :     s" UTF-8" search nip nip
322 : anton 1.15 IF set-encoding-utf-8 ELSE set-encoding-fixed-width THEN ;
323 :    
324 : anton 1.23 :noname ( -- )
325 :     defers 'cold
326 :     utf-8-cold
327 :     ; is 'cold
328 : anton 1.15
329 :     utf-8-cold

CVS Admin

Powered by ViewCVS 1.0-dev
(Powered by ViewCVS)

ViewCVS and CVS Help