ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/staticperl/perl/ext/Unicode/Normalize/mkheader
Revision: 1.1
Committed: Thu Jun 30 14:27:06 2005 UTC (21 years, 3 months ago) by root
Branch: MAIN
CVS Tags: PERL-5-8-7, HEAD
Branch point for: PERL
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 #!perl
2     #
3     # This auxiliary script makes five header files
4     # used for building XSUB of Unicode::Normalize.
5     #
6     # Usage:
7     # <do 'mkheader'> in perl, or <perl mkheader> in command line
8     #
9     # Input files:
10     # unicore/CombiningClass.pl (or unicode/CombiningClass.pl)
11     # unicore/Decomposition.pl (or unicode/Decomposition.pl)
12     # unicore/CompositionExclusions.txt (or unicode/CompExcl.txt)
13     #
14     # Output files:
15     # unfcan.h
16     # unfcpt.h
17     # unfcmb.h
18     # unfcmp.h
19     # unfexc.h
20     #
21     use 5.006;
22     use strict;
23     use warnings;
24     use Carp;
25     use File::Spec;
26    
27     BEGIN {
28     unless ("A" eq pack('U', 0x41)) {
29     die "Unicode::Normalize cannot stringify a Unicode code point\n";
30     }
31     }
32    
33     our $PACKAGE = 'Unicode::Normalize, mkheader';
34    
35     our $Combin = do "unicore/CombiningClass.pl"
36     || do "unicode/CombiningClass.pl"
37     || croak "$PACKAGE: CombiningClass.pl not found";
38    
39     our $Decomp = do "unicore/Decomposition.pl"
40     || do "unicode/Decomposition.pl"
41     || croak "$PACKAGE: Decomposition.pl not found";
42    
43     our %Combin; # $codepoint => $number : combination class
44     our %Canon; # $codepoint => \@codepoints : canonical decomp.
45     our %Compat; # $codepoint => \@codepoints : compat. decomp.
46     # after _U_stringify(), ($codepoint => $hexstring) for %Canon and %Compat
47     our %Exclus; # $codepoint => 1 : composition exclusions
48     our %Single; # $codepoint => 1 : singletons
49     our %NonStD; # $codepoint => 1 : non-starter decompositions
50    
51     our %Comp1st; # $codepoint => $listname : may be composed with a next char.
52     our %Comp2nd; # $codepoint => 1 : may be composed with a prev char.
53     our %CompList; # $listname,$2nd => $codepoint : composite
54    
55     our $prefix = "UNF_";
56     our $structname = "${prefix}complist";
57    
58     ########## definition of Hangul constants ##########
59     use constant SBase => 0xAC00;
60     use constant SFinal => 0xD7A3; # SBase -1 + SCount
61     use constant SCount => 11172; # LCount * NCount
62     use constant NCount => 588; # VCount * TCount
63     use constant LBase => 0x1100;
64     use constant LFinal => 0x1112;
65     use constant LCount => 19;
66     use constant VBase => 0x1161;
67     use constant VFinal => 0x1175;
68     use constant VCount => 21;
69     use constant TBase => 0x11A7;
70     use constant TFinal => 0x11C2;
71     use constant TCount => 28;
72    
73     sub decomposeHangul {
74     my $SIndex = $_[0] - SBase;
75     my $LIndex = int( $SIndex / NCount);
76     my $VIndex = int(($SIndex % NCount) / TCount);
77     my $TIndex = $SIndex % TCount;
78     my @ret = (
79     LBase + $LIndex,
80     VBase + $VIndex,
81     $TIndex ? (TBase + $TIndex) : (),
82     );
83     wantarray ? @ret : pack('U*', @ret);
84     # any element in @ret greater than 0xFF, so no need of u2n conversion.
85     }
86    
87     ########## getting full decomposion ##########
88     {
89     my($f, $fh);
90     foreach my $d (@INC) {
91     $f = File::Spec->catfile($d, "unicore", "CompositionExclusions.txt");
92     last if open($fh, $f);
93     $f = File::Spec->catfile($d, "unicode", "CompExcl.txt");
94     last if open($fh, $f);
95     $f = undef;
96     }
97     croak "$PACKAGE: neither unicore/CompositionExclusions.txt "
98     . "nor unicode/CompExcl.txt is found in @INC" unless defined $f;
99    
100     while (<$fh>) {
101     next if /^#/ or /^$/;
102     s/#.*//;
103     $Exclus{ hex($1) } = 1 if /([0-9A-Fa-f]+)/;
104     }
105     close $fh;
106     }
107    
108     ##
109     ## converts string "hhhh hhhh hhhh" to a numeric list
110     ##
111     sub _getHexArray { map hex, $_[0] =~ /([0-9A-Fa-f]+)/g }
112    
113     while ($Combin =~ /(.+)/g) {
114     my @tab = split /\t/, $1;
115     my $ini = hex $tab[0];
116     if ($tab[1] eq '') {
117     $Combin{ $ini } = $tab[2];
118     } else {
119     $Combin{ $_ } = $tab[2] foreach $ini .. hex($tab[1]);
120     }
121     }
122    
123     while ($Decomp =~ /(.+)/g) {
124     my @tab = split /\t/, $1;
125     my $compat = $tab[2] =~ s/<[^>]+>//;
126     my $dec = [ _getHexArray($tab[2]) ]; # decomposition
127     my $ini = hex($tab[0]); # initial decomposable character
128    
129     my $listname =
130     @$dec == 2 ? sprintf("${structname}_%06x", $dec->[0]) : 'USELESS';
131     # %04x is bad since it'd place _3046 after _1d157.
132    
133     if ($tab[1] eq '') {
134     $Compat{ $ini } = $dec;
135    
136     if (! $compat) {
137     $Canon{ $ini } = $dec;
138    
139     if (@$dec == 2) {
140     if ($Combin{ $dec->[0] }) {
141     $NonStD{ $ini } = 1;
142     } else {
143     $CompList{ $listname }{ $dec->[1] } = $ini;
144     $Comp1st{ $dec->[0] } = $listname;
145     $Comp2nd{ $dec->[1] } = 1 if ! $Exclus{$ini};
146     }
147     } elsif (@$dec == 1) {
148     $Single{ $ini } = 1;
149     } else {
150     croak("Weird Canonical Decomposition of U+$tab[0]");
151     }
152     }
153     } else {
154     foreach my $u ($ini .. hex($tab[1])) {
155     $Compat{ $u } = $dec;
156    
157     if (! $compat) {
158     $Canon{ $u } = $dec;
159    
160     if (@$dec == 2) {
161     if ($Combin{ $dec->[0] }) {
162     $NonStD{ $u } = 1;
163     } else {
164     $CompList{ $listname }{ $dec->[1] } = $u;
165     $Comp1st{ $dec->[0] } = $listname;
166     $Comp2nd{ $dec->[1] } = 1 if ! $Exclus{$u};
167     }
168     } elsif (@$dec == 1) {
169     $Single{ $u } = 1;
170     } else {
171     croak("Weird Canonical Decomposition of U+$tab[0]");
172     }
173     }
174     }
175     }
176     }
177    
178     # modern HANGUL JUNGSEONG and HANGUL JONGSEONG jamo
179     foreach my $j (0x1161..0x1175, 0x11A8..0x11C2) {
180     $Comp2nd{$j} = 1;
181     }
182    
183     sub getCanonList {
184     my @src = @_;
185     my @dec = map {
186     (SBase <= $_ && $_ <= SFinal) ? decomposeHangul($_)
187     : $Canon{$_} ? @{ $Canon{$_} } : $_
188     } @src;
189     return join(" ",@src) eq join(" ",@dec) ? @dec : getCanonList(@dec);
190     # condition @src == @dec is not ok.
191     }
192    
193     sub getCompatList {
194     my @src = @_;
195     my @dec = map {
196     (SBase <= $_ && $_ <= SFinal) ? decomposeHangul($_)
197     : $Compat{$_} ? @{ $Compat{$_} } : $_
198     } @src;
199     return join(" ",@src) eq join(" ",@dec) ? @dec : getCompatList(@dec);
200     # condition @src == @dec is not ok.
201     }
202    
203     # exhaustive decomposition
204     foreach my $key (keys %Canon) {
205     $Canon{$key} = [ getCanonList($key) ];
206     }
207    
208     # exhaustive decomposition
209     foreach my $key (keys %Compat) {
210     $Compat{$key} = [ getCompatList($key) ];
211     }
212    
213     sub _pack_U {
214     return pack('U*', @_);
215     }
216    
217     sub _U_stringify {
218     sprintf '"%s"', join '',
219     map sprintf("\\x%02x", $_), unpack 'C*', _pack_U(@_);
220     }
221    
222     foreach my $hash (\%Canon, \%Compat) {
223     foreach my $key (keys %$hash) {
224     $hash->{$key} = _U_stringify( @{ $hash->{$key} } );
225     }
226     }
227    
228     ########## writing header files ##########
229    
230     my @boolfunc = (
231     {
232     name => "Exclusion",
233     type => "bool",
234     hash => \%Exclus,
235     },
236     {
237     name => "Singleton",
238     type => "bool",
239     hash => \%Single,
240     },
241     {
242     name => "NonStDecomp",
243     type => "bool",
244     hash => \%NonStD,
245     },
246     {
247     name => "Comp2nd",
248     type => "bool",
249     hash => \%Comp2nd,
250     },
251     );
252    
253     my $file = "unfexc.h";
254     open FH, ">$file" or croak "$PACKAGE: $file can't be made";
255     binmode FH; select FH;
256    
257     print << 'EOF';
258     /*
259     * This file is auto-generated by mkheader.
260     * Any changes here will be lost!
261     */
262     EOF
263    
264     foreach my $tbl (@boolfunc) {
265     my @temp = sort {$a <=> $b} keys %{$tbl->{hash}};
266     my $type = $tbl->{type};
267     my $name = $tbl->{name};
268     print "$type is$name (UV uv)\n{\nreturn\n\t";
269    
270     while (@temp) {
271     my $cur = shift @temp;
272     if (@temp && $cur + 1 == $temp[0]) {
273     print "($cur <= uv && uv <= ";
274     while (@temp && $cur + 1 == $temp[0]) {
275     $cur = shift @temp;
276     }
277     print "$cur)";
278     print "\n\t|| " if @temp;
279     } else {
280     print "uv == $cur";
281     print "\n\t|| " if @temp;
282     }
283     }
284     print "\n\t? TRUE : FALSE;\n}\n\n";
285     }
286    
287     close FH;
288    
289     ####################################
290    
291     my $compinit =
292     "typedef struct { UV nextchar; UV composite; } $structname;\n\n";
293    
294     foreach my $i (sort keys %CompList) {
295     $compinit .= "$structname $i [] = {\n";
296     $compinit .= join ",\n",
297     map sprintf("\t{ %d, %d }", $_, $CompList{$i}{$_}),
298     sort {$a <=> $b } keys %{ $CompList{$i} };
299     $compinit .= ",\n{0,0}\n};\n\n"; # with sentinel
300     }
301    
302     my @tripletable = (
303     {
304     file => "unfcmb",
305     name => "combin",
306     type => "STDCHAR",
307     hash => \%Combin,
308     null => 0,
309     },
310     {
311     file => "unfcan",
312     name => "canon",
313     type => "char*",
314     hash => \%Canon,
315     null => "NULL",
316     },
317     {
318     file => "unfcpt",
319     name => "compat",
320     type => "char*",
321     hash => \%Compat,
322     null => "NULL",
323     },
324     {
325     file => "unfcmp",
326     name => "compos",
327     type => "$structname *",
328     hash => \%Comp1st,
329     null => "NULL",
330     init => $compinit,
331     },
332     );
333    
334     foreach my $tbl (@tripletable) {
335     my $file = "$tbl->{file}.h";
336     my $head = "${prefix}$tbl->{name}";
337     my $type = $tbl->{type};
338     my $hash = $tbl->{hash};
339     my $null = $tbl->{null};
340     my $init = $tbl->{init};
341    
342     open FH, ">$file" or croak "$PACKAGE: $file can't be made";
343     binmode FH; select FH;
344     my %val;
345    
346     print FH << 'EOF';
347     /*
348     * This file is auto-generated by mkheader.
349     * Any changes here will be lost!
350     */
351     EOF
352    
353     print $init if defined $init;
354    
355     foreach my $uv (keys %$hash) {
356     croak sprintf("a Unicode code point 0x%04X over 0x10FFFF.", $uv)
357     unless $uv <= 0x10FFFF;
358     my @c = unpack 'CCCC', pack 'N', $uv;
359     $val{ $c[1] }{ $c[2] }{ $c[3] } = $hash->{$uv};
360     }
361    
362     foreach my $p (sort { $a <=> $b } keys %val) {
363     next if ! $val{ $p };
364     for (my $r = 0; $r < 256; $r++) {
365     next if ! $val{ $p }{ $r };
366     printf "$type ${head}_%02x_%02x [256] = {\n", $p, $r;
367     for (my $c = 0; $c < 256; $c++) {
368     print "\t", defined $val{$p}{$r}{$c}
369     ? "($type)".$val{$p}{$r}{$c}
370     : $null;
371     print ',' if $c != 255;
372     print "\n" if $c % 8 == 7;
373     }
374     print "};\n\n";
375     }
376     }
377     foreach my $p (sort { $a <=> $b } keys %val) {
378     next if ! $val{ $p };
379     printf "$type* ${head}_%02x [256] = {\n", $p;
380     for (my $r = 0; $r < 256; $r++) {
381     print $val{ $p }{ $r }
382     ? sprintf("${head}_%02x_%02x", $p, $r)
383     : "NULL";
384     print ',' if $r != 255;
385     print "\n" if $val{ $p }{ $r } || ($r+1) % 8 == 0;
386     }
387     print "};\n\n";
388     }
389     print "$type** $head [] = {\n";
390     for (my $p = 0; $p <= 0x10; $p++) {
391     print $val{ $p } ? sprintf("${head}_%02x", $p) : "NULL";
392     print ',' if $p != 0x10;
393     print "\n";
394     }
395     print "};\n\n";
396     close FH;
397     }
398    
399     1;
400     __END__