push 2f3ca95c4974ba229fa47d638b3044f50788f3bd
[wine/hacks.git] / libs / wine / cpmap.pl
blobf27c5f206ed6c6b4b0e8b7d7fab7807eb5813c50
1 #!/usr/bin/perl -w
3 # Generate code page .c files from ftp.unicode.org descriptions
5 # Copyright 2000 Alexandre Julliard
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2.1 of the License, or (at your option) any later version.
12 # This library 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 GNU
15 # Lesser General Public License for more details.
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 use strict;
24 # base directory for ftp.unicode.org files
25 my $BASEDIR = "ftp.unicode.org/Public/";
26 my $MAPPREFIX = $BASEDIR . "MAPPINGS/";
28 # UnicodeData file
29 my $UNICODEDATA = $BASEDIR . "UNIDATA/UnicodeData.txt";
31 # Sort keys file
32 my $SORTKEYS = "www.unicode.org/reports/tr10/allkeys.txt";
34 # Defaults mapping
35 my $DEFAULTS = "./defaults";
37 # Default char for undefined mappings
38 my $DEF_CHAR = ord '?';
40 my @allfiles =
42 [ 37, "VENDORS/MICSFT/EBCDIC/CP037.TXT", 0, "IBM EBCDIC US Canada" ],
43 [ 424, "VENDORS/MISC/CP424.TXT", 0, "IBM EBCDIC Hebrew" ],
44 [ 437, "VENDORS/MICSFT/PC/CP437.TXT", 1, "OEM United States" ],
45 [ 500, "VENDORS/MICSFT/EBCDIC/CP500.TXT", 0, "IBM EBCDIC International" ],
46 [ 737, "VENDORS/MICSFT/PC/CP737.TXT", 1, "OEM Greek 437G" ],
47 [ 775, "VENDORS/MICSFT/PC/CP775.TXT", 1, "OEM Baltic" ],
48 [ 850, "VENDORS/MICSFT/PC/CP850.TXT", 1, "OEM Multilingual Latin 1" ],
49 [ 852, "VENDORS/MICSFT/PC/CP852.TXT", 1, "OEM Slovak Latin 2" ],
50 [ 855, "VENDORS/MICSFT/PC/CP855.TXT", 1, "OEM Cyrillic" ],
51 [ 856, "VENDORS/MISC/CP856.TXT", 0, "Hebrew PC" ],
52 [ 857, "VENDORS/MICSFT/PC/CP857.TXT", 1, "OEM Turkish" ],
53 [ 860, "VENDORS/MICSFT/PC/CP860.TXT", 1, "OEM Portuguese" ],
54 [ 861, "VENDORS/MICSFT/PC/CP861.TXT", 1, "OEM Icelandic" ],
55 [ 862, "VENDORS/MICSFT/PC/CP862.TXT", 1, "OEM Hebrew" ],
56 [ 863, "VENDORS/MICSFT/PC/CP863.TXT", 1, "OEM Canadian French" ],
57 [ 864, "VENDORS/MICSFT/PC/CP864.TXT", 0, "OEM Arabic" ],
58 [ 865, "VENDORS/MICSFT/PC/CP865.TXT", 1, "OEM Nordic" ],
59 [ 866, "VENDORS/MICSFT/PC/CP866.TXT", 1, "OEM Russian" ],
60 [ 869, "VENDORS/MICSFT/PC/CP869.TXT", 1, "OEM Greek" ],
61 [ 874, "VENDORS/MICSFT/WindowsBestFit/bestfit874.txt", 1, "ANSI/OEM Thai" ],
62 [ 875, "VENDORS/MICSFT/EBCDIC/CP875.TXT", 0, "IBM EBCDIC Greek" ],
63 [ 878, "VENDORS/MISC/KOI8-R.TXT", 0, "Russian KOI8" ],
64 [ 932, "VENDORS/MICSFT/WindowsBestFit/bestfit932.txt", 0, "ANSI/OEM Japanese Shift-JIS" ],
65 [ 936, "VENDORS/MICSFT/WindowsBestFit/bestfit936.txt", 0, "ANSI/OEM Simplified Chinese GBK" ],
66 [ 949, "VENDORS/MICSFT/WindowsBestFit/bestfit949.txt", 0, "ANSI/OEM Korean Unified Hangul" ],
67 [ 950, "VENDORS/MICSFT/WindowsBestFit/bestfit950.txt", 0, "ANSI/OEM Traditional Chinese Big5" ],
68 [ 1006, "VENDORS/MISC/CP1006.TXT", 0, "IBM Arabic" ],
69 [ 1026, "VENDORS/MICSFT/EBCDIC/CP1026.TXT", 0, "IBM EBCDIC Latin 5 Turkish" ],
70 [ 1250, "VENDORS/MICSFT/WindowsBestFit/bestfit1250.txt", 0, "ANSI Eastern Europe" ],
71 [ 1251, "VENDORS/MICSFT/WindowsBestFit/bestfit1251.txt", 0, "ANSI Cyrillic" ],
72 [ 1252, "VENDORS/MICSFT/WindowsBestFit/bestfit1252.txt", 0, "ANSI Latin 1" ],
73 [ 1253, "VENDORS/MICSFT/WindowsBestFit/bestfit1253.txt", 0, "ANSI Greek" ],
74 [ 1254, "VENDORS/MICSFT/WindowsBestFit/bestfit1254.txt", 0, "ANSI Turkish" ],
75 [ 1255, "VENDORS/MICSFT/WindowsBestFit/bestfit1255.txt", 0, "ANSI Hebrew" ],
76 [ 1256, "VENDORS/MICSFT/WindowsBestFit/bestfit1256.txt", 0, "ANSI Arabic" ],
77 [ 1257, "VENDORS/MICSFT/WindowsBestFit/bestfit1257.txt", 0, "ANSI Baltic" ],
78 [ 1258, "VENDORS/MICSFT/WindowsBestFit/bestfit1258.txt", 0, "ANSI/OEM Viet Nam" ],
79 [ 1361, "OBSOLETE/EASTASIA/KSC/JOHAB.TXT", 0, "Korean Johab" ],
80 [ 10000, "VENDORS/MICSFT/MAC/ROMAN.TXT", 0, "Mac Roman" ],
81 [ 10006, "VENDORS/MICSFT/MAC/GREEK.TXT", 0, "Mac Greek" ],
82 [ 10007, "VENDORS/MICSFT/MAC/CYRILLIC.TXT", 0, "Mac Cyrillic" ],
83 [ 10029, "VENDORS/MICSFT/MAC/LATIN2.TXT", 0, "Mac Latin 2" ],
84 [ 10079, "VENDORS/MICSFT/MAC/ICELAND.TXT", 0, "Mac Icelandic" ],
85 [ 10081, "VENDORS/MICSFT/MAC/TURKISH.TXT", 0, "Mac Turkish" ],
86 [ 20127, undef, 0, "US-ASCII (7bit)" ],
87 [ 20866, "VENDORS/MISC/KOI8-R.TXT", 0, "Russian KOI8" ],
88 [ 20932, "OBSOLETE/EASTASIA/JIS/JIS0208.TXT", 0, "EUC-JP" ],
89 [ 21866, "VENDORS/MISC/KOI8-U.TXT", 0, "Ukrainian KOI8" ],
90 [ 28591, "ISO8859/8859-1.TXT", 0, "ISO 8859-1 Latin 1" ],
91 [ 28592, "ISO8859/8859-2.TXT", 0, "ISO 8859-2 Latin 2 (East European)" ],
92 [ 28593, "ISO8859/8859-3.TXT", 0, "ISO 8859-3 Latin 3 (South European)" ],
93 [ 28594, "ISO8859/8859-4.TXT", 0, "ISO 8859-4 Latin 4 (Baltic old)" ],
94 [ 28595, "ISO8859/8859-5.TXT", 0, "ISO 8859-5 Cyrillic" ],
95 [ 28596, "ISO8859/8859-6.TXT", 0, "ISO 8859-6 Arabic" ],
96 [ 28597, "ISO8859/8859-7.TXT", 0, "ISO 8859-7 Greek" ],
97 [ 28598, "ISO8859/8859-8.TXT", 0, "ISO 8859-8 Hebrew" ],
98 [ 28599, "ISO8859/8859-9.TXT", 0, "ISO 8859-9 Latin 5 (Turkish)" ],
99 [ 28600, "ISO8859/8859-10.TXT", 0, "ISO 8859-10 Latin 6 (Nordic)" ],
100 [ 28603, "ISO8859/8859-13.TXT", 0, "ISO 8859-13 Latin 7 (Baltic)" ],
101 [ 28604, "ISO8859/8859-14.TXT", 0, "ISO 8859-14 Latin 8 (Celtic)" ],
102 [ 28605, "ISO8859/8859-15.TXT", 0, "ISO 8859-15 Latin 9 (Euro)" ],
103 [ 28606, "ISO8859/8859-16.TXT", 0, "ISO 8859-16 Latin 10 (Balkan)" ]
107 my %ctype =
109 "upper" => 0x0001,
110 "lower" => 0x0002,
111 "digit" => 0x0004,
112 "space" => 0x0008,
113 "punct" => 0x0010,
114 "cntrl" => 0x0020,
115 "blank" => 0x0040,
116 "xdigit" => 0x0080,
117 "alpha" => 0x0100
120 my %categories =
122 "Lu" => $ctype{"alpha"}|$ctype{"upper"}, # Letter, Uppercase
123 "Ll" => $ctype{"alpha"}|$ctype{"lower"}, # Letter, Lowercase
124 "Lt" => $ctype{"alpha"}, # Letter, Titlecase
125 "Mn" => $ctype{"punct"}, # Mark, Non-Spacing
126 "Mc" => $ctype{"punct"}, # Mark, Spacing Combining
127 "Me" => $ctype{"punct"}, # Mark, Enclosing
128 "Nd" => $ctype{"digit"}, # Number, Decimal Digit
129 "Nl" => $ctype{"punct"}, # Number, Letter
130 "No" => $ctype{"punct"}, # Number, Other
131 "Zs" => $ctype{"space"}, # Separator, Space
132 "Zl" => $ctype{"space"}, # Separator, Line
133 "Zp" => $ctype{"space"}, # Separator, Paragraph
134 "Cc" => $ctype{"cntrl"}, # Other, Control
135 "Cf" => 0, # Other, Format
136 "Cs" => 0, # Other, Surrogate
137 "Co" => 0, # Other, Private Use
138 "Cn" => 0, # Other, Not Assigned
139 "Lm" => $ctype{"punct"}, # Letter, Modifier
140 "Lo" => $ctype{"alpha"}, # Letter, Other
141 "Pc" => $ctype{"punct"}, # Punctuation, Connector
142 "Pd" => $ctype{"punct"}, # Punctuation, Dash
143 "Ps" => $ctype{"punct"}, # Punctuation, Open
144 "Pe" => $ctype{"punct"}, # Punctuation, Close
145 "Pi" => $ctype{"punct"}, # Punctuation, Initial quote
146 "Pf" => $ctype{"punct"}, # Punctuation, Final quote
147 "Po" => $ctype{"punct"}, # Punctuation, Other
148 "Sm" => $ctype{"punct"}, # Symbol, Math
149 "Sc" => $ctype{"punct"}, # Symbol, Currency
150 "Sk" => $ctype{"punct"}, # Symbol, Modifier
151 "So" => $ctype{"punct"} # Symbol, Other
154 # a few characters need additional categories that cannot be determined automatically
155 my %special_categories =
157 "xdigit" => [ ord('0')..ord('9'),ord('A')..ord('F'),ord('a')..ord('f'),
158 0xff10..0xff19, 0xff21..0xff26, 0xff41..0xff46 ],
159 "space" => [ 0x09..0x0d, 0x85 ],
160 "blank" => [ 0x09, 0x20, 0xa0, 0x3000, 0xfeff ],
161 "cntrl" => [ 0x070f, 0x180b, 0x180c, 0x180d, 0x180e, 0x200c, 0x200d,
162 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
163 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
164 0xfff9, 0xfffa, 0xfffb ]
167 my %directions =
169 "L" => 1, # Left-to-Right
170 "LRE" => 11, # Left-to-Right Embedding
171 "LRO" => 11, # Left-to-Right Override
172 "R" => 2, # Right-to-Left
173 "AL" => 2, # Right-to-Left Arabic
174 "RLE" => 11, # Right-to-Left Embedding
175 "RLO" => 11, # Right-to-Left Override
176 "PDF" => 11, # Pop Directional Format
177 "EN" => 3, # European Number
178 "ES" => 4, # European Number Separator
179 "ET" => 5, # European Number Terminator
180 "AN" => 6, # Arabic Number
181 "CS" => 7, # Common Number Separator
182 "NSM" => 0, # Non-Spacing Mark
183 "BN" => 0, # Boundary Neutral
184 "B" => 8, # Paragraph Separator
185 "S" => 9, # Segment Separator
186 "WS" => 10, # Whitespace
187 "ON" => 11 # Other Neutrals
190 my @cp2uni = ();
191 my @lead_bytes = ();
192 my @uni2cp = ();
193 my @unicode_defaults = ();
194 my @unicode_aliases = ();
195 my @tolower_table = ();
196 my @toupper_table = ();
197 my @digitmap_table = ();
198 my @compatmap_table = ();
199 my @category_table = (0) x 65536;
200 my @direction_table = ();
201 my @decomp_table = ();
202 my @compose_table = ();
205 ################################################################
206 # read in the defaults file
207 sub READ_DEFAULTS($)
209 my $filename = shift;
210 my $start;
212 # first setup a few default mappings
214 open DEFAULTS, "$filename" or die "Cannot open $filename";
215 print "Loading $filename\n";
216 while (<DEFAULTS>)
218 next if /^\#/; # skip comments
219 next if /^$/; # skip empty lines
220 if (/^(([0-9a-fA-F]+)(,[0-9a-fA-F]+)*)\s+([0-9a-fA-F]+|'.'|none)\s+(\#.*)?/)
222 my @src = map hex, split /,/,$1;
223 my $dst = $4;
224 my $comment = $5;
225 if ($#src > 0) { push @unicode_aliases, \@src; }
226 next if ($dst eq "none");
227 $dst = ($dst =~ /\'.\'/) ? ord substr($dst,1,1) : hex $dst;
228 foreach my $src (@src)
230 die "Duplicate value" if defined($unicode_defaults[$src]);
231 $unicode_defaults[$src] = $dst;
233 next;
235 die "Unrecognized line $_\n";
238 # now build mappings from the decomposition field of the Unicode database
240 open UNICODEDATA, "$UNICODEDATA" or die "Cannot open $UNICODEDATA";
241 print "Loading $UNICODEDATA\n";
242 while (<UNICODEDATA>)
244 # Decode the fields ...
245 my ($code, $name, $cat, $comb, $bidi,
246 $decomp, $dec, $dig, $num, $mirror,
247 $oldname, $comment, $upper, $lower, $title) = split /;/;
248 my $dst;
249 my $src = hex $code;
251 die "unknown category $cat" unless defined $categories{$cat};
252 die "unknown directionality $bidi" unless defined $directions{$bidi};
254 $category_table[$src] = $categories{$cat};
255 $direction_table[$src] = $directions{$bidi};
257 if ($lower ne "")
259 $tolower_table[$src] = hex $lower;
260 $category_table[$src] |= $ctype{"upper"}|$ctype{"alpha"};
262 if ($upper ne "")
264 $toupper_table[$src] = hex $upper;
265 $category_table[$src] |= $ctype{"lower"}|$ctype{"alpha"};
267 if ($dec ne "")
269 $category_table[$src] |= $ctype{"digit"};
271 if ($dig ne "")
273 $digitmap_table[$src] = ord $dig;
276 # copy the category and direction for everything between First/Last pairs
277 if ($name =~ /, First>/) { $start = $src; }
278 if ($name =~ /, Last>/)
280 while ($start < $src)
282 $category_table[$start] = $category_table[$src];
283 $direction_table[$start] = $direction_table[$src];
284 $start++;
288 next if $decomp eq ""; # no decomposition, skip it
290 if ($decomp =~ /^<([a-zA-Z]+)>\s+([0-9a-fA-F]+)$/)
292 # decomposition of the form "<foo> 1234" -> use char if type is known
293 if (($src >= 0xf900 && $src < 0xfb00) || ($src >= 0xfe30 && $src < 0xfffd))
295 # Single char decomposition in the compatibility range
296 $compatmap_table[$src] = hex $2;
298 next unless ($1 eq "font" ||
299 $1 eq "noBreak" ||
300 $1 eq "circle" ||
301 $1 eq "super" ||
302 $1 eq "sub" ||
303 $1 eq "wide" ||
304 $1 eq "narrow" ||
305 $1 eq "compat" ||
306 $1 eq "small");
307 $dst = hex $2;
309 elsif ($decomp =~ /^<compat>\s+0020\s+([0-9a-fA-F]+)/)
311 # decomposition "<compat> 0020 1234" -> combining accent
312 $dst = hex $1;
314 elsif ($decomp =~ /^([0-9a-fA-F]+)/)
316 # decomposition contains only char values without prefix -> use first char
317 $dst = hex $1;
318 $category_table[$src] |= $category_table[$dst] if defined $category_table[$dst];
319 # store decomposition if it contains two chars
320 if ($decomp =~ /^([0-9a-fA-F]+)\s+([0-9a-fA-F]+)$/)
322 $decomp_table[$src] = [ hex $1, hex $2 ];
323 push @compose_table, [ hex $1, hex $2, $src ];
325 elsif ($decomp =~ /^(<[a-z]+>\s)*([0-9a-fA-F]+)$/ &&
326 (($src >= 0xf900 && $src < 0xfb00) || ($src >= 0xfe30 && $src < 0xfffd)))
328 # Single char decomposition in the compatibility range
329 $compatmap_table[$src] = hex $2;
332 else
334 next;
337 next if defined($unicode_defaults[$src]); # may have been set in the defaults file
339 # check for loops
340 for (my $i = $dst; ; $i = $unicode_defaults[$i])
342 die sprintf("loop detected for %04x -> %04x",$src,$dst) if $i == $src;
343 last unless defined($unicode_defaults[$i]);
345 $unicode_defaults[$src] = $dst;
348 # patch the category of some special characters
350 foreach my $cat (keys %special_categories)
352 my $flag = $ctype{$cat};
353 foreach my $i (@{$special_categories{$cat}}) { $category_table[$i] |= $flag; }
358 ################################################################
359 # parse the input file
360 sub READ_FILE($)
362 my $name = shift;
363 open INPUT,$name or die "Cannot open $name";
365 while (<INPUT>)
367 next if /^\#/; # skip comments
368 next if /^$/; # skip empty lines
369 next if /\x1a/; # skip ^Z
370 next if (/^0x([0-9a-fA-F]+)\s+\#UNDEFINED/); # undefined char
372 if (/^0x([0-9a-fA-F]+)\s+\#DBCS LEAD BYTE/)
374 my $cp = hex $1;
375 push @lead_bytes,$cp;
376 $cp2uni[$cp] = 0;
377 next;
379 if (/^0x([0-9a-fA-F]+)\s+0x([0-9a-fA-F]+)\s+(\#.*)?/)
381 my $cp = hex $1;
382 my $uni = hex $2;
383 $cp2uni[$cp] = $uni unless defined($cp2uni[$cp]);
384 $uni2cp[$uni] = $cp unless defined($uni2cp[$uni]);
385 if ($cp > 0xff && !defined($cp2uni[$cp >> 8]))
387 push @lead_bytes,$cp >> 8;
388 $cp2uni[$cp >> 8] = 0;
390 next;
392 die "$name: Unrecognized line $_\n";
397 ################################################################
398 # fill input data for the 20127 (us-ascii) codepage
399 sub fill_20127_codepage()
401 for (my $i = 0; $i < 128; $i++) { $cp2uni[$i] = $uni2cp[$i] = $i; }
402 for (my $i = 128; $i < 256; $i++) { $cp2uni[$i] = $i & 0x7f; }
405 ################################################################
406 # get a mapping including glyph chars for MB_USEGLYPHCHARS
408 sub get_glyphs_mapping(@)
410 $_[0x01] = 0x263a; # (WHITE SMILING FACE)
411 $_[0x02] = 0x263b; # (BLACK SMILING FACE)
412 $_[0x03] = 0x2665; # (BLACK HEART SUIT)
413 $_[0x04] = 0x2666; # (BLACK DIAMOND SUIT)
414 $_[0x05] = 0x2663; # (BLACK CLUB SUIT)
415 $_[0x06] = 0x2660; # (BLACK SPADE SUIT)
416 $_[0x07] = 0x2022; # (BULLET)
417 $_[0x08] = 0x25d8; # (INVERSE BULLET)
418 $_[0x09] = 0x25cb; # (WHITE CIRCLE)
419 $_[0x0a] = 0x25d9; # (INVERSE WHITE CIRCLE)
420 $_[0x0b] = 0x2642; # (MALE SIGN)
421 $_[0x0c] = 0x2640; # (FEMALE SIGN)
422 $_[0x0d] = 0x266a; # (EIGHTH NOTE)
423 $_[0x0e] = 0x266b; # (BEAMED EIGHTH NOTES)
424 $_[0x0f] = 0x263c; # (WHITE SUN WITH RAYS)
425 $_[0x10] = 0x25ba; # (BLACK RIGHT-POINTING POINTER)
426 $_[0x11] = 0x25c4; # (BLACK LEFT-POINTING POINTER)
427 $_[0x12] = 0x2195; # (UP DOWN ARROW)
428 $_[0x13] = 0x203c; # (DOUBLE EXCLAMATION MARK)
429 $_[0x14] = 0x00b6; # (PILCROW SIGN)
430 $_[0x15] = 0x00a7; # (SECTION SIGN)
431 $_[0x16] = 0x25ac; # (BLACK RECTANGLE)
432 $_[0x17] = 0x21a8; # (UP DOWN ARROW WITH BASE)
433 $_[0x18] = 0x2191; # (UPWARDS ARROW)
434 $_[0x19] = 0x2193; # (DOWNWARDS ARROW)
435 $_[0x1a] = 0x2192; # (RIGHTWARDS ARROW)
436 $_[0x1b] = 0x2190; # (LEFTWARDS ARROW)
437 $_[0x1c] = 0x221f; # (RIGHT ANGLE)
438 $_[0x1d] = 0x2194; # (LEFT RIGHT ARROW)
439 $_[0x1e] = 0x25b2; # (BLACK UP-POINTING TRIANGLE)
440 $_[0x1f] = 0x25bc; # (BLACK DOWN-POINTING TRIANGLE)
441 $_[0x7f] = 0x2302; # (HOUSE)
442 return @_;
445 ################################################################
446 # build EUC-JP table from the JIS 0208 file
447 # FIXME: for proper EUC-JP we should probably read JIS 0212 too
448 # but this would require 3-byte DBCS characters
449 sub READ_JIS0208_FILE($)
451 my $name = shift;
453 # ASCII chars
454 for (my $i = 0x00; $i <= 0x7f; $i++)
456 $cp2uni[$i] = $i;
457 $uni2cp[$i] = $i;
460 # JIS X 0201 right plane
461 for (my $i = 0xa1; $i <= 0xdf; $i++)
463 $cp2uni[0x8e00 + $i] = 0xfec0 + $i;
464 $uni2cp[0xfec0 + $i] = 0x8e00 + $i;
467 # lead bytes
468 foreach my $i (0x8e, 0x8f, 0xa1 .. 0xfe)
470 push @lead_bytes,$i;
471 $cp2uni[$i] = 0;
474 # undefined chars
475 foreach my $i (0x80 .. 0x8d, 0x90 .. 0xa0, 0xff)
477 $cp2uni[$i] = $DEF_CHAR;
480 # Shift-JIS compatibility
481 $uni2cp[0x00a5] = 0x5c;
482 $uni2cp[0x203e] = 0x7e;
484 # Fix backslash conversion
485 $cp2uni[0xa1c0] = 0xff3c;
486 $uni2cp[0xff3c] = 0xa1c0;
488 open INPUT, "$name" or die "Cannot open $name";
489 while (<INPUT>)
491 next if /^\#/; # skip comments
492 next if /^$/; # skip empty lines
493 next if /\x1a/; # skip ^Z
494 if (/^0x[0-9a-fA-F]+\s+0x([0-9a-fA-F]+)\s+0x([0-9a-fA-F]+)\s+(\#.*)?/)
496 my $cp = 0x8080 + hex $1;
497 my $uni = hex $2;
498 $cp2uni[$cp] = $uni unless defined($cp2uni[$cp]);
499 $uni2cp[$uni] = $cp unless defined($uni2cp[$uni]);
500 next;
502 die "$name: Unrecognized line $_\n";
507 ################################################################
508 # build the sort keys table
509 sub READ_SORTKEYS_FILE()
511 my @sortkeys = ();
512 for (my $i = 0; $i < 65536; $i++) { $sortkeys[$i] = [ -1, 0, 0, 0, 0 ] };
514 open INPUT, "$SORTKEYS" or die "Cannot open $SORTKEYS";
515 print "Loading $SORTKEYS\n";
516 while (<INPUT>)
518 next if /^\#/; # skip comments
519 next if /^$/; # skip empty lines
520 next if /\x1a/; # skip ^Z
521 next if /^\@version/; # skip @version header
522 if (/^([0-9a-fA-F]+)\s+;\s+\[([*.])([0-9a-fA-F]{4})\.([0-9a-fA-F]{4})\.([0-9a-fA-F]{4})\.([0-9a-fA-F]+)\]/)
524 my ($uni,$variable) = (hex $1, $2);
525 next if $uni > 65535;
526 $sortkeys[$uni] = [ $uni, hex $3, hex $4, hex $5, hex $6 ];
527 next;
529 if (/^([0-9a-fA-F]+\s+)+;\s+\[[*.]([0-9a-fA-F]{4})\.([0-9a-fA-F]{4})\.([0-9a-fA-F]{4})\.([0-9a-fA-F]+)\]/)
531 # multiple character sequence, ignored for now
532 next;
534 die "$SORTKEYS: Unrecognized line $_\n";
536 close INPUT;
538 # compress the keys to 32 bit:
539 # key 1 to 16 bits, key 2 to 8 bits, key 3 to 4 bits, key 4 to 1 bit
541 @sortkeys = sort { ${$a}[1] <=> ${$b}[1] or
542 ${$a}[2] <=> ${$b}[2] or
543 ${$a}[3] <=> ${$b}[3] or
544 ${$a}[4] <=> ${$b}[4] or
545 $a cmp $b; } @sortkeys;
547 my ($n2, $n3) = (1, 1);
548 my @keys = (-1, -1, -1, -1, -1 );
549 my @flatkeys = ();
551 for (my $i = 0; $i < 65536; $i++)
553 my @current = @{$sortkeys[$i]};
554 next if $current[0] == -1;
555 if ($current[1] == $keys[1])
557 if ($current[2] == $keys[2])
559 if ($current[3] == $keys[3])
561 # nothing
563 else
565 $keys[3] = $current[3];
566 $n3++;
567 die if ($n3 >= 16);
570 else
572 $keys[2] = $current[2];
573 $keys[3] = $current[3];
574 $n2++;
575 $n3 = 1;
576 die if ($n2 >= 256);
579 else
581 $keys[1] = $current[1];
582 $keys[2] = $current[2];
583 $keys[3] = $current[3];
584 $n2 = 1;
585 $n3 = 1;
588 if ($current[2]) { $current[2] = $n2; }
589 if ($current[3]) { $current[3] = $n3; }
590 if ($current[4]) { $current[4] = 1; }
592 $flatkeys[$current[0]] = ($current[1] << 16) | ($current[2] << 8) | ($current[3] << 4) | $current[4];
594 return @flatkeys;
598 ################################################################
599 # build the sort keys table
600 sub DUMP_SORTKEYS($@)
602 my ($filename, @keys) = @_;
604 # count the number of 256-key ranges that contain something
606 my @offsets = ();
607 my $ranges = 2;
608 for (my $i = 0; $i < 256; $i++) { $offsets[$i] = 256; }
609 for (my $i = 0; $i < 65536; $i++)
611 next unless defined $keys[$i];
612 $offsets[$i >> 8] = $ranges * 256;
613 $ranges++;
614 $i |= 255;
617 # output the range offsets
619 open OUTPUT,">$filename.new" or die "Cannot create $filename";
620 printf "Building $filename\n";
621 printf OUTPUT "/* Unicode collation element table */\n";
622 printf OUTPUT "/* generated from %s */\n", $SORTKEYS;
623 printf OUTPUT "/* DO NOT EDIT!! */\n\n";
625 printf OUTPUT "const unsigned int collation_table[%d] =\n{\n", $ranges*256;
626 printf OUTPUT " /* index */\n";
627 printf OUTPUT "%s,\n", DUMP_ARRAY( "0x%08x", 0, @offsets );
629 # output the default values
631 printf OUTPUT " /* defaults */\n";
632 printf OUTPUT "%s", DUMP_ARRAY( "0x%08x", 0, (0xffffffff) x 256 );
634 # output all the key ranges
636 for (my $i = 0; $i < 256; $i++)
638 next if $offsets[$i] == 256;
639 printf OUTPUT ",\n /* 0x%02x00 .. 0x%02xff */\n", $i, $i;
640 printf OUTPUT "%s", DUMP_ARRAY( "0x%08x", 0xffffffff, @keys[($i<<8) .. ($i<<8)+255] );
642 printf OUTPUT "\n};\n";
643 close OUTPUT;
644 save_file($filename);
648 ################################################################
649 # add default mappings once the file had been read
650 sub ADD_DEFAULT_MAPPINGS()
652 # Apply aliases
654 foreach my $alias (@unicode_aliases)
656 my $target = undef;
657 foreach my $src (@$alias)
659 if (defined($uni2cp[$src]))
661 $target = $uni2cp[$src];
662 last;
665 next unless defined($target);
667 # At least one char of the alias set is defined, set the others to the same value
668 foreach my $src (@$alias)
670 $uni2cp[$src] = $target unless defined($uni2cp[$src]);
674 # For every src -> target mapping in the defaults table,
675 # make uni2cp[src] = uni2cp[target] if uni2cp[target] is defined
677 for (my $src = 0; $src < 65536; $src++)
679 next if defined($uni2cp[$src]); # source has a definition already
680 next unless defined($unicode_defaults[$src]); # no default for this char
681 my $target = $unicode_defaults[$src];
683 # do a recursive mapping until we find a target char that is defined
684 while (!defined($uni2cp[$target]) &&
685 defined($unicode_defaults[$target])) { $target = $unicode_defaults[$target]; }
687 if (defined($uni2cp[$target])) { $uni2cp[$src] = $uni2cp[$target]; }
690 # Add an identity mapping for all undefined chars
692 for (my $i = 0; $i < 256; $i++)
694 next if defined($cp2uni[$i]);
695 next if defined($uni2cp[$i]);
696 $cp2uni[$i] = $uni2cp[$i] = $i;
700 ################################################################
701 # dump an array of integers
702 sub DUMP_ARRAY($$@)
704 my ($format,$default,@array) = @_;
705 my $i;
706 my $ret = " ";
707 for ($i = 0; $i < $#array; $i++)
709 $ret .= sprintf($format, defined $array[$i] ? $array[$i] : $default);
710 $ret .= (($i % 8) != 7) ? ", " : ",\n ";
712 $ret .= sprintf($format, defined $array[$i] ? $array[$i] : $default);
713 return $ret;
716 ################################################################
717 # dump an SBCS mapping table
718 sub dump_sbcs_table($$$$$)
720 my ($codepage, $has_glyphs, $name, $def, $defw) = @_;
721 my $i;
723 # output the ascii->unicode table
725 if ($has_glyphs)
727 printf OUTPUT "static const WCHAR cp2uni[512] =\n";
728 printf OUTPUT "{\n%s", DUMP_ARRAY( "0x%04x", $defw, @cp2uni[0 .. 255] );
729 printf OUTPUT ",\n /* glyphs */\n%s\n};\n\n",
730 DUMP_ARRAY( "0x%04x", $defw, get_glyphs_mapping(@cp2uni[0 .. 255]) );
732 else
734 printf OUTPUT "static const WCHAR cp2uni[256] =\n";
735 printf OUTPUT "{\n%s\n};\n\n", DUMP_ARRAY( "0x%04x", $defw, @cp2uni[0 .. 255] );
738 # count the number of unicode->ascii subtables that contain something
740 my @filled = ();
741 my $subtables = 1;
742 for (my $i = 0; $i < 65536; $i++)
744 next unless defined $uni2cp[$i];
745 $filled[$i >> 8] = 1;
746 $subtables++;
747 $i |= 255;
750 # output all the subtables into a single array
752 printf OUTPUT "static const unsigned char uni2cp_low[%d] =\n{\n", $subtables*256;
753 for (my $i = 0; $i < 256; $i++)
755 next unless $filled[$i];
756 printf OUTPUT " /* 0x%02x00 .. 0x%02xff */\n", $i, $i;
757 printf OUTPUT "%s,\n", DUMP_ARRAY( "0x%02x", $def, @uni2cp[($i<<8) .. ($i<<8)+255] );
759 printf OUTPUT " /* defaults */\n";
760 printf OUTPUT "%s\n};\n\n", DUMP_ARRAY( "0x%02x", 0, ($def) x 256 );
762 # output a table of the offsets of the subtables in the previous array
764 my $pos = 0;
765 my @offsets = ();
766 for (my $i = 0; $i < 256; $i++)
768 if ($filled[$i]) { push @offsets, $pos; $pos += 256; }
769 else { push @offsets, ($subtables-1) * 256; }
771 printf OUTPUT "static const unsigned short uni2cp_high[256] =\n";
772 printf OUTPUT "{\n%s\n};\n\n", DUMP_ARRAY( "0x%04x", 0, @offsets );
774 # output the code page descriptor
776 printf OUTPUT "const struct sbcs_table cptable_%03d =\n{\n", $codepage;
777 printf OUTPUT " { %d, 1, 0x%04x, 0x%04x, \"%s\" },\n",
778 $codepage, $def, $defw, $name;
779 printf OUTPUT " cp2uni,\n";
780 if ($has_glyphs) { printf OUTPUT " cp2uni + 256,\n"; }
781 else { printf OUTPUT " cp2uni,\n"; }
782 printf OUTPUT " uni2cp_low,\n";
783 printf OUTPUT " uni2cp_high\n};\n";
787 ################################################################
788 # dump a DBCS mapping table
789 sub dump_dbcs_table($$$$@)
791 my ($codepage, $name, $def, $defw, @lb_ranges) = @_;
793 # build a list of lead bytes that are actually used
795 my @lblist = ();
796 LBLOOP: for (my $y = 0; $y <= $#lead_bytes; $y++)
798 my $base = $lead_bytes[$y] << 8;
799 for (my $x = 0; $x < 256; $x++)
801 if (defined $cp2uni[$base+$x])
803 push @lblist,$lead_bytes[$y];
804 next LBLOOP;
808 my $unused = ($#lead_bytes > $#lblist);
810 # output the ascii->unicode table for the single byte chars
812 printf OUTPUT "static const WCHAR cp2uni[%d] =\n", 256 * ($#lblist + 2 + $unused);
813 printf OUTPUT "{\n%s,\n", DUMP_ARRAY( "0x%04x", $defw, @cp2uni[0 .. 255] );
815 # output the default table for unused lead bytes
817 if ($unused)
819 printf OUTPUT " /* unused lead bytes */\n";
820 printf OUTPUT "%s,\n", DUMP_ARRAY( "0x%04x", 0, ($defw) x 256 );
823 # output the ascii->unicode table for each DBCS lead byte
825 for (my $y = 0; $y <= $#lblist; $y++)
827 my $base = $lblist[$y] << 8;
828 printf OUTPUT " /* lead byte %02x */\n", $lblist[$y];
829 printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", $defw, @cp2uni[$base .. $base+255] );
830 printf OUTPUT ($y < $#lblist) ? ",\n" : "\n};\n\n";
833 # output the lead byte subtables offsets
835 my @offsets = ();
836 for (my $x = 0; $x < 256; $x++) { $offsets[$x] = 0; }
837 for (my $x = 0; $x <= $#lblist; $x++) { $offsets[$lblist[$x]] = $x + 1; }
838 if ($unused)
840 # increment all lead bytes offset to take into account the unused table
841 for (my $x = 0; $x <= $#lead_bytes; $x++) { $offsets[$lead_bytes[$x]]++; }
843 printf OUTPUT "static const unsigned char cp2uni_leadbytes[256] =\n";
844 printf OUTPUT "{\n%s\n};\n\n", DUMP_ARRAY( "0x%02x", 0, @offsets );
846 # count the number of unicode->ascii subtables that contain something
848 my @filled = ();
849 my $subtables = 1;
850 for (my $i = 0; $i < 65536; $i++)
852 next unless defined $uni2cp[$i];
853 $filled[$i >> 8] = 1;
854 $subtables++;
855 $i |= 255;
858 # output all the subtables into a single array
860 printf OUTPUT "static const unsigned short uni2cp_low[%d] =\n{\n", $subtables*256;
861 for (my $y = 0; $y < 256; $y++)
863 next unless $filled[$y];
864 printf OUTPUT " /* 0x%02x00 .. 0x%02xff */\n", $y, $y;
865 printf OUTPUT "%s,\n", DUMP_ARRAY( "0x%04x", $def, @uni2cp[($y<<8) .. ($y<<8)+255] );
867 printf OUTPUT " /* defaults */\n";
868 printf OUTPUT "%s\n};\n\n", DUMP_ARRAY( "0x%04x", 0, ($def) x 256 );
870 # output a table of the offsets of the subtables in the previous array
872 my $pos = 0;
873 @offsets = ();
874 for (my $y = 0; $y < 256; $y++)
876 if ($filled[$y]) { push @offsets, $pos; $pos += 256; }
877 else { push @offsets, ($subtables-1) * 256; }
879 printf OUTPUT "static const unsigned short uni2cp_high[256] =\n";
880 printf OUTPUT "{\n%s\n};\n\n", DUMP_ARRAY( "0x%04x", 0, @offsets );
882 # output the code page descriptor
884 printf OUTPUT "const struct dbcs_table cptable_%03d =\n{\n", $codepage;
885 printf OUTPUT " { %d, 2, 0x%04x, 0x%04x, \"%s\" },\n",
886 $codepage, $def, $defw, $name;
887 printf OUTPUT " cp2uni,\n";
888 printf OUTPUT " cp2uni_leadbytes,\n";
889 printf OUTPUT " uni2cp_low,\n";
890 printf OUTPUT " uni2cp_high,\n";
891 printf OUTPUT " {\n %s\n }\n", DUMP_ARRAY( "0x%02x", 0, @lb_ranges, 0, 0 );
892 printf OUTPUT "};\n";
896 ################################################################
897 # get the list of defined lead byte ranges
898 sub get_lb_ranges()
900 my @list = ();
901 my @ranges = ();
902 my $i = 0;
903 foreach $i (@lead_bytes) { $list[$i] = 1; }
904 my $on = 0;
905 for (my $i = 0; $i < 256; $i++)
907 if ($on)
909 if (!defined $list[$i]) { push @ranges, $i-1; $on = 0; }
911 else
913 if ($list[$i]) { push @ranges, $i; $on = 1; }
916 if ($on) { push @ranges, 0xff; }
917 return @ranges;
921 ################################################################
922 # dump the case mapping tables
923 sub DUMP_CASE_MAPPINGS($)
925 my $filename = shift;
926 open OUTPUT,">$filename.new" or die "Cannot create $filename";
927 printf "Building $filename\n";
928 printf OUTPUT "/* Unicode case mappings */\n";
929 printf OUTPUT "/* Automatically generated; DO NOT EDIT!! */\n\n";
930 printf OUTPUT "#include \"wine/unicode.h\"\n\n";
932 DUMP_CASE_TABLE( "wine_casemap_lower", @tolower_table );
933 DUMP_CASE_TABLE( "wine_casemap_upper", @toupper_table );
934 DUMP_CASE_TABLE( "wine_digitmap", @digitmap_table );
935 DUMP_CASE_TABLE( "wine_compatmap", @compatmap_table );
936 close OUTPUT;
937 save_file($filename);
941 ################################################################
942 # dump a case mapping table
943 sub DUMP_CASE_TABLE($@)
945 my ($name,@table) = @_;
947 # count the number of sub tables that contain something
948 # also compute the low and upper populated bounds
950 my @lowerbounds = ( 0, 0 );
951 my @upperbounds = ( 0, 255 );
952 my $index = 0;
953 my @filled = ();
954 for (my $i = 0; $i < 65536; $i++)
956 next unless defined $table[$i];
957 if (!defined $filled[$i >> 8])
959 $lowerbounds[$index] = $i & 0xff;
960 $upperbounds[$index] = 0xff - $lowerbounds[$index];
961 $filled[$i >> 8] = $index * 256 + 512;
962 $index++;
964 else
966 $upperbounds[$index-1] = 0xff - ($i & 0xff);
968 $table[$i] = ($table[$i] - $i) & 0xffff;
971 # Collapse blocks upwards if possible
972 my $removed = 0;
973 $index = 0;
974 for (my $i = 0; $i < 256; $i++)
976 next unless defined $filled[$i];
977 if ($upperbounds[$index - 1] > $lowerbounds[$index])
979 $removed = $removed + $lowerbounds[$index];
981 else
983 $removed = $removed + $upperbounds[$index - 1];
984 $lowerbounds[$index] = $upperbounds[$index - 1];
986 $filled[$i] = $filled[$i] - $removed;
987 $index++;
990 # dump the table
992 printf OUTPUT "const WCHAR %s[%d] =\n", $name, $index * 256 + 512 - $removed;
993 printf OUTPUT "{\n /* index */\n";
994 printf OUTPUT "%s,\n", DUMP_ARRAY( "0x%04x", 256, @filled );
995 printf OUTPUT " /* defaults */\n";
996 printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, (0) x 256 );
997 $index = 0;
998 for (my $i = 0; $i < 256; $i++)
1000 next unless $filled[$i];
1001 printf OUTPUT ",\n /* 0x%02x%02x .. 0x%02xff */\n", $i, $lowerbounds[$index], $i;
1002 printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0,
1003 @table[($i<<8) + $lowerbounds[$index] .. ($i<<8)+255] );
1004 $index++;
1006 printf OUTPUT "\n};\n";
1010 ################################################################
1011 # dump the ctype tables
1012 sub DUMP_CTYPE_TABLES($)
1014 my $filename = shift;
1015 open OUTPUT,">$filename.new" or die "Cannot create $filename";
1016 printf "Building $filename\n";
1017 printf OUTPUT "/* Unicode ctype tables */\n";
1018 printf OUTPUT "/* Automatically generated; DO NOT EDIT!! */\n\n";
1019 printf OUTPUT "#include \"wine/unicode.h\"\n\n";
1021 my @array = (0) x 256;
1022 my %sequences;
1024 # add the direction in the high 4 bits of the category
1025 for (my $i = 0; $i < 65536; $i++)
1027 $category_table[$i] |= $direction_table[$i] << 12 if defined $direction_table[$i];
1030 # try to merge table rows
1031 for (my $row = 0; $row < 256; $row++)
1033 my $rowtxt = sprintf "%04x" x 256, @category_table[($row<<8)..($row<<8)+255];
1034 if (defined($sequences{$rowtxt}))
1036 # reuse an existing row
1037 $array[$row] = $sequences{$rowtxt};
1039 else
1041 # create a new row
1042 $sequences{$rowtxt} = $array[$row] = $#array + 1;
1043 push @array, @category_table[($row<<8)..($row<<8)+255];
1047 printf OUTPUT "const unsigned short wine_wctype_table[%d] =\n{\n", $#array+1;
1048 printf OUTPUT " /* offsets */\n%s,\n", DUMP_ARRAY( "0x%04x", 0, @array[0..255] );
1049 printf OUTPUT " /* values */\n%s\n};\n", DUMP_ARRAY( "0x%04x", 0, @array[256..$#array] );
1051 close OUTPUT;
1052 save_file($filename);
1056 ################################################################
1057 # dump the char composition tables
1058 sub DUMP_COMPOSE_TABLES($)
1060 my $filename = shift;
1062 open OUTPUT,">$filename.new" or die "Cannot create $filename";
1063 printf "Building $filename\n";
1064 printf OUTPUT "/* Unicode char composition */\n";
1065 printf OUTPUT "/* Automatically generated; DO NOT EDIT!! */\n\n";
1066 printf OUTPUT "#include \"wine/unicode.h\"\n\n";
1068 ######### composition table
1070 my @filled = ();
1071 foreach my $i (@compose_table)
1073 my @comp = @$i;
1074 push @{$filled[$comp[1]]}, [ $comp[0], $comp[2] ];
1077 # count how many different second chars we have
1079 my $count = 0;
1080 for (my $i = 0; $i < 65536; $i++)
1082 next unless defined $filled[$i];
1083 $count++;
1086 # build the table of second chars and offsets
1088 my $pos = $count + 1;
1089 my @table = ();
1090 for (my $i = 0; $i < 65536; $i++)
1092 next unless defined $filled[$i];
1093 push @table, $i, $pos;
1094 $pos += @{$filled[$i]};
1096 # terminator with last position
1097 push @table, 0, $pos;
1098 printf OUTPUT "const WCHAR unicode_compose_table[0x%x] =\n{\n", 2*$pos;
1099 printf OUTPUT " /* second chars + offsets */\n%s", DUMP_ARRAY( "0x%04x", 0, @table );
1101 # build the table of first chars and mappings
1103 for (my $i = 0; $i < 65536; $i++)
1105 next unless defined $filled[$i];
1106 my @table = ();
1107 my @list = sort { $a->[0] <=> $b->[0] } @{$filled[$i]};
1108 for (my $j = 0; $j <= $#list; $j++)
1110 push @table, $list[$j][0], $list[$j][1];
1112 printf OUTPUT ",\n /* 0x%04x */\n%s", $i, DUMP_ARRAY( "0x%04x", 0, @table );
1114 printf OUTPUT "\n};\n\nconst unsigned int unicode_compose_table_size = %d;\n\n", $count;
1116 ######### decomposition table
1118 # first determine all the 16-char subsets that contain something
1120 @filled = (0) x 4096;
1121 $pos = 16*2; # for the null subset
1122 for (my $i = 0; $i < 65536; $i++)
1124 next unless defined $decomp_table[$i];
1125 $filled[$i >> 4] = $pos;
1126 $pos += 16*2;
1127 $i |= 15;
1129 my $total = $pos;
1131 # now count the 256-char subsets that contain something
1133 my @filled_idx = (256) x 256;
1134 $pos = 256 + 16;
1135 for (my $i = 0; $i < 4096; $i++)
1137 next unless $filled[$i];
1138 $filled_idx[$i >> 4] = $pos;
1139 $pos += 16;
1140 $i |= 15;
1142 my $null_offset = $pos; # null mapping
1143 $total += $pos;
1145 # add the index offsets to the subsets positions
1147 for (my $i = 0; $i < 4096; $i++)
1149 next unless $filled[$i];
1150 $filled[$i] += $null_offset;
1153 # dump the main index
1155 printf OUTPUT "const WCHAR unicode_decompose_table[%d] =\n", $total;
1156 printf OUTPUT "{\n /* index */\n";
1157 printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @filled_idx );
1158 printf OUTPUT ",\n /* null sub-index */\n%s", DUMP_ARRAY( "0x%04x", 0, ($null_offset) x 16 );
1160 # dump the second-level indexes
1162 for (my $i = 0; $i < 256; $i++)
1164 next unless ($filled_idx[$i] > 256);
1165 my @table = @filled[($i<<4)..($i<<4)+15];
1166 for (my $j = 0; $j < 16; $j++) { $table[$j] ||= $null_offset; }
1167 printf OUTPUT ",\n /* sub-index %02x */\n", $i;
1168 printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @table );
1171 # dump the 16-char subsets
1173 printf OUTPUT ",\n /* null mapping */\n";
1174 printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, (0) x 32 );
1176 for (my $i = 0; $i < 4096; $i++)
1178 next unless $filled[$i];
1179 my @table = (0) x 32;
1180 for (my $j = 0; $j < 16; $j++)
1182 if (defined $decomp_table[($i<<4) + $j])
1184 $table[2 * $j] = ${$decomp_table[($i << 4) + $j]}[0];
1185 $table[2 * $j + 1] = ${$decomp_table[($i << 4) + $j]}[1];
1188 printf OUTPUT ",\n /* 0x%03x0 .. 0x%03xf */\n", $i, $i;
1189 printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @table );
1192 printf OUTPUT "\n};\n";
1193 close OUTPUT;
1194 save_file($filename);
1198 ################################################################
1199 # handle a "bestfit" Windows mapping file
1201 sub handle_bestfit_file($$$)
1203 my ($filename, $has_glyphs, $comment) = @_;
1204 my $state = "";
1205 my ($codepage, $width, $def, $defw, $count);
1206 my ($lb_cur, $lb_end);
1207 my @lb_ranges = ();
1209 open INPUT,$MAPPREFIX . $filename or die "Cannot open $filename";
1211 while (<INPUT>)
1213 next if /^;/; # skip comments
1214 next if /^\s*$/; # skip empty lines
1215 next if /\x1a/; # skip ^Z
1216 last if /^ENDCODEPAGE/;
1218 if (/^CODEPAGE\s+(\d+)/)
1220 $codepage = $1;
1221 next;
1223 if (/^CPINFO\s+(\d+)\s+0x([0-9a-fA-f]+)\s+0x([0-9a-fA-F]+)/)
1225 $width = $1;
1226 $def = hex $2;
1227 $defw = hex $3;
1228 next;
1230 if (/^(MBTABLE|WCTABLE|DBCSRANGE|DBCSTABLE)\s+(\d+)/)
1232 $state = $1;
1233 $count = $2;
1234 next;
1236 if (/^0x([0-9a-fA-F]+)\s+0x([0-9a-fA-F]+)/)
1238 if ($state eq "MBTABLE")
1240 my $cp = hex $1;
1241 my $uni = hex $2;
1242 $cp2uni[$cp] = $uni unless defined($cp2uni[$cp]);
1243 next;
1245 if ($state eq "WCTABLE")
1247 my $uni = hex $1;
1248 my $cp = hex $2;
1249 $uni2cp[$uni] = $cp unless defined($uni2cp[$uni]);
1250 next;
1252 if ($state eq "DBCSRANGE")
1254 my $start = hex $1;
1255 my $end = hex $2;
1256 push @lb_ranges, $start, $end;
1257 for (my $i = $start; $i <= $end; $i++)
1259 push @lead_bytes, $i;
1260 $cp2uni[$i] = 0;
1262 $lb_cur = $start;
1263 $lb_end = $end;
1264 next;
1266 if ($state eq "DBCSTABLE")
1268 my $mb = hex $1;
1269 my $uni = hex $2;
1270 my $cp = ($lb_cur << 8) | $mb;
1271 $cp2uni[$cp] = $uni unless defined($cp2uni[$cp]);
1272 if (!--$count)
1274 if (++$lb_cur > $lb_end) { $state = "DBCSRANGE"; }
1276 next;
1279 die "$filename: Unrecognized line $_\n";
1281 close INPUT;
1283 my $output = sprintf "c_%03d.c", $codepage;
1284 open OUTPUT,">$output.new" or die "Cannot create $output";
1286 printf "Building %s from %s (%s)\n", $output, $filename, $comment;
1288 # dump all tables
1290 printf OUTPUT "/* code page %03d (%s) */\n", $codepage, $comment;
1291 printf OUTPUT "/* generated from %s */\n", $MAPPREFIX . $filename;
1292 printf OUTPUT "/* DO NOT EDIT!! */\n\n";
1293 printf OUTPUT "#include \"wine/unicode.h\"\n\n";
1295 if ($width == 1) { dump_sbcs_table( $codepage, $has_glyphs, $comment, $def, $defw ); }
1296 else { dump_dbcs_table( $codepage, $comment, $def, $defw, @lb_ranges ); }
1297 close OUTPUT;
1298 save_file($output);
1302 ################################################################
1303 # read an input file and generate the corresponding .c file
1304 sub HANDLE_FILE(@)
1306 my ($codepage,$filename,$has_glyphs,$comment) = @_;
1308 @cp2uni = ();
1309 @lead_bytes = ();
1310 @uni2cp = ();
1312 # symbol codepage file is special
1313 if ($codepage == 20932) { READ_JIS0208_FILE($MAPPREFIX . $filename); }
1314 elsif ($codepage == 20127) { fill_20127_codepage(); }
1315 elsif ($filename =~ /\/bestfit/)
1317 handle_bestfit_file( $filename, $has_glyphs, $comment );
1318 return;
1320 else { READ_FILE($MAPPREFIX . $filename); }
1322 ADD_DEFAULT_MAPPINGS();
1324 my $output = sprintf "c_%03d.c", $codepage;
1325 open OUTPUT,">$output.new" or die "Cannot create $output";
1327 printf "Building %s from %s (%s)\n", $output, $filename || "hardcoded data", $comment;
1329 # dump all tables
1331 printf OUTPUT "/* code page %03d (%s) */\n", $codepage, $comment;
1332 if ($filename)
1334 printf OUTPUT "/* generated from %s */\n", $MAPPREFIX . $filename;
1335 printf OUTPUT "/* DO NOT EDIT!! */\n\n";
1337 else
1339 printf OUTPUT "/* Automatically generated; DO NOT EDIT!! */\n\n";
1341 printf OUTPUT "#include \"wine/unicode.h\"\n\n";
1343 if (!@lead_bytes) { dump_sbcs_table( $codepage, $has_glyphs, $comment, $DEF_CHAR, $DEF_CHAR ); }
1344 else { dump_dbcs_table( $codepage, $comment, $DEF_CHAR, $DEF_CHAR, get_lb_ranges() ); }
1345 close OUTPUT;
1346 save_file($output);
1350 ################################################################
1351 # save a file if modified
1352 sub save_file($)
1354 my $file = shift;
1355 if (-f $file && !system "cmp $file $file.new >/dev/null")
1357 unlink "$file.new";
1359 else
1361 rename "$file.new", "$file";
1366 ################################################################
1367 # output the list of codepage tables into the cptable.c file
1368 sub OUTPUT_CPTABLE()
1370 my @tables_decl = ();
1372 foreach my $file (@allfiles)
1374 my ($codepage,$filename,$comment) = @$file;
1375 push @tables_decl, sprintf("extern union cptable cptable_%03d;\n",$codepage);
1378 push @tables_decl, sprintf("\nstatic const union cptable * const cptables[%d] =\n{\n",$#allfiles+1);
1379 foreach my $file (@allfiles)
1381 my ($codepage,$filename,$comment) = @$file;
1382 push @tables_decl, sprintf(" &cptable_%03d,\n", $codepage);
1384 push @tables_decl, "};";
1385 REPLACE_IN_FILE( "cptable.c", @tables_decl );
1388 ################################################################
1389 # replace the contents of a file between ### cpmap ### marks
1391 sub REPLACE_IN_FILE($@)
1393 my $name = shift;
1394 my @data = @_;
1395 my @lines = ();
1396 open(FILE,$name) or die "Can't open $name";
1397 while (<FILE>)
1399 push @lines, $_;
1400 last if /\#\#\# cpmap begin \#\#\#/;
1402 push @lines, @data;
1403 while (<FILE>)
1405 if (/\#\#\# cpmap end \#\#\#/) { push @lines, "\n", $_; last; }
1407 push @lines, <FILE>;
1408 open(FILE,">$name.new") or die "Can't modify $name";
1409 print FILE @lines;
1410 close(FILE);
1411 save_file($name);
1414 ################################################################
1415 # main routine
1417 READ_DEFAULTS( $DEFAULTS );
1418 DUMP_CASE_MAPPINGS( "casemap.c" );
1419 DUMP_SORTKEYS( "collation.c", READ_SORTKEYS_FILE() );
1420 DUMP_COMPOSE_TABLES( "compose.c" );
1421 DUMP_CTYPE_TABLES( "wctype.c" );
1423 foreach my $file (@allfiles) { HANDLE_FILE( @{$file} ); }
1425 OUTPUT_CPTABLE();
1427 exit 0;
1429 # Local Variables:
1430 # compile-command: "./cpmap.pl && make -k"
1431 # End: