~ubuntu-branches/ubuntu/lucid/camomile/lucid

« back to all changes in this revision

Viewing changes to public/uNF.ml

  • Committer: Bazaar Package Importer
  • Author(s): Sylvain Le Gall
  • Date: 2005-12-03 01:18:55 UTC
  • Revision ID: james.westby@ubuntu.com-20051203011855-qzvwlld1xyqnl62t
Tags: upstream-0.6.3
ImportĀ upstreamĀ versionĀ 0.6.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
(* $Id: uNF.ml,v 1.4 2004/11/03 11:21:51 yori Exp $ *)
 
2
(* Copyright 2002 Yamagata Yoriyuki. distributed with LGPL *)
 
3
 
 
4
open UCharInfo
 
5
 
 
6
let null = UChar.chr_of_uint 0
 
7
 
 
8
let decomposition_tbl = load_decomposition_tbl ()
 
9
let decomposition u = UCharTbl.get decomposition_tbl u
 
10
 
 
11
let composition_exclusion_tbl = load_composition_exclusion_tbl ()
 
12
let composition_exclusion u = UCharTbl.Bool.get composition_exclusion_tbl u
 
13
 
 
14
let composition_tbl = load_composition_tbl ()
 
15
let composition u = UCharTbl.get composition_tbl u
 
16
 
 
17
let rec add_list x = function
 
18
    [] -> ()
 
19
  | u :: r ->
 
20
      XString.add_char x u;
 
21
      add_list x r
 
22
 
 
23
let shiftright x i j =
 
24
  for k = j downto i do XString.set x (k + 1) (XString.get x k) done
 
25
 
 
26
let rotate x i j =
 
27
  let u = XString.get x j in
 
28
  shiftright x i (j - 1);
 
29
  XString.set x i u
 
30
 
 
31
let blit x i x' i' len =
 
32
  for k = 0 to len - 1 do
 
33
    XString.set x' (i' + k) (XString.get x (i + k));
 
34
  done
 
35
 
 
36
let rec nfd u =
 
37
  match decomposition u with
 
38
    `HangulSyllable -> Hangul.decompose u
 
39
  | `Composite (`Canon, d) -> d
 
40
  | _ -> [u]
 
41
 
 
42
let rec nfkd u =
 
43
  match decomposition u with
 
44
    `HangulSyllable -> 
 
45
      Hangul.decompose u
 
46
  | `Composite (_, d) ->
 
47
      List.fold_right (fun u a -> (nfkd u) @ a) d []
 
48
  | `Canonform -> [u]
 
49
 
 
50
let rec canon_decompose_uchar x u =
 
51
  match decomposition u with
 
52
    `HangulSyllable ->
 
53
      Hangul.add_decomposition x u
 
54
  | `Composite (`Canon, d) -> 
 
55
      add_list x d
 
56
  | _ -> XString.add_char x u
 
57
 
 
58
class canon_decompose (c_out : UChar.t OOChannel.obj_output_channel) =
 
59
  object
 
60
    method put u = List.iter c_out#put (nfd u)
 
61
    method close_out = c_out#close_out
 
62
    method flush () = c_out#flush ()
 
63
  end
 
64
 
 
65
let rec kompat_decompose_uchar x u =
 
66
  match decomposition u with
 
67
    `Composite (_, d) -> 
 
68
      List.iter (kompat_decompose_uchar x) d
 
69
  | _ -> Hangul.add_decomposition x u
 
70
 
 
71
class kompat_decompose c_out : [UChar.t] OOChannel.obj_output_channel =
 
72
  object
 
73
    method put u = List.iter c_out#put (nfkd u)
 
74
    method close_out = c_out#close_out
 
75
    method flush () = c_out#flush ()
 
76
  end
 
77
 
 
78
let canon_reorder x =
 
79
  let chead = ref 0 in
 
80
  let pos = ref 0 in
 
81
  for i = 0 to XString.length x - 1 do
 
82
    let u = XString.get x i in
 
83
    let c = combined_class u in
 
84
    if c = 0 then chead := i else begin
 
85
      pos := i - 1;
 
86
      while
 
87
        !pos >= !chead &&
 
88
        combined_class (XString.get x !pos) > c
 
89
      do decr pos done;
 
90
      rotate x (!pos + 1) i
 
91
    end
 
92
  done
 
93
 
 
94
class canon_reorder c_out : [UChar.t] OOChannel.obj_output_channel =
 
95
  object (self)
 
96
    val mutable sq = []
 
97
    method private out_buf =
 
98
      let sq' = 
 
99
        List.stable_sort
 
100
          (fun (c1, _) (c2, _) -> c1 - c2)
 
101
          sq in
 
102
      List.iter (fun (_, u) -> c_out#put u) sq';
 
103
      sq <- []
 
104
    method put u =
 
105
      let c = combined_class u in
 
106
      if c = 0 then
 
107
        (if sq <> [] then self#out_buf;
 
108
         c_out#put u)
 
109
      else
 
110
        sq <- (c, u) :: sq
 
111
    method close_out () = 
 
112
      self#out_buf;
 
113
      c_out#close_out ()
 
114
    method flush () =  
 
115
      if sq <> [] then
 
116
        failwith 
 
117
          "uNF.canon_reorder#flush: \
 
118
             Cannot flush the entire buffer";
 
119
      c_out#flush ()
 
120
  end
 
121
 
 
122
let rec look_composition u1 = function
 
123
    [] -> None
 
124
  | (u, u') :: rest when u = u1 ->
 
125
      if composition_exclusion u' || combined_class u' <> 0 then None
 
126
      else Some u'
 
127
  | _ :: rest -> look_composition u1 rest
 
128
 
 
129
let rec canon_compose_loop x i j x' k c' =
 
130
  if j >= XString.length x then begin
 
131
    blit x i x' (k + 1) (XString.length x - i);
 
132
    k + max (XString.length x - i) 0
 
133
  end else
 
134
    let u = XString.get x j in
 
135
    let c = combined_class u in
 
136
    let b = if j = i || c' <> c then (*not blocked!*)
 
137
      match look_composition u (composition (XString.get x' k)) with
 
138
        None -> true
 
139
      | Some u' ->
 
140
          XString.set x' k u';
 
141
          shiftright x i (j - 1); 
 
142
          false
 
143
    else true
 
144
    in
 
145
    if b && c = 0 then begin
 
146
      blit x i x' (k + 1) (j - i + 1);
 
147
      canon_compose_loop x (j + 1) (j + 1) x' (k + 1 + j - i) 0
 
148
    end else
 
149
      let i' = if b then i else i + 1 in
 
150
      let c' = if b then c else c' in
 
151
      canon_compose_loop x i' (j + 1) x' k c'
 
152
        
 
153
let canon_compose x' x =
 
154
  if XString.length x = 0 then () else
 
155
  let pos = ref 0 in
 
156
  while 
 
157
    !pos < XString.length x &&
 
158
    combined_class (XString.get x !pos) <> 0 
 
159
  do incr pos done;
 
160
  blit x 0 x' 0 !pos;
 
161
  if !pos < XString.length x then begin
 
162
    XString.set x' !pos (XString.get x !pos);
 
163
    pos := canon_compose_loop x (!pos + 1) (!pos + 1) x' !pos 0
 
164
  end else ();
 
165
  XString.shrink x' (!pos + 1)
 
166
 
 
167
class canon_compose c_out : [UChar.t] OOChannel.obj_output_channel =
 
168
  object (self)
 
169
    val mutable has_strt = false
 
170
    val mutable strt = null
 
171
    val mutable cmp_cnd = []
 
172
    val mutable lst_cc = -1
 
173
    val sq = Queue.create ()
 
174
    method private set_strt u =
 
175
      if has_strt then c_out#put strt;
 
176
      Queue.iter c_out#put sq;
 
177
      strt <- u;
 
178
      has_strt <- true;
 
179
      cmp_cnd <- composition u;
 
180
      lst_cc <- -1;
 
181
      Queue.clear sq
 
182
    method private output_buffer () =
 
183
      if has_strt then c_out#put strt;
 
184
      Queue.iter c_out#put sq;
 
185
    method put u =
 
186
      let c = combined_class u in
 
187
      if not has_strt then
 
188
        if c = 0 then self#set_strt u
 
189
        else c_out#put u
 
190
      else
 
191
        if c = lst_cc then Queue.add u sq else
 
192
        match look_composition u cmp_cnd with
 
193
          Some u' -> strt <- u'
 
194
        | None ->
 
195
            if c = 0 then self#set_strt u else begin
 
196
              Queue.add u sq;
 
197
              lst_cc <- c
 
198
            end
 
199
    method close_out () =
 
200
      self#output_buffer ();
 
201
      c_out#close_out ()
 
202
    method flush () = 
 
203
      self#output_buffer ();
 
204
      c_out#flush ()
 
205
  end
 
206
 
 
207
class nfd c_out =
 
208
  let c = new canon_reorder c_out in
 
209
  object
 
210
    inherit canon_decompose c
 
211
  end
 
212
 
 
213
class nfc c_out =
 
214
  let c = new canon_compose c_out in
 
215
  let c = new canon_reorder c in
 
216
  object
 
217
    inherit canon_decompose c
 
218
    method flush = c_out#flush
 
219
  end
 
220
 
 
221
class nfkd c_out  =
 
222
  let c = new canon_reorder c_out in
 
223
  object
 
224
    inherit kompat_decompose c
 
225
    method flush = c_out#flush
 
226
  end
 
227
 
 
228
class nfkc c_out =
 
229
  let c = new canon_compose c_out in
 
230
  let c = new canon_reorder c in
 
231
  object
 
232
    inherit kompat_decompose c
 
233
    method flush = c_out#flush
 
234
  end
 
235
 
 
236
module type Type =
 
237
sig
 
238
  type text
 
239
  val nfd : text -> text
 
240
  val nfkd : text -> text
 
241
  val nfc : text -> text
 
242
  val nfkc : text -> text
 
243
 
 
244
  module NFCBuf :  sig
 
245
    type buf
 
246
    val create : int -> buf
 
247
 
 
248
    val contents : buf -> text
 
249
    val clear : buf -> unit
 
250
    val reset : buf -> unit
 
251
    val add_char : buf -> UChar.t -> unit
 
252
    val add_string : buf -> text -> unit
 
253
    val add_buffer : buf -> buf -> unit
 
254
  end
 
255
 
 
256
  val nfc_append : text -> text -> text
 
257
 
 
258
  val put_nfd : XString.t -> text -> unit
 
259
  val put_nfkd : XString.t -> text -> unit
 
260
  val put_nfc : XString.t -> text -> unit
 
261
  val put_nfkc : XString.t -> text -> unit
 
262
 
 
263
  type index
 
264
 
 
265
  val nfd_inc : 
 
266
      text -> index -> 
 
267
        ([`Inc of UChar.t list * index * 'a lazy_t ] as 'a)
 
268
  val canon_compare : text -> text -> int
 
269
end
 
270
 
 
271
module Make (Text : UnicodeString.Type) =
 
272
  struct
 
273
 
 
274
    type inc = [`Inc of UChar.t list * Text.index * 'a lazy_t] as 'a
 
275
 
 
276
    let rec inc_end i =
 
277
      `Inc ([], i, lazy (inc_end i))
 
278
 
 
279
    let rec inc_canon_decompose t i : inc =
 
280
      if Text.out_of_range t i then inc_end i else
 
281
      let i' = Text.next t i in
 
282
      `Inc (nfd (Text.look t i), i', lazy (inc_canon_decompose t i'))
 
283
        
 
284
    let rec canon_insert_list ((u, c) as x) a =
 
285
      match a with
 
286
        [] -> [x]
 
287
      | (u', c') as y :: rest ->
 
288
          if c' <= c then
 
289
            y :: canon_insert_list x rest
 
290
          else
 
291
            x :: a
 
292
 
 
293
    let rec split1_list = function
 
294
        [] -> []
 
295
      | (x, _) :: rest -> x :: split1_list rest
 
296
 
 
297
    let canon_sort_list sq =
 
298
      let rec loop a = function
 
299
          [] -> split1_list a
 
300
        | (u, 0) :: rest -> (split1_list a) @ (u :: (loop [] rest))
 
301
        | (u, c) as x :: rest ->
 
302
            loop (canon_insert_list x a) rest in
 
303
      loop [] sq
 
304
 
 
305
    let rec read_combined_class = function
 
306
        [] -> []
 
307
      | u :: rest -> 
 
308
          (u, combined_class u) :: read_combined_class rest
 
309
 
 
310
    let inc_reorder f t i =
 
311
      let `Inc (us, i', f) = f t i in 
 
312
      let rec loop (f : inc Lazy.t) a i =
 
313
        let `Inc (us, i', f) = Lazy.force f in
 
314
        let a' = read_combined_class us in
 
315
        match a' with
 
316
          [] ->
 
317
            `Inc (canon_sort_list a, i, lazy (inc_end i))
 
318
        | (_, 0) :: _ -> 
 
319
            `Inc (canon_sort_list a, i, lazy (loop f a' i'))
 
320
        | _ -> loop f (a @ a') i' in
 
321
      loop f (read_combined_class us) i'
 
322
 
 
323
    let nfd_inc t i =
 
324
      inc_reorder inc_canon_decompose t i
 
325
 
 
326
    let canon_compare t1 t2 =
 
327
      let `Inc(us1, _, f1) = nfd_inc t1 (Text.nth t1 0) in
 
328
      let `Inc(us2, _, f2) = nfd_inc t2 (Text.nth t2 0) in
 
329
      let rec loop us1 us2 f1 f2 =
 
330
        match us1, us2 with
 
331
          [], [] -> 0
 
332
        | [], _ -> ~-1
 
333
        | _, [] -> 1
 
334
        | u1 :: r1, u2 :: r2 ->
 
335
            let sgn = UChar.compare u1 u2 in
 
336
            if sgn <> 0 then sgn else
 
337
            let us1, f1 =
 
338
              if r1 = [] then
 
339
                let `Inc (us1, _, f1) = Lazy.force f1 in
 
340
                (us1, f1)
 
341
              else
 
342
                (r1, f1) in
 
343
            let us2, f2 =
 
344
              if r2 = [] then
 
345
                let `Inc (us2, _, f2) = Lazy.force f2 in
 
346
                (us2, f2)
 
347
              else
 
348
                (r2, f2) in
 
349
            loop us1 us2 f1 f2 in
 
350
      loop us1 us2 f1 f2
 
351
 
 
352
    type text = Text.t
 
353
    type index = Text.index
 
354
 
 
355
    let canon_decompose x t =
 
356
      Text.iter (canon_decompose_uchar x) t
 
357
 
 
358
    let kompat_decompose x t =
 
359
      Text.iter (kompat_decompose_uchar x) t
 
360
        
 
361
    let text_of_xstring x = Text.init (XString.length x) (XString.get x)
 
362
 
 
363
    let nfd t =
 
364
      let x = XString.make 0 (UChar.chr_of_uint 0) in
 
365
      canon_decompose x t;
 
366
      canon_reorder x;
 
367
      text_of_xstring x
 
368
 
 
369
    let nfkd t =
 
370
      let x = XString.make 0 (UChar.chr_of_uint 0) in
 
371
      kompat_decompose x t;
 
372
      canon_reorder x;
 
373
      text_of_xstring x
 
374
 
 
375
    let nfc t =
 
376
      let x = XString.make 0 (UChar.chr_of_uint 0) in
 
377
      canon_decompose x t;
 
378
      canon_reorder x;
 
379
      canon_compose x x;
 
380
      Hangul.compose x x;
 
381
      text_of_xstring x
 
382
 
 
383
    let nfkc t =
 
384
      let x = XString.make 0 (UChar.chr_of_uint 0) in
 
385
      kompat_decompose x t;
 
386
      canon_reorder x;
 
387
      canon_compose x x;
 
388
      Hangul.compose x x;
 
389
      text_of_xstring x
 
390
 
 
391
    let put_nfd x t =
 
392
      XString.clear x;
 
393
      canon_decompose x t;
 
394
      canon_reorder x
 
395
 
 
396
    let put_nfkd x t =
 
397
      XString.clear x;
 
398
      kompat_decompose x t;
 
399
      canon_reorder x
 
400
 
 
401
    let put_nfc x t =
 
402
      XString.clear x;
 
403
      canon_decompose x t;
 
404
      canon_reorder x;
 
405
      canon_compose x x;
 
406
      Hangul.compose x x
 
407
 
 
408
    let put_nfkc x t =
 
409
      XString.clear x;
 
410
      kompat_decompose x t;
 
411
      canon_reorder x;
 
412
      canon_compose x x;
 
413
      Hangul.compose x x
 
414
 
 
415
    module NFCBuf = struct
 
416
 
 
417
      type buf = {mutable normalized : bool; mutable buf : XString.t}
 
418
 
 
419
      let create bufsize = 
 
420
        {normalized = true; buf = XString.make ~bufsize 0 null}
 
421
 
 
422
      let contents b =
 
423
        (if not b.normalized then
 
424
          let buf = XString.make 0 null in
 
425
          XString.iter (canon_decompose_uchar buf) b.buf;
 
426
          canon_reorder buf;
 
427
          canon_compose buf buf;
 
428
          b.buf <- buf;
 
429
          b.normalized <- true);
 
430
        text_of_xstring b.buf
 
431
 
 
432
      let clear b =
 
433
        b.normalized <- true;
 
434
        XString.clear b.buf
 
435
 
 
436
      let reset b =
 
437
        b.normalized <- true;
 
438
        XString.reset b.buf
 
439
 
 
440
      let add_char b u =
 
441
        b.normalized <- false;
 
442
        XString.add_char b.buf u
 
443
 
 
444
      let add_string b t =
 
445
        b.normalized <- false;
 
446
        Text.iter (XString.add_char b.buf) t
 
447
 
 
448
      let add_buffer b1 b2 =
 
449
        b1.normalized <- false;
 
450
        XString.add_xstring b1.buf b2.buf
 
451
    end
 
452
 
 
453
    let nfc_append t1 t2 =
 
454
      let b = XString.make 0 null in
 
455
      canon_decompose b t1;
 
456
      canon_decompose b t2;
 
457
      canon_reorder b;
 
458
      canon_compose b b;
 
459
      text_of_xstring b
 
460
  end