3 unshift @INC, qw(../../lib ../../../lib);
4 $ENV{PATH} .= ';../..;../../..' if $^O eq 'MSWin32';
11 # These may get re-ordered.
12 # RAW is a do_now as inserted by &enter
13 # AGG is an aggreagated do_now, as built up by &process
28 # (See the algorithm in encengine.c - we're building structures for it)
30 # There are two sorts of structures.
31 # "do_now" (an array, two variants of what needs storing) is whatever we need
32 # to do now we've read an input byte.
33 # It's housed in a "do_next" (which is how we got to it), and in turn points
34 # to a "do_next" which contains all the "do_now"s for the next input byte.
36 # There will be a "do_next" which is the start state.
37 # For a single byte encoding it's the only "do_next" - each "do_now" points
38 # back to it, and each "do_now" will cause bytes. There is no state.
40 # For a multi-byte encoding where all characters in the input are the same
41 # length, then there will be a tree of "do_now"->"do_next"->"do_now"
42 # branching out from the start state, one step for each input byte.
43 # The leaf "do_now"s will all be at the same distance from the start state,
44 # only the leaf "do_now"s cause output bytes, and they in turn point back to
47 # For an encoding where there are varaible length input byte sequences, you
48 # will encounter a leaf "do_now" sooner for the shorter input sequences, but
49 # as before the leaves will point back to the start state.
51 # The system will cope with escape encodings (imagine them as a mostly
52 # self-contained tree for each escape state, and cross links between trees
53 # at the state-switching characters) but so far no input format defines these.
55 # The system will also cope with having output "leaves" in the middle of
56 # the bifurcating branches, not just at the extremities, but again no
57 # input format does this yet.
59 # There are two variants of the "do_now" structure. The first, smaller variant
60 # is generated by &enter as the input file is read. There is one structure
61 # for each input byte. Say we are mapping a single byte encoding to a
62 # single byte encoding, with "ABCD" going "abcd". There will be
63 # 4 "do_now"s, {"A" => [...,"a",...], "B" => [...,"b",...], "C"=>..., "D"=>...}
65 # &process then walks the tree, building aggregate "do_now" structres for
66 # adjacent bytes where possible. The aggregate is for a contiguous range of
67 # bytes which each produce the same length of output, each move to the
68 # same next state, and each have the same fallback flag.
69 # So our 4 RAW "do_now"s above become replaced by a single structure
71 # ["A", "D", "abcd", 1, ...]
72 # ie, for an input byte $_ in "A".."D", output 1 byte, found as
73 # substr ("abcd", (ord $_ - ord "A") * 1, 1)
74 # which maps very nicely into pointer arithmetic in C for encengine.c
78 # UTF-8 encode long hand - only covers part of perl's range
80 # chr() works in native space so convert value from table
81 # into that space before using chr().
82 my $ch = chr(utf8::unicode_to_native($_[0]));
83 # Now get core perl to encode that the way it likes.
91 ## my ($ch,$page) = @_; return chr($ch);
97 # encode double byte MS byte first
98 ## my ($ch,$page) = @_; return chr($page).chr($ch);
99 return chr ($_[1]) . chr $_[0];
104 # encode Multi-byte - single for 0..255 otherwise double
105 ## my ($ch,$page) = @_;
106 ## return &encode_D if $page;
108 return chr ($_[1]) . chr $_[0] if $_[1];
112 my %encode_types = (U => \&encode_U,
118 # Win32 does not expand globs on command line
119 eval "\@ARGV = map(glob(\$_),\@ARGV)" if ($^O eq 'MSWin32');
123 # -Q to disable the duplicate codepoint test
124 # -S make mapping errors fatal
125 # -q to remove comments written to output files
126 # -O to enable the (brute force) substring optimiser
127 # -o <output> to specify the output file name (else it's the first arg)
128 # -f <inlist> to give a file with a list of input files (else use the args)
129 # -n <name> to name the encoding (else use the basename of the input file.
130 getopts('SQqOo:f:n:',\%opt);
132 # This really should go first, else the die here causes empty (non-erroneous)
133 # output files to be written.
135 if (exists $opt{'f'}) {
136 # -F is followed by name of file containing list of filenames
137 my $flist = $opt{'f'};
138 open(FLIST,$flist) || die "Cannot open $flist:$!";
139 chomp(@encfiles = <FLIST>);
145 my $cname = (exists $opt{'o'}) ? $opt{'o'} : shift(@ARGV);
146 chmod(0666,$cname) if -f $cname && !-w $cname;
147 open(C,">$cname") || die "Cannot open $cname:$!";
152 my ($doC,$doEnc,$doUcm,$doPet);
154 if ($cname =~ /\.(c|xs)$/)
157 $dname =~ s/(\.[^\.]*)?$/_def.h/;
158 chmod(0666,$dname) if -f $cname && !-w $dname;
159 open(D,">$dname") || die "Cannot open $dname:$!";
160 $hname =~ s/(\.[^\.]*)?$/.h/;
161 chmod(0666,$hname) if -f $cname && !-w $hname;
162 open(H,">$hname") || die "Cannot open $hname:$!";
164 foreach my $fh (\*C,\*D,\*H)
166 print $fh <<"END" unless $opt{'q'};
168 !!!!!!! DO NOT EDIT THIS FILE !!!!!!!
169 This file was autogenerated by:
175 if ($cname =~ /(\w+)\.xs$/)
177 print C "#include <EXTERN.h>\n";
178 print C "#include <perl.h>\n";
179 print C "#include <XSUB.h>\n";
180 print C "#define U8 U8\n";
182 print C "#include \"encode.h\"\n";
185 elsif ($cname =~ /\.enc$/)
189 elsif ($cname =~ /\.ucm$/)
193 elsif ($cname =~ /\.pet$/)
206 if ($a =~ /^.*-(\d+)/)
209 if ($b =~ /^.*-(\d+)/)
219 foreach my $enc (sort cmp_name @encfiles)
221 my ($name,$sfx) = $enc =~ /^.*?([\w-]+)\.(enc|ucm)$/;
222 $name = $opt{'n'} if exists $opt{'n'};
227 compile_enc(\*E,lc($name));
231 compile_ucm(\*E,lc($name));
236 warn "Cannot open $enc for $name:$!";
242 print STDERR "Writing compiled form\n";
243 foreach my $name (sort cmp_name keys %encoding)
245 my ($e2u,$u2e,$erep,$min_el,$max_el) = @{$encoding{$name}};
246 output(\*C,$name.'_utf8',$e2u);
247 output(\*C,'utf8_'.$name,$u2e);
248 push(@{$encoding{$name}},outstring(\*C,$e2u->{Cname}.'_def',$erep));
250 foreach my $enc (sort cmp_name keys %encoding)
252 my ($e2u,$u2e,$rep,$min_el,$max_el,$rsym) = @{$encoding{$enc}};
253 my @info = ($e2u->{Cname},$u2e->{Cname},$rsym,length($rep),$min_el,$max_el);
254 my $sym = "${enc}_encoding";
256 print C "encode_t $sym = \n";
257 print C " {",join(',',@info,"{\"$enc\",(const char *)0}"),"};\n\n";
260 foreach my $enc (sort cmp_name keys %encoding)
262 my $sym = "${enc}_encoding";
264 print H "extern encode_t $sym;\n";
265 print D " Encode_XSEncoding(aTHX_ &$sym);\n";
268 if ($cname =~ /(\w+)\.xs$/)
274 Encode_XSEncoding(pTHX_ encode_t *enc)
277 HV *stash = gv_stashpv("Encode::XS", TRUE);
278 SV *sv = sv_bless(newRV_noinc(newSViv(PTR2IV(enc))),stash);
284 const char *name = enc->name[i++];
285 XPUSHs(sv_2mortal(newSVpvn(name,strlen(name))));
288 call_pv("Encode::define_encoding",G_DISCARD);
294 print C "\nMODULE = Encode::$mod\tPACKAGE = Encode::$mod\n\n";
295 print C "BOOT:\n{\n";
296 print C "#include \"$dname\"\n";
299 # Close in void context is bad, m'kay
300 close(D) or warn "Error closing '$dname': $!";
301 close(H) or warn "Error closing '$hname': $!";
303 my $perc_saved = $strings/($strings + $saved) * 100;
304 my $perc_subsaved = $strings/($strings + $subsave) * 100;
305 printf STDERR "%d bytes in string tables\n",$strings;
306 printf STDERR "%d bytes (%.3g%%) saved spotting duplicates\n",
307 $saved, $perc_saved if $saved;
308 printf STDERR "%d bytes (%.3g%%) saved using substrings\n",
309 $subsave, $perc_subsaved if $subsave;
313 foreach my $name (sort cmp_name keys %encoding)
315 my ($e2u,$u2e,$erep,$min_el,$max_el) = @{$encoding{$name}};
316 output_enc(\*C,$name,$e2u);
321 foreach my $name (sort cmp_name keys %encoding)
323 my ($e2u,$u2e,$erep,$min_el,$max_el) = @{$encoding{$name}};
324 output_ucm(\*C,$name,$u2e,$erep,$min_el,$max_el);
328 # writing half meg files and then not checking to see if you just filled the
330 close(C) or die "Error closing '$cname': $!";
332 # End of the main program.
344 last if /^\s*CHARMAP\s*$/i;
345 if (/^\s*<(\w+)>\s+"?([^"]*)"?\s*$/i) # " # Grrr
350 if (!defined($cs = $attr{'code_set_name'}))
352 warn "No <code_set_name> in $name\n";
356 $name = $cs unless exists $opt{'n'};
362 if (exists $attr{'subchar'})
365 $attr{'subchar'} =~ /^\s*/cg;
366 push(@byte,$1) while $attr{'subchar'} =~ /\G\\x([0-9a-f]+)/icg;
367 $erep = join('',map(chr(hex($_)),@byte));
369 print "Reading $name ($cs)\n";
375 last if /^\s*END\s+CHARMAP\s*$/i;
379 $u = $1 if (/^<U([0-9a-f]+)>\s+/igc);
380 push(@byte,$1) while /\G\\x([0-9a-f]+)/igc;
381 $fb = $1 if /\G\s*(\|[0-3])/gc;
382 # warn "$_: $u @byte | $fb\n";
383 die "Bad line:$_" unless /\G\s*(#.*)?$/gc;
386 my $uch = encode_U(hex($u));
387 my $ech = join('',map(chr(hex($_)),@byte));
388 my $el = length($ech);
389 $max_el = $el if (!defined($max_el) || $el > $max_el);
390 $min_el = $el if (!defined($min_el) || $el < $min_el);
401 # $fb is fallback flag
402 # 0 - round trip safe
403 # 1 - fallback for unicode -> enc
404 # 2 - skip sub-char mapping
405 # 3 - fallback enc -> unicode
406 enter($u2e,$uch,$ech,$u2e,$fb+0) if ($fb =~ /[01]/);
407 enter($e2u,$ech,$uch,$e2u,$fb+0) if ($fb =~ /[03]/);
416 die "$nfb entries without fallback, $hfb entries with\n";
418 $encoding{$name} = [$e2u,$u2e,$erep,$min_el,$max_el];
430 while ($type = <$fh>)
432 last if $type !~ /^\s*#/;
435 return if $type eq 'E';
436 # Do the hash lookup once, rather than once per function call. 4% speedup.
437 my $type_func = $encode_types{$type};
438 my ($def,$sym,$pages) = split(/\s+/,scalar(<$fh>));
439 warn "$type encoded $name\n";
441 # Save a defined test by setting these to defined values.
442 my $min_el = ~0; # A very big integer
443 my $max_el = 0; # Anything must be longer than 0
446 $rep = &$type_func($v & 0xFF, ($v >> 8) & 0xffe);
450 # use -Q to silence the seen test. Makefile.PL uses this by default.
451 $seen = {} unless $opt{Q};
456 my $page = hex($line);
461 # So why is it 1% faster to leave the my here?
463 $line =~ s/\r\n$/\n/;
464 die "$.:${line}Line should be exactly 65 characters long including
465 newline (".length($line).")" unless length ($line) == 65;
466 # Split line into groups of 4 hex digits, convert groups to ints
468 # map {hex $_} $line =~ /(....)/g
469 # This takes 63.75 (2.5% less time)
470 # unpack "n*", pack "H*", $line
471 # There's an implicit loop in map. Loops are bad, m'kay. Ops are bad, m'kay
472 # Doing it as while ($line =~ /(....)/g) took 74.63
473 foreach my $val (unpack "n*", pack "H*", $line)
475 next if $val == 0xFFFD;
476 my $ech = &$type_func($ch,$page);
477 if ($val || (!$ch && !$page))
479 my $el = length($ech);
480 $max_el = $el if $el > $max_el;
481 $min_el = $el if $el < $min_el;
482 my $uch = encode_U($val);
484 # We're doing the test.
485 # We don't need to read this quickly, so storing it as a scalar,
486 # rather than 3 (anon array, plus the 2 scalars it holds) saves
487 # RAM and may make us faster on low RAM systems. [see __END__]
488 if (exists $seen->{$uch})
490 warn sprintf("U%04X is %02X%02X and %04X\n",
491 $val,$page,$ch,$seen->{$uch});
496 $seen->{$uch} = $page << 8 | $ch;
499 # Passing 2 extra args each time is 3.6% slower!
500 # Even with having to add $fallback ||= 0 later
501 enter_fb0($e2u,$ech,$uch);
502 enter_fb0($u2e,$uch,$ech);
506 # No character at this position
507 # enter($e2u,$ech,undef,$e2u);
513 die "\$min_el=$min_el, \$max_el=$max_el - seems we read no lines"
514 if $min_el > $max_el;
515 die "$errors mapping conflicts\n" if ($errors && $opt{'S'});
516 $encoding{$name} = [$e2u,$u2e,$rep,$min_el,$max_el];
519 # my ($a,$s,$d,$t,$fb) = @_;
521 my ($current,$inbytes,$outbytes,$next,$fallback) = @_;
522 # state we shift to after this (multibyte) input character defaults to same
525 # Making sure it is defined seems to be faster than {no warnings;} in
526 # &process, or passing it in as 0 explicity.
527 # XXX $fallback ||= 0;
529 # Start at the beginning and work forwards through the string to zero.
530 # effectively we are removing 1 character from the front each time
531 # but we don't actually edit the string. [this alone seems to be 14% speedup]
532 # Hence -$pos is the length of the remaining string.
533 my $pos = -length $inbytes;
535 my $byte = substr $inbytes, $pos, 1;
538 # RAW_OUT_BYTES => 2,
540 # to unicode an array would seem to be better, because the pages are dense.
541 # from unicode can be very sparse, favouring a hash.
542 # hash using the bytes (all length 1) as keys rather than ord value,
543 # as it's easier to sort these in &process.
545 # It's faster to always add $fallback even if it's undef, rather than
546 # choosing between 3 and 4 element array. (hence why we set it defined
548 my $do_now = $current->{Raw}{$byte} ||= [{},-$pos,'',$fallback];
549 # When $pos was -1 we were at the last input character.
551 $do_now->[RAW_OUT_BYTES] = $outbytes;
552 $do_now->[RAW_NEXT] = $next;
555 # Tail recursion. The intermdiate state may not have a name yet.
556 $current = $do_now->[RAW_NEXT];
560 # This is purely for optimistation. It's just &enter hard coded for $fallback
561 # of 0, using only a 3 entry array ref to save memory for every entry.
563 my ($current,$inbytes,$outbytes,$next) = @_;
566 my $pos = -length $inbytes;
568 my $byte = substr $inbytes, $pos, 1;
569 my $do_now = $current->{Raw}{$byte} ||= [{},-$pos,''];
571 $do_now->[RAW_OUT_BYTES] = $outbytes;
572 $do_now->[RAW_NEXT] = $next;
575 $current = $do_now->[RAW_NEXT];
582 my ($fh,$name,$s) = @_;
583 my $sym = $strings{$s};
586 $saved += length($s);
591 foreach my $o (keys %strings)
593 next unless (my $i = index($o,$s)) >= 0;
595 # gcc things that 0x0e+0x10 (anything with e+) starts to look like
596 # a hexadecimal floating point constant. Silly gcc. Only p
597 # introduces a floating point constant. Put the space in to stop it
599 $sym .= sprintf(" +0x%02x",$i) if ($i);
600 $subsave += length($s);
601 return $strings{$s} = $sym;
604 $strings{$s} = $sym = $name;
605 $strings += length($s);
606 my $definition = sprintf "static const U8 %s[%d] = { ",$name,length($s);
607 # Maybe we should assert that these are all <256.
608 $definition .= join(',',unpack "C*",$s);
609 # We have a single long line. Split it at convenient commas.
610 $definition =~ s/(.{74,77},)/$1\n/g;
611 print $fh "$definition };\n\n";
622 my ($l, $agg_max_in, $agg_next, $agg_in_len, $agg_out_len, $agg_fallback);
625 foreach my $key (sort keys %$raw) {
628 # RAW_OUT_BYTES => 2,
630 my ($next, $in_len, $out_bytes, $fallback) = @{$raw->{$key}};
631 # Now we are converting from raw to aggregate, switch from 1 byte strings
636 # If this == fails, we're going to reset $agg_max_in below anyway.
637 $b == ++$agg_max_in &&
638 # References in numeric context give the pointer as an int.
639 $agg_next == $next &&
640 $agg_in_len == $in_len &&
641 $agg_out_len == length $out_bytes &&
642 $agg_fallback == $fallback
643 # && length($l->[AGG_OUT_BYTES]) < 16
645 # my $i = ord($b)-ord($l->[AGG_MIN_IN]);
646 # we can aggregate this byte onto the end.
647 $l->[AGG_MAX_IN] = $b;
648 $l->[AGG_OUT_BYTES] .= $out_bytes;
652 # AGG_OUT_BYTES => 2,
657 # Reset the last thing we saw, plus set 5 lexicals to save some derefs.
658 # (only gains .6% on euc-jp -- is it worth it?)
659 push @ent, $l = [$b, $agg_max_in = $b, $out_bytes, $agg_next = $next,
660 $agg_in_len = $in_len, $agg_out_len = length $out_bytes,
661 $agg_fallback = $fallback];
663 if (exists $next->{Cname}) {
664 $next->{'Forward'} = 1 if $next != $a;
666 process(sprintf("%s_%02x",$name,$b),$next);
669 # encengine.c rules say that last entry must be for 255
670 if ($agg_max_in < 255) {
671 push @ent, [1+$agg_max_in, 255,undef,$a,0,0];
673 $a->{'Entries'} = \@ent;
679 my $name = $a->{'Cname'};
681 foreach my $b (@{$a->{'Entries'}})
683 next unless $b->[AGG_OUT_LEN];
684 my $s = $b->[AGG_MIN_IN];
685 my $e = $b->[AGG_MAX_IN];
686 outstring($fh,sprintf("%s__%02x_%02x",$name,$s,$e),$b->[AGG_OUT_BYTES]);
690 print $fh "\nstatic encpage_t $name\[",scalar(@{$a->{'Entries'}}),"];\n";
693 foreach my $b (@{$a->{'Entries'}})
695 my ($s,$e,$out,$t,$end,$l) = @$b;
696 outtable($fh,$t) unless $t->{'Done'};
698 print $fh "\nstatic encpage_t $name\[",scalar(@{$a->{'Entries'}}),"] = {\n";
699 foreach my $b (@{$a->{'Entries'}})
701 my ($sc,$ec,$out,$t,$end,$l,$fb) = @$b;
706 printf $fh outstring($fh,'',$out);
712 print $fh ",",$t->{Cname};
713 printf $fh ",0x%02x,0x%02x,$l,$end},\n",$sc,$ec;
720 my ($fh,$name,$a) = @_;
728 my ($fh,$name,$a) = @_;
729 die "Changed - fix me for new structure";
730 foreach my $b (sort keys %$a)
732 my ($s,$e,$out,$t,$end,$l,$fb) = @{$a->{$b}};
744 my $s = do "unicore/Name.pl";
745 die "char_names: unicore/Name.pl: $!\n" unless defined $s;
747 while ($s =~ /\G([0-9a-f]+)\t([0-9a-f]*)\t(.*?)\s*\n/igc)
751 last if $s >= 0x10000;
752 my $e = length($2) ? hex($2) : $s;
753 for (my $i = $s; $i <= $e; $i++)
756 # print sprintf("U%04X $name\n",$i);
763 my ($cmap,$a,$t,$pre) = @_;
764 # warn sprintf("Page %x\n",$pre);
766 foreach my $key (sort keys %$raw) {
769 # RAW_OUT_BYTES => 2,
771 my ($next, $in_len, $out_bytes, $fallback) = @{$raw->{$key}};
775 if ($next != $a && $next != $t) {
776 output_ucm_page($cmap,$a,$next,(($pre|($u &0x3F)) << 6)&0xFFFF);
777 } elsif (length $out_bytes) {
779 $u = $pre|($u &0x3f);
781 my $s = sprintf "<U%04X> ",$u;
782 #foreach my $c (split(//,$out_bytes)) {
783 # $s .= sprintf "\\x%02X",ord($c);
785 # 9.5% faster changing that loop to this:
786 $s .= sprintf +("\\x%02X" x length $out_bytes), unpack "C*", $out_bytes;
787 $s .= sprintf " |%d # %s\n",($fallback ? 1 : 0),$uname[$u];
790 warn join(',',$u, @{$raw->{$key}},$a,$t);
797 my ($fh,$name,$h,$rep,$min_el,$max_el) = @_;
798 print $fh "# $0 @orig_ARGV\n" unless $opt{'q'};
799 print $fh "<code_set_name> \"$name\"\n";
803 print $fh "<mb_cur_min> $min_el\n";
807 print $fh "<mb_cur_max> $max_el\n";
811 print $fh "<subchar> ";
812 foreach my $c (split(//,$rep))
814 printf $fh "\\x%02X",ord($c);
819 output_ucm_page(\@cmap,$h,$h,0);
820 print $fh "#\nCHARMAP\n";
821 foreach my $line (sort { substr($a,8) cmp substr($b,8) } @cmap)
825 print $fh "END CHARMAP\n";
830 With %seen holding array refs:
832 865.66 real 28.80 user 8.79 sys
833 7904 maximum resident set size
834 1356 average shared memory size
835 18566 average unshared data size
836 229 average unshared stack size
840 With %seen holding simple scalars:
842 342.16 real 27.11 user 3.54 sys
843 8388 maximum resident set size
844 1394 average shared memory size
845 14969 average unshared data size
846 236 average unshared stack size
850 Yes, 5 minutes is faster than 15. Above is for CP936 in CN. Only difference is
851 how %seen is storing things its seen. So it is pathalogically bad on a 16M
852 RAM machine, but it's going to help even on modern machines.
853 Swapping is bad, m'kay :-)