diff options
Diffstat (limited to 'Master')
204 files changed, 111517 insertions, 0 deletions
diff --git a/Master/tlpkg/tlperl/lib/CPAN/API/HOWTO.pod b/Master/tlpkg/tlperl/lib/CPAN/API/HOWTO.pod new file mode 100644 index 00000000000..e65a4bc9313 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/API/HOWTO.pod @@ -0,0 +1,44 @@ +=head1 NAME + +CPAN::API::HOWTO - a recipe book for programming with CPAN.pm + +=head1 RECIPES + +All of these recipes assume that you have put "use CPAN" at the top of +your program. + +=head2 What distribution contains a particular module? + + my $distribution = CPAN::Shell->expand( + "Module", "Data::UUID" + )->distribution()->pretty_id(); + +This returns a string of the form "AUTHORID/TARBALL". If you want the +full path and filename to this distribution on a CPAN mirror, then it is +C<.../authors/id/A/AU/AUTHORID/TARBALL>. + +=head2 What modules does a particular distribution contain? + + CPAN::Index->reload(); + my @modules = CPAN::Shell->expand( + "Distribution", "JHI/Graph-0.83.tar.gz" + )->containsmods(); + +You may also refer to a distribution in the form A/AU/AUTHORID/TARBALL. + +=head1 SEE ALSO + +the main CPAN.pm documentation + +=head1 LICENSE + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +See L<http://www.perl.com/perl/misc/Artistic.html> + +=head1 AUTHOR + +David Cantrell + +=cut diff --git a/Master/tlpkg/tlperl/lib/CPAN/Author.pm b/Master/tlpkg/tlperl/lib/CPAN/Author.pm new file mode 100644 index 00000000000..e9e9226be5d --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Author.pm @@ -0,0 +1,236 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +# vim: ts=4 sts=4 sw=4: +package CPAN::Author; +use strict; + +use CPAN::InfoObj; +@CPAN::Author::ISA = qw(CPAN::InfoObj); +use vars qw( + $VERSION +); +$VERSION = "5.5"; + +package CPAN::Author; +use strict; + +#-> sub CPAN::Author::force +sub force { + my $self = shift; + $self->{force}++; +} + +#-> sub CPAN::Author::force +sub unforce { + my $self = shift; + delete $self->{force}; +} + +#-> sub CPAN::Author::id +sub id { + my $self = shift; + my $id = $self->{ID}; + $CPAN::Frontend->mydie("Illegal author id[$id]") unless $id =~ /^[A-Z]/; + $id; +} + +#-> sub CPAN::Author::as_glimpse ; +sub as_glimpse { + my($self) = @_; + my(@m); + my $class = ref($self); + $class =~ s/^CPAN:://; + push @m, sprintf(qq{%-15s %s ("%s" <%s>)\n}, + $class, + $self->{ID}, + $self->fullname, + $self->email); + join "", @m; +} + +#-> sub CPAN::Author::fullname ; +sub fullname { + shift->ro->{FULLNAME}; +} +*name = \&fullname; + +#-> sub CPAN::Author::email ; +sub email { shift->ro->{EMAIL}; } + +#-> sub CPAN::Author::ls ; +sub ls { + my $self = shift; + my $glob = shift || ""; + my $silent = shift || 0; + my $id = $self->id; + + # adapted from CPAN::Distribution::verifyCHECKSUM ; + my(@csf); # chksumfile + @csf = $self->id =~ /(.)(.)(.*)/; + $csf[1] = join "", @csf[0,1]; + $csf[2] = join "", @csf[1,2]; # ("A","AN","ANDK") + my(@dl); + @dl = $self->dir_listing([$csf[0],"CHECKSUMS"], 0, 1); + unless (grep {$_->[2] eq $csf[1]} @dl) { + $CPAN::Frontend->myprint("Directory $csf[1]/ does not exist\n") unless $silent ; + return; + } + @dl = $self->dir_listing([@csf[0,1],"CHECKSUMS"], 0, 1); + unless (grep {$_->[2] eq $csf[2]} @dl) { + $CPAN::Frontend->myprint("Directory $id/ does not exist\n") unless $silent; + return; + } + @dl = $self->dir_listing([@csf,"CHECKSUMS"], 1, 1); + if ($glob) { + if ($CPAN::META->has_inst("Text::Glob")) { + $glob =~ s|/$|/*|; + my $rglob = Text::Glob::glob_to_regex($glob); + CPAN->debug("glob[$glob]rglob[$rglob]dl[@dl]") if $CPAN::DEBUG; + my @tmpdl = grep { $_->[2] =~ /$rglob/ } @dl; + if (1==@tmpdl && $tmpdl[0][0]==0) { + $rglob = Text::Glob::glob_to_regex("$glob/*"); + @dl = grep { $_->[2] =~ /$rglob/ } @dl; + } else { + @dl = @tmpdl; + } + CPAN->debug("rglob[$rglob]dl[@dl]") if $CPAN::DEBUG; + } else { + $CPAN::Frontend->mydie("Text::Glob not installed, cannot proceed"); + } + } + unless ($silent >= 2) { + $CPAN::Frontend->myprint + ( + join "", + map { + sprintf + ( + "%8d %10s %s/%s%s\n", + $_->[0], + $_->[1], + $id, + $_->[2], + 0==$_->[0]?"/":"", + ) + } sort { $a->[2] cmp $b->[2] } @dl + ); + } + @dl; +} + +# returns an array of arrays, the latter contain (size,mtime,filename) +#-> sub CPAN::Author::dir_listing ; +sub dir_listing { + my $self = shift; + my $chksumfile = shift; + my $recursive = shift; + my $may_ftp = shift; + + my $lc_want = + File::Spec->catfile($CPAN::Config->{keep_source_where}, + "authors", "id", @$chksumfile); + + my $fh; + + CPAN->debug("chksumfile[@$chksumfile]recursive[$recursive]may_ftp[$may_ftp]") if $CPAN::DEBUG; + # Purge and refetch old (pre-PGP) CHECKSUMS; they are a security + # hazard. (Without GPG installed they are not that much better, + # though.) + $fh = FileHandle->new; + if (open($fh, $lc_want)) { + my $line = <$fh>; close $fh; + unlink($lc_want) unless $line =~ /PGP/; + } + + local($") = "/"; + # connect "force" argument with "index_expire". + my $force = $self->{force}; + if (my @stat = stat $lc_want) { + $force ||= $stat[9] + $CPAN::Config->{index_expire}*86400 <= time; + } + my $lc_file; + if ($may_ftp) { + $lc_file = eval { + CPAN::FTP->localize + ( + "authors/id/@$chksumfile", + $lc_want, + $force, + ); + }; + unless ($lc_file) { + $CPAN::Frontend->myprint("Trying $lc_want.gz\n"); + $chksumfile->[-1] .= ".gz"; + $lc_file = eval { + CPAN::FTP->localize + ("authors/id/@$chksumfile", + "$lc_want.gz", + 1, + ); + }; + if ($lc_file) { + $lc_file =~ s{\.gz(?!\n)\Z}{}; #}; + eval{CPAN::Tarzip->new("$lc_file.gz")->gunzip($lc_file)}; + } else { + return; + } + } + } else { + $lc_file = $lc_want; + # we *could* second-guess and if the user has a file: URL, + # then we could look there. But on the other hand, if they do + # have a file: URL, wy did they choose to set + # $CPAN::Config->{show_upload_date} to false? + } + + # adapted from CPAN::Distribution::CHECKSUM_check_file ; + $fh = FileHandle->new; + my($cksum); + if (open $fh, $lc_file) { + local($/); + my $eval = <$fh>; + $eval =~ s/\015?\012/\n/g; + close $fh; + my($compmt) = Safe->new(); + $cksum = $compmt->reval($eval); + if ($@) { + rename $lc_file, "$lc_file.bad"; + Carp::confess($@) if $@; + } + } elsif ($may_ftp) { + Carp::carp ("Could not open '$lc_file' for reading."); + } else { + # Maybe should warn: "You may want to set show_upload_date to a true value" + return; + } + my(@result,$f); + for $f (sort keys %$cksum) { + if (exists $cksum->{$f}{isdir}) { + if ($recursive) { + my(@dir) = @$chksumfile; + pop @dir; + push @dir, $f, "CHECKSUMS"; + push @result, [ 0, "-", $f ]; + push @result, map { + [$_->[0], $_->[1], "$f/$_->[2]"] + } $self->dir_listing(\@dir,1,$may_ftp); + } else { + push @result, [ 0, "-", $f ]; + } + } else { + push @result, [ + ($cksum->{$f}{"size"}||0), + $cksum->{$f}{"mtime"}||"---", + $f + ]; + } + } + @result; +} + +#-> sub CPAN::Author::reports +sub reports { + $CPAN::Frontend->mywarn("reports on authors not implemented. +Please file a bugreport if you need this.\n"); +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/Bundle.pm b/Master/tlpkg/tlperl/lib/CPAN/Bundle.pm new file mode 100644 index 00000000000..e7360f80485 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Bundle.pm @@ -0,0 +1,287 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +# vim: ts=4 sts=4 sw=4: +package CPAN::Bundle; +use strict; +use CPAN::Module; +@CPAN::Bundle::ISA = qw(CPAN::Module); + +use vars qw( + $VERSION +); +$VERSION = "5.5"; + +sub look { + my $self = shift; + $CPAN::Frontend->myprint($self->as_string); +} + +#-> CPAN::Bundle::undelay +sub undelay { + my $self = shift; + delete $self->{later}; + for my $c ( $self->contains ) { + my $obj = CPAN::Shell->expandany($c) or next; + $obj->undelay; + } +} + +# mark as dirty/clean +#-> sub CPAN::Bundle::color_cmd_tmps ; +sub color_cmd_tmps { + my($self) = shift; + my($depth) = shift || 0; + my($color) = shift || 0; + my($ancestors) = shift || []; + # a module needs to recurse to its cpan_file, a distribution needs + # to recurse into its prereq_pms, a bundle needs to recurse into its modules + + return if exists $self->{incommandcolor} + && $color==1 + && $self->{incommandcolor}==$color; + if ($depth>=$CPAN::MAX_RECURSION) { + die(CPAN::Exception::RecursiveDependency->new($ancestors)); + } + # warn "color_cmd_tmps $depth $color " . $self->id; # sleep 1; + + for my $c ( $self->contains ) { + my $obj = CPAN::Shell->expandany($c) or next; + CPAN->debug("c[$c]obj[$obj]") if $CPAN::DEBUG; + $obj->color_cmd_tmps($depth+1,$color,[@$ancestors, $self->id]); + } + # never reached code? + #if ($color==0) { + #delete $self->{badtestcnt}; + #} + $self->{incommandcolor} = $color; +} + +#-> sub CPAN::Bundle::as_string ; +sub as_string { + my($self) = @_; + $self->contains; + # following line must be "=", not "||=" because we have a moving target + $self->{INST_VERSION} = $self->inst_version; + return $self->SUPER::as_string; +} + +#-> sub CPAN::Bundle::contains ; +sub contains { + my($self) = @_; + my($inst_file) = $self->inst_file || ""; + my($id) = $self->id; + $self->debug("inst_file[$inst_file]id[$id]") if $CPAN::DEBUG; + if ($inst_file && CPAN::Version->vlt($self->inst_version,$self->cpan_version)) { + undef $inst_file; + } + unless ($inst_file) { + # Try to get at it in the cpan directory + $self->debug("no inst_file") if $CPAN::DEBUG; + my $cpan_file; + $CPAN::Frontend->mydie("I don't know a bundle with ID $id\n") unless + $cpan_file = $self->cpan_file; + if ($cpan_file eq "N/A") { + $CPAN::Frontend->mydie("Bundle $id not found on disk and not on CPAN. + Maybe stale symlink? Maybe removed during session? Giving up.\n"); + } + my $dist = $CPAN::META->instance('CPAN::Distribution', + $self->cpan_file); + $self->debug("before get id[$dist->{ID}]") if $CPAN::DEBUG; + $dist->get; + $self->debug("after get id[$dist->{ID}]") if $CPAN::DEBUG; + my($todir) = $CPAN::Config->{'cpan_home'}; + my(@me,$from,$to,$me); + @me = split /::/, $self->id; + $me[-1] .= ".pm"; + $me = File::Spec->catfile(@me); + $from = $self->find_bundle_file($dist->{build_dir},join('/',@me)); + $to = File::Spec->catfile($todir,$me); + File::Path::mkpath(File::Basename::dirname($to)); + File::Copy::copy($from, $to) + or Carp::confess("Couldn't copy $from to $to: $!"); + $inst_file = $to; + } + my @result; + my $fh = FileHandle->new; + local $/ = "\n"; + open($fh,$inst_file) or die "Could not open '$inst_file': $!"; + my $in_cont = 0; + $self->debug("inst_file[$inst_file]") if $CPAN::DEBUG; + while (<$fh>) { + $in_cont = m/^=(?!head1\s+(?i-xsm:CONTENTS))/ ? 0 : + m/^=head1\s+(?i-xsm:CONTENTS)/ ? 1 : $in_cont; + next unless $in_cont; + next if /^=/; + s/\#.*//; + next if /^\s+$/; + chomp; + push @result, (split " ", $_, 2)[0]; + } + close $fh; + delete $self->{STATUS}; + $self->{CONTAINS} = \@result; + $self->debug("CONTAINS[@result]") if $CPAN::DEBUG; + unless (@result) { + $CPAN::Frontend->mywarn(qq{ +The bundle file "$inst_file" may be a broken +bundlefile. It seems not to contain any bundle definition. +Please check the file and if it is bogus, please delete it. +Sorry for the inconvenience. +}); + } + @result; +} + +#-> sub CPAN::Bundle::find_bundle_file +# $where is in local format, $what is in unix format +sub find_bundle_file { + my($self,$where,$what) = @_; + $self->debug("where[$where]what[$what]") if $CPAN::DEBUG; +### The following two lines let CPAN.pm become Bundle/CPAN.pm :-( +### my $bu = File::Spec->catfile($where,$what); +### return $bu if -f $bu; + my $manifest = File::Spec->catfile($where,"MANIFEST"); + unless (-f $manifest) { + require ExtUtils::Manifest; + my $cwd = CPAN::anycwd(); + $self->safe_chdir($where); + ExtUtils::Manifest::mkmanifest(); + $self->safe_chdir($cwd); + } + my $fh = FileHandle->new($manifest) + or Carp::croak("Couldn't open $manifest: $!"); + local($/) = "\n"; + my $bundle_filename = $what; + $bundle_filename =~ s|Bundle.*/||; + my $bundle_unixpath; + while (<$fh>) { + next if /^\s*\#/; + my($file) = /(\S+)/; + if ($file =~ m|\Q$what\E$|) { + $bundle_unixpath = $file; + # return File::Spec->catfile($where,$bundle_unixpath); # bad + last; + } + # retry if she managed to have no Bundle directory + $bundle_unixpath = $file if $file =~ m|\Q$bundle_filename\E$|; + } + return File::Spec->catfile($where, split /\//, $bundle_unixpath) + if $bundle_unixpath; + Carp::croak("Couldn't find a Bundle file in $where"); +} + +# needs to work quite differently from Module::inst_file because of +# cpan_home/Bundle/ directory and the possibility that we have +# shadowing effect. As it makes no sense to take the first in @INC for +# Bundles, we parse them all for $VERSION and take the newest. + +#-> sub CPAN::Bundle::inst_file ; +sub inst_file { + my($self) = @_; + my($inst_file); + my(@me); + @me = split /::/, $self->id; + $me[-1] .= ".pm"; + my($incdir,$bestv); + foreach $incdir ($CPAN::Config->{'cpan_home'},@INC) { + my $parsefile = File::Spec->catfile($incdir, @me); + CPAN->debug("parsefile[$parsefile]") if $CPAN::DEBUG; + next unless -f $parsefile; + my $have = eval { MM->parse_version($parsefile); }; + if ($@) { + $CPAN::Frontend->mywarn("Error while parsing version number in file '$parsefile'\n"); + } + if (!$bestv || CPAN::Version->vgt($have,$bestv)) { + $self->{INST_FILE} = $parsefile; + $self->{INST_VERSION} = $bestv = $have; + } + } + $self->{INST_FILE}; +} + +#-> sub CPAN::Bundle::inst_version ; +sub inst_version { + my($self) = @_; + $self->inst_file; # finds INST_VERSION as side effect + $self->{INST_VERSION}; +} + +#-> sub CPAN::Bundle::rematein ; +sub rematein { + my($self,$meth) = @_; + $self->debug("self[$self] meth[$meth]") if $CPAN::DEBUG; + my($id) = $self->id; + Carp::croak( "Can't $meth $id, don't have an associated bundle file. :-(\n" ) + unless $self->inst_file || $self->cpan_file; + my($s,%fail); + for $s ($self->contains) { + my($type) = $s =~ m|/| ? 'CPAN::Distribution' : + $s =~ m|^Bundle::| ? 'CPAN::Bundle' : 'CPAN::Module'; + if ($type eq 'CPAN::Distribution') { + $CPAN::Frontend->mywarn(qq{ +The Bundle }.$self->id.qq{ contains +explicitly a file '$s'. +Going to $meth that. +}); + $CPAN::Frontend->mysleep(5); + } + # possibly noisy action: + $self->debug("type[$type] s[$s]") if $CPAN::DEBUG; + my $obj = $CPAN::META->instance($type,$s); + $obj->{reqtype} = $self->{reqtype}; + $obj->$meth(); + } +} + +# If a bundle contains another that contains an xs_file we have here, +# we just don't bother I suppose +#-> sub CPAN::Bundle::xs_file +sub xs_file { + return 0; +} + +#-> sub CPAN::Bundle::force ; +sub fforce { shift->rematein('fforce',@_); } +#-> sub CPAN::Bundle::force ; +sub force { shift->rematein('force',@_); } +#-> sub CPAN::Bundle::notest ; +sub notest { shift->rematein('notest',@_); } +#-> sub CPAN::Bundle::get ; +sub get { shift->rematein('get',@_); } +#-> sub CPAN::Bundle::make ; +sub make { shift->rematein('make',@_); } +#-> sub CPAN::Bundle::test ; +sub test { + my $self = shift; + # $self->{badtestcnt} ||= 0; + $self->rematein('test',@_); +} +#-> sub CPAN::Bundle::install ; +sub install { + my $self = shift; + $self->rematein('install',@_); +} +#-> sub CPAN::Bundle::clean ; +sub clean { shift->rematein('clean',@_); } + +#-> sub CPAN::Bundle::uptodate ; +sub uptodate { + my($self) = @_; + return 0 unless $self->SUPER::uptodate; # we mut have the current Bundle def + my $c; + foreach $c ($self->contains) { + my $obj = CPAN::Shell->expandany($c); + return 0 unless $obj->uptodate; + } + return 1; +} + +#-> sub CPAN::Bundle::readme ; +sub readme { + my($self) = @_; + my($file) = $self->cpan_file or $CPAN::Frontend->myprint(qq{ +No File found for bundle } . $self->id . qq{\n}), return; + $self->debug("self[$self] file[$file]") if $CPAN::DEBUG; + $CPAN::META->instance('CPAN::Distribution',$file)->readme; +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/CacheMgr.pm b/Master/tlpkg/tlperl/lib/CPAN/CacheMgr.pm new file mode 100644 index 00000000000..827baeaefdb --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/CacheMgr.pm @@ -0,0 +1,246 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +# vim: ts=4 sts=4 sw=4: +package CPAN::CacheMgr; +use strict; +use CPAN::InfoObj; +@CPAN::CacheMgr::ISA = qw(CPAN::InfoObj CPAN); +use Cwd qw(chdir); +use File::Find; + +use vars qw( + $VERSION +); +$VERSION = "5.5"; + +package CPAN::CacheMgr; +use strict; + +#-> sub CPAN::CacheMgr::as_string ; +sub as_string { + eval { require Data::Dumper }; + if ($@) { + return shift->SUPER::as_string; + } else { + return Data::Dumper::Dumper(shift); + } +} + +#-> sub CPAN::CacheMgr::cachesize ; +sub cachesize { + shift->{DU}; +} + +#-> sub CPAN::CacheMgr::tidyup ; +sub tidyup { + my($self) = @_; + return unless $CPAN::META->{LOCK}; + return unless -d $self->{ID}; + my @toremove = grep { $self->{SIZE}{$_}==0 } @{$self->{FIFO}}; + for my $current (0..$#toremove) { + my $toremove = $toremove[$current]; + $CPAN::Frontend->myprint(sprintf( + "DEL(%d/%d): %s \n", + $current+1, + scalar @toremove, + $toremove, + ) + ); + return if $CPAN::Signal; + $self->_clean_cache($toremove); + return if $CPAN::Signal; + } +} + +#-> sub CPAN::CacheMgr::dir ; +sub dir { + shift->{ID}; +} + +#-> sub CPAN::CacheMgr::entries ; +sub entries { + my($self,$dir) = @_; + return unless defined $dir; + $self->debug("reading dir[$dir]") if $CPAN::DEBUG; + $dir ||= $self->{ID}; + my($cwd) = CPAN::anycwd(); + chdir $dir or Carp::croak("Can't chdir to $dir: $!"); + my $dh = DirHandle->new(File::Spec->curdir) + or Carp::croak("Couldn't opendir $dir: $!"); + my(@entries); + for ($dh->read) { + next if $_ eq "." || $_ eq ".."; + if (-f $_) { + push @entries, File::Spec->catfile($dir,$_); + } elsif (-d _) { + push @entries, File::Spec->catdir($dir,$_); + } else { + $CPAN::Frontend->mywarn("Warning: weird direntry in $dir: $_\n"); + } + } + chdir $cwd or Carp::croak("Can't chdir to $cwd: $!"); + sort { -M $a <=> -M $b} @entries; +} + +#-> sub CPAN::CacheMgr::disk_usage ; +sub disk_usage { + my($self,$dir,$fast) = @_; + return if exists $self->{SIZE}{$dir}; + return if $CPAN::Signal; + my($Du) = 0; + if (-e $dir) { + if (-d $dir) { + unless (-x $dir) { + unless (chmod 0755, $dir) { + $CPAN::Frontend->mywarn("I have neither the -x permission nor the ". + "permission to change the permission; cannot ". + "estimate disk usage of '$dir'\n"); + $CPAN::Frontend->mysleep(5); + return; + } + } + } elsif (-f $dir) { + # nothing to say, no matter what the permissions + } + } else { + $CPAN::Frontend->mywarn("File or directory '$dir' has gone, ignoring\n"); + return; + } + if ($fast) { + $Du = 0; # placeholder + } else { + find( + sub { + $File::Find::prune++ if $CPAN::Signal; + return if -l $_; + if ($^O eq 'MacOS') { + require Mac::Files; + my $cat = Mac::Files::FSpGetCatInfo($_); + $Du += $cat->ioFlLgLen() + $cat->ioFlRLgLen() if $cat; + } else { + if (-d _) { + unless (-x _) { + unless (chmod 0755, $_) { + $CPAN::Frontend->mywarn("I have neither the -x permission nor ". + "the permission to change the permission; ". + "can only partially estimate disk usage ". + "of '$_'\n"); + $CPAN::Frontend->mysleep(5); + return; + } + } + } else { + $Du += (-s _); + } + } + }, + $dir + ); + } + return if $CPAN::Signal; + $self->{SIZE}{$dir} = $Du/1024/1024; + unshift @{$self->{FIFO}}, $dir; + $self->debug("measured $dir is $Du") if $CPAN::DEBUG; + $self->{DU} += $Du/1024/1024; + $self->{DU}; +} + +#-> sub CPAN::CacheMgr::_clean_cache ; +sub _clean_cache { + my($self,$dir) = @_; + return unless -e $dir; + unless (File::Spec->canonpath(File::Basename::dirname($dir)) + eq File::Spec->canonpath($CPAN::Config->{build_dir})) { + $CPAN::Frontend->mywarn("Directory '$dir' not below $CPAN::Config->{build_dir}, ". + "will not remove\n"); + $CPAN::Frontend->mysleep(5); + return; + } + $self->debug("have to rmtree $dir, will free $self->{SIZE}{$dir}") + if $CPAN::DEBUG; + File::Path::rmtree($dir); + my $id_deleted = 0; + if ($dir !~ /\.yml$/ && -f "$dir.yml") { + my $yaml_module = CPAN::_yaml_module(); + if ($CPAN::META->has_inst($yaml_module)) { + my($peek_yaml) = eval { CPAN->_yaml_loadfile("$dir.yml"); }; + if ($@) { + $CPAN::Frontend->mywarn("(parse error on '$dir.yml' removing anyway)"); + unlink "$dir.yml" or + $CPAN::Frontend->mywarn("(Could not unlink '$dir.yml': $!)"); + return; + } elsif (my $id = $peek_yaml->[0]{distribution}{ID}) { + $CPAN::META->delete("CPAN::Distribution", $id); + + # XXX we should restore the state NOW, otherise this + # distro does not exist until we read an index. BUG ALERT(?) + + # $CPAN::Frontend->mywarn (" +++\n"); + $id_deleted++; + } + } + unlink "$dir.yml"; # may fail + unless ($id_deleted) { + CPAN->debug("no distro found associated with '$dir'"); + } + } + $self->{DU} -= $self->{SIZE}{$dir}; + delete $self->{SIZE}{$dir}; +} + +#-> sub CPAN::CacheMgr::new ; +sub new { + my $class = shift; + my $time = time; + my($debug,$t2); + $debug = ""; + my $self = { + ID => $CPAN::Config->{build_dir}, + MAX => $CPAN::Config->{'build_cache'}, + SCAN => $CPAN::Config->{'scan_cache'} || 'atstart', + DU => 0 + }; + File::Path::mkpath($self->{ID}); + my $dh = DirHandle->new($self->{ID}); + bless $self, $class; + $self->scan_cache; + $t2 = time; + $debug .= "timing of CacheMgr->new: ".($t2 - $time); + $time = $t2; + CPAN->debug($debug) if $CPAN::DEBUG; + $self; +} + +#-> sub CPAN::CacheMgr::scan_cache ; +sub scan_cache { + my $self = shift; + return if $self->{SCAN} eq 'never'; + $CPAN::Frontend->mydie("Unknown scan_cache argument: $self->{SCAN}") + unless $self->{SCAN} eq 'atstart'; + return unless $CPAN::META->{LOCK}; + $CPAN::Frontend->myprint( + sprintf("Scanning cache %s for sizes\n", + $self->{ID})); + my $e; + my @entries = $self->entries($self->{ID}); + my $i = 0; + my $painted = 0; + for $e (@entries) { + my $symbol = "."; + if ($self->{DU} > $self->{MAX}) { + $symbol = "-"; + $self->disk_usage($e,1); + } else { + $self->disk_usage($e); + } + $i++; + while (($painted/76) < ($i/@entries)) { + $CPAN::Frontend->myprint($symbol); + $painted++; + } + return if $CPAN::Signal; + } + $CPAN::Frontend->myprint("DONE\n"); + $self->tidyup; +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/Complete.pm b/Master/tlpkg/tlperl/lib/CPAN/Complete.pm new file mode 100644 index 00000000000..e1fe896d4a5 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Complete.pm @@ -0,0 +1,175 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +# vim: ts=4 sts=4 sw=4: +package CPAN::Complete; +use strict; +@CPAN::Complete::ISA = qw(CPAN::Debug); +# Q: where is the "How do I add a new command" HOWTO? +# A: svn diff -r 1048:1049 where andk added the report command +@CPAN::Complete::COMMANDS = sort qw( + ? ! a b d h i m o q r u + autobundle + bye + clean + cvs_import + dump + exit + failed + force + fforce + hosts + install + install_tested + is_tested + look + ls + make + mkmyconfig + notest + perldoc + quit + readme + recent + recompile + reload + report + reports + scripts + smoke + test + upgrade +); + +use vars qw( + $VERSION +); +$VERSION = "5.5"; + +package CPAN::Complete; +use strict; + +sub gnu_cpl { + my($text, $line, $start, $end) = @_; + my(@perlret) = cpl($text, $line, $start); + # find longest common match. Can anybody show me how to peruse + # T::R::Gnu to have this done automatically? Seems expensive. + return () unless @perlret; + my($newtext) = $text; + for (my $i = length($text)+1;;$i++) { + last unless length($perlret[0]) && length($perlret[0]) >= $i; + my $try = substr($perlret[0],0,$i); + my @tries = grep {substr($_,0,$i) eq $try} @perlret; + # warn "try[$try]tries[@tries]"; + if (@tries == @perlret) { + $newtext = $try; + } else { + last; + } + } + ($newtext,@perlret); +} + +#-> sub CPAN::Complete::cpl ; +sub cpl { + my($word,$line,$pos) = @_; + $word ||= ""; + $line ||= ""; + $pos ||= 0; + CPAN->debug("word [$word] line[$line] pos[$pos]") if $CPAN::DEBUG; + $line =~ s/^\s*//; + if ($line =~ s/^((?:notest|f?force)\s*)//) { + $pos -= length($1); + } + my @return; + if ($pos == 0 || $line =~ /^(?:h(?:elp)?|\?)\s/) { + @return = grep /^\Q$word\E/, @CPAN::Complete::COMMANDS; + } elsif ( $line !~ /^[\!abcdghimorutl]/ ) { + @return = (); + } elsif ($line =~ /^a\s/) { + @return = cplx('CPAN::Author',uc($word)); + } elsif ($line =~ /^ls\s/) { + my($author,$rest) = $word =~ m|([^/]+)/?(.*)|; + @return = $rest ? () : map {"$_/"} cplx('CPAN::Author',uc($author||"")); + if (0 && 1==@return) { # XXX too slow and even wrong when there is a * already + @return = grep /^\Q$word\E/, map {"$author/$_->[2]"} CPAN::Shell->expand("Author",$author)->ls("$rest*","2"); + } + } elsif ($line =~ /^b\s/) { + CPAN::Shell->local_bundles; + @return = cplx('CPAN::Bundle',$word); + } elsif ($line =~ /^d\s/) { + @return = cplx('CPAN::Distribution',$word); + } elsif ($line =~ m/^( + [mru]|make|clean|dump|get|test|install|readme|look|cvs_import|perldoc|recent + )\s/x ) { + if ($word =~ /^Bundle::/) { + CPAN::Shell->local_bundles; + } + @return = (cplx('CPAN::Module',$word),cplx('CPAN::Bundle',$word)); + } elsif ($line =~ /^i\s/) { + @return = cpl_any($word); + } elsif ($line =~ /^reload\s/) { + @return = cpl_reload($word,$line,$pos); + } elsif ($line =~ /^o\s/) { + @return = cpl_option($word,$line,$pos); + } elsif ($line =~ m/^\S+\s/ ) { + # fallback for future commands and what we have forgotten above + @return = (cplx('CPAN::Module',$word),cplx('CPAN::Bundle',$word)); + } else { + @return = (); + } + return @return; +} + +#-> sub CPAN::Complete::cplx ; +sub cplx { + my($class, $word) = @_; + if (CPAN::_sqlite_running()) { + $CPAN::SQLite->search($class, "^\Q$word\E"); + } + my $method = "id"; + $method = "pretty_id" if $class eq "CPAN::Distribution"; + sort grep /^\Q$word\E/, map { $_->$method() } $CPAN::META->all_objects($class); +} + +#-> sub CPAN::Complete::cpl_any ; +sub cpl_any { + my($word) = shift; + return ( + cplx('CPAN::Author',$word), + cplx('CPAN::Bundle',$word), + cplx('CPAN::Distribution',$word), + cplx('CPAN::Module',$word), + ); +} + +#-> sub CPAN::Complete::cpl_reload ; +sub cpl_reload { + my($word,$line,$pos) = @_; + $word ||= ""; + my(@words) = split " ", $line; + CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG; + my(@ok) = qw(cpan index); + return @ok if @words == 1; + return grep /^\Q$word\E/, @ok if @words == 2 && $word; +} + +#-> sub CPAN::Complete::cpl_option ; +sub cpl_option { + my($word,$line,$pos) = @_; + $word ||= ""; + my(@words) = split " ", $line; + CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG; + my(@ok) = qw(conf debug); + return @ok if @words == 1; + return grep /^\Q$word\E/, @ok if @words == 2 && length($word); + if (0) { + } elsif ($words[1] eq 'index') { + return (); + } elsif ($words[1] eq 'conf') { + return CPAN::HandleConfig::cpl(@_); + } elsif ($words[1] eq 'debug') { + return sort grep /^\Q$word\E/i, + sort keys %CPAN::DEBUG, 'all'; + } +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/Debug.pm b/Master/tlpkg/tlperl/lib/CPAN/Debug.pm new file mode 100644 index 00000000000..23c4a3685b6 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Debug.pm @@ -0,0 +1,79 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +package CPAN::Debug; +use strict; +use vars qw($VERSION); + +$VERSION = "5.5001"; +# module is internal to CPAN.pm + +%CPAN::DEBUG = qw[ + CPAN 1 + Index 2 + InfoObj 4 + Author 8 + Distribution 16 + Bundle 32 + Module 64 + CacheMgr 128 + Complete 256 + FTP 512 + Shell 1024 + Eval 2048 + HandleConfig 4096 + Tarzip 8192 + Version 16384 + Queue 32768 + FirstTime 65536 +]; + +$CPAN::DEBUG ||= 0; + +#-> sub CPAN::Debug::debug ; +sub debug { + my($self,$arg) = @_; + + my @caller; + my $i = 0; + while () { + my(@c) = (caller($i))[0 .. ($i ? 3 : 2)]; + last unless defined $c[0]; + push @caller, \@c; + for (0,3) { + last if $_ > $#c; + $c[$_] =~ s/.*:://; + } + for (1) { + $c[$_] =~ s|.*/||; + } + last if ++$i>=3; + } + pop @caller; + if ($CPAN::DEBUG{$caller[0][0]} & $CPAN::DEBUG) { + if ($arg and ref $arg) { + eval { require Data::Dumper }; + if ($@) { + $CPAN::Frontend->myprint("Debug(\n" . $arg->as_string . ")\n"); + } else { + $CPAN::Frontend->myprint("Debug(\n" . Data::Dumper::Dumper($arg) . ")\n"); + } + } else { + my $outer = ""; + local $" = ","; + if (@caller>1) { + $outer = ",[@{$caller[1]}]"; + } + $CPAN::Frontend->myprint("Debug(@{$caller[0]}$outer): $arg\n"); + } + } +} + +1; + +__END__ + +=head1 LICENSE + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=cut diff --git a/Master/tlpkg/tlperl/lib/CPAN/DeferredCode.pm b/Master/tlpkg/tlperl/lib/CPAN/DeferredCode.pm new file mode 100644 index 00000000000..0db37a64853 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/DeferredCode.pm @@ -0,0 +1,16 @@ +package CPAN::DeferredCode; + +use strict; +use vars qw/$VERSION/; + +use overload fallback => 1, map { ($_ => 'run') } qw/ + bool "" 0+ +/; + +$VERSION = "5.50"; + +sub run { + $_[0]->(); +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/Distribution.pm b/Master/tlpkg/tlperl/lib/CPAN/Distribution.pm new file mode 100644 index 00000000000..ac8f873a130 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Distribution.pm @@ -0,0 +1,3896 @@ +package CPAN::Distribution; +use strict; +use Cwd qw(chdir); +use CPAN::Distroprefs; +use CPAN::InfoObj; +@CPAN::Distribution::ISA = qw(CPAN::InfoObj); +use vars qw($VERSION); +$VERSION = "1.9456_01"; + +# Accessors +sub cpan_comment { + my $self = shift; + my $ro = $self->ro or return; + $ro->{CPAN_COMMENT} +} + +#-> CPAN::Distribution::undelay +sub undelay { + my $self = shift; + for my $delayer ( + "configure_requires_later", + "configure_requires_later_for", + "later", + "later_for", + ) { + delete $self->{$delayer}; + } +} + +#-> CPAN::Distribution::is_dot_dist +sub is_dot_dist { + my($self) = @_; + return substr($self->id,-1,1) eq "."; +} + +# add the A/AN/ stuff +#-> CPAN::Distribution::normalize +sub normalize { + my($self,$s) = @_; + $s = $self->id unless defined $s; + if (substr($s,-1,1) eq ".") { + # using a global because we are sometimes called as static method + if (!$CPAN::META->{LOCK} + && !$CPAN::Have_warned->{"$s is unlocked"}++ + ) { + $CPAN::Frontend->mywarn("You are visiting the local directory + '$s' + without lock, take care that concurrent processes do not do likewise.\n"); + $CPAN::Frontend->mysleep(1); + } + if ($s eq ".") { + $s = "$CPAN::iCwd/."; + } elsif (File::Spec->file_name_is_absolute($s)) { + } elsif (File::Spec->can("rel2abs")) { + $s = File::Spec->rel2abs($s); + } else { + $CPAN::Frontend->mydie("Your File::Spec is too old, please upgrade File::Spec"); + } + CPAN->debug("s[$s]") if $CPAN::DEBUG; + unless ($CPAN::META->exists("CPAN::Distribution", $s)) { + for ($CPAN::META->instance("CPAN::Distribution", $s)) { + $_->{build_dir} = $s; + $_->{archived} = "local_directory"; + $_->{unwrapped} = CPAN::Distrostatus->new("YES -- local_directory"); + } + } + } elsif ( + $s =~ tr|/|| == 1 + or + $s !~ m|[A-Z]/[A-Z-]{2}/[A-Z-]{2,}/| + ) { + return $s if $s =~ m:^N/A|^Contact Author: ; + $s =~ s|^(.)(.)([^/]*/)(.+)$|$1/$1$2/$1$2$3$4|; + CPAN->debug("s[$s]") if $CPAN::DEBUG; + } + $s; +} + +#-> sub CPAN::Distribution::author ; +sub author { + my($self) = @_; + my($authorid); + if (substr($self->id,-1,1) eq ".") { + $authorid = "LOCAL"; + } else { + ($authorid) = $self->pretty_id =~ /^([\w\-]+)/; + } + CPAN::Shell->expand("Author",$authorid); +} + +# tries to get the yaml from CPAN instead of the distro itself: +# EXPERIMENTAL, UNDOCUMENTED AND UNTESTED, for Tels +sub fast_yaml { + my($self) = @_; + my $meta = $self->pretty_id; + $meta =~ s/\.(tar.gz|tgz|zip|tar.bz2)/.meta/; + my(@ls) = CPAN::Shell->globls($meta); + my $norm = $self->normalize($meta); + + my($local_file); + my($local_wanted) = + File::Spec->catfile( + $CPAN::Config->{keep_source_where}, + "authors", + "id", + split(/\//,$norm) + ); + $self->debug("Doing localize") if $CPAN::DEBUG; + unless ($local_file = + CPAN::FTP->localize("authors/id/$norm", + $local_wanted)) { + $CPAN::Frontend->mydie("Giving up on downloading yaml file '$local_wanted'\n"); + } + my $yaml = CPAN->_yaml_loadfile($local_file)->[0]; +} + +#-> sub CPAN::Distribution::cpan_userid +sub cpan_userid { + my $self = shift; + if ($self->{ID} =~ m{[A-Z]/[A-Z\-]{2}/([A-Z\-]+)/}) { + return $1; + } + return $self->SUPER::cpan_userid; +} + +#-> sub CPAN::Distribution::pretty_id +sub pretty_id { + my $self = shift; + my $id = $self->id; + return $id unless $id =~ m|^./../|; + substr($id,5); +} + +#-> sub CPAN::Distribution::base_id +sub base_id { + my $self = shift; + my $id = $self->pretty_id(); + my $base_id = File::Basename::basename($id); + $base_id =~ s{\.(?:tar\.(bz2|gz|Z)|t(?:gz|bz)|zip)$}{}i; + return $base_id; +} + +#-> sub CPAN::Distribution::tested_ok_but_not_installed +sub tested_ok_but_not_installed { + my $self = shift; + return ( + $self->{make_test} + && $self->{build_dir} + && (UNIVERSAL::can($self->{make_test},"failed") ? + ! $self->{make_test}->failed : + $self->{make_test} =~ /^YES/ + ) + && ( + !$self->{install} + || + $self->{install}->failed + ) + ); +} + + +# mark as dirty/clean for the sake of recursion detection. $color=1 +# means "in use", $color=0 means "not in use anymore". $color=2 means +# we have determined prereqs now and thus insist on passing this +# through (at least) once again. + +#-> sub CPAN::Distribution::color_cmd_tmps ; +sub color_cmd_tmps { + my($self) = shift; + my($depth) = shift || 0; + my($color) = shift || 0; + my($ancestors) = shift || []; + # a distribution needs to recurse into its prereq_pms + $self->debug("color_cmd_tmps[$depth,$color,@$ancestors]") if $CPAN::DEBUG; + + return if exists $self->{incommandcolor} + && $color==1 + && $self->{incommandcolor}==$color; + if ($depth>=$CPAN::MAX_RECURSION) { + die(CPAN::Exception::RecursiveDependency->new($ancestors)); + } + # warn "color_cmd_tmps $depth $color " . $self->id; # sleep 1; + my $prereq_pm = $self->prereq_pm; + if (defined $prereq_pm) { + PREREQ: for my $pre (keys %{$prereq_pm->{requires}||{}}, + keys %{$prereq_pm->{build_requires}||{}}) { + next PREREQ if $pre eq "perl"; + my $premo; + unless ($premo = CPAN::Shell->expand("Module",$pre)) { + $CPAN::Frontend->mywarn("prerequisite module[$pre] not known\n"); + $CPAN::Frontend->mysleep(2); + next PREREQ; + } + $premo->color_cmd_tmps($depth+1,$color,[@$ancestors, $self->id]); + } + } + if ($color==0) { + delete $self->{sponsored_mods}; + + # as we are at the end of a command, we'll give up this + # reminder of a broken test. Other commands may test this guy + # again. Maybe 'badtestcnt' should be renamed to + # 'make_test_failed_within_command'? + delete $self->{badtestcnt}; + } + $self->{incommandcolor} = $color; +} + +#-> sub CPAN::Distribution::as_string ; +sub as_string { + my $self = shift; + $self->containsmods; + $self->upload_date; + $self->SUPER::as_string(@_); +} + +#-> sub CPAN::Distribution::containsmods ; +sub containsmods { + my $self = shift; + return keys %{$self->{CONTAINSMODS}} if exists $self->{CONTAINSMODS}; + my $dist_id = $self->{ID}; + for my $mod ($CPAN::META->all_objects("CPAN::Module")) { + my $mod_file = $mod->cpan_file or next; + my $mod_id = $mod->{ID} or next; + # warn "mod_file[$mod_file] dist_id[$dist_id] mod_id[$mod_id]"; + # sleep 1; + if ($CPAN::Signal) { + delete $self->{CONTAINSMODS}; + return; + } + $self->{CONTAINSMODS}{$mod_id} = undef if $mod_file eq $dist_id; + } + keys %{$self->{CONTAINSMODS}||={}}; +} + +#-> sub CPAN::Distribution::upload_date ; +sub upload_date { + my $self = shift; + return $self->{UPLOAD_DATE} if exists $self->{UPLOAD_DATE}; + my(@local_wanted) = split(/\//,$self->id); + my $filename = pop @local_wanted; + push @local_wanted, "CHECKSUMS"; + my $author = CPAN::Shell->expand("Author",$self->cpan_userid); + return unless $author; + my @dl = $author->dir_listing(\@local_wanted,0,$CPAN::Config->{show_upload_date}); + return unless @dl; + my($dirent) = grep { $_->[2] eq $filename } @dl; + # warn sprintf "dirent[%s]id[%s]", $dirent, $self->id; + return unless $dirent->[1]; + return $self->{UPLOAD_DATE} = $dirent->[1]; +} + +#-> sub CPAN::Distribution::uptodate ; +sub uptodate { + my($self) = @_; + my $c; + foreach $c ($self->containsmods) { + my $obj = CPAN::Shell->expandany($c); + unless ($obj->uptodate) { + my $id = $self->pretty_id; + $self->debug("$id not uptodate due to $c") if $CPAN::DEBUG; + return 0; + } + } + return 1; +} + +#-> sub CPAN::Distribution::called_for ; +sub called_for { + my($self,$id) = @_; + $self->{CALLED_FOR} = $id if defined $id; + return $self->{CALLED_FOR}; +} + +#-> sub CPAN::Distribution::get ; +sub get { + my($self) = @_; + $self->debug("checking goto id[$self->{ID}]") if $CPAN::DEBUG; + if (my $goto = $self->prefs->{goto}) { + $CPAN::Frontend->mywarn + (sprintf( + "delegating to '%s' as specified in prefs file '%s' doc %d\n", + $goto, + $self->{prefs_file}, + $self->{prefs_file_doc}, + )); + return $self->goto($goto); + } + local $ENV{PERL5LIB} = defined($ENV{PERL5LIB}) + ? $ENV{PERL5LIB} + : ($ENV{PERLLIB} || ""); + local $ENV{PERL5OPT} = defined $ENV{PERL5OPT} ? $ENV{PERL5OPT} : ""; + $CPAN::META->set_perl5lib; + local $ENV{MAKEFLAGS}; # protect us from outer make calls + + EXCUSE: { + my @e; + my $goodbye_message; + $self->debug("checking disabled id[$self->{ID}]") if $CPAN::DEBUG; + if ($self->prefs->{disabled} && ! $self->{force_update}) { + my $why = sprintf( + "Disabled via prefs file '%s' doc %d", + $self->{prefs_file}, + $self->{prefs_file_doc}, + ); + push @e, $why; + $self->{unwrapped} = CPAN::Distrostatus->new("NO $why"); + $goodbye_message = "[disabled] -- NA $why"; + # note: not intended to be persistent but at least visible + # during this session + } else { + if (exists $self->{build_dir} && -d $self->{build_dir} + && ($self->{modulebuild}||$self->{writemakefile}) + ) { + # this deserves print, not warn: + $CPAN::Frontend->myprint(" Has already been unwrapped into directory ". + "$self->{build_dir}\n" + ); + return 1; + } + + # although we talk about 'force' we shall not test on + # force directly. New model of force tries to refrain from + # direct checking of force. + exists $self->{unwrapped} and ( + UNIVERSAL::can($self->{unwrapped},"failed") ? + $self->{unwrapped}->failed : + $self->{unwrapped} =~ /^NO/ + ) + and push @e, "Unwrapping had some problem, won't try again without force"; + } + if (@e) { + $CPAN::Frontend->mywarn(join "", map {"$_\n"} @e); + if ($goodbye_message) { + $self->goodbye($goodbye_message); + } + return; + } + } + my $sub_wd = CPAN::anycwd(); # for cleaning up as good as possible + + my($local_file); + unless ($self->{build_dir} && -d $self->{build_dir}) { + $self->get_file_onto_local_disk; + return if $CPAN::Signal; + $self->check_integrity; + return if $CPAN::Signal; + (my $packagedir,$local_file) = $self->run_preps_on_packagedir; + if (exists $self->{writemakefile} && ref $self->{writemakefile} + && $self->{writemakefile}->can("failed") && + $self->{writemakefile}->failed) { + return; + } + $packagedir ||= $self->{build_dir}; + $self->{build_dir} = $packagedir; + } + + if ($CPAN::Signal) { + $self->safe_chdir($sub_wd); + return; + } + return $self->choose_MM_or_MB($local_file); +} + +#-> CPAN::Distribution::get_file_onto_local_disk +sub get_file_onto_local_disk { + my($self) = @_; + + return if $self->is_dot_dist; + my($local_file); + my($local_wanted) = + File::Spec->catfile( + $CPAN::Config->{keep_source_where}, + "authors", + "id", + split(/\//,$self->id) + ); + + $self->debug("Doing localize") if $CPAN::DEBUG; + unless ($local_file = + CPAN::FTP->localize("authors/id/$self->{ID}", + $local_wanted)) { + my $note = ""; + if ($CPAN::Index::DATE_OF_02) { + $note = "Note: Current database in memory was generated ". + "on $CPAN::Index::DATE_OF_02\n"; + } + $CPAN::Frontend->mydie("Giving up on '$local_wanted'\n$note"); + } + + $self->debug("local_wanted[$local_wanted]local_file[$local_file]") if $CPAN::DEBUG; + $self->{localfile} = $local_file; +} + + +#-> CPAN::Distribution::check_integrity +sub check_integrity { + my($self) = @_; + + return if $self->is_dot_dist; + if ($CPAN::META->has_inst("Digest::SHA")) { + $self->debug("Digest::SHA is installed, verifying"); + $self->verifyCHECKSUM; + } else { + $self->debug("Digest::SHA is NOT installed"); + } +} + +#-> CPAN::Distribution::run_preps_on_packagedir +sub run_preps_on_packagedir { + my($self) = @_; + return if $self->is_dot_dist; + + $CPAN::META->{cachemgr} ||= CPAN::CacheMgr->new(); # unsafe meta access, ok + my $builddir = $CPAN::META->{cachemgr}->dir; # unsafe meta access, ok + $self->safe_chdir($builddir); + $self->debug("Removing tmp-$$") if $CPAN::DEBUG; + File::Path::rmtree("tmp-$$"); + unless (mkdir "tmp-$$", 0755) { + $CPAN::Frontend->unrecoverable_error(<<EOF); +Couldn't mkdir '$builddir/tmp-$$': $! + +Cannot continue: Please find the reason why I cannot make the +directory +$builddir/tmp-$$ +and fix the problem, then retry. + +EOF + } + if ($CPAN::Signal) { + return; + } + $self->safe_chdir("tmp-$$"); + + # + # Unpack the goods + # + my $local_file = $self->{localfile}; + my $ct = eval{CPAN::Tarzip->new($local_file)}; + unless ($ct) { + $self->{unwrapped} = CPAN::Distrostatus->new("NO"); + delete $self->{build_dir}; + return; + } + if ($local_file =~ /(\.tar\.(bz2|gz|Z)|\.tgz)(?!\n)\Z/i) { + $self->{was_uncompressed}++ unless eval{$ct->gtest()}; + $self->untar_me($ct); + } elsif ( $local_file =~ /\.zip(?!\n)\Z/i ) { + $self->unzip_me($ct); + } else { + $self->{was_uncompressed}++ unless $ct->gtest(); + $local_file = $self->handle_singlefile($local_file); + } + + # we are still in the tmp directory! + # Let's check if the package has its own directory. + my $dh = DirHandle->new(File::Spec->curdir) + or Carp::croak("Couldn't opendir .: $!"); + my @readdir = grep $_ !~ /^\.\.?(?!\n)\Z/s, $dh->read; ### MAC?? + if (grep { $_ eq "pax_global_header" } @readdir) { + $CPAN::Frontend->mywarn("Your (un)tar seems to have extracted a file named 'pax_global_header' +from the tarball '$local_file'. +This is almost certainly an error. Please upgrade your tar. +I'll ignore this file for now. +See also http://rt.cpan.org/Ticket/Display.html?id=38932\n"); + $CPAN::Frontend->mysleep(5); + @readdir = grep { $_ ne "pax_global_header" } @readdir; + } + $dh->close; + my ($packagedir); + # XXX here we want in each branch File::Temp to protect all build_dir directories + if (CPAN->has_usable("File::Temp")) { + my $tdir_base; + my $from_dir; + my @dirents; + if (@readdir == 1 && -d $readdir[0]) { + $tdir_base = $readdir[0]; + $from_dir = File::Spec->catdir(File::Spec->curdir,$readdir[0]); + my $dh2; + unless ($dh2 = DirHandle->new($from_dir)) { + my($mode) = (stat $from_dir)[2]; + my $why = sprintf + ( + "Couldn't opendir '%s', mode '%o': %s", + $from_dir, + $mode, + $!, + ); + $CPAN::Frontend->mywarn("$why\n"); + $self->{writemakefile} = CPAN::Distrostatus->new("NO -- $why"); + return; + } + @dirents = grep $_ !~ /^\.\.?(?!\n)\Z/s, $dh2->read; ### MAC?? + } else { + my $userid = $self->cpan_userid; + CPAN->debug("userid[$userid]"); + if (!$userid or $userid eq "N/A") { + $userid = "anon"; + } + $tdir_base = $userid; + $from_dir = File::Spec->curdir; + @dirents = @readdir; + } + $packagedir = File::Temp::tempdir( + "$tdir_base-XXXXXX", + DIR => $builddir, + CLEANUP => 0, + ); + chmod 0777 &~ umask, $packagedir; # may fail + my $f; + for $f (@dirents) { # is already without "." and ".." + my $from = File::Spec->catdir($from_dir,$f); + my $to = File::Spec->catdir($packagedir,$f); + unless (File::Copy::move($from,$to)) { + my $err = $!; + $from = File::Spec->rel2abs($from); + Carp::confess("Couldn't move $from to $to: $err"); + } + } + } else { # older code below, still better than nothing when there is no File::Temp + my($distdir); + if (@readdir == 1 && -d $readdir[0]) { + $distdir = $readdir[0]; + $packagedir = File::Spec->catdir($builddir,$distdir); + $self->debug("packagedir[$packagedir]builddir[$builddir]distdir[$distdir]") + if $CPAN::DEBUG; + -d $packagedir and $CPAN::Frontend->myprint("Removing previously used ". + "$packagedir\n"); + File::Path::rmtree($packagedir); + unless (File::Copy::move($distdir,$packagedir)) { + $CPAN::Frontend->unrecoverable_error(<<EOF); +Couldn't move '$distdir' to '$packagedir': $! + +Cannot continue: Please find the reason why I cannot move +$builddir/tmp-$$/$distdir +to +$packagedir +and fix the problem, then retry + +EOF + } + $self->debug(sprintf("moved distdir[%s] to packagedir[%s] -e[%s]-d[%s]", + $distdir, + $packagedir, + -e $packagedir, + -d $packagedir, + )) if $CPAN::DEBUG; + } else { + my $userid = $self->cpan_userid; + CPAN->debug("userid[$userid]") if $CPAN::DEBUG; + if (!$userid or $userid eq "N/A") { + $userid = "anon"; + } + my $pragmatic_dir = $userid . '000'; + $pragmatic_dir =~ s/\W_//g; + $pragmatic_dir++ while -d "../$pragmatic_dir"; + $packagedir = File::Spec->catdir($builddir,$pragmatic_dir); + $self->debug("packagedir[$packagedir]") if $CPAN::DEBUG; + File::Path::mkpath($packagedir); + my($f); + for $f (@readdir) { # is already without "." and ".." + my $to = File::Spec->catdir($packagedir,$f); + File::Copy::move($f,$to) or Carp::confess("Couldn't move $f to $to: $!"); + } + } + } + $self->{build_dir} = $packagedir; + $self->safe_chdir($builddir); + File::Path::rmtree("tmp-$$"); + + $self->safe_chdir($packagedir); + $self->_signature_business(); + $self->safe_chdir($builddir); + + return($packagedir,$local_file); +} + +#-> sub CPAN::Distribution::parse_meta_yml ; +sub parse_meta_yml { + my($self, $yaml) = @_; + $self->debug(sprintf("parse_meta_yml[%s]",$yaml||'undef')) if $CPAN::DEBUG; + my $build_dir = $self->{build_dir} or die "PANIC: cannot parse yaml without a build_dir"; + $yaml ||= File::Spec->catfile($build_dir,"META.yml"); + $self->debug("meta[$yaml]") if $CPAN::DEBUG; + return unless -f $yaml; + my $early_yaml; + eval { + $CPAN::META->has_inst("Parse::CPAN::Meta") or die; + # P::C::M returns last document in scalar context + $early_yaml = Parse::CPAN::Meta::LoadFile($yaml); + }; + unless ($early_yaml) { + eval { $early_yaml = CPAN->_yaml_loadfile($yaml)->[0]; }; + } + $self->debug(sprintf("yaml[%s]", $early_yaml || 'UNDEF')) if $CPAN::DEBUG; + $self->debug($early_yaml) if $CPAN::DEBUG && $early_yaml; + return $early_yaml || undef; +} + +#-> sub CPAN::Distribution::satisfy_requires ; +sub satisfy_requires { + my ($self) = @_; + $self->debug("Entering satisfy_requires") if $CPAN::DEBUG; + if (my @prereq = $self->unsat_prereq("later")) { + $self->debug("unsatisfied[@prereq]") if $CPAN::DEBUG; + $self->debug(@prereq) if $CPAN::DEBUG && @prereq; + if ($prereq[0][0] eq "perl") { + my $need = "requires perl '$prereq[0][1]'"; + my $id = $self->pretty_id; + $CPAN::Frontend->mywarn("$id $need; you have only $]; giving up\n"); + $self->{make} = CPAN::Distrostatus->new("NO $need"); + $self->store_persistent_state; + die "[prereq] -- NOT OK\n"; + } else { + my $follow = eval { $self->follow_prereqs("later",@prereq); }; + if (0) { + } elsif ($follow) { + # signal success to the queuerunner + return 1; + } elsif ($@ && ref $@ && $@->isa("CPAN::Exception::RecursiveDependency")) { + $CPAN::Frontend->mywarn($@); + die "[depend] -- NOT OK\n"; + } + } + } + return; +} + +#-> sub CPAN::Distribution::satisfy_configure_requires ; +sub satisfy_configure_requires { + my($self) = @_; + $self->debug("Entering satisfy_configure_requires") if $CPAN::DEBUG; + my $enable_configure_requires = 1; + if (!$enable_configure_requires) { + return 1; + # if we return 1 here, everything is as before we introduced + # configure_requires that means, things with + # configure_requires simply fail, all others succeed + } + my @prereq = $self->unsat_prereq("configure_requires_later"); + $self->debug("configure_requires[@prereq]") if $CPAN::DEBUG; + return 1 unless @prereq; + $self->debug(\@prereq) if $CPAN::DEBUG; + if ($self->{configure_requires_later}) { + for my $k (keys %{$self->{configure_requires_later_for}||{}}) { + if ($self->{configure_requires_later_for}{$k}>1) { + # we must not come here a second time + $CPAN::Frontend->mywarn("Panic: Some prerequisites is not available, please investigate..."); + require YAML::Syck; + $CPAN::Frontend->mydie + ( + YAML::Syck::Dump + ({self=>$self, prereq=>\@prereq}) + ); + } + } + } + if ($prereq[0][0] eq "perl") { + my $need = "requires perl '$prereq[0][1]'"; + my $id = $self->pretty_id; + $CPAN::Frontend->mywarn("$id $need; you have only $]; giving up\n"); + $self->{make} = CPAN::Distrostatus->new("NO $need"); + $self->store_persistent_state; + return $self->goodbye("[prereq] -- NOT OK"); + } else { + my $follow = eval { + $self->follow_prereqs("configure_requires_later", @prereq); + }; + if (0) { + } elsif ($follow) { + return; + } elsif ($@ && ref $@ && $@->isa("CPAN::Exception::RecursiveDependency")) { + $CPAN::Frontend->mywarn($@); + return $self->goodbye("[depend] -- NOT OK"); + } + else { + return $self->goodbye("[configure_requires] -- NOT OK"); + } + } + die "never reached"; +} + +#-> sub CPAN::Distribution::choose_MM_or_MB ; +sub choose_MM_or_MB { + my($self,$local_file) = @_; + $self->satisfy_configure_requires() or return; + my($mpl) = File::Spec->catfile($self->{build_dir},"Makefile.PL"); + my($mpl_exists) = -f $mpl; + unless ($mpl_exists) { + # NFS has been reported to have racing problems after the + # renaming of a directory in some environments. + # This trick helps. + $CPAN::Frontend->mysleep(1); + my $mpldh = DirHandle->new($self->{build_dir}) + or Carp::croak("Couldn't opendir $self->{build_dir}: $!"); + $mpl_exists = grep /^Makefile\.PL$/, $mpldh->read; + $mpldh->close; + } + my $prefer_installer = "eumm"; # eumm|mb + if (-f File::Spec->catfile($self->{build_dir},"Build.PL")) { + if ($mpl_exists) { # they *can* choose + if ($CPAN::META->has_inst("Module::Build")) { + $prefer_installer = CPAN::HandleConfig->prefs_lookup( + $self, q{prefer_installer} + ); + # M::B <= 0.35 left a DATA handle open that + # causes problems upgrading M::B on Windows + close *Module::Build::Version::DATA + if fileno *Module::Build::Version::DATA; + } + } else { + $prefer_installer = "mb"; + } + } + return unless $self->patch; + if (lc($prefer_installer) eq "rand") { + $prefer_installer = rand()<.5 ? "eumm" : "mb"; + } + if (lc($prefer_installer) eq "mb") { + $self->{modulebuild} = 1; + } elsif ($self->{archived} eq "patch") { + # not an edge case, nothing to install for sure + my $why = "A patch file cannot be installed"; + $CPAN::Frontend->mywarn("Refusing to handle this file: $why\n"); + $self->{writemakefile} = CPAN::Distrostatus->new("NO $why"); + } elsif (! $mpl_exists) { + $self->_edge_cases($mpl,$local_file); + } + if ($self->{build_dir} + && + $CPAN::Config->{build_dir_reuse} + ) { + $self->store_persistent_state; + } + return $self; +} + +#-> CPAN::Distribution::store_persistent_state +sub store_persistent_state { + my($self) = @_; + my $dir = $self->{build_dir}; + unless (File::Spec->canonpath(File::Basename::dirname($dir)) + eq File::Spec->canonpath($CPAN::Config->{build_dir})) { + $CPAN::Frontend->mywarnonce("Directory '$dir' not below $CPAN::Config->{build_dir}, ". + "will not store persistent state\n"); + return; + } + my $file = sprintf "%s.yml", $dir; + my $yaml_module = CPAN::_yaml_module(); + if ($CPAN::META->has_inst($yaml_module)) { + CPAN->_yaml_dumpfile( + $file, + { + time => time, + perl => CPAN::_perl_fingerprint(), + distribution => $self, + } + ); + } else { + $CPAN::Frontend->myprintonce("'$yaml_module' not installed, ". + "will not store persistent state\n"); + } +} + +#-> CPAN::Distribution::try_download +sub try_download { + my($self,$patch) = @_; + my $norm = $self->normalize($patch); + my($local_wanted) = + File::Spec->catfile( + $CPAN::Config->{keep_source_where}, + "authors", + "id", + split(/\//,$norm), + ); + $self->debug("Doing localize") if $CPAN::DEBUG; + return CPAN::FTP->localize("authors/id/$norm", + $local_wanted); +} + +{ + my $stdpatchargs = ""; + #-> CPAN::Distribution::patch + sub patch { + my($self) = @_; + $self->debug("checking patches id[$self->{ID}]") if $CPAN::DEBUG; + my $patches = $self->prefs->{patches}; + $patches ||= ""; + $self->debug("patches[$patches]") if $CPAN::DEBUG; + if ($patches) { + return unless @$patches; + $self->safe_chdir($self->{build_dir}); + CPAN->debug("patches[$patches]") if $CPAN::DEBUG; + my $patchbin = $CPAN::Config->{patch}; + unless ($patchbin && length $patchbin) { + $CPAN::Frontend->mydie("No external patch command configured\n\n". + "Please run 'o conf init /patch/'\n\n"); + } + unless (MM->maybe_command($patchbin)) { + $CPAN::Frontend->mydie("No external patch command available\n\n". + "Please run 'o conf init /patch/'\n\n"); + } + $patchbin = CPAN::HandleConfig->safe_quote($patchbin); + local $ENV{PATCH_GET} = 0; # formerly known as -g0 + unless ($stdpatchargs) { + my $system = "$patchbin --version |"; + local *FH; + open FH, $system or die "Could not fork '$system': $!"; + local $/ = "\n"; + my $pversion; + PARSEVERSION: while (<FH>) { + if (/^patch\s+([\d\.]+)/) { + $pversion = $1; + last PARSEVERSION; + } + } + if ($pversion) { + $stdpatchargs = "-N --fuzz=3"; + } else { + $stdpatchargs = "-N"; + } + } + my $countedpatches = @$patches == 1 ? "1 patch" : (scalar @$patches . " patches"); + $CPAN::Frontend->myprint("Going to apply $countedpatches:\n"); + my $patches_dir = $CPAN::Config->{patches_dir}; + for my $patch (@$patches) { + if ($patches_dir && !File::Spec->file_name_is_absolute($patch)) { + my $f = File::Spec->catfile($patches_dir, $patch); + $patch = $f if -f $f; + } + unless (-f $patch) { + CPAN->debug("not on disk: patch[$patch]") if $CPAN::DEBUG; + if (my $trydl = $self->try_download($patch)) { + $patch = $trydl; + } else { + my $fail = "Could not find patch '$patch'"; + $CPAN::Frontend->mywarn("$fail; cannot continue\n"); + $self->{unwrapped} = CPAN::Distrostatus->new("NO -- $fail"); + delete $self->{build_dir}; + return; + } + } + $CPAN::Frontend->myprint(" $patch\n"); + my $readfh = CPAN::Tarzip->TIEHANDLE($patch); + + my $pcommand; + my $ppp = $self->_patch_p_parameter($readfh); + if ($ppp eq "applypatch") { + $pcommand = "$CPAN::Config->{applypatch} -verbose"; + } else { + my $thispatchargs = join " ", $stdpatchargs, $ppp; + $pcommand = "$patchbin $thispatchargs"; + } + + $readfh = CPAN::Tarzip->TIEHANDLE($patch); # open again + my $writefh = FileHandle->new; + $CPAN::Frontend->myprint(" $pcommand\n"); + unless (open $writefh, "|$pcommand") { + my $fail = "Could not fork '$pcommand'"; + $CPAN::Frontend->mywarn("$fail; cannot continue\n"); + $self->{unwrapped} = CPAN::Distrostatus->new("NO -- $fail"); + delete $self->{build_dir}; + return; + } + binmode($writefh); + while (my $x = $readfh->READLINE) { + print $writefh $x; + } + unless (close $writefh) { + my $fail = "Could not apply patch '$patch'"; + $CPAN::Frontend->mywarn("$fail; cannot continue\n"); + $self->{unwrapped} = CPAN::Distrostatus->new("NO -- $fail"); + delete $self->{build_dir}; + return; + } + } + $self->{patched}++; + } + return 1; + } +} + +sub _patch_p_parameter { + my($self,$fh) = @_; + my $cnt_files = 0; + my $cnt_p0files = 0; + local($_); + while ($_ = $fh->READLINE) { + if ( + $CPAN::Config->{applypatch} + && + /\#\#\#\# ApplyPatch data follows \#\#\#\#/ + ) { + return "applypatch" + } + next unless /^[\*\+]{3}\s(\S+)/; + my $file = $1; + $cnt_files++; + $cnt_p0files++ if -f $file; + CPAN->debug("file[$file]cnt_files[$cnt_files]cnt_p0files[$cnt_p0files]") + if $CPAN::DEBUG; + } + return "-p1" unless $cnt_files; + return $cnt_files==$cnt_p0files ? "-p0" : "-p1"; +} + +#-> sub CPAN::Distribution::_edge_cases +# with "configure" or "Makefile" or single file scripts +sub _edge_cases { + my($self,$mpl,$local_file) = @_; + $self->debug(sprintf("makefilepl[%s]anycwd[%s]", + $mpl, + CPAN::anycwd(), + )) if $CPAN::DEBUG; + my $build_dir = $self->{build_dir}; + my($configure) = File::Spec->catfile($build_dir,"Configure"); + if (-f $configure) { + # do we have anything to do? + $self->{configure} = $configure; + } elsif (-f File::Spec->catfile($build_dir,"Makefile")) { + $CPAN::Frontend->mywarn(qq{ +Package comes with a Makefile and without a Makefile.PL. +We\'ll try to build it with that Makefile then. +}); + $self->{writemakefile} = CPAN::Distrostatus->new("YES"); + $CPAN::Frontend->mysleep(2); + } else { + my $cf = $self->called_for || "unknown"; + if ($cf =~ m|/|) { + $cf =~ s|.*/||; + $cf =~ s|\W.*||; + } + $cf =~ s|[/\\:]||g; # risk of filesystem damage + $cf = "unknown" unless length($cf); + if (my $crud = $self->_contains_crud($build_dir)) { + my $why = qq{Package contains $crud; not recognized as a perl package, giving up}; + $CPAN::Frontend->mywarn("$why\n"); + $self->{writemakefile} = CPAN::Distrostatus->new(qq{NO -- $why}); + return; + } + $CPAN::Frontend->mywarn(qq{Package seems to come without Makefile.PL. + (The test -f "$mpl" returned false.) + Writing one on our own (setting NAME to $cf)\a\n}); + $self->{had_no_makefile_pl}++; + $CPAN::Frontend->mysleep(3); + + # Writing our own Makefile.PL + + my $exefile_stanza = ""; + if ($self->{archived} eq "maybe_pl") { + $exefile_stanza = $self->_exefile_stanza($build_dir,$local_file); + } + + my $fh = FileHandle->new; + $fh->open(">$mpl") + or Carp::croak("Could not open >$mpl: $!"); + $fh->print( + qq{# This Makefile.PL has been autogenerated by the module CPAN.pm +# because there was no Makefile.PL supplied. +# Autogenerated on: }.scalar localtime().qq{ + +use ExtUtils::MakeMaker; +WriteMakefile( + NAME => q[$cf],$exefile_stanza + ); +}); + $fh->close; + } +} + +#-> CPAN;:Distribution::_contains_crud +sub _contains_crud { + my($self,$dir) = @_; + my(@dirs, $dh, @files); + opendir $dh, $dir or return; + my $dirent; + for $dirent (readdir $dh) { + next if $dirent =~ /^\.\.?$/; + my $path = File::Spec->catdir($dir,$dirent); + if (-d $path) { + push @dirs, $dirent; + } elsif (-f $path) { + push @files, $dirent; + } + } + if (@dirs && @files) { + return "both files[@files] and directories[@dirs]"; + } elsif (@files > 2) { + return "several files[@files] but no Makefile.PL or Build.PL"; + } + return; +} + +#-> CPAN;:Distribution::_exefile_stanza +sub _exefile_stanza { + my($self,$build_dir,$local_file) = @_; + + my $fh = FileHandle->new; + my $script_file = File::Spec->catfile($build_dir,$local_file); + $fh->open($script_file) + or Carp::croak("Could not open script '$script_file': $!"); + local $/ = "\n"; + # name parsen und prereq + my($state) = "poddir"; + my($name, $prereq) = ("", ""); + while (<$fh>) { + if ($state eq "poddir" && /^=head\d\s+(\S+)/) { + if ($1 eq 'NAME') { + $state = "name"; + } elsif ($1 eq 'PREREQUISITES') { + $state = "prereq"; + } + } elsif ($state =~ m{^(name|prereq)$}) { + if (/^=/) { + $state = "poddir"; + } elsif (/^\s*$/) { + # nop + } elsif ($state eq "name") { + if ($name eq "") { + ($name) = /^(\S+)/; + $state = "poddir"; + } + } elsif ($state eq "prereq") { + $prereq .= $_; + } + } elsif (/^=cut\b/) { + last; + } + } + $fh->close; + + for ($name) { + s{.*<}{}; # strip X<...> + s{>.*}{}; + } + chomp $prereq; + $prereq = join " ", split /\s+/, $prereq; + my($PREREQ_PM) = join("\n", map { + s{.*<}{}; # strip X<...> + s{>.*}{}; + if (/[\s\'\"]/) { # prose? + } else { + s/[^\w:]$//; # period? + " "x28 . "'$_' => 0,"; + } + } split /\s*,\s*/, $prereq); + + if ($name) { + my $to_file = File::Spec->catfile($build_dir, $name); + rename $script_file, $to_file + or die "Can't rename $script_file to $to_file: $!"; + } + + return " + EXE_FILES => ['$name'], + PREREQ_PM => { +$PREREQ_PM + }, +"; +} + +#-> CPAN::Distribution::_signature_business +sub _signature_business { + my($self) = @_; + my $check_sigs = CPAN::HandleConfig->prefs_lookup($self, + q{check_sigs}); + if ($check_sigs) { + if ($CPAN::META->has_inst("Module::Signature")) { + if (-f "SIGNATURE") { + $self->debug("Module::Signature is installed, verifying") if $CPAN::DEBUG; + my $rv = Module::Signature::verify(); + if ($rv != Module::Signature::SIGNATURE_OK() and + $rv != Module::Signature::SIGNATURE_MISSING()) { + $CPAN::Frontend->mywarn( + qq{\nSignature invalid for }. + qq{distribution file. }. + qq{Please investigate.\n\n} + ); + + my $wrap = + sprintf(qq{I'd recommend removing %s. Some error occurred }. + qq{while checking its signature, so it could }. + qq{be invalid. Maybe you have configured }. + qq{your 'urllist' with a bad URL. Please check this }. + qq{array with 'o conf urllist' and retry. Or }. + qq{examine the distribution in a subshell. Try + look %s +and run + cpansign -v +}, + $self->{localfile}, + $self->pretty_id, + ); + $self->{signature_verify} = CPAN::Distrostatus->new("NO"); + $CPAN::Frontend->mywarn(Text::Wrap::wrap("","",$wrap)); + $CPAN::Frontend->mysleep(5) if $CPAN::Frontend->can("mysleep"); + } else { + $self->{signature_verify} = CPAN::Distrostatus->new("YES"); + $self->debug("Module::Signature has verified") if $CPAN::DEBUG; + } + } else { + $CPAN::Frontend->mywarn(qq{Package came without SIGNATURE\n\n}); + } + } else { + $self->debug("Module::Signature is NOT installed") if $CPAN::DEBUG; + } + } +} + +#-> CPAN::Distribution::untar_me ; +sub untar_me { + my($self,$ct) = @_; + $self->{archived} = "tar"; + my $result = eval { $ct->untar() }; + if ($result) { + $self->{unwrapped} = CPAN::Distrostatus->new("YES"); + } else { + $self->{unwrapped} = CPAN::Distrostatus->new("NO -- untar failed"); + } +} + +# CPAN::Distribution::unzip_me ; +sub unzip_me { + my($self,$ct) = @_; + $self->{archived} = "zip"; + if ($ct->unzip()) { + $self->{unwrapped} = CPAN::Distrostatus->new("YES"); + } else { + $self->{unwrapped} = CPAN::Distrostatus->new("NO -- unzip failed"); + } + return; +} + +sub handle_singlefile { + my($self,$local_file) = @_; + + if ( $local_file =~ /\.pm(\.(gz|Z))?(?!\n)\Z/ ) { + $self->{archived} = "pm"; + } elsif ( $local_file =~ /\.patch(\.(gz|bz2))?(?!\n)\Z/ ) { + $self->{archived} = "patch"; + } else { + $self->{archived} = "maybe_pl"; + } + + my $to = File::Basename::basename($local_file); + if ($to =~ s/\.(gz|Z)(?!\n)\Z//) { + if (eval{CPAN::Tarzip->new($local_file)->gunzip($to)}) { + $self->{unwrapped} = CPAN::Distrostatus->new("YES"); + } else { + $self->{unwrapped} = CPAN::Distrostatus->new("NO -- uncompressing failed"); + } + } else { + if (File::Copy::cp($local_file,".")) { + $self->{unwrapped} = CPAN::Distrostatus->new("YES"); + } else { + $self->{unwrapped} = CPAN::Distrostatus->new("NO -- copying failed"); + } + } + return $to; +} + +#-> sub CPAN::Distribution::new ; +sub new { + my($class,%att) = @_; + + # $CPAN::META->{cachemgr} ||= CPAN::CacheMgr->new(); + + my $this = { %att }; + return bless $this, $class; +} + +#-> sub CPAN::Distribution::look ; +sub look { + my($self) = @_; + + if ($^O eq 'MacOS') { + $self->Mac::BuildTools::look; + return; + } + + if ( $CPAN::Config->{'shell'} ) { + $CPAN::Frontend->myprint(qq{ +Trying to open a subshell in the build directory... +}); + } else { + $CPAN::Frontend->myprint(qq{ +Your configuration does not define a value for subshells. +Please define it with "o conf shell <your shell>" +}); + return; + } + my $dist = $self->id; + my $dir; + unless ($dir = $self->dir) { + $self->get; + } + unless ($dir ||= $self->dir) { + $CPAN::Frontend->mywarn(qq{ +Could not determine which directory to use for looking at $dist. +}); + return; + } + my $pwd = CPAN::anycwd(); + $self->safe_chdir($dir); + $CPAN::Frontend->myprint(qq{Working directory is $dir\n}); + { + local $ENV{CPAN_SHELL_LEVEL} = $ENV{CPAN_SHELL_LEVEL}||0; + $ENV{CPAN_SHELL_LEVEL} += 1; + my $shell = CPAN::HandleConfig->safe_quote($CPAN::Config->{'shell'}); + + local $ENV{PERL5LIB} = defined($ENV{PERL5LIB}) + ? $ENV{PERL5LIB} + : ($ENV{PERLLIB} || ""); + + local $ENV{PERL5OPT} = defined $ENV{PERL5OPT} ? $ENV{PERL5OPT} : ""; + $CPAN::META->set_perl5lib; + local $ENV{MAKEFLAGS}; # protect us from outer make calls + + unless (system($shell) == 0) { + my $code = $? >> 8; + $CPAN::Frontend->mywarn("Subprocess shell exit code $code\n"); + } + } + $self->safe_chdir($pwd); +} + +# CPAN::Distribution::cvs_import ; +sub cvs_import { + my($self) = @_; + $self->get; + my $dir = $self->dir; + + my $package = $self->called_for; + my $module = $CPAN::META->instance('CPAN::Module', $package); + my $version = $module->cpan_version; + + my $userid = $self->cpan_userid; + + my $cvs_dir = (split /\//, $dir)[-1]; + $cvs_dir =~ s/-\d+[^-]+(?!\n)\Z//; + my $cvs_root = + $CPAN::Config->{cvsroot} || $ENV{CVSROOT}; + my $cvs_site_perl = + $CPAN::Config->{cvs_site_perl} || $ENV{CVS_SITE_PERL}; + if ($cvs_site_perl) { + $cvs_dir = "$cvs_site_perl/$cvs_dir"; + } + my $cvs_log = qq{"imported $package $version sources"}; + $version =~ s/\./_/g; + # XXX cvs: undocumented and unclear how it was meant to work + my @cmd = ('cvs', '-d', $cvs_root, 'import', '-m', $cvs_log, + "$cvs_dir", $userid, "v$version"); + + my $pwd = CPAN::anycwd(); + chdir($dir) or $CPAN::Frontend->mydie(qq{Could not chdir to "$dir": $!}); + + $CPAN::Frontend->myprint(qq{Working directory is $dir\n}); + + $CPAN::Frontend->myprint(qq{@cmd\n}); + system(@cmd) == 0 or + # XXX cvs + $CPAN::Frontend->mydie("cvs import failed"); + chdir($pwd) or $CPAN::Frontend->mydie(qq{Could not chdir to "$pwd": $!}); +} + +#-> sub CPAN::Distribution::readme ; +sub readme { + my($self) = @_; + my($dist) = $self->id; + my($sans,$suffix) = $dist =~ /(.+)\.(tgz|tar[\._-]gz|tar\.Z|zip)$/; + $self->debug("sans[$sans] suffix[$suffix]\n") if $CPAN::DEBUG; + my($local_file); + my($local_wanted) = + File::Spec->catfile( + $CPAN::Config->{keep_source_where}, + "authors", + "id", + split(/\//,"$sans.readme"), + ); + my $readme = "authors/id/$sans.readme"; + $self->debug("Doing localize for '$readme'") if $CPAN::DEBUG; + $local_file = CPAN::FTP->localize($readme, + $local_wanted) + or $CPAN::Frontend->mydie(qq{No $sans.readme found}); + + if ($^O eq 'MacOS') { + Mac::BuildTools::launch_file($local_file); + return; + } + + my $fh_pager = FileHandle->new; + local($SIG{PIPE}) = "IGNORE"; + my $pager = $CPAN::Config->{'pager'} || "cat"; + $fh_pager->open("|$pager") + or die "Could not open pager $pager\: $!"; + my $fh_readme = FileHandle->new; + $fh_readme->open($local_file) + or $CPAN::Frontend->mydie(qq{Could not open "$local_file": $!}); + $CPAN::Frontend->myprint(qq{ +Displaying file + $local_file +with pager "$pager" +}); + $fh_pager->print(<$fh_readme>); + $fh_pager->close; +} + +#-> sub CPAN::Distribution::verifyCHECKSUM ; +sub verifyCHECKSUM { + my($self) = @_; + EXCUSE: { + my @e; + $self->{CHECKSUM_STATUS} ||= ""; + $self->{CHECKSUM_STATUS} eq "OK" and push @e, "Checksum was ok"; + $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e; + } + my($lc_want,$lc_file,@local,$basename); + @local = split(/\//,$self->id); + pop @local; + push @local, "CHECKSUMS"; + $lc_want = + File::Spec->catfile($CPAN::Config->{keep_source_where}, + "authors", "id", @local); + local($") = "/"; + if (my $size = -s $lc_want) { + $self->debug("lc_want[$lc_want]size[$size]") if $CPAN::DEBUG; + if ($self->CHECKSUM_check_file($lc_want,1)) { + return $self->{CHECKSUM_STATUS} = "OK"; + } + } + $lc_file = CPAN::FTP->localize("authors/id/@local", + $lc_want,1); + unless ($lc_file) { + $CPAN::Frontend->myprint("Trying $lc_want.gz\n"); + $local[-1] .= ".gz"; + $lc_file = CPAN::FTP->localize("authors/id/@local", + "$lc_want.gz",1); + if ($lc_file) { + $lc_file =~ s/\.gz(?!\n)\Z//; + eval{CPAN::Tarzip->new("$lc_file.gz")->gunzip($lc_file)}; + } else { + return; + } + } + if ($self->CHECKSUM_check_file($lc_file)) { + return $self->{CHECKSUM_STATUS} = "OK"; + } +} + +#-> sub CPAN::Distribution::SIG_check_file ; +sub SIG_check_file { + my($self,$chk_file) = @_; + my $rv = eval { Module::Signature::_verify($chk_file) }; + + if ($rv == Module::Signature::SIGNATURE_OK()) { + $CPAN::Frontend->myprint("Signature for $chk_file ok\n"); + return $self->{SIG_STATUS} = "OK"; + } else { + $CPAN::Frontend->myprint(qq{\nSignature invalid for }. + qq{distribution file. }. + qq{Please investigate.\n\n}. + $self->as_string, + $CPAN::META->instance( + 'CPAN::Author', + $self->cpan_userid + )->as_string); + + my $wrap = qq{I\'d recommend removing $chk_file. Its signature +is invalid. Maybe you have configured your 'urllist' with +a bad URL. Please check this array with 'o conf urllist', and +retry.}; + + $CPAN::Frontend->mydie(Text::Wrap::wrap("","",$wrap)); + } +} + +#-> sub CPAN::Distribution::CHECKSUM_check_file ; + +# sloppy is 1 when we have an old checksums file that maybe is good +# enough + +sub CHECKSUM_check_file { + my($self,$chk_file,$sloppy) = @_; + my($cksum,$file,$basename); + + $sloppy ||= 0; + $self->debug("chk_file[$chk_file]sloppy[$sloppy]") if $CPAN::DEBUG; + my $check_sigs = CPAN::HandleConfig->prefs_lookup($self, + q{check_sigs}); + if ($check_sigs) { + if ($CPAN::META->has_inst("Module::Signature")) { + $self->debug("Module::Signature is installed, verifying") if $CPAN::DEBUG; + $self->SIG_check_file($chk_file); + } else { + $self->debug("Module::Signature is NOT installed") if $CPAN::DEBUG; + } + } + + $file = $self->{localfile}; + $basename = File::Basename::basename($file); + my $fh = FileHandle->new; + if (open $fh, $chk_file) { + local($/); + my $eval = <$fh>; + $eval =~ s/\015?\012/\n/g; + close $fh; + my($compmt) = Safe->new(); + $cksum = $compmt->reval($eval); + if ($@) { + rename $chk_file, "$chk_file.bad"; + Carp::confess($@) if $@; + } + } else { + Carp::carp "Could not open $chk_file for reading"; + } + + if (! ref $cksum or ref $cksum ne "HASH") { + $CPAN::Frontend->mywarn(qq{ +Warning: checksum file '$chk_file' broken. + +When trying to read that file I expected to get a hash reference +for further processing, but got garbage instead. +}); + my $answer = CPAN::Shell::colorable_makemaker_prompt("Proceed nonetheless?", "no"); + $answer =~ /^\s*y/i or $CPAN::Frontend->mydie("Aborted.\n"); + $self->{CHECKSUM_STATUS} = "NIL -- CHECKSUMS file broken"; + return; + } elsif (exists $cksum->{$basename}{sha256}) { + $self->debug("Found checksum for $basename:" . + "$cksum->{$basename}{sha256}\n") if $CPAN::DEBUG; + + open($fh, $file); + binmode $fh; + my $eq = $self->eq_CHECKSUM($fh,$cksum->{$basename}{sha256}); + $fh->close; + $fh = CPAN::Tarzip->TIEHANDLE($file); + + unless ($eq) { + my $dg = Digest::SHA->new(256); + my($data,$ref); + $ref = \$data; + while ($fh->READ($ref, 4096) > 0) { + $dg->add($data); + } + my $hexdigest = $dg->hexdigest; + $eq += $hexdigest eq $cksum->{$basename}{'sha256-ungz'}; + } + + if ($eq) { + $CPAN::Frontend->myprint("Checksum for $file ok\n"); + return $self->{CHECKSUM_STATUS} = "OK"; + } else { + $CPAN::Frontend->myprint(qq{\nChecksum mismatch for }. + qq{distribution file. }. + qq{Please investigate.\n\n}. + $self->as_string, + $CPAN::META->instance( + 'CPAN::Author', + $self->cpan_userid + )->as_string); + + my $wrap = qq{I\'d recommend removing $file. Its +checksum is incorrect. Maybe you have configured your 'urllist' with +a bad URL. Please check this array with 'o conf urllist', and +retry.}; + + $CPAN::Frontend->mydie(Text::Wrap::wrap("","",$wrap)); + + # former versions just returned here but this seems a + # serious threat that deserves a die + + # $CPAN::Frontend->myprint("\n\n"); + # sleep 3; + # return; + } + # close $fh if fileno($fh); + } else { + return if $sloppy; + unless ($self->{CHECKSUM_STATUS}) { + $CPAN::Frontend->mywarn(qq{ +Warning: No checksum for $basename in $chk_file. + +The cause for this may be that the file is very new and the checksum +has not yet been calculated, but it may also be that something is +going awry right now. +}); + my $answer = CPAN::Shell::colorable_makemaker_prompt("Proceed?", "yes"); + $answer =~ /^\s*y/i or $CPAN::Frontend->mydie("Aborted.\n"); + } + $self->{CHECKSUM_STATUS} = "NIL -- distro not in CHECKSUMS file"; + return; + } +} + +#-> sub CPAN::Distribution::eq_CHECKSUM ; +sub eq_CHECKSUM { + my($self,$fh,$expect) = @_; + if ($CPAN::META->has_inst("Digest::SHA")) { + my $dg = Digest::SHA->new(256); + my($data); + while (read($fh, $data, 4096)) { + $dg->add($data); + } + my $hexdigest = $dg->hexdigest; + # warn "fh[$fh] hex[$hexdigest] aexp[$expectMD5]"; + return $hexdigest eq $expect; + } + return 1; +} + +#-> sub CPAN::Distribution::force ; + +# Both CPAN::Modules and CPAN::Distributions know if "force" is in +# effect by autoinspection, not by inspecting a global variable. One +# of the reason why this was chosen to work that way was the treatment +# of dependencies. They should not automatically inherit the force +# status. But this has the downside that ^C and die() will return to +# the prompt but will not be able to reset the force_update +# attributes. We try to correct for it currently in the read_metadata +# routine, and immediately before we check for a Signal. I hope this +# works out in one of v1.57_53ff + +# "Force get forgets previous error conditions" + +#-> sub CPAN::Distribution::fforce ; +sub fforce { + my($self, $method) = @_; + $self->force($method,1); +} + +#-> sub CPAN::Distribution::force ; +sub force { + my($self, $method,$fforce) = @_; + my %phase_map = ( + get => [ + "unwrapped", + "build_dir", + "archived", + "localfile", + "CHECKSUM_STATUS", + "signature_verify", + "prefs", + "prefs_file", + "prefs_file_doc", + ], + make => [ + "writemakefile", + "make", + "modulebuild", + "prereq_pm", + ], + test => [ + "badtestcnt", + "make_test", + ], + install => [ + "install", + ], + unknown => [ + "reqtype", + "yaml_content", + ], + ); + my $methodmatch = 0; + my $ldebug = 0; + PHASE: for my $phase (qw(unknown get make test install)) { # order matters + $methodmatch = 1 if $fforce || $phase eq $method; + next unless $methodmatch; + ATTRIBUTE: for my $att (@{$phase_map{$phase}}) { + if ($phase eq "get") { + if (substr($self->id,-1,1) eq "." + && $att =~ /(unwrapped|build_dir|archived)/ ) { + # cannot be undone for local distros + next ATTRIBUTE; + } + if ($att eq "build_dir" + && $self->{build_dir} + && $CPAN::META->{is_tested} + ) { + delete $CPAN::META->{is_tested}{$self->{build_dir}}; + } + } elsif ($phase eq "test") { + if ($att eq "make_test" + && $self->{make_test} + && $self->{make_test}{COMMANDID} + && $self->{make_test}{COMMANDID} == $CPAN::CurrentCommandId + ) { + # endless loop too likely + next ATTRIBUTE; + } + } + delete $self->{$att}; + if ($ldebug || $CPAN::DEBUG) { + # local $CPAN::DEBUG = 16; # Distribution + CPAN->debug(sprintf "id[%s]phase[%s]att[%s]", $self->id, $phase, $att); + } + } + } + if ($method && $method =~ /make|test|install/) { + $self->{force_update} = 1; # name should probably have been force_install + } +} + +#-> sub CPAN::Distribution::notest ; +sub notest { + my($self, $method) = @_; + # $CPAN::Frontend->mywarn("XDEBUG: set notest for $self $method"); + $self->{"notest"}++; # name should probably have been force_install +} + +#-> sub CPAN::Distribution::unnotest ; +sub unnotest { + my($self) = @_; + # warn "XDEBUG: deleting notest"; + delete $self->{notest}; +} + +#-> sub CPAN::Distribution::unforce ; +sub unforce { + my($self) = @_; + delete $self->{force_update}; +} + +#-> sub CPAN::Distribution::isa_perl ; +sub isa_perl { + my($self) = @_; + my $file = File::Basename::basename($self->id); + if ($file =~ m{ ^ perl + -? + (5) + ([._-]) + ( + \d{3}(_[0-4][0-9])? + | + \d+\.\d+ + ) + \.tar[._-](?:gz|bz2) + (?!\n)\Z + }xs) { + return "$1.$3"; + } elsif ($self->cpan_comment + && + $self->cpan_comment =~ /isa_perl\(.+?\)/) { + return $1; + } +} + + +#-> sub CPAN::Distribution::perl ; +sub perl { + my ($self) = @_; + if (! $self) { + use Carp qw(carp); + carp __PACKAGE__ . "::perl was called without parameters."; + } + return CPAN::HandleConfig->safe_quote($CPAN::Perl); +} + + +#-> sub CPAN::Distribution::make ; +sub make { + my($self) = @_; + if (my $goto = $self->prefs->{goto}) { + return $self->goto($goto); + } + my $make = $self->{modulebuild} ? "Build" : "make"; + # Emergency brake if they said install Pippi and get newest perl + if ($self->isa_perl) { + if ( + $self->called_for ne $self->id && + ! $self->{force_update} + ) { + # if we die here, we break bundles + $CPAN::Frontend + ->mywarn(sprintf( + qq{The most recent version "%s" of the module "%s" +is part of the perl-%s distribution. To install that, you need to run + force install %s --or-- + install %s +}, + $CPAN::META->instance( + 'CPAN::Module', + $self->called_for + )->cpan_version, + $self->called_for, + $self->isa_perl, + $self->called_for, + $self->id, + )); + $self->{make} = CPAN::Distrostatus->new("NO isa perl"); + $CPAN::Frontend->mysleep(1); + return; + } + } + $CPAN::Frontend->myprint(sprintf "Running %s for %s\n", $make, $self->id); + $self->get; + return if $self->prefs->{disabled} && ! $self->{force_update}; + if ($self->{configure_requires_later}) { + return; + } + local $ENV{PERL5LIB} = defined($ENV{PERL5LIB}) + ? $ENV{PERL5LIB} + : ($ENV{PERLLIB} || ""); + local $ENV{PERL5OPT} = defined $ENV{PERL5OPT} ? $ENV{PERL5OPT} : ""; + $CPAN::META->set_perl5lib; + local $ENV{MAKEFLAGS}; # protect us from outer make calls + + if ($CPAN::Signal) { + delete $self->{force_update}; + return; + } + + my $builddir; + EXCUSE: { + my @e; + if (!$self->{archived} || $self->{archived} eq "NO") { + push @e, "Is neither a tar nor a zip archive."; + } + + if (!$self->{unwrapped} + || ( + UNIVERSAL::can($self->{unwrapped},"failed") ? + $self->{unwrapped}->failed : + $self->{unwrapped} =~ /^NO/ + )) { + push @e, "Had problems unarchiving. Please build manually"; + } + + unless ($self->{force_update}) { + exists $self->{signature_verify} and + ( + UNIVERSAL::can($self->{signature_verify},"failed") ? + $self->{signature_verify}->failed : + $self->{signature_verify} =~ /^NO/ + ) + and push @e, "Did not pass the signature test."; + } + + if (exists $self->{writemakefile} && + ( + UNIVERSAL::can($self->{writemakefile},"failed") ? + $self->{writemakefile}->failed : + $self->{writemakefile} =~ /^NO/ + )) { + # XXX maybe a retry would be in order? + my $err = UNIVERSAL::can($self->{writemakefile},"text") ? + $self->{writemakefile}->text : + $self->{writemakefile}; + $err =~ s/^NO\s*(--\s+)?//; + $err ||= "Had some problem writing Makefile"; + $err .= ", won't make"; + push @e, $err; + } + + if (defined $self->{make}) { + if (UNIVERSAL::can($self->{make},"failed") ? + $self->{make}->failed : + $self->{make} =~ /^NO/) { + if ($self->{force_update}) { + # Trying an already failed 'make' (unless somebody else blocks) + } else { + # introduced for turning recursion detection into a distrostatus + my $error = length $self->{make}>3 + ? substr($self->{make},3) : "Unknown error"; + $CPAN::Frontend->mywarn("Could not make: $error\n"); + $self->store_persistent_state; + return; + } + } else { + push @e, "Has already been made"; + my $wait_for_prereqs = eval { $self->satisfy_requires }; + return 1 if $wait_for_prereqs; # tells queuerunner to continue + return $self->goodbye($@) if $@; # tells queuerunner to stop + } + } + + my $later = $self->{later} || $self->{configure_requires_later}; + if ($later) { # see also undelay + if ($later) { + push @e, $later; + } + } + + $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e; + $builddir = $self->dir or + $CPAN::Frontend->mydie("PANIC: Cannot determine build directory\n"); + unless (chdir $builddir) { + push @e, "Couldn't chdir to '$builddir': $!"; + } + $CPAN::Frontend->mywarn(join "", map {" $_\n"} @e) and return if @e; + } + if ($CPAN::Signal) { + delete $self->{force_update}; + return; + } + $CPAN::Frontend->myprint("\n CPAN.pm: Going to build ".$self->id."\n\n"); + $self->debug("Changed directory to $builddir") if $CPAN::DEBUG; + + if ($^O eq 'MacOS') { + Mac::BuildTools::make($self); + return; + } + + my %env; + while (my($k,$v) = each %ENV) { + next unless defined $v; + $env{$k} = $v; + } + local %ENV = %env; + if ($CPAN::Config->{prerequisites_policy} eq "follow") { + $ENV{PERL_AUTOINSTALL} ||= "--defaultdeps"; + $ENV{PERL_EXTUTILS_AUTOINSTALL} ||= "--defaultdeps"; + } + my $system; + my $pl_commandline; + if ($self->prefs->{pl}) { + $pl_commandline = $self->prefs->{pl}{commandline}; + } + if ($pl_commandline) { + $system = $pl_commandline; + $ENV{PERL} = $^X; + } elsif ($self->{'configure'}) { + $system = $self->{'configure'}; + } elsif ($self->{modulebuild}) { + my($perl) = $self->perl or die "Couldn\'t find executable perl\n"; + $system = "$perl Build.PL $CPAN::Config->{mbuildpl_arg}"; + } else { + my($perl) = $self->perl or die "Couldn\'t find executable perl\n"; + my $switch = ""; +# This needs a handler that can be turned on or off: +# $switch = "-MExtUtils::MakeMaker ". +# "-Mops=:default,:filesys_read,:filesys_open,require,chdir" +# if $] > 5.00310; + my $makepl_arg = $self->_make_phase_arg("pl"); + $ENV{PERL5_CPAN_IS_EXECUTING} = File::Spec->catfile($self->{build_dir}, + "Makefile.PL"); + $system = sprintf("%s%s Makefile.PL%s", + $perl, + $switch ? " $switch" : "", + $makepl_arg ? " $makepl_arg" : "", + ); + } + my $pl_env; + if ($self->prefs->{pl}) { + $pl_env = $self->prefs->{pl}{env}; + } + if ($pl_env) { + for my $e (keys %$pl_env) { + $ENV{$e} = $pl_env->{$e}; + } + } + if (exists $self->{writemakefile}) { + } else { + local($SIG{ALRM}) = sub { die "inactivity_timeout reached\n" }; + my($ret,$pid,$output); + $@ = ""; + my $go_via_alarm; + if ($CPAN::Config->{inactivity_timeout}) { + require Config; + if ($Config::Config{d_alarm} + && + $Config::Config{d_alarm} eq "define" + ) { + $go_via_alarm++ + } else { + $CPAN::Frontend->mywarn("Warning: you have configured the config ". + "variable 'inactivity_timeout' to ". + "'$CPAN::Config->{inactivity_timeout}'. But ". + "on this machine the system call 'alarm' ". + "isn't available. This means that we cannot ". + "provide the feature of intercepting long ". + "waiting code and will turn this feature off.\n" + ); + $CPAN::Config->{inactivity_timeout} = 0; + } + } + if ($go_via_alarm) { + if ( $self->_should_report('pl') ) { + ($output, $ret) = CPAN::Reporter::record_command( + $system, + $CPAN::Config->{inactivity_timeout}, + ); + CPAN::Reporter::grade_PL( $self, $system, $output, $ret ); + } + else { + eval { + alarm $CPAN::Config->{inactivity_timeout}; + local $SIG{CHLD}; # = sub { wait }; + if (defined($pid = fork)) { + if ($pid) { #parent + # wait; + waitpid $pid, 0; + } else { #child + # note, this exec isn't necessary if + # inactivity_timeout is 0. On the Mac I'd + # suggest, we set it always to 0. + exec $system; + } + } else { + $CPAN::Frontend->myprint("Cannot fork: $!"); + return; + } + }; + alarm 0; + if ($@) { + kill 9, $pid; + waitpid $pid, 0; + my $err = "$@"; + $CPAN::Frontend->myprint($err); + $self->{writemakefile} = CPAN::Distrostatus->new("NO $err"); + $@ = ""; + $self->store_persistent_state; + return $self->goodbye("$system -- TIMED OUT"); + } + } + } else { + if (my $expect_model = $self->_prefs_with_expect("pl")) { + # XXX probably want to check _should_report here and warn + # about not being able to use CPAN::Reporter with expect + $ret = $self->_run_via_expect($system,'writemakefile',$expect_model); + if (! defined $ret + && $self->{writemakefile} + && $self->{writemakefile}->failed) { + # timeout + return; + } + } + elsif ( $self->_should_report('pl') ) { + ($output, $ret) = CPAN::Reporter::record_command($system); + CPAN::Reporter::grade_PL( $self, $system, $output, $ret ); + } + else { + $ret = system($system); + } + if ($ret != 0) { + $self->{writemakefile} = CPAN::Distrostatus + ->new("NO '$system' returned status $ret"); + $CPAN::Frontend->mywarn("Warning: No success on command[$system]\n"); + $self->store_persistent_state; + return $self->goodbye("$system -- NOT OK"); + } + } + if (-f "Makefile" || -f "Build") { + $self->{writemakefile} = CPAN::Distrostatus->new("YES"); + delete $self->{make_clean}; # if cleaned before, enable next + } else { + my $makefile = $self->{modulebuild} ? "Build" : "Makefile"; + my $why = "No '$makefile' created"; + $CPAN::Frontend->mywarn($why); + $self->{writemakefile} = CPAN::Distrostatus + ->new(qq{NO -- $why\n}); + $self->store_persistent_state; + return $self->goodbye("$system -- NOT OK"); + } + } + if ($CPAN::Signal) { + delete $self->{force_update}; + return; + } + my $wait_for_prereqs = eval { $self->satisfy_requires }; + return 1 if $wait_for_prereqs; # tells queuerunner to continue + return $self->goodbye($@) if $@; # tells queuerunner to stop + if ($CPAN::Signal) { + delete $self->{force_update}; + return; + } + my $make_commandline; + if ($self->prefs->{make}) { + $make_commandline = $self->prefs->{make}{commandline}; + } + if ($make_commandline) { + $system = $make_commandline; + $ENV{PERL} = CPAN::find_perl(); + } else { + if ($self->{modulebuild}) { + unless (-f "Build") { + my $cwd = CPAN::anycwd(); + $CPAN::Frontend->mywarn("Alert: no Build file available for 'make $self->{id}'". + " in cwd[$cwd]. Danger, Will Robinson!\n"); + $CPAN::Frontend->mysleep(5); + } + $system = join " ", $self->_build_command(), $CPAN::Config->{mbuild_arg}; + } else { + $system = join " ", $self->_make_command(), $CPAN::Config->{make_arg}; + } + $system =~ s/\s+$//; + my $make_arg = $self->_make_phase_arg("make"); + $system = sprintf("%s%s", + $system, + $make_arg ? " $make_arg" : "", + ); + } + my $make_env; + if ($self->prefs->{make}) { + $make_env = $self->prefs->{make}{env}; + } + if ($make_env) { # overriding the local ENV of PL, not the outer + # ENV, but unlikely to be a risk + for my $e (keys %$make_env) { + $ENV{$e} = $make_env->{$e}; + } + } + my $expect_model = $self->_prefs_with_expect("make"); + my $want_expect = 0; + if ( $expect_model && @{$expect_model->{talk}} ) { + my $can_expect = $CPAN::META->has_inst("Expect"); + if ($can_expect) { + $want_expect = 1; + } else { + $CPAN::Frontend->mywarn("Expect not installed, falling back to ". + "system()\n"); + } + } + my $system_ok; + if ($want_expect) { + # XXX probably want to check _should_report here and + # warn about not being able to use CPAN::Reporter with expect + $system_ok = $self->_run_via_expect($system,'make',$expect_model) == 0; + } + elsif ( $self->_should_report('make') ) { + my ($output, $ret) = CPAN::Reporter::record_command($system); + CPAN::Reporter::grade_make( $self, $system, $output, $ret ); + $system_ok = ! $ret; + } + else { + $system_ok = system($system) == 0; + } + $self->introduce_myself; + if ( $system_ok ) { + $CPAN::Frontend->myprint(" $system -- OK\n"); + $self->{make} = CPAN::Distrostatus->new("YES"); + } else { + $self->{writemakefile} ||= CPAN::Distrostatus->new("YES"); + $self->{make} = CPAN::Distrostatus->new("NO"); + $CPAN::Frontend->mywarn(" $system -- NOT OK\n"); + } + $self->store_persistent_state; +} + +# CPAN::Distribution::goodbye ; +sub goodbye { + my($self,$goodbye) = @_; + my $id = $self->pretty_id; + $CPAN::Frontend->mywarn(" $id\n $goodbye\n"); + return; +} + +# CPAN::Distribution::_run_via_expect ; +sub _run_via_expect { + my($self,$system,$phase,$expect_model) = @_; + CPAN->debug("system[$system]expect_model[$expect_model]") if $CPAN::DEBUG; + if ($CPAN::META->has_inst("Expect")) { + my $expo = Expect->new; # expo Expect object; + $expo->spawn($system); + $expect_model->{mode} ||= "deterministic"; + if ($expect_model->{mode} eq "deterministic") { + return $self->_run_via_expect_deterministic($expo,$phase,$expect_model); + } elsif ($expect_model->{mode} eq "anyorder") { + return $self->_run_via_expect_anyorder($expo,$phase,$expect_model); + } else { + die "Panic: Illegal expect mode: $expect_model->{mode}"; + } + } else { + $CPAN::Frontend->mywarn("Expect not installed, falling back to system()\n"); + return system($system); + } +} + +sub _run_via_expect_anyorder { + my($self,$expo,$phase,$expect_model) = @_; + my $timeout = $expect_model->{timeout} || 5; + my $reuse = $expect_model->{reuse}; + my @expectacopy = @{$expect_model->{talk}}; # we trash it! + my $but = ""; + my $timeout_start = time; + EXPECT: while () { + my($eof,$ran_into_timeout); + # XXX not up to the full power of expect. one could certainly + # wrap all of the talk pairs into a single expect call and on + # success tweak it and step ahead to the next question. The + # current implementation unnecessarily limits itself to a + # single match. + my @match = $expo->expect(1, + [ eof => sub { + $eof++; + } ], + [ timeout => sub { + $ran_into_timeout++; + } ], + -re => eval"qr{.}", + ); + if ($match[2]) { + $but .= $match[2]; + } + $but .= $expo->clear_accum; + if ($eof) { + $expo->soft_close; + return $expo->exitstatus(); + } elsif ($ran_into_timeout) { + # warn "DEBUG: they are asking a question, but[$but]"; + for (my $i = 0; $i <= $#expectacopy; $i+=2) { + my($next,$send) = @expectacopy[$i,$i+1]; + my $regex = eval "qr{$next}"; + # warn "DEBUG: will compare with regex[$regex]."; + if ($but =~ /$regex/) { + # warn "DEBUG: will send send[$send]"; + $expo->send($send); + # never allow reusing an QA pair unless they told us + splice @expectacopy, $i, 2 unless $reuse; + $but =~ s/(?s:^.*?)$regex//; + $timeout_start = time; + next EXPECT; + } + } + my $have_waited = time - $timeout_start; + if ($have_waited < $timeout) { + # warn "DEBUG: have_waited[$have_waited]timeout[$timeout]"; + next EXPECT; + } + my $why = "could not answer a question during the dialog"; + $CPAN::Frontend->mywarn("Failing: $why\n"); + $self->{$phase} = + CPAN::Distrostatus->new("NO $why"); + return 0; + } + } +} + +sub _run_via_expect_deterministic { + my($self,$expo,$phase,$expect_model) = @_; + my $ran_into_timeout; + my $ran_into_eof; + my $timeout = $expect_model->{timeout} || 15; # currently unsettable + my $expecta = $expect_model->{talk}; + EXPECT: for (my $i = 0; $i <= $#$expecta; $i+=2) { + my($re,$send) = @$expecta[$i,$i+1]; + CPAN->debug("timeout[$timeout]re[$re]") if $CPAN::DEBUG; + my $regex = eval "qr{$re}"; + $expo->expect($timeout, + [ eof => sub { + my $but = $expo->clear_accum; + $CPAN::Frontend->mywarn("EOF (maybe harmless) +expected[$regex]\nbut[$but]\n\n"); + $ran_into_eof++; + } ], + [ timeout => sub { + my $but = $expo->clear_accum; + $CPAN::Frontend->mywarn("TIMEOUT +expected[$regex]\nbut[$but]\n\n"); + $ran_into_timeout++; + } ], + -re => $regex); + if ($ran_into_timeout) { + # note that the caller expects 0 for success + $self->{$phase} = + CPAN::Distrostatus->new("NO timeout during expect dialog"); + return 0; + } elsif ($ran_into_eof) { + last EXPECT; + } + $expo->send($send); + } + $expo->soft_close; + return $expo->exitstatus(); +} + +#-> CPAN::Distribution::_validate_distropref +sub _validate_distropref { + my($self,@args) = @_; + if ( + $CPAN::META->has_inst("CPAN::Kwalify") + && + $CPAN::META->has_inst("Kwalify") + ) { + eval {CPAN::Kwalify::_validate("distroprefs",@args);}; + if ($@) { + $CPAN::Frontend->mywarn($@); + } + } else { + CPAN->debug("not validating '@args'") if $CPAN::DEBUG; + } +} + +#-> CPAN::Distribution::_find_prefs +sub _find_prefs { + my($self) = @_; + my $distroid = $self->pretty_id; + #CPAN->debug("distroid[$distroid]") if $CPAN::DEBUG; + my $prefs_dir = $CPAN::Config->{prefs_dir}; + return if $prefs_dir =~ /^\s*$/; + eval { File::Path::mkpath($prefs_dir); }; + if ($@) { + $CPAN::Frontend->mydie("Cannot create directory $prefs_dir"); + } + # shortcut if there are no distroprefs files + { + my $dh = DirHandle->new($prefs_dir) or $CPAN::Frontend->mydie("Couldn't open '$prefs_dir': $!"); + my @files = map { /\.(yml|dd|st)\z/i } $dh->read; + return unless @files; + } + my $yaml_module = CPAN::_yaml_module(); + my $ext_map = {}; + my @extensions; + if ($CPAN::META->has_inst($yaml_module)) { + $ext_map->{yml} = 'CPAN'; + } else { + my @fallbacks; + if ($CPAN::META->has_inst("Data::Dumper")) { + push @fallbacks, $ext_map->{dd} = 'Data::Dumper'; + } + if ($CPAN::META->has_inst("Storable")) { + push @fallbacks, $ext_map->{st} = 'Storable'; + } + if (@fallbacks) { + local $" = " and "; + unless ($self->{have_complained_about_missing_yaml}++) { + $CPAN::Frontend->mywarnonce("'$yaml_module' not installed, falling back ". + "to @fallbacks to read prefs '$prefs_dir'\n"); + } + } else { + unless ($self->{have_complained_about_missing_yaml}++) { + $CPAN::Frontend->mywarnonce("'$yaml_module' not installed, cannot ". + "read prefs '$prefs_dir'\n"); + } + } + } + my $finder = CPAN::Distroprefs->find($prefs_dir, $ext_map); + DIRENT: while (my $result = $finder->next) { + if ($result->is_warning) { + $CPAN::Frontend->mywarn($result->as_string); + $CPAN::Frontend->mysleep(1); + next DIRENT; + } elsif ($result->is_fatal) { + $CPAN::Frontend->mydie($result->as_string); + } + + my @prefs = @{ $result->prefs }; + + ELEMENT: for my $y (0..$#prefs) { + my $pref = $prefs[$y]; + $self->_validate_distropref($pref->data, $result->abs, $y); + + # I don't know why we silently skip when there's no match, but + # complain if there's an empty match hashref, and there's no + # comment explaining why -- hdp, 2008-03-18 + unless ($pref->has_any_match) { + next ELEMENT; + } + + unless ($pref->has_valid_subkeys) { + $CPAN::Frontend->mydie(sprintf + "Nonconforming .%s file '%s': " . + "missing match/* subattribute. " . + "Please remove, cannot continue.", + $result->ext, $result->abs, + ); + } + + my $arg = { + env => \%ENV, + distribution => $distroid, + perl => \&CPAN::find_perl, + perlconfig => \%Config::Config, + module => sub { [ $self->containsmods ] }, + }; + + if ($pref->matches($arg)) { + return { + prefs => $pref->data, + prefs_file => $result->abs, + prefs_file_doc => $y, + }; + } + + } + } + return; +} + +# CPAN::Distribution::prefs +sub prefs { + my($self) = @_; + if (exists $self->{negative_prefs_cache} + && + $self->{negative_prefs_cache} != $CPAN::CurrentCommandId + ) { + delete $self->{negative_prefs_cache}; + delete $self->{prefs}; + } + if (exists $self->{prefs}) { + return $self->{prefs}; # XXX comment out during debugging + } + if ($CPAN::Config->{prefs_dir}) { + CPAN->debug("prefs_dir[$CPAN::Config->{prefs_dir}]") if $CPAN::DEBUG; + my $prefs = $self->_find_prefs(); + $prefs ||= ""; # avoid warning next line + CPAN->debug("prefs[$prefs]") if $CPAN::DEBUG; + if ($prefs) { + for my $x (qw(prefs prefs_file prefs_file_doc)) { + $self->{$x} = $prefs->{$x}; + } + my $bs = sprintf( + "%s[%s]", + File::Basename::basename($self->{prefs_file}), + $self->{prefs_file_doc}, + ); + my $filler1 = "_" x 22; + my $filler2 = int(66 - length($bs))/2; + $filler2 = 0 if $filler2 < 0; + $filler2 = " " x $filler2; + $CPAN::Frontend->myprint(" +$filler1 D i s t r o P r e f s $filler1 +$filler2 $bs $filler2 +"); + $CPAN::Frontend->mysleep(1); + return $self->{prefs}; + } + } + $self->{negative_prefs_cache} = $CPAN::CurrentCommandId; + return $self->{prefs} = +{}; +} + +# CPAN::Distribution::_make_phase_arg +sub _make_phase_arg { + my($self, $phase) = @_; + my $_make_phase_arg; + my $prefs = $self->prefs; + if ( + $prefs + && exists $prefs->{$phase} + && exists $prefs->{$phase}{args} + && $prefs->{$phase}{args} + ) { + $_make_phase_arg = join(" ", + map {CPAN::HandleConfig + ->safe_quote($_)} @{$prefs->{$phase}{args}}, + ); + } + +# cpan[2]> o conf make[TAB] +# make make_install_make_command +# make_arg makepl_arg +# make_install_arg +# cpan[2]> o conf mbuild[TAB] +# mbuild_arg mbuild_install_build_command +# mbuild_install_arg mbuildpl_arg + + my $mantra; # must switch make/mbuild here + if ($self->{modulebuild}) { + $mantra = "mbuild"; + } else { + $mantra = "make"; + } + my %map = ( + pl => "pl_arg", + make => "_arg", + test => "_test_arg", # does not really exist but maybe + # will some day and now protects + # us from unini warnings + install => "_install_arg", + ); + my $phase_underscore_meshup = $map{$phase}; + my $what = sprintf "%s%s", $mantra, $phase_underscore_meshup; + + $_make_phase_arg ||= $CPAN::Config->{$what}; + return $_make_phase_arg; +} + +# CPAN::Distribution::_make_command +sub _make_command { + my ($self) = @_; + if ($self) { + return + CPAN::HandleConfig + ->safe_quote( + CPAN::HandleConfig->prefs_lookup($self, + q{make}) + || $Config::Config{make} + || 'make' + ); + } else { + # Old style call, without object. Deprecated + Carp::confess("CPAN::_make_command() used as function. Don't Do That."); + return + safe_quote(undef, + CPAN::HandleConfig->prefs_lookup($self,q{make}) + || $CPAN::Config->{make} + || $Config::Config{make} + || 'make'); + } +} + +#-> sub CPAN::Distribution::follow_prereqs ; +sub follow_prereqs { + my($self) = shift; + my($slot) = shift; + my(@prereq_tuples) = grep {$_->[0] ne "perl"} @_; + return unless @prereq_tuples; + my(@good_prereq_tuples); + for my $p (@prereq_tuples) { + # XXX watch out for foul ones + push @good_prereq_tuples, $p; + } + my $pretty_id = $self->pretty_id; + my %map = ( + b => "build_requires", + r => "requires", + c => "commandline", + ); + my($filler1,$filler2,$filler3,$filler4); + my $unsat = "Unsatisfied dependencies detected during"; + my $w = length($unsat) > length($pretty_id) ? length($unsat) : length($pretty_id); + { + my $r = int(($w - length($unsat))/2); + my $l = $w - length($unsat) - $r; + $filler1 = "-"x4 . " "x$l; + $filler2 = " "x$r . "-"x4 . "\n"; + } + { + my $r = int(($w - length($pretty_id))/2); + my $l = $w - length($pretty_id) - $r; + $filler3 = "-"x4 . " "x$l; + $filler4 = " "x$r . "-"x4 . "\n"; + } + $CPAN::Frontend-> + myprint("$filler1 $unsat $filler2". + "$filler3 $pretty_id $filler4". + join("", map {" $_->[0] \[$map{$_->[1]}]\n"} @good_prereq_tuples), + ); + my $follow = 0; + if ($CPAN::Config->{prerequisites_policy} eq "follow") { + $follow = 1; + } elsif ($CPAN::Config->{prerequisites_policy} eq "ask") { + my $answer = CPAN::Shell::colorable_makemaker_prompt( +"Shall I follow them and prepend them to the queue +of modules we are processing right now?", "yes"); + $follow = $answer =~ /^\s*y/i; + } else { + my @prereq = map { $_=>[0] } @good_prereq_tuples; + local($") = ", "; + $CPAN::Frontend-> + myprint(" Ignoring dependencies on modules @prereq\n"); + } + if ($follow) { + my $id = $self->id; + # color them as dirty + for my $gp (@good_prereq_tuples) { + # warn "calling color_cmd_tmps(0,1)"; + my $p = $gp->[0]; + my $any = CPAN::Shell->expandany($p); + $self->{$slot . "_for"}{$any->id}++; + if ($any) { + $any->color_cmd_tmps(0,2); + } else { + $CPAN::Frontend->mywarn("Warning (maybe a bug): Cannot expand prereq '$p'\n"); + $CPAN::Frontend->mysleep(2); + } + } + # queue them and re-queue yourself + CPAN::Queue->jumpqueue({qmod => $id, reqtype => $self->{reqtype}}, + map {+{qmod=>$_->[0],reqtype=>$_->[1]}} reverse @good_prereq_tuples); + $self->{$slot} = "Delayed until after prerequisites"; + return 1; # signal success to the queuerunner + } + return; +} + +sub _feature_depends { + my($self) = @_; + my $meta_yml = $self->parse_meta_yml(); + my $optf = $meta_yml->{optional_features} or return; + if (!ref $optf or ref $optf ne "HASH"){ + $CPAN::Frontend->mywarn("The content of optional_features is not a HASH reference. Cannot use it.\n"); + $optf = {}; + } + my $wantf = $self->prefs->{features} or return; + if (!ref $wantf or ref $wantf ne "ARRAY"){ + $CPAN::Frontend->mywarn("The content of 'features' is not an ARRAY reference. Cannot use it.\n"); + $wantf = []; + } + my $dep = +{}; + for my $wf (@$wantf) { + if (my $f = $optf->{$wf}) { + $CPAN::Frontend->myprint("Found the demanded feature '$wf' that ". + "is accompanied by this description:\n". + $f->{description}. + "\n\n" + ); + # configure_requires currently not in the spec, unlikely to be useful anyway + for my $reqtype (qw(configure_requires build_requires requires)) { + my $reqhash = $f->{$reqtype} or next; + while (my($k,$v) = each %$reqhash) { + $dep->{$reqtype}{$k} = $v; + } + } + } else { + $CPAN::Frontend->mywarn("The demanded feature '$wf' was not ". + "found in the META.yml file". + "\n\n" + ); + } + } + $dep; +} + +#-> sub CPAN::Distribution::unsat_prereq ; +# return ([Foo,"r"],[Bar,"b"]) for normal modules +# return ([perl=>5.008]) if we need a newer perl than we are running under +# (sorry for the inconsistency, it was an accident) +sub unsat_prereq { + my($self,$slot) = @_; + my(%merged,$prereq_pm); + my $prefs_depends = $self->prefs->{depends}||{}; + my $feature_depends = $self->_feature_depends(); + if ($slot eq "configure_requires_later") { + my $meta_yml = $self->parse_meta_yml(); + if (defined $meta_yml && (! ref $meta_yml || ref $meta_yml ne "HASH")) { + $CPAN::Frontend->mywarn("The content of META.yml is defined but not a HASH reference. Cannot use it.\n"); + $meta_yml = +{}; + } + %merged = ( + %{$meta_yml->{configure_requires}||{}}, + %{$prefs_depends->{configure_requires}||{}}, + %{$feature_depends->{configure_requires}||{}}, + ); + if (-f "Build.PL" + && ! -f "Makefile.PL" + && ! exists $merged{"Module::Build"} + && ! $CPAN::META->has_inst("Module::Build") + ) { + $CPAN::Frontend->mywarn( + " Warning: CPAN.pm discovered Module::Build as undeclared prerequisite.\n". + " Adding it now as such.\n" + ); + $CPAN::Frontend->mysleep(5); + $merged{"Module::Build"} = 0; + delete $self->{writemakefile}; + } + $prereq_pm = {}; # configure_requires defined as "b" + } elsif ($slot eq "later") { + my $prereq_pm_0 = $self->prereq_pm || {}; + for my $reqtype (qw(requires build_requires)) { + $prereq_pm->{$reqtype} = {%{$prereq_pm_0->{$reqtype}||{}}}; # copy to not pollute it + for my $dep ($prefs_depends,$feature_depends) { + for my $k (keys %{$dep->{$reqtype}||{}}) { + $prereq_pm->{$reqtype}{$k} = $dep->{$reqtype}{$k}; + } + } + } + %merged = (%{$prereq_pm->{requires}||{}},%{$prereq_pm->{build_requires}||{}}); + } else { + die "Panic: illegal slot '$slot'"; + } + my(@need); + my @merged = %merged; + CPAN->debug("all merged_prereqs[@merged]") if $CPAN::DEBUG; + NEED: while (my($need_module, $need_version) = each %merged) { + my($available_version,$inst_file,$available_file,$nmo); + if ($need_module eq "perl") { + $available_version = $]; + $available_file = CPAN::find_perl(); + } else { + if (CPAN::_sqlite_running()) { + CPAN::Index->reload; + $CPAN::SQLite->search("CPAN::Module",$need_module); + } + $nmo = $CPAN::META->instance("CPAN::Module",$need_module); + next if $nmo->uptodate; + $inst_file = $nmo->inst_file || ''; + $available_file = $nmo->available_file || ''; + + # if they have not specified a version, we accept any installed one + if ( $available_file + and ( # a few quick shortcurcuits + not defined $need_version + or $need_version eq '0' # "==" would trigger warning when not numeric + or $need_version eq "undef" + )) { + unless ($nmo->inst_deprecated) { + next NEED; + } + + } + + $available_version = $nmo->available_version; + } + + # We only want to install prereqs if either they're not installed + # or if the installed version is too old. We cannot omit this + # check, because if 'force' is in effect, nobody else will check. + # But we don't want to accept a deprecated module installed as part + # of the Perl core, so we continue if the available file is the installed + # one and is deprecated + + if ( $available_file ) { + if ( $inst_file && $available_file eq $inst_file && $nmo->inst_deprecated ) { + # continue installing as a prereq + } + else { + next NEED if $self->_fulfills_all_version_rqs( + $need_module,$available_file,$available_version,$need_version + ); + } + } + + if ($need_module eq "perl") { + return ["perl", $need_version]; + } + $self->{sponsored_mods}{$need_module} ||= 0; + CPAN->debug("need_module[$need_module]s/s/n[$self->{sponsored_mods}{$need_module}]") if $CPAN::DEBUG; + if (my $sponsoring = $self->{sponsored_mods}{$need_module}++) { + # We have already sponsored it and for some reason it's still + # not available. So we do ... what?? + + # if we push it again, we have a potential infinite loop + + # The following "next" was a very problematic construct. + # It helped a lot but broke some day and had to be + # replaced. + + # We must be able to deal with modules that come again and + # again as a prereq and have themselves prereqs and the + # queue becomes long but finally we would find the correct + # order. The RecursiveDependency check should trigger a + # die when it's becoming too weird. Unfortunately removing + # this next breaks many other things. + + # The bug that brought this up is described in Todo under + # "5.8.9 cannot install Compress::Zlib" + + # next; # this is the next that had to go away + + # The following "next NEED" are fine and the error message + # explains well what is going on. For example when the DBI + # fails and consequently DBD::SQLite fails and now we are + # processing CPAN::SQLite. Then we must have a "next" for + # DBD::SQLite. How can we get it and how can we identify + # all other cases we must identify? + + my $do = $nmo->distribution; + next NEED unless $do; # not on CPAN + if (CPAN::Version->vcmp($need_version, $nmo->ro->{CPAN_VERSION}) > 0){ + $CPAN::Frontend->mywarn("Warning: Prerequisite ". + "'$need_module => $need_version' ". + "for '$self->{ID}' seems ". + "not available according to the indices\n" + ); + next NEED; + } + NOSAYER: for my $nosayer ( + "unwrapped", + "writemakefile", + "signature_verify", + "make", + "make_test", + "install", + "make_clean", + ) { + if ($do->{$nosayer}) { + my $selfid = $self->pretty_id; + my $did = $do->pretty_id; + if (UNIVERSAL::can($do->{$nosayer},"failed") ? + $do->{$nosayer}->failed : + $do->{$nosayer} =~ /^NO/) { + if ($nosayer eq "make_test" + && + $do->{make_test}{COMMANDID} != $CPAN::CurrentCommandId + ) { + next NOSAYER; + } + $CPAN::Frontend->mywarn("Warning: Prerequisite ". + "'$need_module => $need_version' ". + "for '$selfid' failed when ". + "processing '$did' with ". + "'$nosayer => $do->{$nosayer}'. Continuing, ". + "but chances to succeed are limited.\n" + ); + $CPAN::Frontend->mysleep($sponsoring/10); + next NEED; + } else { # the other guy succeeded + if ($nosayer =~ /^(install|make_test)$/) { + # we had this with + # DMAKI/DateTime-Calendar-Chinese-0.05.tar.gz + # in 2007-03 for 'make install' + # and 2008-04: #30464 (for 'make test') + $CPAN::Frontend->mywarn("Warning: Prerequisite ". + "'$need_module => $need_version' ". + "for '$selfid' already built ". + "but the result looks suspicious. ". + "Skipping another build attempt, ". + "to prevent looping endlessly.\n" + ); + next NEED; + } + } + } + } + } + my $needed_as = exists $prereq_pm->{requires}{$need_module} ? "r" : "b"; + push @need, [$need_module,$needed_as]; + } + my @unfolded = map { "[".join(",",@$_)."]" } @need; + CPAN->debug("returning from unsat_prereq[@unfolded]") if $CPAN::DEBUG; + @need; +} + +sub _fulfills_all_version_rqs { + my($self,$need_module,$available_file,$available_version,$need_version) = @_; + my(@all_requirements) = split /\s*,\s*/, $need_version; + local($^W) = 0; + my $ok = 0; + RQ: for my $rq (@all_requirements) { + if ($rq =~ s|>=\s*||) { + } elsif ($rq =~ s|>\s*||) { + # 2005-12: one user + if (CPAN::Version->vgt($available_version,$rq)) { + $ok++; + } + next RQ; + } elsif ($rq =~ s|!=\s*||) { + # 2005-12: no user + if (CPAN::Version->vcmp($available_version,$rq)) { + $ok++; + next RQ; + } else { + $ok=0; + last RQ; + } + } elsif ($rq =~ m|<=?\s*|) { + # 2005-12: no user + $CPAN::Frontend->mywarn("Downgrading not supported (rq[$rq])\n"); + $ok++; + next RQ; + } elsif ($rq =~ s|==\s*||) { + # 2009-07: ELLIOTJS/Perl-Critic-1.099_002.tar.gz + if (CPAN::Version->vcmp($available_version,$rq)) { + $ok=0; + last RQ; + } else { + $ok++; + next RQ; + } + } + if (! CPAN::Version->vgt($rq, $available_version)) { + $ok++; + } + CPAN->debug(sprintf("need_module[%s]available_file[%s]". + "available_version[%s]rq[%s]ok[%d]", + $need_module, + $available_file, + $available_version, + CPAN::Version->readable($rq), + $ok, + )) if $CPAN::DEBUG; + } + my $ret = $ok == @all_requirements; + CPAN->debug(sprintf("need_module[%s]ok[%s]all_requirements[%d]",$need_module, $ok, scalar @all_requirements)) if $CPAN::DEBUG; + return $ret; +} + +#-> sub CPAN::Distribution::read_yaml ; +sub read_yaml { + my($self) = @_; + my $build_dir; + unless ($build_dir = $self->{build_dir}) { + # maybe permission on build_dir was missing + $CPAN::Frontend->mywarn("Warning: cannot determine META.yml without a build_dir.\n"); + return; + } + # if MYMETA.yml exists, that takes precedence over META.yml + my $meta = File::Spec->catfile($build_dir,"META.yml"); + my $mymeta = File::Spec->catfile($build_dir,"MYMETA.yml"); + my $meta_file = -f $mymeta ? $mymeta : $meta; + $self->debug("meta_file[$meta_file]") if $CPAN::DEBUG; + return unless -f $meta_file; + my $yaml; + eval { $yaml = $self->parse_meta_yml($meta_file) }; + if ($@ or ! $yaml) { + $CPAN::Frontend->mywarnonce("Could not read ". + "'$meta_file'. Falling back to other ". + "methods to determine prerequisites\n"); + return undef; # if we die, then we cannot read YAML's own META.yml + } + # not "authoritative" + if (defined $yaml && (! ref $yaml || ref $yaml ne "HASH")) { + $CPAN::Frontend->mywarn("META.yml does not seem to be conforming, cannot use it.\n"); + $yaml = undef; + } + $self->debug(sprintf "yaml[%s]", $yaml || "UNDEF") + if $CPAN::DEBUG; + $self->debug($yaml) if $CPAN::DEBUG && $yaml; + # MYMETA.yml is static and authoritative by definition + if ( $meta_file eq $mymeta ) { + return $yaml; + } + # META.yml is authoritative only if dynamic_config is defined and false + if ( defined $yaml->{dynamic_config} && ! $yaml->{dynamic_config} ) { + return $yaml; + } + # otherwise, we can't use what we found + return undef; +} + +#-> sub CPAN::Distribution::prereq_pm ; +sub prereq_pm { + my($self) = @_; + return unless $self->{writemakefile} # no need to have succeeded + # but we must have run it + || $self->{modulebuild}; + unless ($self->{build_dir}) { + return; + } + CPAN->debug(sprintf "writemakefile[%s]modulebuild[%s]", + $self->{writemakefile}||"", + $self->{modulebuild}||"", + ) if $CPAN::DEBUG; + my($req,$breq); + if (my $yaml = $self->read_yaml) { # often dynamic_config prevents a result here + $req = $yaml->{requires} || {}; + $breq = $yaml->{build_requires} || {}; + undef $req unless ref $req eq "HASH" && %$req; + if ($req) { + if ($yaml->{generated_by} && + $yaml->{generated_by} =~ /ExtUtils::MakeMaker version ([\d\._]+)/) { + my $eummv = do { local $^W = 0; $1+0; }; + if ($eummv < 6.2501) { + # thanks to Slaven for digging that out: MM before + # that could be wrong because it could reflect a + # previous release + undef $req; + } + } + my $areq; + my $do_replace; + while (my($k,$v) = each %{$req||{}}) { + if ($v =~ /\d/) { + $areq->{$k} = $v; + } elsif ($k =~ /[A-Za-z]/ && + $v =~ /[A-Za-z]/ && + $CPAN::META->exists("CPAN::Module",$v) + ) { + $CPAN::Frontend->mywarn("Suspicious key-value pair in META.yml's ". + "requires hash: $k => $v; I'll take both ". + "key and value as a module name\n"); + $CPAN::Frontend->mysleep(1); + $areq->{$k} = 0; + $areq->{$v} = 0; + $do_replace++; + } + } + $req = $areq if $do_replace; + } + } + unless ($req || $breq) { + my $build_dir; + unless ( $build_dir = $self->{build_dir} ) { + return; + } + my $makefile = File::Spec->catfile($build_dir,"Makefile"); + my $fh; + if (-f $makefile + and + $fh = FileHandle->new("<$makefile\0")) { + CPAN->debug("Getting prereq from Makefile") if $CPAN::DEBUG; + local($/) = "\n"; + while (<$fh>) { + last if /MakeMaker post_initialize section/; + my($p) = m{^[\#] + \s+PREREQ_PM\s+=>\s+(.+) + }x; + next unless $p; + # warn "Found prereq expr[$p]"; + + # Regexp modified by A.Speer to remember actual version of file + # PREREQ_PM hash key wants, then add to + while ( $p =~ m/(?:\s)([\w\:]+)=>(q\[.*?\]|undef),?/g ) { + my($m,$n) = ($1,$2); + # When a prereq is mentioned twice: let the bigger + # win; usual culprit is that they declared + # build_requires separately from requires; see + # rt.cpan.org #47774 + my($prevn); + if ( defined $req->{$m} ) { + $prevn = $req->{$m}; + } + if ($n =~ /^q\[(.*?)\]$/) { + $n = $1; + } + if (!$prevn || CPAN::Version->vlt($prevn, $n)){ + $req->{$m} = $n; + } + } + last; + } + } + } + unless ($req || $breq) { + my $build_dir = $self->{build_dir} or die "Panic: no build_dir?"; + my $buildfile = File::Spec->catfile($build_dir,"Build"); + if (-f $buildfile) { + CPAN->debug("Found '$buildfile'") if $CPAN::DEBUG; + my $build_prereqs = File::Spec->catfile($build_dir,"_build","prereqs"); + if (-f $build_prereqs) { + CPAN->debug("Getting prerequisites from '$build_prereqs'") if $CPAN::DEBUG; + my $content = do { local *FH; + open FH, $build_prereqs + or $CPAN::Frontend->mydie("Could not open ". + "'$build_prereqs': $!"); + local $/; + <FH>; + }; + my $bphash = eval $content; + if ($@) { + } else { + $req = $bphash->{requires} || +{}; + $breq = $bphash->{build_requires} || +{}; + } + } + } + } + if ($req || $breq) { + return $self->{prereq_pm} = { requires => $req, build_requires => $breq }; + } +} + +#-> sub CPAN::Distribution::test ; +sub test { + my($self) = @_; + if (my $goto = $self->prefs->{goto}) { + return $self->goto($goto); + } + $self->make; + return if $self->prefs->{disabled} && ! $self->{force_update}; + if ($CPAN::Signal) { + delete $self->{force_update}; + return; + } + # warn "XDEBUG: checking for notest: $self->{notest} $self"; + if ($self->{notest}) { + $CPAN::Frontend->myprint("Skipping test because of notest pragma\n"); + return 1; + } + + my $make = $self->{modulebuild} ? "Build" : "make"; + + local $ENV{PERL5LIB} = defined($ENV{PERL5LIB}) + ? $ENV{PERL5LIB} + : ($ENV{PERLLIB} || ""); + + local $ENV{PERL5OPT} = defined $ENV{PERL5OPT} ? $ENV{PERL5OPT} : ""; + $CPAN::META->set_perl5lib; + local $ENV{MAKEFLAGS}; # protect us from outer make calls + + $CPAN::Frontend->myprint("Running $make test\n"); + + EXCUSE: { + my @e; + if ($self->{make} or $self->{later}) { + # go ahead + } else { + push @e, + "Make had some problems, won't test"; + } + + exists $self->{make} and + ( + UNIVERSAL::can($self->{make},"failed") ? + $self->{make}->failed : + $self->{make} =~ /^NO/ + ) and push @e, "Can't test without successful make"; + $self->{badtestcnt} ||= 0; + if ($self->{badtestcnt} > 0) { + require Data::Dumper; + CPAN->debug(sprintf "NOREPEAT[%s]", Data::Dumper::Dumper($self)) if $CPAN::DEBUG; + push @e, "Won't repeat unsuccessful test during this command"; + } + + push @e, $self->{later} if $self->{later}; + push @e, $self->{configure_requires_later} if $self->{configure_requires_later}; + + if (exists $self->{build_dir}) { + if (exists $self->{make_test}) { + if ( + UNIVERSAL::can($self->{make_test},"failed") ? + $self->{make_test}->failed : + $self->{make_test} =~ /^NO/ + ) { + if ( + UNIVERSAL::can($self->{make_test},"commandid") + && + $self->{make_test}->commandid == $CPAN::CurrentCommandId + ) { + push @e, "Has already been tested within this command"; + } + } else { + push @e, "Has already been tested successfully"; + # if global "is_tested" has been cleared, we need to mark this to + # be added to PERL5LIB if not already installed + if ($self->tested_ok_but_not_installed) { + $CPAN::META->is_tested($self->{build_dir},$self->{make_test}{TIME}); + } + } + } + } elsif (!@e) { + push @e, "Has no own directory"; + } + $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e; + unless (chdir $self->{build_dir}) { + push @e, "Couldn't chdir to '$self->{build_dir}': $!"; + } + $CPAN::Frontend->mywarn(join "", map {" $_\n"} @e) and return if @e; + } + $self->debug("Changed directory to $self->{build_dir}") + if $CPAN::DEBUG; + + if ($^O eq 'MacOS') { + Mac::BuildTools::make_test($self); + return; + } + + if ($self->{modulebuild}) { + my $thm = CPAN::Shell->expand("Module","Test::Harness"); + my $v = $thm->inst_version; + if (CPAN::Version->vlt($v,2.62)) { + # XXX Eric Wilhelm reported this as a bug: klapperl: + # Test::Harness 3.0 self-tests, so that should be 'unless + # installing Test::Harness' + unless ($self->id eq $thm->distribution->id) { + $CPAN::Frontend->mywarn(qq{The version of your Test::Harness is only + '$v', you need at least '2.62'. Please upgrade your Test::Harness.\n}); + $self->{make_test} = CPAN::Distrostatus->new("NO Test::Harness too old"); + return; + } + } + } + + if ( ! $self->{force_update} ) { + # bypass actual tests if "trust_test_report_history" and have a report + my $have_tested_fcn; + if ( $CPAN::Config->{trust_test_report_history} + && $CPAN::META->has_inst("CPAN::Reporter::History") + && ( $have_tested_fcn = CPAN::Reporter::History->can("have_tested" ))) { + if ( my @reports = $have_tested_fcn->( dist => $self->base_id ) ) { + # Do nothing if grade was DISCARD + if ( $reports[-1]->{grade} =~ /^(?:PASS|UNKNOWN)$/ ) { + $self->{make_test} = CPAN::Distrostatus->new("YES"); + # if global "is_tested" has been cleared, we need to mark this to + # be added to PERL5LIB if not already installed + if ($self->tested_ok_but_not_installed) { + $CPAN::META->is_tested($self->{build_dir},$self->{make_test}{TIME}); + } + $CPAN::Frontend->myprint("Found prior test report -- OK\n"); + return; + } + elsif ( $reports[-1]->{grade} =~ /^(?:FAIL|NA)$/ ) { + $self->{make_test} = CPAN::Distrostatus->new("NO"); + $self->{badtestcnt}++; + $CPAN::Frontend->mywarn("Found prior test report -- NOT OK\n"); + return; + } + } + } + } + + my $system; + my $prefs_test = $self->prefs->{test}; + if (my $commandline + = exists $prefs_test->{commandline} ? $prefs_test->{commandline} : "") { + $system = $commandline; + $ENV{PERL} = CPAN::find_perl(); + } elsif ($self->{modulebuild}) { + $system = sprintf "%s test", $self->_build_command(); + unless (-e "Build") { + my $id = $self->pretty_id; + $CPAN::Frontend->mywarn("Alert: no 'Build' file found while trying to test '$id'"); + } + } else { + $system = join " ", $self->_make_command(), "test"; + } + my $make_test_arg = $self->_make_phase_arg("test"); + $system = sprintf("%s%s", + $system, + $make_test_arg ? " $make_test_arg" : "", + ); + my($tests_ok); + my %env; + while (my($k,$v) = each %ENV) { + next unless defined $v; + $env{$k} = $v; + } + local %ENV = %env; + my $test_env; + if ($self->prefs->{test}) { + $test_env = $self->prefs->{test}{env}; + } + if ($test_env) { + for my $e (keys %$test_env) { + $ENV{$e} = $test_env->{$e}; + } + } + my $expect_model = $self->_prefs_with_expect("test"); + my $want_expect = 0; + if ( $expect_model && @{$expect_model->{talk}} ) { + my $can_expect = $CPAN::META->has_inst("Expect"); + if ($can_expect) { + $want_expect = 1; + } else { + $CPAN::Frontend->mywarn("Expect not installed, falling back to ". + "testing without\n"); + } + } + if ($want_expect) { + if ($self->_should_report('test')) { + $CPAN::Frontend->mywarn("Reporting via CPAN::Reporter is currently ". + "not supported when distroprefs specify ". + "an interactive test\n"); + } + $tests_ok = $self->_run_via_expect($system,'test',$expect_model) == 0; + } elsif ( $self->_should_report('test') ) { + $tests_ok = CPAN::Reporter::test($self, $system); + } else { + $tests_ok = system($system) == 0; + } + $self->introduce_myself; + if ( $tests_ok ) { + { + my @prereq; + + # local $CPAN::DEBUG = 16; # Distribution + for my $m (keys %{$self->{sponsored_mods}}) { + next unless $self->{sponsored_mods}{$m} > 0; + my $m_obj = CPAN::Shell->expand("Module",$m) or next; + # XXX we need available_version which reflects + # $ENV{PERL5LIB} so that already tested but not yet + # installed modules are counted. + my $available_version = $m_obj->available_version; + my $available_file = $m_obj->available_file; + if ($available_version && + !CPAN::Version->vlt($available_version,$self->{prereq_pm}{$m}) + ) { + CPAN->debug("m[$m] good enough available_version[$available_version]") + if $CPAN::DEBUG; + } elsif ($available_file + && ( + !$self->{prereq_pm}{$m} + || + $self->{prereq_pm}{$m} == 0 + ) + ) { + # lex Class::Accessor::Chained::Fast which has no $VERSION + CPAN->debug("m[$m] have available_file[$available_file]") + if $CPAN::DEBUG; + } else { + push @prereq, $m; + } + } + if (@prereq) { + my $cnt = @prereq; + my $which = join ",", @prereq; + my $but = $cnt == 1 ? "one dependency not OK ($which)" : + "$cnt dependencies missing ($which)"; + $CPAN::Frontend->mywarn("Tests succeeded but $but\n"); + $self->{make_test} = CPAN::Distrostatus->new("NO $but"); + $self->store_persistent_state; + return $self->goodbye("[dependencies] -- NA"); + } + } + + $CPAN::Frontend->myprint(" $system -- OK\n"); + $self->{make_test} = CPAN::Distrostatus->new("YES"); + $CPAN::META->is_tested($self->{build_dir},$self->{make_test}{TIME}); + # probably impossible to need the next line because badtestcnt + # has a lifespan of one command + delete $self->{badtestcnt}; + } else { + $self->{make_test} = CPAN::Distrostatus->new("NO"); + $self->{badtestcnt}++; + $CPAN::Frontend->mywarn(" $system -- NOT OK\n"); + CPAN::Shell->optprint + ("hint", + sprintf + ("//hint// to see the cpan-testers results for installing this module, try: + reports %s\n", + $self->pretty_id)); + } + $self->store_persistent_state; +} + +sub _prefs_with_expect { + my($self,$where) = @_; + return unless my $prefs = $self->prefs; + return unless my $where_prefs = $prefs->{$where}; + if ($where_prefs->{expect}) { + return { + mode => "deterministic", + timeout => 15, + talk => $where_prefs->{expect}, + }; + } elsif ($where_prefs->{"eexpect"}) { + return $where_prefs->{"eexpect"}; + } + return; +} + +#-> sub CPAN::Distribution::clean ; +sub clean { + my($self) = @_; + my $make = $self->{modulebuild} ? "Build" : "make"; + $CPAN::Frontend->myprint("Running $make clean\n"); + unless (exists $self->{archived}) { + $CPAN::Frontend->mywarn("Distribution seems to have never been unzipped". + "/untarred, nothing done\n"); + return 1; + } + unless (exists $self->{build_dir}) { + $CPAN::Frontend->mywarn("Distribution has no own directory, nothing to do.\n"); + return 1; + } + if (exists $self->{writemakefile} + and $self->{writemakefile}->failed + ) { + $CPAN::Frontend->mywarn("No Makefile, don't know how to 'make clean'\n"); + return 1; + } + EXCUSE: { + my @e; + exists $self->{make_clean} and $self->{make_clean} eq "YES" and + push @e, "make clean already called once"; + $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e; + } + chdir $self->{build_dir} or + Carp::confess("Couldn't chdir to $self->{build_dir}: $!"); + $self->debug("Changed directory to $self->{build_dir}") if $CPAN::DEBUG; + + if ($^O eq 'MacOS') { + Mac::BuildTools::make_clean($self); + return; + } + + my $system; + if ($self->{modulebuild}) { + unless (-f "Build") { + my $cwd = CPAN::anycwd(); + $CPAN::Frontend->mywarn("Alert: no Build file available for 'clean $self->{id}". + " in cwd[$cwd]. Danger, Will Robinson!"); + $CPAN::Frontend->mysleep(5); + } + $system = sprintf "%s clean", $self->_build_command(); + } else { + $system = join " ", $self->_make_command(), "clean"; + } + my $system_ok = system($system) == 0; + $self->introduce_myself; + if ( $system_ok ) { + $CPAN::Frontend->myprint(" $system -- OK\n"); + + # $self->force; + + # Jost Krieger pointed out that this "force" was wrong because + # it has the effect that the next "install" on this distribution + # will untar everything again. Instead we should bring the + # object's state back to where it is after untarring. + + for my $k (qw( + force_update + install + writemakefile + make + make_test + )) { + delete $self->{$k}; + } + $self->{make_clean} = CPAN::Distrostatus->new("YES"); + + } else { + # Hmmm, what to do if make clean failed? + + $self->{make_clean} = CPAN::Distrostatus->new("NO"); + $CPAN::Frontend->mywarn(qq{ $system -- NOT OK\n}); + + # 2006-02-27: seems silly to me to force a make now + # $self->force("make"); # so that this directory won't be used again + + } + $self->store_persistent_state; +} + +#-> sub CPAN::Distribution::goto ; +sub goto { + my($self,$goto) = @_; + $goto = $self->normalize($goto); + my $why = sprintf( + "Goto '$goto' via prefs file '%s' doc %d", + $self->{prefs_file}, + $self->{prefs_file_doc}, + ); + $self->{unwrapped} = CPAN::Distrostatus->new("NO $why"); + # 2007-07-16 akoenig : Better than NA would be if we could inherit + # the status of the $goto distro but given the exceptional nature + # of 'goto' I feel reluctant to implement it + my $goodbye_message = "[goto] -- NA $why"; + $self->goodbye($goodbye_message); + + # inject into the queue + + CPAN::Queue->delete($self->id); + CPAN::Queue->jumpqueue({qmod => $goto, reqtype => $self->{reqtype}}); + + # and run where we left off + + my($method) = (caller(1))[3]; + CPAN->instance("CPAN::Distribution",$goto)->$method(); + CPAN::Queue->delete_first($goto); +} + +#-> sub CPAN::Distribution::install ; +sub install { + my($self) = @_; + if (my $goto = $self->prefs->{goto}) { + return $self->goto($goto); + } + unless ($self->{badtestcnt}) { + $self->test; + } + if ($CPAN::Signal) { + delete $self->{force_update}; + return; + } + my $make = $self->{modulebuild} ? "Build" : "make"; + $CPAN::Frontend->myprint("Running $make install\n"); + EXCUSE: { + my @e; + if ($self->{make} or $self->{later}) { + # go ahead + } else { + push @e, + "Make had some problems, won't install"; + } + + exists $self->{make} and + ( + UNIVERSAL::can($self->{make},"failed") ? + $self->{make}->failed : + $self->{make} =~ /^NO/ + ) and + push @e, "Make had returned bad status, install seems impossible"; + + if (exists $self->{build_dir}) { + } elsif (!@e) { + push @e, "Has no own directory"; + } + + if (exists $self->{make_test} and + ( + UNIVERSAL::can($self->{make_test},"failed") ? + $self->{make_test}->failed : + $self->{make_test} =~ /^NO/ + )) { + if ($self->{force_update}) { + $self->{make_test}->text("FAILED but failure ignored because ". + "'force' in effect"); + } else { + push @e, "make test had returned bad status, ". + "won't install without force" + } + } + if (exists $self->{install}) { + if (UNIVERSAL::can($self->{install},"text") ? + $self->{install}->text eq "YES" : + $self->{install} =~ /^YES/ + ) { + $CPAN::Frontend->myprint(" Already done\n"); + $CPAN::META->is_installed($self->{build_dir}); + return 1; + } else { + # comment in Todo on 2006-02-11; maybe retry? + push @e, "Already tried without success"; + } + } + + push @e, $self->{later} if $self->{later}; + push @e, $self->{configure_requires_later} if $self->{configure_requires_later}; + + $CPAN::Frontend->myprint(join "", map {" $_\n"} @e) and return if @e; + unless (chdir $self->{build_dir}) { + push @e, "Couldn't chdir to '$self->{build_dir}': $!"; + } + $CPAN::Frontend->mywarn(join "", map {" $_\n"} @e) and return if @e; + } + $self->debug("Changed directory to $self->{build_dir}") + if $CPAN::DEBUG; + + if ($^O eq 'MacOS') { + Mac::BuildTools::make_install($self); + return; + } + + my $system; + if (my $commandline = $self->prefs->{install}{commandline}) { + $system = $commandline; + $ENV{PERL} = CPAN::find_perl(); + } elsif ($self->{modulebuild}) { + my($mbuild_install_build_command) = + exists $CPAN::HandleConfig::keys{mbuild_install_build_command} && + $CPAN::Config->{mbuild_install_build_command} ? + $CPAN::Config->{mbuild_install_build_command} : + $self->_build_command(); + $system = sprintf("%s install %s", + $mbuild_install_build_command, + $CPAN::Config->{mbuild_install_arg}, + ); + } else { + my($make_install_make_command) = + CPAN::HandleConfig->prefs_lookup($self, + q{make_install_make_command}) + || $self->_make_command(); + $system = sprintf("%s install %s", + $make_install_make_command, + $CPAN::Config->{make_install_arg}, + ); + } + + my($stderr) = $^O eq "MSWin32" ? "" : " 2>&1 "; + my $brip = CPAN::HandleConfig->prefs_lookup($self, + q{build_requires_install_policy}); + $brip ||="ask/yes"; + my $id = $self->id; + my $reqtype = $self->{reqtype} ||= "c"; # in doubt it was a command + my $want_install = "yes"; + if ($reqtype eq "b") { + if ($brip eq "no") { + $want_install = "no"; + } elsif ($brip =~ m|^ask/(.+)|) { + my $default = $1; + $default = "yes" unless $default =~ /^(y|n)/i; + $want_install = + CPAN::Shell::colorable_makemaker_prompt + ("$id is just needed temporarily during building or testing. ". + "Do you want to install it permanently?", + $default); + } + } + unless ($want_install =~ /^y/i) { + my $is_only = "is only 'build_requires'"; + $CPAN::Frontend->mywarn("Not installing because $is_only\n"); + $self->{install} = CPAN::Distrostatus->new("NO -- $is_only"); + delete $self->{force_update}; + return; + } + local $ENV{PERL5LIB} = defined($ENV{PERL5LIB}) + ? $ENV{PERL5LIB} + : ($ENV{PERLLIB} || ""); + + local $ENV{PERL5OPT} = defined $ENV{PERL5OPT} ? $ENV{PERL5OPT} : ""; + $CPAN::META->set_perl5lib; + my($pipe) = FileHandle->new("$system $stderr |") || Carp::croak +("Can't execute $system: $!"); + my($makeout) = ""; + while (<$pipe>) { + print $_; # intentionally NOT use Frontend->myprint because it + # looks irritating when we markup in color what we + # just pass through from an external program + $makeout .= $_; + } + $pipe->close; + my $close_ok = $? == 0; + $self->introduce_myself; + if ( $close_ok ) { + $CPAN::Frontend->myprint(" $system -- OK\n"); + $CPAN::META->is_installed($self->{build_dir}); + $self->{install} = CPAN::Distrostatus->new("YES"); + } else { + $self->{install} = CPAN::Distrostatus->new("NO"); + $CPAN::Frontend->mywarn(" $system -- NOT OK\n"); + my $mimc = + CPAN::HandleConfig->prefs_lookup($self, + q{make_install_make_command}); + if ( + $makeout =~ /permission/s + && $> > 0 + && ( + ! $mimc + || $mimc eq (CPAN::HandleConfig->prefs_lookup($self, + q{make})) + ) + ) { + $CPAN::Frontend->myprint( + qq{----\n}. + qq{ You may have to su }. + qq{to root to install the package\n}. + qq{ (Or you may want to run something like\n}. + qq{ o conf make_install_make_command 'sudo make'\n}. + qq{ to raise your permissions.} + ); + } + } + delete $self->{force_update}; + $self->store_persistent_state; +} + +sub introduce_myself { + my($self) = @_; + $CPAN::Frontend->myprint(sprintf(" %s\n",$self->pretty_id)); +} + +#-> sub CPAN::Distribution::dir ; +sub dir { + shift->{build_dir}; +} + +#-> sub CPAN::Distribution::perldoc ; +sub perldoc { + my($self) = @_; + + my($dist) = $self->id; + my $package = $self->called_for; + + if ($CPAN::META->has_inst("Pod::Perldocs")) { + my($perl) = $self->perl + or $CPAN::Frontend->mydie("Couldn't find executable perl\n"); + my @args = ($perl, q{-MPod::Perldocs}, q{-e}, + q{Pod::Perldocs->run()}, $package); + my($wstatus); + unless ( ($wstatus = system(@args)) == 0 ) { + my $estatus = $wstatus >> 8; + $CPAN::Frontend->myprint(qq{ + Function system("@args") + returned status $estatus (wstat $wstatus) + }); + } + } + else { + $self->_display_url( $CPAN::Defaultdocs . $package ); + } +} + +#-> sub CPAN::Distribution::_check_binary ; +sub _check_binary { + my ($dist,$shell,$binary) = @_; + my ($pid,$out); + + $CPAN::Frontend->myprint(qq{ + _check_binary($binary)\n}) + if $CPAN::DEBUG; + + if ($CPAN::META->has_inst("File::Which")) { + return File::Which::which($binary); + } else { + local *README; + $pid = open README, "which $binary|" + or $CPAN::Frontend->mywarn(qq{Could not fork 'which $binary': $!\n}); + return unless $pid; + while (<README>) { + $out .= $_; + } + close README + or $CPAN::Frontend->mywarn("Could not run 'which $binary': $!\n") + and return; + } + + $CPAN::Frontend->myprint(qq{ + $out \n}) + if $CPAN::DEBUG && $out; + + return $out; +} + +#-> sub CPAN::Distribution::_display_url ; +sub _display_url { + my($self,$url) = @_; + my($res,$saved_file,$pid,$out); + + $CPAN::Frontend->myprint(qq{ + _display_url($url)\n}) + if $CPAN::DEBUG; + + # should we define it in the config instead? + my $html_converter = "html2text.pl"; + + my $web_browser = $CPAN::Config->{'lynx'} || undef; + my $web_browser_out = $web_browser + ? CPAN::Distribution->_check_binary($self,$web_browser) + : undef; + + if ($web_browser_out) { + # web browser found, run the action + my $browser = CPAN::HandleConfig->safe_quote($CPAN::Config->{'lynx'}); + $CPAN::Frontend->myprint(qq{system[$browser $url]}) + if $CPAN::DEBUG; + $CPAN::Frontend->myprint(qq{ +Displaying URL + $url +with browser $browser +}); + $CPAN::Frontend->mysleep(1); + system("$browser $url"); + if ($saved_file) { 1 while unlink($saved_file) } + } else { + # web browser not found, let's try text only + my $html_converter_out = + CPAN::Distribution->_check_binary($self,$html_converter); + $html_converter_out = CPAN::HandleConfig->safe_quote($html_converter_out); + + if ($html_converter_out ) { + # html2text found, run it + $saved_file = CPAN::Distribution->_getsave_url( $self, $url ); + $CPAN::Frontend->mydie(qq{ERROR: problems while getting $url\n}) + unless defined($saved_file); + + local *README; + $pid = open README, "$html_converter $saved_file |" + or $CPAN::Frontend->mydie(qq{ +Could not fork '$html_converter $saved_file': $!}); + my($fh,$filename); + if ($CPAN::META->has_usable("File::Temp")) { + $fh = File::Temp->new( + dir => File::Spec->tmpdir, + template => 'cpan_htmlconvert_XXXX', + suffix => '.txt', + unlink => 0, + ); + $filename = $fh->filename; + } else { + $filename = "cpan_htmlconvert_$$.txt"; + $fh = FileHandle->new(); + open $fh, ">$filename" or die; + } + while (<README>) { + $fh->print($_); + } + close README or + $CPAN::Frontend->mydie(qq{Could not run '$html_converter $saved_file': $!}); + my $tmpin = $fh->filename; + $CPAN::Frontend->myprint(sprintf(qq{ +Run '%s %s' and +saved output to %s\n}, + $html_converter, + $saved_file, + $tmpin, + )) if $CPAN::DEBUG; + close $fh; + local *FH; + open FH, $tmpin + or $CPAN::Frontend->mydie(qq{Could not open "$tmpin": $!}); + my $fh_pager = FileHandle->new; + local($SIG{PIPE}) = "IGNORE"; + my $pager = $CPAN::Config->{'pager'} || "cat"; + $fh_pager->open("|$pager") + or $CPAN::Frontend->mydie(qq{ +Could not open pager '$pager': $!}); + $CPAN::Frontend->myprint(qq{ +Displaying URL + $url +with pager "$pager" +}); + $CPAN::Frontend->mysleep(1); + $fh_pager->print(<FH>); + $fh_pager->close; + } else { + # coldn't find the web browser or html converter + $CPAN::Frontend->myprint(qq{ +You need to install lynx or $html_converter to use this feature.}); + } + } +} + +#-> sub CPAN::Distribution::_getsave_url ; +sub _getsave_url { + my($dist, $shell, $url) = @_; + + $CPAN::Frontend->myprint(qq{ + _getsave_url($url)\n}) + if $CPAN::DEBUG; + + my($fh,$filename); + if ($CPAN::META->has_usable("File::Temp")) { + $fh = File::Temp->new( + dir => File::Spec->tmpdir, + template => "cpan_getsave_url_XXXX", + suffix => ".html", + unlink => 0, + ); + $filename = $fh->filename; + } else { + $fh = FileHandle->new; + $filename = "cpan_getsave_url_$$.html"; + } + my $tmpin = $filename; + if ($CPAN::META->has_usable('LWP')) { + $CPAN::Frontend->myprint("Fetching with LWP: + $url +"); + my $Ua; + CPAN::LWP::UserAgent->config; + eval { $Ua = CPAN::LWP::UserAgent->new; }; + if ($@) { + $CPAN::Frontend->mywarn("ERROR: CPAN::LWP::UserAgent->new dies with $@\n"); + return; + } else { + my($var); + $Ua->proxy('http', $var) + if $var = $CPAN::Config->{http_proxy} || $ENV{http_proxy}; + $Ua->no_proxy($var) + if $var = $CPAN::Config->{no_proxy} || $ENV{no_proxy}; + } + + my $req = HTTP::Request->new(GET => $url); + $req->header('Accept' => 'text/html'); + my $res = $Ua->request($req); + if ($res->is_success) { + $CPAN::Frontend->myprint(" + request successful.\n") + if $CPAN::DEBUG; + print $fh $res->content; + close $fh; + $CPAN::Frontend->myprint(qq{ + saved content to $tmpin \n}) + if $CPAN::DEBUG; + return $tmpin; + } else { + $CPAN::Frontend->myprint(sprintf( + "LWP failed with code[%s], message[%s]\n", + $res->code, + $res->message, + )); + return; + } + } else { + $CPAN::Frontend->mywarn(" LWP not available\n"); + return; + } +} + +#-> sub CPAN::Distribution::_build_command +sub _build_command { + my($self) = @_; + if ($^O eq "MSWin32") { # special code needed at least up to + # Module::Build 0.2611 and 0.2706; a fix + # in M:B has been promised 2006-01-30 + my($perl) = $self->perl or $CPAN::Frontend->mydie("Couldn't find executable perl\n"); + return "$perl ./Build"; + } + return "./Build"; +} + +#-> sub CPAN::Distribution::_should_report +sub _should_report { + my($self, $phase) = @_; + die "_should_report() requires a 'phase' argument" + if ! defined $phase; + + # configured + my $test_report = CPAN::HandleConfig->prefs_lookup($self, + q{test_report}); + return unless $test_report; + + # don't repeat if we cached a result + return $self->{should_report} + if exists $self->{should_report}; + + # don't report if we generated a Makefile.PL + if ( $self->{had_no_makefile_pl} ) { + $CPAN::Frontend->mywarn( + "Will not send CPAN Testers report with generated Makefile.PL.\n" + ); + return $self->{should_report} = 0; + } + + # available + if ( ! $CPAN::META->has_inst("CPAN::Reporter")) { + $CPAN::Frontend->mywarnonce( + "CPAN::Reporter not installed. No reports will be sent.\n" + ); + return $self->{should_report} = 0; + } + + # capable + my $crv = CPAN::Reporter->VERSION; + if ( CPAN::Version->vlt( $crv, 0.99 ) ) { + # don't cache $self->{should_report} -- need to check each phase + if ( $phase eq 'test' ) { + return 1; + } + else { + $CPAN::Frontend->mywarn( + "Reporting on the '$phase' phase requires CPAN::Reporter 0.99, but \n" . + "you only have version $crv\. Only 'test' phase reports will be sent.\n" + ); + return; + } + } + + # appropriate + if ($self->is_dot_dist) { + $CPAN::Frontend->mywarn("Reporting via CPAN::Reporter is disabled ". + "for local directories\n"); + return $self->{should_report} = 0; + } + if ($self->prefs->{patches} + && + @{$self->prefs->{patches}} + && + $self->{patched} + ) { + $CPAN::Frontend->mywarn("Reporting via CPAN::Reporter is disabled ". + "when the source has been patched\n"); + return $self->{should_report} = 0; + } + + # proceed and cache success + return $self->{should_report} = 1; +} + +#-> sub CPAN::Distribution::reports +sub reports { + my($self) = @_; + my $pathname = $self->id; + $CPAN::Frontend->myprint("Distribution: $pathname\n"); + + unless ($CPAN::META->has_inst("CPAN::DistnameInfo")) { + $CPAN::Frontend->mydie("CPAN::DistnameInfo not installed; cannot continue"); + } + unless ($CPAN::META->has_usable("LWP")) { + $CPAN::Frontend->mydie("LWP not installed; cannot continue"); + } + unless ($CPAN::META->has_usable("File::Temp")) { + $CPAN::Frontend->mydie("File::Temp not installed; cannot continue"); + } + + my $d = CPAN::DistnameInfo->new($pathname); + + my $dist = $d->dist; # "CPAN-DistnameInfo" + my $version = $d->version; # "0.02" + my $maturity = $d->maturity; # "released" + my $filename = $d->filename; # "CPAN-DistnameInfo-0.02.tar.gz" + my $cpanid = $d->cpanid; # "GBARR" + my $distvname = $d->distvname; # "CPAN-DistnameInfo-0.02" + + my $url = sprintf "http://www.cpantesters.org/show/%s.yaml", $dist; + + CPAN::LWP::UserAgent->config; + my $Ua; + eval { $Ua = CPAN::LWP::UserAgent->new; }; + if ($@) { + $CPAN::Frontend->mydie("CPAN::LWP::UserAgent->new dies with $@\n"); + } + $CPAN::Frontend->myprint("Fetching '$url'..."); + my $resp = $Ua->get($url); + unless ($resp->is_success) { + $CPAN::Frontend->mydie(sprintf "Could not download '%s': %s\n", $url, $resp->code); + } + $CPAN::Frontend->myprint("DONE\n\n"); + my $yaml = $resp->content; + # was fuer ein Umweg! + my $fh = File::Temp->new( + dir => File::Spec->tmpdir, + template => 'cpan_reports_XXXX', + suffix => '.yaml', + unlink => 0, + ); + my $tfilename = $fh->filename; + print $fh $yaml; + close $fh or $CPAN::Frontend->mydie("Could not close '$tfilename': $!"); + my $unserialized = CPAN->_yaml_loadfile($tfilename)->[0]; + unlink $tfilename or $CPAN::Frontend->mydie("Could not unlink '$tfilename': $!"); + my %other_versions; + my $this_version_seen; + for my $rep (@$unserialized) { + my $rversion = $rep->{version}; + if ($rversion eq $version) { + unless ($this_version_seen++) { + $CPAN::Frontend->myprint ("$rep->{version}:\n"); + } + my $arch = $rep->{archname} || $rep->{platform} || '????'; + my $grade = $rep->{action} || $rep->{status} || '????'; + my $ostext = $rep->{ostext} || ucfirst($rep->{osname}) || '????'; + $CPAN::Frontend->myprint + (sprintf("%1s%1s%-4s %s on %s %s (%s)\n", + $arch eq $Config::Config{archname}?"*":"", + $grade eq "PASS"?"+":$grade eq"FAIL"?"-":"", + $grade, + $rep->{perl}, + $ostext, + $rep->{osvers}, + $arch, + )); + } else { + $other_versions{$rep->{version}}++; + } + } + unless ($this_version_seen) { + $CPAN::Frontend->myprint("No reports found for version '$version' +Reports for other versions:\n"); + for my $v (sort keys %other_versions) { + $CPAN::Frontend->myprint(" $v\: $other_versions{$v}\n"); + } + } + $url =~ s/\.yaml/.html/; + $CPAN::Frontend->myprint("See $url for details\n"); +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/Distroprefs.pm b/Master/tlpkg/tlperl/lib/CPAN/Distroprefs.pm new file mode 100644 index 00000000000..e1be9cdf749 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Distroprefs.pm @@ -0,0 +1,451 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +# vim: ts=4 sts=4 sw=4: + +use strict; +package CPAN::Distroprefs; + +use vars qw($VERSION); +$VERSION = '6'; + +package CPAN::Distroprefs::Result; + +use File::Spec; + +sub new { bless $_[1] || {} => $_[0] } + +sub abs { File::Spec->catfile($_[0]->dir, $_[0]->file) } + +sub __cloner { + my ($class, $name, $newclass) = @_; + $newclass = 'CPAN::Distroprefs::Result::' . $newclass; + no strict 'refs'; + *{$class . '::' . $name} = sub { + $newclass->new({ + %{ $_[0] }, + %{ $_[1] }, + }); + }; +} +BEGIN { __PACKAGE__->__cloner(as_warning => 'Warning') } +BEGIN { __PACKAGE__->__cloner(as_fatal => 'Fatal') } +BEGIN { __PACKAGE__->__cloner(as_success => 'Success') } + +sub __accessor { + my ($class, $key) = @_; + no strict 'refs'; + *{$class . '::' . $key} = sub { $_[0]->{$key} }; +} +BEGIN { __PACKAGE__->__accessor($_) for qw(type file ext dir) } + +sub is_warning { 0 } +sub is_fatal { 0 } +sub is_success { 0 } + +package CPAN::Distroprefs::Result::Error; +use vars qw(@ISA); +BEGIN { @ISA = 'CPAN::Distroprefs::Result' } ## no critic +BEGIN { __PACKAGE__->__accessor($_) for qw(msg) } + +sub as_string { + my ($self) = @_; + if ($self->msg) { + return sprintf $self->fmt_reason, $self->file, $self->msg; + } else { + return sprintf $self->fmt_unknown, $self->file; + } +} + +package CPAN::Distroprefs::Result::Warning; +use vars qw(@ISA); +BEGIN { @ISA = 'CPAN::Distroprefs::Result::Error' } ## no critic +sub is_warning { 1 } +sub fmt_reason { "Error reading distroprefs file %s, skipping: %s" } +sub fmt_unknown { "Unknown error reading distroprefs file %s, skipping." } + +package CPAN::Distroprefs::Result::Fatal; +use vars qw(@ISA); +BEGIN { @ISA = 'CPAN::Distroprefs::Result::Error' } ## no critic +sub is_fatal { 1 } +sub fmt_reason { "Error reading distroprefs file %s: %s" } +sub fmt_unknown { "Unknown error reading distroprefs file %s." } + +package CPAN::Distroprefs::Result::Success; +use vars qw(@ISA); +BEGIN { @ISA = 'CPAN::Distroprefs::Result' } ## no critic +BEGIN { __PACKAGE__->__accessor($_) for qw(prefs extension) } +sub is_success { 1 } + +package CPAN::Distroprefs::Iterator; + +sub new { bless $_[1] => $_[0] } + +sub next { $_[0]->() } + +package CPAN::Distroprefs; + +use Carp (); +use DirHandle; + +sub _load_method { + my ($self, $loader, $result) = @_; + return '_load_yaml' if $loader eq 'CPAN' or $loader =~ /^YAML(::|$)/; + return '_load_' . $result->ext; +} + +sub _load_yaml { + my ($self, $loader, $result) = @_; + my $data = eval { + $loader eq 'CPAN' + ? $loader->_yaml_loadfile($result->abs) + : [ $loader->can('LoadFile')->($result->abs) ] + }; + if (my $err = $@) { + die $result->as_warning({ + msg => $err, + }); + } elsif (!$data) { + die $result->as_warning; + } else { + return @$data; + } +} + +sub _load_dd { + my ($self, $loader, $result) = @_; + my @data; + { + package CPAN::Eval; + # this caused a die in CPAN.pm, and I am leaving it 'fatal', though I'm + # not sure why we wouldn't just skip the file as we do for all other + # errors. -- hdp + my $abs = $result->abs; + open FH, "<$abs" or die $result->as_fatal(msg => "$!"); + local $/; + my $eval = <FH>; + close FH; + no strict; + eval $eval; + if (my $err = $@) { + die $result->as_warning({ msg => $err }); + } + my $i = 1; + while (${"VAR$i"}) { + push @data, ${"VAR$i"}; + $i++; + } + } + return @data; +} + +sub _load_st { + my ($self, $loader, $result) = @_; + # eval because Storable is never forward compatible + my @data = eval { @{scalar $loader->can('retrieve')->($result->abs) } }; + if (my $err = $@) { + die $result->as_warning({ msg => $err }); + } + return @data; +} + +sub find { + my ($self, $dir, $ext_map) = @_; + + my $dh = DirHandle->new($dir) or Carp::croak("Couldn't open '$dir': $!"); + my @files = sort $dh->read; + + # label the block so that we can use redo in the middle + return CPAN::Distroprefs::Iterator->new(sub { LOOP: { + return unless %$ext_map; + + local $_ = shift @files; + return unless defined; + redo if $_ eq '.' || $_ eq '..'; + + my $possible_ext = join "|", map { quotemeta } keys %$ext_map; + my ($ext) = /\.($possible_ext)$/ or redo; + my $loader = $ext_map->{$ext}; + + my $result = CPAN::Distroprefs::Result->new({ + file => $_, ext => $ext, dir => $dir + }); + # copied from CPAN.pm; is this ever actually possible? + redo unless -f $result->abs; + + my $load_method = $self->_load_method($loader, $result); + my @prefs = eval { $self->$load_method($loader, $result) }; + if (my $err = $@) { + if (ref($err) && eval { $err->isa('CPAN::Distroprefs::Result') }) { + return $err; + } + # rethrow any exceptions that we did not generate + die $err; + } elsif (!@prefs) { + # the loader should have handled this, but just in case: + return $result->as_warning; + } + return $result->as_success({ + prefs => [ + map { CPAN::Distroprefs::Pref->new({ data => $_ }) } @prefs + ], + }); + } }); +} + +package CPAN::Distroprefs::Pref; + +use Carp (); + +sub new { bless $_[1] => $_[0] } + +sub data { shift->{data} } + +sub has_any_match { $_[0]->data->{match} ? 1 : 0 } + +sub has_match { + my $match = $_[0]->data->{match} || return 0; + exists $match->{$_[1]} || exists $match->{"not_$_[1]"} +} + +sub has_valid_subkeys { + grep { exists $_[0]->data->{match}{$_} } + map { $_, "not_$_" } + $_[0]->match_attributes +} + +sub _pattern { + my $re = shift; + my $p = eval sprintf 'qr{%s}', $re; + if ($@) { + $@ =~ s/\n$//; + die "Error in Distroprefs pattern qr{$re}\n$@"; + } + return $p; +} + +sub _match_scalar { + my ($match, $data) = @_; + my $qr = _pattern($match); + return $data =~ /$qr/; +} + +sub _match_hash { + my ($match, $data) = @_; + for my $mkey (keys %$match) { + (my $dkey = $mkey) =~ s/^not_//; + my $val = defined $data->{$dkey} ? $data->{$dkey} : ''; + if (_match_scalar($match->{$mkey}, $val)) { + return 0 if $mkey =~ /^not_/; + } + else { + return 0 if $mkey !~ /^not_/; + } + } + return 1; +} + +sub _match { + my ($self, $key, $data, $matcher) = @_; + my $m = $self->data->{match}; + if (exists $m->{$key}) { + return 0 unless $matcher->($m->{$key}, $data); + } + if (exists $m->{"not_$key"}) { + return 0 if $matcher->($m->{"not_$key"}, $data); + } + return 1; +} + +sub _scalar_match { + my ($self, $key, $data) = @_; + return $self->_match($key, $data, \&_match_scalar); +} + +sub _hash_match { + my ($self, $key, $data) = @_; + return $self->_match($key, $data, \&_match_hash); +} + +# do not take the order of C<keys %$match> because "module" is by far the +# slowest +sub match_attributes { qw(env distribution perl perlconfig module) } + +sub match_module { + my ($self, $modules) = @_; + return $self->_match("module", $modules, sub { + my($match, $data) = @_; + my $qr = _pattern($match); + for my $module (@$data) { + return 1 if $module =~ /$qr/; + } + return 0; + }); +} + +sub match_distribution { shift->_scalar_match(distribution => @_) } +sub match_perl { shift->_scalar_match(perl => @_) } + +sub match_perlconfig { shift->_hash_match(perlconfig => @_) } +sub match_env { shift->_hash_match(env => @_) } + +sub matches { + my ($self, $arg) = @_; + + my $default_match = 0; + for my $key (grep { $self->has_match($_) } $self->match_attributes) { + unless (exists $arg->{$key}) { + Carp::croak "Can't match pref: missing argument key $key"; + } + $default_match = 1; + my $val = $arg->{$key}; + # make it possible to avoid computing things until we have to + if (ref($val) eq 'CODE') { $val = $val->() } + my $meth = "match_$key"; + return 0 unless $self->$meth($val); + } + + return $default_match; +} + +1; + +__END__ + +=head1 NAME + +CPAN::Distroprefs -- read and match distroprefs + +=head1 SYNOPSIS + + use CPAN::Distroprefs; + + my %info = (... distribution/environment info ...); + + my $finder = CPAN::Distroprefs->find($prefs_dir, \%ext_map); + + while (my $result = $finder->next) { + + die $result->as_string if $result->is_fatal; + + warn($result->as_string), next if $result->is_warning; + + for my $pref (@{ $result->prefs }) { + if ($pref->matches(\%info)) { + return $pref; + } + } + } + + +=head1 DESCRIPTION + +This module encapsulates reading L<Distroprefs|CPAN> and matching them against CPAN distributions. + +=head1 INTERFACE + + my $finder = CPAN::Distroprefs->find($dir, \%ext_map); + + while (my $result = $finder->next) { ... } + +Build an iterator which finds distroprefs files in the given directory. + +C<%ext_map> is a hashref whose keys are file extensions and whose values are +modules used to load matching files: + + { + 'yml' => 'YAML::Syck', + 'dd' => 'Data::Dumper', + ... + } + +Each time C<< $finder->next >> is called, the iterator returns one of two +possible values: + +=over + +=item * a CPAN::Distroprefs::Result object + +=item * C<undef>, indicating that no prefs files remain to be found + +=back + +=head1 RESULTS + +L<C<find()>|/INTERFACE> returns CPAN::Distroprefs::Result objects to +indicate success or failure when reading a prefs file. + +=head2 Common + +All results share some common attributes: + +=head3 type + +C<success>, C<warning>, or C<fatal> + +=head3 file + +the file from which these prefs were read, or to which this error refers (relative filename) + +=head3 ext + +the file's extension, which determines how to load it + +=head3 dir + +the directory the file was read from + +=head3 abs + +the absolute path to the file + +=head2 Errors + +Error results (warning and fatal) contain: + +=head3 msg + +the error message (usually either C<$!> or a YAML error) + +=head2 Successes + +Success results contain: + +=head3 prefs + +an arrayref of CPAN::Distroprefs::Pref objects + +=head1 PREFS + +CPAN::Distroprefs::Pref objects represent individual distroprefs documents. +They are constructed automatically as part of C<success> results from C<find()>. + +=head3 data + +the pref information as a hashref, suitable for e.g. passing to Kwalify + +=head3 match_attributes + +returns a list of the valid match attributes (see the Distroprefs section in L<CPAN>) + +currently: C<env perl perlconfig distribution module> + +=head3 has_any_match + +true if this pref has a 'match' attribute at all + +=head3 has_valid_subkeys + +true if this pref has a 'match' attribute and at least one valid match attribute + +=head3 matches + + if ($pref->matches(\%arg)) { ... } + +true if this pref matches the passed-in hashref, which must have a value for +each of the C<match_attributes> (above) + +=head1 LICENSE + +This program is free software; you can redistribute it and/or modify it under +the same terms as Perl itself. + +=cut diff --git a/Master/tlpkg/tlperl/lib/CPAN/Distrostatus.pm b/Master/tlpkg/tlperl/lib/CPAN/Distrostatus.pm new file mode 100644 index 00000000000..0cc6cc9a793 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Distrostatus.pm @@ -0,0 +1,45 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +# vim: ts=4 sts=4 sw=4: +package CPAN::Distrostatus; +use overload '""' => "as_string", + fallback => 1; +use vars qw($something_has_failed_at); +use vars qw( + $VERSION +); +$VERSION = "5.5"; + + +sub new { + my($class,$arg) = @_; + my $failed = substr($arg,0,2) eq "NO"; + if ($failed) { + $something_has_failed_at = $CPAN::CurrentCommandId; + } + bless { + TEXT => $arg, + FAILED => $failed, + COMMANDID => $CPAN::CurrentCommandId, + TIME => time, + }, $class; +} +sub something_has_just_failed () { + defined $something_has_failed_at && + $something_has_failed_at == $CPAN::CurrentCommandId; +} +sub commandid { shift->{COMMANDID} } +sub failed { shift->{FAILED} } +sub text { + my($self,$set) = @_; + if (defined $set) { + $self->{TEXT} = $set; + } + $self->{TEXT}; +} +sub as_string { + my($self) = @_; + $self->text; +} + + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/Exception/RecursiveDependency.pm b/Master/tlpkg/tlperl/lib/CPAN/Exception/RecursiveDependency.pm new file mode 100644 index 00000000000..b928ad74e31 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Exception/RecursiveDependency.pm @@ -0,0 +1,85 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +# vim: ts=4 sts=4 sw=4: +package CPAN::Exception::RecursiveDependency; +use strict; +use overload '""' => "as_string"; + +use vars qw( + $VERSION +); +$VERSION = "5.5"; + +# a module sees its distribution (no version) +# a distribution sees its prereqs (which are module names) (usually with versions) +# a bundle sees its module names and/or its distributions (no version) + +sub new { + my($class) = shift; + my($deps_arg) = shift; + my (@deps,%seen,$loop_starts_with); + DCHAIN: for my $dep (@$deps_arg) { + push @deps, {name => $dep, display_as => $dep}; + if ($seen{$dep}++) { + $loop_starts_with = $dep; + last DCHAIN; + } + } + my $in_loop = 0; + for my $i (0..$#deps) { + my $x = $deps[$i]{name}; + $in_loop ||= $loop_starts_with && $x eq $loop_starts_with; + my $xo = CPAN::Shell->expandany($x) or next; + if ($xo->isa("CPAN::Module")) { + my $have = $xo->inst_version || "N/A"; + my($want,$d,$want_type); + if ($i>0 and $d = $deps[$i-1]{name}) { + my $do = CPAN::Shell->expandany($d); + $want = $do->{prereq_pm}{requires}{$x}; + if (defined $want) { + $want_type = "requires: "; + } else { + $want = $do->{prereq_pm}{build_requires}{$x}; + if (defined $want) { + $want_type = "build_requires: "; + } else { + $want_type = "unknown status"; + $want = "???"; + } + } + } else { + $want = $xo->cpan_version; + $want_type = "want: "; + } + $deps[$i]{have} = $have; + $deps[$i]{want_type} = $want_type; + $deps[$i]{want} = $want; + $deps[$i]{display_as} = "$x (have: $have; $want_type$want)"; + } elsif ($xo->isa("CPAN::Distribution")) { + $deps[$i]{display_as} = $xo->pretty_id; + if ($in_loop) { + $xo->{make} = CPAN::Distrostatus->new("NO cannot resolve circular dependency"); + } else { + $xo->{make} = CPAN::Distrostatus->new("NO one dependency ($loop_starts_with) is a circular dependency"); + } + $xo->store_persistent_state; # otherwise I will not reach + # all involved parties for + # the next session + } + } + bless { deps => \@deps, loop_starts_with => $loop_starts_with }, $class; +} + +sub as_string { + my($self) = shift; + my $deps = $self->{deps}; + my $loop_starts_with = $self->{loop_starts_with}; + unless ($loop_starts_with) { + return "--not a recursive/circular dependency--"; + } + my $ret = "\nRecursive dependency detected:\n "; + $ret .= join("\n => ", map {$_->{display_as}} @$deps); + $ret .= ".\nCannot resolve.\n"; + $ret; +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/Exception/blocked_urllist.pm b/Master/tlpkg/tlperl/lib/CPAN/Exception/blocked_urllist.pm new file mode 100644 index 00000000000..102c194e612 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Exception/blocked_urllist.pm @@ -0,0 +1,46 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +# vim: ts=4 sts=4 sw=4: +package CPAN::Exception::blocked_urllist; +use strict; +use overload '""' => "as_string"; + +use vars qw( + $VERSION +); +$VERSION = "1.0"; + + +sub new { + my($class) = @_; + bless {}, $class; +} + +sub as_string { + my($self) = shift; + if ($CPAN::Config->{connect_to_internet_ok}) { + return qq{ + +You have not configured a urllist for CPAN mirrors. Configure it with + + o conf init urllist + +}; + } else { + return qq{ + +You have not configured a urllist and do not allow connections to the +internet to get a list of mirrors. If you wish to get a list of CPAN +mirrors to pick from, use this command + + o conf init connect_to_internet_ok urllist + +If you do not wish to get a list of mirrors and would prefer to set +your urllist manually, use just this command instead + + o conf init urllist + +}; + } +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/Exception/yaml_not_installed.pm b/Master/tlpkg/tlperl/lib/CPAN/Exception/yaml_not_installed.pm new file mode 100644 index 00000000000..e1259e5397d --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Exception/yaml_not_installed.pm @@ -0,0 +1,73 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +# vim: ts=4 sts=4 sw=4: +package CPAN::Exception::yaml_not_installed; +use strict; +use overload '""' => "as_string"; + +use vars qw( + $VERSION +); +$VERSION = "5.5"; + + +sub new { + my($class,$module,$file,$during) = @_; + bless { module => $module, file => $file, during => $during }, $class; +} + +sub as_string { + my($self) = shift; + "'$self->{module}' not installed, cannot $self->{during} '$self->{file}'\n"; +} + +package CPAN::Exception::yaml_process_error; +use strict; +use overload '""' => "as_string"; + +use vars qw( + $VERSION +); +$VERSION = "5.5"; + + +sub new { + my($class,$module,$file,$during,$error) = @_; + # my $at = Carp::longmess(""); # XXX find something more beautiful + bless { module => $module, + file => $file, + during => $during, + error => $error, + # at => $at, + }, $class; +} + +sub as_string { + my($self) = shift; + if ($self->{during}) { + if ($self->{file}) { + if ($self->{module}) { + if ($self->{error}) { + return "Alert: While trying to '$self->{during}' YAML file\n". + " '$self->{file}'\n". + "with '$self->{module}' the following error was encountered:\n". + " $self->{error}\n"; + } else { + return "Alert: While trying to '$self->{during}' YAML file\n". + " '$self->{file}'\n". + "with '$self->{module}' some unknown error was encountered\n"; + } + } else { + return "Alert: While trying to '$self->{during}' YAML file\n". + " '$self->{file}'\n". + "some unknown error was encountered\n"; + } + } else { + return "Alert: While trying to '$self->{during}' some YAML file\n". + "some unknown error was encountered\n"; + } + } else { + return "Alert: unknown error encountered\n"; + } +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/FTP.pm b/Master/tlpkg/tlperl/lib/CPAN/FTP.pm new file mode 100644 index 00000000000..268ca284678 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/FTP.pm @@ -0,0 +1,1074 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +# vim: ts=4 sts=4 sw=4: +package CPAN::FTP; +use strict; + +use Fcntl qw(:flock); +use File::Basename qw(dirname); +use File::Path qw(mkpath); +use CPAN::FTP::netrc; +use vars qw($connect_to_internet_ok $Ua $Thesite $ThesiteURL $Themethod); + +@CPAN::FTP::ISA = qw(CPAN::Debug); + +use vars qw( + $VERSION +); +$VERSION = "5.5004"; + +#-> sub CPAN::FTP::ftp_statistics +# if they want to rewrite, they need to pass in a filehandle +sub _ftp_statistics { + my($self,$fh) = @_; + my $locktype = $fh ? LOCK_EX : LOCK_SH; + $fh ||= FileHandle->new; + my $file = File::Spec->catfile($CPAN::Config->{cpan_home},"FTPstats.yml"); + mkpath dirname $file; + open $fh, "+>>$file" or $CPAN::Frontend->mydie("Could not open '$file': $!"); + my $sleep = 1; + my $waitstart; + while (!CPAN::_flock($fh, $locktype|LOCK_NB)) { + $waitstart ||= localtime(); + if ($sleep>3) { + $CPAN::Frontend->mywarn("Waiting for a read lock on '$file' (since $waitstart)\n"); + } + $CPAN::Frontend->mysleep($sleep); + if ($sleep <= 3) { + $sleep+=0.33; + } elsif ($sleep <=6) { + $sleep+=0.11; + } + } + my $stats = eval { CPAN->_yaml_loadfile($file); }; + if ($@) { + if (ref $@) { + if (ref $@ eq "CPAN::Exception::yaml_not_installed") { + $CPAN::Frontend->myprint("Warning (usually harmless): $@\n"); + return; + } elsif (ref $@ eq "CPAN::Exception::yaml_process_error") { + $CPAN::Frontend->mydie($@); + } + } else { + $CPAN::Frontend->mydie($@); + } + } + return $stats->[0]; +} + +#-> sub CPAN::FTP::_mytime +sub _mytime () { + if (CPAN->has_inst("Time::HiRes")) { + return Time::HiRes::time(); + } else { + return time; + } +} + +#-> sub CPAN::FTP::_new_stats +sub _new_stats { + my($self,$file) = @_; + my $ret = { + file => $file, + attempts => [], + start => _mytime, + }; + $ret; +} + +#-> sub CPAN::FTP::_add_to_statistics +sub _add_to_statistics { + my($self,$stats) = @_; + my $yaml_module = CPAN::_yaml_module(); + $self->debug("yaml_module[$yaml_module]") if $CPAN::DEBUG; + if ($CPAN::META->has_inst($yaml_module)) { + $stats->{thesiteurl} = $ThesiteURL; + $stats->{end} = CPAN::FTP::_mytime(); + my $fh = FileHandle->new; + my $time = time; + my $sdebug = 0; + my @debug; + @debug = $time if $sdebug; + my $fullstats = $self->_ftp_statistics($fh); + close $fh; + $fullstats->{history} ||= []; + push @debug, scalar @{$fullstats->{history}} if $sdebug; + push @debug, time if $sdebug; + push @{$fullstats->{history}}, $stats; + # YAML.pm 0.62 is unacceptably slow with 999; + # YAML::Syck 0.82 has no noticable performance problem with 999; + my $ftpstats_size = $CPAN::Config->{ftpstats_size} || 99; + my $ftpstats_period = $CPAN::Config->{ftpstats_period} || 14; + while ( + @{$fullstats->{history}} > $ftpstats_size + || $time - $fullstats->{history}[0]{start} > 86400*$ftpstats_period + ) { + shift @{$fullstats->{history}} + } + push @debug, scalar @{$fullstats->{history}} if $sdebug; + push @debug, time if $sdebug; + push @debug, scalar localtime($fullstats->{history}[0]{start}) if $sdebug; + # need no eval because if this fails, it is serious + my $sfile = File::Spec->catfile($CPAN::Config->{cpan_home},"FTPstats.yml"); + CPAN->_yaml_dumpfile("$sfile.$$",$fullstats); + if ( $sdebug ) { + local $CPAN::DEBUG = 512; # FTP + push @debug, time; + CPAN->debug(sprintf("DEBUG history: before_read[%d]before[%d]at[%d]". + "after[%d]at[%d]oldest[%s]dumped backat[%d]", + @debug, + )); + } + # Win32 cannot rename a file to an existing filename + unlink($sfile) if ($^O eq 'MSWin32' or $^O eq 'os2'); + _copy_stat($sfile, "$sfile.$$") if -e $sfile; + rename "$sfile.$$", $sfile + or $CPAN::Frontend->mydie("Could not rename '$sfile.$$' to '$sfile': $!\n"); + } +} + +# Copy some stat information (owner, group, mode and) from one file to +# another. +# This is a utility function which might be moved to a utility repository. +#-> sub CPAN::FTP::_copy_stat +sub _copy_stat { + my($src, $dest) = @_; + my @stat = stat($src); + if (!@stat) { + $CPAN::Frontend->mywarn("Can't stat '$src': $!\n"); + return; + } + + eval { + chmod $stat[2], $dest + or $CPAN::Frontend->mywarn("Can't chmod '$dest' to " . sprintf("0%o", $stat[2]) . ": $!\n"); + }; + warn $@ if $@; + eval { + chown $stat[4], $stat[5], $dest + or do { + my $save_err = $!; # otherwise it's lost in the get... calls + $CPAN::Frontend->mywarn("Can't chown '$dest' to " . + (getpwuid($stat[4]))[0] . "/" . + (getgrgid($stat[5]))[0] . ": $save_err\n" + ); + }; + }; + warn $@ if $@; +} + +# if file is CHECKSUMS, suggest the place where we got the file to be +# checked from, maybe only for young files? +#-> sub CPAN::FTP::_recommend_url_for +sub _recommend_url_for { + my($self, $file, $urllist) = @_; + if ($file =~ s|/CHECKSUMS(.gz)?$||) { + my $fullstats = $self->_ftp_statistics(); + my $history = $fullstats->{history} || []; + while (my $last = pop @$history) { + last if $last->{end} - time > 3600; # only young results are interesting + next unless $last->{file}; # dirname of nothing dies! + next unless $file eq dirname($last->{file}); + return $last->{thesiteurl}; + } + } + if ($CPAN::Config->{randomize_urllist} + && + rand(1) < $CPAN::Config->{randomize_urllist} + ) { + $urllist->[int rand scalar @$urllist]; + } else { + return (); + } +} + +#-> sub CPAN::FTP::_get_urllist +sub _get_urllist { + my($self, $with_defaults) = @_; + $with_defaults ||= 0; + CPAN->debug("with_defaults[$with_defaults]") if $CPAN::DEBUG; + + $CPAN::Config->{urllist} ||= []; + unless (ref $CPAN::Config->{urllist} eq 'ARRAY') { + $CPAN::Frontend->mywarn("Malformed urllist; ignoring. Configuration file corrupt?\n"); + $CPAN::Config->{urllist} = []; + } + my @urllist = grep { defined $_ and length $_ } @{$CPAN::Config->{urllist}}; + push @urllist, @CPAN::Defaultsites if $with_defaults; + for my $u (@urllist) { + CPAN->debug("u[$u]") if $CPAN::DEBUG; + if (UNIVERSAL::can($u,"text")) { + $u->{TEXT} .= "/" unless substr($u->{TEXT},-1) eq "/"; + } else { + $u .= "/" unless substr($u,-1) eq "/"; + $u = CPAN::URL->new(TEXT => $u, FROM => "USER"); + } + } + \@urllist; +} + +#-> sub CPAN::FTP::ftp_get ; +sub ftp_get { + my($class,$host,$dir,$file,$target) = @_; + $class->debug( + qq[Going to fetch file [$file] from dir [$dir] + on host [$host] as local [$target]\n] + ) if $CPAN::DEBUG; + my $ftp = Net::FTP->new($host); + unless ($ftp) { + $CPAN::Frontend->mywarn(" Could not connect to host '$host' with Net::FTP\n"); + return; + } + return 0 unless defined $ftp; + $ftp->debug(1) if $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG; + $class->debug(qq[Going to login("anonymous","$Config::Config{cf_email}")]); + unless ( $ftp->login("anonymous",$Config::Config{'cf_email'}) ) { + my $msg = $ftp->message; + $CPAN::Frontend->mywarn(" Couldn't login on $host: $msg\n"); + return; + } + unless ( $ftp->cwd($dir) ) { + my $msg = $ftp->message; + $CPAN::Frontend->mywarn(" Couldn't cwd $dir: $msg\n"); + return; + } + $ftp->binary; + $class->debug(qq[Going to ->get("$file","$target")\n]) if $CPAN::DEBUG; + unless ( $ftp->get($file,$target) ) { + my $msg = $ftp->message; + $CPAN::Frontend->mywarn(" Couldn't fetch $file from $host: $msg\n"); + return; + } + $ftp->quit; # it's ok if this fails + return 1; +} + +# If more accuracy is wanted/needed, Chris Leach sent me this patch... + + # > *** /install/perl/live/lib/CPAN.pm- Wed Sep 24 13:08:48 1997 + # > --- /tmp/cp Wed Sep 24 13:26:40 1997 + # > *************** + # > *** 1562,1567 **** + # > --- 1562,1580 ---- + # > return 1 if substr($url,0,4) eq "file"; + # > return 1 unless $url =~ m|://([^/]+)|; + # > my $host = $1; + # > + my $proxy = $CPAN::Config->{'http_proxy'} || $ENV{'http_proxy'}; + # > + if ($proxy) { + # > + $proxy =~ m|://([^/:]+)|; + # > + $proxy = $1; + # > + my $noproxy = $CPAN::Config->{'no_proxy'} || $ENV{'no_proxy'}; + # > + if ($noproxy) { + # > + if ($host !~ /$noproxy$/) { + # > + $host = $proxy; + # > + } + # > + } else { + # > + $host = $proxy; + # > + } + # > + } + # > require Net::Ping; + # > return 1 unless $Net::Ping::VERSION >= 2; + # > my $p; + + +#-> sub CPAN::FTP::localize ; +sub localize { + my($self,$file,$aslocal,$force,$with_defaults) = @_; + $force ||= 0; + Carp::croak( "Usage: ->localize(cpan_file,as_local_file[,\$force])" ) + unless defined $aslocal; + if ($CPAN::DEBUG){ + require Carp; + my $longmess = Carp::longmess(); + $self->debug("file[$file] aslocal[$aslocal] force[$force] carplongmess[$longmess]"); + } + if ($^O eq 'MacOS') { + # Comment by AK on 2000-09-03: Uniq short filenames would be + # available in CHECKSUMS file + my($name, $path) = File::Basename::fileparse($aslocal, ''); + if (length($name) > 31) { + $name =~ s/( + \.( + readme(\.(gz|Z))? | + (tar\.)?(gz|Z) | + tgz | + zip | + pm\.(gz|Z) + ) + )$//x; + my $suf = $1; + my $size = 31 - length($suf); + while (length($name) > $size) { + chop $name; + } + $name .= $suf; + $aslocal = File::Spec->catfile($path, $name); + } + } + + if (-f $aslocal && -r _ && !($force & 1)) { + my $size; + if ($size = -s $aslocal) { + $self->debug("aslocal[$aslocal]size[$size]") if $CPAN::DEBUG; + return $aslocal; + } else { + # empty file from a previous unsuccessful attempt to download it + unlink $aslocal or + $CPAN::Frontend->mydie("Found a zero-length '$aslocal' that I ". + "could not remove."); + } + } + my($maybe_restore) = 0; + if (-f $aslocal) { + rename $aslocal, "$aslocal.bak$$"; + $maybe_restore++; + } + + my($aslocal_dir) = dirname($aslocal); + # Inheritance is not easier to manage than a few if/else branches + if ($CPAN::META->has_usable('LWP::UserAgent')) { + unless ($Ua) { + CPAN::LWP::UserAgent->config; + eval {$Ua = CPAN::LWP::UserAgent->new;}; # Why is has_usable still not fit enough? + if ($@) { + $CPAN::Frontend->mywarn("CPAN::LWP::UserAgent->new dies with $@\n") + if $CPAN::DEBUG; + } else { + my($var); + $Ua->proxy('ftp', $var) + if $var = $CPAN::Config->{ftp_proxy} || $ENV{ftp_proxy}; + $Ua->proxy('http', $var) + if $var = $CPAN::Config->{http_proxy} || $ENV{http_proxy}; + $Ua->no_proxy($var) + if $var = $CPAN::Config->{no_proxy} || $ENV{no_proxy}; + } + } + } + for my $prx (qw(ftp_proxy http_proxy no_proxy)) { + $ENV{$prx} = $CPAN::Config->{$prx} if $CPAN::Config->{$prx}; + } + + # Try the list of urls for each single object. We keep a record + # where we did get a file from + my(@reordered,$last); + my $ccurllist = $self->_get_urllist($with_defaults); + $last = $#$ccurllist; + if ($force & 2) { # local cpans probably out of date, don't reorder + @reordered = (0..$last); + } else { + @reordered = + sort { + (substr($ccurllist->[$b],0,4) eq "file") + <=> + (substr($ccurllist->[$a],0,4) eq "file") + or + defined($ThesiteURL) + and + ($ccurllist->[$b] eq $ThesiteURL) + <=> + ($ccurllist->[$a] eq $ThesiteURL) + } 0..$last; + } + my(@levels); + $Themethod ||= ""; + $self->debug("Themethod[$Themethod]reordered[@reordered]") if $CPAN::DEBUG; + my @all_levels = ( + ["dleasy", "file"], + ["dleasy"], + ["dlhard"], + ["dlhardest"], + ["dleasy", "http","defaultsites"], + ["dlhard", "http","defaultsites"], + ["dleasy", "ftp", "defaultsites"], + ["dlhard", "ftp", "defaultsites"], + ["dlhardest","", "defaultsites"], + ); + if ($Themethod) { + @levels = grep {$_->[0] eq $Themethod} @all_levels; + push @levels, grep {$_->[0] ne $Themethod} @all_levels; + } else { + @levels = @all_levels; + } + @levels = qw/dleasy/ if $^O eq 'MacOS'; + my($levelno); + local $ENV{FTP_PASSIVE} = + exists $CPAN::Config->{ftp_passive} ? + $CPAN::Config->{ftp_passive} : 1; + my $ret; + my $stats = $self->_new_stats($file); + for ($CPAN::Config->{connect_to_internet_ok}) { + $connect_to_internet_ok = $_ if not defined $connect_to_internet_ok and defined $_; + } + LEVEL: for $levelno (0..$#levels) { + my $level_tuple = $levels[$levelno]; + my($level,$scheme,$sitetag) = @$level_tuple; + $self->mymkpath($aslocal_dir) unless $scheme && "file" eq $scheme; + my $defaultsites = $sitetag && $sitetag eq "defaultsites" && !@$ccurllist; + my @urllist; + if ($defaultsites) { + unless (defined $connect_to_internet_ok) { + $CPAN::Frontend->myprint(sprintf qq{ +I would like to connect to one of the following sites to get '%s': + +%s +}, + $file, + join("",map { " ".$_->text."\n" } @CPAN::Defaultsites), + ); + my $answer = CPAN::Shell::colorable_makemaker_prompt("Is it OK to try to connect to the Internet?", "yes"); + if ($answer =~ /^y/i) { + $connect_to_internet_ok = 1; + } else { + $connect_to_internet_ok = 0; + } + } + if ($connect_to_internet_ok) { + @urllist = @CPAN::Defaultsites; + } else { + my $sleep = 2; + # the tricky thing about dying here is that everybody + # believes that calls to exists() or all_objects() are + # safe. + require CPAN::Exception::blocked_urllist; + die CPAN::Exception::blocked_urllist->new; + } + } else { # ! $defaultsites + my @host_seq = $level =~ /dleasy/ ? + @reordered : 0..$last; # reordered has file and $Thesiteurl first + @urllist = map { $ccurllist->[$_] } @host_seq; + } + $self->debug("synth. urllist[@urllist]") if $CPAN::DEBUG; + my $aslocal_tempfile = $aslocal . ".tmp" . $$; + if (my $recommend = $self->_recommend_url_for($file,\@urllist)) { + @urllist = grep { $_ ne $recommend } @urllist; + unshift @urllist, $recommend; + } + $self->debug("synth. urllist[@urllist]") if $CPAN::DEBUG; + $ret = $self->hostdlxxx($level,$scheme,\@urllist,$file,$aslocal_tempfile,$stats); + if ($ret) { + CPAN->debug("ret[$ret]aslocal[$aslocal]") if $CPAN::DEBUG; + if ($ret eq $aslocal_tempfile) { + # if we got it exactly as we asked for, only then we + # want to rename + rename $aslocal_tempfile, $aslocal + or $CPAN::Frontend->mydie("Error while trying to rename ". + "'$ret' to '$aslocal': $!"); + $ret = $aslocal; + } + elsif (-f $ret && $scheme eq 'file' ) { + # it's a local file, so there's nothing left to do, we + # let them read from where it is + } + $Themethod = $level; + my $now = time; + # utime $now, $now, $aslocal; # too bad, if we do that, we + # might alter a local mirror + $self->debug("level[$level]") if $CPAN::DEBUG; + last LEVEL; + } else { + unlink $aslocal_tempfile; + last if $CPAN::Signal; # need to cleanup + } + } + if ($ret) { + $stats->{filesize} = -s $ret; + } + $self->debug("before _add_to_statistics") if $CPAN::DEBUG; + $self->_add_to_statistics($stats); + $self->debug("after _add_to_statistics") if $CPAN::DEBUG; + if ($ret) { + unlink "$aslocal.bak$$"; + return $ret; + } + unless ($CPAN::Signal) { + my(@mess); + local $" = " "; + if (@{$CPAN::Config->{urllist}}) { + push @mess, + qq{Please check, if the URLs I found in your configuration file \(}. + join(", ", @{$CPAN::Config->{urllist}}). + qq{\) are valid.}; + } else { + push @mess, qq{Your urllist is empty!}; + } + push @mess, qq{The urllist can be edited.}, + qq{E.g. with 'o conf urllist push ftp://myurl/'}; + $CPAN::Frontend->mywarn(Text::Wrap::wrap("","","@mess"). "\n\n"); + $CPAN::Frontend->mydie("Could not fetch $file\n"); + } + if ($maybe_restore) { + rename "$aslocal.bak$$", $aslocal; + $CPAN::Frontend->myprint("Trying to get away with old file:\n" . + $self->ls($aslocal) . "\n"); + return $aslocal; + } + return; +} + +sub mymkpath { + my($self, $aslocal_dir) = @_; + mkpath($aslocal_dir); + $CPAN::Frontend->mywarn(qq{Warning: You are not allowed to write into }. + qq{directory "$aslocal_dir". + I\'ll continue, but if you encounter problems, they may be due + to insufficient permissions.\n}) unless -w $aslocal_dir; +} + +sub hostdlxxx { + my $self = shift; + my $level = shift; + my $scheme = shift; + my $h = shift; + $h = [ grep /^\Q$scheme\E:/, @$h ] if $scheme; + my $method = "host$level"; + $self->$method($h, @_); +} + +sub _set_attempt { + my($self,$stats,$method,$url) = @_; + push @{$stats->{attempts}}, { + method => $method, + start => _mytime, + url => $url, + }; +} + +# package CPAN::FTP; +sub hostdleasy { #called from hostdlxxx + my($self,$host_seq,$file,$aslocal,$stats) = @_; + my($ro_url); + HOSTEASY: for $ro_url (@$host_seq) { + $self->_set_attempt($stats,"dleasy",$ro_url); + my $url .= "$ro_url$file"; + $self->debug("localizing perlish[$url]") if $CPAN::DEBUG; + if ($url =~ /^file:/) { + my $l; + if ($CPAN::META->has_inst('URI::URL')) { + my $u = URI::URL->new($url); + $l = $u->file; + } else { # works only on Unix, is poorly constructed, but + # hopefully better than nothing. + # RFC 1738 says fileurl BNF is + # fileurl = "file://" [ host | "localhost" ] "/" fpath + # Thanks to "Mark D. Baushke" <mdb@cisco.com> for + # the code + ($l = $url) =~ s|^file://[^/]*/|/|; # discard the host part + $l =~ s|^file:||; # assume they + # meant + # file://localhost + $l =~ s|^/||s + if ! -f $l && $l =~ m|^/\w:|; # e.g. /P: + } + $self->debug("local file[$l]") if $CPAN::DEBUG; + if ( -f $l && -r _) { + $ThesiteURL = $ro_url; + return $l; + } + # If request is for a compressed file and we can find the + # uncompressed file also, return the path of the uncompressed file + # otherwise, decompress it and return the resulting path + if ($l =~ /(.+)\.gz$/) { + my $ungz = $1; + if ( -f $ungz && -r _) { + $ThesiteURL = $ro_url; + return $ungz; + } + else { + eval { CPAN::Tarzip->new($l)->gunzip($aslocal) }; + if ( -f $aslocal) { + $ThesiteURL = $ro_url; + return $aslocal; + } + else { + $CPAN::Frontend->mywarn("Error decompressing '$l': $@\n") + if $@; + return; + } + } + } + # Otherwise, return the local file path if it exists + elsif ( -f $l && -r _) { + $ThesiteURL = $ro_url; + return $l; + } + # If we can't find it, but there is a compressed version + # of it, then decompress it + elsif (-f "$l.gz") { + $self->debug("found compressed $l.gz") if $CPAN::DEBUG; + eval { CPAN::Tarzip->new("$l.gz")->gunzip($aslocal) }; + if ( -f $aslocal) { + $ThesiteURL = $ro_url; + return $aslocal; + } + else { + $CPAN::Frontend->mywarn("Error decompressing '$l': $@\n") + if $@; + return; + } + } + $CPAN::Frontend->mywarn("Could not find '$l'\n"); + } + $self->debug("it was not a file URL") if $CPAN::DEBUG; + if ($CPAN::META->has_usable('LWP')) { + $CPAN::Frontend->myprint("Fetching with LWP:\n$url\n"); + unless ($Ua) { + CPAN::LWP::UserAgent->config; + eval { $Ua = CPAN::LWP::UserAgent->new; }; + if ($@) { + $CPAN::Frontend->mywarn("CPAN::LWP::UserAgent->new dies with $@\n"); + } + } + my $res = $Ua->mirror($url, $aslocal); + if ($res->is_success) { + $ThesiteURL = $ro_url; + my $now = time; + utime $now, $now, $aslocal; # download time is more + # important than upload + # time + return $aslocal; + } elsif ($url !~ /\.gz(?!\n)\Z/) { + my $gzurl = "$url.gz"; + $CPAN::Frontend->myprint("Fetching with LWP:\n$gzurl\n"); + $res = $Ua->mirror($gzurl, "$aslocal.gz"); + if ($res->is_success) { + if (eval {CPAN::Tarzip->new("$aslocal.gz")->gunzip($aslocal)}) { + $ThesiteURL = $ro_url; + return $aslocal; + } + } + } else { + $CPAN::Frontend->myprint(sprintf( + "LWP failed with code[%s] message[%s]\n", + $res->code, + $res->message, + )); + # Alan Burlison informed me that in firewall environments + # Net::FTP can still succeed where LWP fails. So we do not + # skip Net::FTP anymore when LWP is available. + } + } else { + $CPAN::Frontend->mywarn(" LWP not available\n"); + } + return if $CPAN::Signal; + if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) { + # that's the nice and easy way thanks to Graham + $self->debug("recognized ftp") if $CPAN::DEBUG; + my($host,$dir,$getfile) = ($1,$2,$3); + if ($CPAN::META->has_usable('Net::FTP')) { + $dir =~ s|/+|/|g; + $CPAN::Frontend->myprint("Fetching with Net::FTP:\n$url\n"); + $self->debug("getfile[$getfile]dir[$dir]host[$host]" . + "aslocal[$aslocal]") if $CPAN::DEBUG; + if (CPAN::FTP->ftp_get($host,$dir,$getfile,$aslocal)) { + $ThesiteURL = $ro_url; + return $aslocal; + } + if ($aslocal !~ /\.gz(?!\n)\Z/) { + my $gz = "$aslocal.gz"; + $CPAN::Frontend->myprint("Fetching with Net::FTP\n$url.gz\n"); + if (CPAN::FTP->ftp_get($host, + $dir, + "$getfile.gz", + $gz) && + eval{CPAN::Tarzip->new($gz)->gunzip($aslocal)} + ) { + $ThesiteURL = $ro_url; + return $aslocal; + } + } + # next HOSTEASY; + } else { + CPAN->debug("Net::FTP does not count as usable atm") if $CPAN::DEBUG; + } + } + if ( + UNIVERSAL::can($ro_url,"text") + and + $ro_url->{FROM} eq "USER" + ) { + ##address #17973: default URLs should not try to override + ##user-defined URLs just because LWP is not available + my $ret = $self->hostdlhard([$ro_url],$file,$aslocal,$stats); + return $ret if $ret; + } + return if $CPAN::Signal; + } +} + +# package CPAN::FTP; +sub hostdlhard { + my($self,$host_seq,$file,$aslocal,$stats) = @_; + + # Came back if Net::FTP couldn't establish connection (or + # failed otherwise) Maybe they are behind a firewall, but they + # gave us a socksified (or other) ftp program... + + my($ro_url); + my($devnull) = $CPAN::Config->{devnull} || ""; + # < /dev/null "; + my($aslocal_dir) = dirname($aslocal); + mkpath($aslocal_dir); + my $some_dl_success = 0; + my $any_attempt = 0; + HOSTHARD: for $ro_url (@$host_seq) { + $self->_set_attempt($stats,"dlhard",$ro_url); + my $url = "$ro_url$file"; + my($proto,$host,$dir,$getfile); + + # Courtesy Mark Conty mark_conty@cargill.com change from + # if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) { + # to + if ($url =~ m|^([^:]+)://(.*?)/(.*)/(.*)|) { + # proto not yet used + ($proto,$host,$dir,$getfile) = ($1,$2,$3,$4); + } else { + next HOSTHARD; # who said, we could ftp anything except ftp? + } + next HOSTHARD if $proto eq "file"; # file URLs would have had + # success above. Likely a bogus URL + + # making at least one attempt against a host + $any_attempt++; + + $self->debug("localizing funkyftpwise[$url]") if $CPAN::DEBUG; + + # Try the most capable first and leave ncftp* for last as it only + # does FTP. + my $proxy_vars = $self->_proxy_vars($ro_url); + DLPRG: for my $f (qw(curl wget lynx ncftpget ncftp)) { + my $funkyftp = CPAN::HandleConfig->safe_quote($CPAN::Config->{$f}); + next DLPRG unless defined $funkyftp; + next DLPRG if $funkyftp =~ /^\s*$/; + + my($src_switch) = ""; + my($chdir) = ""; + my($stdout_redir) = " > \"$aslocal\""; + if ($f eq "lynx") { + $src_switch = " -source"; + } elsif ($f eq "ncftp") { + next DLPRG unless $url =~ m{\Aftp://}; + $src_switch = " -c"; + } elsif ($f eq "wget") { + $src_switch = " -O \"$aslocal\""; + $stdout_redir = ""; + } elsif ($f eq 'curl') { + $src_switch = ' -L -f -s -S --netrc-optional'; + if ($proxy_vars->{http_proxy}) { + $src_switch .= qq{ -U "$proxy_vars->{proxy_user}:$proxy_vars->{proxy_pass}" -x "$proxy_vars->{http_proxy}"}; + } + } elsif ($f eq "ncftpget") { + next DLPRG unless $url =~ m{\Aftp://}; + $chdir = "cd $aslocal_dir && "; + $stdout_redir = ""; + } + $CPAN::Frontend->myprint( + qq[ +Trying with + $funkyftp$src_switch +to get + $url +]); + my($system) = + "$chdir$funkyftp$src_switch \"$url\" $devnull$stdout_redir"; + $self->debug("system[$system]") if $CPAN::DEBUG; + my($wstatus) = system($system); + if ($f eq "lynx") { + # lynx returns 0 when it fails somewhere + if (-s $aslocal) { + my $content = do { local *FH; + open FH, $aslocal or die; + local $/; + <FH> }; + if ($content =~ /^<.*(<title>[45]|Error [45])/si) { + $CPAN::Frontend->mywarn(qq{ +No success, the file that lynx has downloaded looks like an error message: +$content +}); + $CPAN::Frontend->mysleep(1); + next DLPRG; + } + $some_dl_success++; + } else { + $CPAN::Frontend->myprint(qq{ +No success, the file that lynx has downloaded is an empty file. +}); + next DLPRG; + } + } + if ($wstatus == 0) { + if (-s $aslocal) { + # Looks good + $some_dl_success++; + } + $ThesiteURL = $ro_url; + return $aslocal; + } else { + my $estatus = $wstatus >> 8; + my $size = -f $aslocal ? + ", left\n$aslocal with size ".-s _ : + "\nWarning: expected file [$aslocal] doesn't exist"; + $CPAN::Frontend->myprint(qq{ + Function system("$system") + returned status $estatus (wstat $wstatus)$size + }); + } + return if $CPAN::Signal; + } # download/transfer programs (DLPRG) + } # host + return unless $any_attempt; + if ($some_dl_success) { + $CPAN::Frontend->mywarn("Warning: doesn't seem we had substantial success downloading '$aslocal'. Don't know how to proceed.\n"); + } else { + $CPAN::Frontend->mywarn("Warning: no success downloading '$aslocal'. Giving up on it.\n"); + } + return; +} + +#-> CPAN::FTP::_proxy_vars +sub _proxy_vars { + my($self,$url) = @_; + my $ret = +{}; + my $http_proxy = $CPAN::Config->{'http_proxy'} || $ENV{'http_proxy'}; + if ($http_proxy) { + my($host) = $url =~ m|://([^/:]+)|; + my $want_proxy = 1; + my $noproxy = $CPAN::Config->{'no_proxy'} || $ENV{'no_proxy'} || ""; + my @noproxy = split /\s*,\s*/, $noproxy; + if ($host) { + DOMAIN: for my $domain (@noproxy) { + if ($host =~ /\Q$domain\E$/) { # cf. LWP::UserAgent + $want_proxy = 0; + last DOMAIN; + } + } + } else { + $CPAN::Frontend->mywarn(" Could not determine host from http_proxy '$http_proxy'\n"); + } + if ($want_proxy) { + my($user, $pass) = + &CPAN::LWP::UserAgent::get_proxy_credentials(); + $ret = { + proxy_user => $user, + proxy_pass => $pass, + http_proxy => $http_proxy + }; + } + } + return $ret; +} + +# package CPAN::FTP; +sub hostdlhardest { + my($self,$host_seq,$file,$aslocal,$stats) = @_; + + return unless @$host_seq; + my($ro_url); + my($aslocal_dir) = dirname($aslocal); + mkpath($aslocal_dir); + my $ftpbin = $CPAN::Config->{ftp}; + unless ($ftpbin && length $ftpbin && MM->maybe_command($ftpbin)) { + $CPAN::Frontend->myprint("No external ftp command available\n\n"); + return; + } + $CPAN::Frontend->mywarn(qq{ +As a last resort we now switch to the external ftp command '$ftpbin' +to get '$aslocal'. + +Doing so often leads to problems that are hard to diagnose. + +If you're the victim of such problems, please consider unsetting the +ftp config variable with + + o conf ftp "" + o conf commit + +}); + $CPAN::Frontend->mysleep(2); + HOSTHARDEST: for $ro_url (@$host_seq) { + $self->_set_attempt($stats,"dlhardest",$ro_url); + my $url = "$ro_url$file"; + $self->debug("localizing ftpwise[$url]") if $CPAN::DEBUG; + unless ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) { + next; + } + my($host,$dir,$getfile) = ($1,$2,$3); + my $timestamp = 0; + my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime, + $ctime,$blksize,$blocks) = stat($aslocal); + $timestamp = $mtime ||= 0; + my($netrc) = CPAN::FTP::netrc->new; + my($netrcfile) = $netrc->netrc; + my($verbose) = $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG ? " -v" : ""; + my $targetfile = File::Basename::basename($aslocal); + my(@dialog); + push( + @dialog, + "lcd $aslocal_dir", + "cd /", + map("cd $_", split /\//, $dir), # RFC 1738 + "bin", + "passive", + "get $getfile $targetfile", + "quit" + ); + if (! $netrcfile) { + CPAN->debug("No ~/.netrc file found") if $CPAN::DEBUG; + } elsif ($netrc->hasdefault || $netrc->contains($host)) { + CPAN->debug(sprintf("hasdef[%d]cont($host)[%d]", + $netrc->hasdefault, + $netrc->contains($host))) if $CPAN::DEBUG; + if ($netrc->protected) { + my $dialog = join "", map { " $_\n" } @dialog; + my $netrc_explain; + if ($netrc->contains($host)) { + $netrc_explain = "Relying that your .netrc entry for '$host' ". + "manages the login"; + } else { + $netrc_explain = "Relying that your default .netrc entry ". + "manages the login"; + } + $CPAN::Frontend->myprint(qq{ + Trying with external ftp to get + '$url' + $netrc_explain + Going to send the dialog +$dialog +} + ); + $self->talk_ftp("$ftpbin$verbose $host", + @dialog); + ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, + $atime,$mtime,$ctime,$blksize,$blocks) = stat($aslocal); + $mtime ||= 0; + if ($mtime > $timestamp) { + $CPAN::Frontend->myprint("GOT $aslocal\n"); + $ThesiteURL = $ro_url; + return $aslocal; + } else { + $CPAN::Frontend->myprint("Hmm... Still failed!\n"); + } + return if $CPAN::Signal; + } else { + $CPAN::Frontend->mywarn(qq{Your $netrcfile is not }. + qq{correctly protected.\n}); + } + } else { + $CPAN::Frontend->mywarn("Your ~/.netrc neither contains $host + nor does it have a default entry\n"); + } + + # OK, they don't have a valid ~/.netrc. Use 'ftp -n' + # then and login manually to host, using e-mail as + # password. + $CPAN::Frontend->myprint(qq{Issuing "$ftpbin$verbose -n"\n}); + unshift( + @dialog, + "open $host", + "user anonymous $Config::Config{'cf_email'}" + ); + my $dialog = join "", map { " $_\n" } @dialog; + $CPAN::Frontend->myprint(qq{ + Trying with external ftp to get + $url + Going to send the dialog +$dialog +} + ); + $self->talk_ftp("$ftpbin$verbose -n", @dialog); + ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, + $atime,$mtime,$ctime,$blksize,$blocks) = stat($aslocal); + $mtime ||= 0; + if ($mtime > $timestamp) { + $CPAN::Frontend->myprint("GOT $aslocal\n"); + $ThesiteURL = $ro_url; + return $aslocal; + } else { + $CPAN::Frontend->myprint("Bad luck... Still failed!\n"); + } + return if $CPAN::Signal; + $CPAN::Frontend->mywarn("Can't access URL $url.\n\n"); + $CPAN::Frontend->mysleep(2); + } # host +} + +# package CPAN::FTP; +sub talk_ftp { + my($self,$command,@dialog) = @_; + my $fh = FileHandle->new; + $fh->open("|$command") or die "Couldn't open ftp: $!"; + foreach (@dialog) { $fh->print("$_\n") } + $fh->close; # Wait for process to complete + my $wstatus = $?; + my $estatus = $wstatus >> 8; + $CPAN::Frontend->myprint(qq{ +Subprocess "|$command" + returned status $estatus (wstat $wstatus) +}) if $wstatus; +} + +# find2perl needs modularization, too, all the following is stolen +# from there +# CPAN::FTP::ls +sub ls { + my($self,$name) = @_; + my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$sizemm, + $atime,$mtime,$ctime,$blksize,$blocks) = lstat($name); + + my($perms,%user,%group); + my $pname = $name; + + if ($blocks) { + $blocks = int(($blocks + 1) / 2); + } + else { + $blocks = int(($sizemm + 1023) / 1024); + } + + if (-f _) { $perms = '-'; } + elsif (-d _) { $perms = 'd'; } + elsif (-c _) { $perms = 'c'; $sizemm = &sizemm; } + elsif (-b _) { $perms = 'b'; $sizemm = &sizemm; } + elsif (-p _) { $perms = 'p'; } + elsif (-S _) { $perms = 's'; } + else { $perms = 'l'; $pname .= ' -> ' . readlink($_); } + + my(@rwx) = ('---','--x','-w-','-wx','r--','r-x','rw-','rwx'); + my(@moname) = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); + my $tmpmode = $mode; + my $tmp = $rwx[$tmpmode & 7]; + $tmpmode >>= 3; + $tmp = $rwx[$tmpmode & 7] . $tmp; + $tmpmode >>= 3; + $tmp = $rwx[$tmpmode & 7] . $tmp; + substr($tmp,2,1) =~ tr/-x/Ss/ if -u _; + substr($tmp,5,1) =~ tr/-x/Ss/ if -g _; + substr($tmp,8,1) =~ tr/-x/Tt/ if -k _; + $perms .= $tmp; + + my $user = $user{$uid} || $uid; # too lazy to implement lookup + my $group = $group{$gid} || $gid; + + my($sec,$min,$hour,$mday,$mon,$year) = localtime($mtime); + my($timeyear); + my($moname) = $moname[$mon]; + if (-M _ > 365.25 / 2) { + $timeyear = $year + 1900; + } + else { + $timeyear = sprintf("%02d:%02d", $hour, $min); + } + + sprintf "%5lu %4ld %-10s %2d %-8s %-8s %8s %s %2d %5s %s\n", + $ino, + $blocks, + $perms, + $nlink, + $user, + $group, + $sizemm, + $moname, + $mday, + $timeyear, + $pname; +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/FTP/netrc.pm b/Master/tlpkg/tlperl/lib/CPAN/FTP/netrc.pm new file mode 100644 index 00000000000..c05405e7ef6 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/FTP/netrc.pm @@ -0,0 +1,63 @@ +package CPAN::FTP::netrc; +use strict; + +$CPAN::FTP::netrc::VERSION = $CPAN::FTP::netrc::VERSION = "1.00"; + +# package CPAN::FTP::netrc; +sub new { + my($class) = @_; + my $home = CPAN::HandleConfig::home(); + my $file = File::Spec->catfile($home,".netrc"); + + my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, + $atime,$mtime,$ctime,$blksize,$blocks) + = stat($file); + $mode ||= 0; + my $protected = 0; + + my($fh,@machines,$hasdefault); + $hasdefault = 0; + $fh = FileHandle->new or die "Could not create a filehandle"; + + if($fh->open($file)) { + $protected = ($mode & 077) == 0; + local($/) = ""; + NETRC: while (<$fh>) { + my(@tokens) = split " ", $_; + TOKEN: while (@tokens) { + my($t) = shift @tokens; + if ($t eq "default") { + $hasdefault++; + last NETRC; + } + last TOKEN if $t eq "macdef"; + if ($t eq "machine") { + push @machines, shift @tokens; + } + } + } + } else { + $file = $hasdefault = $protected = ""; + } + + bless { + 'mach' => [@machines], + 'netrc' => $file, + 'hasdefault' => $hasdefault, + 'protected' => $protected, + }, $class; +} + +# CPAN::FTP::netrc::hasdefault; +sub hasdefault { shift->{'hasdefault'} } +sub netrc { shift->{'netrc'} } +sub protected { shift->{'protected'} } +sub contains { + my($self,$mach) = @_; + for ( @{$self->{'mach'}} ) { + return 1 if $_ eq $mach; + } + return 0; +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/FirstTime.pm b/Master/tlpkg/tlperl/lib/CPAN/FirstTime.pm new file mode 100644 index 00000000000..53ffbf1ef04 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/FirstTime.pm @@ -0,0 +1,1800 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +package CPAN::FirstTime; +use strict; + +use ExtUtils::MakeMaker (); +use FileHandle (); +use File::Basename (); +use File::Path (); +use File::Spec (); +use CPAN::Mirrors (); +use vars qw($VERSION $silent); +$VERSION = "5.5301"; + +=head1 NAME + +CPAN::FirstTime - Utility for CPAN::Config file Initialization + +=head1 SYNOPSIS + +CPAN::FirstTime::init() + +=head1 DESCRIPTION + +The init routine asks a few questions and writes a CPAN/Config.pm or +CPAN/MyConfig.pm file (depending on what it is currently using). + +In the following all questions and explanations regarding config +variables are collected. + +=cut + +# down until the next =back the manpage must be parsed by the program +# because the text is used in the init dialogues. + +my @podpara = split /\n\n/, <<'=back'; + +=over 2 + +=item auto_commit + +Normally CPAN.pm keeps config variables in memory and changes need to +be saved in a separate 'o conf commit' command to make them permanent +between sessions. If you set the 'auto_commit' option to true, changes +to a config variable are always automatically committed to disk. + +Always commit changes to config variables to disk? + +=item build_cache + +CPAN.pm can limit the size of the disk area for keeping the build +directories with all the intermediate files. + +Cache size for build directory (in MB)? + +=item build_dir + +Directory where the build process takes place? + +=item build_dir_reuse + +Until version 1.88 CPAN.pm never trusted the contents of the build_dir +directory between sessions. Since 1.88_58 CPAN.pm has a YAML-based +mechanism that makes it possible to share the contents of the +build_dir/ directory between different sessions with the same version +of perl. People who prefer to test things several days before +installing will like this feature because it safes a lot of time. + +If you say yes to the following question, CPAN will try to store +enough information about the build process so that it can pick up in +future sessions at the same state of affairs as it left a previous +session. + +Store and re-use state information about distributions between +CPAN.pm sessions? + +=item build_requires_install_policy + +When a module declares another one as a 'build_requires' prerequisite +this means that the other module is only needed for building or +testing the module but need not be installed permanently. In this case +you may wish to install that other module nonetheless or just keep it +in the 'build_dir' directory to have it available only temporarily. +Installing saves time on future installations but makes the perl +installation bigger. + +You can choose if you want to always install (yes), never install (no) +or be always asked. In the latter case you can set the default answer +for the question to yes (ask/yes) or no (ask/no). + +Policy on installing 'build_requires' modules (yes, no, ask/yes, +ask/no)? + +=item cache_metadata + +To considerably speed up the initial CPAN shell startup, it is +possible to use Storable to create a cache of metadata. If Storable is +not available, the normal index mechanism will be used. + +Note: this mechanism is not used when use_sqlite is on and SQLLite is +running. + +Cache metadata (yes/no)? + +=item check_sigs + +CPAN packages can be digitally signed by authors and thus verified +with the security provided by strong cryptography. The exact mechanism +is defined in the Module::Signature module. While this is generally +considered a good thing, it is not always convenient to the end user +to install modules that are signed incorrectly or where the key of the +author is not available or where some prerequisite for +Module::Signature has a bug and so on. + +With the check_sigs parameter you can turn signature checking on and +off. The default is off for now because the whole tool chain for the +functionality is not yet considered mature by some. The author of +CPAN.pm would recommend setting it to true most of the time and +turning it off only if it turns out to be annoying. + +Note that if you do not have Module::Signature installed, no signature +checks will be performed at all. + +Always try to check and verify signatures if a SIGNATURE file is in +the package and Module::Signature is installed (yes/no)? + +=item colorize_output + +When you have Term::ANSIColor installed, you can turn on colorized +output to have some visual differences between normal CPAN.pm output, +warnings, debugging output, and the output of the modules being +installed. Set your favorite colors after some experimenting with the +Term::ANSIColor module. + +Do you want to turn on colored output? + +=item colorize_print + +Color for normal output? + +=item colorize_warn + +Color for warnings? + +=item colorize_debug + +Color for debugging messages? + +=item commandnumber_in_prompt + +The prompt of the cpan shell can contain the current command number +for easier tracking of the session or be a plain string. + +Do you want the command number in the prompt (yes/no)? + +=item connect_to_internet_ok + +If you have never defined your own C<urllist> in your configuration +then C<CPAN.pm> will be hesitant to use the built in default sites for +downloading. It will ask you once per session if a connection to the +internet is OK and only if you say yes, it will try to connect. But to +avoid this question, you can choose your favorite download sites once +and get away with it. Or, if you have no favorite download sites +answer yes to the following question. + +If no urllist has been chosen yet, would you prefer CPAN.pm to connect +to the built-in default sites without asking? (yes/no)? + +=item ftp_passive + +Shall we always set the FTP_PASSIVE environment variable when dealing +with ftp download (yes/no)? + +=item ftpstats_period + +Statistics about downloads are truncated by size and period +simultaneously. + +How many days shall we keep statistics about downloads? + +=item ftpstats_size + +Statistics about downloads are truncated by size and period +simultaneously. + +How many items shall we keep in the statistics about downloads? + +=item getcwd + +CPAN.pm changes the current working directory often and needs to +determine its own current working directory. Per default it uses +Cwd::cwd but if this doesn't work on your system for some reason, +alternatives can be configured according to the following table: + + cwd Cwd::cwd + getcwd Cwd::getcwd + fastcwd Cwd::fastcwd + backtickcwd external command cwd + +Preferred method for determining the current working directory? + +=item halt_on_failure + +Normaly, CPAN.pm continues processing the full list of targets and +dependencies, even if one of them fails. However, you can specify +that CPAN should halt after the first failure. + +Do you want to halt on failure (yes/no)? + +=item histfile + +If you have one of the readline packages (Term::ReadLine::Perl, +Term::ReadLine::Gnu, possibly others) installed, the interactive CPAN +shell will have history support. The next two questions deal with the +filename of the history file and with its size. If you do not want to +set this variable, please hit SPACE RETURN to the following question. + +File to save your history? + +=item histsize + +Number of lines to save? + +=item inactivity_timeout + +Sometimes you may wish to leave the processes run by CPAN alone +without caring about them. Because the Makefile.PL or the Build.PL +sometimes contains question you're expected to answer, you can set a +timer that will kill a 'perl Makefile.PL' process after the specified +time in seconds. + +If you set this value to 0, these processes will wait forever. This is +the default and recommended setting. + +Timeout for inactivity during {Makefile,Build}.PL? + +=item index_expire + +The CPAN indexes are usually rebuilt once or twice per hour, but the +typical CPAN mirror mirrors only once or twice per day. Depending on +the quality of your mirror and your desire to be on the bleeding edge, +you may want to set the following value to more or less than one day +(which is the default). It determines after how many days CPAN.pm +downloads new indexes. + +Let the index expire after how many days? + +=item inhibit_startup_message + +When the CPAN shell is started it normally displays a greeting message +that contains the running version and the status of readline support. + +Do you want to turn this message off? + +=item keep_source_where + +Unless you are accessing the CPAN on your filesystem via a file: URL, +CPAN.pm needs to keep the source files it downloads somewhere. Please +supply a directory where the downloaded files are to be kept. + +Download target directory? + +=item load_module_verbosity + +When CPAN.pm loads a module it needs for some optional feature, it +usually reports about module name and version. Choose 'v' to get this +message, 'none' to suppress it. + +Verbosity level for loading modules (none or v)? + +=item makepl_arg + +Every Makefile.PL is run by perl in a separate process. Likewise we +run 'make' and 'make install' in separate processes. If you have +any parameters (e.g. PREFIX, UNINST or the like) you want to +pass to the calls, please specify them here. + +If you don't understand this question, just press ENTER. + +Typical frequently used settings: + + PREFIX=~/perl # non-root users (please see manual for more hints) + +Parameters for the 'perl Makefile.PL' command? + +=item make_arg + +Parameters for the 'make' command? Typical frequently used setting: + + -j3 # dual processor system (on GNU make) + +Your choice: + +=item make_install_arg + +Parameters for the 'make install' command? +Typical frequently used setting: + + UNINST=1 # to always uninstall potentially conflicting files + +Your choice: + +=item make_install_make_command + +Do you want to use a different make command for 'make install'? +Cautious people will probably prefer: + + su root -c make + or + sudo make + or + /path1/to/sudo -u admin_account /path2/to/make + +or some such. Your choice: + +=item mbuildpl_arg + +A Build.PL is run by perl in a separate process. Likewise we run +'./Build' and './Build install' in separate processes. If you have any +parameters you want to pass to the calls, please specify them here. + +Typical frequently used settings: + + --install_base /home/xxx # different installation directory + +Parameters for the 'perl Build.PL' command? + +=item mbuild_arg + +Parameters for the './Build' command? Setting might be: + + --extra_linker_flags -L/usr/foo/lib # non-standard library location + +Your choice: + +=item mbuild_install_arg + +Parameters for the './Build install' command? Typical frequently used +setting: + + --uninst 1 # uninstall conflicting files + +Your choice: + +=item mbuild_install_build_command + +Do you want to use a different command for './Build install'? Sudo +users will probably prefer: + + su root -c ./Build + or + sudo ./Build + or + /path1/to/sudo -u admin_account ./Build + +or some such. Your choice: + +=item pager + +What is your favorite pager program? + +=item prefer_installer + +When you have Module::Build installed and a module comes with both a +Makefile.PL and a Build.PL, which shall have precedence? + +The main two standard installer modules are the old and well +established ExtUtils::MakeMaker (for short: EUMM) which uses the +Makefile.PL. And the next generation installer Module::Build (MB) +which works with the Build.PL (and often comes with a Makefile.PL +too). If a module comes only with one of the two we will use that one +but if both are supplied then a decision must be made between EUMM and +MB. See also http://rt.cpan.org/Ticket/Display.html?id=29235 for a +discussion about the right default. + +Or, as a third option you can choose RAND which will make a random +decision (something regular CPAN testers will enjoy). + +In case you can choose between running a Makefile.PL or a Build.PL, +which installer would you prefer (EUMM or MB or RAND)? + +=item prefs_dir + +CPAN.pm can store customized build environments based on regular +expressions for distribution names. These are YAML files where the +default options for CPAN.pm and the environment can be overridden and +dialog sequences can be stored that can later be executed by an +Expect.pm object. The CPAN.pm distribution comes with some prefab YAML +files that cover sample distributions that can be used as blueprints +to store one own prefs. Please check out the distroprefs/ directory of +the CPAN.pm distribution to get a quick start into the prefs system. + +Directory where to store default options/environment/dialogs for +building modules that need some customization? + +=item prerequisites_policy + +The CPAN module can detect when a module which you are trying to build +depends on prerequisites. If this happens, it can build the +prerequisites for you automatically ('follow'), ask you for +confirmation ('ask'), or just ignore them ('ignore'). Choosing +'follow' also sets PERL_AUTOINSTALL and PERL_EXTUTILS_AUTOINSTALL for +"--defaultdeps" if not already set. + +Please set your policy to one of the three values. + +Policy on building prerequisites (follow, ask or ignore)? + +=item randomize_urllist + +CPAN.pm can introduce some randomness when using hosts for download +that are configured in the urllist parameter. Enter a numeric value +between 0 and 1 to indicate how often you want to let CPAN.pm try a +random host from the urllist. A value of one specifies to always use a +random host as the first try. A value of zero means no randomness at +all. Anything in between specifies how often, on average, a random +host should be tried first. + +Randomize parameter + +=item scan_cache + +By default, each time the CPAN module is started, cache scanning is +performed to keep the cache size in sync. To prevent this, answer +'never'. + +Perform cache scanning (atstart or never)? + +=item shell + +What is your favorite shell? + +=item show_unparsable_versions + +During the 'r' command CPAN.pm finds modules without version number. +When the command finishes, it prints a report about this. If you +want this report to be very verbose, say yes to the following +variable. + +Show all individual modules that have no $VERSION? + +=item show_upload_date + +The 'd' and the 'm' command normally only show you information they +have in their in-memory database and thus will never connect to the +internet. If you set the 'show_upload_date' variable to true, 'm' and +'d' will additionally show you the upload date of the module or +distribution. Per default this feature is off because it may require a +net connection to get at the upload date. + +Always try to show upload date with 'd' and 'm' command (yes/no)? + +=item show_zero_versions + +During the 'r' command CPAN.pm finds modules with a version number of +zero. When the command finishes, it prints a report about this. If you +want this report to be very verbose, say yes to the following +variable. + +Show all individual modules that have a $VERSION of zero? + +=item tar_verbosity + +When CPAN.pm uses the tar command, which switch for the verbosity +shall be used? Choose 'none' for quiet operation, 'v' for file +name listing, 'vv' for full listing. + +Tar command verbosity level (none or v or vv)? + +=item term_is_latin + +The next option deals with the charset (aka character set) your +terminal supports. In general, CPAN is English speaking territory, so +the charset does not matter much but some CPAN have names that are +outside the ASCII range. If your terminal supports UTF-8, you should +say no to the next question. If it expects ISO-8859-1 (also known as +LATIN1) then you should say yes. If it supports neither, your answer +does not matter because you will not be able to read the names of some +authors anyway. If you answer no, names will be output in UTF-8. + +Your terminal expects ISO-8859-1 (yes/no)? + +=item term_ornaments + +When using Term::ReadLine, you can turn ornaments on so that your +input stands out against the output from CPAN.pm. + +Do you want to turn ornaments on? + +=item test_report + +The goal of the CPAN Testers project (http://testers.cpan.org/) is to +test as many CPAN packages as possible on as many platforms as +possible. This provides valuable feedback to module authors and +potential users to identify bugs or platform compatibility issues and +improves the overall quality and value of CPAN. + +One way you can contribute is to send test results for each module +that you install. If you install the CPAN::Reporter module, you have +the option to automatically generate and email test reports to CPAN +Testers whenever you run tests on a CPAN package. + +See the CPAN::Reporter documentation for additional details and +configuration settings. If your firewall blocks outgoing email, +you will need to configure CPAN::Reporter before sending reports. + +Email test reports if CPAN::Reporter is installed (yes/no)? + +=item perl5lib_verbosity + +When CPAN.pm extends @INC via PERL5LIB, it prints a list of +directories added (or a summary of how many directories are +added). Choose 'v' to get this message, 'none' to suppress it. + +Verbosity level for PERL5LIB changes (none or v)? + +=item trust_test_report_history + +When a distribution has already been tested by CPAN::Reporter on +this machine, CPAN can skip the test phase and just rely on the +test report history instead. + +Note that this will not apply to distributions that failed tests +because of missing dependencies. Also, tests can be run +regardless of the history using "force". + +Do you want to rely on the test report history (yes/no)? + +=item use_sqlite + +CPAN::SQLite is a layer between the index files that are downloaded +from the CPAN and CPAN.pm that speeds up metadata queries and reduces +memory consumption of CPAN.pm considerably. + +Use CPAN::SQLite if available? (yes/no)? + +=item version_timeout + +This timeout prevents CPAN from hanging when trying to parse a +pathologically coded $VERSION from a module. + +The default is 15 seconds. If you set this value to 0, no timeout +will occur, but this is not recommended. + +Timeout for parsing module versions? + +=item yaml_load_code + +Both YAML.pm and YAML::Syck are capable of deserialising code. As this +requires a string eval, which might be a security risk, you can use +this option to enable or disable the deserialisation of code via +CPAN::DeferredCode. (Note: This does not work under perl 5.6) + +Do you want to enable code deserialisation (yes/no)? + +=item yaml_module + +At the time of this writing (2009-03) there are three YAML +implementations working: YAML, YAML::Syck, and YAML::XS. The latter +two are faster but need a C compiler installed on your system. There +may be more alternative YAML conforming modules. When I tried two +other players, YAML::Tiny and YAML::Perl, they seemed not powerful +enough to work with CPAN.pm. This may have changed in the meantime. + +Which YAML implementation would you prefer? + +=back + +=head1 LICENSE + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=cut + +use vars qw( %prompts ); + +{ + + my @prompts = ( + +manual_config => qq[ +CPAN is the world-wide archive of perl resources. It consists of about +300 sites that all replicate the same contents around the globe. Many +countries have at least one CPAN site already. The resources found on +CPAN are easily accessible with the CPAN.pm module. If you want to use +CPAN.pm, lots of things have to be configured. Fortunately, most of +them can be determined automatically. If you prefer the automatic +configuration, answer 'yes' below. + +If you prefer to enter a dialog instead, you can answer 'no' to this +question and I'll let you configure in small steps one thing after the +other. (Note: you can revisit this dialog anytime later by typing 'o +conf init' at the cpan prompt.) + +], + +auto_pick => qq{ +Would you like me to automatically choose the best CPAN mirror +sites for you? (This means connecting to the Internet and could +take a couple minutes)}, + +config_intro => qq{ + +The following questions are intended to help you with the +configuration. The CPAN module needs a directory of its own to cache +important index files and maybe keep a temporary mirror of CPAN files. +This may be a site-wide or a personal directory. + +}, + +# cpan_home => qq{ }, + +cpan_home_where => qq{ + +First of all, I'd like to create this directory. Where? + +}, + +external_progs => qq{ + +The CPAN module will need a few external programs to work properly. +Please correct me, if I guess the wrong path for a program. Don't +panic if you do not have some of them, just press ENTER for those. To +disable the use of a program, you can type a space followed by ENTER. + +}, + +proxy_intro => qq{ + +If you're accessing the net via proxies, you can specify them in the +CPAN configuration or via environment variables. The variable in +the \$CPAN::Config takes precedence. + +}, + +proxy_user => qq{ + +If your proxy is an authenticating proxy, you can store your username +permanently. If you do not want that, just press RETURN. You will then +be asked for your username in every future session. + +}, + +proxy_pass => qq{ + +Your password for the authenticating proxy can also be stored +permanently on disk. If this violates your security policy, just press +RETURN. You will then be asked for the password in every future +session. + +}, + +urls_intro => qq{ +Now you need to choose your CPAN mirror sites. You can let me +pick mirrors for you, you can select them from a list or you +can enter them by hand. +}, + +urls_picker_intro => qq{First, pick a nearby continent and country by typing in the number(s) +in front of the item(s) you want to select. You can pick several of +each, separated by spaces. Then, you will be presented with a list of +URLs of CPAN mirrors in the countries you selected, along with +previously selected URLs. Select some of those URLs, or just keep the +old list. Finally, you will be prompted for any extra URLs -- file:, +ftp:, or http: -- that host a CPAN mirror. + +You should select more than one (just in case the first isn't available). + +}, + +password_warn => qq{ + +Warning: Term::ReadKey seems not to be available, your password will +be echoed to the terminal! + +}, + + ); + + die "Coding error in \@prompts declaration. Odd number of elements, above" + if (@prompts % 2); + + %prompts = @prompts; + + if (scalar(keys %prompts) != scalar(@prompts)/2) { + my %already; + for my $item (0..$#prompts) { + next if $item % 2; + die "$prompts[$item] is duplicated\n" if $already{$prompts[$item]}++; + } + } + + shift @podpara; + while (@podpara) { + warn "Alert: cannot parse my own manpage for init dialog" unless $podpara[0] =~ s/^=item\s+//; + my $name = shift @podpara; + my @para; + while (@podpara && $podpara[0] !~ /^=item/) { + push @para, shift @podpara; + } + $prompts{$name} = pop @para; + if (@para) { + $prompts{$name . "_intro"} = join "", map { "$_\n\n" } @para; + } + } + +} + +sub init { + my($configpm, %args) = @_; + use Config; + # extra args after 'o conf init' + my $matcher = $args{args} && @{$args{args}} ? $args{args}[0] : ''; + if ($matcher =~ /^\/(.*)\/$/) { + # case /regex/ => take the first, ignore the rest + $matcher = $1; + shift @{$args{args}}; + if (@{$args{args}}) { + local $" = " "; + $CPAN::Frontend->mywarn("Ignoring excessive arguments '@{$args{args}}'"); + $CPAN::Frontend->mysleep(2); + } + } elsif (0 == length $matcher) { + } elsif (0 && $matcher eq "~") { # extremely buggy, but a nice idea + my @unconfigured = grep { not exists $CPAN::Config->{$_} + or not defined $CPAN::Config->{$_} + or not length $CPAN::Config->{$_} + } keys %$CPAN::Config; + $matcher = "\\b(".join("|", @unconfigured).")\\b"; + $CPAN::Frontend->mywarn("matcher[$matcher]"); + } else { + # case WORD... => all arguments must be valid + for my $arg (@{$args{args}}) { + unless (exists $CPAN::HandleConfig::keys{$arg}) { + $CPAN::Frontend->mywarn("'$arg' is not a valid configuration variable\n"); + return; + } + } + $matcher = "\\b(".join("|",@{$args{args}}).")\\b"; + } + CPAN->debug("matcher[$matcher]") if $CPAN::DEBUG; + + unless ($CPAN::VERSION) { + require CPAN::Nox; + } + require CPAN::HandleConfig; + CPAN::HandleConfig::require_myconfig_or_config(); + $CPAN::Config ||= {}; + local($/) = "\n"; + local($\) = ""; + local($|) = 1; + + my($ans,$default); # why so half global? + + # + #= Files, directories + # + + unless ($matcher) { + $CPAN::Frontend->myprint($prompts{manual_config}); + } + + my $manual_conf; + + local *_real_prompt; + if ( $args{autoconfig} ) { + $manual_conf = "no"; + } elsif ($matcher) { + $manual_conf = "yes"; + } else { + my $_conf = prompt("Would you like me to configure as much as possible ". + "automatically?", "yes"); + $manual_conf = ($_conf and $_conf =~ /^y/i) ? "no" : "yes"; + } + CPAN->debug("manual_conf[$manual_conf]") if $CPAN::DEBUG; + my $fastread; + { + if ($manual_conf =~ /^y/i) { + $fastread = 0; + } else { + $fastread = 1; + $silent = 1; + $CPAN::Config->{urllist} ||= []; + $CPAN::Config->{connect_to_internet_ok} ||= 1; + + local $^W = 0; + # prototype should match that of &MakeMaker::prompt + my $current_second = time; + my $current_second_count = 0; + my $i_am_mad = 0; + # silent prompting -- just quietly use default + *_real_prompt = sub { return $_[1] }; + } + } + + if (!$matcher or q{ + build_dir + build_dir_reuse + cpan_home + keep_source_where + prefs_dir + } =~ /$matcher/) { + $CPAN::Frontend->myprint($prompts{config_intro}) unless $silent; + + init_cpan_home($matcher); + + my_dflt_prompt("keep_source_where", + File::Spec->catdir($CPAN::Config->{cpan_home},"sources"), + $matcher, + ); + my_dflt_prompt("build_dir", + File::Spec->catdir($CPAN::Config->{cpan_home},"build"), + $matcher + ); + my_yn_prompt(build_dir_reuse => 0, $matcher); + my_dflt_prompt("prefs_dir", + File::Spec->catdir($CPAN::Config->{cpan_home},"prefs"), + $matcher + ); + } + + # + #= Config: auto_commit + # + + my_yn_prompt(auto_commit => 0, $matcher); + + # + #= Cache size, Index expire + # + my_dflt_prompt(build_cache => 100, $matcher); + + my_dflt_prompt(index_expire => 1, $matcher); + my_prompt_loop(scan_cache => 'atstart', $matcher, 'atstart|never'); + + # + #= cache_metadata + # + + my_yn_prompt(cache_metadata => 1, $matcher); + my_yn_prompt(use_sqlite => 0, $matcher); + + # + #= Do we follow PREREQ_PM? + # + + my_prompt_loop(prerequisites_policy => 'follow', $matcher, + 'follow|ask|ignore'); + my_prompt_loop(build_requires_install_policy => 'yes', $matcher, + 'yes|no|ask/yes|ask/no'); + + # + #= Module::Signature + # + my_yn_prompt(check_sigs => 0, $matcher); + + # + #= CPAN::Reporter + # + if (!$matcher or 'test_report' =~ /$matcher/) { + my_yn_prompt(test_report => 0, $matcher); + if ( + $CPAN::Config->{test_report} && + $CPAN::META->has_inst("CPAN::Reporter") && + CPAN::Reporter->can('configure') + ) { + local *_real_prompt; + *_real_prompt = \&CPAN::Shell::colorable_makemaker_prompt; + my $_conf = prompt("Would you like me configure CPAN::Reporter now?", $silent ? "no" : "yes"); + if ($_conf =~ /^y/i) { + $CPAN::Frontend->myprint("\nProceeding to configure CPAN::Reporter.\n"); + CPAN::Reporter::configure(); + $CPAN::Frontend->myprint("\nReturning to CPAN configuration.\n"); + } + } + } + + my_yn_prompt(trust_test_report_history => 0, $matcher); + + # + #= YAML vs. YAML::Syck + # + if (!$matcher or "yaml_module" =~ /$matcher/) { + my_dflt_prompt(yaml_module => "YAML", $matcher); + my $old_v = $CPAN::Config->{load_module_verbosity}; + $CPAN::Config->{load_module_verbosity} = q[none]; + if (!$silent && !$CPAN::META->has_inst($CPAN::Config->{yaml_module})) { + $CPAN::Frontend->mywarn + ("Warning (maybe harmless): '$CPAN::Config->{yaml_module}' not installed.\n"); + $CPAN::Frontend->mysleep(3); + } + $CPAN::Config->{load_module_verbosity} = $old_v; + } + + # + #= YAML code deserialisation + # + my_yn_prompt(yaml_load_code => 0, $matcher); + + # + #= External programs + # + my(@path) = split /$Config{'path_sep'}/, $ENV{'PATH'}; + _init_external_progs($matcher,\@path); + + { + my $path = $CPAN::Config->{'pager'} || + $ENV{PAGER} || find_exe("less",\@path) || + find_exe("more",\@path) || ($^O eq 'MacOS' ? $ENV{EDITOR} : 0 ) + || "more"; + my_dflt_prompt(pager => $path, $matcher); + } + + { + my $path = $CPAN::Config->{'shell'}; + if ($path && File::Spec->file_name_is_absolute($path)) { + $CPAN::Frontend->mywarn("Warning: configured $path does not exist\n") + unless -e $path; + $path = ""; + } + $path ||= $ENV{SHELL}; + $path ||= $ENV{COMSPEC} if $^O eq "MSWin32"; + if ($^O eq 'MacOS') { + $CPAN::Config->{'shell'} = 'not_here'; + } else { + $path ||= 'sh', $path =~ s,\\,/,g if $^O eq 'os2'; # Cosmetic only + my_dflt_prompt(shell => $path, $matcher); + } + } + + # + # verbosity + # + + my_prompt_loop(tar_verbosity => 'none', $matcher, + 'none|v|vv'); + my_prompt_loop(load_module_verbosity => 'none', $matcher, + 'none|v'); + my_prompt_loop(perl5lib_verbosity => 'none', $matcher, + 'none|v'); + my_yn_prompt(inhibit_startup_message => 0, $matcher); + + # + #= Installer, arguments to make etc. + # + + my_prompt_loop(prefer_installer => 'MB', $matcher, 'MB|EUMM|RAND'); + + if (!$matcher or 'makepl_arg make_arg' =~ /$matcher/) { + my_dflt_prompt(makepl_arg => "", $matcher); + my_dflt_prompt(make_arg => "", $matcher); + if ( $CPAN::Config->{makepl_arg} =~ /LIBS=|INC=/ ) { + $CPAN::Frontend->mywarn( + "Warning: Using LIBS or INC in makepl_arg will likely break distributions\n" . + "that specify their own LIBS or INC options in Makefile.PL.\n" + ); + } + + } + + require CPAN::HandleConfig; + if (exists $CPAN::HandleConfig::keys{make_install_make_command}) { + # as long as Windows needs $self->_build_command, we cannot + # support sudo on windows :-) + my_dflt_prompt(make_install_make_command => $CPAN::Config->{make} || "", + $matcher); + } + + my_dflt_prompt(make_install_arg => $CPAN::Config->{make_arg} || "", + $matcher); + + my_dflt_prompt(mbuildpl_arg => "", $matcher); + my_dflt_prompt(mbuild_arg => "", $matcher); + + if (exists $CPAN::HandleConfig::keys{mbuild_install_build_command} + and $^O ne "MSWin32") { + # as long as Windows needs $self->_build_command, we cannot + # support sudo on windows :-) + my_dflt_prompt(mbuild_install_build_command => "./Build", $matcher); + } + + my_dflt_prompt(mbuild_install_arg => "", $matcher); + + # + #= Alarm period + # + + my_dflt_prompt(inactivity_timeout => 0, $matcher); + my_dflt_prompt(version_timeout => 15, $matcher); + + # + #== halt_on_failure + # + my_yn_prompt(halt_on_failure => 0, $matcher); + + # + #= Proxies + # + + my @proxy_vars = qw/ftp_proxy http_proxy no_proxy/; + my @proxy_user_vars = qw/proxy_user proxy_pass/; + if (!$matcher or "@proxy_vars @proxy_user_vars" =~ /$matcher/) { + $CPAN::Frontend->myprint($prompts{proxy_intro}) unless $silent; + + for (@proxy_vars) { + $prompts{$_} = "Your $_?"; + my_dflt_prompt($_ => $ENV{$_}||"", $matcher); + } + + if ($CPAN::Config->{ftp_proxy} || + $CPAN::Config->{http_proxy}) { + + $default = $CPAN::Config->{proxy_user} || $CPAN::LWP::UserAgent::USER || ""; + + $CPAN::Frontend->myprint($prompts{proxy_user}) unless $silent; + + if ($CPAN::Config->{proxy_user} = prompt("Your proxy user id?",$default)) { + $CPAN::Frontend->myprint($prompts{proxy_pass}) unless $silent; + + if ($CPAN::META->has_inst("Term::ReadKey")) { + Term::ReadKey::ReadMode("noecho"); + } else { + $CPAN::Frontend->myprint($prompts{password_warn}) unless $silent; + } + $CPAN::Config->{proxy_pass} = prompt_no_strip("Your proxy password?"); + if ($CPAN::META->has_inst("Term::ReadKey")) { + Term::ReadKey::ReadMode("restore"); + } + $CPAN::Frontend->myprint("\n\n") unless $silent; + } + } + } + + # + #= how FTP works + # + + my_yn_prompt(ftp_passive => 1, $matcher); + + # + #= how cwd works + # + + my_prompt_loop(getcwd => 'cwd', $matcher, + 'cwd|getcwd|fastcwd|backtickcwd'); + + # + #= the CPAN shell itself (prompt, color) + # + + my_yn_prompt(commandnumber_in_prompt => 1, $matcher); + my_yn_prompt(term_ornaments => 1, $matcher); + if ("colorize_output colorize_print colorize_warn colorize_debug" =~ $matcher) { + my_yn_prompt(colorize_output => 0, $matcher); + if ($CPAN::Config->{colorize_output}) { + if ($CPAN::META->has_inst("Term::ANSIColor")) { + my $T="gYw"; + $CPAN::Frontend->myprint( " on_ on_y ". + " on_ma on_\n") unless $silent; + $CPAN::Frontend->myprint( " on_black on_red green ellow ". + "on_blue genta on_cyan white\n") unless $silent; + + for my $FG ("", "bold", + map {$_,"bold $_"} "black","red","green", + "yellow","blue", + "magenta", + "cyan","white") { + $CPAN::Frontend->myprint(sprintf( "%12s ", $FG)) unless $silent; + for my $BG ("",map {"on_$_"} qw(black red green yellow + blue magenta cyan white)) { + $CPAN::Frontend->myprint( $FG||$BG ? + Term::ANSIColor::colored(" $T ","$FG $BG") : " $T ") unless $silent; + } + $CPAN::Frontend->myprint( "\n" ) unless $silent; + } + $CPAN::Frontend->myprint( "\n" ) unless $silent; + } + for my $tuple ( + ["colorize_print", "bold blue on_white"], + ["colorize_warn", "bold red on_white"], + ["colorize_debug", "black on_cyan"], + ) { + my_dflt_prompt($tuple->[0] => $tuple->[1], $matcher); + if ($CPAN::META->has_inst("Term::ANSIColor")) { + eval { Term::ANSIColor::color($CPAN::Config->{$tuple->[0]})}; + if ($@) { + $CPAN::Config->{$tuple->[0]} = $tuple->[1]; + $CPAN::Frontend->mywarn($@."setting to default '$tuple->[1]'\n"); + } + } + } + } + } + + # + #== term_is_latin + # + + my_yn_prompt(term_is_latin => 1, $matcher); + + # + #== save history in file 'histfile' + # + + if (!$matcher or 'histfile histsize' =~ /$matcher/) { + $CPAN::Frontend->myprint($prompts{histfile_intro}) unless $silent; + defined($default = $CPAN::Config->{histfile}) or + $default = File::Spec->catfile($CPAN::Config->{cpan_home},"histfile"); + my_dflt_prompt(histfile => $default, $matcher); + + if ($CPAN::Config->{histfile}) { + defined($default = $CPAN::Config->{histsize}) or $default = 100; + my_dflt_prompt(histsize => $default, $matcher); + } + } + + # + #== do an ls on the m or the d command + # + my_yn_prompt(show_upload_date => 0, $matcher); + + # + #== verbosity at the end of the r command + # + if (!$matcher + or 'show_unparsable_versions' =~ /$matcher/ + or 'show_zero_versions' =~ /$matcher/ + ) { + $CPAN::Frontend->myprint($prompts{show_unparsable_or_zero_versions_intro}); + my_yn_prompt(show_unparsable_versions => 0, $matcher); + my_yn_prompt(show_zero_versions => 0, $matcher); + } + + # + #= MIRRORED.BY and conf_sites() + # + + # remember, this is only triggered if no urllist is given, so 0 is + # fair and protects the default site from being overloaded and + # gives the user more chances to select his own urllist. + my_yn_prompt("connect_to_internet_ok" => $fastread ? 1 : 0, $matcher); + $CPAN::Config->{urllist} ||= []; + if ($matcher) { + if ("urllist" =~ $matcher) { + $CPAN::Frontend->myprint($prompts{urls_intro}); + + # conf_sites would go into endless loop with the smash prompt + local *_real_prompt; + *_real_prompt = \&CPAN::Shell::colorable_makemaker_prompt; + my $_conf = prompt($prompts{auto_pick}, "yes"); + + if ( $_conf =~ /^y/i ) { + conf_sites( auto_pick => 1 ) or bring_your_own(); + } + else { + my $_conf = prompt( + "Would you like to pick from the CPAN mirror list?", "yes" + ); + + if ( $_conf =~ /^y/i ) { + conf_sites(); + } + bring_your_own(); + } + _print_urllist(); + } + if ("randomize_urllist" =~ $matcher) { + my_dflt_prompt(randomize_urllist => 0, $matcher); + } + if ("ftpstats_size" =~ $matcher) { + my_dflt_prompt(ftpstats_size => 99, $matcher); + } + if ("ftpstats_period" =~ $matcher) { + my_dflt_prompt(ftpstats_period => 14, $matcher); + } + } elsif ($fastread) { + $silent = 0; + local *_real_prompt; + *_real_prompt = \&CPAN::Shell::colorable_makemaker_prompt; + if ( @{ $CPAN::Config->{urllist} } ) { + $CPAN::Frontend->myprint( + "\nYour 'urllist' is already configured. Type 'o conf init urllist' to change it.\n" + ); + } + else { + $CPAN::Frontend->myprint( + "Autoconfigured everything but 'urllist'.\n" + ); + + $CPAN::Frontend->myprint($prompts{urls_intro}); + + my $_conf = prompt($prompts{auto_pick}, "yes"); + + if ( $_conf =~ /^y/i ) { + conf_sites( auto_pick => 1 ) or bring_your_own(); + } + else { + my $_conf = prompt( + "Would you like to pick from the CPAN mirror list?", "yes" + ); + + if ( $_conf =~ /^y/i ) { + conf_sites(); + } + bring_your_own(); + } + _print_urllist(); + } + $CPAN::Frontend->myprint( + "\nAutoconfiguration complete.\n" + ); + } + + $silent = 0; # reset + + $CPAN::Frontend->myprint("\n"); + if ($matcher && !$CPAN::Config->{auto_commit}) { + $CPAN::Frontend->myprint("Please remember to call 'o conf commit' to ". + "make the config permanent!\n"); + } else { + CPAN::HandleConfig->commit($configpm); + } +} + +sub _init_external_progs { + my($matcher,$PATH) = @_; + my @external_progs = qw/bzip2 gzip tar unzip + + make + + curl lynx wget ncftpget ncftp ftp + + gpg + + patch applypatch + /; + if (!$matcher or "@external_progs" =~ /$matcher/) { + $CPAN::Frontend->myprint($prompts{external_progs}) unless $silent; + + my $old_warn = $^W; + local $^W if $^O eq 'MacOS'; + local $^W = $old_warn; + my $progname; + for $progname (@external_progs) { + next if $matcher && $progname !~ /$matcher/; + if ($^O eq 'MacOS') { + $CPAN::Config->{$progname} = 'not_here'; + next; + } + + my $progcall = $progname; + unless ($matcher) { + # we really don't need ncftp if we have ncftpget, but + # if they chose this dialog via matcher, they shall have it + next if $progname eq "ncftp" && $CPAN::Config->{ncftpget} gt " "; + } + my $path = $CPAN::Config->{$progname} + || $Config::Config{$progname} + || ""; + if (File::Spec->file_name_is_absolute($path)) { + # testing existence is not good enough, some have these exe + # extensions + + # warn "Warning: configured $path does not exist\n" unless -e $path; + # $path = ""; + } elsif ($path =~ /^\s+$/) { + # preserve disabled programs + } else { + $path = ''; + } + unless ($path) { + # e.g. make -> nmake + $progcall = $Config::Config{$progname} if $Config::Config{$progname}; + } + + $path ||= find_exe($progcall,$PATH); + unless ($path) { # not -e $path, because find_exe already checked that + local $"=";"; + $CPAN::Frontend->mywarn("Warning: $progcall not found in PATH[@$PATH]\n") unless $silent; + if ($progname eq "make") { + $CPAN::Frontend->mywarn("ALERT: 'make' is an essential tool for ". + "building perl Modules. Please make sure you ". + "have 'make' (or some equivalent) ". + "working.\n" + ); + if ($^O eq "MSWin32") { + $CPAN::Frontend->mywarn(" +Windows users may want to follow this procedure when back in the CPAN shell: + + look YVES/scripts/alien_nmake.pl + perl alien_nmake.pl + +This will install nmake on your system which can be used as a 'make' +substitute. You can then revisit this dialog with + + o conf init make + +"); + } + } + } + $prompts{$progname} = "Where is your $progname program?"; + my_dflt_prompt($progname,$path,$matcher); + } + } +} + +sub init_cpan_home { + my($matcher) = @_; + if (!$matcher or 'cpan_home' =~ /$matcher/) { + my $cpan_home = $CPAN::Config->{cpan_home} + || File::Spec->catdir(CPAN::HandleConfig::home(), ".cpan"); + + if (-d $cpan_home) { + $CPAN::Frontend->myprint(qq{ + +I see you already have a directory + $cpan_home +Shall we use it as the general CPAN build and cache directory? + +}) unless $silent; + } else { + # no cpan-home, must prompt and get one + $CPAN::Frontend->myprint($prompts{cpan_home_where}) unless $silent; + } + + my $default = $cpan_home; + my $loop = 0; + my($last_ans,$ans); + $CPAN::Frontend->myprint(" <cpan_home>\n") unless $silent; + PROMPT: while ($ans = prompt("CPAN build and cache directory?",$default)) { + if (File::Spec->file_name_is_absolute($ans)) { + my @cpan_home = split /[\/\\]/, $ans; + DIR: for my $dir (@cpan_home) { + if ($dir =~ /^~/ and (!$last_ans or $ans ne $last_ans)) { + $CPAN::Frontend + ->mywarn("Warning: a tilde in the path will be ". + "taken as a literal tilde. Please ". + "confirm again if you want to keep it\n"); + $last_ans = $default = $ans; + next PROMPT; + } + } + } else { + require Cwd; + my $cwd = Cwd::cwd(); + my $absans = File::Spec->catdir($cwd,$ans); + $CPAN::Frontend->mywarn("The path '$ans' is not an ". + "absolute path. Please specify ". + "an absolute path\n"); + $default = $absans; + next PROMPT; + } + eval { File::Path::mkpath($ans); }; # dies if it can't + if ($@) { + $CPAN::Frontend->mywarn("Couldn't create directory $ans.\n". + "Please retry.\n"); + next PROMPT; + } + if (-d $ans && -w _) { + last PROMPT; + } else { + $CPAN::Frontend->mywarn("Couldn't find directory $ans\n". + "or directory is not writable. Please retry.\n"); + if (++$loop > 5) { + $CPAN::Frontend->mydie("Giving up"); + } + } + } + $CPAN::Config->{cpan_home} = $ans; + } +} + +sub my_dflt_prompt { + my ($item, $dflt, $m) = @_; + my $default = $CPAN::Config->{$item} || $dflt; + + if (!$silent && (!$m || $item =~ /$m/)) { + if (my $intro = $prompts{$item . "_intro"}) { + $CPAN::Frontend->myprint($intro); + } + $CPAN::Frontend->myprint(" <$item>\n"); + $CPAN::Config->{$item} = prompt($prompts{$item}, $default); + } else { + $CPAN::Config->{$item} = $default; + } +} + +sub my_yn_prompt { + my ($item, $dflt, $m) = @_; + my $default; + defined($default = $CPAN::Config->{$item}) or $default = $dflt; + + # $DB::single = 1; + if (!$silent && (!$m || $item =~ /$m/)) { + if (my $intro = $prompts{$item . "_intro"}) { + $CPAN::Frontend->myprint($intro); + } + $CPAN::Frontend->myprint(" <$item>\n"); + my $ans = prompt($prompts{$item}, $default ? 'yes' : 'no'); + $CPAN::Config->{$item} = ($ans =~ /^[y1]/i ? 1 : 0); + } else { + $CPAN::Config->{$item} = $default; + } +} + +sub my_prompt_loop { + my ($item, $dflt, $m, $ok) = @_; + my $default = $CPAN::Config->{$item} || $dflt; + my $ans; + + if (!$silent && (!$m || $item =~ /$m/)) { + $CPAN::Frontend->myprint($prompts{$item . "_intro"}); + $CPAN::Frontend->myprint(" <$item>\n"); + do { $ans = prompt($prompts{$item}, $default); + } until $ans =~ /$ok/; + $CPAN::Config->{$item} = $ans; + } else { + $CPAN::Config->{$item} = $default; + } +} + + +# Here's the logic about the MIRRORED.BY file. There are a number of scenarios: +# (1) We have a cached MIRRORED.BY file +# (1a) We're auto-picking +# - Refresh it automatically if it's old +# (1b) Otherwise, ask if using cached is ok. If old, default to no. +# - If cached is not ok, get it from the Internet. If it succeeds we use +# the new file. Otherwise, we use the old file. +# (2) We don't have a copy at all +# (2a) If we are allowed to connect, we try to get a new copy. If it succeeds, +# we use it, otherwise, we warn about failure +# (2b) If we aren't allowed to connect, + +sub conf_sites { + my %args = @_; + # auto pick implies using the internet + $CPAN::Config->{connect_to_internet_ok} = 1 if $args{auto_pick}; + + my $m = 'MIRRORED.BY'; + my $mby = File::Spec->catfile($CPAN::Config->{keep_source_where},$m); + File::Path::mkpath(File::Basename::dirname($mby)); + # Why are we using MIRRORED.BY from the current directory? + # Is this for testing? -- dagolden, 2009-11-05 + if (-f $mby && -f $m && -M $m < -M $mby) { + require File::Copy; + File::Copy::copy($m,$mby) or die "Could not update $mby: $!"; + } + local $^T = time; + # if we have a cached copy is not older than 60 days, we either + # use it or refresh it or fall back to it if the refresh failed. + if ($mby && -f $mby && -s _ > 0 ) { + my $very_old = (-M $mby > 60); + my $mtime = localtime((stat _)[9]); + # if auto_pick, refresh anything old automatically + if ( $args{auto_pick} ) { + if ( $very_old ) { + $CPAN::Frontend->myprint(qq{Trying to refresh your mirror list\n}); + eval { CPAN::FTP->localize($m,$mby,3,1) } + or $CPAN::Frontend->myprint(qq{Refresh failed. Using the old cached copy instead.\n}); + $CPAN::Frontend->myprint("\n"); + } + } + else { + my $prompt = qq{Found a cached mirror list as of $mtime + +If you'd like to just use the cached copy, answer 'yes', below. +If you'd like an updated copy of the mirror list, answer 'no' and +I'll get a fresh one from the Internet. + +Shall I use the cached mirror list?}; + my $ans = prompt($prompt, $very_old ? "no" : "yes"); + if ($ans =~ /^n/i) { + $CPAN::Frontend->myprint(qq{Trying to refresh your mirror list\n}); + # you asked for it from the Internet + $CPAN::Config->{connect_to_internet_ok} = 1; + eval { CPAN::FTP->localize($m,$mby,3,1) } + or $CPAN::Frontend->myprint(qq{Refresh failed. Using the old cached copy instead.\n}); + $CPAN::Frontend->myprint("\n"); + } + } + } + # else there is no cached copy and we must fetch or fail + else { + # If they haven't agree to connect to the internet, ask again + if ( ! $CPAN::Config->{connect_to_internet_ok} ) { + my $prompt = q{You are missing a copy of the CPAN mirror list. + +May I connect to the Internet to get it?}; + my $ans = prompt($prompt, "yes"); + if ($ans =~ /^y/i) { + $CPAN::Config->{connect_to_internet_ok} = 1; + } + } + + # Now get it from the Internet or complain + if ( $CPAN::Config->{connect_to_internet_ok} ) { + $CPAN::Frontend->myprint(qq{Trying to fetch a mirror list from the Internet\n}); + eval { CPAN::FTP->localize($m,$mby,3,1) } + or $CPAN::Frontend->mywarn(<<'HERE'); +We failed to get a copy of the mirror list from the Internet. +You will need to provide CPAN mirror URLs yourself. +HERE + $CPAN::Frontend->myprint("\n"); + } + else { + $CPAN::Frontend->mywarn(<<'HERE'); +You will need to provide CPAN mirror URLs yourself or set +'o conf connect_to_internet_ok 1' and try again. +HERE + } + } + + # if we finally have a good local MIRRORED.BY, get on with picking + if (-f $mby && -s _ > 0){ + $CPAN::Config->{urllist} = + $args{auto_pick} ? auto_mirrored_by($mby) : choose_mirrored_by($mby); + return 1; + } + + return; +} + +sub find_exe { + my($exe,$path) = @_; + my($dir); + #warn "in find_exe exe[$exe] path[@$path]"; + for $dir (@$path) { + my $abs = File::Spec->catfile($dir,$exe); + if (($abs = MM->maybe_command($abs))) { + return $abs; + } + } +} + +sub picklist { + my($items,$prompt,$default,$require_nonempty,$empty_warning)=@_; + CPAN->debug("picklist('$items','$prompt','$default','$require_nonempty',". + "'$empty_warning')") if $CPAN::DEBUG; + $default ||= ''; + + my $pos = 0; + + my @nums; + SELECTION: while (1) { + + # display, at most, 15 items at a time + my $limit = $#{ $items } - $pos; + $limit = 15 if $limit > 15; + + # show the next $limit items, get the new position + $pos = display_some($items, $limit, $pos, $default); + $pos = 0 if $pos >= @$items; + + my $num = prompt($prompt,$default); + + @nums = split (' ', $num); + { + my %seen; + @nums = grep { !$seen{$_}++ } @nums; + } + my $i = scalar @$items; + unrangify(\@nums); + if (0 == @nums) { + # cannot allow nothing because nothing means paging! + # return; + } elsif (grep (/\D/ || $_ < 1 || $_ > $i, @nums)) { + $CPAN::Frontend->mywarn("invalid items entered, try again\n"); + if ("@nums" =~ /\D/) { + $CPAN::Frontend->mywarn("(we are expecting only numbers between 1 and $i)\n"); + } + next SELECTION; + } + if ($require_nonempty && !@nums) { + $CPAN::Frontend->mywarn("$empty_warning\n"); + } + + # a blank line continues... + unless (@nums){ + $CPAN::Frontend->mysleep(0.1); # prevent hot spinning process on the next bug + next SELECTION; + } + last; + } + for (@nums) { $_-- } + @{$items}[@nums]; +} + +sub unrangify ($) { + my($nums) = $_[0]; + my @nums2 = (); + while (@{$nums||[]}) { + my $n = shift @$nums; + if ($n =~ /^(\d+)-(\d+)$/) { + my @range = $1 .. $2; + # warn "range[@range]"; + push @nums2, @range; + } else { + push @nums2, $n; + } + } + push @$nums, @nums2; +} + +sub display_some { + my ($items, $limit, $pos, $default) = @_; + $pos ||= 0; + + my @displayable = @$items[$pos .. ($pos + $limit)]; + for my $item (@displayable) { + $CPAN::Frontend->myprint(sprintf "(%d) %s\n", ++$pos, $item); + } + my $hit_what = $default ? "SPACE RETURN" : "RETURN"; + $CPAN::Frontend->myprint(sprintf("%d more items, hit %s to show them\n", + (@$items - $pos), + $hit_what, + )) + if $pos < @$items; + return $pos; +} + +sub auto_mirrored_by { + my $local = shift or return; + local $|=1; + $CPAN::Frontend->myprint("Searching for the best CPAN mirrors (please be patient) ..."); + my $mirrors = CPAN::Mirrors->new($local); + my $cnt = 0; + my @best = $mirrors->best_mirrors( + how_many => 5, + callback => sub { $CPAN::Frontend->myprint(".") }, + ); + my $urllist = [ map { $_->ftp } @best ]; + push @$urllist, grep { /^file:/ } @{$CPAN::Config->{urllist}}; + $CPAN::Frontend->myprint(" done!\n\n"); + return $urllist; +} + +sub choose_mirrored_by { + my $local = shift or return; + my ($default); + my $mirrors = CPAN::Mirrors->new($local); + my @previous_urls = @{$CPAN::Config->{urllist}}; + + $CPAN::Frontend->myprint($prompts{urls_picker_intro}); + + my (@cont, $cont, %cont, @countries, @urls, %seen); + my $no_previous_warn = + "Sorry! since you don't have any existing picks, you must make a\n" . + "geographic selection."; + my $offer_cont = [sort $mirrors->continents]; + if (@previous_urls) { + push @$offer_cont, "(edit previous picks)"; + $default = @$offer_cont; + } else { + # cannot allow nothing because nothing means paging! + # push @$offer_cont, "(none of the above)"; + } + @cont = picklist($offer_cont, + "Select your continent (or several nearby continents)", + $default, + ! @previous_urls, + $no_previous_warn); + # cannot allow nothing because nothing means paging! + # return unless @cont; + + foreach $cont (@cont) { + my @c = sort $mirrors->countries($cont); + @cont{@c} = map ($cont, 0..$#c); + @c = map ("$_ ($cont)", @c) if @cont > 1; + push (@countries, @c); + } + if (@previous_urls && @countries) { + push @countries, "(edit previous picks)"; + $default = @countries; + } + + if (@countries) { + @countries = picklist (\@countries, + "Select your country (or several nearby countries)", + $default, + ! @previous_urls, + $no_previous_warn); + %seen = map (($_ => 1), @previous_urls); + # hmmm, should take list of defaults from CPAN::Config->{'urllist'}... + foreach my $country (@countries) { + next if $country =~ /edit previous picks/; + (my $bare_country = $country) =~ s/ \(.*\)//; + my @u; + for my $m ( $mirrors->mirrors($bare_country) ) { + push @u, $m->ftp if $m->ftp; + push @u, $m->http if $m->http; + } + @u = grep (! $seen{$_}, @u); + @u = map ("$_ ($bare_country)", @u) + if @countries > 1; + push (@urls, sort @u); + } + } + push (@urls, map ("$_ (previous pick)", @previous_urls)); + my $prompt = "Select as many URLs as you like (by number), +put them on one line, separated by blanks, hyphenated ranges allowed + e.g. '1 4 5' or '7 1-4 8'"; + if (@previous_urls) { + $default = join (' ', ((scalar @urls) - (scalar @previous_urls) + 1) .. + (scalar @urls)); + $prompt .= "\n(or just hit RETURN to keep your previous picks)"; + } + + @urls = picklist (\@urls, $prompt, $default); + foreach (@urls) { s/ \(.*\)//; } + return [ @urls ]; +} + +sub bring_your_own { + my $urllist = [ @{$CPAN::Config->{urllist}} ]; + my %seen = map (($_ => 1), @$urllist); + my($ans,@urls); + my $eacnt = 0; # empty answers + $CPAN::Frontend->myprint(<<'HERE'); + +Now you can enter your own CPAN URLs by hand. A local CPAN mirror can be +listed using a 'file:' URL like 'file:///path/to/cpan/' + +HERE + do { + my $prompt = "Enter another URL or RETURN to quit:"; + unless (%seen) { + $prompt = qq{CPAN.pm needs at least one URL where it can fetch CPAN files from. + +Please enter your CPAN site:}; + } + $ans = prompt ($prompt, ""); + + if ($ans) { + $ans =~ s|/?\z|/|; # has to end with one slash + # XXX This manipulation is odd. Shouldn't we check that $ans is + # a directory before converting to file:///? And we need /// below, + # too, don't we? -- dagolden, 2009-11-05 + $ans = "file:$ans" unless $ans =~ /:/; # without a scheme is a file: + if ($ans =~ /^\w+:\/./) { + push @urls, $ans unless $seen{$ans}++; + } else { + $CPAN::Frontend-> + myprint(sprintf(qq{"%s" doesn\'t look like an URL at first sight. +I\'ll ignore it for now. +You can add it to your %s +later if you\'re sure it\'s right.\n}, + $ans, + $INC{'CPAN/MyConfig.pm'} + || $INC{'CPAN/Config.pm'} + || "configuration file", + )); + } + } else { + if (++$eacnt >= 5) { + $CPAN::Frontend-> + mywarn("Giving up.\n"); + $CPAN::Frontend->mysleep(5); + return; + } + } + } while $ans || !%seen; + + @$urllist = CPAN::_uniq(@$urllist, @urls); + $CPAN::Config->{urllist} = $urllist; +} + +sub _print_urllist { + $CPAN::Frontend->myprint("New urllist\n"); + for ( @{$CPAN::Config->{urllist} || []} ) { + $CPAN::Frontend->myprint(" $_\n") + }; +} + +sub _strip_spaces { + $_[0] =~ s/^\s+//; # no leading spaces + $_[0] =~ s/\s+\z//; # no trailing spaces +} + +sub prompt ($;$) { + unless (defined &_real_prompt) { + *_real_prompt = \&CPAN::Shell::colorable_makemaker_prompt; + } + my $ans = _real_prompt(@_); + + _strip_spaces($ans); + $CPAN::Frontend->myprint("\n"); + + return $ans; +} + + +sub prompt_no_strip ($;$) { + return _real_prompt(@_); +} + + + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/HandleConfig.pm b/Master/tlpkg/tlperl/lib/CPAN/HandleConfig.pm new file mode 100644 index 00000000000..76cd81eee8b --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/HandleConfig.pm @@ -0,0 +1,741 @@ +package CPAN::HandleConfig; +use strict; +use vars qw(%can %keys $loading $VERSION); + +$VERSION = "5.5001"; # see also CPAN::Config::VERSION at end of file + +%can = ( + commit => "Commit changes to disk", + defaults => "Reload defaults from disk", + help => "Short help about 'o conf' usage", + init => "Interactive setting of all options", +); + +# Q: where is the "How do I add a new config option" HOWTO? +# A1: svn diff -r 757:758 # where dagolden added test_report +# A2: svn diff -r 985:986 # where andk added yaml_module +# A3: 1. add new config option to %keys below +# 2. add a Pod description in CPAN::FirstTime; it should include a +# prompt line; see others for examples +# 3. add a "matcher" section in CPAN::FirstTime::init that includes +# a prompt function; see others for examples +# 4. add config option to documentation section in CPAN.pm + +%keys = map { $_ => undef } + ( + "applypatch", + "auto_commit", + "build_cache", + "build_dir", + "build_dir_reuse", + "build_requires_install_policy", + "bzip2", + "cache_metadata", + "check_sigs", + "colorize_debug", + "colorize_output", + "colorize_print", + "colorize_warn", + "commandnumber_in_prompt", + "commands_quote", + "connect_to_internet_ok", + "cpan_home", + "curl", + "dontload_hash", # deprecated after 1.83_68 (rev. 581) + "dontload_list", + "ftp", + "ftp_passive", + "ftp_proxy", + "ftpstats_size", + "ftpstats_period", + "getcwd", + "gpg", + "gzip", + "halt_on_failure", + "histfile", + "histsize", + "http_proxy", + "inactivity_timeout", + "index_expire", + "inhibit_startup_message", + "keep_source_where", + "load_module_verbosity", + "lynx", + "make", + "make_arg", + "make_install_arg", + "make_install_make_command", + "makepl_arg", + "mbuild_arg", + "mbuild_install_arg", + "mbuild_install_build_command", + "mbuildpl_arg", + "ncftp", + "ncftpget", + "no_proxy", + "pager", + "password", + "patch", + "patches_dir", + "perl5lib_verbosity", + "prefer_installer", + "prefs_dir", + "prerequisites_policy", + "proxy_pass", + "proxy_user", + "randomize_urllist", + "scan_cache", + "shell", + "show_unparsable_versions", + "show_upload_date", + "show_zero_versions", + "tar", + "tar_verbosity", + "term_is_latin", + "term_ornaments", + "test_report", + "trust_test_report_history", + "unzip", + "urllist", + "use_sqlite", + "username", + "version_timeout", + "wait_list", + "wget", + "yaml_load_code", + "yaml_module", + ); + +my %prefssupport = map { $_ => 1 } + ( + "build_requires_install_policy", + "check_sigs", + "make", + "make_install_make_command", + "prefer_installer", + "test_report", + ); + +# returns true on successful action +sub edit { + my($self,@args) = @_; + return unless @args; + CPAN->debug("self[$self]args[".join(" | ",@args)."]"); + my($o,$str,$func,$args,$key_exists); + $o = shift @args; + if($can{$o}) { + my $success = $self->$o(args => \@args); # o conf init => sub init => sub load + unless ($success) { + die "Panic: could not configure CPAN.pm for args [@args]. Giving up."; + } + } else { + CPAN->debug("o[$o]") if $CPAN::DEBUG; + unless (exists $keys{$o}) { + $CPAN::Frontend->mywarn("Warning: unknown configuration variable '$o'\n"); + } + my $changed; + + + # one day I used randomize_urllist for a boolean, so we must + # list them explicitly --ak + if (0) { + } elsif ($o =~ /^(wait_list|urllist|dontload_list)$/) { + + # + # ARRAYS + # + + $func = shift @args; + $func ||= ""; + CPAN->debug("func[$func]args[@args]") if $CPAN::DEBUG; + # Let's avoid eval, it's easier to comprehend without. + if ($func eq "push") { + push @{$CPAN::Config->{$o}}, @args; + $changed = 1; + } elsif ($func eq "pop") { + pop @{$CPAN::Config->{$o}}; + $changed = 1; + } elsif ($func eq "shift") { + shift @{$CPAN::Config->{$o}}; + $changed = 1; + } elsif ($func eq "unshift") { + unshift @{$CPAN::Config->{$o}}, @args; + $changed = 1; + } elsif ($func eq "splice") { + my $offset = shift @args || 0; + my $length = shift @args || 0; + splice @{$CPAN::Config->{$o}}, $offset, $length, @args; # may warn + $changed = 1; + } elsif ($func) { + $CPAN::Config->{$o} = [$func, @args]; + $changed = 1; + } else { + $self->prettyprint($o); + } + if ($changed) { + if ($o eq "urllist") { + # reset the cached values + undef $CPAN::FTP::Thesite; + undef $CPAN::FTP::Themethod; + $CPAN::Index::LAST_TIME = 0; + } elsif ($o eq "dontload_list") { + # empty it, it will be built up again + $CPAN::META->{dontload_hash} = {}; + } + } + } elsif ($o =~ /_hash$/) { + + # + # HASHES + # + + if (@args==1 && $args[0] eq "") { + @args = (); + } elsif (@args % 2) { + push @args, ""; + } + $CPAN::Config->{$o} = { @args }; + $changed = 1; + } else { + + # + # SCALARS + # + + if (defined $args[0]) { + $CPAN::CONFIG_DIRTY = 1; + $CPAN::Config->{$o} = $args[0]; + $changed = 1; + } + $self->prettyprint($o) + if exists $keys{$o} or defined $CPAN::Config->{$o}; + } + if ($changed) { + if ($CPAN::Config->{auto_commit}) { + $self->commit; + } else { + $CPAN::CONFIG_DIRTY = 1; + $CPAN::Frontend->myprint("Please use 'o conf commit' to ". + "make the config permanent!\n\n"); + } + } + } +} + +sub prettyprint { + my($self,$k) = @_; + my $v = $CPAN::Config->{$k}; + if (ref $v) { + my(@report); + if (ref $v eq "ARRAY") { + @report = map {"\t$_ \[$v->[$_]]\n"} 0..$#$v; + } else { + @report = map + { + sprintf "\t%-18s => %s\n", + "[$_]", + defined $v->{$_} ? "[$v->{$_}]" : "undef" + } keys %$v; + } + $CPAN::Frontend->myprint( + join( + "", + sprintf( + " %-18s\n", + $k + ), + @report + ) + ); + } elsif (defined $v) { + $CPAN::Frontend->myprint(sprintf " %-18s [%s]\n", $k, $v); + } else { + $CPAN::Frontend->myprint(sprintf " %-18s undef\n", $k); + } +} + +sub commit { + my($self,@args) = @_; + CPAN->debug("args[@args]") if $CPAN::DEBUG; + if ($CPAN::RUN_DEGRADED) { + $CPAN::Frontend->mydie( + "'o conf commit' disabled in ". + "degraded mode. Maybe try\n". + " !undef \$CPAN::RUN_DEGRADED\n" + ); + } + my $configpm; + if (@args) { + if ($args[0] eq "args") { + # we have not signed that contract + } else { + $configpm = $args[0]; + } + } + unless (defined $configpm) { + $configpm ||= $INC{"CPAN/MyConfig.pm"}; + $configpm ||= $INC{"CPAN/Config.pm"}; + $configpm || Carp::confess(q{ +CPAN::Config::commit called without an argument. +Please specify a filename where to save the configuration or try +"o conf init" to have an interactive course through configing. +}); + } + my($mode); + if (-f $configpm) { + $mode = (stat $configpm)[2]; + if ($mode && ! -w _) { + Carp::confess("$configpm is not writable"); + } + } + + my $msg; + my $home = home(); + $msg = <<EOF unless $configpm =~ /MyConfig/; + +# This is CPAN.pm's systemwide configuration file. This file provides +# defaults for users, and the values can be changed in a per-user +# configuration file. The user-config file is being looked for as +# $home/.cpan/CPAN/MyConfig.pm. + +EOF + $msg ||= "\n"; + my($fh) = FileHandle->new; + rename $configpm, "$configpm~" if -f $configpm; + open $fh, ">$configpm" or + $CPAN::Frontend->mydie("Couldn't open >$configpm: $!"); + $fh->print(qq[$msg\$CPAN::Config = \{\n]); + foreach (sort keys %$CPAN::Config) { + unless (exists $keys{$_}) { + # do not drop them: forward compatibility! + $CPAN::Frontend->mywarn("Unknown config variable '$_'\n"); + next; + } + $fh->print( + " '$_' => ", + $self->neatvalue($CPAN::Config->{$_}), + ",\n" + ); + } + + $fh->print("};\n1;\n__END__\n"); + close $fh; + + #$mode = 0444 | ( $mode & 0111 ? 0111 : 0 ); + #chmod $mode, $configpm; +###why was that so? $self->defaults; + $CPAN::Frontend->myprint("commit: wrote '$configpm'\n"); + $CPAN::CONFIG_DIRTY = 0; + 1; +} + +# stolen from MakeMaker; not taking the original because it is buggy; +# bugreport will have to say: keys of hashes remain unquoted and can +# produce syntax errors +sub neatvalue { + my($self, $v) = @_; + return "undef" unless defined $v; + my($t) = ref $v; + unless ($t) { + $v =~ s/\\/\\\\/g; + return "q[$v]"; + } + if ($t eq 'ARRAY') { + my(@m, @neat); + push @m, "["; + foreach my $elem (@$v) { + push @neat, "q[$elem]"; + } + push @m, join ", ", @neat; + push @m, "]"; + return join "", @m; + } + return "$v" unless $t eq 'HASH'; + my(@m, $key, $val); + while (($key,$val) = each %$v) { + last unless defined $key; # cautious programming in case (undef,undef) is true + push(@m,"q[$key]=>".$self->neatvalue($val)) ; + } + return "{ ".join(', ',@m)." }"; +} + +sub defaults { + my($self) = @_; + if ($CPAN::RUN_DEGRADED) { + $CPAN::Frontend->mydie( + "'o conf defaults' disabled in ". + "degraded mode. Maybe try\n". + " !undef \$CPAN::RUN_DEGRADED\n" + ); + } + my $done; + for my $config (qw(CPAN/MyConfig.pm CPAN/Config.pm)) { + if ($INC{$config}) { + CPAN->debug("INC{'$config'}[$INC{$config}]") if $CPAN::DEBUG; + CPAN::Shell->_reload_this($config,{reloforce => 1}); + $CPAN::Frontend->myprint("'$INC{$config}' reread\n"); + last; + } + } + $CPAN::CONFIG_DIRTY = 0; + 1; +} + +=head2 C<< CLASS->safe_quote ITEM >> + +Quotes an item to become safe against spaces +in shell interpolation. An item is enclosed +in double quotes if: + + - the item contains spaces in the middle + - the item does not start with a quote + +This happens to avoid shell interpolation +problems when whitespace is present in +directory names. + +This method uses C<commands_quote> to determine +the correct quote. If C<commands_quote> is +a space, no quoting will take place. + + +if it starts and ends with the same quote character: leave it as it is + +if it contains no whitespace: leave it as it is + +if it contains whitespace, then + +if it contains quotes: better leave it as it is + +else: quote it with the correct quote type for the box we're on + +=cut + +{ + # Instead of patching the guess, set commands_quote + # to the right value + my ($quotes,$use_quote) + = $^O eq 'MSWin32' + ? ('"', '"') + : (q{"'}, "'") + ; + + sub safe_quote { + my ($self, $command) = @_; + # Set up quote/default quote + my $quote = $CPAN::Config->{commands_quote} || $quotes; + + if ($quote ne ' ' + and defined($command ) + and $command =~ /\s/ + and $command !~ /[$quote]/) { + return qq<$use_quote$command$use_quote> + } + return $command; + } +} + +sub init { + my($self,@args) = @_; + CPAN->debug("self[$self]args[".join(",",@args)."]"); + $self->load(doit => 1, @args); + 1; +} + +# This is a piece of repeated code that is abstracted here for +# maintainability. RMB +# +sub _configpmtest { + my($configpmdir, $configpmtest) = @_; + if (-w $configpmtest) { + return $configpmtest; + } elsif (-w $configpmdir) { + #_#_# following code dumped core on me with 5.003_11, a.k. + my $configpm_bak = "$configpmtest.bak"; + unlink $configpm_bak if -f $configpm_bak; + if( -f $configpmtest ) { + if( rename $configpmtest, $configpm_bak ) { + $CPAN::Frontend->mywarn(<<END); +Old configuration file $configpmtest + moved to $configpm_bak +END + } + } + my $fh = FileHandle->new; + if ($fh->open(">$configpmtest")) { + $fh->print("1;\n"); + return $configpmtest; + } else { + # Should never happen + Carp::confess("Cannot open >$configpmtest"); + } + } else { return } +} + +sub require_myconfig_or_config () { + return if $INC{"CPAN/MyConfig.pm"}; + local @INC = @INC; + my $home = home(); + unshift @INC, File::Spec->catdir($home,'.cpan'); + eval { require CPAN::MyConfig }; + my $err_myconfig = $@; + if ($err_myconfig and $err_myconfig !~ m#locate CPAN/MyConfig\.pm#) { + die "Error while requiring CPAN::MyConfig:\n$err_myconfig"; + } + unless ($INC{"CPAN/MyConfig.pm"}) { # this guy has settled his needs already + eval {require CPAN::Config;}; # not everybody has one + my $err_config = $@; + if ($err_config and $err_config !~ m#locate CPAN/Config\.pm#) { + die "Error while requiring CPAN::Config:\n$err_config"; + } + } +} + +sub home () { + my $home; + # Suppress load messages until we load the config and know whether + # load messages are desired. Otherwise, it's unexpected and odd + # why one load message pops up even when verbosity is turned off. + # This means File::HomeDir load messages are never seen, but I + # think that's probably OK -- DAGOLDEN + + # 5.6.2 seemed to segfault localizing a value in a hashref + # so do it manually instead + my $old_v = $CPAN::Config->{load_module_verbosity}; + $CPAN::Config->{load_module_verbosity} = q[none]; + if ($CPAN::META->has_usable("File::HomeDir")) { + if ($^O eq 'darwin') { + $home = File::HomeDir->my_home; # my_data is ~/Library/Application Support on darwin, + # which causes issues in the toolchain. + } + else { + $home = File::HomeDir->my_data || File::HomeDir->my_home; + } + } + unless (defined $home) { + $home = $ENV{HOME}; + } + $CPAN::Config->{load_module_verbosity} = $old_v; + $home; +} + +sub load { + my($self, %args) = @_; + $CPAN::Be_Silent++ if $args{be_silent}; + my $doit; + $doit = delete $args{doit} || 0; + $loading = 0 unless defined $loading; + + use Carp; + require_myconfig_or_config; + my @miss = $self->missing_config_data; + CPAN->debug("doit[$doit]loading[$loading]miss[@miss]") if $CPAN::DEBUG; + return unless $doit || @miss; + return if $loading; + local $loading = ($loading||0) + 1; + + require CPAN::FirstTime; + my($redo,$configpm,$fh); + if (defined $INC{"CPAN/Config.pm"} && -w $INC{"CPAN/Config.pm"}) { + $configpm = $INC{"CPAN/Config.pm"}; + $redo++; + } elsif (defined $INC{"CPAN/MyConfig.pm"} && -w $INC{"CPAN/MyConfig.pm"}) { + $configpm = $INC{"CPAN/MyConfig.pm"}; + $redo++; + } else { + my($path_to_cpan) = File::Basename::dirname($INC{"CPAN.pm"}); + my($configpmdir) = File::Spec->catdir($path_to_cpan,"CPAN"); + my($configpmtest) = File::Spec->catfile($configpmdir,"Config.pm"); + my $inc_key; + if (-d $configpmdir or File::Path::mkpath($configpmdir)) { + $configpm = _configpmtest($configpmdir,$configpmtest); + $inc_key = "CPAN/Config.pm"; + } + unless ($configpm) { + $configpmdir = File::Spec->catdir(home,".cpan","CPAN"); + File::Path::mkpath($configpmdir); + $configpmtest = File::Spec->catfile($configpmdir,"MyConfig.pm"); + $configpm = _configpmtest($configpmdir,$configpmtest); + $inc_key = "CPAN/MyConfig.pm"; + } + if ($configpm) { + $INC{$inc_key} = $configpm; + } else { + my $myconfigpm = File::Spec->catfile(home,".cpan","CPAN","MyConfig.pm"); + $CPAN::Frontend->mydie(<<"END"); +WARNING: CPAN.pm is unable to write a configuration file. You need write +access to your default perl library directories or you must be able to +create and write to '$myconfigpm'. + +Aborting configuration. +END + } + + } + local($") = ", "; + if ($redo && !$doit) { + $CPAN::Frontend->myprint(<<END); +Sorry, we have to rerun the configuration dialog for CPAN.pm due to +some missing parameters... Will write to + <<$configpm>> + +END + $args{args} = \@miss; + } + my $initialized = CPAN::FirstTime::init($configpm, %args); + return $initialized; +} + + +# returns mandatory but missing entries in the Config +sub missing_config_data { + my(@miss); + for ( + "auto_commit", + "build_cache", + "build_dir", + "cache_metadata", + "cpan_home", + "ftp_proxy", + #"gzip", + "http_proxy", + "index_expire", + #"inhibit_startup_message", + "keep_source_where", + #"make", + "make_arg", + "make_install_arg", + "makepl_arg", + "mbuild_arg", + "mbuild_install_arg", + ($^O eq "MSWin32" ? "" : "mbuild_install_build_command"), + "mbuildpl_arg", + "no_proxy", + #"pager", + "prerequisites_policy", + "scan_cache", + #"tar", + #"unzip", + "urllist", + ) { + next unless exists $keys{$_}; + push @miss, $_ unless defined $CPAN::Config->{$_}; + } + return @miss; +} + +sub help { + $CPAN::Frontend->myprint(q[ +Known options: + commit commit session changes to disk + defaults reload default config values from disk + help this help + init enter a dialog to set all or a set of parameters + +Edit key values as in the following (the "o" is a literal letter o): + o conf build_cache 15 + o conf build_dir "/foo/bar" + o conf urllist shift + o conf urllist unshift ftp://ftp.foo.bar/ + o conf inhibit_startup_message 1 + +]); + 1; #don't reprint CPAN::Config +} + +sub cpl { + my($word,$line,$pos) = @_; + $word ||= ""; + CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG; + my(@words) = split " ", substr($line,0,$pos+1); + if ( + defined($words[2]) + and + $words[2] =~ /list$/ + and + ( + @words == 3 + || + @words == 4 && length($word) + ) + ) { + return grep /^\Q$word\E/, qw(splice shift unshift pop push); + } elsif (defined($words[2]) + and + $words[2] eq "init" + and + ( + @words == 3 + || + @words >= 4 && length($word) + )) { + return sort grep /^\Q$word\E/, keys %keys; + } elsif (@words >= 4) { + return (); + } + my %seen; + my(@o_conf) = sort grep { !$seen{$_}++ } + keys %can, + keys %$CPAN::Config, + keys %keys; + return grep /^\Q$word\E/, @o_conf; +} + +sub prefs_lookup { + my($self,$distro,$what) = @_; + + if ($prefssupport{$what}) { + return $CPAN::Config->{$what} unless + $distro + and $distro->prefs + and $distro->prefs->{cpanconfig} + and defined $distro->prefs->{cpanconfig}{$what}; + return $distro->prefs->{cpanconfig}{$what}; + } else { + $CPAN::Frontend->mywarn("Warning: $what not yet officially ". + "supported for distroprefs, doing a normal lookup"); + return $CPAN::Config->{$what}; + } +} + + +{ + package + CPAN::Config; ####::###### #hide from indexer + # note: J. Nick Koston wrote me that they are using + # CPAN::Config->commit although undocumented. I suggested + # CPAN::Shell->o("conf","commit") even when ugly it is at least + # documented + + # that's why I added the CPAN::Config class with autoload and + # deprecated warning + + use strict; + use vars qw($AUTOLOAD $VERSION); + $VERSION = "5.5001"; + + # formerly CPAN::HandleConfig was known as CPAN::Config + sub AUTOLOAD { ## no critic + my $class = shift; # e.g. in dh-make-perl: CPAN::Config + my($l) = $AUTOLOAD; + $CPAN::Frontend->mywarn("Dispatching deprecated method '$l' to CPAN::HandleConfig\n"); + $l =~ s/.*:://; + CPAN::HandleConfig->$l(@_); + } +} + +1; + +__END__ + +=head1 LICENSE + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=cut + +# Local Variables: +# mode: cperl +# cperl-indent-level: 4 +# End: diff --git a/Master/tlpkg/tlperl/lib/CPAN/Index.pm b/Master/tlpkg/tlperl/lib/CPAN/Index.pm new file mode 100644 index 00000000000..9df757de706 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Index.pm @@ -0,0 +1,619 @@ +package CPAN::Index; +use strict; +use vars qw($LAST_TIME $DATE_OF_02 $DATE_OF_03 $HAVE_REANIMATED $VERSION); +$VERSION = "1.94"; +@CPAN::Index::ISA = qw(CPAN::Debug); +$LAST_TIME ||= 0; +$DATE_OF_03 ||= 0; +# use constant PROTOCOL => "2.0"; # outcommented to avoid warning on upgrade from 1.57 +sub PROTOCOL { 2.0 } + +#-> sub CPAN::Index::force_reload ; +sub force_reload { + my($class) = @_; + $CPAN::Index::LAST_TIME = 0; + $class->reload(1); +} + +my @indexbundle = + ( + { + reader => "rd_authindex", + dir => "authors", + remotefile => '01mailrc.txt.gz', + shortlocalfile => '01mailrc.gz', + }, + { + reader => "rd_modpacks", + dir => "modules", + remotefile => '02packages.details.txt.gz', + shortlocalfile => '02packag.gz', + }, + { + reader => "rd_modlist", + dir => "modules", + remotefile => '03modlist.data.gz', + shortlocalfile => '03mlist.gz', + }, + ); + +#-> sub CPAN::Index::reload ; +sub reload { + my($self,$force) = @_; + my $time = time; + + # XXX check if a newer one is available. (We currently read it + # from time to time) + for ($CPAN::Config->{index_expire}) { + $_ = 0.001 unless $_ && $_ > 0.001; + } + unless (1 || $CPAN::Have_warned->{readmetadatacache}++) { + # debug here when CPAN doesn't seem to read the Metadata + require Carp; + Carp::cluck("META-PROTOCOL[$CPAN::META->{PROTOCOL}]"); + } + unless ($CPAN::META->{PROTOCOL}) { + $self->read_metadata_cache; + $CPAN::META->{PROTOCOL} ||= "1.0"; + } + if ( $CPAN::META->{PROTOCOL} < PROTOCOL ) { + # warn "Setting last_time to 0"; + $LAST_TIME = 0; # No warning necessary + } + if ($LAST_TIME + $CPAN::Config->{index_expire}*86400 > $time + and ! $force) { + # called too often + # CPAN->debug("LAST_TIME[$LAST_TIME]index_expire[$CPAN::Config->{index_expire}]time[$time]"); + } elsif (0) { + # IFF we are developing, it helps to wipe out the memory + # between reloads, otherwise it is not what a user expects. + undef $CPAN::META; # Neue Gruendlichkeit since v1.52(r1.274) + $CPAN::META = CPAN->new; + } else { + my($debug,$t2); + local $LAST_TIME = $time; + local $CPAN::META->{PROTOCOL} = PROTOCOL; + + my $needshort = $^O eq "dos"; + + INX: for my $indexbundle (@indexbundle) { + my $reader = $indexbundle->{reader}; + my $localfile = $needshort ? $indexbundle->{shortlocalfile} : $indexbundle->{remotefile}; + my $localpath = File::Spec->catfile($indexbundle->{dir}, $localfile); + my $remote = join "/", $indexbundle->{dir}, $indexbundle->{remotefile}; + my $localized = $self->reload_x($remote, $localpath, $force); + $self->$reader($localized); # may die but we let the shell catch it + if ($CPAN::DEBUG){ + $t2 = time; + $debug = "timing reading 01[".($t2 - $time)."]"; + $time = $t2; + } + return if $CPAN::Signal; # this is sometimes lengthy + } + $self->write_metadata_cache; + if ($CPAN::DEBUG){ + $t2 = time; + $debug .= "03[".($t2 - $time)."]"; + $time = $t2; + } + CPAN->debug($debug) if $CPAN::DEBUG; + } + if ($CPAN::Config->{build_dir_reuse}) { + $self->reanimate_build_dir; + } + if (CPAN::_sqlite_running()) { + $CPAN::SQLite->reload(time => $time, force => $force) + if not $LAST_TIME; + } + $LAST_TIME = $time; + $CPAN::META->{PROTOCOL} = PROTOCOL; +} + +#-> sub CPAN::Index::reanimate_build_dir ; +sub reanimate_build_dir { + my($self) = @_; + unless ($CPAN::META->has_inst($CPAN::Config->{yaml_module}||"YAML")) { + return; + } + return if $HAVE_REANIMATED++; + my $d = $CPAN::Config->{build_dir}; + my $dh = DirHandle->new; + opendir $dh, $d or return; # does not exist + my $dirent; + my $i = 0; + my $painted = 0; + my $restored = 0; + my @candidates = map { $_->[0] } + sort { $b->[1] <=> $a->[1] } + map { [ $_, -M File::Spec->catfile($d,$_) ] } + grep {/\.yml$/} readdir $dh; + unless (@candidates) { + $CPAN::Frontend->myprint("Build_dir empty, nothing to restore\n"); + return; + } + $CPAN::Frontend->myprint + (sprintf("Going to read %d yaml file%s from %s/\n", + scalar @candidates, + @candidates==1 ? "" : "s", + $CPAN::Config->{build_dir} + )); + my $start = CPAN::FTP::_mytime(); + DISTRO: for $i (0..$#candidates) { + my $dirent = $candidates[$i]; + my $y = eval {CPAN->_yaml_loadfile(File::Spec->catfile($d,$dirent))}; + if ($@) { + warn "Error while parsing file '$dirent'; error: '$@'"; + next DISTRO; + } + my $c = $y->[0]; + if ($c && $c->{perl} && $c->{distribution} && CPAN->_perl_fingerprint($c->{perl})) { + my $key = $c->{distribution}{ID}; + for my $k (keys %{$c->{distribution}}) { + if ($c->{distribution}{$k} + && ref $c->{distribution}{$k} + && UNIVERSAL::isa($c->{distribution}{$k},"CPAN::Distrostatus")) { + $c->{distribution}{$k}{COMMANDID} = $i - @candidates; + } + } + + #we tried to restore only if element already + #exists; but then we do not work with metadata + #turned off. + my $do + = $CPAN::META->{readwrite}{'CPAN::Distribution'}{$key} + = $c->{distribution}; + for my $skipper (qw( + badtestcnt + configure_requires_later + configure_requires_later_for + force_update + later + later_for + notest + should_report + sponsored_mods + prefs + negative_prefs_cache + )) { + delete $do->{$skipper}; + } + if ($do->can("tested_ok_but_not_installed")) { + if ($do->tested_ok_but_not_installed) { + $CPAN::META->is_tested($do->{build_dir},$do->{make_test}{TIME}); + } else { + next DISTRO; + } + } + $restored++; + } + $i++; + while (($painted/76) < ($i/@candidates)) { + $CPAN::Frontend->myprint("."); + $painted++; + } + } + my $took = CPAN::FTP::_mytime() - $start; + $CPAN::Frontend->myprint(sprintf( + "DONE\nRestored the state of %s (in %.4f secs)\n", + $restored || "none", + $took, + )); +} + + +#-> sub CPAN::Index::reload_x ; +sub reload_x { + my($cl,$wanted,$localname,$force) = @_; + $force |= 2; # means we're dealing with an index here + CPAN::HandleConfig->load; # we should guarantee loading wherever + # we rely on Config XXX + $localname ||= $wanted; + my $abs_wanted = File::Spec->catfile($CPAN::Config->{'keep_source_where'}, + $localname); + if ( + -f $abs_wanted && + -M $abs_wanted < $CPAN::Config->{'index_expire'} && + !($force & 1) + ) { + my $s = $CPAN::Config->{'index_expire'} == 1 ? "" : "s"; + $cl->debug(qq{$abs_wanted younger than $CPAN::Config->{'index_expire'} }. + qq{day$s. I\'ll use that.}); + return $abs_wanted; + } else { + $force |= 1; # means we're quite serious about it. + } + return CPAN::FTP->localize($wanted,$abs_wanted,$force); +} + +#-> sub CPAN::Index::rd_authindex ; +sub rd_authindex { + my($cl, $index_target) = @_; + return unless defined $index_target; + return if CPAN::_sqlite_running(); + my @lines; + $CPAN::Frontend->myprint("Going to read '$index_target'\n"); + local(*FH); + tie *FH, 'CPAN::Tarzip', $index_target; + local($/) = "\n"; + local($_); + push @lines, split /\012/ while <FH>; + my $i = 0; + my $painted = 0; + foreach (@lines) { + my($userid,$fullname,$email) = + m/alias\s+(\S+)\s+\"([^\"\<]*)\s+\<(.*)\>\"/; + $fullname ||= $email; + if ($userid && $fullname && $email) { + my $userobj = $CPAN::META->instance('CPAN::Author',$userid); + $userobj->set('FULLNAME' => $fullname, 'EMAIL' => $email); + } else { + CPAN->debug(sprintf "line[%s]", $_) if $CPAN::DEBUG; + } + $i++; + while (($painted/76) < ($i/@lines)) { + $CPAN::Frontend->myprint("."); + $painted++; + } + return if $CPAN::Signal; + } + $CPAN::Frontend->myprint("DONE\n"); +} + +sub userid { + my($self,$dist) = @_; + $dist = $self->{'id'} unless defined $dist; + my($ret) = $dist =~ m|(?:\w/\w\w/)?([^/]+)/|; + $ret; +} + +#-> sub CPAN::Index::rd_modpacks ; +sub rd_modpacks { + my($self, $index_target) = @_; + return unless defined $index_target; + return if CPAN::_sqlite_running(); + $CPAN::Frontend->myprint("Going to read '$index_target'\n"); + my $fh = CPAN::Tarzip->TIEHANDLE($index_target); + local $_; + CPAN->debug(sprintf "start[%d]", time) if $CPAN::DEBUG; + my $slurp = ""; + my $chunk; + while (my $bytes = $fh->READ(\$chunk,8192)) { + $slurp.=$chunk; + } + my @lines = split /\012/, $slurp; + CPAN->debug(sprintf "end[%d]", time) if $CPAN::DEBUG; + undef $fh; + # read header + my($line_count,$last_updated); + while (@lines) { + my $shift = shift(@lines); + last if $shift =~ /^\s*$/; + $shift =~ /^Line-Count:\s+(\d+)/ and $line_count = $1; + $shift =~ /^Last-Updated:\s+(.+)/ and $last_updated = $1; + } + CPAN->debug("line_count[$line_count]last_updated[$last_updated]") if $CPAN::DEBUG; + if (not defined $line_count) { + + $CPAN::Frontend->mywarn(qq{Warning: Your $index_target does not contain a Line-Count header. +Please check the validity of the index file by comparing it to more +than one CPAN mirror. I'll continue but problems seem likely to +happen.\a +}); + + $CPAN::Frontend->mysleep(5); + } elsif ($line_count != scalar @lines) { + + $CPAN::Frontend->mywarn(sprintf qq{Warning: Your %s +contains a Line-Count header of %d but I see %d lines there. Please +check the validity of the index file by comparing it to more than one +CPAN mirror. I'll continue but problems seem likely to happen.\a\n}, +$index_target, $line_count, scalar(@lines)); + + } + if (not defined $last_updated) { + + $CPAN::Frontend->mywarn(qq{Warning: Your $index_target does not contain a Last-Updated header. +Please check the validity of the index file by comparing it to more +than one CPAN mirror. I'll continue but problems seem likely to +happen.\a +}); + + $CPAN::Frontend->mysleep(5); + } else { + + $CPAN::Frontend + ->myprint(sprintf qq{ Database was generated on %s\n}, + $last_updated); + $DATE_OF_02 = $last_updated; + + my $age = time; + if ($CPAN::META->has_inst('HTTP::Date')) { + require HTTP::Date; + $age -= HTTP::Date::str2time($last_updated); + } else { + $CPAN::Frontend->mywarn(" HTTP::Date not available\n"); + require Time::Local; + my(@d) = $last_updated =~ / (\d+) (\w+) (\d+) (\d+):(\d+):(\d+) /; + $d[1] = index("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec", $d[1])/4; + $age -= $d[1]>=0 ? Time::Local::timegm(@d[5,4,3,0,1,2]) : 0; + } + $age /= 3600*24; + if ($age > 30) { + + $CPAN::Frontend + ->mywarn(sprintf + qq{Warning: This index file is %d days old. + Please check the host you chose as your CPAN mirror for staleness. + I'll continue but problems seem likely to happen.\a\n}, + $age); + + } elsif ($age < -1) { + + $CPAN::Frontend + ->mywarn(sprintf + qq{Warning: Your system date is %d days behind this index file! + System time: %s + Timestamp index file: %s + Please fix your system time, problems with the make command expected.\n}, + -$age, + scalar gmtime, + $DATE_OF_02, + ); + + } + } + + + # A necessity since we have metadata_cache: delete what isn't + # there anymore + my $secondtime = $CPAN::META->exists("CPAN::Module","CPAN"); + CPAN->debug("secondtime[$secondtime]") if $CPAN::DEBUG; + my(%exists); + my $i = 0; + my $painted = 0; + foreach (@lines) { + # before 1.56 we split into 3 and discarded the rest. From + # 1.57 we assign remaining text to $comment thus allowing to + # influence isa_perl + my($mod,$version,$dist,$comment) = split " ", $_, 4; + unless ($mod && defined $version && $dist) { + $CPAN::Frontend->mywarn("Could not split line[$_]\n"); + next; + } + my($bundle,$id,$userid); + + if ($mod eq 'CPAN' && + ! ( + CPAN::Queue->exists('Bundle::CPAN') || + CPAN::Queue->exists('CPAN') + ) + ) { + local($^W)= 0; + if ($version > $CPAN::VERSION) { + $CPAN::Frontend->mywarn(qq{ + New CPAN.pm version (v$version) available. + [Currently running version is v$CPAN::VERSION] + You might want to try + install CPAN + reload cpan + to both upgrade CPAN.pm and run the new version without leaving + the current session. + +}); #}); + $CPAN::Frontend->mysleep(2); + $CPAN::Frontend->myprint(qq{\n}); + } + last if $CPAN::Signal; + } elsif ($mod =~ /^Bundle::(.*)/) { + $bundle = $1; + } + + if ($bundle) { + $id = $CPAN::META->instance('CPAN::Bundle',$mod); + # Let's make it a module too, because bundles have so much + # in common with modules. + + # Changed in 1.57_63: seems like memory bloat now without + # any value, so commented out + + # $CPAN::META->instance('CPAN::Module',$mod); + + } else { + + # instantiate a module object + $id = $CPAN::META->instance('CPAN::Module',$mod); + + } + + # Although CPAN prohibits same name with different version the + # indexer may have changed the version for the same distro + # since the last time ("Force Reindexing" feature) + if ($id->cpan_file ne $dist + || + $id->cpan_version ne $version + ) { + $userid = $id->userid || $self->userid($dist); + $id->set( + 'CPAN_USERID' => $userid, + 'CPAN_VERSION' => $version, + 'CPAN_FILE' => $dist, + ); + } + + # instantiate a distribution object + if ($CPAN::META->exists('CPAN::Distribution',$dist)) { + # we do not need CONTAINSMODS unless we do something with + # this dist, so we better produce it on demand. + + ## my $obj = $CPAN::META->instance( + ## 'CPAN::Distribution' => $dist + ## ); + ## $obj->{CONTAINSMODS}{$mod} = undef; # experimental + } else { + $CPAN::META->instance( + 'CPAN::Distribution' => $dist + )->set( + 'CPAN_USERID' => $userid, + 'CPAN_COMMENT' => $comment, + ); + } + if ($secondtime) { + for my $name ($mod,$dist) { + # $self->debug("exists name[$name]") if $CPAN::DEBUG; + $exists{$name} = undef; + } + } + $i++; + while (($painted/76) < ($i/@lines)) { + $CPAN::Frontend->myprint("."); + $painted++; + } + return if $CPAN::Signal; + } + $CPAN::Frontend->myprint("DONE\n"); + if ($secondtime) { + for my $class (qw(CPAN::Module CPAN::Bundle CPAN::Distribution)) { + for my $o ($CPAN::META->all_objects($class)) { + next if exists $exists{$o->{ID}}; + $CPAN::META->delete($class,$o->{ID}); + # CPAN->debug("deleting ID[$o->{ID}] in class[$class]") + # if $CPAN::DEBUG; + } + } + } +} + +#-> sub CPAN::Index::rd_modlist ; +sub rd_modlist { + my($cl,$index_target) = @_; + return unless defined $index_target; + return if CPAN::_sqlite_running(); + $CPAN::Frontend->myprint("Going to read '$index_target'\n"); + my $fh = CPAN::Tarzip->TIEHANDLE($index_target); + local $_; + my $slurp = ""; + my $chunk; + while (my $bytes = $fh->READ(\$chunk,8192)) { + $slurp.=$chunk; + } + my @eval2 = split /\012/, $slurp; + + while (@eval2) { + my $shift = shift(@eval2); + if ($shift =~ /^Date:\s+(.*)/) { + if ($DATE_OF_03 eq $1) { + $CPAN::Frontend->myprint("Unchanged.\n"); + return; + } + ($DATE_OF_03) = $1; + } + last if $shift =~ /^\s*$/; + } + push @eval2, q{CPAN::Modulelist->data;}; + local($^W) = 0; + my($compmt) = Safe->new("CPAN::Safe1"); + my($eval2) = join("\n", @eval2); + CPAN->debug(sprintf "length of eval2[%d]", length $eval2) if $CPAN::DEBUG; + my $ret = $compmt->reval($eval2); + Carp::confess($@) if $@; + return if $CPAN::Signal; + my $i = 0; + my $until = keys(%$ret); + my $painted = 0; + CPAN->debug(sprintf "until[%d]", $until) if $CPAN::DEBUG; + for (keys %$ret) { + my $obj = $CPAN::META->instance("CPAN::Module",$_); + delete $ret->{$_}{modid}; # not needed here, maybe elsewhere + $obj->set(%{$ret->{$_}}); + $i++; + while (($painted/76) < ($i/$until)) { + $CPAN::Frontend->myprint("."); + $painted++; + } + return if $CPAN::Signal; + } + $CPAN::Frontend->myprint("DONE\n"); +} + +#-> sub CPAN::Index::write_metadata_cache ; +sub write_metadata_cache { + my($self) = @_; + return unless $CPAN::Config->{'cache_metadata'}; + return if CPAN::_sqlite_running(); + return unless $CPAN::META->has_usable("Storable"); + my $cache; + foreach my $k (qw(CPAN::Bundle CPAN::Author CPAN::Module + CPAN::Distribution)) { + $cache->{$k} = $CPAN::META->{readonly}{$k}; # unsafe meta access, ok + } + my $metadata_file = File::Spec->catfile($CPAN::Config->{cpan_home},"Metadata"); + $cache->{last_time} = $LAST_TIME; + $cache->{DATE_OF_02} = $DATE_OF_02; + $cache->{PROTOCOL} = PROTOCOL; + $CPAN::Frontend->myprint("Going to write $metadata_file\n"); + eval { Storable::nstore($cache, $metadata_file) }; + $CPAN::Frontend->mywarn($@) if $@; # ?? missing "\n" after $@ in mywarn ?? +} + +#-> sub CPAN::Index::read_metadata_cache ; +sub read_metadata_cache { + my($self) = @_; + return unless $CPAN::Config->{'cache_metadata'}; + return if CPAN::_sqlite_running(); + return unless $CPAN::META->has_usable("Storable"); + my $metadata_file = File::Spec->catfile($CPAN::Config->{cpan_home},"Metadata"); + return unless -r $metadata_file and -f $metadata_file; + $CPAN::Frontend->myprint("Going to read '$metadata_file'\n"); + my $cache; + eval { $cache = Storable::retrieve($metadata_file) }; + $CPAN::Frontend->mywarn($@) if $@; # ?? missing "\n" after $@ in mywarn ?? + if (!$cache || !UNIVERSAL::isa($cache, 'HASH')) { + $LAST_TIME = 0; + return; + } + if (exists $cache->{PROTOCOL}) { + if (PROTOCOL > $cache->{PROTOCOL}) { + $CPAN::Frontend->mywarn(sprintf("Ignoring Metadata cache written ". + "with protocol v%s, requiring v%s\n", + $cache->{PROTOCOL}, + PROTOCOL) + ); + return; + } + } else { + $CPAN::Frontend->mywarn("Ignoring Metadata cache written ". + "with protocol v1.0\n"); + return; + } + my $clcnt = 0; + my $idcnt = 0; + while(my($class,$v) = each %$cache) { + next unless $class =~ /^CPAN::/; + $CPAN::META->{readonly}{$class} = $v; # unsafe meta access, ok + while (my($id,$ro) = each %$v) { + $CPAN::META->{readwrite}{$class}{$id} ||= + $class->new(ID=>$id, RO=>$ro); + $idcnt++; + } + $clcnt++; + } + unless ($clcnt) { # sanity check + $CPAN::Frontend->myprint("Warning: Found no data in $metadata_file\n"); + return; + } + if ($idcnt < 1000) { + $CPAN::Frontend->myprint("Warning: Found only $idcnt objects ". + "in $metadata_file\n"); + return; + } + $CPAN::META->{PROTOCOL} ||= + $cache->{PROTOCOL}; # reading does not up or downgrade, but it + # does initialize to some protocol + $LAST_TIME = $cache->{last_time}; + $DATE_OF_02 = $cache->{DATE_OF_02}; + $CPAN::Frontend->myprint(" Database was generated on $DATE_OF_02\n") + if defined $DATE_OF_02; # An old cache may not contain DATE_OF_02 + return; +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/InfoObj.pm b/Master/tlpkg/tlperl/lib/CPAN/InfoObj.pm new file mode 100644 index 00000000000..9198316c69f --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/InfoObj.pm @@ -0,0 +1,224 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +# vim: ts=4 sts=4 sw=4: +package CPAN::InfoObj; +use strict; + +use CPAN::Debug; +@CPAN::InfoObj::ISA = qw(CPAN::Debug); + +use Cwd qw(chdir); + +use vars qw( + $VERSION +); +$VERSION = "5.5"; + +sub ro { + my $self = shift; + exists $self->{RO} and return $self->{RO}; +} + +#-> sub CPAN::InfoObj::cpan_userid +sub cpan_userid { + my $self = shift; + my $ro = $self->ro; + if ($ro) { + return $ro->{CPAN_USERID} || "N/A"; + } else { + $self->debug("ID[$self->{ID}]"); + # N/A for bundles found locally + return "N/A"; + } +} + +sub id { shift->{ID}; } + +#-> sub CPAN::InfoObj::new ; +sub new { + my $this = bless {}, shift; + %$this = @_; + $this +} + +# The set method may only be used by code that reads index data or +# otherwise "objective" data from the outside world. All session +# related material may do anything else with instance variables but +# must not touch the hash under the RO attribute. The reason is that +# the RO hash gets written to Metadata file and is thus persistent. + +#-> sub CPAN::InfoObj::safe_chdir ; +sub safe_chdir { + my($self,$todir) = @_; + # we die if we cannot chdir and we are debuggable + Carp::confess("safe_chdir called without todir argument") + unless defined $todir and length $todir; + if (chdir $todir) { + $self->debug(sprintf "changed directory to %s", CPAN::anycwd()) + if $CPAN::DEBUG; + } else { + if (-e $todir) { + unless (-x $todir) { + unless (chmod 0755, $todir) { + my $cwd = CPAN::anycwd(); + $CPAN::Frontend->mywarn("I have neither the -x permission nor the ". + "permission to change the permission; cannot ". + "chdir to '$todir'\n"); + $CPAN::Frontend->mysleep(5); + $CPAN::Frontend->mydie(qq{Could not chdir from cwd[$cwd] }. + qq{to todir[$todir]: $!}); + } + } + } else { + $CPAN::Frontend->mydie("Directory '$todir' has gone. Cannot continue.\n"); + } + if (chdir $todir) { + $self->debug(sprintf "changed directory to %s", CPAN::anycwd()) + if $CPAN::DEBUG; + } else { + my $cwd = CPAN::anycwd(); + $CPAN::Frontend->mydie(qq{Could not chdir from cwd[$cwd] }. + qq{to todir[$todir] (a chmod has been issued): $!}); + } + } +} + +#-> sub CPAN::InfoObj::set ; +sub set { + my($self,%att) = @_; + my $class = ref $self; + + # This must be ||=, not ||, because only if we write an empty + # reference, only then the set method will write into the readonly + # area. But for Distributions that spring into existence, maybe + # because of a typo, we do not like it that they are written into + # the readonly area and made permanent (at least for a while) and + # that is why we do not "allow" other places to call ->set. + unless ($self->id) { + CPAN->debug("Bug? Empty ID, rejecting"); + return; + } + my $ro = $self->{RO} = + $CPAN::META->{readonly}{$class}{$self->id} ||= {}; + + while (my($k,$v) = each %att) { + $ro->{$k} = $v; + } +} + +#-> sub CPAN::InfoObj::as_glimpse ; +sub as_glimpse { + my($self) = @_; + my(@m); + my $class = ref($self); + $class =~ s/^CPAN:://; + my $id = $self->can("pretty_id") ? $self->pretty_id : $self->{ID}; + push @m, sprintf "%-15s %s\n", $class, $id; + join "", @m; +} + +#-> sub CPAN::InfoObj::as_string ; +sub as_string { + my($self) = @_; + my(@m); + my $class = ref($self); + $class =~ s/^CPAN:://; + push @m, $class, " id = $self->{ID}\n"; + my $ro; + unless ($ro = $self->ro) { + if (substr($self->{ID},-1,1) eq ".") { # directory + $ro = +{}; + } else { + $CPAN::Frontend->mywarn("Unknown object $self->{ID}\n"); + $CPAN::Frontend->mysleep(5); + return; + } + } + for (sort keys %$ro) { + # next if m/^(ID|RO)$/; + my $extra = ""; + if ($_ eq "CPAN_USERID") { + $extra .= " ("; + $extra .= $self->fullname; + my $email; # old perls! + if ($email = $CPAN::META->instance("CPAN::Author", + $self->cpan_userid + )->email) { + $extra .= " <$email>"; + } else { + $extra .= " <no email>"; + } + $extra .= ")"; + } elsif ($_ eq "FULLNAME") { # potential UTF-8 conversion + push @m, sprintf " %-12s %s\n", $_, $self->fullname; + next; + } + next unless defined $ro->{$_}; + push @m, sprintf " %-12s %s%s\n", $_, $ro->{$_}, $extra; + } + KEY: for (sort keys %$self) { + next if m/^(ID|RO)$/; + unless (defined $self->{$_}) { + delete $self->{$_}; + next KEY; + } + if (ref($self->{$_}) eq "ARRAY") { + push @m, sprintf " %-12s %s\n", $_, "@{$self->{$_}}"; + } elsif (ref($self->{$_}) eq "HASH") { + my $value; + if (/^CONTAINSMODS$/) { + $value = join(" ",sort keys %{$self->{$_}}); + } elsif (/^prereq_pm$/) { + my @value; + my $v = $self->{$_}; + for my $x (sort keys %$v) { + my @svalue; + for my $y (sort keys %{$v->{$x}}) { + push @svalue, "$y=>$v->{$x}{$y}"; + } + push @value, "$x\:" . join ",", @svalue if @svalue; + } + $value = join ";", @value; + } else { + $value = $self->{$_}; + } + push @m, sprintf( + " %-12s %s\n", + $_, + $value, + ); + } else { + push @m, sprintf " %-12s %s\n", $_, $self->{$_}; + } + } + join "", @m, "\n"; +} + +#-> sub CPAN::InfoObj::fullname ; +sub fullname { + my($self) = @_; + $CPAN::META->instance("CPAN::Author",$self->cpan_userid)->fullname; +} + +#-> sub CPAN::InfoObj::dump ; +sub dump { + my($self, $what) = @_; + unless ($CPAN::META->has_inst("Data::Dumper")) { + $CPAN::Frontend->mydie("dump command requires Data::Dumper installed"); + } + local $Data::Dumper::Sortkeys; + $Data::Dumper::Sortkeys = 1; + my $out = Data::Dumper::Dumper($what ? eval $what : $self); + if (length $out > 100000) { + my $fh_pager = FileHandle->new; + local($SIG{PIPE}) = "IGNORE"; + my $pager = $CPAN::Config->{'pager'} || "cat"; + $fh_pager->open("|$pager") + or die "Could not open pager $pager\: $!"; + $fh_pager->print($out); + close $fh_pager; + } else { + $CPAN::Frontend->myprint($out); + } +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/Kwalify.pm b/Master/tlpkg/tlperl/lib/CPAN/Kwalify.pm new file mode 100644 index 00000000000..3cade90b91a --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Kwalify.pm @@ -0,0 +1,136 @@ +=head1 NAME + +CPAN::Kwalify - Interface between CPAN.pm and Kwalify.pm + +=head1 SYNOPSIS + + use CPAN::Kwalify; + validate($schema_name, $data, $file, $doc); + +=head1 DESCRIPTION + +=over + +=item _validate($schema_name, $data, $file, $doc) + +$schema_name is the name of a supported schema. Currently only +C<distroprefs> is supported. $data is the data to be validated. $file +is the absolute path to the file the data are coming from. $doc is the +index of the document within $doc that is to be validated. The last +two arguments are only there for better error reporting. + +Relies on being called from within CPAN.pm. + +Dies if something fails. Does not return anything useful. + +=item yaml($schema_name) + +Returns the YAML text of that schema. Dies if something fails. + +=back + +=head1 AUTHOR + +Andreas Koenig C<< <andk@cpan.org> >> + +=head1 LICENSE + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +See L<http://www.perl.com/perl/misc/Artistic.html> + + + +=cut + + +use strict; + +package CPAN::Kwalify; +use vars qw($VERSION $VAR1); +$VERSION = "5.50"; + +use File::Spec (); + +my %vcache = (); + +my $schema_loaded = {}; + +sub _validate { + my($schema_name,$data,$abs,$y) = @_; + my $yaml_module = CPAN->_yaml_module; + if ( + $CPAN::META->has_inst($yaml_module) + && + $CPAN::META->has_inst("Kwalify") + ) { + my $load = UNIVERSAL::can($yaml_module,"Load"); + unless ($schema_loaded->{$schema_name}) { + eval { + my $schema_yaml = yaml($schema_name); + $schema_loaded->{$schema_name} = $load->($schema_yaml); + }; + if ($@) { + # we know that YAML.pm 0.62 cannot parse the schema, + # so we try a fallback + my $content = do { + my $path = __FILE__; + $path =~ s/\.pm$//; + $path = File::Spec->catfile($path, "$schema_name.dd"); + local *FH; + open FH, $path or die "Could not open '$path': $!"; + local $/; + <FH>; + }; + $VAR1 = undef; + eval $content; + if (my $err = $@) { + die "parsing of '$schema_name.dd' failed: $err"; + } + $schema_loaded->{$schema_name} = $VAR1; + } + } + } + if (my $schema = $schema_loaded->{$schema_name}) { + my $mtime = (stat $abs)[9]; + for my $k (keys %{$vcache{$abs}}) { + delete $vcache{$abs}{$k} unless $k eq $mtime; + } + return if $vcache{$abs}{$mtime}{$y}++; + eval { Kwalify::validate($schema, $data) }; + if (my $err = $@) { + my $info = {}; yaml($schema_name, info => $info); + die "validation of distropref '$abs'[$y] against schema '$info->{path}' failed: $err"; + } + } +} + +sub _clear_cache { + %vcache = (); +} + +sub yaml { + my($schema_name, %opt) = @_; + my $content = do { + my $path = __FILE__; + $path =~ s/\.pm$//; + $path = File::Spec->catfile($path, "$schema_name.yml"); + if ($opt{info}) { + $opt{info}{path} = $path; + } + local *FH; + open FH, $path or die "Could not open '$path': $!"; + local $/; + <FH>; + }; + return $content; +} + +1; + +# Local Variables: +# mode: cperl +# cperl-indent-level: 4 +# End: + diff --git a/Master/tlpkg/tlperl/lib/CPAN/Kwalify/distroprefs.dd b/Master/tlpkg/tlperl/lib/CPAN/Kwalify/distroprefs.dd new file mode 100644 index 00000000000..fd046271b87 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Kwalify/distroprefs.dd @@ -0,0 +1,150 @@ +$VAR1 = { + "mapping" => { + "comment" => { + "type" => "text" + }, + "cpanconfig" => { + "mapping" => { + "=" => { + "type" => "text" + } + }, + "type" => "map" + }, + "depends" => { + "mapping" => { + "build_requires" => { + "mapping" => { + "=" => { + "type" => "text" + } + }, + "type" => "map" + }, + "configure_requires" => {}, + "requires" => {} + }, + "type" => "map" + }, + "disabled" => { + "enum" => [ + 0, + 1 + ], + "type" => "int" + }, + "features" => { + "sequence" => [ + { + "type" => "text" + } + ], + "type" => "seq" + }, + "goto" => { + "type" => "text" + }, + "install" => { + "mapping" => { + "args" => { + "sequence" => [ + { + "type" => "text" + } + ], + "type" => "seq" + }, + "commandline" => { + "type" => "text" + }, + "eexpect" => { + "mapping" => { + "mode" => { + "enum" => [ + "deterministic", + "anyorder" + ], + "type" => "text" + }, + "reuse" => { + "type" => "int" + }, + "talk" => { + "sequence" => [ + { + "type" => "text" + } + ], + "type" => "seq" + }, + "timeout" => { + "type" => "number" + } + }, + "type" => "map" + }, + "env" => { + "mapping" => { + "=" => { + "type" => "text" + } + }, + "type" => "map" + }, + "expect" => { + "sequence" => [ + { + "type" => "text" + } + ], + "type" => "seq" + } + }, + "type" => "map" + }, + "make" => {}, + "match" => { + "mapping" => { + "distribution" => { + "type" => "text" + }, + "env" => { + "mapping" => { + "=" => { + "type" => "text" + } + }, + "type" => "map" + }, + "module" => { + "type" => "text" + }, + "perl" => { + "type" => "text" + }, + "perlconfig" => {} + }, + "type" => "map" + }, + "patches" => { + "sequence" => [ + { + "type" => "text" + } + ], + "type" => "seq" + }, + "pl" => {}, + "reminder" => { + "type" => "text" + }, + "test" => {} + }, + "type" => "map" +}; +$VAR1->{"mapping"}{"depends"}{"mapping"}{"configure_requires"} = $VAR1->{"mapping"}{"depends"}{"mapping"}{"build_requires"}; +$VAR1->{"mapping"}{"depends"}{"mapping"}{"requires"} = $VAR1->{"mapping"}{"depends"}{"mapping"}{"build_requires"}; +$VAR1->{"mapping"}{"make"} = $VAR1->{"mapping"}{"install"}; +$VAR1->{"mapping"}{"match"}{"mapping"}{"perlconfig"} = $VAR1->{"mapping"}{"match"}{"mapping"}{"env"}; +$VAR1->{"mapping"}{"pl"} = $VAR1->{"mapping"}{"install"}; +$VAR1->{"mapping"}{"test"} = $VAR1->{"mapping"}{"install"}; diff --git a/Master/tlpkg/tlperl/lib/CPAN/Kwalify/distroprefs.yml b/Master/tlpkg/tlperl/lib/CPAN/Kwalify/distroprefs.yml new file mode 100644 index 00000000000..431f1742767 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Kwalify/distroprefs.yml @@ -0,0 +1,92 @@ +--- +type: map +mapping: + comment: + type: text + depends: + type: map + mapping: + configure_requires: + &requires_common + type: map + mapping: + =: + type: text + build_requires: *requires_common + requires: *requires_common + match: + type: map + mapping: + distribution: + type: text + module: + type: text + perl: + type: text + perlconfig: + &matchhash_common + type: map + mapping: + =: + type: text + env: *matchhash_common + install: + &args_env_expect + type: map + mapping: + args: + type: seq + sequence: + - type: text + commandline: + type: text + env: + type: map + mapping: + =: + type: text + expect: + type: seq + sequence: + - type: text + eexpect: + type: map + mapping: + mode: + type: text + enum: + - deterministic + - anyorder + timeout: + type: number + reuse: + type: int + talk: + type: seq + sequence: + - type: text + make: *args_env_expect + pl: *args_env_expect + test: *args_env_expect + patches: + type: seq + sequence: + - type: text + disabled: + type: int + enum: + - 0 + - 1 + goto: + type: text + cpanconfig: + type: map + mapping: + =: + type: text + features: + type: seq + sequence: + - type: text + reminder: + type: text diff --git a/Master/tlpkg/tlperl/lib/CPAN/LWP/UserAgent.pm b/Master/tlpkg/tlperl/lib/CPAN/LWP/UserAgent.pm new file mode 100644 index 00000000000..7bb86f9a15d --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/LWP/UserAgent.pm @@ -0,0 +1,135 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +# vim: ts=4 sts=4 sw=4: +package CPAN::LWP::UserAgent; +use strict; +use vars qw(@ISA $USER $PASSWD $SETUPDONE); +# we delay requiring LWP::UserAgent and setting up inheritance until we need it + +$CPAN::LWP::UserAgent::VERSION = $CPAN::LWP::UserAgent::VERSION = "1.94"; + +sub config { + return if $SETUPDONE; + if ($CPAN::META->has_usable('LWP::UserAgent')) { + require LWP::UserAgent; + @ISA = qw(Exporter LWP::UserAgent); ## no critic + $SETUPDONE++; + } else { + $CPAN::Frontend->mywarn(" LWP::UserAgent not available\n"); + } +} + +sub get_basic_credentials { + my($self, $realm, $uri, $proxy) = @_; + if ($USER && $PASSWD) { + return ($USER, $PASSWD); + } + if ( $proxy ) { + ($USER,$PASSWD) = $self->get_proxy_credentials(); + } else { + ($USER,$PASSWD) = $self->get_non_proxy_credentials(); + } + return($USER,$PASSWD); +} + +sub get_proxy_credentials { + my $self = shift; + my ($user, $password); + if ( defined $CPAN::Config->{proxy_user} ) { + $user = $CPAN::Config->{proxy_user}; + $password = $CPAN::Config->{proxy_pass} || ""; + return ($user, $password); + } + my $username_prompt = "\nProxy authentication needed! + (Note: to permanently configure username and password run + o conf proxy_user your_username + o conf proxy_pass your_password + )\nUsername:"; + ($user, $password) = + _get_username_and_password_from_user($username_prompt); + return ($user,$password); +} + +sub get_non_proxy_credentials { + my $self = shift; + my ($user,$password); + if ( defined $CPAN::Config->{username} ) { + $user = $CPAN::Config->{username}; + $password = $CPAN::Config->{password} || ""; + return ($user, $password); + } + my $username_prompt = "\nAuthentication needed! + (Note: to permanently configure username and password run + o conf username your_username + o conf password your_password + )\nUsername:"; + + ($user, $password) = + _get_username_and_password_from_user($username_prompt); + return ($user,$password); +} + +sub _get_username_and_password_from_user { + my $username_message = shift; + my ($username,$password); + + ExtUtils::MakeMaker->import(qw(prompt)); + $username = prompt($username_message); + if ($CPAN::META->has_inst("Term::ReadKey")) { + Term::ReadKey::ReadMode("noecho"); + } + else { + $CPAN::Frontend->mywarn( + "Warning: Term::ReadKey seems not to be available, your password will be echoed to the terminal!\n" + ); + } + $password = prompt("Password:"); + + if ($CPAN::META->has_inst("Term::ReadKey")) { + Term::ReadKey::ReadMode("restore"); + } + $CPAN::Frontend->myprint("\n\n"); + return ($username,$password); +} + +# mirror(): Its purpose is to deal with proxy authentication. When we +# call SUPER::mirror, we relly call the mirror method in +# LWP::UserAgent. LWP::UserAgent will then call +# $self->get_basic_credentials or some equivalent and this will be +# $self->dispatched to our own get_basic_credentials method. + +# Our own get_basic_credentials sets $USER and $PASSWD, two globals. + +# 407 stands for HTTP_PROXY_AUTHENTICATION_REQUIRED. Which means +# although we have gone through our get_basic_credentials, the proxy +# server refuses to connect. This could be a case where the username or +# password has changed in the meantime, so I'm trying once again without +# $USER and $PASSWD to give the get_basic_credentials routine another +# chance to set $USER and $PASSWD. + +# mirror(): Its purpose is to deal with proxy authentication. When we +# call SUPER::mirror, we relly call the mirror method in +# LWP::UserAgent. LWP::UserAgent will then call +# $self->get_basic_credentials or some equivalent and this will be +# $self->dispatched to our own get_basic_credentials method. + +# Our own get_basic_credentials sets $USER and $PASSWD, two globals. + +# 407 stands for HTTP_PROXY_AUTHENTICATION_REQUIRED. Which means +# although we have gone through our get_basic_credentials, the proxy +# server refuses to connect. This could be a case where the username or +# password has changed in the meantime, so I'm trying once again without +# $USER and $PASSWD to give the get_basic_credentials routine another +# chance to set $USER and $PASSWD. + +sub mirror { + my($self,$url,$aslocal) = @_; + my $result = $self->SUPER::mirror($url,$aslocal); + if ($result->code == 407) { + undef $USER; + undef $PASSWD; + $result = $self->SUPER::mirror($url,$aslocal); + } + $result; +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/Mirrors.pm b/Master/tlpkg/tlperl/lib/CPAN/Mirrors.pm new file mode 100644 index 00000000000..1a3402e8de5 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Mirrors.pm @@ -0,0 +1,260 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +# vim: ts=4 sts=4 sw=4: +package CPAN::Mirrors; +use strict; +use vars qw($VERSION $urllist $silent); +$VERSION = "1.77"; + +use Carp; +use FileHandle; +use Fcntl ":flock"; + +sub new { + my ($class, $file) = @_; + my $self = bless { + mirrors => [], + geography => {}, + }, $class; + + my $handle = FileHandle->new; + $handle->open($file) + or croak "Couldn't open $file: $!"; + flock $handle, LOCK_SH; + $self->_parse($file,$handle); + flock $handle, LOCK_UN; + $handle->close; + + # populate continents & countries + + return $self +} + +sub continents { + my ($self) = @_; + return keys %{$self->{geography}}; +} + +sub countries { + my ($self, @continents) = @_; + @continents = $self->continents unless @continents; + my @countries; + for my $c (@continents) { + push @countries, keys %{ $self->{geography}{$c} }; + } + return @countries; +} + +sub mirrors { + my ($self, @countries) = @_; + return @{$self->{mirrors}} unless @countries; + my %wanted = map { $_ => 1 } @countries; + my @found; + for my $m (@{$self->{mirrors}}) { + push @found, $m if exists $wanted{$m->country}; + } + return @found; +} + +sub best_mirrors { + my ($self, %args) = @_; + my $how_many = $args{how_many} || 1; + my $callback = $args{callback}; + my $verbose = $args{verbose}; + my $conts = $args{continents} || []; + $conts = [$conts] unless ref $conts; + + my $seen = {}; + + if ( ! @$conts ) { + print "Searching for the best continent ...\n" if $verbose; + my @best = $self->_find_best_continent($seen, $verbose, $callback); + + # how many continents to find enough mirrors? We should scan + # more than we need -- arbitrarily, we'll say x2 + my $count = 0; + for my $c ( @best ) { + push @$conts, $c; + $count += $self->mirrors( $self->countries($c) ); + last if $count >= 2 * $how_many; + } + } + + print "Scanning " . join(", ", @$conts) . " ...\n" if $verbose; + + my @timings; + for my $m ($self->mirrors($self->countries(@$conts))) { + next unless $m->ftp; + my $hostname = $m->hostname; + if ( $seen->{$hostname} ) { + push @timings, $seen->{$hostname} + if defined $seen->{$hostname}[1]; + } + else { + my $ping = $m->ping; + next unless defined $ping; + push @timings, [$m, $ping]; + $callback->($m,$ping) if $callback; + } + } + return unless @timings; + $how_many = @timings if $how_many > @timings; + my @best = + map { $_->[0] } + sort { $a->[1] <=> $b->[1] } @timings; + + return wantarray ? @best[0 .. $how_many-1] : $best[0]; +} + +sub _find_best_continent { + my ($self, $seen, $verbose, $callback) = @_; + + my %median; + CONT: for my $c ( $self->continents ) { + my @mirrors = $self->mirrors( $self->countries($c) ); + next CONT unless @mirrors; + my $sample = 9; + my $n = (@mirrors < $sample) ? @mirrors : $sample; + my @tests; + RANDOM: while ( @mirrors && @tests < $n ) { + my $m = splice( @mirrors, int(rand(@mirrors)), 1 ); + my $ping = $m->ping; + $callback->($m,$ping) if $callback; + # record undef so we don't try again + $seen->{$m->hostname} = [$m, $ping]; + next RANDOM unless defined $ping; + push @tests, $ping; + } + next CONT unless @tests; + @tests = sort { $a <=> $b } @tests; + if ( @tests == 1 ) { + $median{$c} = $tests[0]; + } + elsif ( @tests % 2 ) { + $median{$c} = $tests[ int(@tests / 2) ]; + } + else { + my $mid_high = int(@tests/2); + $median{$c} = ($tests[$mid_high-1] + $tests[$mid_high])/2; + } + } + + my @best_cont = sort { $median{$a} <=> $median{$b} } keys %median ; + + if ( $verbose ) { + print "Median result by continent:\n"; + for my $c ( @best_cont ) { + printf( " %d ms %s\n", int($median{$c}*1000+.5), $c ); + } + } + + return wantarray ? @best_cont : $best_cont[0]; +} + +# Adapted from Parse::CPAN::MirroredBy by Adam Kennedy +sub _parse { + my ($self, $file, $handle) = @_; + my $output = $self->{mirrors}; + my $geo = $self->{geography}; + + local $/ = "\012"; + my $line = 0; + my $mirror = undef; + while ( 1 ) { + # Next line + my $string = <$handle>; + last if ! defined $string; + $line = $line + 1; + + # Remove the useless lines + chomp( $string ); + next if $string =~ /^\s*$/; + next if $string =~ /^\s*#/; + + # Hostname or property? + if ( $string =~ /^\s/ ) { + # Property + unless ( $string =~ /^\s+(\w+)\s+=\s+\"(.*)\"$/ ) { + croak("Invalid property on line $line"); + } + my ($prop, $value) = ($1,$2); + $mirror ||= {}; + if ( $prop eq 'dst_location' ) { + my (@location,$continent,$country); + @location = (split /\s*,\s*/, $value) + and ($continent, $country) = @location[-1,-2]; + $continent =~ s/\s\(.*//; + $continent =~ s/\W+$//; # if Jarkko doesn't know latitude/longitude + $geo->{$continent}{$country} = 1 if $continent && $country; + $mirror->{continent} = $continent || "unknown"; + $mirror->{country} = $country || "unknown"; + } + elsif ( $prop eq 'dst_http' ) { + $mirror->{http} = $value; + } + elsif ( $prop eq 'dst_ftp' ) { + $mirror->{ftp} = $value; + } + elsif ( $prop eq 'dst_rsync' ) { + $mirror->{rsync} = $value; + } + else { + $prop =~ s/^dst_//; + $mirror->{$prop} = $value; + } + } else { + # Hostname + unless ( $string =~ /^([\w\.-]+)\:\s*$/ ) { + croak("Invalid host name on line $line"); + } + my $current = $mirror; + $mirror = { hostname => "$1" }; + if ( $current ) { + push @$output, CPAN::Mirrored::By->new($current); + } + } + } + if ( $mirror ) { + push @$output, CPAN::Mirrored::By->new($mirror); + } + + return; +} + +#--------------------------------------------------------------------------# + +package CPAN::Mirrored::By; +use strict; +use Net::Ping (); + +sub new { + my($self,$arg) = @_; + $arg ||= {}; + bless $arg, $self; +} +sub hostname { shift->{hostname} } +sub continent { shift->{continent} } +sub country { shift->{country} } +sub http { shift->{http} || '' } +sub ftp { shift->{ftp} || '' } +sub rsync { shift->{rsync} || '' } + +sub url { + my $self = shift; + return $self->{ftp} || $self->{http}; +} + +sub ping { + my $self = shift; + my $ping = Net::Ping->new("tcp",1); + my ($proto) = $self->url =~ m{^([^:]+)}; + my $port = $proto eq 'http' ? 80 : 21; + return unless $port; + $ping->port_number($port); + $ping->hires(1); + my ($alive,$rtt) = $ping->ping($self->hostname); + return $alive ? $rtt : undef; +} + + +1; + diff --git a/Master/tlpkg/tlperl/lib/CPAN/Module.pm b/Master/tlpkg/tlperl/lib/CPAN/Module.pm new file mode 100644 index 00000000000..43c42bf1049 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Module.pm @@ -0,0 +1,688 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +# vim: ts=4 sts=4 sw=4: +package CPAN::Module; +use strict; +@CPAN::Module::ISA = qw(CPAN::InfoObj); + +use vars qw( + $VERSION +); +$VERSION = "5.5"; + +BEGIN { + # alarm() is not implemented in perl 5.6.x and earlier under Windows + *ALARM_IMPLEMENTED = sub () { $] >= 5.007 || $^O !~ /MSWin/ }; +} + +# Accessors +#-> sub CPAN::Module::userid +sub userid { + my $self = shift; + my $ro = $self->ro; + return unless $ro; + return $ro->{userid} || $ro->{CPAN_USERID}; +} +#-> sub CPAN::Module::description +sub description { + my $self = shift; + my $ro = $self->ro or return ""; + $ro->{description} +} + +#-> sub CPAN::Module::distribution +sub distribution { + my($self) = @_; + CPAN::Shell->expand("Distribution",$self->cpan_file); +} + +#-> sub CPAN::Module::_is_representative_module +sub _is_representative_module { + my($self) = @_; + return $self->{_is_representative_module} if defined $self->{_is_representative_module}; + my $pm = $self->cpan_file or return $self->{_is_representative_module} = 0; + $pm =~ s|.+/||; + $pm =~ s{\.(?:tar\.(bz2|gz|Z)|t(?:gz|bz)|zip)$}{}i; # see base_id + $pm =~ s|-\d+\.\d+.+$||; + $pm =~ s|-[\d\.]+$||; + $pm =~ s/-/::/g; + $self->{_is_representative_module} = $pm eq $self->{ID} ? 1 : 0; + # warn "DEBUG: $pm eq $self->{ID} => $self->{_is_representative_module}"; + $self->{_is_representative_module}; +} + +#-> sub CPAN::Module::undelay +sub undelay { + my $self = shift; + delete $self->{later}; + if ( my $dist = CPAN::Shell->expand("Distribution", $self->cpan_file) ) { + $dist->undelay; + } +} + +# mark as dirty/clean +#-> sub CPAN::Module::color_cmd_tmps ; +sub color_cmd_tmps { + my($self) = shift; + my($depth) = shift || 0; + my($color) = shift || 0; + my($ancestors) = shift || []; + # a module needs to recurse to its cpan_file + + return if exists $self->{incommandcolor} + && $color==1 + && $self->{incommandcolor}==$color; + return if $color==0 && !$self->{incommandcolor}; + if ($color>=1) { + if ( $self->uptodate ) { + $self->{incommandcolor} = $color; + return; + } elsif (my $have_version = $self->available_version) { + # maybe what we have is good enough + if (@$ancestors) { + my $who_asked_for_me = $ancestors->[-1]; + my $obj = CPAN::Shell->expandany($who_asked_for_me); + if (0) { + } elsif ($obj->isa("CPAN::Bundle")) { + # bundles cannot specify a minimum version + return; + } elsif ($obj->isa("CPAN::Distribution")) { + if (my $prereq_pm = $obj->prereq_pm) { + for my $k (keys %$prereq_pm) { + if (my $want_version = $prereq_pm->{$k}{$self->id}) { + if (CPAN::Version->vcmp($have_version,$want_version) >= 0) { + $self->{incommandcolor} = $color; + return; + } + } + } + } + } + } + } + } else { + $self->{incommandcolor} = $color; # set me before recursion, + # so we can break it + } + if ($depth>=$CPAN::MAX_RECURSION) { + die(CPAN::Exception::RecursiveDependency->new($ancestors)); + } + # warn "color_cmd_tmps $depth $color " . $self->id; # sleep 1; + + if ( my $dist = CPAN::Shell->expand("Distribution", $self->cpan_file) ) { + $dist->color_cmd_tmps($depth+1,$color,[@$ancestors, $self->id]); + } + # unreached code? + # if ($color==0) { + # delete $self->{badtestcnt}; + # } + $self->{incommandcolor} = $color; +} + +#-> sub CPAN::Module::as_glimpse ; +sub as_glimpse { + my($self) = @_; + my(@m); + my $class = ref($self); + $class =~ s/^CPAN:://; + my $color_on = ""; + my $color_off = ""; + if ( + $CPAN::Shell::COLOR_REGISTERED + && + $CPAN::META->has_inst("Term::ANSIColor") + && + $self->description + ) { + $color_on = Term::ANSIColor::color("green"); + $color_off = Term::ANSIColor::color("reset"); + } + my $uptodateness = " "; + unless ($class eq "Bundle") { + my $u = $self->uptodate; + $uptodateness = $u ? "=" : "<" if defined $u; + }; + my $id = do { + my $d = $self->distribution; + $d ? $d -> pretty_id : $self->cpan_userid; + }; + push @m, sprintf("%-7s %1s %s%-22s%s (%s)\n", + $class, + $uptodateness, + $color_on, + $self->id, + $color_off, + $id, + ); + join "", @m; +} + +#-> sub CPAN::Module::dslip_status +sub dslip_status { + my($self) = @_; + my($stat); + # development status + @{$stat->{D}}{qw,i c a b R M S,} = qw,idea + pre-alpha alpha beta released + mature standard,; + # support level + @{$stat->{S}}{qw,m d u n a,} = qw,mailing-list + developer comp.lang.perl.* + none abandoned,; + # language + @{$stat->{L}}{qw,p c + o h,} = qw,perl C C++ other hybrid,; + # interface + @{$stat->{I}}{qw,f r O p h n,} = qw,functions + references+ties + object-oriented pragma + hybrid none,; + # public licence + @{$stat->{P}}{qw,p g l b a 2 o d r n,} = qw,Standard-Perl + GPL LGPL + BSD Artistic Artistic_2 + open-source + distribution_allowed + restricted_distribution + no_licence,; + for my $x (qw(d s l i p)) { + $stat->{$x}{' '} = 'unknown'; + $stat->{$x}{'?'} = 'unknown'; + } + my $ro = $self->ro; + return +{} unless $ro && $ro->{statd}; + return { + D => $ro->{statd}, + S => $ro->{stats}, + L => $ro->{statl}, + I => $ro->{stati}, + P => $ro->{statp}, + DV => $stat->{D}{$ro->{statd}}, + SV => $stat->{S}{$ro->{stats}}, + LV => $stat->{L}{$ro->{statl}}, + IV => $stat->{I}{$ro->{stati}}, + PV => $stat->{P}{$ro->{statp}}, + }; +} + +#-> sub CPAN::Module::as_string ; +sub as_string { + my($self) = @_; + my(@m); + CPAN->debug("$self entering as_string") if $CPAN::DEBUG; + my $class = ref($self); + $class =~ s/^CPAN:://; + local($^W) = 0; + push @m, $class, " id = $self->{ID}\n"; + my $sprintf = " %-12s %s\n"; + push @m, sprintf($sprintf, 'DESCRIPTION', $self->description) + if $self->description; + my $sprintf2 = " %-12s %s (%s)\n"; + my($userid); + $userid = $self->userid; + if ( $userid ) { + my $author; + if ($author = CPAN::Shell->expand('Author',$userid)) { + my $email = ""; + my $m; # old perls + if ($m = $author->email) { + $email = " <$m>"; + } + push @m, sprintf( + $sprintf2, + 'CPAN_USERID', + $userid, + $author->fullname . $email + ); + } + } + push @m, sprintf($sprintf, 'CPAN_VERSION', $self->cpan_version) + if $self->cpan_version; + if (my $cpan_file = $self->cpan_file) { + push @m, sprintf($sprintf, 'CPAN_FILE', $cpan_file); + if (my $dist = CPAN::Shell->expand("Distribution",$cpan_file)) { + my $upload_date = $dist->upload_date; + if ($upload_date) { + push @m, sprintf($sprintf, 'UPLOAD_DATE', $upload_date); + } + } + } + my $sprintf3 = " %-12s %1s%1s%1s%1s%1s (%s,%s,%s,%s,%s)\n"; + my $dslip = $self->dslip_status; + push @m, sprintf( + $sprintf3, + 'DSLIP_STATUS', + @{$dslip}{qw(D S L I P DV SV LV IV PV)}, + ) if $dslip->{D}; + my $local_file = $self->inst_file; + unless ($self->{MANPAGE}) { + my $manpage; + if ($local_file) { + $manpage = $self->manpage_headline($local_file); + } else { + # If we have already untarred it, we should look there + my $dist = $CPAN::META->instance('CPAN::Distribution', + $self->cpan_file); + # warn "dist[$dist]"; + # mff=manifest file; mfh=manifest handle + my($mff,$mfh); + if ( + $dist->{build_dir} + and + (-f ($mff = File::Spec->catfile($dist->{build_dir}, "MANIFEST"))) + and + $mfh = FileHandle->new($mff) + ) { + CPAN->debug("mff[$mff]") if $CPAN::DEBUG; + my $lfre = $self->id; # local file RE + $lfre =~ s/::/./g; + $lfre .= "\\.pm\$"; + my($lfl); # local file file + local $/ = "\n"; + my(@mflines) = <$mfh>; + for (@mflines) { + s/^\s+//; + s/\s.*//s; + } + while (length($lfre)>5 and !$lfl) { + ($lfl) = grep /$lfre/, @mflines; + CPAN->debug("lfl[$lfl]lfre[$lfre]") if $CPAN::DEBUG; + $lfre =~ s/.+?\.//; + } + $lfl =~ s/\s.*//; # remove comments + $lfl =~ s/\s+//g; # chomp would maybe be too system-specific + my $lfl_abs = File::Spec->catfile($dist->{build_dir},$lfl); + # warn "lfl_abs[$lfl_abs]"; + if (-f $lfl_abs) { + $manpage = $self->manpage_headline($lfl_abs); + } + } + } + $self->{MANPAGE} = $manpage if $manpage; + } + my($item); + for $item (qw/MANPAGE/) { + push @m, sprintf($sprintf, $item, $self->{$item}) + if exists $self->{$item}; + } + for $item (qw/CONTAINS/) { + push @m, sprintf($sprintf, $item, join(" ",@{$self->{$item}})) + if exists $self->{$item} && @{$self->{$item}}; + } + push @m, sprintf($sprintf, 'INST_FILE', + $local_file || "(not installed)"); + push @m, sprintf($sprintf, 'INST_VERSION', + $self->inst_version) if $local_file; + if (%{$CPAN::META->{is_tested}||{}}) { # XXX needs to be methodified somehow + my $available_file = $self->available_file; + if ($available_file && $available_file ne $local_file) { + push @m, sprintf($sprintf, 'AVAILABLE_FILE', $available_file); + push @m, sprintf($sprintf, 'AVAILABLE_VERSION', $self->available_version); + } + } + join "", @m, "\n"; +} + +#-> sub CPAN::Module::manpage_headline +sub manpage_headline { + my($self,$local_file) = @_; + my(@local_file) = $local_file; + $local_file =~ s/\.pm(?!\n)\Z/.pod/; + push @local_file, $local_file; + my(@result,$locf); + for $locf (@local_file) { + next unless -f $locf; + my $fh = FileHandle->new($locf) + or $Carp::Frontend->mydie("Couldn't open $locf: $!"); + my $inpod = 0; + local $/ = "\n"; + while (<$fh>) { + $inpod = m/^=(?!head1\s+NAME\s*$)/ ? 0 : + m/^=head1\s+NAME\s*$/ ? 1 : $inpod; + next unless $inpod; + next if /^=/; + next if /^\s+$/; + chomp; + push @result, $_; + } + close $fh; + last if @result; + } + for (@result) { + s/^\s+//; + s/\s+$//; + } + join " ", @result; +} + +#-> sub CPAN::Module::cpan_file ; +# Note: also inherited by CPAN::Bundle +sub cpan_file { + my $self = shift; + # CPAN->debug(sprintf "id[%s]", $self->id) if $CPAN::DEBUG; + unless ($self->ro) { + CPAN::Index->reload; + } + my $ro = $self->ro; + if ($ro && defined $ro->{CPAN_FILE}) { + return $ro->{CPAN_FILE}; + } else { + my $userid = $self->userid; + if ( $userid ) { + if ($CPAN::META->exists("CPAN::Author",$userid)) { + my $author = $CPAN::META->instance("CPAN::Author", + $userid); + my $fullname = $author->fullname; + my $email = $author->email; + unless (defined $fullname && defined $email) { + return sprintf("Contact Author %s", + $userid, + ); + } + return "Contact Author $fullname <$email>"; + } else { + return "Contact Author $userid (Email address not available)"; + } + } else { + return "N/A"; + } + } +} + +#-> sub CPAN::Module::cpan_version ; +sub cpan_version { + my $self = shift; + + my $ro = $self->ro; + unless ($ro) { + # Can happen with modules that are not on CPAN + $ro = {}; + } + $ro->{CPAN_VERSION} = 'undef' + unless defined $ro->{CPAN_VERSION}; + $ro->{CPAN_VERSION}; +} + +#-> sub CPAN::Module::force ; +sub force { + my($self) = @_; + $self->{force_update} = 1; +} + +#-> sub CPAN::Module::fforce ; +sub fforce { + my($self) = @_; + $self->{force_update} = 2; +} + +#-> sub CPAN::Module::notest ; +sub notest { + my($self) = @_; + # $CPAN::Frontend->mywarn("XDEBUG: set notest for Module"); + $self->{notest}++; +} + +#-> sub CPAN::Module::rematein ; +sub rematein { + my($self,$meth) = @_; + $CPAN::Frontend->myprint(sprintf("Running %s for module '%s'\n", + $meth, + $self->id)); + my $cpan_file = $self->cpan_file; + if ($cpan_file eq "N/A" || $cpan_file =~ /^Contact Author/) { + $CPAN::Frontend->mywarn(sprintf qq{ + The module %s isn\'t available on CPAN. + + Either the module has not yet been uploaded to CPAN, or it is + temporary unavailable. Please contact the author to find out + more about the status. Try 'i %s'. +}, + $self->id, + $self->id, + ); + return; + } + my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file); + $pack->called_for($self->id); + if (exists $self->{force_update}) { + if ($self->{force_update} == 2) { + $pack->fforce($meth); + } else { + $pack->force($meth); + } + } + $pack->notest($meth) if exists $self->{notest} && $self->{notest}; + + $pack->{reqtype} ||= ""; + CPAN->debug("dist-reqtype[$pack->{reqtype}]". + "self-reqtype[$self->{reqtype}]") if $CPAN::DEBUG; + if ($pack->{reqtype}) { + if ($pack->{reqtype} eq "b" && $self->{reqtype} =~ /^[rc]$/) { + $pack->{reqtype} = $self->{reqtype}; + if ( + exists $pack->{install} + && + ( + UNIVERSAL::can($pack->{install},"failed") ? + $pack->{install}->failed : + $pack->{install} =~ /^NO/ + ) + ) { + delete $pack->{install}; + $CPAN::Frontend->mywarn + ("Promoting $pack->{ID} from 'build_requires' to 'requires'"); + } + } + } else { + $pack->{reqtype} = $self->{reqtype}; + } + + my $success = eval { + $pack->$meth(); + }; + my $err = $@; + $pack->unforce if $pack->can("unforce") && exists $self->{force_update}; + $pack->unnotest if $pack->can("unnotest") && exists $self->{notest}; + delete $self->{force_update}; + delete $self->{notest}; + if ($err) { + die $err; + } + return $success; +} + +#-> sub CPAN::Module::perldoc ; +sub perldoc { shift->rematein('perldoc') } +#-> sub CPAN::Module::readme ; +sub readme { shift->rematein('readme') } +#-> sub CPAN::Module::look ; +sub look { shift->rematein('look') } +#-> sub CPAN::Module::cvs_import ; +sub cvs_import { shift->rematein('cvs_import') } +#-> sub CPAN::Module::get ; +sub get { shift->rematein('get',@_) } +#-> sub CPAN::Module::make ; +sub make { shift->rematein('make') } +#-> sub CPAN::Module::test ; +sub test { + my $self = shift; + # $self->{badtestcnt} ||= 0; + $self->rematein('test',@_); +} + +#-> sub CPAN::Module::deprecated_in_core ; +sub deprecated_in_core { + my ($self) = @_; + return unless $CPAN::META->has_inst('Module::CoreList') && Module::CoreList->can('is_deprecated'); + return Module::CoreList::is_deprecated($self->{ID}); +} + +#-> sub CPAN::Module::inst_deprecated; +# Indicates whether the *installed* version of the module is a deprecated *and* +# installed as part of the Perl core library path +sub inst_deprecated { + my ($self) = @_; + my $inst_file = $self->inst_file or return; + return $self->deprecated_in_core && $self->_in_priv_or_arch($inst_file); +} + +#-> sub CPAN::Module::uptodate ; +sub uptodate { + my ($self) = @_; + local ($_); + my $inst = $self->inst_version or return 0; + my $cpan = $self->cpan_version; + return 0 if CPAN::Version->vgt($cpan,$inst) || $self->inst_deprecated; + CPAN->debug + (join + ("", + "returning uptodate. ", + "cpan[$cpan]inst[$inst]", + )) if $CPAN::DEBUG; + return 1; +} + +# returns true if installed in privlib or archlib +sub _in_priv_or_arch { + my($self,$inst_file) = @_; + for my $confdirname (qw(archlibexp privlibexp)) { + my $confdir = $Config::Config{$confdirname}; + if ($confdir eq substr($inst_file,0,length($confdir))) { + return 1; + } + } + return 0; +} + +#-> sub CPAN::Module::install ; +sub install { + my($self) = @_; + my($doit) = 0; + if ($self->uptodate + && + not exists $self->{force_update} + ) { + $CPAN::Frontend->myprint(sprintf("%s is up to date (%s).\n", + $self->id, + $self->inst_version, + )); + } else { + $doit = 1; + } + my $ro = $self->ro; + if ($ro && $ro->{stats} && $ro->{stats} eq "a") { + $CPAN::Frontend->mywarn(qq{ +\n\n\n ***WARNING*** + The module $self->{ID} has no active maintainer (CPAN support level flag 'abandoned').\n\n\n +}); + $CPAN::Frontend->mysleep(5); + } + return $doit ? $self->rematein('install') : 1; +} +#-> sub CPAN::Module::clean ; +sub clean { shift->rematein('clean') } + +#-> sub CPAN::Module::inst_file ; +sub inst_file { + my($self) = @_; + $self->_file_in_path([@INC]); +} + +#-> sub CPAN::Module::available_file ; +sub available_file { + my($self) = @_; + my $sep = $Config::Config{path_sep}; + my $perllib = $ENV{PERL5LIB}; + $perllib = $ENV{PERLLIB} unless defined $perllib; + my @perllib = split(/$sep/,$perllib) if defined $perllib; + my @cpan_perl5inc; + if ($CPAN::Perl5lib_tempfile) { + my $yaml = CPAN->_yaml_loadfile($CPAN::Perl5lib_tempfile); + @cpan_perl5inc = @{$yaml->[0]{inc} || []}; + } + $self->_file_in_path([@cpan_perl5inc,@perllib,@INC]); +} + +#-> sub CPAN::Module::file_in_path ; +sub _file_in_path { + my($self,$path) = @_; + my($dir,@packpath); + @packpath = split /::/, $self->{ID}; + $packpath[-1] .= ".pm"; + if (@packpath == 1 && $packpath[0] eq "readline.pm") { + unshift @packpath, "Term", "ReadLine"; # historical reasons + } + foreach $dir (@$path) { + my $pmfile = File::Spec->catfile($dir,@packpath); + if (-f $pmfile) { + return $pmfile; + } + } + return; +} + +#-> sub CPAN::Module::xs_file ; +sub xs_file { + my($self) = @_; + my($dir,@packpath); + @packpath = split /::/, $self->{ID}; + push @packpath, $packpath[-1]; + $packpath[-1] .= "." . $Config::Config{'dlext'}; + foreach $dir (@INC) { + my $xsfile = File::Spec->catfile($dir,'auto',@packpath); + if (-f $xsfile) { + return $xsfile; + } + } + return; +} + +#-> sub CPAN::Module::inst_version ; +sub inst_version { + my($self) = @_; + my $parsefile = $self->inst_file or return; + my $have = $self->parse_version($parsefile); + $have; +} + +#-> sub CPAN::Module::inst_version ; +sub available_version { + my($self) = @_; + my $parsefile = $self->available_file or return; + my $have = $self->parse_version($parsefile); + $have; +} + +#-> sub CPAN::Module::parse_version ; +sub parse_version { + my($self,$parsefile) = @_; + if (ALARM_IMPLEMENTED) { + my $timeout = (exists($CPAN::Config{'version_timeout'})) + ? $CPAN::Config{'version_timeout'} + : 15; + alarm($timeout); + } + my $have = eval { + local $SIG{ALRM} = sub { die "alarm\n" }; + MM->parse_version($parsefile); + }; + if ($@) { + $CPAN::Frontend->mywarn("Error while parsing version number in file '$parsefile'\n"); + } + alarm(0) if ALARM_IMPLEMENTED; + my $leastsanity = eval { defined $have && length $have; }; + $have = "undef" unless $leastsanity; + $have =~ s/^ //; # since the %vd hack these two lines here are needed + $have =~ s/ $//; # trailing whitespace happens all the time + + $have = CPAN::Version->readable($have); + + $have =~ s/\s*//g; # stringify to float around floating point issues + $have; # no stringify needed, \s* above matches always +} + +#-> sub CPAN::Module::reports +sub reports { + my($self) = @_; + $self->distribution->reports; +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/Nox.pm b/Master/tlpkg/tlperl/lib/CPAN/Nox.pm new file mode 100644 index 00000000000..5fe5a25ae6e --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Nox.pm @@ -0,0 +1,51 @@ +package CPAN::Nox; +use strict; +use vars qw($VERSION @EXPORT); + +BEGIN{ + $CPAN::Suppress_readline=1 unless defined $CPAN::term; +} + +use base 'Exporter'; +use CPAN; + +$VERSION = "5.50"; +$CPAN::META->has_inst('Digest::MD5','no'); +$CPAN::META->has_inst('LWP','no'); +$CPAN::META->has_inst('Compress::Zlib','no'); +@EXPORT = @CPAN::EXPORT; + +*AUTOLOAD = \&CPAN::AUTOLOAD; + +1; + +__END__ + +=head1 NAME + +CPAN::Nox - Wrapper around CPAN.pm without using any XS module + +=head1 SYNOPSIS + +Interactive mode: + + perl -MCPAN::Nox -e shell; + +=head1 DESCRIPTION + +This package has the same functionality as CPAN.pm, but tries to +prevent the usage of compiled extensions during its own +execution. Its primary purpose is a rescue in case you upgraded perl +and broke binary compatibility somehow. + +=head1 LICENSE + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L<CPAN> + +=cut + diff --git a/Master/tlpkg/tlperl/lib/CPAN/Prompt.pm b/Master/tlpkg/tlperl/lib/CPAN/Prompt.pm new file mode 100644 index 00000000000..7a4e2d81e13 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Prompt.pm @@ -0,0 +1,29 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +# vim: ts=4 sts=4 sw=4: +package CPAN::Prompt; +use overload '""' => "as_string"; +use vars qw($prompt); +use vars qw( + $VERSION +); +$VERSION = "5.5"; + + +$prompt = "cpan> "; +$CPAN::CurrentCommandId ||= 0; +sub new { + bless {}, shift; +} +sub as_string { + my $word = "cpan"; + unless ($CPAN::META->{LOCK}) { + $word = "nolock_cpan"; + } + if ($CPAN::Config->{commandnumber_in_prompt}) { + sprintf "$word\[%d]> ", $CPAN::CurrentCommandId; + } else { + "$word> "; + } +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/Queue.pm b/Master/tlpkg/tlperl/lib/CPAN/Queue.pm new file mode 100644 index 00000000000..b60f57c1cfe --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Queue.pm @@ -0,0 +1,198 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +use strict; +package CPAN::Queue::Item; + +# CPAN::Queue::Item::new ; +sub new { + my($class,@attr) = @_; + my $self = bless { @attr }, $class; + return $self; +} + +sub as_string { + my($self) = @_; + $self->{qmod}; +} + +# r => requires, b => build_requires, c => commandline +sub reqtype { + my($self) = @_; + $self->{reqtype}; +} + +package CPAN::Queue; + +# One use of the queue is to determine if we should or shouldn't +# announce the availability of a new CPAN module + +# Now we try to use it for dependency tracking. For that to happen +# we need to draw a dependency tree and do the leaves first. This can +# easily be reached by running CPAN.pm recursively, but we don't want +# to waste memory and run into deep recursion. So what we can do is +# this: + +# CPAN::Queue is the package where the queue is maintained. Dependencies +# often have high priority and must be brought to the head of the queue, +# possibly by jumping the queue if they are already there. My first code +# attempt tried to be extremely correct. Whenever a module needed +# immediate treatment, I either unshifted it to the front of the queue, +# or, if it was already in the queue, I spliced and let it bypass the +# others. This became a too correct model that made it impossible to put +# an item more than once into the queue. Why would you need that? Well, +# you need temporary duplicates as the manager of the queue is a loop +# that +# +# (1) looks at the first item in the queue without shifting it off +# +# (2) cares for the item +# +# (3) removes the item from the queue, *even if its agenda failed and +# even if the item isn't the first in the queue anymore* (that way +# protecting against never ending queues) +# +# So if an item has prerequisites, the installation fails now, but we +# want to retry later. That's easy if we have it twice in the queue. +# +# I also expect insane dependency situations where an item gets more +# than two lives in the queue. Simplest example is triggered by 'install +# Foo Foo Foo'. People make this kind of mistakes and I don't want to +# get in the way. I wanted the queue manager to be a dumb servant, not +# one that knows everything. +# +# Who would I tell in this model that the user wants to be asked before +# processing? I can't attach that information to the module object, +# because not modules are installed but distributions. So I'd have to +# tell the distribution object that it should ask the user before +# processing. Where would the question be triggered then? Most probably +# in CPAN::Distribution::rematein. + +use vars qw{ @All $VERSION }; +$VERSION = "5.5"; + +# CPAN::Queue::queue_item ; +sub queue_item { + my($class,@attr) = @_; + my $item = "$class\::Item"->new(@attr); + $class->qpush($item); + return 1; +} + +# CPAN::Queue::qpush ; +sub qpush { + my($class,$obj) = @_; + push @All, $obj; + CPAN->debug(sprintf("in new All[%s]", + join("",map {sprintf " %s\[%s]\n",$_->{qmod},$_->{reqtype}} @All), + )) if $CPAN::DEBUG; +} + +# CPAN::Queue::first ; +sub first { + my $obj = $All[0]; + $obj; +} + +# CPAN::Queue::delete_first ; +sub delete_first { + my($class,$what) = @_; + my $i; + for my $i (0..$#All) { + if ( $All[$i]->{qmod} eq $what ) { + splice @All, $i, 1; + return; + } + } +} + +# CPAN::Queue::jumpqueue ; +sub jumpqueue { + my $class = shift; + my @what = @_; + CPAN->debug(sprintf("before jumpqueue All[%s] what[%s]", + join("", + map {sprintf " %s\[%s]\n",$_->{qmod},$_->{reqtype}} @All, @what + ))) if $CPAN::DEBUG; + unless (defined $what[0]{reqtype}) { + # apparently it was not the Shell that sent us this enquiry, + # treat it as commandline + $what[0]{reqtype} = "c"; + } + my $inherit_reqtype = $what[0]{reqtype} =~ /^(c|r)$/ ? "r" : "b"; + WHAT: for my $what_tuple (@what) { + my($what,$reqtype) = @$what_tuple{qw(qmod reqtype)}; + if ($reqtype eq "r" + && + $inherit_reqtype eq "b" + ) { + $reqtype = "b"; + } + my $jumped = 0; + for (my $i=0; $i<$#All;$i++) { #prevent deep recursion + # CPAN->debug("i[$i]this[$All[$i]{qmod}]what[$what]") if $CPAN::DEBUG; + if ($All[$i]{qmod} eq $what) { + $jumped++; + if ($jumped >= 50) { + die "PANIC: object[$what] 50 instances on the queue, looks like ". + "some recursiveness has hit"; + } elsif ($jumped > 25) { # one's OK if e.g. just processing + # now; more are OK if user typed + # it several times + my $sleep = sprintf "%.1f", $jumped/10; + $CPAN::Frontend->mywarn( +qq{Warning: Object [$what] queued $jumped times, sleeping $sleep secs!\n} + ); + $CPAN::Frontend->mysleep($sleep); + # next WHAT; + } + } + } + my $obj = "$class\::Item"->new( + qmod => $what, + reqtype => $reqtype + ); + unshift @All, $obj; + } + CPAN->debug(sprintf("after jumpqueue All[%s]", + join("",map {sprintf " %s\[%s]\n",$_->{qmod},$_->{reqtype}} @All) + )) if $CPAN::DEBUG; +} + +# CPAN::Queue::exists ; +sub exists { + my($self,$what) = @_; + my @all = map { $_->{qmod} } @All; + my $exists = grep { $_->{qmod} eq $what } @All; + # warn "in exists what[$what] all[@all] exists[$exists]"; + $exists; +} + +# CPAN::Queue::delete ; +sub delete { + my($self,$mod) = @_; + @All = grep { $_->{qmod} ne $mod } @All; + CPAN->debug(sprintf("after delete mod[%s] All[%s]", + $mod, + join("",map {sprintf " %s\[%s]\n",$_->{qmod},$_->{reqtype}} @All) + )) if $CPAN::DEBUG; +} + +# CPAN::Queue::nullify_queue ; +sub nullify_queue { + @All = (); +} + +# CPAN::Queue::size ; +sub size { + return scalar @All; +} + +1; + +__END__ + +=head1 LICENSE + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=cut diff --git a/Master/tlpkg/tlperl/lib/CPAN/Shell.pm b/Master/tlpkg/tlperl/lib/CPAN/Shell.pm new file mode 100644 index 00000000000..91cbdd22ac8 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Shell.pm @@ -0,0 +1,1988 @@ +package CPAN::Shell; +use strict; + +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +# vim: ts=4 sts=4 sw=4: + +use vars qw( + $ADVANCED_QUERY + $AUTOLOAD + $COLOR_REGISTERED + $Help + $autoload_recursion + $reload + @ISA + @relo + $VERSION + ); +@relo = ( + "CPAN.pm", + "CPAN/Author.pm", + "CPAN/CacheMgr.pm", + "CPAN/Complete.pm", + "CPAN/Debug.pm", + "CPAN/DeferredCode.pm", + "CPAN/Distribution.pm", + "CPAN/Distroprefs.pm", + "CPAN/Distrostatus.pm", + "CPAN/Exception/RecursiveDependency.pm", + "CPAN/Exception/yaml_not_installed.pm", + "CPAN/FirstTime.pm", + "CPAN/FTP.pm", + "CPAN/FTP/netrc.pm", + "CPAN/HandleConfig.pm", + "CPAN/Index.pm", + "CPAN/InfoObj.pm", + "CPAN/Kwalify.pm", + "CPAN/LWP/UserAgent.pm", + "CPAN/Module.pm", + "CPAN/Prompt.pm", + "CPAN/Queue.pm", + "CPAN/Reporter/Config.pm", + "CPAN/Reporter/History.pm", + "CPAN/Reporter/PrereqCheck.pm", + "CPAN/Reporter.pm", + "CPAN/Shell.pm", + "CPAN/SQLite.pm", + "CPAN/Tarzip.pm", + "CPAN/Version.pm", + ); +$VERSION = "5.5001"; +# record the initial timestamp for reload. +$reload = { map {$INC{$_} ? ($_,(stat $INC{$_})[9]) : ()} @relo }; +@CPAN::Shell::ISA = qw(CPAN::Debug); +use Cwd qw(chdir); +use Carp (); +$COLOR_REGISTERED ||= 0; +$Help = { + '?' => \"help", + '!' => "eval the rest of the line as perl", + a => "whois author", + autobundle => "write inventory into a bundle file", + b => "info about bundle", + bye => \"quit", + clean => "clean up a distribution's build directory", + # cvs_import + d => "info about a distribution", + # dump + exit => \"quit", + failed => "list all failed actions within current session", + fforce => "redo a command from scratch", + force => "redo a command", + get => "download a distribution", + h => \"help", + help => "overview over commands; 'help ...' explains specific commands", + hosts => "statistics about recently used hosts", + i => "info about authors/bundles/distributions/modules", + install => "install a distribution", + install_tested => "install all distributions tested OK", + is_tested => "list all distributions tested OK", + look => "open a subshell in a distribution's directory", + ls => "list distributions matching a fileglob", + m => "info about a module", + make => "make/build a distribution", + mkmyconfig => "write current config into a CPAN/MyConfig.pm file", + notest => "run a (usually install) command but leave out the test phase", + o => "'o conf ...' for config stuff; 'o debug ...' for debugging", + perldoc => "try to get a manpage for a module", + q => \"quit", + quit => "leave the cpan shell", + r => "review upgradable modules", + readme => "display the README of a distro with a pager", + recent => "show recent uploads to the CPAN", + # recompile + reload => "'reload cpan' or 'reload index'", + report => "test a distribution and send a test report to cpantesters", + reports => "info about reported tests from cpantesters", + # scripts + # smoke + test => "test a distribution", + u => "display uninstalled modules", + upgrade => "combine 'r' command with immediate installation", + }; +{ + $autoload_recursion ||= 0; + + #-> sub CPAN::Shell::AUTOLOAD ; + sub AUTOLOAD { ## no critic + $autoload_recursion++; + my($l) = $AUTOLOAD; + my $class = shift(@_); + # warn "autoload[$l] class[$class]"; + $l =~ s/.*:://; + if ($CPAN::Signal) { + warn "Refusing to autoload '$l' while signal pending"; + $autoload_recursion--; + return; + } + if ($autoload_recursion > 1) { + my $fullcommand = join " ", map { "'$_'" } $l, @_; + warn "Refusing to autoload $fullcommand in recursion\n"; + $autoload_recursion--; + return; + } + if ($l =~ /^w/) { + # XXX needs to be reconsidered + if ($CPAN::META->has_inst('CPAN::WAIT')) { + CPAN::WAIT->$l(@_); + } else { + $CPAN::Frontend->mywarn(qq{ +Commands starting with "w" require CPAN::WAIT to be installed. +Please consider installing CPAN::WAIT to use the fulltext index. +For this you just need to type + install CPAN::WAIT +}); + } + } else { + $CPAN::Frontend->mywarn(qq{Unknown shell command '$l'. }. + qq{Type ? for help. +}); + } + $autoload_recursion--; + } +} + + +#-> sub CPAN::Shell::h ; +sub h { + my($class,$about) = @_; + if (defined $about) { + my $help; + if (exists $Help->{$about}) { + if (ref $Help->{$about}) { # aliases + $about = ${$Help->{$about}}; + } + $help = $Help->{$about}; + } else { + $help = "No help available"; + } + $CPAN::Frontend->myprint("$about\: $help\n"); + } else { + my $filler = " " x (80 - 28 - length($CPAN::VERSION)); + $CPAN::Frontend->myprint(qq{ +Display Information $filler (ver $CPAN::VERSION) + command argument description + a,b,d,m WORD or /REGEXP/ about authors, bundles, distributions, modules + i WORD or /REGEXP/ about any of the above + ls AUTHOR or GLOB about files in the author's directory + (with WORD being a module, bundle or author name or a distribution + name of the form AUTHOR/DISTRIBUTION) + +Download, Test, Make, Install... + get download clean make clean + make make (implies get) look open subshell in dist directory + test make test (implies make) readme display these README files + install make install (implies test) perldoc display POD documentation + +Upgrade + r WORDs or /REGEXP/ or NONE report updates for some/matching/all modules + upgrade WORDs or /REGEXP/ or NONE upgrade some/matching/all modules + +Pragmas + force CMD try hard to do command fforce CMD try harder + notest CMD skip testing + +Other + h,? display this menu ! perl-code eval a perl command + o conf [opt] set and query options q quit the cpan shell + reload cpan load CPAN.pm again reload index load newer indices + autobundle Snapshot recent latest CPAN uploads}); +} +} + +*help = \&h; + +#-> sub CPAN::Shell::a ; +sub a { + my($self,@arg) = @_; + # authors are always UPPERCASE + for (@arg) { + $_ = uc $_ unless /=/; + } + $CPAN::Frontend->myprint($self->format_result('Author',@arg)); +} + +#-> sub CPAN::Shell::globls ; +sub globls { + my($self,$s,$pragmas) = @_; + # ls is really very different, but we had it once as an ordinary + # command in the Shell (upto rev. 321) and we could not handle + # force well then + my(@accept,@preexpand); + if ($s =~ /[\*\?\/]/) { + if ($CPAN::META->has_inst("Text::Glob")) { + if (my($au,$pathglob) = $s =~ m|(.*?)/(.*)|) { + my $rau = Text::Glob::glob_to_regex(uc $au); + CPAN::Shell->debug("au[$au]pathglob[$pathglob]rau[$rau]") + if $CPAN::DEBUG; + push @preexpand, map { $_->id . "/" . $pathglob } + CPAN::Shell->expand_by_method('CPAN::Author',['id'],"/$rau/"); + } else { + my $rau = Text::Glob::glob_to_regex(uc $s); + push @preexpand, map { $_->id } + CPAN::Shell->expand_by_method('CPAN::Author', + ['id'], + "/$rau/"); + } + } else { + $CPAN::Frontend->mydie("Text::Glob not installed, cannot proceed"); + } + } else { + push @preexpand, uc $s; + } + for (@preexpand) { + unless (/^[A-Z0-9\-]+(\/|$)/i) { + $CPAN::Frontend->mywarn("ls command rejects argument $_: not an author\n"); + next; + } + push @accept, $_; + } + my $silent = @accept>1; + my $last_alpha = ""; + my @results; + for my $a (@accept) { + my($author,$pathglob); + if ($a =~ m|(.*?)/(.*)|) { + my $a2 = $1; + $pathglob = $2; + $author = CPAN::Shell->expand_by_method('CPAN::Author', + ['id'], + $a2) + or $CPAN::Frontend->mydie("No author found for $a2\n"); + } else { + $author = CPAN::Shell->expand_by_method('CPAN::Author', + ['id'], + $a) + or $CPAN::Frontend->mydie("No author found for $a\n"); + } + if ($silent) { + my $alpha = substr $author->id, 0, 1; + my $ad; + if ($alpha eq $last_alpha) { + $ad = ""; + } else { + $ad = "[$alpha]"; + $last_alpha = $alpha; + } + $CPAN::Frontend->myprint($ad); + } + for my $pragma (@$pragmas) { + if ($author->can($pragma)) { + $author->$pragma(); + } + } + CPAN->debug("author[$author]pathglob[$pathglob]silent[$silent]") if $CPAN::DEBUG; + push @results, $author->ls($pathglob,$silent); # silent if + # more than one + # author + for my $pragma (@$pragmas) { + my $unpragma = "un$pragma"; + if ($author->can($unpragma)) { + $author->$unpragma(); + } + } + } + @results; +} + +#-> sub CPAN::Shell::local_bundles ; +sub local_bundles { + my($self,@which) = @_; + my($incdir,$bdir,$dh); + foreach $incdir ($CPAN::Config->{'cpan_home'},@INC) { + my @bbase = "Bundle"; + while (my $bbase = shift @bbase) { + $bdir = File::Spec->catdir($incdir,split /::/, $bbase); + CPAN->debug("bdir[$bdir]\@bbase[@bbase]") if $CPAN::DEBUG; + if ($dh = DirHandle->new($bdir)) { # may fail + my($entry); + for $entry ($dh->read) { + next if $entry =~ /^\./; + next unless $entry =~ /^\w+(\.pm)?(?!\n)\Z/; + if (-d File::Spec->catdir($bdir,$entry)) { + push @bbase, "$bbase\::$entry"; + } else { + next unless $entry =~ s/\.pm(?!\n)\Z//; + $CPAN::META->instance('CPAN::Bundle',"$bbase\::$entry"); + } + } + } + } + } +} + +#-> sub CPAN::Shell::b ; +sub b { + my($self,@which) = @_; + CPAN->debug("which[@which]") if $CPAN::DEBUG; + $self->local_bundles; + $CPAN::Frontend->myprint($self->format_result('Bundle',@which)); +} + +#-> sub CPAN::Shell::d ; +sub d { $CPAN::Frontend->myprint(shift->format_result('Distribution',@_));} + +#-> sub CPAN::Shell::m ; +sub m { # emacs confused here }; sub mimimimimi { # emacs in sync here + my $self = shift; + my @m = @_; + for (@m) { + if (m|(?:\w+/)*\w+\.pm$|) { # same regexp in expandany + s/.pm$//; + s|/|::|g; + } + } + $CPAN::Frontend->myprint($self->format_result('Module',@m)); +} + +#-> sub CPAN::Shell::i ; +sub i { + my($self) = shift; + my(@args) = @_; + @args = '/./' unless @args; + my(@result); + for my $type (qw/Bundle Distribution Module/) { + push @result, $self->expand($type,@args); + } + # Authors are always uppercase. + push @result, $self->expand("Author", map { uc $_ } @args); + + my $result = @result == 1 ? + $result[0]->as_string : + @result == 0 ? + "No objects found of any type for argument @args\n" : + join("", + (map {$_->as_glimpse} @result), + scalar @result, " items found\n", + ); + $CPAN::Frontend->myprint($result); +} + +#-> sub CPAN::Shell::o ; + +# CPAN::Shell::o and CPAN::HandleConfig::edit are closely related. 'o +# conf' calls through to CPAN::HandleConfig::edit. 'o conf' should +# probably have been called 'set' and 'o debug' maybe 'set debug' or +# 'debug'; 'o conf ARGS' calls ->edit in CPAN/HandleConfig.pm +sub o { + my($self,$o_type,@o_what) = @_; + $o_type ||= ""; + CPAN->debug("o_type[$o_type] o_what[".join(" | ",@o_what)."]\n"); + if ($o_type eq 'conf') { + my($cfilter); + ($cfilter) = $o_what[0] =~ m|^/(.*)/$| if @o_what; + if (!@o_what or $cfilter) { # print all things, "o conf" + $cfilter ||= ""; + my $qrfilter = eval 'qr/$cfilter/'; + my($k,$v); + $CPAN::Frontend->myprint("\$CPAN::Config options from "); + my @from; + if (exists $INC{'CPAN/Config.pm'}) { + push @from, $INC{'CPAN/Config.pm'}; + } + if (exists $INC{'CPAN/MyConfig.pm'}) { + push @from, $INC{'CPAN/MyConfig.pm'}; + } + $CPAN::Frontend->myprint(join " and ", map {"'$_'"} @from); + $CPAN::Frontend->myprint(":\n"); + for $k (sort keys %CPAN::HandleConfig::can) { + next unless $k =~ /$qrfilter/; + $v = $CPAN::HandleConfig::can{$k}; + $CPAN::Frontend->myprint(sprintf " %-18s [%s]\n", $k, $v); + } + $CPAN::Frontend->myprint("\n"); + for $k (sort keys %CPAN::HandleConfig::keys) { + next unless $k =~ /$qrfilter/; + CPAN::HandleConfig->prettyprint($k); + } + $CPAN::Frontend->myprint("\n"); + } else { + if (CPAN::HandleConfig->edit(@o_what)) { + } else { + $CPAN::Frontend->myprint(qq{Type 'o conf' to view all configuration }. + qq{items\n\n}); + } + } + } elsif ($o_type eq 'debug') { + my(%valid); + @o_what = () if defined $o_what[0] && $o_what[0] =~ /help/i; + if (@o_what) { + while (@o_what) { + my($what) = shift @o_what; + if ($what =~ s/^-// && exists $CPAN::DEBUG{$what}) { + $CPAN::DEBUG &= $CPAN::DEBUG ^ $CPAN::DEBUG{$what}; + next; + } + if ( exists $CPAN::DEBUG{$what} ) { + $CPAN::DEBUG |= $CPAN::DEBUG{$what}; + } elsif ($what =~ /^\d/) { + $CPAN::DEBUG = $what; + } elsif (lc $what eq 'all') { + my($max) = 0; + for (values %CPAN::DEBUG) { + $max += $_; + } + $CPAN::DEBUG = $max; + } else { + my($known) = 0; + for (keys %CPAN::DEBUG) { + next unless lc($_) eq lc($what); + $CPAN::DEBUG |= $CPAN::DEBUG{$_}; + $known = 1; + } + $CPAN::Frontend->myprint("unknown argument [$what]\n") + unless $known; + } + } + } else { + my $raw = "Valid options for debug are ". + join(", ",sort(keys %CPAN::DEBUG), 'all'). + qq{ or a number. Completion works on the options. }. + qq{Case is ignored.}; + require Text::Wrap; + $CPAN::Frontend->myprint(Text::Wrap::fill("","",$raw)); + $CPAN::Frontend->myprint("\n\n"); + } + if ($CPAN::DEBUG) { + $CPAN::Frontend->myprint("Options set for debugging ($CPAN::DEBUG):\n"); + my($k,$v); + for $k (sort {$CPAN::DEBUG{$a} <=> $CPAN::DEBUG{$b}} keys %CPAN::DEBUG) { + $v = $CPAN::DEBUG{$k}; + $CPAN::Frontend->myprint(sprintf " %-14s(%s)\n", $k, $v) + if $v & $CPAN::DEBUG; + } + } else { + $CPAN::Frontend->myprint("Debugging turned off completely.\n"); + } + } else { + $CPAN::Frontend->myprint(qq{ +Known options: + conf set or get configuration variables + debug set or get debugging options +}); + } +} + +# CPAN::Shell::paintdots_onreload +sub paintdots_onreload { + my($ref) = shift; + sub { + if ( $_[0] =~ /[Ss]ubroutine ([\w:]+) redefined/ ) { + my($subr) = $1; + ++$$ref; + local($|) = 1; + # $CPAN::Frontend->myprint(".($subr)"); + $CPAN::Frontend->myprint("."); + if ($subr =~ /\bshell\b/i) { + # warn "debug[$_[0]]"; + + # It would be nice if we could detect that a + # subroutine has actually changed, but for now we + # practically always set the GOTOSHELL global + + $CPAN::GOTOSHELL=1; + } + return; + } + warn @_; + }; +} + +#-> sub CPAN::Shell::hosts ; +sub hosts { + my($self) = @_; + my $fullstats = CPAN::FTP->_ftp_statistics(); + my $history = $fullstats->{history} || []; + my %S; # statistics + while (my $last = pop @$history) { + my $attempts = $last->{attempts} or next; + my $start; + if (@$attempts) { + $start = $attempts->[-1]{start}; + if ($#$attempts > 0) { + for my $i (0..$#$attempts-1) { + my $url = $attempts->[$i]{url} or next; + $S{no}{$url}++; + } + } + } else { + $start = $last->{start}; + } + next unless $last->{thesiteurl}; # C-C? bad filenames? + $S{start} = $start; + $S{end} ||= $last->{end}; + my $dltime = $last->{end} - $start; + my $dlsize = $last->{filesize} || 0; + my $url = ref $last->{thesiteurl} ? $last->{thesiteurl}->text : $last->{thesiteurl}; + my $s = $S{ok}{$url} ||= {}; + $s->{n}++; + $s->{dlsize} ||= 0; + $s->{dlsize} += $dlsize/1024; + $s->{dltime} ||= 0; + $s->{dltime} += $dltime; + } + my $res; + for my $url (keys %{$S{ok}}) { + next if $S{ok}{$url}{dltime} == 0; # div by zero + push @{$res->{ok}}, [@{$S{ok}{$url}}{qw(n dlsize dltime)}, + $S{ok}{$url}{dlsize}/$S{ok}{$url}{dltime}, + $url, + ]; + } + for my $url (keys %{$S{no}}) { + push @{$res->{no}}, [$S{no}{$url}, + $url, + ]; + } + my $R = ""; # report + if ($S{start} && $S{end}) { + $R .= sprintf "Log starts: %s\n", $S{start} ? scalar(localtime $S{start}) : "unknown"; + $R .= sprintf "Log ends : %s\n", $S{end} ? scalar(localtime $S{end}) : "unknown"; + } + if ($res->{ok} && @{$res->{ok}}) { + $R .= sprintf "\nSuccessful downloads: + N kB secs kB/s url\n"; + my $i = 20; + for (sort { $b->[3] <=> $a->[3] } @{$res->{ok}}) { + $R .= sprintf "%4d %8d %5d %9.1f %s\n", @$_; + last if --$i<=0; + } + } + if ($res->{no} && @{$res->{no}}) { + $R .= sprintf "\nUnsuccessful downloads:\n"; + my $i = 20; + for (sort { $b->[0] <=> $a->[0] } @{$res->{no}}) { + $R .= sprintf "%4d %s\n", @$_; + last if --$i<=0; + } + } + $CPAN::Frontend->myprint($R); +} + +# here is where 'reload cpan' is done +#-> sub CPAN::Shell::reload ; +sub reload { + my($self,$command,@arg) = @_; + $command ||= ""; + $self->debug("self[$self]command[$command]arg[@arg]") if $CPAN::DEBUG; + if ($command =~ /^cpan$/i) { + my $redef = 0; + chdir $CPAN::iCwd if $CPAN::iCwd; # may fail + my $failed; + MFILE: for my $f (@relo) { + next unless exists $INC{$f}; + my $p = $f; + $p =~ s/\.pm$//; + $p =~ s|/|::|g; + $CPAN::Frontend->myprint("($p"); + local($SIG{__WARN__}) = paintdots_onreload(\$redef); + $self->_reload_this($f) or $failed++; + my $v = eval "$p\::->VERSION"; + $CPAN::Frontend->myprint("v$v)"); + } + $CPAN::Frontend->myprint("\n$redef subroutines redefined\n"); + if ($failed) { + my $errors = $failed == 1 ? "error" : "errors"; + $CPAN::Frontend->mywarn("\n$failed $errors during reload. You better quit ". + "this session.\n"); + } + } elsif ($command =~ /^index$/i) { + CPAN::Index->force_reload; + } else { + $CPAN::Frontend->myprint(qq{cpan re-evals the CPAN modules +index re-reads the index files\n}); + } +} + +# reload means only load again what we have loaded before +#-> sub CPAN::Shell::_reload_this ; +sub _reload_this { + my($self,$f,$args) = @_; + CPAN->debug("f[$f]") if $CPAN::DEBUG; + return 1 unless $INC{$f}; # we never loaded this, so we do not + # reload but say OK + my $pwd = CPAN::anycwd(); + CPAN->debug("pwd[$pwd]") if $CPAN::DEBUG; + my($file); + for my $inc (@INC) { + $file = File::Spec->catfile($inc,split /\//, $f); + last if -f $file; + $file = ""; + } + CPAN->debug("file[$file]") if $CPAN::DEBUG; + my @inc = @INC; + unless ($file && -f $file) { + # this thingie is not in the INC path, maybe CPAN/MyConfig.pm? + $file = $INC{$f}; + unless (CPAN->has_inst("File::Basename")) { + @inc = File::Basename::dirname($file); + } else { + # do we ever need this? + @inc = substr($file,0,-length($f)-1); # bring in back to me! + } + } + CPAN->debug("file[$file]inc[@inc]") if $CPAN::DEBUG; + unless (-f $file) { + $CPAN::Frontend->mywarn("Found no file to reload for '$f'\n"); + return; + } + my $mtime = (stat $file)[9]; + $reload->{$f} ||= -1; + my $must_reload = $mtime != $reload->{$f}; + $args ||= {}; + $must_reload ||= $args->{reloforce}; # o conf defaults needs this + if ($must_reload) { + my $fh = FileHandle->new($file) or + $CPAN::Frontend->mydie("Could not open $file: $!"); + local($/); + local $^W = 1; + my $content = <$fh>; + CPAN->debug(sprintf("reload file[%s] content[%s...]",$file,substr($content,0,128))) + if $CPAN::DEBUG; + delete $INC{$f}; + local @INC = @inc; + eval "require '$f'"; + if ($@) { + warn $@; + return; + } + $reload->{$f} = $mtime; + } else { + $CPAN::Frontend->myprint("__unchanged__"); + } + return 1; +} + +#-> sub CPAN::Shell::mkmyconfig ; +sub mkmyconfig { + my($self, $cpanpm, %args) = @_; + require CPAN::FirstTime; + my $home = CPAN::HandleConfig::home(); + $cpanpm = $INC{'CPAN/MyConfig.pm'} || + File::Spec->catfile(split /\//, "$home/.cpan/CPAN/MyConfig.pm"); + File::Path::mkpath(File::Basename::dirname($cpanpm)) unless -e $cpanpm; + CPAN::HandleConfig::require_myconfig_or_config(); + $CPAN::Config ||= {}; + $CPAN::Config = { + %$CPAN::Config, + build_dir => undef, + cpan_home => undef, + keep_source_where => undef, + histfile => undef, + }; + CPAN::FirstTime::init($cpanpm, %args); +} + +#-> sub CPAN::Shell::_binary_extensions ; +sub _binary_extensions { + my($self) = shift @_; + my(@result,$module,%seen,%need,$headerdone); + for $module ($self->expand('Module','/./')) { + my $file = $module->cpan_file; + next if $file eq "N/A"; + next if $file =~ /^Contact Author/; + my $dist = $CPAN::META->instance('CPAN::Distribution',$file); + next if $dist->isa_perl; + next unless $module->xs_file; + local($|) = 1; + $CPAN::Frontend->myprint("."); + push @result, $module; + } +# print join " | ", @result; + $CPAN::Frontend->myprint("\n"); + return @result; +} + +#-> sub CPAN::Shell::recompile ; +sub recompile { + my($self) = shift @_; + my($module,@module,$cpan_file,%dist); + @module = $self->_binary_extensions(); + for $module (@module) { # we force now and compile later, so we + # don't do it twice + $cpan_file = $module->cpan_file; + my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file); + $pack->force; + $dist{$cpan_file}++; + } + for $cpan_file (sort keys %dist) { + $CPAN::Frontend->myprint(" CPAN: Recompiling $cpan_file\n\n"); + my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file); + $pack->install; + $CPAN::Signal = 0; # it's tempting to reset Signal, so we can + # stop a package from recompiling, + # e.g. IO-1.12 when we have perl5.003_10 + } +} + +#-> sub CPAN::Shell::scripts ; +sub scripts { + my($self, $arg) = @_; + $CPAN::Frontend->mywarn(">>>> experimental command, currently unsupported <<<<\n\n"); + + for my $req (qw( HTML::LinkExtor Sort::Versions List::Util )) { + unless ($CPAN::META->has_inst($req)) { + $CPAN::Frontend->mywarn(" $req not available\n"); + } + } + my $p = HTML::LinkExtor->new(); + my $indexfile = "/home/ftp/pub/PAUSE/scripts/new/index.html"; + unless (-f $indexfile) { + $CPAN::Frontend->mydie("found no indexfile[$indexfile]\n"); + } + $p->parse_file($indexfile); + my @hrefs; + my $qrarg; + if ($arg =~ s|^/(.+)/$|$1|) { + $qrarg = eval 'qr/$arg/'; # hide construct from 5.004 + } + for my $l ($p->links) { + my $tag = shift @$l; + next unless $tag eq "a"; + my %att = @$l; + my $href = $att{href}; + next unless $href =~ s|^\.\./authors/id/./../||; + if ($arg) { + if ($qrarg) { + if ($href =~ $qrarg) { + push @hrefs, $href; + } + } else { + if ($href =~ /\Q$arg\E/) { + push @hrefs, $href; + } + } + } else { + push @hrefs, $href; + } + } + # now filter for the latest version if there is more than one of a name + my %stems; + for (sort @hrefs) { + my $href = $_; + s/-v?\d.*//; + my $stem = $_; + $stems{$stem} ||= []; + push @{$stems{$stem}}, $href; + } + for (sort keys %stems) { + my $highest; + if (@{$stems{$_}} > 1) { + $highest = List::Util::reduce { + Sort::Versions::versioncmp($a,$b) > 0 ? $a : $b + } @{$stems{$_}}; + } else { + $highest = $stems{$_}[0]; + } + $CPAN::Frontend->myprint("$highest\n"); + } +} + +#-> sub CPAN::Shell::report ; +sub report { + my($self,@args) = @_; + unless ($CPAN::META->has_inst("CPAN::Reporter")) { + $CPAN::Frontend->mydie("CPAN::Reporter not installed; cannot continue"); + } + local $CPAN::Config->{test_report} = 1; + $self->force("test",@args); # force is there so that the test be + # re-run (as documented) +} + +# compare with is_tested +#-> sub CPAN::Shell::install_tested +sub install_tested { + my($self,@some) = @_; + $CPAN::Frontend->mywarn("install_tested() must not be called with arguments.\n"), + return if @some; + CPAN::Index->reload; + + for my $b (reverse $CPAN::META->_list_sorted_descending_is_tested) { + my $yaml = "$b.yml"; + unless (-f $yaml) { + $CPAN::Frontend->mywarn("No YAML file for $b available, skipping\n"); + next; + } + my $yaml_content = CPAN->_yaml_loadfile($yaml); + my $id = $yaml_content->[0]{distribution}{ID}; + unless ($id) { + $CPAN::Frontend->mywarn("No ID found in '$yaml', skipping\n"); + next; + } + my $do = CPAN::Shell->expandany($id); + unless ($do) { + $CPAN::Frontend->mywarn("Could not expand ID '$id', skipping\n"); + next; + } + unless ($do->{build_dir}) { + $CPAN::Frontend->mywarn("Distro '$id' has no build_dir, skipping\n"); + next; + } + unless ($do->{build_dir} eq $b) { + $CPAN::Frontend->mywarn("Distro '$id' has build_dir '$do->{build_dir}' but expected '$b', skipping\n"); + next; + } + push @some, $do; + } + + $CPAN::Frontend->mywarn("No tested distributions found.\n"), + return unless @some; + + @some = grep { $_->{make_test} && ! $_->{make_test}->failed } @some; + $CPAN::Frontend->mywarn("No distributions tested with this build of perl found.\n"), + return unless @some; + + # @some = grep { not $_->uptodate } @some; + # $CPAN::Frontend->mywarn("No non-uptodate distributions tested with this build of perl found.\n"), + # return unless @some; + + CPAN->debug("some[@some]"); + for my $d (@some) { + my $id = $d->can("pretty_id") ? $d->pretty_id : $d->id; + $CPAN::Frontend->myprint("install_tested: Running for $id\n"); + $CPAN::Frontend->mysleep(1); + $self->install($d); + } +} + +#-> sub CPAN::Shell::upgrade ; +sub upgrade { + my($self,@args) = @_; + $self->install($self->r(@args)); +} + +#-> sub CPAN::Shell::_u_r_common ; +sub _u_r_common { + my($self) = shift @_; + my($what) = shift @_; + CPAN->debug("self[$self] what[$what] args[@_]") if $CPAN::DEBUG; + Carp::croak "Usage: \$obj->_u_r_common(a|r|u)" unless + $what && $what =~ /^[aru]$/; + my(@args) = @_; + @args = '/./' unless @args; + my(@result,$module,%seen,%need,$headerdone, + $version_undefs,$version_zeroes, + @version_undefs,@version_zeroes); + $version_undefs = $version_zeroes = 0; + my $sprintf = "%s%-25s%s %9s %9s %s\n"; + my @expand = $self->expand('Module',@args); + if ($CPAN::DEBUG) { # Looks like noise to me, was very useful for debugging + # for metadata cache + my $expand = scalar @expand; + $CPAN::Frontend->myprint(sprintf "%d matches in the database, time[%d]\n", $expand, time); + } + my @sexpand; + if ($] < 5.008) { + # hard to believe that the more complex sorting can lead to + # stack curruptions on older perl + @sexpand = sort {$a->id cmp $b->id} @expand; + } else { + @sexpand = map { + $_->[1] + } sort { + $b->[0] <=> $a->[0] + || + $a->[1]{ID} cmp $b->[1]{ID}, + } map { + [$_->_is_representative_module, + $_ + ] + } @expand; + } + if ($CPAN::DEBUG) { + $CPAN::Frontend->myprint(sprintf "sorted at time[%d]\n", time); + sleep 1; + } + MODULE: for $module (@sexpand) { + my $file = $module->cpan_file; + next MODULE unless defined $file; # ?? + $file =~ s!^./../!!; + my($latest) = $module->cpan_version; + my($inst_file) = $module->inst_file; + CPAN->debug("file[$file]latest[$latest]") if $CPAN::DEBUG; + my($have); + return if $CPAN::Signal; + my($next_MODULE); + eval { # version.pm involved! + if ($inst_file) { + if ($what eq "a") { + $have = $module->inst_version; + } elsif ($what eq "r") { + $have = $module->inst_version; + local($^W) = 0; + if ($have eq "undef") { + $version_undefs++; + push @version_undefs, $module->as_glimpse; + } elsif (CPAN::Version->vcmp($have,0)==0) { + $version_zeroes++; + push @version_zeroes, $module->as_glimpse; + } + ++$next_MODULE unless CPAN::Version->vgt($latest, $have); + # to be pedantic we should probably say: + # && !($have eq "undef" && $latest ne "undef" && $latest gt ""); + # to catch the case where CPAN has a version 0 and we have a version undef + } elsif ($what eq "u") { + ++$next_MODULE; + } + } else { + if ($what eq "a") { + ++$next_MODULE; + } elsif ($what eq "r") { + ++$next_MODULE; + } elsif ($what eq "u") { + $have = "-"; + } + } + }; + next MODULE if $next_MODULE; + if ($@) { + $CPAN::Frontend->mywarn + (sprintf("Error while comparing cpan/installed versions of '%s': +INST_FILE: %s +INST_VERSION: %s %s +CPAN_VERSION: %s %s +", + $module->id, + $inst_file || "", + (defined $have ? $have : "[UNDEFINED]"), + (ref $have ? ref $have : ""), + $latest, + (ref $latest ? ref $latest : ""), + )); + next MODULE; + } + return if $CPAN::Signal; # this is sometimes lengthy + $seen{$file} ||= 0; + if ($what eq "a") { + push @result, sprintf "%s %s\n", $module->id, $have; + } elsif ($what eq "r") { + push @result, $module->id; + next MODULE if $seen{$file}++; + } elsif ($what eq "u") { + push @result, $module->id; + next MODULE if $seen{$file}++; + next MODULE if $file =~ /^Contact/; + } + unless ($headerdone++) { + $CPAN::Frontend->myprint("\n"); + $CPAN::Frontend->myprint(sprintf( + $sprintf, + "", + "Package namespace", + "", + "installed", + "latest", + "in CPAN file" + )); + } + my $color_on = ""; + my $color_off = ""; + if ( + $COLOR_REGISTERED + && + $CPAN::META->has_inst("Term::ANSIColor") + && + $module->description + ) { + $color_on = Term::ANSIColor::color("green"); + $color_off = Term::ANSIColor::color("reset"); + } + $CPAN::Frontend->myprint(sprintf $sprintf, + $color_on, + $module->id, + $color_off, + $have, + $latest, + $file); + $need{$module->id}++; + } + unless (%need) { + if ($what eq "u") { + $CPAN::Frontend->myprint("No modules found for @args\n"); + } elsif ($what eq "r") { + $CPAN::Frontend->myprint("All modules are up to date for @args\n"); + } + } + if ($what eq "r") { + if ($version_zeroes) { + my $s_has = $version_zeroes > 1 ? "s have" : " has"; + $CPAN::Frontend->myprint(qq{$version_zeroes installed module$s_has }. + qq{a version number of 0\n}); + if ($CPAN::Config->{show_zero_versions}) { + local $" = "\t"; + $CPAN::Frontend->myprint(qq{ they are\n\t@version_zeroes\n}); + $CPAN::Frontend->myprint(qq{(use 'o conf show_zero_versions 0' }. + qq{to hide them)\n}); + } else { + $CPAN::Frontend->myprint(qq{(use 'o conf show_zero_versions 1' }. + qq{to show them)\n}); + } + } + if ($version_undefs) { + my $s_has = $version_undefs > 1 ? "s have" : " has"; + $CPAN::Frontend->myprint(qq{$version_undefs installed module$s_has no }. + qq{parsable version number\n}); + if ($CPAN::Config->{show_unparsable_versions}) { + local $" = "\t"; + $CPAN::Frontend->myprint(qq{ they are\n\t@version_undefs\n}); + $CPAN::Frontend->myprint(qq{(use 'o conf show_unparsable_versions 0' }. + qq{to hide them)\n}); + } else { + $CPAN::Frontend->myprint(qq{(use 'o conf show_unparsable_versions 1' }. + qq{to show them)\n}); + } + } + } + @result; +} + +#-> sub CPAN::Shell::r ; +sub r { + shift->_u_r_common("r",@_); +} + +#-> sub CPAN::Shell::u ; +sub u { + shift->_u_r_common("u",@_); +} + +#-> sub CPAN::Shell::failed ; +sub failed { + my($self,$only_id,$silent) = @_; + my @failed; + DIST: for my $d ($CPAN::META->all_objects("CPAN::Distribution")) { + my $failed = ""; + NAY: for my $nosayer ( # order matters! + "unwrapped", + "writemakefile", + "signature_verify", + "make", + "make_test", + "install", + "make_clean", + ) { + next unless exists $d->{$nosayer}; + next unless defined $d->{$nosayer}; + next unless ( + UNIVERSAL::can($d->{$nosayer},"failed") ? + $d->{$nosayer}->failed : + $d->{$nosayer} =~ /^NO/ + ); + next NAY if $only_id && $only_id != ( + UNIVERSAL::can($d->{$nosayer},"commandid") + ? + $d->{$nosayer}->commandid + : + $CPAN::CurrentCommandId + ); + $failed = $nosayer; + last; + } + next DIST unless $failed; + my $id = $d->id; + $id =~ s|^./../||; + #$print .= sprintf( + # " %-45s: %s %s\n", + push @failed, + ( + UNIVERSAL::can($d->{$failed},"failed") ? + [ + $d->{$failed}->commandid, + $id, + $failed, + $d->{$failed}->text, + $d->{$failed}{TIME}||0, + ] : + [ + 1, + $id, + $failed, + $d->{$failed}, + 0, + ] + ); + } + my $scope; + if ($only_id) { + $scope = "this command"; + } elsif ($CPAN::Index::HAVE_REANIMATED) { + $scope = "this or a previous session"; + # it might be nice to have a section for previous session and + # a second for this + } else { + $scope = "this session"; + } + if (@failed) { + my $print; + my $debug = 0; + if ($debug) { + $print = join "", + map { sprintf "%5d %-45s: %s %s\n", @$_ } + sort { $a->[0] <=> $b->[0] } @failed; + } else { + $print = join "", + map { sprintf " %-45s: %s %s\n", @$_[1..3] } + sort { + $a->[0] <=> $b->[0] + || + $a->[4] <=> $b->[4] + } @failed; + } + $CPAN::Frontend->myprint("Failed during $scope:\n$print"); + } elsif (!$only_id || !$silent) { + $CPAN::Frontend->myprint("Nothing failed in $scope\n"); + } +} + +# XXX intentionally undocumented because completely bogus, unportable, +# useless, etc. + +#-> sub CPAN::Shell::status ; +sub status { + my($self) = @_; + require Devel::Size; + my $ps = FileHandle->new; + open $ps, "/proc/$$/status"; + my $vm = 0; + while (<$ps>) { + next unless /VmSize:\s+(\d+)/; + $vm = $1; + last; + } + $CPAN::Frontend->mywarn(sprintf( + "%-27s %6d\n%-27s %6d\n", + "vm", + $vm, + "CPAN::META", + Devel::Size::total_size($CPAN::META)/1024, + )); + for my $k (sort keys %$CPAN::META) { + next unless substr($k,0,4) eq "read"; + warn sprintf " %-26s %6d\n", $k, Devel::Size::total_size($CPAN::META->{$k})/1024; + for my $k2 (sort keys %{$CPAN::META->{$k}}) { + warn sprintf " %-25s %6d (keys: %6d)\n", + $k2, + Devel::Size::total_size($CPAN::META->{$k}{$k2})/1024, + scalar keys %{$CPAN::META->{$k}{$k2}}; + } + } +} + +# compare with install_tested +#-> sub CPAN::Shell::is_tested +sub is_tested { + my($self) = @_; + CPAN::Index->reload; + for my $b (reverse $CPAN::META->_list_sorted_descending_is_tested) { + my $time; + if ($CPAN::META->{is_tested}{$b}) { + $time = scalar(localtime $CPAN::META->{is_tested}{$b}); + } else { + $time = scalar localtime; + $time =~ s/\S/?/g; + } + $CPAN::Frontend->myprint(sprintf "%s %s\n", $time, $b); + } +} + +#-> sub CPAN::Shell::autobundle ; +sub autobundle { + my($self) = shift; + CPAN::HandleConfig->load unless $CPAN::Config_loaded++; + my(@bundle) = $self->_u_r_common("a",@_); + my($todir) = File::Spec->catdir($CPAN::Config->{'cpan_home'},"Bundle"); + File::Path::mkpath($todir); + unless (-d $todir) { + $CPAN::Frontend->myprint("Couldn't mkdir $todir for some reason\n"); + return; + } + my($y,$m,$d) = (localtime)[5,4,3]; + $y+=1900; + $m++; + my($c) = 0; + my($me) = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, $c; + my($to) = File::Spec->catfile($todir,"$me.pm"); + while (-f $to) { + $me = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, ++$c; + $to = File::Spec->catfile($todir,"$me.pm"); + } + my($fh) = FileHandle->new(">$to") or Carp::croak "Can't open >$to: $!"; + $fh->print( + "package Bundle::$me;\n\n", + "\$","VERSION = '0.01';\n\n", # hide from perl-reversion + "1;\n\n", + "__END__\n\n", + "=head1 NAME\n\n", + "Bundle::$me - Snapshot of installation on ", + $Config::Config{'myhostname'}, + " on ", + scalar(localtime), + "\n\n=head1 SYNOPSIS\n\n", + "perl -MCPAN -e 'install Bundle::$me'\n\n", + "=head1 CONTENTS\n\n", + join("\n", @bundle), + "\n\n=head1 CONFIGURATION\n\n", + Config->myconfig, + "\n\n=head1 AUTHOR\n\n", + "This Bundle has been generated automatically ", + "by the autobundle routine in CPAN.pm.\n", + ); + $fh->close; + $CPAN::Frontend->myprint("\nWrote bundle file + $to\n\n"); +} + +#-> sub CPAN::Shell::expandany ; +sub expandany { + my($self,$s) = @_; + CPAN->debug("s[$s]") if $CPAN::DEBUG; + my $module_as_path = ""; + if ($s =~ m|(?:\w+/)*\w+\.pm$|) { # same regexp in sub m + $module_as_path = $s; + $module_as_path =~ s/.pm$//; + $module_as_path =~ s|/|::|g; + } + if ($module_as_path) { + if ($module_as_path =~ m|^Bundle::|) { + $self->local_bundles; + return $self->expand('Bundle',$module_as_path); + } else { + return $self->expand('Module',$module_as_path) + if $CPAN::META->exists('CPAN::Module',$module_as_path); + } + } elsif ($s =~ m|/| or substr($s,-1,1) eq ".") { # looks like a file or a directory + $s = CPAN::Distribution->normalize($s); + return $CPAN::META->instance('CPAN::Distribution',$s); + # Distributions spring into existence, not expand + } elsif ($s =~ m|^Bundle::|) { + $self->local_bundles; # scanning so late for bundles seems + # both attractive and crumpy: always + # current state but easy to forget + # somewhere + return $self->expand('Bundle',$s); + } else { + return $self->expand('Module',$s) + if $CPAN::META->exists('CPAN::Module',$s); + } + return; +} + +#-> sub CPAN::Shell::expand ; +sub expand { + my $self = shift; + my($type,@args) = @_; + CPAN->debug("type[$type]args[@args]") if $CPAN::DEBUG; + my $class = "CPAN::$type"; + my $methods = ['id']; + for my $meth (qw(name)) { + next unless $class->can($meth); + push @$methods, $meth; + } + $self->expand_by_method($class,$methods,@args); +} + +#-> sub CPAN::Shell::expand_by_method ; +sub expand_by_method { + my $self = shift; + my($class,$methods,@args) = @_; + my($arg,@m); + for $arg (@args) { + my($regex,$command); + if ($arg =~ m|^/(.*)/$|) { + $regex = $1; +# FIXME: there seem to be some ='s in the author data, which trigger +# a failure here. This needs to be contemplated. +# } elsif ($arg =~ m/=/) { +# $command = 1; + } + my $obj; + CPAN->debug(sprintf "class[%s]regex[%s]command[%s]", + $class, + defined $regex ? $regex : "UNDEFINED", + defined $command ? $command : "UNDEFINED", + ) if $CPAN::DEBUG; + if (defined $regex) { + if (CPAN::_sqlite_running()) { + CPAN::Index->reload; + $CPAN::SQLite->search($class, $regex); + } + for $obj ( + $CPAN::META->all_objects($class) + ) { + unless ($obj && UNIVERSAL::can($obj,"id") && $obj->id) { + # BUG, we got an empty object somewhere + require Data::Dumper; + CPAN->debug(sprintf( + "Bug in CPAN: Empty id on obj[%s][%s]", + $obj, + Data::Dumper::Dumper($obj) + )) if $CPAN::DEBUG; + next; + } + for my $method (@$methods) { + my $match = eval {$obj->$method() =~ /$regex/i}; + if ($@) { + my($err) = $@ =~ /^(.+) at .+? line \d+\.$/; + $err ||= $@; # if we were too restrictive above + $CPAN::Frontend->mydie("$err\n"); + } elsif ($match) { + push @m, $obj; + last; + } + } + } + } elsif ($command) { + die "equal sign in command disabled (immature interface), ". + "you can set + ! \$CPAN::Shell::ADVANCED_QUERY=1 +to enable it. But please note, this is HIGHLY EXPERIMENTAL code +that may go away anytime.\n" + unless $ADVANCED_QUERY; + my($method,$criterion) = $arg =~ /(.+?)=(.+)/; + my($matchcrit) = $criterion =~ m/^~(.+)/; + for my $self ( + sort + {$a->id cmp $b->id} + $CPAN::META->all_objects($class) + ) { + my $lhs = $self->$method() or next; # () for 5.00503 + if ($matchcrit) { + push @m, $self if $lhs =~ m/$matchcrit/; + } else { + push @m, $self if $lhs eq $criterion; + } + } + } else { + my($xarg) = $arg; + if ( $class eq 'CPAN::Bundle' ) { + $xarg =~ s/^(Bundle::)?(.*)/Bundle::$2/; + } elsif ($class eq "CPAN::Distribution") { + $xarg = CPAN::Distribution->normalize($arg); + } else { + $xarg =~ s/:+/::/g; + } + if ($CPAN::META->exists($class,$xarg)) { + $obj = $CPAN::META->instance($class,$xarg); + } elsif ($CPAN::META->exists($class,$arg)) { + $obj = $CPAN::META->instance($class,$arg); + } else { + next; + } + push @m, $obj; + } + } + @m = sort {$a->id cmp $b->id} @m; + if ( $CPAN::DEBUG ) { + my $wantarray = wantarray; + my $join_m = join ",", map {$_->id} @m; + # $self->debug("wantarray[$wantarray]join_m[$join_m]"); + my $count = scalar @m; + $self->debug("class[$class]wantarray[$wantarray]count m[$count]"); + } + return wantarray ? @m : $m[0]; +} + +#-> sub CPAN::Shell::format_result ; +sub format_result { + my($self) = shift; + my($type,@args) = @_; + @args = '/./' unless @args; + my(@result) = $self->expand($type,@args); + my $result = @result == 1 ? + $result[0]->as_string : + @result == 0 ? + "No objects of type $type found for argument @args\n" : + join("", + (map {$_->as_glimpse} @result), + scalar @result, " items found\n", + ); + $result; +} + +#-> sub CPAN::Shell::report_fh ; +{ + my $installation_report_fh; + my $previously_noticed = 0; + + sub report_fh { + return $installation_report_fh if $installation_report_fh; + if ($CPAN::META->has_usable("File::Temp")) { + $installation_report_fh + = File::Temp->new( + dir => File::Spec->tmpdir, + template => 'cpan_install_XXXX', + suffix => '.txt', + unlink => 0, + ); + } + unless ( $installation_report_fh ) { + warn("Couldn't open installation report file; " . + "no report file will be generated." + ) unless $previously_noticed++; + } + } +} + + +# The only reason for this method is currently to have a reliable +# debugging utility that reveals which output is going through which +# channel. No, I don't like the colors ;-) + +# to turn colordebugging on, write +# cpan> o conf colorize_output 1 + +#-> sub CPAN::Shell::colorize_output ; +{ + my $print_ornamented_have_warned = 0; + sub colorize_output { + my $colorize_output = $CPAN::Config->{colorize_output}; + if ($colorize_output && !$CPAN::META->has_inst("Term::ANSIColor")) { + unless ($print_ornamented_have_warned++) { + # no myprint/mywarn within myprint/mywarn! + warn "Colorize_output is set to true but Term::ANSIColor is not +installed. To activate colorized output, please install Term::ANSIColor.\n\n"; + } + $colorize_output = 0; + } + return $colorize_output; + } +} + + +#-> sub CPAN::Shell::print_ornamented ; +sub print_ornamented { + my($self,$what,$ornament) = @_; + return unless defined $what; + + local $| = 1; # Flush immediately + if ( $CPAN::Be_Silent ) { + print {report_fh()} $what; + return; + } + my $swhat = "$what"; # stringify if it is an object + if ($CPAN::Config->{term_is_latin}) { + # note: deprecated, need to switch to $LANG and $LC_* + # courtesy jhi: + $swhat + =~ s{([\xC0-\xDF])([\x80-\xBF])}{chr(ord($1)<<6&0xC0|ord($2)&0x3F)}eg; #}; + } + if ($self->colorize_output) { + if ( $CPAN::DEBUG && $swhat =~ /^Debug\(/ ) { + # if you want to have this configurable, please file a bugreport + $ornament = $CPAN::Config->{colorize_debug} || "black on_cyan"; + } + my $color_on = eval { Term::ANSIColor::color($ornament) } || ""; + if ($@) { + print "Term::ANSIColor rejects color[$ornament]: $@\n +Please choose a different color (Hint: try 'o conf init /color/')\n"; + } + # GGOLDBACH/Test-GreaterVersion-0.008 broke without this + # $trailer construct. We want the newline be the last thing if + # there is a newline at the end ensuring that the next line is + # empty for other players + my $trailer = ""; + $trailer = $1 if $swhat =~ s/([\r\n]+)\z//; + print $color_on, + $swhat, + Term::ANSIColor::color("reset"), + $trailer; + } else { + print $swhat; + } +} + +#-> sub CPAN::Shell::myprint ; + +# where is myprint/mywarn/Frontend/etc. documented? Where to use what? +# I think, we send everything to STDOUT and use print for normal/good +# news and warn for news that need more attention. Yes, this is our +# working contract for now. +sub myprint { + my($self,$what) = @_; + $self->print_ornamented($what, + $CPAN::Config->{colorize_print}||'bold blue on_white', + ); +} + +my %already_printed; +#-> sub CPAN::Shell::mywarnonce ; +sub myprintonce { + my($self,$what) = @_; + $self->myprint($what) unless $already_printed{$what}++; +} + +sub optprint { + my($self,$category,$what) = @_; + my $vname = $category . "_verbosity"; + CPAN::HandleConfig->load unless $CPAN::Config_loaded++; + if (!$CPAN::Config->{$vname} + || $CPAN::Config->{$vname} =~ /^v/ + ) { + $CPAN::Frontend->myprint($what); + } +} + +#-> sub CPAN::Shell::myexit ; +sub myexit { + my($self,$what) = @_; + $self->myprint($what); + exit; +} + +#-> sub CPAN::Shell::mywarn ; +sub mywarn { + my($self,$what) = @_; + $self->print_ornamented($what, $CPAN::Config->{colorize_warn}||'bold red on_white'); +} + +my %already_warned; +#-> sub CPAN::Shell::mywarnonce ; +sub mywarnonce { + my($self,$what) = @_; + $self->mywarn($what) unless $already_warned{$what}++; +} + +# only to be used for shell commands +#-> sub CPAN::Shell::mydie ; +sub mydie { + my($self,$what) = @_; + $self->mywarn($what); + + # If it is the shell, we want the following die to be silent, + # but if it is not the shell, we would need a 'die $what'. We need + # to take care that only shell commands use mydie. Is this + # possible? + + die "\n"; +} + +# sub CPAN::Shell::colorable_makemaker_prompt ; +sub colorable_makemaker_prompt { + my($foo,$bar) = @_; + if (CPAN::Shell->colorize_output) { + my $ornament = $CPAN::Config->{colorize_print}||'bold blue on_white'; + my $color_on = eval { Term::ANSIColor::color($ornament); } || ""; + print $color_on; + } + my $ans = ExtUtils::MakeMaker::prompt($foo,$bar); + if (CPAN::Shell->colorize_output) { + print Term::ANSIColor::color('reset'); + } + return $ans; +} + +# use this only for unrecoverable errors! +#-> sub CPAN::Shell::unrecoverable_error ; +sub unrecoverable_error { + my($self,$what) = @_; + my @lines = split /\n/, $what; + my $longest = 0; + for my $l (@lines) { + $longest = length $l if length $l > $longest; + } + $longest = 62 if $longest > 62; + for my $l (@lines) { + if ($l =~ /^\s*$/) { + $l = "\n"; + next; + } + $l = "==> $l"; + if (length $l < 66) { + $l = pack "A66 A*", $l, "<=="; + } + $l .= "\n"; + } + unshift @lines, "\n"; + $self->mydie(join "", @lines); +} + +#-> sub CPAN::Shell::mysleep ; +sub mysleep { + my($self, $sleep) = @_; + if (CPAN->has_inst("Time::HiRes")) { + Time::HiRes::sleep($sleep); + } else { + sleep($sleep < 1 ? 1 : int($sleep + 0.5)); + } +} + +#-> sub CPAN::Shell::setup_output ; +sub setup_output { + return if -t STDOUT; + my $odef = select STDERR; + $| = 1; + select STDOUT; + $| = 1; + select $odef; +} + +#-> sub CPAN::Shell::rematein ; +# RE-adme||MA-ke||TE-st||IN-stall : nearly everything runs through here +sub rematein { + my $self = shift; + # this variable was global and disturbed programmers, so localize: + local $CPAN::Distrostatus::something_has_failed_at; + my($meth,@some) = @_; + my @pragma; + while($meth =~ /^(ff?orce|notest)$/) { + push @pragma, $meth; + $meth = shift @some or + $CPAN::Frontend->mydie("Pragma $pragma[-1] used without method: ". + "cannot continue"); + } + setup_output(); + CPAN->debug("pragma[@pragma]meth[$meth]some[@some]") if $CPAN::DEBUG; + + # Here is the place to set "test_count" on all involved parties to + # 0. We then can pass this counter on to the involved + # distributions and those can refuse to test if test_count > X. In + # the first stab at it we could use a 1 for "X". + + # But when do I reset the distributions to start with 0 again? + # Jost suggested to have a random or cycling interaction ID that + # we pass through. But the ID is something that is just left lying + # around in addition to the counter, so I'd prefer to set the + # counter to 0 now, and repeat at the end of the loop. But what + # about dependencies? They appear later and are not reset, they + # enter the queue but not its copy. How do they get a sensible + # test_count? + + # With configure_requires, "get" is vulnerable in recursion. + + my $needs_recursion_protection = "get|make|test|install"; + + # construct the queue + my($s,@s,@qcopy); + STHING: foreach $s (@some) { + my $obj; + if (ref $s) { + CPAN->debug("s is an object[$s]") if $CPAN::DEBUG; + $obj = $s; + } elsif ($s =~ m|[\$\@\%]|) { # looks like a perl variable + } elsif ($s =~ m|^/|) { # looks like a regexp + if (substr($s,-1,1) eq ".") { + $obj = CPAN::Shell->expandany($s); + } else { + my @obj; + CLASS: for my $class (qw(Distribution Bundle Module)) { + if (@obj = $self->expand($class,$s)) { + last CLASS; + } + } + if (@obj) { + if (1==@obj) { + $obj = $obj[0]; + } else { + $CPAN::Frontend->mywarn("Sorry, $meth with a regular expression is ". + "only supported when unambiguous.\nRejecting argument '$s'\n"); + $CPAN::Frontend->mysleep(2); + next STHING; + } + } + } + } elsif ($meth eq "ls") { + $self->globls($s,\@pragma); + next STHING; + } else { + CPAN->debug("calling expandany [$s]") if $CPAN::DEBUG; + $obj = CPAN::Shell->expandany($s); + } + if (0) { + } elsif (ref $obj) { + if ($meth =~ /^($needs_recursion_protection)$/) { + # it would be silly to check for recursion for look or dump + # (we are in CPAN::Shell::rematein) + CPAN->debug("Going to test against recursion") if $CPAN::DEBUG; + eval { $obj->color_cmd_tmps(0,1); }; + if ($@) { + if (ref $@ + and $@->isa("CPAN::Exception::RecursiveDependency")) { + $CPAN::Frontend->mywarn($@); + } else { + if (0) { + require Carp; + Carp::confess(sprintf "DEBUG: \$\@[%s]ref[%s]", $@, ref $@); + } + die; + } + } + } + CPAN::Queue->queue_item(qmod => $obj->id, reqtype => "c"); + push @qcopy, $obj; + } elsif ($CPAN::META->exists('CPAN::Author',uc($s))) { + $obj = $CPAN::META->instance('CPAN::Author',uc($s)); + if ($meth =~ /^(dump|ls|reports)$/) { + $obj->$meth(); + } else { + $CPAN::Frontend->mywarn( + join "", + "Don't be silly, you can't $meth ", + $obj->fullname, + " ;-)\n" + ); + $CPAN::Frontend->mysleep(2); + } + } elsif ($s =~ m|[\$\@\%]| && $meth eq "dump") { + CPAN::InfoObj->dump($s); + } else { + $CPAN::Frontend + ->mywarn(qq{Warning: Cannot $meth $s, }. + qq{don't know what it is. +Try the command + + i /$s/ + +to find objects with matching identifiers. +}); + $CPAN::Frontend->mysleep(2); + } + } + + # queuerunner (please be warned: when I started to change the + # queue to hold objects instead of names, I made one or two + # mistakes and never found which. I reverted back instead) + QITEM: while (my $q = CPAN::Queue->first) { + my $obj; + my $s = $q->as_string; + my $reqtype = $q->reqtype || ""; + $obj = CPAN::Shell->expandany($s); + unless ($obj) { + # don't know how this can happen, maybe we should panic, + # but maybe we get a solution from the first user who hits + # this unfortunate exception? + $CPAN::Frontend->mywarn("Warning: Could not expand string '$s' ". + "to an object. Skipping.\n"); + $CPAN::Frontend->mysleep(5); + CPAN::Queue->delete_first($s); + next QITEM; + } + $obj->{reqtype} ||= ""; + { + # force debugging because CPAN::SQLite somehow delivers us + # an empty object; + + # local $CPAN::DEBUG = 1024; # Shell; probably fixed now + + CPAN->debug("s[$s]obj-reqtype[$obj->{reqtype}]". + "q-reqtype[$reqtype]") if $CPAN::DEBUG; + } + if ($obj->{reqtype}) { + if ($obj->{reqtype} eq "b" && $reqtype =~ /^[rc]$/) { + $obj->{reqtype} = $reqtype; + if ( + exists $obj->{install} + && + ( + UNIVERSAL::can($obj->{install},"failed") ? + $obj->{install}->failed : + $obj->{install} =~ /^NO/ + ) + ) { + delete $obj->{install}; + $CPAN::Frontend->mywarn + ("Promoting $obj->{ID} from 'build_requires' to 'requires'"); + } + } + } else { + $obj->{reqtype} = $reqtype; + } + + for my $pragma (@pragma) { + if ($pragma + && + $obj->can($pragma)) { + $obj->$pragma($meth); + } + } + if (UNIVERSAL::can($obj, 'called_for')) { + $obj->called_for($s); + } + CPAN->debug(qq{pragma[@pragma]meth[$meth]}. + qq{ID[$obj->{ID}]}) if $CPAN::DEBUG; + + push @qcopy, $obj; + if ($meth =~ /^(report)$/) { # they came here with a pragma? + $self->$meth($obj); + } elsif (! UNIVERSAL::can($obj,$meth)) { + # Must never happen + my $serialized = ""; + if (0) { + } elsif ($CPAN::META->has_inst("YAML::Syck")) { + $serialized = YAML::Syck::Dump($obj); + } elsif ($CPAN::META->has_inst("YAML")) { + $serialized = YAML::Dump($obj); + } elsif ($CPAN::META->has_inst("Data::Dumper")) { + $serialized = Data::Dumper::Dumper($obj); + } else { + require overload; + $serialized = overload::StrVal($obj); + } + CPAN->debug("Going to panic. meth[$meth]s[$s]") if $CPAN::DEBUG; + $CPAN::Frontend->mydie("Panic: obj[$serialized] cannot meth[$meth]"); + } elsif ($obj->$meth()) { + CPAN::Queue->delete($s); + CPAN->debug("From queue deleted. meth[$meth]s[$s]") if $CPAN::DEBUG; + } else { + CPAN->debug("Failed. pragma[@pragma]meth[$meth]") if $CPAN::DEBUG; + } + + $obj->undelay; + for my $pragma (@pragma) { + my $unpragma = "un$pragma"; + if ($obj->can($unpragma)) { + $obj->$unpragma(); + } + } + if ($CPAN::Config->{halt_on_failure} + && + CPAN::Distrostatus::something_has_just_failed() + ) { + $CPAN::Frontend->mywarn("Stopping: '$meth' failed for '$s'.\n"); + CPAN::Queue->nullify_queue; + last QITEM; + } + CPAN::Queue->delete_first($s); + } + if ($meth =~ /^($needs_recursion_protection)$/) { + for my $obj (@qcopy) { + $obj->color_cmd_tmps(0,0); + } + } +} + +#-> sub CPAN::Shell::recent ; +sub recent { + my($self) = @_; + if ($CPAN::META->has_inst("XML::LibXML")) { + my $url = $CPAN::Defaultrecent; + $CPAN::Frontend->myprint("Going to fetch '$url'\n"); + unless ($CPAN::META->has_usable("LWP")) { + $CPAN::Frontend->mydie("LWP not installed; cannot continue"); + } + CPAN::LWP::UserAgent->config; + my $Ua; + eval { $Ua = CPAN::LWP::UserAgent->new; }; + if ($@) { + $CPAN::Frontend->mydie("CPAN::LWP::UserAgent->new dies with $@\n"); + } + my $resp = $Ua->get($url); + unless ($resp->is_success) { + $CPAN::Frontend->mydie(sprintf "Could not download '%s': %s\n", $url, $resp->code); + } + $CPAN::Frontend->myprint("DONE\n\n"); + my $xml = XML::LibXML->new->parse_string($resp->content); + if (0) { + my $s = $xml->serialize(2); + $s =~ s/\n\s*\n/\n/g; + $CPAN::Frontend->myprint($s); + return; + } + my @distros; + if ($url =~ /winnipeg/) { + my $pubdate = $xml->findvalue("/rss/channel/pubDate"); + $CPAN::Frontend->myprint(" pubDate: $pubdate\n\n"); + for my $eitem ($xml->findnodes("/rss/channel/item")) { + my $distro = $eitem->findvalue("enclosure/\@url"); + $distro =~ s|.*?/authors/id/./../||; + my $size = $eitem->findvalue("enclosure/\@length"); + my $desc = $eitem->findvalue("description"); + $desc =~ s/.+? - //; + $CPAN::Frontend->myprint("$distro [$size b]\n $desc\n"); + push @distros, $distro; + } + } elsif ($url =~ /search.*uploads.rdf/) { + # xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + # xmlns="http://purl.org/rss/1.0/" + # xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" + # xmlns:dc="http://purl.org/dc/elements/1.1/" + # xmlns:syn="http://purl.org/rss/1.0/modules/syndication/" + # xmlns:admin="http://webns.net/mvcb/" + + + my $dc_date = $xml->findvalue("//*[local-name(.) = 'RDF']/*[local-name(.) = 'channel']/*[local-name(.) = 'date']"); + $CPAN::Frontend->myprint(" dc:date: $dc_date\n\n"); + my $finish_eitem = 0; + local $SIG{INT} = sub { $finish_eitem = 1 }; + EITEM: for my $eitem ($xml->findnodes("//*[local-name(.) = 'RDF']/*[local-name(.) = 'item']")) { + my $distro = $eitem->findvalue("\@rdf:about"); + $distro =~ s|.*~||; # remove up to the tilde before the name + $distro =~ s|/$||; # remove trailing slash + $distro =~ s|([^/]+)|\U$1\E|; # upcase the name + my $author = uc $1 or die "distro[$distro] without author, cannot continue"; + my $desc = $eitem->findvalue("*[local-name(.) = 'description']"); + my $i = 0; + SUBDIRTEST: while () { + last SUBDIRTEST if ++$i >= 6; # half a dozen must do! + if (my @ret = $self->globls("$distro*")) { + @ret = grep {$_->[2] !~ /meta/} @ret; + @ret = grep {length $_->[2]} @ret; + if (@ret) { + $distro = "$author/$ret[0][2]"; + last SUBDIRTEST; + } + } + $distro =~ s|/|/*/|; # allow it to reside in a subdirectory + } + + next EITEM if $distro =~ m|\*|; # did not find the thing + $CPAN::Frontend->myprint("____$desc\n"); + push @distros, $distro; + last EITEM if $finish_eitem; + } + } + return \@distros; + } else { + # deprecated old version + $CPAN::Frontend->mydie("no XML::LibXML installed, cannot continue\n"); + } +} + +#-> sub CPAN::Shell::smoke ; +sub smoke { + my($self) = @_; + my $distros = $self->recent; + DISTRO: for my $distro (@$distros) { + next if $distro =~ m|/Bundle-|; # XXX crude heuristic to skip bundles + $CPAN::Frontend->myprint(sprintf "Going to download and test '$distro'\n"); + { + my $skip = 0; + local $SIG{INT} = sub { $skip = 1 }; + for (0..9) { + $CPAN::Frontend->myprint(sprintf "\r%2d (Hit ^C to skip)", 10-$_); + sleep 1; + if ($skip) { + $CPAN::Frontend->myprint(" skipped\n"); + next DISTRO; + } + } + } + $CPAN::Frontend->myprint("\r \n"); # leave the dirty line with a newline + $self->test($distro); + } +} + +{ + # set up the dispatching methods + no strict "refs"; + for my $command (qw( + clean + cvs_import + dump + force + fforce + get + install + look + ls + make + notest + perldoc + readme + reports + test + )) { + *$command = sub { shift->rematein($command, @_); }; + } +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/Tarzip.pm b/Master/tlpkg/tlperl/lib/CPAN/Tarzip.pm new file mode 100644 index 00000000000..63451e7450d --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Tarzip.pm @@ -0,0 +1,451 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +package CPAN::Tarzip; +use strict; +use vars qw($VERSION @ISA $BUGHUNTING); +use CPAN::Debug; +use File::Basename qw(basename); +$VERSION = "5.5011"; +# module is internal to CPAN.pm + +@ISA = qw(CPAN::Debug); ## no critic +$BUGHUNTING ||= 0; # released code must have turned off + +# it's ok if file doesn't exist, it just matters if it is .gz or .bz2 +sub new { + my($class,$file) = @_; + $CPAN::Frontend->mydie("CPAN::Tarzip->new called without arg") unless defined $file; + my $me = { FILE => $file }; + if ($file =~ /\.(bz2|gz|zip|tbz|tgz)$/i) { + $me->{ISCOMPRESSED} = 1; + } else { + $me->{ISCOMPRESSED} = 0; + } + if (0) { + } elsif ($file =~ /\.(?:bz2|tbz)$/i) { + unless ($me->{UNGZIPPRG} = $CPAN::Config->{bzip2}) { + my $bzip2 = _my_which("bzip2"); + if ($bzip2) { + $me->{UNGZIPPRG} = $bzip2; + } else { + $CPAN::Frontend->mydie(qq{ +CPAN.pm needs the external program bzip2 in order to handle '$file'. +Please install it now and run 'o conf init bzip2' from the +CPAN shell prompt to register it as external program. +}); + } + } + } else { + $me->{UNGZIPPRG} = _my_which("gzip"); + } + $me->{TARPRG} = _my_which("tar") || _my_which("gtar"); + bless $me, $class; +} + +sub _my_which { + my($what) = @_; + if ($CPAN::Config->{$what}) { + return $CPAN::Config->{$what}; + } + if ($CPAN::META->has_inst("File::Which")) { + return File::Which::which($what); + } + my @cand = MM->maybe_command($what); + return $cand[0] if @cand; + require File::Spec; + my $component; + PATH_COMPONENT: foreach $component (File::Spec->path()) { + next unless defined($component) && $component; + my($abs) = File::Spec->catfile($component,$what); + if (MM->maybe_command($abs)) { + return $abs; + } + } + return; +} + +sub gzip { + my($self,$read) = @_; + my $write = $self->{FILE}; + if ($CPAN::META->has_inst("Compress::Zlib")) { + my($buffer,$fhw); + $fhw = FileHandle->new($read) + or $CPAN::Frontend->mydie("Could not open $read: $!"); + my $cwd = `pwd`; + my $gz = Compress::Zlib::gzopen($write, "wb") + or $CPAN::Frontend->mydie("Cannot gzopen $write: $! (pwd is $cwd)\n"); + $gz->gzwrite($buffer) + while read($fhw,$buffer,4096) > 0 ; + $gz->gzclose() ; + $fhw->close; + return 1; + } else { + my $command = CPAN::HandleConfig->safe_quote($self->{UNGZIPPRG}); + system(qq{$command -c "$read" > "$write"})==0; + } +} + + +sub gunzip { + my($self,$write) = @_; + my $read = $self->{FILE}; + if ($CPAN::META->has_inst("Compress::Zlib")) { + my($buffer,$fhw); + $fhw = FileHandle->new(">$write") + or $CPAN::Frontend->mydie("Could not open >$write: $!"); + my $gz = Compress::Zlib::gzopen($read, "rb") + or $CPAN::Frontend->mydie("Cannot gzopen $read: $!\n"); + $fhw->print($buffer) + while $gz->gzread($buffer) > 0 ; + $CPAN::Frontend->mydie("Error reading from $read: $!\n") + if $gz->gzerror != Compress::Zlib::Z_STREAM_END(); + $gz->gzclose() ; + $fhw->close; + return 1; + } else { + my $command = CPAN::HandleConfig->safe_quote($self->{UNGZIPPRG}); + system(qq{$command -dc "$read" > "$write"})==0; + } +} + + +sub gtest { + my($self) = @_; + return $self->{GTEST} if exists $self->{GTEST}; + defined $self->{FILE} or $CPAN::Frontend->mydie("gtest called but no FILE specified"); + my $read = $self->{FILE}; + my $success; + if ($read=~/\.(?:bz2|tbz)$/ && $CPAN::META->has_inst("Compress::Bzip2")) { + my($buffer,$len); + $len = 0; + my $gz = Compress::Bzip2::bzopen($read, "rb") + or $CPAN::Frontend->mydie(sprintf("Cannot gzopen %s: %s\n", + $read, + $Compress::Bzip2::bzerrno)); + while ($gz->bzread($buffer) > 0 ) { + $len += length($buffer); + $buffer = ""; + } + my $err = $gz->bzerror; + $success = ! $err || $err == Compress::Bzip2::BZ_STREAM_END(); + if ($len == -s $read) { + $success = 0; + CPAN->debug("hit an uncompressed file") if $CPAN::DEBUG; + } + $gz->gzclose(); + CPAN->debug("err[$err]success[$success]") if $CPAN::DEBUG; + } elsif ( $read=~/\.(?:gz|tgz)$/ && $CPAN::META->has_inst("Compress::Zlib") ) { + # After I had reread the documentation in zlib.h, I discovered that + # uncompressed files do not lead to an gzerror (anymore?). + my($buffer,$len); + $len = 0; + my $gz = Compress::Zlib::gzopen($read, "rb") + or $CPAN::Frontend->mydie(sprintf("Cannot gzopen %s: %s\n", + $read, + $Compress::Zlib::gzerrno)); + while ($gz->gzread($buffer) > 0 ) { + $len += length($buffer); + $buffer = ""; + } + my $err = $gz->gzerror; + $success = ! $err || $err == Compress::Zlib::Z_STREAM_END(); + if ($len == -s $read) { + $success = 0; + CPAN->debug("hit an uncompressed file") if $CPAN::DEBUG; + } + $gz->gzclose(); + CPAN->debug("err[$err]success[$success]") if $CPAN::DEBUG; + } elsif (!$self->{ISCOMPRESSED}) { + $success = 0; + } else { + my $command = CPAN::HandleConfig->safe_quote($self->{UNGZIPPRG}); + $success = 0==system(qq{$command -qdt "$read"}); + } + return $self->{GTEST} = $success; +} + + +sub TIEHANDLE { + my($class,$file) = @_; + my $ret; + $class->debug("file[$file]"); + my $self = $class->new($file); + if (0) { + } elsif (!$self->gtest) { + my $fh = FileHandle->new($file) + or $CPAN::Frontend->mydie("Could not open file[$file]: $!"); + binmode $fh; + $self->{FH} = $fh; + $class->debug("via uncompressed FH"); + } elsif ($file =~ /\.(?:bz2|tbz)$/ && $CPAN::META->has_inst("Compress::Bzip2")) { + my $gz = Compress::Bzip2::bzopen($file,"rb") or + $CPAN::Frontend->mydie("Could not bzopen $file"); + $self->{GZ} = $gz; + $class->debug("via Compress::Bzip2"); + } elsif ($file =~/\.(?:gz|tgz)$/ && $CPAN::META->has_inst("Compress::Zlib")) { + my $gz = Compress::Zlib::gzopen($file,"rb") or + $CPAN::Frontend->mydie("Could not gzopen $file"); + $self->{GZ} = $gz; + $class->debug("via Compress::Zlib"); + } else { + my $gzip = CPAN::HandleConfig->safe_quote($self->{UNGZIPPRG}); + my $pipe = "$gzip -dc $file |"; + my $fh = FileHandle->new($pipe) or $CPAN::Frontend->mydie("Could not pipe[$pipe]: $!"); + binmode $fh; + $self->{FH} = $fh; + $class->debug("via external $gzip"); + } + $self; +} + + +sub READLINE { + my($self) = @_; + if (exists $self->{GZ}) { + my $gz = $self->{GZ}; + my($line,$bytesread); + $bytesread = $gz->gzreadline($line); + return undef if $bytesread <= 0; + return $line; + } else { + my $fh = $self->{FH}; + return scalar <$fh>; + } +} + + +sub READ { + my($self,$ref,$length,$offset) = @_; + $CPAN::Frontend->mydie("read with offset not implemented") if defined $offset; + if (exists $self->{GZ}) { + my $gz = $self->{GZ}; + my $byteread = $gz->gzread($$ref,$length);# 30eaf79e8b446ef52464b5422da328a8 + return $byteread; + } else { + my $fh = $self->{FH}; + return read($fh,$$ref,$length); + } +} + + +sub DESTROY { + my($self) = @_; + if (exists $self->{GZ}) { + my $gz = $self->{GZ}; + $gz->gzclose() if defined $gz; # hard to say if it is allowed + # to be undef ever. AK, 2000-09 + } else { + my $fh = $self->{FH}; + $fh->close if defined $fh; + } + undef $self; +} + +sub untar { + my($self) = @_; + my $file = $self->{FILE}; + my($prefer) = 0; + + my $exttar = $self->{TARPRG} || ""; + $exttar = "" if $exttar =~ /^\s+$/; # user refuses to use it + my $extgzip = $self->{UNGZIPPRG} || ""; + $extgzip = "" if $extgzip =~ /^\s+$/; # user refuses to use it + + if (0) { # makes changing order easier + } elsif ($BUGHUNTING) { + $prefer=2; + } elsif ($exttar && $extgzip && $file =~ /\.(?:bz2|tbz)$/i) { + # until Archive::Tar handles bzip2 + $prefer = 1; + } elsif ( + $CPAN::META->has_usable("Archive::Tar") + && + $CPAN::META->has_inst("Compress::Zlib") ) { + $prefer = 2; + } elsif ($exttar && $extgzip) { + # no modules and not bz2 + $prefer = 1; + # but solaris binary tar is a problem + if ($^O eq 'solaris' && qx($exttar --version 2>/dev/null) !~ /gnu/i) { + $CPAN::Frontend->mywarn(<< 'END_WARN'); + +WARNING: Many CPAN distributions were archived with GNU tar and some of +them may be incompatible with Solaris tar. We respectfully suggest you +configure CPAN to use a GNU tar instead ("o conf init tar") or install +a recent Archive::Tar instead; + +END_WARN + } + } else { + my $foundtar = $exttar ? "'$exttar'" : "nothing"; + my $foundzip = $extgzip ? "'$extgzip'" : $foundtar ? "nothing" : "also nothing"; + my $foundAT; + if ($CPAN::META->has_usable("Archive::Tar")) { + $foundAT = sprintf "'%s'", "Archive::Tar::"->VERSION; + } else { + $foundAT = "nothing"; + } + my $foundCZ; + if ($CPAN::META->has_inst("Compress::Zlib")) { + $foundCZ = sprintf "'%s'", "Compress::Zlib::"->VERSION; + } elsif ($foundAT) { + $foundCZ = "nothing"; + } else { + $foundCZ = "also nothing"; + } + $CPAN::Frontend->mydie(qq{ + +CPAN.pm needs either the external programs tar and gzip -or- both +modules Archive::Tar and Compress::Zlib installed. + +For tar I found $foundtar, for gzip $foundzip. + +For Archive::Tar I found $foundAT, for Compress::Zlib $foundCZ; + +Can't continue cutting file '$file'. +}); + } + my $tar_verb = "v"; + if (defined $CPAN::Config->{tar_verbosity}) { + $tar_verb = $CPAN::Config->{tar_verbosity} eq "none" ? "" : + $CPAN::Config->{tar_verbosity}; + } + if ($prefer==1) { # 1 => external gzip+tar + my($system); + my $is_compressed = $self->gtest(); + my $tarcommand = CPAN::HandleConfig->safe_quote($exttar); + if ($is_compressed) { + my $command = CPAN::HandleConfig->safe_quote($extgzip); + $system = qq{$command -dc }. + qq{< "$file" | $tarcommand x${tar_verb}f -}; + } else { + $system = qq{$tarcommand x${tar_verb}f "$file"}; + } + if (system($system) != 0) { + # people find the most curious tar binaries that cannot handle + # pipes + if ($is_compressed) { + (my $ungzf = $file) =~ s/\.gz(?!\n)\Z//; + $ungzf = basename $ungzf; + my $ct = CPAN::Tarzip->new($file); + if ($ct->gunzip($ungzf)) { + $CPAN::Frontend->myprint(qq{Uncompressed $file successfully\n}); + } else { + $CPAN::Frontend->mydie(qq{Couldn\'t uncompress $file\n}); + } + $file = $ungzf; + } + $system = qq{$tarcommand x${tar_verb}f "$file"}; + $CPAN::Frontend->myprint(qq{Using Tar:$system:\n}); + if (system($system)==0) { + $CPAN::Frontend->myprint(qq{Untarred $file successfully\n}); + } else { + $CPAN::Frontend->mydie(qq{Couldn\'t untar $file\n}); + } + return 1; + } else { + return 1; + } + } elsif ($prefer==2) { # 2 => modules + unless ($CPAN::META->has_usable("Archive::Tar")) { + $CPAN::Frontend->mydie("Archive::Tar not installed, please install it to continue"); + } + # Make sure AT does not use uid/gid/permissions in the archive + # This leaves it to the user's umask instead + local $Archive::Tar::CHMOD = 1; + local $Archive::Tar::SAME_PERMISSIONS = 0; + # Make sure AT leaves current user as owner + local $Archive::Tar::CHOWN = 0; + my $tar = Archive::Tar->new($file,1); + my $af; # archive file + my @af; + if ($BUGHUNTING) { + # RCS 1.337 had this code, it turned out unacceptable slow but + # it revealed a bug in Archive::Tar. Code is only here to hunt + # the bug again. It should never be enabled in published code. + # GDGraph3d-0.53 was an interesting case according to Larry + # Virden. + warn(">>>Bughunting code enabled<<< " x 20); + for $af ($tar->list_files) { + if ($af =~ m!^(/|\.\./)!) { + $CPAN::Frontend->mydie("ALERT: Archive contains ". + "illegal member [$af]"); + } + $CPAN::Frontend->myprint("$af\n"); + $tar->extract($af); # slow but effective for finding the bug + return if $CPAN::Signal; + } + } else { + for $af ($tar->list_files) { + if ($af =~ m!^(/|\.\./)!) { + $CPAN::Frontend->mydie("ALERT: Archive contains ". + "illegal member [$af]"); + } + if ($tar_verb eq "v" || $tar_verb eq "vv") { + $CPAN::Frontend->myprint("$af\n"); + } + push @af, $af; + return if $CPAN::Signal; + } + $tar->extract(@af) or + $CPAN::Frontend->mydie("Could not untar with Archive::Tar."); + } + + Mac::BuildTools::convert_files([$tar->list_files], 1) + if ($^O eq 'MacOS'); + + return 1; + } +} + +sub unzip { + my($self) = @_; + my $file = $self->{FILE}; + if ($CPAN::META->has_inst("Archive::Zip")) { + # blueprint of the code from Archive::Zip::Tree::extractTree(); + my $zip = Archive::Zip->new(); + my $status; + $status = $zip->read($file); + $CPAN::Frontend->mydie("Read of file[$file] failed\n") + if $status != Archive::Zip::AZ_OK(); + $CPAN::META->debug("Successfully read file[$file]") if $CPAN::DEBUG; + my @members = $zip->members(); + for my $member ( @members ) { + my $af = $member->fileName(); + if ($af =~ m!^(/|\.\./)!) { + $CPAN::Frontend->mydie("ALERT: Archive contains ". + "illegal member [$af]"); + } + $status = $member->extractToFileNamed( $af ); + $CPAN::META->debug("af[$af]status[$status]") if $CPAN::DEBUG; + $CPAN::Frontend->mydie("Extracting of file[$af] from zipfile[$file] failed\n") if + $status != Archive::Zip::AZ_OK(); + return if $CPAN::Signal; + } + return 1; + } elsif ( my $unzip = $CPAN::Config->{unzip} ) { + my @system = ($unzip, $file); + return system(@system) == 0; + } + else { + $CPAN::Frontend->mydie(<<"END"); + +Can't unzip '$file': + +You have not configured an 'unzip' program and do not have Archive::Zip +installed. Please either install Archive::Zip or else configure 'unzip' +by running the command 'o conf init unzip' from the CPAN shell prompt. + +END + } +} + +1; + +__END__ + +=head1 LICENSE + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=cut diff --git a/Master/tlpkg/tlperl/lib/CPAN/URL.pm b/Master/tlpkg/tlperl/lib/CPAN/URL.pm new file mode 100644 index 00000000000..52b42eec88e --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/URL.pm @@ -0,0 +1,31 @@ +# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*- +# vim: ts=4 sts=4 sw=4: +package CPAN::URL; +use overload '""' => "as_string", fallback => 1; +# accessors: TEXT(the url string), FROM(DEF=>defaultlist,USER=>urllist), +# planned are things like age or quality + +use vars qw( + $VERSION +); +$VERSION = "5.5"; + +sub new { + my($class,%args) = @_; + bless { + %args + }, $class; +} +sub as_string { + my($self) = @_; + $self->text; +} +sub text { + my($self,$set) = @_; + if (defined $set) { + $self->{TEXT} = $set; + } + $self->{TEXT}; +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPAN/Version.pm b/Master/tlpkg/tlperl/lib/CPAN/Version.pm new file mode 100644 index 00000000000..da876aac2d7 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPAN/Version.pm @@ -0,0 +1,173 @@ +package CPAN::Version; + +use strict; +use vars qw($VERSION); +$VERSION = "5.5"; + +# CPAN::Version::vcmp courtesy Jost Krieger +sub vcmp { + my($self,$l,$r) = @_; + local($^W) = 0; + CPAN->debug("l[$l] r[$r]") if $CPAN::DEBUG; + + return 0 if $l eq $r; # short circuit for quicker success + + for ($l,$r) { + s/_//g; + } + CPAN->debug("l[$l] r[$r]") if $CPAN::DEBUG; + for ($l,$r) { + next unless tr/.// > 1 || /^v/; + s/^v?/v/; + 1 while s/\.0+(\d)/.$1/; # remove leading zeroes per group + } + CPAN->debug("l[$l] r[$r]") if $CPAN::DEBUG; + if ($l=~/^v/ <=> $r=~/^v/) { + for ($l,$r) { + next if /^v/; + $_ = $self->float2vv($_); + } + } + CPAN->debug("l[$l] r[$r]") if $CPAN::DEBUG; + my $lvstring = "v0"; + my $rvstring = "v0"; + if ($] >= 5.006 + && $l =~ /^v/ + && $r =~ /^v/) { + $lvstring = $self->vstring($l); + $rvstring = $self->vstring($r); + CPAN->debug(sprintf "lv[%vd] rv[%vd]", $lvstring, $rvstring) if $CPAN::DEBUG; + } + + return ( + ($l ne "undef") <=> ($r ne "undef") + || + $lvstring cmp $rvstring + || + $l <=> $r + || + $l cmp $r + ); +} + +sub vgt { + my($self,$l,$r) = @_; + $self->vcmp($l,$r) > 0; +} + +sub vlt { + my($self,$l,$r) = @_; + 0 + ($self->vcmp($l,$r) < 0); +} + +sub vge { + my($self,$l,$r) = @_; + $self->vcmp($l,$r) >= 0; +} + +sub vle { + my($self,$l,$r) = @_; + 0 + ($self->vcmp($l,$r) <= 0); +} + +sub vstring { + my($self,$n) = @_; + $n =~ s/^v// or die "CPAN::Version::vstring() called with invalid arg [$n]"; + pack "U*", split /\./, $n; +} + +# vv => visible vstring +sub float2vv { + my($self,$n) = @_; + my($rev) = int($n); + $rev ||= 0; + my($mantissa) = $n =~ /\.(\d{1,12})/; # limit to 12 digits to limit + # architecture influence + $mantissa ||= 0; + $mantissa .= "0" while length($mantissa)%3; + my $ret = "v" . $rev; + while ($mantissa) { + $mantissa =~ s/(\d{1,3})// or + die "Panic: length>0 but not a digit? mantissa[$mantissa]"; + $ret .= ".".int($1); + } + # warn "n[$n]ret[$ret]"; + $ret =~ s/(\.0)+/.0/; # v1.0.0 => v1.0 + $ret; +} + +sub readable { + my($self,$n) = @_; + $n =~ /^([\w\-\+\.]+)/; + + return $1 if defined $1 && length($1)>0; + # if the first user reaches version v43, he will be treated as "+". + # We'll have to decide about a new rule here then, depending on what + # will be the prevailing versioning behavior then. + + if ($] < 5.006) { # or whenever v-strings were introduced + # we get them wrong anyway, whatever we do, because 5.005 will + # have already interpreted 0.2.4 to be "0.24". So even if he + # indexer sends us something like "v0.2.4" we compare wrongly. + + # And if they say v1.2, then the old perl takes it as "v12" + + if (defined $CPAN::Frontend) { + $CPAN::Frontend->mywarn("Suspicious version string seen [$n]\n"); + } else { + warn("Suspicious version string seen [$n]\n"); + } + return $n; + } + my $better = sprintf "v%vd", $n; + CPAN->debug("n[$n] better[$better]") if $CPAN::DEBUG; + return $better; +} + +1; + +__END__ + +=head1 NAME + +CPAN::Version - utility functions to compare CPAN versions + +=head1 SYNOPSIS + + use CPAN::Version; + + CPAN::Version->vgt("1.1","1.1.1"); # 1 bc. 1.1 > 1.001001 + + CPAN::Version->vlt("1.1","1.1"); # 0 bc. 1.1 not < 1.1 + + CPAN::Version->vcmp("1.1","1.1.1"); # 1 bc. first is larger + + CPAN::Version->vcmp("1.1.1","1.1"); # -1 bc. first is smaller + + CPAN::Version->readable(v1.2.3); # "v1.2.3" + + CPAN::Version->vstring("v1.2.3"); # v1.2.3 + + CPAN::Version->float2vv(1.002003); # "v1.2.3" + +=head1 DESCRIPTION + +This module mediates between some version that perl sees in a package +and the version that is published by the CPAN indexer. + +It's only written as a helper module for both CPAN.pm and CPANPLUS.pm. + +As it stands it predates version.pm but has the same goal: make +version strings visible and comparable. + +=head1 LICENSE + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=cut + +# Local Variables: +# mode: cperl +# cperl-indent-level: 4 +# End: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Backend.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Backend.pm new file mode 100644 index 00000000000..a599e5429eb --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Backend.pm @@ -0,0 +1,1330 @@ +package CPANPLUS::Backend; + +use strict; + + +use CPANPLUS::Error; +use CPANPLUS::Configure; +use CPANPLUS::Internals; +use CPANPLUS::Internals::Constants; +use CPANPLUS::Module; +use CPANPLUS::Module::Author; +use CPANPLUS::Backend::RV; + +use FileHandle; +use File::Spec (); +use File::Spec::Unix (); +use File::Basename (); +use Params::Check qw[check]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +$Params::Check::VERBOSE = 1; + +use vars qw[@ISA $VERSION]; + +@ISA = qw[CPANPLUS::Internals]; +$VERSION = $CPANPLUS::Internals::VERSION; + +### mark that we're running under CPANPLUS to spawned processes +$ENV{'PERL5_CPANPLUS_IS_RUNNING'} = $$; + +### XXX version.pm MAY format this version, if it's in use... :( +### so for consistency, just call ->VERSION ourselves as well. +$ENV{'PERL5_CPANPLUS_IS_VERSION'} = __PACKAGE__->VERSION; + +=pod + +=head1 NAME + +CPANPLUS::Backend + +=head1 SYNOPSIS + + my $cb = CPANPLUS::Backend->new; + my $conf = $cb->configure_object; + + my $author = $cb->author_tree('KANE'); + my $mod = $cb->module_tree('Some::Module'); + my $mod = $cb->parse_module( module => 'Some::Module' ); + + my @objs = $cb->search( type => TYPE, + allow => [...] ); + + $cb->flush('all'); + $cb->reload_indices; + $cb->local_mirror; + + +=head1 DESCRIPTION + +This module provides the programmer's interface to the C<CPANPLUS> +libraries. + +=head1 ENVIRONMENT + +When C<CPANPLUS::Backend> is loaded, which is necessary for just +about every <CPANPLUS> operation, the environment variable +C<PERL5_CPANPLUS_IS_RUNNING> is set to the current process id. + +Additionally, the environment variable C<PERL5_CPANPLUS_IS_VERSION> +will be set to the version of C<CPANPLUS::Backend>. + +This information might be useful somehow to spawned processes. + +=head1 METHODS + +=head2 $cb = CPANPLUS::Backend->new( [CONFIGURE_OBJ] ) + +This method returns a new C<CPANPLUS::Backend> object. +This also initialises the config corresponding to this object. +You have two choices in this: + +=over 4 + +=item Provide a valid C<CPANPLUS::Configure> object + +This will be used verbatim. + +=item No arguments + +Your default config will be loaded and used. + +=back + +New will return a C<CPANPLUS::Backend> object on success and die on +failure. + +=cut + +sub new { + my $class = shift; + my $conf; + + if( $_[0] && IS_CONFOBJ->( conf => $_[0] ) ) { + $conf = shift; + } else { + $conf = CPANPLUS::Configure->new() or return; + } + + my $self = $class->SUPER::_init( _conf => $conf ); + + return $self; +} + +=pod + +=head2 $href = $cb->module_tree( [@modules_names_list] ) + +Returns a reference to the CPANPLUS module tree. + +If you give it any arguments, they will be treated as module names +and C<module_tree> will try to look up these module names and +return the corresponding module objects instead. + +See L<CPANPLUS::Module> for the operations you can perform on a +module object. + +=cut + +sub module_tree { + my $self = shift; + my $modtree = $self->_module_tree; + + if( @_ ) { + my @rv; + for my $name ( grep { defined } @_) { + + ### From John Malmberg: This is failing on VMS + ### because ODS-2 does not retain the case of + ### filenames that are created. + ### The problem is the filename is being converted + ### to a module name and then looked up in the + ### %$modtree hash. + ### + ### As a fix, we do a search on VMS instead -- + ### more cpu cycles, but it gets around the case + ### problem --kane + my ($modobj) = do { + ON_VMS + ? $self->search( + type => 'module', + allow => [qr/^$name$/i], + ) + : $modtree->{$name} + }; + + push @rv, $modobj || ''; + } + return @rv == 1 ? $rv[0] : @rv; + } else { + return $modtree; + } +} + +=pod + +=head2 $href = $cb->author_tree( [@author_names_list] ) + +Returns a reference to the CPANPLUS author tree. + +If you give it any arguments, they will be treated as author names +and C<author_tree> will try to look up these author names and +return the corresponding author objects instead. + +See L<CPANPLUS::Module::Author> for the operations you can perform on +an author object. + +=cut + +sub author_tree { + my $self = shift; + my $authtree = $self->_author_tree; + + if( @_ ) { + my @rv; + for my $name (@_) { + push @rv, $authtree->{$name} || ''; + } + return @rv == 1 ? $rv[0] : @rv; + } else { + return $authtree; + } +} + +=pod + +=head2 $conf = $cb->configure_object; + +Returns a copy of the C<CPANPLUS::Configure> object. + +See L<CPANPLUS::Configure> for operations you can perform on a +configure object. + +=cut + +sub configure_object { return shift->_conf() }; + +=head2 $su = $cb->selfupdate_object; + +Returns a copy of the C<CPANPLUS::Selfupdate> object. + +See the L<CPANPLUS::Selfupdate> manpage for the operations +you can perform on the selfupdate object. + +=cut + +sub selfupdate_object { return shift->_selfupdate() }; + +=pod + +=head2 @mods = $cb->search( type => TYPE, allow => AREF, [data => AREF, verbose => BOOL] ) + +C<search> enables you to search for either module or author objects, +based on their data. The C<type> you can specify is any of the +accessors specified in C<CPANPLUS::Module::Author> or +C<CPANPLUS::Module>. C<search> will determine by the C<type> you +specified whether to search by author object or module object. + +You have to specify an array reference of regular expressions or +strings to match against. The rules used for this array ref are the +same as in C<Params::Check>, so read that manpage for details. + +The search is an C<or> search, meaning that if C<any> of the criteria +match, the search is considered to be successful. + +You can specify the result of a previous search as C<data> to limit +the new search to these module or author objects, rather than the +entire module or author tree. This is how you do C<and> searches. + +Returns a list of module or author objects on success and false +on failure. + +See L<CPANPLUS::Module> for the operations you can perform on a +module object. +See L<CPANPLUS::Module::Author> for the operations you can perform on +an author object. + +=cut + +sub search { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my ($type); + my $args = do { + local $Params::Check::NO_DUPLICATES = 0; + local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + type => { required => 1, allow => [CPANPLUS::Module->accessors(), + CPANPLUS::Module::Author->accessors()], store => \$type }, + allow => { required => 1, default => [ ], strict_type => 1 }, + }; + + check( $tmpl, \%hash ) + } or return; + + ### figure out whether it was an author or a module search + ### when ambiguous, it'll be an author search. + my $aref; + if( grep { $type eq $_ } CPANPLUS::Module::Author->accessors() ) { + $aref = $self->_search_author_tree( %$args ); + } else { + $aref = $self->_search_module_tree( %$args ); + } + + return @$aref if $aref; + return; +} + +=pod + +=head2 $backend_rv = $cb->fetch( modules => \@mods ) + +Fetches a list of modules. C<@mods> can be a list of distribution +names, module names or module objects--basically anything that +L<parse_module> can understand. + +See the equivalent method in C<CPANPLUS::Module> for details on +other options you can pass. + +Since this is a multi-module method call, the return value is +implemented as a C<CPANPLUS::Backend::RV> object. Please consult +that module's documentation on how to interpret the return value. + +=head2 $backend_rv = $cb->extract( modules => \@mods ) + +Extracts a list of modules. C<@mods> can be a list of distribution +names, module names or module objects--basically anything that +L<parse_module> can understand. + +See the equivalent method in C<CPANPLUS::Module> for details on +other options you can pass. + +Since this is a multi-module method call, the return value is +implemented as a C<CPANPLUS::Backend::RV> object. Please consult +that module's documentation on how to interpret the return value. + +=head2 $backend_rv = $cb->install( modules => \@mods ) + +Installs a list of modules. C<@mods> can be a list of distribution +names, module names or module objects--basically anything that +L<parse_module> can understand. + +See the equivalent method in C<CPANPLUS::Module> for details on +other options you can pass. + +Since this is a multi-module method call, the return value is +implemented as a C<CPANPLUS::Backend::RV> object. Please consult +that module's documentation on how to interpret the return value. + +=head2 $backend_rv = $cb->readme( modules => \@mods ) + +Fetches the readme for a list of modules. C<@mods> can be a list of +distribution names, module names or module objects--basically +anything that L<parse_module> can understand. + +See the equivalent method in C<CPANPLUS::Module> for details on +other options you can pass. + +Since this is a multi-module method call, the return value is +implemented as a C<CPANPLUS::Backend::RV> object. Please consult +that module's documentation on how to interpret the return value. + +=head2 $backend_rv = $cb->files( modules => \@mods ) + +Returns a list of files used by these modules if they are installed. +C<@mods> can be a list of distribution names, module names or module +objects--basically anything that L<parse_module> can understand. + +See the equivalent method in C<CPANPLUS::Module> for details on +other options you can pass. + +Since this is a multi-module method call, the return value is +implemented as a C<CPANPLUS::Backend::RV> object. Please consult +that module's documentation on how to interpret the return value. + +=head2 $backend_rv = $cb->distributions( modules => \@mods ) + +Returns a list of module objects representing all releases for this +module on success. +C<@mods> can be a list of distribution names, module names or module +objects, basically anything that L<parse_module> can understand. + +See the equivalent method in C<CPANPLUS::Module> for details on +other options you can pass. + +Since this is a multi-module method call, the return value is +implemented as a C<CPANPLUS::Backend::RV> object. Please consult +that module's documentation on how to interpret the return value. + +=cut + +### XXX add direcotry_tree, packlist etc? or maybe remove files? ### +for my $func (qw[fetch extract install readme files distributions]) { + no strict 'refs'; + + *$func = sub { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my ($mods); + my $args = do { + local $Params::Check::NO_DUPLICATES = 1; + local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + modules => { default => [], strict_type => 1, + required => 1, store => \$mods }, + }; + + check( $tmpl, \%hash ); + } or return; + + ### make them all into module objects ### + my %mods = map { $_ => $self->parse_module(module => $_) || '' } @$mods; + + my $flag; my $href; + while( my($name,$obj) = each %mods ) { + $href->{$name} = IS_MODOBJ->( mod => $obj ) + ? $obj->$func( %$args ) + : undef; + + $flag++ unless $href->{$name}; + } + + return CPANPLUS::Backend::RV->new( + function => $func, + ok => !$flag, + rv => $href, + args => \%hash, + ); + } +} + +=pod + +=head2 $mod_obj = $cb->parse_module( module => $modname|$distname|$modobj|URI|PATH ) + +C<parse_module> tries to find a C<CPANPLUS::Module> object that +matches your query. Here's a list of examples you could give to +C<parse_module>; + +=over 4 + +=item Text::Bastardize + +=item Text-Bastardize + +=item Text-Bastardize-1.06 + +=item AYRNIEU/Text-Bastardize + +=item AYRNIEU/Text-Bastardize-1.06 + +=item AYRNIEU/Text-Bastardize-1.06.tar.gz + +=item http://example.com/Text-Bastardize-1.06.tar.gz + +=item file:///tmp/Text-Bastardize-1.06.tar.gz + +=item /tmp/Text-Bastardize-1.06 + +=item ./Text-Bastardize-1.06 + +=item . + +=back + +These items would all come up with a C<CPANPLUS::Module> object for +C<Text::Bastardize>. The ones marked explicitly as being version 1.06 +would give back a C<CPANPLUS::Module> object of that version. +Even if the version on CPAN is currently higher. + +The last three are examples of PATH resolution. In the first, we supply +an absolute path to the unwrapped distribution. In the second the +distribution is relative to the current working directory. +In the third, we will use the current working directory. + +If C<parse_module> is unable to actually find the module you are looking +for in its module tree, but you supplied it with an author, module +and version part in a distribution name or URI, it will create a fake +C<CPANPLUS::Module> object for you, that you can use just like the +real thing. + +See L<CPANPLUS::Module> for the operations you can perform on a +module object. + +If even this fancy guessing doesn't enable C<parse_module> to create +a fake module object for you to use, it will warn about an error and +return false. + +=cut + +sub parse_module { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my $mod; + my $tmpl = { + module => { required => 1, store => \$mod }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + return $mod if IS_MODOBJ->( module => $mod ); + + ### ok, so it's not a module object, but a ref nonetheless? + ### what are you smoking? + if( ref $mod ) { + error(loc("Can not parse module string from reference '%1'", $mod )); + return; + } + + ### check only for allowed characters in a module name + unless( $mod =~ /[^\w:]/ ) { + + ### perhaps we can find it in the module tree? + my $maybe = $self->module_tree($mod); + return $maybe if IS_MODOBJ->( module => $maybe ); + } + + ### Special case arbitary file paths such as '.' etc. + if ( $mod and -d File::Spec->rel2abs($mod) ) { + my $dir = File::Spec->rel2abs($mod); + my $parent = File::Spec->rel2abs( File::Spec->catdir( $dir, '..' ) ); + + ### fix paths on VMS + if (ON_VMS) { + $dir = VMS::Filespec::unixify($dir); + $parent = VMS::Filespec::unixify($parent); + } + + my $dist = $mod = File::Basename::basename($dir); + $dist .= '-0' unless $dist =~ /\-[0-9._]+$/; + $dist .= '.tar.gz' unless $dist =~ /\.[A-Za-z]+$/; + + my $modobj = CPANPLUS::Module::Fake->new( + module => $mod, + version => 0, + package => $dist, + path => $parent, + author => CPANPLUS::Module::Author::Fake->new + ); + + ### better guess for the version + $modobj->version( $modobj->package_version ) + if defined $modobj->package_version; + + ### better guess at module name, if possible + if ( my $pkgname = $modobj->package_name ) { + $pkgname =~ s/-/::/g; + + ### no sense replacing it unless we changed something + $modobj->module( $pkgname ) + if ($pkgname ne $modobj->package_name) || $pkgname !~ /-/; + } + + $modobj->status->fetch( $parent ); + $modobj->status->extract( $dir ); + $modobj->get_installer_type; + return $modobj; + } + + ### ok, so it looks like a distribution then? + my @parts = split '/', $mod; + my $dist = pop @parts; + + ### ah, it's a URL + if( $mod =~ m|\w+://.+| ) { + my $modobj = CPANPLUS::Module::Fake->new( + module => $dist, + version => 0, + package => $dist, + path => File::Spec::Unix->catdir( + $conf->_get_mirror('base'), + UNKNOWN_DL_LOCATION ), + author => CPANPLUS::Module::Author::Fake->new + ); + + ### set the fetch_from accessor so we know to by pass the + ### usual mirrors + $modobj->status->_fetch_from( $mod ); + + ### better guess for the version + $modobj->version( $modobj->package_version ) + if defined $modobj->package_version; + + ### better guess at module name, if possible + if ( my $pkgname = $modobj->package_name ) { + $pkgname =~ s/-/::/g; + + ### no sense replacing it unless we changed something + $modobj->module( $pkgname ) + if ($pkgname ne $modobj->package_name) || $pkgname !~ /-/; + } + + return $modobj; + } + + ### perhaps we can find it's a third party module? + { my $modobj = CPANPLUS::Module::Fake->new( + module => $mod, + version => 0, + package => $dist, + path => File::Spec::Unix->catdir( + $conf->_get_mirror('base'), + UNKNOWN_DL_LOCATION ), + author => CPANPLUS::Module::Author::Fake->new + ); + if( $modobj->is_third_party ) { + my $info = $modobj->third_party_information; + + $modobj->author->author( $info->{author} ); + $modobj->author->email( $info->{author_url} ); + $modobj->description( $info->{url} ); + + return $modobj; + } + } + + unless( $dist ) { + error( loc("%1 is not a proper distribution name!", $mod) ); + return; + } + + ### there's wonky uris out there, like this: + ### E/EY/EYCK/Net/Lite/Net-Lite-FTP-0.091 + ### compensate for that + my $author; + ### you probably have an A/AB/ABC/....../Dist.tgz type uri + if( (defined $parts[0] and length $parts[0] == 1) and + (defined $parts[1] and length $parts[1] == 2) and + $parts[2] =~ /^$parts[0]/i and $parts[2] =~ /^$parts[1]/i + ) { + splice @parts, 0, 2; # remove the first 2 entries from the list + $author = shift @parts; # this is the actual author name then + + ### we''ll assume a ABC/..../Dist.tgz + } else { + $author = shift @parts || ''; + } + + my($pkg, $version, $ext, $full) = + $self->_split_package_string( package => $dist ); + + ### translate a distribution into a module name ### + my $guess = $pkg; + $guess =~ s/-/::/g if $guess; + + my $maybe = $self->module_tree( $guess ); + if( IS_MODOBJ->( module => $maybe ) ) { + + ### maybe you asked for a package instead + if ( $maybe->package eq $mod ) { + return $maybe; + + ### perhaps an outdated version instead? + } elsif ( $version ) { + my $auth_obj; my $path; + + ### did you give us an author part? ### + if( $author ) { + $auth_obj = CPANPLUS::Module::Author::Fake->new( + _id => $maybe->_id, + cpanid => uc $author, + author => uc $author, + ); + $path = File::Spec::Unix->catdir( + $conf->_get_mirror('base'), + substr(uc $author, 0, 1), + substr(uc $author, 0, 2), + uc $author, + @parts, #possible sub dirs + ); + } else { + $auth_obj = $maybe->author; + $path = $maybe->path; + } + + if( $maybe->package_name eq $pkg ) { + + my $modobj = CPANPLUS::Module::Fake->new( + module => $maybe->module, + version => $version, + ### no extension? use the extension the original package + ### had instead + package => do { $ext + ? $full + : $full .'.'. $maybe->package_extension + }, + path => $path, + author => $auth_obj, + _id => $maybe->_id + ); + return $modobj; + + ### you asked for a specific version? + ### assume our $maybe is the one you wanted, + ### and fix up the version.. + } else { + + my $modobj = $maybe->clone; + $modobj->version( $version ); + $modobj->package( + $maybe->package_name .'-'. + $version .'.'. + $maybe->package_extension + ); + + ### you wanted a specific author, but it's not the one + ### from the module tree? we'll fix it up + if( $author and $author ne $modobj->author->cpanid ) { + $modobj->author( $auth_obj ); + $modobj->path( $path ); + } + + return $modobj; + } + + ### you didn't care about a version, so just return the object then + } elsif ( !$version ) { + return $maybe; + } + + ### ok, so we can't find it, and it's not an outdated dist either + ### perhaps we can fake one based on the author name and so on + } elsif ( $author and $version ) { + + ### be extra friendly and pad the .tar.gz suffix where needed + ### it's just a guess of course, but most dists are .tar.gz + $dist .= '.tar.gz' unless $dist =~ /\.[A-Za-z]+$/; + + ### XXX duplication from above for generating author obj + path... + my $modobj = CPANPLUS::Module::Fake->new( + module => $guess, + version => $version, + package => $dist, + author => CPANPLUS::Module::Author::Fake->new( + author => uc $author, + cpanid => uc $author, + _id => $self->_id, + ), + path => File::Spec::Unix->catdir( + $conf->_get_mirror('base'), + substr(uc $author, 0, 1), + substr(uc $author, 0, 2), + uc $author, + @parts, #possible subdirs + ), + _id => $self->_id, + ); + + return $modobj; + + ### face it, we have /no/ idea what he or she wants... + ### let's start putting the blame somewhere + } else { + + # Lets not give up too easily. There is one last chance + # http://perlmonks.org/?node_id=805957 + # This should catch edge-cases where the package name + # is unrelated to the modules it contains. + + my ($modobj) = grep { $_->package_name eq $mod } + $self->search( type => 'package', allow => [ qr/^\Q$mod\E/ ], ); + return $modobj if IS_MODOBJ->( module => $modobj ); + + unless( $author ) { + error( loc( "'%1' does not contain an author part", $mod ) ); + } + + error( loc( "Cannot find '%1' in the module tree", $mod ) ); + } + + return; +} + +=pod + +=head2 $bool = $cb->reload_indices( [update_source => BOOL, verbose => BOOL] ); + +This method reloads the source files. + +If C<update_source> is set to true, this will fetch new source files +from your CPAN mirror. Otherwise, C<reload_indices> will do its +usual cache checking and only update them if they are out of date. + +By default, C<update_source> will be false. + +The verbose setting defaults to what you have specified in your +config file. + +Returns true on success and false on failure. + +=cut + +sub reload_indices { + my $self = shift; + my %hash = @_; + my $conf = $self->configure_object; + + my $tmpl = { + update_source => { default => 0, allow => [qr/^\d$/] }, + verbose => { default => $conf->get_conf('verbose') }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + ### make a call to the internal _module_tree, so it triggers cache + ### file age + my $uptodate = $self->_check_trees( %$args ); + + + return 1 if $self->_build_trees( + uptodate => $uptodate, + use_stored => 0, + verbose => $conf->get_conf('verbose'), + ); + + error( loc( "Error rebuilding source trees!" ) ); + + return; +} + +=pod + +=head2 $bool = $cb->flush(CACHE_NAME) + +This method allows flushing of caches. +There are several things which can be flushed: + +=over 4 + +=item * C<methods> + +The return status of methods which have been attempted, such as +different ways of fetching files. It is recommended that automatic +flushing be used instead. + +=item * C<hosts> + +The return status of URIs which have been attempted, such as +different hosts of fetching files. It is recommended that automatic +flushing be used instead. + +=item * C<modules> + +Information about modules such as prerequisites and whether +installation succeeded, failed, or was not attempted. + +=item * C<lib> + +This resets PERL5LIB, which is changed to ensure that while installing +modules they are in our @INC. + +=item * C<load> + +This resets the cache of modules we've attempted to load, but failed. +This enables you to load them again after a failed load, if they +somehow have become available. + +=item * C<all> + +Flush all of the aforementioned caches. + +=back + +Returns true on success and false on failure. + +=cut + +sub flush { + my $self = shift; + my $type = shift or return; + + my $cache = { + methods => [ qw( methods load ) ], + hosts => [ qw( hosts ) ], + modules => [ qw( modules lib) ], + lib => [ qw( lib ) ], + load => [ qw( load ) ], + all => [ qw( hosts lib modules methods load ) ], + }; + + my $aref = $cache->{$type} + or ( + error( loc("No such cache '%1'", $type) ), + return + ); + + return $self->_flush( list => $aref ); +} + +=pod + +=head2 @mods = $cb->installed() + +Returns a list of module objects of all your installed modules. +If an error occurs, it will return false. + +See L<CPANPLUS::Module> for the operations you can perform on a +module object. + +=cut + +sub installed { + my $self = shift; + my $aref = $self->_all_installed; + + return @$aref if $aref; + return; +} + +=pod + +=head2 $bool = $cb->local_mirror([path => '/dir/to/save/to', index_files => BOOL, force => BOOL, verbose => BOOL] ) + +Creates a local mirror of CPAN, of only the most recent sources in a +location you specify. If you set this location equal to a custom host +in your C<CPANPLUS::Config> you can use your local mirror to install +from. + +It takes the following arguments: + +=over 4 + +=item path + +The location where to create the local mirror. + +=item index_files + +Enable/disable fetching of index files. You can disable fetching of the +index files if you don't plan to use the local mirror as your primary +site, or if you'd like up-to-date index files be fetched from elsewhere. + +Defaults to true. + +=item force + +Forces refetching of packages, even if they are there already. + +Defaults to whatever setting you have in your C<CPANPLUS::Config>. + +=item verbose + +Prints more messages about what its doing. + +Defaults to whatever setting you have in your C<CPANPLUS::Config>. + +=back + +Returns true on success and false on error. + +=cut + +sub local_mirror { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my($path, $index, $force, $verbose); + my $tmpl = { + path => { default => $conf->get_conf('base'), + store => \$path }, + index_files => { default => 1, store => \$index }, + force => { default => $conf->get_conf('force'), + store => \$force }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + }; + + check( $tmpl, \%hash ) or return; + + unless( -d $path ) { + $self->_mkdir( dir => $path ) + or( error( loc( "Could not create '%1', giving up", $path ) ), + return + ); + } elsif ( ! -w _ ) { + error( loc( "Could not write to '%1', giving up", $path ) ); + return; + } + + my $flag; + AUTHOR: { + for my $auth ( sort { $a->cpanid cmp $b->cpanid } + values %{$self->author_tree} + ) { + + MODULE: { + my $i; + for my $mod ( $auth->modules ) { + my $fetchdir = File::Spec->catdir( $path, $mod->path ); + + my %opts = ( + verbose => $verbose, + force => $force, + fetchdir => $fetchdir, + ); + + ### only do this the for the first module ### + unless( $i++ ) { + $mod->_get_checksums_file( + %opts + ) or ( + error( loc( "Could not fetch %1 file, " . + "skipping author '%2'", + CHECKSUMS, $auth->cpanid ) ), + $flag++, next AUTHOR + ); + } + + $mod->fetch( %opts ) + or( error( loc( "Could not fetch '%1'", $mod->module ) ), + $flag++, next MODULE + ); + } } + } } + + if( $index ) { + for my $name (qw[auth dslip mod]) { + $self->_update_source( + name => $name, + verbose => $verbose, + path => $path, + ) or ( $flag++, next ); + } + } + + return !$flag; +} + +=pod + +=head2 $file = $cb->autobundle([path => OUTPUT_PATH, force => BOOL, verbose => BOOL]) + +Writes out a snapshot of your current installation in C<CPAN> bundle +style. This can then be used to install the same modules for a +different or on a different machine by issuing the following commands: + + ### using the default shell: + CPAN Terminal> i file://path/to/Snapshot_XXYY.pm + + ### using the API + $modobj = $cb->parse_module( module => 'file://path/to/Snapshot_XXYY.pm' ); + $modobj->install; + +It will, by default, write to an 'autobundle' directory under your +cpanplus homedirectory, but you can override that by supplying a +C<path> argument. + +It will return the location of the output file on success and false on +failure. + +=cut + +sub autobundle { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my($path,$force,$verbose); + my $tmpl = { + force => { default => $conf->get_conf('force'), store => \$force }, + verbose => { default => $conf->get_conf('verbose'), store => \$verbose }, + path => { default => File::Spec->catdir( + $conf->get_conf('base'), + $self->_perl_version( perl => $^X ), + $conf->_get_build('distdir'), + $conf->_get_build('autobundle') ), + store => \$path }, + }; + + check($tmpl, \%hash) or return; + + unless( -d $path ) { + $self->_mkdir( dir => $path ) + or( error(loc("Could not create directory '%1'", $path ) ), + return + ); + } + + my $name; my $file; + { ### default filename for the bundle ### + my($year,$month,$day) = (localtime)[5,4,3]; + $year += 1900; $month++; + + my $ext = 0; + + my $prefix = $conf->_get_build('autobundle_prefix'); + my $format = "${prefix}_%04d_%02d_%02d_%02d"; + + BLOCK: { + $name = sprintf( $format, $year, $month, $day, $ext); + + $file = File::Spec->catfile( $path, $name . '.pm' ); + + -f $file ? ++$ext && redo BLOCK : last BLOCK; + } + } + my $fh; + unless( $fh = FileHandle->new( ">$file" ) ) { + error( loc( "Could not open '%1' for writing: %2", $file, $! ) ); + return; + } + + ### make sure we load the module tree *before* doing this, as it + ### starts to chdir all over the place + $self->module_tree; + + my $string = join "\n\n", + map { + join ' ', + $_->module, + ($_->installed_version(verbose => 0) || 'undef') + } sort { + $a->module cmp $b->module + } $self->installed; + + my $now = scalar localtime; + my $head = '=head1'; + my $pkg = __PACKAGE__; + my $version = $self->VERSION; + my $perl_v = join '', `$^X -V`; + + print $fh <<EOF; +package $name; + +\$VERSION = '0.01'; + +1; + +__END__ + +$head NAME + +$name - Snapshot of your installation at $now + +$head SYNOPSIS + +To install the modules from this snapshot, run: + + cpanp -i file://full/path/to/${name}.pm + +$head CONTENTS + +$string + +$head CONFIGURATION + +$perl_v + +$head AUTHOR + +This bundle has been generated autotomatically by + $pkg $version + +EOF + + close $fh; + + return $file; +} + +=head2 $bool = $cb->save_state + +Explicit command to save memory state to disk. This can be used to save +information to disk about where a module was extracted, the result of +C<make test>, etc. This will then be re-loaded into memory when a new +session starts. + +The capability of saving state to disk depends on the source engine +being used (See C<CPANPLUS::Config> for the option to choose your +source engine). The default storage engine supports this option. + +Most users will not need this command, but it can handy for automated +systems like setting up CPAN smoke testers. + +The method will return true if it managed to save the state to disk, +or false if it did not. + +=cut + +sub save_state { + my $self = shift; + return $self->_save_state( @_ ); +} + + +### XXX these wrappers are not individually tested! only the underlying +### code through source.t and indirectly trought he CustomSource plugin. +=pod + +=head1 CUSTOM MODULE SOURCES + +Besides the sources as provided by the general C<CPAN> mirrors, it's +possible to add your own sources list to your C<CPANPLUS> index. + +The methodology behind this works much like C<Debian's apt-sources>. + +The methods below show you how to make use of this functionality. Also +note that most of these methods are available through the default shell +plugin command C</cs>, making them available as shortcuts through the +shell and via the commandline. + +=head2 %files = $cb->list_custom_sources + +Returns a mapping of registered custom sources and their local indices +as follows: + + /full/path/to/local/index => http://remote/source + +Note that any file starting with an C<#> is being ignored. + +=cut + +sub list_custom_sources { + return shift->__list_custom_module_sources( @_ ); +} + +=head2 $local_index = $cb->add_custom_source( uri => URI, [verbose => BOOL] ); + +Adds an C<URI> to your own sources list and mirrors its index. See the +documentation on C<< $cb->update_custom_source >> on how this is done. + +Returns the full path to the local index on success, or false on failure. + +Note that when adding a new C<URI>, the change to the in-memory tree is +not saved until you rebuild or save the tree to disk again. You can do +this using the C<< $cb->reload_indices >> method. + +=cut + +sub add_custom_source { + return shift->_add_custom_module_source( @_ ); +} + +=head2 $local_index = $cb->remove_custom_source( uri => URI, [verbose => BOOL] ); + +Removes an C<URI> from your own sources list and removes its index. + +To find out what C<URI>s you have as part of your own sources list, use +the C<< $cb->list_custom_sources >> method. + +Returns the full path to the deleted local index file on success, or false +on failure. + +=cut + +### XXX do clever dispatching based on arg number? +sub remove_custom_source { + return shift->_remove_custom_module_source( @_ ); +} + +=head2 $bool = $cb->update_custom_source( [remote => URI] ); + +Updates the indexes for all your custom sources. It does this by fetching +a file called C<packages.txt> in the root of the custom sources's C<URI>. +If you provide the C<remote> argument, it will only update the index for +that specific C<URI>. + +Here's an example of how custom sources would resolve into index files: + + file:///path/to/sources => file:///path/to/sources/packages.txt + http://example.com/sources => http://example.com/sources/packages.txt + ftp://example.com/sources => ftp://example.com/sources/packages.txt + +The file C<packages.txt> simply holds a list of packages that can be found +under the root of the C<URI>. This file can be automatically generated for +you when the remote source is a C<file:// URI>. For C<http://>, C<ftp://>, +and similar, the administrator of that repository should run the method +C<< $cb->write_custom_source_index >> on the repository to allow remote +users to index it. + +For details, see the C<< $cb->write_custom_source_index >> method below. + +All packages that are added via this mechanism will be attributed to the +author with C<CPANID> C<LOCAL>. You can use this id to search for all +added packages. + +=cut + +sub update_custom_source { + my $self = shift; + + ### if it mentions /remote/, the request is to update a single uri, + ### not all the ones we have, so dispatch appropriately + my $rv = grep( /remote/i, @_) + ? $self->__update_custom_module_source( @_ ) + : $self->__update_custom_module_sources( @_ ); + + return $rv; +} + +=head2 $file = $cb->write_custom_source_index( path => /path/to/package/root, [to => /path/to/index/file, verbose => BOOL] ); + +Writes the index for a custom repository root. Most users will not have to +worry about this, but administrators of a repository will need to make sure +their indexes are up to date. + +The index will be written to a file called C<packages.txt> in your repository +root, which you can specify with the C<path> argument. You can override this +location by specifying the C<to> argument, but in normal operation, that should +not be required. + +Once the index file is written, users can then add the C<URI> pointing to +the repository to their custom list of sources and start using it right away. See the C<< $cb->add_custom_source >> method for user details. + +=cut + +sub write_custom_source_index { + return shift->__write_custom_module_index( @_ ); +} + +1; + +=pod + +=head1 BUG REPORTS + +Please report bugs or other issues to E<lt>bug-cpanplus@rt.cpan.org<gt>. + +=head1 AUTHOR + +This module by Jos Boumans E<lt>kane@cpan.orgE<gt>. + +=head1 COPYRIGHT + +The CPAN++ interface (of which this module is a part of) is copyright (c) +2001 - 2007, Jos Boumans E<lt>kane@cpan.orgE<gt>. All rights reserved. + +This library is free software; you may redistribute and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L<CPANPLUS::Configure>, L<CPANPLUS::Module>, L<CPANPLUS::Module::Author>, +L<CPANPLUS::Selfupdate> + +=cut + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: + +__END__ + +todo: +sub dist { # not sure about this one -- probably already done + enough in Module.pm +sub reports { # in Module.pm, wrapper here + + diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Backend/RV.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Backend/RV.pm new file mode 100644 index 00000000000..9edbe0452c9 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Backend/RV.pm @@ -0,0 +1,144 @@ +package CPANPLUS::Backend::RV; + +use strict; +use vars qw[$STRUCT]; + + +use CPANPLUS::Error; +use CPANPLUS::Internals::Constants; + +use IPC::Cmd qw[can_run run]; +use Params::Check qw[check]; + +use base 'Object::Accessor'; + +local $Params::Check::VERBOSE = 1; + + +=pod + +=head1 NAME + +CPANPLUS::Backend::RV + +=head1 SYNOPSIS + + ### create a CPANPLUS::Backend::RV object + $backend_rv = CPANPLUS::Backend::RV->new( + ok => $boolean, + args => $args, + rv => $return_value + function => $calling_function ); + + ### if you have a CPANPLUS::Backend::RV object + $passed_args = $backend_rv->args; # args passed to function + $ok = $backend_rv->ok; # boolean indication overall + # result of the call + $function = $backend_rv->fucntion # name of the calling + # function + $rv = $backend_rv->rv # the actual return value + # of the calling function + +=head1 DESCRIPTION + +This module provides return value objects for multi-module +calls to CPANPLUS::Backend. In boolean context, it returns the status +of the overall result (ie, the same as the C<ok> method would). + +=head1 METHODS + +=head2 new( ok => BOOL, args => DATA, rv => DATA, [function => $method_name] ) + +Creates a new CPANPLUS::Backend::RV object from the data provided. +This method should only be called by CPANPLUS::Backend functions. +The accessors may be used by users inspecting an RV object. + +All the argument names can be used as accessors later to retrieve the +data. + +Arguments: + +=over 4 + +=item ok + +Boolean indicating overall success + +=item args + +The arguments provided to the function that returned this rv object. +Useful to inspect later to see what was actually passed to the function +in case of an error. + +=item rv + +An arbitrary data structure that has the detailed return values of each +of your multi-module calls. + +=item function + +The name of the function that created this rv object. +Can be explicitly passed. If not, C<new()> will try to deduce the name +from C<caller()> information. + +=back + +=cut + +sub new { + my $class = shift; + my %hash = @_; + + my $tmpl = { + ok => { required => 1, allow => BOOLEANS }, + args => { required => 1 }, + rv => { required => 1 }, + function => { default => CALLING_FUNCTION->() }, + }; + + my $args = check( $tmpl, \%hash ) or return; + my $self = bless {}, $class; + +# $self->mk_accessors( qw[ok args function rv] ); + $self->mk_accessors( keys %$tmpl ); + + ### set the values passed in the struct ### + while( my($key,$val) = each %$args ) { + $self->$key( $val ); + } + + return $self; +} + +sub _ok { return shift->ok } +#sub _stringify { Carp::carp( "stringifying!" ); overload::StrVal( shift ) } + +### make it easier to check if($rv) { foo() } +### this allows people to not have to explicitly say +### if( $rv->ok ) { foo() } +### XXX add an explicit stringify, so it doesn't fall back to "bool"? :( +use overload bool => \&_ok, +# '""' => \&_stringify, + fallback => 1; + +=pod + +=head1 BUG REPORTS + +Please report bugs or other issues to E<lt>bug-cpanplus@rt.cpan.org<gt>. + +=head1 AUTHOR + +This module by Jos Boumans E<lt>kane@cpan.orgE<gt>. + +=head1 COPYRIGHT + +The CPAN++ interface (of which this module is a part of) is copyright (c) +2001 - 2007, Jos Boumans E<lt>kane@cpan.orgE<gt>. All rights reserved. + +This library is free software; you may redistribute and/or modify it +under the same terms as Perl itself. + +=cut + +1; diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Config.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Config.pm new file mode 100644 index 00000000000..740ef1e637f --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Config.pm @@ -0,0 +1,797 @@ +package CPANPLUS::Config; + +use strict; +use warnings; + +use base 'Object::Accessor'; + +use base 'CPANPLUS::Internals::Utils'; + +use Config; +use File::Spec; +use Module::Load; +use CPANPLUS; +use CPANPLUS::Error; +use CPANPLUS::Internals::Constants; + +use File::Basename qw[dirname]; +use IPC::Cmd qw[can_run]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; +use Module::Load::Conditional qw[check_install]; + + +=pod + +=head1 NAME + +CPANPLUS::Config + +=head1 SYNOPSIS + + ### conf object via CPANPLUS::Backend; + $cb = CPANPLUS::Backend->new; + $conf = $cb->configure_object; + + ### or as a standalone object + $conf = CPANPLUS::Configure->new; + + ### values in 'conf' section + $verbose = $conf->get_conf( 'verbose' ); + $conf->set_conf( verbose => 1 ); + + ### values in 'program' section + $editor = $conf->get_program( 'editor' ); + $conf->set_program( editor => '/bin/vi' ); + +=head1 DESCRIPTION + +This module contains defaults and heuristics for configuration +information for CPANPLUS. To change any of these values, please +see the documentation in C<CPANPLUS::Configure>. + +Below you'll find a list of configuration types and keys, and +their meaning. + +=head1 CONFIGURATION + +=cut + +### BAH! you can't have POD interleaved with a hash +### declaration.. so declare every entry seperatedly :( +my $Conf = { + '_fetch' => { + 'blacklist' => [ 'ftp' ], + }, + + ### _source, _build and _mirror are supposed to be static + ### no changes should be needed unless pause/cpan changes + '_source' => { + 'hosts' => 'MIRRORED.BY', + 'auth' => '01mailrc.txt.gz', + 'stored' => 'sourcefiles', + 'dslip' => '03modlist.data.gz', + 'update' => '86400', + 'mod' => '02packages.details.txt.gz', + 'custom_index' => 'packages.txt', + }, + '_build' => { + 'plugins' => 'plugins', + 'moddir' => 'build', + 'startdir' => '', + 'distdir' => 'dist', + 'autobundle' => 'autobundle', + 'autobundle_prefix' => 'Snapshot', + 'autdir' => 'authors', + 'install_log_dir' => 'install-logs', + 'custom_sources' => 'custom-sources', + 'sanity_check' => 1, + }, + '_mirror' => { + 'base' => 'authors/id/', + 'auth' => 'authors/01mailrc.txt.gz', + 'dslip' => 'modules/03modlist.data.gz', + 'mod' => 'modules/02packages.details.txt.gz' + }, +}; + +=head2 Section 'conf' + +=over 4 + +=item hosts + +An array ref containing hosts entries to be queried for packages. + +An example entry would like this: + + { 'scheme' => 'ftp', + 'path' => '/pub/CPAN/', + 'host' => 'ftp.cpan.org' + }, + +=cut + + ### default host list + $Conf->{'conf'}->{'hosts'} = [ + { + 'scheme' => 'ftp', + 'path' => '/pub/CPAN/', + 'host' => 'ftp.cpan.org' + }, + { + 'scheme' => 'http', + 'path' => '/', + 'host' => 'www.cpan.org' + }, + { + 'scheme' => 'ftp', + 'path' => '/pub/CPAN/', + 'host' => 'ftp.nl.uu.net' + }, + { + 'scheme' => 'ftp', + 'path' => '/pub/CPAN/', + 'host' => 'cpan.valueclick.com' + }, + { + 'scheme' => 'ftp', + 'path' => '/pub/languages/perl/CPAN/', + 'host' => 'ftp.funet.fi' + } + ]; + +=item allow_build_interactivity + +Boolean flag to indicate whether 'perl Makefile.PL' and similar +are run interactively or not. Defaults to 'true'. + +=cut + + $Conf->{'conf'}->{'allow_build_interactivity'} = 1; + +=item base + +The directory CPANPLUS keeps all its build and state information in. +Defaults to ~/.cpanplus. + +=cut + + $Conf->{'conf'}->{'base'} = File::Spec->catdir( + __PACKAGE__->_home_dir, DOT_CPANPLUS ); + +=item buildflags + +Any flags to be passed to 'perl Build.PL'. See C<perldoc Module::Build> +for details. Defaults to an empty string. + +=cut + + $Conf->{'conf'}->{'buildflags'} = ''; + +=item cpantest + +Boolean flag to indicate whether or not to mail test results of module +installations to C<http://testers.cpan.org>. Defaults to 'false'. + +=cut + + $Conf->{'conf'}->{'cpantest'} = 0; + +=item cpantest_mx + +String holding an explicit mailserver to use when sending out emails +for C<http://testers.cpan.org>. An empty string will use your system +settings. Defaults to an empty string. + +=cut + + $Conf->{'conf'}->{'cpantest_mx'} = ''; + +=item debug + +Boolean flag to enable or disable extensive debuggging information. +Defaults to 'false'. + +=cut + + $Conf->{'conf'}->{'debug'} = 0; + +=item dist_type + +Default distribution type to use when building packages. See C<cpan2dist> +or C<CPANPLUS::Dist> for details. An empty string will not use any +package building software. Defaults to an empty string. + +=cut + + $Conf->{'conf'}->{'dist_type'} = ''; + +=item email + +Email address to use for anonymous ftp access and as C<from> address +when sending emails. Defaults to an C<example.com> address. + +=cut + + $Conf->{'conf'}->{'email'} = DEFAULT_EMAIL; + +=item enable_custom_sources + +Boolean flag indicating whether custom sources should be enabled or +not. See the C<CUSTOM MODULE SOURCES> in C<CPANPLUS::Backend> for +details on how to use them. + +Defaults to C<true> + +=cut + + ### this addresses #32248 which requests a possibillity to + ### turn off custom sources + $Conf->{'conf'}->{'enable_custom_sources'} = 1; + +=item extractdir + +String containing the directory where fetched archives should be +extracted. An empty string will use a directory under your C<base> +directory. Defaults to an empty string. + +=cut + + $Conf->{'conf'}->{'extractdir'} = ''; + +=item fetchdir + +String containing the directory where fetched archives should be +stored. An empty string will use a directory under your C<base> +directory. Defaults to an empty string. + +=cut + + $Conf->{'conf'}->{'fetchdir'} = ''; + +=item flush + +Boolean indicating whether build failures, cache dirs etc should +be flushed after every operation or not. Defaults to 'true'. + +=cut + + $Conf->{'conf'}->{'flush'} = 1; + +=item force + +Boolean indicating whether files should be forcefully overwritten +if they exist, modules should be installed when they fail tests, +etc. Defaults to 'false'. + +=cut + + $Conf->{'conf'}->{'force'} = 0; + +=item lib + +An array ref holding directories to be added to C<@INC> when CPANPLUS +starts up. Defaults to an empty array reference. + +=cut + + $Conf->{'conf'}->{'lib'} = []; + +=item makeflags + +A string holding flags that will be passed to the C<make> program +when invoked. Defaults to an empty string. + +=cut + + $Conf->{'conf'}->{'makeflags'} = ''; + +=item makemakerflags + +A string holding flags that will be passed to C<perl Makefile.PL> +when invoked. Defaults to an empty string. + +=cut + + $Conf->{'conf'}->{'makemakerflags'} = ''; + +=item md5 + +A boolean indicating whether or not md5 checks should be done when +an archive is fetched. Defaults to 'true' if you have C<Digest::MD5> +installed, 'false' otherwise. + +=cut + + $Conf->{'conf'}->{'md5'} = ( + check_install( module => 'Digest::MD5' ) ? 1 : 0 ); + +=item no_update + +A boolean indicating whether or not C<CPANPLUS>' source files should be +updated or not. Defaults to 'false'. + +=cut + + $Conf->{'conf'}->{'no_update'} = 0; + +=item passive + +A boolean indicating whether or not to use passive ftp connections. +Defaults to 'true'. + +=cut + + $Conf->{'conf'}->{'passive'} = 1; + +=item prefer_bin + +A boolean indicating whether or not to prefer command line programs +over perl modules. Defaults to 'false' unless you do not have +C<Compress::Zlib> installed (as that would mean we could not extract +C<.tar.gz> files) + +=cut + ### if we dont have c::zlib, we'll need to use /bin/tar or we + ### can not extract any files. Good time to change the default + $Conf->{'conf'}->{'prefer_bin'} = + (eval {require Compress::Zlib; 1} ? 0 : 1 ); + +=item prefer_makefile + +A boolean indicating whether or not prefer a C<Makefile.PL> over a +C<Build.PL> file if both are present. Defaults to 'true', unless +the perl version is at least 5.10.1 or appropriate versions of L<Module::Build> +and L<CPANPLUS::Dist::Build> are available. + +=cut + + $Conf->{'conf'}->{'prefer_makefile'} = + ( $] >= 5.010001 or + ( check_install( module => 'Module::Build', version => '0.32' ) and + check_install( module => INSTALLER_BUILD, version => '0.24' ) ) + ? 0 : 1 ); + +=item prereqs + +A digit indicating what to do when a package you are installing has a +prerequisite. Options are: + + 0 Do not install + 1 Install + 2 Ask + 3 Ignore (dangerous, install will probably fail!) + +The default is to ask. + +=cut + + $Conf->{'conf'}->{'prereqs'} = PREREQ_ASK; + +=item shell + +A string holding the shell class you wish to start up when starting +C<CPANPLUS> in interactive mode. + +Defaults to C<CPANPLUS::Shell::Default>, the default CPANPLUS shell. + +=cut + + $Conf->{'conf'}->{'shell'} = 'CPANPLUS::Shell::Default'; + +=item show_startup_tip + +A boolean indicating whether or not to show start up tips in the +interactive shell. Defaults to 'true'. + +=cut + + $Conf->{'conf'}->{'show_startup_tip'} = 1; + +=item signature + +A boolean indicating whether or not check signatures if packages are +signed. Defaults to 'true' if you have C<gpg> or C<Crypt::OpenPGP> +installed, 'false' otherwise. + +=cut + + $Conf->{'conf'}->{'signature'} = do { + check_install( module => 'Module::Signature', version => '0.06' ) + and ( can_run('gpg') || + check_install(module => 'Crypt::OpenPGP') + ); + } ? 1 : 0; + +=item skiptest + +A boolean indicating whether or not to skip tests when installing modules. +Defaults to 'false'. + +=cut + + $Conf->{'conf'}->{'skiptest'} = 0; + +=item storable + +A boolean indicating whether or not to use C<Storable> to write compiled +source file information to disk. This makes for faster startup and look +up times, but takes extra diskspace. Defaults to 'true' if you have +C<Storable> installed and 'false' if you don't. + +=cut + + $Conf->{'conf'}->{'storable'} = + ( check_install( module => 'Storable' ) ? 1 : 0 ); + +=item timeout + +Digit indicating the time before a fetch request times out (in seconds). +Defaults to 300. + +=cut + + $Conf->{'conf'}->{'timeout'} = 300; + +=item verbose + +A boolean indicating whether or not C<CPANPLUS> runs in verbose mode. +Defaults to 'true' if you have the environment variable +C<PERL5_CPANPLUS_VERBOSE> set to true, 'false' otherwise. + +It is recommended you run with verbose enabled, but it is disabled +for historical reasons. + +=cut + + $Conf->{'conf'}->{'verbose'} = $ENV{PERL5_CPANPLUS_VERBOSE} || 0; + +=item write_install_log + +A boolean indicating whether or not to write install logs after installing +a module using the interactive shell. Defaults to 'true'. + + +=cut + + $Conf->{'conf'}->{'write_install_logs'} = 1; + +=item source_engine + +Class to use as the source engine, which is generally a subclass of +C<CPANPLUS::Internals::Source>. Default to C<CPANPLUS::Internals::Source::Memory>. + +=cut + + $Conf->{'conf'}->{'source_engine'} = DEFAULT_SOURCE_ENGINE; + +=item cpantest_reporter_args + +A hashref of key => value pairs that are passed to the constructor +of C<Test::Reporter>. If you'd want to enable TLS for example, you'd +set it to: + + { transport => 'Net::SMTP::TLS', + transport_args => [ User => 'Joe', Password => '123' ], + } + +=cut + + $Conf->{'conf'}->{'cpantest_reporter_args'} = {}; + +=back + +=head2 Section 'program' + +=cut + + ### Paths get stripped of whitespace on win32 in the constructor + ### sudo gets emptied if there's no need for it in the constructor + +=over 4 + +=item editor + +A string holding the path to your editor of choice. Defaults to your +$ENV{EDITOR}, $ENV{VISUAL}, 'vi' or 'pico' programs, in that order. + +=cut + + $Conf->{'program'}->{'editor'} = do { + $ENV{'EDITOR'} || $ENV{'VISUAL'} || + can_run('vi') || can_run('pico') + }; + +=item make + +A string holding the path to your C<make> binary. Looks for the C<make> +program used to build perl or failing that, a C<make> in your path. + +=cut + + $Conf->{'program'}->{'make'} = + can_run($Config{'make'}) || can_run('make'); + +=item pager + +A string holding the path to your pager of choice. Defaults to your +$ENV{PAGER}, 'less' or 'more' programs, in that order. + +=cut + + $Conf->{'program'}->{'pager'} = + $ENV{'PAGER'} || can_run('less') || can_run('more'); + + ### no one uses this feature anyway, and it's only working for EU::MM + ### and not for module::build + #'perl' => '', + +=item shell + +A string holding the path to your login shell of choice. Defaults to your +$ENV{SHELL} setting, or $ENV{COMSPEC} on Windows. + +=cut + + $Conf->{'program'}->{'shell'} = $^O eq 'MSWin32' + ? $ENV{COMSPEC} + : $ENV{SHELL}; + +=item sudo + +A string holding the path to your C<sudo> binary if your install path +requires super user permissions. Looks for C<sudo> in your path, or +remains empty if you do not require super user permissions to install. + +=cut + + $Conf->{'program'}->{'sudo'} = do { + ### let's assume you dont need sudo, + ### unless one of the below criteria tells us otherwise + my $sudo = undef; + + ### you're a normal user, you might need sudo + if( $> ) { + + ### check for all install dirs! + ### you have write permissions to the installdir, + ### you don't need sudo + if( -w $Config{'installsitelib'} && -w $Config{'installsitebin'} ) { + + ### installsiteman3dir is a 5.8'ism.. don't check + ### it on 5.6.x... + if( defined $Config{'installsiteman3dir'} ) { + $sudo = -w $Config{'installsiteman3dir'} + ? undef + : can_run('sudo'); + } else { + $sudo = undef; + } + + ### you have PERL_MM_OPT set to some alternate + ### install place. You probably have write permissions + ### to that + } elsif ( $ENV{'PERL_MM_OPT'} and + $ENV{'PERL_MM_OPT'} =~ /INSTALL|LIB|PREFIX/ + ) { + $sudo = undef; + + ### you probably don't have write permissions + } else { + $sudo = can_run('sudo'); + } + } + + ### and return the value + $sudo; + }; + +=item perlwrapper + +A string holding the path to the C<cpanp-run-perl> utility bundled +with CPANPLUS, which is used to enable autoflushing in spawned processes. + +=cut + + ### perlwrapper that allows us to turn on autoflushing + $Conf->{'program'}->{'perlwrapper'} = sub { + my $name = 'cpanp-run-perl'; + + my @bins = do{ + require Config; + my $ver = $Config::Config{version}; + + ### if we are running with 'versiononly' enabled, + ### all binaries will have the perlversion appended + ### ie, cpanp will become cpanp5.9.5 + ### so prefer the versioned binary in that case + $Config::Config{versiononly} + ? ($name.$ver, $name) + : ($name, $name.$ver); + }; + + ### patch from Steve Hay Fri 29 Jun 2007 14:26:02 GMT+02:00 + ### Msg-Id: <4684FA5A.7030506@uk.radan.com> + ### look for files with a ".bat" extension as well on Win32 + @bins = map { $_, "$_.bat" } @bins if $^O eq 'MSWin32'; + + my $path; + BIN: for my $bin (@bins) { + + ### parallel to your cpanp/cpanp-boxed + my $maybe = File::Spec->rel2abs( + File::Spec->catfile( dirname($0), $bin ) + ); + $path = $maybe and last BIN if -f $maybe; + + ### parallel to your CPANPLUS.pm: + ### $INC{cpanplus}/../bin/cpanp-run-perl + $maybe = File::Spec->rel2abs( + File::Spec->catfile( + dirname($INC{'CPANPLUS.pm'}), + '..', # lib dir + 'bin', # bin dir + $bin, # script + ) + ); + $path = $maybe and last BIN if -f $maybe; + + ### you installed CPANPLUS in a custom prefix, + ### so go paralel to /that/. PREFIX=/tmp/cp + ### would put cpanp-run-perl in /tmp/cp/bin and + ### CPANPLUS.pm in + ### /tmp/cp/lib/perl5/site_perl/5.8.8 + $maybe = File::Spec->rel2abs( + File::Spec->catfile( + dirname( $INC{'CPANPLUS.pm'} ), + '..', '..', '..', '..', # 4x updir + 'bin', # bin dir + $bin, # script + ) + ); + $path = $maybe and last BIN if -f $maybe; + + ### in your path -- take this one last, the + ### previous two assume extracted tarballs + ### or user installs + ### note that we don't use 'can_run' as it's + ### not an executable, just a wrapper... + ### prefer anything that's found in the path paralel to your $^X + for my $dir (File::Spec->rel2abs( dirname($^X) ), + split(/\Q$Config::Config{path_sep}\E/, $ENV{PATH}), + File::Spec->curdir, + ) { + + ### On VMS the path could be in UNIX format, and we + ### currently need it to be in VMS format + $dir = VMS::Filespec::vmspath($dir) if ON_VMS; + + $maybe = File::Spec->catfile( $dir, $bin ); + $path = $maybe and last BIN if -f $maybe; + } + } + + ### we should have a $path by now ideally, if so return it + return $path if defined $path; + + ### if not, warn about it and give sensible default. + ### XXX try to be a no-op instead then.. + ### cross your fingers... + ### pass '-P' to perl: "run program through C + ### preprocessor before compilation" + ### XXX using -P actually changes the way some Makefile.PLs + ### are executed, so don't do that... --kane + error(loc( + "Could not find the '%1' binary in your path". + "--this may be a problem.\n". + "Please locate this program and set ". + "your '%2' config entry to its path.\n". + "From the default shell, you can do this by typing:\n\n". + " %3\n". + " %4\n", + $name, 'perlwrapper', + 's program perlwrapper FULL_PATH_TO_CPANP_RUN_PERL', + 's save' + )); + return ''; + }->(); + +=back + +=cut + +sub new { + my $class = shift; + my $obj = $class->SUPER::new; + + $obj->mk_accessors( keys %$Conf ); + + for my $acc ( keys %$Conf ) { + my $subobj = Object::Accessor->new; + $subobj->mk_accessors( keys %{$Conf->{$acc}} ); + + ### read in all the settings from the sub accessors; + for my $subacc ( $subobj->ls_accessors ) { + $subobj->$subacc( $Conf->{$acc}->{$subacc} ); + } + + ### now store it in the parent object + $obj->$acc( $subobj ); + } + + $obj->_clean_up_paths; + + ### shut up IPC::Cmd warning about not findin IPC::Run on win32 + $IPC::Cmd::WARN = 0; + + return $obj; +} + +sub _clean_up_paths { + my $self = shift; + + ### clean up paths if we are on win32 + if( $^O eq 'MSWin32' ) { + for my $pgm ( $self->program->ls_accessors ) { + my $path = $self->program->$pgm; + + ### paths with whitespace needs to be shortened + ### for shell outs. + if ($path and $path =~ /\s+/) { + my($prog, $args); + + ### patch from Steve Hay, 13nd of June 2007 + ### msg-id: <467012A4.6060705@uk.radan.com> + ### windows directories are not allowed to end with + ### a space, so any occurrence of '\w\s+/\w+' means + ### we're dealing with arguments, not directory + ### names. + if ($path =~ /^(.*?)(\s+\/.*$)/) { + ($prog, $args) = ($1, $2); + + ### otherwise, there are no arguments + } else { + ($prog, $args) = ($path, ''); + } + + $prog = Win32::GetShortPathName( $prog ); + $self->program->$pgm( $prog . $args ); + } + } + } + + return 1; +} + +1; + +=pod + +=head1 BUG REPORTS + +Please report bugs or other issues to E<lt>bug-cpanplus@rt.cpan.org<gt>. + +=head1 AUTHOR + +This module by Jos Boumans E<lt>kane@cpan.orgE<gt>. + +=head1 COPYRIGHT + +The CPAN++ interface (of which this module is a part of) is copyright (c) +2001 - 2007, Jos Boumans E<lt>kane@cpan.orgE<gt>. All rights reserved. + +This library is free software; you may redistribute and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L<CPANPLUS::Backend>, L<CPANPLUS::Configure::Setup>, L<CPANPLUS::Configure> + +=cut + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Configure.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Configure.pm new file mode 100644 index 00000000000..baac91dc886 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Configure.pm @@ -0,0 +1,630 @@ +package CPANPLUS::Configure; +use strict; + + +use CPANPLUS::Internals::Constants; +use CPANPLUS::Error; +use CPANPLUS::Config; + +use Log::Message; +use Module::Load qw[load]; +use Params::Check qw[check]; +use File::Basename qw[dirname]; +use Module::Loaded (); +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +use vars qw[$AUTOLOAD $VERSION $MIN_CONFIG_VERSION]; +use base qw[CPANPLUS::Internals::Utils]; + +local $Params::Check::VERBOSE = 1; + +### require, avoid circular use ### +require CPANPLUS::Internals; +$VERSION = $CPANPLUS::Internals::VERSION = $CPANPLUS::Internals::VERSION; + +### can't use O::A as we're using our own AUTOLOAD to get to +### the config options. +for my $meth ( qw[conf _lib _perl5lib]) { + no strict 'refs'; + + *$meth = sub { + my $self = shift; + $self->{'_'.$meth} = $_[0] if @_; + return $self->{'_'.$meth}; + } +} + + +=pod + +=head1 NAME + +CPANPLUS::Configure + +=head1 SYNOPSIS + + $conf = CPANPLUS::Configure->new( ); + + $bool = $conf->can_save; + $bool = $conf->save( $where ); + + @opts = $conf->options( $type ); + + $make = $conf->get_program('make'); + $verbose = $conf->set_conf( verbose => 1 ); + +=head1 DESCRIPTION + +This module deals with all the configuration issues for CPANPLUS. +Users can use objects created by this module to alter the behaviour +of CPANPLUS. + +Please refer to the C<CPANPLUS::Backend> documentation on how to +obtain a C<CPANPLUS::Configure> object. + +=head1 METHODS + +=head2 $Configure = CPANPLUS::Configure->new( load_configs => BOOL ) + +This method returns a new object. Normal users will never need to +invoke the C<new> method, but instead retrieve the desired object via +a method call on a C<CPANPLUS::Backend> object. + +=item load_configs + +Controls whether or not additional user configurations are to be loaded +or not. Defaults to C<true>. + +=cut + +### store teh CPANPLUS::Config object in a closure, so we only +### initialize it once.. otherwise, on a 2nd ->new, settings +### from configs on top of this one will be reset +{ my $Config; + + sub new { + my $class = shift; + my %hash = @_; + + ### XXX pass on options to ->init() like rescan? + my ($load); + my $tmpl = { + load_configs => { default => 1, store => \$load }, + }; + + check( $tmpl, \%hash ) or ( + warn Params::Check->last_error, return + ); + + $Config ||= CPANPLUS::Config->new; + my $self = bless {}, $class; + $self->conf( $Config ); + + ### you want us to load other configs? + ### these can override things in the default config + $self->init if $load; + + ### after processing the config files, check what + ### @INC and PERL5LIB are set to. + $self->_lib( \@INC ); + $self->_perl5lib( $ENV{'PERL5LIB'} ); + + return $self; + } +} + +=head2 $bool = $Configure->init( [rescan => BOOL]) + +Initialize the configure with other config files than just +the default 'CPANPLUS::Config'. + +Called from C<new()> to load user/system configurations + +If the C<rescan> option is provided, your disk will be +examined again to see if there are new config files that +could be read. Defaults to C<false>. + +Returns true on success, false on failure. + +=cut + +### move the Module::Pluggable detection to runtime, rather +### than compile time, so that a simple 'require CPANPLUS' +### doesn't start running over your filesystem for no good +### reason. Make sure we only do the M::P call once though. +### we use $loaded to mark it +{ my $loaded; + my $warned; + sub init { + my $self = shift; + my $obj = $self->conf; + my %hash = @_; + + my ($rescan); + my $tmpl = { + rescan => { default => 0, store => \$rescan }, + }; + + check( $tmpl, \%hash ) or ( + warn Params::Check->last_error, return + ); + + ### if the base dir is changed, we have to rescan it + ### for any CPANPLUS::Config::* files as well, so keep + ### track of it + my $cur_base = $self->get_conf('base'); + + ### warn if we find an old style config specified + ### via environment variables + { my $env = ENV_CPANPLUS_CONFIG; + if( $ENV{$env} and not $warned ) { + $warned++; + error(loc("Specifying a config file in your environment " . + "using %1 is obsolete.\nPlease follow the ". + "directions outlined in %2 or use the '%3' command\n". + "in the default shell to use custom config files.", + $env, "CPANPLUS::Configure->save", 's save')); + } + } + + { ### make sure that the homedir is included now + local @INC = ( LIB_DIR->($cur_base), @INC ); + + ### only set it up once + if( !$loaded++ or $rescan ) { + ### find plugins & extra configs + ### check $home/.cpanplus/lib as well + require Module::Pluggable; + + Module::Pluggable->import( + search_path => ['CPANPLUS::Config'], + search_dirs => [ LIB_DIR->($cur_base) ], + except => qr/::SUPER$/, + sub_name => 'configs' + ); + } + + + ### do system config, user config, rest.. in that order + ### apparently, on a 2nd invocation of -->configs, a + ### ::ISA::CACHE package can appear.. that's bad... + my %confs = map { $_ => $_ } + grep { $_ !~ /::ISA::/ } __PACKAGE__->configs; + my @confs = grep { defined } + map { delete $confs{$_} } CONFIG_SYSTEM, CONFIG_USER; + push @confs, sort keys %confs; + + for my $plugin ( @confs ) { + msg(loc("Found config '%1'", $plugin),0); + + ### if we already did this the /last/ time around dont + ### run the setup agian. + if( my $loc = Module::Loaded::is_loaded( $plugin ) ) { + msg(loc(" Already loaded '%1' (%2)", $plugin, $loc), 0); + next; + } else { + msg(loc(" Loading config '%1'", $plugin),0); + + if( eval { load $plugin; 1 } ) { + msg(loc(" Loaded '%1' (%2)", + $plugin, Module::Loaded::is_loaded( $plugin ) ), 0); + } else { + error(loc(" Error loading '%1': %2", $plugin, $@)); + } + } + + if( $@ ) { + error(loc("Could not load '%1': %2", $plugin, $@)); + next; + } + + my $sub = $plugin->can('setup'); + $sub->( $self ) if $sub; + } + } + + ### did one of the plugins change the base dir? then we should + ### scan the dirs again + if( $cur_base ne $self->get_conf('base') ) { + msg(loc("Base dir changed from '%1' to '%2', rescanning", + $cur_base, $self->get_conf('base')), 0); + $self->init( @_, rescan => 1 ); + } + + ### clean up the paths once more, just in case + $obj->_clean_up_paths; + + ### XXX in case the 'lib' param got changed, we need to + ### add that now, or it's not propagating ;( + { my $lib = $self->get_conf('lib'); + my %inc = map { $_ => $_ } @INC; + for my $l ( @$lib ) { + push @INC, $l unless $inc{$l}; + } + $self->_lib( \@INC ); + } + + return 1; + } +} +=pod + +=head2 can_save( [$config_location] ) + +Check if we can save the configuration to the specified file. +If no file is provided, defaults to your personal config. + +Returns true if the file can be saved, false otherwise. + +=cut + +sub can_save { + my $self = shift; + my $file = shift || CONFIG_USER_FILE->(); + + return 1 unless -e $file; + + chmod 0644, $file; + return (-w $file); +} + +=pod + +=head2 $file = $conf->save( [$package_name] ) + +Saves the configuration to the package name you provided. +If this package is not C<CPANPLUS::Config::System>, it will +be saved in your C<.cpanplus> directory, otherwise it will +be attempted to be saved in the system wide directory. + +If no argument is provided, it will default to your personal +config. + +Returns the full path to the file if the config was saved, +false otherwise. + +=cut + +sub _config_pm_to_file { + my $self = shift; + my $pm = shift or return; + my $dir = shift || CONFIG_USER_LIB_DIR->(); + + ### only 3 types of files know: home, system and 'other' + ### so figure out where to save them based on their type + my $file; + if( $pm eq CONFIG_USER ) { + $file = CONFIG_USER_FILE->(); + + } elsif ( $pm eq CONFIG_SYSTEM ) { + $file = CONFIG_SYSTEM_FILE->(); + + ### third party file + } else { + my $cfg_pkg = CONFIG . '::'; + unless( $pm =~ /^$cfg_pkg/ ) { + error(loc( + "WARNING: Your config package '%1' is not in the '%2' ". + "namespace and will not be automatically detected by %3", + $pm, $cfg_pkg, 'CPANPLUS' + )); + } + + $file = File::Spec->catfile( + $dir, + split( '::', $pm ) + ) . '.pm'; + } + + return $file; +} + + +sub save { + my $self = shift; + my $pm = shift || CONFIG_USER; + my $savedir = shift || ''; + + my $file = $self->_config_pm_to_file( $pm, $savedir ) or return; + my $dir = dirname( $file ); + + unless( -d $dir ) { + $self->_mkdir( dir => $dir ) or ( + error(loc("Can not create directory '%1' to save config to",$dir)), + return + ) + } + return unless $self->can_save($file); + + ### find only accesors that are not private + my @acc = sort grep { $_ !~ /^_/ } $self->conf->ls_accessors; + + ### for dumping the values + use Data::Dumper; + + my @lines; + for my $acc ( @acc ) { + + push @lines, "### $acc section", $/; + + for my $key ( $self->conf->$acc->ls_accessors ) { + my $val = Dumper( $self->conf->$acc->$key ); + + $val =~ s/\$VAR1\s+=\s+//; + $val =~ s/;\n//; + + push @lines, '$'. "conf->set_${acc}( $key => $val );", $/; + } + push @lines, $/,$/; + + } + + my $str = join '', map { " $_" } @lines; + + ### use a variable to make sure the pod parser doesn't snag it + my $is = '='; + my $time = gmtime; + + + my $msg = <<_END_OF_CONFIG_; +############################################### +### +### Configuration structure for $pm +### +############################################### + +#last changed: $time GMT + +### minimal pod, so you can find it with perldoc -l, etc +${is}pod + +${is}head1 NAME + +$pm + +${is}head1 DESCRIPTION + +This is a CPANPLUS configuration file. Editing this +config changes the way CPANPLUS will behave + +${is}cut + +package $pm; + +use strict; + +sub setup { + my \$conf = shift; + +$str + + return 1; +} + +1; + +_END_OF_CONFIG_ + + $self->_move( file => $file, to => "$file~" ) if -f $file; + + my $fh = new FileHandle; + $fh->open(">$file") + or (error(loc("Could not open '%1' for writing: %2", $file, $!)), + return ); + + $fh->print($msg); + $fh->close; + + return $file; +} + +=pod + +=head2 options( type => TYPE ) + +Returns a list of all valid config options given a specific type +(like for example C<conf> of C<program>) or false if the type does +not exist + +=cut + +sub options { + my $self = shift; + my $conf = $self->conf; + my %hash = @_; + + my $type; + my $tmpl = { + type => { required => 1, default => '', + strict_type => 1, store => \$type }, + }; + + check($tmpl, \%hash) or return; + + my %seen; + return sort grep { !$seen{$_}++ } + map { $_->$type->ls_accessors if $_->can($type) } + $self->conf; + return; +} + +=pod + +=head1 ACCESSORS + +Accessors that start with a C<_> are marked private -- regular users +should never need to use these. + +See the C<CPANPLUS::Config> documentation for what items can be +set and retrieved. + +=head2 get_SOMETHING( ITEM, [ITEM, ITEM, ... ] ); + +The C<get_*> style accessors merely retrieves one or more desired +config options. + +=head2 set_SOMETHING( ITEM => VAL, [ITEM => VAL, ITEM => VAL, ... ] ); + +The C<set_*> style accessors set the current value for one +or more config options and will return true upon success, false on +failure. + +=head2 add_SOMETHING( ITEM => VAL, [ITEM => VAL, ITEM => VAL, ... ] ); + +The C<add_*> style accessor adds a new key to a config key. + +Currently, the following accessors exist: + +=over 4 + +=item set|get_conf + +Simple configuration directives like verbosity and favourite shell. + +=item set|get_program + +Location of helper programs. + +=item _set|_get_build + +Locations of where to put what files for CPANPLUS. + +=item _set|_get_source + +Locations and names of source files locally. + +=item _set|_get_mirror + +Locations and names of source files remotely. + +=item _set|_get_fetch + +Special settings pertaining to the fetching of files. + +=back + +=cut + +sub AUTOLOAD { + my $self = shift; + my $conf = $self->conf; + + my $name = $AUTOLOAD; + $name =~ s/.+:://; + + my ($private, $action, $field) = + $name =~ m/^(_)?((?:[gs]et|add))_([a-z]+)$/; + + my $type = ''; + $type .= '_' if $private; + $type .= $field if $field; + + unless ( $conf->can($type) ) { + error( loc("Invalid method type: '%1'", $name) ); + return; + } + + unless( scalar @_ ) { + error( loc("No arguments provided!") ); + return; + } + + ### retrieve a current value for an existing key ### + if( $action eq 'get' ) { + for my $key (@_) { + my @list = (); + + ### get it from the user config first + if( $conf->can($type) and $conf->$type->can($key) ) { + push @list, $conf->$type->$key; + + ### XXX EU::AI compatibility hack to provide lookups like in + ### cpanplus 0.04x; we renamed ->_get_build('base') to + ### ->get_conf('base') + } elsif ( $type eq '_build' and $key eq 'base' ) { + return $self->get_conf($key); + + } else { + error( loc(q[No such key '%1' in field '%2'], $key, $type) ); + return; + } + + return wantarray ? @list : $list[0]; + } + + ### set an existing key to a new value ### + } elsif ( $action eq 'set' ) { + my %args = @_; + + while( my($key,$val) = each %args ) { + + if( $conf->can($type) and $conf->$type->can($key) ) { + $conf->$type->$key( $val ); + + } else { + error( loc(q[No such key '%1' in field '%2'], $key, $type) ); + return; + } + } + + return 1; + + ### add a new key to the config ### + } elsif ( $action eq 'add' ) { + my %args = @_; + + while( my($key,$val) = each %args ) { + + if( $conf->$type->can($key) ) { + error( loc( q[Key '%1' already exists for field '%2'], + $key, $type)); + return; + } else { + $conf->$type->mk_accessors( $key ); + $conf->$type->$key( $val ); + } + } + return 1; + + } else { + + error( loc(q[Unknown action '%1'], $action) ); + return; + } +} + +sub DESTROY { 1 }; + +1; + +=pod + +=head1 BUG REPORTS + +Please report bugs or other issues to E<lt>bug-cpanplus@rt.cpan.org<gt>. + +=head1 AUTHOR + +This module by Jos Boumans E<lt>kane@cpan.orgE<gt>. + +=head1 COPYRIGHT + +The CPAN++ interface (of which this module is a part of) is copyright (c) +2001 - 2007, Jos Boumans E<lt>kane@cpan.orgE<gt>. All rights reserved. + +This library is free software; you may redistribute and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L<CPANPLUS::Backend>, L<CPANPLUS::Configure::Setup>, L<CPANPLUS::Config> + +=cut + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: + diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Configure/Setup.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Configure/Setup.pm new file mode 100644 index 00000000000..3bcf8f45090 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Configure/Setup.pm @@ -0,0 +1,1653 @@ +package CPANPLUS::Configure::Setup; + +use strict; +use vars qw(@ISA); + +use base qw[CPANPLUS::Internals::Utils]; +use base qw[Object::Accessor]; + +use Config; +use Term::UI; +use Module::Load; +use Term::ReadLine; + + +use CPANPLUS::Internals::Utils; +use CPANPLUS::Internals::Constants; +use CPANPLUS::Error; + +use IPC::Cmd qw[can_run]; +use Params::Check qw[check]; +use Module::Load::Conditional qw[check_install]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +### silence Term::UI +$Term::UI::VERBOSE = 0; + +#Can't ioctl TIOCGETP: Unknown error +#Consider installing Term::ReadKey from CPAN site nearby +# at http://www.perl.com/CPAN +#Or use +# perl -MCPAN -e shell +#to reach CPAN. Falling back to 'stty'. +# If you do not want to see this warning, set PERL_READLINE_NOWARN +#in your environment. +#'stty' is not recognized as an internal or external command, +#operable program or batch file. +#Cannot call `stty': No such file or directory at C:/Perl/site/lib/Term/ReadLine/ + +### setting this var in the meantime to avoid this warning ### +$ENV{PERL_READLINE_NOWARN} = 1; + + +sub new { + my $class = shift; + my %hash = @_; + + my $tmpl = { + configure_object => { }, + term => { }, + backend => { }, + autoreply => { default => 0, }, + skip_mirrors => { default => 0, }, + use_previous => { default => 1, }, + config_type => { default => CONFIG_USER }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + ### initialize object + my $obj = $class->SUPER::new( keys %$tmpl ); + for my $acc ( $obj->ls_accessors ) { + $obj->$acc( $args->{$acc} ); + } + + ### otherwise there's a circular use ### + load CPANPLUS::Configure; + load CPANPLUS::Backend; + + $obj->configure_object( CPANPLUS::Configure->new() ) + unless $obj->configure_object; + + $obj->backend( CPANPLUS::Backend->new( $obj->configure_object ) ) + unless $obj->backend; + + ### use empty string in case user only has T::R::Stub -- it complains + $obj->term( Term::ReadLine->new('') ) + unless $obj->term; + + ### enable autoreply if that was passed ### + $Term::UI::AUTOREPLY = $obj->autoreply; + + return $obj; +} + +sub init { + my $self = shift; + my $term = $self->term; + + ### default setting, unless changed + $self->config_type( CONFIG_USER ) unless $self->config_type; + + my $save = loc('Save & exit'); + my $exit = loc('Quit without saving'); + my @map = ( + # key on the display # method to dispatch to + [ loc('Select Configuration file') => '_save_where' ], + [ loc('Setup CLI Programs') => '_setup_program' ], + [ loc('Setup CPANPLUS Home directory') => '_setup_base' ], + [ loc('Setup FTP/Email settings') => '_setup_ftp' ], + [ loc('Setup basic preferences') => '_setup_conf' ], + [ loc('Setup installer settings') => '_setup_installer' ], + [ loc('Select mirrors'), => '_setup_hosts' ], + [ loc('Edit configuration file') => '_edit' ], + [ $save => '_save' ], + [ $exit => 1 ], + ); + + my @keys = map { $_->[0] } @map; # sorted keys + my %map = map { @$_ } @map; # lookup hash + + PICK_SECTION: { + print loc(" +=================> MAIN MENU <================= + +Welcome to the CPANPLUS configuration. Please select which +parts you wish to configure + +Defaults are taken from your current configuration. +If you would save now, your settings would be written to: + + %1 + + ", $self->config_type ); + + my $choice = $term->get_reply( + prompt => "Section to configure:", + choices => \@keys, + default => $keys[0] + ); + + ### exit configuration? + if( $choice eq $exit ) { + print loc(" +Quitting setup, changes will not be saved. + "); + return 1; + } + + my $method = $map{$choice}; + + my $rv = $self->$method or print loc(" +There was an error setting up this section. You might want to try again + "); + + ### was it save & exit? + if( $choice eq $save and $rv ) { + print loc(" +Quitting setup, changes are saved to '%1' + ", $self->config_type + ); + return 1; + } + + ### otherwise, present choice again + redo PICK_SECTION; + } + + return 1; +} + + + +### sub that figures out what kind of config type the user wants +sub _save_where { + my $self = shift; + my $term = $self->term; + my $conf = $self->configure_object; + + + ASK_CONFIG_TYPE: { + + print loc( q[ +Where would you like to save your CPANPLUS Configuration file? + +If you want to configure CPANPLUS for this user only, +select the '%1' option. +The file will then be saved in your homedirectory. + +If you are the system administrator of this machine, +and would like to make this config available globally, +select the '%2' option. +The file will be then be saved in your CPANPLUS +installation directory. + + ], CONFIG_USER, CONFIG_SYSTEM ); + + + ### ask what config type we should save to + my $type = $term->get_reply( + prompt => loc("Type of configuration file"), + default => $self->config_type || CONFIG_USER, + choices => [CONFIG_USER, CONFIG_SYSTEM], + ); + + my $file = $conf->_config_pm_to_file( $type ); + + ### can we save to this file? + unless( $conf->can_save( $file ) ) { + error(loc( + "Can not save to file '%1'-- please check permissions " . + "and try again", $file + )); + + redo ASK_CONFIG_FILE; + } + + ### you already have the file -- are we allowed to overwrite + ### or should we try again? + if ( -e $file and -w _ ) { + print loc(q[ +I see you already have this file: + %1 + +The file will not be overwritten until you explicitly save it. + + ], $file ); + + redo ASK_CONFIG_TYPE + unless $term->ask_yn( + prompt => loc( "Do you wish to use this file?"), + default => 'n', + ); + } + + print $/, loc("Using '%1' as your configuration type", $type); + + return $self->config_type($type); + } +} + + +### setup the build & cache dirs +sub _setup_base { + my $self = shift; + my $term = $self->term; + my $conf = $self->configure_object; + + my $base = $conf->get_conf('base'); + my $home = File::Spec->catdir( $self->_home_dir, DOT_CPANPLUS ); + + print loc(" +CPANPLUS needs a directory of its own to cache important index +files and maybe keep a temporary mirror of CPAN files. +This may be a site-wide directory or a personal directory. + +For a single-user installation, we suggest using your home directory. + +"); + + my $where; + ASK_HOME_DIR: { + my $other = loc('Somewhere else'); + if( $base and ($base ne $home) ) { + print loc("You have several choices:"); + + $where = $term->get_reply( + prompt => loc('Please pick one'), + choices => [$home, $base, $other], + default => $home, + ); + } else { + $where = $base; + } + + if( $where and -d $where ) { + print loc(" +I see you already have a directory: + %1 + + "), $where; + + my $yn = $term->ask_yn( + prompt => loc('Should I use it?'), + default => 'y', + ); + $where = '' unless $yn; + } + + if( $where and ($where ne $other) and not -d $where ) { + if (!$self->_mkdir( dir => $where ) ) { + print "\n", loc("Unable to create directory '%1'", $where); + redo ASK_HOME_DIR; + } + + } elsif( not $where or ($where eq $other) ) { + print loc(" +First of all, I'd like to create this directory. + + "); + + NEW_HOME: { + $where = $term->get_reply( + prompt => loc('Where shall I create it?'), + default => $home, + ); + + my $again; + if( -d $where and not -w _ ) { + print "\n", loc("I can't seem to write in this directory"); + $again++; + } elsif (!$self->_mkdir( dir => $where ) ) { + print "\n", loc("Unable to create directory '%1'", $where); + $again++; + } + + if( $again ) { + print "\n", loc('Please select another directory'), "\n\n"; + redo NEW_HOME; + } + } + } + } + + ### tidy up the path and store it + $where = File::Spec->rel2abs($where); + $conf->set_conf( base => $where ); + + ### create subdirectories ### + my @dirs = + File::Spec->catdir( $where, $self->_perl_version(perl => $^X), + $conf->_get_build('moddir') ), + map { + File::Spec->catdir( $where, $conf->_get_build($_) ) + } qw[autdir distdir]; + + for my $dir ( @dirs ) { + unless( $self->_mkdir( dir => $dir ) ) { + warn loc("I wasn't able to create '%1'", $dir), "\n"; + } + } + + ### clear away old storable images before 0.031 + for my $src (qw[dslip mailrc packages]) { + 1 while unlink File::Spec->catfile( $where, $src ); + + } + + print loc(q[ +Your CPANPLUS build and cache directory has been set to: + %1 + + ], $where); + + return 1; +} + +sub _setup_ftp { + my $self = shift; + my $term = $self->term; + my $conf = $self->configure_object; + + ######################### + ## are you a pacifist? ## + ######################### + + print loc(" +If you are connecting through a firewall or proxy that doesn't handle +FTP all that well you can use passive FTP. + +"); + + my $yn = $term->ask_yn( + prompt => loc("Use passive FTP?"), + default => $conf->get_conf('passive'), + ); + + $conf->set_conf(passive => $yn); + + ### set the ENV var as well, else it won't get set till AFTER + ### the configuration is saved. but we fetch files BEFORE that. + $ENV{FTP_PASSIVE} = $yn; + + print "\n"; + print $yn + ? loc("I will use passive FTP.") + : loc("I won't use passive FTP."); + print "\n"; + + ############################# + ## should fetches timeout? ## + ############################# + + print loc(" +CPANPLUS can specify a network timeout for downloads (in whole seconds). +If none is desired (or to skip this question), enter '0'. + +"); + + my $timeout = 0 + $term->get_reply( + prompt => loc("Network timeout for downloads"), + default => $conf->get_conf('timeout') || 0, + allow => qr/(?!\D)/, ### whole numbers only + ); + + $conf->set_conf(timeout => $timeout); + + print "\n"; + print $timeout + ? loc("The network timeout for downloads is %1 seconds.", $timeout) + : loc("The network timeout for downloads is not set."); + print "\n"; + + ############################ + ## where can I reach you? ## + ############################ + + print loc(" +What email address should we send as our anonymous password when +fetching modules from CPAN servers? Some servers will NOT allow you to +connect without a valid email address, or at least something that looks +like one. +Also, if you choose to report test results at some point, a valid email +is required for the 'from' field, so choose wisely. + + "); + + my $other = 'Something else'; + my @choices = (DEFAULT_EMAIL, $Config{cf_email}, $other); + my $current = $conf->get_conf('email'); + + ### if your current address is not in the list, add it to the choices + unless (grep { $_ eq $current } @choices) { + unshift @choices, $current; + } + + my $email = $term->get_reply( + prompt => loc('Which email address shall I use?'), + default => $current || $choices[0], + choices => \@choices, + ); + + if( $email eq $other ) { + EMAIL: { + $email = $term->get_reply( + prompt => loc('Email address: '), + ); + + unless( $self->_valid_email($email) ) { + print loc(" +You did not enter a valid email address, please try again! + ") if length $email; + + redo EMAIL; + } + } + } + + print loc(" +Your 'email' is now: + %1 + + ", $email); + + $conf->set_conf( email => $email ); + + return 1; +} + + +### commandline programs +sub _setup_program { + my $self = shift; + my $term = $self->term; + my $conf = $self->configure_object; + + print loc(" +CPANPLUS can use command line utilities to do certain +tasks, rather than use perl modules. + +If you wish to use a certain command utility, just enter +the full path (or accept the default). If you do not wish +to use it, enter a single space. + +Note that the paths you provide should not contain spaces, which is +needed to make a distinction between program name and options to that +program. For Win32 machines, you can use the short name for a path, +like '%1'. +", 'c:\Progra~1\prog.exe' ); + + for my $prog ( sort $conf->options( type => 'program') ) { + PROGRAM: { + print "\n", loc("Where can I find your '%1' utility? ". + "(Enter a single space to disable)", $prog ), "\n"; + + my $loc = $term->get_reply( + prompt => "Path to your '$prog'", + default => $conf->get_program( $prog ), + ); + + ### empty line clears it + my $cmd = $loc =~ /^\s*$/ ? undef : $loc; + my ($bin) = $cmd =~ /^(\S+)/; + + ### did you provide a valid program ? + if( $bin and not can_run( $bin ) ) { + print "\n"; + print loc("Can not find the binary '%1' in your path!", $bin); + redo PROGRAM; + } + + ### make is special -- we /need/ it! + if( $prog eq 'make' and not $bin ) { + print loc( + "==> Without your '%1' utility, I can not function! <==", + 'make' + ); + print loc("Please provide one!"); + + ### show win32 where to download + if ( $^O eq 'MSWin32' ) { + print loc("You can get '%1' from:", NMAKE); + print "\t". NMAKE_URL ."\n"; + } + print "\n"; + redo PROGRAM; + } + + $conf->set_program( $prog => $cmd ); + print $cmd + ? loc( "Your '%1' utility has been set to '%2'.", + $prog, $cmd ) + : loc( "Your '%1' has been disabled.", $prog ); + print "\n"; + } + } + + return 1; +} + +sub _setup_installer { + my $self = shift; + my $term = $self->term; + my $conf = $self->configure_object; + + my $none = 'None'; + { + print loc(" +CPANPLUS uses binary programs as well as Perl modules to accomplish +various tasks. Normally, CPANPLUS will prefer the use of Perl modules +over binary programs. + +You can change this setting by making CPANPLUS prefer the use of +certain binary programs if they are available. + + "); + + ### default to using binaries if we don't have compress::zlib only + ### -- it'll get very noisy otherwise + my $type = 'prefer_bin'; + my $yn = $term->ask_yn( + prompt => loc("Should I prefer the use of binary programs?"), + default => $conf->get_conf( $type ), + ); + + print $yn + ? loc("Ok, I will prefer to use binary programs if possible.") + : loc("Ok, I will prefer to use Perl modules if possible."); + print "\n\n"; + + + $conf->set_conf( $type => $yn ); + } + + { + print loc(" +Makefile.PL is run by perl in a separate process, and accepts various +flags that controls the module's installation. For instance, if you +would like to install modules to your private user directory, set +'makemakerflags' to: + +LIB=~/perl/lib INSTALLMAN1DIR=~/perl/man/man1 INSTALLMAN3DIR=~/perl/man/man3 + +and be sure that you do NOT set UNINST=1 in 'makeflags' below. + +Enter a name=value list separated by whitespace, but quote any embedded +spaces that you want to preserve. (Enter a space to clear any existing +settings.) + +If you don't understand this question, just press ENTER. + + "); + + my $type = 'makemakerflags'; + my $flags = $term->get_reply( + prompt => 'Makefile.PL flags?', + default => $conf->get_conf($type), + ); + + $flags = '' if $flags eq $none || $flags !~ /\S/; + + print "\n", loc("Your '%1' have been set to:", 'Makefile.PL flags'), + "\n ", ( $flags ? $flags : loc('*nothing entered*')), + "\n\n"; + + $conf->set_conf( $type => $flags ); + } + + { + print loc(" +Like Makefile.PL, we run 'make' and 'make install' as separate processes. +If you have any parameters (e.g. '-j3' in dual processor systems) you want +to pass to the calls, please specify them here. + +In particular, 'UNINST=1' is recommended for root users, unless you have +fine-tuned ideas of where modules should be installed in the \@INC path. + +Enter a name=value list separated by whitespace, but quote any embedded +spaces that you want to preserve. (Enter a space to clear any existing +settings.) + +Again, if you don't understand this question, just press ENTER. + + "); + my $type = 'makeflags'; + my $flags = $term->get_reply( + prompt => 'make flags?', + default => $conf->get_conf($type), + ); + + $flags = '' if $flags eq $none || $flags !~ /\S/; + + print "\n", loc("Your '%1' have been set to:", $type), + "\n ", ( $flags ? $flags : loc('*nothing entered*')), + "\n\n"; + + $conf->set_conf( $type => $flags ); + } + + { + print loc(" +An alternative to ExtUtils::MakeMaker and Makefile.PL there's a module +called Module::Build which uses a Build.PL. + +If you would like to specify any flags to pass when executing the +Build.PL (and Build) script, please enter them below. + +For instance, if you would like to install modules to your private +user directory, you could enter: + + install_base=/my/private/path + +Or to uninstall old copies of modules before updating, you might +want to enter: + + uninst=1 + +Again, if you don't understand this question, just press ENTER. + + "); + + my $type = 'buildflags'; + my $flags = $term->get_reply( + prompt => 'Build.PL and Build flags?', + default => $conf->get_conf($type), + ); + + $flags = '' if $flags eq $none || $flags !~ /\S/; + + print "\n", loc("Your '%1' have been set to:", + 'Build.PL and Build flags'), + "\n ", ( $flags ? $flags : loc('*nothing entered*')), + "\n\n"; + + $conf->set_conf( $type => $flags ); + } + + ### use EU::MM or module::build? ### + { + print loc(" +Some modules provide both a Build.PL (Module::Build) and a Makefile.PL +(ExtUtils::MakeMaker). By default, CPANPLUS prefers Makefile.PL. + +Module::Build support is not bundled standard with CPANPLUS, but +requires you to install 'CPANPLUS::Dist::Build' from CPAN. + +Although Module::Build is a pure perl solution, which means you will +not need a 'make' binary, it does have some limitations. The most +important is that CPANPLUS is unable to uninstall any modules installed +by Module::Build. + +Again, if you don't understand this question, just press ENTER. + + "); + my $type = 'prefer_makefile'; + my $yn = $term->ask_yn( + prompt => loc("Prefer Makefile.PL over Build.PL?"), + default => $conf->get_conf($type), + ); + + $conf->set_conf( $type => $yn ); + } + + { + print loc(' +If you like, CPANPLUS can add extra directories to your @INC list during +startup. These will just be used by CPANPLUS and will not change your +external environment or perl interpreter. Enter a space separated list of +pathnames to be added to your @INC, quoting any with embedded whitespace. +(To clear the current value enter a single space.) + + '); + + my $type = 'lib'; + my $flags = $term->get_reply( + prompt => loc('Additional @INC directories to add?'), + default => (join " ", @{$conf->get_conf($type) || []} ), + ); + + my $lib; + unless( $flags =~ /\S/ ) { + $lib = []; + } else { + (@$lib) = $flags =~ m/\s*("[^"]+"|'[^']+'|[^\s]+)/g; + } + + print "\n", loc("Your additional libs are now:"), "\n"; + + print scalar @$lib + ? map { " $_\n" } @$lib + : " ", loc("*nothing entered*"), "\n"; + print "\n\n"; + + $conf->set_conf( $type => $lib ); + } + + return 1; +} + + +sub _setup_conf { + my $self = shift; + my $term = $self->term; + my $conf = $self->configure_object; + + my $none = 'None'; + { + ############ + ## noisy? ## + ############ + + print loc(" +In normal operation I can just give you basic information about what I +am doing, or I can be more verbose and give you every little detail. + + "); + + my $type = 'verbose'; + my $yn = $term->ask_yn( + prompt => loc("Should I be verbose?"), + default => $conf->get_conf( $type ), ); + + print "\n"; + print $yn + ? loc("You asked for it!") + : loc("I'll try to be quiet"); + + $conf->set_conf( $type => $yn ); + } + + { + ####################### + ## flush you animal! ## + ####################### + + print loc(" +In the interest of speed, we keep track of what modules were installed +successfully and which failed in the current session. We can flush this +data automatically, or you can explicitly issue a 'flush' when you want +to purge it. + + "); + + my $type = 'flush'; + my $yn = $term->ask_yn( + prompt => loc("Flush automatically?"), + default => $conf->get_conf( $type ), + ); + + print "\n"; + print $yn + ? loc("I'll flush after every full module install.") + : loc("I won't flush until you tell me to."); + + $conf->set_conf( $type => $yn ); + } + + { + ##################### + ## force installs? ## + ##################### + + print loc(" +Usually, when a test fails, I won't install the module, but if you +prefer, I can force the install anyway. + + "); + + my $type = 'force'; + my $yn = $term->ask_yn( + prompt => loc("Force installs?"), + default => $conf->get_conf( $type ), + ); + + print "\n"; + print $yn + ? loc("I will force installs.") + : loc("I won't force installs."); + + $conf->set_conf( $type => $yn ); + } + + { + ################### + ## about prereqs ## + ################### + + print loc(" +Sometimes a module will require other modules to be installed before it +will work. CPANPLUS can attempt to install these for you automatically +if you like, or you can do the deed yourself. + +If you would prefer that we NEVER try to install extra modules +automatically, select NO. (Usually you will want this set to YES.) + +If you would like to build modules to satisfy testing or prerequisites, +but not actually install them, select BUILD. + +NOTE: This feature requires you to flush the 'lib' cache for longer +running programs (refer to the CPANPLUS::Backend documentations for +more details). + +Otherwise, select ASK to have us ask your permission to install them. + + "); + + my $type = 'prereqs'; + + my @map = ( + [ PREREQ_IGNORE, # conf value + loc('No, do not install prerequisites'), # UI Value + loc("I won't install prerequisites") # diag message + ], + [ PREREQ_INSTALL, + loc('Yes, please install prerequisites'), + loc("I will install prerequisites") + ], + [ PREREQ_ASK, + loc('Ask me before installing a prerequisite'), + loc("I will ask permission to install") + ], + [ PREREQ_BUILD, + loc('Build prerequisites, but do not install them'), + loc( "I will only build, but not install prerequisites" ) + ], + ); + + my %reply = map { $_->[1] => $_->[0] } @map; # choice => value + my %diag = map { $_->[1] => $_->[2] } @map; # choice => diag message + my %conf = map { $_->[0] => $_->[1] } @map; # value => ui choice + + my $reply = $term->get_reply( + prompt => loc('Follow prerequisites?'), + default => $conf{ $conf->get_conf( $type ) }, + choices => [ @conf{ sort keys %conf } ], + ); + print "\n"; + + my $value = $reply{ $reply }; + my $diag = $diag{ $reply }; + + $conf->set_conf( $type => $value ); + print $diag, "\n"; + } + + { print loc(" +Modules in the CPAN archives are protected with md5 checksums. + +This requires the Perl module Digest::MD5 to be installed (which +CPANPLUS can do for you later); + + "); + my $type = 'md5'; + + my $yn = $term->ask_yn( + prompt => loc("Shall I use the MD5 checksums?"), + default => $conf->get_conf( $type ), + ); + + print $yn + ? loc("I will use the MD5 checksums if you have it") + : loc("I won't use the MD5 checksums"); + + $conf->set_conf( $type => $yn ); + + } + + + { ########################################### + ## sally sells seashells by the seashore ## + ########################################### + + print loc(" +By default CPANPLUS uses its own shell when invoked. If you would prefer +a different shell, such as one you have written or otherwise acquired, +please enter the full name for your shell module. + + "); + + my $type = 'shell'; + my $other = 'Other'; + my @choices = (qw| CPANPLUS::Shell::Default + CPANPLUS::Shell::Classic |, + $other ); + my $default = $conf->get_conf($type); + + unshift @choices, $default unless grep { $_ eq $default } @choices; + + my $reply = $term->get_reply( + prompt => loc('Which CPANPLUS shell do you want to use?'), + default => $default, + choices => \@choices, + ); + + if( $reply eq $other ) { + SHELL: { + $reply = $term->get_reply( + prompt => loc( 'Please enter the name of the shell '. + 'you wish to use: '), + ); + + unless( check_install( module => $reply ) ) { + print "\n", + loc("Could not find '$reply' in your path " . + "-- please try again"), + "\n"; + redo SHELL; + } + } + } + + print "\n", loc("Your shell is now: %1", $reply), "\n\n"; + + $conf->set_conf( $type => $reply ); + } + + { + ################### + ## use storable? ## + ################### + + print loc(" +To speed up the start time of CPANPLUS, and maintain a cache over +multiple runs, we can use Storable to freeze some information. +Would you like to do this? + +"); + my $type = 'storable'; + my $yn = $term->ask_yn( + prompt => loc("Use Storable?"), + default => $conf->get_conf( $type ) ? 1 : 0, + ); + print "\n"; + print $yn + ? loc("I will use Storable if you have it") + : loc("I will not use Storable"); + + $conf->set_conf( $type => $yn ); + } + + { + ################### + ## use sqlite ? ## + ################### + + print loc(" + +To limit the amount of RAM used by CPANPLUS, you can use the SQLite +source backend instead. Note that it is currently still experimental. +Would you like to do this? + +"); + my $type = 'source_engine'; + my $class = 'CPANPLUS::Internals::Source::SQLite'; + my $yn = $term->ask_yn( + prompt => loc("Use SQLite?"), + default => $conf->get_conf( $type ) eq $class ? 1 : 0, + ); + print "\n"; + print $yn + ? loc("I will use SQLite") + : loc("I will not use SQLite"); + + $conf->set_conf( $type => $class ); + } + + { + ################### + ## use cpantest? ## + ################### + + print loc(" +CPANPLUS has support for the Test::Reporter module, which can be utilized +to report success and failures of modules installed by CPANPLUS. Would +you like to do this? Note that you will still be prompted before +sending each report. + +If you don't have all the required modules installed yet, you should +consider installing '%1' + +This package bundles all the required modules to enable test reporting +and querying from CPANPLUS. +You can do so straight after this installation. + + ", 'Bundle::CPANPLUS::Test::Reporter'); + + my $type = 'cpantest'; + my $yn = $term->ask_yn( + prompt => loc('Report test results?'), + default => $conf->get_conf( $type ) ? 1 : 0, + ); + + print "\n"; + print $yn + ? loc("I will prompt you to report test results") + : loc("I won't prompt you to report test results"); + + $conf->set_conf( $type => $yn ); + } + + { + ################################### + ## use cryptographic signatures? ## + ################################### + + print loc(" +The Module::Signature extension allows CPAN authors to sign their +distributions using PGP signatures. Would you like to check for +module's cryptographic integrity before attempting to install them? +Note that this requires either the 'gpg' utility or Crypt::OpenPGP +to be installed. + + "); + my $type = 'signature'; + + my $yn = $term->ask_yn( + prompt => loc('Shall I check module signatures?'), + default => $conf->get_conf($type) ? 1 : 0, + ); + + print "\n"; + print $yn + ? loc("Ok, I will attempt to check module signatures.") + : loc("Ok, I won't attempt to check module signatures."); + + $conf->set_conf( $type => $yn ); + } + + return 1; +} + +sub _setup_hosts { + my $self = shift; + my $term = $self->term; + my $conf = $self->configure_object; + + + if( scalar @{ $conf->get_conf('hosts') } ) { + + my $hosts; + for my $href ( @{$conf->get_conf('hosts')} ) { + $hosts .= "\t$href->{scheme}://$href->{host}$href->{path}\n"; + } + + print loc(" +I see you already have some hosts selected: + +$hosts + +If you'd like to stick with your current settings, just select 'Yes'. +Otherwise, select 'No' and you can reconfigure your hosts + +"); + my $yn = $term->ask_yn( + prompt => loc("Would you like to keep your current hosts?"), + default => 'y', + ); + return 1 if $yn; + } + + my @hosts; + MAIN: { + + print loc(" +Now we need to know where your favorite CPAN sites are located. Make a +list of a few sites (just in case the first on the array won't work). + +If you are mirroring CPAN to your local workstation, specify a file: +URI by picking the CUSTOM option. + +Otherwise, let us fetch the official CPAN mirror list and you can pick +the mirror that suits you best from a list by using the MIRROR option; +First, pick a nearby continent and country. Then, you will be presented +with a list of URLs of CPAN mirrors in the country you selected. Select +one or more of those URLs. + +Note, the latter option requires a working net connection. + +You can select VIEW to see your current selection and QUIT when you +are done. + +"); + + my $reply = $term->get_reply( + prompt => loc('Please choose an option'), + choices => [qw|Mirror Custom View Quit|], + default => 'Mirror', + ); + + goto MIRROR if $reply eq 'Mirror'; + goto CUSTOM if $reply eq 'Custom'; + goto QUIT if $reply eq 'Quit'; + + $self->_view_hosts(@hosts) if $reply eq 'View'; + redo MAIN; + } + + my $mirror_file; + my $hosts; + MIRROR: { + $mirror_file ||= $self->_get_mirrored_by or return; + $hosts ||= $self->_parse_mirrored_by($mirror_file) or return; + + my ($continent, $country, $host) = $self->_guess_from_timezone( $hosts ); + + CONTINENT: { + my %seen; + my @choices = sort map { + $_->{'continent'} + } grep { + not $seen{$_->{'continent'}}++ + } values %$hosts; + push @choices, qw[Custom Up Quit]; + + my $reply = $term->get_reply( + prompt => loc('Pick a continent'), + default => $continent, + choices => \@choices, + ); + + goto MAIN if $reply eq 'Up'; + goto CUSTOM if $reply eq 'Custom'; + goto QUIT if $reply eq 'Quit'; + + $continent = $reply; + } + + COUNTRY: { + my %seen; + my @choices = sort map { + $_->{'country'} + } grep { + not $seen{$_->{'country'}}++ + } grep { + ($_->{'continent'} eq $continent) + } values %$hosts; + push @choices, qw[Custom Up Quit]; + + my $reply = $term->get_reply( + prompt => loc('Pick a country'), + default => $country, + choices => \@choices, + ); + + goto CONTINENT if $reply eq 'Up'; + goto CUSTOM if $reply eq 'Custom'; + goto QUIT if $reply eq 'Quit'; + + $country = $reply; + } + + HOST: { + my @list = grep { + $_->{'continent'} eq $continent and + $_->{'country'} eq $country + } values %$hosts; + + my %map; my $default; + for my $href (@list) { + for my $con ( @{$href->{'connections'}} ) { + next unless length $con->{'host'}; + + my $entry = $con->{'scheme'} . '://' . $con->{'host'}; + $default = $entry if $con->{'host'} eq $host; + + $map{$entry} = $con; + } + } + + CHOICE: { + + ### doesn't play nice with Term::UI :( + ### should make t::ui figure out pager opens + #$self->_pager_open; # host lists might be long + + print loc(" +You can enter multiple sites by seperating them by a space. +For example: + 1 4 2 5 + "); + + my @reply = $term->get_reply( + prompt => loc('Please pick a site: '), + choices => [sort(keys %map), + qw|Custom View Up Quit|], + default => $default, + multi => 1, + ); + #$self->_pager_close; + + + goto COUNTRY if grep { $_ eq 'Up' } @reply; + goto CUSTOM if grep { $_ eq 'Custom' } @reply; + goto QUIT if grep { $_ eq 'Quit' } @reply; + + ### add the host, but only if it's not on the stack already ### + unless( grep { $_ eq 'View' } @reply ) { + for my $reply (@reply) { + if( grep { $_ eq $map{$reply} } @hosts ) { + print loc("Host '%1' already selected", $reply); + print "\n\n"; + } else { + push @hosts, $map{$reply} + } + } + } + + $self->_view_hosts(@hosts); + + goto QUIT if $self->autoreply; + redo CHOICE; + } + } + } + + CUSTOM: { + print loc(" +If there are any additional URLs you would like to use, please add them +now. You may enter them separately or as a space delimited list. + +We provide a default fall-back URL, but you are welcome to override it +with e.g. 'http://www.cpan.org/' if LWP, wget or curl is installed. + +(Enter a single space when you are done, or to simply skip this step.) + +Note that if you want to use a local depository, you will have to enter +as follows: + +file://server/path/to/cpan + +if the file is on a server on your local network or as: + +file:///path/to/cpan + +if the file is on your local disk. Note the three /// after the file: bit + +"); + + CHOICE: { + my $reply = $term->get_reply( + prompt => loc("Additionals host(s) to add: "), + default => '', + ); + + last CHOICE unless $reply =~ /\S/; + + my $href = $self->_parse_host($reply); + + if( $href ) { + push @hosts, $href + unless grep { + $href->{'scheme'} eq $_->{'scheme'} and + $href->{'host'} eq $_->{'host'} and + $href->{'path'} eq $_->{'path'} + } @hosts; + + last CHOICE if $self->autoreply; + } else { + print loc("Invalid uri! Please try again!"); + } + + $self->_view_hosts(@hosts); + + redo CHOICE; + } + + DONE: { + + print loc(" +Where would you like to go now? + +Please pick one of the following options or Quit when you are done + +"); + my $answer = $term->get_reply( + prompt => loc("Where to now?"), + default => 'Quit', + choices => [qw|Mirror Custom View Quit|], + ); + + if( $answer eq 'View' ) { + $self->_view_hosts(@hosts); + redo DONE; + } + + goto MIRROR if $answer eq 'Mirror'; + goto CUSTOM if $answer eq 'Custom'; + goto QUIT if $answer eq 'Quit'; + } + } + + QUIT: { + $conf->set_conf( hosts => \@hosts ); + + print loc(" +Your host configuration has been saved + +"); + } + + return 1; +} + +sub _view_hosts { + my $self = shift; + my @hosts = @_; + + print "\n\n"; + + if( scalar @hosts ) { + my $i = 1; + for my $host (@hosts) { + + ### show full path on file uris, otherwise, just show host + my $path = join '', ( + $host->{'scheme'} eq 'file' + ? ( ($host->{'host'} || '[localhost]'), + $host->{path} ) + : $host->{'host'} + ); + + printf "%-40s %30s\n", + loc("Selected %1",$host->{'scheme'} . '://' . $path ), + loc("%quant(%2,host) selected thus far.", $i); + $i++; + } + } else { + print loc("No hosts selected so far."); + } + + print "\n\n"; + + return 1; +} + +sub _get_mirrored_by { + my $self = shift; + my $cpan = $self->backend; + my $conf = $self->configure_object; + + print loc(" +Now, we are going to fetch the mirror list for first-time configurations. +This may take a while... + +"); + + ### use the enew configuratoin ### + $cpan->configure_object( $conf ); + + load CPANPLUS::Module::Fake; + load CPANPLUS::Module::Author::Fake; + + my $mb = CPANPLUS::Module::Fake->new( + module => $conf->_get_source('hosts'), + path => '', + package => $conf->_get_source('hosts'), + author => CPANPLUS::Module::Author::Fake->new( + _id => $cpan->_id ), + _id => $cpan->_id, + ); + + my $file = $cpan->_fetch( fetchdir => $conf->get_conf('base'), + module => $mb ); + + return $file if $file; + return; +} + +sub _parse_mirrored_by { + my $self = shift; + my $file = shift; + + -s $file or return; + + my $fh = new FileHandle; + $fh->open("$file") + or ( + warn(loc('Could not open file "%1": %2', $file, $!)), + return + ); + + ### slurp the file in ### + { local $/; $file = <$fh> } + + ### remove comments ### + $file =~ s/#.*$//gm; + + $fh->close; + + ### sample host entry ### + # ftp.sun.ac.za: + # frequency = "daily" + # dst_ftp = "ftp://ftp.sun.ac.za/CPAN/CPAN/" + # dst_location = "Stellenbosch, South Africa, Africa (-26.1992 28.0564)" + # dst_organisation = "University of Stellenbosch" + # dst_timezone = "+2" + # dst_contact = "ftpadm@ftp.sun.ac.za" + # dst_src = "ftp.funet.fi" + # + # # dst_dst = "ftp://ftp.sun.ac.za/CPAN/CPAN/" + # # dst_contact = "mailto:ftpadm@ftp.sun.ac.za + # # dst_src = "ftp.funet.fi" + + ### host name as key, rest of the entry as value ### + my %hosts = $file =~ m/([a-zA-Z0-9\-\.]+):\s+((?:\w+\s+=\s+".*?"\s+)+)/gs; + + while (my($host,$data) = each %hosts) { + + my $href; + map { + s/^\s*//; + my @a = split /\s*=\s*/; + $a[1] =~ s/^"(.+?)"$/$1/g; + $href->{ pop @a } = pop @a; + } grep /\S/, split /\n/, $data; + + ($href->{city_area}, $href->{country}, $href->{continent}, + $href->{latitude}, $href->{longitude} ) = + $href->{dst_location} =~ + m/ + #Aizu-Wakamatsu, Tohoku-chiho, Fukushima + ^"?( + (?:[^,]+?)\s* # city + (?: + (?:,\s*[^,]+?)\s* # optional area + )*? # some have multiple areas listed + ) + + #Japan + ,\s*([^,]+?)\s* # country + + #Asia + ,\s*([^,]+?)\s* # continent + + # (37.4333 139.9821) + \((\S+)\s+(\S+?)\)"?$ # (latitude longitude) + /sx; + + ### parse the different hosts, store them in config format ### + my @list; + + for my $type (qw[dst_ftp dst_rsync dst_http]) { + my $path = $href->{$type}; + next unless $path =~ /\w/; + if ($type eq 'dst_rsync' && $path !~ /^rsync:/) { + $path =~ s{::}{/}; + $path = "rsync://$path/"; + } + my $parts = $self->_parse_host($path); + push @list, $parts; + } + + $href->{connections} = \@list; + $hosts{$host} = $href; + } + + return \%hosts; +} + +sub _parse_host { + my $self = shift; + my $host = shift; + + my @parts = $host =~ m|^(\w*)://([^/]*)(/.*)$|s; + + my $href; + for my $key (qw[scheme host path]) { + $href->{$key} = shift @parts; + } + + return if lc($href->{'scheme'}) ne 'file' and !$href->{'host'}; + return if !$href->{'path'}; + + return $href; +} + +## tries to figure out close hosts based on your timezone +## +## Currently can only report on unique items for each of zones, countries, and +## sites. In the future this will be combined with something else (perhaps a +## ping?) to narrow down multiple choices. +## +## Tries to return the best zone, country, and site for your location. Any non- +## unique items will be set to undef instead. +## +## (takes hashref, returns array) +## +sub _guess_from_timezone { + my $self = shift; + my $hosts = shift; + my (%zones, %countries, %sites); + + ### autrijus - build time zone table + my %freq_weight = ( + 'hourly' => 2400, + '4 times a day' => 400, + '4x daily' => 400, + 'daily' => 100, + 'twice daily' => 50, + 'weekly' => 15, + ); + + while (my ($site, $host) = each %{$hosts}) { + my ($zone, $continent, $country, $frequency) = + @{$host}{qw/dst_timezone continent country frequency/}; + + + # skip non-well-formed ones + next unless $continent and $country and $zone =~ /^[-+]?\d+(?::30)?/; + ### fix style + chomp $zone; + $zone =~ s/:30/.5/; + $zone =~ s/^\+//; + $zone =~ s/"//g; + + $zones{$zone}{$continent}++; + $countries{$zone}{$continent}{$country}++; + $sites{$zone}{$continent}{$country}{$site} = $freq_weight{$frequency}; + } + + use Time::Local; + my $offset = ((timegm(localtime) - timegm(gmtime)) / 3600); + + local $_; + + ## pick the entry with most country/site/frequency, one level each; + ## note it has to be sorted -- otherwise we're depending on the hash order. + ## also, the list context assignment (pick first one) is deliberate. + + my ($continent) = map { + (sort { ($_->{$b} <=> $_->{$a}) or $b cmp $a } keys(%{$_})) + } $zones{$offset}; + + my ($country) = map { + (sort { ($_->{$b} <=> $_->{$a}) or $b cmp $a } keys(%{$_})) + } $countries{$offset}{$continent}; + + my ($site) = map { + (sort { ($_->{$b} <=> $_->{$a}) or $b cmp $a } keys(%{$_})) + } $sites{$offset}{$continent}{$country}; + + return ($continent, $country, $site); +} # _guess_from_timezone + + +### big big regex, stolen to check if you enter a valid address +{ + my $RFC822PAT; # RFC pattern to match for valid email address + + sub _valid_email { + my $self = shift; + if (!$RFC822PAT) { + my $esc = '\\\\'; my $Period = '\.'; my $space = '\040'; + my $tab = '\t'; my $OpenBR = '\['; my $CloseBR = '\]'; + my $OpenParen = '\('; my $CloseParen = '\)'; my $NonASCII = '\x80-\xff'; + my $ctrl = '\000-\037'; my $CRlist = '\012\015'; + + my $qtext = qq/[^$esc$NonASCII$CRlist\"]/; + my $dtext = qq/[^$esc$NonASCII$CRlist$OpenBR$CloseBR]/; + my $quoted_pair = qq< $esc [^$NonASCII] >; # an escaped character + my $ctext = qq< [^$esc$NonASCII$CRlist()] >; + my $Cnested = qq< $OpenParen $ctext* (?: $quoted_pair $ctext* )* $CloseParen >; + my $comment = qq< $OpenParen $ctext* (?: (?: $quoted_pair | $Cnested ) $ctext* )* $CloseParen >; + my $X = qq< [$space$tab]* (?: $comment [$space$tab]* )* >; + my $atom_char = qq/[^($space)<>\@,;:\".$esc$OpenBR$CloseBR$ctrl$NonASCII]/; + my $atom = qq< $atom_char+ (?!$atom_char) >; + my $quoted_str = qq< \" $qtext * (?: $quoted_pair $qtext * )* \" >; + my $word = qq< (?: $atom | $quoted_str ) >; + my $domain_ref = $atom; + my $domain_lit = qq< $OpenBR (?: $dtext | $quoted_pair )* $CloseBR >; + my $sub_domain = qq< (?: $domain_ref | $domain_lit) $X >; + my $domain = qq< $sub_domain (?: $Period $X $sub_domain)* >; + my $route = qq< \@ $X $domain (?: , $X \@ $X $domain )* : $X >; + my $local_part = qq< $word $X (?: $Period $X $word $X )* >; + my $addr_spec = qq< $local_part \@ $X $domain >; + my $route_addr = qq[ < $X (?: $route )? $addr_spec > ]; + my $phrase_ctrl = '\000-\010\012-\037'; # like ctrl, but without tab + my $phrase_char = qq/[^()<>\@,;:\".$esc$OpenBR$CloseBR$NonASCII$phrase_ctrl]/; + my $phrase = qq< $word $phrase_char * (?: (?: $comment | $quoted_str ) $phrase_char * )* >; + $RFC822PAT = qq< $X (?: $addr_spec | $phrase $route_addr) >; + } + + return scalar ($_[0] =~ /$RFC822PAT/ox); + } +} + + + + + + +1; + + +sub _edit { + my $self = shift; + my $conf = $self->configure_object; + my $file = shift || $conf->_config_pm_to_file( $self->config_type ); + my $editor = shift || $conf->get_program('editor'); + my $term = $self->term; + + unless( $editor ) { + print loc(" +I'm sorry, I can't find a suitable editor, so I can't offer you +post-configuration editing of the config file + +"); + return 1; + } + + ### save the thing first, so there's something to edit + $self->_save; + + return !system("$editor $file"); +} + +sub _save { + my $self = shift; + my $conf = $self->configure_object; + + return $conf->save( $self->config_type ); +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Dist.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist.pm new file mode 100644 index 00000000000..551b8ec405f --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist.pm @@ -0,0 +1,688 @@ +package CPANPLUS::Dist; + +use strict; + +use CPANPLUS::Error; +use CPANPLUS::Internals::Constants; + +use Cwd (); +use Object::Accessor; +use Parse::CPAN::Meta; + +use IPC::Cmd qw[run]; +use Params::Check qw[check]; +use Module::Load::Conditional qw[can_load check_install]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +use base 'Object::Accessor'; + +local $Params::Check::VERBOSE = 1; + +=pod + +=head1 NAME + +CPANPLUS::Dist + +=head1 SYNOPSIS + + my $dist = CPANPLUS::Dist::YOUR_DIST_TYPE_HERE->new( + module => $modobj, + ); + +=head1 DESCRIPTION + +C<CPANPLUS::Dist> is a base class for C<CPANPLUS::Dist::MM> +and C<CPANPLUS::Dist::Build>. Developers of other C<CPANPLUS::Dist::*> +plugins should look at C<CPANPLUS::Dist::Base>. + +=head1 ACCESSORS + +=over 4 + +=item parent() + +Returns the C<CPANPLUS::Module> object that parented this object. + +=item status() + +Returns the C<Object::Accessor> object that keeps the status for +this module. + +=back + +=head1 STATUS ACCESSORS + +All accessors can be accessed as follows: + $deb->status->ACCESSOR + +=over 4 + +=item created() + +Boolean indicating whether the dist was created successfully. +Explicitly set to C<0> when failed, so a value of C<undef> may be +interpreted as C<not yet attempted>. + +=item installed() + +Boolean indicating whether the dist was installed successfully. +Explicitly set to C<0> when failed, so a value of C<undef> may be +interpreted as C<not yet attempted>. + +=item uninstalled() + +Boolean indicating whether the dist was uninstalled successfully. +Explicitly set to C<0> when failed, so a value of C<undef> may be +interpreted as C<not yet attempted>. + +=item dist() + +The location of the final distribution. This may be a file or +directory, depending on how your distribution plug in of choice +works. This will be set upon a successful create. + +=cut + +=back + +=head2 $dist = CPANPLUS::Dist::YOUR_DIST_TYPE_HERE->new( module => MODOBJ ); + +Create a new C<CPANPLUS::Dist::YOUR_DIST_TYPE_HERE> object based on the +provided C<MODOBJ>. + +*** DEPRECATED *** +The optional argument C<format> is used to indicate what type of dist +you would like to create (like C<CPANPLUS::Dist::MM> or +C<CPANPLUS::Dist::Build> and so on ). + +C<< CPANPLUS::Dist->new >> is exlusively meant as a method to be +inherited by C<CPANPLUS::Dist::MM|Build>. + +Returns a C<CPANPLUS::Dist::YOUR_DIST_TYPE_HERE> object on success +and false on failure. + +=cut + +sub new { + my $self = shift; + my $class = ref $self || $self; + my %hash = @_; + + ### first verify we got a module object ### + my( $mod, $format ); + my $tmpl = { + module => { required => 1, allow => IS_MODOBJ, store => \$mod }, + ### for backwards compatibility + format => { default => $class, store => \$format, + allow => [ __PACKAGE__->dist_types ], + }, + }; + check( $tmpl, \%hash ) or return; + + unless( can_load( modules => { $format => '0.0' }, verbose => 1 ) ) { + error(loc("'%1' not found -- you need '%2' version '%3' or higher ". + "to detect plugins", $format, 'Module::Pluggable','2.4')); + return; + } + + ### get an empty o::a object for this class + my $obj = $format->SUPER::new; + + $obj->mk_accessors( qw[parent status] ); + + ### set the parent + $obj->parent( $mod ); + + ### create a status object ### + { my $acc = Object::Accessor->new; + $obj->status($acc); + + ### add minimum supported accessors + $acc->mk_accessors( qw[prepared created installed uninstalled + distdir dist] ); + } + + ### get the conf object ### + my $conf = $mod->parent->configure_object(); + + ### check if the format is available in this environment ### + if( $conf->_get_build('sanity_check') and not $obj->format_available ) { + error( loc( "Format '%1' is not available", $format) ); + return; + } + + ### now initialize it or admit failure + unless( $obj->init ) { + error(loc("Dist initialization of '%1' failed for '%2'", + $format, $mod->module)); + return; + } + + ### return the object + return $obj; +} + +=head2 @dists = CPANPLUS::Dist->dist_types; + +Returns a list of the CPANPLUS::Dist::* classes available + +=cut + +### returns a list of dist_types we support +### will get overridden by Module::Pluggable if loaded +### XXX add support for 'plugin' dir in config as well +{ my $Loaded; + my @Dists = (INSTALLER_MM); + my @Ignore = (); + + ### backdoor method to add more dist types + sub _add_dist_types { my $self = shift; push @Dists, @_ }; + + ### backdoor method to exclude dist types + sub _ignore_dist_types { my $self = shift; push @Ignore, @_ }; + sub _reset_dist_ignore { @Ignore = () }; + + ### locally add the plugins dir to @INC, so we can find extra plugins + #local @INC = @INC, File::Spec->catdir( + # $conf->get_conf('base'), + # $conf->_get_build('plugins') ); + + ### load any possible plugins + sub dist_types { + + if ( !$Loaded++ and check_install( module => 'Module::Pluggable', + version => '2.4') + ) { + require Module::Pluggable; + + my $only_re = __PACKAGE__ . '::\w+$'; + my %except = map { $_ => 1 } + INSTALLER_SAMPLE, + INSTALLER_BASE; + + Module::Pluggable->import( + sub_name => '_dist_types', + search_path => __PACKAGE__, + only => qr/$only_re/, + require => 1, + except => [ keys %except ] + ); + my %ignore = map { $_ => $_ } @Ignore; + + push @Dists, grep { not $ignore{$_} and not $except{$_} } + __PACKAGE__->_dist_types; + } + + return @Dists; + } + +=head2 $bool = CPANPLUS::Dist->rescan_dist_types; + +Rescans C<@INC> for available dist types. Useful if you've installed new +C<CPANPLUS::Dist::*> classes and want to make them available to the +current process. + +=cut + + sub rescan_dist_types { + my $dist = shift; + $Loaded = 0; # reset the flag; + return $dist->dist_types; + } +} + +=head2 $bool = CPANPLUS::Dist->has_dist_type( $type ) + +Returns true if distribution type C<$type> is loaded/supported. + +=cut + +sub has_dist_type { + my $dist = shift; + my $type = shift or return; + + return scalar grep { $_ eq $type } CPANPLUS::Dist->dist_types; +} + +=head2 $bool = $dist->prereq_satisfied( modobj => $modobj, version => $version_spec ) + +Returns true if this prereq is satisfied. Returns false if it's not. +Also issues an error if it seems "unsatisfiable," i.e. if it can't be +found on CPAN or the latest CPAN version doesn't satisfy it. + +=cut + +sub prereq_satisfied { + my $dist = shift; + my $cb = $dist->parent->parent; + my %hash = @_; + + my($mod,$ver); + my $tmpl = { + version => { required => 1, store => \$ver }, + modobj => { required => 1, store => \$mod, allow => IS_MODOBJ }, + }; + + check( $tmpl, \%hash ) or return; + + return 1 if $mod->is_uptodate( version => $ver ); + + if ( $cb->_vcmp( $ver, $mod->version ) > 0 ) { + + error(loc( + "This distribution depends on %1, but the latest version". + " of %2 on CPAN (%3) doesn't satisfy the specific version". + " dependency (%4). You may have to resolve this dependency ". + "manually.", + $mod->module, $mod->module, $mod->version, $ver )); + + } + + return; +} + +=head2 $configure_requires = $dist->find_configure_requires( [file => /path/to/META.yml] ) + +Reads the configure_requires for this distribution from the META.yml +file in the root directory and returns a hashref with module names +and versions required. + +=cut + +sub find_configure_requires { + my $self = shift; + my $mod = $self->parent; + my $meth = 'configure_requires'; + + ### the prereqs as we have them now + my @args = ( + defaults => $mod->status->$meth || {}, + keys => [ $meth ], + ); + + ### the default file to use, which may be overriden + push @args, ( file => META_YML->( $mod->status->extract ) ) + if defined $mod->status->extract; + + my $href = $self->_prereqs_from_meta_file( @args, @_ ); + + ### and store it in the module + $mod->status->$meth( $href ); + + return { %$href }; +} + +sub find_mymeta_requires { + my $self = shift; + my $mod = $self->parent; + my $meth = 'prereqs'; + + ### the prereqs as we have them now + my @args = ( + defaults => $mod->status->$meth || {}, + keys => [qw|requires build_requires|], + ); + + ### the default file to use, which may be overriden + push @args, ( file => MYMETA_YML->( $mod->status->extract ) ) + if defined $mod->status->extract; + + my $href = $self->_prereqs_from_meta_file( @args, @_ ); + + ### and store it in the module + $mod->status->$meth( $href ); + + return { %$href }; +} + +sub _prereqs_from_meta_file { + my $self = shift; + my $mod = $self->parent; + my %hash = @_; + + my( $meta, $defaults, $keys ); + my $tmpl = { ### check if we have an extract path. if not, we + ### get 'undef value' warnings from file::spec + file => { default => do { defined $mod->status->extract + ? META_YML->( $mod->status->extract ) + : '' }, + store => \$meta, + }, + defaults => { required => 1, default => {}, strict_type => 1, + store => \$defaults }, + keys => { required => 1, default => [], strict_type => 1, + store => \$keys }, + }; + + check( $tmpl, \%hash ) or return; + + ### if there's a meta file, we read it; + if( -e $meta ) { + + ### Parse::CPAN::Meta uses exceptions for errors + ### hash returned in list context!!! + my ($doc) = eval { Parse::CPAN::Meta::LoadFile( $meta ) }; + + unless( $doc ) { + error(loc( "Could not read %1: '%2'", $meta, $@ )); + return $defaults; + } + + ### read the keys now, make sure not to throw + ### away anything that was already added + for my $key ( @$keys ) { + $defaults = { + %$defaults, + %{ $doc->{$key} }, + } if $doc->{ $key }; + } + } + + ### and return a copy + return \%{ $defaults }; +} + +=head2 $bool = $dist->_resolve_prereqs( ... ) + +Makes sure prerequisites are resolved + + format The dist class to use to make the prereqs + (ie. CPANPLUS::Dist::MM) + + prereqs Hash of the prerequisite modules and their versions + + target What to do with the prereqs. + create => Just build them + install => Install them + ignore => Ignore them + + prereq_build If true, always build the prereqs even if already + resolved + + verbose Be verbose + + force Force the prereq to be built, even if already resolved + +=cut + +sub _resolve_prereqs { + my $dist = shift; + my $self = $dist->parent; + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my ($prereqs, $format, $verbose, $target, $force, $prereq_build); + my $tmpl = { + ### XXX perhaps this should not be required, since it may not be + ### packaged, just installed... + ### Let it be empty as well -- that means the $modobj->install + ### routine will figure it out, which is fine if we didn't have any + ### very specific wishes (it will even detect the favourite + ### dist_type). + format => { required => 1, store => \$format, + allow => ['',__PACKAGE__->dist_types], }, + prereqs => { required => 1, default => { }, + strict_type => 1, store => \$prereqs }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + force => { default => $conf->get_conf('force'), + store => \$force }, + ### make sure allow matches with $mod->install's list + target => { default => '', store => \$target, + allow => ['',qw[create ignore install]] }, + prereq_build => { default => 0, store => \$prereq_build }, + }; + + check( $tmpl, \%hash ) or return; + + ### so there are no prereqs? then don't even bother + return 1 unless keys %$prereqs; + + ### Make sure we wound up where we started. + my $original_wd = Cwd::cwd; + + ### so you didn't provide an explicit target. + ### maybe your config can tell us what to do. + $target ||= { + PREREQ_ASK, TARGET_INSTALL, # we'll bail out if the user says no + PREREQ_BUILD, TARGET_CREATE, + PREREQ_IGNORE, TARGET_IGNORE, + PREREQ_INSTALL, TARGET_INSTALL, + }->{ $conf->get_conf('prereqs') } || ''; + + ### XXX BIG NASTY HACK XXX FIXME at some point. + ### when installing Bundle::CPANPLUS::Dependencies, we want to + ### install all packages matching 'cpanplus' to be installed last, + ### as all CPANPLUS' prereqs are being installed as well, but are + ### being loaded for bootstrapping purposes. This means CPANPLUS + ### can find them, but for example cpanplus::dist::build won't, + ### which gets messy FAST. So, here we sort our prereqs only IF + ### the parent module is Bundle::CPANPLUS::Dependencies. + ### Really, we would wnat some sort of sorted prereq mechanism, + ### but Bundle:: doesn't support it, and we flatten everything + ### to a hash internally. A sorted hash *might* do the trick if + ### we got a transparent implementation.. that would mean we would + ### just have to remove the 'sort' here, and all will be well + my @sorted_prereqs; + + ### use regex, could either be a module name, or a package name + if( $self->module =~ /^Bundle(::|-)CPANPLUS(::|-)Dependencies/ ) { + my (@first, @last); + for my $mod ( sort keys %$prereqs ) { + $mod =~ /CPANPLUS/ + ? push @last, $mod + : push @first, $mod; + } + @sorted_prereqs = (@first, @last); + } else { + @sorted_prereqs = sort keys %$prereqs; + } + + ### first, transfer this key/value pairing into a + ### list of module objects + desired versions + my @install_me; + + for my $mod ( @sorted_prereqs ) { + my $version = $prereqs->{$mod}; + + ### 'perl' is a special case, there's no mod object for it + if( $mod eq PERL_CORE ) { + + ### run a CLI invocation to see if the perl you specified is + ### uptodate + my $ok = run( command => "$^X -M$version -e1", verbose => 0 ); + + unless( $ok ) { + error(loc( "Module '%1' needs perl version '%2', but you ". + "only have version '%3' -- can not proceed", + $self->module, $version, + $cb->_perl_version( perl => $^X ) ) ); + return; + } + + next; + } + + my $modobj = $cb->module_tree($mod); + + #### XXX we ignore the version, and just assume that the latest + #### version from cpan will meet your requirements... dodgy =/ + unless( $modobj ) { + # Check if it is a core module + my $sub = CPANPLUS::Module->can( + 'module_is_supplied_with_perl_core' ); + my $core = $sub->( $mod ); + unless ( $core ) { + error( loc( "No such module '%1' found on CPAN", $mod ) ); + next; + } + if ( $cb->_vcmp( $version, $core ) > 0 ) { + error(loc( "Version of core module '%1' ('%2') is too low for ". + "'%3' (needs '%4') -- carrying on but this may be a problem", + $mod, $core, + $self->module, $version )); + } + next; + } + + ### it's not uptodate, we need to install it + if( !$dist->prereq_satisfied(modobj => $modobj, version => $version)) { + msg(loc("Module '%1' requires '%2' version '%3' to be installed ", + $self->module, $modobj->module, $version), $verbose ); + + push @install_me, [$modobj, $version]; + + ### it's not an MM or Build format, that means it's a package + ### manager... we'll need to install it as well, via the PM + } elsif ( INSTALL_VIA_PACKAGE_MANAGER->($format) and + !$modobj->package_is_perl_core and + ($target ne TARGET_IGNORE) + ) { + msg(loc("Module '%1' depends on '%2', may need to build a '%3' ". + "package for it as well", $self->module, $modobj->module, + $format)); + push @install_me, [$modobj, $version]; + } + } + + + + ### so you just want to ignore prereqs? ### + if( $target eq TARGET_IGNORE ) { + + ### but you have modules you need to install + if( @install_me ) { + msg(loc("Ignoring prereqs, this may mean your install will fail"), + $verbose); + msg(loc("'%1' listed the following dependencies:", $self->module), + $verbose); + + for my $aref (@install_me) { + my ($mod,$version) = @$aref; + + my $str = sprintf "\t%-35s %8s\n", $mod->module, $version; + msg($str,$verbose); + } + + return; + + ### ok, no problem, you have all needed prereqs anyway + } else { + return 1; + } + } + + my $flag; + for my $aref (@install_me) { + my($modobj,$version) = @$aref; + + ### another prereq may have already installed this one... + ### so dont ask again if the module turns out to be uptodate + ### see bug [#11840] + ### if either force or prereq_build are given, the prereq + ### should be built anyway + next if (!$force and !$prereq_build) && + $dist->prereq_satisfied(modobj => $modobj, version => $version); + + ### either we're told to ignore the prereq, + ### or the user wants us to ask him + if( ( $conf->get_conf('prereqs') == PREREQ_ASK and not + $cb->_callbacks->install_prerequisite->($self, $modobj) + ) + ) { + msg(loc("Will not install prerequisite '%1' -- Note " . + "that the overall install may fail due to this", + $modobj->module), $verbose); + next; + } + + ### value set and false -- means failure ### + if( defined $modobj->status->installed + && !$modobj->status->installed + ) { + error( loc( "Prerequisite '%1' failed to install before in " . + "this session", $modobj->module ) ); + $flag++; + last; + } + + ### part of core? + if( $modobj->package_is_perl_core ) { + error(loc("Prerequisite '%1' is perl-core (%2) -- not ". + "installing that. Aborting install", + $modobj->module, $modobj->package ) ); + $flag++; + last; + } + + ### circular dependency code ### + my $pending = $cb->_status->pending_prereqs || {}; + + ### recursive dependency ### + if ( $pending->{ $modobj->module } ) { + error( loc( "Recursive dependency detected (%1) -- skipping", + $modobj->module ) ); + next; + } + + ### register this dependency as pending ### + $pending->{ $modobj->module } = $modobj; + $cb->_status->pending_prereqs( $pending ); + + ### call $modobj->install rather than doing + ### CPANPLUS::Dist->new and the like ourselves, + ### since ->install will take care of fetch && + ### extract as well + my $pa = $dist->status->_prepare_args || {}; + my $ca = $dist->status->_create_args || {}; + my $ia = $dist->status->_install_args || {}; + + unless( $modobj->install( %$pa, %$ca, %$ia, + force => $force, + verbose => $verbose, + format => $format, + target => $target ) + ) { + error(loc("Failed to install '%1' as prerequisite " . + "for '%2'", $modobj->module, $self->module ) ); + $flag++; + } + + ### unregister the pending dependency ### + $pending->{ $modobj->module } = 0; + $cb->_status->pending_prereqs( $pending ); + + last if $flag; + + ### don't want us to install? ### + if( $target ne TARGET_INSTALL ) { + my $dir = $modobj->status->extract + or error(loc("No extraction dir for '%1' found ". + "-- weird", $modobj->module)); + + $modobj->add_to_includepath(); + + next; + } + } + + ### reset the $prereqs iterator, in case we bailed out early ### + keys %$prereqs; + + ### chdir back to where we started + chdir $original_wd; + + return 1 unless $flag; + return; +} + +1; + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Autobundle.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Autobundle.pm new file mode 100644 index 00000000000..16638b258f8 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Autobundle.pm @@ -0,0 +1,117 @@ +package CPANPLUS::Dist::Autobundle; + +use strict; +use warnings; +use CPANPLUS::Error qw[error msg]; +use Params::Check qw[check]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +use base qw[CPANPLUS::Dist::Base]; + +=head1 NAME + +CPANPLUS::Dist::Autobundle + +=head1 SYNOPSIS + + $modobj = $cb->parse_module( module => 'file://path/to/Snapshot_XXYY.pm' ); + $modobj->install; + +=head1 DESCRIPTION + +C<CPANPLUS::Dist::Autobundle> is a distribution class for installing installation +snapshots as created by C<CPANPLUS>' C<autobundle> command. + +All modules as mentioned in the snapshot will be installed on your system. + +=cut + +sub init { + my $dist = shift; + my $status = $dist->status; + + $status->mk_accessors( + qw[prepared created installed _prepare_args _create_args _install_args] + ); + + return 1; +} + +sub prepare { + my $dist = shift; + my %args = @_; + + ### store the arguments, so ->install can use them in recursive loops ### + $dist->status->_prepare_args( \%args ); + + return $dist->status->prepared( 1 ); +} + +sub create { + my $dist = shift; + my $self = $dist->parent; + + ### we're also the cpan_dist, since we don't need to have anything + ### prepared + $dist = $self->status->dist_cpan if $self->status->dist_cpan; + $self->status->dist_cpan( $dist ) unless $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my( $force, $verbose, $prereq_target, $prereq_format, $prereq_build); + + my $args = do { + local $Params::Check::ALLOW_UNKNOWN = 1; + my $tmpl = { + force => { default => $conf->get_conf('force'), + store => \$force }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + prereq_target => { default => '', store => \$prereq_target }, + + ### don't set the default prereq format to 'makemaker' -- wrong! + prereq_format => { #default => $self->status->installer_type, + default => '', + store => \$prereq_format }, + prereq_build => { default => 0, store => \$prereq_build }, + }; + + check( $tmpl, \%hash ) or return; + }; + + ### maybe we already ran a create on this object? ### + return 1 if $dist->status->created && !$force; + + ### store the arguments, so ->install can use them in recursive loops ### + $dist->status->_create_args( \%hash ); + + msg(loc("Resolving prerequisites mentioned in the bundle"), $verbose); + + ### this will set the directory back to the start + ### dir, so we must chdir /again/ + my $ok = $dist->_resolve_prereqs( + format => $prereq_format, + verbose => $verbose, + prereqs => $self->status->prereqs, + target => $prereq_target, + force => $force, + prereq_build => $prereq_build, + ); + + ### if all went well, mark it & return + return $dist->status->created( $ok ? 1 : 0); +} + +sub install { + my $dist = shift; + my %args = @_; + + ### store the arguments, so ->install can use them in recursive loops ### + $dist->status->_install_args( \%args ); + + return $dist->status->installed( 1 ); +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Base.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Base.pm new file mode 100644 index 00000000000..c7108ed1392 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Base.pm @@ -0,0 +1,261 @@ +package CPANPLUS::Dist::Base; + +use strict; + +use base qw[CPANPLUS::Dist]; +use vars qw[$VERSION]; +$VERSION = $CPANPLUS::Internals::VERSION = $CPANPLUS::Internals::VERSION; + + +=head1 NAME + +CPANPLUS::Dist::Base - Base class for custom distribution classes + +=head1 SYNOPSIS + + package CPANPLUS::Dist::MY_IMPLEMENTATION + + use base 'CPANPLUS::Dist::Base'; + + sub prepare { + my $dist = shift; + + ### do the 'standard' things + $dist->SUPER::prepare( @_ ) or return; + + ### do MY_IMPLEMENTATION specific things + ... + + ### don't forget to set the status! + return $dist->status->prepared( $SUCCESS ? 1 : 0 ); + } + + +=head1 DESCRIPTION + +CPANPLUS::Dist::Base functions as a base class for all custom +distribution implementations. It does all the mundane work +CPANPLUS would have done without a custom distribution, so you +can override just the parts you need to make your own implementation +work. + +=head1 FLOW + +Below is a brief outline when and in which order methods in this +class are called: + + $Class->format_available; # can we use this class on this system? + + $dist->init; # set up custom accessors, etc + $dist->prepare; # find/write meta information + $dist->create; # write the distribution file + $dist->install; # install the distribution file + + $dist->uninstall; # remove the distribution (OPTIONAL) + +=head1 METHODS + +=cut + +=head2 @subs = $Class->methods + +Returns a list of methods that this class implements that you can +override. + +=cut + +sub methods { + return qw[format_available init prepare create install uninstall] +} + +=head2 $bool = $Class->format_available + +This method is called when someone requests a module to be installed +via the superclass. This gives you the opportunity to check if all +the needed requirements to build and install this distribution have +been met. + +For example, you might need a command line program, or a certain perl +module installed to do your job. Now is the time to check. + +Simply return true if the request can proceed and false if it can not. + +The C<CPANPLUS::Dist::Base> implementation always returns true. + +=cut + +sub format_available { return 1 } + + +=head2 $bool = $dist->init + +This method is called just after the new dist object is set up and +before the C<prepare> method is called. This is the time to set up +the object so it can be used with your class. + +For example, you might want to add extra accessors to the C<status> +object, which you might do as follows: + + $dist->status->mk_accessors( qw[my_implementation_accessor] ); + +The C<status> object is implemented as an instance of the +C<Object::Accessor> class. Please refer to its documentation for +details. + +Return true if the initialization was successul, and false if it was +not. + +The C<CPANPLUS::Dist::Base> implementation does not alter your object +and always returns true. + +=cut + +sub init { return 1; } + +=head2 $bool = $dist->prepare + +This runs the preparation step of your distribution. This step is meant +to set up the environment so the C<create> step can create the actual +distribution(file). +A C<prepare> call in the standard C<ExtUtils::MakeMaker> distribution +would, for example, run C<perl Makefile.PL> to find the dependencies +for a distribution. For a C<debian> distribution, this is where you +would write all the metafiles required for the C<dpkg-*> tools. + +The C<CPANPLUS::Dist::Base> implementation simply calls the underlying +distribution class (Typically C<CPANPLUS::Dist::MM> or +C<CPANPLUS::Dist::Build>). + +Sets C<< $dist->status->prepared >> to the return value of this function. +If you override this method, you should make sure to set this value. + +=cut + +sub prepare { + ### just in case you already did a create call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + my $dist_cpan = $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + + $dist->status->prepared( $dist_cpan->prepare( @_ ) ); +} + +=head2 $bool = $dist->create + +This runs the creation step of your distribution. This step is meant +to follow up on the C<prepare> call, that set up your environment so +the C<create> step can create the actual distribution(file). +A C<create> call in the standard C<ExtUtils::MakeMaker> distribution +would, for example, run C<make> and C<make test> to build and test +a distribution. For a C<debian> distribution, this is where you +would create the actual C<.deb> file using C<dpkg>. + +The C<CPANPLUS::Dist::Base> implementation simply calls the underlying +distribution class (Typically C<CPANPLUS::Dist::MM> or +C<CPANPLUS::Dist::Build>). + +Sets C<< $dist->status->dist >> to the location of the created +distribution. +If you override this method, you should make sure to set this value. + +Sets C<< $dist->status->created >> to the return value of this function. +If you override this method, you should make sure to set this value. + +=cut + +sub create { + ### just in case you already did a create call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + my $dist_cpan = $self->status->dist_cpan; + $dist = $self->status->dist if $self->status->dist; + $self->status->dist( $dist ) unless $self->status->dist; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my $format = ref $dist; + + ### make sure to set this variable, if the caller hasn't yet + ### just so we have some clue where the dist left off. + $dist->status->dist( $dist_cpan->status->distdir ) + unless defined $dist->status->dist; + + $dist->status->created( $dist_cpan->create(prereq_format => $format, @_) ); +} + +=head2 $bool = $dist->install + +This runs the install step of your distribution. This step is meant +to follow up on the C<create> call, which prepared a distribution(file) +to install. +A C<create> call in the standard C<ExtUtils::MakeMaker> distribution +would, for example, run C<make install> to copy the distribution files +to their final destination. For a C<debian> distribution, this is where +you would run C<dpkg --install> on the created C<.deb> file. + +The C<CPANPLUS::Dist::Base> implementation simply calls the underlying +distribution class (Typically C<CPANPLUS::Dist::MM> or +C<CPANPLUS::Dist::Build>). + +Sets C<< $dist->status->installed >> to the return value of this function. +If you override this method, you should make sure to set this value. + +=cut + +sub install { + ### just in case you already did a create call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + my $dist_cpan = $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + + $dist->status->installed( $dist_cpan->install( @_ ) ); +} + +=head2 $bool = $dist->uninstall + +This runs the uninstall step of your distribution. This step is meant +to remove the distribution from the file system. +A C<uninstall> call in the standard C<ExtUtils::MakeMaker> distribution +would, for example, run C<make uninstall> to remove the distribution +files the file system. For a C<debian> distribution, this is where you +would run C<dpkg --uninstall PACKAGE>. + +The C<CPANPLUS::Dist::Base> implementation simply calls the underlying +distribution class (Typically C<CPANPLUS::Dist::MM> or +C<CPANPLUS::Dist::Build>). + +Sets C<< $dist->status->uninstalled >> to the return value of this function. +If you override this method, you should make sure to set this value. + +=cut + +sub uninstall { + ### just in case you already did a create call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + my $dist_cpan = $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + + $dist->status->uninstalled( $dist_cpan->uninstall( @_ ) ); +} + +1; + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Build.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Build.pm new file mode 100644 index 00000000000..0f27639cda5 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Build.pm @@ -0,0 +1,836 @@ +package CPANPLUS::Dist::Build; + +use strict; +use warnings; +use vars qw[@ISA $STATUS $VERSION]; +@ISA = qw[CPANPLUS::Dist]; + +use CPANPLUS::Internals::Constants; + +### these constants were exported by CPANPLUS::Internals::Constants +### in previous versions.. they do the same though. If we want to have +### a normal 'use' here, up the dependency to CPANPLUS 0.056 or higher +BEGIN { + require CPANPLUS::Dist::Build::Constants; + CPANPLUS::Dist::Build::Constants->import() + if not __PACKAGE__->can('BUILD') && __PACKAGE__->can('BUILD_DIR'); +} + +use CPANPLUS::Error; + +use Config; +use FileHandle; +use Cwd; +use version; + +use IPC::Cmd qw[run]; +use Params::Check qw[check]; +use Module::Load::Conditional qw[can_load check_install]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +local $Params::Check::VERBOSE = 1; + +$VERSION = '0.46'; + +=pod + +=head1 NAME + +CPANPLUS::Dist::Build - CPANPLUS plugin to install packages that use Build.PL + +=head1 SYNOPSIS + + my $build = CPANPLUS::Dist->new( + format => 'CPANPLUS::Dist::Build', + module => $modobj, + ); + + $build->prepare; # runs Build.PL + $build->create; # runs build && build test + $build->install; # runs build install + + +=head1 DESCRIPTION + +C<CPANPLUS::Dist::Build> is a distribution class for C<Module::Build> +related modules. +Using this package, you can create, install and uninstall perl +modules. It inherits from C<CPANPLUS::Dist>. + +Normal users won't have to worry about the interface to this module, +as it functions transparently as a plug-in to C<CPANPLUS> and will +just C<Do The Right Thing> when it's loaded. + +=head1 ACCESSORS + +=over 4 + +=item C<parent()> + +Returns the C<CPANPLUS::Module> object that parented this object. + +=item C<status()> + +Returns the C<Object::Accessor> object that keeps the status for +this module. + +=back + +=head1 STATUS ACCESSORS + +All accessors can be accessed as follows: + $build->status->ACCESSOR + +=over 4 + +=item C<build_pl ()> + +Location of the Build file. +Set to 0 explicitly if something went wrong. + +=item C<build ()> + +BOOL indicating if the C<Build> command was successful. + +=item C<test ()> + +BOOL indicating if the C<Build test> command was successful. + +=item C<prepared ()> + +BOOL indicating if the C<prepare> call exited succesfully +This gets set after C<perl Build.PL> + +=item C<distdir ()> + +Full path to the directory in which the C<prepare> call took place, +set after a call to C<prepare>. + +=item C<created ()> + +BOOL indicating if the C<create> call exited succesfully. This gets +set after C<Build> and C<Build test>. + +=item C<installed ()> + +BOOL indicating if the module was installed. This gets set after +C<Build install> exits successfully. + +=item uninstalled () + +BOOL indicating if the module was uninstalled properly. + +=item C<_create_args ()> + +Storage of the arguments passed to C<create> for this object. Used +for recursive calls when satisfying prerequisites. + +=item C<_install_args ()> + +Storage of the arguments passed to C<install> for this object. Used +for recursive calls when satisfying prerequisites. + +=back + +=cut + +=head1 METHODS + +=head2 $bool = CPANPLUS::Dist::Build->format_available(); + +Returns a boolean indicating whether or not you can use this package +to create and install modules in your environment. + +=cut + +### check if the format is available ### +sub format_available { + my $mod = "Module::Build"; + unless( can_load( modules => { $mod => '0.2611' } ) ) { + error( loc( "You do not have '%1' -- '%2' not available", + $mod, __PACKAGE__ ) ); + return; + } + + return 1; +} + + +=head2 $bool = $dist->init(); + +Sets up the C<CPANPLUS::Dist::Build> object for use. +Effectively creates all the needed status accessors. + +Called automatically whenever you create a new C<CPANPLUS::Dist> object. + +=cut + +sub init { + my $dist = shift; + my $status = $dist->status; + + $status->mk_accessors(qw[build_pl build test created installed uninstalled + _create_args _install_args _prepare_args + _mb_object _buildflags + ]); + + ### just in case 'format_available' didn't get called + require Module::Build; + + return 1; +} + +=pod + +=head2 $bool = $dist->prepare([perl => '/path/to/perl', buildflags => 'EXTRA=FLAGS', force => BOOL, verbose => BOOL]) + +C<prepare> prepares a distribution, running C<Build.PL> +and establishing any prerequisites this +distribution has. + +The variable C<PERL5_CPANPLUS_IS_EXECUTING> will be set to the full path +of the C<Build.PL> that is being executed. This enables any code inside +the C<Build.PL> to know that it is being installed via CPANPLUS. + +After a succcesfull C<prepare> you may call C<create> to create the +distribution, followed by C<install> to actually install it. + +Returns true on success and false on failure. + +=cut + +sub prepare { + ### just in case you already did a create call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + + ### we're also the cpan_dist, since we don't need to have anything + ### prepared from another installer + $dist = $self->status->dist_cpan if $self->status->dist_cpan; + $self->status->dist_cpan( $dist ) unless $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my $dir; + unless( $dir = $self->status->extract ) { + error( loc( "No dir found to operate on!" ) ); + return; + } + + my $args; + my( $force, $verbose, $buildflags, $perl, $prereq_target, $prereq_format, + $prereq_build ); + { local $Params::Check::ALLOW_UNKNOWN = 1; + my $tmpl = { + force => { default => $conf->get_conf('force'), + store => \$force }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + perl => { default => $^X, store => \$perl }, + buildflags => { default => $conf->get_conf('buildflags'), + store => \$buildflags }, + prereq_target => { default => '', store => \$prereq_target }, + prereq_format => { default => '', + store => \$prereq_format }, + prereq_build => { default => 0, store => \$prereq_build }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + return 1 if $dist->status->prepared && !$force; + + $dist->status->_prepare_args( $args ); + + ### chdir to work directory ### + my $orig = cwd(); + unless( $cb->_chdir( dir => $dir ) ) { + error( loc( "Could not chdir to build directory '%1'", $dir ) ); + return; + } + + ### by now we've loaded module::build, and we're using the API, so + ### it's safe to remove CPANPLUS::inc from our inc path, especially + ### because it can trip up tests run under taint (just like EU::MM). + ### turn off our PERL5OPT so no modules from CPANPLUS::inc get + ### included in make test -- it should build without. + ### also, modules that run in taint mode break if we leave + ### our code ref in perl5opt + ### XXX we've removed the ENV settings from cp::inc, so only need + ### to reset the @INC + #local $ENV{PERL5OPT} = CPANPLUS::inc->original_perl5opt; + #local $ENV{PERL5LIB} = CPANPLUS::inc->original_perl5lib; + #local @INC = CPANPLUS::inc->original_inc; + + ### this will generate warnings under anything lower than M::B 0.2606 + my @buildflags = $dist->_buildflags_as_list( $buildflags ); + $dist->status->_buildflags( $buildflags ); + + my $fail; + RUN: { + # 0.85_01 + ### we resolve 'configure requires' here, so we can run the 'perl + ### Makefile.PL' command + ### XXX for tests: mock f_c_r to something that *can* resolve and + ### something that *doesnt* resolve. Check the error log for ok + ### on this step or failure + ### XXX make a seperate tarball to test for this scenario: simply + ### containing a makefile.pl/build.pl for test purposes? + my $safe_ver = version->new('0.85_01'); + if ( version->new($CPANPLUS::Internals::VERSION) >= $safe_ver ) + { my $configure_requires = $dist->find_configure_requires; + my $ok = $dist->_resolve_prereqs( + format => $prereq_format, + verbose => $verbose, + prereqs => $configure_requires, + target => $prereq_target, + force => $force, + prereq_build => $prereq_build, + ); + + unless( $ok ) { + + #### use $dist->flush to reset the cache ### + error( loc( "Unable to satisfy '%1' for '%2' " . + "-- aborting install", + 'configure_requires', $self->module ) ); + $dist->status->prepared(0); + $fail++; + last RUN; + } + ### end of prereq resolving ### + } + + # Wrap the exception that may be thrown here (should likely be + # done at a much higher level). + my $prep_output; + + my $env = ENV_CPANPLUS_IS_EXECUTING; + local $ENV{$env} = BUILD_PL->( $dir ); + my $run_perl = $conf->get_program('perlwrapper'); + my $cmd = [$perl, $run_perl, BUILD_PL->($dir), @buildflags]; + + unless ( scalar run( command => $cmd, + buffer => \$prep_output, + verbose => $verbose ) + ) { + error( loc( "Build.PL failed: %1", $prep_output ) ); + $fail++; last RUN; + } + + msg( $prep_output, 0 ); + + my $prereqs = $self->status->prereqs; + + $prereqs ||= $dist->_find_prereqs( verbose => $verbose, + dir => $dir, + perl => $perl, + buildflags => $buildflags ); + + } + + ### send out test report? ### + if( $fail and $conf->get_conf('cpantest') ) { + $cb->_send_report( + module => $self, + failed => $fail, + buffer => CPANPLUS::Error->stack_as_string, + verbose => $verbose, + force => $force, + ) or error(loc("Failed to send test report for '%1'", + $self->module ) ); + } + + unless( $cb->_chdir( dir => $orig ) ) { + error( loc( "Could not chdir back to start dir '%1'", $orig ) ); + } + + ### save where we wrote this stuff -- same as extract dir in normal + ### installer circumstances + $dist->status->distdir( $self->status->extract ); + + return $dist->status->prepared( $fail ? 0 : 1 ); +} + +sub _find_prereqs { + my $dist = shift; + my $self = $dist->parent; + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my ($verbose, $dir, $buildflags, $perl); + my $tmpl = { + verbose => { default => $conf->get_conf('verbose'), store => \$verbose }, + dir => { default => $self->status->extract, store => \$dir }, + perl => { default => $^X, store => \$perl }, + buildflags => { default => $conf->get_conf('buildflags'), + store => \$buildflags }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + my $prereqs = {}; + + $prereqs = $dist->find_mymeta_requires() + if $dist->can('find_mymeta_requires'); + + if ( keys %$prereqs ) { + # Ugly hack + } + else { + my $safe_ver = version->new('0.31_03'); + my $content; + PREREQS: { + if ( version->new( $Module::Build::VERSION ) >= $safe_ver and IPC::Cmd->can_capture_buffer ) { + my @buildflags = $dist->_buildflags_as_list( $buildflags ); + + # Use the new Build action 'prereq_data' + my $run_perl = $conf->get_program('perlwrapper'); + + unless ( scalar run( command => [$perl, $run_perl, BUILD->($dir), 'prereq_data', @buildflags], + buffer => \$content, + verbose => 0 ) + ) { + error( loc( "Build 'prereq_data' failed: %1 %2", $!, $content ) ); + #return; + } + else { + last PREREQS; + } + + } + + my $file = File::Spec->catfile( $dir, '_build', 'prereqs' ); + return unless -f $file; + + my $fh = FileHandle->new(); + + unless( $fh->open( $file ) ) { + error( loc( "Cannot open '%1': %2", $file, $! ) ); + return; + } + + $content = do { local $/; <$fh> }; + + } + + return unless $content; + my $bphash = eval $content; + return unless $bphash and ref $bphash eq 'HASH'; + foreach my $type ('requires', 'build_requires') { + next unless $bphash->{$type} and ref $bphash->{$type} eq 'HASH'; + $prereqs->{$_} = $bphash->{$type}->{$_} for keys %{ $bphash->{$type} }; + } + } + # Temporary fix + delete $prereqs->{'perl'}; + + ### allows for a user defined callback to filter the prerequisite + ### list as they see fit, to remove (or add) any prereqs they see + ### fit. The default installed callback will return the hashref in + ### an unmodified form + ### this callback got added after cpanplus 0.0562, so use a 'can' + ### to find out if it's supported. For older versions, we'll just + ### return the hashref as is ourselves. + my $href = $cb->_callbacks->can('filter_prereqs') + ? $cb->_callbacks->filter_prereqs->( $cb, $prereqs ) + : $prereqs; + + $self->status->prereqs( $href ); + + ### make sure it's not the same ref + return { %$href }; +} + +=pod + +=head2 $dist->create([perl => '/path/to/perl', buildflags => 'EXTRA=FLAGS', prereq_target => TARGET, force => BOOL, verbose => BOOL, skiptest => BOOL]) + +C<create> preps a distribution for installation. This means it will +run C<Build> and C<Build test>. +This will also satisfy any prerequisites the module may have. + +If you set C<skiptest> to true, it will skip the C<Build test> stage. +If you set C<force> to true, it will go over all the stages of the +C<Build> process again, ignoring any previously cached results. It +will also ignore a bad return value from C<Build test> and still allow +the operation to return true. + +Returns true on success and false on failure. + +You may then call C<< $dist->install >> on the object to actually +install it. + +=cut + +sub create { + ### just in case you already did a create call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + + ### we're also the cpan_dist, since we don't need to have anything + ### prepared from another installer + $dist = $self->status->dist_cpan if $self->status->dist_cpan; + $self->status->dist_cpan( $dist ) unless $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my $dir; + unless( $dir = $self->status->extract ) { + error( loc( "No dir found to operate on!" ) ); + return; + } + + my $args; + my( $force, $verbose, $buildflags, $skiptest, $prereq_target, + $perl, $prereq_format, $prereq_build); + { local $Params::Check::ALLOW_UNKNOWN = 1; + my $tmpl = { + force => { default => $conf->get_conf('force'), + store => \$force }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + perl => { default => $^X, store => \$perl }, + buildflags => { default => $conf->get_conf('buildflags'), + store => \$buildflags }, + skiptest => { default => $conf->get_conf('skiptest'), + store => \$skiptest }, + prereq_target => { default => '', store => \$prereq_target }, + ### don't set the default format to 'build' -- that is wrong! + prereq_format => { #default => $self->status->installer_type, + default => '', + store => \$prereq_format }, + prereq_build => { default => 0, store => \$prereq_build }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + # restore the state as we have created this already. + if ( $dist->status->created && !$force ) { + ### add this directory to your lib ### + $self->add_to_includepath(); + return 1; + } + + $dist->status->_create_args( $args ); + + ### is this dist prepared? + unless( $dist->status->prepared ) { + error( loc( "You have not successfully prepared a '%2' distribution ". + "yet -- cannot create yet", __PACKAGE__ ) ); + return; + } + + ### chdir to work directory ### + my $orig = cwd(); + unless( $cb->_chdir( dir => $dir ) ) { + error( loc( "Could not chdir to build directory '%1'", $dir ) ); + return; + } + + ### by now we've loaded module::build, and we're using the API, so + ### it's safe to remove CPANPLUS::inc from our inc path, especially + ### because it can trip up tests run under taint (just like EU::MM). + ### turn off our PERL5OPT so no modules from CPANPLUS::inc get + ### included in make test -- it should build without. + ### also, modules that run in taint mode break if we leave + ### our code ref in perl5opt + ### XXX we've removed the ENV settings from cp::inc, so only need + ### to reset the @INC + #local $ENV{PERL5OPT} = CPANPLUS::inc->original_perl5opt; + #local $ENV{PERL5LIB} = CPANPLUS::inc->original_perl5lib; + #local @INC = CPANPLUS::inc->original_inc; + + ### but do it *before* the new_from_context, as M::B seems + ### to be actually running the file... + ### an unshift in the block seems to be ignored.. somehow... + #{ my $lib = $self->best_path_to_module_build; + # unshift @INC, $lib if $lib; + #} + unshift @INC, $self->best_path_to_module_build + if $self->best_path_to_module_build; + + ### this will generate warnings under anything lower than M::B 0.2606 + my @buildflags = $dist->_buildflags_as_list( $buildflags ); + $dist->status->_buildflags( $buildflags ); + + my $fail; my $prereq_fail; my $test_fail; + RUN: { + + my $run_perl = $conf->get_program('perlwrapper'); + + ### this will set the directory back to the start + ### dir, so we must chdir /again/ + my $ok = $dist->_resolve_prereqs( + force => $force, + format => $prereq_format, + verbose => $verbose, + prereqs => $self->status->prereqs, + target => $prereq_target, + prereq_build => $prereq_build, + ); + + unless( $cb->_chdir( dir => $dir ) ) { + error( loc( "Could not chdir to build directory '%1'", $dir ) ); + return; + } + + unless( $ok ) { + #### use $dist->flush to reset the cache ### + error( loc( "Unable to satisfy prerequisites for '%1' " . + "-- aborting install", $self->module ) ); + $dist->status->build(0); + $fail++; $prereq_fail++; + last RUN; + } + + my ($captured, $cmd); + if ( ON_VMS ) { + $cmd = [$perl, BUILD->($dir), @buildflags]; + } + else { + $cmd = [$perl, $run_perl, BUILD->($dir), @buildflags]; + } + + unless ( scalar run( command => $cmd, + buffer => \$captured, + verbose => $verbose ) + ) { + error( loc( "MAKE failed:\n%1", $captured ) ); + $dist->status->build(0); + $fail++; last RUN; + } + + msg( $captured, 0 ); + + $dist->status->build(1); + + ### add this directory to your lib ### + $self->add_to_includepath(); + + ### this buffer will not include what tests failed due to a + ### M::B/Test::Harness bug. Reported as #9793 with patch + ### against 0.2607 on 26/1/2005 + unless( $skiptest ) { + my $test_output; + if ( ON_VMS ) { + $cmd = [$perl, BUILD->($dir), "test", @buildflags]; + } + else { + $cmd = [$perl, $run_perl, BUILD->($dir), "test", @buildflags]; + } + unless ( scalar run( command => $cmd, + buffer => \$test_output, + verbose => $verbose ) + ) { + error( loc( "MAKE TEST failed:\n%1 ", $test_output ) ); + + ### mark specifically *test* failure.. so we dont + ### send success on force... + $test_fail++; + + if( !$force and !$cb->_callbacks->proceed_on_test_failure->( + $self, $@ ) + ) { + $dist->status->test(0); + $fail++; last RUN; + } + + } + else { + msg( loc( "MAKE TEST passed:\n%1", $test_output ), 0 ); + #msg( $test_output, 0 ); + $dist->status->test(1); + } + } + else { + msg(loc("Tests skipped"), $verbose); + } + } + + unless( $cb->_chdir( dir => $orig ) ) { + error( loc( "Could not chdir back to start dir '%1'", $orig ) ); + } + + ### send out test report? ### + if( $conf->get_conf('cpantest') and not $prereq_fail ) { + $cb->_send_report( + module => $self, + failed => $test_fail || $fail, + buffer => CPANPLUS::Error->stack_as_string, + verbose => $verbose, + force => $force, + tests_skipped => $skiptest, + ) or error(loc("Failed to send test report for '%1'", + $self->module ) ); + } + + return $dist->status->created( $fail ? 0 : 1 ); +} + +=head2 $dist->install([verbose => BOOL, perl => /path/to/perl]) + +Actually installs the created dist. + +Returns true on success and false on failure. + +=cut + +sub install { + ### just in case you already did a create call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + + ### we're also the cpan_dist, since we don't need to have anything + ### prepared from another installer + $dist = $self->status->dist_cpan if $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + + my $verbose; my $perl; my $force; my $buildflags; + { local $Params::Check::ALLOW_UNKNOWN = 1; + my $tmpl = { + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + force => { default => $conf->get_conf('force'), + store => \$force }, + buildflags => { default => $conf->get_conf('buildflags'), + store => \$buildflags }, + perl => { default => $^X, store => \$perl }, + }; + + my $args = check( $tmpl, \%hash ) or return; + $dist->status->_install_args( $args ); + } + + my $dir; + unless( $dir = $self->status->extract ) { + error( loc( "No dir found to operate on!" ) ); + return; + } + + my $orig = cwd(); + + unless( $cb->_chdir( dir => $dir ) ) { + error( loc( "Could not chdir to build directory '%1'", $dir ) ); + return; + } + + ### value set and false -- means failure ### + if( defined $self->status->installed && + !$self->status->installed && !$force + ) { + error( loc( "Module '%1' has failed to install before this session " . + "-- aborting install", $self->module ) ); + return; + } + + my $fail; + my @buildflags = $dist->_buildflags_as_list( $buildflags ); + my $run_perl = $conf->get_program('perlwrapper'); + + ### hmm, how is this going to deal with sudo? + ### for now, check effective uid, if it's not root, + ### shell out, otherwise use the method + if( $> ) { + + ### don't worry about loading the right version of M::B anymore + ### the 'new_from_context' already added the 'right' path to + ### M::B at the top of the build.pl + my $cmd; + if ( ON_VMS ) { + $cmd = [$perl, BUILD->($dir), "install", @buildflags]; + } + else { + $cmd = [$perl, $run_perl, BUILD->($dir), "install", @buildflags]; + } + my $sudo = $conf->get_program('sudo'); + unshift @$cmd, $sudo if $sudo; + + + my $buffer; + unless( scalar run( command => $cmd, + buffer => \$buffer, + verbose => $verbose ) + ) { + error(loc("Could not run '%1': %2", 'Build install', $buffer)); + $fail++; + } + } else { + my ($install_output, $cmd); + if ( ON_VMS ) { + $cmd = [$perl, BUILD->($dir), "install", @buildflags]; + } + else { + $cmd = [$perl, $run_perl, BUILD->($dir), "install", @buildflags]; + } + unless( scalar run( command => $cmd, + buffer => \$install_output, + verbose => $verbose ) + ) { + error(loc("Could not run '%1': %2", 'Build install', $install_output)); + $fail++; + } + else { + msg( $install_output, 0 ); + } + } + + + unless( $cb->_chdir( dir => $orig ) ) { + error( loc( "Could not chdir back to start dir '%1'", $orig ) ); + } + + return $dist->status->installed( $fail ? 0 : 1 ); +} + +### returns the string 'foo=bar --zot quux' +### as the list 'foo=bar', '--zot', 'qux' +sub _buildflags_as_list { + my $self = shift; + my $flags = shift or return; + + return Module::Build->split_like_shell($flags); +} + +=head1 AUTHOR + +Originally by Jos Boumans E<lt>kane@cpan.orgE<gt>. Brought to working +condition by Ken Williams E<lt>kwilliams@cpan.orgE<gt>. + +Other hackery and currently maintained by Chris C<BinGOs> Williams ( no relation ). E<lt>bingos@cpan.orgE<gt>. + +=head1 LICENSE + +The CPAN++ interface (of which this module is a part of) is +copyright (c) 2001, 2002, 2003, 2004, 2005 Jos Boumans E<lt>kane@cpan.orgE<gt>. +All rights reserved. + +This library is free software; +you may redistribute and/or modify it under the same +terms as Perl itself. + +=cut + +qq[Putting the Module::Build into CPANPLUS]; + + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: + diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Build/Constants.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Build/Constants.pm new file mode 100644 index 00000000000..1ac02108e44 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Build/Constants.pm @@ -0,0 +1,69 @@ +package CPANPLUS::Dist::Build::Constants; + +use strict; +use warnings; +use File::Spec; + +BEGIN { + + require Exporter; + use vars qw[$VERSION @ISA @EXPORT]; + + $VERSION = '0.46'; + @ISA = qw[Exporter]; + @EXPORT = qw[ BUILD_DIR BUILD ]; +} + + +use constant BUILD_DIR => sub { return @_ + ? File::Spec->catdir($_[0], '_build') + : '_build'; + }; +use constant BUILD => sub { my $file = @_ + ? File::Spec->catfile($_[0], 'Build') + : 'Build'; + + ### on VMS, '.com' is appended when + ### creating the Build file + $file .= '.com' if $^O eq 'VMS'; + + return $file; + }; + +1; + +=head1 NAME + +CPANPLUS::Dist::Build::Constants - Constants for CPANPLUS::Dist::Build + +=head1 SYNOPSIS + + use CPANPLUS::Dist::Build::Constants; + +=head1 DESCRIPTION + +CPANPLUS::Dist::Build::Constants provides some constants required by L<CPANPLUS::Dist::Build>. + +=head1 AUTHOR + +Originally by Jos Boumans E<lt>kane@cpan.orgE<gt>. Brought to working +condition and currently maintained by Ken Williams E<lt>kwilliams@cpan.orgE<gt>. + +=head1 LICENSE + +The CPAN++ interface (of which this module is a part of) is +copyright (c) 2001, 2002, 2003, 2004, 2005 Jos Boumans E<lt>kane@cpan.orgE<gt>. +All rights reserved. + +This library is free software; +you may redistribute and/or modify it under the same +terms as Perl itself. + +=cut + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/MM.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/MM.pm new file mode 100644 index 00000000000..be65cd43cc8 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/MM.pm @@ -0,0 +1,1007 @@ +package CPANPLUS::Dist::MM; + +use warnings; +use strict; +use vars qw[@ISA $STATUS]; +use base 'CPANPLUS::Dist::Base'; + +use CPANPLUS::Internals::Constants; +use CPANPLUS::Internals::Constants::Report; +use CPANPLUS::Error; +use FileHandle; +use Cwd; + +use IPC::Cmd qw[run]; +use Params::Check qw[check]; +use File::Basename qw[dirname]; +use Module::Load::Conditional qw[can_load check_install]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +local $Params::Check::VERBOSE = 1; + +=pod + +=head1 NAME + +CPANPLUS::Dist::MM + +=head1 SYNOPSIS + + $mm = CPANPLUS::Dist::MM->new( module => $modobj ); + + $mm->create; # runs make && make test + $mm->install; # runs make install + + +=head1 DESCRIPTION + +C<CPANPLUS::Dist::MM> is a distribution class for MakeMaker related +modules. +Using this package, you can create, install and uninstall perl +modules. It inherits from C<CPANPLUS::Dist>. + +=head1 ACCESSORS + +=over 4 + +=item parent() + +Returns the C<CPANPLUS::Module> object that parented this object. + +=item status() + +Returns the C<Object::Accessor> object that keeps the status for +this module. + +=back + +=head1 STATUS ACCESSORS + +All accessors can be accessed as follows: + $mm->status->ACCESSOR + +=over 4 + +=item makefile () + +Location of the Makefile (or Build file). +Set to 0 explicitly if something went wrong. + +=item make () + +BOOL indicating if the C<make> (or C<Build>) command was successful. + +=item test () + +BOOL indicating if the C<make test> (or C<Build test>) command was +successful. + +=item prepared () + +BOOL indicating if the C<prepare> call exited succesfully +This gets set after C<perl Makefile.PL> + +=item distdir () + +Full path to the directory in which the C<prepare> call took place, +set after a call to C<prepare>. + +=item created () + +BOOL indicating if the C<create> call exited succesfully. This gets +set after C<make> and C<make test>. + +=item installed () + +BOOL indicating if the module was installed. This gets set after +C<make install> (or C<Build install>) exits successfully. + +=item uninstalled () + +BOOL indicating if the module was uninstalled properly. + +=item _create_args () + +Storage of the arguments passed to C<create> for this object. Used +for recursive calls when satisfying prerequisites. + +=item _install_args () + +Storage of the arguments passed to C<install> for this object. Used +for recursive calls when satisfying prerequisites. + +=back + +=cut + +=head1 METHODS + +=head2 $bool = $dist->format_available(); + +Returns a boolean indicating whether or not you can use this package +to create and install modules in your environment. + +=cut + +### check if the format is available ### +sub format_available { + my $dist = shift; + + ### we might be called as $class->format_available =/ + require CPANPLUS::Internals; + my $cb = CPANPLUS::Internals->_retrieve_id( + CPANPLUS::Internals->_last_id ); + my $conf = $cb->configure_object; + + my $mod = "ExtUtils::MakeMaker"; + unless( can_load( modules => { $mod => 0.0 } ) ) { + error( loc( "You do not have '%1' -- '%2' not available", + $mod, __PACKAGE__ ) ); + return; + } + + for my $pgm ( qw[make] ) { + unless( $conf->get_program( $pgm ) ) { + error(loc( + "You do not have '%1' in your path -- '%2' not available\n" . + "Please check your config entry for '%1'", + $pgm, __PACKAGE__ , $pgm + )); + return; + } + } + + return 1; +} + +=pod $bool = $dist->init(); + +Sets up the C<CPANPLUS::Dist::MM> object for use. +Effectively creates all the needed status accessors. + +Called automatically whenever you create a new C<CPANPLUS::Dist> object. + +=cut + +sub init { + my $dist = shift; + my $status = $dist->status; + + $status->mk_accessors(qw[makefile make test created installed uninstalled + bin_make _prepare_args _create_args _install_args] + ); + + return 1; +} + +=pod $bool = $dist->prepare([perl => '/path/to/perl', makemakerflags => 'EXTRA=FLAGS', force => BOOL, verbose => BOOL]) + +C<prepare> preps a distribution for installation. This means it will +run C<perl Makefile.PL> and determine what prerequisites this distribution +declared. + +If you set C<force> to true, it will go over all the stages of the +C<prepare> process again, ignoring any previously cached results. + +When running C<perl Makefile.PL>, the environment variable +C<PERL5_CPANPLUS_IS_EXECUTING> will be set to the full path of the +C<Makefile.PL> that is being executed. This enables any code inside +the C<Makefile.PL> to know that it is being installed via CPANPLUS. + +Returns true on success and false on failure. + +You may then call C<< $dist->create >> on the object to create the +installable files. + +=cut + +sub prepare { + ### just in case you already did a create call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + + ### we're also the cpan_dist, since we don't need to have anything + ### prepared + $dist = $self->status->dist_cpan if $self->status->dist_cpan; + $self->status->dist_cpan( $dist ) unless $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my $dir; + unless( $dir = $self->status->extract ) { + error( loc( "No dir found to operate on!" ) ); + return; + } + + my $args; + my( $force, $verbose, $perl, @mmflags, $prereq_target, $prereq_format, + $prereq_build ); + { local $Params::Check::ALLOW_UNKNOWN = 1; + my $tmpl = { + perl => { default => $^X, store => \$perl }, + makemakerflags => { default => + $conf->get_conf('makemakerflags') || '', + store => \$mmflags[0] }, + force => { default => $conf->get_conf('force'), + store => \$force }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + prereq_target => { default => '', store => \$prereq_target }, + prereq_format => { default => '', + store => \$prereq_format }, + prereq_build => { default => 0, store => \$prereq_build }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + + ### maybe we already ran a create on this object? ### + return 1 if $dist->status->prepared && !$force; + + ### store the arguments, so ->install can use them in recursive loops ### + $dist->status->_prepare_args( $args ); + + ### chdir to work directory ### + my $orig = cwd(); + unless( $cb->_chdir( dir => $dir ) ) { + error( loc( "Could not chdir to build directory '%1'", $dir ) ); + return; + } + + my $fail; + RUN: { + + ### we resolve 'configure requires' here, so we can run the 'perl + ### Makefile.PL' command + ### XXX for tests: mock f_c_r to something that *can* resolve and + ### something that *doesnt* resolve. Check the error log for ok + ### on this step or failure + ### XXX make a seperate tarball to test for this scenario: simply + ### containing a makefile.pl/build.pl for test purposes? + { my $configure_requires = $dist->find_configure_requires; + my $ok = $dist->_resolve_prereqs( + format => $prereq_format, + verbose => $verbose, + prereqs => $configure_requires, + target => $prereq_target, + force => $force, + prereq_build => $prereq_build, + ); + + unless( $ok ) { + + #### use $dist->flush to reset the cache ### + error( loc( "Unable to satisfy '%1' for '%2' " . + "-- aborting install", + 'configure_requires', $self->module ) ); + $dist->status->prepared(0); + $fail++; + last RUN; + } + ### end of prereq resolving ### + } + + + + ### don't run 'perl makefile.pl' again if there's a makefile already + if( -e MAKEFILE->() && (-M MAKEFILE->() < -M $dir) && !$force ) { + msg(loc("'%1' already exists, not running '%2 %3' again ". + " unless you force", + MAKEFILE->(), $perl, MAKEFILE_PL->() ), $verbose ); + + } else { + unless( -e MAKEFILE_PL->() ) { + msg(loc("No '%1' found - attempting to generate one", + MAKEFILE_PL->() ), $verbose ); + + $dist->write_makefile_pl( + verbose => $verbose, + force => $force + ); + + ### bail out if there's no makefile.pl ### + unless( -e MAKEFILE_PL->() ) { + error( loc( "Could not find '%1' - cannot continue", + MAKEFILE_PL->() ) ); + + ### mark that we screwed up ### + $dist->status->makefile(0); + $fail++; last RUN; + } + } + + ### you can turn off running this verbose by changing + ### the config setting below, although it is really not + ### recommended + my $run_verbose = $verbose || + $conf->get_conf('allow_build_interactivity') || + 0; + + ### this makes MakeMaker use defaults if possible, according + ### to schwern. See ticket 8047 for details. + local $ENV{PERL_MM_USE_DEFAULT} = 1 unless $run_verbose; + + ### turn off our PERL5OPT so no modules from CPANPLUS::inc get + ### included in the makefile.pl -- it should build without + ### also, modules that run in taint mode break if we leave + ### our code ref in perl5opt + ### XXX we've removed the ENV settings from cp::inc, so only need + ### to reset the @INC + #local $ENV{PERL5OPT} = CPANPLUS::inc->original_perl5opt || ''; + + ### make sure it's a string, so that mmflags that have more than + ### one key value pair are passed as is, rather than as: + ### perl Makefile.PL "key=val key=>val" + + + #### XXX this needs to be the absolute path to the Makefile.PL + ### since cpanp-run-perl uses 'do' to execute the file, and do() + ### checks your @INC.. so, if there's _another_ makefile.pl in + ### your @INC, it will execute that one... + my $makefile_pl = MAKEFILE_PL->( $cb->_safe_path( path => $dir ) ); + + ### setting autoflush to true fixes issue from rt #8047 + ### XXX this means that we need to keep the path to CPANPLUS + ### in @INC, stopping us from resolving dependencies on CPANPLUS + ### at bootstrap time properly. + + ### XXX this fails under ipc::run due to the extra quotes, + ### but it works in ipc::open3. however, ipc::open3 doesn't work + ### on win32/cygwin. XXX TODO get a windows box and sort this out + # my $cmd = qq[$perl -MEnglish -le ] . + # QUOTE_PERL_ONE_LINER->( + # qq[\$OUTPUT_AUTOFLUSH++,do(q($makefile_pl))] + # ) + # . $mmflags; + + # my $flush = OPT_AUTOFLUSH; + # my $cmd = "$perl $flush $makefile_pl $mmflags"; + + my $run_perl = $conf->get_program('perlwrapper'); + my $cmd = [$perl, $run_perl, $makefile_pl, @mmflags]; + + ### set ENV var to tell underlying code this is what we're + ### executing. + my $captured; + my $rv = do { + my $env = ENV_CPANPLUS_IS_EXECUTING; + local $ENV{$env} = $makefile_pl; + scalar run( command => $cmd, + buffer => \$captured, + verbose => $run_verbose, # may be interactive + ); + }; + + unless( $rv ) { + error( loc( "Could not run '%1 %2': %3 -- cannot continue", + $perl, MAKEFILE_PL->(), $captured ) ); + + $dist->status->makefile(0); + $fail++; last RUN; + } + + ### put the output on the stack, don't print it + msg( $captured, 0 ); + } + + ### so, nasty feature in Module::Build, that when a Makefile.PL + ### is a disguised Build.PL, it generates a Build file, not a + ### Makefile. this breaks everything :( see rt bug #19741 + if( not -e MAKEFILE->( $dir ) and -e BUILD_PL->( $dir ) ) { + error(loc( + "We just ran '%1' without errors, but no '%2' is ". + "present. However, there is a '%3' file, so this may ". + "be related to bug #19741 in %4, which describes a ". + "fake '%5' which generates a '%6' file instead of a '%7'. ". + "You could try to work around this issue by setting '%8' ". + "to false and trying again. This will attempt to use the ". + "'%9' instead.", + "$^X ".MAKEFILE_PL->(), MAKEFILE->(), BUILD_PL->(), + 'Module::Build', MAKEFILE_PL->(), 'Build', MAKEFILE->(), + 'prefer_makefile', BUILD_PL->() + )); + + $fail++, last RUN; + } + + ### if we got here, we managed to make a 'makefile' ### + $dist->status->makefile( MAKEFILE->($dir) ); + + ### start resolving prereqs ### + my $prereqs = $self->status->prereqs; + + ### a hashref of prereqs on success, undef on failure ### + $prereqs ||= $dist->_find_prereqs( + verbose => $verbose, + file => $dist->status->makefile + ); + + unless( $prereqs ) { + error( loc( "Unable to scan '%1' for prereqs", + $dist->status->makefile ) ); + + $fail++; last RUN; + } + } + + unless( $cb->_chdir( dir => $orig ) ) { + error( loc( "Could not chdir back to start dir '%1'", $orig ) ); + } + + ### save where we wrote this stuff -- same as extract dir in normal + ### installer circumstances + $dist->status->distdir( $self->status->extract ); + + return $dist->status->prepared( $fail ? 0 : 1); +} + +=pod + +=head2 $href = $dist->_find_prereqs( file => '/path/to/Makefile', [verbose => BOOL]) + +Parses a C<Makefile> for C<PREREQ_PM> entries and distills from that +any prerequisites mentioned in the C<Makefile> + +Returns a hash with module-version pairs on success and false on +failure. + +=cut + +sub _find_prereqs { + my $dist = shift; + my $self = $dist->parent; + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my ($verbose, $file); + my $tmpl = { + verbose => { default => $conf->get_conf('verbose'), store => \$verbose }, + file => { required => 1, allow => FILE_READABLE, store => \$file }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + ### see if we got prereqs from MYMETA + my $prereqs = $dist->find_mymeta_requires(); + + ### we found some prereqs, we'll trust MYMETA + ### but we do need to run it through the callback + return $cb->_callbacks->filter_prereqs->( $cb, $prereqs ) if keys %$prereqs; + + my $fh = FileHandle->new(); + unless( $fh->open( $file ) ) { + error( loc( "Cannot open '%1': %2", $file, $! ) ); + return; + } + + my %p; + while( local $_ = <$fh> ) { + my ($found) = m|^[\#]\s+PREREQ_PM\s+=>\s+(.+)|; + + next unless $found; + + while( $found =~ m/(?:\s)([\w\:]+)=>(?:q\[(.*?)\],?|undef)/g ) { + if( defined $p{$1} ) { + my $ver = $cb->_version_to_number(version => $2); + $p{$1} = $ver + if $cb->_vcmp( $ver, $p{$1} ) > 0; + } + else { + $p{$1} = $cb->_version_to_number(version => $2); + } + } + last; + } + + my $href = $cb->_callbacks->filter_prereqs->( $cb, \%p ); + + $self->status->prereqs( $href ); + + ### just to make sure it's not the same reference ### + return { %$href }; +} + +=pod + +=head2 $bool = $dist->create([perl => '/path/to/perl', make => '/path/to/make', makeflags => 'EXTRA=FLAGS', prereq_target => TARGET, skiptest => BOOL, force => BOOL, verbose => BOOL]) + +C<create> creates the files necessary for installation. This means +it will run C<make> and C<make test>. This will also scan for and +attempt to satisfy any prerequisites the module may have. + +If you set C<skiptest> to true, it will skip the C<make test> stage. +If you set C<force> to true, it will go over all the stages of the +C<make> process again, ignoring any previously cached results. It +will also ignore a bad return value from C<make test> and still allow +the operation to return true. + +Returns true on success and false on failure. + +You may then call C<< $dist->install >> on the object to actually +install it. + +=cut + +sub create { + ### just in case you already did a create call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + + ### we're also the cpan_dist, since we don't need to have anything + ### prepared + $dist = $self->status->dist_cpan if $self->status->dist_cpan; + $self->status->dist_cpan( $dist ) unless $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my $dir; + unless( $dir = $self->status->extract ) { + error( loc( "No dir found to operate on!" ) ); + return; + } + + my $args; + my( $force, $verbose, $make, $makeflags, $skiptest, $prereq_target, $perl, + @mmflags, $prereq_format, $prereq_build); + { local $Params::Check::ALLOW_UNKNOWN = 1; + my $tmpl = { + perl => { default => $^X, store => \$perl }, + force => { default => $conf->get_conf('force'), + store => \$force }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + make => { default => $conf->get_program('make'), + store => \$make }, + makeflags => { default => $conf->get_conf('makeflags'), + store => \$makeflags }, + skiptest => { default => $conf->get_conf('skiptest'), + store => \$skiptest }, + prereq_target => { default => '', store => \$prereq_target }, + ### don't set the default prereq format to 'makemaker' -- wrong! + prereq_format => { #default => $self->status->installer_type, + default => '', + store => \$prereq_format }, + prereq_build => { default => 0, store => \$prereq_build }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + ### maybe we already ran a create on this object? + ### make sure we add to include path again, just in case we came from + ### ->save_state, at which point we need to restore @INC/$PERL5LIB + if( $dist->status->created && !$force ) { + $self->add_to_includepath; + return 1; + } + + ### store the arguments, so ->install can use them in recursive loops ### + $dist->status->_create_args( $args ); + + unless( $dist->status->prepared ) { + error( loc( "You have not successfully prepared a '%2' distribution ". + "yet -- cannot create yet", __PACKAGE__ ) ); + return; + } + + + ### chdir to work directory ### + my $orig = cwd(); + unless( $cb->_chdir( dir => $dir ) ) { + error( loc( "Could not chdir to build directory '%1'", $dir ) ); + return; + } + + my $fail; my $prereq_fail; my $test_fail; + RUN: { + ### this will set the directory back to the start + ### dir, so we must chdir /again/ + my $ok = $dist->_resolve_prereqs( + format => $prereq_format, + verbose => $verbose, + prereqs => $self->status->prereqs, + target => $prereq_target, + force => $force, + prereq_build => $prereq_build, + ); + + unless( $cb->_chdir( dir => $dir ) ) { + error( loc( "Could not chdir to build directory '%1'", $dir ) ); + return; + } + + unless( $ok ) { + + #### use $dist->flush to reset the cache ### + error( loc( "Unable to satisfy prerequisites for '%1' " . + "-- aborting install", $self->module ) ); + $dist->status->make(0); + $fail++; $prereq_fail++; + last RUN; + } + ### end of prereq resolving ### + + my $captured; + + ### 'make' section ### + if( -d BLIB->($dir) && (-M BLIB->($dir) < -M $dir) && !$force ) { + msg(loc("Already ran '%1' for this module [%2] -- " . + "not running again unless you force", + $make, $self->module ), $verbose ); + } else { + unless(scalar run( command => [$make, $makeflags], + buffer => \$captured, + verbose => $verbose ) + ) { + error( loc( "MAKE failed: %1 %2", $!, $captured ) ); + $dist->status->make(0); + $fail++; last RUN; + } + + ### put the output on the stack, don't print it + msg( $captured, 0 ); + + $dist->status->make(1); + + ### add this directory to your lib ### + $self->add_to_includepath(); + + ### dont bail out here, there's a conditional later on + #last RUN if $skiptest; + } + + ### 'make test' section ### + unless( $skiptest ) { + + ### turn off our PERL5OPT so no modules from CPANPLUS::inc get + ### included in make test -- it should build without + ### also, modules that run in taint mode break if we leave + ### our code ref in perl5opt + ### XXX CPANPLUS::inc functionality is now obsolete. + #local $ENV{PERL5OPT} = CPANPLUS::inc->original_perl5opt || ''; + + ### you can turn off running this verbose by changing + ### the config setting below, although it is really not + ### recommended + my $run_verbose = + $verbose || + $conf->get_conf('allow_build_interactivity') || + 0; + + ### XXX need to add makeflags here too? + ### yes, but they should really be split out -- see bug #4143 + if( scalar run( + command => [$make, 'test', $makeflags], + buffer => \$captured, + verbose => $run_verbose, + ) ) { + ### tests might pass because it doesn't have any tests defined + ### log this occasion non-verbosely, so our test reporter can + ### pick up on this + if ( NO_TESTS_DEFINED->( $captured ) ) { + msg( NO_TESTS_DEFINED->( $captured ), 0 ) + } else { + msg( loc( "MAKE TEST passed: %1", $captured ), 0 ); + } + + $dist->status->test(1); + } else { + error( loc( "MAKE TEST failed: %1 %2", $!, $captured ) ); + + ### send out error report here? or do so at a higher level? + ### --higher level --kane. + $dist->status->test(0); + + ### mark specifically *test* failure.. so we dont + ### send success on force... + $test_fail++; + + if( !$force and !$cb->_callbacks->proceed_on_test_failure->( + $self, $captured ) + ) { + $fail++; last RUN; + } + } + } + } #</RUN> + + unless( $cb->_chdir( dir => $orig ) ) { + error( loc( "Could not chdir back to start dir '%1'", $orig ) ); + } + + ### send out test report? + ### only do so if the failure is this module, not its prereq + if( $conf->get_conf('cpantest') and not $prereq_fail) { + $cb->_send_report( + module => $self, + failed => $test_fail || $fail, + buffer => CPANPLUS::Error->stack_as_string, + verbose => $verbose, + force => $force, + ) or error(loc("Failed to send test report for '%1'", + $self->module ) ); + } + + return $dist->status->created( $fail ? 0 : 1); +} + +=pod + +=head2 $bool = $dist->install([make => '/path/to/make', makemakerflags => 'EXTRA=FLAGS', force => BOOL, verbose => BOOL]) + +C<install> runs the following command: + make install + +Returns true on success, false on failure. + +=cut + +sub install { + + ### just in case you did the create with ANOTHER dist object linked + ### to the same module object + my $dist = shift(); + my $self = $dist->parent; + $dist = $self->status->dist_cpan if $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + + unless( $dist->status->created ) { + error(loc("You have not successfully created a '%2' distribution yet " . + "-- cannot install yet", __PACKAGE__ )); + return; + } + + my $dir; + unless( $dir = $self->status->extract ) { + error( loc( "No dir found to operate on!" ) ); + return; + } + + my $args; + my($force,$verbose,$make,$makeflags); + { local $Params::Check::ALLOW_UNKNOWN = 1; + my $tmpl = { + force => { default => $conf->get_conf('force'), + store => \$force }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + make => { default => $conf->get_program('make'), + store => \$make }, + makeflags => { default => $conf->get_conf('makeflags'), + store => \$makeflags }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + ### value set and false -- means failure ### + if( defined $self->status->installed && + !$self->status->installed && !$force + ) { + error( loc( "Module '%1' has failed to install before this session " . + "-- aborting install", $self->module ) ); + return; + } + + + $dist->status->_install_args( $args ); + + my $orig = cwd(); + unless( $cb->_chdir( dir => $dir ) ) { + error( loc( "Could not chdir to build directory '%1'", $dir ) ); + return; + } + + my $fail; my $captured; + + ### 'make install' section ### + ### XXX need makeflags here too? + ### yes, but they should really be split out.. see bug #4143 + my $cmd = [$make, 'install', $makeflags]; + my $sudo = $conf->get_program('sudo'); + unshift @$cmd, $sudo if $sudo and $>; + + $cb->flush('lib'); + unless(scalar run( command => $cmd, + verbose => $verbose, + buffer => \$captured, + ) ) { + error( loc( "MAKE INSTALL failed: %1 %2", $!, $captured ) ); + $fail++; + } + + ### put the output on the stack, don't print it + msg( $captured, 0 ); + + unless( $cb->_chdir( dir => $orig ) ) { + error( loc( "Could not chdir back to start dir '%1'", $orig ) ); + } + + return $dist->status->installed( $fail ? 0 : 1 ); + +} + +=pod + +=head2 $bool = $dist->write_makefile_pl([force => BOOL, verbose => BOOL]) + +This routine can write a C<Makefile.PL> from the information in a +module object. It is used to write a C<Makefile.PL> when the original +author forgot it (!!). + +Returns 1 on success and false on failure. + +The file gets written to the directory the module's been extracted +to. + +=cut + +sub write_makefile_pl { + ### just in case you already did a call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + $dist = $self->status->dist_cpan if $self->status->dist_cpan; + $self->status->dist_cpan( $dist ) unless $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my $dir; + unless( $dir = $self->status->extract ) { + error( loc( "No dir found to operate on!" ) ); + return; + } + + my ($force, $verbose); + my $tmpl = { + force => { default => $conf->get_conf('force'), + store => \$force }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + my $file = MAKEFILE_PL->($dir); + if( -s $file && !$force ) { + msg(loc("Already created '%1' - not doing so again without force", + $file ), $verbose ); + return 1; + } + + ### due to a bug with AS perl 5.8.4 built 810 (and maybe others) + ### opening files with content in them already does nasty things; + ### seek to pos 0 and then print, but not truncating the file + ### bug reported to activestate on 19 sep 2004: + ### http://bugs.activestate.com/show_bug.cgi?id=34051 + unlink $file if $force; + + my $fh = new FileHandle; + unless( $fh->open( ">$file" ) ) { + error( loc( "Could not create file '%1': %2", $file, $! ) ); + return; + } + + my $mf = MAKEFILE_PL->(); + my $name = $self->module; + my $version = $self->version; + my $author = $self->author->author; + my $href = $self->status->prereqs; + my $prereqs = join ",\n", map { + (' ' x 25) . "'$_'\t=> '$href->{$_}'" + } keys %$href; + $prereqs ||= ''; # just in case there are none; + + print $fh qq| + ### Auto-generated $mf by CPANPLUS ### + + use ExtUtils::MakeMaker; + + WriteMakefile( + NAME => '$name', + VERSION => '$version', + AUTHOR => '$author', + PREREQ_PM => { +$prereqs + }, + ); + \n|; + + $fh->close; + return 1; +} + +sub dist_dir { + ### just in case you already did a call for this module object + ### just via a different dist object + my $dist = shift; + my $self = $dist->parent; + $dist = $self->status->dist_cpan if $self->status->dist_cpan; + $self->status->dist_cpan( $dist ) unless $self->status->dist_cpan; + + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my $make; my $verbose; + { local $Params::Check::ALLOW_UNKNOWN = 1; + my $tmpl = { + make => { default => $conf->get_program('make'), + store => \$make }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + }; + + check( $tmpl, \%hash ) or return; + } + + + my $dir; + unless( $dir = $self->status->extract ) { + error( loc( "No dir found to operate on!" ) ); + return; + } + + ### chdir to work directory ### + my $orig = cwd(); + unless( $cb->_chdir( dir => $dir ) ) { + error( loc( "Could not chdir to build directory '%1'", $dir ) ); + return; + } + + my $fail; my $distdir; + TRY: { + $dist->prepare( @_ ) or (++$fail, last TRY); + + + my $captured; + unless(scalar run( command => [$make, 'distdir'], + buffer => \$captured, + verbose => $verbose ) + ) { + error( loc( "MAKE DISTDIR failed: %1 %2", $!, $captured ) ); + ++$fail, last TRY; + } + + ### /path/to/Foo-Bar-1.2/Foo-Bar-1.2 + $distdir = File::Spec->catdir( $dir, $self->package_name . '-' . + $self->package_version ); + + unless( -d $distdir ) { + error(loc("Do not know where '%1' got created", 'distdir')); + ++$fail, last TRY; + } + } + + unless( $cb->_chdir( dir => $orig ) ) { + error( loc( "Could not chdir to start directory '%1'", $orig ) ); + return; + } + + return if $fail; + return $distdir; +} + + +1; + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Sample.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Sample.pm new file mode 100644 index 00000000000..0b0939208ff --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Dist/Sample.pm @@ -0,0 +1,16 @@ +package CPANPLUS::Dist::Sample; + +=pod + +=head1 NAME + +CPANPLUS::Dist::Sample -- Sample code to create your own Dist::* plugin + +=head1 Description. + +This document is B<Obsolete>. Please read the documentation and code +in C<CPANPLUS::Dist::Base>. + +=cut + +1; diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Error.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Error.pm new file mode 100644 index 00000000000..38710a8a857 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Error.pm @@ -0,0 +1,201 @@ +package CPANPLUS::Error; + +use strict; + +use Log::Message private => 0;; + +=pod + +=head1 NAME + +CPANPLUS::Error + +=head1 SYNOPSIS + + use CPANPLUS::Error qw[cp_msg cp_error]; + +=head1 DESCRIPTION + +This module provides the error handling code for the CPANPLUS +libraries, and is mainly intended for internal use. + +=head1 FUNCTIONS + +=head2 cp_msg("message string" [,VERBOSE]) + +Records a message on the stack, and prints it to C<STDOUT> (or actually +C<$MSG_FH>, see the C<GLOBAL VARIABLES> section below), if the +C<VERBOSE> option is true. +The C<VERBOSE> option defaults to false. + +=head2 msg() + +An alias for C<cp_msg>. + +=head2 cp_error("error string" [,VERBOSE]) + +Records an error on the stack, and prints it to C<STDERR> (or actually +C<$ERROR_FH>, see the C<GLOBAL VARIABLES> sections below), if the +C<VERBOSE> option is true. +The C<VERBOSE> options defaults to true. + +=head2 error() + +An alias for C<cp_error>. + +=head1 CLASS METHODS + +=head2 CPANPLUS::Error->stack() + +Retrieves all the items on the stack. Since C<CPANPLUS::Error> is +implemented using C<Log::Message>, consult its manpage for the +function C<retrieve> to see what is returned and how to use the items. + +=head2 CPANPLUS::Error->stack_as_string([TRACE]) + +Returns the whole stack as a printable string. If the C<TRACE> option is +true all items are returned with C<Carp::longmess> output, rather than +just the message. +C<TRACE> defaults to false. + +=head2 CPANPLUS::Error->flush() + +Removes all the items from the stack and returns them. Since +C<CPANPLUS::Error> is implemented using C<Log::Message>, consult its +manpage for the function C<retrieve> to see what is returned and how +to use the items. + +=cut + +BEGIN { + use Exporter; + use Params::Check qw[check]; + use vars qw[@EXPORT @ISA $ERROR_FH $MSG_FH]; + + @ISA = 'Exporter'; + @EXPORT = qw[cp_error cp_msg error msg]; + + my $log = new Log::Message; + + for my $func ( @EXPORT ) { + no strict 'refs'; + + my $prefix = 'cp_'; + my $name = $func; + $name =~ s/^$prefix//g; + + *$func = sub { + my $msg = shift; + + ### no point storing non-messages + return unless defined $msg; + + $log->store( + message => $msg, + tag => uc $name, + level => $prefix . $name, + extra => [@_] + ); + }; + } + + sub flush { + return reverse $log->flush; + } + + sub stack { + return $log->retrieve( chrono => 1 ); + } + + sub stack_as_string { + my $class = shift; + my $trace = shift() ? 1 : 0; + + return join $/, map { + '[' . $_->tag . '] [' . $_->when . '] ' . + ($trace ? $_->message . ' ' . $_->longmess + : $_->message); + } __PACKAGE__->stack; + } +} + +=head1 GLOBAL VARIABLES + +=over 4 + +=item $ERROR_FH + +This is the filehandle all the messages sent to C<error()> are being +printed. This defaults to C<*STDERR>. + +=item $MSG_FH + +This is the filehandle all the messages sent to C<msg()> are being +printed. This default to C<*STDOUT>. + +=cut +local $| = 1; +$ERROR_FH = \*STDERR; +$MSG_FH = \*STDOUT; + +package Log::Message::Handlers; +use Carp (); + +{ + + sub cp_msg { + my $self = shift; + my $verbose = shift; + + ### so you don't want us to print the msg? ### + return if defined $verbose && $verbose == 0; + + my $old_fh = select $CPANPLUS::Error::MSG_FH; + + print '['. $self->tag . '] ' . $self->message . "\n"; + select $old_fh; + + return; + } + + sub cp_error { + my $self = shift; + my $verbose = shift; + + ### so you don't want us to print the error? ### + return if defined $verbose && $verbose == 0; + + my $old_fh = select $CPANPLUS::Error::ERROR_FH; + + ### is only going to be 1 for now anyway ### + ### C::I may not be loaded, so do a can() check first + my $cb = CPANPLUS::Internals->can('_return_all_objects') + ? (CPANPLUS::Internals->_return_all_objects)[0] + : undef; + + ### maybe we didn't initialize an internals object (yet) ### + my $debug = $cb ? $cb->configure_object->get_conf('debug') : 0; + my $msg = '['. $self->tag . '] ' . $self->message . "\n"; + + ### i'm getting this warning in the test suite: + ### Ambiguous call resolved as CORE::warn(), qualify as such or + ### use & at CPANPLUS/Error.pm line 57. + ### no idea where it's coming from, since there's no 'sub warn' + ### anywhere to be found, but i'll mark it explicitly nonetheless + ### --kane + print $debug ? Carp::shortmess($msg) : $msg . "\n"; + + select $old_fh; + + return; + } +} + +1; + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/FAQ.pod b/Master/tlpkg/tlperl/lib/CPANPLUS/FAQ.pod new file mode 100644 index 00000000000..82bb57aaf47 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/FAQ.pod @@ -0,0 +1,30 @@ +=pod + +=head1 NAME + +CPANPLUS::FAQ + +=head1 DESCRIPTION + +This document attempts to provide answers to commonly asked questions. + + XXX Work in progress + +=head1 BUG REPORTS + +Please report bugs or other issues to E<lt>bug-cpanplus@rt.cpan.org<gt>. + +=head1 AUTHOR + +This module by Jos Boumans E<lt>kane@cpan.orgE<gt>. + +=head1 COPYRIGHT + +The CPAN++ interface (of which this module is a part of) is copyright (c) +2001 - 2007, Jos Boumans E<lt>kane@cpan.orgE<gt>. All rights reserved. + +This library is free software; you may redistribute and/or modify it +under the same terms as Perl itself. + +=cut + diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Hacking.pod b/Master/tlpkg/tlperl/lib/CPANPLUS/Hacking.pod new file mode 100644 index 00000000000..1a28b9e5b05 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Hacking.pod @@ -0,0 +1,135 @@ +=pod + +=head1 NAME + +CPANPLUS::Hacking + +=head1 DESCRIPTION + +This document attempts to describe how to develop with the +CPANPLUS environment most easily, how certain things work and why. + +This is basically a quick-start guide to people who want to add +features or patches to CPANPLUS. + +=head1 OBTAINING CPANPLUS + +Checkout CPANPLUS from its Subversion repository at +L<http://oss.dwim.org/cpanplus-devel> . + +=head1 INSTALLING CPANPLUS + +CPANPLUS follows the standard perl module installation process: + + perl Makefile.PL + make + make test + make install + +=head1 CONFIGURING CPANPLUS + +When running C<perl Makefile.PL> you will be prompted to configure. +If you have already done so, and merely wish to update the C<Makefile>, +simply run: + + perl Makefile.PL JFDI=1 + +This will keep your configuration intact. Note however, if there are +changes to the default configuration file C<Config.pm-orig>, you should +either delete your current config file and reconfigure, or patch your +config file from the new entries in C<Config.pm-orig>. + +=head1 RUNNING CPANPLUS FROM DEVELOPMENT ENVIRONMENT + +If you'd rather not install the development version to your +C<site_perl> directory, that's no problem. You can set your C<PERL5LIB> +environment variable to CPANPLUS' C<lib> directory, and you can run it +from there. + +=head1 RUNNING CPANPLUS TESTS + +Tests are what tells us if CPANPLUS is working. If a test is not working, +try to run it explicilty like this: + + perl -I/path/to/cpanplus/lib t/XX_name_of_test.t 1 + +The extra '1' makes sure that all the messages and errors (they might +be errors we're testing for!) are being printed rather than kept quiet. +This is a great way to find out the context of any failures that may +occur. + +If you believe this test failure proves a bug in CPANPLUS, the long +output of the test file is something we'd like to see alongside your +bug report. + +=head1 FINDING BUGS + +Sometimes you might find bugs in CPANPLUS' behaviour. If you encounter +these in a development snapshot, we'd appreciate a complete patch (as +described below in the L<SENDING PATCHES> section. + +If it's way over your head, then of course reporting the bug is always +better than not reporting it at all. Before you do so though, make +sure you have the B<latest> development snapshot, and the bug still +persists there. If so, report the bug to this address: + + cpanplus-devel@lists.sourceforge.net + +A good C<patch> would have the following characteristics: + +=over 4 + +=item Problem description + +Describe clearly what the bug is you found, and what it should have +done instead. + +=item Program demonstrating the bug + +Show us how to reproduce the bug, in a simple of a program as possible + +=item [OPTIONAL] A patch to the test suite to test for the bug + +Amend our test suite by making sure this bug will be found in this, and +future versions of CPANPLUS (see L<SUPPLYING PATCHES>) + +=item [OPTIONAL] A patch to the code + tests + documentation + +Fix the bug, update the docs & tests. That way your bug will be gone +forever :) + +=back + +=head1 SUPPLYING PATCHES + +Patches are a good thing, and they are welcome. Especially if they fix +bugs you've found along the way, or that others have reported. + +We prefer patches in the following format: + +=over 4 + +=item * In C<diff -u> or C<diff -c> format + +=item * From the root of the snapshot + +=item * Including patches for code + tests + docs + +=item * Sent per mail to cpanplus-devel@lists.sourceforge.net + +=item * With subject containing C<[PATCH]> + description of the patch + +=back + +You will always be informed if a patch is applied or rejected, and in +case of rejection why that is (perhaps you can tweak the patch to have +it accepted after all). + +=cut + +__END__ + +* perl5lib +* perl t/foo 1 +* patches to cpanplus-devel +* snap/devel.tgz diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Internals.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals.pm new file mode 100644 index 00000000000..fedcb670aa4 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals.pm @@ -0,0 +1,516 @@ +package CPANPLUS::Internals; + +### we /need/ perl5.6.1 or higher -- we use coderefs in @INC, +### and 5.6.0 is just too buggy +use 5.006001; + +use strict; +use Config; + + +use CPANPLUS::Error; + +use CPANPLUS::Selfupdate; + +use CPANPLUS::Internals::Extract; +use CPANPLUS::Internals::Fetch; +use CPANPLUS::Internals::Utils; +use CPANPLUS::Internals::Constants; +use CPANPLUS::Internals::Search; +use CPANPLUS::Internals::Report; + + +require base; +use Cwd qw[cwd]; +use Module::Load qw[load]; +use Params::Check qw[check]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; +use Module::Load::Conditional qw[can_load]; + +use Object::Accessor; + + +local $Params::Check::VERBOSE = 1; + +use vars qw[@ISA $VERSION]; + +@ISA = qw[ + CPANPLUS::Internals::Extract + CPANPLUS::Internals::Fetch + CPANPLUS::Internals::Utils + CPANPLUS::Internals::Search + CPANPLUS::Internals::Report + ]; + +$VERSION = "0.90"; + +=pod + +=head1 NAME + +CPANPLUS::Internals + +=head1 SYNOPSIS + + my $internals = CPANPLUS::Internals->_init( _conf => $conf ); + my $backend = CPANPLUS::Internals->_retrieve_id( $ID ); + +=head1 DESCRIPTION + +This module is the guts of CPANPLUS -- it inherits from all other +modules in the CPANPLUS::Internals::* namespace, thus defying normal +rules of OO programming -- but if you're reading this, you already +know what's going on ;) + +Please read the C<CPANPLUS::Backend> documentation for the normal API. + +=head1 ACCESSORS + +=over 4 + +=item _conf + +Get/set the configure object + +=item _id + +Get/set the id + +=cut + +### autogenerate accessors ### +for my $key ( qw[_conf _id _modules _hosts _methods _status + _callbacks _selfupdate _mtree _atree] +) { + no strict 'refs'; + *{__PACKAGE__."::$key"} = sub { + $_[0]->{$key} = $_[1] if @_ > 1; + return $_[0]->{$key}; + } +} + +=pod + +=back + +=head1 METHODS + +=head2 $internals = CPANPLUS::Internals->_init( _conf => CONFIG_OBJ ) + +C<_init> creates a new CPANPLUS::Internals object. + +You have to pass it a valid C<CPANPLUS::Configure> object. + +Returns the object on success, or dies on failure. + +=cut +{ ### NOTE: + ### if extra callbacks are added, don't forget to update the + ### 02-internals.t test script with them! + my $callback_map = { + ### name default value + install_prerequisite => 1, # install prereqs when 'ask' is set? + edit_test_report => 0, # edit the prepared test report? + send_test_report => 1, # send the test report? + # munge the test report + munge_test_report => sub { return $_[1] }, + # filter out unwanted prereqs + filter_prereqs => sub { return $_[1] }, + # continue if 'make test' fails? + proceed_on_test_failure => sub { return 0 }, + munge_dist_metafile => sub { return $_[1] }, + }; + + my $status = Object::Accessor->new; + $status->mk_accessors(qw[pending_prereqs]); + + my $callback = Object::Accessor->new; + $callback->mk_accessors(keys %$callback_map); + + my $conf; + my $Tmpl = { + _conf => { required => 1, store => \$conf, + allow => IS_CONFOBJ }, + _id => { default => '', no_override => 1 }, + _authortree => { default => '', no_override => 1 }, + _modtree => { default => '', no_override => 1 }, + _hosts => { default => {}, no_override => 1 }, + _methods => { default => {}, no_override => 1 }, + _status => { default => '<empty>', no_override => 1 }, + _callbacks => { default => '<empty>', no_override => 1 }, + }; + + sub _init { + my $class = shift; + my %hash = @_; + + ### temporary warning until we fix the storing of multiple id's + ### and their serialization: + ### probably not going to happen --kane + if( my $id = $class->_last_id ) { + # make it a singleton. + warn loc(q[%1 currently only supports one %2 object per ] . + qq[running program\n], 'CPANPLUS', $class); + + return $class->_retrieve_id( $id ); + } + + my $args = check($Tmpl, \%hash) + or die loc(qq[Could not initialize '%1' object], $class); + + bless $args, $class; + + $args->{'_id'} = $args->_inc_id; + $args->{'_status'} = $status; + $args->{'_callbacks'} = $callback; + + ### initialize callbacks to default state ### + for my $name ( $callback->ls_accessors ) { + my $rv = ref $callback_map->{$name} ? 'sub return value' : + $callback_map->{$name} ? 'true' : 'false'; + + $args->_callbacks->$name( + sub { msg(loc("DEFAULT '%1' HANDLER RETURNING '%2'", + $name, $rv), $args->_conf->get_conf('debug')); + return ref $callback_map->{$name} + ? $callback_map->{$name}->( @_ ) + : $callback_map->{$name}; + } + ); + } + + ### create a selfupdate object + $args->_selfupdate( CPANPLUS::Selfupdate->new( $args ) ); + + ### initalize it as an empty hashref ### + $args->_status->pending_prereqs( {} ); + + $conf->_set_build( startdir => cwd() ), + or error( loc("couldn't locate current dir!") ); + + $ENV{FTP_PASSIVE} = 1, if $conf->get_conf('passive'); + + my $id = $args->_store_id( $args ); + + unless ( $id == $args->_id ) { + error( loc("IDs do not match: %1 != %2. Storage failed!", + $id, $args->_id) ); + } + + ### different source engines available now, so set them here + { my $store = $conf->get_conf( 'source_engine' ) + || DEFAULT_SOURCE_ENGINE; + + unless( can_load( modules => { $store => '0.0' }, verbose => 1 ) ) { + error( loc( "Could not load source engine '%1'", $store ) ); + + if( $store ne DEFAULT_SOURCE_ENGINE ) { + msg( loc("Falling back to %1", DEFAULT_SOURCE_ENGINE), 1 ); + + load DEFAULT_SOURCE_ENGINE; + + base->import( DEFAULT_SOURCE_ENGINE ); + } else { + return; + } + } else { + base->import( $store ); + } + } + + return $args; + } + +=pod + +=head2 $bool = $internals->_flush( list => \@caches ) + +Flushes the designated caches from the C<CPANPLUS> object. + +Returns true on success, false if one or more caches could not be +be flushed. + +=cut + + sub _flush { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my $aref; + my $tmpl = { + list => { required => 1, default => [], + strict_type => 1, store => \$aref }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + my $flag = 0; + for my $what (@$aref) { + my $cache = '_' . $what; + + ### set the include paths back to their original ### + if( $what eq 'lib' ) { + $ENV{PERL5LIB} = $conf->_perl5lib || ''; + @INC = @{$conf->_lib}; + + ### give all modules a new status object -- this is slightly + ### costly, but the best way to make sure all statusses are + ### forgotten --kane + } elsif ( $what eq 'modules' ) { + for my $modobj ( values %{$self->module_tree} ) { + + $modobj->_flush; + } + + ### blow away the methods cache... currently, that's only + ### File::Fetch's method fail list + } elsif ( $what eq 'methods' ) { + + ### still fucking p4 :( ### + $File'Fetch::METHOD_FAIL = $File'Fetch::METHOD_FAIL = {}; + + ### blow away the m::l::c cache, so modules can be (re)loaded + ### again if they become available + } elsif ( $what eq 'load' ) { + undef $Module::Load::Conditional::CACHE; + + } else { + unless ( exists $self->{$cache} && exists $Tmpl->{$cache} ) { + error( loc( "No such cache: '%1'", $what ) ); + $flag++; + next; + } else { + $self->$cache( {} ); + } + } + } + return !$flag; + } + +### NOTE: +### if extra callbacks are added, don't forget to update the +### 02-internals.t test script with them! + +=pod + +=head2 $bool = $internals->_register_callback( name => CALLBACK_NAME, code => CODEREF ); + +Registers a callback for later use by the internal libraries. + +Here is a list of the currently used callbacks: + +=over 4 + +=item install_prerequisite + +Is called when the user wants to be C<asked> about what to do with +prerequisites. Should return a boolean indicating true to install +the prerequisite and false to skip it. + +=item send_test_report + +Is called when the user should be prompted if he wishes to send the +test report. Should return a boolean indicating true to send the +test report and false to skip it. + +=item munge_test_report + +Is called when the test report message has been composed, giving +the user a chance to programatically alter it. Should return the +(munged) message to be sent. + +=item edit_test_report + +Is called when the user should be prompted to edit test reports +about to be sent out by Test::Reporter. Should return a boolean +indicating true to edit the test report in an editor and false +to skip it. + +=item proceed_on_test_failure + +Is called when 'make test' or 'Build test' fails. Should return +a boolean indicating whether the install should continue even if +the test failed. + +=item munge_dist_metafile + +Is called when the C<CPANPLUS::Dist::*> metafile is created, like +C<control> for C<CPANPLUS::Dist::Deb>, giving the user a chance to +programatically alter it. Should return the (munged) text to be +written to the metafile. + +=back + +=cut + + sub _register_callback { + my $self = shift or return; + my %hash = @_; + + my ($name,$code); + my $tmpl = { + name => { required => 1, store => \$name, + allow => [$callback->ls_accessors] }, + code => { required => 1, allow => IS_CODEREF, + store => \$code }, + }; + + check( $tmpl, \%hash ) or return; + + $self->_callbacks->$name( $code ) or return; + + return 1; + } + +# =head2 $bool = $internals->_add_callback( name => CALLBACK_NAME, code => CODEREF ); +# +# Adds a new callback to be used from anywhere in the system. If the callback +# is already known, an error is raised and false is returned. If the callback +# is not yet known, it is added, and the corresponding coderef is registered +# using the +# +# =cut +# +# sub _add_callback { +# my $self = shift or return; +# my %hash = @_; +# +# my ($name,$code); +# my $tmpl = { +# name => { required => 1, store => \$name, }, +# code => { required => 1, allow => IS_CODEREF, +# store => \$code }, +# }; +# +# check( $tmpl, \%hash ) or return; +# +# if( $callback->can( $name ) ) { +# error(loc("Callback '%1' is already registered")); +# return; +# } +# +# $callback->mk_accessor( $name ); +# +# $self->_register_callback( name => $name, code => $code ) or return; +# +# return 1; +# } + +} + +=pod + +=head2 $bool = $internals->_add_to_includepath( directories => \@dirs ) + +Adds a list of directories to the include path. +This means they get added to C<@INC> as well as C<$ENV{PERL5LIB}>. + +Returns true on success, false on failure. + +=cut + +sub _add_to_includepath { + my $self = shift; + my %hash = @_; + + my $dirs; + my $tmpl = { + directories => { required => 1, default => [], store => \$dirs, + strict_type => 1 }, + }; + + check( $tmpl, \%hash ) or return; + + my $s = $Config{'path_sep'}; + + ### only add if it's not added yet + for my $lib (@$dirs) { + push @INC, $lib unless grep { $_ eq $lib } @INC; + # + ### it will be complaining if $ENV{PERL5LIB] is not defined (yet). + local $^W; + $ENV{'PERL5LIB'} .= $s . $lib + unless $ENV{'PERL5LIB'} =~ qr|\Q$s$lib\E|; + } + + return 1; +} + +=pod + +=head2 $id = CPANPLUS::Internals->_last_id + +Return the id of the last object stored. + +=head2 $id = CPANPLUS::Internals->_store_id( $internals ) + +Store this object; return its id. + +=head2 $obj = CPANPLUS::Internals->_retrieve_id( $ID ) + +Retrieve an object based on its ID -- return false on error. + +=head2 CPANPLUS::Internals->_remove_id( $ID ) + +Remove the object marked by $ID from storage. + +=head2 @objs = CPANPLUS::Internals->_return_all_objects + +Return all stored objects. + +=cut + + +### code for storing multiple objects +### -- although we only support one right now +### XXX when support for multiple objects comes, saving source will have +### to change +{ + my $idref = {}; + my $count = 0; + + sub _inc_id { return ++$count; } + + sub _last_id { $count } + + sub _store_id { + my $self = shift; + my $obj = shift or return; + + unless( IS_INTERNALS_OBJ->($obj) ) { + error( loc("The object you passed has the wrong ref type: '%1'", + ref $obj) ); + return; + } + + $idref->{ $obj->_id } = $obj; + return $obj->_id; + } + + sub _retrieve_id { + my $self = shift; + my $id = shift or return; + + my $obj = $idref->{$id}; + return $obj; + } + + sub _remove_id { + my $self = shift; + my $id = shift or return; + + return delete $idref->{$id}; + } + + sub _return_all_objects { return values %$idref } +} + +1; + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Constants.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Constants.pm new file mode 100644 index 00000000000..1a38200dfb7 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Constants.pm @@ -0,0 +1,375 @@ +package CPANPLUS::Internals::Constants; + +use strict; + +use CPANPLUS::Error; + +use Config; +use File::Spec; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +require Exporter; +use vars qw[$VERSION @ISA @EXPORT]; + +use Package::Constants; + +@ISA = qw[Exporter]; +@EXPORT = Package::Constants->list( __PACKAGE__ ); + + +sub constants { @EXPORT }; + +use constant INSTALLER_BUILD + => 'CPANPLUS::Dist::Build'; +use constant INSTALLER_MM => 'CPANPLUS::Dist::MM'; +use constant INSTALLER_SAMPLE + => 'CPANPLUS::Dist::Sample'; +use constant INSTALLER_BASE => 'CPANPLUS::Dist::Base'; +use constant INSTALLER_AUTOBUNDLE + => 'CPANPLUS::Dist::Autobundle'; + +use constant SHELL_DEFAULT => 'CPANPLUS::Shell::Default'; +use constant SHELL_CLASSIC => 'CPANPLUS::Shell::Classic'; + +use constant CONFIG => 'CPANPLUS::Config'; +use constant CONFIG_USER => 'CPANPLUS::Config::User'; +use constant CONFIG_SYSTEM => 'CPANPLUS::Config::System'; +use constant CONFIG_BOXED => 'CPANPLUS::Config::Boxed'; + +use constant DEFAULT_SOURCE_ENGINE + => 'CPANPLUS::Internals::Source::Memory'; + +use constant TARGET_INIT => 'init'; +use constant TARGET_CREATE => 'create'; +use constant TARGET_PREPARE => 'prepare'; +use constant TARGET_INSTALL => 'install'; +use constant TARGET_IGNORE => 'ignore'; + +use constant ON_WIN32 => $^O eq 'MSWin32'; +use constant ON_NETWARE => $^O eq 'NetWare'; +use constant ON_CYGWIN => $^O eq 'cygwin'; +use constant ON_VMS => $^O eq 'VMS'; + +use constant DOT_CPANPLUS => ON_VMS ? '_cpanplus' : '.cpanplus'; + +use constant OPT_AUTOFLUSH => '-MCPANPLUS::Internals::Utils::Autoflush'; + +use constant UNKNOWN_DL_LOCATION + => 'UNKNOWN-ORIGIN'; + +use constant NMAKE => 'nmake.exe'; +use constant NMAKE_URL => + 'ftp://ftp.microsoft.com/Softlib/MSLFILES/nmake15.exe'; + +use constant INSTALL_VIA_PACKAGE_MANAGER + => sub { my $fmt = $_[0] or return; + return 1 if $fmt ne INSTALLER_BUILD and + $fmt ne INSTALLER_MM; + }; + +use constant IS_CODEREF => sub { ref $_[-1] eq 'CODE' }; +use constant IS_MODOBJ => sub { UNIVERSAL::isa($_[-1], + 'CPANPLUS::Module') }; +use constant IS_FAKE_MODOBJ => sub { UNIVERSAL::isa($_[-1], + 'CPANPLUS::Module::Fake') }; +use constant IS_AUTHOBJ => sub { UNIVERSAL::isa($_[-1], + 'CPANPLUS::Module::Author') }; +use constant IS_FAKE_AUTHOBJ + => sub { UNIVERSAL::isa($_[-1], + 'CPANPLUS::Module::Author::Fake') }; + +use constant IS_CONFOBJ => sub { UNIVERSAL::isa($_[-1], + 'CPANPLUS::Configure') }; + +use constant IS_RVOBJ => sub { UNIVERSAL::isa($_[-1], + 'CPANPLUS::Backend::RV') }; + +use constant IS_INTERNALS_OBJ + => sub { UNIVERSAL::isa($_[-1], + 'CPANPLUS::Internals') }; + +use constant IS_FILE => sub { return 1 if -e $_[-1] }; + +use constant FILE_EXISTS => sub { + my $file = $_[-1]; + return 1 if IS_FILE->($file); + local $Carp::CarpLevel = + $Carp::CarpLevel+2; + error(loc( q[File '%1' does not exist], + $file)); + return; + }; + +use constant FILE_READABLE => sub { + my $file = $_[-1]; + return 1 if -e $file && -r _; + local $Carp::CarpLevel = + $Carp::CarpLevel+2; + error( loc( q[File '%1' is not readable ]. + q[or does not exist], $file)); + return; + }; +use constant IS_DIR => sub { return 1 if -d $_[-1] }; + +use constant DIR_EXISTS => sub { + my $dir = $_[-1]; + return 1 if IS_DIR->($dir); + local $Carp::CarpLevel = + $Carp::CarpLevel+2; + error(loc(q[Dir '%1' does not exist], + $dir)); + return; + }; + + ### On VMS, if the $Config{make} is either MMK + ### or MMS, then the makefile is 'DESCRIP.MMS'. +use constant MAKEFILE => sub { my $file = + (ON_VMS and + $Config::Config{make} =~ /MM[S|K]/i) + ? 'DESCRIP.MMS' + : 'Makefile'; + + return @_ + ? File::Spec->catfile( @_, $file ) + : $file; + }; +use constant MAKEFILE_PL => sub { return @_ + ? File::Spec->catfile( @_, + 'Makefile.PL' ) + : 'Makefile.PL'; + }; +use constant BUILD_PL => sub { return @_ + ? File::Spec->catfile( @_, + 'Build.PL' ) + : 'Build.PL'; + }; + +use constant META_YML => sub { return @_ + ? File::Spec->catfile( @_, 'META.yml' ) + : 'META.yml'; + }; + +use constant MYMETA_YML => sub { return @_ + ? File::Spec->catfile( @_, 'MYMETA.yml' ) + : 'MYMETA.yml'; + }; + +use constant BLIB => sub { return @_ + ? File::Spec->catfile(@_, 'blib') + : 'blib'; + }; + +use constant LIB => 'lib'; +use constant LIB_DIR => sub { return @_ + ? File::Spec->catdir(@_, LIB) + : LIB; + }; +use constant AUTO => 'auto'; +use constant LIB_AUTO_DIR => sub { return @_ + ? File::Spec->catdir(@_, LIB, AUTO) + : File::Spec->catdir(LIB, AUTO) + }; +use constant ARCH => 'arch'; +use constant ARCH_DIR => sub { return @_ + ? File::Spec->catdir(@_, ARCH) + : ARCH; + }; +use constant ARCH_AUTO_DIR => sub { return @_ + ? File::Spec->catdir(@_,ARCH,AUTO) + : File::Spec->catdir(ARCH,AUTO) + }; + +use constant BLIB_LIBDIR => sub { return @_ + ? File::Spec->catdir( + @_, BLIB->(), LIB ) + : File::Spec->catdir( BLIB->(), LIB ); + }; + +use constant CONFIG_USER_LIB_DIR => sub { + require CPANPLUS::Internals::Utils; + LIB_DIR->( + CPANPLUS::Internals::Utils->_home_dir, + DOT_CPANPLUS + ); + }; +use constant CONFIG_USER_FILE => sub { + File::Spec->catfile( + CONFIG_USER_LIB_DIR->(), + split('::', CONFIG_USER), + ) . '.pm'; + }; +use constant CONFIG_SYSTEM_FILE => sub { + require CPANPLUS::Internals; + require File::Basename; + my $dir = File::Basename::dirname( + $INC{'CPANPLUS/Internals.pm'} + ); + + ### XXX use constants + File::Spec->catfile( + $dir, qw[Config System.pm] + ); + }; + +use constant README => sub { my $obj = $_[0]; + my $pkg = $obj->package_name; + $pkg .= '-' . $obj->package_version . + '.readme'; + return $pkg; + }; +use constant META_EXT => 'meta'; + +use constant META => sub { my $obj = $_[0]; + my $pkg = $obj->package_name; + $pkg .= '-' . $obj->package_version . + '.' . META_EXT; + return $pkg; + }; + +use constant OPEN_FILE => sub { + my($file, $mode) = (@_, ''); + my $fh; + open $fh, "$mode" . $file + or error(loc( + "Could not open file '%1': %2", + $file, $!)); + return $fh if $fh; + return; + }; + +use constant OPEN_DIR => sub { + my $dir = shift; + my $dh; + opendir $dh, $dir or error(loc( + "Could not open dir '%1': %2", $dir, $! + )); + + return $dh if $dh; + return; + }; + +use constant READ_DIR => sub { + my $dir = shift; + my $dh = OPEN_DIR->( $dir ) or return; + + ### exclude . and .. + my @files = grep { $_ !~ /^\.{1,2}/ } + readdir($dh); + + ### Remove trailing dot on VMS when + ### using VMS syntax. + if( ON_VMS ) { + s/(?<!\^)\.$// for @files; + } + + return @files; + }; + +use constant STRIP_GZ_SUFFIX + => sub { + my $file = $_[0] or return; + $file =~ s/.gz$//i; + return $file; + }; + +use constant CHECKSUMS => 'CHECKSUMS'; +use constant PGP_HEADER => '-----BEGIN PGP SIGNED MESSAGE-----'; +use constant ENV_CPANPLUS_CONFIG + => 'PERL5_CPANPLUS_CONFIG'; +use constant ENV_CPANPLUS_IS_EXECUTING + => 'PERL5_CPANPLUS_IS_EXECUTING'; +use constant DEFAULT_EMAIL => 'cpanplus@example.com'; +use constant CPANPLUS_UA => sub { ### for the version number ### + require CPANPLUS::Internals; + "CPANPLUS/$CPANPLUS::Internals::VERSION" + }; +use constant TESTERS_URL => sub { + 'http://cpantesters.org/distro/'. + uc(substr($_[0],0,1)) .'/'. $_[0] . '.yaml'; + }; +use constant TESTERS_DETAILS_URL + => sub { + 'http://cpantesters.org/distro/'. + uc(substr($_[0],0,1)) .'/'. $_[0]; + }; + +use constant CREATE_FILE_URI + => sub { + my $dir = $_[0] or return; + return $dir =~ m|^/| + ? 'file://' . $dir + : 'file:///' . $dir; + }; + +use constant EMPTY_DSLIP => ' '; + +use constant CUSTOM_AUTHOR_ID + => 'LOCAL'; + +use constant DOT_SHELL_DEFAULT_RC + => '.shell-default.rc'; + +use constant SOURCE_SQLITE_DB + => 'db.sql'; + +use constant PREREQ_IGNORE => 0; +use constant PREREQ_INSTALL => 1; +use constant PREREQ_ASK => 2; +use constant PREREQ_BUILD => 3; +use constant BOOLEANS => [0,1]; +use constant CALLING_FUNCTION + => sub { my $lvl = $_[0] || 0; + return join '::', (caller(2+$lvl))[3] + }; +use constant PERL_CORE => 'perl'; +use constant STORABLE_EXT => '.stored'; + +use constant GET_XS_FILES => sub { my $dir = $_[0] or return; + require File::Find; + my @files; + File::Find::find( + sub { push @files, $File::Find::name + if $File::Find::name =~ /\.xs$/i + }, $dir ); + + return @files; + }; + +use constant INSTALL_LOG_FILE + => sub { my $obj = shift or return; + my $name = $obj->name; $name =~ s/::/-/g; + $name .= '-'. $obj->version; + $name .= '-'. scalar(time) . '.log'; + return $name; + }; + +use constant ON_OLD_CYGWIN => do { ON_CYGWIN and $] < 5.008 + ? loc( + "Your perl version for %1 is too low; ". + "Require %2 or higher for this function", + $^O, '5.8.0' ) + : ''; + }; + +### XXX these 2 are probably obsolete -- check & remove; +use constant DOT_EXISTS => '.exists'; + +use constant QUOTE_PERL_ONE_LINER + => sub { my $line = shift or return; + + ### use double quotes on these systems + return qq["$line"] + if ON_WIN32 || ON_NETWARE || ON_VMS; + + ### single quotes on the rest + return qq['$line']; + }; + +1; + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Constants/Report.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Constants/Report.pm new file mode 100644 index 00000000000..59a41a6083b --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Constants/Report.pm @@ -0,0 +1,407 @@ +package CPANPLUS::Internals::Constants::Report; + +use strict; +use CPANPLUS::Error; + +use File::Spec; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +require Exporter; +use vars qw[$VERSION @ISA @EXPORT]; + +use Package::Constants; + +### for the version +require CPANPLUS::Internals; + +$VERSION = $CPANPLUS::Internals::VERSION = $CPANPLUS::Internals::VERSION; +@ISA = qw[Exporter]; +@EXPORT = Package::Constants->list( __PACKAGE__ ); + + +### OS to regex map ### +my %OS = ( + Amiga => 'amigaos', + Atari => 'mint', + BSD => 'bsdos|darwin|freebsd|openbsd|netbsd', + Be => 'beos', + BeOS => 'beos', + Cygwin => 'cygwin', + Darwin => 'darwin', + EBCDIC => 'os390|os400|posix-bc|vmesa', + HPUX => 'hpux', + Linux => 'linux', + MSDOS => 'dos|os2|MSWin32|cygwin', + 'bin\\d*Mac'=> 'MacOS|darwin', # binMac, bin56Mac, bin58Mac... + Mac => 'MacOS|darwin', + MacPerl => 'MacOS', + MacOS => 'MacOS|darwin', + MacOSX => 'darwin', + MPE => 'mpeix', + MPEiX => 'mpeix', + OS2 => 'os2', + Plan9 => 'plan9', + RISCOS => 'riscos', + SGI => 'irix', + Solaris => 'solaris', + Unix => 'aix|bsdos|darwin|dgux|dynixptx|freebsd|'. + 'linux|hpux|machten|netbsd|next|openbsd|dec_osf|'. + 'svr4|sco_sv|unicos|unicosmk|solaris|sunos', + VMS => 'VMS', + VOS => 'VOS', + Win32 => 'MSWin32|cygwin', + Win32API => 'MSWin32|cygwin', +); + +use constant GRADE_FAIL => 'fail'; +use constant GRADE_PASS => 'pass'; +use constant GRADE_NA => 'na'; +use constant GRADE_UNKNOWN => 'unknown'; + +use constant MAX_REPORT_SEND + => 2; + +use constant CPAN_TESTERS_EMAIL + => 'cpan-testers@perl.org'; + +### the cpan mail account for this user ### +use constant CPAN_MAIL_ACCOUNT + => sub { + my $username = shift or return; + return $username . '@cpan.org'; + }; + +### check if this module is platform specific and if we're on that +### specific platform. Alternately, the module is not platform specific +### and we're always OK to send out test results. +use constant RELEVANT_TEST_RESULT + => sub { + my $mod = shift or return; + my $name = $mod->module; + my $specific; + for my $platform (keys %OS) { + if( $name =~ /\b$platform\b/i ) { + # beware the Mac != MAC + next if($platform eq 'Mac' && + $name !~ /\b$platform\b/); + $specific++; + return 1 if + $^O =~ /^(?:$OS{$platform})$/ + } + }; + return $specific ? 0 : 1; + }; + +use constant UNSUPPORTED_OS + => sub { + my $buffer = shift or return; + if( $buffer =~ + /No support for OS|OS unsupported/im ) { + return 1; + } + return 0; + }; + +use constant PERL_VERSION_TOO_LOW + => sub { + my $buffer = shift or return; + # ExtUtils::MakeMaker format + if( $buffer =~ + /Perl .*? required--this is only .*?/m ) { + return 1; + } + # Module::Build format + if( $buffer =~ + /ERROR:( perl:)? Version .*?( of perl)? is installed, but we need version >= .*?/m ) { + return 1; + } + return 0; + }; + +use constant NO_TESTS_DEFINED + => sub { + my $buffer = shift or return; + if( $buffer =~ + /(No tests defined( for [\w:]+ extension)?\.)/ + and $buffer !~ /\*\.t/m and + $buffer !~ /test\.pl/m + ) { + return $1 + } + + return; + }; + +### what stage did the test fail? ### +use constant TEST_FAIL_STAGE + => sub { + my $buffer = shift or return; + return $buffer =~ /(MAKE [A-Z]+).*/ + ? lc $1 : + 'fetch'; + }; + + +use constant MISSING_PREREQS_LIST + => sub { + my $buffer = shift; + my $last = ( split /\[ERROR\] .+? MAKE TEST/, $buffer )[-1]; + my @list = map { s/.pm$//; s|/|::|g; $_ } + ($last =~ + m/\bCan\'t locate (\S+) in \@INC/g); + + ### make sure every missing prereq is only + ### listed once + { my %seen; + @list = grep { !$seen{$_}++ } @list + } + + return @list; + }; + +use constant MISSING_EXTLIBS_LIST + => sub { + my $buffer = shift; + my @list = + ($buffer =~ + m/No library found for -l([-\w]+)/g); + + return @list; + }; + +use constant REPORT_MESSAGE_HEADER + => sub { + my ($version, $author) = @_; + return << "."; + +Dear $author, + +This is a computer-generated error report created automatically by +CPANPLUS, version $version. Testers personal comments may appear +at the end of this report. + +. + }; + +use constant REPORT_MESSAGE_FAIL_HEADER + => sub { + my($stage, $buffer) = @_; + return << "."; + +Thank you for uploading your work to CPAN. However, it appears that +there were some problems testing your distribution. + +TEST RESULTS: + +Below is the error stack from stage '$stage': + +$buffer + +. + }; + +use constant REPORT_MISSING_PREREQS + => sub { + my ($author,$email,@missing) = @_; + $author = ($author && $email) + ? "$author ($email)" + : 'Your Name Here'; + + my $modules = join "\n", @missing; + my $prereqs = join "\n", + map {"\t'$_'\t=> '0',". + " # or a minimum working version"} + @missing; + + return << "."; + +MISSING PREREQUISITES: + +It was observed that the test suite seem to fail without these modules: + +$modules + +As such, adding the prerequisite module(s) to 'PREREQ_PM' in your +Makefile.PL should solve this problem. For example: + +WriteMakefile( + AUTHOR => '$author', + ... # other information + PREREQ_PM => { +$prereqs + } +); + +Thanks! :-) + +. + }; + +use constant REPORT_MISSING_TESTS + => sub { + return << "."; +RECOMMENDATIONS: + +It would be very helpful if you could include even a simple test +script in the next release, so people can verify which platforms +can successfully install them, as well as avoid regression bugs? + +A simple 't/use.t' that says: + +#!/usr/bin/env perl -w +use strict; +use Test; +BEGIN { plan tests => 1 } + +use Your::Module::Here; ok(1); +exit; +__END__ + +would be appreciated. If you are interested in making a more robust +test suite, please see the Test::Simple, Test::More and Test::Tutorial +documentation at <http://search.cpan.org/dist/Test-Simple/>. + +Thanks! :-) + +. + }; + +use constant REPORT_LOADED_PREREQS + => sub { + my $mod = shift; + my $cb = $mod->parent; + my $prq = $mod->status->prereqs || {}; + + ### not every prereq may be coming from CPAN + ### so maybe we wont find it in our module + ### tree at all... + ### skip ones that cant be found in teh list + ### as reported in #12723 + my @prq = grep { defined } + map { $cb->module_tree($_) } + sort keys %$prq; + + ### no prereqs? + return '' unless @prq; + + ### some apparently, list what we loaded + my $str = << "."; +PREREQUISITES: + +Here is a list of prerequisites you specified and versions we +managed to load: + +. + $str .= join '', + map { sprintf "\t%s %-30s %8s %8s\n", + @$_ + + } [' ', 'Module Name', 'Have', 'Want'], + map { my $want = $prq->{$_->name}; + [ do { $_->is_uptodate( + version => $want + ) ? ' ' : '!' + }, + $_->name, + $_->installed_version, + $want + ], + ### might be empty entries in there + } grep { $_ } @prq; + + return $str; + }; + +use constant REPORT_TOOLCHAIN_VERSIONS + => sub { + my $mod = shift; + my $cb = $mod->parent; + #die unless $cb->isa('CPANPLUS::Backend'); + + my @toolchain_modules= qw( + CPANPLUS + CPANPLUS::Dist::Build + Cwd + ExtUtils::CBuilder + ExtUtils::Command + ExtUtils::Install + ExtUtils::MakeMaker + ExtUtils::Manifest + ExtUtils::ParseXS + File::Spec + Module::Build + Test::Harness + Test::More + version + ); + + my @toolchain = + grep { $_ } #module_tree returns '' when module is not found + map { $cb->module_tree($_) } + sort @toolchain_modules; + + ### no prereqs? + return '' unless @toolchain; + + ### toolchain modules + my $str = << "."; + +Perl module toolchain versions installed: +. + $str .= join '', + map { sprintf "\t%-30s %8s\n", + @$_ + + } ['Module Name', 'Have'], + map { + [ $_->name, + $_->installed_version, + ], + ### might be empty entries in there + } @toolchain; + + return $str; + }; + + +use constant REPORT_TESTS_SKIPPED + => sub { + return << "."; + +******************************** NOTE ******************************** +*** *** +*** The tests for this module were skipped during this build *** +*** *** +********************************************************************** + +. + }; + +use constant REPORT_MESSAGE_FOOTER + => sub { + return << "."; + +******************************** NOTE ******************************** +The comments above are created mechanically, possibly without manual +checking by the sender. As there are many people performing automatic +tests on each upload to CPAN, it is likely that you will receive +identical messages about the same problem. + +If you believe that the message is mistaken, please reply to the first +one with correction and/or additional informations, and do not take +it personally. We appreciate your patience. :) +********************************************************************** + +Additional comments: + +. + }; + +1; + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Extract.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Extract.pm new file mode 100644 index 00000000000..84a48a50dea --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Extract.pm @@ -0,0 +1,243 @@ +package CPANPLUS::Internals::Extract; + +use strict; + +use CPANPLUS::Error; +use CPANPLUS::Internals::Constants; + +use File::Spec (); +use File::Basename (); +use Archive::Extract; +use IPC::Cmd qw[run]; +use Params::Check qw[check]; +use Module::Load::Conditional qw[can_load check_install]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +local $Params::Check::VERBOSE = 1; + +=pod + +=head1 NAME + +CPANPLUS::Internals::Extract + +=head1 SYNOPSIS + + ### for source files ### + $self->_gunzip( file => 'foo.gz', output => 'blah.txt' ); + + ### for modules/packages ### + $dir = $self->_extract( module => $modobj, + extractdir => '/some/where' ); + +=head1 DESCRIPTION + +CPANPLUS::Internals::Extract extracts compressed files for CPANPLUS. +It can do this by either a pure perl solution (preferred) with the +use of C<Archive::Tar> and C<Compress::Zlib>, or with binaries, like +C<gzip> and C<tar>. + +The flow looks like this: + + $cb->_extract + Delegate to Archive::Extract + +=head1 METHODS + +=head2 $dir = _extract( module => $modobj, [perl => '/path/to/perl', extractdir => '/path/to/extract/to', prefer_bin => BOOL, verbose => BOOL, force => BOOL] ) + +C<_extract> will take a module object and extract it to C<extractdir> +if provided, or the default location which is obtained from your +config. + +The file name is obtained by looking at C<< $modobj->status->fetch >> +and will be parsed to see if it's a tar or zip archive. + +If it's a zip archive, C<__unzip> will be called, otherwise C<__untar> +will be called. In the unlikely event the file is of neither format, +an error will be thrown. + +C<_extract> takes the following options: + +=over 4 + +=item module + +A C<CPANPLUS::Module> object. This is required. + +=item extractdir + +The directory to extract the archive to. By default this looks +something like: + /CPANPLUS_BASE/PERL_VERSION/BUILD/MODULE_NAME + +=item prefer_bin + +A flag indicating whether you prefer a pure perl solution, ie +C<Archive::Tar> or C<Archive::Zip> respectively, or a binary solution +like C<unzip> and C<tar>. + +=item perl + +The path to the perl executable to use for any perl calls. Also used +to determine the build version directory for extraction. + +=item verbose + +Specifies whether to be verbose or not. Defaults to your corresponding +config entry. + +=item force + +Specifies whether to force the extraction or not. Defaults to your +corresponding config entry. + +=back + +All other options are passed on verbatim to C<__unzip> or C<__untar>. + +Returns the directory the file was extracted to on success and false +on failure. + +=cut + +sub _extract { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + local $Params::Check::ALLOW_UNKNOWN = 1; + + my( $mod, $verbose, $force ); + my $tmpl = { + force => { default => $conf->get_conf('force'), + store => \$force }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + prefer_bin => { default => $conf->get_conf('prefer_bin') }, + extractdir => { default => $conf->get_conf('extractdir') }, + module => { required => 1, allow => IS_MODOBJ, store => \$mod }, + perl => { default => $^X }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + ### did we already extract it ? ### + my $loc = $mod->status->extract(); + + if( $loc && !$force ) { + msg(loc("Already extracted '%1' to '%2'. ". + "Won't extract again without force", + $mod->module, $loc), $verbose); + return $loc; + } + + ### did we already fetch the file? ### + my $file = $mod->status->fetch(); + unless( -s $file ) { + error( loc( "File '%1' has zero size: cannot extract", $file ) ); + return; + } + + ### the dir to extract to ### + my $to = $args->{'extractdir'} || + File::Spec->catdir( + $conf->get_conf('base'), + $self->_perl_version( perl => $args->{'perl'} ), + $conf->_get_build('moddir'), + ); + + ### delegate to Archive::Extract ### + ### set up some flags for archive::extract ### + local $Archive::Extract::PREFER_BIN = $args->{'prefer_bin'}; + local $Archive::Extract::DEBUG = $conf->get_conf('debug'); + local $Archive::Extract::WARN = $verbose; + + my $ae = Archive::Extract->new( archive => $file ); + + unless( $ae->extract( to => $to ) ) { + error( loc( "Unable to extract '%1' to '%2': %3", + $file, $to, $ae->error ) ); + return; + } + + ### if ->files is not filled, we dont know what the hell was + ### extracted.. try to offer a suggestion and bail :( + unless ( $ae->files ) { + error( loc( "'%1' was not able to determine extracted ". + "files from the archive. Instal '%2' and ensure ". + "it works properly and try again", + $ae->is_zip ? 'Archive::Zip' : 'Archive::Tar' ) ); + return; + } + + + ### print out what files we extracted ### + msg(loc("Extracted '%1'",$_),$verbose) for @{$ae->files}; + + ### set them all to be +w for the owner, so we don't get permission + ### denied for overwriting files that are just +r + + ### this is to rigurous -- just change to +w for the owner [cpan #13358] + #chmod 0755, map { File::Spec->rel2abs( File::Spec->catdir($to, $_) ) } + # @{$ae->files}; + + for my $file ( @{$ae->files} ) { + my $path = File::Spec->rel2abs( File::Spec->catfile($to, $file) ); + + $self->_mode_plus_w( file => $path ); + } + + ### check the return value for the extracted path ### + ### Make an educated guess if we didn't get an extract_path + ### back + ### XXX apparently some people make their own dists and they + ### pack up '.' which means the leading directory is '.' + ### and only the second directory is the actual module directory + ### so, we'll have to check if our educated guess exists first, + ### then see if the extract path works.. and if nothing works... + ### well, then we really don't know. + + my $dir; + for my $try ( + File::Spec->rel2abs( + ### _safe_path must be called before catdir because catdir on + ### VMS currently will not handle the extra dots in the directories. + File::Spec->catdir( $self->_safe_path( path => $to ) , + $self->_safe_path( path => + $mod->package_name .'-'. + $mod->package_version + ) ) ) , + File::Spec->rel2abs( $ae->extract_path ), + ) { + ($dir = $try) && last if -d $try; + } + + ### test if the dir exists ### + unless( $dir && -d $dir ) { + error(loc("Unable to determine extract dir for '%1'",$mod->module)); + return; + + } else { + msg(loc("Extracted '%1' to '%2'", $mod->module, $dir), $verbose); + + ### register where we extracted the files to, + ### also store what files were extracted + $mod->status->extract( $dir ); + $mod->status->files( $ae->files ); + } + + ### also, figure out what kind of install we're dealing with ### + $mod->get_installer_type(); + + return $mod->status->extract(); +} + +1; + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Fetch.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Fetch.pm new file mode 100644 index 00000000000..395965bab60 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Fetch.pm @@ -0,0 +1,473 @@ +package CPANPLUS::Internals::Fetch; + +use strict; + +use CPANPLUS::Error; +use CPANPLUS::Internals::Constants; + +use File::Fetch; +use File::Spec; +use Cwd qw[cwd]; +use IPC::Cmd qw[run]; +use Params::Check qw[check]; +use Module::Load::Conditional qw[can_load]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +$Params::Check::VERBOSE = 1; + +=pod + +=head1 NAME + +CPANPLUS::Internals::Fetch + +=head1 SYNOPSIS + + my $output = $cb->_fetch( + module => $modobj, + fetchdir => '/path/to/save/to', + verbose => BOOL, + force => BOOL, + ); + + $cb->_add_fail_host( host => 'foo.com' ); + $cb->_host_ok( host => 'foo.com' ); + + +=head1 DESCRIPTION + +CPANPLUS::Internals::Fetch fetches files from either ftp, http, file +or rsync mirrors. + +This is the rough flow: + + $cb->_fetch + Delegate to File::Fetch; + + +=head1 METHODS + +=cut + +=head1 $path = _fetch( module => $modobj, [fetchdir => '/path/to/save/to', fetch_from => 'scheme://path/to/fetch/from', verbose => BOOL, force => BOOL, prefer_bin => BOOL, ttl => $seconds] ) + +C<_fetch> will fetch files based on the information in a module +object. You always need a module object. If you want a fake module +object for a one-off fetch, look at C<CPANPLUS::Module::Fake>. + +C<fetchdir> is the place to save the file to. Usually this +information comes from your configuration, but you can override it +expressly if needed. + +C<fetch_from> lets you specify an URI to get this file from. If you +do not specify one, your list of configured hosts will be probed to +download the file from. + +C<force> forces a new download, even if the file already exists. + +C<verbose> simply indicates whether or not to print extra messages. + +C<prefer_bin> indicates whether you prefer the use of commandline +programs over perl modules. Defaults to your corresponding config +setting. + +C<ttl> (in seconds) indicates how long a cached copy is valid for. If +the fetch time of the local copy is within the ttl, the cached copy is +returned. Otherwise, the file is refetched. + +C<_fetch> figures out, based on the host list, what scheme to use and +from there, delegates to C<File::Fetch> do the actual fetching. + +Returns the path of the output file on success, false on failure. + +Note that you can set a C<blacklist> on certain methods in the config. +Simply add the identifying name of the method (ie, C<lwp>) to: + $conf->_set_fetch( blacklist => ['lwp'] ); + +And the C<LWP> function will be skipped by C<File::Fetch>. + +=cut + +sub _fetch { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + local $Params::Check::NO_DUPLICATES = 0; + + my ($modobj, $verbose, $force, $fetch_from, $ttl); + my $tmpl = { + module => { required => 1, allow => IS_MODOBJ, store => \$modobj }, + fetchdir => { default => $conf->get_conf('fetchdir') }, + fetch_from => { default => '', store => \$fetch_from }, + force => { default => $conf->get_conf('force'), + store => \$force }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + prefer_bin => { default => $conf->get_conf('prefer_bin') }, + ttl => { default => 0, store => \$ttl }, + }; + + + my $args = check( $tmpl, \%hash ) or return; + + ### check if we already downloaded the thing ### + if( (my $where = $modobj->status->fetch()) and not $force and not $ttl ) { + + msg(loc("Already fetched '%1' to '%2', " . + "won't fetch again without force", + $modobj->module, $where ), $verbose ); + return $where; + } + + my ($remote_file, $local_file, $local_path); + + ### build the local path to downlaod to ### + { + $local_path = $args->{fetchdir} || + File::Spec->catdir( + $conf->get_conf('base'), + $modobj->path, + ); + + ### create the path if it doesn't exist ### + unless( -d $local_path ) { + unless( $self->_mkdir( dir => $local_path ) ) { + msg( loc("Could not create path '%1'", $local_path), $verbose); + return; + } + } + + $local_file = File::Spec->rel2abs( + File::Spec->catfile( + $local_path, + $modobj->package, + ) + ); + + ### do we already have the file? if so, can we use the cached version, + ### or do we need to refetch? + if( -e $local_file ) { + + my $unlink = 0; + my $use_cached = 0; + + ### if force is in effect, we have to refetch + if( $force ) { + $unlink++ + + ### if you provided a ttl, and it was exceeded, we'll refetch, + } elsif( $ttl and ([stat $local_file]->[9] + $ttl > time) ) { + msg(loc("Using cached file '%1' on disk; ". + "ttl (%2s) is not exceeded", + $local_file, $ttl), $verbose ); + + $use_cached++; + + ### if you provided a ttl, and the above conditional didn't match, + ### we exceeded the ttl, so we refetch + } elsif ( $ttl ) { + $unlink++; + + ### otherwise we can use the cached version + } else { + $use_cached++; + } + + if( $unlink ) { + ### some fetches will fail if the files exist already, so let's + ### delete them first + 1 while unlink $local_file; + + msg(loc("Could not delete %1, some methods may " . + "fail to force a download", $local_file), $verbose) + if -e $local_file; + + } else { + + ### store where we fetched it ### + $modobj->status->fetch( $local_file ); + + return $local_file; + } + } + } + + + ### we got a custom URI + if ( $fetch_from ) { + my $abs = $self->__file_fetch( from => $fetch_from, + to => $local_path, + verbose => $verbose ); + + unless( $abs ) { + error(loc("Unable to download '%1'", $fetch_from)); + return; + } + + ### store where we fetched it ### + $modobj->status->fetch( $abs ); + + return $abs; + + ### we will get it from one of our mirrors + } else { + ### build the remote path to download from ### + { $remote_file = File::Spec::Unix->catfile( + $modobj->path, + $modobj->package, + ); + unless( $remote_file ) { + error( loc('No remote file given for download') ); + return; + } + } + + ### see if we even have a host or a method to use to download with ### + my $found_host; + my @maybe_bad_host; + + HOST: { + ### F*CKING PIECE OF F*CKING p4 SHIT makes + ### '$File :: Fetch::SOME_VAR' + ### into a meta variable and starts substituting the file name... + ### GRAAAAAAAAAAAAAAAAAAAAAAH! + ### use ' to combat it! + + ### set up some flags for File::Fetch ### + local $File'Fetch::BLACKLIST = $conf->_get_fetch('blacklist'); + local $File'Fetch::TIMEOUT = $conf->get_conf('timeout'); + local $File'Fetch::DEBUG = $conf->get_conf('debug'); + local $File'Fetch::FTP_PASSIVE = $conf->get_conf('passive'); + local $File'Fetch::FROM_EMAIL = $conf->get_conf('email'); + local $File'Fetch::PREFER_BIN = $conf->get_conf('prefer_bin'); + local $File'Fetch::WARN = $verbose; + + + ### loop over all hosts we have ### + for my $host ( @{$conf->get_conf('hosts')} ) { + $found_host++; + + my $where; + + ### file:// uris are special and need parsing + if( $host->{'scheme'} eq 'file' ) { + + ### the full path in the native format of the OS + my $host_spec = + File::Spec->file_name_is_absolute( $host->{'path'} ) + ? $host->{'path'} + : File::Spec->rel2abs( $host->{'path'} ); + + ### there might be volumes involved on vms/win32 + if( ON_WIN32 or ON_VMS ) { + + ### now extract the volume in order to be Win32 and + ### VMS friendly. + ### 'no_file' indicates that there's no file part + ### of this path, so we only get 2 bits returned. + my ($vol, $host_path) = File::Spec->splitpath( + $host_spec, 'no_file' + ); + + ### and split up the directories + my @host_dirs = File::Spec->splitdir( $host_path ); + + ### if we got a volume we pretend its a directory for + ### the sake of the file:// url + if( defined $vol and $vol ) { + + ### D:\foo\bar needs to be encoded as D|\foo\bar + ### For details, see the following link: + ### http://en.wikipedia.org/wiki/File:// + ### The RFC doesnt seem to address Windows volume + ### descriptors but it does address VMS volume + ### descriptors, however wikipedia covers a bit of + ### history regarding win32 + $vol =~ s/:$/|/ if ON_WIN32; + + $vol =~ s/:// if ON_VMS; + + ### XXX i'm not sure what cases this is addressing. + ### this comes straight from dmq's file:// patches + ### for win32. --kane + ### According to dmq, the best summary is: + ### "if file:// urls dont look right on VMS reuse + ### the win32 logic and see if that fixes things" + + ### first element not empty? Might happen on VMS. + ### prepend the volume in that case. + if( $host_dirs[0] ) { + unshift @host_dirs, $vol; + + ### element empty? reuse it to store the volume + ### encoded as a directory name. (Win32/VMS) + } else { + $host_dirs[0] = $vol; + } + } + + ### now it's in UNIX format, which is the same format + ### as used for URIs + $host_spec = File::Spec::Unix->catdir( @host_dirs ); + } + + ### now create the file:// uri from the components + $where = CREATE_FILE_URI->( + File::Spec::Unix->catfile( + $host->{'host'} || '', + $host_spec, + $remote_file, + ) + ); + + ### its components will be in unix format, for a http://, + ### ftp:// or any other style of URI + } else { + my $mirror_path = File::Spec::Unix->catfile( + $host->{'path'}, $remote_file + ); + + my %args = ( scheme => $host->{scheme}, + host => $host->{host}, + path => $mirror_path, + ); + + $where = $self->_host_to_uri( %args ); + } + + my $abs = $self->__file_fetch( from => $where, + to => $local_path, + verbose => $verbose ); + + ### we got a path back? + if( $abs ) { + ### store where we fetched it ### + $modobj->status->fetch( $abs ); + + ### this host is good, the previous ones are apparently + ### not, so mark them as such. + $self->_add_fail_host( host => $_ ) for @maybe_bad_host; + + return $abs; + } + + ### so we tried to get the file but didn't actually fetch it -- + ### there's a chance this host is bad. mark it as such and + ### actually flag it back if we manage to get the file + ### somewhere else + push @maybe_bad_host, $host; + } + } + + $found_host + ? error(loc("Fetch failed: host list exhausted " . + "-- are you connected today?")) + : error(loc("No hosts found to download from " . + "-- check your config")); + } + + return; +} + +sub __file_fetch { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my ($where, $local_path, $verbose); + my $tmpl = { + from => { required => 1, store => \$where }, + to => { required => 1, store => \$local_path }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + }; + + check( $tmpl, \%hash ) or return; + + msg(loc("Trying to get '%1'", $where ), $verbose ); + + ### build the object ### + my $ff = File::Fetch->new( uri => $where ); + + ### sanity check ### + error(loc("Bad uri '%1'",$where)), return unless $ff; + + if( my $file = $ff->fetch( to => $local_path ) ) { + unless( -e $file && -s _ ) { + msg(loc("'%1' said it fetched '%2', but it was not created", + 'File::Fetch', $file), $verbose); + + } else { + my $abs = File::Spec->rel2abs( $file ); + + ### so TTLs will work + $self->_update_timestamp( file => $abs ); + + return $abs; + } + + } else { + error(loc("Fetching of '%1' failed: %2", $where, $ff->error)); + } + + return; +} + +=pod + +=head2 _add_fail_host( host => $host_hashref ) + +Mark a particular host as bad. This makes C<CPANPLUS::Internals::Fetch> +skip it in fetches until this cache is flushed. + +=head2 _host_ok( host => $host_hashref ) + +Query the cache to see if this host is ok, or if it has been flagged +as bad. + +Returns true if the host is ok, false otherwise. + +=cut + +{ ### caching functions ### + + sub _add_fail_host { + my $self = shift; + my %hash = @_; + + my $host; + my $tmpl = { + host => { required => 1, default => {}, + strict_type => 1, store => \$host }, + }; + + check( $tmpl, \%hash ) or return; + + return $self->_hosts->{$host} = 1; + } + + sub _host_ok { + my $self = shift; + my %hash = @_; + + my $host; + my $tmpl = { + host => { required => 1, store => \$host }, + }; + + check( $tmpl, \%hash ) or return; + + return $self->_hosts->{$host} ? 0 : 1; + } +} + + +1; + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Report.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Report.pm new file mode 100644 index 00000000000..774c6b91a02 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Report.pm @@ -0,0 +1,645 @@ +package CPANPLUS::Internals::Report; + +use strict; + +use CPANPLUS::Error; +use CPANPLUS::Internals::Constants; +use CPANPLUS::Internals::Constants::Report; + +use Data::Dumper; + +use Params::Check qw[check]; +use Module::Load::Conditional qw[can_load]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +$Params::Check::VERBOSE = 1; + +### for the version ### +require CPANPLUS::Internals; + +=head1 NAME + +CPANPLUS::Internals::Report + +=head1 SYNOPSIS + + ### enable test reporting + $cb->configure_object->set_conf( cpantest => 1 ); + + ### set custom mx host, shouldn't normally be needed + $cb->configure_object->set_conf( cpantest_mx => 'smtp.example.com' ); + +=head1 DESCRIPTION + +This module provides all the functionality to send test reports to +C<http://testers.cpan.org> using the C<Test::Reporter> module. + +All methods will be called automatically if you have C<CPANPLUS> +configured to enable test reporting (see the C<SYNOPSIS>). + +=head1 METHODS + +=head2 $bool = $cb->_have_query_report_modules + +This function checks if all the required modules are here for querying +reports. It returns true and loads them if they are, or returns false +otherwise. + +=head2 $bool = $cb->_have_send_report_modules + +This function checks if all the required modules are here for sending +reports. It returns true and loads them if they are, or returns false +otherwise. + +=cut + +### XXX remove this list and move it into selfupdate, somehow.. +### this is dual administration +{ my $query_list = { + 'File::Fetch' => '0.13_02', + 'Parse::CPAN::Meta' => '0.0', + 'File::Temp' => '0.0', + }; + + my $send_list = { + %$query_list, + 'Test::Reporter' => '1.34', + }; + + sub _have_query_report_modules { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my $tmpl = { + verbose => { default => $conf->get_conf('verbose') }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + return can_load( modules => $query_list, verbose => $args->{verbose} ) + ? 1 + : 0; + } + + sub _have_send_report_modules { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my $tmpl = { + verbose => { default => $conf->get_conf('verbose') }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + return can_load( modules => $send_list, verbose => $args->{verbose} ) + ? 1 + : 0; + } +} + +=head2 @list = $cb->_query_report( module => $modobj, [all_versions => BOOL, verbose => BOOL] ) + +This function queries the CPAN testers database at +I<http://testers.cpan.org/> for test results of specified module objects, +module names or distributions. + +The optional argument C<all_versions> controls whether all versions of +a given distribution should be grabbed. It defaults to false +(fetching only reports for the current version). + +Returns the a list with the following data structures (for CPANPLUS +version 0.042) on success, or false on failure. The contents of the +data structure depends on what I<http://testers.cpan.org> returns, +but generally looks like this: + + { + 'grade' => 'PASS', + 'dist' => 'CPANPLUS-0.042', + 'platform' => 'i686-pld-linux-thread-multi' + 'details' => 'http://nntp.x.perl.org/group/perl.cpan.testers/98316' + ... + }, + { + 'grade' => 'PASS', + 'dist' => 'CPANPLUS-0.042', + 'platform' => 'i686-linux-thread-multi' + 'details' => 'http://nntp.x.perl.org/group/perl.cpan.testers/99416' + ... + }, + { + 'grade' => 'FAIL', + 'dist' => 'CPANPLUS-0.042', + 'platform' => 'cygwin-multi-64int', + 'details' => 'http://nntp.x.perl.org/group/perl.cpan.testers/99371' + ... + }, + { + 'grade' => 'FAIL', + 'dist' => 'CPANPLUS-0.042', + 'platform' => 'i586-linux', + 'details' => 'http://nntp.x.perl.org/group/perl.cpan.testers/99396' + ... + }, + +The status of the test can be one of the following: +UNKNOWN, PASS, FAIL or NA (not applicable). + +=cut + +sub _query_report { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my($mod, $verbose, $all); + my $tmpl = { + module => { required => 1, allow => IS_MODOBJ, + store => \$mod }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + all_versions => { default => 0, store => \$all }, + }; + + check( $tmpl, \%hash ) or return; + + ### check if we have the modules we need for querying + return unless $self->_have_query_report_modules( verbose => 1 ); + + + ### XXX no longer use LWP here. However, that means we don't + ### automagically set proxies anymore!!! + # my $ua = LWP::UserAgent->new; + # $ua->agent( CPANPLUS_UA->() ); + # + ### set proxies if we have them ### + # $ua->env_proxy(); + + my $url = TESTERS_URL->($mod->package_name); + my $ff = File::Fetch->new( uri => $url ); + + msg( loc("Fetching: '%1'", $url), $verbose ); + + my $res = do { + my $tempdir = File::Temp::tempdir(); + my $where = $ff->fetch( to => $tempdir ); + + unless( $where ) { + error( loc( "Fetching report for '%1' failed: %2", + $url, $ff->error ) ); + return; + } + + my $fh = OPEN_FILE->( $where ); + + do { local $/; <$fh> }; + }; + + my ($aref) = eval { Parse::CPAN::Meta::Load( $res ) }; + + if( $@ ) { + error(loc("Error reading result: %1", $@)); + return; + }; + + my $dist = $mod->package_name .'-'. $mod->package_version; + my $details = TESTERS_DETAILS_URL->($mod->package_name); + + my @rv; + for my $href ( @$aref ) { + next unless $all or defined $href->{'distversion'} && + $href->{'distversion'} eq $dist; + + $href->{'details'} = $details; + + ### backwards compatibility :( + $href->{'dist'} ||= $href->{'distversion'}; + $href->{'grade'} ||= $href->{'action'} || $href->{'status'}; + + push @rv, $href; + } + + return @rv if @rv; + return; +} + +=pod + +=head2 $bool = $cb->_send_report( module => $modobj, buffer => $make_output, failed => BOOL, [save => BOOL, address => $email_to, verbose => BOOL, force => BOOL]); + +This function sends a testers report to C<cpan-testers@perl.org> for a +particular distribution. +It returns true on success, and false on failure. + +It takes the following options: + +=over 4 + +=item module + +The module object of this particular distribution + +=item buffer + +The output buffer from the 'make/make test' process + +=item failed + +Boolean indicating if the 'make/make test' went wrong + +=item save + +Boolean indicating if the report should be saved locally instead of +mailed out. If provided, this function will return the location the +report was saved to, rather than a simple boolean 'TRUE'. + +Defaults to false. + +=item address + +The email address to mail the report for. You should never need to +override this, but it might be useful for debugging purposes. + +Defaults to C<cpan-testers@perl.org>. + +=item verbose + +Boolean indicating on whether or not to be verbose. + +Defaults to your configuration settings + +=item force + +Boolean indicating whether to force the sending, even if the max +amount of reports for fails have already been reached, or if you +may already have sent it before. + +Defaults to your configuration settings + +=back + +=cut + +sub _send_report { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + ### do you even /have/ test::reporter? ### + unless( $self->_have_send_report_modules(verbose => 1) ) { + error( loc( "You don't have '%1' (or modules required by '%2') ". + "installed, you cannot report test results.", + 'Test::Reporter', 'Test::Reporter' ) ); + return; + } + + ### check arguments ### + my ($buffer, $failed, $mod, $verbose, $force, $address, $save, + $tests_skipped ); + my $tmpl = { + module => { required => 1, store => \$mod, allow => IS_MODOBJ }, + buffer => { required => 1, store => \$buffer }, + failed => { required => 1, store => \$failed }, + address => { default => CPAN_TESTERS_EMAIL, store => \$address }, + save => { default => 0, store => \$save }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + force => { default => $conf->get_conf('force'), + store => \$force }, + tests_skipped + => { default => 0, store => \$tests_skipped }, + }; + + check( $tmpl, \%hash ) or return; + + ### get the data to fill the email with ### + my $name = $mod->module; + my $dist = $mod->package_name . '-' . $mod->package_version; + my $author = $mod->author->author; + my $email = $mod->author->email || CPAN_MAIL_ACCOUNT->( $author ); + my $cp_conf = $conf->get_conf('cpantest') || ''; + my $int_ver = $CPANPLUS::Internals::VERSION; + my $cb = $mod->parent; + + + ### will be 'fetch', 'make', 'test', 'install', etc ### + my $stage = TEST_FAIL_STAGE->($buffer); + + ### determine the grade now ### + + my $grade; + ### check if this is a platform specific module ### + ### if we failed the test, there may be reasons why + ### an 'NA' might have to be insted + GRADE: { if ( $failed ) { + + + ### XXX duplicated logic between this block + ### and REPORTED_LOADED_PREREQS :( + + ### figure out if the prereqs are on CPAN at all + ### -- if not, send NA grade + ### Also, if our version of prereqs is too low, + ### -- send NA grade. + ### This is to address bug: #25327: do not count + ### as FAIL modules where prereqs are not filled + { my $prq = $mod->status->prereqs || {}; + + while( my($prq_name,$prq_ver) = each %$prq ) { + my $obj = $cb->module_tree( $prq_name ); + my $sub = CPANPLUS::Module->can( + 'module_is_supplied_with_perl_core' ); + + ### if we can't find the module and it's not supplied with core. + ### this addresses: #32064: NA reports generated for failing + ### tests where core prereqs are specified + ### Note that due to a bug in Module::CoreList, in some released + ### version of perl (5.8.6+ and 5.9.2-4 at the time of writing) + ### 'Config' is not recognized as a core module. See this bug: + ### http://rt.cpan.org/Ticket/Display.html?id=32155 + if( !$obj and !$sub->( $prq_name ) ) { + msg(loc( "Prerequisite '%1' for '%2' could not be obtained". + " from CPAN -- sending N/A grade", + $prq_name, $name ), $verbose ); + + $grade = GRADE_NA; + last GRADE; + } + + if ( !$obj ) { + my $vcore = $sub->( $prq_name ); + if ( $cb->_vcmp( $prq_ver, $vcore ) > 0 ) { + msg(loc( "Version of core module '%1' ('%2') is too low for ". + "'%3' (needs '%4') -- sending N/A grade", + $prq_name, $vcore, + $name, $prq_ver ), $verbose ); + + $grade = GRADE_NA; + last GRADE; + } + } + + if( $obj and $cb->_vcmp( $prq_ver, $obj->installed_version ) > 0 ) { + msg(loc( "Installed version of '%1' ('%2') is too low for ". + "'%3' (needs '%4') -- sending N/A grade", + $prq_name, $obj->installed_version, + $name, $prq_ver ), $verbose ); + + $grade = GRADE_NA; + last GRADE; + } + } + } + + unless( RELEVANT_TEST_RESULT->($mod) ) { + msg(loc( + "'%1' is a platform specific module, and the test results on". + " your platform are not relevant --sending N/A grade.", + $name), $verbose); + + $grade = GRADE_NA; + + } elsif ( UNSUPPORTED_OS->( $buffer ) ) { + msg(loc( + "'%1' is a platform specific module, and the test results on". + " your platform are not relevant --sending N/A grade.", + $name), $verbose); + + $grade = GRADE_NA; + + ### you dont have a high enough perl version? + } elsif ( PERL_VERSION_TOO_LOW->( $buffer ) ) { + msg(loc("'%1' requires a higher version of perl than your current ". + "version -- sending N/A grade.", $name), $verbose); + + $grade = GRADE_NA; + + ### perhaps where were no tests... + ### see if the thing even had tests ### + } elsif ( NO_TESTS_DEFINED->( $buffer ) ) { + $grade = GRADE_UNKNOWN; + ### failures in PL or make/build stage are now considered UNKNOWN + } elsif ( $stage !~ /\btest\b/ ) { + + $grade = GRADE_UNKNOWN + + } else { + + $grade = GRADE_FAIL; + } + + ### if we got here, it didn't fail and tests were present.. so a PASS + ### is in order + } else { + $grade = GRADE_PASS; + } } + + ### so an error occurred, let's see what stage it went wrong in ### + + ### the header -- always include so the CPANPLUS version is apparent + my $message = REPORT_MESSAGE_HEADER->( $int_ver, $author ); + + if( $grade eq GRADE_FAIL or $grade eq GRADE_UNKNOWN) { + + ### return if one or more missing external libraries + if( my @missing = MISSING_EXTLIBS_LIST->($buffer) ) { + msg(loc("Not sending test report - " . + "external libraries not pre-installed")); + return 1; + } + + ### return if we're only supposed to report make_test failures ### + return 1 if $cp_conf =~ /\bmaketest_only\b/i + and ($stage !~ /\btest\b/); + + ### the bit where we inform what went wrong + $message .= REPORT_MESSAGE_FAIL_HEADER->( $stage, $buffer ); + + ### was it missing prereqs? ### + if( my @missing = MISSING_PREREQS_LIST->($buffer) ) { + if(!$self->_verify_missing_prereqs( + module => $mod, + missing => \@missing + )) { + msg(loc("Not sending test report - " . + "bogus missing prerequisites report")); + return 1; + } + $message .= REPORT_MISSING_PREREQS->($author,$email,@missing); + } + + ### was it missing test files? ### + if( NO_TESTS_DEFINED->($buffer) ) { + $message .= REPORT_MISSING_TESTS->(); + } + + ### add a list of what modules have been loaded of your prereqs list + $message .= REPORT_LOADED_PREREQS->($mod); + + ### add a list of versions of toolchain modules + $message .= REPORT_TOOLCHAIN_VERSIONS->($mod); + + ### the footer + $message .= REPORT_MESSAGE_FOOTER->(); + + ### it may be another grade than fail/unknown.. may be worth noting + ### that tests got skipped, since the buffer is not added in + } elsif ( $tests_skipped ) { + $message .= REPORT_TESTS_SKIPPED->(); + } elsif( $grade eq GRADE_NA) { + + ### the bit where we inform what went wrong + $message .= REPORT_MESSAGE_FAIL_HEADER->( $stage, $buffer ); + + ### the footer + $message .= REPORT_MESSAGE_FOOTER->(); + + } + + msg( loc("Sending test report for '%1'", $dist), $verbose); + + ### reporter object ### + my $reporter = do { + my $args = $conf->get_conf('cpantest_reporter_args') || {}; + + unless( UNIVERSAL::isa( $args, 'HASH' ) ) { + error(loc("'%1' must be a hashref, ignoring...", + 'cpantest_reporter_args')); + $args = {}; + } + + Test::Reporter->new( + grade => $grade, + distribution => $dist, + via => "CPANPLUS $int_ver", + timeout => $conf->get_conf('timeout') || 60, + debug => $conf->get_conf('debug'), + %$args, + ); + }; + + ### set a custom mx, if requested + $reporter->mx( [ $conf->get_conf('cpantest_mx') ] ) + if $conf->get_conf('cpantest_mx'); + + ### set the from address ### + $reporter->from( $conf->get_conf('email') ) + if $conf->get_conf('email') !~ /\@example\.\w+$/i; + + ### give the user a chance to programattically alter the message + $message = $self->_callbacks->munge_test_report->($mod, $message, $grade); + + ### add the body if we have any ### + $reporter->comments( $message ) if defined $message && length $message; + + ### do a callback to ask if we should send the report + unless ($self->_callbacks->send_test_report->($mod, $grade)) { + msg(loc("Ok, not sending test report")); + return 1; + } + + ### do a callback to ask if we should edit the report + if ($self->_callbacks->edit_test_report->($mod, $grade)) { + ### test::reporter 1.20 and lower don't have a way to set + ### the preferred editor with a method call, but it does + ### respect your env variable, so let's set that. + local $ENV{VISUAL} = $conf->get_program('editor') + if $conf->get_program('editor'); + + $reporter->edit_comments; + } + + ### allow to be overridden, but default to the normal address ### + $reporter->address( $address ); + + ### should we save it locally? ### + if( $save ) { + if( my $file = $reporter->write() ) { + msg(loc("Successfully wrote report for '%1' to '%2'", + $dist, $file), $verbose); + return $file; + + } else { + error(loc("Failed to write report for '%1'", $dist)); + return; + } + + ### XXX should we do an 'already sent' check? ### + ### something broke :( ### + } + else { + my $status; + eval { + $status = $reporter->send(); + }; + if ( $@ ) { + error(loc("Could not send '%1' report for '%2': %3", + $grade, $dist, $@)); + return; + } + if ( $status ) { + msg(loc("Successfully sent '%1' report for '%2'", $grade, $dist), + $verbose); + return 1; + } + error(loc("Could not send '%1' report for '%2': %3", + $grade, $dist, $reporter->errstr)); + return; + } +} + +sub _verify_missing_prereqs { + my $self = shift; + my %hash = @_; + + ### check arguments ### + my ($mod, $missing); + my $tmpl = { + module => { required => 1, store => \$mod }, + missing => { required => 1, store => \$missing }, + }; + + check( $tmpl, \%hash ) or return; + + + my %missing = map {$_ => 1} @$missing; + my $conf = $self->configure_object; + my $extract = $mod->status->extract; + + ### Read pre-requisites from Makefile.PL or Build.PL (if there is one), + ### of the form: + ### 'PREREQ_PM' => { + ### 'Compress::Zlib' => '1.20', + ### 'Test::More' => 0, + ### }, + ### Build.PL uses 'requires' instead of 'PREREQ_PM'. + + my @search; + push @search, ($extract ? MAKEFILE_PL->( $extract ) : MAKEFILE_PL->()); + push @search, ($extract ? BUILD_PL->( $extract ) : BUILD_PL->()); + + for my $file ( @search ) { + if(-e $file and -r $file) { + my $slurp = $self->_get_file_contents(file => $file); + my ($prereq) = + ($slurp =~ /'?(?:PREREQ_PM|requires)'?\s*=>\s*{(.*?)}/s); + my @prereq = + ($prereq =~ /'?([\w\:]+)'?\s*=>\s*'?\d[\d\.\-\_]*'?/sg); + delete $missing{$_} for(@prereq); + } + } + + return 1 if(keys %missing); # There ARE missing prerequisites + return; # All prerequisites accounted for +} + +1; + + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Search.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Search.pm new file mode 100644 index 00000000000..63c4da64d92 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Search.pm @@ -0,0 +1,363 @@ +package CPANPLUS::Internals::Search; + +use strict; + +use CPANPLUS::Error; +use CPANPLUS::Internals::Constants; +use CPANPLUS::Module; +use CPANPLUS::Module::Author; + +use File::Find; +use File::Spec; + +use Params::Check qw[check allow]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +$Params::Check::VERBOSE = 1; + +=pod + +=head1 NAME + +CPANPLUS::Internals::Search + +=head1 SYNOPSIS + + my $aref = $cpan->_search_module_tree( + type => 'package', + allow => [qr/DBI/], + ); + + my $aref = $cpan->_search_author_tree( + type => 'cpanid', + data => \@old_results, + verbose => 1, + allow => [qw|KANE AUTRIJUS|], + ); + + my $aref = $cpan->_all_installed( ); + +=head1 DESCRIPTION + +The functions in this module are designed to find module(objects) +based on certain criteria and return them. + +=head1 METHODS + +=head2 _search_module_tree( type => TYPE, allow => \@regexes, [data => \@previous_results ] ) + +Searches the moduletree for module objects matching the criteria you +specify. Returns an array ref of module objects on success, and false +on failure. + +It takes the following arguments: + +=over 4 + +=item type + +This can be any of the accessors for the C<CPANPLUS::Module> objects. +This is a required argument. + +=item allow + +A set of rules, or more precisely, a list of regexes (via C<qr//> or +plain strings), that the C<type> must adhere too. You can specify as +many as you like, and it will be treated as an C<OR> search. +For an C<AND> search, see the C<data> argument. + +This is a required argument. + +=item data + +An arrayref of previous search results. This is the way to do an C<AND> +search -- C<_search_module_tree> will only search the module objects +specified in C<data> if provided, rather than the moduletree itself. + +=back + +=cut + +# Although the Params::Check solution is more graceful, it is WAY too slow. +# +# This sample script: +# +# use CPANPLUS::Backend; +# my $cb = new CPANPLUS::Backend; +# $cb->module_tree; +# my @list = $cb->search( type => 'module', allow => [qr/^Acme/] ); +# print $_->module, $/ for @list; +# +# Produced the following output using Dprof WITH params::check code +# +# Total Elapsed Time = 3.670024 Seconds +# User+System Time = 3.390373 Seconds +# Exclusive Times +# %Time ExclSec CumulS #Calls sec/call Csec/c Name +# 88.7 3.008 4.463 20610 0.0001 0.0002 Params::Check::check +# 47.4 1.610 1.610 1 1.6100 1.6100 Storable::net_pstore +# 25.6 0.869 0.737 20491 0.0000 0.0000 Locale::Maketext::Simple::_default +# _gettext +# 23.2 0.789 0.524 40976 0.0000 0.0000 Params::Check::_who_was_it +# 23.2 0.789 0.677 20610 0.0000 0.0000 Params::Check::_sanity_check +# 19.7 0.670 0.670 1 0.6700 0.6700 Storable::pretrieve +# 14.1 0.480 0.211 41350 0.0000 0.0000 Params::Check::_convert_case +# 11.5 0.390 0.256 20610 0.0000 0.0000 Params::Check::_hashdefs +# 11.5 0.390 0.255 20697 0.0000 0.0000 Params::Check::_listreqs +# 11.4 0.389 0.177 20653 0.0000 0.0000 Params::Check::_canon_key +# 10.9 0.370 0.356 20697 0.0000 0.0000 Params::Check::_hasreq +# 8.02 0.272 4.750 1 0.2723 4.7501 CPANPLUS::Internals::Search::_sear +# ch_module_tree +# 6.49 0.220 0.086 20653 0.0000 0.0000 Params::Check::_iskey +# 6.19 0.210 0.077 20488 0.0000 0.0000 Params::Check::_store_error +# 5.01 0.170 0.036 20680 0.0000 0.0000 CPANPLUS::Module::__ANON__ +# +# and this output /without/ +# +# Total Elapsed Time = 2.803426 Seconds +# User+System Time = 2.493426 Seconds +# Exclusive Times +# %Time ExclSec CumulS #Calls sec/call Csec/c Name +# 56.9 1.420 1.420 1 1.4200 1.4200 Storable::net_pstore +# 25.6 0.640 0.640 1 0.6400 0.6400 Storable::pretrieve +# 9.22 0.230 0.096 20680 0.0000 0.0000 CPANPLUS::Module::__ANON__ +# 7.06 0.176 0.272 1 0.1762 0.2719 CPANPLUS::Internals::Search::_sear +# ch_module_tree +# 3.21 0.080 0.098 10 0.0080 0.0098 IPC::Cmd::BEGIN +# 1.60 0.040 0.205 13 0.0031 0.0158 CPANPLUS::Internals::BEGIN +# 1.20 0.030 0.030 29 0.0010 0.0010 vars::BEGIN +# 1.20 0.030 0.117 10 0.0030 0.0117 Log::Message::BEGIN +# 1.20 0.030 0.029 9 0.0033 0.0033 CPANPLUS::Internals::Search::BEGIN +# 0.80 0.020 0.020 5 0.0040 0.0040 DynaLoader::dl_load_file +# 0.80 0.020 0.127 10 0.0020 0.0127 CPANPLUS::Module::BEGIN +# 0.80 0.020 0.389 2 0.0099 0.1944 main::BEGIN +# 0.80 0.020 0.359 12 0.0017 0.0299 CPANPLUS::Backend::BEGIN +# 0.40 0.010 0.010 30 0.0003 0.0003 Config::FETCH +# 0.40 0.010 0.010 18 0.0006 0.0005 Locale::Maketext::Simple::load_loc +# + +sub _search_module_tree { + + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my($mods,$list,$verbose,$type); + my $tmpl = { + data => { default => [], + strict_type=> 1, store => \$mods }, + allow => { required => 1, default => [ ], strict_type => 1, + store => \$list }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + type => { required => 1, allow => [CPANPLUS::Module->accessors()], + store => \$type }, + }; + + my $args = do { + ### don't check the template for sanity + ### -- we know it's good and saves a lot of performance + local $Params::Check::SANITY_CHECK_TEMPLATE = 0; + + check( $tmpl, \%hash ); + } or return; + + ### a list of module objects was supplied + if( @$mods ) { + local $Params::Check::VERBOSE = 0; + + my @rv; + for my $mod (@$mods) { + #push @rv, $mod if check( + # { $type => { allow => $list } }, + # { $type => $mod->$type() } + # ); + push @rv, $mod if allow( $mod->$type() => $list ); + + } + return \@rv; + + } else { + my @rv = $self->_source_search_module_tree( + allow => $list, + type => $type, + ); + return \@rv; + } +} + +=pod + +=head2 _search_author_tree( type => TYPE, allow => \@regexex, [data => \@previous_results ] ) + +Searches the authortree for author objects matching the criteria you +specify. Returns an array ref of author objects on success, and false +on failure. + +It takes the following arguments: + +=over 4 + +=item type + +This can be any of the accessors for the C<CPANPLUS::Module::Author> +objects. This is a required argument. + +=item allow + + +A set of rules, or more precisely, a list of regexes (via C<qr//> or +plain strings), that the C<type> must adhere too. You can specify as +many as you like, and it will be treated as an C<OR> search. +For an C<AND> search, see the C<data> argument. + +This is a required argument. + +=item data + +An arrayref of previous search results. This is the way to do an C<and> +search -- C<_search_author_tree> will only search the author objects +specified in C<data> if provided, rather than the authortree itself. + +=back + +=cut + +sub _search_author_tree { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my($authors,$list,$verbose,$type); + my $tmpl = { + data => { default => [], + strict_type=> 1, store => \$authors }, + allow => { required => 1, default => [ ], strict_type => 1, + store => \$list }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + type => { required => 1, allow => [CPANPLUS::Module::Author->accessors()], + store => \$type }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + if( @$authors ) { + local $Params::Check::VERBOSE = 0; + + my @rv; + for my $auth (@$authors) { + #push @rv, $auth if check( + # { $type => { allow => $list } }, + # { $type => $auth->$type } + # ); + push @rv, $auth if allow( $auth->$type() => $list ); + } + return \@rv; + } else { + my @rv = $self->_source_search_author_tree( + allow => $list, + type => $type, + ); + return \@rv; + } +} + +=pod + +=head2 _all_installed() + +This function returns an array ref of module objects of modules that +are installed on this system. + +=cut + +sub _all_installed { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + ### File::Find uses follow_skip => 1 by default, which doesn't die + ### on duplicates, unless they are directories or symlinks. + ### Ticket #29796 shows this code dying on Alien::WxWidgets, + ### which uses symlinks. + ### File::Find doc says to use follow_skip => 2 to ignore duplicates + ### so this will stop it from dying. + my %find_args = ( follow_skip => 2 ); + + ### File::Find uses lstat, which quietly becomes stat on win32 + ### it then uses -l _ which is not allowed by the statbuffer because + ### you did a stat, not an lstat (duh!). so don't tell win32 to + ### follow symlinks, as that will break badly + $find_args{'follow_fast'} = 1 unless ON_WIN32; + + ### never use the @INC hooks to find installed versions of + ### modules -- they're just there in case they're not on the + ### perl install, but the user shouldn't trust them for *other* + ### modules! + ### XXX CPANPLUS::inc is now obsolete, remove the calls + #local @INC = CPANPLUS::inc->original_inc; + + my %seen; my @rv; + for my $dir (@INC ) { + next if $dir eq '.'; + + ### not a directory after all + ### may be coderef or some such + next unless -d $dir; + + ### make sure to clean up the directories just in case, + ### as we're making assumptions about the length + ### This solves rt.cpan issue #19738 + + ### John M. notes: On VMS cannonpath can not currently handle + ### the $dir values that are in UNIX format. + $dir = File::Spec->canonpath( $dir ) unless ON_VMS; + + ### have to use F::S::Unix on VMS, or things will break + my $file_spec = ON_VMS ? 'File::Spec::Unix' : 'File::Spec'; + + ### XXX in some cases File::Find can actually die! + ### so be safe and wrap it in an eval. + eval { File::Find::find( + { %find_args, + wanted => sub { + + return unless /\.pm$/i; + my $mod = $File::Find::name; + + ### make sure it's in Unix format, as it + ### may be in VMS format on VMS; + $mod = VMS::Filespec::unixify( $mod ) if ON_VMS; + + $mod = substr($mod, length($dir) + 1, -3); + $mod = join '::', $file_spec->splitdir($mod); + + return if $seen{$mod}++; + + my $modobj = $self->module_tree($mod); + + ### seperate return, a list context return with one '' + ### in it, is also true! + return unless $modobj; + + push @rv, $modobj; + }, + }, $dir + ) }; + + ### report the error if file::find died + error(loc("Error finding installed files in '%1': %2", $dir, $@)) if $@; + } + + return \@rv; +} + +1; + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Source.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Source.pm new file mode 100644 index 00000000000..54e9d710cfd --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Source.pm @@ -0,0 +1,1417 @@ +package CPANPLUS::Internals::Source; + +use strict; + +use CPANPLUS::Error; +use CPANPLUS::Module; +use CPANPLUS::Module::Fake; +use CPANPLUS::Module::Author; +use CPANPLUS::Internals::Constants; + +use File::Fetch; +use Archive::Extract; + +use IPC::Cmd qw[can_run]; +use File::Temp qw[tempdir]; +use File::Basename qw[dirname]; +use Params::Check qw[check]; +use Module::Load::Conditional qw[can_load]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +$Params::Check::VERBOSE = 1; + +### list of methods the parent class must implement +{ for my $sub ( qw[_init_trees _finalize_trees + _standard_trees_completed _custom_trees_completed + _add_module_object _add_author_object _save_state + ] + ) { + no strict 'refs'; + *$sub = sub { + my $self = shift; + my $class = ref $self || $self; + + require Carp; + Carp::croak( loc( "Class %1 must implement method '%2'", + $class, $sub ) ); + } + } +} + +{ + my $recurse; # flag to prevent recursive calls to *_tree functions + + ### lazy loading of module tree + sub _module_tree { + my $self = $_[0]; + + unless ($self->_mtree or $recurse++ > 0) { + my $uptodate = $self->_check_trees( @_[1..$#_] ); + $self->_build_trees(uptodate => $uptodate); + } + + $recurse--; + return $self->_mtree; + } + + ### lazy loading of author tree + sub _author_tree { + my $self = $_[0]; + + unless ($self->_atree or $recurse++ > 0) { + my $uptodate = $self->_check_trees( @_[1..$#_] ); + $self->_build_trees(uptodate => $uptodate); + } + + $recurse--; + return $self->_atree; + } + +} + + +=pod + +=head1 NAME + +CPANPLUS::Internals::Source + +=head1 SYNOPSIS + + ### lazy load author/module trees ### + + $cb->_author_tree; + $cb->_module_tree; + +=head1 DESCRIPTION + +CPANPLUS::Internals::Source controls the updating of source files and +the parsing of them into usable module/author trees to be used by +C<CPANPLUS>. + +Functions exist to check if source files are still C<good to use> as +well as update them, and then parse them. + +The flow looks like this: + + $cb->_author_tree || $cb->_module_tree + $cb->_check_trees + $cb->__check_uptodate + $cb->_update_source + $cb->__update_custom_module_sources + $cb->__update_custom_module_source + $cb->_build_trees + ### engine methods + { $cb->_init_trees; + $cb->_standard_trees_completed + $cb->_custom_trees_completed + } + $cb->__create_author_tree + ### engine methods + { $cb->_add_author_object } + $cb->__create_module_tree + $cb->__create_dslip_tree + ### engine methods + { $cb->_add_module_object } + $cb->__create_custom_module_entries + + $cb->_dslip_defs + +=head1 METHODS + +=cut + +=pod + +=head2 $cb->_build_trees( uptodate => BOOL, [use_stored => BOOL, path => $path, verbose => BOOL] ) + +This method rebuilds the author- and module-trees from source. + +It takes the following arguments: + +=over 4 + +=item uptodate + +Indicates whether any on disk caches are still ok to use. + +=item path + +The absolute path to the directory holding the source files. + +=item verbose + +A boolean flag indicating whether or not to be verbose. + +=item use_stored + +A boolean flag indicating whether or not it is ok to use previously +stored trees. Defaults to true. + +=back + +Returns a boolean indicating success. + +=cut + +### (re)build the trees ### +sub _build_trees { + my ($self, %hash) = @_; + my $conf = $self->configure_object; + + my($path,$uptodate,$use_stored,$verbose); + my $tmpl = { + path => { default => $conf->get_conf('base'), store => \$path }, + verbose => { default => $conf->get_conf('verbose'), store => \$verbose }, + uptodate => { required => 1, store => \$uptodate }, + use_stored => { default => 1, store => \$use_stored }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + $self->_init_trees( + path => $path, + uptodate => $uptodate, + verbose => $verbose, + use_stored => $use_stored, + ) or do { + error( loc("Could not initialize trees" ) ); + return; + }; + + ### return if we weren't able to build the trees ### + return unless $self->_mtree && $self->_atree; + + ### did we get everything from a stored state? if not, + ### process them now. + if( not $self->_standard_trees_completed ) { + + ### first, prep the author tree + $self->__create_author_tree( + uptodate => $uptodate, + path => $path, + verbose => $verbose, + ) or return; + + ### and now the module tree + $self->_create_mod_tree( + uptodate => $uptodate, + path => $path, + verbose => $verbose, + ) or return; + } + + ### XXX unpleasant hack. since custom sources uses ->parse_module, we + ### already have a special module object with extra meta data. that + ### doesn't gelwell with the sqlite storage engine. So, we check 'normal' + ### trees from seperate trees, so the engine can treat them differently. + ### Effectively this means that with the SQLite engine, for now, custom + ### sources are continuously reparsed =/ -kane + if( not $self->_custom_trees_completed ) { + + ### update them if the other sources are also deemed out of date + if( $conf->get_conf('enable_custom_sources') ) { + $self->__update_custom_module_sources( verbose => $verbose ) + or error(loc("Could not update custom module sources")); + } + + ### add custom sources here if enabled + if( $conf->get_conf('enable_custom_sources') ) { + $self->__create_custom_module_entries( verbose => $verbose ) + or error(loc("Could not create custom module entries")); + } + } + + ### give the source engine a chance to wrap up creation + $self->_finalize_trees( + path => $path, + uptodate => $uptodate, + verbose => $verbose, + use_stored => $use_stored, + ) or do { + error(loc( "Could not finalize trees" )); + return; + }; + + ### still necessary? can only run one instance now ### + ### will probably stay that way --kane +# my $id = $self->_store_id( $self ); +# +# unless ( $id == $self->_id ) { +# error( loc("IDs do not match: %1 != %2. Storage failed!", $id, $self->_id) ); +# } + + return 1; +} + +=pod + +=head2 $cb->_check_trees( [update_source => BOOL, path => PATH, verbose => BOOL] ) + +Retrieve source files and return a boolean indicating whether or not +the source files are up to date. + +Takes several arguments: + +=over 4 + +=item update_source + +A flag to force re-fetching of the source files, even +if they are still up to date. + +=item path + +The absolute path to the directory holding the source files. + +=item verbose + +A boolean flag indicating whether or not to be verbose. + +=back + +Will get information from the config file by default. + +=cut + +### retrieve source files, and returns a boolean indicating if it's up to date +sub _check_trees { + my ($self, %hash) = @_; + my $conf = $self->configure_object; + + my $update_source; + my $verbose; + my $path; + + my $tmpl = { + path => { default => $conf->get_conf('base'), + store => \$path + }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose + }, + update_source => { default => 0, store => \$update_source }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + ### if the user never wants to update their source without explicitly + ### telling us, shortcircuit here + return 1 if $conf->get_conf('no_update') && !$update_source; + + ### a check to see if our source files are still up to date ### + msg( loc("Checking if source files are up to date"), $verbose ); + + my $uptodate = 1; # default return value + + for my $name (qw[auth dslip mod]) { + for my $file ( $conf->_get_source( $name ) ) { + $self->__check_uptodate( + file => File::Spec->catfile( $path, $file ), + name => $name, + update_source => $update_source, + verbose => $verbose, + ) or $uptodate = 0; + } + } + + ### if we're explicitly asked to update the sources, or if the + ### standard source files are out of date, update the custom sources + ### as well + ### RT #47820: Don't try to update custom sources if they are disabled + ### in the configuration. + $self->__update_custom_module_sources( verbose => $verbose ) + if $conf->get_conf('enable_custom_sources') and ( $update_source or !$uptodate ); + + return $uptodate; +} + +=pod + +=head2 $cb->__check_uptodate( file => $file, name => $name, [update_source => BOOL, verbose => BOOL] ) + +C<__check_uptodate> checks if a given source file is still up-to-date +and if not, or when C<update_source> is true, will re-fetch the source +file. + +Takes the following arguments: + +=over 4 + +=item file + +The source file to check. + +=item name + +The internal shortcut name for the source file (used for config +lookups). + +=item update_source + +Flag to force updating of sourcefiles regardless. + +=item verbose + +Boolean to indicate whether to be verbose or not. + +=back + +Returns a boolean value indicating whether the current files are up +to date or not. + +=cut + +### this method checks whether or not the source files we are using are still up to date +sub __check_uptodate { + my $self = shift; + my %hash = @_; + my $conf = $self->configure_object; + + + my $tmpl = { + file => { required => 1 }, + name => { required => 1 }, + update_source => { default => 0 }, + verbose => { default => $conf->get_conf('verbose') }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + my $flag; + unless ( -e $args->{'file'} && ( + ( stat $args->{'file'} )[9] + + $conf->_get_source('update') ) + > time ) { + $flag = 1; + } + + if ( $flag or $args->{'update_source'} ) { + + if ( $self->_update_source( name => $args->{'name'} ) ) { + return 0; # return 0 so 'uptodate' will be set to 0, meaning no + # use of previously stored hashrefs! + } else { + msg( loc("Unable to update source, attempting to get away with using old source file!"), $args->{verbose} ); + return 1; + } + + } else { + return 1; + } +} + +=pod + +=head2 $cb->_update_source( name => $name, [path => $path, verbose => BOOL] ) + +This method does the actual fetching of source files. + +It takes the following arguments: + +=over 4 + +=item name + +The internal shortcut name for the source file (used for config +lookups). + +=item path + +The full path where to write the files. + +=item verbose + +Boolean to indicate whether to be verbose or not. + +=back + +Returns a boolean to indicate success. + +=cut + +### this sub fetches new source files ### +sub _update_source { + my $self = shift; + my %hash = @_; + my $conf = $self->configure_object; + + my $verbose; + my $tmpl = { + name => { required => 1 }, + path => { default => $conf->get_conf('base') }, + verbose => { default => $conf->get_conf('verbose'), store => \$verbose }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + + my $path = $args->{path}; + { ### this could use a clean up - Kane + ### no worries about the / -> we get it from the _ftp configuration, so + ### it's not platform dependant. -kane + my ($dir, $file) = $conf->_get_mirror( $args->{'name'} ) =~ m|(.+/)(.+)$|sg; + + msg( loc("Updating source file '%1'", $file), $verbose ); + + my $fake = CPANPLUS::Module::Fake->new( + module => $args->{'name'}, + path => $dir, + package => $file, + _id => $self->_id, + ); + + ### can't use $fake->fetch here, since ->parent won't work -- + ### the sources haven't been saved yet + my $rv = $self->_fetch( + module => $fake, + fetchdir => $path, + force => 1, + ); + + + unless ($rv) { + error( loc("Couldn't fetch '%1'", $file) ); + return; + } + + $self->_update_timestamp( file => File::Spec->catfile($path, $file) ); + } + + return 1; +} + +=pod + +=head2 $cb->__create_author_tree([path => $path, uptodate => BOOL, verbose => BOOL]) + +This method opens a source files and parses its contents into a +searchable author-tree or restores a file-cached version of a +previous parse, if the sources are uptodate and the file-cache exists. + +It takes the following arguments: + +=over 4 + +=item uptodate + +A flag indicating whether the file-cache is uptodate or not. + +=item path + +The absolute path to the directory holding the source files. + +=item verbose + +A boolean flag indicating whether or not to be verbose. + +=back + +Will get information from the config file by default. + +Returns a tree on success, false on failure. + +=cut + +sub __create_author_tree { + my $self = shift; + my %hash = @_; + my $conf = $self->configure_object; + + + my $tmpl = { + path => { default => $conf->get_conf('base') }, + verbose => { default => $conf->get_conf('verbose') }, + uptodate => { default => 0 }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + my $file = File::Spec->catfile( + $args->{path}, + $conf->_get_source('auth') + ); + + msg(loc("Rebuilding author tree, this might take a while"), + $args->{verbose}); + + ### extract the file ### + my $ae = Archive::Extract->new( archive => $file ) or return; + my $out = STRIP_GZ_SUFFIX->($file); + + ### make sure to set the PREFER_BIN flag if desired ### + { local $Archive::Extract::PREFER_BIN = $conf->get_conf('prefer_bin'); + $ae->extract( to => $out ) or return; + } + + my $cont = $self->_get_file_contents( file => $out ) or return; + + ### don't need it anymore ### + unlink $out; + + for ( split /\n/, $cont ) { + my($id, $name, $email) = m/^alias \s+ + (\S+) \s+ + "\s* ([^\"\<]+?) \s* <(.+)> \s*" + /x; + + $self->_add_author_object( + author => $name, #authors name + email => $email, #authors email address + cpanid => $id, #authors CPAN ID + ) or error( loc("Could not add author '%1'", $name ) ); + + } + + return $self->_atree; + +} #__create_author_tree + +=pod + +=head2 $cb->_create_mod_tree([path => $path, uptodate => BOOL, verbose => BOOL]) + +This method opens a source files and parses its contents into a +searchable module-tree or restores a file-cached version of a +previous parse, if the sources are uptodate and the file-cache exists. + +It takes the following arguments: + +=over 4 + +=item uptodate + +A flag indicating whether the file-cache is up-to-date or not. + +=item path + +The absolute path to the directory holding the source files. + +=item verbose + +A boolean flag indicating whether or not to be verbose. + +=back + +Will get information from the config file by default. + +Returns a tree on success, false on failure. + +=cut + +### this builds a hash reference with the structure of the cpan module tree ### +sub _create_mod_tree { + my $self = shift; + my %hash = @_; + my $conf = $self->configure_object; + + + my $tmpl = { + path => { default => $conf->get_conf('base') }, + verbose => { default => $conf->get_conf('verbose') }, + uptodate => { default => 0 }, + }; + + my $args = check( $tmpl, \%hash ) or return undef; + my $file = File::Spec->catfile($args->{path}, $conf->_get_source('mod')); + + msg(loc("Rebuilding module tree, this might take a while"), + $args->{verbose}); + + + my $dslip_tree = $self->__create_dslip_tree( %$args ); + + ### extract the file ### + my $ae = Archive::Extract->new( archive => $file ) or return; + my $out = STRIP_GZ_SUFFIX->($file); + + ### make sure to set the PREFER_BIN flag if desired ### + { local $Archive::Extract::PREFER_BIN = $conf->get_conf('prefer_bin'); + $ae->extract( to => $out ) or return; + } + + my $content = $self->_get_file_contents( file => $out ) or return; + my $lines = $content =~ tr/\n/\n/; + + ### don't need it anymore ### + unlink $out; + + my($past_header, $count); + for ( split /\n/, $content ) { + + ### quick hack to read past the header of the file ### + ### this is still rather evil... fix some time - Kane + if( m|^\s*$| ) { + unless( $count ) { + error(loc("Could not determine line count from %1", $file)); + return; + } + $past_header = 1; + } + + ### we're still in the header -- find the amount of lines we expect + unless( $past_header ) { + + ### if the line count doesn't match what we expect, bail out + ### this should address: #45644: detect broken index + $count = $1 if /^Line-Count:\s+(\d+)/; + if( $count ) { + if( $lines < $count ) { + error(loc("Expected to read at least %1 lines, but %2 ". + "contains only %3 lines!", + $count, $file, $lines )); + return; + } + } + ### still in the header, keep moving + next; + } + + ### skip empty lines ### + next unless /\S/; + chomp; + + my @data = split /\s+/; + + ### filter out the author and filename as well ### + ### authors can apparently have digits in their names, + ### and dirs can have dots... blah! + my ($author, $package) = $data[2] =~ + m| (?:[A-Z\d-]/)? + (?:[A-Z\d-]{2}/)? + ([A-Z\d-]+) (?:/[\S]+)?/ + ([^/]+)$ + |xsg; + + ### remove file name from the path + $data[2] =~ s|/[^/]+$||; + + my $aobj = $self->author_tree($author); + unless( $aobj ) { + error( loc( "No such author '%1' -- can't make module object " . + "'%2' that is supposed to belong to this author", + $author, $data[0] ) ); + next; + } + + ### adding the dslip info + ### probably can use some optimization + my $dslip; + for my $item ( qw[ statd stats statl stati statp ] ) { + ### checking if there's an entry in the dslip info before + ### catting it on. appeasing warnings this way + $dslip .= $dslip_tree->{ $data[0] }->{$item} + ? $dslip_tree->{ $data[0] }->{$item} + : ' '; + } + + ### XXX this could be sped up if we used author names, not author + ### objects in creation, and then look them up in the author tree + ### when needed. This will need a fix to all the places that create + ### fake author/module objects as well. + + ### callback to store the individual object + $self->_add_module_object( + module => $data[0], # full module name + version => ($data[1] eq 'undef' # version number + ? '0.0' + : $data[1]), + path => File::Spec::Unix->catfile( + $conf->_get_mirror('base'), + $data[2], + ), # extended path on the cpan mirror, + # like /A/AB/ABIGAIL + comment => $data[3], # comment on the module + author => $aobj, + package => $package, # package name, like + # 'foo-bar-baz-1.03.tar.gz' + description => $dslip_tree->{ $data[0] }->{'description'}, + dslip => $dslip, + mtime => '', + ) or error( loc( "Could not add module '%1'", $data[0] ) ); + + } #for + + return $self->_mtree; + +} #_create_mod_tree + +=pod + +=head2 $cb->__create_dslip_tree([path => $path, uptodate => BOOL, verbose => BOOL]) + +This method opens a source files and parses its contents into a +searchable dslip-tree or restores a file-cached version of a +previous parse, if the sources are uptodate and the file-cache exists. + +It takes the following arguments: + +=over 4 + +=item uptodate + +A flag indicating whether the file-cache is uptodate or not. + +=item path + +The absolute path to the directory holding the source files. + +=item verbose + +A boolean flag indicating whether or not to be verbose. + +=back + +Will get information from the config file by default. + +Returns a tree on success, false on failure. + +=cut + +sub __create_dslip_tree { + my $self = shift; + my %hash = @_; + my $conf = $self->configure_object; + + my $tmpl = { + path => { default => $conf->get_conf('base') }, + verbose => { default => $conf->get_conf('verbose') }, + uptodate => { default => 0 }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + ### get the file name of the source ### + my $file = File::Spec->catfile($args->{path}, $conf->_get_source('dslip')); + + ### extract the file ### + my $ae = Archive::Extract->new( archive => $file ) or return; + my $out = STRIP_GZ_SUFFIX->($file); + + ### make sure to set the PREFER_BIN flag if desired ### + { local $Archive::Extract::PREFER_BIN = $conf->get_conf('prefer_bin'); + $ae->extract( to => $out ) or return; + } + + my $in = $self->_get_file_contents( file => $out ) or return; + + ### don't need it anymore ### + unlink $out; + + + ### get rid of the comments and the code ### + ### need a smarter parser, some people have this in their dslip info: + # [ + # 'Statistics::LTU', + # 'R', + # 'd', + # 'p', + # 'O', + # '?', + # 'Implements Linear Threshold Units', + # ...skipping... + # "\x{c4}dd \x{fc}ml\x{e4}\x{fc}ts t\x{f6} \x{eb}v\x{eb}r\x{ff}th\x{ef}ng!", + # 'BENNIE', + # '11' + # ], + ### also, older versions say: + ### $cols = [....] + ### and newer versions say: + ### $CPANPLUS::Modulelist::cols = [...] + ### split '$cols' and '$data' into 2 variables ### + ### use this regex to make sure dslips with ';' in them don't cause + ### parser errors + my ($ds_one, $ds_two) = ($in =~ m|.+}\s+ + (\$(?:CPAN::Modulelist::)?cols.*?) + (\$(?:CPAN::Modulelist::)?data.*) + |sx); + + ### eval them into existence ### + ### still not too fond of this solution - kane ### + my ($cols, $data); + { #local $@; can't use this, it's buggy -kane + + $cols = eval $ds_one; + error( loc("Error in eval of dslip source files: %1", $@) ) if $@; + + $data = eval $ds_two; + error( loc("Error in eval of dslip source files: %1", $@) ) if $@; + + } + + my $tree = {}; + my $primary = "modid"; + + ### this comes from CPAN::Modulelist + ### which is in 03modlist.data.gz + for (@$data){ + my %hash; + @hash{@$cols} = @$_; + $tree->{$hash{$primary}} = \%hash; + } + + return $tree; + +} #__create_dslip_tree + +=pod + +=head2 $cb->_dslip_defs () + +This function returns the definition structure (ARRAYREF) of the +dslip tree. + +=cut + +### these are the definitions used for dslip info +### they shouldn't change over time.. so hardcoding them doesn't appear to +### be a problem. if it is, we need to parse 03modlist.data better to filter +### all this out. +### right now, this is just used to look up dslip info from a module +sub _dslip_defs { + my $self = shift; + + my $aref = [ + + # D + [ q|Development Stage|, { + i => loc('Idea, listed to gain consensus or as a placeholder'), + c => loc('under construction but pre-alpha (not yet released)'), + a => loc('Alpha testing'), + b => loc('Beta testing'), + R => loc('Released'), + M => loc('Mature (no rigorous definition)'), + S => loc('Standard, supplied with Perl 5'), + }], + + # S + [ q|Support Level|, { + m => loc('Mailing-list'), + d => loc('Developer'), + u => loc('Usenet newsgroup comp.lang.perl.modules'), + n => loc('None known, try comp.lang.perl.modules'), + a => loc('Abandoned; volunteers welcome to take over maintainance'), + }], + + # L + [ q|Language Used|, { + p => loc('Perl-only, no compiler needed, should be platform independent'), + c => loc('C and perl, a C compiler will be needed'), + h => loc('Hybrid, written in perl with optional C code, no compiler needed'), + '+' => loc('C++ and perl, a C++ compiler will be needed'), + o => loc('perl and another language other than C or C++'), + }], + + # I + [ q|Interface Style|, { + f => loc('plain Functions, no references used'), + h => loc('hybrid, object and function interfaces available'), + n => loc('no interface at all (huh?)'), + r => loc('some use of unblessed References or ties'), + O => loc('Object oriented using blessed references and/or inheritance'), + }], + + # P + [ q|Public License|, { + p => loc('Standard-Perl: user may choose between GPL and Artistic'), + g => loc('GPL: GNU General Public License'), + l => loc('LGPL: "GNU Lesser General Public License" (previously known as "GNU Library General Public License")'), + b => loc('BSD: The BSD License'), + a => loc('Artistic license alone'), + o => loc('other (but distribution allowed without restrictions)'), + }], + ]; + + return $aref; +} + +=head2 $file = $cb->_add_custom_module_source( uri => URI, [verbose => BOOL] ); + +Adds a custom source index and updates it based on the provided URI. + +Returns the full path to the index file on success or false on failure. + +=cut + +sub _add_custom_module_source { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my($verbose,$uri); + my $tmpl = { + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + uri => { required => 1, store => \$uri } + }; + + check( $tmpl, \%hash ) or return; + + ### what index file should we use on disk? + my $index = $self->__custom_module_source_index_file( uri => $uri ); + + ### already have it. + if( IS_FILE->( $index ) ) { + msg(loc("Source '%1' already added", $uri)); + return 1; + } + + ### do we need to create the targe dir? + { my $dir = dirname( $index ); + unless( IS_DIR->( $dir ) ) { + $self->_mkdir( dir => $dir ) or return + } + } + + ### write the file + my $fh = OPEN_FILE->( $index => '>' ) or do { + error(loc("Could not open index file for '%1'", $uri)); + return; + }; + + ### basically we 'touched' it. Check the return value, may be + ### important on win32 and similar OS, where there's file length + ### limits + close $fh or do { + error(loc("Could not write index file to disk for '%1'", $uri)); + return; + }; + + $self->__update_custom_module_source( + remote => $uri, + local => $index, + verbose => $verbose, + ) or do { + ### we faild to update it, we probably have an empty + ### possibly silly filename on disk now -- remove it + 1 while unlink $index; + return; + }; + + return $index; +} + +=head2 $index = $cb->__custom_module_source_index_file( uri => $uri ); + +Returns the full path to the encoded index file for C<$uri>, as used by +all C<custom module source> routines. + +=cut + +sub __custom_module_source_index_file { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my($verbose,$uri); + my $tmpl = { + uri => { required => 1, store => \$uri } + }; + + check( $tmpl, \%hash ) or return; + + my $index = File::Spec->catfile( + $conf->get_conf('base'), + $conf->_get_build('custom_sources'), + $self->_uri_encode( uri => $uri ), + ); + + return $index; +} + +=head2 $file = $cb->_remove_custom_module_source( uri => URI, [verbose => BOOL] ); + +Removes a custom index file based on the URI provided. + +Returns the full path to the index file on success or false on failure. + +=cut + +sub _remove_custom_module_source { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my($verbose,$uri); + my $tmpl = { + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + uri => { required => 1, store => \$uri } + }; + + check( $tmpl, \%hash ) or return; + + ### use uri => local, instead of the other way around + my %files = reverse $self->__list_custom_module_sources; + + ### On VMS the case of key to %files can be either exact or lower case + ### XXX abstract this lookup out? --kane + my $file = $files{ $uri }; + $file = $files{ lc $uri } if !defined($file) && ON_VMS; + + unless (defined $file) { + error(loc("No such custom source '%1'", $uri)); + return; + }; + + 1 while unlink $file; + + if( IS_FILE->( $file ) ) { + error(loc("Could not remove index file '%1' for custom source '%2'", + $file, $uri)); + return; + } + + msg(loc("Successfully removed index file for '%1'", $uri), $verbose); + + return $file; +} + +=head2 %files = $cb->__list_custom_module_sources + +This method scans the 'custom-sources' directory in your base directory +for additional sources to include in your module tree. + +Returns a list of key value pairs as follows: + + /full/path/to/source/file%3Fencoded => http://decoded/mirror/path + +=cut + +sub __list_custom_module_sources { + my $self = shift; + my $conf = $self->configure_object; + + my($verbose); + my $tmpl = { + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + }; + + my $dir = File::Spec->catdir( + $conf->get_conf('base'), + $conf->_get_build('custom_sources'), + ); + + unless( IS_DIR->( $dir ) ) { + msg(loc("No '%1' dir, skipping custom sources", $dir), $verbose); + return; + } + + ### unencode the files + ### skip ones starting with # though + my %files = map { + my $org = $_; + my $dec = $self->_uri_decode( uri => $_ ); + File::Spec->catfile( $dir, $org ) => $dec + } grep { $_ !~ /^#/ } READ_DIR->( $dir ); + + return %files; +} + +=head2 $bool = $cb->__update_custom_module_sources( [verbose => BOOL] ); + +Attempts to update all the index files to your custom module sources. + +If the index is missing, and it's a C<file://> uri, it will generate +a new local index for you. + +Return true on success, false on failure. + +=cut + +sub __update_custom_module_sources { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my $verbose; + my $tmpl = { + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose } + }; + + check( $tmpl, \%hash ) or return; + + my %files = $self->__list_custom_module_sources; + + ### uptodate check has been done a few levels up. + my $fail; + while( my($local,$remote) = each %files ) { + + $self->__update_custom_module_source( + remote => $remote, + local => $local, + verbose => $verbose, + ) or ( $fail++, next ); + } + + error(loc("Failed updating one or more remote sources files")) if $fail; + + return if $fail; + return 1; +} + +=head2 $ok = $cb->__update_custom_module_source + +Attempts to update all the index files to your custom module sources. + +If the index is missing, and it's a C<file://> uri, it will generate +a new local index for you. + +Return true on success, false on failure. + +=cut + +sub __update_custom_module_source { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my($verbose,$local,$remote); + my $tmpl = { + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + local => { store => \$local, allow => FILE_EXISTS }, + remote => { required => 1, store => \$remote }, + }; + + check( $tmpl, \%hash ) or return; + + msg( loc("Updating sources from '%1'", $remote), $verbose); + + ### if you didn't provide a local file, we'll look in your custom + ### dir to find the local encoded version for you + $local ||= do { + ### find all files we know of + my %files = reverse $self->__list_custom_module_sources or do { + error(loc("No custom modules sources defined -- need '%1' argument", + 'local')); + return; + }; + + ### On VMS the case of key to %files can be either exact or lower case + ### XXX abstract this lookup out? --kane + my $file = $files{ $remote }; + $file = $files{ lc $remote } if !defined ($file) && ON_VMS; + + ### return the local file we're supposed to use + $file or do { + error(loc("Remote source '%1' unknown -- needs '%2' argument", + $remote, 'local')); + return; + }; + }; + + my $uri = join '/', $remote, $conf->_get_source('custom_index'); + my $ff = File::Fetch->new( uri => $uri ); + + ### tempdir doesn't clean up by default, as opposed to tempfile() + ### so add it explicitly. + my $dir = tempdir( CLEANUP => 1 ); + + my $res = do { local $File::Fetch::WARN = 0; + local $File::Fetch::WARN = 0; + $ff->fetch( to => $dir ); + }; + + ### couldn't get the file + unless( $res ) { + + ### it's not a local scheme, so can't auto index + unless( $ff->scheme eq 'file' ) { + error(loc("Could not update sources from '%1': %2", + $remote, $ff->error )); + return; + + ### it's a local uri, we can index it ourselves + } else { + msg(loc("No index file found at '%1', generating one", + $ff->uri), $verbose ); + + ### ON VMS, if you are working with a UNIX file specification, + ### you need currently use the UNIX variants of the File::Spec. + my $ff_path = do { + my $file_class = 'File::Spec'; + $file_class .= '::Unix' if ON_VMS; + $file_class->catdir( File::Spec::Unix->splitdir( $ff->path ) ); + }; + + $self->__write_custom_module_index( + path => $ff_path, + to => $local, + verbose => $verbose, + ) or return; + + ### XXX don't write that here, __write_custom_module_index + ### already prints this out + #msg(loc("Index file written to '%1'", $to), $verbose); + } + + ### copy it to the real spot and update its timestamp + } else { + $self->_move( file => $res, to => $local ) or return; + $self->_update_timestamp( file => $local ); + + msg(loc("Index file saved to '%1'", $local), $verbose); + } + + return $local; +} + +=head2 $bool = $cb->__write_custom_module_index( path => /path/to/packages, [to => /path/to/index/file, verbose => BOOL] ) + +Scans the C<path> you provided for packages and writes an index with all +the available packages to C<$path/packages.txt>. If you'd like the index +to be written to a different file, provide the C<to> argument. + +Returns true on success and false on failure. + +=cut + +sub __write_custom_module_index { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my ($verbose, $path, $to); + my $tmpl = { + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + path => { required => 1, allow => DIR_EXISTS, store => \$path }, + to => { store => \$to }, + }; + + check( $tmpl, \%hash ) or return; + + ### no explicit to? then we'll use our default + $to ||= File::Spec->catfile( $path, $conf->_get_source('custom_index') ); + + my @files; + require File::Find; + File::Find::find( sub { + ### let's see if A::E can even parse it + my $ae = do { + local $Archive::Extract::WARN = 0; + local $Archive::Extract::WARN = 0; + Archive::Extract->new( archive => $File::Find::name ) + } or return; + + ### it's a type A::E recognize, so we can add it + $ae->type or return; + + ### neither $_ nor $File::Find::name have the chunk of the path in + ### it starting $path -- it's either only the filename, or the full + ### path, so we have to strip it ourselves + ### make sure to remove the leading slash as well. + my $copy = $File::Find::name; + my $re = quotemeta($path); + $copy =~ s|^$re[\\/]?||i; + + push @files, $copy; + + }, $path ); + + ### does the dir exist? if not, create it. + { my $dir = dirname( $to ); + unless( IS_DIR->( $dir ) ) { + $self->_mkdir( dir => $dir ) or return + } + } + + ### create the index file + my $fh = OPEN_FILE->( $to => '>' ) or return; + + print $fh "$_\n" for @files; + close $fh; + + msg(loc("Successfully written index file to '%1'", $to), $verbose); + + return $to; +} + + +=head2 $bool = $cb->__create_custom_module_entries( [verbose => BOOL] ) + +Creates entries in the module tree based upon the files as returned +by C<__list_custom_module_sources>. + +Returns true on success, false on failure. + +=cut + +### use $auth_obj as a persistant version, so we don't have to recreate +### modules all the time +{ my $auth_obj; + + sub __create_custom_module_entries { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my $verbose; + my $tmpl = { + verbose => { default => $conf->get_conf('verbose'), store => \$verbose }, + }; + + check( $tmpl, \%hash ) or return undef; + + my %files = $self->__list_custom_module_sources; + + while( my($file,$name) = each %files ) { + + msg(loc("Adding packages from custom source '%1'", $name), $verbose); + + my $fh = OPEN_FILE->( $file ) or next; + + while( local $_ = <$fh> ) { + chomp; + next if /^#/; + next unless /\S+/; + + ### join on / -- it's a URI after all! + my $parse = join '/', $name, $_; + + ### try to make a module object out of it + my $mod = $self->parse_module( module => $parse ) or ( + error(loc("Could not parse '%1'", $_)), + next + ); + + ### mark this object with a custom author + $auth_obj ||= do { + my $id = CUSTOM_AUTHOR_ID; + + ### if the object is being created for the first time, + ### make sure there's an entry in the author tree as + ### well, so we can search on the CPAN ID + $self->author_tree->{ $id } = + CPANPLUS::Module::Author::Fake->new( cpanid => $id ); + }; + + $mod->author( $auth_obj ); + + ### and now add it to the modlue tree -- this MAY + ### override things of course + if( my $old_mod = $self->module_tree( $mod->module ) ) { + + ### On VMS use the old module name to get the real case + $mod->module( $old_mod->module ) if ON_VMS; + + msg(loc("About to overwrite module tree entry for '%1' with '%2'", + $mod->module, $mod->package), $verbose); + } + + ### mark where it came from + $mod->description( loc("Custom source from '%1'",$name) ); + + ### store it in the module tree + $self->module_tree->{ $mod->module } = $mod; + } + } + + return 1; + } +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Source/Memory.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Source/Memory.pm new file mode 100644 index 00000000000..cb3fd4f1e76 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Source/Memory.pm @@ -0,0 +1,374 @@ +package CPANPLUS::Internals::Source::Memory; + +use base 'CPANPLUS::Internals::Source'; + +use strict; + +use CPANPLUS::Error; +use CPANPLUS::Module; +use CPANPLUS::Module::Fake; +use CPANPLUS::Module::Author; +use CPANPLUS::Internals::Constants; + +use File::Fetch; +use Archive::Extract; + +use IPC::Cmd qw[can_run]; +use File::Temp qw[tempdir]; +use File::Basename qw[dirname]; +use Params::Check qw[allow check]; +use Module::Load::Conditional qw[can_load]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +$Params::Check::VERBOSE = 1; + +=head1 NAME + +CPANPLUS::Internals::Source::Memory - In memory implementation + +=cut + +### flag to show if init_trees got its' data from storable. This allows +### us to not write an existing stored file back to disk +{ my $from_storable; + + sub _init_trees { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my($path,$uptodate,$verbose,$use_stored); + my $tmpl = { + path => { default => $conf->get_conf('base'), store => \$path }, + verbose => { default => $conf->get_conf('verbose'), store => \$verbose }, + uptodate => { required => 1, store => \$uptodate }, + use_stored => { default => 1, store => \$use_stored }, + }; + + check( $tmpl, \%hash ) or return; + + ### retrieve the stored source files ### + my $stored = $self->__memory_retrieve_source( + path => $path, + uptodate => $uptodate && $use_stored, + verbose => $verbose, + ) || {}; + + ### we got this from storable if $stored has keys.. + $from_storable = keys %$stored ? 1 : 0; + + ### set up the trees + $self->_atree( $stored->{_atree} || {} ); + $self->_mtree( $stored->{_mtree} || {} ); + + return 1; + } + + sub _standard_trees_completed { return $from_storable } + sub _custom_trees_completed { return $from_storable } + + sub _finalize_trees { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my($path,$uptodate,$verbose); + my $tmpl = { + path => { default => $conf->get_conf('base'), store => \$path }, + verbose => { default => $conf->get_conf('verbose'), store => \$verbose }, + uptodate => { required => 1, store => \$uptodate }, + }; + + { local $Params::Check::ALLOW_UNKNOWN = 1; + check( $tmpl, \%hash ) or return; + } + + ### write the stored files to disk, so we can keep using them + ### from now on, till they become invalid + ### write them if the original sources weren't uptodate, or + ### we didn't just load storable files + $self->__memory_save_source() if !$uptodate or not $from_storable; + + return 1; + } + + ### saves current memory state + sub _save_state { + my $self = shift; + return $self->_finalize_trees( @_, uptodate => 0 ); + } +} + +sub _add_author_object { + my $self = shift; + my %hash = @_; + + my $class; + my $tmpl = { + class => { default => 'CPANPLUS::Module::Author', store => \$class }, + map { $_ => { required => 1 } } + qw[ author cpanid email ] + }; + + my $href = do { + local $Params::Check::NO_DUPLICATES = 1; + check( $tmpl, \%hash ) or return; + }; + + my $obj = $class->new( %$href, _id => $self->_id ); + + $self->author_tree->{ $href->{'cpanid'} } = $obj or return; + + return $obj; +} + +sub _add_module_object { + my $self = shift; + my %hash = @_; + + my $class; + my $tmpl = { + class => { default => 'CPANPLUS::Module', store => \$class }, + map { $_ => { required => 1 } } + qw[ module version path comment author package description dslip mtime ] + }; + + my $href = do { + local $Params::Check::NO_DUPLICATES = 1; + check( $tmpl, \%hash ) or return; + }; + + my $obj = $class->new( %$href, _id => $self->_id ); + + ### Every module get's stored as a module object ### + $self->module_tree->{ $href->{module} } = $obj or return; + + return $obj; +} + +{ my %map = ( + _source_search_module_tree => [ module_tree => 'CPANPLUS::Module' ], + _source_search_author_tree => [ author_tree => 'CPANPLUS::Module::Author' ], + ); + + while( my($sub, $aref) = each %map ) { + no strict 'refs'; + + my($meth, $class) = @$aref; + + *$sub = sub { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my($authors,$list,$verbose,$type); + my $tmpl = { + data => { default => [], + strict_type=> 1, store => \$authors }, + allow => { required => 1, default => [ ], strict_type => 1, + store => \$list }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + type => { required => 1, allow => [$class->accessors()], + store => \$type }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + my @rv; + for my $obj ( values %{ $self->$meth } ) { + #push @rv, $auth if check( + # { $type => { allow => $list } }, + # { $type => $auth->$type } + # ); + push @rv, $obj if allow( $obj->$type() => $list ); + } + + return @rv; + } + } +} + +=pod + +=head2 $cb->__memory_retrieve_source(name => $name, [path => $path, uptodate => BOOL, verbose => BOOL]) + +This method retrieves a I<storable>d tree identified by C<$name>. + +It takes the following arguments: + +=over 4 + +=item name + +The internal name for the source file to retrieve. + +=item uptodate + +A flag indicating whether the file-cache is up-to-date or not. + +=item path + +The absolute path to the directory holding the source files. + +=item verbose + +A boolean flag indicating whether or not to be verbose. + +=back + +Will get information from the config file by default. + +Returns a tree on success, false on failure. + +=cut + +sub __memory_retrieve_source { + my $self = shift; + my %hash = @_; + my $conf = $self->configure_object; + + my $tmpl = { + path => { default => $conf->get_conf('base') }, + verbose => { default => $conf->get_conf('verbose') }, + uptodate => { default => 0 }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + ### check if we can retrieve a frozen data structure with storable ### + my $storable = can_load( modules => {'Storable' => '0.0'} ) + if $conf->get_conf('storable'); + + return unless $storable; + + ### $stored is the name of the frozen data structure ### + my $stored = $self->__memory_storable_file( $args->{path} ); + + if ($storable && -e $stored && -s _ && $args->{'uptodate'}) { + msg( loc("Retrieving %1", $stored), $args->{'verbose'} ); + + my $href = Storable::retrieve($stored); + return $href; + } else { + return; + } +} + +=pod + +=head2 $cb->__memory_save_source([verbose => BOOL, path => $path]) + +This method saves all the parsed trees in I<storable>d format if +C<Storable> is available. + +It takes the following arguments: + +=over 4 + +=item path + +The absolute path to the directory holding the source files. + +=item verbose + +A boolean flag indicating whether or not to be verbose. + +=back + +Will get information from the config file by default. + +Returns true on success, false on failure. + +=cut + +sub __memory_save_source { + my $self = shift; + my %hash = @_; + my $conf = $self->configure_object; + + + my $tmpl = { + path => { default => $conf->get_conf('base'), allow => DIR_EXISTS }, + verbose => { default => $conf->get_conf('verbose') }, + force => { default => 1 }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + my $aref = [qw[_mtree _atree]]; + + ### check if we can retrieve a frozen data structure with storable ### + my $storable; + $storable = can_load( modules => {'Storable' => '0.0'} ) + if $conf->get_conf('storable'); + return unless $storable; + + my $to_write = {}; + foreach my $key ( @$aref ) { + next unless ref( $self->$key ); + $to_write->{$key} = $self->$key; + } + + return unless keys %$to_write; + + ### $stored is the name of the frozen data structure ### + my $stored = $self->__memory_storable_file( $args->{path} ); + + if (-e $stored && not -w $stored) { + msg( loc("%1 not writable; skipped.", $stored), $args->{'verbose'} ); + return; + } + + msg( loc("Writing compiled source information to disk. This might take a little while."), + $args->{'verbose'} ); + + my $flag; + unless( Storable::nstore( $to_write, $stored ) ) { + error( loc("could not store %1!", $stored) ); + $flag++; + } + + return $flag ? 0 : 1; +} + +sub __memory_storable_file { + my $self = shift; + my $conf = $self->configure_object; + my $path = shift or return; + + ### check if we can retrieve a frozen data structure with storable ### + my $storable = $conf->get_conf('storable') + ? can_load( modules => {'Storable' => '0.0'} ) + : 0; + + return unless $storable; + + ### $stored is the name of the frozen data structure ### + ### changed to use File::Spec->catfile -jmb + my $stored = File::Spec->rel2abs( + File::Spec->catfile( + $path, #base dir + $conf->_get_source('stored') #file + . '.s' . + $Storable::VERSION #the version of storable + . '.c' . + $self->VERSION #the version of CPANPLUS + . STORABLE_EXT #append a suffix + ) + ); + + return $stored; +} + + + + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: + +1; diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Source/SQLite.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Source/SQLite.pm new file mode 100644 index 00000000000..a0ddf499bf6 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Source/SQLite.pm @@ -0,0 +1,326 @@ +package CPANPLUS::Internals::Source::SQLite; + +use strict; +use warnings; + +use base 'CPANPLUS::Internals::Source'; + +use CPANPLUS::Error; +use CPANPLUS::Internals::Constants; +use CPANPLUS::Internals::Source::SQLite::Tie; + +use Data::Dumper; +use DBIx::Simple; +use DBD::SQLite; + +use Params::Check qw[allow check]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +use constant TXN_COMMIT => 1000; + +=head1 NAME + +CPANPLUS::Internals::Source::SQLite - SQLite implementation + +=cut + +{ my $Dbh; + my $DbFile; + + sub __sqlite_file { + return $DbFile if $DbFile; + + my $self = shift; + my $conf = $self->configure_object; + + $DbFile = File::Spec->catdir( + $conf->get_conf('base'), + SOURCE_SQLITE_DB + ); + + return $DbFile; + }; + + sub __sqlite_dbh { + return $Dbh if $Dbh; + + my $self = shift; + $Dbh = DBIx::Simple->connect( + "dbi:SQLite:dbname=" . $self->__sqlite_file, + '', '', + { AutoCommit => 1 } + ); + #$Dbh->dbh->trace(1); + + return $Dbh; + }; +} + +{ my $used_old_copy = 0; + + sub _init_trees { + my $self = shift; + my $conf = $self->configure_object; + my %hash = @_; + + my($path,$uptodate,$verbose,$use_stored); + my $tmpl = { + path => { default => $conf->get_conf('base'), store => \$path }, + verbose => { default => $conf->get_conf('verbose'), store => \$verbose }, + uptodate => { required => 1, store => \$uptodate }, + use_stored => { default => 1, store => \$use_stored }, + }; + + check( $tmpl, \%hash ) or return; + + ### if it's not uptodate, or the file doesn't exist, we need to create + ### a new sqlite db + if( not $uptodate or not -e $self->__sqlite_file ) { + $used_old_copy = 0; + + ### chuck the file + 1 while unlink $self->__sqlite_file; + + ### and create a new one + $self->__sqlite_create_db or do { + error(loc("Could not create new SQLite DB")); + return; + } + } else { + $used_old_copy = 1; + } + + ### set up the author tree + { my %at; + tie %at, 'CPANPLUS::Internals::Source::SQLite::Tie', + dbh => $self->__sqlite_dbh, table => 'author', + key => 'cpanid', cb => $self; + + $self->_atree( \%at ); + } + + ### set up the author tree + { my %mt; + tie %mt, 'CPANPLUS::Internals::Source::SQLite::Tie', + dbh => $self->__sqlite_dbh, table => 'module', + key => 'module', cb => $self; + + $self->_mtree( \%mt ); + } + + ### start a transaction + $self->__sqlite_dbh->query('BEGIN'); + + return 1; + + } + + sub _standard_trees_completed { return $used_old_copy } + sub _custom_trees_completed { return } + ### finish transaction + sub _finalize_trees { $_[0]->__sqlite_dbh->query('COMMIT'); return 1 } + + ### saves current memory state, but not implemented in sqlite + sub _save_state { + error(loc("%1 has not implemented writing state to disk", __PACKAGE__)); + return; + } +} + +{ my $txn_count = 0; + + ### XXX move this outside the sub, so we only compute it once + my $class; + my @keys = qw[ author cpanid email ]; + my $tmpl = { + class => { default => 'CPANPLUS::Module::Author', store => \$class }, + map { $_ => { required => 1 } } @keys + }; + + ### dbix::simple's expansion of (??) is REALLY expensive, so do it manually + my $ph = join ',', map { '?' } @keys; + + + sub _add_author_object { + my $self = shift; + my %hash = @_; + my $dbh = $self->__sqlite_dbh; + + my $href = do { + local $Params::Check::NO_DUPLICATES = 1; + local $Params::Check::SANITY_CHECK_TEMPLATE = 0; + check( $tmpl, \%hash ) or return; + }; + + ### keep counting how many we inserted + unless( ++$txn_count % TXN_COMMIT ) { + #warn "Committing transaction $txn_count"; + $dbh->query('COMMIT') or error( $dbh->error ); # commit previous transaction + $dbh->query('BEGIN') or error( $dbh->error ); # and start a new one + } + + $dbh->query( + "INSERT INTO author (". join(',',keys(%$href)) .") VALUES ($ph)", + values %$href + ) or do { + error( $dbh->error ); + return; + }; + + return 1; + } +} + +{ my $txn_count = 0; + + ### XXX move this outside the sub, so we only compute it once + my $class; + my @keys = qw[ module version path comment author package description dslip mtime ]; + my $tmpl = { + class => { default => 'CPANPLUS::Module', store => \$class }, + map { $_ => { required => 1 } } @keys + }; + + ### dbix::simple's expansion of (??) is REALLY expensive, so do it manually + my $ph = join ',', map { '?' } @keys; + + sub _add_module_object { + my $self = shift; + my %hash = @_; + my $dbh = $self->__sqlite_dbh; + + my $href = do { + local $Params::Check::NO_DUPLICATES = 1; + local $Params::Check::SANITY_CHECK_TEMPLATE = 0; + check( $tmpl, \%hash ) or return; + }; + + ### fix up author to be 'plain' string + $href->{'author'} = $href->{'author'}->cpanid; + + ### keep counting how many we inserted + unless( ++$txn_count % TXN_COMMIT ) { + #warn "Committing transaction $txn_count"; + $dbh->query('COMMIT') or error( $dbh->error ); # commit previous transaction + $dbh->query('BEGIN') or error( $dbh->error ); # and start a new one + } + + $dbh->query( + "INSERT INTO module (". join(',',keys(%$href)) .") VALUES ($ph)", + values %$href + ) or do { + error( $dbh->error ); + return; + }; + + return 1; + } +} + +{ my %map = ( + _source_search_module_tree + => [ module => module => 'CPANPLUS::Module' ], + _source_search_author_tree + => [ author => cpanid => 'CPANPLUS::Module::Author' ], + ); + + while( my($sub, $aref) = each %map ) { + no strict 'refs'; + + my($table, $key, $class) = @$aref; + *$sub = sub { + my $self = shift; + my %hash = @_; + my $dbh = $self->__sqlite_dbh; + + my($list,$type); + my $tmpl = { + allow => { required => 1, default => [ ], strict_type => 1, + store => \$list }, + type => { required => 1, allow => [$class->accessors()], + store => \$type }, + }; + + check( $tmpl, \%hash ) or return; + + + ### we aliased 'module' to 'name', so change that here too + $type = 'module' if $type eq 'name'; + + my $res = $dbh->query( "SELECT * from $table" ); + + my $meth = $table .'_tree'; + my @rv = map { $self->$meth( $_->{$key} ) } + grep { allow( $_->{$type} => $list ) } $res->hashes; + + return @rv; + } + } +} + + + +sub __sqlite_create_db { + my $self = shift; + my $dbh = $self->__sqlite_dbh; + + ### we can ignore the result/error; not all sqlite implemantation + ### support this + $dbh->query( qq[ + DROP TABLE IF EXISTS author; + \n] + ) or do { + msg( $dbh->error ); + }; + $dbh->query( qq[ + DROP TABLE IF EXISTS module; + \n] + ) or do { + msg( $dbh->error ); + }; + + + + $dbh->query( qq[ + /* the author information */ + CREATE TABLE author ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + + author varchar(255), + email varchar(255), + cpanid varchar(255) + ); + \n] + + ) or do { + error( $dbh->error ); + return; + }; + + $dbh->query( qq[ + /* the module information */ + CREATE TABLE module ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + + module varchar(255), + version varchar(255), + path varchar(255), + comment varchar(255), + author varchar(255), + package varchar(255), + description varchar(255), + dslip varchar(255), + mtime varchar(255) + ); + + \n] + + ) or do { + error( $dbh->error ); + return; + }; + + return 1; +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Source/SQLite/Tie.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Source/SQLite/Tie.pm new file mode 100644 index 00000000000..f908c9803e4 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Source/SQLite/Tie.pm @@ -0,0 +1,145 @@ +package CPANPLUS::Internals::Source::SQLite::Tie; + +use strict; +use warnings; + +use CPANPLUS::Error; +use CPANPLUS::Module; +use CPANPLUS::Module::Fake; +use CPANPLUS::Module::Author::Fake; +use CPANPLUS::Internals::Constants; + + +use Params::Check qw[check]; +use Module::Load::Conditional qw[can_load]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + + +use Data::Dumper; +$Data::Dumper::Indent = 1; + +require Tie::Hash; +use vars qw[@ISA]; +push @ISA, 'Tie::StdHash'; + + +sub TIEHASH { + my $class = shift; + my %hash = @_; + + my $tmpl = { + dbh => { required => 1 }, + table => { required => 1 }, + key => { required => 1 }, + cb => { required => 1 }, + offset => { default => 0 }, + }; + + my $args = check( $tmpl, \%hash ) or return; + my $obj = bless { %$args, store => {} } , $class; + + return $obj; +} + +sub FETCH { + my $self = shift; + my $key = shift or return; + my $dbh = $self->{dbh}; + my $cb = $self->{cb}; + my $table = $self->{table}; + + + ### did we look this one up before? + if( my $obj = $self->{store}->{$key} ) { + return $obj; + } + + my $res = $dbh->query( + "SELECT * from $table where $self->{key} = ?", $key + ) or do { + error( $dbh->error ); + return; + }; + + my $href = $res->hash; + + ### get rid of the primary key + delete $href->{'id'}; + + ### no results? + return unless keys %$href; + + ### expand author if needed + ### XXX no longer generic :( + if( $table eq 'module' ) { + $href->{author} = $cb->author_tree( $href->{author } ) or return; + } + + my $class = { + module => 'CPANPLUS::Module', + author => 'CPANPLUS::Module::Author', + }->{ $table }; + + my $obj = $self->{store}->{$key} = $class->new( %$href, _id => $cb->_id ); + + return $obj; +} + +sub STORE { + my $self = shift; + my $key = shift; + my $val = shift; + + $self->{store}->{$key} = $val; +} + +1; + +sub FIRSTKEY { + my $self = shift; + my $dbh = $self->{'dbh'}; + + my $res = $dbh->query( + "select $self->{key} from $self->{table} order by $self->{key} limit 1" + ); + + $self->{offset} = 0; + + my $key = $res->flat->[0]; + + return $key; +} + +sub NEXTKEY { + my $self = shift; + my $dbh = $self->{'dbh'}; + + my $res = $dbh->query( + "select $self->{key} from $self->{table} ". + "order by $self->{key} limit 1 offset $self->{offset}" + ); + + $self->{offset} +=1; + + my $key = $res->flat->[0]; + my $val = $self->FETCH( $key ); + + ### use each() semantics + return wantarray ? ( $key, $val ) : $key; +} + +sub EXISTS { !!$_[0]->FETCH( $_[1] ) } + +sub SCALAR { + my $self = shift; + my $dbh = $self->{'dbh'}; + + my $res = $dbh->query( "select count(*) from $self->{table}" ); + + return $res->flat; +} + +### intentionally left blank +sub DELETE { } +sub CLEAR { } + diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Utils.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Utils.pm new file mode 100644 index 00000000000..27d2abcdad1 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Utils.pm @@ -0,0 +1,657 @@ +package CPANPLUS::Internals::Utils; + +use strict; + +use CPANPLUS::Error; +use CPANPLUS::Internals::Constants; + +use Cwd qw[chdir]; +use File::Copy; +use Params::Check qw[check]; +use Module::Load::Conditional qw[can_load]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +local $Params::Check::VERBOSE = 1; + +=pod + +=head1 NAME + +CPANPLUS::Internals::Utils + +=head1 SYNOPSIS + + my $bool = $cb->_mkdir( dir => 'blah' ); + my $bool = $cb->_chdir( dir => 'blah' ); + my $bool = $cb->_rmdir( dir => 'blah' ); + + my $bool = $cb->_move( from => '/some/file', to => '/other/file' ); + my $bool = $cb->_move( from => '/some/dir', to => '/other/dir' ); + + my $cont = $cb->_get_file_contents( file => '/path/to/file' ); + + + my $version = $cb->_perl_version( perl => $^X ); + +=head1 DESCRIPTION + +C<CPANPLUS::Internals::Utils> holds a few convenience functions for +CPANPLUS libraries. + +=head1 METHODS + +=head2 $cb->_mkdir( dir => '/some/dir' ) + +C<_mkdir> creates a full path to a directory. + +Returns true on success, false on failure. + +=cut + +sub _mkdir { + my $self = shift; + + my %hash = @_; + + my $tmpl = { + dir => { required => 1 }, + }; + + my $args = check( $tmpl, \%hash ) or ( + error(loc( Params::Check->last_error ) ), return + ); + + unless( can_load( modules => { 'File::Path' => 0.0 } ) ) { + error( loc("Could not use File::Path! This module should be core!") ); + return; + } + + eval { File::Path::mkpath($args->{dir}) }; + + if($@) { + chomp($@); + error(loc(qq[Could not create directory '%1': %2], $args->{dir}, $@ )); + return; + } + + return 1; +} + +=pod + +=head2 $cb->_chdir( dir => '/some/dir' ) + +C<_chdir> changes directory to a dir. + +Returns true on success, false on failure. + +=cut + +sub _chdir { + my $self = shift; + my %hash = @_; + + my $tmpl = { + dir => { required => 1, allow => DIR_EXISTS }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + unless( chdir $args->{dir} ) { + error( loc(q[Could not chdir into '%1'], $args->{dir}) ); + return; + } + + return 1; +} + +=pod + +=head2 $cb->_rmdir( dir => '/some/dir' ); + +Removes a directory completely, even if it is non-empty. + +Returns true on success, false on failure. + +=cut + +sub _rmdir { + my $self = shift; + my %hash = @_; + + my $tmpl = { + dir => { required => 1, allow => IS_DIR }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + unless( can_load( modules => { 'File::Path' => 0.0 } ) ) { + error( loc("Could not use File::Path! This module should be core!") ); + return; + } + + eval { File::Path::rmtree($args->{dir}) }; + + if($@) { + chomp($@); + error(loc(qq[Could not delete directory '%1': %2], $args->{dir}, $@ )); + return; + } + + return 1; +} + +=pod + +=head2 $cb->_perl_version ( perl => 'some/perl/binary' ); + +C<_perl_version> returns the version of a certain perl binary. +It does this by actually running a command. + +Returns the perl version on success and false on failure. + +=cut + +sub _perl_version { + my $self = shift; + my %hash = @_; + + my $perl; + my $tmpl = { + perl => { required => 1, store => \$perl }, + }; + + check( $tmpl, \%hash ) or return; + + my $perl_version; + ### special perl, or the one we are running under? + if( $perl eq $^X ) { + ### just load the config + require Config; + $perl_version = $Config::Config{version}; + + } else { + my $cmd = $perl . + ' -MConfig -eprint+Config::config_vars+version'; + ($perl_version) = (`$cmd` =~ /version='(.*)'/); + } + + return $perl_version if defined $perl_version; + return; +} + +=pod + +=head2 $cb->_version_to_number( version => $version ); + +Returns a proper module version, or '0.0' if none was available. + +=cut + +sub _version_to_number { + my $self = shift; + my %hash = @_; + + my $version; + my $tmpl = { + version => { default => '0.0', store => \$version }, + }; + + check( $tmpl, \%hash ) or return; + + return $version if $version =~ /^\.?\d/; + return '0.0'; +} + +=pod + +=head2 $cb->_whoami + +Returns the name of the subroutine you're currently in. + +=cut + +sub _whoami { my $name = (caller 1)[3]; $name =~ s/.+:://; $name } + +=pod + +=head2 _get_file_contents( file => $file ); + +Returns the contents of a file + +=cut + +sub _get_file_contents { + my $self = shift; + my %hash = @_; + + my $file; + my $tmpl = { + file => { required => 1, store => \$file } + }; + + check( $tmpl, \%hash ) or return; + + my $fh = OPEN_FILE->($file) or return; + my $contents = do { local $/; <$fh> }; + + return $contents; +} + +=pod $cb->_move( from => $file|$dir, to => $target ); + +Moves a file or directory to the target. + +Returns true on success, false on failure. + +=cut + +sub _move { + my $self = shift; + my %hash = @_; + + my $from; my $to; + my $tmpl = { + file => { required => 1, allow => [IS_FILE,IS_DIR], + store => \$from }, + to => { required => 1, store => \$to } + }; + + check( $tmpl, \%hash ) or return; + + if( File::Copy::move( $from, $to ) ) { + return 1; + } else { + error(loc("Failed to move '%1' to '%2': %3", $from, $to, $!)); + return; + } +} + +=pod $cb->_copy( from => $file|$dir, to => $target ); + +Moves a file or directory to the target. + +Returns true on success, false on failure. + +=cut + +sub _copy { + my $self = shift; + my %hash = @_; + + my($from,$to); + my $tmpl = { + file =>{ required => 1, allow => [IS_FILE,IS_DIR], + store => \$from }, + to => { required => 1, store => \$to } + }; + + check( $tmpl, \%hash ) or return; + + if( File::Copy::copy( $from, $to ) ) { + return 1; + } else { + error(loc("Failed to copy '%1' to '%2': %3", $from, $to, $!)); + return; + } +} + +=head2 $cb->_mode_plus_w( file => '/path/to/file' ); + +Sets the +w bit for the file. + +Returns true on success, false on failure. + +=cut + +sub _mode_plus_w { + my $self = shift; + my %hash = @_; + + require File::stat; + + my $file; + my $tmpl = { + file => { required => 1, allow => IS_FILE, store => \$file }, + }; + + check( $tmpl, \%hash ) or return; + + ### set the mode to +w for a file and +wx for a dir + my $x = File::stat::stat( $file ); + my $mask = -d $file ? 0100 : 0200; + + if( $x and chmod( $x->mode|$mask, $file ) ) { + return 1; + + } else { + error(loc("Failed to '%1' '%2': '%3'", 'chmod +w', $file, $!)); + return; + } +} + +=head2 $uri = $cb->_host_to_uri( scheme => SCHEME, host => HOST, path => PATH ); + +Turns a CPANPLUS::Config style C<host> entry into an URI string. + +Returns the uri on success, and false on failure + +=cut + +sub _host_to_uri { + my $self = shift; + my %hash = @_; + + my($scheme, $host, $path); + my $tmpl = { + scheme => { required => 1, store => \$scheme }, + host => { default => 'localhost', store => \$host }, + path => { default => '', store => \$path }, + }; + + check( $tmpl, \%hash ) or return; + + ### it's an URI, so unixify the path. + ### VMS has a special method for just that + $path = ON_VMS + ? VMS::Filespec::unixify($path) + : File::Spec::Unix->catdir( File::Spec->splitdir( $path ) ); + + return "$scheme://" . File::Spec::Unix->catdir( $host, $path ); +} + +=head2 $cb->_vcmp( VERSION, VERSION ); + +Normalizes the versions passed and does a '<=>' on them, returning the result. + +=cut + +sub _vcmp { + my $self = shift; + my ($x, $y) = @_; + + s/_//g foreach $x, $y; + + return $x <=> $y; +} + +=head2 $cb->_home_dir + +Returns the user's homedir, or C<cwd> if it could not be found + +=cut + +sub _home_dir { + my @os_home_envs = qw( APPDATA HOME USERPROFILE WINDIR SYS$LOGIN ); + + for my $env ( @os_home_envs ) { + next unless exists $ENV{ $env }; + next unless defined $ENV{ $env } && length $ENV{ $env }; + return $ENV{ $env } if -d $ENV{ $env }; + } + + return cwd(); +} + +=head2 $path = $cb->_safe_path( path => $path ); + +Returns a path that's safe to us on Win32 and VMS. + +Only cleans up the path on Win32 if the path exists. + +On VMS, it encodes dots to _ using C<VMS::Filespec::vmsify> + +=cut + +sub _safe_path { + my $self = shift; + + my %hash = @_; + + my $path; + my $tmpl = { + path => { required => 1, store => \$path }, + }; + + check( $tmpl, \%hash ) or return; + + if( ON_WIN32 ) { + ### only need to fix it up if there's spaces in the path + return $path unless $path =~ /\s+/; + + ### clean up paths if we are on win32 + return Win32::GetShortPathName( $path ) || $path; + + } elsif ( ON_VMS ) { + ### XXX According to John Malmberg, there's an VMS issue: + ### catdir on VMS can not currently deal with directory components + ### with dots in them. + ### Fixing this is a a three step procedure, which will work for + ### VMS in its traditional ODS-2 mode, and it will also work if + ### VMS is in the ODS-5 mode that is being implemented. + ### If the path is already in VMS syntax, assume that we are done. + + ### VMS format is a path with a trailing ']' or ':' + return $path if $path =~ /\:|\]$/; + + ### 1. Make sure that the value to be converted, $path is + ### in UNIX directory syntax by appending a '/' to it. + $path .= '/' unless $path =~ m|/$|; + + ### 2. Use VMS::Filespec::vmsify($path . '/') to convert the dots to + ### underscores if needed. The trailing '/' is needed as so that + ### C<vmsify> knows that it should use directory translation instead of + ### filename translation, as filename translation leaves one dot. + $path = VMS::Filespec::vmsify( $path ); + + ### 3. Use $path = File::Spec->splitdir( VMS::Filespec::vmsify( + ### $path . '/') to remove the directory delimiters. + + ### From John Malmberg: + ### File::Spec->catdir will put the path back together. + ### The '/' trick only works if the string is a directory name + ### with UNIX style directory delimiters or no directory delimiters. + ### It is to force vmsify to treat the input specification as UNIX. + ### + ### There is a VMS::Filespec::unixpath() to do the appending of the '/' + ### to the specification, which will do a VMS::Filespec::vmsify() + ### if needed. + ### However it is not a good idea to call vmsify() on a pathname + ### returned by unixify(), and it is not a good idea to call unixify() + ### on a pathname returned by vmsify(). Because of the nature of the + ### conversion, not all file specifications can make the round trip. + ### + ### I think that directory specifications can safely make the round + ### trip, but not ones containing filenames. + $path = File::Spec->catdir( File::Spec->splitdir( $path ) ) + } + + return $path; +} + + +=head2 ($pkg, $version, $ext) = $cb->_split_package_string( package => PACKAGE_STRING ); + +Splits the name of a CPAN package string up into its package, version +and extension parts. + +For example, C<Foo-Bar-1.2.tar.gz> would return the following parts: + + Package: Foo-Bar + Version: 1.2 + Extension: tar.gz + +=cut + +{ my $del_re = qr/[-_\+]/i; # delimiter between elements + my $pkg_re = qr/[a-z] # any letters followed by + [a-z\d]* # any letters, numbers + (?i:\.pm)? # followed by '.pm'--authors do this :( + (?: # optionally repeating: + $del_re # followed by a delimiter + [a-z] # any letters followed by + [a-z\d]* # any letters, numbers + (?i:\.pm)? # followed by '.pm'--authors do this :( + )* + /xi; + + my $ver_re = qr/[a-z]*\d*?[a-z]* # contains a digit and possibly letters + (?: # however, some start with a . only :( + [-._] # followed by a delimiter + [a-z\d]+ # and more digits and or letters + )*? + /xi; + + my $ext_re = qr/[a-z] # a letter, followed by + [a-z\d]* # letters and or digits, optionally + (?: + \. # followed by a dot and letters + [a-z\d]+ # and or digits (like .tar.bz2) + )? # optionally + /xi; + + my $ver_ext_re = qr/ + ($ver_re+) # version, optional + (?: + \. # a literal . + ($ext_re) # extension, + )? # optional, but requires version + /xi; + + ### composed regex for CPAN packages + my $full_re = qr/ + ^ + ( # the whole thing + ($pkg_re+) # package + (?: + $del_re # delimiter + $ver_ext_re # version + extension + )? + ) + $ + /xi; + + ### composed regex for perl packages + my $perl = PERL_CORE; + my $perl_re = qr/ + ^ + ( # the whole thing + ($perl) # package name for 'perl' + (?: + $ver_ext_re # version + extension + )? + ) + $ + /xi; + + +sub _split_package_string { + my $self = shift; + my %hash = @_; + + my $str; + my $tmpl = { package => { required => 1, store => \$str } }; + check( $tmpl, \%hash ) or return; + + + ### 2 different regexes, one for the 'perl' package, + ### one for ordinary CPAN packages.. try them both, + ### first match wins. + for my $re ( $full_re, $perl_re ) { + + ### try the next if the match fails + $str =~ $re or next; + + my $full = $1 || ''; + my $pkg = $2 || ''; + my $ver = $3 || ''; + my $ext = $4 || ''; + + ### this regex resets the capture markers! + ### strip the trailing delimiter + $pkg =~ s/$del_re$//; + + ### strip the .pm package suffix some authors insist on adding + $pkg =~ s/\.pm$//i; + + return ($pkg, $ver, $ext, $full ); + } + + return; + } +} + +{ my %escapes = map { + chr($_) => sprintf("%%%02X", $_) + } 0 .. 255; + + sub _uri_encode { + my $self = shift; + my %hash = @_; + + my $str; + my $tmpl = { + uri => { store => \$str, required => 1 } + }; + + check( $tmpl, \%hash ) or return; + + ### XXX taken straight from URI::Encode + ### Default unsafe characters. RFC 2732 ^(uric - reserved) + $str =~ s|([^A-Za-z0-9\-_.!~*'()])|$escapes{$1}|g; + + return $str; + } + + + sub _uri_decode { + my $self = shift; + my %hash = @_; + + my $str; + my $tmpl = { + uri => { store => \$str, required => 1 } + }; + + check( $tmpl, \%hash ) or return; + + ### XXX use unencode routine in utils? + $str =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg; + + return $str; + } +} + +sub _update_timestamp { + my $self = shift; + my %hash = @_; + + my $file; + my $tmpl = { + file => { required => 1, store => \$file, allow => FILE_EXISTS } + }; + + check( $tmpl, \%hash ) or return; + + ### `touch` the file, so windoze knows it's new -jmb + ### works on *nix too, good fix -Kane + ### make sure it is writable first, otherwise the `touch` will fail + + my $now = time; + unless( chmod( 0644, $file) && utime ($now, $now, $file) ) { + error( loc("Couldn't touch %1", $file) ); + return; + } + + return 1; +} + + +1; + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Utils/Autoflush.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Utils/Autoflush.pm new file mode 100644 index 00000000000..56566436a14 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Internals/Utils/Autoflush.pm @@ -0,0 +1,5 @@ +package CPANPLUS::Internals::Utils::Autoflush; + +BEGIN { $|++ }; + +1; diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Module.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Module.pm new file mode 100644 index 00000000000..9e4b67e4a38 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Module.pm @@ -0,0 +1,1815 @@ +package CPANPLUS::Module; + +use strict; +use vars qw[@ISA]; + + +use CPANPLUS::Dist; +use CPANPLUS::Error; +use CPANPLUS::Module::Signature; +use CPANPLUS::Module::Checksums; +use CPANPLUS::Internals::Constants; + +use FileHandle; + +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; +use IPC::Cmd qw[can_run run]; +use File::Find qw[find]; +use Params::Check qw[check]; +use File::Basename qw[dirname]; +use Module::Load::Conditional qw[can_load check_install]; + +$Params::Check::VERBOSE = 1; + +@ISA = qw[ CPANPLUS::Module::Signature CPANPLUS::Module::Checksums]; + +=pod + +=head1 NAME + +CPANPLUS::Module + +=head1 SYNOPSIS + + ### get a module object from the CPANPLUS::Backend object + my $mod = $cb->module_tree('Some::Module'); + + ### accessors + $mod->version; + $mod->package; + + ### methods + $mod->fetch; + $mod->extract; + $mod->install; + + +=head1 DESCRIPTION + +C<CPANPLUS::Module> creates objects from the information in the +source files. These can then be used to query and perform actions +on, like fetching or installing. + +These objects should only be created internally. For C<fake> objects, +there's the C<CPANPLUS::Module::Fake> class. To obtain a module object +consult the C<CPANPLUS::Backend> documentation. + +=cut + +my $tmpl = { + module => { default => '', required => 1 }, # full module name + version => { default => '0.0' }, # version number + path => { default => '', required => 1 }, # extended path on the + # cpan mirror, like + # /author/id/K/KA/KANE + comment => { default => ''}, # comment on module + package => { default => '', required => 1 }, # package name, like + # 'bar-baz-1.03.tgz' + description => { default => '' }, # description of the + # module + dslip => { default => EMPTY_DSLIP }, # dslip information + _id => { required => 1 }, # id of the Internals + # parent object + _status => { no_override => 1 }, # stores status object + author => { default => '', required => 1, + allow => IS_AUTHOBJ }, # module author + mtime => { default => '' }, +}; + +### some of these will be resolved by wrapper functions that +### do Clever Things to find the actual value, so don't create +### an autogenerated sub for that just here, take an alternate +### name to allow for a wrapper +{ my %rename = ( + dslip => '_dslip' + ); + + ### autogenerate accessors ### + for my $key ( keys %$tmpl ) { + no strict 'refs'; + + my $sub = $rename{$key} || $key; + + *{__PACKAGE__."::$sub"} = sub { + $_[0]->{$key} = $_[1] if @_ > 1; + return $_[0]->{$key}; + } + } +} + + +=pod + +=head1 CLASS METHODS + +=head2 accessors () + +Returns a list of all accessor methods to the object + +=cut + +### *name is an alias, include it explicitly +sub accessors { return ('name', keys %$tmpl) }; + +=head1 ACCESSORS + +An objects of this class has the following accessors: + +=over 4 + +=item name + +Name of the module. + +=item module + +Name of the module. + +=item version + +Version of the module. Defaults to '0.0' if none was provided. + +=item path + +Extended path on the mirror. + +=item comment + +Any comment about the module -- largely unused. + +=item package + +The name of the package. + +=item description + +Description of the module -- only registered modules have this. + +=item dslip + +The five character dslip string, that represents meta-data of the +module -- again, only registered modules have this. + +=cut + +sub dslip { + my $self = shift; + + ### if this module has relevant dslip info, return it + return $self->_dslip if $self->_dslip ne EMPTY_DSLIP; + + ### if not, look at other modules in the same package, + ### see if *they* have any dslip info + for my $mod ( $self->contains ) { + return $mod->_dslip if $mod->_dslip ne EMPTY_DSLIP; + } + + ### ok, really no dslip info found, return the default + return EMPTY_DSLIP; +} + + +=pod + +=item status + +The C<CPANPLUS::Module::Status> object associated with this object. +(see below). + +=item author + +The C<CPANPLUS::Module::Author> object associated with this object. + +=item parent + +The C<CPANPLUS::Internals> object that spawned this module object. + +=back + +=cut + +### Alias ->name to ->module, for human beings. +*name = *module; + +sub parent { + my $self = shift; + my $obj = CPANPLUS::Internals->_retrieve_id( $self->_id ); + + return $obj; +} + +=head1 STATUS ACCESSORS + +C<CPANPLUS> caches a lot of results from method calls and saves data +it collected along the road for later reuse. + +C<CPANPLUS> uses this internally, but it is also available for the end +user. You can get a status object by calling: + + $modobj->status + +You can then query the object as follows: + +=over 4 + +=item installer_type + +The installer type used for this distribution. Will be one of +'makemaker' or 'build'. This determines whether C<CPANPLUS::Dist::MM> +or C<CPANPLUS::Dist::Build> will be used to build this distribution. + +=item dist_cpan + +The dist object used to do the CPAN-side of the installation. Either +a C<CPANPLUS::Dist::MM> or C<CPANPLUS::Dist::Build> object. + +=item dist + +The custom dist object used to do the operating specific side of the +installation, if you've chosen to use this. For example, if you've +chosen to install using the C<ports> format, this may be a +C<CPANPLUS::Dist::Ports> object. + +Undefined if you didn't specify a separate format to install through. + +=item prereqs | requires + +A hashref of prereqs this distribution was found to have. Will look +something like this: + + { Carp => 0.01, strict => 0 } + +Might be undefined if the distribution didn't have any prerequisites. + +=item configure_requires + +Like prereqs, but these are necessary to be installed before the +build process can even begin. + +=item signature + +Flag indicating, if a signature check was done, whether it was OK or +not. + +=item extract + +The directory this distribution was extracted to. + +=item fetch + +The location this distribution was fetched to. + +=item readme + +The text of this distributions README file. + +=item uninstall + +Flag indicating if an uninstall call was done successfully. + +=item created + +Flag indicating if the C<create> call to your dist object was done +successfully. + +=item installed + +Flag indicating if the C<install> call to your dist object was done +successfully. + +=item checksums + +The location of this distributions CHECKSUMS file. + +=item checksum_ok + +Flag indicating if the checksums check was done successfully. + +=item checksum_value + +The checksum value this distribution is expected to have + +=back + +=head1 METHODS + +=head2 $self = CPANPLUS::Module->new( OPTIONS ) + +This method returns a C<CPANPLUS::Module> object. Normal users +should never call this method directly, but instead use the +C<CPANPLUS::Backend> to obtain module objects. + +This example illustrates a C<new()> call with all required arguments: + + CPANPLUS::Module->new( + module => 'Foo', + path => 'authors/id/A/AA/AAA', + package => 'Foo-1.0.tgz', + author => $author_object, + _id => INTERNALS_OBJECT_ID, + ); + +Every accessor is also a valid option to pass to C<new>. + +Returns a module object on success and false on failure. + +=cut + + +sub new { + my($class, %hash) = @_; + + ### don't check the template for sanity + ### -- we know it's good and saves a lot of performance + local $Params::Check::SANITY_CHECK_TEMPLATE = 0; + + my $object = check( $tmpl, \%hash ) or return; + + bless $object, $class; + + return $object; +} + +### only create status objects when they're actually asked for +sub status { + my $self = shift; + return $self->_status if $self->_status; + + my $acc = Object::Accessor->new; + $acc->mk_accessors( qw[ installer_type dist_cpan dist prereqs + signature extract fetch readme uninstall + created installed prepared checksums files + checksum_ok checksum_value _fetch_from + configure_requires + ] ); + + ### create an alias from 'requires' to 'prereqs', so it's more in + ### line with 'configure_requires'; + $acc->mk_aliases( requires => 'prereqs' ); + + $self->_status( $acc ); + + return $self->_status; +} + + +### flush the cache of this object ### +sub _flush { + my $self = shift; + $self->status->mk_flush; + return 1; +} + +=head2 $mod->package_name( [$package_string] ) + +Returns the name of the package a module is in. For C<Acme::Bleach> +that might be C<Acme-Bleach>. + +=head2 $mod->package_version( [$package_string] ) + +Returns the version of the package a module is in. For a module +in the package C<Acme-Bleach-1.1.tar.gz> this would be C<1.1>. + +=head2 $mod->package_extension( [$package_string] ) + +Returns the suffix added by the compression method of a package a +certain module is in. For a module in C<Acme-Bleach-1.1.tar.gz>, this +would be C<tar.gz>. + +=head2 $mod->package_is_perl_core + +Returns a boolean indicating of the package a particular module is in, +is actually a core perl distribution. + +=head2 $mod->module_is_supplied_with_perl_core( [version => $]] ) + +Returns a boolean indicating whether C<ANY VERSION> of this module +was supplied with the current running perl's core package. + +=head2 $mod->is_bundle + +Returns a boolean indicating if the module you are looking at, is +actually a bundle. Bundles are identified as modules whose name starts +with C<Bundle::>. + +=head2 $mod->is_autobundle; + +Returns a boolean indicating if the module you are looking at, is +actually an autobundle as generated by C<< $cb->autobundle >>. + +=head2 $mod->is_third_party + +Returns a boolean indicating whether the package is a known third-party +module (i.e. it's not provided by the standard Perl distribution and +is not available on the CPAN, but on a third party software provider). +See L<Module::ThirdParty> for more details. + +=head2 $mod->third_party_information + +Returns a reference to a hash with more information about a third-party +module. See the documentation about C<module_information()> in +L<Module::ThirdParty> for more details. + +=cut + +{ ### fetches the test reports for a certain module ### + my %map = ( + name => 0, + version => 1, + extension => 2, + ); + + while ( my($type, $index) = each %map ) { + my $name = 'package_' . $type; + + no strict 'refs'; + *$name = sub { + my $self = shift; + my $val = shift || $self->package; + my @res = $self->parent->_split_package_string( package => $val ); + + ### return the corresponding index from the result + return $res[$index] if @res; + return; + }; + } + + sub package_is_perl_core { + my $self = shift; + my $cb = $self->parent; + + ### check if the package looks like a perl core package + return 1 if $self->package_name eq PERL_CORE; + + ### address #44562: ::Module->package_is_perl_code : problem comparing + ### version strings -- use $cb->_vcmp to avoid warnings when version + ### have _ in them + + my $core = $self->module_is_supplied_with_perl_core; + ### ok, so it's found in the core, BUT it could be dual-lifed + if ($core) { + ### if the package is newer than installed, then it's dual-lifed + return if $cb->_vcmp($self->version, $self->installed_version) > 0; + + ### if the package is newer or equal to the corelist, + ### then it's dual-lifed + return if $cb->_vcmp( $self->version, $core ) >= 0; + + ### otherwise, it's older than corelist, thus unsuitable. + return 1; + } + + ### not in corelist, not a perl core package. + return; + } + + sub module_is_supplied_with_perl_core { + my $self = shift; + my $ver = shift || $]; + + ### allow it to be called as a package function as well like: + ### CPANPLUS::Module::module_is_supplied_with_perl_core('Config') + ### so that we can check the status of modules that aren't released + ### to CPAN, but are part of the core. + my $name = ref $self ? $self->module : $self; + + ### check Module::CoreList to see if it's a core package + require Module::CoreList; + + ### Address #41157: Module::module_is_supplied_with_perl_core() + ### broken for perl 5.10: Module::CoreList's version key for the + ### hash has a different number of trailing zero than $] aka + ### $PERL_VERSION. + my $core = $Module::CoreList::version{ 0+$ver }->{ $name }; + + return $core; + } + + ### make sure Bundle-Foo also gets flagged as bundle + sub is_bundle { + my $self = shift; + + ### cpan'd bundle + return 1 if $self->module =~ /^bundle(?:-|::)/i; + + ### autobundle + return 1 if $self->is_autobundle; + + ### neither + return; + } + + ### full path to a generated autobundle + sub is_autobundle { + my $self = shift; + my $conf = $self->parent->configure_object; + my $prefix = $conf->_get_build('autobundle_prefix'); + + return 1 if $self->module eq $prefix; + return; + } + + sub is_third_party { + my $self = shift; + + return unless can_load( modules => { 'Module::ThirdParty' => 0 } ); + + return Module::ThirdParty::is_3rd_party( $self->name ); + } + + sub third_party_information { + my $self = shift; + + return unless $self->is_third_party; + + return Module::ThirdParty::module_information( $self->name ); + } +} + +=pod + +=head2 $clone = $self->clone + +Clones the current module object for tinkering with. +It will have a clean C<CPANPLUS::Module::Status> object, as well as +a fake C<CPANPLUS::Module::Author> object. + +=cut + +{ ### accessors dont change during run time, so only compute once + my @acc = grep !/status/, __PACKAGE__->accessors(); + + sub clone { + my $self = shift; + + ### clone the object ### + my %data = map { $_ => $self->$_ } @acc; + + my $obj = CPANPLUS::Module::Fake->new( %data ); + + return $obj; + } +} + +=pod + +=head2 $where = $self->fetch + +Fetches the module from a CPAN mirror. +Look at L<CPANPLUS::Internals::Fetch::_fetch()> for details on the +options you can pass. + +=cut + +sub fetch { + my $self = shift; + my $cb = $self->parent; + + ### custom args + my %args = ( module => $self ); + + ### if a custom fetch location got specified before, add that here + $args{fetch_from} = $self->status->_fetch_from + if $self->status->_fetch_from; + + my $where = $cb->_fetch( @_, %args ) or return; + + ### do an md5 check ### + if( !$self->status->_fetch_from and + $cb->configure_object->get_conf('md5') and + $self->package ne CHECKSUMS + ) { + unless( $self->_validate_checksum ) { + error( loc( "Checksum error for '%1' -- will not trust package", + $self->package) ); + return; + } + } + + return $where; +} + +=pod + +=head2 $path = $self->extract + +Extracts the fetched module. +Look at L<CPANPLUS::Internals::Extract::_extract()> for details on +the options you can pass. + +=cut + +sub extract { + my $self = shift; + my $cb = $self->parent; + + unless( $self->status->fetch ) { + error( loc( "You have not fetched '%1' yet -- cannot extract", + $self->module) ); + return; + } + + ### can't extract these, so just use the basedir for the file + if( $self->is_autobundle ) { + + ### this is expected to be set after an extract call + $self->get_installer_type; + + return $self->status->extract( dirname( $self->status->fetch ) ); + } + + return $cb->_extract( @_, module => $self ); +} + +=head2 $type = $self->get_installer_type([prefer_makefile => BOOL]) + +Gets the installer type for this module. This may either be C<build> or +C<makemaker>. If C<Module::Build> is unavailable or no installer type +is available, it will fall back to C<makemaker>. If both are available, +it will pick the one indicated by your config, or by the +C<prefer_makefile> option you can pass to this function. + +Returns the installer type on success, and false on error. + +=cut + +sub get_installer_type { + my $self = shift; + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my ($prefer_makefile,$verbose); + my $tmpl = { + prefer_makefile => { default => $conf->get_conf('prefer_makefile'), + store => \$prefer_makefile, allow => BOOLEANS }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + }; + + check( $tmpl, \%hash ) or return; + + my $type; + + ### autobundles use their own installer, so return that + if( $self->is_autobundle ) { + $type = INSTALLER_AUTOBUNDLE; + + } else { + my $extract = $self->status->extract(); + unless( $extract ) { + error(loc( + "Cannot determine installer type of unextracted module '%1'", + $self->module + )); + return; + } + + ### check if it's a makemaker or a module::build type dist ### + my $found_build = -e BUILD_PL->( $extract ); + my $found_makefile = -e MAKEFILE_PL->( $extract ); + + $type = INSTALLER_BUILD if !$prefer_makefile && $found_build; + $type = INSTALLER_BUILD if $found_build && !$found_makefile; + $type = INSTALLER_MM if $prefer_makefile && $found_makefile; + $type = INSTALLER_MM if $found_makefile && !$found_build; + } + + ### ok, so it's a 'build' installer, but you don't /have/ module build + ### XXX duplicated from CPANPLUS::Selfupdate. fix somehow? + if( $type and $type eq INSTALLER_BUILD and ( + not CPANPLUS::Dist->has_dist_type( INSTALLER_BUILD ) + or not $cb->module_tree( INSTALLER_BUILD ) + ->is_uptodate( version => '0.24' ) + ) ) { + + ### XXX this is for recording purposes only. We *have* to install + ### these before even creating a dist object, or we'll get an error + ### saying 'no such dist type'; + ### XXX duplicated from CPANPLUS::Selfupdate. fix somehow? + my $href = $self->status->configure_requires || {}; + my $deps = { INSTALLER_BUILD, '0.24', %$href }; + + $self->status->configure_requires( $deps ); + + msg(loc("This module requires '%1' and '%2' to be installed first. ". + "Adding these modules to your prerequisites list", + 'Module::Build', INSTALLER_BUILD + ), $verbose ); + + + ### ok, actually we found neither ### + } elsif ( !$type ) { + error( loc( "Unable to find '%1' or '%2' for '%3'; ". + "Will default to '%4' but might be unable ". + "to install!", BUILD_PL->(), MAKEFILE_PL->(), + $self->module, INSTALLER_MM ) ); + $type = INSTALLER_MM; + } + + return $self->status->installer_type( $type ) if $type; + return; +} + +=pod + +=head2 $dist = $self->dist([target => 'prepare|create', format => DISTRIBUTION_TYPE, args => {key => val}]); + +Create a distribution object, ready to be installed. +Distribution type defaults to your config settings + +The optional C<args> hashref is passed on to the specific distribution +types' C<create> method after being dereferenced. + +Returns a distribution object on success, false on failure. + +See C<CPANPLUS::Dist> for details. + +=cut + +sub dist { + my $self = shift; + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + ### have you determined your installer type yet? if not, do it here, + ### we need the info + $self->get_installer_type unless $self->status->installer_type; + + my($type,$args,$target); + my $tmpl = { + format => { default => $conf->get_conf('dist_type') || + $self->status->installer_type, + store => \$type }, + target => { default => TARGET_CREATE, store => \$target }, + args => { default => {}, store => \$args }, + }; + + check( $tmpl, \%hash ) or return; + + ### ok, check for $type. Do we have it? + unless( CPANPLUS::Dist->has_dist_type( $type ) ) { + + ### ok, we don't have it. Is it C::D::Build? if so we can install the + ### whole thing now + ### XXX we _could_ do this for any type we dont have actually... + if( $type eq INSTALLER_BUILD ) { + msg(loc("Bootstrapping installer '%1'", $type)); + + ### don't propagate the format, it's the one we're trying to + ### bootstrap, so it'll be an infinite loop if we do + + $cb->module_tree( $type )->install( target => $target, %$args ) or + do { + error(loc("Could not bootstrap installer '%1' -- ". + "can not continue", $type)); + return; + }; + + ### re-scan for available modules now + CPANPLUS::Dist->rescan_dist_types; + + unless( CPANPLUS::Dist->has_dist_type( $type ) ) { + error(loc("Newly installed installer type '%1' should be ". + "available, but is not! -- aborting", $type)); + return; + } else { + msg(loc("Installer '%1' succesfully bootstrapped", $type)); + } + + ### some other plugin you dont have. Abort + } else { + error(loc("Installer type '%1' not found. Please verify your ". + "installation -- aborting", $type )); + return; + } + } + + ### make sure we don't overwrite it, just in case we came + ### back from a ->save_state. This allows restoration to + ### work correctly + my( $dist, $dist_cpan ); + + unless( $dist = $self->status->dist ) { + $dist = $type->new( module => $self ) or return; + $self->status->dist( $dist ); + } + + unless( $dist_cpan = $self->status->dist_cpan ) { + + $dist_cpan = $type eq $self->status->installer_type + ? $self->status->dist + : $self->status->installer_type->new( module => $self ); + + + $self->status->dist_cpan( $dist_cpan ); + } + + + DIST: { + ### just wanted the $dist object? + last DIST if $target eq TARGET_INIT; + + ### first prepare the dist + $dist->prepare( %$args ) or return; + $self->status->prepared(1); + + ### you just wanted us to prepare? + last DIST if $target eq TARGET_PREPARE; + + $dist->create( %$args ) or return; + $self->status->created(1); + } + + return $dist; +} + +=pod + +=head2 $bool = $mod->prepare( ) + +Convenience method around C<install()> that prepares a module +without actually building it. This is equivalent to invoking C<install> +with C<target> set to C<prepare> + +Returns true on success, false on failure. + +=cut + +sub prepare { + my $self = shift; + return $self->install( @_, target => TARGET_PREPARE ); +} + +=head2 $bool = $mod->create( ) + +Convenience method around C<install()> that creates a module. +This is equivalent to invoking C<install> with C<target> set to +C<create> + +Returns true on success, false on failure. + +=cut + +sub create { + my $self = shift; + return $self->install( @_, target => TARGET_CREATE ); +} + +=head2 $bool = $mod->test( ) + +Convenience wrapper around C<install()> that tests a module, without +installing it. +It's the equivalent to invoking C<install()> with C<target> set to +C<create> and C<skiptest> set to C<0>. + +Returns true on success, false on failure. + +=cut + +sub test { + my $self = shift; + return $self->install( @_, target => TARGET_CREATE, skiptest => 0 ); +} + +=pod + +=head2 $bool = $self->install([ target => 'init|prepare|create|install', format => FORMAT_TYPE, extractdir => DIRECTORY, fetchdir => DIRECTORY, prefer_bin => BOOL, force => BOOL, verbose => BOOL, ..... ]); + +Installs the current module. This includes fetching it and extracting +it, if this hasn't been done yet, as well as creating a distribution +object for it. + +This means you can pass it more arguments than described above, which +will be passed on to the relevant methods as they are called. + +See C<CPANPLUS::Internals::Fetch>, C<CPANPLUS::Internals::Extract> and +C<CPANPLUS::Dist> for details. + +Returns true on success, false on failure. + +=cut + +sub install { + my $self = shift; + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my $args; my $target; my $format; + { ### so we can use the rest of the args to the create calls etc ### + local $Params::Check::NO_DUPLICATES = 1; + local $Params::Check::ALLOW_UNKNOWN = 1; + + ### targets 'dist' and 'test' are now completely ignored ### + my $tmpl = { + ### match this allow list with Dist->_resolve_prereqs + target => { default => TARGET_INSTALL, store => \$target, + allow => [TARGET_PREPARE, TARGET_CREATE, + TARGET_INSTALL, TARGET_INIT ] }, + force => { default => $conf->get_conf('force'), }, + verbose => { default => $conf->get_conf('verbose'), }, + format => { default => $conf->get_conf('dist_type'), + store => \$format }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + + ### if this target isn't 'install', we will need to at least 'create' + ### every prereq, so it can build + ### XXX prereq_target of 'prepare' will do weird things here, and is + ### not supported. + $args->{'prereq_target'} ||= TARGET_CREATE if $target ne TARGET_INSTALL; + + ### check if it's already upto date ### + if( $target eq TARGET_INSTALL and !$args->{'force'} and + !$self->package_is_perl_core() and # separate rules apply + ( $self->status->installed() or $self->is_uptodate ) and + !INSTALL_VIA_PACKAGE_MANAGER->($format) + ) { + msg(loc("Module '%1' already up to date, won't install without force", + $self->module), $args->{'verbose'} ); + return $self->status->installed(1); + } + + # if it's a non-installable core package, abort the install. + if( $self->package_is_perl_core() ) { + # if the installed is newer, say so. + if( $self->installed_version > $self->version ) { + error(loc("The core Perl %1 module '%2' (%3) is more ". + "recent than the latest release on CPAN (%4). ". + "Aborting install.", + $], $self->module, $self->installed_version, + $self->version ) ); + # if the installed matches, say so. + } elsif( $self->installed_version == $self->version ) { + error(loc("The core Perl %1 module '%2' (%3) can only ". + "be installed by Perl itself. ". + "Aborting install.", + $], $self->module, $self->installed_version ) ); + # otherwise, the installed is older; say so. + } else { + error(loc("The core Perl %1 module '%2' can only be ". + "upgraded from %3 to %4 by Perl itself (%5). ". + "Aborting install.", + $], $self->module, $self->installed_version, + $self->version, $self->package ) ); + } + return; + + ### it might be a known 3rd party module + } elsif ( $self->is_third_party ) { + my $info = $self->third_party_information; + error(loc( + "%1 is a known third-party module.\n\n". + "As it isn't available on the CPAN, CPANPLUS can't install " . + "it automatically. Therefore you need to install it manually " . + "before proceeding.\n\n". + "%2 is part of %3, published by %4, and should be available ". + "for download at the following address:\n\t%5", + $self->name, $self->name, $info->{name}, $info->{author}, + $info->{url} + )); + + return; + } + + ### fetch it if need be ### + unless( $self->status->fetch ) { + my $params; + for (qw[prefer_bin fetchdir]) { + $params->{$_} = $args->{$_} if exists $args->{$_}; + } + for (qw[force verbose]) { + $params->{$_} = $args->{$_} if defined $args->{$_}; + } + $self->fetch( %$params ) or return; + } + + ### extract it if need be ### + unless( $self->status->extract ) { + my $params; + for (qw[prefer_bin extractdir]) { + $params->{$_} = $args->{$_} if exists $args->{$_}; + } + for (qw[force verbose]) { + $params->{$_} = $args->{$_} if defined $args->{$_}; + } + $self->extract( %$params ) or return; + } + + $format ||= $self->status->installer_type; + + unless( $format ) { + error( loc( "Don't know what installer to use; " . + "Couldn't find either '%1' or '%2' in the extraction " . + "directory '%3' -- will be unable to install", + BUILD_PL->(), MAKEFILE_PL->(), $self->status->extract ) ); + + $self->status->installed(0); + return; + } + + + ### do SIGNATURE checks? ### + ### XXX check status and not recheck EVERY time? + if( $conf->get_conf('signature') ) { + unless( $self->check_signature( verbose => $args->{verbose} ) ) { + error( loc( "Signature check failed for module '%1' ". + "-- Not trusting this module, aborting install", + $self->module ) ); + $self->status->signature(0); + + ### send out test report on broken sig + if( $conf->get_conf('cpantest') ) { + $cb->_send_report( + module => $self, + failed => 1, + buffer => CPANPLUS::Error->stack_as_string, + verbose => $args->{verbose}, + force => $args->{force}, + ) or error(loc("Failed to send test report for '%1'", + $self->module ) ); + } + + return; + + } else { + ### signature OK ### + $self->status->signature(1); + } + } + + ### a target of 'create' basically means not to run make test ### + ### eh, no it /doesn't/.. skiptest => 1 means skiptest => 1. + #$args->{'skiptest'} = 1 if $target eq 'create'; + + ### bundle rules apply ### + if( $self->is_bundle ) { + ### check what we need to install ### + my @prereqs = $self->bundle_modules(); + unless( @prereqs ) { + error( loc( "Bundle '%1' does not specify any modules to install", + $self->module ) ); + + ### XXX mark an error here? ### + } + } + + my $dist = $self->dist( format => $format, + target => $target, + args => $args ); + unless( $dist ) { + error( loc( "Unable to create a new distribution object for '%1' " . + "-- cannot continue", $self->module ) ); + return; + } + + return 1 if $target ne TARGET_INSTALL; + + my $ok = $dist->install( %$args ) ? 1 : 0; + + $self->status->installed($ok); + + return 1 if $ok; + return; +} + +=pod @list = $self->bundle_modules() + +Returns a list of module objects the Bundle specifies. + +This requires you to have extracted the bundle already, using the +C<extract()> method. + +Returns false on error. + +=cut + +sub bundle_modules { + my $self = shift; + my $cb = $self->parent; + + unless( $self->is_bundle ) { + error( loc("'%1' is not a bundle", $self->module ) ); + return; + } + + my @files; + + ### autobundles are special files generated by CPANPLUS. If we can + ### read the file, we can determine the prereqs + if( $self->is_autobundle ) { + my $where; + unless( $where = $self->status->fetch ) { + error(loc("Don't know where '%1' was fetched to", $self->package)); + return; + } + + push @files, $where + + ### regular bundle::* upload + } else { + my $dir; + unless( $dir = $self->status->extract ) { + error(loc("Don't know where '%1' was extracted to", $self->module)); + return; + } + + find( { + wanted => sub { push @files, File::Spec->rel2abs($_) if /\.pm/i }, + no_chdir => 1, + }, $dir ); + } + + my $prereqs = {}; my @list; my $seen = {}; + for my $file ( @files ) { + my $fh = FileHandle->new($file) + or( error(loc("Could not open '%1' for reading: %2", + $file,$!)), next ); + + my $flag; + while( local $_ = <$fh> ) { + ### quick hack to read past the header of the file ### + last if $flag && m|^=head|i; + + ### from perldoc cpan: + ### =head1 CONTENTS + ### In this pod section each line obeys the format + ### Module_Name [Version_String] [- optional text] + $flag = 1 if m|^=head1 CONTENTS|i; + + if ($flag && /^(?!=)(\S+)\s*(\S+)?/) { + my $module = $1; + my $version = $cb->_version_to_number( version => $2 ); + + my $obj = $cb->module_tree($module); + + unless( $obj ) { + error(loc("Cannot find bundled module '%1'", $module), + loc("-- it does not seem to exist") ); + next; + } + + ### make sure we list no duplicates ### + unless( $seen->{ $obj->module }++ ) { + push @list, $obj; + $prereqs->{ $module } = + $cb->_version_to_number( version => $version ); + } + } + } + } + + ### store the prereqs we just found ### + $self->status->prereqs( $prereqs ); + + return @list; +} + +=pod + +=head2 $text = $self->readme + +Fetches the readme belonging to this module and stores it under +C<< $obj->status->readme >>. Returns the readme as a string on +success and returns false on failure. + +=cut + +sub readme { + my $self = shift; + my $conf = $self->parent->configure_object; + + ### did we already dl the readme once? ### + return $self->status->readme() if $self->status->readme(); + + ### this should be core ### + return unless can_load( modules => { FileHandle => '0.0' }, + verbose => 1, + ); + + ### get a clone of the current object, with a fresh status ### + my $obj = $self->clone or return; + + ### munge the package name + my $pkg = README->( $obj ); + $obj->package($pkg); + + my $file; + { ### disable checksum fetches on readme downloads + + my $tmp = $conf->get_conf( 'md5' ); + $conf->set_conf( md5 => 0 ); + + $file = $obj->fetch; + + $conf->set_conf( md5 => $tmp ); + + return unless $file; + } + + ### read the file into a scalar, to store in the original object ### + my $fh = new FileHandle; + unless( $fh->open($file) ) { + error( loc( "Could not open file '%1': %2", $file, $! ) ); + return; + } + + my $in = do{ local $/; <$fh> }; + $fh->close; + + return $self->status->readme( $in ); +} + +=pod + +=head2 $version = $self->installed_version() + +Returns the currently installed version of this module, if any. + +=head2 $where = $self->installed_file() + +Returns the location of the currently installed file of this module, +if any. + +=head2 $dir = $self->installed_dir() + +Returns the directory (or more accurately, the C<@INC> handle) from +which this module was loaded, if any. + +=head2 $bool = $self->is_uptodate([version => VERSION_NUMBER]) + +Returns a boolean indicating if this module is uptodate or not. + +=cut + +### uptodate/installed functions +{ my $map = { # hashkey, alternate rv + installed_version => ['version', 0 ], + installed_file => ['file', ''], + installed_dir => ['dir', ''], + is_uptodate => ['uptodate', 0 ], + }; + + while( my($method, $aref) = each %$map ) { + my($key,$alt_rv) = @$aref; + + no strict 'refs'; + *$method = sub { + ### never use the @INC hooks to find installed versions of + ### modules -- they're just there in case they're not on the + ### perl install, but the user shouldn't trust them for *other* + ### modules! + ### XXX CPANPLUS::inc is now obsolete, so this should not + ### be needed anymore + #local @INC = CPANPLUS::inc->original_inc; + + my $self = shift; + + ### make sure check_install is not looking in %INC, as + ### that may contain some of our sneakily loaded modules + ### that aren't installed as such. -- kane + local $Module::Load::Conditional::CHECK_INC_HASH = 0; + ### this should all that is required for deprecated core modules + local $Module::Load::Conditional::DEPRECATED = 1; + my $href = check_install( + module => $self->module, + version => $self->version, + @_, + ); + + return $href->{$key} || $alt_rv; + } + } +} + + + +=pod + +=head2 $href = $self->details() + +Returns a hashref with key/value pairs offering more information about +a particular module. For example, for C<Time::HiRes> it might look like +this: + + Author Jarkko Hietaniemi (jhi@iki.fi) + Description High resolution time, sleep, and alarm + Development Stage Released + Installed File /usr/local/perl/lib/Time/Hires.pm + Interface Style plain Functions, no references used + Language Used C and perl, a C compiler will be needed + Package Time-HiRes-1.65.tar.gz + Public License Unknown + Support Level Developer + Version Installed 1.52 + Version on CPAN 1.65 + +=cut + +sub details { + my $self = shift; + my $conf = $self->parent->configure_object(); + my $cb = $self->parent; + my %hash = @_; + + my $res = { + Author => loc("%1 (%2)", $self->author->author(), + $self->author->email() ), + Package => $self->package, + Description => $self->description || loc('None given'), + 'Version on CPAN' => $self->version, + }; + + ### check if we have the module installed + ### if so, add version have and version on cpan + $res->{'Version Installed'} = $self->installed_version + if $self->installed_version; + $res->{'Installed File'} = $self->installed_file if $self->installed_file; + + my $i = 0; + for my $item( split '', $self->dslip ) { + $res->{ $cb->_dslip_defs->[$i]->[0] } = + $cb->_dslip_defs->[$i]->[1]->{$item} || loc('Unknown'); + $i++; + } + + return $res; +} + +=head2 @list = $self->contains() + +Returns a list of module objects that represent the modules also +present in the package of this module. + +For example, for C<Archive::Tar> this might return: + + Archive::Tar + Archive::Tar::Constant + Archive::Tar::File + +=cut + +sub contains { + my $self = shift; + my $cb = $self->parent; + my $pkg = $self->package; + + my @mods = $cb->search( type => 'package', allow => [qr/^$pkg$/] ); + + return @mods; +} + +=pod + +=head2 @list_of_hrefs = $self->fetch_report() + +This function queries the CPAN testers database at +I<http://testers.cpan.org/> for test results of specified module +objects, module names or distributions. + +Look at L<CPANPLUS::Internals::Report::_query_report()> for details on +the options you can pass and the return value to expect. + +=cut + +sub fetch_report { + my $self = shift; + my $cb = $self->parent; + + return $cb->_query_report( @_, module => $self ); +} + +=pod + +=head2 $bool = $self->uninstall([type => [all|man|prog]) + +This function uninstalls the specified module object. + +You can install 2 types of files, either C<man> pages or C<prog>ram +files. Alternately you can specify C<all> to uninstall both (which +is the default). + +Returns true on success and false on failure. + +Do note that this does an uninstall via the so-called C<.packlist>, +so if you used a module installer like say, C<ports> or C<apt>, you +should not use this, but use your package manager instead. + +=cut + +sub uninstall { + my $self = shift; + my $conf = $self->parent->configure_object(); + my %hash = @_; + + my ($type,$verbose); + my $tmpl = { + type => { default => 'all', allow => [qw|man prog all|], + store => \$type }, + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + force => { default => $conf->get_conf('force') }, + }; + + ### XXX add a warning here if your default install dist isn't + ### makefile or build -- that means you are using a package manager + ### and this will not do what you think! + + my $args = check( $tmpl, \%hash ) or return; + + if( $conf->get_conf('dist_type') and ( + ($conf->get_conf('dist_type') ne INSTALLER_BUILD) or + ($conf->get_conf('dist_type') ne INSTALLER_MM)) + ) { + msg(loc("You have a default installer type set (%1) ". + "-- you should probably use that package manager to " . + "uninstall modules", $conf->get_conf('dist_type')), $verbose); + } + + ### check if we even have the module installed -- no point in continuing + ### otherwise + unless( $self->installed_version ) { + error( loc( "Module '%1' is not installed, so cannot uninstall", + $self->module ) ); + return; + } + + ### nothing to uninstall ### + my $files = $self->files( type => $type ) or return; + my $dirs = $self->directory_tree( type => $type ) or return; + my $sudo = $conf->get_program('sudo'); + + ### just in case there's no file; M::B doensn't provide .packlists yet ### + my $pack = $self->packlist; + $pack = $pack->[0]->packlist_file() if $pack; + + ### first remove the files, then the dirs if they are empty ### + my $flag = 0; + for my $file( @$files, $pack ) { + next unless defined $file && -f $file; + + msg(loc("Unlinking '%1'", $file), $verbose); + + my @cmd = ($^X, "-eunlink+q[$file]"); + unshift @cmd, $sudo if $sudo; + + my $buffer; + unless ( run( command => \@cmd, + verbose => $verbose, + buffer => \$buffer ) + ) { + error(loc("Failed to unlink '%1': '%2'",$file, $buffer)); + $flag++; + } + } + + for my $dir ( sort @$dirs ) { + local *DIR; + opendir DIR, $dir or next; + my @count = readdir(DIR); + close DIR; + + next unless @count == 2; # . and .. + + msg(loc("Removing '%1'", $dir), $verbose); + + ### this fails on my win2k machines.. it indeed leaves the + ### dir, but it's not a critical error, since the files have + ### been removed. --kane + #unless( rmdir $dir ) { + # error( loc( "Could not remove '%1': %2", $dir, $! ) ) + # unless $^O eq 'MSWin32'; + #} + + my @cmd = ($^X, "-e", "rmdir q[$dir]"); + unshift @cmd, $sudo if $sudo; + + my $buffer; + unless ( run( command => \@cmd, + verbose => $verbose, + buffer => \$buffer ) + ) { + error(loc("Failed to rmdir '%1': %2",$dir,$buffer)); + $flag++; + } + } + + $self->status->uninstall(!$flag); + $self->status->installed( $flag ? 1 : undef); + + return !$flag; +} + +=pod + +=head2 @modobj = $self->distributions() + +Returns a list of module objects representing all releases for this +module on success, false on failure. + +=cut + +sub distributions { + my $self = shift; + my %hash = @_; + + my @list = $self->author->distributions( %hash, module => $self ) or return; + + ### it's another release then by the same author ### + return grep { $_->package_name eq $self->package_name } @list; +} + +=pod + +=head2 @list = $self->files () + +Returns a list of files used by this module, if it is installed. + +=head2 @list = $self->directory_tree () + +Returns a list of directories used by this module. + +=head2 @list = $self->packlist () + +Returns the C<ExtUtils::Packlist> object for this module. + +=head2 @list = $self->validate () + +Returns a list of files that are missing for this modules, but +are present in the .packlist file. + +=cut + +for my $sub (qw[files directory_tree packlist validate]) { + no strict 'refs'; + *$sub = sub { + return shift->_extutils_installed( @_, method => $sub ); + } +} + +### generic method to call an ExtUtils::Installed method ### +sub _extutils_installed { + my $self = shift; + my $cb = $self->parent; + my $conf = $cb->configure_object; + my $home = $cb->_home_dir; # may be needed to fix up prefixes + my %hash = @_; + + my ($verbose,$type,$method); + my $tmpl = { + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose, }, + type => { default => 'all', + allow => [qw|prog man all|], + store => \$type, }, + method => { required => 1, + store => \$method, + allow => [qw|files directory_tree packlist + validate|], + }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + ### old versions of cygwin + perl < 5.8 are buggy here. bail out if we + ### find we're being used by them + { my $err = ON_OLD_CYGWIN; + if($err) { error($err); return }; + } + + return unless can_load( + modules => { 'ExtUtils::Installed' => '0.0' }, + verbose => $verbose, + ); + + my @config_names = ( + ### lib + { lib => 'privlib', # perl-only + arch => 'archlib', # compiled code + prefix => 'prefix', # prefix to both + }, + ### site + { lib => 'sitelib', + arch => 'sitearch', + prefix => 'siteprefix', + }, + ### vendor + { lib => 'vendorlib', + arch => 'vendorarch', + prefix => 'vendorprefix', + }, + ); + + ### search in your regular @INC, and anything you added to your config. + ### this lets EU::Installed find .packlists that are *not* in the standard + ### compiled in @INC path. Requires EU::I 1.42 or up. this addresses #33438 + ### make sure the archname path is also added, as that's where the .packlist + ### files are written + my @libs; + for my $lib ( @{ $conf->get_conf('lib') } ) { + require Config; + + ### and just the standard dir + push @libs, $lib; + + ### figure out what an MM prefix expands to. Basically, it's the + ### site install target from %Config, ie: /opt/lib/perl5/site_perl/5.8.8 + ### minus the site wide prefix, ie: /opt + ### this lets users add the dir they have set as their EU::MM PREFIX + ### to our 'lib' config and it Just Works + ### the arch specific dir, ie: + ### /opt/lib/perl5/site_perl/5.8.8/darwin-2level + ### XXX is this the right thing to do? + + ### we add all 6 dir combos for prefixes: + ### /foo/lib + ### /foo/lib/arch + ### /foo/site/lib + ### /foo/site/lib/arch + ### /foo/vendor/lib + ### /foo/vendor/lib/arch + for my $href ( @config_names ) { + for my $key ( qw[lib arch] ) { + + ### look up the config value -- use EXP for the EXPANDED + ### version, so no ~ etc are found in there + my $dir = $Config::Config{ $href->{ $key } .'exp' } or next; + my $prefix = $Config::Config{ $href->{prefix} }; + + ### prefix may be relative to home, and contain a ~ + ### if so, fix it up. + $prefix =~ s/^~/$home/; + + ### remove the prefix from it, so we can append to our $lib + $dir =~ s/^\Q$prefix\E//; + + ### do the appending + push @libs, File::Spec->catdir( $lib, $dir ); + + } + } + } + + my $inst; + unless( $inst = ExtUtils::Installed->new( extra_libs => \@libs ) ) { + error( loc("Could not create an '%1' object", 'ExtUtils::Installed' ) ); + + ### in case it's being used directly... ### + return; + } + + + { ### EU::Installed can die =/ + my @files; + eval { @files = $inst->$method( $self->module, $type ) }; + + if( $@ ) { + chomp $@; + error( loc("Could not get '%1' for '%2': %3", + $method, $self->module, $@ ) ); + return; + } + + return wantarray ? @files : \@files; + } +} + +=head2 $bool = $self->add_to_includepath; + +Adds the current modules path to C<@INC> and C<$PERL5LIB>. This allows +you to add the module from its build dir to your path. + +You can reset C<@INC> and C<$PERL5LIB> to its original state when you +started the program, by calling: + + $self->parent->flush('lib'); + +=cut + +sub add_to_includepath { + my $self = shift; + my $cb = $self->parent; + + if( my $dir = $self->status->extract ) { + + $cb->_add_to_includepath( + directories => [ + File::Spec->catdir(BLIB->($dir), LIB), + File::Spec->catdir(BLIB->($dir), ARCH), + BLIB->($dir), + ] + ) or return; + + } else { + error(loc( "No extract dir registered for '%1' -- can not add ". + "add builddir to search path!", $self->module )); + return; + } + + return 1; + +} + +=pod + +=head2 $path = $self->best_path_to_module_build(); + +B<OBSOLETE> + +If a newer version of Module::Build is found in your path, it will +return this C<special> path. If the newest version of C<Module::Build> +is found in your regular C<@INC>, the method will return false. This +indicates you do not need to add a special directory to your C<@INC>. + +Note that this is only relevant if you're building your own +C<CPANPLUS::Dist::*> plugin -- the built-in dist types already have +this taken care of. + +=cut + +### make sure we're always running 'perl Build.PL' and friends +### against the highest version of module::build available +sub best_path_to_module_build { + my $self = shift; + + ### Since M::B will actually shell out and run the Build.PL, we must + ### make sure it refinds the proper version of M::B in the path. + ### that may be either in our cp::inc or in site_perl, or even a + ### new M::B being installed. + ### don't add anything else here, as that might screw up prereq checks + + ### XXX this might be needed for Dist::MM too, if a makefile.pl is + ### masquerading as a Build.PL + + ### did we find the most recent module::build in our installer path? + + ### XXX can't do changes to @INC, they're being ignored by + ### new_from_context when writing a Build script. see ticket: + ### #8826 Module::Build ignores changes to @INC when writing Build + ### from new_from_context + ### XXX applied schwern's patches (as seen on CPANPLUS::Devel 10/12/04) + ### and upped the version to 0.26061 of the bundled version, and things + ### work again + + ### this functionality is now obsolete -- prereqs should be installed + ### and we no longer use the CPANPLUS::inc magic.. so comment this out. +# require Module::Build; +# if( CPANPLUS::inc->path_to('Module::Build') and ( +# CPANPLUS::inc->path_to('Module::Build') eq +# CPANPLUS::inc->installer_path ) +# ) { +# +# ### if the module being installed is *not* Module::Build +# ### itself -- as that would undoubtedly be newer -- add +# ### the path to the installers to @INC +# ### if it IS module::build itself, add 'lib' to its path, +# ### as the Build.PL would do as well, but the API doesn't. +# ### this makes self updates possible +# return $self->module eq 'Module::Build' +# ? 'lib' +# : CPANPLUS::inc->installer_path; +# } + + ### otherwise, the path was found through a 'normal' way of + ### scanning @INC. + return; +} + +=pod + +=head1 BUG REPORTS + +Please report bugs or other issues to E<lt>bug-cpanplus@rt.cpan.org<gt>. + +=head1 AUTHOR + +This module by Jos Boumans E<lt>kane@cpan.orgE<gt>. + +=head1 COPYRIGHT + +The CPAN++ interface (of which this module is a part of) is copyright (c) +2001 - 2007, Jos Boumans E<lt>kane@cpan.orgE<gt>. All rights reserved. + +This library is free software; you may redistribute and/or modify it +under the same terms as Perl itself. + +=cut + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: + +1; + +__END__ + +todo: +reports(); diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Module/Author.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Module/Author.pm new file mode 100644 index 00000000000..92940fa51ff --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Module/Author.pm @@ -0,0 +1,232 @@ +package CPANPLUS::Module::Author; + +use strict; + +use CPANPLUS::Error; +use CPANPLUS::Internals::Constants; +use Params::Check qw[check]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +local $Params::Check::VERBOSE = 1; + +=pod + +=head1 NAME + +CPANPLUS::Module::Author + +=head1 SYNOPSIS + + my $author = CPANPLUS::Module::Author->new( + author => 'Jack Ashton', + cpanid => 'JACKASH', + _id => INTERNALS_OBJECT_ID, + ); + + $author->cpanid; + $author->author; + $author->email; + + @dists = $author->distributions; + @mods = $author->modules; + + @accessors = CPANPLUS::Module::Author->accessors; + +=head1 DESCRIPTION + +C<CPANPLUS::Module::Author> creates objects from the information in the +source files. These can then be used to query on. + +These objects should only be created internally. For C<fake> objects, +there's the C<CPANPLUS::Module::Author::Fake> class. + +=head1 ACCESSORS + +An objects of this class has the following accessors: + +=over 4 + +=item author + +Name of the author. + +=item cpanid + +The CPAN id of the author. + +=item email + +The email address of the author, which defaults to '' if not provided. + +=item parent + +The C<CPANPLUS::Internals::Object> that spawned this module object. + +=back + +=cut + +my $tmpl = { + author => { required => 1 }, # full name of the author + cpanid => { required => 1 }, # cpan id + email => { default => '' }, # email address of the author + _id => { required => 1 }, # id of the Internals object that spawned us +}; + +### autogenerate accessors ### +for my $key ( keys %$tmpl ) { + no strict 'refs'; + *{__PACKAGE__."::$key"} = sub { + my $self = shift; + $self->{$key} = $_[0] if @_; + return $self->{$key}; + } +} + +sub parent { + my $self = shift; + my $obj = CPANPLUS::Internals->_retrieve_id( $self->_id ); + + return $obj; +} + +=pod + +=head1 METHODS + +=head2 $auth = CPANPLUS::Module::Author->new( author => AUTHOR_NAME, cpanid => CPAN_ID, _id => INTERNALS_ID [, email => AUTHOR_EMAIL] ) + +This method returns a C<CPANPLUS::Module::Author> object, based on the given +parameters. + +Returns false on failure. + +=cut + +sub new { + my $class = shift; + my %hash = @_; + + ### don't check the template for sanity + ### -- we know it's good and saves a lot of performance + local $Params::Check::SANITY_CHECK_TEMPLATE = 0; + + my $object = check( $tmpl, \%hash ) or return; + + return bless $object, $class; +} + +=pod + +=head2 @mod_objs = $auth->modules() + +Return a list of module objects this author has released. + +=cut + +sub modules { + my $self = shift; + my $cb = $self->parent; + + my $aref = $cb->_search_module_tree( + type => 'author', + ### XXX, depending on backend, this is either an object + ### or the cpanid string. Dont know an elegant way to + ### solve this right now, so passing both + allow => [$self, $self->cpanid], + ); + return @$aref if $aref; + return; +} + +=pod + +=head2 @dists = $auth->distributions() + +Returns a list of module objects representing all the distributions +this author has released. + +=cut + +sub distributions { + my $self = shift; + my %hash = @_; + + local $Params::Check::ALLOW_UNKNOWN = 1; + local $Params::Check::NO_DUPLICATES = 1; + + my $mod; + my $tmpl = { + module => { default => '', store => \$mod }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + ### if we didn't get a module object passed, we'll find one ourselves ### + unless( $mod ) { + my @list = $self->modules; + if( @list ) { + $mod = $list[0]; + } else { + error( loc( "This author has released no modules" ) ); + return; + } + } + + my $file = $mod->checksums( %hash ); + my $href = $mod->_parse_checksums_file( file => $file ) or return; + + my @rv; + for my $name ( keys %$href ) { + + ### shortcut asap, so we avoid extra ops. On big checksums files + ### the call to clone() takes up a lot of time. + ### .meta files are now also in the checksums file, + ### which means we have to filter out things that dont + ### match our regex + next if $mod->package_extension( $name ) eq META_EXT; + + ### used to do this wiht ->clone. However, that calls ->dslip, + ### (which is wrong anyway, as we're doing a different module), + ### which in turn calls ->contains, which scans the entire + ### module tree using _search_module_tree, which uses P::C + ### and is therefor VERY VERY slow. + ### so let's do this the direct way for speed ups. + my $dist = CPANPLUS::Module::Fake->new( + module => do { my $m = $mod->package_name( $name ); + $m =~ s/-/::/g; $m; + }, + version => $mod->package_version( $name ), + package => $name, + path => $mod->path, # same author after all + author => $mod->author, # same author after all + mtime => $href->{$name}->{'mtime'}, # release date + ); + + push @rv, $dist; + } + + return @rv; +} + + +=pod + +=head1 CLASS METHODS + +=head2 accessors () + +Returns a list of all accessor methods to the object + +=cut + +sub accessors { return keys %$tmpl }; + +1; + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Module/Author/Fake.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Module/Author/Fake.pm new file mode 100644 index 00000000000..3156c5c7abb --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Module/Author/Fake.pm @@ -0,0 +1,80 @@ +package CPANPLUS::Module::Author::Fake; + + +use CPANPLUS::Module::Author; +use CPANPLUS::Internals; +use CPANPLUS::Error; + +use strict; +use vars qw[@ISA]; +use Params::Check qw[check]; + +@ISA = qw[CPANPLUS::Module::Author]; + +$Params::Check::VERBOSE = 1; + +=pod + +=head1 NAME + +CPANPLUS::Module::Author::Fake + +=head1 SYNOPSIS + + my $auth = CPANPLUS::Module::Author::Fake->new( + author => 'Foo Bar', + email => 'luser@foo.com', + cpanid => 'FOO', + _id => $cpan->id, + ); + +=head1 DESCRIPTION + +A class for creating fake author objects, for shortcut use internally +by CPANPLUS. + +Inherits from C<CPANPLUS::Module::Author>. + +=head1 METHODS + +=head2 new( _id => DIGIT ) + +Creates a dummy author object. It can take the same options as +C<< CPANPLUS::Module::Author->new >>, but will fill in default ones +if none are provided. Only the _id key is required. + +=cut + +sub new { + my $class = shift; + my %hash = @_; + + my $tmpl = { + author => { default => 'CPANPLUS Internals' }, + email => { default => 'cpanplus-info@lists.sf.net' }, + cpanid => { default => 'CPANPLUS' }, + _id => { default => CPANPLUS::Internals->_last_id }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + my $obj = CPANPLUS::Module::Author->new( %$args ) or return; + + unless( $obj->_id ) { + error(loc("No '%1' specified -- No CPANPLUS object associated!",'_id')); + return; + } + + ### rebless object ### + return bless $obj, $class; +} + +1; + + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Module/Checksums.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Module/Checksums.pm new file mode 100644 index 00000000000..e1a2bbdb6ad --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Module/Checksums.pm @@ -0,0 +1,251 @@ +package CPANPLUS::Module::Checksums; + +use strict; +use vars qw[@ISA]; + + +use CPANPLUS::Error; +use CPANPLUS::Internals::Constants; + +use FileHandle; + +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; +use Params::Check qw[check]; +use Module::Load::Conditional qw[can_load]; + +$Params::Check::VERBOSE = 1; + +@ISA = qw[ CPANPLUS::Module::Signature ]; + +=head1 NAME + +CPANPLUS::Module::Checksums + +=head1 SYNOPSIS + + $file = $modobj->checksums; + $bool = $mobobj->_validate_checksum; + +=head1 DESCRIPTION + +This is a class that provides functions for checking the checksum +of a distribution. Should not be loaded directly, but used via the +interface provided via C<CPANPLUS::Module>. + +=head1 METHODS + +=head2 $mod->checksums + +Fetches the checksums file for this module object. +For the options it can take, see C<CPANPLUS::Module::fetch()>. + +Returns the location of the checksums file on success and false +on error. + +The location of the checksums file is also stored as + + $mod->status->checksums + +=cut + +sub checksums { + my $mod = shift or return; + + my $file = $mod->_get_checksums_file( @_ ); + + return $mod->status->checksums( $file ) if $file; + + return; +} + +### checks if the package checksum matches the one +### from the checksums file +sub _validate_checksum { + my $self = shift; #must be isa CPANPLUS::Module + my $conf = $self->parent->configure_object; + my %hash = @_; + + my $verbose; + my $tmpl = { + verbose => { default => $conf->get_conf('verbose'), + store => \$verbose }, + }; + + check( $tmpl, \%hash ) or return; + + ### if we can't check it, we must assume it's ok ### + return $self->status->checksum_ok(1) + unless can_load( modules => { 'Digest::MD5' => '0.0' } ); + #class CPANPLUS::Module::Status is runtime-generated + + my $file = $self->_get_checksums_file( verbose => $verbose ) or ( + error(loc(q[Could not fetch '%1' file], CHECKSUMS)), return ); + + $self->_check_signature_for_checksum_file( file => $file ) or ( + error(loc(q[Could not verify '%1' file], CHECKSUMS)), return ); + #for whole CHECKSUMS file + + my $href = $self->_parse_checksums_file( file => $file ) or ( + error(loc(q[Could not parse '%1' file], CHECKSUMS)), return ); + + my $size = $href->{ $self->package }->{'size'}; + + ### the checksums file tells us the size of the archive + ### but the downloaded file is of different size + if( defined $size ) { + if( not (-s $self->status->fetch == $size) ) { + error(loc( "Archive size does not match for '%1': " . + "size is '%2' but should be '%3'", + $self->package, -s $self->status->fetch, $size)); + return $self->status->checksum_ok(0); + } + } else { + msg(loc("Archive size is not known for '%1'",$self->package),$verbose); + } + + my $md5 = $href->{ $self->package }->{'md5'}; + + unless( defined $md5 ) { + msg(loc("No 'md5' checksum known for '%1'",$self->package),$verbose); + + return $self->status->checksum_ok(1); + } + + $self->status->checksum_value($md5); + + + my $fh = FileHandle->new( $self->status->fetch ) or return; + binmode $fh; + + my $ctx = Digest::MD5->new; + $ctx->addfile( $fh ); + + my $flag = $ctx->hexdigest eq $md5; + $flag + ? msg(loc("Checksum matches for '%1'", $self->package),$verbose) + : error(loc("Checksum does not match for '%1': " . + "MD5 is '%2' but should be '%3'", + $self->package, $ctx->hexdigest, $md5),$verbose); + + + return $self->status->checksum_ok(1) if $flag; + return $self->status->checksum_ok(0); +} + + +### fetches the module objects checksum file ### +sub _get_checksums_file { + my $self = shift; + my %hash = @_; + + my $clone = $self->clone; + $clone->package( CHECKSUMS ); + + my $file = $clone->fetch( ttl => 3600, %hash ) or return; + + return $file; +} + +sub _parse_checksums_file { + my $self = shift; + my %hash = @_; + + my $file; + my $tmpl = { + file => { required => 1, allow => FILE_READABLE, store => \$file }, + }; + my $args = check( $tmpl, \%hash ); + + my $fh = OPEN_FILE->( $file ) or return; + + ### loop over the header, there might be a pgp signature ### + my $signed; + while (local $_ = <$fh>) { + last if /^\$cksum = \{\s*$/; # skip till this line + my $header = PGP_HEADER; # but be tolerant of whitespace + $signed = 1 if /^${header}\s*$/;# due to crossplatform linebreaks + } + + ### read the filehandle, parse it rather than eval it, even though it + ### *should* be valid perl code + my $dist; + my $cksum = {}; + while (local $_ = <$fh>) { + + if (/^\s*'([^']+)' => \{\s*$/) { + $dist = $1; + + } elsif (/^\s*'([^']+)' => '?([^'\n]+)'?,?\s*$/ and defined $dist) { + $cksum->{$dist}{$1} = $2; + + } elsif (/^\s*}[,;]?\s*$/) { + undef $dist; + + } elsif (/^__END__\s*$/) { + last; + + } else { + error( loc("Malformed %1 line: %2", CHECKSUMS, $_) ); + } + } + + return $cksum; +} + +sub _check_signature_for_checksum_file { + my $self = shift; + + my $conf = $self->parent->configure_object; + my %hash = @_; + + ### you don't want to check signatures, + ### so let's just return true; + return 1 unless $conf->get_conf('signature'); + + my($force,$file,$verbose); + my $tmpl = { + file => { required => 1, allow => FILE_READABLE, store => \$file }, + force => { default => $conf->get_conf('force'), store => \$force }, + verbose => { default => $conf->get_conf('verbose'), store => \$verbose }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + my $fh = OPEN_FILE->($file) or return; + + my $signed; + while (local $_ = <$fh>) { + my $header = PGP_HEADER; + $signed = 1 if /^$header$/; + } + + if ( !$signed ) { + msg(loc("No signature found in %1 file '%2'", + CHECKSUMS, $file), $verbose); + + return 1 unless $force; + + error( loc( "%1 file '%2' is not signed -- aborting", + CHECKSUMS, $file ) ); + return; + + } + + if( can_load( modules => { 'Module::Signature' => '0.06' } ) ) { + # local $Module::Signature::SIGNATURE = $file; + # ... check signatures ... + } + + return 1; +} + + + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: + +1; diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Module/Fake.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Module/Fake.pm new file mode 100644 index 00000000000..84d0233cf83 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Module/Fake.pm @@ -0,0 +1,86 @@ +package CPANPLUS::Module::Fake; + + +use CPANPLUS::Error; +use CPANPLUS::Module; +use CPANPLUS::Module::Author::Fake; +use CPANPLUS::Internals; + +use strict; +use vars qw[@ISA]; +use Params::Check qw[check]; + +@ISA = qw[CPANPLUS::Module]; +$Params::Check::VERBOSE = 1; + +=pod + +=head1 NAME + +CPANPLUS::Module::Fake + +=head1 SYNOPSIS + + my $obj = CPANPLUS::Module::Fake->new( + module => 'Foo', + path => 'ftp/path/to/foo', + author => CPANPLUS::Module::Author::Fake->new, + package => 'fake-1.1.tgz', + _id => $cpan->_id, + ); + +=head1 DESCRIPTION + +A class for creating fake module objects, for shortcut use internally +by CPANPLUS. + +Inherits from C<CPANPLUS::Module>. + +=head1 METHODS + +=head2 new( module => $mod, path => $path, package => $pkg, [_id => DIGIT] ) + +Creates a dummy module object from the above parameters. It can +take more options (same as C<< CPANPLUS::Module->new >> but the above +are required. + +=cut + +sub new { + my $class = shift; + my %hash = @_; + + local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + module => { required => 1 }, + path => { required => 1 }, + package => { required => 1 }, + _id => { default => CPANPLUS::Internals->_last_id }, + author => { default => '' }, + }; + + my $args = check( $tmpl, \%hash ) or return; + + $args->{author} ||= CPANPLUS::Module::Author::Fake->new( + _id => $args->{_id} ); + + my $obj = CPANPLUS::Module->new( %$args ) or return; + + unless( $obj->_id ) { + error(loc("No '%1' specified -- No CPANPLUS object associated!",'_id')); + return; + } + + ### rebless object ### + return bless $obj, $class; +} + +1; + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Module/Signature.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Module/Signature.pm new file mode 100644 index 00000000000..cec6f2906b0 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Module/Signature.pm @@ -0,0 +1,65 @@ +package CPANPLUS::Module::Signature; + +use strict; + + +use Cwd; +use CPANPLUS::Error; +use Params::Check qw[check]; +use Module::Load::Conditional qw[can_load]; + + +### detached sig, not actually used afaik --kane ### +#sub get_signature { +# my $self = shift; +# +# my $clone = $self->clone; +# $clone->package( $self->package . '.sig' ); +# +# return $clone->fetch; +#} + +sub check_signature { + my $self = shift; + my $cb = $self->parent; + my $conf = $cb->configure_object; + my %hash = @_; + + my $verbose; + my $tmpl = { + verbose => {default => $conf->get_conf('verbose'), store => \$verbose}, + }; + + check( $tmpl, \%hash ) or return; + + my $dir = $self->status->extract or ( + error( loc( "Do not know what dir '%1' was extracted to; ". + "Cannot check signature", $self->module ) ), + return ); + + my $cwd = cwd(); + unless( $cb->_chdir( dir => $dir ) ) { + error(loc( "Could not chdir to '%1', cannot verify distribution '%2'", + $dir, $self->module )); + return; + } + + + ### check prerequisites + my $flag; + my $use_list = { 'Module::Signature' => '0.06' }; + if( can_load( modules => $use_list, verbose => 1 ) ) { + my $rv = Module::Signature::verify(); + + unless ($rv eq Module::Signature::SIGNATURE_OK() or + $rv eq Module::Signature::SIGNATURE_MISSING() + ) { + $flag++; # whoops, bad sig + } + } + + $cb->_chdir( dir => $cwd ); + return $flag ? 0 : 1; +} + +1; diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Selfupdate.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Selfupdate.pm new file mode 100644 index 00000000000..48f918ce82e --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Selfupdate.pm @@ -0,0 +1,547 @@ +package CPANPLUS::Selfupdate; + +use strict; +use Params::Check qw[check]; +use IPC::Cmd qw[can_run]; +use CPANPLUS::Error qw[error msg]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +use CPANPLUS::Internals::Constants; + +$Params::Check::VERBOSE = 1; + +=head1 NAME + +CPANPLUS::Selfupdate + +=head1 SYNOPSIS + + $su = $cb->selfupdate_object; + + @feats = $su->list_features; + @feats = $su->list_enabled_features; + + @mods = map { $su->modules_for_feature( $_ ) } @feats; + @mods = $su->list_core_dependencies; + @mods = $su->list_core_modules; + + for ( @mods ) { + print $_->name " should be version " . $_->version_required; + print "Installed version is not uptodate!" + unless $_->is_installed_version_sufficient; + } + + $ok = $su->selfupdate( update => 'all', latest => 0 ); + +=cut + +### a config has describing our deps etc +{ + + my $Modules = { + dependencies => { + 'File::Fetch' => '0.15_02', # lynx & 404 handling + 'File::Spec' => '0.82', + 'IPC::Cmd' => '0.36', # 5.6.2 compat: 2-arg open + 'Locale::Maketext::Simple' => '0.01', + 'Log::Message' => '0.01', + 'Module::Load' => '0.10', + 'Module::Load::Conditional' => '0.31_01', # returns dir for loaded + # modules + 'version' => '0.73', # needed for M::L::C + # addresses #24630 and + # #24675 + # Address ~0 overflow issue + 'Params::Check' => '0.22', + 'Package::Constants' => '0.01', + 'Term::UI' => '0.18', # option parsing + 'Test::Harness' => '2.62', # due to bug #19505 + # only 2.58 and 2.60 are bad + 'Test::More' => '0.47', # to run our tests + 'Archive::Extract' => '0.16', # ./Dir bug fix + 'Archive::Tar' => '1.23', + 'IO::Zlib' => '1.04', # needed for Archive::Tar + 'Object::Accessor' => '0.34', # mk_aliases support + 'Module::CoreList' => '2.22', # deprecated core modules + 'Module::Pluggable' => '2.4', + 'Module::Loaded' => '0.01', + 'Parse::CPAN::Meta' => '0.02', # config_requires support + 'ExtUtils::Install' => '1.42', # uninstall outside @INC + }, + + features => { + # config_key_name => [ + # sub { } to list module key/value pairs + # sub { } to check if feature is enabled + # ] + prefer_makefile => [ + sub { + my $cb = shift; + $cb->configure_object->get_conf('prefer_makefile') + ? { } + : { 'CPANPLUS::Dist::Build' => '0.24' }; + }, + sub { return 1 }, # always enabled + ], + cpantest => [ + { 'Test::Reporter' => '1.34', + 'Parse::CPAN::Meta' => '0.0' + }, + sub { + my $cb = shift; + return $cb->configure_object->get_conf('cpantest'); + }, + ], + dist_type => [ + sub { + my $cb = shift; + my $dist = $cb->configure_object->get_conf('dist_type'); + return { $dist => '0.0' } if $dist; + return; + }, + sub { + my $cb = shift; + return $cb->configure_object->get_conf('dist_type'); + }, + ], + + md5 => [ + { + 'Digest::MD5' => '0.0', + }, + sub { + my $cb = shift; + return $cb->configure_object->get_conf('md5'); + }, + ], + shell => [ + sub { + my $cb = shift; + my $dist = $cb->configure_object->get_conf('shell'); + + ### we bundle these shells, so don't bother having a dep + ### on them... If we don't do this, CPAN.pm actually detects + ### a recursive dependency and breaks (see #26077). + ### This is not an issue for CPANPLUS itself, it handles + ### it smartly. + return if $dist eq SHELL_DEFAULT or $dist eq SHELL_CLASSIC; + return { $dist => '0.0' } if $dist; + return; + }, + sub { return 1 }, + ], + signature => [ + sub { + my $cb = shift; + return { + 'Module::Signature' => '0.06', + } if can_run('gpg'); + ### leave this out -- Crypt::OpenPGP is fairly + ### painful to install, and broken on some platforms + ### so we'll just always fall back to gpg. It may + ### issue a warning or 2, but that's about it. + ### this change due to this ticket: #26914 + # and $cb->configure_object->get_conf('prefer_bin'); + + return { + 'Crypt::OpenPGP' => '0.0', + 'Module::Signature' => '0.06', + }; + }, + sub { + my $cb = shift; + return $cb->configure_object->get_conf('signature'); + }, + ], + storable => [ + { 'Storable' => '0.0' }, + sub { + my $cb = shift; + return $cb->configure_object->get_conf('storable'); + }, + ], + sqlite_backend => [ + { 'DBIx::Simple' => '0.0', + 'DBD::SQLite' => '0.0', + }, + sub { + my $cb = shift; + my $conf = $cb->configure_object; + return $conf->get_conf('source_engine') + eq 'CPANPLUS::Internals::Source::SQLite' + }, + ], + }, + core => { + 'CPANPLUS' => '0.0', + }, + }; + + sub _get_config { return $Modules } +} + +=head1 METHODS + +=head2 $self = CPANPLUS::Selfupdate->new( $backend_object ); + +Sets up a new selfupdate object. Called automatically when +a new backend object is created. + +=cut + +sub new { + my $class = shift; + my $cb = shift or return; + return bless sub { $cb }, $class; +} + + +{ ### cache to find the relevant modules + my $cache = { + core + => sub { my $self = shift; + core => [ $self->list_core_modules ] }, + + dependencies + => sub { my $self = shift; + dependencies => [ $self->list_core_dependencies ] }, + + enabled_features + => sub { my $self = shift; + map { $_ => [ $self->modules_for_feature( $_ ) ] } + $self->list_enabled_features + }, + features + => sub { my $self = shift; + map { $_ => [ $self->modules_for_feature( $_ ) ] } + $self->list_features + }, + ### make sure to do 'core' first, in case + ### we are out of date ourselves + all => [ qw|core dependencies enabled_features| ], + }; + + +=head2 @cat = $self->list_categories + +Returns a list of categories that the C<selfupdate> method accepts. + +See C<selfupdate> for details. + +=cut + + sub list_categories { return sort keys %$cache } + +=head2 %list = $self->list_modules_to_update( update => "core|dependencies|enabled_features|features|all", [latest => BOOL] ) + +List which modules C<selfupdate> would upgrade. You can update either +the core (CPANPLUS itself), the core dependencies, all features you have +currently turned on, or all features available, or everything. + +The C<latest> option determines whether it should update to the latest +version on CPAN, or if the minimal required version for CPANPLUS is +good enough. + +Returns a hash of feature names and lists of module objects to be +upgraded based on the category you provided. For example: + + %list = $self->list_modules_to_update( update => 'core' ); + +Would return: + + ( core => [ $module_object_for_cpanplus ] ); + +=cut + + sub list_modules_to_update { + my $self = shift; + my $cb = $self->(); + my $conf = $cb->configure_object; + my %hash = @_; + + my($type, $latest); + my $tmpl = { + update => { required => 1, store => \$type, + allow => [ keys %$cache ], }, + latest => { default => 0, store => \$latest, allow => BOOLEANS }, + }; + + { local $Params::Check::ALLOW_UNKNOWN = 1; + check( $tmpl, \%hash ) or return; + } + + my $ref = $cache->{$type}; + + ### a list of ( feature1 => \@mods, feature2 => \@mods, etc ) + my %list = UNIVERSAL::isa( $ref, 'ARRAY' ) + ? map { $cache->{$_}->( $self ) } @$ref + : $ref->( $self ); + + ### filter based on whether we need the latest ones or not + for my $aref ( values %list ) { + $aref = [ $latest + ? grep { !$_->is_uptodate } @$aref + : grep { !$_->is_installed_version_sufficient } @$aref + ]; + } + + return %list; + } + +=head2 $bool = $self->selfupdate( update => "core|dependencies|enabled_features|features|all", [latest => BOOL, force => BOOL] ) + +Selfupdate CPANPLUS. You can update either the core (CPANPLUS itself), +the core dependencies, all features you have currently turned on, or +all features available, or everything. + +The C<latest> option determines whether it should update to the latest +version on CPAN, or if the minimal required version for CPANPLUS is +good enough. + +Returns true on success, false on error. + +=cut + + sub selfupdate { + my $self = shift; + my $cb = $self->(); + my $conf = $cb->configure_object; + my %hash = @_; + + my $force; + my $tmpl = { + force => { default => $conf->get_conf('force'), store => \$force }, + }; + + { local $Params::Check::ALLOW_UNKNOWN = 1; + check( $tmpl, \%hash ) or return; + } + + my %list = $self->list_modules_to_update( %hash ) or return; + + ### just the modules please + my @mods = map { @$_ } values %list; + + my $flag; + for my $mod ( @mods ) { + unless( $mod->install( force => $force ) ) { + $flag++; + error(loc("Failed to update module '%1'", $mod->name)); + } + } + + return if $flag; + return 1; + } + +} + +=head2 @features = $self->list_features + +Returns a list of features that are supported by CPANPLUS. + +=cut + +sub list_features { + my $self = shift; + return keys %{ $self->_get_config->{'features'} }; +} + +=head2 @features = $self->list_enabled_features + +Returns a list of features that are enabled in your current +CPANPLUS installation. + +=cut + +sub list_enabled_features { + my $self = shift; + my $cb = $self->(); + + my @enabled; + for my $feat ( $self->list_features ) { + my $ref = $self->_get_config->{'features'}->{$feat}->[1]; + push @enabled, $feat if $ref->($cb); + } + + return @enabled; +} + +=head2 @mods = $self->modules_for_feature( FEATURE [,AS_HASH] ) + +Returns a list of C<CPANPLUS::Selfupdate::Module> objects which +represent the modules required to support this feature. + +For a list of features, call the C<list_features> method. + +If the C<AS_HASH> argument is provided, no module objects are +returned, but a hashref where the keys are names of the modules, +and values are their minimum versions. + +=cut + +sub modules_for_feature { + my $self = shift; + my $feature = shift or return; + my $as_hash = shift || 0; + my $cb = $self->(); + + unless( exists $self->_get_config->{'features'}->{$feature} ) { + error(loc("Unknown feature '%1'", $feature)); + return; + } + + my $ref = $self->_get_config->{'features'}->{$feature}->[0]; + + ### it's either a list of modules/versions or a subroutine that + ### returns a list of modules/versions + my $href = UNIVERSAL::isa( $ref, 'HASH' ) ? $ref : $ref->( $cb ); + + return unless $href; # nothing needed for the feature? + + return $href if $as_hash; + return $self->_hashref_to_module( $href ); +} + + +=head2 @mods = $self->list_core_dependencies( [AS_HASH] ) + +Returns a list of C<CPANPLUS::Selfupdate::Module> objects which +represent the modules that comprise the core dependencies of CPANPLUS. + +If the C<AS_HASH> argument is provided, no module objects are +returned, but a hashref where the keys are names of the modules, +and values are their minimum versions. + +=cut + +sub list_core_dependencies { + my $self = shift; + my $as_hash = shift || 0; + my $cb = $self->(); + my $href = $self->_get_config->{'dependencies'}; + + return $href if $as_hash; + return $self->_hashref_to_module( $href ); +} + +=head2 @mods = $self->list_core_modules( [AS_HASH] ) + +Returns a list of C<CPANPLUS::Selfupdate::Module> objects which +represent the modules that comprise the core of CPANPLUS. + +If the C<AS_HASH> argument is provided, no module objects are +returned, but a hashref where the keys are names of the modules, +and values are their minimum versions. + +=cut + +sub list_core_modules { + my $self = shift; + my $as_hash = shift || 0; + my $cb = $self->(); + my $href = $self->_get_config->{'core'}; + + return $href if $as_hash; + return $self->_hashref_to_module( $href ); +} + +sub _hashref_to_module { + my $self = shift; + my $cb = $self->(); + my $href = shift or return; + + return map { + CPANPLUS::Selfupdate::Module->new( + $cb->module_tree($_) => $href->{$_} + ) + } keys %$href; +} + + +=head1 CPANPLUS::Selfupdate::Module + +C<CPANPLUS::Selfupdate::Module> extends C<CPANPLUS::Module> objects +by providing accessors to aid in selfupdating CPANPLUS. + +These objects are returned by all methods of C<CPANPLUS::Selfupdate> +that return module objects. + +=cut + +{ package CPANPLUS::Selfupdate::Module; + use base 'CPANPLUS::Module'; + + ### stores module name -> cpanplus required version + ### XXX only can deal with 1 pair! + my %Cache = (); + my $Acc = 'version_required'; + + sub new { + my $class = shift; + my $mod = shift or return; + my $ver = shift; return unless defined $ver; + + my $obj = $mod->clone; # clone the module object + bless $obj, $class; # rebless it to our class + + $obj->$Acc( $ver ); + + return $obj; + } + +=head2 $version = $mod->version_required + +Returns the version of this module required for CPANPLUS. + +=cut + + sub version_required { + my $self = shift; + $Cache{ $self->name } = shift() if @_; + return $Cache{ $self->name }; + } + +=head2 $bool = $mod->is_installed_version_sufficient + +Returns true if the installed version of this module is sufficient +for CPANPLUS, or false if it is not. + +=cut + + + sub is_installed_version_sufficient { + my $self = shift; + return $self->is_uptodate( version => $self->$Acc ); + } + +} + +1; + +=pod + +=head1 BUG REPORTS + +Please report bugs or other issues to E<lt>bug-cpanplus@rt.cpan.org<gt>. + +=head1 AUTHOR + +This module by Jos Boumans E<lt>kane@cpan.orgE<gt>. + +=head1 COPYRIGHT + +The CPAN++ interface (of which this module is a part of) is copyright (c) +2001 - 2007, Jos Boumans E<lt>kane@cpan.orgE<gt>. All rights reserved. + +This library is free software; you may redistribute and/or modify it +under the same terms as Perl itself. + +=cut + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Shell.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Shell.pm new file mode 100644 index 00000000000..854d46b16a4 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Shell.pm @@ -0,0 +1,341 @@ +package CPANPLUS::Shell; + +use strict; + +use CPANPLUS::Error; +use CPANPLUS::Configure; +use CPANPLUS::Internals::Constants; + +use Module::Load qw[load]; +use Params::Check qw[check]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +$Params::Check::VERBOSE = 1; + +use vars qw[@ISA $SHELL $DEFAULT]; + +$DEFAULT = SHELL_DEFAULT; + +=pod + +=head1 NAME + +CPANPLUS::Shell + +=head1 SYNOPSIS + + use CPANPLUS::Shell; # load the shell indicated by your + # config -- defaults to + # CPANPLUS::Shell::Default + + use CPANPLUS::Shell qw[Classic] # load CPANPLUS::Shell::Classic; + + my $ui = CPANPLUS::Shell->new(); + my $name = $ui->which; # Find out what shell you loaded + + $ui->shell; # run the ui shell + + +=head1 DESCRIPTION + +This module is the generic loading (and base class) for all C<CPANPLUS> +shells. Through this module you can load any installed C<CPANPLUS> +shell. + +Just about all the functionality is provided by the shell that you have +loaded, and not by this class (which merely functions as a generic +loading class), so please consult the documentation of your shell of +choice. + +=cut + +sub import { + my $class = shift; + my $option = shift; + + ### find out what shell we're supposed to load ### + $SHELL = $option + ? $class . '::' . $option + : do { ### XXX this should offer to reconfigure + ### CPANPLUS, somehow. --rs + ### XXX load Configure only if we really have to + ### as that means any $Conf passed later on will + ### be ignored in favour of the one that was + ### retrieved via ->new --kane + my $conf = CPANPLUS::Configure->new() or + die loc("No configuration available -- aborting") . $/; + $conf->get_conf('shell') || $DEFAULT; + }; + + ### load the shell, fall back to the default if required + ### and die if even that doesn't work + EVAL: { + eval { load $SHELL }; + + if( $@ ) { + my $err = $@; + + die loc("Your default shell '%1' is not available: %2", + $DEFAULT, $err) . + loc("Check your installation!") . "\n" + if $SHELL eq $DEFAULT; + + warn loc("Failed to use '%1': %2", $SHELL, $err), + loc("Switching back to the default shell '%1'", $DEFAULT), + "\n"; + + $SHELL = $DEFAULT; + redo EVAL; + } + } + @ISA = ($SHELL); +} + +sub which { return $SHELL } + +1; + +########################################################################### +### abstracted out subroutines available to programmers of other shells ### +########################################################################### + +package CPANPLUS::Shell::_Base::ReadLine; + +use strict; +use vars qw($AUTOLOAD $TMPL); + +use FileHandle; +use CPANPLUS::Error; +use Params::Check qw[check]; +use Module::Load::Conditional qw[can_load]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +$Params::Check::VERBOSE = 1; + + +$TMPL = { + brand => { default => '', strict_type => 1 }, + prompt => { default => '> ', strict_type => 1 }, + pager => { default => '' }, + backend => { default => '' }, + term => { default => '' }, + format => { default => '' }, + dist_format => { default => '' }, + remote => { default => undef }, + noninteractive => { default => '' }, + cache => { default => [ ] }, + settings => { default => { install_all_prereqs => undef }, + no_override => 1 }, + _old_sigpipe => { default => '', no_override => 1 }, + _old_outfh => { default => '', no_override => 1 }, + _signals => { default => { INT => { } }, no_override => 1 }, +}; + +### autogenerate accessors ### +for my $key ( keys %$TMPL ) { + no strict 'refs'; + *{__PACKAGE__."::$key"} = sub { + my $self = shift; + $self->{$key} = $_[0] if @_; + return $self->{$key}; + } +} + +sub _init { + my $class = shift; + my %hash = @_; + + my $self = check( $TMPL, \%hash ) or return; + + bless $self, $class; + + ### signal handler ### + $SIG{INT} = $self->_signals->{INT}->{handler} = + sub { + unless ( $self->_signals->{INT}->{count}++ ) { + warn loc("Caught SIGINT"), "\n"; + } else { + warn loc("Got another SIGINT"), "\n"; die; + } + }; + ### end sig handler ### + + return $self; +} + +### display shell's banner, takes the Backend object as argument +sub _show_banner { + my $self = shift; + my $cpan = $self->backend; + my $term = $self->term; + + ### Tries to probe for our ReadLine support status + # a) under an interactive shell? + my $rl_avail = (!$term->isa('CPANPLUS::Shell::_Faked')) + # b) do we have a tty terminal? + ? (-t STDIN) + # c) should we enable the term? + ? (!$self->__is_bad_terminal($term)) + # d) external modules available? + ? ($term->ReadLine ne "Term::ReadLine::Stub") + # a+b+c+d => "Smart" terminal + ? loc("enabled") + # a+b+c => "Stub" terminal + : loc("available (try 'i Term::ReadLine::Perl')") + # a+b => "Bad" terminal + : loc("disabled") + # a => "Dumb" terminal + : loc("suppressed") + # none => "Faked" terminal + : loc("suppressed in batch mode"); + + $rl_avail = loc("ReadLine support %1.", $rl_avail); + $rl_avail = "\n*** $rl_avail" if (length($rl_avail) > 45); + + $self->__print( + loc("%1 -- CPAN exploration and module installation (v%2)", + $self->which, $self->which->VERSION()), "\n", + loc("*** Please report bugs to <bug-cpanplus\@rt.cpan.org>."), "\n", + loc("*** Using CPANPLUS::Backend v%1. %2", + $cpan->VERSION, $rl_avail), "\n\n" + ); +} + +### checks whether the Term::ReadLine is broken and needs to fallback to Stub +sub __is_bad_terminal { + my $self = shift; + my $term = $self->term; + + return unless $^O eq 'MSWin32'; + + ### replace the term with the default (stub) one + return $self->term(Term::ReadLine::Stub->new( $self->brand ) ); +} + +### open a pager handle +sub _pager_open { + my $self = shift; + my $cpan = $self->backend; + my $cmd = $cpan->configure_object->get_program('pager') or return; + + $self->_old_sigpipe( $SIG{PIPE} ); + $SIG{PIPE} = 'IGNORE'; + + my $fh = new FileHandle; + unless ( $fh->open("| $cmd") ) { + error(loc("could not pipe to %1: %2\n", $cmd, $!) ); + return; + } + + $fh->autoflush(1); + + $self->pager( $fh ); + $self->_old_outfh( select $fh ); + + return $fh; +} + +### print to the current pager handle, or STDOUT if it's not opened +sub _pager_close { + my $self = shift; + my $pager = $self->pager or return; + + $pager->close if (ref($pager) and $pager->can('close')); + + $self->pager( undef ); + + select $self->_old_outfh; + $SIG{PIPE} = $self->_old_sigpipe; + + return 1; +} + + + +{ + my $win32_console; + + ### determines row count of current terminal; defaults to 25. + ### used by the pager functions + sub _term_rowcount { + my $self = shift; + my $cpan = $self->backend; + my %hash = @_; + + my $default; + my $tmpl = { + default => { default => 25, allow => qr/^\d$/, + store => \$default } + }; + + check( $tmpl, \%hash ) or return; + + if ( $^O eq 'MSWin32' ) { + if ( can_load( modules => { 'Win32::Console' => '0.0' } ) ) { + $win32_console ||= Win32::Console->new(); + my $rows = ($win32_console->Info)[-1]; + return $rows; + } + + } else { + local $Module::Load::Conditional::VERBOSE = 0; + if ( can_load(modules => {'Term::Size' => '0.0'}) ) { + my ($cols, $rows) = Term::Size::chars(); + return $rows; + } + } + return $default; + } +} + +### Custom print routines, mainly to be able to catch output +### in test cases, or redirect it if need be +{ sub __print { + my $self = shift; + print @_; + } + + sub __printf { + my $self = shift; + my $fmt = shift; + + ### MUST specify $fmt as a seperate param, and not as part + ### of @_, as it will then miss the $fmt and return the + ### number of elements in the list... =/ --kane + $self->__print( sprintf( $fmt, @_ ) ); + } +} + +1; + +=pod + +=head1 BUG REPORTS + +Please report bugs or other issues to E<lt>bug-cpanplus@rt.cpan.org<gt>. + +=head1 AUTHOR + +This module by Jos Boumans E<lt>kane@cpan.orgE<gt>. + +=head1 COPYRIGHT + +The CPAN++ interface (of which this module is a part of) is copyright (c) +2001 - 2007, Jos Boumans E<lt>kane@cpan.orgE<gt>. All rights reserved. + +This library is free software; you may redistribute and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L<CPANPLUS::Shell::Default>, L<CPANPLUS::Shell::Classic>, L<cpanp> + +=cut + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: + diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Shell/Classic.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Shell/Classic.pm new file mode 100644 index 00000000000..08c03bcf383 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Shell/Classic.pm @@ -0,0 +1,1236 @@ +################################################## +### CPANPLUS/Shell/Classic.pm ### +### Backwards compatible shell for CPAN++ ### +### Written 08-04-2002 by Jos Boumans ### +################################################## + +package CPANPLUS::Shell::Classic; + +use strict; + + +use CPANPLUS::Error; +use CPANPLUS::Backend; +use CPANPLUS::Configure::Setup; +use CPANPLUS::Internals::Constants; + +use Cwd; +use IPC::Cmd; +use Term::UI; +use Data::Dumper; +use Term::ReadLine; + +use Module::Load qw[load]; +use Params::Check qw[check]; +use Module::Load::Conditional qw[can_load]; + +$Params::Check::VERBOSE = 1; +$Params::Check::ALLOW_UNKNOWN = 1; + +BEGIN { + use vars qw[ $VERSION @ISA ]; + @ISA = qw[ CPANPLUS::Shell::_Base::ReadLine ]; + $VERSION = '0.0562'; +} + +load CPANPLUS::Shell; + + +### our command set ### +my $map = { + a => '_author', + b => '_bundle', + d => '_distribution', + 'm' => '_module', + i => '_find_all', + r => '_uptodate', + u => '_not_supported', + ls => '_ls', + get => '_fetch', + make => '_install', + test => '_install', + install => '_install', + clean => '_not_supported', + look => '_shell', + readme => '_readme', + h => '_help', + '?' => '_help', + o => '_set_conf', + reload => '_reload', + autobundle => '_autobundle', + '!' => '_bang', + #'q' => '_quit', # done it the loop itself +}; + +### the shell object, scoped to the file ### +my $Shell; +my $Brand = 'cpan'; +my $Prompt = $Brand . '> '; + +sub new { + my $class = shift; + + my $cb = new CPANPLUS::Backend; + my $self = $class->SUPER::_init( + brand => $Brand, + term => Term::ReadLine->new( $Brand ), + prompt => $Prompt, + backend => $cb, + format => "%5s %-50s %8s %-10s\n", + ); + ### make it available package wide ### + $Shell = $self; + + ### enable verbose, it's the cpan.pm way + $cb->configure_object->set_conf( verbose => 1 ); + + + ### register install callback ### + $cb->_register_callback( + name => 'install_prerequisite', + code => \&__ask_about_install, + ); + + ### register test report callback ### + $cb->_register_callback( + name => 'edit_test_report', + code => \&__ask_about_test_report, + ); + + return $self; +} + +sub shell { + my $self = shift; + my $term = $self->term; + + $self->_show_banner; + $self->_input_loop && print "\n"; + $self->_quit; +} + +sub _input_loop { + my $self = shift; + my $term = $self->term; + my $cb = $self->backend; + + my $normal_quit = 0; + while ( + defined (my $input = eval { $term->readline($self->prompt) } ) + or $self->_signals->{INT}{count} == 1 + ) { + ### re-initiate all signal handlers + while (my ($sig, $entry) = each %{$self->_signals} ) { + $SIG{$sig} = $entry->{handler} if exists($entry->{handler}); + } + + last if $self->_dispatch_on_input( input => $input ); + + ### flush the lib cache ### + $cb->_flush( list => [qw|lib load|] ); + + } continue { + $self->_signals->{INT}{count}-- + if $self->_signals->{INT}{count}; # clear the sigint count + } + + return 1; +} + +sub _dispatch_on_input { + my $self = shift; + my $conf = $self->backend->configure_object(); + my $term = $self->term; + my %hash = @_; + + my $string; + my $tmpl = { + input => { required => 1, store => \$string } + }; + + check( $tmpl, \%hash ) or return; + + ### the original force setting; + my $force_store = $conf->get_conf( 'force' ); + + ### parse the input: the first part before the space + ### is the command, followed by arguments. + ### see the usage below + my $key; + PARSE_INPUT: { + $string =~ s|^\s*([\w\?\!]+)\s*||; + chomp $string; + $key = lc($1); + } + + ### you prefixed the input with 'force' + ### that means we set the force flag, and + ### reparse the input... + ### YAY goto block :) + if( $key eq 'force' ) { + $conf->set_conf( force => 1 ); + goto PARSE_INPUT; + } + + ### you want to quit + return 1 if $key =~ /^q/; + + my $method = $map->{$key}; + unless( $self->can( $method ) ) { + print "Unknown command '$key'. Type ? for help.\n"; + return; + } + + ### dispatch the method call + eval { $self->$method( + command => $key, + result => [ split /\s+/, $string ], + input => $string ); + }; + warn $@ if $@; + + return; +} + +### displays quit message +sub _quit { + + ### well, that's what CPAN.pm says... + print "Lockfile removed\n"; +} + +sub _not_supported { + my $self = shift; + my %hash = @_; + + my $cmd; + my $tmpl = { + command => { required => 1, store => \$cmd } + }; + + check( $tmpl, \%hash ) or return; + + print "Sorry, the command '$cmd' is not supported\n"; + + return; +} + +sub _fetch { + my $self = shift; + my $cb = $self->backend; + my %hash = @_; + + my($aref, $input); + my $tmpl = { + result => { store => \$aref, default => [] }, + input => { default => 'all', store => \$input }, + }; + + check( $tmpl, \%hash ) or return; + + for my $mod (@$aref) { + my $obj; + + unless( $obj = $cb->module_tree($mod) ) { + print "Warning: Cannot get $input, don't know what it is\n"; + print "Try the command\n\n"; + print "\ti /$mod/\n\n"; + print "to find objects with matching identifiers.\n"; + + next; + } + + $obj->fetch && $obj->extract; + } + + return $aref; +} + +sub _install { + my $self = shift; + my $cb = $self->backend; + my %hash = @_; + + my $mapping = { + make => { target => TARGET_CREATE, skiptest => 1 }, + test => { target => TARGET_CREATE }, + install => { target => TARGET_INSTALL }, + }; + + my($aref,$cmd); + my $tmpl = { + result => { store => \$aref, default => [] }, + command => { required => 1, store => \$cmd, allow => [keys %$mapping] }, + }; + + check( $tmpl, \%hash ) or return; + + for my $mod (@$aref) { + my $obj = $cb->module_tree( $mod ); + + unless( $obj ) { + print "No such module '$mod'\n"; + next; + } + + my $opts = $mapping->{$cmd}; + $obj->install( %$opts ); + } + + return $aref; +} + +sub _shell { + my $self = shift; + my $cb = $self->backend; + my $conf = $cb->configure_object; + my %hash = @_; + + my($aref, $cmd); + my $tmpl = { + result => { store => \$aref, default => [] }, + command => { required => 1, store => \$cmd }, + + }; + + check( $tmpl, \%hash ) or return; + + + my $shell = $conf->get_program('shell'); + unless( $shell ) { + print "Your configuration does not define a value for subshells.\n". + qq[Please define it with "o conf shell <your shell>"\n]; + return; + } + + my $cwd = Cwd::cwd(); + + for my $mod (@$aref) { + print "Running $cmd for $mod\n"; + + my $obj = $cb->module_tree( $mod ) or next; + $obj->fetch or next; + $obj->extract or next; + + $cb->_chdir( dir => $obj->status->extract ) or next; + + #local $ENV{PERL5OPT} = CPANPLUS::inc->original_perl5opt; + if( system($shell) and $! ) { + print "Error executing your subshell '$shell': $!\n"; + next; + } + } + $cb->_chdir( dir => $cwd ); + + return $aref; +} + +sub _readme { + my $self = shift; + my $cb = $self->backend; + my $conf = $cb->configure_object; + my %hash = @_; + + my($aref, $cmd); + my $tmpl = { + result => { store => \$aref, default => [] }, + command => { required => 1, store => \$cmd }, + + }; + + check( $tmpl, \%hash ) or return; + + for my $mod (@$aref) { + my $obj = $cb->module_tree( $mod ) or next; + + if( my $readme = $obj->readme ) { + + $self->_pager_open; + print $readme; + $self->_pager_close; + } + } + + return 1; +} + +sub _reload { + my $self = shift; + my $cb = $self->backend; + my $conf = $cb->configure_object; + my %hash = @_; + + my($input, $cmd); + my $tmpl = { + input => { default => 'all', store => \$input }, + command => { required => 1, store => \$cmd }, + + }; + + check( $tmpl, \%hash ) or return; + + if ( $input =~ /cpan/i ) { + print qq[You want to reload the CPAN code\n]; + print qq[Just type 'q' and then restart... ] . + qq[Trust me, it is MUCH safer\n]; + + } elsif ( $input =~ /index/i ) { + $cb->reload_indices(update_source => 1); + + } else { + print qq[cpan re-evals the CPANPLUS.pm file\n]; + print qq[index re-reads the index files\n]; + } + + return 1; +} + +sub _autobundle { + my $self = shift; + my $cb = $self->backend; + + print qq[Writing bundle file... This may take a while\n]; + + my $where = $cb->autobundle(); + + print $where + ? qq[\nWrote autobundle to $where\n] + : qq[\nCould not create autobundle\n]; + + return 1; +} + +sub _set_conf { + my $self = shift; + my $cb = $self->backend; + my $conf = $cb->configure_object; + my %hash = @_; + + my($aref, $input); + my $tmpl = { + result => { store => \$aref, default => [] }, + input => { default => 'all', store => \$input }, + }; + + check( $tmpl, \%hash ) or return; + + my $type = shift @$aref; + + if( $type eq 'debug' ) { + print qq[Sorry you cannot set debug options through ] . + qq[this shell in CPANPLUS\n]; + return; + + } elsif ( $type eq 'conf' ) { + + ### from CPAN.pm :o) + # CPAN::Shell::o and CPAN::Config::edit are closely related. 'o conf' + # should have been called set and 'o debug' maybe 'set debug' + + # commit Commit changes to disk + # defaults Reload defaults from disk + # init Interactive setting of all options + + my $name = shift @$aref; + my $value = "@$aref"; + + if( $name eq 'init' ) { + my $setup = CPANPLUS::Configure::Setup->new( + conf => $cb->configure_object, + term => $self->term, + backend => $cb, + ); + return $setup->init; + + } elsif ($name eq 'commit' ) {; + $cb->configure_object->save; + print "Your CPAN++ configuration info has been saved!\n\n"; + return; + + } elsif ($name eq 'defaults' ) { + print qq[Sorry, CPANPLUS cannot restore default for you.\n] . + qq[Perhaps you should run the interactive setup again.\n] . + qq[\ttry running 'o conf init'\n]; + return; + + ### we're just supplying things in the 'conf' section now, + ### not the program section.. it's a bit of a hassle to make that + ### work cleanly with the original CPAN.pm interface, so we'll fix + ### it when people start complaining, which is hopefully never. + } else { + unless( $name ) { + my @list = grep { $_ ne 'hosts' } + $conf->options( type => $type ); + + my $method = 'get_' . $type; + + local $Data::Dumper::Indent = 0; + for my $name ( @list ) { + my $val = $conf->$method($name); + ($val) = ref($val) + ? (Data::Dumper::Dumper($val) =~ /= (.*);$/) + : "'$val'"; + printf " %-25s %s\n", $name, $val; + } + + } elsif ( $name eq 'hosts' ) { + print "Setting hosts is not trivial.\n" . + "It is suggested you edit the " . + "configuration file manually"; + + } else { + my $method = 'set_' . $type; + if( $conf->$method($name => defined $value ? $value : '') ) { + my $set_to = defined $value ? $value : 'EMPTY STRING'; + print "Key '$name' was set to '$set_to'\n"; + } + } + } + } else { + print qq[Known options:\n] . + qq[ conf set or get configuration variables\n] . + qq[ debug set or get debugging options\n]; + } + + return; +} + +######################## +### search functions ### +######################## + +sub _author { + my $self = shift; + my $cb = $self->backend; + my %hash = @_; + + my($aref, $short, $input, $class); + my $tmpl = { + result => { store => \$aref, default => ['/./'] }, + short => { default => 0, store => \$short }, + input => { default => 'all', store => \$input }, + class => { default => 'Author', no_override => 1, + store => \$class }, + }; + + check( $tmpl, \%hash ) or return; + + my @regexes = map { m|/(.+)/| ? qr/$1/ : $_ } @$aref; + + + my @rv; + for my $type (qw[author cpanid]) { + push @rv, $cb->search( type => $type, allow => \@regexes ); + } + + unless( @rv ) { + print "No object of type $class found for argument $input\n" + unless $short; + return; + } + + return $self->_pp_author( + result => \@rv, + class => $class, + short => $short, + input => $input ); + +} + +### find all modules matching a query ### +sub _module { + my $self = shift; + my $cb = $self->backend; + my %hash = @_; + + my($aref, $short, $input, $class); + my $tmpl = { + result => { store => \$aref, default => ['/./'] }, + short => { default => 0, store => \$short }, + input => { default => 'all', store => \$input }, + class => { default => 'Module', no_override => 1, + store => \$class }, + }; + + check( $tmpl, \%hash ) or return; + + my @rv; + for my $module (@$aref) { + if( $module =~ m|/(.+)/| ) { + push @rv, $cb->search( type => 'module', + allow => [qr/$1/i] ); + } else { + my $obj = $cb->module_tree( $module ) or next; + push @rv, $obj; + } + } + + return $self->_pp_module( + result => \@rv, + class => $class, + short => $short, + input => $input ); +} + +### find all bundles matching a query ### +sub _bundle { + my $self = shift; + my $cb = $self->backend; + my %hash = @_; + + my($aref, $short, $input, $class); + my $tmpl = { + result => { store => \$aref, default => ['/./'] }, + short => { default => 0, store => \$short }, + input => { default => 'all', store => \$input }, + class => { default => 'Bundle', no_override => 1, + store => \$class }, + }; + + check( $tmpl, \%hash ) or return; + + my @rv; + for my $bundle (@$aref) { + if( $bundle =~ m|/(.+)/| ) { + push @rv, $cb->search( type => 'module', + allow => [qr/Bundle::.*?$1/i] ); + } else { + my $obj = $cb->module_tree( "Bundle::${bundle}" ) or next; + push @rv, $obj; + } + } + + return $self->_pp_module( + result => \@rv, + class => $class, + short => $short, + input => $input ); +} + +sub _distribution { + my $self = shift; + my $cb = $self->backend; + my %hash = @_; + + my($aref, $short, $input, $class); + my $tmpl = { + result => { store => \$aref, default => ['/./'] }, + short => { default => 0, store => \$short }, + input => { default => 'all', store => \$input }, + class => { default => 'Distribution', no_override => 1, + store => \$class }, + }; + + check( $tmpl, \%hash ) or return; + + my @rv; + for my $module (@$aref) { + ### if it's a regex... ### + if ( my ($match) = $module =~ m|^/(.+)/$|) { + + ### something like /FOO/Bar.tar.gz/ was entered + if (my ($path,$package) = $match =~ m|^/?(.+)/(.+)$|) { + my $seen; + + my @data = $cb->search( type => 'package', + allow => [qr/$package/i] ); + + my @list = $cb->search( type => 'path', + allow => [qr/$path/i], + data => \@data ); + + ### make sure we dont list the same dist twice + for my $val ( @list ) { + next if $seen->{$val->package}++; + + push @rv, $val; + } + + ### something like /FOO/ or /Bar.tgz/ was entered + ### so we look both in the path, as well as in the package name + } else { + my $seen; + { my @list = $cb->search( type => 'package', + allow => [qr/$match/i] ); + + ### make sure we dont list the same dist twice + for my $val ( @list ) { + next if $seen->{$val->package}++; + + push @rv, $val; + } + } + + { my @list = $cb->search( type => 'path', + allow => [qr/$match/i] ); + + ### make sure we dont list the same dist twice + for my $val ( @list ) { + next if $seen->{$val->package}++; + + push @rv, $val; + } + + } + } + + } else { + + ### user entered a full dist, like: R/RC/RCAPUTO/POE-0.19.tar.gz + if (my ($path,$package) = $module =~ m|^/?(.+)/(.+)$|) { + my @data = $cb->search( type => 'package', + allow => [qr/^$package$/] ); + my @list = $cb->search( type => 'path', + allow => [qr/$path$/i], + data => \@data); + + ### make sure we dont list the same dist twice + my $seen; + for my $val ( @list ) { + next if $seen->{$val->package}++; + + push @rv, $val; + } + } + } + } + + return $self->_pp_distribution( + result => \@rv, + class => $class, + short => $short, + input => $input ); +} + +sub _find_all { + my $self = shift; + + my @rv; + for my $method (qw[_author _bundle _module _distribution]) { + my $aref = $self->$method( @_, short => 1 ); + + push @rv, @$aref if $aref; + } + + print scalar(@rv). " items found\n" +} + +sub _uptodate { + my $self = shift; + my $cb = $self->backend; + my %hash = @_; + + my($aref, $short, $input, $class); + my $tmpl = { + result => { store => \$aref, default => ['/./'] }, + short => { default => 0, store => \$short }, + input => { default => 'all', store => \$input }, + class => { default => 'Uptodate', no_override => 1, + store => \$class }, + }; + + check( $tmpl, \%hash ) or return; + + + my @rv; + if( @$aref) { + for my $module (@$aref) { + if( $module =~ m|/(.+)/| ) { + my @list = $cb->search( type => 'module', + allow => [qr/$1/i] ); + + ### only add those that are installed and not core + push @rv, grep { not $_->package_is_perl_core } + grep { $_->installed_file } + @list; + + } else { + my $obj = $cb->module_tree( $module ) or next; + push @rv, $obj; + } + } + } else { + @rv = @{$cb->_all_installed}; + } + + return $self->_pp_uptodate( + result => \@rv, + class => $class, + short => $short, + input => $input ); +} + +sub _ls { + my $self = shift; + my $cb = $self->backend; + my %hash = @_; + + my($aref, $short, $input, $class); + my $tmpl = { + result => { store => \$aref, default => [] }, + short => { default => 0, store => \$short }, + input => { default => 'all', store => \$input }, + class => { default => 'Uptodate', no_override => 1, + store => \$class }, + }; + + check( $tmpl, \%hash ) or return; + + my @rv; + for my $name (@$aref) { + my $auth = $cb->author_tree( uc $name ); + + unless( $auth ) { + print qq[ls command rejects argument $name: not an author\n]; + next; + } + + push @rv, $auth->distributions; + } + + return $self->_pp_ls( + result => \@rv, + class => $class, + short => $short, + input => $input ); +} + +############################ +### pretty printing subs ### +############################ + + +sub _pp_author { + my $self = shift; + my %hash = @_; + + my( $aref, $short, $class, $input ); + my $tmpl = { + result => { required => 1, default => [], strict_type => 1, + store => \$aref }, + short => { default => 0, store => \$short }, + class => { required => 1, store => \$class }, + input => { required => 1, store => \$input }, + }; + + check( $tmpl, \%hash ) or return; + + ### no results + if( !@$aref ) { + print "No objects of type $class found for argument $input\n" + unless $short; + + ### one result, long output desired; + } elsif( @$aref == 1 and !$short ) { + + ### should look like this: + #cpan> a KANE + #Author id = KANE + # EMAIL boumans@frg.eur.nl + # FULLNAME Jos Boumans + + my $obj = shift @$aref; + + print "$class id = ", $obj->cpanid(), "\n"; + printf " %-12s %s\n", 'EMAIL', $obj->email(); + printf " %-12s %s%s\n", 'FULLNAME', $obj->author(); + + } else { + + ### should look like this: + #Author KANE (Jos Boumans) + #Author LBROCARD (Leon Brocard) + #2 items found + + for my $obj ( @$aref ) { + printf qq[%-15s %s ("%s" (%s))\n], + $class, $obj->cpanid, $obj->author, $obj->email; + } + print scalar(@$aref)." items found\n" unless $short; + } + + return $aref; +} + +sub _pp_module { + my $self = shift; + my %hash = @_; + + my( $aref, $short, $class, $input ); + my $tmpl = { + result => { required => 1, default => [], strict_type => 1, + store => \$aref }, + short => { default => 0, store => \$short }, + class => { required => 1, store => \$class }, + input => { required => 1, store => \$input }, + }; + + check( $tmpl, \%hash ) or return; + + + ### no results + if( !@$aref ) { + print "No objects of type $class found for argument $input\n" + unless $short; + + ### one result, long output desired; + } elsif( @$aref == 1 and !$short ) { + + + ### should look like this: + #Module id = LWP + # DESCRIPTION Libwww-perl + # CPAN_USERID GAAS (Gisle Aas <gisle@ActiveState.com>) + # CPAN_VERSION 5.64 + # CPAN_FILE G/GA/GAAS/libwww-perl-5.64.tar.gz + # DSLI_STATUS RmpO (released,mailing-list,perl,object-oriented) + # MANPAGE LWP - The World-Wide Web library for Perl + # INST_FILE C:\Perl\site\lib\LWP.pm + # INST_VERSION 5.62 + + my $obj = shift @$aref; + my $aut_obj = $obj->author; + my $format = " %-12s %s%s\n"; + + print "$class id = ", $obj->module(), "\n"; + printf $format, 'DESCRIPTION', $obj->description() + if $obj->description(); + + printf $format, 'CPAN_USERID', $aut_obj->cpanid() . " (" . + $aut_obj->author() . " <" . $aut_obj->email() . ">)"; + + printf $format, 'CPAN_VERSION', $obj->version(); + printf $format, 'CPAN_FILE', $obj->path() . '/' . $obj->package(); + + printf $format, 'DSLI_STATUS', $self->_pp_dslip($obj->dslip) + if $obj->dslip() =~ /\w/; + + #printf $format, 'MANPAGE', $obj->foo(); + ### this is for bundles... CPAN.pm downloads them, + #printf $format, 'CONATAINS, + # parses and goes from there... + + printf $format, 'INST_FILE', $obj->installed_file || + '(not installed)'; + printf $format, 'INST_VERSION', $obj->installed_version; + + + + } else { + + ### should look like this: + #Module LWP (G/GA/GAAS/libwww-perl-5.64.tar.gz) + #Module POE (R/RC/RCAPUTO/POE-0.19.tar.gz) + #2 items found + + for my $obj ( @$aref ) { + printf "%-15s %-15s (%s)\n", $class, $obj->module(), + $obj->path() .'/'. $obj->package(); + } + print scalar(@$aref). " items found\n" unless $short; + } + + return $aref; +} + +sub _pp_dslip { + my $self = shift; + my $dslip = shift or return; + + my (%_statusD, %_statusS, %_statusL, %_statusI); + + @_statusD{qw(? i c a b R M S)} = + qw(unknown idea pre-alpha alpha beta released mature standard); + + @_statusS{qw(? m d u n)} = + qw(unknown mailing-list developer comp.lang.perl.* none); + + @_statusL{qw(? p c + o h)} = qw(unknown perl C C++ other hybrid); + @_statusI{qw(? f r O h)} = + qw(unknown functions references+ties object-oriented hybrid); + + my @status = split("", $dslip); + + my $results = sprintf( "%s (%s,%s,%s,%s)", + $dslip, + $_statusD{$status[0]}, + $_statusS{$status[1]}, + $_statusL{$status[2]}, + $_statusI{$status[3]} + ); + + return $results; +} + +sub _pp_distribution { + my $self = shift; + my $cb = $self->backend; + my %hash = @_; + + my( $aref, $short, $class, $input ); + my $tmpl = { + result => { required => 1, default => [], strict_type => 1, + store => \$aref }, + short => { default => 0, store => \$short }, + class => { required => 1, store => \$class }, + input => { required => 1, store => \$input }, + }; + + check( $tmpl, \%hash ) or return; + + + ### no results + if( !@$aref ) { + print "No objects of type $class found for argument $input\n" + unless $short; + + ### one result, long output desired; + } elsif( @$aref == 1 and !$short ) { + + + ### should look like this: + #Distribution id = S/SA/SABECK/POE-Component-Client-POP3-0.02.tar.gz + # CPAN_USERID SABECK (Scott Beck <scott@gossamer-threads.com>) + # CONTAINSMODS POE::Component::Client::POP3 + + my $obj = shift @$aref; + my $aut_obj = $obj->author; + my $pkg = $obj->package; + my $format = " %-12s %s\n"; + + my @list = $cb->search( type => 'package', + allow => [qr/^$pkg$/] ); + + + print "$class id = ", $obj->path(), '/', $obj->package(), "\n"; + printf $format, 'CPAN_USERID', + $aut_obj->cpanid .' ('. $aut_obj->author . + ' '. $aut_obj->email .')'; + + ### yes i know it's ugly, but it's what cpan.pm does + printf $format, 'CONTAINSMODS', join (' ', map { $_->module } @list); + + } else { + + ### should look like this: + #Distribution LWP (G/GA/GAAS/libwww-perl-5.64.tar.gz) + #Distribution POE (R/RC/RCAPUTO/POE-0.19.tar.gz) + #2 items found + + for my $obj ( @$aref ) { + printf "%-15s %s\n", $class, $obj->path() .'/'. $obj->package(); + } + + print scalar(@$aref). " items found\n" unless $short; + } + + return $aref; +} + +sub _pp_uptodate { + my $self = shift; + my $cb = $self->backend; + my %hash = @_; + + my( $aref, $short, $class, $input ); + my $tmpl = { + result => { required => 1, default => [], strict_type => 1, + store => \$aref }, + short => { default => 0, store => \$short }, + class => { required => 1, store => \$class }, + input => { required => 1, store => \$input }, + }; + + check( $tmpl, \%hash ) or return; + + my $format = "%-25s %9s %9s %s\n"; + + my @not_uptodate; + my $no_version; + + my %seen; + for my $mod (@$aref) { + next if $mod->package_is_perl_core; + next if $seen{ $mod->package }++; + + + if( $mod->installed_file and not $mod->installed_version ) { + $no_version++; + next; + } + + push @not_uptodate, $mod unless $mod->is_uptodate; + } + + unless( @not_uptodate ) { + my $string = $input + ? "for $input" + : ''; + print "All modules are up to date $string\n"; + return; + + } else { + printf $format, ( 'Package namespace', + 'installed', + 'latest', + 'in CPAN file' + ); + } + + for my $mod ( sort { $a->module cmp $b->module } @not_uptodate ) { + printf $format, ( $mod->module, + $mod->installed_version, + $mod->version, + $mod->path .'/'. $mod->package, + ); + } + + print "$no_version installed modules have no (parsable) version number\n" + if $no_version; + + return \@not_uptodate; +} + +sub _pp_ls { + my $self = shift; + my $cb = $self->backend; + my %hash = @_; + + my( $aref, $short, $class, $input ); + my $tmpl = { + result => { required => 1, default => [], strict_type => 1, + store => \$aref }, + short => { default => 0, store => \$short }, + class => { required => 1, store => \$class }, + input => { required => 1, store => \$input }, + }; + + check( $tmpl, \%hash ) or return; + + ### should look something like this: + #6272 2002-05-12 KANE/Acme-Comment-1.00.tar.gz + #8171 2002-08-13 KANE/Acme-Comment-1.01.zip + #7110 2002-09-04 KANE/Acme-Comment-1.02.tar.gz + #7571 2002-09-08 KANE/Acme-Intraweb-1.01.tar.gz + #6625 2001-08-23 KANE/Acme-POE-Knee-1.10.zip + #3058 2003-10-05 KANE/Acme-Test-0.02.tar.gz + + ### don't know size or mtime + #my $format = "%8d %10s %s/%s\n"; + + for my $mod ( sort { $a->package cmp $b->package } @$aref ) { + print "\t" . $mod->package . "\n"; + } + + return $aref; +} + + +############################# +### end pretty print subs ### +############################# + + +sub _bang { + my $self = shift; + my %hash = @_; + + my( $input ); + my $tmpl = { + input => { required => 1, store => \$input }, + }; + + check( $tmpl, \%hash ) or return; + + eval $input; + warn $@ if $@; + + print "\n"; + + return; +} + +sub _help { + print qq[ +Display Information + a authors + b string display bundles + d or info distributions + m /regex/ about modules + i or anything of above + r none reinstall recommendations + u uninstalled distributions + +Download, Test, Make, Install... + get download + make make (implies get) + test modules, make test (implies make) + install dists, bundles make install (implies test) + clean make clean + look open subshell in these dists' directories + readme display these dists' README files + +Other + h,? display this menu ! perl-code eval a perl command + o conf [opt] set and query options q quit the cpan shell + reload cpan load CPAN.pm again reload index load newer indices + autobundle Snapshot force cmd unconditionally do cmd +]; + +} + + + +1; +__END__ + +=pod + +=head1 NAME + +CPANPLUS::Shell::Classic - CPAN.pm emulation for CPANPLUS + +=head1 DESCRIPTION + +The Classic shell is designed to provide the feel of the CPAN.pm shell +using CPANPLUS underneath. + +For detailed documentation, refer to L<CPAN>. + +=head1 BUG REPORTS + +Please report bugs or other issues to E<lt>bug-cpanplus@rt.cpan.org<gt>. + +=head1 AUTHOR + +This module by Jos Boumans E<lt>kane@cpan.orgE<gt>. + +=head1 COPYRIGHT + +The CPAN++ interface (of which this module is a part of) is copyright (c) +2001 - 2007, Jos Boumans E<lt>kane@cpan.orgE<gt>. All rights reserved. + +This library is free software; you may redistribute and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L<CPANPLUS::Configure>, L<CPANPLUS::Module>, L<CPANPLUS::Module::Author> + +=cut + + +=head1 SEE ALSO + +L<CPAN> + +=cut + + + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Shell/Default.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Shell/Default.pm new file mode 100644 index 00000000000..a9d51422f66 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Shell/Default.pm @@ -0,0 +1,1938 @@ +package CPANPLUS::Shell::Default; + +use strict; + + +use CPANPLUS::Error; +use CPANPLUS::Backend; +use CPANPLUS::Configure::Setup; +use CPANPLUS::Internals::Constants; +use CPANPLUS::Internals::Constants::Report qw[GRADE_FAIL]; + +use Cwd; +use IPC::Cmd; +use Term::UI; +use Data::Dumper; +use Term::ReadLine; + +use Module::Load qw[load]; +use Params::Check qw[check]; +use Module::Load::Conditional qw[can_load check_install]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +local $Params::Check::VERBOSE = 1; +local $Data::Dumper::Indent = 1; # for dumpering from ! + +BEGIN { + use vars qw[ $VERSION @ISA ]; + @ISA = qw[ CPANPLUS::Shell::_Base::ReadLine ]; + $VERSION = "0.90"; +} + +load CPANPLUS::Shell; + + +my $map = { + 'm' => '_search_module', + 'a' => '_search_author', + '!' => '_bang', + '?' => '_help', + 'h' => '_help', + 'q' => '_quit', + 'r' => '_readme', + 'v' => '_show_banner', + 'w' => '__display_results', + 'd' => '_fetch', + 'z' => '_shell', + 'f' => '_distributions', + 'x' => '_reload_indices', + 'i' => '_install', + 't' => '_install', + 'l' => '_details', + 'p' => '_print', + 's' => '_set_conf', + 'o' => '_uptodate', + 'b' => '_autobundle', + 'u' => '_uninstall', + '/' => '_meta', # undocumented for now + 'c' => '_reports', +}; +### free letters: e g j k n y ### + + +### will be filled if you have a .default-shell.rc and +### Config::Auto installed +my $rc = {}; + +### the shell object, scoped to the file ### +my $Shell; +my $Brand = loc('CPAN Terminal'); +my $Prompt = $Brand . '> '; + +=pod + +=head1 NAME + +CPANPLUS::Shell::Default + +=head1 SYNOPSIS + + ### loading the shell: + $ cpanp # run 'cpanp' from the command line + $ perl -MCPANPLUS -eshell # load the shell from the command line + + + use CPANPLUS::Shell qw[Default]; # load this shell via the API + # always done via CPANPLUS::Shell + + my $ui = CPANPLUS::Shell->new; + $ui->shell; # run the shell + $ui->dispatch_on_input( input => 'x'); # update the source using the + # dispatch method + + ### when in the shell: + ### Note that all commands can also take options. + ### Look at their underlying CPANPLUS::Backend methods to see + ### what options those are. + cpanp> h # show help messages + cpanp> ? # show help messages + + cpanp> m Acme # find acme modules, allows regexes + cpanp> a KANE # find modules by kane, allows regexes + cpanp> f Acme::Foo # get a list of all releases of Acme::Foo + + cpanp> i Acme::Foo # install Acme::Foo + cpanp> i Acme-Foo-1.3 # install version 1.3 of Acme::Foo + cpanp> i <URI> # install from URI, like ftp://foo.com/X.tgz + cpanp> i <DIR> # install from an absolute or relative directory + cpanp> i 1 3..5 # install search results 1, 3, 4 and 5 + cpanp> i * # install all search results + cpanp> a KANE; i *; # find modules by kane, install all results + cpanp> t Acme::Foo # test Acme::Foo, without installing it + cpanp> u Acme::Foo # uninstall Acme::Foo + cpanp> d Acme::Foo # download Acme::Foo + cpanp> z Acme::Foo # download & extract Acme::Foo, then open a + # shell in the extraction directory + + cpanp> c Acme::Foo # get a list of test results for Acme::Foo + cpanp> l Acme::Foo # view details about the Acme::Foo package + cpanp> r Acme::Foo # view Acme::Foo's README file + cpanp> o # get a list of all installed modules that + # are out of date + cpanp> o 1..3 # list uptodateness from a previous search + + cpanp> s conf # show config settings + cpanp> s conf md5 1 # enable md5 checks + cpanp> s program # show program settings + cpanp> s edit # edit config file + cpanp> s reconfigure # go through initial configuration again + cpanp> s selfupdate # update your CPANPLUS install + cpanp> s save # save config to disk + cpanp> s mirrors # show currently selected mirrors + + cpanp> ! [PERL CODE] # execute the following perl code + + cpanp> b # create an autobundle for this computers + # perl installation + cpanp> x # reload index files (purges cache) + cpanp> x --update_source # reload index files, get fresh source files + cpanp> p [FILE] # print error stack (to a file) + cpanp> v # show the banner + cpanp> w # show last search results again + + cpanp> q # quit the shell + + cpanp> /plugins # list avialable plugins + cpanp> /? PLUGIN # list help test of <PLUGIN> + + ### common options: + cpanp> i ... --skiptest # skip tests + cpanp> i ... --force # force all operations + cpanp> i ... --verbose # run in verbose mode + +=head1 DESCRIPTION + +This module provides the default user interface to C<CPANPLUS>. You +can start it via the C<cpanp> binary, or as detailed in the L<SYNOPSIS>. + +=cut + +sub new { + my $class = shift; + + my $cb = CPANPLUS::Backend->new( @_ ); + my $self = $class->SUPER::_init( + brand => $Brand, + term => Term::ReadLine->new( $Brand ), + prompt => $Prompt, + backend => $cb, + format => "%4s %-55s %8s %-10s\n", + dist_format => "%4s %-42s %-12s %8s %-10s\n", + ); + ### make it available package wide ### + $Shell = $self; + + my $rc_file = File::Spec->catfile( + $cb->configure_object->get_conf('base'), + DOT_SHELL_DEFAULT_RC, + ); + + + if( -e $rc_file && -r _ ) { + $rc = $self->_read_configuration_from_rc( $rc_file ); + } + + ### register install callback ### + $cb->_register_callback( + name => 'install_prerequisite', + code => \&__ask_about_install, + ); + + ### execute any login commands specified ### + $self->dispatch_on_input( input => $rc->{'login'} ) + if defined $rc->{'login'}; + + ### register test report callbacks ### + $cb->_register_callback( + name => 'edit_test_report', + code => \&__ask_about_edit_test_report, + ); + + $cb->_register_callback( + name => 'send_test_report', + code => \&__ask_about_send_test_report, + ); + + $cb->_register_callback( + name => 'proceed_on_test_failure', + code => \&__ask_about_test_failure, + ); + + ### load all the plugins + $self->_plugins_init; + + return $self; +} + +sub shell { + my $self = shift; + my $term = $self->term; + my $conf = $self->backend->configure_object; + + $self->_show_banner; + $self->__print( "*** Type 'p' now to show start up log\n" ); # XXX add to banner? + $self->_show_random_tip if $conf->get_conf('show_startup_tip'); + $self->_input_loop && $self->__print( "\n" ); + $self->_quit; +} + +sub _input_loop { + my $self = shift; + my $term = $self->term; + my $cb = $self->backend; + + my $normal_quit = 0; + while ( + defined (my $input = eval { $term->readline($self->prompt) } ) + or $self->_signals->{INT}{count} == 1 + ) { + ### re-initiate all signal handlers + while (my ($sig, $entry) = each %{$self->_signals} ) { + $SIG{$sig} = $entry->{handler} if exists($entry->{handler}); + } + + $self->__print( "\n" ); + last if $self->dispatch_on_input( input => $input ); + + ### flush the lib cache ### + $cb->_flush( list => [qw|lib load|] ); + + } continue { + ### clear the sigint count + $self->_signals->{INT}{count}-- + if $self->_signals->{INT}{count}; + + ### reset the 'install prereq?' cached answer + $self->settings->{'install_all_prereqs'} = undef; + + } + + return 1; +} + +### return 1 to quit ### +sub dispatch_on_input { + my $self = shift; + my $conf = $self->backend->configure_object(); + my $term = $self->term; + my %hash = @_; + + my($string, $noninteractive); + my $tmpl = { + input => { required => 1, store => \$string }, + noninteractive => { required => 0, store => \$noninteractive }, + }; + + check( $tmpl, \%hash ) or return; + + ### indicates whether or not the user will receive a shell + ### prompt after the command has finished. + $self->noninteractive($noninteractive) if defined $noninteractive; + + my $rv = 1; + + my @cmds = split ';', $string; + while( my $input = shift @cmds ) { + + ### to send over the socket ### + my $org_input = $input; + + my $key; my $options; + { ### make whitespace not count when using special chars + { $input =~ s|^\s*([!?/])|$1 |; } + + ### get the first letter of the input + $input =~ s|^\s*([\w\?\!/])\w*||; + + chomp $input; + $key = lc($1); + + ### we figured out what the command was... + ### if we have more input, that DOES NOT start with a white + ### space char, we misparsed.. like 'Test::Foo::Bar', which + ### would turn into 't', '::Foo::Bar'... + if( $input and $input !~ s/^\s+// ) { + $self->__print( loc("Could not understand command: %1\n". + "Possibly missing command before argument(s)?\n", + $org_input) ); + return; + } + + ### allow overrides from the config file ### + if( defined $rc->{$key} ) { + $input = $rc->{$key} . $input; + } + + ### grab command line options like --no-force and --verbose ### + ($options,$input) = $term->parse_options($input) + unless $key eq '!'; + } + + ### emtpy line? ### + return unless $key; + + ### time to quit ### + return 1 if $key eq 'q'; + + my $method = $map->{$key}; + + ### dispatch meta locally at all times ### + if( $key eq '/' ) { + ### keep track of failures + $rv *= length $self->$method(input => $input, options => $options); + next; + } + + ### flush unless we're trying to print the stack + CPANPLUS::Error->flush unless $key eq 'p'; + + ### connected over a socket? ### + if( $self->remote ) { + + ### unsupported commands ### + if( $key eq 'z' or + ($key eq 's' and $input =~ /^\s*edit/) + ) { + $self->__print( "\n", + loc( "Command '%1' not supported over remote connection", + join ' ', $key, $input + ), "\n\n" ); + + } else { + my($status,$buff) = $self->__send_remote_command($org_input); + + $self->__print( "\n", loc("Command failed!"), "\n\n" ) + unless $status; + + ### keep track of failures + $rv *= length $status; + + $self->_pager_open if $buff =~ tr/\n// > $self->_term_rowcount; + $self->__print( $buff ); + $self->_pager_close; + } + + ### or just a plain local shell? ### + } else { + + unless( $self->can($method) ) { + $self->__print(loc("Unknown command '%1'. Usage:", $key), "\n"); + $self->_help; + + } else { + + ### some methods don't need modules ### + my @mods; + @mods = $self->_select_modules($input) + unless grep {$key eq $_} qw[! m a v w x p s b / ? h]; + + ### keep track of failures + $rv *= defined eval { $self->$method( + modules => \@mods, + options => $options, + input => $input, + choice => $key ) + }; + error( $@ ) if $@; + } + } + } + + ### outside the shell loop, we can return the actual return value; + return $rv if $self->noninteractive; + + return; +} + +sub _select_modules { + my $self = shift; + my $input = shift or return; + my $cache = $self->cache; + my $cb = $self->backend; + + ### expand .. in $input + $input =~ s{\b(\d+)\s*\.\.\s*(\d+)\b} + {join(' ', ($1 < 1 ? 1 : $1) .. ($2 > $#{$cache} ? $#{$cache} : $2))}eg; + + $input = join(' ', 1 .. $#{$cache}) if $input eq '*'; + $input =~ s/'/::/g; # perl 4 convention + + my @rv; + for my $mod (split /\s+/, $input) { + + ### it's a cache look up ### + if( $mod =~ /^\d+/ and $mod > 0 ) { + unless( scalar @$cache ) { + $self->__print( loc("No search was done yet!"), "\n" ); + + } elsif ( my $obj = $cache->[$mod] ) { + push @rv, $obj; + + } else { + $self->__print( loc("No such module: %1", $mod), "\n" ); + } + + } else { + my $obj = $cb->parse_module( module => $mod ); + + unless( $obj ) { + $self->__print( loc("No such module: %1", $mod), "\n" ); + + } else { + push @rv, $obj; + } + } + } + + unless( scalar @rv ) { + $self->__print( loc("No modules found to operate on!\n") ); + return; + } else { + return @rv; + } +} + +sub _format_version { + my $self = shift; + my $version = shift || 0; + + ### fudge $version into the 'optimal' format + $version = 0 if $version eq 'undef'; + $version =~ s/_//g; # everything after gets stripped off otherwise + + ### allow 6 digits after the dot, as that's how perl stringifies + ### x.y.z numbers. + $version = sprintf('%3.6f', $version); + $version = '' if $version == '0.00'; + $version =~ s/(00{0,3})$/' ' x (length $1)/e; + + return $version; +} + +sub __display_results { + my $self = shift; + my $cache = $self->cache; + + my @rv = @$cache; + + if( scalar @rv ) { + + $self->_pager_open if $#{$cache} >= $self->_term_rowcount; + + my $i = 1; + for my $mod (@rv) { + next unless $mod; # first one is undef + # humans start counting at 1 + + ### for dists only -- we have checksum info + if( $mod->mtime ) { + $self->__printf( + $self->dist_format, + $i, + $mod->module, + $mod->mtime, + $self->_format_version( $mod->version ), + $mod->author->cpanid + ); + + } else { + $self->__printf( + $self->format, + $i, + $mod->module, + $self->_format_version( $mod->version ), + $mod->author->cpanid + ); + } + $i++; + } + + $self->_pager_close; + + } else { + $self->__print( loc("No results to display"), "\n" ); + } + + return 1; +} + + +sub _quit { + my $self = shift; + + $self->dispatch_on_input( input => $rc->{'logout'} ) + if defined $rc->{'logout'}; + + $self->__print( loc("Exiting CPANPLUS shell"), "\n" ); + + return 1; +} + +########################### +### actual command subs ### +########################### + + +### print out the help message ### +### perhaps, '?' should be a slightly different version ### +{ my @help; + sub _help { + my $self = shift; + my %hash = @_; + + my $input; + { local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + input => { required => 0, store => \$input } + }; + + my $args = check( $tmpl, \%hash ) or return; + } + + @help = ( +loc('[General]' ), +loc(' h | ? # display help' ), +loc(' q # exit' ), +loc(' v # version information' ), +loc('[Search]' ), +loc(' a AUTHOR ... # search by author(s)' ), +loc(' m MODULE ... # search by module(s)' ), +loc(' f MODULE ... # list all releases of a module' ), +loc(" o [ MODULE ... ] # list installed module(s) that aren't up to date" ), +loc(' w # display the result of your last search again' ), +loc('[Operations]' ), +loc(' i MODULE | NUMBER ... # install module(s), by name or by search number' ), +loc(' i URI | ... # install module(s), by URI (ie http://foo.com/X.tgz)' ), +loc(' i DIR | ... # install module(s), by path (ie ./Module-1.0)' ), +loc(' t MODULE | NUMBER ... # test module(s), by name or by search number' ), +loc(' u MODULE | NUMBER ... # uninstall module(s), by name or by search number' ), +loc(' d MODULE | NUMBER ... # download module(s)' ), +loc(' l MODULE | NUMBER ... # display detailed information about module(s)' ), +loc(' r MODULE | NUMBER ... # display README files of module(s)' ), +loc(' c MODULE | NUMBER ... # check for module report(s) from cpan-testers' ), +loc(' z MODULE | NUMBER ... # extract module(s) and open command prompt in it' ), +loc('[Local Administration]' ), +loc(' b # write a bundle file for your configuration' ), +loc(' s program [OPT VALUE] # set program locations for this session' ), +loc(' s conf [OPT VALUE] # set config options for this session' ), +loc(' s mirrors # show currently selected mirrors' ), +loc(' s reconfigure # reconfigure settings ' ), +loc(' s selfupdate # update your CPANPLUS install '), +loc(' s save [user|system] # save settings for this user or systemwide' ), +loc(' s edit [user|system] # open configuration file in editor and reload' ), +loc(' ! EXPR # evaluate a perl statement' ), +loc(' p [FILE] # print the error stack (optionally to a file)' ), +loc(' x # reload CPAN indices (purges cache)' ), +loc(' x --update_source # reload CPAN indices, get fresh source files' ), +loc('[Common Options]' ), +loc(' i ... --skiptest # skip tests' ), +loc(' i ... --force # force all operations' ), +loc(' i ... --verbose # run in verbose mode' ), +loc('[Plugins]' ), +loc(' /plugins # list available plugins' ), +loc(' /? [PLUGIN NAME] # show usage for (a particular) plugin(s)' ), + + ) unless @help; + + $self->_pager_open if (@help >= $self->_term_rowcount); + ### XXX: functional placeholder for actual 'detailed' help. + $self->__print( "Detailed help for the command '$input' is " . + "not available.\n\n" ) if length $input; + $self->__print( map {"$_\n"} @help ); + $self->__print( $/ ); + $self->_pager_close; + + return 1; + } +} + +### eval some code ### +sub _bang { + my $self = shift; + my $cb = $self->backend; + my %hash = @_; + + + my $input; + { local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + input => { required => 1, store => \$input } + }; + + my $args = check( $tmpl, \%hash ) or return; + } + + local $Data::Dumper::Indent = 1; # for dumpering from ! + eval $input; + error( $@ ) if $@; + $self->__print( "\n" ); + + return if $@; + return 1; +} + +sub _search_module { + my $self = shift; + my $cb = $self->backend; + my %hash = @_; + + my $args; + { local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + input => { required => 1, }, + options => { default => { } }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + my @regexes = map { qr/$_/i } split /\s+/, $args->{'input'}; + + ### XXX this is rather slow, because (probably) + ### of the many method calls + ### XXX need to profile to speed it up =/ + + ### find the modules ### + my @rv = sort { $a->module cmp $b->module } + $cb->search( + %{$args->{'options'}}, + type => 'module', + allow => \@regexes, + ); + + ### store the result in the cache ### + $self->cache([undef,@rv]); + + $self->__display_results; + + return 1; +} + +sub _search_author { + my $self = shift; + my $cb = $self->backend; + my %hash = @_; + + my $args; + { local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + input => { required => 1, }, + options => { default => { } }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + my @regexes = map { qr/$_/i } split /\s+/, $args->{'input'}; + + my @rv; + for my $type (qw[author cpanid]) { + push @rv, $cb->search( + %{$args->{'options'}}, + type => $type, + allow => \@regexes, + ); + } + + my %seen; + my @list = sort { $a->module cmp $b->module } + grep { defined } + map { $_->modules } + grep { not $seen{$_}++ } @rv; + + $self->cache([undef,@list]); + + $self->__display_results; + return 1; +} + +sub _readme { + my $self = shift; + my $cb = $self->backend; + my %hash = @_; + + my $args; my $mods; my $opts; + { local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + modules => { required => 1, store => \$mods }, + options => { default => { }, store => \$opts }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + return unless scalar @$mods; + + $self->_pager_open; + for my $mod ( @$mods ) { + $self->__print( $mod->readme( %$opts ) ); + } + + $self->_pager_close; + + return 1; +} + +sub _fetch { + my $self = shift; + my $cb = $self->backend; + my %hash = @_; + + my $args; my $mods; my $opts; + { local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + modules => { required => 1, store => \$mods }, + options => { default => { }, store => \$opts }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + $self->_pager_open if @$mods >= $self->_term_rowcount; + my $rv = 1; + for my $mod (@$mods) { + my $where = $mod->fetch( %$opts ); + + $rv *= length $where; + + $self->__print( + $where + ? loc("Successfully fetched '%1' to '%2'", + $mod->module, $where ) + : loc("Failed to fetch '%1'", $mod->module) + ); + $self->__print( "\n" ); + } + $self->_pager_close; + + return 1 if $rv; + return; +} + +sub _shell { + my $self = shift; + my $cb = $self->backend; + my $conf = $cb->configure_object; + my %hash = @_; + + my $shell = $conf->get_program('shell'); + unless( $shell ) { + $self->__print( + loc("Your config does not specify a subshell!"), "\n", + loc("Perhaps you need to re-run your setup?"), "\n" + ); + return; + } + + my $args; my $mods; my $opts; + { local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + modules => { required => 1, store => \$mods }, + options => { default => { }, store => \$opts }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + my $cwd = Cwd::cwd(); + for my $mod (@$mods) { + $mod->fetch( %$opts ) or next; + $mod->extract( %$opts ) or next; + + $cb->_chdir( dir => $mod->status->extract() ) or next; + + #local $ENV{PERL5OPT} = CPANPLUS::inc->original_perl5opt; + + if( system($shell) and $! ) { + $self->__print( + loc("Error executing your subshell '%1': %2", + $shell, $!),"\n" + ); + next; + } + } + $cb->_chdir( dir => $cwd ); + + return 1; +} + +sub _distributions { + my $self = shift; + my $cb = $self->backend; + my $conf = $cb->configure_object; + my %hash = @_; + + my $args; my $mods; my $opts; + { local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + modules => { required => 1, store => \$mods }, + options => { default => { }, store => \$opts }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + my @list; + for my $mod (@$mods) { + push @list, sort { $a->version <=> $b->version } + grep { defined } $mod->distributions( %$opts ); + } + + my @rv = sort { $a->module cmp $b->module } @list; + + $self->cache([undef,@rv]); + $self->__display_results; + + return 1; +} + +sub _reload_indices { + my $self = shift; + my $cb = $self->backend; + my %hash = @_; + + my $args; my $opts; + { local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + options => { default => { }, store => \$opts }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + my $rv = $cb->reload_indices( %$opts ); + + ### so the update failed, but you didnt give it any options either + if( !$rv and !(keys %$opts) ) { + $self->__print( + "\nFailure may be due to corrupt source files\n" . + "Try this:\n\tx --update_source\n\n" ); + } + + return $rv; + +} + +sub _install { + my $self = shift; + my $cb = $self->backend; + my $conf = $cb->configure_object; + my %hash = @_; + + my $args; my $mods; my $opts; my $choice; + { local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + modules => { required => 1, store => \$mods }, + options => { default => { }, store => \$opts }, + choice => { required => 1, store => \$choice, + allow => [qw|i t|] }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + unless( scalar @$mods ) { + $self->__print( loc("Nothing done\n") ); + return; + } + + my $target = $choice eq 'i' ? TARGET_INSTALL : TARGET_CREATE; + my $prompt = $choice eq 'i' ? loc('Installing ') : loc('Testing '); + my $action = $choice eq 'i' ? 'install' : 'test'; + + my $status = {}; + ### first loop over the mods to install them ### + for my $mod (@$mods) { + $self->__print( $prompt, $mod->module, " (".$mod->version.")", "\n" ); + + my $log_length = length CPANPLUS::Error->stack_as_string; + + ### store the status for look up when we're done with all + ### install calls + $status->{$mod} = $mod->install( %$opts, target => $target ); + + ### would you like a log file of what happened? + if( $conf->get_conf('write_install_logs') ) { + + if ( ON_WIN32 and !check_install( + module => 'IPC::Run', version => 0.55 ) + ) { + error(loc("IPC::Run version '%1' is required on MSWin32" + . " in order to capture buffers." + . " The logfile generated may not contain" + . " any useful data, until it is installed", 0.55)); + } + + my $dir = File::Spec->catdir( + $conf->get_conf('base'), + $conf->_get_build('install_log_dir'), + ); + ### create the dir if it doesn't exit yet + $cb->_mkdir( dir => $dir ) unless -d $dir; + + my $file = File::Spec->catfile( + $dir, + INSTALL_LOG_FILE->( $mod ) + ); + if ( open my $fh, ">$file" ) { + my $stack = CPANPLUS::Error->stack_as_string; + ### remove everything in the log that was there *before* + ### we started this install + substr( $stack, 0, $log_length, '' ); + + print $fh $stack; + close $fh; + + $self->__print( + loc("*** Install log written to:\n %1\n\n", $file) + ); + } else { + warn "Could not open '$file': $!\n"; + next; + } + } + } + + my $flag; + ### then report whether all this went ok or not ### + for my $mod (@$mods) { + # if( $mod->status->installed ) { + if( $status->{$mod} ) { + $self->__print( + loc("Module '%1' %tense(%2,past) successfully\n", + $mod->module, $action) + ); + } else { + $flag++; + $self->__print( + loc("Error %tense(%1,present) '%2'\n", $action, $mod->module) + ); + } + } + + + + if( !$flag ) { + $self->__print( + loc("No errors %tense(%1,present) all modules", $action), "\n" + ); + } else { + $self->__print( + loc("Problem %tense(%1,present) one or more modules", $action) + ); + $self->__print( "\n" ); + + $self->__print( + loc("*** You can view the complete error buffer by pressing ". + "'%1' ***\n", 'p') + ) unless $conf->get_conf('verbose') || $self->noninteractive; + } + $self->__print( "\n" ); + + return !$flag; +} + +sub __ask_about_install { + my $mod = shift or return; + my $prereq = shift or return; + my $term = $Shell->term; + + $Shell->__print( "\n" ); + $Shell->__print( loc("Module '%1' requires '%2' to be installed", + $mod->module, $prereq->module ) ); + $Shell->__print( "\n\n" ); + + ### previously cached answer? + return $Shell->settings->{'install_all_prereqs'} + if defined $Shell->settings->{'install_all_prereqs'}; + + + $Shell->__print( + loc( "If you don't wish to see this question anymore\n". + "you can disable it by entering the following ". + "commands on the prompt:\n '%1'", + 's conf prereqs 1; s save' ) ); + $Shell->__print("\n\n"); + + my $yes = loc("Yes"); + my $no = loc("No"); + my $all = loc("Yes to all (for this module)"); + my $none = loc("No to all (for this module)"); + + my $reply = $term->get_reply( + prompt => loc("Should I install this module?"), + choices => [ $yes, $no, $all, $none ], + default => $yes, + ); + + ### if 'all' or 'none', save this, so we can apply it to + ### other prereqs in this chain. + $Shell->settings->{'install_all_prereqs'} = + $reply eq $all ? 1 : + $reply eq $none ? 0 : + undef; + + ### if 'yes' or 'all', the user wants it installed + return $reply eq $all ? 1 : + $reply eq $yes ? 1 : + 0; +} + +sub __ask_about_send_test_report { + my($mod, $grade) = @_; + return 1 unless $grade eq GRADE_FAIL; + + my $term = $Shell->term; + + $Shell->__print( "\n" ); + $Shell->__print( + loc("Test report prepared for module '%1'.\n Would you like to ". + "send it? (You can edit it if you like)", $mod->module ) ); + $Shell->__print( "\n\n" ); + my $bool = $term->ask_yn( + prompt => loc("Would you like to send the test report?"), + default => 'n' + ); + + return $bool; +} + +sub __ask_about_edit_test_report { + my($mod, $grade) = @_; + return 0 unless $grade eq GRADE_FAIL; + + my $term = $Shell->term; + + $Shell->__print( "\n" ); + $Shell->__print( + loc("Test report prepared for module '%1'. You can edit this ". + "report if you would like", $mod->module ) ); + $Shell->__print("\n\n"); + my $bool = $term->ask_yn( + prompt => loc("Would you like to edit the test report?"), + default => 'y' + ); + + return $bool; +} + +sub __ask_about_test_failure { + my $mod = shift; + my $captured = shift || ''; + my $term = $Shell->term; + + $Shell->__print( "\n" ); + $Shell->__print( + loc( "The tests for '%1' failed. Would you like me to proceed ". + "anyway or should we abort?", $mod->module ) ); + $Shell->__print( "\n\n" ); + + my $bool = $term->ask_yn( + prompt => loc("Proceed anyway?"), + default => 'n', + ); + + return $bool; +} + + +sub _details { + my $self = shift; + my $cb = $self->backend; + my $conf = $cb->configure_object; + my %hash = @_; + + my $args; my $mods; my $opts; + { local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + modules => { required => 1, store => \$mods }, + options => { default => { }, store => \$opts }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + ### every module has about 10 lines of details + ### maybe more later with Module::CPANTS etc + $self->_pager_open if scalar @$mods * 10 > $self->_term_rowcount; + + + my $format = "%-24s %-45s\n"; + my $cformat = "%-24s %-45s %-10s\n"; + for my $mod (@$mods) { + my $href = $mod->details( %$opts ); + my @list = sort { $a->module cmp $b->module } $mod->contains; + + unless( $href ) { + $self->__print( + loc("No details for %1 - it might be outdated.", + $mod->module), "\n" ); + next; + + } else { + $self->__print( loc( "Details for '%1'\n", $mod->module ) ); + for my $item ( sort keys %$href ) { + $self->__printf( $format, $item, $href->{$item} ); + } + + my $showed; + for my $item ( @list ) { + $self->__printf( + $cformat, ($showed ? '' : 'Contains:'), + $item->module, $item->version + ); + $showed++; + } + $self->__print( "\n" ); + } + } + $self->_pager_close; + $self->__print( "\n" ); + + return 1; +} + +sub _print { + my $self = shift; + my %hash = @_; + + my $args; my $opts; my $file; + { local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + options => { default => { }, store => \$opts }, + input => { default => '', store => \$file }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + my $old; my $fh; + if( $file ) { + $fh = FileHandle->new( ">$file" ) + or( warn loc("Could not open '%1': '%2'", $file, $!), + return + ); + $old = select $fh; + } + + + $self->_pager_open if !$file; + + $self->__print( CPANPLUS::Error->stack_as_string ); + + $self->_pager_close; + + select $old if $old; + $self->__print( "\n" ); + + return 1; +} + +sub _set_conf { + my $self = shift; + my %hash = @_; + my $cb = $self->backend; + my $conf = $cb->configure_object; + + ### possible options + ### XXX hard coded, not optimal :( + my %types = ( + reconfigure => '', + save => q([user | system | boxed]), + edit => '', + program => q([key => val]), + conf => q([key => val]), + mirrors => '', + selfupdate => '', # XXX add all opts here? + ); + + + my $args; my $opts; my $input; + { local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + options => { default => { }, store => \$opts }, + input => { default => '', store => \$input }, + }; + + $args = check( $tmpl, \%hash ) or return; + } + + my ($type,$key,$value) = $input =~ m/(\w+)\s*(\w*)\s*(.*?)$/; + $value =~ s/\s+$//g if $value; + $type = lc $type; + + if( $type eq 'reconfigure' ) { + my $setup = CPANPLUS::Configure::Setup->new( + configure_object => $conf, + term => $self->term, + backend => $cb, + ); + return $setup->init; + + } elsif ( $type eq 'save' ) { + my $where = { + user => CONFIG_USER, + system => CONFIG_SYSTEM, + boxed => CONFIG_BOXED, + }->{ $key } || CONFIG_USER; + + ### boxed is special, so let's get its value from %INC + ### so we can tell it where to save + ### XXX perhaps this logic should be generic for all + ### types, and put in the ->save() routine + my $dir; + if( $where eq CONFIG_BOXED ) { + my $file = join( '/', split( '::', CONFIG_BOXED ) ) . '.pm'; + my $file_re = quotemeta($file); + + my $path = $INC{$file} || ''; + $path =~ s/$file_re$//; + $dir = $path; + } + + my $rv = $cb->configure_object->save( $where => $dir ); + + $self->__print( + $rv + ? loc("Configuration successfully saved to %1\n (%2)\n", + $where, $rv) + : loc("Failed to save configuration\n" ) + ); + return $rv; + + } elsif ( $type eq 'edit' ) { + + my $editor = $conf->get_program('editor') + or( print(loc("No editor specified")), return ); + + my $where = { + user => CONFIG_USER, + system => CONFIG_SYSTEM, + }->{ $key } || CONFIG_USER; + + my $file = $conf->_config_pm_to_file( $where ); + system($editor,$file); + + ### now reload it + ### disable warnings for this + { require Module::Loaded; + Module::Loaded::mark_as_unloaded( $where ); + + ### reinitialize the config + local $^W; + $conf->init; + } + + return 1; + + } elsif ( $type eq 'mirrors' ) { + + $self->__print( + loc("Readonly list of mirrors (in order of preference):\n\n" ) ); + + my $i; + for my $host ( @{$conf->get_conf('hosts')} ) { + my $uri = $cb->_host_to_uri( %$host ); + + $i++; + $self->__print( "\t[$i] $uri\n" ); + } + + $self->__print( + loc("\nTo edit this list, please type: '%1'\n", 's edit') ); + + } elsif ( $type eq 'selfupdate' ) { + my %valid = map { $_ => $_ } + $cb->selfupdate_object->list_categories; + + unless( $valid{$key} ) { + $self->__print( + loc( "To update your current CPANPLUS installation, ". + "choose one of the these options:\n%1", + ( join $/, map { + sprintf "\ts selfupdate %-17s " . + "[--latest=0] [--dryrun]", $_ + } sort keys %valid ) + ) + ); + } else { + my %update_args = ( + update => $key, + latest => 1, + %$opts + ); + + + my %list = $cb->selfupdate_object + ->list_modules_to_update( %update_args ); + + $self->__print(loc("The following updates will take place:"),$/.$/); + + for my $feature ( sort keys %list ) { + my $aref = $list{$feature}; + + ### is it a 'feature' or a built in? + $self->__print( + $valid{$feature} + ? " " . ucfirst($feature) . ":\n" + : " Modules for '$feature' support:\n" + ); + + ### show what modules would be installed + $self->__print( + scalar @$aref + ? map { sprintf " %-42s %-6s -> %-6s \n", + $_->name, $_->installed_version, $_->version + } @$aref + : " No upgrades required\n" + ); + $self->__print( $/ ); + } + + + unless( $opts->{'dryrun'} ) { + $self->__print( loc("Updating your CPANPLUS installation\n") ); + $cb->selfupdate_object->selfupdate( %update_args ); + } + } + + } else { + + if ( $type eq 'program' or $type eq 'conf' ) { + + my $format = { + conf => '%-25s %s', + program => '%-12s %s', + }->{ $type }; + + unless( $key ) { + my @list = grep { $_ ne 'hosts' } + $conf->options( type => $type ); + + my $method = 'get_' . $type; + + local $Data::Dumper::Indent = 0; + for my $name ( @list ) { + my $val = $conf->$method($name) || ''; + ($val) = ref($val) + ? (Data::Dumper::Dumper($val) =~ /= (.*);$/) + : "'$val'"; + + $self->__printf( " $format\n", $name, $val ); + } + + } elsif ( $key eq 'hosts' or $key eq 'lib' ) { + $self->__print( + loc( "Setting %1 is not trivial.\n" . + "It is suggested you use '%2' and edit the " . + "configuration file manually", $key, 's edit') + ); + } else { + my $method = 'set_' . $type; + $conf->$method( $key => defined $value ? $value : '' ) + and $self->__print( loc("Key '%1' was set to '%2'", $key, + defined $value ? $value : 'EMPTY STRING') ); + } + + } else { + $self->__print( loc("Unknown type '%1'",$type || 'EMPTY' ) ); + $self->__print( $/ ); + $self->__print( loc("Try one of the following:") ); + $self->__print( $/, join $/, + map { sprintf "\t%-11s %s", $_, $types{$_} } + sort keys %types ); + } + } + $self->__print( "\n" ); + return 1; +} + +sub _uptodate { + my $self = shift; + my %hash = @_; + my $cb = $self->backend; + my $conf = $cb->configure_object; + + my $opts; my $mods; + { local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + options => { default => { }, store => \$opts }, + modules => { required => 1, store => \$mods }, + }; + + check( $tmpl, \%hash ) or return; + } + + ### long listing? short is default ### + my $long = $opts->{'long'} ? 1 : 0; + + my @list = scalar @$mods ? @$mods : @{$cb->_all_installed}; + + my @rv; my %seen; + for my $mod (@list) { + ### skip this mod if it's up to date ### + next if $mod->is_uptodate; + ### skip this mod if it's core ### + next if $mod->package_is_perl_core; + + if( $long or !$seen{$mod->package}++ ) { + push @rv, $mod; + } + } + + @rv = sort { $a->module cmp $b->module } @rv; + + $self->cache([undef,@rv]); + + $self->_pager_open if scalar @rv >= $self->_term_rowcount; + + my $format = "%5s %12s %12s %-36s %-10s\n"; + + my $i = 1; + for my $mod ( @rv ) { + $self->__printf( + $format, + $i, + $self->_format_version($mod->installed_version) || 'Unparsable', + $self->_format_version( $mod->version ), + $mod->module, + $mod->author->cpanid + ); + $i++; + } + $self->_pager_close; + + return 1; +} + +sub _autobundle { + my $self = shift; + my %hash = @_; + my $cb = $self->backend; + my $conf = $cb->configure_object; + + my $opts; my $input; + { local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + options => { default => { }, store => \$opts }, + input => { default => '', store => \$input }, + }; + + check( $tmpl, \%hash ) or return; + } + + $opts->{'path'} = $input if $input; + + my $where = $cb->autobundle( %$opts ); + + $self->__print( + $where + ? loc("Wrote autobundle to '%1'", $where) + : loc("Could not create autobundle" ) + ); + $self->__print( "\n" ); + + return $where ? 1 : 0; +} + +sub _uninstall { + my $self = shift; + my %hash = @_; + my $cb = $self->backend; + my $term = $self->term; + my $conf = $cb->configure_object; + + my $opts; my $mods; + { local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + options => { default => { }, store => \$opts }, + modules => { default => [], store => \$mods }, + }; + + check( $tmpl, \%hash ) or return; + } + + my $force = $opts->{'force'} || $conf->get_conf('force'); + + unless( $force ) { + my $list = join "\n", map { ' ' . $_->module } @$mods; + + $self->__print( loc(" +This will uninstall the following modules: +%1 + +Note that if you installed them via a package manager, you probably +should use the same package manager to uninstall them + +", $list) ); + + return unless $term->ask_yn( + prompt => loc("Are you sure you want to continue?"), + default => 'n', + ); + } + + ### first loop over all the modules to uninstall them ### + for my $mod (@$mods) { + $self->__print( loc("Uninstalling '%1'", $mod->module), "\n" ); + + $mod->uninstall( %$opts ); + } + + my $flag; + ### then report whether all this went ok or not ### + for my $mod (@$mods) { + if( $mod->status->uninstall ) { + $self->__print( + loc("Module '%1' %tense(uninstall,past) successfully\n", + $mod->module ) ); + } else { + $flag++; + $self->__print( + loc("Error %tense(uninstall,present) '%1'\n", $mod->module) ); + } + } + + if( !$flag ) { + $self->__print( + loc("All modules %tense(uninstall,past) successfully"), "\n" ); + } else { + $self->__print( + loc("Problem %tense(uninstall,present) one or more modules" ), + "\n" ); + + $self->__print( + loc("*** You can view the complete error buffer by pressing '%1'". + "***\n", 'p') ) unless $conf->get_conf('verbose'); + } + $self->__print( "\n" ); + + return !$flag; +} + +sub _reports { + my $self = shift; + my %hash = @_; + my $cb = $self->backend; + my $term = $self->term; + my $conf = $cb->configure_object; + + my $opts; my $mods; + { local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + options => { default => { }, store => \$opts }, + modules => { default => '', store => \$mods }, + }; + + check( $tmpl, \%hash ) or return; + } + + ### XXX might need to be conditional ### + $self->_pager_open; + + for my $mod (@$mods) { + my @list = $mod->fetch_report( %$opts ) + or( print(loc("No reports available for this distribution.")), + next + ); + + @list = reverse + map { $_->[0] } + sort { $a->[1] cmp $b->[1] } + map { [$_, $_->{'dist'}.':'.$_->{'platform'}] } @list; + + + + ### XXX this may need to be sorted better somehow ### + my $url; + my $format = "%8s %s %s\n"; + + my %seen; + for my $href (@list ) { + $self->__print( + "[" . $mod->author->cpanid .'/'. $href->{'dist'} . "]\n" + ) unless $seen{ $href->{'dist'} }++; + + $self->__printf( + $format, + $href->{'grade'}, + $href->{'platform'}, + ($href->{'details'} ? '(*)' : '') + ); + + $url ||= $href->{'details'}; + } + + $self->__print( "\n==> $url\n" ) if $url; + $self->__print( "\n" ); + } + $self->_pager_close; + + return 1; +} + +### Load plugins +{ my @PluginModules; + my %Dispatch = ( + showtip => [ __PACKAGE__, '_show_random_tip'], + plugins => [ __PACKAGE__, '_list_plugins' ], + '?' => [ __PACKAGE__, '_plugins_usage' ], + ); + + sub plugin_modules { return @PluginModules } + sub plugin_table { return %Dispatch } + + my $init_done; + sub _plugins_init { + + ### only initialize once + return if $init_done++; + + ### find all plugins first + if( check_install( module => 'Module::Pluggable', version => '2.4') ) { + require Module::Pluggable; + + my $only_re = __PACKAGE__ . '::Plugins::\w+$'; + + Module::Pluggable->import( + sub_name => '_plugins', + search_path => __PACKAGE__, + only => qr/$only_re/, + #except => [ INSTALLER_MM, INSTALLER_SAMPLE ] + ); + + push @PluginModules, __PACKAGE__->_plugins; + } + + ### now try to load them + for my $p ( __PACKAGE__->plugin_modules ) { + my %map = eval { load $p; $p->import; $p->plugins }; + error(loc("Could not load plugin '$p': $@")), next if $@; + + ### register each plugin + while( my($name, $func) = each %map ) { + + if( not length $name or not length $func ) { + error(loc("Empty plugin name or dispatch function detected")); + next; + } + + if( exists( $Dispatch{$name} ) ) { + error(loc("'%1' is already registered by '%2'", + $name, $Dispatch{$name}->[0])); + next; + } + + ### register name, package and function + $Dispatch{$name} = [ $p, $func ]; + } + } + } + + ### dispatch a plugin command to its function + sub _meta { + my $self = shift; + my %hash = @_; + my $cb = $self->backend; + my $term = $self->term; + my $conf = $cb->configure_object; + + my $opts; my $input; + { local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + options => { default => { }, store => \$opts }, + input => { default => '', store => \$input }, + }; + + check( $tmpl, \%hash ) or return; + } + + $input =~ s/\s*(\S+)\s*//; + my $cmd = $1; + + ### look up the command, or go to the default + my $aref = $Dispatch{ $cmd } || [ __PACKAGE__, '_plugin_default' ]; + + my($pkg,$func) = @$aref; + + my $rv = eval { $pkg->$func( $self, $cb, $cmd, $input, $opts ) }; + + error( $@ ) if $@; + + ### return $rv instead, so input loop can be terminated? + return 1; + } + + sub _plugin_default { error(loc("No such plugin command")) } +} + +### plugin commands +{ my $help_format = " /%-21s # %s\n"; + + sub _list_plugins { + my $self = shift; + + $self->__print( loc("Available plugins:\n") ); + $self->__print( loc(" List usage by using: /? PLUGIN_NAME\n" ) ); + $self->__print( $/ ); + + my %table = __PACKAGE__->plugin_table; + for my $name( sort keys %table ) { + my $pkg = $table{$name}->[0]; + my $this = __PACKAGE__; + + my $who = $pkg eq $this + ? "Standard Plugin" + : do { my $v = $self->_format_version($pkg->VERSION) || ''; + $pkg =~ s/^$this/../; + sprintf "Provided by: %-30s %-10s", $pkg, $v; + }; + + $self->__printf( $help_format, $name, $who ); + } + + $self->__print( $/.$/ ); + + $self->__print( + " Write your own plugins? Read the documentation of:\n" . + " CPANPLUS::Shell::Default::Plugins::HOWTO\n" ); + + $self->__print( $/ ); + } + + sub _list_plugins_help { + return sprintf $help_format, 'plugins', loc("lists available plugins"); + } + + ### registered as a plugin too + sub _show_random_tip_help { + return sprintf $help_format, 'showtip', loc("show usage tips" ); + } + + sub _plugins_usage { + my $self = shift; + my $shell = shift; + my $cb = shift; + my $cmd = shift; + my $input = shift; + my %table = $self->plugin_table; + + my @list = length $input ? split /\s+/, $input : sort keys %table; + + for my $name( @list ) { + + ### no such plugin? skip + error(loc("No such plugin '$name'")), next unless $table{$name}; + + my $pkg = $table{$name}->[0]; + my $func = $table{$name}->[1] . '_help'; + + if ( my $sub = $pkg->can( $func ) ) { + eval { $self->__print( $sub->() ) }; + error( $@ ) if $@; + + } else { + $self->__print(" No usage for '$name' -- try perldoc $pkg"); + } + + $self->__print( $/ ); + } + + $self->__print( $/.$/ ); + } + + sub _plugins_usage_help { + return sprintf $help_format, '? [NAME ...]', + loc("show usage for plugins"); + } +} + +### send a command to a remote host, retrieve the answer; +sub __send_remote_command { + my $self = shift; + my $cmd = shift; + my $remote = $self->remote or return; + my $user = $remote->{'username'}; + my $pass = $remote->{'password'}; + my $conn = $remote->{'connection'}; + my $end = "\015\012"; + my $answer; + + my $send = join "\0", $user, $pass, $cmd; + + print $conn $send . $end; + + ### XXX why doesn't something like this just work? + #1 while recv($conn, $answer, 1024, 0); + while(1) { + my $buff; + $conn->recv( $buff, 1024, 0 ); + $answer .= $buff; + last if $buff =~ /$end$/; + } + + my($status,$buffer) = split "\0", $answer; + + return ($status, $buffer); +} + + +sub _read_configuration_from_rc { + my $self = shift; + my $rc_file = shift; + + my $href; + if( can_load( modules => { 'Config::Auto' => '0.0' } ) ) { + $Config::Auto::DisablePerl = 1; + + eval { $href = Config::Auto::parse( $rc_file, format => 'space' ) }; + + $self->__print( + loc( "Unable to read in config file '%1': %2", $rc_file, $@ ) + ) if $@; + } + + return $href || {}; +} + +{ my @tips = ( + loc( "You can update CPANPLUS by running: '%1'", 's selfupdate' ), + loc( "You can install modules by URL using '%1'", 'i URL' ), + loc( "You can turn off these tips using '%1'", + 's conf show_startup_tip 0' ), + loc( "You can use wildcards like '%1' and '%2' on search results", + '*', '2..5' ) , + loc( "You can use plugins. Type '%1' to list available plugins", + '/plugins' ), + loc( "You can show all your out of date modules using '%1'", 'o' ), + loc( "Many operations take options, like '%1', '%2' or '%3'", + '--verbose', '--force', '--skiptest' ), + loc( "The documentation in %1 and %2 is very useful", + "CPANPLUS::Module", "CPANPLUS::Backend" ), + loc( "You can type '%1' for help and '%2' to exit", 'h', 'q' ), + loc( "You can run an interactive setup using '%1'", 's reconfigure' ), + loc( "You can add custom sources to your index. See '%1' for details", + '/cs --help' ), + loc( "CPANPLUS now has an experimental SQLite backend. You can enable ". + "it via: '%1'. Update dependencies via '%2'", + 's conf source_engine CPANPLUS::Internals::Source::SQLite; s save', + 's selfupdate enabled_features ' ), + ); + + sub _show_random_tip { + my $self = shift; + $self->__print( $/, "Did you know...\n ", + $tips[ int rand scalar @tips ], $/ ); + return 1; + } +} + +1; + +__END__ + +=pod + +=head1 BUG REPORTS + +Please report bugs or other issues to E<lt>bug-cpanplus@rt.cpan.org<gt>. + +=head1 AUTHOR + +This module by Jos Boumans E<lt>kane@cpan.orgE<gt>. + +=head1 COPYRIGHT + +The CPAN++ interface (of which this module is a part of) is copyright (c) +2001 - 2007, Jos Boumans E<lt>kane@cpan.orgE<gt>. All rights reserved. + +This library is free software; you may redistribute and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L<CPANPLUS::Shell::Classic>, L<CPANPLUS::Shell>, L<cpanp> + +=cut + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: + +__END__ + +TODO: + e => "_expand_inc", # scratch it, imho -- not used enough + +### free letters: g j k n y ### diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Shell/Default/Plugins/CustomSource.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Shell/Default/Plugins/CustomSource.pm new file mode 100644 index 00000000000..ad4701a488c --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Shell/Default/Plugins/CustomSource.pm @@ -0,0 +1,201 @@ +package CPANPLUS::Shell::Default::Plugins::CustomSource; + +use strict; +use CPANPLUS::Error qw[error msg]; +use CPANPLUS::Internals::Constants; + +use Data::Dumper; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +=head1 NAME + +CPANPLUS::Shell::Default::Plugins::CustomSource + +=head1 SYNOPSIS + + ### elaborate help text + CPAN Terminal> /? cs + + ### add a new custom source + CPAN Terminal> /cs --add file:///path/to/releases + + ### list all your custom sources by + CPAN Terminal> /cs --list + + ### display the contents of a custom source by URI or ID + CPAN Terminal> /cs --contents file:///path/to/releases + CPAN Terminal> /cs --contents 1 + + ### Update a custom source by URI or ID + CPAN Terminal> /cs --update file:///path/to/releases + CPAN Terminal> /cs --update 1 + + ### Remove a custom source by URI or ID + CPAN Terminal> /cs --remove file:///path/to/releases + CPAN Terminal> /cs --remove 1 + + ### Write an index file for a custom source, to share + ### with 3rd parties or remote users + CPAN Terminal> /cs --write file:///path/to/releases + + ### Make sure to save your sources when adding/removing + ### sources, so your changes are reflected in the cache: + CPAN Terminal> x + +=head1 DESCRIPTION + +This is a C<CPANPLUS::Shell::Default> plugin that can add +custom sources to your CPANPLUS installation. This is a +wrapper around the C<custom module sources> code as outlined +in L<CPANPLUS::Backend/CUSTOM MODULE SOURCES>. + +This allows you to extend your index of available modules +beyond what's available on C<CPAN> with your own local +distributions, or ones offered by third parties. + +=cut + + +sub plugins { + return ( cs => 'custom_source' ) +} + +my $Cb; +my $Shell; +my @Index = (); + +sub _uri_from_cache { + my $self = shift; + my $input = shift or return; + + ### you gave us a search number + my $uri = $input =~ /^\d+$/ + ? $Index[ $input - 1 ] # remember, off by 1! + : $input; + + my %files = reverse $Cb->list_custom_sources; + + ### it's an URI we know + ### VMS can lower case all files, so make sure we check that too + my $local = $files{ $uri }; + $local = $files{ lc $uri } if !$local && ON_VMS; + + if( $local ) { + return wantarray + ? ($uri, $local) + : $uri; + } + + ### couldn't resolve the input + error(loc("Unknown URI/index: '%1'", $input)); + return; +} + +sub _list_custom_sources { + my $class = shift; + + my %files = $Cb->list_custom_sources; + + $Shell->__print( loc("Your remote sources:"), $/ ) if keys %files; + + my $i = 0; + while(my($local,$remote) = each %files) { + $Shell->__printf( " [%2d] %s\n", ++$i, $remote ); + + ### remember, off by 1! + push @Index, $remote; + } + + $Shell->__print( $/ ); +} + +sub _list_contents { + my $class = shift; + my $input = shift; + + my ($uri,$local) = $class->_uri_from_cache( $input ); + unless( $uri ) { + error(loc("--contents needs URI parameter")); + return; + } + + my $fh = OPEN_FILE->( $local ) or return; + + $Shell->__printf( " %s", $_ ) for sort <$fh>; + $Shell->__print( $/ ); +} + +sub custom_source { + my $class = shift; + my $shell = shift; $Shell = $shell; # available to all methods now + my $cb = shift; $Cb = $cb; # available to all methods now + my $cmd = shift; + my $input = shift || ''; + my $opts = shift || {}; + + ### show a list + if( $opts->{'list'} ) { + $class->_list_custom_sources; + + } elsif ( $opts->{'contents'} ) { + $class->_list_contents( $input ); + + } elsif ( $opts->{'add'} ) { + unless( $input ) { + error(loc("--add needs URI parameter")); + return; + } + + $cb->add_custom_source( uri => $input ) + and $shell->__print(loc("Added remote source '%1'", $input), $/); + + $Shell->__print($/, loc("Remote source contains:"), $/, $/); + $class->_list_contents( $input ); + + } elsif ( $opts->{'remove'} ) { + my($uri,$local) = $class->_uri_from_cache( $input ); + unless( $uri ) { + error(loc("--remove needs URI parameter")); + return; + } + + 1 while unlink $local; + + $shell->__print( loc("Removed remote source '%1'", $uri), $/ ); + + } elsif ( $opts->{'update'} ) { + ### did we get input? if so, it's a remote part + my $uri = $class->_uri_from_cache( $input ); + + $cb->update_custom_source( $uri ? ( remote => $uri ) : () ) + and do { $shell->__print( loc("Updated remote sources"), $/ ) }; + + } elsif ( $opts->{'write'} ) { + $cb->write_custom_source_index( path => $input ) and + $shell->__print( loc("Wrote remote source index for '%1'", $input), $/); + + } else { + error(loc("Unrecognized command, see '%1' for help", '/? cs')); + } + + return; +} + +sub custom_source_help { + return loc( + $/ . + ' # Plugin to manage custom sources from the default shell' . $/ . + " # See the 'CUSTOM MODULE SOURCES' section in the " . $/ . + ' # CPANPLUS::Backend documentation for details.' . $/ . + ' /cs --list # list available sources' . $/ . + ' /cs --add URI # add source' . $/ . + ' /cs --remove URI | INDEX # remove source' . $/ . + ' /cs --contents URI | INDEX # show packages from source'. $/ . + ' /cs --update [URI | INDEX] # update source index' . $/ . + ' /cs --write PATH # write source index' . $/ + ); + +} + +1; + diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Shell/Default/Plugins/HOWTO.pod b/Master/tlpkg/tlperl/lib/CPANPLUS/Shell/Default/Plugins/HOWTO.pod new file mode 100644 index 00000000000..ca765f9e0ac --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Shell/Default/Plugins/HOWTO.pod @@ -0,0 +1,136 @@ +=head1 NAME + +CPANPLUS::Shell::Default::Plugins::HOWTO -- documentation on how to write your own plugins + +=head1 SYNOPSIS + + package CPANPLUS::Shell::Default::Plugins::MyPlugin; + + ### return command => method mapping + sub plugins { ( myplugin1 => 'mp1', myplugin2 => 'mp2' ) } + + ### method called when the command '/myplugin1' is issued + sub mp1 { .... } + + ### method called when the command '/? myplugin1' is issued + sub mp1_help { return "Help Text" } + +=head1 DESCRIPTION + +This pod text explains how to write your own plugins for +C<CPANPLUS::Shell::Default>. + +=head1 HOWTO + +=head2 Registering Plugin Modules + +Plugins are detected by using C<Module::Pluggable>. Every module in +the C<CPANPLUS::Shell::Default::Plugins::*> namespace is considered a +plugin, and is attempted to be loaded. + +Therefor, any plugin must be declared in that namespace, in a corresponding +C<.pm> file. + +=head2 Registering Plugin Commands + +To register any plugin commands, a list of key value pairs must be returned +by a C<plugins> method in your package. The keys are the commands you wish +to register, the values are the methods in the plugin package you wish to have +called when the command is issued. + +For example, a simple 'Hello, World!' plugin: + + package CPANPLUS::Shell::Default::Plugins::HW; + + sub plugins { return ( helloworld => 'hw' ) }; + + sub hw { print "Hello, world!\n" } + +When the user in the default shell now issues the C</helloworld> command, +this command will be dispatched to the plugin, and its C<hw> method will +be called + +=head2 Registering Plugin Help + +To provide usage information for your plugin, the user of the default shell +can type C</? PLUGIN_COMMAND>. In that case, the function C<PLUGIN_COMMAND_help> +will be called in your plugin package. + +For example, extending the above example, when a user calls C</? helloworld>, +the function C<hw_help> will be called, which might look like this: + + sub hw_help { " /helloworld # prints "Hello, world!\n" } + +If you dont provide a corresponding _help function to your commands, the +default shell will handle it gracefully, but the user will be stuck without +usage information on your commands, so it's considered undesirable to omit +the help functions. + +=head2 Arguments to Plugin Commands + +Any plugin function will receive the following arguments when called, which +are all positional: + +=over 4 + +=item Classname -- The name of your plugin class + +=item Shell -- The CPANPLUS::Shell::Default object + +=item Backend -- The CPANPLUS::Backend object + +=item Command -- The command issued by the user + +=item Input -- The input string from the user + +=item Options -- A hashref of options provided by the user + +=back + +For example, the following command: + + /helloworld bob --nofoo --bar=2 joe + +Would yield the following arguments: + + sub hw { + my $class = shift; # CPANPLUS::Shell::Default::Plugins::HW + my $shell = shift; # CPANPLUS::Shell::Default object + my $cb = shift; # CPANPLUS::Backend object + my $cmd = shift; # 'helloworld' + my $input = shift; # 'bob joe' + my $opts = shift; # { foo => 0, bar => 2 } + + .... + } + + +=head1 BUG REPORTS + +Please report bugs or other issues to E<lt>bug-cpanplus@rt.cpan.org<gt>. + +=head1 AUTHOR + +This module by Jos Boumans E<lt>kane@cpan.orgE<gt>. + +=head1 COPYRIGHT + +The CPAN++ interface (of which this module is a part of) is copyright (c) +2001 - 2007, Jos Boumans E<lt>kane@cpan.orgE<gt>. All rights reserved. + +This library is free software; you may redistribute and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L<CPANPLUS::Shell::Default>, L<CPANPLUS::Shell>, L<cpanp> + +=cut + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: + diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Shell/Default/Plugins/Remote.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Shell/Default/Plugins/Remote.pm new file mode 100644 index 00000000000..d2b829abded --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Shell/Default/Plugins/Remote.pm @@ -0,0 +1,186 @@ +package CPANPLUS::Shell::Default::Plugins::Remote; + +use strict; + +use Module::Load; +use Params::Check qw[check]; +use CPANPLUS::Error qw[error msg]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +=head1 NAME + +CPANPLUS::Shell::Default::Plugins::Remote + +=head1 SYNOPSIS + + CPAN Terminal> /connect localhost 1337 --user=foo --pass=bar + ... + CPAN Terminal@localhost> /disconnect + +=head1 DESCRIPTION + +This is a C<CPANPLUS::Shell::Default> plugin that allows you to connect +to a machine running an instance of C<CPANPLUS::Daemon>, allowing remote +usage of the C<CPANPLUS Shell>. + +A sample session, updating all modules on a remote machine, might look +like this: + + CPAN Terminal> /connect --user=my_user --pass=secret localhost 1337 + + Connection accepted + + Successfully connected to 'localhost' on port '11337' + + Note that no output will appear until a command has completed + -- this may take a while + + + CPAN Terminal@localhost> o; i * + + [....] + + CPAN Terminal@localhost> /disconnect + + CPAN Terminal> + +=cut + +### store the original prompt here, so we can restore it on disconnect +my $Saved_Prompt; + +sub plugins { ( connect => 'connect', disconnect => 'disconnect' ) } + +sub connect { + my $class = shift; + my $shell = shift; + my $cb = shift; + my $cmd = shift; + my $input = shift || ''; + my $opts = shift || {}; + my $conf = $cb->configure_object; + + my $user; my $pass; + { local $Params::Check::ALLOW_UNKNOWN = 1; + + my $tmpl = { + user => { default => 'cpanpd', store => \$user }, + pass => { required => 1, store => \$pass }, + }; + + check( $tmpl, $opts ) or return; + } + + my @parts = split /\s+/, $input; + my $host = shift @parts || 'localhost'; + my $port = shift @parts || '1337'; + + load IO::Socket; + + my $remote = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => $host, + PeerPort => $port, + ) or ( + error( loc( "Cannot connect to port '%1' ". + "on host '%2'", $port, $host ) ), + return + ); + + my $con = { + connection => $remote, + username => $user, + password => $pass, + }; + + ### store the connection + $shell->remote( $con ); + + my($status,$buffer) = $shell->__send_remote_command( + "VERSION=$CPANPLUS::Shell::Default::VERSION"); + + if( $status ) { + print "\n$buffer\n\n"; + + print loc( "Successfully connected to '%1' on port '%2'", + $host, $port ); + print "\n\n"; + print loc( "Note that no output will appear until a command ". + "has completed\n-- this may take a while" ); + print "\n\n"; + + ### save the original prompt + $Saved_Prompt = $shell->prompt; + + $shell->prompt( $shell->brand .'@'. $host .':'. $port .'> ' ); + + } else { + print "\n$buffer\n\n"; + + print loc( "Failed to connect to '%1' on port '%2'", + $host, $port ); + print "\n\n"; + + $shell->remote( undef ); + } +} + +sub disconnect { + my $class = shift; + my $shell = shift; + + print "\n", ( $shell->remote + ? loc( "Disconnecting from remote host" ) + : loc( "Not connected to remote host" ) + ), "\n\n"; + + $shell->remote( undef ); + $shell->prompt( $Saved_Prompt ); +} + +sub connect_help { + return loc( + " /connect [HOST PORT] # Connect to the remote machine,\n" . + " # defaults taken from your config\n" . + " --user=USER # Optional username\n" . + " --pass=PASS # Optional password" ); +} + +sub disconnect_help { + return loc( + " /disconnect # Disconnect from the remote server" ); +} + +1; + +=pod + +=head1 BUG REPORTS + +Please report bugs or other issues to E<lt>bug-cpanplus@rt.cpan.org<gt>. + +=head1 AUTHOR + +This module by Jos Boumans E<lt>kane@cpan.orgE<gt>. + +=head1 COPYRIGHT + +The CPAN++ interface (of which this module is a part of) is copyright (c) +2001 - 2007, Jos Boumans E<lt>kane@cpan.orgE<gt>. All rights reserved. + +This library is free software; you may redistribute and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L<CPANPLUS::Shell::Default>, L<CPANPLUS::Shell>, L<cpanp> + +=cut + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: + diff --git a/Master/tlpkg/tlperl/lib/CPANPLUS/Shell/Default/Plugins/Source.pm b/Master/tlpkg/tlperl/lib/CPANPLUS/Shell/Default/Plugins/Source.pm new file mode 100644 index 00000000000..889b3d3d9bd --- /dev/null +++ b/Master/tlpkg/tlperl/lib/CPANPLUS/Shell/Default/Plugins/Source.pm @@ -0,0 +1,107 @@ +package CPANPLUS::Shell::Default::Plugins::Source; + +use strict; +use CPANPLUS::Error qw[error msg]; +use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext'; + +=head1 NAME + +CPANPLUS::Shell::Default::Plugins::Source + +=head1 SYNOPSIS + + CPAN Terminal> /source /tmp/list_of_commands /tmp/more_commands + +=head1 DESCRIPTION + +This is a C<CPANPLUS::Shell::Default> plugin that works just like +your unix shells source(1) command; it reads in a file that has +commands in it to execute, and then executes them. + +A sample file might look like this: + + # first, update all the source files + x --update_source + + # find all of my modules that are on the CPAN + # test them, and store the error log + a ^KANE$' + t * + p /home/kane/cpan-autotest/log + + # and inform us we're good to go + ! print "Autotest complete, log stored; please enter your commands!" + +Note how empty lines, and lines starting with a '#' are being skipped +in the execution. + +=cut + + +sub plugins { return ( source => 'source' ) } + +sub source { + my $class = shift; + my $shell = shift; + my $cb = shift; + my $cmd = shift; + my $input = shift || ''; + my $opts = shift || {}; + my $verbose = $cb->configure_object->get_conf('verbose'); + + for my $file ( split /\s+/, $input ) { + my $fh = FileHandle->new("$file") or( + error(loc("Could not open file '%1': %2", $file, $!)), + next + ); + + while( my $line = <$fh> ) { + chomp $line; + + next if $line !~ /\S+/; # skip empty/whitespace only lines + next if $line =~ /^#/; # skip comments + + msg(loc("Dispatching '%1'", $line), $verbose); + return 1 if $shell->dispatch_on_input( input => $line ); + } + } +} + +sub source_help { + return loc(' /source FILE [FILE ..] '. + '# read in commands from the specified file' ), +} + +1; + +=pod + +=head1 BUG REPORTS + +Please report bugs or other issues to E<lt>bug-cpanplus@rt.cpan.org<gt>. + +=head1 AUTHOR + +This module by Jos Boumans E<lt>kane@cpan.orgE<gt>. + +=head1 COPYRIGHT + +The CPAN++ interface (of which this module is a part of) is copyright (c) +2001 - 2007, Jos Boumans E<lt>kane@cpan.orgE<gt>. All rights reserved. + +This library is free software; you may redistribute and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L<CPANPLUS::Shell::Default>, L<CPANPLUS::Shell>, L<cpanp> + +=cut + +# Local variables: +# c-indentation-style: bsd +# c-basic-offset: 4 +# indent-tabs-mode: nil +# End: +# vim: expandtab shiftwidth=4: + diff --git a/Master/tlpkg/tlperl/lib/Encode/Alias.pm b/Master/tlpkg/tlperl/lib/Encode/Alias.pm new file mode 100644 index 00000000000..f142403ca9c --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/Alias.pm @@ -0,0 +1,377 @@ +package Encode::Alias; +use strict; +use warnings; +no warnings 'redefine'; +our $VERSION = do { my @r = ( q$Revision: 2.12 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; +sub DEBUG () { 0 } + +use base qw(Exporter); + +# Public, encouraged API is exported by default + +our @EXPORT = + qw ( + define_alias + find_alias +); + +our @Alias; # ordered matching list +our %Alias; # cached known aliases + +sub find_alias { + require Encode; + my $class = shift; + my $find = shift; + unless ( exists $Alias{$find} ) { + $Alias{$find} = undef; # Recursion guard + for ( my $i = 0 ; $i < @Alias ; $i += 2 ) { + my $alias = $Alias[$i]; + my $val = $Alias[ $i + 1 ]; + my $new; + if ( ref($alias) eq 'Regexp' && $find =~ $alias ) { + DEBUG and warn "eval $val"; + $new = eval $val; + DEBUG and $@ and warn "$val, $@"; + } + elsif ( ref($alias) eq 'CODE' ) { + DEBUG and warn "$alias", "->", "($find)"; + $new = $alias->($find); + } + elsif ( lc($find) eq lc($alias) ) { + $new = $val; + } + if ( defined($new) ) { + next if $new eq $find; # avoid (direct) recursion on bugs + DEBUG and warn "$alias, $new"; + my $enc = + ( ref($new) ) ? $new : Encode::find_encoding($new); + if ($enc) { + $Alias{$find} = $enc; + last; + } + } + } + + # case insensitive search when canonical is not in all lowercase + # RT ticket #7835 + unless ( $Alias{$find} ) { + my $lcfind = lc($find); + for my $name ( keys %Encode::Encoding, keys %Encode::ExtModule ) + { + $lcfind eq lc($name) or next; + $Alias{$find} = Encode::find_encoding($name); + DEBUG and warn "$find => $name"; + } + } + } + if (DEBUG) { + my $name; + if ( my $e = $Alias{$find} ) { + $name = $e->name; + } + else { + $name = ""; + } + warn "find_alias($class, $find)->name = $name"; + } + return $Alias{$find}; +} + +sub define_alias { + while (@_) { + my ( $alias, $name ) = splice( @_, 0, 2 ); + unshift( @Alias, $alias => $name ); # newer one has precedence + if ( ref($alias) ) { + + # clear %Alias cache to allow overrides + my @a = keys %Alias; + for my $k (@a) { + if ( ref($alias) eq 'Regexp' && $k =~ $alias ) { + DEBUG and warn "delete \$Alias\{$k\}"; + delete $Alias{$k}; + } + elsif ( ref($alias) eq 'CODE' ) { + DEBUG and warn "delete \$Alias\{$k\}"; + delete $Alias{ $alias->($name) }; + } + } + } + else { + DEBUG and warn "delete \$Alias\{$alias\}"; + delete $Alias{$alias}; + } + } +} + +# Allow latin-1 style names as well +# 0 1 2 3 4 5 6 7 8 9 10 +our @Latin2iso = ( 0, 1, 2, 3, 4, 9, 10, 13, 14, 15, 16 ); + +# Allow winlatin1 style names as well +our %Winlatin2cp = ( + 'latin1' => 1252, + 'latin2' => 1250, + 'cyrillic' => 1251, + 'greek' => 1253, + 'turkish' => 1254, + 'hebrew' => 1255, + 'arabic' => 1256, + 'baltic' => 1257, + 'vietnamese' => 1258, +); + +init_aliases(); + +sub undef_aliases { + @Alias = (); + %Alias = (); +} + +sub init_aliases { + require Encode; + undef_aliases(); + + # Try all-lower-case version should all else fails + define_alias( qr/^(.*)$/ => '"\L$1"' ); + + # UTF/UCS stuff + define_alias( qr/^(unicode-1-1-)?UTF-?7$/i => '"UTF-7"' ); + define_alias( qr/^UCS-?2-?LE$/i => '"UCS-2LE"' ); + define_alias( + qr/^UCS-?2-?(BE)?$/i => '"UCS-2BE"', + qr/^UCS-?4-?(BE|LE)?$/i => 'uc("UTF-32$1")', + qr/^iso-10646-1$/i => '"UCS-2BE"' + ); + define_alias( + qr/^UTF-?(16|32)-?BE$/i => '"UTF-$1BE"', + qr/^UTF-?(16|32)-?LE$/i => '"UTF-$1LE"', + qr/^UTF-?(16|32)$/i => '"UTF-$1"', + ); + + # ASCII + define_alias( qr/^(?:US-?)ascii$/i => '"ascii"' ); + define_alias( 'C' => 'ascii' ); + define_alias( qr/\b(?:ISO[-_]?)?646(?:[-_]?US)?$/i => '"ascii"' ); + + # Allow variants of iso-8859-1 etc. + define_alias( qr/\biso[-_]?(\d+)[-_](\d+)$/i => '"iso-$1-$2"' ); + + # At least HP-UX has these. + define_alias( qr/\biso8859(\d+)$/i => '"iso-8859-$1"' ); + + # More HP stuff. + define_alias( + qr/\b(?:hp-)?(arabic|greek|hebrew|kana|roman|thai|turkish)8$/i => + '"${1}8"' ); + + # The Official name of ASCII. + define_alias( qr/\bANSI[-_]?X3\.4[-_]?1968$/i => '"ascii"' ); + + # This is a font issue, not an encoding issue. + # (The currency symbol of the Latin 1 upper half + # has been redefined as the euro symbol.) + define_alias( qr/^(.+)\@euro$/i => '"$1"' ); + + define_alias( qr/\b(?:iso[-_]?)?latin[-_]?(\d+)$/i => +'defined $Encode::Alias::Latin2iso[$1] ? "iso-8859-$Encode::Alias::Latin2iso[$1]" : undef' + ); + + define_alias( + qr/\bwin(latin[12]|cyrillic|baltic|greek|turkish| + hebrew|arabic|baltic|vietnamese)$/ix => + '"cp" . $Encode::Alias::Winlatin2cp{lc($1)}' + ); + + # Common names for non-latin preferred MIME names + define_alias( + 'ascii' => 'US-ascii', + 'cyrillic' => 'iso-8859-5', + 'arabic' => 'iso-8859-6', + 'greek' => 'iso-8859-7', + 'hebrew' => 'iso-8859-8', + 'thai' => 'iso-8859-11', + ); + # RT #20781 + define_alias(qr/\btis-?620\b/i => '"iso-8859-11"'); + + # At least AIX has IBM-NNN (surprisingly...) instead of cpNNN. + # And Microsoft has their own naming (again, surprisingly). + # And windows-* is registered in IANA! + define_alias( + qr/\b(?:cp|ibm|ms|windows)[-_ ]?(\d{2,4})$/i => '"cp$1"' ); + + # Sometimes seen with a leading zero. + # define_alias( qr/\bcp037\b/i => '"cp37"'); + + # Mac Mappings + # predefined in *.ucm; unneeded + # define_alias( qr/\bmacIcelandic$/i => '"macIceland"'); + define_alias( qr/^mac_(.*)$/i => '"mac$1"' ); + # http://rt.cpan.org/Ticket/Display.html?id=36326 + define_alias( qr/^macintosh$/i => '"MacRoman"' ); + + # Ououououou. gone. They are differente! + # define_alias( qr/\bmacRomanian$/i => '"macRumanian"'); + + # Standardize on the dashed versions. + define_alias( qr/\bkoi8[\s\-_]*([ru])$/i => '"koi8-$1"' ); + + unless ($Encode::ON_EBCDIC) { + + # for Encode::CN + define_alias( qr/\beuc.*cn$/i => '"euc-cn"' ); + define_alias( qr/\bcn.*euc$/i => '"euc-cn"' ); + + # define_alias( qr/\bGB[- ]?(\d+)$/i => '"euc-cn"' ) + # CP936 doesn't have vendor-addon for GBK, so they're identical. + define_alias( qr/^gbk$/i => '"cp936"' ); + + # This fixes gb2312 vs. euc-cn confusion, practically + define_alias( qr/\bGB[-_ ]?2312(?!-?raw)/i => '"euc-cn"' ); + + # for Encode::JP + define_alias( qr/\bjis$/i => '"7bit-jis"' ); + define_alias( qr/\beuc.*jp$/i => '"euc-jp"' ); + define_alias( qr/\bjp.*euc$/i => '"euc-jp"' ); + define_alias( qr/\bujis$/i => '"euc-jp"' ); + define_alias( qr/\bshift.*jis$/i => '"shiftjis"' ); + define_alias( qr/\bsjis$/i => '"shiftjis"' ); + define_alias( qr/\bwindows-31j$/i => '"cp932"' ); + + # for Encode::KR + define_alias( qr/\beuc.*kr$/i => '"euc-kr"' ); + define_alias( qr/\bkr.*euc$/i => '"euc-kr"' ); + + # This fixes ksc5601 vs. euc-kr confusion, practically + define_alias( qr/(?:x-)?uhc$/i => '"cp949"' ); + define_alias( qr/(?:x-)?windows-949$/i => '"cp949"' ); + define_alias( qr/\bks_c_5601-1987$/i => '"cp949"' ); + + # for Encode::TW + define_alias( qr/\bbig-?5$/i => '"big5-eten"' ); + define_alias( qr/\bbig5-?et(?:en)?$/i => '"big5-eten"' ); + define_alias( qr/\btca[-_]?big5$/i => '"big5-eten"' ); + define_alias( qr/\bbig5-?hk(?:scs)?$/i => '"big5-hkscs"' ); + define_alias( qr/\bhk(?:scs)?[-_]?big5$/i => '"big5-hkscs"' ); + } + + # utf8 is blessed :) + define_alias( qr/\bUTF-8$/i => '"utf-8-strict"' ); + + # At last, Map white space and _ to '-' + define_alias( qr/^(\S+)[\s_]+(.*)$/i => '"$1-$2"' ); +} + +1; +__END__ + +# TODO: HP-UX '8' encodings arabic8 greek8 hebrew8 kana8 thai8 turkish8 +# TODO: HP-UX '15' encodings japanese15 korean15 roi15 +# TODO: Cyrillic encoding ISO-IR-111 (useful?) +# TODO: Armenian encoding ARMSCII-8 +# TODO: Hebrew encoding ISO-8859-8-1 +# TODO: Thai encoding TCVN +# TODO: Vietnamese encodings VPS +# TODO: Mac Asian+African encodings: Arabic Armenian Bengali Burmese +# ChineseSimp ChineseTrad Devanagari Ethiopic ExtArabic +# Farsi Georgian Gujarati Gurmukhi Hebrew Japanese +# Kannada Khmer Korean Laotian Malayalam Mongolian +# Oriya Sinhalese Symbol Tamil Telugu Tibetan Vietnamese + +=head1 NAME + +Encode::Alias - alias definitions to encodings + +=head1 SYNOPSIS + + use Encode; + use Encode::Alias; + define_alias( newName => ENCODING); + +=head1 DESCRIPTION + +Allows newName to be used as an alias for ENCODING. ENCODING may be +either the name of an encoding or an encoding object (as described +in L<Encode>). + +Currently I<newName> can be specified in the following ways: + +=over 4 + +=item As a simple string. + +=item As a qr// compiled regular expression, e.g.: + + define_alias( qr/^iso8859-(\d+)$/i => '"iso-8859-$1"' ); + +In this case, if I<ENCODING> is not a reference, it is C<eval>-ed +in order to allow C<$1> etc. to be substituted. The example is one +way to alias names as used in X11 fonts to the MIME names for the +iso-8859-* family. Note the double quotes inside the single quotes. + +(or, you don't have to do this yourself because this example is predefined) + +If you are using a regex here, you have to use the quotes as shown or +it won't work. Also note that regex handling is tricky even for the +experienced. Use this feature with caution. + +=item As a code reference, e.g.: + + define_alias( sub {shift =~ /^iso8859-(\d+)$/i ? "iso-8859-$1" : undef } ); + +The same effect as the example above in a different way. The coderef +takes the alias name as an argument and returns a canonical name on +success or undef if not. Note the second argument is not required. +Use this with even more caution than the regex version. + +=back + +=head3 Changes in code reference aliasing + +As of Encode 1.87, the older form + + define_alias( sub { return /^iso8859-(\d+)$/i ? "iso-8859-$1" : undef } ); + +no longer works. + +Encode up to 1.86 internally used "local $_" to implement ths older +form. But consider the code below; + + use Encode; + $_ = "eeeee" ; + while (/(e)/g) { + my $utf = decode('aliased-encoding-name', $1); + print "position:",pos,"\n"; + } + +Prior to Encode 1.86 this fails because of "local $_". + +=head2 Alias overloading + +You can override predefined aliases by simply applying define_alias(). +The new alias is always evaluated first, and when necessary, +define_alias() flushes the internal cache to make the new definition +available. + + # redirect SHIFT_JIS to MS/IBM Code Page 932, which is a + # superset of SHIFT_JIS + + define_alias( qr/shift.*jis$/i => '"cp932"' ); + define_alias( qr/sjis$/i => '"cp932"' ); + +If you want to zap all predefined aliases, you can use + + Encode::Alias->undef_aliases; + +to do so. And + + Encode::Alias->init_aliases; + +gets the factory settings back. + +=head1 SEE ALSO + +L<Encode>, L<Encode::Supported> + +=cut + diff --git a/Master/tlpkg/tlperl/lib/Encode/Byte.pm b/Master/tlpkg/tlperl/lib/Encode/Byte.pm new file mode 100644 index 00000000000..d105aa27cc8 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/Byte.pm @@ -0,0 +1,120 @@ +package Encode::Byte; +use strict; +use warnings; +use Encode; +our $VERSION = do { my @r = ( q$Revision: 2.4 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; + +use XSLoader; +XSLoader::load( __PACKAGE__, $VERSION ); + +1; +__END__ + +=head1 NAME + +Encode::Byte - Single Byte Encodings + +=head1 SYNOPSIS + + use Encode qw/encode decode/; + $greek = encode("iso-8859-7", $utf8); # loads Encode::Byte implicitly + $utf8 = decode("iso-8859-7", $greek); # ditto + +=head1 ABSTRACT + +This module implements various single byte encodings. For most cases it uses +\x80-\xff (upper half) to map non-ASCII characters. Encodings +supported are as follows. + + Canonical Alias Description + -------------------------------------------------------------------- + # ISO 8859 series + (iso-8859-1 is in built-in) + iso-8859-2 latin2 [ISO] + iso-8859-3 latin3 [ISO] + iso-8859-4 latin4 [ISO] + iso-8859-5 [ISO] + iso-8859-6 [ISO] + iso-8859-7 [ISO] + iso-8859-8 [ISO] + iso-8859-9 latin5 [ISO] + iso-8859-10 latin6 [ISO] + iso-8859-11 + (iso-8859-12 is nonexistent) + iso-8859-13 latin7 [ISO] + iso-8859-14 latin8 [ISO] + iso-8859-15 latin9 [ISO] + iso-8859-16 latin10 [ISO] + + # Cyrillic + koi8-f + koi8-r cp878 [RFC1489] + koi8-u [RFC2319] + + # Vietnamese + viscii + + # all cp* are also available as ibm-*, ms-*, and windows-* + # also see L<http://msdn.microsoft.com/en-us/library/aa752010%28VS.85%29.aspx> + + cp424 + cp437 + cp737 + cp775 + cp850 + cp852 + cp855 + cp856 + cp857 + cp860 + cp861 + cp862 + cp863 + cp864 + cp865 + cp866 + cp869 + cp874 + cp1006 + cp1250 WinLatin2 + cp1251 WinCyrillic + cp1252 WinLatin1 + cp1253 WinGreek + cp1254 WinTurkish + cp1255 WinHebrew + cp1256 WinArabic + cp1257 WinBaltic + cp1258 WinVietnamese + + # Macintosh + # Also see L<http://developer.apple.com/technotes/tn/tn1150.html> + MacArabic + MacCentralEurRoman + MacCroatian + MacCyrillic + MacFarsi + MacGreek + MacHebrew + MacIcelandic + MacRoman + MacRomanian + MacRumanian + MacSami + MacThai + MacTurkish + MacUkrainian + + # More vendor encodings + AdobeStandardEncoding + nextstep + hp-roman8 + +=head1 DESCRIPTION + +To find how to use this module in detail, see L<Encode>. + +=head1 SEE ALSO + +L<Encode> + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/CJKConstants.pm b/Master/tlpkg/tlperl/lib/Encode/CJKConstants.pm new file mode 100644 index 00000000000..43d20337544 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/CJKConstants.pm @@ -0,0 +1,66 @@ +# +# $Id: CJKConstants.pm,v 2.2 2006/06/03 20:28:48 dankogai Exp $ +# + +package Encode::CJKConstants; + +use strict; +use warnings; +our $RCSID = q$Id: CJKConstants.pm,v 2.2 2006/06/03 20:28:48 dankogai Exp $; +our $VERSION = do { my @r = ( q$Revision: 2.2 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; + +use Carp; + +require Exporter; +our @ISA = qw(Exporter); +our @EXPORT = qw(); +our @EXPORT_OK = qw(%CHARCODE %ESC %RE); +our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK, @EXPORT ] ); + +my %_0208 = ( + 1978 => '\e\$\@', + 1983 => '\e\$B', + 1990 => '\e&\@\e\$B', +); + +our %CHARCODE = ( + UNDEF_EUC => "\xa2\xae", # ¢® in EUC + UNDEF_SJIS => "\x81\xac", # ¢® in SJIS + UNDEF_JIS => "\xa2\xf7", # ¢÷ -- used in unicode + UNDEF_UNICODE => "\x20\x20", # ¢÷ -- used in unicode +); + +our %ESC = ( + GB_2312 => "\e\$A", + JIS_0208 => "\e\$B", + JIS_0212 => "\e\$(D", + KSC_5601 => "\e\$(C", + ASC => "\e\(B", + KANA => "\e\(I", + '2022_KR' => "\e\$)C", +); + +our %RE = ( + ASCII => '[\x00-\x7f]', + BIN => '[\x00-\x06\x7f\xff]', + EUC_0212 => '\x8f[\xa1-\xfe][\xa1-\xfe]', + EUC_C => '[\xa1-\xfe][\xa1-\xfe]', + EUC_KANA => '\x8e[\xa1-\xdf]', + JIS_0208 => "$_0208{1978}|$_0208{1983}|$_0208{1990}", + JIS_0212 => "\e" . '\$\(D', + ISO_ASC => "\e" . '\([BJ]', + JIS_KANA => "\e" . '\(I', + '2022_KR' => "\e" . '\$\)C', + SJIS_C => '[\x81-\x9f\xe0-\xfc][\x40-\x7e\x80-\xfc]', + SJIS_KANA => '[\xa1-\xdf]', + UTF8 => '[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf][\x80-\xbf]' +); + +1; + +=head1 NAME + +Encode::CJKConstants.pm -- Internally used by Encode::??::ISO_2022_* + +=cut + diff --git a/Master/tlpkg/tlperl/lib/Encode/CN.pm b/Master/tlpkg/tlperl/lib/Encode/CN.pm new file mode 100644 index 00000000000..830f34507da --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/CN.pm @@ -0,0 +1,74 @@ +package Encode::CN; +BEGIN { + if ( ord("A") == 193 ) { + die "Encode::CN not supported on EBCDIC\n"; + } +} +use strict; +use warnings; +use Encode; +our $VERSION = do { my @r = ( q$Revision: 2.3 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; +use XSLoader; +XSLoader::load( __PACKAGE__, $VERSION ); + +# Relocated from Encode.pm + +use Encode::CN::HZ; + +# use Encode::CN::2022_CN; + +1; +__END__ + +=head1 NAME + +Encode::CN - China-based Chinese Encodings + +=head1 SYNOPSIS + + use Encode qw/encode decode/; + $euc_cn = encode("euc-cn", $utf8); # loads Encode::CN implicitly + $utf8 = decode("euc-cn", $euc_cn); # ditto + +=head1 DESCRIPTION + +This module implements China-based Chinese charset encodings. +Encodings supported are as follows. + + Canonical Alias Description + -------------------------------------------------------------------- + euc-cn /\beuc.*cn$/i EUC (Extended Unix Character) + /\bcn.*euc$/i + /\bGB[-_ ]?2312(?:\D.*$|$)/i (see below) + gb2312-raw The raw (low-bit) GB2312 character map + gb12345-raw Traditional chinese counterpart to + GB2312 (raw) + iso-ir-165 GB2312 + GB6345 + GB8565 + additions + MacChineseSimp GB2312 + Apple Additions + cp936 Code Page 936, also known as GBK + (Extended GuoBiao) + hz 7-bit escaped GB2312 encoding + -------------------------------------------------------------------- + +To find how to use this module in detail, see L<Encode>. + +=head1 NOTES + +Due to size concerns, C<GB 18030> (an extension to C<GBK>) is distributed +separately on CPAN, under the name L<Encode::HanExtra>. That module +also contains extra Taiwan-based encodings. + +=head1 BUGS + +When you see C<charset=gb2312> on mails and web pages, they really +mean C<euc-cn> encodings. To fix that, C<gb2312> is aliased to C<euc-cn>. +Use C<gb2312-raw> when you really mean it. + +The ASCII region (0x00-0x7f) is preserved for all encodings, even though +this conflicts with mappings by the Unicode Consortium. + +=head1 SEE ALSO + +L<Encode> + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/CN/HZ.pm b/Master/tlpkg/tlperl/lib/Encode/CN/HZ.pm new file mode 100644 index 00000000000..98c16a9053a --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/CN/HZ.pm @@ -0,0 +1,198 @@ +package Encode::CN::HZ; + +use strict; +use warnings; +use utf8 (); + +use vars qw($VERSION); +$VERSION = do { my @r = ( q$Revision: 2.5 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; + +use Encode qw(:fallbacks); + +use base qw(Encode::Encoding); +__PACKAGE__->Define('hz'); + +# HZ is a combination of ASCII and escaped GB, so we implement it +# with the GB2312(raw) encoding here. Cf. RFCs 1842 & 1843. + +# not ported for EBCDIC. Which should be used, "~" or "\x7E"? + +sub needs_lines { 1 } + +sub decode ($$;$) { + my ( $obj, $str, $chk ) = @_; + + my $GB = Encode::find_encoding('gb2312-raw'); + my $ret = ''; + my $in_ascii = 1; # default mode is ASCII. + + while ( length $str ) { + if ($in_ascii) { # ASCII mode + if ( $str =~ s/^([\x00-\x7D\x7F]+)// ) { # no '~' => ASCII + $ret .= $1; + + # EBCDIC should need ascii2native, but not ported. + } + elsif ( $str =~ s/^\x7E\x7E// ) { # escaped tilde + $ret .= '~'; + } + elsif ( $str =~ s/^\x7E\cJ// ) { # '\cJ' == LF in ASCII + 1; # no-op + } + elsif ( $str =~ s/^\x7E\x7B// ) { # '~{' + $in_ascii = 0; # to GB + } + else { # encounters an invalid escape, \x80 or greater + last; + } + } + else { # GB mode; the byte ranges are as in RFC 1843. + no warnings 'uninitialized'; + if ( $str =~ s/^((?:[\x21-\x77][\x21-\x7E])+)// ) { + $ret .= $GB->decode( $1, $chk ); + } + elsif ( $str =~ s/^\x7E\x7D// ) { # '~}' + $in_ascii = 1; + } + else { # invalid + last; + } + } + } + $_[1] = '' if $chk; # needs_lines guarantees no partial character + return $ret; +} + +sub cat_decode { + my ( $obj, undef, $src, $pos, $trm, $chk ) = @_; + my ( $rdst, $rsrc, $rpos ) = \@_[ 1 .. 3 ]; + + my $GB = Encode::find_encoding('gb2312-raw'); + my $ret = ''; + my $in_ascii = 1; # default mode is ASCII. + + my $ini_pos = pos($$rsrc); + + substr( $src, 0, $pos ) = ''; + + my $ini_len = bytes::length($src); + + # $trm is the first of the pair '~~', then 2nd tilde is to be removed. + # XXX: Is better C<$src =~ s/^\x7E// or die if ...>? + $src =~ s/^\x7E// if $trm eq "\x7E"; + + while ( length $src ) { + my $now; + if ($in_ascii) { # ASCII mode + if ( $src =~ s/^([\x00-\x7D\x7F])// ) { # no '~' => ASCII + $now = $1; + } + elsif ( $src =~ s/^\x7E\x7E// ) { # escaped tilde + $now = '~'; + } + elsif ( $src =~ s/^\x7E\cJ// ) { # '\cJ' == LF in ASCII + next; + } + elsif ( $src =~ s/^\x7E\x7B// ) { # '~{' + $in_ascii = 0; # to GB + next; + } + else { # encounters an invalid escape, \x80 or greater + last; + } + } + else { # GB mode; the byte ranges are as in RFC 1843. + if ( $src =~ s/^((?:[\x21-\x77][\x21-\x7F])+)// ) { + $now = $GB->decode( $1, $chk ); + } + elsif ( $src =~ s/^\x7E\x7D// ) { # '~}' + $in_ascii = 1; + next; + } + else { # invalid + last; + } + } + + next if !defined $now; + + $ret .= $now; + + if ( $now eq $trm ) { + $$rdst .= $ret; + $$rpos = $ini_pos + $pos + $ini_len - bytes::length($src); + pos($$rsrc) = $ini_pos; + return 1; + } + } + + $$rdst .= $ret; + $$rpos = $ini_pos + $pos + $ini_len - bytes::length($src); + pos($$rsrc) = $ini_pos; + return ''; # terminator not found +} + +sub encode($$;$) { + my ( $obj, $str, $chk ) = @_; + + my $GB = Encode::find_encoding('gb2312-raw'); + my $ret = ''; + my $in_ascii = 1; # default mode is ASCII. + + no warnings 'utf8'; # $str may be malformed UTF8 at the end of a chunk. + + while ( length $str ) { + if ( $str =~ s/^([[:ascii:]]+)// ) { + my $tmp = $1; + $tmp =~ s/~/~~/g; # escapes tildes + if ( !$in_ascii ) { + $ret .= "\x7E\x7D"; # '~}' + $in_ascii = 1; + } + $ret .= pack 'a*', $tmp; # remove UTF8 flag. + } + elsif ( $str =~ s/(.)// ) { + my $s = $1; + my $tmp = $GB->encode( $s, $chk ); + last if !defined $tmp; + if ( length $tmp == 2 ) { # maybe a valid GB char (XXX) + if ($in_ascii) { + $ret .= "\x7E\x7B"; # '~{' + $in_ascii = 0; + } + $ret .= $tmp; + } + elsif ( length $tmp ) { # maybe FALLBACK in ASCII (XXX) + if ( !$in_ascii ) { + $ret .= "\x7E\x7D"; # '~}' + $in_ascii = 1; + } + $ret .= $tmp; + } + } + else { # if $str is malformed UTF8 *and* if length $str != 0. + last; + } + } + $_[1] = $str if $chk; + + # The state at the end of the chunk is discarded, even if in GB mode. + # That results in the combination of GB-OUT and GB-IN, i.e. "~}~{". + # Parhaps it is harmless, but further investigations may be required... + + if ( !$in_ascii ) { + $ret .= "\x7E\x7D"; # '~}' + $in_ascii = 1; + } + utf8::encode($ret); # https://rt.cpan.org/Ticket/Display.html?id=35120 + return $ret; +} + +1; +__END__ + +=head1 NAME + +Encode::CN::HZ -- internally used by Encode::CN + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/Changes.e2x b/Master/tlpkg/tlperl/lib/Encode/Changes.e2x new file mode 100644 index 00000000000..5c67c55cb93 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/Changes.e2x @@ -0,0 +1,7 @@ +# +# $Id: Changes.e2x,v 2.0 2004/05/16 20:55:15 dankogai Exp $ +# Revision history for Perl extension Encode::$_Name_. +# + +0.01 $_Now_ + Autogenerated by enc2xs version $_Version_. diff --git a/Master/tlpkg/tlperl/lib/Encode/Config.pm b/Master/tlpkg/tlperl/lib/Encode/Config.pm new file mode 100644 index 00000000000..1286a479998 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/Config.pm @@ -0,0 +1,170 @@ +# +# Demand-load module list +# +package Encode::Config; +our $VERSION = do { my @r = ( q$Revision: 2.5 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; + +use strict; +use warnings; + +our %ExtModule = ( + + # Encode::Byte + #iso-8859-1 is in Encode.pm itself + 'iso-8859-2' => 'Encode::Byte', + 'iso-8859-3' => 'Encode::Byte', + 'iso-8859-4' => 'Encode::Byte', + 'iso-8859-5' => 'Encode::Byte', + 'iso-8859-6' => 'Encode::Byte', + 'iso-8859-7' => 'Encode::Byte', + 'iso-8859-8' => 'Encode::Byte', + 'iso-8859-9' => 'Encode::Byte', + 'iso-8859-10' => 'Encode::Byte', + 'iso-8859-11' => 'Encode::Byte', + 'iso-8859-13' => 'Encode::Byte', + 'iso-8859-14' => 'Encode::Byte', + 'iso-8859-15' => 'Encode::Byte', + 'iso-8859-16' => 'Encode::Byte', + 'koi8-f' => 'Encode::Byte', + 'koi8-r' => 'Encode::Byte', + 'koi8-u' => 'Encode::Byte', + 'viscii' => 'Encode::Byte', + 'cp424' => 'Encode::Byte', + 'cp437' => 'Encode::Byte', + 'cp737' => 'Encode::Byte', + 'cp775' => 'Encode::Byte', + 'cp850' => 'Encode::Byte', + 'cp852' => 'Encode::Byte', + 'cp855' => 'Encode::Byte', + 'cp856' => 'Encode::Byte', + 'cp857' => 'Encode::Byte', + 'cp858' => 'Encode::Byte', + 'cp860' => 'Encode::Byte', + 'cp861' => 'Encode::Byte', + 'cp862' => 'Encode::Byte', + 'cp863' => 'Encode::Byte', + 'cp864' => 'Encode::Byte', + 'cp865' => 'Encode::Byte', + 'cp866' => 'Encode::Byte', + 'cp869' => 'Encode::Byte', + 'cp874' => 'Encode::Byte', + 'cp1006' => 'Encode::Byte', + 'cp1250' => 'Encode::Byte', + 'cp1251' => 'Encode::Byte', + 'cp1252' => 'Encode::Byte', + 'cp1253' => 'Encode::Byte', + 'cp1254' => 'Encode::Byte', + 'cp1255' => 'Encode::Byte', + 'cp1256' => 'Encode::Byte', + 'cp1257' => 'Encode::Byte', + 'cp1258' => 'Encode::Byte', + 'AdobeStandardEncoding' => 'Encode::Byte', + 'MacArabic' => 'Encode::Byte', + 'MacCentralEurRoman' => 'Encode::Byte', + 'MacCroatian' => 'Encode::Byte', + 'MacCyrillic' => 'Encode::Byte', + 'MacFarsi' => 'Encode::Byte', + 'MacGreek' => 'Encode::Byte', + 'MacHebrew' => 'Encode::Byte', + 'MacIcelandic' => 'Encode::Byte', + 'MacRoman' => 'Encode::Byte', + 'MacRomanian' => 'Encode::Byte', + 'MacRumanian' => 'Encode::Byte', + 'MacSami' => 'Encode::Byte', + 'MacThai' => 'Encode::Byte', + 'MacTurkish' => 'Encode::Byte', + 'MacUkrainian' => 'Encode::Byte', + 'nextstep' => 'Encode::Byte', + 'hp-roman8' => 'Encode::Byte', + #'gsm0338' => 'Encode::Byte', + 'gsm0338' => 'Encode::GSM0338', + + # Encode::EBCDIC + 'cp37' => 'Encode::EBCDIC', + 'cp500' => 'Encode::EBCDIC', + 'cp875' => 'Encode::EBCDIC', + 'cp1026' => 'Encode::EBCDIC', + 'cp1047' => 'Encode::EBCDIC', + 'posix-bc' => 'Encode::EBCDIC', + + # Encode::Symbol + 'dingbats' => 'Encode::Symbol', + 'symbol' => 'Encode::Symbol', + 'AdobeSymbol' => 'Encode::Symbol', + 'AdobeZdingbat' => 'Encode::Symbol', + 'MacDingbats' => 'Encode::Symbol', + 'MacSymbol' => 'Encode::Symbol', + + # Encode::Unicode + 'UCS-2BE' => 'Encode::Unicode', + 'UCS-2LE' => 'Encode::Unicode', + 'UTF-16' => 'Encode::Unicode', + 'UTF-16BE' => 'Encode::Unicode', + 'UTF-16LE' => 'Encode::Unicode', + 'UTF-32' => 'Encode::Unicode', + 'UTF-32BE' => 'Encode::Unicode', + 'UTF-32LE' => 'Encode::Unicode', + 'UTF-7' => 'Encode::Unicode::UTF7', +); + +unless ( ord("A") == 193 ) { + %ExtModule = ( + %ExtModule, + 'euc-cn' => 'Encode::CN', + 'gb12345-raw' => 'Encode::CN', + 'gb2312-raw' => 'Encode::CN', + 'hz' => 'Encode::CN', + 'iso-ir-165' => 'Encode::CN', + 'cp936' => 'Encode::CN', + 'MacChineseSimp' => 'Encode::CN', + + '7bit-jis' => 'Encode::JP', + 'euc-jp' => 'Encode::JP', + 'iso-2022-jp' => 'Encode::JP', + 'iso-2022-jp-1' => 'Encode::JP', + 'jis0201-raw' => 'Encode::JP', + 'jis0208-raw' => 'Encode::JP', + 'jis0212-raw' => 'Encode::JP', + 'cp932' => 'Encode::JP', + 'MacJapanese' => 'Encode::JP', + 'shiftjis' => 'Encode::JP', + + 'euc-kr' => 'Encode::KR', + 'iso-2022-kr' => 'Encode::KR', + 'johab' => 'Encode::KR', + 'ksc5601-raw' => 'Encode::KR', + 'cp949' => 'Encode::KR', + 'MacKorean' => 'Encode::KR', + + 'big5-eten' => 'Encode::TW', + 'big5-hkscs' => 'Encode::TW', + 'cp950' => 'Encode::TW', + 'MacChineseTrad' => 'Encode::TW', + + #'big5plus' => 'Encode::HanExtra', + #'euc-tw' => 'Encode::HanExtra', + #'gb18030' => 'Encode::HanExtra', + + 'MIME-Header' => 'Encode::MIME::Header', + 'MIME-B' => 'Encode::MIME::Header', + 'MIME-Q' => 'Encode::MIME::Header', + + 'MIME-Header-ISO_2022_JP' => 'Encode::MIME::Header::ISO_2022_JP', + ); +} + +# +# Why not export ? to keep ConfigLocal Happy! +# +while ( my ( $enc, $mod ) = each %ExtModule ) { + $Encode::ExtModule{$enc} = $mod; +} + +1; +__END__ + +=head1 NAME + +Encode::Config -- internally used by Encode + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/ConfigLocal_PM.e2x b/Master/tlpkg/tlperl/lib/Encode/ConfigLocal_PM.e2x new file mode 100644 index 00000000000..e203dfded50 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/ConfigLocal_PM.e2x @@ -0,0 +1,13 @@ +# +# Local demand-load module list +# +# You should not edit this file by hand! use "enc2xs -C" +# +package Encode::ConfigLocal; +our $VERSION = $_LocalVer_; + +use strict; + +$_ModLines_ + +1; diff --git a/Master/tlpkg/tlperl/lib/Encode/EBCDIC.pm b/Master/tlpkg/tlperl/lib/Encode/EBCDIC.pm new file mode 100644 index 00000000000..8024c130da1 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/EBCDIC.pm @@ -0,0 +1,45 @@ +package Encode::EBCDIC; +use strict; +use warnings; +use Encode; +our $VERSION = do { my @r = ( q$Revision: 2.2 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; + +use XSLoader; +XSLoader::load( __PACKAGE__, $VERSION ); + +1; +__END__ + +=head1 NAME + +Encode::EBCDIC - EBCDIC Encodings + +=head1 SYNOPSIS + + use Encode qw/encode decode/; + $posix_bc = encode("posix-bc", $utf8); # loads Encode::EBCDIC implicitly + $utf8 = decode("", $posix_bc); # ditto + +=head1 ABSTRACT + +This module implements various EBCDIC-Based encodings. Encodings +supported are as follows. + + Canonical Alias Description + -------------------------------------------------------------------- + cp37 + cp500 + cp875 + cp1026 + cp1047 + posix-bc + +=head1 DESCRIPTION + +To find how to use this module in detail, see L<Encode>. + +=head1 SEE ALSO + +L<Encode>, L<perlebcdic> + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/Encoder.pm b/Master/tlpkg/tlperl/lib/Encode/Encoder.pm new file mode 100644 index 00000000000..f7194f81ac4 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/Encoder.pm @@ -0,0 +1,253 @@ +# +# $Id: Encoder.pm,v 2.1 2006/05/03 18:24:10 dankogai Exp $ +# +package Encode::Encoder; +use strict; +use warnings; +our $VERSION = do { my @r = ( q$Revision: 2.1 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; + +require Exporter; +our @ISA = qw(Exporter); +our @EXPORT_OK = qw ( encoder ); + +our $AUTOLOAD; +sub DEBUG () { 0 } +use Encode qw(encode decode find_encoding from_to); +use Carp; + +sub new { + my ( $class, $data, $encname ) = @_; + unless ($encname) { + $encname = Encode::is_utf8($data) ? 'utf8' : ''; + } + else { + my $obj = find_encoding($encname) + or croak __PACKAGE__, ": unknown encoding: $encname"; + $encname = $obj->name; + } + my $self = { + data => $data, + encoding => $encname, + }; + bless $self => $class; +} + +sub encoder { __PACKAGE__->new(@_) } + +sub data { + my ( $self, $data ) = @_; + if ( defined $data ) { + $self->{data} = $data; + return $data; + } + else { + return $self->{data}; + } +} + +sub encoding { + my ( $self, $encname ) = @_; + if ($encname) { + my $obj = find_encoding($encname) + or confess __PACKAGE__, ": unknown encoding: $encname"; + $self->{encoding} = $obj->name; + return $self; + } + else { + return $self->{encoding}; + } +} + +sub bytes { + my ( $self, $encname ) = @_; + $encname ||= $self->{encoding}; + my $obj = find_encoding($encname) + or confess __PACKAGE__, ": unknown encoding: $encname"; + $self->{data} = $obj->decode( $self->{data}, 1 ); + $self->{encoding} = ''; + return $self; +} + +sub DESTROY { # defined so it won't autoload. + DEBUG and warn shift; +} + +sub AUTOLOAD { + my $self = shift; + my $type = ref($self) + or confess "$self is not an object"; + my $myname = $AUTOLOAD; + $myname =~ s/.*://; # strip fully-qualified portion + my $obj = find_encoding($myname) + or confess __PACKAGE__, ": unknown encoding: $myname"; + DEBUG and warn $self->{encoding}, " => ", $obj->name; + if ( $self->{encoding} ) { + from_to( $self->{data}, $self->{encoding}, $obj->name, 1 ); + } + else { + $self->{data} = $obj->encode( $self->{data}, 1 ); + } + $self->{encoding} = $obj->name; + return $self; +} + +use overload + q("") => sub { $_[0]->{data} }, + q(0+) => sub { use bytes(); bytes::length( $_[0]->{data} ) }, + fallback => 1, + ; + +1; +__END__ + +=head1 NAME + +Encode::Encoder -- Object Oriented Encoder + +=head1 SYNOPSIS + + use Encode::Encoder; + # Encode::encode("ISO-8859-1", $data); + Encode::Encoder->new($data)->iso_8859_1; # OOP way + # shortcut + use Encode::Encoder qw(encoder); + encoder($data)->iso_8859_1; + # you can stack them! + encoder($data)->iso_8859_1->base64; # provided base64() is defined + # you can use it as a decoder as well + encoder($base64)->bytes('base64')->latin1; + # stringified + print encoder($data)->utf8->latin1; # prints the string in latin1 + # numified + encoder("\x{abcd}\x{ef}g")->utf8 == 6; # true. bytes::length($data) + +=head1 ABSTRACT + +B<Encode::Encoder> allows you to use Encode in an object-oriented +style. This is not only more intuitive than a functional approach, +but also handier when you want to stack encodings. Suppose you want +your UTF-8 string converted to Latin1 then Base64: you can simply say + + my $base64 = encoder($utf8)->latin1->base64; + +instead of + + my $latin1 = encode("latin1", $utf8); + my $base64 = encode_base64($utf8); + +or the lazier and more convoluted + + my $base64 = encode_base64(encode("latin1", $utf8)); + +=head1 Description + +Here is how to use this module. + +=over 4 + +=item * + +There are at least two instance variables stored in a hash reference, +{data} and {encoding}. + +=item * + +When there is no method, it takes the method name as the name of the +encoding and encodes the instance I<data> with I<encoding>. If successful, +the instance I<encoding> is set accordingly. + +=item * + +You can retrieve the result via -E<gt>data but usually you don't have to +because the stringify operator ("") is overridden to do exactly that. + +=back + +=head2 Predefined Methods + +This module predefines the methods below: + +=over 4 + +=item $e = Encode::Encoder-E<gt>new([$data, $encoding]); + +returns an encoder object. Its data is initialized with $data if +present, and its encoding is set to $encoding if present. + +When $encoding is omitted, it defaults to utf8 if $data is already in +utf8 or "" (empty string) otherwise. + +=item encoder() + +is an alias of Encode::Encoder-E<gt>new(). This one is exported on demand. + +=item $e-E<gt>data([$data]) + +When $data is present, sets the instance data to $data and returns the +object itself. Otherwise, the current instance data is returned. + +=item $e-E<gt>encoding([$encoding]) + +When $encoding is present, sets the instance encoding to $encoding and +returns the object itself. Otherwise, the current instance encoding is +returned. + +=item $e-E<gt>bytes([$encoding]) + +decodes instance data from $encoding, or the instance encoding if +omitted. If the conversion is successful, the instance encoding +will be set to "". + +The name I<bytes> was deliberately picked to avoid namespace tainting +-- this module may be used as a base class so method names that appear +in Encode::Encoding are avoided. + +=back + +=head2 Example: base64 transcoder + +This module is designed to work with L<Encode::Encoding>. +To make the Base64 transcoder example above really work, you could +write a module like this: + + package Encode::Base64; + use base 'Encode::Encoding'; + __PACKAGE__->Define('base64'); + use MIME::Base64; + sub encode{ + my ($obj, $data) = @_; + return encode_base64($data); + } + sub decode{ + my ($obj, $data) = @_; + return decode_base64($data); + } + 1; + __END__ + +And your caller module would be something like this: + + use Encode::Encoder; + use Encode::Base64; + + # now you can really do the following + + encoder($data)->iso_8859_1->base64; + encoder($base64)->bytes('base64')->latin1; + +=head2 Operator Overloading + +This module overloads two operators, stringify ("") and numify (0+). + +Stringify dumps the data inside the object. + +Numify returns the number of bytes in the instance data. + +They come in handy when you want to print or find the size of data. + +=head1 SEE ALSO + +L<Encode>, +L<Encode::Encoding> + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/Encoding.pm b/Master/tlpkg/tlperl/lib/Encode/Encoding.pm new file mode 100644 index 00000000000..768d6d126ac --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/Encoding.pm @@ -0,0 +1,360 @@ +package Encode::Encoding; + +# Base class for classes which implement encodings +use strict; +use warnings; +our $VERSION = do { my @r = ( q$Revision: 2.5 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; + +require Encode; + +sub DEBUG { 0 } + +sub Define { + my $obj = shift; + my $canonical = shift; + $obj = bless { Name => $canonical }, $obj unless ref $obj; + + # warn "$canonical => $obj\n"; + Encode::define_encoding( $obj, $canonical, @_ ); +} + +sub name { return shift->{'Name'} } + +sub mime_name{ + require Encode::MIME::Name; + return Encode::MIME::Name::get_mime_name(shift->name); +} + +# sub renew { return $_[0] } + +sub renew { + my $self = shift; + my $clone = bless {%$self} => ref($self); + $clone->{renewed}++; # so the caller can see it + DEBUG and warn $clone->{renewed}; + return $clone; +} + +sub renewed { return $_[0]->{renewed} || 0 } + +*new_sequence = \&renew; + +sub needs_lines { 0 } + +sub perlio_ok { + eval { require PerlIO::encoding }; + return $@ ? 0 : 1; +} + +# (Temporary|legacy) methods + +sub toUnicode { shift->decode(@_) } +sub fromUnicode { shift->encode(@_) } + +# +# Needs to be overloaded or just croak +# + +sub encode { + require Carp; + my $obj = shift; + my $class = ref($obj) ? ref($obj) : $obj; + Carp::croak( $class . "->encode() not defined!" ); +} + +sub decode { + require Carp; + my $obj = shift; + my $class = ref($obj) ? ref($obj) : $obj; + Carp::croak( $class . "->encode() not defined!" ); +} + +sub DESTROY { } + +1; +__END__ + +=head1 NAME + +Encode::Encoding - Encode Implementation Base Class + +=head1 SYNOPSIS + + package Encode::MyEncoding; + use base qw(Encode::Encoding); + + __PACKAGE__->Define(qw(myCanonical myAlias)); + +=head1 DESCRIPTION + +As mentioned in L<Encode>, encodings are (in the current +implementation at least) defined as objects. The mapping of encoding +name to object is via the C<%Encode::Encoding> hash. Though you can +directly manipulate this hash, it is strongly encouraged to use this +base class module and add encode() and decode() methods. + +=head2 Methods you should implement + +You are strongly encouraged to implement methods below, at least +either encode() or decode(). + +=over 4 + +=item -E<gt>encode($string [,$check]) + +MUST return the octet sequence representing I<$string>. + +=over 2 + +=item * + +If I<$check> is true, it SHOULD modify I<$string> in place to remove +the converted part (i.e. the whole string unless there is an error). +If perlio_ok() is true, SHOULD becomes MUST. + +=item * + +If an error occurs, it SHOULD return the octet sequence for the +fragment of string that has been converted and modify $string in-place +to remove the converted part leaving it starting with the problem +fragment. If perlio_ok() is true, SHOULD becomes MUST. + +=item * + +If I<$check> is is false then C<encode> MUST make a "best effort" to +convert the string - for example, by using a replacement character. + +=back + +=item -E<gt>decode($octets [,$check]) + +MUST return the string that I<$octets> represents. + +=over 2 + +=item * + +If I<$check> is true, it SHOULD modify I<$octets> in place to remove +the converted part (i.e. the whole sequence unless there is an +error). If perlio_ok() is true, SHOULD becomes MUST. + +=item * + +If an error occurs, it SHOULD return the fragment of string that has +been converted and modify $octets in-place to remove the converted +part leaving it starting with the problem fragment. If perlio_ok() is +true, SHOULD becomes MUST. + +=item * + +If I<$check> is false then C<decode> should make a "best effort" to +convert the string - for example by using Unicode's "\x{FFFD}" as a +replacement character. + +=back + +=back + +If you want your encoding to work with L<encoding> pragma, you should +also implement the method below. + +=over 4 + +=item -E<gt>cat_decode($destination, $octets, $offset, $terminator [,$check]) + +MUST decode I<$octets> with I<$offset> and concatenate it to I<$destination>. +Decoding will terminate when $terminator (a string) appears in output. +I<$offset> will be modified to the last $octets position at end of decode. +Returns true if $terminator appears output, else returns false. + +=back + +=head2 Other methods defined in Encode::Encodings + +You do not have to override methods shown below unless you have to. + +=over 4 + +=item -E<gt>name + +Predefined As: + + sub name { return shift->{'Name'} } + +MUST return the string representing the canonical name of the encoding. + +=item -E<gt>mime_name + +Predefined As: + + sub mime_name{ + require Encode::MIME::Name; + return Encode::MIME::Name::get_mime_name(shift->name); + } + +MUST return the string representing the IANA charset name of the encoding. + +=item -E<gt>renew + +Predefined As: + + sub renew { + my $self = shift; + my $clone = bless { %$self } => ref($self); + $clone->{renewed}++; + return $clone; + } + +This method reconstructs the encoding object if necessary. If you need +to store the state during encoding, this is where you clone your object. + +PerlIO ALWAYS calls this method to make sure it has its own private +encoding object. + +=item -E<gt>renewed + +Predefined As: + + sub renewed { $_[0]->{renewed} || 0 } + +Tells whether the object is renewed (and how many times). Some +modules emit C<Use of uninitialized value in null operation> warning +unless the value is numeric so return 0 for false. + +=item -E<gt>perlio_ok() + +Predefined As: + + sub perlio_ok { + eval{ require PerlIO::encoding }; + return $@ ? 0 : 1; + } + +If your encoding does not support PerlIO for some reasons, just; + + sub perlio_ok { 0 } + +=item -E<gt>needs_lines() + +Predefined As: + + sub needs_lines { 0 }; + +If your encoding can work with PerlIO but needs line buffering, you +MUST define this method so it returns true. 7bit ISO-2022 encodings +are one example that needs this. When this method is missing, false +is assumed. + +=back + +=head2 Example: Encode::ROT13 + + package Encode::ROT13; + use strict; + use base qw(Encode::Encoding); + + __PACKAGE__->Define('rot13'); + + sub encode($$;$){ + my ($obj, $str, $chk) = @_; + $str =~ tr/A-Za-z/N-ZA-Mn-za-m/; + $_[1] = '' if $chk; # this is what in-place edit means + return $str; + } + + # Jr pna or ynml yvxr guvf; + *decode = \&encode; + + 1; + +=head1 Why the heck Encode API is different? + +It should be noted that the I<$check> behaviour is different from the +outer public API. The logic is that the "unchecked" case is useful +when the encoding is part of a stream which may be reporting errors +(e.g. STDERR). In such cases, it is desirable to get everything +through somehow without causing additional errors which obscure the +original one. Also, the encoding is best placed to know what the +correct replacement character is, so if that is the desired behaviour +then letting low level code do it is the most efficient. + +By contrast, if I<$check> is true, the scheme above allows the +encoding to do as much as it can and tell the layer above how much +that was. What is lacking at present is a mechanism to report what +went wrong. The most likely interface will be an additional method +call to the object, or perhaps (to avoid forcing per-stream objects +on otherwise stateless encodings) an additional parameter. + +It is also highly desirable that encoding classes inherit from +C<Encode::Encoding> as a base class. This allows that class to define +additional behaviour for all encoding objects. + + package Encode::MyEncoding; + use base qw(Encode::Encoding); + + __PACKAGE__->Define(qw(myCanonical myAlias)); + +to create an object with C<< bless {Name => ...}, $class >>, and call +define_encoding. They inherit their C<name> method from +C<Encode::Encoding>. + +=head2 Compiled Encodings + +For the sake of speed and efficiency, most of the encodings are now +supported via a I<compiled form>: XS modules generated from UCM +files. Encode provides the enc2xs tool to achieve that. Please see +L<enc2xs> for more details. + +=head1 SEE ALSO + +L<perlmod>, L<enc2xs> + +=begin future + +=over 4 + +=item Scheme 1 + +The fixup routine gets passed the remaining fragment of string being +processed. It modifies it in place to remove bytes/characters it can +understand and returns a string used to represent them. For example: + + sub fixup { + my $ch = substr($_[0],0,1,''); + return sprintf("\x{%02X}",ord($ch); + } + +This scheme is close to how the underlying C code for Encode works, +but gives the fixup routine very little context. + +=item Scheme 2 + +The fixup routine gets passed the original string, an index into +it of the problem area, and the output string so far. It appends +what it wants to the output string and returns a new index into the +original string. For example: + + sub fixup { + # my ($s,$i,$d) = @_; + my $ch = substr($_[0],$_[1],1); + $_[2] .= sprintf("\x{%02X}",ord($ch); + return $_[1]+1; + } + +This scheme gives maximal control to the fixup routine but is more +complicated to code, and may require that the internals of Encode be tweaked to +keep the original string intact. + +=item Other Schemes + +Hybrids of the above. + +Multiple return values rather than in-place modifications. + +Index into the string could be C<pos($str)> allowing C<s/\G...//>. + +=back + +=end future + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/GSM0338.pm b/Master/tlpkg/tlperl/lib/Encode/GSM0338.pm new file mode 100644 index 00000000000..2ea71f2f77e --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/GSM0338.pm @@ -0,0 +1,292 @@ +# +# $Id: GSM0338.pm,v 2.1 2008/05/07 20:56:05 dankogai Exp $ +# +package Encode::GSM0338; + +use strict; +use warnings; +use Carp; + +use vars qw($VERSION); +$VERSION = do { my @r = ( q$Revision: 2.1 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; + +use Encode qw(:fallbacks); + +use base qw(Encode::Encoding); +__PACKAGE__->Define('gsm0338'); + +sub needs_lines { 1 } +sub perlio_ok { 0 } + +use utf8; +our %UNI2GSM = ( + "\x{0040}" => "\x00", # COMMERCIAL AT + "\x{000A}" => "\x0A", # LINE FEED + "\x{000C}" => "\x1B\x0A", # FORM FEED + "\x{000D}" => "\x0D", # CARRIAGE RETURN + "\x{0020}" => "\x20", # SPACE + "\x{0021}" => "\x21", # EXCLAMATION MARK + "\x{0022}" => "\x22", # QUOTATION MARK + "\x{0023}" => "\x23", # NUMBER SIGN + "\x{0024}" => "\x02", # DOLLAR SIGN + "\x{0025}" => "\x25", # PERCENT SIGN + "\x{0026}" => "\x26", # AMPERSAND + "\x{0027}" => "\x27", # APOSTROPHE + "\x{0028}" => "\x28", # LEFT PARENTHESIS + "\x{0029}" => "\x29", # RIGHT PARENTHESIS + "\x{002A}" => "\x2A", # ASTERISK + "\x{002B}" => "\x2B", # PLUS SIGN + "\x{002C}" => "\x2C", # COMMA + "\x{002D}" => "\x2D", # HYPHEN-MINUS + "\x{002E}" => "\x2E", # FULL STOP + "\x{002F}" => "\x2F", # SOLIDUS + "\x{0030}" => "\x30", # DIGIT ZERO + "\x{0031}" => "\x31", # DIGIT ONE + "\x{0032}" => "\x32", # DIGIT TWO + "\x{0033}" => "\x33", # DIGIT THREE + "\x{0034}" => "\x34", # DIGIT FOUR + "\x{0035}" => "\x35", # DIGIT FIVE + "\x{0036}" => "\x36", # DIGIT SIX + "\x{0037}" => "\x37", # DIGIT SEVEN + "\x{0038}" => "\x38", # DIGIT EIGHT + "\x{0039}" => "\x39", # DIGIT NINE + "\x{003A}" => "\x3A", # COLON + "\x{003B}" => "\x3B", # SEMICOLON + "\x{003C}" => "\x3C", # LESS-THAN SIGN + "\x{003D}" => "\x3D", # EQUALS SIGN + "\x{003E}" => "\x3E", # GREATER-THAN SIGN + "\x{003F}" => "\x3F", # QUESTION MARK + "\x{0041}" => "\x41", # LATIN CAPITAL LETTER A + "\x{0042}" => "\x42", # LATIN CAPITAL LETTER B + "\x{0043}" => "\x43", # LATIN CAPITAL LETTER C + "\x{0044}" => "\x44", # LATIN CAPITAL LETTER D + "\x{0045}" => "\x45", # LATIN CAPITAL LETTER E + "\x{0046}" => "\x46", # LATIN CAPITAL LETTER F + "\x{0047}" => "\x47", # LATIN CAPITAL LETTER G + "\x{0048}" => "\x48", # LATIN CAPITAL LETTER H + "\x{0049}" => "\x49", # LATIN CAPITAL LETTER I + "\x{004A}" => "\x4A", # LATIN CAPITAL LETTER J + "\x{004B}" => "\x4B", # LATIN CAPITAL LETTER K + "\x{004C}" => "\x4C", # LATIN CAPITAL LETTER L + "\x{004D}" => "\x4D", # LATIN CAPITAL LETTER M + "\x{004E}" => "\x4E", # LATIN CAPITAL LETTER N + "\x{004F}" => "\x4F", # LATIN CAPITAL LETTER O + "\x{0050}" => "\x50", # LATIN CAPITAL LETTER P + "\x{0051}" => "\x51", # LATIN CAPITAL LETTER Q + "\x{0052}" => "\x52", # LATIN CAPITAL LETTER R + "\x{0053}" => "\x53", # LATIN CAPITAL LETTER S + "\x{0054}" => "\x54", # LATIN CAPITAL LETTER T + "\x{0055}" => "\x55", # LATIN CAPITAL LETTER U + "\x{0056}" => "\x56", # LATIN CAPITAL LETTER V + "\x{0057}" => "\x57", # LATIN CAPITAL LETTER W + "\x{0058}" => "\x58", # LATIN CAPITAL LETTER X + "\x{0059}" => "\x59", # LATIN CAPITAL LETTER Y + "\x{005A}" => "\x5A", # LATIN CAPITAL LETTER Z + "\x{005F}" => "\x11", # LOW LINE + "\x{0061}" => "\x61", # LATIN SMALL LETTER A + "\x{0062}" => "\x62", # LATIN SMALL LETTER B + "\x{0063}" => "\x63", # LATIN SMALL LETTER C + "\x{0064}" => "\x64", # LATIN SMALL LETTER D + "\x{0065}" => "\x65", # LATIN SMALL LETTER E + "\x{0066}" => "\x66", # LATIN SMALL LETTER F + "\x{0067}" => "\x67", # LATIN SMALL LETTER G + "\x{0068}" => "\x68", # LATIN SMALL LETTER H + "\x{0069}" => "\x69", # LATIN SMALL LETTER I + "\x{006A}" => "\x6A", # LATIN SMALL LETTER J + "\x{006B}" => "\x6B", # LATIN SMALL LETTER K + "\x{006C}" => "\x6C", # LATIN SMALL LETTER L + "\x{006D}" => "\x6D", # LATIN SMALL LETTER M + "\x{006E}" => "\x6E", # LATIN SMALL LETTER N + "\x{006F}" => "\x6F", # LATIN SMALL LETTER O + "\x{0070}" => "\x70", # LATIN SMALL LETTER P + "\x{0071}" => "\x71", # LATIN SMALL LETTER Q + "\x{0072}" => "\x72", # LATIN SMALL LETTER R + "\x{0073}" => "\x73", # LATIN SMALL LETTER S + "\x{0074}" => "\x74", # LATIN SMALL LETTER T + "\x{0075}" => "\x75", # LATIN SMALL LETTER U + "\x{0076}" => "\x76", # LATIN SMALL LETTER V + "\x{0077}" => "\x77", # LATIN SMALL LETTER W + "\x{0078}" => "\x78", # LATIN SMALL LETTER X + "\x{0079}" => "\x79", # LATIN SMALL LETTER Y + "\x{007A}" => "\x7A", # LATIN SMALL LETTER Z + "\x{000C}" => "\x1B\x0A", # FORM FEED + "\x{005B}" => "\x1B\x3C", # LEFT SQUARE BRACKET + "\x{005C}" => "\x1B\x2F", # REVERSE SOLIDUS + "\x{005D}" => "\x1B\x3E", # RIGHT SQUARE BRACKET + "\x{005E}" => "\x1B\x14", # CIRCUMFLEX ACCENT + "\x{007B}" => "\x1B\x28", # LEFT CURLY BRACKET + "\x{007C}" => "\x1B\x40", # VERTICAL LINE + "\x{007D}" => "\x1B\x29", # RIGHT CURLY BRACKET + "\x{007E}" => "\x1B\x3D", # TILDE + "\x{00A0}" => "\x1B", # NO-BREAK SPACE + "\x{00A1}" => "\x40", # INVERTED EXCLAMATION MARK + "\x{00A3}" => "\x01", # POUND SIGN + "\x{00A4}" => "\x24", # CURRENCY SIGN + "\x{00A5}" => "\x03", # YEN SIGN + "\x{00A7}" => "\x5F", # SECTION SIGN + "\x{00BF}" => "\x60", # INVERTED QUESTION MARK + "\x{00C4}" => "\x5B", # LATIN CAPITAL LETTER A WITH DIAERESIS + "\x{00C5}" => "\x0E", # LATIN CAPITAL LETTER A WITH RING ABOVE + "\x{00C6}" => "\x1C", # LATIN CAPITAL LETTER AE + "\x{00C9}" => "\x1F", # LATIN CAPITAL LETTER E WITH ACUTE + "\x{00D1}" => "\x5D", # LATIN CAPITAL LETTER N WITH TILDE + "\x{00D6}" => "\x5C", # LATIN CAPITAL LETTER O WITH DIAERESIS + "\x{00D8}" => "\x0B", # LATIN CAPITAL LETTER O WITH STROKE + "\x{00DC}" => "\x5E", # LATIN CAPITAL LETTER U WITH DIAERESIS + "\x{00DF}" => "\x1E", # LATIN SMALL LETTER SHARP S + "\x{00E0}" => "\x7F", # LATIN SMALL LETTER A WITH GRAVE + "\x{00E4}" => "\x7B", # LATIN SMALL LETTER A WITH DIAERESIS + "\x{00E5}" => "\x0F", # LATIN SMALL LETTER A WITH RING ABOVE + "\x{00E6}" => "\x1D", # LATIN SMALL LETTER AE + "\x{00E7}" => "\x09", # LATIN SMALL LETTER C WITH CEDILLA + "\x{00E8}" => "\x04", # LATIN SMALL LETTER E WITH GRAVE + "\x{00E9}" => "\x05", # LATIN SMALL LETTER E WITH ACUTE + "\x{00EC}" => "\x07", # LATIN SMALL LETTER I WITH GRAVE + "\x{00F1}" => "\x7D", # LATIN SMALL LETTER N WITH TILDE + "\x{00F2}" => "\x08", # LATIN SMALL LETTER O WITH GRAVE + "\x{00F6}" => "\x7C", # LATIN SMALL LETTER O WITH DIAERESIS + "\x{00F8}" => "\x0C", # LATIN SMALL LETTER O WITH STROKE + "\x{00F9}" => "\x06", # LATIN SMALL LETTER U WITH GRAVE + "\x{00FC}" => "\x7E", # LATIN SMALL LETTER U WITH DIAERESIS + "\x{0393}" => "\x13", # GREEK CAPITAL LETTER GAMMA + "\x{0394}" => "\x10", # GREEK CAPITAL LETTER DELTA + "\x{0398}" => "\x19", # GREEK CAPITAL LETTER THETA + "\x{039B}" => "\x14", # GREEK CAPITAL LETTER LAMDA + "\x{039E}" => "\x1A", # GREEK CAPITAL LETTER XI + "\x{03A0}" => "\x16", # GREEK CAPITAL LETTER PI + "\x{03A3}" => "\x18", # GREEK CAPITAL LETTER SIGMA + "\x{03A6}" => "\x12", # GREEK CAPITAL LETTER PHI + "\x{03A8}" => "\x17", # GREEK CAPITAL LETTER PSI + "\x{03A9}" => "\x15", # GREEK CAPITAL LETTER OMEGA + "\x{20AC}" => "\x1B\x65", # EURO SIGN +); +our %GSM2UNI = reverse %UNI2GSM; +our $ESC = "\x1b"; +our $ATMARK = "\x40"; +our $FBCHAR = "\x3F"; +our $NBSP = "\x{00A0}"; + +#define ERR_DECODE_NOMAP "%s \"\\x%02" UVXf "\" does not map to Unicode" + +sub decode ($$;$) { + my ( $obj, $bytes, $chk ) = @_; + my $str; + while ( length $bytes ) { + my $c = substr( $bytes, 0, 1, '' ); + my $u; + if ( $c eq "\x00" ) { + my $c2 = substr( $bytes, 0, 1, '' ); + $u = + !length $c2 ? $ATMARK + : $c2 eq "\x00" ? "\x{0000}" + : exists $GSM2UNI{$c2} ? $ATMARK . $GSM2UNI{$c2} + : $chk + ? croak sprintf( "\\x%02X\\x%02X does not map to Unicode", + ord($c), ord($c2) ) + : $ATMARK . $FBCHAR; + + } + elsif ( $c eq $ESC ) { + my $c2 = substr( $bytes, 0, 1, '' ); + $u = + exists $GSM2UNI{ $c . $c2 } ? $GSM2UNI{ $c . $c2 } + : exists $GSM2UNI{$c2} ? $NBSP . $GSM2UNI{$c2} + : $chk + ? croak sprintf( "\\x%02X\\x%02X does not map to Unicode", + ord($c), ord($c2) ) + : $NBSP . $FBCHAR; + } + else { + $u = + exists $GSM2UNI{$c} + ? $GSM2UNI{$c} + : $chk ? ref $chk eq 'CODE' + ? $chk->( ord $c ) + : croak sprintf( "\\x%02X does not map to Unicode", ord($c) ) + : $FBCHAR; + } + $str .= $u; + } + $_[1] = $bytes if $chk; + return $str; +} + +#define ERR_ENCODE_NOMAP "\"\\x{%04" UVxf "}\" does not map to %s" + +sub encode($$;$) { + my ( $obj, $str, $chk ) = @_; + my $bytes; + while ( length $str ) { + my $u = substr( $str, 0, 1, '' ); + my $c; + $bytes .= + exists $UNI2GSM{$u} + ? $UNI2GSM{$u} + : $chk ? ref $chk eq 'CODE' + ? $chk->( ord($u) ) + : croak sprintf( "\\x{%04x} does not map to %s", + ord($u), $obj->name ) + : $FBCHAR; + } + $_[1] = $str if $chk; + return $bytes; +} + +1; +__END__ + +=head1 NAME + +Encode::GSM0338 -- ESTI GSM 03.38 Encoding + +=head1 SYNOPSIS + + use Encode qw/encode decode/; + $gsm0338 = encode("gsm0338", $utf8); # loads Encode::GSM0338 implicitly + $utf8 = decode("gsm0338", $gsm0338); # ditto + +=head1 DESCRIPTION + +GSM0338 is for GSM handsets. Though it shares alphanumerals with ASCII, +control character ranges and other parts are mapped very differently, +mainly to store Greek characters. There are also escape sequences +(starting with 0x1B) to cover e.g. the Euro sign. + +This was once handled by L<Encode::Bytes> but because of all those +unusual specifications, Encode 2.20 has relocated the support to +this module. + +=head1 NOTES + +Unlike most other encodings, the following aways croaks on error +for any $chk that evaluates to true. + + $gsm0338 = encode("gsm0338", $utf8 $chk); + $utf8 = decode("gsm0338", $gsm0338, $chk); + +So if you want to check the validity of the encoding, surround the +expression with C<eval {}> block as follows; + + eval { + $utf8 = decode("gsm0338", $gsm0338, $chk); + }; + if ($@){ + # handle exception here + } + +=head1 BUGS + +ESTI GSM 03.38 Encoding itself. + +Mapping \x00 to '@' causes too much pain everywhere. + +Its use of \x1b (escape) is also very questionable. + +Because of those two, the code paging approach used use in ucm-based +Encoding SOMETIMES fails so this module was written. + +=head1 SEE ALSO + +L<Encode> + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/Guess.pm b/Master/tlpkg/tlperl/lib/Encode/Guess.pm new file mode 100644 index 00000000000..1ad7147e7f5 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/Guess.pm @@ -0,0 +1,355 @@ +package Encode::Guess; +use strict; +use warnings; +use Encode qw(:fallbacks find_encoding); +our $VERSION = do { my @r = ( q$Revision: 2.3 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; + +my $Canon = 'Guess'; +sub DEBUG () { 0 } +our %DEF_SUSPECTS = map { $_ => find_encoding($_) } qw(ascii utf8); +$Encode::Encoding{$Canon} = bless { + Name => $Canon, + Suspects => {%DEF_SUSPECTS}, +} => __PACKAGE__; + +use base qw(Encode::Encoding); +sub needs_lines { 1 } +sub perlio_ok { 0 } + +our @EXPORT = qw(guess_encoding); +our $NoUTFAutoGuess = 0; +our $UTF8_BOM = pack( "C3", 0xef, 0xbb, 0xbf ); + +sub import { # Exporter not used so we do it on our own + my $callpkg = caller; + for my $item (@EXPORT) { + no strict 'refs'; + *{"$callpkg\::$item"} = \&{"$item"}; + } + set_suspects(@_); +} + +sub set_suspects { + my $class = shift; + my $self = ref($class) ? $class : $Encode::Encoding{$Canon}; + $self->{Suspects} = {%DEF_SUSPECTS}; + $self->add_suspects(@_); +} + +sub add_suspects { + my $class = shift; + my $self = ref($class) ? $class : $Encode::Encoding{$Canon}; + for my $c (@_) { + my $e = find_encoding($c) or die "Unknown encoding: $c"; + $self->{Suspects}{ $e->name } = $e; + DEBUG and warn "Added: ", $e->name; + } +} + +sub decode($$;$) { + my ( $obj, $octet, $chk ) = @_; + my $guessed = guess( $obj, $octet ); + unless ( ref($guessed) ) { + require Carp; + Carp::croak($guessed); + } + my $utf8 = $guessed->decode( $octet, $chk ); + $_[1] = $octet if $chk; + return $utf8; +} + +sub guess_encoding { + guess( $Encode::Encoding{$Canon}, @_ ); +} + +sub guess { + my $class = shift; + my $obj = ref($class) ? $class : $Encode::Encoding{$Canon}; + my $octet = shift; + + # sanity check + return "Empty string, empty guess" unless defined $octet and length $octet; + + # cheat 0: utf8 flag; + if ( Encode::is_utf8($octet) ) { + return find_encoding('utf8') unless $NoUTFAutoGuess; + Encode::_utf8_off($octet); + } + + # cheat 1: BOM + use Encode::Unicode; + unless ($NoUTFAutoGuess) { + my $BOM = pack( 'C3', unpack( "C3", $octet ) ); + return find_encoding('utf8') + if ( defined $BOM and $BOM eq $UTF8_BOM ); + $BOM = unpack( 'N', $octet ); + return find_encoding('UTF-32') + if ( defined $BOM and ( $BOM == 0xFeFF or $BOM == 0xFFFe0000 ) ); + $BOM = unpack( 'n', $octet ); + return find_encoding('UTF-16') + if ( defined $BOM and ( $BOM == 0xFeFF or $BOM == 0xFFFe ) ); + if ( $octet =~ /\x00/o ) + { # if \x00 found, we assume UTF-(16|32)(BE|LE) + my $utf; + my ( $be, $le ) = ( 0, 0 ); + if ( $octet =~ /\x00\x00/o ) { # UTF-32(BE|LE) assumed + $utf = "UTF-32"; + for my $char ( unpack( 'N*', $octet ) ) { + $char & 0x0000ffff and $be++; + $char & 0xffff0000 and $le++; + } + } + else { # UTF-16(BE|LE) assumed + $utf = "UTF-16"; + for my $char ( unpack( 'n*', $octet ) ) { + $char & 0x00ff and $be++; + $char & 0xff00 and $le++; + } + } + DEBUG and warn "$utf, be == $be, le == $le"; + $be == $le + and return + "Encodings ambiguous between $utf BE and LE ($be, $le)"; + $utf .= ( $be > $le ) ? 'BE' : 'LE'; + return find_encoding($utf); + } + } + my %try = %{ $obj->{Suspects} }; + for my $c (@_) { + my $e = find_encoding($c) or die "Unknown encoding: $c"; + $try{ $e->name } = $e; + DEBUG and warn "Added: ", $e->name; + } + my $nline = 1; + for my $line ( split /\r\n?|\n/, $octet ) { + + # cheat 2 -- \e in the string + if ( $line =~ /\e/o ) { + my @keys = keys %try; + delete @try{qw/utf8 ascii/}; + for my $k (@keys) { + ref( $try{$k} ) eq 'Encode::XS' and delete $try{$k}; + } + } + my %ok = %try; + + # warn join(",", keys %try); + for my $k ( keys %try ) { + my $scratch = $line; + $try{$k}->decode( $scratch, FB_QUIET ); + if ( $scratch eq '' ) { + DEBUG and warn sprintf( "%4d:%-24s ok\n", $nline, $k ); + } + else { + use bytes (); + DEBUG + and warn sprintf( "%4d:%-24s not ok; %d bytes left\n", + $nline, $k, bytes::length($scratch) ); + delete $ok{$k}; + } + } + %ok or return "No appropriate encodings found!"; + if ( scalar( keys(%ok) ) == 1 ) { + my ($retval) = values(%ok); + return $retval; + } + %try = %ok; + $nline++; + } + $try{ascii} + or return "Encodings too ambiguous: ", join( " or ", keys %try ); + return $try{ascii}; +} + +1; +__END__ + +=head1 NAME + +Encode::Guess -- Guesses encoding from data + +=head1 SYNOPSIS + + # if you are sure $data won't contain anything bogus + + use Encode; + use Encode::Guess qw/euc-jp shiftjis 7bit-jis/; + my $utf8 = decode("Guess", $data); + my $data = encode("Guess", $utf8); # this doesn't work! + + # more elaborate way + use Encode::Guess; + my $enc = guess_encoding($data, qw/euc-jp shiftjis 7bit-jis/); + ref($enc) or die "Can't guess: $enc"; # trap error this way + $utf8 = $enc->decode($data); + # or + $utf8 = decode($enc->name, $data) + +=head1 ABSTRACT + +Encode::Guess enables you to guess in what encoding a given data is +encoded, or at least tries to. + +=head1 DESCRIPTION + +By default, it checks only ascii, utf8 and UTF-16/32 with BOM. + + use Encode::Guess; # ascii/utf8/BOMed UTF + +To use it more practically, you have to give the names of encodings to +check (I<suspects> as follows). The name of suspects can either be +canonical names or aliases. + +CAVEAT: Unlike UTF-(16|32), BOM in utf8 is NOT AUTOMATICALLY STRIPPED. + + # tries all major Japanese Encodings as well + use Encode::Guess qw/euc-jp shiftjis 7bit-jis/; + +If the C<$Encode::Guess::NoUTFAutoGuess> variable is set to a true +value, no heuristics will be applied to UTF8/16/32, and the result +will be limited to the suspects and C<ascii>. + +=over 4 + +=item Encode::Guess->set_suspects + +You can also change the internal suspects list via C<set_suspects> +method. + + use Encode::Guess; + Encode::Guess->set_suspects(qw/euc-jp shiftjis 7bit-jis/); + +=item Encode::Guess->add_suspects + +Or you can use C<add_suspects> method. The difference is that +C<set_suspects> flushes the current suspects list while +C<add_suspects> adds. + + use Encode::Guess; + Encode::Guess->add_suspects(qw/euc-jp shiftjis 7bit-jis/); + # now the suspects are euc-jp,shiftjis,7bit-jis, AND + # euc-kr,euc-cn, and big5-eten + Encode::Guess->add_suspects(qw/euc-kr euc-cn big5-eten/); + +=item Encode::decode("Guess" ...) + +When you are content with suspects list, you can now + + my $utf8 = Encode::decode("Guess", $data); + +=item Encode::Guess->guess($data) + +But it will croak if: + +=over + +=item * + +Two or more suspects remain + +=item * + +No suspects left + +=back + +So you should instead try this; + + my $decoder = Encode::Guess->guess($data); + +On success, $decoder is an object that is documented in +L<Encode::Encoding>. So you can now do this; + + my $utf8 = $decoder->decode($data); + +On failure, $decoder now contains an error message so the whole thing +would be as follows; + + my $decoder = Encode::Guess->guess($data); + die $decoder unless ref($decoder); + my $utf8 = $decoder->decode($data); + +=item guess_encoding($data, [, I<list of suspects>]) + +You can also try C<guess_encoding> function which is exported by +default. It takes $data to check and it also takes the list of +suspects by option. The optional suspect list is I<not reflected> to +the internal suspects list. + + my $decoder = guess_encoding($data, qw/euc-jp euc-kr euc-cn/); + die $decoder unless ref($decoder); + my $utf8 = $decoder->decode($data); + # check only ascii and utf8 + my $decoder = guess_encoding($data); + +=back + +=head1 CAVEATS + +=over 4 + +=item * + +Because of the algorithm used, ISO-8859 series and other single-byte +encodings do not work well unless either one of ISO-8859 is the only +one suspect (besides ascii and utf8). + + use Encode::Guess; + # perhaps ok + my $decoder = guess_encoding($data, 'latin1'); + # definitely NOT ok + my $decoder = guess_encoding($data, qw/latin1 greek/); + +The reason is that Encode::Guess guesses encoding by trial and error. +It first splits $data into lines and tries to decode the line for each +suspect. It keeps it going until all but one encoding is eliminated +out of suspects list. ISO-8859 series is just too successful for most +cases (because it fills almost all code points in \x00-\xff). + +=item * + +Do not mix national standard encodings and the corresponding vendor +encodings. + + # a very bad idea + my $decoder + = guess_encoding($data, qw/shiftjis MacJapanese cp932/); + +The reason is that vendor encoding is usually a superset of national +standard so it becomes too ambiguous for most cases. + +=item * + +On the other hand, mixing various national standard encodings +automagically works unless $data is too short to allow for guessing. + + # This is ok if $data is long enough + my $decoder = + guess_encoding($data, qw/euc-cn + euc-jp shiftjis 7bit-jis + euc-kr + big5-eten/); + +=item * + +DO NOT PUT TOO MANY SUSPECTS! Don't you try something like this! + + my $decoder = guess_encoding($data, + Encode->encodings(":all")); + +=back + +It is, after all, just a guess. You should alway be explicit when it +comes to encodings. But there are some, especially Japanese, +environment that guess-coding is a must. Use this module with care. + +=head1 TO DO + +Encode::Guess does not work on EBCDIC platforms. + +=head1 SEE ALSO + +L<Encode>, L<Encode::Encoding> + +=cut + diff --git a/Master/tlpkg/tlperl/lib/Encode/JP.pm b/Master/tlpkg/tlperl/lib/Encode/JP.pm new file mode 100644 index 00000000000..4251170c561 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/JP.pm @@ -0,0 +1,95 @@ +package Encode::JP; +BEGIN { + if ( ord("A") == 193 ) { + die "Encode::JP not supported on EBCDIC\n"; + } +} +use strict; +use warnings; +use Encode; +our $VERSION = do { my @r = ( q$Revision: 2.4 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; + +use XSLoader; +XSLoader::load( __PACKAGE__, $VERSION ); + +use Encode::JP::JIS7; + +1; +__END__ + +=head1 NAME + +Encode::JP - Japanese Encodings + +=head1 SYNOPSIS + + use Encode qw/encode decode/; + $euc_jp = encode("euc-jp", $utf8); # loads Encode::JP implicitly + $utf8 = decode("euc-jp", $euc_jp); # ditto + +=head1 ABSTRACT + +This module implements Japanese charset encodings. Encodings +supported are as follows. + + Canonical Alias Description + -------------------------------------------------------------------- + euc-jp /\beuc.*jp$/i EUC (Extended Unix Character) + /\bjp.*euc/i + /\bujis$/i + shiftjis /\bshift.*jis$/i Shift JIS (aka MS Kanji) + /\bsjis$/i + 7bit-jis /\bjis$/i 7bit JIS + iso-2022-jp ISO-2022-JP [RFC1468] + = 7bit JIS with all Halfwidth Kana + converted to Fullwidth + iso-2022-jp-1 ISO-2022-JP-1 [RFC2237] + = ISO-2022-JP with JIS X 0212-1990 + support. See below + MacJapanese Shift JIS + Apple vendor mappings + cp932 /\bwindows-31j$/i Code Page 932 + = Shift JIS + MS/IBM vendor mappings + jis0201-raw JIS0201, raw format + jis0208-raw JIS0201, raw format + jis0212-raw JIS0201, raw format + -------------------------------------------------------------------- + +=head1 DESCRIPTION + +To find out how to use this module in detail, see L<Encode>. + +=head1 Note on ISO-2022-JP(-1)? + +ISO-2022-JP-1 (RFC2237) is a superset of ISO-2022-JP (RFC1468) which +adds support for JIS X 0212-1990. That means you can use the same +code to decode to utf8 but not vice versa. + + $utf8 = decode('iso-2022-jp-1', $stream); + +and + + $utf8 = decode('iso-2022-jp', $stream); + +yield the same result but + + $with_0212 = encode('iso-2022-jp-1', $utf8); + +is now different from + + $without_0212 = encode('iso-2022-jp', $utf8 ); + +In the latter case, characters that map to 0212 are first converted +to U+3013 (0xA2AE in EUC-JP; a white square also known as 'Tofu' or +'geta mark') then fed to the decoding engine. U+FFFD is not used, +in order to preserve text layout as much as possible. + +=head1 BUGS + +The ASCII region (0x00-0x7f) is preserved for all encodings, even +though this conflicts with mappings by the Unicode Consortium. + +=head1 SEE ALSO + +L<Encode> + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/JP/H2Z.pm b/Master/tlpkg/tlperl/lib/Encode/JP/H2Z.pm new file mode 100644 index 00000000000..f8e2230da11 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/JP/H2Z.pm @@ -0,0 +1,176 @@ +# +# $Id: H2Z.pm,v 2.2 2006/06/03 20:28:48 dankogai Exp $ +# + +package Encode::JP::H2Z; + +use strict; +use warnings; + +our $RCSID = q$Id: H2Z.pm,v 2.2 2006/06/03 20:28:48 dankogai Exp $; +our $VERSION = do { my @r = ( q$Revision: 2.2 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; + +use Encode::CJKConstants qw(:all); + +use vars qw(%_D2Z $_PAT_D2Z + %_Z2D $_PAT_Z2D + %_H2Z $_PAT_H2Z + %_Z2H $_PAT_Z2H); + +%_H2Z = ( + "\x8e\xa1" => "\xa1\xa3", #¡£ + "\x8e\xa2" => "\xa1\xd6", #¡Ö + "\x8e\xa3" => "\xa1\xd7", #¡× + "\x8e\xa4" => "\xa1\xa2", #¡¢ + "\x8e\xa5" => "\xa1\xa6", #¡¦ + "\x8e\xa6" => "\xa5\xf2", #¥ò + "\x8e\xa7" => "\xa5\xa1", #¥¡ + "\x8e\xa8" => "\xa5\xa3", #¥£ + "\x8e\xa9" => "\xa5\xa5", #¥¥ + "\x8e\xaa" => "\xa5\xa7", #¥§ + "\x8e\xab" => "\xa5\xa9", #¥© + "\x8e\xac" => "\xa5\xe3", #¥ã + "\x8e\xad" => "\xa5\xe5", #¥å + "\x8e\xae" => "\xa5\xe7", #¥ç + "\x8e\xaf" => "\xa5\xc3", #¥Ã + "\x8e\xb0" => "\xa1\xbc", #¡¼ + "\x8e\xb1" => "\xa5\xa2", #¥¢ + "\x8e\xb2" => "\xa5\xa4", #¥¤ + "\x8e\xb3" => "\xa5\xa6", #¥¦ + "\x8e\xb4" => "\xa5\xa8", #¥¨ + "\x8e\xb5" => "\xa5\xaa", #¥ª + "\x8e\xb6" => "\xa5\xab", #¥« + "\x8e\xb7" => "\xa5\xad", #¥ + "\x8e\xb8" => "\xa5\xaf", #¥¯ + "\x8e\xb9" => "\xa5\xb1", #¥± + "\x8e\xba" => "\xa5\xb3", #¥³ + "\x8e\xbb" => "\xa5\xb5", #¥µ + "\x8e\xbc" => "\xa5\xb7", #¥· + "\x8e\xbd" => "\xa5\xb9", #¥¹ + "\x8e\xbe" => "\xa5\xbb", #¥» + "\x8e\xbf" => "\xa5\xbd", #¥½ + "\x8e\xc0" => "\xa5\xbf", #¥¿ + "\x8e\xc1" => "\xa5\xc1", #¥Á + "\x8e\xc2" => "\xa5\xc4", #¥Ä + "\x8e\xc3" => "\xa5\xc6", #¥Æ + "\x8e\xc4" => "\xa5\xc8", #¥È + "\x8e\xc5" => "\xa5\xca", #¥Ê + "\x8e\xc6" => "\xa5\xcb", #¥Ë + "\x8e\xc7" => "\xa5\xcc", #¥Ì + "\x8e\xc8" => "\xa5\xcd", #¥Í + "\x8e\xc9" => "\xa5\xce", #¥Î + "\x8e\xca" => "\xa5\xcf", #¥Ï + "\x8e\xcb" => "\xa5\xd2", #¥Ò + "\x8e\xcc" => "\xa5\xd5", #¥Õ + "\x8e\xcd" => "\xa5\xd8", #¥Ø + "\x8e\xce" => "\xa5\xdb", #¥Û + "\x8e\xcf" => "\xa5\xde", #¥Þ + "\x8e\xd0" => "\xa5\xdf", #¥ß + "\x8e\xd1" => "\xa5\xe0", #¥à + "\x8e\xd2" => "\xa5\xe1", #¥á + "\x8e\xd3" => "\xa5\xe2", #¥â + "\x8e\xd4" => "\xa5\xe4", #¥ä + "\x8e\xd5" => "\xa5\xe6", #¥æ + "\x8e\xd6" => "\xa5\xe8", #¥è + "\x8e\xd7" => "\xa5\xe9", #¥é + "\x8e\xd8" => "\xa5\xea", #¥ê + "\x8e\xd9" => "\xa5\xeb", #¥ë + "\x8e\xda" => "\xa5\xec", #¥ì + "\x8e\xdb" => "\xa5\xed", #¥í + "\x8e\xdc" => "\xa5\xef", #¥ï + "\x8e\xdd" => "\xa5\xf3", #¥ó + "\x8e\xde" => "\xa1\xab", #¡« + "\x8e\xdf" => "\xa1\xac", #¡¬ +); + +%_D2Z = ( + "\x8e\xb6\x8e\xde" => "\xa5\xac", #¥¬ + "\x8e\xb7\x8e\xde" => "\xa5\xae", #¥® + "\x8e\xb8\x8e\xde" => "\xa5\xb0", #¥° + "\x8e\xb9\x8e\xde" => "\xa5\xb2", #¥² + "\x8e\xba\x8e\xde" => "\xa5\xb4", #¥´ + "\x8e\xbb\x8e\xde" => "\xa5\xb6", #¥¶ + "\x8e\xbc\x8e\xde" => "\xa5\xb8", #¥¸ + "\x8e\xbd\x8e\xde" => "\xa5\xba", #¥º + "\x8e\xbe\x8e\xde" => "\xa5\xbc", #¥¼ + "\x8e\xbf\x8e\xde" => "\xa5\xbe", #¥¾ + "\x8e\xc0\x8e\xde" => "\xa5\xc0", #¥À + "\x8e\xc1\x8e\xde" => "\xa5\xc2", #¥Â + "\x8e\xc2\x8e\xde" => "\xa5\xc5", #¥Å + "\x8e\xc3\x8e\xde" => "\xa5\xc7", #¥Ç + "\x8e\xc4\x8e\xde" => "\xa5\xc9", #¥É + "\x8e\xca\x8e\xde" => "\xa5\xd0", #¥Ð + "\x8e\xcb\x8e\xde" => "\xa5\xd3", #¥Ó + "\x8e\xcc\x8e\xde" => "\xa5\xd6", #¥Ö + "\x8e\xcd\x8e\xde" => "\xa5\xd9", #¥Ù + "\x8e\xce\x8e\xde" => "\xa5\xdc", #¥Ü + "\x8e\xca\x8e\xdf" => "\xa5\xd1", #¥Ñ + "\x8e\xcb\x8e\xdf" => "\xa5\xd4", #¥Ô + "\x8e\xcc\x8e\xdf" => "\xa5\xd7", #¥× + "\x8e\xcd\x8e\xdf" => "\xa5\xda", #¥Ú + "\x8e\xce\x8e\xdf" => "\xa5\xdd", #¥Ý + "\x8e\xb3\x8e\xde" => "\xa5\xf4", #¥ô +); + +# init only once; + +#$_PAT_D2Z = join("|", keys %_D2Z); +#$_PAT_H2Z = join("|", keys %_H2Z); + +%_Z2H = reverse %_H2Z; +%_Z2D = reverse %_D2Z; + +#$_PAT_Z2H = join("|", keys %_Z2H); +#$_PAT_Z2D = join("|", keys %_Z2D); + +sub h2z { + no warnings qw(uninitialized); + my $r_str = shift; + my ($keep_dakuten) = @_; + my $n = 0; + unless ($keep_dakuten) { + $n = ( + $$r_str =~ s( + ($RE{EUC_KANA} + (?:\x8e[\xde\xdf])?) + ){ + my $str = $1; + $_D2Z{$str} || $_H2Z{$str} || + # in case dakuten and handakuten are side-by-side! + $_H2Z{substr($str,0,2)} . $_H2Z{substr($str,2,2)}; + }eogx + ); + } + else { + $n = ( + $$r_str =~ s( + ($RE{EUC_KANA}) + ){ + $_H2Z{$1}; + }eogx + ); + } + $n; +} + +sub z2h { + my $r_str = shift; + my $n = ( + $$r_str =~ s( + ($RE{EUC_C}|$RE{EUC_0212}|$RE{EUC_KANA}) + ){ + $_Z2D{$1} || $_Z2H{$1} || $1; + }eogx + ); + $n; +} + +1; +__END__ + + +=head1 NAME + +Encode::JP::H2Z -- internally used by Encode::JP::2022_JP* + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/JP/JIS7.pm b/Master/tlpkg/tlperl/lib/Encode/JP/JIS7.pm new file mode 100644 index 00000000000..3b5699c7fd0 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/JP/JIS7.pm @@ -0,0 +1,165 @@ +package Encode::JP::JIS7; +use strict; +use warnings; +our $VERSION = do { my @r = ( q$Revision: 2.4 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; + +use Encode qw(:fallbacks); + +for my $name ( '7bit-jis', 'iso-2022-jp', 'iso-2022-jp-1' ) { + my $h2z = ( $name eq '7bit-jis' ) ? 0 : 1; + my $jis0212 = ( $name eq 'iso-2022-jp' ) ? 0 : 1; + + $Encode::Encoding{$name} = bless { + Name => $name, + h2z => $h2z, + jis0212 => $jis0212, + } => __PACKAGE__; +} + +use base qw(Encode::Encoding); + +# we override this to 1 so PerlIO works +sub needs_lines { 1 } + +use Encode::CJKConstants qw(:all); + +# +# decode is identical for all 2022 variants +# + +sub decode($$;$) { + my ( $obj, $str, $chk ) = @_; + my $residue = ''; + if ($chk) { + $str =~ s/([^\x00-\x7f].*)$//so and $residue = $1; + } + $residue .= jis_euc( \$str ); + $_[1] = $residue if $chk; + return Encode::decode( 'euc-jp', $str, FB_PERLQQ ); +} + +# +# encode is different +# + +sub encode($$;$) { + require Encode::JP::H2Z; + my ( $obj, $utf8, $chk ) = @_; + + # empty the input string in the stack so perlio is ok + $_[1] = '' if $chk; + my ( $h2z, $jis0212 ) = @$obj{qw(h2z jis0212)}; + my $octet = Encode::encode( 'euc-jp', $utf8, $chk ); + $h2z and &Encode::JP::H2Z::h2z( \$octet ); + euc_jis( \$octet, $jis0212 ); + return $octet; +} + +# +# cat_decode +# +my $re_scan_jis_g = qr{ + \G ( ($RE{JIS_0212}) | $RE{JIS_0208} | + ($RE{ISO_ASC}) | ($RE{JIS_KANA}) | ) + ([^\e]*) +}x; + +sub cat_decode { # ($obj, $dst, $src, $pos, $trm, $chk) + my ( $obj, undef, undef, $pos, $trm ) = @_; # currently ignores $chk + my ( $rdst, $rsrc, $rpos ) = \@_[ 1, 2, 3 ]; + local ${^ENCODING}; + use bytes; + my $opos = pos($$rsrc); + pos($$rsrc) = $pos; + while ( $$rsrc =~ /$re_scan_jis_g/gc ) { + my ( $esc, $esc_0212, $esc_asc, $esc_kana, $chunk ) = + ( $1, $2, $3, $4, $5 ); + + unless ($chunk) { $esc or last; next; } + + if ( $esc && !$esc_asc ) { + $chunk =~ tr/\x21-\x7e/\xa1-\xfe/; + if ($esc_kana) { + $chunk =~ s/([\xa1-\xdf])/\x8e$1/og; + } + elsif ($esc_0212) { + $chunk =~ s/([\xa1-\xfe][\xa1-\xfe])/\x8f$1/og; + } + $chunk = Encode::decode( 'euc-jp', $chunk, 0 ); + } + elsif ( ( my $npos = index( $chunk, $trm ) ) >= 0 ) { + $$rdst .= substr( $chunk, 0, $npos + length($trm) ); + $$rpos += length($esc) + $npos + length($trm); + pos($$rsrc) = $opos; + return 1; + } + $$rdst .= $chunk; + $$rpos = pos($$rsrc); + } + $$rpos = pos($$rsrc); + pos($$rsrc) = $opos; + return ''; +} + +# JIS<->EUC +my $re_scan_jis = qr{ + (?:($RE{JIS_0212})|$RE{JIS_0208}|($RE{ISO_ASC})|($RE{JIS_KANA}))([^\e]*) +}x; + +sub jis_euc { + local ${^ENCODING}; + my $r_str = shift; + $$r_str =~ s($re_scan_jis) + { + my ($esc_0212, $esc_asc, $esc_kana, $chunk) = + ($1, $2, $3, $4); + if (!$esc_asc) { + $chunk =~ tr/\x21-\x7e/\xa1-\xfe/; + if ($esc_kana) { + $chunk =~ s/([\xa1-\xdf])/\x8e$1/og; + } + elsif ($esc_0212) { + $chunk =~ s/([\xa1-\xfe][\xa1-\xfe])/\x8f$1/og; + } + } + $chunk; + }geox; + my ($residue) = ( $$r_str =~ s/(\e.*)$//so ); + return $residue; +} + +sub euc_jis { + no warnings qw(uninitialized); + local ${^ENCODING}; + my $r_str = shift; + my $jis0212 = shift; + $$r_str =~ s{ + ((?:$RE{EUC_C})+|(?:$RE{EUC_KANA})+|(?:$RE{EUC_0212})+) + }{ + my $chunk = $1; + my $esc = + ( $chunk =~ tr/\x8E//d ) ? $ESC{KANA} : + ( $chunk =~ tr/\x8F//d ) ? $ESC{JIS_0212} : + $ESC{JIS_0208}; + if ($esc eq $ESC{JIS_0212} && !$jis0212){ + # fallback to '?' + $chunk =~ tr/\xA1-\xFE/\x3F/; + }else{ + $chunk =~ tr/\xA1-\xFE/\x21-\x7E/; + } + $esc . $chunk . $ESC{ASC}; + }geox; + $$r_str =~ s/\Q$ESC{ASC}\E + (\Q$ESC{KANA}\E|\Q$ESC{JIS_0212}\E|\Q$ESC{JIS_0208}\E)/$1/gox; + $$r_str; +} + +1; +__END__ + + +=head1 NAME + +Encode::JP::JIS7 -- internally used by Encode::JP + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/KR.pm b/Master/tlpkg/tlperl/lib/Encode/KR.pm new file mode 100644 index 00000000000..cf2c1174e4b --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/KR.pm @@ -0,0 +1,69 @@ +package Encode::KR; +BEGIN { + if ( ord("A") == 193 ) { + die "Encode::KR not supported on EBCDIC\n"; + } +} +use strict; +use warnings; +use Encode; +our $VERSION = do { my @r = ( q$Revision: 2.3 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; +use XSLoader; +XSLoader::load( __PACKAGE__, $VERSION ); + +use Encode::KR::2022_KR; + +1; +__END__ + +=head1 NAME + +Encode::KR - Korean Encodings + +=head1 SYNOPSIS + + use Encode qw/encode decode/; + $euc_kr = encode("euc-kr", $utf8); # loads Encode::KR implicitly + $utf8 = decode("euc-kr", $euc_kr); # ditto + +=head1 DESCRIPTION + +This module implements Korean charset encodings. Encodings supported +are as follows. + + + Canonical Alias Description + -------------------------------------------------------------------- + euc-kr /\beuc.*kr$/i EUC (Extended Unix Character) + /\bkr.*euc$/i + ksc5601-raw Korean standard code set (as is) + cp949 /(?:x-)?uhc$/i + /(?:x-)?windows-949$/i + /\bks_c_5601-1987$/i + Code Page 949 (EUC-KR + 8,822 + (additional Hangul syllables) + MacKorean EUC-KR + Apple Vendor Mappings + johab JOHAB A supplementary encoding defined in + Annex 3 of KS X 1001:1998 + iso-2022-kr iso-2022-kr [RFC1557] + -------------------------------------------------------------------- + +To find how to use this module in detail, see L<Encode>. + +=head1 BUGS + +When you see C<charset=ks_c_5601-1987> on mails and web pages, they really +mean "cp949" encodings. To fix that, the following aliases are set; + + qr/(?:x-)?uhc$/i => '"cp949"' + qr/(?:x-)?windows-949$/i => '"cp949"' + qr/ks_c_5601-1987$/i => '"cp949"' + +The ASCII region (0x00-0x7f) is preserved for all encodings, even +though this conflicts with mappings by the Unicode Consortium. + +=head1 SEE ALSO + +L<Encode> + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/KR/2022_KR.pm b/Master/tlpkg/tlperl/lib/Encode/KR/2022_KR.pm new file mode 100644 index 00000000000..0218d971ee2 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/KR/2022_KR.pm @@ -0,0 +1,81 @@ +package Encode::KR::2022_KR; +use strict; +use warnings; +our $VERSION = do { my @r = ( q$Revision: 2.2 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; + +use Encode qw(:fallbacks); + +use base qw(Encode::Encoding); +__PACKAGE__->Define('iso-2022-kr'); + +sub needs_lines { 1 } + +sub perlio_ok { + return 0; # for the time being +} + +sub decode { + my ( $obj, $str, $chk ) = @_; + my $res = $str; + my $residue = iso_euc( \$res ); + + # This is for PerlIO + $_[1] = $residue if $chk; + return Encode::decode( 'euc-kr', $res, FB_PERLQQ ); +} + +sub encode { + my ( $obj, $utf8, $chk ) = @_; + + # empty the input string in the stack so perlio is ok + $_[1] = '' if $chk; + my $octet = Encode::encode( 'euc-kr', $utf8, FB_PERLQQ ); + euc_iso( \$octet ); + return $octet; +} + +use Encode::CJKConstants qw(:all); + +# ISO<->EUC + +sub iso_euc { + my $r_str = shift; + $$r_str =~ s/$RE{'2022_KR'}//gox; # remove the designator + $$r_str =~ s{ # replace characters in GL + \x0e # between SO(\x0e) and SI(\x0f) + ([^\x0f]*) # with characters in GR + \x0f + } + { + my $out= $1; + $out =~ tr/\x21-\x7e/\xa1-\xfe/; + $out; + }geox; + my ($residue) = ( $$r_str =~ s/(\e.*)$//so ); + return $residue; +} + +sub euc_iso { + no warnings qw(uninitialized); + my $r_str = shift; + substr( $$r_str, 0, 0 ) = + $ESC{'2022_KR'}; # put the designator at the beg. + $$r_str =~ + s{ # move KS X 1001 characters in GR to GL + ($RE{EUC_C}+) # and enclose them with SO and SI + }{ + my $str = $1; + $str =~ tr/\xA1-\xFE/\x21-\x7E/; + "\x0e" . $str . "\x0f"; + }geox; + $$r_str; +} + +1; +__END__ + +=head1 NAME + +Encode::KR::2022_KR -- internally used by Encode::KR + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/MIME/Header.pm b/Master/tlpkg/tlperl/lib/Encode/MIME/Header.pm new file mode 100644 index 00000000000..9728dc32d89 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/MIME/Header.pm @@ -0,0 +1,241 @@ +package Encode::MIME::Header; +use strict; +use warnings; +no warnings 'redefine'; + +our $VERSION = do { my @r = ( q$Revision: 2.11 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; +use Encode qw(find_encoding encode_utf8 decode_utf8); +use MIME::Base64; +use Carp; + +my %seed = ( + decode_b => '1', # decodes 'B' encoding ? + decode_q => '1', # decodes 'Q' encoding ? + encode => 'B', # encode with 'B' or 'Q' ? + bpl => 75, # bytes per line +); + +$Encode::Encoding{'MIME-Header'} = + bless { %seed, Name => 'MIME-Header', } => __PACKAGE__; + +$Encode::Encoding{'MIME-B'} = bless { + %seed, + decode_q => 0, + Name => 'MIME-B', +} => __PACKAGE__; + +$Encode::Encoding{'MIME-Q'} = bless { + %seed, + decode_q => 1, + encode => 'Q', + Name => 'MIME-Q', +} => __PACKAGE__; + +use base qw(Encode::Encoding); + +sub needs_lines { 1 } +sub perlio_ok { 0 } + +sub decode($$;$) { + use utf8; + my ( $obj, $str, $chk ) = @_; + + # zap spaces between encoded words + $str =~ s/\?=\s+=\?/\?==\?/gos; + + # multi-line header to single line + $str =~ s/(?:\r\n|[\r\n])[ \t]//gos; + + 1 while ( $str =~ + s/(=\?[-0-9A-Za-z_]+\?[Qq]\?)(.*?)\?=\1(.*?\?=)/$1$2$3/ ) + ; # Concat consecutive QP encoded mime headers + # Fixes breaking inside multi-byte characters + + $str =~ s{ + =\? # begin encoded word + ([-0-9A-Za-z_]+) # charset (encoding) + (?:\*[A-Za-z]{1,8}(?:-[A-Za-z]{1,8})*)? # language (RFC 2231) + \?([QqBb])\? # delimiter + (.*?) # Base64-encodede contents + \?= # end encoded word + }{ + if (uc($2) eq 'B'){ + $obj->{decode_b} or croak qq(MIME "B" unsupported); + decode_b($1, $3, $chk); + } elsif (uc($2) eq 'Q'){ + $obj->{decode_q} or croak qq(MIME "Q" unsupported); + decode_q($1, $3, $chk); + } else { + croak qq(MIME "$2" encoding is nonexistent!); + } + }egox; + $_[1] = $str if $chk; + return $str; +} + +sub decode_b { + my $enc = shift; + my $d = find_encoding($enc) or croak qq(Unknown encoding "$enc"); + my $db64 = decode_base64(shift); + my $chk = shift; + return $d->name eq 'utf8' + ? Encode::decode_utf8($db64) + : $d->decode( $db64, $chk || Encode::FB_PERLQQ ); +} + +sub decode_q { + my ( $enc, $q, $chk ) = @_; + my $d = find_encoding($enc) or croak qq(Unknown encoding "$enc"); + $q =~ s/_/ /go; + $q =~ s/=([0-9A-Fa-f]{2})/pack("C", hex($1))/ego; + return $d->name eq 'utf8' + ? Encode::decode_utf8($q) + : $d->decode( $q, $chk || Encode::FB_PERLQQ ); +} + +my $especials = + join( '|' => map { quotemeta( chr($_) ) } + unpack( "C*", qq{()<>@,;:"'/[]?.=} ) ); + +my $re_encoded_word = qr{ + =\? # begin encoded word + (?:[-0-9A-Za-z_]+) # charset (encoding) + (?:\*[A-Za-z]{1,8}(?:-[A-Za-z]{1,8})*)? # language (RFC 2231) + \?(?:[QqBb])\? # delimiter + (?:.*?) # Base64-encodede contents + \?= # end encoded word +}xo; + +my $re_especials = qr{$re_encoded_word|$especials}xo; + +sub encode($$;$) { + my ( $obj, $str, $chk ) = @_; + my @line = (); + for my $line ( split /\r\n|[\r\n]/o, $str ) { + my ( @word, @subline ); + for my $word ( split /($re_especials)/o, $line ) { + if ( $word =~ /[^\x00-\x7f]/o + or $word =~ /^$re_encoded_word$/o ) + { + push @word, $obj->_encode($word); + } + else { + push @word, $word; + } + } + my $subline = ''; + for my $word (@word) { + use bytes (); + if ( bytes::length($subline) + bytes::length($word) > + $obj->{bpl} ) + { + push @subline, $subline; + $subline = ''; + } + $subline .= $word; + } + $subline and push @subline, $subline; + push @line, join( "\n " => @subline ); + } + $_[1] = '' if $chk; + return join( "\n", @line ); +} + +use constant HEAD => '=?UTF-8?'; +use constant TAIL => '?='; +use constant SINGLE => { B => \&_encode_b, Q => \&_encode_q, }; + +sub _encode { + my ( $o, $str ) = @_; + my $enc = $o->{encode}; + my $llen = ( $o->{bpl} - length(HEAD) - 2 - length(TAIL) ); + + # to coerce a floating-point arithmetics, the following contains + # .0 in numbers -- dankogai + $llen *= $enc eq 'B' ? 3.0 / 4.0 : 1.0 / 3.0; + my @result = (); + my $chunk = ''; + while ( length( my $chr = substr( $str, 0, 1, '' ) ) ) { + use bytes (); + if ( bytes::length($chunk) + bytes::length($chr) > $llen ) { + push @result, SINGLE->{$enc}($chunk); + $chunk = ''; + } + $chunk .= $chr; + } + length($chunk) and push @result, SINGLE->{$enc}($chunk); + return @result; +} + +sub _encode_b { + HEAD . 'B?' . encode_base64( encode_utf8(shift), '' ) . TAIL; +} + +sub _encode_q { + my $chunk = shift; + $chunk = encode_utf8($chunk); + $chunk =~ s{ + ([^0-9A-Za-z]) + }{ + join("" => map {sprintf "=%02X", $_} unpack("C*", $1)) + }egox; + return HEAD . 'Q?' . $chunk . TAIL; +} + +1; +__END__ + +=head1 NAME + +Encode::MIME::Header -- MIME 'B' and 'Q' header encoding + +=head1 SYNOPSIS + + use Encode qw/encode decode/; + $utf8 = decode('MIME-Header', $header); + $header = encode('MIME-Header', $utf8); + +=head1 ABSTRACT + +This module implements RFC 2047 Mime Header Encoding. There are 3 +variant encoding names; C<MIME-Header>, C<MIME-B> and C<MIME-Q>. The +difference is described below + + decode() encode() + ---------------------------------------------- + MIME-Header Both B and Q =?UTF-8?B?....?= + MIME-B B only; Q croaks =?UTF-8?B?....?= + MIME-Q Q only; B croaks =?UTF-8?Q?....?= + +=head1 DESCRIPTION + +When you decode(=?I<encoding>?I<X>?I<ENCODED WORD>?=), I<ENCODED WORD> +is extracted and decoded for I<X> encoding (B for Base64, Q for +Quoted-Printable). Then the decoded chunk is fed to +decode(I<encoding>). So long as I<encoding> is supported by Encode, +any source encoding is fine. + +When you encode, it just encodes UTF-8 string with I<X> encoding then +quoted with =?UTF-8?I<X>?....?= . The parts that RFC 2047 forbids to +encode are left as is and long lines are folded within 76 bytes per +line. + +=head1 BUGS + +It would be nice to support encoding to non-UTF8, such as =?ISO-2022-JP? +and =?ISO-8859-1?= but that makes the implementation too complicated. +These days major mail agents all support =?UTF-8? so I think it is +just good enough. + +Due to popular demand, 'MIME-Header-ISO_2022_JP' was introduced by +Makamaka. Thre are still too many MUAs especially cellular phone +handsets which does not grok UTF-8. + +=head1 SEE ALSO + +L<Encode> + +RFC 2047, L<http://www.faqs.org/rfcs/rfc2047.html> and many other +locations. + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/MIME/Header/ISO_2022_JP.pm b/Master/tlpkg/tlperl/lib/Encode/MIME/Header/ISO_2022_JP.pm new file mode 100644 index 00000000000..4abfbd05ef8 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/MIME/Header/ISO_2022_JP.pm @@ -0,0 +1,131 @@ +package Encode::MIME::Header::ISO_2022_JP; + +use strict; +use warnings; + +use base qw(Encode::MIME::Header); + +$Encode::Encoding{'MIME-Header-ISO_2022_JP'} = + bless { encode => 'B', bpl => 76, Name => 'MIME-Header-ISO_2022_JP' } => + __PACKAGE__; + +use constant HEAD => '=?ISO-2022-JP?B?'; +use constant TAIL => '?='; + +use Encode::CJKConstants qw(%RE); + +our $VERSION = do { my @r = ( q$Revision: 1.3 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; + +# I owe the below codes totally to +# Jcode by Dan Kogai & http://www.din.or.jp/~ohzaki/perl.htm#JP_Base64 + +sub encode { + my $self = shift; + my $str = shift; + + utf8::encode($str) if ( Encode::is_utf8($str) ); + Encode::from_to( $str, 'utf8', 'euc-jp' ); + + my ($trailing_crlf) = ( $str =~ /(\n|\r|\x0d\x0a)$/o ); + + $str = _mime_unstructured_header( $str, $self->{bpl} ); + + not $trailing_crlf and $str =~ s/(\n|\r|\x0d\x0a)$//o; + + return $str; +} + +sub _mime_unstructured_header { + my ( $oldheader, $bpl ) = @_; + my $crlf = $oldheader =~ /\n$/; + my ( $header, @words, @wordstmp, $i ) = (''); + + $oldheader =~ s/\s+$//; + + @wordstmp = split /\s+/, $oldheader; + + for ( $i = 0 ; $i < $#wordstmp ; $i++ ) { + if ( $wordstmp[$i] !~ /^[\x21-\x7E]+$/ + and $wordstmp[ $i + 1 ] !~ /^[\x21-\x7E]+$/ ) + { + $wordstmp[ $i + 1 ] = "$wordstmp[$i] $wordstmp[$i + 1]"; + } + else { + push( @words, $wordstmp[$i] ); + } + } + + push( @words, $wordstmp[-1] ); + + for my $word (@words) { + if ( $word =~ /^[\x21-\x7E]+$/ ) { + $header =~ /(?:.*\n)*(.*)/; + if ( length($1) + length($word) > $bpl ) { + $header .= "\n $word"; + } + else { + $header .= $word; + } + } + else { + $header = _add_encoded_word( $word, $header, $bpl ); + } + + $header =~ /(?:.*\n)*(.*)/; + + if ( length($1) == $bpl ) { + $header .= "\n "; + } + else { + $header .= ' '; + } + } + + $header =~ s/\n? $//mg; + + $crlf ? "$header\n" : $header; +} + +sub _add_encoded_word { + my ( $str, $line, $bpl ) = @_; + my $result = ''; + + while ( length($str) ) { + my $target = $str; + $str = ''; + + if ( + length($line) + 22 + + ( $target =~ /^(?:$RE{EUC_0212}|$RE{EUC_C})/o ) * 8 > $bpl ) + { + $line =~ s/[ \t\n\r]*$/\n/; + $result .= $line; + $line = ' '; + } + + while (1) { + my $iso_2022_jp = $target; + Encode::from_to( $iso_2022_jp, 'euc-jp', 'iso-2022-jp' ); + + my $encoded = + HEAD . MIME::Base64::encode_base64( $iso_2022_jp, '' ) . TAIL; + + if ( length($encoded) + length($line) > $bpl ) { + $target =~ + s/($RE{EUC_0212}|$RE{EUC_KANA}|$RE{EUC_C}|$RE{ASCII})$//o; + $str = $1 . $str; + } + else { + $line .= $encoded; + last; + } + } + + } + + $result . $line; +} + +1; +__END__ + diff --git a/Master/tlpkg/tlperl/lib/Encode/MIME/Name.pm b/Master/tlpkg/tlperl/lib/Encode/MIME/Name.pm new file mode 100644 index 00000000000..10d86a746dc --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/MIME/Name.pm @@ -0,0 +1,94 @@ +package Encode::MIME::Name; +use strict; +use warnings; +our $VERSION = do { my @r = ( q$Revision: 1.1 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; + +our %MIME_NAME_OF = ( + 'AdobeStandardEncoding' => 'Adobe-Standard-Encoding', + 'AdobeSymbol' => 'Adobe-Symbol-Encoding', + 'ascii' => 'US-ASCII', + 'big5-hkscs' => 'Big5-HKSCS', + 'cp1026' => 'IBM1026', + 'cp1047' => 'IBM1047', + 'cp1250' => 'windows-1250', + 'cp1251' => 'windows-1251', + 'cp1252' => 'windows-1252', + 'cp1253' => 'windows-1253', + 'cp1254' => 'windows-1254', + 'cp1255' => 'windows-1255', + 'cp1256' => 'windows-1256', + 'cp1257' => 'windows-1257', + 'cp1258' => 'windows-1258', + 'cp37' => 'IBM037', + 'cp424' => 'IBM424', + 'cp437' => 'IBM437', + 'cp500' => 'IBM500', + 'cp775' => 'IBM775', + 'cp850' => 'IBM850', + 'cp852' => 'IBM852', + 'cp855' => 'IBM855', + 'cp857' => 'IBM857', + 'cp860' => 'IBM860', + 'cp861' => 'IBM861', + 'cp862' => 'IBM862', + 'cp863' => 'IBM863', + 'cp864' => 'IBM864', + 'cp865' => 'IBM865', + 'cp866' => 'IBM866', + 'cp869' => 'IBM869', + 'cp936' => 'GBK', + 'euc-jp' => 'EUC-JP', + 'euc-kr' => 'EUC-KR', + #'gb2312-raw' => 'GB2312', # no, you're wrong, I18N::Charset + 'hp-roman8' => 'hp-roman8', + 'hz' => 'HZ-GB-2312', + 'iso-2022-jp' => 'ISO-2022-JP', + 'iso-2022-jp-1' => 'ISO-2022-JP', + 'iso-2022-kr' => 'ISO-2022-KR', + 'iso-8859-1' => 'ISO-8859-1', + 'iso-8859-10' => 'ISO-8859-10', + 'iso-8859-13' => 'ISO-8859-13', + 'iso-8859-14' => 'ISO-8859-14', + 'iso-8859-15' => 'ISO-8859-15', + 'iso-8859-16' => 'ISO-8859-16', + 'iso-8859-2' => 'ISO-8859-2', + 'iso-8859-3' => 'ISO-8859-3', + 'iso-8859-4' => 'ISO-8859-4', + 'iso-8859-5' => 'ISO-8859-5', + 'iso-8859-6' => 'ISO-8859-6', + 'iso-8859-7' => 'ISO-8859-7', + 'iso-8859-8' => 'ISO-8859-8', + 'iso-8859-9' => 'ISO-8859-9', + #'jis0201-raw' => 'JIS_X0201', + #'jis0208-raw' => 'JIS_C6226-1983', + #'jis0212-raw' => 'JIS_X0212-1990', + 'koi8-r' => 'KOI8-R', + 'koi8-u' => 'KOI8-U', + #'ksc5601-raw' => 'KS_C_5601-1987', + 'shiftjis' => 'Shift_JIS', + 'UTF-16' => 'UTF-16', + 'UTF-16BE' => 'UTF-16BE', + 'UTF-16LE' => 'UTF-16LE', + 'UTF-32' => 'UTF-32', + 'UTF-32BE' => 'UTF-32BE', + 'UTF-32LE' => 'UTF-32LE', + 'UTF-7' => 'UTF-7', + 'utf8' => 'UTF-8', + 'utf-8-strict' => 'UTF-8', + 'viscii' => 'VISCII', +); + +sub get_mime_name($) { $MIME_NAME_OF{$_[0]} }; + +1; +__END__ + +=head1 NAME + +Encode::MIME::NAME -- internally used by Encode + +=head1 SEE ALSO + +L<I18N::Charset> + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/Makefile_PL.e2x b/Master/tlpkg/tlperl/lib/Encode/Makefile_PL.e2x new file mode 100644 index 00000000000..1d83a2fbda2 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/Makefile_PL.e2x @@ -0,0 +1,180 @@ +# +# This file is auto-generated by: +# enc2xs version $_Version_ +# $_Now_ +# +use 5.7.2; +use strict; +use ExtUtils::MakeMaker; +use Config; + +# Please edit the following to the taste! +my $name = '$_Name_'; +my %tables = ( + $_Name__t => [ $_TableFiles_ ], + ); + +#### DO NOT EDIT BEYOND THIS POINT! +require File::Spec; +my ($enc2xs, $encode_h) = (); +PATHLOOP: +for my $d (@Config{qw/bin sitebin vendorbin/}, + (split /$Config{path_sep}/o, $ENV{PATH})){ + for my $f (qw/enc2xs enc2xs5.7.3/){ + my $path = File::Spec->catfile($d, $f); + -r $path and $enc2xs = $path and last PATHLOOP; + } +} +$enc2xs or die "enc2xs not found!"; +print "enc2xs is $enc2xs\n"; +my %encode_h = (); +for my $d (@INC){ + my $dir = File::Spec->catfile($d, "Encode"); + my $file = File::Spec->catfile($dir, "encode.h"); + -f $file and $encode_h{$dir} = -M $file; +} +%encode_h or die "encode.h not found!"; +# find the latest one +($encode_h) = sort {$encode_h{$b} <=> $encode_h{$a}} keys %encode_h; +print "encode.h is at $encode_h\n"; + +WriteMakefile( + INC => "-I$encode_h", +#### END_OF_HEADER -- DO NOT EDIT THIS LINE BY HAND! #### + NAME => 'Encode::'.$name, + VERSION_FROM => "$name.pm", + OBJECT => '$(O_FILES)', + 'dist' => { + COMPRESS => 'gzip -9f', + SUFFIX => 'gz', + DIST_DEFAULT => 'all tardist', + }, + MAN3PODS => {}, + PREREQ_PM => { + 'Encode' => "1.41", + }, + # OS 390 winges about line numbers > 64K ??? + XSOPT => '-nolinenumbers', + ); + +package MY; + +sub post_initialize +{ + my ($self) = @_; + my %o; + my $x = $self->{'OBJ_EXT'}; + # Add the table O_FILES + foreach my $e (keys %tables) + { + $o{$e.$x} = 1; + } + $o{"$name$x"} = 1; + $self->{'O_FILES'} = [sort keys %o]; + my @files = ("$name.xs"); + $self->{'C'} = ["$name.c"]; + # The next two lines to make MacPerl Happy -- dankogai via pudge + $self->{SOURCE} .= " $name.c" + if $^O eq 'MacOS' && $self->{SOURCE} !~ /\b$name\.c\b/; + # $self->{'H'} = [$self->catfile($self->updir,'encode.h')]; + my %xs; + foreach my $table (keys %tables) { + push (@{$self->{'C'}},"$table.c"); + # Do NOT add $table.h etc. to H_FILES unless we own up as to how they + # get built. + foreach my $ext (qw($(OBJ_EXT) .c .h .exh .fnm)) { + push (@files,$table.$ext); + } + } + $self->{'XS'} = { "$name.xs" => "$name.c" }; + $self->{'clean'}{'FILES'} .= join(' ',@files); + open(XS,">$name.xs") || die "Cannot open $name.xs:$!"; + print XS <<'END'; +#include <EXTERN.h> +#include <perl.h> +#include <XSUB.h> +#define U8 U8 +#include "encode.h" +END + foreach my $table (keys %tables) { + print XS qq[#include "${table}.h"\n]; + } + print XS <<"END"; + +static void +Encode_XSEncoding(pTHX_ encode_t *enc) +{ + dSP; + HV *stash = gv_stashpv("Encode::XS", TRUE); + SV *sv = sv_bless(newRV_noinc(newSViv(PTR2IV(enc))),stash); + int i = 0; + PUSHMARK(sp); + XPUSHs(sv); + while (enc->name[i]) + { + const char *name = enc->name[i++]; + XPUSHs(sv_2mortal(newSVpvn(name,strlen(name)))); + } + PUTBACK; + call_pv("Encode::define_encoding",G_DISCARD); + SvREFCNT_dec(sv); +} + +MODULE = Encode::$name PACKAGE = Encode::$name +PROTOTYPES: DISABLE +BOOT: +{ +END + foreach my $table (keys %tables) { + print XS qq[#include "${table}.exh"\n]; + } + print XS "}\n"; + close(XS); + return "# Built $name.xs\n\n"; +} + +sub postamble +{ + my $self = shift; + my $dir = "."; # $self->catdir('Encode'); + my $str = "# $name\$(OBJ_EXT) depends on .h and .exh files not .c files - but all written by enc2xs\n"; + $str .= "$name.c : $name.xs "; + foreach my $table (keys %tables) + { + $str .= " $table.c"; + } + $str .= "\n\n"; + $str .= "$name\$(OBJ_EXT) : $name.c\n\n"; + + foreach my $table (keys %tables) + { + my $numlines = 1; + my $lengthsofar = length($str); + my $continuator = ''; + $str .= "$table.c : Makefile.PL"; + foreach my $file (@{$tables{$table}}) + { + $str .= $continuator.' '.$self->catfile($dir,$file); + if ( length($str)-$lengthsofar > 128*$numlines ) + { + $continuator .= " \\\n\t"; + $numlines++; + } else { + $continuator = ''; + } + } + my $plib = $self->{PERL_CORE} ? '"-I$(PERL_LIB)"' : ''; + my $ucopts = '-"Q"'; + $str .= + qq{\n\t\$(PERL) $plib $enc2xs $ucopts -o \$\@ -f $table.fnm\n\n}; + open (FILELIST, ">$table.fnm") + || die "Could not open $table.fnm: $!"; + foreach my $file (@{$tables{$table}}) + { + print FILELIST $self->catfile($dir,$file) . "\n"; + } + close(FILELIST); + } + return $str; +} + diff --git a/Master/tlpkg/tlperl/lib/Encode/PerlIO.pod b/Master/tlpkg/tlperl/lib/Encode/PerlIO.pod new file mode 100644 index 00000000000..1a9269a9b0c --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/PerlIO.pod @@ -0,0 +1,167 @@ +=head1 NAME + +Encode::PerlIO -- a detailed document on Encode and PerlIO + +=head1 Overview + +It is very common to want to do encoding transformations when +reading or writing files, network connections, pipes etc. +If Perl is configured to use the new 'perlio' IO system then +C<Encode> provides a "layer" (see L<PerlIO>) which can transform +data as it is read or written. + +Here is how the blind poet would modernise the encoding: + + use Encode; + open(my $iliad,'<:encoding(iso-8859-7)','iliad.greek'); + open(my $utf8,'>:utf8','iliad.utf8'); + my @epic = <$iliad>; + print $utf8 @epic; + close($utf8); + close($illiad); + +In addition, the new IO system can also be configured to read/write +UTF-8 encoded characters (as noted above, this is efficient): + + open(my $fh,'>:utf8','anything'); + print $fh "Any \x{0021} string \N{SMILEY FACE}\n"; + +Either of the above forms of "layer" specifications can be made the default +for a lexical scope with the C<use open ...> pragma. See L<open>. + +Once a handle is open, its layers can be altered using C<binmode>. + +Without any such configuration, or if Perl itself is built using the +system's own IO, then write operations assume that the file handle +accepts only I<bytes> and will C<die> if a character larger than 255 is +written to the handle. When reading, each octet from the handle becomes +a byte-in-a-character. Note that this default is the same behaviour +as bytes-only languages (including Perl before v5.6) would have, +and is sufficient to handle native 8-bit encodings e.g. iso-8859-1, +EBCDIC etc. and any legacy mechanisms for handling other encodings +and binary data. + +In other cases, it is the program's responsibility to transform +characters into bytes using the API above before doing writes, and to +transform the bytes read from a handle into characters before doing +"character operations" (e.g. C<lc>, C</\W+/>, ...). + +You can also use PerlIO to convert larger amounts of data you don't +want to bring into memory. For example, to convert between ISO-8859-1 +(Latin 1) and UTF-8 (or UTF-EBCDIC in EBCDIC machines): + + open(F, "<:encoding(iso-8859-1)", "data.txt") or die $!; + open(G, ">:utf8", "data.utf") or die $!; + while (<F>) { print G } + + # Could also do "print G <F>" but that would pull + # the whole file into memory just to write it out again. + +More examples: + + open(my $f, "<:encoding(cp1252)") + open(my $g, ">:encoding(iso-8859-2)") + open(my $h, ">:encoding(latin9)") # iso-8859-15 + +See also L<encoding> for how to change the default encoding of the +data in your script. + +=head1 How does it work? + +Here is a crude diagram of how filehandle, PerlIO, and Encode +interact. + + filehandle <-> PerlIO PerlIO <-> scalar (read/printed) + \ / + Encode + +When PerlIO receives data from either direction, it fills a buffer +(currently with 1024 bytes) and passes the buffer to Encode. +Encode tries to convert the valid part and passes it back to PerlIO, +leaving invalid parts (usually a partial character) in the buffer. +PerlIO then appends more data to the buffer, calls Encode again, +and so on until the data stream ends. + +To do so, PerlIO always calls (de|en)code methods with CHECK set to 1. +This ensures that the method stops at the right place when it +encounters partial character. The following is what happens when +PerlIO and Encode tries to encode (from utf8) more than 1024 bytes +and the buffer boundary happens to be in the middle of a character. + + A B C .... ~ \x{3000} .... + 41 42 43 .... 7E e3 80 80 .... + <- buffer ---------------> + << encoded >>>>>>>>>> + <- next buffer ------ + +Encode converts from the beginning to \x7E, leaving \xe3 in the buffer +because it is invalid (partial character). + +Unfortunately, this scheme does not work well with escape-based +encodings such as ISO-2022-JP. + +=head1 Line Buffering + +Now let's see what happens when you try to decode from ISO-2022-JP and +the buffer ends in the middle of a character. + + JIS208-ESC \x{5f3e} + A B C .... ~ \e $ B |DAN | .... + 41 42 43 .... 7E 1b 24 41 43 46 .... + <- buffer ---------------------------> + << encoded >>>>>>>>>>>>>>>>>>>>>>> + +As you see, the next buffer begins with \x43. But \x43 is 'C' in +ASCII, which is wrong in this case because we are now in JISX 0208 +area so it has to convert \x43\x46, not \x43. Unlike utf8 and EUC, +in escape-based encodings you can't tell if a given octet is a whole +character or just part of it. + +Fortunately PerlIO also supports line buffer if you tell PerlIO to use +one instead of fixed buffer. Since ISO-2022-JP is guaranteed to revert to ASCII at the end of the line, partial +character will never happen when line buffer is used. + +To tell PerlIO to use line buffer, implement -E<gt>needs_lines method +for your encoding object. See L<Encode::Encoding> for details. + +Thanks to these efforts most encodings that come with Encode support +PerlIO but that still leaves following encodings. + + iso-2022-kr + MIME-B + MIME-Header + MIME-Q + +Fortunately iso-2022-kr is hardly used (according to Jungshik) and +MIME-* are very unlikely to be fed to PerlIO because they are for mail +headers. See L<Encode::MIME::Header> for details. + +=head2 How can I tell whether my encoding fully supports PerlIO ? + +As of this writing, any encoding whose class belongs to Encode::XS and +Encode::Unicode works. The Encode module has a C<perlio_ok> method +which you can use before applying PerlIO encoding to the filehandle. +Here is an example: + + my $use_perlio = perlio_ok($enc); + my $layer = $use_perlio ? "<:raw" : "<:encoding($enc)"; + open my $fh, $layer, $file or die "$file : $!"; + while(<$fh>){ + $_ = decode($enc, $_) unless $use_perlio; + # .... + } + +=head1 SEE ALSO + +L<Encode::Encoding>, +L<Encode::Supported>, +L<Encode::PerlIO>, +L<encoding>, +L<perlebcdic>, +L<perlfunc/open>, +L<perlunicode>, +L<utf8>, +the Perl Unicode Mailing List E<lt>perl-unicode@perl.orgE<gt> + +=cut + diff --git a/Master/tlpkg/tlperl/lib/Encode/README.e2x b/Master/tlpkg/tlperl/lib/Encode/README.e2x new file mode 100644 index 00000000000..28a31a655c2 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/README.e2x @@ -0,0 +1,31 @@ +Encode::$_Name_ version 0.1 +======== + +NAME + Encode::$_Name_ - <describe encoding> + +SYNOPSIS + use Encode::$_Name_; + #<put more words here> +ABSTRACT + <fill this in> +INSTALLATION + +To install this module type the following: + + perl Makefile.PL + make + make test + make install + +DEPENDENCIES + +This module requires perl version 5.7.3 or later. + +COPYRIGHT AND LICENCE + +Copyright (C) 2002 Your Name <your@address.domain> + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. + diff --git a/Master/tlpkg/tlperl/lib/Encode/Supported.pod b/Master/tlpkg/tlperl/lib/Encode/Supported.pod new file mode 100644 index 00000000000..e84faafd9e2 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/Supported.pod @@ -0,0 +1,901 @@ +=head1 NAME + +Encode::Supported -- Encodings supported by Encode + +=head1 DESCRIPTION + +=head2 Encoding Names + +Encoding names are case insensitive. White space in names +is ignored. In addition, an encoding may have aliases. +Each encoding has one "canonical" name. The "canonical" +name is chosen from the names of the encoding by picking +the first in the following sequence (with a few exceptions). + +=over 2 + +=item * + +The name used by the Perl community. That includes 'utf8' and 'ascii'. +Unlike aliases, canonical names directly reach the method so such +frequently used words like 'utf8' don't need to do alias lookups. + +=item * + +The MIME name as defined in IETF RFCs. This includes all "iso-"s. + +=item * + +The name in the IANA registry. + +=item * + +The name used by the organization that defined it. + +=back + +In case I<de jure> canonical names differ from that of the Encode +module, they are always aliased if it ever be implemented. So you can +safely tell if a given encoding is implemented or not just by passing +the canonical name. + +Because of all the alias issues, and because in the general case +encodings have state, "Encode" uses an encoding object internally +once an operation is in progress. + +=head1 Supported Encodings + +As of Perl 5.8.0, at least the following encodings are recognized. +Note that unless otherwise specified, they are all case insensitive +(via alias) and all occurrence of spaces are replaced with '-'. +In other words, "ISO 8859 1" and "iso-8859-1" are identical. + +Encodings are categorized and implemented in several different modules +but you don't have to C<use Encode::XX> to make them available for +most cases. Encode.pm will automatically load those modules on demand. + +=head2 Built-in Encodings + +The following encodings are always available. + + Canonical Aliases Comments & References + ---------------------------------------------------------------- + ascii US-ascii ISO-646-US [ECMA] + ascii-ctrl Special Encoding + iso-8859-1 latin1 [ISO] + null Special Encoding + utf8 UTF-8 [RFC2279] + ---------------------------------------------------------------- + +I<null> and I<ascii-ctrl> are special. "null" fails for all character +so when you set fallback mode to PERLQQ, HTMLCREF or XMLCREF, ALL +CHARACTERS will fall back to character references. Ditto for +"ascii-ctrl" except for control characters. For fallback modes, see +L<Encode>. + +=head2 Encode::Unicode -- other Unicode encodings + +Unicode coding schemes other than native utf8 are supported by +Encode::Unicode, which will be autoloaded on demand. + + ---------------------------------------------------------------- + UCS-2BE UCS-2, iso-10646-1 [IANA, UC] + UCS-2LE [UC] + UTF-16 [UC] + UTF-16BE [UC] + UTF-16LE [UC] + UTF-32 [UC] + UTF-32BE UCS-4 [UC] + UTF-32LE [UC] + UTF-7 [RFC2152] + ---------------------------------------------------------------- + +To find how (UCS-2|UTF-(16|32))(LE|BE)? differ from one another, +see L<Encode::Unicode>. + +UTF-7 is a special encoding which "re-encodes" UTF-16BE into a 7-bit +encoding. It is implemented seperately by Encode::Unicode::UTF7. + +=head2 Encode::Byte -- Extended ASCII + +Encode::Byte implements most single-byte encodings except for +Symbols and EBCDIC. The following encodings are based on single-byte +encodings implemented as extended ASCII. Most of them map +\x80-\xff (upper half) to non-ASCII characters. + +=over 2 + +=item ISO-8859 and corresponding vendor mappings + +Since there are so many, they are presented in table format with +languages and corresponding encoding names by vendors. Note that +the table is sorted in order of ISO-8859 and the corresponding vendor +mappings are slightly different from that of ISO. See +L<http://czyborra.com/charsets/iso8859.html> for details. + + Lang/Regions ISO/Other Std. DOS Windows Macintosh Others + ---------------------------------------------------------------- + N. America (ASCII) cp437 AdobeStandardEncoding + cp863 (DOSCanadaF) + W. Europe iso-8859-1 cp850 cp1252 MacRoman nextstep + hp-roman8 + cp860 (DOSPortuguese) + Cntrl. Europe iso-8859-2 cp852 cp1250 MacCentralEurRoman + MacCroatian + MacRomanian + MacRumanian + Latin3[1] iso-8859-3 + Latin4[2] iso-8859-4 + Cyrillics iso-8859-5 cp855 cp1251 MacCyrillic + (See also next section) cp866 MacUkrainian + Arabic iso-8859-6 cp864 cp1256 MacArabic + cp1006 MacFarsi + Greek iso-8859-7 cp737 cp1253 MacGreek + cp869 (DOSGreek2) + Hebrew iso-8859-8 cp862 cp1255 MacHebrew + Turkish iso-8859-9 cp857 cp1254 MacTurkish + Nordics iso-8859-10 cp865 + cp861 MacIcelandic + MacSami + Thai iso-8859-11[3] cp874 MacThai + (iso-8859-12 is nonexistent. Reserved for Indics?) + Baltics iso-8859-13 cp775 cp1257 + Celtics iso-8859-14 + Latin9 [4] iso-8859-15 + Latin10 iso-8859-16 + Vietnamese viscii cp1258 MacVietnamese + ---------------------------------------------------------------- + + [1] Esperanto, Maltese, and Turkish. Turkish is now on 8859-9. + [2] Baltics. Now on 8859-10, except for Latvian. + [3] TIS 620 + Non-Breaking Space (0xA0 / U+00A0) + [4] Nicknamed Latin0; the Euro sign as well as French and Finnish + letters that are missing from 8859-1 were added. + +All cp* are also available as ibm-*, ms-*, and windows-* . See also +L<http://czyborra.com/charsets/codepages.html>. + +Macintosh encodings don't seem to be registered in such entities as +IANA. "Canonical" names in Encode are based upon Apple's Tech Note +1150. See L<http://developer.apple.com/technotes/tn/tn1150.html> +for details. + +=item KOI8 - De Facto Standard for the Cyrillic world + +Though ISO-8859 does have ISO-8859-5, the KOI8 series is far more +popular in the Net. L<Encode> comes with the following KOI charsets. +For gory details, see L<http://czyborra.com/charsets/cyrillic.html> + + ---------------------------------------------------------------- + koi8-f + koi8-r cp878 [RFC1489] + koi8-u [RFC2319] + ---------------------------------------------------------------- + +=back + +=head2 gsm0338 - Hentai Latin 1 + +GSM0338 is for GSM handsets. Though it shares alphanumerals with +ASCII, control character ranges and other parts are mapped very +differently, mainly to store Greek characters. There are also escape +sequences (starting with 0x1B) to cover e.g. the Euro sign. + +This was once handled by L<Encode::Bytes> but because of all those +unusual specifications, Encode 2.20 has relocated the support to +L<Encode::GSM0338>. See L<Encode::GSM0338> for details. + +=over 2 + +=item gsm0338 support before 2.19 + +Some special cases like a trailing 0x00 byte or a lone 0x1B byte are not +well-defined and decode() will return an empty string for them. +One possible workaround is + + $gsm =~ s/\x00\z/\x00\x00/; + $uni = decode("gsm0338", $gsm); + $uni .= "\xA0" if $gsm =~ /\x1B\z/; + +Note that the Encode implementation of GSM0338 does not implement the +reuse of Latin capital letters as Greek capital letters (for example, +the 0x5A is U+005A (LATIN CAPITAL LETTER Z), not U+0396 (GREEK CAPITAL +LETTER ZETA). + +The GSM0338 is also covered in Encode::Byte even though it is not +an "extended ASCII" encoding. + +=back + +=head2 CJK: Chinese, Japanese, Korean (Multibyte) + +Note that Vietnamese is listed above. Also read "Encoding vs Charset" +below. Also note that these are implemented in distinct modules by +countries, due to the size concerns (simplified Chinese is mapped +to 'CN', continental China, while traditional Chinese is mapped to +'TW', Taiwan). Please refer to their respective documentation pages. + +=over 2 + +=item Encode::CN -- Continental China + + Standard DOS/Win Macintosh Comment/Reference + ---------------------------------------------------------------- + euc-cn [1] MacChineseSimp + (gbk) cp936 [2] + gb12345-raw { GB12345 without CES } + gb2312-raw { GB2312 without CES } + hz + iso-ir-165 + ---------------------------------------------------------------- + + [1] GB2312 is aliased to this. See L<Microsoft-related naming mess> + [2] gbk is aliased to this. See L<Microsoft-related naming mess> + +=item Encode::JP -- Japan + + Standard DOS/Win Macintosh Comment/Reference + ---------------------------------------------------------------- + euc-jp + shiftjis cp932 macJapanese + 7bit-jis + iso-2022-jp [RFC1468] + iso-2022-jp-1 [RFC2237] + jis0201-raw { JIS X 0201 (roman + halfwidth kana) without CES } + jis0208-raw { JIS X 0208 (Kanji + fullwidth kana) without CES } + jis0212-raw { JIS X 0212 (Extended Kanji) without CES } + ---------------------------------------------------------------- + +=item Encode::KR -- Korea + + Standard DOS/Win Macintosh Comment/Reference + ---------------------------------------------------------------- + euc-kr MacKorean [RFC1557] + cp949 [1] + iso-2022-kr [RFC1557] + johab [KS X 1001:1998, Annex 3] + ksc5601-raw { KSC5601 without CES } + ---------------------------------------------------------------- + + [1] ks_c_5601-1987, (x-)?windows-949, and uhc are aliased to this. + See below. + +=item Encode::TW -- Taiwan + + Standard DOS/Win Macintosh Comment/Reference + ---------------------------------------------------------------- + big5-eten cp950 MacChineseTrad {big5 aliased to big5-eten} + big5-hkscs + ---------------------------------------------------------------- + +=item Encode::HanExtra -- More Chinese via CPAN + +Due to the size concerns, additional Chinese encodings below are +distributed separately on CPAN, under the name Encode::HanExtra. + + Standard DOS/Win Macintosh Comment/Reference + ---------------------------------------------------------------- + big5ext CMEX's Big5e Extension + big5plus CMEX's Big5+ Extension + cccii Chinese Character Code for Information Interchange + euc-tw EUC (Extended Unix Character) + gb18030 GBK with Traditional Characters + ---------------------------------------------------------------- + +=item Encode::JIS2K -- JIS X 0213 encodings via CPAN + +Due to size concerns, additional Japanese encodings below are +distributed separately on CPAN, under the name Encode::JIS2K. + + Standard DOS/Win Macintosh Comment/Reference + ---------------------------------------------------------------- + euc-jisx0213 + shiftjisx0123 + iso-2022-jp-3 + jis0213-1-raw + jis0213-2-raw + ---------------------------------------------------------------- + +=back + +=head2 Miscellaneous encodings + +=over 2 + +=item Encode::EBCDIC + +See L<perlebcdic> for details. + + ---------------------------------------------------------------- + cp37 + cp500 + cp875 + cp1026 + cp1047 + posix-bc + ---------------------------------------------------------------- + +=item Encode::Symbols + +For symbols and dingbats. + + ---------------------------------------------------------------- + symbol + dingbats + MacDingbats + AdobeZdingbat + AdobeSymbol + ---------------------------------------------------------------- + +=item Encode::MIME::Header + +Strictly speaking, MIME header encoding documented in RFC 2047 is more +of encapsulation than encoding. However, their support in modern +world is imperative so they are supported. + + ---------------------------------------------------------------- + MIME-Header [RFC2047] + MIME-B [RFC2047] + MIME-Q [RFC2047] + ---------------------------------------------------------------- + +=item Encode::Guess + +This one is not a name of encoding but a utility that lets you pick up +the most appropriate encoding for a data out of given I<suspects>. See +L<Encode::Guess> for details. + +=back + +=head1 Unsupported encodings + +The following encodings are not supported as yet; some because they +are rarely used, some because of technical difficulties. They may +be supported by external modules via CPAN in the future, however. + +=over 2 + +=item ISO-2022-JP-2 [RFC1554] + +Not very popular yet. Needs Unicode Database or equivalent to +implement encode() (because it includes JIS X 0208/0212, KSC5601, and +GB2312 simultaneously, whose code points in Unicode overlap. So you +need to lookup the database to determine to what character set a given +Unicode character should belong). + +=item ISO-2022-CN [RFC1922] + +Not very popular. Needs CNS 11643-1 and -2 which are not available in +this module. CNS 11643 is supported (via euc-tw) in Encode::HanExtra. +Autrijus Tang may add support for this encoding in his module in future. + +=item Various HP-UX encodings + +The following are unsupported due to the lack of mapping data. + + '8' - arabic8, greek8, hebrew8, kana8, thai8, and turkish8 + '15' - japanese15, korean15, and roi15 + +=item Cyrillic encoding ISO-IR-111 + +Anton Tagunov doubts its usefulness. + +=item ISO-8859-8-1 [Hebrew] + +None of the Encode team knows Hebrew enough (ISO-8859-8, cp1255 and +MacHebrew are supported because and just because there were mappings +available at L<http://www.unicode.org/>). Contributions welcome. + +=item ISIRI 3342, Iran System, ISIRI 2900 [Farsi] + +Ditto. + +=item Thai encoding TCVN + +Ditto. + +=item Vietnamese encodings VPS + +Though Jungshik Shin has reported that Mozilla supports this encoding, +it was too late before 5.8.0 for us to add it. In the future, it +may be available via a separate module. See +L<http://lxr.mozilla.org/seamonkey/source/intl/uconv/ucvlatin/vps.uf> +and +L<http://lxr.mozilla.org/seamonkey/source/intl/uconv/ucvlatin/vps.ut> +if you are interested in helping us. + +=item Various Mac encodings + +The following are unsupported due to the lack of mapping data. + + MacArmenian, MacBengali, MacBurmese, MacEthiopic + MacExtArabic, MacGeorgian, MacKannada, MacKhmer + MacLaotian, MacMalayalam, MacMongolian, MacOriya + MacSinhalese, MacTamil, MacTelugu, MacTibetan + MacVietnamese + +The rest which are already available are based upon the vendor mappings +at L<http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/> . + +=item (Mac) Indic encodings + +The maps for the following are available at L<http://www.unicode.org/> +but remain unsupport because those encodings need algorithmical +approach, currently unsupported by F<enc2xs>: + + MacDevanagari + MacGurmukhi + MacGujarati + +For details, please see C<Unicode mapping issues and notes:> at +L<http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/DEVANAGA.TXT> . + +I believe this issue is prevalent not only for Mac Indics but also in +other Indic encodings, but the above were the only Indic encodings +maps that I could find at L<http://www.unicode.org/> . + +=back + +=head1 Encoding vs. Charset -- terminology + +We are used to using the term (character) I<encoding> and I<character +set> interchangeably. But just as confusing the terms byte and +character is dangerous and the terms should be differentiated when +needed, we need to differentiate I<encoding> and I<character set>. + +To understand that, here is a description of how we make computers +grok our characters. + +=over 2 + +=item * + +First we start with which characters to include. We call this +collection of characters I<character repertoire>. + +=item * + +Then we have to give each character a unique ID so your computer can +tell the difference between 'a' and 'A'. This itemized character +repertoire is now a I<character set>. + +=item * + +If your computer can grow the character set without further +processing, you can go ahead and use it. This is called a I<coded +character set> (CCS) or I<raw character encoding>. ASCII is used this +way for most cases. + +=item * + +But in many cases, especially multi-byte CJK encodings, you have to +tweak a little more. Your network connection may not accept any data +with the Most Significant Bit set, and your computer may not be able to +tell if a given byte is a whole character or just half of it. So you +have to I<encode> the character set to use it. + +A I<character encoding scheme> (CES) determines how to encode a given +character set, or a set of multiple character sets. 7bit ISO-2022 is +an example of a CES. You switch between character sets via I<escape +sequences>. + +=back + +Technically, or mathematically, speaking, a character set encoded in +such a CES that maps character by character may form a CCS. EUC is such +an example. The CES of EUC is as follows: + +=over 2 + +=item * + +Map ASCII unchanged. + +=item * + +Map such a character set that consists of 94 or 96 powered by N +members by adding 0x80 to each byte. + +=item * + +You can also use 0x8e and 0x8f to indicate that the following sequence of +characters belongs to yet another character set. To each following byte +is added the value 0x80. + +=back + +By carefully looking at the encoded byte sequence, you can find that the +byte sequence conforms a unique number. In that sense, EUC is a CCS +generated by a CES above from up to four CCS (complicated?). UTF-8 +falls into this category. See L<perlUnicode/"UTF-8"> to find out how +UTF-8 maps Unicode to a byte sequence. + +You may also have found out by now why 7bit ISO-2022 cannot comprise +a CCS. If you look at a byte sequence \x21\x21, you can't tell if +it is two !'s or IDEOGRAPHIC SPACE. EUC maps the latter to \xA1\xA1 +so you have no trouble differentiating between "!!". and S<" ">. + +=head1 Encoding Classification (by Anton Tagunov and Dan Kogai) + +This section tries to classify the supported encodings by their +applicability for information exchange over the Internet and to +choose the most suitable aliases to name them in the context of +such communication. + +=over 2 + +=item * + +To (en|de)code encodings marked by C<(**)>, you need +C<Encode::HanExtra>, available from CPAN. + +=back + +Encoding names + + US-ASCII UTF-8 ISO-8859-* KOI8-R + Shift_JIS EUC-JP ISO-2022-JP ISO-2022-JP-1 + EUC-KR Big5 GB2312 + +are registered with IANA as preferred MIME names and may +be used over the Internet. + +C<Shift_JIS> has been officialized by JIS X 0208:1997. +L<Microsoft-related naming mess> gives details. + +C<GB2312> is the IANA name for C<EUC-CN>. +See L<Microsoft-related naming mess> for details. + +C<GB_2312-80> I<raw> encoding is available as C<gb2312-raw> +with Encode. See L<Encode::CN> for details. + + EUC-CN + KOI8-U [RFC2319] + +have not been registered with IANA (as of March 2002) but +seem to be supported by major web browsers. +The IANA name for C<EUC-CN> is C<GB2312>. + + KS_C_5601-1987 + +is heavily misused. +See L<Microsoft-related naming mess> for details. + +C<KS_C_5601-1987> I<raw> encoding is available as C<kcs5601-raw> +with Encode. See L<Encode::KR> for details. + + UTF-16 UTF-16BE UTF-16LE + +are IANA-registered C<charset>s. See [RFC 2781] for details. +Jungshik Shin reports that UTF-16 with a BOM is well accepted +by MS IE 5/6 and NS 4/6. Beware however that + +=over 2 + +=item * + +C<UTF-16> support in any software you're going to be +using/interoperating with has probably been less tested +then C<UTF-8> support + +=item * + +C<UTF-8> coded data seamlessly passes traditional +command piping (C<cat>, C<more>, etc.) while C<UTF-16> coded +data is likely to cause confusion (with its zero bytes, +for example) + +=item * + +it is beyond the power of words to describe the way HTML browsers +encode non-C<ASCII> form data. To get a general impression, visit +L<http://www.alanflavell.org.uk/charset/form-i18n.html>. +While encoding of form data has stabilized for C<UTF-8> encoded pages +(at least IE 5/6, NS 6, and Opera 6 behave consistently), be sure to +expect fun (and cross-browser discrepancies) with C<UTF-16> encoded +pages! + +=back + +The rule of thumb is to use C<UTF-8> unless you know what +you're doing and unless you really benefit from using C<UTF-16>. + + ISO-IR-165 [RFC1345] + VISCII + GB 12345 + GB 18030 (**) (see links bellow) + EUC-TW (**) + +are totally valid encodings but not registered at IANA. +The names under which they are listed here are probably the +most widely-known names for these encodings and are recommended +names. + + BIG5PLUS (**) + +is a proprietary name. + +=head2 Microsoft-related naming mess + +Microsoft products misuse the following names: + +=over 2 + +=item KS_C_5601-1987 + +Microsoft extension to C<EUC-KR>. + +Proper names: C<CP949>, C<UHC>, C<x-windows-949> (as used by Mozilla). + +See L<http://lists.w3.org/Archives/Public/ietf-charsets/2001AprJun/0033.html> +for details. + +Encode aliases C<KS_C_5601-1987> to C<cp949> to reflect this common +misusage. I<Raw> C<KS_C_5601-1987> encoding is available as +C<kcs5601-raw>. + +See L<Encode::KR> for details. + +=item GB2312 + +Microsoft extension to C<EUC-CN>. + +Proper names: C<CP936>, C<GBK>. + +C<GB2312> has been registered in the C<EUC-CN> meaning at +IANA. This has partially repaired the situation: Microsoft's +C<GB2312> has become a superset of the official C<GB2312>. + +Encode aliases C<GB2312> to C<euc-cn> in full agreement with +IANA registration. C<cp936> is supported separately. +I<Raw> C<GB_2312-80> encoding is available as C<gb2312-raw>. + +See L<Encode::CN> for details. + +=item Big5 + +Microsoft extension to C<Big5>. + +Proper name: C<CP950>. + +Encode separately supports C<Big5> and C<cp950>. + +=item Shift_JIS + +Microsoft's understanding of C<Shift_JIS>. + +JIS has not endorsed the full Microsoft standard however. +The official C<Shift_JIS> includes only JIS X 0201 and JIS X 0208 +character sets, while Microsoft has always used C<Shift_JIS> +to encode a wider character repertoire. See C<IANA> registration for +C<Windows-31J>. + +As a historical predecessor, Microsoft's variant +probably has more rights for the name, though it may be objected +that Microsoft shouldn't have used JIS as part of the name +in the first place. + +Unambiguous name: C<CP932>. C<IANA> name (also used by Mozilla, and +provided as an alias by Encode): C<Windows-31J>. + +Encode separately supports C<Shift_JIS> and C<cp932>. + +=back + +=head1 Glossary + +=over 2 + +=item character repertoire + +A collection of unique characters. A I<character> set in the strictest +sense. At this stage, characters are not numbered. + +=item coded character set (CCS) + +A character set that is mapped in a way computers can use directly. +Many character encodings, including EUC, fall in this category. + +=item character encoding scheme (CES) + +An algorithm to map a character set to a byte sequence. You don't +have to be able to tell which character set a given byte sequence +belongs. 7-bit ISO-2022 is a CES but it cannot be a CCS. EUC is an +example of being both a CCS and CES. + +=item charset (in MIME context) + +has long been used in the meaning of C<encoding>, CES. + +While the word combination C<character set> has lost this meaning +in MIME context since [RFC 2130], the C<charset> abbreviation has +retained it. This is how [RFC 2277] and [RFC 2278] bless C<charset>: + + This document uses the term "charset" to mean a set of rules for + mapping from a sequence of octets to a sequence of characters, such + as the combination of a coded character set and a character encoding + scheme; this is also what is used as an identifier in MIME "charset=" + parameters, and registered in the IANA charset registry ... (Note + that this is NOT a term used by other standards bodies, such as ISO). + [RFC 2277] + +=item EUC + +Extended Unix Character. See ISO-2022. + +=item ISO-2022 + +A CES that was carefully designed to coexist with ASCII. There are a 7 +bit version and an 8 bit version. + +The 7 bit version switches character set via escape sequence so it +cannot form a CCS. Since this is more difficult to handle in programs +than the 8 bit version, the 7 bit version is not very popular except for +iso-2022-jp, the I<de facto> standard CES for e-mails. + +The 8 bit version can form a CCS. EUC and ISO-8859 are two examples +thereof. Pre-5.6 perl could use them as string literals. + +=item UCS + +Short for I<Universal Character Set>. When you say just UCS, it means +I<Unicode>. + +=item UCS-2 + +ISO/IEC 10646 encoding form: Universal Character Set coded in two +octets. + +=item Unicode + +A character set that aims to include all character repertoires of the +world. Many character sets in various national as well as industrial +standards have become, in a way, just subsets of Unicode. + +=item UTF + +Short for I<Unicode Transformation Format>. Determines how to map a +Unicode character into a byte sequence. + +=item UTF-16 + +A UTF in 16-bit encoding. Can either be in big endian or little +endian. The big endian version is called UTF-16BE (equal to UCS-2 + +surrogate support) and the little endian version is called UTF-16LE. + +=back + +=head1 See Also + +L<Encode>, +L<Encode::Byte>, +L<Encode::CN>, L<Encode::JP>, L<Encode::KR>, L<Encode::TW>, +L<Encode::EBCDIC>, L<Encode::Symbol> +L<Encode::MIME::Header>, L<Encode::Guess> + +=head1 References + +=over 2 + +=item ECMA + +European Computer Manufacturers Association +L<http://www.ecma.ch> + +=over 2 + +=item ECMA-035 (eq C<ISO-2022>) + +L<http://www.ecma.ch/ecma1/STAND/ECMA-035.HTM> + +The specification of ISO-2022 is available from the link above. + +=back + +=item IANA + +Internet Assigned Numbers Authority +L<http://www.iana.org/> + +=over 2 + +=item Assigned Charset Names by IANA + +L<http://www.iana.org/assignments/character-sets> + +Most of the C<canonical names> in Encode derive from this list +so you can directly apply the string you have extracted from MIME +header of mails and web pages. + +=back + +=item ISO + +International Organization for Standardization +L<http://www.iso.ch/> + +=item RFC + +Request For Comments -- need I say more? +L<http://www.rfc-editor.org/>, L<http://www.ietf.org/rfc.html>, +L<http://www.faqs.org/rfcs/> + +=item UC + +Unicode Consortium +L<http://www.unicode.org/> + +=over 2 + +=item Unicode Glossary + +L<http://www.unicode.org/glossary/> + +The glossary of this document is based upon this site. + +=back + +=back + +=head2 Other Notable Sites + +=over 2 + +=item czyborra.com + +L<http://czyborra.com/> + +Contains a lot of useful information, especially gory details of ISO +vs. vendor mappings. + +=item CJK.inf + +L<http://examples.oreilly.com/cjkvinfo/doc/cjk.inf> + +Somewhat obsolete (last update in 1996), but still useful. Also try + +L<ftp://ftp.oreilly.com/pub/examples/nutshell/cjkv/pdf/GB18030_Summary.pdf> + +You will find brief info on C<EUC-CN>, C<GBK> and mostly on C<GB 18030>. + +=item Jungshik Shin's Hangul FAQ + +L<http://jshin.net/faq> + +And especially its subject 8. + +L<http://jshin.net/faq/qa8.html> + +A comprehensive overview of the Korean (C<KS *>) standards. + +=item debian.org: "Introduction to i18n" + +A brief description for most of the mentioned CJK encodings is +contained in +L<http://www.debian.org/doc/manuals/intro-i18n/ch-codes.en.html> + +=back + +=head2 Offline sources + +=over 2 + +=item C<CJKV Information Processing> by Ken Lunde + +CJKV Information Processing +1999 O'Reilly & Associates, ISBN : 1-56592-224-7 + +The modern successor of C<CJK.inf>. + +Features a comprehensive coverage of CJKV character sets and +encodings along with many other issues faced by anyone trying +to better support CJKV languages/scripts in all the areas of +information processing. + +To purchase this book, visit +L<http://oreilly.com/catalog/9780596514471/> +or your favourite bookstore. + +=back + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/Symbol.pm b/Master/tlpkg/tlperl/lib/Encode/Symbol.pm new file mode 100644 index 00000000000..77031aad75c --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/Symbol.pm @@ -0,0 +1,44 @@ +package Encode::Symbol; +use strict; +use warnings; +use Encode; +our $VERSION = do { my @r = ( q$Revision: 2.2 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; + +use XSLoader; +XSLoader::load( __PACKAGE__, $VERSION ); + +1; +__END__ + +=head1 NAME + +Encode::Symbol - Symbol Encodings + +=head1 SYNOPSIS + + use Encode qw/encode decode/; + $symbol = encode("symbol", $utf8); # loads Encode::Symbol implicitly + $utf8 = decode("", $symbol); # ditto + +=head1 ABSTRACT + +This module implements symbol and dingbats encodings. Encodings +supported are as follows. + + Canonical Alias Description + -------------------------------------------------------------------- + symbol + dingbats + AdobeZDingbat + AdobeSymbol + MacDingbats + +=head1 DESCRIPTION + +To find out how to use this module in detail, see L<Encode>. + +=head1 SEE ALSO + +L<Encode> + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/TW.pm b/Master/tlpkg/tlperl/lib/Encode/TW.pm new file mode 100644 index 00000000000..c30499bee1e --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/TW.pm @@ -0,0 +1,75 @@ +package Encode::TW; +BEGIN { + if ( ord("A") == 193 ) { + die "Encode::TW not supported on EBCDIC\n"; + } +} +use strict; +use warnings; +use Encode; +our $VERSION = do { my @r = ( q$Revision: 2.3 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; +use XSLoader; +XSLoader::load( __PACKAGE__, $VERSION ); + +1; +__END__ + +=head1 NAME + +Encode::TW - Taiwan-based Chinese Encodings + +=head1 SYNOPSIS + + use Encode qw/encode decode/; + $big5 = encode("big5", $utf8); # loads Encode::TW implicitly + $utf8 = decode("big5", $big5); # ditto + +=head1 DESCRIPTION + +This module implements tradition Chinese charset encodings as used +in Taiwan and Hong Kong. +Encodings supported are as follows. + + Canonical Alias Description + -------------------------------------------------------------------- + big5-eten /\bbig-?5$/i Big5 encoding (with ETen extensions) + /\bbig5-?et(en)?$/i + /\btca-?big5$/i + big5-hkscs /\bbig5-?hk(scs)?$/i + /\bhk(scs)?-?big5$/i + Big5 + Cantonese characters in Hong Kong + MacChineseTrad Big5 + Apple Vendor Mappings + cp950 Code Page 950 + = Big5 + Microsoft vendor mappings + -------------------------------------------------------------------- + +To find out how to use this module in detail, see L<Encode>. + +=head1 NOTES + +Due to size concerns, C<EUC-TW> (Extended Unix Character), C<CCCII> +(Chinese Character Code for Information Interchange), C<BIG5PLUS> +(CMEX's Big5+) and C<BIG5EXT> (CMEX's Big5e) are distributed separately +on CPAN, under the name L<Encode::HanExtra>. That module also contains +extra China-based encodings. + +=head1 BUGS + +Since the original C<big5> encoding (1984) is not supported anywhere +(glibc and DOS-based systems uses C<big5> to mean C<big5-eten>; Microsoft +uses C<big5> to mean C<cp950>), a conscious decision was made to alias +C<big5> to C<big5-eten>, which is the de facto superset of the original +big5. + +The C<CNS11643> encoding files are not complete. For common C<CNS11643> +manipulation, please use C<EUC-TW> in L<Encode::HanExtra>, which contains +planes 1-7. + +The ASCII region (0x00-0x7f) is preserved for all encodings, even +though this conflicts with mappings by the Unicode Consortium. + +=head1 SEE ALSO + +L<Encode> + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/Unicode.pm b/Master/tlpkg/tlperl/lib/Encode/Unicode.pm new file mode 100644 index 00000000000..f71567c6196 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/Unicode.pm @@ -0,0 +1,270 @@ +package Encode::Unicode; + +use strict; +use warnings; +no warnings 'redefine'; + +our $VERSION = do { my @r = ( q$Revision: 2.7 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; + +use XSLoader; +XSLoader::load( __PACKAGE__, $VERSION ); + +# +# Object Generator 8 transcoders all at once! +# + +require Encode; + +our %BOM_Unknown = map { $_ => 1 } qw(UTF-16 UTF-32); + +for my $name ( + qw(UTF-16 UTF-16BE UTF-16LE + UTF-32 UTF-32BE UTF-32LE + UCS-2BE UCS-2LE) + ) +{ + my ( $size, $endian, $ucs2, $mask ); + $name =~ /^(\w+)-(\d+)(\w*)$/o; + if ( $ucs2 = ( $1 eq 'UCS' ) ) { + $size = 2; + } + else { + $size = $2 / 8; + } + $endian = ( $3 eq 'BE' ) ? 'n' : ( $3 eq 'LE' ) ? 'v' : ''; + $size == 4 and $endian = uc($endian); + + $Encode::Encoding{$name} = bless { + Name => $name, + size => $size, + endian => $endian, + ucs2 => $ucs2, + } => __PACKAGE__; +} + +use base qw(Encode::Encoding); + +sub renew { + my $self = shift; + $BOM_Unknown{ $self->name } or return $self; + my $clone = bless {%$self} => ref($self); + $clone->{renewed}++; # so the caller knows it is renewed. + return $clone; +} + +# There used to be a perl implemntation of (en|de)code but with +# XS version is ripe, perl version is zapped for optimal speed + +*decode = \&decode_xs; +*encode = \&encode_xs; + +1; +__END__ + +=head1 NAME + +Encode::Unicode -- Various Unicode Transformation Formats + +=cut + +=head1 SYNOPSIS + + use Encode qw/encode decode/; + $ucs2 = encode("UCS-2BE", $utf8); + $utf8 = decode("UCS-2BE", $ucs2); + +=head1 ABSTRACT + +This module implements all Character Encoding Schemes of Unicode that +are officially documented by Unicode Consortium (except, of course, +for UTF-8, which is a native format in perl). + +=over 4 + +=item L<http://www.unicode.org/glossary/> says: + +I<Character Encoding Scheme> A character encoding form plus byte +serialization. There are Seven character encoding schemes in Unicode: +UTF-8, UTF-16, UTF-16BE, UTF-16LE, UTF-32 (UCS-4), UTF-32BE (UCS-4BE) and +UTF-32LE (UCS-4LE), and UTF-7. + +Since UTF-7 is a 7-bit (re)encoded version of UTF-16BE, It is not part of +Unicode's Character Encoding Scheme. It is separately implemented in +Encode::Unicode::UTF7. For details see L<Encode::Unicode::UTF7>. + +=item Quick Reference + + Decodes from ord(N) Encodes chr(N) to... + octet/char BOM S.P d800-dfff ord > 0xffff \x{1abcd} == + ---------------+-----------------+------------------------------ + UCS-2BE 2 N N is bogus Not Available + UCS-2LE 2 N N bogus Not Available + UTF-16 2/4 Y Y is S.P S.P BE/LE + UTF-16BE 2/4 N Y S.P S.P 0xd82a,0xdfcd + UTF-16LE 2/4 N Y S.P S.P 0x2ad8,0xcddf + UTF-32 4 Y - is bogus As is BE/LE + UTF-32BE 4 N - bogus As is 0x0001abcd + UTF-32LE 4 N - bogus As is 0xcdab0100 + UTF-8 1-4 - - bogus >= 4 octets \xf0\x9a\af\8d + ---------------+-----------------+------------------------------ + +=back + +=head1 Size, Endianness, and BOM + +You can categorize these CES by 3 criteria: size of each character, +endianness, and Byte Order Mark. + +=head2 by size + +UCS-2 is a fixed-length encoding with each character taking 16 bits. +It B<does not> support I<surrogate pairs>. When a surrogate pair +is encountered during decode(), its place is filled with \x{FFFD} +if I<CHECK> is 0, or the routine croaks if I<CHECK> is 1. When a +character whose ord value is larger than 0xFFFF is encountered, +its place is filled with \x{FFFD} if I<CHECK> is 0, or the routine +croaks if I<CHECK> is 1. + +UTF-16 is almost the same as UCS-2 but it supports I<surrogate pairs>. +When it encounters a high surrogate (0xD800-0xDBFF), it fetches the +following low surrogate (0xDC00-0xDFFF) and C<desurrogate>s them to +form a character. Bogus surrogates result in death. When \x{10000} +or above is encountered during encode(), it C<ensurrogate>s them and +pushes the surrogate pair to the output stream. + +UTF-32 (UCS-4) is a fixed-length encoding with each character taking 32 bits. +Since it is 32-bit, there is no need for I<surrogate pairs>. + +=head2 by endianness + +The first (and now failed) goal of Unicode was to map all character +repertoires into a fixed-length integer so that programmers are happy. +Since each character is either a I<short> or I<long> in C, you have to +pay attention to the endianness of each platform when you pass data +to one another. + +Anything marked as BE is Big Endian (or network byte order) and LE is +Little Endian (aka VAX byte order). For anything not marked either +BE or LE, a character called Byte Order Mark (BOM) indicating the +endianness is prepended to the string. + +CAVEAT: Though BOM in utf8 (\xEF\xBB\xBF) is valid, it is meaningless +and as of this writing Encode suite just leave it as is (\x{FeFF}). + +=over 4 + +=item BOM as integer when fetched in network byte order + + 16 32 bits/char + ------------------------- + BE 0xFeFF 0x0000FeFF + LE 0xFFFe 0xFFFe0000 + ------------------------- + +=back + +This modules handles the BOM as follows. + +=over 4 + +=item * + +When BE or LE is explicitly stated as the name of encoding, BOM is +simply treated as a normal character (ZERO WIDTH NO-BREAK SPACE). + +=item * + +When BE or LE is omitted during decode(), it checks if BOM is at the +beginning of the string; if one is found, the endianness is set to +what the BOM says. If no BOM is found, the routine dies. + +=item * + +When BE or LE is omitted during encode(), it returns a BE-encoded +string with BOM prepended. So when you want to encode a whole text +file, make sure you encode() the whole text at once, not line by line +or each line, not file, will have a BOM prepended. + +=item * + +C<UCS-2> is an exception. Unlike others, this is an alias of UCS-2BE. +UCS-2 is already registered by IANA and others that way. + +=back + +=head1 Surrogate Pairs + +To say the least, surrogate pairs were the biggest mistake of the +Unicode Consortium. But according to the late Douglas Adams in I<The +Hitchhiker's Guide to the Galaxy> Trilogy, C<In the beginning the +Universe was created. This has made a lot of people very angry and +been widely regarded as a bad move>. Their mistake was not of this +magnitude so let's forgive them. + +(I don't dare make any comparison with Unicode Consortium and the +Vogons here ;) Or, comparing Encode to Babel Fish is completely +appropriate -- if you can only stick this into your ear :) + +Surrogate pairs were born when the Unicode Consortium finally +admitted that 16 bits were not big enough to hold all the world's +character repertoires. But they already made UCS-2 16-bit. What +do we do? + +Back then, the range 0xD800-0xDFFF was not allocated. Let's split +that range in half and use the first half to represent the C<upper +half of a character> and the second half to represent the C<lower +half of a character>. That way, you can represent 1024 * 1024 = +1048576 more characters. Now we can store character ranges up to +\x{10ffff} even with 16-bit encodings. This pair of half-character is +now called a I<surrogate pair> and UTF-16 is the name of the encoding +that embraces them. + +Here is a formula to ensurrogate a Unicode character \x{10000} and +above; + + $hi = ($uni - 0x10000) / 0x400 + 0xD800; + $lo = ($uni - 0x10000) % 0x400 + 0xDC00; + +And to desurrogate; + + $uni = 0x10000 + ($hi - 0xD800) * 0x400 + ($lo - 0xDC00); + +Note this move has made \x{D800}-\x{DFFF} into a forbidden zone but +perl does not prohibit the use of characters within this range. To perl, +every one of \x{0000_0000} up to \x{ffff_ffff} (*) is I<a character>. + + (*) or \x{ffff_ffff_ffff_ffff} if your perl is compiled with 64-bit + integer support! + +=head1 Error Checking + +Unlike most encodings which accept various ways to handle errors, +Unicode encodings simply croaks. + + % perl -MEncode -e'$_ = "\xfe\xff\xd8\xd9\xda\xdb\0\n"' \ + -e'Encode::from_to($_, "utf16","shift_jis", 0); print' + UTF-16:Malformed LO surrogate d8d9 at /path/to/Encode.pm line 184. + % perl -MEncode -e'$a = "BOM missing"' \ + -e' Encode::from_to($a, "utf16", "shift_jis", 0); print' + UTF-16:Unrecognised BOM 424f at /path/to/Encode.pm line 184. + +Unlike other encodings where mappings are not one-to-one against +Unicode, UTFs are supposed to map 100% against one another. So Encode +is more strict on UTFs. + +Consider that "division by zero" of Encode :) + +=head1 SEE ALSO + +L<Encode>, L<Encode::Unicode::UTF7>, L<http://www.unicode.org/glossary/>, +L<http://www.unicode.org/unicode/faq/utf_bom.html>, + +RFC 2781 L<http://www.ietf.org/rfc/rfc2781.txt>, + +The whole Unicode standard L<http://www.unicode.org/unicode/uni2book/u2.html> + +Ch. 15, pp. 403 of C<Programming Perl (3rd Edition)> +by Larry Wall, Tom Christiansen, Jon Orwant; +O'Reilly & Associates; ISBN 0-596-00027-8 + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/Unicode/UTF7.pm b/Master/tlpkg/tlperl/lib/Encode/Unicode/UTF7.pm new file mode 100644 index 00000000000..6ee46195854 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/Unicode/UTF7.pm @@ -0,0 +1,128 @@ +# +# $Id: UTF7.pm,v 2.4 2006/06/03 20:28:48 dankogai Exp $ +# +package Encode::Unicode::UTF7; +use strict; +use warnings; +no warnings 'redefine'; +use base qw(Encode::Encoding); +__PACKAGE__->Define('UTF-7'); +our $VERSION = do { my @r = ( q$Revision: 2.4 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r }; +use MIME::Base64; +use Encode; + +# +# Algorithms taken from Unicode::String by Gisle Aas +# + +our $OPTIONAL_DIRECT_CHARS = 1; +my $specials = quotemeta "\'(),-./:?"; +$OPTIONAL_DIRECT_CHARS + and $specials .= quotemeta "!\"#$%&*;<=>@[]^_`{|}"; + +# \s will not work because it matches U+3000 DEOGRAPHIC SPACE +# We use qr/[\n\r\t\ ] instead +my $re_asis = qr/(?:[\n\r\t\ A-Za-z0-9$specials])/; +my $re_encoded = qr/(?:[^\n\r\t\ A-Za-z0-9$specials])/; +my $e_utf16 = find_encoding("UTF-16BE"); + +sub needs_lines { 1 } + +sub encode($$;$) { + my ( $obj, $str, $chk ) = @_; + my $len = length($str); + pos($str) = 0; + my $bytes = ''; + while ( pos($str) < $len ) { + if ( $str =~ /\G($re_asis+)/ogc ) { + $bytes .= $1; + } + elsif ( $str =~ /\G($re_encoded+)/ogsc ) { + if ( $1 eq "+" ) { + $bytes .= "+-"; + } + else { + my $s = $1; + my $base64 = encode_base64( $e_utf16->encode($s), '' ); + $base64 =~ s/=+$//; + $bytes .= "+$base64-"; + } + } + else { + die "This should not happen! (pos=" . pos($str) . ")"; + } + } + $_[1] = '' if $chk; + return $bytes; +} + +sub decode($$;$) { + my ( $obj, $bytes, $chk ) = @_; + my $len = length($bytes); + my $str = ""; + no warnings 'uninitialized'; + while ( pos($bytes) < $len ) { + if ( $bytes =~ /\G([^+]+)/ogc ) { + $str .= $1; + } + elsif ( $bytes =~ /\G\+-/ogc ) { + $str .= "+"; + } + elsif ( $bytes =~ /\G\+([A-Za-z0-9+\/]+)-?/ogsc ) { + my $base64 = $1; + my $pad = length($base64) % 4; + $base64 .= "=" x ( 4 - $pad ) if $pad; + $str .= $e_utf16->decode( decode_base64($base64) ); + } + elsif ( $bytes =~ /\G\+/ogc ) { + $^W and warn "Bad UTF7 data escape"; + $str .= "+"; + } + else { + die "This should not happen " . pos($bytes); + } + } + $_[1] = '' if $chk; + return $str; +} +1; +__END__ + +=head1 NAME + +Encode::Unicode::UTF7 -- UTF-7 encoding + +=head1 SYNOPSIS + + use Encode qw/encode decode/; + $utf7 = encode("UTF-7", $utf8); + $utf8 = decode("UTF-7", $ucs2); + +=head1 ABSTRACT + +This module implements UTF-7 encoding documented in RFC 2152. UTF-7, +as its name suggests, is a 7-bit re-encoded version of UTF-16BE. It +is designed to be MTA-safe and expected to be a standard way to +exchange Unicoded mails via mails. But with the advent of UTF-8 and +8-bit compliant MTAs, UTF-7 is hardly ever used. + +UTF-7 was not supported by Encode until version 1.95 because of that. +But Unicode::String, a module by Gisle Aas which adds Unicode supports +to non-utf8-savvy perl did support UTF-7, the UTF-7 support was added +so Encode can supersede Unicode::String 100%. + +=head1 In Practice + +When you want to encode Unicode for mails and web pages, however, do +not use UTF-7 unless you are sure your recipients and readers can +handle it. Very few MUAs and WWW Browsers support these days (only +Mozilla seems to support one). For general cases, use UTF-8 for +message body and MIME-Header for header instead. + +=head1 SEE ALSO + +L<Encode>, L<Encode::Unicode>, L<Unicode::String> + +RFC 2781 L<http://www.ietf.org/rfc/rfc2152.txt> + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/_PM.e2x b/Master/tlpkg/tlperl/lib/Encode/_PM.e2x new file mode 100644 index 00000000000..eb59cd1b520 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/_PM.e2x @@ -0,0 +1,23 @@ +package Encode::$_Name_; +our $VERSION = "0.01"; + +use Encode; +use XSLoader; +XSLoader::load(__PACKAGE__,$VERSION); + +1; +__END__ + +=head1 NAME + +Encode::$_Name_ - New Encoding + +=head1 SYNOPSIS + +You got to fill this in! + +=head1 SEE ALSO + +L<Encode> + +=cut diff --git a/Master/tlpkg/tlperl/lib/Encode/_T.e2x b/Master/tlpkg/tlperl/lib/Encode/_T.e2x new file mode 100644 index 00000000000..6cf5f293d54 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/_T.e2x @@ -0,0 +1,7 @@ +use strict; +# Adjust the number here! +use Test::More tests => 2; + +use_ok('Encode'); +use_ok('Encode::$_Name_'); +# Add more test here! diff --git a/Master/tlpkg/tlperl/lib/Encode/encode.h b/Master/tlpkg/tlperl/lib/Encode/encode.h new file mode 100644 index 00000000000..0dcf83d32bc --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Encode/encode.h @@ -0,0 +1,113 @@ +#ifndef ENCODE_H +#define ENCODE_H + +#ifndef U8 +/* + A tad devious this: + perl normally has a #define for U8 - if that isn't present then we + typedef it - leaving it #ifndef so we can do data parts without + getting extern references to the code parts +*/ +typedef unsigned char U8; +#endif + +typedef struct encpage_s encpage_t; + +struct encpage_s +{ + /* fields ordered to pack nicely on 32-bit machines */ + const U8 *const seq; /* Packed output sequences we generate + if we match */ + const encpage_t *const next; /* Page to go to if we match */ + const U8 min; /* Min value of octet to match this entry */ + const U8 max; /* Max value of octet to match this entry */ + const U8 dlen; /* destination length - + size of entries in seq */ + const U8 slen; /* source length - + number of source octets needed */ +}; + +/* + At any point in a translation there is a page pointer which points + at an array of the above structures. + + Basic operation : + get octet from source stream. + if (octet >= min && octet < max) { + if slen is 0 then we cannot represent this character. + if we have less than slen octets (including this one) then + we have a partial character. + otherwise + copy dlen octets from seq + dlen*(octet-min) to output + (dlen may be zero if we don't know yet.) + load page pointer with next to continue. + (is slen is one this is end of a character) + get next octet. + } + else { + increment the page pointer to look at next slot in the array + } + + arrays SHALL be constructed so there is an entry which matches + ..0xFF at the end, and either maps it or indicates no + representation. + + if MSB of slen is set then mapping is an approximate "FALLBACK" entry. + +*/ + + +typedef struct encode_s encode_t; +struct encode_s +{ + const encpage_t *const t_utf8; /* Starting table for translation from + the encoding to UTF-8 form */ + const encpage_t *const f_utf8; /* Starting table for translation + from UTF-8 to the encoding */ + const U8 *const rep; /* Replacement character in this + encoding e.g. "?" */ + int replen; /* Number of octets in rep */ + U8 min_el; /* Minimum octets to represent a + character */ + U8 max_el; /* Maximum octets to represent a + character */ + const char *const name[2]; /* name(s) of this encoding */ +}; + +#ifdef U8 +/* See comment at top of file for deviousness */ + +extern int do_encode(const encpage_t *enc, const U8 *src, STRLEN *slen, + U8 *dst, STRLEN dlen, STRLEN *dout, int approx, + const U8 *term, STRLEN tlen); + +extern void Encode_DefineEncoding(encode_t *enc); + +#endif /* U8 */ + +#define ENCODE_NOSPACE 1 +#define ENCODE_PARTIAL 2 +#define ENCODE_NOREP 3 +#define ENCODE_FALLBACK 4 +#define ENCODE_FOUND_TERM 5 + +#define FBCHAR_UTF8 "\xEF\xBF\xBD" + +#define ENCODE_DIE_ON_ERR 0x0001 /* croaks immediately */ +#define ENCODE_WARN_ON_ERR 0x0002 /* warn on error; may proceed */ +#define ENCODE_RETURN_ON_ERR 0x0004 /* immediately returns on NOREP */ +#define ENCODE_LEAVE_SRC 0x0008 /* $src updated unless set */ +#define ENCODE_PERLQQ 0x0100 /* perlqq fallback string */ +#define ENCODE_HTMLCREF 0x0200 /* HTML character ref. fb mode */ +#define ENCODE_XMLCREF 0x0400 /* XML character ref. fb mode */ +#define ENCODE_STOP_AT_PARTIAL 0x0800 /* stop at partial explicitly */ + +#define ENCODE_FB_DEFAULT 0x0000 +#define ENCODE_FB_CROAK 0x0001 +#define ENCODE_FB_QUIET ENCODE_RETURN_ON_ERR +#define ENCODE_FB_WARN (ENCODE_RETURN_ON_ERR|ENCODE_WARN_ON_ERR) +#define ENCODE_FB_PERLQQ (ENCODE_PERLQQ|ENCODE_LEAVE_SRC) +#define ENCODE_FB_HTMLCREF (ENCODE_HTMLCREF|ENCODE_LEAVE_SRC) +#define ENCODE_FB_XMLCREF (ENCODE_XMLCREF|ENCODE_LEAVE_SRC) + +#endif /* ENCODE_H */ diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder.pm b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder.pm new file mode 100644 index 00000000000..7854e88dc94 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder.pm @@ -0,0 +1,331 @@ +package ExtUtils::CBuilder; + +use File::Spec (); +use File::Path (); +use File::Basename (); + +use vars qw($VERSION @ISA); +$VERSION = '0.27'; +$VERSION = eval $VERSION; + +# Okay, this is the brute-force method of finding out what kind of +# platform we're on. I don't know of a systematic way. These values +# came from the latest (bleadperl) perlport.pod. + +my %OSTYPES = qw( + aix Unix + bsdos Unix + dgux Unix + dynixptx Unix + freebsd Unix + linux Unix + hpux Unix + irix Unix + darwin Unix + machten Unix + next Unix + openbsd Unix + netbsd Unix + dec_osf Unix + svr4 Unix + svr5 Unix + sco_sv Unix + unicos Unix + unicosmk Unix + solaris Unix + sunos Unix + cygwin Unix + os2 Unix + gnu Unix + gnukfreebsd Unix + haiku Unix + + dos Windows + MSWin32 Windows + + os390 EBCDIC + os400 EBCDIC + posix-bc EBCDIC + vmesa EBCDIC + + MacOS MacOS + VMS VMS + VOS VOS + riscos RiscOS + amigaos Amiga + mpeix MPEiX + ); + +# We only use this once - don't waste a symbol table entry on it. +# More importantly, don't make it an inheritable method. +my $load = sub { + my $mod = shift; + eval "use $mod"; + die $@ if $@; + @ISA = ($mod); +}; + +{ + my @package = split /::/, __PACKAGE__; + + if (grep {-e File::Spec->catfile($_, @package, 'Platform', $^O) . '.pm'} @INC) { + $load->(__PACKAGE__ . "::Platform::$^O"); + + } elsif (exists $OSTYPES{$^O} and + grep {-e File::Spec->catfile($_, @package, 'Platform', $OSTYPES{$^O}) . '.pm'} @INC) { + $load->(__PACKAGE__ . "::Platform::$OSTYPES{$^O}"); + + } else { + $load->(__PACKAGE__ . "::Base"); + } +} + +sub os_type { $OSTYPES{$^O} } + +1; +__END__ + +=head1 NAME + +ExtUtils::CBuilder - Compile and link C code for Perl modules + +=head1 SYNOPSIS + + use ExtUtils::CBuilder; + + my $b = ExtUtils::CBuilder->new(%options); + $obj_file = $b->compile(source => 'MyModule.c'); + $lib_file = $b->link(objects => $obj_file); + +=head1 DESCRIPTION + +This module can build the C portions of Perl modules by invoking the +appropriate compilers and linkers in a cross-platform manner. It was +motivated by the C<Module::Build> project, but may be useful for other +purposes as well. However, it is I<not> intended as a general +cross-platform interface to all your C building needs. That would +have been a much more ambitious goal! + +=head1 METHODS + +=over 4 + +=item new + +Returns a new C<ExtUtils::CBuilder> object. A C<config> parameter +lets you override C<Config.pm> settings for all operations performed +by the object, as in the following example: + + # Use a different compiler than Config.pm says + my $b = ExtUtils::CBuilder->new( config => + { ld => 'gcc' } ); + +A C<quiet> parameter tells C<CBuilder> to not print its C<system()> +commands before executing them: + + # Be quieter than normal + my $b = ExtUtils::CBuilder->new( quiet => 1 ); + +=item have_compiler + +Returns true if the current system has a working C compiler and +linker, false otherwise. To determine this, we actually compile and +link a sample C library. The sample will be compiled in the system +tempdir or, if that fails for some reason, in the current directory. + +=item have_cplusplus + +Just like have_compiler but for C++ instead of C. + +=item compile + +Compiles a C source file and produces an object file. The name of the +object file is returned. The source file is specified in a C<source> +parameter, which is required; the other parameters listed below are +optional. + +=over 4 + +=item C<object_file> + +Specifies the name of the output file to create. Otherwise the +C<object_file()> method will be consulted, passing it the name of the +C<source> file. + +=item C<include_dirs> + +Specifies any additional directories in which to search for header +files. May be given as a string indicating a single directory, or as +a list reference indicating multiple directories. + +=item C<extra_compiler_flags> + +Specifies any additional arguments to pass to the compiler. Should be +given as a list reference containing the arguments individually, or if +this is not possible, as a string containing all the arguments +together. + +=item C<C++> + +Specifies that the source file is a C++ source file and sets appropriate +compiler flags + +=back + +The operation of this method is also affected by the +C<archlibexp>, C<cccdlflags>, C<ccflags>, C<optimize>, and C<cc> +entries in C<Config.pm>. + +=item link + +Invokes the linker to produce a library file from object files. In +scalar context, the name of the library file is returned. In list +context, the library file and any temporary files created are +returned. A required C<objects> parameter contains the name of the +object files to process, either in a string (for one object file) or +list reference (for one or more files). The following parameters are +optional: + + +=over 4 + +=item lib_file + +Specifies the name of the output library file to create. Otherwise +the C<lib_file()> method will be consulted, passing it the name of +the first entry in C<objects>. + +=item module_name + +Specifies the name of the Perl module that will be created by linking. +On platforms that need to do prelinking (Win32, OS/2, etc.) this is a +required parameter. + +=item extra_linker_flags + +Any additional flags you wish to pass to the linker. + +=back + +On platforms where C<need_prelink()> returns true, C<prelink()> +will be called automatically. + +The operation of this method is also affected by the C<lddlflags>, +C<shrpenv>, and C<ld> entries in C<Config.pm>. + +=item link_executable + +Invokes the linker to produce an executable file from object files. In +scalar context, the name of the executable file is returned. In list +context, the executable file and any temporary files created are +returned. A required C<objects> parameter contains the name of the +object files to process, either in a string (for one object file) or +list reference (for one or more files). The optional parameters are +the same as C<link> with exception for + + +=over 4 + +=item exe_file + +Specifies the name of the output executable file to create. Otherwise +the C<exe_file()> method will be consulted, passing it the name of the +first entry in C<objects>. + +=back + +=item object_file + + my $object_file = $b->object_file($source_file); + +Converts the name of a C source file to the most natural name of an +output object file to create from it. For instance, on Unix the +source file F<foo.c> would result in the object file F<foo.o>. + +=item lib_file + + my $lib_file = $b->lib_file($object_file); + +Converts the name of an object file to the most natural name of a +output library file to create from it. For instance, on Mac OS X the +object file F<foo.o> would result in the library file F<foo.bundle>. + +=item exe_file + + my $exe_file = $b->exe_file($object_file); + +Converts the name of an object file to the most natural name of an +executable file to create from it. For instance, on Mac OS X the +object file F<foo.o> would result in the executable file F<foo>, and +on Windows it would result in F<foo.exe>. + + +=item prelink + +On certain platforms like Win32, OS/2, VMS, and AIX, it is necessary +to perform some actions before invoking the linker. The +C<ExtUtils::Mksymlists> module does this, writing files used by the +linker during the creation of shared libraries for dynamic extensions. +The names of any files written will be returned as a list. + +Several parameters correspond to C<ExtUtils::Mksymlists::Mksymlists()> +options, as follows: + + Mksymlists() prelink() type + -------------|-------------------|------------------- + NAME | dl_name | string (required) + DLBASE | dl_base | string + FILE | dl_file | string + DL_VARS | dl_vars | array reference + DL_FUNCS | dl_funcs | hash reference + FUNCLIST | dl_func_list | array reference + IMPORTS | dl_imports | hash reference + VERSION | dl_version | string + +Please see the documentation for C<ExtUtils::Mksymlists> for the +details of what these parameters do. + +=item need_prelink + +Returns true on platforms where C<prelink()> should be called +during linking, and false otherwise. + +=item extra_link_args_after_prelink + +Returns list of extra arguments to give to the link command; the arguments +are the same as for prelink(), with addition of array reference to the +results of prelink(); this reference is indexed by key C<prelink_res>. + +=back + +=head1 TO DO + +Currently this has only been tested on Unix and doesn't contain any of +the Windows-specific code from the C<Module::Build> project. I'll do +that next. + +=head1 HISTORY + +This module is an outgrowth of the C<Module::Build> project, to which +there have been many contributors. Notably, Randy W. Sims submitted +lots of code to support 3 compilers on Windows and helped with various +other platform-specific issues. Ilya Zakharevich has contributed +fixes for OS/2; John E. Malmberg and Peter Prymmer have done likewise +for VMS. + +=head1 AUTHOR + +Ken Williams, kwilliams@cpan.org + +=head1 COPYRIGHT + +Copyright (c) 2003-2005 Ken Williams. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +perl(1), Module::Build(3) + +=cut diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Base.pm b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Base.pm new file mode 100644 index 00000000000..28036c61bdc --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Base.pm @@ -0,0 +1,307 @@ +package ExtUtils::CBuilder::Base; + +use strict; +use File::Spec; +use File::Basename; +use Cwd (); +use Config; +use Text::ParseWords; +use IO::File; + +use vars qw($VERSION); +$VERSION = '0.27'; + +sub new { + my $class = shift; + my $self = bless {@_}, $class; + + $self->{properties}{perl} = $class->find_perl_interpreter + or warn "Warning: Can't locate your perl binary"; + + while (my ($k,$v) = each %Config) { + $self->{config}{$k} = $v unless exists $self->{config}{$k}; + } + $self->{config}{cc} = $ENV{CC} if exists $ENV{CC}; + return $self; +} + +sub find_perl_interpreter { + my $perl; + File::Spec->file_name_is_absolute($perl = $^X) + or -f ($perl = $Config::Config{perlpath}) + or ($perl = $^X); + return $perl; +} + +sub add_to_cleanup { + my $self = shift; + foreach (@_) { + $self->{files_to_clean}{$_} = 1; + } +} + +sub cleanup { + my $self = shift; + foreach my $file (keys %{$self->{files_to_clean}}) { + unlink $file; + } +} + +sub object_file { + my ($self, $filename) = @_; + + # File name, minus the suffix + (my $file_base = $filename) =~ s/\.[^.]+$//; + return "$file_base$self->{config}{obj_ext}"; +} + +sub arg_include_dirs { + my $self = shift; + return map {"-I$_"} @_; +} + +sub arg_nolink { '-c' } + +sub arg_object_file { + my ($self, $file) = @_; + return ('-o', $file); +} + +sub arg_share_object_file { + my ($self, $file) = @_; + return ($self->split_like_shell($self->{config}{lddlflags}), '-o', $file); +} + +sub arg_exec_file { + my ($self, $file) = @_; + return ('-o', $file); +} + +sub arg_defines { + my ($self, %args) = @_; + return map "-D$_=$args{$_}", keys %args; +} + +sub compile { + my ($self, %args) = @_; + die "Missing 'source' argument to compile()" unless defined $args{source}; + + my $cf = $self->{config}; # For convenience + + $args{object_file} ||= $self->object_file($args{source}); + + my @include_dirs = $self->arg_include_dirs + (@{$args{include_dirs} || []}, + $self->perl_inc()); + + my @defines = $self->arg_defines( %{$args{defines} || {}} ); + + my @extra_compiler_flags = $self->split_like_shell($args{extra_compiler_flags}); + my @cccdlflags = $self->split_like_shell($cf->{cccdlflags}); + my @ccflags = $self->split_like_shell($cf->{ccflags}); + push @ccflags, qw/-x c++/ if $args{'C++'}; + my @optimize = $self->split_like_shell($cf->{optimize}); + my @flags = (@include_dirs, @defines, @cccdlflags, @extra_compiler_flags, + $self->arg_nolink, + @ccflags, @optimize, + $self->arg_object_file($args{object_file}), + ); + + my @cc = $self->split_like_shell($cf->{cc}); + + $self->do_system(@cc, @flags, $args{source}) + or die "error building $args{object_file} from '$args{source}'"; + + return $args{object_file}; +} + +sub have_compiler { + my ($self, $is_cplusplus) = @_; + return $self->{have_compiler} if defined $self->{have_compiler}; + + my $result; + my $attempts = 3; + # tmpdir has issues for some people so fall back to current dir + DIR: for my $dir ( File::Spec->tmpdir, '.' ) { + + # don't clobber existing files (rare, but possible) + my $rand = int(rand(2**31)); + my $tmpfile = File::Spec->catfile($dir, "compilet-$rand.c"); + $tmpfile .= "c" if $is_cplusplus; + if ( -e $tmpfile ) { + redo DIR if $attempts--; + next DIR; + } + + { + my $FH = IO::File->new("> $tmpfile") or die "Can't create $tmpfile: $!"; + if ( $is_cplusplus ) { + print $FH "class Bogus { public: int boot_compilet() { return 1; } };\n"; + } + else { + print $FH "int boot_compilet() { return 1; }\n"; + } + } + + my ($obj_file, @lib_files); + eval { + local $^W = 0; + local $self->{quiet} = 1; + $obj_file = $self->compile('C++' => $is_cplusplus, source => $tmpfile); + @lib_files = $self->link(objects => $obj_file, module_name => 'compilet'); + }; + $result = $@ ? 0 : 1; + + foreach (grep defined, $tmpfile, $obj_file, @lib_files) { + 1 while unlink; + } + last DIR if $result; + } + + return $self->{have_compiler} = $result; +} + +sub have_cplusplus { + push @_, 1; + goto &have_compiler; +} + +sub lib_file { + my ($self, $dl_file) = @_; + $dl_file =~ s/\.[^.]+$//; + $dl_file =~ tr/"//d; + return "$dl_file.$self->{config}{dlext}"; +} + + +sub exe_file { + my ($self, $dl_file) = @_; + $dl_file =~ s/\.[^.]+$//; + $dl_file =~ tr/"//d; + return "$dl_file$self->{config}{_exe}"; +} + +sub need_prelink { 0 } + +sub extra_link_args_after_prelink { return } + +sub prelink { + my ($self, %args) = @_; + + ($args{dl_file} = $args{dl_name}) =~ s/.*::// unless $args{dl_file}; + + require ExtUtils::Mksymlists; + ExtUtils::Mksymlists::Mksymlists( # dl. abbrev for dynamic library + DL_VARS => $args{dl_vars} || [], + DL_FUNCS => $args{dl_funcs} || {}, + FUNCLIST => $args{dl_func_list} || [], + IMPORTS => $args{dl_imports} || {}, + NAME => $args{dl_name}, # Name of the Perl module + DLBASE => $args{dl_base}, # Basename of DLL file + FILE => $args{dl_file}, # Dir + Basename of symlist file + VERSION => (defined $args{dl_version} ? $args{dl_version} : '0.0'), + ); + + # Mksymlists will create one of these files + return grep -e, map "$args{dl_file}.$_", qw(ext def opt); +} + +sub link { + my ($self, %args) = @_; + return $self->_do_link('lib_file', lddl => 1, %args); +} + +sub link_executable { + my ($self, %args) = @_; + return $self->_do_link('exe_file', lddl => 0, %args); +} + +sub _do_link { + my ($self, $type, %args) = @_; + + my $cf = $self->{config}; # For convenience + + my $objects = delete $args{objects}; + $objects = [$objects] unless ref $objects; + my $out = $args{$type} || $self->$type($objects->[0]); + + my @temp_files; + @temp_files = + $self->prelink(%args, + dl_name => $args{module_name}) if $args{lddl} && $self->need_prelink; + + my @linker_flags = ($self->split_like_shell($args{extra_linker_flags}), + $self->extra_link_args_after_prelink(%args, dl_name => $args{module_name}, + prelink_res => \@temp_files)); + + my @output = $args{lddl} ? $self->arg_share_object_file($out) : $self->arg_exec_file($out); + my @shrp = $self->split_like_shell($cf->{shrpenv}); + my @ld = $self->split_like_shell($cf->{ld}); + + $self->do_system(@shrp, @ld, @output, @$objects, @linker_flags) + or die "error building $out from @$objects"; + + return wantarray ? ($out, @temp_files) : $out; +} + + +sub do_system { + my ($self, @cmd) = @_; + print "@cmd\n" if !$self->{quiet}; + return !system(@cmd); +} + +sub split_like_shell { + my ($self, $string) = @_; + + return () unless defined($string); + return @$string if UNIVERSAL::isa($string, 'ARRAY'); + $string =~ s/^\s+|\s+$//g; + return () unless length($string); + + return Text::ParseWords::shellwords($string); +} + +# if building perl, perl's main source directory +sub perl_src { + # N.B. makemaker actually searches regardless of PERL_CORE, but + # only squawks at not finding it if PERL_CORE is set + + return unless $ENV{PERL_CORE}; + + my $Updir = File::Spec->updir; + my $dir = File::Spec->curdir; + + # Try up to 5 levels upwards + for (0..10) { + if ( + -f File::Spec->catfile($dir,"config_h.SH") + && + -f File::Spec->catfile($dir,"perl.h") + && + -f File::Spec->catfile($dir,"lib","Exporter.pm") + ) { + return Cwd::realpath( $dir ); + } + + $dir = File::Spec->catdir($dir, $Updir); + } + + warn "PERL_CORE is set but I can't find your perl source!\n"; + return ''; # return empty string if $ENV{PERL_CORE} but can't find dir ??? +} + +# directory of perl's include files +sub perl_inc { + my $self = shift; + + $self->perl_src() || File::Spec->catdir($self->{config}{archlibexp},"CORE"); +} + +sub DESTROY { + my $self = shift; + local($., $@, $!, $^E, $?); + $self->cleanup(); +} + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/Unix.pm b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/Unix.pm new file mode 100644 index 00000000000..78ff244b5ba --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/Unix.pm @@ -0,0 +1,40 @@ +package ExtUtils::CBuilder::Platform::Unix; + +use strict; +use ExtUtils::CBuilder::Base; + +use vars qw($VERSION @ISA); +$VERSION = '0.27'; +@ISA = qw(ExtUtils::CBuilder::Base); + +sub link_executable { + my $self = shift; + + # On some platforms (which ones??) $Config{cc} seems to be a better + # bet for linking executables than $Config{ld}. Cygwin is a notable + # exception. + local $self->{config}{ld} = + $self->{config}{cc} . " " . $self->{config}{ldflags}; + return $self->SUPER::link_executable(@_); +} + +sub link { + my $self = shift; + my $cf = $self->{config}; + + # Some platforms (notably Mac OS X 10.3, but some others too) expect + # the syntax "FOO=BAR /bin/command arg arg" to work in %Config + # (notably $Config{ld}). It usually works in system(SCALAR), but we + # use system(LIST). We fix it up here with 'env'. + + local $cf->{ld} = $cf->{ld}; + if (ref $cf->{ld}) { + unshift @{$cf->{ld}}, 'env' if $cf->{ld}[0] =~ /^\s*\w+=/; + } else { + $cf->{ld} =~ s/^(\s*\w+=)/env $1/; + } + + return $self->SUPER::link(@_); +} + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/VMS.pm b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/VMS.pm new file mode 100644 index 00000000000..35a2eba550b --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/VMS.pm @@ -0,0 +1,294 @@ +package ExtUtils::CBuilder::Platform::VMS; + +use strict; +use ExtUtils::CBuilder::Base; + +use vars qw($VERSION @ISA); +$VERSION = '0.27'; +@ISA = qw(ExtUtils::CBuilder::Base); + +use File::Spec::Functions qw(catfile catdir); + +# We do prelink, but don't want the parent to redo it. + +sub need_prelink { 0 } + +sub arg_defines { + my ($self, %args) = @_; + + s/"/""/g foreach values %args; + + my @config_defines; + + # VMS can only have one define qualifier; add the one from config, if any. + if ($self->{config}{ccflags} =~ s{/ def[^=]+ =+ \(? ([^\/\)]*) } {}ix) { + push @config_defines, $1; + } + + return '' unless keys(%args) || @config_defines; + + return ('/define=(' + . join(',', + @config_defines, + map "\"$_" . ( length($args{$_}) ? "=$args{$_}" : '') . "\"", + keys %args) + . ')'); +} + +sub arg_include_dirs { + my ($self, @dirs) = @_; + + # VMS can only have one include list, add the one from config. + if ($self->{config}{ccflags} =~ s{/inc[^=]+(?:=)+(?:\()?([^\/\)]*)} {}i) { + unshift @dirs, $1; + } + return unless @dirs; + + return ('/include=(' . join(',', @dirs) . ')'); +} + +sub _do_link { + my ($self, $type, %args) = @_; + + my $objects = delete $args{objects}; + $objects = [$objects] unless ref $objects; + + if ($args{lddl}) { + + # prelink will call Mksymlists, which creates the extension-specific + # linker options file and populates it with the boot symbol. + + my @temp_files = $self->prelink(%args, dl_name => $args{module_name}); + + # We now add the rest of what we need to the linker options file. We + # should replicate the functionality of C<ExtUtils::MM_VMS::dlsyms>, + # but there is as yet no infrastructure for handling object libraries, + # so for now we depend on object files being listed individually on the + # command line, which should work for simple cases. We do bring in our + # own version of C<ExtUtils::Liblist::Kid::ext> so that any additional + # libraries (including PERLSHR) can be added to the options file. + + my @optlibs = $self->_liblist_ext( $args{'libs'} ); + + my $optfile = 'sys$disk:[]' . $temp_files[0]; + open my $opt_fh, '>>', $optfile + or die "_do_link: Unable to open $optfile: $!"; + for my $lib (@optlibs) {print $opt_fh "$lib\n" if length $lib } + close $opt_fh; + + $objects->[-1] .= ','; + push @$objects, $optfile . '/OPTIONS,'; + + # This one not needed for DEC C, but leave for completeness. + push @$objects, $self->perl_inc() . 'perlshr_attr.opt/OPTIONS'; + } + + return $self->SUPER::_do_link($type, %args, objects => $objects); +} + +sub arg_nolink { return; } + +sub arg_object_file { + my ($self, $file) = @_; + return "/obj=$file"; +} + +sub arg_exec_file { + my ($self, $file) = @_; + return ("/exe=$file"); +} + +sub arg_share_object_file { + my ($self, $file) = @_; + return ("$self->{config}{lddlflags}=$file"); +} + + +sub lib_file { + my ($self, $dl_file) = @_; + $dl_file =~ s/\.[^.]+$//; + $dl_file =~ tr/"//d; + $dl_file = $dl_file .= '.' . $self->{config}{dlext}; + + # Need to create with the same name as DynaLoader will load with. + if (defined &DynaLoader::mod2fname) { + my ($dev,$dir,$file) = File::Spec->splitpath($dl_file); + $file = DynaLoader::mod2fname([$file]); + $dl_file = File::Spec->catpath($dev,$dir,$file); + } + return $dl_file; +} + +# The following is reproduced almost verbatim from ExtUtils::Liblist::Kid::_vms_ext. +# We can't just call that because it's tied up with the MakeMaker object hierarchy. + +sub _liblist_ext { + my($self, $potential_libs,$verbose,$give_libs) = @_; + $verbose ||= 0; + + my(@crtls,$crtlstr); + @crtls = ( ($self->{'config'}{'ldflags'} =~ m-/Debug-i ? $self->{'config'}{'dbgprefix'} : '') + . 'PerlShr/Share' ); + push(@crtls, grep { not /\(/ } split /\s+/, $self->{'config'}{'perllibs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $self->{'config'}{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and + # a library spec could be resolved via a logical name, we go to some trouble + # to ensure that the copy in the local tree is used, rather than one to + # which a system-wide logical may point. + if ($self->perl_src) { + my($lib,$locspec,$type); + foreach $lib (@crtls) { + if (($locspec,$type) = $lib =~ m{^([\w\$-]+)(/\w+)?} and $locspec =~ /perl/i) { + if (lc $type eq '/share') { $locspec .= $self->{'config'}{'exe_ext'}; } + elsif (lc $type eq '/library') { $locspec .= $self->{'config'}{'lib_ext'}; } + else { $locspec .= $self->{'config'}{'obj_ext'}; } + $locspec = catfile($self->perl_src, $locspec); + $lib = "$locspec$type" if -e $locspec; + } + } + } + $crtlstr = @crtls ? join(' ',@crtls) : ''; + + unless ($potential_libs) { + warn "Result:\n\tEXTRALIBS: \n\tLDLOADLIBS: $crtlstr\n" if $verbose; + return ('', '', $crtlstr, '', ($give_libs ? [] : ())); + } + + my(@dirs,@libs,$dir,$lib,%found,@fndlibs,$ldlib); + my $cwd = cwd(); + my($so,$lib_ext,$obj_ext) = @{$self->{'config'}}{'so','lib_ext','obj_ext'}; + # List of common Unix library names and their VMS equivalents + # (VMS equivalent of '' indicates that the library is automatically + # searched by the linker, and should be skipped here.) + my(@flibs, %libs_seen); + my %libmap = ( 'm' => '', 'f77' => '', 'F77' => '', 'V77' => '', 'c' => '', + 'malloc' => '', 'crypt' => '', 'resolv' => '', 'c_s' => '', + 'socket' => '', 'X11' => 'DECW$XLIBSHR', + 'Xt' => 'DECW$XTSHR', 'Xm' => 'DECW$XMLIBSHR', + 'Xmu' => 'DECW$XMULIBSHR'); + if ($self->{'config'}{'vms_cc_type'} ne 'decc') { $libmap{'curses'} = 'VAXCCURSE'; } + + warn "Potential libraries are '$potential_libs'\n" if $verbose; + + # First, sort out directories and library names in the input + foreach $lib (split ' ',$potential_libs) { + push(@dirs,$1), next if $lib =~ /^-L(.*)/; + push(@dirs,$lib), next if $lib =~ /[:>\]]$/; + push(@dirs,$lib), next if -d $lib; + push(@libs,$1), next if $lib =~ /^-l(.*)/; + push(@libs,$lib); + } + push(@dirs,split(' ',$self->{'config'}{'libpth'})); + + # Now make sure we've got VMS-syntax absolute directory specs + # (We don't, however, check whether someone's hidden a relative + # path in a logical name.) + foreach $dir (@dirs) { + unless (-d $dir) { + warn "Skipping nonexistent Directory $dir\n" if $verbose > 1; + $dir = ''; + next; + } + warn "Resolving directory $dir\n" if $verbose; + if (!File::Spec->file_name_is_absolute($dir)) { + $dir = catdir($cwd,$dir); + } + } + @dirs = grep { length($_) } @dirs; + unshift(@dirs,''); # Check each $lib without additions first + + LIB: foreach $lib (@libs) { + if (exists $libmap{$lib}) { + next unless length $libmap{$lib}; + $lib = $libmap{$lib}; + } + + my(@variants,$variant,$cand); + my($ctype) = ''; + + # If we don't have a file type, consider it a possibly abbreviated name and + # check for common variants. We try these first to grab libraries before + # a like-named executable image (e.g. -lperl resolves to perlshr.exe + # before perl.exe). + if ($lib !~ /\.[^:>\]]*$/) { + push(@variants,"${lib}shr","${lib}rtl","${lib}lib"); + push(@variants,"lib$lib") if $lib !~ /[:>\]]/; + } + push(@variants,$lib); + warn "Looking for $lib\n" if $verbose; + foreach $variant (@variants) { + my($fullname, $name); + + foreach $dir (@dirs) { + my($type); + + $name = "$dir$variant"; + warn "\tChecking $name\n" if $verbose > 2; + $fullname = VMS::Filespec::rmsexpand($name); + if (defined $fullname and -f $fullname) { + # It's got its own suffix, so we'll have to figure out the type + if ($fullname =~ /(?:$so|exe)$/i) { $type = 'SHR'; } + elsif ($fullname =~ /(?:$lib_ext|olb)$/i) { $type = 'OLB'; } + elsif ($fullname =~ /(?:$obj_ext|obj)$/i) { + warn "Note (probably harmless): " + ."Plain object file $fullname found in library list\n"; + $type = 'OBJ'; + } + else { + warn "Note (probably harmless): " + ."Unknown library type for $fullname; assuming shared\n"; + $type = 'SHR'; + } + } + elsif (-f ($fullname = VMS::Filespec::rmsexpand($name,$so)) or + -f ($fullname = VMS::Filespec::rmsexpand($name,'.exe'))) { + $type = 'SHR'; + $name = $fullname unless $fullname =~ /exe;?\d*$/i; + } + elsif (not length($ctype) and # If we've got a lib already, + # don't bother + ( -f ($fullname = VMS::Filespec::rmsexpand($name,$lib_ext)) or + -f ($fullname = VMS::Filespec::rmsexpand($name,'.olb')))) { + $type = 'OLB'; + $name = $fullname unless $fullname =~ /olb;?\d*$/i; + } + elsif (not length($ctype) and # If we've got a lib already, + # don't bother + ( -f ($fullname = VMS::Filespec::rmsexpand($name,$obj_ext)) or + -f ($fullname = VMS::Filespec::rmsexpand($name,'.obj')))) { + warn "Note (probably harmless): " + ."Plain object file $fullname found in library list\n"; + $type = 'OBJ'; + $name = $fullname unless $fullname =~ /obj;?\d*$/i; + } + if (defined $type) { + $ctype = $type; $cand = $name; + last if $ctype eq 'SHR'; + } + } + if ($ctype) { + # This has to precede any other CRTLs, so just make it first + if ($cand eq 'VAXCCURSE') { unshift @{$found{$ctype}}, $cand; } + else { push @{$found{$ctype}}, $cand; } + warn "\tFound as $cand (really $fullname), type $ctype\n" + if $verbose > 1; + push @flibs, $name unless $libs_seen{$fullname}++; + next LIB; + } + } + warn "Note (probably harmless): " + ."No library found for $lib\n"; + } + + push @fndlibs, @{$found{OBJ}} if exists $found{OBJ}; + push @fndlibs, map { "$_/Library" } @{$found{OLB}} if exists $found{OLB}; + push @fndlibs, map { "$_/Share" } @{$found{SHR}} if exists $found{SHR}; + $lib = join(' ',@fndlibs); + + $ldlib = $crtlstr ? "$lib $crtlstr" : $lib; + warn "Result:\n\tEXTRALIBS: $lib\n\tLDLOADLIBS: $ldlib\n" if $verbose; + wantarray ? ($lib, '', $ldlib, '', ($give_libs ? \@flibs : ())) : $lib; +} + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/Windows.pm b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/Windows.pm new file mode 100644 index 00000000000..f0b98dbaa30 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/Windows.pm @@ -0,0 +1,288 @@ +package ExtUtils::CBuilder::Platform::Windows; + +use strict; +use warnings; + +use File::Basename; +use File::Spec; + +use ExtUtils::CBuilder::Base; +use IO::File; + +use vars qw($VERSION @ISA); +$VERSION = '0.27'; +@ISA = qw(ExtUtils::CBuilder::Base); + +=begin comment + +The compiler-specific packages implement functions for generating properly +formatted commandlines for the compiler being used. Each package +defines two primary functions 'format_linker_cmd()' & +'format_compiler_cmd()' that accepts a list of named arguments (a +hash) and returns a list of formatted options suitable for invoking the +compiler. By default, if the compiler supports scripting of its +operation then a script file is built containing the options while +those options are removed from the commandline, and a reference to the +script is pushed onto the commandline in their place. Scripting the +compiler in this way helps to avoid the problems associated with long +commandlines under some shells. + +=end comment + +=cut + +sub new { + my $class = shift; + my $self = $class->SUPER::new(@_); + my $cf = $self->{config}; + + # Inherit from an appropriate compiler driver class + my $driver = "ExtUtils::CBuilder::Platform::Windows::" . $self->_compiler_type; + eval "require $driver" or die "Could not load compiler driver: $@"; + unshift @ISA, $driver; + + return $self; +} + +sub _compiler_type { + my $self = shift; + my $cc = $self->{config}{cc}; + + return ( $cc =~ /cl(\.exe)?$/ ? 'MSVC' + : $cc =~ /bcc32(\.exe)?$/ ? 'BCC' + : 'GCC'); +} + +sub split_like_shell { + # Since Windows will pass the whole command string (not an argument + # array) to the target program and make the program parse it itself, + # we don't actually need to do any processing here. + (my $self, local $_) = @_; + + return @$_ if defined() && UNIVERSAL::isa($_, 'ARRAY'); + return unless defined() && length(); + return ($_); +} + +sub do_system { + # See above + my $self = shift; + my $cmd = join(" ", + grep length, + map {$a=$_;$a=~s/\t/ /g;$a=~s/^\s+|\s+$//;$a} + grep defined, @_); + return $self->SUPER::do_system($cmd); +} + +sub arg_defines { + my ($self, %args) = @_; + s/"/\\"/g foreach values %args; + return map qq{"-D$_=$args{$_}"}, keys %args; +} + +sub compile { + my ($self, %args) = @_; + my $cf = $self->{config}; + + die "Missing 'source' argument to compile()" unless defined $args{source}; + + my ($basename, $srcdir) = + ( File::Basename::fileparse($args{source}, '\.[^.]+$') )[0,1]; + + $srcdir ||= File::Spec->curdir(); + + my @defines = $self->arg_defines( %{ $args{defines} || {} } ); + + my %spec = ( + srcdir => $srcdir, + builddir => $srcdir, + basename => $basename, + source => $args{source}, + output => File::Spec->catfile($srcdir, $basename) . $cf->{obj_ext}, + cc => $cf->{cc}, + cflags => [ + $self->split_like_shell($cf->{ccflags}), + $self->split_like_shell($cf->{cccdlflags}), + $self->split_like_shell($args{extra_compiler_flags}), + ], + optimize => [ $self->split_like_shell($cf->{optimize}) ], + defines => \@defines, + includes => [ @{$args{include_dirs} || []} ], + perlinc => [ + $self->perl_inc(), + $self->split_like_shell($cf->{incpath}), + ], + use_scripts => 1, # XXX provide user option to change this??? + ); + + $self->normalize_filespecs( + \$spec{source}, + \$spec{output}, + $spec{includes}, + $spec{perlinc}, + ); + + my @cmds = $self->format_compiler_cmd(%spec); + while ( my $cmd = shift @cmds ) { + $self->do_system( @$cmd ) + or die "error building $cf->{dlext} file from '$args{source}'"; + } + + (my $out = $spec{output}) =~ tr/'"//d; + return $out; +} + +sub need_prelink { 1 } + +sub link { + my ($self, %args) = @_; + my $cf = $self->{config}; + + my @objects = ( ref $args{objects} eq 'ARRAY' ? @{$args{objects}} : $args{objects} ); + my $to = join '', (File::Spec->splitpath($objects[0]))[0,1]; + $to ||= File::Spec->curdir(); + + (my $file_base = $args{module_name}) =~ s/.*:://; + my $output = $args{lib_file} || + File::Spec->catfile($to, "$file_base.$cf->{dlext}"); + + # if running in perl source tree, look for libs there, not installed + my $lddlflags = $cf->{lddlflags}; + my $perl_src = $self->perl_src(); + $lddlflags =~ s/\Q$cf->{archlibexp}\E[\\\/]CORE/$perl_src/ if $perl_src; + + my %spec = ( + srcdir => $to, + builddir => $to, + startup => [ ], + objects => \@objects, + libs => [ ], + output => $output, + ld => $cf->{ld}, + libperl => $cf->{libperl}, + perllibs => [ $self->split_like_shell($cf->{perllibs}) ], + libpath => [ $self->split_like_shell($cf->{libpth}) ], + lddlflags => [ $self->split_like_shell($lddlflags) ], + other_ldflags => [ $self->split_like_shell($args{extra_linker_flags} || '') ], + use_scripts => 1, # XXX provide user option to change this??? + ); + + unless ( $spec{basename} ) { + ($spec{basename} = $args{module_name}) =~ s/.*:://; + } + + $spec{srcdir} = File::Spec->canonpath( $spec{srcdir} ); + $spec{builddir} = File::Spec->canonpath( $spec{builddir} ); + + $spec{output} ||= File::Spec->catfile( $spec{builddir}, + $spec{basename} . '.'.$cf->{dlext} ); + $spec{manifest} ||= File::Spec->catfile( $spec{builddir}, + $spec{basename} . '.'.$cf->{dlext}.'.manifest'); + $spec{implib} ||= File::Spec->catfile( $spec{builddir}, + $spec{basename} . $cf->{lib_ext} ); + $spec{explib} ||= File::Spec->catfile( $spec{builddir}, + $spec{basename} . '.exp' ); + if ($cf->{cc} eq 'cl') { + $spec{dbg_file} ||= File::Spec->catfile( $spec{builddir}, + $spec{basename} . '.pdb' ); + } + elsif ($cf->{cc} eq 'bcc32') { + $spec{dbg_file} ||= File::Spec->catfile( $spec{builddir}, + $spec{basename} . '.tds' ); + } + $spec{def_file} ||= File::Spec->catfile( $spec{srcdir} , + $spec{basename} . '.def' ); + $spec{base_file} ||= File::Spec->catfile( $spec{srcdir} , + $spec{basename} . '.base' ); + + $self->add_to_cleanup( + grep defined, + @{[ @spec{qw(manifest implib explib dbg_file def_file base_file map_file)} ]} + ); + + foreach my $opt ( qw(output manifest implib explib dbg_file def_file map_file base_file) ) { + $self->normalize_filespecs( \$spec{$opt} ); + } + + foreach my $opt ( qw(libpath startup objects) ) { + $self->normalize_filespecs( $spec{$opt} ); + } + + (my $def_base = $spec{def_file}) =~ tr/'"//d; + $def_base =~ s/\.def$//; + $self->prelink( dl_name => $args{module_name}, + dl_file => $def_base, + dl_base => $spec{basename} ); + + my @cmds = $self->format_linker_cmd(%spec); + while ( my $cmd = shift @cmds ) { + $self->do_system( @$cmd ); + } + + $spec{output} =~ tr/'"//d; + return wantarray + ? grep defined, @spec{qw[output manifest implib explib dbg_file def_file map_file base_file]} + : $spec{output}; +} + +# canonize & quote paths +sub normalize_filespecs { + my ($self, @specs) = @_; + foreach my $spec ( grep defined, @specs ) { + if ( ref $spec eq 'ARRAY') { + $self->normalize_filespecs( map {\$_} grep defined, @$spec ) + } elsif ( ref $spec eq 'SCALAR' ) { + $$spec =~ tr/"//d if $$spec; + next unless $$spec; + $$spec = '"' . File::Spec->canonpath($$spec) . '"'; + } elsif ( ref $spec eq '' ) { + $spec = '"' . File::Spec->canonpath($spec) . '"'; + } else { + die "Don't know how to normalize " . (ref $spec || $spec) . "\n"; + } + } +} + +# directory of perl's include files +sub perl_inc { + my $self = shift; + + my $perl_src = $self->perl_src(); + + if ($perl_src) { + File::Spec->catdir($perl_src, "lib", "CORE"); + } else { + File::Spec->catdir($self->{config}{archlibexp},"CORE"); + } +} + +1; + +__END__ + +=head1 NAME + +ExtUtils::CBuilder::Platform::Windows - Builder class for Windows platforms + +=head1 DESCRIPTION + +This module implements the Windows-specific parts of ExtUtils::CBuilder. +Most of the Windows-specific stuff has to do with compiling and +linking C code. Currently we support the 3 compilers perl itself +supports: MSVC, BCC, and GCC. + +This module inherits from C<ExtUtils::CBuilder::Base>, so any functionality +not implemented here will be implemented there. The interfaces are +defined by the L<ExtUtils::CBuilder> documentation. + +=head1 AUTHOR + +Ken Williams <ken@mathforum.org> + +Most of the code here was written by Randy W. Sims <RandyS@ThePierianSpring.org>. + +=head1 SEE ALSO + +perl(1), ExtUtils::CBuilder(3), ExtUtils::MakeMaker(3) + +=cut diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/Windows/BCC.pm b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/Windows/BCC.pm new file mode 100644 index 00000000000..ee65c91a159 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/Windows/BCC.pm @@ -0,0 +1,130 @@ +package ExtUtils::CBuilder::Platform::Windows::BCC; + +use vars qw($VERSION); +$VERSION = '0.27'; + +sub format_compiler_cmd { + my ($self, %spec) = @_; + + foreach my $path ( @{ $spec{includes} || [] }, + @{ $spec{perlinc} || [] } ) { + $path = '-I' . $path; + } + + %spec = $self->write_compiler_script(%spec) + if $spec{use_scripts}; + + return [ grep {defined && length} ( + $spec{cc}, '-c' , + @{$spec{includes}} , + @{$spec{cflags}} , + @{$spec{optimize}} , + @{$spec{defines}} , + @{$spec{perlinc}} , + "-o$spec{output}" , + $spec{source} , + ) ]; +} + +sub write_compiler_script { + my ($self, %spec) = @_; + + my $script = File::Spec->catfile( $spec{srcdir}, + $spec{basename} . '.ccs' ); + + $self->add_to_cleanup($script); + + print "Generating script '$script'\n" if !$self->{quiet}; + + my $SCRIPT = IO::File->new( ">$script" ) + or die( "Could not create script '$script': $!" ); + + # XXX Borland "response files" seem to be unable to accept macro + # definitions containing quoted strings. Escaping strings with + # backslash doesn't work, and any level of quotes are stripped. The + # result is is a floating point number in the source file where a + # string is expected. So we leave the macros on the command line. + print $SCRIPT join( "\n", + map { ref $_ ? @{$_} : $_ } + grep defined, + delete( + @spec{ qw(includes cflags optimize perlinc) } ) + ); + + push @{$spec{includes}}, '@"' . $script . '"'; + + return %spec; +} + +sub format_linker_cmd { + my ($self, %spec) = @_; + + foreach my $path ( @{$spec{libpath}} ) { + $path = "-L$path"; + } + + push( @{$spec{startup}}, 'c0d32.obj' ) + unless ( $spec{starup} && @{$spec{startup}} ); + + %spec = $self->write_linker_script(%spec) + if $spec{use_scripts}; + + return [ grep {defined && length} ( + $spec{ld} , + @{$spec{lddlflags}} , + @{$spec{libpath}} , + @{$spec{other_ldflags}} , + @{$spec{startup}} , + @{$spec{objects}} , ',', + $spec{output} , ',', + $spec{map_file} , ',', + $spec{libperl} , + @{$spec{perllibs}} , ',', + $spec{def_file} + ) ]; +} + +sub write_linker_script { + my ($self, %spec) = @_; + + # To work around Borlands "unique" commandline syntax, + # two scripts are used: + + my $ld_script = File::Spec->catfile( $spec{srcdir}, + $spec{basename} . '.lds' ); + my $ld_libs = File::Spec->catfile( $spec{srcdir}, + $spec{basename} . '.lbs' ); + + $self->add_to_cleanup($ld_script, $ld_libs); + + print "Generating scripts '$ld_script' and '$ld_libs'.\n" if !$self->{quiet}; + + # Script 1: contains options & names of object files. + my $LD_SCRIPT = IO::File->new( ">$ld_script" ) + or die( "Could not create linker script '$ld_script': $!" ); + + print $LD_SCRIPT join( " +\n", + map { @{$_} } + grep defined, + delete( + @spec{ qw(lddlflags libpath other_ldflags startup objects) } ) + ); + + # Script 2: contains name of libs to link against. + my $LD_LIBS = IO::File->new( ">$ld_libs" ) + or die( "Could not create linker script '$ld_libs': $!" ); + + print $LD_LIBS join( " +\n", + (delete $spec{libperl} || ''), + @{delete $spec{perllibs} || []}, + ); + + push @{$spec{lddlflags}}, '@"' . $ld_script . '"'; + push @{$spec{perllibs}}, '@"' . $ld_libs . '"'; + + return %spec; +} + +1; + + diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/Windows/GCC.pm b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/Windows/GCC.pm new file mode 100644 index 00000000000..132bf842bdb --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/Windows/GCC.pm @@ -0,0 +1,151 @@ +package ExtUtils::CBuilder::Platform::Windows::GCC; + +use vars qw($VERSION); +$VERSION = '0.27'; + +sub format_compiler_cmd { + my ($self, %spec) = @_; + + foreach my $path ( @{ $spec{includes} || [] }, + @{ $spec{perlinc} || [] } ) { + $path = '-I' . $path; + } + + # split off any -arguments included in cc + my @cc = split / (?=-)/, $spec{cc}; + + return [ grep {defined && length} ( + @cc, '-c' , + @{$spec{includes}} , + @{$spec{cflags}} , + @{$spec{optimize}} , + @{$spec{defines}} , + @{$spec{perlinc}} , + '-o', $spec{output} , + $spec{source} , + ) ]; +} + +sub format_linker_cmd { + my ($self, %spec) = @_; + my $cf = $self->{config}; + + # The Config.pm variable 'libperl' is hardcoded to the full name + # of the perl import library (i.e. 'libperl56.a'). GCC will not + # find it unless the 'lib' prefix & the extension are stripped. + $spec{libperl} =~ s/^(?:lib)?([^.]+).*$/-l$1/; + + unshift( @{$spec{other_ldflags}}, '-nostartfiles' ) + if ( $spec{startup} && @{$spec{startup}} ); + + # From ExtUtils::MM_Win32: + # + ## one thing for GCC/Mingw32: + ## we try to overcome non-relocateable-DLL problems by generating + ## a (hopefully unique) image-base from the dll's name + ## -- BKS, 10-19-1999 + File::Basename::basename( $spec{output} ) =~ /(....)(.{0,4})/; + $spec{image_base} = sprintf( "0x%x0000", unpack('n', $1 ^ $2) ); + + %spec = $self->write_linker_script(%spec) + if $spec{use_scripts}; + + foreach my $path ( @{$spec{libpath}} ) { + $path = "-L$path"; + } + + my @cmds; # Stores the series of commands needed to build the module. + + my $DLLTOOL = $cf->{dlltool} || 'dlltool'; + + push @cmds, [ + $DLLTOOL, '--def' , $spec{def_file}, + '--output-exp' , $spec{explib} + ]; + + # split off any -arguments included in ld + my @ld = split / (?=-)/, $spec{ld}; + + push @cmds, [ grep {defined && length} ( + @ld , + '-o', $spec{output} , + "-Wl,--base-file,$spec{base_file}" , + "-Wl,--image-base,$spec{image_base}" , + @{$spec{lddlflags}} , + @{$spec{libpath}} , + @{$spec{startup}} , + @{$spec{objects}} , + @{$spec{other_ldflags}} , + $spec{libperl} , + @{$spec{perllibs}} , + $spec{explib} , + $spec{map_file} ? ('-Map', $spec{map_file}) : '' + ) ]; + + push @cmds, [ + $DLLTOOL, '--def' , $spec{def_file}, + '--output-exp' , $spec{explib}, + '--base-file' , $spec{base_file} + ]; + + push @cmds, [ grep {defined && length} ( + @ld , + '-o', $spec{output} , + "-Wl,--image-base,$spec{image_base}" , + @{$spec{lddlflags}} , + @{$spec{libpath}} , + @{$spec{startup}} , + @{$spec{objects}} , + @{$spec{other_ldflags}} , + $spec{libperl} , + @{$spec{perllibs}} , + $spec{explib} , + $spec{map_file} ? ('-Map', $spec{map_file}) : '' + ) ]; + + return @cmds; +} + +sub write_linker_script { + my ($self, %spec) = @_; + + my $script = File::Spec->catfile( $spec{srcdir}, + $spec{basename} . '.lds' ); + + $self->add_to_cleanup($script); + + print "Generating script '$script'\n" if !$self->{quiet}; + + my $SCRIPT = IO::File->new( ">$script" ) + or die( "Could not create script '$script': $!" ); + + print $SCRIPT ( 'SEARCH_DIR(' . $_ . ")\n" ) + for @{delete $spec{libpath} || []}; + + # gcc takes only one startup file, so the first object in startup is + # specified as the startup file and any others are shifted into the + # beginning of the list of objects. + if ( $spec{startup} && @{$spec{startup}} ) { + print $SCRIPT 'STARTUP(' . shift( @{$spec{startup}} ) . ")\n"; + unshift @{$spec{objects}}, + @{delete $spec{startup} || []}; + } + + print $SCRIPT 'INPUT(' . join( ',', + @{delete $spec{objects} || []} + ) . ")\n"; + + print $SCRIPT 'INPUT(' . join( ' ', + (delete $spec{libperl} || ''), + @{delete $spec{perllibs} || []}, + ) . ")\n"; + + #it is important to keep the order 1.linker_script - 2.other_ldflags + unshift @{$spec{other_ldflags}}, '"' . $script . '"'; + + return %spec; +} + +1; + + diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/Windows/MSVC.pm b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/Windows/MSVC.pm new file mode 100644 index 00000000000..7da1c9b4c12 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/Windows/MSVC.pm @@ -0,0 +1,131 @@ +package ExtUtils::CBuilder::Platform::Windows::MSVC; + +use vars qw($VERSION); +$VERSION = '0.27'; + +sub arg_exec_file { + my ($self, $file) = @_; + return "/OUT:$file"; +} + +sub format_compiler_cmd { + my ($self, %spec) = @_; + + foreach my $path ( @{ $spec{includes} || [] }, + @{ $spec{perlinc} || [] } ) { + $path = '-I' . $path; + } + + %spec = $self->write_compiler_script(%spec) + if $spec{use_scripts}; + + return [ grep {defined && length} ( + $spec{cc},'-nologo','-c', + @{$spec{includes}} , + @{$spec{cflags}} , + @{$spec{optimize}} , + @{$spec{defines}} , + @{$spec{perlinc}} , + "-Fo$spec{output}" , + $spec{source} , + ) ]; +} + +sub write_compiler_script { + my ($self, %spec) = @_; + + my $script = File::Spec->catfile( $spec{srcdir}, + $spec{basename} . '.ccs' ); + + $self->add_to_cleanup($script); + print "Generating script '$script'\n" if !$self->{quiet}; + + my $SCRIPT = IO::File->new( ">$script" ) + or die( "Could not create script '$script': $!" ); + + print $SCRIPT join( "\n", + map { ref $_ ? @{$_} : $_ } + grep defined, + delete( + @spec{ qw(includes cflags optimize defines perlinc) } ) + ); + + push @{$spec{includes}}, '@"' . $script . '"'; + + return %spec; +} + +sub format_linker_cmd { + my ($self, %spec) = @_; + my $cf = $self->{config}; + + foreach my $path ( @{$spec{libpath}} ) { + $path = "-libpath:$path"; + } + + my $output = $spec{output}; + + $spec{def_file} &&= '-def:' . $spec{def_file}; + $spec{output} &&= '-out:' . $spec{output}; + $spec{manifest} &&= '-manifest ' . $spec{manifest}; + $spec{implib} &&= '-implib:' . $spec{implib}; + $spec{map_file} &&= '-map:' . $spec{map_file}; + + %spec = $self->write_linker_script(%spec) + if $spec{use_scripts}; + + my @cmds; # Stores the series of commands needed to build the module. + + push @cmds, [ grep {defined && length} ( + $spec{ld} , + @{$spec{lddlflags}} , + @{$spec{libpath}} , + @{$spec{other_ldflags}} , + @{$spec{startup}} , + @{$spec{objects}} , + $spec{map_file} , + $spec{libperl} , + @{$spec{perllibs}} , + $spec{def_file} , + $spec{implib} , + $spec{output} , + ) ]; + + # Embed the manifest file if it exists + push @cmds, [ + 'if', 'exist', $spec{manifest}, 'mt', '-nologo', $spec{manifest}, '-outputresource:' . "$output;2" + ]; + + return @cmds; +} + +sub write_linker_script { + my ($self, %spec) = @_; + + my $script = File::Spec->catfile( $spec{srcdir}, + $spec{basename} . '.lds' ); + + $self->add_to_cleanup($script); + + print "Generating script '$script'\n" if !$self->{quiet}; + + my $SCRIPT = IO::File->new( ">$script" ) + or die( "Could not create script '$script': $!" ); + + print $SCRIPT join( "\n", + map { ref $_ ? @{$_} : $_ } + grep defined, + delete( + @spec{ qw(lddlflags libpath other_ldflags + startup objects libperl perllibs + def_file implib map_file) } ) + ); + + push @{$spec{lddlflags}}, '@"' . $script . '"'; + + return %spec; +} + +1; + + diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/aix.pm b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/aix.pm new file mode 100644 index 00000000000..656e0dc67ff --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/aix.pm @@ -0,0 +1,31 @@ +package ExtUtils::CBuilder::Platform::aix; + +use strict; +use ExtUtils::CBuilder::Platform::Unix; +use File::Spec; + +use vars qw($VERSION @ISA); +$VERSION = '0.27'; +@ISA = qw(ExtUtils::CBuilder::Platform::Unix); + +sub need_prelink { 1 } + +sub link { + my ($self, %args) = @_; + my $cf = $self->{config}; + + (my $baseext = $args{module_name}) =~ s/.*:://; + my $perl_inc = $self->perl_inc(); + + # Massage some very naughty bits in %Config + local $cf->{lddlflags} = $cf->{lddlflags}; + for ($cf->{lddlflags}) { + s/\Q$(BASEEXT)\E/$baseext/; + s/\Q$(PERL_INC)\E/$perl_inc/; + } + + return $self->SUPER::link(%args); +} + + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/cygwin.pm b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/cygwin.pm new file mode 100644 index 00000000000..f8650978ec4 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/cygwin.pm @@ -0,0 +1,33 @@ +package ExtUtils::CBuilder::Platform::cygwin; + +use strict; +use File::Spec; +use ExtUtils::CBuilder::Platform::Unix; + +use vars qw($VERSION @ISA); +$VERSION = '0.27'; +@ISA = qw(ExtUtils::CBuilder::Platform::Unix); + +# TODO: If a specific exe_file name is requested, if the exe created +# doesn't have that name, we might want to rename it. Apparently asking +# for an exe of "foo" might result in "foo.exe". Alternatively, we should +# make sure the return value is correctly "foo.exe". +# C.f http://rt.cpan.org/Public/Bug/Display.html?id=41003 +sub link_executable { + my $self = shift; + return $self->SUPER::link_executable(@_); +} + +sub link { + my ($self, %args) = @_; + + my $lib = $self->{config}{useshrplib} ? 'libperl.dll.a' : 'libperl.a'; + $args{extra_linker_flags} = [ + File::Spec->catfile($self->perl_inc(), $lib), + $self->split_like_shell($args{extra_linker_flags}) + ]; + + return $self->SUPER::link(%args); +} + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/darwin.pm b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/darwin.pm new file mode 100644 index 00000000000..efc79347708 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/darwin.pm @@ -0,0 +1,22 @@ +package ExtUtils::CBuilder::Platform::darwin; + +use strict; +use ExtUtils::CBuilder::Platform::Unix; + +use vars qw($VERSION @ISA); +$VERSION = '0.27'; +@ISA = qw(ExtUtils::CBuilder::Platform::Unix); + +sub compile { + my $self = shift; + my $cf = $self->{config}; + + # -flat_namespace isn't a compile flag, it's a linker flag. But + # it's mistakenly in Config.pm as both. Make the correction here. + local $cf->{ccflags} = $cf->{ccflags}; + $cf->{ccflags} =~ s/-flat_namespace//; + $self->SUPER::compile(@_); +} + + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/dec_osf.pm b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/dec_osf.pm new file mode 100644 index 00000000000..d07b71f6d65 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/dec_osf.pm @@ -0,0 +1,18 @@ +package ExtUtils::CBuilder::Platform::dec_osf; + +use strict; +use ExtUtils::CBuilder::Platform::Unix; +use File::Spec; + +use vars qw($VERSION @ISA); +@ISA = qw(ExtUtils::CBuilder::Platform::Unix); +$VERSION = '0.27'; + +sub link_executable { + my $self = shift; + # $Config{ld} is 'ld' but that won't work: use the cc instead. + local $self->{config}{ld} = $self->{config}{cc}; + return $self->SUPER::link_executable(@_); +} + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/os2.pm b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/os2.pm new file mode 100644 index 00000000000..2815d587d7f --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/CBuilder/Platform/os2.pm @@ -0,0 +1,80 @@ +package ExtUtils::CBuilder::Platform::os2; + +use strict; +use ExtUtils::CBuilder::Platform::Unix; + +use vars qw($VERSION @ISA); +$VERSION = '0.27'; +@ISA = qw(ExtUtils::CBuilder::Platform::Unix); + +sub need_prelink { 1 } + +sub prelink { + # Generate import libraries (XXXX currently near .DEF; should be near DLL!) + my $self = shift; + my %args = @_; + + my @res = $self->SUPER::prelink(%args); + die "Unexpected number of DEF files" unless @res == 1; + die "Can't find DEF file in the output" + unless $res[0] =~ m,^(.*)\.def$,si; + my $libname = "$1$self->{config}{lib_ext}"; # Put .LIB file near .DEF file + $self->do_system('emximp', '-o', $libname, $res[0]) or die "emxexp: res=$?"; + return (@res, $libname); +} + +sub _do_link { + my $self = shift; + my ($how, %args) = @_; + if ($how eq 'lib_file' + and (defined $args{module_name} and length $args{module_name})) { + + # DynaLoader::mod2fname() is a builtin func + my $lib = DynaLoader::mod2fname([split /::/, $args{module_name}]); + + # Now know the basename, find directory parts via lib_file, or objects + my $objs = ( (ref $args{objects}) ? $args{objects} : [$args{objects}] ); + my $near_obj = $self->lib_file(@$objs); + my $ref_file = ( defined $args{lib_file} ? $args{lib_file} : $near_obj ); + my $lib_dir = ($ref_file =~ m,(.*)[/\\],s ? "$1/" : '' ); + my $exp_dir = ($near_obj =~ m,(.*)[/\\],s ? "$1/" : '' ); + + $args{dl_file} = $1 if $near_obj =~ m,(.*)\.,s; # put ExportList near OBJ + $args{lib_file} = "$lib_dir$lib.$self->{config}{dlext}"; # DLL file + + # XXX _do_link does not have place to put libraries? + push @$objs, $self->perl_inc() . "/libperl$self->{config}{lib_ext}"; + $args{objects} = $objs; + } + # Some 'env' do exec(), thus return too early when run from ksh; + # To avoid 'env', remove (useless) shrpenv + local $self->{config}{shrpenv} = ''; + return $self->SUPER::_do_link($how, %args); +} + +sub extra_link_args_after_prelink { + # Add .DEF file to the link line + my ($self, %args) = @_; + + my @DEF = grep /\.def$/i, @{$args{prelink_res}}; + die "More than one .def files created by `prelink' stage" if @DEF > 1; + # XXXX No "$how" argument here, so how to test for dynamic link? + die "No .def file created by `prelink' stage" + unless @DEF or not @{$args{prelink_res}}; + + my @after_libs = ($OS2::is_aout ? () + : $self->perl_inc() . "/libperl_override$self->{config}{lib_ext}"); + # , "-L", "-lperl" + (@after_libs, @DEF); +} + +sub link_executable { + # ldflags is not expecting .exe extension given on command line; remove -Zexe + my $self = shift; + local $self->{config}{ldflags} = $self->{config}{ldflags}; + $self->{config}{ldflags} =~ s/(?<!\S)-Zexe(?!\S)//; + return $self->SUPER::link_executable(@_); +} + + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/Command.pm b/Master/tlpkg/tlperl/lib/ExtUtils/Command.pm new file mode 100644 index 00000000000..b5632ff06d6 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/Command.pm @@ -0,0 +1,369 @@ +package ExtUtils::Command; + +use 5.00503; +use strict; +use Carp; +use File::Copy; +use File::Compare; +use File::Basename; +use File::Path qw(rmtree); +require Exporter; +use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION); +@ISA = qw(Exporter); +@EXPORT = qw(cp rm_f rm_rf mv cat eqtime mkpath touch test_f test_d chmod + dos2unix); +$VERSION = '1.16'; + +my $Is_VMS = $^O eq 'VMS'; +my $Is_VMS_mode = $Is_VMS; +my $Is_VMS_noefs = $Is_VMS; +my $Is_Win32 = $^O eq 'MSWin32'; + +if( $Is_VMS ) { + my $vms_unix_rpt; + my $vms_efs; + my $vms_case; + + if (eval { local $SIG{__DIE__}; require VMS::Feature; }) { + $vms_unix_rpt = VMS::Feature::current("filename_unix_report"); + $vms_efs = VMS::Feature::current("efs_charset"); + $vms_case = VMS::Feature::current("efs_case_preserve"); + } else { + my $unix_rpt = $ENV{'DECC$FILENAME_UNIX_REPORT'} || ''; + my $efs_charset = $ENV{'DECC$EFS_CHARSET'} || ''; + my $efs_case = $ENV{'DECC$EFS_CASE_PRESERVE'} || ''; + $vms_unix_rpt = $unix_rpt =~ /^[ET1]/i; + $vms_efs = $efs_charset =~ /^[ET1]/i; + $vms_case = $efs_case =~ /^[ET1]/i; + } + $Is_VMS_mode = 0 if $vms_unix_rpt; + $Is_VMS_noefs = 0 if ($vms_efs); +} + + +=head1 NAME + +ExtUtils::Command - utilities to replace common UNIX commands in Makefiles etc. + +=head1 SYNOPSIS + + perl -MExtUtils::Command -e cat files... > destination + perl -MExtUtils::Command -e mv source... destination + perl -MExtUtils::Command -e cp source... destination + perl -MExtUtils::Command -e touch files... + perl -MExtUtils::Command -e rm_f files... + perl -MExtUtils::Command -e rm_rf directories... + perl -MExtUtils::Command -e mkpath directories... + perl -MExtUtils::Command -e eqtime source destination + perl -MExtUtils::Command -e test_f file + perl -MExtUtils::Command -e test_d directory + perl -MExtUtils::Command -e chmod mode files... + ... + +=head1 DESCRIPTION + +The module is used to replace common UNIX commands. In all cases the +functions work from @ARGV rather than taking arguments. This makes +them easier to deal with in Makefiles. Call them like this: + + perl -MExtUtils::Command -e some_command some files to work on + +and I<NOT> like this: + + perl -MExtUtils::Command -e 'some_command qw(some files to work on)' + +For that use L<Shell::Command>. + +Filenames with * and ? will be glob expanded. + + +=head2 FUNCTIONS + +=over 4 + +=cut + +# VMS uses % instead of ? to mean "one character" +my $wild_regex = $Is_VMS ? '*%' : '*?'; +sub expand_wildcards +{ + @ARGV = map(/[$wild_regex]/o ? glob($_) : $_,@ARGV); +} + + +=item cat + + cat file ... + +Concatenates all files mentioned on command line to STDOUT. + +=cut + +sub cat () +{ + expand_wildcards(); + print while (<>); +} + +=item eqtime + + eqtime source destination + +Sets modified time of destination to that of source. + +=cut + +sub eqtime +{ + my ($src,$dst) = @ARGV; + local @ARGV = ($dst); touch(); # in case $dst doesn't exist + utime((stat($src))[8,9],$dst); +} + +=item rm_rf + + rm_rf files or directories ... + +Removes files and directories - recursively (even if readonly) + +=cut + +sub rm_rf +{ + expand_wildcards(); + rmtree([grep -e $_,@ARGV],0,0); +} + +=item rm_f + + rm_f file ... + +Removes files (even if readonly) + +=cut + +sub rm_f { + expand_wildcards(); + + foreach my $file (@ARGV) { + next unless -f $file; + + next if _unlink($file); + + chmod(0777, $file); + + next if _unlink($file); + + carp "Cannot delete $file: $!"; + } +} + +sub _unlink { + my $files_unlinked = 0; + foreach my $file (@_) { + my $delete_count = 0; + $delete_count++ while unlink $file; + $files_unlinked++ if $delete_count; + } + return $files_unlinked; +} + + +=item touch + + touch file ... + +Makes files exist, with current timestamp + +=cut + +sub touch { + my $t = time; + expand_wildcards(); + foreach my $file (@ARGV) { + open(FILE,">>$file") || die "Cannot write $file:$!"; + close(FILE); + utime($t,$t,$file); + } +} + +=item mv + + mv source_file destination_file + mv source_file source_file destination_dir + +Moves source to destination. Multiple sources are allowed if +destination is an existing directory. + +Returns true if all moves succeeded, false otherwise. + +=cut + +sub mv { + expand_wildcards(); + my @src = @ARGV; + my $dst = pop @src; + + croak("Too many arguments") if (@src > 1 && ! -d $dst); + + my $nok = 0; + foreach my $src (@src) { + $nok ||= !move($src,$dst); + } + return !$nok; +} + +=item cp + + cp source_file destination_file + cp source_file source_file destination_dir + +Copies sources to the destination. Multiple sources are allowed if +destination is an existing directory. + +Returns true if all copies succeeded, false otherwise. + +=cut + +sub cp { + expand_wildcards(); + my @src = @ARGV; + my $dst = pop @src; + + croak("Too many arguments") if (@src > 1 && ! -d $dst); + + my $nok = 0; + foreach my $src (@src) { + $nok ||= !copy($src,$dst); + + # Win32 does not update the mod time of a copied file, just the + # created time which make does not look at. + utime(time, time, $dst) if $Is_Win32; + } + return $nok; +} + +=item chmod + + chmod mode files ... + +Sets UNIX like permissions 'mode' on all the files. e.g. 0666 + +=cut + +sub chmod { + local @ARGV = @ARGV; + my $mode = shift(@ARGV); + expand_wildcards(); + + if( $Is_VMS_mode && $Is_VMS_noefs) { + foreach my $idx (0..$#ARGV) { + my $path = $ARGV[$idx]; + next unless -d $path; + + # chmod 0777, [.foo.bar] doesn't work on VMS, you have to do + # chmod 0777, [.foo]bar.dir + my @dirs = File::Spec->splitdir( $path ); + $dirs[-1] .= '.dir'; + $path = File::Spec->catfile(@dirs); + + $ARGV[$idx] = $path; + } + } + + chmod(oct $mode,@ARGV) || die "Cannot chmod ".join(' ',$mode,@ARGV).":$!"; +} + +=item mkpath + + mkpath directory ... + +Creates directories, including any parent directories. + +=cut + +sub mkpath +{ + expand_wildcards(); + File::Path::mkpath([@ARGV],0,0777); +} + +=item test_f + + test_f file + +Tests if a file exists. I<Exits> with 0 if it does, 1 if it does not (ie. +shell's idea of true and false). + +=cut + +sub test_f +{ + exit(-f $ARGV[0] ? 0 : 1); +} + +=item test_d + + test_d directory + +Tests if a directory exists. I<Exits> with 0 if it does, 1 if it does +not (ie. shell's idea of true and false). + +=cut + +sub test_d +{ + exit(-d $ARGV[0] ? 0 : 1); +} + +=item dos2unix + + dos2unix files or dirs ... + +Converts DOS and OS/2 linefeeds to Unix style recursively. + +=cut + +sub dos2unix { + require File::Find; + File::Find::find(sub { + return if -d; + return unless -w _; + return unless -r _; + return if -B _; + + local $\; + + my $orig = $_; + my $temp = '.dos2unix_tmp'; + open ORIG, $_ or do { warn "dos2unix can't open $_: $!"; return }; + open TEMP, ">$temp" or + do { warn "dos2unix can't create .dos2unix_tmp: $!"; return }; + while (my $line = <ORIG>) { + $line =~ s/\015\012/\012/g; + print TEMP $line; + } + close ORIG; + close TEMP; + rename $temp, $orig; + + }, @ARGV); +} + +=back + +=head1 SEE ALSO + +Shell::Command which is these same functions but take arguments normally. + + +=head1 AUTHOR + +Nick Ing-Simmons C<ni-s@cpan.org> + +Maintained by Michael G Schwern C<schwern@pobox.com> within the +ExtUtils-MakeMaker package and, as a separate CPAN package, by +Randy Kobes C<r.kobes@uwinnipeg.ca>. + +=cut + diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/Command/MM.pm b/Master/tlpkg/tlperl/lib/ExtUtils/Command/MM.pm new file mode 100644 index 00000000000..f9b474de16f --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/Command/MM.pm @@ -0,0 +1,275 @@ +package ExtUtils::Command::MM; + +require 5.006; + +use strict; +use warnings; + +require Exporter; +our @ISA = qw(Exporter); + +our @EXPORT = qw(test_harness pod2man perllocal_install uninstall + warn_if_old_packlist); +our $VERSION = '6.56'; + +my $Is_VMS = $^O eq 'VMS'; + + +=head1 NAME + +ExtUtils::Command::MM - Commands for the MM's to use in Makefiles + +=head1 SYNOPSIS + + perl "-MExtUtils::Command::MM" -e "function" "--" arguments... + + +=head1 DESCRIPTION + +B<FOR INTERNAL USE ONLY!> The interface is not stable. + +ExtUtils::Command::MM encapsulates code which would otherwise have to +be done with large "one" liners. + +Any $(FOO) used in the examples are make variables, not Perl. + +=over 4 + +=item B<test_harness> + + test_harness($verbose, @test_libs); + +Runs the tests on @ARGV via Test::Harness passing through the $verbose +flag. Any @test_libs will be unshifted onto the test's @INC. + +@test_libs are run in alphabetical order. + +=cut + +sub test_harness { + require Test::Harness; + require File::Spec; + + $Test::Harness::verbose = shift; + + # Because Windows doesn't do this for us and listing all the *.t files + # out on the command line can blow over its exec limit. + require ExtUtils::Command; + my @argv = ExtUtils::Command::expand_wildcards(@ARGV); + + local @INC = @INC; + unshift @INC, map { File::Spec->rel2abs($_) } @_; + Test::Harness::runtests(sort { lc $a cmp lc $b } @argv); +} + + + +=item B<pod2man> + + pod2man( '--option=value', + $podfile1 => $manpage1, + $podfile2 => $manpage2, + ... + ); + + # or args on @ARGV + +pod2man() is a function performing most of the duties of the pod2man +program. Its arguments are exactly the same as pod2man as of 5.8.0 +with the addition of: + + --perm_rw octal permission to set the resulting manpage to + +And the removal of: + + --verbose/-v + --help/-h + +If no arguments are given to pod2man it will read from @ARGV. + +If Pod::Man is unavailable, this function will warn and return undef. + +=cut + +sub pod2man { + local @ARGV = @_ ? @_ : @ARGV; + + { + local $@; + if( !eval { require Pod::Man } ) { + warn "Pod::Man is not available: $@". + "Man pages will not be generated during this install.\n"; + return undef; + } + } + require Getopt::Long; + + # We will cheat and just use Getopt::Long. We fool it by putting + # our arguments into @ARGV. Should be safe. + my %options = (); + Getopt::Long::config ('bundling_override'); + Getopt::Long::GetOptions (\%options, + 'section|s=s', 'release|r=s', 'center|c=s', + 'date|d=s', 'fixed=s', 'fixedbold=s', 'fixeditalic=s', + 'fixedbolditalic=s', 'official|o', 'quotes|q=s', 'lax|l', + 'name|n=s', 'perm_rw=i' + ); + + # If there's no files, don't bother going further. + return 0 unless @ARGV; + + # Official sets --center, but don't override things explicitly set. + if ($options{official} && !defined $options{center}) { + $options{center} = q[Perl Programmer's Reference Guide]; + } + + # This isn't a valid Pod::Man option and is only accepted for backwards + # compatibility. + delete $options{lax}; + + do {{ # so 'next' works + my ($pod, $man) = splice(@ARGV, 0, 2); + + next if ((-e $man) && + (-M $man < -M $pod) && + (-M $man < -M "Makefile")); + + print "Manifying $man\n"; + + my $parser = Pod::Man->new(%options); + $parser->parse_from_file($pod, $man) + or do { warn("Could not install $man\n"); next }; + + if (exists $options{perm_rw}) { + chmod(oct($options{perm_rw}), $man) + or do { warn("chmod $options{perm_rw} $man: $!\n"); next }; + } + }} while @ARGV; + + return 1; +} + + +=item B<warn_if_old_packlist> + + perl "-MExtUtils::Command::MM" -e warn_if_old_packlist <somefile> + +Displays a warning that an old packlist file was found. Reads the +filename from @ARGV. + +=cut + +sub warn_if_old_packlist { + my $packlist = $ARGV[0]; + + return unless -f $packlist; + print <<"PACKLIST_WARNING"; +WARNING: I have found an old package in + $packlist. +Please make sure the two installations are not conflicting +PACKLIST_WARNING + +} + + +=item B<perllocal_install> + + perl "-MExtUtils::Command::MM" -e perllocal_install + <type> <module name> <key> <value> ... + + # VMS only, key|value pairs come on STDIN + perl "-MExtUtils::Command::MM" -e perllocal_install + <type> <module name> < <key>|<value> ... + +Prints a fragment of POD suitable for appending to perllocal.pod. +Arguments are read from @ARGV. + +'type' is the type of what you're installing. Usually 'Module'. + +'module name' is simply the name of your module. (Foo::Bar) + +Key/value pairs are extra information about the module. Fields include: + + installed into which directory your module was out into + LINKTYPE dynamic or static linking + VERSION module version number + EXE_FILES any executables installed in a space seperated + list + +=cut + +sub perllocal_install { + my($type, $name) = splice(@ARGV, 0, 2); + + # VMS feeds args as a piped file on STDIN since it usually can't + # fit all the args on a single command line. + my @mod_info = $Is_VMS ? split /\|/, <STDIN> + : @ARGV; + + my $pod; + $pod = sprintf <<POD, scalar localtime; + =head2 %s: C<$type> L<$name|$name> + + =over 4 + +POD + + do { + my($key, $val) = splice(@mod_info, 0, 2); + + $pod .= <<POD + =item * + + C<$key: $val> + +POD + + } while(@mod_info); + + $pod .= "=back\n\n"; + $pod =~ s/^ //mg; + print $pod; + + return 1; +} + +=item B<uninstall> + + perl "-MExtUtils::Command::MM" -e uninstall <packlist> + +A wrapper around ExtUtils::Install::uninstall(). Warns that +uninstallation is deprecated and doesn't actually perform the +uninstallation. + +=cut + +sub uninstall { + my($packlist) = shift @ARGV; + + require ExtUtils::Install; + + print <<'WARNING'; + +Uninstall is unsafe and deprecated, the uninstallation was not performed. +We will show what would have been done. + +WARNING + + ExtUtils::Install::uninstall($packlist, 1, 1); + + print <<'WARNING'; + +Uninstall is unsafe and deprecated, the uninstallation was not performed. +Please check the list above carefully, there may be errors. +Remove the appropriate files manually. +Sorry for the inconvenience. + +WARNING + +} + +=back + +=cut + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/Constant.pm b/Master/tlpkg/tlperl/lib/ExtUtils/Constant.pm new file mode 100644 index 00000000000..0a20b89b792 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/Constant.pm @@ -0,0 +1,565 @@ +package ExtUtils::Constant; +use vars qw (@ISA $VERSION @EXPORT_OK %EXPORT_TAGS); +$VERSION = 0.22; + +=head1 NAME + +ExtUtils::Constant - generate XS code to import C header constants + +=head1 SYNOPSIS + + use ExtUtils::Constant qw (WriteConstants); + WriteConstants( + NAME => 'Foo', + NAMES => [qw(FOO BAR BAZ)], + ); + # Generates wrapper code to make the values of the constants FOO BAR BAZ + # available to perl + +=head1 DESCRIPTION + +ExtUtils::Constant facilitates generating C and XS wrapper code to allow +perl modules to AUTOLOAD constants defined in C library header files. +It is principally used by the C<h2xs> utility, on which this code is based. +It doesn't contain the routines to scan header files to extract these +constants. + +=head1 USAGE + +Generally one only needs to call the C<WriteConstants> function, and then + + #include "const-c.inc" + +in the C section of C<Foo.xs> + + INCLUDE: const-xs.inc + +in the XS section of C<Foo.xs>. + +For greater flexibility use C<constant_types()>, C<C_constant> and +C<XS_constant>, with which C<WriteConstants> is implemented. + +Currently this module understands the following types. h2xs may only know +a subset. The sizes of the numeric types are chosen by the C<Configure> +script at compile time. + +=over 4 + +=item IV + +signed integer, at least 32 bits. + +=item UV + +unsigned integer, the same size as I<IV> + +=item NV + +floating point type, probably C<double>, possibly C<long double> + +=item PV + +NUL terminated string, length will be determined with C<strlen> + +=item PVN + +A fixed length thing, given as a [pointer, length] pair. If you know the +length of a string at compile time you may use this instead of I<PV> + +=item SV + +A B<mortal> SV. + +=item YES + +Truth. (C<PL_sv_yes>) The value is not needed (and ignored). + +=item NO + +Defined Falsehood. (C<PL_sv_no>) The value is not needed (and ignored). + +=item UNDEF + +C<undef>. The value of the macro is not needed. + +=back + +=head1 FUNCTIONS + +=over 4 + +=cut + +if ($] >= 5.006) { + eval "use warnings; 1" or die $@; +} +use strict; +use Carp qw(croak cluck); + +use Exporter; +use ExtUtils::Constant::Utils qw(C_stringify); +use ExtUtils::Constant::XS qw(%XS_Constant %XS_TypeSet); + +@ISA = 'Exporter'; + +%EXPORT_TAGS = ( 'all' => [ qw( + XS_constant constant_types return_clause memEQ_clause C_stringify + C_constant autoload WriteConstants WriteMakefileSnippet +) ] ); + +@EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); + +=item constant_types + +A function returning a single scalar with C<#define> definitions for the +constants used internally between the generated C and XS functions. + +=cut + +sub constant_types { + ExtUtils::Constant::XS->header(); +} + +sub memEQ_clause { + cluck "ExtUtils::Constant::memEQ_clause is deprecated"; + ExtUtils::Constant::XS->memEQ_clause({name=>$_[0], checked_at=>$_[1], + indent=>$_[2]}); +} + +sub return_clause ($$) { + cluck "ExtUtils::Constant::return_clause is deprecated"; + my $indent = shift; + ExtUtils::Constant::XS->return_clause({indent=>$indent}, @_); +} + +sub switch_clause { + cluck "ExtUtils::Constant::switch_clause is deprecated"; + my $indent = shift; + my $comment = shift; + ExtUtils::Constant::XS->switch_clause({indent=>$indent, comment=>$comment}, + @_); +} + +sub C_constant { + my ($package, $subname, $default_type, $what, $indent, $breakout, @items) + = @_; + ExtUtils::Constant::XS->C_constant({package => $package, subname => $subname, + default_type => $default_type, + types => $what, indent => $indent, + breakout => $breakout}, @items); +} + +=item XS_constant PACKAGE, TYPES, XS_SUBNAME, C_SUBNAME + +A function to generate the XS code to implement the perl subroutine +I<PACKAGE>::constant used by I<PACKAGE>::AUTOLOAD to load constants. +This XS code is a wrapper around a C subroutine usually generated by +C<C_constant>, and usually named C<constant>. + +I<TYPES> should be given either as a comma separated list of types that the +C subroutine C<constant> will generate or as a reference to a hash. It should +be the same list of types as C<C_constant> was given. +[Otherwise C<XS_constant> and C<C_constant> may have different ideas about +the number of parameters passed to the C function C<constant>] + +You can call the perl visible subroutine something other than C<constant> if +you give the parameter I<XS_SUBNAME>. The C subroutine it calls defaults to +the name of the perl visible subroutine, unless you give the parameter +I<C_SUBNAME>. + +=cut + +sub XS_constant { + my $package = shift; + my $what = shift; + my $XS_subname = shift; + my $C_subname = shift; + $XS_subname ||= 'constant'; + $C_subname ||= $XS_subname; + + if (!ref $what) { + # Convert line of the form IV,UV,NV to hash + $what = {map {$_ => 1} split /,\s*/, ($what)}; + } + my $params = ExtUtils::Constant::XS->params ($what); + my $type; + + my $xs = <<"EOT"; +void +$XS_subname(sv) + PREINIT: +#ifdef dXSTARG + dXSTARG; /* Faster if we have it. */ +#else + dTARGET; +#endif + STRLEN len; + int type; +EOT + + if ($params->{IV}) { + $xs .= " IV iv;\n"; + } else { + $xs .= " /* IV\t\tiv;\tUncomment this if you need to return IVs */\n"; + } + if ($params->{NV}) { + $xs .= " NV nv;\n"; + } else { + $xs .= " /* NV\t\tnv;\tUncomment this if you need to return NVs */\n"; + } + if ($params->{PV}) { + $xs .= " const char *pv;\n"; + } else { + $xs .= + " /* const char\t*pv;\tUncomment this if you need to return PVs */\n"; + } + + $xs .= << 'EOT'; + INPUT: + SV * sv; + const char * s = SvPV(sv, len); +EOT + if ($params->{''}) { + $xs .= << 'EOT'; + INPUT: + int utf8 = SvUTF8(sv); +EOT + } + $xs .= << 'EOT'; + PPCODE: +EOT + + if ($params->{IV} xor $params->{NV}) { + $xs .= << "EOT"; + /* Change this to $C_subname(aTHX_ s, len, &iv, &nv); + if you need to return both NVs and IVs */ +EOT + } + $xs .= " type = $C_subname(aTHX_ s, len"; + $xs .= ', utf8' if $params->{''}; + $xs .= ', &iv' if $params->{IV}; + $xs .= ', &nv' if $params->{NV}; + $xs .= ', &pv' if $params->{PV}; + $xs .= ', &sv' if $params->{SV}; + $xs .= ");\n"; + + # If anyone is insane enough to suggest a package name containing % + my $package_sprintf_safe = $package; + $package_sprintf_safe =~ s/%/%%/g; + + $xs .= << "EOT"; + /* Return 1 or 2 items. First is error message, or undef if no error. + Second, if present, is found value */ + switch (type) { + case PERL_constant_NOTFOUND: + sv = + sv_2mortal(newSVpvf("%s is not a valid $package_sprintf_safe macro", s)); + PUSHs(sv); + break; + case PERL_constant_NOTDEF: + sv = sv_2mortal(newSVpvf( + "Your vendor has not defined $package_sprintf_safe macro %s, used", + s)); + PUSHs(sv); + break; +EOT + + foreach $type (sort keys %XS_Constant) { + # '' marks utf8 flag needed. + next if $type eq ''; + $xs .= "\t/* Uncomment this if you need to return ${type}s\n" + unless $what->{$type}; + $xs .= " case PERL_constant_IS$type:\n"; + if (length $XS_Constant{$type}) { + $xs .= << "EOT"; + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + $XS_Constant{$type}; +EOT + } else { + # Do nothing. return (), which will be correctly interpreted as + # (undef, undef) + } + $xs .= " break;\n"; + unless ($what->{$type}) { + chop $xs; # Yes, another need for chop not chomp. + $xs .= " */\n"; + } + } + $xs .= << "EOT"; + default: + sv = sv_2mortal(newSVpvf( + "Unexpected return type %d while processing $package_sprintf_safe macro %s, used", + type, s)); + PUSHs(sv); + } +EOT + + return $xs; +} + + +=item autoload PACKAGE, VERSION, AUTOLOADER + +A function to generate the AUTOLOAD subroutine for the module I<PACKAGE> +I<VERSION> is the perl version the code should be backwards compatible with. +It defaults to the version of perl running the subroutine. If I<AUTOLOADER> +is true, the AUTOLOAD subroutine falls back on AutoLoader::AUTOLOAD for all +names that the constant() routine doesn't recognise. + +=cut + +# ' # Grr. syntax highlighters that don't grok pod. + +sub autoload { + my ($module, $compat_version, $autoloader) = @_; + $compat_version ||= $]; + croak "Can't maintain compatibility back as far as version $compat_version" + if $compat_version < 5; + my $func = "sub AUTOLOAD {\n" + . " # This AUTOLOAD is used to 'autoload' constants from the constant()\n" + . " # XS function."; + $func .= " If a constant is not found then control is passed\n" + . " # to the AUTOLOAD in AutoLoader." if $autoloader; + + + $func .= "\n\n" + . " my \$constname;\n"; + $func .= + " our \$AUTOLOAD;\n" if ($compat_version >= 5.006); + + $func .= <<"EOT"; + (\$constname = \$AUTOLOAD) =~ s/.*:://; + croak "&${module}::constant not defined" if \$constname eq 'constant'; + my (\$error, \$val) = constant(\$constname); +EOT + + if ($autoloader) { + $func .= <<'EOT'; + if ($error) { + if ($error =~ /is not a valid/) { + $AutoLoader::AUTOLOAD = $AUTOLOAD; + goto &AutoLoader::AUTOLOAD; + } else { + croak $error; + } + } +EOT + } else { + $func .= + " if (\$error) { croak \$error; }\n"; + } + + $func .= <<'END'; + { + no strict 'refs'; + # Fixed between 5.005_53 and 5.005_61 +#XXX if ($] >= 5.00561) { +#XXX *$AUTOLOAD = sub () { $val }; +#XXX } +#XXX else { + *$AUTOLOAD = sub { $val }; +#XXX } + } + goto &$AUTOLOAD; +} + +END + + return $func; +} + + +=item WriteMakefileSnippet + +WriteMakefileSnippet ATTRIBUTE =E<gt> VALUE [, ...] + +A function to generate perl code for Makefile.PL that will regenerate +the constant subroutines. Parameters are named as passed to C<WriteConstants>, +with the addition of C<INDENT> to specify the number of leading spaces +(default 2). + +Currently only C<INDENT>, C<NAME>, C<DEFAULT_TYPE>, C<NAMES>, C<C_FILE> and +C<XS_FILE> are recognised. + +=cut + +sub WriteMakefileSnippet { + my %args = @_; + my $indent = $args{INDENT} || 2; + + my $result = <<"EOT"; +ExtUtils::Constant::WriteConstants( + NAME => '$args{NAME}', + NAMES => \\\@names, + DEFAULT_TYPE => '$args{DEFAULT_TYPE}', +EOT + foreach (qw (C_FILE XS_FILE)) { + next unless exists $args{$_}; + $result .= sprintf " %-12s => '%s',\n", + $_, $args{$_}; + } + $result .= <<'EOT'; + ); +EOT + + $result =~ s/^/' 'x$indent/gem; + return ExtUtils::Constant::XS->dump_names({default_type=>$args{DEFAULT_TYPE}, + indent=>$indent,}, + @{$args{NAMES}}) + . $result; +} + +=item WriteConstants ATTRIBUTE =E<gt> VALUE [, ...] + +Writes a file of C code and a file of XS code which you should C<#include> +and C<INCLUDE> in the C and XS sections respectively of your module's XS +code. You probably want to do this in your C<Makefile.PL>, so that you can +easily edit the list of constants without touching the rest of your module. +The attributes supported are + +=over 4 + +=item NAME + +Name of the module. This must be specified + +=item DEFAULT_TYPE + +The default type for the constants. If not specified C<IV> is assumed. + +=item BREAKOUT_AT + +The names of the constants are grouped by length. Generate child subroutines +for each group with this number or more names in. + +=item NAMES + +An array of constants' names, either scalars containing names, or hashrefs +as detailed in L<"C_constant">. + +=item PROXYSUBS + +If true, uses proxy subs. See L<ExtUtils::Constant::ProxySubs>. + +=item C_FH + +A filehandle to write the C code to. If not given, then I<C_FILE> is opened +for writing. + +=item C_FILE + +The name of the file to write containing the C code. The default is +C<const-c.inc>. The C<-> in the name ensures that the file can't be +mistaken for anything related to a legitimate perl package name, and +not naming the file C<.c> avoids having to override Makefile.PL's +C<.xs> to C<.c> rules. + +=item XS_FH + +A filehandle to write the XS code to. If not given, then I<XS_FILE> is opened +for writing. + +=item XS_FILE + +The name of the file to write containing the XS code. The default is +C<const-xs.inc>. + +=item XS_SUBNAME + +The perl visible name of the XS subroutine generated which will return the +constants. The default is C<constant>. + +=item C_SUBNAME + +The name of the C subroutine generated which will return the constants. +The default is I<XS_SUBNAME>. Child subroutines have C<_> and the name +length appended, so constants with 10 character names would be in +C<constant_10> with the default I<XS_SUBNAME>. + +=back + +=cut + +sub WriteConstants { + my %ARGS = + ( # defaults + C_FILE => 'const-c.inc', + XS_FILE => 'const-xs.inc', + XS_SUBNAME => 'constant', + DEFAULT_TYPE => 'IV', + @_); + + $ARGS{C_SUBNAME} ||= $ARGS{XS_SUBNAME}; # No-one sane will have C_SUBNAME eq '0' + + croak "Module name not specified" unless length $ARGS{NAME}; + + my $c_fh = $ARGS{C_FH}; + if (!$c_fh) { + if ($] <= 5.008) { + # We need these little games, rather than doing things + # unconditionally, because we're used in core Makefile.PLs before + # IO is available (needed by filehandle), but also we want to work on + # older perls where undefined scalars do not automatically turn into + # anonymous file handles. + require FileHandle; + $c_fh = FileHandle->new(); + } + open $c_fh, ">$ARGS{C_FILE}" or die "Can't open $ARGS{C_FILE}: $!"; + } + + my $xs_fh = $ARGS{XS_FH}; + if (!$xs_fh) { + if ($] <= 5.008) { + require FileHandle; + $xs_fh = FileHandle->new(); + } + open $xs_fh, ">$ARGS{XS_FILE}" or die "Can't open $ARGS{XS_FILE}: $!"; + } + + # As this subroutine is intended to make code that isn't edited, there's no + # need for the user to specify any types that aren't found in the list of + # names. + + if ($ARGS{PROXYSUBS}) { + require ExtUtils::Constant::ProxySubs; + $ARGS{C_FH} = $c_fh; + $ARGS{XS_FH} = $xs_fh; + ExtUtils::Constant::ProxySubs->WriteConstants(%ARGS); + } else { + my $types = {}; + + print $c_fh constant_types(); # macro defs + print $c_fh "\n"; + + # indent is still undef. Until anyone implements indent style rules with + # it. + foreach (ExtUtils::Constant::XS->C_constant({package => $ARGS{NAME}, + subname => $ARGS{C_SUBNAME}, + default_type => + $ARGS{DEFAULT_TYPE}, + types => $types, + breakout => + $ARGS{BREAKOUT_AT}}, + @{$ARGS{NAMES}})) { + print $c_fh $_, "\n"; # C constant subs + } + print $xs_fh XS_constant ($ARGS{NAME}, $types, $ARGS{XS_SUBNAME}, + $ARGS{C_SUBNAME}); + } + + close $c_fh or warn "Error closing $ARGS{C_FILE}: $!" unless $ARGS{C_FH}; + close $xs_fh or warn "Error closing $ARGS{XS_FILE}: $!" unless $ARGS{XS_FH}; +} + +1; +__END__ + +=back + +=head1 AUTHOR + +Nicholas Clark <nick@ccl4.org> based on the code in C<h2xs> by Larry Wall and +others + +=cut diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/Constant/Base.pm b/Master/tlpkg/tlperl/lib/ExtUtils/Constant/Base.pm new file mode 100644 index 00000000000..b5b79af1ea7 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/Constant/Base.pm @@ -0,0 +1,1006 @@ +package ExtUtils::Constant::Base; + +use strict; +use vars qw($VERSION); +use Carp; +use Text::Wrap; +use ExtUtils::Constant::Utils qw(C_stringify perl_stringify); +$VERSION = '0.04'; + +use constant is_perl56 => ($] < 5.007 && $] > 5.005_50); + + +=head1 NAME + +ExtUtils::Constant::Base - base class for ExtUtils::Constant objects + +=head1 SYNOPSIS + + require ExtUtils::Constant::Base; + @ISA = 'ExtUtils::Constant::Base'; + +=head1 DESCRIPTION + +ExtUtils::Constant::Base provides a base implementation of methods to +generate C code to give fast constant value lookup by named string. Currently +it's mostly used ExtUtils::Constant::XS, which generates the lookup code +for the constant() subroutine found in many XS modules. + +=head1 USAGE + +ExtUtils::Constant::Base exports no subroutines. The following methods are +available + +=over 4 + +=cut + +sub valid_type { + # Default to assuming that you don't need different types of return data. + 1; +} +sub default_type { + ''; +} + +=item header + +A method returning a scalar containing definitions needed, typically for a +C header file. + +=cut + +sub header { + '' +} + +# This might actually be a return statement. Note that you are responsible +# for any space you might need before your value, as it lets to perform +# "tricks" such as "return KEY_" and have strings appended. +sub assignment_clause_for_type; +# In which case this might be an empty string +sub return_statement_for_type {undef}; +sub return_statement_for_notdef; +sub return_statement_for_notfound; + +# "#if 1" is true to a C pre-processor +sub macro_from_name { + 1; +} + +sub macro_from_item { + 1; +} + +sub macro_to_ifdef { + my ($self, $macro) = @_; + if (ref $macro) { + return $macro->[0]; + } + if (defined $macro && $macro ne "" && $macro ne "1") { + return $macro ? "#ifdef $macro\n" : "#if 0\n"; + } + return ""; +} + +sub macro_to_endif { + my ($self, $macro) = @_; + + if (ref $macro) { + return $macro->[1]; + } + if (defined $macro && $macro ne "" && $macro ne "1") { + return "#endif\n"; + } + return ""; +} + +sub name_param { + 'name'; +} + +# This is possibly buggy, in that it's not mandatory (below, in the main +# C_constant parameters, but is expected to exist here, if it's needed) +# Buggy because if you're definitely pure 8 bit only, and will never be +# presented with your constants in utf8, the default form of C_constant can't +# be told not to do the utf8 version. + +sub is_utf8_param { + 'utf8'; +} + +sub memEQ { + "!memcmp"; +} + +=item memEQ_clause args_hashref + +A method to return a suitable C C<if> statement to check whether I<name> +is equal to the C variable C<name>. If I<checked_at> is defined, then it +is used to avoid C<memEQ> for short names, or to generate a comment to +highlight the position of the character in the C<switch> statement. + +If i<checked_at> is a reference to a scalar, then instead it gives +the characters pre-checked at the beginning, (and the number of chars by +which the C variable name has been advanced. These need to be chopped from +the front of I<name>). + +=cut + +sub memEQ_clause { +# if (memEQ(name, "thingy", 6)) { + # Which could actually be a character comparison or even "" + my ($self, $args) = @_; + my ($name, $checked_at, $indent) = @{$args}{qw(name checked_at indent)}; + $indent = ' ' x ($indent || 4); + my $front_chop; + if (ref $checked_at) { + # regexp won't work on 5.6.1 without use utf8; in turn that won't work + # on 5.005_03. + substr ($name, 0, length $$checked_at,) = ''; + $front_chop = C_stringify ($$checked_at); + undef $checked_at; + } + my $len = length $name; + + if ($len < 2) { + return $indent . "{\n" + if (defined $checked_at and $checked_at == 0) or $len == 0; + # We didn't switch, drop through to the code for the 2 character string + $checked_at = 1; + } + + my $name_param = $self->name_param; + + if ($len < 3 and defined $checked_at) { + my $check; + if ($checked_at == 1) { + $check = 0; + } elsif ($checked_at == 0) { + $check = 1; + } + if (defined $check) { + my $char = C_stringify (substr $name, $check, 1); + # Placate 5.005 with a break in the string. I can't see a good way of + # getting it to not take [ as introducing an array lookup, even with + # ${name_param}[$check] + return $indent . "if ($name_param" . "[$check] == '$char') {\n"; + } + } + if (($len == 2 and !defined $checked_at) + or ($len == 3 and defined ($checked_at) and $checked_at == 2)) { + my $char1 = C_stringify (substr $name, 0, 1); + my $char2 = C_stringify (substr $name, 1, 1); + return $indent . + "if ($name_param" . "[0] == '$char1' && $name_param" . "[1] == '$char2') {\n"; + } + if (($len == 3 and defined ($checked_at) and $checked_at == 1)) { + my $char1 = C_stringify (substr $name, 0, 1); + my $char2 = C_stringify (substr $name, 2, 1); + return $indent . + "if ($name_param" . "[0] == '$char1' && $name_param" . "[2] == '$char2') {\n"; + } + + my $pointer = '^'; + my $have_checked_last = defined ($checked_at) && $len == $checked_at + 1; + if ($have_checked_last) { + # Checked at the last character, so no need to memEQ it. + $pointer = C_stringify (chop $name); + $len--; + } + + $name = C_stringify ($name); + my $memEQ = $self->memEQ(); + my $body = $indent . "if ($memEQ($name_param, \"$name\", $len)) {\n"; + # Put a little ^ under the letter we checked at + # Screws up for non printable and non-7 bit stuff, but that's too hard to + # get right. + if (defined $checked_at) { + $body .= $indent . "/* " . (' ' x length $memEQ) + . (' ' x length $name_param) + . (' ' x $checked_at) . $pointer + . (' ' x ($len - $checked_at + length $len)) . " */\n"; + } elsif (defined $front_chop) { + $body .= $indent . "/* $front_chop" + . (' ' x ($len + 1 + length $len)) . " */\n"; + } + return $body; +} + +=item dump_names arg_hashref, ITEM... + +An internal function to generate the embedded perl code that will regenerate +the constant subroutines. I<default_type>, I<types> and I<ITEM>s are the +same as for C_constant. I<indent> is treated as number of spaces to indent +by. If C<declare_types> is true a C<$types> is always declared in the perl +code generated, if defined and false never declared, and if undefined C<$types> +is only declared if the values in I<types> as passed in cannot be inferred from +I<default_types> and the I<ITEM>s. + +=cut + +sub dump_names { + my ($self, $args, @items) = @_; + my ($default_type, $what, $indent, $declare_types) + = @{$args}{qw(default_type what indent declare_types)}; + $indent = ' ' x ($indent || 0); + + my $result; + my (@simple, @complex, %used_types); + foreach (@items) { + my $type; + if (ref $_) { + $type = $_->{type} || $default_type; + if ($_->{utf8}) { + # For simplicity always skip the bytes case, and reconstitute this entry + # from its utf8 twin. + next if $_->{utf8} eq 'no'; + # Copy the hashref, as we don't want to mess with the caller's hashref. + $_ = {%$_}; + unless (is_perl56) { + utf8::decode ($_->{name}); + } else { + $_->{name} = pack 'U*', unpack 'U0U*', $_->{name}; + } + delete $_->{utf8}; + } + } else { + $_ = {name=>$_}; + $type = $default_type; + } + $used_types{$type}++; + if ($type eq $default_type + # grr 5.6.1 + and length $_->{name} + and length $_->{name} == ($_->{name} =~ tr/A-Za-z0-9_//) + and !defined ($_->{macro}) and !defined ($_->{value}) + and !defined ($_->{default}) and !defined ($_->{pre}) + and !defined ($_->{post}) and !defined ($_->{def_pre}) + and !defined ($_->{def_post}) and !defined ($_->{weight})) { + # It's the default type, and the name consists only of A-Za-z0-9_ + push @simple, $_->{name}; + } else { + push @complex, $_; + } + } + + if (!defined $declare_types) { + # Do they pass in any types we weren't already using? + foreach (keys %$what) { + next if $used_types{$_}; + $declare_types++; # Found one in $what that wasn't used. + last; # And one is enough to terminate this loop + } + } + if ($declare_types) { + $result = $indent . 'my $types = {map {($_, 1)} qw(' + . join (" ", sort keys %$what) . ")};\n"; + } + local $Text::Wrap::huge = 'overflow'; + local $Text::Wrap::columns = 80; + $result .= wrap ($indent . "my \@names = (qw(", + $indent . " ", join (" ", sort @simple) . ")"); + if (@complex) { + foreach my $item (sort {$a->{name} cmp $b->{name}} @complex) { + my $name = perl_stringify $item->{name}; + my $line = ",\n$indent {name=>\"$name\""; + $line .= ", type=>\"$item->{type}\"" if defined $item->{type}; + foreach my $thing (qw (macro value default pre post def_pre def_post)) { + my $value = $item->{$thing}; + if (defined $value) { + if (ref $value) { + $line .= ", $thing=>[\"" + . join ('", "', map {perl_stringify $_} @$value) . '"]'; + } else { + $line .= ", $thing=>\"" . perl_stringify($value) . "\""; + } + } + } + $line .= "}"; + # Ensure that the enclosing C comment doesn't end + # by turning */ into *" . "/ + $line =~ s!\*\/!\*" . "/!gs; + # gcc -Wall doesn't like finding /* inside a comment + $line =~ s!\/\*!/" . "\*!gs; + $result .= $line; + } + } + $result .= ");\n"; + + $result; +} + +=item assign arg_hashref, VALUE... + +A method to return a suitable assignment clause. If I<type> is aggregate +(eg I<PVN> expects both pointer and length) then there should be multiple +I<VALUE>s for the components. I<pre> and I<post> if defined give snippets +of C code to proceed and follow the assignment. I<pre> will be at the start +of a block, so variables may be defined in it. + +=cut +# Hmm. value undef to to NOTDEF? value () to do NOTFOUND? + +sub assign { + my $self = shift; + my $args = shift; + my ($indent, $type, $pre, $post, $item) + = @{$args}{qw(indent type pre post item)}; + $post ||= ''; + my $clause; + my $close; + if ($pre) { + chomp $pre; + $close = "$indent}\n"; + $clause = $indent . "{\n"; + $indent .= " "; + $clause .= "$indent$pre"; + $clause .= ";" unless $pre =~ /;$/; + $clause .= "\n"; + } + confess "undef \$type" unless defined $type; + confess "Can't generate code for type $type" + unless $self->valid_type($type); + + $clause .= join '', map {"$indent$_\n"} + $self->assignment_clause_for_type({type=>$type,item=>$item}, @_); + chomp $post; + if (length $post) { + $clause .= "$post"; + $clause .= ";" unless $post =~ /;$/; + $clause .= "\n"; + } + my $return = $self->return_statement_for_type($type); + $clause .= "$indent$return\n" if defined $return; + $clause .= $close if $close; + return $clause; +} + +=item return_clause arg_hashref, ITEM + +A method to return a suitable C<#ifdef> clause. I<ITEM> is a hashref +(as passed to C<C_constant> and C<match_clause>. I<indent> is the number +of spaces to indent, defaulting to 6. + +=cut + +sub return_clause { + +##ifdef thingy +# *iv_return = thingy; +# return PERL_constant_ISIV; +##else +# return PERL_constant_NOTDEF; +##endif + my ($self, $args, $item) = @_; + my $indent = $args->{indent}; + + my ($name, $value, $default, $pre, $post, $def_pre, $def_post, $type) + = @$item{qw (name value default pre post def_pre def_post type)}; + $value = $name unless defined $value; + my $macro = $self->macro_from_item($item); + $indent = ' ' x ($indent || 6); + unless (defined $type) { + # use Data::Dumper; print STDERR Dumper ($item); + confess "undef \$type"; + } + + ##ifdef thingy + my $clause = $self->macro_to_ifdef($macro); + + # *iv_return = thingy; + # return PERL_constant_ISIV; + $clause + .= $self->assign ({indent=>$indent, type=>$type, pre=>$pre, post=>$post, + item=>$item}, ref $value ? @$value : $value); + + if (defined $macro && $macro ne "" && $macro ne "1") { + ##else + $clause .= "#else\n"; + + # return PERL_constant_NOTDEF; + if (!defined $default) { + my $notdef = $self->return_statement_for_notdef(); + $clause .= "$indent$notdef\n" if defined $notdef; + } else { + my @default = ref $default ? @$default : $default; + $type = shift @default; + $clause .= $self->assign ({indent=>$indent, type=>$type, pre=>$pre, + post=>$post, item=>$item}, @default); + } + } + ##endif + $clause .= $self->macro_to_endif($macro); + + return $clause; +} + +sub match_clause { + # $offset defined if we have checked an offset. + my ($self, $args, $item) = @_; + my ($offset, $indent) = @{$args}{qw(checked_at indent)}; + $indent = ' ' x ($indent || 4); + my $body = ''; + my ($no, $yes, $either, $name, $inner_indent); + if (ref $item eq 'ARRAY') { + ($yes, $no) = @$item; + $either = $yes || $no; + confess "$item is $either expecting hashref in [0] || [1]" + unless ref $either eq 'HASH'; + $name = $either->{name}; + } else { + confess "$item->{name} has utf8 flag '$item->{utf8}', should be false" + if $item->{utf8}; + $name = $item->{name}; + $inner_indent = $indent; + } + + $body .= $self->memEQ_clause ({name => $name, checked_at => $offset, + indent => length $indent}); + # If we've been presented with an arrayref for $item, then the user string + # contains in the range 128-255, and we need to check whether it was utf8 + # (or not). + # In the worst case we have two named constants, where one's name happens + # encoded in UTF8 happens to be the same byte sequence as the second's + # encoded in (say) ISO-8859-1. + # In this case, $yes and $no both have item hashrefs. + if ($yes) { + $body .= $indent . " if (" . $self->is_utf8_param . ") {\n"; + } elsif ($no) { + $body .= $indent . " if (!" . $self->is_utf8_param . ") {\n"; + } + if ($either) { + $body .= $self->return_clause ({indent=>4 + length $indent}, $either); + if ($yes and $no) { + $body .= $indent . " } else {\n"; + $body .= $self->return_clause ({indent=>4 + length $indent}, $no); + } + $body .= $indent . " }\n"; + } else { + $body .= $self->return_clause ({indent=>2 + length $indent}, $item); + } + $body .= $indent . "}\n"; +} + + +=item switch_clause arg_hashref, NAMELEN, ITEMHASH, ITEM... + +An internal method to generate a suitable C<switch> clause, called by +C<C_constant> I<ITEM>s are in the hash ref format as given in the description +of C<C_constant>, and must all have the names of the same length, given by +I<NAMELEN>. I<ITEMHASH> is a reference to a hash, keyed by name, values being +the hashrefs in the I<ITEM> list. (No parameters are modified, and there can +be keys in the I<ITEMHASH> that are not in the list of I<ITEM>s without +causing problems - the hash is passed in to save generating it afresh for +each call). + +=cut + +sub switch_clause { + my ($self, $args, $namelen, $items, @items) = @_; + my ($indent, $comment) = @{$args}{qw(indent comment)}; + $indent = ' ' x ($indent || 2); + + local $Text::Wrap::huge = 'overflow'; + local $Text::Wrap::columns = 80; + + my @names = sort map {$_->{name}} @items; + my $leader = $indent . '/* '; + my $follower = ' ' x length $leader; + my $body = $indent . "/* Names all of length $namelen. */\n"; + if (defined $comment) { + $body = wrap ($leader, $follower, $comment) . "\n"; + $leader = $follower; + } + my @safe_names = @names; + foreach (@safe_names) { + confess sprintf "Name '$_' is length %d, not $namelen", length + unless length == $namelen; + # Argh. 5.6.1 + # next unless tr/A-Za-z0-9_//c; + next if tr/A-Za-z0-9_// == length; + $_ = '"' . perl_stringify ($_) . '"'; + # Ensure that the enclosing C comment doesn't end + # by turning */ into *" . "/ + s!\*\/!\*"."/!gs; + # gcc -Wall doesn't like finding /* inside a comment + s!\/\*!/"."\*!gs; + } + $body .= wrap ($leader, $follower, join (" ", @safe_names) . " */") . "\n"; + # Figure out what to switch on. + # (RMS, Spread of jump table, Position, Hashref) + my @best = (1e38, ~0); + # Prefer the last character over the others. (As it lets us shorten the + # memEQ clause at no cost). + foreach my $i ($namelen - 1, 0 .. ($namelen - 2)) { + my ($min, $max) = (~0, 0); + my %spread; + if (is_perl56) { + # Need proper Unicode preserving hash keys for bytes in range 128-255 + # here too, for some reason. grr 5.6.1 yet again. + tie %spread, 'ExtUtils::Constant::Aaargh56Hash'; + } + foreach (@names) { + my $char = substr $_, $i, 1; + my $ord = ord $char; + confess "char $ord is out of range" if $ord > 255; + $max = $ord if $ord > $max; + $min = $ord if $ord < $min; + push @{$spread{$char}}, $_; + # warn "$_ $char"; + } + # I'm going to pick the character to split on that minimises the root + # mean square of the number of names in each case. Normally this should + # be the one with the most keys, but it may pick a 7 where the 8 has + # one long linear search. I'm not sure if RMS or just sum of squares is + # actually better. + # $max and $min are for the tie-breaker if the root mean squares match. + # Assuming that the compiler may be building a jump table for the + # switch() then try to minimise the size of that jump table. + # Finally use < not <= so that if it still ties the earliest part of + # the string wins. Because if that passes but the memEQ fails, it may + # only need the start of the string to bin the choice. + # I think. But I'm micro-optimising. :-) + # OK. Trump that. Now favour the last character of the string, before the + # rest. + my $ss; + $ss += @$_ * @$_ foreach values %spread; + my $rms = sqrt ($ss / keys %spread); + if ($rms < $best[0] || ($rms == $best[0] && ($max - $min) < $best[1])) { + @best = ($rms, $max - $min, $i, \%spread); + } + } + confess "Internal error. Failed to pick a switch point for @names" + unless defined $best[2]; + # use Data::Dumper; print Dumper (@best); + my ($offset, $best) = @best[2,3]; + $body .= $indent . "/* Offset $offset gives the best switch position. */\n"; + + my $do_front_chop = $offset == 0 && $namelen > 2; + if ($do_front_chop) { + $body .= $indent . "switch (*" . $self->name_param() . "++) {\n"; + } else { + $body .= $indent . "switch (" . $self->name_param() . "[$offset]) {\n"; + } + foreach my $char (sort keys %$best) { + confess sprintf "'$char' is %d bytes long, not 1", length $char + if length ($char) != 1; + confess sprintf "char %#X is out of range", ord $char if ord ($char) > 255; + $body .= $indent . "case '" . C_stringify ($char) . "':\n"; + foreach my $thisone (sort { + # Deal with the case of an item actually being an array ref to 1 or 2 + # hashrefs. Don't assign to $a or $b, as they're aliases to the orignal + my $l = ref $a eq 'ARRAY' ? ($a->[0] || $->[1]) : $a; + my $r = ref $b eq 'ARRAY' ? ($b->[0] || $->[1]) : $b; + # Sort by weight first + ($r->{weight} || 0) <=> ($l->{weight} || 0) + # Sort equal weights by name + or $l->{name} cmp $r->{name}} + # If this looks evil, maybe it is. $items is a + # hashref, and we're doing a hash slice on it + @{$items}{@{$best->{$char}}}) { + # warn "You are here"; + if ($do_front_chop) { + $body .= $self->match_clause ({indent => 2 + length $indent, + checked_at => \$char}, $thisone); + } else { + $body .= $self->match_clause ({indent => 2 + length $indent, + checked_at => $offset}, $thisone); + } + } + $body .= $indent . " break;\n"; + } + $body .= $indent . "}\n"; + return $body; +} + +sub C_constant_return_type { + "static int"; +} + +sub C_constant_prefix_param { + ''; +} + +sub C_constant_prefix_param_defintion { + ''; +} + +sub name_param_definition { + "const char *" . $_[0]->name_param; +} + +sub namelen_param { + 'len'; +} + +sub namelen_param_definition { + 'size_t ' . $_[0]->namelen_param; +} + +sub C_constant_other_params { + ''; +} + +sub C_constant_other_params_defintion { + ''; +} + +=item params WHAT + +An "internal" method, subject to change, currently called to allow an +overriding class to cache information that will then be passed into all +the C<*param*> calls. (Yes, having to read the source to make sense of this is +considered a known bug). I<WHAT> is be a hashref of types the constant +function will return. In ExtUtils::Constant::XS this method is used to +returns a hashref keyed IV NV PV SV to show which combination of pointers will +be needed in the C argument list generated by +C_constant_other_params_definition and C_constant_other_params + +=cut + +sub params { + ''; +} + + +=item dogfood arg_hashref, ITEM... + +An internal function to generate the embedded perl code that will regenerate +the constant subroutines. Parameters are the same as for C_constant. + +Currently the base class does nothing and returns an empty string. + +=cut + +sub dogfood { + '' +} + +=item normalise_items args, default_type, seen_types, seen_items, ITEM... + +Convert the items to a normalised form. For 8 bit and Unicode values converts +the item to an array of 1 or 2 items, both 8 bit and UTF-8 encoded. + +=cut + +sub normalise_items +{ + my $self = shift; + my $args = shift; + my $default_type = shift; + my $what = shift; + my $items = shift; + my @new_items; + foreach my $orig (@_) { + my ($name, $item); + if (ref $orig) { + # Make a copy which is a normalised version of the ref passed in. + $name = $orig->{name}; + my ($type, $macro, $value) = @$orig{qw (type macro value)}; + $type ||= $default_type; + $what->{$type} = 1; + $item = {name=>$name, type=>$type}; + + undef $macro if defined $macro and $macro eq $name; + $item->{macro} = $macro if defined $macro; + undef $value if defined $value and $value eq $name; + $item->{value} = $value if defined $value; + foreach my $key (qw(default pre post def_pre def_post weight + not_constant)) { + my $value = $orig->{$key}; + $item->{$key} = $value if defined $value; + # warn "$key $value"; + } + } else { + $name = $orig; + $item = {name=>$name, type=>$default_type}; + $what->{$default_type} = 1; + } + warn +(ref ($self) || $self) + . "doesn't know how to handle values of type $_ used in macro $name" + unless $self->valid_type ($item->{type}); + # tr///c is broken on 5.6.1 for utf8, so my original tr/\0-\177//c + # doesn't work. Upgrade to 5.8 + # if ($name !~ tr/\0-\177//c || $] < 5.005_50) { + if ($name =~ tr/\0-\177// == length $name || $] < 5.005_50 + || $args->{disable_utf8_duplication}) { + # No characters outside 7 bit ASCII. + if (exists $items->{$name}) { + die "Multiple definitions for macro $name"; + } + $items->{$name} = $item; + } else { + # No characters outside 8 bit. This is hardest. + if (exists $items->{$name} and ref $items->{$name} ne 'ARRAY') { + confess "Unexpected ASCII definition for macro $name"; + } + # Again, 5.6.1 tr broken, so s/5\.6.*/5\.8\.0/; + # if ($name !~ tr/\0-\377//c) { + if ($name =~ tr/\0-\377// == length $name) { +# if ($] < 5.007) { +# $name = pack "C*", unpack "U*", $name; +# } + $item->{utf8} = 'no'; + $items->{$name}[1] = $item; + push @new_items, $item; + # Copy item, to create the utf8 variant. + $item = {%$item}; + } + # Encode the name as utf8 bytes. + unless (is_perl56) { + utf8::encode($name); + } else { +# warn "Was >$name< " . length ${name}; + $name = pack 'C*', unpack 'C*', $name . pack 'U*'; +# warn "Now '${name}' " . length ${name}; + } + if ($items->{$name}[0]) { + die "Multiple definitions for macro $name"; + } + $item->{utf8} = 'yes'; + $item->{name} = $name; + $items->{$name}[0] = $item; + # We have need for the utf8 flag. + $what->{''} = 1; + } + push @new_items, $item; + } + @new_items; +} + +=item C_constant arg_hashref, ITEM... + +A function that returns a B<list> of C subroutine definitions that return +the value and type of constants when passed the name by the XS wrapper. +I<ITEM...> gives a list of constant names. Each can either be a string, +which is taken as a C macro name, or a reference to a hash with the following +keys + +=over 8 + +=item name + +The name of the constant, as seen by the perl code. + +=item type + +The type of the constant (I<IV>, I<NV> etc) + +=item value + +A C expression for the value of the constant, or a list of C expressions if +the type is aggregate. This defaults to the I<name> if not given. + +=item macro + +The C pre-processor macro to use in the C<#ifdef>. This defaults to the +I<name>, and is mainly used if I<value> is an C<enum>. If a reference an +array is passed then the first element is used in place of the C<#ifdef> +line, and the second element in place of the C<#endif>. This allows +pre-processor constructions such as + + #if defined (foo) + #if !defined (bar) + ... + #endif + #endif + +to be used to determine if a constant is to be defined. + +A "macro" 1 signals that the constant is always defined, so the C<#if>/C<#endif> +test is omitted. + +=item default + +Default value to use (instead of C<croak>ing with "your vendor has not +defined...") to return if the macro isn't defined. Specify a reference to +an array with type followed by value(s). + +=item pre + +C code to use before the assignment of the value of the constant. This allows +you to use temporary variables to extract a value from part of a C<struct> +and return this as I<value>. This C code is places at the start of a block, +so you can declare variables in it. + +=item post + +C code to place between the assignment of value (to a temporary) and the +return from the function. This allows you to clear up anything in I<pre>. +Rarely needed. + +=item def_pre + +=item def_post + +Equivalents of I<pre> and I<post> for the default value. + +=item utf8 + +Generated internally. Is zero or undefined if name is 7 bit ASCII, +"no" if the name is 8 bit (and so should only match if SvUTF8() is false), +"yes" if the name is utf8 encoded. + +The internals automatically clone any name with characters 128-255 but none +256+ (ie one that could be either in bytes or utf8) into a second entry +which is utf8 encoded. + +=item weight + +Optional sorting weight for names, to determine the order of +linear testing when multiple names fall in the same case of a switch clause. +Higher comes earlier, undefined defaults to zero. + +=back + +In the argument hashref, I<package> is the name of the package, and is only +used in comments inside the generated C code. I<subname> defaults to +C<constant> if undefined. + +I<default_type> is the type returned by C<ITEM>s that don't specify their +type. It defaults to the value of C<default_type()>. I<types> should be given +either as a comma separated list of types that the C subroutine I<subname> +will generate or as a reference to a hash. I<default_type> will be added to +the list if not present, as will any types given in the list of I<ITEM>s. The +resultant list should be the same list of types that C<XS_constant> is +given. [Otherwise C<XS_constant> and C<C_constant> may differ in the number of +parameters to the constant function. I<indent> is currently unused and +ignored. In future it may be used to pass in information used to change the C +indentation style used.] The best way to maintain consistency is to pass in a +hash reference and let this function update it. + +I<breakout> governs when child functions of I<subname> are generated. If there +are I<breakout> or more I<ITEM>s with the same length of name, then the code +to switch between them is placed into a function named I<subname>_I<len>, for +example C<constant_5> for names 5 characters long. The default I<breakout> is +3. A single C<ITEM> is always inlined. + +=cut + +# The parameter now BREAKOUT was previously documented as: +# +# I<NAMELEN> if defined signals that all the I<name>s of the I<ITEM>s are of +# this length, and that the constant name passed in by perl is checked and +# also of this length. It is used during recursion, and should be C<undef> +# unless the caller has checked all the lengths during code generation, and +# the generated subroutine is only to be called with a name of this length. +# +# As you can see it now performs this function during recursion by being a +# scalar reference. + +sub C_constant { + my ($self, $args, @items) = @_; + my ($package, $subname, $default_type, $what, $indent, $breakout) = + @{$args}{qw(package subname default_type types indent breakout)}; + $package ||= 'Foo'; + $subname ||= 'constant'; + # I'm not using this. But a hashref could be used for full formatting without + # breaking this API + # $indent ||= 0; + + my ($namelen, $items); + if (ref $breakout) { + # We are called recursively. We trust @items to be normalised, $what to + # be a hashref, and pinch %$items from our parent to save recalculation. + ($namelen, $items) = @$breakout; + } else { + $items = {}; + if (is_perl56) { + # Need proper Unicode preserving hash keys. + require ExtUtils::Constant::Aaargh56Hash; + tie %$items, 'ExtUtils::Constant::Aaargh56Hash'; + } + $breakout ||= 3; + $default_type ||= $self->default_type(); + if (!ref $what) { + # Convert line of the form IV,UV,NV to hash + $what = {map {$_ => 1} split /,\s*/, ($what || '')}; + # Figure out what types we're dealing with, and assign all unknowns to the + # default type + } + @items = $self->normalise_items ({}, $default_type, $what, $items, @items); + # use Data::Dumper; print Dumper @items; + } + my $params = $self->params ($what); + + # Probably "static int" + my ($body, @subs); + $body = $self->C_constant_return_type($params) . "\n$subname (" + # Eg "pTHX_ " + . $self->C_constant_prefix_param_defintion($params) + # Probably "const char *name" + . $self->name_param_definition($params); + # Something like ", STRLEN len" + $body .= ", " . $self->namelen_param_definition($params) + unless defined $namelen; + $body .= $self->C_constant_other_params_defintion($params); + $body .= ") {\n"; + + if (defined $namelen) { + # We are a child subroutine. Print the simple description + my $comment = 'When generated this function returned values for the list' + . ' of names given here. However, subsequent manual editing may have' + . ' added or removed some.'; + $body .= $self->switch_clause ({indent=>2, comment=>$comment}, + $namelen, $items, @items); + } else { + # We are the top level. + $body .= " /* Initially switch on the length of the name. */\n"; + $body .= $self->dogfood ({package => $package, subname => $subname, + default_type => $default_type, what => $what, + indent => $indent, breakout => $breakout}, + @items); + $body .= ' switch ('.$self->namelen_param().") {\n"; + # Need to group names of the same length + my @by_length; + foreach (@items) { + push @{$by_length[length $_->{name}]}, $_; + } + foreach my $i (0 .. $#by_length) { + next unless $by_length[$i]; # None of this length + $body .= " case $i:\n"; + if (@{$by_length[$i]} == 1) { + my $only_thing = $by_length[$i]->[0]; + if ($only_thing->{utf8}) { + if ($only_thing->{utf8} eq 'yes') { + # With utf8 on flag item is passed in element 0 + $body .= $self->match_clause (undef, [$only_thing]); + } else { + # With utf8 off flag item is passed in element 1 + $body .= $self->match_clause (undef, [undef, $only_thing]); + } + } else { + $body .= $self->match_clause (undef, $only_thing); + } + } elsif (@{$by_length[$i]} < $breakout) { + $body .= $self->switch_clause ({indent=>4}, + $i, $items, @{$by_length[$i]}); + } else { + # Only use the minimal set of parameters actually needed by the types + # of the names of this length. + my $what = {}; + foreach (@{$by_length[$i]}) { + $what->{$_->{type}} = 1; + $what->{''} = 1 if $_->{utf8}; + } + $params = $self->params ($what); + push @subs, $self->C_constant ({package=>$package, + subname=>"${subname}_$i", + default_type => $default_type, + types => $what, indent => $indent, + breakout => [$i, $items]}, + @{$by_length[$i]}); + $body .= " return ${subname}_$i (" + # Eg "aTHX_ " + . $self->C_constant_prefix_param($params) + # Probably "name" + . $self->name_param($params); + $body .= $self->C_constant_other_params($params); + $body .= ");\n"; + } + $body .= " break;\n"; + } + $body .= " }\n"; + } + my $notfound = $self->return_statement_for_notfound(); + $body .= " $notfound\n" if $notfound; + $body .= "}\n"; + return (@subs, $body); +} + +1; +__END__ + +=back + +=head1 BUGS + +Not everything is documented yet. + +Probably others. + +=head1 AUTHOR + +Nicholas Clark <nick@ccl4.org> based on the code in C<h2xs> by Larry Wall and +others diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/Constant/ProxySubs.pm b/Master/tlpkg/tlperl/lib/ExtUtils/Constant/ProxySubs.pm new file mode 100644 index 00000000000..c3fe8ed3c56 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/Constant/ProxySubs.pm @@ -0,0 +1,549 @@ +package ExtUtils::Constant::ProxySubs; + +use strict; +use vars qw($VERSION @ISA %type_to_struct %type_from_struct %type_to_sv + %type_to_C_value %type_is_a_problem %type_num_args + %type_temporary); +use Carp; +require ExtUtils::Constant::XS; +use ExtUtils::Constant::Utils qw(C_stringify); +use ExtUtils::Constant::XS qw(%XS_TypeSet); + +$VERSION = '0.06'; +@ISA = 'ExtUtils::Constant::XS'; + +%type_to_struct = + ( + IV => '{const char *name; I32 namelen; IV value;}', + NV => '{const char *name; I32 namelen; NV value;}', + UV => '{const char *name; I32 namelen; UV value;}', + PV => '{const char *name; I32 namelen; const char *value;}', + PVN => '{const char *name; I32 namelen; const char *value; STRLEN len;}', + YES => '{const char *name; I32 namelen;}', + NO => '{const char *name; I32 namelen;}', + UNDEF => '{const char *name; I32 namelen;}', + '' => '{const char *name; I32 namelen;} ', + ); + +%type_from_struct = + ( + IV => sub { $_[0] . '->value' }, + NV => sub { $_[0] . '->value' }, + UV => sub { $_[0] . '->value' }, + PV => sub { $_[0] . '->value' }, + PVN => sub { $_[0] . '->value', $_[0] . '->len' }, + YES => sub {}, + NO => sub {}, + UNDEF => sub {}, + '' => sub {}, + ); + +%type_to_sv = + ( + IV => sub { "newSViv($_[0])" }, + NV => sub { "newSVnv($_[0])" }, + UV => sub { "newSVuv($_[0])" }, + PV => sub { "newSVpv($_[0], 0)" }, + PVN => sub { "newSVpvn($_[0], $_[1])" }, + YES => sub { '&PL_sv_yes' }, + NO => sub { '&PL_sv_no' }, + UNDEF => sub { '&PL_sv_undef' }, + '' => sub { '&PL_sv_yes' }, + SV => sub {"SvREFCNT_inc($_[0])"}, + ); + +%type_to_C_value = + ( + YES => sub {}, + NO => sub {}, + UNDEF => sub {}, + '' => sub {}, + ); + +sub type_to_C_value { + my ($self, $type) = @_; + return $type_to_C_value{$type} || sub {return map {ref $_ ? @$_ : $_} @_}; +} + +# TODO - figure out if there is a clean way for the type_to_sv code to +# attempt s/sv_2mortal// and if it succeeds tell type_to_sv not to add +# SvREFCNT_inc +%type_is_a_problem = + ( + # The documentation says *mortal SV*, but we now need a non-mortal copy. + SV => 1, + ); + +%type_temporary = + ( + SV => ['SV *'], + PV => ['const char *'], + PVN => ['const char *', 'STRLEN'], + ); +$type_temporary{$_} = [$_] foreach qw(IV UV NV); + +while (my ($type, $value) = each %XS_TypeSet) { + $type_num_args{$type} + = defined $value ? ref $value ? scalar @$value : 1 : 0; +} +$type_num_args{''} = 0; + +sub partition_names { + my ($self, $default_type, @items) = @_; + my (%found, @notfound, @trouble); + + while (my $item = shift @items) { + my $default = delete $item->{default}; + if ($default) { + # If we find a default value, convert it into a regular item and + # append it to the queue of items to process + my $default_item = {%$item}; + $default_item->{invert_macro} = 1; + $default_item->{pre} = delete $item->{def_pre}; + $default_item->{post} = delete $item->{def_post}; + $default_item->{type} = shift @$default; + $default_item->{value} = $default; + push @items, $default_item; + } else { + # It can be "not found" unless it's the default (invert the macro) + # or the "macro" is an empty string (ie no macro) + push @notfound, $item unless $item->{invert_macro} + or !$self->macro_to_ifdef($self->macro_from_item($item)); + } + + if ($item->{pre} or $item->{post} or $item->{not_constant} + or $type_is_a_problem{$item->{type}}) { + push @trouble, $item; + } else { + push @{$found{$item->{type}}}, $item; + } + } + # use Data::Dumper; print Dumper \%found; + (\%found, \@notfound, \@trouble); +} + +sub boottime_iterator { + my ($self, $type, $iterator, $hash, $subname) = @_; + my $extractor = $type_from_struct{$type}; + die "Can't find extractor code for type $type" + unless defined $extractor; + my $generator = $type_to_sv{$type}; + die "Can't find generator code for type $type" + unless defined $generator; + + my $athx = $self->C_constant_prefix_param(); + + return sprintf <<"EOBOOT", &$generator(&$extractor($iterator)); + while ($iterator->name) { + $subname($athx $hash, $iterator->name, + $iterator->namelen, %s); + ++$iterator; + } +EOBOOT +} + +sub name_len_value_macro { + my ($self, $item) = @_; + my $name = $item->{name}; + my $value = $item->{value}; + $value = $item->{name} unless defined $value; + + my $namelen = length $name; + if ($name =~ tr/\0-\377// != $namelen) { + # the hash API signals UTF-8 by passing the length negated. + utf8::encode($name); + $namelen = -length $name; + } + $name = C_stringify($name); + + my $macro = $self->macro_from_item($item); + ($name, $namelen, $value, $macro); +} + +sub WriteConstants { + my $self = shift; + my $ARGS = {@_}; + + my ($c_fh, $xs_fh, $c_subname, $xs_subname, $default_type, $package) + = @{$ARGS}{qw(C_FH XS_FH C_SUBNAME XS_SUBNAME DEFAULT_TYPE NAME)}; + + my $options = $ARGS->{PROXYSUBS}; + $options = {} unless ref $options; + my $explosives = $options->{croak_on_read}; + + $xs_subname ||= 'constant'; + + # If anyone is insane enough to suggest a package name containing % + my $package_sprintf_safe = $package; + $package_sprintf_safe =~ s/%/%%/g; + + # All the types we see + my $what = {}; + # A hash to lookup items with. + my $items = {}; + + my @items = $self->normalise_items ({disable_utf8_duplication => 1}, + $default_type, $what, $items, + @{$ARGS->{NAMES}}); + + # Partition the values by type. Also include any defaults in here + # Everything that doesn't have a default needs alternative code for + # "I'm missing" + # And everything that has pre or post code ends up in a private block + my ($found, $notfound, $trouble) + = $self->partition_names($default_type, @items); + + my $pthx = $self->C_constant_prefix_param_defintion(); + my $athx = $self->C_constant_prefix_param(); + my $symbol_table = C_stringify($package) . '::'; + + my $can_do_pcs = $] >= 5.009; + my $cast_CONSTSUB = $] < 5.010 ? '(char *)' : ''; + + print $c_fh $self->header(), <<"EOADD"; +static void +${c_subname}_add_symbol($pthx HV *hash, const char *name, I32 namelen, SV *value) { +EOADD + if (!$can_do_pcs) { + print $c_fh <<'EO_NOPCS'; + if (namelen == namelen) { +EO_NOPCS + } else { + print $c_fh <<"EO_PCS"; + SV **sv = hv_fetch(hash, name, namelen, TRUE); + if (!sv) { + Perl_croak($athx "Couldn't add key '%s' to %%$package_sprintf_safe\::", + name); + } + if (SvOK(*sv) || SvTYPE(*sv) == SVt_PVGV) { + /* Someone has been here before us - have to make a real sub. */ +EO_PCS + } + # This piece of code is common to both + print $c_fh <<"EOADD"; + newCONSTSUB(hash, ${cast_CONSTSUB}name, value); +EOADD + if ($can_do_pcs) { + print $c_fh <<'EO_PCS'; + } else { + SvUPGRADE(*sv, SVt_RV); + SvRV_set(*sv, value); + SvROK_on(*sv); + SvREADONLY_on(value); + } +EO_PCS + } else { + print $c_fh <<'EO_NOPCS'; + } +EO_NOPCS + } + print $c_fh <<'EOADD'; +} + +EOADD + + print $c_fh $explosives ? <<"EXPLODE" : "\n"; + +static int +Im_sorry_Dave(pTHX_ SV *sv, MAGIC *mg) +{ + PERL_UNUSED_ARG(mg); + Perl_croak(aTHX_ + "Your vendor has not defined $package_sprintf_safe macro %"SVf + " used", sv); + NORETURN_FUNCTION_END; +} + +static MGVTBL not_defined_vtbl = { + Im_sorry_Dave, /* get - I'm afraid I can't do that */ + Im_sorry_Dave, /* set */ + 0, /* len */ + 0, /* clear */ + 0, /* free */ + 0, /* copy */ + 0, /* dup */ +}; + +EXPLODE + +{ + my $key = $symbol_table; + # Just seems tidier (and slightly more space efficient) not to have keys + # such as Fcntl:: + $key =~ s/::$//; + my $key_len = length $key; + + print $c_fh <<"MISSING"; + +#ifndef SYMBIAN + +/* Store a hash of all symbols missing from the package. To avoid trampling on + the package namespace (uninvited) put each package's hash in our namespace. + To avoid creating lots of typeblogs and symbol tables for sub-packages, put + each package's hash into one hash in our namespace. */ + +static HV * +get_missing_hash(pTHX) { + HV *const parent + = get_hv("ExtUtils::Constant::ProxySubs::Missing", GVf_MULTI); + /* We could make a hash of hashes directly, but this would confuse anything + at Perl space that looks at us, and as we're visible in Perl space, + best to play nice. */ + SV *const *const ref + = hv_fetch(parent, "$key", $key_len, TRUE); + HV *new_hv; + + if (!ref) + return NULL; + + if (SvROK(*ref)) + return (HV*) SvRV(*ref); + + new_hv = newHV(); + SvUPGRADE(*ref, SVt_RV); + SvRV_set(*ref, (SV *)new_hv); + SvROK_on(*ref); + return new_hv; +} + +#endif + +MISSING + +} + + print $xs_fh <<"EOBOOT"; +BOOT: + { +#ifdef dTHX + dTHX; +#endif + HV *symbol_table = get_hv("$symbol_table", GV_ADD); +#ifndef SYMBIAN + HV *${c_subname}_missing; +#endif +EOBOOT + + my %iterator; + + $found->{''} + = [map {{%$_, type=>'', invert_macro => 1}} @$notfound]; + + foreach my $type (sort keys %$found) { + my $struct = $type_to_struct{$type}; + my $type_to_value = $self->type_to_C_value($type); + my $number_of_args = $type_num_args{$type}; + die "Can't find structure definition for type $type" + unless defined $struct; + + my $struct_type = $type ? lc($type) . '_s' : 'notfound_s'; + print $c_fh "struct $struct_type $struct;\n"; + + my $array_name = 'values_for_' . ($type ? lc $type : 'notfound'); + print $xs_fh <<"EOBOOT"; + + static const struct $struct_type $array_name\[] = + { +EOBOOT + + + foreach my $item (@{$found->{$type}}) { + my ($name, $namelen, $value, $macro) + = $self->name_len_value_macro($item); + + my $ifdef = $self->macro_to_ifdef($macro); + if (!$ifdef && $item->{invert_macro}) { + carp("Attempting to supply a default for '$name' which has no conditional macro"); + next; + } + print $xs_fh $ifdef; + if ($item->{invert_macro}) { + print $xs_fh + " /* This is the default value: */\n" if $type; + print $xs_fh "#else\n"; + } + print $xs_fh " { ", join (', ', "\"$name\"", $namelen, + &$type_to_value($value)), " },\n", + $self->macro_to_endif($macro); + } + + + # Terminate the list with a NULL + print $xs_fh " { NULL, 0", (", 0" x $number_of_args), " } };\n"; + + $iterator{$type} = "value_for_" . ($type ? lc $type : 'notfound'); + + print $xs_fh <<"EOBOOT"; + const struct $struct_type *$iterator{$type} = $array_name; +EOBOOT + } + + delete $found->{''}; + + print $xs_fh <<"EOBOOT"; +#ifndef SYMBIAN + ${c_subname}_missing = get_missing_hash(aTHX); +#endif +EOBOOT + + my $add_symbol_subname = $c_subname . '_add_symbol'; + foreach my $type (sort keys %$found) { + print $xs_fh $self->boottime_iterator($type, $iterator{$type}, + 'symbol_table', + $add_symbol_subname); + } + + print $xs_fh <<"EOBOOT"; + while (value_for_notfound->name) { +EOBOOT + + print $xs_fh $explosives ? <<"EXPLODE" : << "DONT"; + SV *tripwire = newSV(0); + + sv_magicext(tripwire, 0, PERL_MAGIC_ext, ¬_defined_vtbl, 0, 0); + SvPV_set(tripwire, (char *)value_for_notfound->name); + if(value_for_notfound->namelen >= 0) { + SvCUR_set(tripwire, value_for_notfound->namelen); + } else { + SvCUR_set(tripwire, -value_for_notfound->namelen); + SvUTF8_on(tripwire); + } + SvPOKp_on(tripwire); + SvREADONLY_on(tripwire); + assert(SvLEN(tripwire) == 0); + + $add_symbol_subname($athx symbol_table, value_for_notfound->name, + value_for_notfound->namelen, tripwire); +EXPLODE + + /* Need to add prototypes, else parsing will vary by platform. */ + SV **sv = hv_fetch(symbol_table, value_for_notfound->name, + value_for_notfound->namelen, TRUE); + if (!sv) { + Perl_croak($athx + "Couldn't add key '%s' to %%$package_sprintf_safe\::", + value_for_notfound->name); + } + if (!SvOK(*sv) && SvTYPE(*sv) != SVt_PVGV) { + /* Nothing was here before, so mark a prototype of "" */ + sv_setpvn(*sv, "", 0); + } else if (SvPOK(*sv) && SvCUR(*sv) == 0) { + /* There is already a prototype of "" - do nothing */ + } else { + /* Someone has been here before us - have to make a real + typeglob. */ + /* It turns out to be incredibly hard to deal with all the + corner cases of sub foo (); and reporting errors correctly, + so lets cheat a bit. Start with a constant subroutine */ + CV *cv = newCONSTSUB(symbol_table, + ${cast_CONSTSUB}value_for_notfound->name, + &PL_sv_yes); + /* and then turn it into a non constant declaration only. */ + SvREFCNT_dec(CvXSUBANY(cv).any_ptr); + CvCONST_off(cv); + CvXSUB(cv) = NULL; + CvXSUBANY(cv).any_ptr = NULL; + } +#ifndef SYMBIAN + if (!hv_store(${c_subname}_missing, value_for_notfound->name, + value_for_notfound->namelen, &PL_sv_yes, 0)) + Perl_croak($athx "Couldn't add key '%s' to missing_hash", + value_for_notfound->name); +#endif +DONT + + print $xs_fh <<"EOBOOT"; + + ++value_for_notfound; + } +EOBOOT + + foreach my $item (@$trouble) { + my ($name, $namelen, $value, $macro) + = $self->name_len_value_macro($item); + my $ifdef = $self->macro_to_ifdef($macro); + my $type = $item->{type}; + my $type_to_value = $self->type_to_C_value($type); + + print $xs_fh $ifdef; + if ($item->{invert_macro}) { + print $xs_fh + " /* This is the default value: */\n" if $type; + print $xs_fh "#else\n"; + } + my $generator = $type_to_sv{$type}; + die "Can't find generator code for type $type" + unless defined $generator; + + print $xs_fh " {\n"; + # We need to use a temporary value because some really troublesome + # items use C pre processor directives in their values, and in turn + # these don't fit nicely in the macro-ised generator functions + my $counter = 0; + printf $xs_fh " %s temp%d;\n", $_, $counter++ + foreach @{$type_temporary{$type}}; + + print $xs_fh " $item->{pre}\n" if $item->{pre}; + + # And because the code in pre might be both declarations and + # statements, we can't declare and assign to the temporaries in one. + $counter = 0; + printf $xs_fh " temp%d = %s;\n", $counter++, $_ + foreach &$type_to_value($value); + + my @tempvarnames = map {sprintf 'temp%d', $_} 0 .. $counter - 1; + printf $xs_fh <<"EOBOOT", $name, &$generator(@tempvarnames); + ${c_subname}_add_symbol($athx symbol_table, "%s", + $namelen, %s); +EOBOOT + print $xs_fh " $item->{post}\n" if $item->{post}; + print $xs_fh " }\n"; + + print $xs_fh $self->macro_to_endif($macro); + } + + print $xs_fh <<EOBOOT; + /* As we've been creating subroutines, we better invalidate any cached + methods */ + ++PL_sub_generation; + } +EOBOOT + + print $xs_fh $explosives ? <<"EXPLODE" : <<"DONT"; + +void +$xs_subname(sv) + INPUT: + SV * sv; + PPCODE: + sv = newSVpvf("Your vendor has not defined $package_sprintf_safe macro %" SVf + ", used", sv); + PUSHs(sv_2mortal(sv)); +EXPLODE + +void +$xs_subname(sv) + PREINIT: + STRLEN len; + INPUT: + SV * sv; + const char * s = SvPV(sv, len); + PPCODE: +#ifdef SYMBIAN + sv = newSVpvf("%"SVf" is not a valid $package_sprintf_safe macro", sv); +#else + HV *${c_subname}_missing = get_missing_hash(aTHX); + if (hv_exists(${c_subname}_missing, s, SvUTF8(sv) ? -(I32)len : (I32)len)) { + sv = newSVpvf("Your vendor has not defined $package_sprintf_safe macro %" SVf + ", used", sv); + } else { + sv = newSVpvf("%"SVf" is not a valid $package_sprintf_safe macro", + sv); + } +#endif + PUSHs(sv_2mortal(sv)); +DONT + +} + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/Constant/Utils.pm b/Master/tlpkg/tlperl/lib/ExtUtils/Constant/Utils.pm new file mode 100644 index 00000000000..016507c72a6 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/Constant/Utils.pm @@ -0,0 +1,131 @@ +package ExtUtils::Constant::Utils; + +use strict; +use vars qw($VERSION @EXPORT_OK @ISA $is_perl56); +use Carp; + +@ISA = 'Exporter'; +@EXPORT_OK = qw(C_stringify perl_stringify); +$VERSION = '0.02'; + +$is_perl56 = ($] < 5.007 && $] > 5.005_50); + +=head1 NAME + +ExtUtils::Constant::Utils - helper functions for ExtUtils::Constant + +=head1 SYNOPSIS + + use ExtUtils::Constant::Utils qw (C_stringify); + $C_code = C_stringify $stuff; + +=head1 DESCRIPTION + +ExtUtils::Constant::Utils packages up utility subroutines used by +ExtUtils::Constant, ExtUtils::Constant::Base and derived classes. All its +functions are explicitly exportable. + +=head1 USAGE + +=over 4 + +=item C_stringify NAME + +A function which returns a 7 bit ASCII correctly \ escaped version of the +string passed suitable for C's "" or ''. It will die if passed Unicode +characters. + +=cut + +# Hopefully make a happy C identifier. +sub C_stringify { + local $_ = shift; + return unless defined $_; + # grr 5.6.1 + confess "Wide character in '$_' intended as a C identifier" + if tr/\0-\377// != length; + # grr 5.6.1 moreso because its regexps will break on data that happens to + # be utf8, which includes my 8 bit test cases. + $_ = pack 'C*', unpack 'U*', $_ . pack 'U*' if $is_perl56; + s/\\/\\\\/g; + s/([\"\'])/\\$1/g; # Grr. fix perl mode. + s/\n/\\n/g; # Ensure newlines don't end up in octal + s/\r/\\r/g; + s/\t/\\t/g; + s/\f/\\f/g; + s/\a/\\a/g; + if (ord('A') == 193) { # EBCDIC has no ^\0-\177 workalike. + s/([[:^print:]])/sprintf "\\%03o", ord $1/ge; + } else { + s/([^\0-\177])/sprintf "\\%03o", ord $1/ge; + } + unless ($] < 5.006) { + # This will elicit a warning on 5.005_03 about [: :] being reserved unless + # I cheat + my $cheat = '([[:^print:]])'; + s/$cheat/sprintf "\\%03o", ord $1/ge; + } else { + require POSIX; + s/([^A-Za-z0-9_])/POSIX::isprint($1) ? $1 : sprintf "\\%03o", ord $1/ge; + } + $_; +} + +=item perl_stringify NAME + +A function which returns a 7 bit ASCII correctly \ escaped version of the +string passed suitable for a perl "" string. + +=cut + +# Hopefully make a happy perl identifier. +sub perl_stringify { + local $_ = shift; + return unless defined $_; + s/\\/\\\\/g; + s/([\"\'])/\\$1/g; # Grr. fix perl mode. + s/\n/\\n/g; # Ensure newlines don't end up in octal + s/\r/\\r/g; + s/\t/\\t/g; + s/\f/\\f/g; + s/\a/\\a/g; + unless ($] < 5.006) { + if ($] > 5.007) { + if (ord('A') == 193) { # EBCDIC has no ^\0-\177 workalike. + s/([[:^print:]])/sprintf "\\x{%X}", ord $1/ge; + } else { + s/([^\0-\177])/sprintf "\\x{%X}", ord $1/ge; + } + } else { + # Grr 5.6.1. And I don't think I can use utf8; to force the regexp + # because 5.005_03 will fail. + # This is grim, but I also can't split on // + my $copy; + foreach my $index (0 .. length ($_) - 1) { + my $char = substr ($_, $index, 1); + $copy .= ($char le "\177") ? $char : sprintf "\\x{%X}", ord $char; + } + $_ = $copy; + } + # This will elicit a warning on 5.005_03 about [: :] being reserved unless + # I cheat + my $cheat = '([[:^print:]])'; + s/$cheat/sprintf "\\%03o", ord $1/ge; + } else { + # Turns out "\x{}" notation only arrived with 5.6 + s/([^\0-\177])/sprintf "\\x%02X", ord $1/ge; + require POSIX; + s/([^A-Za-z0-9_])/POSIX::isprint($1) ? $1 : sprintf "\\%03o", ord $1/ge; + } + $_; +} + +1; +__END__ + +=back + +=head1 AUTHOR + +Nicholas Clark <nick@ccl4.org> based on the code in C<h2xs> by Larry Wall and +others diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/Constant/XS.pm b/Master/tlpkg/tlperl/lib/ExtUtils/Constant/XS.pm new file mode 100644 index 00000000000..14eb8097146 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/Constant/XS.pm @@ -0,0 +1,259 @@ +package ExtUtils::Constant::XS; + +use strict; +use vars qw($VERSION %XS_Constant %XS_TypeSet @ISA @EXPORT_OK $is_perl56); +use Carp; +use ExtUtils::Constant::Utils 'perl_stringify'; +require ExtUtils::Constant::Base; + + +@ISA = qw(ExtUtils::Constant::Base Exporter); +@EXPORT_OK = qw(%XS_Constant %XS_TypeSet); + +$VERSION = '0.03'; + +$is_perl56 = ($] < 5.007 && $] > 5.005_50); + +=head1 NAME + +ExtUtils::Constant::XS - generate C code for XS modules' constants. + +=head1 SYNOPSIS + + require ExtUtils::Constant::XS; + +=head1 DESCRIPTION + +ExtUtils::Constant::XS overrides ExtUtils::Constant::Base to generate C +code for XS modules' constants. + +=head1 BUGS + +Nothing is documented. + +Probably others. + +=head1 AUTHOR + +Nicholas Clark <nick@ccl4.org> based on the code in C<h2xs> by Larry Wall and +others + +=cut + +# '' is used as a flag to indicate non-ascii macro names, and hence the need +# to pass in the utf8 on/off flag. +%XS_Constant = ( + '' => '', + IV => 'PUSHi(iv)', + UV => 'PUSHu((UV)iv)', + NV => 'PUSHn(nv)', + PV => 'PUSHp(pv, strlen(pv))', + PVN => 'PUSHp(pv, iv)', + SV => 'PUSHs(sv)', + YES => 'PUSHs(&PL_sv_yes)', + NO => 'PUSHs(&PL_sv_no)', + UNDEF => '', # implicit undef +); + +%XS_TypeSet = ( + IV => '*iv_return = ', + UV => '*iv_return = (IV)', + NV => '*nv_return = ', + PV => '*pv_return = ', + PVN => ['*pv_return = ', '*iv_return = (IV)'], + SV => '*sv_return = ', + YES => undef, + NO => undef, + UNDEF => undef, +); + +sub header { + my $start = 1; + my @lines; + push @lines, "#define PERL_constant_NOTFOUND\t$start\n"; $start++; + push @lines, "#define PERL_constant_NOTDEF\t$start\n"; $start++; + foreach (sort keys %XS_Constant) { + next if $_ eq ''; + push @lines, "#define PERL_constant_IS$_\t$start\n"; $start++; + } + push @lines, << 'EOT'; + +#ifndef NVTYPE +typedef double NV; /* 5.6 and later define NVTYPE, and typedef NV to it. */ +#endif +#ifndef aTHX_ +#define aTHX_ /* 5.6 or later define this for threading support. */ +#endif +#ifndef pTHX_ +#define pTHX_ /* 5.6 or later define this for threading support. */ +#endif +EOT + + return join '', @lines; +} + +sub valid_type { + my ($self, $type) = @_; + return exists $XS_TypeSet{$type}; +} + +# This might actually be a return statement +sub assignment_clause_for_type { + my $self = shift; + my $args = shift; + my $type = $args->{type}; + my $typeset = $XS_TypeSet{$type}; + if (ref $typeset) { + die "Type $type is aggregate, but only single value given" + if @_ == 1; + return map {"$typeset->[$_]$_[$_];"} 0 .. $#$typeset; + } elsif (defined $typeset) { + confess "Aggregate value given for type $type" + if @_ > 1; + return "$typeset$_[0];"; + } + return (); +} + +sub return_statement_for_type { + my ($self, $type) = @_; + # In the future may pass in an options hash + $type = $type->{type} if ref $type; + "return PERL_constant_IS$type;"; +} + +sub return_statement_for_notdef { + # my ($self) = @_; + "return PERL_constant_NOTDEF;"; +} + +sub return_statement_for_notfound { + # my ($self) = @_; + "return PERL_constant_NOTFOUND;"; +} + +sub default_type { + 'IV'; +} + +sub macro_from_name { + my ($self, $item) = @_; + my $macro = $item->{name}; + $macro = $item->{value} unless defined $macro; + $macro; +} + +sub macro_from_item { + my ($self, $item) = @_; + my $macro = $item->{macro}; + $macro = $self->macro_from_name($item) unless defined $macro; + $macro; +} + +# Keep to the traditional perl source macro +sub memEQ { + "memEQ"; +} + +sub params { + my ($self, $what) = @_; + foreach (sort keys %$what) { + warn "ExtUtils::Constant doesn't know how to handle values of type $_" unless defined $XS_Constant{$_}; + } + my $params = {}; + $params->{''} = 1 if $what->{''}; + $params->{IV} = 1 if $what->{IV} || $what->{UV} || $what->{PVN}; + $params->{NV} = 1 if $what->{NV}; + $params->{PV} = 1 if $what->{PV} || $what->{PVN}; + $params->{SV} = 1 if $what->{SV}; + return $params; +} + + +sub C_constant_prefix_param { + "aTHX_ "; +} + +sub C_constant_prefix_param_defintion { + "pTHX_ "; +} + +sub namelen_param_definition { + 'STRLEN ' . $_[0] -> namelen_param; +} + +sub C_constant_other_params_defintion { + my ($self, $params) = @_; + my $body = ''; + $body .= ", int utf8" if $params->{''}; + $body .= ", IV *iv_return" if $params->{IV}; + $body .= ", NV *nv_return" if $params->{NV}; + $body .= ", const char **pv_return" if $params->{PV}; + $body .= ", SV **sv_return" if $params->{SV}; + $body; +} + +sub C_constant_other_params { + my ($self, $params) = @_; + my $body = ''; + $body .= ", utf8" if $params->{''}; + $body .= ", iv_return" if $params->{IV}; + $body .= ", nv_return" if $params->{NV}; + $body .= ", pv_return" if $params->{PV}; + $body .= ", sv_return" if $params->{SV}; + $body; +} + +sub dogfood { + my ($self, $args, @items) = @_; + my ($package, $subname, $default_type, $what, $indent, $breakout) = + @{$args}{qw(package subname default_type what indent breakout)}; + my $result = <<"EOT"; + /* When generated this function returned values for the list of names given + in this section of perl code. Rather than manually editing these functions + to add or remove constants, which would result in this comment and section + of code becoming inaccurate, we recommend that you edit this section of + code, and use it to regenerate a new set of constant functions which you + then use to replace the originals. + + Regenerate these constant functions by feeding this entire source file to + perl -x + +#!$^X -w +use ExtUtils::Constant qw (constant_types C_constant XS_constant); + +EOT + $result .= $self->dump_names ({default_type=>$default_type, what=>$what, + indent=>0, declare_types=>1}, + @items); + $result .= <<'EOT'; + +print constant_types(), "\n"; # macro defs +EOT + $package = perl_stringify($package); + $result .= + "foreach (C_constant (\"$package\", '$subname', '$default_type', \$types, "; + # The form of the indent parameter isn't defined. (Yet) + if (defined $indent) { + require Data::Dumper; + $Data::Dumper::Terse=1; + $Data::Dumper::Terse=1; # Not used once. :-) + chomp ($indent = Data::Dumper::Dumper ($indent)); + $result .= $indent; + } else { + $result .= 'undef'; + } + $result .= ", $breakout" . ', @names) ) { + print $_, "\n"; # C constant subs +} +print "\n#### XS Section:\n"; +print XS_constant ("' . $package . '", $types); +__END__ + */ + +'; + + $result; +} + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/Embed.pm b/Master/tlpkg/tlperl/lib/ExtUtils/Embed.pm new file mode 100644 index 00000000000..24ae9092f52 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/Embed.pm @@ -0,0 +1,511 @@ +# $Id: Embed.pm,v 1.1.1.1 2002/01/16 19:27:19 schwern Exp $ +require 5.002; + +package ExtUtils::Embed; +require Exporter; +require FileHandle; +use Config; +use Getopt::Std; +use File::Spec; + +#Only when we need them +#require ExtUtils::MakeMaker; +#require ExtUtils::Liblist; + +use vars qw(@ISA @EXPORT $VERSION + @Extensions $Verbose $lib_ext + $opt_o $opt_s + ); +use strict; + +# This is not a dual-life module, so no need for development version numbers +$VERSION = '1.28'; + +@ISA = qw(Exporter); +@EXPORT = qw(&xsinit &ldopts + &ccopts &ccflags &ccdlflags &perl_inc + &xsi_header &xsi_protos &xsi_body); + +#let's have Miniperl borrow from us instead +#require ExtUtils::Miniperl; +#*canon = \&ExtUtils::Miniperl::canon; + +$Verbose = 0; +$lib_ext = $Config{lib_ext} || '.a'; + +sub is_cmd { $0 eq '-e' } + +sub my_return { + my $val = shift; + if(is_cmd) { + print $val; + } + else { + return $val; + } +} + +sub xsinit { + my($file, $std, $mods) = @_; + my($fh,@mods,%seen); + $file ||= "perlxsi.c"; + my $xsinit_proto = "pTHX"; + + if (@_) { + @mods = @$mods if $mods; + } + else { + getopts('o:s:'); + $file = $opt_o if defined $opt_o; + $std = $opt_s if defined $opt_s; + @mods = @ARGV; + } + $std = 1 unless scalar @mods; + + if ($file eq "STDOUT") { + $fh = \*STDOUT; + } + else { + $fh = new FileHandle "> $file"; + } + + push(@mods, static_ext()) if defined $std; + @mods = grep(!$seen{$_}++, @mods); + + print $fh &xsi_header(); + print $fh "EXTERN_C void xs_init ($xsinit_proto);\n\n"; + print $fh &xsi_protos(@mods); + + print $fh "\nEXTERN_C void\nxs_init($xsinit_proto)\n{\n"; + print $fh &xsi_body(@mods); + print $fh "}\n"; + +} + +sub xsi_header { + return <<EOF; +#include <EXTERN.h> +#include <perl.h> + +EOF +} + +sub xsi_protos { + my(@exts) = @_; + my(@retval,%seen); + my $boot_proto = "pTHX_ CV* cv"; + foreach $_ (@exts){ + my($pname) = canon('/', $_); + my($mname, $cname); + ($mname = $pname) =~ s!/!::!g; + ($cname = $pname) =~ s!/!__!g; + my($ccode) = "EXTERN_C void boot_${cname} ($boot_proto);\n"; + next if $seen{$ccode}++; + push(@retval, $ccode); + } + return join '', @retval; +} + +sub xsi_body { + my(@exts) = @_; + my($pname,@retval,%seen); + my($dl) = canon('/','DynaLoader'); + push(@retval, "\tchar *file = __FILE__;\n"); + push(@retval, "\tdXSUB_SYS;\n") if $] > 5.002; + push(@retval, "\n"); + + foreach $_ (@exts){ + my($pname) = canon('/', $_); + my($mname, $cname, $ccode); + ($mname = $pname) =~ s!/!::!g; + ($cname = $pname) =~ s!/!__!g; + if ($pname eq $dl){ + # Must NOT install 'DynaLoader::boot_DynaLoader' as 'bootstrap'! + # boot_DynaLoader is called directly in DynaLoader.pm + $ccode = "\t/* DynaLoader is a special case */\n\tnewXS(\"${mname}::boot_${cname}\", boot_${cname}, file);\n"; + push(@retval, $ccode) unless $seen{$ccode}++; + } else { + $ccode = "\tnewXS(\"${mname}::bootstrap\", boot_${cname}, file);\n"; + push(@retval, $ccode) unless $seen{$ccode}++; + } + } + return join '', @retval; +} + +sub static_ext { + unless (scalar @Extensions) { + my $static_ext = $Config{static_ext}; + $static_ext =~ s/^\s+//; + @Extensions = sort split /\s+/, $static_ext; + unshift @Extensions, qw(DynaLoader); + } + @Extensions; +} + +sub _escape { + my $arg = shift; + $$arg =~ s/([\(\)])/\\$1/g; +} + +sub _ldflags { + my $ldflags = $Config{ldflags}; + _escape(\$ldflags); + return $ldflags; +} + +sub _ccflags { + my $ccflags = $Config{ccflags}; + _escape(\$ccflags); + return $ccflags; +} + +sub _ccdlflags { + my $ccdlflags = $Config{ccdlflags}; + _escape(\$ccdlflags); + return $ccdlflags; +} + +sub ldopts { + require ExtUtils::MakeMaker; + require ExtUtils::Liblist; + my($std,$mods,$link_args,$path) = @_; + my(@mods,@link_args,@argv); + my($dllib,$config_libs,@potential_libs,@path); + local($") = ' ' unless $" eq ' '; + if (scalar @_) { + @link_args = @$link_args if $link_args; + @mods = @$mods if $mods; + } + else { + @argv = @ARGV; + #hmm + while($_ = shift @argv) { + /^-std$/ && do { $std = 1; next; }; + /^--$/ && do { @link_args = @argv; last; }; + /^-I(.*)/ && do { $path = $1 || shift @argv; next; }; + push(@mods, $_); + } + } + $std = 1 unless scalar @link_args; + my $sep = $Config{path_sep} || ':'; + @path = $path ? split(/\Q$sep/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; + # makemaker includes std libs on windows by default + if ($^O ne 'MSWin32' and defined($std)) { + push(@potential_libs, $Config{perllibs}); + } + + push(@mods, static_ext()) if $std; + + my($mod,@ns,$root,$sub,$extra,$archive,@archives); + print STDERR "Searching (@path) for archives\n" if $Verbose; + foreach $mod (@mods) { + @ns = split(/::|\/|\\/, $mod); + $sub = $ns[-1]; + $root = File::Spec->catdir(@ns); + + print STDERR "searching for '$sub${lib_ext}'\n" if $Verbose; + foreach (@path) { + next unless -e ($archive = File::Spec->catdir($_,"auto",$root,"$sub$lib_ext")); + push @archives, $archive; + if(-e ($extra = File::Spec->catdir($_,"auto",$root,"extralibs.ld"))) { + local(*FH); + if(open(FH, $extra)) { + my($libs) = <FH>; chomp $libs; + push @potential_libs, split /\s+/, $libs; + } + else { + warn "Couldn't open '$extra'"; + } + } + last; + } + } + #print STDERR "\@potential_libs = @potential_libs\n"; + + my $libperl; + if ($^O eq 'MSWin32') { + $libperl = $Config{libperl}; + } + elsif ($^O eq 'os390' && $Config{usedl}) { + # Nothing for OS/390 (z/OS) dynamic. + } else { + $libperl = (grep(/^-l\w*perl\w*$/, @link_args))[0] + || ($Config{libperl} =~ /^lib(\w+)(\Q$lib_ext\E|\.\Q$Config{dlext}\E)$/ + ? "-l$1" : '') + || "-lperl"; + } + + my $lpath = File::Spec->catdir($Config{archlibexp}, 'CORE'); + $lpath = qq["$lpath"] if $^O eq 'MSWin32'; + my($extralibs, $bsloadlibs, $ldloadlibs, $ld_run_path) = + MM->ext(join ' ', "-L$lpath", $libperl, @potential_libs); + + my $ld_or_bs = $bsloadlibs || $ldloadlibs; + print STDERR "bs: $bsloadlibs ** ld: $ldloadlibs" if $Verbose; + my $ccdlflags = _ccdlflags(); + my $ldflags = _ldflags(); + my $linkage = "$ccdlflags $ldflags @archives $ld_or_bs"; + print STDERR "ldopts: '$linkage'\n" if $Verbose; + + return $linkage if scalar @_; + my_return("$linkage\n"); +} + +sub ccflags { + my $ccflags = _ccflags(); + my_return(" $ccflags "); +} + +sub ccdlflags { + my $ccdlflags = _ccdlflags(); + my_return(" $ccdlflags "); +} + +sub perl_inc { + my $dir = File::Spec->catdir($Config{archlibexp}, 'CORE'); + $dir = qq["$dir"] if $^O eq 'MSWin32'; + my_return(" -I$dir "); +} + +sub ccopts { + ccflags . perl_inc; +} + +sub canon { + my($as, @ext) = @_; + foreach(@ext) { + # might be X::Y or lib/auto/X/Y/Y.a + next if s!::!/!g; + s:^(lib|ext)/(auto/)?::; + s:/\w+\.\w+$::; + } + map(s:/:$as:, @ext) if ($as ne '/'); + @ext; +} + +__END__ + +=head1 NAME + +ExtUtils::Embed - Utilities for embedding Perl in C/C++ applications + +=head1 SYNOPSIS + + + perl -MExtUtils::Embed -e xsinit + perl -MExtUtils::Embed -e ccopts + perl -MExtUtils::Embed -e ldopts + +=head1 DESCRIPTION + +ExtUtils::Embed provides utility functions for embedding a Perl interpreter +and extensions in your C/C++ applications. +Typically, an application B<Makefile> will invoke ExtUtils::Embed +functions while building your application. + +=head1 @EXPORT + +ExtUtils::Embed exports the following functions: + +xsinit(), ldopts(), ccopts(), perl_inc(), ccflags(), +ccdlflags(), xsi_header(), xsi_protos(), xsi_body() + +=head1 FUNCTIONS + +=over 4 + +=item xsinit() + +Generate C/C++ code for the XS initializer function. + +When invoked as C<`perl -MExtUtils::Embed -e xsinit --`> +the following options are recognized: + +B<-o> E<lt>output filenameE<gt> (Defaults to B<perlxsi.c>) + +B<-o STDOUT> will print to STDOUT. + +B<-std> (Write code for extensions that are linked with the current Perl.) + +Any additional arguments are expected to be names of modules +to generate code for. + +When invoked with parameters the following are accepted and optional: + +C<xsinit($filename,$std,[@modules])> + +Where, + +B<$filename> is equivalent to the B<-o> option. + +B<$std> is boolean, equivalent to the B<-std> option. + +B<[@modules]> is an array ref, same as additional arguments mentioned above. + +=item Examples + + + perl -MExtUtils::Embed -e xsinit -- -o xsinit.c Socket + + +This will generate code with an B<xs_init> function that glues the perl B<Socket::bootstrap> function +to the C B<boot_Socket> function and writes it to a file named F<xsinit.c>. + +Note that B<DynaLoader> is a special case where it must call B<boot_DynaLoader> directly. + + perl -MExtUtils::Embed -e xsinit + + +This will generate code for linking with B<DynaLoader> and +each static extension found in B<$Config{static_ext}>. +The code is written to the default file name B<perlxsi.c>. + + + perl -MExtUtils::Embed -e xsinit -- -o xsinit.c -std DBI DBD::Oracle + + +Here, code is written for all the currently linked extensions along with code +for B<DBI> and B<DBD::Oracle>. + +If you have a working B<DynaLoader> then there is rarely any need to statically link in any +other extensions. + +=item ldopts() + +Output arguments for linking the Perl library and extensions to your +application. + +When invoked as C<`perl -MExtUtils::Embed -e ldopts --`> +the following options are recognized: + +B<-std> + +Output arguments for linking the Perl library and any extensions linked +with the current Perl. + +B<-I> E<lt>path1:path2E<gt> + +Search path for ModuleName.a archives. +Default path is B<@INC>. +Library archives are expected to be found as +B</some/path/auto/ModuleName/ModuleName.a> +For example, when looking for B<Socket.a> relative to a search path, +we should find B<auto/Socket/Socket.a> + +When looking for B<DBD::Oracle> relative to a search path, +we should find B<auto/DBD/Oracle/Oracle.a> + +Keep in mind that you can always supply B</my/own/path/ModuleName.a> +as an additional linker argument. + +B<--> E<lt>list of linker argsE<gt> + +Additional linker arguments to be considered. + +Any additional arguments found before the B<--> token +are expected to be names of modules to generate code for. + +When invoked with parameters the following are accepted and optional: + +C<ldopts($std,[@modules],[@link_args],$path)> + +Where: + +B<$std> is boolean, equivalent to the B<-std> option. + +B<[@modules]> is equivalent to additional arguments found before the B<--> token. + +B<[@link_args]> is equivalent to arguments found after the B<--> token. + +B<$path> is equivalent to the B<-I> option. + +In addition, when ldopts is called with parameters, it will return the argument string +rather than print it to STDOUT. + +=item Examples + + + perl -MExtUtils::Embed -e ldopts + + +This will print arguments for linking with B<libperl> and +extensions found in B<$Config{static_ext}>. This includes libraries +found in B<$Config{libs}> and the first ModuleName.a library +for each extension that is found by searching B<@INC> or the path +specified by the B<-I> option. +In addition, when ModuleName.a is found, additional linker arguments +are picked up from the B<extralibs.ld> file in the same directory. + + + perl -MExtUtils::Embed -e ldopts -- -std Socket + + +This will do the same as the above example, along with printing additional arguments for linking with the B<Socket> extension. + + perl -MExtUtils::Embed -e ldopts -- -std Msql -- -L/usr/msql/lib -lmsql + +Any arguments after the second '--' token are additional linker +arguments that will be examined for potential conflict. If there is no +conflict, the additional arguments will be part of the output. + + +=item perl_inc() + +For including perl header files this function simply prints: + + -I$Config{archlibexp}/CORE + +So, rather than having to say: + + perl -MConfig -e 'print "-I$Config{archlibexp}/CORE"' + +Just say: + + perl -MExtUtils::Embed -e perl_inc + +=item ccflags(), ccdlflags() + +These functions simply print $Config{ccflags} and $Config{ccdlflags} + +=item ccopts() + +This function combines perl_inc(), ccflags() and ccdlflags() into one. + +=item xsi_header() + +This function simply returns a string defining the same B<EXTERN_C> macro as +B<perlmain.c> along with #including B<perl.h> and B<EXTERN.h>. + +=item xsi_protos(@modules) + +This function returns a string of B<boot_$ModuleName> prototypes for each @modules. + +=item xsi_body(@modules) + +This function returns a string of calls to B<newXS()> that glue the module B<bootstrap> +function to B<boot_ModuleName> for each @modules. + +B<xsinit()> uses the xsi_* functions to generate most of its code. + +=back + +=head1 EXAMPLES + +For examples on how to use B<ExtUtils::Embed> for building C/C++ applications +with embedded perl, see L<perlembed>. + +=head1 SEE ALSO + +L<perlembed> + +=head1 AUTHOR + +Doug MacEachern E<lt>F<dougm@osf.org>E<gt> + +Based on ideas from Tim Bunce E<lt>F<Tim.Bunce@ig.co.uk>E<gt> and +B<minimod.pl> by Andreas Koenig E<lt>F<k@anna.in-berlin.de>E<gt> and Tim Bunce. + +=cut + diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/Install.pm b/Master/tlpkg/tlperl/lib/ExtUtils/Install.pm new file mode 100644 index 00000000000..da583650fdf --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/Install.pm @@ -0,0 +1,1365 @@ +package ExtUtils::Install; +use strict; + +use vars qw(@ISA @EXPORT $VERSION $MUST_REBOOT %Config); + +use AutoSplit; +use Carp (); +use Config qw(%Config); +use Cwd qw(cwd); +use Exporter; +use ExtUtils::Packlist; +use File::Basename qw(dirname); +use File::Compare qw(compare); +use File::Copy; +use File::Find qw(find); +use File::Path; +use File::Spec; + + +@ISA = ('Exporter'); +@EXPORT = ('install','uninstall','pm_to_blib', 'install_default'); + +=pod + +=head1 NAME + +ExtUtils::Install - install files from here to there + +=head1 SYNOPSIS + + use ExtUtils::Install; + + install({ 'blib/lib' => 'some/install/dir' } ); + + uninstall($packlist); + + pm_to_blib({ 'lib/Foo/Bar.pm' => 'blib/lib/Foo/Bar.pm' }); + +=head1 VERSION + +1.55 + +=cut + +$VERSION = '1.55'; # <---- dont forget to update the POD section just above this line! +$VERSION = eval $VERSION; + +=pod + +=head1 DESCRIPTION + +Handles the installing and uninstalling of perl modules, scripts, man +pages, etc... + +Both install() and uninstall() are specific to the way +ExtUtils::MakeMaker handles the installation and deinstallation of +perl modules. They are not designed as general purpose tools. + +On some operating systems such as Win32 installation may not be possible +until after a reboot has occured. This can have varying consequences: +removing an old DLL does not impact programs using the new one, but if +a new DLL cannot be installed properly until reboot then anything +depending on it must wait. The package variable + + $ExtUtils::Install::MUST_REBOOT + +is used to store this status. + +If this variable is true then such an operation has occured and +anything depending on this module cannot proceed until a reboot +has occured. + +If this value is defined but false then such an operation has +ocurred, but should not impact later operations. + +=begin _private + +=over + +=item _chmod($$;$) + +Wrapper to chmod() for debugging and error trapping. + +=item _warnonce(@) + +Warns about something only once. + +=item _choke(@) + +Dies with a special message. + +=back + +=end _private + +=cut + +my $Is_VMS = $^O eq 'VMS'; +my $Is_VMS_noefs = $Is_VMS; +my $Is_MacPerl = $^O eq 'MacOS'; +my $Is_Win32 = $^O eq 'MSWin32'; +my $Is_cygwin = $^O eq 'cygwin'; +my $CanMoveAtBoot = ($Is_Win32 || $Is_cygwin); + + if( $Is_VMS ) { + my $vms_unix_rpt; + my $vms_efs; + my $vms_case; + + if (eval { local $SIG{__DIE__}; require VMS::Feature; }) { + $vms_unix_rpt = VMS::Feature::current("filename_unix_report"); + $vms_efs = VMS::Feature::current("efs_charset"); + $vms_case = VMS::Feature::current("efs_case_preserve"); + } else { + my $unix_rpt = $ENV{'DECC$FILENAME_UNIX_REPORT'} || ''; + my $efs_charset = $ENV{'DECC$EFS_CHARSET'} || ''; + my $efs_case = $ENV{'DECC$EFS_CASE_PRESERVE'} || ''; + $vms_unix_rpt = $unix_rpt =~ /^[ET1]/i; + $vms_efs = $efs_charset =~ /^[ET1]/i; + $vms_case = $efs_case =~ /^[ET1]/i; + } + $Is_VMS_noefs = 0 if ($vms_efs); + } + + + +# *note* CanMoveAtBoot is only incidentally the same condition as below +# this needs not hold true in the future. +my $Has_Win32API_File = ($Is_Win32 || $Is_cygwin) + ? (eval {require Win32API::File; 1} || 0) + : 0; + + +my $Inc_uninstall_warn_handler; + +# install relative to here + +my $INSTALL_ROOT = $ENV{PERL_INSTALL_ROOT}; + +my $Curdir = File::Spec->curdir; +my $Updir = File::Spec->updir; + +sub _estr(@) { + return join "\n",'!' x 72,@_,'!' x 72,''; +} + +{my %warned; +sub _warnonce(@) { + my $first=shift; + my $msg=_estr "WARNING: $first",@_; + warn $msg unless $warned{$msg}++; +}} + +sub _choke(@) { + my $first=shift; + my $msg=_estr "ERROR: $first",@_; + Carp::croak($msg); +} + + +sub _chmod($$;$) { + my ( $mode, $item, $verbose )=@_; + $verbose ||= 0; + if (chmod $mode, $item) { + printf "chmod(0%o, %s)\n",$mode, $item if $verbose > 1; + } else { + my $err="$!"; + _warnonce sprintf "WARNING: Failed chmod(0%o, %s): %s\n", + $mode, $item, $err + if -e $item; + } +} + +=begin _private + +=over + +=item _move_file_at_boot( $file, $target, $moan ) + +OS-Specific, Win32/Cygwin + +Schedules a file to be moved/renamed/deleted at next boot. +$file should be a filespec of an existing file +$target should be a ref to an array if the file is to be deleted +otherwise it should be a filespec for a rename. If the file is existing +it will be replaced. + +Sets $MUST_REBOOT to 0 to indicate a deletion operation has occured +and sets it to 1 to indicate that a move operation has been requested. + +returns 1 on success, on failure if $moan is false errors are fatal. +If $moan is true then returns 0 on error and warns instead of dies. + +=end _private + +=cut + + + +sub _move_file_at_boot { #XXX OS-SPECIFIC + my ( $file, $target, $moan )= @_; + Carp::confess("Panic: Can't _move_file_at_boot on this platform!") + unless $CanMoveAtBoot; + + my $descr= ref $target + ? "'$file' for deletion" + : "'$file' for installation as '$target'"; + + if ( ! $Has_Win32API_File ) { + + my @msg=( + "Cannot schedule $descr at reboot.", + "Try installing Win32API::File to allow operations on locked files", + "to be scheduled during reboot. Or try to perform the operation by", + "hand yourself. (You may need to close other perl processes first)" + ); + if ( $moan ) { _warnonce(@msg) } else { _choke(@msg) } + return 0; + } + my $opts= Win32API::File::MOVEFILE_DELAY_UNTIL_REBOOT(); + $opts= $opts | Win32API::File::MOVEFILE_REPLACE_EXISTING() + unless ref $target; + + _chmod( 0666, $file ); + _chmod( 0666, $target ) unless ref $target; + + if (Win32API::File::MoveFileEx( $file, $target, $opts )) { + $MUST_REBOOT ||= ref $target ? 0 : 1; + return 1; + } else { + my @msg=( + "MoveFileEx $descr at reboot failed: $^E", + "You may try to perform the operation by hand yourself. ", + "(You may need to close other perl processes first).", + ); + if ( $moan ) { _warnonce(@msg) } else { _choke(@msg) } + } + return 0; +} + + +=begin _private + + +=item _unlink_or_rename( $file, $tryhard, $installing ) + +OS-Specific, Win32/Cygwin + +Tries to get a file out of the way by unlinking it or renaming it. On +some OS'es (Win32 based) DLL files can end up locked such that they can +be renamed but not deleted. Likewise sometimes a file can be locked such +that it cant even be renamed or changed except at reboot. To handle +these cases this routine finds a tempfile name that it can either rename +the file out of the way or use as a proxy for the install so that the +rename can happen later (at reboot). + + $file : the file to remove. + $tryhard : should advanced tricks be used for deletion + $installing : we are not merely deleting but we want to overwrite + +When $tryhard is not true if the unlink fails its fatal. When $tryhard +is true then the file is attempted to be renamed. The renamed file is +then scheduled for deletion. If the rename fails then $installing +governs what happens. If it is false the failure is fatal. If it is true +then an attempt is made to schedule installation at boot using a +temporary file to hold the new file. If this fails then a fatal error is +thrown, if it succeeds it returns the temporary file name (which will be +a derivative of the original in the same directory) so that the caller can +use it to install under. In all other cases of success returns $file. +On failure throws a fatal error. + +=back + +=end _private + +=cut + + + +sub _unlink_or_rename { #XXX OS-SPECIFIC + my ( $file, $tryhard, $installing )= @_; + + _chmod( 0666, $file ); + my $unlink_count = 0; + while (unlink $file) { $unlink_count++; } + return $file if $unlink_count > 0; + my $error="$!"; + + _choke("Cannot unlink '$file': $!") + unless $CanMoveAtBoot && $tryhard; + + my $tmp= "AAA"; + ++$tmp while -e "$file.$tmp"; + $tmp= "$file.$tmp"; + + warn "WARNING: Unable to unlink '$file': $error\n", + "Going to try to rename it to '$tmp'.\n"; + + if ( rename $file, $tmp ) { + warn "Rename succesful. Scheduling '$tmp'\nfor deletion at reboot.\n"; + # when $installing we can set $moan to true. + # IOW, if we cant delete the renamed file at reboot its + # not the end of the world. The other cases are more serious + # and need to be fatal. + _move_file_at_boot( $tmp, [], $installing ); + return $file; + } elsif ( $installing ) { + _warnonce("Rename failed: $!. Scheduling '$tmp'\nfor". + " installation as '$file' at reboot.\n"); + _move_file_at_boot( $tmp, $file ); + return $tmp; + } else { + _choke("Rename failed:$!", "Cannot procede."); + } + +} + + +=pod + +=head2 Functions + +=begin _private + +=over + +=item _get_install_skip + +Handles loading the INSTALL.SKIP file. Returns an array of patterns to use. + +=cut + + + +sub _get_install_skip { + my ( $skip, $verbose )= @_; + if ($ENV{EU_INSTALL_IGNORE_SKIP}) { + print "EU_INSTALL_IGNORE_SKIP is set, ignore skipfile settings\n" + if $verbose>2; + return []; + } + if ( ! defined $skip ) { + print "Looking for install skip list\n" + if $verbose>2; + for my $file ( 'INSTALL.SKIP', $ENV{EU_INSTALL_SITE_SKIPFILE} ) { + next unless $file; + print "\tChecking for $file\n" + if $verbose>2; + if (-e $file) { + $skip= $file; + last; + } + } + } + if ($skip && !ref $skip) { + print "Reading skip patterns from '$skip'.\n" + if $verbose; + if (open my $fh,$skip ) { + my @patterns; + while (<$fh>) { + chomp; + next if /^\s*(?:#|$)/; + print "\tSkip pattern: $_\n" if $verbose>3; + push @patterns, $_; + } + $skip= \@patterns; + } else { + warn "Can't read skip file:'$skip':$!\n"; + $skip=[]; + } + } elsif ( UNIVERSAL::isa($skip,'ARRAY') ) { + print "Using array for skip list\n" + if $verbose>2; + } elsif ($verbose) { + print "No skip list found.\n" + if $verbose>1; + $skip= []; + } + warn "Got @{[0+@$skip]} skip patterns.\n" + if $verbose>3; + return $skip +} + +=pod + +=item _have_write_access + +Abstract a -w check that tries to use POSIX::access() if possible. + +=cut + +{ + my $has_posix; + sub _have_write_access { + my $dir=shift; + unless (defined $has_posix) { + $has_posix= (!$Is_cygwin && !$Is_Win32 + && eval 'local $^W; require POSIX; 1') || 0; + } + if ($has_posix) { + return POSIX::access($dir, POSIX::W_OK()); + } else { + return -w $dir; + } + } +} + +=pod + +=item _can_write_dir(C<$dir>) + +Checks whether a given directory is writable, taking account +the possibility that the directory might not exist and would have to +be created first. + +Returns a list, containing: C<($writable, $determined_by, @create)> + +C<$writable> says whether whether the directory is (hypothetically) writable + +C<$determined_by> is the directory the status was determined from. It will be +either the C<$dir>, or one of its parents. + +C<@create> is a list of directories that would probably have to be created +to make the requested directory. It may not actually be correct on +relative paths with C<..> in them. But for our purposes it should work ok + +=cut + + +sub _can_write_dir { + my $dir=shift; + return + unless defined $dir and length $dir; + + my ($vol, $dirs, $file) = File::Spec->splitpath($dir,1); + my @dirs = File::Spec->splitdir($dirs); + unshift @dirs, File::Spec->curdir + unless File::Spec->file_name_is_absolute($dir); + + my $path=''; + my @make; + while (@dirs) { + if ($Is_VMS_noefs) { + # There is a bug in catdir that is fixed when the EFS character + # set is enabled, which requires this VMS specific code. + $dir = File::Spec->catdir($vol,@dirs); + } + else { + $dir = File::Spec->catdir(@dirs); + $dir = File::Spec->catpath($vol,$dir,'') + if defined $vol and length $vol; + } + next if ( $dir eq $path ); + if ( ! -e $dir ) { + unshift @make,$dir; + next; + } + if ( _have_write_access($dir) ) { + return 1,$dir,@make + } else { + return 0,$dir,@make + } + } continue { + pop @dirs; + } + return 0; +} + +=pod + +=item _mkpath($dir,$show,$mode,$verbose,$dry_run) + +Wrapper around File::Path::mkpath() to handle errors. + +If $verbose is true and >1 then additional diagnostics will be produced, also +this will force $show to true. + +If $dry_run is true then the directory will not be created but a check will be +made to see whether it would be possible to write to the directory, or that +it would be possible to create the directory. + +If $dry_run is not true dies if the directory can not be created or is not +writable. + +=cut + +sub _mkpath { + my ($dir,$show,$mode,$verbose,$dry_run)=@_; + if ( $verbose && $verbose > 1 && ! -d $dir) { + $show= 1; + printf "mkpath(%s,%d,%#o)\n", $dir, $show, $mode; + } + if (!$dry_run) { + if ( ! eval { File::Path::mkpath($dir,$show,$mode); 1 } ) { + _choke("Can't create '$dir'","$@"); + } + + } + my ($can,$root,@make)=_can_write_dir($dir); + if (!$can) { + my @msg=( + "Can't create '$dir'", + $root ? "Do not have write permissions on '$root'" + : "Unknown Error" + ); + if ($dry_run) { + _warnonce @msg; + } else { + _choke @msg; + } + } elsif ($show and $dry_run) { + print "$_\n" for @make; + } + +} + +=pod + +=item _copy($from,$to,$verbose,$dry_run) + +Wrapper around File::Copy::copy to handle errors. + +If $verbose is true and >1 then additional dignostics will be emitted. + +If $dry_run is true then the copy will not actually occur. + +Dies if the copy fails. + +=cut + + +sub _copy { + my ( $from, $to, $verbose, $dry_run)=@_; + if ($verbose && $verbose>1) { + printf "copy(%s,%s)\n", $from, $to; + } + if (!$dry_run) { + File::Copy::copy($from,$to) + or Carp::croak( _estr "ERROR: Cannot copy '$from' to '$to': $!" ); + } +} + +=pod + +=item _chdir($from) + +Wrapper around chdir to catch errors. + +If not called in void context returns the cwd from before the chdir. + +dies on error. + +=cut + +sub _chdir { + my ($dir)= @_; + my $ret; + if (defined wantarray) { + $ret= cwd; + } + chdir $dir + or _choke("Couldn't chdir to '$dir': $!"); + return $ret; +} + +=pod + +=end _private + +=item B<install> + + # deprecated forms + install(\%from_to); + install(\%from_to, $verbose, $dry_run, $uninstall_shadows, + $skip, $always_copy, \%result); + + # recommended form as of 1.47 + install([ + from_to => \%from_to, + verbose => 1, + dry_run => 0, + uninstall_shadows => 1, + skip => undef, + always_copy => 1, + result => \%install_results, + ]); + + +Copies each directory tree of %from_to to its corresponding value +preserving timestamps and permissions. + +There are two keys with a special meaning in the hash: "read" and +"write". These contain packlist files. After the copying is done, +install() will write the list of target files to $from_to{write}. If +$from_to{read} is given the contents of this file will be merged into +the written file. The read and the written file may be identical, but +on AFS it is quite likely that people are installing to a different +directory than the one where the files later appear. + +If $verbose is true, will print out each file removed. Default is +false. This is "make install VERBINST=1". $verbose values going +up to 5 show increasingly more diagnostics output. + +If $dry_run is true it will only print what it was going to do +without actually doing it. Default is false. + +If $uninstall_shadows is true any differing versions throughout @INC +will be uninstalled. This is "make install UNINST=1" + +As of 1.37_02 install() supports the use of a list of patterns to filter out +files that shouldn't be installed. If $skip is omitted or undefined then +install will try to read the list from INSTALL.SKIP in the CWD. This file is +a list of regular expressions and is just like the MANIFEST.SKIP file used +by L<ExtUtils::Manifest>. + +A default site INSTALL.SKIP may be provided by setting then environment +variable EU_INSTALL_SITE_SKIPFILE, this will only be used when there isn't a +distribution specific INSTALL.SKIP. If the environment variable +EU_INSTALL_IGNORE_SKIP is true then no install file filtering will be +performed. + +If $skip is undefined then the skip file will be autodetected and used if it +is found. If $skip is a reference to an array then it is assumed the array +contains the list of patterns, if $skip is a true non reference it is +assumed to be the filename holding the list of patterns, any other value of +$skip is taken to mean that no install filtering should occur. + +B<Changes As of Version 1.47> + +As of version 1.47 the following additions were made to the install interface. +Note that the new argument style and use of the %result hash is recommended. + +The $always_copy parameter which when true causes files to be updated +regardles as to whether they have changed, if it is defined but false then +copies are made only if the files have changed, if it is undefined then the +value of the environment variable EU_INSTALL_ALWAYS_COPY is used as default. + +The %result hash will be populated with the various keys/subhashes reflecting +the install. Currently these keys and their structure are: + + install => { $target => $source }, + install_fail => { $target => $source }, + install_unchanged => { $target => $source }, + + install_filtered => { $source => $pattern }, + + uninstall => { $uninstalled => $source }, + uninstall_fail => { $uninstalled => $source }, + +where C<$source> is the filespec of the file being installed. C<$target> is where +it is being installed to, and C<$uninstalled> is any shadow file that is in C<@INC> +or C<$ENV{PERL5LIB}> or other standard locations, and C<$pattern> is the pattern that +caused a source file to be skipped. In future more keys will be added, such as to +show created directories, however this requires changes in other modules and must +therefore wait. + +These keys will be populated before any exceptions are thrown should there be an +error. + +Note that all updates of the %result are additive, the hash will not be +cleared before use, thus allowing status results of many installs to be easily +aggregated. + +B<NEW ARGUMENT STYLE> + +If there is only one argument and it is a reference to an array then +the array is assumed to contain a list of key-value pairs specifying +the options. In this case the option "from_to" is mandatory. This style +means that you dont have to supply a cryptic list of arguments and can +use a self documenting argument list that is easier to understand. + +This is now the recommended interface to install(). + +B<RETURN> + +If all actions were successful install will return a hashref of the results +as described above for the $result parameter. If any action is a failure +then install will die, therefore it is recommended to pass in the $result +parameter instead of using the return value. If the result parameter is +provided then the returned hashref will be the passed in hashref. + +=cut + +sub install { #XXX OS-SPECIFIC + my($from_to,$verbose,$dry_run,$uninstall_shadows,$skip,$always_copy,$result) = @_; + if (@_==1 and eval { 1+@$from_to }) { + my %opts = @$from_to; + $from_to = $opts{from_to} + or Carp::confess("from_to is a mandatory parameter"); + $verbose = $opts{verbose}; + $dry_run = $opts{dry_run}; + $uninstall_shadows = $opts{uninstall_shadows}; + $skip = $opts{skip}; + $always_copy = $opts{always_copy}; + $result = $opts{result}; + } + + $result ||= {}; + $verbose ||= 0; + $dry_run ||= 0; + + $skip= _get_install_skip($skip,$verbose); + $always_copy = $ENV{EU_INSTALL_ALWAYS_COPY} + || $ENV{EU_ALWAYS_COPY} + || 0 + unless defined $always_copy; + + my(%from_to) = %$from_to; + my(%pack, $dir, %warned); + my($packlist) = ExtUtils::Packlist->new(); + + local(*DIR); + for (qw/read write/) { + $pack{$_}=$from_to{$_}; + delete $from_to{$_}; + } + my $tmpfile = install_rooted_file($pack{"read"}); + $packlist->read($tmpfile) if (-f $tmpfile); + my $cwd = cwd(); + my @found_files; + my %check_dirs; + + MOD_INSTALL: foreach my $source (sort keys %from_to) { + #copy the tree to the target directory without altering + #timestamp and permission and remember for the .packlist + #file. The packlist file contains the absolute paths of the + #install locations. AFS users may call this a bug. We'll have + #to reconsider how to add the means to satisfy AFS users also. + + #October 1997: we want to install .pm files into archlib if + #there are any files in arch. So we depend on having ./blib/arch + #hardcoded here. + + my $targetroot = install_rooted_dir($from_to{$source}); + + my $blib_lib = File::Spec->catdir('blib', 'lib'); + my $blib_arch = File::Spec->catdir('blib', 'arch'); + if ($source eq $blib_lib and + exists $from_to{$blib_arch} and + directory_not_empty($blib_arch) + ){ + $targetroot = install_rooted_dir($from_to{$blib_arch}); + print "Files found in $blib_arch: installing files in $blib_lib into architecture dependent library tree\n"; + } + + next unless -d $source; + _chdir($source); + # 5.5.3's File::Find missing no_chdir option + # XXX OS-SPECIFIC + # File::Find seems to always be Unixy except on MacPerl :( + my $current_directory= $Is_MacPerl ? $Curdir : '.'; + find(sub { + my ($mode,$size,$atime,$mtime) = (stat)[2,7,8,9]; + + return if !-f _; + my $origfile = $_; + + return if $origfile eq ".exists"; + my $targetdir = File::Spec->catdir($targetroot, $File::Find::dir); + my $targetfile = File::Spec->catfile($targetdir, $origfile); + my $sourcedir = File::Spec->catdir($source, $File::Find::dir); + my $sourcefile = File::Spec->catfile($sourcedir, $origfile); + + for my $pat (@$skip) { + if ( $sourcefile=~/$pat/ ) { + print "Skipping $targetfile (filtered)\n" + if $verbose>1; + $result->{install_filtered}{$sourcefile} = $pat; + return; + } + } + # we have to do this for back compat with old File::Finds + # and because the target is relative + my $save_cwd = _chdir($cwd); + my $diff = 0; + # XXX: I wonder how useful this logic is actually -- demerphq + if ( $always_copy or !-f $targetfile or -s $targetfile != $size) { + $diff++; + } else { + # we might not need to copy this file + $diff = compare($sourcefile, $targetfile); + } + $check_dirs{$targetdir}++ + unless -w $targetfile; + + push @found_files, + [ $diff, $File::Find::dir, $origfile, + $mode, $size, $atime, $mtime, + $targetdir, $targetfile, $sourcedir, $sourcefile, + + ]; + #restore the original directory we were in when File::Find + #called us so that it doesnt get horribly confused. + _chdir($save_cwd); + }, $current_directory ); + _chdir($cwd); + } + foreach my $targetdir (sort keys %check_dirs) { + _mkpath( $targetdir, 0, 0755, $verbose, $dry_run ); + } + foreach my $found (@found_files) { + my ($diff, $ffd, $origfile, $mode, $size, $atime, $mtime, + $targetdir, $targetfile, $sourcedir, $sourcefile)= @$found; + + my $realtarget= $targetfile; + if ($diff) { + eval { + if (-f $targetfile) { + print "_unlink_or_rename($targetfile)\n" if $verbose>1; + $targetfile= _unlink_or_rename( $targetfile, 'tryhard', 'install' ) + unless $dry_run; + } elsif ( ! -d $targetdir ) { + _mkpath( $targetdir, 0, 0755, $verbose, $dry_run ); + } + print "Installing $targetfile\n"; + + _copy( $sourcefile, $targetfile, $verbose, $dry_run, ); + + + #XXX OS-SPECIFIC + print "utime($atime,$mtime,$targetfile)\n" if $verbose>1; + utime($atime,$mtime + $Is_VMS,$targetfile) unless $dry_run>1; + + + $mode = 0444 | ( $mode & 0111 ? 0111 : 0 ); + $mode = $mode | 0222 + if $realtarget ne $targetfile; + _chmod( $mode, $targetfile, $verbose ); + $result->{install}{$targetfile} = $sourcefile; + 1 + } or do { + $result->{install_fail}{$targetfile} = $sourcefile; + die $@; + }; + } else { + $result->{install_unchanged}{$targetfile} = $sourcefile; + print "Skipping $targetfile (unchanged)\n" if $verbose; + } + + if ( $uninstall_shadows ) { + inc_uninstall($sourcefile,$ffd, $verbose, + $dry_run, + $realtarget ne $targetfile ? $realtarget : "", + $result); + } + + # Record the full pathname. + $packlist->{$targetfile}++; + } + + if ($pack{'write'}) { + $dir = install_rooted_dir(dirname($pack{'write'})); + _mkpath( $dir, 0, 0755, $verbose, $dry_run ); + print "Writing $pack{'write'}\n" if $verbose; + $packlist->write(install_rooted_file($pack{'write'})) unless $dry_run; + } + + _do_cleanup($verbose); + return $result; +} + +=begin _private + +=item _do_cleanup + +Standardize finish event for after another instruction has occured. +Handles converting $MUST_REBOOT to a die for instance. + +=end _private + +=cut + +sub _do_cleanup { + my ($verbose) = @_; + if ($MUST_REBOOT) { + die _estr "Operation not completed! ", + "You must reboot to complete the installation.", + "Sorry."; + } elsif (defined $MUST_REBOOT & $verbose) { + warn _estr "Installation will be completed at the next reboot.\n", + "However it is not necessary to reboot immediately.\n"; + } +} + +=begin _undocumented + +=item install_rooted_file( $file ) + +Returns $file, or catfile($INSTALL_ROOT,$file) if $INSTALL_ROOT +is defined. + +=item install_rooted_dir( $dir ) + +Returns $dir, or catdir($INSTALL_ROOT,$dir) if $INSTALL_ROOT +is defined. + +=end _undocumented + +=cut + + +sub install_rooted_file { + if (defined $INSTALL_ROOT) { + File::Spec->catfile($INSTALL_ROOT, $_[0]); + } else { + $_[0]; + } +} + + +sub install_rooted_dir { + if (defined $INSTALL_ROOT) { + File::Spec->catdir($INSTALL_ROOT, $_[0]); + } else { + $_[0]; + } +} + +=begin _undocumented + +=item forceunlink( $file, $tryhard ) + +Tries to delete a file. If $tryhard is true then we will use whatever +devious tricks we can to delete the file. Currently this only applies to +Win32 in that it will try to use Win32API::File to schedule a delete at +reboot. A wrapper for _unlink_or_rename(). + +=end _undocumented + +=cut + + +sub forceunlink { + my ( $file, $tryhard )= @_; #XXX OS-SPECIFIC + _unlink_or_rename( $file, $tryhard, not("installing") ); +} + +=begin _undocumented + +=item directory_not_empty( $dir ) + +Returns 1 if there is an .exists file somewhere in a directory tree. +Returns 0 if there is not. + +=end _undocumented + +=cut + +sub directory_not_empty ($) { + my($dir) = @_; + my $files = 0; + find(sub { + return if $_ eq ".exists"; + if (-f) { + $File::Find::prune++; + $files = 1; + } + }, $dir); + return $files; +} + +=pod + +=item B<install_default> I<DISCOURAGED> + + install_default(); + install_default($fullext); + +Calls install() with arguments to copy a module from blib/ to the +default site installation location. + +$fullext is the name of the module converted to a directory +(ie. Foo::Bar would be Foo/Bar). If $fullext is not specified, it +will attempt to read it from @ARGV. + +This is primarily useful for install scripts. + +B<NOTE> This function is not really useful because of the hard-coded +install location with no way to control site vs core vs vendor +directories and the strange way in which the module name is given. +Consider its use discouraged. + +=cut + +sub install_default { + @_ < 2 or Carp::croak("install_default should be called with 0 or 1 argument"); + my $FULLEXT = @_ ? shift : $ARGV[0]; + defined $FULLEXT or die "Do not know to where to write install log"; + my $INST_LIB = File::Spec->catdir($Curdir,"blib","lib"); + my $INST_ARCHLIB = File::Spec->catdir($Curdir,"blib","arch"); + my $INST_BIN = File::Spec->catdir($Curdir,'blib','bin'); + my $INST_SCRIPT = File::Spec->catdir($Curdir,'blib','script'); + my $INST_MAN1DIR = File::Spec->catdir($Curdir,'blib','man1'); + my $INST_MAN3DIR = File::Spec->catdir($Curdir,'blib','man3'); + + my @INST_HTML; + if($Config{installhtmldir}) { + my $INST_HTMLDIR = File::Spec->catdir($Curdir,'blib','html'); + @INST_HTML = ($INST_HTMLDIR => $Config{installhtmldir}); + } + + install({ + read => "$Config{sitearchexp}/auto/$FULLEXT/.packlist", + write => "$Config{installsitearch}/auto/$FULLEXT/.packlist", + $INST_LIB => (directory_not_empty($INST_ARCHLIB)) ? + $Config{installsitearch} : + $Config{installsitelib}, + $INST_ARCHLIB => $Config{installsitearch}, + $INST_BIN => $Config{installbin} , + $INST_SCRIPT => $Config{installscript}, + $INST_MAN1DIR => $Config{installman1dir}, + $INST_MAN3DIR => $Config{installman3dir}, + @INST_HTML, + },1,0,0); +} + + +=item B<uninstall> + + uninstall($packlist_file); + uninstall($packlist_file, $verbose, $dont_execute); + +Removes the files listed in a $packlist_file. + +If $verbose is true, will print out each file removed. Default is +false. + +If $dont_execute is true it will only print what it was going to do +without actually doing it. Default is false. + +=cut + +sub uninstall { + my($fil,$verbose,$dry_run) = @_; + $verbose ||= 0; + $dry_run ||= 0; + + die _estr "ERROR: no packlist file found: '$fil'" + unless -f $fil; + # my $my_req = $self->catfile(qw(auto ExtUtils Install forceunlink.al)); + # require $my_req; # Hairy, but for the first + my ($packlist) = ExtUtils::Packlist->new($fil); + foreach (sort(keys(%$packlist))) { + chomp; + print "unlink $_\n" if $verbose; + forceunlink($_,'tryhard') unless $dry_run; + } + print "unlink $fil\n" if $verbose; + forceunlink($fil, 'tryhard') unless $dry_run; + _do_cleanup($verbose); +} + +=begin _undocumented + +=item inc_uninstall($filepath,$libdir,$verbose,$dry_run,$ignore,$results) + +Remove shadowed files. If $ignore is true then it is assumed to hold +a filename to ignore. This is used to prevent spurious warnings from +occuring when doing an install at reboot. + +We now only die when failing to remove a file that has precedence over +our own, when our install has precedence we only warn. + +$results is assumed to contain a hashref which will have the keys +'uninstall' and 'uninstall_fail' populated with keys for the files +removed and values of the source files they would shadow. + +=end _undocumented + +=cut + +sub inc_uninstall { + my($filepath,$libdir,$verbose,$dry_run,$ignore,$results) = @_; + my($dir); + $ignore||=""; + my $file = (File::Spec->splitpath($filepath))[2]; + my %seen_dir = (); + + my @PERL_ENV_LIB = split $Config{path_sep}, defined $ENV{'PERL5LIB'} + ? $ENV{'PERL5LIB'} : $ENV{'PERLLIB'} || ''; + + my @dirs=( @PERL_ENV_LIB, + @INC, + @Config{qw(archlibexp + privlibexp + sitearchexp + sitelibexp)}); + + #warn join "\n","---",@dirs,"---"; + my $seen_ours; + foreach $dir ( @dirs ) { + my $canonpath = $Is_VMS ? $dir : File::Spec->canonpath($dir); + next if $canonpath eq $Curdir; + next if $seen_dir{$canonpath}++; + my $targetfile = File::Spec->catfile($canonpath,$libdir,$file); + next unless -f $targetfile; + + # The reason why we compare file's contents is, that we cannot + # know, which is the file we just installed (AFS). So we leave + # an identical file in place + my $diff = 0; + if ( -f $targetfile && -s _ == -s $filepath) { + # We have a good chance, we can skip this one + $diff = compare($filepath,$targetfile); + } else { + $diff++; + } + print "#$file and $targetfile differ\n" if $diff && $verbose > 1; + + if (!$diff or $targetfile eq $ignore) { + $seen_ours = 1; + next; + } + if ($dry_run) { + $results->{uninstall}{$targetfile} = $filepath; + if ($verbose) { + $Inc_uninstall_warn_handler ||= ExtUtils::Install::Warn->new(); + $libdir =~ s|^\./||s ; # That's just cosmetics, no need to port. It looks prettier. + $Inc_uninstall_warn_handler->add( + File::Spec->catfile($libdir, $file), + $targetfile + ); + } + # if not verbose, we just say nothing + } else { + print "Unlinking $targetfile (shadowing?)\n" if $verbose; + eval { + die "Fake die for testing" + if $ExtUtils::Install::Testing and + ucase(File::Spec->canonpath($ExtUtils::Install::Testing)) eq ucase($targetfile); + forceunlink($targetfile,'tryhard'); + $results->{uninstall}{$targetfile} = $filepath; + 1; + } or do { + $results->{fail_uninstall}{$targetfile} = $filepath; + if ($seen_ours) { + warn "Failed to remove probably harmless shadow file '$targetfile'\n"; + } else { + die "$@\n"; + } + }; + } + } +} + +=begin _undocumented + +=item run_filter($cmd,$src,$dest) + +Filter $src using $cmd into $dest. + +=end _undocumented + +=cut + +sub run_filter { + my ($cmd, $src, $dest) = @_; + local(*CMD, *SRC); + open(CMD, "|$cmd >$dest") || die "Cannot fork: $!"; + open(SRC, $src) || die "Cannot open $src: $!"; + my $buf; + my $sz = 1024; + while (my $len = sysread(SRC, $buf, $sz)) { + syswrite(CMD, $buf, $len); + } + close SRC; + close CMD or die "Filter command '$cmd' failed for $src"; +} + +=pod + +=item B<pm_to_blib> + + pm_to_blib(\%from_to, $autosplit_dir); + pm_to_blib(\%from_to, $autosplit_dir, $filter_cmd); + +Copies each key of %from_to to its corresponding value efficiently. +Filenames with the extension .pm are autosplit into the $autosplit_dir. +Any destination directories are created. + +$filter_cmd is an optional shell command to run each .pm file through +prior to splitting and copying. Input is the contents of the module, +output the new module contents. + +You can have an environment variable PERL_INSTALL_ROOT set which will +be prepended as a directory to each installed file (and directory). + +=cut + +sub pm_to_blib { + my($fromto,$autodir,$pm_filter) = @_; + + _mkpath($autodir,0,0755); + while(my($from, $to) = each %$fromto) { + if( -f $to && -s $from == -s $to && -M $to < -M $from ) { + print "Skip $to (unchanged)\n"; + next; + } + + # When a pm_filter is defined, we need to pre-process the source first + # to determine whether it has changed or not. Therefore, only perform + # the comparison check when there's no filter to be ran. + # -- RAM, 03/01/2001 + + my $need_filtering = defined $pm_filter && length $pm_filter && + $from =~ /\.pm$/; + + if (!$need_filtering && 0 == compare($from,$to)) { + print "Skip $to (unchanged)\n"; + next; + } + if (-f $to){ + # we wont try hard here. its too likely to mess things up. + forceunlink($to); + } else { + _mkpath(dirname($to),0,0755); + } + if ($need_filtering) { + run_filter($pm_filter, $from, $to); + print "$pm_filter <$from >$to\n"; + } else { + _copy( $from, $to ); + print "cp $from $to\n"; + } + my($mode,$atime,$mtime) = (stat $from)[2,8,9]; + utime($atime,$mtime+$Is_VMS,$to); + _chmod(0444 | ( $mode & 0111 ? 0111 : 0 ),$to); + next unless $from =~ /\.pm$/; + _autosplit($to,$autodir); + } +} + + +=begin _private + +=item _autosplit + +From 1.0307 back, AutoSplit will sometimes leave an open filehandle to +the file being split. This causes problems on systems with mandatory +locking (ie. Windows). So we wrap it and close the filehandle. + +=end _private + +=cut + +sub _autosplit { #XXX OS-SPECIFIC + my $retval = autosplit(@_); + close *AutoSplit::IN if defined *AutoSplit::IN{IO}; + + return $retval; +} + + +package ExtUtils::Install::Warn; + +sub new { bless {}, shift } + +sub add { + my($self,$file,$targetfile) = @_; + push @{$self->{$file}}, $targetfile; +} + +sub DESTROY { + unless(defined $INSTALL_ROOT) { + my $self = shift; + my($file,$i,$plural); + foreach $file (sort keys %$self) { + $plural = @{$self->{$file}} > 1 ? "s" : ""; + print "## Differing version$plural of $file found. You might like to\n"; + for (0..$#{$self->{$file}}) { + print "rm ", $self->{$file}[$_], "\n"; + $i++; + } + } + $plural = $i>1 ? "all those files" : "this file"; + my $inst = (_invokant() eq 'ExtUtils::MakeMaker') + ? ( $Config::Config{make} || 'make' ).' install' + . ( $Is_VMS ? '/MACRO="UNINST"=1' : ' UNINST=1' ) + : './Build install uninst=1'; + print "## Running '$inst' will unlink $plural for you.\n"; + } +} + +=begin _private + +=item _invokant + +Does a heuristic on the stack to see who called us for more intelligent +error messages. Currently assumes we will be called only by Module::Build +or by ExtUtils::MakeMaker. + +=end _private + +=cut + +sub _invokant { + my @stack; + my $frame = 0; + while (my $file = (caller($frame++))[1]) { + push @stack, (File::Spec->splitpath($file))[2]; + } + + my $builder; + my $top = pop @stack; + if ($top =~ /^Build/i || exists($INC{'Module/Build.pm'})) { + $builder = 'Module::Build'; + } else { + $builder = 'ExtUtils::MakeMaker'; + } + return $builder; +} + +=pod + +=back + +=head1 ENVIRONMENT + +=over 4 + +=item B<PERL_INSTALL_ROOT> + +Will be prepended to each install path. + +=item B<EU_INSTALL_IGNORE_SKIP> + +Will prevent the automatic use of INSTALL.SKIP as the install skip file. + +=item B<EU_INSTALL_SITE_SKIPFILE> + +If there is no INSTALL.SKIP file in the make directory then this value +can be used to provide a default. + +=item B<EU_INSTALL_ALWAYS_COPY> + +If this environment variable is true then normal install processes will +always overwrite older identical files during the install process. + +Note that the alias EU_ALWAYS_COPY will be supported if EU_INSTALL_ALWAYS_COPY +is not defined until at least the 1.50 release. Please ensure you use the +correct EU_INSTALL_ALWAYS_COPY. + +=back + +=head1 AUTHOR + +Original author lost in the mists of time. Probably the same as Makemaker. + +Production release currently maintained by demerphq C<yves at cpan.org>, +extensive changes by Michael G. Schwern. + +Send bug reports via http://rt.cpan.org/. Please send your +generated Makefile along with your report. + +=head1 LICENSE + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +See L<http://www.perl.com/perl/misc/Artistic.html> + + +=cut + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/Installed.pm b/Master/tlpkg/tlperl/lib/ExtUtils/Installed.pm new file mode 100644 index 00000000000..9cb1fc10d75 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/Installed.pm @@ -0,0 +1,462 @@ +package ExtUtils::Installed; + +use 5.00503; +use strict; +#use warnings; # XXX requires 5.6 +use Carp qw(); +use ExtUtils::Packlist; +use ExtUtils::MakeMaker; +use Config; +use File::Find; +use File::Basename; +use File::Spec; + +my $Is_VMS = $^O eq 'VMS'; +my $DOSISH = ($^O =~ /^(MSWin\d\d|os2|dos|mint)$/); + +require VMS::Filespec if $Is_VMS; + +use vars qw($VERSION); +$VERSION = '1.999_001'; +$VERSION = eval $VERSION; + +sub _is_prefix { + my ($self, $path, $prefix) = @_; + return unless defined $prefix && defined $path; + + if( $Is_VMS ) { + $prefix = VMS::Filespec::unixify($prefix); + $path = VMS::Filespec::unixify($path); + } + + # Unix path normalization. + $prefix = File::Spec->canonpath($prefix); + + return 1 if substr($path, 0, length($prefix)) eq $prefix; + + if ($DOSISH) { + $path =~ s|\\|/|g; + $prefix =~ s|\\|/|g; + return 1 if $path =~ m{^\Q$prefix\E}i; + } + return(0); +} + +sub _is_doc { + my ($self, $path) = @_; + + my $man1dir = $self->{':private:'}{Config}{man1direxp}; + my $man3dir = $self->{':private:'}{Config}{man3direxp}; + return(($man1dir && $self->_is_prefix($path, $man1dir)) + || + ($man3dir && $self->_is_prefix($path, $man3dir)) + ? 1 : 0) +} + +sub _is_type { + my ($self, $path, $type) = @_; + return 1 if $type eq "all"; + + return($self->_is_doc($path)) if $type eq "doc"; + my $conf= $self->{':private:'}{Config}; + if ($type eq "prog") { + return($self->_is_prefix($path, $conf->{prefix} || $conf->{prefixexp}) + && !($self->_is_doc($path)) ? 1 : 0); + } + return(0); +} + +sub _is_under { + my ($self, $path, @under) = @_; + $under[0] = "" if (! @under); + foreach my $dir (@under) { + return(1) if ($self->_is_prefix($path, $dir)); + } + + return(0); +} + +sub _fix_dirs { + my ($self, @dirs)= @_; + # File::Find does not know how to deal with VMS filepaths. + if( $Is_VMS ) { + $_ = VMS::Filespec::unixify($_) + for @dirs; + } + + if ($DOSISH) { + s|\\|/|g for @dirs; + } + return wantarray ? @dirs : $dirs[0]; +} + +sub _make_entry { + my ($self, $module, $packlist_file, $modfile)= @_; + + my $data= { + module => $module, + packlist => scalar(ExtUtils::Packlist->new($packlist_file)), + packlist_file => $packlist_file, + }; + + if (!$modfile) { + $data->{version} = $self->{':private:'}{Config}{version}; + } else { + $data->{modfile} = $modfile; + # Find the top-level module file in @INC + $data->{version} = ''; + foreach my $dir (@{$self->{':private:'}{INC}}) { + my $p = File::Spec->catfile($dir, $modfile); + if (-r $p) { + $module = _module_name($p, $module) if $Is_VMS; + + $data->{version} = MM->parse_version($p); + $data->{version_from} = $p; + $data->{packlist_valid} = exists $data->{packlist}{$p}; + last; + } + } + } + $self->{$module}= $data; +} + +our $INSTALLED; +sub new { + my ($class) = shift(@_); + $class = ref($class) || $class; + + my %args = @_; + + return $INSTALLED if $INSTALLED and ($args{default_get} || $args{default}); + + my $self = bless {}, $class; + + $INSTALLED= $self if $args{default_set} || $args{default}; + + + if ($args{config_override}) { + eval { + $self->{':private:'}{Config} = { %{$args{config_override}} }; + } or Carp::croak( + "The 'config_override' parameter must be a hash reference." + ); + } + else { + $self->{':private:'}{Config} = \%Config; + } + + for my $tuple ([inc_override => INC => [ @INC ] ], + [ extra_libs => EXTRA => [] ]) + { + my ($arg,$key,$val)=@$tuple; + if ( $args{$arg} ) { + eval { + $self->{':private:'}{$key} = [ @{$args{$arg}} ]; + } or Carp::croak( + "The '$arg' parameter must be an array reference." + ); + } + elsif ($val) { + $self->{':private:'}{$key} = $val; + } + } + { + my %dupe; + @{$self->{':private:'}{LIBDIRS}} = grep { -e $_ && !$dupe{$_}++ } + @{$self->{':private:'}{EXTRA}}, @{$self->{':private:'}{INC}}; + } + + my @dirs= $self->_fix_dirs(@{$self->{':private:'}{LIBDIRS}}); + + # Read the core packlist + my $archlib = $self->_fix_dirs($self->{':private:'}{Config}{archlibexp}); + $self->_make_entry("Perl",File::Spec->catfile($archlib, '.packlist')); + + my $root; + # Read the module packlists + my $sub = sub { + # Only process module .packlists + return if $_ ne ".packlist" || $File::Find::dir eq $archlib; + + # Hack of the leading bits of the paths & convert to a module name + my $module = $File::Find::name; + my $found = $module =~ s!^.*?/auto/(.*)/.packlist!$1!s + or do { + # warn "Woah! \$_=$_\n\$module=$module\n\$File::Find::dir=$File::Find::dir\n", + # join ("\n",@dirs); + return; + }; + + my $modfile = "$module.pm"; + $module =~ s!/!::!g; + + return if $self->{$module}; #shadowing? + $self->_make_entry($module,$File::Find::name,$modfile); + }; + while (@dirs) { + $root= shift @dirs; + next if !-d $root; + find($sub,$root); + } + + return $self; +} + +# VMS's non-case preserving file-system means the package name can't +# be reconstructed from the filename. +sub _module_name { + my($file, $orig_module) = @_; + + my $module = ''; + if (open PACKFH, $file) { + while (<PACKFH>) { + if (/package\s+(\S+)\s*;/) { + my $pack = $1; + # Make a sanity check, that lower case $module + # is identical to lowercase $pack before + # accepting it + if (lc($pack) eq lc($orig_module)) { + $module = $pack; + last; + } + } + } + close PACKFH; + } + + print STDERR "Couldn't figure out the package name for $file\n" + unless $module; + + return $module; +} + +sub modules { + my ($self) = @_; + $self= $self->new(default=>1) if !ref $self; + + # Bug/feature of sort in scalar context requires this. + return wantarray + ? sort grep { not /^:private:$/ } keys %$self + : grep { not /^:private:$/ } keys %$self; +} + +sub files { + my ($self, $module, $type, @under) = @_; + $self= $self->new(default=>1) if !ref $self; + + # Validate arguments + Carp::croak("$module is not installed") if (! exists($self->{$module})); + $type = "all" if (! defined($type)); + Carp::croak('type must be "all", "prog" or "doc"') + if ($type ne "all" && $type ne "prog" && $type ne "doc"); + + my (@files); + foreach my $file (keys(%{$self->{$module}{packlist}})) { + push(@files, $file) + if ($self->_is_type($file, $type) && + $self->_is_under($file, @under)); + } + return(@files); +} + +sub directories { + my ($self, $module, $type, @under) = @_; + $self= $self->new(default=>1) if !ref $self; + my (%dirs); + foreach my $file ($self->files($module, $type, @under)) { + $dirs{dirname($file)}++; + } + return sort keys %dirs; +} + +sub directory_tree { + my ($self, $module, $type, @under) = @_; + $self= $self->new(default=>1) if !ref $self; + my (%dirs); + foreach my $dir ($self->directories($module, $type, @under)) { + $dirs{$dir}++; + my ($last) = (""); + while ($last ne $dir) { + $last = $dir; + $dir = dirname($dir); + last if !$self->_is_under($dir, @under); + $dirs{$dir}++; + } + } + return(sort(keys(%dirs))); +} + +sub validate { + my ($self, $module, $remove) = @_; + $self= $self->new(default=>1) if !ref $self; + Carp::croak("$module is not installed") if (! exists($self->{$module})); + return($self->{$module}{packlist}->validate($remove)); +} + +sub packlist { + my ($self, $module) = @_; + $self= $self->new(default=>1) if !ref $self; + Carp::croak("$module is not installed") if (! exists($self->{$module})); + return($self->{$module}{packlist}); +} + +sub version { + my ($self, $module) = @_; + $self= $self->new(default=>1) if !ref $self; + Carp::croak("$module is not installed") if (! exists($self->{$module})); + return($self->{$module}{version}); +} + +sub debug_dump { + my ($self, $module) = @_; + $self= $self->new(default=>1) if !ref $self; + local $self->{":private:"}{Config}; + require Data::Dumper; + print Data::Dumper->new([$self])->Sortkeys(1)->Indent(1)->Dump(); +} + + +1; + +__END__ + +=head1 NAME + +ExtUtils::Installed - Inventory management of installed modules + +=head1 SYNOPSIS + + use ExtUtils::Installed; + my ($inst) = ExtUtils::Installed->new(); + my (@modules) = $inst->modules(); + my (@missing) = $inst->validate("DBI"); + my $all_files = $inst->files("DBI"); + my $files_below_usr_local = $inst->files("DBI", "all", "/usr/local"); + my $all_dirs = $inst->directories("DBI"); + my $dirs_below_usr_local = $inst->directory_tree("DBI", "prog"); + my $packlist = $inst->packlist("DBI"); + +=head1 DESCRIPTION + +ExtUtils::Installed provides a standard way to find out what core and module +files have been installed. It uses the information stored in .packlist files +created during installation to provide this information. In addition it +provides facilities to classify the installed files and to extract directory +information from the .packlist files. + +=head1 USAGE + +The new() function searches for all the installed .packlists on the system, and +stores their contents. The .packlists can be queried with the functions +described below. Where it searches by default is determined by the settings found +in C<%Config::Config>, and what the value is of the PERL5LIB environment variable. + +=head1 METHODS + +Unless specified otherwise all method can be called as class methods, or as object +methods. If called as class methods then the "default" object will be used, and if +necessary created using the current processes %Config and @INC. See the +'default' option to new() for details. + + +=over 4 + +=item new() + +This takes optional named parameters. Without parameters, this +searches for all the installed .packlists on the system using +information from C<%Config::Config> and the default module search +paths C<@INC>. The packlists are read using the +L<ExtUtils::Packlist> module. + +If the named parameter C<config_override> is specified, +it should be a reference to a hash which contains all information +usually found in C<%Config::Config>. For example, you can obtain +the configuration information for a separate perl installation and +pass that in. + + my $yoda_cfg = get_fake_config('yoda'); + my $yoda_inst = ExtUtils::Installed->new(config_override=>$yoda_cfg); + +Similarly, the parameter C<inc_override> may be a reference to an +array which is used in place of the default module search paths +from C<@INC>. + + use Config; + my @dirs = split(/\Q$Config{path_sep}\E/, $ENV{PERL5LIB}); + my $p5libs = ExtUtils::Installed->new(inc_override=>\@dirs); + +B<Note>: You probably do not want to use these options alone, almost always +you will want to set both together. + +The parameter c<extra_libs> can be used to specify B<additional> paths to +search for installed modules. For instance + + my $installed = ExtUtils::Installed->new(extra_libs=>["/my/lib/path"]); + +This should only be necessary if C</my/lib/path> is not in PERL5LIB. + +Finally there is the 'default', and the related 'default_get' and 'default_set' +options. These options control the "default" object which is provided by the +class interface to the methods. Setting C<default_get> to true tells the constructor +to return the default object if it is defined. Setting C<default_set> to true tells +the constructor to make the default object the constructed object. Setting the +C<default> option is like setting both to true. This is used primarily internally +and probably isn't interesting to any real user. + +=item modules() + +This returns a list of the names of all the installed modules. The perl 'core' +is given the special name 'Perl'. + +=item files() + +This takes one mandatory parameter, the name of a module. It returns a list of +all the filenames from the package. To obtain a list of core perl files, use +the module name 'Perl'. Additional parameters are allowed. The first is one +of the strings "prog", "doc" or "all", to select either just program files, +just manual files or all files. The remaining parameters are a list of +directories. The filenames returned will be restricted to those under the +specified directories. + +=item directories() + +This takes one mandatory parameter, the name of a module. It returns a list of +all the directories from the package. Additional parameters are allowed. The +first is one of the strings "prog", "doc" or "all", to select either just +program directories, just manual directories or all directories. The remaining +parameters are a list of directories. The directories returned will be +restricted to those under the specified directories. This method returns only +the leaf directories that contain files from the specified module. + +=item directory_tree() + +This is identical in operation to directories(), except that it includes all the +intermediate directories back up to the specified directories. + +=item validate() + +This takes one mandatory parameter, the name of a module. It checks that all +the files listed in the modules .packlist actually exist, and returns a list of +any missing files. If an optional second argument which evaluates to true is +given any missing files will be removed from the .packlist + +=item packlist() + +This returns the ExtUtils::Packlist object for the specified module. + +=item version() + +This returns the version number for the specified module. + +=back + +=head1 EXAMPLE + +See the example in L<ExtUtils::Packlist>. + +=head1 AUTHOR + +Alan Burlison <Alan.Burlison@uk.sun.com> + +=cut diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/Liblist.pm b/Master/tlpkg/tlperl/lib/ExtUtils/Liblist.pm new file mode 100644 index 00000000000..ea4dac4ae7c --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/Liblist.pm @@ -0,0 +1,286 @@ +package ExtUtils::Liblist; + +use strict; + +our $VERSION = '6.56'; + +use File::Spec; +require ExtUtils::Liblist::Kid; +our @ISA = qw(ExtUtils::Liblist::Kid File::Spec); + +# Backwards compatibility with old interface. +sub ext { + goto &ExtUtils::Liblist::Kid::ext; +} + +sub lsdir { + shift; + my $rex = qr/$_[1]/; + opendir DIR, $_[0]; + my @out = grep /$rex/, readdir DIR; + closedir DIR; + return @out; +} + +__END__ + +=head1 NAME + +ExtUtils::Liblist - determine libraries to use and how to use them + +=head1 SYNOPSIS + + require ExtUtils::Liblist; + + $MM->ext($potential_libs, $verbose, $need_names); + + # Usually you can get away with: + ExtUtils::Liblist->ext($potential_libs, $verbose, $need_names) + +=head1 DESCRIPTION + +This utility takes a list of libraries in the form C<-llib1 -llib2 +-llib3> and returns lines suitable for inclusion in an extension +Makefile. Extra library paths may be included with the form +C<-L/another/path> this will affect the searches for all subsequent +libraries. + +It returns an array of four or five scalar values: EXTRALIBS, +BSLOADLIBS, LDLOADLIBS, LD_RUN_PATH, and, optionally, a reference to +the array of the filenames of actual libraries. Some of these don't +mean anything unless on Unix. See the details about those platform +specifics below. The list of the filenames is returned only if +$need_names argument is true. + +Dependent libraries can be linked in one of three ways: + +=over 2 + +=item * For static extensions + +by the ld command when the perl binary is linked with the extension +library. See EXTRALIBS below. + +=item * For dynamic extensions at build/link time + +by the ld command when the shared object is built/linked. See +LDLOADLIBS below. + +=item * For dynamic extensions at load time + +by the DynaLoader when the shared object is loaded. See BSLOADLIBS +below. + +=back + +=head2 EXTRALIBS + +List of libraries that need to be linked with when linking a perl +binary which includes this extension. Only those libraries that +actually exist are included. These are written to a file and used +when linking perl. + +=head2 LDLOADLIBS and LD_RUN_PATH + +List of those libraries which can or must be linked into the shared +library when created using ld. These may be static or dynamic +libraries. LD_RUN_PATH is a colon separated list of the directories +in LDLOADLIBS. It is passed as an environment variable to the process +that links the shared library. + +=head2 BSLOADLIBS + +List of those libraries that are needed but can be linked in +dynamically at run time on this platform. SunOS/Solaris does not need +this because ld records the information (from LDLOADLIBS) into the +object file. This list is used to create a .bs (bootstrap) file. + +=head1 PORTABILITY + +This module deals with a lot of system dependencies and has quite a +few architecture specific C<if>s in the code. + +=head2 VMS implementation + +The version of ext() which is executed under VMS differs from the +Unix-OS/2 version in several respects: + +=over 2 + +=item * + +Input library and path specifications are accepted with or without the +C<-l> and C<-L> prefixes used by Unix linkers. If neither prefix is +present, a token is considered a directory to search if it is in fact +a directory, and a library to search for otherwise. Authors who wish +their extensions to be portable to Unix or OS/2 should use the Unix +prefixes, since the Unix-OS/2 version of ext() requires them. + +=item * + +Wherever possible, shareable images are preferred to object libraries, +and object libraries to plain object files. In accordance with VMS +naming conventions, ext() looks for files named I<lib>shr and I<lib>rtl; +it also looks for I<lib>lib and libI<lib> to accommodate Unix conventions +used in some ported software. + +=item * + +For each library that is found, an appropriate directive for a linker options +file is generated. The return values are space-separated strings of +these directives, rather than elements used on the linker command line. + +=item * + +LDLOADLIBS contains both the libraries found based on C<$potential_libs> and +the CRTLs, if any, specified in Config.pm. EXTRALIBS contains just those +libraries found based on C<$potential_libs>. BSLOADLIBS and LD_RUN_PATH +are always empty. + +=back + +In addition, an attempt is made to recognize several common Unix library +names, and filter them out or convert them to their VMS equivalents, as +appropriate. + +In general, the VMS version of ext() should properly handle input from +extensions originally designed for a Unix or VMS environment. If you +encounter problems, or discover cases where the search could be improved, +please let us know. + +=head2 Win32 implementation + +The version of ext() which is executed under Win32 differs from the +Unix-OS/2 version in several respects: + +=over 2 + +=item * + +If C<$potential_libs> is empty, the return value will be empty. +Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) +will be appended to the list of C<$potential_libs>. The libraries +will be searched for in the directories specified in C<$potential_libs>, +C<$Config{libpth}>, and in C<$Config{installarchlib}/CORE>. +For each library that is found, a space-separated list of fully qualified +library pathnames is generated. + +=item * + +Input library and path specifications are accepted with or without the +C<-l> and C<-L> prefixes used by Unix linkers. + +An entry of the form C<-La:\foo> specifies the C<a:\foo> directory to look +for the libraries that follow. + +An entry of the form C<-lfoo> specifies the library C<foo>, which may be +spelled differently depending on what kind of compiler you are using. If +you are using GCC, it gets translated to C<libfoo.a>, but for other win32 +compilers, it becomes C<foo.lib>. If no files are found by those translated +names, one more attempt is made to find them using either C<foo.a> or +C<libfoo.lib>, depending on whether GCC or some other win32 compiler is +being used, respectively. + +If neither the C<-L> or C<-l> prefix is present in an entry, the entry is +considered a directory to search if it is in fact a directory, and a +library to search for otherwise. The C<$Config{lib_ext}> suffix will +be appended to any entries that are not directories and don't already have +the suffix. + +Note that the C<-L> and C<-l> prefixes are B<not required>, but authors +who wish their extensions to be portable to Unix or OS/2 should use the +prefixes, since the Unix-OS/2 version of ext() requires them. + +=item * + +Entries cannot be plain object files, as many Win32 compilers will +not handle object files in the place of libraries. + +=item * + +Entries in C<$potential_libs> beginning with a colon and followed by +alphanumeric characters are treated as flags. Unknown flags will be ignored. + +An entry that matches C</:nodefault/i> disables the appending of default +libraries found in C<$Config{perllibs}> (this should be only needed very rarely). + +An entry that matches C</:nosearch/i> disables all searching for +the libraries specified after it. Translation of C<-Lfoo> and +C<-lfoo> still happens as appropriate (depending on compiler being used, +as reflected by C<$Config{cc}>), but the entries are not verified to be +valid files or directories. + +An entry that matches C</:search/i> reenables searching for +the libraries specified after it. You can put it at the end to +enable searching for default libraries specified by C<$Config{perllibs}>. + +=item * + +The libraries specified may be a mixture of static libraries and +import libraries (to link with DLLs). Since both kinds are used +pretty transparently on the Win32 platform, we do not attempt to +distinguish between them. + +=item * + +LDLOADLIBS and EXTRALIBS are always identical under Win32, and BSLOADLIBS +and LD_RUN_PATH are always empty (this may change in future). + +=item * + +You must make sure that any paths and path components are properly +surrounded with double-quotes if they contain spaces. For example, +C<$potential_libs> could be (literally): + + "-Lc:\Program Files\vc\lib" msvcrt.lib "la test\foo bar.lib" + +Note how the first and last entries are protected by quotes in order +to protect the spaces. + +=item * + +Since this module is most often used only indirectly from extension +C<Makefile.PL> files, here is an example C<Makefile.PL> entry to add +a library to the build process for an extension: + + LIBS => ['-lgl'] + +When using GCC, that entry specifies that MakeMaker should first look +for C<libgl.a> (followed by C<gl.a>) in all the locations specified by +C<$Config{libpth}>. + +When using a compiler other than GCC, the above entry will search for +C<gl.lib> (followed by C<libgl.lib>). + +If the library happens to be in a location not in C<$Config{libpth}>, +you need: + + LIBS => ['-Lc:\gllibs -lgl'] + +Here is a less often used example: + + LIBS => ['-lgl', ':nosearch -Ld:\mesalibs -lmesa -luser32'] + +This specifies a search for library C<gl> as before. If that search +fails to find the library, it looks at the next item in the list. The +C<:nosearch> flag will prevent searching for the libraries that follow, +so it simply returns the value as C<-Ld:\mesalibs -lmesa -luser32>, +since GCC can use that value as is with its linker. + +When using the Visual C compiler, the second item is returned as +C<-libpath:d:\mesalibs mesa.lib user32.lib>. + +When using the Borland compiler, the second item is returned as +C<-Ld:\mesalibs mesa.lib user32.lib>, and MakeMaker takes care of +moving the C<-Ld:\mesalibs> to the correct place in the linker +command line. + +=back + + +=head1 SEE ALSO + +L<ExtUtils::MakeMaker> + +=cut + diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/Liblist/Kid.pm b/Master/tlpkg/tlperl/lib/ExtUtils/Liblist/Kid.pm new file mode 100644 index 00000000000..b807e97cc86 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/Liblist/Kid.pm @@ -0,0 +1,546 @@ +package ExtUtils::Liblist::Kid; + +# XXX Splitting this out into its own .pm is a temporary solution. + +# This kid package is to be used by MakeMaker. It will not work if +# $self is not a Makemaker. + +use 5.006; +# Broken out of MakeMaker from version 4.11 + +use strict; +our $VERSION = 6.56; + +use Config; +use Cwd 'cwd'; +use File::Basename; +use File::Spec; + +sub ext { + if ($^O eq 'VMS') { return &_vms_ext; } + elsif($^O eq 'MSWin32') { return &_win32_ext; } + else { return &_unix_os2_ext; } +} + +sub _unix_os2_ext { + my($self,$potential_libs, $verbose, $give_libs) = @_; + $verbose ||= 0; + + if ($^O =~ 'os2' and $Config{perllibs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; + $potential_libs .= $Config{perllibs}; + } + return ("", "", "", "", ($give_libs ? [] : ())) unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{so}; + my($libs) = defined $Config{perllibs} ? $Config{perllibs} : $Config{libs}; + my $Config_libext = $Config{lib_ext} || ".a"; + + + # compute $extralibs, $bsloadlibs and $ldloadlibs from + # $potential_libs + # this is a rewrite of Andy Dougherty's extliblist in perl + + my(@searchpath); # from "-L/path" entries in $potential_libs + my(@libpath) = split " ", $Config{'libpth'}; + my(@ldloadlibs, @bsloadlibs, @extralibs, @ld_run_path, %ld_run_path_seen); + my(@libs, %libs_seen); + my($fullname, @fullname); + my($pwd) = cwd(); # from Cwd.pm + my($found) = 0; + + foreach my $thislib (split ' ', $potential_libs) { + + # Handle possible linker path arguments. + if ($thislib =~ s/^(-[LR]|-Wl,-R)//){ # save path flag type + my($ptype) = $1; + unless (-d $thislib){ + warn "$ptype$thislib ignored, directory does not exist\n" + if $verbose; + next; + } + my($rtype) = $ptype; + if (($ptype eq '-R') or ($ptype eq '-Wl,-R')) { + if ($Config{'lddlflags'} =~ /-Wl,-R/) { + $rtype = '-Wl,-R'; + } elsif ($Config{'lddlflags'} =~ /-R/) { + $rtype = '-R'; + } + } + unless (File::Spec->file_name_is_absolute($thislib)) { + warn "Warning: $ptype$thislib changed to $ptype$pwd/$thislib\n"; + $thislib = $self->catdir($pwd,$thislib); + } + push(@searchpath, $thislib); + push(@extralibs, "$ptype$thislib"); + push(@ldloadlibs, "$rtype$thislib"); + next; + } + + # Handle possible library arguments. + unless ($thislib =~ s/^-l//){ + warn "Unrecognized argument in LIBS ignored: '$thislib'\n"; + next; + } + + my($found_lib)=0; + foreach my $thispth (@searchpath, @libpath) { + + # Try to find the full name of the library. We need this to + # determine whether it's a dynamically-loadable library or not. + # This tends to be subject to various os-specific quirks. + # For gcc-2.6.2 on linux (March 1995), DLD can not load + # .sa libraries, with the exception of libm.sa, so we + # deliberately skip them. + if (@fullname = + $self->lsdir($thispth,"^\Qlib$thislib.$so.\E[0-9]+")){ + # Take care that libfoo.so.10 wins against libfoo.so.9. + # Compare two libraries to find the most recent version + # number. E.g. if you have libfoo.so.9.0.7 and + # libfoo.so.10.1, first convert all digits into two + # decimal places. Then we'll add ".00" to the shorter + # strings so that we're comparing strings of equal length + # Thus we'll compare libfoo.so.09.07.00 with + # libfoo.so.10.01.00. Some libraries might have letters + # in the version. We don't know what they mean, but will + # try to skip them gracefully -- we'll set any letter to + # '0'. Finally, sort in reverse so we can take the + # first element. + + #TODO: iterate through the directory instead of sorting + + $fullname = "$thispth/" . + (sort { my($ma) = $a; + my($mb) = $b; + $ma =~ tr/A-Za-z/0/s; + $ma =~ s/\b(\d)\b/0$1/g; + $mb =~ tr/A-Za-z/0/s; + $mb =~ s/\b(\d)\b/0$1/g; + while (length($ma) < length($mb)) { $ma .= ".00"; } + while (length($mb) < length($ma)) { $mb .= ".00"; } + # Comparison deliberately backwards + $mb cmp $ma;} @fullname)[0]; + } elsif (-f ($fullname="$thispth/lib$thislib.$so") + && (($Config{'dlsrc'} ne "dl_dld.xs") || ($thislib eq "m"))){ + } elsif (-f ($fullname="$thispth/lib${thislib}_s$Config_libext") + && ($Config{'archname'} !~ /RM\d\d\d-svr4/) + && ($thislib .= "_s") ){ # we must explicitly use _s version + } elsif (-f ($fullname="$thispth/lib$thislib$Config_libext")){ + } elsif (-f ($fullname="$thispth/$thislib$Config_libext")){ + } elsif (-f ($fullname="$thispth/lib$thislib.dll$Config_libext")){ + } elsif (-f ($fullname="$thispth/Slib$thislib$Config_libext")){ + } elsif ($^O eq 'dgux' + && -l ($fullname="$thispth/lib$thislib$Config_libext") + && readlink($fullname) =~ /^elink:/s) { + # Some of DG's libraries look like misconnected symbolic + # links, but development tools can follow them. (They + # look like this: + # + # libm.a -> elink:${SDE_PATH:-/usr}/sde/\ + # ${TARGET_BINARY_INTERFACE:-m88kdgux}/usr/lib/libm.a + # + # , the compilation tools expand the environment variables.) + } else { + warn "$thislib not found in $thispth\n" if $verbose; + next; + } + warn "'-l$thislib' found at $fullname\n" if $verbose; + push @libs, $fullname unless $libs_seen{$fullname}++; + $found++; + $found_lib++; + + # Now update library lists + + # what do we know about this library... + my $is_dyna = ($fullname !~ /\Q$Config_libext\E\z/); + my $in_perl = ($libs =~ /\B-l\Q${thislib}\E\b/s); + + # include the path to the lib once in the dynamic linker path + # but only if it is a dynamic lib and not in Perl itself + my($fullnamedir) = dirname($fullname); + push @ld_run_path, $fullnamedir + if $is_dyna && !$in_perl && + !$ld_run_path_seen{$fullnamedir}++; + + # Do not add it into the list if it is already linked in + # with the main perl executable. + # We have to special-case the NeXT, because math and ndbm + # are both in libsys_s + unless ($in_perl || + ($Config{'osname'} eq 'next' && + ($thislib eq 'm' || $thislib eq 'ndbm')) ){ + push(@extralibs, "-l$thislib"); + } + + # We might be able to load this archive file dynamically + if ( ($Config{'dlsrc'} =~ /dl_next/ && $Config{'osvers'} lt '4_0') + || ($Config{'dlsrc'} =~ /dl_dld/) ) + { + # We push -l$thislib instead of $fullname because + # it avoids hardwiring a fixed path into the .bs file. + # Mkbootstrap will automatically add dl_findfile() to + # the .bs file if it sees a name in the -l format. + # USE THIS, when dl_findfile() is fixed: + # push(@bsloadlibs, "-l$thislib"); + # OLD USE WAS while checking results against old_extliblist + push(@bsloadlibs, "$fullname"); + } else { + if ($is_dyna){ + # For SunOS4, do not add in this shared library if + # it is already linked in the main perl executable + push(@ldloadlibs, "-l$thislib") + unless ($in_perl and $^O eq 'sunos'); + } else { + push(@ldloadlibs, "-l$thislib"); + } + } + last; # found one here so don't bother looking further + } + warn "Note (probably harmless): " + ."No library found for -l$thislib\n" + unless $found_lib>0; + } + + unless( $found ) { + return ('','','','', ($give_libs ? \@libs : ())); + } + else { + return ("@extralibs", "@bsloadlibs", "@ldloadlibs", + join(":",@ld_run_path), ($give_libs ? \@libs : ())); + } +} + +sub _win32_ext { + + require Text::ParseWords; + + my($self, $potential_libs, $verbose, $give_libs) = @_; + $verbose ||= 0; + + # If user did not supply a list, we punt. + # (caller should probably use the list in $Config{libs}) + return ("", "", "", "", ($give_libs ? [] : ())) unless $potential_libs; + + my $cc = $Config{cc}; + my $VC = $cc =~ /^cl/i; + my $BC = $cc =~ /^bcc/i; + my $GC = $cc =~ /^gcc/i; + my $so = $Config{'so'}; + my $libs = $Config{'perllibs'}; + my $libpth = $Config{'libpth'}; + my $libext = $Config{'lib_ext'} || ".lib"; + my(@libs, %libs_seen); + + if ($libs and $potential_libs !~ /:nodefault/i) { + # If Config.pm defines a set of default libs, we always + # tack them on to the user-supplied list, unless the user + # specified :nodefault + + $potential_libs .= " " if $potential_libs; + $potential_libs .= $libs; + } + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + # normalize to forward slashes + $libpth =~ s,\\,/,g; + $potential_libs =~ s,\\,/,g; + + # compute $extralibs from $potential_libs + + my @searchpath; # from "-L/path" in $potential_libs + my @libpath = Text::ParseWords::quotewords('\s+', 0, $libpth); + my @extralibs; + my $pwd = cwd(); # from Cwd.pm + my $lib = ''; + my $found = 0; + my $search = 1; + my($fullname); + + # add "$Config{installarchlib}/CORE" to default search path + push @libpath, "$Config{installarchlib}/CORE"; + + if ($VC and exists $ENV{LIB} and $ENV{LIB}) { + push @libpath, split /;/, $ENV{LIB}; + } + + foreach (Text::ParseWords::quotewords('\s+', 0, $potential_libs)){ + + my $thislib = $_; + + # see if entry is a flag + if (/^:\w+$/) { + $search = 0 if lc eq ':nosearch'; + $search = 1 if lc eq ':search'; + warn "Ignoring unknown flag '$thislib'\n" + if $verbose and !/^:(no)?(search|default)$/i; + next; + } + + # if searching is disabled, do compiler-specific translations + unless ($search) { + s/^-l(.+)$/$1.lib/ unless $GC; + s/^-L/-libpath:/ if $VC; + push(@extralibs, $_); + $found++; + next; + } + + # handle possible linker path arguments + if (s/^-L// and not -d) { + warn "$thislib ignored, directory does not exist\n" + if $verbose; + next; + } + elsif (-d) { + unless (File::Spec->file_name_is_absolute($_)) { + warn "Warning: '$thislib' changed to '-L$pwd/$_'\n"; + $_ = $self->catdir($pwd,$_); + } + push(@searchpath, $_); + next; + } + + # handle possible library arguments + if (s/^-l// and $GC and !/^lib/i) { + $_ = "lib$_"; + } + $_ .= $libext if !/\Q$libext\E$/i; + + my $secondpass = 0; + LOOKAGAIN: + + # look for the file itself + if (-f) { + warn "'$thislib' found as '$_'\n" if $verbose; + $found++; + push(@extralibs, $_); + next; + } + + my $found_lib = 0; + foreach my $thispth (@searchpath, @libpath){ + unless (-f ($fullname="$thispth\\$_")) { + warn "'$thislib' not found as '$fullname'\n" if $verbose; + next; + } + warn "'$thislib' found as '$fullname'\n" if $verbose; + $found++; + $found_lib++; + push(@extralibs, $fullname); + push @libs, $fullname unless $libs_seen{$fullname}++; + last; + } + + # do another pass with (or without) leading 'lib' if they used -l + if (!$found_lib and $thislib =~ /^-l/ and !$secondpass++) { + if ($GC) { + goto LOOKAGAIN if s/^lib//i; + } + elsif (!/^lib/i) { + $_ = "lib$_"; + goto LOOKAGAIN; + } + } + + # give up + warn "Note (probably harmless): " + ."No library found for $thislib\n" + unless $found_lib>0; + + } + + return ('','','','', ($give_libs ? \@libs : ())) unless $found; + + # make sure paths with spaces are properly quoted + @extralibs = map { (/\s/ && !/^".*"$/) ? qq["$_"] : $_ } @extralibs; + @libs = map { (/\s/ && !/^".*"$/) ? qq["$_"] : $_ } @libs; + $lib = join(' ',@extralibs); + + # normalize back to backward slashes (to help braindead tools) + # XXX this may break equally braindead GNU tools that don't understand + # backslashes, either. Seems like one can't win here. Cursed be CP/M. + $lib =~ s,/,\\,g; + + warn "Result: $lib\n" if $verbose; + wantarray ? ($lib, '', $lib, '', ($give_libs ? \@libs : ())) : $lib; +} + + +sub _vms_ext { + my($self, $potential_libs, $verbose, $give_libs) = @_; + $verbose ||= 0; + + my(@crtls,$crtlstr); + @crtls = ( ($Config{'ldflags'} =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'perllibs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and + # a library spec could be resolved via a logical name, we go to some trouble + # to insure that the copy in the local tree is used, rather than one to + # which a system-wide logical may point. + if ($self->{PERL_SRC}) { + my($locspec,$type); + foreach my $lib (@crtls) { + if (($locspec,$type) = $lib =~ m{^([\w\$-]+)(/\w+)?} and $locspec =~ /perl/i) { + if (lc $type eq '/share') { $locspec .= $Config{'exe_ext'}; } + elsif (lc $type eq '/library') { $locspec .= $Config{'lib_ext'}; } + else { $locspec .= $Config{'obj_ext'}; } + $locspec = $self->catfile($self->{PERL_SRC},$locspec); + $lib = "$locspec$type" if -e $locspec; + } + } + } + $crtlstr = @crtls ? join(' ',@crtls) : ''; + + unless ($potential_libs) { + warn "Result:\n\tEXTRALIBS: \n\tLDLOADLIBS: $crtlstr\n" if $verbose; + return ('', '', $crtlstr, '', ($give_libs ? [] : ())); + } + + my(%found,@fndlibs,$ldlib); + my $cwd = cwd(); + my($so,$lib_ext,$obj_ext) = @Config{'so','lib_ext','obj_ext'}; + # List of common Unix library names and their VMS equivalents + # (VMS equivalent of '' indicates that the library is automatically + # searched by the linker, and should be skipped here.) + my(@flibs, %libs_seen); + my %libmap = ( 'm' => '', 'f77' => '', 'F77' => '', 'V77' => '', 'c' => '', + 'malloc' => '', 'crypt' => '', 'resolv' => '', 'c_s' => '', + 'socket' => '', 'X11' => 'DECW$XLIBSHR', + 'Xt' => 'DECW$XTSHR', 'Xm' => 'DECW$XMLIBSHR', + 'Xmu' => 'DECW$XMULIBSHR'); + if ($Config{'vms_cc_type'} ne 'decc') { $libmap{'curses'} = 'VAXCCURSE'; } + + warn "Potential libraries are '$potential_libs'\n" if $verbose; + + # First, sort out directories and library names in the input + my(@dirs, @libs); + foreach my $lib (split ' ',$potential_libs) { + push(@dirs,$1), next if $lib =~ /^-L(.*)/; + push(@dirs,$lib), next if $lib =~ /[:>\]]$/; + push(@dirs,$lib), next if -d $lib; + push(@libs,$1), next if $lib =~ /^-l(.*)/; + push(@libs,$lib); + } + push(@dirs,split(' ',$Config{'libpth'})); + + # Now make sure we've got VMS-syntax absolute directory specs + # (We don't, however, check whether someone's hidden a relative + # path in a logical name.) + foreach my $dir (@dirs) { + unless (-d $dir) { + warn "Skipping nonexistent Directory $dir\n" if $verbose > 1; + $dir = ''; + next; + } + warn "Resolving directory $dir\n" if $verbose; + if (File::Spec->file_name_is_absolute($dir)) { + $dir = $self->fixpath($dir,1); + } + else { + $dir = $self->catdir($cwd,$dir); + } + } + @dirs = grep { length($_) } @dirs; + unshift(@dirs,''); # Check each $lib without additions first + + LIB: foreach my $lib (@libs) { + if (exists $libmap{$lib}) { + next unless length $libmap{$lib}; + $lib = $libmap{$lib}; + } + + my(@variants,$cand); + my($ctype) = ''; + + # If we don't have a file type, consider it a possibly abbreviated name and + # check for common variants. We try these first to grab libraries before + # a like-named executable image (e.g. -lperl resolves to perlshr.exe + # before perl.exe). + if ($lib !~ /\.[^:>\]]*$/) { + push(@variants,"${lib}shr","${lib}rtl","${lib}lib"); + push(@variants,"lib$lib") if $lib !~ /[:>\]]/; + } + push(@variants,$lib); + warn "Looking for $lib\n" if $verbose; + foreach my $variant (@variants) { + my($fullname, $name); + + foreach my $dir (@dirs) { + my($type); + + $name = "$dir$variant"; + warn "\tChecking $name\n" if $verbose > 2; + $fullname = VMS::Filespec::rmsexpand($name); + if (defined $fullname and -f $fullname) { + # It's got its own suffix, so we'll have to figure out the type + if ($fullname =~ /(?:$so|exe)$/i) { $type = 'SHR'; } + elsif ($fullname =~ /(?:$lib_ext|olb)$/i) { $type = 'OLB'; } + elsif ($fullname =~ /(?:$obj_ext|obj)$/i) { + warn "Note (probably harmless): " + ."Plain object file $fullname found in library list\n"; + $type = 'OBJ'; + } + else { + warn "Note (probably harmless): " + ."Unknown library type for $fullname; assuming shared\n"; + $type = 'SHR'; + } + } + elsif (-f ($fullname = VMS::Filespec::rmsexpand($name,$so)) or + -f ($fullname = VMS::Filespec::rmsexpand($name,'.exe'))) { + $type = 'SHR'; + $name = $fullname unless $fullname =~ /exe;?\d*$/i; + } + elsif (not length($ctype) and # If we've got a lib already, + # don't bother + ( -f ($fullname = VMS::Filespec::rmsexpand($name,$lib_ext)) or + -f ($fullname = VMS::Filespec::rmsexpand($name,'.olb')))) { + $type = 'OLB'; + $name = $fullname unless $fullname =~ /olb;?\d*$/i; + } + elsif (not length($ctype) and # If we've got a lib already, + # don't bother + ( -f ($fullname = VMS::Filespec::rmsexpand($name,$obj_ext)) or + -f ($fullname = VMS::Filespec::rmsexpand($name,'.obj')))) { + warn "Note (probably harmless): " + ."Plain object file $fullname found in library list\n"; + $type = 'OBJ'; + $name = $fullname unless $fullname =~ /obj;?\d*$/i; + } + if (defined $type) { + $ctype = $type; $cand = $name; + last if $ctype eq 'SHR'; + } + } + if ($ctype) { + # This has to precede any other CRTLs, so just make it first + if ($cand eq 'VAXCCURSE') { unshift @{$found{$ctype}}, $cand; } + else { push @{$found{$ctype}}, $cand; } + warn "\tFound as $cand (really $fullname), type $ctype\n" + if $verbose > 1; + push @flibs, $name unless $libs_seen{$fullname}++; + next LIB; + } + } + warn "Note (probably harmless): " + ."No library found for $lib\n"; + } + + push @fndlibs, @{$found{OBJ}} if exists $found{OBJ}; + push @fndlibs, map { "$_/Library" } @{$found{OLB}} if exists $found{OLB}; + push @fndlibs, map { "$_/Share" } @{$found{SHR}} if exists $found{SHR}; + my $lib = join(' ',@fndlibs); + + $ldlib = $crtlstr ? "$lib $crtlstr" : $lib; + warn "Result:\n\tEXTRALIBS: $lib\n\tLDLOADLIBS: $ldlib\n" if $verbose; + wantarray ? ($lib, '', $ldlib, '', ($give_libs ? \@flibs : ())) : $lib; +} + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MANIFEST.SKIP b/Master/tlpkg/tlperl/lib/ExtUtils/MANIFEST.SKIP new file mode 100644 index 00000000000..e50a7b390f7 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MANIFEST.SKIP @@ -0,0 +1,51 @@ +# Avoid version control files. +\bRCS\b +\bCVS\b +\bSCCS\b +,v$ +\B\.svn\b +\B\.git\b +\B\.gitignore\b +\b_darcs\b +\B\.cvsignore$ + +# Avoid VMS specific MakeMaker generated files +\bDescrip.MMS$ +\bDESCRIP.MMS$ +\bdescrip.mms$ + +# Avoid Makemaker generated and utility files. +\bMANIFEST\.bak +\bMakefile$ +\bblib/ +\bMakeMaker-\d +\bpm_to_blib\.ts$ +\bpm_to_blib$ +\bblibdirs\.ts$ # 6.18 through 6.25 generated this + +# Avoid Module::Build generated and utility files. +\bBuild$ +\b_build/ +\bBuild.bat$ +\bBuild.COM$ +\bBUILD.COM$ +\bbuild.com$ + +# Avoid temp and backup files. +~$ +\.old$ +\#$ +\b\.# +\.bak$ +\.tmp$ +\.# +\.rej$ + +# Avoid OS-specific files/dirs +# Mac OSX metadata +\B\.DS_Store +# Mac OSX SMB mount metadata files +\B\._ + +# Avoid Devel::Cover files. +\bcover_db\b diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MM.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MM.pm new file mode 100644 index 00000000000..eac5f483494 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MM.pm @@ -0,0 +1,90 @@ +package ExtUtils::MM; + +use strict; +use ExtUtils::MakeMaker::Config; + +our $VERSION = '6.56'; + +require ExtUtils::Liblist; +require ExtUtils::MakeMaker; +our @ISA = qw(ExtUtils::Liblist ExtUtils::MakeMaker); + +=head1 NAME + +ExtUtils::MM - OS adjusted ExtUtils::MakeMaker subclass + +=head1 SYNOPSIS + + require ExtUtils::MM; + my $mm = MM->new(...); + +=head1 DESCRIPTION + +B<FOR INTERNAL USE ONLY> + +ExtUtils::MM is a subclass of ExtUtils::MakeMaker which automatically +chooses the appropriate OS specific subclass for you +(ie. ExtUils::MM_Unix, etc...). + +It also provides a convenient alias via the MM class (I didn't want +MakeMaker modules outside of ExtUtils/). + +This class might turn out to be a temporary solution, but MM won't go +away. + +=cut + +{ + # Convenient alias. + package MM; + our @ISA = qw(ExtUtils::MM); + sub DESTROY {} +} + +sub _is_win95 { + # miniperl might not have the Win32 functions available and we need + # to run in miniperl. + my $have_win32 = eval { require Win32 }; + return $have_win32 && defined &Win32::IsWin95 ? Win32::IsWin95() + : ! defined $ENV{SYSTEMROOT}; +} + +my %Is = (); +$Is{VMS} = $^O eq 'VMS'; +$Is{OS2} = $^O eq 'os2'; +$Is{MacOS} = $^O eq 'MacOS'; +if( $^O eq 'MSWin32' ) { + _is_win95() ? $Is{Win95} = 1 : $Is{Win32} = 1; +} +$Is{UWIN} = $^O =~ /^uwin(-nt)?$/; +$Is{Cygwin} = $^O eq 'cygwin'; +$Is{NW5} = $Config{osname} eq 'NetWare'; # intentional +$Is{BeOS} = ($^O =~ /beos/i or $^O eq 'haiku'); +$Is{DOS} = $^O eq 'dos'; +if( $Is{NW5} ) { + $^O = 'NetWare'; + delete $Is{Win32}; +} +$Is{VOS} = $^O eq 'vos'; +$Is{QNX} = $^O eq 'qnx'; +$Is{AIX} = $^O eq 'aix'; +$Is{Darwin} = $^O eq 'darwin'; + +$Is{Unix} = !grep { $_ } values %Is; + +map { delete $Is{$_} unless $Is{$_} } keys %Is; +_assert( keys %Is == 1 ); +my($OS) = keys %Is; + + +my $class = "ExtUtils::MM_$OS"; +eval "require $class" unless $INC{"ExtUtils/MM_$OS.pm"}; ## no critic +die $@ if $@; +unshift @ISA, $class; + + +sub _assert { + my $sanity = shift; + die sprintf "Assert failed at %s line %d\n", (caller)[1,2] unless $sanity; + return; +} diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MM_AIX.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MM_AIX.pm new file mode 100644 index 00000000000..5179be4bc2a --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MM_AIX.pm @@ -0,0 +1,79 @@ +package ExtUtils::MM_AIX; + +use strict; +our $VERSION = '6.56'; + +require ExtUtils::MM_Unix; +our @ISA = qw(ExtUtils::MM_Unix); + +use ExtUtils::MakeMaker qw(neatvalue); + + +=head1 NAME + +ExtUtils::MM_AIX - AIX specific subclass of ExtUtils::MM_Unix + +=head1 SYNOPSIS + + Don't use this module directly. + Use ExtUtils::MM and let it choose. + +=head1 DESCRIPTION + +This is a subclass of ExtUtils::MM_Unix which contains functionality for +AIX. + +Unless otherwise stated it works just like ExtUtils::MM_Unix + +=head2 Overridden methods + +=head3 dlsyms + +Define DL_FUNCS and DL_VARS and write the *.exp files. + +=cut + +sub dlsyms { + my($self,%attribs) = @_; + + return '' unless $self->needs_linking(); + + my($funcs) = $attribs{DL_FUNCS} || $self->{DL_FUNCS} || {}; + my($vars) = $attribs{DL_VARS} || $self->{DL_VARS} || []; + my($funclist) = $attribs{FUNCLIST} || $self->{FUNCLIST} || []; + my(@m); + + push(@m," +dynamic :: $self->{BASEEXT}.exp + +") unless $self->{SKIPHASH}{'dynamic'}; # dynamic and static are subs, so... + + push(@m," +static :: $self->{BASEEXT}.exp + +") unless $self->{SKIPHASH}{'static'}; # we avoid a warning if we tick them + + push(@m," +$self->{BASEEXT}.exp: Makefile.PL +",' $(PERLRUN) -e \'use ExtUtils::Mksymlists; \\ + Mksymlists("NAME" => "',$self->{NAME},'", "DL_FUNCS" => ', + neatvalue($funcs), ', "FUNCLIST" => ', neatvalue($funclist), + ', "DL_VARS" => ', neatvalue($vars), ');\' +'); + + join('',@m); +} + + +=head1 AUTHOR + +Michael G Schwern <schwern@pobox.com> with code from ExtUtils::MM_Unix + +=head1 SEE ALSO + +L<ExtUtils::MakeMaker> + +=cut + + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MM_Any.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MM_Any.pm new file mode 100644 index 00000000000..4905aebc642 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MM_Any.pm @@ -0,0 +1,2334 @@ +package ExtUtils::MM_Any; + +use strict; +our $VERSION = '6.56'; + +use Carp; +use File::Spec; +use File::Basename; +BEGIN { our @ISA = qw(File::Spec); } + +# We need $Verbose +use ExtUtils::MakeMaker qw($Verbose); + +use ExtUtils::MakeMaker::Config; + + +# So we don't have to keep calling the methods over and over again, +# we have these globals to cache the values. Faster and shrtr. +my $Curdir = __PACKAGE__->curdir; +my $Rootdir = __PACKAGE__->rootdir; +my $Updir = __PACKAGE__->updir; + + +=head1 NAME + +ExtUtils::MM_Any - Platform-agnostic MM methods + +=head1 SYNOPSIS + + FOR INTERNAL USE ONLY! + + package ExtUtils::MM_SomeOS; + + # Temporarily, you have to subclass both. Put MM_Any first. + require ExtUtils::MM_Any; + require ExtUtils::MM_Unix; + @ISA = qw(ExtUtils::MM_Any ExtUtils::Unix); + +=head1 DESCRIPTION + +B<FOR INTERNAL USE ONLY!> + +ExtUtils::MM_Any is a superclass for the ExtUtils::MM_* set of +modules. It contains methods which are either inherently +cross-platform or are written in a cross-platform manner. + +Subclass off of ExtUtils::MM_Any I<and> ExtUtils::MM_Unix. This is a +temporary solution. + +B<THIS MAY BE TEMPORARY!> + + +=head1 METHODS + +Any methods marked I<Abstract> must be implemented by subclasses. + + +=head2 Cross-platform helper methods + +These are methods which help writing cross-platform code. + + + +=head3 os_flavor I<Abstract> + + my @os_flavor = $mm->os_flavor; + +@os_flavor is the style of operating system this is, usually +corresponding to the MM_*.pm file we're using. + +The first element of @os_flavor is the major family (ie. Unix, +Windows, VMS, OS/2, etc...) and the rest are sub families. + +Some examples: + + Cygwin98 ('Unix', 'Cygwin', 'Cygwin9x') + Windows ('Win32') + Win98 ('Win32', 'Win9x') + Linux ('Unix', 'Linux') + MacOS X ('Unix', 'Darwin', 'MacOS', 'MacOS X') + OS/2 ('OS/2') + +This is used to write code for styles of operating system. +See os_flavor_is() for use. + + +=head3 os_flavor_is + + my $is_this_flavor = $mm->os_flavor_is($this_flavor); + my $is_this_flavor = $mm->os_flavor_is(@one_of_these_flavors); + +Checks to see if the current operating system is one of the given flavors. + +This is useful for code like: + + if( $mm->os_flavor_is('Unix') ) { + $out = `foo 2>&1`; + } + else { + $out = `foo`; + } + +=cut + +sub os_flavor_is { + my $self = shift; + my %flavors = map { ($_ => 1) } $self->os_flavor; + return (grep { $flavors{$_} } @_) ? 1 : 0; +} + + +=head3 can_load_xs + + my $can_load_xs = $self->can_load_xs; + +Returns true if we have the ability to load XS. + +This is important because miniperl, used to build XS modules in the +core, can not load XS. + +=cut + +sub can_load_xs { + return defined &DynaLoader::boot_DynaLoader ? 1 : 0; +} + + +=head3 split_command + + my @cmds = $MM->split_command($cmd, @args); + +Most OS have a maximum command length they can execute at once. Large +modules can easily generate commands well past that limit. Its +necessary to split long commands up into a series of shorter commands. + +C<split_command> will return a series of @cmds each processing part of +the args. Collectively they will process all the arguments. Each +individual line in @cmds will not be longer than the +$self->max_exec_len being careful to take into account macro expansion. + +$cmd should include any switches and repeated initial arguments. + +If no @args are given, no @cmds will be returned. + +Pairs of arguments will always be preserved in a single command, this +is a heuristic for things like pm_to_blib and pod2man which work on +pairs of arguments. This makes things like this safe: + + $self->split_command($cmd, %pod2man); + + +=cut + +sub split_command { + my($self, $cmd, @args) = @_; + + my @cmds = (); + return(@cmds) unless @args; + + # If the command was given as a here-doc, there's probably a trailing + # newline. + chomp $cmd; + + # set aside 30% for macro expansion. + my $len_left = int($self->max_exec_len * 0.70); + $len_left -= length $self->_expand_macros($cmd); + + do { + my $arg_str = ''; + my @next_args; + while( @next_args = splice(@args, 0, 2) ) { + # Two at a time to preserve pairs. + my $next_arg_str = "\t ". join ' ', @next_args, "\n"; + + if( !length $arg_str ) { + $arg_str .= $next_arg_str + } + elsif( length($arg_str) + length($next_arg_str) > $len_left ) { + unshift @args, @next_args; + last; + } + else { + $arg_str .= $next_arg_str; + } + } + chop $arg_str; + + push @cmds, $self->escape_newlines("$cmd \n$arg_str"); + } while @args; + + return @cmds; +} + + +sub _expand_macros { + my($self, $cmd) = @_; + + $cmd =~ s{\$\((\w+)\)}{ + defined $self->{$1} ? $self->{$1} : "\$($1)" + }e; + return $cmd; +} + + +=head3 echo + + my @commands = $MM->echo($text); + my @commands = $MM->echo($text, $file); + my @commands = $MM->echo($text, $file, $appending); + +Generates a set of @commands which print the $text to a $file. + +If $file is not given, output goes to STDOUT. + +If $appending is true the $file will be appended to rather than +overwritten. + +=cut + +sub echo { + my($self, $text, $file, $appending) = @_; + $appending ||= 0; + + my @cmds = map { '$(NOECHO) $(ECHO) '.$self->quote_literal($_) } + split /\n/, $text; + if( $file ) { + my $redirect = $appending ? '>>' : '>'; + $cmds[0] .= " $redirect $file"; + $_ .= " >> $file" foreach @cmds[1..$#cmds]; + } + + return @cmds; +} + + +=head3 wraplist + + my $args = $mm->wraplist(@list); + +Takes an array of items and turns them into a well-formatted list of +arguments. In most cases this is simply something like: + + FOO \ + BAR \ + BAZ + +=cut + +sub wraplist { + my $self = shift; + return join " \\\n\t", @_; +} + + +=head3 maketext_filter + + my $filter_make_text = $mm->maketext_filter($make_text); + +The text of the Makefile is run through this method before writing to +disk. It allows systems a chance to make portability fixes to the +Makefile. + +By default it does nothing. + +This method is protected and not intended to be called outside of +MakeMaker. + +=cut + +sub maketext_filter { return $_[1] } + + +=head3 cd I<Abstract> + + my $subdir_cmd = $MM->cd($subdir, @cmds); + +This will generate a make fragment which runs the @cmds in the given +$dir. The rough equivalent to this, except cross platform. + + cd $subdir && $cmd + +Currently $dir can only go down one level. "foo" is fine. "foo/bar" is +not. "../foo" is right out. + +The resulting $subdir_cmd has no leading tab nor trailing newline. This +makes it easier to embed in a make string. For example. + + my $make = sprintf <<'CODE', $subdir_cmd; + foo : + $(ECHO) what + %s + $(ECHO) mouche + CODE + + +=head3 oneliner I<Abstract> + + my $oneliner = $MM->oneliner($perl_code); + my $oneliner = $MM->oneliner($perl_code, \@switches); + +This will generate a perl one-liner safe for the particular platform +you're on based on the given $perl_code and @switches (a -e is +assumed) suitable for using in a make target. It will use the proper +shell quoting and escapes. + +$(PERLRUN) will be used as perl. + +Any newlines in $perl_code will be escaped. Leading and trailing +newlines will be stripped. Makes this idiom much easier: + + my $code = $MM->oneliner(<<'CODE', [...switches...]); +some code here +another line here +CODE + +Usage might be something like: + + # an echo emulation + $oneliner = $MM->oneliner('print "Foo\n"'); + $make = '$oneliner > somefile'; + +All dollar signs must be doubled in the $perl_code if you expect them +to be interpreted normally, otherwise it will be considered a make +macro. Also remember to quote make macros else it might be used as a +bareword. For example: + + # Assign the value of the $(VERSION_FROM) make macro to $vf. + $oneliner = $MM->oneliner('$$vf = "$(VERSION_FROM)"'); + +Its currently very simple and may be expanded sometime in the figure +to include more flexible code and switches. + + +=head3 quote_literal I<Abstract> + + my $safe_text = $MM->quote_literal($text); + +This will quote $text so it is interpreted literally in the shell. + +For example, on Unix this would escape any single-quotes in $text and +put single-quotes around the whole thing. + + +=head3 escape_newlines I<Abstract> + + my $escaped_text = $MM->escape_newlines($text); + +Shell escapes newlines in $text. + + +=head3 max_exec_len I<Abstract> + + my $max_exec_len = $MM->max_exec_len; + +Calculates the maximum command size the OS can exec. Effectively, +this is the max size of a shell command line. + +=for _private +$self->{_MAX_EXEC_LEN} is set by this method, but only for testing purposes. + + +=head3 make + + my $make = $MM->make; + +Returns the make variant we're generating the Makefile for. This attempts +to do some normalization on the information from %Config or the user. + +=cut + +sub make { + my $self = shift; + + my $make = lc $self->{MAKE}; + + # Truncate anything like foomake6 to just foomake. + $make =~ s/^(\w+make).*/$1/; + + # Turn gnumake into gmake. + $make =~ s/^gnu/g/; + + return $make; +} + + +=head2 Targets + +These are methods which produce make targets. + + +=head3 all_target + +Generate the default target 'all'. + +=cut + +sub all_target { + my $self = shift; + + return <<'MAKE_EXT'; +all :: pure_all + $(NOECHO) $(NOOP) +MAKE_EXT + +} + + +=head3 blibdirs_target + + my $make_frag = $mm->blibdirs_target; + +Creates the blibdirs target which creates all the directories we use +in blib/. + +The blibdirs.ts target is deprecated. Depend on blibdirs instead. + + +=cut + +sub blibdirs_target { + my $self = shift; + + my @dirs = map { uc "\$(INST_$_)" } qw(libdir archlib + autodir archautodir + bin script + man1dir man3dir + ); + + my @exists = map { $_.'$(DFSEP).exists' } @dirs; + + my $make = sprintf <<'MAKE', join(' ', @exists); +blibdirs : %s + $(NOECHO) $(NOOP) + +# Backwards compat with 6.18 through 6.25 +blibdirs.ts : blibdirs + $(NOECHO) $(NOOP) + +MAKE + + $make .= $self->dir_target(@dirs); + + return $make; +} + + +=head3 clean (o) + +Defines the clean target. + +=cut + +sub clean { +# --- Cleanup and Distribution Sections --- + + my($self, %attribs) = @_; + my @m; + push(@m, ' +# Delete temporary files but do not touch installed files. We don\'t delete +# the Makefile here so a later make realclean still has a makefile to use. + +clean :: clean_subdirs +'); + + my @files = values %{$self->{XS}}; # .c files from *.xs files + my @dirs = qw(blib); + + # Normally these are all under blib but they might have been + # redefined. + # XXX normally this would be a good idea, but the Perl core sets + # INST_LIB = ../../lib rather than actually installing the files. + # So a "make clean" in an ext/ directory would blow away lib. + # Until the core is adjusted let's leave this out. +# push @dirs, qw($(INST_ARCHLIB) $(INST_LIB) +# $(INST_BIN) $(INST_SCRIPT) +# $(INST_MAN1DIR) $(INST_MAN3DIR) +# $(INST_LIBDIR) $(INST_ARCHLIBDIR) $(INST_AUTODIR) +# $(INST_STATIC) $(INST_DYNAMIC) $(INST_BOOT) +# ); + + + if( $attribs{FILES} ) { + # Use @dirs because we don't know what's in here. + push @dirs, ref $attribs{FILES} ? + @{$attribs{FILES}} : + split /\s+/, $attribs{FILES} ; + } + + push(@files, qw[$(MAKE_APERL_FILE) + perlmain.c tmon.out mon.out so_locations + blibdirs.ts pm_to_blib pm_to_blib.ts + *$(OBJ_EXT) *$(LIB_EXT) perl.exe perl perl$(EXE_EXT) + $(BOOTSTRAP) $(BASEEXT).bso + $(BASEEXT).def lib$(BASEEXT).def + $(BASEEXT).exp $(BASEEXT).x + ]); + + push(@files, $self->catfile('$(INST_ARCHAUTODIR)','extralibs.all')); + push(@files, $self->catfile('$(INST_ARCHAUTODIR)','extralibs.ld')); + + # core files + push(@files, qw[core core.*perl.*.? *perl.core]); + push(@files, map { "core." . "[0-9]"x$_ } (1..5)); + + # OS specific things to clean up. Use @dirs since we don't know + # what might be in here. + push @dirs, $self->extra_clean_files; + + # Occasionally files are repeated several times from different sources + { my(%f) = map { ($_ => 1) } @files; @files = keys %f; } + { my(%d) = map { ($_ => 1) } @dirs; @dirs = keys %d; } + + push @m, map "\t$_\n", $self->split_command('- $(RM_F)', @files); + push @m, map "\t$_\n", $self->split_command('- $(RM_RF)', @dirs); + + # Leave Makefile.old around for realclean + push @m, <<'MAKE'; + - $(MV) $(FIRST_MAKEFILE) $(MAKEFILE_OLD) $(DEV_NULL) +MAKE + + push(@m, "\t$attribs{POSTOP}\n") if $attribs{POSTOP}; + + join("", @m); +} + + +=head3 clean_subdirs_target + + my $make_frag = $MM->clean_subdirs_target; + +Returns the clean_subdirs target. This is used by the clean target to +call clean on any subdirectories which contain Makefiles. + +=cut + +sub clean_subdirs_target { + my($self) = shift; + + # No subdirectories, no cleaning. + return <<'NOOP_FRAG' unless @{$self->{DIR}}; +clean_subdirs : + $(NOECHO) $(NOOP) +NOOP_FRAG + + + my $clean = "clean_subdirs :\n"; + + for my $dir (@{$self->{DIR}}) { + my $subclean = $self->oneliner(sprintf <<'CODE', $dir); +chdir '%s'; system '$(MAKE) clean' if -f '$(FIRST_MAKEFILE)'; +CODE + + $clean .= "\t$subclean\n"; + } + + return $clean; +} + + +=head3 dir_target + + my $make_frag = $mm->dir_target(@directories); + +Generates targets to create the specified directories and set its +permission to PERM_DIR. + +Because depending on a directory to just ensure it exists doesn't work +too well (the modified time changes too often) dir_target() creates a +.exists file in the created directory. It is this you should depend on. +For portability purposes you should use the $(DIRFILESEP) macro rather +than a '/' to seperate the directory from the file. + + yourdirectory$(DIRFILESEP).exists + +=cut + +sub dir_target { + my($self, @dirs) = @_; + + my $make = ''; + foreach my $dir (@dirs) { + $make .= sprintf <<'MAKE', ($dir) x 7; +%s$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) %s + $(NOECHO) $(CHMOD) $(PERM_DIR) %s + $(NOECHO) $(TOUCH) %s$(DFSEP).exists + +MAKE + + } + + return $make; +} + + +=head3 distdir + +Defines the scratch directory target that will hold the distribution +before tar-ing (or shar-ing). + +=cut + +# For backwards compatibility. +*dist_dir = *distdir; + +sub distdir { + my($self) = shift; + + my $meta_target = $self->{NO_META} ? '' : 'distmeta'; + my $sign_target = !$self->{SIGN} ? '' : 'distsignature'; + + return sprintf <<'MAKE_FRAG', $meta_target, $sign_target; +create_distdir : + $(RM_RF) $(DISTVNAME) + $(PERLRUN) "-MExtUtils::Manifest=manicopy,maniread" \ + -e "manicopy(maniread(),'$(DISTVNAME)', '$(DIST_CP)');" + +distdir : create_distdir %s %s + $(NOECHO) $(NOOP) + +MAKE_FRAG + +} + + +=head3 dist_test + +Defines a target that produces the distribution in the +scratchdirectory, and runs 'perl Makefile.PL; make ;make test' in that +subdirectory. + +=cut + +sub dist_test { + my($self) = shift; + + my $mpl_args = join " ", map qq["$_"], @ARGV; + + my $test = $self->cd('$(DISTVNAME)', + '$(ABSPERLRUN) Makefile.PL '.$mpl_args, + '$(MAKE) $(PASTHRU)', + '$(MAKE) test $(PASTHRU)' + ); + + return sprintf <<'MAKE_FRAG', $test; +disttest : distdir + %s + +MAKE_FRAG + + +} + + +=head3 dynamic (o) + +Defines the dynamic target. + +=cut + +sub dynamic { +# --- Dynamic Loading Sections --- + + my($self) = shift; + ' +dynamic :: $(FIRST_MAKEFILE) $(INST_DYNAMIC) $(INST_BOOT) + $(NOECHO) $(NOOP) +'; +} + + +=head3 makemakerdflt_target + + my $make_frag = $mm->makemakerdflt_target + +Returns a make fragment with the makemakerdeflt_target specified. +This target is the first target in the Makefile, is the default target +and simply points off to 'all' just in case any make variant gets +confused or something gets snuck in before the real 'all' target. + +=cut + +sub makemakerdflt_target { + return <<'MAKE_FRAG'; +makemakerdflt : all + $(NOECHO) $(NOOP) +MAKE_FRAG + +} + + +=head3 manifypods_target + + my $manifypods_target = $self->manifypods_target; + +Generates the manifypods target. This target generates man pages from +all POD files in MAN1PODS and MAN3PODS. + +=cut + +sub manifypods_target { + my($self) = shift; + + my $man1pods = ''; + my $man3pods = ''; + my $dependencies = ''; + + # populate manXpods & dependencies: + foreach my $name (keys %{$self->{MAN1PODS}}, keys %{$self->{MAN3PODS}}) { + $dependencies .= " \\\n\t$name"; + } + + my $manify = <<END; +manifypods : pure_all $dependencies +END + + my @man_cmds; + foreach my $section (qw(1 3)) { + my $pods = $self->{"MAN${section}PODS"}; + push @man_cmds, $self->split_command(<<CMD, %$pods); + \$(NOECHO) \$(POD2MAN) --section=$section --perm_rw=\$(PERM_RW) +CMD + } + + $manify .= "\t\$(NOECHO) \$(NOOP)\n" unless @man_cmds; + $manify .= join '', map { "$_\n" } @man_cmds; + + return $manify; +} + + +=head3 metafile_target + + my $target = $mm->metafile_target; + +Generate the metafile target. + +Writes the file META.yml YAML encoded meta-data about the module in +the distdir. The format follows Module::Build's as closely as +possible. + +=cut + +sub metafile_target { + my $self = shift; + + return <<'MAKE_FRAG' if $self->{NO_META}; +metafile : + $(NOECHO) $(NOOP) +MAKE_FRAG + + my @metadata = $self->metafile_data( + $self->{META_ADD} || {}, + $self->{META_MERGE} || {}, + ); + my $meta = $self->metafile_file(@metadata); + my @write_meta = $self->echo($meta, 'META_new.yml'); + + return sprintf <<'MAKE_FRAG', join("\n\t", @write_meta); +metafile : create_distdir + $(NOECHO) $(ECHO) Generating META.yml + %s + -$(NOECHO) $(MV) META_new.yml $(DISTVNAME)/META.yml +MAKE_FRAG + +} + + +=begin private + +=head3 _sort_pairs + + my @pairs = _sort_pairs($sort_sub, \%hash); + +Sorts the pairs of a hash based on keys ordered according +to C<$sort_sub>. + +=end private + +=cut + +sub _sort_pairs { + my $sort = shift; + my $pairs = shift; + return map { $_ => $pairs->{$_} } + sort $sort + keys %$pairs; +} + + +# Taken from Module::Build::Base +sub _hash_merge { + my ($self, $h, $k, $v) = @_; + if (ref $h->{$k} eq 'ARRAY') { + push @{$h->{$k}}, ref $v ? @$v : $v; + } elsif (ref $h->{$k} eq 'HASH') { + $self->_hash_merge($h->{$k}, $_, $v->{$_}) foreach keys %$v; + } else { + $h->{$k} = $v; + } +} + + +=head3 metafile_data + + my @metadata_pairs = $mm->metafile_data(\%meta_add, \%meta_merge); + +Returns the data which MakeMaker turns into the META.yml file. + +Values of %meta_add will overwrite any existing metadata in those +keys. %meta_merge will be merged with them. + +=cut + +sub metafile_data { + my $self = shift; + my($meta_add, $meta_merge) = @_; + + # The order in which standard meta keys should be written. + my @meta_order = qw( + name + version + abstract + author + license + distribution_type + + configure_requires + build_requires + requires + + resources + + provides + no_index + + generated_by + meta-spec + ); + + # Check the original args so we can tell between the user setting it + # to an empty hash and it just being initialized. + my $configure_requires; + if( $self->{ARGS}{CONFIGURE_REQUIRES} ) { + $configure_requires = $self->{CONFIGURE_REQUIRES}; + } else { + $configure_requires = { + 'ExtUtils::MakeMaker' => 0, + }; + } + my $build_requires; + if( $self->{ARGS}{BUILD_REQUIRES} ) { + $build_requires = $self->{BUILD_REQUIRES}; + } else { + $build_requires = { + 'ExtUtils::MakeMaker' => 0, + }; + } + + my %meta = ( + name => $self->{DISTNAME}, + version => $self->{VERSION}, + abstract => $self->{ABSTRACT}, + license => $self->{LICENSE} || 'unknown', + distribution_type => $self->{PM} ? 'module' : 'script', + + configure_requires => $configure_requires, + + build_requires => $build_requires, + + no_index => { + directory => [qw(t inc)] + }, + + generated_by => "ExtUtils::MakeMaker version $ExtUtils::MakeMaker::VERSION", + 'meta-spec' => { + url => 'http://module-build.sourceforge.net/META-spec-v1.4.html', + version => 1.4 + }, + ); + + # The author key is required and it takes a list. + $meta{author} = defined $self->{AUTHOR} ? [$self->{AUTHOR}] : []; + + $meta{requires} = $self->{PREREQ_PM} if defined $self->{PREREQ_PM}; + $meta{requires}{perl} = $self->{MIN_PERL_VERSION} if $self->{MIN_PERL_VERSION}; + + while( my($key, $val) = each %$meta_add ) { + $meta{$key} = $val; + } + + while( my($key, $val) = each %$meta_merge ) { + $self->_hash_merge(\%meta, $key, $val); + } + + my @meta_pairs; + + # Put the standard keys first in the proper order. + for my $key (@meta_order) { + next unless exists $meta{$key}; + + push @meta_pairs, $key, delete $meta{$key}; + } + + # Then tack everything else onto the end, alpha sorted. + for my $key (sort {lc $a cmp lc $b} keys %meta) { + push @meta_pairs, $key, $meta{$key}; + } + + return @meta_pairs +} + +=begin private + +=head3 _dump_hash + + $yaml = _dump_hash(\%options, %hash); + +Implements a fake YAML dumper for a hash given +as a list of pairs. No quoting/escaping is done. Keys +are supposed to be strings. Values are undef, strings, +hash refs or array refs of strings. + +Supported options are: + + delta => STR - indentation delta + use_header => BOOL - whether to include a YAML header + indent => STR - a string of spaces + default: '' + + max_key_length => INT - maximum key length used to align + keys and values of the same hash + default: 20 + key_sort => CODE - a sort sub + It may be undef, which means no sorting by keys + default: sub { lc $a cmp lc $b } + + customs => HASH - special options for certain keys + (whose values are hashes themselves) + may contain: max_key_length, key_sort, customs + +=end private + +=cut + +sub _dump_hash { + croak "first argument should be a hash ref" unless ref $_[0] eq 'HASH'; + my $options = shift; + my %hash = @_; + + # Use a list to preserve order. + my @pairs; + + my $k_sort + = exists $options->{key_sort} ? $options->{key_sort} + : sub { lc $a cmp lc $b }; + if ($k_sort) { + croak "'key_sort' should be a coderef" unless ref $k_sort eq 'CODE'; + @pairs = _sort_pairs($k_sort, \%hash); + } else { # list of pairs, no sorting + @pairs = @_; + } + + my $yaml = $options->{use_header} ? "--- #YAML:1.0\n" : ''; + my $indent = $options->{indent} || ''; + my $k_length = min( + ($options->{max_key_length} || 20), + max(map { length($_) + 1 } grep { !ref $hash{$_} } keys %hash) + ); + my $customs = $options->{customs} || {}; + + # printf format for key + my $k_format = "%-${k_length}s"; + + while( @pairs ) { + my($key, $val) = splice @pairs, 0, 2; + $val = '~' unless defined $val; + if(ref $val eq 'HASH') { + if ( keys %$val ) { + my %k_options = ( # options for recursive call + delta => $options->{delta}, + use_header => 0, + indent => $indent . $options->{delta}, + ); + if (exists $customs->{$key}) { + my %k_custom = %{$customs->{$key}}; + foreach my $k qw(key_sort max_key_length customs) { + $k_options{$k} = $k_custom{$k} if exists $k_custom{$k}; + } + } + $yaml .= $indent . "$key:\n" + . _dump_hash(\%k_options, %$val); + } + else { + $yaml .= $indent . "$key: {}\n"; + } + } + elsif (ref $val eq 'ARRAY') { + if( @$val ) { + $yaml .= $indent . "$key:\n"; + + for (@$val) { + croak "only nested arrays of non-refs are supported" if ref $_; + $yaml .= $indent . $options->{delta} . "- $_\n"; + } + } + else { + $yaml .= $indent . "$key: []\n"; + } + } + elsif( ref $val and !blessed($val) ) { + croak "only nested hashes, arrays and objects are supported"; + } + else { # if it's an object, just stringify it + $yaml .= $indent . sprintf "$k_format %s\n", "$key:", $val; + } + }; + + return $yaml; + +} + +sub blessed { + return eval { $_[0]->isa("UNIVERSAL"); }; +} + +sub max { + return (sort { $b <=> $a } @_)[0]; +} + +sub min { + return (sort { $a <=> $b } @_)[0]; +} + +=head3 metafile_file + + my $meta_yml = $mm->metafile_file(@metadata_pairs); + +Turns the @metadata_pairs into YAML. + +This method does not implement a complete YAML dumper, being limited +to dump a hash with values which are strings, undef's or nested hashes +and arrays of strings. No quoting/escaping is done. + +=cut + +sub metafile_file { + my $self = shift; + + my %dump_options = ( + use_header => 1, + delta => ' ' x 4, + key_sort => undef, + ); + return _dump_hash(\%dump_options, @_); + +} + + +=head3 distmeta_target + + my $make_frag = $mm->distmeta_target; + +Generates the distmeta target to add META.yml to the MANIFEST in the +distdir. + +=cut + +sub distmeta_target { + my $self = shift; + + my $add_meta = $self->oneliner(<<'CODE', ['-MExtUtils::Manifest=maniadd']); +eval { maniadd({q{META.yml} => q{Module meta-data (added by MakeMaker)}}) } + or print "Could not add META.yml to MANIFEST: $${'@'}\n" +CODE + + my $add_meta_to_distdir = $self->cd('$(DISTVNAME)', $add_meta); + + return sprintf <<'MAKE', $add_meta_to_distdir; +distmeta : create_distdir metafile + $(NOECHO) %s + +MAKE + +} + + +=head3 realclean (o) + +Defines the realclean target. + +=cut + +sub realclean { + my($self, %attribs) = @_; + + my @dirs = qw($(DISTVNAME)); + my @files = qw($(FIRST_MAKEFILE) $(MAKEFILE_OLD)); + + # Special exception for the perl core where INST_* is not in blib. + # This cleans up the files built from the ext/ directory (all XS). + if( $self->{PERL_CORE} ) { + push @dirs, qw($(INST_AUTODIR) $(INST_ARCHAUTODIR)); + push @files, values %{$self->{PM}}; + } + + if( $self->has_link_code ){ + push @files, qw($(OBJECT)); + } + + if( $attribs{FILES} ) { + if( ref $attribs{FILES} ) { + push @dirs, @{ $attribs{FILES} }; + } + else { + push @dirs, split /\s+/, $attribs{FILES}; + } + } + + # Occasionally files are repeated several times from different sources + { my(%f) = map { ($_ => 1) } @files; @files = keys %f; } + { my(%d) = map { ($_ => 1) } @dirs; @dirs = keys %d; } + + my $rm_cmd = join "\n\t", map { "$_" } + $self->split_command('- $(RM_F)', @files); + my $rmf_cmd = join "\n\t", map { "$_" } + $self->split_command('- $(RM_RF)', @dirs); + + my $m = sprintf <<'MAKE', $rm_cmd, $rmf_cmd; +# Delete temporary files (via clean) and also delete dist files +realclean purge :: clean realclean_subdirs + %s + %s +MAKE + + $m .= "\t$attribs{POSTOP}\n" if $attribs{POSTOP}; + + return $m; +} + + +=head3 realclean_subdirs_target + + my $make_frag = $MM->realclean_subdirs_target; + +Returns the realclean_subdirs target. This is used by the realclean +target to call realclean on any subdirectories which contain Makefiles. + +=cut + +sub realclean_subdirs_target { + my $self = shift; + + return <<'NOOP_FRAG' unless @{$self->{DIR}}; +realclean_subdirs : + $(NOECHO) $(NOOP) +NOOP_FRAG + + my $rclean = "realclean_subdirs :\n"; + + foreach my $dir (@{$self->{DIR}}) { + foreach my $makefile ('$(MAKEFILE_OLD)', '$(FIRST_MAKEFILE)' ) { + my $subrclean .= $self->oneliner(sprintf <<'CODE', $dir, ($makefile) x 2); +chdir '%s'; system '$(MAKE) $(USEMAKEFILE) %s realclean' if -f '%s'; +CODE + + $rclean .= sprintf <<'RCLEAN', $subrclean; + - %s +RCLEAN + + } + } + + return $rclean; +} + + +=head3 signature_target + + my $target = $mm->signature_target; + +Generate the signature target. + +Writes the file SIGNATURE with "cpansign -s". + +=cut + +sub signature_target { + my $self = shift; + + return <<'MAKE_FRAG'; +signature : + cpansign -s +MAKE_FRAG + +} + + +=head3 distsignature_target + + my $make_frag = $mm->distsignature_target; + +Generates the distsignature target to add SIGNATURE to the MANIFEST in the +distdir. + +=cut + +sub distsignature_target { + my $self = shift; + + my $add_sign = $self->oneliner(<<'CODE', ['-MExtUtils::Manifest=maniadd']); +eval { maniadd({q{SIGNATURE} => q{Public-key signature (added by MakeMaker)}}) } + or print "Could not add SIGNATURE to MANIFEST: $${'@'}\n" +CODE + + my $sign_dist = $self->cd('$(DISTVNAME)' => 'cpansign -s'); + + # cpansign -s complains if SIGNATURE is in the MANIFEST yet does not + # exist + my $touch_sig = $self->cd('$(DISTVNAME)' => '$(TOUCH) SIGNATURE'); + my $add_sign_to_dist = $self->cd('$(DISTVNAME)' => $add_sign ); + + return sprintf <<'MAKE', $add_sign_to_dist, $touch_sig, $sign_dist +distsignature : create_distdir + $(NOECHO) %s + $(NOECHO) %s + %s + +MAKE + +} + + +=head3 special_targets + + my $make_frag = $mm->special_targets + +Returns a make fragment containing any targets which have special +meaning to make. For example, .SUFFIXES and .PHONY. + +=cut + +sub special_targets { + my $make_frag = <<'MAKE_FRAG'; +.SUFFIXES : .xs .c .C .cpp .i .s .cxx .cc $(OBJ_EXT) + +.PHONY: all config static dynamic test linkext manifest blibdirs clean realclean disttest distdir + +MAKE_FRAG + + $make_frag .= <<'MAKE_FRAG' if $ENV{CLEARCASE_ROOT}; +.NO_CONFIG_REC: Makefile + +MAKE_FRAG + + return $make_frag; +} + + + + +=head2 Init methods + +Methods which help initialize the MakeMaker object and macros. + + +=head3 init_ABSTRACT + + $mm->init_ABSTRACT + +=cut + +sub init_ABSTRACT { + my $self = shift; + + if( $self->{ABSTRACT_FROM} and $self->{ABSTRACT} ) { + warn "Both ABSTRACT_FROM and ABSTRACT are set. ". + "Ignoring ABSTRACT_FROM.\n"; + return; + } + + if ($self->{ABSTRACT_FROM}){ + $self->{ABSTRACT} = $self->parse_abstract($self->{ABSTRACT_FROM}) or + carp "WARNING: Setting ABSTRACT via file ". + "'$self->{ABSTRACT_FROM}' failed\n"; + } +} + +=head3 init_INST + + $mm->init_INST; + +Called by init_main. Sets up all INST_* variables except those related +to XS code. Those are handled in init_xs. + +=cut + +sub init_INST { + my($self) = shift; + + $self->{INST_ARCHLIB} ||= $self->catdir($Curdir,"blib","arch"); + $self->{INST_BIN} ||= $self->catdir($Curdir,'blib','bin'); + + # INST_LIB typically pre-set if building an extension after + # perl has been built and installed. Setting INST_LIB allows + # you to build directly into, say $Config{privlibexp}. + unless ($self->{INST_LIB}){ + if ($self->{PERL_CORE}) { + if (defined $Cross::platform) { + $self->{INST_LIB} = $self->{INST_ARCHLIB} = + $self->catdir($self->{PERL_LIB},"..","xlib", + $Cross::platform); + } + else { + $self->{INST_LIB} = $self->{INST_ARCHLIB} = $self->{PERL_LIB}; + } + } else { + $self->{INST_LIB} = $self->catdir($Curdir,"blib","lib"); + } + } + + my @parentdir = split(/::/, $self->{PARENT_NAME}); + $self->{INST_LIBDIR} = $self->catdir('$(INST_LIB)', @parentdir); + $self->{INST_ARCHLIBDIR} = $self->catdir('$(INST_ARCHLIB)', @parentdir); + $self->{INST_AUTODIR} = $self->catdir('$(INST_LIB)', 'auto', + '$(FULLEXT)'); + $self->{INST_ARCHAUTODIR} = $self->catdir('$(INST_ARCHLIB)', 'auto', + '$(FULLEXT)'); + + $self->{INST_SCRIPT} ||= $self->catdir($Curdir,'blib','script'); + + $self->{INST_MAN1DIR} ||= $self->catdir($Curdir,'blib','man1'); + $self->{INST_MAN3DIR} ||= $self->catdir($Curdir,'blib','man3'); + + return 1; +} + + +=head3 init_INSTALL + + $mm->init_INSTALL; + +Called by init_main. Sets up all INSTALL_* variables (except +INSTALLDIRS) and *PREFIX. + +=cut + +sub init_INSTALL { + my($self) = shift; + + if( $self->{ARGS}{INSTALL_BASE} and $self->{ARGS}{PREFIX} ) { + die "Only one of PREFIX or INSTALL_BASE can be given. Not both.\n"; + } + + if( $self->{ARGS}{INSTALL_BASE} ) { + $self->init_INSTALL_from_INSTALL_BASE; + } + else { + $self->init_INSTALL_from_PREFIX; + } +} + + +=head3 init_INSTALL_from_PREFIX + + $mm->init_INSTALL_from_PREFIX; + +=cut + +sub init_INSTALL_from_PREFIX { + my $self = shift; + + $self->init_lib2arch; + + # There are often no Config.pm defaults for these new man variables so + # we fall back to the old behavior which is to use installman*dir + foreach my $num (1, 3) { + my $k = 'installsiteman'.$num.'dir'; + + $self->{uc $k} ||= uc "\$(installman${num}dir)" + unless $Config{$k}; + } + + foreach my $num (1, 3) { + my $k = 'installvendorman'.$num.'dir'; + + unless( $Config{$k} ) { + $self->{uc $k} ||= $Config{usevendorprefix} + ? uc "\$(installman${num}dir)" + : ''; + } + } + + $self->{INSTALLSITEBIN} ||= '$(INSTALLBIN)' + unless $Config{installsitebin}; + $self->{INSTALLSITESCRIPT} ||= '$(INSTALLSCRIPT)' + unless $Config{installsitescript}; + + unless( $Config{installvendorbin} ) { + $self->{INSTALLVENDORBIN} ||= $Config{usevendorprefix} + ? $Config{installbin} + : ''; + } + unless( $Config{installvendorscript} ) { + $self->{INSTALLVENDORSCRIPT} ||= $Config{usevendorprefix} + ? $Config{installscript} + : ''; + } + + + my $iprefix = $Config{installprefixexp} || $Config{installprefix} || + $Config{prefixexp} || $Config{prefix} || ''; + my $vprefix = $Config{usevendorprefix} ? $Config{vendorprefixexp} : ''; + my $sprefix = $Config{siteprefixexp} || ''; + + # 5.005_03 doesn't have a siteprefix. + $sprefix = $iprefix unless $sprefix; + + + $self->{PREFIX} ||= ''; + + if( $self->{PREFIX} ) { + @{$self}{qw(PERLPREFIX SITEPREFIX VENDORPREFIX)} = + ('$(PREFIX)') x 3; + } + else { + $self->{PERLPREFIX} ||= $iprefix; + $self->{SITEPREFIX} ||= $sprefix; + $self->{VENDORPREFIX} ||= $vprefix; + + # Lots of MM extension authors like to use $(PREFIX) so we + # put something sensible in there no matter what. + $self->{PREFIX} = '$('.uc $self->{INSTALLDIRS}.'PREFIX)'; + } + + my $arch = $Config{archname}; + my $version = $Config{version}; + + # default style + my $libstyle = $Config{installstyle} || 'lib/perl5'; + my $manstyle = ''; + + if( $self->{LIBSTYLE} ) { + $libstyle = $self->{LIBSTYLE}; + $manstyle = $self->{LIBSTYLE} eq 'lib/perl5' ? 'lib/perl5' : ''; + } + + # Some systems, like VOS, set installman*dir to '' if they can't + # read man pages. + for my $num (1, 3) { + $self->{'INSTALLMAN'.$num.'DIR'} ||= 'none' + unless $Config{'installman'.$num.'dir'}; + } + + my %bin_layouts = + ( + bin => { s => $iprefix, + t => 'perl', + d => 'bin' }, + vendorbin => { s => $vprefix, + t => 'vendor', + d => 'bin' }, + sitebin => { s => $sprefix, + t => 'site', + d => 'bin' }, + script => { s => $iprefix, + t => 'perl', + d => 'bin' }, + vendorscript=> { s => $vprefix, + t => 'vendor', + d => 'bin' }, + sitescript => { s => $sprefix, + t => 'site', + d => 'bin' }, + ); + + my %man_layouts = + ( + man1dir => { s => $iprefix, + t => 'perl', + d => 'man/man1', + style => $manstyle, }, + siteman1dir => { s => $sprefix, + t => 'site', + d => 'man/man1', + style => $manstyle, }, + vendorman1dir => { s => $vprefix, + t => 'vendor', + d => 'man/man1', + style => $manstyle, }, + + man3dir => { s => $iprefix, + t => 'perl', + d => 'man/man3', + style => $manstyle, }, + siteman3dir => { s => $sprefix, + t => 'site', + d => 'man/man3', + style => $manstyle, }, + vendorman3dir => { s => $vprefix, + t => 'vendor', + d => 'man/man3', + style => $manstyle, }, + ); + + my %lib_layouts = + ( + privlib => { s => $iprefix, + t => 'perl', + d => '', + style => $libstyle, }, + vendorlib => { s => $vprefix, + t => 'vendor', + d => '', + style => $libstyle, }, + sitelib => { s => $sprefix, + t => 'site', + d => 'site_perl', + style => $libstyle, }, + + archlib => { s => $iprefix, + t => 'perl', + d => "$version/$arch", + style => $libstyle }, + vendorarch => { s => $vprefix, + t => 'vendor', + d => "$version/$arch", + style => $libstyle }, + sitearch => { s => $sprefix, + t => 'site', + d => "site_perl/$version/$arch", + style => $libstyle }, + ); + + + # Special case for LIB. + if( $self->{LIB} ) { + foreach my $var (keys %lib_layouts) { + my $Installvar = uc "install$var"; + + if( $var =~ /arch/ ) { + $self->{$Installvar} ||= + $self->catdir($self->{LIB}, $Config{archname}); + } + else { + $self->{$Installvar} ||= $self->{LIB}; + } + } + } + + my %type2prefix = ( perl => 'PERLPREFIX', + site => 'SITEPREFIX', + vendor => 'VENDORPREFIX' + ); + + my %layouts = (%bin_layouts, %man_layouts, %lib_layouts); + while( my($var, $layout) = each(%layouts) ) { + my($s, $t, $d, $style) = @{$layout}{qw(s t d style)}; + my $r = '$('.$type2prefix{$t}.')'; + + print STDERR "Prefixing $var\n" if $Verbose >= 2; + + my $installvar = "install$var"; + my $Installvar = uc $installvar; + next if $self->{$Installvar}; + + $d = "$style/$d" if $style; + $self->prefixify($installvar, $s, $r, $d); + + print STDERR " $Installvar == $self->{$Installvar}\n" + if $Verbose >= 2; + } + + # Generate these if they weren't figured out. + $self->{VENDORARCHEXP} ||= $self->{INSTALLVENDORARCH}; + $self->{VENDORLIBEXP} ||= $self->{INSTALLVENDORLIB}; + + return 1; +} + + +=head3 init_from_INSTALL_BASE + + $mm->init_from_INSTALL_BASE + +=cut + +my %map = ( + lib => [qw(lib perl5)], + arch => [('lib', 'perl5', $Config{archname})], + bin => [qw(bin)], + man1dir => [qw(man man1)], + man3dir => [qw(man man3)] + ); +$map{script} = $map{bin}; + +sub init_INSTALL_from_INSTALL_BASE { + my $self = shift; + + @{$self}{qw(PREFIX VENDORPREFIX SITEPREFIX PERLPREFIX)} = + '$(INSTALL_BASE)'; + + my %install; + foreach my $thing (keys %map) { + foreach my $dir (('', 'SITE', 'VENDOR')) { + my $uc_thing = uc $thing; + my $key = "INSTALL".$dir.$uc_thing; + + $install{$key} ||= + $self->catdir('$(INSTALL_BASE)', @{$map{$thing}}); + } + } + + # Adjust for variable quirks. + $install{INSTALLARCHLIB} ||= delete $install{INSTALLARCH}; + $install{INSTALLPRIVLIB} ||= delete $install{INSTALLLIB}; + + foreach my $key (keys %install) { + $self->{$key} ||= $install{$key}; + } + + return 1; +} + + +=head3 init_VERSION I<Abstract> + + $mm->init_VERSION + +Initialize macros representing versions of MakeMaker and other tools + +MAKEMAKER: path to the MakeMaker module. + +MM_VERSION: ExtUtils::MakeMaker Version + +MM_REVISION: ExtUtils::MakeMaker version control revision (for backwards + compat) + +VERSION: version of your module + +VERSION_MACRO: which macro represents the version (usually 'VERSION') + +VERSION_SYM: like version but safe for use as an RCS revision number + +DEFINE_VERSION: -D line to set the module version when compiling + +XS_VERSION: version in your .xs file. Defaults to $(VERSION) + +XS_VERSION_MACRO: which macro represents the XS version. + +XS_DEFINE_VERSION: -D line to set the xs version when compiling. + +Called by init_main. + +=cut + +sub init_VERSION { + my($self) = shift; + + $self->{MAKEMAKER} = $ExtUtils::MakeMaker::Filename; + $self->{MM_VERSION} = $ExtUtils::MakeMaker::VERSION; + $self->{MM_REVISION}= $ExtUtils::MakeMaker::Revision; + $self->{VERSION_FROM} ||= ''; + + if ($self->{VERSION_FROM}){ + $self->{VERSION} = $self->parse_version($self->{VERSION_FROM}); + if( $self->{VERSION} eq 'undef' ) { + carp("WARNING: Setting VERSION via file ". + "'$self->{VERSION_FROM}' failed\n"); + } + } + + # strip blanks + if (defined $self->{VERSION}) { + $self->{VERSION} =~ s/^\s+//; + $self->{VERSION} =~ s/\s+$//; + } + else { + $self->{VERSION} = ''; + } + + + $self->{VERSION_MACRO} = 'VERSION'; + ($self->{VERSION_SYM} = $self->{VERSION}) =~ s/\W/_/g; + $self->{DEFINE_VERSION} = '-D$(VERSION_MACRO)=\"$(VERSION)\"'; + + + # Graham Barr and Paul Marquess had some ideas how to ensure + # version compatibility between the *.pm file and the + # corresponding *.xs file. The bottomline was, that we need an + # XS_VERSION macro that defaults to VERSION: + $self->{XS_VERSION} ||= $self->{VERSION}; + + $self->{XS_VERSION_MACRO} = 'XS_VERSION'; + $self->{XS_DEFINE_VERSION} = '-D$(XS_VERSION_MACRO)=\"$(XS_VERSION)\"'; + +} + + +=head3 init_others + + $MM->init_others(); + +Initializes the macro definitions used by tools_other() and places them +in the $MM object. + +If there is no description, its the same as the parameter to +WriteMakefile() documented in ExtUtils::MakeMaker. + +Defines at least these macros. + + Macro Description + + NOOP Do nothing + NOECHO Tell make not to display the command itself + + MAKEFILE + FIRST_MAKEFILE + MAKEFILE_OLD + MAKE_APERL_FILE File used by MAKE_APERL + + SHELL Program used to run shell commands + + ECHO Print text adding a newline on the end + RM_F Remove a file + RM_RF Remove a directory + TOUCH Update a file's timestamp + TEST_F Test for a file's existence + CP Copy a file + MV Move a file + CHMOD Change permissions on a file + FALSE Exit with non-zero + TRUE Exit with zero + + UMASK_NULL Nullify umask + DEV_NULL Suppress all command output + +=cut + +sub init_others { + my $self = shift; + + $self->{ECHO} ||= $self->oneliner('print qq{@ARGV}', ['-l']); + $self->{ECHO_N} ||= $self->oneliner('print qq{@ARGV}'); + + $self->{TOUCH} ||= $self->oneliner('touch', ["-MExtUtils::Command"]); + $self->{CHMOD} ||= $self->oneliner('chmod', ["-MExtUtils::Command"]); + $self->{RM_F} ||= $self->oneliner('rm_f', ["-MExtUtils::Command"]); + $self->{RM_RF} ||= $self->oneliner('rm_rf', ["-MExtUtils::Command"]); + $self->{TEST_F} ||= $self->oneliner('test_f', ["-MExtUtils::Command"]); + $self->{FALSE} ||= $self->oneliner('exit 1'); + $self->{TRUE} ||= $self->oneliner('exit 0'); + + $self->{MKPATH} ||= $self->oneliner('mkpath', ["-MExtUtils::Command"]); + + $self->{CP} ||= $self->oneliner('cp', ["-MExtUtils::Command"]); + $self->{MV} ||= $self->oneliner('mv', ["-MExtUtils::Command"]); + + $self->{MOD_INSTALL} ||= + $self->oneliner(<<'CODE', ['-MExtUtils::Install']); +install([ from_to => {@ARGV}, verbose => '$(VERBINST)', uninstall_shadows => '$(UNINST)', dir_mode => '$(PERM_DIR)' ]); +CODE + $self->{DOC_INSTALL} ||= $self->oneliner('perllocal_install', ["-MExtUtils::Command::MM"]); + $self->{UNINSTALL} ||= $self->oneliner('uninstall', ["-MExtUtils::Command::MM"]); + $self->{WARN_IF_OLD_PACKLIST} ||= + $self->oneliner('warn_if_old_packlist', ["-MExtUtils::Command::MM"]); + $self->{FIXIN} ||= $self->oneliner('MY->fixin(shift)', ["-MExtUtils::MY"]); + $self->{EQUALIZE_TIMESTAMP} ||= $self->oneliner('eqtime', ["-MExtUtils::Command"]); + + $self->{UNINST} ||= 0; + $self->{VERBINST} ||= 0; + + $self->{FIRST_MAKEFILE} ||= $self->{MAKEFILE} || 'Makefile'; + $self->{MAKEFILE} ||= $self->{FIRST_MAKEFILE}; + $self->{MAKEFILE_OLD} ||= $self->{MAKEFILE}.'.old'; + $self->{MAKE_APERL_FILE} ||= $self->{MAKEFILE}.'.aperl'; + + # Not everybody uses -f to indicate "use this Makefile instead" + $self->{USEMAKEFILE} ||= '-f'; + + # Some makes require a wrapper around macros passed in on the command + # line. + $self->{MACROSTART} ||= ''; + $self->{MACROEND} ||= ''; + + $self->{SHELL} ||= $Config{sh}; + + # UMASK_NULL is not used by MakeMaker but some CPAN modules + # make use of it. + $self->{UMASK_NULL} ||= "umask 0"; + + # Not the greatest default, but its something. + $self->{DEV_NULL} ||= "> /dev/null 2>&1"; + + $self->{NOOP} ||= '$(TRUE)'; + $self->{NOECHO} = '@' unless defined $self->{NOECHO}; + + $self->{LD_RUN_PATH} = ""; + + $self->{LIBS} = $self->_fix_libs($self->{LIBS}); + + # Compute EXTRALIBS, BSLOADLIBS and LDLOADLIBS from $self->{LIBS} + foreach my $libs ( @{$self->{LIBS}} ){ + $libs =~ s/^\s*(.*\S)\s*$/$1/; # remove leading and trailing whitespace + my(@libs) = $self->extliblist($libs); + if ($libs[0] or $libs[1] or $libs[2]){ + # LD_RUN_PATH now computed by ExtUtils::Liblist + ($self->{EXTRALIBS}, $self->{BSLOADLIBS}, + $self->{LDLOADLIBS}, $self->{LD_RUN_PATH}) = @libs; + last; + } + } + + if ( $self->{OBJECT} ) { + $self->{OBJECT} =~ s!\.o(bj)?\b!\$(OBJ_EXT)!g; + } else { + # init_dirscan should have found out, if we have C files + $self->{OBJECT} = ""; + $self->{OBJECT} = '$(BASEEXT)$(OBJ_EXT)' if @{$self->{C}||[]}; + } + $self->{OBJECT} =~ s/\n+/ \\\n\t/g; + + $self->{BOOTDEP} = (-f "$self->{BASEEXT}_BS") ? "$self->{BASEEXT}_BS" : ""; + $self->{PERLMAINCC} ||= '$(CC)'; + $self->{LDFROM} = '$(OBJECT)' unless $self->{LDFROM}; + + # Sanity check: don't define LINKTYPE = dynamic if we're skipping + # the 'dynamic' section of MM. We don't have this problem with + # 'static', since we either must use it (%Config says we can't + # use dynamic loading) or the caller asked for it explicitly. + if (!$self->{LINKTYPE}) { + $self->{LINKTYPE} = $self->{SKIPHASH}{'dynamic'} + ? 'static' + : ($Config{usedl} ? 'dynamic' : 'static'); + } + + return 1; +} + + +# Lets look at $self->{LIBS} carefully: It may be an anon array, a string or +# undefined. In any case we turn it into an anon array +sub _fix_libs { + my($self, $libs) = @_; + + return !defined $libs ? [''] : + !ref $libs ? [$libs] : + !defined $libs->[0] ? [''] : + $libs ; +} + + +=head3 tools_other + + my $make_frag = $MM->tools_other; + +Returns a make fragment containing definitions for the macros init_others() +initializes. + +=cut + +sub tools_other { + my($self) = shift; + my @m; + + # We set PM_FILTER as late as possible so it can see all the earlier + # on macro-order sensitive makes such as nmake. + for my $tool (qw{ SHELL CHMOD CP MV NOOP NOECHO RM_F RM_RF TEST_F TOUCH + UMASK_NULL DEV_NULL MKPATH EQUALIZE_TIMESTAMP + FALSE TRUE + ECHO ECHO_N + UNINST VERBINST + MOD_INSTALL DOC_INSTALL UNINSTALL + WARN_IF_OLD_PACKLIST + MACROSTART MACROEND + USEMAKEFILE + PM_FILTER + FIXIN + } ) + { + next unless defined $self->{$tool}; + push @m, "$tool = $self->{$tool}\n"; + } + + return join "", @m; +} + + +=head3 init_DIRFILESEP I<Abstract> + + $MM->init_DIRFILESEP; + my $dirfilesep = $MM->{DIRFILESEP}; + +Initializes the DIRFILESEP macro which is the seperator between the +directory and filename in a filepath. ie. / on Unix, \ on Win32 and +nothing on VMS. + +For example: + + # instead of $(INST_ARCHAUTODIR)/extralibs.ld + $(INST_ARCHAUTODIR)$(DIRFILESEP)extralibs.ld + +Something of a hack but it prevents a lot of code duplication between +MM_* variants. + +Do not use this as a seperator between directories. Some operating +systems use different seperators between subdirectories as between +directories and filenames (for example: VOLUME:[dir1.dir2]file on VMS). + +=head3 init_linker I<Abstract> + + $mm->init_linker; + +Initialize macros which have to do with linking. + +PERL_ARCHIVE: path to libperl.a equivalent to be linked to dynamic +extensions. + +PERL_ARCHIVE_AFTER: path to a library which should be put on the +linker command line I<after> the external libraries to be linked to +dynamic extensions. This may be needed if the linker is one-pass, and +Perl includes some overrides for C RTL functions, such as malloc(). + +EXPORT_LIST: name of a file that is passed to linker to define symbols +to be exported. + +Some OSes do not need these in which case leave it blank. + + +=head3 init_platform + + $mm->init_platform + +Initialize any macros which are for platform specific use only. + +A typical one is the version number of your OS specific mocule. +(ie. MM_Unix_VERSION or MM_VMS_VERSION). + +=cut + +sub init_platform { + return ''; +} + + +=head3 init_MAKE + + $mm->init_MAKE + +Initialize MAKE from either a MAKE environment variable or $Config{make}. + +=cut + +sub init_MAKE { + my $self = shift; + + $self->{MAKE} ||= $ENV{MAKE} || $Config{make}; +} + + +=head2 Tools + +A grab bag of methods to generate specific macros and commands. + + + +=head3 manifypods + +Defines targets and routines to translate the pods into manpages and +put them into the INST_* directories. + +=cut + +sub manifypods { + my $self = shift; + + my $POD2MAN_macro = $self->POD2MAN_macro(); + my $manifypods_target = $self->manifypods_target(); + + return <<END_OF_TARGET; + +$POD2MAN_macro + +$manifypods_target + +END_OF_TARGET + +} + + +=head3 POD2MAN_macro + + my $pod2man_macro = $self->POD2MAN_macro + +Returns a definition for the POD2MAN macro. This is a program +which emulates the pod2man utility. You can add more switches to the +command by simply appending them on the macro. + +Typical usage: + + $(POD2MAN) --section=3 --perm_rw=$(PERM_RW) podfile1 man_page1 ... + +=cut + +sub POD2MAN_macro { + my $self = shift; + +# Need the trailing '--' so perl stops gobbling arguments and - happens +# to be an alternative end of line seperator on VMS so we quote it + return <<'END_OF_DEF'; +POD2MAN_EXE = $(PERLRUN) "-MExtUtils::Command::MM" -e pod2man "--" +POD2MAN = $(POD2MAN_EXE) +END_OF_DEF +} + + +=head3 test_via_harness + + my $command = $mm->test_via_harness($perl, $tests); + +Returns a $command line which runs the given set of $tests with +Test::Harness and the given $perl. + +Used on the t/*.t files. + +=cut + +sub test_via_harness { + my($self, $perl, $tests) = @_; + + return qq{\t$perl "-MExtUtils::Command::MM" }. + qq{"-e" "test_harness(\$(TEST_VERBOSE), '\$(INST_LIB)', '\$(INST_ARCHLIB)')" $tests\n}; +} + +=head3 test_via_script + + my $command = $mm->test_via_script($perl, $script); + +Returns a $command line which just runs a single test without +Test::Harness. No checks are done on the results, they're just +printed. + +Used for test.pl, since they don't always follow Test::Harness +formatting. + +=cut + +sub test_via_script { + my($self, $perl, $script) = @_; + return qq{\t$perl "-I\$(INST_LIB)" "-I\$(INST_ARCHLIB)" $script\n}; +} + + +=head3 tool_autosplit + +Defines a simple perl call that runs autosplit. May be deprecated by +pm_to_blib soon. + +=cut + +sub tool_autosplit { + my($self, %attribs) = @_; + + my $maxlen = $attribs{MAXLEN} ? '$$AutoSplit::Maxlen=$attribs{MAXLEN};' + : ''; + + my $asplit = $self->oneliner(sprintf <<'PERL_CODE', $maxlen); +use AutoSplit; %s autosplit($$ARGV[0], $$ARGV[1], 0, 1, 1) +PERL_CODE + + return sprintf <<'MAKE_FRAG', $asplit; +# Usage: $(AUTOSPLITFILE) FileToSplit AutoDirToSplitInto +AUTOSPLITFILE = %s + +MAKE_FRAG + +} + + +=head3 arch_check + + my $arch_ok = $mm->arch_check( + $INC{"Config.pm"}, + File::Spec->catfile($Config{archlibexp}, "Config.pm") + ); + +A sanity check that what Perl thinks the architecture is and what +Config thinks the architecture is are the same. If they're not it +will return false and show a diagnostic message. + +When building Perl it will always return true, as nothing is installed +yet. + +The interface is a bit odd because this is the result of a +quick refactoring. Don't rely on it. + +=cut + +sub arch_check { + my $self = shift; + my($pconfig, $cconfig) = @_; + + return 1 if $self->{PERL_SRC}; + + my($pvol, $pthinks) = $self->splitpath($pconfig); + my($cvol, $cthinks) = $self->splitpath($cconfig); + + $pthinks = $self->canonpath($pthinks); + $cthinks = $self->canonpath($cthinks); + + my $ret = 1; + if ($pthinks ne $cthinks) { + print "Have $pthinks\n"; + print "Want $cthinks\n"; + + $ret = 0; + + my $arch = (grep length, $self->splitdir($pthinks))[-1]; + + print STDOUT <<END unless $self->{UNINSTALLED_PERL}; +Your perl and your Config.pm seem to have different ideas about the +architecture they are running on. +Perl thinks: [$arch] +Config says: [$Config{archname}] +This may or may not cause problems. Please check your installation of perl +if you have problems building this extension. +END + } + + return $ret; +} + + + +=head2 File::Spec wrappers + +ExtUtils::MM_Any is a subclass of File::Spec. The methods noted here +override File::Spec. + + + +=head3 catfile + +File::Spec <= 0.83 has a bug where the file part of catfile is not +canonicalized. This override fixes that bug. + +=cut + +sub catfile { + my $self = shift; + return $self->canonpath($self->SUPER::catfile(@_)); +} + + + +=head2 Misc + +Methods I can't really figure out where they should go yet. + + +=head3 find_tests + + my $test = $mm->find_tests; + +Returns a string suitable for feeding to the shell to return all +tests in t/*.t. + +=cut + +sub find_tests { + my($self) = shift; + return -d 't' ? 't/*.t' : ''; +} + + +=head3 extra_clean_files + + my @files_to_clean = $MM->extra_clean_files; + +Returns a list of OS specific files to be removed in the clean target in +addition to the usual set. + +=cut + +# An empty method here tickled a perl 5.8.1 bug and would return its object. +sub extra_clean_files { + return; +} + + +=head3 installvars + + my @installvars = $mm->installvars; + +A list of all the INSTALL* variables without the INSTALL prefix. Useful +for iteration or building related variable sets. + +=cut + +sub installvars { + return qw(PRIVLIB SITELIB VENDORLIB + ARCHLIB SITEARCH VENDORARCH + BIN SITEBIN VENDORBIN + SCRIPT SITESCRIPT VENDORSCRIPT + MAN1DIR SITEMAN1DIR VENDORMAN1DIR + MAN3DIR SITEMAN3DIR VENDORMAN3DIR + ); +} + + +=head3 libscan + + my $wanted = $self->libscan($path); + +Takes a path to a file or dir and returns an empty string if we don't +want to include this file in the library. Otherwise it returns the +the $path unchanged. + +Mainly used to exclude version control administrative directories from +installation. + +=cut + +sub libscan { + my($self,$path) = @_; + my($dirs,$file) = ($self->splitpath($path))[1,2]; + return '' if grep /^(?:RCS|CVS|SCCS|\.svn|_darcs)$/, + $self->splitdir($dirs), $file; + + return $path; +} + + +=head3 platform_constants + + my $make_frag = $mm->platform_constants + +Returns a make fragment defining all the macros initialized in +init_platform() rather than put them in constants(). + +=cut + +sub platform_constants { + return ''; +} + +=begin private + +=head3 _PREREQ_PRINT + + $self->_PREREQ_PRINT; + +Implements PREREQ_PRINT. + +Refactored out of MakeMaker->new(). + +=end private + +=cut + +sub _PREREQ_PRINT { + my $self = shift; + + require Data::Dumper; + my @what = ('PREREQ_PM'); + push @what, 'MIN_PERL_VERSION' if $self->{MIN_PERL_VERSION}; + push @what, 'BUILD_REQUIRES' if $self->{BUILD_REQUIRES}; + print Data::Dumper->Dump([@{$self}{@what}], \@what); + exit 0; +} + + +=begin private + +=head3 _PRINT_PREREQ + + $mm->_PRINT_PREREQ; + +Implements PRINT_PREREQ, a slightly different version of PREREQ_PRINT +added by Redhat to, I think, support generating RPMs from Perl modules. + +Should not include BUILD_REQUIRES as RPMs do not incluide them. + +Refactored out of MakeMaker->new(). + +=end private + +=cut + +sub _PRINT_PREREQ { + my $self = shift; + + my $prereqs= $self->{PREREQ_PM}; + my @prereq = map { [$_, $prereqs->{$_}] } keys %$prereqs; + + if ( $self->{MIN_PERL_VERSION} ) { + push @prereq, ['perl' => $self->{MIN_PERL_VERSION}]; + } + + print join(" ", map { "perl($_->[0])>=$_->[1] " } + sort { $a->[0] cmp $b->[0] } @prereq), "\n"; + exit 0; +} + + +=begin private + +=head3 _all_prereqs + + my $prereqs = $self->_all_prereqs; + +Returns a hash ref of both PREREQ_PM and BUILD_REQUIRES. + +=end private + +=cut + +sub _all_prereqs { + my $self = shift; + + return { %{$self->{PREREQ_PM}}, %{$self->{BUILD_REQUIRES}} }; +} + + +=head1 AUTHOR + +Michael G Schwern <schwern@pobox.com> and the denizens of +makemaker@perl.org with code from ExtUtils::MM_Unix and +ExtUtils::MM_Win32. + + +=cut + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MM_BeOS.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MM_BeOS.pm new file mode 100644 index 00000000000..0b7c8db9225 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MM_BeOS.pm @@ -0,0 +1,61 @@ +package ExtUtils::MM_BeOS; + +use strict; + +=head1 NAME + +ExtUtils::MM_BeOS - methods to override UN*X behaviour in ExtUtils::MakeMaker + +=head1 SYNOPSIS + + use ExtUtils::MM_BeOS; # Done internally by ExtUtils::MakeMaker if needed + +=head1 DESCRIPTION + +See ExtUtils::MM_Unix for a documentation of the methods provided +there. This package overrides the implementation of these methods, not +the semantics. + +=over 4 + +=cut + +use ExtUtils::MakeMaker::Config; +use File::Spec; +require ExtUtils::MM_Any; +require ExtUtils::MM_Unix; + +our @ISA = qw( ExtUtils::MM_Any ExtUtils::MM_Unix ); +our $VERSION = '6.56'; + + +=item os_flavor + +BeOS is BeOS. + +=cut + +sub os_flavor { + return('BeOS'); +} + +=item init_linker + +libperl.a equivalent to be linked to dynamic extensions. + +=cut + +sub init_linker { + my($self) = shift; + + $self->{PERL_ARCHIVE} ||= + File::Spec->catdir('$(PERL_INC)',$Config{libperl}); + $self->{PERL_ARCHIVE_AFTER} ||= ''; + $self->{EXPORT_LIST} ||= ''; +} + +=back + +1; +__END__ + diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MM_Cygwin.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MM_Cygwin.pm new file mode 100644 index 00000000000..394fbc68a75 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MM_Cygwin.pm @@ -0,0 +1,123 @@ +package ExtUtils::MM_Cygwin; + +use strict; + +use ExtUtils::MakeMaker::Config; +use File::Spec; + +require ExtUtils::MM_Unix; +require ExtUtils::MM_Win32; +our @ISA = qw( ExtUtils::MM_Unix ); + +our $VERSION = '6.56'; + + +=head1 NAME + +ExtUtils::MM_Cygwin - methods to override UN*X behaviour in ExtUtils::MakeMaker + +=head1 SYNOPSIS + + use ExtUtils::MM_Cygwin; # Done internally by ExtUtils::MakeMaker if needed + +=head1 DESCRIPTION + +See ExtUtils::MM_Unix for a documentation of the methods provided there. + +=over 4 + +=item os_flavor + +We're Unix and Cygwin. + +=cut + +sub os_flavor { + return('Unix', 'Cygwin'); +} + +=item cflags + +if configured for dynamic loading, triggers #define EXT in EXTERN.h + +=cut + +sub cflags { + my($self,$libperl)=@_; + return $self->{CFLAGS} if $self->{CFLAGS}; + return '' unless $self->needs_linking(); + + my $base = $self->SUPER::cflags($libperl); + foreach (split /\n/, $base) { + /^(\S*)\s*=\s*(\S*)$/ and $self->{$1} = $2; + }; + $self->{CCFLAGS} .= " -DUSEIMPORTLIB" if ($Config{useshrplib} eq 'true'); + + return $self->{CFLAGS} = qq{ +CCFLAGS = $self->{CCFLAGS} +OPTIMIZE = $self->{OPTIMIZE} +PERLTYPE = $self->{PERLTYPE} +}; + +} + + +=item replace_manpage_separator + +replaces strings '::' with '.' in MAN*POD man page names + +=cut + +sub replace_manpage_separator { + my($self, $man) = @_; + $man =~ s{/+}{.}g; + return $man; +} + +=item init_linker + +points to libperl.a + +=cut + +sub init_linker { + my $self = shift; + + if ($Config{useshrplib} eq 'true') { + my $libperl = '$(PERL_INC)' .'/'. "$Config{libperl}"; + if( $] >= 5.006002 ) { + $libperl =~ s/a$/dll.a/; + } + $self->{PERL_ARCHIVE} = $libperl; + } else { + $self->{PERL_ARCHIVE} = + '$(PERL_INC)' .'/'. ("$Config{libperl}" or "libperl.a"); + } + + $self->{PERL_ARCHIVE_AFTER} ||= ''; + $self->{EXPORT_LIST} ||= ''; +} + +=item maybe_command + +If our path begins with F</cygdrive/> then we use C<ExtUtils::MM_Win32> +to determine if it may be a command. Otherwise we use the tests +from C<ExtUtils::MM_Unix>. + +=cut + +sub maybe_command { + my ($self, $file) = @_; + + if ($file =~ m{^/cygdrive/}i) { + return ExtUtils::MM_Win32->maybe_command($file); + } + + return $self->SUPER::maybe_command($file); +} + +=back + +=cut + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MM_DOS.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MM_DOS.pm new file mode 100644 index 00000000000..fc0a7947235 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MM_DOS.pm @@ -0,0 +1,65 @@ +package ExtUtils::MM_DOS; + +use strict; + +our $VERSION = 6.56; + +require ExtUtils::MM_Any; +require ExtUtils::MM_Unix; +our @ISA = qw( ExtUtils::MM_Any ExtUtils::MM_Unix ); + + +=head1 NAME + +ExtUtils::MM_DOS - DOS specific subclass of ExtUtils::MM_Unix + +=head1 SYNOPSIS + + Don't use this module directly. + Use ExtUtils::MM and let it choose. + +=head1 DESCRIPTION + +This is a subclass of ExtUtils::MM_Unix which contains functionality +for DOS. + +Unless otherwise stated, it works just like ExtUtils::MM_Unix + +=head2 Overridden methods + +=over 4 + +=item os_flavor + +=cut + +sub os_flavor { + return('DOS'); +} + +=item B<replace_manpage_separator> + +Generates Foo__Bar.3 style man page names + +=cut + +sub replace_manpage_separator { + my($self, $man) = @_; + + $man =~ s,/+,__,g; + return $man; +} + +=back + +=head1 AUTHOR + +Michael G Schwern <schwern@pobox.com> with code from ExtUtils::MM_Unix + +=head1 SEE ALSO + +L<ExtUtils::MM_Unix>, L<ExtUtils::MakeMaker> + +=cut + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MM_Darwin.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MM_Darwin.pm new file mode 100644 index 00000000000..1cb87c78815 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MM_Darwin.pm @@ -0,0 +1,47 @@ +package ExtUtils::MM_Darwin; + +use strict; + +BEGIN { + require ExtUtils::MM_Unix; + our @ISA = qw( ExtUtils::MM_Unix ); +} + +our $VERSION = '6.56'; + + +=head1 NAME + +ExtUtils::MM_Darwin - special behaviors for OS X + +=head1 SYNOPSIS + + For internal MakeMaker use only + +=head1 DESCRIPTION + +See L<ExtUtils::MM_Unix> for L<ExtUtils::MM_Any> for documention on the +methods overridden here. + +=head2 Overriden Methods + +=head3 init_dist + +Turn off Apple tar's tendency to copy resource forks as "._foo" files. + +=cut + +sub init_dist { + my $self = shift; + + # Thank you, Apple, for breaking tar and then breaking the work around. + # 10.4 wants COPY_EXTENDED_ATTRIBUTES_DISABLE while 10.5 wants + # COPYFILE_DISABLE. I'm not going to push my luck and instead just + # set both. + $self->{TAR} ||= + 'COPY_EXTENDED_ATTRIBUTES_DISABLE=1 COPYFILE_DISABLE=1 tar'; + + $self->SUPER::init_dist(@_); +} + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MM_MacOS.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MM_MacOS.pm new file mode 100644 index 00000000000..cfc82051e1b --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MM_MacOS.pm @@ -0,0 +1,40 @@ +package ExtUtils::MM_MacOS; + +use strict; + +our $VERSION = 6.56; + +sub new { + die <<'UNSUPPORTED'; +MacOS Classic (MacPerl) is no longer supported by MakeMaker. +Please use Module::Build instead. +UNSUPPORTED +} + +=head1 NAME + +ExtUtils::MM_MacOS - once produced Makefiles for MacOS Classic + +=head1 SYNOPSIS + + # MM_MacOS no longer contains any code. This is just a stub. + +=head1 DESCRIPTION + +Once upon a time, MakeMaker could produce an approximation of a correct +Makefile on MacOS Classic (MacPerl). Due to a lack of maintainers, this +fell out of sync with the rest of MakeMaker and hadn't worked in years. +Since there's little chance of it being repaired, MacOS Classic is fading +away, and the code was icky to begin with, the code has been deleted to +make maintenance easier. + +Those interested in writing modules for MacPerl should use Module::Build +which works better than MakeMaker ever did. + +Anyone interested in resurrecting this file should pull the old version +from the MakeMaker CVS repository and contact makemaker@perl.org, but we +really encourage you to work on Module::Build instead. + +=cut + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MM_NW5.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MM_NW5.pm new file mode 100644 index 00000000000..0c8f6c0affb --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MM_NW5.pm @@ -0,0 +1,269 @@ +package ExtUtils::MM_NW5; + +=head1 NAME + +ExtUtils::MM_NW5 - methods to override UN*X behaviour in ExtUtils::MakeMaker + +=head1 SYNOPSIS + + use ExtUtils::MM_NW5; # Done internally by ExtUtils::MakeMaker if needed + +=head1 DESCRIPTION + +See ExtUtils::MM_Unix for a documentation of the methods provided +there. This package overrides the implementation of these methods, not +the semantics. + +=over + +=cut + +use strict; +use ExtUtils::MakeMaker::Config; +use File::Basename; + +our $VERSION = '6.56'; + +require ExtUtils::MM_Win32; +our @ISA = qw(ExtUtils::MM_Win32); + +use ExtUtils::MakeMaker qw( &neatvalue ); + +$ENV{EMXSHELL} = 'sh'; # to run `commands` + +my $BORLAND = $Config{'cc'} =~ /^bcc/i; +my $GCC = $Config{'cc'} =~ /^gcc/i; + + +=item os_flavor + +We're Netware in addition to being Windows. + +=cut + +sub os_flavor { + my $self = shift; + return ($self->SUPER::os_flavor, 'Netware'); +} + +=item init_platform + +Add Netware macros. + +LIBPTH, BASE_IMPORT, NLM_VERSION, MPKTOOL, TOOLPATH, BOOT_SYMBOL, +NLM_SHORT_NAME, INCLUDE, PATH, MM_NW5_REVISION + + +=item platform_constants + +Add Netware macros initialized above to the Makefile. + +=cut + +sub init_platform { + my($self) = shift; + + # To get Win32's setup. + $self->SUPER::init_platform; + + # incpath is copied to makefile var INCLUDE in constants sub, here just + # make it empty + my $libpth = $Config{'libpth'}; + $libpth =~ s( )(;); + $self->{'LIBPTH'} = $libpth; + + $self->{'BASE_IMPORT'} = $Config{'base_import'}; + + # Additional import file specified from Makefile.pl + if($self->{'base_import'}) { + $self->{'BASE_IMPORT'} .= ', ' . $self->{'base_import'}; + } + + $self->{'NLM_VERSION'} = $Config{'nlm_version'}; + $self->{'MPKTOOL'} = $Config{'mpktool'}; + $self->{'TOOLPATH'} = $Config{'toolpath'}; + + (my $boot = $self->{'NAME'}) =~ s/:/_/g; + $self->{'BOOT_SYMBOL'}=$boot; + + # If the final binary name is greater than 8 chars, + # truncate it here. + if(length($self->{'BASEEXT'}) > 8) { + $self->{'NLM_SHORT_NAME'} = substr($self->{'BASEEXT'},0,8); + } + + # Get the include path and replace the spaces with ; + # Copy this to makefile as INCLUDE = d:\...;d:\; + ($self->{INCLUDE} = $Config{'incpath'}) =~ s/([ ]*)-I/;/g; + + # Set the path to CodeWarrior binaries which might not have been set in + # any other place + $self->{PATH} = '$(PATH);$(TOOLPATH)'; + + $self->{MM_NW5_VERSION} = $VERSION; +} + +sub platform_constants { + my($self) = shift; + my $make_frag = ''; + + # Setup Win32's constants. + $make_frag .= $self->SUPER::platform_constants; + + foreach my $macro (qw(LIBPTH BASE_IMPORT NLM_VERSION MPKTOOL + TOOLPATH BOOT_SYMBOL NLM_SHORT_NAME INCLUDE PATH + MM_NW5_VERSION + )) + { + next unless defined $self->{$macro}; + $make_frag .= "$macro = $self->{$macro}\n"; + } + + return $make_frag; +} + + +=item const_cccmd + +=cut + +sub const_cccmd { + my($self,$libperl)=@_; + return $self->{CONST_CCCMD} if $self->{CONST_CCCMD}; + return '' unless $self->needs_linking(); + return $self->{CONST_CCCMD} = <<'MAKE_FRAG'; +CCCMD = $(CC) $(CCFLAGS) $(INC) $(OPTIMIZE) \ + $(PERLTYPE) $(MPOLLUTE) -o $@ \ + -DVERSION=\"$(VERSION)\" -DXS_VERSION=\"$(XS_VERSION)\" +MAKE_FRAG + +} + + +=item static_lib + +=cut + +sub static_lib { + my($self) = @_; + + return '' unless $self->has_link_code; + + my $m = <<'END'; +$(INST_STATIC): $(OBJECT) $(MYEXTLIB) $(INST_ARCHAUTODIR)$(DFSEP).exists + $(RM_RF) $@ +END + + # If this extension has it's own library (eg SDBM_File) + # then copy that to $(INST_STATIC) and add $(OBJECT) into it. + $m .= <<'END' if $self->{MYEXTLIB}; + $self->{CP} $(MYEXTLIB) $@ +END + + my $ar_arg; + if( $BORLAND ) { + $ar_arg = '$@ $(OBJECT:^"+")'; + } + elsif( $GCC ) { + $ar_arg = '-ru $@ $(OBJECT)'; + } + else { + $ar_arg = '-type library -o $@ $(OBJECT)'; + } + + $m .= sprintf <<'END', $ar_arg; + $(AR) %s + $(NOECHO) $(ECHO) "$(EXTRALIBS)" > $(INST_ARCHAUTODIR)\extralibs.ld + $(CHMOD) 755 $@ +END + + $m .= <<'END' if $self->{PERL_SRC}; + $(NOECHO) $(ECHO) "$(EXTRALIBS)" >> $(PERL_SRC)\ext.libs + + +END + return $m; +} + +=item dynamic_lib + +Defines how to produce the *.so (or equivalent) files. + +=cut + +sub dynamic_lib { + my($self, %attribs) = @_; + return '' unless $self->needs_linking(); #might be because of a subdir + + return '' unless $self->has_link_code; + + my($otherldflags) = $attribs{OTHERLDFLAGS} || ($BORLAND ? 'c0d32.obj': ''); + my($inst_dynamic_dep) = $attribs{INST_DYNAMIC_DEP} || ""; + my($ldfrom) = '$(LDFROM)'; + + (my $boot = $self->{NAME}) =~ s/:/_/g; + + my $m = <<'MAKE_FRAG'; +# This section creates the dynamically loadable $(INST_DYNAMIC) +# from $(OBJECT) and possibly $(MYEXTLIB). +OTHERLDFLAGS = '.$otherldflags.' +INST_DYNAMIC_DEP = '.$inst_dynamic_dep.' + +# Create xdc data for an MT safe NLM in case of mpk build +$(INST_DYNAMIC): $(OBJECT) $(MYEXTLIB) $(BOOTSTRAP) $(INST_ARCHAUTODIR)$(DFSEP).exists + $(NOECHO) $(ECHO) Export boot_$(BOOT_SYMBOL) > $(BASEEXT).def + $(NOECHO) $(ECHO) $(BASE_IMPORT) >> $(BASEEXT).def + $(NOECHO) $(ECHO) Import @$(PERL_INC)\perl.imp >> $(BASEEXT).def +MAKE_FRAG + + + if ( $self->{CCFLAGS} =~ m/ -DMPK_ON /) { + $m .= <<'MAKE_FRAG'; + $(MPKTOOL) $(XDCFLAGS) $(BASEEXT).xdc + $(NOECHO) $(ECHO) xdcdata $(BASEEXT).xdc >> $(BASEEXT).def +MAKE_FRAG + } + + # Reconstruct the X.Y.Z version. + my $version = join '.', map { sprintf "%d", $_ } + $] =~ /(\d)\.(\d{3})(\d{2})/; + $m .= sprintf ' $(LD) $(LDFLAGS) $(OBJECT:.obj=.obj) -desc "Perl %s Extension ($(BASEEXT)) XS_VERSION: $(XS_VERSION)" -nlmversion $(NLM_VERSION)', $version; + + # Taking care of long names like FileHandle, ByteLoader, SDBM_File etc + if($self->{NLM_SHORT_NAME}) { + # In case of nlms with names exceeding 8 chars, build nlm in the + # current dir, rename and move to auto\lib. + $m .= q{ -o $(NLM_SHORT_NAME).$(DLEXT)} + } else { + $m .= q{ -o $(INST_AUTODIR)\\$(BASEEXT).$(DLEXT)} + } + + # Add additional lib files if any (SDBM_File) + $m .= q{ $(MYEXTLIB) } if $self->{MYEXTLIB}; + + $m .= q{ $(PERL_INC)\Main.lib -commandfile $(BASEEXT).def}."\n"; + + if($self->{NLM_SHORT_NAME}) { + $m .= <<'MAKE_FRAG'; + if exist $(INST_AUTODIR)\$(NLM_SHORT_NAME).$(DLEXT) del $(INST_AUTODIR)\$(NLM_SHORT_NAME).$(DLEXT) + move $(NLM_SHORT_NAME).$(DLEXT) $(INST_AUTODIR) +MAKE_FRAG + } + + $m .= <<'MAKE_FRAG'; + + $(CHMOD) 755 $@ +MAKE_FRAG + + return $m; +} + + +1; +__END__ + +=back + +=cut + + diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MM_OS2.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MM_OS2.pm new file mode 100644 index 00000000000..680502baf24 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MM_OS2.pm @@ -0,0 +1,152 @@ +package ExtUtils::MM_OS2; + +use strict; + +use ExtUtils::MakeMaker qw(neatvalue); +use File::Spec; + +our $VERSION = '6.56'; + +require ExtUtils::MM_Any; +require ExtUtils::MM_Unix; +our @ISA = qw(ExtUtils::MM_Any ExtUtils::MM_Unix); + +=pod + +=head1 NAME + +ExtUtils::MM_OS2 - methods to override UN*X behaviour in ExtUtils::MakeMaker + +=head1 SYNOPSIS + + use ExtUtils::MM_OS2; # Done internally by ExtUtils::MakeMaker if needed + +=head1 DESCRIPTION + +See ExtUtils::MM_Unix for a documentation of the methods provided +there. This package overrides the implementation of these methods, not +the semantics. + +=head1 METHODS + +=over 4 + +=item init_dist + +Define TO_UNIX to convert OS2 linefeeds to Unix style. + +=cut + +sub init_dist { + my($self) = @_; + + $self->{TO_UNIX} ||= <<'MAKE_TEXT'; +$(NOECHO) $(TEST_F) tmp.zip && $(RM_F) tmp.zip; $(ZIP) -ll -mr tmp.zip $(DISTVNAME) && unzip -o tmp.zip && $(RM_F) tmp.zip +MAKE_TEXT + + $self->SUPER::init_dist; +} + +sub dlsyms { + my($self,%attribs) = @_; + + my($funcs) = $attribs{DL_FUNCS} || $self->{DL_FUNCS} || {}; + my($vars) = $attribs{DL_VARS} || $self->{DL_VARS} || []; + my($funclist) = $attribs{FUNCLIST} || $self->{FUNCLIST} || []; + my($imports) = $attribs{IMPORTS} || $self->{IMPORTS} || {}; + my(@m); + (my $boot = $self->{NAME}) =~ s/:/_/g; + + if (not $self->{SKIPHASH}{'dynamic'}) { + push(@m," +$self->{BASEEXT}.def: Makefile.PL +", + ' $(PERL) "-I$(PERL_ARCHLIB)" "-I$(PERL_LIB)" -e \'use ExtUtils::Mksymlists; \\ + Mksymlists("NAME" => "$(NAME)", "DLBASE" => "$(DLBASE)", ', + '"VERSION" => "$(VERSION)", "DISTNAME" => "$(DISTNAME)", ', + '"INSTALLDIRS" => "$(INSTALLDIRS)", ', + '"DL_FUNCS" => ',neatvalue($funcs), + ', "FUNCLIST" => ',neatvalue($funclist), + ', "IMPORTS" => ',neatvalue($imports), + ', "DL_VARS" => ', neatvalue($vars), ');\' +'); + } + if ($self->{IMPORTS} && %{$self->{IMPORTS}}) { + # Make import files (needed for static build) + -d 'tmp_imp' or mkdir 'tmp_imp', 0777 or die "Can't mkdir tmp_imp"; + open my $imp, '>', 'tmpimp.imp' or die "Can't open tmpimp.imp"; + while (my($name, $exp) = each %{$self->{IMPORTS}}) { + my ($lib, $id) = ($exp =~ /(.*)\.(.*)/) or die "Malformed IMPORT `$exp'"; + print $imp "$name $lib $id ?\n"; + } + close $imp or die "Can't close tmpimp.imp"; + # print "emximp -o tmpimp$Config::Config{lib_ext} tmpimp.imp\n"; + system "emximp -o tmpimp$Config::Config{lib_ext} tmpimp.imp" + and die "Cannot make import library: $!, \$?=$?"; + # May be running under miniperl, so have no glob... + eval "unlink <tmp_imp/*>; 1" or system "rm tmp_imp/*"; + system "cd tmp_imp; $Config::Config{ar} x ../tmpimp$Config::Config{lib_ext}" + and die "Cannot extract import objects: $!, \$?=$?"; + } + join('',@m); +} + +sub static_lib { + my($self) = @_; + my $old = $self->ExtUtils::MM_Unix::static_lib(); + return $old unless $self->{IMPORTS} && %{$self->{IMPORTS}}; + + my @chunks = split /\n{2,}/, $old; + shift @chunks unless length $chunks[0]; # Empty lines at the start + $chunks[0] .= <<'EOC'; + + $(AR) $(AR_STATIC_ARGS) $@ tmp_imp/* && $(RANLIB) $@ +EOC + return join "\n\n". '', @chunks; +} + +sub replace_manpage_separator { + my($self,$man) = @_; + $man =~ s,/+,.,g; + $man; +} + +sub maybe_command { + my($self,$file) = @_; + $file =~ s,[/\\]+,/,g; + return $file if -x $file && ! -d _; + return "$file.exe" if -x "$file.exe" && ! -d _; + return "$file.cmd" if -x "$file.cmd" && ! -d _; + return; +} + +=item init_linker + +=cut + +sub init_linker { + my $self = shift; + + $self->{PERL_ARCHIVE} = "\$(PERL_INC)/libperl\$(LIB_EXT)"; + + $self->{PERL_ARCHIVE_AFTER} = $OS2::is_aout + ? '' + : '$(PERL_INC)/libperl_override$(LIB_EXT)'; + $self->{EXPORT_LIST} = '$(BASEEXT).def'; +} + +=item os_flavor + +OS/2 is OS/2 + +=cut + +sub os_flavor { + return('OS/2'); +} + +=back + +=cut + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MM_QNX.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MM_QNX.pm new file mode 100644 index 00000000000..f78d5e8a9ee --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MM_QNX.pm @@ -0,0 +1,57 @@ +package ExtUtils::MM_QNX; + +use strict; +our $VERSION = '6.56'; + +require ExtUtils::MM_Unix; +our @ISA = qw(ExtUtils::MM_Unix); + + +=head1 NAME + +ExtUtils::MM_QNX - QNX specific subclass of ExtUtils::MM_Unix + +=head1 SYNOPSIS + + Don't use this module directly. + Use ExtUtils::MM and let it choose. + +=head1 DESCRIPTION + +This is a subclass of ExtUtils::MM_Unix which contains functionality for +QNX. + +Unless otherwise stated it works just like ExtUtils::MM_Unix + +=head2 Overridden methods + +=head3 extra_clean_files + +Add .err files corresponding to each .c file. + +=cut + +sub extra_clean_files { + my $self = shift; + + my @errfiles = @{$self->{C}}; + for ( @errfiles ) { + s/.c$/.err/; + } + + return( @errfiles, 'perlmain.err' ); +} + + +=head1 AUTHOR + +Michael G Schwern <schwern@pobox.com> with code from ExtUtils::MM_Unix + +=head1 SEE ALSO + +L<ExtUtils::MakeMaker> + +=cut + + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MM_UWIN.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MM_UWIN.pm new file mode 100644 index 00000000000..5adc46ea8d2 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MM_UWIN.pm @@ -0,0 +1,64 @@ +package ExtUtils::MM_UWIN; + +use strict; +our $VERSION = 6.56; + +require ExtUtils::MM_Unix; +our @ISA = qw(ExtUtils::MM_Unix); + + +=head1 NAME + +ExtUtils::MM_UWIN - U/WIN specific subclass of ExtUtils::MM_Unix + +=head1 SYNOPSIS + + Don't use this module directly. + Use ExtUtils::MM and let it choose. + +=head1 DESCRIPTION + +This is a subclass of ExtUtils::MM_Unix which contains functionality for +the AT&T U/WIN UNIX on Windows environment. + +Unless otherwise stated it works just like ExtUtils::MM_Unix + +=head2 Overridden methods + +=over 4 + +=item os_flavor + +In addition to being Unix, we're U/WIN. + +=cut + +sub os_flavor { + return('Unix', 'U/WIN'); +} + + +=item B<replace_manpage_separator> + +=cut + +sub replace_manpage_separator { + my($self, $man) = @_; + + $man =~ s,/+,.,g; + return $man; +} + +=back + +=head1 AUTHOR + +Michael G Schwern <schwern@pobox.com> with code from ExtUtils::MM_Unix + +=head1 SEE ALSO + +L<ExtUtils::MM_Win32>, L<ExtUtils::MakeMaker> + +=cut + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MM_Unix.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MM_Unix.pm new file mode 100644 index 00000000000..239d6df826c --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MM_Unix.pm @@ -0,0 +1,3634 @@ +package ExtUtils::MM_Unix; + +require 5.006; + +use strict; + +use Carp; +use ExtUtils::MakeMaker::Config; +use File::Basename qw(basename dirname); +use DirHandle; + +our %Config_Override; + +use ExtUtils::MakeMaker qw($Verbose neatvalue); + +# If we make $VERSION an our variable parse_version() breaks +use vars qw($VERSION); +$VERSION = '6.56'; + +require ExtUtils::MM_Any; +our @ISA = qw(ExtUtils::MM_Any); + +my %Is; +BEGIN { + $Is{OS2} = $^O eq 'os2'; + $Is{Win32} = $^O eq 'MSWin32' || $Config{osname} eq 'NetWare'; + $Is{Dos} = $^O eq 'dos'; + $Is{VMS} = $^O eq 'VMS'; + $Is{OSF} = $^O eq 'dec_osf'; + $Is{IRIX} = $^O eq 'irix'; + $Is{NetBSD} = $^O eq 'netbsd'; + $Is{Interix} = $^O eq 'interix'; + $Is{SunOS4} = $^O eq 'sunos'; + $Is{Solaris} = $^O eq 'solaris'; + $Is{SunOS} = $Is{SunOS4} || $Is{Solaris}; + $Is{BSD} = ($^O =~ /^(?:free|net|open)bsd$/ or + grep( $^O eq $_, qw(bsdos interix dragonfly) ) + ); +} + +BEGIN { + if( $Is{VMS} ) { + # For things like vmsify() + require VMS::Filespec; + VMS::Filespec->import; + } +} + + +=head1 NAME + +ExtUtils::MM_Unix - methods used by ExtUtils::MakeMaker + +=head1 SYNOPSIS + +C<require ExtUtils::MM_Unix;> + +=head1 DESCRIPTION + +The methods provided by this package are designed to be used in +conjunction with ExtUtils::MakeMaker. When MakeMaker writes a +Makefile, it creates one or more objects that inherit their methods +from a package C<MM>. MM itself doesn't provide any methods, but it +ISA ExtUtils::MM_Unix class. The inheritance tree of MM lets operating +specific packages take the responsibility for all the methods provided +by MM_Unix. We are trying to reduce the number of the necessary +overrides by defining rather primitive operations within +ExtUtils::MM_Unix. + +If you are going to write a platform specific MM package, please try +to limit the necessary overrides to primitive methods, and if it is not +possible to do so, let's work out how to achieve that gain. + +If you are overriding any of these methods in your Makefile.PL (in the +MY class), please report that to the makemaker mailing list. We are +trying to minimize the necessary method overrides and switch to data +driven Makefile.PLs wherever possible. In the long run less methods +will be overridable via the MY class. + +=head1 METHODS + +The following description of methods is still under +development. Please refer to the code for not suitably documented +sections and complain loudly to the makemaker@perl.org mailing list. +Better yet, provide a patch. + +Not all of the methods below are overridable in a +Makefile.PL. Overridable methods are marked as (o). All methods are +overridable by a platform specific MM_*.pm file. + +Cross-platform methods are being moved into MM_Any. If you can't find +something that used to be in here, look in MM_Any. + +=cut + +# So we don't have to keep calling the methods over and over again, +# we have these globals to cache the values. Faster and shrtr. +my $Curdir = __PACKAGE__->curdir; +my $Rootdir = __PACKAGE__->rootdir; +my $Updir = __PACKAGE__->updir; + + +=head2 Methods + +=over 4 + +=item os_flavor + +Simply says that we're Unix. + +=cut + +sub os_flavor { + return('Unix'); +} + + +=item c_o (o) + +Defines the suffix rules to compile different flavors of C files to +object files. + +=cut + +sub c_o { +# --- Translation Sections --- + + my($self) = shift; + return '' unless $self->needs_linking(); + my(@m); + + my $command = '$(CCCMD)'; + my $flags = '$(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE)'; + + if (my $cpp = $Config{cpprun}) { + my $cpp_cmd = $self->const_cccmd; + $cpp_cmd =~ s/^CCCMD\s*=\s*\$\(CC\)/$cpp/; + push @m, qq{ +.c.i: + $cpp_cmd $flags \$*.c > \$*.i +}; + } + + push @m, qq{ +.c.s: + $command -S $flags \$*.c + +.c\$(OBJ_EXT): + $command $flags \$*.c + +.cpp\$(OBJ_EXT): + $command $flags \$*.cpp + +.cxx\$(OBJ_EXT): + $command $flags \$*.cxx + +.cc\$(OBJ_EXT): + $command $flags \$*.cc +}; + + push @m, qq{ +.C\$(OBJ_EXT): + $command $flags \$*.C +} if !$Is{OS2} and !$Is{Win32} and !$Is{Dos}; #Case-specific + + return join "", @m; +} + +=item cflags (o) + +Does very much the same as the cflags script in the perl +distribution. It doesn't return the whole compiler command line, but +initializes all of its parts. The const_cccmd method then actually +returns the definition of the CCCMD macro which uses these parts. + +=cut + +#' + +sub cflags { + my($self,$libperl)=@_; + return $self->{CFLAGS} if $self->{CFLAGS}; + return '' unless $self->needs_linking(); + + my($prog, $uc, $perltype, %cflags); + $libperl ||= $self->{LIBPERL_A} || "libperl$self->{LIB_EXT}" ; + $libperl =~ s/\.\$\(A\)$/$self->{LIB_EXT}/; + + @cflags{qw(cc ccflags optimize shellflags)} + = @Config{qw(cc ccflags optimize shellflags)}; + my($optdebug) = ""; + + $cflags{shellflags} ||= ''; + + my(%map) = ( + D => '-DDEBUGGING', + E => '-DEMBED', + DE => '-DDEBUGGING -DEMBED', + M => '-DEMBED -DMULTIPLICITY', + DM => '-DDEBUGGING -DEMBED -DMULTIPLICITY', + ); + + if ($libperl =~ /libperl(\w*)\Q$self->{LIB_EXT}/){ + $uc = uc($1); + } else { + $uc = ""; # avoid warning + } + $perltype = $map{$uc} ? $map{$uc} : ""; + + if ($uc =~ /^D/) { + $optdebug = "-g"; + } + + + my($name); + ( $name = $self->{NAME} . "_cflags" ) =~ s/:/_/g ; + if ($prog = $Config{$name}) { + # Expand hints for this extension via the shell + print STDOUT "Processing $name hint:\n" if $Verbose; + my(@o)=`cc=\"$cflags{cc}\" + ccflags=\"$cflags{ccflags}\" + optimize=\"$cflags{optimize}\" + perltype=\"$cflags{perltype}\" + optdebug=\"$cflags{optdebug}\" + eval '$prog' + echo cc=\$cc + echo ccflags=\$ccflags + echo optimize=\$optimize + echo perltype=\$perltype + echo optdebug=\$optdebug + `; + foreach my $line (@o){ + chomp $line; + if ($line =~ /(.*?)=\s*(.*)\s*$/){ + $cflags{$1} = $2; + print STDOUT " $1 = $2\n" if $Verbose; + } else { + print STDOUT "Unrecognised result from hint: '$line'\n"; + } + } + } + + if ($optdebug) { + $cflags{optimize} = $optdebug; + } + + for (qw(ccflags optimize perltype)) { + $cflags{$_} ||= ''; + $cflags{$_} =~ s/^\s+//; + $cflags{$_} =~ s/\s+/ /g; + $cflags{$_} =~ s/\s+$//; + $self->{uc $_} ||= $cflags{$_}; + } + + if ($self->{POLLUTE}) { + $self->{CCFLAGS} .= ' -DPERL_POLLUTE '; + } + + my $pollute = ''; + if ($Config{usemymalloc} and not $Config{bincompat5005} + and not $Config{ccflags} =~ /-DPERL_POLLUTE_MALLOC\b/ + and $self->{PERL_MALLOC_OK}) { + $pollute = '$(PERL_MALLOC_DEF)'; + } + + $self->{CCFLAGS} = quote_paren($self->{CCFLAGS}); + $self->{OPTIMIZE} = quote_paren($self->{OPTIMIZE}); + + return $self->{CFLAGS} = qq{ +CCFLAGS = $self->{CCFLAGS} +OPTIMIZE = $self->{OPTIMIZE} +PERLTYPE = $self->{PERLTYPE} +MPOLLUTE = $pollute +}; + +} + + +=item const_cccmd (o) + +Returns the full compiler call for C programs and stores the +definition in CONST_CCCMD. + +=cut + +sub const_cccmd { + my($self,$libperl)=@_; + return $self->{CONST_CCCMD} if $self->{CONST_CCCMD}; + return '' unless $self->needs_linking(); + return $self->{CONST_CCCMD} = + q{CCCMD = $(CC) -c $(PASTHRU_INC) $(INC) \\ + $(CCFLAGS) $(OPTIMIZE) \\ + $(PERLTYPE) $(MPOLLUTE) $(DEFINE_VERSION) \\ + $(XS_DEFINE_VERSION)}; +} + +=item const_config (o) + +Defines a couple of constants in the Makefile that are imported from +%Config. + +=cut + +sub const_config { +# --- Constants Sections --- + + my($self) = shift; + my @m = <<"END"; + +# These definitions are from config.sh (via $INC{'Config.pm'}). +# They may have been overridden via Makefile.PL or on the command line. +END + + my(%once_only); + foreach my $key (@{$self->{CONFIG}}){ + # SITE*EXP macros are defined in &constants; avoid duplicates here + next if $once_only{$key}; + $self->{uc $key} = quote_paren($self->{uc $key}); + push @m, uc($key) , ' = ' , $self->{uc $key}, "\n"; + $once_only{$key} = 1; + } + join('', @m); +} + +=item const_loadlibs (o) + +Defines EXTRALIBS, LDLOADLIBS, BSLOADLIBS, LD_RUN_PATH. See +L<ExtUtils::Liblist> for details. + +=cut + +sub const_loadlibs { + my($self) = shift; + return "" unless $self->needs_linking; + my @m; + push @m, qq{ +# $self->{NAME} might depend on some other libraries: +# See ExtUtils::Liblist for details +# +}; + for my $tmp (qw/ + EXTRALIBS LDLOADLIBS BSLOADLIBS + /) { + next unless defined $self->{$tmp}; + push @m, "$tmp = $self->{$tmp}\n"; + } + # don't set LD_RUN_PATH if empty + for my $tmp (qw/ + LD_RUN_PATH + /) { + next unless $self->{$tmp}; + push @m, "$tmp = $self->{$tmp}\n"; + } + return join "", @m; +} + +=item constants (o) + + my $make_frag = $mm->constants; + +Prints out macros for lots of constants. + +=cut + +sub constants { + my($self) = @_; + my @m = (); + + $self->{DFSEP} = '$(DIRFILESEP)'; # alias for internal use + + for my $macro (qw( + + AR_STATIC_ARGS DIRFILESEP DFSEP + NAME NAME_SYM + VERSION VERSION_MACRO VERSION_SYM DEFINE_VERSION + XS_VERSION XS_VERSION_MACRO XS_DEFINE_VERSION + INST_ARCHLIB INST_SCRIPT INST_BIN INST_LIB + INST_MAN1DIR INST_MAN3DIR + MAN1EXT MAN3EXT + INSTALLDIRS INSTALL_BASE DESTDIR PREFIX + PERLPREFIX SITEPREFIX VENDORPREFIX + ), + (map { ("INSTALL".$_, + "DESTINSTALL".$_) + } $self->installvars), + qw( + PERL_LIB + PERL_ARCHLIB + LIBPERL_A MYEXTLIB + FIRST_MAKEFILE MAKEFILE_OLD MAKE_APERL_FILE + PERLMAINCC PERL_SRC PERL_INC + PERL FULLPERL ABSPERL + PERLRUN FULLPERLRUN ABSPERLRUN + PERLRUNINST FULLPERLRUNINST ABSPERLRUNINST + PERL_CORE + PERM_DIR PERM_RW PERM_RWX + + ) ) + { + next unless defined $self->{$macro}; + + # pathnames can have sharp signs in them; escape them so + # make doesn't think it is a comment-start character. + $self->{$macro} =~ s/#/\\#/g; + push @m, "$macro = $self->{$macro}\n"; + } + + push @m, qq{ +MAKEMAKER = $self->{MAKEMAKER} +MM_VERSION = $self->{MM_VERSION} +MM_REVISION = $self->{MM_REVISION} +}; + + push @m, q{ +# FULLEXT = Pathname for extension directory (eg Foo/Bar/Oracle). +# BASEEXT = Basename part of FULLEXT. May be just equal FULLEXT. (eg Oracle) +# PARENT_NAME = NAME without BASEEXT and no trailing :: (eg Foo::Bar) +# DLBASE = Basename part of dynamic library. May be just equal BASEEXT. +}; + + for my $macro (qw/ + MAKE + FULLEXT BASEEXT PARENT_NAME DLBASE VERSION_FROM INC DEFINE OBJECT + LDFROM LINKTYPE BOOTDEP + / ) + { + next unless defined $self->{$macro}; + push @m, "$macro = $self->{$macro}\n"; + } + + push @m, " +# Handy lists of source code files: +XS_FILES = ".$self->wraplist(sort keys %{$self->{XS}})." +C_FILES = ".$self->wraplist(@{$self->{C}})." +O_FILES = ".$self->wraplist(@{$self->{O_FILES}})." +H_FILES = ".$self->wraplist(@{$self->{H}})." +MAN1PODS = ".$self->wraplist(sort keys %{$self->{MAN1PODS}})." +MAN3PODS = ".$self->wraplist(sort keys %{$self->{MAN3PODS}})." +"; + + + push @m, q{ +# Where is the Config information that we are using/depend on +CONFIGDEP = $(PERL_ARCHLIB)$(DFSEP)Config.pm $(PERL_INC)$(DFSEP)config.h +}; + + + push @m, qq{ +# Where to build things +INST_LIBDIR = $self->{INST_LIBDIR} +INST_ARCHLIBDIR = $self->{INST_ARCHLIBDIR} + +INST_AUTODIR = $self->{INST_AUTODIR} +INST_ARCHAUTODIR = $self->{INST_ARCHAUTODIR} + +INST_STATIC = $self->{INST_STATIC} +INST_DYNAMIC = $self->{INST_DYNAMIC} +INST_BOOT = $self->{INST_BOOT} +}; + + + push @m, qq{ +# Extra linker info +EXPORT_LIST = $self->{EXPORT_LIST} +PERL_ARCHIVE = $self->{PERL_ARCHIVE} +PERL_ARCHIVE_AFTER = $self->{PERL_ARCHIVE_AFTER} +}; + + push @m, " + +TO_INST_PM = ".$self->wraplist(sort keys %{$self->{PM}})." + +PM_TO_BLIB = ".$self->wraplist(%{$self->{PM}})." +"; + + join('',@m); +} + + +=item depend (o) + +Same as macro for the depend attribute. + +=cut + +sub depend { + my($self,%attribs) = @_; + my(@m,$key,$val); + while (($key,$val) = each %attribs){ + last unless defined $key; + push @m, "$key : $val\n"; + } + join "", @m; +} + + +=item init_DEST + + $mm->init_DEST + +Defines the DESTDIR and DEST* variables paralleling the INSTALL*. + +=cut + +sub init_DEST { + my $self = shift; + + # Initialize DESTDIR + $self->{DESTDIR} ||= ''; + + # Make DEST variables. + foreach my $var ($self->installvars) { + my $destvar = 'DESTINSTALL'.$var; + $self->{$destvar} ||= '$(DESTDIR)$(INSTALL'.$var.')'; + } +} + + +=item init_dist + + $mm->init_dist; + +Defines a lot of macros for distribution support. + + macro description default + + TAR tar command to use tar + TARFLAGS flags to pass to TAR cvf + + ZIP zip command to use zip + ZIPFLAGS flags to pass to ZIP -r + + COMPRESS compression command to gzip --best + use for tarfiles + SUFFIX suffix to put on .gz + compressed files + + SHAR shar command to use shar + + PREOP extra commands to run before + making the archive + POSTOP extra commands to run after + making the archive + + TO_UNIX a command to convert linefeeds + to Unix style in your archive + + CI command to checkin your ci -u + sources to version control + RCS_LABEL command to label your sources rcs -Nv$(VERSION_SYM): -q + just after CI is run + + DIST_CP $how argument to manicopy() best + when the distdir is created + + DIST_DEFAULT default target to use to tardist + create a distribution + + DISTVNAME name of the resulting archive $(DISTNAME)-$(VERSION) + (minus suffixes) + +=cut + +sub init_dist { + my $self = shift; + + $self->{TAR} ||= 'tar'; + $self->{TARFLAGS} ||= 'cvf'; + $self->{ZIP} ||= 'zip'; + $self->{ZIPFLAGS} ||= '-r'; + $self->{COMPRESS} ||= 'gzip --best'; + $self->{SUFFIX} ||= '.gz'; + $self->{SHAR} ||= 'shar'; + $self->{PREOP} ||= '$(NOECHO) $(NOOP)'; # eg update MANIFEST + $self->{POSTOP} ||= '$(NOECHO) $(NOOP)'; # eg remove the distdir + $self->{TO_UNIX} ||= '$(NOECHO) $(NOOP)'; + + $self->{CI} ||= 'ci -u'; + $self->{RCS_LABEL}||= 'rcs -Nv$(VERSION_SYM): -q'; + $self->{DIST_CP} ||= 'best'; + $self->{DIST_DEFAULT} ||= 'tardist'; + + ($self->{DISTNAME} = $self->{NAME}) =~ s{::}{-}g unless $self->{DISTNAME}; + $self->{DISTVNAME} ||= $self->{DISTNAME}.'-'.$self->{VERSION}; + +} + +=item dist (o) + + my $dist_macros = $mm->dist(%overrides); + +Generates a make fragment defining all the macros initialized in +init_dist. + +%overrides can be used to override any of the above. + +=cut + +sub dist { + my($self, %attribs) = @_; + + my $make = ''; + foreach my $key (qw( + TAR TARFLAGS ZIP ZIPFLAGS COMPRESS SUFFIX SHAR + PREOP POSTOP TO_UNIX + CI RCS_LABEL DIST_CP DIST_DEFAULT + DISTNAME DISTVNAME + )) + { + my $value = $attribs{$key} || $self->{$key}; + $make .= "$key = $value\n"; + } + + return $make; +} + +=item dist_basics (o) + +Defines the targets distclean, distcheck, skipcheck, manifest, veryclean. + +=cut + +sub dist_basics { + my($self) = shift; + + return <<'MAKE_FRAG'; +distclean :: realclean distcheck + $(NOECHO) $(NOOP) + +distcheck : + $(PERLRUN) "-MExtUtils::Manifest=fullcheck" -e fullcheck + +skipcheck : + $(PERLRUN) "-MExtUtils::Manifest=skipcheck" -e skipcheck + +manifest : + $(PERLRUN) "-MExtUtils::Manifest=mkmanifest" -e mkmanifest + +veryclean : realclean + $(RM_F) *~ */*~ *.orig */*.orig *.bak */*.bak *.old */*.old + +MAKE_FRAG + +} + +=item dist_ci (o) + +Defines a check in target for RCS. + +=cut + +sub dist_ci { + my($self) = shift; + return q{ +ci : + $(PERLRUN) "-MExtUtils::Manifest=maniread" \\ + -e "@all = keys %{ maniread() };" \\ + -e "print(qq{Executing $(CI) @all\n}); system(qq{$(CI) @all});" \\ + -e "print(qq{Executing $(RCS_LABEL) ...\n}); system(qq{$(RCS_LABEL) @all});" +}; +} + +=item dist_core (o) + + my $dist_make_fragment = $MM->dist_core; + +Puts the targets necessary for 'make dist' together into one make +fragment. + +=cut + +sub dist_core { + my($self) = shift; + + my $make_frag = ''; + foreach my $target (qw(dist tardist uutardist tarfile zipdist zipfile + shdist)) + { + my $method = $target.'_target'; + $make_frag .= "\n"; + $make_frag .= $self->$method(); + } + + return $make_frag; +} + + +=item B<dist_target> + + my $make_frag = $MM->dist_target; + +Returns the 'dist' target to make an archive for distribution. This +target simply checks to make sure the Makefile is up-to-date and +depends on $(DIST_DEFAULT). + +=cut + +sub dist_target { + my($self) = shift; + + my $date_check = $self->oneliner(<<'CODE', ['-l']); +print 'Warning: Makefile possibly out of date with $(VERSION_FROM)' + if -e '$(VERSION_FROM)' and -M '$(VERSION_FROM)' < -M '$(FIRST_MAKEFILE)'; +CODE + + return sprintf <<'MAKE_FRAG', $date_check; +dist : $(DIST_DEFAULT) $(FIRST_MAKEFILE) + $(NOECHO) %s +MAKE_FRAG +} + +=item B<tardist_target> + + my $make_frag = $MM->tardist_target; + +Returns the 'tardist' target which is simply so 'make tardist' works. +The real work is done by the dynamically named tardistfile_target() +method, tardist should have that as a dependency. + +=cut + +sub tardist_target { + my($self) = shift; + + return <<'MAKE_FRAG'; +tardist : $(DISTVNAME).tar$(SUFFIX) + $(NOECHO) $(NOOP) +MAKE_FRAG +} + +=item B<zipdist_target> + + my $make_frag = $MM->zipdist_target; + +Returns the 'zipdist' target which is simply so 'make zipdist' works. +The real work is done by the dynamically named zipdistfile_target() +method, zipdist should have that as a dependency. + +=cut + +sub zipdist_target { + my($self) = shift; + + return <<'MAKE_FRAG'; +zipdist : $(DISTVNAME).zip + $(NOECHO) $(NOOP) +MAKE_FRAG +} + +=item B<tarfile_target> + + my $make_frag = $MM->tarfile_target; + +The name of this target is the name of the tarball generated by +tardist. This target does the actual work of turning the distdir into +a tarball. + +=cut + +sub tarfile_target { + my($self) = shift; + + return <<'MAKE_FRAG'; +$(DISTVNAME).tar$(SUFFIX) : distdir + $(PREOP) + $(TO_UNIX) + $(TAR) $(TARFLAGS) $(DISTVNAME).tar $(DISTVNAME) + $(RM_RF) $(DISTVNAME) + $(COMPRESS) $(DISTVNAME).tar + $(POSTOP) +MAKE_FRAG +} + +=item zipfile_target + + my $make_frag = $MM->zipfile_target; + +The name of this target is the name of the zip file generated by +zipdist. This target does the actual work of turning the distdir into +a zip file. + +=cut + +sub zipfile_target { + my($self) = shift; + + return <<'MAKE_FRAG'; +$(DISTVNAME).zip : distdir + $(PREOP) + $(ZIP) $(ZIPFLAGS) $(DISTVNAME).zip $(DISTVNAME) + $(RM_RF) $(DISTVNAME) + $(POSTOP) +MAKE_FRAG +} + +=item uutardist_target + + my $make_frag = $MM->uutardist_target; + +Converts the tarfile into a uuencoded file + +=cut + +sub uutardist_target { + my($self) = shift; + + return <<'MAKE_FRAG'; +uutardist : $(DISTVNAME).tar$(SUFFIX) + uuencode $(DISTVNAME).tar$(SUFFIX) $(DISTVNAME).tar$(SUFFIX) > $(DISTVNAME).tar$(SUFFIX)_uu +MAKE_FRAG +} + + +=item shdist_target + + my $make_frag = $MM->shdist_target; + +Converts the distdir into a shell archive. + +=cut + +sub shdist_target { + my($self) = shift; + + return <<'MAKE_FRAG'; +shdist : distdir + $(PREOP) + $(SHAR) $(DISTVNAME) > $(DISTVNAME).shar + $(RM_RF) $(DISTVNAME) + $(POSTOP) +MAKE_FRAG +} + + +=item dlsyms (o) + +Used by some OS' to define DL_FUNCS and DL_VARS and write the *.exp files. + +Normally just returns an empty string. + +=cut + +sub dlsyms { + return ''; +} + + +=item dynamic_bs (o) + +Defines targets for bootstrap files. + +=cut + +sub dynamic_bs { + my($self, %attribs) = @_; + return ' +BOOTSTRAP = +' unless $self->has_link_code(); + + my $target = $Is{VMS} ? '$(MMS$TARGET)' : '$@'; + + return sprintf <<'MAKE_FRAG', ($target) x 5; +BOOTSTRAP = $(BASEEXT).bs + +# As Mkbootstrap might not write a file (if none is required) +# we use touch to prevent make continually trying to remake it. +# The DynaLoader only reads a non-empty file. +$(BOOTSTRAP) : $(FIRST_MAKEFILE) $(BOOTDEP) $(INST_ARCHAUTODIR)$(DFSEP).exists + $(NOECHO) $(ECHO) "Running Mkbootstrap for $(NAME) ($(BSLOADLIBS))" + $(NOECHO) $(PERLRUN) \ + "-MExtUtils::Mkbootstrap" \ + -e "Mkbootstrap('$(BASEEXT)','$(BSLOADLIBS)');" + $(NOECHO) $(TOUCH) %s + $(CHMOD) $(PERM_RW) %s + +$(INST_BOOT) : $(BOOTSTRAP) $(INST_ARCHAUTODIR)$(DFSEP).exists + $(NOECHO) $(RM_RF) %s + - $(CP) $(BOOTSTRAP) %s + $(CHMOD) $(PERM_RW) %s +MAKE_FRAG +} + +=item dynamic_lib (o) + +Defines how to produce the *.so (or equivalent) files. + +=cut + +sub dynamic_lib { + my($self, %attribs) = @_; + return '' unless $self->needs_linking(); #might be because of a subdir + + return '' unless $self->has_link_code; + + my($otherldflags) = $attribs{OTHERLDFLAGS} || ""; + my($inst_dynamic_dep) = $attribs{INST_DYNAMIC_DEP} || ""; + my($armaybe) = $attribs{ARMAYBE} || $self->{ARMAYBE} || ":"; + my($ldfrom) = '$(LDFROM)'; + $armaybe = 'ar' if ($Is{OSF} and $armaybe eq ':'); + my(@m); + my $ld_opt = $Is{OS2} ? '$(OPTIMIZE) ' : ''; # Useful on other systems too? + my $ld_fix = $Is{OS2} ? '|| ( $(RM_F) $@ && sh -c false )' : ''; + push(@m,' +# This section creates the dynamically loadable $(INST_DYNAMIC) +# from $(OBJECT) and possibly $(MYEXTLIB). +ARMAYBE = '.$armaybe.' +OTHERLDFLAGS = '.$ld_opt.$otherldflags.' +INST_DYNAMIC_DEP = '.$inst_dynamic_dep.' +INST_DYNAMIC_FIX = '.$ld_fix.' + +$(INST_DYNAMIC): $(OBJECT) $(MYEXTLIB) $(BOOTSTRAP) $(INST_ARCHAUTODIR)$(DFSEP).exists $(EXPORT_LIST) $(PERL_ARCHIVE) $(PERL_ARCHIVE_AFTER) $(INST_DYNAMIC_DEP) +'); + if ($armaybe ne ':'){ + $ldfrom = 'tmp$(LIB_EXT)'; + push(@m,' $(ARMAYBE) cr '.$ldfrom.' $(OBJECT)'."\n"); + push(@m,' $(RANLIB) '."$ldfrom\n"); + } + $ldfrom = "-all $ldfrom -none" if $Is{OSF}; + + # The IRIX linker doesn't use LD_RUN_PATH + my $ldrun = $Is{IRIX} && $self->{LD_RUN_PATH} ? + qq{-rpath "$self->{LD_RUN_PATH}"} : ''; + + # For example in AIX the shared objects/libraries from previous builds + # linger quite a while in the shared dynalinker cache even when nobody + # is using them. This is painful if one for instance tries to restart + # a failed build because the link command will fail unnecessarily 'cos + # the shared object/library is 'busy'. + push(@m,' $(RM_F) $@ +'); + + my $libs = '$(LDLOADLIBS)'; + + if (($Is{NetBSD} || $Is{Interix}) && $Config{'useshrplib'} eq 'true') { + # Use nothing on static perl platforms, and to the flags needed + # to link against the shared libperl library on shared perl + # platforms. We peek at lddlflags to see if we need -Wl,-R + # or -R to add paths to the run-time library search path. + if ($Config{'lddlflags'} =~ /-Wl,-R/) { + $libs .= ' -L$(PERL_INC) -Wl,-R$(INSTALLARCHLIB)/CORE -Wl,-R$(PERL_ARCHLIB)/CORE -lperl'; + } elsif ($Config{'lddlflags'} =~ /-R/) { + $libs .= ' -L$(PERL_INC) -R$(INSTALLARCHLIB)/CORE -R$(PERL_ARCHLIB)/CORE -lperl'; + } + } + + my $ld_run_path_shell = ""; + if ($self->{LD_RUN_PATH} ne "") { + $ld_run_path_shell = 'LD_RUN_PATH="$(LD_RUN_PATH)" '; + } + + push @m, sprintf <<'MAKE', $ld_run_path_shell, $ldrun, $ldfrom, $libs; + %s$(LD) %s $(LDDLFLAGS) %s $(OTHERLDFLAGS) -o $@ $(MYEXTLIB) \ + $(PERL_ARCHIVE) %s $(PERL_ARCHIVE_AFTER) $(EXPORT_LIST) \ + $(INST_DYNAMIC_FIX) +MAKE + + push @m, <<'MAKE'; + $(CHMOD) $(PERM_RWX) $@ +MAKE + + return join('',@m); +} + +=item exescan + +Deprecated method. Use libscan instead. + +=cut + +sub exescan { + my($self,$path) = @_; + $path; +} + +=item extliblist + +Called by init_others, and calls ext ExtUtils::Liblist. See +L<ExtUtils::Liblist> for details. + +=cut + +sub extliblist { + my($self,$libs) = @_; + require ExtUtils::Liblist; + $self->ext($libs, $Verbose); +} + +=item find_perl + +Finds the executables PERL and FULLPERL + +=cut + +sub find_perl { + my($self, $ver, $names, $dirs, $trace) = @_; + + if ($trace >= 2){ + print "Looking for perl $ver by these names: +@$names +in these dirs: +@$dirs +"; + } + + my $stderr_duped = 0; + local *STDERR_COPY; + + unless ($Is{BSD}) { + # >& and lexical filehandles together give 5.6.2 indigestion + if( open(STDERR_COPY, '>&STDERR') ) { ## no critic + $stderr_duped = 1; + } + else { + warn <<WARNING; +find_perl() can't dup STDERR: $! +You might see some garbage while we search for Perl +WARNING + } + } + + foreach my $name (@$names){ + foreach my $dir (@$dirs){ + next unless defined $dir; # $self->{PERL_SRC} may be undefined + my ($abs, $val); + if ($self->file_name_is_absolute($name)) { # /foo/bar + $abs = $name; + } elsif ($self->canonpath($name) eq + $self->canonpath(basename($name))) { # foo + $abs = $self->catfile($dir, $name); + } else { # foo/bar + $abs = $self->catfile($Curdir, $name); + } + print "Checking $abs\n" if ($trace >= 2); + next unless $self->maybe_command($abs); + print "Executing $abs\n" if ($trace >= 2); + + my $version_check = qq{$abs -le "require $ver; print qq{VER_OK}"}; + $version_check = "$Config{run} $version_check" + if defined $Config{run} and length $Config{run}; + + # To avoid using the unportable 2>&1 to suppress STDERR, + # we close it before running the command. + # However, thanks to a thread library bug in many BSDs + # ( http://www.freebsd.org/cgi/query-pr.cgi?pr=51535 ) + # we cannot use the fancier more portable way in here + # but instead need to use the traditional 2>&1 construct. + if ($Is{BSD}) { + $val = `$version_check 2>&1`; + } else { + close STDERR if $stderr_duped; + $val = `$version_check`; + + # 5.6.2's 3-arg open doesn't work with >& + open STDERR, ">&STDERR_COPY" ## no critic + if $stderr_duped; + } + + if ($val =~ /^VER_OK/m) { + print "Using PERL=$abs\n" if $trace; + return $abs; + } elsif ($trace >= 2) { + print "Result: '$val' ".($? >> 8)."\n"; + } + } + } + print STDOUT "Unable to find a perl $ver (by these names: @$names, in these dirs: @$dirs)\n"; + 0; # false and not empty +} + + +=item fixin + + $mm->fixin(@files); + +Inserts the sharpbang or equivalent magic number to a set of @files. + +=cut + +sub fixin { # stolen from the pink Camel book, more or less + my ( $self, @files ) = @_; + + my ($does_shbang) = $Config{'sharpbang'} =~ /^\s*\#\!/; + for my $file (@files) { + my $file_new = "$file.new"; + my $file_bak = "$file.bak"; + + open( my $fixin, '<', $file ) or croak "Can't process '$file': $!"; + local $/ = "\n"; + chomp( my $line = <$fixin> ); + next unless $line =~ s/^\s*\#!\s*//; # Not a shbang file. + # Now figure out the interpreter name. + my ( $cmd, $arg ) = split ' ', $line, 2; + $cmd =~ s!^.*/!!; + + # Now look (in reverse) for interpreter in absolute PATH (unless perl). + my $interpreter; + if ( $cmd =~ m{^perl(?:\z|[^a-z])} ) { + if ( $Config{startperl} =~ m,^\#!.*/perl, ) { + $interpreter = $Config{startperl}; + $interpreter =~ s,^\#!,,; + } + else { + $interpreter = $Config{perlpath}; + } + } + else { + my (@absdirs) + = reverse grep { $self->file_name_is_absolute($_) } $self->path; + $interpreter = ''; + + foreach my $dir (@absdirs) { + if ( $self->maybe_command($cmd) ) { + warn "Ignoring $interpreter in $file\n" + if $Verbose && $interpreter; + $interpreter = $self->catfile( $dir, $cmd ); + } + } + } + + # Figure out how to invoke interpreter on this machine. + + my ($shb) = ""; + if ($interpreter) { + print STDOUT "Changing sharpbang in $file to $interpreter" + if $Verbose; + + # this is probably value-free on DOSISH platforms + if ($does_shbang) { + $shb .= "$Config{'sharpbang'}$interpreter"; + $shb .= ' ' . $arg if defined $arg; + $shb .= "\n"; + } + $shb .= qq{ +eval 'exec $interpreter $arg -S \$0 \${1+"\$\@"}' + if 0; # not running under some shell +} unless $Is{Win32}; # this won't work on win32, so don't + } + else { + warn "Can't find $cmd in PATH, $file unchanged" + if $Verbose; + next; + } + + open( my $fixout, ">", "$file_new" ) or do { + warn "Can't create new $file: $!\n"; + next; + }; + + # Print out the new #! line (or equivalent). + local $\; + local $/; + print $fixout $shb, <$fixin>; + close $fixin; + close $fixout; + + chmod 0666, $file_bak; + unlink $file_bak; + unless ( _rename( $file, $file_bak ) ) { + warn "Can't rename $file to $file_bak: $!"; + next; + } + unless ( _rename( $file_new, $file ) ) { + warn "Can't rename $file_new to $file: $!"; + unless ( _rename( $file_bak, $file ) ) { + warn "Can't rename $file_bak back to $file either: $!"; + warn "Leaving $file renamed as $file_bak\n"; + } + next; + } + unlink $file_bak; + } + continue { + system("$Config{'eunicefix'} $file") if $Config{'eunicefix'} ne ':'; + } +} + + +sub _rename { + my($old, $new) = @_; + + foreach my $file ($old, $new) { + if( $Is{VMS} and basename($file) !~ /\./ ) { + # rename() in 5.8.0 on VMS will not rename a file if it + # does not contain a dot yet it returns success. + $file = "$file."; + } + } + + return rename($old, $new); +} + + +=item force (o) + +Writes an empty FORCE: target. + +=cut + +sub force { + my($self) = shift; + '# Phony target to force checking subdirectories. +FORCE : + $(NOECHO) $(NOOP) +'; +} + +=item guess_name + +Guess the name of this package by examining the working directory's +name. MakeMaker calls this only if the developer has not supplied a +NAME attribute. + +=cut + +# '; + +sub guess_name { + my($self) = @_; + use Cwd 'cwd'; + my $name = basename(cwd()); + $name =~ s|[\-_][\d\.\-]+\z||; # this is new with MM 5.00, we + # strip minus or underline + # followed by a float or some such + print "Warning: Guessing NAME [$name] from current directory name.\n"; + $name; +} + +=item has_link_code + +Returns true if C, XS, MYEXTLIB or similar objects exist within this +object that need a compiler. Does not descend into subdirectories as +needs_linking() does. + +=cut + +sub has_link_code { + my($self) = shift; + return $self->{HAS_LINK_CODE} if defined $self->{HAS_LINK_CODE}; + if ($self->{OBJECT} or @{$self->{C} || []} or $self->{MYEXTLIB}){ + $self->{HAS_LINK_CODE} = 1; + return 1; + } + return $self->{HAS_LINK_CODE} = 0; +} + + +=item init_dirscan + +Scans the directory structure and initializes DIR, XS, XS_FILES, +C, C_FILES, O_FILES, H, H_FILES, PL_FILES, EXE_FILES. + +Called by init_main. + +=cut + +sub init_dirscan { # --- File and Directory Lists (.xs .pm .pod etc) + my($self) = @_; + my(%dir, %xs, %c, %h, %pl_files, %pm); + + my %ignore = map {( $_ => 1 )} qw(Makefile.PL Build.PL test.pl t); + + # ignore the distdir + $Is{VMS} ? $ignore{"$self->{DISTVNAME}.dir"} = 1 + : $ignore{$self->{DISTVNAME}} = 1; + + @ignore{map lc, keys %ignore} = values %ignore if $Is{VMS}; + + foreach my $name ($self->lsdir($Curdir)){ + next if $name =~ /\#/; + next if $name eq $Curdir or $name eq $Updir or $ignore{$name}; + next unless $self->libscan($name); + if (-d $name){ + next if -l $name; # We do not support symlinks at all + next if $self->{NORECURS}; + $dir{$name} = $name if (-f $self->catfile($name,"Makefile.PL")); + } elsif ($name =~ /\.xs\z/){ + my($c); ($c = $name) =~ s/\.xs\z/.c/; + $xs{$name} = $c; + $c{$c} = 1; + } elsif ($name =~ /\.c(pp|xx|c)?\z/i){ # .c .C .cpp .cxx .cc + $c{$name} = 1 + unless $name =~ m/perlmain\.c/; # See MAP_TARGET + } elsif ($name =~ /\.h\z/i){ + $h{$name} = 1; + } elsif ($name =~ /\.PL\z/) { + ($pl_files{$name} = $name) =~ s/\.PL\z// ; + } elsif (($Is{VMS} || $Is{Dos}) && $name =~ /[._]pl$/i) { + # case-insensitive filesystem, one dot per name, so foo.h.PL + # under Unix appears as foo.h_pl under VMS or fooh.pl on Dos + local($/); open(my $pl, '<', $name); my $txt = <$pl>; close $pl; + if ($txt =~ /Extracting \S+ \(with variable substitutions/) { + ($pl_files{$name} = $name) =~ s/[._]pl\z//i ; + } + else { + $pm{$name} = $self->catfile($self->{INST_LIBDIR},$name); + } + } elsif ($name =~ /\.(p[ml]|pod)\z/){ + $pm{$name} = $self->catfile($self->{INST_LIBDIR},$name); + } + } + + $self->{PL_FILES} ||= \%pl_files; + $self->{DIR} ||= [sort keys %dir]; + $self->{XS} ||= \%xs; + $self->{C} ||= [sort keys %c]; + $self->{H} ||= [sort keys %h]; + $self->{PM} ||= \%pm; + + my @o_files = @{$self->{C}}; + $self->{O_FILES} = [grep s/\.c(pp|xx|c)?\z/$self->{OBJ_EXT}/i, @o_files]; +} + + +=item init_MANPODS + +Determines if man pages should be generated and initializes MAN1PODS +and MAN3PODS as appropriate. + +=cut + +sub init_MANPODS { + my $self = shift; + + # Set up names of manual pages to generate from pods + foreach my $man (qw(MAN1 MAN3)) { + if ( $self->{"${man}PODS"} + or $self->{"INSTALL${man}DIR"} =~ /^(none|\s*)$/ + ) { + $self->{"${man}PODS"} ||= {}; + } + else { + my $init_method = "init_${man}PODS"; + $self->$init_method(); + } + } +} + + +sub _has_pod { + my($self, $file) = @_; + + my($ispod)=0; + if (open( my $fh, '<', $file )) { + while (<$fh>) { + if (/^=(?:head\d+|item|pod)\b/) { + $ispod=1; + last; + } + } + close $fh; + } else { + # If it doesn't exist yet, we assume, it has pods in it + $ispod = 1; + } + + return $ispod; +} + + +=item init_MAN1PODS + +Initializes MAN1PODS from the list of EXE_FILES. + +=cut + +sub init_MAN1PODS { + my($self) = @_; + + if ( exists $self->{EXE_FILES} ) { + foreach my $name (@{$self->{EXE_FILES}}) { + next unless $self->_has_pod($name); + + $self->{MAN1PODS}->{$name} = + $self->catfile("\$(INST_MAN1DIR)", + basename($name).".\$(MAN1EXT)"); + } + } +} + + +=item init_MAN3PODS + +Initializes MAN3PODS from the list of PM files. + +=cut + +sub init_MAN3PODS { + my $self = shift; + + my %manifypods = (); # we collect the keys first, i.e. the files + # we have to convert to pod + + foreach my $name (keys %{$self->{PM}}) { + if ($name =~ /\.pod\z/ ) { + $manifypods{$name} = $self->{PM}{$name}; + } elsif ($name =~ /\.p[ml]\z/ ) { + if( $self->_has_pod($name) ) { + $manifypods{$name} = $self->{PM}{$name}; + } + } + } + + my $parentlibs_re = join '|', @{$self->{PMLIBPARENTDIRS}}; + + # Remove "Configure.pm" and similar, if it's not the only pod listed + # To force inclusion, just name it "Configure.pod", or override + # MAN3PODS + foreach my $name (keys %manifypods) { + if ($self->{PERL_CORE} and $name =~ /(config|setup).*\.pm/is) { + delete $manifypods{$name}; + next; + } + my($manpagename) = $name; + $manpagename =~ s/\.p(od|m|l)\z//; + # everything below lib is ok + unless($manpagename =~ s!^\W*($parentlibs_re)\W+!!s) { + $manpagename = $self->catfile( + split(/::/,$self->{PARENT_NAME}),$manpagename + ); + } + $manpagename = $self->replace_manpage_separator($manpagename); + $self->{MAN3PODS}->{$name} = + $self->catfile("\$(INST_MAN3DIR)", "$manpagename.\$(MAN3EXT)"); + } +} + + +=item init_PM + +Initializes PMLIBDIRS and PM from PMLIBDIRS. + +=cut + +sub init_PM { + my $self = shift; + + # Some larger extensions often wish to install a number of *.pm/pl + # files into the library in various locations. + + # The attribute PMLIBDIRS holds an array reference which lists + # subdirectories which we should search for library files to + # install. PMLIBDIRS defaults to [ 'lib', $self->{BASEEXT} ]. We + # recursively search through the named directories (skipping any + # which don't exist or contain Makefile.PL files). + + # For each *.pm or *.pl file found $self->libscan() is called with + # the default installation path in $_[1]. The return value of + # libscan defines the actual installation location. The default + # libscan function simply returns the path. The file is skipped + # if libscan returns false. + + # The default installation location passed to libscan in $_[1] is: + # + # ./*.pm => $(INST_LIBDIR)/*.pm + # ./xyz/... => $(INST_LIBDIR)/xyz/... + # ./lib/... => $(INST_LIB)/... + # + # In this way the 'lib' directory is seen as the root of the actual + # perl library whereas the others are relative to INST_LIBDIR + # (which includes PARENT_NAME). This is a subtle distinction but one + # that's important for nested modules. + + unless( $self->{PMLIBDIRS} ) { + if( $Is{VMS} ) { + # Avoid logical name vs directory collisions + $self->{PMLIBDIRS} = ['./lib', "./$self->{BASEEXT}"]; + } + else { + $self->{PMLIBDIRS} = ['lib', $self->{BASEEXT}]; + } + } + + #only existing directories that aren't in $dir are allowed + + # Avoid $_ wherever possible: + # @{$self->{PMLIBDIRS}} = grep -d && !$dir{$_}, @{$self->{PMLIBDIRS}}; + my (@pmlibdirs) = @{$self->{PMLIBDIRS}}; + @{$self->{PMLIBDIRS}} = (); + my %dir = map { ($_ => $_) } @{$self->{DIR}}; + foreach my $pmlibdir (@pmlibdirs) { + -d $pmlibdir && !$dir{$pmlibdir} && push @{$self->{PMLIBDIRS}}, $pmlibdir; + } + + unless( $self->{PMLIBPARENTDIRS} ) { + @{$self->{PMLIBPARENTDIRS}} = ('lib'); + } + + return if $self->{PM} and $self->{ARGS}{PM}; + + if (@{$self->{PMLIBDIRS}}){ + print "Searching PMLIBDIRS: @{$self->{PMLIBDIRS}}\n" + if ($Verbose >= 2); + require File::Find; + File::Find::find(sub { + if (-d $_){ + unless ($self->libscan($_)){ + $File::Find::prune = 1; + } + return; + } + return if /\#/; + return if /~$/; # emacs temp files + return if /,v$/; # RCS files + return if m{\.swp$}; # vim swap files + + my $path = $File::Find::name; + my $prefix = $self->{INST_LIBDIR}; + my $striplibpath; + + my $parentlibs_re = join '|', @{$self->{PMLIBPARENTDIRS}}; + $prefix = $self->{INST_LIB} + if ($striplibpath = $path) =~ s{^(\W*)($parentlibs_re)\W} + {$1}i; + + my($inst) = $self->catfile($prefix,$striplibpath); + local($_) = $inst; # for backwards compatibility + $inst = $self->libscan($inst); + print "libscan($path) => '$inst'\n" if ($Verbose >= 2); + return unless $inst; + $self->{PM}{$path} = $inst; + }, @{$self->{PMLIBDIRS}}); + } +} + + +=item init_DIRFILESEP + +Using / for Unix. Called by init_main. + +=cut + +sub init_DIRFILESEP { + my($self) = shift; + + $self->{DIRFILESEP} = '/'; +} + + +=item init_main + +Initializes AR, AR_STATIC_ARGS, BASEEXT, CONFIG, DISTNAME, DLBASE, +EXE_EXT, FULLEXT, FULLPERL, FULLPERLRUN, FULLPERLRUNINST, INST_*, +INSTALL*, INSTALLDIRS, LIB_EXT, LIBPERL_A, MAP_TARGET, NAME, +OBJ_EXT, PARENT_NAME, PERL, PERL_ARCHLIB, PERL_INC, PERL_LIB, +PERL_SRC, PERLRUN, PERLRUNINST, PREFIX, VERSION, +VERSION_SYM, XS_VERSION. + +=cut + +sub init_main { + my($self) = @_; + + # --- Initialize Module Name and Paths + + # NAME = Foo::Bar::Oracle + # FULLEXT = Foo/Bar/Oracle + # BASEEXT = Oracle + # PARENT_NAME = Foo::Bar +### Only UNIX: +### ($self->{FULLEXT} = +### $self->{NAME}) =~ s!::!/!g ; #eg. BSD/Foo/Socket + $self->{FULLEXT} = $self->catdir(split /::/, $self->{NAME}); + + + # Copied from DynaLoader: + + my(@modparts) = split(/::/,$self->{NAME}); + my($modfname) = $modparts[-1]; + + # Some systems have restrictions on files names for DLL's etc. + # mod2fname returns appropriate file base name (typically truncated) + # It may also edit @modparts if required. + if (defined &DynaLoader::mod2fname) { + $modfname = &DynaLoader::mod2fname(\@modparts); + } + + ($self->{PARENT_NAME}, $self->{BASEEXT}) = $self->{NAME} =~ m!(?:([\w:]+)::)?(\w+)\z! ; + $self->{PARENT_NAME} ||= ''; + + if (defined &DynaLoader::mod2fname) { + # As of 5.001m, dl_os2 appends '_' + $self->{DLBASE} = $modfname; + } else { + $self->{DLBASE} = '$(BASEEXT)'; + } + + + # --- Initialize PERL_LIB, PERL_SRC + + # *Real* information: where did we get these two from? ... + my $inc_config_dir = dirname($INC{'Config.pm'}); + my $inc_carp_dir = dirname($INC{'Carp.pm'}); + + unless ($self->{PERL_SRC}){ + foreach my $dir_count (1..8) { # 8 is the VMS limit for nesting + my $dir = $self->catdir(($Updir) x $dir_count); + + if (-f $self->catfile($dir,"config_h.SH") && + -f $self->catfile($dir,"perl.h") && + -f $self->catfile($dir,"lib","strict.pm") + ) { + $self->{PERL_SRC}=$dir ; + last; + } + } + } + + warn "PERL_CORE is set but I can't find your PERL_SRC!\n" if + $self->{PERL_CORE} and !$self->{PERL_SRC}; + + if ($self->{PERL_SRC}){ + $self->{PERL_LIB} ||= $self->catdir("$self->{PERL_SRC}","lib"); + + if (defined $Cross::platform) { + $self->{PERL_ARCHLIB} = + $self->catdir("$self->{PERL_SRC}","xlib",$Cross::platform); + $self->{PERL_INC} = + $self->catdir("$self->{PERL_SRC}","xlib",$Cross::platform, + $Is{Win32}?("CORE"):()); + } + else { + $self->{PERL_ARCHLIB} = $self->{PERL_LIB}; + $self->{PERL_INC} = ($Is{Win32}) ? + $self->catdir($self->{PERL_LIB},"CORE") : $self->{PERL_SRC}; + } + + # catch a situation that has occurred a few times in the past: + unless ( + -s $self->catfile($self->{PERL_SRC},'cflags') + or + $Is{VMS} + && + -s $self->catfile($self->{PERL_SRC},'vmsish.h') + or + $Is{Win32} + ){ + warn qq{ +You cannot build extensions below the perl source tree after executing +a 'make clean' in the perl source tree. + +To rebuild extensions distributed with the perl source you should +simply Configure (to include those extensions) and then build perl as +normal. After installing perl the source tree can be deleted. It is +not needed for building extensions by running 'perl Makefile.PL' +usually without extra arguments. + +It is recommended that you unpack and build additional extensions away +from the perl source tree. +}; + } + } else { + # we should also consider $ENV{PERL5LIB} here + my $old = $self->{PERL_LIB} || $self->{PERL_ARCHLIB} || $self->{PERL_INC}; + $self->{PERL_LIB} ||= $Config{privlibexp}; + $self->{PERL_ARCHLIB} ||= $Config{archlibexp}; + $self->{PERL_INC} = $self->catdir("$self->{PERL_ARCHLIB}","CORE"); # wild guess for now + my $perl_h; + + if (not -f ($perl_h = $self->catfile($self->{PERL_INC},"perl.h")) + and not $old){ + # Maybe somebody tries to build an extension with an + # uninstalled Perl outside of Perl build tree + my $lib; + for my $dir (@INC) { + $lib = $dir, last if -e $self->catfile($dir, "Config.pm"); + } + if ($lib) { + # Win32 puts its header files in /perl/src/lib/CORE. + # Unix leaves them in /perl/src. + my $inc = $Is{Win32} ? $self->catdir($lib, "CORE" ) + : dirname $lib; + if (-e $self->catfile($inc, "perl.h")) { + $self->{PERL_LIB} = $lib; + $self->{PERL_ARCHLIB} = $lib; + $self->{PERL_INC} = $inc; + $self->{UNINSTALLED_PERL} = 1; + print STDOUT <<EOP; +... Detected uninstalled Perl. Trying to continue. +EOP + } + } + } + } + + # We get SITELIBEXP and SITEARCHEXP directly via + # Get_from_Config. When we are running standard modules, these + # won't matter, we will set INSTALLDIRS to "perl". Otherwise we + # set it to "site". I prefer that INSTALLDIRS be set from outside + # MakeMaker. + $self->{INSTALLDIRS} ||= "site"; + + $self->{MAN1EXT} ||= $Config{man1ext}; + $self->{MAN3EXT} ||= $Config{man3ext}; + + # Get some stuff out of %Config if we haven't yet done so + print STDOUT "CONFIG must be an array ref\n" + if ($self->{CONFIG} and ref $self->{CONFIG} ne 'ARRAY'); + $self->{CONFIG} = [] unless (ref $self->{CONFIG}); + push(@{$self->{CONFIG}}, @ExtUtils::MakeMaker::Get_from_Config); + push(@{$self->{CONFIG}}, 'shellflags') if $Config{shellflags}; + my(%once_only); + foreach my $m (@{$self->{CONFIG}}){ + next if $once_only{$m}; + print STDOUT "CONFIG key '$m' does not exist in Config.pm\n" + unless exists $Config{$m}; + $self->{uc $m} ||= $Config{$m}; + $once_only{$m} = 1; + } + +# This is too dangerous: +# if ($^O eq "next") { +# $self->{AR} = "libtool"; +# $self->{AR_STATIC_ARGS} = "-o"; +# } +# But I leave it as a placeholder + + $self->{AR_STATIC_ARGS} ||= "cr"; + + # These should never be needed + $self->{OBJ_EXT} ||= '.o'; + $self->{LIB_EXT} ||= '.a'; + + $self->{MAP_TARGET} ||= "perl"; + + $self->{LIBPERL_A} ||= "libperl$self->{LIB_EXT}"; + + # make a simple check if we find strict + warn "Warning: PERL_LIB ($self->{PERL_LIB}) seems not to be a perl library directory + (strict.pm not found)" + unless -f $self->catfile("$self->{PERL_LIB}","strict.pm") || + $self->{NAME} eq "ExtUtils::MakeMaker"; +} + +=item init_others + +Initializes EXTRALIBS, BSLOADLIBS, LDLOADLIBS, LIBS, LD_RUN_PATH, LD, +OBJECT, BOOTDEP, PERLMAINCC, LDFROM, LINKTYPE, SHELL, NOOP, +FIRST_MAKEFILE, MAKEFILE_OLD, NOECHO, RM_F, RM_RF, TEST_F, +TOUCH, CP, MV, CHMOD, UMASK_NULL, ECHO, ECHO_N + +=cut + +sub init_others { # --- Initialize Other Attributes + my($self) = shift; + + $self->{ECHO} ||= 'echo'; + $self->{ECHO_N} ||= 'echo -n'; + $self->{RM_F} ||= "rm -f"; + $self->{RM_RF} ||= "rm -rf"; + $self->{TOUCH} ||= "touch"; + $self->{TEST_F} ||= "test -f"; + $self->{CP} ||= "cp"; + $self->{MV} ||= "mv"; + $self->{CHMOD} ||= "chmod"; + $self->{FALSE} ||= 'false'; + $self->{TRUE} ||= 'true'; + + $self->{LD} ||= 'ld'; + + $self->SUPER::init_others(@_); + + # After SUPER::init_others so $Config{shell} has a + # chance to get set. + $self->{SHELL} ||= '/bin/sh'; + + return 1; +} + + +=item init_linker + +Unix has no need of special linker flags. + +=cut + +sub init_linker { + my($self) = shift; + $self->{PERL_ARCHIVE} ||= ''; + $self->{PERL_ARCHIVE_AFTER} ||= ''; + $self->{EXPORT_LIST} ||= ''; +} + + +=begin _protected + +=item init_lib2arch + + $mm->init_lib2arch + +=end _protected + +=cut + +sub init_lib2arch { + my($self) = shift; + + # The user who requests an installation directory explicitly + # should not have to tell us an architecture installation directory + # as well. We look if a directory exists that is named after the + # architecture. If not we take it as a sign that it should be the + # same as the requested installation directory. Otherwise we take + # the found one. + for my $libpair ({l=>"privlib", a=>"archlib"}, + {l=>"sitelib", a=>"sitearch"}, + {l=>"vendorlib", a=>"vendorarch"}, + ) + { + my $lib = "install$libpair->{l}"; + my $Lib = uc $lib; + my $Arch = uc "install$libpair->{a}"; + if( $self->{$Lib} && ! $self->{$Arch} ){ + my($ilib) = $Config{$lib}; + + $self->prefixify($Arch,$ilib,$self->{$Lib}); + + unless (-d $self->{$Arch}) { + print STDOUT "Directory $self->{$Arch} not found\n" + if $Verbose; + $self->{$Arch} = $self->{$Lib}; + } + print STDOUT "Defaulting $Arch to $self->{$Arch}\n" if $Verbose; + } + } +} + + +=item init_PERL + + $mm->init_PERL; + +Called by init_main. Sets up ABSPERL, PERL, FULLPERL and all the +*PERLRUN* permutations. + + PERL is allowed to be miniperl + FULLPERL must be a complete perl + + ABSPERL is PERL converted to an absolute path + + *PERLRUN contains everything necessary to run perl, find it's + libraries, etc... + + *PERLRUNINST is *PERLRUN + everything necessary to find the + modules being built. + +=cut + +sub init_PERL { + my($self) = shift; + + my @defpath = (); + foreach my $component ($self->{PERL_SRC}, $self->path(), + $Config{binexp}) + { + push @defpath, $component if defined $component; + } + + # Build up a set of file names (not command names). + my $thisperl = $self->canonpath($^X); + $thisperl .= $Config{exe_ext} unless + # VMS might have a file version # at the end + $Is{VMS} ? $thisperl =~ m/$Config{exe_ext}(;\d+)?$/i + : $thisperl =~ m/$Config{exe_ext}$/i; + + # We need a relative path to perl when in the core. + $thisperl = $self->abs2rel($thisperl) if $self->{PERL_CORE}; + + my @perls = ($thisperl); + push @perls, map { "$_$Config{exe_ext}" } + ('perl', 'perl5', "perl$Config{version}"); + + # miniperl has priority over all but the cannonical perl when in the + # core. Otherwise its a last resort. + my $miniperl = "miniperl$Config{exe_ext}"; + if( $self->{PERL_CORE} ) { + splice @perls, 1, 0, $miniperl; + } + else { + push @perls, $miniperl; + } + + $self->{PERL} ||= + $self->find_perl(5.0, \@perls, \@defpath, $Verbose ); + # don't check if perl is executable, maybe they have decided to + # supply switches with perl + + # When built for debugging, VMS doesn't create perl.exe but ndbgperl.exe. + my $perl_name = 'perl'; + $perl_name = 'ndbgperl' if $Is{VMS} && + defined $Config{usevmsdebug} && $Config{usevmsdebug} eq 'define'; + + # XXX This logic is flawed. If "miniperl" is anywhere in the path + # it will get confused. It should be fixed to work only on the filename. + # Define 'FULLPERL' to be a non-miniperl (used in test: target) + ($self->{FULLPERL} = $self->{PERL}) =~ s/miniperl/$perl_name/i + unless $self->{FULLPERL}; + + # Little hack to get around VMS's find_perl putting "MCR" in front + # sometimes. + $self->{ABSPERL} = $self->{PERL}; + my $has_mcr = $self->{ABSPERL} =~ s/^MCR\s*//; + if( $self->file_name_is_absolute($self->{ABSPERL}) ) { + $self->{ABSPERL} = '$(PERL)'; + } + else { + $self->{ABSPERL} = $self->rel2abs($self->{ABSPERL}); + + # Quote the perl command if it contains whitespace + $self->{ABSPERL} = $self->quote_literal($self->{ABSPERL}) + if $self->{ABSPERL} =~ /\s/; + + $self->{ABSPERL} = 'MCR '.$self->{ABSPERL} if $has_mcr; + } + + # Are we building the core? + $self->{PERL_CORE} = $ENV{PERL_CORE} unless exists $self->{PERL_CORE}; + $self->{PERL_CORE} = 0 unless defined $self->{PERL_CORE}; + + # How do we run perl? + foreach my $perl (qw(PERL FULLPERL ABSPERL)) { + my $run = $perl.'RUN'; + + $self->{$run} = "\$($perl)"; + + # Make sure perl can find itself before it's installed. + $self->{$run} .= q{ "-I$(PERL_LIB)" "-I$(PERL_ARCHLIB)"} + if $self->{UNINSTALLED_PERL} || $self->{PERL_CORE}; + + $self->{$perl.'RUNINST'} = + sprintf q{$(%sRUN) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)"}, $perl; + } + + return 1; +} + + +=item init_platform + +=item platform_constants + +Add MM_Unix_VERSION. + +=cut + +sub init_platform { + my($self) = shift; + + $self->{MM_Unix_VERSION} = $VERSION; + $self->{PERL_MALLOC_DEF} = '-DPERL_EXTMALLOC_DEF -Dmalloc=Perl_malloc '. + '-Dfree=Perl_mfree -Drealloc=Perl_realloc '. + '-Dcalloc=Perl_calloc'; + +} + +sub platform_constants { + my($self) = shift; + my $make_frag = ''; + + foreach my $macro (qw(MM_Unix_VERSION PERL_MALLOC_DEF)) + { + next unless defined $self->{$macro}; + $make_frag .= "$macro = $self->{$macro}\n"; + } + + return $make_frag; +} + + +=item init_PERM + + $mm->init_PERM + +Called by init_main. Initializes PERL_* + +=cut + +sub init_PERM { + my($self) = shift; + + $self->{PERM_DIR} = 755 unless defined $self->{PERM_DIR}; + $self->{PERM_RW} = 644 unless defined $self->{PERM_RW}; + $self->{PERM_RWX} = 755 unless defined $self->{PERM_RWX}; + + return 1; +} + + +=item init_xs + + $mm->init_xs + +Sets up macros having to do with XS code. Currently just INST_STATIC, +INST_DYNAMIC and INST_BOOT. + +=cut + +sub init_xs { + my $self = shift; + + if ($self->has_link_code()) { + $self->{INST_STATIC} = + $self->catfile('$(INST_ARCHAUTODIR)', '$(BASEEXT)$(LIB_EXT)'); + $self->{INST_DYNAMIC} = + $self->catfile('$(INST_ARCHAUTODIR)', '$(DLBASE).$(DLEXT)'); + $self->{INST_BOOT} = + $self->catfile('$(INST_ARCHAUTODIR)', '$(BASEEXT).bs'); + } else { + $self->{INST_STATIC} = ''; + $self->{INST_DYNAMIC} = ''; + $self->{INST_BOOT} = ''; + } +} + +=item install (o) + +Defines the install target. + +=cut + +sub install { + my($self, %attribs) = @_; + my(@m); + + push @m, q{ +install :: pure_install doc_install + $(NOECHO) $(NOOP) + +install_perl :: pure_perl_install doc_perl_install + $(NOECHO) $(NOOP) + +install_site :: pure_site_install doc_site_install + $(NOECHO) $(NOOP) + +install_vendor :: pure_vendor_install doc_vendor_install + $(NOECHO) $(NOOP) + +pure_install :: pure_$(INSTALLDIRS)_install + $(NOECHO) $(NOOP) + +doc_install :: doc_$(INSTALLDIRS)_install + $(NOECHO) $(NOOP) + +pure__install : pure_site_install + $(NOECHO) $(ECHO) INSTALLDIRS not defined, defaulting to INSTALLDIRS=site + +doc__install : doc_site_install + $(NOECHO) $(ECHO) INSTALLDIRS not defined, defaulting to INSTALLDIRS=site + +pure_perl_install :: all + $(NOECHO) $(MOD_INSTALL) \ + read }.$self->catfile('$(PERL_ARCHLIB)','auto','$(FULLEXT)','.packlist').q{ \ + write }.$self->catfile('$(DESTINSTALLARCHLIB)','auto','$(FULLEXT)','.packlist').q{ \ + $(INST_LIB) $(DESTINSTALLPRIVLIB) \ + $(INST_ARCHLIB) $(DESTINSTALLARCHLIB) \ + $(INST_BIN) $(DESTINSTALLBIN) \ + $(INST_SCRIPT) $(DESTINSTALLSCRIPT) \ + $(INST_MAN1DIR) $(DESTINSTALLMAN1DIR) \ + $(INST_MAN3DIR) $(DESTINSTALLMAN3DIR) + $(NOECHO) $(WARN_IF_OLD_PACKLIST) \ + }.$self->catdir('$(SITEARCHEXP)','auto','$(FULLEXT)').q{ + + +pure_site_install :: all + $(NOECHO) $(MOD_INSTALL) \ + read }.$self->catfile('$(SITEARCHEXP)','auto','$(FULLEXT)','.packlist').q{ \ + write }.$self->catfile('$(DESTINSTALLSITEARCH)','auto','$(FULLEXT)','.packlist').q{ \ + $(INST_LIB) $(DESTINSTALLSITELIB) \ + $(INST_ARCHLIB) $(DESTINSTALLSITEARCH) \ + $(INST_BIN) $(DESTINSTALLSITEBIN) \ + $(INST_SCRIPT) $(DESTINSTALLSITESCRIPT) \ + $(INST_MAN1DIR) $(DESTINSTALLSITEMAN1DIR) \ + $(INST_MAN3DIR) $(DESTINSTALLSITEMAN3DIR) + $(NOECHO) $(WARN_IF_OLD_PACKLIST) \ + }.$self->catdir('$(PERL_ARCHLIB)','auto','$(FULLEXT)').q{ + +pure_vendor_install :: all + $(NOECHO) $(MOD_INSTALL) \ + read }.$self->catfile('$(VENDORARCHEXP)','auto','$(FULLEXT)','.packlist').q{ \ + write }.$self->catfile('$(DESTINSTALLVENDORARCH)','auto','$(FULLEXT)','.packlist').q{ \ + $(INST_LIB) $(DESTINSTALLVENDORLIB) \ + $(INST_ARCHLIB) $(DESTINSTALLVENDORARCH) \ + $(INST_BIN) $(DESTINSTALLVENDORBIN) \ + $(INST_SCRIPT) $(DESTINSTALLVENDORSCRIPT) \ + $(INST_MAN1DIR) $(DESTINSTALLVENDORMAN1DIR) \ + $(INST_MAN3DIR) $(DESTINSTALLVENDORMAN3DIR) + +doc_perl_install :: all + $(NOECHO) $(ECHO) Appending installation info to $(DESTINSTALLARCHLIB)/perllocal.pod + -$(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB) + -$(NOECHO) $(DOC_INSTALL) \ + "Module" "$(NAME)" \ + "installed into" "$(INSTALLPRIVLIB)" \ + LINKTYPE "$(LINKTYPE)" \ + VERSION "$(VERSION)" \ + EXE_FILES "$(EXE_FILES)" \ + >> }.$self->catfile('$(DESTINSTALLARCHLIB)','perllocal.pod').q{ + +doc_site_install :: all + $(NOECHO) $(ECHO) Appending installation info to $(DESTINSTALLARCHLIB)/perllocal.pod + -$(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB) + -$(NOECHO) $(DOC_INSTALL) \ + "Module" "$(NAME)" \ + "installed into" "$(INSTALLSITELIB)" \ + LINKTYPE "$(LINKTYPE)" \ + VERSION "$(VERSION)" \ + EXE_FILES "$(EXE_FILES)" \ + >> }.$self->catfile('$(DESTINSTALLARCHLIB)','perllocal.pod').q{ + +doc_vendor_install :: all + $(NOECHO) $(ECHO) Appending installation info to $(DESTINSTALLARCHLIB)/perllocal.pod + -$(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB) + -$(NOECHO) $(DOC_INSTALL) \ + "Module" "$(NAME)" \ + "installed into" "$(INSTALLVENDORLIB)" \ + LINKTYPE "$(LINKTYPE)" \ + VERSION "$(VERSION)" \ + EXE_FILES "$(EXE_FILES)" \ + >> }.$self->catfile('$(DESTINSTALLARCHLIB)','perllocal.pod').q{ + +}; + + push @m, q{ +uninstall :: uninstall_from_$(INSTALLDIRS)dirs + $(NOECHO) $(NOOP) + +uninstall_from_perldirs :: + $(NOECHO) $(UNINSTALL) }.$self->catfile('$(PERL_ARCHLIB)','auto','$(FULLEXT)','.packlist').q{ + +uninstall_from_sitedirs :: + $(NOECHO) $(UNINSTALL) }.$self->catfile('$(SITEARCHEXP)','auto','$(FULLEXT)','.packlist').q{ + +uninstall_from_vendordirs :: + $(NOECHO) $(UNINSTALL) }.$self->catfile('$(VENDORARCHEXP)','auto','$(FULLEXT)','.packlist').q{ +}; + + join("",@m); +} + +=item installbin (o) + +Defines targets to make and to install EXE_FILES. + +=cut + +sub installbin { + my($self) = shift; + + return "" unless $self->{EXE_FILES} && ref $self->{EXE_FILES} eq "ARRAY"; + my @exefiles = @{$self->{EXE_FILES}}; + return "" unless @exefiles; + + @exefiles = map vmsify($_), @exefiles if $Is{VMS}; + + my %fromto; + for my $from (@exefiles) { + my($path)= $self->catfile('$(INST_SCRIPT)', basename($from)); + + local($_) = $path; # for backwards compatibility + my $to = $self->libscan($path); + print "libscan($from) => '$to'\n" if ($Verbose >=2); + + $to = vmsify($to) if $Is{VMS}; + $fromto{$from} = $to; + } + my @to = values %fromto; + + my @m; + push(@m, qq{ +EXE_FILES = @exefiles + +pure_all :: @to + \$(NOECHO) \$(NOOP) + +realclean :: +}); + + # realclean can get rather large. + push @m, map "\t$_\n", $self->split_command('$(RM_F)', @to); + push @m, "\n"; + + + # A target for each exe file. + while (my($from,$to) = each %fromto) { + last unless defined $from; + + push @m, sprintf <<'MAKE', $to, $from, $to, $from, $to, $to, $to; +%s : %s $(FIRST_MAKEFILE) $(INST_SCRIPT)$(DFSEP).exists $(INST_BIN)$(DFSEP).exists + $(NOECHO) $(RM_F) %s + $(CP) %s %s + $(FIXIN) %s + -$(NOECHO) $(CHMOD) $(PERM_RWX) %s + +MAKE + + } + + join "", @m; +} + + +=item linkext (o) + +Defines the linkext target which in turn defines the LINKTYPE. + +=cut + +sub linkext { + my($self, %attribs) = @_; + # LINKTYPE => static or dynamic or '' + my($linktype) = defined $attribs{LINKTYPE} ? + $attribs{LINKTYPE} : '$(LINKTYPE)'; + " +linkext :: $linktype + \$(NOECHO) \$(NOOP) +"; +} + +=item lsdir + +Takes as arguments a directory name and a regular expression. Returns +all entries in the directory that match the regular expression. + +=cut + +sub lsdir { + my($self) = shift; + my($dir, $regex) = @_; + my(@ls); + my $dh = new DirHandle; + $dh->open($dir || ".") or return (); + @ls = $dh->read; + $dh->close; + @ls = grep(/$regex/, @ls) if $regex; + @ls; +} + +=item macro (o) + +Simple subroutine to insert the macros defined by the macro attribute +into the Makefile. + +=cut + +sub macro { + my($self,%attribs) = @_; + my(@m,$key,$val); + while (($key,$val) = each %attribs){ + last unless defined $key; + push @m, "$key = $val\n"; + } + join "", @m; +} + +=item makeaperl (o) + +Called by staticmake. Defines how to write the Makefile to produce a +static new perl. + +By default the Makefile produced includes all the static extensions in +the perl library. (Purified versions of library files, e.g., +DynaLoader_pure_p1_c0_032.a are automatically ignored to avoid link errors.) + +=cut + +sub makeaperl { + my($self, %attribs) = @_; + my($makefilename, $searchdirs, $static, $extra, $perlinc, $target, $tmp, $libperl) = + @attribs{qw(MAKE DIRS STAT EXTRA INCL TARGET TMP LIBPERL)}; + my(@m); + push @m, " +# --- MakeMaker makeaperl section --- +MAP_TARGET = $target +FULLPERL = $self->{FULLPERL} +"; + return join '', @m if $self->{PARENT}; + + my($dir) = join ":", @{$self->{DIR}}; + + unless ($self->{MAKEAPERL}) { + push @m, q{ +$(MAP_TARGET) :: static $(MAKE_APERL_FILE) + $(MAKE) $(USEMAKEFILE) $(MAKE_APERL_FILE) $@ + +$(MAKE_APERL_FILE) : $(FIRST_MAKEFILE) pm_to_blib + $(NOECHO) $(ECHO) Writing \"$(MAKE_APERL_FILE)\" for this $(MAP_TARGET) + $(NOECHO) $(PERLRUNINST) \ + Makefile.PL DIR=}, $dir, q{ \ + MAKEFILE=$(MAKE_APERL_FILE) LINKTYPE=static \ + MAKEAPERL=1 NORECURS=1 CCCDLFLAGS=}; + + foreach (@ARGV){ + if( /\s/ ){ + s/=(.*)/='$1'/; + } + push @m, " \\\n\t\t$_"; + } +# push @m, map( " \\\n\t\t$_", @ARGV ); + push @m, "\n"; + + return join '', @m; + } + + + + my($cccmd, $linkcmd, $lperl); + + + $cccmd = $self->const_cccmd($libperl); + $cccmd =~ s/^CCCMD\s*=\s*//; + $cccmd =~ s/\$\(INC\)/ "-I$self->{PERL_INC}" /; + $cccmd .= " $Config{cccdlflags}" + if ($Config{useshrplib} eq 'true'); + $cccmd =~ s/\(CC\)/\(PERLMAINCC\)/; + + # The front matter of the linkcommand... + $linkcmd = join ' ', "\$(CC)", + grep($_, @Config{qw(ldflags ccdlflags)}); + $linkcmd =~ s/\s+/ /g; + $linkcmd =~ s,(perl\.exp),\$(PERL_INC)/$1,; + + # Which *.a files could we make use of... + my %static; + require File::Find; + File::Find::find(sub { + return unless m/\Q$self->{LIB_EXT}\E$/; + + # Skip perl's libraries. + return if m/^libperl/ or m/^perl\Q$self->{LIB_EXT}\E$/; + + # Skip purified versions of libraries + # (e.g., DynaLoader_pure_p1_c0_032.a) + return if m/_pure_\w+_\w+_\w+\.\w+$/ and -f "$File::Find::dir/.pure"; + + if( exists $self->{INCLUDE_EXT} ){ + my $found = 0; + + (my $xx = $File::Find::name) =~ s,.*?/auto/,,s; + $xx =~ s,/?$_,,; + $xx =~ s,/,::,g; + + # Throw away anything not explicitly marked for inclusion. + # DynaLoader is implied. + foreach my $incl ((@{$self->{INCLUDE_EXT}},'DynaLoader')){ + if( $xx eq $incl ){ + $found++; + last; + } + } + return unless $found; + } + elsif( exists $self->{EXCLUDE_EXT} ){ + (my $xx = $File::Find::name) =~ s,.*?/auto/,,s; + $xx =~ s,/?$_,,; + $xx =~ s,/,::,g; + + # Throw away anything explicitly marked for exclusion + foreach my $excl (@{$self->{EXCLUDE_EXT}}){ + return if( $xx eq $excl ); + } + } + + # don't include the installed version of this extension. I + # leave this line here, although it is not necessary anymore: + # I patched minimod.PL instead, so that Miniperl.pm won't + # enclude duplicates + + # Once the patch to minimod.PL is in the distribution, I can + # drop it + return if $File::Find::name =~ m:auto/$self->{FULLEXT}/$self->{BASEEXT}$self->{LIB_EXT}\z:; + use Cwd 'cwd'; + $static{cwd() . "/" . $_}++; + }, grep( -d $_, @{$searchdirs || []}) ); + + # We trust that what has been handed in as argument, will be buildable + $static = [] unless $static; + @static{@{$static}} = (1) x @{$static}; + + $extra = [] unless $extra && ref $extra eq 'ARRAY'; + for (sort keys %static) { + next unless /\Q$self->{LIB_EXT}\E\z/; + $_ = dirname($_) . "/extralibs.ld"; + push @$extra, $_; + } + + s/^(.*)/"-I$1"/ for @{$perlinc || []}; + + $target ||= "perl"; + $tmp ||= "."; + +# MAP_STATIC doesn't look into subdirs yet. Once "all" is made and we +# regenerate the Makefiles, MAP_STATIC and the dependencies for +# extralibs.all are computed correctly + push @m, " +MAP_LINKCMD = $linkcmd +MAP_PERLINC = @{$perlinc || []} +MAP_STATIC = ", +join(" \\\n\t", reverse sort keys %static), " + +MAP_PRELIBS = $Config{perllibs} $Config{cryptlib} +"; + + if (defined $libperl) { + ($lperl = $libperl) =~ s/\$\(A\)/$self->{LIB_EXT}/; + } + unless ($libperl && -f $lperl) { # Ilya's code... + my $dir = $self->{PERL_SRC} || "$self->{PERL_ARCHLIB}/CORE"; + $dir = "$self->{PERL_ARCHLIB}/.." if $self->{UNINSTALLED_PERL}; + $libperl ||= "libperl$self->{LIB_EXT}"; + $libperl = "$dir/$libperl"; + $lperl ||= "libperl$self->{LIB_EXT}"; + $lperl = "$dir/$lperl"; + + if (! -f $libperl and ! -f $lperl) { + # We did not find a static libperl. Maybe there is a shared one? + if ($Is{SunOS}) { + $lperl = $libperl = "$dir/$Config{libperl}"; + # SUNOS ld does not take the full path to a shared library + $libperl = '' if $Is{SunOS4}; + } + } + + print STDOUT "Warning: $libperl not found + If you're going to build a static perl binary, make sure perl is installed + otherwise ignore this warning\n" + unless (-f $lperl || defined($self->{PERL_SRC})); + } + + # SUNOS ld does not take the full path to a shared library + my $llibperl = $libperl ? '$(MAP_LIBPERL)' : '-lperl'; + + push @m, " +MAP_LIBPERL = $libperl +LLIBPERL = $llibperl +"; + + push @m, ' +$(INST_ARCHAUTODIR)/extralibs.all : $(INST_ARCHAUTODIR)$(DFSEP).exists '.join(" \\\n\t", @$extra).' + $(NOECHO) $(RM_F) $@ + $(NOECHO) $(TOUCH) $@ +'; + + foreach my $catfile (@$extra){ + push @m, "\tcat $catfile >> \$\@\n"; + } + +push @m, " +\$(MAP_TARGET) :: $tmp/perlmain\$(OBJ_EXT) \$(MAP_LIBPERL) \$(MAP_STATIC) \$(INST_ARCHAUTODIR)/extralibs.all + \$(MAP_LINKCMD) -o \$\@ \$(OPTIMIZE) $tmp/perlmain\$(OBJ_EXT) \$(LDFROM) \$(MAP_STATIC) \$(LLIBPERL) `cat \$(INST_ARCHAUTODIR)/extralibs.all` \$(MAP_PRELIBS) + \$(NOECHO) \$(ECHO) 'To install the new \"\$(MAP_TARGET)\" binary, call' + \$(NOECHO) \$(ECHO) ' \$(MAKE) \$(USEMAKEFILE) $makefilename inst_perl MAP_TARGET=\$(MAP_TARGET)' + \$(NOECHO) \$(ECHO) 'To remove the intermediate files say' + \$(NOECHO) \$(ECHO) ' \$(MAKE) \$(USEMAKEFILE) $makefilename map_clean' + +$tmp/perlmain\$(OBJ_EXT): $tmp/perlmain.c +"; + push @m, "\t".$self->cd($tmp, qq[$cccmd "-I\$(PERL_INC)" perlmain.c])."\n"; + + push @m, qq{ +$tmp/perlmain.c: $makefilename}, q{ + $(NOECHO) $(ECHO) Writing $@ + $(NOECHO) $(PERL) $(MAP_PERLINC) "-MExtUtils::Miniperl" \\ + -e "writemain(grep s#.*/auto/##s, split(q| |, q|$(MAP_STATIC)|))" > $@t && $(MV) $@t $@ + +}; + push @m, "\t", q{$(NOECHO) $(PERL) $(INSTALLSCRIPT)/fixpmain +} if (defined (&Dos::UseLFN) && Dos::UseLFN()==0); + + + push @m, q{ +doc_inst_perl : + $(NOECHO) $(ECHO) Appending installation info to $(DESTINSTALLARCHLIB)/perllocal.pod + -$(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB) + -$(NOECHO) $(DOC_INSTALL) \ + "Perl binary" "$(MAP_TARGET)" \ + MAP_STATIC "$(MAP_STATIC)" \ + MAP_EXTRA "`cat $(INST_ARCHAUTODIR)/extralibs.all`" \ + MAP_LIBPERL "$(MAP_LIBPERL)" \ + >> }.$self->catfile('$(DESTINSTALLARCHLIB)','perllocal.pod').q{ + +}; + + push @m, q{ +inst_perl : pure_inst_perl doc_inst_perl + +pure_inst_perl : $(MAP_TARGET) + }.$self->{CP}.q{ $(MAP_TARGET) }.$self->catfile('$(DESTINSTALLBIN)','$(MAP_TARGET)').q{ + +clean :: map_clean + +map_clean : + }.$self->{RM_F}.qq{ $tmp/perlmain\$(OBJ_EXT) $tmp/perlmain.c \$(MAP_TARGET) $makefilename \$(INST_ARCHAUTODIR)/extralibs.all +}; + + join '', @m; +} + +=item makefile (o) + +Defines how to rewrite the Makefile. + +=cut + +sub makefile { + my($self) = shift; + my $m; + # We do not know what target was originally specified so we + # must force a manual rerun to be sure. But as it should only + # happen very rarely it is not a significant problem. + $m = ' +$(OBJECT) : $(FIRST_MAKEFILE) + +' if $self->{OBJECT}; + + my $newer_than_target = $Is{VMS} ? '$(MMS$SOURCE_LIST)' : '$?'; + my $mpl_args = join " ", map qq["$_"], @ARGV; + + $m .= sprintf <<'MAKE_FRAG', $newer_than_target, $mpl_args; +# We take a very conservative approach here, but it's worth it. +# We move Makefile to Makefile.old here to avoid gnu make looping. +$(FIRST_MAKEFILE) : Makefile.PL $(CONFIGDEP) + $(NOECHO) $(ECHO) "Makefile out-of-date with respect to %s" + $(NOECHO) $(ECHO) "Cleaning current config before rebuilding Makefile..." + -$(NOECHO) $(RM_F) $(MAKEFILE_OLD) + -$(NOECHO) $(MV) $(FIRST_MAKEFILE) $(MAKEFILE_OLD) + - $(MAKE) $(USEMAKEFILE) $(MAKEFILE_OLD) clean $(DEV_NULL) + $(PERLRUN) Makefile.PL %s + $(NOECHO) $(ECHO) "==> Your Makefile has been rebuilt. <==" + $(NOECHO) $(ECHO) "==> Please rerun the $(MAKE) command. <==" + $(FALSE) + +MAKE_FRAG + + return $m; +} + + +=item maybe_command + +Returns true, if the argument is likely to be a command. + +=cut + +sub maybe_command { + my($self,$file) = @_; + return $file if -x $file && ! -d $file; + return; +} + + +=item needs_linking (o) + +Does this module need linking? Looks into subdirectory objects (see +also has_link_code()) + +=cut + +sub needs_linking { + my($self) = shift; + + my $caller = (caller(0))[3]; + confess("needs_linking called too early") if + $caller =~ /^ExtUtils::MakeMaker::/; + return $self->{NEEDS_LINKING} if defined $self->{NEEDS_LINKING}; + if ($self->has_link_code or $self->{MAKEAPERL}){ + $self->{NEEDS_LINKING} = 1; + return 1; + } + foreach my $child (keys %{$self->{CHILDREN}}) { + if ($self->{CHILDREN}->{$child}->needs_linking) { + $self->{NEEDS_LINKING} = 1; + return 1; + } + } + return $self->{NEEDS_LINKING} = 0; +} + + +=item parse_abstract + +parse a file and return what you think is the ABSTRACT + +=cut + +sub parse_abstract { + my($self,$parsefile) = @_; + my $result; + + local $/ = "\n"; + open(my $fh, '<', $parsefile) or die "Could not open '$parsefile': $!"; + my $inpod = 0; + my $package = $self->{DISTNAME}; + $package =~ s/-/::/g; + while (<$fh>) { + $inpod = /^=(?!cut)/ ? 1 : /^=cut/ ? 0 : $inpod; + next if !$inpod; + chop; + next unless /^($package\s-\s)(.*)/; + $result = $2; + last; + } + close $fh; + + return $result; +} + +=item parse_version + + my $version = MM->parse_version($file); + +Parse a $file and return what $VERSION is set to by the first assignment. +It will return the string "undef" if it can't figure out what $VERSION +is. $VERSION should be for all to see, so C<our $VERSION> or plain $VERSION +are okay, but C<my $VERSION> is not. + +C<<package Foo VERSION>> is also checked for. The first version +declaration found is used, but this may change as it differs from how +Perl does it. + +parse_version() will try to C<use version> before checking for +C<$VERSION> so the following will work. + + $VERSION = qv(1.2.3); + +=cut + +sub parse_version { + my($self,$parsefile) = @_; + my $result; + + local $/ = "\n"; + local $_; + open(my $fh, '<', $parsefile) or die "Could not open '$parsefile': $!"; + my $inpod = 0; + while (<$fh>) { + $inpod = /^=(?!cut)/ ? 1 : /^=cut/ ? 0 : $inpod; + next if $inpod || /^\s*#/; + chop; + next if /^\s*(if|unless)/; + if ( m{^ \s* package \s+ \w[\w\:\']* \s+ (v?[0-9._]+) \s* ; }x ) { + local $^W = 0; + $result = $1; + } + elsif ( m{(?<!\\) ([\$*]) (([\w\:\']*) \bVERSION)\b .* =}x ) { + my $eval = qq{ + package ExtUtils::MakeMaker::_version; + no strict; + BEGIN { eval { + # Ensure any version() routine which might have leaked + # into this package has been deleted. Interferes with + # version->import() + undef *version; + require version; + "version"->import; + } } + + local $1$2; + \$$2=undef; + do { + $_ + }; + \$$2; + }; + local $^W = 0; + $result = eval($eval); ## no critic + warn "Could not eval '$eval' in $parsefile: $@" if $@; + } + else { + next; + } + last if defined $result; + } + close $fh; + + $result = "undef" unless defined $result; + return $result; +} + + +=item pasthru (o) + +Defines the string that is passed to recursive make calls in +subdirectories. + +=cut + +sub pasthru { + my($self) = shift; + my(@m); + + my(@pasthru); + my($sep) = $Is{VMS} ? ',' : ''; + $sep .= "\\\n\t"; + + foreach my $key (qw(LIB LIBPERL_A LINKTYPE OPTIMIZE + PREFIX INSTALL_BASE) + ) + { + next unless defined $self->{$key}; + push @pasthru, "$key=\"\$($key)\""; + } + + foreach my $key (qw(DEFINE INC)) { + next unless defined $self->{$key}; + push @pasthru, "PASTHRU_$key=\"\$(PASTHRU_$key)\""; + } + + push @m, "\nPASTHRU = ", join ($sep, @pasthru), "\n"; + join "", @m; +} + +=item perl_script + +Takes one argument, a file name, and returns the file name, if the +argument is likely to be a perl script. On MM_Unix this is true for +any ordinary, readable file. + +=cut + +sub perl_script { + my($self,$file) = @_; + return $file if -r $file && -f _; + return; +} + +=item perldepend (o) + +Defines the dependency from all *.h files that come with the perl +distribution. + +=cut + +sub perldepend { + my($self) = shift; + my(@m); + + my $make_config = $self->cd('$(PERL_SRC)', '$(MAKE) lib/Config.pm'); + + push @m, sprintf <<'MAKE_FRAG', $make_config if $self->{PERL_SRC}; +# Check for unpropogated config.sh changes. Should never happen. +# We do NOT just update config.h because that is not sufficient. +# An out of date config.h is not fatal but complains loudly! +$(PERL_INC)/config.h: $(PERL_SRC)/config.sh + -$(NOECHO) $(ECHO) "Warning: $(PERL_INC)/config.h out of date with $(PERL_SRC)/config.sh"; $(FALSE) + +$(PERL_ARCHLIB)/Config.pm: $(PERL_SRC)/config.sh + $(NOECHO) $(ECHO) "Warning: $(PERL_ARCHLIB)/Config.pm may be out of date with $(PERL_SRC)/config.sh" + %s +MAKE_FRAG + + return join "", @m unless $self->needs_linking; + + push @m, q{ +PERL_HDRS = \ + $(PERL_INC)/EXTERN.h \ + $(PERL_INC)/INTERN.h \ + $(PERL_INC)/XSUB.h \ + $(PERL_INC)/av.h \ + $(PERL_INC)/cc_runtime.h \ + $(PERL_INC)/config.h \ + $(PERL_INC)/cop.h \ + $(PERL_INC)/cv.h \ + $(PERL_INC)/dosish.h \ + $(PERL_INC)/embed.h \ + $(PERL_INC)/embedvar.h \ + $(PERL_INC)/fakethr.h \ + $(PERL_INC)/form.h \ + $(PERL_INC)/gv.h \ + $(PERL_INC)/handy.h \ + $(PERL_INC)/hv.h \ + $(PERL_INC)/intrpvar.h \ + $(PERL_INC)/iperlsys.h \ + $(PERL_INC)/keywords.h \ + $(PERL_INC)/mg.h \ + $(PERL_INC)/nostdio.h \ + $(PERL_INC)/op.h \ + $(PERL_INC)/opcode.h \ + $(PERL_INC)/patchlevel.h \ + $(PERL_INC)/perl.h \ + $(PERL_INC)/perlio.h \ + $(PERL_INC)/perlsdio.h \ + $(PERL_INC)/perlsfio.h \ + $(PERL_INC)/perlvars.h \ + $(PERL_INC)/perly.h \ + $(PERL_INC)/pp.h \ + $(PERL_INC)/pp_proto.h \ + $(PERL_INC)/proto.h \ + $(PERL_INC)/regcomp.h \ + $(PERL_INC)/regexp.h \ + $(PERL_INC)/regnodes.h \ + $(PERL_INC)/scope.h \ + $(PERL_INC)/sv.h \ + $(PERL_INC)/thread.h \ + $(PERL_INC)/unixish.h \ + $(PERL_INC)/util.h + +$(OBJECT) : $(PERL_HDRS) +} if $self->{OBJECT}; + + push @m, join(" ", values %{$self->{XS}})." : \$(XSUBPPDEPS)\n" if %{$self->{XS}}; + + join "\n", @m; +} + + +=item pm_to_blib + +Defines target that copies all files in the hash PM to their +destination and autosplits them. See L<ExtUtils::Install/DESCRIPTION> + +=cut + +sub pm_to_blib { + my $self = shift; + my($autodir) = $self->catdir('$(INST_LIB)','auto'); + my $r = q{ +pm_to_blib : $(FIRST_MAKEFILE) $(TO_INST_PM) +}; + + # VMS will swallow '' and PM_FILTER is often empty. So use q[] + my $pm_to_blib = $self->oneliner(<<CODE, ['-MExtUtils::Install']); +pm_to_blib({\@ARGV}, '$autodir', q[\$(PM_FILTER)], '\$(PERM_DIR)') +CODE + + my @cmds = $self->split_command($pm_to_blib, %{$self->{PM}}); + + $r .= join '', map { "\t\$(NOECHO) $_\n" } @cmds; + $r .= qq{\t\$(NOECHO) \$(TOUCH) pm_to_blib\n}; + + return $r; +} + +=item post_constants (o) + +Returns an empty string per default. Dedicated to overrides from +within Makefile.PL after all constants have been defined. + +=cut + +sub post_constants{ + ""; +} + +=item post_initialize (o) + +Returns an empty string per default. Used in Makefile.PLs to add some +chunk of text to the Makefile after the object is initialized. + +=cut + +sub post_initialize { + ""; +} + +=item postamble (o) + +Returns an empty string. Can be used in Makefile.PLs to write some +text to the Makefile at the end. + +=cut + +sub postamble { + ""; +} + +# transform dot-separated version string into comma-separated quadruple +# examples: '1.2.3.4.5' => '1,2,3,4' +# '1.2.3' => '1,2,3,0' +sub _ppd_version { + my ($self, $string) = @_; + return join ',', ((split /\./, $string), (0) x 4)[0..3]; +} + +=item ppd + +Defines target that creates a PPD (Perl Package Description) file +for a binary distribution. + +=cut + +sub ppd { + my($self) = @_; + + my $abstract = $self->{ABSTRACT} || ''; + $abstract =~ s/\n/\\n/sg; + $abstract =~ s/</</g; + $abstract =~ s/>/>/g; + + my $author = $self->{AUTHOR} || ''; + $author =~ s/</</g; + $author =~ s/>/>/g; + + my $ppd_xml = sprintf <<'PPD_HTML', $self->{VERSION}, $abstract, $author; +<SOFTPKG NAME="$(DISTNAME)" VERSION="%s"> + <ABSTRACT>%s</ABSTRACT> + <AUTHOR>%s</AUTHOR> +PPD_HTML + + $ppd_xml .= " <IMPLEMENTATION>\n"; + if ( $self->{MIN_PERL_VERSION} ) { + my $min_perl_version = $self->_ppd_version($self->{MIN_PERL_VERSION}); + $ppd_xml .= sprintf <<'PPD_PERLVERS', $min_perl_version; + <PERLCORE VERSION="%s" /> +PPD_PERLVERS + + } + + # Don't add "perl" to requires. perl dependencies are + # handles by ARCHITECTURE. + my %prereqs = %{$self->{PREREQ_PM}}; + delete $prereqs{perl}; + + # Build up REQUIRE + foreach my $prereq (sort keys %prereqs) { + my $name = $prereq; + $name .= '::' unless $name =~ /::/; + my $version = $prereqs{$prereq}+0; # force numification + + my %attrs = ( NAME => $name ); + $attrs{VERSION} = $version if $version; + my $attrs = join " ", map { qq[$_="$attrs{$_}"] } keys %attrs; + $ppd_xml .= qq( <REQUIRE $attrs />\n); + } + + my $archname = $Config{archname}; + if ($] >= 5.008) { + # archname did not change from 5.6 to 5.8, but those versions may + # not be not binary compatible so now we append the part of the + # version that changes when binary compatibility may change + $archname .= "-$Config{PERL_REVISION}.$Config{PERL_VERSION}"; + } + $ppd_xml .= sprintf <<'PPD_OUT', $archname; + <ARCHITECTURE NAME="%s" /> +PPD_OUT + + if ($self->{PPM_INSTALL_SCRIPT}) { + if ($self->{PPM_INSTALL_EXEC}) { + $ppd_xml .= sprintf qq{ <INSTALL EXEC="%s">%s</INSTALL>\n}, + $self->{PPM_INSTALL_EXEC}, $self->{PPM_INSTALL_SCRIPT}; + } + else { + $ppd_xml .= sprintf qq{ <INSTALL>%s</INSTALL>\n}, + $self->{PPM_INSTALL_SCRIPT}; + } + } + + my ($bin_location) = $self->{BINARY_LOCATION} || ''; + $bin_location =~ s/\\/\\\\/g; + + $ppd_xml .= sprintf <<'PPD_XML', $bin_location; + <CODEBASE HREF="%s" /> + </IMPLEMENTATION> +</SOFTPKG> +PPD_XML + + my @ppd_cmds = $self->echo($ppd_xml, '$(DISTNAME).ppd'); + + return sprintf <<'PPD_OUT', join "\n\t", @ppd_cmds; +# Creates a PPD (Perl Package Description) for a binary distribution. +ppd : + %s +PPD_OUT + +} + +=item prefixify + + $MM->prefixify($var, $prefix, $new_prefix, $default); + +Using either $MM->{uc $var} || $Config{lc $var}, it will attempt to +replace it's $prefix with a $new_prefix. + +Should the $prefix fail to match I<AND> a PREFIX was given as an +argument to WriteMakefile() it will set it to the $new_prefix + +$default. This is for systems whose file layouts don't neatly fit into +our ideas of prefixes. + +This is for heuristics which attempt to create directory structures +that mirror those of the installed perl. + +For example: + + $MM->prefixify('installman1dir', '/usr', '/home/foo', 'man/man1'); + +this will attempt to remove '/usr' from the front of the +$MM->{INSTALLMAN1DIR} path (initializing it to $Config{installman1dir} +if necessary) and replace it with '/home/foo'. If this fails it will +simply use '/home/foo/man/man1'. + +=cut + +sub prefixify { + my($self,$var,$sprefix,$rprefix,$default) = @_; + + my $path = $self->{uc $var} || + $Config_Override{lc $var} || $Config{lc $var} || ''; + + $rprefix .= '/' if $sprefix =~ m|/$|; + + print STDERR " prefixify $var => $path\n" if $Verbose >= 2; + print STDERR " from $sprefix to $rprefix\n" if $Verbose >= 2; + + if( $self->{ARGS}{PREFIX} && + $path !~ s{^\Q$sprefix\E\b}{$rprefix}s ) + { + + print STDERR " cannot prefix, using default.\n" if $Verbose >= 2; + print STDERR " no default!\n" if !$default && $Verbose >= 2; + + $path = $self->catdir($rprefix, $default) if $default; + } + + print " now $path\n" if $Verbose >= 2; + return $self->{uc $var} = $path; +} + + +=item processPL (o) + +Defines targets to run *.PL files. + +=cut + +sub processPL { + my $self = shift; + my $pl_files = $self->{PL_FILES}; + + return "" unless $pl_files; + + my $m = ''; + foreach my $plfile (sort keys %$pl_files) { + my $list = ref($pl_files->{$plfile}) + ? $pl_files->{$plfile} + : [$pl_files->{$plfile}]; + + foreach my $target (@$list) { + if( $Is{VMS} ) { + $plfile = vmsify($self->eliminate_macros($plfile)); + $target = vmsify($self->eliminate_macros($target)); + } + + # Normally a .PL file runs AFTER pm_to_blib so it can have + # blib in its @INC and load the just built modules. BUT if + # the generated module is something in $(TO_INST_PM) which + # pm_to_blib depends on then it can't depend on pm_to_blib + # else we have a dependency loop. + my $pm_dep; + my $perlrun; + if( defined $self->{PM}{$target} ) { + $pm_dep = ''; + $perlrun = 'PERLRUN'; + } + else { + $pm_dep = 'pm_to_blib'; + $perlrun = 'PERLRUNINST'; + } + + $m .= <<MAKE_FRAG; + +all :: $target + \$(NOECHO) \$(NOOP) + +$target :: $plfile $pm_dep + \$($perlrun) $plfile $target +MAKE_FRAG + + } + } + + return $m; +} + +=item quote_paren + +Backslashes parentheses C<()> in command line arguments. +Doesn't handle recursive Makefile C<$(...)> constructs, +but handles simple ones. + +=cut + +sub quote_paren { + my $arg = shift; + $arg =~ s{\$\((.+?)\)}{\$\\\\($1\\\\)}g; # protect $(...) + $arg =~ s{(?<!\\)([()])}{\\$1}g; # quote unprotected + $arg =~ s{\$\\\\\((.+?)\\\\\)}{\$($1)}g; # unprotect $(...) + return $arg; +} + +=item replace_manpage_separator + + my $man_name = $MM->replace_manpage_separator($file_path); + +Takes the name of a package, which may be a nested package, in the +form 'Foo/Bar.pm' and replaces the slash with C<::> or something else +safe for a man page file name. Returns the replacement. + +=cut + +sub replace_manpage_separator { + my($self,$man) = @_; + + $man =~ s,/+,::,g; + return $man; +} + + +=item cd + +=cut + +sub cd { + my($self, $dir, @cmds) = @_; + + # No leading tab and no trailing newline makes for easier embedding + my $make_frag = join "\n\t", map { "cd $dir && $_" } @cmds; + + return $make_frag; +} + +=item oneliner + +=cut + +sub oneliner { + my($self, $cmd, $switches) = @_; + $switches = [] unless defined $switches; + + # Strip leading and trailing newlines + $cmd =~ s{^\n+}{}; + $cmd =~ s{\n+$}{}; + + my @cmds = split /\n/, $cmd; + $cmd = join " \n\t -e ", map $self->quote_literal($_), @cmds; + $cmd = $self->escape_newlines($cmd); + + $switches = join ' ', @$switches; + + return qq{\$(ABSPERLRUN) $switches -e $cmd --}; +} + + +=item quote_literal + +=cut + +sub quote_literal { + my($self, $text) = @_; + + # I think all we have to quote is single quotes and I think + # this is a safe way to do it. + $text =~ s{'}{'\\''}g; + + return "'$text'"; +} + + +=item escape_newlines + +=cut + +sub escape_newlines { + my($self, $text) = @_; + + $text =~ s{\n}{\\\n}g; + + return $text; +} + + +=item max_exec_len + +Using POSIX::ARG_MAX. Otherwise falling back to 4096. + +=cut + +sub max_exec_len { + my $self = shift; + + if (!defined $self->{_MAX_EXEC_LEN}) { + if (my $arg_max = eval { require POSIX; &POSIX::ARG_MAX }) { + $self->{_MAX_EXEC_LEN} = $arg_max; + } + else { # POSIX minimum exec size + $self->{_MAX_EXEC_LEN} = 4096; + } + } + + return $self->{_MAX_EXEC_LEN}; +} + + +=item static (o) + +Defines the static target. + +=cut + +sub static { +# --- Static Loading Sections --- + + my($self) = shift; + ' +## $(INST_PM) has been moved to the all: target. +## It remains here for awhile to allow for old usage: "make static" +static :: $(FIRST_MAKEFILE) $(INST_STATIC) + $(NOECHO) $(NOOP) +'; +} + +=item static_lib (o) + +Defines how to produce the *.a (or equivalent) files. + +=cut + +sub static_lib { + my($self) = @_; + return '' unless $self->has_link_code; + + my(@m); + push(@m, <<'END'); + +$(INST_STATIC) : $(OBJECT) $(MYEXTLIB) $(INST_ARCHAUTODIR)$(DFSEP).exists + $(RM_RF) $@ +END + + # If this extension has its own library (eg SDBM_File) + # then copy that to $(INST_STATIC) and add $(OBJECT) into it. + push(@m, <<'MAKE_FRAG') if $self->{MYEXTLIB}; + $(CP) $(MYEXTLIB) $@ +MAKE_FRAG + + my $ar; + if (exists $self->{FULL_AR} && -x $self->{FULL_AR}) { + # Prefer the absolute pathed ar if available so that PATH + # doesn't confuse us. Perl itself is built with the full_ar. + $ar = 'FULL_AR'; + } else { + $ar = 'AR'; + } + push @m, sprintf <<'MAKE_FRAG', $ar; + $(%s) $(AR_STATIC_ARGS) $@ $(OBJECT) && $(RANLIB) $@ + $(CHMOD) $(PERM_RWX) $@ + $(NOECHO) $(ECHO) "$(EXTRALIBS)" > $(INST_ARCHAUTODIR)/extralibs.ld +MAKE_FRAG + + # Old mechanism - still available: + push @m, <<'MAKE_FRAG' if $self->{PERL_SRC} && $self->{EXTRALIBS}; + $(NOECHO) $(ECHO) "$(EXTRALIBS)" >> $(PERL_SRC)/ext.libs +MAKE_FRAG + + join('', @m); +} + +=item staticmake (o) + +Calls makeaperl. + +=cut + +sub staticmake { + my($self, %attribs) = @_; + my(@static); + + my(@searchdirs)=($self->{PERL_ARCHLIB}, $self->{SITEARCHEXP}, $self->{INST_ARCHLIB}); + + # And as it's not yet built, we add the current extension + # but only if it has some C code (or XS code, which implies C code) + if (@{$self->{C}}) { + @static = $self->catfile($self->{INST_ARCHLIB}, + "auto", + $self->{FULLEXT}, + "$self->{BASEEXT}$self->{LIB_EXT}" + ); + } + + # Either we determine now, which libraries we will produce in the + # subdirectories or we do it at runtime of the make. + + # We could ask all subdir objects, but I cannot imagine, why it + # would be necessary. + + # Instead we determine all libraries for the new perl at + # runtime. + my(@perlinc) = ($self->{INST_ARCHLIB}, $self->{INST_LIB}, $self->{PERL_ARCHLIB}, $self->{PERL_LIB}); + + $self->makeaperl(MAKE => $self->{MAKEFILE}, + DIRS => \@searchdirs, + STAT => \@static, + INCL => \@perlinc, + TARGET => $self->{MAP_TARGET}, + TMP => "", + LIBPERL => $self->{LIBPERL_A} + ); +} + +=item subdir_x (o) + +Helper subroutine for subdirs + +=cut + +sub subdir_x { + my($self, $subdir) = @_; + + my $subdir_cmd = $self->cd($subdir, + '$(MAKE) $(USEMAKEFILE) $(FIRST_MAKEFILE) all $(PASTHRU)' + ); + return sprintf <<'EOT', $subdir_cmd; + +subdirs :: + $(NOECHO) %s +EOT + +} + +=item subdirs (o) + +Defines targets to process subdirectories. + +=cut + +sub subdirs { +# --- Sub-directory Sections --- + my($self) = shift; + my(@m); + # This method provides a mechanism to automatically deal with + # subdirectories containing further Makefile.PL scripts. + # It calls the subdir_x() method for each subdirectory. + foreach my $dir (@{$self->{DIR}}){ + push(@m, $self->subdir_x($dir)); +#### print "Including $dir subdirectory\n"; + } + if (@m){ + unshift(@m, " +# The default clean, realclean and test targets in this Makefile +# have automatically been given entries for each subdir. + +"); + } else { + push(@m, "\n# none") + } + join('',@m); +} + +=item test (o) + +Defines the test targets. + +=cut + +sub test { +# --- Test and Installation Sections --- + + my($self, %attribs) = @_; + my $tests = $attribs{TESTS} || ''; + if (!$tests && -d 't') { + $tests = $self->find_tests; + } + # note: 'test.pl' name is also hardcoded in init_dirscan() + my(@m); + push(@m," +TEST_VERBOSE=0 +TEST_TYPE=test_\$(LINKTYPE) +TEST_FILE = test.pl +TEST_FILES = $tests +TESTDB_SW = -d + +testdb :: testdb_\$(LINKTYPE) + +test :: \$(TEST_TYPE) subdirs-test + +subdirs-test :: + \$(NOECHO) \$(NOOP) + +"); + + foreach my $dir (@{ $self->{DIR} }) { + my $test = $self->cd($dir, '$(MAKE) test $(PASTHRU)'); + + push @m, <<END +subdirs-test :: + \$(NOECHO) $test + +END + } + + push(@m, "\t\$(NOECHO) \$(ECHO) 'No tests defined for \$(NAME) extension.'\n") + unless $tests or -f "test.pl" or @{$self->{DIR}}; + push(@m, "\n"); + + push(@m, "test_dynamic :: pure_all\n"); + push(@m, $self->test_via_harness('$(FULLPERLRUN)', '$(TEST_FILES)')) + if $tests; + push(@m, $self->test_via_script('$(FULLPERLRUN)', '$(TEST_FILE)')) + if -f "test.pl"; + push(@m, "\n"); + + push(@m, "testdb_dynamic :: pure_all\n"); + push(@m, $self->test_via_script('$(FULLPERLRUN) $(TESTDB_SW)', + '$(TEST_FILE)')); + push(@m, "\n"); + + # Occasionally we may face this degenerate target: + push @m, "test_ : test_dynamic\n\n"; + + if ($self->needs_linking()) { + push(@m, "test_static :: pure_all \$(MAP_TARGET)\n"); + push(@m, $self->test_via_harness('./$(MAP_TARGET)', '$(TEST_FILES)')) if $tests; + push(@m, $self->test_via_script('./$(MAP_TARGET)', '$(TEST_FILE)')) if -f "test.pl"; + push(@m, "\n"); + push(@m, "testdb_static :: pure_all \$(MAP_TARGET)\n"); + push(@m, $self->test_via_script('./$(MAP_TARGET) $(TESTDB_SW)', '$(TEST_FILE)')); + push(@m, "\n"); + } else { + push @m, "test_static :: test_dynamic\n"; + push @m, "testdb_static :: testdb_dynamic\n"; + } + join("", @m); +} + +=item test_via_harness (override) + +For some reason which I forget, Unix machines like to have +PERL_DL_NONLAZY set for tests. + +=cut + +sub test_via_harness { + my($self, $perl, $tests) = @_; + return $self->SUPER::test_via_harness("PERL_DL_NONLAZY=1 $perl", $tests); +} + +=item test_via_script (override) + +Again, the PERL_DL_NONLAZY thing. + +=cut + +sub test_via_script { + my($self, $perl, $script) = @_; + return $self->SUPER::test_via_script("PERL_DL_NONLAZY=1 $perl", $script); +} + + +=item tool_xsubpp (o) + +Determines typemaps, xsubpp version, prototype behaviour. + +=cut + +sub tool_xsubpp { + my($self) = shift; + return "" unless $self->needs_linking; + + my $xsdir; + my @xsubpp_dirs = @INC; + + # Make sure we pick up the new xsubpp if we're building perl. + unshift @xsubpp_dirs, $self->{PERL_LIB} if $self->{PERL_CORE}; + + foreach my $dir (@xsubpp_dirs) { + $xsdir = $self->catdir($dir, 'ExtUtils'); + if( -r $self->catfile($xsdir, "xsubpp") ) { + last; + } + } + + my $tmdir = File::Spec->catdir($self->{PERL_LIB},"ExtUtils"); + my(@tmdeps) = $self->catfile($tmdir,'typemap'); + if( $self->{TYPEMAPS} ){ + foreach my $typemap (@{$self->{TYPEMAPS}}){ + if( ! -f $typemap ) { + warn "Typemap $typemap not found.\n"; + } + else { + push(@tmdeps, $typemap); + } + } + } + push(@tmdeps, "typemap") if -f "typemap"; + my(@tmargs) = map("-typemap $_", @tmdeps); + if( exists $self->{XSOPT} ){ + unshift( @tmargs, $self->{XSOPT} ); + } + + if ($Is{VMS} && + $Config{'ldflags'} && + $Config{'ldflags'} =~ m!/Debug!i && + (!exists($self->{XSOPT}) || $self->{XSOPT} !~ /linenumbers/) + ) + { + unshift(@tmargs,'-nolinenumbers'); + } + + + $self->{XSPROTOARG} = "" unless defined $self->{XSPROTOARG}; + + return qq{ +XSUBPPDIR = $xsdir +XSUBPP = \$(XSUBPPDIR)\$(DFSEP)xsubpp +XSUBPPRUN = \$(PERLRUN) \$(XSUBPP) +XSPROTOARG = $self->{XSPROTOARG} +XSUBPPDEPS = @tmdeps \$(XSUBPP) +XSUBPPARGS = @tmargs +XSUBPP_EXTRA_ARGS = +}; +}; + + +=item all_target + +Build man pages, too + +=cut + +sub all_target { + my $self = shift; + + return <<'MAKE_EXT'; +all :: pure_all manifypods + $(NOECHO) $(NOOP) +MAKE_EXT +} + +=item top_targets (o) + +Defines the targets all, subdirs, config, and O_FILES + +=cut + +sub top_targets { +# --- Target Sections --- + + my($self) = shift; + my(@m); + + push @m, $self->all_target, "\n" unless $self->{SKIPHASH}{'all'}; + + push @m, ' +pure_all :: config pm_to_blib subdirs linkext + $(NOECHO) $(NOOP) + +subdirs :: $(MYEXTLIB) + $(NOECHO) $(NOOP) + +config :: $(FIRST_MAKEFILE) blibdirs + $(NOECHO) $(NOOP) +'; + + push @m, ' +$(O_FILES): $(H_FILES) +' if @{$self->{O_FILES} || []} && @{$self->{H} || []}; + + push @m, q{ +help : + perldoc ExtUtils::MakeMaker +}; + + join('',@m); +} + +=item writedoc + +Obsolete, deprecated method. Not used since Version 5.21. + +=cut + +sub writedoc { +# --- perllocal.pod section --- + my($self,$what,$name,@attribs)=@_; + my $time = localtime; + print "=head2 $time: $what C<$name>\n\n=over 4\n\n=item *\n\n"; + print join "\n\n=item *\n\n", map("C<$_>",@attribs); + print "\n\n=back\n\n"; +} + +=item xs_c (o) + +Defines the suffix rules to compile XS files to C. + +=cut + +sub xs_c { + my($self) = shift; + return '' unless $self->needs_linking(); + ' +.xs.c: + $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(XSUBPP_EXTRA_ARGS) $*.xs > $*.xsc && $(MV) $*.xsc $*.c +'; +} + +=item xs_cpp (o) + +Defines the suffix rules to compile XS files to C++. + +=cut + +sub xs_cpp { + my($self) = shift; + return '' unless $self->needs_linking(); + ' +.xs.cpp: + $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.xsc && $(MV) $*.xsc $*.cpp +'; +} + +=item xs_o (o) + +Defines suffix rules to go from XS to object files directly. This is +only intended for broken make implementations. + +=cut + +sub xs_o { # many makes are too dumb to use xs_c then c_o + my($self) = shift; + return '' unless $self->needs_linking(); + ' +.xs$(OBJ_EXT): + $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.xsc && $(MV) $*.xsc $*.c + $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c +'; +} + + +1; + +=back + +=head1 SEE ALSO + +L<ExtUtils::MakeMaker> + +=cut + +__END__ diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MM_VMS.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MM_VMS.pm new file mode 100644 index 00000000000..2066d035976 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MM_VMS.pm @@ -0,0 +1,1994 @@ +package ExtUtils::MM_VMS; + +use strict; + +use ExtUtils::MakeMaker::Config; +require Exporter; + +BEGIN { + # so we can compile the thing on non-VMS platforms. + if( $^O eq 'VMS' ) { + require VMS::Filespec; + VMS::Filespec->import; + } +} + +use File::Basename; + +our $VERSION = '6.56'; + +require ExtUtils::MM_Any; +require ExtUtils::MM_Unix; +our @ISA = qw( ExtUtils::MM_Any ExtUtils::MM_Unix ); + +use ExtUtils::MakeMaker qw($Verbose neatvalue); +our $Revision = $ExtUtils::MakeMaker::Revision; + + +=head1 NAME + +ExtUtils::MM_VMS - methods to override UN*X behaviour in ExtUtils::MakeMaker + +=head1 SYNOPSIS + + Do not use this directly. + Instead, use ExtUtils::MM and it will figure out which MM_* + class to use for you. + +=head1 DESCRIPTION + +See ExtUtils::MM_Unix for a documentation of the methods provided +there. This package overrides the implementation of these methods, not +the semantics. + +=head2 Methods always loaded + +=over 4 + +=item wraplist + +Converts a list into a string wrapped at approximately 80 columns. + +=cut + +sub wraplist { + my($self) = shift; + my($line,$hlen) = ('',0); + + foreach my $word (@_) { + # Perl bug -- seems to occasionally insert extra elements when + # traversing array (scalar(@array) doesn't show them, but + # foreach(@array) does) (5.00307) + next unless $word =~ /\w/; + $line .= ' ' if length($line); + if ($hlen > 80) { $line .= "\\\n\t"; $hlen = 0; } + $line .= $word; + $hlen += length($word) + 2; + } + $line; +} + + +# This isn't really an override. It's just here because ExtUtils::MM_VMS +# appears in @MM::ISA before ExtUtils::Liblist::Kid, so if there isn't an ext() +# in MM_VMS, then AUTOLOAD is called, and bad things happen. So, we just +# mimic inheritance here and hand off to ExtUtils::Liblist::Kid. +# XXX This hackery will die soon. --Schwern +sub ext { + require ExtUtils::Liblist::Kid; + goto &ExtUtils::Liblist::Kid::ext; +} + +=back + +=head2 Methods + +Those methods which override default MM_Unix methods are marked +"(override)", while methods unique to MM_VMS are marked "(specific)". +For overridden methods, documentation is limited to an explanation +of why this method overrides the MM_Unix method; see the ExtUtils::MM_Unix +documentation for more details. + +=over 4 + +=item guess_name (override) + +Try to determine name of extension being built. We begin with the name +of the current directory. Since VMS filenames are case-insensitive, +however, we look for a F<.pm> file whose name matches that of the current +directory (presumably the 'main' F<.pm> file for this extension), and try +to find a C<package> statement from which to obtain the Mixed::Case +package name. + +=cut + +sub guess_name { + my($self) = @_; + my($defname,$defpm,@pm,%xs); + local *PM; + + $defname = basename(fileify($ENV{'DEFAULT'})); + $defname =~ s![\d\-_]*\.dir.*$!!; # Clip off .dir;1 suffix, and package version + $defpm = $defname; + # Fallback in case for some reason a user has copied the files for an + # extension into a working directory whose name doesn't reflect the + # extension's name. We'll use the name of a unique .pm file, or the + # first .pm file with a matching .xs file. + if (not -e "${defpm}.pm") { + @pm = glob('*.pm'); + s/.pm$// for @pm; + if (@pm == 1) { ($defpm = $pm[0]) =~ s/.pm$//; } + elsif (@pm) { + %xs = map { s/.xs$//; ($_,1) } glob('*.xs'); ## no critic + if (keys %xs) { + foreach my $pm (@pm) { + $defpm = $pm, last if exists $xs{$pm}; + } + } + } + } + if (open(my $pm, '<', "${defpm}.pm")){ + while (<$pm>) { + if (/^\s*package\s+([^;]+)/i) { + $defname = $1; + last; + } + } + print STDOUT "Warning (non-fatal): Couldn't find package name in ${defpm}.pm;\n\t", + "defaulting package name to $defname\n" + if eof($pm); + close $pm; + } + else { + print STDOUT "Warning (non-fatal): Couldn't find ${defpm}.pm;\n\t", + "defaulting package name to $defname\n"; + } + $defname =~ s#[\d.\-_]+$##; + $defname; +} + +=item find_perl (override) + +Use VMS file specification syntax and CLI commands to find and +invoke Perl images. + +=cut + +sub find_perl { + my($self, $ver, $names, $dirs, $trace) = @_; + my($vmsfile,@sdirs,@snames,@cand); + my($rslt); + my($inabs) = 0; + local *TCF; + + if( $self->{PERL_CORE} ) { + # Check in relative directories first, so we pick up the current + # version of Perl if we're running MakeMaker as part of the main build. + @sdirs = sort { my($absa) = $self->file_name_is_absolute($a); + my($absb) = $self->file_name_is_absolute($b); + if ($absa && $absb) { return $a cmp $b } + else { return $absa ? 1 : ($absb ? -1 : ($a cmp $b)); } + } @$dirs; + # Check miniperl before perl, and check names likely to contain + # version numbers before "generic" names, so we pick up an + # executable that's less likely to be from an old installation. + @snames = sort { my($ba) = $a =~ m!([^:>\]/]+)$!; # basename + my($bb) = $b =~ m!([^:>\]/]+)$!; + my($ahasdir) = (length($a) - length($ba) > 0); + my($bhasdir) = (length($b) - length($bb) > 0); + if ($ahasdir and not $bhasdir) { return 1; } + elsif ($bhasdir and not $ahasdir) { return -1; } + else { $bb =~ /\d/ <=> $ba =~ /\d/ + or substr($ba,0,1) cmp substr($bb,0,1) + or length($bb) <=> length($ba) } } @$names; + } + else { + @sdirs = @$dirs; + @snames = @$names; + } + + # Image names containing Perl version use '_' instead of '.' under VMS + s/\.(\d+)$/_$1/ for @snames; + if ($trace >= 2){ + print "Looking for perl $ver by these names:\n"; + print "\t@snames,\n"; + print "in these dirs:\n"; + print "\t@sdirs\n"; + } + foreach my $dir (@sdirs){ + next unless defined $dir; # $self->{PERL_SRC} may be undefined + $inabs++ if $self->file_name_is_absolute($dir); + if ($inabs == 1) { + # We've covered relative dirs; everything else is an absolute + # dir (probably an installed location). First, we'll try + # potential command names, to see whether we can avoid a long + # MCR expression. + foreach my $name (@snames) { + push(@cand,$name) if $name =~ /^[\w\-\$]+$/; + } + $inabs++; # Should happen above in next $dir, but just in case... + } + foreach my $name (@snames){ + push @cand, ($name !~ m![/:>\]]!) ? $self->catfile($dir,$name) + : $self->fixpath($name,0); + } + } + foreach my $name (@cand) { + print "Checking $name\n" if $trace >= 2; + # If it looks like a potential command, try it without the MCR + if ($name =~ /^[\w\-\$]+$/) { + open(my $tcf, ">", "temp_mmvms.com") + or die('unable to open temp file'); + print $tcf "\$ set message/nofacil/nosever/noident/notext\n"; + print $tcf "\$ $name -e \"require $ver; print \"\"VER_OK\\n\"\"\"\n"; + close $tcf; + $rslt = `\@temp_mmvms.com` ; + unlink('temp_mmvms.com'); + if ($rslt =~ /VER_OK/) { + print "Using PERL=$name\n" if $trace; + return $name; + } + } + next unless $vmsfile = $self->maybe_command($name); + $vmsfile =~ s/;[\d\-]*$//; # Clip off version number; we can use a newer version as well + print "Executing $vmsfile\n" if ($trace >= 2); + open(my $tcf, '>', "temp_mmvms.com") + or die('unable to open temp file'); + print $tcf "\$ set message/nofacil/nosever/noident/notext\n"; + print $tcf "\$ mcr $vmsfile -e \"require $ver; print \"\"VER_OK\\n\"\"\" \n"; + close $tcf; + $rslt = `\@temp_mmvms.com`; + unlink('temp_mmvms.com'); + if ($rslt =~ /VER_OK/) { + print "Using PERL=MCR $vmsfile\n" if $trace; + return "MCR $vmsfile"; + } + } + print STDOUT "Unable to find a perl $ver (by these names: @$names, in these dirs: @$dirs)\n"; + 0; # false and not empty +} + +=item maybe_command (override) + +Follows VMS naming conventions for executable files. +If the name passed in doesn't exactly match an executable file, +appends F<.Exe> (or equivalent) to check for executable image, and F<.Com> +to check for DCL procedure. If this fails, checks directories in DCL$PATH +and finally F<Sys$System:> for an executable file having the name specified, +with or without the F<.Exe>-equivalent suffix. + +=cut + +sub maybe_command { + my($self,$file) = @_; + return $file if -x $file && ! -d _; + my(@dirs) = (''); + my(@exts) = ('',$Config{'exe_ext'},'.exe','.com'); + + if ($file !~ m![/:>\]]!) { + for (my $i = 0; defined $ENV{"DCL\$PATH;$i"}; $i++) { + my $dir = $ENV{"DCL\$PATH;$i"}; + $dir .= ':' unless $dir =~ m%[\]:]$%; + push(@dirs,$dir); + } + push(@dirs,'Sys$System:'); + foreach my $dir (@dirs) { + my $sysfile = "$dir$file"; + foreach my $ext (@exts) { + return $file if -x "$sysfile$ext" && ! -d _; + } + } + } + return 0; +} + + +=item pasthru (override) + +VMS has $(MMSQUALIFIERS) which is a listing of all the original command line +options. This is used in every invocation of make in the VMS Makefile so +PASTHRU should not be necessary. Using PASTHRU tends to blow commands past +the 256 character limit. + +=cut + +sub pasthru { + return "PASTHRU=\n"; +} + + +=item pm_to_blib (override) + +VMS wants a dot in every file so we can't have one called 'pm_to_blib', +it becomes 'pm_to_blib.' and MMS/K isn't smart enough to know that when +you have a target called 'pm_to_blib' it should look for 'pm_to_blib.'. + +So in VMS its pm_to_blib.ts. + +=cut + +sub pm_to_blib { + my $self = shift; + + my $make = $self->SUPER::pm_to_blib; + + $make =~ s{^pm_to_blib :}{pm_to_blib.ts :}m; + $make =~ s{\$\(TOUCH\) pm_to_blib}{\$(TOUCH) pm_to_blib.ts}; + + $make = <<'MAKE' . $make; +# Dummy target to match Unix target name; we use pm_to_blib.ts as +# timestamp file to avoid repeated invocations under VMS +pm_to_blib : pm_to_blib.ts + $(NOECHO) $(NOOP) + +MAKE + + return $make; +} + + +=item perl_script (override) + +If name passed in doesn't specify a readable file, appends F<.com> or +F<.pl> and tries again, since it's customary to have file types on all files +under VMS. + +=cut + +sub perl_script { + my($self,$file) = @_; + return $file if -r $file && ! -d _; + return "$file.com" if -r "$file.com"; + return "$file.pl" if -r "$file.pl"; + return ''; +} + + +=item replace_manpage_separator + +Use as separator a character which is legal in a VMS-syntax file name. + +=cut + +sub replace_manpage_separator { + my($self,$man) = @_; + $man = unixify($man); + $man =~ s#/+#__#g; + $man; +} + +=item init_DEST + +(override) Because of the difficulty concatenating VMS filepaths we +must pre-expand the DEST* variables. + +=cut + +sub init_DEST { + my $self = shift; + + $self->SUPER::init_DEST; + + # Expand DEST variables. + foreach my $var ($self->installvars) { + my $destvar = 'DESTINSTALL'.$var; + $self->{$destvar} = $self->eliminate_macros($self->{$destvar}); + } +} + + +=item init_DIRFILESEP + +No seperator between a directory path and a filename on VMS. + +=cut + +sub init_DIRFILESEP { + my($self) = shift; + + $self->{DIRFILESEP} = ''; + return 1; +} + + +=item init_main (override) + + +=cut + +sub init_main { + my($self) = shift; + + $self->SUPER::init_main; + + $self->{DEFINE} ||= ''; + if ($self->{DEFINE} ne '') { + my(@terms) = split(/\s+/,$self->{DEFINE}); + my(@defs,@udefs); + foreach my $def (@terms) { + next unless $def; + my $targ = \@defs; + if ($def =~ s/^-([DU])//) { # If it was a Unix-style definition + $targ = \@udefs if $1 eq 'U'; + $def =~ s/='(.*)'$/=$1/; # then remove shell-protection '' + $def =~ s/^'(.*)'$/$1/; # from entire term or argument + } + if ($def =~ /=/) { + $def =~ s/"/""/g; # Protect existing " from DCL + $def = qq["$def"]; # and quote to prevent parsing of = + } + push @$targ, $def; + } + + $self->{DEFINE} = ''; + if (@defs) { + $self->{DEFINE} = '/Define=(' . join(',',@defs) . ')'; + } + if (@udefs) { + $self->{DEFINE} .= '/Undef=(' . join(',',@udefs) . ')'; + } + } +} + +=item init_others (override) + +Provide VMS-specific forms of various utility commands, then hand +off to the default MM_Unix method. + +DEV_NULL should probably be overriden with something. + +Also changes EQUALIZE_TIMESTAMP to set revision date of target file to +one second later than source file, since MMK interprets precisely +equal revision dates for a source and target file as a sign that the +target needs to be updated. + +=cut + +sub init_others { + my($self) = @_; + + $self->{NOOP} = 'Continue'; + $self->{NOECHO} ||= '@ '; + + $self->{MAKEFILE} ||= $self->{FIRST_MAKEFILE} || 'Descrip.MMS'; + $self->{FIRST_MAKEFILE} ||= $self->{MAKEFILE}; + $self->{MAKE_APERL_FILE} ||= 'Makeaperl.MMS'; + $self->{MAKEFILE_OLD} ||= $self->eliminate_macros('$(FIRST_MAKEFILE)_old'); +# +# If an extension is not specified, then MMS/MMK assumes an +# an extension of .MMS. If there really is no extension, +# then a trailing "." needs to be appended to specify a +# a null extension. +# + $self->{MAKEFILE} .= '.' unless $self->{MAKEFILE} =~ m/\./; + $self->{FIRST_MAKEFILE} .= '.' unless $self->{FIRST_MAKEFILE} =~ m/\./; + $self->{MAKE_APERL_FILE} .= '.' unless $self->{MAKE_APERL_FILE} =~ m/\./; + $self->{MAKEFILE_OLD} .= '.' unless $self->{MAKEFILE_OLD} =~ m/\./; + + $self->{MACROSTART} ||= '/Macro=('; + $self->{MACROEND} ||= ')'; + $self->{USEMAKEFILE} ||= '/Descrip='; + + $self->{EQUALIZE_TIMESTAMP} ||= '$(ABSPERLRUN) -we "open F,qq{>>$ARGV[1]};close F;utime(0,(stat($ARGV[0]))[9]+1,$ARGV[1])"'; + + $self->{MOD_INSTALL} ||= + $self->oneliner(<<'CODE', ['-MExtUtils::Install']); +install([ from_to => {split(' ', <STDIN>)}, verbose => '$(VERBINST)', uninstall_shadows => '$(UNINST)', dir_mode => '$(PERM_DIR)' ]); +CODE + + $self->SUPER::init_others; + + $self->{SHELL} ||= 'Posix'; + + $self->{UMASK_NULL} = '! '; + + # Redirection on VMS goes before the command, not after as on Unix. + # $(DEV_NULL) is used once and its not worth going nuts over making + # it work. However, Unix's DEV_NULL is quite wrong for VMS. + $self->{DEV_NULL} = ''; + + if ($self->{OBJECT} =~ /\s/) { + $self->{OBJECT} =~ s/(\\)?\n+\s+/ /g; + $self->{OBJECT} = $self->wraplist( + map $self->fixpath($_,0), split /,?\s+/, $self->{OBJECT} + ); + } + + $self->{LDFROM} = $self->wraplist( + map $self->fixpath($_,0), split /,?\s+/, $self->{LDFROM} + ); +} + + +=item init_platform (override) + +Add PERL_VMS, MM_VMS_REVISION and MM_VMS_VERSION. + +MM_VMS_REVISION is for backwards compatibility before MM_VMS had a +$VERSION. + +=cut + +sub init_platform { + my($self) = shift; + + $self->{MM_VMS_REVISION} = $Revision; + $self->{MM_VMS_VERSION} = $VERSION; + $self->{PERL_VMS} = $self->catdir($self->{PERL_SRC}, 'VMS') + if $self->{PERL_SRC}; +} + + +=item platform_constants + +=cut + +sub platform_constants { + my($self) = shift; + my $make_frag = ''; + + foreach my $macro (qw(PERL_VMS MM_VMS_REVISION MM_VMS_VERSION)) + { + next unless defined $self->{$macro}; + $make_frag .= "$macro = $self->{$macro}\n"; + } + + return $make_frag; +} + + +=item init_VERSION (override) + +Override the *DEFINE_VERSION macros with VMS semantics. Translate the +MAKEMAKER filepath to VMS style. + +=cut + +sub init_VERSION { + my $self = shift; + + $self->SUPER::init_VERSION; + + $self->{DEFINE_VERSION} = '"$(VERSION_MACRO)=""$(VERSION)"""'; + $self->{XS_DEFINE_VERSION} = '"$(XS_VERSION_MACRO)=""$(XS_VERSION)"""'; + $self->{MAKEMAKER} = vmsify($INC{'ExtUtils/MakeMaker.pm'}); +} + + +=item constants (override) + +Fixes up numerous file and directory macros to insure VMS syntax +regardless of input syntax. Also makes lists of files +comma-separated. + +=cut + +sub constants { + my($self) = @_; + + # Be kind about case for pollution + for (@ARGV) { $_ = uc($_) if /POLLUTE/i; } + + # Cleanup paths for directories in MMS macros. + foreach my $macro ( qw [ + INST_BIN INST_SCRIPT INST_LIB INST_ARCHLIB + PERL_LIB PERL_ARCHLIB + PERL_INC PERL_SRC ], + (map { 'INSTALL'.$_ } $self->installvars) + ) + { + next unless defined $self->{$macro}; + next if $macro =~ /MAN/ && $self->{$macro} eq 'none'; + $self->{$macro} = $self->fixpath($self->{$macro},1); + } + + # Cleanup paths for files in MMS macros. + foreach my $macro ( qw[LIBPERL_A FIRST_MAKEFILE MAKEFILE_OLD + MAKE_APERL_FILE MYEXTLIB] ) + { + next unless defined $self->{$macro}; + $self->{$macro} = $self->fixpath($self->{$macro},0); + } + + # Fixup files for MMS macros + # XXX is this list complete? + for my $macro (qw/ + FULLEXT VERSION_FROM OBJECT LDFROM + / ) { + next unless defined $self->{$macro}; + $self->{$macro} = $self->fixpath($self->{$macro},0); + } + + + for my $macro (qw/ XS MAN1PODS MAN3PODS PM /) { + # Where is the space coming from? --jhi + next unless $self ne " " && defined $self->{$macro}; + my %tmp = (); + for my $key (keys %{$self->{$macro}}) { + $tmp{$self->fixpath($key,0)} = + $self->fixpath($self->{$macro}{$key},0); + } + $self->{$macro} = \%tmp; + } + + for my $macro (qw/ C O_FILES H /) { + next unless defined $self->{$macro}; + my @tmp = (); + for my $val (@{$self->{$macro}}) { + push(@tmp,$self->fixpath($val,0)); + } + $self->{$macro} = \@tmp; + } + + # mms/k does not define a $(MAKE) macro. + $self->{MAKE} = '$(MMS)$(MMSQUALIFIERS)'; + + return $self->SUPER::constants; +} + + +=item special_targets + +Clear the default .SUFFIXES and put in our own list. + +=cut + +sub special_targets { + my $self = shift; + + my $make_frag .= <<'MAKE_FRAG'; +.SUFFIXES : +.SUFFIXES : $(OBJ_EXT) .c .cpp .cxx .xs + +MAKE_FRAG + + return $make_frag; +} + +=item cflags (override) + +Bypass shell script and produce qualifiers for CC directly (but warn +user if a shell script for this extension exists). Fold multiple +/Defines into one, since some C compilers pay attention to only one +instance of this qualifier on the command line. + +=cut + +sub cflags { + my($self,$libperl) = @_; + my($quals) = $self->{CCFLAGS} || $Config{'ccflags'}; + my($definestr,$undefstr,$flagoptstr) = ('','',''); + my($incstr) = '/Include=($(PERL_INC)'; + my($name,$sys,@m); + + ( $name = $self->{NAME} . "_cflags" ) =~ s/:/_/g ; + print STDOUT "Unix shell script ".$Config{"$self->{'BASEEXT'}_cflags"}. + " required to modify CC command for $self->{'BASEEXT'}\n" + if ($Config{$name}); + + if ($quals =~ / -[DIUOg]/) { + while ($quals =~ / -([Og])(\d*)\b/) { + my($type,$lvl) = ($1,$2); + $quals =~ s/ -$type$lvl\b\s*//; + if ($type eq 'g') { $flagoptstr = '/NoOptimize'; } + else { $flagoptstr = '/Optimize' . (defined($lvl) ? "=$lvl" : ''); } + } + while ($quals =~ / -([DIU])(\S+)/) { + my($type,$def) = ($1,$2); + $quals =~ s/ -$type$def\s*//; + $def =~ s/"/""/g; + if ($type eq 'D') { $definestr .= qq["$def",]; } + elsif ($type eq 'I') { $incstr .= ',' . $self->fixpath($def,1); } + else { $undefstr .= qq["$def",]; } + } + } + if (length $quals and $quals !~ m!/!) { + warn "MM_VMS: Ignoring unrecognized CCFLAGS elements \"$quals\"\n"; + $quals = ''; + } + $definestr .= q["PERL_POLLUTE",] if $self->{POLLUTE}; + if (length $definestr) { chop($definestr); $quals .= "/Define=($definestr)"; } + if (length $undefstr) { chop($undefstr); $quals .= "/Undef=($undefstr)"; } + # Deal with $self->{DEFINE} here since some C compilers pay attention + # to only one /Define clause on command line, so we have to + # conflate the ones from $Config{'ccflags'} and $self->{DEFINE} + # ($self->{DEFINE} has already been VMSified in constants() above) + if ($self->{DEFINE}) { $quals .= $self->{DEFINE}; } + for my $type (qw(Def Undef)) { + my(@terms); + while ($quals =~ m:/${type}i?n?e?=([^/]+):ig) { + my $term = $1; + $term =~ s:^\((.+)\)$:$1:; + push @terms, $term; + } + if ($type eq 'Def') { + push @terms, qw[ $(DEFINE_VERSION) $(XS_DEFINE_VERSION) ]; + } + if (@terms) { + $quals =~ s:/${type}i?n?e?=[^/]+::ig; + $quals .= "/${type}ine=(" . join(',',@terms) . ')'; + } + } + + $libperl or $libperl = $self->{LIBPERL_A} || "libperl.olb"; + + # Likewise with $self->{INC} and /Include + if ($self->{'INC'}) { + my(@includes) = split(/\s+/,$self->{INC}); + foreach (@includes) { + s/^-I//; + $incstr .= ','.$self->fixpath($_,1); + } + } + $quals .= "$incstr)"; +# $quals =~ s/,,/,/g; $quals =~ s/\(,/(/g; + $self->{CCFLAGS} = $quals; + + $self->{PERLTYPE} ||= ''; + + $self->{OPTIMIZE} ||= $flagoptstr || $Config{'optimize'}; + if ($self->{OPTIMIZE} !~ m!/!) { + if ($self->{OPTIMIZE} =~ m!-g!) { $self->{OPTIMIZE} = '/Debug/NoOptimize' } + elsif ($self->{OPTIMIZE} =~ /-O(\d*)/) { + $self->{OPTIMIZE} = '/Optimize' . (defined($1) ? "=$1" : ''); + } + else { + warn "MM_VMS: Can't parse OPTIMIZE \"$self->{OPTIMIZE}\"; using default\n" if length $self->{OPTIMIZE}; + $self->{OPTIMIZE} = '/Optimize'; + } + } + + return $self->{CFLAGS} = qq{ +CCFLAGS = $self->{CCFLAGS} +OPTIMIZE = $self->{OPTIMIZE} +PERLTYPE = $self->{PERLTYPE} +}; +} + +=item const_cccmd (override) + +Adds directives to point C preprocessor to the right place when +handling #include E<lt>sys/foo.hE<gt> directives. Also constructs CC +command line a bit differently than MM_Unix method. + +=cut + +sub const_cccmd { + my($self,$libperl) = @_; + my(@m); + + return $self->{CONST_CCCMD} if $self->{CONST_CCCMD}; + return '' unless $self->needs_linking(); + if ($Config{'vms_cc_type'} eq 'gcc') { + push @m,' +.FIRST + ',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" Then Define/NoLog SYS GNU_CC_Include:[VMS]'; + } + elsif ($Config{'vms_cc_type'} eq 'vaxc') { + push @m,' +.FIRST + ',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" .and. F$TrnLnm("VAXC$Include").eqs."" Then Define/NoLog SYS Sys$Library + ',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" .and. F$TrnLnm("VAXC$Include").nes."" Then Define/NoLog SYS VAXC$Include'; + } + else { + push @m,' +.FIRST + ',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" .and. F$TrnLnm("DECC$System_Include").eqs."" Then Define/NoLog SYS ', + ($Config{'archname'} eq 'VMS_AXP' ? 'Sys$Library' : 'DECC$Library_Include'),' + ',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" .and. F$TrnLnm("DECC$System_Include").nes."" Then Define/NoLog SYS DECC$System_Include'; + } + + push(@m, "\n\nCCCMD = $Config{'cc'} \$(CCFLAGS)\$(OPTIMIZE)\n"); + + $self->{CONST_CCCMD} = join('',@m); +} + + +=item tools_other (override) + +Throw in some dubious extra macros for Makefile args. + +Also keep around the old $(SAY) macro in case somebody's using it. + +=cut + +sub tools_other { + my($self) = @_; + + # XXX Are these necessary? Does anyone override them? They're longer + # than just typing the literal string. + my $extra_tools = <<'EXTRA_TOOLS'; + +# Just in case anyone is using the old macro. +USEMACROS = $(MACROSTART) +SAY = $(ECHO) + +EXTRA_TOOLS + + return $self->SUPER::tools_other . $extra_tools; +} + +=item init_dist (override) + +VMSish defaults for some values. + + macro description default + + ZIPFLAGS flags to pass to ZIP -Vu + + COMPRESS compression command to gzip + use for tarfiles + SUFFIX suffix to put on -gz + compressed files + + SHAR shar command to use vms_share + + DIST_DEFAULT default target to use to tardist + create a distribution + + DISTVNAME Use VERSION_SYM instead of $(DISTNAME)-$(VERSION_SYM) + VERSION for the name + +=cut + +sub init_dist { + my($self) = @_; + $self->{ZIPFLAGS} ||= '-Vu'; + $self->{COMPRESS} ||= 'gzip'; + $self->{SUFFIX} ||= '-gz'; + $self->{SHAR} ||= 'vms_share'; + $self->{DIST_DEFAULT} ||= 'zipdist'; + + $self->SUPER::init_dist; + + $self->{DISTVNAME} = "$self->{DISTNAME}-$self->{VERSION_SYM}" + unless $self->{ARGS}{DISTVNAME}; + + return; +} + +=item c_o (override) + +Use VMS syntax on command line. In particular, $(DEFINE) and +$(PERL_INC) have been pulled into $(CCCMD). Also use MM[SK] macros. + +=cut + +sub c_o { + my($self) = @_; + return '' unless $self->needs_linking(); + ' +.c$(OBJ_EXT) : + $(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).c + +.cpp$(OBJ_EXT) : + $(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).cpp + +.cxx$(OBJ_EXT) : + $(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).cxx + +'; +} + +=item xs_c (override) + +Use MM[SK] macros. + +=cut + +sub xs_c { + my($self) = @_; + return '' unless $self->needs_linking(); + ' +.xs.c : + $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(MMS$TARGET_NAME).xs >$(MMS$TARGET) +'; +} + +=item xs_o (override) + +Use MM[SK] macros, and VMS command line for C compiler. + +=cut + +sub xs_o { # many makes are too dumb to use xs_c then c_o + my($self) = @_; + return '' unless $self->needs_linking(); + ' +.xs$(OBJ_EXT) : + $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(MMS$TARGET_NAME).xs >$(MMS$TARGET_NAME).c + $(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).c +'; +} + + +=item dlsyms (override) + +Create VMS linker options files specifying universal symbols for this +extension's shareable image, and listing other shareable images or +libraries to which it should be linked. + +=cut + +sub dlsyms { + my($self,%attribs) = @_; + + return '' unless $self->needs_linking(); + + my($funcs) = $attribs{DL_FUNCS} || $self->{DL_FUNCS} || {}; + my($vars) = $attribs{DL_VARS} || $self->{DL_VARS} || []; + my($funclist) = $attribs{FUNCLIST} || $self->{FUNCLIST} || []; + my(@m); + + unless ($self->{SKIPHASH}{'dynamic'}) { + push(@m,' +dynamic :: $(INST_ARCHAUTODIR)$(BASEEXT).opt + $(NOECHO) $(NOOP) +'); + } + + push(@m,' +static :: $(INST_ARCHAUTODIR)$(BASEEXT).opt + $(NOECHO) $(NOOP) +') unless $self->{SKIPHASH}{'static'}; + + push @m,' +$(INST_ARCHAUTODIR)$(BASEEXT).opt : $(BASEEXT).opt + $(CP) $(MMS$SOURCE) $(MMS$TARGET) + +$(BASEEXT).opt : Makefile.PL + $(PERLRUN) -e "use ExtUtils::Mksymlists;" - + ',qq[-e "Mksymlists('NAME' => '$self->{NAME}', 'DL_FUNCS' => ], + neatvalue($funcs),q[, 'DL_VARS' => ],neatvalue($vars), + q[, 'FUNCLIST' => ],neatvalue($funclist),qq[)"\n]; + + push @m, ' $(PERL) -e "print ""$(INST_STATIC)/Include='; + if ($self->{OBJECT} =~ /\bBASEEXT\b/ or + $self->{OBJECT} =~ /\b$self->{BASEEXT}\b/i) { + push @m, ($Config{d_vms_case_sensitive_symbols} + ? uc($self->{BASEEXT}) :'$(BASEEXT)'); + } + else { # We don't have a "main" object file, so pull 'em all in + # Upcase module names if linker is being case-sensitive + my($upcase) = $Config{d_vms_case_sensitive_symbols}; + my(@omods) = split ' ', $self->eliminate_macros($self->{OBJECT}); + for (@omods) { + s/\.[^.]*$//; # Trim off file type + s[\$\(\w+_EXT\)][]; # even as a macro + s/.*[:>\/\]]//; # Trim off dir spec + $_ = uc if $upcase; + }; + + my(@lines); + my $tmp = shift @omods; + foreach my $elt (@omods) { + $tmp .= ",$elt"; + if (length($tmp) > 80) { push @lines, $tmp; $tmp = ''; } + } + push @lines, $tmp; + push @m, '(', join( qq[, -\\n\\t"";" >>\$(MMS\$TARGET)\n\t\$(PERL) -e "print ""], @lines),')'; + } + push @m, '\n$(INST_STATIC)/Library\n"";" >>$(MMS$TARGET)',"\n"; + + if (length $self->{LDLOADLIBS}) { + my($line) = ''; + foreach my $lib (split ' ', $self->{LDLOADLIBS}) { + $lib =~ s%\$%\\\$%g; # Escape '$' in VMS filespecs + if (length($line) + length($lib) > 160) { + push @m, "\t\$(PERL) -e \"print qq{$line}\" >>\$(MMS\$TARGET)\n"; + $line = $lib . '\n'; + } + else { $line .= $lib . '\n'; } + } + push @m, "\t\$(PERL) -e \"print qq{$line}\" >>\$(MMS\$TARGET)\n" if $line; + } + + join('',@m); + +} + +=item dynamic_lib (override) + +Use VMS Link command. + +=cut + +sub dynamic_lib { + my($self, %attribs) = @_; + return '' unless $self->needs_linking(); #might be because of a subdir + + return '' unless $self->has_link_code(); + + my($otherldflags) = $attribs{OTHERLDFLAGS} || ""; + my($inst_dynamic_dep) = $attribs{INST_DYNAMIC_DEP} || ""; + my $shr = $Config{'dbgprefix'} . 'PerlShr'; + my(@m); + push @m," + +OTHERLDFLAGS = $otherldflags +INST_DYNAMIC_DEP = $inst_dynamic_dep + +"; + push @m, ' +$(INST_DYNAMIC) : $(INST_STATIC) $(PERL_INC)perlshr_attr.opt $(INST_ARCHAUTODIR)$(DFSEP).exists $(EXPORT_LIST) $(PERL_ARCHIVE) $(INST_DYNAMIC_DEP) + If F$TrnLNm("',$shr,'").eqs."" Then Define/NoLog/User ',"$shr Sys\$Share:$shr.$Config{'dlext'}",' + Link $(LDFLAGS) /Shareable=$(MMS$TARGET)$(OTHERLDFLAGS) $(BASEEXT).opt/Option,$(PERL_INC)perlshr_attr.opt/Option +'; + + join('',@m); +} + + +=item static_lib (override) + +Use VMS commands to manipulate object library. + +=cut + +sub static_lib { + my($self) = @_; + return '' unless $self->needs_linking(); + + return ' +$(INST_STATIC) : + $(NOECHO) $(NOOP) +' unless ($self->{OBJECT} or @{$self->{C} || []} or $self->{MYEXTLIB}); + + my(@m); + push @m,' +# Rely on suffix rule for update action +$(OBJECT) : $(INST_ARCHAUTODIR)$(DFSEP).exists + +$(INST_STATIC) : $(OBJECT) $(MYEXTLIB) +'; + # If this extension has its own library (eg SDBM_File) + # then copy that to $(INST_STATIC) and add $(OBJECT) into it. + push(@m, "\t",'$(CP) $(MYEXTLIB) $(MMS$TARGET)',"\n") if $self->{MYEXTLIB}; + + push(@m,"\t",'If F$Search("$(MMS$TARGET)").eqs."" Then Library/Object/Create $(MMS$TARGET)',"\n"); + + # if there was a library to copy, then we can't use MMS$SOURCE_LIST, + # 'cause it's a library and you can't stick them in other libraries. + # In that case, we use $OBJECT instead and hope for the best + if ($self->{MYEXTLIB}) { + push(@m,"\t",'Library/Object/Replace $(MMS$TARGET) $(OBJECT)',"\n"); + } else { + push(@m,"\t",'Library/Object/Replace $(MMS$TARGET) $(MMS$SOURCE_LIST)',"\n"); + } + + push @m, "\t\$(NOECHO) \$(PERL) -e 1 >\$(INST_ARCHAUTODIR)extralibs.ld\n"; + foreach my $lib (split ' ', $self->{EXTRALIBS}) { + push(@m,"\t",'$(NOECHO) $(PERL) -e "print qq{',$lib,'\n}" >>$(INST_ARCHAUTODIR)extralibs.ld',"\n"); + } + join('',@m); +} + + +=item extra_clean_files + +Clean up some OS specific files. Plus the temp file used to shorten +a lot of commands. + +=cut + +sub extra_clean_files { + return qw( + *.Map *.Dmp *.Lis *.cpp *.$(DLEXT) *.Opt $(BASEEXT).bso + .MM_Tmp + ); +} + + +=item zipfile_target + +=item tarfile_target + +=item shdist_target + +Syntax for invoking shar, tar and zip differs from that for Unix. + +=cut + +sub zipfile_target { + my($self) = shift; + + return <<'MAKE_FRAG'; +$(DISTVNAME).zip : distdir + $(PREOP) + $(ZIP) "$(ZIPFLAGS)" $(MMS$TARGET) [.$(DISTVNAME)...]*.*; + $(RM_RF) $(DISTVNAME) + $(POSTOP) +MAKE_FRAG +} + +sub tarfile_target { + my($self) = shift; + + return <<'MAKE_FRAG'; +$(DISTVNAME).tar$(SUFFIX) : distdir + $(PREOP) + $(TO_UNIX) + $(TAR) "$(TARFLAGS)" $(DISTVNAME).tar [.$(DISTVNAME)...] + $(RM_RF) $(DISTVNAME) + $(COMPRESS) $(DISTVNAME).tar + $(POSTOP) +MAKE_FRAG +} + +sub shdist_target { + my($self) = shift; + + return <<'MAKE_FRAG'; +shdist : distdir + $(PREOP) + $(SHAR) [.$(DISTVNAME)...]*.*; $(DISTVNAME).share + $(RM_RF) $(DISTVNAME) + $(POSTOP) +MAKE_FRAG +} + + +# --- Test and Installation Sections --- + +=item install (override) + +Work around DCL's 255 character limit several times,and use +VMS-style command line quoting in a few cases. + +=cut + +sub install { + my($self, %attribs) = @_; + my(@m); + + push @m, q[ +install :: all pure_install doc_install + $(NOECHO) $(NOOP) + +install_perl :: all pure_perl_install doc_perl_install + $(NOECHO) $(NOOP) + +install_site :: all pure_site_install doc_site_install + $(NOECHO) $(NOOP) + +pure_install :: pure_$(INSTALLDIRS)_install + $(NOECHO) $(NOOP) + +doc_install :: doc_$(INSTALLDIRS)_install + $(NOECHO) $(NOOP) + +pure__install : pure_site_install + $(NOECHO) $(ECHO) "INSTALLDIRS not defined, defaulting to INSTALLDIRS=site" + +doc__install : doc_site_install + $(NOECHO) $(ECHO) "INSTALLDIRS not defined, defaulting to INSTALLDIRS=site" + +# This hack brought to you by DCL's 255-character command line limit +pure_perl_install :: + $(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'read '.File::Spec->catfile('$(PERL_ARCHLIB)','auto','$(FULLEXT)','.packlist').' '" >.MM_tmp + $(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'write '.File::Spec->catfile('$(DESTINSTALLARCHLIB)','auto','$(FULLEXT)','.packlist').' '" >>.MM_tmp + $(NOECHO) $(ECHO_N) "$(INST_LIB) $(DESTINSTALLPRIVLIB) " >>.MM_tmp + $(NOECHO) $(ECHO_N) "$(INST_ARCHLIB) $(DESTINSTALLARCHLIB) " >>.MM_tmp + $(NOECHO) $(ECHO_N) "$(INST_BIN) $(DESTINSTALLBIN) " >>.MM_tmp + $(NOECHO) $(ECHO_N) "$(INST_SCRIPT) $(DESTINSTALLSCRIPT) " >>.MM_tmp + $(NOECHO) $(ECHO_N) "$(INST_MAN1DIR) $(DESTINSTALLMAN1DIR) " >>.MM_tmp + $(NOECHO) $(ECHO_N) "$(INST_MAN3DIR) $(DESTINSTALLMAN3DIR) " >>.MM_tmp + $(NOECHO) $(MOD_INSTALL) <.MM_tmp + $(NOECHO) $(RM_F) .MM_tmp + $(NOECHO) $(WARN_IF_OLD_PACKLIST) ].$self->catfile($self->{SITEARCHEXP},'auto',$self->{FULLEXT},'.packlist').q[ + +# Likewise +pure_site_install :: + $(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'read '.File::Spec->catfile('$(SITEARCHEXP)','auto','$(FULLEXT)','.packlist').' '" >.MM_tmp + $(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'write '.File::Spec->catfile('$(DESTINSTALLSITEARCH)','auto','$(FULLEXT)','.packlist').' '" >>.MM_tmp + $(NOECHO) $(ECHO_N) "$(INST_LIB) $(DESTINSTALLSITELIB) " >>.MM_tmp + $(NOECHO) $(ECHO_N) "$(INST_ARCHLIB) $(DESTINSTALLSITEARCH) " >>.MM_tmp + $(NOECHO) $(ECHO_N) "$(INST_BIN) $(DESTINSTALLSITEBIN) " >>.MM_tmp + $(NOECHO) $(ECHO_N) "$(INST_SCRIPT) $(DESTINSTALLSCRIPT) " >>.MM_tmp + $(NOECHO) $(ECHO_N) "$(INST_MAN1DIR) $(DESTINSTALLSITEMAN1DIR) " >>.MM_tmp + $(NOECHO) $(ECHO_N) "$(INST_MAN3DIR) $(DESTINSTALLSITEMAN3DIR) " >>.MM_tmp + $(NOECHO) $(MOD_INSTALL) <.MM_tmp + $(NOECHO) $(RM_F) .MM_tmp + $(NOECHO) $(WARN_IF_OLD_PACKLIST) ].$self->catfile($self->{PERL_ARCHLIB},'auto',$self->{FULLEXT},'.packlist').q[ + +pure_vendor_install :: + $(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'read '.File::Spec->catfile('$(VENDORARCHEXP)','auto','$(FULLEXT)','.packlist').' '" >.MM_tmp + $(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'write '.File::Spec->catfile('$(DESTINSTALLVENDORARCH)','auto','$(FULLEXT)','.packlist').' '" >>.MM_tmp + $(NOECHO) $(ECHO_N) "$(INST_LIB) $(DESTINSTALLVENDORLIB) " >>.MM_tmp + $(NOECHO) $(ECHO_N) "$(INST_ARCHLIB) $(DESTINSTALLVENDORARCH) " >>.MM_tmp + $(NOECHO) $(ECHO_N) "$(INST_BIN) $(DESTINSTALLVENDORBIN) " >>.MM_tmp + $(NOECHO) $(ECHO_N) "$(INST_SCRIPT) $(DESTINSTALLSCRIPT) " >>.MM_tmp + $(NOECHO) $(ECHO_N) "$(INST_MAN1DIR) $(DESTINSTALLVENDORMAN1DIR) " >>.MM_tmp + $(NOECHO) $(ECHO_N) "$(INST_MAN3DIR) $(DESTINSTALLVENDORMAN3DIR) " >>.MM_tmp + $(NOECHO) $(MOD_INSTALL) <.MM_tmp + $(NOECHO) $(RM_F) .MM_tmp + +# Ditto +doc_perl_install :: + $(NOECHO) $(ECHO) "Appending installation info to ].$self->catfile($self->{DESTINSTALLARCHLIB}, 'perllocal.pod').q[" + $(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB) + $(NOECHO) $(ECHO_N) "installed into|$(INSTALLPRIVLIB)|" >.MM_tmp + $(NOECHO) $(ECHO_N) "LINKTYPE|$(LINKTYPE)|VERSION|$(VERSION)|EXE_FILES|$(EXE_FILES) " >>.MM_tmp + $(NOECHO) $(DOC_INSTALL) "Module" "$(NAME)" <.MM_tmp >>].$self->catfile($self->{DESTINSTALLARCHLIB},'perllocal.pod').q[ + $(NOECHO) $(RM_F) .MM_tmp + +# And again +doc_site_install :: + $(NOECHO) $(ECHO) "Appending installation info to ].$self->catfile($self->{DESTINSTALLARCHLIB}, 'perllocal.pod').q[" + $(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB) + $(NOECHO) $(ECHO_N) "installed into|$(INSTALLSITELIB)|" >.MM_tmp + $(NOECHO) $(ECHO_N) "LINKTYPE|$(LINKTYPE)|VERSION|$(VERSION)|EXE_FILES|$(EXE_FILES) " >>.MM_tmp + $(NOECHO) $(DOC_INSTALL) "Module" "$(NAME)" <.MM_tmp >>].$self->catfile($self->{DESTINSTALLARCHLIB},'perllocal.pod').q[ + $(NOECHO) $(RM_F) .MM_tmp + +doc_vendor_install :: + $(NOECHO) $(ECHO) "Appending installation info to ].$self->catfile($self->{DESTINSTALLARCHLIB}, 'perllocal.pod').q[" + $(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB) + $(NOECHO) $(ECHO_N) "installed into|$(INSTALLVENDORLIB)|" >.MM_tmp + $(NOECHO) $(ECHO_N) "LINKTYPE|$(LINKTYPE)|VERSION|$(VERSION)|EXE_FILES|$(EXE_FILES) " >>.MM_tmp + $(NOECHO) $(DOC_INSTALL) "Module" "$(NAME)" <.MM_tmp >>].$self->catfile($self->{DESTINSTALLARCHLIB},'perllocal.pod').q[ + $(NOECHO) $(RM_F) .MM_tmp + +]; + + push @m, q[ +uninstall :: uninstall_from_$(INSTALLDIRS)dirs + $(NOECHO) $(NOOP) + +uninstall_from_perldirs :: + $(NOECHO) $(UNINSTALL) ].$self->catfile($self->{PERL_ARCHLIB},'auto',$self->{FULLEXT},'.packlist').q[ + $(NOECHO) $(ECHO) "Uninstall is now deprecated and makes no actual changes." + $(NOECHO) $(ECHO) "Please check the list above carefully for errors, and manually remove" + $(NOECHO) $(ECHO) "the appropriate files. Sorry for the inconvenience." + +uninstall_from_sitedirs :: + $(NOECHO) $(UNINSTALL) ].$self->catfile($self->{SITEARCHEXP},'auto',$self->{FULLEXT},'.packlist').q[ + $(NOECHO) $(ECHO) "Uninstall is now deprecated and makes no actual changes." + $(NOECHO) $(ECHO) "Please check the list above carefully for errors, and manually remove" + $(NOECHO) $(ECHO) "the appropriate files. Sorry for the inconvenience." +]; + + join('',@m); +} + +=item perldepend (override) + +Use VMS-style syntax for files; it's cheaper to just do it directly here +than to have the MM_Unix method call C<catfile> repeatedly. Also, if +we have to rebuild Config.pm, use MM[SK] to do it. + +=cut + +sub perldepend { + my($self) = @_; + my(@m); + + push @m, ' +$(OBJECT) : $(PERL_INC)EXTERN.h, $(PERL_INC)INTERN.h, $(PERL_INC)XSUB.h +$(OBJECT) : $(PERL_INC)av.h, $(PERL_INC)cc_runtime.h, $(PERL_INC)config.h +$(OBJECT) : $(PERL_INC)cop.h, $(PERL_INC)cv.h, $(PERL_INC)embed.h +$(OBJECT) : $(PERL_INC)embedvar.h, $(PERL_INC)form.h +$(OBJECT) : $(PERL_INC)gv.h, $(PERL_INC)handy.h, $(PERL_INC)hv.h +$(OBJECT) : $(PERL_INC)intrpvar.h, $(PERL_INC)iperlsys.h, $(PERL_INC)keywords.h +$(OBJECT) : $(PERL_INC)mg.h, $(PERL_INC)nostdio.h, $(PERL_INC)op.h +$(OBJECT) : $(PERL_INC)opcode.h, $(PERL_INC)patchlevel.h +$(OBJECT) : $(PERL_INC)perl.h, $(PERL_INC)perlio.h +$(OBJECT) : $(PERL_INC)perlsdio.h, $(PERL_INC)perlvars.h +$(OBJECT) : $(PERL_INC)perly.h, $(PERL_INC)pp.h, $(PERL_INC)pp_proto.h +$(OBJECT) : $(PERL_INC)proto.h, $(PERL_INC)regcomp.h, $(PERL_INC)regexp.h +$(OBJECT) : $(PERL_INC)regnodes.h, $(PERL_INC)scope.h, $(PERL_INC)sv.h +$(OBJECT) : $(PERL_INC)thread.h, $(PERL_INC)util.h, $(PERL_INC)vmsish.h + +' if $self->{OBJECT}; + + if ($self->{PERL_SRC}) { + my(@macros); + my($mmsquals) = '$(USEMAKEFILE)[.vms]$(FIRST_MAKEFILE)'; + push(@macros,'__AXP__=1') if $Config{'archname'} eq 'VMS_AXP'; + push(@macros,'DECC=1') if $Config{'vms_cc_type'} eq 'decc'; + push(@macros,'GNUC=1') if $Config{'vms_cc_type'} eq 'gcc'; + push(@macros,'SOCKET=1') if $Config{'d_has_sockets'}; + push(@macros,qq["CC=$Config{'cc'}"]) if $Config{'cc'} =~ m!/!; + $mmsquals .= '$(USEMACROS)' . join(',',@macros) . '$(MACROEND)' if @macros; + push(@m,q[ +# Check for unpropagated config.sh changes. Should never happen. +# We do NOT just update config.h because that is not sufficient. +# An out of date config.h is not fatal but complains loudly! +$(PERL_INC)config.h : $(PERL_SRC)config.sh + $(NOOP) + +$(PERL_ARCHLIB)Config.pm : $(PERL_SRC)config.sh + $(NOECHO) Write Sys$Error "$(PERL_ARCHLIB)Config.pm may be out of date with config.h or genconfig.pl" + olddef = F$Environment("Default") + Set Default $(PERL_SRC) + $(MMS)],$mmsquals,); + if ($self->{PERL_ARCHLIB} =~ m|\[-| && $self->{PERL_SRC} =~ m|(\[-+)|) { + my($prefix,$target) = ($1,$self->fixpath('$(PERL_ARCHLIB)Config.pm',0)); + $target =~ s/\Q$prefix/[/; + push(@m," $target"); + } + else { push(@m,' $(MMS$TARGET)'); } + push(@m,q[ + Set Default 'olddef' +]); + } + + push(@m, join(" ", map($self->fixpath($_,0),values %{$self->{XS}}))." : \$(XSUBPPDEPS)\n") + if %{$self->{XS}}; + + join('',@m); +} + + +=item makeaperl (override) + +Undertake to build a new set of Perl images using VMS commands. Since +VMS does dynamic loading, it's not necessary to statically link each +extension into the Perl image, so this isn't the normal build path. +Consequently, it hasn't really been tested, and may well be incomplete. + +=cut + +our %olbs; # needs to be localized + +sub makeaperl { + my($self, %attribs) = @_; + my($makefilename, $searchdirs, $static, $extra, $perlinc, $target, $tmpdir, $libperl) = + @attribs{qw(MAKE DIRS STAT EXTRA INCL TARGET TMP LIBPERL)}; + my(@m); + push @m, " +# --- MakeMaker makeaperl section --- +MAP_TARGET = $target +"; + return join '', @m if $self->{PARENT}; + + my($dir) = join ":", @{$self->{DIR}}; + + unless ($self->{MAKEAPERL}) { + push @m, q{ +$(MAKE_APERL_FILE) : $(FIRST_MAKEFILE) + $(NOECHO) $(ECHO) "Writing ""$(MMS$TARGET)"" for this $(MAP_TARGET)" + $(NOECHO) $(PERLRUNINST) \ + Makefile.PL DIR=}, $dir, q{ \ + FIRST_MAKEFILE=$(MAKE_APERL_FILE) LINKTYPE=static \ + MAKEAPERL=1 NORECURS=1 }; + + push @m, map(q[ \\\n\t\t"$_"], @ARGV),q{ + +$(MAP_TARGET) :: $(MAKE_APERL_FILE) + $(MAKE)$(USEMAKEFILE)$(MAKE_APERL_FILE) static $(MMS$TARGET) +}; + push @m, "\n"; + + return join '', @m; + } + + + my($linkcmd,@optlibs,@staticpkgs,$extralist,$targdir,$libperldir,%libseen); + local($_); + + # The front matter of the linkcommand... + $linkcmd = join ' ', $Config{'ld'}, + grep($_, @Config{qw(large split ldflags ccdlflags)}); + $linkcmd =~ s/\s+/ /g; + + # Which *.olb files could we make use of... + local(%olbs); # XXX can this be lexical? + $olbs{$self->{INST_ARCHAUTODIR}} = "$self->{BASEEXT}\$(LIB_EXT)"; + require File::Find; + File::Find::find(sub { + return unless m/\Q$self->{LIB_EXT}\E$/; + return if m/^libperl/; + + if( exists $self->{INCLUDE_EXT} ){ + my $found = 0; + + (my $xx = $File::Find::name) =~ s,.*?/auto/,,; + $xx =~ s,/?$_,,; + $xx =~ s,/,::,g; + + # Throw away anything not explicitly marked for inclusion. + # DynaLoader is implied. + foreach my $incl ((@{$self->{INCLUDE_EXT}},'DynaLoader')){ + if( $xx eq $incl ){ + $found++; + last; + } + } + return unless $found; + } + elsif( exists $self->{EXCLUDE_EXT} ){ + (my $xx = $File::Find::name) =~ s,.*?/auto/,,; + $xx =~ s,/?$_,,; + $xx =~ s,/,::,g; + + # Throw away anything explicitly marked for exclusion + foreach my $excl (@{$self->{EXCLUDE_EXT}}){ + return if( $xx eq $excl ); + } + } + + $olbs{$ENV{DEFAULT}} = $_; + }, grep( -d $_, @{$searchdirs || []})); + + # We trust that what has been handed in as argument will be buildable + $static = [] unless $static; + @olbs{@{$static}} = (1) x @{$static}; + + $extra = [] unless $extra && ref $extra eq 'ARRAY'; + # Sort the object libraries in inverse order of + # filespec length to try to insure that dependent extensions + # will appear before their parents, so the linker will + # search the parent library to resolve references. + # (e.g. Intuit::DWIM will precede Intuit, so unresolved + # references from [.intuit.dwim]dwim.obj can be found + # in [.intuit]intuit.olb). + for (sort { length($a) <=> length($b) } keys %olbs) { + next unless $olbs{$_} =~ /\Q$self->{LIB_EXT}\E$/; + my($dir) = $self->fixpath($_,1); + my($extralibs) = $dir . "extralibs.ld"; + my($extopt) = $dir . $olbs{$_}; + $extopt =~ s/$self->{LIB_EXT}$/.opt/; + push @optlibs, "$dir$olbs{$_}"; + # Get external libraries this extension will need + if (-f $extralibs ) { + my %seenthis; + open my $list, "<", $extralibs or warn $!,next; + while (<$list>) { + chomp; + # Include a library in the link only once, unless it's mentioned + # multiple times within a single extension's options file, in which + # case we assume the builder needed to search it again later in the + # link. + my $skip = exists($libseen{$_}) && !exists($seenthis{$_}); + $libseen{$_}++; $seenthis{$_}++; + next if $skip; + push @$extra,$_; + } + } + # Get full name of extension for ExtUtils::Miniperl + if (-f $extopt) { + open my $opt, '<', $extopt or die $!; + while (<$opt>) { + next unless /(?:UNIVERSAL|VECTOR)=boot_([\w_]+)/; + my $pkg = $1; + $pkg =~ s#__*#::#g; + push @staticpkgs,$pkg; + } + } + } + # Place all of the external libraries after all of the Perl extension + # libraries in the final link, in order to maximize the opportunity + # for XS code from multiple extensions to resolve symbols against the + # same external library while only including that library once. + push @optlibs, @$extra; + + $target = "Perl$Config{'exe_ext'}" unless $target; + my $shrtarget; + ($shrtarget,$targdir) = fileparse($target); + $shrtarget =~ s/^([^.]*)/$1Shr/; + $shrtarget = $targdir . $shrtarget; + $target = "Perlshr.$Config{'dlext'}" unless $target; + $tmpdir = "[]" unless $tmpdir; + $tmpdir = $self->fixpath($tmpdir,1); + if (@optlibs) { $extralist = join(' ',@optlibs); } + else { $extralist = ''; } + # Let ExtUtils::Liblist find the necessary libs for us (but skip PerlShr) + # that's what we're building here). + push @optlibs, grep { !/PerlShr/i } split ' ', +($self->ext())[2]; + if ($libperl) { + unless (-f $libperl || -f ($libperl = $self->catfile($Config{'installarchlib'},'CORE',$libperl))) { + print STDOUT "Warning: $libperl not found\n"; + undef $libperl; + } + } + unless ($libperl) { + if (defined $self->{PERL_SRC}) { + $libperl = $self->catfile($self->{PERL_SRC},"libperl$self->{LIB_EXT}"); + } elsif (-f ($libperl = $self->catfile($Config{'installarchlib'},'CORE',"libperl$self->{LIB_EXT}")) ) { + } else { + print STDOUT "Warning: $libperl not found + If you're going to build a static perl binary, make sure perl is installed + otherwise ignore this warning\n"; + } + } + $libperldir = $self->fixpath((fileparse($libperl))[1],1); + + push @m, ' +# Fill in the target you want to produce if it\'s not perl +MAP_TARGET = ',$self->fixpath($target,0),' +MAP_SHRTARGET = ',$self->fixpath($shrtarget,0)," +MAP_LINKCMD = $linkcmd +MAP_PERLINC = ", $perlinc ? map('"$_" ',@{$perlinc}) : ''," +MAP_EXTRA = $extralist +MAP_LIBPERL = ",$self->fixpath($libperl,0),' +'; + + + push @m,"\n${tmpdir}Makeaperl.Opt : \$(MAP_EXTRA)\n"; + foreach (@optlibs) { + push @m,' $(NOECHO) $(PERL) -e "print q{',$_,'}" >>$(MMS$TARGET)',"\n"; + } + push @m,"\n${tmpdir}PerlShr.Opt :\n\t"; + push @m,'$(NOECHO) $(PERL) -e "print q{$(MAP_SHRTARGET)}" >$(MMS$TARGET)',"\n"; + + push @m,' +$(MAP_SHRTARGET) : $(MAP_LIBPERL) Makeaperl.Opt ',"${libperldir}Perlshr_Attr.Opt",' + $(MAP_LINKCMD)/Shareable=$(MMS$TARGET) $(MAP_LIBPERL), Makeaperl.Opt/Option ',"${libperldir}Perlshr_Attr.Opt/Option",' +$(MAP_TARGET) : $(MAP_SHRTARGET) ',"${tmpdir}perlmain\$(OBJ_EXT) ${tmpdir}PerlShr.Opt",' + $(MAP_LINKCMD) ',"${tmpdir}perlmain\$(OBJ_EXT)",', PerlShr.Opt/Option + $(NOECHO) $(ECHO) "To install the new ""$(MAP_TARGET)"" binary, say" + $(NOECHO) $(ECHO) " $(MAKE)$(USEMAKEFILE)$(FIRST_MAKEFILE) inst_perl $(USEMACROS)MAP_TARGET=$(MAP_TARGET)$(ENDMACRO)" + $(NOECHO) $(ECHO) "To remove the intermediate files, say + $(NOECHO) $(ECHO) " $(MAKE)$(USEMAKEFILE)$(FIRST_MAKEFILE) map_clean" +'; + push @m,"\n${tmpdir}perlmain.c : \$(FIRST_MAKEFILE)\n\t\$(NOECHO) \$(PERL) -e 1 >${tmpdir}Writemain.tmp\n"; + push @m, "# More from the 255-char line length limit\n"; + foreach (@staticpkgs) { + push @m,' $(NOECHO) $(PERL) -e "print q{',$_,qq[}" >>${tmpdir}Writemain.tmp\n]; + } + + push @m, sprintf <<'MAKE_FRAG', $tmpdir, $tmpdir; + $(NOECHO) $(PERL) $(MAP_PERLINC) -ane "use ExtUtils::Miniperl; writemain(@F)" %sWritemain.tmp >$(MMS$TARGET) + $(NOECHO) $(RM_F) %sWritemain.tmp +MAKE_FRAG + + push @m, q[ +# Still more from the 255-char line length limit +doc_inst_perl : + $(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB) + $(NOECHO) $(ECHO) "Perl binary $(MAP_TARGET)|" >.MM_tmp + $(NOECHO) $(ECHO) "MAP_STATIC|$(MAP_STATIC)|" >>.MM_tmp + $(NOECHO) $(PERL) -pl040 -e " " ].$self->catfile('$(INST_ARCHAUTODIR)','extralibs.all'),q[ >>.MM_tmp + $(NOECHO) $(ECHO) -e "MAP_LIBPERL|$(MAP_LIBPERL)|" >>.MM_tmp + $(NOECHO) $(DOC_INSTALL) <.MM_tmp >>].$self->catfile('$(DESTINSTALLARCHLIB)','perllocal.pod').q[ + $(NOECHO) $(RM_F) .MM_tmp +]; + + push @m, " +inst_perl : pure_inst_perl doc_inst_perl + \$(NOECHO) \$(NOOP) + +pure_inst_perl : \$(MAP_TARGET) + $self->{CP} \$(MAP_SHRTARGET) ",$self->fixpath($Config{'installbin'},1)," + $self->{CP} \$(MAP_TARGET) ",$self->fixpath($Config{'installbin'},1)," + +clean :: map_clean + \$(NOECHO) \$(NOOP) + +map_clean : + \$(RM_F) ${tmpdir}perlmain\$(OBJ_EXT) ${tmpdir}perlmain.c \$(FIRST_MAKEFILE) + \$(RM_F) ${tmpdir}Makeaperl.Opt ${tmpdir}PerlShr.Opt \$(MAP_TARGET) +"; + + join '', @m; +} + + +# --- Output postprocessing section --- + +=item maketext_filter (override) + +Insure that colons marking targets are preceded by space, in order +to distinguish the target delimiter from a colon appearing as +part of a filespec. + +=cut + +sub maketext_filter { + my($self, $text) = @_; + + $text =~ s/^([^\s:=]+)(:+\s)/$1 $2/mg; + return $text; +} + +=item prefixify (override) + +prefixifying on VMS is simple. Each should simply be: + + perl_root:[some.dir] + +which can just be converted to: + + volume:[your.prefix.some.dir] + +otherwise you get the default layout. + +In effect, your search prefix is ignored and $Config{vms_prefix} is +used instead. + +=cut + +sub prefixify { + my($self, $var, $sprefix, $rprefix, $default) = @_; + + # Translate $(PERLPREFIX) to a real path. + $rprefix = $self->eliminate_macros($rprefix); + $rprefix = vmspath($rprefix) if $rprefix; + $sprefix = vmspath($sprefix) if $sprefix; + + $default = vmsify($default) + unless $default =~ /\[.*\]/; + + (my $var_no_install = $var) =~ s/^install//; + my $path = $self->{uc $var} || + $ExtUtils::MM_Unix::Config_Override{lc $var} || + $Config{lc $var} || $Config{lc $var_no_install}; + + if( !$path ) { + print STDERR " no Config found for $var.\n" if $Verbose >= 2; + $path = $self->_prefixify_default($rprefix, $default); + } + elsif( !$self->{ARGS}{PREFIX} || !$self->file_name_is_absolute($path) ) { + # do nothing if there's no prefix or if its relative + } + elsif( $sprefix eq $rprefix ) { + print STDERR " no new prefix.\n" if $Verbose >= 2; + } + else { + + print STDERR " prefixify $var => $path\n" if $Verbose >= 2; + print STDERR " from $sprefix to $rprefix\n" if $Verbose >= 2; + + my($path_vol, $path_dirs) = $self->splitpath( $path ); + if( $path_vol eq $Config{vms_prefix}.':' ) { + print STDERR " $Config{vms_prefix}: seen\n" if $Verbose >= 2; + + $path_dirs =~ s{^\[}{\[.} unless $path_dirs =~ m{^\[\.}; + $path = $self->_catprefix($rprefix, $path_dirs); + } + else { + $path = $self->_prefixify_default($rprefix, $default); + } + } + + print " now $path\n" if $Verbose >= 2; + return $self->{uc $var} = $path; +} + + +sub _prefixify_default { + my($self, $rprefix, $default) = @_; + + print STDERR " cannot prefix, using default.\n" if $Verbose >= 2; + + if( !$default ) { + print STDERR "No default!\n" if $Verbose >= 1; + return; + } + if( !$rprefix ) { + print STDERR "No replacement prefix!\n" if $Verbose >= 1; + return ''; + } + + return $self->_catprefix($rprefix, $default); +} + +sub _catprefix { + my($self, $rprefix, $default) = @_; + + my($rvol, $rdirs) = $self->splitpath($rprefix); + if( $rvol ) { + return $self->catpath($rvol, + $self->catdir($rdirs, $default), + '' + ) + } + else { + return $self->catdir($rdirs, $default); + } +} + + +=item cd + +=cut + +sub cd { + my($self, $dir, @cmds) = @_; + + $dir = vmspath($dir); + + my $cmd = join "\n\t", map "$_", @cmds; + + # No leading tab makes it look right when embedded + my $make_frag = sprintf <<'MAKE_FRAG', $dir, $cmd; +startdir = F$Environment("Default") + Set Default %s + %s + Set Default 'startdir' +MAKE_FRAG + + # No trailing newline makes this easier to embed + chomp $make_frag; + + return $make_frag; +} + + +=item oneliner + +=cut + +sub oneliner { + my($self, $cmd, $switches) = @_; + $switches = [] unless defined $switches; + + # Strip leading and trailing newlines + $cmd =~ s{^\n+}{}; + $cmd =~ s{\n+$}{}; + + $cmd = $self->quote_literal($cmd); + $cmd = $self->escape_newlines($cmd); + + # Switches must be quoted else they will be lowercased. + $switches = join ' ', map { qq{"$_"} } @$switches; + + return qq{\$(ABSPERLRUN) $switches -e $cmd "--"}; +} + + +=item B<echo> + +perl trips up on "<foo>" thinking it's an input redirect. So we use the +native Write command instead. Besides, its faster. + +=cut + +sub echo { + my($self, $text, $file, $appending) = @_; + $appending ||= 0; + + my $opencmd = $appending ? 'Open/Append' : 'Open/Write'; + + my @cmds = ("\$(NOECHO) $opencmd MMECHOFILE $file "); + push @cmds, map { '$(NOECHO) Write MMECHOFILE '.$self->quote_literal($_) } + split /\n/, $text; + push @cmds, '$(NOECHO) Close MMECHOFILE'; + return @cmds; +} + + +=item quote_literal + +=cut + +sub quote_literal { + my($self, $text) = @_; + + # I believe this is all we should need. + $text =~ s{"}{""}g; + + return qq{"$text"}; +} + +=item escape_newlines + +=cut + +sub escape_newlines { + my($self, $text) = @_; + + $text =~ s{\n}{-\n}g; + + return $text; +} + +=item max_exec_len + +256 characters. + +=cut + +sub max_exec_len { + my $self = shift; + + return $self->{_MAX_EXEC_LEN} ||= 256; +} + +=item init_linker + +=cut + +sub init_linker { + my $self = shift; + $self->{EXPORT_LIST} ||= '$(BASEEXT).opt'; + + my $shr = $Config{dbgprefix} . 'PERLSHR'; + if ($self->{PERL_SRC}) { + $self->{PERL_ARCHIVE} ||= + $self->catfile($self->{PERL_SRC}, "$shr.$Config{'dlext'}"); + } + else { + $self->{PERL_ARCHIVE} ||= + $ENV{$shr} ? $ENV{$shr} : "Sys\$Share:$shr.$Config{'dlext'}"; + } + + $self->{PERL_ARCHIVE_AFTER} ||= ''; +} + + +=item catdir (override) + +=item catfile (override) + +Eliminate the macros in the output to the MMS/MMK file. + +(File::Spec::VMS used to do this for us, but it's being removed) + +=cut + +sub catdir { + my $self = shift; + + # Process the macros on VMS MMS/MMK + my @args = map { m{\$\(} ? $self->eliminate_macros($_) : $_ } @_; + + my $dir = $self->SUPER::catdir(@args); + + # Fix up the directory and force it to VMS format. + $dir = $self->fixpath($dir, 1); + + return $dir; +} + +sub catfile { + my $self = shift; + + # Process the macros on VMS MMS/MMK + my @args = map { m{\$\(} ? $self->eliminate_macros($_) : $_ } @_; + + my $file = $self->SUPER::catfile(@args); + + $file = vmsify($file); + + return $file +} + + +=item eliminate_macros + +Expands MM[KS]/Make macros in a text string, using the contents of +identically named elements of C<%$self>, and returns the result +as a file specification in Unix syntax. + +NOTE: This is the canonical version of the method. The version in +File::Spec::VMS is deprecated. + +=cut + +sub eliminate_macros { + my($self,$path) = @_; + return '' unless $path; + $self = {} unless ref $self; + + if ($path =~ /\s/) { + return join ' ', map { $self->eliminate_macros($_) } split /\s+/, $path; + } + + my($npath) = unixify($path); + # sometimes unixify will return a string with an off-by-one trailing null + $npath =~ s{\0$}{}; + + my($complex) = 0; + my($head,$macro,$tail); + + # perform m##g in scalar context so it acts as an iterator + while ($npath =~ m#(.*?)\$\((\S+?)\)(.*)#gs) { + if (defined $self->{$2}) { + ($head,$macro,$tail) = ($1,$2,$3); + if (ref $self->{$macro}) { + if (ref $self->{$macro} eq 'ARRAY') { + $macro = join ' ', @{$self->{$macro}}; + } + else { + print "Note: can't expand macro \$($macro) containing ",ref($self->{$macro}), + "\n\t(using MMK-specific deferred substitutuon; MMS will break)\n"; + $macro = "\cB$macro\cB"; + $complex = 1; + } + } + else { ($macro = unixify($self->{$macro})) =~ s#/\Z(?!\n)##; } + $npath = "$head$macro$tail"; + } + } + if ($complex) { $npath =~ s#\cB(.*?)\cB#\${$1}#gs; } + $npath; +} + +=item fixpath + + my $path = $mm->fixpath($path); + my $path = $mm->fixpath($path, $is_dir); + +Catchall routine to clean up problem MM[SK]/Make macros. Expands macros +in any directory specification, in order to avoid juxtaposing two +VMS-syntax directories when MM[SK] is run. Also expands expressions which +are all macro, so that we can tell how long the expansion is, and avoid +overrunning DCL's command buffer when MM[KS] is running. + +fixpath() checks to see whether the result matches the name of a +directory in the current default directory and returns a directory or +file specification accordingly. C<$is_dir> can be set to true to +force fixpath() to consider the path to be a directory or false to force +it to be a file. + +NOTE: This is the canonical version of the method. The version in +File::Spec::VMS is deprecated. + +=cut + +sub fixpath { + my($self,$path,$force_path) = @_; + return '' unless $path; + $self = bless {}, $self unless ref $self; + my($fixedpath,$prefix,$name); + + if ($path =~ /[ \t]/) { + return join ' ', + map { $self->fixpath($_,$force_path) } + split /[ \t]+/, $path; + } + + if ($path =~ m#^\$\([^\)]+\)\Z(?!\n)#s || $path =~ m#[/:>\]]#) { + if ($force_path or $path =~ /(?:DIR\)|\])\Z(?!\n)/) { + $fixedpath = vmspath($self->eliminate_macros($path)); + } + else { + $fixedpath = vmsify($self->eliminate_macros($path)); + } + } + elsif ((($prefix,$name) = ($path =~ m#^\$\(([^\)]+)\)(.+)#s)) && $self->{$prefix}) { + my($vmspre) = $self->eliminate_macros("\$($prefix)"); + # is it a dir or just a name? + $vmspre = ($vmspre =~ m|/| or $prefix =~ /DIR\Z(?!\n)/) ? vmspath($vmspre) : ''; + $fixedpath = ($vmspre ? $vmspre : $self->{$prefix}) . $name; + $fixedpath = vmspath($fixedpath) if $force_path; + } + else { + $fixedpath = $path; + $fixedpath = vmspath($fixedpath) if $force_path; + } + # No hints, so we try to guess + if (!defined($force_path) and $fixedpath !~ /[:>(.\]]/) { + $fixedpath = vmspath($fixedpath) if -d $fixedpath; + } + + # Trim off root dirname if it's had other dirs inserted in front of it. + $fixedpath =~ s/\.000000([\]>])/$1/; + # Special case for VMS absolute directory specs: these will have had device + # prepended during trip through Unix syntax in eliminate_macros(), since + # Unix syntax has no way to express "absolute from the top of this device's + # directory tree". + if ($path =~ /^[\[>][^.\-]/) { $fixedpath =~ s/^[^\[<]+//; } + + return $fixedpath; +} + + +=item os_flavor + +VMS is VMS. + +=cut + +sub os_flavor { + return('VMS'); +} + +=back + + +=head1 AUTHOR + +Original author Charles Bailey F<bailey@newman.upenn.edu> + +Maintained by Michael G Schwern F<schwern@pobox.com> + +See L<ExtUtils::MakeMaker> for patching and contact information. + + +=cut + +1; + diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MM_VOS.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MM_VOS.pm new file mode 100644 index 00000000000..1814a1dae4c --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MM_VOS.pm @@ -0,0 +1,50 @@ +package ExtUtils::MM_VOS; + +use strict; +our $VERSION = '6.56'; + +require ExtUtils::MM_Unix; +our @ISA = qw(ExtUtils::MM_Unix); + + +=head1 NAME + +ExtUtils::MM_VOS - VOS specific subclass of ExtUtils::MM_Unix + +=head1 SYNOPSIS + + Don't use this module directly. + Use ExtUtils::MM and let it choose. + +=head1 DESCRIPTION + +This is a subclass of ExtUtils::MM_Unix which contains functionality for +VOS. + +Unless otherwise stated it works just like ExtUtils::MM_Unix + +=head2 Overridden methods + +=head3 extra_clean_files + +Cleanup VOS core files + +=cut + +sub extra_clean_files { + return qw(*.kp); +} + + +=head1 AUTHOR + +Michael G Schwern <schwern@pobox.com> with code from ExtUtils::MM_Unix + +=head1 SEE ALSO + +L<ExtUtils::MakeMaker> + +=cut + + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MM_Win32.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MM_Win32.pm new file mode 100644 index 00000000000..19e462de593 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MM_Win32.pm @@ -0,0 +1,585 @@ +package ExtUtils::MM_Win32; + +use strict; + + +=head1 NAME + +ExtUtils::MM_Win32 - methods to override UN*X behaviour in ExtUtils::MakeMaker + +=head1 SYNOPSIS + + use ExtUtils::MM_Win32; # Done internally by ExtUtils::MakeMaker if needed + +=head1 DESCRIPTION + +See ExtUtils::MM_Unix for a documentation of the methods provided +there. This package overrides the implementation of these methods, not +the semantics. + +=cut + +use ExtUtils::MakeMaker::Config; +use File::Basename; +use File::Spec; +use ExtUtils::MakeMaker qw( neatvalue ); + +require ExtUtils::MM_Any; +require ExtUtils::MM_Unix; +our @ISA = qw( ExtUtils::MM_Any ExtUtils::MM_Unix ); +our $VERSION = '6.56'; + +$ENV{EMXSHELL} = 'sh'; # to run `commands` + +my $BORLAND = $Config{'cc'} =~ /^bcc/i ? 1 : 0; +my $GCC = $Config{'cc'} =~ /\bgcc$/i ? 1 : 0; +my $DLLTOOL = $Config{'dlltool'} || 'dlltool'; + + +=head2 Overridden methods + +=over 4 + +=item B<dlsyms> + +=cut + +sub dlsyms { + my($self,%attribs) = @_; + + my($funcs) = $attribs{DL_FUNCS} || $self->{DL_FUNCS} || {}; + my($vars) = $attribs{DL_VARS} || $self->{DL_VARS} || []; + my($funclist) = $attribs{FUNCLIST} || $self->{FUNCLIST} || []; + my($imports) = $attribs{IMPORTS} || $self->{IMPORTS} || {}; + my(@m); + + if (not $self->{SKIPHASH}{'dynamic'}) { + push(@m," +$self->{BASEEXT}.def: Makefile.PL +", + q! $(PERLRUN) -MExtUtils::Mksymlists \\ + -e "Mksymlists('NAME'=>\"!, $self->{NAME}, + q!\", 'DLBASE' => '!,$self->{DLBASE}, + # The above two lines quoted differently to work around + # a bug in the 4DOS/4NT command line interpreter. The visible + # result of the bug was files named q('extension_name',) *with the + # single quotes and the comma* in the extension build directories. + q!', 'DL_FUNCS' => !,neatvalue($funcs), + q!, 'FUNCLIST' => !,neatvalue($funclist), + q!, 'IMPORTS' => !,neatvalue($imports), + q!, 'DL_VARS' => !, neatvalue($vars), q!);" +!); + } + join('',@m); +} + +=item replace_manpage_separator + +Changes the path separator with . + +=cut + +sub replace_manpage_separator { + my($self,$man) = @_; + $man =~ s,/+,.,g; + $man; +} + + +=item B<maybe_command> + +Since Windows has nothing as simple as an executable bit, we check the +file extension. + +The PATHEXT env variable will be used to get a list of extensions that +might indicate a command, otherwise .com, .exe, .bat and .cmd will be +used by default. + +=cut + +sub maybe_command { + my($self,$file) = @_; + my @e = exists($ENV{'PATHEXT'}) + ? split(/;/, $ENV{PATHEXT}) + : qw(.com .exe .bat .cmd); + my $e = ''; + for (@e) { $e .= "\Q$_\E|" } + chop $e; + # see if file ends in one of the known extensions + if ($file =~ /($e)$/i) { + return $file if -e $file; + } + else { + for (@e) { + return "$file$_" if -e "$file$_"; + } + } + return; +} + + +=item B<init_DIRFILESEP> + +Using \ for Windows. + +=cut + +sub init_DIRFILESEP { + my($self) = shift; + + # The ^ makes sure its not interpreted as an escape in nmake + $self->{DIRFILESEP} = $self->is_make_type('nmake') ? '^\\' : + $self->is_make_type('dmake') ? '\\\\' + : '\\'; +} + +=item B<init_others> + +Override some of the Unix specific commands with portable +ExtUtils::Command ones. + +Also provide defaults for LD and AR in case the %Config values aren't +set. + +LDLOADLIBS's default is changed to $Config{libs}. + +Adjustments are made for Borland's quirks needing -L to come first. + +=cut + +sub init_others { + my ($self) = @_; + + $self->{NOOP} ||= 'rem'; + $self->{DEV_NULL} ||= '> NUL'; + + $self->{FIXIN} ||= $self->{PERL_CORE} ? + "\$(PERLRUN) $self->{PERL_SRC}/win32/bin/pl2bat.pl" : + 'pl2bat.bat'; + + $self->{LD} ||= 'link'; + $self->{AR} ||= 'lib'; + + $self->SUPER::init_others; + + # Setting SHELL from $Config{sh} can break dmake. Its ok without it. + delete $self->{SHELL}; + + $self->{LDLOADLIBS} ||= $Config{libs}; + # -Lfoo must come first for Borland, so we put it in LDDLFLAGS + if ($BORLAND) { + my $libs = $self->{LDLOADLIBS}; + my $libpath = ''; + while ($libs =~ s/(?:^|\s)(("?)-L.+?\2)(?:\s|$)/ /) { + $libpath .= ' ' if length $libpath; + $libpath .= $1; + } + $self->{LDLOADLIBS} = $libs; + $self->{LDDLFLAGS} ||= $Config{lddlflags}; + $self->{LDDLFLAGS} .= " $libpath"; + } + + return 1; +} + + +=item init_platform + +Add MM_Win32_VERSION. + +=item platform_constants + +=cut + +sub init_platform { + my($self) = shift; + + $self->{MM_Win32_VERSION} = $VERSION; +} + +sub platform_constants { + my($self) = shift; + my $make_frag = ''; + + foreach my $macro (qw(MM_Win32_VERSION)) + { + next unless defined $self->{$macro}; + $make_frag .= "$macro = $self->{$macro}\n"; + } + + return $make_frag; +} + + +=item special_targets + +Add .USESHELL target for dmake. + +=cut + +sub special_targets { + my($self) = @_; + + my $make_frag = $self->SUPER::special_targets; + + $make_frag .= <<'MAKE_FRAG' if $self->is_make_type('dmake'); +.USESHELL : +MAKE_FRAG + + return $make_frag; +} + + +=item static_lib + +Changes how to run the linker. + +The rest is duplicate code from MM_Unix. Should move the linker code +to its own method. + +=cut + +sub static_lib { + my($self) = @_; + return '' unless $self->has_link_code; + + my(@m); + push(@m, <<'END'); +$(INST_STATIC): $(OBJECT) $(MYEXTLIB) $(INST_ARCHAUTODIR)$(DFSEP).exists + $(RM_RF) $@ +END + + # If this extension has its own library (eg SDBM_File) + # then copy that to $(INST_STATIC) and add $(OBJECT) into it. + push @m, <<'MAKE_FRAG' if $self->{MYEXTLIB}; + $(CP) $(MYEXTLIB) $@ +MAKE_FRAG + + push @m, +q{ $(AR) }.($BORLAND ? '$@ $(OBJECT:^"+")' + : ($GCC ? '-ru $@ $(OBJECT)' + : '-out:$@ $(OBJECT)')).q{ + $(CHMOD) $(PERM_RWX) $@ + $(NOECHO) $(ECHO) "$(EXTRALIBS)" > $(INST_ARCHAUTODIR)\extralibs.ld +}; + + # Old mechanism - still available: + push @m, <<'MAKE_FRAG' if $self->{PERL_SRC} && $self->{EXTRALIBS}; + $(NOECHO) $(ECHO) "$(EXTRALIBS)" >> $(PERL_SRC)\ext.libs +MAKE_FRAG + + join('', @m); +} + + +=item dynamic_lib + +Complicated stuff for Win32 that I don't understand. :( + +=cut + +sub dynamic_lib { + my($self, %attribs) = @_; + return '' unless $self->needs_linking(); #might be because of a subdir + + return '' unless $self->has_link_code; + + my($otherldflags) = $attribs{OTHERLDFLAGS} || ($BORLAND ? 'c0d32.obj': ''); + my($inst_dynamic_dep) = $attribs{INST_DYNAMIC_DEP} || ""; + my($ldfrom) = '$(LDFROM)'; + my(@m); + +# one thing for GCC/Mingw32: +# we try to overcome non-relocateable-DLL problems by generating +# a (hopefully unique) image-base from the dll's name +# -- BKS, 10-19-1999 + if ($GCC) { + my $dllname = $self->{BASEEXT} . "." . $self->{DLEXT}; + $dllname =~ /(....)(.{0,4})/; + my $baseaddr = unpack("n", $1 ^ $2); + $otherldflags .= sprintf("-Wl,--image-base,0x%x0000 ", $baseaddr); + } + + push(@m,' +# This section creates the dynamically loadable $(INST_DYNAMIC) +# from $(OBJECT) and possibly $(MYEXTLIB). +OTHERLDFLAGS = '.$otherldflags.' +INST_DYNAMIC_DEP = '.$inst_dynamic_dep.' + +$(INST_DYNAMIC): $(OBJECT) $(MYEXTLIB) $(BOOTSTRAP) $(INST_ARCHAUTODIR)$(DFSEP).exists $(EXPORT_LIST) $(PERL_ARCHIVE) $(INST_DYNAMIC_DEP) +'); + if ($GCC) { + push(@m, + q{ }.$DLLTOOL.q{ --def $(EXPORT_LIST) --output-exp dll.exp + $(LD) -o $@ -Wl,--base-file -Wl,dll.base $(LDDLFLAGS) }.$ldfrom.q{ $(OTHERLDFLAGS) $(MYEXTLIB) $(PERL_ARCHIVE) $(LDLOADLIBS) dll.exp + }.$DLLTOOL.q{ --def $(EXPORT_LIST) --base-file dll.base --output-exp dll.exp + $(LD) -o $@ $(LDDLFLAGS) }.$ldfrom.q{ $(OTHERLDFLAGS) $(MYEXTLIB) $(PERL_ARCHIVE) $(LDLOADLIBS) dll.exp }); + } elsif ($BORLAND) { + push(@m, + q{ $(LD) $(LDDLFLAGS) $(OTHERLDFLAGS) }.$ldfrom.q{,$@,,} + .($self->is_make_type('dmake') + ? q{$(PERL_ARCHIVE:s,/,\,) $(LDLOADLIBS:s,/,\,) } + .q{$(MYEXTLIB:s,/,\,),$(EXPORT_LIST:s,/,\,)} + : q{$(subst /,\,$(PERL_ARCHIVE)) $(subst /,\,$(LDLOADLIBS)) } + .q{$(subst /,\,$(MYEXTLIB)),$(subst /,\,$(EXPORT_LIST))}) + .q{,$(RESFILES)}); + } else { # VC + push(@m, + q{ $(LD) -out:$@ $(LDDLFLAGS) }.$ldfrom.q{ $(OTHERLDFLAGS) } + .q{$(MYEXTLIB) $(PERL_ARCHIVE) $(LDLOADLIBS) -def:$(EXPORT_LIST)}); + + # Embed the manifest file if it exists + push(@m, q{ + if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;2 + if exist $@.manifest del $@.manifest}); + } + push @m, ' + $(CHMOD) $(PERM_RWX) $@ +'; + + join('',@m); +} + +=item extra_clean_files + +Clean out some extra dll.{base,exp} files which might be generated by +gcc. Otherwise, take out all *.pdb files. + +=cut + +sub extra_clean_files { + my $self = shift; + + return $GCC ? (qw(dll.base dll.exp)) : ('*.pdb'); +} + +=item init_linker + +=cut + +sub init_linker { + my $self = shift; + + $self->{PERL_ARCHIVE} = "\$(PERL_INC)\\$Config{libperl}"; + $self->{PERL_ARCHIVE_AFTER} = ''; + $self->{EXPORT_LIST} = '$(BASEEXT).def'; +} + + +=item perl_script + +Checks for the perl program under several common perl extensions. + +=cut + +sub perl_script { + my($self,$file) = @_; + return $file if -r $file && -f _; + return "$file.pl" if -r "$file.pl" && -f _; + return "$file.plx" if -r "$file.plx" && -f _; + return "$file.bat" if -r "$file.bat" && -f _; + return; +} + + +=item xs_o + +This target is stubbed out. Not sure why. + +=cut + +sub xs_o { + return '' +} + + +=item pasthru + +All we send is -nologo to nmake to prevent it from printing its damned +banner. + +=cut + +sub pasthru { + my($self) = shift; + return "PASTHRU = " . ($self->is_make_type('nmake') ? "-nologo" : ""); +} + + +=item arch_check (override) + +Normalize all arguments for consistency of comparison. + +=cut + +sub arch_check { + my $self = shift; + + # Win32 is an XS module, minperl won't have it. + # arch_check() is not critical, so just fake it. + return 1 unless $self->can_load_xs; + return $self->SUPER::arch_check( map { $self->_normalize_path_name($_) } @_); +} + +sub _normalize_path_name { + my $self = shift; + my $file = shift; + + require Win32; + my $short = Win32::GetShortPathName($file); + return defined $short ? lc $short : lc $file; +} + + +=item oneliner + +These are based on what command.com does on Win98. They may be wrong +for other Windows shells, I don't know. + +=cut + +sub oneliner { + my($self, $cmd, $switches) = @_; + $switches = [] unless defined $switches; + + # Strip leading and trailing newlines + $cmd =~ s{^\n+}{}; + $cmd =~ s{\n+$}{}; + + $cmd = $self->quote_literal($cmd); + $cmd = $self->escape_newlines($cmd); + + $switches = join ' ', @$switches; + + return qq{\$(ABSPERLRUN) $switches -e $cmd --}; +} + + +sub quote_literal { + my($self, $text) = @_; + + # I don't know if this is correct, but it seems to work on + # Win98's command.com + $text =~ s{"}{\\"}g; + + # dmake eats '{' inside double quotes and leaves alone { outside double + # quotes; however it transforms {{ into { either inside and outside double + # quotes. It also translates }} into }. The escaping below is not + # 100% correct. + if( $self->is_make_type('dmake') ) { + $text =~ s/{/{{/g; + $text =~ s/}}/}}}/g; + } + + return qq{"$text"}; +} + + +sub escape_newlines { + my($self, $text) = @_; + + # Escape newlines + $text =~ s{\n}{\\\n}g; + + return $text; +} + + +=item cd + +dmake can handle Unix style cd'ing but nmake (at least 1.5) cannot. It +wants: + + cd dir1\dir2 + command + another_command + cd ..\.. + +=cut + +sub cd { + my($self, $dir, @cmds) = @_; + + return $self->SUPER::cd($dir, @cmds) unless $self->is_make_type('nmake'); + + my $cmd = join "\n\t", map "$_", @cmds; + + my $updirs = $self->catdir(map { $self->updir } $self->splitdir($dir)); + + # No leading tab and no trailing newline makes for easier embedding. + my $make_frag = sprintf <<'MAKE_FRAG', $dir, $cmd, $updirs; +cd %s + %s + cd %s +MAKE_FRAG + + chomp $make_frag; + + return $make_frag; +} + + +=item max_exec_len + +nmake 1.50 limits command length to 2048 characters. + +=cut + +sub max_exec_len { + my $self = shift; + + return $self->{_MAX_EXEC_LEN} ||= 2 * 1024; +} + + +=item os_flavor + +Windows is Win32. + +=cut + +sub os_flavor { + return('Win32'); +} + + +=item cflags + +Defines the PERLDLL symbol if we are configured for static building since all +code destined for the perl5xx.dll must be compiled with the PERLDLL symbol +defined. + +=cut + +sub cflags { + my($self,$libperl)=@_; + return $self->{CFLAGS} if $self->{CFLAGS}; + return '' unless $self->needs_linking(); + + my $base = $self->SUPER::cflags($libperl); + foreach (split /\n/, $base) { + /^(\S*)\s*=\s*(\S*)$/ and $self->{$1} = $2; + }; + $self->{CCFLAGS} .= " -DPERLDLL" if ($self->{LINKTYPE} eq 'static'); + + return $self->{CFLAGS} = qq{ +CCFLAGS = $self->{CCFLAGS} +OPTIMIZE = $self->{OPTIMIZE} +PERLTYPE = $self->{PERLTYPE} +}; + +} + +sub is_make_type { + my($self, $type) = @_; + return !! ($self->make =~ /\b$type(?:\.exe)?$/); +} + +1; +__END__ + +=back + +=cut + + diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MM_Win95.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MM_Win95.pm new file mode 100644 index 00000000000..c47147695e8 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MM_Win95.pm @@ -0,0 +1,124 @@ +package ExtUtils::MM_Win95; + +use strict; + +our $VERSION = '6.56'; + +require ExtUtils::MM_Win32; +our @ISA = qw(ExtUtils::MM_Win32); + +use ExtUtils::MakeMaker::Config; + + +=head1 NAME + +ExtUtils::MM_Win95 - method to customize MakeMaker for Win9X + +=head1 SYNOPSIS + + You should not be using this module directly. + +=head1 DESCRIPTION + +This is a subclass of ExtUtils::MM_Win32 containing changes necessary +to get MakeMaker playing nice with command.com and other Win9Xisms. + +=head2 Overridden methods + +Most of these make up for limitations in the Win9x/nmake command shell. +Mostly its lack of &&. + +=over 4 + + +=item xs_c + +The && problem. + +=cut + +sub xs_c { + my($self) = shift; + return '' unless $self->needs_linking(); + ' +.xs.c: + $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.c + ' +} + + +=item xs_cpp + +The && problem + +=cut + +sub xs_cpp { + my($self) = shift; + return '' unless $self->needs_linking(); + ' +.xs.cpp: + $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.cpp + '; +} + +=item xs_o + +The && problem. + +=cut + +sub xs_o { + my($self) = shift; + return '' unless $self->needs_linking(); + ' +.xs$(OBJ_EXT): + $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.c + $(CCCMD) $(CCCDLFLAGS) -I$(PERL_INC) $(DEFINE) $*.c + '; +} + + +=item max_exec_len + +Win98 chokes on things like Encode if we set the max length to nmake's max +of 2K. So we go for a more conservative value of 1K. + +=cut + +sub max_exec_len { + my $self = shift; + + return $self->{_MAX_EXEC_LEN} ||= 1024; +} + + +=item os_flavor + +Win95 and Win98 and WinME are collectively Win9x and Win32 + +=cut + +sub os_flavor { + my $self = shift; + return ($self->SUPER::os_flavor, 'Win9x'); +} + + +=back + + +=head1 AUTHOR + +Code originally inside MM_Win32. Original author unknown. + +Currently maintained by Michael G Schwern C<schwern@pobox.com>. + +Send patches and ideas to C<makemaker@perl.org>. + +See http://www.makemaker.org. + +=cut + + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MY.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MY.pm new file mode 100644 index 00000000000..bed177d210a --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MY.pm @@ -0,0 +1,40 @@ +package ExtUtils::MY; + +use strict; +require ExtUtils::MM; + +our $VERSION = 6.56; +our @ISA = qw(ExtUtils::MM); + +{ + package MY; + our @ISA = qw(ExtUtils::MY); +} + +sub DESTROY {} + + +=head1 NAME + +ExtUtils::MY - ExtUtils::MakeMaker subclass for customization + +=head1 SYNOPSIS + + # in your Makefile.PL + sub MY::whatever { + ... + } + +=head1 DESCRIPTION + +B<FOR INTERNAL USE ONLY> + +ExtUtils::MY is a subclass of ExtUtils::MM. Its provided in your +Makefile.PL for you to add and override MakeMaker functionality. + +It also provides a convenient alias via the MY class. + +ExtUtils::MY might turn out to be a temporary solution, but MY won't +go away. + +=cut diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MakeMaker.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MakeMaker.pm new file mode 100644 index 00000000000..4422b686ce7 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MakeMaker.pm @@ -0,0 +1,2807 @@ +# $Id$ +package ExtUtils::MakeMaker; + +use strict; + +BEGIN {require 5.006;} + +require Exporter; +use ExtUtils::MakeMaker::Config; +use Carp (); +use File::Path; + +our $Verbose = 0; # exported +our @Parent; # needs to be localized +our @Get_from_Config; # referenced by MM_Unix +our @MM_Sections; +our @Overridable; +my @Prepend_parent; +my %Recognized_Att_Keys; + +our $VERSION = '6.56'; + +# Emulate something resembling CVS $Revision$ +(our $Revision = $VERSION) =~ s{_}{}; +$Revision = int $Revision * 10000; + +our $Filename = __FILE__; # referenced outside MakeMaker + +our @ISA = qw(Exporter); +our @EXPORT = qw(&WriteMakefile &writeMakefile $Verbose &prompt); +our @EXPORT_OK = qw($VERSION &neatvalue &mkbootstrap &mksymlists + &WriteEmptyMakefile); + +# These will go away once the last of the Win32 & VMS specific code is +# purged. +my $Is_VMS = $^O eq 'VMS'; +my $Is_Win32 = $^O eq 'MSWin32'; + +full_setup(); + +require ExtUtils::MM; # Things like CPAN assume loading ExtUtils::MakeMaker + # will give them MM. + +require ExtUtils::MY; # XXX pre-5.8 versions of ExtUtils::Embed expect + # loading ExtUtils::MakeMaker will give them MY. + # This will go when Embed is its own CPAN module. + + +sub WriteMakefile { + Carp::croak "WriteMakefile: Need even number of args" if @_ % 2; + + require ExtUtils::MY; + my %att = @_; + + _verify_att(\%att); + + my $mm = MM->new(\%att); + $mm->flush; + + return $mm; +} + + +# Basic signatures of the attributes WriteMakefile takes. Each is the +# reference type. Empty value indicate it takes a non-reference +# scalar. +my %Att_Sigs; +my %Special_Sigs = ( + C => 'ARRAY', + CONFIG => 'ARRAY', + CONFIGURE => 'CODE', + DIR => 'ARRAY', + DL_FUNCS => 'HASH', + DL_VARS => 'ARRAY', + EXCLUDE_EXT => 'ARRAY', + EXE_FILES => 'ARRAY', + FUNCLIST => 'ARRAY', + H => 'ARRAY', + IMPORTS => 'HASH', + INCLUDE_EXT => 'ARRAY', + LIBS => ['ARRAY',''], + MAN1PODS => 'HASH', + MAN3PODS => 'HASH', + META_ADD => 'HASH', + META_MERGE => 'HASH', + PL_FILES => 'HASH', + PM => 'HASH', + PMLIBDIRS => 'ARRAY', + PMLIBPARENTDIRS => 'ARRAY', + PREREQ_PM => 'HASH', + BUILD_REQUIRES => 'HASH', + CONFIGURE_REQUIRES => 'HASH', + SKIP => 'ARRAY', + TYPEMAPS => 'ARRAY', + XS => 'HASH', + VERSION => ['version',''], + _KEEP_AFTER_FLUSH => '', + + clean => 'HASH', + depend => 'HASH', + dist => 'HASH', + dynamic_lib=> 'HASH', + linkext => 'HASH', + macro => 'HASH', + postamble => 'HASH', + realclean => 'HASH', + test => 'HASH', + tool_autosplit => 'HASH', +); + +@Att_Sigs{keys %Recognized_Att_Keys} = ('') x keys %Recognized_Att_Keys; +@Att_Sigs{keys %Special_Sigs} = values %Special_Sigs; + + +sub _verify_att { + my($att) = @_; + + while( my($key, $val) = each %$att ) { + my $sig = $Att_Sigs{$key}; + unless( defined $sig ) { + warn "WARNING: $key is not a known parameter.\n"; + next; + } + + my @sigs = ref $sig ? @$sig : $sig; + my $given = ref $val; + unless( grep { _is_of_type($val, $_) } @sigs ) { + my $takes = join " or ", map { _format_att($_) } @sigs; + + my $has = _format_att($given); + warn "WARNING: $key takes a $takes not a $has.\n". + " Please inform the author.\n"; + } + } +} + + +# Check if a given thing is a reference or instance of $type +sub _is_of_type { + my($thing, $type) = @_; + + return 1 if ref $thing eq $type; + + local $SIG{__DIE__}; + return 1 if eval{ $thing->isa($type) }; + + return 0; +} + + +sub _format_att { + my $given = shift; + + return $given eq '' ? "string/number" + : uc $given eq $given ? "$given reference" + : "$given object" + ; +} + + +sub prompt ($;$) { ## no critic + my($mess, $def) = @_; + Carp::confess("prompt function called without an argument") + unless defined $mess; + + my $isa_tty = -t STDIN && (-t STDOUT || !(-f STDOUT || -c STDOUT)) ; + + my $dispdef = defined $def ? "[$def] " : " "; + $def = defined $def ? $def : ""; + + local $|=1; + local $\; + print "$mess $dispdef"; + + my $ans; + if ($ENV{PERL_MM_USE_DEFAULT} || (!$isa_tty && eof STDIN)) { + print "$def\n"; + } + else { + $ans = <STDIN>; + if( defined $ans ) { + chomp $ans; + } + else { # user hit ctrl-D + print "\n"; + } + } + + return (!defined $ans || $ans eq '') ? $def : $ans; +} + +sub eval_in_subdirs { + my($self) = @_; + use Cwd qw(cwd abs_path); + my $pwd = cwd() || die "Can't figure out your cwd!"; + + local @INC = map eval {abs_path($_) if -e} || $_, @INC; + push @INC, '.'; # '.' has to always be at the end of @INC + + foreach my $dir (@{$self->{DIR}}){ + my($abs) = $self->catdir($pwd,$dir); + eval { $self->eval_in_x($abs); }; + last if $@; + } + chdir $pwd; + die $@ if $@; +} + +sub eval_in_x { + my($self,$dir) = @_; + chdir $dir or Carp::carp("Couldn't change to directory $dir: $!"); + + { + package main; + do './Makefile.PL'; + }; + if ($@) { +# if ($@ =~ /prerequisites/) { +# die "MakeMaker WARNING: $@"; +# } else { +# warn "WARNING from evaluation of $dir/Makefile.PL: $@"; +# } + die "ERROR from evaluation of $dir/Makefile.PL: $@"; + } +} + + +# package name for the classes into which the first object will be blessed +my $PACKNAME = 'PACK000'; + +sub full_setup { + $Verbose ||= 0; + + my @attrib_help = qw/ + + AUTHOR ABSTRACT ABSTRACT_FROM BINARY_LOCATION + C CAPI CCFLAGS CONFIG CONFIGURE DEFINE DIR DISTNAME DISTVNAME + DL_FUNCS DL_VARS + EXCLUDE_EXT EXE_FILES FIRST_MAKEFILE + FULLPERL FULLPERLRUN FULLPERLRUNINST + FUNCLIST H IMPORTS + + INST_ARCHLIB INST_SCRIPT INST_BIN INST_LIB INST_MAN1DIR INST_MAN3DIR + INSTALLDIRS + DESTDIR PREFIX INSTALL_BASE + PERLPREFIX SITEPREFIX VENDORPREFIX + INSTALLPRIVLIB INSTALLSITELIB INSTALLVENDORLIB + INSTALLARCHLIB INSTALLSITEARCH INSTALLVENDORARCH + INSTALLBIN INSTALLSITEBIN INSTALLVENDORBIN + INSTALLMAN1DIR INSTALLMAN3DIR + INSTALLSITEMAN1DIR INSTALLSITEMAN3DIR + INSTALLVENDORMAN1DIR INSTALLVENDORMAN3DIR + INSTALLSCRIPT INSTALLSITESCRIPT INSTALLVENDORSCRIPT + PERL_LIB PERL_ARCHLIB + SITELIBEXP SITEARCHEXP + + INC INCLUDE_EXT LDFROM LIB LIBPERL_A LIBS LICENSE + LINKTYPE MAKE MAKEAPERL MAKEFILE MAKEFILE_OLD MAN1PODS MAN3PODS MAP_TARGET + META_ADD META_MERGE MIN_PERL_VERSION BUILD_REQUIRES CONFIGURE_REQUIRES + MYEXTLIB NAME NEEDS_LINKING NOECHO NO_META NORECURS NO_VC OBJECT OPTIMIZE + PERL_MALLOC_OK PERL PERLMAINCC PERLRUN PERLRUNINST PERL_CORE + PERL_SRC PERM_DIR PERM_RW PERM_RWX + PL_FILES PM PM_FILTER PMLIBDIRS PMLIBPARENTDIRS POLLUTE PPM_INSTALL_EXEC + PPM_INSTALL_SCRIPT PREREQ_FATAL PREREQ_PM PREREQ_PRINT PRINT_PREREQ + SIGN SKIP TYPEMAPS VERSION VERSION_FROM XS XSOPT XSPROTOARG + XS_VERSION clean depend dist dynamic_lib linkext macro realclean + tool_autosplit + + MACPERL_SRC MACPERL_LIB MACLIBS_68K MACLIBS_PPC MACLIBS_SC MACLIBS_MRC + MACLIBS_ALL_68K MACLIBS_ALL_PPC MACLIBS_SHARED + /; + + # IMPORTS is used under OS/2 and Win32 + + # @Overridable is close to @MM_Sections but not identical. The + # order is important. Many subroutines declare macros. These + # depend on each other. Let's try to collect the macros up front, + # then pasthru, then the rules. + + # MM_Sections are the sections we have to call explicitly + # in Overridable we have subroutines that are used indirectly + + + @MM_Sections = + qw( + + post_initialize const_config constants platform_constants + tool_autosplit tool_xsubpp tools_other + + makemakerdflt + + dist macro depend cflags const_loadlibs const_cccmd + post_constants + + pasthru + + special_targets + c_o xs_c xs_o + top_targets blibdirs linkext dlsyms dynamic dynamic_bs + dynamic_lib static static_lib manifypods processPL + installbin subdirs + clean_subdirs clean realclean_subdirs realclean + metafile signature + dist_basics dist_core distdir dist_test dist_ci distmeta distsignature + install force perldepend makefile staticmake test ppd + + ); # loses section ordering + + @Overridable = @MM_Sections; + push @Overridable, qw[ + + libscan makeaperl needs_linking + subdir_x test_via_harness test_via_script + + init_VERSION init_dist init_INST init_INSTALL init_DEST init_dirscan + init_PM init_MANPODS init_xs init_PERL init_DIRFILESEP init_linker + ]; + + push @MM_Sections, qw[ + + pm_to_blib selfdocument + + ]; + + # Postamble needs to be the last that was always the case + push @MM_Sections, "postamble"; + push @Overridable, "postamble"; + + # All sections are valid keys. + @Recognized_Att_Keys{@MM_Sections} = (1) x @MM_Sections; + + # we will use all these variables in the Makefile + @Get_from_Config = + qw( + ar cc cccdlflags ccdlflags dlext dlsrc exe_ext full_ar ld + lddlflags ldflags libc lib_ext obj_ext osname osvers ranlib + sitelibexp sitearchexp so + ); + + # 5.5.3 doesn't have any concept of vendor libs + push @Get_from_Config, qw( vendorarchexp vendorlibexp ) if $] >= 5.006; + + foreach my $item (@attrib_help){ + $Recognized_Att_Keys{$item} = 1; + } + foreach my $item (@Get_from_Config) { + $Recognized_Att_Keys{uc $item} = $Config{$item}; + print "Attribute '\U$item\E' => '$Config{$item}'\n" + if ($Verbose >= 2); + } + + # + # When we eval a Makefile.PL in a subdirectory, that one will ask + # us (the parent) for the values and will prepend "..", so that + # all files to be installed end up below OUR ./blib + # + @Prepend_parent = qw( + INST_BIN INST_LIB INST_ARCHLIB INST_SCRIPT + MAP_TARGET INST_MAN1DIR INST_MAN3DIR PERL_SRC + PERL FULLPERL + ); +} + +sub writeMakefile { + die <<END; + +The extension you are trying to build apparently is rather old and +most probably outdated. We detect that from the fact, that a +subroutine "writeMakefile" is called, and this subroutine is not +supported anymore since about October 1994. + +Please contact the author or look into CPAN (details about CPAN can be +found in the FAQ and at http:/www.perl.com) for a more recent version +of the extension. If you're really desperate, you can try to change +the subroutine name from writeMakefile to WriteMakefile and rerun +'perl Makefile.PL', but you're most probably left alone, when you do +so. + +The MakeMaker team + +END +} + +sub new { + my($class,$self) = @_; + my($key); + + # Store the original args passed to WriteMakefile() + foreach my $k (keys %$self) { + $self->{ARGS}{$k} = $self->{$k}; + } + + $self = {} unless defined $self; + + $self->{PREREQ_PM} ||= {}; + $self->{BUILD_REQUIRES} ||= {}; + + # Temporarily bless it into MM so it can be used as an + # object. It will be blessed into a temp package later. + bless $self, "MM"; + + if ("@ARGV" =~ /\bPREREQ_PRINT\b/) { + $self->_PREREQ_PRINT; + } + + # PRINT_PREREQ is RedHatism. + if ("@ARGV" =~ /\bPRINT_PREREQ\b/) { + $self->_PRINT_PREREQ; + } + + print STDOUT "MakeMaker (v$VERSION)\n" if $Verbose; + if (-f "MANIFEST" && ! -f "Makefile"){ + check_manifest(); + } + + check_hints($self); + + # Translate X.Y.Z to X.00Y00Z + if( defined $self->{MIN_PERL_VERSION} ) { + $self->{MIN_PERL_VERSION} =~ s{ ^ (\d+) \. (\d+) \. (\d+) $ } + {sprintf "%d.%03d%03d", $1, $2, $3}ex; + } + + my $perl_version_ok = eval { + local $SIG{__WARN__} = sub { + # simulate "use warnings FATAL => 'all'" for vintage perls + die @_; + }; + !$self->{MIN_PERL_VERSION} or $self->{MIN_PERL_VERSION} <= $] + }; + if (!$perl_version_ok) { + if (!defined $perl_version_ok) { + warn <<'END'; +Warning: MIN_PERL_VERSION is not in a recognized format. +Recommended is a quoted numerical value like '5.005' or '5.008001'. +END + } + elsif ($self->{PREREQ_FATAL}) { + die sprintf <<"END", $self->{MIN_PERL_VERSION}, $]; +MakeMaker FATAL: perl version too low for this distribution. +Required is %s. We run %s. +END + } + else { + warn sprintf + "Warning: Perl version %s or higher required. We run %s.\n", + $self->{MIN_PERL_VERSION}, $]; + } + } + + my %configure_att; # record &{$self->{CONFIGURE}} attributes + my(%initial_att) = %$self; # record initial attributes + + my(%unsatisfied) = (); + my $prereqs = $self->_all_prereqs; + foreach my $prereq (sort keys %$prereqs) { + my $required_version = $prereqs->{$prereq}; + + my $installed_file = MM->_installed_file_for_module($prereq); + my $pr_version = 0; + $pr_version = MM->parse_version($installed_file) if $installed_file; + $pr_version = 0 if $pr_version eq 'undef'; + + # convert X.Y_Z alpha version #s to X.YZ for easier comparisons + $pr_version =~ s/(\d+)\.(\d+)_(\d+)/$1.$2$3/; + + if (!$installed_file) { + warn sprintf "Warning: prerequisite %s %s not found.\n", + $prereq, $required_version + unless $self->{PREREQ_FATAL}; + + $unsatisfied{$prereq} = 'not installed'; + } + elsif ($pr_version < $required_version ){ + warn sprintf "Warning: prerequisite %s %s not found. We have %s.\n", + $prereq, $required_version, ($pr_version || 'unknown version') + unless $self->{PREREQ_FATAL}; + + $unsatisfied{$prereq} = $required_version ? $required_version : 'unknown version' ; + } + } + + if (%unsatisfied && $self->{PREREQ_FATAL}){ + my $failedprereqs = join "\n", map {" $_ $unsatisfied{$_}"} + sort { $a cmp $b } keys %unsatisfied; + die <<"END"; +MakeMaker FATAL: prerequisites not found. +$failedprereqs + +Please install these modules first and rerun 'perl Makefile.PL'. +END + } + + if (defined $self->{CONFIGURE}) { + if (ref $self->{CONFIGURE} eq 'CODE') { + %configure_att = %{&{$self->{CONFIGURE}}}; + $self = { %$self, %configure_att }; + } else { + Carp::croak "Attribute 'CONFIGURE' to WriteMakefile() not a code reference\n"; + } + } + + # This is for old Makefiles written pre 5.00, will go away + if ( Carp::longmess("") =~ /runsubdirpl/s ){ + Carp::carp("WARNING: Please rerun 'perl Makefile.PL' to regenerate your Makefiles\n"); + } + + my $newclass = ++$PACKNAME; + local @Parent = @Parent; # Protect against non-local exits + { + print "Blessing Object into class [$newclass]\n" if $Verbose>=2; + mv_all_methods("MY",$newclass); + bless $self, $newclass; + push @Parent, $self; + require ExtUtils::MY; + + no strict 'refs'; ## no critic; + @{"$newclass\:\:ISA"} = 'MM'; + } + + if (defined $Parent[-2]){ + $self->{PARENT} = $Parent[-2]; + for my $key (@Prepend_parent) { + next unless defined $self->{PARENT}{$key}; + + # Don't stomp on WriteMakefile() args. + next if defined $self->{ARGS}{$key} and + $self->{ARGS}{$key} eq $self->{$key}; + + $self->{$key} = $self->{PARENT}{$key}; + + unless ($Is_VMS && $key =~ /PERL$/) { + $self->{$key} = $self->catdir("..",$self->{$key}) + unless $self->file_name_is_absolute($self->{$key}); + } else { + # PERL or FULLPERL will be a command verb or even a + # command with an argument instead of a full file + # specification under VMS. So, don't turn the command + # into a filespec, but do add a level to the path of + # the argument if not already absolute. + my @cmd = split /\s+/, $self->{$key}; + $cmd[1] = $self->catfile('[-]',$cmd[1]) + unless (@cmd < 2) || $self->file_name_is_absolute($cmd[1]); + $self->{$key} = join(' ', @cmd); + } + } + if ($self->{PARENT}) { + $self->{PARENT}->{CHILDREN}->{$newclass} = $self; + foreach my $opt (qw(POLLUTE PERL_CORE LINKTYPE)) { + if (exists $self->{PARENT}->{$opt} + and not exists $self->{$opt}) + { + # inherit, but only if already unspecified + $self->{$opt} = $self->{PARENT}->{$opt}; + } + } + } + my @fm = grep /^FIRST_MAKEFILE=/, @ARGV; + parse_args($self,@fm) if @fm; + } else { + parse_args($self,split(' ', $ENV{PERL_MM_OPT} || ''),@ARGV); + } + + + $self->{NAME} ||= $self->guess_name; + + ($self->{NAME_SYM} = $self->{NAME}) =~ s/\W+/_/g; + + $self->init_MAKE; + $self->init_main; + $self->init_VERSION; + $self->init_dist; + $self->init_INST; + $self->init_INSTALL; + $self->init_DEST; + $self->init_dirscan; + $self->init_PM; + $self->init_MANPODS; + $self->init_xs; + $self->init_PERL; + $self->init_DIRFILESEP; + $self->init_linker; + $self->init_ABSTRACT; + + $self->arch_check( + $INC{'Config.pm'}, + $self->catfile($Config{'archlibexp'}, "Config.pm") + ); + + $self->init_others(); + $self->init_platform(); + $self->init_PERM(); + my($argv) = neatvalue(\@ARGV); + $argv =~ s/^\[/(/; + $argv =~ s/\]$/)/; + + push @{$self->{RESULT}}, <<END; +# This Makefile is for the $self->{NAME} extension to perl. +# +# It was generated automatically by MakeMaker version +# $VERSION (Revision: $Revision) from the contents of +# Makefile.PL. Don't edit this file, edit Makefile.PL instead. +# +# ANY CHANGES MADE HERE WILL BE LOST! +# +# MakeMaker ARGV: $argv +# +END + + push @{$self->{RESULT}}, $self->_MakeMaker_Parameters_section(\%initial_att); + + if (defined $self->{CONFIGURE}) { + push @{$self->{RESULT}}, <<END; + +# MakeMaker 'CONFIGURE' Parameters: +END + if (scalar(keys %configure_att) > 0) { + foreach my $key (sort keys %configure_att){ + next if $key eq 'ARGS'; + my($v) = neatvalue($configure_att{$key}); + $v =~ s/(CODE|HASH|ARRAY|SCALAR)\([\dxa-f]+\)/$1\(...\)/; + $v =~ tr/\n/ /s; + push @{$self->{RESULT}}, "# $key => $v"; + } + } + else + { + push @{$self->{RESULT}}, "# no values returned"; + } + undef %configure_att; # free memory + } + + # turn the SKIP array into a SKIPHASH hash + for my $skip (@{$self->{SKIP} || []}) { + $self->{SKIPHASH}{$skip} = 1; + } + delete $self->{SKIP}; # free memory + + if ($self->{PARENT}) { + for (qw/install dist dist_basics dist_core distdir dist_test dist_ci/) { + $self->{SKIPHASH}{$_} = 1; + } + } + + # We run all the subdirectories now. They don't have much to query + # from the parent, but the parent has to query them: if they need linking! + unless ($self->{NORECURS}) { + $self->eval_in_subdirs if @{$self->{DIR}}; + } + + foreach my $section ( @MM_Sections ){ + # Support for new foo_target() methods. + my $method = $section; + $method .= '_target' unless $self->can($method); + + print "Processing Makefile '$section' section\n" if ($Verbose >= 2); + my($skipit) = $self->skipcheck($section); + if ($skipit){ + push @{$self->{RESULT}}, "\n# --- MakeMaker $section section $skipit."; + } else { + my(%a) = %{$self->{$section} || {}}; + push @{$self->{RESULT}}, "\n# --- MakeMaker $section section:"; + push @{$self->{RESULT}}, "# " . join ", ", %a if $Verbose && %a; + push @{$self->{RESULT}}, $self->maketext_filter( + $self->$method( %a ) + ); + } + } + + push @{$self->{RESULT}}, "\n# End."; + + $self; +} + +sub WriteEmptyMakefile { + Carp::croak "WriteEmptyMakefile: Need an even number of args" if @_ % 2; + + my %att = @_; + my $self = MM->new(\%att); + + my $new = $self->{MAKEFILE}; + my $old = $self->{MAKEFILE_OLD}; + if (-f $old) { + _unlink($old) or warn "unlink $old: $!"; + } + if ( -f $new ) { + _rename($new, $old) or warn "rename $new => $old: $!" + } + open my $mfh, '>', $new or die "open $new for write: $!"; + print $mfh <<'EOP'; +all : + +clean : + +install : + +makemakerdflt : + +test : + +EOP + close $mfh or die "close $new for write: $!"; +} + + +=begin private + +=head3 _installed_file_for_module + + my $file = MM->_installed_file_for_module($module); + +Return the first installed .pm $file associated with the $module. The +one which will show up when you C<use $module>. + +$module is something like "strict" or "Test::More". + +=end private + +=cut + +sub _installed_file_for_module { + my $class = shift; + my $prereq = shift; + + my $file = "$prereq.pm"; + $file =~ s{::}{/}g; + + my $path; + for my $dir (@INC) { + my $tmp = File::Spec->catfile($dir, $file); + if ( -r $tmp ) { + $path = $tmp; + last; + } + } + + return $path; +} + + +# Extracted from MakeMaker->new so we can test it +sub _MakeMaker_Parameters_section { + my $self = shift; + my $att = shift; + + my @result = <<'END'; +# MakeMaker Parameters: +END + + foreach my $key (sort keys %$att){ + next if $key eq 'ARGS'; + my ($v) = neatvalue($att->{$key}); + if ($key eq 'PREREQ_PM') { + # CPAN.pm takes prereqs from this field in 'Makefile' + # and does not know about BUILD_REQUIRES + $v = neatvalue({ %{ $att->{PREREQ_PM} || {} }, %{ $att->{BUILD_REQUIRES} || {} } }); + } else { + $v = neatvalue($att->{$key}); + } + + $v =~ s/(CODE|HASH|ARRAY|SCALAR)\([\dxa-f]+\)/$1\(...\)/; + $v =~ tr/\n/ /s; + push @result, "# $key => $v"; + } + + return @result; +} + + +sub check_manifest { + print STDOUT "Checking if your kit is complete...\n"; + require ExtUtils::Manifest; + # avoid warning + $ExtUtils::Manifest::Quiet = $ExtUtils::Manifest::Quiet = 1; + my(@missed) = ExtUtils::Manifest::manicheck(); + if (@missed) { + print STDOUT "Warning: the following files are missing in your kit:\n"; + print "\t", join "\n\t", @missed; + print STDOUT "\n"; + print STDOUT "Please inform the author.\n"; + } else { + print STDOUT "Looks good\n"; + } +} + +sub parse_args{ + my($self, @args) = @_; + foreach (@args) { + unless (m/(.*?)=(.*)/) { + ++$Verbose if m/^verb/; + next; + } + my($name, $value) = ($1, $2); + if ($value =~ m/^~(\w+)?/) { # tilde with optional username + $value =~ s [^~(\w*)] + [$1 ? + ((getpwnam($1))[7] || "~$1") : + (getpwuid($>))[7] + ]ex; + } + + # Remember the original args passed it. It will be useful later. + $self->{ARGS}{uc $name} = $self->{uc $name} = $value; + } + + # catch old-style 'potential_libs' and inform user how to 'upgrade' + if (defined $self->{potential_libs}){ + my($msg)="'potential_libs' => '$self->{potential_libs}' should be"; + if ($self->{potential_libs}){ + print STDOUT "$msg changed to:\n\t'LIBS' => ['$self->{potential_libs}']\n"; + } else { + print STDOUT "$msg deleted.\n"; + } + $self->{LIBS} = [$self->{potential_libs}]; + delete $self->{potential_libs}; + } + # catch old-style 'ARMAYBE' and inform user how to 'upgrade' + if (defined $self->{ARMAYBE}){ + my($armaybe) = $self->{ARMAYBE}; + print STDOUT "ARMAYBE => '$armaybe' should be changed to:\n", + "\t'dynamic_lib' => {ARMAYBE => '$armaybe'}\n"; + my(%dl) = %{$self->{dynamic_lib} || {}}; + $self->{dynamic_lib} = { %dl, ARMAYBE => $armaybe}; + delete $self->{ARMAYBE}; + } + if (defined $self->{LDTARGET}){ + print STDOUT "LDTARGET should be changed to LDFROM\n"; + $self->{LDFROM} = $self->{LDTARGET}; + delete $self->{LDTARGET}; + } + # Turn a DIR argument on the command line into an array + if (defined $self->{DIR} && ref \$self->{DIR} eq 'SCALAR') { + # So they can choose from the command line, which extensions they want + # the grep enables them to have some colons too much in case they + # have to build a list with the shell + $self->{DIR} = [grep $_, split ":", $self->{DIR}]; + } + # Turn a INCLUDE_EXT argument on the command line into an array + if (defined $self->{INCLUDE_EXT} && ref \$self->{INCLUDE_EXT} eq 'SCALAR') { + $self->{INCLUDE_EXT} = [grep $_, split '\s+', $self->{INCLUDE_EXT}]; + } + # Turn a EXCLUDE_EXT argument on the command line into an array + if (defined $self->{EXCLUDE_EXT} && ref \$self->{EXCLUDE_EXT} eq 'SCALAR') { + $self->{EXCLUDE_EXT} = [grep $_, split '\s+', $self->{EXCLUDE_EXT}]; + } + + foreach my $mmkey (sort keys %$self){ + next if $mmkey eq 'ARGS'; + print STDOUT " $mmkey => ", neatvalue($self->{$mmkey}), "\n" if $Verbose; + print STDOUT "'$mmkey' is not a known MakeMaker parameter name.\n" + unless exists $Recognized_Att_Keys{$mmkey}; + } + $| = 1 if $Verbose; +} + +sub check_hints { + my($self) = @_; + # We allow extension-specific hints files. + + require File::Spec; + my $curdir = File::Spec->curdir; + + my $hint_dir = File::Spec->catdir($curdir, "hints"); + return unless -d $hint_dir; + + # First we look for the best hintsfile we have + my($hint)="${^O}_$Config{osvers}"; + $hint =~ s/\./_/g; + $hint =~ s/_$//; + return unless $hint; + + # Also try without trailing minor version numbers. + while (1) { + last if -f File::Spec->catfile($hint_dir, "$hint.pl"); # found + } continue { + last unless $hint =~ s/_[^_]*$//; # nothing to cut off + } + my $hint_file = File::Spec->catfile($hint_dir, "$hint.pl"); + + return unless -f $hint_file; # really there + + _run_hintfile($self, $hint_file); +} + +sub _run_hintfile { + our $self; + local($self) = shift; # make $self available to the hint file. + my($hint_file) = shift; + + local($@, $!); + print STDERR "Processing hints file $hint_file\n"; + + # Just in case the ./ isn't on the hint file, which File::Spec can + # often strip off, we bung the curdir into @INC + local @INC = (File::Spec->curdir, @INC); + my $ret = do $hint_file; + if( !defined $ret ) { + my $error = $@ || $!; + print STDERR $error; + } +} + +sub mv_all_methods { + my($from,$to) = @_; + + # Here you see the *current* list of methods that are overridable + # from Makefile.PL via MY:: subroutines. As of VERSION 5.07 I'm + # still trying to reduce the list to some reasonable minimum -- + # because I want to make it easier for the user. A.K. + + local $SIG{__WARN__} = sub { + # can't use 'no warnings redefined', 5.6 only + warn @_ unless $_[0] =~ /^Subroutine .* redefined/ + }; + foreach my $method (@Overridable) { + + # We cannot say "next" here. Nick might call MY->makeaperl + # which isn't defined right now + + # Above statement was written at 4.23 time when Tk-b8 was + # around. As Tk-b9 only builds with 5.002something and MM 5 is + # standard, we try to enable the next line again. It was + # commented out until MM 5.23 + + next unless defined &{"${from}::$method"}; + + { + no strict 'refs'; ## no critic + *{"${to}::$method"} = \&{"${from}::$method"}; + + # If we delete a method, then it will be undefined and cannot + # be called. But as long as we have Makefile.PLs that rely on + # %MY:: being intact, we have to fill the hole with an + # inheriting method: + + { + package MY; + my $super = "SUPER::".$method; + *{$method} = sub { + shift->$super(@_); + }; + } + } + } + + # We have to clean out %INC also, because the current directory is + # changed frequently and Graham Barr prefers to get his version + # out of a History.pl file which is "required" so woudn't get + # loaded again in another extension requiring a History.pl + + # With perl5.002_01 the deletion of entries in %INC caused Tk-b11 + # to core dump in the middle of a require statement. The required + # file was Tk/MMutil.pm. The consequence is, we have to be + # extremely careful when we try to give perl a reason to reload a + # library with same name. The workaround prefers to drop nothing + # from %INC and teach the writers not to use such libraries. + +# my $inc; +# foreach $inc (keys %INC) { +# #warn "***$inc*** deleted"; +# delete $INC{$inc}; +# } +} + +sub skipcheck { + my($self) = shift; + my($section) = @_; + if ($section eq 'dynamic') { + print STDOUT "Warning (non-fatal): Target 'dynamic' depends on targets ", + "in skipped section 'dynamic_bs'\n" + if $self->{SKIPHASH}{dynamic_bs} && $Verbose; + print STDOUT "Warning (non-fatal): Target 'dynamic' depends on targets ", + "in skipped section 'dynamic_lib'\n" + if $self->{SKIPHASH}{dynamic_lib} && $Verbose; + } + if ($section eq 'dynamic_lib') { + print STDOUT "Warning (non-fatal): Target '\$(INST_DYNAMIC)' depends on ", + "targets in skipped section 'dynamic_bs'\n" + if $self->{SKIPHASH}{dynamic_bs} && $Verbose; + } + if ($section eq 'static') { + print STDOUT "Warning (non-fatal): Target 'static' depends on targets ", + "in skipped section 'static_lib'\n" + if $self->{SKIPHASH}{static_lib} && $Verbose; + } + return 'skipped' if $self->{SKIPHASH}{$section}; + return ''; +} + +sub flush { + my $self = shift; + + my $finalname = $self->{MAKEFILE}; + print STDOUT "Writing $finalname for $self->{NAME}\n"; + + unlink($finalname, "MakeMaker.tmp", $Is_VMS ? 'Descrip.MMS' : ()); + open(my $fh,">", "MakeMaker.tmp") + or die "Unable to open MakeMaker.tmp: $!"; + + for my $chunk (@{$self->{RESULT}}) { + print $fh "$chunk\n"; + } + + close $fh; + _rename("MakeMaker.tmp", $finalname) or + warn "rename MakeMaker.tmp => $finalname: $!"; + chmod 0644, $finalname unless $Is_VMS; + + my %keep = map { ($_ => 1) } qw(NEEDS_LINKING HAS_LINK_CODE); + + if ($self->{PARENT} && !$self->{_KEEP_AFTER_FLUSH}) { + foreach (keys %$self) { # safe memory + delete $self->{$_} unless $keep{$_}; + } + } + + system("$Config::Config{eunicefix} $finalname") unless $Config::Config{eunicefix} eq ":"; +} + + +# This is a rename for OS's where the target must be unlinked first. +sub _rename { + my($src, $dest) = @_; + chmod 0666, $dest; + unlink $dest; + return rename $src, $dest; +} + +# This is an unlink for OS's where the target must be writable first. +sub _unlink { + my @files = @_; + chmod 0666, @files; + return unlink @files; +} + + +# The following mkbootstrap() is only for installations that are calling +# the pre-4.1 mkbootstrap() from their old Makefiles. This MakeMaker +# writes Makefiles, that use ExtUtils::Mkbootstrap directly. +sub mkbootstrap { + die <<END; +!!! Your Makefile has been built such a long time ago, !!! +!!! that is unlikely to work with current MakeMaker. !!! +!!! Please rebuild your Makefile !!! +END +} + +# Ditto for mksymlists() as of MakeMaker 5.17 +sub mksymlists { + die <<END; +!!! Your Makefile has been built such a long time ago, !!! +!!! that is unlikely to work with current MakeMaker. !!! +!!! Please rebuild your Makefile !!! +END +} + +sub neatvalue { + my($v) = @_; + return "undef" unless defined $v; + my($t) = ref $v; + return "q[$v]" unless $t; + if ($t eq 'ARRAY') { + my(@m, @neat); + push @m, "["; + foreach my $elem (@$v) { + push @neat, "q[$elem]"; + } + push @m, join ", ", @neat; + push @m, "]"; + return join "", @m; + } + return "$v" unless $t eq 'HASH'; + my(@m, $key, $val); + while (($key,$val) = each %$v){ + last unless defined $key; # cautious programming in case (undef,undef) is true + push(@m,"$key=>".neatvalue($val)) ; + } + return "{ ".join(', ',@m)." }"; +} + +sub selfdocument { + my($self) = @_; + my(@m); + if ($Verbose){ + push @m, "\n# Full list of MakeMaker attribute values:"; + foreach my $key (sort keys %$self){ + next if $key eq 'RESULT' || $key =~ /^[A-Z][a-z]/; + my($v) = neatvalue($self->{$key}); + $v =~ s/(CODE|HASH|ARRAY|SCALAR)\([\dxa-f]+\)/$1\(...\)/; + $v =~ tr/\n/ /s; + push @m, "# $key => $v"; + } + } + join "\n", @m; +} + +1; + +__END__ + +=head1 NAME + +ExtUtils::MakeMaker - Create a module Makefile + +=head1 SYNOPSIS + + use ExtUtils::MakeMaker; + + WriteMakefile( ATTRIBUTE => VALUE [, ...] ); + +=head1 DESCRIPTION + +This utility is designed to write a Makefile for an extension module +from a Makefile.PL. It is based on the Makefile.SH model provided by +Andy Dougherty and the perl5-porters. + +It splits the task of generating the Makefile into several subroutines +that can be individually overridden. Each subroutine returns the text +it wishes to have written to the Makefile. + +MakeMaker is object oriented. Each directory below the current +directory that contains a Makefile.PL is treated as a separate +object. This makes it possible to write an unlimited number of +Makefiles with a single invocation of WriteMakefile(). + +=head2 How To Write A Makefile.PL + +See ExtUtils::MakeMaker::Tutorial. + +The long answer is the rest of the manpage :-) + +=head2 Default Makefile Behaviour + +The generated Makefile enables the user of the extension to invoke + + perl Makefile.PL # optionally "perl Makefile.PL verbose" + make + make test # optionally set TEST_VERBOSE=1 + make install # See below + +The Makefile to be produced may be altered by adding arguments of the +form C<KEY=VALUE>. E.g. + + perl Makefile.PL INSTALL_BASE=~ + +Other interesting targets in the generated Makefile are + + make config # to check if the Makefile is up-to-date + make clean # delete local temp files (Makefile gets renamed) + make realclean # delete derived files (including ./blib) + make ci # check in all the files in the MANIFEST file + make dist # see below the Distribution Support section + +=head2 make test + +MakeMaker checks for the existence of a file named F<test.pl> in the +current directory and if it exists it execute the script with the +proper set of perl C<-I> options. + +MakeMaker also checks for any files matching glob("t/*.t"). It will +execute all matching files in alphabetical order via the +L<Test::Harness> module with the C<-I> switches set correctly. + +If you'd like to see the raw output of your tests, set the +C<TEST_VERBOSE> variable to true. + + make test TEST_VERBOSE=1 + +=head2 make testdb + +A useful variation of the above is the target C<testdb>. It runs the +test under the Perl debugger (see L<perldebug>). If the file +F<test.pl> exists in the current directory, it is used for the test. + +If you want to debug some other testfile, set the C<TEST_FILE> variable +thusly: + + make testdb TEST_FILE=t/mytest.t + +By default the debugger is called using C<-d> option to perl. If you +want to specify some other option, set the C<TESTDB_SW> variable: + + make testdb TESTDB_SW=-Dx + +=head2 make install + +make alone puts all relevant files into directories that are named by +the macros INST_LIB, INST_ARCHLIB, INST_SCRIPT, INST_MAN1DIR and +INST_MAN3DIR. All these default to something below ./blib if you are +I<not> building below the perl source directory. If you I<are> +building below the perl source, INST_LIB and INST_ARCHLIB default to +../../lib, and INST_SCRIPT is not defined. + +The I<install> target of the generated Makefile copies the files found +below each of the INST_* directories to their INSTALL* +counterparts. Which counterparts are chosen depends on the setting of +INSTALLDIRS according to the following table: + + INSTALLDIRS set to + perl site vendor + + PERLPREFIX SITEPREFIX VENDORPREFIX + INST_ARCHLIB INSTALLARCHLIB INSTALLSITEARCH INSTALLVENDORARCH + INST_LIB INSTALLPRIVLIB INSTALLSITELIB INSTALLVENDORLIB + INST_BIN INSTALLBIN INSTALLSITEBIN INSTALLVENDORBIN + INST_SCRIPT INSTALLSCRIPT INSTALLSITESCRIPT INSTALLVENDORSCRIPT + INST_MAN1DIR INSTALLMAN1DIR INSTALLSITEMAN1DIR INSTALLVENDORMAN1DIR + INST_MAN3DIR INSTALLMAN3DIR INSTALLSITEMAN3DIR INSTALLVENDORMAN3DIR + +The INSTALL... macros in turn default to their %Config +($Config{installprivlib}, $Config{installarchlib}, etc.) counterparts. + +You can check the values of these variables on your system with + + perl '-V:install.*' + +And to check the sequence in which the library directories are +searched by perl, run + + perl -le 'print join $/, @INC' + +Sometimes older versions of the module you're installing live in other +directories in @INC. Because Perl loads the first version of a module it +finds, not the newest, you might accidentally get one of these older +versions even after installing a brand new version. To delete I<all other +versions of the module you're installing> (not simply older ones) set the +C<UNINST> variable. + + make install UNINST=1 + + +=head2 INSTALL_BASE + +INSTALL_BASE can be passed into Makefile.PL to change where your +module will be installed. INSTALL_BASE is more like what everyone +else calls "prefix" than PREFIX is. + +To have everything installed in your home directory, do the following. + + # Unix users, INSTALL_BASE=~ works fine + perl Makefile.PL INSTALL_BASE=/path/to/your/home/dir + +Like PREFIX, it sets several INSTALL* attributes at once. Unlike +PREFIX it is easy to predict where the module will end up. The +installation pattern looks like this: + + INSTALLARCHLIB INSTALL_BASE/lib/perl5/$Config{archname} + INSTALLPRIVLIB INSTALL_BASE/lib/perl5 + INSTALLBIN INSTALL_BASE/bin + INSTALLSCRIPT INSTALL_BASE/bin + INSTALLMAN1DIR INSTALL_BASE/man/man1 + INSTALLMAN3DIR INSTALL_BASE/man/man3 + +INSTALL_BASE in MakeMaker and C<--install_base> in Module::Build (as +of 0.28) install to the same location. If you want MakeMaker and +Module::Build to install to the same location simply set INSTALL_BASE +and C<--install_base> to the same location. + +INSTALL_BASE was added in 6.31. + + +=head2 PREFIX and LIB attribute + +PREFIX and LIB can be used to set several INSTALL* attributes in one +go. Here's an example for installing into your home directory. + + # Unix users, PREFIX=~ works fine + perl Makefile.PL PREFIX=/path/to/your/home/dir + +This will install all files in the module under your home directory, +with man pages and libraries going into an appropriate place (usually +~/man and ~/lib). How the exact location is determined is complicated +and depends on how your Perl was configured. INSTALL_BASE works more +like what other build systems call "prefix" than PREFIX and we +recommend you use that instead. + +Another way to specify many INSTALL directories with a single +parameter is LIB. + + perl Makefile.PL LIB=~/lib + +This will install the module's architecture-independent files into +~/lib, the architecture-dependent files into ~/lib/$archname. + +Note, that in both cases the tilde expansion is done by MakeMaker, not +by perl by default, nor by make. + +Conflicts between parameters LIB, PREFIX and the various INSTALL* +arguments are resolved so that: + +=over 4 + +=item * + +setting LIB overrides any setting of INSTALLPRIVLIB, INSTALLARCHLIB, +INSTALLSITELIB, INSTALLSITEARCH (and they are not affected by PREFIX); + +=item * + +without LIB, setting PREFIX replaces the initial C<$Config{prefix}> +part of those INSTALL* arguments, even if the latter are explicitly +set (but are set to still start with C<$Config{prefix}>). + +=back + +If the user has superuser privileges, and is not working on AFS or +relatives, then the defaults for INSTALLPRIVLIB, INSTALLARCHLIB, +INSTALLSCRIPT, etc. will be appropriate, and this incantation will be +the best: + + perl Makefile.PL; + make; + make test + make install + +make install per default writes some documentation of what has been +done into the file C<$(INSTALLARCHLIB)/perllocal.pod>. This feature +can be bypassed by calling make pure_install. + +=head2 AFS users + +will have to specify the installation directories as these most +probably have changed since perl itself has been installed. They will +have to do this by calling + + perl Makefile.PL INSTALLSITELIB=/afs/here/today \ + INSTALLSCRIPT=/afs/there/now INSTALLMAN3DIR=/afs/for/manpages + make + +Be careful to repeat this procedure every time you recompile an +extension, unless you are sure the AFS installation directories are +still valid. + +=head2 Static Linking of a new Perl Binary + +An extension that is built with the above steps is ready to use on +systems supporting dynamic loading. On systems that do not support +dynamic loading, any newly created extension has to be linked together +with the available resources. MakeMaker supports the linking process +by creating appropriate targets in the Makefile whenever an extension +is built. You can invoke the corresponding section of the makefile with + + make perl + +That produces a new perl binary in the current directory with all +extensions linked in that can be found in INST_ARCHLIB, SITELIBEXP, +and PERL_ARCHLIB. To do that, MakeMaker writes a new Makefile, on +UNIX, this is called Makefile.aperl (may be system dependent). If you +want to force the creation of a new perl, it is recommended, that you +delete this Makefile.aperl, so the directories are searched-through +for linkable libraries again. + +The binary can be installed into the directory where perl normally +resides on your machine with + + make inst_perl + +To produce a perl binary with a different name than C<perl>, either say + + perl Makefile.PL MAP_TARGET=myperl + make myperl + make inst_perl + +or say + + perl Makefile.PL + make myperl MAP_TARGET=myperl + make inst_perl MAP_TARGET=myperl + +In any case you will be prompted with the correct invocation of the +C<inst_perl> target that installs the new binary into INSTALLBIN. + +make inst_perl per default writes some documentation of what has been +done into the file C<$(INSTALLARCHLIB)/perllocal.pod>. This +can be bypassed by calling make pure_inst_perl. + +Warning: the inst_perl: target will most probably overwrite your +existing perl binary. Use with care! + +Sometimes you might want to build a statically linked perl although +your system supports dynamic loading. In this case you may explicitly +set the linktype with the invocation of the Makefile.PL or make: + + perl Makefile.PL LINKTYPE=static # recommended + +or + + make LINKTYPE=static # works on most systems + +=head2 Determination of Perl Library and Installation Locations + +MakeMaker needs to know, or to guess, where certain things are +located. Especially INST_LIB and INST_ARCHLIB (where to put the files +during the make(1) run), PERL_LIB and PERL_ARCHLIB (where to read +existing modules from), and PERL_INC (header files and C<libperl*.*>). + +Extensions may be built either using the contents of the perl source +directory tree or from the installed perl library. The recommended way +is to build extensions after you have run 'make install' on perl +itself. You can do that in any directory on your hard disk that is not +below the perl source tree. The support for extensions below the ext +directory of the perl distribution is only good for the standard +extensions that come with perl. + +If an extension is being built below the C<ext/> directory of the perl +source then MakeMaker will set PERL_SRC automatically (e.g., +C<../..>). If PERL_SRC is defined and the extension is recognized as +a standard extension, then other variables default to the following: + + PERL_INC = PERL_SRC + PERL_LIB = PERL_SRC/lib + PERL_ARCHLIB = PERL_SRC/lib + INST_LIB = PERL_LIB + INST_ARCHLIB = PERL_ARCHLIB + +If an extension is being built away from the perl source then MakeMaker +will leave PERL_SRC undefined and default to using the installed copy +of the perl library. The other variables default to the following: + + PERL_INC = $archlibexp/CORE + PERL_LIB = $privlibexp + PERL_ARCHLIB = $archlibexp + INST_LIB = ./blib/lib + INST_ARCHLIB = ./blib/arch + +If perl has not yet been installed then PERL_SRC can be defined on the +command line as shown in the previous section. + + +=head2 Which architecture dependent directory? + +If you don't want to keep the defaults for the INSTALL* macros, +MakeMaker helps you to minimize the typing needed: the usual +relationship between INSTALLPRIVLIB and INSTALLARCHLIB is determined +by Configure at perl compilation time. MakeMaker supports the user who +sets INSTALLPRIVLIB. If INSTALLPRIVLIB is set, but INSTALLARCHLIB not, +then MakeMaker defaults the latter to be the same subdirectory of +INSTALLPRIVLIB as Configure decided for the counterparts in %Config , +otherwise it defaults to INSTALLPRIVLIB. The same relationship holds +for INSTALLSITELIB and INSTALLSITEARCH. + +MakeMaker gives you much more freedom than needed to configure +internal variables and get different results. It is worth to mention, +that make(1) also lets you configure most of the variables that are +used in the Makefile. But in the majority of situations this will not +be necessary, and should only be done if the author of a package +recommends it (or you know what you're doing). + +=head2 Using Attributes and Parameters + +The following attributes may be specified as arguments to WriteMakefile() +or as NAME=VALUE pairs on the command line. + +=over 2 + +=item ABSTRACT + +One line description of the module. Will be included in PPD file. + +=item ABSTRACT_FROM + +Name of the file that contains the package description. MakeMaker looks +for a line in the POD matching /^($package\s-\s)(.*)/. This is typically +the first line in the "=head1 NAME" section. $2 becomes the abstract. + +=item AUTHOR + +String containing name (and email address) of package author(s). Is used +in PPD (Perl Package Description) files for PPM (Perl Package Manager). + +=item BINARY_LOCATION + +Used when creating PPD files for binary packages. It can be set to a +full or relative path or URL to the binary archive for a particular +architecture. For example: + + perl Makefile.PL BINARY_LOCATION=x86/Agent.tar.gz + +builds a PPD package that references a binary of the C<Agent> package, +located in the C<x86> directory relative to the PPD itself. + +=item BUILD_REQUIRES + +A hash of modules that are needed to build your module but not run it. + +This will go into the C<build_requires> field of your F<META.yml>. + +The format is the same as PREREQ_PM. + +=item C + +Ref to array of *.c file names. Initialised from a directory scan +and the values portion of the XS attribute hash. This is not +currently used by MakeMaker but may be handy in Makefile.PLs. + +=item CCFLAGS + +String that will be included in the compiler call command line between +the arguments INC and OPTIMIZE. + +=item CONFIG + +Arrayref. E.g. [qw(archname manext)] defines ARCHNAME & MANEXT from +config.sh. MakeMaker will add to CONFIG the following values anyway: +ar +cc +cccdlflags +ccdlflags +dlext +dlsrc +ld +lddlflags +ldflags +libc +lib_ext +obj_ext +ranlib +sitelibexp +sitearchexp +so + +=item CONFIGURE + +CODE reference. The subroutine should return a hash reference. The +hash may contain further attributes, e.g. {LIBS =E<gt> ...}, that have to +be determined by some evaluation method. + +=item CONFIGURE_REQUIRES + +A hash of modules that are required to run Makefile.PL itself, but not +to run your distribution. + +This will go into the C<configure_requires> field of your F<META.yml>. + +Defaults to C<<< { "ExtUtils::MakeMaker" => 0 } >>> + +The format is the same as PREREQ_PM. + +=item DEFINE + +Something like C<"-DHAVE_UNISTD_H"> + +=item DESTDIR + +This is the root directory into which the code will be installed. It +I<prepends itself to the normal prefix>. For example, if your code +would normally go into F</usr/local/lib/perl> you could set DESTDIR=~/tmp/ +and installation would go into F<~/tmp/usr/local/lib/perl>. + +This is primarily of use for people who repackage Perl modules. + +NOTE: Due to the nature of make, it is important that you put the trailing +slash on your DESTDIR. F<~/tmp/> not F<~/tmp>. + +=item DIR + +Ref to array of subdirectories containing Makefile.PLs e.g. ['sdbm'] +in ext/SDBM_File + +=item DISTNAME + +A safe filename for the package. + +Defaults to NAME above but with :: replaced with -. + +For example, Foo::Bar becomes Foo-Bar. + +=item DISTVNAME + +Your name for distributing the package with the version number +included. This is used by 'make dist' to name the resulting archive +file. + +Defaults to DISTNAME-VERSION. + +For example, version 1.04 of Foo::Bar becomes Foo-Bar-1.04. + +On some OS's where . has special meaning VERSION_SYM may be used in +place of VERSION. + +=item DL_FUNCS + +Hashref of symbol names for routines to be made available as universal +symbols. Each key/value pair consists of the package name and an +array of routine names in that package. Used only under AIX, OS/2, +VMS and Win32 at present. The routine names supplied will be expanded +in the same way as XSUB names are expanded by the XS() macro. +Defaults to + + {"$(NAME)" => ["boot_$(NAME)" ] } + +e.g. + + {"RPC" => [qw( boot_rpcb rpcb_gettime getnetconfigent )], + "NetconfigPtr" => [ 'DESTROY'] } + +Please see the L<ExtUtils::Mksymlists> documentation for more information +about the DL_FUNCS, DL_VARS and FUNCLIST attributes. + +=item DL_VARS + +Array of symbol names for variables to be made available as universal symbols. +Used only under AIX, OS/2, VMS and Win32 at present. Defaults to []. +(e.g. [ qw(Foo_version Foo_numstreams Foo_tree ) ]) + +=item EXCLUDE_EXT + +Array of extension names to exclude when doing a static build. This +is ignored if INCLUDE_EXT is present. Consult INCLUDE_EXT for more +details. (e.g. [ qw( Socket POSIX ) ] ) + +This attribute may be most useful when specified as a string on the +command line: perl Makefile.PL EXCLUDE_EXT='Socket Safe' + +=item EXE_FILES + +Ref to array of executable files. The files will be copied to the +INST_SCRIPT directory. Make realclean will delete them from there +again. + +If your executables start with something like #!perl or +#!/usr/bin/perl MakeMaker will change this to the path of the perl +'Makefile.PL' was invoked with so the programs will be sure to run +properly even if perl is not in /usr/bin/perl. + +=item FIRST_MAKEFILE + +The name of the Makefile to be produced. This is used for the second +Makefile that will be produced for the MAP_TARGET. + +Defaults to 'Makefile' or 'Descrip.MMS' on VMS. + +(Note: we couldn't use MAKEFILE because dmake uses this for something +else). + +=item FULLPERL + +Perl binary able to run this extension, load XS modules, etc... + +=item FULLPERLRUN + +Like PERLRUN, except it uses FULLPERL. + +=item FULLPERLRUNINST + +Like PERLRUNINST, except it uses FULLPERL. + +=item FUNCLIST + +This provides an alternate means to specify function names to be +exported from the extension. Its value is a reference to an +array of function names to be exported by the extension. These +names are passed through unaltered to the linker options file. + +=item H + +Ref to array of *.h file names. Similar to C. + +=item IMPORTS + +This attribute is used to specify names to be imported into the +extension. Takes a hash ref. + +It is only used on OS/2 and Win32. + +=item INC + +Include file dirs eg: C<"-I/usr/5include -I/path/to/inc"> + +=item INCLUDE_EXT + +Array of extension names to be included when doing a static build. +MakeMaker will normally build with all of the installed extensions when +doing a static build, and that is usually the desired behavior. If +INCLUDE_EXT is present then MakeMaker will build only with those extensions +which are explicitly mentioned. (e.g. [ qw( Socket POSIX ) ]) + +It is not necessary to mention DynaLoader or the current extension when +filling in INCLUDE_EXT. If the INCLUDE_EXT is mentioned but is empty then +only DynaLoader and the current extension will be included in the build. + +This attribute may be most useful when specified as a string on the +command line: perl Makefile.PL INCLUDE_EXT='POSIX Socket Devel::Peek' + +=item INSTALLARCHLIB + +Used by 'make install', which copies files from INST_ARCHLIB to this +directory if INSTALLDIRS is set to perl. + +=item INSTALLBIN + +Directory to install binary files (e.g. tkperl) into if +INSTALLDIRS=perl. + +=item INSTALLDIRS + +Determines which of the sets of installation directories to choose: +perl, site or vendor. Defaults to site. + +=item INSTALLMAN1DIR + +=item INSTALLMAN3DIR + +These directories get the man pages at 'make install' time if +INSTALLDIRS=perl. Defaults to $Config{installman*dir}. + +If set to 'none', no man pages will be installed. + +=item INSTALLPRIVLIB + +Used by 'make install', which copies files from INST_LIB to this +directory if INSTALLDIRS is set to perl. + +Defaults to $Config{installprivlib}. + +=item INSTALLSCRIPT + +Used by 'make install' which copies files from INST_SCRIPT to this +directory if INSTALLDIRS=perl. + +=item INSTALLSITEARCH + +Used by 'make install', which copies files from INST_ARCHLIB to this +directory if INSTALLDIRS is set to site (default). + +=item INSTALLSITEBIN + +Used by 'make install', which copies files from INST_BIN to this +directory if INSTALLDIRS is set to site (default). + +=item INSTALLSITELIB + +Used by 'make install', which copies files from INST_LIB to this +directory if INSTALLDIRS is set to site (default). + +=item INSTALLSITEMAN1DIR + +=item INSTALLSITEMAN3DIR + +These directories get the man pages at 'make install' time if +INSTALLDIRS=site (default). Defaults to +$(SITEPREFIX)/man/man$(MAN*EXT). + +If set to 'none', no man pages will be installed. + +=item INSTALLSITESCRIPT + +Used by 'make install' which copies files from INST_SCRIPT to this +directory if INSTALLDIRS is set to site (default). + +=item INSTALLVENDORARCH + +Used by 'make install', which copies files from INST_ARCHLIB to this +directory if INSTALLDIRS is set to vendor. + +=item INSTALLVENDORBIN + +Used by 'make install', which copies files from INST_BIN to this +directory if INSTALLDIRS is set to vendor. + +=item INSTALLVENDORLIB + +Used by 'make install', which copies files from INST_LIB to this +directory if INSTALLDIRS is set to vendor. + +=item INSTALLVENDORMAN1DIR + +=item INSTALLVENDORMAN3DIR + +These directories get the man pages at 'make install' time if +INSTALLDIRS=vendor. Defaults to $(VENDORPREFIX)/man/man$(MAN*EXT). + +If set to 'none', no man pages will be installed. + +=item INSTALLVENDORSCRIPT + +Used by 'make install' which copies files from INST_SCRIPT to this +directory if INSTALLDIRS is set to vendor. + +=item INST_ARCHLIB + +Same as INST_LIB for architecture dependent files. + +=item INST_BIN + +Directory to put real binary files during 'make'. These will be copied +to INSTALLBIN during 'make install' + +=item INST_LIB + +Directory where we put library files of this extension while building +it. + +=item INST_MAN1DIR + +Directory to hold the man pages at 'make' time + +=item INST_MAN3DIR + +Directory to hold the man pages at 'make' time + +=item INST_SCRIPT + +Directory, where executable files should be installed during +'make'. Defaults to "./blib/script", just to have a dummy location during +testing. make install will copy the files in INST_SCRIPT to +INSTALLSCRIPT. + +=item LD + +Program to be used to link libraries for dynamic loading. + +Defaults to $Config{ld}. + +=item LDDLFLAGS + +Any special flags that might need to be passed to ld to create a +shared library suitable for dynamic loading. It is up to the makefile +to use it. (See L<Config/lddlflags>) + +Defaults to $Config{lddlflags}. + +=item LDFROM + +Defaults to "$(OBJECT)" and is used in the ld command to specify +what files to link/load from (also see dynamic_lib below for how to +specify ld flags) + +=item LIB + +LIB should only be set at C<perl Makefile.PL> time but is allowed as a +MakeMaker argument. It has the effect of setting both INSTALLPRIVLIB +and INSTALLSITELIB to that value regardless any explicit setting of +those arguments (or of PREFIX). INSTALLARCHLIB and INSTALLSITEARCH +are set to the corresponding architecture subdirectory. + +=item LIBPERL_A + +The filename of the perllibrary that will be used together with this +extension. Defaults to libperl.a. + +=item LIBS + +An anonymous array of alternative library +specifications to be searched for (in order) until +at least one library is found. E.g. + + 'LIBS' => ["-lgdbm", "-ldbm -lfoo", "-L/path -ldbm.nfs"] + +Mind, that any element of the array +contains a complete set of arguments for the ld +command. So do not specify + + 'LIBS' => ["-ltcl", "-ltk", "-lX11"] + +See ODBM_File/Makefile.PL for an example, where an array is needed. If +you specify a scalar as in + + 'LIBS' => "-ltcl -ltk -lX11" + +MakeMaker will turn it into an array with one element. + +=item LICENSE + +The licensing terms of your distribution. Generally its "perl" for the +same license as Perl itself. + +See L<Module::Build::API> for the list of options. + +Defaults to "unknown". + +=item LINKTYPE + +'static' or 'dynamic' (default unless usedl=undef in +config.sh). Should only be used to force static linking (also see +linkext below). + +=item MAKE + +Variant of make you intend to run the generated Makefile with. This +parameter lets Makefile.PL know what make quirks to account for when +generating the Makefile. + +MakeMaker also honors the MAKE environment variable. This parameter +takes precedent. + +Currently the only significant values are 'dmake' and 'nmake' for Windows +users. + +Defaults to $Config{make}. + +=item MAKEAPERL + +Boolean which tells MakeMaker, that it should include the rules to +make a perl. This is handled automatically as a switch by +MakeMaker. The user normally does not need it. + +=item MAKEFILE_OLD + +When 'make clean' or similar is run, the $(FIRST_MAKEFILE) will be +backed up at this location. + +Defaults to $(FIRST_MAKEFILE).old or $(FIRST_MAKEFILE)_old on VMS. + +=item MAN1PODS + +Hashref of pod-containing files. MakeMaker will default this to all +EXE_FILES files that include POD directives. The files listed +here will be converted to man pages and installed as was requested +at Configure time. + +This hash should map POD files (or scripts containing POD) to the +man file names under the C<blib/man1/> directory, as in the following +example: + + MAN1PODS => { + 'doc/command.pod' => 'blib/man1/command.1', + 'scripts/script.pl' => 'blib/man1/script.1', + } + +=item MAN3PODS + +Hashref that assigns to *.pm and *.pod files the files into which the +manpages are to be written. MakeMaker parses all *.pod and *.pm files +for POD directives. Files that contain POD will be the default keys of +the MAN3PODS hashref. These will then be converted to man pages during +C<make> and will be installed during C<make install>. + +Example similar to MAN1PODS. + +=item MAP_TARGET + +If it is intended, that a new perl binary be produced, this variable +may hold a name for that binary. Defaults to perl + +=item META_ADD + +=item META_MERGE + +A hashrefs of items to add to the F<META.yml>. + +They differ in how they behave if they have the same key as the +default metadata. META_ADD will override the default value with it's +own. META_MERGE will merge its value with the default. + +Unless you want to override the defaults, prefer META_MERGE so as to +get the advantage of any future defaults. + +=item MIN_PERL_VERSION + +The minimum required version of Perl for this distribution. + +Either 5.006001 or 5.6.1 format is acceptable. + +=item MYEXTLIB + +If the extension links to a library that it builds set this to the +name of the library (see SDBM_File) + +=item NAME + +Perl module name for this extension (DBD::Oracle). This will default +to the directory name but should be explicitly defined in the +Makefile.PL. + +=item NEEDS_LINKING + +MakeMaker will figure out if an extension contains linkable code +anywhere down the directory tree, and will set this variable +accordingly, but you can speed it up a very little bit if you define +this boolean variable yourself. + +=item NOECHO + +Command so make does not print the literal commands its running. + +By setting it to an empty string you can generate a Makefile that +prints all commands. Mainly used in debugging MakeMaker itself. + +Defaults to C<@>. + +=item NORECURS + +Boolean. Attribute to inhibit descending into subdirectories. + +=item NO_META + +When true, suppresses the generation and addition to the MANIFEST of +the META.yml module meta-data file during 'make distdir'. + +Defaults to false. + +=item NO_VC + +In general, any generated Makefile checks for the current version of +MakeMaker and the version the Makefile was built under. If NO_VC is +set, the version check is neglected. Do not write this into your +Makefile.PL, use it interactively instead. + +=item OBJECT + +List of object files, defaults to '$(BASEEXT)$(OBJ_EXT)', but can be a long +string containing all object files, e.g. "tkpBind.o +tkpButton.o tkpCanvas.o" + +(Where BASEEXT is the last component of NAME, and OBJ_EXT is $Config{obj_ext}.) + +=item OPTIMIZE + +Defaults to C<-O>. Set it to C<-g> to turn debugging on. The flag is +passed to subdirectory makes. + +=item PERL + +Perl binary for tasks that can be done by miniperl + +=item PERL_CORE + +Set only when MakeMaker is building the extensions of the Perl core +distribution. + +=item PERLMAINCC + +The call to the program that is able to compile perlmain.c. Defaults +to $(CC). + +=item PERL_ARCHLIB + +Same as for PERL_LIB, but for architecture dependent files. + +Used only when MakeMaker is building the extensions of the Perl core +distribution (because normally $(PERL_ARCHLIB) is automatically in @INC, +and adding it would get in the way of PERL5LIB). + +=item PERL_LIB + +Directory containing the Perl library to use. + +Used only when MakeMaker is building the extensions of the Perl core +distribution (because normally $(PERL_LIB) is automatically in @INC, +and adding it would get in the way of PERL5LIB). + +=item PERL_MALLOC_OK + +defaults to 0. Should be set to TRUE if the extension can work with +the memory allocation routines substituted by the Perl malloc() subsystem. +This should be applicable to most extensions with exceptions of those + +=over 4 + +=item * + +with bugs in memory allocations which are caught by Perl's malloc(); + +=item * + +which interact with the memory allocator in other ways than via +malloc(), realloc(), free(), calloc(), sbrk() and brk(); + +=item * + +which rely on special alignment which is not provided by Perl's malloc(). + +=back + +B<NOTE.> Negligence to set this flag in I<any one> of loaded extension +nullifies many advantages of Perl's malloc(), such as better usage of +system resources, error detection, memory usage reporting, catchable failure +of memory allocations, etc. + +=item PERLPREFIX + +Directory under which core modules are to be installed. + +Defaults to $Config{installprefixexp} falling back to +$Config{installprefix}, $Config{prefixexp} or $Config{prefix} should +$Config{installprefixexp} not exist. + +Overridden by PREFIX. + +=item PERLRUN + +Use this instead of $(PERL) when you wish to run perl. It will set up +extra necessary flags for you. + +=item PERLRUNINST + +Use this instead of $(PERL) when you wish to run perl to work with +modules. It will add things like -I$(INST_ARCH) and other necessary +flags so perl can see the modules you're about to install. + +=item PERL_SRC + +Directory containing the Perl source code (use of this should be +avoided, it may be undefined) + +=item PERM_DIR + +Desired permission for directories. Defaults to C<755>. + +=item PERM_RW + +Desired permission for read/writable files. Defaults to C<644>. + +=item PERM_RWX + +Desired permission for executable files. Defaults to C<755>. + +=item PL_FILES + +MakeMaker can run programs to generate files for you at build time. +By default any file named *.PL (except Makefile.PL and Build.PL) in +the top level directory will be assumed to be a Perl program and run +passing its own basename in as an argument. For example... + + perl foo.PL foo + +This behavior can be overridden by supplying your own set of files to +search. PL_FILES accepts a hash ref, the key being the file to run +and the value is passed in as the first argument when the PL file is run. + + PL_FILES => {'bin/foobar.PL' => 'bin/foobar'} + +Would run bin/foobar.PL like this: + + perl bin/foobar.PL bin/foobar + +If multiple files from one program are desired an array ref can be used. + + PL_FILES => {'bin/foobar.PL' => [qw(bin/foobar1 bin/foobar2)]} + +In this case the program will be run multiple times using each target file. + + perl bin/foobar.PL bin/foobar1 + perl bin/foobar.PL bin/foobar2 + +PL files are normally run B<after> pm_to_blib and include INST_LIB and +INST_ARCH in its C<@INC> so the just built modules can be +accessed... unless the PL file is making a module (or anything else in +PM) in which case it is run B<before> pm_to_blib and does not include +INST_LIB and INST_ARCH in its C<@INC>. This apparently odd behavior +is there for backwards compatibility (and its somewhat DWIM). + + +=item PM + +Hashref of .pm files and *.pl files to be installed. e.g. + + {'name_of_file.pm' => '$(INST_LIBDIR)/install_as.pm'} + +By default this will include *.pm and *.pl and the files found in +the PMLIBDIRS directories. Defining PM in the +Makefile.PL will override PMLIBDIRS. + +=item PMLIBDIRS + +Ref to array of subdirectories containing library files. Defaults to +[ 'lib', $(BASEEXT) ]. The directories will be scanned and I<any> files +they contain will be installed in the corresponding location in the +library. A libscan() method can be used to alter the behaviour. +Defining PM in the Makefile.PL will override PMLIBDIRS. + +(Where BASEEXT is the last component of NAME.) + +=item PM_FILTER + +A filter program, in the traditional Unix sense (input from stdin, output +to stdout) that is passed on each .pm file during the build (in the +pm_to_blib() phase). It is empty by default, meaning no filtering is done. + +Great care is necessary when defining the command if quoting needs to be +done. For instance, you would need to say: + + {'PM_FILTER' => 'grep -v \\"^\\#\\"'} + +to remove all the leading comments on the fly during the build. The +extra \\ are necessary, unfortunately, because this variable is interpolated +within the context of a Perl program built on the command line, and double +quotes are what is used with the -e switch to build that command line. The +# is escaped for the Makefile, since what is going to be generated will then +be: + + PM_FILTER = grep -v \"^\#\" + +Without the \\ before the #, we'd have the start of a Makefile comment, +and the macro would be incorrectly defined. + +=item POLLUTE + +Release 5.005 grandfathered old global symbol names by providing preprocessor +macros for extension source compatibility. As of release 5.6, these +preprocessor definitions are not available by default. The POLLUTE flag +specifies that the old names should still be defined: + + perl Makefile.PL POLLUTE=1 + +Please inform the module author if this is necessary to successfully install +a module under 5.6 or later. + +=item PPM_INSTALL_EXEC + +Name of the executable used to run C<PPM_INSTALL_SCRIPT> below. (e.g. perl) + +=item PPM_INSTALL_SCRIPT + +Name of the script that gets executed by the Perl Package Manager after +the installation of a package. + +=item PREFIX + +This overrides all the default install locations. Man pages, +libraries, scripts, etc... MakeMaker will try to make an educated +guess about where to place things under the new PREFIX based on your +Config defaults. Failing that, it will fall back to a structure +which should be sensible for your platform. + +If you specify LIB or any INSTALL* variables they will not be effected +by the PREFIX. + +=item PREREQ_FATAL + +Bool. If this parameter is true, failing to have the required modules +(or the right versions thereof) will be fatal. C<perl Makefile.PL> +will C<die> instead of simply informing the user of the missing dependencies. + +It is I<extremely> rare to have to use C<PREREQ_FATAL>. Its use by module +authors is I<strongly discouraged> and should never be used lightly. +Module installation tools have ways of resolving umet dependencies but +to do that they need a F<Makefile>. Using C<PREREQ_FATAL> breaks this. +That's bad. + +The only situation where it is appropriate is when you have +dependencies that are indispensible to actually I<write> a +F<Makefile>. For example, MakeMaker's F<Makefile.PL> needs L<File::Spec>. +If its not available it cannot write the F<Makefile>. + +Note: see L<Test::Harness> for a shortcut for stopping tests early +if you are missing dependencies and are afraid that users might +use your module with an incomplete environment. + +=item PREREQ_PM + +A hash of modules that are needed to run your module. The keys are +the module names ie. Test::More, and the minimum version is the +value. If the required version number is 0 any version will do. + +This will go into the C<requires> field of your F<META.yml>. + + PREREQ_PM => { + # Require Test::More at least 0.47 + "Test::More" => "0.47", + + # Require any version of Acme::Buffy + "Acme::Buffy" => 0, + } + +=item PREREQ_PRINT + +Bool. If this parameter is true, the prerequisites will be printed to +stdout and MakeMaker will exit. The output format is an evalable hash +ref. + + $PREREQ_PM = { + 'A::B' => Vers1, + 'C::D' => Vers2, + ... + }; + +If a distribution defines a minimal required perl version, this is +added to the output as an additional line of the form: + + $MIN_PERL_VERSION = '5.008001'; + +If BUILD_REQUIRES is not empty, it will be dumped as $BUILD_REQUIRES hasref. + +=item PRINT_PREREQ + +RedHatism for C<PREREQ_PRINT>. The output format is different, though: + + perl(A::B)>=Vers1 perl(C::D)>=Vers2 ... + +A minimal required perl version, if present, will look like this: + + perl(perl)>=5.008001 + +=item SITEPREFIX + +Like PERLPREFIX, but only for the site install locations. + +Defaults to $Config{siteprefixexp}. Perls prior to 5.6.0 didn't have +an explicit siteprefix in the Config. In those cases +$Config{installprefix} will be used. + +Overridable by PREFIX + +=item SIGN + +When true, perform the generation and addition to the MANIFEST of the +SIGNATURE file in the distdir during 'make distdir', via 'cpansign +-s'. + +Note that you need to install the Module::Signature module to +perform this operation. + +Defaults to false. + +=item SKIP + +Arrayref. E.g. [qw(name1 name2)] skip (do not write) sections of the +Makefile. Caution! Do not use the SKIP attribute for the negligible +speedup. It may seriously damage the resulting Makefile. Only use it +if you really need it. + +=item TYPEMAPS + +Ref to array of typemap file names. Use this when the typemaps are +in some directory other than the current directory or when they are +not named B<typemap>. The last typemap in the list takes +precedence. A typemap in the current directory has highest +precedence, even if it isn't listed in TYPEMAPS. The default system +typemap has lowest precedence. + +=item VENDORPREFIX + +Like PERLPREFIX, but only for the vendor install locations. + +Defaults to $Config{vendorprefixexp}. + +Overridable by PREFIX + +=item VERBINST + +If true, make install will be verbose + +=item VERSION + +Your version number for distributing the package. This defaults to +0.1. + +=item VERSION_FROM + +Instead of specifying the VERSION in the Makefile.PL you can let +MakeMaker parse a file to determine the version number. The parsing +routine requires that the file named by VERSION_FROM contains one +single line to compute the version number. The first line in the file +that contains something like a $VERSION assignment or C<package Name +VERSION> will be used. The following lines will be parsed o.k.: + + # Good + package Foo::Bar 1.23; # 1.23 + $VERSION = '1.00'; # 1.00 + *VERSION = \'1.01'; # 1.01 + ($VERSION) = q$Revision$ =~ /(\d+)/g; # The digits in $Revision$ + $FOO::VERSION = '1.10'; # 1.10 + *FOO::VERSION = \'1.11'; # 1.11 + +but these will fail: + + # Bad + my $VERSION = '1.01'; + local $VERSION = '1.02'; + local $FOO::VERSION = '1.30'; + +"Version strings" are incompatible should not be used. + + # Bad + $VERSION = 1.2.3; + $VERSION = v1.2.3; + +L<version> objects are fine. As of MakeMaker 6.35 version.pm will be +automatically loaded, but you must declare the dependency on version.pm. +For compatibility with older MakeMaker you should load on the same line +as $VERSION is declared. + + # All on one line + use version; our $VERSION = qv(1.2.3); + +(Putting C<my> or C<local> on the preceding line will work o.k.) + +The file named in VERSION_FROM is not added as a dependency to +Makefile. This is not really correct, but it would be a major pain +during development to have to rewrite the Makefile for any smallish +change in that file. If you want to make sure that the Makefile +contains the correct VERSION macro after any change of the file, you +would have to do something like + + depend => { Makefile => '$(VERSION_FROM)' } + +See attribute C<depend> below. + +=item VERSION_SYM + +A sanitized VERSION with . replaced by _. For places where . has +special meaning (some filesystems, RCS labels, etc...) + +=item XS + +Hashref of .xs files. MakeMaker will default this. e.g. + + {'name_of_file.xs' => 'name_of_file.c'} + +The .c files will automatically be included in the list of files +deleted by a make clean. + +=item XSOPT + +String of options to pass to xsubpp. This might include C<-C++> or +C<-extern>. Do not include typemaps here; the TYPEMAP parameter exists for +that purpose. + +=item XSPROTOARG + +May be set to an empty string, which is identical to C<-prototypes>, or +C<-noprototypes>. See the xsubpp documentation for details. MakeMaker +defaults to the empty string. + +=item XS_VERSION + +Your version number for the .xs file of this package. This defaults +to the value of the VERSION attribute. + +=back + +=head2 Additional lowercase attributes + +can be used to pass parameters to the methods which implement that +part of the Makefile. Parameters are specified as a hash ref but are +passed to the method as a hash. + +=over 2 + +=item clean + + {FILES => "*.xyz foo"} + +=item depend + + {ANY_TARGET => ANY_DEPENDENCY, ...} + +(ANY_TARGET must not be given a double-colon rule by MakeMaker.) + +=item dist + + {TARFLAGS => 'cvfF', COMPRESS => 'gzip', SUFFIX => '.gz', + SHAR => 'shar -m', DIST_CP => 'ln', ZIP => '/bin/zip', + ZIPFLAGS => '-rl', DIST_DEFAULT => 'private tardist' } + +If you specify COMPRESS, then SUFFIX should also be altered, as it is +needed to tell make the target file of the compression. Setting +DIST_CP to ln can be useful, if you need to preserve the timestamps on +your files. DIST_CP can take the values 'cp', which copies the file, +'ln', which links the file, and 'best' which copies symbolic links and +links the rest. Default is 'best'. + +=item dynamic_lib + + {ARMAYBE => 'ar', OTHERLDFLAGS => '...', INST_DYNAMIC_DEP => '...'} + +=item linkext + + {LINKTYPE => 'static', 'dynamic' or ''} + +NB: Extensions that have nothing but *.pm files had to say + + {LINKTYPE => ''} + +with Pre-5.0 MakeMakers. Since version 5.00 of MakeMaker such a line +can be deleted safely. MakeMaker recognizes when there's nothing to +be linked. + +=item macro + + {ANY_MACRO => ANY_VALUE, ...} + +=item postamble + +Anything put here will be passed to MY::postamble() if you have one. + +=item realclean + + {FILES => '$(INST_ARCHAUTODIR)/*.xyz'} + +=item test + + {TESTS => 't/*.t'} + +=item tool_autosplit + + {MAXLEN => 8} + +=back + +=head2 Overriding MakeMaker Methods + +If you cannot achieve the desired Makefile behaviour by specifying +attributes you may define private subroutines in the Makefile.PL. +Each subroutine returns the text it wishes to have written to +the Makefile. To override a section of the Makefile you can +either say: + + sub MY::c_o { "new literal text" } + +or you can edit the default by saying something like: + + package MY; # so that "SUPER" works right + sub c_o { + my $inherited = shift->SUPER::c_o(@_); + $inherited =~ s/old text/new text/; + $inherited; + } + +If you are running experiments with embedding perl as a library into +other applications, you might find MakeMaker is not sufficient. You'd +better have a look at ExtUtils::Embed which is a collection of utilities +for embedding. + +If you still need a different solution, try to develop another +subroutine that fits your needs and submit the diffs to +C<makemaker@perl.org> + +For a complete description of all MakeMaker methods see +L<ExtUtils::MM_Unix>. + +Here is a simple example of how to add a new target to the generated +Makefile: + + sub MY::postamble { + return <<'MAKE_FRAG'; + $(MYEXTLIB): sdbm/Makefile + cd sdbm && $(MAKE) all + + MAKE_FRAG + } + +=head2 The End Of Cargo Cult Programming + +WriteMakefile() now does some basic sanity checks on its parameters to +protect against typos and malformatted values. This means some things +which happened to work in the past will now throw warnings and +possibly produce internal errors. + +Some of the most common mistakes: + +=over 2 + +=item C<< MAN3PODS => ' ' >> + +This is commonly used to suppress the creation of man pages. MAN3PODS +takes a hash ref not a string, but the above worked by accident in old +versions of MakeMaker. + +The correct code is C<< MAN3PODS => { } >>. + +=back + + +=head2 Hintsfile support + +MakeMaker.pm uses the architecture specific information from +Config.pm. In addition it evaluates architecture specific hints files +in a C<hints/> directory. The hints files are expected to be named +like their counterparts in C<PERL_SRC/hints>, but with an C<.pl> file +name extension (eg. C<next_3_2.pl>). They are simply C<eval>ed by +MakeMaker within the WriteMakefile() subroutine, and can be used to +execute commands as well as to include special variables. The rules +which hintsfile is chosen are the same as in Configure. + +The hintsfile is eval()ed immediately after the arguments given to +WriteMakefile are stuffed into a hash reference $self but before this +reference becomes blessed. So if you want to do the equivalent to +override or create an attribute you would say something like + + $self->{LIBS} = ['-ldbm -lucb -lc']; + +=head2 Distribution Support + +For authors of extensions MakeMaker provides several Makefile +targets. Most of the support comes from the ExtUtils::Manifest module, +where additional documentation can be found. + +=over 4 + +=item make distcheck + +reports which files are below the build directory but not in the +MANIFEST file and vice versa. (See ExtUtils::Manifest::fullcheck() for +details) + +=item make skipcheck + +reports which files are skipped due to the entries in the +C<MANIFEST.SKIP> file (See ExtUtils::Manifest::skipcheck() for +details) + +=item make distclean + +does a realclean first and then the distcheck. Note that this is not +needed to build a new distribution as long as you are sure that the +MANIFEST file is ok. + +=item make manifest + +rewrites the MANIFEST file, adding all remaining files found (See +ExtUtils::Manifest::mkmanifest() for details) + +=item make distdir + +Copies all the files that are in the MANIFEST file to a newly created +directory with the name C<$(DISTNAME)-$(VERSION)>. If that directory +exists, it will be removed first. + +Additionally, it will create a META.yml module meta-data file in the +distdir and add this to the distdir's MANIFEST. You can shut this +behavior off with the NO_META flag. + +=item make disttest + +Makes a distdir first, and runs a C<perl Makefile.PL>, a make, and +a make test in that directory. + +=item make tardist + +First does a distdir. Then a command $(PREOP) which defaults to a null +command, followed by $(TO_UNIX), which defaults to a null command under +UNIX, and will convert files in distribution directory to UNIX format +otherwise. Next it runs C<tar> on that directory into a tarfile and +deletes the directory. Finishes with a command $(POSTOP) which +defaults to a null command. + +=item make dist + +Defaults to $(DIST_DEFAULT) which in turn defaults to tardist. + +=item make uutardist + +Runs a tardist first and uuencodes the tarfile. + +=item make shdist + +First does a distdir. Then a command $(PREOP) which defaults to a null +command. Next it runs C<shar> on that directory into a sharfile and +deletes the intermediate directory again. Finishes with a command +$(POSTOP) which defaults to a null command. Note: For shdist to work +properly a C<shar> program that can handle directories is mandatory. + +=item make zipdist + +First does a distdir. Then a command $(PREOP) which defaults to a null +command. Runs C<$(ZIP) $(ZIPFLAGS)> on that directory into a +zipfile. Then deletes that directory. Finishes with a command +$(POSTOP) which defaults to a null command. + +=item make ci + +Does a $(CI) and a $(RCS_LABEL) on all files in the MANIFEST file. + +=back + +Customization of the dist targets can be done by specifying a hash +reference to the dist attribute of the WriteMakefile call. The +following parameters are recognized: + + CI ('ci -u') + COMPRESS ('gzip --best') + POSTOP ('@ :') + PREOP ('@ :') + TO_UNIX (depends on the system) + RCS_LABEL ('rcs -q -Nv$(VERSION_SYM):') + SHAR ('shar') + SUFFIX ('.gz') + TAR ('tar') + TARFLAGS ('cvf') + ZIP ('zip') + ZIPFLAGS ('-r') + +An example: + + WriteMakefile( + ...other options... + dist => { + COMPRESS => "bzip2", + SUFFIX => ".bz2" + } + ); + + +=head2 Module Meta-Data + +Long plaguing users of MakeMaker based modules has been the problem of +getting basic information about the module out of the sources +I<without> running the F<Makefile.PL> and doing a bunch of messy +heuristics on the resulting F<Makefile>. To this end a simple module +meta-data file has been introduced, F<META.yml>. + +F<META.yml> is a YAML document (see http://www.yaml.org) containing +basic information about the module (name, version, prerequisites...) +in an easy to read format. The format is developed and defined by the +Module::Build developers (see +http://module-build.sourceforge.net/META-spec.html) + +MakeMaker will automatically generate a F<META.yml> file for you and +add it to your F<MANIFEST> as part of the 'distdir' target (and thus +the 'dist' target). This is intended to seamlessly and rapidly +populate CPAN with module meta-data. If you wish to shut this feature +off, set the C<NO_META> C<WriteMakefile()> flag to true. + + +=head2 Disabling an extension + +If some events detected in F<Makefile.PL> imply that there is no way +to create the Module, but this is a normal state of things, then you +can create a F<Makefile> which does nothing, but succeeds on all the +"usual" build targets. To do so, use + + use ExtUtils::MakeMaker qw(WriteEmptyMakefile); + WriteEmptyMakefile(); + +instead of WriteMakefile(). + +This may be useful if other modules expect this module to be I<built> +OK, as opposed to I<work> OK (say, this system-dependent module builds +in a subdirectory of some other distribution, or is listed as a +dependency in a CPAN::Bundle, but the functionality is supported by +different means on the current architecture). + +=head2 Other Handy Functions + +=over 4 + +=item prompt + + my $value = prompt($message); + my $value = prompt($message, $default); + +The C<prompt()> function provides an easy way to request user input +used to write a makefile. It displays the $message as a prompt for +input. If a $default is provided it will be used as a default. The +function returns the $value selected by the user. + +If C<prompt()> detects that it is not running interactively and there +is nothing on STDIN or if the PERL_MM_USE_DEFAULT environment variable +is set to true, the $default will be used without prompting. This +prevents automated processes from blocking on user input. + +If no $default is provided an empty string will be used instead. + +=back + + +=head1 ENVIRONMENT + +=over 4 + +=item PERL_MM_OPT + +Command line options used by C<MakeMaker-E<gt>new()>, and thus by +C<WriteMakefile()>. The string is split on whitespace, and the result +is processed before any actual command line arguments are processed. + +=item PERL_MM_USE_DEFAULT + +If set to a true value then MakeMaker's prompt function will +always return the default without waiting for user input. + +=item PERL_CORE + +Same as the PERL_CORE parameter. The parameter overrides this. + +=back + +=head1 SEE ALSO + +L<Module::Build> is a pure-Perl alternative to MakeMaker which does +not rely on make or any other external utility. It is easier to +extend to suit your needs. + +L<Module::Install> is a wrapper around MakeMaker which adds features +not normally available. + +L<ExtUtils::ModuleMaker> and L<Module::Starter> are both modules to +help you setup your distribution. + +=head1 AUTHORS + +Andy Dougherty C<doughera@lafayette.edu>, Andreas KE<ouml>nig +C<andreas.koenig@mind.de>, Tim Bunce C<timb@cpan.org>. VMS +support by Charles Bailey C<bailey@newman.upenn.edu>. OS/2 support +by Ilya Zakharevich C<ilya@math.ohio-state.edu>. + +Currently maintained by Michael G Schwern C<schwern@pobox.com> + +Send patches and ideas to C<makemaker@perl.org>. + +Send bug reports via http://rt.cpan.org/. Please send your +generated Makefile along with your report. + +For more up-to-date information, see L<http://www.makemaker.org>. + +=head1 LICENSE + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +See L<http://www.perl.com/perl/misc/Artistic.html> + + +=cut diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MakeMaker/Config.pm b/Master/tlpkg/tlperl/lib/ExtUtils/MakeMaker/Config.pm new file mode 100644 index 00000000000..38b60affdda --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MakeMaker/Config.pm @@ -0,0 +1,39 @@ +package ExtUtils::MakeMaker::Config; + +use strict; + +our $VERSION = '6.56'; + +use Config (); + +# Give us an overridable config. +our %Config = %Config::Config; + +sub import { + my $caller = caller; + + no strict 'refs'; ## no critic + *{$caller.'::Config'} = \%Config; +} + +1; + + +=head1 NAME + +ExtUtils::MakeMaker::Config - Wrapper around Config.pm + + +=head1 SYNOPSIS + + use ExtUtils::MakeMaker::Config; + print $Config{installbin}; # or whatever + + +=head1 DESCRIPTION + +B<FOR INTERNAL USE ONLY> + +A very thin wrapper around Config.pm so MakeMaker is easier to test. + +=cut diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MakeMaker/FAQ.pod b/Master/tlpkg/tlperl/lib/ExtUtils/MakeMaker/FAQ.pod new file mode 100644 index 00000000000..d33f82e53b9 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MakeMaker/FAQ.pod @@ -0,0 +1,431 @@ +package ExtUtils::MakeMaker::FAQ; + +our $VERSION = '1.12'; + +1; +__END__ + +=head1 NAME + +ExtUtils::MakeMaker::FAQ - Frequently Asked Questions About MakeMaker + +=head1 DESCRIPTION + +FAQs, tricks and tips for C<ExtUtils::MakeMaker>. + + +=head2 Module Installation + +=over 4 + +=item How do I install a module into my home directory? + +If you're not the Perl administrator you probably don't have +permission to install a module to its default location. Then you +should install it for your own use into your home directory like so: + + # Non-unix folks, replace ~ with /path/to/your/home/dir + perl Makefile.PL INSTALL_BASE=~ + +This will put modules into F<~/lib/perl5>, man pages into F<~/man> and +programs into F<~/bin>. + +To ensure your Perl programs can see these newly installed modules, +set your C<PERL5LIB> environment variable to F<~/lib/perl5> or tell +each of your programs to look in that directory with the following: + + use lib "$ENV{HOME}/lib/perl5"; + +or if $ENV{HOME} isn't set and you don't want to set it for some +reason, do it the long way. + + use lib "/path/to/your/home/dir/lib/perl5"; + + +=item How do I get MakeMaker and Module::Build to install to the same place? + +Module::Build, as of 0.28, supports two ways to install to the same +location as MakeMaker. + +1) Use INSTALL_BASE / C<--install_base> + +MakeMaker (as of 6.31) and Module::Build (as of 0.28) both can install +to the same locations using the "install_base" concept. See +L<ExtUtils::MakeMaker/INSTALL_BASE> for details. To get MM and MB to +install to the same location simply set INSTALL_BASE in MM and +C<--install_base> in MB to the same location. + + perl Makefile.PL INSTALL_BASE=/whatever + perl Build.PL --install_base /whatever + +2) Use PREFIX / C<--prefix> + +Module::Build 0.28 added support for C<--prefix> which works like +MakeMaker's PREFIX. + + perl Makefile.PL PREFIX=/whatever + perl Build.PL --prefix /whatever + + +=item How do I keep from installing man pages? + +Recent versions of MakeMaker will only install man pages on Unix like +operating systems. + +For an individual module: + + perl Makefile.PL INSTALLMAN1DIR=none INSTALLMAN3DIR=none + +If you want to suppress man page installation for all modules you have +to reconfigure Perl and tell it 'none' when it asks where to install +man pages. + + +=item How do I use a module without installing it? + +Two ways. One is to build the module normally... + + perl Makefile.PL + make + make test + +...and then set the PERL5LIB environment variable to point at the +blib/lib and blib/arch directories. + +The other is to install the module in a temporary location. + + perl Makefile.PL INSTALL_BASE=~/tmp + make + make test + make install + +And then set PERL5LIB to F<~/tmp/lib/perl5>. This works well when you +have multiple modules to work with. It also ensures that the module +goes through its full installation process which may modify it. + +=item PREFIX vs INSTALL_BASE from Module::Build::Cookbook + +The behavior of PREFIX is complicated and depends closely on how your +Perl is configured. The resulting installation locations will vary from +machine to machine and even different installations of Perl on the same machine. +Because of this, its difficult to document where prefix will place your modules. + +In contrast, INSTALL_BASE has predictable, easy to explain installation locations. +Now that Module::Build and MakeMaker both have INSTALL_BASE there is little reason +to use PREFIX other than to preserve your existing installation locations. If you +are starting a fresh Perl installation we encourage you to use INSTALL_BASE. If +you have an existing installation installed via PREFIX, consider moving it to an +installation structure matching INSTALL_BASE and using that instead. + +=back + + +=head2 Philosophy and History + +=over 4 + +=item Why not just use <insert other build config tool here>? + +Why did MakeMaker reinvent the build configuration wheel? Why not +just use autoconf or automake or ppm or Ant or ... + +There are many reasons, but the major one is cross-platform +compatibility. + +Perl is one of the most ported pieces of software ever. It works on +operating systems I've never even heard of (see perlport for details). +It needs a build tool that can work on all those platforms and with +any wacky C compilers and linkers they might have. + +No such build tool exists. Even make itself has wildly different +dialects. So we have to build our own. + + +=item What is Module::Build and how does it relate to MakeMaker? + +Module::Build is a project by Ken Williams to supplant MakeMaker. +Its primary advantages are: + +=over 8 + +=item * pure perl. no make, no shell commands + +=item * easier to customize + +=item * cleaner internals + +=item * less cruft + +=back + +Module::Build is the official heir apparent to MakeMaker and we +encourage people to work on M::B rather than spending time adding features +to MakeMaker. + +=back + + +=head2 Module Writing + +=over 4 + +=item How do I keep my $VERSION up to date without resetting it manually? + +Often you want to manually set the $VERSION in the main module +distribution because this is the version that everybody sees on CPAN +and maybe you want to customize it a bit. But for all the other +modules in your dist, $VERSION is really just bookkeeping and all that's +important is it goes up every time the module is changed. Doing this +by hand is a pain and you often forget. + +Simplest way to do it automatically is to use your version control +system's revision number (you are using version control, right?). + +In CVS, RCS and SVN you use $Revision$ (see the documentation of your +version control system for details). Every time the file is checked +in the $Revision$ will be updated, updating your $VERSION. + +SVN uses a simple integer for $Revision$ so you can adapt it for your +$VERSION like so: + + ($VERSION) = q$Revision$ =~ /(\d+)/; + +In CVS and RCS version 1.9 is followed by 1.10. Since CPAN compares +version numbers numerically we use a sprintf() to convert 1.9 to 1.009 +and 1.10 to 1.010 which compare properly. + + $VERSION = sprintf "%d.%03d", q$Revision$ =~ /(\d+)\.(\d+)/g; + +If branches are involved (ie. $Revision: 1.5.3.4$) its a little more +complicated. + + # must be all on one line or MakeMaker will get confused. + $VERSION = do { my @r = (q$Revision$ =~ /\d+/g); sprintf "%d."."%03d" x $#r, @r }; + +In SVN, $Revision$ should be the same for every file in the project so +they would all have the same $VERSION. CVS and RCS have a different +$Revision$ per file so each file will have a differnt $VERSION. +Distributed version control systems, such as SVK, may have a different +$Revision$ based on who checks out the file leading to a different $VERSION +on each machine! Finally, some distributed version control systems, such +as darcs, have no concept of revision number at all. + + +=item What's this F<META.yml> thing and how did it get in my F<MANIFEST>?! + +F<META.yml> is a module meta-data file pioneered by Module::Build and +automatically generated as part of the 'distdir' target (and thus +'dist'). See L<ExtUtils::MakeMaker/"Module Meta-Data">. + +To shut off its generation, pass the C<NO_META> flag to C<WriteMakefile()>. + + +=item How do I delete everything not in my F<MANIFEST>? + +Some folks are surpried that C<make distclean> does not delete +everything not listed in their MANIFEST (thus making a clean +distribution) but only tells them what they need to delete. This is +done because it is considered too dangerous. While developing your +module you might write a new file, not add it to the MANIFEST, then +run a C<distclean> and be sad because your new work was deleted. + +If you really want to do this, you can use +C<ExtUtils::Manifest::manifind()> to read the MANIFEST and File::Find +to delete the files. But you have to be careful. Here's a script to +do that. Use at your own risk. Have fun blowing holes in your foot. + + #!/usr/bin/perl -w + + use strict; + + use File::Spec; + use File::Find; + use ExtUtils::Manifest qw(maniread); + + my %manifest = map {( $_ => 1 )} + grep { File::Spec->canonpath($_) } + keys %{ maniread() }; + + if( !keys %manifest ) { + print "No files found in MANIFEST. Stopping.\n"; + exit; + } + + find({ + wanted => sub { + my $path = File::Spec->canonpath($_); + + return unless -f $path; + return if exists $manifest{ $path }; + + print "unlink $path\n"; + unlink $path; + }, + no_chdir => 1 + }, + "." + ); + + +=item Which zip should I use on Windows for '[nd]make zipdist'? + +We recommend InfoZIP: L<http://www.info-zip.org/Zip.html> + + +=back + +=head2 XS + +=over 4 + +=item How to I prevent "object version X.XX does not match bootstrap parameter Y.YY" errors? + +XS code is very sensitive to the module version number and will +complain if the version number in your Perl module doesn't match. If +you change your module's version # without rerunning Makefile.PL the old +version number will remain in the Makefile causing the XS code to be built +with the wrong number. + +To avoid this, you can force the Makefile to be rebuilt whenever you +change the module containing the version number by adding this to your +WriteMakefile() arguments. + + depend => { '$(FIRST_MAKEFILE)' => '$(VERSION_FROM)' } + + +=item How do I make two or more XS files coexist in the same directory? + +Sometimes you need to have two and more XS files in the same package. +One way to go is to put them into separate directories, but sometimes +this is not the most suitable solution. The following technique allows +you to put two (and more) XS files in the same directory. + +Let's assume that we have a package C<Cool::Foo>, which includes +C<Cool::Foo> and C<Cool::Bar> modules each having a separate XS +file. First we use the following I<Makefile.PL>: + + use ExtUtils::MakeMaker; + + WriteMakefile( + NAME => 'Cool::Foo', + VERSION_FROM => 'Foo.pm', + OBJECT => q/$(O_FILES)/, + # ... other attrs ... + ); + +Notice the C<OBJECT> attribute. MakeMaker generates the following +variables in I<Makefile>: + + # Handy lists of source code files: + XS_FILES= Bar.xs \ + Foo.xs + C_FILES = Bar.c \ + Foo.c + O_FILES = Bar.o \ + Foo.o + +Therefore we can use the C<O_FILES> variable to tell MakeMaker to use +these objects into the shared library. + +That's pretty much it. Now write I<Foo.pm> and I<Foo.xs>, I<Bar.pm> +and I<Bar.xs>, where I<Foo.pm> bootstraps the shared library and +I<Bar.pm> simply loading I<Foo.pm>. + +The only issue left is to how to bootstrap I<Bar.xs>. This is done +from I<Foo.xs>: + + MODULE = Cool::Foo PACKAGE = Cool::Foo + + BOOT: + # boot the second XS file + boot_Cool__Bar(aTHX_ cv); + +If you have more than two files, this is the place where you should +boot extra XS files from. + +The following four files sum up all the details discussed so far. + + Foo.pm: + ------- + package Cool::Foo; + + require DynaLoader; + + our @ISA = qw(DynaLoader); + our $VERSION = '0.01'; + bootstrap Cool::Foo $VERSION; + + 1; + + Bar.pm: + ------- + package Cool::Bar; + + use Cool::Foo; # bootstraps Bar.xs + + 1; + + Foo.xs: + ------- + #include "EXTERN.h" + #include "perl.h" + #include "XSUB.h" + + MODULE = Cool::Foo PACKAGE = Cool::Foo + + BOOT: + # boot the second XS file + boot_Cool__Bar(aTHX_ cv); + + MODULE = Cool::Foo PACKAGE = Cool::Foo PREFIX = cool_foo_ + + void + cool_foo_perl_rules() + + CODE: + fprintf(stderr, "Cool::Foo says: Perl Rules\n"); + + Bar.xs: + ------- + #include "EXTERN.h" + #include "perl.h" + #include "XSUB.h" + + MODULE = Cool::Bar PACKAGE = Cool::Bar PREFIX = cool_bar_ + + void + cool_bar_perl_rules() + + CODE: + fprintf(stderr, "Cool::Bar says: Perl Rules\n"); + +And of course a very basic test: + + t/cool.t: + -------- + use Test; + BEGIN { plan tests => 1 }; + use Cool::Foo; + use Cool::Bar; + Cool::Foo::perl_rules(); + Cool::Bar::perl_rules(); + ok 1; + +This tip has been brought to you by Nick Ing-Simmons and Stas Bekman. + +=back + +=head1 PATCHING + +If you have a question you'd like to see added to the FAQ (whether or +not you have the answer) please send it to makemaker@perl.org. + +=head1 AUTHOR + +The denizens of makemaker@perl.org. + +=head1 SEE ALSO + +L<ExtUtils::MakeMaker> + +=cut diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/MakeMaker/Tutorial.pod b/Master/tlpkg/tlperl/lib/ExtUtils/MakeMaker/Tutorial.pod new file mode 100644 index 00000000000..8ad72649b1a --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/MakeMaker/Tutorial.pod @@ -0,0 +1,180 @@ +package ExtUtils::MakeMaker::Tutorial; + +our $VERSION = 0.02; + + +=head1 NAME + +ExtUtils::MakeMaker::Tutorial - Writing a module with MakeMaker + +=head1 SYNOPSIS + + use ExtUtils::MakeMaker; + + WriteMakefile( + NAME => 'Your::Module', + VERSION_FROM => 'lib/Your/Module.pm' + ); + +=head1 DESCRIPTION + +This is a short tutorial on writing a simple module with MakeMaker. +Its really not that hard. + + +=head2 The Mantra + +MakeMaker modules are installed using this simple mantra + + perl Makefile.PL + make + make test + make install + +There are lots more commands and options, but the above will do it. + + +=head2 The Layout + +The basic files in a module look something like this. + + Makefile.PL + MANIFEST + lib/Your/Module.pm + +That's all that's strictly necessary. There's additional files you might +want: + + lib/Your/Other/Module.pm + t/some_test.t + t/some_other_test.t + Changes + README + INSTALL + MANIFEST.SKIP + bin/some_program + +=over 4 + +=item Makefile.PL + +When you run Makefile.PL, it makes a Makefile. That's the whole point of +MakeMaker. The Makefile.PL is a simple program which loads +ExtUtils::MakeMaker and runs the WriteMakefile() function to generate a +Makefile. + +Here's an example of what you need for a simple module: + + use ExtUtils::MakeMaker; + + WriteMakefile( + NAME => 'Your::Module', + VERSION_FROM => 'lib/Your/Module.pm' + ); + +NAME is the top-level namespace of your module. VERSION_FROM is the file +which contains the $VERSION variable for the entire distribution. Typically +this is the same as your top-level module. + + +=item MANIFEST + +A simple listing of all the files in your distribution. + + Makefile.PL + MANIFEST + lib/Your/Module.pm + +File paths in a MANIFEST always use Unix conventions (ie. /) even if you're +not on Unix. + +You can write this by hand or generate it with 'make manifest'. + +See L<ExtUtils::Manifest> for more details. + + +=item lib/ + +This is the directory where your .pm and .pod files you wish to have +installed go. They are layed out according to namespace. So Foo::Bar +is F<lib/Foo/Bar.pm>. + + +=item t/ + +Tests for your modules go here. Each test filename ends with a .t. +So F<t/foo.t>/ 'make test' will run these tests. The directory is flat, +you cannot, for example, have t/foo/bar.t run by 'make test'. + +Tests are run from the top level of your distribution. So inside a test +you would refer to ./lib to enter the lib directory, for example. + + +=item Changes + +A log of changes you've made to this module. The layout is free-form. +Here's an example: + + 1.01 Fri Apr 11 00:21:25 PDT 2003 + - thing() does some stuff now + - fixed the wiggy bug in withit() + + 1.00 Mon Apr 7 00:57:15 PDT 2003 + - "Rain of Frogs" now supported + + +=item README + +A short description of your module, what it does, why someone would use it +and its limitations. CPAN automatically pulls your README file out of +the archive and makes it available to CPAN users, it is the first thing +they will read to decide if your module is right for them. + + +=item INSTALL + +Instructions on how to install your module along with any dependencies. +Suggested information to include here: + + any extra modules required for use + the minimum version of Perl required + if only works on certain operating systems + + +=item MANIFEST.SKIP + +A file full of regular expressions to exclude when using 'make +manifest' to generate the MANIFEST. These regular expressions +are checked against each file path found in the distribution (so +you're matching against "t/foo.t" not "foo.t"). + +Here's a sample: + + ~$ # ignore emacs and vim backup files + .bak$ # ignore manual backups + \# # ignore CVS old revision files and emacs temp files + +Since # can be used for comments, # must be escaped. + +MakeMaker comes with a default MANIFEST.SKIP to avoid things like +version control directories and backup files. Specifying your own +will override this default. + + +=item bin/ + + +=back + +=head1 SEE ALSO + +L<perlmodstyle> gives stylistic help writing a module. + +L<perlnewmod> gives more information about how to write a module. + +There are modules to help you through the process of writing a module: +L<ExtUtils::ModuleMaker>, L<Module::Install>, L<PAR> + +=cut + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/Manifest.pm b/Master/tlpkg/tlperl/lib/ExtUtils/Manifest.pm new file mode 100644 index 00000000000..df621d5f435 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/Manifest.pm @@ -0,0 +1,881 @@ +package ExtUtils::Manifest; + +require Exporter; +use Config; +use File::Basename; +use File::Copy 'copy'; +use File::Find; +use File::Spec; +use Carp; +use strict; + +use vars qw($VERSION @ISA @EXPORT_OK + $Is_MacOS $Is_VMS $Is_VMS_mode $Is_VMS_lc $Is_VMS_nodot + $Debug $Verbose $Quiet $MANIFEST $DEFAULT_MSKIP); + +$VERSION = '1.57'; +@ISA=('Exporter'); +@EXPORT_OK = qw(mkmanifest + manicheck filecheck fullcheck skipcheck + manifind maniread manicopy maniadd + maniskip + ); + +$Is_MacOS = $^O eq 'MacOS'; +$Is_VMS = $^O eq 'VMS'; +$Is_VMS_mode = 0; +$Is_VMS_lc = 0; +$Is_VMS_nodot = 0; # No dots in dir names or double dots in files + +if ($Is_VMS) { + require VMS::Filespec if $Is_VMS; + my $vms_unix_rpt; + my $vms_efs; + my $vms_case; + + $Is_VMS_mode = 1; + $Is_VMS_lc = 1; + $Is_VMS_nodot = 1; + if (eval { local $SIG{__DIE__}; require VMS::Feature; }) { + $vms_unix_rpt = VMS::Feature::current("filename_unix_report"); + $vms_efs = VMS::Feature::current("efs_charset"); + $vms_case = VMS::Feature::current("efs_case_preserve"); + } else { + my $unix_rpt = $ENV{'DECC$FILENAME_UNIX_REPORT'} || ''; + my $efs_charset = $ENV{'DECC$EFS_CHARSET'} || ''; + my $efs_case = $ENV{'DECC$EFS_CASE_PRESERVE'} || ''; + $vms_unix_rpt = $unix_rpt =~ /^[ET1]/i; + $vms_efs = $efs_charset =~ /^[ET1]/i; + $vms_case = $efs_case =~ /^[ET1]/i; + } + $Is_VMS_lc = 0 if ($vms_case); + $Is_VMS_mode = 0 if ($vms_unix_rpt); + $Is_VMS_nodot = 0 if ($vms_efs); +} + +$Debug = $ENV{PERL_MM_MANIFEST_DEBUG} || 0; +$Verbose = defined $ENV{PERL_MM_MANIFEST_VERBOSE} ? + $ENV{PERL_MM_MANIFEST_VERBOSE} : 1; +$Quiet = 0; +$MANIFEST = 'MANIFEST'; + +$DEFAULT_MSKIP = File::Spec->catfile( dirname(__FILE__), "$MANIFEST.SKIP" ); + + +=head1 NAME + +ExtUtils::Manifest - utilities to write and check a MANIFEST file + +=head1 SYNOPSIS + + use ExtUtils::Manifest qw(...funcs to import...); + + mkmanifest(); + + my @missing_files = manicheck; + my @skipped = skipcheck; + my @extra_files = filecheck; + my($missing, $extra) = fullcheck; + + my $found = manifind(); + + my $manifest = maniread(); + + manicopy($read,$target); + + maniadd({$file => $comment, ...}); + + +=head1 DESCRIPTION + +=head2 Functions + +ExtUtils::Manifest exports no functions by default. The following are +exported on request + +=over 4 + +=item mkmanifest + + mkmanifest(); + +Writes all files in and below the current directory to your F<MANIFEST>. +It works similar to the result of the Unix command + + find . > MANIFEST + +All files that match any regular expression in a file F<MANIFEST.SKIP> +(if it exists) are ignored. + +Any existing F<MANIFEST> file will be saved as F<MANIFEST.bak>. + +=cut + +sub _sort { + return sort { lc $a cmp lc $b } @_; +} + +sub mkmanifest { + my $manimiss = 0; + my $read = (-r 'MANIFEST' && maniread()) or $manimiss++; + $read = {} if $manimiss; + local *M; + my $bakbase = $MANIFEST; + $bakbase =~ s/\./_/g if $Is_VMS_nodot; # avoid double dots + rename $MANIFEST, "$bakbase.bak" unless $manimiss; + open M, "> $MANIFEST" or die "Could not open $MANIFEST: $!"; + my $skip = maniskip(); + my $found = manifind(); + my($key,$val,$file,%all); + %all = (%$found, %$read); + $all{$MANIFEST} = ($Is_VMS_mode ? "$MANIFEST\t\t" : '') . + 'This list of files' + if $manimiss; # add new MANIFEST to known file list + foreach $file (_sort keys %all) { + if ($skip->($file)) { + # Policy: only remove files if they're listed in MANIFEST.SKIP. + # Don't remove files just because they don't exist. + warn "Removed from $MANIFEST: $file\n" if $Verbose and exists $read->{$file}; + next; + } + if ($Verbose){ + warn "Added to $MANIFEST: $file\n" unless exists $read->{$file}; + } + my $text = $all{$file}; + $file = _unmacify($file); + my $tabs = (5 - (length($file)+1)/8); + $tabs = 1 if $tabs < 1; + $tabs = 0 unless $text; + if ($file =~ /\s/) { + $file =~ s/([\\'])/\\$1/g; + $file = "'$file'"; + } + print M $file, "\t" x $tabs, $text, "\n"; + } + close M; +} + +# Geez, shouldn't this use File::Spec or File::Basename or something? +# Why so careful about dependencies? +sub clean_up_filename { + my $filename = shift; + $filename =~ s|^\./||; + $filename =~ s/^:([^:]+)$/$1/ if $Is_MacOS; + return $filename; +} + + +=item manifind + + my $found = manifind(); + +returns a hash reference. The keys of the hash are the files found +below the current directory. + +=cut + +sub manifind { + my $p = shift || {}; + my $found = {}; + + my $wanted = sub { + my $name = clean_up_filename($File::Find::name); + warn "Debug: diskfile $name\n" if $Debug; + return if -d $_; + + if( $Is_VMS_lc ) { + $name =~ s#(.*)\.$#\L$1#; + $name = uc($name) if $name =~ /^MANIFEST(\.SKIP)?$/i; + } + $found->{$name} = ""; + }; + + # We have to use "$File::Find::dir/$_" in preprocess, because + # $File::Find::name is unavailable. + # Also, it's okay to use / here, because MANIFEST files use Unix-style + # paths. + find({wanted => $wanted}, + $Is_MacOS ? ":" : "."); + + return $found; +} + + +=item manicheck + + my @missing_files = manicheck(); + +checks if all the files within a C<MANIFEST> in the current directory +really do exist. If C<MANIFEST> and the tree below the current +directory are in sync it silently returns an empty list. +Otherwise it returns a list of files which are listed in the +C<MANIFEST> but missing from the directory, and by default also +outputs these names to STDERR. + +=cut + +sub manicheck { + return _check_files(); +} + + +=item filecheck + + my @extra_files = filecheck(); + +finds files below the current directory that are not mentioned in the +C<MANIFEST> file. An optional file C<MANIFEST.SKIP> will be +consulted. Any file matching a regular expression in such a file will +not be reported as missing in the C<MANIFEST> file. The list of any +extraneous files found is returned, and by default also reported to +STDERR. + +=cut + +sub filecheck { + return _check_manifest(); +} + + +=item fullcheck + + my($missing, $extra) = fullcheck(); + +does both a manicheck() and a filecheck(), returning then as two array +refs. + +=cut + +sub fullcheck { + return [_check_files()], [_check_manifest()]; +} + + +=item skipcheck + + my @skipped = skipcheck(); + +lists all the files that are skipped due to your C<MANIFEST.SKIP> +file. + +=cut + +sub skipcheck { + my($p) = @_; + my $found = manifind(); + my $matches = maniskip(); + + my @skipped = (); + foreach my $file (_sort keys %$found){ + if (&$matches($file)){ + warn "Skipping $file\n" unless $Quiet; + push @skipped, $file; + next; + } + } + + return @skipped; +} + + +sub _check_files { + my $p = shift; + my $dosnames=(defined(&Dos::UseLFN) && Dos::UseLFN()==0); + my $read = maniread() || {}; + my $found = manifind($p); + + my(@missfile) = (); + foreach my $file (_sort keys %$read){ + warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug; + if ($dosnames){ + $file = lc $file; + $file =~ s=(\.(\w|-)+)=substr ($1,0,4)=ge; + $file =~ s=((\w|-)+)=substr ($1,0,8)=ge; + } + unless ( exists $found->{$file} ) { + warn "No such file: $file\n" unless $Quiet; + push @missfile, $file; + } + } + + return @missfile; +} + + +sub _check_manifest { + my($p) = @_; + my $read = maniread() || {}; + my $found = manifind($p); + my $skip = maniskip(); + + my @missentry = (); + foreach my $file (_sort keys %$found){ + next if $skip->($file); + warn "Debug: manicheck checking from disk $file\n" if $Debug; + unless ( exists $read->{$file} ) { + my $canon = $Is_MacOS ? "\t" . _unmacify($file) : ''; + warn "Not in $MANIFEST: $file$canon\n" unless $Quiet; + push @missentry, $file; + } + } + + return @missentry; +} + + +=item maniread + + my $manifest = maniread(); + my $manifest = maniread($manifest_file); + +reads a named C<MANIFEST> file (defaults to C<MANIFEST> in the current +directory) and returns a HASH reference with files being the keys and +comments being the values of the HASH. Blank lines and lines which +start with C<#> in the C<MANIFEST> file are discarded. + +=cut + +sub maniread { + my ($mfile) = @_; + $mfile ||= $MANIFEST; + my $read = {}; + local *M; + unless (open M, "< $mfile"){ + warn "Problem opening $mfile: $!"; + return $read; + } + local $_; + while (<M>){ + chomp; + next if /^\s*#/; + + my($file, $comment); + + # filename may contain spaces if enclosed in '' + # (in which case, \\ and \' are escapes) + if (($file, $comment) = /^'(\\[\\']|.+)+'\s*(.*)/) { + $file =~ s/\\([\\'])/$1/g; + } + else { + ($file, $comment) = /^(\S+)\s*(.*)/; + } + next unless $file; + + if ($Is_MacOS) { + $file = _macify($file); + $file =~ s/\\([0-3][0-7][0-7])/sprintf("%c", oct($1))/ge; + } + elsif ($Is_VMS_mode) { + require File::Basename; + my($base,$dir) = File::Basename::fileparse($file); + # Resolve illegal file specifications in the same way as tar + if ($Is_VMS_nodot) { + $dir =~ tr/./_/; + my(@pieces) = split(/\./,$base); + if (@pieces > 2) + { $base = shift(@pieces) . '.' . join('_',@pieces); } + my $okfile = "$dir$base"; + warn "Debug: Illegal name $file changed to $okfile\n" if $Debug; + $file = $okfile; + } + $file = lc($file) + unless $Is_VMS_lc &&($file =~ /^MANIFEST(\.SKIP)?$/); + } + + $read->{$file} = $comment; + } + close M; + $read; +} + +=item maniskip + + my $skipchk = maniskip(); + my $skipchk = maniskip($manifest_skip_file); + + if ($skipchk->($file)) { .. } + +reads a named C<MANIFEST.SKIP> file (defaults to C<MANIFEST.SKIP> in +the current directory) and returns a CODE reference that tests whether +a given filename should be skipped. + +=cut + +# returns an anonymous sub that decides if an argument matches +sub maniskip { + my @skip ; + my $mfile = shift || "$MANIFEST.SKIP"; + _check_mskip_directives($mfile) if -f $mfile; + local(*M, $_); + open M, "< $mfile" or open M, "< $DEFAULT_MSKIP" or return sub {0}; + while (<M>){ + chomp; + s/\r//; + $_ =~ qr{^\s*(?:(?:'([^\\']*(?:\\.[^\\']*)*)')|([^#\s]\S*))?(?:(?:\s*)|(?:\s+(.*?)\s*))$}; + #my $comment = $3; + my $filename = $2; + if ( defined($1) ) { + $filename = $1; + $filename =~ s/\\(['\\])/$1/g; + } + next if (not defined($filename) or not $filename); + push @skip, _macify($filename); + } + close M; + return sub {0} unless (scalar @skip > 0); + + my $opts = $Is_VMS_mode ? '(?i)' : ''; + + # Make sure each entry is isolated in its own parentheses, in case + # any of them contain alternations + my $regex = join '|', map "(?:$_)", @skip; + + return sub { $_[0] =~ qr{$opts$regex} }; +} + +# checks for the special directives +# #!include_default +# #!include /path/to/some/manifest.skip +# in a custom MANIFEST.SKIP for, for including +# the content of, respectively, the default MANIFEST.SKIP +# and an external manifest.skip file +sub _check_mskip_directives { + my $mfile = shift; + local (*M, $_); + my @lines = (); + my $flag = 0; + unless (open M, "< $mfile") { + warn "Problem opening $mfile: $!"; + return; + } + while (<M>) { + if (/^#!include_default\s*$/) { + if (my @default = _include_mskip_file()) { + push @lines, @default; + warn "Debug: Including default MANIFEST.SKIP\n" if $Debug; + $flag++; + } + next; + } + if (/^#!include\s+(.*)\s*$/) { + my $external_file = $1; + if (my @external = _include_mskip_file($external_file)) { + push @lines, @external; + warn "Debug: Including external $external_file\n" if $Debug; + $flag++; + } + next; + } + push @lines, $_; + } + close M; + return unless $flag; + my $bakbase = $mfile; + $bakbase =~ s/\./_/g if $Is_VMS_nodot; # avoid double dots + rename $mfile, "$bakbase.bak"; + warn "Debug: Saving original $mfile as $bakbase.bak\n" if $Debug; + unless (open M, "> $mfile") { + warn "Problem opening $mfile: $!"; + return; + } + print M $_ for (@lines); + close M; + return; +} + +# returns an array containing the lines of an external +# manifest.skip file, if given, or $DEFAULT_MSKIP +sub _include_mskip_file { + my $mskip = shift || $DEFAULT_MSKIP; + unless (-f $mskip) { + warn qq{Included file "$mskip" not found - skipping}; + return; + } + local (*M, $_); + unless (open M, "< $mskip") { + warn "Problem opening $mskip: $!"; + return; + } + my @lines = (); + push @lines, "\n#!start included $mskip\n"; + push @lines, $_ while <M>; + close M; + push @lines, "#!end included $mskip\n\n"; + return @lines; +} + +=item manicopy + + manicopy(\%src, $dest_dir); + manicopy(\%src, $dest_dir, $how); + +Copies the files that are the keys in %src to the $dest_dir. %src is +typically returned by the maniread() function. + + manicopy( maniread(), $dest_dir ); + +This function is useful for producing a directory tree identical to the +intended distribution tree. + +$how can be used to specify a different methods of "copying". Valid +values are C<cp>, which actually copies the files, C<ln> which creates +hard links, and C<best> which mostly links the files but copies any +symbolic link to make a tree without any symbolic link. C<cp> is the +default. + +=cut + +sub manicopy { + my($read,$target,$how)=@_; + croak "manicopy() called without target argument" unless defined $target; + $how ||= 'cp'; + require File::Path; + require File::Basename; + + $target = VMS::Filespec::unixify($target) if $Is_VMS_mode; + File::Path::mkpath([ $target ],! $Quiet,$Is_VMS ? undef : 0755); + foreach my $file (keys %$read){ + if ($Is_MacOS) { + if ($file =~ m!:!) { + my $dir = _maccat($target, $file); + $dir =~ s/[^:]+$//; + File::Path::mkpath($dir,1,0755); + } + cp_if_diff($file, _maccat($target, $file), $how); + } else { + $file = VMS::Filespec::unixify($file) if $Is_VMS_mode; + if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not? + my $dir = File::Basename::dirname($file); + $dir = VMS::Filespec::unixify($dir) if $Is_VMS_mode; + File::Path::mkpath(["$target/$dir"],! $Quiet,$Is_VMS ? undef : 0755); + } + cp_if_diff($file, "$target/$file", $how); + } + } +} + +sub cp_if_diff { + my($from, $to, $how)=@_; + if (! -f $from) { + carp "$from not found"; + return; + } + my($diff) = 0; + local(*F,*T); + open(F,"< $from\0") or die "Can't read $from: $!\n"; + if (open(T,"< $to\0")) { + local $_; + while (<F>) { $diff++,last if $_ ne <T>; } + $diff++ unless eof(T); + close T; + } + else { $diff++; } + close F; + if ($diff) { + if (-e $to) { + unlink($to) or confess "unlink $to: $!"; + } + STRICT_SWITCH: { + best($from,$to), last STRICT_SWITCH if $how eq 'best'; + cp($from,$to), last STRICT_SWITCH if $how eq 'cp'; + ln($from,$to), last STRICT_SWITCH if $how eq 'ln'; + croak("ExtUtils::Manifest::cp_if_diff " . + "called with illegal how argument [$how]. " . + "Legal values are 'best', 'cp', and 'ln'."); + } + } +} + +sub cp { + my ($srcFile, $dstFile) = @_; + my ($access,$mod) = (stat $srcFile)[8,9]; + + copy($srcFile,$dstFile); + utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile; + _manicopy_chmod($srcFile, $dstFile); +} + + +sub ln { + my ($srcFile, $dstFile) = @_; + # Fix-me - VMS can support links. + return &cp if $Is_VMS or ($^O eq 'MSWin32' and Win32::IsWin95()); + link($srcFile, $dstFile); + + unless( _manicopy_chmod($srcFile, $dstFile) ) { + unlink $dstFile; + return; + } + 1; +} + +# 1) Strip off all group and world permissions. +# 2) Let everyone read it. +# 3) If the owner can execute it, everyone can. +sub _manicopy_chmod { + my($srcFile, $dstFile) = @_; + + my $perm = 0444 | (stat $srcFile)[2] & 0700; + chmod( $perm | ( $perm & 0100 ? 0111 : 0 ), $dstFile ); +} + +# Files that are often modified in the distdir. Don't hard link them. +my @Exceptions = qw(MANIFEST META.yml SIGNATURE); +sub best { + my ($srcFile, $dstFile) = @_; + + my $is_exception = grep $srcFile =~ /$_/, @Exceptions; + if ($is_exception or !$Config{d_link} or -l $srcFile) { + cp($srcFile, $dstFile); + } else { + ln($srcFile, $dstFile) or cp($srcFile, $dstFile); + } +} + +sub _macify { + my($file) = @_; + + return $file unless $Is_MacOS; + + $file =~ s|^\./||; + if ($file =~ m|/|) { + $file =~ s|/+|:|g; + $file = ":$file"; + } + + $file; +} + +sub _maccat { + my($f1, $f2) = @_; + + return "$f1/$f2" unless $Is_MacOS; + + $f1 .= ":$f2"; + $f1 =~ s/([^:]:):/$1/g; + return $f1; +} + +sub _unmacify { + my($file) = @_; + + return $file unless $Is_MacOS; + + $file =~ s|^:||; + $file =~ s|([/ \n])|sprintf("\\%03o", unpack("c", $1))|ge; + $file =~ y|:|/|; + + $file; +} + + +=item maniadd + + maniadd({ $file => $comment, ...}); + +Adds an entry to an existing F<MANIFEST> unless its already there. + +$file will be normalized (ie. Unixified). B<UNIMPLEMENTED> + +=cut + +sub maniadd { + my($additions) = shift; + + _normalize($additions); + _fix_manifest($MANIFEST); + + my $manifest = maniread(); + my @needed = grep { !exists $manifest->{$_} } keys %$additions; + return 1 unless @needed; + + open(MANIFEST, ">>$MANIFEST") or + die "maniadd() could not open $MANIFEST: $!"; + + foreach my $file (_sort @needed) { + my $comment = $additions->{$file} || ''; + if ($file =~ /\s/) { + $file =~ s/([\\'])/\\$1/g; + $file = "'$file'"; + } + printf MANIFEST "%-40s %s\n", $file, $comment; + } + close MANIFEST or die "Error closing $MANIFEST: $!"; + + return 1; +} + + +# Sometimes MANIFESTs are missing a trailing newline. Fix this. +sub _fix_manifest { + my $manifest_file = shift; + + open MANIFEST, $MANIFEST or die "Could not open $MANIFEST: $!"; + + # Yes, we should be using seek(), but I'd like to avoid loading POSIX + # to get SEEK_* + my @manifest = <MANIFEST>; + close MANIFEST; + + unless( $manifest[-1] =~ /\n\z/ ) { + open MANIFEST, ">>$MANIFEST" or die "Could not open $MANIFEST: $!"; + print MANIFEST "\n"; + close MANIFEST; + } +} + + +# UNIMPLEMENTED +sub _normalize { + return; +} + + +=back + +=head2 MANIFEST + +A list of files in the distribution, one file per line. The MANIFEST +always uses Unix filepath conventions even if you're not on Unix. This +means F<foo/bar> style not F<foo\bar>. + +Anything between white space and an end of line within a C<MANIFEST> +file is considered to be a comment. Any line beginning with # is also +a comment. Beginning with ExtUtils::Manifest 1.52, a filename may +contain whitespace characters if it is enclosed in single quotes; single +quotes or backslashes in that filename must be backslash-escaped. + + # this a comment + some/file + some/other/file comment about some/file + 'some/third file' comment + + +=head2 MANIFEST.SKIP + +The file MANIFEST.SKIP may contain regular expressions of files that +should be ignored by mkmanifest() and filecheck(). The regular +expressions should appear one on each line. Blank lines and lines +which start with C<#> are skipped. Use C<\#> if you need a regular +expression to start with a C<#>. + +For example: + + # Version control files and dirs. + \bRCS\b + \bCVS\b + ,v$ + \B\.svn\b + + # Makemaker generated files and dirs. + ^MANIFEST\. + ^Makefile$ + ^blib/ + ^MakeMaker-\d + + # Temp, old and emacs backup files. + ~$ + \.old$ + ^#.*#$ + ^\.# + +If no MANIFEST.SKIP file is found, a default set of skips will be +used, similar to the example above. If you want nothing skipped, +simply make an empty MANIFEST.SKIP file. + +In one's own MANIFEST.SKIP file, certain directives +can be used to include the contents of other MANIFEST.SKIP +files. At present two such directives are recognized. + +=over 4 + +=item #!include_default + +This inserts the contents of the default MANIFEST.SKIP file + +=item #!include /Path/to/another/manifest.skip + +This inserts the contents of the specified external file + +=back + +The included contents will be inserted into the MANIFEST.SKIP +file in between I<#!start included /path/to/manifest.skip> +and I<#!end included /path/to/manifest.skip> markers. +The original MANIFEST.SKIP is saved as MANIFEST.SKIP.bak. + +=head2 EXPORT_OK + +C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>, +C<&maniread>, and C<&manicopy> are exportable. + +=head2 GLOBAL VARIABLES + +C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it +results in both a different C<MANIFEST> and a different +C<MANIFEST.SKIP> file. This is useful if you want to maintain +different distributions for different audiences (say a user version +and a developer version including RCS). + +C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value, +all functions act silently. + +C<$ExtUtils::Manifest::Debug> defaults to 0. If set to a true value, +or if PERL_MM_MANIFEST_DEBUG is true, debugging output will be +produced. + +=head1 DIAGNOSTICS + +All diagnostic output is sent to C<STDERR>. + +=over 4 + +=item C<Not in MANIFEST:> I<file> + +is reported if a file is found which is not in C<MANIFEST>. + +=item C<Skipping> I<file> + +is reported if a file is skipped due to an entry in C<MANIFEST.SKIP>. + +=item C<No such file:> I<file> + +is reported if a file mentioned in a C<MANIFEST> file does not +exist. + +=item C<MANIFEST:> I<$!> + +is reported if C<MANIFEST> could not be opened. + +=item C<Added to MANIFEST:> I<file> + +is reported by mkmanifest() if $Verbose is set and a file is added +to MANIFEST. $Verbose is set to 1 by default. + +=back + +=head1 ENVIRONMENT + +=over 4 + +=item B<PERL_MM_MANIFEST_DEBUG> + +Turns on debugging + +=back + +=head1 SEE ALSO + +L<ExtUtils::MakeMaker> which has handy targets for most of the functionality. + +=head1 AUTHOR + +Andreas Koenig C<andreas.koenig@anima.de> + +Maintained by Michael G Schwern C<schwern@pobox.com> within the +ExtUtils-MakeMaker package and, as a separate CPAN package, by +Randy Kobes C<r.kobes@uwinnipeg.ca>. + +=cut + +1; diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/Miniperl.pm b/Master/tlpkg/tlperl/lib/ExtUtils/Miniperl.pm new file mode 100644 index 00000000000..493cb347e44 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/Miniperl.pm @@ -0,0 +1,280 @@ +# This File keeps the contents of miniperlmain.c. +# +# It was generated automatically by minimod.PL from the contents +# of miniperlmain.c. Don't edit this file! +# +# ANY CHANGES MADE HERE WILL BE LOST! +# + + +package ExtUtils::Miniperl; +require Exporter; +@ISA = qw(Exporter); +@EXPORT = qw(&writemain); + +$head= <<'EOF!HEAD'; +/* miniperlmain.c + * + * Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003, + * 2004, 2005, 2006, 2007, by Larry Wall and others + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +/* + * The Road goes ever on and on + * Down from the door where it began. + * + * [Bilbo on p.35 of _The Lord of the Rings_, I/i: "A Long-Expected Party"] + * [Frodo on p.73 of _The Lord of the Rings_, I/iii: "Three Is Company"] + */ + +/* This file contains the main() function for the perl interpreter. + * Note that miniperlmain.c contains main() for the 'miniperl' binary, + * while perlmain.c contains main() for the 'perl' binary. + * + * Miniperl is like perl except that it does not support dynamic loading, + * and in fact is used to build the dynamic modules needed for the 'real' + * perl executable. + */ + +#ifdef OEMVS +#ifdef MYMALLOC +/* sbrk is limited to first heap segment so make it big */ +#pragma runopts(HEAP(8M,500K,ANYWHERE,KEEP,8K,4K) STACK(,,ANY,) ALL31(ON)) +#else +#pragma runopts(HEAP(2M,500K,ANYWHERE,KEEP,8K,4K) STACK(,,ANY,) ALL31(ON)) +#endif +#endif + + +#include "EXTERN.h" +#define PERL_IN_MINIPERLMAIN_C +#include "perl.h" +#include "XSUB.h" + +static void xs_init (pTHX); +static PerlInterpreter *my_perl; + +#if defined (atarist) +/* The Atari operating system doesn't have a dynamic stack. The + stack size is determined from this value. */ +long _stksize = 64 * 1024; +#endif + +#if defined(PERL_GLOBAL_STRUCT_PRIVATE) +/* The static struct perl_vars* may seem counterproductive since the + * whole idea PERL_GLOBAL_STRUCT_PRIVATE was to avoid statics, but note + * that this static is not in the shared perl library, the globals PL_Vars + * and PL_VarsPtr will stay away. */ +static struct perl_vars* my_plvarsp; +struct perl_vars* Perl_GetVarsPrivate(void) { return my_plvarsp; } +#endif + +#ifdef NO_ENV_ARRAY_IN_MAIN +extern char **environ; +int +main(int argc, char **argv) +#else +int +main(int argc, char **argv, char **env) +#endif +{ + dVAR; + int exitstatus, i; +#ifdef PERL_GLOBAL_STRUCT + struct perl_vars *plvarsp = init_global_struct(); +# ifdef PERL_GLOBAL_STRUCT_PRIVATE + my_vars = my_plvarsp = plvarsp; +# endif +#endif /* PERL_GLOBAL_STRUCT */ + (void)env; +#ifndef PERL_USE_SAFE_PUTENV + PL_use_safe_putenv = 0; +#endif /* PERL_USE_SAFE_PUTENV */ + + /* if user wants control of gprof profiling off by default */ + /* noop unless Configure is given -Accflags=-DPERL_GPROF_CONTROL */ + PERL_GPROF_MONCONTROL(0); + +#ifdef NO_ENV_ARRAY_IN_MAIN + PERL_SYS_INIT3(&argc,&argv,&environ); +#else + PERL_SYS_INIT3(&argc,&argv,&env); +#endif + +#if defined(USE_ITHREADS) + /* XXX Ideally, this should really be happening in perl_alloc() or + * perl_construct() to keep libperl.a transparently fork()-safe. + * It is currently done here only because Apache/mod_perl have + * problems due to lack of a call to cancel pthread_atfork() + * handlers when shared objects that contain the handlers may + * be dlclose()d. This forces applications that embed perl to + * call PTHREAD_ATFORK() explicitly, but if and only if it hasn't + * been called at least once before in the current process. + * --GSAR 2001-07-20 */ + PTHREAD_ATFORK(Perl_atfork_lock, + Perl_atfork_unlock, + Perl_atfork_unlock); +#endif + + if (!PL_do_undump) { + my_perl = perl_alloc(); + if (!my_perl) + exit(1); + perl_construct(my_perl); + PL_perl_destruct_level = 0; + } + PL_exit_flags |= PERL_EXIT_DESTRUCT_END; + exitstatus = perl_parse(my_perl, xs_init, argc, argv, (char **)NULL); + if (!exitstatus) + perl_run(my_perl); + + /* Unregister our signal handler before destroying my_perl */ + for (i = 0; PL_sig_name[i]; i++) { + if (rsignal_state(PL_sig_num[i]) == (Sighandler_t) PL_csighandlerp) { + rsignal(PL_sig_num[i], (Sighandler_t) SIG_DFL); + } + } + + exitstatus = perl_destruct(my_perl); + + perl_free(my_perl); + +#if defined(USE_ENVIRON_ARRAY) && defined(PERL_TRACK_MEMPOOL) && !defined(NO_ENV_ARRAY_IN_MAIN) + /* + * The old environment may have been freed by perl_free() + * when PERL_TRACK_MEMPOOL is defined, but without having + * been restored by perl_destruct() before (this is only + * done if destruct_level > 0). + * + * It is important to have a valid environment for atexit() + * routines that are eventually called. + */ + environ = env; +#endif + +#ifdef PERL_GLOBAL_STRUCT + free_global_struct(plvarsp); +#endif /* PERL_GLOBAL_STRUCT */ + + PERL_SYS_TERM(); + + exit(exitstatus); + return exitstatus; +} + +/* Register any extra external extensions */ + +EOF!HEAD +$tail=<<'EOF!TAIL'; + +static void +xs_init(pTHX) +{ + PERL_UNUSED_CONTEXT; +} + +/* + * Local variables: + * c-indentation-style: bsd + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + * + * ex: set ts=8 sts=4 sw=4 noet: + */ +EOF!TAIL + +sub writemain{ + my(@exts) = @_; + + my($pname); + my($dl) = canon('/','DynaLoader'); + print $head; + + foreach $_ (@exts){ + my($pname) = canon('/', $_); + my($mname, $cname); + ($mname = $pname) =~ s!/!::!g; + ($cname = $pname) =~ s!/!__!g; + print "EXTERN_C void boot_${cname} (pTHX_ CV* cv);\n"; + } + + my ($tail1,$tail2,$tail3) = ( $tail =~ /\A(.*{\s*\n)(.*\n)(\s*\}.*)\Z/s ); + + print $tail1; + print "\tconst char file[] = __FILE__;\n"; + print "\tdXSUB_SYS;\n" if $] > 5.002; + print $tail2; + + foreach $_ (@exts){ + my($pname) = canon('/', $_); + my($mname, $cname, $ccode); + ($mname = $pname) =~ s!/!::!g; + ($cname = $pname) =~ s!/!__!g; + print "\t{\n"; + if ($pname eq $dl){ + # Must NOT install 'DynaLoader::boot_DynaLoader' as 'bootstrap'! + # boot_DynaLoader is called directly in DynaLoader.pm + $ccode = "\t/* DynaLoader is a special case */\n +\tnewXS(\"${mname}::boot_${cname}\", boot_${cname}, file);\n"; + print $ccode unless $SEEN{$ccode}++; + } else { + $ccode = "\tnewXS(\"${mname}::bootstrap\", boot_${cname}, file);\n"; + print $ccode unless $SEEN{$ccode}++; + } + print "\t}\n"; + } + print $tail3; +} + +sub canon{ + my($as, @ext) = @_; + foreach(@ext){ + # might be X::Y or lib/auto/X/Y/Y.a + next if s!::!/!g; + s:^(lib|ext)/(auto/)?::; + s:/\w+\.\w+$::; + } + grep(s:/:$as:, @ext) if ($as ne '/'); + @ext; +} + +1; +__END__ + +=head1 NAME + +ExtUtils::Miniperl, writemain - write the C code for perlmain.c + +=head1 SYNOPSIS + +C<use ExtUtils::Miniperl;> + +C<writemain(@directories);> + +=head1 DESCRIPTION + +This whole module is written when perl itself is built from a script +called minimod.PL. In case you want to patch it, please patch +minimod.PL in the perl distribution instead. + +writemain() takes an argument list of directories containing archive +libraries that relate to perl modules and should be linked into a new +perl binary. It writes to STDOUT a corresponding perlmain.c file that +is a plain C file containing all the bootstrap code to make the +modules associated with the libraries available from within perl. + +The typical usage is from within a Makefile generated by +ExtUtils::MakeMaker. So under normal circumstances you won't have to +deal with this module directly. + +=head1 SEE ALSO + +L<ExtUtils::MakeMaker> + +=cut + diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/Mkbootstrap.pm b/Master/tlpkg/tlperl/lib/ExtUtils/Mkbootstrap.pm new file mode 100644 index 00000000000..707466a98dd --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/Mkbootstrap.pm @@ -0,0 +1,109 @@ +package ExtUtils::Mkbootstrap; + +# There's just too much Dynaloader incest here to turn on strict vars. +use strict 'refs'; + +our $VERSION = '6.56'; + +require Exporter; +our @ISA = ('Exporter'); +our @EXPORT = ('&Mkbootstrap'); + +use Config; + +our $Verbose = 0; + + +sub Mkbootstrap { + my($baseext, @bsloadlibs)=@_; + @bsloadlibs = grep($_, @bsloadlibs); # strip empty libs + + print STDOUT " bsloadlibs=@bsloadlibs\n" if $Verbose; + + # We need DynaLoader here because we and/or the *_BS file may + # call dl_findfile(). We don't say `use' here because when + # first building perl extensions the DynaLoader will not have + # been built when MakeMaker gets first used. + require DynaLoader; + + rename "$baseext.bs", "$baseext.bso" + if -s "$baseext.bs"; + + if (-f "${baseext}_BS"){ + $_ = "${baseext}_BS"; + package DynaLoader; # execute code as if in DynaLoader + local($osname, $dlsrc) = (); # avoid warnings + ($osname, $dlsrc) = @Config::Config{qw(osname dlsrc)}; + $bscode = ""; + unshift @INC, "."; + require $_; + shift @INC; + } + + if ($Config{'dlsrc'} =~ /^dl_dld/){ + package DynaLoader; + push(@dl_resolve_using, dl_findfile('-lc')); + } + + my(@all) = (@bsloadlibs, @DynaLoader::dl_resolve_using); + my($method) = ''; + if (@all){ + open my $bs, ">", "$baseext.bs" + or die "Unable to open $baseext.bs: $!"; + print STDOUT "Writing $baseext.bs\n"; + print STDOUT " containing: @all" if $Verbose; + print $bs "# $baseext DynaLoader bootstrap file for $^O architecture.\n"; + print $bs "# Do not edit this file, changes will be lost.\n"; + print $bs "# This file was automatically generated by the\n"; + print $bs "# Mkbootstrap routine in ExtUtils::Mkbootstrap (v$VERSION).\n"; + print $bs "\@DynaLoader::dl_resolve_using = "; + # If @all contains names in the form -lxxx or -Lxxx then it's asking for + # runtime library location so we automatically add a call to dl_findfile() + if (" @all" =~ m/ -[lLR]/){ + print $bs " dl_findfile(qw(\n @all\n ));\n"; + }else{ + print $bs " qw(@all);\n"; + } + # write extra code if *_BS says so + print $bs $DynaLoader::bscode if $DynaLoader::bscode; + print $bs "\n1;\n"; + close $bs; + } +} + +1; + +__END__ + +=head1 NAME + +ExtUtils::Mkbootstrap - make a bootstrap file for use by DynaLoader + +=head1 SYNOPSIS + +C<Mkbootstrap> + +=head1 DESCRIPTION + +Mkbootstrap typically gets called from an extension Makefile. + +There is no C<*.bs> file supplied with the extension. Instead, there may +be a C<*_BS> file which has code for the special cases, like posix for +berkeley db on the NeXT. + +This file will get parsed, and produce a maybe empty +C<@DynaLoader::dl_resolve_using> array for the current architecture. +That will be extended by $BSLOADLIBS, which was computed by +ExtUtils::Liblist::ext(). If this array still is empty, we do nothing, +else we write a .bs file with an C<@DynaLoader::dl_resolve_using> +array. + +The C<*_BS> file can put some code into the generated C<*.bs> file by +placing it in C<$bscode>. This is a handy 'escape' mechanism that may +prove useful in complex situations. + +If @DynaLoader::dl_resolve_using contains C<-L*> or C<-l*> entries then +Mkbootstrap will automatically add a dl_findfile() call to the +generated C<*.bs> file. + +=cut diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/Mksymlists.pm b/Master/tlpkg/tlperl/lib/ExtUtils/Mksymlists.pm new file mode 100644 index 00000000000..962c67fd57f --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/Mksymlists.pm @@ -0,0 +1,312 @@ +package ExtUtils::Mksymlists; + +use 5.006; +use strict qw[ subs refs ]; +# no strict 'vars'; # until filehandles are exempted + +use Carp; +use Exporter; +use Config; + +our @ISA = qw(Exporter); +our @EXPORT = qw(&Mksymlists); +our $VERSION = '6.56'; + +sub Mksymlists { + my(%spec) = @_; + my($osname) = $^O; + + croak("Insufficient information specified to Mksymlists") + unless ( $spec{NAME} or + ($spec{FILE} and ($spec{DL_FUNCS} or $spec{FUNCLIST})) ); + + $spec{DL_VARS} = [] unless $spec{DL_VARS}; + ($spec{FILE} = $spec{NAME}) =~ s/.*::// unless $spec{FILE}; + $spec{FUNCLIST} = [] unless $spec{FUNCLIST}; + $spec{DL_FUNCS} = { $spec{NAME} => [] } + unless ( ($spec{DL_FUNCS} and keys %{$spec{DL_FUNCS}}) or + @{$spec{FUNCLIST}}); + if (defined $spec{DL_FUNCS}) { + foreach my $package (keys %{$spec{DL_FUNCS}}) { + my($packprefix,$bootseen); + ($packprefix = $package) =~ s/\W/_/g; + foreach my $sym (@{$spec{DL_FUNCS}->{$package}}) { + if ($sym =~ /^boot_/) { + push(@{$spec{FUNCLIST}},$sym); + $bootseen++; + } + else { + push(@{$spec{FUNCLIST}},"XS_${packprefix}_$sym"); + } + } + push(@{$spec{FUNCLIST}},"boot_$packprefix") unless $bootseen; + } + } + +# We'll need this if we ever add any OS which uses mod2fname +# not as pseudo-builtin. +# require DynaLoader; + if (defined &DynaLoader::mod2fname and not $spec{DLBASE}) { + $spec{DLBASE} = DynaLoader::mod2fname([ split(/::/,$spec{NAME}) ]); + } + + if ($osname eq 'aix') { _write_aix(\%spec); } + elsif ($osname eq 'MacOS'){ _write_aix(\%spec) } + elsif ($osname eq 'VMS') { _write_vms(\%spec) } + elsif ($osname eq 'os2') { _write_os2(\%spec) } + elsif ($osname eq 'MSWin32') { _write_win32(\%spec) } + else { + croak("Don't know how to create linker option file for $osname\n"); + } +} + + +sub _write_aix { + my($data) = @_; + + rename "$data->{FILE}.exp", "$data->{FILE}.exp_old"; + + open( my $exp, ">", "$data->{FILE}.exp") + or croak("Can't create $data->{FILE}.exp: $!\n"); + print $exp join("\n",@{$data->{DL_VARS}}, "\n") if @{$data->{DL_VARS}}; + print $exp join("\n",@{$data->{FUNCLIST}}, "\n") if @{$data->{FUNCLIST}}; + close $exp; +} + + +sub _write_os2 { + my($data) = @_; + require Config; + my $threaded = ($Config::Config{archname} =~ /-thread/ ? " threaded" : ""); + + if (not $data->{DLBASE}) { + ($data->{DLBASE} = $data->{NAME}) =~ s/.*:://; + $data->{DLBASE} = substr($data->{DLBASE},0,7) . '_'; + } + my $distname = $data->{DISTNAME} || $data->{NAME}; + $distname = "Distribution $distname"; + my $patchlevel = " pl$Config{perl_patchlevel}" || ''; + my $comment = sprintf "Perl (v%s%s%s) module %s", + $Config::Config{version}, $threaded, $patchlevel, $data->{NAME}; + chomp $comment; + if ($data->{INSTALLDIRS} and $data->{INSTALLDIRS} eq 'perl') { + $distname = 'perl5-porters@perl.org'; + $comment = "Core $comment"; + } + $comment = "$comment (Perl-config: $Config{config_args})"; + $comment = substr($comment, 0, 200) . "...)" if length $comment > 203; + rename "$data->{FILE}.def", "$data->{FILE}_def.old"; + + open(my $def, ">", "$data->{FILE}.def") + or croak("Can't create $data->{FILE}.def: $!\n"); + print $def "LIBRARY '$data->{DLBASE}' INITINSTANCE TERMINSTANCE\n"; + print $def "DESCRIPTION '\@#$distname:$data->{VERSION}#\@ $comment'\n"; + print $def "CODE LOADONCALL\n"; + print $def "DATA LOADONCALL NONSHARED MULTIPLE\n"; + print $def "EXPORTS\n "; + print $def join("\n ",@{$data->{DL_VARS}}, "\n") if @{$data->{DL_VARS}}; + print $def join("\n ",@{$data->{FUNCLIST}}, "\n") if @{$data->{FUNCLIST}}; + if (%{$data->{IMPORTS}}) { + print $def "IMPORTS\n"; + my ($name, $exp); + while (($name, $exp)= each %{$data->{IMPORTS}}) { + print $def " $name=$exp\n"; + } + } + close $def; +} + +sub _write_win32 { + my($data) = @_; + + require Config; + if (not $data->{DLBASE}) { + ($data->{DLBASE} = $data->{NAME}) =~ s/.*:://; + $data->{DLBASE} = substr($data->{DLBASE},0,7) . '_'; + } + rename "$data->{FILE}.def", "$data->{FILE}_def.old"; + + open( my $def, ">", "$data->{FILE}.def" ) + or croak("Can't create $data->{FILE}.def: $!\n"); + # put library name in quotes (it could be a keyword, like 'Alias') + if ($Config::Config{'cc'} !~ /^gcc/i) { + print $def "LIBRARY \"$data->{DLBASE}\"\n"; + } + print $def "EXPORTS\n "; + my @syms; + # Export public symbols both with and without underscores to + # ensure compatibility between DLLs from different compilers + # NOTE: DynaLoader itself only uses the names without underscores, + # so this is only to cover the case when the extension DLL may be + # linked to directly from C. GSAR 97-07-10 + if ($Config::Config{'cc'} =~ /^bcc/i) { + for (@{$data->{DL_VARS}}, @{$data->{FUNCLIST}}) { + push @syms, "_$_", "$_ = _$_"; + } + } + else { + for (@{$data->{DL_VARS}}, @{$data->{FUNCLIST}}) { + push @syms, "$_", "_$_ = $_"; + } + } + print $def join("\n ",@syms, "\n") if @syms; + if (%{$data->{IMPORTS}}) { + print $def "IMPORTS\n"; + my ($name, $exp); + while (($name, $exp)= each %{$data->{IMPORTS}}) { + print $def " $name=$exp\n"; + } + } + close $def; +} + + +sub _write_vms { + my($data) = @_; + + require Config; # a reminder for once we do $^O + require ExtUtils::XSSymSet; + + my($isvax) = $Config::Config{'archname'} =~ /VAX/i; + my($set) = new ExtUtils::XSSymSet; + + rename "$data->{FILE}.opt", "$data->{FILE}.opt_old"; + + open(my $opt,">", "$data->{FILE}.opt") + or croak("Can't create $data->{FILE}.opt: $!\n"); + + # Options file declaring universal symbols + # Used when linking shareable image for dynamic extension, + # or when linking PerlShr into which we've added this package + # as a static extension + # We don't do anything to preserve order, so we won't relax + # the GSMATCH criteria for a dynamic extension + + print $opt "case_sensitive=yes\n" + if $Config::Config{d_vms_case_sensitive_symbols}; + + foreach my $sym (@{$data->{FUNCLIST}}) { + my $safe = $set->addsym($sym); + if ($isvax) { print $opt "UNIVERSAL=$safe\n" } + else { print $opt "SYMBOL_VECTOR=($safe=PROCEDURE)\n"; } + } + + foreach my $sym (@{$data->{DL_VARS}}) { + my $safe = $set->addsym($sym); + print $opt "PSECT_ATTR=${sym},PIC,OVR,RD,NOEXE,WRT,NOSHR\n"; + if ($isvax) { print $opt "UNIVERSAL=$safe\n" } + else { print $opt "SYMBOL_VECTOR=($safe=DATA)\n"; } + } + + close $opt; +} + +1; + +__END__ + +=head1 NAME + +ExtUtils::Mksymlists - write linker options files for dynamic extension + +=head1 SYNOPSIS + + use ExtUtils::Mksymlists; + Mksymlists({ NAME => $name , + DL_VARS => [ $var1, $var2, $var3 ], + DL_FUNCS => { $pkg1 => [ $func1, $func2 ], + $pkg2 => [ $func3 ] }); + +=head1 DESCRIPTION + +C<ExtUtils::Mksymlists> produces files used by the linker under some OSs +during the creation of shared libraries for dynamic extensions. It is +normally called from a MakeMaker-generated Makefile when the extension +is built. The linker option file is generated by calling the function +C<Mksymlists>, which is exported by default from C<ExtUtils::Mksymlists>. +It takes one argument, a list of key-value pairs, in which the following +keys are recognized: + +=over 4 + +=item DLBASE + +This item specifies the name by which the linker knows the +extension, which may be different from the name of the +extension itself (for instance, some linkers add an '_' to the +name of the extension). If it is not specified, it is derived +from the NAME attribute. It is presently used only by OS2 and Win32. + +=item DL_FUNCS + +This is identical to the DL_FUNCS attribute available via MakeMaker, +from which it is usually taken. Its value is a reference to an +associative array, in which each key is the name of a package, and +each value is an a reference to an array of function names which +should be exported by the extension. For instance, one might say +C<DL_FUNCS =E<gt> { Homer::Iliad =E<gt> [ qw(trojans greeks) ], +Homer::Odyssey =E<gt> [ qw(travellers family suitors) ] }>. The +function names should be identical to those in the XSUB code; +C<Mksymlists> will alter the names written to the linker option +file to match the changes made by F<xsubpp>. In addition, if +none of the functions in a list begin with the string B<boot_>, +C<Mksymlists> will add a bootstrap function for that package, +just as xsubpp does. (If a B<boot_E<lt>pkgE<gt>> function is +present in the list, it is passed through unchanged.) If +DL_FUNCS is not specified, it defaults to the bootstrap +function for the extension specified in NAME. + +=item DL_VARS + +This is identical to the DL_VARS attribute available via MakeMaker, +and, like DL_FUNCS, it is usually specified via MakeMaker. Its +value is a reference to an array of variable names which should +be exported by the extension. + +=item FILE + +This key can be used to specify the name of the linker option file +(minus the OS-specific extension), if for some reason you do not +want to use the default value, which is the last word of the NAME +attribute (I<e.g.> for C<Tk::Canvas>, FILE defaults to C<Canvas>). + +=item FUNCLIST + +This provides an alternate means to specify function names to be +exported from the extension. Its value is a reference to an +array of function names to be exported by the extension. These +names are passed through unaltered to the linker options file. +Specifying a value for the FUNCLIST attribute suppresses automatic +generation of the bootstrap function for the package. To still create +the bootstrap name you have to specify the package name in the +DL_FUNCS hash: + + Mksymlists({ NAME => $name , + FUNCLIST => [ $func1, $func2 ], + DL_FUNCS => { $pkg => [] } }); + + +=item IMPORTS + +This attribute is used to specify names to be imported into the +extension. It is currently only used by OS/2 and Win32. + +=item NAME + +This gives the name of the extension (I<e.g.> C<Tk::Canvas>) for which +the linker option file will be produced. + +=back + +When calling C<Mksymlists>, one should always specify the NAME +attribute. In most cases, this is all that's necessary. In +the case of unusual extensions, however, the other attributes +can be used to provide additional information to the linker. + +=head1 AUTHOR + +Charles Bailey I<E<lt>bailey@newman.upenn.eduE<gt>> + +=head1 REVISION + +Last revised 14-Feb-1996, for Perl 5.002. diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/Packlist.pm b/Master/tlpkg/tlperl/lib/ExtUtils/Packlist.pm new file mode 100644 index 00000000000..b77a556be50 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/Packlist.pm @@ -0,0 +1,352 @@ +package ExtUtils::Packlist; + +use 5.00503; +use strict; +use Carp qw(); +use Config; +use vars qw($VERSION $Relocations); +$VERSION = '1.44'; +$VERSION = eval $VERSION; + +# Used for generating filehandle globs. IO::File might not be available! +my $fhname = "FH1"; + +=begin _undocumented + +=over + +=item mkfh() + +Make a filehandle. Same kind of idea as Symbol::gensym(). + +=cut + +sub mkfh() +{ +no strict; +my $fh = \*{$fhname++}; +use strict; +return($fh); +} + +=item __find_relocations + +Works out what absolute paths in the configuration have been located at run +time relative to $^X, and generates a regexp that matches them + +=end _undocumented + +=back + +=cut + +sub __find_relocations +{ + my %paths; + while (my ($raw_key, $raw_val) = each %Config) { + my $exp_key = $raw_key . "exp"; + next unless exists $Config{$exp_key}; + next unless $raw_val =~ m!\.\.\./!; + $paths{$Config{$exp_key}}++; + } + # Longest prefixes go first in the alternatives + my $alternations = join "|", map {quotemeta $_} + sort {length $b <=> length $a} keys %paths; + qr/^($alternations)/o; +} + +sub new($$) +{ +my ($class, $packfile) = @_; +$class = ref($class) || $class; +my %self; +tie(%self, $class, $packfile); +return(bless(\%self, $class)); +} + +sub TIEHASH +{ +my ($class, $packfile) = @_; +my $self = { packfile => $packfile }; +bless($self, $class); +$self->read($packfile) if (defined($packfile) && -f $packfile); +return($self); +} + +sub STORE +{ +$_[0]->{data}->{$_[1]} = $_[2]; +} + +sub FETCH +{ +return($_[0]->{data}->{$_[1]}); +} + +sub FIRSTKEY +{ +my $reset = scalar(keys(%{$_[0]->{data}})); +return(each(%{$_[0]->{data}})); +} + +sub NEXTKEY +{ +return(each(%{$_[0]->{data}})); +} + +sub EXISTS +{ +return(exists($_[0]->{data}->{$_[1]})); +} + +sub DELETE +{ +return(delete($_[0]->{data}->{$_[1]})); +} + +sub CLEAR +{ +%{$_[0]->{data}} = (); +} + +sub DESTROY +{ +} + +sub read($;$) +{ +my ($self, $packfile) = @_; +$self = tied(%$self) || $self; + +if (defined($packfile)) { $self->{packfile} = $packfile; } +else { $packfile = $self->{packfile}; } +Carp::croak("No packlist filename specified") if (! defined($packfile)); +my $fh = mkfh(); +open($fh, "<$packfile") || Carp::croak("Can't open file $packfile: $!"); +$self->{data} = {}; +my ($line); +while (defined($line = <$fh>)) + { + chomp $line; + my ($key, $data) = $line; + if ($key =~ /^(.*?)( \w+=.*)$/) + { + $key = $1; + $data = { map { split('=', $_) } split(' ', $2)}; + + if ($Config{userelocatableinc} && $data->{relocate_as}) + { + require File::Spec; + require Cwd; + my ($vol, $dir) = File::Spec->splitpath($packfile); + my $newpath = File::Spec->catpath($vol, $dir, $data->{relocate_as}); + $key = Cwd::realpath($newpath); + } + } + $key =~ s!/\./!/!g; # Some .packlists have spurious '/./' bits in the paths + $self->{data}->{$key} = $data; + } +close($fh); +} + +sub write($;$) +{ +my ($self, $packfile) = @_; +$self = tied(%$self) || $self; +if (defined($packfile)) { $self->{packfile} = $packfile; } +else { $packfile = $self->{packfile}; } +Carp::croak("No packlist filename specified") if (! defined($packfile)); +my $fh = mkfh(); +open($fh, ">$packfile") || Carp::croak("Can't open file $packfile: $!"); +foreach my $key (sort(keys(%{$self->{data}}))) + { + my $data = $self->{data}->{$key}; + if ($Config{userelocatableinc}) { + $Relocations ||= __find_relocations(); + if ($packfile =~ $Relocations) { + # We are writing into a subdirectory of a run-time relocated + # path. Figure out if the this file is also within a subdir. + my $prefix = $1; + if (File::Spec->no_upwards(File::Spec->abs2rel($key, $prefix))) + { + # The relocated path is within the found prefix + my $packfile_prefix; + (undef, $packfile_prefix) + = File::Spec->splitpath($packfile); + + my $relocate_as + = File::Spec->abs2rel($key, $packfile_prefix); + + if (!ref $data) { + $data = {}; + } + $data->{relocate_as} = $relocate_as; + } + } + } + print $fh ("$key"); + if (ref($data)) + { + foreach my $k (sort(keys(%$data))) + { + print $fh (" $k=$data->{$k}"); + } + } + print $fh ("\n"); + } +close($fh); +} + +sub validate($;$) +{ +my ($self, $remove) = @_; +$self = tied(%$self) || $self; +my @missing; +foreach my $key (sort(keys(%{$self->{data}}))) + { + if (! -e $key) + { + push(@missing, $key); + delete($self->{data}{$key}) if ($remove); + } + } +return(@missing); +} + +sub packlist_file($) +{ +my ($self) = @_; +$self = tied(%$self) || $self; +return($self->{packfile}); +} + +1; + +__END__ + +=head1 NAME + +ExtUtils::Packlist - manage .packlist files + +=head1 SYNOPSIS + + use ExtUtils::Packlist; + my ($pl) = ExtUtils::Packlist->new('.packlist'); + $pl->read('/an/old/.packlist'); + my @missing_files = $pl->validate(); + $pl->write('/a/new/.packlist'); + + $pl->{'/some/file/name'}++; + or + $pl->{'/some/other/file/name'} = { type => 'file', + from => '/some/file' }; + +=head1 DESCRIPTION + +ExtUtils::Packlist provides a standard way to manage .packlist files. +Functions are provided to read and write .packlist files. The original +.packlist format is a simple list of absolute pathnames, one per line. In +addition, this package supports an extended format, where as well as a filename +each line may contain a list of attributes in the form of a space separated +list of key=value pairs. This is used by the installperl script to +differentiate between files and links, for example. + +=head1 USAGE + +The hash reference returned by the new() function can be used to examine and +modify the contents of the .packlist. Items may be added/deleted from the +.packlist by modifying the hash. If the value associated with a hash key is a +scalar, the entry written to the .packlist by any subsequent write() will be a +simple filename. If the value is a hash, the entry written will be the +filename followed by the key=value pairs from the hash. Reading back the +.packlist will recreate the original entries. + +=head1 FUNCTIONS + +=over 4 + +=item new() + +This takes an optional parameter, the name of a .packlist. If the file exists, +it will be opened and the contents of the file will be read. The new() method +returns a reference to a hash. This hash holds an entry for each line in the +.packlist. In the case of old-style .packlists, the value associated with each +key is undef. In the case of new-style .packlists, the value associated with +each key is a hash containing the key=value pairs following the filename in the +.packlist. + +=item read() + +This takes an optional parameter, the name of the .packlist to be read. If +no file is specified, the .packlist specified to new() will be read. If the +.packlist does not exist, Carp::croak will be called. + +=item write() + +This takes an optional parameter, the name of the .packlist to be written. If +no file is specified, the .packlist specified to new() will be overwritten. + +=item validate() + +This checks that every file listed in the .packlist actually exists. If an +argument which evaluates to true is given, any missing files will be removed +from the internal hash. The return value is a list of the missing files, which +will be empty if they all exist. + +=item packlist_file() + +This returns the name of the associated .packlist file + +=back + +=head1 EXAMPLE + +Here's C<modrm>, a little utility to cleanly remove an installed module. + + #!/usr/local/bin/perl -w + + use strict; + use IO::Dir; + use ExtUtils::Packlist; + use ExtUtils::Installed; + + sub emptydir($) { + my ($dir) = @_; + my $dh = IO::Dir->new($dir) || return(0); + my @count = $dh->read(); + $dh->close(); + return(@count == 2 ? 1 : 0); + } + + # Find all the installed packages + print("Finding all installed modules...\n"); + my $installed = ExtUtils::Installed->new(); + + foreach my $module (grep(!/^Perl$/, $installed->modules())) { + my $version = $installed->version($module) || "???"; + print("Found module $module Version $version\n"); + print("Do you want to delete $module? [n] "); + my $r = <STDIN>; chomp($r); + if ($r && $r =~ /^y/i) { + # Remove all the files + foreach my $file (sort($installed->files($module))) { + print("rm $file\n"); + unlink($file); + } + my $pf = $installed->packlist($module)->packlist_file(); + print("rm $pf\n"); + unlink($pf); + foreach my $dir (sort($installed->directory_tree($module))) { + if (emptydir($dir)) { + print("rmdir $dir\n"); + rmdir($dir); + } + } + } + } + +=head1 AUTHOR + +Alan Burlison <Alan.Burlison@uk.sun.com> + +=cut diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/ParseXS.pm b/Master/tlpkg/tlperl/lib/ExtUtils/ParseXS.pm new file mode 100644 index 00000000000..05c3e690027 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/ParseXS.pm @@ -0,0 +1,2111 @@ +package ExtUtils::ParseXS; + +use 5.006; # We use /??{}/ in regexes +use Cwd; +use Config; +use File::Basename; +use File::Spec; +use Symbol; + +require Exporter; + +@ISA = qw(Exporter); +@EXPORT_OK = qw(process_file); + +# use strict; # One of these days... + +my(@XSStack); # Stack of conditionals and INCLUDEs +my($XSS_work_idx, $cpp_next_tmp); + +use vars qw($VERSION); +$VERSION = '2.21'; +$VERSION = eval $VERSION if $VERSION =~ /_/; + +use vars qw(%input_expr %output_expr $ProtoUsed @InitFileCode $FH $proto_re $Overload $errors $Fallback + $cplusplus $hiertype $WantPrototypes $WantVersionChk $except $WantLineNumbers + $WantOptimize $process_inout $process_argtypes @tm + $dir $filename $filepathname %IncludedFiles + %type_kind %proto_letter + %targetable $BLOCK_re $lastline $lastline_no + $Package $Prefix @line @BootCode %args_match %defaults %var_types %arg_list @proto_arg + $processing_arg_with_types %argtype_seen @outlist %in_out %lengthof + $proto_in_this_xsub $scope_in_this_xsub $interface $prepush_done $interface_macro $interface_macro_set + $ProtoThisXSUB $ScopeThisXSUB $xsreturn + @line_no $ret_type $func_header $orig_args + ); # Add these just to get compilation to happen. + + +sub process_file { + + # Allow for $package->process_file(%hash) in the future + my ($pkg, %args) = @_ % 2 ? @_ : (__PACKAGE__, @_); + + $ProtoUsed = exists $args{prototypes}; + + # Set defaults. + %args = ( + # 'C++' => 0, # Doesn't seem to *do* anything... + hiertype => 0, + except => 0, + prototypes => 0, + versioncheck => 1, + linenumbers => 1, + optimize => 1, + prototypes => 0, + inout => 1, + argtypes => 1, + typemap => [], + output => \*STDOUT, + csuffix => '.c', + %args, + ); + + # Global Constants + + my ($Is_VMS, $SymSet); + if ($^O eq 'VMS') { + $Is_VMS = 1; + # Establish set of global symbols with max length 28, since xsubpp + # will later add the 'XS_' prefix. + require ExtUtils::XSSymSet; + $SymSet = new ExtUtils::XSSymSet 28; + } + @XSStack = ({type => 'none'}); + ($XSS_work_idx, $cpp_next_tmp) = (0, "XSubPPtmpAAAA"); + @InitFileCode = (); + $FH = Symbol::gensym(); + $proto_re = "[" . quotemeta('\$%&*@;[]') . "]" ; + $Overload = 0; + $errors = 0; + $Fallback = '&PL_sv_undef'; + + # Most of the 1500 lines below uses these globals. We'll have to + # clean this up sometime, probably. For now, we just pull them out + # of %args. -Ken + + $cplusplus = $args{'C++'}; + $hiertype = $args{hiertype}; + $WantPrototypes = $args{prototypes}; + $WantVersionChk = $args{versioncheck}; + $except = $args{except} ? ' TRY' : ''; + $WantLineNumbers = $args{linenumbers}; + $WantOptimize = $args{optimize}; + $process_inout = $args{inout}; + $process_argtypes = $args{argtypes}; + @tm = ref $args{typemap} ? @{$args{typemap}} : ($args{typemap}); + + for ($args{filename}) { + die "Missing required parameter 'filename'" unless $_; + $filepathname = $_; + ($dir, $filename) = (dirname($_), basename($_)); + $filepathname =~ s/\\/\\\\/g; + $IncludedFiles{$_}++; + } + + # Open the input file + open($FH, $args{filename}) or die "cannot open $args{filename}: $!\n"; + + # Open the output file if given as a string. If they provide some + # other kind of reference, trust them that we can print to it. + if (not ref $args{output}) { + open my($fh), "> $args{output}" or die "Can't create $args{output}: $!"; + $args{outfile} = $args{output}; + $args{output} = $fh; + } + + # Really, we shouldn't have to chdir() or select() in the first + # place. For now, just save & restore. + my $orig_cwd = cwd(); + my $orig_fh = select(); + + chdir($dir); + my $pwd = cwd(); + my $csuffix = $args{csuffix}; + + if ($WantLineNumbers) { + my $cfile; + if ( $args{outfile} ) { + $cfile = $args{outfile}; + } else { + $cfile = $args{filename}; + $cfile =~ s/\.xs$/$csuffix/i or $cfile .= $csuffix; + } + tie(*PSEUDO_STDOUT, 'ExtUtils::ParseXS::CountLines', $cfile, $args{output}); + select PSEUDO_STDOUT; + } else { + select $args{output}; + } + + foreach my $typemap (@tm) { + die "Can't find $typemap in $pwd\n" unless -r $typemap; + } + + push @tm, standard_typemap_locations(); + + foreach my $typemap (@tm) { + next unless -f $typemap ; + # skip directories, binary files etc. + warn("Warning: ignoring non-text typemap file '$typemap'\n"), next + unless -T $typemap ; + open(TYPEMAP, $typemap) + or warn ("Warning: could not open typemap file '$typemap': $!\n"), next; + my $mode = 'Typemap'; + my $junk = "" ; + my $current = \$junk; + while (<TYPEMAP>) { + next if /^\s* #/; + my $line_no = $. + 1; + if (/^INPUT\s*$/) { + $mode = 'Input'; $current = \$junk; next; + } + if (/^OUTPUT\s*$/) { + $mode = 'Output'; $current = \$junk; next; + } + if (/^TYPEMAP\s*$/) { + $mode = 'Typemap'; $current = \$junk; next; + } + if ($mode eq 'Typemap') { + chomp; + my $line = $_ ; + TrimWhitespace($_) ; + # skip blank lines and comment lines + next if /^$/ or /^#/ ; + my($type,$kind, $proto) = /^\s*(.*?\S)\s+(\S+)\s*($proto_re*)\s*$/ or + warn("Warning: File '$typemap' Line $. '$line' TYPEMAP entry needs 2 or 3 columns\n"), next; + $type = TidyType($type) ; + $type_kind{$type} = $kind ; + # prototype defaults to '$' + $proto = "\$" unless $proto ; + warn("Warning: File '$typemap' Line $. '$line' Invalid prototype '$proto'\n") + unless ValidProtoString($proto) ; + $proto_letter{$type} = C_string($proto) ; + } elsif (/^\s/) { + $$current .= $_; + } elsif ($mode eq 'Input') { + s/\s+$//; + $input_expr{$_} = ''; + $current = \$input_expr{$_}; + } else { + s/\s+$//; + $output_expr{$_} = ''; + $current = \$output_expr{$_}; + } + } + close(TYPEMAP); + } + + foreach my $value (values %input_expr) { + $value =~ s/;*\s+\z//; + # Move C pre-processor instructions to column 1 to be strictly ANSI + # conformant. Some pre-processors are fussy about this. + $value =~ s/^\s+#/#/mg; + } + foreach my $value (values %output_expr) { + # And again. + $value =~ s/^\s+#/#/mg; + } + + my ($cast, $size); + our $bal = qr[(?:(?>[^()]+)|\((??{ $bal })\))*]; # ()-balanced + $cast = qr[(?:\(\s*SV\s*\*\s*\)\s*)?]; # Optional (SV*) cast + $size = qr[,\s* (??{ $bal }) ]x; # Third arg (to setpvn) + + foreach my $key (keys %output_expr) { + # We can still bootstrap compile 're', because in code re.pm is + # available to miniperl, and does not attempt to load the XS code. + use re 'eval'; + + my ($t, $with_size, $arg, $sarg) = + ($output_expr{$key} =~ + m[^ \s+ sv_set ( [iunp] ) v (n)? # Type, is_setpvn + \s* \( \s* $cast \$arg \s* , + \s* ( (??{ $bal }) ) # Set from + ( (??{ $size }) )? # Possible sizeof set-from + \) \s* ; \s* $ + ]x); + $targetable{$key} = [$t, $with_size, $arg, $sarg] if $t; + } + + my $END = "!End!\n\n"; # "impossible" keyword (multiple newline) + + # Match an XS keyword + $BLOCK_re= '\s*(' . join('|', qw( + REQUIRE BOOT CASE PREINIT INPUT INIT CODE PPCODE OUTPUT + CLEANUP ALIAS ATTRS PROTOTYPES PROTOTYPE VERSIONCHECK INCLUDE + SCOPE INTERFACE INTERFACE_MACRO C_ARGS POSTCALL OVERLOAD FALLBACK + )) . "|$END)\\s*:"; + + + our ($C_group_rex, $C_arg); + # Group in C (no support for comments or literals) + $C_group_rex = qr/ [({\[] + (?: (?> [^()\[\]{}]+ ) | (??{ $C_group_rex }) )* + [)}\]] /x ; + # Chunk in C without comma at toplevel (no comments): + $C_arg = qr/ (?: (?> [^()\[\]{},"']+ ) + | (??{ $C_group_rex }) + | " (?: (?> [^\\"]+ ) + | \\. + )* " # String literal + | ' (?: (?> [^\\']+ ) | \\. )* ' # Char literal + )* /xs; + + # Identify the version of xsubpp used + print <<EOM ; +/* + * This file was generated automatically by ExtUtils::ParseXS version $VERSION from the + * contents of $filename. Do not edit this file, edit $filename instead. + * + * ANY CHANGES MADE HERE WILL BE LOST! + * + */ + +EOM + + + print("#line 1 \"$filepathname\"\n") + if $WantLineNumbers; + + firstmodule: + while (<$FH>) { + if (/^=/) { + my $podstartline = $.; + do { + if (/^=cut\s*$/) { + # We can't just write out a /* */ comment, as our embedded + # POD might itself be in a comment. We can't put a /**/ + # comment inside #if 0, as the C standard says that the source + # file is decomposed into preprocessing characters in the stage + # before preprocessing commands are executed. + # I don't want to leave the text as barewords, because the spec + # isn't clear whether macros are expanded before or after + # preprocessing commands are executed, and someone pathological + # may just have defined one of the 3 words as a macro that does + # something strange. Multiline strings are illegal in C, so + # the "" we write must be a string literal. And they aren't + # concatenated until 2 steps later, so we are safe. + # - Nicholas Clark + print("#if 0\n \"Skipped embedded POD.\"\n#endif\n"); + printf("#line %d \"$filepathname\"\n", $. + 1) + if $WantLineNumbers; + next firstmodule + } + + } while (<$FH>); + # At this point $. is at end of file so die won't state the start + # of the problem, and as we haven't yet read any lines &death won't + # show the correct line in the message either. + die ("Error: Unterminated pod in $filename, line $podstartline\n") + unless $lastline; + } + last if ($Package, $Prefix) = + /^MODULE\s*=\s*[\w:]+(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/; + + print $_; + } + unless (defined $_) { + warn "Didn't find a 'MODULE ... PACKAGE ... PREFIX' line\n"; + exit 0; # Not a fatal error for the caller process + } + + print 'ExtUtils::ParseXS::CountLines'->end_marker, "\n" if $WantLineNumbers; + + print <<"EOF"; +#ifndef PERL_UNUSED_VAR +# define PERL_UNUSED_VAR(var) if (0) var = var +#endif + +EOF + + print <<"EOF"; +#ifndef PERL_ARGS_ASSERT_CROAK_XS_USAGE +#define PERL_ARGS_ASSERT_CROAK_XS_USAGE assert(cv); assert(params) + +/* prototype to pass -Wmissing-prototypes */ +STATIC void +S_croak_xs_usage(pTHX_ const CV *const cv, const char *const params); + +STATIC void +S_croak_xs_usage(pTHX_ const CV *const cv, const char *const params) +{ + const GV *const gv = CvGV(cv); + + PERL_ARGS_ASSERT_CROAK_XS_USAGE; + + if (gv) { + const char *const gvname = GvNAME(gv); + const HV *const stash = GvSTASH(gv); + const char *const hvname = stash ? HvNAME(stash) : NULL; + + if (hvname) + Perl_croak(aTHX_ "Usage: %s::%s(%s)", hvname, gvname, params); + else + Perl_croak(aTHX_ "Usage: %s(%s)", gvname, params); + } else { + /* Pants. I don't think that it should be possible to get here. */ + Perl_croak(aTHX_ "Usage: CODE(0x%"UVxf")(%s)", PTR2UV(cv), params); + } +} +#undef PERL_ARGS_ASSERT_CROAK_XS_USAGE + +#ifdef PERL_IMPLICIT_CONTEXT +#define croak_xs_usage(a,b) S_croak_xs_usage(aTHX_ a,b) +#else +#define croak_xs_usage S_croak_xs_usage +#endif + +#endif + +/* NOTE: the prototype of newXSproto() is different in versions of perls, + * so we define a portable version of newXSproto() + */ +#ifdef newXS_flags +#define newXSproto_portable(name, c_impl, file, proto) newXS_flags(name, c_impl, file, proto, 0) +#else +#define newXSproto_portable(name, c_impl, file, proto) (PL_Sv=(SV*)newXS(name, c_impl, file), sv_setpv(PL_Sv, proto), (CV*)PL_Sv) +#endif /* !defined(newXS_flags) */ + +EOF + + print 'ExtUtils::ParseXS::CountLines'->end_marker, "\n" if $WantLineNumbers; + + $lastline = $_; + $lastline_no = $.; + + PARAGRAPH: + while (fetch_para()) { + # Print initial preprocessor statements and blank lines + while (@line && $line[0] !~ /^[^\#]/) { + my $line = shift(@line); + print $line, "\n"; + next unless $line =~ /^\#\s*((if)(?:n?def)?|elsif|else|endif)\b/; + my $statement = $+; + if ($statement eq 'if') { + $XSS_work_idx = @XSStack; + push(@XSStack, {type => 'if'}); + } else { + death ("Error: `$statement' with no matching `if'") + if $XSStack[-1]{type} ne 'if'; + if ($XSStack[-1]{varname}) { + push(@InitFileCode, "#endif\n"); + push(@BootCode, "#endif"); + } + + my(@fns) = keys %{$XSStack[-1]{functions}}; + if ($statement ne 'endif') { + # Hide the functions defined in other #if branches, and reset. + @{$XSStack[-1]{other_functions}}{@fns} = (1) x @fns; + @{$XSStack[-1]}{qw(varname functions)} = ('', {}); + } else { + my($tmp) = pop(@XSStack); + 0 while (--$XSS_work_idx + && $XSStack[$XSS_work_idx]{type} ne 'if'); + # Keep all new defined functions + push(@fns, keys %{$tmp->{other_functions}}); + @{$XSStack[$XSS_work_idx]{functions}}{@fns} = (1) x @fns; + } + } + } + + next PARAGRAPH unless @line; + + if ($XSS_work_idx && !$XSStack[$XSS_work_idx]{varname}) { + # We are inside an #if, but have not yet #defined its xsubpp variable. + print "#define $cpp_next_tmp 1\n\n"; + push(@InitFileCode, "#if $cpp_next_tmp\n"); + push(@BootCode, "#if $cpp_next_tmp"); + $XSStack[$XSS_work_idx]{varname} = $cpp_next_tmp++; + } + + death ("Code is not inside a function" + ." (maybe last function was ended by a blank line " + ." followed by a statement on column one?)") + if $line[0] =~ /^\s/; + + my ($class, $externC, $static, $ellipsis, $wantRETVAL, $RETVAL_no_return); + my (@fake_INPUT_pre); # For length(s) generated variables + my (@fake_INPUT); + + # initialize info arrays + undef(%args_match); + undef(%var_types); + undef(%defaults); + undef(%arg_list) ; + undef(@proto_arg) ; + undef($processing_arg_with_types) ; + undef(%argtype_seen) ; + undef(@outlist) ; + undef(%in_out) ; + undef(%lengthof) ; + undef($proto_in_this_xsub) ; + undef($scope_in_this_xsub) ; + undef($interface); + undef($prepush_done); + $interface_macro = 'XSINTERFACE_FUNC' ; + $interface_macro_set = 'XSINTERFACE_FUNC_SET' ; + $ProtoThisXSUB = $WantPrototypes ; + $ScopeThisXSUB = 0; + $xsreturn = 0; + + $_ = shift(@line); + while (my $kwd = check_keyword("REQUIRE|PROTOTYPES|FALLBACK|VERSIONCHECK|INCLUDE|SCOPE")) { + &{"${kwd}_handler"}() ; + next PARAGRAPH unless @line ; + $_ = shift(@line); + } + + if (check_keyword("BOOT")) { + &check_cpp; + push (@BootCode, "#line $line_no[@line_no - @line] \"$filepathname\"") + if $WantLineNumbers && $line[0] !~ /^\s*#\s*line\b/; + push (@BootCode, @line, "") ; + next PARAGRAPH ; + } + + + # extract return type, function name and arguments + ($ret_type) = TidyType($_); + $RETVAL_no_return = 1 if $ret_type =~ s/^NO_OUTPUT\s+//; + + # Allow one-line ANSI-like declaration + unshift @line, $2 + if $process_argtypes + and $ret_type =~ s/^(.*?\w.*?)\s*\b(\w+\s*\(.*)/$1/s; + + # a function definition needs at least 2 lines + blurt ("Error: Function definition too short '$ret_type'"), next PARAGRAPH + unless @line ; + + $externC = 1 if $ret_type =~ s/^extern "C"\s+//; + $static = 1 if $ret_type =~ s/^static\s+//; + + $func_header = shift(@line); + blurt ("Error: Cannot parse function definition from '$func_header'"), next PARAGRAPH + unless $func_header =~ /^(?:([\w:]*)::)?(\w+)\s*\(\s*(.*?)\s*\)\s*(const)?\s*(;\s*)?$/s; + + ($class, $func_name, $orig_args) = ($1, $2, $3) ; + $class = "$4 $class" if $4; + ($pname = $func_name) =~ s/^($Prefix)?/$Packprefix/; + ($clean_func_name = $func_name) =~ s/^$Prefix//; + $Full_func_name = "${Packid}_$clean_func_name"; + if ($Is_VMS) { + $Full_func_name = $SymSet->addsym($Full_func_name); + } + + # Check for duplicate function definition + for my $tmp (@XSStack) { + next unless defined $tmp->{functions}{$Full_func_name}; + Warn("Warning: duplicate function definition '$clean_func_name' detected"); + last; + } + $XSStack[$XSS_work_idx]{functions}{$Full_func_name} ++ ; + %XsubAliases = %XsubAliasValues = %Interfaces = @Attributes = (); + $DoSetMagic = 1; + + $orig_args =~ s/\\\s*/ /g; # process line continuations + my @args; + + my %only_C_inlist; # Not in the signature of Perl function + if ($process_argtypes and $orig_args =~ /\S/) { + my $args = "$orig_args ,"; + if ($args =~ /^( (??{ $C_arg }) , )* $ /x) { + @args = ($args =~ /\G ( (??{ $C_arg }) ) , /xg); + for ( @args ) { + s/^\s+//; + s/\s+$//; + my ($arg, $default) = / ( [^=]* ) ( (?: = .* )? ) /x; + my ($pre, $name) = ($arg =~ /(.*?) \s* + \b ( \w+ | length\( \s*\w+\s* \) ) + \s* $ /x); + next unless defined($pre) && length($pre); + my $out_type = ''; + my $inout_var; + if ($process_inout and s/^(IN|IN_OUTLIST|OUTLIST|OUT|IN_OUT)\s+//) { + my $type = $1; + $out_type = $type if $type ne 'IN'; + $arg =~ s/^(IN|IN_OUTLIST|OUTLIST|OUT|IN_OUT)\s+//; + $pre =~ s/^(IN|IN_OUTLIST|OUTLIST|OUT|IN_OUT)\s+//; + } + my $islength; + if ($name =~ /^length\( \s* (\w+) \s* \)\z/x) { + $name = "XSauto_length_of_$1"; + $islength = 1; + die "Default value on length() argument: `$_'" + if length $default; + } + if (length $pre or $islength) { # Has a type + if ($islength) { + push @fake_INPUT_pre, $arg; + } else { + push @fake_INPUT, $arg; + } + # warn "pushing '$arg'\n"; + $argtype_seen{$name}++; + $_ = "$name$default"; # Assigns to @args + } + $only_C_inlist{$_} = 1 if $out_type eq "OUTLIST" or $islength; + push @outlist, $name if $out_type =~ /OUTLIST$/; + $in_out{$name} = $out_type if $out_type; + } + } else { + @args = split(/\s*,\s*/, $orig_args); + Warn("Warning: cannot parse argument list '$orig_args', fallback to split"); + } + } else { + @args = split(/\s*,\s*/, $orig_args); + for (@args) { + if ($process_inout and s/^(IN|IN_OUTLIST|OUTLIST|IN_OUT|OUT)\s+//) { + my $out_type = $1; + next if $out_type eq 'IN'; + $only_C_inlist{$_} = 1 if $out_type eq "OUTLIST"; + push @outlist, $name if $out_type =~ /OUTLIST$/; + $in_out{$_} = $out_type; + } + } + } + if (defined($class)) { + my $arg0 = ((defined($static) or $func_name eq 'new') + ? "CLASS" : "THIS"); + unshift(@args, $arg0); + } + my $extra_args = 0; + @args_num = (); + $num_args = 0; + my $report_args = ''; + foreach my $i (0 .. $#args) { + if ($args[$i] =~ s/\.\.\.//) { + $ellipsis = 1; + if ($args[$i] eq '' && $i == $#args) { + $report_args .= ", ..."; + pop(@args); + last; + } + } + if ($only_C_inlist{$args[$i]}) { + push @args_num, undef; + } else { + push @args_num, ++$num_args; + $report_args .= ", $args[$i]"; + } + if ($args[$i] =~ /^([^=]*[^\s=])\s*=\s*(.*)/s) { + $extra_args++; + $args[$i] = $1; + $defaults{$args[$i]} = $2; + $defaults{$args[$i]} =~ s/"/\\"/g; + } + $proto_arg[$i+1] = '$' ; + } + $min_args = $num_args - $extra_args; + $report_args =~ s/"/\\"/g; + $report_args =~ s/^,\s+//; + my @func_args = @args; + shift @func_args if defined($class); + + for (@func_args) { + s/^/&/ if $in_out{$_}; + } + $func_args = join(", ", @func_args); + @args_match{@args} = @args_num; + + $PPCODE = grep(/^\s*PPCODE\s*:/, @line); + $CODE = grep(/^\s*CODE\s*:/, @line); + # Detect CODE: blocks which use ST(n)= or XST_m*(n,v) + # to set explicit return values. + $EXPLICIT_RETURN = ($CODE && + ("@line" =~ /(\bST\s*\([^;]*=) | (\bXST_m\w+\s*\()/x )); + $ALIAS = grep(/^\s*ALIAS\s*:/, @line); + $INTERFACE = grep(/^\s*INTERFACE\s*:/, @line); + + $xsreturn = 1 if $EXPLICIT_RETURN; + + $externC = $externC ? qq[extern "C"] : ""; + + # print function header + print Q(<<"EOF"); +#$externC +#XS(XS_${Full_func_name}); /* prototype to pass -Wmissing-prototypes */ +#XS(XS_${Full_func_name}) +#[[ +##ifdef dVAR +# dVAR; dXSARGS; +##else +# dXSARGS; +##endif +EOF + print Q(<<"EOF") if $ALIAS ; +# dXSI32; +EOF + print Q(<<"EOF") if $INTERFACE ; +# dXSFUNCTION($ret_type); +EOF + if ($ellipsis) { + $cond = ($min_args ? qq(items < $min_args) : 0); + } elsif ($min_args == $num_args) { + $cond = qq(items != $min_args); + } else { + $cond = qq(items < $min_args || items > $num_args); + } + + print Q(<<"EOF") if $except; +# char errbuf[1024]; +# *errbuf = '\0'; +EOF + + if($cond) { + print Q(<<"EOF"); +# if ($cond) +# croak_xs_usage(cv, "$report_args"); +EOF + } else { + # cv likely to be unused + print Q(<<"EOF"); +# PERL_UNUSED_VAR(cv); /* -W */ +EOF + } + + #gcc -Wall: if an xsub has PPCODE is used + #it is possible none of ST, XSRETURN or XSprePUSH macros are used + #hence `ax' (setup by dXSARGS) is unused + #XXX: could breakup the dXSARGS; into dSP;dMARK;dITEMS + #but such a move could break third-party extensions + print Q(<<"EOF") if $PPCODE; +# PERL_UNUSED_VAR(ax); /* -Wall */ +EOF + + print Q(<<"EOF") if $PPCODE; +# SP -= items; +EOF + + # Now do a block of some sort. + + $condnum = 0; + $cond = ''; # last CASE: condidional + push(@line, "$END:"); + push(@line_no, $line_no[-1]); + $_ = ''; + &check_cpp; + while (@line) { + &CASE_handler if check_keyword("CASE"); + print Q(<<"EOF"); +# $except [[ +EOF + + # do initialization of input variables + $thisdone = 0; + $retvaldone = 0; + $deferred = ""; + %arg_list = () ; + $gotRETVAL = 0; + + INPUT_handler() ; + process_keyword("INPUT|PREINIT|INTERFACE_MACRO|C_ARGS|ALIAS|ATTRS|PROTOTYPE|SCOPE|OVERLOAD") ; + + print Q(<<"EOF") if $ScopeThisXSUB; +# ENTER; +# [[ +EOF + + if (!$thisdone && defined($class)) { + if (defined($static) or $func_name eq 'new') { + print "\tchar *"; + $var_types{"CLASS"} = "char *"; + &generate_init("char *", 1, "CLASS"); + } + else { + print "\t$class *"; + $var_types{"THIS"} = "$class *"; + &generate_init("$class *", 1, "THIS"); + } + } + + # do code + if (/^\s*NOT_IMPLEMENTED_YET/) { + print "\n\tPerl_croak(aTHX_ \"$pname: not implemented yet\");\n"; + $_ = '' ; + } else { + if ($ret_type ne "void") { + print "\t" . &map_type($ret_type, 'RETVAL') . ";\n" + if !$retvaldone; + $args_match{"RETVAL"} = 0; + $var_types{"RETVAL"} = $ret_type; + print "\tdXSTARG;\n" + if $WantOptimize and $targetable{$type_kind{$ret_type}}; + } + + if (@fake_INPUT or @fake_INPUT_pre) { + unshift @line, @fake_INPUT_pre, @fake_INPUT, $_; + $_ = ""; + $processing_arg_with_types = 1; + INPUT_handler() ; + } + print $deferred; + + process_keyword("INIT|ALIAS|ATTRS|PROTOTYPE|INTERFACE_MACRO|INTERFACE|C_ARGS|OVERLOAD") ; + + if (check_keyword("PPCODE")) { + print_section(); + death ("PPCODE must be last thing") if @line; + print "\tLEAVE;\n" if $ScopeThisXSUB; + print "\tPUTBACK;\n\treturn;\n"; + } elsif (check_keyword("CODE")) { + print_section() ; + } elsif (defined($class) and $func_name eq "DESTROY") { + print "\n\t"; + print "delete THIS;\n"; + } else { + print "\n\t"; + if ($ret_type ne "void") { + print "RETVAL = "; + $wantRETVAL = 1; + } + if (defined($static)) { + if ($func_name eq 'new') { + $func_name = "$class"; + } else { + print "${class}::"; + } + } elsif (defined($class)) { + if ($func_name eq 'new') { + $func_name .= " $class"; + } else { + print "THIS->"; + } + } + $func_name =~ s/^\Q$args{'s'}// + if exists $args{'s'}; + $func_name = 'XSFUNCTION' if $interface; + print "$func_name($func_args);\n"; + } + } + + # do output variables + $gotRETVAL = 0; # 1 if RETVAL seen in OUTPUT section; + undef $RETVAL_code ; # code to set RETVAL (from OUTPUT section); + # $wantRETVAL set if 'RETVAL =' autogenerated + ($wantRETVAL, $ret_type) = (0, 'void') if $RETVAL_no_return; + undef %outargs ; + process_keyword("POSTCALL|OUTPUT|ALIAS|ATTRS|PROTOTYPE|OVERLOAD"); + + &generate_output($var_types{$_}, $args_match{$_}, $_, $DoSetMagic) + for grep $in_out{$_} =~ /OUT$/, keys %in_out; + + # all OUTPUT done, so now push the return value on the stack + if ($gotRETVAL && $RETVAL_code) { + print "\t$RETVAL_code\n"; + } elsif ($gotRETVAL || $wantRETVAL) { + my $t = $WantOptimize && $targetable{$type_kind{$ret_type}}; + my $var = 'RETVAL'; + my $type = $ret_type; + + # 0: type, 1: with_size, 2: how, 3: how_size + if ($t and not $t->[1] and $t->[0] eq 'p') { + # PUSHp corresponds to setpvn. Treate setpv directly + my $what = eval qq("$t->[2]"); + warn $@ if $@; + + print "\tsv_setpv(TARG, $what); XSprePUSH; PUSHTARG;\n"; + $prepush_done = 1; + } + elsif ($t) { + my $what = eval qq("$t->[2]"); + warn $@ if $@; + + my $size = $t->[3]; + $size = '' unless defined $size; + $size = eval qq("$size"); + warn $@ if $@; + print "\tXSprePUSH; PUSH$t->[0]($what$size);\n"; + $prepush_done = 1; + } + else { + # RETVAL almost never needs SvSETMAGIC() + &generate_output($ret_type, 0, 'RETVAL', 0); + } + } + + $xsreturn = 1 if $ret_type ne "void"; + my $num = $xsreturn; + my $c = @outlist; + print "\tXSprePUSH;" if $c and not $prepush_done; + print "\tEXTEND(SP,$c);\n" if $c; + $xsreturn += $c; + generate_output($var_types{$_}, $num++, $_, 0, 1) for @outlist; + + # do cleanup + process_keyword("CLEANUP|ALIAS|ATTRS|PROTOTYPE|OVERLOAD") ; + + print Q(<<"EOF") if $ScopeThisXSUB; +# ]] +EOF + print Q(<<"EOF") if $ScopeThisXSUB and not $PPCODE; +# LEAVE; +EOF + + # print function trailer + print Q(<<"EOF"); +# ]] +EOF + print Q(<<"EOF") if $except; +# BEGHANDLERS +# CATCHALL +# sprintf(errbuf, "%s: %s\\tpropagated", Xname, Xreason); +# ENDHANDLERS +EOF + if (check_keyword("CASE")) { + blurt ("Error: No `CASE:' at top of function") + unless $condnum; + $_ = "CASE: $_"; # Restore CASE: label + next; + } + last if $_ eq "$END:"; + death(/^$BLOCK_re/o ? "Misplaced `$1:'" : "Junk at end of function ($_)"); + } + + print Q(<<"EOF") if $except; +# if (errbuf[0]) +# Perl_croak(aTHX_ errbuf); +EOF + + if ($xsreturn) { + print Q(<<"EOF") unless $PPCODE; +# XSRETURN($xsreturn); +EOF + } else { + print Q(<<"EOF") unless $PPCODE; +# XSRETURN_EMPTY; +EOF + } + + print Q(<<"EOF"); +#]] +# +EOF + + our $newXS = "newXS" ; + our $proto = "" ; + + # Build the prototype string for the xsub + if ($ProtoThisXSUB) { + $newXS = "newXSproto_portable"; + + if ($ProtoThisXSUB eq 2) { + # User has specified empty prototype + } + elsif ($ProtoThisXSUB eq 1) { + my $s = ';'; + if ($min_args < $num_args) { + $s = ''; + $proto_arg[$min_args] .= ";" ; + } + push @proto_arg, "$s\@" + if $ellipsis ; + + $proto = join ("", grep defined, @proto_arg); + } + else { + # User has specified a prototype + $proto = $ProtoThisXSUB; + } + $proto = qq{, "$proto"}; + } + + if (%XsubAliases) { + $XsubAliases{$pname} = 0 + unless defined $XsubAliases{$pname} ; + while ( ($name, $value) = each %XsubAliases) { + push(@InitFileCode, Q(<<"EOF")); +# cv = ${newXS}(\"$name\", XS_$Full_func_name, file$proto); +# XSANY.any_i32 = $value ; +EOF + } + } + elsif (@Attributes) { + push(@InitFileCode, Q(<<"EOF")); +# cv = ${newXS}(\"$pname\", XS_$Full_func_name, file$proto); +# apply_attrs_string("$Package", cv, "@Attributes", 0); +EOF + } + elsif ($interface) { + while ( ($name, $value) = each %Interfaces) { + $name = "$Package\::$name" unless $name =~ /::/; + push(@InitFileCode, Q(<<"EOF")); +# cv = ${newXS}(\"$name\", XS_$Full_func_name, file$proto); +# $interface_macro_set(cv,$value) ; +EOF + } + } + else { + push(@InitFileCode, + " (void)${newXS}(\"$pname\", XS_$Full_func_name, file$proto);\n"); + } + } + + if ($Overload) # make it findable with fetchmethod + { + print Q(<<"EOF"); +#XS(XS_${Packid}_nil); /* prototype to pass -Wmissing-prototypes */ +#XS(XS_${Packid}_nil) +#{ +# dXSARGS; +# XSRETURN_EMPTY; +#} +# +EOF + unshift(@InitFileCode, <<"MAKE_FETCHMETHOD_WORK"); + /* Making a sub named "${Package}::()" allows the package */ + /* to be findable via fetchmethod(), and causes */ + /* overload::Overloaded("${Package}") to return true. */ + (void)${newXS}("${Package}::()", XS_${Packid}_nil, file$proto); +MAKE_FETCHMETHOD_WORK + } + + # print initialization routine + + print Q(<<"EOF"); +##ifdef __cplusplus +#extern "C" +##endif +EOF + + print Q(<<"EOF"); +#XS(boot_$Module_cname); /* prototype to pass -Wmissing-prototypes */ +#XS(boot_$Module_cname) +EOF + + print Q(<<"EOF"); +#[[ +##ifdef dVAR +# dVAR; dXSARGS; +##else +# dXSARGS; +##endif +EOF + + #Under 5.8.x and lower, newXS is declared in proto.h as expecting a non-const + #file name argument. If the wrong qualifier is used, it causes breakage with + #C++ compilers and warnings with recent gcc. + #-Wall: if there is no $Full_func_name there are no xsubs in this .xs + #so `file' is unused + print Q(<<"EOF") if $Full_func_name; +##if (PERL_REVISION == 5 && PERL_VERSION < 9) +# char* file = __FILE__; +##else +# const char* file = __FILE__; +##endif +EOF + + print Q("#\n"); + + print Q(<<"EOF"); +# PERL_UNUSED_VAR(cv); /* -W */ +# PERL_UNUSED_VAR(items); /* -W */ +EOF + + print Q(<<"EOF") if $WantVersionChk ; +# XS_VERSION_BOOTCHECK ; +# +EOF + + print Q(<<"EOF") if defined $XsubAliases or defined $Interfaces ; +# { +# CV * cv ; +# +EOF + + print Q(<<"EOF") if ($Overload); +# /* register the overloading (type 'A') magic */ +# PL_amagic_generation++; +# /* The magic for overload gets a GV* via gv_fetchmeth as */ +# /* mentioned above, and looks in the SV* slot of it for */ +# /* the "fallback" status. */ +# sv_setsv( +# get_sv( "${Package}::()", TRUE ), +# $Fallback +# ); +EOF + + print @InitFileCode; + + print Q(<<"EOF") if defined $XsubAliases or defined $Interfaces ; +# } +EOF + + if (@BootCode) + { + print "\n /* Initialisation Section */\n\n" ; + @line = @BootCode; + print_section(); + print "\n /* End of Initialisation Section */\n\n" ; + } + + print Q(<<'EOF'); +##if (PERL_REVISION == 5 && PERL_VERSION >= 9) +# if (PL_unitcheckav) +# call_list(PL_scopestack_ix, PL_unitcheckav); +##endif +EOF + + print Q(<<"EOF"); +# XSRETURN_YES; +#]] +# +EOF + + warn("Please specify prototyping behavior for $filename (see perlxs manual)\n") + unless $ProtoUsed ; + + chdir($orig_cwd); + select($orig_fh); + untie *PSEUDO_STDOUT if tied *PSEUDO_STDOUT; + close $FH; + + return 1; +} + +sub errors { $errors } + +sub standard_typemap_locations { + # Add all the default typemap locations to the search path + my @tm = qw(typemap); + + my $updir = File::Spec->updir; + foreach my $dir (File::Spec->catdir(($updir) x 1), File::Spec->catdir(($updir) x 2), + File::Spec->catdir(($updir) x 3), File::Spec->catdir(($updir) x 4)) { + + unshift @tm, File::Spec->catfile($dir, 'typemap'); + unshift @tm, File::Spec->catfile($dir, lib => ExtUtils => 'typemap'); + } + foreach my $dir (@INC) { + my $file = File::Spec->catfile($dir, ExtUtils => 'typemap'); + unshift @tm, $file if -e $file; + } + return @tm; +} + +sub TrimWhitespace +{ + $_[0] =~ s/^\s+|\s+$//go ; +} + +sub TidyType + { + local ($_) = @_ ; + + # rationalise any '*' by joining them into bunches and removing whitespace + s#\s*(\*+)\s*#$1#g; + s#(\*+)# $1 #g ; + + # change multiple whitespace into a single space + s/\s+/ /g ; + + # trim leading & trailing whitespace + TrimWhitespace($_) ; + + $_ ; +} + +# Input: ($_, @line) == unparsed input. +# Output: ($_, @line) == (rest of line, following lines). +# Return: the matched keyword if found, otherwise 0 +sub check_keyword { + $_ = shift(@line) while !/\S/ && @line; + s/^(\s*)($_[0])\s*:\s*(?:#.*)?/$1/s && $2; +} + +sub print_section { + # the "do" is required for right semantics + do { $_ = shift(@line) } while !/\S/ && @line; + + print("#line ", $line_no[@line_no - @line -1], " \"$filepathname\"\n") + if $WantLineNumbers && !/^\s*#\s*line\b/ && !/^#if XSubPPtmp/; + for (; defined($_) && !/^$BLOCK_re/o; $_ = shift(@line)) { + print "$_\n"; + } + print 'ExtUtils::ParseXS::CountLines'->end_marker, "\n" if $WantLineNumbers; +} + +sub merge_section { + my $in = ''; + + while (!/\S/ && @line) { + $_ = shift(@line); + } + + for (; defined($_) && !/^$BLOCK_re/o; $_ = shift(@line)) { + $in .= "$_\n"; + } + chomp $in; + return $in; + } + +sub process_keyword($) + { + my($pattern) = @_ ; + my $kwd ; + + &{"${kwd}_handler"}() + while $kwd = check_keyword($pattern) ; + } + +sub CASE_handler { + blurt ("Error: `CASE:' after unconditional `CASE:'") + if $condnum && $cond eq ''; + $cond = $_; + TrimWhitespace($cond); + print " ", ($condnum++ ? " else" : ""), ($cond ? " if ($cond)\n" : "\n"); + $_ = '' ; +} + +sub INPUT_handler { + for (; !/^$BLOCK_re/o; $_ = shift(@line)) { + last if /^\s*NOT_IMPLEMENTED_YET/; + next unless /\S/; # skip blank lines + + TrimWhitespace($_) ; + my $line = $_ ; + + # remove trailing semicolon if no initialisation + s/\s*;$//g unless /[=;+].*\S/ ; + + # Process the length(foo) declarations + if (s/^([^=]*)\blength\(\s*(\w+)\s*\)\s*$/$1 XSauto_length_of_$2=NO_INIT/x) { + print "\tSTRLEN\tSTRLEN_length_of_$2;\n"; + $lengthof{$2} = $name; + # $islengthof{$name} = $1; + $deferred .= "\n\tXSauto_length_of_$2 = STRLEN_length_of_$2;\n"; + } + + # check for optional initialisation code + my $var_init = '' ; + $var_init = $1 if s/\s*([=;+].*)$//s ; + $var_init =~ s/"/\\"/g; + + s/\s+/ /g; + my ($var_type, $var_addr, $var_name) = /^(.*?[^&\s])\s*(\&?)\s*\b(\w+)$/s + or blurt("Error: invalid argument declaration '$line'"), next; + + # Check for duplicate definitions + blurt ("Error: duplicate definition of argument '$var_name' ignored"), next + if $arg_list{$var_name}++ + or defined $argtype_seen{$var_name} and not $processing_arg_with_types; + + $thisdone |= $var_name eq "THIS"; + $retvaldone |= $var_name eq "RETVAL"; + $var_types{$var_name} = $var_type; + # XXXX This check is a safeguard against the unfinished conversion of + # generate_init(). When generate_init() is fixed, + # one can use 2-args map_type() unconditionally. + if ($var_type =~ / \( \s* \* \s* \) /x) { + # Function pointers are not yet supported with &output_init! + print "\t" . &map_type($var_type, $var_name); + $name_printed = 1; + } else { + print "\t" . &map_type($var_type); + $name_printed = 0; + } + $var_num = $args_match{$var_name}; + + $proto_arg[$var_num] = ProtoString($var_type) + if $var_num ; + $func_args =~ s/\b($var_name)\b/&$1/ if $var_addr; + if ($var_init =~ /^[=;]\s*NO_INIT\s*;?\s*$/ + or $in_out{$var_name} and $in_out{$var_name} =~ /^OUT/ + and $var_init !~ /\S/) { + if ($name_printed) { + print ";\n"; + } else { + print "\t$var_name;\n"; + } + } elsif ($var_init =~ /\S/) { + &output_init($var_type, $var_num, $var_name, $var_init, $name_printed); + } elsif ($var_num) { + # generate initialization code + &generate_init($var_type, $var_num, $var_name, $name_printed); + } else { + print ";\n"; + } + } +} + +sub OUTPUT_handler { + for (; !/^$BLOCK_re/o; $_ = shift(@line)) { + next unless /\S/; + if (/^\s*SETMAGIC\s*:\s*(ENABLE|DISABLE)\s*/) { + $DoSetMagic = ($1 eq "ENABLE" ? 1 : 0); + next; + } + my ($outarg, $outcode) = /^\s*(\S+)\s*(.*?)\s*$/s ; + blurt ("Error: duplicate OUTPUT argument '$outarg' ignored"), next + if $outargs{$outarg} ++ ; + if (!$gotRETVAL and $outarg eq 'RETVAL') { + # deal with RETVAL last + $RETVAL_code = $outcode ; + $gotRETVAL = 1 ; + next ; + } + blurt ("Error: OUTPUT $outarg not an argument"), next + unless defined($args_match{$outarg}); + blurt("Error: No input definition for OUTPUT argument '$outarg' - ignored"), next + unless defined $var_types{$outarg} ; + $var_num = $args_match{$outarg}; + if ($outcode) { + print "\t$outcode\n"; + print "\tSvSETMAGIC(ST(" , $var_num-1 , "));\n" if $DoSetMagic; + } else { + &generate_output($var_types{$outarg}, $var_num, $outarg, $DoSetMagic); + } + delete $in_out{$outarg} # No need to auto-OUTPUT + if exists $in_out{$outarg} and $in_out{$outarg} =~ /OUT$/; + } +} + +sub C_ARGS_handler() { + my $in = merge_section(); + + TrimWhitespace($in); + $func_args = $in; +} + +sub INTERFACE_MACRO_handler() { + my $in = merge_section(); + + TrimWhitespace($in); + if ($in =~ /\s/) { # two + ($interface_macro, $interface_macro_set) = split ' ', $in; + } else { + $interface_macro = $in; + $interface_macro_set = 'UNKNOWN_CVT'; # catch later + } + $interface = 1; # local + $Interfaces = 1; # global +} + +sub INTERFACE_handler() { + my $in = merge_section(); + + TrimWhitespace($in); + + foreach (split /[\s,]+/, $in) { + my $name = $_; + $name =~ s/^$Prefix//; + $Interfaces{$name} = $_; + } + print Q(<<"EOF"); +# XSFUNCTION = $interface_macro($ret_type,cv,XSANY.any_dptr); +EOF + $interface = 1; # local + $Interfaces = 1; # global +} + +sub CLEANUP_handler() { print_section() } +sub PREINIT_handler() { print_section() } +sub POSTCALL_handler() { print_section() } +sub INIT_handler() { print_section() } + +sub GetAliases + { + my ($line) = @_ ; + my ($orig) = $line ; + my ($alias) ; + my ($value) ; + + # Parse alias definitions + # format is + # alias = value alias = value ... + + while ($line =~ s/^\s*([\w:]+)\s*=\s*(\w+)\s*//) { + $alias = $1 ; + $orig_alias = $alias ; + $value = $2 ; + + # check for optional package definition in the alias + $alias = $Packprefix . $alias if $alias !~ /::/ ; + + # check for duplicate alias name & duplicate value + Warn("Warning: Ignoring duplicate alias '$orig_alias'") + if defined $XsubAliases{$alias} ; + + Warn("Warning: Aliases '$orig_alias' and '$XsubAliasValues{$value}' have identical values") + if $XsubAliasValues{$value} ; + + $XsubAliases = 1; + $XsubAliases{$alias} = $value ; + $XsubAliasValues{$value} = $orig_alias ; + } + + blurt("Error: Cannot parse ALIAS definitions from '$orig'") + if $line ; + } + +sub ATTRS_handler () + { + for (; !/^$BLOCK_re/o; $_ = shift(@line)) { + next unless /\S/; + TrimWhitespace($_) ; + push @Attributes, $_; + } + } + +sub ALIAS_handler () + { + for (; !/^$BLOCK_re/o; $_ = shift(@line)) { + next unless /\S/; + TrimWhitespace($_) ; + GetAliases($_) if $_ ; + } + } + +sub OVERLOAD_handler() +{ + for (; !/^$BLOCK_re/o; $_ = shift(@line)) { + next unless /\S/; + TrimWhitespace($_) ; + while ( s/^\s*([\w:"\\)\+\-\*\/\%\<\>\.\&\|\^\!\~\{\}\=]+)\s*//) { + $Overload = 1 unless $Overload; + my $overload = "$Package\::(".$1 ; + push(@InitFileCode, + " (void)${newXS}(\"$overload\", XS_$Full_func_name, file$proto);\n"); + } + } +} + +sub FALLBACK_handler() +{ + # the rest of the current line should contain either TRUE, + # FALSE or UNDEF + + TrimWhitespace($_) ; + my %map = ( + TRUE => "&PL_sv_yes", 1 => "&PL_sv_yes", + FALSE => "&PL_sv_no", 0 => "&PL_sv_no", + UNDEF => "&PL_sv_undef", + ) ; + + # check for valid FALLBACK value + death ("Error: FALLBACK: TRUE/FALSE/UNDEF") unless exists $map{uc $_} ; + + $Fallback = $map{uc $_} ; +} + + +sub REQUIRE_handler () + { + # the rest of the current line should contain a version number + my ($Ver) = $_ ; + + TrimWhitespace($Ver) ; + + death ("Error: REQUIRE expects a version number") + unless $Ver ; + + # check that the version number is of the form n.n + death ("Error: REQUIRE: expected a number, got '$Ver'") + unless $Ver =~ /^\d+(\.\d*)?/ ; + + death ("Error: xsubpp $Ver (or better) required--this is only $VERSION.") + unless $VERSION >= $Ver ; + } + +sub VERSIONCHECK_handler () + { + # the rest of the current line should contain either ENABLE or + # DISABLE + + TrimWhitespace($_) ; + + # check for ENABLE/DISABLE + death ("Error: VERSIONCHECK: ENABLE/DISABLE") + unless /^(ENABLE|DISABLE)/i ; + + $WantVersionChk = 1 if $1 eq 'ENABLE' ; + $WantVersionChk = 0 if $1 eq 'DISABLE' ; + + } + +sub PROTOTYPE_handler () + { + my $specified ; + + death("Error: Only 1 PROTOTYPE definition allowed per xsub") + if $proto_in_this_xsub ++ ; + + for (; !/^$BLOCK_re/o; $_ = shift(@line)) { + next unless /\S/; + $specified = 1 ; + TrimWhitespace($_) ; + if ($_ eq 'DISABLE') { + $ProtoThisXSUB = 0 + } elsif ($_ eq 'ENABLE') { + $ProtoThisXSUB = 1 + } else { + # remove any whitespace + s/\s+//g ; + death("Error: Invalid prototype '$_'") + unless ValidProtoString($_) ; + $ProtoThisXSUB = C_string($_) ; + } + } + + # If no prototype specified, then assume empty prototype "" + $ProtoThisXSUB = 2 unless $specified ; + + $ProtoUsed = 1 ; + + } + +sub SCOPE_handler () + { + death("Error: Only 1 SCOPE declaration allowed per xsub") + if $scope_in_this_xsub ++ ; + + TrimWhitespace($_); + death ("Error: SCOPE: ENABLE/DISABLE") + unless /^(ENABLE|DISABLE)\b/i; + $ScopeThisXSUB = ( uc($1) eq 'ENABLE' ); + } + +sub PROTOTYPES_handler () + { + # the rest of the current line should contain either ENABLE or + # DISABLE + + TrimWhitespace($_) ; + + # check for ENABLE/DISABLE + death ("Error: PROTOTYPES: ENABLE/DISABLE") + unless /^(ENABLE|DISABLE)/i ; + + $WantPrototypes = 1 if $1 eq 'ENABLE' ; + $WantPrototypes = 0 if $1 eq 'DISABLE' ; + $ProtoUsed = 1 ; + + } + +sub INCLUDE_handler () + { + # the rest of the current line should contain a valid filename + + TrimWhitespace($_) ; + + death("INCLUDE: filename missing") + unless $_ ; + + death("INCLUDE: output pipe is illegal") + if /^\s*\|/ ; + + # simple minded recursion detector + death("INCLUDE loop detected") + if $IncludedFiles{$_} ; + + ++ $IncludedFiles{$_} unless /\|\s*$/ ; + + # Save the current file context. + push(@XSStack, { + type => 'file', + LastLine => $lastline, + LastLineNo => $lastline_no, + Line => \@line, + LineNo => \@line_no, + Filename => $filename, + Filepathname => $filepathname, + Handle => $FH, + }) ; + + $FH = Symbol::gensym(); + + # open the new file + open ($FH, "$_") or death("Cannot open '$_': $!") ; + + print Q(<<"EOF"); +# +#/* INCLUDE: Including '$_' from '$filename' */ +# +EOF + + $filename = $_ ; + $filepathname = "$dir/$filename"; + + # Prime the pump by reading the first + # non-blank line + + # skip leading blank lines + while (<$FH>) { + last unless /^\s*$/ ; + } + + $lastline = $_ ; + $lastline_no = $. ; + + } + +sub PopFile() + { + return 0 unless $XSStack[-1]{type} eq 'file' ; + + my $data = pop @XSStack ; + my $ThisFile = $filename ; + my $isPipe = ($filename =~ /\|\s*$/) ; + + -- $IncludedFiles{$filename} + unless $isPipe ; + + close $FH ; + + $FH = $data->{Handle} ; + # $filename is the leafname, which for some reason isused for diagnostic + # messages, whereas $filepathname is the full pathname, and is used for + # #line directives. + $filename = $data->{Filename} ; + $filepathname = $data->{Filepathname} ; + $lastline = $data->{LastLine} ; + $lastline_no = $data->{LastLineNo} ; + @line = @{ $data->{Line} } ; + @line_no = @{ $data->{LineNo} } ; + + if ($isPipe and $? ) { + -- $lastline_no ; + print STDERR "Error reading from pipe '$ThisFile': $! in $filename, line $lastline_no\n" ; + exit 1 ; + } + + print Q(<<"EOF"); +# +#/* INCLUDE: Returning to '$filename' from '$ThisFile' */ +# +EOF + + return 1 ; + } + +sub ValidProtoString ($) + { + my($string) = @_ ; + + if ( $string =~ /^$proto_re+$/ ) { + return $string ; + } + + return 0 ; + } + +sub C_string ($) + { + my($string) = @_ ; + + $string =~ s[\\][\\\\]g ; + $string ; + } + +sub ProtoString ($) + { + my ($type) = @_ ; + + $proto_letter{$type} or "\$" ; + } + +sub check_cpp { + my @cpp = grep(/^\#\s*(?:if|e\w+)/, @line); + if (@cpp) { + my ($cpp, $cpplevel); + for $cpp (@cpp) { + if ($cpp =~ /^\#\s*if/) { + $cpplevel++; + } elsif (!$cpplevel) { + Warn("Warning: #else/elif/endif without #if in this function"); + print STDERR " (precede it with a blank line if the matching #if is outside the function)\n" + if $XSStack[-1]{type} eq 'if'; + return; + } elsif ($cpp =~ /^\#\s*endif/) { + $cpplevel--; + } + } + Warn("Warning: #if without #endif in this function") if $cpplevel; + } +} + + +sub Q { + my($text) = @_; + $text =~ s/^#//gm; + $text =~ s/\[\[/{/g; + $text =~ s/\]\]/}/g; + $text; +} + +# Read next xsub into @line from ($lastline, <$FH>). +sub fetch_para { + # parse paragraph + death ("Error: Unterminated `#if/#ifdef/#ifndef'") + if !defined $lastline && $XSStack[-1]{type} eq 'if'; + @line = (); + @line_no = () ; + return PopFile() if !defined $lastline; + + if ($lastline =~ + /^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/) { + $Module = $1; + $Package = defined($2) ? $2 : ''; # keep -w happy + $Prefix = defined($3) ? $3 : ''; # keep -w happy + $Prefix = quotemeta $Prefix ; + ($Module_cname = $Module) =~ s/\W/_/g; + ($Packid = $Package) =~ tr/:/_/; + $Packprefix = $Package; + $Packprefix .= "::" if $Packprefix ne ""; + $lastline = ""; + } + + for (;;) { + # Skip embedded PODs + while ($lastline =~ /^=/) { + while ($lastline = <$FH>) { + last if ($lastline =~ /^=cut\s*$/); + } + death ("Error: Unterminated pod") unless $lastline; + $lastline = <$FH>; + chomp $lastline; + $lastline =~ s/^\s+$//; + } + if ($lastline !~ /^\s*#/ || + # CPP directives: + # ANSI: if ifdef ifndef elif else endif define undef + # line error pragma + # gcc: warning include_next + # obj-c: import + # others: ident (gcc notes that some cpps have this one) + $lastline =~ /^#[ \t]*(?:(?:if|ifn?def|elif|else|endif|define|undef|pragma|error|warning|line\s+\d+|ident)\b|(?:include(?:_next)?|import)\s*["<].*[>"])/) { + last if $lastline =~ /^\S/ && @line && $line[-1] eq ""; + push(@line, $lastline); + push(@line_no, $lastline_no) ; + } + + # Read next line and continuation lines + last unless defined($lastline = <$FH>); + $lastline_no = $.; + my $tmp_line; + $lastline .= $tmp_line + while ($lastline =~ /\\$/ && defined($tmp_line = <$FH>)); + + chomp $lastline; + $lastline =~ s/^\s+$//; + } + pop(@line), pop(@line_no) while @line && $line[-1] eq ""; + 1; +} + +sub output_init { + local($type, $num, $var, $init, $name_printed) = @_; + local($arg) = "ST(" . ($num - 1) . ")"; + + if ( $init =~ /^=/ ) { + if ($name_printed) { + eval qq/print " $init\\n"/; + } else { + eval qq/print "\\t$var $init\\n"/; + } + warn $@ if $@; + } else { + if ( $init =~ s/^\+// && $num ) { + &generate_init($type, $num, $var, $name_printed); + } elsif ($name_printed) { + print ";\n"; + $init =~ s/^;//; + } else { + eval qq/print "\\t$var;\\n"/; + warn $@ if $@; + $init =~ s/^;//; + } + $deferred .= eval qq/"\\n\\t$init\\n"/; + warn $@ if $@; + } +} + +sub Warn + { + # work out the line number + my $line_no = $line_no[@line_no - @line -1] ; + + print STDERR "@_ in $filename, line $line_no\n" ; + } + +sub blurt + { + Warn @_ ; + $errors ++ + } + +sub death + { + Warn @_ ; + exit 1 ; + } + +sub generate_init { + local($type, $num, $var) = @_; + local($arg) = "ST(" . ($num - 1) . ")"; + local($argoff) = $num - 1; + local($ntype); + local($tk); + + $type = TidyType($type) ; + blurt("Error: '$type' not in typemap"), return + unless defined($type_kind{$type}); + + ($ntype = $type) =~ s/\s*\*/Ptr/g; + ($subtype = $ntype) =~ s/(?:Array)?(?:Ptr)?$//; + $tk = $type_kind{$type}; + $tk =~ s/OBJ$/REF/ if $func_name =~ /DESTROY$/; + if ($tk eq 'T_PV' and exists $lengthof{$var}) { + print "\t$var" unless $name_printed; + print " = ($type)SvPV($arg, STRLEN_length_of_$var);\n"; + die "default value not supported with length(NAME) supplied" + if defined $defaults{$var}; + return; + } + $type =~ tr/:/_/ unless $hiertype; + blurt("Error: No INPUT definition for type '$type', typekind '$type_kind{$type}' found"), return + unless defined $input_expr{$tk} ; + $expr = $input_expr{$tk}; + if ($expr =~ /DO_ARRAY_ELEM/) { + blurt("Error: '$subtype' not in typemap"), return + unless defined($type_kind{$subtype}); + blurt("Error: No INPUT definition for type '$subtype', typekind '$type_kind{$subtype}' found"), return + unless defined $input_expr{$type_kind{$subtype}} ; + $subexpr = $input_expr{$type_kind{$subtype}}; + $subexpr =~ s/\$type/\$subtype/g; + $subexpr =~ s/ntype/subtype/g; + $subexpr =~ s/\$arg/ST(ix_$var)/g; + $subexpr =~ s/\n\t/\n\t\t/g; + $subexpr =~ s/is not of (.*\")/[arg %d] is not of $1, ix_$var + 1/g; + $subexpr =~ s/\$var/${var}[ix_$var - $argoff]/; + $expr =~ s/DO_ARRAY_ELEM/$subexpr/; + } + if ($expr =~ m#/\*.*scope.*\*/#i) { # "scope" in C comments + $ScopeThisXSUB = 1; + } + if (defined($defaults{$var})) { + $expr =~ s/(\t+)/$1 /g; + $expr =~ s/ /\t/g; + if ($name_printed) { + print ";\n"; + } else { + eval qq/print "\\t$var;\\n"/; + warn $@ if $@; + } + if ($defaults{$var} eq 'NO_INIT') { + $deferred .= eval qq/"\\n\\tif (items >= $num) {\\n$expr;\\n\\t}\\n"/; + } else { + $deferred .= eval qq/"\\n\\tif (items < $num)\\n\\t $var = $defaults{$var};\\n\\telse {\\n$expr;\\n\\t}\\n"/; + } + warn $@ if $@; + } elsif ($ScopeThisXSUB or $expr !~ /^\s*\$var =/) { + if ($name_printed) { + print ";\n"; + } else { + eval qq/print "\\t$var;\\n"/; + warn $@ if $@; + } + $deferred .= eval qq/"\\n$expr;\\n"/; + warn $@ if $@; + } else { + die "panic: do not know how to handle this branch for function pointers" + if $name_printed; + eval qq/print "$expr;\\n"/; + warn $@ if $@; + } +} + +sub generate_output { + local($type, $num, $var, $do_setmagic, $do_push) = @_; + local($arg) = "ST(" . ($num - ($num != 0)) . ")"; + local($argoff) = $num - 1; + local($ntype); + + $type = TidyType($type) ; + if ($type =~ /^array\(([^,]*),(.*)\)/) { + print "\t$arg = sv_newmortal();\n"; + print "\tsv_setpvn($arg, (char *)$var, $2 * sizeof($1));\n"; + print "\tSvSETMAGIC($arg);\n" if $do_setmagic; + } else { + blurt("Error: '$type' not in typemap"), return + unless defined($type_kind{$type}); + blurt("Error: No OUTPUT definition for type '$type', typekind '$type_kind{$type}' found"), return + unless defined $output_expr{$type_kind{$type}} ; + ($ntype = $type) =~ s/\s*\*/Ptr/g; + $ntype =~ s/\(\)//g; + ($subtype = $ntype) =~ s/(?:Array)?(?:Ptr)?$//; + $expr = $output_expr{$type_kind{$type}}; + if ($expr =~ /DO_ARRAY_ELEM/) { + blurt("Error: '$subtype' not in typemap"), return + unless defined($type_kind{$subtype}); + blurt("Error: No OUTPUT definition for type '$subtype', typekind '$type_kind{$subtype}' found"), return + unless defined $output_expr{$type_kind{$subtype}} ; + $subexpr = $output_expr{$type_kind{$subtype}}; + $subexpr =~ s/ntype/subtype/g; + $subexpr =~ s/\$arg/ST(ix_$var)/g; + $subexpr =~ s/\$var/${var}[ix_$var]/g; + $subexpr =~ s/\n\t/\n\t\t/g; + $expr =~ s/DO_ARRAY_ELEM\n/$subexpr/; + eval "print qq\a$expr\a"; + warn $@ if $@; + print "\t\tSvSETMAGIC(ST(ix_$var));\n" if $do_setmagic; + } elsif ($var eq 'RETVAL') { + if ($expr =~ /^\t\$arg = new/) { + # We expect that $arg has refcnt 1, so we need to + # mortalize it. + eval "print qq\a$expr\a"; + warn $@ if $@; + print "\tsv_2mortal(ST($num));\n"; + print "\tSvSETMAGIC(ST($num));\n" if $do_setmagic; + } elsif ($expr =~ /^\s*\$arg\s*=/) { + # We expect that $arg has refcnt >=1, so we need + # to mortalize it! + eval "print qq\a$expr\a"; + warn $@ if $@; + print "\tsv_2mortal(ST(0));\n"; + print "\tSvSETMAGIC(ST(0));\n" if $do_setmagic; + } else { + # Just hope that the entry would safely write it + # over an already mortalized value. By + # coincidence, something like $arg = &sv_undef + # works too. + print "\tST(0) = sv_newmortal();\n"; + eval "print qq\a$expr\a"; + warn $@ if $@; + # new mortals don't have set magic + } + } elsif ($do_push) { + print "\tPUSHs(sv_newmortal());\n"; + $arg = "ST($num)"; + eval "print qq\a$expr\a"; + warn $@ if $@; + print "\tSvSETMAGIC($arg);\n" if $do_setmagic; + } elsif ($arg =~ /^ST\(\d+\)$/) { + eval "print qq\a$expr\a"; + warn $@ if $@; + print "\tSvSETMAGIC($arg);\n" if $do_setmagic; + } + } +} + +sub map_type { + my($type, $varname) = @_; + + # C++ has :: in types too so skip this + $type =~ tr/:/_/ unless $hiertype; + $type =~ s/^array\(([^,]*),(.*)\).*/$1 */s; + if ($varname) { + if ($varname && $type =~ / \( \s* \* (?= \s* \) ) /xg) { + (substr $type, pos $type, 0) = " $varname "; + } else { + $type .= "\t$varname"; + } + } + $type; +} + + +######################################################### +package + ExtUtils::ParseXS::CountLines; +use strict; +use vars qw($SECTION_END_MARKER); + +sub TIEHANDLE { + my ($class, $cfile, $fh) = @_; + $cfile =~ s/\\/\\\\/g; + $SECTION_END_MARKER = qq{#line --- "$cfile"}; + + return bless {buffer => '', + fh => $fh, + line_no => 1, + }, $class; +} + +sub PRINT { + my $self = shift; + for (@_) { + $self->{buffer} .= $_; + while ($self->{buffer} =~ s/^([^\n]*\n)//) { + my $line = $1; + ++ $self->{line_no}; + $line =~ s|^\#line\s+---(?=\s)|#line $self->{line_no}|; + print {$self->{fh}} $line; + } + } +} + +sub PRINTF { + my $self = shift; + my $fmt = shift; + $self->PRINT(sprintf($fmt, @_)); +} + +sub DESTROY { + # Not necessary if we're careful to end with a "\n" + my $self = shift; + print {$self->{fh}} $self->{buffer}; +} + +sub UNTIE { + # This sub does nothing, but is neccessary for references to be released. +} + +sub end_marker { + return $SECTION_END_MARKER; +} + + +1; +__END__ + +=head1 NAME + +ExtUtils::ParseXS - converts Perl XS code into C code + +=head1 SYNOPSIS + + use ExtUtils::ParseXS qw(process_file); + + process_file( filename => 'foo.xs' ); + + process_file( filename => 'foo.xs', + output => 'bar.c', + 'C++' => 1, + typemap => 'path/to/typemap', + hiertype => 1, + except => 1, + prototypes => 1, + versioncheck => 1, + linenumbers => 1, + optimize => 1, + prototypes => 1, + ); +=head1 DESCRIPTION + +C<ExtUtils::ParseXS> will compile XS code into C code by embedding the constructs +necessary to let C functions manipulate Perl values and creates the glue +necessary to let Perl access those functions. The compiler uses typemaps to +determine how to map C function parameters and variables to Perl values. + +The compiler will search for typemap files called I<typemap>. It will use +the following search path to find default typemaps, with the rightmost +typemap taking precedence. + + ../../../typemap:../../typemap:../typemap:typemap + +=head1 EXPORT + +None by default. C<process_file()> may be exported upon request. + + +=head1 FUNCTIONS + +=over 4 + +=item process_xs() + +This function processes an XS file and sends output to a C file. +Named parameters control how the processing is done. The following +parameters are accepted: + +=over 4 + +=item B<C++> + +Adds C<extern "C"> to the C code. Default is false. + +=item B<hiertype> + +Retains C<::> in type names so that C++ hierachical types can be +mapped. Default is false. + +=item B<except> + +Adds exception handling stubs to the C code. Default is false. + +=item B<typemap> + +Indicates that a user-supplied typemap should take precedence over the +default typemaps. A single typemap may be specified as a string, or +multiple typemaps can be specified in an array reference, with the +last typemap having the highest precedence. + +=item B<prototypes> + +Generates prototype code for all xsubs. Default is false. + +=item B<versioncheck> + +Makes sure at run time that the object file (derived from the C<.xs> +file) and the C<.pm> files have the same version number. Default is +true. + +=item B<linenumbers> + +Adds C<#line> directives to the C output so error messages will look +like they came from the original XS file. Default is true. + +=item B<optimize> + +Enables certain optimizations. The only optimization that is currently +affected is the use of I<target>s by the output C code (see L<perlguts>). +Not optimizing may significantly slow down the generated code, but this is the way +B<xsubpp> of 5.005 and earlier operated. Default is to optimize. + +=item B<inout> + +Enable recognition of C<IN>, C<OUT_LIST> and C<INOUT_LIST> +declarations. Default is true. + +=item B<argtypes> + +Enable recognition of ANSI-like descriptions of function signature. +Default is true. + +=item B<s> + +I have no clue what this does. Strips function prefixes? + +=back + +=item errors() + +This function returns the number of [a certain kind of] errors +encountered during processing of the XS file. + +=back + +=head1 AUTHOR + +Based on xsubpp code, written by Larry Wall. + +Maintained by: + +=over 4 + +=item * + +Ken Williams, <ken@mathforum.org> + +=item * + +David Golden, <dagolden@cpan.org> + +=back + +=head1 COPYRIGHT + +Copyright 2002-2009 by Ken Williams, David Golden and other contributors. All +rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +Based on the ExtUtils::xsubpp code by Larry Wall and the Perl 5 +Porters, which was released under the same license terms. + +=head1 SEE ALSO + +L<perl>, ExtUtils::xsubpp, ExtUtils::MakeMaker, L<perlxs>, L<perlxstut>. + +=cut diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/testlib.pm b/Master/tlpkg/tlperl/lib/ExtUtils/testlib.pm new file mode 100644 index 00000000000..fe01beb0e1e --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/testlib.pm @@ -0,0 +1,41 @@ +package ExtUtils::testlib; + +use strict; +use warnings; + +our $VERSION = 6.56; + +use Cwd; +use File::Spec; + +# So the tests can chdir around and not break @INC. +# We use getcwd() because otherwise rel2abs will blow up under taint +# mode pre-5.8. We detaint is so @INC won't be tainted. This is +# no worse, and probably better, than just shoving an untainted, +# relative "blib/lib" onto @INC. +my $cwd; +BEGIN { + ($cwd) = getcwd() =~ /(.*)/; +} +use lib map { File::Spec->rel2abs($_, $cwd) } qw(blib/arch blib/lib); +1; +__END__ + +=head1 NAME + +ExtUtils::testlib - add blib/* directories to @INC + +=head1 SYNOPSIS + + use ExtUtils::testlib; + +=head1 DESCRIPTION + +After an extension has been built and before it is installed it may be +desirable to test it bypassing C<make test>. By adding + + use ExtUtils::testlib; + +to a test program the intermediate directories used by C<make> are +added to @INC. + diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/typemap b/Master/tlpkg/tlperl/lib/ExtUtils/typemap new file mode 100644 index 00000000000..f88858762d5 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/typemap @@ -0,0 +1,336 @@ +# basic C types +int T_IV +unsigned T_UV +unsigned int T_UV +long T_IV +unsigned long T_UV +short T_IV +unsigned short T_UV +char T_CHAR +unsigned char T_U_CHAR +char * T_PV +unsigned char * T_PV +const char * T_PV +caddr_t T_PV +wchar_t * T_PV +wchar_t T_IV +# bool_t is defined in <rpc/rpc.h> +bool_t T_IV +size_t T_UV +ssize_t T_IV +time_t T_NV +unsigned long * T_OPAQUEPTR +char ** T_PACKEDARRAY +void * T_PTR +Time_t * T_PV +SV * T_SV +SVREF T_SVREF +AV * T_AVREF +HV * T_HVREF +CV * T_CVREF + +IV T_IV +UV T_UV +NV T_NV +I32 T_IV +I16 T_IV +I8 T_IV +STRLEN T_UV +U32 T_U_LONG +U16 T_U_SHORT +U8 T_UV +Result T_U_CHAR +Boolean T_BOOL +float T_FLOAT +double T_DOUBLE +SysRet T_SYSRET +SysRetLong T_SYSRET +FILE * T_STDIO +PerlIO * T_INOUT +FileHandle T_PTROBJ +InputStream T_IN +InOutStream T_INOUT +OutputStream T_OUT +bool T_BOOL + +############################################################################# +INPUT +T_SV + $var = $arg +T_SVREF + if (SvROK($arg)) + $var = (SV*)SvRV($arg); + else + Perl_croak(aTHX_ \"%s: %s is not a reference\", + ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, + \"$var\") +T_AVREF + if (SvROK($arg) && SvTYPE(SvRV($arg))==SVt_PVAV) + $var = (AV*)SvRV($arg); + else + Perl_croak(aTHX_ \"%s: %s is not an array reference\", + ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, + \"$var\") +T_HVREF + if (SvROK($arg) && SvTYPE(SvRV($arg))==SVt_PVHV) + $var = (HV*)SvRV($arg); + else + Perl_croak(aTHX_ \"%s: %s is not a hash reference\", + ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, + \"$var\") +T_CVREF + if (SvROK($arg) && SvTYPE(SvRV($arg))==SVt_PVCV) + $var = (CV*)SvRV($arg); + else + Perl_croak(aTHX_ \"%s: %s is not a code reference\", + ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, + \"$var\") +T_SYSRET + $var NOT IMPLEMENTED +T_UV + $var = ($type)SvUV($arg) +T_IV + $var = ($type)SvIV($arg) +T_INT + $var = (int)SvIV($arg) +T_ENUM + $var = ($type)SvIV($arg) +T_BOOL + $var = (bool)SvTRUE($arg) +T_U_INT + $var = (unsigned int)SvUV($arg) +T_SHORT + $var = (short)SvIV($arg) +T_U_SHORT + $var = (unsigned short)SvUV($arg) +T_LONG + $var = (long)SvIV($arg) +T_U_LONG + $var = (unsigned long)SvUV($arg) +T_CHAR + $var = (char)*SvPV_nolen($arg) +T_U_CHAR + $var = (unsigned char)SvUV($arg) +T_FLOAT + $var = (float)SvNV($arg) +T_NV + $var = ($type)SvNV($arg) +T_DOUBLE + $var = (double)SvNV($arg) +T_PV + $var = ($type)SvPV_nolen($arg) +T_PTR + $var = INT2PTR($type,SvIV($arg)) +T_PTRREF + if (SvROK($arg)) { + IV tmp = SvIV((SV*)SvRV($arg)); + $var = INT2PTR($type,tmp); + } + else + Perl_croak(aTHX_ \"%s: %s is not a reference\", + ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, + \"$var\") +T_REF_IV_REF + if (sv_isa($arg, \"${ntype}\")) { + IV tmp = SvIV((SV*)SvRV($arg)); + $var = *INT2PTR($type *, tmp); + } + else + Perl_croak(aTHX_ \"%s: %s is not of type %s\", + ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, + \"$var\", \"$ntype\") +T_REF_IV_PTR + if (sv_isa($arg, \"${ntype}\")) { + IV tmp = SvIV((SV*)SvRV($arg)); + $var = INT2PTR($type, tmp); + } + else + Perl_croak(aTHX_ \"%s: %s is not of type %s\", + ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, + \"$var\", \"$ntype\") +T_PTROBJ + if (SvROK($arg) && sv_derived_from($arg, \"${ntype}\")) { + IV tmp = SvIV((SV*)SvRV($arg)); + $var = INT2PTR($type,tmp); + } + else + Perl_croak(aTHX_ \"%s: %s is not of type %s\", + ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, + \"$var\", \"$ntype\") +T_PTRDESC + if (sv_isa($arg, \"${ntype}\")) { + IV tmp = SvIV((SV*)SvRV($arg)); + ${type}_desc = (\U${type}_DESC\E*) tmp; + $var = ${type}_desc->ptr; + } + else + Perl_croak(aTHX_ \"%s: %s is not of type %s\", + ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, + \"$var\", \"$ntype\") +T_REFREF + if (SvROK($arg)) { + IV tmp = SvIV((SV*)SvRV($arg)); + $var = *INT2PTR($type,tmp); + } + else + Perl_croak(aTHX_ \"%s: %s is not a reference\", + ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, + \"$var\") +T_REFOBJ + if (sv_isa($arg, \"${ntype}\")) { + IV tmp = SvIV((SV*)SvRV($arg)); + $var = *INT2PTR($type,tmp); + } + else + Perl_croak(aTHX_ \"%s: %s is not of type %s\", + ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, + \"$var\", \"$ntype\") +T_OPAQUE + $var = *($type *)SvPV_nolen($arg) +T_OPAQUEPTR + $var = ($type)SvPV_nolen($arg) +T_PACKED + $var = XS_unpack_$ntype($arg) +T_PACKEDARRAY + $var = XS_unpack_$ntype($arg) +T_CALLBACK + $var = make_perl_cb_$type($arg) +T_ARRAY + U32 ix_$var = $argoff; + $var = $ntype(items -= $argoff); + while (items--) { + DO_ARRAY_ELEM; + ix_$var++; + } + /* this is the number of elements in the array */ + ix_$var -= $argoff +T_STDIO + $var = PerlIO_findFILE(IoIFP(sv_2io($arg))) +T_IN + $var = IoIFP(sv_2io($arg)) +T_INOUT + $var = IoIFP(sv_2io($arg)) +T_OUT + $var = IoOFP(sv_2io($arg)) +############################################################################# +OUTPUT +T_SV + $arg = $var; +T_SVREF + $arg = newRV((SV*)$var); +T_AVREF + $arg = newRV((SV*)$var); +T_HVREF + $arg = newRV((SV*)$var); +T_CVREF + $arg = newRV((SV*)$var); +T_IV + sv_setiv($arg, (IV)$var); +T_UV + sv_setuv($arg, (UV)$var); +T_INT + sv_setiv($arg, (IV)$var); +T_SYSRET + if ($var != -1) { + if ($var == 0) + sv_setpvn($arg, "0 but true", 10); + else + sv_setiv($arg, (IV)$var); + } +T_ENUM + sv_setiv($arg, (IV)$var); +T_BOOL + $arg = boolSV($var); +T_U_INT + sv_setuv($arg, (UV)$var); +T_SHORT + sv_setiv($arg, (IV)$var); +T_U_SHORT + sv_setuv($arg, (UV)$var); +T_LONG + sv_setiv($arg, (IV)$var); +T_U_LONG + sv_setuv($arg, (UV)$var); +T_CHAR + sv_setpvn($arg, (char *)&$var, 1); +T_U_CHAR + sv_setuv($arg, (UV)$var); +T_FLOAT + sv_setnv($arg, (double)$var); +T_NV + sv_setnv($arg, (NV)$var); +T_DOUBLE + sv_setnv($arg, (double)$var); +T_PV + sv_setpv((SV*)$arg, $var); +T_PTR + sv_setiv($arg, PTR2IV($var)); +T_PTRREF + sv_setref_pv($arg, Nullch, (void*)$var); +T_REF_IV_REF + sv_setref_pv($arg, \"${ntype}\", (void*)new $ntype($var)); +T_REF_IV_PTR + sv_setref_pv($arg, \"${ntype}\", (void*)$var); +T_PTROBJ + sv_setref_pv($arg, \"${ntype}\", (void*)$var); +T_PTRDESC + sv_setref_pv($arg, \"${ntype}\", (void*)new\U${type}_DESC\E($var)); +T_REFREF + NOT_IMPLEMENTED +T_REFOBJ + NOT IMPLEMENTED +T_OPAQUE + sv_setpvn($arg, (char *)&$var, sizeof($var)); +T_OPAQUEPTR + sv_setpvn($arg, (char *)$var, sizeof(*$var)); +T_PACKED + XS_pack_$ntype($arg, $var); +T_PACKEDARRAY + XS_pack_$ntype($arg, $var, count_$ntype); +T_DATAUNIT + sv_setpvn($arg, $var.chp(), $var.size()); +T_CALLBACK + sv_setpvn($arg, $var.context.value().chp(), + $var.context.value().size()); +T_ARRAY + { + U32 ix_$var; + EXTEND(SP,size_$var); + for (ix_$var = 0; ix_$var < size_$var; ix_$var++) { + ST(ix_$var) = sv_newmortal(); + DO_ARRAY_ELEM + } + } +T_STDIO + { + GV *gv = newGVgen("$Package"); + PerlIO *fp = PerlIO_importFILE($var,0); + if ( fp && do_open(gv, "+<&", 3, FALSE, 0, 0, fp) ) + sv_setsv($arg, sv_bless(newRV((SV*)gv), gv_stashpv("$Package",1))); + else + $arg = &PL_sv_undef; + } +T_IN + { + GV *gv = newGVgen("$Package"); + if ( do_open(gv, "<&", 2, FALSE, 0, 0, $var) ) + sv_setsv($arg, sv_bless(newRV((SV*)gv), gv_stashpv("$Package",1))); + else + $arg = &PL_sv_undef; + } +T_INOUT + { + GV *gv = newGVgen("$Package"); + if ( do_open(gv, "+<&", 3, FALSE, 0, 0, $var) ) + sv_setsv($arg, sv_bless(newRV((SV*)gv), gv_stashpv("$Package",1))); + else + $arg = &PL_sv_undef; + } +T_OUT + { + GV *gv = newGVgen("$Package"); + if ( do_open(gv, "+>&", 3, FALSE, 0, 0, $var) ) + sv_setsv($arg, sv_bless(newRV((SV*)gv), gv_stashpv("$Package",1))); + else + $arg = &PL_sv_undef; + } diff --git a/Master/tlpkg/tlperl/lib/ExtUtils/xsubpp b/Master/tlpkg/tlperl/lib/ExtUtils/xsubpp new file mode 100644 index 00000000000..e4e5b774d82 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/ExtUtils/xsubpp @@ -0,0 +1,156 @@ +#!./miniperl + +require 5.002; +use ExtUtils::ParseXS qw(process_file); +use Getopt::Long; + +my %args = (); + +my $usage = "Usage: xsubpp [-v] [-csuffix csuffix] [-except] [-prototypes] [-noversioncheck] [-nolinenumbers] [-nooptimize] [-noinout] [-noargtypes] [-s pattern] [-typemap typemap]... file.xs\n"; + +Getopt::Long::Configure qw(no_auto_abbrev no_ignore_case); + +@ARGV = grep {$_ ne '-C++'} @ARGV; # Allow -C++ for backward compatibility +GetOptions(\%args, qw(hiertype! + prototypes! + versioncheck! + linenumbers! + optimize! + inout! + argtypes! + object_capi! + except! + v + typemap=s@ + output=s + s=s + csuffix=s + )) + or die $usage; + +if ($args{v}) { + print "xsubpp version $ExtUtils::ParseXS::VERSION\n"; + exit; +} + +@ARGV == 1 or die $usage; + +$args{filename} = shift @ARGV; + +process_file(%args); +exit( ExtUtils::ParseXS::errors() ? 1 : 0 ); + +__END__ + +=head1 NAME + +xsubpp - compiler to convert Perl XS code into C code + +=head1 SYNOPSIS + +B<xsubpp> [B<-v>] [B<-except>] [B<-s pattern>] [B<-prototypes>] [B<-noversioncheck>] [B<-nolinenumbers>] [B<-nooptimize>] [B<-typemap typemap>] [B<-output filename>]... file.xs + +=head1 DESCRIPTION + +This compiler is typically run by the makefiles created by L<ExtUtils::MakeMaker>. + +I<xsubpp> will compile XS code into C code by embedding the constructs +necessary to let C functions manipulate Perl values and creates the glue +necessary to let Perl access those functions. The compiler uses typemaps to +determine how to map C function parameters and variables to Perl values. + +The compiler will search for typemap files called I<typemap>. It will use +the following search path to find default typemaps, with the rightmost +typemap taking precedence. + + ../../../typemap:../../typemap:../typemap:typemap + +It will also use a default typemap installed as C<ExtUtils::typemap>. + +=head1 OPTIONS + +Note that the C<XSOPT> MakeMaker option may be used to add these options to +any makefiles generated by MakeMaker. + +=over 5 + +=item B<-hiertype> + +Retains '::' in type names so that C++ hierarchical types can be mapped. + +=item B<-except> + +Adds exception handling stubs to the C code. + +=item B<-typemap typemap> + +Indicates that a user-supplied typemap should take precedence over the +default typemaps. This option may be used multiple times, with the last +typemap having the highest precedence. + +=item B<-output filename> + +Specifies the name of the output file to generate. If no file is +specified, output will be written to standard output. + +=item B<-v> + +Prints the I<xsubpp> version number to standard output, then exits. + +=item B<-prototypes> + +By default I<xsubpp> will not automatically generate prototype code for +all xsubs. This flag will enable prototypes. + +=item B<-noversioncheck> + +Disables the run time test that determines if the object file (derived +from the C<.xs> file) and the C<.pm> files have the same version +number. + +=item B<-nolinenumbers> + +Prevents the inclusion of `#line' directives in the output. + +=item B<-nooptimize> + +Disables certain optimizations. The only optimization that is currently +affected is the use of I<target>s by the output C code (see L<perlguts>). +This may significantly slow down the generated code, but this is the way +B<xsubpp> of 5.005 and earlier operated. + +=item B<-noinout> + +Disable recognition of C<IN>, C<OUT_LIST> and C<INOUT_LIST> declarations. + +=item B<-noargtypes> + +Disable recognition of ANSI-like descriptions of function signature. + +=item B<-C++> + +Currently doesn't do anything at all. This flag has been a no-op for +many versions of perl, at least as far back as perl5.003_07. It's +allowed here for backwards compatibility. + +=back + +=head1 ENVIRONMENT + +No environment variables are used. + +=head1 AUTHOR + +Originally by Larry Wall. Turned into the C<ExtUtils::ParseXS> module +by Ken Williams. + +=head1 MODIFICATION HISTORY + +See the file F<Changes>. + +=head1 SEE ALSO + +perl(1), perlxs(1), perlxstut(1), ExtUtils::ParseXS + +=cut + diff --git a/Master/tlpkg/tlperl/lib/IO/Compress/Adapter/Bzip2.pm b/Master/tlpkg/tlperl/lib/IO/Compress/Adapter/Bzip2.pm new file mode 100644 index 00000000000..3e2e89f8e12 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Compress/Adapter/Bzip2.pm @@ -0,0 +1,162 @@ +package IO::Compress::Adapter::Bzip2 ; + +use strict; +use warnings; +use bytes; + +use IO::Compress::Base::Common 2.024 qw(:Status); + +#use Compress::Bzip2 ; +use Compress::Raw::Bzip2 2.024 ; + +our ($VERSION); +$VERSION = '2.024'; + +sub mkCompObject +{ + my $BlockSize100K = shift ; + my $WorkFactor = shift ; + my $Verbosity = shift ; + + my ($def, $status) = new Compress::Raw::Bzip2(1, $BlockSize100K, + $WorkFactor, $Verbosity); + #my ($def, $status) = bzdeflateInit(); + #-BlockSize100K => $params->value('BlockSize100K'), + #-WorkFactor => $params->value('WorkFactor'); + + return (undef, "Could not create Deflate object: $status", $status) + if $status != BZ_OK ; + + return bless {'Def' => $def, + 'Error' => '', + 'ErrorNo' => 0, + } ; +} + +sub compr +{ + my $self = shift ; + + my $def = $self->{Def}; + + #my ($out, $status) = $def->bzdeflate(defined ${$_[0]} ? ${$_[0]} : "") ; + my $status = $def->bzdeflate($_[0], $_[1]) ; + $self->{ErrorNo} = $status; + + if ($status != BZ_RUN_OK) + { + $self->{Error} = "Deflate Error: $status"; + return STATUS_ERROR; + } + + #${ $_[1] } .= $out if defined $out; + + return STATUS_OK; +} + +sub flush +{ + my $self = shift ; + + my $def = $self->{Def}; + + #my ($out, $status) = $def->bzflush($opt); + #my $status = $def->bzflush($_[0], $opt); + my $status = $def->bzflush($_[0]); + $self->{ErrorNo} = $status; + + if ($status != BZ_RUN_OK) + { + $self->{Error} = "Deflate Error: $status"; + return STATUS_ERROR; + } + + #${ $_[0] } .= $out if defined $out ; + return STATUS_OK; + +} + +sub close +{ + my $self = shift ; + + my $def = $self->{Def}; + + #my ($out, $status) = $def->bzclose(); + my $status = $def->bzclose($_[0]); + $self->{ErrorNo} = $status; + + if ($status != BZ_STREAM_END) + { + $self->{Error} = "Deflate Error: $status"; + return STATUS_ERROR; + } + + #${ $_[0] } .= $out if defined $out ; + return STATUS_OK; + +} + + +sub reset +{ + my $self = shift ; + + my $outer = $self->{Outer}; + + my ($def, $status) = new Compress::Raw::Bzip2(); + $self->{ErrorNo} = ($status == BZ_OK) ? 0 : $status ; + + if ($status != BZ_OK) + { + $self->{Error} = "Cannot create Deflate object: $status"; + return STATUS_ERROR; + } + + $self->{Def} = $def; + + return STATUS_OK; +} + +sub compressedBytes +{ + my $self = shift ; + $self->{Def}->compressedBytes(); +} + +sub uncompressedBytes +{ + my $self = shift ; + $self->{Def}->uncompressedBytes(); +} + +#sub total_out +#{ +# my $self = shift ; +# 0; +#} +# + +#sub total_in +#{ +# my $self = shift ; +# $self->{Def}->total_in(); +#} +# +#sub crc32 +#{ +# my $self = shift ; +# $self->{Def}->crc32(); +#} +# +#sub adler32 +#{ +# my $self = shift ; +# $self->{Def}->adler32(); +#} + + +1; + +__END__ + diff --git a/Master/tlpkg/tlperl/lib/IO/Compress/Adapter/Deflate.pm b/Master/tlpkg/tlperl/lib/IO/Compress/Adapter/Deflate.pm new file mode 100644 index 00000000000..f23a9819c67 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Compress/Adapter/Deflate.pm @@ -0,0 +1,165 @@ +package IO::Compress::Adapter::Deflate ; + +use strict; +use warnings; +use bytes; + +use IO::Compress::Base::Common 2.024 qw(:Status); + +use Compress::Raw::Zlib 2.024 qw(Z_OK Z_FINISH MAX_WBITS) ; +our ($VERSION); + +$VERSION = '2.024'; + +sub mkCompObject +{ + my $crc32 = shift ; + my $adler32 = shift ; + my $level = shift ; + my $strategy = shift ; + + my ($def, $status) = new Compress::Raw::Zlib::Deflate + -AppendOutput => 1, + -CRC32 => $crc32, + -ADLER32 => $adler32, + -Level => $level, + -Strategy => $strategy, + -WindowBits => - MAX_WBITS; + + return (undef, "Cannot create Deflate object: $status", $status) + if $status != Z_OK; + + return bless {'Def' => $def, + 'Error' => '', + } ; +} + +sub compr +{ + my $self = shift ; + + my $def = $self->{Def}; + + my $status = $def->deflate($_[0], $_[1]) ; + $self->{ErrorNo} = $status; + + if ($status != Z_OK) + { + $self->{Error} = "Deflate Error: $status"; + return STATUS_ERROR; + } + + return STATUS_OK; +} + +sub flush +{ + my $self = shift ; + + my $def = $self->{Def}; + + my $opt = $_[1] || Z_FINISH; + my $status = $def->flush($_[0], $opt); + $self->{ErrorNo} = $status; + + if ($status != Z_OK) + { + $self->{Error} = "Deflate Error: $status"; + return STATUS_ERROR; + } + + return STATUS_OK; + +} + +sub close +{ + my $self = shift ; + + my $def = $self->{Def}; + + $def->flush($_[0], Z_FINISH) + if defined $def ; +} + +sub reset +{ + my $self = shift ; + + my $def = $self->{Def}; + + my $status = $def->deflateReset() ; + $self->{ErrorNo} = $status; + if ($status != Z_OK) + { + $self->{Error} = "Deflate Error: $status"; + return STATUS_ERROR; + } + + return STATUS_OK; +} + +sub deflateParams +{ + my $self = shift ; + + my $def = $self->{Def}; + + my $status = $def->deflateParams(@_); + $self->{ErrorNo} = $status; + if ($status != Z_OK) + { + $self->{Error} = "deflateParams Error: $status"; + return STATUS_ERROR; + } + + return STATUS_OK; +} + + + +#sub total_out +#{ +# my $self = shift ; +# $self->{Def}->total_out(); +#} +# +#sub total_in +#{ +# my $self = shift ; +# $self->{Def}->total_in(); +#} + +sub compressedBytes +{ + my $self = shift ; + + $self->{Def}->compressedBytes(); +} + +sub uncompressedBytes +{ + my $self = shift ; + $self->{Def}->uncompressedBytes(); +} + + + + +sub crc32 +{ + my $self = shift ; + $self->{Def}->crc32(); +} + +sub adler32 +{ + my $self = shift ; + $self->{Def}->adler32(); +} + + +1; + +__END__ + diff --git a/Master/tlpkg/tlperl/lib/IO/Compress/Adapter/Identity.pm b/Master/tlpkg/tlperl/lib/IO/Compress/Adapter/Identity.pm new file mode 100644 index 00000000000..16f14d8e7f3 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Compress/Adapter/Identity.pm @@ -0,0 +1,101 @@ +package IO::Compress::Adapter::Identity ; + +use strict; +use warnings; +use bytes; + +use IO::Compress::Base::Common 2.024 qw(:Status); +our ($VERSION); + +$VERSION = '2.024'; + +sub mkCompObject +{ + my $level = shift ; + my $strategy = shift ; + + return bless { + 'CompSize' => 0, + 'UnCompSize' => 0, + 'Error' => '', + 'ErrorNo' => 0, + } ; +} + +sub compr +{ + my $self = shift ; + + if (defined ${ $_[0] } && length ${ $_[0] }) { + $self->{CompSize} += length ${ $_[0] } ; + $self->{UnCompSize} = $self->{CompSize} ; + + if ( ref $_[1] ) + { ${ $_[1] } .= ${ $_[0] } } + else + { $_[1] .= ${ $_[0] } } + } + + return STATUS_OK ; +} + +sub flush +{ + my $self = shift ; + + return STATUS_OK; +} + +sub close +{ + my $self = shift ; + + return STATUS_OK; +} + +sub reset +{ + my $self = shift ; + + $self->{CompSize} = 0; + $self->{UnCompSize} = 0; + + return STATUS_OK; +} + +sub deflateParams +{ + my $self = shift ; + + return STATUS_OK; +} + +#sub total_out +#{ +# my $self = shift ; +# return $self->{UnCompSize} ; +#} +# +#sub total_in +#{ +# my $self = shift ; +# return $self->{UnCompSize} ; +#} + +sub compressedBytes +{ + my $self = shift ; + return $self->{UnCompSize} ; +} + +sub uncompressedBytes +{ + my $self = shift ; + return $self->{UnCompSize} ; +} + +1; + + +__END__ + diff --git a/Master/tlpkg/tlperl/lib/IO/Compress/Base.pm b/Master/tlpkg/tlperl/lib/IO/Compress/Base.pm new file mode 100644 index 00000000000..5a20f60007b --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Compress/Base.pm @@ -0,0 +1,981 @@ + +package IO::Compress::Base ; + +require 5.004 ; + +use strict ; +use warnings; + +use IO::Compress::Base::Common 2.024 ; + +use IO::File ; +use Scalar::Util qw(blessed readonly); + +#use File::Glob; +#require Exporter ; +use Carp ; +use Symbol; +use bytes; + +our (@ISA, $VERSION); +@ISA = qw(Exporter IO::File); + +$VERSION = '2.024'; + +#Can't locate object method "SWASHNEW" via package "utf8" (perhaps you forgot to load "utf8"?) at .../ext/Compress-Zlib/Gzip/blib/lib/Compress/Zlib/Common.pm line 16. + +sub saveStatus +{ + my $self = shift ; + ${ *$self->{ErrorNo} } = shift() + 0 ; + ${ *$self->{Error} } = '' ; + + return ${ *$self->{ErrorNo} } ; +} + + +sub saveErrorString +{ + my $self = shift ; + my $retval = shift ; + ${ *$self->{Error} } = shift ; + ${ *$self->{ErrorNo} } = shift() + 0 if @_ ; + + return $retval; +} + +sub croakError +{ + my $self = shift ; + $self->saveErrorString(0, $_[0]); + croak $_[0]; +} + +sub closeError +{ + my $self = shift ; + my $retval = shift ; + + my $errno = *$self->{ErrorNo}; + my $error = ${ *$self->{Error} }; + + $self->close(); + + *$self->{ErrorNo} = $errno ; + ${ *$self->{Error} } = $error ; + + return $retval; +} + + + +sub error +{ + my $self = shift ; + return ${ *$self->{Error} } ; +} + +sub errorNo +{ + my $self = shift ; + return ${ *$self->{ErrorNo} } ; +} + + +sub writeAt +{ + my $self = shift ; + my $offset = shift; + my $data = shift; + + if (defined *$self->{FH}) { + my $here = tell(*$self->{FH}); + return $self->saveErrorString(undef, "Cannot seek to end of output filehandle: $!", $!) + if $here < 0 ; + seek(*$self->{FH}, $offset, SEEK_SET) + or return $self->saveErrorString(undef, "Cannot seek to end of output filehandle: $!", $!) ; + defined *$self->{FH}->write($data, length $data) + or return $self->saveErrorString(undef, $!, $!) ; + seek(*$self->{FH}, $here, SEEK_SET) + or return $self->saveErrorString(undef, "Cannot seek to end of output filehandle: $!", $!) ; + } + else { + substr(${ *$self->{Buffer} }, $offset, length($data)) = $data ; + } + + return 1; +} + +sub output +{ + my $self = shift ; + my $data = shift ; + my $last = shift ; + + return 1 + if length $data == 0 && ! $last ; + + if ( *$self->{FilterEnvelope} ) { + *_ = \$data; + &{ *$self->{FilterEnvelope} }(); + } + + if (length $data) { + if ( defined *$self->{FH} ) { + defined *$self->{FH}->write( $data, length $data ) + or return $self->saveErrorString(0, $!, $!); + } + else { + ${ *$self->{Buffer} } .= $data ; + } + } + + return 1; +} + +sub getOneShotParams +{ + return ( 'MultiStream' => [1, 1, Parse_boolean, 1], + ); +} + +sub checkParams +{ + my $self = shift ; + my $class = shift ; + + my $got = shift || IO::Compress::Base::Parameters::new(); + + $got->parse( + { + # Generic Parameters + 'AutoClose' => [1, 1, Parse_boolean, 0], + #'Encode' => [1, 1, Parse_any, undef], + 'Strict' => [0, 1, Parse_boolean, 1], + 'Append' => [1, 1, Parse_boolean, 0], + 'BinModeIn' => [1, 1, Parse_boolean, 0], + + 'FilterEnvelope' => [1, 1, Parse_any, undef], + + $self->getExtraParams(), + *$self->{OneShot} ? $self->getOneShotParams() + : (), + }, + @_) or $self->croakError("${class}: $got->{Error}") ; + + return $got ; +} + +sub _create +{ + my $obj = shift; + my $got = shift; + + *$obj->{Closed} = 1 ; + + my $class = ref $obj; + $obj->croakError("$class: Missing Output parameter") + if ! @_ && ! $got ; + + my $outValue = shift ; + my $oneShot = 1 ; + + if (! $got) + { + $oneShot = 0 ; + $got = $obj->checkParams($class, undef, @_) + or return undef ; + } + + my $lax = ! $got->value('Strict') ; + + my $outType = whatIsOutput($outValue); + + $obj->ckOutputParam($class, $outValue) + or return undef ; + + if ($outType eq 'buffer') { + *$obj->{Buffer} = $outValue; + } + else { + my $buff = "" ; + *$obj->{Buffer} = \$buff ; + } + + # Merge implies Append + my $merge = $got->value('Merge') ; + my $appendOutput = $got->value('Append') || $merge ; + *$obj->{Append} = $appendOutput; + *$obj->{FilterEnvelope} = $got->value('FilterEnvelope') ; + + if ($merge) + { + # Switch off Merge mode if output file/buffer is empty/doesn't exist + if (($outType eq 'buffer' && length $$outValue == 0 ) || + ($outType ne 'buffer' && (! -e $outValue || (-w _ && -z _))) ) + { $merge = 0 } + } + + # If output is a file, check that it is writable + #no warnings; + #if ($outType eq 'filename' && -e $outValue && ! -w _) + # { return $obj->saveErrorString(undef, "Output file '$outValue' is not writable" ) } + + + + if ($got->parsed('Encode')) { + my $want_encoding = $got->value('Encode'); + *$obj->{Encoding} = getEncoding($obj, $class, $want_encoding); + } + + $obj->ckParams($got) + or $obj->croakError("${class}: " . $obj->error()); + + + $obj->saveStatus(STATUS_OK) ; + + my $status ; + if (! $merge) + { + *$obj->{Compress} = $obj->mkComp($got) + or return undef; + + *$obj->{UnCompSize} = new U64 ; + *$obj->{CompSize} = new U64 ; + + if ( $outType eq 'buffer') { + ${ *$obj->{Buffer} } = '' + unless $appendOutput ; + } + else { + if ($outType eq 'handle') { + *$obj->{FH} = $outValue ; + setBinModeOutput(*$obj->{FH}) ; + $outValue->flush() ; + *$obj->{Handle} = 1 ; + if ($appendOutput) + { + seek(*$obj->{FH}, 0, SEEK_END) + or return $obj->saveErrorString(undef, "Cannot seek to end of output filehandle: $!", $!) ; + + } + } + elsif ($outType eq 'filename') { + no warnings; + my $mode = '>' ; + $mode = '>>' + if $appendOutput; + *$obj->{FH} = new IO::File "$mode $outValue" + or return $obj->saveErrorString(undef, "cannot open file '$outValue': $!", $!) ; + *$obj->{StdIO} = ($outValue eq '-'); + setBinModeOutput(*$obj->{FH}) ; + } + } + + *$obj->{Header} = $obj->mkHeader($got) ; + $obj->output( *$obj->{Header} ) + or return undef; + } + else + { + *$obj->{Compress} = $obj->createMerge($outValue, $outType) + or return undef; + } + + *$obj->{Closed} = 0 ; + *$obj->{AutoClose} = $got->value('AutoClose') ; + *$obj->{Output} = $outValue; + *$obj->{ClassName} = $class; + *$obj->{Got} = $got; + *$obj->{OneShot} = 0 ; + + return $obj ; +} + +sub ckOutputParam +{ + my $self = shift ; + my $from = shift ; + my $outType = whatIsOutput($_[0]); + + $self->croakError("$from: output parameter not a filename, filehandle or scalar ref") + if ! $outType ; + + #$self->croakError("$from: output filename is undef or null string") + #if $outType eq 'filename' && (! defined $_[0] || $_[0] eq '') ; + + $self->croakError("$from: output buffer is read-only") + if $outType eq 'buffer' && readonly(${ $_[0] }); + + return 1; +} + + +sub _def +{ + my $obj = shift ; + + my $class= (caller)[0] ; + my $name = (caller(1))[3] ; + + $obj->croakError("$name: expected at least 1 parameters\n") + unless @_ >= 1 ; + + my $input = shift ; + my $haveOut = @_ ; + my $output = shift ; + + my $x = new IO::Compress::Base::Validator($class, *$obj->{Error}, $name, $input, $output) + or return undef ; + + push @_, $output if $haveOut && $x->{Hash}; + + *$obj->{OneShot} = 1 ; + + my $got = $obj->checkParams($name, undef, @_) + or return undef ; + + $x->{Got} = $got ; + +# if ($x->{Hash}) +# { +# while (my($k, $v) = each %$input) +# { +# $v = \$input->{$k} +# unless defined $v ; +# +# $obj->_singleTarget($x, 1, $k, $v, @_) +# or return undef ; +# } +# +# return keys %$input ; +# } + + if ($x->{GlobMap}) + { + $x->{oneInput} = 1 ; + foreach my $pair (@{ $x->{Pairs} }) + { + my ($from, $to) = @$pair ; + $obj->_singleTarget($x, 1, $from, $to, @_) + or return undef ; + } + + return scalar @{ $x->{Pairs} } ; + } + + if (! $x->{oneOutput} ) + { + my $inFile = ($x->{inType} eq 'filenames' + || $x->{inType} eq 'filename'); + + $x->{inType} = $inFile ? 'filename' : 'buffer'; + + foreach my $in ($x->{oneInput} ? $input : @$input) + { + my $out ; + $x->{oneInput} = 1 ; + + $obj->_singleTarget($x, $inFile, $in, \$out, @_) + or return undef ; + + push @$output, \$out ; + #if ($x->{outType} eq 'array') + # { push @$output, \$out } + #else + # { $output->{$in} = \$out } + } + + return 1 ; + } + + # finally the 1 to 1 and n to 1 + return $obj->_singleTarget($x, 1, $input, $output, @_); + + croak "should not be here" ; +} + +sub _singleTarget +{ + my $obj = shift ; + my $x = shift ; + my $inputIsFilename = shift; + my $input = shift; + + if ($x->{oneInput}) + { + $obj->getFileInfo($x->{Got}, $input) + if isaFilename($input) and $inputIsFilename ; + + my $z = $obj->_create($x->{Got}, @_) + or return undef ; + + + defined $z->_wr2($input, $inputIsFilename) + or return $z->closeError(undef) ; + + return $z->close() ; + } + else + { + my $afterFirst = 0 ; + my $inputIsFilename = ($x->{inType} ne 'array'); + my $keep = $x->{Got}->clone(); + + #for my $element ( ($x->{inType} eq 'hash') ? keys %$input : @$input) + for my $element ( @$input) + { + my $isFilename = isaFilename($element); + + if ( $afterFirst ++ ) + { + defined addInterStream($obj, $element, $isFilename) + or return $obj->closeError(undef) ; + } + else + { + $obj->getFileInfo($x->{Got}, $element) + if $isFilename; + + $obj->_create($x->{Got}, @_) + or return undef ; + } + + defined $obj->_wr2($element, $isFilename) + or return $obj->closeError(undef) ; + + *$obj->{Got} = $keep->clone(); + } + return $obj->close() ; + } + +} + +sub _wr2 +{ + my $self = shift ; + + my $source = shift ; + my $inputIsFilename = shift; + + my $input = $source ; + if (! $inputIsFilename) + { + $input = \$source + if ! ref $source; + } + + if ( ref $input && ref $input eq 'SCALAR' ) + { + return $self->syswrite($input, @_) ; + } + + if ( ! ref $input || isaFilehandle($input)) + { + my $isFilehandle = isaFilehandle($input) ; + + my $fh = $input ; + + if ( ! $isFilehandle ) + { + $fh = new IO::File "<$input" + or return $self->saveErrorString(undef, "cannot open file '$input': $!", $!) ; + } + binmode $fh if *$self->{Got}->valueOrDefault('BinModeIn') ; + + my $status ; + my $buff ; + my $count = 0 ; + while ($status = read($fh, $buff, 16 * 1024)) { + $count += length $buff; + defined $self->syswrite($buff, @_) + or return undef ; + } + + return $self->saveErrorString(undef, $!, $!) + if ! defined $status ; + + if ( (!$isFilehandle || *$self->{AutoClose}) && $input ne '-') + { + $fh->close() + or return undef ; + } + + return $count ; + } + + croak "Should not be here"; + return undef; +} + +sub addInterStream +{ + my $self = shift ; + my $input = shift ; + my $inputIsFilename = shift ; + + if (*$self->{Got}->value('MultiStream')) + { + $self->getFileInfo(*$self->{Got}, $input) + #if isaFilename($input) and $inputIsFilename ; + if isaFilename($input) ; + + # TODO -- newStream needs to allow gzip/zip header to be modified + return $self->newStream(); + } + elsif (*$self->{Got}->value('AutoFlush')) + { + #return $self->flush(Z_FULL_FLUSH); + } + + return 1 ; +} + +sub getFileInfo +{ +} + +sub TIEHANDLE +{ + return $_[0] if ref($_[0]); + die "OOPS\n" ; +} + +sub UNTIE +{ + my $self = shift ; +} + +sub DESTROY +{ + my $self = shift ; + local ($., $@, $!, $^E, $?); + + $self->close() ; + + # TODO - memory leak with 5.8.0 - this isn't called until + # global destruction + # + %{ *$self } = () ; + undef $self ; +} + + + +sub filterUncompressed +{ +} + +sub syswrite +{ + my $self = shift ; + + my $buffer ; + if (ref $_[0] ) { + $self->croakError( *$self->{ClassName} . "::write: not a scalar reference" ) + unless ref $_[0] eq 'SCALAR' ; + $buffer = $_[0] ; + } + else { + $buffer = \$_[0] ; + } + + $] >= 5.008 and ( utf8::downgrade($$buffer, 1) + or croak "Wide character in " . *$self->{ClassName} . "::write:"); + + + if (@_ > 1) { + my $slen = defined $$buffer ? length($$buffer) : 0; + my $len = $slen; + my $offset = 0; + $len = $_[1] if $_[1] < $len; + + if (@_ > 2) { + $offset = $_[2] || 0; + $self->croakError(*$self->{ClassName} . "::write: offset outside string") + if $offset > $slen; + if ($offset < 0) { + $offset += $slen; + $self->croakError( *$self->{ClassName} . "::write: offset outside string") if $offset < 0; + } + my $rem = $slen - $offset; + $len = $rem if $rem < $len; + } + + $buffer = \substr($$buffer, $offset, $len) ; + } + + return 0 if ! defined $$buffer || length $$buffer == 0 ; + + if (*$self->{Encoding}) { + $$buffer = *$self->{Encoding}->encode($$buffer); + } + + $self->filterUncompressed($buffer); + + my $buffer_length = defined $$buffer ? length($$buffer) : 0 ; + *$self->{UnCompSize}->add($buffer_length) ; + + my $outBuffer=''; + my $status = *$self->{Compress}->compr($buffer, $outBuffer) ; + + return $self->saveErrorString(undef, *$self->{Compress}{Error}, + *$self->{Compress}{ErrorNo}) + if $status == STATUS_ERROR; + + *$self->{CompSize}->add(length $outBuffer) ; + + $self->output($outBuffer) + or return undef; + + return $buffer_length; +} + +sub print +{ + my $self = shift; + + #if (ref $self) { + # $self = *$self{GLOB} ; + #} + + if (defined $\) { + if (defined $,) { + defined $self->syswrite(join($,, @_) . $\); + } else { + defined $self->syswrite(join("", @_) . $\); + } + } else { + if (defined $,) { + defined $self->syswrite(join($,, @_)); + } else { + defined $self->syswrite(join("", @_)); + } + } +} + +sub printf +{ + my $self = shift; + my $fmt = shift; + defined $self->syswrite(sprintf($fmt, @_)); +} + + + +sub flush +{ + my $self = shift ; + + my $outBuffer=''; + my $status = *$self->{Compress}->flush($outBuffer, @_) ; + return $self->saveErrorString(0, *$self->{Compress}{Error}, + *$self->{Compress}{ErrorNo}) + if $status == STATUS_ERROR; + + if ( defined *$self->{FH} ) { + *$self->{FH}->clearerr(); + } + + *$self->{CompSize}->add(length $outBuffer) ; + + $self->output($outBuffer) + or return 0; + + if ( defined *$self->{FH} ) { + defined *$self->{FH}->flush() + or return $self->saveErrorString(0, $!, $!); + } + + return 1; +} + +sub newStream +{ + my $self = shift ; + + $self->_writeTrailer() + or return 0 ; + + my $got = $self->checkParams('newStream', *$self->{Got}, @_) + or return 0 ; + + $self->ckParams($got) + or $self->croakError("newStream: $self->{Error}"); + + *$self->{Compress} = $self->mkComp($got) + or return 0; + + *$self->{Header} = $self->mkHeader($got) ; + $self->output(*$self->{Header} ) + or return 0; + + *$self->{UnCompSize}->reset(); + *$self->{CompSize}->reset(); + + return 1 ; +} + +sub reset +{ + my $self = shift ; + return *$self->{Compress}->reset() ; +} + +sub _writeTrailer +{ + my $self = shift ; + + my $trailer = ''; + + my $status = *$self->{Compress}->close($trailer) ; + return $self->saveErrorString(0, *$self->{Compress}{Error}, *$self->{Compress}{ErrorNo}) + if $status == STATUS_ERROR; + + *$self->{CompSize}->add(length $trailer) ; + + $trailer .= $self->mkTrailer(); + defined $trailer + or return 0; + + return $self->output($trailer); +} + +sub _writeFinalTrailer +{ + my $self = shift ; + + return $self->output($self->mkFinalTrailer()); +} + +sub close +{ + my $self = shift ; + + return 1 if *$self->{Closed} || ! *$self->{Compress} ; + *$self->{Closed} = 1 ; + + untie *$self + if $] >= 5.008 ; + + $self->_writeTrailer() + or return 0 ; + + $self->_writeFinalTrailer() + or return 0 ; + + $self->output( "", 1 ) + or return 0; + + if (defined *$self->{FH}) { + + #if (! *$self->{Handle} || *$self->{AutoClose}) { + if ((! *$self->{Handle} || *$self->{AutoClose}) && ! *$self->{StdIO}) { + $! = 0 ; + *$self->{FH}->close() + or return $self->saveErrorString(0, $!, $!); + } + delete *$self->{FH} ; + # This delete can set $! in older Perls, so reset the errno + $! = 0 ; + } + + return 1; +} + + +#sub total_in +#sub total_out +#sub msg +# +#sub crc +#{ +# my $self = shift ; +# return *$self->{Compress}->crc32() ; +#} +# +#sub msg +#{ +# my $self = shift ; +# return *$self->{Compress}->msg() ; +#} +# +#sub dict_adler +#{ +# my $self = shift ; +# return *$self->{Compress}->dict_adler() ; +#} +# +#sub get_Level +#{ +# my $self = shift ; +# return *$self->{Compress}->get_Level() ; +#} +# +#sub get_Strategy +#{ +# my $self = shift ; +# return *$self->{Compress}->get_Strategy() ; +#} + + +sub tell +{ + my $self = shift ; + + return *$self->{UnCompSize}->get32bit() ; +} + +sub eof +{ + my $self = shift ; + + return *$self->{Closed} ; +} + + +sub seek +{ + my $self = shift ; + my $position = shift; + my $whence = shift ; + + my $here = $self->tell() ; + my $target = 0 ; + + #use IO::Handle qw(SEEK_SET SEEK_CUR SEEK_END); + use IO::Handle ; + + if ($whence == IO::Handle::SEEK_SET) { + $target = $position ; + } + elsif ($whence == IO::Handle::SEEK_CUR || $whence == IO::Handle::SEEK_END) { + $target = $here + $position ; + } + else { + $self->croakError(*$self->{ClassName} . "::seek: unknown value, $whence, for whence parameter"); + } + + # short circuit if seeking to current offset + return 1 if $target == $here ; + + # Outlaw any attempt to seek backwards + $self->croakError(*$self->{ClassName} . "::seek: cannot seek backwards") + if $target < $here ; + + # Walk the file to the new offset + my $offset = $target - $here ; + + my $buffer ; + defined $self->syswrite("\x00" x $offset) + or return 0; + + return 1 ; +} + +sub binmode +{ + 1; +# my $self = shift ; +# return defined *$self->{FH} +# ? binmode *$self->{FH} +# : 1 ; +} + +sub fileno +{ + my $self = shift ; + return defined *$self->{FH} + ? *$self->{FH}->fileno() + : undef ; +} + +sub opened +{ + my $self = shift ; + return ! *$self->{Closed} ; +} + +sub autoflush +{ + my $self = shift ; + return defined *$self->{FH} + ? *$self->{FH}->autoflush(@_) + : undef ; +} + +sub input_line_number +{ + return undef ; +} + + +sub _notAvailable +{ + my $name = shift ; + return sub { croak "$name Not Available: File opened only for output" ; } ; +} + +*read = _notAvailable('read'); +*READ = _notAvailable('read'); +*readline = _notAvailable('readline'); +*READLINE = _notAvailable('readline'); +*getc = _notAvailable('getc'); +*GETC = _notAvailable('getc'); + +*FILENO = \&fileno; +*PRINT = \&print; +*PRINTF = \&printf; +*WRITE = \&syswrite; +*write = \&syswrite; +*SEEK = \&seek; +*TELL = \&tell; +*EOF = \&eof; +*CLOSE = \&close; +*BINMODE = \&binmode; + +#*sysread = \&_notAvailable; +#*syswrite = \&_write; + +1; + +__END__ + +=head1 NAME + +IO::Compress::Base - Base Class for IO::Compress modules + +=head1 SYNOPSIS + + use IO::Compress::Base ; + +=head1 DESCRIPTION + +This module is not intended for direct use in application code. Its sole +purpose if to to be sub-classed by IO::Compress modules. + +=head1 SEE ALSO + +L<Compress::Zlib>, L<IO::Compress::Gzip>, L<IO::Uncompress::Gunzip>, L<IO::Compress::Deflate>, L<IO::Uncompress::Inflate>, L<IO::Compress::RawDeflate>, L<IO::Uncompress::RawInflate>, L<IO::Compress::Bzip2>, L<IO::Uncompress::Bunzip2>, L<IO::Compress::Lzma>, L<IO::Uncompress::UnLzma>, L<IO::Compress::Xz>, L<IO::Uncompress::UnXz>, L<IO::Compress::Lzop>, L<IO::Uncompress::UnLzop>, L<IO::Compress::Lzf>, L<IO::Uncompress::UnLzf>, L<IO::Uncompress::AnyInflate>, L<IO::Uncompress::AnyUncompress> + +L<Compress::Zlib::FAQ|Compress::Zlib::FAQ> + +L<File::GlobMapper|File::GlobMapper>, L<Archive::Zip|Archive::Zip>, +L<Archive::Tar|Archive::Tar>, +L<IO::Zlib|IO::Zlib> + +=head1 AUTHOR + +This module was written by Paul Marquess, F<pmqs@cpan.org>. + +=head1 MODIFICATION HISTORY + +See the Changes file. + +=head1 COPYRIGHT AND LICENSE + +Copyright (c) 2005-2010 Paul Marquess. All rights reserved. + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + diff --git a/Master/tlpkg/tlperl/lib/IO/Compress/Base/Common.pm b/Master/tlpkg/tlperl/lib/IO/Compress/Base/Common.pm new file mode 100644 index 00000000000..4f8b4dadc36 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Compress/Base/Common.pm @@ -0,0 +1,956 @@ +package IO::Compress::Base::Common; + +use strict ; +use warnings; +use bytes; + +use Carp; +use Scalar::Util qw(blessed readonly); +use File::GlobMapper; + +require Exporter; +our ($VERSION, @ISA, @EXPORT, %EXPORT_TAGS, $HAS_ENCODE); +@ISA = qw(Exporter); +$VERSION = '2.024'; + +@EXPORT = qw( isaFilehandle isaFilename whatIsInput whatIsOutput + isaFileGlobString cleanFileGlobString oneTarget + setBinModeInput setBinModeOutput + ckInOutParams + createSelfTiedObject + getEncoding + + WANT_CODE + WANT_EXT + WANT_UNDEF + WANT_HASH + + STATUS_OK + STATUS_ENDSTREAM + STATUS_EOF + STATUS_ERROR + ); + +%EXPORT_TAGS = ( Status => [qw( STATUS_OK + STATUS_ENDSTREAM + STATUS_EOF + STATUS_ERROR + )]); + + +use constant STATUS_OK => 0; +use constant STATUS_ENDSTREAM => 1; +use constant STATUS_EOF => 2; +use constant STATUS_ERROR => -1; + +sub hasEncode() +{ + if (! defined $HAS_ENCODE) { + eval + { + require Encode; + Encode->import(); + }; + + $HAS_ENCODE = $@ ? 0 : 1 ; + } + + return $HAS_ENCODE; +} + +sub getEncoding($$$) +{ + my $obj = shift; + my $class = shift ; + my $want_encoding = shift ; + + $obj->croakError("$class: Encode module needed to use -Encode") + if ! hasEncode(); + + my $encoding = Encode::find_encoding($want_encoding); + + $obj->croakError("$class: Encoding '$want_encoding' is not available") + if ! $encoding; + + return $encoding; +} + +our ($needBinmode); +$needBinmode = ($^O eq 'MSWin32' || + ($] >= 5.006 && eval ' ${^UNICODE} || ${^UTF8LOCALE} ')) + ? 1 : 1 ; + +sub setBinModeInput($) +{ + my $handle = shift ; + + binmode $handle + if $needBinmode; +} + +sub setBinModeOutput($) +{ + my $handle = shift ; + + binmode $handle + if $needBinmode; +} + +sub isaFilehandle($) +{ + use utf8; # Pragma needed to keep Perl 5.6.0 happy + return (defined $_[0] and + (UNIVERSAL::isa($_[0],'GLOB') or + UNIVERSAL::isa($_[0],'IO::Handle') or + UNIVERSAL::isa(\$_[0],'GLOB')) + ) +} + +sub isaFilename($) +{ + return (defined $_[0] and + ! ref $_[0] and + UNIVERSAL::isa(\$_[0], 'SCALAR')); +} + +sub isaFileGlobString +{ + return defined $_[0] && $_[0] =~ /^<.*>$/; +} + +sub cleanFileGlobString +{ + my $string = shift ; + + $string =~ s/^\s*<\s*(.*)\s*>\s*$/$1/; + + return $string; +} + +use constant WANT_CODE => 1 ; +use constant WANT_EXT => 2 ; +use constant WANT_UNDEF => 4 ; +#use constant WANT_HASH => 8 ; +use constant WANT_HASH => 0 ; + +sub whatIsInput($;$) +{ + my $got = whatIs(@_); + + if (defined $got && $got eq 'filename' && defined $_[0] && $_[0] eq '-') + { + #use IO::File; + $got = 'handle'; + $_[0] = *STDIN; + #$_[0] = new IO::File("<-"); + } + + return $got; +} + +sub whatIsOutput($;$) +{ + my $got = whatIs(@_); + + if (defined $got && $got eq 'filename' && defined $_[0] && $_[0] eq '-') + { + $got = 'handle'; + $_[0] = *STDOUT; + #$_[0] = new IO::File(">-"); + } + + return $got; +} + +sub whatIs ($;$) +{ + return 'handle' if isaFilehandle($_[0]); + + my $wantCode = defined $_[1] && $_[1] & WANT_CODE ; + my $extended = defined $_[1] && $_[1] & WANT_EXT ; + my $undef = defined $_[1] && $_[1] & WANT_UNDEF ; + my $hash = defined $_[1] && $_[1] & WANT_HASH ; + + return 'undef' if ! defined $_[0] && $undef ; + + if (ref $_[0]) { + return '' if blessed($_[0]); # is an object + #return '' if UNIVERSAL::isa($_[0], 'UNIVERSAL'); # is an object + return 'buffer' if UNIVERSAL::isa($_[0], 'SCALAR'); + return 'array' if UNIVERSAL::isa($_[0], 'ARRAY') && $extended ; + return 'hash' if UNIVERSAL::isa($_[0], 'HASH') && $hash ; + return 'code' if UNIVERSAL::isa($_[0], 'CODE') && $wantCode ; + return ''; + } + + return 'fileglob' if $extended && isaFileGlobString($_[0]); + return 'filename'; +} + +sub oneTarget +{ + return $_[0] =~ /^(code|handle|buffer|filename)$/; +} + +sub IO::Compress::Base::Validator::new +{ + my $class = shift ; + + my $Class = shift ; + my $error_ref = shift ; + my $reportClass = shift ; + + my %data = (Class => $Class, + Error => $error_ref, + reportClass => $reportClass, + ) ; + + my $obj = bless \%data, $class ; + + local $Carp::CarpLevel = 1; + + my $inType = $data{inType} = whatIsInput($_[0], WANT_EXT|WANT_HASH); + my $outType = $data{outType} = whatIsOutput($_[1], WANT_EXT|WANT_HASH); + + my $oneInput = $data{oneInput} = oneTarget($inType); + my $oneOutput = $data{oneOutput} = oneTarget($outType); + + if (! $inType) + { + $obj->croakError("$reportClass: illegal input parameter") ; + #return undef ; + } + +# if ($inType eq 'hash') +# { +# $obj->{Hash} = 1 ; +# $obj->{oneInput} = 1 ; +# return $obj->validateHash($_[0]); +# } + + if (! $outType) + { + $obj->croakError("$reportClass: illegal output parameter") ; + #return undef ; + } + + + if ($inType ne 'fileglob' && $outType eq 'fileglob') + { + $obj->croakError("Need input fileglob for outout fileglob"); + } + +# if ($inType ne 'fileglob' && $outType eq 'hash' && $inType ne 'filename' ) +# { +# $obj->croakError("input must ne filename or fileglob when output is a hash"); +# } + + if ($inType eq 'fileglob' && $outType eq 'fileglob') + { + $data{GlobMap} = 1 ; + $data{inType} = $data{outType} = 'filename'; + my $mapper = new File::GlobMapper($_[0], $_[1]); + if ( ! $mapper ) + { + return $obj->saveErrorString($File::GlobMapper::Error) ; + } + $data{Pairs} = $mapper->getFileMap(); + + return $obj; + } + + $obj->croakError("$reportClass: input and output $inType are identical") + if $inType eq $outType && $_[0] eq $_[1] && $_[0] ne '-' ; + + if ($inType eq 'fileglob') # && $outType ne 'fileglob' + { + my $glob = cleanFileGlobString($_[0]); + my @inputs = glob($glob); + + if (@inputs == 0) + { + # TODO -- legal or die? + die "globmap matched zero file -- legal or die???" ; + } + elsif (@inputs == 1) + { + $obj->validateInputFilenames($inputs[0]) + or return undef; + $_[0] = $inputs[0] ; + $data{inType} = 'filename' ; + $data{oneInput} = 1; + } + else + { + $obj->validateInputFilenames(@inputs) + or return undef; + $_[0] = [ @inputs ] ; + $data{inType} = 'filenames' ; + } + } + elsif ($inType eq 'filename') + { + $obj->validateInputFilenames($_[0]) + or return undef; + } + elsif ($inType eq 'array') + { + $data{inType} = 'filenames' ; + $obj->validateInputArray($_[0]) + or return undef ; + } + + return $obj->saveErrorString("$reportClass: output buffer is read-only") + if $outType eq 'buffer' && readonly(${ $_[1] }); + + if ($outType eq 'filename' ) + { + $obj->croakError("$reportClass: output filename is undef or null string") + if ! defined $_[1] || $_[1] eq '' ; + + if (-e $_[1]) + { + if (-d _ ) + { + return $obj->saveErrorString("output file '$_[1]' is a directory"); + } + } + } + + return $obj ; +} + +sub IO::Compress::Base::Validator::saveErrorString +{ + my $self = shift ; + ${ $self->{Error} } = shift ; + return undef; + +} + +sub IO::Compress::Base::Validator::croakError +{ + my $self = shift ; + $self->saveErrorString($_[0]); + croak $_[0]; +} + + + +sub IO::Compress::Base::Validator::validateInputFilenames +{ + my $self = shift ; + + foreach my $filename (@_) + { + $self->croakError("$self->{reportClass}: input filename is undef or null string") + if ! defined $filename || $filename eq '' ; + + next if $filename eq '-'; + + if (! -e $filename ) + { + return $self->saveErrorString("input file '$filename' does not exist"); + } + + if (-d _ ) + { + return $self->saveErrorString("input file '$filename' is a directory"); + } + + if (! -r _ ) + { + return $self->saveErrorString("cannot open file '$filename': $!"); + } + } + + return 1 ; +} + +sub IO::Compress::Base::Validator::validateInputArray +{ + my $self = shift ; + + if ( @{ $_[0] } == 0 ) + { + return $self->saveErrorString("empty array reference") ; + } + + foreach my $element ( @{ $_[0] } ) + { + my $inType = whatIsInput($element); + + if (! $inType) + { + $self->croakError("unknown input parameter") ; + } + elsif($inType eq 'filename') + { + $self->validateInputFilenames($element) + or return undef ; + } + else + { + $self->croakError("not a filename") ; + } + } + + return 1 ; +} + +#sub IO::Compress::Base::Validator::validateHash +#{ +# my $self = shift ; +# my $href = shift ; +# +# while (my($k, $v) = each %$href) +# { +# my $ktype = whatIsInput($k); +# my $vtype = whatIsOutput($v, WANT_EXT|WANT_UNDEF) ; +# +# if ($ktype ne 'filename') +# { +# return $self->saveErrorString("hash key not filename") ; +# } +# +# my %valid = map { $_ => 1 } qw(filename buffer array undef handle) ; +# if (! $valid{$vtype}) +# { +# return $self->saveErrorString("hash value not ok") ; +# } +# } +# +# return $self ; +#} + +sub createSelfTiedObject +{ + my $class = shift || (caller)[0] ; + my $error_ref = shift ; + + my $obj = bless Symbol::gensym(), ref($class) || $class; + tie *$obj, $obj if $] >= 5.005; + *$obj->{Closed} = 1 ; + $$error_ref = ''; + *$obj->{Error} = $error_ref ; + my $errno = 0 ; + *$obj->{ErrorNo} = \$errno ; + + return $obj; +} + + + +#package Parse::Parameters ; +# +# +#require Exporter; +#our ($VERSION, @ISA, @EXPORT); +#$VERSION = '2.000_08'; +#@ISA = qw(Exporter); + +$EXPORT_TAGS{Parse} = [qw( ParseParameters + Parse_any Parse_unsigned Parse_signed + Parse_boolean Parse_custom Parse_string + Parse_multiple Parse_writable_scalar + ) + ]; + +push @EXPORT, @{ $EXPORT_TAGS{Parse} } ; + +use constant Parse_any => 0x01; +use constant Parse_unsigned => 0x02; +use constant Parse_signed => 0x04; +use constant Parse_boolean => 0x08; +use constant Parse_string => 0x10; +use constant Parse_custom => 0x12; + +#use constant Parse_store_ref => 0x100 ; +use constant Parse_multiple => 0x100 ; +use constant Parse_writable => 0x200 ; +use constant Parse_writable_scalar => 0x400 | Parse_writable ; + +use constant OFF_PARSED => 0 ; +use constant OFF_TYPE => 1 ; +use constant OFF_DEFAULT => 2 ; +use constant OFF_FIXED => 3 ; +use constant OFF_FIRST_ONLY => 4 ; +use constant OFF_STICKY => 5 ; + + + +sub ParseParameters +{ + my $level = shift || 0 ; + + my $sub = (caller($level + 1))[3] ; + local $Carp::CarpLevel = 1 ; + + return $_[1] + if @_ == 2 && defined $_[1] && UNIVERSAL::isa($_[1], "IO::Compress::Base::Parameters"); + + my $p = new IO::Compress::Base::Parameters() ; + $p->parse(@_) + or croak "$sub: $p->{Error}" ; + + return $p; +} + +#package IO::Compress::Base::Parameters; + +use strict; +use warnings; +use Carp; + +sub IO::Compress::Base::Parameters::new +{ + my $class = shift ; + + my $obj = { Error => '', + Got => {}, + } ; + + #return bless $obj, ref($class) || $class || __PACKAGE__ ; + return bless $obj, 'IO::Compress::Base::Parameters' ; +} + +sub IO::Compress::Base::Parameters::setError +{ + my $self = shift ; + my $error = shift ; + my $retval = @_ ? shift : undef ; + + $self->{Error} = $error ; + return $retval; +} + +#sub getError +#{ +# my $self = shift ; +# return $self->{Error} ; +#} + +sub IO::Compress::Base::Parameters::parse +{ + my $self = shift ; + + my $default = shift ; + + my $got = $self->{Got} ; + my $firstTime = keys %{ $got } == 0 ; + my $other; + + my (@Bad) ; + my @entered = () ; + + # Allow the options to be passed as a hash reference or + # as the complete hash. + if (@_ == 0) { + @entered = () ; + } + elsif (@_ == 1) { + my $href = $_[0] ; + + return $self->setError("Expected even number of parameters, got 1") + if ! defined $href or ! ref $href or ref $href ne "HASH" ; + + foreach my $key (keys %$href) { + push @entered, $key ; + push @entered, \$href->{$key} ; + } + } + else { + my $count = @_; + return $self->setError("Expected even number of parameters, got $count") + if $count % 2 != 0 ; + + for my $i (0.. $count / 2 - 1) { + if ($_[2 * $i] eq '__xxx__') { + $other = $_[2 * $i + 1] ; + } + else { + push @entered, $_[2 * $i] ; + push @entered, \$_[2 * $i + 1] ; + } + } + } + + + while (my ($key, $v) = each %$default) + { + croak "need 4 params [@$v]" + if @$v != 4 ; + + my ($first_only, $sticky, $type, $value) = @$v ; + my $x ; + $self->_checkType($key, \$value, $type, 0, \$x) + or return undef ; + + $key = lc $key; + + if ($firstTime || ! $sticky) { + $x = [] + if $type & Parse_multiple; + + $got->{$key} = [0, $type, $value, $x, $first_only, $sticky] ; + } + + $got->{$key}[OFF_PARSED] = 0 ; + } + + my %parsed = (); + + if ($other) + { + for my $key (keys %$default) + { + my $canonkey = lc $key; + if ($other->parsed($canonkey)) + { + my $value = $other->value($canonkey); +#print "SET '$canonkey' to $value [$$value]\n"; + ++ $parsed{$canonkey}; + $got->{$canonkey}[OFF_PARSED] = 1; + $got->{$canonkey}[OFF_DEFAULT] = $value; + $got->{$canonkey}[OFF_FIXED] = $value; + } + } + } + + for my $i (0.. @entered / 2 - 1) { + my $key = $entered[2* $i] ; + my $value = $entered[2* $i+1] ; + + #print "Key [$key] Value [$value]" ; + #print defined $$value ? "[$$value]\n" : "[undef]\n"; + + $key =~ s/^-// ; + my $canonkey = lc $key; + + if ($got->{$canonkey} && ($firstTime || + ! $got->{$canonkey}[OFF_FIRST_ONLY] )) + { + my $type = $got->{$canonkey}[OFF_TYPE] ; + my $parsed = $parsed{$canonkey}; + ++ $parsed{$canonkey}; + + return $self->setError("Muliple instances of '$key' found") + if $parsed && $type & Parse_multiple == 0 ; + + my $s ; + $self->_checkType($key, $value, $type, 1, \$s) + or return undef ; + + $value = $$value ; + if ($type & Parse_multiple) { + $got->{$canonkey}[OFF_PARSED] = 1; + push @{ $got->{$canonkey}[OFF_FIXED] }, $s ; + } + else { + $got->{$canonkey} = [1, $type, $value, $s] ; + } + } + else + { push (@Bad, $key) } + } + + if (@Bad) { + my ($bad) = join(", ", @Bad) ; + return $self->setError("unknown key value(s) $bad") ; + } + + return 1; +} + +sub IO::Compress::Base::Parameters::_checkType +{ + my $self = shift ; + + my $key = shift ; + my $value = shift ; + my $type = shift ; + my $validate = shift ; + my $output = shift; + + #local $Carp::CarpLevel = $level ; + #print "PARSE $type $key $value $validate $sub\n" ; + + if ($type & Parse_writable_scalar) + { + return $self->setError("Parameter '$key' not writable") + if $validate && readonly $$value ; + + if (ref $$value) + { + return $self->setError("Parameter '$key' not a scalar reference") + if $validate && ref $$value ne 'SCALAR' ; + + $$output = $$value ; + } + else + { + return $self->setError("Parameter '$key' not a scalar") + if $validate && ref $value ne 'SCALAR' ; + + $$output = $value ; + } + + return 1; + } + +# if ($type & Parse_store_ref) +# { +# #$value = $$value +# # if ref ${ $value } ; +# +# $$output = $value ; +# return 1; +# } + + $value = $$value ; + + if ($type & Parse_any) + { + $$output = $value ; + return 1; + } + elsif ($type & Parse_unsigned) + { + return $self->setError("Parameter '$key' must be an unsigned int, got 'undef'") + if $validate && ! defined $value ; + return $self->setError("Parameter '$key' must be an unsigned int, got '$value'") + if $validate && $value !~ /^\d+$/; + + $$output = defined $value ? $value : 0 ; + return 1; + } + elsif ($type & Parse_signed) + { + return $self->setError("Parameter '$key' must be a signed int, got 'undef'") + if $validate && ! defined $value ; + return $self->setError("Parameter '$key' must be a signed int, got '$value'") + if $validate && $value !~ /^-?\d+$/; + + $$output = defined $value ? $value : 0 ; + return 1 ; + } + elsif ($type & Parse_boolean) + { + return $self->setError("Parameter '$key' must be an int, got '$value'") + if $validate && defined $value && $value !~ /^\d*$/; + $$output = defined $value ? $value != 0 : 0 ; + return 1; + } + elsif ($type & Parse_string) + { + $$output = defined $value ? $value : "" ; + return 1; + } + + $$output = $value ; + return 1; +} + + + +sub IO::Compress::Base::Parameters::parsed +{ + my $self = shift ; + my $name = shift ; + + return $self->{Got}{lc $name}[OFF_PARSED] ; +} + +sub IO::Compress::Base::Parameters::value +{ + my $self = shift ; + my $name = shift ; + + if (@_) + { + $self->{Got}{lc $name}[OFF_PARSED] = 1; + $self->{Got}{lc $name}[OFF_DEFAULT] = $_[0] ; + $self->{Got}{lc $name}[OFF_FIXED] = $_[0] ; + } + + return $self->{Got}{lc $name}[OFF_FIXED] ; +} + +sub IO::Compress::Base::Parameters::valueOrDefault +{ + my $self = shift ; + my $name = shift ; + my $default = shift ; + + my $value = $self->{Got}{lc $name}[OFF_DEFAULT] ; + + return $value if defined $value ; + return $default ; +} + +sub IO::Compress::Base::Parameters::wantValue +{ + my $self = shift ; + my $name = shift ; + + return defined $self->{Got}{lc $name}[OFF_DEFAULT] ; + +} + +sub IO::Compress::Base::Parameters::clone +{ + my $self = shift ; + my $obj = { }; + my %got ; + + while (my ($k, $v) = each %{ $self->{Got} }) { + $got{$k} = [ @$v ]; + } + + $obj->{Error} = $self->{Error}; + $obj->{Got} = \%got ; + + return bless $obj, 'IO::Compress::Base::Parameters' ; +} + +package U64; + +use constant MAX32 => 0xFFFFFFFF ; +use constant HI_1 => MAX32 + 1 ; +use constant LOW => 0 ; +use constant HIGH => 1; + +sub new +{ + my $class = shift ; + + my $high = 0 ; + my $low = 0 ; + + if (@_ == 2) { + $high = shift ; + $low = shift ; + } + elsif (@_ == 1) { + $low = shift ; + } + + bless [$low, $high], $class; +} + +sub newUnpack_V64 +{ + my $string = shift; + + my ($low, $hi) = unpack "V V", $string ; + bless [ $low, $hi ], "U64"; +} + +sub newUnpack_V32 +{ + my $string = shift; + + my $low = unpack "V", $string ; + bless [ $low, 0 ], "U64"; +} + +sub reset +{ + my $self = shift; + $self->[HIGH] = $self->[LOW] = 0; +} + +sub clone +{ + my $self = shift; + bless [ @$self ], ref $self ; +} + +sub getHigh +{ + my $self = shift; + return $self->[HIGH]; +} + +sub getLow +{ + my $self = shift; + return $self->[LOW]; +} + +sub get32bit +{ + my $self = shift; + return $self->[LOW]; +} + +sub get64bit +{ + my $self = shift; + # Not using << here because the result will still be + # a 32-bit value on systems where int size is 32-bits + return $self->[HIGH] * HI_1 + $self->[LOW]; +} + +sub add +{ + my $self = shift; + my $value = shift; + + if (ref $value eq 'U64') { + $self->[HIGH] += $value->[HIGH] ; + $value = $value->[LOW]; + } + + my $available = MAX32 - $self->[LOW] ; + + if ($value > $available) { + ++ $self->[HIGH] ; + $self->[LOW] = $value - $available - 1; + } + else { + $self->[LOW] += $value ; + } + +} + +sub equal +{ + my $self = shift; + my $other = shift; + + return $self->[LOW] == $other->[LOW] && + $self->[HIGH] == $other->[HIGH] ; +} + +sub is64bit +{ + my $self = shift; + return $self->[HIGH] > 0 ; +} + +sub getPacked_V64 +{ + my $self = shift; + + return pack "V V", @$self ; +} + +sub getPacked_V32 +{ + my $self = shift; + + return pack "V", $self->[LOW] ; +} + +sub pack_V64 +{ + my $low = shift; + + return pack "V V", $low, 0; +} + + +package IO::Compress::Base::Common; + +1; diff --git a/Master/tlpkg/tlperl/lib/IO/Compress/Bzip2.pm b/Master/tlpkg/tlperl/lib/IO/Compress/Bzip2.pm new file mode 100644 index 00000000000..2a85ef55b19 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Compress/Bzip2.pm @@ -0,0 +1,758 @@ +package IO::Compress::Bzip2 ; + +use strict ; +use warnings; +use bytes; +require Exporter ; + +use IO::Compress::Base 2.024 ; + +use IO::Compress::Base::Common 2.024 qw(createSelfTiedObject); +use IO::Compress::Adapter::Bzip2 2.024 ; + + + +our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, $Bzip2Error); + +$VERSION = '2.024'; +$Bzip2Error = ''; + +@ISA = qw(Exporter IO::Compress::Base); +@EXPORT_OK = qw( $Bzip2Error bzip2 ) ; +%EXPORT_TAGS = %IO::Compress::Base::EXPORT_TAGS ; +push @{ $EXPORT_TAGS{all} }, @EXPORT_OK ; +Exporter::export_ok_tags('all'); + + + +sub new +{ + my $class = shift ; + + my $obj = createSelfTiedObject($class, \$Bzip2Error); + return $obj->_create(undef, @_); +} + +sub bzip2 +{ + my $obj = createSelfTiedObject(undef, \$Bzip2Error); + $obj->_def(@_); +} + + +sub mkHeader +{ + my $self = shift ; + return ''; + +} + +sub getExtraParams +{ + my $self = shift ; + + use IO::Compress::Base::Common 2.024 qw(:Parse); + + return ( + 'BlockSize100K' => [0, 1, Parse_unsigned, 1], + 'WorkFactor' => [0, 1, Parse_unsigned, 0], + 'Verbosity' => [0, 1, Parse_boolean, 0], + ); +} + + + +sub ckParams +{ + my $self = shift ; + my $got = shift; + + # check that BlockSize100K is a number between 1 & 9 + if ($got->parsed('BlockSize100K')) { + my $value = $got->value('BlockSize100K'); + return $self->saveErrorString(undef, "Parameter 'BlockSize100K' not between 1 and 9, got $value") + unless defined $value && $value >= 1 && $value <= 9; + + } + + # check that WorkFactor between 0 & 250 + if ($got->parsed('WorkFactor')) { + my $value = $got->value('WorkFactor'); + return $self->saveErrorString(undef, "Parameter 'WorkFactor' not between 0 and 250, got $value") + unless $value >= 0 && $value <= 250; + } + + return 1 ; +} + + +sub mkComp +{ + my $self = shift ; + my $got = shift ; + + my $BlockSize100K = $got->value('BlockSize100K'); + my $WorkFactor = $got->value('WorkFactor'); + my $Verbosity = $got->value('Verbosity'); + + my ($obj, $errstr, $errno) = IO::Compress::Adapter::Bzip2::mkCompObject( + $BlockSize100K, $WorkFactor, + $Verbosity); + + return $self->saveErrorString(undef, $errstr, $errno) + if ! defined $obj; + + return $obj; +} + + +sub mkTrailer +{ + my $self = shift ; + return ''; +} + +sub mkFinalTrailer +{ + return ''; +} + +#sub newHeader +#{ +# my $self = shift ; +# return ''; +#} + +sub getInverseClass +{ + return ('IO::Uncompress::Bunzip2'); +} + +sub getFileInfo +{ + my $self = shift ; + my $params = shift; + my $file = shift ; + +} + +1; + +__END__ + +=head1 NAME + +IO::Compress::Bzip2 - Write bzip2 files/buffers + + + +=head1 SYNOPSIS + + use IO::Compress::Bzip2 qw(bzip2 $Bzip2Error) ; + + my $status = bzip2 $input => $output [,OPTS] + or die "bzip2 failed: $Bzip2Error\n"; + + my $z = new IO::Compress::Bzip2 $output [,OPTS] + or die "bzip2 failed: $Bzip2Error\n"; + + $z->print($string); + $z->printf($format, $string); + $z->write($string); + $z->syswrite($string [, $length, $offset]); + $z->flush(); + $z->tell(); + $z->eof(); + $z->seek($position, $whence); + $z->binmode(); + $z->fileno(); + $z->opened(); + $z->autoflush(); + $z->input_line_number(); + $z->newStream( [OPTS] ); + + $z->close() ; + + $Bzip2Error ; + + # IO::File mode + + print $z $string; + printf $z $format, $string; + tell $z + eof $z + seek $z, $position, $whence + binmode $z + fileno $z + close $z ; + + +=head1 DESCRIPTION + +This module provides a Perl interface that allows writing bzip2 +compressed data to files or buffer. + +For reading bzip2 files/buffers, see the companion module +L<IO::Uncompress::Bunzip2|IO::Uncompress::Bunzip2>. + +=head1 Functional Interface + +A top-level function, C<bzip2>, is provided to carry out +"one-shot" compression between buffers and/or files. For finer +control over the compression process, see the L</"OO Interface"> +section. + + use IO::Compress::Bzip2 qw(bzip2 $Bzip2Error) ; + + bzip2 $input => $output [,OPTS] + or die "bzip2 failed: $Bzip2Error\n"; + +The functional interface needs Perl5.005 or better. + +=head2 bzip2 $input => $output [, OPTS] + +C<bzip2> expects at least two parameters, C<$input> and C<$output>. + +=head3 The C<$input> parameter + +The parameter, C<$input>, is used to define the source of +the uncompressed data. + +It can take one of the following forms: + +=over 5 + +=item A filename + +If the C<$input> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for reading and the input data +will be read from it. + +=item A filehandle + +If the C<$input> parameter is a filehandle, the input data will be +read from it. +The string '-' can be used as an alias for standard input. + +=item A scalar reference + +If C<$input> is a scalar reference, the input data will be read +from C<$$input>. + +=item An array reference + +If C<$input> is an array reference, each element in the array must be a +filename. + +The input data will be read from each file in turn. + +The complete array will be walked to ensure that it only +contains valid filenames before any data is compressed. + +=item An Input FileGlob string + +If C<$input> is a string that is delimited by the characters "<" and ">" +C<bzip2> will assume that it is an I<input fileglob string>. The +input is the list of files that match the fileglob. + +If the fileglob does not match any files ... + +See L<File::GlobMapper|File::GlobMapper> for more details. + +=back + +If the C<$input> parameter is any other type, C<undef> will be returned. + +=head3 The C<$output> parameter + +The parameter C<$output> is used to control the destination of the +compressed data. This parameter can take one of these forms. + +=over 5 + +=item A filename + +If the C<$output> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for writing and the compressed +data will be written to it. + +=item A filehandle + +If the C<$output> parameter is a filehandle, the compressed data +will be written to it. +The string '-' can be used as an alias for standard output. + +=item A scalar reference + +If C<$output> is a scalar reference, the compressed data will be +stored in C<$$output>. + +=item An Array Reference + +If C<$output> is an array reference, the compressed data will be +pushed onto the array. + +=item An Output FileGlob + +If C<$output> is a string that is delimited by the characters "<" and ">" +C<bzip2> will assume that it is an I<output fileglob string>. The +output is the list of files that match the fileglob. + +When C<$output> is an fileglob string, C<$input> must also be a fileglob +string. Anything else is an error. + +=back + +If the C<$output> parameter is any other type, C<undef> will be returned. + +=head2 Notes + +When C<$input> maps to multiple files/buffers and C<$output> is a single +file/buffer the input files/buffers will be stored +in C<$output> as a concatenated series of compressed data streams. + +=head2 Optional Parameters + +Unless specified below, the optional parameters for C<bzip2>, +C<OPTS>, are the same as those used with the OO interface defined in the +L</"Constructor Options"> section below. + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option applies to any input or output data streams to +C<bzip2> that are filehandles. + +If C<AutoClose> is specified, and the value is true, it will result in all +input and/or output filehandles being closed once C<bzip2> has +completed. + +This parameter defaults to 0. + +=item C<< BinModeIn => 0|1 >> + +When reading from a file or filehandle, set C<binmode> before reading. + +Defaults to 0. + +=item C<< Append => 0|1 >> + +TODO + +=back + +=head2 Examples + +To read the contents of the file C<file1.txt> and write the compressed +data to the file C<file1.txt.bz2>. + + use strict ; + use warnings ; + use IO::Compress::Bzip2 qw(bzip2 $Bzip2Error) ; + + my $input = "file1.txt"; + bzip2 $input => "$input.bz2" + or die "bzip2 failed: $Bzip2Error\n"; + +To read from an existing Perl filehandle, C<$input>, and write the +compressed data to a buffer, C<$buffer>. + + use strict ; + use warnings ; + use IO::Compress::Bzip2 qw(bzip2 $Bzip2Error) ; + use IO::File ; + + my $input = new IO::File "<file1.txt" + or die "Cannot open 'file1.txt': $!\n" ; + my $buffer ; + bzip2 $input => \$buffer + or die "bzip2 failed: $Bzip2Error\n"; + +To compress all files in the directory "/my/home" that match "*.txt" +and store the compressed data in the same directory + + use strict ; + use warnings ; + use IO::Compress::Bzip2 qw(bzip2 $Bzip2Error) ; + + bzip2 '</my/home/*.txt>' => '<*.bz2>' + or die "bzip2 failed: $Bzip2Error\n"; + +and if you want to compress each file one at a time, this will do the trick + + use strict ; + use warnings ; + use IO::Compress::Bzip2 qw(bzip2 $Bzip2Error) ; + + for my $input ( glob "/my/home/*.txt" ) + { + my $output = "$input.bz2" ; + bzip2 $input => $output + or die "Error compressing '$input': $Bzip2Error\n"; + } + +=head1 OO Interface + +=head2 Constructor + +The format of the constructor for C<IO::Compress::Bzip2> is shown below + + my $z = new IO::Compress::Bzip2 $output [,OPTS] + or die "IO::Compress::Bzip2 failed: $Bzip2Error\n"; + +It returns an C<IO::Compress::Bzip2> object on success and undef on failure. +The variable C<$Bzip2Error> will contain an error message on failure. + +If you are running Perl 5.005 or better the object, C<$z>, returned from +IO::Compress::Bzip2 can be used exactly like an L<IO::File|IO::File> filehandle. +This means that all normal output file operations can be carried out +with C<$z>. +For example, to write to a compressed file/buffer you can use either of +these forms + + $z->print("hello world\n"); + print $z "hello world\n"; + +The mandatory parameter C<$output> is used to control the destination +of the compressed data. This parameter can take one of these forms. + +=over 5 + +=item A filename + +If the C<$output> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for writing and the compressed data +will be written to it. + +=item A filehandle + +If the C<$output> parameter is a filehandle, the compressed data will be +written to it. +The string '-' can be used as an alias for standard output. + +=item A scalar reference + +If C<$output> is a scalar reference, the compressed data will be stored +in C<$$output>. + +=back + +If the C<$output> parameter is any other type, C<IO::Compress::Bzip2>::new will +return undef. + +=head2 Constructor Options + +C<OPTS> is any combination of the following options: + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option is only valid when the C<$output> parameter is a filehandle. If +specified, and the value is true, it will result in the C<$output> being +closed once either the C<close> method is called or the C<IO::Compress::Bzip2> +object is destroyed. + +This parameter defaults to 0. + +=item C<< Append => 0|1 >> + +Opens C<$output> in append mode. + +The behaviour of this option is dependent on the type of C<$output>. + +=over 5 + +=item * A Buffer + +If C<$output> is a buffer and C<Append> is enabled, all compressed data +will be append to the end if C<$output>. Otherwise C<$output> will be +cleared before any data is written to it. + +=item * A Filename + +If C<$output> is a filename and C<Append> is enabled, the file will be +opened in append mode. Otherwise the contents of the file, if any, will be +truncated before any compressed data is written to it. + +=item * A Filehandle + +If C<$output> is a filehandle, the file pointer will be positioned to the +end of the file via a call to C<seek> before any compressed data is written +to it. Otherwise the file pointer will not be moved. + +=back + +This parameter defaults to 0. + +=item C<< BlockSize100K => number >> + +Specify the number of 100K blocks bzip2 uses during compression. + +Valid values are from 1 to 9, where 9 is best compression. + +The default is 1. + +=item C<< WorkFactor => number >> + +Specifies how much effort bzip2 should take before resorting to a slower +fallback compression algorithm. + +Valid values range from 0 to 250, where 0 means use the default value 30. + +The default is 0. + +=item C<< Strict => 0|1 >> + +This is a placeholder option. + +=back + +=head2 Examples + +TODO + +=head1 Methods + +=head2 print + +Usage is + + $z->print($data) + print $z $data + +Compresses and outputs the contents of the C<$data> parameter. This +has the same behaviour as the C<print> built-in. + +Returns true if successful. + +=head2 printf + +Usage is + + $z->printf($format, $data) + printf $z $format, $data + +Compresses and outputs the contents of the C<$data> parameter. + +Returns true if successful. + +=head2 syswrite + +Usage is + + $z->syswrite $data + $z->syswrite $data, $length + $z->syswrite $data, $length, $offset + +Compresses and outputs the contents of the C<$data> parameter. + +Returns the number of uncompressed bytes written, or C<undef> if +unsuccessful. + +=head2 write + +Usage is + + $z->write $data + $z->write $data, $length + $z->write $data, $length, $offset + +Compresses and outputs the contents of the C<$data> parameter. + +Returns the number of uncompressed bytes written, or C<undef> if +unsuccessful. + +=head2 flush + +Usage is + + $z->flush; + +Flushes any pending compressed data to the output file/buffer. + +TODO + +Returns true on success. + +=head2 tell + +Usage is + + $z->tell() + tell $z + +Returns the uncompressed file offset. + +=head2 eof + +Usage is + + $z->eof(); + eof($z); + +Returns true if the C<close> method has been called. + +=head2 seek + + $z->seek($position, $whence); + seek($z, $position, $whence); + +Provides a sub-set of the C<seek> functionality, with the restriction +that it is only legal to seek forward in the output file/buffer. +It is a fatal error to attempt to seek backward. + +Empty parts of the file/buffer will have NULL (0x00) bytes written to them. + +The C<$whence> parameter takes one the usual values, namely SEEK_SET, +SEEK_CUR or SEEK_END. + +Returns 1 on success, 0 on failure. + +=head2 binmode + +Usage is + + $z->binmode + binmode $z ; + +This is a noop provided for completeness. + +=head2 opened + + $z->opened() + +Returns true if the object currently refers to a opened file/buffer. + +=head2 autoflush + + my $prev = $z->autoflush() + my $prev = $z->autoflush(EXPR) + +If the C<$z> object is associated with a file or a filehandle, this method +returns the current autoflush setting for the underlying filehandle. If +C<EXPR> is present, and is non-zero, it will enable flushing after every +write/print operation. + +If C<$z> is associated with a buffer, this method has no effect and always +returns C<undef>. + +B<Note> that the special variable C<$|> B<cannot> be used to set or +retrieve the autoflush setting. + +=head2 input_line_number + + $z->input_line_number() + $z->input_line_number(EXPR) + +This method always returns C<undef> when compressing. + +=head2 fileno + + $z->fileno() + fileno($z) + +If the C<$z> object is associated with a file or a filehandle, C<fileno> +will return the underlying file descriptor. Once the C<close> method is +called C<fileno> will return C<undef>. + +If the C<$z> object is is associated with a buffer, this method will return +C<undef>. + +=head2 close + + $z->close() ; + close $z ; + +Flushes any pending compressed data and then closes the output file/buffer. + +For most versions of Perl this method will be automatically invoked if +the IO::Compress::Bzip2 object is destroyed (either explicitly or by the +variable with the reference to the object going out of scope). The +exceptions are Perl versions 5.005 through 5.00504 and 5.8.0. In +these cases, the C<close> method will be called automatically, but +not until global destruction of all live objects when the program is +terminating. + +Therefore, if you want your scripts to be able to run on all versions +of Perl, you should call C<close> explicitly and not rely on automatic +closing. + +Returns true on success, otherwise 0. + +If the C<AutoClose> option has been enabled when the IO::Compress::Bzip2 +object was created, and the object is associated with a file, the +underlying file will also be closed. + +=head2 newStream([OPTS]) + +Usage is + + $z->newStream( [OPTS] ) + +Closes the current compressed data stream and starts a new one. + +OPTS consists of any of the the options that are available when creating +the C<$z> object. + +See the L</"Constructor Options"> section for more details. + +=head1 Importing + +No symbolic constants are required by this IO::Compress::Bzip2 at present. + +=over 5 + +=item :all + +Imports C<bzip2> and C<$Bzip2Error>. +Same as doing this + + use IO::Compress::Bzip2 qw(bzip2 $Bzip2Error) ; + + + +=back + +=head1 EXAMPLES + +=head2 Apache::GZip Revisited + +See L<IO::Compress::Bzip2::FAQ|IO::Compress::Bzip2::FAQ/"Apache::GZip Revisited"> + + + +=head2 Working with Net::FTP + +See L<IO::Compress::Bzip2::FAQ|IO::Compress::Bzip2::FAQ/"Compressed files and Net::FTP"> + +=head1 SEE ALSO + +L<Compress::Zlib>, L<IO::Compress::Gzip>, L<IO::Uncompress::Gunzip>, L<IO::Compress::Deflate>, L<IO::Uncompress::Inflate>, L<IO::Compress::RawDeflate>, L<IO::Uncompress::RawInflate>, L<IO::Uncompress::Bunzip2>, L<IO::Compress::Lzop>, L<IO::Uncompress::UnLzop>, L<IO::Compress::Lzf>, L<IO::Uncompress::UnLzf>, L<IO::Uncompress::AnyInflate>, L<IO::Uncompress::AnyUncompress> + +L<Compress::Zlib::FAQ|Compress::Zlib::FAQ> + +L<File::GlobMapper|File::GlobMapper>, L<Archive::Zip|Archive::Zip>, +L<Archive::Tar|Archive::Tar>, +L<IO::Zlib|IO::Zlib> + +The primary site for the bzip2 program is F<http://www.bzip.org>. + +See the module L<Compress::Bzip2|Compress::Bzip2> + +=head1 AUTHOR + +This module was written by Paul Marquess, F<pmqs@cpan.org>. + +=head1 MODIFICATION HISTORY + +See the Changes file. + +=head1 COPYRIGHT AND LICENSE + +Copyright (c) 2005-2008 Paul Marquess. All rights reserved. + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + diff --git a/Master/tlpkg/tlperl/lib/IO/Compress/Deflate.pm b/Master/tlpkg/tlperl/lib/IO/Compress/Deflate.pm new file mode 100644 index 00000000000..0f46e59d3a4 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Compress/Deflate.pm @@ -0,0 +1,930 @@ +package IO::Compress::Deflate ; + +use strict ; +use warnings; +use bytes; + +require Exporter ; + +use IO::Compress::RawDeflate 2.024 ; + +use Compress::Raw::Zlib 2.024 ; +use IO::Compress::Zlib::Constants 2.024 ; +use IO::Compress::Base::Common 2.024 qw(createSelfTiedObject); + + +our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, $DeflateError); + +$VERSION = '2.024'; +$DeflateError = ''; + +@ISA = qw(Exporter IO::Compress::RawDeflate); +@EXPORT_OK = qw( $DeflateError deflate ) ; +%EXPORT_TAGS = %IO::Compress::RawDeflate::DEFLATE_CONSTANTS ; +push @{ $EXPORT_TAGS{all} }, @EXPORT_OK ; +Exporter::export_ok_tags('all'); + + +sub new +{ + my $class = shift ; + + my $obj = createSelfTiedObject($class, \$DeflateError); + return $obj->_create(undef, @_); +} + +sub deflate +{ + my $obj = createSelfTiedObject(undef, \$DeflateError); + return $obj->_def(@_); +} + + +sub bitmask($$$$) +{ + my $into = shift ; + my $value = shift ; + my $offset = shift ; + my $mask = shift ; + + return $into | (($value & $mask) << $offset ) ; +} + +sub mkDeflateHdr($$$;$) +{ + my $method = shift ; + my $cinfo = shift; + my $level = shift; + my $fdict_adler = shift ; + + my $cmf = 0; + my $flg = 0; + my $fdict = 0; + $fdict = 1 if defined $fdict_adler; + + $cmf = bitmask($cmf, $method, ZLIB_CMF_CM_OFFSET, ZLIB_CMF_CM_BITS); + $cmf = bitmask($cmf, $cinfo, ZLIB_CMF_CINFO_OFFSET, ZLIB_CMF_CINFO_BITS); + + $flg = bitmask($flg, $fdict, ZLIB_FLG_FDICT_OFFSET, ZLIB_FLG_FDICT_BITS); + $flg = bitmask($flg, $level, ZLIB_FLG_LEVEL_OFFSET, ZLIB_FLG_LEVEL_BITS); + + my $fcheck = 31 - ($cmf * 256 + $flg) % 31 ; + $flg = bitmask($flg, $fcheck, ZLIB_FLG_FCHECK_OFFSET, ZLIB_FLG_FCHECK_BITS); + + my $hdr = pack("CC", $cmf, $flg) ; + $hdr .= pack("N", $fdict_adler) if $fdict ; + + return $hdr; +} + +sub mkHeader +{ + my $self = shift ; + my $param = shift ; + + my $level = $param->value('Level'); + my $strategy = $param->value('Strategy'); + + my $lflag ; + $level = 6 + if $level == Z_DEFAULT_COMPRESSION ; + + if (ZLIB_VERNUM >= 0x1210) + { + if ($strategy >= Z_HUFFMAN_ONLY || $level < 2) + { $lflag = ZLIB_FLG_LEVEL_FASTEST } + elsif ($level < 6) + { $lflag = ZLIB_FLG_LEVEL_FAST } + elsif ($level == 6) + { $lflag = ZLIB_FLG_LEVEL_DEFAULT } + else + { $lflag = ZLIB_FLG_LEVEL_SLOWEST } + } + else + { + $lflag = ($level - 1) >> 1 ; + $lflag = 3 if $lflag > 3 ; + } + + #my $wbits = (MAX_WBITS - 8) << 4 ; + my $wbits = 7; + mkDeflateHdr(ZLIB_CMF_CM_DEFLATED, $wbits, $lflag); +} + +sub ckParams +{ + my $self = shift ; + my $got = shift; + + $got->value('ADLER32' => 1); + return 1 ; +} + + +sub mkTrailer +{ + my $self = shift ; + return pack("N", *$self->{Compress}->adler32()) ; +} + +sub mkFinalTrailer +{ + return ''; +} + +#sub newHeader +#{ +# my $self = shift ; +# return *$self->{Header}; +#} + +sub getExtraParams +{ + my $self = shift ; + return $self->getZlibParams(), +} + +sub getInverseClass +{ + return ('IO::Uncompress::Inflate', + \$IO::Uncompress::Inflate::InflateError); +} + +sub getFileInfo +{ + my $self = shift ; + my $params = shift; + my $file = shift ; + +} + + + +1; + +__END__ + +=head1 NAME + +IO::Compress::Deflate - Write RFC 1950 files/buffers + + + +=head1 SYNOPSIS + + use IO::Compress::Deflate qw(deflate $DeflateError) ; + + my $status = deflate $input => $output [,OPTS] + or die "deflate failed: $DeflateError\n"; + + my $z = new IO::Compress::Deflate $output [,OPTS] + or die "deflate failed: $DeflateError\n"; + + $z->print($string); + $z->printf($format, $string); + $z->write($string); + $z->syswrite($string [, $length, $offset]); + $z->flush(); + $z->tell(); + $z->eof(); + $z->seek($position, $whence); + $z->binmode(); + $z->fileno(); + $z->opened(); + $z->autoflush(); + $z->input_line_number(); + $z->newStream( [OPTS] ); + + $z->deflateParams(); + + $z->close() ; + + $DeflateError ; + + # IO::File mode + + print $z $string; + printf $z $format, $string; + tell $z + eof $z + seek $z, $position, $whence + binmode $z + fileno $z + close $z ; + + +=head1 DESCRIPTION + +This module provides a Perl interface that allows writing compressed +data to files or buffer as defined in RFC 1950. + +For reading RFC 1950 files/buffers, see the companion module +L<IO::Uncompress::Inflate|IO::Uncompress::Inflate>. + +=head1 Functional Interface + +A top-level function, C<deflate>, is provided to carry out +"one-shot" compression between buffers and/or files. For finer +control over the compression process, see the L</"OO Interface"> +section. + + use IO::Compress::Deflate qw(deflate $DeflateError) ; + + deflate $input => $output [,OPTS] + or die "deflate failed: $DeflateError\n"; + +The functional interface needs Perl5.005 or better. + +=head2 deflate $input => $output [, OPTS] + +C<deflate> expects at least two parameters, C<$input> and C<$output>. + +=head3 The C<$input> parameter + +The parameter, C<$input>, is used to define the source of +the uncompressed data. + +It can take one of the following forms: + +=over 5 + +=item A filename + +If the C<$input> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for reading and the input data +will be read from it. + +=item A filehandle + +If the C<$input> parameter is a filehandle, the input data will be +read from it. +The string '-' can be used as an alias for standard input. + +=item A scalar reference + +If C<$input> is a scalar reference, the input data will be read +from C<$$input>. + +=item An array reference + +If C<$input> is an array reference, each element in the array must be a +filename. + +The input data will be read from each file in turn. + +The complete array will be walked to ensure that it only +contains valid filenames before any data is compressed. + +=item An Input FileGlob string + +If C<$input> is a string that is delimited by the characters "<" and ">" +C<deflate> will assume that it is an I<input fileglob string>. The +input is the list of files that match the fileglob. + +If the fileglob does not match any files ... + +See L<File::GlobMapper|File::GlobMapper> for more details. + +=back + +If the C<$input> parameter is any other type, C<undef> will be returned. + +=head3 The C<$output> parameter + +The parameter C<$output> is used to control the destination of the +compressed data. This parameter can take one of these forms. + +=over 5 + +=item A filename + +If the C<$output> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for writing and the compressed +data will be written to it. + +=item A filehandle + +If the C<$output> parameter is a filehandle, the compressed data +will be written to it. +The string '-' can be used as an alias for standard output. + +=item A scalar reference + +If C<$output> is a scalar reference, the compressed data will be +stored in C<$$output>. + +=item An Array Reference + +If C<$output> is an array reference, the compressed data will be +pushed onto the array. + +=item An Output FileGlob + +If C<$output> is a string that is delimited by the characters "<" and ">" +C<deflate> will assume that it is an I<output fileglob string>. The +output is the list of files that match the fileglob. + +When C<$output> is an fileglob string, C<$input> must also be a fileglob +string. Anything else is an error. + +=back + +If the C<$output> parameter is any other type, C<undef> will be returned. + +=head2 Notes + +When C<$input> maps to multiple files/buffers and C<$output> is a single +file/buffer the input files/buffers will be stored +in C<$output> as a concatenated series of compressed data streams. + +=head2 Optional Parameters + +Unless specified below, the optional parameters for C<deflate>, +C<OPTS>, are the same as those used with the OO interface defined in the +L</"Constructor Options"> section below. + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option applies to any input or output data streams to +C<deflate> that are filehandles. + +If C<AutoClose> is specified, and the value is true, it will result in all +input and/or output filehandles being closed once C<deflate> has +completed. + +This parameter defaults to 0. + +=item C<< BinModeIn => 0|1 >> + +When reading from a file or filehandle, set C<binmode> before reading. + +Defaults to 0. + +=item C<< Append => 0|1 >> + +The behaviour of this option is dependent on the type of output data +stream. + +=over 5 + +=item * A Buffer + +If C<Append> is enabled, all compressed data will be append to the end of +the output buffer. Otherwise the output buffer will be cleared before any +compressed data is written to it. + +=item * A Filename + +If C<Append> is enabled, the file will be opened in append mode. Otherwise +the contents of the file, if any, will be truncated before any compressed +data is written to it. + +=item * A Filehandle + +If C<Append> is enabled, the filehandle will be positioned to the end of +the file via a call to C<seek> before any compressed data is +written to it. Otherwise the file pointer will not be moved. + +=back + +When C<Append> is specified, and set to true, it will I<append> all compressed +data to the output data stream. + +So when the output is a filehandle it will carry out a seek to the eof +before writing any compressed data. If the output is a filename, it will be opened for +appending. If the output is a buffer, all compressed data will be appened to +the existing buffer. + +Conversely when C<Append> is not specified, or it is present and is set to +false, it will operate as follows. + +When the output is a filename, it will truncate the contents of the file +before writing any compressed data. If the output is a filehandle +its position will not be changed. If the output is a buffer, it will be +wiped before any compressed data is output. + +Defaults to 0. + +=back + +=head2 Examples + +To read the contents of the file C<file1.txt> and write the compressed +data to the file C<file1.txt.1950>. + + use strict ; + use warnings ; + use IO::Compress::Deflate qw(deflate $DeflateError) ; + + my $input = "file1.txt"; + deflate $input => "$input.1950" + or die "deflate failed: $DeflateError\n"; + +To read from an existing Perl filehandle, C<$input>, and write the +compressed data to a buffer, C<$buffer>. + + use strict ; + use warnings ; + use IO::Compress::Deflate qw(deflate $DeflateError) ; + use IO::File ; + + my $input = new IO::File "<file1.txt" + or die "Cannot open 'file1.txt': $!\n" ; + my $buffer ; + deflate $input => \$buffer + or die "deflate failed: $DeflateError\n"; + +To compress all files in the directory "/my/home" that match "*.txt" +and store the compressed data in the same directory + + use strict ; + use warnings ; + use IO::Compress::Deflate qw(deflate $DeflateError) ; + + deflate '</my/home/*.txt>' => '<*.1950>' + or die "deflate failed: $DeflateError\n"; + +and if you want to compress each file one at a time, this will do the trick + + use strict ; + use warnings ; + use IO::Compress::Deflate qw(deflate $DeflateError) ; + + for my $input ( glob "/my/home/*.txt" ) + { + my $output = "$input.1950" ; + deflate $input => $output + or die "Error compressing '$input': $DeflateError\n"; + } + +=head1 OO Interface + +=head2 Constructor + +The format of the constructor for C<IO::Compress::Deflate> is shown below + + my $z = new IO::Compress::Deflate $output [,OPTS] + or die "IO::Compress::Deflate failed: $DeflateError\n"; + +It returns an C<IO::Compress::Deflate> object on success and undef on failure. +The variable C<$DeflateError> will contain an error message on failure. + +If you are running Perl 5.005 or better the object, C<$z>, returned from +IO::Compress::Deflate can be used exactly like an L<IO::File|IO::File> filehandle. +This means that all normal output file operations can be carried out +with C<$z>. +For example, to write to a compressed file/buffer you can use either of +these forms + + $z->print("hello world\n"); + print $z "hello world\n"; + +The mandatory parameter C<$output> is used to control the destination +of the compressed data. This parameter can take one of these forms. + +=over 5 + +=item A filename + +If the C<$output> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for writing and the compressed data +will be written to it. + +=item A filehandle + +If the C<$output> parameter is a filehandle, the compressed data will be +written to it. +The string '-' can be used as an alias for standard output. + +=item A scalar reference + +If C<$output> is a scalar reference, the compressed data will be stored +in C<$$output>. + +=back + +If the C<$output> parameter is any other type, C<IO::Compress::Deflate>::new will +return undef. + +=head2 Constructor Options + +C<OPTS> is any combination of the following options: + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option is only valid when the C<$output> parameter is a filehandle. If +specified, and the value is true, it will result in the C<$output> being +closed once either the C<close> method is called or the C<IO::Compress::Deflate> +object is destroyed. + +This parameter defaults to 0. + +=item C<< Append => 0|1 >> + +Opens C<$output> in append mode. + +The behaviour of this option is dependent on the type of C<$output>. + +=over 5 + +=item * A Buffer + +If C<$output> is a buffer and C<Append> is enabled, all compressed data +will be append to the end of C<$output>. Otherwise C<$output> will be +cleared before any data is written to it. + +=item * A Filename + +If C<$output> is a filename and C<Append> is enabled, the file will be +opened in append mode. Otherwise the contents of the file, if any, will be +truncated before any compressed data is written to it. + +=item * A Filehandle + +If C<$output> is a filehandle, the file pointer will be positioned to the +end of the file via a call to C<seek> before any compressed data is written +to it. Otherwise the file pointer will not be moved. + +=back + +This parameter defaults to 0. + +=item C<< Merge => 0|1 >> + +This option is used to compress input data and append it to an existing +compressed data stream in C<$output>. The end result is a single compressed +data stream stored in C<$output>. + +It is a fatal error to attempt to use this option when C<$output> is not an +RFC 1950 data stream. + +There are a number of other limitations with the C<Merge> option: + +=over 5 + +=item 1 + +This module needs to have been built with zlib 1.2.1 or better to work. A +fatal error will be thrown if C<Merge> is used with an older version of +zlib. + +=item 2 + +If C<$output> is a file or a filehandle, it must be seekable. + +=back + +This parameter defaults to 0. + +=item -Level + +Defines the compression level used by zlib. The value should either be +a number between 0 and 9 (0 means no compression and 9 is maximum +compression), or one of the symbolic constants defined below. + + Z_NO_COMPRESSION + Z_BEST_SPEED + Z_BEST_COMPRESSION + Z_DEFAULT_COMPRESSION + +The default is Z_DEFAULT_COMPRESSION. + +Note, these constants are not imported by C<IO::Compress::Deflate> by default. + + use IO::Compress::Deflate qw(:strategy); + use IO::Compress::Deflate qw(:constants); + use IO::Compress::Deflate qw(:all); + +=item -Strategy + +Defines the strategy used to tune the compression. Use one of the symbolic +constants defined below. + + Z_FILTERED + Z_HUFFMAN_ONLY + Z_RLE + Z_FIXED + Z_DEFAULT_STRATEGY + +The default is Z_DEFAULT_STRATEGY. + +=item C<< Strict => 0|1 >> + +This is a placeholder option. + +=back + +=head2 Examples + +TODO + +=head1 Methods + +=head2 print + +Usage is + + $z->print($data) + print $z $data + +Compresses and outputs the contents of the C<$data> parameter. This +has the same behaviour as the C<print> built-in. + +Returns true if successful. + +=head2 printf + +Usage is + + $z->printf($format, $data) + printf $z $format, $data + +Compresses and outputs the contents of the C<$data> parameter. + +Returns true if successful. + +=head2 syswrite + +Usage is + + $z->syswrite $data + $z->syswrite $data, $length + $z->syswrite $data, $length, $offset + +Compresses and outputs the contents of the C<$data> parameter. + +Returns the number of uncompressed bytes written, or C<undef> if +unsuccessful. + +=head2 write + +Usage is + + $z->write $data + $z->write $data, $length + $z->write $data, $length, $offset + +Compresses and outputs the contents of the C<$data> parameter. + +Returns the number of uncompressed bytes written, or C<undef> if +unsuccessful. + +=head2 flush + +Usage is + + $z->flush; + $z->flush($flush_type); + +Flushes any pending compressed data to the output file/buffer. + +This method takes an optional parameter, C<$flush_type>, that controls +how the flushing will be carried out. By default the C<$flush_type> +used is C<Z_FINISH>. Other valid values for C<$flush_type> are +C<Z_NO_FLUSH>, C<Z_SYNC_FLUSH>, C<Z_FULL_FLUSH> and C<Z_BLOCK>. It is +strongly recommended that you only set the C<flush_type> parameter if +you fully understand the implications of what it does - overuse of C<flush> +can seriously degrade the level of compression achieved. See the C<zlib> +documentation for details. + +Returns true on success. + +=head2 tell + +Usage is + + $z->tell() + tell $z + +Returns the uncompressed file offset. + +=head2 eof + +Usage is + + $z->eof(); + eof($z); + +Returns true if the C<close> method has been called. + +=head2 seek + + $z->seek($position, $whence); + seek($z, $position, $whence); + +Provides a sub-set of the C<seek> functionality, with the restriction +that it is only legal to seek forward in the output file/buffer. +It is a fatal error to attempt to seek backward. + +Empty parts of the file/buffer will have NULL (0x00) bytes written to them. + +The C<$whence> parameter takes one the usual values, namely SEEK_SET, +SEEK_CUR or SEEK_END. + +Returns 1 on success, 0 on failure. + +=head2 binmode + +Usage is + + $z->binmode + binmode $z ; + +This is a noop provided for completeness. + +=head2 opened + + $z->opened() + +Returns true if the object currently refers to a opened file/buffer. + +=head2 autoflush + + my $prev = $z->autoflush() + my $prev = $z->autoflush(EXPR) + +If the C<$z> object is associated with a file or a filehandle, this method +returns the current autoflush setting for the underlying filehandle. If +C<EXPR> is present, and is non-zero, it will enable flushing after every +write/print operation. + +If C<$z> is associated with a buffer, this method has no effect and always +returns C<undef>. + +B<Note> that the special variable C<$|> B<cannot> be used to set or +retrieve the autoflush setting. + +=head2 input_line_number + + $z->input_line_number() + $z->input_line_number(EXPR) + +This method always returns C<undef> when compressing. + +=head2 fileno + + $z->fileno() + fileno($z) + +If the C<$z> object is associated with a file or a filehandle, C<fileno> +will return the underlying file descriptor. Once the C<close> method is +called C<fileno> will return C<undef>. + +If the C<$z> object is is associated with a buffer, this method will return +C<undef>. + +=head2 close + + $z->close() ; + close $z ; + +Flushes any pending compressed data and then closes the output file/buffer. + +For most versions of Perl this method will be automatically invoked if +the IO::Compress::Deflate object is destroyed (either explicitly or by the +variable with the reference to the object going out of scope). The +exceptions are Perl versions 5.005 through 5.00504 and 5.8.0. In +these cases, the C<close> method will be called automatically, but +not until global destruction of all live objects when the program is +terminating. + +Therefore, if you want your scripts to be able to run on all versions +of Perl, you should call C<close> explicitly and not rely on automatic +closing. + +Returns true on success, otherwise 0. + +If the C<AutoClose> option has been enabled when the IO::Compress::Deflate +object was created, and the object is associated with a file, the +underlying file will also be closed. + +=head2 newStream([OPTS]) + +Usage is + + $z->newStream( [OPTS] ) + +Closes the current compressed data stream and starts a new one. + +OPTS consists of any of the the options that are available when creating +the C<$z> object. + +See the L</"Constructor Options"> section for more details. + +=head2 deflateParams + +Usage is + + $z->deflateParams + +TODO + +=head1 Importing + +A number of symbolic constants are required by some methods in +C<IO::Compress::Deflate>. None are imported by default. + +=over 5 + +=item :all + +Imports C<deflate>, C<$DeflateError> and all symbolic +constants that can be used by C<IO::Compress::Deflate>. Same as doing this + + use IO::Compress::Deflate qw(deflate $DeflateError :constants) ; + +=item :constants + +Import all symbolic constants. Same as doing this + + use IO::Compress::Deflate qw(:flush :level :strategy) ; + +=item :flush + +These symbolic constants are used by the C<flush> method. + + Z_NO_FLUSH + Z_PARTIAL_FLUSH + Z_SYNC_FLUSH + Z_FULL_FLUSH + Z_FINISH + Z_BLOCK + +=item :level + +These symbolic constants are used by the C<Level> option in the constructor. + + Z_NO_COMPRESSION + Z_BEST_SPEED + Z_BEST_COMPRESSION + Z_DEFAULT_COMPRESSION + +=item :strategy + +These symbolic constants are used by the C<Strategy> option in the constructor. + + Z_FILTERED + Z_HUFFMAN_ONLY + Z_RLE + Z_FIXED + Z_DEFAULT_STRATEGY + + + + +=back + +=head1 EXAMPLES + +=head2 Apache::GZip Revisited + +See L<IO::Compress::FAQ|IO::Compress::FAQ/"Apache::GZip Revisited"> + + + +=head2 Working with Net::FTP + +See L<IO::Compress::FAQ|IO::Compress::FAQ/"Compressed files and Net::FTP"> + +=head1 SEE ALSO + +L<Compress::Zlib>, L<IO::Compress::Gzip>, L<IO::Uncompress::Gunzip>, L<IO::Uncompress::Inflate>, L<IO::Compress::RawDeflate>, L<IO::Uncompress::RawInflate>, L<IO::Compress::Bzip2>, L<IO::Uncompress::Bunzip2>, L<IO::Compress::Lzma>, L<IO::Uncompress::UnLzma>, L<IO::Compress::Xz>, L<IO::Uncompress::UnXz>, L<IO::Compress::Lzop>, L<IO::Uncompress::UnLzop>, L<IO::Compress::Lzf>, L<IO::Uncompress::UnLzf>, L<IO::Uncompress::AnyInflate>, L<IO::Uncompress::AnyUncompress> + +L<Compress::Zlib::FAQ|Compress::Zlib::FAQ> + +L<File::GlobMapper|File::GlobMapper>, L<Archive::Zip|Archive::Zip>, +L<Archive::Tar|Archive::Tar>, +L<IO::Zlib|IO::Zlib> + +For RFC 1950, 1951 and 1952 see +F<http://www.faqs.org/rfcs/rfc1950.html>, +F<http://www.faqs.org/rfcs/rfc1951.html> and +F<http://www.faqs.org/rfcs/rfc1952.html> + +The I<zlib> compression library was written by Jean-loup Gailly +F<gzip@prep.ai.mit.edu> and Mark Adler F<madler@alumni.caltech.edu>. + +The primary site for the I<zlib> compression library is +F<http://www.zlib.org>. + +The primary site for gzip is F<http://www.gzip.org>. + +=head1 AUTHOR + +This module was written by Paul Marquess, F<pmqs@cpan.org>. + +=head1 MODIFICATION HISTORY + +See the Changes file. + +=head1 COPYRIGHT AND LICENSE + +Copyright (c) 2005-2010 Paul Marquess. All rights reserved. + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + diff --git a/Master/tlpkg/tlperl/lib/IO/Compress/Gzip.pm b/Master/tlpkg/tlperl/lib/IO/Compress/Gzip.pm new file mode 100644 index 00000000000..1978b91b283 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Compress/Gzip.pm @@ -0,0 +1,1242 @@ + +package IO::Compress::Gzip ; + +require 5.004 ; + +use strict ; +use warnings; +use bytes; + + +use IO::Compress::RawDeflate 2.024 ; + +use Compress::Raw::Zlib 2.024 ; +use IO::Compress::Base::Common 2.024 qw(:Status :Parse createSelfTiedObject); +use IO::Compress::Gzip::Constants 2.024 ; +use IO::Compress::Zlib::Extra 2.024 ; + +BEGIN +{ + if (defined &utf8::downgrade ) + { *noUTF8 = \&utf8::downgrade } + else + { *noUTF8 = sub {} } +} + +require Exporter ; + +our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, $GzipError); + +$VERSION = '2.024'; +$GzipError = '' ; + +@ISA = qw(Exporter IO::Compress::RawDeflate); +@EXPORT_OK = qw( $GzipError gzip ) ; +%EXPORT_TAGS = %IO::Compress::RawDeflate::DEFLATE_CONSTANTS ; +push @{ $EXPORT_TAGS{all} }, @EXPORT_OK ; +Exporter::export_ok_tags('all'); + +sub new +{ + my $class = shift ; + + my $obj = createSelfTiedObject($class, \$GzipError); + + $obj->_create(undef, @_); +} + + +sub gzip +{ + my $obj = createSelfTiedObject(undef, \$GzipError); + return $obj->_def(@_); +} + +#sub newHeader +#{ +# my $self = shift ; +# #return GZIP_MINIMUM_HEADER ; +# return $self->mkHeader(*$self->{Got}); +#} + +sub getExtraParams +{ + my $self = shift ; + + return ( + # zlib behaviour + $self->getZlibParams(), + + # Gzip header fields + 'Minimal' => [0, 1, Parse_boolean, 0], + 'Comment' => [0, 1, Parse_any, undef], + 'Name' => [0, 1, Parse_any, undef], + 'Time' => [0, 1, Parse_any, undef], + 'TextFlag' => [0, 1, Parse_boolean, 0], + 'HeaderCRC' => [0, 1, Parse_boolean, 0], + 'OS_Code' => [0, 1, Parse_unsigned, $Compress::Raw::Zlib::gzip_os_code], + 'ExtraField'=> [0, 1, Parse_any, undef], + 'ExtraFlags'=> [0, 1, Parse_any, undef], + + ); +} + + +sub ckParams +{ + my $self = shift ; + my $got = shift ; + + # gzip always needs crc32 + $got->value('CRC32' => 1); + + return 1 + if $got->value('Merge') ; + + my $strict = $got->value('Strict') ; + + + { + if (! $got->parsed('Time') ) { + # Modification time defaults to now. + $got->value('Time' => time) ; + } + + # Check that the Name & Comment don't have embedded NULLs + # Also check that they only contain ISO 8859-1 chars. + if ($got->parsed('Name') && defined $got->value('Name')) { + my $name = $got->value('Name'); + + return $self->saveErrorString(undef, "Null Character found in Name", + Z_DATA_ERROR) + if $strict && $name =~ /\x00/ ; + + return $self->saveErrorString(undef, "Non ISO 8859-1 Character found in Name", + Z_DATA_ERROR) + if $strict && $name =~ /$GZIP_FNAME_INVALID_CHAR_RE/o ; + } + + if ($got->parsed('Comment') && defined $got->value('Comment')) { + my $comment = $got->value('Comment'); + + return $self->saveErrorString(undef, "Null Character found in Comment", + Z_DATA_ERROR) + if $strict && $comment =~ /\x00/ ; + + return $self->saveErrorString(undef, "Non ISO 8859-1 Character found in Comment", + Z_DATA_ERROR) + if $strict && $comment =~ /$GZIP_FCOMMENT_INVALID_CHAR_RE/o; + } + + if ($got->parsed('OS_Code') ) { + my $value = $got->value('OS_Code'); + + return $self->saveErrorString(undef, "OS_Code must be between 0 and 255, got '$value'") + if $value < 0 || $value > 255 ; + + } + + # gzip only supports Deflate at present + $got->value('Method' => Z_DEFLATED) ; + + if ( ! $got->parsed('ExtraFlags')) { + $got->value('ExtraFlags' => 2) + if $got->value('Level') == Z_BEST_SPEED ; + $got->value('ExtraFlags' => 4) + if $got->value('Level') == Z_BEST_COMPRESSION ; + } + + my $data = $got->value('ExtraField') ; + if (defined $data) { + my $bad = IO::Compress::Zlib::Extra::parseExtraField($data, $strict, 1) ; + return $self->saveErrorString(undef, "Error with ExtraField Parameter: $bad", Z_DATA_ERROR) + if $bad ; + + $got->value('ExtraField', $data) ; + } + } + + return 1; +} + +sub mkTrailer +{ + my $self = shift ; + return pack("V V", *$self->{Compress}->crc32(), + *$self->{UnCompSize}->get32bit()); +} + +sub getInverseClass +{ + return ('IO::Uncompress::Gunzip', + \$IO::Uncompress::Gunzip::GunzipError); +} + +sub getFileInfo +{ + my $self = shift ; + my $params = shift; + my $filename = shift ; + + my $defaultTime = (stat($filename))[9] ; + + $params->value('Name' => $filename) + if ! $params->parsed('Name') ; + + $params->value('Time' => $defaultTime) + if ! $params->parsed('Time') ; +} + + +sub mkHeader +{ + my $self = shift ; + my $param = shift ; + + # stort-circuit if a minimal header is requested. + return GZIP_MINIMUM_HEADER if $param->value('Minimal') ; + + # METHOD + my $method = $param->valueOrDefault('Method', GZIP_CM_DEFLATED) ; + + # FLAGS + my $flags = GZIP_FLG_DEFAULT ; + $flags |= GZIP_FLG_FTEXT if $param->value('TextFlag') ; + $flags |= GZIP_FLG_FHCRC if $param->value('HeaderCRC') ; + $flags |= GZIP_FLG_FEXTRA if $param->wantValue('ExtraField') ; + $flags |= GZIP_FLG_FNAME if $param->wantValue('Name') ; + $flags |= GZIP_FLG_FCOMMENT if $param->wantValue('Comment') ; + + # MTIME + my $time = $param->valueOrDefault('Time', GZIP_MTIME_DEFAULT) ; + + # EXTRA FLAGS + my $extra_flags = $param->valueOrDefault('ExtraFlags', GZIP_XFL_DEFAULT); + + # OS CODE + my $os_code = $param->valueOrDefault('OS_Code', GZIP_OS_DEFAULT) ; + + + my $out = pack("C4 V C C", + GZIP_ID1, # ID1 + GZIP_ID2, # ID2 + $method, # Compression Method + $flags, # Flags + $time, # Modification Time + $extra_flags, # Extra Flags + $os_code, # Operating System Code + ) ; + + # EXTRA + if ($flags & GZIP_FLG_FEXTRA) { + my $extra = $param->value('ExtraField') ; + $out .= pack("v", length $extra) . $extra ; + } + + # NAME + if ($flags & GZIP_FLG_FNAME) { + my $name .= $param->value('Name') ; + $name =~ s/\x00.*$//; + $out .= $name ; + # Terminate the filename with NULL unless it already is + $out .= GZIP_NULL_BYTE + if !length $name or + substr($name, 1, -1) ne GZIP_NULL_BYTE ; + } + + # COMMENT + if ($flags & GZIP_FLG_FCOMMENT) { + my $comment .= $param->value('Comment') ; + $comment =~ s/\x00.*$//; + $out .= $comment ; + # Terminate the comment with NULL unless it already is + $out .= GZIP_NULL_BYTE + if ! length $comment or + substr($comment, 1, -1) ne GZIP_NULL_BYTE; + } + + # HEADER CRC + $out .= pack("v", crc32($out) & 0x00FF ) if $param->value('HeaderCRC') ; + + noUTF8($out); + + return $out ; +} + +sub mkFinalTrailer +{ + return ''; +} + +1; + +__END__ + +=head1 NAME + +IO::Compress::Gzip - Write RFC 1952 files/buffers + + + +=head1 SYNOPSIS + + use IO::Compress::Gzip qw(gzip $GzipError) ; + + my $status = gzip $input => $output [,OPTS] + or die "gzip failed: $GzipError\n"; + + my $z = new IO::Compress::Gzip $output [,OPTS] + or die "gzip failed: $GzipError\n"; + + $z->print($string); + $z->printf($format, $string); + $z->write($string); + $z->syswrite($string [, $length, $offset]); + $z->flush(); + $z->tell(); + $z->eof(); + $z->seek($position, $whence); + $z->binmode(); + $z->fileno(); + $z->opened(); + $z->autoflush(); + $z->input_line_number(); + $z->newStream( [OPTS] ); + + $z->deflateParams(); + + $z->close() ; + + $GzipError ; + + # IO::File mode + + print $z $string; + printf $z $format, $string; + tell $z + eof $z + seek $z, $position, $whence + binmode $z + fileno $z + close $z ; + + +=head1 DESCRIPTION + +This module provides a Perl interface that allows writing compressed +data to files or buffer as defined in RFC 1952. + +All the gzip headers defined in RFC 1952 can be created using +this module. + +For reading RFC 1952 files/buffers, see the companion module +L<IO::Uncompress::Gunzip|IO::Uncompress::Gunzip>. + +=head1 Functional Interface + +A top-level function, C<gzip>, is provided to carry out +"one-shot" compression between buffers and/or files. For finer +control over the compression process, see the L</"OO Interface"> +section. + + use IO::Compress::Gzip qw(gzip $GzipError) ; + + gzip $input => $output [,OPTS] + or die "gzip failed: $GzipError\n"; + +The functional interface needs Perl5.005 or better. + +=head2 gzip $input => $output [, OPTS] + +C<gzip> expects at least two parameters, C<$input> and C<$output>. + +=head3 The C<$input> parameter + +The parameter, C<$input>, is used to define the source of +the uncompressed data. + +It can take one of the following forms: + +=over 5 + +=item A filename + +If the C<$input> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for reading and the input data +will be read from it. + +=item A filehandle + +If the C<$input> parameter is a filehandle, the input data will be +read from it. +The string '-' can be used as an alias for standard input. + +=item A scalar reference + +If C<$input> is a scalar reference, the input data will be read +from C<$$input>. + +=item An array reference + +If C<$input> is an array reference, each element in the array must be a +filename. + +The input data will be read from each file in turn. + +The complete array will be walked to ensure that it only +contains valid filenames before any data is compressed. + +=item An Input FileGlob string + +If C<$input> is a string that is delimited by the characters "<" and ">" +C<gzip> will assume that it is an I<input fileglob string>. The +input is the list of files that match the fileglob. + +If the fileglob does not match any files ... + +See L<File::GlobMapper|File::GlobMapper> for more details. + +=back + +If the C<$input> parameter is any other type, C<undef> will be returned. + +In addition, if C<$input> is a simple filename, the default values for +the C<Name> and C<Time> options will be sourced from that file. + +If you do not want to use these defaults they can be overridden by +explicitly setting the C<Name> and C<Time> options or by setting the +C<Minimal> parameter. + +=head3 The C<$output> parameter + +The parameter C<$output> is used to control the destination of the +compressed data. This parameter can take one of these forms. + +=over 5 + +=item A filename + +If the C<$output> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for writing and the compressed +data will be written to it. + +=item A filehandle + +If the C<$output> parameter is a filehandle, the compressed data +will be written to it. +The string '-' can be used as an alias for standard output. + +=item A scalar reference + +If C<$output> is a scalar reference, the compressed data will be +stored in C<$$output>. + +=item An Array Reference + +If C<$output> is an array reference, the compressed data will be +pushed onto the array. + +=item An Output FileGlob + +If C<$output> is a string that is delimited by the characters "<" and ">" +C<gzip> will assume that it is an I<output fileglob string>. The +output is the list of files that match the fileglob. + +When C<$output> is an fileglob string, C<$input> must also be a fileglob +string. Anything else is an error. + +=back + +If the C<$output> parameter is any other type, C<undef> will be returned. + +=head2 Notes + +When C<$input> maps to multiple files/buffers and C<$output> is a single +file/buffer the input files/buffers will be stored +in C<$output> as a concatenated series of compressed data streams. + +=head2 Optional Parameters + +Unless specified below, the optional parameters for C<gzip>, +C<OPTS>, are the same as those used with the OO interface defined in the +L</"Constructor Options"> section below. + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option applies to any input or output data streams to +C<gzip> that are filehandles. + +If C<AutoClose> is specified, and the value is true, it will result in all +input and/or output filehandles being closed once C<gzip> has +completed. + +This parameter defaults to 0. + +=item C<< BinModeIn => 0|1 >> + +When reading from a file or filehandle, set C<binmode> before reading. + +Defaults to 0. + +=item C<< Append => 0|1 >> + +The behaviour of this option is dependent on the type of output data +stream. + +=over 5 + +=item * A Buffer + +If C<Append> is enabled, all compressed data will be append to the end of +the output buffer. Otherwise the output buffer will be cleared before any +compressed data is written to it. + +=item * A Filename + +If C<Append> is enabled, the file will be opened in append mode. Otherwise +the contents of the file, if any, will be truncated before any compressed +data is written to it. + +=item * A Filehandle + +If C<Append> is enabled, the filehandle will be positioned to the end of +the file via a call to C<seek> before any compressed data is +written to it. Otherwise the file pointer will not be moved. + +=back + +When C<Append> is specified, and set to true, it will I<append> all compressed +data to the output data stream. + +So when the output is a filehandle it will carry out a seek to the eof +before writing any compressed data. If the output is a filename, it will be opened for +appending. If the output is a buffer, all compressed data will be appened to +the existing buffer. + +Conversely when C<Append> is not specified, or it is present and is set to +false, it will operate as follows. + +When the output is a filename, it will truncate the contents of the file +before writing any compressed data. If the output is a filehandle +its position will not be changed. If the output is a buffer, it will be +wiped before any compressed data is output. + +Defaults to 0. + +=back + +=head2 Examples + +To read the contents of the file C<file1.txt> and write the compressed +data to the file C<file1.txt.gz>. + + use strict ; + use warnings ; + use IO::Compress::Gzip qw(gzip $GzipError) ; + + my $input = "file1.txt"; + gzip $input => "$input.gz" + or die "gzip failed: $GzipError\n"; + +To read from an existing Perl filehandle, C<$input>, and write the +compressed data to a buffer, C<$buffer>. + + use strict ; + use warnings ; + use IO::Compress::Gzip qw(gzip $GzipError) ; + use IO::File ; + + my $input = new IO::File "<file1.txt" + or die "Cannot open 'file1.txt': $!\n" ; + my $buffer ; + gzip $input => \$buffer + or die "gzip failed: $GzipError\n"; + +To compress all files in the directory "/my/home" that match "*.txt" +and store the compressed data in the same directory + + use strict ; + use warnings ; + use IO::Compress::Gzip qw(gzip $GzipError) ; + + gzip '</my/home/*.txt>' => '<*.gz>' + or die "gzip failed: $GzipError\n"; + +and if you want to compress each file one at a time, this will do the trick + + use strict ; + use warnings ; + use IO::Compress::Gzip qw(gzip $GzipError) ; + + for my $input ( glob "/my/home/*.txt" ) + { + my $output = "$input.gz" ; + gzip $input => $output + or die "Error compressing '$input': $GzipError\n"; + } + +=head1 OO Interface + +=head2 Constructor + +The format of the constructor for C<IO::Compress::Gzip> is shown below + + my $z = new IO::Compress::Gzip $output [,OPTS] + or die "IO::Compress::Gzip failed: $GzipError\n"; + +It returns an C<IO::Compress::Gzip> object on success and undef on failure. +The variable C<$GzipError> will contain an error message on failure. + +If you are running Perl 5.005 or better the object, C<$z>, returned from +IO::Compress::Gzip can be used exactly like an L<IO::File|IO::File> filehandle. +This means that all normal output file operations can be carried out +with C<$z>. +For example, to write to a compressed file/buffer you can use either of +these forms + + $z->print("hello world\n"); + print $z "hello world\n"; + +The mandatory parameter C<$output> is used to control the destination +of the compressed data. This parameter can take one of these forms. + +=over 5 + +=item A filename + +If the C<$output> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for writing and the compressed data +will be written to it. + +=item A filehandle + +If the C<$output> parameter is a filehandle, the compressed data will be +written to it. +The string '-' can be used as an alias for standard output. + +=item A scalar reference + +If C<$output> is a scalar reference, the compressed data will be stored +in C<$$output>. + +=back + +If the C<$output> parameter is any other type, C<IO::Compress::Gzip>::new will +return undef. + +=head2 Constructor Options + +C<OPTS> is any combination of the following options: + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option is only valid when the C<$output> parameter is a filehandle. If +specified, and the value is true, it will result in the C<$output> being +closed once either the C<close> method is called or the C<IO::Compress::Gzip> +object is destroyed. + +This parameter defaults to 0. + +=item C<< Append => 0|1 >> + +Opens C<$output> in append mode. + +The behaviour of this option is dependent on the type of C<$output>. + +=over 5 + +=item * A Buffer + +If C<$output> is a buffer and C<Append> is enabled, all compressed data +will be append to the end of C<$output>. Otherwise C<$output> will be +cleared before any data is written to it. + +=item * A Filename + +If C<$output> is a filename and C<Append> is enabled, the file will be +opened in append mode. Otherwise the contents of the file, if any, will be +truncated before any compressed data is written to it. + +=item * A Filehandle + +If C<$output> is a filehandle, the file pointer will be positioned to the +end of the file via a call to C<seek> before any compressed data is written +to it. Otherwise the file pointer will not be moved. + +=back + +This parameter defaults to 0. + +=item C<< Merge => 0|1 >> + +This option is used to compress input data and append it to an existing +compressed data stream in C<$output>. The end result is a single compressed +data stream stored in C<$output>. + +It is a fatal error to attempt to use this option when C<$output> is not an +RFC 1952 data stream. + +There are a number of other limitations with the C<Merge> option: + +=over 5 + +=item 1 + +This module needs to have been built with zlib 1.2.1 or better to work. A +fatal error will be thrown if C<Merge> is used with an older version of +zlib. + +=item 2 + +If C<$output> is a file or a filehandle, it must be seekable. + +=back + +This parameter defaults to 0. + +=item -Level + +Defines the compression level used by zlib. The value should either be +a number between 0 and 9 (0 means no compression and 9 is maximum +compression), or one of the symbolic constants defined below. + + Z_NO_COMPRESSION + Z_BEST_SPEED + Z_BEST_COMPRESSION + Z_DEFAULT_COMPRESSION + +The default is Z_DEFAULT_COMPRESSION. + +Note, these constants are not imported by C<IO::Compress::Gzip> by default. + + use IO::Compress::Gzip qw(:strategy); + use IO::Compress::Gzip qw(:constants); + use IO::Compress::Gzip qw(:all); + +=item -Strategy + +Defines the strategy used to tune the compression. Use one of the symbolic +constants defined below. + + Z_FILTERED + Z_HUFFMAN_ONLY + Z_RLE + Z_FIXED + Z_DEFAULT_STRATEGY + +The default is Z_DEFAULT_STRATEGY. + +=item C<< Minimal => 0|1 >> + +If specified, this option will force the creation of the smallest possible +compliant gzip header (which is exactly 10 bytes long) as defined in +RFC 1952. + +See the section titled "Compliance" in RFC 1952 for a definition +of the values used for the fields in the gzip header. + +All other parameters that control the content of the gzip header will +be ignored if this parameter is set to 1. + +This parameter defaults to 0. + +=item C<< Comment => $comment >> + +Stores the contents of C<$comment> in the COMMENT field in +the gzip header. +By default, no comment field is written to the gzip file. + +If the C<-Strict> option is enabled, the comment can only consist of ISO +8859-1 characters plus line feed. + +If the C<-Strict> option is disabled, the comment field can contain any +character except NULL. If any null characters are present, the field +will be truncated at the first NULL. + +=item C<< Name => $string >> + +Stores the contents of C<$string> in the gzip NAME header field. If +C<Name> is not specified, no gzip NAME field will be created. + +If the C<-Strict> option is enabled, C<$string> can only consist of ISO +8859-1 characters. + +If C<-Strict> is disabled, then C<$string> can contain any character +except NULL. If any null characters are present, the field will be +truncated at the first NULL. + +=item C<< Time => $number >> + +Sets the MTIME field in the gzip header to $number. + +This field defaults to the time the C<IO::Compress::Gzip> object was created +if this option is not specified. + +=item C<< TextFlag => 0|1 >> + +This parameter controls the setting of the FLG.FTEXT bit in the gzip +header. It is used to signal that the data stored in the gzip file/buffer +is probably text. + +The default is 0. + +=item C<< HeaderCRC => 0|1 >> + +When true this parameter will set the FLG.FHCRC bit to 1 in the gzip header +and set the CRC16 header field to the CRC of the complete gzip header +except the CRC16 field itself. + +B<Note> that gzip files created with the C<HeaderCRC> flag set to 1 cannot +be read by most, if not all, of the the standard gunzip utilities, most +notably gzip version 1.2.4. You should therefore avoid using this option if +you want to maximize the portability of your gzip files. + +This parameter defaults to 0. + +=item C<< OS_Code => $value >> + +Stores C<$value> in the gzip OS header field. A number between 0 and 255 is +valid. + +If not specified, this parameter defaults to the OS code of the Operating +System this module was built on. The value 3 is used as a catch-all for all +Unix variants and unknown Operating Systems. + +=item C<< ExtraField => $data >> + +This parameter allows additional metadata to be stored in the ExtraField in +the gzip header. An RFC 1952 compliant ExtraField consists of zero or more +subfields. Each subfield consists of a two byte header followed by the +subfield data. + +The list of subfields can be supplied in any of the following formats + + -ExtraField => [$id1, $data1, + $id2, $data2, + ... + ] + -ExtraField => [ [$id1 => $data1], + [$id2 => $data2], + ... + ] + -ExtraField => { $id1 => $data1, + $id2 => $data2, + ... + } + +Where C<$id1>, C<$id2> are two byte subfield ID's. The second byte of +the ID cannot be 0, unless the C<Strict> option has been disabled. + +If you use the hash syntax, you have no control over the order in which +the ExtraSubFields are stored, plus you cannot have SubFields with +duplicate ID. + +Alternatively the list of subfields can by supplied as a scalar, thus + + -ExtraField => $rawdata + +If you use the raw format, and the C<Strict> option is enabled, +C<IO::Compress::Gzip> will check that C<$rawdata> consists of zero or more +conformant sub-fields. When C<Strict> is disabled, C<$rawdata> can +consist of any arbitrary byte stream. + +The maximum size of the Extra Field 65535 bytes. + +=item C<< ExtraFlags => $value >> + +Sets the XFL byte in the gzip header to C<$value>. + +If this option is not present, the value stored in XFL field will be +determined by the setting of the C<Level> option. + +If C<< Level => Z_BEST_SPEED >> has been specified then XFL is set to 2. +If C<< Level => Z_BEST_COMPRESSION >> has been specified then XFL is set to 4. +Otherwise XFL is set to 0. + +=item C<< Strict => 0|1 >> + +C<Strict> will optionally police the values supplied with other options +to ensure they are compliant with RFC1952. + +This option is enabled by default. + +If C<Strict> is enabled the following behaviour will be policed: + +=over 5 + +=item * + +The value supplied with the C<Name> option can only contain ISO 8859-1 +characters. + +=item * + +The value supplied with the C<Comment> option can only contain ISO 8859-1 +characters plus line-feed. + +=item * + +The values supplied with the C<-Name> and C<-Comment> options cannot +contain multiple embedded nulls. + +=item * + +If an C<ExtraField> option is specified and it is a simple scalar, +it must conform to the sub-field structure as defined in RFC 1952. + +=item * + +If an C<ExtraField> option is specified the second byte of the ID will be +checked in each subfield to ensure that it does not contain the reserved +value 0x00. + +=back + +When C<Strict> is disabled the following behaviour will be policed: + +=over 5 + +=item * + +The value supplied with C<-Name> option can contain +any character except NULL. + +=item * + +The value supplied with C<-Comment> option can contain any character +except NULL. + +=item * + +The values supplied with the C<-Name> and C<-Comment> options can contain +multiple embedded nulls. The string written to the gzip header will +consist of the characters up to, but not including, the first embedded +NULL. + +=item * + +If an C<ExtraField> option is specified and it is a simple scalar, the +structure will not be checked. The only error is if the length is too big. + +=item * + +The ID header in an C<ExtraField> sub-field can consist of any two bytes. + +=back + +=back + +=head2 Examples + +TODO + +=head1 Methods + +=head2 print + +Usage is + + $z->print($data) + print $z $data + +Compresses and outputs the contents of the C<$data> parameter. This +has the same behaviour as the C<print> built-in. + +Returns true if successful. + +=head2 printf + +Usage is + + $z->printf($format, $data) + printf $z $format, $data + +Compresses and outputs the contents of the C<$data> parameter. + +Returns true if successful. + +=head2 syswrite + +Usage is + + $z->syswrite $data + $z->syswrite $data, $length + $z->syswrite $data, $length, $offset + +Compresses and outputs the contents of the C<$data> parameter. + +Returns the number of uncompressed bytes written, or C<undef> if +unsuccessful. + +=head2 write + +Usage is + + $z->write $data + $z->write $data, $length + $z->write $data, $length, $offset + +Compresses and outputs the contents of the C<$data> parameter. + +Returns the number of uncompressed bytes written, or C<undef> if +unsuccessful. + +=head2 flush + +Usage is + + $z->flush; + $z->flush($flush_type); + +Flushes any pending compressed data to the output file/buffer. + +This method takes an optional parameter, C<$flush_type>, that controls +how the flushing will be carried out. By default the C<$flush_type> +used is C<Z_FINISH>. Other valid values for C<$flush_type> are +C<Z_NO_FLUSH>, C<Z_SYNC_FLUSH>, C<Z_FULL_FLUSH> and C<Z_BLOCK>. It is +strongly recommended that you only set the C<flush_type> parameter if +you fully understand the implications of what it does - overuse of C<flush> +can seriously degrade the level of compression achieved. See the C<zlib> +documentation for details. + +Returns true on success. + +=head2 tell + +Usage is + + $z->tell() + tell $z + +Returns the uncompressed file offset. + +=head2 eof + +Usage is + + $z->eof(); + eof($z); + +Returns true if the C<close> method has been called. + +=head2 seek + + $z->seek($position, $whence); + seek($z, $position, $whence); + +Provides a sub-set of the C<seek> functionality, with the restriction +that it is only legal to seek forward in the output file/buffer. +It is a fatal error to attempt to seek backward. + +Empty parts of the file/buffer will have NULL (0x00) bytes written to them. + +The C<$whence> parameter takes one the usual values, namely SEEK_SET, +SEEK_CUR or SEEK_END. + +Returns 1 on success, 0 on failure. + +=head2 binmode + +Usage is + + $z->binmode + binmode $z ; + +This is a noop provided for completeness. + +=head2 opened + + $z->opened() + +Returns true if the object currently refers to a opened file/buffer. + +=head2 autoflush + + my $prev = $z->autoflush() + my $prev = $z->autoflush(EXPR) + +If the C<$z> object is associated with a file or a filehandle, this method +returns the current autoflush setting for the underlying filehandle. If +C<EXPR> is present, and is non-zero, it will enable flushing after every +write/print operation. + +If C<$z> is associated with a buffer, this method has no effect and always +returns C<undef>. + +B<Note> that the special variable C<$|> B<cannot> be used to set or +retrieve the autoflush setting. + +=head2 input_line_number + + $z->input_line_number() + $z->input_line_number(EXPR) + +This method always returns C<undef> when compressing. + +=head2 fileno + + $z->fileno() + fileno($z) + +If the C<$z> object is associated with a file or a filehandle, C<fileno> +will return the underlying file descriptor. Once the C<close> method is +called C<fileno> will return C<undef>. + +If the C<$z> object is is associated with a buffer, this method will return +C<undef>. + +=head2 close + + $z->close() ; + close $z ; + +Flushes any pending compressed data and then closes the output file/buffer. + +For most versions of Perl this method will be automatically invoked if +the IO::Compress::Gzip object is destroyed (either explicitly or by the +variable with the reference to the object going out of scope). The +exceptions are Perl versions 5.005 through 5.00504 and 5.8.0. In +these cases, the C<close> method will be called automatically, but +not until global destruction of all live objects when the program is +terminating. + +Therefore, if you want your scripts to be able to run on all versions +of Perl, you should call C<close> explicitly and not rely on automatic +closing. + +Returns true on success, otherwise 0. + +If the C<AutoClose> option has been enabled when the IO::Compress::Gzip +object was created, and the object is associated with a file, the +underlying file will also be closed. + +=head2 newStream([OPTS]) + +Usage is + + $z->newStream( [OPTS] ) + +Closes the current compressed data stream and starts a new one. + +OPTS consists of any of the the options that are available when creating +the C<$z> object. + +See the L</"Constructor Options"> section for more details. + +=head2 deflateParams + +Usage is + + $z->deflateParams + +TODO + +=head1 Importing + +A number of symbolic constants are required by some methods in +C<IO::Compress::Gzip>. None are imported by default. + +=over 5 + +=item :all + +Imports C<gzip>, C<$GzipError> and all symbolic +constants that can be used by C<IO::Compress::Gzip>. Same as doing this + + use IO::Compress::Gzip qw(gzip $GzipError :constants) ; + +=item :constants + +Import all symbolic constants. Same as doing this + + use IO::Compress::Gzip qw(:flush :level :strategy) ; + +=item :flush + +These symbolic constants are used by the C<flush> method. + + Z_NO_FLUSH + Z_PARTIAL_FLUSH + Z_SYNC_FLUSH + Z_FULL_FLUSH + Z_FINISH + Z_BLOCK + +=item :level + +These symbolic constants are used by the C<Level> option in the constructor. + + Z_NO_COMPRESSION + Z_BEST_SPEED + Z_BEST_COMPRESSION + Z_DEFAULT_COMPRESSION + +=item :strategy + +These symbolic constants are used by the C<Strategy> option in the constructor. + + Z_FILTERED + Z_HUFFMAN_ONLY + Z_RLE + Z_FIXED + Z_DEFAULT_STRATEGY + + + + +=back + +=head1 EXAMPLES + +=head2 Apache::GZip Revisited + +See L<IO::Compress::FAQ|IO::Compress::FAQ/"Apache::GZip Revisited"> + + + +=head2 Working with Net::FTP + +See L<IO::Compress::FAQ|IO::Compress::FAQ/"Compressed files and Net::FTP"> + +=head1 SEE ALSO + +L<Compress::Zlib>, L<IO::Uncompress::Gunzip>, L<IO::Compress::Deflate>, L<IO::Uncompress::Inflate>, L<IO::Compress::RawDeflate>, L<IO::Uncompress::RawInflate>, L<IO::Compress::Bzip2>, L<IO::Uncompress::Bunzip2>, L<IO::Compress::Lzma>, L<IO::Uncompress::UnLzma>, L<IO::Compress::Xz>, L<IO::Uncompress::UnXz>, L<IO::Compress::Lzop>, L<IO::Uncompress::UnLzop>, L<IO::Compress::Lzf>, L<IO::Uncompress::UnLzf>, L<IO::Uncompress::AnyInflate>, L<IO::Uncompress::AnyUncompress> + +L<Compress::Zlib::FAQ|Compress::Zlib::FAQ> + +L<File::GlobMapper|File::GlobMapper>, L<Archive::Zip|Archive::Zip>, +L<Archive::Tar|Archive::Tar>, +L<IO::Zlib|IO::Zlib> + +For RFC 1950, 1951 and 1952 see +F<http://www.faqs.org/rfcs/rfc1950.html>, +F<http://www.faqs.org/rfcs/rfc1951.html> and +F<http://www.faqs.org/rfcs/rfc1952.html> + +The I<zlib> compression library was written by Jean-loup Gailly +F<gzip@prep.ai.mit.edu> and Mark Adler F<madler@alumni.caltech.edu>. + +The primary site for the I<zlib> compression library is +F<http://www.zlib.org>. + +The primary site for gzip is F<http://www.gzip.org>. + +=head1 AUTHOR + +This module was written by Paul Marquess, F<pmqs@cpan.org>. + +=head1 MODIFICATION HISTORY + +See the Changes file. + +=head1 COPYRIGHT AND LICENSE + +Copyright (c) 2005-2010 Paul Marquess. All rights reserved. + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + diff --git a/Master/tlpkg/tlperl/lib/IO/Compress/Gzip/Constants.pm b/Master/tlpkg/tlperl/lib/IO/Compress/Gzip/Constants.pm new file mode 100644 index 00000000000..8504330d188 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Compress/Gzip/Constants.pm @@ -0,0 +1,148 @@ +package IO::Compress::Gzip::Constants; + +use strict ; +use warnings; +use bytes; + +require Exporter; + +our ($VERSION, @ISA, @EXPORT, %GZIP_OS_Names); +our ($GZIP_FNAME_INVALID_CHAR_RE, $GZIP_FCOMMENT_INVALID_CHAR_RE); + +$VERSION = '2.024'; + +@ISA = qw(Exporter); + +@EXPORT= qw( + + GZIP_ID_SIZE + GZIP_ID1 + GZIP_ID2 + + GZIP_FLG_DEFAULT + GZIP_FLG_FTEXT + GZIP_FLG_FHCRC + GZIP_FLG_FEXTRA + GZIP_FLG_FNAME + GZIP_FLG_FCOMMENT + GZIP_FLG_RESERVED + + GZIP_CM_DEFLATED + + GZIP_MIN_HEADER_SIZE + GZIP_TRAILER_SIZE + + GZIP_MTIME_DEFAULT + GZIP_XFL_DEFAULT + GZIP_FEXTRA_HEADER_SIZE + GZIP_FEXTRA_MAX_SIZE + GZIP_FEXTRA_SUBFIELD_HEADER_SIZE + GZIP_FEXTRA_SUBFIELD_ID_SIZE + GZIP_FEXTRA_SUBFIELD_LEN_SIZE + GZIP_FEXTRA_SUBFIELD_MAX_SIZE + + $GZIP_FNAME_INVALID_CHAR_RE + $GZIP_FCOMMENT_INVALID_CHAR_RE + + GZIP_FHCRC_SIZE + + GZIP_ISIZE_MAX + GZIP_ISIZE_MOD_VALUE + + + GZIP_NULL_BYTE + + GZIP_OS_DEFAULT + + %GZIP_OS_Names + + GZIP_MINIMUM_HEADER + + ); + +# Constant names derived from RFC 1952 + +use constant GZIP_ID_SIZE => 2 ; +use constant GZIP_ID1 => 0x1F; +use constant GZIP_ID2 => 0x8B; + +use constant GZIP_MIN_HEADER_SIZE => 10 ;# minimum gzip header size +use constant GZIP_TRAILER_SIZE => 8 ; + + +use constant GZIP_FLG_DEFAULT => 0x00 ; +use constant GZIP_FLG_FTEXT => 0x01 ; +use constant GZIP_FLG_FHCRC => 0x02 ; # called CONTINUATION in gzip +use constant GZIP_FLG_FEXTRA => 0x04 ; +use constant GZIP_FLG_FNAME => 0x08 ; +use constant GZIP_FLG_FCOMMENT => 0x10 ; +#use constant GZIP_FLG_ENCRYPTED => 0x20 ; # documented in gzip sources +use constant GZIP_FLG_RESERVED => (0x20 | 0x40 | 0x80) ; + +use constant GZIP_XFL_DEFAULT => 0x00 ; + +use constant GZIP_MTIME_DEFAULT => 0x00 ; + +use constant GZIP_FEXTRA_HEADER_SIZE => 2 ; +use constant GZIP_FEXTRA_MAX_SIZE => 0xFFFF ; +use constant GZIP_FEXTRA_SUBFIELD_ID_SIZE => 2 ; +use constant GZIP_FEXTRA_SUBFIELD_LEN_SIZE => 2 ; +use constant GZIP_FEXTRA_SUBFIELD_HEADER_SIZE => GZIP_FEXTRA_SUBFIELD_ID_SIZE + + GZIP_FEXTRA_SUBFIELD_LEN_SIZE; +use constant GZIP_FEXTRA_SUBFIELD_MAX_SIZE => GZIP_FEXTRA_MAX_SIZE - + GZIP_FEXTRA_SUBFIELD_HEADER_SIZE ; + + +if (ord('A') == 193) +{ + # EBCDIC + $GZIP_FNAME_INVALID_CHAR_RE = '[\x00-\x3f\xff]'; + $GZIP_FCOMMENT_INVALID_CHAR_RE = '[\x00-\x0a\x11-\x14\x16-\x3f\xff]'; + +} +else +{ + $GZIP_FNAME_INVALID_CHAR_RE = '[\x00-\x1F\x7F-\x9F]'; + $GZIP_FCOMMENT_INVALID_CHAR_RE = '[\x00-\x09\x11-\x1F\x7F-\x9F]'; +} + +use constant GZIP_FHCRC_SIZE => 2 ; # aka CONTINUATION in gzip + +use constant GZIP_CM_DEFLATED => 8 ; + +use constant GZIP_NULL_BYTE => "\x00"; +use constant GZIP_ISIZE_MAX => 0xFFFFFFFF ; +use constant GZIP_ISIZE_MOD_VALUE => GZIP_ISIZE_MAX + 1 ; + +# OS Names sourced from http://www.gzip.org/format.txt + +use constant GZIP_OS_DEFAULT=> 0xFF ; +%GZIP_OS_Names = ( + 0 => 'MS-DOS', + 1 => 'Amiga', + 2 => 'VMS', + 3 => 'Unix', + 4 => 'VM/CMS', + 5 => 'Atari TOS', + 6 => 'HPFS (OS/2, NT)', + 7 => 'Macintosh', + 8 => 'Z-System', + 9 => 'CP/M', + 10 => 'TOPS-20', + 11 => 'NTFS (NT)', + 12 => 'SMS QDOS', + 13 => 'Acorn RISCOS', + 14 => 'VFAT file system (Win95, NT)', + 15 => 'MVS', + 16 => 'BeOS', + 17 => 'Tandem/NSK', + 18 => 'THEOS', + GZIP_OS_DEFAULT() => 'Unknown', + ) ; + +use constant GZIP_MINIMUM_HEADER => pack("C4 V C C", + GZIP_ID1, GZIP_ID2, GZIP_CM_DEFLATED, GZIP_FLG_DEFAULT, + GZIP_MTIME_DEFAULT, GZIP_XFL_DEFAULT, GZIP_OS_DEFAULT) ; + + +1; diff --git a/Master/tlpkg/tlperl/lib/IO/Compress/RawDeflate.pm b/Master/tlpkg/tlperl/lib/IO/Compress/RawDeflate.pm new file mode 100644 index 00000000000..b97b51c0509 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Compress/RawDeflate.pm @@ -0,0 +1,1017 @@ +package IO::Compress::RawDeflate ; + +# create RFC1951 +# +use strict ; +use warnings; +use bytes; + + +use IO::Compress::Base 2.024 ; +use IO::Compress::Base::Common 2.024 qw(:Status createSelfTiedObject); +use IO::Compress::Adapter::Deflate 2.024 ; + +require Exporter ; + + +our ($VERSION, @ISA, @EXPORT_OK, %DEFLATE_CONSTANTS, %EXPORT_TAGS, $RawDeflateError); + +$VERSION = '2.024'; +$RawDeflateError = ''; + +@ISA = qw(Exporter IO::Compress::Base); +@EXPORT_OK = qw( $RawDeflateError rawdeflate ) ; + +%EXPORT_TAGS = ( flush => [qw{ + Z_NO_FLUSH + Z_PARTIAL_FLUSH + Z_SYNC_FLUSH + Z_FULL_FLUSH + Z_FINISH + Z_BLOCK + }], + level => [qw{ + Z_NO_COMPRESSION + Z_BEST_SPEED + Z_BEST_COMPRESSION + Z_DEFAULT_COMPRESSION + }], + strategy => [qw{ + Z_FILTERED + Z_HUFFMAN_ONLY + Z_RLE + Z_FIXED + Z_DEFAULT_STRATEGY + }], + + ); + +{ + my %seen; + foreach (keys %EXPORT_TAGS ) + { + push @{$EXPORT_TAGS{constants}}, + grep { !$seen{$_}++ } + @{ $EXPORT_TAGS{$_} } + } + $EXPORT_TAGS{all} = $EXPORT_TAGS{constants} ; +} + + +%DEFLATE_CONSTANTS = %EXPORT_TAGS; + +push @{ $EXPORT_TAGS{all} }, @EXPORT_OK ; + +Exporter::export_ok_tags('all'); + + + +sub new +{ + my $class = shift ; + + my $obj = createSelfTiedObject($class, \$RawDeflateError); + + return $obj->_create(undef, @_); +} + +sub rawdeflate +{ + my $obj = createSelfTiedObject(undef, \$RawDeflateError); + return $obj->_def(@_); +} + +sub ckParams +{ + my $self = shift ; + my $got = shift; + + return 1 ; +} + +sub mkComp +{ + my $self = shift ; + my $got = shift ; + + my ($obj, $errstr, $errno) = IO::Compress::Adapter::Deflate::mkCompObject( + $got->value('CRC32'), + $got->value('Adler32'), + $got->value('Level'), + $got->value('Strategy') + ); + + return $self->saveErrorString(undef, $errstr, $errno) + if ! defined $obj; + + return $obj; +} + + +sub mkHeader +{ + my $self = shift ; + return ''; +} + +sub mkTrailer +{ + my $self = shift ; + return ''; +} + +sub mkFinalTrailer +{ + return ''; +} + + +#sub newHeader +#{ +# my $self = shift ; +# return ''; +#} + +sub getExtraParams +{ + my $self = shift ; + return $self->getZlibParams(); +} + +sub getZlibParams +{ + my $self = shift ; + + use IO::Compress::Base::Common 2.024 qw(:Parse); + use Compress::Raw::Zlib 2.024 qw(Z_DEFLATED Z_DEFAULT_COMPRESSION Z_DEFAULT_STRATEGY); + + + return ( + + # zlib behaviour + #'Method' => [0, 1, Parse_unsigned, Z_DEFLATED], + 'Level' => [0, 1, Parse_signed, Z_DEFAULT_COMPRESSION], + 'Strategy' => [0, 1, Parse_signed, Z_DEFAULT_STRATEGY], + + 'CRC32' => [0, 1, Parse_boolean, 0], + 'ADLER32' => [0, 1, Parse_boolean, 0], + 'Merge' => [1, 1, Parse_boolean, 0], + ); + + +} + +sub getInverseClass +{ + return ('IO::Uncompress::RawInflate', + \$IO::Uncompress::RawInflate::RawInflateError); +} + +sub getFileInfo +{ + my $self = shift ; + my $params = shift; + my $file = shift ; + +} + +use IO::Seekable qw(SEEK_SET); + +sub createMerge +{ + my $self = shift ; + my $outValue = shift ; + my $outType = shift ; + + my ($invClass, $error_ref) = $self->getInverseClass(); + eval "require $invClass" + or die "aaaahhhh" ; + + my $inf = $invClass->new( $outValue, + Transparent => 0, + #Strict => 1, + AutoClose => 0, + Scan => 1) + or return $self->saveErrorString(undef, "Cannot create InflateScan object: $$error_ref" ) ; + + my $end_offset = 0; + $inf->scan() + or return $self->saveErrorString(undef, "Error Scanning: $$error_ref", $inf->errorNo) ; + $inf->zap($end_offset) + or return $self->saveErrorString(undef, "Error Zapping: $$error_ref", $inf->errorNo) ; + + my $def = *$self->{Compress} = $inf->createDeflate(); + + *$self->{Header} = *$inf->{Info}{Header}; + *$self->{UnCompSize} = *$inf->{UnCompSize}->clone(); + *$self->{CompSize} = *$inf->{CompSize}->clone(); + # TODO -- fix this + #*$self->{CompSize} = new U64(0, *$self->{UnCompSize_32bit}); + + + if ( $outType eq 'buffer') + { substr( ${ *$self->{Buffer} }, $end_offset) = '' } + elsif ($outType eq 'handle' || $outType eq 'filename') { + *$self->{FH} = *$inf->{FH} ; + delete *$inf->{FH}; + *$self->{FH}->flush() ; + *$self->{Handle} = 1 if $outType eq 'handle'; + + #seek(*$self->{FH}, $end_offset, SEEK_SET) + *$self->{FH}->seek($end_offset, SEEK_SET) + or return $self->saveErrorString(undef, $!, $!) ; + } + + return $def ; +} + +#### zlib specific methods + +sub deflateParams +{ + my $self = shift ; + + my $level = shift ; + my $strategy = shift ; + + my $status = *$self->{Compress}->deflateParams(Level => $level, Strategy => $strategy) ; + return $self->saveErrorString(0, *$self->{Compress}{Error}, *$self->{Compress}{ErrorNo}) + if $status == STATUS_ERROR; + + return 1; +} + + + + +1; + +__END__ + +=head1 NAME + +IO::Compress::RawDeflate - Write RFC 1951 files/buffers + + + +=head1 SYNOPSIS + + use IO::Compress::RawDeflate qw(rawdeflate $RawDeflateError) ; + + my $status = rawdeflate $input => $output [,OPTS] + or die "rawdeflate failed: $RawDeflateError\n"; + + my $z = new IO::Compress::RawDeflate $output [,OPTS] + or die "rawdeflate failed: $RawDeflateError\n"; + + $z->print($string); + $z->printf($format, $string); + $z->write($string); + $z->syswrite($string [, $length, $offset]); + $z->flush(); + $z->tell(); + $z->eof(); + $z->seek($position, $whence); + $z->binmode(); + $z->fileno(); + $z->opened(); + $z->autoflush(); + $z->input_line_number(); + $z->newStream( [OPTS] ); + + $z->deflateParams(); + + $z->close() ; + + $RawDeflateError ; + + # IO::File mode + + print $z $string; + printf $z $format, $string; + tell $z + eof $z + seek $z, $position, $whence + binmode $z + fileno $z + close $z ; + + +=head1 DESCRIPTION + +This module provides a Perl interface that allows writing compressed +data to files or buffer as defined in RFC 1951. + +Note that RFC 1951 data is not a good choice of compression format +to use in isolation, especially if you want to auto-detect it. + +For reading RFC 1951 files/buffers, see the companion module +L<IO::Uncompress::RawInflate|IO::Uncompress::RawInflate>. + +=head1 Functional Interface + +A top-level function, C<rawdeflate>, is provided to carry out +"one-shot" compression between buffers and/or files. For finer +control over the compression process, see the L</"OO Interface"> +section. + + use IO::Compress::RawDeflate qw(rawdeflate $RawDeflateError) ; + + rawdeflate $input => $output [,OPTS] + or die "rawdeflate failed: $RawDeflateError\n"; + +The functional interface needs Perl5.005 or better. + +=head2 rawdeflate $input => $output [, OPTS] + +C<rawdeflate> expects at least two parameters, C<$input> and C<$output>. + +=head3 The C<$input> parameter + +The parameter, C<$input>, is used to define the source of +the uncompressed data. + +It can take one of the following forms: + +=over 5 + +=item A filename + +If the C<$input> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for reading and the input data +will be read from it. + +=item A filehandle + +If the C<$input> parameter is a filehandle, the input data will be +read from it. +The string '-' can be used as an alias for standard input. + +=item A scalar reference + +If C<$input> is a scalar reference, the input data will be read +from C<$$input>. + +=item An array reference + +If C<$input> is an array reference, each element in the array must be a +filename. + +The input data will be read from each file in turn. + +The complete array will be walked to ensure that it only +contains valid filenames before any data is compressed. + +=item An Input FileGlob string + +If C<$input> is a string that is delimited by the characters "<" and ">" +C<rawdeflate> will assume that it is an I<input fileglob string>. The +input is the list of files that match the fileglob. + +If the fileglob does not match any files ... + +See L<File::GlobMapper|File::GlobMapper> for more details. + +=back + +If the C<$input> parameter is any other type, C<undef> will be returned. + +=head3 The C<$output> parameter + +The parameter C<$output> is used to control the destination of the +compressed data. This parameter can take one of these forms. + +=over 5 + +=item A filename + +If the C<$output> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for writing and the compressed +data will be written to it. + +=item A filehandle + +If the C<$output> parameter is a filehandle, the compressed data +will be written to it. +The string '-' can be used as an alias for standard output. + +=item A scalar reference + +If C<$output> is a scalar reference, the compressed data will be +stored in C<$$output>. + +=item An Array Reference + +If C<$output> is an array reference, the compressed data will be +pushed onto the array. + +=item An Output FileGlob + +If C<$output> is a string that is delimited by the characters "<" and ">" +C<rawdeflate> will assume that it is an I<output fileglob string>. The +output is the list of files that match the fileglob. + +When C<$output> is an fileglob string, C<$input> must also be a fileglob +string. Anything else is an error. + +=back + +If the C<$output> parameter is any other type, C<undef> will be returned. + +=head2 Notes + +When C<$input> maps to multiple files/buffers and C<$output> is a single +file/buffer the input files/buffers will be stored +in C<$output> as a concatenated series of compressed data streams. + +=head2 Optional Parameters + +Unless specified below, the optional parameters for C<rawdeflate>, +C<OPTS>, are the same as those used with the OO interface defined in the +L</"Constructor Options"> section below. + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option applies to any input or output data streams to +C<rawdeflate> that are filehandles. + +If C<AutoClose> is specified, and the value is true, it will result in all +input and/or output filehandles being closed once C<rawdeflate> has +completed. + +This parameter defaults to 0. + +=item C<< BinModeIn => 0|1 >> + +When reading from a file or filehandle, set C<binmode> before reading. + +Defaults to 0. + +=item C<< Append => 0|1 >> + +The behaviour of this option is dependent on the type of output data +stream. + +=over 5 + +=item * A Buffer + +If C<Append> is enabled, all compressed data will be append to the end of +the output buffer. Otherwise the output buffer will be cleared before any +compressed data is written to it. + +=item * A Filename + +If C<Append> is enabled, the file will be opened in append mode. Otherwise +the contents of the file, if any, will be truncated before any compressed +data is written to it. + +=item * A Filehandle + +If C<Append> is enabled, the filehandle will be positioned to the end of +the file via a call to C<seek> before any compressed data is +written to it. Otherwise the file pointer will not be moved. + +=back + +When C<Append> is specified, and set to true, it will I<append> all compressed +data to the output data stream. + +So when the output is a filehandle it will carry out a seek to the eof +before writing any compressed data. If the output is a filename, it will be opened for +appending. If the output is a buffer, all compressed data will be appened to +the existing buffer. + +Conversely when C<Append> is not specified, or it is present and is set to +false, it will operate as follows. + +When the output is a filename, it will truncate the contents of the file +before writing any compressed data. If the output is a filehandle +its position will not be changed. If the output is a buffer, it will be +wiped before any compressed data is output. + +Defaults to 0. + +=back + +=head2 Examples + +To read the contents of the file C<file1.txt> and write the compressed +data to the file C<file1.txt.1951>. + + use strict ; + use warnings ; + use IO::Compress::RawDeflate qw(rawdeflate $RawDeflateError) ; + + my $input = "file1.txt"; + rawdeflate $input => "$input.1951" + or die "rawdeflate failed: $RawDeflateError\n"; + +To read from an existing Perl filehandle, C<$input>, and write the +compressed data to a buffer, C<$buffer>. + + use strict ; + use warnings ; + use IO::Compress::RawDeflate qw(rawdeflate $RawDeflateError) ; + use IO::File ; + + my $input = new IO::File "<file1.txt" + or die "Cannot open 'file1.txt': $!\n" ; + my $buffer ; + rawdeflate $input => \$buffer + or die "rawdeflate failed: $RawDeflateError\n"; + +To compress all files in the directory "/my/home" that match "*.txt" +and store the compressed data in the same directory + + use strict ; + use warnings ; + use IO::Compress::RawDeflate qw(rawdeflate $RawDeflateError) ; + + rawdeflate '</my/home/*.txt>' => '<*.1951>' + or die "rawdeflate failed: $RawDeflateError\n"; + +and if you want to compress each file one at a time, this will do the trick + + use strict ; + use warnings ; + use IO::Compress::RawDeflate qw(rawdeflate $RawDeflateError) ; + + for my $input ( glob "/my/home/*.txt" ) + { + my $output = "$input.1951" ; + rawdeflate $input => $output + or die "Error compressing '$input': $RawDeflateError\n"; + } + +=head1 OO Interface + +=head2 Constructor + +The format of the constructor for C<IO::Compress::RawDeflate> is shown below + + my $z = new IO::Compress::RawDeflate $output [,OPTS] + or die "IO::Compress::RawDeflate failed: $RawDeflateError\n"; + +It returns an C<IO::Compress::RawDeflate> object on success and undef on failure. +The variable C<$RawDeflateError> will contain an error message on failure. + +If you are running Perl 5.005 or better the object, C<$z>, returned from +IO::Compress::RawDeflate can be used exactly like an L<IO::File|IO::File> filehandle. +This means that all normal output file operations can be carried out +with C<$z>. +For example, to write to a compressed file/buffer you can use either of +these forms + + $z->print("hello world\n"); + print $z "hello world\n"; + +The mandatory parameter C<$output> is used to control the destination +of the compressed data. This parameter can take one of these forms. + +=over 5 + +=item A filename + +If the C<$output> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for writing and the compressed data +will be written to it. + +=item A filehandle + +If the C<$output> parameter is a filehandle, the compressed data will be +written to it. +The string '-' can be used as an alias for standard output. + +=item A scalar reference + +If C<$output> is a scalar reference, the compressed data will be stored +in C<$$output>. + +=back + +If the C<$output> parameter is any other type, C<IO::Compress::RawDeflate>::new will +return undef. + +=head2 Constructor Options + +C<OPTS> is any combination of the following options: + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option is only valid when the C<$output> parameter is a filehandle. If +specified, and the value is true, it will result in the C<$output> being +closed once either the C<close> method is called or the C<IO::Compress::RawDeflate> +object is destroyed. + +This parameter defaults to 0. + +=item C<< Append => 0|1 >> + +Opens C<$output> in append mode. + +The behaviour of this option is dependent on the type of C<$output>. + +=over 5 + +=item * A Buffer + +If C<$output> is a buffer and C<Append> is enabled, all compressed data +will be append to the end of C<$output>. Otherwise C<$output> will be +cleared before any data is written to it. + +=item * A Filename + +If C<$output> is a filename and C<Append> is enabled, the file will be +opened in append mode. Otherwise the contents of the file, if any, will be +truncated before any compressed data is written to it. + +=item * A Filehandle + +If C<$output> is a filehandle, the file pointer will be positioned to the +end of the file via a call to C<seek> before any compressed data is written +to it. Otherwise the file pointer will not be moved. + +=back + +This parameter defaults to 0. + +=item C<< Merge => 0|1 >> + +This option is used to compress input data and append it to an existing +compressed data stream in C<$output>. The end result is a single compressed +data stream stored in C<$output>. + +It is a fatal error to attempt to use this option when C<$output> is not an +RFC 1951 data stream. + +There are a number of other limitations with the C<Merge> option: + +=over 5 + +=item 1 + +This module needs to have been built with zlib 1.2.1 or better to work. A +fatal error will be thrown if C<Merge> is used with an older version of +zlib. + +=item 2 + +If C<$output> is a file or a filehandle, it must be seekable. + +=back + +This parameter defaults to 0. + +=item -Level + +Defines the compression level used by zlib. The value should either be +a number between 0 and 9 (0 means no compression and 9 is maximum +compression), or one of the symbolic constants defined below. + + Z_NO_COMPRESSION + Z_BEST_SPEED + Z_BEST_COMPRESSION + Z_DEFAULT_COMPRESSION + +The default is Z_DEFAULT_COMPRESSION. + +Note, these constants are not imported by C<IO::Compress::RawDeflate> by default. + + use IO::Compress::RawDeflate qw(:strategy); + use IO::Compress::RawDeflate qw(:constants); + use IO::Compress::RawDeflate qw(:all); + +=item -Strategy + +Defines the strategy used to tune the compression. Use one of the symbolic +constants defined below. + + Z_FILTERED + Z_HUFFMAN_ONLY + Z_RLE + Z_FIXED + Z_DEFAULT_STRATEGY + +The default is Z_DEFAULT_STRATEGY. + +=item C<< Strict => 0|1 >> + +This is a placeholder option. + +=back + +=head2 Examples + +TODO + +=head1 Methods + +=head2 print + +Usage is + + $z->print($data) + print $z $data + +Compresses and outputs the contents of the C<$data> parameter. This +has the same behaviour as the C<print> built-in. + +Returns true if successful. + +=head2 printf + +Usage is + + $z->printf($format, $data) + printf $z $format, $data + +Compresses and outputs the contents of the C<$data> parameter. + +Returns true if successful. + +=head2 syswrite + +Usage is + + $z->syswrite $data + $z->syswrite $data, $length + $z->syswrite $data, $length, $offset + +Compresses and outputs the contents of the C<$data> parameter. + +Returns the number of uncompressed bytes written, or C<undef> if +unsuccessful. + +=head2 write + +Usage is + + $z->write $data + $z->write $data, $length + $z->write $data, $length, $offset + +Compresses and outputs the contents of the C<$data> parameter. + +Returns the number of uncompressed bytes written, or C<undef> if +unsuccessful. + +=head2 flush + +Usage is + + $z->flush; + $z->flush($flush_type); + +Flushes any pending compressed data to the output file/buffer. + +This method takes an optional parameter, C<$flush_type>, that controls +how the flushing will be carried out. By default the C<$flush_type> +used is C<Z_FINISH>. Other valid values for C<$flush_type> are +C<Z_NO_FLUSH>, C<Z_SYNC_FLUSH>, C<Z_FULL_FLUSH> and C<Z_BLOCK>. It is +strongly recommended that you only set the C<flush_type> parameter if +you fully understand the implications of what it does - overuse of C<flush> +can seriously degrade the level of compression achieved. See the C<zlib> +documentation for details. + +Returns true on success. + +=head2 tell + +Usage is + + $z->tell() + tell $z + +Returns the uncompressed file offset. + +=head2 eof + +Usage is + + $z->eof(); + eof($z); + +Returns true if the C<close> method has been called. + +=head2 seek + + $z->seek($position, $whence); + seek($z, $position, $whence); + +Provides a sub-set of the C<seek> functionality, with the restriction +that it is only legal to seek forward in the output file/buffer. +It is a fatal error to attempt to seek backward. + +Empty parts of the file/buffer will have NULL (0x00) bytes written to them. + +The C<$whence> parameter takes one the usual values, namely SEEK_SET, +SEEK_CUR or SEEK_END. + +Returns 1 on success, 0 on failure. + +=head2 binmode + +Usage is + + $z->binmode + binmode $z ; + +This is a noop provided for completeness. + +=head2 opened + + $z->opened() + +Returns true if the object currently refers to a opened file/buffer. + +=head2 autoflush + + my $prev = $z->autoflush() + my $prev = $z->autoflush(EXPR) + +If the C<$z> object is associated with a file or a filehandle, this method +returns the current autoflush setting for the underlying filehandle. If +C<EXPR> is present, and is non-zero, it will enable flushing after every +write/print operation. + +If C<$z> is associated with a buffer, this method has no effect and always +returns C<undef>. + +B<Note> that the special variable C<$|> B<cannot> be used to set or +retrieve the autoflush setting. + +=head2 input_line_number + + $z->input_line_number() + $z->input_line_number(EXPR) + +This method always returns C<undef> when compressing. + +=head2 fileno + + $z->fileno() + fileno($z) + +If the C<$z> object is associated with a file or a filehandle, C<fileno> +will return the underlying file descriptor. Once the C<close> method is +called C<fileno> will return C<undef>. + +If the C<$z> object is is associated with a buffer, this method will return +C<undef>. + +=head2 close + + $z->close() ; + close $z ; + +Flushes any pending compressed data and then closes the output file/buffer. + +For most versions of Perl this method will be automatically invoked if +the IO::Compress::RawDeflate object is destroyed (either explicitly or by the +variable with the reference to the object going out of scope). The +exceptions are Perl versions 5.005 through 5.00504 and 5.8.0. In +these cases, the C<close> method will be called automatically, but +not until global destruction of all live objects when the program is +terminating. + +Therefore, if you want your scripts to be able to run on all versions +of Perl, you should call C<close> explicitly and not rely on automatic +closing. + +Returns true on success, otherwise 0. + +If the C<AutoClose> option has been enabled when the IO::Compress::RawDeflate +object was created, and the object is associated with a file, the +underlying file will also be closed. + +=head2 newStream([OPTS]) + +Usage is + + $z->newStream( [OPTS] ) + +Closes the current compressed data stream and starts a new one. + +OPTS consists of any of the the options that are available when creating +the C<$z> object. + +See the L</"Constructor Options"> section for more details. + +=head2 deflateParams + +Usage is + + $z->deflateParams + +TODO + +=head1 Importing + +A number of symbolic constants are required by some methods in +C<IO::Compress::RawDeflate>. None are imported by default. + +=over 5 + +=item :all + +Imports C<rawdeflate>, C<$RawDeflateError> and all symbolic +constants that can be used by C<IO::Compress::RawDeflate>. Same as doing this + + use IO::Compress::RawDeflate qw(rawdeflate $RawDeflateError :constants) ; + +=item :constants + +Import all symbolic constants. Same as doing this + + use IO::Compress::RawDeflate qw(:flush :level :strategy) ; + +=item :flush + +These symbolic constants are used by the C<flush> method. + + Z_NO_FLUSH + Z_PARTIAL_FLUSH + Z_SYNC_FLUSH + Z_FULL_FLUSH + Z_FINISH + Z_BLOCK + +=item :level + +These symbolic constants are used by the C<Level> option in the constructor. + + Z_NO_COMPRESSION + Z_BEST_SPEED + Z_BEST_COMPRESSION + Z_DEFAULT_COMPRESSION + +=item :strategy + +These symbolic constants are used by the C<Strategy> option in the constructor. + + Z_FILTERED + Z_HUFFMAN_ONLY + Z_RLE + Z_FIXED + Z_DEFAULT_STRATEGY + + + + +=back + +=head1 EXAMPLES + +=head2 Apache::GZip Revisited + +See L<IO::Compress::FAQ|IO::Compress::FAQ/"Apache::GZip Revisited"> + + + +=head2 Working with Net::FTP + +See L<IO::Compress::FAQ|IO::Compress::FAQ/"Compressed files and Net::FTP"> + +=head1 SEE ALSO + +L<Compress::Zlib>, L<IO::Compress::Gzip>, L<IO::Uncompress::Gunzip>, L<IO::Compress::Deflate>, L<IO::Uncompress::Inflate>, L<IO::Uncompress::RawInflate>, L<IO::Compress::Bzip2>, L<IO::Uncompress::Bunzip2>, L<IO::Compress::Lzma>, L<IO::Uncompress::UnLzma>, L<IO::Compress::Xz>, L<IO::Uncompress::UnXz>, L<IO::Compress::Lzop>, L<IO::Uncompress::UnLzop>, L<IO::Compress::Lzf>, L<IO::Uncompress::UnLzf>, L<IO::Uncompress::AnyInflate>, L<IO::Uncompress::AnyUncompress> + +L<Compress::Zlib::FAQ|Compress::Zlib::FAQ> + +L<File::GlobMapper|File::GlobMapper>, L<Archive::Zip|Archive::Zip>, +L<Archive::Tar|Archive::Tar>, +L<IO::Zlib|IO::Zlib> + +For RFC 1950, 1951 and 1952 see +F<http://www.faqs.org/rfcs/rfc1950.html>, +F<http://www.faqs.org/rfcs/rfc1951.html> and +F<http://www.faqs.org/rfcs/rfc1952.html> + +The I<zlib> compression library was written by Jean-loup Gailly +F<gzip@prep.ai.mit.edu> and Mark Adler F<madler@alumni.caltech.edu>. + +The primary site for the I<zlib> compression library is +F<http://www.zlib.org>. + +The primary site for gzip is F<http://www.gzip.org>. + +=head1 AUTHOR + +This module was written by Paul Marquess, F<pmqs@cpan.org>. + +=head1 MODIFICATION HISTORY + +See the Changes file. + +=head1 COPYRIGHT AND LICENSE + +Copyright (c) 2005-2010 Paul Marquess. All rights reserved. + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + diff --git a/Master/tlpkg/tlperl/lib/IO/Compress/Zip.pm b/Master/tlpkg/tlperl/lib/IO/Compress/Zip.pm new file mode 100644 index 00000000000..5e37d78f97d --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Compress/Zip.pm @@ -0,0 +1,1612 @@ +package IO::Compress::Zip ; + +use strict ; +use warnings; +use bytes; + +use IO::Compress::Base::Common 2.024 qw(:Status createSelfTiedObject); +use IO::Compress::RawDeflate 2.024 ; +use IO::Compress::Adapter::Deflate 2.024 ; +use IO::Compress::Adapter::Identity 2.024 ; +use IO::Compress::Zlib::Extra 2.024 ; +use IO::Compress::Zip::Constants 2.024 ; + + +use Compress::Raw::Zlib 2.024 qw(crc32) ; +BEGIN +{ + eval { require IO::Compress::Adapter::Bzip2 ; + import IO::Compress::Adapter::Bzip2 2.024 ; + require IO::Compress::Bzip2 ; + import IO::Compress::Bzip2 2.024 ; + } ; +# eval { require IO::Compress::Adapter::Lzma ; +# import IO::Compress::Adapter::Lzma 2.020 ; +# require IO::Compress::Lzma ; +# import IO::Compress::Lzma 2.024 ; +# } ; +} + + +require Exporter ; + +our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, $ZipError); + +$VERSION = '2.024'; +$ZipError = ''; + +@ISA = qw(Exporter IO::Compress::RawDeflate); +@EXPORT_OK = qw( $ZipError zip ) ; +%EXPORT_TAGS = %IO::Compress::RawDeflate::DEFLATE_CONSTANTS ; +push @{ $EXPORT_TAGS{all} }, @EXPORT_OK ; + +$EXPORT_TAGS{zip_method} = [qw( ZIP_CM_STORE ZIP_CM_DEFLATE ZIP_CM_BZIP2 ZIP_CM_LZMA)]; +push @{ $EXPORT_TAGS{all} }, @{ $EXPORT_TAGS{zip_method} }; + +Exporter::export_ok_tags('all'); + +sub new +{ + my $class = shift ; + + my $obj = createSelfTiedObject($class, \$ZipError); + $obj->_create(undef, @_); +} + +sub zip +{ + my $obj = createSelfTiedObject(undef, \$ZipError); + return $obj->_def(@_); +} + +sub mkComp +{ + my $self = shift ; + my $got = shift ; + + my ($obj, $errstr, $errno) ; + + if (*$self->{ZipData}{Method} == ZIP_CM_STORE) { + ($obj, $errstr, $errno) = IO::Compress::Adapter::Identity::mkCompObject( + $got->value('Level'), + $got->value('Strategy') + ); + *$self->{ZipData}{CRC32} = crc32(undef); + } + elsif (*$self->{ZipData}{Method} == ZIP_CM_DEFLATE) { + ($obj, $errstr, $errno) = IO::Compress::Adapter::Deflate::mkCompObject( + $got->value('CRC32'), + $got->value('Adler32'), + $got->value('Level'), + $got->value('Strategy') + ); + } + elsif (*$self->{ZipData}{Method} == ZIP_CM_BZIP2) { + ($obj, $errstr, $errno) = IO::Compress::Adapter::Bzip2::mkCompObject( + $got->value('BlockSize100K'), + $got->value('WorkFactor'), + $got->value('Verbosity') + ); + *$self->{ZipData}{CRC32} = crc32(undef); + } +# elsif (*$self->{ZipData}{Method} == ZIP_CM_LZMA) { +# ($obj, $errstr, $errno) = IO::Compress::Adapter::Lzma::mkCompObject(); +# *$self->{ZipData}{CRC32} = crc32(undef); +# } + + return $self->saveErrorString(undef, $errstr, $errno) + if ! defined $obj; + + if (! defined *$self->{ZipData}{SizesOffset}) { + *$self->{ZipData}{SizesOffset} = 0; + *$self->{ZipData}{Offset} = new U64 ; + } + + *$self->{ZipData}{AnyZip64} = 0 + if ! defined *$self->{ZipData}{AnyZip64} ; + + return $obj; +} + +sub reset +{ + my $self = shift ; + + *$self->{Compress}->reset(); + *$self->{ZipData}{CRC32} = Compress::Raw::Zlib::crc32(''); + + return STATUS_OK; +} + +sub filterUncompressed +{ + my $self = shift ; + + if (*$self->{ZipData}{Method} == ZIP_CM_DEFLATE) { + *$self->{ZipData}{CRC32} = *$self->{Compress}->crc32(); + } + else { + *$self->{ZipData}{CRC32} = crc32(${$_[0]}, *$self->{ZipData}{CRC32}); + + } +} + +sub mkHeader +{ + my $self = shift; + my $param = shift ; + + + *$self->{ZipData}{LocalHdrOffset} = U64::clone(*$self->{ZipData}{Offset}); + + my $filename = ''; + $filename = $param->value('Name') || ''; + + my $comment = ''; + $comment = $param->value('Comment') || ''; + + my $hdr = ''; + + my $time = _unixToDosTime($param->value('Time')); + + my $extra = ''; + my $ctlExtra = ''; + my $empty = 0; + my $osCode = $param->value('OS_Code') ; + my $extFileAttr = 0 ; + + # This code assumes Unix. + $extFileAttr = 0666 << 16 + if $osCode == ZIP_OS_CODE_UNIX ; + + if (*$self->{ZipData}{Zip64}) { + $empty = 0xFFFFFFFF; + + my $x = ''; + $x .= pack "V V", 0, 0 ; # uncompressedLength + $x .= pack "V V", 0, 0 ; # compressedLength + $extra .= IO::Compress::Zlib::Extra::mkSubField(ZIP_EXTRA_ID_ZIP64, $x); + } + + if (! $param->value('Minimal')) { + if (defined $param->value('exTime')) + { + $extra .= mkExtendedTime($param->value('MTime'), + $param->value('ATime'), + $param->value('CTime')); + + $ctlExtra .= mkExtendedTime($param->value('MTime')); + } + + if ( $param->value('UID') && $osCode == ZIP_OS_CODE_UNIX) + { + $extra .= mkUnix2Extra( $param->value('UID'), $param->value('GID')); + $ctlExtra .= mkUnix2Extra(); + } + + $extFileAttr = $param->value('ExtAttr') + if defined $param->value('ExtAttr') ; + + $extra .= $param->value('ExtraFieldLocal') + if defined $param->value('ExtraFieldLocal'); + + $ctlExtra .= $param->value('ExtraFieldCentral') + if defined $param->value('ExtraFieldCentral'); + } + + my $gpFlag = 0 ; + $gpFlag |= ZIP_GP_FLAG_STREAMING_MASK + if *$self->{ZipData}{Stream} ; + + my $method = *$self->{ZipData}{Method} ; + + my $version = $ZIP_CM_MIN_VERSIONS{$method}; + $version = ZIP64_MIN_VERSION + if ZIP64_MIN_VERSION > $version && *$self->{ZipData}{Zip64}; + my $madeBy = ($param->value('OS_Code') << 8) + $version; + my $extract = $version; + + *$self->{ZipData}{Version} = $version; + *$self->{ZipData}{MadeBy} = $madeBy; + + my $ifa = 0; + $ifa |= ZIP_IFA_TEXT_MASK + if $param->value('TextFlag'); + + $hdr .= pack "V", ZIP_LOCAL_HDR_SIG ; # signature + $hdr .= pack 'v', $extract ; # extract Version & OS + $hdr .= pack 'v', $gpFlag ; # general purpose flag (set streaming mode) + $hdr .= pack 'v', $method ; # compression method (deflate) + $hdr .= pack 'V', $time ; # last mod date/time + $hdr .= pack 'V', 0 ; # crc32 - 0 when streaming + $hdr .= pack 'V', $empty ; # compressed length - 0 when streaming + $hdr .= pack 'V', $empty ; # uncompressed length - 0 when streaming + $hdr .= pack 'v', length $filename ; # filename length + $hdr .= pack 'v', length $extra ; # extra length + + $hdr .= $filename ; + + # Remember the offset for the compressed & uncompressed lengths in the + # local header. + if (*$self->{ZipData}{Zip64}) { + *$self->{ZipData}{SizesOffset} = *$self->{ZipData}{Offset}->get64bit() + + length($hdr) + 4 ; + } + else { + *$self->{ZipData}{SizesOffset} = *$self->{ZipData}{Offset}->get64bit() + + 18; + } + + $hdr .= $extra ; + + + my $ctl = ''; + + $ctl .= pack "V", ZIP_CENTRAL_HDR_SIG ; # signature + $ctl .= pack 'v', $madeBy ; # version made by + $ctl .= pack 'v', $extract ; # extract Version + $ctl .= pack 'v', $gpFlag ; # general purpose flag (streaming mode) + $ctl .= pack 'v', $method ; # compression method (deflate) + $ctl .= pack 'V', $time ; # last mod date/time + $ctl .= pack 'V', 0 ; # crc32 + $ctl .= pack 'V', $empty ; # compressed length + $ctl .= pack 'V', $empty ; # uncompressed length + $ctl .= pack 'v', length $filename ; # filename length + + *$self->{ZipData}{ExtraOffset} = length $ctl; + *$self->{ZipData}{ExtraSize} = length $ctlExtra ; + + $ctl .= pack 'v', length $ctlExtra ; # extra length + $ctl .= pack 'v', length $comment ; # file comment length + $ctl .= pack 'v', 0 ; # disk number start + $ctl .= pack 'v', $ifa ; # internal file attributes + $ctl .= pack 'V', $extFileAttr ; # external file attributes + + # offset to local hdr + if (*$self->{ZipData}{LocalHdrOffset}->is64bit() ) { + $ctl .= pack 'V', 0xFFFFFFFF ; + } + else { + $ctl .= *$self->{ZipData}{LocalHdrOffset}->getPacked_V32() ; + } + + $ctl .= $filename ; + $ctl .= $ctlExtra ; + $ctl .= $comment ; + + *$self->{ZipData}{Offset}->add(length $hdr) ; + + *$self->{ZipData}{CentralHeader} = $ctl; + + return $hdr; +} + +sub mkTrailer +{ + my $self = shift ; + + my $crc32 ; + if (*$self->{ZipData}{Method} == ZIP_CM_DEFLATE) { + $crc32 = pack "V", *$self->{Compress}->crc32(); + } + else { + $crc32 = pack "V", *$self->{ZipData}{CRC32}; + } + + my $ctl = *$self->{ZipData}{CentralHeader} ; + + my $sizes ; + if (! *$self->{ZipData}{Zip64}) { + $sizes .= *$self->{CompSize}->getPacked_V32() ; # Compressed size + $sizes .= *$self->{UnCompSize}->getPacked_V32() ; # Uncompressed size + } + else { + $sizes .= *$self->{CompSize}->getPacked_V64() ; # Compressed size + $sizes .= *$self->{UnCompSize}->getPacked_V64() ; # Uncompressed size + } + + my $data = $crc32 . $sizes ; + + my $xtrasize = *$self->{UnCompSize}->getPacked_V64() ; # Uncompressed size + $xtrasize .= *$self->{CompSize}->getPacked_V64() ; # Compressed size + + my $hdr = ''; + + if (*$self->{ZipData}{Stream}) { + $hdr = pack "V", ZIP_DATA_HDR_SIG ; # signature + $hdr .= $data ; + } + else { + $self->writeAt(*$self->{ZipData}{LocalHdrOffset}->get64bit() + 14, $crc32) + or return undef; + $self->writeAt(*$self->{ZipData}{SizesOffset}, + *$self->{ZipData}{Zip64} ? $xtrasize : $sizes) + or return undef; + } + + # Central Header Record/Zip64 extended field + + substr($ctl, 16, length $crc32) = $crc32 ; + + my $x = ''; + + # uncompressed length + if (*$self->{UnCompSize}->is64bit() ) { + $x .= *$self->{UnCompSize}->getPacked_V64() ; + } else { + substr($ctl, 24, 4) = *$self->{UnCompSize}->getPacked_V32() ; + } + + # compressed length + if (*$self->{CompSize}->is64bit() ) { + $x .= *$self->{CompSize}->getPacked_V64() ; + } else { + substr($ctl, 20, 4) = *$self->{CompSize}->getPacked_V32() ; + } + + # Local Header offset + $x .= *$self->{ZipData}{LocalHdrOffset}->getPacked_V64() + if *$self->{ZipData}{LocalHdrOffset}->is64bit() ; + + # disk no - always zero, so don't need it + #$x .= pack "V", 0 ; + + if (length $x) { + my $xtra = IO::Compress::Zlib::Extra::mkSubField(ZIP_EXTRA_ID_ZIP64, $x); + $ctl .= $xtra ; + substr($ctl, *$self->{ZipData}{ExtraOffset}, 2) = + pack 'v', *$self->{ZipData}{ExtraSize} + length $xtra; + + *$self->{ZipData}{AnyZip64} = 1; + } + + *$self->{ZipData}{Offset}->add(length($hdr)); + *$self->{ZipData}{Offset}->add( *$self->{CompSize} ); + push @{ *$self->{ZipData}{CentralDir} }, $ctl ; + + return $hdr; +} + +sub mkFinalTrailer +{ + my $self = shift ; + + my $comment = ''; + $comment = *$self->{ZipData}{ZipComment} ; + + my $cd_offset = *$self->{ZipData}{Offset}->get32bit() ; # offset to start central dir + + my $entries = @{ *$self->{ZipData}{CentralDir} }; + my $cd = join '', @{ *$self->{ZipData}{CentralDir} }; + my $cd_len = length $cd ; + + my $z64e = ''; + + if ( *$self->{ZipData}{AnyZip64} ) { + + my $v = *$self->{ZipData}{Version} ; + my $mb = *$self->{ZipData}{MadeBy} ; + $z64e .= pack 'v', $mb ; # Version made by + $z64e .= pack 'v', $v ; # Version to extract + $z64e .= pack 'V', 0 ; # number of disk + $z64e .= pack 'V', 0 ; # number of disk with central dir + $z64e .= U64::pack_V64 $entries ; # entries in central dir on this disk + $z64e .= U64::pack_V64 $entries ; # entries in central dir + $z64e .= U64::pack_V64 $cd_len ; # size of central dir + $z64e .= *$self->{ZipData}{Offset}->getPacked_V64() ; # offset to start central dir + + $z64e = pack("V", ZIP64_END_CENTRAL_REC_HDR_SIG) # signature + . U64::pack_V64(length $z64e) + . $z64e ; + + *$self->{ZipData}{Offset}->add(length $cd) ; + + $z64e .= pack "V", ZIP64_END_CENTRAL_LOC_HDR_SIG; # signature + $z64e .= pack 'V', 0 ; # number of disk with central dir + $z64e .= *$self->{ZipData}{Offset}->getPacked_V64() ; # offset to end zip64 central dir + $z64e .= pack 'V', 1 ; # Total number of disks + + $cd_offset = 0xFFFFFFFF ; + $cd_len = 0xFFFFFFFF if $cd_len >= 0xFFFFFFFF ; + $entries = 0xFFFF if $entries >= 0xFFFF ; + } + + my $ecd = ''; + $ecd .= pack "V", ZIP_END_CENTRAL_HDR_SIG ; # signature + $ecd .= pack 'v', 0 ; # number of disk + $ecd .= pack 'v', 0 ; # number of disk with central dir + $ecd .= pack 'v', $entries ; # entries in central dir on this disk + $ecd .= pack 'v', $entries ; # entries in central dir + $ecd .= pack 'V', $cd_len ; # size of central dir + $ecd .= pack 'V', $cd_offset ; # offset to start central dir + $ecd .= pack 'v', length $comment ; # zipfile comment length + $ecd .= $comment; + + return $cd . $z64e . $ecd ; +} + +sub ckParams +{ + my $self = shift ; + my $got = shift; + + $got->value('CRC32' => 1); + + if (! $got->parsed('Time') ) { + # Modification time defaults to now. + $got->value('Time' => time) ; + } + + if ($got->parsed('exTime') ) { + my $timeRef = $got->value('exTime'); + if ( defined $timeRef) { + return $self->saveErrorString(undef, "exTime not a 3-element array ref") + if ref $timeRef ne 'ARRAY' || @$timeRef != 3; + } + + $got->value("MTime", $timeRef->[1]); + $got->value("ATime", $timeRef->[0]); + $got->value("CTime", $timeRef->[2]); + } + + # Unix2 Extended Attribute + if ($got->parsed('exUnix2') ) { + my $timeRef = $got->value('exUnix2'); + if ( defined $timeRef) { + return $self->saveErrorString(undef, "exUnix2 not a 2-element array ref") + if ref $timeRef ne 'ARRAY' || @$timeRef != 2; + } + + $got->value("UID", $timeRef->[0]); + $got->value("GID", $timeRef->[1]); + } + + *$self->{ZipData}{AnyZip64} = 1 + if $got->value('Zip64'); + *$self->{ZipData}{Zip64} = $got->value('Zip64'); + *$self->{ZipData}{Stream} = $got->value('Stream'); + + my $method = $got->value('Method'); + return $self->saveErrorString(undef, "Unknown Method '$method'") + if ! defined $ZIP_CM_MIN_VERSIONS{$method}; + + return $self->saveErrorString(undef, "Bzip2 not available") + if $method == ZIP_CM_BZIP2 and + ! defined $IO::Compress::Adapter::Bzip2::VERSION; + + return $self->saveErrorString(undef, "Lzma not available") + if $method == ZIP_CM_LZMA ; + #and + #! defined $IO::Compress::Adapter::Lzma::VERSION; + + *$self->{ZipData}{Method} = $method; + + *$self->{ZipData}{ZipComment} = $got->value('ZipComment') ; + + for my $name (qw( ExtraFieldLocal ExtraFieldCentral )) + { + my $data = $got->value($name) ; + if (defined $data) { + my $bad = IO::Compress::Zlib::Extra::parseExtraField($data, 1, 0) ; + return $self->saveErrorString(undef, "Error with $name Parameter: $bad") + if $bad ; + + $got->value($name, $data) ; + } + } + + return undef + if defined $IO::Compress::Bzip2::VERSION + and ! IO::Compress::Bzip2::ckParams($self, $got); + + return 1 ; +} + +#sub newHeader +#{ +# my $self = shift ; +# +# return $self->mkHeader(*$self->{Got}); +#} + +sub getExtraParams +{ + my $self = shift ; + + use IO::Compress::Base::Common 2.024 qw(:Parse); + use Compress::Raw::Zlib 2.024 qw(Z_DEFLATED Z_DEFAULT_COMPRESSION Z_DEFAULT_STRATEGY); + + my @Bzip2 = (); + + @Bzip2 = IO::Compress::Bzip2::getExtraParams($self) + if defined $IO::Compress::Bzip2::VERSION; + + return ( + # zlib behaviour + $self->getZlibParams(), + + 'Stream' => [1, 1, Parse_boolean, 1], + #'Store' => [0, 1, Parse_boolean, 0], + 'Method' => [0, 1, Parse_unsigned, ZIP_CM_DEFLATE], + +# # Zip header fields + 'Minimal' => [0, 1, Parse_boolean, 0], + 'Zip64' => [0, 1, Parse_boolean, 0], + 'Comment' => [0, 1, Parse_any, ''], + 'ZipComment'=> [0, 1, Parse_any, ''], + 'Name' => [0, 1, Parse_any, ''], + 'Time' => [0, 1, Parse_any, undef], + 'exTime' => [0, 1, Parse_any, undef], + 'exUnix2' => [0, 1, Parse_any, undef], + 'ExtAttr' => [0, 1, Parse_any, 0], + 'OS_Code' => [0, 1, Parse_unsigned, $Compress::Raw::Zlib::gzip_os_code], + + 'TextFlag' => [0, 1, Parse_boolean, 0], + 'ExtraFieldLocal' => [0, 1, Parse_any, undef], + 'ExtraFieldCentral'=> [0, 1, Parse_any, undef], + + @Bzip2, + ); +} + +sub getInverseClass +{ + return ('IO::Uncompress::Unzip', + \$IO::Uncompress::Unzip::UnzipError); +} + +sub getFileInfo +{ + my $self = shift ; + my $params = shift; + my $filename = shift ; + + my ($mode, $uid, $gid, $atime, $mtime, $ctime) + = (stat($filename))[2, 4,5, 8,9,10] ; + + $params->value('Name' => $filename) + if ! $params->parsed('Name') ; + + $params->value('Time' => $mtime) + if ! $params->parsed('Time') ; + + if ( ! $params->parsed('exTime')) + { + $params->value('MTime' => $mtime) ; + $params->value('ATime' => $atime) ; + $params->value('CTime' => undef) ; # No Creation time + $params->value("exTime", [$mtime, $atime, undef]); + } + + # NOTE - Unix specific code alert + $params->value('ExtAttr' => $mode << 16) + if ! $params->parsed('ExtAttr'); + + $params->value('UID' => $uid) ; + $params->value('GID' => $gid) ; + +} + +sub mkExtendedTime +{ + # order expected is m, a, c + + my $times = ''; + my $bit = 1 ; + my $flags = 0; + + for my $time (@_) + { + if (defined $time) + { + $flags |= $bit; + $times .= pack("V", $time); + } + + $bit <<= 1 ; + } + + return IO::Compress::Zlib::Extra::mkSubField(ZIP_EXTRA_ID_EXT_TIMESTAMP, + pack("C", $flags) . $times); +} + +sub mkUnix2Extra +{ + my $ids = ''; + for my $id (@_) + { + $ids .= pack("v", $id); + } + + return IO::Compress::Zlib::Extra::mkSubField(ZIP_EXTRA_ID_INFO_ZIP_UNIX2, + $ids); +} + + +# from Archive::Zip +sub _unixToDosTime # Archive::Zip::Member +{ + my $time_t = shift; + # TODO - add something to cope with unix time < 1980 + my ( $sec, $min, $hour, $mday, $mon, $year ) = localtime($time_t); + my $dt = 0; + $dt += ( $sec >> 1 ); + $dt += ( $min << 5 ); + $dt += ( $hour << 11 ); + $dt += ( $mday << 16 ); + $dt += ( ( $mon + 1 ) << 21 ); + $dt += ( ( $year - 80 ) << 25 ); + return $dt; +} + +1; + +__END__ + +=head1 NAME + +IO::Compress::Zip - Write zip files/buffers + + + +=head1 SYNOPSIS + + use IO::Compress::Zip qw(zip $ZipError) ; + + my $status = zip $input => $output [,OPTS] + or die "zip failed: $ZipError\n"; + + my $z = new IO::Compress::Zip $output [,OPTS] + or die "zip failed: $ZipError\n"; + + $z->print($string); + $z->printf($format, $string); + $z->write($string); + $z->syswrite($string [, $length, $offset]); + $z->flush(); + $z->tell(); + $z->eof(); + $z->seek($position, $whence); + $z->binmode(); + $z->fileno(); + $z->opened(); + $z->autoflush(); + $z->input_line_number(); + $z->newStream( [OPTS] ); + + $z->deflateParams(); + + $z->close() ; + + $ZipError ; + + # IO::File mode + + print $z $string; + printf $z $format, $string; + tell $z + eof $z + seek $z, $position, $whence + binmode $z + fileno $z + close $z ; + + +=head1 DESCRIPTION + +This module provides a Perl interface that allows writing zip +compressed data to files or buffer. + +The primary purpose of this module is to provide streaming write access to +zip files and buffers. It is not a general-purpose file archiver. If that +is what you want, check out C<Archive::Zip>. + +At present three compression methods are supported by IO::Compress::Zip, +namely Store (no compression at all), Deflate and Bzip2. + +Note that to create Bzip2 content, the module C<IO::Compress::Bzip2> must +be installed. + +For reading zip files/buffers, see the companion module +L<IO::Uncompress::Unzip|IO::Uncompress::Unzip>. + +=head1 Functional Interface + +A top-level function, C<zip>, is provided to carry out +"one-shot" compression between buffers and/or files. For finer +control over the compression process, see the L</"OO Interface"> +section. + + use IO::Compress::Zip qw(zip $ZipError) ; + + zip $input => $output [,OPTS] + or die "zip failed: $ZipError\n"; + +The functional interface needs Perl5.005 or better. + +=head2 zip $input => $output [, OPTS] + +C<zip> expects at least two parameters, C<$input> and C<$output>. + +=head3 The C<$input> parameter + +The parameter, C<$input>, is used to define the source of +the uncompressed data. + +It can take one of the following forms: + +=over 5 + +=item A filename + +If the C<$input> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for reading and the input data +will be read from it. + +=item A filehandle + +If the C<$input> parameter is a filehandle, the input data will be +read from it. +The string '-' can be used as an alias for standard input. + +=item A scalar reference + +If C<$input> is a scalar reference, the input data will be read +from C<$$input>. + +=item An array reference + +If C<$input> is an array reference, each element in the array must be a +filename. + +The input data will be read from each file in turn. + +The complete array will be walked to ensure that it only +contains valid filenames before any data is compressed. + +=item An Input FileGlob string + +If C<$input> is a string that is delimited by the characters "<" and ">" +C<zip> will assume that it is an I<input fileglob string>. The +input is the list of files that match the fileglob. + +If the fileglob does not match any files ... + +See L<File::GlobMapper|File::GlobMapper> for more details. + +=back + +If the C<$input> parameter is any other type, C<undef> will be returned. + +In addition, if C<$input> is a simple filename, the default values for +the C<Name>, C<Time>, C<ExtAttr> and C<exTime> options will be sourced from that file. + +If you do not want to use these defaults they can be overridden by +explicitly setting the C<Name>, C<Time>, C<ExtAttr> and C<exTime> options or by setting the +C<Minimal> parameter. + +=head3 The C<$output> parameter + +The parameter C<$output> is used to control the destination of the +compressed data. This parameter can take one of these forms. + +=over 5 + +=item A filename + +If the C<$output> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for writing and the compressed +data will be written to it. + +=item A filehandle + +If the C<$output> parameter is a filehandle, the compressed data +will be written to it. +The string '-' can be used as an alias for standard output. + +=item A scalar reference + +If C<$output> is a scalar reference, the compressed data will be +stored in C<$$output>. + +=item An Array Reference + +If C<$output> is an array reference, the compressed data will be +pushed onto the array. + +=item An Output FileGlob + +If C<$output> is a string that is delimited by the characters "<" and ">" +C<zip> will assume that it is an I<output fileglob string>. The +output is the list of files that match the fileglob. + +When C<$output> is an fileglob string, C<$input> must also be a fileglob +string. Anything else is an error. + +=back + +If the C<$output> parameter is any other type, C<undef> will be returned. + +=head2 Notes + +When C<$input> maps to multiple files/buffers and C<$output> is a single +file/buffer the input files/buffers will each be stored +in C<$output> as a distinct entry. + +=head2 Optional Parameters + +Unless specified below, the optional parameters for C<zip>, +C<OPTS>, are the same as those used with the OO interface defined in the +L</"Constructor Options"> section below. + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option applies to any input or output data streams to +C<zip> that are filehandles. + +If C<AutoClose> is specified, and the value is true, it will result in all +input and/or output filehandles being closed once C<zip> has +completed. + +This parameter defaults to 0. + +=item C<< BinModeIn => 0|1 >> + +When reading from a file or filehandle, set C<binmode> before reading. + +Defaults to 0. + +=item C<< Append => 0|1 >> + +The behaviour of this option is dependent on the type of output data +stream. + +=over 5 + +=item * A Buffer + +If C<Append> is enabled, all compressed data will be append to the end of +the output buffer. Otherwise the output buffer will be cleared before any +compressed data is written to it. + +=item * A Filename + +If C<Append> is enabled, the file will be opened in append mode. Otherwise +the contents of the file, if any, will be truncated before any compressed +data is written to it. + +=item * A Filehandle + +If C<Append> is enabled, the filehandle will be positioned to the end of +the file via a call to C<seek> before any compressed data is +written to it. Otherwise the file pointer will not be moved. + +=back + +When C<Append> is specified, and set to true, it will I<append> all compressed +data to the output data stream. + +So when the output is a filehandle it will carry out a seek to the eof +before writing any compressed data. If the output is a filename, it will be opened for +appending. If the output is a buffer, all compressed data will be appened to +the existing buffer. + +Conversely when C<Append> is not specified, or it is present and is set to +false, it will operate as follows. + +When the output is a filename, it will truncate the contents of the file +before writing any compressed data. If the output is a filehandle +its position will not be changed. If the output is a buffer, it will be +wiped before any compressed data is output. + +Defaults to 0. + +=back + +=head2 Examples + +To read the contents of the file C<file1.txt> and write the compressed +data to the file C<file1.txt.zip>. + + use strict ; + use warnings ; + use IO::Compress::Zip qw(zip $ZipError) ; + + my $input = "file1.txt"; + zip $input => "$input.zip" + or die "zip failed: $ZipError\n"; + +To read from an existing Perl filehandle, C<$input>, and write the +compressed data to a buffer, C<$buffer>. + + use strict ; + use warnings ; + use IO::Compress::Zip qw(zip $ZipError) ; + use IO::File ; + + my $input = new IO::File "<file1.txt" + or die "Cannot open 'file1.txt': $!\n" ; + my $buffer ; + zip $input => \$buffer + or die "zip failed: $ZipError\n"; + +To compress all files in the directory "/my/home" that match "*.txt" +and store the compressed data in the same directory + + use strict ; + use warnings ; + use IO::Compress::Zip qw(zip $ZipError) ; + + zip '</my/home/*.txt>' => '<*.zip>' + or die "zip failed: $ZipError\n"; + +and if you want to compress each file one at a time, this will do the trick + + use strict ; + use warnings ; + use IO::Compress::Zip qw(zip $ZipError) ; + + for my $input ( glob "/my/home/*.txt" ) + { + my $output = "$input.zip" ; + zip $input => $output + or die "Error compressing '$input': $ZipError\n"; + } + +=head1 OO Interface + +=head2 Constructor + +The format of the constructor for C<IO::Compress::Zip> is shown below + + my $z = new IO::Compress::Zip $output [,OPTS] + or die "IO::Compress::Zip failed: $ZipError\n"; + +It returns an C<IO::Compress::Zip> object on success and undef on failure. +The variable C<$ZipError> will contain an error message on failure. + +If you are running Perl 5.005 or better the object, C<$z>, returned from +IO::Compress::Zip can be used exactly like an L<IO::File|IO::File> filehandle. +This means that all normal output file operations can be carried out +with C<$z>. +For example, to write to a compressed file/buffer you can use either of +these forms + + $z->print("hello world\n"); + print $z "hello world\n"; + +The mandatory parameter C<$output> is used to control the destination +of the compressed data. This parameter can take one of these forms. + +=over 5 + +=item A filename + +If the C<$output> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for writing and the compressed data +will be written to it. + +=item A filehandle + +If the C<$output> parameter is a filehandle, the compressed data will be +written to it. +The string '-' can be used as an alias for standard output. + +=item A scalar reference + +If C<$output> is a scalar reference, the compressed data will be stored +in C<$$output>. + +=back + +If the C<$output> parameter is any other type, C<IO::Compress::Zip>::new will +return undef. + +=head2 Constructor Options + +C<OPTS> is any combination of the following options: + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option is only valid when the C<$output> parameter is a filehandle. If +specified, and the value is true, it will result in the C<$output> being +closed once either the C<close> method is called or the C<IO::Compress::Zip> +object is destroyed. + +This parameter defaults to 0. + +=item C<< Append => 0|1 >> + +Opens C<$output> in append mode. + +The behaviour of this option is dependent on the type of C<$output>. + +=over 5 + +=item * A Buffer + +If C<$output> is a buffer and C<Append> is enabled, all compressed data +will be append to the end of C<$output>. Otherwise C<$output> will be +cleared before any data is written to it. + +=item * A Filename + +If C<$output> is a filename and C<Append> is enabled, the file will be +opened in append mode. Otherwise the contents of the file, if any, will be +truncated before any compressed data is written to it. + +=item * A Filehandle + +If C<$output> is a filehandle, the file pointer will be positioned to the +end of the file via a call to C<seek> before any compressed data is written +to it. Otherwise the file pointer will not be moved. + +=back + +This parameter defaults to 0. + +=item C<< Name => $string >> + +Stores the contents of C<$string> in the zip filename header field. If +C<Name> is not specified, no zip filename field will be created. + +=item C<< Time => $number >> + +Sets the last modified time field in the zip header to $number. + +This field defaults to the time the C<IO::Compress::Zip> object was created +if this option is not specified. + +=item C<< ExtAttr => $attr >> + +This option controls the "external file attributes" field in the central +header of the zip file. This is a 4 byte field. + +If you are running a Unix derivative this value defaults to + + 0666 << 16 + +This should allow read/write access to any files that are extracted from +the zip file/buffer. + +For all other systems it defaults to 0. + +=item C<< exTime => [$atime, $mtime, $ctime] >> + +This option expects an array reference with exactly three elements: +C<$atime>, C<mtime> and C<$ctime>. These correspond to the last access +time, last modification time and creation time respectively. + +It uses these values to set the extended timestamp field (ID is "UT") in +the local zip header using the three values, $atime, $mtime, $ctime. In +addition it sets the extended timestamp field in the central zip header +using C<$mtime>. + +If any of the three values is C<undef> that time value will not be used. +So, for example, to set only the C<$mtime> you would use this + + exTime => [undef, $mtime, undef] + +If the C<Minimal> option is set to true, this option will be ignored. + +By default no extended time field is created. + +=item C<< exUnix2 => [$uid, $gid] >> + +This option expects an array reference with exactly two elements: C<$uid> +and C<$gid>. These values correspond to the numeric user ID and group ID +of the owner of the files respectively. + +When the C<exUnix2> option is present it will trigger the creation of a +Unix2 extra field (ID is "Ux") in the local zip. This will be populated +with C<$uid> and C<$gid>. In addition an empty Unix2 extra field will also +be created in the central zip header + +If the C<Minimal> option is set to true, this option will be ignored. + +By default no Unix2 extra field is created. + +=item C<< Comment => $comment >> + +Stores the contents of C<$comment> in the Central File Header of +the zip file. + +By default, no comment field is written to the zip file. + +=item C<< ZipComment => $comment >> + +Stores the contents of C<$comment> in the End of Central Directory record +of the zip file. + +By default, no comment field is written to the zip file. + +=item C<< Method => $method >> + +Controls which compression method is used. At present three compression +methods are supported, namely Store (no compression at all), Deflate and +Bzip2. + +The symbols, ZIP_CM_STORE, ZIP_CM_DEFLATE and ZIP_CM_BZIP2 are used to +select the compression method. + +These constants are not imported by C<IO::Compress::Zip> by default. + + use IO::Compress::Zip qw(:zip_method); + use IO::Compress::Zip qw(:constants); + use IO::Compress::Zip qw(:all); + +Note that to create Bzip2 content, the module C<IO::Compress::Bzip2> must +be installed. A fatal error will be thrown if you attempt to create Bzip2 +content when C<IO::Compress::Bzip2> is not available. + +The default method is ZIP_CM_DEFLATE. + +=item C<< Stream => 0|1 >> + +This option controls whether the zip file/buffer output is created in +streaming mode. + +Note that when outputting to a file with streaming mode disabled (C<Stream> +is 0), the output file must be seekable. + +The default is 1. + +=item C<< Zip64 => 0|1 >> + +Create a Zip64 zip file/buffer. This option should only be used if you want +to store files larger than 4 Gig. + +If you intend to manipulate the Zip64 zip files created with this module +using an external zip/unzip make sure that it supports Zip64. + +In particular, if you are using Info-Zip you need to have zip version 3.x +or better to update a Zip64 archive and unzip version 6.x to read a zip64 +archive. + +The default is 0. + +=item C<< TextFlag => 0|1 >> + +This parameter controls the setting of a bit in the zip central header. It +is used to signal that the data stored in the zip file/buffer is probably +text. + +The default is 0. + +=item C<< ExtraFieldLocal => $data >> +=item C<< ExtraFieldCentral => $data >> + +The C<ExtraFieldLocal> option is used to store additional metadata in the +local header for the zip file/buffer. The C<ExtraFieldCentral> does the +same for the matching central header. + +An extra field consists of zero or more subfields. Each subfield consists +of a two byte header followed by the subfield data. + +The list of subfields can be supplied in any of the following formats + + ExtraFieldLocal => [$id1, $data1, + $id2, $data2, + ... + ] + + ExtraFieldLocal => [ [$id1 => $data1], + [$id2 => $data2], + ... + ] + + ExtraFieldLocal => { $id1 => $data1, + $id2 => $data2, + ... + } + +Where C<$id1>, C<$id2> are two byte subfield ID's. + +If you use the hash syntax, you have no control over the order in which +the ExtraSubFields are stored, plus you cannot have SubFields with +duplicate ID. + +Alternatively the list of subfields can by supplied as a scalar, thus + + ExtraField => $rawdata + +The Extended Time field (ID "UT"), set using the C<exTime> option, and the +Unix2 extra field (ID "Ux), set using the C<exUnix2> option, are examples +of extra fields. + +If the C<Minimal> option is set to true, this option will be ignored. + +The maximum size of an extra field 65535 bytes. + +=item C<< Minimal => 1|0 >> + +If specified, this option will disable the creation of all extra fields +in the zip local and central headers. So the C<exTime>, C<exUnix2>, +C<ExtraFieldLocal> and C<ExtraFieldCentral> options will be ignored. + +This parameter defaults to 0. + +=item C<< BlockSize100K => number >> + +Specify the number of 100K blocks bzip2 uses during compression. + +Valid values are from 1 to 9, where 9 is best compression. + +This option is only valid if the C<Method> is ZIP_CM_BZIP2. It is ignored +otherwise. + +The default is 1. + +=item C<< WorkFactor => number >> + +Specifies how much effort bzip2 should take before resorting to a slower +fallback compression algorithm. + +Valid values range from 0 to 250, where 0 means use the default value 30. + +This option is only valid if the C<Method> is ZIP_CM_BZIP2. It is ignored +otherwise. + +The default is 0. + +=item -Level + +Defines the compression level used by zlib. The value should either be +a number between 0 and 9 (0 means no compression and 9 is maximum +compression), or one of the symbolic constants defined below. + + Z_NO_COMPRESSION + Z_BEST_SPEED + Z_BEST_COMPRESSION + Z_DEFAULT_COMPRESSION + +The default is Z_DEFAULT_COMPRESSION. + +Note, these constants are not imported by C<IO::Compress::Zip> by default. + + use IO::Compress::Zip qw(:strategy); + use IO::Compress::Zip qw(:constants); + use IO::Compress::Zip qw(:all); + +=item -Strategy + +Defines the strategy used to tune the compression. Use one of the symbolic +constants defined below. + + Z_FILTERED + Z_HUFFMAN_ONLY + Z_RLE + Z_FIXED + Z_DEFAULT_STRATEGY + +The default is Z_DEFAULT_STRATEGY. + +=item C<< Strict => 0|1 >> + +This is a placeholder option. + +=back + +=head2 Examples + +TODO + +=head1 Methods + +=head2 print + +Usage is + + $z->print($data) + print $z $data + +Compresses and outputs the contents of the C<$data> parameter. This +has the same behaviour as the C<print> built-in. + +Returns true if successful. + +=head2 printf + +Usage is + + $z->printf($format, $data) + printf $z $format, $data + +Compresses and outputs the contents of the C<$data> parameter. + +Returns true if successful. + +=head2 syswrite + +Usage is + + $z->syswrite $data + $z->syswrite $data, $length + $z->syswrite $data, $length, $offset + +Compresses and outputs the contents of the C<$data> parameter. + +Returns the number of uncompressed bytes written, or C<undef> if +unsuccessful. + +=head2 write + +Usage is + + $z->write $data + $z->write $data, $length + $z->write $data, $length, $offset + +Compresses and outputs the contents of the C<$data> parameter. + +Returns the number of uncompressed bytes written, or C<undef> if +unsuccessful. + +=head2 flush + +Usage is + + $z->flush; + $z->flush($flush_type); + +Flushes any pending compressed data to the output file/buffer. + +This method takes an optional parameter, C<$flush_type>, that controls +how the flushing will be carried out. By default the C<$flush_type> +used is C<Z_FINISH>. Other valid values for C<$flush_type> are +C<Z_NO_FLUSH>, C<Z_SYNC_FLUSH>, C<Z_FULL_FLUSH> and C<Z_BLOCK>. It is +strongly recommended that you only set the C<flush_type> parameter if +you fully understand the implications of what it does - overuse of C<flush> +can seriously degrade the level of compression achieved. See the C<zlib> +documentation for details. + +Returns true on success. + +=head2 tell + +Usage is + + $z->tell() + tell $z + +Returns the uncompressed file offset. + +=head2 eof + +Usage is + + $z->eof(); + eof($z); + +Returns true if the C<close> method has been called. + +=head2 seek + + $z->seek($position, $whence); + seek($z, $position, $whence); + +Provides a sub-set of the C<seek> functionality, with the restriction +that it is only legal to seek forward in the output file/buffer. +It is a fatal error to attempt to seek backward. + +Empty parts of the file/buffer will have NULL (0x00) bytes written to them. + +The C<$whence> parameter takes one the usual values, namely SEEK_SET, +SEEK_CUR or SEEK_END. + +Returns 1 on success, 0 on failure. + +=head2 binmode + +Usage is + + $z->binmode + binmode $z ; + +This is a noop provided for completeness. + +=head2 opened + + $z->opened() + +Returns true if the object currently refers to a opened file/buffer. + +=head2 autoflush + + my $prev = $z->autoflush() + my $prev = $z->autoflush(EXPR) + +If the C<$z> object is associated with a file or a filehandle, this method +returns the current autoflush setting for the underlying filehandle. If +C<EXPR> is present, and is non-zero, it will enable flushing after every +write/print operation. + +If C<$z> is associated with a buffer, this method has no effect and always +returns C<undef>. + +B<Note> that the special variable C<$|> B<cannot> be used to set or +retrieve the autoflush setting. + +=head2 input_line_number + + $z->input_line_number() + $z->input_line_number(EXPR) + +This method always returns C<undef> when compressing. + +=head2 fileno + + $z->fileno() + fileno($z) + +If the C<$z> object is associated with a file or a filehandle, C<fileno> +will return the underlying file descriptor. Once the C<close> method is +called C<fileno> will return C<undef>. + +If the C<$z> object is is associated with a buffer, this method will return +C<undef>. + +=head2 close + + $z->close() ; + close $z ; + +Flushes any pending compressed data and then closes the output file/buffer. + +For most versions of Perl this method will be automatically invoked if +the IO::Compress::Zip object is destroyed (either explicitly or by the +variable with the reference to the object going out of scope). The +exceptions are Perl versions 5.005 through 5.00504 and 5.8.0. In +these cases, the C<close> method will be called automatically, but +not until global destruction of all live objects when the program is +terminating. + +Therefore, if you want your scripts to be able to run on all versions +of Perl, you should call C<close> explicitly and not rely on automatic +closing. + +Returns true on success, otherwise 0. + +If the C<AutoClose> option has been enabled when the IO::Compress::Zip +object was created, and the object is associated with a file, the +underlying file will also be closed. + +=head2 newStream([OPTS]) + +Usage is + + $z->newStream( [OPTS] ) + +Closes the current compressed data stream and starts a new one. + +OPTS consists of any of the the options that are available when creating +the C<$z> object. + +See the L</"Constructor Options"> section for more details. + +=head2 deflateParams + +Usage is + + $z->deflateParams + +TODO + +=head1 Importing + +A number of symbolic constants are required by some methods in +C<IO::Compress::Zip>. None are imported by default. + +=over 5 + +=item :all + +Imports C<zip>, C<$ZipError> and all symbolic +constants that can be used by C<IO::Compress::Zip>. Same as doing this + + use IO::Compress::Zip qw(zip $ZipError :constants) ; + +=item :constants + +Import all symbolic constants. Same as doing this + + use IO::Compress::Zip qw(:flush :level :strategy :zip_method) ; + +=item :flush + +These symbolic constants are used by the C<flush> method. + + Z_NO_FLUSH + Z_PARTIAL_FLUSH + Z_SYNC_FLUSH + Z_FULL_FLUSH + Z_FINISH + Z_BLOCK + +=item :level + +These symbolic constants are used by the C<Level> option in the constructor. + + Z_NO_COMPRESSION + Z_BEST_SPEED + Z_BEST_COMPRESSION + Z_DEFAULT_COMPRESSION + +=item :strategy + +These symbolic constants are used by the C<Strategy> option in the constructor. + + Z_FILTERED + Z_HUFFMAN_ONLY + Z_RLE + Z_FIXED + Z_DEFAULT_STRATEGY + +=item :zip_method + +These symbolic constants are used by the C<Method> option in the +constructor. + + ZIP_CM_STORE + ZIP_CM_DEFLATE + ZIP_CM_BZIP2 + + + + +=back + +=head1 EXAMPLES + +=head2 Apache::GZip Revisited + +See L<IO::Compress::FAQ|IO::Compress::FAQ/"Apache::GZip Revisited"> + + + +=head2 Working with Net::FTP + +See L<IO::Compress::FAQ|IO::Compress::FAQ/"Compressed files and Net::FTP"> + +=head1 SEE ALSO + +L<Compress::Zlib>, L<IO::Compress::Gzip>, L<IO::Uncompress::Gunzip>, L<IO::Compress::Deflate>, L<IO::Uncompress::Inflate>, L<IO::Compress::RawDeflate>, L<IO::Uncompress::RawInflate>, L<IO::Compress::Bzip2>, L<IO::Uncompress::Bunzip2>, L<IO::Compress::Lzma>, L<IO::Uncompress::UnLzma>, L<IO::Compress::Xz>, L<IO::Uncompress::UnXz>, L<IO::Compress::Lzop>, L<IO::Uncompress::UnLzop>, L<IO::Compress::Lzf>, L<IO::Uncompress::UnLzf>, L<IO::Uncompress::AnyInflate>, L<IO::Uncompress::AnyUncompress> + +L<Compress::Zlib::FAQ|Compress::Zlib::FAQ> + +L<File::GlobMapper|File::GlobMapper>, L<Archive::Zip|Archive::Zip>, +L<Archive::Tar|Archive::Tar>, +L<IO::Zlib|IO::Zlib> + +For RFC 1950, 1951 and 1952 see +F<http://www.faqs.org/rfcs/rfc1950.html>, +F<http://www.faqs.org/rfcs/rfc1951.html> and +F<http://www.faqs.org/rfcs/rfc1952.html> + +The I<zlib> compression library was written by Jean-loup Gailly +F<gzip@prep.ai.mit.edu> and Mark Adler F<madler@alumni.caltech.edu>. + +The primary site for the I<zlib> compression library is +F<http://www.zlib.org>. + +The primary site for gzip is F<http://www.gzip.org>. + +=head1 AUTHOR + +This module was written by Paul Marquess, F<pmqs@cpan.org>. + +=head1 MODIFICATION HISTORY + +See the Changes file. + +=head1 COPYRIGHT AND LICENSE + +Copyright (c) 2005-2010 Paul Marquess. All rights reserved. + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + diff --git a/Master/tlpkg/tlperl/lib/IO/Compress/Zip/Constants.pm b/Master/tlpkg/tlperl/lib/IO/Compress/Zip/Constants.pm new file mode 100644 index 00000000000..c8cb95342a2 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Compress/Zip/Constants.pm @@ -0,0 +1,105 @@ +package IO::Compress::Zip::Constants; + +use strict ; +use warnings; + +require Exporter; + +our ($VERSION, @ISA, @EXPORT, %ZIP_CM_MIN_VERSIONS); + +$VERSION = '2.024'; + +@ISA = qw(Exporter); + +@EXPORT= qw( + + ZIP_CM_STORE + ZIP_CM_DEFLATE + ZIP_CM_BZIP2 + ZIP_CM_LZMA + ZIP_CM_PPMD + + ZIP_LOCAL_HDR_SIG + ZIP_DATA_HDR_SIG + ZIP_CENTRAL_HDR_SIG + ZIP_END_CENTRAL_HDR_SIG + ZIP64_END_CENTRAL_REC_HDR_SIG + ZIP64_END_CENTRAL_LOC_HDR_SIG + ZIP64_ARCHIVE_EXTRA_SIG + ZIP64_DIGITAL_SIGNATURE_SIG + + ZIP_GP_FLAG_ENCRYPTED_MASK + ZIP_GP_FLAG_STREAMING_MASK + ZIP_GP_FLAG_PATCHED_MASK + ZIP_GP_FLAG_STRONG_ENCRYPTED_MASK + ZIP_GP_FLAG_LZMA_EOS_PRESENT + ZIP_GP_FLAG_LANGUAGE_ENCODING + + ZIP_EXTRA_ID_ZIP64 + ZIP_EXTRA_ID_EXT_TIMESTAMP + ZIP_EXTRA_ID_INFO_ZIP_UNIX2 + ZIP_EXTRA_ID_INFO_ZIP_UNIXn + ZIP_EXTRA_ID_JAVA_EXE + + ZIP_OS_CODE_UNIX + ZIP_OS_CODE_DEFAULT + + ZIP_IFA_TEXT_MASK + + %ZIP_CM_MIN_VERSIONS + ZIP64_MIN_VERSION + + ); + +# Compression types supported +use constant ZIP_CM_STORE => 0 ; +use constant ZIP_CM_DEFLATE => 8 ; +use constant ZIP_CM_BZIP2 => 12 ; +use constant ZIP_CM_LZMA => 14 ; # Not Supported yet +use constant ZIP_CM_PPMD => 98 ; # Not Supported yet + +# General Purpose Flag +use constant ZIP_GP_FLAG_ENCRYPTED_MASK => (1 << 0) ; +use constant ZIP_GP_FLAG_STREAMING_MASK => (1 << 3) ; +use constant ZIP_GP_FLAG_PATCHED_MASK => (1 << 5) ; +use constant ZIP_GP_FLAG_STRONG_ENCRYPTED_MASK => (1 << 6) ; +use constant ZIP_GP_FLAG_LZMA_EOS_PRESENT => (1 << 1) ; +use constant ZIP_GP_FLAG_LANGUAGE_ENCODING => (1 << 11) ; + +# Internal File Attributes +use constant ZIP_IFA_TEXT_MASK => 1; + +# Signatures for each of the headers +use constant ZIP_LOCAL_HDR_SIG => 0x04034b50; +use constant ZIP_DATA_HDR_SIG => 0x08074b50; +use constant ZIP_CENTRAL_HDR_SIG => 0x02014b50; +use constant ZIP_END_CENTRAL_HDR_SIG => 0x06054b50; +use constant ZIP64_END_CENTRAL_REC_HDR_SIG => 0x06064b50; +use constant ZIP64_END_CENTRAL_LOC_HDR_SIG => 0x07064b50; +use constant ZIP64_ARCHIVE_EXTRA_SIG => 0x08064b50; +use constant ZIP64_DIGITAL_SIGNATURE_SIG => 0x05054b50; + +use constant ZIP_OS_CODE_UNIX => 3; +use constant ZIP_OS_CODE_DEFAULT => 3; + +# Extra Field ID's +use constant ZIP_EXTRA_ID_ZIP64 => pack "v", 1; +use constant ZIP_EXTRA_ID_EXT_TIMESTAMP => "UT"; +use constant ZIP_EXTRA_ID_INFO_ZIP_UNIX2 => "Ux"; +use constant ZIP_EXTRA_ID_INFO_ZIP_UNIXn => "ux"; +use constant ZIP_EXTRA_ID_JAVA_EXE => pack "v", 0xCAFE; + +use constant ZIP64_MIN_VERSION => 45; + +%ZIP_CM_MIN_VERSIONS = ( + ZIP_CM_STORE() => 20, + ZIP_CM_DEFLATE() => 20, + ZIP_CM_BZIP2() => 46, + ZIP_CM_LZMA() => 63, + ); + + +1; + +__END__ + diff --git a/Master/tlpkg/tlperl/lib/IO/Compress/Zlib/Constants.pm b/Master/tlpkg/tlperl/lib/IO/Compress/Zlib/Constants.pm new file mode 100644 index 00000000000..10fcf345f63 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Compress/Zlib/Constants.pm @@ -0,0 +1,77 @@ + +package IO::Compress::Zlib::Constants ; + +use strict ; +use warnings; +use bytes; + +require Exporter; + +our ($VERSION, @ISA, @EXPORT); + +$VERSION = '2.024'; + +@ISA = qw(Exporter); + +@EXPORT= qw( + + ZLIB_HEADER_SIZE + ZLIB_TRAILER_SIZE + + ZLIB_CMF_CM_OFFSET + ZLIB_CMF_CM_BITS + ZLIB_CMF_CM_DEFLATED + + ZLIB_CMF_CINFO_OFFSET + ZLIB_CMF_CINFO_BITS + ZLIB_CMF_CINFO_MAX + + ZLIB_FLG_FCHECK_OFFSET + ZLIB_FLG_FCHECK_BITS + + ZLIB_FLG_FDICT_OFFSET + ZLIB_FLG_FDICT_BITS + + ZLIB_FLG_LEVEL_OFFSET + ZLIB_FLG_LEVEL_BITS + + ZLIB_FLG_LEVEL_FASTEST + ZLIB_FLG_LEVEL_FAST + ZLIB_FLG_LEVEL_DEFAULT + ZLIB_FLG_LEVEL_SLOWEST + + ZLIB_FDICT_SIZE + + ); + +# Constant names derived from RFC1950 + +use constant ZLIB_HEADER_SIZE => 2; +use constant ZLIB_TRAILER_SIZE => 4; + +use constant ZLIB_CMF_CM_OFFSET => 0; +use constant ZLIB_CMF_CM_BITS => 0xF ; # 0b1111 +use constant ZLIB_CMF_CM_DEFLATED => 8; + +use constant ZLIB_CMF_CINFO_OFFSET => 4; +use constant ZLIB_CMF_CINFO_BITS => 0xF ; # 0b1111; +use constant ZLIB_CMF_CINFO_MAX => 7; + +use constant ZLIB_FLG_FCHECK_OFFSET => 0; +use constant ZLIB_FLG_FCHECK_BITS => 0x1F ; # 0b11111; + +use constant ZLIB_FLG_FDICT_OFFSET => 5; +use constant ZLIB_FLG_FDICT_BITS => 0x1 ; # 0b1; + +use constant ZLIB_FLG_LEVEL_OFFSET => 6; +use constant ZLIB_FLG_LEVEL_BITS => 0x3 ; # 0b11; + +use constant ZLIB_FLG_LEVEL_FASTEST => 0; +use constant ZLIB_FLG_LEVEL_FAST => 1; +use constant ZLIB_FLG_LEVEL_DEFAULT => 2; +use constant ZLIB_FLG_LEVEL_SLOWEST => 3; + +use constant ZLIB_FDICT_SIZE => 4; + + +1; diff --git a/Master/tlpkg/tlperl/lib/IO/Compress/Zlib/Extra.pm b/Master/tlpkg/tlperl/lib/IO/Compress/Zlib/Extra.pm new file mode 100644 index 00000000000..6812bb409dc --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Compress/Zlib/Extra.pm @@ -0,0 +1,198 @@ +package IO::Compress::Zlib::Extra; + +require 5.004 ; + +use strict ; +use warnings; +use bytes; + +our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS); + +$VERSION = '2.024'; + +use IO::Compress::Gzip::Constants 2.024 ; + +sub ExtraFieldError +{ + return $_[0]; + return "Error with ExtraField Parameter: $_[0]" ; +} + +sub validateExtraFieldPair +{ + my $pair = shift ; + my $strict = shift; + my $gzipMode = shift ; + + return ExtraFieldError("Not an array ref") + unless ref $pair && ref $pair eq 'ARRAY'; + + return ExtraFieldError("SubField must have two parts") + unless @$pair == 2 ; + + return ExtraFieldError("SubField ID is a reference") + if ref $pair->[0] ; + + return ExtraFieldError("SubField Data is a reference") + if ref $pair->[1] ; + + # ID is exactly two chars + return ExtraFieldError("SubField ID not two chars long") + unless length $pair->[0] == GZIP_FEXTRA_SUBFIELD_ID_SIZE ; + + # Check that the 2nd byte of the ID isn't 0 + return ExtraFieldError("SubField ID 2nd byte is 0x00") + if $strict && $gzipMode && substr($pair->[0], 1, 1) eq "\x00" ; + + return ExtraFieldError("SubField Data too long") + if length $pair->[1] > GZIP_FEXTRA_SUBFIELD_MAX_SIZE ; + + + return undef ; +} + +sub parseRawExtra +{ + my $data = shift ; + my $extraRef = shift; + my $strict = shift; + my $gzipMode = shift ; + + #my $lax = shift ; + + #return undef + # if $lax ; + + my $XLEN = length $data ; + + return ExtraFieldError("Too Large") + if $XLEN > GZIP_FEXTRA_MAX_SIZE; + + my $offset = 0 ; + while ($offset < $XLEN) { + + return ExtraFieldError("Truncated in FEXTRA Body Section") + if $offset + GZIP_FEXTRA_SUBFIELD_HEADER_SIZE > $XLEN ; + + my $id = substr($data, $offset, GZIP_FEXTRA_SUBFIELD_ID_SIZE); + $offset += GZIP_FEXTRA_SUBFIELD_ID_SIZE; + + my $subLen = unpack("v", substr($data, $offset, + GZIP_FEXTRA_SUBFIELD_LEN_SIZE)); + $offset += GZIP_FEXTRA_SUBFIELD_LEN_SIZE ; + + return ExtraFieldError("Truncated in FEXTRA Body Section") + if $offset + $subLen > $XLEN ; + + my $bad = validateExtraFieldPair( [$id, + substr($data, $offset, $subLen)], + $strict, $gzipMode ); + return $bad if $bad ; + push @$extraRef, [$id => substr($data, $offset, $subLen)] + if defined $extraRef;; + + $offset += $subLen ; + } + + + return undef ; +} + + +sub mkSubField +{ + my $id = shift ; + my $data = shift ; + + return $id . pack("v", length $data) . $data ; +} + +sub parseExtraField +{ + my $dataRef = $_[0]; + my $strict = $_[1]; + my $gzipMode = $_[2]; + #my $lax = @_ == 2 ? $_[1] : 1; + + + # ExtraField can be any of + # + # -ExtraField => $data + # + # -ExtraField => [$id1, $data1, + # $id2, $data2] + # ... + # ] + # + # -ExtraField => [ [$id1 => $data1], + # [$id2 => $data2], + # ... + # ] + # + # -ExtraField => { $id1 => $data1, + # $id2 => $data2, + # ... + # } + + if ( ! ref $dataRef ) { + + return undef + if ! $strict; + + return parseRawExtra($dataRef, undef, 1, $gzipMode); + } + + #my $data = $$dataRef; + my $data = $dataRef; + my $out = '' ; + + if (ref $data eq 'ARRAY') { + if (ref $data->[0]) { + + foreach my $pair (@$data) { + return ExtraFieldError("Not list of lists") + unless ref $pair eq 'ARRAY' ; + + my $bad = validateExtraFieldPair($pair, $strict, $gzipMode) ; + return $bad if $bad ; + + $out .= mkSubField(@$pair); + } + } + else { + return ExtraFieldError("Not even number of elements") + unless @$data % 2 == 0; + + for (my $ix = 0; $ix <= length(@$data) -1 ; $ix += 2) { + my $bad = validateExtraFieldPair([$data->[$ix], + $data->[$ix+1]], + $strict, $gzipMode) ; + return $bad if $bad ; + + $out .= mkSubField($data->[$ix], $data->[$ix+1]); + } + } + } + elsif (ref $data eq 'HASH') { + while (my ($id, $info) = each %$data) { + my $bad = validateExtraFieldPair([$id, $info], $strict, $gzipMode); + return $bad if $bad ; + + $out .= mkSubField($id, $info); + } + } + else { + return ExtraFieldError("Not a scalar, array ref or hash ref") ; + } + + return ExtraFieldError("Too Large") + if length $out > GZIP_FEXTRA_MAX_SIZE; + + $_[0] = $out ; + + return undef; +} + +1; + +__END__ diff --git a/Master/tlpkg/tlperl/lib/IO/Dir.pm b/Master/tlpkg/tlperl/lib/IO/Dir.pm new file mode 100644 index 00000000000..cce392c2ce3 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Dir.pm @@ -0,0 +1,248 @@ +# IO::Dir.pm +# +# Copyright (c) 1997-8 Graham Barr <gbarr@pobox.com>. All rights reserved. +# This program is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. + +package IO::Dir; + +use 5.006; + +use strict; +use Carp; +use Symbol; +use Exporter; +use IO::File; +our(@ISA, $VERSION, @EXPORT_OK); +use Tie::Hash; +use File::stat; +use File::Spec; + +@ISA = qw(Tie::Hash Exporter); +$VERSION = "1.07"; +$VERSION = eval $VERSION; +@EXPORT_OK = qw(DIR_UNLINK); + +sub DIR_UNLINK () { 1 } + +sub new { + @_ >= 1 && @_ <= 2 or croak 'usage: new IO::Dir [DIRNAME]'; + my $class = shift; + my $dh = gensym; + if (@_) { + IO::Dir::open($dh, $_[0]) + or return undef; + } + bless $dh, $class; +} + +sub DESTROY { + my ($dh) = @_; + local($., $@, $!, $^E, $?); + no warnings 'io'; + closedir($dh); +} + +sub open { + @_ == 2 or croak 'usage: $dh->open(DIRNAME)'; + my ($dh, $dirname) = @_; + return undef + unless opendir($dh, $dirname); + # a dir name should always have a ":" in it; assume dirname is + # in current directory + $dirname = ':' . $dirname if ( ($^O eq 'MacOS') && ($dirname !~ /:/) ); + ${*$dh}{io_dir_path} = $dirname; + 1; +} + +sub close { + @_ == 1 or croak 'usage: $dh->close()'; + my ($dh) = @_; + closedir($dh); +} + +sub read { + @_ == 1 or croak 'usage: $dh->read()'; + my ($dh) = @_; + readdir($dh); +} + +sub seek { + @_ == 2 or croak 'usage: $dh->seek(POS)'; + my ($dh,$pos) = @_; + seekdir($dh,$pos); +} + +sub tell { + @_ == 1 or croak 'usage: $dh->tell()'; + my ($dh) = @_; + telldir($dh); +} + +sub rewind { + @_ == 1 or croak 'usage: $dh->rewind()'; + my ($dh) = @_; + rewinddir($dh); +} + +sub TIEHASH { + my($class,$dir,$options) = @_; + + my $dh = $class->new($dir) + or return undef; + + $options ||= 0; + + ${*$dh}{io_dir_unlink} = $options & DIR_UNLINK; + $dh; +} + +sub FIRSTKEY { + my($dh) = @_; + $dh->rewind; + scalar $dh->read; +} + +sub NEXTKEY { + my($dh) = @_; + scalar $dh->read; +} + +sub EXISTS { + my($dh,$key) = @_; + -e File::Spec->catfile(${*$dh}{io_dir_path}, $key); +} + +sub FETCH { + my($dh,$key) = @_; + &lstat(File::Spec->catfile(${*$dh}{io_dir_path}, $key)); +} + +sub STORE { + my($dh,$key,$data) = @_; + my($atime,$mtime) = ref($data) ? @$data : ($data,$data); + my $file = File::Spec->catfile(${*$dh}{io_dir_path}, $key); + unless(-e $file) { + my $io = IO::File->new($file,O_CREAT | O_RDWR); + $io->close if $io; + } + utime($atime,$mtime, $file); +} + +sub DELETE { + my($dh,$key) = @_; + + # Only unlink if unlink-ing is enabled + return 0 + unless ${*$dh}{io_dir_unlink}; + + my $file = File::Spec->catfile(${*$dh}{io_dir_path}, $key); + + -d $file + ? rmdir($file) + : unlink($file); +} + +1; + +__END__ + +=head1 NAME + +IO::Dir - supply object methods for directory handles + +=head1 SYNOPSIS + + use IO::Dir; + $d = IO::Dir->new("."); + if (defined $d) { + while (defined($_ = $d->read)) { something($_); } + $d->rewind; + while (defined($_ = $d->read)) { something_else($_); } + undef $d; + } + + tie %dir, 'IO::Dir', "."; + foreach (keys %dir) { + print $_, " " , $dir{$_}->size,"\n"; + } + +=head1 DESCRIPTION + +The C<IO::Dir> package provides two interfaces to perl's directory reading +routines. + +The first interface is an object approach. C<IO::Dir> provides an object +constructor and methods, which are just wrappers around perl's built in +directory reading routines. + +=over 4 + +=item new ( [ DIRNAME ] ) + +C<new> is the constructor for C<IO::Dir> objects. It accepts one optional +argument which, if given, C<new> will pass to C<open> + +=back + +The following methods are wrappers for the directory related functions built +into perl (the trailing `dir' has been removed from the names). See L<perlfunc> +for details of these functions. + +=over 4 + +=item open ( DIRNAME ) + +=item read () + +=item seek ( POS ) + +=item tell () + +=item rewind () + +=item close () + +=back + +C<IO::Dir> also provides an interface to reading directories via a tied +hash. The tied hash extends the interface beyond just the directory +reading routines by the use of C<lstat>, from the C<File::stat> package, +C<unlink>, C<rmdir> and C<utime>. + +=over 4 + +=item tie %hash, 'IO::Dir', DIRNAME [, OPTIONS ] + +=back + +The keys of the hash will be the names of the entries in the directory. +Reading a value from the hash will be the result of calling +C<File::stat::lstat>. Deleting an element from the hash will +delete the corresponding file or subdirectory, +provided that C<DIR_UNLINK> is included in the C<OPTIONS>. + +Assigning to an entry in the hash will cause the time stamps of the file +to be modified. If the file does not exist then it will be created. Assigning +a single integer to a hash element will cause both the access and +modification times to be changed to that value. Alternatively a reference to +an array of two values can be passed. The first array element will be used to +set the access time and the second element will be used to set the modification +time. + +=head1 SEE ALSO + +L<File::stat> + +=head1 AUTHOR + +Graham Barr. Currently maintained by the Perl Porters. Please report all +bugs to <perl5-porters@perl.org>. + +=head1 COPYRIGHT + +Copyright (c) 1997-2003 Graham Barr <gbarr@pobox.com>. All rights reserved. +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=cut diff --git a/Master/tlpkg/tlperl/lib/IO/File.pm b/Master/tlpkg/tlperl/lib/IO/File.pm new file mode 100644 index 00000000000..d33d090d0b2 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/File.pm @@ -0,0 +1,204 @@ +# + +package IO::File; + +=head1 NAME + +IO::File - supply object methods for filehandles + +=head1 SYNOPSIS + + use IO::File; + + $fh = new IO::File; + if ($fh->open("< file")) { + print <$fh>; + $fh->close; + } + + $fh = new IO::File "> file"; + if (defined $fh) { + print $fh "bar\n"; + $fh->close; + } + + $fh = new IO::File "file", "r"; + if (defined $fh) { + print <$fh>; + undef $fh; # automatically closes the file + } + + $fh = new IO::File "file", O_WRONLY|O_APPEND; + if (defined $fh) { + print $fh "corge\n"; + + $pos = $fh->getpos; + $fh->setpos($pos); + + undef $fh; # automatically closes the file + } + + autoflush STDOUT 1; + +=head1 DESCRIPTION + +C<IO::File> inherits from C<IO::Handle> and C<IO::Seekable>. It extends +these classes with methods that are specific to file handles. + +=head1 CONSTRUCTOR + +=over 4 + +=item new ( FILENAME [,MODE [,PERMS]] ) + +Creates an C<IO::File>. If it receives any parameters, they are passed to +the method C<open>; if the open fails, the object is destroyed. Otherwise, +it is returned to the caller. + +=item new_tmpfile + +Creates an C<IO::File> opened for read/write on a newly created temporary +file. On systems where this is possible, the temporary file is anonymous +(i.e. it is unlinked after creation, but held open). If the temporary +file cannot be created or opened, the C<IO::File> object is destroyed. +Otherwise, it is returned to the caller. + +=back + +=head1 METHODS + +=over 4 + +=item open( FILENAME [,MODE [,PERMS]] ) + +=item open( FILENAME, IOLAYERS ) + +C<open> accepts one, two or three parameters. With one parameter, +it is just a front end for the built-in C<open> function. With two or three +parameters, the first parameter is a filename that may include +whitespace or other special characters, and the second parameter is +the open mode, optionally followed by a file permission value. + +If C<IO::File::open> receives a Perl mode string ("E<gt>", "+E<lt>", etc.) +or an ANSI C fopen() mode string ("w", "r+", etc.), it uses the basic +Perl C<open> operator (but protects any special characters). + +If C<IO::File::open> is given a numeric mode, it passes that mode +and the optional permissions value to the Perl C<sysopen> operator. +The permissions default to 0666. + +If C<IO::File::open> is given a mode that includes the C<:> character, +it passes all the three arguments to the three-argument C<open> operator. + +For convenience, C<IO::File> exports the O_XXX constants from the +Fcntl module, if this module is available. + +=item binmode( [LAYER] ) + +C<binmode> sets C<binmode> on the underlying C<IO> object, as documented +in C<perldoc -f binmode>. + +C<binmode> accepts one optional parameter, which is the layer to be +passed on to the C<binmode> call. + +=back + +=head1 NOTE + +Some operating systems may perform C<IO::File::new()> or C<IO::File::open()> +on a directory without errors. This behavior is not portable and not +suggested for use. Using C<opendir()> and C<readdir()> or C<IO::Dir> are +suggested instead. + +=head1 SEE ALSO + +L<perlfunc>, +L<perlop/"I/O Operators">, +L<IO::Handle>, +L<IO::Seekable>, +L<IO::Dir> + +=head1 HISTORY + +Derived from FileHandle.pm by Graham Barr E<lt>F<gbarr@pobox.com>E<gt>. + +=cut + +use 5.006_001; +use strict; +our($VERSION, @EXPORT, @EXPORT_OK, @ISA); +use Carp; +use Symbol; +use SelectSaver; +use IO::Seekable; +use File::Spec; + +require Exporter; + +@ISA = qw(IO::Handle IO::Seekable Exporter); + +$VERSION = "1.14"; + +@EXPORT = @IO::Seekable::EXPORT; + +eval { + # Make all Fcntl O_XXX constants available for importing + require Fcntl; + my @O = grep /^O_/, @Fcntl::EXPORT; + Fcntl->import(@O); # first we import what we want to export + push(@EXPORT, @O); +}; + +################################################ +## Constructor +## + +sub new { + my $type = shift; + my $class = ref($type) || $type || "IO::File"; + @_ >= 0 && @_ <= 3 + or croak "usage: new $class [FILENAME [,MODE [,PERMS]]]"; + my $fh = $class->SUPER::new(); + if (@_) { + $fh->open(@_) + or return undef; + } + $fh; +} + +################################################ +## Open +## + +sub open { + @_ >= 2 && @_ <= 4 or croak 'usage: $fh->open(FILENAME [,MODE [,PERMS]])'; + my ($fh, $file) = @_; + if (@_ > 2) { + my ($mode, $perms) = @_[2, 3]; + if ($mode =~ /^\d+$/) { + defined $perms or $perms = 0666; + return sysopen($fh, $file, $mode, $perms); + } elsif ($mode =~ /:/) { + return open($fh, $mode, $file) if @_ == 3; + croak 'usage: $fh->open(FILENAME, IOLAYERS)'; + } else { + return open($fh, IO::Handle::_open_mode_string($mode), $file); + } + } + open($fh, $file); +} + +################################################ +## Binmode +## + +sub binmode { + ( @_ == 1 or @_ == 2 ) or croak 'usage $fh->binmode([LAYER])'; + + my($fh, $layer) = @_; + + return binmode $$fh unless $layer; + return binmode $$fh, $layer; +} + +1; diff --git a/Master/tlpkg/tlperl/lib/IO/Handle.pm b/Master/tlpkg/tlperl/lib/IO/Handle.pm new file mode 100644 index 00000000000..2f1f1b423bc --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Handle.pm @@ -0,0 +1,635 @@ +package IO::Handle; + +=head1 NAME + +IO::Handle - supply object methods for I/O handles + +=head1 SYNOPSIS + + use IO::Handle; + + $io = new IO::Handle; + if ($io->fdopen(fileno(STDIN),"r")) { + print $io->getline; + $io->close; + } + + $io = new IO::Handle; + if ($io->fdopen(fileno(STDOUT),"w")) { + $io->print("Some text\n"); + } + + # setvbuf is not available by default on Perls 5.8.0 and later. + use IO::Handle '_IOLBF'; + $io->setvbuf($buffer_var, _IOLBF, 1024); + + undef $io; # automatically closes the file if it's open + + autoflush STDOUT 1; + +=head1 DESCRIPTION + +C<IO::Handle> is the base class for all other IO handle classes. It is +not intended that objects of C<IO::Handle> would be created directly, +but instead C<IO::Handle> is inherited from by several other classes +in the IO hierarchy. + +If you are reading this documentation, looking for a replacement for +the C<FileHandle> package, then I suggest you read the documentation +for C<IO::File> too. + +=head1 CONSTRUCTOR + +=over 4 + +=item new () + +Creates a new C<IO::Handle> object. + +=item new_from_fd ( FD, MODE ) + +Creates an C<IO::Handle> like C<new> does. +It requires two parameters, which are passed to the method C<fdopen>; +if the fdopen fails, the object is destroyed. Otherwise, it is returned +to the caller. + +=back + +=head1 METHODS + +See L<perlfunc> for complete descriptions of each of the following +supported C<IO::Handle> methods, which are just front ends for the +corresponding built-in functions: + + $io->close + $io->eof + $io->fcntl( FUNCTION, SCALAR ) + $io->fileno + $io->format_write( [FORMAT_NAME] ) + $io->getc + $io->ioctl( FUNCTION, SCALAR ) + $io->read ( BUF, LEN, [OFFSET] ) + $io->print ( ARGS ) + $io->printf ( FMT, [ARGS] ) + $io->say ( ARGS ) + $io->stat + $io->sysread ( BUF, LEN, [OFFSET] ) + $io->syswrite ( BUF, [LEN, [OFFSET]] ) + $io->truncate ( LEN ) + +See L<perlvar> for complete descriptions of each of the following +supported C<IO::Handle> methods. All of them return the previous +value of the attribute and takes an optional single argument that when +given will set the value. If no argument is given the previous value +is unchanged (except for $io->autoflush will actually turn ON +autoflush by default). + + $io->autoflush ( [BOOL] ) $| + $io->format_page_number( [NUM] ) $% + $io->format_lines_per_page( [NUM] ) $= + $io->format_lines_left( [NUM] ) $- + $io->format_name( [STR] ) $~ + $io->format_top_name( [STR] ) $^ + $io->input_line_number( [NUM]) $. + +The following methods are not supported on a per-filehandle basis. + + IO::Handle->format_line_break_characters( [STR] ) $: + IO::Handle->format_formfeed( [STR]) $^L + IO::Handle->output_field_separator( [STR] ) $, + IO::Handle->output_record_separator( [STR] ) $\ + + IO::Handle->input_record_separator( [STR] ) $/ + +Furthermore, for doing normal I/O you might need these: + +=over 4 + +=item $io->fdopen ( FD, MODE ) + +C<fdopen> is like an ordinary C<open> except that its first parameter +is not a filename but rather a file handle name, an IO::Handle object, +or a file descriptor number. (For the documentation of the C<open> +method, see L<IO::File>.) + +=item $io->opened + +Returns true if the object is currently a valid file descriptor, false +otherwise. + +=item $io->getline + +This works like <$io> described in L<perlop/"I/O Operators"> +except that it's more readable and can be safely called in a +list context but still returns just one line. If used as the conditional ++within a C<while> or C-style C<for> loop, however, you will need to ++emulate the functionality of <$io> with C<< defined($_ = $io->getline) >>. + +=item $io->getlines + +This works like <$io> when called in a list context to read all +the remaining lines in a file, except that it's more readable. +It will also croak() if accidentally called in a scalar context. + +=item $io->ungetc ( ORD ) + +Pushes a character with the given ordinal value back onto the given +handle's input stream. Only one character of pushback per handle is +guaranteed. + +=item $io->write ( BUF, LEN [, OFFSET ] ) + +This C<write> is like C<write> found in C, that is it is the +opposite of read. The wrapper for the perl C<write> function is +called C<format_write>. + +=item $io->error + +Returns a true value if the given handle has experienced any errors +since it was opened or since the last call to C<clearerr>, or if the +handle is invalid. It only returns false for a valid handle with no +outstanding errors. + +=item $io->clearerr + +Clear the given handle's error indicator. Returns -1 if the handle is +invalid, 0 otherwise. + +=item $io->sync + +C<sync> synchronizes a file's in-memory state with that on the +physical medium. C<sync> does not operate at the perlio api level, but +operates on the file descriptor (similar to sysread, sysseek and +systell). This means that any data held at the perlio api level will not +be synchronized. To synchronize data that is buffered at the perlio api +level you must use the flush method. C<sync> is not implemented on all +platforms. Returns "0 but true" on success, C<undef> on error, C<undef> +for an invalid handle. See L<fsync(3c)>. + +=item $io->flush + +C<flush> causes perl to flush any buffered data at the perlio api level. +Any unread data in the buffer will be discarded, and any unwritten data +will be written to the underlying file descriptor. Returns "0 but true" +on success, C<undef> on error. + +=item $io->printflush ( ARGS ) + +Turns on autoflush, print ARGS and then restores the autoflush status of the +C<IO::Handle> object. Returns the return value from print. + +=item $io->blocking ( [ BOOL ] ) + +If called with an argument C<blocking> will turn on non-blocking IO if +C<BOOL> is false, and turn it off if C<BOOL> is true. + +C<blocking> will return the value of the previous setting, or the +current setting if C<BOOL> is not given. + +If an error occurs C<blocking> will return undef and C<$!> will be set. + +=back + + +If the C functions setbuf() and/or setvbuf() are available, then +C<IO::Handle::setbuf> and C<IO::Handle::setvbuf> set the buffering +policy for an IO::Handle. The calling sequences for the Perl functions +are the same as their C counterparts--including the constants C<_IOFBF>, +C<_IOLBF>, and C<_IONBF> for setvbuf()--except that the buffer parameter +specifies a scalar variable to use as a buffer. You should only +change the buffer before any I/O, or immediately after calling flush. + +WARNING: The IO::Handle::setvbuf() is not available by default on +Perls 5.8.0 and later because setvbuf() is rather specific to using +the stdio library, while Perl prefers the new perlio subsystem instead. + +WARNING: A variable used as a buffer by C<setbuf> or C<setvbuf> B<must not +be modified> in any way until the IO::Handle is closed or C<setbuf> or +C<setvbuf> is called again, or memory corruption may result! Remember that +the order of global destruction is undefined, so even if your buffer +variable remains in scope until program termination, it may be undefined +before the file IO::Handle is closed. Note that you need to import the +constants C<_IOFBF>, C<_IOLBF>, and C<_IONBF> explicitly. Like C, setbuf +returns nothing. setvbuf returns "0 but true", on success, C<undef> on +failure. + +Lastly, there is a special method for working under B<-T> and setuid/gid +scripts: + +=over 4 + +=item $io->untaint + +Marks the object as taint-clean, and as such data read from it will also +be considered taint-clean. Note that this is a very trusting action to +take, and appropriate consideration for the data source and potential +vulnerability should be kept in mind. Returns 0 on success, -1 if setting +the taint-clean flag failed. (eg invalid handle) + +=back + +=head1 NOTE + +An C<IO::Handle> object is a reference to a symbol/GLOB reference (see +the C<Symbol> package). Some modules that +inherit from C<IO::Handle> may want to keep object related variables +in the hash table part of the GLOB. In an attempt to prevent modules +trampling on each other I propose the that any such module should prefix +its variables with its own name separated by _'s. For example the IO::Socket +module keeps a C<timeout> variable in 'io_socket_timeout'. + +=head1 SEE ALSO + +L<perlfunc>, +L<perlop/"I/O Operators">, +L<IO::File> + +=head1 BUGS + +Due to backwards compatibility, all filehandles resemble objects +of class C<IO::Handle>, or actually classes derived from that class. +They actually aren't. Which means you can't derive your own +class from C<IO::Handle> and inherit those methods. + +=head1 HISTORY + +Derived from FileHandle.pm by Graham Barr E<lt>F<gbarr@pobox.com>E<gt> + +=cut + +use 5.006_001; +use strict; +our($VERSION, @EXPORT_OK, @ISA); +use Carp; +use Symbol; +use SelectSaver; +use IO (); # Load the XS module + +require Exporter; +@ISA = qw(Exporter); + +$VERSION = "1.28"; +$VERSION = eval $VERSION; + +@EXPORT_OK = qw( + autoflush + output_field_separator + output_record_separator + input_record_separator + input_line_number + format_page_number + format_lines_per_page + format_lines_left + format_name + format_top_name + format_line_break_characters + format_formfeed + format_write + + print + printf + say + getline + getlines + + printflush + flush + + SEEK_SET + SEEK_CUR + SEEK_END + _IOFBF + _IOLBF + _IONBF +); + +################################################ +## Constructors, destructors. +## + +sub new { + my $class = ref($_[0]) || $_[0] || "IO::Handle"; + @_ == 1 or croak "usage: new $class"; + my $io = gensym; + bless $io, $class; +} + +sub new_from_fd { + my $class = ref($_[0]) || $_[0] || "IO::Handle"; + @_ == 3 or croak "usage: new_from_fd $class FD, MODE"; + my $io = gensym; + shift; + IO::Handle::fdopen($io, @_) + or return undef; + bless $io, $class; +} + +# +# There is no need for DESTROY to do anything, because when the +# last reference to an IO object is gone, Perl automatically +# closes its associated files (if any). However, to avoid any +# attempts to autoload DESTROY, we here define it to do nothing. +# +sub DESTROY {} + + +################################################ +## Open and close. +## + +sub _open_mode_string { + my ($mode) = @_; + $mode =~ /^\+?(<|>>?)$/ + or $mode =~ s/^r(\+?)$/$1</ + or $mode =~ s/^w(\+?)$/$1>/ + or $mode =~ s/^a(\+?)$/$1>>/ + or croak "IO::Handle: bad open mode: $mode"; + $mode; +} + +sub fdopen { + @_ == 3 or croak 'usage: $io->fdopen(FD, MODE)'; + my ($io, $fd, $mode) = @_; + local(*GLOB); + + if (ref($fd) && "".$fd =~ /GLOB\(/o) { + # It's a glob reference; Alias it as we cannot get name of anon GLOBs + my $n = qualify(*GLOB); + *GLOB = *{*$fd}; + $fd = $n; + } elsif ($fd =~ m#^\d+$#) { + # It's an FD number; prefix with "=". + $fd = "=$fd"; + } + + open($io, _open_mode_string($mode) . '&' . $fd) + ? $io : undef; +} + +sub close { + @_ == 1 or croak 'usage: $io->close()'; + my($io) = @_; + + close($io); +} + +################################################ +## Normal I/O functions. +## + +# flock +# select + +sub opened { + @_ == 1 or croak 'usage: $io->opened()'; + defined fileno($_[0]); +} + +sub fileno { + @_ == 1 or croak 'usage: $io->fileno()'; + fileno($_[0]); +} + +sub getc { + @_ == 1 or croak 'usage: $io->getc()'; + getc($_[0]); +} + +sub eof { + @_ == 1 or croak 'usage: $io->eof()'; + eof($_[0]); +} + +sub print { + @_ or croak 'usage: $io->print(ARGS)'; + my $this = shift; + print $this @_; +} + +sub printf { + @_ >= 2 or croak 'usage: $io->printf(FMT,[ARGS])'; + my $this = shift; + printf $this @_; +} + +sub say { + @_ or croak 'usage: $io->say(ARGS)'; + my $this = shift; + local $\ = "\n"; + print $this @_; +} + +sub getline { + @_ == 1 or croak 'usage: $io->getline()'; + my $this = shift; + return scalar <$this>; +} + +*gets = \&getline; # deprecated + +sub getlines { + @_ == 1 or croak 'usage: $io->getlines()'; + wantarray or + croak 'Can\'t call $io->getlines in a scalar context, use $io->getline'; + my $this = shift; + return <$this>; +} + +sub truncate { + @_ == 2 or croak 'usage: $io->truncate(LEN)'; + truncate($_[0], $_[1]); +} + +sub read { + @_ == 3 || @_ == 4 or croak 'usage: $io->read(BUF, LEN [, OFFSET])'; + read($_[0], $_[1], $_[2], $_[3] || 0); +} + +sub sysread { + @_ == 3 || @_ == 4 or croak 'usage: $io->sysread(BUF, LEN [, OFFSET])'; + sysread($_[0], $_[1], $_[2], $_[3] || 0); +} + +sub write { + @_ >= 2 && @_ <= 4 or croak 'usage: $io->write(BUF [, LEN [, OFFSET]])'; + local($\) = ""; + $_[2] = length($_[1]) unless defined $_[2]; + print { $_[0] } substr($_[1], $_[3] || 0, $_[2]); +} + +sub syswrite { + @_ >= 2 && @_ <= 4 or croak 'usage: $io->syswrite(BUF [, LEN [, OFFSET]])'; + if (defined($_[2])) { + syswrite($_[0], $_[1], $_[2], $_[3] || 0); + } else { + syswrite($_[0], $_[1]); + } +} + +sub stat { + @_ == 1 or croak 'usage: $io->stat()'; + stat($_[0]); +} + +################################################ +## State modification functions. +## + +sub autoflush { + my $old = new SelectSaver qualify($_[0], caller); + my $prev = $|; + $| = @_ > 1 ? $_[1] : 1; + $prev; +} + +sub output_field_separator { + carp "output_field_separator is not supported on a per-handle basis" + if ref($_[0]); + my $prev = $,; + $, = $_[1] if @_ > 1; + $prev; +} + +sub output_record_separator { + carp "output_record_separator is not supported on a per-handle basis" + if ref($_[0]); + my $prev = $\; + $\ = $_[1] if @_ > 1; + $prev; +} + +sub input_record_separator { + carp "input_record_separator is not supported on a per-handle basis" + if ref($_[0]); + my $prev = $/; + $/ = $_[1] if @_ > 1; + $prev; +} + +sub input_line_number { + local $.; + () = tell qualify($_[0], caller) if ref($_[0]); + my $prev = $.; + $. = $_[1] if @_ > 1; + $prev; +} + +sub format_page_number { + my $old; + $old = new SelectSaver qualify($_[0], caller) if ref($_[0]); + my $prev = $%; + $% = $_[1] if @_ > 1; + $prev; +} + +sub format_lines_per_page { + my $old; + $old = new SelectSaver qualify($_[0], caller) if ref($_[0]); + my $prev = $=; + $= = $_[1] if @_ > 1; + $prev; +} + +sub format_lines_left { + my $old; + $old = new SelectSaver qualify($_[0], caller) if ref($_[0]); + my $prev = $-; + $- = $_[1] if @_ > 1; + $prev; +} + +sub format_name { + my $old; + $old = new SelectSaver qualify($_[0], caller) if ref($_[0]); + my $prev = $~; + $~ = qualify($_[1], caller) if @_ > 1; + $prev; +} + +sub format_top_name { + my $old; + $old = new SelectSaver qualify($_[0], caller) if ref($_[0]); + my $prev = $^; + $^ = qualify($_[1], caller) if @_ > 1; + $prev; +} + +sub format_line_break_characters { + carp "format_line_break_characters is not supported on a per-handle basis" + if ref($_[0]); + my $prev = $:; + $: = $_[1] if @_ > 1; + $prev; +} + +sub format_formfeed { + carp "format_formfeed is not supported on a per-handle basis" + if ref($_[0]); + my $prev = $^L; + $^L = $_[1] if @_ > 1; + $prev; +} + +sub formline { + my $io = shift; + my $picture = shift; + local($^A) = $^A; + local($\) = ""; + formline($picture, @_); + print $io $^A; +} + +sub format_write { + @_ < 3 || croak 'usage: $io->write( [FORMAT_NAME] )'; + if (@_ == 2) { + my ($io, $fmt) = @_; + my $oldfmt = $io->format_name(qualify($fmt,caller)); + CORE::write($io); + $io->format_name($oldfmt); + } else { + CORE::write($_[0]); + } +} + +sub fcntl { + @_ == 3 || croak 'usage: $io->fcntl( OP, VALUE );'; + my ($io, $op) = @_; + return fcntl($io, $op, $_[2]); +} + +sub ioctl { + @_ == 3 || croak 'usage: $io->ioctl( OP, VALUE );'; + my ($io, $op) = @_; + return ioctl($io, $op, $_[2]); +} + +# this sub is for compatability with older releases of IO that used +# a sub called constant to detemine if a constant existed -- GMB +# +# The SEEK_* and _IO?BF constants were the only constants at that time +# any new code should just chech defined(&CONSTANT_NAME) + +sub constant { + no strict 'refs'; + my $name = shift; + (($name =~ /^(SEEK_(SET|CUR|END)|_IO[FLN]BF)$/) && defined &{$name}) + ? &{$name}() : undef; +} + + +# so that flush.pl can be deprecated + +sub printflush { + my $io = shift; + my $old; + $old = new SelectSaver qualify($io, caller) if ref($io); + local $| = 1; + if(ref($io)) { + print $io @_; + } + else { + print @_; + } +} + +1; diff --git a/Master/tlpkg/tlperl/lib/IO/Pipe.pm b/Master/tlpkg/tlperl/lib/IO/Pipe.pm new file mode 100644 index 00000000000..827cc48bfcd --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Pipe.pm @@ -0,0 +1,257 @@ +# IO::Pipe.pm +# +# Copyright (c) 1996-8 Graham Barr <gbarr@pobox.com>. All rights reserved. +# This program is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. + +package IO::Pipe; + +use 5.006_001; + +use IO::Handle; +use strict; +our($VERSION); +use Carp; +use Symbol; + +$VERSION = "1.13"; + +sub new { + my $type = shift; + my $class = ref($type) || $type || "IO::Pipe"; + @_ == 0 || @_ == 2 or croak "usage: new $class [READFH, WRITEFH]"; + + my $me = bless gensym(), $class; + + my($readfh,$writefh) = @_ ? @_ : $me->handles; + + pipe($readfh, $writefh) + or return undef; + + @{*$me} = ($readfh, $writefh); + + $me; +} + +sub handles { + @_ == 1 or croak 'usage: $pipe->handles()'; + (IO::Pipe::End->new(), IO::Pipe::End->new()); +} + +my $do_spawn = $^O eq 'os2' || $^O eq 'MSWin32'; + +sub _doit { + my $me = shift; + my $rw = shift; + + my $pid = $do_spawn ? 0 : fork(); + + if($pid) { # Parent + return $pid; + } + elsif(defined $pid) { # Child or spawn + my $fh; + my $io = $rw ? \*STDIN : \*STDOUT; + my ($mode, $save) = $rw ? "r" : "w"; + if ($do_spawn) { + require Fcntl; + $save = IO::Handle->new_from_fd($io, $mode); + my $handle = shift; + # Close in child: + unless ($^O eq 'MSWin32') { + fcntl($handle, Fcntl::F_SETFD(), 1) or croak "fcntl: $!"; + } + $fh = $rw ? ${*$me}[0] : ${*$me}[1]; + } else { + shift; + $fh = $rw ? $me->reader() : $me->writer(); # close the other end + } + bless $io, "IO::Handle"; + $io->fdopen($fh, $mode); + $fh->close; + + if ($do_spawn) { + $pid = eval { system 1, @_ }; # 1 == P_NOWAIT + my $err = $!; + + $io->fdopen($save, $mode); + $save->close or croak "Cannot close $!"; + croak "IO::Pipe: Cannot spawn-NOWAIT: $err" if not $pid or $pid < 0; + return $pid; + } else { + exec @_ or + croak "IO::Pipe: Cannot exec: $!"; + } + } + else { + croak "IO::Pipe: Cannot fork: $!"; + } + + # NOT Reached +} + +sub reader { + @_ >= 1 or croak 'usage: $pipe->reader( [SUB_COMMAND_ARGS] )'; + my $me = shift; + + return undef + unless(ref($me) || ref($me = $me->new)); + + my $fh = ${*$me}[0]; + my $pid; + $pid = $me->_doit(0, $fh, @_) + if(@_); + + close ${*$me}[1]; + bless $me, ref($fh); + *$me = *$fh; # Alias self to handle + $me->fdopen($fh->fileno,"r") + unless defined($me->fileno); + bless $fh; # Really wan't un-bless here + ${*$me}{'io_pipe_pid'} = $pid + if defined $pid; + + $me; +} + +sub writer { + @_ >= 1 or croak 'usage: $pipe->writer( [SUB_COMMAND_ARGS] )'; + my $me = shift; + + return undef + unless(ref($me) || ref($me = $me->new)); + + my $fh = ${*$me}[1]; + my $pid; + $pid = $me->_doit(1, $fh, @_) + if(@_); + + close ${*$me}[0]; + bless $me, ref($fh); + *$me = *$fh; # Alias self to handle + $me->fdopen($fh->fileno,"w") + unless defined($me->fileno); + bless $fh; # Really wan't un-bless here + ${*$me}{'io_pipe_pid'} = $pid + if defined $pid; + + $me; +} + +package IO::Pipe::End; + +our(@ISA); + +@ISA = qw(IO::Handle); + +sub close { + my $fh = shift; + my $r = $fh->SUPER::close(@_); + + waitpid(${*$fh}{'io_pipe_pid'},0) + if(defined ${*$fh}{'io_pipe_pid'}); + + $r; +} + +1; + +__END__ + +=head1 NAME + +IO::Pipe - supply object methods for pipes + +=head1 SYNOPSIS + + use IO::Pipe; + + $pipe = new IO::Pipe; + + if($pid = fork()) { # Parent + $pipe->reader(); + + while(<$pipe>) { + ... + } + + } + elsif(defined $pid) { # Child + $pipe->writer(); + + print $pipe ... + } + + or + + $pipe = new IO::Pipe; + + $pipe->reader(qw(ls -l)); + + while(<$pipe>) { + ... + } + +=head1 DESCRIPTION + +C<IO::Pipe> provides an interface to creating pipes between +processes. + +=head1 CONSTRUCTOR + +=over 4 + +=item new ( [READER, WRITER] ) + +Creates an C<IO::Pipe>, which is a reference to a newly created symbol +(see the C<Symbol> package). C<IO::Pipe::new> optionally takes two +arguments, which should be objects blessed into C<IO::Handle>, or a +subclass thereof. These two objects will be used for the system call +to C<pipe>. If no arguments are given then method C<handles> is called +on the new C<IO::Pipe> object. + +These two handles are held in the array part of the GLOB until either +C<reader> or C<writer> is called. + +=back + +=head1 METHODS + +=over 4 + +=item reader ([ARGS]) + +The object is re-blessed into a sub-class of C<IO::Handle>, and becomes a +handle at the reading end of the pipe. If C<ARGS> are given then C<fork> +is called and C<ARGS> are passed to exec. + +=item writer ([ARGS]) + +The object is re-blessed into a sub-class of C<IO::Handle>, and becomes a +handle at the writing end of the pipe. If C<ARGS> are given then C<fork> +is called and C<ARGS> are passed to exec. + +=item handles () + +This method is called during construction by C<IO::Pipe::new> +on the newly created C<IO::Pipe> object. It returns an array of two objects +blessed into C<IO::Pipe::End>, or a subclass thereof. + +=back + +=head1 SEE ALSO + +L<IO::Handle> + +=head1 AUTHOR + +Graham Barr. Currently maintained by the Perl Porters. Please report all +bugs to <perl5-porters@perl.org>. + +=head1 COPYRIGHT + +Copyright (c) 1996-8 Graham Barr <gbarr@pobox.com>. All rights reserved. +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=cut diff --git a/Master/tlpkg/tlperl/lib/IO/Poll.pm b/Master/tlpkg/tlperl/lib/IO/Poll.pm new file mode 100644 index 00000000000..e7fb0135069 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Poll.pm @@ -0,0 +1,209 @@ + +# IO::Poll.pm +# +# Copyright (c) 1997-8 Graham Barr <gbarr@pobox.com>. All rights reserved. +# This program is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. + +package IO::Poll; + +use strict; +use IO::Handle; +use Exporter (); +our(@ISA, @EXPORT_OK, @EXPORT, $VERSION); + +@ISA = qw(Exporter); +$VERSION = "0.07"; + +@EXPORT = qw( POLLIN + POLLOUT + POLLERR + POLLHUP + POLLNVAL + ); + +@EXPORT_OK = qw( + POLLPRI + POLLRDNORM + POLLWRNORM + POLLRDBAND + POLLWRBAND + POLLNORM + ); + +# [0] maps fd's to requested masks +# [1] maps fd's to returned masks +# [2] maps fd's to handles +sub new { + my $class = shift; + + my $self = bless [{},{},{}], $class; + + $self; +} + +sub mask { + my $self = shift; + my $io = shift; + my $fd = fileno($io); + return unless defined $fd; + if (@_) { + my $mask = shift; + if($mask) { + $self->[0]{$fd}{$io} = $mask; # the error events are always returned + $self->[1]{$fd} = 0; # output mask + $self->[2]{$io} = $io; # remember handle + } else { + delete $self->[0]{$fd}{$io}; + unless(%{$self->[0]{$fd}}) { + # We no longer have any handles for this FD + delete $self->[1]{$fd}; + delete $self->[0]{$fd}; + } + delete $self->[2]{$io}; + } + } + + return unless exists $self->[0]{$fd} and exists $self->[0]{$fd}{$io}; + return $self->[0]{$fd}{$io}; +} + + +sub poll { + my($self,$timeout) = @_; + + $self->[1] = {}; + + my($fd,$mask,$iom); + my @poll = (); + + while(($fd,$iom) = each %{$self->[0]}) { + $mask = 0; + $mask |= $_ for values(%$iom); + push(@poll,$fd => $mask); + } + + my $ret = @poll ? _poll(defined($timeout) ? $timeout * 1000 : -1,@poll) : 0; + + return $ret + unless $ret > 0; + + while(@poll) { + my($fd,$got) = splice(@poll,0,2); + $self->[1]{$fd} = $got if $got; + } + + return $ret; +} + +sub events { + my $self = shift; + my $io = shift; + my $fd = fileno($io); + exists $self->[1]{$fd} and exists $self->[0]{$fd}{$io} + ? $self->[1]{$fd} & ($self->[0]{$fd}{$io}|POLLHUP|POLLERR|POLLNVAL) + : 0; +} + +sub remove { + my $self = shift; + my $io = shift; + $self->mask($io,0); +} + +sub handles { + my $self = shift; + return values %{$self->[2]} unless @_; + + my $events = shift || 0; + my($fd,$ev,$io,$mask); + my @handles = (); + + while(($fd,$ev) = each %{$self->[1]}) { + while (($io,$mask) = each %{$self->[0]{$fd}}) { + $mask |= POLLHUP|POLLERR|POLLNVAL; # must allow these + push @handles,$self->[2]{$io} if ($ev & $mask) & $events; + } + } + return @handles; +} + +1; + +__END__ + +=head1 NAME + +IO::Poll - Object interface to system poll call + +=head1 SYNOPSIS + + use IO::Poll qw(POLLRDNORM POLLWRNORM POLLIN POLLHUP); + + $poll = new IO::Poll; + + $poll->mask($input_handle => POLLIN); + $poll->mask($output_handle => POLLOUT); + + $poll->poll($timeout); + + $ev = $poll->events($input); + +=head1 DESCRIPTION + +C<IO::Poll> is a simple interface to the system level poll routine. + +=head1 METHODS + +=over 4 + +=item mask ( IO [, EVENT_MASK ] ) + +If EVENT_MASK is given, then, if EVENT_MASK is non-zero, IO is added to the +list of file descriptors and the next call to poll will check for +any event specified in EVENT_MASK. If EVENT_MASK is zero then IO will be +removed from the list of file descriptors. + +If EVENT_MASK is not given then the return value will be the current +event mask value for IO. + +=item poll ( [ TIMEOUT ] ) + +Call the system level poll routine. If TIMEOUT is not specified then the +call will block. Returns the number of handles which had events +happen, or -1 on error. + +=item events ( IO ) + +Returns the event mask which represents the events that happened on IO +during the last call to C<poll>. + +=item remove ( IO ) + +Remove IO from the list of file descriptors for the next poll. + +=item handles( [ EVENT_MASK ] ) + +Returns a list of handles. If EVENT_MASK is not given then a list of all +handles known will be returned. If EVENT_MASK is given then a list +of handles will be returned which had one of the events specified by +EVENT_MASK happen during the last call ti C<poll> + +=back + +=head1 SEE ALSO + +L<poll(2)>, L<IO::Handle>, L<IO::Select> + +=head1 AUTHOR + +Graham Barr. Currently maintained by the Perl Porters. Please report all +bugs to <perl5-porters@perl.org>. + +=head1 COPYRIGHT + +Copyright (c) 1997-8 Graham Barr <gbarr@pobox.com>. All rights reserved. +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=cut diff --git a/Master/tlpkg/tlperl/lib/IO/Seekable.pm b/Master/tlpkg/tlperl/lib/IO/Seekable.pm new file mode 100644 index 00000000000..db1effda287 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Seekable.pm @@ -0,0 +1,128 @@ +# + +package IO::Seekable; + +=head1 NAME + +IO::Seekable - supply seek based methods for I/O objects + +=head1 SYNOPSIS + + use IO::Seekable; + package IO::Something; + @ISA = qw(IO::Seekable); + +=head1 DESCRIPTION + +C<IO::Seekable> does not have a constructor of its own as it is intended to +be inherited by other C<IO::Handle> based objects. It provides methods +which allow seeking of the file descriptors. + +=over 4 + +=item $io->getpos + +Returns an opaque value that represents the current position of the +IO::File, or C<undef> if this is not possible (eg an unseekable stream such +as a terminal, pipe or socket). If the fgetpos() function is available in +your C library it is used to implements getpos, else perl emulates getpos +using C's ftell() function. + +=item $io->setpos + +Uses the value of a previous getpos call to return to a previously visited +position. Returns "0 but true" on success, C<undef> on failure. + +=back + +See L<perlfunc> for complete descriptions of each of the following +supported C<IO::Seekable> methods, which are just front ends for the +corresponding built-in functions: + +=over 4 + +=item $io->seek ( POS, WHENCE ) + +Seek the IO::File to position POS, relative to WHENCE: + +=over 8 + +=item WHENCE=0 (SEEK_SET) + +POS is absolute position. (Seek relative to the start of the file) + +=item WHENCE=1 (SEEK_CUR) + +POS is an offset from the current position. (Seek relative to current) + +=item WHENCE=2 (SEEK_END) + +POS is an offset from the end of the file. (Seek relative to end) + +=back + +The SEEK_* constants can be imported from the C<Fcntl> module if you +don't wish to use the numbers C<0> C<1> or C<2> in your code. + +Returns C<1> upon success, C<0> otherwise. + +=item $io->sysseek( POS, WHENCE ) + +Similar to $io->seek, but sets the IO::File's position using the system +call lseek(2) directly, so will confuse most perl IO operators except +sysread and syswrite (see L<perlfunc> for full details) + +Returns the new position, or C<undef> on failure. A position +of zero is returned as the string C<"0 but true"> + +=item $io->tell + +Returns the IO::File's current position, or -1 on error. + +=back + +=head1 SEE ALSO + +L<perlfunc>, +L<perlop/"I/O Operators">, +L<IO::Handle> +L<IO::File> + +=head1 HISTORY + +Derived from FileHandle.pm by Graham Barr E<lt>gbarr@pobox.comE<gt> + +=cut + +use 5.006_001; +use Carp; +use strict; +our($VERSION, @EXPORT, @ISA); +use IO::Handle (); +# XXX we can't get these from IO::Handle or we'll get prototype +# mismatch warnings on C<use POSIX; use IO::File;> :-( +use Fcntl qw(SEEK_SET SEEK_CUR SEEK_END); +require Exporter; + +@EXPORT = qw(SEEK_SET SEEK_CUR SEEK_END); +@ISA = qw(Exporter); + +$VERSION = "1.10"; +$VERSION = eval $VERSION; + +sub seek { + @_ == 3 or croak 'usage: $io->seek(POS, WHENCE)'; + seek($_[0], $_[1], $_[2]); +} + +sub sysseek { + @_ == 3 or croak 'usage: $io->sysseek(POS, WHENCE)'; + sysseek($_[0], $_[1], $_[2]); +} + +sub tell { + @_ == 1 or croak 'usage: $io->tell()'; + tell($_[0]); +} + +1; diff --git a/Master/tlpkg/tlperl/lib/IO/Select.pm b/Master/tlpkg/tlperl/lib/IO/Select.pm new file mode 100644 index 00000000000..fc05fe70e9c --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Select.pm @@ -0,0 +1,381 @@ +# IO::Select.pm +# +# Copyright (c) 1997-8 Graham Barr <gbarr@pobox.com>. All rights reserved. +# This program is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. + +package IO::Select; + +use strict; +use warnings::register; +use vars qw($VERSION @ISA); +require Exporter; + +$VERSION = "1.17"; + +@ISA = qw(Exporter); # This is only so we can do version checking + +sub VEC_BITS () {0} +sub FD_COUNT () {1} +sub FIRST_FD () {2} + +sub new +{ + my $self = shift; + my $type = ref($self) || $self; + + my $vec = bless [undef,0], $type; + + $vec->add(@_) + if @_; + + $vec; +} + +sub add +{ + shift->_update('add', @_); +} + + +sub remove +{ + shift->_update('remove', @_); +} + + +sub exists +{ + my $vec = shift; + my $fno = $vec->_fileno(shift); + return undef unless defined $fno; + $vec->[$fno + FIRST_FD]; +} + + +sub _fileno +{ + my($self, $f) = @_; + return unless defined $f; + $f = $f->[0] if ref($f) eq 'ARRAY'; + ($f =~ /^\d+$/) ? $f : fileno($f); +} + +sub _update +{ + my $vec = shift; + my $add = shift eq 'add'; + + my $bits = $vec->[VEC_BITS]; + $bits = '' unless defined $bits; + + my $count = 0; + my $f; + foreach $f (@_) + { + my $fn = $vec->_fileno($f); + next unless defined $fn; + my $i = $fn + FIRST_FD; + if ($add) { + if (defined $vec->[$i]) { + $vec->[$i] = $f; # if array rest might be different, so we update + next; + } + $vec->[FD_COUNT]++; + vec($bits, $fn, 1) = 1; + $vec->[$i] = $f; + } else { # remove + next unless defined $vec->[$i]; + $vec->[FD_COUNT]--; + vec($bits, $fn, 1) = 0; + $vec->[$i] = undef; + } + $count++; + } + $vec->[VEC_BITS] = $vec->[FD_COUNT] ? $bits : undef; + $count; +} + +sub can_read +{ + my $vec = shift; + my $timeout = shift; + my $r = $vec->[VEC_BITS]; + + defined($r) && (select($r,undef,undef,$timeout) > 0) + ? handles($vec, $r) + : (); +} + +sub can_write +{ + my $vec = shift; + my $timeout = shift; + my $w = $vec->[VEC_BITS]; + + defined($w) && (select(undef,$w,undef,$timeout) > 0) + ? handles($vec, $w) + : (); +} + +sub has_exception +{ + my $vec = shift; + my $timeout = shift; + my $e = $vec->[VEC_BITS]; + + defined($e) && (select(undef,undef,$e,$timeout) > 0) + ? handles($vec, $e) + : (); +} + +sub has_error +{ + warnings::warn("Call to deprecated method 'has_error', use 'has_exception'") + if warnings::enabled(); + goto &has_exception; +} + +sub count +{ + my $vec = shift; + $vec->[FD_COUNT]; +} + +sub bits +{ + my $vec = shift; + $vec->[VEC_BITS]; +} + +sub as_string # for debugging +{ + my $vec = shift; + my $str = ref($vec) . ": "; + my $bits = $vec->bits; + my $count = $vec->count; + $str .= defined($bits) ? unpack("b*", $bits) : "undef"; + $str .= " $count"; + my @handles = @$vec; + splice(@handles, 0, FIRST_FD); + for (@handles) { + $str .= " " . (defined($_) ? "$_" : "-"); + } + $str; +} + +sub _max +{ + my($a,$b,$c) = @_; + $a > $b + ? $a > $c + ? $a + : $c + : $b > $c + ? $b + : $c; +} + +sub select +{ + shift + if defined $_[0] && !ref($_[0]); + + my($r,$w,$e,$t) = @_; + my @result = (); + + my $rb = defined $r ? $r->[VEC_BITS] : undef; + my $wb = defined $w ? $w->[VEC_BITS] : undef; + my $eb = defined $e ? $e->[VEC_BITS] : undef; + + if(select($rb,$wb,$eb,$t) > 0) + { + my @r = (); + my @w = (); + my @e = (); + my $i = _max(defined $r ? scalar(@$r)-1 : 0, + defined $w ? scalar(@$w)-1 : 0, + defined $e ? scalar(@$e)-1 : 0); + + for( ; $i >= FIRST_FD ; $i--) + { + my $j = $i - FIRST_FD; + push(@r, $r->[$i]) + if defined $rb && defined $r->[$i] && vec($rb, $j, 1); + push(@w, $w->[$i]) + if defined $wb && defined $w->[$i] && vec($wb, $j, 1); + push(@e, $e->[$i]) + if defined $eb && defined $e->[$i] && vec($eb, $j, 1); + } + + @result = (\@r, \@w, \@e); + } + @result; +} + + +sub handles +{ + my $vec = shift; + my $bits = shift; + my @h = (); + my $i; + my $max = scalar(@$vec) - 1; + + for ($i = FIRST_FD; $i <= $max; $i++) + { + next unless defined $vec->[$i]; + push(@h, $vec->[$i]) + if !defined($bits) || vec($bits, $i - FIRST_FD, 1); + } + + @h; +} + +1; +__END__ + +=head1 NAME + +IO::Select - OO interface to the select system call + +=head1 SYNOPSIS + + use IO::Select; + + $s = IO::Select->new(); + + $s->add(\*STDIN); + $s->add($some_handle); + + @ready = $s->can_read($timeout); + + @ready = IO::Select->new(@handles)->can_read(0); + +=head1 DESCRIPTION + +The C<IO::Select> package implements an object approach to the system C<select> +function call. It allows the user to see what IO handles, see L<IO::Handle>, +are ready for reading, writing or have an exception pending. + +=head1 CONSTRUCTOR + +=over 4 + +=item new ( [ HANDLES ] ) + +The constructor creates a new object and optionally initialises it with a set +of handles. + +=back + +=head1 METHODS + +=over 4 + +=item add ( HANDLES ) + +Add the list of handles to the C<IO::Select> object. It is these values that +will be returned when an event occurs. C<IO::Select> keeps these values in a +cache which is indexed by the C<fileno> of the handle, so if more than one +handle with the same C<fileno> is specified then only the last one is cached. + +Each handle can be an C<IO::Handle> object, an integer or an array +reference where the first element is an C<IO::Handle> or an integer. + +=item remove ( HANDLES ) + +Remove all the given handles from the object. This method also works +by the C<fileno> of the handles. So the exact handles that were added +need not be passed, just handles that have an equivalent C<fileno> + +=item exists ( HANDLE ) + +Returns a true value (actually the handle itself) if it is present. +Returns undef otherwise. + +=item handles + +Return an array of all registered handles. + +=item can_read ( [ TIMEOUT ] ) + +Return an array of handles that are ready for reading. C<TIMEOUT> is +the maximum amount of time to wait before returning an empty list, in +seconds, possibly fractional. If C<TIMEOUT> is not given and any +handles are registered then the call will block. + +=item can_write ( [ TIMEOUT ] ) + +Same as C<can_read> except check for handles that can be written to. + +=item has_exception ( [ TIMEOUT ] ) + +Same as C<can_read> except check for handles that have an exception +condition, for example pending out-of-band data. + +=item count () + +Returns the number of handles that the object will check for when +one of the C<can_> methods is called or the object is passed to +the C<select> static method. + +=item bits() + +Return the bit string suitable as argument to the core select() call. + +=item select ( READ, WRITE, EXCEPTION [, TIMEOUT ] ) + +C<select> is a static method, that is you call it with the package name +like C<new>. C<READ>, C<WRITE> and C<EXCEPTION> are either C<undef> or +C<IO::Select> objects. C<TIMEOUT> is optional and has the same effect as +for the core select call. + +The result will be an array of 3 elements, each a reference to an array +which will hold the handles that are ready for reading, writing and have +exceptions respectively. Upon error an empty list is returned. + +=back + +=head1 EXAMPLE + +Here is a short example which shows how C<IO::Select> could be used +to write a server which communicates with several sockets while also +listening for more connections on a listen socket + + use IO::Select; + use IO::Socket; + + $lsn = new IO::Socket::INET(Listen => 1, LocalPort => 8080); + $sel = new IO::Select( $lsn ); + + while(@ready = $sel->can_read) { + foreach $fh (@ready) { + if($fh == $lsn) { + # Create a new socket + $new = $lsn->accept; + $sel->add($new); + } + else { + # Process socket + + # Maybe we have finished with the socket + $sel->remove($fh); + $fh->close; + } + } + } + +=head1 AUTHOR + +Graham Barr. Currently maintained by the Perl Porters. Please report all +bugs to <perl5-porters@perl.org>. + +=head1 COPYRIGHT + +Copyright (c) 1997-8 Graham Barr <gbarr@pobox.com>. All rights reserved. +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=cut + diff --git a/Master/tlpkg/tlperl/lib/IO/Socket.pm b/Master/tlpkg/tlperl/lib/IO/Socket.pm new file mode 100644 index 00000000000..6d4f6ab6123 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Socket.pm @@ -0,0 +1,540 @@ +# IO::Socket.pm +# +# Copyright (c) 1997-8 Graham Barr <gbarr@pobox.com>. All rights reserved. +# This program is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. + +package IO::Socket; + +require 5.006; + +use IO::Handle; +use Socket 1.3; +use Carp; +use strict; +our(@ISA, $VERSION, @EXPORT_OK); +use Exporter; +use Errno; + +# legacy + +require IO::Socket::INET; +require IO::Socket::UNIX if ($^O ne 'epoc' && $^O ne 'symbian'); + +@ISA = qw(IO::Handle); + +$VERSION = "1.31"; + +@EXPORT_OK = qw(sockatmark); + +sub import { + my $pkg = shift; + if (@_ && $_[0] eq 'sockatmark') { # not very extensible but for now, fast + Exporter::export_to_level('IO::Socket', 1, $pkg, 'sockatmark'); + } else { + my $callpkg = caller; + Exporter::export 'Socket', $callpkg, @_; + } +} + +sub new { + my($class,%arg) = @_; + my $sock = $class->SUPER::new(); + + $sock->autoflush(1); + + ${*$sock}{'io_socket_timeout'} = delete $arg{Timeout}; + + return scalar(%arg) ? $sock->configure(\%arg) + : $sock; +} + +my @domain2pkg; + +sub register_domain { + my($p,$d) = @_; + $domain2pkg[$d] = $p; +} + +sub configure { + my($sock,$arg) = @_; + my $domain = delete $arg->{Domain}; + + croak 'IO::Socket: Cannot configure a generic socket' + unless defined $domain; + + croak "IO::Socket: Unsupported socket domain" + unless defined $domain2pkg[$domain]; + + croak "IO::Socket: Cannot configure socket in domain '$domain'" + unless ref($sock) eq "IO::Socket"; + + bless($sock, $domain2pkg[$domain]); + $sock->configure($arg); +} + +sub socket { + @_ == 4 or croak 'usage: $sock->socket(DOMAIN, TYPE, PROTOCOL)'; + my($sock,$domain,$type,$protocol) = @_; + + socket($sock,$domain,$type,$protocol) or + return undef; + + ${*$sock}{'io_socket_domain'} = $domain; + ${*$sock}{'io_socket_type'} = $type; + ${*$sock}{'io_socket_proto'} = $protocol; + + $sock; +} + +sub socketpair { + @_ == 4 || croak 'usage: IO::Socket->socketpair(DOMAIN, TYPE, PROTOCOL)'; + my($class,$domain,$type,$protocol) = @_; + my $sock1 = $class->new(); + my $sock2 = $class->new(); + + socketpair($sock1,$sock2,$domain,$type,$protocol) or + return (); + + ${*$sock1}{'io_socket_type'} = ${*$sock2}{'io_socket_type'} = $type; + ${*$sock1}{'io_socket_proto'} = ${*$sock2}{'io_socket_proto'} = $protocol; + + ($sock1,$sock2); +} + +sub connect { + @_ == 2 or croak 'usage: $sock->connect(NAME)'; + my $sock = shift; + my $addr = shift; + my $timeout = ${*$sock}{'io_socket_timeout'}; + my $err; + my $blocking; + + $blocking = $sock->blocking(0) if $timeout; + if (!connect($sock, $addr)) { + if (defined $timeout && ($!{EINPROGRESS} || $!{EWOULDBLOCK})) { + require IO::Select; + + my $sel = new IO::Select $sock; + + undef $!; + if (!$sel->can_write($timeout)) { + $err = $! || (exists &Errno::ETIMEDOUT ? &Errno::ETIMEDOUT : 1); + $@ = "connect: timeout"; + } + elsif (!connect($sock,$addr) && + not ($!{EISCONN} || ($! == 10022 && $^O eq 'MSWin32')) + ) { + # Some systems refuse to re-connect() to + # an already open socket and set errno to EISCONN. + # Windows sets errno to WSAEINVAL (10022) + $err = $!; + $@ = "connect: $!"; + } + } + elsif ($blocking || !($!{EINPROGRESS} || $!{EWOULDBLOCK})) { + $err = $!; + $@ = "connect: $!"; + } + } + + $sock->blocking(1) if $blocking; + + $! = $err if $err; + + $err ? undef : $sock; +} + +# Enable/disable blocking IO on sockets. +# Without args return the current status of blocking, +# with args change the mode as appropriate, returning the +# old setting, or in case of error during the mode change +# undef. + +sub blocking { + my $sock = shift; + + return $sock->SUPER::blocking(@_) + if $^O ne 'MSWin32'; + + # Windows handles blocking differently + # + # http://groups.google.co.uk/group/perl.perl5.porters/browse_thread/thread/b4e2b1d88280ddff/630b667a66e3509f?#630b667a66e3509f + # http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/ioctlsocket_2.asp + # + # 0x8004667e is FIONBIO + # + # which is used to set blocking behaviour. + + # NOTE: + # This is a little confusing, the perl keyword for this is + # 'blocking' but the OS level behaviour is 'non-blocking', probably + # because sockets are blocking by default. + # Therefore internally we have to reverse the semantics. + + my $orig= !${*$sock}{io_sock_nonblocking}; + + return $orig unless @_; + + my $block = shift; + + if ( !$block != !$orig ) { + ${*$sock}{io_sock_nonblocking} = $block ? 0 : 1; + ioctl($sock, 0x8004667e, pack("L!",${*$sock}{io_sock_nonblocking})) + or return undef; + } + + return $orig; +} + + +sub close { + @_ == 1 or croak 'usage: $sock->close()'; + my $sock = shift; + ${*$sock}{'io_socket_peername'} = undef; + $sock->SUPER::close(); +} + +sub bind { + @_ == 2 or croak 'usage: $sock->bind(NAME)'; + my $sock = shift; + my $addr = shift; + + return bind($sock, $addr) ? $sock + : undef; +} + +sub listen { + @_ >= 1 && @_ <= 2 or croak 'usage: $sock->listen([QUEUE])'; + my($sock,$queue) = @_; + $queue = 5 + unless $queue && $queue > 0; + + return listen($sock, $queue) ? $sock + : undef; +} + +sub accept { + @_ == 1 || @_ == 2 or croak 'usage $sock->accept([PKG])'; + my $sock = shift; + my $pkg = shift || $sock; + my $timeout = ${*$sock}{'io_socket_timeout'}; + my $new = $pkg->new(Timeout => $timeout); + my $peer = undef; + + if(defined $timeout) { + require IO::Select; + + my $sel = new IO::Select $sock; + + unless ($sel->can_read($timeout)) { + $@ = 'accept: timeout'; + $! = (exists &Errno::ETIMEDOUT ? &Errno::ETIMEDOUT : 1); + return; + } + } + + $peer = accept($new,$sock) + or return; + + return wantarray ? ($new, $peer) + : $new; +} + +sub sockname { + @_ == 1 or croak 'usage: $sock->sockname()'; + getsockname($_[0]); +} + +sub peername { + @_ == 1 or croak 'usage: $sock->peername()'; + my($sock) = @_; + ${*$sock}{'io_socket_peername'} ||= getpeername($sock); +} + +sub connected { + @_ == 1 or croak 'usage: $sock->connected()'; + my($sock) = @_; + getpeername($sock); +} + +sub send { + @_ >= 2 && @_ <= 4 or croak 'usage: $sock->send(BUF, [FLAGS, [TO]])'; + my $sock = $_[0]; + my $flags = $_[2] || 0; + my $peer = $_[3] || $sock->peername; + + croak 'send: Cannot determine peer address' + unless(defined $peer); + + my $r = defined(getpeername($sock)) + ? send($sock, $_[1], $flags) + : send($sock, $_[1], $flags, $peer); + + # remember who we send to, if it was successful + ${*$sock}{'io_socket_peername'} = $peer + if(@_ == 4 && defined $r); + + $r; +} + +sub recv { + @_ == 3 || @_ == 4 or croak 'usage: $sock->recv(BUF, LEN [, FLAGS])'; + my $sock = $_[0]; + my $len = $_[2]; + my $flags = $_[3] || 0; + + # remember who we recv'd from + ${*$sock}{'io_socket_peername'} = recv($sock, $_[1]='', $len, $flags); +} + +sub shutdown { + @_ == 2 or croak 'usage: $sock->shutdown(HOW)'; + my($sock, $how) = @_; + ${*$sock}{'io_socket_peername'} = undef; + shutdown($sock, $how); +} + +sub setsockopt { + @_ == 4 or croak '$sock->setsockopt(LEVEL, OPTNAME, OPTVAL)'; + setsockopt($_[0],$_[1],$_[2],$_[3]); +} + +my $intsize = length(pack("i",0)); + +sub getsockopt { + @_ == 3 or croak '$sock->getsockopt(LEVEL, OPTNAME)'; + my $r = getsockopt($_[0],$_[1],$_[2]); + # Just a guess + $r = unpack("i", $r) + if(defined $r && length($r) == $intsize); + $r; +} + +sub sockopt { + my $sock = shift; + @_ == 1 ? $sock->getsockopt(SOL_SOCKET,@_) + : $sock->setsockopt(SOL_SOCKET,@_); +} + +sub atmark { + @_ == 1 or croak 'usage: $sock->atmark()'; + my($sock) = @_; + sockatmark($sock); +} + +sub timeout { + @_ == 1 || @_ == 2 or croak 'usage: $sock->timeout([VALUE])'; + my($sock,$val) = @_; + my $r = ${*$sock}{'io_socket_timeout'}; + + ${*$sock}{'io_socket_timeout'} = defined $val ? 0 + $val : $val + if(@_ == 2); + + $r; +} + +sub sockdomain { + @_ == 1 or croak 'usage: $sock->sockdomain()'; + my $sock = shift; + ${*$sock}{'io_socket_domain'}; +} + +sub socktype { + @_ == 1 or croak 'usage: $sock->socktype()'; + my $sock = shift; + ${*$sock}{'io_socket_type'} +} + +sub protocol { + @_ == 1 or croak 'usage: $sock->protocol()'; + my($sock) = @_; + ${*$sock}{'io_socket_proto'}; +} + +1; + +__END__ + +=head1 NAME + +IO::Socket - Object interface to socket communications + +=head1 SYNOPSIS + + use IO::Socket; + +=head1 DESCRIPTION + +C<IO::Socket> provides an object interface to creating and using sockets. It +is built upon the L<IO::Handle> interface and inherits all the methods defined +by L<IO::Handle>. + +C<IO::Socket> only defines methods for those operations which are common to all +types of socket. Operations which are specified to a socket in a particular +domain have methods defined in sub classes of C<IO::Socket> + +C<IO::Socket> will export all functions (and constants) defined by L<Socket>. + +=head1 CONSTRUCTOR + +=over 4 + +=item new ( [ARGS] ) + +Creates an C<IO::Socket>, which is a reference to a +newly created symbol (see the C<Symbol> package). C<new> +optionally takes arguments, these arguments are in key-value pairs. +C<new> only looks for one key C<Domain> which tells new which domain +the socket will be in. All other arguments will be passed to the +configuration method of the package for that domain, See below. + + NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE + +As of VERSION 1.18 all IO::Socket objects have autoflush turned on +by default. This was not the case with earlier releases. + + NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE + +=back + +=head1 METHODS + +See L<perlfunc> for complete descriptions of each of the following +supported C<IO::Socket> methods, which are just front ends for the +corresponding built-in functions: + + socket + socketpair + bind + listen + accept + send + recv + peername (getpeername) + sockname (getsockname) + shutdown + +Some methods take slightly different arguments to those defined in L<perlfunc> +in attempt to make the interface more flexible. These are + +=over 4 + +=item accept([PKG]) + +perform the system call C<accept> on the socket and return a new +object. The new object will be created in the same class as the listen +socket, unless C<PKG> is specified. This object can be used to +communicate with the client that was trying to connect. + +In a scalar context the new socket is returned, or undef upon +failure. In a list context a two-element array is returned containing +the new socket and the peer address; the list will be empty upon +failure. + +The timeout in the [PKG] can be specified as zero to effect a "poll", +but you shouldn't do that because a new IO::Select object will be +created behind the scenes just to do the single poll. This is +horrendously inefficient. Use rather true select() with a zero +timeout on the handle, or non-blocking IO. + +=item socketpair(DOMAIN, TYPE, PROTOCOL) + +Call C<socketpair> and return a list of two sockets created, or an +empty list on failure. + +=back + +Additional methods that are provided are: + +=over 4 + +=item atmark + +True if the socket is currently positioned at the urgent data mark, +false otherwise. + + use IO::Socket; + + my $sock = IO::Socket::INET->new('some_server'); + $sock->read($data, 1024) until $sock->atmark; + +Note: this is a reasonably new addition to the family of socket +functions, so all systems may not support this yet. If it is +unsupported by the system, an attempt to use this method will +abort the program. + +The atmark() functionality is also exportable as sockatmark() function: + + use IO::Socket 'sockatmark'; + +This allows for a more traditional use of sockatmark() as a procedural +socket function. If your system does not support sockatmark(), the +C<use> declaration will fail at compile time. + +=item connected + +If the socket is in a connected state the peer address is returned. +If the socket is not in a connected state then undef will be returned. + +=item protocol + +Returns the numerical number for the protocol being used on the socket, if +known. If the protocol is unknown, as with an AF_UNIX socket, zero +is returned. + +=item sockdomain + +Returns the numerical number for the socket domain type. For example, for +an AF_INET socket the value of &AF_INET will be returned. + +=item sockopt(OPT [, VAL]) + +Unified method to both set and get options in the SOL_SOCKET level. If called +with one argument then getsockopt is called, otherwise setsockopt is called. + +=item getsockopt(LEVEL, OPT) + +Get option associated with the socket. Other levels than SOL_SOCKET +may be specified here. + +=item setsockopt(LEVEL, OPT, VAL) + +Set option associated with the socket. Other levels than SOL_SOCKET +may be specified here. + +=item socktype + +Returns the numerical number for the socket type. For example, for +a SOCK_STREAM socket the value of &SOCK_STREAM will be returned. + +=item timeout([VAL]) + +Set or get the timeout value (in seconds) associated with this socket. +If called without any arguments then the current setting is returned. If +called with an argument the current setting is changed and the previous +value returned. + +=back + +=head1 SEE ALSO + +L<Socket>, L<IO::Handle>, L<IO::Socket::INET>, L<IO::Socket::UNIX> + +=head1 AUTHOR + +Graham Barr. atmark() by Lincoln Stein. Currently maintained by the +Perl Porters. Please report all bugs to <perl5-porters@perl.org>. + +=head1 COPYRIGHT + +Copyright (c) 1997-8 Graham Barr <gbarr@pobox.com>. All rights reserved. +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +The atmark() implementation: Copyright 2001, Lincoln Stein <lstein@cshl.org>. +This module is distributed under the same terms as Perl itself. +Feel free to use, modify and redistribute it as long as you retain +the correct attribution. + +=cut diff --git a/Master/tlpkg/tlperl/lib/IO/Socket/INET.pm b/Master/tlpkg/tlperl/lib/IO/Socket/INET.pm new file mode 100644 index 00000000000..2f0e5d1d7a6 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Socket/INET.pm @@ -0,0 +1,464 @@ +# IO::Socket::INET.pm +# +# Copyright (c) 1997-8 Graham Barr <gbarr@pobox.com>. All rights reserved. +# This program is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. + +package IO::Socket::INET; + +use strict; +our(@ISA, $VERSION); +use IO::Socket; +use Socket; +use Carp; +use Exporter; +use Errno; + +@ISA = qw(IO::Socket); +$VERSION = "1.31"; + +my $EINVAL = exists(&Errno::EINVAL) ? Errno::EINVAL() : 1; + +IO::Socket::INET->register_domain( AF_INET ); + +my %socket_type = ( tcp => SOCK_STREAM, + udp => SOCK_DGRAM, + icmp => SOCK_RAW + ); +my %proto_number; +$proto_number{tcp} = Socket::IPPROTO_TCP() if defined &Socket::IPPROTO_TCP; +$proto_number{udp} = Socket::IPPROTO_UDP() if defined &Socket::IPPROTO_UDP; +$proto_number{icmp} = Socket::IPPROTO_ICMP() if defined &Socket::IPPROTO_ICMP; +my %proto_name = reverse %proto_number; + +sub new { + my $class = shift; + unshift(@_, "PeerAddr") if @_ == 1; + return $class->SUPER::new(@_); +} + +sub _cache_proto { + my @proto = @_; + for (map lc($_), $proto[0], split(' ', $proto[1])) { + $proto_number{$_} = $proto[2]; + } + $proto_name{$proto[2]} = $proto[0]; +} + +sub _get_proto_number { + my $name = lc(shift); + return undef unless defined $name; + return $proto_number{$name} if exists $proto_number{$name}; + + my @proto = getprotobyname($name); + return undef unless @proto; + _cache_proto(@proto); + + return $proto[2]; +} + +sub _get_proto_name { + my $num = shift; + return undef unless defined $num; + return $proto_name{$num} if exists $proto_name{$num}; + + my @proto = getprotobynumber($num); + return undef unless @proto; + _cache_proto(@proto); + + return $proto[0]; +} + +sub _sock_info { + my($addr,$port,$proto) = @_; + my $origport = $port; + my @serv = (); + + $port = $1 + if(defined $addr && $addr =~ s,:([\w\(\)/]+)$,,); + + if(defined $proto && $proto =~ /\D/) { + my $num = _get_proto_number($proto); + unless (defined $num) { + $@ = "Bad protocol '$proto'"; + return; + } + $proto = $num; + } + + if(defined $port) { + my $defport = ($port =~ s,\((\d+)\)$,,) ? $1 : undef; + my $pnum = ($port =~ m,^(\d+)$,)[0]; + + @serv = getservbyname($port, _get_proto_name($proto) || "") + if ($port =~ m,\D,); + + $port = $serv[2] || $defport || $pnum; + unless (defined $port) { + $@ = "Bad service '$origport'"; + return; + } + + $proto = _get_proto_number($serv[3]) if @serv && !$proto; + } + + return ($addr || undef, + $port || undef, + $proto || undef + ); +} + +sub _error { + my $sock = shift; + my $err = shift; + { + local($!); + my $title = ref($sock).": "; + $@ = join("", $_[0] =~ /^$title/ ? "" : $title, @_); + $sock->close() + if(defined fileno($sock)); + } + $! = $err; + return undef; +} + +sub _get_addr { + my($sock,$addr_str, $multi) = @_; + my @addr; + if ($multi && $addr_str !~ /^\d+(?:\.\d+){3}$/) { + (undef, undef, undef, undef, @addr) = gethostbyname($addr_str); + } else { + my $h = inet_aton($addr_str); + push(@addr, $h) if defined $h; + } + @addr; +} + +sub configure { + my($sock,$arg) = @_; + my($lport,$rport,$laddr,$raddr,$proto,$type); + + + $arg->{LocalAddr} = $arg->{LocalHost} + if exists $arg->{LocalHost} && !exists $arg->{LocalAddr}; + + ($laddr,$lport,$proto) = _sock_info($arg->{LocalAddr}, + $arg->{LocalPort}, + $arg->{Proto}) + or return _error($sock, $!, $@); + + $laddr = defined $laddr ? inet_aton($laddr) + : INADDR_ANY; + + return _error($sock, $EINVAL, "Bad hostname '",$arg->{LocalAddr},"'") + unless(defined $laddr); + + $arg->{PeerAddr} = $arg->{PeerHost} + if exists $arg->{PeerHost} && !exists $arg->{PeerAddr}; + + unless(exists $arg->{Listen}) { + ($raddr,$rport,$proto) = _sock_info($arg->{PeerAddr}, + $arg->{PeerPort}, + $proto) + or return _error($sock, $!, $@); + } + + $proto ||= _get_proto_number('tcp'); + + $type = $arg->{Type} || $socket_type{lc _get_proto_name($proto)}; + + my @raddr = (); + + if(defined $raddr) { + @raddr = $sock->_get_addr($raddr, $arg->{MultiHomed}); + return _error($sock, $EINVAL, "Bad hostname '",$arg->{PeerAddr},"'") + unless @raddr; + } + + while(1) { + + $sock->socket(AF_INET, $type, $proto) or + return _error($sock, $!, "$!"); + + if (defined $arg->{Blocking}) { + defined $sock->blocking($arg->{Blocking}) + or return _error($sock, $!, "$!"); + } + + if ($arg->{Reuse} || $arg->{ReuseAddr}) { + $sock->sockopt(SO_REUSEADDR,1) or + return _error($sock, $!, "$!"); + } + + if ($arg->{ReusePort}) { + $sock->sockopt(SO_REUSEPORT,1) or + return _error($sock, $!, "$!"); + } + + if ($arg->{Broadcast}) { + $sock->sockopt(SO_BROADCAST,1) or + return _error($sock, $!, "$!"); + } + + if($lport || ($laddr ne INADDR_ANY) || exists $arg->{Listen}) { + $sock->bind($lport || 0, $laddr) or + return _error($sock, $!, "$!"); + } + + if(exists $arg->{Listen}) { + $sock->listen($arg->{Listen} || 5) or + return _error($sock, $!, "$!"); + last; + } + + # don't try to connect unless we're given a PeerAddr + last unless exists($arg->{PeerAddr}); + + $raddr = shift @raddr; + + return _error($sock, $EINVAL, 'Cannot determine remote port') + unless($rport || $type == SOCK_DGRAM || $type == SOCK_RAW); + + last + unless($type == SOCK_STREAM || defined $raddr); + + return _error($sock, $EINVAL, "Bad hostname '",$arg->{PeerAddr},"'") + unless defined $raddr; + +# my $timeout = ${*$sock}{'io_socket_timeout'}; +# my $before = time() if $timeout; + + undef $@; + if ($sock->connect(pack_sockaddr_in($rport, $raddr))) { +# ${*$sock}{'io_socket_timeout'} = $timeout; + return $sock; + } + + return _error($sock, $!, $@ || "Timeout") + unless @raddr; + +# if ($timeout) { +# my $new_timeout = $timeout - (time() - $before); +# return _error($sock, +# (exists(&Errno::ETIMEDOUT) ? Errno::ETIMEDOUT() : $EINVAL), +# "Timeout") if $new_timeout <= 0; +# ${*$sock}{'io_socket_timeout'} = $new_timeout; +# } + + } + + $sock; +} + +sub connect { + @_ == 2 || @_ == 3 or + croak 'usage: $sock->connect(NAME) or $sock->connect(PORT, ADDR)'; + my $sock = shift; + return $sock->SUPER::connect(@_ == 1 ? shift : pack_sockaddr_in(@_)); +} + +sub bind { + @_ == 2 || @_ == 3 or + croak 'usage: $sock->bind(NAME) or $sock->bind(PORT, ADDR)'; + my $sock = shift; + return $sock->SUPER::bind(@_ == 1 ? shift : pack_sockaddr_in(@_)) +} + +sub sockaddr { + @_ == 1 or croak 'usage: $sock->sockaddr()'; + my($sock) = @_; + my $name = $sock->sockname; + $name ? (sockaddr_in($name))[1] : undef; +} + +sub sockport { + @_ == 1 or croak 'usage: $sock->sockport()'; + my($sock) = @_; + my $name = $sock->sockname; + $name ? (sockaddr_in($name))[0] : undef; +} + +sub sockhost { + @_ == 1 or croak 'usage: $sock->sockhost()'; + my($sock) = @_; + my $addr = $sock->sockaddr; + $addr ? inet_ntoa($addr) : undef; +} + +sub peeraddr { + @_ == 1 or croak 'usage: $sock->peeraddr()'; + my($sock) = @_; + my $name = $sock->peername; + $name ? (sockaddr_in($name))[1] : undef; +} + +sub peerport { + @_ == 1 or croak 'usage: $sock->peerport()'; + my($sock) = @_; + my $name = $sock->peername; + $name ? (sockaddr_in($name))[0] : undef; +} + +sub peerhost { + @_ == 1 or croak 'usage: $sock->peerhost()'; + my($sock) = @_; + my $addr = $sock->peeraddr; + $addr ? inet_ntoa($addr) : undef; +} + +1; + +__END__ + +=head1 NAME + +IO::Socket::INET - Object interface for AF_INET domain sockets + +=head1 SYNOPSIS + + use IO::Socket::INET; + +=head1 DESCRIPTION + +C<IO::Socket::INET> provides an object interface to creating and using sockets +in the AF_INET domain. It is built upon the L<IO::Socket> interface and +inherits all the methods defined by L<IO::Socket>. + +=head1 CONSTRUCTOR + +=over 4 + +=item new ( [ARGS] ) + +Creates an C<IO::Socket::INET> object, which is a reference to a +newly created symbol (see the C<Symbol> package). C<new> +optionally takes arguments, these arguments are in key-value pairs. + +In addition to the key-value pairs accepted by L<IO::Socket>, +C<IO::Socket::INET> provides. + + + PeerAddr Remote host address <hostname>[:<port>] + PeerHost Synonym for PeerAddr + PeerPort Remote port or service <service>[(<no>)] | <no> + LocalAddr Local host bind address hostname[:port] + LocalHost Synonym for LocalAddr + LocalPort Local host bind port <service>[(<no>)] | <no> + Proto Protocol name (or number) "tcp" | "udp" | ... + Type Socket type SOCK_STREAM | SOCK_DGRAM | ... + Listen Queue size for listen + ReuseAddr Set SO_REUSEADDR before binding + Reuse Set SO_REUSEADDR before binding (deprecated, prefer ReuseAddr) + ReusePort Set SO_REUSEPORT before binding + Broadcast Set SO_BROADCAST before binding + Timeout Timeout value for various operations + MultiHomed Try all addresses for multi-homed hosts + Blocking Determine if connection will be blocking mode + +If C<Listen> is defined then a listen socket is created, else if the +socket type, which is derived from the protocol, is SOCK_STREAM then +connect() is called. + +Although it is not illegal, the use of C<MultiHomed> on a socket +which is in non-blocking mode is of little use. This is because the +first connect will never fail with a timeout as the connect call +will not block. + +The C<PeerAddr> can be a hostname or the IP-address on the +"xx.xx.xx.xx" form. The C<PeerPort> can be a number or a symbolic +service name. The service name might be followed by a number in +parenthesis which is used if the service is not known by the system. +The C<PeerPort> specification can also be embedded in the C<PeerAddr> +by preceding it with a ":". + +If C<Proto> is not given and you specify a symbolic C<PeerPort> port, +then the constructor will try to derive C<Proto> from the service +name. As a last resort C<Proto> "tcp" is assumed. The C<Type> +parameter will be deduced from C<Proto> if not specified. + +If the constructor is only passed a single argument, it is assumed to +be a C<PeerAddr> specification. + +If C<Blocking> is set to 0, the connection will be in nonblocking mode. +If not specified it defaults to 1 (blocking mode). + +Examples: + + $sock = IO::Socket::INET->new(PeerAddr => 'www.perl.org', + PeerPort => 'http(80)', + Proto => 'tcp'); + + $sock = IO::Socket::INET->new(PeerAddr => 'localhost:smtp(25)'); + + $sock = IO::Socket::INET->new(Listen => 5, + LocalAddr => 'localhost', + LocalPort => 9000, + Proto => 'tcp'); + + $sock = IO::Socket::INET->new('127.0.0.1:25'); + + $sock = IO::Socket::INET->new(PeerPort => 9999, + PeerAddr => inet_ntoa(INADDR_BROADCAST), + Proto => udp, + LocalAddr => 'localhost', + Broadcast => 1 ) + or die "Can't bind : $@\n"; + + NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE + +As of VERSION 1.18 all IO::Socket objects have autoflush turned on +by default. This was not the case with earlier releases. + + NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE + +=back + +=head2 METHODS + +=over 4 + +=item sockaddr () + +Return the address part of the sockaddr structure for the socket + +=item sockport () + +Return the port number that the socket is using on the local host + +=item sockhost () + +Return the address part of the sockaddr structure for the socket in a +text form xx.xx.xx.xx + +=item peeraddr () + +Return the address part of the sockaddr structure for the socket on +the peer host + +=item peerport () + +Return the port number for the socket on the peer host. + +=item peerhost () + +Return the address part of the sockaddr structure for the socket on the +peer host in a text form xx.xx.xx.xx + +=back + +=head1 SEE ALSO + +L<Socket>, L<IO::Socket> + +=head1 AUTHOR + +Graham Barr. Currently maintained by the Perl Porters. Please report all +bugs to <perl5-porters@perl.org>. + +=head1 COPYRIGHT + +Copyright (c) 1996-8 Graham Barr <gbarr@pobox.com>. All rights reserved. +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=cut diff --git a/Master/tlpkg/tlperl/lib/IO/Socket/UNIX.pm b/Master/tlpkg/tlperl/lib/IO/Socket/UNIX.pm new file mode 100644 index 00000000000..baa092ba1fb --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Socket/UNIX.pm @@ -0,0 +1,143 @@ +# IO::Socket::UNIX.pm +# +# Copyright (c) 1997-8 Graham Barr <gbarr@pobox.com>. All rights reserved. +# This program is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. + +package IO::Socket::UNIX; + +use strict; +our(@ISA, $VERSION); +use IO::Socket; +use Carp; + +@ISA = qw(IO::Socket); +$VERSION = "1.23"; +$VERSION = eval $VERSION; + +IO::Socket::UNIX->register_domain( AF_UNIX ); + +sub new { + my $class = shift; + unshift(@_, "Peer") if @_ == 1; + return $class->SUPER::new(@_); +} + +sub configure { + my($sock,$arg) = @_; + my($bport,$cport); + + my $type = $arg->{Type} || SOCK_STREAM; + + $sock->socket(AF_UNIX, $type, 0) or + return undef; + + if(exists $arg->{Local}) { + my $addr = sockaddr_un($arg->{Local}); + $sock->bind($addr) or + return undef; + } + if(exists $arg->{Listen} && $type != SOCK_DGRAM) { + $sock->listen($arg->{Listen} || 5) or + return undef; + } + elsif(exists $arg->{Peer}) { + my $addr = sockaddr_un($arg->{Peer}); + $sock->connect($addr) or + return undef; + } + + $sock; +} + +sub hostpath { + @_ == 1 or croak 'usage: $sock->hostpath()'; + my $n = $_[0]->sockname || return undef; + (sockaddr_un($n))[0]; +} + +sub peerpath { + @_ == 1 or croak 'usage: $sock->peerpath()'; + my $n = $_[0]->peername || return undef; + (sockaddr_un($n))[0]; +} + +1; # Keep require happy + +__END__ + +=head1 NAME + +IO::Socket::UNIX - Object interface for AF_UNIX domain sockets + +=head1 SYNOPSIS + + use IO::Socket::UNIX; + +=head1 DESCRIPTION + +C<IO::Socket::UNIX> provides an object interface to creating and using sockets +in the AF_UNIX domain. It is built upon the L<IO::Socket> interface and +inherits all the methods defined by L<IO::Socket>. + +=head1 CONSTRUCTOR + +=over 4 + +=item new ( [ARGS] ) + +Creates an C<IO::Socket::UNIX> object, which is a reference to a +newly created symbol (see the C<Symbol> package). C<new> +optionally takes arguments, these arguments are in key-value pairs. + +In addition to the key-value pairs accepted by L<IO::Socket>, +C<IO::Socket::UNIX> provides. + + Type Type of socket (eg SOCK_STREAM or SOCK_DGRAM) + Local Path to local fifo + Peer Path to peer fifo + Listen Create a listen socket + +If the constructor is only passed a single argument, it is assumed to +be a C<Peer> specification. + + + NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE + +As of VERSION 1.18 all IO::Socket objects have autoflush turned on +by default. This was not the case with earlier releases. + + NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE + +=back + +=head1 METHODS + +=over 4 + +=item hostpath() + +Returns the pathname to the fifo at the local end + +=item peerpath() + +Returns the pathanme to the fifo at the peer end + +=back + +=head1 SEE ALSO + +L<Socket>, L<IO::Socket> + +=head1 AUTHOR + +Graham Barr. Currently maintained by the Perl Porters. Please report all +bugs to <perl5-porters@perl.org>. + +=head1 COPYRIGHT + +Copyright (c) 1996-8 Graham Barr <gbarr@pobox.com>. All rights reserved. +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=cut diff --git a/Master/tlpkg/tlperl/lib/IO/Uncompress/Adapter/Bunzip2.pm b/Master/tlpkg/tlperl/lib/IO/Uncompress/Adapter/Bunzip2.pm new file mode 100644 index 00000000000..98677e3c09f --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Uncompress/Adapter/Bunzip2.pm @@ -0,0 +1,112 @@ +package IO::Uncompress::Adapter::Bunzip2; + +use strict; +use warnings; +use bytes; + +use IO::Compress::Base::Common 2.024 qw(:Status); + +use Compress::Raw::Bzip2 2.024 ; + +our ($VERSION, @ISA); +$VERSION = '2.024'; + +sub mkUncompObject +{ + my $small = shift || 0; + my $verbosity = shift || 0; + + my ($inflate, $status) = new Compress::Raw::Bunzip2(1, 1, $small, $verbosity, 1); + + return (undef, "Could not create Inflation object: $status", $status) + if $status != BZ_OK ; + + return bless {'Inf' => $inflate, + 'CompSize' => 0, + 'UnCompSize' => 0, + 'Error' => '', + 'ConsumesInput' => 1, + } ; + +} + +sub uncompr +{ + my $self = shift ; + my $from = shift ; + my $to = shift ; + my $eof = shift ; + + my $inf = $self->{Inf}; + + my $status = $inf->bzinflate($from, $to); + $self->{ErrorNo} = $status; + + if ($status != BZ_OK && $status != BZ_STREAM_END ) + { + $self->{Error} = "Inflation Error: $status"; + return STATUS_ERROR; + } + + + return STATUS_OK if $status == BZ_OK ; + return STATUS_ENDSTREAM if $status == BZ_STREAM_END ; + return STATUS_ERROR ; +} + + +sub reset +{ + my $self = shift ; + + my ($inf, $status) = new Compress::Raw::Bunzip2(); + $self->{ErrorNo} = ($status == BZ_OK) ? 0 : $status ; + + if ($status != BZ_OK) + { + $self->{Error} = "Cannot create Inflate object: $status"; + return STATUS_ERROR; + } + + $self->{Inf} = $inf; + + return STATUS_OK ; +} + +sub compressedBytes +{ + my $self = shift ; + $self->{Inf}->compressedBytes(); +} + +sub uncompressedBytes +{ + my $self = shift ; + $self->{Inf}->uncompressedBytes(); +} + +sub crc32 +{ + my $self = shift ; + #$self->{Inf}->crc32(); +} + +sub adler32 +{ + my $self = shift ; + #$self->{Inf}->adler32(); +} + +sub sync +{ + my $self = shift ; + #( $self->{Inf}->inflateSync(@_) == BZ_OK) + # ? STATUS_OK + # : STATUS_ERROR ; +} + + +1; + +__END__ + diff --git a/Master/tlpkg/tlperl/lib/IO/Uncompress/Adapter/Identity.pm b/Master/tlpkg/tlperl/lib/IO/Uncompress/Adapter/Identity.pm new file mode 100644 index 00000000000..27de6e0f36b --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Uncompress/Adapter/Identity.pm @@ -0,0 +1,105 @@ +package IO::Uncompress::Adapter::Identity; + +use warnings; +use strict; +use bytes; + +use IO::Compress::Base::Common 2.024 qw(:Status); + +our ($VERSION); + +$VERSION = '2.024'; + +use Compress::Raw::Zlib 2.024 (); + +sub mkUncompObject +{ + my $crc32 = 1; #shift ; + my $adler32 = shift; + + bless { 'CompSize' => 0, + 'UnCompSize' => 0, + 'wantCRC32' => $crc32, + 'CRC32' => Compress::Raw::Zlib::crc32(''), + 'wantADLER32'=> $adler32, + 'ADLER32' => Compress::Raw::Zlib::adler32(''), + 'ConsumesInput' => 1, + + } ; +} + +sub uncompr +{ + my $self = shift; + my $eof = $_[2]; + + if (defined ${ $_[0] } && length ${ $_[0] }) { + $self->{CompSize} += length ${ $_[0] } ; + $self->{UnCompSize} = $self->{CompSize} ; + + $self->{CRC32} = Compress::Raw::Zlib::crc32($_[0], $self->{CRC32}) + if $self->{wantCRC32}; + + $self->{ADLER32} = Compress::Zlib::adler32($_[0], $self->{ADLER32}) + if $self->{wantADLER32}; + + ${ $_[1] } .= ${ $_[0] }; + ${ $_[0] } = ""; + } + + return STATUS_ENDSTREAM if $eof; + return STATUS_OK ; +} + +sub reset +{ + my $self = shift; + + $self->{CompSize} = 0; + $self->{UnCompSize} = 0; + $self->{CRC32} = Compress::Raw::Zlib::crc32(''); + $self->{ADLER32} = Compress::Raw::Zlib::adler32(''); + + return STATUS_OK ; +} + + +#sub count +#{ +# my $self = shift ; +# return $self->{UnCompSize} ; +#} + +sub compressedBytes +{ + my $self = shift ; + return $self->{UnCompSize} ; +} + +sub uncompressedBytes +{ + my $self = shift ; + return $self->{UnCompSize} ; +} + +sub sync +{ + return STATUS_OK ; +} + +sub crc32 +{ + my $self = shift ; + return $self->{CRC32}; +} + +sub adler32 +{ + my $self = shift ; + return $self->{ADLER32}; +} + + +1; + +__END__ diff --git a/Master/tlpkg/tlperl/lib/IO/Uncompress/Adapter/Inflate.pm b/Master/tlpkg/tlperl/lib/IO/Uncompress/Adapter/Inflate.pm new file mode 100644 index 00000000000..aac1e413ffe --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Uncompress/Adapter/Inflate.pm @@ -0,0 +1,158 @@ +package IO::Uncompress::Adapter::Inflate; + +use strict; +use warnings; +use bytes; + +use IO::Compress::Base::Common 2.024 qw(:Status); +use Compress::Raw::Zlib 2.024 qw(Z_OK Z_BUF_ERROR Z_STREAM_END Z_FINISH MAX_WBITS); + +our ($VERSION); +$VERSION = '2.024'; + + + +sub mkUncompObject +{ + my $crc32 = shift || 1; + my $adler32 = shift || 1; + my $scan = shift || 0; + + my $inflate ; + my $status ; + + if ($scan) + { + ($inflate, $status) = new Compress::Raw::Zlib::InflateScan + #LimitOutput => 1, + CRC32 => $crc32, + ADLER32 => $adler32, + WindowBits => - MAX_WBITS ; + } + else + { + ($inflate, $status) = new Compress::Raw::Zlib::Inflate + AppendOutput => 1, + LimitOutput => 1, + CRC32 => $crc32, + ADLER32 => $adler32, + WindowBits => - MAX_WBITS ; + } + + return (undef, "Could not create Inflation object: $status", $status) + if $status != Z_OK ; + + return bless {'Inf' => $inflate, + 'CompSize' => 0, + 'UnCompSize' => 0, + 'Error' => '', + 'ConsumesInput' => 1, + } ; + +} + +sub uncompr +{ + my $self = shift ; + my $from = shift ; + my $to = shift ; + my $eof = shift ; + + my $inf = $self->{Inf}; + + my $status = $inf->inflate($from, $to, $eof); + $self->{ErrorNo} = $status; + + if ($status != Z_OK && $status != Z_STREAM_END && $status != Z_BUF_ERROR) + { + $self->{Error} = "Inflation Error: $status"; + return STATUS_ERROR; + } + + return STATUS_OK if $status == Z_BUF_ERROR ; # ??? + return STATUS_OK if $status == Z_OK ; + return STATUS_ENDSTREAM if $status == Z_STREAM_END ; + return STATUS_ERROR ; +} + +sub reset +{ + my $self = shift ; + $self->{Inf}->inflateReset(); + + return STATUS_OK ; +} + +#sub count +#{ +# my $self = shift ; +# $self->{Inf}->inflateCount(); +#} + +sub crc32 +{ + my $self = shift ; + $self->{Inf}->crc32(); +} + +sub compressedBytes +{ + my $self = shift ; + $self->{Inf}->compressedBytes(); +} + +sub uncompressedBytes +{ + my $self = shift ; + $self->{Inf}->uncompressedBytes(); +} + +sub adler32 +{ + my $self = shift ; + $self->{Inf}->adler32(); +} + +sub sync +{ + my $self = shift ; + ( $self->{Inf}->inflateSync(@_) == Z_OK) + ? STATUS_OK + : STATUS_ERROR ; +} + + +sub getLastBlockOffset +{ + my $self = shift ; + $self->{Inf}->getLastBlockOffset(); +} + +sub getEndOffset +{ + my $self = shift ; + $self->{Inf}->getEndOffset(); +} + +sub resetLastBlockByte +{ + my $self = shift ; + $self->{Inf}->resetLastBlockByte(@_); +} + +sub createDeflateStream +{ + my $self = shift ; + my $deflate = $self->{Inf}->createDeflateStream(@_); + return bless {'Def' => $deflate, + 'CompSize' => 0, + 'UnCompSize' => 0, + 'Error' => '', + }, 'IO::Compress::Adapter::Deflate'; +} + +1; + + +__END__ + diff --git a/Master/tlpkg/tlperl/lib/IO/Uncompress/AnyInflate.pm b/Master/tlpkg/tlperl/lib/IO/Uncompress/AnyInflate.pm new file mode 100644 index 00000000000..68038f5d374 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Uncompress/AnyInflate.pm @@ -0,0 +1,987 @@ +package IO::Uncompress::AnyInflate ; + +# for RFC1950, RFC1951 or RFC1952 + +use strict; +use warnings; +use bytes; + +use IO::Compress::Base::Common 2.024 qw(createSelfTiedObject); + +use IO::Uncompress::Adapter::Inflate 2.024 (); + + +use IO::Uncompress::Base 2.024 ; +use IO::Uncompress::Gunzip 2.024 ; +use IO::Uncompress::Inflate 2.024 ; +use IO::Uncompress::RawInflate 2.024 ; +use IO::Uncompress::Unzip 2.024 ; + +require Exporter ; + +our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, $AnyInflateError); + +$VERSION = '2.024'; +$AnyInflateError = ''; + +@ISA = qw( Exporter IO::Uncompress::Base ); +@EXPORT_OK = qw( $AnyInflateError anyinflate ) ; +%EXPORT_TAGS = %IO::Uncompress::Base::DEFLATE_CONSTANTS ; +push @{ $EXPORT_TAGS{all} }, @EXPORT_OK ; +Exporter::export_ok_tags('all'); + +# TODO - allow the user to pick a set of the three formats to allow +# or just assume want to auto-detect any of the three formats. + +sub new +{ + my $class = shift ; + my $obj = createSelfTiedObject($class, \$AnyInflateError); + $obj->_create(undef, 0, @_); +} + +sub anyinflate +{ + my $obj = createSelfTiedObject(undef, \$AnyInflateError); + return $obj->_inf(@_) ; +} + +sub getExtraParams +{ + use IO::Compress::Base::Common 2.024 qw(:Parse); + return ( 'RawInflate' => [1, 1, Parse_boolean, 0] ) ; +} + +sub ckParams +{ + my $self = shift ; + my $got = shift ; + + # any always needs both crc32 and adler32 + $got->value('CRC32' => 1); + $got->value('ADLER32' => 1); + + return 1; +} + +sub mkUncomp +{ + my $self = shift ; + my $got = shift ; + + my ($obj, $errstr, $errno) = IO::Uncompress::Adapter::Inflate::mkUncompObject(); + + return $self->saveErrorString(undef, $errstr, $errno) + if ! defined $obj; + + *$self->{Uncomp} = $obj; + + my @possible = qw( Inflate Gunzip Unzip ); + unshift @possible, 'RawInflate' + if 1 || $got->value('RawInflate'); + + my $magic = $self->ckMagic( @possible ); + + if ($magic) { + *$self->{Info} = $self->readHeader($magic) + or return undef ; + + return 1; + } + + return 0 ; +} + + + +sub ckMagic +{ + my $self = shift; + my @names = @_ ; + + my $keep = ref $self ; + for my $class ( map { "IO::Uncompress::$_" } @names) + { + bless $self => $class; + my $magic = $self->ckMagic(); + + if ($magic) + { + #bless $self => $class; + return $magic ; + } + + $self->pushBack(*$self->{HeaderPending}) ; + *$self->{HeaderPending} = '' ; + } + + bless $self => $keep; + return undef; +} + +1 ; + +__END__ + + +=head1 NAME + +IO::Uncompress::AnyInflate - Uncompress zlib-based (zip, gzip) file/buffer + +=head1 SYNOPSIS + + use IO::Uncompress::AnyInflate qw(anyinflate $AnyInflateError) ; + + my $status = anyinflate $input => $output [,OPTS] + or die "anyinflate failed: $AnyInflateError\n"; + + my $z = new IO::Uncompress::AnyInflate $input [OPTS] + or die "anyinflate failed: $AnyInflateError\n"; + + $status = $z->read($buffer) + $status = $z->read($buffer, $length) + $status = $z->read($buffer, $length, $offset) + $line = $z->getline() + $char = $z->getc() + $char = $z->ungetc() + $char = $z->opened() + + $status = $z->inflateSync() + + $data = $z->trailingData() + $status = $z->nextStream() + $data = $z->getHeaderInfo() + $z->tell() + $z->seek($position, $whence) + $z->binmode() + $z->fileno() + $z->eof() + $z->close() + + $AnyInflateError ; + + # IO::File mode + + <$z> + read($z, $buffer); + read($z, $buffer, $length); + read($z, $buffer, $length, $offset); + tell($z) + seek($z, $position, $whence) + binmode($z) + fileno($z) + eof($z) + close($z) + +=head1 DESCRIPTION + +This module provides a Perl interface that allows the reading of +files/buffers that have been compressed in a number of formats that use the +zlib compression library. + +The formats supported are + +=over 5 + +=item RFC 1950 + +=item RFC 1951 (optionally) + +=item gzip (RFC 1952) + +=item zip + +=back + +The module will auto-detect which, if any, of the supported +compression formats is being used. + +=head1 Functional Interface + +A top-level function, C<anyinflate>, is provided to carry out +"one-shot" uncompression between buffers and/or files. For finer +control over the uncompression process, see the L</"OO Interface"> +section. + + use IO::Uncompress::AnyInflate qw(anyinflate $AnyInflateError) ; + + anyinflate $input => $output [,OPTS] + or die "anyinflate failed: $AnyInflateError\n"; + +The functional interface needs Perl5.005 or better. + +=head2 anyinflate $input => $output [, OPTS] + +C<anyinflate> expects at least two parameters, C<$input> and C<$output>. + +=head3 The C<$input> parameter + +The parameter, C<$input>, is used to define the source of +the compressed data. + +It can take one of the following forms: + +=over 5 + +=item A filename + +If the C<$input> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for reading and the input data +will be read from it. + +=item A filehandle + +If the C<$input> parameter is a filehandle, the input data will be +read from it. +The string '-' can be used as an alias for standard input. + +=item A scalar reference + +If C<$input> is a scalar reference, the input data will be read +from C<$$input>. + +=item An array reference + +If C<$input> is an array reference, each element in the array must be a +filename. + +The input data will be read from each file in turn. + +The complete array will be walked to ensure that it only +contains valid filenames before any data is uncompressed. + +=item An Input FileGlob string + +If C<$input> is a string that is delimited by the characters "<" and ">" +C<anyinflate> will assume that it is an I<input fileglob string>. The +input is the list of files that match the fileglob. + +If the fileglob does not match any files ... + +See L<File::GlobMapper|File::GlobMapper> for more details. + +=back + +If the C<$input> parameter is any other type, C<undef> will be returned. + +=head3 The C<$output> parameter + +The parameter C<$output> is used to control the destination of the +uncompressed data. This parameter can take one of these forms. + +=over 5 + +=item A filename + +If the C<$output> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for writing and the uncompressed +data will be written to it. + +=item A filehandle + +If the C<$output> parameter is a filehandle, the uncompressed data +will be written to it. +The string '-' can be used as an alias for standard output. + +=item A scalar reference + +If C<$output> is a scalar reference, the uncompressed data will be +stored in C<$$output>. + +=item An Array Reference + +If C<$output> is an array reference, the uncompressed data will be +pushed onto the array. + +=item An Output FileGlob + +If C<$output> is a string that is delimited by the characters "<" and ">" +C<anyinflate> will assume that it is an I<output fileglob string>. The +output is the list of files that match the fileglob. + +When C<$output> is an fileglob string, C<$input> must also be a fileglob +string. Anything else is an error. + +=back + +If the C<$output> parameter is any other type, C<undef> will be returned. + +=head2 Notes + +When C<$input> maps to multiple compressed files/buffers and C<$output> is +a single file/buffer, after uncompression C<$output> will contain a +concatenation of all the uncompressed data from each of the input +files/buffers. + +=head2 Optional Parameters + +Unless specified below, the optional parameters for C<anyinflate>, +C<OPTS>, are the same as those used with the OO interface defined in the +L</"Constructor Options"> section below. + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option applies to any input or output data streams to +C<anyinflate> that are filehandles. + +If C<AutoClose> is specified, and the value is true, it will result in all +input and/or output filehandles being closed once C<anyinflate> has +completed. + +This parameter defaults to 0. + +=item C<< BinModeOut => 0|1 >> + +When writing to a file or filehandle, set C<binmode> before writing to the +file. + +Defaults to 0. + +=item C<< Append => 0|1 >> + +The behaviour of this option is dependent on the type of output data +stream. + +=over 5 + +=item * A Buffer + +If C<Append> is enabled, all uncompressed data will be append to the end of +the output buffer. Otherwise the output buffer will be cleared before any +uncompressed data is written to it. + +=item * A Filename + +If C<Append> is enabled, the file will be opened in append mode. Otherwise +the contents of the file, if any, will be truncated before any uncompressed +data is written to it. + +=item * A Filehandle + +If C<Append> is enabled, the filehandle will be positioned to the end of +the file via a call to C<seek> before any uncompressed data is +written to it. Otherwise the file pointer will not be moved. + +=back + +When C<Append> is specified, and set to true, it will I<append> all uncompressed +data to the output data stream. + +So when the output is a filehandle it will carry out a seek to the eof +before writing any uncompressed data. If the output is a filename, it will be opened for +appending. If the output is a buffer, all uncompressed data will be appened to +the existing buffer. + +Conversely when C<Append> is not specified, or it is present and is set to +false, it will operate as follows. + +When the output is a filename, it will truncate the contents of the file +before writing any uncompressed data. If the output is a filehandle +its position will not be changed. If the output is a buffer, it will be +wiped before any uncompressed data is output. + +Defaults to 0. + +=item C<< MultiStream => 0|1 >> + +If the input file/buffer contains multiple compressed data streams, this +option will uncompress the whole lot as a single data stream. + +Defaults to 0. + +=item C<< TrailingData => $scalar >> + +Returns the data, if any, that is present immediately after the compressed +data stream once uncompression is complete. + +This option can be used when there is useful information immediately +following the compressed data stream, and you don't know the length of the +compressed data stream. + +If the input is a buffer, C<trailingData> will return everything from the +end of the compressed data stream to the end of the buffer. + +If the input is a filehandle, C<trailingData> will return the data that is +left in the filehandle input buffer once the end of the compressed data +stream has been reached. You can then use the filehandle to read the rest +of the input file. + +Don't bother using C<trailingData> if the input is a filename. + +If you know the length of the compressed data stream before you start +uncompressing, you can avoid having to use C<trailingData> by setting the +C<InputLength> option. + +=back + +=head2 Examples + +To read the contents of the file C<file1.txt.Compressed> and write the +uncompressed data to the file C<file1.txt>. + + use strict ; + use warnings ; + use IO::Uncompress::AnyInflate qw(anyinflate $AnyInflateError) ; + + my $input = "file1.txt.Compressed"; + my $output = "file1.txt"; + anyinflate $input => $output + or die "anyinflate failed: $AnyInflateError\n"; + +To read from an existing Perl filehandle, C<$input>, and write the +uncompressed data to a buffer, C<$buffer>. + + use strict ; + use warnings ; + use IO::Uncompress::AnyInflate qw(anyinflate $AnyInflateError) ; + use IO::File ; + + my $input = new IO::File "<file1.txt.Compressed" + or die "Cannot open 'file1.txt.Compressed': $!\n" ; + my $buffer ; + anyinflate $input => \$buffer + or die "anyinflate failed: $AnyInflateError\n"; + +To uncompress all files in the directory "/my/home" that match "*.txt.Compressed" and store the compressed data in the same directory + + use strict ; + use warnings ; + use IO::Uncompress::AnyInflate qw(anyinflate $AnyInflateError) ; + + anyinflate '</my/home/*.txt.Compressed>' => '</my/home/#1.txt>' + or die "anyinflate failed: $AnyInflateError\n"; + +and if you want to compress each file one at a time, this will do the trick + + use strict ; + use warnings ; + use IO::Uncompress::AnyInflate qw(anyinflate $AnyInflateError) ; + + for my $input ( glob "/my/home/*.txt.Compressed" ) + { + my $output = $input; + $output =~ s/.Compressed// ; + anyinflate $input => $output + or die "Error compressing '$input': $AnyInflateError\n"; + } + +=head1 OO Interface + +=head2 Constructor + +The format of the constructor for IO::Uncompress::AnyInflate is shown below + + my $z = new IO::Uncompress::AnyInflate $input [OPTS] + or die "IO::Uncompress::AnyInflate failed: $AnyInflateError\n"; + +Returns an C<IO::Uncompress::AnyInflate> object on success and undef on failure. +The variable C<$AnyInflateError> will contain an error message on failure. + +If you are running Perl 5.005 or better the object, C<$z>, returned from +IO::Uncompress::AnyInflate can be used exactly like an L<IO::File|IO::File> filehandle. +This means that all normal input file operations can be carried out with +C<$z>. For example, to read a line from a compressed file/buffer you can +use either of these forms + + $line = $z->getline(); + $line = <$z>; + +The mandatory parameter C<$input> is used to determine the source of the +compressed data. This parameter can take one of three forms. + +=over 5 + +=item A filename + +If the C<$input> parameter is a scalar, it is assumed to be a filename. This +file will be opened for reading and the compressed data will be read from it. + +=item A filehandle + +If the C<$input> parameter is a filehandle, the compressed data will be +read from it. +The string '-' can be used as an alias for standard input. + +=item A scalar reference + +If C<$input> is a scalar reference, the compressed data will be read from +C<$$output>. + +=back + +=head2 Constructor Options + +The option names defined below are case insensitive and can be optionally +prefixed by a '-'. So all of the following are valid + + -AutoClose + -autoclose + AUTOCLOSE + autoclose + +OPTS is a combination of the following options: + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option is only valid when the C<$input> parameter is a filehandle. If +specified, and the value is true, it will result in the file being closed once +either the C<close> method is called or the IO::Uncompress::AnyInflate object is +destroyed. + +This parameter defaults to 0. + +=item C<< MultiStream => 0|1 >> + +Allows multiple concatenated compressed streams to be treated as a single +compressed stream. Decompression will stop once either the end of the +file/buffer is reached, an error is encountered (premature eof, corrupt +compressed data) or the end of a stream is not immediately followed by the +start of another stream. + +This parameter defaults to 0. + +=item C<< Prime => $string >> + +This option will uncompress the contents of C<$string> before processing the +input file/buffer. + +This option can be useful when the compressed data is embedded in another +file/data structure and it is not possible to work out where the compressed +data begins without having to read the first few bytes. If this is the +case, the uncompression can be I<primed> with these bytes using this +option. + +=item C<< Transparent => 0|1 >> + +If this option is set and the input file/buffer is not compressed data, +the module will allow reading of it anyway. + +In addition, if the input file/buffer does contain compressed data and +there is non-compressed data immediately following it, setting this option +will make this module treat the whole file/bufffer as a single data stream. + +This option defaults to 1. + +=item C<< BlockSize => $num >> + +When reading the compressed input data, IO::Uncompress::AnyInflate will read it in +blocks of C<$num> bytes. + +This option defaults to 4096. + +=item C<< InputLength => $size >> + +When present this option will limit the number of compressed bytes read +from the input file/buffer to C<$size>. This option can be used in the +situation where there is useful data directly after the compressed data +stream and you know beforehand the exact length of the compressed data +stream. + +This option is mostly used when reading from a filehandle, in which case +the file pointer will be left pointing to the first byte directly after the +compressed data stream. + +This option defaults to off. + +=item C<< Append => 0|1 >> + +This option controls what the C<read> method does with uncompressed data. + +If set to 1, all uncompressed data will be appended to the output parameter +of the C<read> method. + +If set to 0, the contents of the output parameter of the C<read> method +will be overwritten by the uncompressed data. + +Defaults to 0. + +=item C<< Strict => 0|1 >> + +This option controls whether the extra checks defined below are used when +carrying out the decompression. When Strict is on, the extra tests are +carried out, when Strict is off they are not. + +The default for this option is off. + +If the input is an RFC 1950 data stream, the following will be checked: + +=over 5 + +=item 1 + +The ADLER32 checksum field must be present. + +=item 2 + +The value of the ADLER32 field read must match the adler32 value of the +uncompressed data actually contained in the file. + +=back + +If the input is a gzip (RFC 1952) data stream, the following will be checked: + +=over 5 + +=item 1 + +If the FHCRC bit is set in the gzip FLG header byte, the CRC16 bytes in the +header must match the crc16 value of the gzip header actually read. + +=item 2 + +If the gzip header contains a name field (FNAME) it consists solely of ISO +8859-1 characters. + +=item 3 + +If the gzip header contains a comment field (FCOMMENT) it consists solely +of ISO 8859-1 characters plus line-feed. + +=item 4 + +If the gzip FEXTRA header field is present it must conform to the sub-field +structure as defined in RFC 1952. + +=item 5 + +The CRC32 and ISIZE trailer fields must be present. + +=item 6 + +The value of the CRC32 field read must match the crc32 value of the +uncompressed data actually contained in the gzip file. + +=item 7 + +The value of the ISIZE fields read must match the length of the +uncompressed data actually read from the file. + +=back + +=item C<< RawInflate => 0|1 >> + +When auto-detecting the compressed format, try to test for raw-deflate (RFC +1951) content using the C<IO::Uncompress::RawInflate> module. + +The reason this is not default behaviour is because RFC 1951 content can +only be detected by attempting to uncompress it. This process is error +prone and can result is false positives. + +Defaults to 0. + +=item C<< ParseExtra => 0|1 >> +If the gzip FEXTRA header field is present and this option is set, it will +force the module to check that it conforms to the sub-field structure as +defined in RFC 1952. + +If the C<Strict> is on it will automatically enable this option. + +Defaults to 0. + +=back + +=head2 Examples + +TODO + +=head1 Methods + +=head2 read + +Usage is + + $status = $z->read($buffer) + +Reads a block of compressed data (the size the the compressed block is +determined by the C<Buffer> option in the constructor), uncompresses it and +writes any uncompressed data into C<$buffer>. If the C<Append> parameter is +set in the constructor, the uncompressed data will be appended to the +C<$buffer> parameter. Otherwise C<$buffer> will be overwritten. + +Returns the number of uncompressed bytes written to C<$buffer>, zero if eof +or a negative number on error. + +=head2 read + +Usage is + + $status = $z->read($buffer, $length) + $status = $z->read($buffer, $length, $offset) + + $status = read($z, $buffer, $length) + $status = read($z, $buffer, $length, $offset) + +Attempt to read C<$length> bytes of uncompressed data into C<$buffer>. + +The main difference between this form of the C<read> method and the +previous one, is that this one will attempt to return I<exactly> C<$length> +bytes. The only circumstances that this function will not is if end-of-file +or an IO error is encountered. + +Returns the number of uncompressed bytes written to C<$buffer>, zero if eof +or a negative number on error. + +=head2 getline + +Usage is + + $line = $z->getline() + $line = <$z> + +Reads a single line. + +This method fully supports the use of of the variable C<$/> (or +C<$INPUT_RECORD_SEPARATOR> or C<$RS> when C<English> is in use) to +determine what constitutes an end of line. Paragraph mode, record mode and +file slurp mode are all supported. + +=head2 getc + +Usage is + + $char = $z->getc() + +Read a single character. + +=head2 ungetc + +Usage is + + $char = $z->ungetc($string) + +=head2 inflateSync + +Usage is + + $status = $z->inflateSync() + +TODO + +=head2 getHeaderInfo + +Usage is + + $hdr = $z->getHeaderInfo(); + @hdrs = $z->getHeaderInfo(); + +This method returns either a hash reference (in scalar context) or a list +or hash references (in array context) that contains information about each +of the header fields in the compressed data stream(s). + +=head2 tell + +Usage is + + $z->tell() + tell $z + +Returns the uncompressed file offset. + +=head2 eof + +Usage is + + $z->eof(); + eof($z); + +Returns true if the end of the compressed input stream has been reached. + +=head2 seek + + $z->seek($position, $whence); + seek($z, $position, $whence); + +Provides a sub-set of the C<seek> functionality, with the restriction +that it is only legal to seek forward in the input file/buffer. +It is a fatal error to attempt to seek backward. + +The C<$whence> parameter takes one the usual values, namely SEEK_SET, +SEEK_CUR or SEEK_END. + +Returns 1 on success, 0 on failure. + +=head2 binmode + +Usage is + + $z->binmode + binmode $z ; + +This is a noop provided for completeness. + +=head2 opened + + $z->opened() + +Returns true if the object currently refers to a opened file/buffer. + +=head2 autoflush + + my $prev = $z->autoflush() + my $prev = $z->autoflush(EXPR) + +If the C<$z> object is associated with a file or a filehandle, this method +returns the current autoflush setting for the underlying filehandle. If +C<EXPR> is present, and is non-zero, it will enable flushing after every +write/print operation. + +If C<$z> is associated with a buffer, this method has no effect and always +returns C<undef>. + +B<Note> that the special variable C<$|> B<cannot> be used to set or +retrieve the autoflush setting. + +=head2 input_line_number + + $z->input_line_number() + $z->input_line_number(EXPR) + +Returns the current uncompressed line number. If C<EXPR> is present it has +the effect of setting the line number. Note that setting the line number +does not change the current position within the file/buffer being read. + +The contents of C<$/> are used to to determine what constitutes a line +terminator. + +=head2 fileno + + $z->fileno() + fileno($z) + +If the C<$z> object is associated with a file or a filehandle, C<fileno> +will return the underlying file descriptor. Once the C<close> method is +called C<fileno> will return C<undef>. + +If the C<$z> object is is associated with a buffer, this method will return +C<undef>. + +=head2 close + + $z->close() ; + close $z ; + +Closes the output file/buffer. + +For most versions of Perl this method will be automatically invoked if +the IO::Uncompress::AnyInflate object is destroyed (either explicitly or by the +variable with the reference to the object going out of scope). The +exceptions are Perl versions 5.005 through 5.00504 and 5.8.0. In +these cases, the C<close> method will be called automatically, but +not until global destruction of all live objects when the program is +terminating. + +Therefore, if you want your scripts to be able to run on all versions +of Perl, you should call C<close> explicitly and not rely on automatic +closing. + +Returns true on success, otherwise 0. + +If the C<AutoClose> option has been enabled when the IO::Uncompress::AnyInflate +object was created, and the object is associated with a file, the +underlying file will also be closed. + +=head2 nextStream + +Usage is + + my $status = $z->nextStream(); + +Skips to the next compressed data stream in the input file/buffer. If a new +compressed data stream is found, the eof marker will be cleared and C<$.> +will be reset to 0. + +Returns 1 if a new stream was found, 0 if none was found, and -1 if an +error was encountered. + +=head2 trailingData + +Usage is + + my $data = $z->trailingData(); + +Returns the data, if any, that is present immediately after the compressed +data stream once uncompression is complete. It only makes sense to call +this method once the end of the compressed data stream has been +encountered. + +This option can be used when there is useful information immediately +following the compressed data stream, and you don't know the length of the +compressed data stream. + +If the input is a buffer, C<trailingData> will return everything from the +end of the compressed data stream to the end of the buffer. + +If the input is a filehandle, C<trailingData> will return the data that is +left in the filehandle input buffer once the end of the compressed data +stream has been reached. You can then use the filehandle to read the rest +of the input file. + +Don't bother using C<trailingData> if the input is a filename. + +If you know the length of the compressed data stream before you start +uncompressing, you can avoid having to use C<trailingData> by setting the +C<InputLength> option in the constructor. + +=head1 Importing + +No symbolic constants are required by this IO::Uncompress::AnyInflate at present. + +=over 5 + +=item :all + +Imports C<anyinflate> and C<$AnyInflateError>. +Same as doing this + + use IO::Uncompress::AnyInflate qw(anyinflate $AnyInflateError) ; + +=back + +=head1 EXAMPLES + +=head2 Working with Net::FTP + +See L<IO::Uncompress::AnyInflate::FAQ|IO::Uncompress::AnyInflate::FAQ/"Compressed files and Net::FTP"> + +=head1 SEE ALSO + +L<Compress::Zlib>, L<IO::Compress::Gzip>, L<IO::Uncompress::Gunzip>, L<IO::Compress::Deflate>, L<IO::Uncompress::Inflate>, L<IO::Compress::RawDeflate>, L<IO::Uncompress::RawInflate>, L<IO::Compress::Bzip2>, L<IO::Uncompress::Bunzip2>, L<IO::Compress::Lzma>, L<IO::Uncompress::UnLzma>, L<IO::Compress::Xz>, L<IO::Uncompress::UnXz>, L<IO::Compress::Lzop>, L<IO::Uncompress::UnLzop>, L<IO::Compress::Lzf>, L<IO::Uncompress::UnLzf>, L<IO::Uncompress::AnyUncompress> + +L<Compress::Zlib::FAQ|Compress::Zlib::FAQ> + +L<File::GlobMapper|File::GlobMapper>, L<Archive::Zip|Archive::Zip>, +L<Archive::Tar|Archive::Tar>, +L<IO::Zlib|IO::Zlib> + +For RFC 1950, 1951 and 1952 see +F<http://www.faqs.org/rfcs/rfc1950.html>, +F<http://www.faqs.org/rfcs/rfc1951.html> and +F<http://www.faqs.org/rfcs/rfc1952.html> + +The I<zlib> compression library was written by Jean-loup Gailly +F<gzip@prep.ai.mit.edu> and Mark Adler F<madler@alumni.caltech.edu>. + +The primary site for the I<zlib> compression library is +F<http://www.zlib.org>. + +The primary site for gzip is F<http://www.gzip.org>. + +=head1 AUTHOR + +This module was written by Paul Marquess, F<pmqs@cpan.org>. + +=head1 MODIFICATION HISTORY + +See the Changes file. + +=head1 COPYRIGHT AND LICENSE + +Copyright (c) 2005-2010 Paul Marquess. All rights reserved. + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + diff --git a/Master/tlpkg/tlperl/lib/IO/Uncompress/AnyUncompress.pm b/Master/tlpkg/tlperl/lib/IO/Uncompress/AnyUncompress.pm new file mode 100644 index 00000000000..5984921e25b --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Uncompress/AnyUncompress.pm @@ -0,0 +1,1018 @@ +package IO::Uncompress::AnyUncompress ; + +use strict; +use warnings; +use bytes; + +use IO::Compress::Base::Common 2.024 qw(createSelfTiedObject); + +use IO::Uncompress::Base 2.024 ; + + +require Exporter ; + +our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, $AnyUncompressError); + +$VERSION = '2.024'; +$AnyUncompressError = ''; + +@ISA = qw( Exporter IO::Uncompress::Base ); +@EXPORT_OK = qw( $AnyUncompressError anyuncompress ) ; +%EXPORT_TAGS = %IO::Uncompress::Base::DEFLATE_CONSTANTS ; +push @{ $EXPORT_TAGS{all} }, @EXPORT_OK ; +Exporter::export_ok_tags('all'); + +# TODO - allow the user to pick a set of the three formats to allow +# or just assume want to auto-detect any of the three formats. + +BEGIN +{ + eval ' use IO::Uncompress::Adapter::Inflate 2.024 ;'; + eval ' use IO::Uncompress::Adapter::Bunzip2 2.024 ;'; + eval ' use IO::Uncompress::Adapter::LZO 2.024 ;'; + eval ' use IO::Uncompress::Adapter::Lzf 2.024 ;'; + eval ' use IO::Uncompress::Adapter::UnLzma 2.020 ;'; + eval ' use IO::Uncompress::Adapter::UnXz 2.020 ;'; + + eval ' use IO::Uncompress::Bunzip2 2.024 ;'; + eval ' use IO::Uncompress::UnLzop 2.024 ;'; + eval ' use IO::Uncompress::Gunzip 2.024 ;'; + eval ' use IO::Uncompress::Inflate 2.024 ;'; + eval ' use IO::Uncompress::RawInflate 2.024 ;'; + eval ' use IO::Uncompress::Unzip 2.024 ;'; + eval ' use IO::Uncompress::UnLzf 2.024 ;'; + eval ' use IO::Uncompress::UnLzma 2.024 ;'; + eval ' use IO::Uncompress::UnXz 2.024 ;'; +} + +sub new +{ + my $class = shift ; + my $obj = createSelfTiedObject($class, \$AnyUncompressError); + $obj->_create(undef, 0, @_); +} + +sub anyuncompress +{ + my $obj = createSelfTiedObject(undef, \$AnyUncompressError); + return $obj->_inf(@_) ; +} + +sub getExtraParams +{ + use IO::Compress::Base::Common 2.024 qw(:Parse); + return ( 'RawInflate' => [1, 1, Parse_boolean, 0] , + 'UnLzma' => [1, 1, Parse_boolean, 0] ) ; +} + +sub ckParams +{ + my $self = shift ; + my $got = shift ; + + # any always needs both crc32 and adler32 + $got->value('CRC32' => 1); + $got->value('ADLER32' => 1); + + return 1; +} + +sub mkUncomp +{ + my $self = shift ; + my $got = shift ; + + my $magic ; + + # try zlib first + if (defined $IO::Uncompress::RawInflate::VERSION ) + { + my ($obj, $errstr, $errno) = IO::Uncompress::Adapter::Inflate::mkUncompObject(); + + return $self->saveErrorString(undef, $errstr, $errno) + if ! defined $obj; + + *$self->{Uncomp} = $obj; + + my @possible = qw( Inflate Gunzip Unzip ); + unshift @possible, 'RawInflate' + if $got->value('RawInflate'); + + $magic = $self->ckMagic( @possible ); + + if ($magic) { + *$self->{Info} = $self->readHeader($magic) + or return undef ; + + return 1; + } + } + + if (defined $IO::Uncompress::UnLzma::VERSION && $got->value('UnLzma')) + { + my ($obj, $errstr, $errno) = IO::Uncompress::Adapter::UnLzma::mkUncompObject(); + + return $self->saveErrorString(undef, $errstr, $errno) + if ! defined $obj; + + *$self->{Uncomp} = $obj; + + my @possible = qw( UnLzma ); + #unshift @possible, 'RawInflate' + # if $got->value('RawInflate'); + + if ( *$self->{Info} = $self->ckMagic( @possible )) + { + return 1; + } + } + + if (defined $IO::Uncompress::UnXz::VERSION and + $magic = $self->ckMagic('UnXz')) { + *$self->{Info} = $self->readHeader($magic) + or return undef ; + + my ($obj, $errstr, $errno) = + IO::Uncompress::Adapter::UnXz::mkUncompObject(); + + return $self->saveErrorString(undef, $errstr, $errno) + if ! defined $obj; + + *$self->{Uncomp} = $obj; + + return 1; + } + + if (defined $IO::Uncompress::Bunzip2::VERSION and + $magic = $self->ckMagic('Bunzip2')) { + *$self->{Info} = $self->readHeader($magic) + or return undef ; + + my ($obj, $errstr, $errno) = IO::Uncompress::Adapter::Bunzip2::mkUncompObject(); + + return $self->saveErrorString(undef, $errstr, $errno) + if ! defined $obj; + + *$self->{Uncomp} = $obj; + + return 1; + } + + if (defined $IO::Uncompress::UnLzop::VERSION and + $magic = $self->ckMagic('UnLzop')) { + + *$self->{Info} = $self->readHeader($magic) + or return undef ; + + my ($obj, $errstr, $errno) = IO::Uncompress::Adapter::LZO::mkUncompObject(); + + return $self->saveErrorString(undef, $errstr, $errno) + if ! defined $obj; + + *$self->{Uncomp} = $obj; + + return 1; + } + + if (defined $IO::Uncompress::UnLzf::VERSION and + $magic = $self->ckMagic('UnLzf')) { + + *$self->{Info} = $self->readHeader($magic) + or return undef ; + + my ($obj, $errstr, $errno) = IO::Uncompress::Adapter::Lzf::mkUncompObject(); + + return $self->saveErrorString(undef, $errstr, $errno) + if ! defined $obj; + + *$self->{Uncomp} = $obj; + + return 1; + } + + return 0 ; +} + + + +sub ckMagic +{ + my $self = shift; + my @names = @_ ; + + my $keep = ref $self ; + for my $class ( map { "IO::Uncompress::$_" } @names) + { + bless $self => $class; + my $magic = $self->ckMagic(); + + if ($magic) + { + #bless $self => $class; + return $magic ; + } + + $self->pushBack(*$self->{HeaderPending}) ; + *$self->{HeaderPending} = '' ; + } + + bless $self => $keep; + return undef; +} + +1 ; + +__END__ + + +=head1 NAME + +IO::Uncompress::AnyUncompress - Uncompress gzip, zip, bzip2 or lzop file/buffer + +=head1 SYNOPSIS + + use IO::Uncompress::AnyUncompress qw(anyuncompress $AnyUncompressError) ; + + my $status = anyuncompress $input => $output [,OPTS] + or die "anyuncompress failed: $AnyUncompressError\n"; + + my $z = new IO::Uncompress::AnyUncompress $input [OPTS] + or die "anyuncompress failed: $AnyUncompressError\n"; + + $status = $z->read($buffer) + $status = $z->read($buffer, $length) + $status = $z->read($buffer, $length, $offset) + $line = $z->getline() + $char = $z->getc() + $char = $z->ungetc() + $char = $z->opened() + + $data = $z->trailingData() + $status = $z->nextStream() + $data = $z->getHeaderInfo() + $z->tell() + $z->seek($position, $whence) + $z->binmode() + $z->fileno() + $z->eof() + $z->close() + + $AnyUncompressError ; + + # IO::File mode + + <$z> + read($z, $buffer); + read($z, $buffer, $length); + read($z, $buffer, $length, $offset); + tell($z) + seek($z, $position, $whence) + binmode($z) + fileno($z) + eof($z) + close($z) + +=head1 DESCRIPTION + +This module provides a Perl interface that allows the reading of +files/buffers that have been compressed with a variety of compression +libraries. + +The formats supported are: + +=over 5 + +=item RFC 1950 + +=item RFC 1951 (optionally) + +=item gzip (RFC 1952) + +=item zip + +=item bzip2 + +=item lzop + +=item lzf + +=item lzma + +=item xz + +=back + +The module will auto-detect which, if any, of the supported +compression formats is being used. + +=head1 Functional Interface + +A top-level function, C<anyuncompress>, is provided to carry out +"one-shot" uncompression between buffers and/or files. For finer +control over the uncompression process, see the L</"OO Interface"> +section. + + use IO::Uncompress::AnyUncompress qw(anyuncompress $AnyUncompressError) ; + + anyuncompress $input => $output [,OPTS] + or die "anyuncompress failed: $AnyUncompressError\n"; + +The functional interface needs Perl5.005 or better. + +=head2 anyuncompress $input => $output [, OPTS] + +C<anyuncompress> expects at least two parameters, C<$input> and C<$output>. + +=head3 The C<$input> parameter + +The parameter, C<$input>, is used to define the source of +the compressed data. + +It can take one of the following forms: + +=over 5 + +=item A filename + +If the C<$input> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for reading and the input data +will be read from it. + +=item A filehandle + +If the C<$input> parameter is a filehandle, the input data will be +read from it. +The string '-' can be used as an alias for standard input. + +=item A scalar reference + +If C<$input> is a scalar reference, the input data will be read +from C<$$input>. + +=item An array reference + +If C<$input> is an array reference, each element in the array must be a +filename. + +The input data will be read from each file in turn. + +The complete array will be walked to ensure that it only +contains valid filenames before any data is uncompressed. + +=item An Input FileGlob string + +If C<$input> is a string that is delimited by the characters "<" and ">" +C<anyuncompress> will assume that it is an I<input fileglob string>. The +input is the list of files that match the fileglob. + +If the fileglob does not match any files ... + +See L<File::GlobMapper|File::GlobMapper> for more details. + +=back + +If the C<$input> parameter is any other type, C<undef> will be returned. + +=head3 The C<$output> parameter + +The parameter C<$output> is used to control the destination of the +uncompressed data. This parameter can take one of these forms. + +=over 5 + +=item A filename + +If the C<$output> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for writing and the uncompressed +data will be written to it. + +=item A filehandle + +If the C<$output> parameter is a filehandle, the uncompressed data +will be written to it. +The string '-' can be used as an alias for standard output. + +=item A scalar reference + +If C<$output> is a scalar reference, the uncompressed data will be +stored in C<$$output>. + +=item An Array Reference + +If C<$output> is an array reference, the uncompressed data will be +pushed onto the array. + +=item An Output FileGlob + +If C<$output> is a string that is delimited by the characters "<" and ">" +C<anyuncompress> will assume that it is an I<output fileglob string>. The +output is the list of files that match the fileglob. + +When C<$output> is an fileglob string, C<$input> must also be a fileglob +string. Anything else is an error. + +=back + +If the C<$output> parameter is any other type, C<undef> will be returned. + +=head2 Notes + +When C<$input> maps to multiple compressed files/buffers and C<$output> is +a single file/buffer, after uncompression C<$output> will contain a +concatenation of all the uncompressed data from each of the input +files/buffers. + +=head2 Optional Parameters + +Unless specified below, the optional parameters for C<anyuncompress>, +C<OPTS>, are the same as those used with the OO interface defined in the +L</"Constructor Options"> section below. + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option applies to any input or output data streams to +C<anyuncompress> that are filehandles. + +If C<AutoClose> is specified, and the value is true, it will result in all +input and/or output filehandles being closed once C<anyuncompress> has +completed. + +This parameter defaults to 0. + +=item C<< BinModeOut => 0|1 >> + +When writing to a file or filehandle, set C<binmode> before writing to the +file. + +Defaults to 0. + +=item C<< Append => 0|1 >> + +The behaviour of this option is dependent on the type of output data +stream. + +=over 5 + +=item * A Buffer + +If C<Append> is enabled, all uncompressed data will be append to the end of +the output buffer. Otherwise the output buffer will be cleared before any +uncompressed data is written to it. + +=item * A Filename + +If C<Append> is enabled, the file will be opened in append mode. Otherwise +the contents of the file, if any, will be truncated before any uncompressed +data is written to it. + +=item * A Filehandle + +If C<Append> is enabled, the filehandle will be positioned to the end of +the file via a call to C<seek> before any uncompressed data is +written to it. Otherwise the file pointer will not be moved. + +=back + +When C<Append> is specified, and set to true, it will I<append> all uncompressed +data to the output data stream. + +So when the output is a filehandle it will carry out a seek to the eof +before writing any uncompressed data. If the output is a filename, it will be opened for +appending. If the output is a buffer, all uncompressed data will be appened to +the existing buffer. + +Conversely when C<Append> is not specified, or it is present and is set to +false, it will operate as follows. + +When the output is a filename, it will truncate the contents of the file +before writing any uncompressed data. If the output is a filehandle +its position will not be changed. If the output is a buffer, it will be +wiped before any uncompressed data is output. + +Defaults to 0. + +=item C<< MultiStream => 0|1 >> + +If the input file/buffer contains multiple compressed data streams, this +option will uncompress the whole lot as a single data stream. + +Defaults to 0. + +=item C<< TrailingData => $scalar >> + +Returns the data, if any, that is present immediately after the compressed +data stream once uncompression is complete. + +This option can be used when there is useful information immediately +following the compressed data stream, and you don't know the length of the +compressed data stream. + +If the input is a buffer, C<trailingData> will return everything from the +end of the compressed data stream to the end of the buffer. + +If the input is a filehandle, C<trailingData> will return the data that is +left in the filehandle input buffer once the end of the compressed data +stream has been reached. You can then use the filehandle to read the rest +of the input file. + +Don't bother using C<trailingData> if the input is a filename. + +If you know the length of the compressed data stream before you start +uncompressing, you can avoid having to use C<trailingData> by setting the +C<InputLength> option. + +=back + +=head2 Examples + +To read the contents of the file C<file1.txt.Compressed> and write the +uncompressed data to the file C<file1.txt>. + + use strict ; + use warnings ; + use IO::Uncompress::AnyUncompress qw(anyuncompress $AnyUncompressError) ; + + my $input = "file1.txt.Compressed"; + my $output = "file1.txt"; + anyuncompress $input => $output + or die "anyuncompress failed: $AnyUncompressError\n"; + +To read from an existing Perl filehandle, C<$input>, and write the +uncompressed data to a buffer, C<$buffer>. + + use strict ; + use warnings ; + use IO::Uncompress::AnyUncompress qw(anyuncompress $AnyUncompressError) ; + use IO::File ; + + my $input = new IO::File "<file1.txt.Compressed" + or die "Cannot open 'file1.txt.Compressed': $!\n" ; + my $buffer ; + anyuncompress $input => \$buffer + or die "anyuncompress failed: $AnyUncompressError\n"; + +To uncompress all files in the directory "/my/home" that match "*.txt.Compressed" and store the compressed data in the same directory + + use strict ; + use warnings ; + use IO::Uncompress::AnyUncompress qw(anyuncompress $AnyUncompressError) ; + + anyuncompress '</my/home/*.txt.Compressed>' => '</my/home/#1.txt>' + or die "anyuncompress failed: $AnyUncompressError\n"; + +and if you want to compress each file one at a time, this will do the trick + + use strict ; + use warnings ; + use IO::Uncompress::AnyUncompress qw(anyuncompress $AnyUncompressError) ; + + for my $input ( glob "/my/home/*.txt.Compressed" ) + { + my $output = $input; + $output =~ s/.Compressed// ; + anyuncompress $input => $output + or die "Error compressing '$input': $AnyUncompressError\n"; + } + +=head1 OO Interface + +=head2 Constructor + +The format of the constructor for IO::Uncompress::AnyUncompress is shown below + + my $z = new IO::Uncompress::AnyUncompress $input [OPTS] + or die "IO::Uncompress::AnyUncompress failed: $AnyUncompressError\n"; + +Returns an C<IO::Uncompress::AnyUncompress> object on success and undef on failure. +The variable C<$AnyUncompressError> will contain an error message on failure. + +If you are running Perl 5.005 or better the object, C<$z>, returned from +IO::Uncompress::AnyUncompress can be used exactly like an L<IO::File|IO::File> filehandle. +This means that all normal input file operations can be carried out with +C<$z>. For example, to read a line from a compressed file/buffer you can +use either of these forms + + $line = $z->getline(); + $line = <$z>; + +The mandatory parameter C<$input> is used to determine the source of the +compressed data. This parameter can take one of three forms. + +=over 5 + +=item A filename + +If the C<$input> parameter is a scalar, it is assumed to be a filename. This +file will be opened for reading and the compressed data will be read from it. + +=item A filehandle + +If the C<$input> parameter is a filehandle, the compressed data will be +read from it. +The string '-' can be used as an alias for standard input. + +=item A scalar reference + +If C<$input> is a scalar reference, the compressed data will be read from +C<$$output>. + +=back + +=head2 Constructor Options + +The option names defined below are case insensitive and can be optionally +prefixed by a '-'. So all of the following are valid + + -AutoClose + -autoclose + AUTOCLOSE + autoclose + +OPTS is a combination of the following options: + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option is only valid when the C<$input> parameter is a filehandle. If +specified, and the value is true, it will result in the file being closed once +either the C<close> method is called or the IO::Uncompress::AnyUncompress object is +destroyed. + +This parameter defaults to 0. + +=item C<< MultiStream => 0|1 >> + +Allows multiple concatenated compressed streams to be treated as a single +compressed stream. Decompression will stop once either the end of the +file/buffer is reached, an error is encountered (premature eof, corrupt +compressed data) or the end of a stream is not immediately followed by the +start of another stream. + +This parameter defaults to 0. + +=item C<< Prime => $string >> + +This option will uncompress the contents of C<$string> before processing the +input file/buffer. + +This option can be useful when the compressed data is embedded in another +file/data structure and it is not possible to work out where the compressed +data begins without having to read the first few bytes. If this is the +case, the uncompression can be I<primed> with these bytes using this +option. + +=item C<< Transparent => 0|1 >> + +If this option is set and the input file/buffer is not compressed data, +the module will allow reading of it anyway. + +In addition, if the input file/buffer does contain compressed data and +there is non-compressed data immediately following it, setting this option +will make this module treat the whole file/bufffer as a single data stream. + +This option defaults to 1. + +=item C<< BlockSize => $num >> + +When reading the compressed input data, IO::Uncompress::AnyUncompress will read it in +blocks of C<$num> bytes. + +This option defaults to 4096. + +=item C<< InputLength => $size >> + +When present this option will limit the number of compressed bytes read +from the input file/buffer to C<$size>. This option can be used in the +situation where there is useful data directly after the compressed data +stream and you know beforehand the exact length of the compressed data +stream. + +This option is mostly used when reading from a filehandle, in which case +the file pointer will be left pointing to the first byte directly after the +compressed data stream. + +This option defaults to off. + +=item C<< Append => 0|1 >> + +This option controls what the C<read> method does with uncompressed data. + +If set to 1, all uncompressed data will be appended to the output parameter +of the C<read> method. + +If set to 0, the contents of the output parameter of the C<read> method +will be overwritten by the uncompressed data. + +Defaults to 0. + +=item C<< Strict => 0|1 >> + +This option controls whether the extra checks defined below are used when +carrying out the decompression. When Strict is on, the extra tests are +carried out, when Strict is off they are not. + +The default for this option is off. + +=item C<< RawInflate => 0|1 >> + +When auto-detecting the compressed format, try to test for raw-deflate (RFC +1951) content using the C<IO::Uncompress::RawInflate> module. + +The reason this is not default behaviour is because RFC 1951 content can +only be detected by attempting to uncompress it. This process is error +prone and can result is false positives. + +Defaults to 0. + +=item C<< UnLzma => 0|1 >> + +When auto-detecting the compressed format, try to test for lzma_alone +content using the C<IO::Uncompress::UnLzma> module. + +The reason this is not default behaviour is because lzma_alone content can +only be detected by attempting to uncompress it. This process is error +prone and can result is false positives. + +Defaults to 0. + +=back + +=head2 Examples + +TODO + +=head1 Methods + +=head2 read + +Usage is + + $status = $z->read($buffer) + +Reads a block of compressed data (the size the the compressed block is +determined by the C<Buffer> option in the constructor), uncompresses it and +writes any uncompressed data into C<$buffer>. If the C<Append> parameter is +set in the constructor, the uncompressed data will be appended to the +C<$buffer> parameter. Otherwise C<$buffer> will be overwritten. + +Returns the number of uncompressed bytes written to C<$buffer>, zero if eof +or a negative number on error. + +=head2 read + +Usage is + + $status = $z->read($buffer, $length) + $status = $z->read($buffer, $length, $offset) + + $status = read($z, $buffer, $length) + $status = read($z, $buffer, $length, $offset) + +Attempt to read C<$length> bytes of uncompressed data into C<$buffer>. + +The main difference between this form of the C<read> method and the +previous one, is that this one will attempt to return I<exactly> C<$length> +bytes. The only circumstances that this function will not is if end-of-file +or an IO error is encountered. + +Returns the number of uncompressed bytes written to C<$buffer>, zero if eof +or a negative number on error. + +=head2 getline + +Usage is + + $line = $z->getline() + $line = <$z> + +Reads a single line. + +This method fully supports the use of of the variable C<$/> (or +C<$INPUT_RECORD_SEPARATOR> or C<$RS> when C<English> is in use) to +determine what constitutes an end of line. Paragraph mode, record mode and +file slurp mode are all supported. + +=head2 getc + +Usage is + + $char = $z->getc() + +Read a single character. + +=head2 ungetc + +Usage is + + $char = $z->ungetc($string) + +=head2 getHeaderInfo + +Usage is + + $hdr = $z->getHeaderInfo(); + @hdrs = $z->getHeaderInfo(); + +This method returns either a hash reference (in scalar context) or a list +or hash references (in array context) that contains information about each +of the header fields in the compressed data stream(s). + +=head2 tell + +Usage is + + $z->tell() + tell $z + +Returns the uncompressed file offset. + +=head2 eof + +Usage is + + $z->eof(); + eof($z); + +Returns true if the end of the compressed input stream has been reached. + +=head2 seek + + $z->seek($position, $whence); + seek($z, $position, $whence); + +Provides a sub-set of the C<seek> functionality, with the restriction +that it is only legal to seek forward in the input file/buffer. +It is a fatal error to attempt to seek backward. + +The C<$whence> parameter takes one the usual values, namely SEEK_SET, +SEEK_CUR or SEEK_END. + +Returns 1 on success, 0 on failure. + +=head2 binmode + +Usage is + + $z->binmode + binmode $z ; + +This is a noop provided for completeness. + +=head2 opened + + $z->opened() + +Returns true if the object currently refers to a opened file/buffer. + +=head2 autoflush + + my $prev = $z->autoflush() + my $prev = $z->autoflush(EXPR) + +If the C<$z> object is associated with a file or a filehandle, this method +returns the current autoflush setting for the underlying filehandle. If +C<EXPR> is present, and is non-zero, it will enable flushing after every +write/print operation. + +If C<$z> is associated with a buffer, this method has no effect and always +returns C<undef>. + +B<Note> that the special variable C<$|> B<cannot> be used to set or +retrieve the autoflush setting. + +=head2 input_line_number + + $z->input_line_number() + $z->input_line_number(EXPR) + +Returns the current uncompressed line number. If C<EXPR> is present it has +the effect of setting the line number. Note that setting the line number +does not change the current position within the file/buffer being read. + +The contents of C<$/> are used to to determine what constitutes a line +terminator. + +=head2 fileno + + $z->fileno() + fileno($z) + +If the C<$z> object is associated with a file or a filehandle, C<fileno> +will return the underlying file descriptor. Once the C<close> method is +called C<fileno> will return C<undef>. + +If the C<$z> object is is associated with a buffer, this method will return +C<undef>. + +=head2 close + + $z->close() ; + close $z ; + +Closes the output file/buffer. + +For most versions of Perl this method will be automatically invoked if +the IO::Uncompress::AnyUncompress object is destroyed (either explicitly or by the +variable with the reference to the object going out of scope). The +exceptions are Perl versions 5.005 through 5.00504 and 5.8.0. In +these cases, the C<close> method will be called automatically, but +not until global destruction of all live objects when the program is +terminating. + +Therefore, if you want your scripts to be able to run on all versions +of Perl, you should call C<close> explicitly and not rely on automatic +closing. + +Returns true on success, otherwise 0. + +If the C<AutoClose> option has been enabled when the IO::Uncompress::AnyUncompress +object was created, and the object is associated with a file, the +underlying file will also be closed. + +=head2 nextStream + +Usage is + + my $status = $z->nextStream(); + +Skips to the next compressed data stream in the input file/buffer. If a new +compressed data stream is found, the eof marker will be cleared and C<$.> +will be reset to 0. + +Returns 1 if a new stream was found, 0 if none was found, and -1 if an +error was encountered. + +=head2 trailingData + +Usage is + + my $data = $z->trailingData(); + +Returns the data, if any, that is present immediately after the compressed +data stream once uncompression is complete. It only makes sense to call +this method once the end of the compressed data stream has been +encountered. + +This option can be used when there is useful information immediately +following the compressed data stream, and you don't know the length of the +compressed data stream. + +If the input is a buffer, C<trailingData> will return everything from the +end of the compressed data stream to the end of the buffer. + +If the input is a filehandle, C<trailingData> will return the data that is +left in the filehandle input buffer once the end of the compressed data +stream has been reached. You can then use the filehandle to read the rest +of the input file. + +Don't bother using C<trailingData> if the input is a filename. + +If you know the length of the compressed data stream before you start +uncompressing, you can avoid having to use C<trailingData> by setting the +C<InputLength> option in the constructor. + +=head1 Importing + +No symbolic constants are required by this IO::Uncompress::AnyUncompress at present. + +=over 5 + +=item :all + +Imports C<anyuncompress> and C<$AnyUncompressError>. +Same as doing this + + use IO::Uncompress::AnyUncompress qw(anyuncompress $AnyUncompressError) ; + +=back + +=head1 EXAMPLES + +=head1 SEE ALSO + +L<Compress::Zlib>, L<IO::Compress::Gzip>, L<IO::Uncompress::Gunzip>, L<IO::Compress::Deflate>, L<IO::Uncompress::Inflate>, L<IO::Compress::RawDeflate>, L<IO::Uncompress::RawInflate>, L<IO::Compress::Bzip2>, L<IO::Uncompress::Bunzip2>, L<IO::Compress::Lzma>, L<IO::Uncompress::UnLzma>, L<IO::Compress::Xz>, L<IO::Uncompress::UnXz>, L<IO::Compress::Lzop>, L<IO::Uncompress::UnLzop>, L<IO::Compress::Lzf>, L<IO::Uncompress::UnLzf>, L<IO::Uncompress::AnyInflate> + +L<Compress::Zlib::FAQ|Compress::Zlib::FAQ> + +L<File::GlobMapper|File::GlobMapper>, L<Archive::Zip|Archive::Zip>, +L<Archive::Tar|Archive::Tar>, +L<IO::Zlib|IO::Zlib> + +=head1 AUTHOR + +This module was written by Paul Marquess, F<pmqs@cpan.org>. + +=head1 MODIFICATION HISTORY + +See the Changes file. + +=head1 COPYRIGHT AND LICENSE + +Copyright (c) 2005-2010 Paul Marquess. All rights reserved. + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + diff --git a/Master/tlpkg/tlperl/lib/IO/Uncompress/Base.pm b/Master/tlpkg/tlperl/lib/IO/Uncompress/Base.pm new file mode 100644 index 00000000000..33f2ac23758 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Uncompress/Base.pm @@ -0,0 +1,1474 @@ + +package IO::Uncompress::Base ; + +use strict ; +use warnings; +use bytes; + +our (@ISA, $VERSION, @EXPORT_OK, %EXPORT_TAGS); +@ISA = qw(Exporter IO::File); + + +$VERSION = '2.024'; + +use constant G_EOF => 0 ; +use constant G_ERR => -1 ; + +use IO::Compress::Base::Common 2.024 ; +#use Parse::Parameters ; + +use IO::File ; +use Symbol; +use Scalar::Util qw(readonly); +use List::Util qw(min); +use Carp ; + +%EXPORT_TAGS = ( ); +push @{ $EXPORT_TAGS{all} }, @EXPORT_OK ; +#Exporter::export_ok_tags('all') ; + + + +sub smartRead +{ + my $self = $_[0]; + my $out = $_[1]; + my $size = $_[2]; + $$out = "" ; + + my $offset = 0 ; + + + if (defined *$self->{InputLength}) { + return 0 + if *$self->{InputLengthRemaining} <= 0 ; + $size = min($size, *$self->{InputLengthRemaining}); + } + + if ( length *$self->{Prime} ) { + #$$out = substr(*$self->{Prime}, 0, $size, '') ; + $$out = substr(*$self->{Prime}, 0, $size) ; + substr(*$self->{Prime}, 0, $size) = '' ; + if (length $$out == $size) { + *$self->{InputLengthRemaining} -= length $$out + if defined *$self->{InputLength}; + + return length $$out ; + } + $offset = length $$out ; + } + + my $get_size = $size - $offset ; + + if (defined *$self->{FH}) { + if ($offset) { + # Not using this + # + # *$self->{FH}->read($$out, $get_size, $offset); + # + # because the filehandle may not support the offset parameter + # An example is Net::FTP + my $tmp = ''; + *$self->{FH}->read($tmp, $get_size) && + (substr($$out, $offset) = $tmp); + } + else + { *$self->{FH}->read($$out, $get_size) } + } + elsif (defined *$self->{InputEvent}) { + my $got = 1 ; + while (length $$out < $size) { + last + if ($got = *$self->{InputEvent}->($$out, $get_size)) <= 0; + } + + if (length $$out > $size ) { + #*$self->{Prime} = substr($$out, $size, length($$out), ''); + *$self->{Prime} = substr($$out, $size, length($$out)); + substr($$out, $size, length($$out)) = ''; + } + + *$self->{EventEof} = 1 if $got <= 0 ; + } + else { + no warnings 'uninitialized'; + my $buf = *$self->{Buffer} ; + $$buf = '' unless defined $$buf ; + #$$out = '' unless defined $$out ; + substr($$out, $offset) = substr($$buf, *$self->{BufferOffset}, $get_size); + if (*$self->{ConsumeInput}) + { substr($$buf, 0, $get_size) = '' } + else + { *$self->{BufferOffset} += length($$out) - $offset } + } + + *$self->{InputLengthRemaining} -= length($$out) #- $offset + if defined *$self->{InputLength}; + + $self->saveStatus(length $$out < 0 ? STATUS_ERROR : STATUS_OK) ; + + return length $$out; +} + +sub pushBack +{ + my $self = shift ; + + return if ! defined $_[0] || length $_[0] == 0 ; + + if (defined *$self->{FH} || defined *$self->{InputEvent} ) { + *$self->{Prime} = $_[0] . *$self->{Prime} ; + *$self->{InputLengthRemaining} += length($_[0]); + } + else { + my $len = length $_[0]; + + if($len > *$self->{BufferOffset}) { + *$self->{Prime} = substr($_[0], 0, $len - *$self->{BufferOffset}) . *$self->{Prime} ; + *$self->{InputLengthRemaining} = *$self->{InputLength}; + *$self->{BufferOffset} = 0 + } + else { + *$self->{InputLengthRemaining} += length($_[0]); + *$self->{BufferOffset} -= length($_[0]) ; + } + } +} + +sub smartSeek +{ + my $self = shift ; + my $offset = shift ; + my $truncate = shift; + #print "smartSeek to $offset\n"; + + # TODO -- need to take prime into account + if (defined *$self->{FH}) + { *$self->{FH}->seek($offset, SEEK_SET) } + else { + *$self->{BufferOffset} = $offset ; + substr(${ *$self->{Buffer} }, *$self->{BufferOffset}) = '' + if $truncate; + return 1; + } +} + +sub smartWrite +{ + my $self = shift ; + my $out_data = shift ; + + if (defined *$self->{FH}) { + # flush needed for 5.8.0 + defined *$self->{FH}->write($out_data, length $out_data) && + defined *$self->{FH}->flush() ; + } + else { + my $buf = *$self->{Buffer} ; + substr($$buf, *$self->{BufferOffset}, length $out_data) = $out_data ; + *$self->{BufferOffset} += length($out_data) ; + return 1; + } +} + +sub smartReadExact +{ + return $_[0]->smartRead($_[1], $_[2]) == $_[2]; +} + +sub smartEof +{ + my ($self) = $_[0]; + local $.; + + return 0 if length *$self->{Prime} || *$self->{PushMode}; + + if (defined *$self->{FH}) + { + # Could use + # + # *$self->{FH}->eof() + # + # here, but this can cause trouble if + # the filehandle is itself a tied handle, but it uses sysread. + # Then we get into mixing buffered & non-buffered IO, which will cause trouble + + my $info = $self->getErrInfo(); + + my $buffer = ''; + my $status = $self->smartRead(\$buffer, 1); + $self->pushBack($buffer) if length $buffer; + $self->setErrInfo($info); + + return $status == 0 ; + } + elsif (defined *$self->{InputEvent}) + { *$self->{EventEof} } + else + { *$self->{BufferOffset} >= length(${ *$self->{Buffer} }) } +} + +sub clearError +{ + my $self = shift ; + + *$self->{ErrorNo} = 0 ; + ${ *$self->{Error} } = '' ; +} + +sub getErrInfo +{ + my $self = shift ; + + return [ *$self->{ErrorNo}, ${ *$self->{Error} } ] ; +} + +sub setErrInfo +{ + my $self = shift ; + my $ref = shift; + + *$self->{ErrorNo} = $ref->[0] ; + ${ *$self->{Error} } = $ref->[1] ; +} + +sub saveStatus +{ + my $self = shift ; + my $errno = shift() + 0 ; + #return $errno unless $errno || ! defined *$self->{ErrorNo}; + #return $errno unless $errno ; + + *$self->{ErrorNo} = $errno; + ${ *$self->{Error} } = '' ; + + return *$self->{ErrorNo} ; +} + + +sub saveErrorString +{ + my $self = shift ; + my $retval = shift ; + + #return $retval if ${ *$self->{Error} }; + + ${ *$self->{Error} } = shift ; + *$self->{ErrorNo} = shift() + 0 if @_ ; + + #warn "saveErrorString: " . ${ *$self->{Error} } . " " . *$self->{Error} . "\n" ; + return $retval; +} + +sub croakError +{ + my $self = shift ; + $self->saveErrorString(0, $_[0]); + croak $_[0]; +} + + +sub closeError +{ + my $self = shift ; + my $retval = shift ; + + my $errno = *$self->{ErrorNo}; + my $error = ${ *$self->{Error} }; + + $self->close(); + + *$self->{ErrorNo} = $errno ; + ${ *$self->{Error} } = $error ; + + return $retval; +} + +sub error +{ + my $self = shift ; + return ${ *$self->{Error} } ; +} + +sub errorNo +{ + my $self = shift ; + return *$self->{ErrorNo}; +} + +sub HeaderError +{ + my ($self) = shift; + return $self->saveErrorString(undef, "Header Error: $_[0]", STATUS_ERROR); +} + +sub TrailerError +{ + my ($self) = shift; + return $self->saveErrorString(G_ERR, "Trailer Error: $_[0]", STATUS_ERROR); +} + +sub TruncatedHeader +{ + my ($self) = shift; + return $self->HeaderError("Truncated in $_[0] Section"); +} + +sub TruncatedTrailer +{ + my ($self) = shift; + return $self->TrailerError("Truncated in $_[0] Section"); +} + +sub postCheckParams +{ + return 1; +} + +sub checkParams +{ + my $self = shift ; + my $class = shift ; + + my $got = shift || IO::Compress::Base::Parameters::new(); + + my $Valid = { + 'BlockSize' => [1, 1, Parse_unsigned, 16 * 1024], + 'AutoClose' => [1, 1, Parse_boolean, 0], + 'Strict' => [1, 1, Parse_boolean, 0], + 'Append' => [1, 1, Parse_boolean, 0], + 'Prime' => [1, 1, Parse_any, undef], + 'MultiStream' => [1, 1, Parse_boolean, 0], + 'Transparent' => [1, 1, Parse_any, 1], + 'Scan' => [1, 1, Parse_boolean, 0], + 'InputLength' => [1, 1, Parse_unsigned, undef], + 'BinModeOut' => [1, 1, Parse_boolean, 0], + #'Encode' => [1, 1, Parse_any, undef], + + #'ConsumeInput' => [1, 1, Parse_boolean, 0], + + $self->getExtraParams(), + + #'Todo - Revert to ordinary file on end Z_STREAM_END'=> 0, + # ContinueAfterEof + } ; + + $Valid->{TrailingData} = [1, 1, Parse_writable_scalar, undef] + if *$self->{OneShot} ; + + $got->parse($Valid, @_ ) + or $self->croakError("${class}: $got->{Error}") ; + + $self->postCheckParams($got) + or $self->croakError("${class}: " . $self->error()) ; + + return $got; +} + +sub _create +{ + my $obj = shift; + my $got = shift; + my $append_mode = shift ; + + my $class = ref $obj; + $obj->croakError("$class: Missing Input parameter") + if ! @_ && ! $got ; + + my $inValue = shift ; + + *$obj->{OneShot} = 0 ; + + if (! $got) + { + $got = $obj->checkParams($class, undef, @_) + or return undef ; + } + + my $inType = whatIsInput($inValue, 1); + + $obj->ckInputParam($class, $inValue, 1) + or return undef ; + + *$obj->{InNew} = 1; + + $obj->ckParams($got) + or $obj->croakError("${class}: " . *$obj->{Error}); + + if ($inType eq 'buffer' || $inType eq 'code') { + *$obj->{Buffer} = $inValue ; + *$obj->{InputEvent} = $inValue + if $inType eq 'code' ; + } + else { + if ($inType eq 'handle') { + *$obj->{FH} = $inValue ; + *$obj->{Handle} = 1 ; + + # Need to rewind for Scan + *$obj->{FH}->seek(0, SEEK_SET) + if $got->value('Scan'); + } + else { + no warnings ; + my $mode = '<'; + $mode = '+<' if $got->value('Scan'); + *$obj->{StdIO} = ($inValue eq '-'); + *$obj->{FH} = new IO::File "$mode $inValue" + or return $obj->saveErrorString(undef, "cannot open file '$inValue': $!", $!) ; + } + + *$obj->{LineNo} = $. = 0; + setBinModeInput(*$obj->{FH}) ; + + my $buff = "" ; + *$obj->{Buffer} = \$buff ; + } + + if ($got->parsed('Encode')) { + my $want_encoding = $got->value('Encode'); + *$obj->{Encoding} = getEncoding($obj, $class, $want_encoding); + } + + + *$obj->{InputLength} = $got->parsed('InputLength') + ? $got->value('InputLength') + : undef ; + *$obj->{InputLengthRemaining} = $got->value('InputLength'); + *$obj->{BufferOffset} = 0 ; + *$obj->{AutoClose} = $got->value('AutoClose'); + *$obj->{Strict} = $got->value('Strict'); + *$obj->{BlockSize} = $got->value('BlockSize'); + *$obj->{Append} = $got->value('Append'); + *$obj->{AppendOutput} = $append_mode || $got->value('Append'); + *$obj->{ConsumeInput} = $got->value('ConsumeInput'); + *$obj->{Transparent} = $got->value('Transparent'); + *$obj->{MultiStream} = $got->value('MultiStream'); + + # TODO - move these two into RawDeflate + *$obj->{Scan} = $got->value('Scan'); + *$obj->{ParseExtra} = $got->value('ParseExtra') + || $got->value('Strict') ; + *$obj->{Type} = ''; + *$obj->{Prime} = $got->value('Prime') || '' ; + *$obj->{Pending} = ''; + *$obj->{Plain} = 0; + *$obj->{PlainBytesRead} = 0; + *$obj->{InflatedBytesRead} = 0; + *$obj->{UnCompSize} = new U64; + *$obj->{CompSize} = new U64; + *$obj->{TotalInflatedBytesRead} = 0; + *$obj->{NewStream} = 0 ; + *$obj->{EventEof} = 0 ; + *$obj->{ClassName} = $class ; + *$obj->{Params} = $got ; + + if (*$obj->{ConsumeInput}) { + *$obj->{InNew} = 0; + *$obj->{Closed} = 0; + return $obj + } + + my $status = $obj->mkUncomp($got); + + return undef + unless defined $status; + + if ( ! $status) { + return undef + unless *$obj->{Transparent}; + + $obj->clearError(); + *$obj->{Type} = 'plain'; + *$obj->{Plain} = 1; + #$status = $obj->mkIdentityUncomp($class, $got); + $obj->pushBack(*$obj->{HeaderPending}) ; + } + + push @{ *$obj->{InfoList} }, *$obj->{Info} ; + + $obj->saveStatus(STATUS_OK) ; + *$obj->{InNew} = 0; + *$obj->{Closed} = 0; + + return $obj; +} + +sub ckInputParam +{ + my $self = shift ; + my $from = shift ; + my $inType = whatIsInput($_[0], $_[1]); + + $self->croakError("$from: input parameter not a filename, filehandle, array ref or scalar ref") + if ! $inType ; + +# if ($inType eq 'filename' ) +# { +# return $self->saveErrorString(1, "$from: input filename is undef or null string", STATUS_ERROR) +# if ! defined $_[0] || $_[0] eq '' ; +# +# if ($_[0] ne '-' && ! -e $_[0] ) +# { +# return $self->saveErrorString(1, +# "input file '$_[0]' does not exist", STATUS_ERROR); +# } +# } + + return 1; +} + + +sub _inf +{ + my $obj = shift ; + + my $class = (caller)[0] ; + my $name = (caller(1))[3] ; + + $obj->croakError("$name: expected at least 1 parameters\n") + unless @_ >= 1 ; + + my $input = shift ; + my $haveOut = @_ ; + my $output = shift ; + + + my $x = new IO::Compress::Base::Validator($class, *$obj->{Error}, $name, $input, $output) + or return undef ; + + push @_, $output if $haveOut && $x->{Hash}; + + *$obj->{OneShot} = 1 ; + + my $got = $obj->checkParams($name, undef, @_) + or return undef ; + + if ($got->parsed('TrailingData')) + { + *$obj->{TrailingData} = $got->value('TrailingData'); + } + + *$obj->{MultiStream} = $got->value('MultiStream'); + $got->value('MultiStream', 0); + + $x->{Got} = $got ; + +# if ($x->{Hash}) +# { +# while (my($k, $v) = each %$input) +# { +# $v = \$input->{$k} +# unless defined $v ; +# +# $obj->_singleTarget($x, $k, $v, @_) +# or return undef ; +# } +# +# return keys %$input ; +# } + + if ($x->{GlobMap}) + { + $x->{oneInput} = 1 ; + foreach my $pair (@{ $x->{Pairs} }) + { + my ($from, $to) = @$pair ; + $obj->_singleTarget($x, $from, $to, @_) + or return undef ; + } + + return scalar @{ $x->{Pairs} } ; + } + + if (! $x->{oneOutput} ) + { + my $inFile = ($x->{inType} eq 'filenames' + || $x->{inType} eq 'filename'); + + $x->{inType} = $inFile ? 'filename' : 'buffer'; + + foreach my $in ($x->{oneInput} ? $input : @$input) + { + my $out ; + $x->{oneInput} = 1 ; + + $obj->_singleTarget($x, $in, $output, @_) + or return undef ; + } + + return 1 ; + } + + # finally the 1 to 1 and n to 1 + return $obj->_singleTarget($x, $input, $output, @_); + + croak "should not be here" ; +} + +sub retErr +{ + my $x = shift ; + my $string = shift ; + + ${ $x->{Error} } = $string ; + + return undef ; +} + +sub _singleTarget +{ + my $self = shift ; + my $x = shift ; + my $input = shift; + my $output = shift; + + my $buff = ''; + $x->{buff} = \$buff ; + + my $fh ; + if ($x->{outType} eq 'filename') { + my $mode = '>' ; + $mode = '>>' + if $x->{Got}->value('Append') ; + $x->{fh} = new IO::File "$mode $output" + or return retErr($x, "cannot open file '$output': $!") ; + binmode $x->{fh} if $x->{Got}->valueOrDefault('BinModeOut'); + + } + + elsif ($x->{outType} eq 'handle') { + $x->{fh} = $output; + binmode $x->{fh} if $x->{Got}->valueOrDefault('BinModeOut'); + if ($x->{Got}->value('Append')) { + seek($x->{fh}, 0, SEEK_END) + or return retErr($x, "Cannot seek to end of output filehandle: $!") ; + } + } + + + elsif ($x->{outType} eq 'buffer' ) + { + $$output = '' + unless $x->{Got}->value('Append'); + $x->{buff} = $output ; + } + + if ($x->{oneInput}) + { + defined $self->_rd2($x, $input, $output) + or return undef; + } + else + { + for my $element ( ($x->{inType} eq 'hash') ? keys %$input : @$input) + { + defined $self->_rd2($x, $element, $output) + or return undef ; + } + } + + + if ( ($x->{outType} eq 'filename' && $output ne '-') || + ($x->{outType} eq 'handle' && $x->{Got}->value('AutoClose'))) { + $x->{fh}->close() + or return retErr($x, $!); + delete $x->{fh}; + } + + return 1 ; +} + +sub _rd2 +{ + my $self = shift ; + my $x = shift ; + my $input = shift; + my $output = shift; + + my $z = createSelfTiedObject($x->{Class}, *$self->{Error}); + + $z->_create($x->{Got}, 1, $input, @_) + or return undef ; + + my $status ; + my $fh = $x->{fh}; + + while (1) { + + while (($status = $z->read($x->{buff})) > 0) { + if ($fh) { + print $fh ${ $x->{buff} } + or return $z->saveErrorString(undef, "Error writing to output file: $!", $!); + ${ $x->{buff} } = '' ; + } + } + + if (! $x->{oneOutput} ) { + my $ot = $x->{outType} ; + + if ($ot eq 'array') + { push @$output, $x->{buff} } + elsif ($ot eq 'hash') + { $output->{$input} = $x->{buff} } + + my $buff = ''; + $x->{buff} = \$buff; + } + + last if $status < 0 || $z->smartEof(); + #last if $status < 0 ; + + last + unless *$self->{MultiStream}; + + $status = $z->nextStream(); + + last + unless $status == 1 ; + } + + return $z->closeError(undef) + if $status < 0 ; + + ${ *$self->{TrailingData} } = $z->trailingData() + if defined *$self->{TrailingData} ; + + $z->close() + or return undef ; + + return 1 ; +} + +sub TIEHANDLE +{ + return $_[0] if ref($_[0]); + die "OOPS\n" ; + +} + +sub UNTIE +{ + my $self = shift ; +} + + +sub getHeaderInfo +{ + my $self = shift ; + wantarray ? @{ *$self->{InfoList} } : *$self->{Info}; +} + +sub readBlock +{ + my $self = shift ; + my $buff = shift ; + my $size = shift ; + + if (defined *$self->{CompressedInputLength}) { + if (*$self->{CompressedInputLengthRemaining} == 0) { + delete *$self->{CompressedInputLength}; + *$self->{CompressedInputLengthDone} = 1; + return STATUS_OK ; + } + $size = min($size, *$self->{CompressedInputLengthRemaining} ); + *$self->{CompressedInputLengthRemaining} -= $size ; + } + + my $status = $self->smartRead($buff, $size) ; + return $self->saveErrorString(STATUS_ERROR, "Error Reading Data") + if $status < 0 ; + + if ($status == 0 ) { + *$self->{Closed} = 1 ; + *$self->{EndStream} = 1 ; + return $self->saveErrorString(STATUS_ERROR, "unexpected end of file", STATUS_ERROR); + } + + return STATUS_OK; +} + +sub postBlockChk +{ + return STATUS_OK; +} + +sub _raw_read +{ + # return codes + # >0 - ok, number of bytes read + # =0 - ok, eof + # <0 - not ok + + my $self = shift ; + + return G_EOF if *$self->{Closed} ; + #return G_EOF if !length *$self->{Pending} && *$self->{EndStream} ; + return G_EOF if *$self->{EndStream} ; + + my $buffer = shift ; + my $scan_mode = shift ; + + if (*$self->{Plain}) { + my $tmp_buff ; + my $len = $self->smartRead(\$tmp_buff, *$self->{BlockSize}) ; + + return $self->saveErrorString(G_ERR, "Error reading data: $!", $!) + if $len < 0 ; + + if ($len == 0 ) { + *$self->{EndStream} = 1 ; + } + else { + *$self->{PlainBytesRead} += $len ; + $$buffer .= $tmp_buff; + } + + return $len ; + } + + if (*$self->{NewStream}) { + + $self->gotoNextStream() > 0 + or return G_ERR; + + # For the headers that actually uncompressed data, put the + # uncompressed data into the output buffer. + $$buffer .= *$self->{Pending} ; + my $len = length *$self->{Pending} ; + *$self->{Pending} = ''; + return $len; + } + + my $temp_buf = ''; + my $outSize = 0; + my $status = $self->readBlock(\$temp_buf, *$self->{BlockSize}, $outSize) ; + return G_ERR + if $status == STATUS_ERROR ; + + my $buf_len = 0; + if ($status == STATUS_OK) { + my $beforeC_len = length $temp_buf; + my $before_len = defined $$buffer ? length $$buffer : 0 ; + $status = *$self->{Uncomp}->uncompr(\$temp_buf, $buffer, + defined *$self->{CompressedInputLengthDone} || + $self->smartEof(), $outSize); + + # Remember the input buffer if it wasn't consumed completely + $self->pushBack($temp_buf) if *$self->{Uncomp}{ConsumesInput}; + + return $self->saveErrorString(G_ERR, *$self->{Uncomp}{Error}, *$self->{Uncomp}{ErrorNo}) + if $self->saveStatus($status) == STATUS_ERROR; + + $self->postBlockChk($buffer, $before_len) == STATUS_OK + or return G_ERR; + + $buf_len = defined $$buffer ? length($$buffer) - $before_len : 0; + + *$self->{CompSize}->add($beforeC_len - length $temp_buf) ; + + *$self->{InflatedBytesRead} += $buf_len ; + *$self->{TotalInflatedBytesRead} += $buf_len ; + *$self->{UnCompSize}->add($buf_len) ; + + $self->filterUncompressed($buffer); + + if (*$self->{Encoding}) { + $$buffer = *$self->{Encoding}->decode($$buffer); + } + } + + if ($status == STATUS_ENDSTREAM) { + + *$self->{EndStream} = 1 ; +#$self->pushBack($temp_buf) ; +#$temp_buf = ''; + + my $trailer; + my $trailer_size = *$self->{Info}{TrailerLength} ; + my $got = 0; + if (*$self->{Info}{TrailerLength}) + { + $got = $self->smartRead(\$trailer, $trailer_size) ; + } + + if ($got == $trailer_size) { + $self->chkTrailer($trailer) == STATUS_OK + or return G_ERR; + } + else { + return $self->TrailerError("trailer truncated. Expected " . + "$trailer_size bytes, got $got") + if *$self->{Strict}; + $self->pushBack($trailer) ; + } + + # TODO - if want to file file pointer, do it here + + if (! $self->smartEof()) { + *$self->{NewStream} = 1 ; + + if (*$self->{MultiStream}) { + *$self->{EndStream} = 0 ; + return $buf_len ; + } + } + + } + + + # return the number of uncompressed bytes read + return $buf_len ; +} + +sub reset +{ + my $self = shift ; + + return *$self->{Uncomp}->reset(); +} + +sub filterUncompressed +{ +} + +#sub isEndStream +#{ +# my $self = shift ; +# return *$self->{NewStream} || +# *$self->{EndStream} ; +#} + +sub nextStream +{ + my $self = shift ; + + my $status = $self->gotoNextStream(); + $status == 1 + or return $status ; + + *$self->{TotalInflatedBytesRead} = 0 ; + *$self->{LineNo} = $. = 0; + + return 1; +} + +sub gotoNextStream +{ + my $self = shift ; + + if (! *$self->{NewStream}) { + my $status = 1; + my $buffer ; + + # TODO - make this more efficient if know the offset for the end of + # the stream and seekable + $status = $self->read($buffer) + while $status > 0 ; + + return $status + if $status < 0; + } + + *$self->{NewStream} = 0 ; + *$self->{EndStream} = 0 ; + $self->reset(); + *$self->{UnCompSize}->reset(); + *$self->{CompSize}->reset(); + + my $magic = $self->ckMagic(); + #*$self->{EndStream} = 0 ; + + if ( ! defined $magic) { + if (! *$self->{Transparent} ) + { + *$self->{EndStream} = 1 ; + return 0; + } + + $self->clearError(); + *$self->{Type} = 'plain'; + *$self->{Plain} = 1; + $self->pushBack(*$self->{HeaderPending}) ; + } + else + { + *$self->{Info} = $self->readHeader($magic); + + if ( ! defined *$self->{Info} ) { + *$self->{EndStream} = 1 ; + return -1; + } + } + + push @{ *$self->{InfoList} }, *$self->{Info} ; + + return 1; +} + +sub streamCount +{ + my $self = shift ; + return 1 if ! defined *$self->{InfoList}; + return scalar @{ *$self->{InfoList} } ; +} + +sub read +{ + # return codes + # >0 - ok, number of bytes read + # =0 - ok, eof + # <0 - not ok + + my $self = shift ; + + return G_EOF if *$self->{Closed} ; + + my $buffer ; + + if (ref $_[0] ) { + $self->croakError(*$self->{ClassName} . "::read: buffer parameter is read-only") + if readonly(${ $_[0] }); + + $self->croakError(*$self->{ClassName} . "::read: not a scalar reference $_[0]" ) + unless ref $_[0] eq 'SCALAR' ; + $buffer = $_[0] ; + } + else { + $self->croakError(*$self->{ClassName} . "::read: buffer parameter is read-only") + if readonly($_[0]); + + $buffer = \$_[0] ; + } + + my $length = $_[1] ; + my $offset = $_[2] || 0; + + if (! *$self->{AppendOutput}) { + if (! $offset) { + $$buffer = '' ; + } + else { + if ($offset > length($$buffer)) { + $$buffer .= "\x00" x ($offset - length($$buffer)); + } + else { + substr($$buffer, $offset) = ''; + } + } + } + + return G_EOF if !length *$self->{Pending} && *$self->{EndStream} ; + + # the core read will return 0 if asked for 0 bytes + return 0 if defined $length && $length == 0 ; + + $length = $length || 0; + + $self->croakError(*$self->{ClassName} . "::read: length parameter is negative") + if $length < 0 ; + + # Short-circuit if this is a simple read, with no length + # or offset specified. + unless ( $length || $offset) { + if (length *$self->{Pending}) { + $$buffer .= *$self->{Pending} ; + my $len = length *$self->{Pending}; + *$self->{Pending} = '' ; + return $len ; + } + else { + my $len = 0; + $len = $self->_raw_read($buffer) + while ! *$self->{EndStream} && $len == 0 ; + return $len ; + } + } + + # Need to jump through more hoops - either length or offset + # or both are specified. + my $out_buffer = *$self->{Pending} ; + *$self->{Pending} = ''; + + + while (! *$self->{EndStream} && length($out_buffer) < $length) + { + my $buf_len = $self->_raw_read(\$out_buffer); + return $buf_len + if $buf_len < 0 ; + } + + $length = length $out_buffer + if length($out_buffer) < $length ; + + return 0 + if $length == 0 ; + + $$buffer = '' + if ! defined $$buffer; + + $offset = length $$buffer + if *$self->{AppendOutput} ; + + *$self->{Pending} = $out_buffer; + $out_buffer = \*$self->{Pending} ; + + #substr($$buffer, $offset) = substr($$out_buffer, 0, $length, '') ; + substr($$buffer, $offset) = substr($$out_buffer, 0, $length) ; + substr($$out_buffer, 0, $length) = '' ; + + return $length ; +} + +sub _getline +{ + my $self = shift ; + + # Slurp Mode + if ( ! defined $/ ) { + my $data ; + 1 while $self->read($data) > 0 ; + return \$data ; + } + + # Record Mode + if ( ref $/ eq 'SCALAR' && ${$/} =~ /^\d+$/ && ${$/} > 0) { + my $reclen = ${$/} ; + my $data ; + $self->read($data, $reclen) ; + return \$data ; + } + + # Paragraph Mode + if ( ! length $/ ) { + my $paragraph ; + while ($self->read($paragraph) > 0 ) { + if ($paragraph =~ s/^(.*?\n\n+)//s) { + *$self->{Pending} = $paragraph ; + my $par = $1 ; + return \$par ; + } + } + return \$paragraph; + } + + # $/ isn't empty, or a reference, so it's Line Mode. + { + my $line ; + my $offset; + my $p = \*$self->{Pending} ; + + if (length(*$self->{Pending}) && + ($offset = index(*$self->{Pending}, $/)) >=0) { + my $l = substr(*$self->{Pending}, 0, $offset + length $/ ); + substr(*$self->{Pending}, 0, $offset + length $/) = ''; + return \$l; + } + + while ($self->read($line) > 0 ) { + my $offset = index($line, $/); + if ($offset >= 0) { + my $l = substr($line, 0, $offset + length $/ ); + substr($line, 0, $offset + length $/) = ''; + $$p = $line; + return \$l; + } + } + + return \$line; + } +} + +sub getline +{ + my $self = shift; + my $current_append = *$self->{AppendOutput} ; + *$self->{AppendOutput} = 1; + my $lineref = $self->_getline(); + $. = ++ *$self->{LineNo} if defined $$lineref ; + *$self->{AppendOutput} = $current_append; + return $$lineref ; +} + +sub getlines +{ + my $self = shift; + $self->croakError(*$self->{ClassName} . + "::getlines: called in scalar context\n") unless wantarray; + my($line, @lines); + push(@lines, $line) + while defined($line = $self->getline); + return @lines; +} + +sub READLINE +{ + goto &getlines if wantarray; + goto &getline; +} + +sub getc +{ + my $self = shift; + my $buf; + return $buf if $self->read($buf, 1); + return undef; +} + +sub ungetc +{ + my $self = shift; + *$self->{Pending} = "" unless defined *$self->{Pending} ; + *$self->{Pending} = $_[0] . *$self->{Pending} ; +} + + +sub trailingData +{ + my $self = shift ; + + if (defined *$self->{FH} || defined *$self->{InputEvent} ) { + return *$self->{Prime} ; + } + else { + my $buf = *$self->{Buffer} ; + my $offset = *$self->{BufferOffset} ; + return substr($$buf, $offset) ; + } +} + + +sub eof +{ + my $self = shift ; + + return (*$self->{Closed} || + (!length *$self->{Pending} + && ( $self->smartEof() || *$self->{EndStream}))) ; +} + +sub tell +{ + my $self = shift ; + + my $in ; + if (*$self->{Plain}) { + $in = *$self->{PlainBytesRead} ; + } + else { + $in = *$self->{TotalInflatedBytesRead} ; + } + + my $pending = length *$self->{Pending} ; + + return 0 if $pending > $in ; + return $in - $pending ; +} + +sub close +{ + # todo - what to do if close is called before the end of the gzip file + # do we remember any trailing data? + my $self = shift ; + + return 1 if *$self->{Closed} ; + + untie *$self + if $] >= 5.008 ; + + my $status = 1 ; + + if (defined *$self->{FH}) { + if ((! *$self->{Handle} || *$self->{AutoClose}) && ! *$self->{StdIO}) { + #if ( *$self->{AutoClose}) { + local $.; + $! = 0 ; + $status = *$self->{FH}->close(); + return $self->saveErrorString(0, $!, $!) + if !*$self->{InNew} && $self->saveStatus($!) != 0 ; + } + delete *$self->{FH} ; + $! = 0 ; + } + *$self->{Closed} = 1 ; + + return 1; +} + +sub DESTROY +{ + my $self = shift ; + local ($., $@, $!, $^E, $?); + + $self->close() ; +} + +sub seek +{ + my $self = shift ; + my $position = shift; + my $whence = shift ; + + my $here = $self->tell() ; + my $target = 0 ; + + + if ($whence == SEEK_SET) { + $target = $position ; + } + elsif ($whence == SEEK_CUR) { + $target = $here + $position ; + } + elsif ($whence == SEEK_END) { + $target = $position ; + $self->croakError(*$self->{ClassName} . "::seek: SEEK_END not allowed") ; + } + else { + $self->croakError(*$self->{ClassName} ."::seek: unknown value, $whence, for whence parameter"); + } + + # short circuit if seeking to current offset + if ($target == $here) { + # On ordinary filehandles, seeking to the current + # position also clears the EOF condition, so we + # emulate this behavior locally while simultaneously + # cascading it to the underlying filehandle + if (*$self->{Plain}) { + *$self->{EndStream} = 0; + seek(*$self->{FH},0,1) if *$self->{FH}; + } + return 1; + } + + # Outlaw any attempt to seek backwards + $self->croakError( *$self->{ClassName} ."::seek: cannot seek backwards") + if $target < $here ; + + # Walk the file to the new offset + my $offset = $target - $here ; + + my $got; + while (($got = $self->read(my $buffer, min($offset, *$self->{BlockSize})) ) > 0) + { + $offset -= $got; + last if $offset == 0 ; + } + + $here = $self->tell() ; + return $offset == 0 ? 1 : 0 ; +} + +sub fileno +{ + my $self = shift ; + return defined *$self->{FH} + ? fileno *$self->{FH} + : undef ; +} + +sub binmode +{ + 1; +# my $self = shift ; +# return defined *$self->{FH} +# ? binmode *$self->{FH} +# : 1 ; +} + +sub opened +{ + my $self = shift ; + return ! *$self->{Closed} ; +} + +sub autoflush +{ + my $self = shift ; + return defined *$self->{FH} + ? *$self->{FH}->autoflush(@_) + : undef ; +} + +sub input_line_number +{ + my $self = shift ; + my $last = *$self->{LineNo}; + $. = *$self->{LineNo} = $_[1] if @_ ; + return $last; +} + + +*BINMODE = \&binmode; +*SEEK = \&seek; +*READ = \&read; +*sysread = \&read; +*TELL = \&tell; +*EOF = \&eof; + +*FILENO = \&fileno; +*CLOSE = \&close; + +sub _notAvailable +{ + my $name = shift ; + #return sub { croak "$name Not Available" ; } ; + return sub { croak "$name Not Available: File opened only for intput" ; } ; +} + + +*print = _notAvailable('print'); +*PRINT = _notAvailable('print'); +*printf = _notAvailable('printf'); +*PRINTF = _notAvailable('printf'); +*write = _notAvailable('write'); +*WRITE = _notAvailable('write'); + +#*sysread = \&read; +#*syswrite = \&_notAvailable; + + + +package IO::Uncompress::Base ; + + +1 ; +__END__ + +=head1 NAME + +IO::Uncompress::Base - Base Class for IO::Uncompress modules + +=head1 SYNOPSIS + + use IO::Uncompress::Base ; + +=head1 DESCRIPTION + +This module is not intended for direct use in application code. Its sole +purpose if to to be sub-classed by IO::Unompress modules. + +=head1 SEE ALSO + +L<Compress::Zlib>, L<IO::Compress::Gzip>, L<IO::Uncompress::Gunzip>, L<IO::Compress::Deflate>, L<IO::Uncompress::Inflate>, L<IO::Compress::RawDeflate>, L<IO::Uncompress::RawInflate>, L<IO::Compress::Bzip2>, L<IO::Uncompress::Bunzip2>, L<IO::Compress::Lzma>, L<IO::Uncompress::UnLzma>, L<IO::Compress::Xz>, L<IO::Uncompress::UnXz>, L<IO::Compress::Lzop>, L<IO::Uncompress::UnLzop>, L<IO::Compress::Lzf>, L<IO::Uncompress::UnLzf>, L<IO::Uncompress::AnyInflate>, L<IO::Uncompress::AnyUncompress> + +L<Compress::Zlib::FAQ|Compress::Zlib::FAQ> + +L<File::GlobMapper|File::GlobMapper>, L<Archive::Zip|Archive::Zip>, +L<Archive::Tar|Archive::Tar>, +L<IO::Zlib|IO::Zlib> + +=head1 AUTHOR + +This module was written by Paul Marquess, F<pmqs@cpan.org>. + +=head1 MODIFICATION HISTORY + +See the Changes file. + +=head1 COPYRIGHT AND LICENSE + +Copyright (c) 2005-2010 Paul Marquess. All rights reserved. + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + diff --git a/Master/tlpkg/tlperl/lib/IO/Uncompress/Bunzip2.pm b/Master/tlpkg/tlperl/lib/IO/Uncompress/Bunzip2.pm new file mode 100644 index 00000000000..b3988c41851 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Uncompress/Bunzip2.pm @@ -0,0 +1,858 @@ +package IO::Uncompress::Bunzip2 ; + +use strict ; +use warnings; +use bytes; + +use IO::Compress::Base::Common 2.024 qw(:Status createSelfTiedObject); + +use IO::Uncompress::Base 2.024 ; +use IO::Uncompress::Adapter::Bunzip2 2.024 ; + +require Exporter ; +our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, $Bunzip2Error); + +$VERSION = '2.024'; +$Bunzip2Error = ''; + +@ISA = qw( Exporter IO::Uncompress::Base ); +@EXPORT_OK = qw( $Bunzip2Error bunzip2 ) ; +#%EXPORT_TAGS = %IO::Uncompress::Base::EXPORT_TAGS ; +push @{ $EXPORT_TAGS{all} }, @EXPORT_OK ; +#Exporter::export_ok_tags('all'); + + +sub new +{ + my $class = shift ; + my $obj = createSelfTiedObject($class, \$Bunzip2Error); + + $obj->_create(undef, 0, @_); +} + +sub bunzip2 +{ + my $obj = createSelfTiedObject(undef, \$Bunzip2Error); + return $obj->_inf(@_); +} + +sub getExtraParams +{ + my $self = shift ; + + use IO::Compress::Base::Common 2.024 qw(:Parse); + + return ( + 'Verbosity' => [1, 1, Parse_boolean, 0], + 'Small' => [1, 1, Parse_boolean, 0], + ); +} + + +sub ckParams +{ + my $self = shift ; + my $got = shift ; + + return 1; +} + +sub mkUncomp +{ + my $self = shift ; + my $got = shift ; + + my $magic = $self->ckMagic() + or return 0; + + *$self->{Info} = $self->readHeader($magic) + or return undef ; + + my $Small = $got->value('Small'); + my $Verbosity = $got->value('Verbosity'); + + my ($obj, $errstr, $errno) = IO::Uncompress::Adapter::Bunzip2::mkUncompObject( + $Small, $Verbosity); + + return $self->saveErrorString(undef, $errstr, $errno) + if ! defined $obj; + + *$self->{Uncomp} = $obj; + + return 1; + +} + + +sub ckMagic +{ + my $self = shift; + + my $magic ; + $self->smartReadExact(\$magic, 4); + + *$self->{HeaderPending} = $magic ; + + return $self->HeaderError("Header size is " . + 4 . " bytes") + if length $magic != 4; + + return $self->HeaderError("Bad Magic.") + if ! isBzip2Magic($magic) ; + + + *$self->{Type} = 'bzip2'; + return $magic; +} + +sub readHeader +{ + my $self = shift; + my $magic = shift ; + + $self->pushBack($magic); + *$self->{HeaderPending} = ''; + + + return { + 'Type' => 'bzip2', + 'FingerprintLength' => 4, + 'HeaderLength' => 4, + 'TrailerLength' => 0, + 'Header' => '$magic' + }; + +} + +sub chkTrailer +{ + return STATUS_OK; +} + + + +sub isBzip2Magic +{ + my $buffer = shift ; + return $buffer =~ /^BZh\d$/; +} + +1 ; + +__END__ + + +=head1 NAME + +IO::Uncompress::Bunzip2 - Read bzip2 files/buffers + +=head1 SYNOPSIS + + use IO::Uncompress::Bunzip2 qw(bunzip2 $Bunzip2Error) ; + + my $status = bunzip2 $input => $output [,OPTS] + or die "bunzip2 failed: $Bunzip2Error\n"; + + my $z = new IO::Uncompress::Bunzip2 $input [OPTS] + or die "bunzip2 failed: $Bunzip2Error\n"; + + $status = $z->read($buffer) + $status = $z->read($buffer, $length) + $status = $z->read($buffer, $length, $offset) + $line = $z->getline() + $char = $z->getc() + $char = $z->ungetc() + $char = $z->opened() + + $data = $z->trailingData() + $status = $z->nextStream() + $data = $z->getHeaderInfo() + $z->tell() + $z->seek($position, $whence) + $z->binmode() + $z->fileno() + $z->eof() + $z->close() + + $Bunzip2Error ; + + # IO::File mode + + <$z> + read($z, $buffer); + read($z, $buffer, $length); + read($z, $buffer, $length, $offset); + tell($z) + seek($z, $position, $whence) + binmode($z) + fileno($z) + eof($z) + close($z) + +=head1 DESCRIPTION + +This module provides a Perl interface that allows the reading of +bzip2 files/buffers. + +For writing bzip2 files/buffers, see the companion module IO::Compress::Bzip2. + +=head1 Functional Interface + +A top-level function, C<bunzip2>, is provided to carry out +"one-shot" uncompression between buffers and/or files. For finer +control over the uncompression process, see the L</"OO Interface"> +section. + + use IO::Uncompress::Bunzip2 qw(bunzip2 $Bunzip2Error) ; + + bunzip2 $input => $output [,OPTS] + or die "bunzip2 failed: $Bunzip2Error\n"; + +The functional interface needs Perl5.005 or better. + +=head2 bunzip2 $input => $output [, OPTS] + +C<bunzip2> expects at least two parameters, C<$input> and C<$output>. + +=head3 The C<$input> parameter + +The parameter, C<$input>, is used to define the source of +the compressed data. + +It can take one of the following forms: + +=over 5 + +=item A filename + +If the C<$input> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for reading and the input data +will be read from it. + +=item A filehandle + +If the C<$input> parameter is a filehandle, the input data will be +read from it. +The string '-' can be used as an alias for standard input. + +=item A scalar reference + +If C<$input> is a scalar reference, the input data will be read +from C<$$input>. + +=item An array reference + +If C<$input> is an array reference, each element in the array must be a +filename. + +The input data will be read from each file in turn. + +The complete array will be walked to ensure that it only +contains valid filenames before any data is uncompressed. + +=item An Input FileGlob string + +If C<$input> is a string that is delimited by the characters "<" and ">" +C<bunzip2> will assume that it is an I<input fileglob string>. The +input is the list of files that match the fileglob. + +If the fileglob does not match any files ... + +See L<File::GlobMapper|File::GlobMapper> for more details. + +=back + +If the C<$input> parameter is any other type, C<undef> will be returned. + +=head3 The C<$output> parameter + +The parameter C<$output> is used to control the destination of the +uncompressed data. This parameter can take one of these forms. + +=over 5 + +=item A filename + +If the C<$output> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for writing and the uncompressed +data will be written to it. + +=item A filehandle + +If the C<$output> parameter is a filehandle, the uncompressed data +will be written to it. +The string '-' can be used as an alias for standard output. + +=item A scalar reference + +If C<$output> is a scalar reference, the uncompressed data will be +stored in C<$$output>. + +=item An Array Reference + +If C<$output> is an array reference, the uncompressed data will be +pushed onto the array. + +=item An Output FileGlob + +If C<$output> is a string that is delimited by the characters "<" and ">" +C<bunzip2> will assume that it is an I<output fileglob string>. The +output is the list of files that match the fileglob. + +When C<$output> is an fileglob string, C<$input> must also be a fileglob +string. Anything else is an error. + +=back + +If the C<$output> parameter is any other type, C<undef> will be returned. + +=head2 Notes + +When C<$input> maps to multiple compressed files/buffers and C<$output> is +a single file/buffer, after uncompression C<$output> will contain a +concatenation of all the uncompressed data from each of the input +files/buffers. + +=head2 Optional Parameters + +Unless specified below, the optional parameters for C<bunzip2>, +C<OPTS>, are the same as those used with the OO interface defined in the +L</"Constructor Options"> section below. + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option applies to any input or output data streams to +C<bunzip2> that are filehandles. + +If C<AutoClose> is specified, and the value is true, it will result in all +input and/or output filehandles being closed once C<bunzip2> has +completed. + +This parameter defaults to 0. + +=item C<< BinModeOut => 0|1 >> + +When writing to a file or filehandle, set C<binmode> before writing to the +file. + +Defaults to 0. + +=item C<< Append => 0|1 >> + +TODO + +=item C<< MultiStream => 0|1 >> + +If the input file/buffer contains multiple compressed data streams, this +option will uncompress the whole lot as a single data stream. + +Defaults to 0. + +=item C<< TrailingData => $scalar >> + +Returns the data, if any, that is present immediately after the compressed +data stream once uncompression is complete. + +This option can be used when there is useful information immediately +following the compressed data stream, and you don't know the length of the +compressed data stream. + +If the input is a buffer, C<trailingData> will return everything from the +end of the compressed data stream to the end of the buffer. + +If the input is a filehandle, C<trailingData> will return the data that is +left in the filehandle input buffer once the end of the compressed data +stream has been reached. You can then use the filehandle to read the rest +of the input file. + +Don't bother using C<trailingData> if the input is a filename. + +If you know the length of the compressed data stream before you start +uncompressing, you can avoid having to use C<trailingData> by setting the +C<InputLength> option. + +=back + +=head2 Examples + +To read the contents of the file C<file1.txt.bz2> and write the +compressed data to the file C<file1.txt>. + + use strict ; + use warnings ; + use IO::Uncompress::Bunzip2 qw(bunzip2 $Bunzip2Error) ; + + my $input = "file1.txt.bz2"; + my $output = "file1.txt"; + bunzip2 $input => $output + or die "bunzip2 failed: $Bunzip2Error\n"; + +To read from an existing Perl filehandle, C<$input>, and write the +uncompressed data to a buffer, C<$buffer>. + + use strict ; + use warnings ; + use IO::Uncompress::Bunzip2 qw(bunzip2 $Bunzip2Error) ; + use IO::File ; + + my $input = new IO::File "<file1.txt.bz2" + or die "Cannot open 'file1.txt.bz2': $!\n" ; + my $buffer ; + bunzip2 $input => \$buffer + or die "bunzip2 failed: $Bunzip2Error\n"; + +To uncompress all files in the directory "/my/home" that match "*.txt.bz2" and store the compressed data in the same directory + + use strict ; + use warnings ; + use IO::Uncompress::Bunzip2 qw(bunzip2 $Bunzip2Error) ; + + bunzip2 '</my/home/*.txt.bz2>' => '</my/home/#1.txt>' + or die "bunzip2 failed: $Bunzip2Error\n"; + +and if you want to compress each file one at a time, this will do the trick + + use strict ; + use warnings ; + use IO::Uncompress::Bunzip2 qw(bunzip2 $Bunzip2Error) ; + + for my $input ( glob "/my/home/*.txt.bz2" ) + { + my $output = $input; + $output =~ s/.bz2// ; + bunzip2 $input => $output + or die "Error compressing '$input': $Bunzip2Error\n"; + } + +=head1 OO Interface + +=head2 Constructor + +The format of the constructor for IO::Uncompress::Bunzip2 is shown below + + my $z = new IO::Uncompress::Bunzip2 $input [OPTS] + or die "IO::Uncompress::Bunzip2 failed: $Bunzip2Error\n"; + +Returns an C<IO::Uncompress::Bunzip2> object on success and undef on failure. +The variable C<$Bunzip2Error> will contain an error message on failure. + +If you are running Perl 5.005 or better the object, C<$z>, returned from +IO::Uncompress::Bunzip2 can be used exactly like an L<IO::File|IO::File> filehandle. +This means that all normal input file operations can be carried out with +C<$z>. For example, to read a line from a compressed file/buffer you can +use either of these forms + + $line = $z->getline(); + $line = <$z>; + +The mandatory parameter C<$input> is used to determine the source of the +compressed data. This parameter can take one of three forms. + +=over 5 + +=item A filename + +If the C<$input> parameter is a scalar, it is assumed to be a filename. This +file will be opened for reading and the compressed data will be read from it. + +=item A filehandle + +If the C<$input> parameter is a filehandle, the compressed data will be +read from it. +The string '-' can be used as an alias for standard input. + +=item A scalar reference + +If C<$input> is a scalar reference, the compressed data will be read from +C<$$output>. + +=back + +=head2 Constructor Options + +The option names defined below are case insensitive and can be optionally +prefixed by a '-'. So all of the following are valid + + -AutoClose + -autoclose + AUTOCLOSE + autoclose + +OPTS is a combination of the following options: + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option is only valid when the C<$input> parameter is a filehandle. If +specified, and the value is true, it will result in the file being closed once +either the C<close> method is called or the IO::Uncompress::Bunzip2 object is +destroyed. + +This parameter defaults to 0. + +=item C<< MultiStream => 0|1 >> + +Allows multiple concatenated compressed streams to be treated as a single +compressed stream. Decompression will stop once either the end of the +file/buffer is reached, an error is encountered (premature eof, corrupt +compressed data) or the end of a stream is not immediately followed by the +start of another stream. + +This parameter defaults to 0. + +=item C<< Prime => $string >> + +This option will uncompress the contents of C<$string> before processing the +input file/buffer. + +This option can be useful when the compressed data is embedded in another +file/data structure and it is not possible to work out where the compressed +data begins without having to read the first few bytes. If this is the +case, the uncompression can be I<primed> with these bytes using this +option. + +=item C<< Transparent => 0|1 >> + +If this option is set and the input file/buffer is not compressed data, +the module will allow reading of it anyway. + +In addition, if the input file/buffer does contain compressed data and +there is non-compressed data immediately following it, setting this option +will make this module treat the whole file/bufffer as a single data stream. + +This option defaults to 1. + +=item C<< BlockSize => $num >> + +When reading the compressed input data, IO::Uncompress::Bunzip2 will read it in +blocks of C<$num> bytes. + +This option defaults to 4096. + +=item C<< InputLength => $size >> + +When present this option will limit the number of compressed bytes read +from the input file/buffer to C<$size>. This option can be used in the +situation where there is useful data directly after the compressed data +stream and you know beforehand the exact length of the compressed data +stream. + +This option is mostly used when reading from a filehandle, in which case +the file pointer will be left pointing to the first byte directly after the +compressed data stream. + +This option defaults to off. + +=item C<< Append => 0|1 >> + +This option controls what the C<read> method does with uncompressed data. + +If set to 1, all uncompressed data will be appended to the output parameter +of the C<read> method. + +If set to 0, the contents of the output parameter of the C<read> method +will be overwritten by the uncompressed data. + +Defaults to 0. + +=item C<< Strict => 0|1 >> + +This option is a no-op. + +=item C<< Small => 0|1 >> + +When non-zero this options will make bzip2 use a decompression algorithm +that uses less memory at the expense of increasing the amount of time +taken for decompression. + +Default is 0. + +=back + +=head2 Examples + +TODO + +=head1 Methods + +=head2 read + +Usage is + + $status = $z->read($buffer) + +Reads a block of compressed data (the size the the compressed block is +determined by the C<Buffer> option in the constructor), uncompresses it and +writes any uncompressed data into C<$buffer>. If the C<Append> parameter is +set in the constructor, the uncompressed data will be appended to the +C<$buffer> parameter. Otherwise C<$buffer> will be overwritten. + +Returns the number of uncompressed bytes written to C<$buffer>, zero if eof +or a negative number on error. + +=head2 read + +Usage is + + $status = $z->read($buffer, $length) + $status = $z->read($buffer, $length, $offset) + + $status = read($z, $buffer, $length) + $status = read($z, $buffer, $length, $offset) + +Attempt to read C<$length> bytes of uncompressed data into C<$buffer>. + +The main difference between this form of the C<read> method and the +previous one, is that this one will attempt to return I<exactly> C<$length> +bytes. The only circumstances that this function will not is if end-of-file +or an IO error is encountered. + +Returns the number of uncompressed bytes written to C<$buffer>, zero if eof +or a negative number on error. + +=head2 getline + +Usage is + + $line = $z->getline() + $line = <$z> + +Reads a single line. + +This method fully supports the use of of the variable C<$/> (or +C<$INPUT_RECORD_SEPARATOR> or C<$RS> when C<English> is in use) to +determine what constitutes an end of line. Paragraph mode, record mode and +file slurp mode are all supported. + +=head2 getc + +Usage is + + $char = $z->getc() + +Read a single character. + +=head2 ungetc + +Usage is + + $char = $z->ungetc($string) + +=head2 getHeaderInfo + +Usage is + + $hdr = $z->getHeaderInfo(); + @hdrs = $z->getHeaderInfo(); + +This method returns either a hash reference (in scalar context) or a list +or hash references (in array context) that contains information about each +of the header fields in the compressed data stream(s). + +=head2 tell + +Usage is + + $z->tell() + tell $z + +Returns the uncompressed file offset. + +=head2 eof + +Usage is + + $z->eof(); + eof($z); + +Returns true if the end of the compressed input stream has been reached. + +=head2 seek + + $z->seek($position, $whence); + seek($z, $position, $whence); + +Provides a sub-set of the C<seek> functionality, with the restriction +that it is only legal to seek forward in the input file/buffer. +It is a fatal error to attempt to seek backward. + +The C<$whence> parameter takes one the usual values, namely SEEK_SET, +SEEK_CUR or SEEK_END. + +Returns 1 on success, 0 on failure. + +=head2 binmode + +Usage is + + $z->binmode + binmode $z ; + +This is a noop provided for completeness. + +=head2 opened + + $z->opened() + +Returns true if the object currently refers to a opened file/buffer. + +=head2 autoflush + + my $prev = $z->autoflush() + my $prev = $z->autoflush(EXPR) + +If the C<$z> object is associated with a file or a filehandle, this method +returns the current autoflush setting for the underlying filehandle. If +C<EXPR> is present, and is non-zero, it will enable flushing after every +write/print operation. + +If C<$z> is associated with a buffer, this method has no effect and always +returns C<undef>. + +B<Note> that the special variable C<$|> B<cannot> be used to set or +retrieve the autoflush setting. + +=head2 input_line_number + + $z->input_line_number() + $z->input_line_number(EXPR) + +Returns the current uncompressed line number. If C<EXPR> is present it has +the effect of setting the line number. Note that setting the line number +does not change the current position within the file/buffer being read. + +The contents of C<$/> are used to to determine what constitutes a line +terminator. + +=head2 fileno + + $z->fileno() + fileno($z) + +If the C<$z> object is associated with a file or a filehandle, C<fileno> +will return the underlying file descriptor. Once the C<close> method is +called C<fileno> will return C<undef>. + +If the C<$z> object is is associated with a buffer, this method will return +C<undef>. + +=head2 close + + $z->close() ; + close $z ; + +Closes the output file/buffer. + +For most versions of Perl this method will be automatically invoked if +the IO::Uncompress::Bunzip2 object is destroyed (either explicitly or by the +variable with the reference to the object going out of scope). The +exceptions are Perl versions 5.005 through 5.00504 and 5.8.0. In +these cases, the C<close> method will be called automatically, but +not until global destruction of all live objects when the program is +terminating. + +Therefore, if you want your scripts to be able to run on all versions +of Perl, you should call C<close> explicitly and not rely on automatic +closing. + +Returns true on success, otherwise 0. + +If the C<AutoClose> option has been enabled when the IO::Uncompress::Bunzip2 +object was created, and the object is associated with a file, the +underlying file will also be closed. + +=head2 nextStream + +Usage is + + my $status = $z->nextStream(); + +Skips to the next compressed data stream in the input file/buffer. If a new +compressed data stream is found, the eof marker will be cleared and C<$.> +will be reset to 0. + +Returns 1 if a new stream was found, 0 if none was found, and -1 if an +error was encountered. + +=head2 trailingData + +Usage is + + my $data = $z->trailingData(); + +Returns the data, if any, that is present immediately after the compressed +data stream once uncompression is complete. It only makes sense to call +this method once the end of the compressed data stream has been +encountered. + +This option can be used when there is useful information immediately +following the compressed data stream, and you don't know the length of the +compressed data stream. + +If the input is a buffer, C<trailingData> will return everything from the +end of the compressed data stream to the end of the buffer. + +If the input is a filehandle, C<trailingData> will return the data that is +left in the filehandle input buffer once the end of the compressed data +stream has been reached. You can then use the filehandle to read the rest +of the input file. + +Don't bother using C<trailingData> if the input is a filename. + +If you know the length of the compressed data stream before you start +uncompressing, you can avoid having to use C<trailingData> by setting the +C<InputLength> option in the constructor. + +=head1 Importing + +No symbolic constants are required by this IO::Uncompress::Bunzip2 at present. + +=over 5 + +=item :all + +Imports C<bunzip2> and C<$Bunzip2Error>. +Same as doing this + + use IO::Uncompress::Bunzip2 qw(bunzip2 $Bunzip2Error) ; + +=back + +=head1 EXAMPLES + +=head2 Working with Net::FTP + +See L<IO::Uncompress::Bunzip2::FAQ|IO::Uncompress::Bunzip2::FAQ/"Compressed files and Net::FTP"> + +=head1 SEE ALSO + +L<Compress::Zlib>, L<IO::Compress::Gzip>, L<IO::Uncompress::Gunzip>, L<IO::Compress::Deflate>, L<IO::Uncompress::Inflate>, L<IO::Compress::RawDeflate>, L<IO::Uncompress::RawInflate>, L<IO::Compress::Bzip2>, L<IO::Compress::Lzop>, L<IO::Uncompress::UnLzop>, L<IO::Compress::Lzf>, L<IO::Uncompress::UnLzf>, L<IO::Uncompress::AnyInflate>, L<IO::Uncompress::AnyUncompress> + +L<Compress::Zlib::FAQ|Compress::Zlib::FAQ> + +L<File::GlobMapper|File::GlobMapper>, L<Archive::Zip|Archive::Zip>, +L<Archive::Tar|Archive::Tar>, +L<IO::Zlib|IO::Zlib> + +The primary site for the bzip2 program is F<http://www.bzip.org>. + +See the module L<Compress::Bzip2|Compress::Bzip2> + +=head1 AUTHOR + +This module was written by Paul Marquess, F<pmqs@cpan.org>. + +=head1 MODIFICATION HISTORY + +See the Changes file. + +=head1 COPYRIGHT AND LICENSE + +Copyright (c) 2005-2008 Paul Marquess. All rights reserved. + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + diff --git a/Master/tlpkg/tlperl/lib/IO/Uncompress/Gunzip.pm b/Master/tlpkg/tlperl/lib/IO/Uncompress/Gunzip.pm new file mode 100644 index 00000000000..f3e4e6561f0 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Uncompress/Gunzip.pm @@ -0,0 +1,1111 @@ + +package IO::Uncompress::Gunzip ; + +require 5.004 ; + +# for RFC1952 + +use strict ; +use warnings; +use bytes; + +use IO::Uncompress::RawInflate 2.024 ; + +use Compress::Raw::Zlib 2.024 qw( crc32 ) ; +use IO::Compress::Base::Common 2.024 qw(:Status createSelfTiedObject); +use IO::Compress::Gzip::Constants 2.024 ; +use IO::Compress::Zlib::Extra 2.024 ; + +require Exporter ; + +our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, $GunzipError); + +@ISA = qw( Exporter IO::Uncompress::RawInflate ); +@EXPORT_OK = qw( $GunzipError gunzip ); +%EXPORT_TAGS = %IO::Uncompress::RawInflate::DEFLATE_CONSTANTS ; +push @{ $EXPORT_TAGS{all} }, @EXPORT_OK ; +Exporter::export_ok_tags('all'); + +$GunzipError = ''; + +$VERSION = '2.024'; + +sub new +{ + my $class = shift ; + $GunzipError = ''; + my $obj = createSelfTiedObject($class, \$GunzipError); + + $obj->_create(undef, 0, @_); +} + +sub gunzip +{ + my $obj = createSelfTiedObject(undef, \$GunzipError); + return $obj->_inf(@_) ; +} + +sub getExtraParams +{ + use IO::Compress::Base::Common 2.024 qw(:Parse); + return ( 'ParseExtra' => [1, 1, Parse_boolean, 0] ) ; +} + +sub ckParams +{ + my $self = shift ; + my $got = shift ; + + # gunzip always needs crc32 + $got->value('CRC32' => 1); + + return 1; +} + +sub ckMagic +{ + my $self = shift; + + my $magic ; + $self->smartReadExact(\$magic, GZIP_ID_SIZE); + + *$self->{HeaderPending} = $magic ; + + return $self->HeaderError("Minimum header size is " . + GZIP_MIN_HEADER_SIZE . " bytes") + if length $magic != GZIP_ID_SIZE ; + + return $self->HeaderError("Bad Magic") + if ! isGzipMagic($magic) ; + + *$self->{Type} = 'rfc1952'; + + return $magic ; +} + +sub readHeader +{ + my $self = shift; + my $magic = shift; + + return $self->_readGzipHeader($magic); +} + +sub chkTrailer +{ + my $self = shift; + my $trailer = shift; + + # Check CRC & ISIZE + my ($CRC32, $ISIZE) = unpack("V V", $trailer) ; + *$self->{Info}{CRC32} = $CRC32; + *$self->{Info}{ISIZE} = $ISIZE; + + if (*$self->{Strict}) { + return $self->TrailerError("CRC mismatch") + if $CRC32 != *$self->{Uncomp}->crc32() ; + + my $exp_isize = *$self->{UnCompSize}->get32bit(); + return $self->TrailerError("ISIZE mismatch. Got $ISIZE" + . ", expected $exp_isize") + if $ISIZE != $exp_isize ; + } + + return STATUS_OK; +} + +sub isGzipMagic +{ + my $buffer = shift ; + return 0 if length $buffer < GZIP_ID_SIZE ; + my ($id1, $id2) = unpack("C C", $buffer) ; + return $id1 == GZIP_ID1 && $id2 == GZIP_ID2 ; +} + +sub _readFullGzipHeader($) +{ + my ($self) = @_ ; + my $magic = '' ; + + $self->smartReadExact(\$magic, GZIP_ID_SIZE); + + *$self->{HeaderPending} = $magic ; + + return $self->HeaderError("Minimum header size is " . + GZIP_MIN_HEADER_SIZE . " bytes") + if length $magic != GZIP_ID_SIZE ; + + + return $self->HeaderError("Bad Magic") + if ! isGzipMagic($magic) ; + + my $status = $self->_readGzipHeader($magic); + delete *$self->{Transparent} if ! defined $status ; + return $status ; +} + +sub _readGzipHeader($) +{ + my ($self, $magic) = @_ ; + my ($HeaderCRC) ; + my ($buffer) = '' ; + + $self->smartReadExact(\$buffer, GZIP_MIN_HEADER_SIZE - GZIP_ID_SIZE) + or return $self->HeaderError("Minimum header size is " . + GZIP_MIN_HEADER_SIZE . " bytes") ; + + my $keep = $magic . $buffer ; + *$self->{HeaderPending} = $keep ; + + # now split out the various parts + my ($cm, $flag, $mtime, $xfl, $os) = unpack("C C V C C", $buffer) ; + + $cm == GZIP_CM_DEFLATED + or return $self->HeaderError("Not Deflate (CM is $cm)") ; + + # check for use of reserved bits + return $self->HeaderError("Use of Reserved Bits in FLG field.") + if $flag & GZIP_FLG_RESERVED ; + + my $EXTRA ; + my @EXTRA = () ; + if ($flag & GZIP_FLG_FEXTRA) { + $EXTRA = "" ; + $self->smartReadExact(\$buffer, GZIP_FEXTRA_HEADER_SIZE) + or return $self->TruncatedHeader("FEXTRA Length") ; + + my ($XLEN) = unpack("v", $buffer) ; + $self->smartReadExact(\$EXTRA, $XLEN) + or return $self->TruncatedHeader("FEXTRA Body"); + $keep .= $buffer . $EXTRA ; + + if ($XLEN && *$self->{'ParseExtra'}) { + my $bad = IO::Compress::Zlib::Extra::parseRawExtra($EXTRA, + \@EXTRA, 1, 1); + return $self->HeaderError($bad) + if defined $bad; + } + } + + my $origname ; + if ($flag & GZIP_FLG_FNAME) { + $origname = "" ; + while (1) { + $self->smartReadExact(\$buffer, 1) + or return $self->TruncatedHeader("FNAME"); + last if $buffer eq GZIP_NULL_BYTE ; + $origname .= $buffer + } + $keep .= $origname . GZIP_NULL_BYTE ; + + return $self->HeaderError("Non ISO 8859-1 Character found in Name") + if *$self->{Strict} && $origname =~ /$GZIP_FNAME_INVALID_CHAR_RE/o ; + } + + my $comment ; + if ($flag & GZIP_FLG_FCOMMENT) { + $comment = ""; + while (1) { + $self->smartReadExact(\$buffer, 1) + or return $self->TruncatedHeader("FCOMMENT"); + last if $buffer eq GZIP_NULL_BYTE ; + $comment .= $buffer + } + $keep .= $comment . GZIP_NULL_BYTE ; + + return $self->HeaderError("Non ISO 8859-1 Character found in Comment") + if *$self->{Strict} && $comment =~ /$GZIP_FCOMMENT_INVALID_CHAR_RE/o ; + } + + if ($flag & GZIP_FLG_FHCRC) { + $self->smartReadExact(\$buffer, GZIP_FHCRC_SIZE) + or return $self->TruncatedHeader("FHCRC"); + + $HeaderCRC = unpack("v", $buffer) ; + my $crc16 = crc32($keep) & 0xFF ; + + return $self->HeaderError("CRC16 mismatch.") + if *$self->{Strict} && $crc16 != $HeaderCRC; + + $keep .= $buffer ; + } + + # Assume compression method is deflated for xfl tests + #if ($xfl) { + #} + + *$self->{Type} = 'rfc1952'; + + return { + 'Type' => 'rfc1952', + 'FingerprintLength' => 2, + 'HeaderLength' => length $keep, + 'TrailerLength' => GZIP_TRAILER_SIZE, + 'Header' => $keep, + 'isMinimalHeader' => $keep eq GZIP_MINIMUM_HEADER ? 1 : 0, + + 'MethodID' => $cm, + 'MethodName' => $cm == GZIP_CM_DEFLATED ? "Deflated" : "Unknown" , + 'TextFlag' => $flag & GZIP_FLG_FTEXT ? 1 : 0, + 'HeaderCRCFlag' => $flag & GZIP_FLG_FHCRC ? 1 : 0, + 'NameFlag' => $flag & GZIP_FLG_FNAME ? 1 : 0, + 'CommentFlag' => $flag & GZIP_FLG_FCOMMENT ? 1 : 0, + 'ExtraFlag' => $flag & GZIP_FLG_FEXTRA ? 1 : 0, + 'Name' => $origname, + 'Comment' => $comment, + 'Time' => $mtime, + 'OsID' => $os, + 'OsName' => defined $GZIP_OS_Names{$os} + ? $GZIP_OS_Names{$os} : "Unknown", + 'HeaderCRC' => $HeaderCRC, + 'Flags' => $flag, + 'ExtraFlags' => $xfl, + 'ExtraFieldRaw' => $EXTRA, + 'ExtraField' => [ @EXTRA ], + + + #'CompSize'=> $compsize, + #'CRC32'=> $CRC32, + #'OrigSize'=> $ISIZE, + } +} + + +1; + +__END__ + + +=head1 NAME + +IO::Uncompress::Gunzip - Read RFC 1952 files/buffers + +=head1 SYNOPSIS + + use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ; + + my $status = gunzip $input => $output [,OPTS] + or die "gunzip failed: $GunzipError\n"; + + my $z = new IO::Uncompress::Gunzip $input [OPTS] + or die "gunzip failed: $GunzipError\n"; + + $status = $z->read($buffer) + $status = $z->read($buffer, $length) + $status = $z->read($buffer, $length, $offset) + $line = $z->getline() + $char = $z->getc() + $char = $z->ungetc() + $char = $z->opened() + + $status = $z->inflateSync() + + $data = $z->trailingData() + $status = $z->nextStream() + $data = $z->getHeaderInfo() + $z->tell() + $z->seek($position, $whence) + $z->binmode() + $z->fileno() + $z->eof() + $z->close() + + $GunzipError ; + + # IO::File mode + + <$z> + read($z, $buffer); + read($z, $buffer, $length); + read($z, $buffer, $length, $offset); + tell($z) + seek($z, $position, $whence) + binmode($z) + fileno($z) + eof($z) + close($z) + +=head1 DESCRIPTION + +This module provides a Perl interface that allows the reading of +files/buffers that conform to RFC 1952. + +For writing RFC 1952 files/buffers, see the companion module IO::Compress::Gzip. + +=head1 Functional Interface + +A top-level function, C<gunzip>, is provided to carry out +"one-shot" uncompression between buffers and/or files. For finer +control over the uncompression process, see the L</"OO Interface"> +section. + + use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ; + + gunzip $input => $output [,OPTS] + or die "gunzip failed: $GunzipError\n"; + +The functional interface needs Perl5.005 or better. + +=head2 gunzip $input => $output [, OPTS] + +C<gunzip> expects at least two parameters, C<$input> and C<$output>. + +=head3 The C<$input> parameter + +The parameter, C<$input>, is used to define the source of +the compressed data. + +It can take one of the following forms: + +=over 5 + +=item A filename + +If the C<$input> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for reading and the input data +will be read from it. + +=item A filehandle + +If the C<$input> parameter is a filehandle, the input data will be +read from it. +The string '-' can be used as an alias for standard input. + +=item A scalar reference + +If C<$input> is a scalar reference, the input data will be read +from C<$$input>. + +=item An array reference + +If C<$input> is an array reference, each element in the array must be a +filename. + +The input data will be read from each file in turn. + +The complete array will be walked to ensure that it only +contains valid filenames before any data is uncompressed. + +=item An Input FileGlob string + +If C<$input> is a string that is delimited by the characters "<" and ">" +C<gunzip> will assume that it is an I<input fileglob string>. The +input is the list of files that match the fileglob. + +If the fileglob does not match any files ... + +See L<File::GlobMapper|File::GlobMapper> for more details. + +=back + +If the C<$input> parameter is any other type, C<undef> will be returned. + +=head3 The C<$output> parameter + +The parameter C<$output> is used to control the destination of the +uncompressed data. This parameter can take one of these forms. + +=over 5 + +=item A filename + +If the C<$output> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for writing and the uncompressed +data will be written to it. + +=item A filehandle + +If the C<$output> parameter is a filehandle, the uncompressed data +will be written to it. +The string '-' can be used as an alias for standard output. + +=item A scalar reference + +If C<$output> is a scalar reference, the uncompressed data will be +stored in C<$$output>. + +=item An Array Reference + +If C<$output> is an array reference, the uncompressed data will be +pushed onto the array. + +=item An Output FileGlob + +If C<$output> is a string that is delimited by the characters "<" and ">" +C<gunzip> will assume that it is an I<output fileglob string>. The +output is the list of files that match the fileglob. + +When C<$output> is an fileglob string, C<$input> must also be a fileglob +string. Anything else is an error. + +=back + +If the C<$output> parameter is any other type, C<undef> will be returned. + +=head2 Notes + +When C<$input> maps to multiple compressed files/buffers and C<$output> is +a single file/buffer, after uncompression C<$output> will contain a +concatenation of all the uncompressed data from each of the input +files/buffers. + +=head2 Optional Parameters + +Unless specified below, the optional parameters for C<gunzip>, +C<OPTS>, are the same as those used with the OO interface defined in the +L</"Constructor Options"> section below. + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option applies to any input or output data streams to +C<gunzip> that are filehandles. + +If C<AutoClose> is specified, and the value is true, it will result in all +input and/or output filehandles being closed once C<gunzip> has +completed. + +This parameter defaults to 0. + +=item C<< BinModeOut => 0|1 >> + +When writing to a file or filehandle, set C<binmode> before writing to the +file. + +Defaults to 0. + +=item C<< Append => 0|1 >> + +The behaviour of this option is dependent on the type of output data +stream. + +=over 5 + +=item * A Buffer + +If C<Append> is enabled, all uncompressed data will be append to the end of +the output buffer. Otherwise the output buffer will be cleared before any +uncompressed data is written to it. + +=item * A Filename + +If C<Append> is enabled, the file will be opened in append mode. Otherwise +the contents of the file, if any, will be truncated before any uncompressed +data is written to it. + +=item * A Filehandle + +If C<Append> is enabled, the filehandle will be positioned to the end of +the file via a call to C<seek> before any uncompressed data is +written to it. Otherwise the file pointer will not be moved. + +=back + +When C<Append> is specified, and set to true, it will I<append> all uncompressed +data to the output data stream. + +So when the output is a filehandle it will carry out a seek to the eof +before writing any uncompressed data. If the output is a filename, it will be opened for +appending. If the output is a buffer, all uncompressed data will be appened to +the existing buffer. + +Conversely when C<Append> is not specified, or it is present and is set to +false, it will operate as follows. + +When the output is a filename, it will truncate the contents of the file +before writing any uncompressed data. If the output is a filehandle +its position will not be changed. If the output is a buffer, it will be +wiped before any uncompressed data is output. + +Defaults to 0. + +=item C<< MultiStream => 0|1 >> + +If the input file/buffer contains multiple compressed data streams, this +option will uncompress the whole lot as a single data stream. + +Defaults to 0. + +=item C<< TrailingData => $scalar >> + +Returns the data, if any, that is present immediately after the compressed +data stream once uncompression is complete. + +This option can be used when there is useful information immediately +following the compressed data stream, and you don't know the length of the +compressed data stream. + +If the input is a buffer, C<trailingData> will return everything from the +end of the compressed data stream to the end of the buffer. + +If the input is a filehandle, C<trailingData> will return the data that is +left in the filehandle input buffer once the end of the compressed data +stream has been reached. You can then use the filehandle to read the rest +of the input file. + +Don't bother using C<trailingData> if the input is a filename. + +If you know the length of the compressed data stream before you start +uncompressing, you can avoid having to use C<trailingData> by setting the +C<InputLength> option. + +=back + +=head2 Examples + +To read the contents of the file C<file1.txt.gz> and write the +uncompressed data to the file C<file1.txt>. + + use strict ; + use warnings ; + use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ; + + my $input = "file1.txt.gz"; + my $output = "file1.txt"; + gunzip $input => $output + or die "gunzip failed: $GunzipError\n"; + +To read from an existing Perl filehandle, C<$input>, and write the +uncompressed data to a buffer, C<$buffer>. + + use strict ; + use warnings ; + use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ; + use IO::File ; + + my $input = new IO::File "<file1.txt.gz" + or die "Cannot open 'file1.txt.gz': $!\n" ; + my $buffer ; + gunzip $input => \$buffer + or die "gunzip failed: $GunzipError\n"; + +To uncompress all files in the directory "/my/home" that match "*.txt.gz" and store the compressed data in the same directory + + use strict ; + use warnings ; + use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ; + + gunzip '</my/home/*.txt.gz>' => '</my/home/#1.txt>' + or die "gunzip failed: $GunzipError\n"; + +and if you want to compress each file one at a time, this will do the trick + + use strict ; + use warnings ; + use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ; + + for my $input ( glob "/my/home/*.txt.gz" ) + { + my $output = $input; + $output =~ s/.gz// ; + gunzip $input => $output + or die "Error compressing '$input': $GunzipError\n"; + } + +=head1 OO Interface + +=head2 Constructor + +The format of the constructor for IO::Uncompress::Gunzip is shown below + + my $z = new IO::Uncompress::Gunzip $input [OPTS] + or die "IO::Uncompress::Gunzip failed: $GunzipError\n"; + +Returns an C<IO::Uncompress::Gunzip> object on success and undef on failure. +The variable C<$GunzipError> will contain an error message on failure. + +If you are running Perl 5.005 or better the object, C<$z>, returned from +IO::Uncompress::Gunzip can be used exactly like an L<IO::File|IO::File> filehandle. +This means that all normal input file operations can be carried out with +C<$z>. For example, to read a line from a compressed file/buffer you can +use either of these forms + + $line = $z->getline(); + $line = <$z>; + +The mandatory parameter C<$input> is used to determine the source of the +compressed data. This parameter can take one of three forms. + +=over 5 + +=item A filename + +If the C<$input> parameter is a scalar, it is assumed to be a filename. This +file will be opened for reading and the compressed data will be read from it. + +=item A filehandle + +If the C<$input> parameter is a filehandle, the compressed data will be +read from it. +The string '-' can be used as an alias for standard input. + +=item A scalar reference + +If C<$input> is a scalar reference, the compressed data will be read from +C<$$output>. + +=back + +=head2 Constructor Options + +The option names defined below are case insensitive and can be optionally +prefixed by a '-'. So all of the following are valid + + -AutoClose + -autoclose + AUTOCLOSE + autoclose + +OPTS is a combination of the following options: + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option is only valid when the C<$input> parameter is a filehandle. If +specified, and the value is true, it will result in the file being closed once +either the C<close> method is called or the IO::Uncompress::Gunzip object is +destroyed. + +This parameter defaults to 0. + +=item C<< MultiStream => 0|1 >> + +Allows multiple concatenated compressed streams to be treated as a single +compressed stream. Decompression will stop once either the end of the +file/buffer is reached, an error is encountered (premature eof, corrupt +compressed data) or the end of a stream is not immediately followed by the +start of another stream. + +This parameter defaults to 0. + +=item C<< Prime => $string >> + +This option will uncompress the contents of C<$string> before processing the +input file/buffer. + +This option can be useful when the compressed data is embedded in another +file/data structure and it is not possible to work out where the compressed +data begins without having to read the first few bytes. If this is the +case, the uncompression can be I<primed> with these bytes using this +option. + +=item C<< Transparent => 0|1 >> + +If this option is set and the input file/buffer is not compressed data, +the module will allow reading of it anyway. + +In addition, if the input file/buffer does contain compressed data and +there is non-compressed data immediately following it, setting this option +will make this module treat the whole file/bufffer as a single data stream. + +This option defaults to 1. + +=item C<< BlockSize => $num >> + +When reading the compressed input data, IO::Uncompress::Gunzip will read it in +blocks of C<$num> bytes. + +This option defaults to 4096. + +=item C<< InputLength => $size >> + +When present this option will limit the number of compressed bytes read +from the input file/buffer to C<$size>. This option can be used in the +situation where there is useful data directly after the compressed data +stream and you know beforehand the exact length of the compressed data +stream. + +This option is mostly used when reading from a filehandle, in which case +the file pointer will be left pointing to the first byte directly after the +compressed data stream. + +This option defaults to off. + +=item C<< Append => 0|1 >> + +This option controls what the C<read> method does with uncompressed data. + +If set to 1, all uncompressed data will be appended to the output parameter +of the C<read> method. + +If set to 0, the contents of the output parameter of the C<read> method +will be overwritten by the uncompressed data. + +Defaults to 0. + +=item C<< Strict => 0|1 >> + +This option controls whether the extra checks defined below are used when +carrying out the decompression. When Strict is on, the extra tests are +carried out, when Strict is off they are not. + +The default for this option is off. + +=over 5 + +=item 1 + +If the FHCRC bit is set in the gzip FLG header byte, the CRC16 bytes in the +header must match the crc16 value of the gzip header actually read. + +=item 2 + +If the gzip header contains a name field (FNAME) it consists solely of ISO +8859-1 characters. + +=item 3 + +If the gzip header contains a comment field (FCOMMENT) it consists solely +of ISO 8859-1 characters plus line-feed. + +=item 4 + +If the gzip FEXTRA header field is present it must conform to the sub-field +structure as defined in RFC 1952. + +=item 5 + +The CRC32 and ISIZE trailer fields must be present. + +=item 6 + +The value of the CRC32 field read must match the crc32 value of the +uncompressed data actually contained in the gzip file. + +=item 7 + +The value of the ISIZE fields read must match the length of the +uncompressed data actually read from the file. + +=back + +=item C<< ParseExtra => 0|1 >> +If the gzip FEXTRA header field is present and this option is set, it will +force the module to check that it conforms to the sub-field structure as +defined in RFC 1952. + +If the C<Strict> is on it will automatically enable this option. + +Defaults to 0. + +=back + +=head2 Examples + +TODO + +=head1 Methods + +=head2 read + +Usage is + + $status = $z->read($buffer) + +Reads a block of compressed data (the size the the compressed block is +determined by the C<Buffer> option in the constructor), uncompresses it and +writes any uncompressed data into C<$buffer>. If the C<Append> parameter is +set in the constructor, the uncompressed data will be appended to the +C<$buffer> parameter. Otherwise C<$buffer> will be overwritten. + +Returns the number of uncompressed bytes written to C<$buffer>, zero if eof +or a negative number on error. + +=head2 read + +Usage is + + $status = $z->read($buffer, $length) + $status = $z->read($buffer, $length, $offset) + + $status = read($z, $buffer, $length) + $status = read($z, $buffer, $length, $offset) + +Attempt to read C<$length> bytes of uncompressed data into C<$buffer>. + +The main difference between this form of the C<read> method and the +previous one, is that this one will attempt to return I<exactly> C<$length> +bytes. The only circumstances that this function will not is if end-of-file +or an IO error is encountered. + +Returns the number of uncompressed bytes written to C<$buffer>, zero if eof +or a negative number on error. + +=head2 getline + +Usage is + + $line = $z->getline() + $line = <$z> + +Reads a single line. + +This method fully supports the use of of the variable C<$/> (or +C<$INPUT_RECORD_SEPARATOR> or C<$RS> when C<English> is in use) to +determine what constitutes an end of line. Paragraph mode, record mode and +file slurp mode are all supported. + +=head2 getc + +Usage is + + $char = $z->getc() + +Read a single character. + +=head2 ungetc + +Usage is + + $char = $z->ungetc($string) + +=head2 inflateSync + +Usage is + + $status = $z->inflateSync() + +TODO + +=head2 getHeaderInfo + +Usage is + + $hdr = $z->getHeaderInfo(); + @hdrs = $z->getHeaderInfo(); + +This method returns either a hash reference (in scalar context) or a list +or hash references (in array context) that contains information about each +of the header fields in the compressed data stream(s). + +=over 5 + +=item Name + +The contents of the Name header field, if present. If no name is +present, the value will be undef. Note this is different from a zero length +name, which will return an empty string. + +=item Comment + +The contents of the Comment header field, if present. If no comment is +present, the value will be undef. Note this is different from a zero length +comment, which will return an empty string. + +=back + +=head2 tell + +Usage is + + $z->tell() + tell $z + +Returns the uncompressed file offset. + +=head2 eof + +Usage is + + $z->eof(); + eof($z); + +Returns true if the end of the compressed input stream has been reached. + +=head2 seek + + $z->seek($position, $whence); + seek($z, $position, $whence); + +Provides a sub-set of the C<seek> functionality, with the restriction +that it is only legal to seek forward in the input file/buffer. +It is a fatal error to attempt to seek backward. + +The C<$whence> parameter takes one the usual values, namely SEEK_SET, +SEEK_CUR or SEEK_END. + +Returns 1 on success, 0 on failure. + +=head2 binmode + +Usage is + + $z->binmode + binmode $z ; + +This is a noop provided for completeness. + +=head2 opened + + $z->opened() + +Returns true if the object currently refers to a opened file/buffer. + +=head2 autoflush + + my $prev = $z->autoflush() + my $prev = $z->autoflush(EXPR) + +If the C<$z> object is associated with a file or a filehandle, this method +returns the current autoflush setting for the underlying filehandle. If +C<EXPR> is present, and is non-zero, it will enable flushing after every +write/print operation. + +If C<$z> is associated with a buffer, this method has no effect and always +returns C<undef>. + +B<Note> that the special variable C<$|> B<cannot> be used to set or +retrieve the autoflush setting. + +=head2 input_line_number + + $z->input_line_number() + $z->input_line_number(EXPR) + +Returns the current uncompressed line number. If C<EXPR> is present it has +the effect of setting the line number. Note that setting the line number +does not change the current position within the file/buffer being read. + +The contents of C<$/> are used to to determine what constitutes a line +terminator. + +=head2 fileno + + $z->fileno() + fileno($z) + +If the C<$z> object is associated with a file or a filehandle, C<fileno> +will return the underlying file descriptor. Once the C<close> method is +called C<fileno> will return C<undef>. + +If the C<$z> object is is associated with a buffer, this method will return +C<undef>. + +=head2 close + + $z->close() ; + close $z ; + +Closes the output file/buffer. + +For most versions of Perl this method will be automatically invoked if +the IO::Uncompress::Gunzip object is destroyed (either explicitly or by the +variable with the reference to the object going out of scope). The +exceptions are Perl versions 5.005 through 5.00504 and 5.8.0. In +these cases, the C<close> method will be called automatically, but +not until global destruction of all live objects when the program is +terminating. + +Therefore, if you want your scripts to be able to run on all versions +of Perl, you should call C<close> explicitly and not rely on automatic +closing. + +Returns true on success, otherwise 0. + +If the C<AutoClose> option has been enabled when the IO::Uncompress::Gunzip +object was created, and the object is associated with a file, the +underlying file will also be closed. + +=head2 nextStream + +Usage is + + my $status = $z->nextStream(); + +Skips to the next compressed data stream in the input file/buffer. If a new +compressed data stream is found, the eof marker will be cleared and C<$.> +will be reset to 0. + +Returns 1 if a new stream was found, 0 if none was found, and -1 if an +error was encountered. + +=head2 trailingData + +Usage is + + my $data = $z->trailingData(); + +Returns the data, if any, that is present immediately after the compressed +data stream once uncompression is complete. It only makes sense to call +this method once the end of the compressed data stream has been +encountered. + +This option can be used when there is useful information immediately +following the compressed data stream, and you don't know the length of the +compressed data stream. + +If the input is a buffer, C<trailingData> will return everything from the +end of the compressed data stream to the end of the buffer. + +If the input is a filehandle, C<trailingData> will return the data that is +left in the filehandle input buffer once the end of the compressed data +stream has been reached. You can then use the filehandle to read the rest +of the input file. + +Don't bother using C<trailingData> if the input is a filename. + +If you know the length of the compressed data stream before you start +uncompressing, you can avoid having to use C<trailingData> by setting the +C<InputLength> option in the constructor. + +=head1 Importing + +No symbolic constants are required by this IO::Uncompress::Gunzip at present. + +=over 5 + +=item :all + +Imports C<gunzip> and C<$GunzipError>. +Same as doing this + + use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ; + +=back + +=head1 EXAMPLES + +=head2 Working with Net::FTP + +See L<IO::Uncompress::Gunzip::FAQ|IO::Uncompress::Gunzip::FAQ/"Compressed files and Net::FTP"> + +=head1 SEE ALSO + +L<Compress::Zlib>, L<IO::Compress::Gzip>, L<IO::Compress::Deflate>, L<IO::Uncompress::Inflate>, L<IO::Compress::RawDeflate>, L<IO::Uncompress::RawInflate>, L<IO::Compress::Bzip2>, L<IO::Uncompress::Bunzip2>, L<IO::Compress::Lzma>, L<IO::Uncompress::UnLzma>, L<IO::Compress::Xz>, L<IO::Uncompress::UnXz>, L<IO::Compress::Lzop>, L<IO::Uncompress::UnLzop>, L<IO::Compress::Lzf>, L<IO::Uncompress::UnLzf>, L<IO::Uncompress::AnyInflate>, L<IO::Uncompress::AnyUncompress> + +L<Compress::Zlib::FAQ|Compress::Zlib::FAQ> + +L<File::GlobMapper|File::GlobMapper>, L<Archive::Zip|Archive::Zip>, +L<Archive::Tar|Archive::Tar>, +L<IO::Zlib|IO::Zlib> + +For RFC 1950, 1951 and 1952 see +F<http://www.faqs.org/rfcs/rfc1950.html>, +F<http://www.faqs.org/rfcs/rfc1951.html> and +F<http://www.faqs.org/rfcs/rfc1952.html> + +The I<zlib> compression library was written by Jean-loup Gailly +F<gzip@prep.ai.mit.edu> and Mark Adler F<madler@alumni.caltech.edu>. + +The primary site for the I<zlib> compression library is +F<http://www.zlib.org>. + +The primary site for gzip is F<http://www.gzip.org>. + +=head1 AUTHOR + +This module was written by Paul Marquess, F<pmqs@cpan.org>. + +=head1 MODIFICATION HISTORY + +See the Changes file. + +=head1 COPYRIGHT AND LICENSE + +Copyright (c) 2005-2010 Paul Marquess. All rights reserved. + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + diff --git a/Master/tlpkg/tlperl/lib/IO/Uncompress/Inflate.pm b/Master/tlpkg/tlperl/lib/IO/Uncompress/Inflate.pm new file mode 100644 index 00000000000..956f62e0835 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Uncompress/Inflate.pm @@ -0,0 +1,982 @@ +package IO::Uncompress::Inflate ; +# for RFC1950 + +use strict ; +use warnings; +use bytes; + +use IO::Compress::Base::Common 2.024 qw(:Status createSelfTiedObject); +use IO::Compress::Zlib::Constants 2.024 ; + +use IO::Uncompress::RawInflate 2.024 ; + +require Exporter ; +our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, $InflateError); + +$VERSION = '2.024'; +$InflateError = ''; + +@ISA = qw( Exporter IO::Uncompress::RawInflate ); +@EXPORT_OK = qw( $InflateError inflate ) ; +%EXPORT_TAGS = %IO::Uncompress::RawInflate::DEFLATE_CONSTANTS ; +push @{ $EXPORT_TAGS{all} }, @EXPORT_OK ; +Exporter::export_ok_tags('all'); + + +sub new +{ + my $class = shift ; + my $obj = createSelfTiedObject($class, \$InflateError); + + $obj->_create(undef, 0, @_); +} + +sub inflate +{ + my $obj = createSelfTiedObject(undef, \$InflateError); + return $obj->_inf(@_); +} + +sub getExtraParams +{ + return (); +} + +sub ckParams +{ + my $self = shift ; + my $got = shift ; + + # gunzip always needs adler32 + $got->value('ADLER32' => 1); + + return 1; +} + +sub ckMagic +{ + my $self = shift; + + my $magic ; + $self->smartReadExact(\$magic, ZLIB_HEADER_SIZE); + + *$self->{HeaderPending} = $magic ; + + return $self->HeaderError("Header size is " . + ZLIB_HEADER_SIZE . " bytes") + if length $magic != ZLIB_HEADER_SIZE; + + #return $self->HeaderError("CRC mismatch.") + return undef + if ! $self->isZlibMagic($magic) ; + + *$self->{Type} = 'rfc1950'; + return $magic; +} + +sub readHeader +{ + my $self = shift; + my $magic = shift ; + + return $self->_readDeflateHeader($magic) ; +} + +sub chkTrailer +{ + my $self = shift; + my $trailer = shift; + + my $ADLER32 = unpack("N", $trailer) ; + *$self->{Info}{ADLER32} = $ADLER32; + return $self->TrailerError("CRC mismatch") + if *$self->{Strict} && $ADLER32 != *$self->{Uncomp}->adler32() ; + + return STATUS_OK; +} + + + +sub isZlibMagic +{ + my $self = shift; + my $buffer = shift ; + + return 0 + if length $buffer < ZLIB_HEADER_SIZE ; + + my $hdr = unpack("n", $buffer) ; + #return 0 if $hdr % 31 != 0 ; + return $self->HeaderError("CRC mismatch.") + if $hdr % 31 != 0 ; + + my ($CMF, $FLG) = unpack "C C", $buffer; + my $cm = bits($CMF, ZLIB_CMF_CM_OFFSET, ZLIB_CMF_CM_BITS) ; + + # Only Deflate supported + return $self->HeaderError("Not Deflate (CM is $cm)") + if $cm != ZLIB_CMF_CM_DEFLATED ; + + # Max window value is 7 for Deflate. + my $cinfo = bits($CMF, ZLIB_CMF_CINFO_OFFSET, ZLIB_CMF_CINFO_BITS) ; + return $self->HeaderError("CINFO > " . ZLIB_CMF_CINFO_MAX . + " (CINFO is $cinfo)") + if $cinfo > ZLIB_CMF_CINFO_MAX ; + + return 1; +} + +sub bits +{ + my $data = shift ; + my $offset = shift ; + my $mask = shift ; + + ($data >> $offset ) & $mask & 0xFF ; +} + + +sub _readDeflateHeader +{ + my ($self, $buffer) = @_ ; + +# if (! $buffer) { +# $self->smartReadExact(\$buffer, ZLIB_HEADER_SIZE); +# +# *$self->{HeaderPending} = $buffer ; +# +# return $self->HeaderError("Header size is " . +# ZLIB_HEADER_SIZE . " bytes") +# if length $buffer != ZLIB_HEADER_SIZE; +# +# return $self->HeaderError("CRC mismatch.") +# if ! isZlibMagic($buffer) ; +# } + + my ($CMF, $FLG) = unpack "C C", $buffer; + my $FDICT = bits($FLG, ZLIB_FLG_FDICT_OFFSET, ZLIB_FLG_FDICT_BITS ), + + my $cm = bits($CMF, ZLIB_CMF_CM_OFFSET, ZLIB_CMF_CM_BITS) ; + $cm == ZLIB_CMF_CM_DEFLATED + or return $self->HeaderError("Not Deflate (CM is $cm)") ; + + my $DICTID; + if ($FDICT) { + $self->smartReadExact(\$buffer, ZLIB_FDICT_SIZE) + or return $self->TruncatedHeader("FDICT"); + + $DICTID = unpack("N", $buffer) ; + } + + *$self->{Type} = 'rfc1950'; + + return { + 'Type' => 'rfc1950', + 'FingerprintLength' => ZLIB_HEADER_SIZE, + 'HeaderLength' => ZLIB_HEADER_SIZE, + 'TrailerLength' => ZLIB_TRAILER_SIZE, + 'Header' => $buffer, + + CMF => $CMF , + CM => bits($CMF, ZLIB_CMF_CM_OFFSET, ZLIB_CMF_CM_BITS ), + CINFO => bits($CMF, ZLIB_CMF_CINFO_OFFSET, ZLIB_CMF_CINFO_BITS ), + FLG => $FLG , + FCHECK => bits($FLG, ZLIB_FLG_FCHECK_OFFSET, ZLIB_FLG_FCHECK_BITS), + FDICT => bits($FLG, ZLIB_FLG_FDICT_OFFSET, ZLIB_FLG_FDICT_BITS ), + FLEVEL => bits($FLG, ZLIB_FLG_LEVEL_OFFSET, ZLIB_FLG_LEVEL_BITS ), + DICTID => $DICTID , + + }; +} + + + + +1 ; + +__END__ + + +=head1 NAME + +IO::Uncompress::Inflate - Read RFC 1950 files/buffers + +=head1 SYNOPSIS + + use IO::Uncompress::Inflate qw(inflate $InflateError) ; + + my $status = inflate $input => $output [,OPTS] + or die "inflate failed: $InflateError\n"; + + my $z = new IO::Uncompress::Inflate $input [OPTS] + or die "inflate failed: $InflateError\n"; + + $status = $z->read($buffer) + $status = $z->read($buffer, $length) + $status = $z->read($buffer, $length, $offset) + $line = $z->getline() + $char = $z->getc() + $char = $z->ungetc() + $char = $z->opened() + + $status = $z->inflateSync() + + $data = $z->trailingData() + $status = $z->nextStream() + $data = $z->getHeaderInfo() + $z->tell() + $z->seek($position, $whence) + $z->binmode() + $z->fileno() + $z->eof() + $z->close() + + $InflateError ; + + # IO::File mode + + <$z> + read($z, $buffer); + read($z, $buffer, $length); + read($z, $buffer, $length, $offset); + tell($z) + seek($z, $position, $whence) + binmode($z) + fileno($z) + eof($z) + close($z) + +=head1 DESCRIPTION + +This module provides a Perl interface that allows the reading of +files/buffers that conform to RFC 1950. + +For writing RFC 1950 files/buffers, see the companion module IO::Compress::Deflate. + +=head1 Functional Interface + +A top-level function, C<inflate>, is provided to carry out +"one-shot" uncompression between buffers and/or files. For finer +control over the uncompression process, see the L</"OO Interface"> +section. + + use IO::Uncompress::Inflate qw(inflate $InflateError) ; + + inflate $input => $output [,OPTS] + or die "inflate failed: $InflateError\n"; + +The functional interface needs Perl5.005 or better. + +=head2 inflate $input => $output [, OPTS] + +C<inflate> expects at least two parameters, C<$input> and C<$output>. + +=head3 The C<$input> parameter + +The parameter, C<$input>, is used to define the source of +the compressed data. + +It can take one of the following forms: + +=over 5 + +=item A filename + +If the C<$input> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for reading and the input data +will be read from it. + +=item A filehandle + +If the C<$input> parameter is a filehandle, the input data will be +read from it. +The string '-' can be used as an alias for standard input. + +=item A scalar reference + +If C<$input> is a scalar reference, the input data will be read +from C<$$input>. + +=item An array reference + +If C<$input> is an array reference, each element in the array must be a +filename. + +The input data will be read from each file in turn. + +The complete array will be walked to ensure that it only +contains valid filenames before any data is uncompressed. + +=item An Input FileGlob string + +If C<$input> is a string that is delimited by the characters "<" and ">" +C<inflate> will assume that it is an I<input fileglob string>. The +input is the list of files that match the fileglob. + +If the fileglob does not match any files ... + +See L<File::GlobMapper|File::GlobMapper> for more details. + +=back + +If the C<$input> parameter is any other type, C<undef> will be returned. + +=head3 The C<$output> parameter + +The parameter C<$output> is used to control the destination of the +uncompressed data. This parameter can take one of these forms. + +=over 5 + +=item A filename + +If the C<$output> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for writing and the uncompressed +data will be written to it. + +=item A filehandle + +If the C<$output> parameter is a filehandle, the uncompressed data +will be written to it. +The string '-' can be used as an alias for standard output. + +=item A scalar reference + +If C<$output> is a scalar reference, the uncompressed data will be +stored in C<$$output>. + +=item An Array Reference + +If C<$output> is an array reference, the uncompressed data will be +pushed onto the array. + +=item An Output FileGlob + +If C<$output> is a string that is delimited by the characters "<" and ">" +C<inflate> will assume that it is an I<output fileglob string>. The +output is the list of files that match the fileglob. + +When C<$output> is an fileglob string, C<$input> must also be a fileglob +string. Anything else is an error. + +=back + +If the C<$output> parameter is any other type, C<undef> will be returned. + +=head2 Notes + +When C<$input> maps to multiple compressed files/buffers and C<$output> is +a single file/buffer, after uncompression C<$output> will contain a +concatenation of all the uncompressed data from each of the input +files/buffers. + +=head2 Optional Parameters + +Unless specified below, the optional parameters for C<inflate>, +C<OPTS>, are the same as those used with the OO interface defined in the +L</"Constructor Options"> section below. + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option applies to any input or output data streams to +C<inflate> that are filehandles. + +If C<AutoClose> is specified, and the value is true, it will result in all +input and/or output filehandles being closed once C<inflate> has +completed. + +This parameter defaults to 0. + +=item C<< BinModeOut => 0|1 >> + +When writing to a file or filehandle, set C<binmode> before writing to the +file. + +Defaults to 0. + +=item C<< Append => 0|1 >> + +The behaviour of this option is dependent on the type of output data +stream. + +=over 5 + +=item * A Buffer + +If C<Append> is enabled, all uncompressed data will be append to the end of +the output buffer. Otherwise the output buffer will be cleared before any +uncompressed data is written to it. + +=item * A Filename + +If C<Append> is enabled, the file will be opened in append mode. Otherwise +the contents of the file, if any, will be truncated before any uncompressed +data is written to it. + +=item * A Filehandle + +If C<Append> is enabled, the filehandle will be positioned to the end of +the file via a call to C<seek> before any uncompressed data is +written to it. Otherwise the file pointer will not be moved. + +=back + +When C<Append> is specified, and set to true, it will I<append> all uncompressed +data to the output data stream. + +So when the output is a filehandle it will carry out a seek to the eof +before writing any uncompressed data. If the output is a filename, it will be opened for +appending. If the output is a buffer, all uncompressed data will be appened to +the existing buffer. + +Conversely when C<Append> is not specified, or it is present and is set to +false, it will operate as follows. + +When the output is a filename, it will truncate the contents of the file +before writing any uncompressed data. If the output is a filehandle +its position will not be changed. If the output is a buffer, it will be +wiped before any uncompressed data is output. + +Defaults to 0. + +=item C<< MultiStream => 0|1 >> + +If the input file/buffer contains multiple compressed data streams, this +option will uncompress the whole lot as a single data stream. + +Defaults to 0. + +=item C<< TrailingData => $scalar >> + +Returns the data, if any, that is present immediately after the compressed +data stream once uncompression is complete. + +This option can be used when there is useful information immediately +following the compressed data stream, and you don't know the length of the +compressed data stream. + +If the input is a buffer, C<trailingData> will return everything from the +end of the compressed data stream to the end of the buffer. + +If the input is a filehandle, C<trailingData> will return the data that is +left in the filehandle input buffer once the end of the compressed data +stream has been reached. You can then use the filehandle to read the rest +of the input file. + +Don't bother using C<trailingData> if the input is a filename. + +If you know the length of the compressed data stream before you start +uncompressing, you can avoid having to use C<trailingData> by setting the +C<InputLength> option. + +=back + +=head2 Examples + +To read the contents of the file C<file1.txt.1950> and write the +uncompressed data to the file C<file1.txt>. + + use strict ; + use warnings ; + use IO::Uncompress::Inflate qw(inflate $InflateError) ; + + my $input = "file1.txt.1950"; + my $output = "file1.txt"; + inflate $input => $output + or die "inflate failed: $InflateError\n"; + +To read from an existing Perl filehandle, C<$input>, and write the +uncompressed data to a buffer, C<$buffer>. + + use strict ; + use warnings ; + use IO::Uncompress::Inflate qw(inflate $InflateError) ; + use IO::File ; + + my $input = new IO::File "<file1.txt.1950" + or die "Cannot open 'file1.txt.1950': $!\n" ; + my $buffer ; + inflate $input => \$buffer + or die "inflate failed: $InflateError\n"; + +To uncompress all files in the directory "/my/home" that match "*.txt.1950" and store the compressed data in the same directory + + use strict ; + use warnings ; + use IO::Uncompress::Inflate qw(inflate $InflateError) ; + + inflate '</my/home/*.txt.1950>' => '</my/home/#1.txt>' + or die "inflate failed: $InflateError\n"; + +and if you want to compress each file one at a time, this will do the trick + + use strict ; + use warnings ; + use IO::Uncompress::Inflate qw(inflate $InflateError) ; + + for my $input ( glob "/my/home/*.txt.1950" ) + { + my $output = $input; + $output =~ s/.1950// ; + inflate $input => $output + or die "Error compressing '$input': $InflateError\n"; + } + +=head1 OO Interface + +=head2 Constructor + +The format of the constructor for IO::Uncompress::Inflate is shown below + + my $z = new IO::Uncompress::Inflate $input [OPTS] + or die "IO::Uncompress::Inflate failed: $InflateError\n"; + +Returns an C<IO::Uncompress::Inflate> object on success and undef on failure. +The variable C<$InflateError> will contain an error message on failure. + +If you are running Perl 5.005 or better the object, C<$z>, returned from +IO::Uncompress::Inflate can be used exactly like an L<IO::File|IO::File> filehandle. +This means that all normal input file operations can be carried out with +C<$z>. For example, to read a line from a compressed file/buffer you can +use either of these forms + + $line = $z->getline(); + $line = <$z>; + +The mandatory parameter C<$input> is used to determine the source of the +compressed data. This parameter can take one of three forms. + +=over 5 + +=item A filename + +If the C<$input> parameter is a scalar, it is assumed to be a filename. This +file will be opened for reading and the compressed data will be read from it. + +=item A filehandle + +If the C<$input> parameter is a filehandle, the compressed data will be +read from it. +The string '-' can be used as an alias for standard input. + +=item A scalar reference + +If C<$input> is a scalar reference, the compressed data will be read from +C<$$output>. + +=back + +=head2 Constructor Options + +The option names defined below are case insensitive and can be optionally +prefixed by a '-'. So all of the following are valid + + -AutoClose + -autoclose + AUTOCLOSE + autoclose + +OPTS is a combination of the following options: + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option is only valid when the C<$input> parameter is a filehandle. If +specified, and the value is true, it will result in the file being closed once +either the C<close> method is called or the IO::Uncompress::Inflate object is +destroyed. + +This parameter defaults to 0. + +=item C<< MultiStream => 0|1 >> + +Allows multiple concatenated compressed streams to be treated as a single +compressed stream. Decompression will stop once either the end of the +file/buffer is reached, an error is encountered (premature eof, corrupt +compressed data) or the end of a stream is not immediately followed by the +start of another stream. + +This parameter defaults to 0. + +=item C<< Prime => $string >> + +This option will uncompress the contents of C<$string> before processing the +input file/buffer. + +This option can be useful when the compressed data is embedded in another +file/data structure and it is not possible to work out where the compressed +data begins without having to read the first few bytes. If this is the +case, the uncompression can be I<primed> with these bytes using this +option. + +=item C<< Transparent => 0|1 >> + +If this option is set and the input file/buffer is not compressed data, +the module will allow reading of it anyway. + +In addition, if the input file/buffer does contain compressed data and +there is non-compressed data immediately following it, setting this option +will make this module treat the whole file/bufffer as a single data stream. + +This option defaults to 1. + +=item C<< BlockSize => $num >> + +When reading the compressed input data, IO::Uncompress::Inflate will read it in +blocks of C<$num> bytes. + +This option defaults to 4096. + +=item C<< InputLength => $size >> + +When present this option will limit the number of compressed bytes read +from the input file/buffer to C<$size>. This option can be used in the +situation where there is useful data directly after the compressed data +stream and you know beforehand the exact length of the compressed data +stream. + +This option is mostly used when reading from a filehandle, in which case +the file pointer will be left pointing to the first byte directly after the +compressed data stream. + +This option defaults to off. + +=item C<< Append => 0|1 >> + +This option controls what the C<read> method does with uncompressed data. + +If set to 1, all uncompressed data will be appended to the output parameter +of the C<read> method. + +If set to 0, the contents of the output parameter of the C<read> method +will be overwritten by the uncompressed data. + +Defaults to 0. + +=item C<< Strict => 0|1 >> + +This option controls whether the extra checks defined below are used when +carrying out the decompression. When Strict is on, the extra tests are +carried out, when Strict is off they are not. + +The default for this option is off. + +=over 5 + +=item 1 + +The ADLER32 checksum field must be present. + +=item 2 + +The value of the ADLER32 field read must match the adler32 value of the +uncompressed data actually contained in the file. + +=back + +=back + +=head2 Examples + +TODO + +=head1 Methods + +=head2 read + +Usage is + + $status = $z->read($buffer) + +Reads a block of compressed data (the size the the compressed block is +determined by the C<Buffer> option in the constructor), uncompresses it and +writes any uncompressed data into C<$buffer>. If the C<Append> parameter is +set in the constructor, the uncompressed data will be appended to the +C<$buffer> parameter. Otherwise C<$buffer> will be overwritten. + +Returns the number of uncompressed bytes written to C<$buffer>, zero if eof +or a negative number on error. + +=head2 read + +Usage is + + $status = $z->read($buffer, $length) + $status = $z->read($buffer, $length, $offset) + + $status = read($z, $buffer, $length) + $status = read($z, $buffer, $length, $offset) + +Attempt to read C<$length> bytes of uncompressed data into C<$buffer>. + +The main difference between this form of the C<read> method and the +previous one, is that this one will attempt to return I<exactly> C<$length> +bytes. The only circumstances that this function will not is if end-of-file +or an IO error is encountered. + +Returns the number of uncompressed bytes written to C<$buffer>, zero if eof +or a negative number on error. + +=head2 getline + +Usage is + + $line = $z->getline() + $line = <$z> + +Reads a single line. + +This method fully supports the use of of the variable C<$/> (or +C<$INPUT_RECORD_SEPARATOR> or C<$RS> when C<English> is in use) to +determine what constitutes an end of line. Paragraph mode, record mode and +file slurp mode are all supported. + +=head2 getc + +Usage is + + $char = $z->getc() + +Read a single character. + +=head2 ungetc + +Usage is + + $char = $z->ungetc($string) + +=head2 inflateSync + +Usage is + + $status = $z->inflateSync() + +TODO + +=head2 getHeaderInfo + +Usage is + + $hdr = $z->getHeaderInfo(); + @hdrs = $z->getHeaderInfo(); + +This method returns either a hash reference (in scalar context) or a list +or hash references (in array context) that contains information about each +of the header fields in the compressed data stream(s). + +=head2 tell + +Usage is + + $z->tell() + tell $z + +Returns the uncompressed file offset. + +=head2 eof + +Usage is + + $z->eof(); + eof($z); + +Returns true if the end of the compressed input stream has been reached. + +=head2 seek + + $z->seek($position, $whence); + seek($z, $position, $whence); + +Provides a sub-set of the C<seek> functionality, with the restriction +that it is only legal to seek forward in the input file/buffer. +It is a fatal error to attempt to seek backward. + +The C<$whence> parameter takes one the usual values, namely SEEK_SET, +SEEK_CUR or SEEK_END. + +Returns 1 on success, 0 on failure. + +=head2 binmode + +Usage is + + $z->binmode + binmode $z ; + +This is a noop provided for completeness. + +=head2 opened + + $z->opened() + +Returns true if the object currently refers to a opened file/buffer. + +=head2 autoflush + + my $prev = $z->autoflush() + my $prev = $z->autoflush(EXPR) + +If the C<$z> object is associated with a file or a filehandle, this method +returns the current autoflush setting for the underlying filehandle. If +C<EXPR> is present, and is non-zero, it will enable flushing after every +write/print operation. + +If C<$z> is associated with a buffer, this method has no effect and always +returns C<undef>. + +B<Note> that the special variable C<$|> B<cannot> be used to set or +retrieve the autoflush setting. + +=head2 input_line_number + + $z->input_line_number() + $z->input_line_number(EXPR) + +Returns the current uncompressed line number. If C<EXPR> is present it has +the effect of setting the line number. Note that setting the line number +does not change the current position within the file/buffer being read. + +The contents of C<$/> are used to to determine what constitutes a line +terminator. + +=head2 fileno + + $z->fileno() + fileno($z) + +If the C<$z> object is associated with a file or a filehandle, C<fileno> +will return the underlying file descriptor. Once the C<close> method is +called C<fileno> will return C<undef>. + +If the C<$z> object is is associated with a buffer, this method will return +C<undef>. + +=head2 close + + $z->close() ; + close $z ; + +Closes the output file/buffer. + +For most versions of Perl this method will be automatically invoked if +the IO::Uncompress::Inflate object is destroyed (either explicitly or by the +variable with the reference to the object going out of scope). The +exceptions are Perl versions 5.005 through 5.00504 and 5.8.0. In +these cases, the C<close> method will be called automatically, but +not until global destruction of all live objects when the program is +terminating. + +Therefore, if you want your scripts to be able to run on all versions +of Perl, you should call C<close> explicitly and not rely on automatic +closing. + +Returns true on success, otherwise 0. + +If the C<AutoClose> option has been enabled when the IO::Uncompress::Inflate +object was created, and the object is associated with a file, the +underlying file will also be closed. + +=head2 nextStream + +Usage is + + my $status = $z->nextStream(); + +Skips to the next compressed data stream in the input file/buffer. If a new +compressed data stream is found, the eof marker will be cleared and C<$.> +will be reset to 0. + +Returns 1 if a new stream was found, 0 if none was found, and -1 if an +error was encountered. + +=head2 trailingData + +Usage is + + my $data = $z->trailingData(); + +Returns the data, if any, that is present immediately after the compressed +data stream once uncompression is complete. It only makes sense to call +this method once the end of the compressed data stream has been +encountered. + +This option can be used when there is useful information immediately +following the compressed data stream, and you don't know the length of the +compressed data stream. + +If the input is a buffer, C<trailingData> will return everything from the +end of the compressed data stream to the end of the buffer. + +If the input is a filehandle, C<trailingData> will return the data that is +left in the filehandle input buffer once the end of the compressed data +stream has been reached. You can then use the filehandle to read the rest +of the input file. + +Don't bother using C<trailingData> if the input is a filename. + +If you know the length of the compressed data stream before you start +uncompressing, you can avoid having to use C<trailingData> by setting the +C<InputLength> option in the constructor. + +=head1 Importing + +No symbolic constants are required by this IO::Uncompress::Inflate at present. + +=over 5 + +=item :all + +Imports C<inflate> and C<$InflateError>. +Same as doing this + + use IO::Uncompress::Inflate qw(inflate $InflateError) ; + +=back + +=head1 EXAMPLES + +=head2 Working with Net::FTP + +See L<IO::Uncompress::Inflate::FAQ|IO::Uncompress::Inflate::FAQ/"Compressed files and Net::FTP"> + +=head1 SEE ALSO + +L<Compress::Zlib>, L<IO::Compress::Gzip>, L<IO::Uncompress::Gunzip>, L<IO::Compress::Deflate>, L<IO::Compress::RawDeflate>, L<IO::Uncompress::RawInflate>, L<IO::Compress::Bzip2>, L<IO::Uncompress::Bunzip2>, L<IO::Compress::Lzma>, L<IO::Uncompress::UnLzma>, L<IO::Compress::Xz>, L<IO::Uncompress::UnXz>, L<IO::Compress::Lzop>, L<IO::Uncompress::UnLzop>, L<IO::Compress::Lzf>, L<IO::Uncompress::UnLzf>, L<IO::Uncompress::AnyInflate>, L<IO::Uncompress::AnyUncompress> + +L<Compress::Zlib::FAQ|Compress::Zlib::FAQ> + +L<File::GlobMapper|File::GlobMapper>, L<Archive::Zip|Archive::Zip>, +L<Archive::Tar|Archive::Tar>, +L<IO::Zlib|IO::Zlib> + +For RFC 1950, 1951 and 1952 see +F<http://www.faqs.org/rfcs/rfc1950.html>, +F<http://www.faqs.org/rfcs/rfc1951.html> and +F<http://www.faqs.org/rfcs/rfc1952.html> + +The I<zlib> compression library was written by Jean-loup Gailly +F<gzip@prep.ai.mit.edu> and Mark Adler F<madler@alumni.caltech.edu>. + +The primary site for the I<zlib> compression library is +F<http://www.zlib.org>. + +The primary site for gzip is F<http://www.gzip.org>. + +=head1 AUTHOR + +This module was written by Paul Marquess, F<pmqs@cpan.org>. + +=head1 MODIFICATION HISTORY + +See the Changes file. + +=head1 COPYRIGHT AND LICENSE + +Copyright (c) 2005-2010 Paul Marquess. All rights reserved. + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + diff --git a/Master/tlpkg/tlperl/lib/IO/Uncompress/RawInflate.pm b/Master/tlpkg/tlperl/lib/IO/Uncompress/RawInflate.pm new file mode 100644 index 00000000000..f017fa0f599 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Uncompress/RawInflate.pm @@ -0,0 +1,1110 @@ +package IO::Uncompress::RawInflate ; +# for RFC1951 + +use strict ; +use warnings; +use bytes; + +use Compress::Raw::Zlib 2.024 ; +use IO::Compress::Base::Common 2.024 qw(:Status createSelfTiedObject); + +use IO::Uncompress::Base 2.024 ; +use IO::Uncompress::Adapter::Inflate 2.024 ; + +require Exporter ; +our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, %DEFLATE_CONSTANTS, $RawInflateError); + +$VERSION = '2.024'; +$RawInflateError = ''; + +@ISA = qw( Exporter IO::Uncompress::Base ); +@EXPORT_OK = qw( $RawInflateError rawinflate ) ; +%DEFLATE_CONSTANTS = (); +%EXPORT_TAGS = %IO::Uncompress::Base::EXPORT_TAGS ; +push @{ $EXPORT_TAGS{all} }, @EXPORT_OK ; +Exporter::export_ok_tags('all'); + +#{ +# # Execute at runtime +# my %bad; +# for my $module (qw(Compress::Raw::Zlib IO::Compress::Base::Common IO::Uncompress::Base IO::Uncompress::Adapter::Inflate)) +# { +# my $ver = ${ $module . "::VERSION"} ; +# +# $bad{$module} = $ver +# if $ver ne $VERSION; +# } +# +# if (keys %bad) +# { +# my $string = join "\n", map { "$_ $bad{$_}" } keys %bad; +# die caller(0)[0] . "needs version $VERSION mismatch\n$string\n"; +# } +#} + +sub new +{ + my $class = shift ; + my $obj = createSelfTiedObject($class, \$RawInflateError); + $obj->_create(undef, 0, @_); +} + +sub rawinflate +{ + my $obj = createSelfTiedObject(undef, \$RawInflateError); + return $obj->_inf(@_); +} + +sub getExtraParams +{ + return (); +} + +sub ckParams +{ + my $self = shift ; + my $got = shift ; + + return 1; +} + +sub mkUncomp +{ + my $self = shift ; + my $got = shift ; + + my ($obj, $errstr, $errno) = IO::Uncompress::Adapter::Inflate::mkUncompObject( + $got->value('CRC32'), + $got->value('ADLER32'), + $got->value('Scan'), + ); + + return $self->saveErrorString(undef, $errstr, $errno) + if ! defined $obj; + + *$self->{Uncomp} = $obj; + + my $magic = $self->ckMagic() + or return 0; + + *$self->{Info} = $self->readHeader($magic) + or return undef ; + + return 1; + +} + + +sub ckMagic +{ + my $self = shift; + + return $self->_isRaw() ; +} + +sub readHeader +{ + my $self = shift; + my $magic = shift ; + + return { + 'Type' => 'rfc1951', + 'FingerprintLength' => 0, + 'HeaderLength' => 0, + 'TrailerLength' => 0, + 'Header' => '' + }; +} + +sub chkTrailer +{ + return STATUS_OK ; +} + +sub _isRaw +{ + my $self = shift ; + + my $got = $self->_isRawx(@_); + + if ($got) { + *$self->{Pending} = *$self->{HeaderPending} ; + } + else { + $self->pushBack(*$self->{HeaderPending}); + *$self->{Uncomp}->reset(); + } + *$self->{HeaderPending} = ''; + + return $got ; +} + +sub _isRawx +{ + my $self = shift ; + my $magic = shift ; + + $magic = '' unless defined $magic ; + + my $buffer = ''; + + $self->smartRead(\$buffer, *$self->{BlockSize}) >= 0 + or return $self->saveErrorString(undef, "No data to read"); + + my $temp_buf = $magic . $buffer ; + *$self->{HeaderPending} = $temp_buf ; + $buffer = ''; + my $status = *$self->{Uncomp}->uncompr(\$temp_buf, \$buffer, $self->smartEof()) ; + + return $self->saveErrorString(undef, *$self->{Uncomp}{Error}, STATUS_ERROR) + if $status == STATUS_ERROR; + + $self->pushBack($temp_buf) ; + + return $self->saveErrorString(undef, "unexpected end of file", STATUS_ERROR) + if $self->smartEof() && $status != STATUS_ENDSTREAM; + + #my $buf_len = *$self->{Uncomp}->uncompressedBytes(); + my $buf_len = length $buffer; + + if ($status == STATUS_ENDSTREAM) { + if (*$self->{MultiStream} + && (length $temp_buf || ! $self->smartEof())){ + *$self->{NewStream} = 1 ; + *$self->{EndStream} = 0 ; + } + else { + *$self->{EndStream} = 1 ; + } + } + *$self->{HeaderPending} = $buffer ; + *$self->{InflatedBytesRead} = $buf_len ; + *$self->{TotalInflatedBytesRead} += $buf_len ; + *$self->{Type} = 'rfc1951'; + + $self->saveStatus(STATUS_OK); + + return { + 'Type' => 'rfc1951', + 'HeaderLength' => 0, + 'TrailerLength' => 0, + 'Header' => '' + }; +} + + +sub inflateSync +{ + my $self = shift ; + + # inflateSync is a no-op in Plain mode + return 1 + if *$self->{Plain} ; + + return 0 if *$self->{Closed} ; + #return G_EOF if !length *$self->{Pending} && *$self->{EndStream} ; + return 0 if ! length *$self->{Pending} && *$self->{EndStream} ; + + # Disable CRC check + *$self->{Strict} = 0 ; + + my $status ; + while (1) + { + my $temp_buf ; + + if (length *$self->{Pending} ) + { + $temp_buf = *$self->{Pending} ; + *$self->{Pending} = ''; + } + else + { + $status = $self->smartRead(\$temp_buf, *$self->{BlockSize}) ; + return $self->saveErrorString(0, "Error Reading Data") + if $status < 0 ; + + if ($status == 0 ) { + *$self->{EndStream} = 1 ; + return $self->saveErrorString(0, "unexpected end of file", STATUS_ERROR); + } + } + + $status = *$self->{Uncomp}->sync($temp_buf) ; + + if ($status == STATUS_OK) + { + *$self->{Pending} .= $temp_buf ; + return 1 ; + } + + last unless $status == STATUS_ERROR ; + } + + return 0; +} + +#sub performScan +#{ +# my $self = shift ; +# +# my $status ; +# my $end_offset = 0; +# +# $status = $self->scan() +# #or return $self->saveErrorString(undef, "Error Scanning: $$error_ref", $self->errorNo) ; +# or return $self->saveErrorString(G_ERR, "Error Scanning: $status") +# +# $status = $self->zap($end_offset) +# or return $self->saveErrorString(G_ERR, "Error Zapping: $status"); +# #or return $self->saveErrorString(undef, "Error Zapping: $$error_ref", $self->errorNo) ; +# +# #(*$obj->{Deflate}, $status) = $inf->createDeflate(); +# +## *$obj->{Header} = *$inf->{Info}{Header}; +## *$obj->{UnCompSize_32bit} = +## *$obj->{BytesWritten} = *$inf->{UnCompSize_32bit} ; +## *$obj->{CompSize_32bit} = *$inf->{CompSize_32bit} ; +# +# +## if ( $outType eq 'buffer') +## { substr( ${ *$self->{Buffer} }, $end_offset) = '' } +## elsif ($outType eq 'handle' || $outType eq 'filename') { +## *$self->{FH} = *$inf->{FH} ; +## delete *$inf->{FH}; +## *$obj->{FH}->flush() ; +## *$obj->{Handle} = 1 if $outType eq 'handle'; +## +## #seek(*$obj->{FH}, $end_offset, SEEK_SET) +## *$obj->{FH}->seek($end_offset, SEEK_SET) +## or return $obj->saveErrorString(undef, $!, $!) ; +## } +# +#} + +sub scan +{ + my $self = shift ; + + return 1 if *$self->{Closed} ; + return 1 if !length *$self->{Pending} && *$self->{EndStream} ; + + my $buffer = '' ; + my $len = 0; + + $len = $self->_raw_read(\$buffer, 1) + while ! *$self->{EndStream} && $len >= 0 ; + + #return $len if $len < 0 ? $len : 0 ; + return $len < 0 ? 0 : 1 ; +} + +sub zap +{ + my $self = shift ; + + my $headerLength = *$self->{Info}{HeaderLength}; + my $block_offset = $headerLength + *$self->{Uncomp}->getLastBlockOffset(); + $_[0] = $headerLength + *$self->{Uncomp}->getEndOffset(); + #printf "# End $_[0], headerlen $headerLength \n";; + #printf "# block_offset $block_offset %x\n", $block_offset; + my $byte ; + ( $self->smartSeek($block_offset) && + $self->smartRead(\$byte, 1) ) + or return $self->saveErrorString(0, $!, $!); + + #printf "#byte is %x\n", unpack('C*',$byte); + *$self->{Uncomp}->resetLastBlockByte($byte); + #printf "#to byte is %x\n", unpack('C*',$byte); + + ( $self->smartSeek($block_offset) && + $self->smartWrite($byte) ) + or return $self->saveErrorString(0, $!, $!); + + #$self->smartSeek($end_offset, 1); + + return 1 ; +} + +sub createDeflate +{ + my $self = shift ; + my ($def, $status) = *$self->{Uncomp}->createDeflateStream( + -AppendOutput => 1, + -WindowBits => - MAX_WBITS, + -CRC32 => *$self->{Params}->value('CRC32'), + -ADLER32 => *$self->{Params}->value('ADLER32'), + ); + + return wantarray ? ($status, $def) : $def ; +} + + +1; + +__END__ + + +=head1 NAME + +IO::Uncompress::RawInflate - Read RFC 1951 files/buffers + +=head1 SYNOPSIS + + use IO::Uncompress::RawInflate qw(rawinflate $RawInflateError) ; + + my $status = rawinflate $input => $output [,OPTS] + or die "rawinflate failed: $RawInflateError\n"; + + my $z = new IO::Uncompress::RawInflate $input [OPTS] + or die "rawinflate failed: $RawInflateError\n"; + + $status = $z->read($buffer) + $status = $z->read($buffer, $length) + $status = $z->read($buffer, $length, $offset) + $line = $z->getline() + $char = $z->getc() + $char = $z->ungetc() + $char = $z->opened() + + $status = $z->inflateSync() + + $data = $z->trailingData() + $status = $z->nextStream() + $data = $z->getHeaderInfo() + $z->tell() + $z->seek($position, $whence) + $z->binmode() + $z->fileno() + $z->eof() + $z->close() + + $RawInflateError ; + + # IO::File mode + + <$z> + read($z, $buffer); + read($z, $buffer, $length); + read($z, $buffer, $length, $offset); + tell($z) + seek($z, $position, $whence) + binmode($z) + fileno($z) + eof($z) + close($z) + +=head1 DESCRIPTION + +This module provides a Perl interface that allows the reading of +files/buffers that conform to RFC 1951. + +For writing RFC 1951 files/buffers, see the companion module IO::Compress::RawDeflate. + +=head1 Functional Interface + +A top-level function, C<rawinflate>, is provided to carry out +"one-shot" uncompression between buffers and/or files. For finer +control over the uncompression process, see the L</"OO Interface"> +section. + + use IO::Uncompress::RawInflate qw(rawinflate $RawInflateError) ; + + rawinflate $input => $output [,OPTS] + or die "rawinflate failed: $RawInflateError\n"; + +The functional interface needs Perl5.005 or better. + +=head2 rawinflate $input => $output [, OPTS] + +C<rawinflate> expects at least two parameters, C<$input> and C<$output>. + +=head3 The C<$input> parameter + +The parameter, C<$input>, is used to define the source of +the compressed data. + +It can take one of the following forms: + +=over 5 + +=item A filename + +If the C<$input> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for reading and the input data +will be read from it. + +=item A filehandle + +If the C<$input> parameter is a filehandle, the input data will be +read from it. +The string '-' can be used as an alias for standard input. + +=item A scalar reference + +If C<$input> is a scalar reference, the input data will be read +from C<$$input>. + +=item An array reference + +If C<$input> is an array reference, each element in the array must be a +filename. + +The input data will be read from each file in turn. + +The complete array will be walked to ensure that it only +contains valid filenames before any data is uncompressed. + +=item An Input FileGlob string + +If C<$input> is a string that is delimited by the characters "<" and ">" +C<rawinflate> will assume that it is an I<input fileglob string>. The +input is the list of files that match the fileglob. + +If the fileglob does not match any files ... + +See L<File::GlobMapper|File::GlobMapper> for more details. + +=back + +If the C<$input> parameter is any other type, C<undef> will be returned. + +=head3 The C<$output> parameter + +The parameter C<$output> is used to control the destination of the +uncompressed data. This parameter can take one of these forms. + +=over 5 + +=item A filename + +If the C<$output> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for writing and the uncompressed +data will be written to it. + +=item A filehandle + +If the C<$output> parameter is a filehandle, the uncompressed data +will be written to it. +The string '-' can be used as an alias for standard output. + +=item A scalar reference + +If C<$output> is a scalar reference, the uncompressed data will be +stored in C<$$output>. + +=item An Array Reference + +If C<$output> is an array reference, the uncompressed data will be +pushed onto the array. + +=item An Output FileGlob + +If C<$output> is a string that is delimited by the characters "<" and ">" +C<rawinflate> will assume that it is an I<output fileglob string>. The +output is the list of files that match the fileglob. + +When C<$output> is an fileglob string, C<$input> must also be a fileglob +string. Anything else is an error. + +=back + +If the C<$output> parameter is any other type, C<undef> will be returned. + +=head2 Notes + +When C<$input> maps to multiple compressed files/buffers and C<$output> is +a single file/buffer, after uncompression C<$output> will contain a +concatenation of all the uncompressed data from each of the input +files/buffers. + +=head2 Optional Parameters + +Unless specified below, the optional parameters for C<rawinflate>, +C<OPTS>, are the same as those used with the OO interface defined in the +L</"Constructor Options"> section below. + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option applies to any input or output data streams to +C<rawinflate> that are filehandles. + +If C<AutoClose> is specified, and the value is true, it will result in all +input and/or output filehandles being closed once C<rawinflate> has +completed. + +This parameter defaults to 0. + +=item C<< BinModeOut => 0|1 >> + +When writing to a file or filehandle, set C<binmode> before writing to the +file. + +Defaults to 0. + +=item C<< Append => 0|1 >> + +The behaviour of this option is dependent on the type of output data +stream. + +=over 5 + +=item * A Buffer + +If C<Append> is enabled, all uncompressed data will be append to the end of +the output buffer. Otherwise the output buffer will be cleared before any +uncompressed data is written to it. + +=item * A Filename + +If C<Append> is enabled, the file will be opened in append mode. Otherwise +the contents of the file, if any, will be truncated before any uncompressed +data is written to it. + +=item * A Filehandle + +If C<Append> is enabled, the filehandle will be positioned to the end of +the file via a call to C<seek> before any uncompressed data is +written to it. Otherwise the file pointer will not be moved. + +=back + +When C<Append> is specified, and set to true, it will I<append> all uncompressed +data to the output data stream. + +So when the output is a filehandle it will carry out a seek to the eof +before writing any uncompressed data. If the output is a filename, it will be opened for +appending. If the output is a buffer, all uncompressed data will be appened to +the existing buffer. + +Conversely when C<Append> is not specified, or it is present and is set to +false, it will operate as follows. + +When the output is a filename, it will truncate the contents of the file +before writing any uncompressed data. If the output is a filehandle +its position will not be changed. If the output is a buffer, it will be +wiped before any uncompressed data is output. + +Defaults to 0. + +=item C<< MultiStream => 0|1 >> + +This option is a no-op. + +=item C<< TrailingData => $scalar >> + +Returns the data, if any, that is present immediately after the compressed +data stream once uncompression is complete. + +This option can be used when there is useful information immediately +following the compressed data stream, and you don't know the length of the +compressed data stream. + +If the input is a buffer, C<trailingData> will return everything from the +end of the compressed data stream to the end of the buffer. + +If the input is a filehandle, C<trailingData> will return the data that is +left in the filehandle input buffer once the end of the compressed data +stream has been reached. You can then use the filehandle to read the rest +of the input file. + +Don't bother using C<trailingData> if the input is a filename. + +If you know the length of the compressed data stream before you start +uncompressing, you can avoid having to use C<trailingData> by setting the +C<InputLength> option. + +=back + +=head2 Examples + +To read the contents of the file C<file1.txt.1951> and write the +uncompressed data to the file C<file1.txt>. + + use strict ; + use warnings ; + use IO::Uncompress::RawInflate qw(rawinflate $RawInflateError) ; + + my $input = "file1.txt.1951"; + my $output = "file1.txt"; + rawinflate $input => $output + or die "rawinflate failed: $RawInflateError\n"; + +To read from an existing Perl filehandle, C<$input>, and write the +uncompressed data to a buffer, C<$buffer>. + + use strict ; + use warnings ; + use IO::Uncompress::RawInflate qw(rawinflate $RawInflateError) ; + use IO::File ; + + my $input = new IO::File "<file1.txt.1951" + or die "Cannot open 'file1.txt.1951': $!\n" ; + my $buffer ; + rawinflate $input => \$buffer + or die "rawinflate failed: $RawInflateError\n"; + +To uncompress all files in the directory "/my/home" that match "*.txt.1951" and store the compressed data in the same directory + + use strict ; + use warnings ; + use IO::Uncompress::RawInflate qw(rawinflate $RawInflateError) ; + + rawinflate '</my/home/*.txt.1951>' => '</my/home/#1.txt>' + or die "rawinflate failed: $RawInflateError\n"; + +and if you want to compress each file one at a time, this will do the trick + + use strict ; + use warnings ; + use IO::Uncompress::RawInflate qw(rawinflate $RawInflateError) ; + + for my $input ( glob "/my/home/*.txt.1951" ) + { + my $output = $input; + $output =~ s/.1951// ; + rawinflate $input => $output + or die "Error compressing '$input': $RawInflateError\n"; + } + +=head1 OO Interface + +=head2 Constructor + +The format of the constructor for IO::Uncompress::RawInflate is shown below + + my $z = new IO::Uncompress::RawInflate $input [OPTS] + or die "IO::Uncompress::RawInflate failed: $RawInflateError\n"; + +Returns an C<IO::Uncompress::RawInflate> object on success and undef on failure. +The variable C<$RawInflateError> will contain an error message on failure. + +If you are running Perl 5.005 or better the object, C<$z>, returned from +IO::Uncompress::RawInflate can be used exactly like an L<IO::File|IO::File> filehandle. +This means that all normal input file operations can be carried out with +C<$z>. For example, to read a line from a compressed file/buffer you can +use either of these forms + + $line = $z->getline(); + $line = <$z>; + +The mandatory parameter C<$input> is used to determine the source of the +compressed data. This parameter can take one of three forms. + +=over 5 + +=item A filename + +If the C<$input> parameter is a scalar, it is assumed to be a filename. This +file will be opened for reading and the compressed data will be read from it. + +=item A filehandle + +If the C<$input> parameter is a filehandle, the compressed data will be +read from it. +The string '-' can be used as an alias for standard input. + +=item A scalar reference + +If C<$input> is a scalar reference, the compressed data will be read from +C<$$output>. + +=back + +=head2 Constructor Options + +The option names defined below are case insensitive and can be optionally +prefixed by a '-'. So all of the following are valid + + -AutoClose + -autoclose + AUTOCLOSE + autoclose + +OPTS is a combination of the following options: + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option is only valid when the C<$input> parameter is a filehandle. If +specified, and the value is true, it will result in the file being closed once +either the C<close> method is called or the IO::Uncompress::RawInflate object is +destroyed. + +This parameter defaults to 0. + +=item C<< MultiStream => 0|1 >> + +Allows multiple concatenated compressed streams to be treated as a single +compressed stream. Decompression will stop once either the end of the +file/buffer is reached, an error is encountered (premature eof, corrupt +compressed data) or the end of a stream is not immediately followed by the +start of another stream. + +This parameter defaults to 0. + +=item C<< Prime => $string >> + +This option will uncompress the contents of C<$string> before processing the +input file/buffer. + +This option can be useful when the compressed data is embedded in another +file/data structure and it is not possible to work out where the compressed +data begins without having to read the first few bytes. If this is the +case, the uncompression can be I<primed> with these bytes using this +option. + +=item C<< Transparent => 0|1 >> + +If this option is set and the input file/buffer is not compressed data, +the module will allow reading of it anyway. + +In addition, if the input file/buffer does contain compressed data and +there is non-compressed data immediately following it, setting this option +will make this module treat the whole file/bufffer as a single data stream. + +This option defaults to 1. + +=item C<< BlockSize => $num >> + +When reading the compressed input data, IO::Uncompress::RawInflate will read it in +blocks of C<$num> bytes. + +This option defaults to 4096. + +=item C<< InputLength => $size >> + +When present this option will limit the number of compressed bytes read +from the input file/buffer to C<$size>. This option can be used in the +situation where there is useful data directly after the compressed data +stream and you know beforehand the exact length of the compressed data +stream. + +This option is mostly used when reading from a filehandle, in which case +the file pointer will be left pointing to the first byte directly after the +compressed data stream. + +This option defaults to off. + +=item C<< Append => 0|1 >> + +This option controls what the C<read> method does with uncompressed data. + +If set to 1, all uncompressed data will be appended to the output parameter +of the C<read> method. + +If set to 0, the contents of the output parameter of the C<read> method +will be overwritten by the uncompressed data. + +Defaults to 0. + +=item C<< Strict => 0|1 >> + +This option is a no-op. + +=back + +=head2 Examples + +TODO + +=head1 Methods + +=head2 read + +Usage is + + $status = $z->read($buffer) + +Reads a block of compressed data (the size the the compressed block is +determined by the C<Buffer> option in the constructor), uncompresses it and +writes any uncompressed data into C<$buffer>. If the C<Append> parameter is +set in the constructor, the uncompressed data will be appended to the +C<$buffer> parameter. Otherwise C<$buffer> will be overwritten. + +Returns the number of uncompressed bytes written to C<$buffer>, zero if eof +or a negative number on error. + +=head2 read + +Usage is + + $status = $z->read($buffer, $length) + $status = $z->read($buffer, $length, $offset) + + $status = read($z, $buffer, $length) + $status = read($z, $buffer, $length, $offset) + +Attempt to read C<$length> bytes of uncompressed data into C<$buffer>. + +The main difference between this form of the C<read> method and the +previous one, is that this one will attempt to return I<exactly> C<$length> +bytes. The only circumstances that this function will not is if end-of-file +or an IO error is encountered. + +Returns the number of uncompressed bytes written to C<$buffer>, zero if eof +or a negative number on error. + +=head2 getline + +Usage is + + $line = $z->getline() + $line = <$z> + +Reads a single line. + +This method fully supports the use of of the variable C<$/> (or +C<$INPUT_RECORD_SEPARATOR> or C<$RS> when C<English> is in use) to +determine what constitutes an end of line. Paragraph mode, record mode and +file slurp mode are all supported. + +=head2 getc + +Usage is + + $char = $z->getc() + +Read a single character. + +=head2 ungetc + +Usage is + + $char = $z->ungetc($string) + +=head2 inflateSync + +Usage is + + $status = $z->inflateSync() + +TODO + +=head2 getHeaderInfo + +Usage is + + $hdr = $z->getHeaderInfo(); + @hdrs = $z->getHeaderInfo(); + +This method returns either a hash reference (in scalar context) or a list +or hash references (in array context) that contains information about each +of the header fields in the compressed data stream(s). + +=head2 tell + +Usage is + + $z->tell() + tell $z + +Returns the uncompressed file offset. + +=head2 eof + +Usage is + + $z->eof(); + eof($z); + +Returns true if the end of the compressed input stream has been reached. + +=head2 seek + + $z->seek($position, $whence); + seek($z, $position, $whence); + +Provides a sub-set of the C<seek> functionality, with the restriction +that it is only legal to seek forward in the input file/buffer. +It is a fatal error to attempt to seek backward. + +The C<$whence> parameter takes one the usual values, namely SEEK_SET, +SEEK_CUR or SEEK_END. + +Returns 1 on success, 0 on failure. + +=head2 binmode + +Usage is + + $z->binmode + binmode $z ; + +This is a noop provided for completeness. + +=head2 opened + + $z->opened() + +Returns true if the object currently refers to a opened file/buffer. + +=head2 autoflush + + my $prev = $z->autoflush() + my $prev = $z->autoflush(EXPR) + +If the C<$z> object is associated with a file or a filehandle, this method +returns the current autoflush setting for the underlying filehandle. If +C<EXPR> is present, and is non-zero, it will enable flushing after every +write/print operation. + +If C<$z> is associated with a buffer, this method has no effect and always +returns C<undef>. + +B<Note> that the special variable C<$|> B<cannot> be used to set or +retrieve the autoflush setting. + +=head2 input_line_number + + $z->input_line_number() + $z->input_line_number(EXPR) + +Returns the current uncompressed line number. If C<EXPR> is present it has +the effect of setting the line number. Note that setting the line number +does not change the current position within the file/buffer being read. + +The contents of C<$/> are used to to determine what constitutes a line +terminator. + +=head2 fileno + + $z->fileno() + fileno($z) + +If the C<$z> object is associated with a file or a filehandle, C<fileno> +will return the underlying file descriptor. Once the C<close> method is +called C<fileno> will return C<undef>. + +If the C<$z> object is is associated with a buffer, this method will return +C<undef>. + +=head2 close + + $z->close() ; + close $z ; + +Closes the output file/buffer. + +For most versions of Perl this method will be automatically invoked if +the IO::Uncompress::RawInflate object is destroyed (either explicitly or by the +variable with the reference to the object going out of scope). The +exceptions are Perl versions 5.005 through 5.00504 and 5.8.0. In +these cases, the C<close> method will be called automatically, but +not until global destruction of all live objects when the program is +terminating. + +Therefore, if you want your scripts to be able to run on all versions +of Perl, you should call C<close> explicitly and not rely on automatic +closing. + +Returns true on success, otherwise 0. + +If the C<AutoClose> option has been enabled when the IO::Uncompress::RawInflate +object was created, and the object is associated with a file, the +underlying file will also be closed. + +=head2 nextStream + +Usage is + + my $status = $z->nextStream(); + +Skips to the next compressed data stream in the input file/buffer. If a new +compressed data stream is found, the eof marker will be cleared and C<$.> +will be reset to 0. + +Returns 1 if a new stream was found, 0 if none was found, and -1 if an +error was encountered. + +=head2 trailingData + +Usage is + + my $data = $z->trailingData(); + +Returns the data, if any, that is present immediately after the compressed +data stream once uncompression is complete. It only makes sense to call +this method once the end of the compressed data stream has been +encountered. + +This option can be used when there is useful information immediately +following the compressed data stream, and you don't know the length of the +compressed data stream. + +If the input is a buffer, C<trailingData> will return everything from the +end of the compressed data stream to the end of the buffer. + +If the input is a filehandle, C<trailingData> will return the data that is +left in the filehandle input buffer once the end of the compressed data +stream has been reached. You can then use the filehandle to read the rest +of the input file. + +Don't bother using C<trailingData> if the input is a filename. + +If you know the length of the compressed data stream before you start +uncompressing, you can avoid having to use C<trailingData> by setting the +C<InputLength> option in the constructor. + +=head1 Importing + +No symbolic constants are required by this IO::Uncompress::RawInflate at present. + +=over 5 + +=item :all + +Imports C<rawinflate> and C<$RawInflateError>. +Same as doing this + + use IO::Uncompress::RawInflate qw(rawinflate $RawInflateError) ; + +=back + +=head1 EXAMPLES + +=head2 Working with Net::FTP + +See L<IO::Uncompress::RawInflate::FAQ|IO::Uncompress::RawInflate::FAQ/"Compressed files and Net::FTP"> + +=head1 SEE ALSO + +L<Compress::Zlib>, L<IO::Compress::Gzip>, L<IO::Uncompress::Gunzip>, L<IO::Compress::Deflate>, L<IO::Uncompress::Inflate>, L<IO::Compress::RawDeflate>, L<IO::Compress::Bzip2>, L<IO::Uncompress::Bunzip2>, L<IO::Compress::Lzma>, L<IO::Uncompress::UnLzma>, L<IO::Compress::Xz>, L<IO::Uncompress::UnXz>, L<IO::Compress::Lzop>, L<IO::Uncompress::UnLzop>, L<IO::Compress::Lzf>, L<IO::Uncompress::UnLzf>, L<IO::Uncompress::AnyInflate>, L<IO::Uncompress::AnyUncompress> + +L<Compress::Zlib::FAQ|Compress::Zlib::FAQ> + +L<File::GlobMapper|File::GlobMapper>, L<Archive::Zip|Archive::Zip>, +L<Archive::Tar|Archive::Tar>, +L<IO::Zlib|IO::Zlib> + +For RFC 1950, 1951 and 1952 see +F<http://www.faqs.org/rfcs/rfc1950.html>, +F<http://www.faqs.org/rfcs/rfc1951.html> and +F<http://www.faqs.org/rfcs/rfc1952.html> + +The I<zlib> compression library was written by Jean-loup Gailly +F<gzip@prep.ai.mit.edu> and Mark Adler F<madler@alumni.caltech.edu>. + +The primary site for the I<zlib> compression library is +F<http://www.zlib.org>. + +The primary site for gzip is F<http://www.gzip.org>. + +=head1 AUTHOR + +This module was written by Paul Marquess, F<pmqs@cpan.org>. + +=head1 MODIFICATION HISTORY + +See the Changes file. + +=head1 COPYRIGHT AND LICENSE + +Copyright (c) 2005-2010 Paul Marquess. All rights reserved. + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + diff --git a/Master/tlpkg/tlperl/lib/IO/Uncompress/Unzip.pm b/Master/tlpkg/tlperl/lib/IO/Uncompress/Unzip.pm new file mode 100644 index 00000000000..e7d6849f66b --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Uncompress/Unzip.pm @@ -0,0 +1,1549 @@ +package IO::Uncompress::Unzip; + +require 5.004 ; + +# for RFC1952 + +use strict ; +use warnings; +use bytes; + +use IO::Uncompress::RawInflate 2.024 ; +use IO::Compress::Base::Common 2.024 qw(:Status createSelfTiedObject); +use IO::Uncompress::Adapter::Inflate 2.024 ; +use IO::Uncompress::Adapter::Identity 2.024 ; +use IO::Compress::Zlib::Extra 2.024 ; +use IO::Compress::Zip::Constants 2.024 ; + +use Compress::Raw::Zlib 2.024 qw(crc32) ; + +BEGIN +{ + eval { require IO::Uncompress::Adapter::Bunzip2 ; + import IO::Uncompress::Adapter::Bunzip2 } ; +# eval { require IO::Uncompress::Adapter::UnLzma ; +# import IO::Uncompress::Adapter::UnLzma } ; +} + + +require Exporter ; + +our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, $UnzipError, %headerLookup); + +$VERSION = '2.024'; +$UnzipError = ''; + +@ISA = qw(Exporter IO::Uncompress::RawInflate); +@EXPORT_OK = qw( $UnzipError unzip ); +%EXPORT_TAGS = %IO::Uncompress::RawInflate::EXPORT_TAGS ; +push @{ $EXPORT_TAGS{all} }, @EXPORT_OK ; +Exporter::export_ok_tags('all'); + +%headerLookup = ( + ZIP_CENTRAL_HDR_SIG, \&skipCentralDirectory, + ZIP_END_CENTRAL_HDR_SIG, \&skipEndCentralDirectory, + ZIP64_END_CENTRAL_REC_HDR_SIG, \&skipCentralDirectory64Rec, + ZIP64_END_CENTRAL_LOC_HDR_SIG, \&skipCentralDirectory64Loc, + ZIP64_ARCHIVE_EXTRA_SIG, \&skipArchiveExtra, + ZIP64_DIGITAL_SIGNATURE_SIG, \&skipDigitalSignature, + ); + +sub new +{ + my $class = shift ; + my $obj = createSelfTiedObject($class, \$UnzipError); + $obj->_create(undef, 0, @_); +} + +sub unzip +{ + my $obj = createSelfTiedObject(undef, \$UnzipError); + return $obj->_inf(@_) ; +} + +sub getExtraParams +{ + use IO::Compress::Base::Common 2.024 qw(:Parse); + + + return ( +# # Zip header fields + 'Name' => [1, 1, Parse_any, undef], + +# 'Stream' => [1, 1, Parse_boolean, 1], + # This means reading the central directory to get + # 1. the local header offsets + # 2. The compressed data length + ); +} + +sub ckParams +{ + my $self = shift ; + my $got = shift ; + + # unzip always needs crc32 + $got->value('CRC32' => 1); + + *$self->{UnzipData}{Name} = $got->value('Name'); + + return 1; +} + +sub mkUncomp +{ + my $self = shift ; + my $got = shift ; + + my $magic = $self->ckMagic() + or return 0; + + *$self->{Info} = $self->readHeader($magic) + or return undef ; + + return 1; + +} + +sub ckMagic +{ + my $self = shift; + + my $magic ; + $self->smartReadExact(\$magic, 4); + + *$self->{HeaderPending} = $magic ; + + return $self->HeaderError("Minimum header size is " . + 4 . " bytes") + if length $magic != 4 ; + + return $self->HeaderError("Bad Magic") + if ! _isZipMagic($magic) ; + + *$self->{Type} = 'zip'; + + return $magic ; +} + + +sub fastForward +{ + my $self = shift; + my $offset = shift; + + # TODO - if Stream isn't enabled & reading from file, use seek + + my $buffer = ''; + my $c = 1024 * 16; + + while ($offset > 0) + { + $c = length $offset + if length $offset < $c ; + + $offset -= $c; + + $self->smartReadExact(\$buffer, $c) + or return 0; + } + + return 1; +} + + +sub readHeader +{ + my $self = shift; + my $magic = shift ; + + my $name = *$self->{UnzipData}{Name} ; + my $hdr = $self->_readZipHeader($magic) ; + + while (defined $hdr) + { + if (! defined $name || $hdr->{Name} eq $name) + { + return $hdr ; + } + + # skip the data + # TODO - when Stream is off, use seek + my $buffer; + if (*$self->{ZipData}{Streaming}) { + + while (1) { + + my $b; + my $status = $self->smartRead(\$b, 1024 * 16); + return undef + if $status <= 0 ; + + my $temp_buf; + my $out; + $status = *$self->{Uncomp}->uncompr(\$b, \$temp_buf, 0, $out); + + return $self->saveErrorString(undef, *$self->{Uncomp}{Error}, + *$self->{Uncomp}{ErrorNo}) + if $self->saveStatus($status) == STATUS_ERROR; + + if ($status == STATUS_ENDSTREAM) { + *$self->{Uncomp}->reset(); + $self->pushBack($b) ; + last; + } + } + + # skip the trailer + $self->smartReadExact(\$buffer, $hdr->{TrailerLength}) + or return $self->saveErrorString(undef, "Truncated file"); + } + else { + my $c = $hdr->{CompressedLength}->get64bit(); + $self->fastForward($c) + or return $self->saveErrorString(undef, "Truncated file"); + $buffer = ''; + } + + $self->chkTrailer($buffer) == STATUS_OK + or return $self->saveErrorString(undef, "Truncated file"); + + $hdr = $self->_readFullZipHeader(); + + return $self->saveErrorString(undef, "Cannot find '$name'") + if $self->smartEof(); + } + + return undef; +} + +sub chkTrailer +{ + my $self = shift; + my $trailer = shift; + + my ($sig, $CRC32, $cSize, $uSize) ; + my ($cSizeHi, $uSizeHi) = (0, 0); + if (*$self->{ZipData}{Streaming}) { + $sig = unpack ("V", substr($trailer, 0, 4)); + $CRC32 = unpack ("V", substr($trailer, 4, 4)); + + if (*$self->{ZipData}{Zip64} ) { + $cSize = U64::newUnpack_V64 substr($trailer, 8, 8); + $uSize = U64::newUnpack_V64 substr($trailer, 16, 8); + } + else { + $cSize = U64::newUnpack_V32 substr($trailer, 8, 4); + $uSize = U64::newUnpack_V32 substr($trailer, 12, 4); + } + + return $self->TrailerError("Data Descriptor signature, got $sig") + if $sig != ZIP_DATA_HDR_SIG; + } + else { + ($CRC32, $cSize, $uSize) = + (*$self->{ZipData}{Crc32}, + *$self->{ZipData}{CompressedLen}, + *$self->{ZipData}{UnCompressedLen}); + } + + *$self->{Info}{CRC32} = *$self->{ZipData}{CRC32} ; + *$self->{Info}{CompressedLength} = $cSize->get64bit(); + *$self->{Info}{UncompressedLength} = $uSize->get64bit(); + + if (*$self->{Strict}) { + return $self->TrailerError("CRC mismatch") + if $CRC32 != *$self->{ZipData}{CRC32} ; + + return $self->TrailerError("CSIZE mismatch.") + if ! $cSize->equal(*$self->{CompSize}); + + return $self->TrailerError("USIZE mismatch.") + if ! $uSize->equal(*$self->{UnCompSize}); + } + + my $reachedEnd = STATUS_ERROR ; + # check for central directory or end of central directory + while (1) + { + my $magic ; + my $got = $self->smartRead(\$magic, 4); + + return $self->saveErrorString(STATUS_ERROR, "Truncated file") + if $got != 4 && *$self->{Strict}; + + if ($got == 0) { + return STATUS_EOF ; + } + elsif ($got < 0) { + return STATUS_ERROR ; + } + elsif ($got < 4) { + $self->pushBack($magic) ; + return STATUS_OK ; + } + + my $sig = unpack("V", $magic) ; + + my $hdr; + if ($hdr = $headerLookup{$sig}) + { + if (&$hdr($self, $magic) != STATUS_OK ) { + if (*$self->{Strict}) { + return STATUS_ERROR ; + } + else { + $self->clearError(); + return STATUS_OK ; + } + } + + if ($sig == ZIP_END_CENTRAL_HDR_SIG) + { + return STATUS_OK ; + last; + } + } + elsif ($sig == ZIP_LOCAL_HDR_SIG) + { + $self->pushBack($magic) ; + return STATUS_OK ; + } + else + { + # put the data back + $self->pushBack($magic) ; + last; + } + } + + return $reachedEnd ; +} + +sub skipCentralDirectory +{ + my $self = shift; + my $magic = shift ; + + my $buffer; + $self->smartReadExact(\$buffer, 46 - 4) + or return $self->TrailerError("Minimum header size is " . + 46 . " bytes") ; + + my $keep = $magic . $buffer ; + *$self->{HeaderPending} = $keep ; + + #my $versionMadeBy = unpack ("v", substr($buffer, 4-4, 2)); + #my $extractVersion = unpack ("v", substr($buffer, 6-4, 2)); + #my $gpFlag = unpack ("v", substr($buffer, 8-4, 2)); + #my $compressedMethod = unpack ("v", substr($buffer, 10-4, 2)); + #my $lastModTime = unpack ("V", substr($buffer, 12-4, 4)); + #my $crc32 = unpack ("V", substr($buffer, 16-4, 4)); + my $compressedLength = unpack ("V", substr($buffer, 20-4, 4)); + my $uncompressedLength = unpack ("V", substr($buffer, 24-4, 4)); + my $filename_length = unpack ("v", substr($buffer, 28-4, 2)); + my $extra_length = unpack ("v", substr($buffer, 30-4, 2)); + my $comment_length = unpack ("v", substr($buffer, 32-4, 2)); + #my $disk_start = unpack ("v", substr($buffer, 34-4, 2)); + #my $int_file_attrib = unpack ("v", substr($buffer, 36-4, 2)); + #my $ext_file_attrib = unpack ("V", substr($buffer, 38-4, 2)); + #my $lcl_hdr_offset = unpack ("V", substr($buffer, 42-4, 2)); + + + my $filename; + my $extraField; + my $comment ; + if ($filename_length) + { + $self->smartReadExact(\$filename, $filename_length) + or return $self->TruncatedTrailer("filename"); + $keep .= $filename ; + } + + if ($extra_length) + { + $self->smartReadExact(\$extraField, $extra_length) + or return $self->TruncatedTrailer("extra"); + $keep .= $extraField ; + } + + if ($comment_length) + { + $self->smartReadExact(\$comment, $comment_length) + or return $self->TruncatedTrailer("comment"); + $keep .= $comment ; + } + + return STATUS_OK ; +} + +sub skipArchiveExtra +{ + my $self = shift; + my $magic = shift ; + + my $buffer; + $self->smartReadExact(\$buffer, 4) + or return $self->TrailerError("Minimum header size is " . + 4 . " bytes") ; + + my $keep = $magic . $buffer ; + + my $size = unpack ("V", $buffer); + + $self->smartReadExact(\$buffer, $size) + or return $self->TrailerError("Minimum header size is " . + $size . " bytes") ; + + $keep .= $buffer ; + *$self->{HeaderPending} = $keep ; + + return STATUS_OK ; +} + + +sub skipCentralDirectory64Rec +{ + my $self = shift; + my $magic = shift ; + + my $buffer; + $self->smartReadExact(\$buffer, 8) + or return $self->TrailerError("Minimum header size is " . + 8 . " bytes") ; + + my $keep = $magic . $buffer ; + + my ($sizeLo, $sizeHi) = unpack ("V V", $buffer); + my $size = $sizeHi * 0xFFFFFFFF + $sizeLo; + + $self->fastForward($size) + or return $self->TrailerError("Minimum header size is " . + $size . " bytes") ; + + #$keep .= $buffer ; + #*$self->{HeaderPending} = $keep ; + + #my $versionMadeBy = unpack ("v", substr($buffer, 0, 2)); + #my $extractVersion = unpack ("v", substr($buffer, 2, 2)); + #my $diskNumber = unpack ("V", substr($buffer, 4, 4)); + #my $cntrlDirDiskNo = unpack ("V", substr($buffer, 8, 4)); + #my $entriesInThisCD = unpack ("V V", substr($buffer, 12, 8)); + #my $entriesInCD = unpack ("V V", substr($buffer, 20, 8)); + #my $sizeOfCD = unpack ("V V", substr($buffer, 28, 8)); + #my $offsetToCD = unpack ("V V", substr($buffer, 36, 8)); + + return STATUS_OK ; +} + +sub skipCentralDirectory64Loc +{ + my $self = shift; + my $magic = shift ; + + my $buffer; + $self->smartReadExact(\$buffer, 20 - 4) + or return $self->TrailerError("Minimum header size is " . + 20 . " bytes") ; + + my $keep = $magic . $buffer ; + *$self->{HeaderPending} = $keep ; + + #my $startCdDisk = unpack ("V", substr($buffer, 4-4, 4)); + #my $offsetToCD = unpack ("V V", substr($buffer, 8-4, 8)); + #my $diskCount = unpack ("V", substr($buffer, 16-4, 4)); + + return STATUS_OK ; +} + +sub skipEndCentralDirectory +{ + my $self = shift; + my $magic = shift ; + + my $buffer; + $self->smartReadExact(\$buffer, 22 - 4) + or return $self->TrailerError("Minimum header size is " . + 22 . " bytes") ; + + my $keep = $magic . $buffer ; + *$self->{HeaderPending} = $keep ; + + #my $diskNumber = unpack ("v", substr($buffer, 4-4, 2)); + #my $cntrlDirDiskNo = unpack ("v", substr($buffer, 6-4, 2)); + #my $entriesInThisCD = unpack ("v", substr($buffer, 8-4, 2)); + #my $entriesInCD = unpack ("v", substr($buffer, 10-4, 2)); + #my $sizeOfCD = unpack ("V", substr($buffer, 12-4, 2)); + #my $offsetToCD = unpack ("V", substr($buffer, 16-4, 2)); + my $comment_length = unpack ("v", substr($buffer, 20-4, 2)); + + + my $comment ; + if ($comment_length) + { + $self->smartReadExact(\$comment, $comment_length) + or return $self->TruncatedTrailer("comment"); + $keep .= $comment ; + } + + return STATUS_OK ; +} + + +sub _isZipMagic +{ + my $buffer = shift ; + return 0 if length $buffer < 4 ; + my $sig = unpack("V", $buffer) ; + return $sig == ZIP_LOCAL_HDR_SIG ; +} + + +sub _readFullZipHeader($) +{ + my ($self) = @_ ; + my $magic = '' ; + + $self->smartReadExact(\$magic, 4); + + *$self->{HeaderPending} = $magic ; + + return $self->HeaderError("Minimum header size is " . + 30 . " bytes") + if length $magic != 4 ; + + + return $self->HeaderError("Bad Magic") + if ! _isZipMagic($magic) ; + + my $status = $self->_readZipHeader($magic); + delete *$self->{Transparent} if ! defined $status ; + return $status ; +} + +sub _readZipHeader($) +{ + my ($self, $magic) = @_ ; + my ($HeaderCRC) ; + my ($buffer) = '' ; + + $self->smartReadExact(\$buffer, 30 - 4) + or return $self->HeaderError("Minimum header size is " . + 30 . " bytes") ; + + my $keep = $magic . $buffer ; + *$self->{HeaderPending} = $keep ; + + my $extractVersion = unpack ("v", substr($buffer, 4-4, 2)); + my $gpFlag = unpack ("v", substr($buffer, 6-4, 2)); + my $compressedMethod = unpack ("v", substr($buffer, 8-4, 2)); + my $lastModTime = unpack ("V", substr($buffer, 10-4, 4)); + my $crc32 = unpack ("V", substr($buffer, 14-4, 4)); + my $compressedLength = U64::newUnpack_V32 substr($buffer, 18-4, 4); + my $uncompressedLength = U64::newUnpack_V32 substr($buffer, 22-4, 4); + my $filename_length = unpack ("v", substr($buffer, 26-4, 2)); + my $extra_length = unpack ("v", substr($buffer, 28-4, 2)); + + my $filename; + my $extraField; + my @EXTRA = (); + my $streamingMode = ($gpFlag & ZIP_GP_FLAG_STREAMING_MASK) ? 1 : 0 ; + + return $self->HeaderError("Streamed Stored content not supported") + if $streamingMode && $compressedMethod == 0 ; + + return $self->HeaderError("Encrypted content not supported") + if $gpFlag & (ZIP_GP_FLAG_ENCRYPTED_MASK|ZIP_GP_FLAG_STRONG_ENCRYPTED_MASK); + + return $self->HeaderError("Patch content not supported") + if $gpFlag & ZIP_GP_FLAG_PATCHED_MASK; + + *$self->{ZipData}{Streaming} = $streamingMode; + + + if ($filename_length) + { + $self->smartReadExact(\$filename, $filename_length) + or return $self->TruncatedHeader("Filename"); + $keep .= $filename ; + } + + my $zip64 = 0 ; + + if ($extra_length) + { + $self->smartReadExact(\$extraField, $extra_length) + or return $self->TruncatedHeader("Extra Field"); + + my $bad = IO::Compress::Zlib::Extra::parseRawExtra($extraField, + \@EXTRA, 1, 0); + return $self->HeaderError($bad) + if defined $bad; + + $keep .= $extraField ; + + my %Extra ; + for (@EXTRA) + { + $Extra{$_->[0]} = \$_->[1]; + } + + if (defined $Extra{ZIP_EXTRA_ID_ZIP64()}) + { + $zip64 = 1 ; + + my $buff = ${ $Extra{ZIP_EXTRA_ID_ZIP64()} }; + + # This code assumes that all the fields in the Zip64 + # extra field aren't necessarily present. The spec says that + # they only exist if the equivalent local headers are -1. + + if (! $streamingMode) { + my $offset = 0 ; + + if ($uncompressedLength->get32bit() == 0xFFFFFFFF ) { + $uncompressedLength + = U64::newUnpack_V64 substr($buff, 0, 8); + + $offset += 8 ; + } + + if ($compressedLength->get32bit() == 0xFFFFFFFF) { + + $compressedLength + = U64::newUnpack_V64 substr($buff, $offset, 8); + + $offset += 8 ; + } + } + } + } + + *$self->{ZipData}{Zip64} = $zip64; + + if (! $streamingMode) { + *$self->{ZipData}{Streaming} = 0; + *$self->{ZipData}{Crc32} = $crc32; + *$self->{ZipData}{CompressedLen} = $compressedLength; + *$self->{ZipData}{UnCompressedLen} = $uncompressedLength; + *$self->{CompressedInputLengthRemaining} = + *$self->{CompressedInputLength} = $compressedLength->get64bit(); + } + + *$self->{ZipData}{CRC32} = crc32(undef); + *$self->{ZipData}{Method} = $compressedMethod; + if ($compressedMethod == ZIP_CM_DEFLATE) + { + *$self->{Type} = 'zip-deflate'; + my $obj = IO::Uncompress::Adapter::Inflate::mkUncompObject(1,0,0); + + *$self->{Uncomp} = $obj; + } + elsif ($compressedMethod == ZIP_CM_BZIP2) + { + return $self->HeaderError("Unsupported Compression format $compressedMethod") + if ! defined $IO::Uncompress::Adapter::Bunzip2::VERSION ; + + *$self->{Type} = 'zip-bzip2'; + + my $obj = IO::Uncompress::Adapter::Bunzip2::mkUncompObject(); + + *$self->{Uncomp} = $obj; + } +# elsif ($compressedMethod == ZIP_CM_LZMA) +# { +# return $self->HeaderError("Unsupported Compression format $compressedMethod") +# if ! defined $IO::Uncompress::Adapter::UnLzma::VERSION ; +# +# *$self->{Type} = 'zip-lzma'; +# my $LzmaHeader; +# $self->smartReadExact(\$LzmaHeader, 4) +# or return $self->saveErrorString(undef, "Truncated file"); +# my ($verHi, $verLo) = unpack ("CC", substr($LzmaHeader, 0, 2)); +# my $LzmaPropertiesSize = unpack ("v", substr($LzmaHeader, 2, 2)); +# +# +# my $LzmaPropertyData; +# $self->smartReadExact(\$LzmaPropertyData, $LzmaPropertiesSize) +# or return $self->saveErrorString(undef, "Truncated file"); +# #my $LzmaInfo = unpack ("C", substr($LzmaPropertyData, 0, 1)); +# #my $LzmaDictSize = unpack ("V", substr($LzmaPropertyData, 1, 4)); +# +# # Create an LZMA_Alone header +# $self->pushBack($LzmaPropertyData . +# $uncompressedLength->getPacked_V64()); +# +# my $obj = +# IO::Uncompress::Adapter::UnLzma::mkUncompObject(); +# +# *$self->{Uncomp} = $obj; +# } + elsif ($compressedMethod == ZIP_CM_STORE) + { + # TODO -- add support for reading uncompressed + + *$self->{Type} = 'zip-stored'; + + my $obj = IO::Uncompress::Adapter::Identity::mkUncompObject(); + + *$self->{Uncomp} = $obj; + } + else + { + return $self->HeaderError("Unsupported Compression format $compressedMethod"); + } + + return { + 'Type' => 'zip', + 'FingerprintLength' => 4, + #'HeaderLength' => $compressedMethod == 8 ? length $keep : 0, + 'HeaderLength' => length $keep, + 'Zip64' => $zip64, + 'TrailerLength' => ! $streamingMode ? 0 : $zip64 ? 24 : 16, + 'Header' => $keep, + 'CompressedLength' => $compressedLength , + 'UncompressedLength' => $uncompressedLength , + 'CRC32' => $crc32 , + 'Name' => $filename, + 'Time' => _dosToUnixTime($lastModTime), + 'Stream' => $streamingMode, + + 'MethodID' => $compressedMethod, + 'MethodName' => $compressedMethod == ZIP_CM_DEFLATE + ? "Deflated" + : $compressedMethod == ZIP_CM_BZIP2 + ? "Bzip2" + : $compressedMethod == ZIP_CM_LZMA + ? "Lzma" + : $compressedMethod == ZIP_CM_STORE + ? "Stored" + : "Unknown" , + +# 'TextFlag' => $flag & GZIP_FLG_FTEXT ? 1 : 0, +# 'HeaderCRCFlag' => $flag & GZIP_FLG_FHCRC ? 1 : 0, +# 'NameFlag' => $flag & GZIP_FLG_FNAME ? 1 : 0, +# 'CommentFlag' => $flag & GZIP_FLG_FCOMMENT ? 1 : 0, +# 'ExtraFlag' => $flag & GZIP_FLG_FEXTRA ? 1 : 0, +# 'Comment' => $comment, +# 'OsID' => $os, +# 'OsName' => defined $GZIP_OS_Names{$os} +# ? $GZIP_OS_Names{$os} : "Unknown", +# 'HeaderCRC' => $HeaderCRC, +# 'Flags' => $flag, +# 'ExtraFlags' => $xfl, + 'ExtraFieldRaw' => $extraField, + 'ExtraField' => [ @EXTRA ], + + + } +} + +sub filterUncompressed +{ + my $self = shift ; + + if (*$self->{ZipData}{Method} == ZIP_CM_DEFLATE) { + *$self->{ZipData}{CRC32} = *$self->{Uncomp}->crc32() ; + } + else { + *$self->{ZipData}{CRC32} = crc32(${$_[0]}, *$self->{ZipData}{CRC32}); + } +} + + +# from Archive::Zip & info-zip +sub _dosToUnixTime +{ + my $dt = shift; + + my $year = ( ( $dt >> 25 ) & 0x7f ) + 80; + my $mon = ( ( $dt >> 21 ) & 0x0f ) - 1; + my $mday = ( ( $dt >> 16 ) & 0x1f ); + + my $hour = ( ( $dt >> 11 ) & 0x1f ); + my $min = ( ( $dt >> 5 ) & 0x3f ); + my $sec = ( ( $dt << 1 ) & 0x3e ); + + + use POSIX 'mktime'; + + my $time_t = mktime( $sec, $min, $hour, $mday, $mon, $year, 0, 0, -1 ); + return 0 if ! defined $time_t; + return $time_t; +} + + +1; + +__END__ + + +=head1 NAME + +IO::Uncompress::Unzip - Read zip files/buffers + +=head1 SYNOPSIS + + use IO::Uncompress::Unzip qw(unzip $UnzipError) ; + + my $status = unzip $input => $output [,OPTS] + or die "unzip failed: $UnzipError\n"; + + my $z = new IO::Uncompress::Unzip $input [OPTS] + or die "unzip failed: $UnzipError\n"; + + $status = $z->read($buffer) + $status = $z->read($buffer, $length) + $status = $z->read($buffer, $length, $offset) + $line = $z->getline() + $char = $z->getc() + $char = $z->ungetc() + $char = $z->opened() + + $status = $z->inflateSync() + + $data = $z->trailingData() + $status = $z->nextStream() + $data = $z->getHeaderInfo() + $z->tell() + $z->seek($position, $whence) + $z->binmode() + $z->fileno() + $z->eof() + $z->close() + + $UnzipError ; + + # IO::File mode + + <$z> + read($z, $buffer); + read($z, $buffer, $length); + read($z, $buffer, $length, $offset); + tell($z) + seek($z, $position, $whence) + binmode($z) + fileno($z) + eof($z) + close($z) + +=head1 DESCRIPTION + +This module provides a Perl interface that allows the reading of +zlib files/buffers. + +For writing zip files/buffers, see the companion module IO::Compress::Zip. + +=head1 Functional Interface + +A top-level function, C<unzip>, is provided to carry out +"one-shot" uncompression between buffers and/or files. For finer +control over the uncompression process, see the L</"OO Interface"> +section. + + use IO::Uncompress::Unzip qw(unzip $UnzipError) ; + + unzip $input => $output [,OPTS] + or die "unzip failed: $UnzipError\n"; + +The functional interface needs Perl5.005 or better. + +=head2 unzip $input => $output [, OPTS] + +C<unzip> expects at least two parameters, C<$input> and C<$output>. + +=head3 The C<$input> parameter + +The parameter, C<$input>, is used to define the source of +the compressed data. + +It can take one of the following forms: + +=over 5 + +=item A filename + +If the C<$input> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for reading and the input data +will be read from it. + +=item A filehandle + +If the C<$input> parameter is a filehandle, the input data will be +read from it. +The string '-' can be used as an alias for standard input. + +=item A scalar reference + +If C<$input> is a scalar reference, the input data will be read +from C<$$input>. + +=item An array reference + +If C<$input> is an array reference, each element in the array must be a +filename. + +The input data will be read from each file in turn. + +The complete array will be walked to ensure that it only +contains valid filenames before any data is uncompressed. + +=item An Input FileGlob string + +If C<$input> is a string that is delimited by the characters "<" and ">" +C<unzip> will assume that it is an I<input fileglob string>. The +input is the list of files that match the fileglob. + +If the fileglob does not match any files ... + +See L<File::GlobMapper|File::GlobMapper> for more details. + +=back + +If the C<$input> parameter is any other type, C<undef> will be returned. + +=head3 The C<$output> parameter + +The parameter C<$output> is used to control the destination of the +uncompressed data. This parameter can take one of these forms. + +=over 5 + +=item A filename + +If the C<$output> parameter is a simple scalar, it is assumed to be a +filename. This file will be opened for writing and the uncompressed +data will be written to it. + +=item A filehandle + +If the C<$output> parameter is a filehandle, the uncompressed data +will be written to it. +The string '-' can be used as an alias for standard output. + +=item A scalar reference + +If C<$output> is a scalar reference, the uncompressed data will be +stored in C<$$output>. + +=item An Array Reference + +If C<$output> is an array reference, the uncompressed data will be +pushed onto the array. + +=item An Output FileGlob + +If C<$output> is a string that is delimited by the characters "<" and ">" +C<unzip> will assume that it is an I<output fileglob string>. The +output is the list of files that match the fileglob. + +When C<$output> is an fileglob string, C<$input> must also be a fileglob +string. Anything else is an error. + +=back + +If the C<$output> parameter is any other type, C<undef> will be returned. + +=head2 Notes + +When C<$input> maps to multiple compressed files/buffers and C<$output> is +a single file/buffer, after uncompression C<$output> will contain a +concatenation of all the uncompressed data from each of the input +files/buffers. + +=head2 Optional Parameters + +Unless specified below, the optional parameters for C<unzip>, +C<OPTS>, are the same as those used with the OO interface defined in the +L</"Constructor Options"> section below. + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option applies to any input or output data streams to +C<unzip> that are filehandles. + +If C<AutoClose> is specified, and the value is true, it will result in all +input and/or output filehandles being closed once C<unzip> has +completed. + +This parameter defaults to 0. + +=item C<< BinModeOut => 0|1 >> + +When writing to a file or filehandle, set C<binmode> before writing to the +file. + +Defaults to 0. + +=item C<< Append => 0|1 >> + +The behaviour of this option is dependent on the type of output data +stream. + +=over 5 + +=item * A Buffer + +If C<Append> is enabled, all uncompressed data will be append to the end of +the output buffer. Otherwise the output buffer will be cleared before any +uncompressed data is written to it. + +=item * A Filename + +If C<Append> is enabled, the file will be opened in append mode. Otherwise +the contents of the file, if any, will be truncated before any uncompressed +data is written to it. + +=item * A Filehandle + +If C<Append> is enabled, the filehandle will be positioned to the end of +the file via a call to C<seek> before any uncompressed data is +written to it. Otherwise the file pointer will not be moved. + +=back + +When C<Append> is specified, and set to true, it will I<append> all uncompressed +data to the output data stream. + +So when the output is a filehandle it will carry out a seek to the eof +before writing any uncompressed data. If the output is a filename, it will be opened for +appending. If the output is a buffer, all uncompressed data will be appened to +the existing buffer. + +Conversely when C<Append> is not specified, or it is present and is set to +false, it will operate as follows. + +When the output is a filename, it will truncate the contents of the file +before writing any uncompressed data. If the output is a filehandle +its position will not be changed. If the output is a buffer, it will be +wiped before any uncompressed data is output. + +Defaults to 0. + +=item C<< MultiStream => 0|1 >> + +If the input file/buffer contains multiple compressed data streams, this +option will uncompress the whole lot as a single data stream. + +Defaults to 0. + +=item C<< TrailingData => $scalar >> + +Returns the data, if any, that is present immediately after the compressed +data stream once uncompression is complete. + +This option can be used when there is useful information immediately +following the compressed data stream, and you don't know the length of the +compressed data stream. + +If the input is a buffer, C<trailingData> will return everything from the +end of the compressed data stream to the end of the buffer. + +If the input is a filehandle, C<trailingData> will return the data that is +left in the filehandle input buffer once the end of the compressed data +stream has been reached. You can then use the filehandle to read the rest +of the input file. + +Don't bother using C<trailingData> if the input is a filename. + +If you know the length of the compressed data stream before you start +uncompressing, you can avoid having to use C<trailingData> by setting the +C<InputLength> option. + +=back + +=head2 Examples + +To read the contents of the file C<file1.txt.zip> and write the +uncompressed data to the file C<file1.txt>. + + use strict ; + use warnings ; + use IO::Uncompress::Unzip qw(unzip $UnzipError) ; + + my $input = "file1.txt.zip"; + my $output = "file1.txt"; + unzip $input => $output + or die "unzip failed: $UnzipError\n"; + +To read from an existing Perl filehandle, C<$input>, and write the +uncompressed data to a buffer, C<$buffer>. + + use strict ; + use warnings ; + use IO::Uncompress::Unzip qw(unzip $UnzipError) ; + use IO::File ; + + my $input = new IO::File "<file1.txt.zip" + or die "Cannot open 'file1.txt.zip': $!\n" ; + my $buffer ; + unzip $input => \$buffer + or die "unzip failed: $UnzipError\n"; + +To uncompress all files in the directory "/my/home" that match "*.txt.zip" and store the compressed data in the same directory + + use strict ; + use warnings ; + use IO::Uncompress::Unzip qw(unzip $UnzipError) ; + + unzip '</my/home/*.txt.zip>' => '</my/home/#1.txt>' + or die "unzip failed: $UnzipError\n"; + +and if you want to compress each file one at a time, this will do the trick + + use strict ; + use warnings ; + use IO::Uncompress::Unzip qw(unzip $UnzipError) ; + + for my $input ( glob "/my/home/*.txt.zip" ) + { + my $output = $input; + $output =~ s/.zip// ; + unzip $input => $output + or die "Error compressing '$input': $UnzipError\n"; + } + +=head1 OO Interface + +=head2 Constructor + +The format of the constructor for IO::Uncompress::Unzip is shown below + + my $z = new IO::Uncompress::Unzip $input [OPTS] + or die "IO::Uncompress::Unzip failed: $UnzipError\n"; + +Returns an C<IO::Uncompress::Unzip> object on success and undef on failure. +The variable C<$UnzipError> will contain an error message on failure. + +If you are running Perl 5.005 or better the object, C<$z>, returned from +IO::Uncompress::Unzip can be used exactly like an L<IO::File|IO::File> filehandle. +This means that all normal input file operations can be carried out with +C<$z>. For example, to read a line from a compressed file/buffer you can +use either of these forms + + $line = $z->getline(); + $line = <$z>; + +The mandatory parameter C<$input> is used to determine the source of the +compressed data. This parameter can take one of three forms. + +=over 5 + +=item A filename + +If the C<$input> parameter is a scalar, it is assumed to be a filename. This +file will be opened for reading and the compressed data will be read from it. + +=item A filehandle + +If the C<$input> parameter is a filehandle, the compressed data will be +read from it. +The string '-' can be used as an alias for standard input. + +=item A scalar reference + +If C<$input> is a scalar reference, the compressed data will be read from +C<$$output>. + +=back + +=head2 Constructor Options + +The option names defined below are case insensitive and can be optionally +prefixed by a '-'. So all of the following are valid + + -AutoClose + -autoclose + AUTOCLOSE + autoclose + +OPTS is a combination of the following options: + +=over 5 + +=item C<< AutoClose => 0|1 >> + +This option is only valid when the C<$input> parameter is a filehandle. If +specified, and the value is true, it will result in the file being closed once +either the C<close> method is called or the IO::Uncompress::Unzip object is +destroyed. + +This parameter defaults to 0. + +=item C<< MultiStream => 0|1 >> + +Treats the complete zip file/buffer as a single compressed data +stream. When reading in multi-stream mode each member of the zip +file/buffer will be uncompressed in turn until the end of the file/buffer +is encountered. + +This parameter defaults to 0. + +=item C<< Prime => $string >> + +This option will uncompress the contents of C<$string> before processing the +input file/buffer. + +This option can be useful when the compressed data is embedded in another +file/data structure and it is not possible to work out where the compressed +data begins without having to read the first few bytes. If this is the +case, the uncompression can be I<primed> with these bytes using this +option. + +=item C<< Transparent => 0|1 >> + +If this option is set and the input file/buffer is not compressed data, +the module will allow reading of it anyway. + +In addition, if the input file/buffer does contain compressed data and +there is non-compressed data immediately following it, setting this option +will make this module treat the whole file/bufffer as a single data stream. + +This option defaults to 1. + +=item C<< BlockSize => $num >> + +When reading the compressed input data, IO::Uncompress::Unzip will read it in +blocks of C<$num> bytes. + +This option defaults to 4096. + +=item C<< InputLength => $size >> + +When present this option will limit the number of compressed bytes read +from the input file/buffer to C<$size>. This option can be used in the +situation where there is useful data directly after the compressed data +stream and you know beforehand the exact length of the compressed data +stream. + +This option is mostly used when reading from a filehandle, in which case +the file pointer will be left pointing to the first byte directly after the +compressed data stream. + +This option defaults to off. + +=item C<< Append => 0|1 >> + +This option controls what the C<read> method does with uncompressed data. + +If set to 1, all uncompressed data will be appended to the output parameter +of the C<read> method. + +If set to 0, the contents of the output parameter of the C<read> method +will be overwritten by the uncompressed data. + +Defaults to 0. + +=item C<< Strict => 0|1 >> + +This option controls whether the extra checks defined below are used when +carrying out the decompression. When Strict is on, the extra tests are +carried out, when Strict is off they are not. + +The default for this option is off. + +=back + +=head2 Examples + +TODO + +=head1 Methods + +=head2 read + +Usage is + + $status = $z->read($buffer) + +Reads a block of compressed data (the size the the compressed block is +determined by the C<Buffer> option in the constructor), uncompresses it and +writes any uncompressed data into C<$buffer>. If the C<Append> parameter is +set in the constructor, the uncompressed data will be appended to the +C<$buffer> parameter. Otherwise C<$buffer> will be overwritten. + +Returns the number of uncompressed bytes written to C<$buffer>, zero if eof +or a negative number on error. + +=head2 read + +Usage is + + $status = $z->read($buffer, $length) + $status = $z->read($buffer, $length, $offset) + + $status = read($z, $buffer, $length) + $status = read($z, $buffer, $length, $offset) + +Attempt to read C<$length> bytes of uncompressed data into C<$buffer>. + +The main difference between this form of the C<read> method and the +previous one, is that this one will attempt to return I<exactly> C<$length> +bytes. The only circumstances that this function will not is if end-of-file +or an IO error is encountered. + +Returns the number of uncompressed bytes written to C<$buffer>, zero if eof +or a negative number on error. + +=head2 getline + +Usage is + + $line = $z->getline() + $line = <$z> + +Reads a single line. + +This method fully supports the use of of the variable C<$/> (or +C<$INPUT_RECORD_SEPARATOR> or C<$RS> when C<English> is in use) to +determine what constitutes an end of line. Paragraph mode, record mode and +file slurp mode are all supported. + +=head2 getc + +Usage is + + $char = $z->getc() + +Read a single character. + +=head2 ungetc + +Usage is + + $char = $z->ungetc($string) + +=head2 inflateSync + +Usage is + + $status = $z->inflateSync() + +TODO + +=head2 getHeaderInfo + +Usage is + + $hdr = $z->getHeaderInfo(); + @hdrs = $z->getHeaderInfo(); + +This method returns either a hash reference (in scalar context) or a list +or hash references (in array context) that contains information about each +of the header fields in the compressed data stream(s). + +=head2 tell + +Usage is + + $z->tell() + tell $z + +Returns the uncompressed file offset. + +=head2 eof + +Usage is + + $z->eof(); + eof($z); + +Returns true if the end of the compressed input stream has been reached. + +=head2 seek + + $z->seek($position, $whence); + seek($z, $position, $whence); + +Provides a sub-set of the C<seek> functionality, with the restriction +that it is only legal to seek forward in the input file/buffer. +It is a fatal error to attempt to seek backward. + +The C<$whence> parameter takes one the usual values, namely SEEK_SET, +SEEK_CUR or SEEK_END. + +Returns 1 on success, 0 on failure. + +=head2 binmode + +Usage is + + $z->binmode + binmode $z ; + +This is a noop provided for completeness. + +=head2 opened + + $z->opened() + +Returns true if the object currently refers to a opened file/buffer. + +=head2 autoflush + + my $prev = $z->autoflush() + my $prev = $z->autoflush(EXPR) + +If the C<$z> object is associated with a file or a filehandle, this method +returns the current autoflush setting for the underlying filehandle. If +C<EXPR> is present, and is non-zero, it will enable flushing after every +write/print operation. + +If C<$z> is associated with a buffer, this method has no effect and always +returns C<undef>. + +B<Note> that the special variable C<$|> B<cannot> be used to set or +retrieve the autoflush setting. + +=head2 input_line_number + + $z->input_line_number() + $z->input_line_number(EXPR) + +Returns the current uncompressed line number. If C<EXPR> is present it has +the effect of setting the line number. Note that setting the line number +does not change the current position within the file/buffer being read. + +The contents of C<$/> are used to to determine what constitutes a line +terminator. + +=head2 fileno + + $z->fileno() + fileno($z) + +If the C<$z> object is associated with a file or a filehandle, C<fileno> +will return the underlying file descriptor. Once the C<close> method is +called C<fileno> will return C<undef>. + +If the C<$z> object is is associated with a buffer, this method will return +C<undef>. + +=head2 close + + $z->close() ; + close $z ; + +Closes the output file/buffer. + +For most versions of Perl this method will be automatically invoked if +the IO::Uncompress::Unzip object is destroyed (either explicitly or by the +variable with the reference to the object going out of scope). The +exceptions are Perl versions 5.005 through 5.00504 and 5.8.0. In +these cases, the C<close> method will be called automatically, but +not until global destruction of all live objects when the program is +terminating. + +Therefore, if you want your scripts to be able to run on all versions +of Perl, you should call C<close> explicitly and not rely on automatic +closing. + +Returns true on success, otherwise 0. + +If the C<AutoClose> option has been enabled when the IO::Uncompress::Unzip +object was created, and the object is associated with a file, the +underlying file will also be closed. + +=head2 nextStream + +Usage is + + my $status = $z->nextStream(); + +Skips to the next compressed data stream in the input file/buffer. If a new +compressed data stream is found, the eof marker will be cleared and C<$.> +will be reset to 0. + +Returns 1 if a new stream was found, 0 if none was found, and -1 if an +error was encountered. + +=head2 trailingData + +Usage is + + my $data = $z->trailingData(); + +Returns the data, if any, that is present immediately after the compressed +data stream once uncompression is complete. It only makes sense to call +this method once the end of the compressed data stream has been +encountered. + +This option can be used when there is useful information immediately +following the compressed data stream, and you don't know the length of the +compressed data stream. + +If the input is a buffer, C<trailingData> will return everything from the +end of the compressed data stream to the end of the buffer. + +If the input is a filehandle, C<trailingData> will return the data that is +left in the filehandle input buffer once the end of the compressed data +stream has been reached. You can then use the filehandle to read the rest +of the input file. + +Don't bother using C<trailingData> if the input is a filename. + +If you know the length of the compressed data stream before you start +uncompressing, you can avoid having to use C<trailingData> by setting the +C<InputLength> option in the constructor. + +=head1 Importing + +No symbolic constants are required by this IO::Uncompress::Unzip at present. + +=over 5 + +=item :all + +Imports C<unzip> and C<$UnzipError>. +Same as doing this + + use IO::Uncompress::Unzip qw(unzip $UnzipError) ; + +=back + +=head1 EXAMPLES + +=head2 Working with Net::FTP + +See L<IO::Uncompress::Unzip::FAQ|IO::Uncompress::Unzip::FAQ/"Compressed files and Net::FTP"> + +=head1 SEE ALSO + +L<Compress::Zlib>, L<IO::Compress::Gzip>, L<IO::Uncompress::Gunzip>, L<IO::Compress::Deflate>, L<IO::Uncompress::Inflate>, L<IO::Compress::RawDeflate>, L<IO::Uncompress::RawInflate>, L<IO::Compress::Bzip2>, L<IO::Uncompress::Bunzip2>, L<IO::Compress::Lzma>, L<IO::Uncompress::UnLzma>, L<IO::Compress::Xz>, L<IO::Uncompress::UnXz>, L<IO::Compress::Lzop>, L<IO::Uncompress::UnLzop>, L<IO::Compress::Lzf>, L<IO::Uncompress::UnLzf>, L<IO::Uncompress::AnyInflate>, L<IO::Uncompress::AnyUncompress> + +L<Compress::Zlib::FAQ|Compress::Zlib::FAQ> + +L<File::GlobMapper|File::GlobMapper>, L<Archive::Zip|Archive::Zip>, +L<Archive::Tar|Archive::Tar>, +L<IO::Zlib|IO::Zlib> + +For RFC 1950, 1951 and 1952 see +F<http://www.faqs.org/rfcs/rfc1950.html>, +F<http://www.faqs.org/rfcs/rfc1951.html> and +F<http://www.faqs.org/rfcs/rfc1952.html> + +The I<zlib> compression library was written by Jean-loup Gailly +F<gzip@prep.ai.mit.edu> and Mark Adler F<madler@alumni.caltech.edu>. + +The primary site for the I<zlib> compression library is +F<http://www.zlib.org>. + +The primary site for gzip is F<http://www.gzip.org>. + +=head1 AUTHOR + +This module was written by Paul Marquess, F<pmqs@cpan.org>. + +=head1 MODIFICATION HISTORY + +See the Changes file. + +=head1 COPYRIGHT AND LICENSE + +Copyright (c) 2005-2010 Paul Marquess. All rights reserved. + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + diff --git a/Master/tlpkg/tlperl/lib/IO/Zlib.pm b/Master/tlpkg/tlperl/lib/IO/Zlib.pm new file mode 100644 index 00000000000..55534b4f374 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/IO/Zlib.pm @@ -0,0 +1,652 @@ +# IO::Zlib.pm +# +# Copyright (c) 1998-2004 Tom Hughes <tom@compton.nu>. +# All rights reserved. This program is free software; you can redistribute +# it and/or modify it under the same terms as Perl itself. + +package IO::Zlib; + +$VERSION = "1.10"; + +=head1 NAME + +IO::Zlib - IO:: style interface to L<Compress::Zlib> + +=head1 SYNOPSIS + +With any version of Perl 5 you can use the basic OO interface: + + use IO::Zlib; + + $fh = new IO::Zlib; + if ($fh->open("file.gz", "rb")) { + print <$fh>; + $fh->close; + } + + $fh = IO::Zlib->new("file.gz", "wb9"); + if (defined $fh) { + print $fh "bar\n"; + $fh->close; + } + + $fh = IO::Zlib->new("file.gz", "rb"); + if (defined $fh) { + print <$fh>; + undef $fh; # automatically closes the file + } + +With Perl 5.004 you can also use the TIEHANDLE interface to access +compressed files just like ordinary files: + + use IO::Zlib; + + tie *FILE, 'IO::Zlib', "file.gz", "wb"; + print FILE "line 1\nline2\n"; + + tie *FILE, 'IO::Zlib', "file.gz", "rb"; + while (<FILE>) { print "LINE: ", $_ }; + +=head1 DESCRIPTION + +C<IO::Zlib> provides an IO:: style interface to L<Compress::Zlib> and +hence to gzip/zlib compressed files. It provides many of the same methods +as the L<IO::Handle> interface. + +Starting from IO::Zlib version 1.02, IO::Zlib can also use an +external F<gzip> command. The default behaviour is to try to use +an external F<gzip> if no C<Compress::Zlib> can be loaded, unless +explicitly disabled by + + use IO::Zlib qw(:gzip_external 0); + +If explicitly enabled by + + use IO::Zlib qw(:gzip_external 1); + +then the external F<gzip> is used B<instead> of C<Compress::Zlib>. + +=head1 CONSTRUCTOR + +=over 4 + +=item new ( [ARGS] ) + +Creates an C<IO::Zlib> object. If it receives any parameters, they are +passed to the method C<open>; if the open fails, the object is destroyed. +Otherwise, it is returned to the caller. + +=back + +=head1 OBJECT METHODS + +=over 4 + +=item open ( FILENAME, MODE ) + +C<open> takes two arguments. The first is the name of the file to open +and the second is the open mode. The mode can be anything acceptable to +L<Compress::Zlib> and by extension anything acceptable to I<zlib> (that +basically means POSIX fopen() style mode strings plus an optional number +to indicate the compression level). + +=item opened + +Returns true if the object currently refers to a opened file. + +=item close + +Close the file associated with the object and disassociate +the file from the handle. +Done automatically on destroy. + +=item getc + +Return the next character from the file, or undef if none remain. + +=item getline + +Return the next line from the file, or undef on end of string. +Can safely be called in an array context. +Currently ignores $/ ($INPUT_RECORD_SEPARATOR or $RS when L<English> +is in use) and treats lines as delimited by "\n". + +=item getlines + +Get all remaining lines from the file. +It will croak() if accidentally called in a scalar context. + +=item print ( ARGS... ) + +Print ARGS to the file. + +=item read ( BUF, NBYTES, [OFFSET] ) + +Read some bytes from the file. +Returns the number of bytes actually read, 0 on end-of-file, undef on error. + +=item eof + +Returns true if the handle is currently positioned at end of file? + +=item seek ( OFFSET, WHENCE ) + +Seek to a given position in the stream. +Not yet supported. + +=item tell + +Return the current position in the stream, as a numeric offset. +Not yet supported. + +=item setpos ( POS ) + +Set the current position, using the opaque value returned by C<getpos()>. +Not yet supported. + +=item getpos ( POS ) + +Return the current position in the string, as an opaque object. +Not yet supported. + +=back + +=head1 USING THE EXTERNAL GZIP + +If the external F<gzip> is used, the following C<open>s are used: + + open(FH, "gzip -dc $filename |") # for read opens + open(FH, " | gzip > $filename") # for write opens + +You can modify the 'commands' for example to hardwire +an absolute path by e.g. + + use IO::Zlib ':gzip_read_open' => '/some/where/gunzip -c %s |'; + use IO::Zlib ':gzip_write_open' => '| /some/where/gzip.exe > %s'; + +The C<%s> is expanded to be the filename (C<sprintf> is used, so be +careful to escape any other C<%> signs). The 'commands' are checked +for sanity - they must contain the C<%s>, and the read open must end +with the pipe sign, and the write open must begin with the pipe sign. + +=head1 CLASS METHODS + +=over 4 + +=item has_Compress_Zlib + +Returns true if C<Compress::Zlib> is available. Note that this does +not mean that C<Compress::Zlib> is being used: see L</gzip_external> +and L<gzip_used>. + +=item gzip_external + +Undef if an external F<gzip> B<can> be used if C<Compress::Zlib> is +not available (see L</has_Compress_Zlib>), true if an external F<gzip> +is explicitly used, false if an external F<gzip> must not be used. +See L</gzip_used>. + +=item gzip_used + +True if an external F<gzip> is being used, false if not. + +=item gzip_read_open + +Return the 'command' being used for opening a file for reading using an +external F<gzip>. + +=item gzip_write_open + +Return the 'command' being used for opening a file for writing using an +external F<gzip>. + +=back + +=head1 DIAGNOSTICS + +=over 4 + +=item IO::Zlib::getlines: must be called in list context + +If you want read lines, you must read in list context. + +=item IO::Zlib::gzopen_external: mode '...' is illegal + +Use only modes 'rb' or 'wb' or /wb[1-9]/. + +=item IO::Zlib::import: '...' is illegal + +The known import symbols are the C<:gzip_external>, C<:gzip_read_open>, +and C<:gzip_write_open>. Anything else is not recognized. + +=item IO::Zlib::import: ':gzip_external' requires an argument + +The C<:gzip_external> requires one boolean argument. + +=item IO::Zlib::import: 'gzip_read_open' requires an argument + +The C<:gzip_external> requires one string argument. + +=item IO::Zlib::import: 'gzip_read' '...' is illegal + +The C<:gzip_read_open> argument must end with the pipe sign (|) +and have the C<%s> for the filename. See L</"USING THE EXTERNAL GZIP">. + +=item IO::Zlib::import: 'gzip_write_open' requires an argument + +The C<:gzip_external> requires one string argument. + +=item IO::Zlib::import: 'gzip_write_open' '...' is illegal + +The C<:gzip_write_open> argument must begin with the pipe sign (|) +and have the C<%s> for the filename. An output redirect (>) is also +often a good idea, depending on your operating system shell syntax. +See L</"USING THE EXTERNAL GZIP">. + +=item IO::Zlib::import: no Compress::Zlib and no external gzip + +Given that we failed to load C<Compress::Zlib> and that the use of + an external F<gzip> was disabled, IO::Zlib has not much chance of working. + +=item IO::Zlib::open: needs a filename + +No filename, no open. + +=item IO::Zlib::READ: NBYTES must be specified + +We must know how much to read. + +=item IO::Zlib::WRITE: too long LENGTH + +The LENGTH must be less than or equal to the buffer size. + +=back + +=head1 SEE ALSO + +L<perlfunc>, +L<perlop/"I/O Operators">, +L<IO::Handle>, +L<Compress::Zlib> + +=head1 HISTORY + +Created by Tom Hughes E<lt>F<tom@compton.nu>E<gt>. + +Support for external gzip added by Jarkko Hietaniemi E<lt>F<jhi@iki.fi>E<gt>. + +=head1 COPYRIGHT + +Copyright (c) 1998-2004 Tom Hughes E<lt>F<tom@compton.nu>E<gt>. +All rights reserved. This program is free software; you can redistribute +it and/or modify it under the same terms as Perl itself. + +=cut + +require 5.006; + +use strict; +use vars qw($VERSION $AUTOLOAD @ISA); + +use Carp; +use Fcntl qw(SEEK_SET); + +my $has_Compress_Zlib; +my $aliased; + +sub has_Compress_Zlib { + $has_Compress_Zlib; +} + +BEGIN { + eval { require Compress::Zlib }; + $has_Compress_Zlib = $@ || $Compress::Zlib::VERSION < 2.000 ? 0 : 1; +} + +use Symbol; +use Tie::Handle; + +# These might use some $^O logic. +my $gzip_read_open = "gzip -dc %s |"; +my $gzip_write_open = "| gzip > %s"; + +my $gzip_external; +my $gzip_used; + +sub gzip_read_open { + $gzip_read_open; +} + +sub gzip_write_open { + $gzip_write_open; +} + +sub gzip_external { + $gzip_external; +} + +sub gzip_used { + $gzip_used; +} + +sub can_gunzip { + $has_Compress_Zlib || $gzip_external; +} + +sub _import { + my $import = shift; + while (@_) { + if ($_[0] eq ':gzip_external') { + shift; + if (@_) { + $gzip_external = shift; + } else { + croak "$import: ':gzip_external' requires an argument"; + } + } + elsif ($_[0] eq ':gzip_read_open') { + shift; + if (@_) { + $gzip_read_open = shift; + croak "$import: ':gzip_read_open' '$gzip_read_open' is illegal" + unless $gzip_read_open =~ /^.+%s.+\|\s*$/; + } else { + croak "$import: ':gzip_read_open' requires an argument"; + } + } + elsif ($_[0] eq ':gzip_write_open') { + shift; + if (@_) { + $gzip_write_open = shift; + croak "$import: ':gzip_write_open' '$gzip_read_open' is illegal" + unless $gzip_write_open =~ /^\s*\|.+%s.*$/; + } else { + croak "$import: ':gzip_write_open' requires an argument"; + } + } + else { + last; + } + } + return @_; +} + +sub _alias { + my $import = shift; + if ((!$has_Compress_Zlib && !defined $gzip_external) || $gzip_external) { + # The undef *gzopen is really needed only during + # testing where we eval several 'use IO::Zlib's. + undef *gzopen; + *gzopen = \&gzopen_external; + *IO::Handle::gzread = \&gzread_external; + *IO::Handle::gzwrite = \&gzwrite_external; + *IO::Handle::gzreadline = \&gzreadline_external; + *IO::Handle::gzeof = \&gzeof_external; + *IO::Handle::gzclose = \&gzclose_external; + $gzip_used = 1; + } else { + croak "$import: no Compress::Zlib and no external gzip" + unless $has_Compress_Zlib; + *gzopen = \&Compress::Zlib::gzopen; + *gzread = \&Compress::Zlib::gzread; + *gzwrite = \&Compress::Zlib::gzwrite; + *gzreadline = \&Compress::Zlib::gzreadline; + *gzeof = \&Compress::Zlib::gzeof; + } + $aliased = 1; +} + +sub import { + shift; + my $import = "IO::Zlib::import"; + if (@_) { + if (_import($import, @_)) { + croak "$import: '@_' is illegal"; + } + } + _alias($import); +} + +@ISA = qw(Tie::Handle); + +sub TIEHANDLE +{ + my $class = shift; + my @args = @_; + + my $self = bless {}, $class; + + return @args ? $self->OPEN(@args) : $self; +} + +sub DESTROY +{ +} + +sub OPEN +{ + my $self = shift; + my $filename = shift; + my $mode = shift; + + croak "IO::Zlib::open: needs a filename" unless defined($filename); + + $self->{'file'} = gzopen($filename,$mode); + + return defined($self->{'file'}) ? $self : undef; +} + +sub CLOSE +{ + my $self = shift; + + return undef unless defined($self->{'file'}); + + my $status = $self->{'file'}->gzclose(); + + delete $self->{'file'}; + + return ($status == 0) ? 1 : undef; +} + +sub READ +{ + my $self = shift; + my $bufref = \$_[0]; + my $nbytes = $_[1]; + my $offset = $_[2] || 0; + + croak "IO::Zlib::READ: NBYTES must be specified" unless defined($nbytes); + + $$bufref = "" unless defined($$bufref); + + my $bytesread = $self->{'file'}->gzread(substr($$bufref,$offset),$nbytes); + + return undef if $bytesread < 0; + + return $bytesread; +} + +sub READLINE +{ + my $self = shift; + + my $line; + + return () if $self->{'file'}->gzreadline($line) <= 0; + + return $line unless wantarray; + + my @lines = $line; + + while ($self->{'file'}->gzreadline($line) > 0) + { + push @lines, $line; + } + + return @lines; +} + +sub WRITE +{ + my $self = shift; + my $buf = shift; + my $length = shift; + my $offset = shift; + + croak "IO::Zlib::WRITE: too long LENGTH" unless $offset + $length <= length($buf); + + return $self->{'file'}->gzwrite(substr($buf,$offset,$length)); +} + +sub EOF +{ + my $self = shift; + + return $self->{'file'}->gzeof(); +} + +sub FILENO +{ + return undef; +} + +sub new +{ + my $class = shift; + my @args = @_; + + _alias("new", @_) unless $aliased; # Some call new IO::Zlib directly... + + my $self = gensym(); + + tie *{$self}, $class, @args; + + return tied(${$self}) ? bless $self, $class : undef; +} + +sub getline +{ + my $self = shift; + + return scalar tied(*{$self})->READLINE(); +} + +sub getlines +{ + my $self = shift; + + croak "IO::Zlib::getlines: must be called in list context" + unless wantarray; + + return tied(*{$self})->READLINE(); +} + +sub opened +{ + my $self = shift; + + return defined tied(*{$self})->{'file'}; +} + +sub AUTOLOAD +{ + my $self = shift; + + $AUTOLOAD =~ s/.*:://; + $AUTOLOAD =~ tr/a-z/A-Z/; + + return tied(*{$self})->$AUTOLOAD(@_); +} + +sub gzopen_external { + my ($filename, $mode) = @_; + require IO::Handle; + my $fh = IO::Handle->new(); + if ($mode =~ /r/) { + # Because someone will try to read ungzipped files + # with this we peek and verify the signature. Yes, + # this means that we open the file twice (if it is + # gzipped). + # Plenty of race conditions exist in this code, but + # the alternative would be to capture the stderr of + # gzip and parse it, which would be a portability nightmare. + if (-e $filename && open($fh, $filename)) { + binmode $fh; + my $sig; + my $rdb = read($fh, $sig, 2); + if ($rdb == 2 && $sig eq "\x1F\x8B") { + my $ropen = sprintf $gzip_read_open, $filename; + if (open($fh, $ropen)) { + binmode $fh; + return $fh; + } else { + return undef; + } + } + seek($fh, 0, SEEK_SET) or + die "IO::Zlib: open('$filename', 'r'): seek: $!"; + return $fh; + } else { + return undef; + } + } elsif ($mode =~ /w/) { + my $level = ''; + $level = "-$1" if $mode =~ /([1-9])/; + # To maximize portability we would need to open + # two filehandles here, one for "| gzip $level" + # and another for "> $filename", and then when + # writing copy bytes from the first to the second. + # We are using IO::Handle objects for now, however, + # and they can only contain one stream at a time. + my $wopen = sprintf $gzip_write_open, $filename; + if (open($fh, $wopen)) { + $fh->autoflush(1); + binmode $fh; + return $fh; + } else { + return undef; + } + } else { + croak "IO::Zlib::gzopen_external: mode '$mode' is illegal"; + } + return undef; +} + +sub gzread_external { + # Use read() instead of syswrite() because people may + # mix reads and readlines, and we don't want to mess + # the stdio buffering. See also gzreadline_external() + # and gzwrite_external(). + my $nread = read($_[0], $_[1], @_ == 3 ? $_[2] : 4096); + defined $nread ? $nread : -1; +} + +sub gzwrite_external { + # Using syswrite() is okay (cf. gzread_external()) + # since the bytes leave this process and buffering + # is therefore not an issue. + my $nwrote = syswrite($_[0], $_[1]); + defined $nwrote ? $nwrote : -1; +} + +sub gzreadline_external { + # See the comment in gzread_external(). + $_[1] = readline($_[0]); + return defined $_[1] ? length($_[1]) : -1; +} + +sub gzeof_external { + return eof($_[0]); +} + +sub gzclose_external { + close($_[0]); + # I am not entirely certain why this is needed but it seems + # the above close() always fails (as if the stream would have + # been already closed - something to do with using external + # processes via pipes?) + return 0; +} + +1; diff --git a/Master/tlpkg/tlperl/lib/Unicode/Collate.pm b/Master/tlpkg/tlperl/lib/Unicode/Collate.pm new file mode 100644 index 00000000000..2e989d6bb54 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Unicode/Collate.pm @@ -0,0 +1,1877 @@ +package Unicode::Collate; + +BEGIN { + unless ("A" eq pack('U', 0x41)) { + die "Unicode::Collate cannot stringify a Unicode code point\n"; + } +} + +use 5.006; +use strict; +use warnings; +use Carp; +use File::Spec; + +no warnings 'utf8'; + +our $VERSION = '0.52_01'; +our $PACKAGE = __PACKAGE__; + +my @Path = qw(Unicode Collate); +my $KeyFile = "allkeys.txt"; + +# Perl's boolean +use constant TRUE => 1; +use constant FALSE => ""; +use constant NOMATCHPOS => -1; + +# A coderef to get combining class imported from Unicode::Normalize +# (i.e. \&Unicode::Normalize::getCombinClass). +# This is also used as a HAS_UNICODE_NORMALIZE flag. +my $CVgetCombinClass; + +# Supported Levels +use constant MinLevel => 1; +use constant MaxLevel => 4; + +# Minimum weights at level 2 and 3, respectively +use constant Min2Wt => 0x20; +use constant Min3Wt => 0x02; + +# Shifted weight at 4th level +use constant Shift4Wt => 0xFFFF; + +# A boolean for Variable and 16-bit weights at 4 levels of Collation Element +# PROBLEM: The Default Unicode Collation Element Table +# has weights over 0xFFFF at the 4th level. +# The tie-breaking in the variable weights +# other than "shift" (as well as "shift-trimmed") is unreliable. +use constant VCE_TEMPLATE => 'Cn4'; + +# A sort key: 16-bit weights +# See also the PROBLEM on VCE_TEMPLATE above. +use constant KEY_TEMPLATE => 'n*'; + +# Level separator in a sort key: +# i.e. pack(KEY_TEMPLATE, 0) +use constant LEVEL_SEP => "\0\0"; + +# As Unicode code point separator for hash keys. +# A joined code point string (denoted by JCPS below) +# like "65;768" is used for internal processing +# instead of Perl's Unicode string like "\x41\x{300}", +# as the native code point is different from the Unicode code point +# on EBCDIC platform. +# This character must not be included in any stringified +# representation of an integer. +use constant CODE_SEP => ';'; + +# boolean values of variable weights +use constant NON_VAR => 0; # Non-Variable character +use constant VAR => 1; # Variable character + +# specific code points +use constant Hangul_LBase => 0x1100; +use constant Hangul_LIni => 0x1100; +use constant Hangul_LFin => 0x1159; +use constant Hangul_LFill => 0x115F; +use constant Hangul_VBase => 0x1161; +use constant Hangul_VIni => 0x1160; # from Vowel Filler +use constant Hangul_VFin => 0x11A2; +use constant Hangul_TBase => 0x11A7; # from "no-final" codepoint +use constant Hangul_TIni => 0x11A8; +use constant Hangul_TFin => 0x11F9; +use constant Hangul_TCount => 28; +use constant Hangul_NCount => 588; +use constant Hangul_SBase => 0xAC00; +use constant Hangul_SIni => 0xAC00; +use constant Hangul_SFin => 0xD7A3; +use constant CJK_UidIni => 0x4E00; +use constant CJK_UidFin => 0x9FA5; +use constant CJK_UidF41 => 0x9FBB; +use constant CJK_ExtAIni => 0x3400; +use constant CJK_ExtAFin => 0x4DB5; +use constant CJK_ExtBIni => 0x20000; +use constant CJK_ExtBFin => 0x2A6D6; +use constant BMP_Max => 0xFFFF; + +# Logical_Order_Exception in PropList.txt +my $DefaultRearrange = [ 0x0E40..0x0E44, 0x0EC0..0x0EC4 ]; + +sub UCA_Version { "14" } + +sub Base_Unicode_Version { "4.1.0" } + +###### + +sub pack_U { + return pack('U*', @_); +} + +sub unpack_U { + return unpack('U*', shift(@_).pack('U*')); +} + +###### + +my (%VariableOK); +@VariableOK{ qw/ + blanked non-ignorable shifted shift-trimmed + / } = (); # keys lowercased + +our @ChangeOK = qw/ + alternate backwards level normalization rearrange + katakana_before_hiragana upper_before_lower + overrideHangul overrideCJK preprocess UCA_Version + hangul_terminator variable + /; + +our @ChangeNG = qw/ + entry mapping table maxlength + ignoreChar ignoreName undefChar undefName variableTable + versionTable alternateTable backwardsTable forwardsTable rearrangeTable + derivCode normCode rearrangeHash + backwardsFlag + /; +# The hash key 'ignored' is deleted at v 0.21. +# The hash key 'isShift' is deleted at v 0.23. +# The hash key 'combining' is deleted at v 0.24. +# The hash key 'entries' is deleted at v 0.30. +# The hash key 'L3_ignorable' is deleted at v 0.40. + +sub version { + my $self = shift; + return $self->{versionTable} || 'unknown'; +} + +my (%ChangeOK, %ChangeNG); +@ChangeOK{ @ChangeOK } = (); +@ChangeNG{ @ChangeNG } = (); + +sub change { + my $self = shift; + my %hash = @_; + my %old; + if (exists $hash{variable} && exists $hash{alternate}) { + delete $hash{alternate}; + } + elsif (!exists $hash{variable} && exists $hash{alternate}) { + $hash{variable} = $hash{alternate}; + } + foreach my $k (keys %hash) { + if (exists $ChangeOK{$k}) { + $old{$k} = $self->{$k}; + $self->{$k} = $hash{$k}; + } + elsif (exists $ChangeNG{$k}) { + croak "change of $k via change() is not allowed!"; + } + # else => ignored + } + $self->checkCollator(); + return wantarray ? %old : $self; +} + +sub _checkLevel { + my $level = shift; + my $key = shift; # 'level' or 'backwards' + MinLevel <= $level or croak sprintf + "Illegal level %d (in value for key '%s') lower than %d.", + $level, $key, MinLevel; + $level <= MaxLevel or croak sprintf + "Unsupported level %d (in value for key '%s') higher than %d.", + $level, $key, MaxLevel; +} + +my %DerivCode = ( + 8 => \&_derivCE_8, + 9 => \&_derivCE_9, + 11 => \&_derivCE_9, # 11 == 9 + 14 => \&_derivCE_14, +); + +sub checkCollator { + my $self = shift; + _checkLevel($self->{level}, "level"); + + $self->{derivCode} = $DerivCode{ $self->{UCA_Version} } + or croak "Illegal UCA version (passed $self->{UCA_Version})."; + + $self->{variable} ||= $self->{alternate} || $self->{variableTable} || + $self->{alternateTable} || 'shifted'; + $self->{variable} = $self->{alternate} = lc($self->{variable}); + exists $VariableOK{ $self->{variable} } + or croak "$PACKAGE unknown variable parameter name: $self->{variable}"; + + if (! defined $self->{backwards}) { + $self->{backwardsFlag} = 0; + } + elsif (! ref $self->{backwards}) { + _checkLevel($self->{backwards}, "backwards"); + $self->{backwardsFlag} = 1 << $self->{backwards}; + } + else { + my %level; + $self->{backwardsFlag} = 0; + for my $b (@{ $self->{backwards} }) { + _checkLevel($b, "backwards"); + $level{$b} = 1; + } + for my $v (sort keys %level) { + $self->{backwardsFlag} += 1 << $v; + } + } + + defined $self->{rearrange} or $self->{rearrange} = []; + ref $self->{rearrange} + or croak "$PACKAGE: list for rearrangement must be store in ARRAYREF"; + + # keys of $self->{rearrangeHash} are $self->{rearrange}. + $self->{rearrangeHash} = undef; + + if (@{ $self->{rearrange} }) { + @{ $self->{rearrangeHash} }{ @{ $self->{rearrange} } } = (); + } + + $self->{normCode} = undef; + + if (defined $self->{normalization}) { + eval { require Unicode::Normalize }; + $@ and croak "Unicode::Normalize is required to normalize strings"; + + $CVgetCombinClass ||= \&Unicode::Normalize::getCombinClass; + + if ($self->{normalization} =~ /^(?:NF)D\z/) { # tweak for default + $self->{normCode} = \&Unicode::Normalize::NFD; + } + elsif ($self->{normalization} ne 'prenormalized') { + my $norm = $self->{normalization}; + $self->{normCode} = sub { + Unicode::Normalize::normalize($norm, shift); + }; + eval { $self->{normCode}->("") }; # try + $@ and croak "$PACKAGE unknown normalization form name: $norm"; + } + } + return; +} + +sub new +{ + my $class = shift; + my $self = bless { @_ }, $class; + + # If undef is passed explicitly, no file is read. + $self->{table} = $KeyFile if ! exists $self->{table}; + $self->read_table() if defined $self->{table}; + + if ($self->{entry}) { + while ($self->{entry} =~ /([^\n]+)/g) { + $self->parseEntry($1); + } + } + + $self->{level} ||= MaxLevel; + $self->{UCA_Version} ||= UCA_Version(); + + $self->{overrideHangul} = FALSE + if ! exists $self->{overrideHangul}; + $self->{overrideCJK} = FALSE + if ! exists $self->{overrideCJK}; + $self->{normalization} = 'NFD' + if ! exists $self->{normalization}; + $self->{rearrange} = $self->{rearrangeTable} || + ($self->{UCA_Version} <= 11 ? $DefaultRearrange : []) + if ! exists $self->{rearrange}; + $self->{backwards} = $self->{backwardsTable} + if ! exists $self->{backwards}; + + $self->checkCollator(); + + return $self; +} + +sub read_table { + my $self = shift; + + my($f, $fh); + foreach my $d (@INC) { + $f = File::Spec->catfile($d, @Path, $self->{table}); + last if open($fh, $f); + $f = undef; + } + if (!defined $f) { + $f = File::Spec->catfile(@Path, $self->{table}); + croak("$PACKAGE: Can't locate $f in \@INC (\@INC contains: @INC)"); + } + + while (my $line = <$fh>) { + next if $line =~ /^\s*#/; + unless ($line =~ s/^\s*\@//) { + $self->parseEntry($line); + next; + } + + # matched ^\s*\@ + if ($line =~ /^version\s*(\S*)/) { + $self->{versionTable} ||= $1; + } + elsif ($line =~ /^variable\s+(\S*)/) { # since UTS #10-9 + $self->{variableTable} ||= $1; + } + elsif ($line =~ /^alternate\s+(\S*)/) { # till UTS #10-8 + $self->{alternateTable} ||= $1; + } + elsif ($line =~ /^backwards\s+(\S*)/) { + push @{ $self->{backwardsTable} }, $1; + } + elsif ($line =~ /^forwards\s+(\S*)/) { # parhaps no use + push @{ $self->{forwardsTable} }, $1; + } + elsif ($line =~ /^rearrange\s+(.*)/) { # (\S*) is NG + push @{ $self->{rearrangeTable} }, _getHexArray($1); + } + } + close $fh; +} + + +## +## get $line, parse it, and write an entry in $self +## +sub parseEntry +{ + my $self = shift; + my $line = shift; + my($name, $entry, @uv, @key); + + return if $line !~ /^\s*[0-9A-Fa-f]/; + + # removes comment and gets name + $name = $1 + if $line =~ s/[#%]\s*(.*)//; + return if defined $self->{undefName} && $name =~ /$self->{undefName}/; + + # gets element + my($e, $k) = split /;/, $line; + croak "Wrong Entry: <charList> must be separated by ';' from <collElement>" + if ! $k; + + @uv = _getHexArray($e); + return if !@uv; + + $entry = join(CODE_SEP, @uv); # in JCPS + + if (defined $self->{undefChar} || defined $self->{ignoreChar}) { + my $ele = pack_U(@uv); + + # regarded as if it were not entried in the table + return + if defined $self->{undefChar} && $ele =~ /$self->{undefChar}/; + + # replaced as completely ignorable + $k = '[.0000.0000.0000.0000]' + if defined $self->{ignoreChar} && $ele =~ /$self->{ignoreChar}/; + } + + # replaced as completely ignorable + $k = '[.0000.0000.0000.0000]' + if defined $self->{ignoreName} && $name =~ /$self->{ignoreName}/; + + my $is_L3_ignorable = TRUE; + + foreach my $arr ($k =~ /\[([^\[\]]+)\]/g) { # SPACEs allowed + my $var = $arr =~ /\*/; # exactly /^\*/ but be lenient. + my @wt = _getHexArray($arr); + push @key, pack(VCE_TEMPLATE, $var, @wt); + $is_L3_ignorable = FALSE + if $wt[0] || $wt[1] || $wt[2]; + # Conformance Test for 3.1.1 and 4.0.0 shows Level 3 ignorable + # is completely ignorable. + # For expansion, an entry $is_L3_ignorable + # if and only if "all" CEs are [.0000.0000.0000]. + } + + $self->{mapping}{$entry} = $is_L3_ignorable ? [] : \@key; + + if (@uv > 1) { + (!$self->{maxlength}{$uv[0]} || $self->{maxlength}{$uv[0]} < @uv) + and $self->{maxlength}{$uv[0]} = @uv; + } +} + + +## +## VCE = _varCE(variable term, VCE) +## +sub _varCE +{ + my $vbl = shift; + my $vce = shift; + if ($vbl eq 'non-ignorable') { + return $vce; + } + my ($var, @wt) = unpack VCE_TEMPLATE, $vce; + + if ($var) { + return pack(VCE_TEMPLATE, $var, 0, 0, 0, + $vbl eq 'blanked' ? $wt[3] : $wt[0]); + } + elsif ($vbl eq 'blanked') { + return $vce; + } + else { + return pack(VCE_TEMPLATE, $var, @wt[0..2], + $vbl eq 'shifted' && $wt[0]+$wt[1]+$wt[2] ? Shift4Wt : 0); + } +} + +sub viewSortKey +{ + my $self = shift; + $self->visualizeSortKey($self->getSortKey(@_)); +} + +sub visualizeSortKey +{ + my $self = shift; + my $view = join " ", map sprintf("%04X", $_), unpack(KEY_TEMPLATE, shift); + + if ($self->{UCA_Version} <= 8) { + $view =~ s/ ?0000 ?/|/g; + } else { + $view =~ s/\b0000\b/|/g; + } + return "[$view]"; +} + + +## +## arrayref of JCPS = splitEnt(string to be collated) +## arrayref of arrayref[JCPS, ini_pos, fin_pos] = splitEnt(string, true) +## +sub splitEnt +{ + my $self = shift; + my $wLen = $_[1]; + + my $code = $self->{preprocess}; + my $norm = $self->{normCode}; + my $map = $self->{mapping}; + my $max = $self->{maxlength}; + my $reH = $self->{rearrangeHash}; + my $ver9 = $self->{UCA_Version} >= 9 && $self->{UCA_Version} <= 11; + + my ($str, @buf); + + if ($wLen) { + $code and croak "Preprocess breaks character positions. " + . "Don't use with index(), match(), etc."; + $norm and croak "Normalization breaks character positions. " + . "Don't use with index(), match(), etc."; + $str = $_[0]; + } + else { + $str = $_[0]; + $str = &$code($str) if ref $code; + $str = &$norm($str) if ref $norm; + } + + # get array of Unicode code point of string. + my @src = unpack_U($str); + + # rearrangement: + # Character positions are not kept if rearranged, + # then neglected if $wLen is true. + if ($reH && ! $wLen) { + for (my $i = 0; $i < @src; $i++) { + if (exists $reH->{ $src[$i] } && $i + 1 < @src) { + ($src[$i], $src[$i+1]) = ($src[$i+1], $src[$i]); + $i++; + } + } + } + + # remove a code point marked as a completely ignorable. + for (my $i = 0; $i < @src; $i++) { + $src[$i] = undef + if _isIllegal($src[$i]) || ($ver9 && + $map->{ $src[$i] } && @{ $map->{ $src[$i] } } == 0); + } + + for (my $i = 0; $i < @src; $i++) { + my $jcps = $src[$i]; + + # skip removed code point + if (! defined $jcps) { + if ($wLen && @buf) { + $buf[-1][2] = $i + 1; + } + next; + } + + my $i_orig = $i; + + # find contraction + if ($max->{$jcps}) { + my $temp_jcps = $jcps; + my $jcpsLen = 1; + my $maxLen = $max->{$jcps}; + + for (my $p = $i + 1; $jcpsLen < $maxLen && $p < @src; $p++) { + next if ! defined $src[$p]; + $temp_jcps .= CODE_SEP . $src[$p]; + $jcpsLen++; + if ($map->{$temp_jcps}) { + $jcps = $temp_jcps; + $i = $p; + } + } + + # not-contiguous contraction with Combining Char (cf. UTS#10, S2.1). + # This process requires Unicode::Normalize. + # If "normalization" is undef, here should be skipped *always* + # (in spite of bool value of $CVgetCombinClass), + # since canonical ordering cannot be expected. + # Blocked combining character should not be contracted. + + if ($self->{normalization}) + # $self->{normCode} is false in the case of "prenormalized". + { + my $preCC = 0; + my $curCC = 0; + + for (my $p = $i + 1; $p < @src; $p++) { + next if ! defined $src[$p]; + $curCC = $CVgetCombinClass->($src[$p]); + last unless $curCC; + my $tail = CODE_SEP . $src[$p]; + if ($preCC != $curCC && $map->{$jcps.$tail}) { + $jcps .= $tail; + $src[$p] = undef; + } else { + $preCC = $curCC; + } + } + } + } + + # skip completely ignorable + if ($map->{$jcps} && @{ $map->{$jcps} } == 0) { + if ($wLen && @buf) { + $buf[-1][2] = $i + 1; + } + next; + } + + push @buf, $wLen ? [$jcps, $i_orig, $i + 1] : $jcps; + } + return \@buf; +} + + +## +## list of VCE = getWt(JCPS) +## +sub getWt +{ + my $self = shift; + my $u = shift; + my $vbl = $self->{variable}; + my $map = $self->{mapping}; + my $der = $self->{derivCode}; + + return if !defined $u; + return map(_varCE($vbl, $_), @{ $map->{$u} }) + if $map->{$u}; + + # JCPS must not be a contraction, then it's a code point. + if (Hangul_SIni <= $u && $u <= Hangul_SFin) { + my $hang = $self->{overrideHangul}; + my @hangulCE; + if ($hang) { + @hangulCE = map(pack(VCE_TEMPLATE, NON_VAR, @$_), &$hang($u)); + } + elsif (!defined $hang) { + @hangulCE = $der->($u); + } + else { + my $max = $self->{maxlength}; + my @decH = _decompHangul($u); + + if (@decH == 2) { + my $contract = join(CODE_SEP, @decH); + @decH = ($contract) if $map->{$contract}; + } else { # must be <@decH == 3> + if ($max->{$decH[0]}) { + my $contract = join(CODE_SEP, @decH); + if ($map->{$contract}) { + @decH = ($contract); + } else { + $contract = join(CODE_SEP, @decH[0,1]); + $map->{$contract} and @decH = ($contract, $decH[2]); + } + # even if V's ignorable, LT contraction is not supported. + # If such a situatution were required, NFD should be used. + } + if (@decH == 3 && $max->{$decH[1]}) { + my $contract = join(CODE_SEP, @decH[1,2]); + $map->{$contract} and @decH = ($decH[0], $contract); + } + } + + @hangulCE = map({ + $map->{$_} ? @{ $map->{$_} } : $der->($_); + } @decH); + } + return map _varCE($vbl, $_), @hangulCE; + } + elsif (_isUIdeo($u, $self->{UCA_Version})) { + my $cjk = $self->{overrideCJK}; + return map _varCE($vbl, $_), + $cjk + ? map(pack(VCE_TEMPLATE, NON_VAR, @$_), &$cjk($u)) + : defined $cjk && $self->{UCA_Version} <= 8 && $u < 0x10000 + ? _uideoCE_8($u) + : $der->($u); + } + else { + return map _varCE($vbl, $_), $der->($u); + } +} + + +## +## string sortkey = getSortKey(string arg) +## +sub getSortKey +{ + my $self = shift; + my $lev = $self->{level}; + my $rEnt = $self->splitEnt(shift); # get an arrayref of JCPS + my $v2i = $self->{UCA_Version} >= 9 && + $self->{variable} ne 'non-ignorable'; + + my @buf; # weight arrays + if ($self->{hangul_terminator}) { + my $preHST = ''; + foreach my $jcps (@$rEnt) { + # weird things like VL, TL-contraction are not considered! + my $curHST = ''; + foreach my $u (split /;/, $jcps) { + $curHST .= getHST($u); + } + if ($preHST && !$curHST || # hangul before non-hangul + $preHST =~ /L\z/ && $curHST =~ /^T/ || + $preHST =~ /V\z/ && $curHST =~ /^L/ || + $preHST =~ /T\z/ && $curHST =~ /^[LV]/) { + + push @buf, $self->getWtHangulTerm(); + } + $preHST = $curHST; + + push @buf, $self->getWt($jcps); + } + $preHST # end at hangul + and push @buf, $self->getWtHangulTerm(); + } + else { + foreach my $jcps (@$rEnt) { + push @buf, $self->getWt($jcps); + } + } + + # make sort key + my @ret = ([],[],[],[]); + my $last_is_variable; + + foreach my $vwt (@buf) { + my($var, @wt) = unpack(VCE_TEMPLATE, $vwt); + + # "Ignorable (L1, L2) after Variable" since track. v. 9 + if ($v2i) { + if ($var) { + $last_is_variable = TRUE; + } + elsif (!$wt[0]) { # ignorable + next if $last_is_variable; + } + else { + $last_is_variable = FALSE; + } + } + foreach my $v (0..$lev-1) { + 0 < $wt[$v] and push @{ $ret[$v] }, $wt[$v]; + } + } + + # modification of tertiary weights + if ($self->{upper_before_lower}) { + foreach my $w (@{ $ret[2] }) { + if (0x8 <= $w && $w <= 0xC) { $w -= 6 } # lower + elsif (0x2 <= $w && $w <= 0x6) { $w += 6 } # upper + elsif ($w == 0x1C) { $w += 1 } # square upper + elsif ($w == 0x1D) { $w -= 1 } # square lower + } + } + if ($self->{katakana_before_hiragana}) { + foreach my $w (@{ $ret[2] }) { + if (0x0F <= $w && $w <= 0x13) { $w -= 2 } # katakana + elsif (0x0D <= $w && $w <= 0x0E) { $w += 5 } # hiragana + } + } + + if ($self->{backwardsFlag}) { + for (my $v = MinLevel; $v <= MaxLevel; $v++) { + if ($self->{backwardsFlag} & (1 << $v)) { + @{ $ret[$v-1] } = reverse @{ $ret[$v-1] }; + } + } + } + + join LEVEL_SEP, map pack(KEY_TEMPLATE, @$_), @ret; +} + + +## +## int compare = cmp(string a, string b) +## +sub cmp { $_[0]->getSortKey($_[1]) cmp $_[0]->getSortKey($_[2]) } +sub eq { $_[0]->getSortKey($_[1]) eq $_[0]->getSortKey($_[2]) } +sub ne { $_[0]->getSortKey($_[1]) ne $_[0]->getSortKey($_[2]) } +sub lt { $_[0]->getSortKey($_[1]) lt $_[0]->getSortKey($_[2]) } +sub le { $_[0]->getSortKey($_[1]) le $_[0]->getSortKey($_[2]) } +sub gt { $_[0]->getSortKey($_[1]) gt $_[0]->getSortKey($_[2]) } +sub ge { $_[0]->getSortKey($_[1]) ge $_[0]->getSortKey($_[2]) } + +## +## list[strings] sorted = sort(list[strings] arg) +## +sub sort { + my $obj = shift; + return + map { $_->[1] } + sort{ $a->[0] cmp $b->[0] } + map [ $obj->getSortKey($_), $_ ], @_; +} + + +sub _derivCE_14 { + my $u = shift; + my $base = + (CJK_UidIni <= $u && $u <= CJK_UidF41) + ? 0xFB40 : # CJK + (CJK_ExtAIni <= $u && $u <= CJK_ExtAFin || + CJK_ExtBIni <= $u && $u <= CJK_ExtBFin) + ? 0xFB80 # CJK ext. + : 0xFBC0; # others + + my $aaaa = $base + ($u >> 15); + my $bbbb = ($u & 0x7FFF) | 0x8000; + return + pack(VCE_TEMPLATE, NON_VAR, $aaaa, Min2Wt, Min3Wt, $u), + pack(VCE_TEMPLATE, NON_VAR, $bbbb, 0, 0, $u); +} + +sub _derivCE_9 { + my $u = shift; + my $base = + (CJK_UidIni <= $u && $u <= CJK_UidFin) + ? 0xFB40 : # CJK + (CJK_ExtAIni <= $u && $u <= CJK_ExtAFin || + CJK_ExtBIni <= $u && $u <= CJK_ExtBFin) + ? 0xFB80 # CJK ext. + : 0xFBC0; # others + + my $aaaa = $base + ($u >> 15); + my $bbbb = ($u & 0x7FFF) | 0x8000; + return + pack(VCE_TEMPLATE, NON_VAR, $aaaa, Min2Wt, Min3Wt, $u), + pack(VCE_TEMPLATE, NON_VAR, $bbbb, 0, 0, $u); +} + +sub _derivCE_8 { + my $code = shift; + my $aaaa = 0xFF80 + ($code >> 15); + my $bbbb = ($code & 0x7FFF) | 0x8000; + return + pack(VCE_TEMPLATE, NON_VAR, $aaaa, 2, 1, $code), + pack(VCE_TEMPLATE, NON_VAR, $bbbb, 0, 0, $code); +} + +sub _uideoCE_8 { + my $u = shift; + return pack(VCE_TEMPLATE, NON_VAR, $u, Min2Wt, Min3Wt, $u); +} + +sub _isUIdeo { + my ($u, $uca_vers) = @_; + return( + (CJK_UidIni <= $u && + ($uca_vers >= 14 ? ( $u <= CJK_UidF41) : ($u <= CJK_UidFin))) + || + (CJK_ExtAIni <= $u && $u <= CJK_ExtAFin) + || + (CJK_ExtBIni <= $u && $u <= CJK_ExtBFin) + ); +} + + +sub getWtHangulTerm { + my $self = shift; + return _varCE($self->{variable}, + pack(VCE_TEMPLATE, NON_VAR, $self->{hangul_terminator}, 0,0,0)); +} + + +## +## "hhhh hhhh hhhh" to (dddd, dddd, dddd) +## +sub _getHexArray { map hex, $_[0] =~ /([0-9a-fA-F]+)/g } + +# +# $code *must* be in Hangul syllable. +# Check it before you enter here. +# +sub _decompHangul { + my $code = shift; + my $si = $code - Hangul_SBase; + my $li = int( $si / Hangul_NCount); + my $vi = int(($si % Hangul_NCount) / Hangul_TCount); + my $ti = $si % Hangul_TCount; + return ( + Hangul_LBase + $li, + Hangul_VBase + $vi, + $ti ? (Hangul_TBase + $ti) : (), + ); +} + +sub _isIllegal { + my $code = shift; + return ! defined $code # removed + || ($code < 0 || 0x10FFFF < $code) # out of range + || (($code & 0xFFFE) == 0xFFFE) # ??FFF[EF] (cf. utf8.c) + || (0xD800 <= $code && $code <= 0xDFFF) # unpaired surrogates + || (0xFDD0 <= $code && $code <= 0xFDEF) # other non-characters + ; +} + +# Hangul Syllable Type +sub getHST { + my $u = shift; + return + Hangul_LIni <= $u && $u <= Hangul_LFin || $u == Hangul_LFill ? "L" : + Hangul_VIni <= $u && $u <= Hangul_VFin ? "V" : + Hangul_TIni <= $u && $u <= Hangul_TFin ? "T" : + Hangul_SIni <= $u && $u <= Hangul_SFin ? + ($u - Hangul_SBase) % Hangul_TCount ? "LVT" : "LV" : ""; +} + + +## +## bool _nonIgnorAtLevel(arrayref weights, int level) +## +sub _nonIgnorAtLevel($$) +{ + my $wt = shift; + return if ! defined $wt; + my $lv = shift; + return grep($wt->[$_-1] != 0, MinLevel..$lv) ? TRUE : FALSE; +} + +## +## bool _eqArray( +## arrayref of arrayref[weights] source, +## arrayref of arrayref[weights] substr, +## int level) +## * comparison of graphemes vs graphemes. +## @$source >= @$substr must be true (check it before call this); +## +sub _eqArray($$$) +{ + my $source = shift; + my $substr = shift; + my $lev = shift; + + for my $g (0..@$substr-1){ + # Do the $g'th graphemes have the same number of AV weigths? + return if @{ $source->[$g] } != @{ $substr->[$g] }; + + for my $w (0..@{ $substr->[$g] }-1) { + for my $v (0..$lev-1) { + return if $source->[$g][$w][$v] != $substr->[$g][$w][$v]; + } + } + } + return 1; +} + +## +## (int position, int length) +## int position = index(string, substring, position, [undoc'ed grobal]) +## +## With "grobal" (only for the list context), +## returns list of arrayref[position, length]. +## +sub index +{ + my $self = shift; + my $str = shift; + my $len = length($str); + my $subE = $self->splitEnt(shift); + my $pos = @_ ? shift : 0; + $pos = 0 if $pos < 0; + my $grob = shift; + + my $lev = $self->{level}; + my $v2i = $self->{UCA_Version} >= 9 && + $self->{variable} ne 'non-ignorable'; + + if (! @$subE) { + my $temp = $pos <= 0 ? 0 : $len <= $pos ? $len : $pos; + return $grob + ? map([$_, 0], $temp..$len) + : wantarray ? ($temp,0) : $temp; + } + $len < $pos + and return wantarray ? () : NOMATCHPOS; + my $strE = $self->splitEnt($pos ? substr($str, $pos) : $str, TRUE); + @$strE + or return wantarray ? () : NOMATCHPOS; + + my(@strWt, @iniPos, @finPos, @subWt, @g_ret); + + my $last_is_variable; + for my $vwt (map $self->getWt($_), @$subE) { + my($var, @wt) = unpack(VCE_TEMPLATE, $vwt); + my $to_be_pushed = _nonIgnorAtLevel(\@wt,$lev); + + # "Ignorable (L1, L2) after Variable" since track. v. 9 + if ($v2i) { + if ($var) { + $last_is_variable = TRUE; + } + elsif (!$wt[0]) { # ignorable + $to_be_pushed = FALSE if $last_is_variable; + } + else { + $last_is_variable = FALSE; + } + } + + if (@subWt && !$var && !$wt[0]) { + push @{ $subWt[-1] }, \@wt if $to_be_pushed; + } else { + push @subWt, [ \@wt ]; + } + } + + my $count = 0; + my $end = @$strE - 1; + + $last_is_variable = FALSE; # reuse + for (my $i = 0; $i <= $end; ) { # no $i++ + my $found_base = 0; + + # fetch a grapheme + while ($i <= $end && $found_base == 0) { + for my $vwt ($self->getWt($strE->[$i][0])) { + my($var, @wt) = unpack(VCE_TEMPLATE, $vwt); + my $to_be_pushed = _nonIgnorAtLevel(\@wt,$lev); + + # "Ignorable (L1, L2) after Variable" since track. v. 9 + if ($v2i) { + if ($var) { + $last_is_variable = TRUE; + } + elsif (!$wt[0]) { # ignorable + $to_be_pushed = FALSE if $last_is_variable; + } + else { + $last_is_variable = FALSE; + } + } + + if (@strWt && !$var && !$wt[0]) { + push @{ $strWt[-1] }, \@wt if $to_be_pushed; + $finPos[-1] = $strE->[$i][2]; + } elsif ($to_be_pushed) { + push @strWt, [ \@wt ]; + push @iniPos, $found_base ? NOMATCHPOS : $strE->[$i][1]; + $finPos[-1] = NOMATCHPOS if $found_base; + push @finPos, $strE->[$i][2]; + $found_base++; + } + # else ===> no-op + } + $i++; + } + + # try to match + while ( @strWt > @subWt || (@strWt == @subWt && $i > $end) ) { + if ($iniPos[0] != NOMATCHPOS && + $finPos[$#subWt] != NOMATCHPOS && + _eqArray(\@strWt, \@subWt, $lev)) { + my $temp = $iniPos[0] + $pos; + + if ($grob) { + push @g_ret, [$temp, $finPos[$#subWt] - $iniPos[0]]; + splice @strWt, 0, $#subWt; + splice @iniPos, 0, $#subWt; + splice @finPos, 0, $#subWt; + } + else { + return wantarray + ? ($temp, $finPos[$#subWt] - $iniPos[0]) + : $temp; + } + } + shift @strWt; + shift @iniPos; + shift @finPos; + } + } + + return $grob + ? @g_ret + : wantarray ? () : NOMATCHPOS; +} + +## +## scalarref to matching part = match(string, substring) +## +sub match +{ + my $self = shift; + if (my($pos,$len) = $self->index($_[0], $_[1])) { + my $temp = substr($_[0], $pos, $len); + return wantarray ? $temp : \$temp; + # An lvalue ref \substr should be avoided, + # since its value is affected by modification of its referent. + } + else { + return; + } +} + +## +## arrayref matching parts = gmatch(string, substring) +## +sub gmatch +{ + my $self = shift; + my $str = shift; + my $sub = shift; + return map substr($str, $_->[0], $_->[1]), + $self->index($str, $sub, 0, 'g'); +} + +## +## bool subst'ed = subst(string, substring, replace) +## +sub subst +{ + my $self = shift; + my $code = ref $_[2] eq 'CODE' ? $_[2] : FALSE; + + if (my($pos,$len) = $self->index($_[0], $_[1])) { + if ($code) { + my $mat = substr($_[0], $pos, $len); + substr($_[0], $pos, $len, $code->($mat)); + } else { + substr($_[0], $pos, $len, $_[2]); + } + return TRUE; + } + else { + return FALSE; + } +} + +## +## int count = gsubst(string, substring, replace) +## +sub gsubst +{ + my $self = shift; + my $code = ref $_[2] eq 'CODE' ? $_[2] : FALSE; + my $cnt = 0; + + # Replacement is carried out from the end, then use reverse. + for my $pos_len (reverse $self->index($_[0], $_[1], 0, 'g')) { + if ($code) { + my $mat = substr($_[0], $pos_len->[0], $pos_len->[1]); + substr($_[0], $pos_len->[0], $pos_len->[1], $code->($mat)); + } else { + substr($_[0], $pos_len->[0], $pos_len->[1], $_[2]); + } + $cnt++; + } + return $cnt; +} + +1; +__END__ + +=head1 NAME + +Unicode::Collate - Unicode Collation Algorithm + +=head1 SYNOPSIS + + use Unicode::Collate; + + #construct + $Collator = Unicode::Collate->new(%tailoring); + + #sort + @sorted = $Collator->sort(@not_sorted); + + #compare + $result = $Collator->cmp($a, $b); # returns 1, 0, or -1. + + # If %tailoring is false (i.e. empty), + # $Collator should do the default collation. + +=head1 DESCRIPTION + +This module is an implementation of Unicode Technical Standard #10 +(a.k.a. UTS #10) - Unicode Collation Algorithm (a.k.a. UCA). + +=head2 Constructor and Tailoring + +The C<new> method returns a collator object. + + $Collator = Unicode::Collate->new( + UCA_Version => $UCA_Version, + alternate => $alternate, # deprecated: use of 'variable' is recommended. + backwards => $levelNumber, # or \@levelNumbers + entry => $element, + hangul_terminator => $term_primary_weight, + ignoreName => qr/$ignoreName/, + ignoreChar => qr/$ignoreChar/, + katakana_before_hiragana => $bool, + level => $collationLevel, + normalization => $normalization_form, + overrideCJK => \&overrideCJK, + overrideHangul => \&overrideHangul, + preprocess => \&preprocess, + rearrange => \@charList, + table => $filename, + undefName => qr/$undefName/, + undefChar => qr/$undefChar/, + upper_before_lower => $bool, + variable => $variable, + ); + +=over 4 + +=item UCA_Version + +If the tracking version number of UCA is given, +behavior of that tracking version is emulated on collating. +If omitted, the return value of C<UCA_Version()> is used. +C<UCA_Version()> should return the latest tracking version supported. + +The supported tracking version: 8, 9, 11, or 14. + + UCA Unicode Standard DUCET (@version) + --------------------------------------------------- + 8 3.1 3.0.1 (3.0.1d9) + 9 3.1 with Corrigendum 3 3.1.1 (3.1.1) + 11 4.0 4.0.0 (4.0.0) + 14 4.1.0 4.1.0 (4.1.0) + +Note: Recent UTS #10 renames "Tracking Version" to "Revision." + +=item alternate + +-- see 3.2.2 Alternate Weighting, version 8 of UTS #10 + +For backward compatibility, C<alternate> (old name) can be used +as an alias for C<variable>. + +=item backwards + +-- see 3.1.2 French Accents, UTS #10. + + backwards => $levelNumber or \@levelNumbers + +Weights in reverse order; ex. level 2 (diacritic ordering) in French. +If omitted, forwards at all the levels. + +=item entry + +-- see 3.1 Linguistic Features; 3.2.1 File Format, UTS #10. + +If the same character (or a sequence of characters) exists +in the collation element table through C<table>, +mapping to collation elements is overrided. +If it does not exist, the mapping is defined additionally. + + entry => <<'ENTRY', # for DUCET v4.0.0 (allkeys-4.0.0.txt) +0063 0068 ; [.0E6A.0020.0002.0063] # ch +0043 0068 ; [.0E6A.0020.0007.0043] # Ch +0043 0048 ; [.0E6A.0020.0008.0043] # CH +006C 006C ; [.0F4C.0020.0002.006C] # ll +004C 006C ; [.0F4C.0020.0007.004C] # Ll +004C 004C ; [.0F4C.0020.0008.004C] # LL +00F1 ; [.0F7B.0020.0002.00F1] # n-tilde +006E 0303 ; [.0F7B.0020.0002.00F1] # n-tilde +00D1 ; [.0F7B.0020.0008.00D1] # N-tilde +004E 0303 ; [.0F7B.0020.0008.00D1] # N-tilde +ENTRY + + entry => <<'ENTRY', # for DUCET v4.0.0 (allkeys-4.0.0.txt) +00E6 ; [.0E33.0020.0002.00E6][.0E8B.0020.0002.00E6] # ae ligature as <a><e> +00C6 ; [.0E33.0020.0008.00C6][.0E8B.0020.0008.00C6] # AE ligature as <A><E> +ENTRY + +B<NOTE:> The code point in the UCA file format (before C<';'>) +B<must> be a Unicode code point (defined as hexadecimal), +but not a native code point. +So C<0063> must always denote C<U+0063>, +but not a character of C<"\x63">. + +Weighting may vary depending on collation element table. +So ensure the weights defined in C<entry> will be consistent with +those in the collation element table loaded via C<table>. + +In DUCET v4.0.0, primary weight of C<C> is C<0E60> +and that of C<D> is C<0E6D>. So setting primary weight of C<CH> to C<0E6A> +(as a value between C<0E60> and C<0E6D>) +makes ordering as C<C E<lt> CH E<lt> D>. +Exactly speaking DUCET already has some characters between C<C> and C<D>: +C<small capital C> (C<U+1D04>) with primary weight C<0E64>, +C<c-hook/C-hook> (C<U+0188/U+0187>) with C<0E65>, +and C<c-curl> (C<U+0255>) with C<0E69>. +Then primary weight C<0E6A> for C<CH> makes C<CH> +ordered between C<c-curl> and C<D>. + +=item hangul_terminator + +-- see 7.1.4 Trailing Weights, UTS #10. + +If a true value is given (non-zero but should be positive), +it will be added as a terminator primary weight to the end of +every standard Hangul syllable. Secondary and any higher weights +for terminator are set to zero. +If the value is false or C<hangul_terminator> key does not exist, +insertion of terminator weights will not be performed. + +Boundaries of Hangul syllables are determined +according to conjoining Jamo behavior in F<the Unicode Standard> +and F<HangulSyllableType.txt>. + +B<Implementation Note:> +(1) For expansion mapping (Unicode character mapped +to a sequence of collation elements), a terminator will not be added +between collation elements, even if Hangul syllable boundary exists there. +Addition of terminator is restricted to the next position +to the last collation element. + +(2) Non-conjoining Hangul letters +(Compatibility Jamo, halfwidth Jamo, and enclosed letters) are not +automatically terminated with a terminator primary weight. +These characters may need terminator included in a collation element +table beforehand. + +=item ignoreChar + +=item ignoreName + +-- see 3.2.2 Variable Weighting, UTS #10. + +Makes the entry in the table completely ignorable; +i.e. as if the weights were zero at all level. + +Through C<ignoreChar>, any character matching C<qr/$ignoreChar/> +will be ignored. Through C<ignoreName>, any character whose name +(given in the C<table> file as a comment) matches C<qr/$ignoreName/> +will be ignored. + +E.g. when 'a' and 'e' are ignorable, +'element' is equal to 'lament' (or 'lmnt'). + +=item katakana_before_hiragana + +-- see 7.3.1 Tertiary Weight Table, UTS #10. + +By default, hiragana is before katakana. +If the parameter is made true, this is reversed. + +B<NOTE>: This parameter simplemindedly assumes that any hiragana/katakana +distinctions must occur in level 3, and their weights at level 3 must be +same as those mentioned in 7.3.1, UTS #10. +If you define your collation elements which violate this requirement, +this parameter does not work validly. + +=item level + +-- see 4.3 Form Sort Key, UTS #10. + +Set the maximum level. +Any higher levels than the specified one are ignored. + + Level 1: alphabetic ordering + Level 2: diacritic ordering + Level 3: case ordering + Level 4: tie-breaking (e.g. in the case when variable is 'shifted') + + ex.level => 2, + +If omitted, the maximum is the 4th. + +=item normalization + +-- see 4.1 Normalize, UTS #10. + +If specified, strings are normalized before preparation of sort keys +(the normalization is executed after preprocess). + +A form name C<Unicode::Normalize::normalize()> accepts will be applied +as C<$normalization_form>. +Acceptable names include C<'NFD'>, C<'NFC'>, C<'NFKD'>, and C<'NFKC'>. +See C<Unicode::Normalize::normalize()> for detail. +If omitted, C<'NFD'> is used. + +C<normalization> is performed after C<preprocess> (if defined). + +Furthermore, special values, C<undef> and C<"prenormalized">, can be used, +though they are not concerned with C<Unicode::Normalize::normalize()>. + +If C<undef> (not a string C<"undef">) is passed explicitly +as the value for this key, +any normalization is not carried out (this may make tailoring easier +if any normalization is not desired). Under C<(normalization =E<gt> undef)>, +only contiguous contractions are resolved; +e.g. even if C<A-ring> (and C<A-ring-cedilla>) is ordered after C<Z>, +C<A-cedilla-ring> would be primary equal to C<A>. +In this point, +C<(normalization =E<gt> undef, preprocess =E<gt> sub { NFD(shift) })> +B<is not> equivalent to C<(normalization =E<gt> 'NFD')>. + +In the case of C<(normalization =E<gt> "prenormalized")>, +any normalization is not performed, but +non-contiguous contractions with combining characters are performed. +Therefore +C<(normalization =E<gt> 'prenormalized', preprocess =E<gt> sub { NFD(shift) })> +B<is> equivalent to C<(normalization =E<gt> 'NFD')>. +If source strings are finely prenormalized, +C<(normalization =E<gt> 'prenormalized')> may save time for normalization. + +Except C<(normalization =E<gt> undef)>, +B<Unicode::Normalize> is required (see also B<CAVEAT>). + +=item overrideCJK + +-- see 7.1 Derived Collation Elements, UTS #10. + +By default, CJK Unified Ideographs are ordered in Unicode codepoint order +but C<CJK Unified Ideographs> (if C<UCA_Version> is 8 to 11, its range is +C<U+4E00..U+9FA5>; if C<UCA_Version> is 14, its range is C<U+4E00..U+9FBB>) +are lesser than C<CJK Unified Ideographs Extension> (its range is +C<U+3400..U+4DB5> and C<U+20000..U+2A6D6>). + +Through C<overrideCJK>, ordering of CJK Unified Ideographs can be overrided. + +ex. CJK Unified Ideographs in the JIS code point order. + + overrideCJK => sub { + my $u = shift; # get a Unicode codepoint + my $b = pack('n', $u); # to UTF-16BE + my $s = your_unicode_to_sjis_converter($b); # convert + my $n = unpack('n', $s); # convert sjis to short + [ $n, 0x20, 0x2, $u ]; # return the collation element + }, + +ex. ignores all CJK Unified Ideographs. + + overrideCJK => sub {()}, # CODEREF returning empty list + + # where ->eq("Pe\x{4E00}rl", "Perl") is true + # as U+4E00 is a CJK Unified Ideograph and to be ignorable. + +If C<undef> is passed explicitly as the value for this key, +weights for CJK Unified Ideographs are treated as undefined. +But assignment of weight for CJK Unified Ideographs +in table or C<entry> is still valid. + +=item overrideHangul + +-- see 7.1 Derived Collation Elements, UTS #10. + +By default, Hangul Syllables are decomposed into Hangul Jamo, +even if C<(normalization =E<gt> undef)>. +But the mapping of Hangul Syllables may be overrided. + +This parameter works like C<overrideCJK>, so see there for examples. + +If you want to override the mapping of Hangul Syllables, +NFD, NFKD, and FCD are not appropriate, +since they will decompose Hangul Syllables before overriding. + +If C<undef> is passed explicitly as the value for this key, +weight for Hangul Syllables is treated as undefined +without decomposition into Hangul Jamo. +But definition of weight for Hangul Syllables +in table or C<entry> is still valid. + +=item preprocess + +-- see 5.1 Preprocessing, UTS #10. + +If specified, the coderef is used to preprocess +before the formation of sort keys. + +ex. dropping English articles, such as "a" or "the". +Then, "the pen" is before "a pencil". + + preprocess => sub { + my $str = shift; + $str =~ s/\b(?:an?|the)\s+//gi; + return $str; + }, + +C<preprocess> is performed before C<normalization> (if defined). + +=item rearrange + +-- see 3.1.3 Rearrangement, UTS #10. + +Characters that are not coded in logical order and to be rearranged. +If C<UCA_Version> is equal to or lesser than 11, default is: + + rearrange => [ 0x0E40..0x0E44, 0x0EC0..0x0EC4 ], + +If you want to disallow any rearrangement, pass C<undef> or C<[]> +(a reference to empty list) as the value for this key. + +If C<UCA_Version> is equal to 14, default is C<[]> (i.e. no rearrangement). + +B<According to the version 9 of UCA, this parameter shall not be used; +but it is not warned at present.> + +=item table + +-- see 3.2 Default Unicode Collation Element Table, UTS #10. + +You can use another collation element table if desired. + +The table file should locate in the F<Unicode/Collate> directory +on C<@INC>. Say, if the filename is F<Foo.txt>, +the table file is searched as F<Unicode/Collate/Foo.txt> in C<@INC>. + +By default, F<allkeys.txt> (as the filename of DUCET) is used. +If you will prepare your own table file, any name other than F<allkeys.txt> +may be better to avoid namespace conflict. + +If C<undef> is passed explicitly as the value for this key, +no file is read (but you can define collation elements via C<entry>). + +A typical way to define a collation element table +without any file of table: + + $onlyABC = Unicode::Collate->new( + table => undef, + entry => << 'ENTRIES', +0061 ; [.0101.0020.0002.0061] # LATIN SMALL LETTER A +0041 ; [.0101.0020.0008.0041] # LATIN CAPITAL LETTER A +0062 ; [.0102.0020.0002.0062] # LATIN SMALL LETTER B +0042 ; [.0102.0020.0008.0042] # LATIN CAPITAL LETTER B +0063 ; [.0103.0020.0002.0063] # LATIN SMALL LETTER C +0043 ; [.0103.0020.0008.0043] # LATIN CAPITAL LETTER C +ENTRIES + ); + +If C<ignoreName> or C<undefName> is used, character names should be +specified as a comment (following C<#>) on each line. + +=item undefChar + +=item undefName + +-- see 6.3.4 Reducing the Repertoire, UTS #10. + +Undefines the collation element as if it were unassigned in the table. +This reduces the size of the table. +If an unassigned character appears in the string to be collated, +the sort key is made from its codepoint +as a single-character collation element, +as it is greater than any other assigned collation elements +(in the codepoint order among the unassigned characters). +But, it'd be better to ignore characters +unfamiliar to you and maybe never used. + +Through C<undefChar>, any character matching C<qr/$undefChar/> +will be undefined. Through C<undefName>, any character whose name +(given in the C<table> file as a comment) matches C<qr/$undefName/> +will be undefined. + +ex. Collation weights for beyond-BMP characters are not stored in object: + + undefChar => qr/[^\0-\x{fffd}]/, + +=item upper_before_lower + +-- see 6.6 Case Comparisons, UTS #10. + +By default, lowercase is before uppercase. +If the parameter is made true, this is reversed. + +B<NOTE>: This parameter simplemindedly assumes that any lowercase/uppercase +distinctions must occur in level 3, and their weights at level 3 must be +same as those mentioned in 7.3.1, UTS #10. +If you define your collation elements which differs from this requirement, +this parameter doesn't work validly. + +=item variable + +-- see 3.2.2 Variable Weighting, UTS #10. + +This key allows to variable weighting for variable collation elements, +which are marked with an ASTERISK in the table +(NOTE: Many punction marks and symbols are variable in F<allkeys.txt>). + + variable => 'blanked', 'non-ignorable', 'shifted', or 'shift-trimmed'. + +These names are case-insensitive. +By default (if specification is omitted), 'shifted' is adopted. + + 'Blanked' Variable elements are made ignorable at levels 1 through 3; + considered at the 4th level. + + 'Non-Ignorable' Variable elements are not reset to ignorable. + + 'Shifted' Variable elements are made ignorable at levels 1 through 3 + their level 4 weight is replaced by the old level 1 weight. + Level 4 weight for Non-Variable elements is 0xFFFF. + + 'Shift-Trimmed' Same as 'shifted', but all FFFF's at the 4th level + are trimmed. + +=back + +=head2 Methods for Collation + +=over 4 + +=item C<@sorted = $Collator-E<gt>sort(@not_sorted)> + +Sorts a list of strings. + +=item C<$result = $Collator-E<gt>cmp($a, $b)> + +Returns 1 (when C<$a> is greater than C<$b>) +or 0 (when C<$a> is equal to C<$b>) +or -1 (when C<$a> is lesser than C<$b>). + +=item C<$result = $Collator-E<gt>eq($a, $b)> + +=item C<$result = $Collator-E<gt>ne($a, $b)> + +=item C<$result = $Collator-E<gt>lt($a, $b)> + +=item C<$result = $Collator-E<gt>le($a, $b)> + +=item C<$result = $Collator-E<gt>gt($a, $b)> + +=item C<$result = $Collator-E<gt>ge($a, $b)> + +They works like the same name operators as theirs. + + eq : whether $a is equal to $b. + ne : whether $a is not equal to $b. + lt : whether $a is lesser than $b. + le : whether $a is lesser than $b or equal to $b. + gt : whether $a is greater than $b. + ge : whether $a is greater than $b or equal to $b. + +=item C<$sortKey = $Collator-E<gt>getSortKey($string)> + +-- see 4.3 Form Sort Key, UTS #10. + +Returns a sort key. + +You compare the sort keys using a binary comparison +and get the result of the comparison of the strings using UCA. + + $Collator->getSortKey($a) cmp $Collator->getSortKey($b) + + is equivalent to + + $Collator->cmp($a, $b) + +=item C<$sortKeyForm = $Collator-E<gt>viewSortKey($string)> + +Converts a sorting key into its representation form. +If C<UCA_Version> is 8, the output is slightly different. + + use Unicode::Collate; + my $c = Unicode::Collate->new(); + print $c->viewSortKey("Perl"),"\n"; + + # output: + # [0B67 0A65 0B7F 0B03 | 0020 0020 0020 0020 | 0008 0002 0002 0002 | FFFF FFFF FFFF FFFF] + # Level 1 Level 2 Level 3 Level 4 + +=back + +=head2 Methods for Searching + +B<DISCLAIMER:> If C<preprocess> or C<normalization> parameter is true +for C<$Collator>, calling these methods (C<index>, C<match>, C<gmatch>, +C<subst>, C<gsubst>) is croaked, +as the position and the length might differ +from those on the specified string. +(And C<rearrange> and C<hangul_terminator> parameters are neglected.) + +The C<match>, C<gmatch>, C<subst>, C<gsubst> methods work +like C<m//>, C<m//g>, C<s///>, C<s///g>, respectively, +but they are not aware of any pattern, but only a literal substring. + +=over 4 + +=item C<$position = $Collator-E<gt>index($string, $substring[, $position])> + +=item C<($position, $length) = $Collator-E<gt>index($string, $substring[, $position])> + +If C<$substring> matches a part of C<$string>, returns +the position of the first occurrence of the matching part in scalar context; +in list context, returns a two-element list of +the position and the length of the matching part. + +If C<$substring> does not match any part of C<$string>, +returns C<-1> in scalar context and +an empty list in list context. + +e.g. you say + + my $Collator = Unicode::Collate->new( normalization => undef, level => 1 ); + # (normalization => undef) is REQUIRED. + my $str = "Ich muß studieren Perl."; + my $sub = "MÜSS"; + my $match; + if (my($pos,$len) = $Collator->index($str, $sub)) { + $match = substr($str, $pos, $len); + } + +and get C<"muß"> in C<$match> since C<"muß"> +is primary equal to C<"MÜSS">. + +=item C<$match_ref = $Collator-E<gt>match($string, $substring)> + +=item C<($match) = $Collator-E<gt>match($string, $substring)> + +If C<$substring> matches a part of C<$string>, in scalar context, returns +B<a reference to> the first occurrence of the matching part +(C<$match_ref> is always true if matches, +since every reference is B<true>); +in list context, returns the first occurrence of the matching part. + +If C<$substring> does not match any part of C<$string>, +returns C<undef> in scalar context and +an empty list in list context. + +e.g. + + if ($match_ref = $Collator->match($str, $sub)) { # scalar context + print "matches [$$match_ref].\n"; + } else { + print "doesn't match.\n"; + } + + or + + if (($match) = $Collator->match($str, $sub)) { # list context + print "matches [$match].\n"; + } else { + print "doesn't match.\n"; + } + +=item C<@match = $Collator-E<gt>gmatch($string, $substring)> + +If C<$substring> matches a part of C<$string>, returns +all the matching parts (or matching count in scalar context). + +If C<$substring> does not match any part of C<$string>, +returns an empty list. + +=item C<$count = $Collator-E<gt>subst($string, $substring, $replacement)> + +If C<$substring> matches a part of C<$string>, +the first occurrence of the matching part is replaced by C<$replacement> +(C<$string> is modified) and return C<$count> (always equals to C<1>). + +C<$replacement> can be a C<CODEREF>, +taking the matching part as an argument, +and returning a string to replace the matching part +(a bit similar to C<s/(..)/$coderef-E<gt>($1)/e>). + +=item C<$count = $Collator-E<gt>gsubst($string, $substring, $replacement)> + +If C<$substring> matches a part of C<$string>, +all the occurrences of the matching part is replaced by C<$replacement> +(C<$string> is modified) and return C<$count>. + +C<$replacement> can be a C<CODEREF>, +taking the matching part as an argument, +and returning a string to replace the matching part +(a bit similar to C<s/(..)/$coderef-E<gt>($1)/eg>). + +e.g. + + my $Collator = Unicode::Collate->new( normalization => undef, level => 1 ); + # (normalization => undef) is REQUIRED. + my $str = "Camel donkey zebra came\x{301}l CAMEL horse cAm\0E\0L..."; + $Collator->gsubst($str, "camel", sub { "<b>$_[0]</b>" }); + + # now $str is "<b>Camel</b> donkey zebra <b>came\x{301}l</b> <b>CAMEL</b> horse <b>cAm\0E\0L</b>..."; + # i.e., all the camels are made bold-faced. + +=back + +=head2 Other Methods + +=over 4 + +=item C<%old_tailoring = $Collator-E<gt>change(%new_tailoring)> + +Change the value of specified keys and returns the changed part. + + $Collator = Unicode::Collate->new(level => 4); + + $Collator->eq("perl", "PERL"); # false + + %old = $Collator->change(level => 2); # returns (level => 4). + + $Collator->eq("perl", "PERL"); # true + + $Collator->change(%old); # returns (level => 2). + + $Collator->eq("perl", "PERL"); # false + +Not all C<(key,value)>s are allowed to be changed. +See also C<@Unicode::Collate::ChangeOK> and C<@Unicode::Collate::ChangeNG>. + +In the scalar context, returns the modified collator +(but it is B<not> a clone from the original). + + $Collator->change(level => 2)->eq("perl", "PERL"); # true + + $Collator->eq("perl", "PERL"); # true; now max level is 2nd. + + $Collator->change(level => 4)->eq("perl", "PERL"); # false + +=item C<$version = $Collator-E<gt>version()> + +Returns the version number (a string) of the Unicode Standard +which the C<table> file used by the collator object is based on. +If the table does not include a version line (starting with C<@version>), +returns C<"unknown">. + +=item C<UCA_Version()> + +Returns the tracking version number of UTS #10 this module consults. + +=item C<Base_Unicode_Version()> + +Returns the version number of UTS #10 this module consults. + +=back + +=head1 EXPORT + +No method will be exported. + +=head1 INSTALL + +Though this module can be used without any C<table> file, +to use this module easily, it is recommended to install a table file +in the UCA format, by copying it under the directory +<a place in @INC>/Unicode/Collate. + +The most preferable one is "The Default Unicode Collation Element Table" +(aka DUCET), available from the Unicode Consortium's website: + + http://www.unicode.org/Public/UCA/ + + http://www.unicode.org/Public/UCA/latest/allkeys.txt (latest version) + +If DUCET is not installed, it is recommended to copy the file +from http://www.unicode.org/Public/UCA/latest/allkeys.txt +to <a place in @INC>/Unicode/Collate/allkeys.txt +manually. + +=head1 CAVEATS + +=over 4 + +=item Normalization + +Use of the C<normalization> parameter requires the B<Unicode::Normalize> +module (see L<Unicode::Normalize>). + +If you need not it (say, in the case when you need not +handle any combining characters), +assign C<normalization =E<gt> undef> explicitly. + +-- see 6.5 Avoiding Normalization, UTS #10. + +=item Conformance Test + +The Conformance Test for the UCA is available +under L<http://www.unicode.org/Public/UCA/>. + +For F<CollationTest_SHIFTED.txt>, +a collator via C<Unicode::Collate-E<gt>new( )> should be used; +for F<CollationTest_NON_IGNORABLE.txt>, a collator via +C<Unicode::Collate-E<gt>new(variable =E<gt> "non-ignorable", level =E<gt> 3)>. + +B<Unicode::Normalize is required to try The Conformance Test.> + +=back + +=head1 AUTHOR, COPYRIGHT AND LICENSE + +The Unicode::Collate module for perl was written by SADAHIRO Tomoyuki, +<SADAHIRO@cpan.org>. This module is Copyright(C) 2001-2005, +SADAHIRO Tomoyuki. Japan. All rights reserved. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +The file Unicode/Collate/allkeys.txt was copied directly +from L<http://www.unicode.org/Public/UCA/4.1.0/allkeys.txt>. +This file is Copyright (c) 1991-2005 Unicode, Inc. All rights reserved. +Distributed under the Terms of Use in L<http://www.unicode.org/copyright.html>. + +=head1 SEE ALSO + +=over 4 + +=item Unicode Collation Algorithm - UTS #10 + +L<http://www.unicode.org/reports/tr10/> + +=item The Default Unicode Collation Element Table (DUCET) + +L<http://www.unicode.org/Public/UCA/latest/allkeys.txt> + +=item The conformance test for the UCA + +L<http://www.unicode.org/Public/UCA/latest/CollationTest.html> + +L<http://www.unicode.org/Public/UCA/latest/CollationTest.zip> + +=item Hangul Syllable Type + +L<http://www.unicode.org/Public/UNIDATA/HangulSyllableType.txt> + +=item Unicode Normalization Forms - UAX #15 + +L<http://www.unicode.org/reports/tr15/> + +=back + +=cut diff --git a/Master/tlpkg/tlperl/lib/Unicode/Collate/allkeys.txt b/Master/tlpkg/tlperl/lib/Unicode/Collate/allkeys.txt new file mode 100644 index 00000000000..f4c63f890c1 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Unicode/Collate/allkeys.txt @@ -0,0 +1,18191 @@ +# allkeys-5.0.0.txt +# Date: 2006-06-09, 15:29:02 PDT [KW] +# +# This file defines the Default Unicode Collation Element Table +# (DUCET) for the Unicode Collation Algorithm +# +# Copyright (c) 2001-2006 Unicode, Inc. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# See UTS #10, Unicode Collation Algorithm, for more information. +# +# Diagnostic weight ranges +# Primary weight range: 0200..2D56 (11095) +# Secondary weight range: 0020..01BF (416) +# Variant secondaries: 0199..019E (6) +# Digit secondaries: 019F..01BF (33) +# Tertiary weight range: 0002..001F (30) +# +@version 5.0.0 + +0000 ; [.0000.0000.0000.0000] # [0000] NULL (in 6429) +0001 ; [.0000.0000.0000.0000] # [0001] START OF HEADING (in 6429) +0002 ; [.0000.0000.0000.0000] # [0002] START OF TEXT (in 6429) +0003 ; [.0000.0000.0000.0000] # [0003] END OF TEXT (in 6429) +0004 ; [.0000.0000.0000.0000] # [0004] END OF TRANSMISSION (in 6429) +0005 ; [.0000.0000.0000.0000] # [0005] ENQUIRY (in 6429) +0006 ; [.0000.0000.0000.0000] # [0006] ACKNOWLEDGE (in 6429) +0007 ; [.0000.0000.0000.0000] # [0007] BELL (in 6429) +0008 ; [.0000.0000.0000.0000] # [0008] BACKSPACE (in 6429) +000E ; [.0000.0000.0000.0000] # [000E] SHIFT OUT (in 6429) +000F ; [.0000.0000.0000.0000] # [000F] SHIFT IN (in 6429) +0010 ; [.0000.0000.0000.0000] # [0010] DATA LINK ESCAPE (in 6429) +0011 ; [.0000.0000.0000.0000] # [0011] DEVICE CONTROL ONE (in 6429) +0012 ; [.0000.0000.0000.0000] # [0012] DEVICE CONTROL TWO (in 6429) +0013 ; [.0000.0000.0000.0000] # [0013] DEVICE CONTROL THREE (in 6429) +0014 ; [.0000.0000.0000.0000] # [0014] DEVICE CONTROL FOUR (in 6429) +0015 ; [.0000.0000.0000.0000] # [0015] NEGATIVE ACKNOWLEDGE (in 6429) +0016 ; [.0000.0000.0000.0000] # [0016] SYNCHRONOUS IDLE (in 6429) +0017 ; [.0000.0000.0000.0000] # [0017] END OF TRANSMISSION BLOCK (in 6429) +0018 ; [.0000.0000.0000.0000] # [0018] CANCEL (in 6429) +0019 ; [.0000.0000.0000.0000] # [0019] END OF MEDIUM (in 6429) +001A ; [.0000.0000.0000.0000] # [001A] SUBSTITUTE (in 6429) +001B ; [.0000.0000.0000.0000] # [001B] ESCAPE (in 6429) +001C ; [.0000.0000.0000.0000] # [001C] FILE SEPARATOR (in 6429) +001D ; [.0000.0000.0000.0000] # [001D] GROUP SEPARATOR (in 6429) +001E ; [.0000.0000.0000.0000] # [001E] RECORD SEPARATOR (in 6429) +001F ; [.0000.0000.0000.0000] # [001F] UNIT SEPARATOR (in 6429) +007F ; [.0000.0000.0000.0000] # [007F] DELETE (in 6429) +0080 ; [.0000.0000.0000.0000] # [0080] <control> +0081 ; [.0000.0000.0000.0000] # [0081] <control> +0082 ; [.0000.0000.0000.0000] # [0082] BREAK PERMITTED HERE (in 6429) +0083 ; [.0000.0000.0000.0000] # [0083] NO BREAK HERE (in 6429) +0084 ; [.0000.0000.0000.0000] # [0084] <control> +0086 ; [.0000.0000.0000.0000] # [0086] START OF SELECTED AREA (in 6429) +0087 ; [.0000.0000.0000.0000] # [0087] END OF SELECTED AREA (in 6429) +0088 ; [.0000.0000.0000.0000] # [0088] CHARACTER TABULATION SET (in 6429) +0089 ; [.0000.0000.0000.0000] # [0089] CHARACTER TABULATION WITH JUSTIFICATION (in 6429) +008A ; [.0000.0000.0000.0000] # [008A] LINE TABULATION SET (in 6429) +008B ; [.0000.0000.0000.0000] # [008B] PARTIAL LINE FORWARD (in 6429) +008C ; [.0000.0000.0000.0000] # [008C] PARTIAL LINE BACKWARD (in 6429) +008D ; [.0000.0000.0000.0000] # [008D] PARTIAL LINE FEED (in 6429) +008E ; [.0000.0000.0000.0000] # [008E] SINGLE SHIFT TWO (in 6429) +008F ; [.0000.0000.0000.0000] # [008F] SINGLE SHIFT THREE (in 6429) +0090 ; [.0000.0000.0000.0000] # [0090] DEVICE CONTROL STRING (in 6429) +0091 ; [.0000.0000.0000.0000] # [0091] PRIVATE USE ONE (in 6429) +0092 ; [.0000.0000.0000.0000] # [0092] PRIVATE USE TWO (in 6429) +0093 ; [.0000.0000.0000.0000] # [0093] SET TRANSMIT STATE (in 6429) +0094 ; [.0000.0000.0000.0000] # [0094] CANCEL CHARACTER (in 6429) +0095 ; [.0000.0000.0000.0000] # [0095] MESSAGE WAITING (in 6429) +0096 ; [.0000.0000.0000.0000] # [0096] START OF GUARDED AREA (in 6429) +0097 ; [.0000.0000.0000.0000] # [0097] END OF GUARDED AREA (in 6429) +0098 ; [.0000.0000.0000.0000] # [0098] START OF STRING (in 6429) +0099 ; [.0000.0000.0000.0000] # [0099] <control> +009A ; [.0000.0000.0000.0000] # [009A] SINGLE CHARACTER INTRODUCER (in 6429) +009B ; [.0000.0000.0000.0000] # [009B] CONTROL SEQUENCE INTRODUCER (in 6429) +009C ; [.0000.0000.0000.0000] # [009C] STRING TERMINATOR (in 6429) +009D ; [.0000.0000.0000.0000] # [009D] OPERATING SYSTEM COMMAND (in 6429) +009E ; [.0000.0000.0000.0000] # [009E] PRIVACY MESSAGE (in 6429) +009F ; [.0000.0000.0000.0000] # [009F] APPLICATION PROGRAM COMMAND (in 6429) +070F ; [.0000.0000.0000.0000] # [070F] SYRIAC ABBREVIATION MARK +180B ; [.0000.0000.0000.0000] # [180B] MONGOLIAN FREE VARIATION SELECTOR ONE +180C ; [.0000.0000.0000.0000] # [180C] MONGOLIAN FREE VARIATION SELECTOR TWO +180D ; [.0000.0000.0000.0000] # [180D] MONGOLIAN FREE VARIATION SELECTOR THREE +180E ; [.0000.0000.0000.0000] # [180E] MONGOLIAN VOWEL SEPARATOR +200B ; [.0000.0000.0000.0000] # [200B] ZERO WIDTH SPACE +200C ; [.0000.0000.0000.0000] # [200C] ZERO WIDTH NON-JOINER +200D ; [.0000.0000.0000.0000] # [200D] ZERO WIDTH JOINER +200E ; [.0000.0000.0000.0000] # [200E] LEFT-TO-RIGHT MARK +200F ; [.0000.0000.0000.0000] # [200F] RIGHT-TO-LEFT MARK +202A ; [.0000.0000.0000.0000] # [202A] LEFT-TO-RIGHT EMBEDDING +202B ; [.0000.0000.0000.0000] # [202B] RIGHT-TO-LEFT EMBEDDING +202C ; [.0000.0000.0000.0000] # [202C] POP DIRECTIONAL FORMATTING +202D ; [.0000.0000.0000.0000] # [202D] LEFT-TO-RIGHT OVERRIDE +202E ; [.0000.0000.0000.0000] # [202E] RIGHT-TO-LEFT OVERRIDE +2060 ; [.0000.0000.0000.0000] # [2060] WORD JOINER +206A ; [.0000.0000.0000.0000] # [206A] INHIBIT SYMMETRIC SWAPPING +206B ; [.0000.0000.0000.0000] # [206B] ACTIVATE SYMMETRIC SWAPPING +206C ; [.0000.0000.0000.0000] # [206C] INHIBIT ARABIC FORM SHAPING +206D ; [.0000.0000.0000.0000] # [206D] ACTIVATE ARABIC FORM SHAPING +206E ; [.0000.0000.0000.0000] # [206E] NATIONAL DIGIT SHAPES +206F ; [.0000.0000.0000.0000] # [206F] NOMINAL DIGIT SHAPES +FE00 ; [.0000.0000.0000.0000] # [FE00] VARIATION SELECTOR-1 +FE01 ; [.0000.0000.0000.0000] # [FE01] VARIATION SELECTOR-2 +FE02 ; [.0000.0000.0000.0000] # [FE02] VARIATION SELECTOR-3 +FE03 ; [.0000.0000.0000.0000] # [FE03] VARIATION SELECTOR-4 +FE04 ; [.0000.0000.0000.0000] # [FE04] VARIATION SELECTOR-5 +FE05 ; [.0000.0000.0000.0000] # [FE05] VARIATION SELECTOR-6 +FE06 ; [.0000.0000.0000.0000] # [FE06] VARIATION SELECTOR-7 +FE07 ; [.0000.0000.0000.0000] # [FE07] VARIATION SELECTOR-8 +FE08 ; [.0000.0000.0000.0000] # [FE08] VARIATION SELECTOR-9 +FE09 ; [.0000.0000.0000.0000] # [FE09] VARIATION SELECTOR-10 +FE0A ; [.0000.0000.0000.0000] # [FE0A] VARIATION SELECTOR-11 +FE0B ; [.0000.0000.0000.0000] # [FE0B] VARIATION SELECTOR-12 +FE0C ; [.0000.0000.0000.0000] # [FE0C] VARIATION SELECTOR-13 +FE0D ; [.0000.0000.0000.0000] # [FE0D] VARIATION SELECTOR-14 +FE0E ; [.0000.0000.0000.0000] # [FE0E] VARIATION SELECTOR-15 +FE0F ; [.0000.0000.0000.0000] # [FE0F] VARIATION SELECTOR-16 +FEFF ; [.0000.0000.0000.0000] # [FEFF] ZERO WIDTH NO-BREAK SPACE +FFF9 ; [.0000.0000.0000.0000] # [FFF9] INTERLINEAR ANNOTATION ANCHOR +FFFA ; [.0000.0000.0000.0000] # [FFFA] INTERLINEAR ANNOTATION SEPARATOR +FFFB ; [.0000.0000.0000.0000] # [FFFB] INTERLINEAR ANNOTATION TERMINATOR +1D173 ; [.0000.0000.0000.0000] # [1D173] MUSICAL SYMBOL BEGIN BEAM +1D174 ; [.0000.0000.0000.0000] # [1D174] MUSICAL SYMBOL END BEAM +1D175 ; [.0000.0000.0000.0000] # [1D175] MUSICAL SYMBOL BEGIN TIE +1D176 ; [.0000.0000.0000.0000] # [1D176] MUSICAL SYMBOL END TIE +1D177 ; [.0000.0000.0000.0000] # [1D177] MUSICAL SYMBOL BEGIN SLUR +1D178 ; [.0000.0000.0000.0000] # [1D178] MUSICAL SYMBOL END SLUR +1D179 ; [.0000.0000.0000.0000] # [1D179] MUSICAL SYMBOL BEGIN PHRASE +1D17A ; [.0000.0000.0000.0000] # [1D17A] MUSICAL SYMBOL END PHRASE +E0001 ; [.0000.0000.0000.0000] # [E0001] LANGUAGE TAG +E0020 ; [.0000.0000.0000.0000] # [E0020] TAG SPACE +E0021 ; [.0000.0000.0000.0000] # [E0021] TAG EXCLAMATION MARK +E0022 ; [.0000.0000.0000.0000] # [E0022] TAG QUOTATION MARK +E0023 ; [.0000.0000.0000.0000] # [E0023] TAG NUMBER SIGN +E0024 ; [.0000.0000.0000.0000] # [E0024] TAG DOLLAR SIGN +E0025 ; [.0000.0000.0000.0000] # [E0025] TAG PERCENT SIGN +E0026 ; [.0000.0000.0000.0000] # [E0026] TAG AMPERSAND +E0027 ; [.0000.0000.0000.0000] # [E0027] TAG APOSTROPHE +E0028 ; [.0000.0000.0000.0000] # [E0028] TAG LEFT PARENTHESIS +E0029 ; [.0000.0000.0000.0000] # [E0029] TAG RIGHT PARENTHESIS +E002A ; [.0000.0000.0000.0000] # [E002A] TAG ASTERISK +E002B ; [.0000.0000.0000.0000] # [E002B] TAG PLUS SIGN +E002C ; [.0000.0000.0000.0000] # [E002C] TAG COMMA +E002D ; [.0000.0000.0000.0000] # [E002D] TAG HYPHEN-MINUS +E002E ; [.0000.0000.0000.0000] # [E002E] TAG FULL STOP +E002F ; [.0000.0000.0000.0000] # [E002F] TAG SOLIDUS +E0030 ; [.0000.0000.0000.0000] # [E0030] TAG DIGIT ZERO +E0031 ; [.0000.0000.0000.0000] # [E0031] TAG DIGIT ONE +E0032 ; [.0000.0000.0000.0000] # [E0032] TAG DIGIT TWO +E0033 ; [.0000.0000.0000.0000] # [E0033] TAG DIGIT THREE +E0034 ; [.0000.0000.0000.0000] # [E0034] TAG DIGIT FOUR +E0035 ; [.0000.0000.0000.0000] # [E0035] TAG DIGIT FIVE +E0036 ; [.0000.0000.0000.0000] # [E0036] TAG DIGIT SIX +E0037 ; [.0000.0000.0000.0000] # [E0037] TAG DIGIT SEVEN +E0038 ; [.0000.0000.0000.0000] # [E0038] TAG DIGIT EIGHT +E0039 ; [.0000.0000.0000.0000] # [E0039] TAG DIGIT NINE +E003A ; [.0000.0000.0000.0000] # [E003A] TAG COLON +E003B ; [.0000.0000.0000.0000] # [E003B] TAG SEMICOLON +E003C ; [.0000.0000.0000.0000] # [E003C] TAG LESS-THAN SIGN +E003D ; [.0000.0000.0000.0000] # [E003D] TAG EQUALS SIGN +E003E ; [.0000.0000.0000.0000] # [E003E] TAG GREATER-THAN SIGN +E003F ; [.0000.0000.0000.0000] # [E003F] TAG QUESTION MARK +E0040 ; [.0000.0000.0000.0000] # [E0040] TAG COMMERCIAL AT +E0041 ; [.0000.0000.0000.0000] # [E0041] TAG LATIN CAPITAL LETTER A +E0042 ; [.0000.0000.0000.0000] # [E0042] TAG LATIN CAPITAL LETTER B +E0043 ; [.0000.0000.0000.0000] # [E0043] TAG LATIN CAPITAL LETTER C +E0044 ; [.0000.0000.0000.0000] # [E0044] TAG LATIN CAPITAL LETTER D +E0045 ; [.0000.0000.0000.0000] # [E0045] TAG LATIN CAPITAL LETTER E +E0046 ; [.0000.0000.0000.0000] # [E0046] TAG LATIN CAPITAL LETTER F +E0047 ; [.0000.0000.0000.0000] # [E0047] TAG LATIN CAPITAL LETTER G +E0048 ; [.0000.0000.0000.0000] # [E0048] TAG LATIN CAPITAL LETTER H +E0049 ; [.0000.0000.0000.0000] # [E0049] TAG LATIN CAPITAL LETTER I +E004A ; [.0000.0000.0000.0000] # [E004A] TAG LATIN CAPITAL LETTER J +E004B ; [.0000.0000.0000.0000] # [E004B] TAG LATIN CAPITAL LETTER K +E004C ; [.0000.0000.0000.0000] # [E004C] TAG LATIN CAPITAL LETTER L +E004D ; [.0000.0000.0000.0000] # [E004D] TAG LATIN CAPITAL LETTER M +E004E ; [.0000.0000.0000.0000] # [E004E] TAG LATIN CAPITAL LETTER N +E004F ; [.0000.0000.0000.0000] # [E004F] TAG LATIN CAPITAL LETTER O +E0050 ; [.0000.0000.0000.0000] # [E0050] TAG LATIN CAPITAL LETTER P +E0051 ; [.0000.0000.0000.0000] # [E0051] TAG LATIN CAPITAL LETTER Q +E0052 ; [.0000.0000.0000.0000] # [E0052] TAG LATIN CAPITAL LETTER R +E0053 ; [.0000.0000.0000.0000] # [E0053] TAG LATIN CAPITAL LETTER S +E0054 ; [.0000.0000.0000.0000] # [E0054] TAG LATIN CAPITAL LETTER T +E0055 ; [.0000.0000.0000.0000] # [E0055] TAG LATIN CAPITAL LETTER U +E0056 ; [.0000.0000.0000.0000] # [E0056] TAG LATIN CAPITAL LETTER V +E0057 ; [.0000.0000.0000.0000] # [E0057] TAG LATIN CAPITAL LETTER W +E0058 ; [.0000.0000.0000.0000] # [E0058] TAG LATIN CAPITAL LETTER X +E0059 ; [.0000.0000.0000.0000] # [E0059] TAG LATIN CAPITAL LETTER Y +E005A ; [.0000.0000.0000.0000] # [E005A] TAG LATIN CAPITAL LETTER Z +E005B ; [.0000.0000.0000.0000] # [E005B] TAG LEFT SQUARE BRACKET +E005C ; [.0000.0000.0000.0000] # [E005C] TAG REVERSE SOLIDUS +E005D ; [.0000.0000.0000.0000] # [E005D] TAG RIGHT SQUARE BRACKET +E005E ; [.0000.0000.0000.0000] # [E005E] TAG CIRCUMFLEX ACCENT +E005F ; [.0000.0000.0000.0000] # [E005F] TAG LOW LINE +E0060 ; [.0000.0000.0000.0000] # [E0060] TAG GRAVE ACCENT +E0061 ; [.0000.0000.0000.0000] # [E0061] TAG LATIN SMALL LETTER A +E0062 ; [.0000.0000.0000.0000] # [E0062] TAG LATIN SMALL LETTER B +E0063 ; [.0000.0000.0000.0000] # [E0063] TAG LATIN SMALL LETTER C +E0064 ; [.0000.0000.0000.0000] # [E0064] TAG LATIN SMALL LETTER D +E0065 ; [.0000.0000.0000.0000] # [E0065] TAG LATIN SMALL LETTER E +E0066 ; [.0000.0000.0000.0000] # [E0066] TAG LATIN SMALL LETTER F +E0067 ; [.0000.0000.0000.0000] # [E0067] TAG LATIN SMALL LETTER G +E0068 ; [.0000.0000.0000.0000] # [E0068] TAG LATIN SMALL LETTER H +E0069 ; [.0000.0000.0000.0000] # [E0069] TAG LATIN SMALL LETTER I +E006A ; [.0000.0000.0000.0000] # [E006A] TAG LATIN SMALL LETTER J +E006B ; [.0000.0000.0000.0000] # [E006B] TAG LATIN SMALL LETTER K +E006C ; [.0000.0000.0000.0000] # [E006C] TAG LATIN SMALL LETTER L +E006D ; [.0000.0000.0000.0000] # [E006D] TAG LATIN SMALL LETTER M +E006E ; [.0000.0000.0000.0000] # [E006E] TAG LATIN SMALL LETTER N +E006F ; [.0000.0000.0000.0000] # [E006F] TAG LATIN SMALL LETTER O +E0070 ; [.0000.0000.0000.0000] # [E0070] TAG LATIN SMALL LETTER P +E0071 ; [.0000.0000.0000.0000] # [E0071] TAG LATIN SMALL LETTER Q +E0072 ; [.0000.0000.0000.0000] # [E0072] TAG LATIN SMALL LETTER R +E0073 ; [.0000.0000.0000.0000] # [E0073] TAG LATIN SMALL LETTER S +E0074 ; [.0000.0000.0000.0000] # [E0074] TAG LATIN SMALL LETTER T +E0075 ; [.0000.0000.0000.0000] # [E0075] TAG LATIN SMALL LETTER U +E0076 ; [.0000.0000.0000.0000] # [E0076] TAG LATIN SMALL LETTER V +E0077 ; [.0000.0000.0000.0000] # [E0077] TAG LATIN SMALL LETTER W +E0078 ; [.0000.0000.0000.0000] # [E0078] TAG LATIN SMALL LETTER X +E0079 ; [.0000.0000.0000.0000] # [E0079] TAG LATIN SMALL LETTER Y +E007A ; [.0000.0000.0000.0000] # [E007A] TAG LATIN SMALL LETTER Z +E007B ; [.0000.0000.0000.0000] # [E007B] TAG LEFT CURLY BRACKET +E007C ; [.0000.0000.0000.0000] # [E007C] TAG VERTICAL LINE +E007D ; [.0000.0000.0000.0000] # [E007D] TAG RIGHT CURLY BRACKET +E007E ; [.0000.0000.0000.0000] # [E007E] TAG TILDE +E007F ; [.0000.0000.0000.0000] # [E007F] CANCEL TAG +E0100 ; [.0000.0000.0000.0000] # [E0100] VARIATION SELECTOR-17 +E0101 ; [.0000.0000.0000.0000] # [E0101] VARIATION SELECTOR-18 +E0102 ; [.0000.0000.0000.0000] # [E0102] VARIATION SELECTOR-19 +E0103 ; [.0000.0000.0000.0000] # [E0103] VARIATION SELECTOR-20 +E0104 ; [.0000.0000.0000.0000] # [E0104] VARIATION SELECTOR-21 +E0105 ; [.0000.0000.0000.0000] # [E0105] VARIATION SELECTOR-22 +E0106 ; [.0000.0000.0000.0000] # [E0106] VARIATION SELECTOR-23 +E0107 ; [.0000.0000.0000.0000] # [E0107] VARIATION SELECTOR-24 +E0108 ; [.0000.0000.0000.0000] # [E0108] VARIATION SELECTOR-25 +E0109 ; [.0000.0000.0000.0000] # [E0109] VARIATION SELECTOR-26 +E010A ; [.0000.0000.0000.0000] # [E010A] VARIATION SELECTOR-27 +E010B ; [.0000.0000.0000.0000] # [E010B] VARIATION SELECTOR-28 +E010C ; [.0000.0000.0000.0000] # [E010C] VARIATION SELECTOR-29 +E010D ; [.0000.0000.0000.0000] # [E010D] VARIATION SELECTOR-30 +E010E ; [.0000.0000.0000.0000] # [E010E] VARIATION SELECTOR-31 +E010F ; [.0000.0000.0000.0000] # [E010F] VARIATION SELECTOR-32 +E0110 ; [.0000.0000.0000.0000] # [E0110] VARIATION SELECTOR-33 +E0111 ; [.0000.0000.0000.0000] # [E0111] VARIATION SELECTOR-34 +E0112 ; [.0000.0000.0000.0000] # [E0112] VARIATION SELECTOR-35 +E0113 ; [.0000.0000.0000.0000] # [E0113] VARIATION SELECTOR-36 +E0114 ; [.0000.0000.0000.0000] # [E0114] VARIATION SELECTOR-37 +E0115 ; [.0000.0000.0000.0000] # [E0115] VARIATION SELECTOR-38 +E0116 ; [.0000.0000.0000.0000] # [E0116] VARIATION SELECTOR-39 +E0117 ; [.0000.0000.0000.0000] # [E0117] VARIATION SELECTOR-40 +E0118 ; [.0000.0000.0000.0000] # [E0118] VARIATION SELECTOR-41 +E0119 ; [.0000.0000.0000.0000] # [E0119] VARIATION SELECTOR-42 +E011A ; [.0000.0000.0000.0000] # [E011A] VARIATION SELECTOR-43 +E011B ; [.0000.0000.0000.0000] # [E011B] VARIATION SELECTOR-44 +E011C ; [.0000.0000.0000.0000] # [E011C] VARIATION SELECTOR-45 +E011D ; [.0000.0000.0000.0000] # [E011D] VARIATION SELECTOR-46 +E011E ; [.0000.0000.0000.0000] # [E011E] VARIATION SELECTOR-47 +E011F ; [.0000.0000.0000.0000] # [E011F] VARIATION SELECTOR-48 +E0120 ; [.0000.0000.0000.0000] # [E0120] VARIATION SELECTOR-49 +E0121 ; [.0000.0000.0000.0000] # [E0121] VARIATION SELECTOR-50 +E0122 ; [.0000.0000.0000.0000] # [E0122] VARIATION SELECTOR-51 +E0123 ; [.0000.0000.0000.0000] # [E0123] VARIATION SELECTOR-52 +E0124 ; [.0000.0000.0000.0000] # [E0124] VARIATION SELECTOR-53 +E0125 ; [.0000.0000.0000.0000] # [E0125] VARIATION SELECTOR-54 +E0126 ; [.0000.0000.0000.0000] # [E0126] VARIATION SELECTOR-55 +E0127 ; [.0000.0000.0000.0000] # [E0127] VARIATION SELECTOR-56 +E0128 ; [.0000.0000.0000.0000] # [E0128] VARIATION SELECTOR-57 +E0129 ; [.0000.0000.0000.0000] # [E0129] VARIATION SELECTOR-58 +E012A ; [.0000.0000.0000.0000] # [E012A] VARIATION SELECTOR-59 +E012B ; [.0000.0000.0000.0000] # [E012B] VARIATION SELECTOR-60 +E012C ; [.0000.0000.0000.0000] # [E012C] VARIATION SELECTOR-61 +E012D ; [.0000.0000.0000.0000] # [E012D] VARIATION SELECTOR-62 +E012E ; [.0000.0000.0000.0000] # [E012E] VARIATION SELECTOR-63 +E012F ; [.0000.0000.0000.0000] # [E012F] VARIATION SELECTOR-64 +E0130 ; [.0000.0000.0000.0000] # [E0130] VARIATION SELECTOR-65 +E0131 ; [.0000.0000.0000.0000] # [E0131] VARIATION SELECTOR-66 +E0132 ; [.0000.0000.0000.0000] # [E0132] VARIATION SELECTOR-67 +E0133 ; [.0000.0000.0000.0000] # [E0133] VARIATION SELECTOR-68 +E0134 ; [.0000.0000.0000.0000] # [E0134] VARIATION SELECTOR-69 +E0135 ; [.0000.0000.0000.0000] # [E0135] VARIATION SELECTOR-70 +E0136 ; [.0000.0000.0000.0000] # [E0136] VARIATION SELECTOR-71 +E0137 ; [.0000.0000.0000.0000] # [E0137] VARIATION SELECTOR-72 +E0138 ; [.0000.0000.0000.0000] # [E0138] VARIATION SELECTOR-73 +E0139 ; [.0000.0000.0000.0000] # [E0139] VARIATION SELECTOR-74 +E013A ; [.0000.0000.0000.0000] # [E013A] VARIATION SELECTOR-75 +E013B ; [.0000.0000.0000.0000] # [E013B] VARIATION SELECTOR-76 +E013C ; [.0000.0000.0000.0000] # [E013C] VARIATION SELECTOR-77 +E013D ; [.0000.0000.0000.0000] # [E013D] VARIATION SELECTOR-78 +E013E ; [.0000.0000.0000.0000] # [E013E] VARIATION SELECTOR-79 +E013F ; [.0000.0000.0000.0000] # [E013F] VARIATION SELECTOR-80 +E0140 ; [.0000.0000.0000.0000] # [E0140] VARIATION SELECTOR-81 +E0141 ; [.0000.0000.0000.0000] # [E0141] VARIATION SELECTOR-82 +E0142 ; [.0000.0000.0000.0000] # [E0142] VARIATION SELECTOR-83 +E0143 ; [.0000.0000.0000.0000] # [E0143] VARIATION SELECTOR-84 +E0144 ; [.0000.0000.0000.0000] # [E0144] VARIATION SELECTOR-85 +E0145 ; [.0000.0000.0000.0000] # [E0145] VARIATION SELECTOR-86 +E0146 ; [.0000.0000.0000.0000] # [E0146] VARIATION SELECTOR-87 +E0147 ; [.0000.0000.0000.0000] # [E0147] VARIATION SELECTOR-88 +E0148 ; [.0000.0000.0000.0000] # [E0148] VARIATION SELECTOR-89 +E0149 ; [.0000.0000.0000.0000] # [E0149] VARIATION SELECTOR-90 +E014A ; [.0000.0000.0000.0000] # [E014A] VARIATION SELECTOR-91 +E014B ; [.0000.0000.0000.0000] # [E014B] VARIATION SELECTOR-92 +E014C ; [.0000.0000.0000.0000] # [E014C] VARIATION SELECTOR-93 +E014D ; [.0000.0000.0000.0000] # [E014D] VARIATION SELECTOR-94 +E014E ; [.0000.0000.0000.0000] # [E014E] VARIATION SELECTOR-95 +E014F ; [.0000.0000.0000.0000] # [E014F] VARIATION SELECTOR-96 +E0150 ; [.0000.0000.0000.0000] # [E0150] VARIATION SELECTOR-97 +E0151 ; [.0000.0000.0000.0000] # [E0151] VARIATION SELECTOR-98 +E0152 ; [.0000.0000.0000.0000] # [E0152] VARIATION SELECTOR-99 +E0153 ; [.0000.0000.0000.0000] # [E0153] VARIATION SELECTOR-100 +E0154 ; [.0000.0000.0000.0000] # [E0154] VARIATION SELECTOR-101 +E0155 ; [.0000.0000.0000.0000] # [E0155] VARIATION SELECTOR-102 +E0156 ; [.0000.0000.0000.0000] # [E0156] VARIATION SELECTOR-103 +E0157 ; [.0000.0000.0000.0000] # [E0157] VARIATION SELECTOR-104 +E0158 ; [.0000.0000.0000.0000] # [E0158] VARIATION SELECTOR-105 +E0159 ; [.0000.0000.0000.0000] # [E0159] VARIATION SELECTOR-106 +E015A ; [.0000.0000.0000.0000] # [E015A] VARIATION SELECTOR-107 +E015B ; [.0000.0000.0000.0000] # [E015B] VARIATION SELECTOR-108 +E015C ; [.0000.0000.0000.0000] # [E015C] VARIATION SELECTOR-109 +E015D ; [.0000.0000.0000.0000] # [E015D] VARIATION SELECTOR-110 +E015E ; [.0000.0000.0000.0000] # [E015E] VARIATION SELECTOR-111 +E015F ; [.0000.0000.0000.0000] # [E015F] VARIATION SELECTOR-112 +E0160 ; [.0000.0000.0000.0000] # [E0160] VARIATION SELECTOR-113 +E0161 ; [.0000.0000.0000.0000] # [E0161] VARIATION SELECTOR-114 +E0162 ; [.0000.0000.0000.0000] # [E0162] VARIATION SELECTOR-115 +E0163 ; [.0000.0000.0000.0000] # [E0163] VARIATION SELECTOR-116 +E0164 ; [.0000.0000.0000.0000] # [E0164] VARIATION SELECTOR-117 +E0165 ; [.0000.0000.0000.0000] # [E0165] VARIATION SELECTOR-118 +E0166 ; [.0000.0000.0000.0000] # [E0166] VARIATION SELECTOR-119 +E0167 ; [.0000.0000.0000.0000] # [E0167] VARIATION SELECTOR-120 +E0168 ; [.0000.0000.0000.0000] # [E0168] VARIATION SELECTOR-121 +E0169 ; [.0000.0000.0000.0000] # [E0169] VARIATION SELECTOR-122 +E016A ; [.0000.0000.0000.0000] # [E016A] VARIATION SELECTOR-123 +E016B ; [.0000.0000.0000.0000] # [E016B] VARIATION SELECTOR-124 +E016C ; [.0000.0000.0000.0000] # [E016C] VARIATION SELECTOR-125 +E016D ; [.0000.0000.0000.0000] # [E016D] VARIATION SELECTOR-126 +E016E ; [.0000.0000.0000.0000] # [E016E] VARIATION SELECTOR-127 +E016F ; [.0000.0000.0000.0000] # [E016F] VARIATION SELECTOR-128 +E0170 ; [.0000.0000.0000.0000] # [E0170] VARIATION SELECTOR-129 +E0171 ; [.0000.0000.0000.0000] # [E0171] VARIATION SELECTOR-130 +E0172 ; [.0000.0000.0000.0000] # [E0172] VARIATION SELECTOR-131 +E0173 ; [.0000.0000.0000.0000] # [E0173] VARIATION SELECTOR-132 +E0174 ; [.0000.0000.0000.0000] # [E0174] VARIATION SELECTOR-133 +E0175 ; [.0000.0000.0000.0000] # [E0175] VARIATION SELECTOR-134 +E0176 ; [.0000.0000.0000.0000] # [E0176] VARIATION SELECTOR-135 +E0177 ; [.0000.0000.0000.0000] # [E0177] VARIATION SELECTOR-136 +E0178 ; [.0000.0000.0000.0000] # [E0178] VARIATION SELECTOR-137 +E0179 ; [.0000.0000.0000.0000] # [E0179] VARIATION SELECTOR-138 +E017A ; [.0000.0000.0000.0000] # [E017A] VARIATION SELECTOR-139 +E017B ; [.0000.0000.0000.0000] # [E017B] VARIATION SELECTOR-140 +E017C ; [.0000.0000.0000.0000] # [E017C] VARIATION SELECTOR-141 +E017D ; [.0000.0000.0000.0000] # [E017D] VARIATION SELECTOR-142 +E017E ; [.0000.0000.0000.0000] # [E017E] VARIATION SELECTOR-143 +E017F ; [.0000.0000.0000.0000] # [E017F] VARIATION SELECTOR-144 +E0180 ; [.0000.0000.0000.0000] # [E0180] VARIATION SELECTOR-145 +E0181 ; [.0000.0000.0000.0000] # [E0181] VARIATION SELECTOR-146 +E0182 ; [.0000.0000.0000.0000] # [E0182] VARIATION SELECTOR-147 +E0183 ; [.0000.0000.0000.0000] # [E0183] VARIATION SELECTOR-148 +E0184 ; [.0000.0000.0000.0000] # [E0184] VARIATION SELECTOR-149 +E0185 ; [.0000.0000.0000.0000] # [E0185] VARIATION SELECTOR-150 +E0186 ; [.0000.0000.0000.0000] # [E0186] VARIATION SELECTOR-151 +E0187 ; [.0000.0000.0000.0000] # [E0187] VARIATION SELECTOR-152 +E0188 ; [.0000.0000.0000.0000] # [E0188] VARIATION SELECTOR-153 +E0189 ; [.0000.0000.0000.0000] # [E0189] VARIATION SELECTOR-154 +E018A ; [.0000.0000.0000.0000] # [E018A] VARIATION SELECTOR-155 +E018B ; [.0000.0000.0000.0000] # [E018B] VARIATION SELECTOR-156 +E018C ; [.0000.0000.0000.0000] # [E018C] VARIATION SELECTOR-157 +E018D ; [.0000.0000.0000.0000] # [E018D] VARIATION SELECTOR-158 +E018E ; [.0000.0000.0000.0000] # [E018E] VARIATION SELECTOR-159 +E018F ; [.0000.0000.0000.0000] # [E018F] VARIATION SELECTOR-160 +E0190 ; [.0000.0000.0000.0000] # [E0190] VARIATION SELECTOR-161 +E0191 ; [.0000.0000.0000.0000] # [E0191] VARIATION SELECTOR-162 +E0192 ; [.0000.0000.0000.0000] # [E0192] VARIATION SELECTOR-163 +E0193 ; [.0000.0000.0000.0000] # [E0193] VARIATION SELECTOR-164 +E0194 ; [.0000.0000.0000.0000] # [E0194] VARIATION SELECTOR-165 +E0195 ; [.0000.0000.0000.0000] # [E0195] VARIATION SELECTOR-166 +E0196 ; [.0000.0000.0000.0000] # [E0196] VARIATION SELECTOR-167 +E0197 ; [.0000.0000.0000.0000] # [E0197] VARIATION SELECTOR-168 +E0198 ; [.0000.0000.0000.0000] # [E0198] VARIATION SELECTOR-169 +E0199 ; [.0000.0000.0000.0000] # [E0199] VARIATION SELECTOR-170 +E019A ; [.0000.0000.0000.0000] # [E019A] VARIATION SELECTOR-171 +E019B ; [.0000.0000.0000.0000] # [E019B] VARIATION SELECTOR-172 +E019C ; [.0000.0000.0000.0000] # [E019C] VARIATION SELECTOR-173 +E019D ; [.0000.0000.0000.0000] # [E019D] VARIATION SELECTOR-174 +E019E ; [.0000.0000.0000.0000] # [E019E] VARIATION SELECTOR-175 +E019F ; [.0000.0000.0000.0000] # [E019F] VARIATION SELECTOR-176 +E01A0 ; [.0000.0000.0000.0000] # [E01A0] VARIATION SELECTOR-177 +E01A1 ; [.0000.0000.0000.0000] # [E01A1] VARIATION SELECTOR-178 +E01A2 ; [.0000.0000.0000.0000] # [E01A2] VARIATION SELECTOR-179 +E01A3 ; [.0000.0000.0000.0000] # [E01A3] VARIATION SELECTOR-180 +E01A4 ; [.0000.0000.0000.0000] # [E01A4] VARIATION SELECTOR-181 +E01A5 ; [.0000.0000.0000.0000] # [E01A5] VARIATION SELECTOR-182 +E01A6 ; [.0000.0000.0000.0000] # [E01A6] VARIATION SELECTOR-183 +E01A7 ; [.0000.0000.0000.0000] # [E01A7] VARIATION SELECTOR-184 +E01A8 ; [.0000.0000.0000.0000] # [E01A8] VARIATION SELECTOR-185 +E01A9 ; [.0000.0000.0000.0000] # [E01A9] VARIATION SELECTOR-186 +E01AA ; [.0000.0000.0000.0000] # [E01AA] VARIATION SELECTOR-187 +E01AB ; [.0000.0000.0000.0000] # [E01AB] VARIATION SELECTOR-188 +E01AC ; [.0000.0000.0000.0000] # [E01AC] VARIATION SELECTOR-189 +E01AD ; [.0000.0000.0000.0000] # [E01AD] VARIATION SELECTOR-190 +E01AE ; [.0000.0000.0000.0000] # [E01AE] VARIATION SELECTOR-191 +E01AF ; [.0000.0000.0000.0000] # [E01AF] VARIATION SELECTOR-192 +E01B0 ; [.0000.0000.0000.0000] # [E01B0] VARIATION SELECTOR-193 +E01B1 ; [.0000.0000.0000.0000] # [E01B1] VARIATION SELECTOR-194 +E01B2 ; [.0000.0000.0000.0000] # [E01B2] VARIATION SELECTOR-195 +E01B3 ; [.0000.0000.0000.0000] # [E01B3] VARIATION SELECTOR-196 +E01B4 ; [.0000.0000.0000.0000] # [E01B4] VARIATION SELECTOR-197 +E01B5 ; [.0000.0000.0000.0000] # [E01B5] VARIATION SELECTOR-198 +E01B6 ; [.0000.0000.0000.0000] # [E01B6] VARIATION SELECTOR-199 +E01B7 ; [.0000.0000.0000.0000] # [E01B7] VARIATION SELECTOR-200 +E01B8 ; [.0000.0000.0000.0000] # [E01B8] VARIATION SELECTOR-201 +E01B9 ; [.0000.0000.0000.0000] # [E01B9] VARIATION SELECTOR-202 +E01BA ; [.0000.0000.0000.0000] # [E01BA] VARIATION SELECTOR-203 +E01BB ; [.0000.0000.0000.0000] # [E01BB] VARIATION SELECTOR-204 +E01BC ; [.0000.0000.0000.0000] # [E01BC] VARIATION SELECTOR-205 +E01BD ; [.0000.0000.0000.0000] # [E01BD] VARIATION SELECTOR-206 +E01BE ; [.0000.0000.0000.0000] # [E01BE] VARIATION SELECTOR-207 +E01BF ; [.0000.0000.0000.0000] # [E01BF] VARIATION SELECTOR-208 +E01C0 ; [.0000.0000.0000.0000] # [E01C0] VARIATION SELECTOR-209 +E01C1 ; [.0000.0000.0000.0000] # [E01C1] VARIATION SELECTOR-210 +E01C2 ; [.0000.0000.0000.0000] # [E01C2] VARIATION SELECTOR-211 +E01C3 ; [.0000.0000.0000.0000] # [E01C3] VARIATION SELECTOR-212 +E01C4 ; [.0000.0000.0000.0000] # [E01C4] VARIATION SELECTOR-213 +E01C5 ; [.0000.0000.0000.0000] # [E01C5] VARIATION SELECTOR-214 +E01C6 ; [.0000.0000.0000.0000] # [E01C6] VARIATION SELECTOR-215 +E01C7 ; [.0000.0000.0000.0000] # [E01C7] VARIATION SELECTOR-216 +E01C8 ; [.0000.0000.0000.0000] # [E01C8] VARIATION SELECTOR-217 +E01C9 ; [.0000.0000.0000.0000] # [E01C9] VARIATION SELECTOR-218 +E01CA ; [.0000.0000.0000.0000] # [E01CA] VARIATION SELECTOR-219 +E01CB ; [.0000.0000.0000.0000] # [E01CB] VARIATION SELECTOR-220 +E01CC ; [.0000.0000.0000.0000] # [E01CC] VARIATION SELECTOR-221 +E01CD ; [.0000.0000.0000.0000] # [E01CD] VARIATION SELECTOR-222 +E01CE ; [.0000.0000.0000.0000] # [E01CE] VARIATION SELECTOR-223 +E01CF ; [.0000.0000.0000.0000] # [E01CF] VARIATION SELECTOR-224 +E01D0 ; [.0000.0000.0000.0000] # [E01D0] VARIATION SELECTOR-225 +E01D1 ; [.0000.0000.0000.0000] # [E01D1] VARIATION SELECTOR-226 +E01D2 ; [.0000.0000.0000.0000] # [E01D2] VARIATION SELECTOR-227 +E01D3 ; [.0000.0000.0000.0000] # [E01D3] VARIATION SELECTOR-228 +E01D4 ; [.0000.0000.0000.0000] # [E01D4] VARIATION SELECTOR-229 +E01D5 ; [.0000.0000.0000.0000] # [E01D5] VARIATION SELECTOR-230 +E01D6 ; [.0000.0000.0000.0000] # [E01D6] VARIATION SELECTOR-231 +E01D7 ; [.0000.0000.0000.0000] # [E01D7] VARIATION SELECTOR-232 +E01D8 ; [.0000.0000.0000.0000] # [E01D8] VARIATION SELECTOR-233 +E01D9 ; [.0000.0000.0000.0000] # [E01D9] VARIATION SELECTOR-234 +E01DA ; [.0000.0000.0000.0000] # [E01DA] VARIATION SELECTOR-235 +E01DB ; [.0000.0000.0000.0000] # [E01DB] VARIATION SELECTOR-236 +E01DC ; [.0000.0000.0000.0000] # [E01DC] VARIATION SELECTOR-237 +E01DD ; [.0000.0000.0000.0000] # [E01DD] VARIATION SELECTOR-238 +E01DE ; [.0000.0000.0000.0000] # [E01DE] VARIATION SELECTOR-239 +E01DF ; [.0000.0000.0000.0000] # [E01DF] VARIATION SELECTOR-240 +E01E0 ; [.0000.0000.0000.0000] # [E01E0] VARIATION SELECTOR-241 +E01E1 ; [.0000.0000.0000.0000] # [E01E1] VARIATION SELECTOR-242 +E01E2 ; [.0000.0000.0000.0000] # [E01E2] VARIATION SELECTOR-243 +E01E3 ; [.0000.0000.0000.0000] # [E01E3] VARIATION SELECTOR-244 +E01E4 ; [.0000.0000.0000.0000] # [E01E4] VARIATION SELECTOR-245 +E01E5 ; [.0000.0000.0000.0000] # [E01E5] VARIATION SELECTOR-246 +E01E6 ; [.0000.0000.0000.0000] # [E01E6] VARIATION SELECTOR-247 +E01E7 ; [.0000.0000.0000.0000] # [E01E7] VARIATION SELECTOR-248 +E01E8 ; [.0000.0000.0000.0000] # [E01E8] VARIATION SELECTOR-249 +E01E9 ; [.0000.0000.0000.0000] # [E01E9] VARIATION SELECTOR-250 +E01EA ; [.0000.0000.0000.0000] # [E01EA] VARIATION SELECTOR-251 +E01EB ; [.0000.0000.0000.0000] # [E01EB] VARIATION SELECTOR-252 +E01EC ; [.0000.0000.0000.0000] # [E01EC] VARIATION SELECTOR-253 +E01ED ; [.0000.0000.0000.0000] # [E01ED] VARIATION SELECTOR-254 +E01EE ; [.0000.0000.0000.0000] # [E01EE] VARIATION SELECTOR-255 +E01EF ; [.0000.0000.0000.0000] # [E01EF] VARIATION SELECTOR-256 +0009 ; [*0201.0020.0002.0009] # HORIZONTAL TABULATION (in 6429) +000A ; [*0202.0020.0002.000A] # LINE FEED (in 6429) +000B ; [*0203.0020.0002.000B] # VERTICAL TABULATION (in 6429) +000C ; [*0204.0020.0002.000C] # FORM FEED (in 6429) +000D ; [*0205.0020.0002.000D] # CARRIAGE RETURN (in 6429) +0020 ; [*0209.0020.0002.0020] # SPACE +0021 ; [*0257.0020.0002.0021] # EXCLAMATION MARK +0022 ; [*02A7.0020.0002.0022] # QUOTATION MARK +0023 ; [*0305.0020.0002.0023] # NUMBER SIGN +0025 ; [*0306.0020.0002.0025] # PERCENT SIGN +0026 ; [*0302.0020.0002.0026] # AMPERSAND +0027 ; [*02A0.0020.0002.0027] # APOSTROPHE +0028 ; [*02B1.0020.0002.0028] # LEFT PARENTHESIS +0029 ; [*02B2.0020.0002.0029] # RIGHT PARENTHESIS +002A ; [*02FB.0020.0002.002A] # ASTERISK +002B ; [*04B8.0020.0002.002B] # PLUS SIGN +002C ; [*0232.0020.0002.002C] # COMMA +002D ; [*0222.0020.0002.002D] # HYPHEN-MINUS +002E ; [*0266.0020.0002.002E] # FULL STOP +002F ; [*02FF.0020.0002.002F] # SOLIDUS +003A ; [*0241.0020.0002.003A] # COLON +003B ; [*023E.0020.0002.003B] # SEMICOLON +003C ; [*04BC.0020.0002.003C] # LESS-THAN SIGN +003D ; [*04BD.0020.0002.003D] # EQUALS SIGN +003E ; [*04BE.0020.0002.003E] # GREATER-THAN SIGN +003F ; [*025C.0020.0002.003F] # QUESTION MARK +0040 ; [*02FA.0020.0002.0040] # COMMERCIAL AT +005B ; [*02B3.0020.0002.005B] # LEFT SQUARE BRACKET +005C ; [*0301.0020.0002.005C] # REVERSE SOLIDUS +005D ; [*02B4.0020.0002.005D] # RIGHT SQUARE BRACKET +005E ; [*0210.0020.0002.005E] # CIRCUMFLEX ACCENT +005F ; [*021C.0020.0002.005F] # LOW LINE +0060 ; [*020D.0020.0002.0060] # GRAVE ACCENT +007B ; [*02B5.0020.0002.007B] # LEFT CURLY BRACKET +007C ; [*04C0.0020.0002.007C] # VERTICAL LINE +007D ; [*02B6.0020.0002.007D] # RIGHT CURLY BRACKET +007E ; [*04C3.0020.0002.007E] # TILDE +0085 ; [*0206.0020.0002.0085] # NEXT LINE (in 6429) +00A0 ; [*0209.0020.001B.00A0] # NO-BREAK SPACE; QQK +00A1 ; [*0258.0020.0002.00A1] # INVERTED EXCLAMATION MARK +00A6 ; [*04C1.0020.0002.00A6] # BROKEN BAR +00A7 ; [*02F5.0020.0002.00A7] # SECTION SIGN +00A8 ; [*0215.0020.0002.00A8] # DIAERESIS +00A9 ; [*02F8.0020.0002.00A9] # COPYRIGHT SIGN +00AB ; [*02AF.0020.0002.00AB] # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +00AC ; [*04BF.0020.0002.00AC] # NOT SIGN +00AD ; [*0221.0020.0002.00AD] # SOFT HYPHEN +00AE ; [*02F9.0020.0002.00AE] # REGISTERED SIGN +00AF ; [*0211.0020.0002.00AF] # MACRON +00B0 ; [*03BF.0020.0002.00B0] # DEGREE SIGN +00B1 ; [*04B9.0020.0002.00B1] # PLUS-MINUS SIGN +00B4 ; [*020E.0020.0002.00B4] # ACUTE ACCENT +00B6 ; [*02F6.0020.0002.00B6] # PILCROW SIGN +00B7 ; [*0273.0020.0002.00B7] # MIDDLE DOT +00B8 ; [*021A.0020.0002.00B8] # CEDILLA +00BB ; [*02B0.0020.0002.00BB] # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +00BF ; [*025D.0020.0002.00BF] # INVERTED QUESTION MARK +00D7 ; [*04BB.0020.0002.00D7] # MULTIPLICATION SIGN +00F7 ; [*04BA.0020.0002.00F7] # DIVISION SIGN +02B9 ; [*0365.0020.0002.02B9] # MODIFIER LETTER PRIME +02BA ; [*0367.0020.0002.02BA] # MODIFIER LETTER DOUBLE PRIME +02C2 ; [*0368.0020.0002.02C2] # MODIFIER LETTER LEFT ARROWHEAD +02C3 ; [*0369.0020.0002.02C3] # MODIFIER LETTER RIGHT ARROWHEAD +02C4 ; [*036A.0020.0002.02C4] # MODIFIER LETTER UP ARROWHEAD +02C5 ; [*036B.0020.0002.02C5] # MODIFIER LETTER DOWN ARROWHEAD +02C6 ; [*036C.0020.0002.02C6] # MODIFIER LETTER CIRCUMFLEX ACCENT +02C7 ; [*036D.0020.0002.02C7] # CARON +02C8 ; [*036E.0020.0002.02C8] # MODIFIER LETTER VERTICAL LINE +02C9 ; [*036F.0020.0002.02C9] # MODIFIER LETTER MACRON +02CA ; [*0370.0020.0002.02CA] # MODIFIER LETTER ACUTE ACCENT +02CB ; [*0371.0020.0002.02CB] # MODIFIER LETTER GRAVE ACCENT +02CC ; [*0372.0020.0002.02CC] # MODIFIER LETTER LOW VERTICAL LINE +02CD ; [*0373.0020.0002.02CD] # MODIFIER LETTER LOW MACRON +02CE ; [*0374.0020.0002.02CE] # MODIFIER LETTER LOW GRAVE ACCENT +02CF ; [*0375.0020.0002.02CF] # MODIFIER LETTER LOW ACUTE ACCENT +02D2 ; [*0376.0020.0002.02D2] # MODIFIER LETTER CENTRED RIGHT HALF RING +02D3 ; [*0377.0020.0002.02D3] # MODIFIER LETTER CENTRED LEFT HALF RING +02D4 ; [*0378.0020.0002.02D4] # MODIFIER LETTER UP TACK +02D5 ; [*0379.0020.0002.02D5] # MODIFIER LETTER DOWN TACK +02D6 ; [*037A.0020.0002.02D6] # MODIFIER LETTER PLUS SIGN +02D7 ; [*037B.0020.0002.02D7] # MODIFIER LETTER MINUS SIGN +02D8 ; [*0213.0020.0002.02D8] # BREVE +02D9 ; [*0214.0020.0002.02D9] # DOT ABOVE +02DA ; [*0216.0020.0002.02DA] # RING ABOVE +02DB ; [*021B.0020.0002.02DB] # OGONEK +02DC ; [*020F.0020.0002.02DC] # SMALL TILDE +02DD ; [*0217.0020.0002.02DD] # DOUBLE ACUTE ACCENT +02DE ; [*037C.0020.0002.02DE] # MODIFIER LETTER RHOTIC HOOK +02DF ; [*037D.0020.0002.02DF] # MODIFIER LETTER CROSS ACCENT +02E5 ; [*037E.0020.0002.02E5] # MODIFIER LETTER EXTRA-HIGH TONE BAR +02E6 ; [*037F.0020.0002.02E6] # MODIFIER LETTER HIGH TONE BAR +02E7 ; [*0380.0020.0002.02E7] # MODIFIER LETTER MID TONE BAR +02E8 ; [*0381.0020.0002.02E8] # MODIFIER LETTER LOW TONE BAR +02E9 ; [*0382.0020.0002.02E9] # MODIFIER LETTER EXTRA-LOW TONE BAR +02EA ; [*0383.0020.0002.02EA] # MODIFIER LETTER YIN DEPARTING TONE MARK +02EB ; [*0384.0020.0002.02EB] # MODIFIER LETTER YANG DEPARTING TONE MARK +02EC ; [*0385.0020.0002.02EC] # MODIFIER LETTER VOICING +02ED ; [*0386.0020.0002.02ED] # MODIFIER LETTER UNASPIRATED +02EF ; [*0387.0020.0002.02EF] # MODIFIER LETTER LOW DOWN ARROWHEAD +02F0 ; [*0388.0020.0002.02F0] # MODIFIER LETTER LOW UP ARROWHEAD +02F1 ; [*0389.0020.0002.02F1] # MODIFIER LETTER LOW LEFT ARROWHEAD +02F2 ; [*038A.0020.0002.02F2] # MODIFIER LETTER LOW RIGHT ARROWHEAD +02F3 ; [*038B.0020.0002.02F3] # MODIFIER LETTER LOW RING +02F4 ; [*038C.0020.0002.02F4] # MODIFIER LETTER MIDDLE GRAVE ACCENT +02F5 ; [*038D.0020.0002.02F5] # MODIFIER LETTER MIDDLE DOUBLE GRAVE ACCENT +02F6 ; [*038E.0020.0002.02F6] # MODIFIER LETTER MIDDLE DOUBLE ACUTE ACCENT +02F7 ; [*038F.0020.0002.02F7] # MODIFIER LETTER LOW TILDE +02F8 ; [*0390.0020.0002.02F8] # MODIFIER LETTER RAISED COLON +02F9 ; [*0391.0020.0002.02F9] # MODIFIER LETTER BEGIN HIGH TONE +02FA ; [*0392.0020.0002.02FA] # MODIFIER LETTER END HIGH TONE +02FB ; [*0393.0020.0002.02FB] # MODIFIER LETTER BEGIN LOW TONE +02FC ; [*0394.0020.0002.02FC] # MODIFIER LETTER END LOW TONE +02FD ; [*0395.0020.0002.02FD] # MODIFIER LETTER SHELF +02FE ; [*0396.0020.0002.02FE] # MODIFIER LETTER OPEN SHELF +02FF ; [*0397.0020.0002.02FF] # MODIFIER LETTER LOW LEFT ARROW +034F ; [.0000.0000.0000.034F] # COMBINING GRAPHEME JOINER +0374 ; [*0365.0020.0002.0374] # GREEK NUMERAL SIGN; QQC +0375 ; [*0366.0020.0002.0375] # GREEK LOWER NUMERAL SIGN +037E ; [*023E.0020.0002.037E] # GREEK QUESTION MARK; QQC +0384 ; [*020E.0020.0002.0384] # GREEK TONOS; QQC +0385 ; [*0215.0020.0002.00A8][.0000.0032.0002.0301] # GREEK DIALYTIKA TONOS; QQCM +0387 ; [*0273.0020.0002.0387] # GREEK ANO TELEIA; QQC +03F6 ; [*04B3.0020.0002.03F6] # GREEK REVERSED LUNATE EPSILON SYMBOL +0482 ; [*03C0.0020.0002.0482] # CYRILLIC THOUSANDS SIGN +0488 ; [.0000.0000.0000.0488] # COMBINING CYRILLIC HUNDRED THOUSANDS SIGN +0489 ; [.0000.0000.0000.0489] # COMBINING CYRILLIC MILLIONS SIGN +055A ; [*032E.0020.0002.055A] # ARMENIAN APOSTROPHE +055B ; [*032F.0020.0002.055B] # ARMENIAN EMPHASIS MARK +055C ; [*0259.0020.0002.055C] # ARMENIAN EXCLAMATION MARK +055D ; [*0233.0020.0002.055D] # ARMENIAN COMMA +055E ; [*025E.0020.0002.055E] # ARMENIAN QUESTION MARK +055F ; [*0330.0020.0002.055F] # ARMENIAN ABBREVIATION MARK +0589 ; [*0242.0020.0002.0589] # ARMENIAN FULL STOP +058A ; [*0223.0020.0002.058A] # ARMENIAN HYPHEN +0591 ; [.0000.0000.0000.0591] # HEBREW ACCENT ETNAHTA +0592 ; [.0000.0000.0000.0592] # HEBREW ACCENT SEGOL +0593 ; [.0000.0000.0000.0593] # HEBREW ACCENT SHALSHELET +0594 ; [.0000.0000.0000.0594] # HEBREW ACCENT ZAQEF QATAN +0595 ; [.0000.0000.0000.0595] # HEBREW ACCENT ZAQEF GADOL +0596 ; [.0000.0000.0000.0596] # HEBREW ACCENT TIPEHA +0597 ; [.0000.0000.0000.0597] # HEBREW ACCENT REVIA +0598 ; [.0000.0000.0000.0598] # HEBREW ACCENT ZARQA +0599 ; [.0000.0000.0000.0599] # HEBREW ACCENT PASHTA +059A ; [.0000.0000.0000.059A] # HEBREW ACCENT YETIV +059B ; [.0000.0000.0000.059B] # HEBREW ACCENT TEVIR +059C ; [.0000.0000.0000.059C] # HEBREW ACCENT GERESH +059D ; [.0000.0000.0000.059D] # HEBREW ACCENT GERESH MUQDAM +059E ; [.0000.0000.0000.059E] # HEBREW ACCENT GERSHAYIM +059F ; [.0000.0000.0000.059F] # HEBREW ACCENT QARNEY PARA +05A0 ; [.0000.0000.0000.05A0] # HEBREW ACCENT TELISHA GEDOLA +05A1 ; [.0000.0000.0000.05A1] # HEBREW ACCENT PAZER +05A2 ; [.0000.0000.0000.05A2] # HEBREW ACCENT ATNAH HAFUKH +05A3 ; [.0000.0000.0000.05A3] # HEBREW ACCENT MUNAH +05A4 ; [.0000.0000.0000.05A4] # HEBREW ACCENT MAHAPAKH +05A5 ; [.0000.0000.0000.05A5] # HEBREW ACCENT MERKHA +05A6 ; [.0000.0000.0000.05A6] # HEBREW ACCENT MERKHA KEFULA +05A7 ; [.0000.0000.0000.05A7] # HEBREW ACCENT DARGA +05A8 ; [.0000.0000.0000.05A8] # HEBREW ACCENT QADMA +05A9 ; [.0000.0000.0000.05A9] # HEBREW ACCENT TELISHA QETANA +05AA ; [.0000.0000.0000.05AA] # HEBREW ACCENT YERAH BEN YOMO +05AB ; [.0000.0000.0000.05AB] # HEBREW ACCENT OLE +05AC ; [.0000.0000.0000.05AC] # HEBREW ACCENT ILUY +05AD ; [.0000.0000.0000.05AD] # HEBREW ACCENT DEHI +05AE ; [.0000.0000.0000.05AE] # HEBREW ACCENT ZINOR +05AF ; [.0000.0000.0000.05AF] # HEBREW MARK MASORA CIRCLE +05BD ; [.0000.0000.0000.05BD] # HEBREW POINT METEG +05BE ; [*0331.0020.0002.05BE] # HEBREW PUNCTUATION MAQAF +05C0 ; [*0332.0020.0002.05C0] # HEBREW PUNCTUATION PASEQ +05C3 ; [*0333.0020.0002.05C3] # HEBREW PUNCTUATION SOF PASUQ +05C4 ; [.0000.0000.0000.05C4] # HEBREW MARK UPPER DOT +05C5 ; [.0000.0000.0000.05C5] # HEBREW MARK LOWER DOT +05C6 ; [*0334.0020.0002.05C6] # HEBREW PUNCTUATION NUN HAFUKHA +05F3 ; [*0335.0020.0002.05F3] # HEBREW PUNCTUATION GERESH +05F4 ; [*0336.0020.0002.05F4] # HEBREW PUNCTUATION GERSHAYIM +0600 ; [.0000.0000.0000.0600] # ARABIC NUMBER SIGN +0601 ; [.0000.0000.0000.0601] # ARABIC SIGN SANAH +0602 ; [.0000.0000.0000.0602] # ARABIC FOOTNOTE MARKER +0603 ; [.0000.0000.0000.0603] # ARABIC SIGN SAFHA +060C ; [*0234.0020.0002.060C] # ARABIC COMMA +060D ; [*0235.0020.0002.060D] # ARABIC DATE SEPARATOR +060E ; [*03C1.0020.0002.060E] # ARABIC POETIC VERSE SIGN +060F ; [*03C2.0020.0002.060F] # ARABIC SIGN MISRA +0610 ; [.0000.0000.0000.0610] # ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM +0611 ; [.0000.0000.0000.0611] # ARABIC SIGN ALAYHE ASSALLAM +0612 ; [.0000.0000.0000.0612] # ARABIC SIGN RAHMATULLAH ALAYHE +0613 ; [.0000.0000.0000.0613] # ARABIC SIGN RADI ALLAHOU ANHU +0614 ; [.0000.0000.0000.0614] # ARABIC SIGN TAKHALLUS +0615 ; [.0000.0000.0000.0615] # ARABIC SMALL HIGH TAH +061B ; [*023F.0020.0002.061B] # ARABIC SEMICOLON +061E ; [*0243.0020.0002.061E] # ARABIC TRIPLE DOT PUNCTUATION MARK +061F ; [*025F.0020.0002.061F] # ARABIC QUESTION MARK +0640 ; [*020B.0020.0002.0640] # ARABIC TATWEEL +066A ; [*0307.0020.0002.066A] # ARABIC PERCENT SIGN +066B ; [*0236.0020.0002.066B] # ARABIC DECIMAL SEPARATOR +066C ; [*0237.0020.0002.066C] # ARABIC THOUSANDS SEPARATOR +066D ; [*02FE.0020.0002.066D] # ARABIC FIVE POINTED STAR +06D4 ; [*0268.0020.0002.06D4] # ARABIC FULL STOP +06D6 ; [.0000.0000.0000.06D6] # ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA +06D7 ; [.0000.0000.0000.06D7] # ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA +06D8 ; [.0000.0000.0000.06D8] # ARABIC SMALL HIGH MEEM INITIAL FORM +06D9 ; [.0000.0000.0000.06D9] # ARABIC SMALL HIGH LAM ALEF +06DA ; [.0000.0000.0000.06DA] # ARABIC SMALL HIGH JEEM +06DB ; [.0000.0000.0000.06DB] # ARABIC SMALL HIGH THREE DOTS +06DC ; [.0000.0000.0000.06DC] # ARABIC SMALL HIGH SEEN +06DD ; [.0000.0000.0000.06DD] # ARABIC END OF AYAH +06DE ; [.0000.0000.0000.06DE] # ARABIC START OF RUB EL HIZB +06DF ; [.0000.0000.0000.06DF] # ARABIC SMALL HIGH ROUNDED ZERO +06E0 ; [.0000.0000.0000.06E0] # ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO +06E1 ; [.0000.0000.0000.06E1] # ARABIC SMALL HIGH DOTLESS HEAD OF KHAH +06E2 ; [.0000.0000.0000.06E2] # ARABIC SMALL HIGH MEEM ISOLATED FORM +06E3 ; [.0000.0000.0000.06E3] # ARABIC SMALL LOW SEEN +06E4 ; [.0000.0000.0000.06E4] # ARABIC SMALL HIGH MADDA +06E7 ; [.0000.0000.0000.06E7] # ARABIC SMALL HIGH YEH +06E8 ; [.0000.0000.0000.06E8] # ARABIC SMALL HIGH NOON +06E9 ; [*03C3.0020.0002.06E9] # ARABIC PLACE OF SAJDAH +06EA ; [.0000.0000.0000.06EA] # ARABIC EMPTY CENTRE LOW STOP +06EB ; [.0000.0000.0000.06EB] # ARABIC EMPTY CENTRE HIGH STOP +06EC ; [.0000.0000.0000.06EC] # ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE +06ED ; [.0000.0000.0000.06ED] # ARABIC SMALL LOW MEEM +0700 ; [*0282.0020.0002.0700] # SYRIAC END OF PARAGRAPH +0701 ; [*0269.0020.0002.0701] # SYRIAC SUPRALINEAR FULL STOP +0702 ; [*026A.0020.0002.0702] # SYRIAC SUBLINEAR FULL STOP +0703 ; [*0244.0020.0002.0703] # SYRIAC SUPRALINEAR COLON +0704 ; [*0245.0020.0002.0704] # SYRIAC SUBLINEAR COLON +0705 ; [*0246.0020.0002.0705] # SYRIAC HORIZONTAL COLON +0706 ; [*0247.0020.0002.0706] # SYRIAC COLON SKEWED LEFT +0707 ; [*0248.0020.0002.0707] # SYRIAC COLON SKEWED RIGHT +0708 ; [*0249.0020.0002.0708] # SYRIAC SUPRALINEAR COLON SKEWED LEFT +0709 ; [*0260.0020.0002.0709] # SYRIAC SUBLINEAR COLON SKEWED RIGHT +070A ; [*0337.0020.0002.070A] # SYRIAC CONTRACTION +070B ; [*0338.0020.0002.070B] # SYRIAC HARKLEAN OBELUS +070C ; [*0339.0020.0002.070C] # SYRIAC HARKLEAN METOBELUS +070D ; [*033A.0020.0002.070D] # SYRIAC HARKLEAN ASTERISCUS +07F6 ; [*03C5.0020.0002.07F6] # NKO SYMBOL OO DENNEN +07F7 ; [*0283.0020.0002.07F7] # NKO SYMBOL GBAKURUNEN +07F8 ; [*0238.0020.0002.07F8] # NKO COMMA +07F9 ; [*025A.0020.0002.07F9] # NKO EXCLAMATION MARK +07FA ; [*020C.0020.0002.07FA] # NKO LAJANYALAN +0964 ; [*0274.0020.0002.0964] # DEVANAGARI DANDA +0965 ; [*0275.0020.0002.0965] # DEVANAGARI DOUBLE DANDA +0970 ; [*033D.0020.0002.0970] # DEVANAGARI ABBREVIATION SIGN +09F8 ; [*0F13.0020.0002.09F8] # BENGALI CURRENCY NUMERATOR ONE LESS THAN THE DENOMINATOR +09F9 ; [*0F14.0020.0002.09F9] # BENGALI CURRENCY DENOMINATOR SIXTEEN +09FA ; [*03C6.0020.0002.09FA] # BENGALI ISSHAR +0B70 ; [*03C7.0020.0002.0B70] # ORIYA ISSHAR +0BF0 ; [*0F15.0020.0002.0BF0] # TAMIL NUMBER TEN +0BF1 ; [*0F16.0020.0002.0BF1] # TAMIL NUMBER ONE HUNDRED +0BF2 ; [*0F17.0020.0002.0BF2] # TAMIL NUMBER ONE THOUSAND +0BF3 ; [*03C8.0020.0002.0BF3] # TAMIL DAY SIGN +0BF4 ; [*03C9.0020.0002.0BF4] # TAMIL MONTH SIGN +0BF5 ; [*03CA.0020.0002.0BF5] # TAMIL YEAR SIGN +0BF6 ; [*03CB.0020.0002.0BF6] # TAMIL DEBIT SIGN +0BF7 ; [*03CC.0020.0002.0BF7] # TAMIL CREDIT SIGN +0BF8 ; [*03CD.0020.0002.0BF8] # TAMIL AS ABOVE SIGN +0BFA ; [*03CE.0020.0002.0BFA] # TAMIL NUMBER SIGN +0CF1 ; [*03CF.0020.0002.0CF1] # KANNADA SIGN JIHVAMULIYA +0CF2 ; [*03D0.0020.0002.0CF2] # KANNADA SIGN UPADHMANIYA +0DF4 ; [*033E.0020.0002.0DF4] # SINHALA PUNCTUATION KUNDDALIYA +0E4F ; [*03D5.0020.0002.0E4F] # THAI CHARACTER FONGMAN +0E5A ; [*033F.0020.0002.0E5A] # THAI CHARACTER ANGKHANKHU +0E5B ; [*0340.0020.0002.0E5B] # THAI CHARACTER KHOMUT +0F01 ; [*03D6.0020.0002.0F01] # TIBETAN MARK GTER YIG MGO TRUNCATED A +0F02 ; [*03D7.0020.0002.0F02] # TIBETAN MARK GTER YIG MGO -UM RNAM BCAD MA +0F03 ; [*03D8.0020.0002.0F03] # TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA +0F04 ; [*0341.0020.0002.0F04] # TIBETAN MARK INITIAL YIG MGO MDUN MA +0F05 ; [*0342.0020.0002.0F05] # TIBETAN MARK CLOSING YIG MGO SGAB MA +0F06 ; [*0343.0020.0002.0F06] # TIBETAN MARK CARET YIG MGO PHUR SHAD MA +0F07 ; [*0344.0020.0002.0F07] # TIBETAN MARK YIG MGO TSHEG SHAD MA +0F08 ; [*0345.0020.0002.0F08] # TIBETAN MARK SBRUL SHAD +0F09 ; [*0346.0020.0002.0F09] # TIBETAN MARK BSKUR YIG MGO +0F0A ; [*0347.0020.0002.0F0A] # TIBETAN MARK BKA- SHOG YIG MGO +0F0B ; [*034A.0020.0002.0F0B] # TIBETAN MARK INTERSYLLABIC TSHEG +0F0C ; [*034A.0020.001B.0F0C] # TIBETAN MARK DELIMITER TSHEG BSTAR; QQK +0F0D ; [*034B.0020.0002.0F0D] # TIBETAN MARK SHAD +0F0E ; [*034C.0020.0002.0F0E] # TIBETAN MARK NYIS SHAD +0F0F ; [*034D.0020.0002.0F0F] # TIBETAN MARK TSHEG SHAD +0F10 ; [*034E.0020.0002.0F10] # TIBETAN MARK NYIS TSHEG SHAD +0F11 ; [*034F.0020.0002.0F11] # TIBETAN MARK RIN CHEN SPUNGS SHAD +0F12 ; [*0350.0020.0002.0F12] # TIBETAN MARK RGYA GRAM SHAD +0F13 ; [*03D9.0020.0002.0F13] # TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN +0F14 ; [*0251.0020.0002.0F14] # TIBETAN MARK GTER TSHEG +0F15 ; [*03DA.0020.0002.0F15] # TIBETAN LOGOTYPE SIGN CHAD RTAGS +0F16 ; [*03DB.0020.0002.0F16] # TIBETAN LOGOTYPE SIGN LHAG RTAGS +0F17 ; [*03DC.0020.0002.0F17] # TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS +0F18 ; [.0000.0000.0000.0F18] # TIBETAN ASTROLOGICAL SIGN -KHYUD PA +0F19 ; [.0000.0000.0000.0F19] # TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS +0F1A ; [*03DD.0020.0002.0F1A] # TIBETAN SIGN RDEL DKAR GCIG +0F1B ; [*03DE.0020.0002.0F1B] # TIBETAN SIGN RDEL DKAR GNYIS +0F1C ; [*03DF.0020.0002.0F1C] # TIBETAN SIGN RDEL DKAR GSUM +0F1D ; [*03E0.0020.0002.0F1D] # TIBETAN SIGN RDEL NAG GCIG +0F1E ; [*03E1.0020.0002.0F1E] # TIBETAN SIGN RDEL NAG GNYIS +0F1F ; [*03E2.0020.0002.0F1F] # TIBETAN SIGN RDEL DKAR RDEL NAG +0F34 ; [*03E3.0020.0002.0F34] # TIBETAN MARK BSDUS RTAGS +0F35 ; [.0000.0000.0000.0F35] # TIBETAN MARK NGAS BZUNG NYI ZLA +0F36 ; [*03E4.0020.0002.0F36] # TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN +0F37 ; [.0000.0000.0000.0F37] # TIBETAN MARK NGAS BZUNG SGOR RTAGS +0F38 ; [*03E5.0020.0002.0F38] # TIBETAN MARK CHE MGO +0F3A ; [*02B7.0020.0002.0F3A] # TIBETAN MARK GUG RTAGS GYON +0F3B ; [*02B8.0020.0002.0F3B] # TIBETAN MARK GUG RTAGS GYAS +0F3C ; [*02B9.0020.0002.0F3C] # TIBETAN MARK ANG KHANG GYON +0F3D ; [*02BA.0020.0002.0F3D] # TIBETAN MARK ANG KHANG GYAS +0F3E ; [*03E6.0020.0002.0F3E] # TIBETAN SIGN YAR TSHES +0F3F ; [*03E7.0020.0002.0F3F] # TIBETAN SIGN MAR TSHES +0F82 ; [.0000.0000.0000.0F82] # TIBETAN SIGN NYI ZLA NAA DA +0F83 ; [.0000.0000.0000.0F83] # TIBETAN SIGN SNA LDAN +0F85 ; [*0351.0020.0002.0F85] # TIBETAN MARK PALUTA +0F86 ; [.0000.0000.0000.0F86] # TIBETAN SIGN LCI RTAGS +0F87 ; [.0000.0000.0000.0F87] # TIBETAN SIGN YANG RTAGS +0FBE ; [*03E8.0020.0002.0FBE] # TIBETAN KU RU KHA +0FBF ; [*03E9.0020.0002.0FBF] # TIBETAN KU RU KHA BZHI MIG CAN +0FC0 ; [*03EA.0020.0002.0FC0] # TIBETAN CANTILLATION SIGN HEAVY BEAT +0FC1 ; [*03EB.0020.0002.0FC1] # TIBETAN CANTILLATION SIGN LIGHT BEAT +0FC2 ; [*03EC.0020.0002.0FC2] # TIBETAN CANTILLATION SIGN CANG TE-U +0FC3 ; [*03ED.0020.0002.0FC3] # TIBETAN CANTILLATION SIGN SBUB -CHAL +0FC4 ; [*03EE.0020.0002.0FC4] # TIBETAN SYMBOL DRIL BU +0FC5 ; [*03EF.0020.0002.0FC5] # TIBETAN SYMBOL RDO RJE +0FC6 ; [.0000.0000.0000.0FC6] # TIBETAN SYMBOL PADMA GDAN +0FC7 ; [*03F0.0020.0002.0FC7] # TIBETAN SYMBOL RDO RJE RGYA GRAM +0FC8 ; [*03F1.0020.0002.0FC8] # TIBETAN SYMBOL PHUR PA +0FC9 ; [*03F2.0020.0002.0FC9] # TIBETAN SYMBOL NOR BU +0FCA ; [*03F3.0020.0002.0FCA] # TIBETAN SYMBOL NOR BU NYIS -KHYIL +0FCB ; [*03F4.0020.0002.0FCB] # TIBETAN SYMBOL NOR BU GSUM -KHYIL +0FCC ; [*03F5.0020.0002.0FCC] # TIBETAN SYMBOL NOR BU BZHI -KHYIL +0FCF ; [*03F6.0020.0002.0FCF] # TIBETAN SIGN RDEL NAG GSUM +0FD0 ; [*0348.0020.0002.0FD0] # TIBETAN MARK BSKA- SHOG GI MGO RGYAN +0FD1 ; [*0349.0020.0002.0FD1] # TIBETAN MARK MNYAM YIG GI MGO RGYAN +104A ; [*027A.0020.0002.104A] # MYANMAR SIGN LITTLE SECTION +104B ; [*027B.0020.0002.104B] # MYANMAR SIGN SECTION +104C ; [*0353.0020.0002.104C] # MYANMAR SYMBOL LOCATIVE +104D ; [*0354.0020.0002.104D] # MYANMAR SYMBOL COMPLETED +104E ; [*0355.0020.0002.104E] # MYANMAR SYMBOL AFOREMENTIONED +104F ; [*0356.0020.0002.104F] # MYANMAR SYMBOL GENITIVE +10FB ; [*0284.0020.0002.10FB] # GEORGIAN PARAGRAPH SEPARATOR +1360 ; [*0285.0020.0002.1360] # ETHIOPIC SECTION MARK +1361 ; [*024A.0020.0002.1361] # ETHIOPIC WORDSPACE +1362 ; [*026B.0020.0002.1362] # ETHIOPIC FULL STOP +1363 ; [*024B.0020.0002.1363] # ETHIOPIC COMMA +1364 ; [*024C.0020.0002.1364] # ETHIOPIC SEMICOLON +1365 ; [*024D.0020.0002.1365] # ETHIOPIC COLON +1366 ; [*024E.0020.0002.1366] # ETHIOPIC PREFACE COLON +1367 ; [*0261.0020.0002.1367] # ETHIOPIC QUESTION MARK +1368 ; [*0286.0020.0002.1368] # ETHIOPIC PARAGRAPH SEPARATOR +1372 ; [*0F18.0020.0002.1372] # ETHIOPIC NUMBER TEN +1373 ; [*0F19.0020.0002.1373] # ETHIOPIC NUMBER TWENTY +1374 ; [*0F1A.0020.0002.1374] # ETHIOPIC NUMBER THIRTY +1375 ; [*0F1B.0020.0002.1375] # ETHIOPIC NUMBER FORTY +1376 ; [*0F1C.0020.0002.1376] # ETHIOPIC NUMBER FIFTY +1377 ; [*0F1D.0020.0002.1377] # ETHIOPIC NUMBER SIXTY +1378 ; [*0F1E.0020.0002.1378] # ETHIOPIC NUMBER SEVENTY +1379 ; [*0F1F.0020.0002.1379] # ETHIOPIC NUMBER EIGHTY +137A ; [*0F20.0020.0002.137A] # ETHIOPIC NUMBER NINETY +137B ; [*0F21.0020.0002.137B] # ETHIOPIC NUMBER HUNDRED +137C ; [*0F22.0020.0002.137C] # ETHIOPIC NUMBER TEN THOUSAND +1390 ; [*0398.0020.0002.1390] # ETHIOPIC TONAL MARK YIZET +1391 ; [*0399.0020.0002.1391] # ETHIOPIC TONAL MARK DERET +1392 ; [*039A.0020.0002.1392] # ETHIOPIC TONAL MARK RIKRIK +1393 ; [*039B.0020.0002.1393] # ETHIOPIC TONAL MARK SHORT RIKRIK +1394 ; [*039C.0020.0002.1394] # ETHIOPIC TONAL MARK DIFAT +1395 ; [*039D.0020.0002.1395] # ETHIOPIC TONAL MARK KENAT +1396 ; [*039E.0020.0002.1396] # ETHIOPIC TONAL MARK CHIRET +1397 ; [*039F.0020.0002.1397] # ETHIOPIC TONAL MARK HIDET +1398 ; [*03A0.0020.0002.1398] # ETHIOPIC TONAL MARK DERET-HIDET +1399 ; [*03A1.0020.0002.1399] # ETHIOPIC TONAL MARK KURT +166D ; [*035B.0020.0002.166D] # CANADIAN SYLLABICS CHI SIGN +166E ; [*026E.0020.0002.166E] # CANADIAN SYLLABICS FULL STOP +1680 ; [*020A.0020.0002.1680] # OGHAM SPACE MARK +169B ; [*02BB.0020.0002.169B] # OGHAM FEATHER MARK +169C ; [*02BC.0020.0002.169C] # OGHAM REVERSED FEATHER MARK +16EB ; [*0254.0020.0002.16EB] # RUNIC SINGLE PUNCTUATION +16EC ; [*0255.0020.0002.16EC] # RUNIC MULTIPLE PUNCTUATION +16ED ; [*0256.0020.0002.16ED] # RUNIC CROSS PUNCTUATION +1735 ; [*0278.0020.0002.1735] # PHILIPPINE SINGLE PUNCTUATION +1736 ; [*0279.0020.0002.1736] # PHILIPPINE DOUBLE PUNCTUATION +17D4 ; [*027C.0020.0002.17D4] # KHMER SIGN KHAN +17D5 ; [*027D.0020.0002.17D5] # KHMER SIGN BARIYOOSAN +17D6 ; [*0252.0020.0002.17D6] # KHMER SIGN CAMNUC PII KUUH +17D7 ; [*0357.0020.0002.17D7] # KHMER SIGN LEK TOO +17D8 ; [*0358.0020.0002.17D8] # KHMER SIGN BEYYAL +17D9 ; [*0359.0020.0002.17D9] # KHMER SIGN PHNAEK MUAN +17DA ; [*035A.0020.0002.17DA] # KHMER SIGN KOOMUUT +1800 ; [*033B.0020.0002.1800] # MONGOLIAN BIRGA +1801 ; [*0267.0020.0002.1801] # MONGOLIAN ELLIPSIS +1802 ; [*0239.0020.0002.1802] # MONGOLIAN COMMA +1803 ; [*026C.0020.0002.1803] # MONGOLIAN FULL STOP +1804 ; [*024F.0020.0002.1804] # MONGOLIAN COLON +1805 ; [*0250.0020.0002.1805] # MONGOLIAN FOUR DOTS +1806 ; [*0225.0020.0002.1806] # MONGOLIAN TODO SOFT HYPHEN +1807 ; [*0226.0020.0002.1807] # MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER +1808 ; [*023A.0020.0002.1808] # MONGOLIAN MANCHU COMMA +1809 ; [*026D.0020.0002.1809] # MONGOLIAN MANCHU FULL STOP +180A ; [*033C.0020.0002.180A] # MONGOLIAN NIRUGU +1940 ; [*0352.0020.0002.1940] # LIMBU SIGN LOO +1944 ; [*025B.0020.0002.1944] # LIMBU EXCLAMATION MARK +1945 ; [*0262.0020.0002.1945] # LIMBU QUESTION MARK +19E0 ; [*03F7.0020.0002.19E0] # KHMER SYMBOL PATHAMASAT +19E1 ; [*03F8.0020.0002.19E1] # KHMER SYMBOL MUOY KOET +19E2 ; [*03F9.0020.0002.19E2] # KHMER SYMBOL PII KOET +19E3 ; [*03FA.0020.0002.19E3] # KHMER SYMBOL BEI KOET +19E4 ; [*03FB.0020.0002.19E4] # KHMER SYMBOL BUON KOET +19E5 ; [*03FC.0020.0002.19E5] # KHMER SYMBOL PRAM KOET +19E6 ; [*03FD.0020.0002.19E6] # KHMER SYMBOL PRAM-MUOY KOET +19E7 ; [*03FE.0020.0002.19E7] # KHMER SYMBOL PRAM-PII KOET +19E8 ; [*03FF.0020.0002.19E8] # KHMER SYMBOL PRAM-BEI KOET +19E9 ; [*0400.0020.0002.19E9] # KHMER SYMBOL PRAM-BUON KOET +19EA ; [*0401.0020.0002.19EA] # KHMER SYMBOL DAP KOET +19EB ; [*0402.0020.0002.19EB] # KHMER SYMBOL DAP-MUOY KOET +19EC ; [*0403.0020.0002.19EC] # KHMER SYMBOL DAP-PII KOET +19ED ; [*0404.0020.0002.19ED] # KHMER SYMBOL DAP-BEI KOET +19EE ; [*0405.0020.0002.19EE] # KHMER SYMBOL DAP-BUON KOET +19EF ; [*0406.0020.0002.19EF] # KHMER SYMBOL DAP-PRAM KOET +19F0 ; [*0407.0020.0002.19F0] # KHMER SYMBOL TUTEYASAT +19F1 ; [*0408.0020.0002.19F1] # KHMER SYMBOL MUOY ROC +19F2 ; [*0409.0020.0002.19F2] # KHMER SYMBOL PII ROC +19F3 ; [*040A.0020.0002.19F3] # KHMER SYMBOL BEI ROC +19F4 ; [*040B.0020.0002.19F4] # KHMER SYMBOL BUON ROC +19F5 ; [*040C.0020.0002.19F5] # KHMER SYMBOL PRAM ROC +19F6 ; [*040D.0020.0002.19F6] # KHMER SYMBOL PRAM-MUOY ROC +19F7 ; [*040E.0020.0002.19F7] # KHMER SYMBOL PRAM-PII ROC +19F8 ; [*040F.0020.0002.19F8] # KHMER SYMBOL PRAM-BEI ROC +19F9 ; [*0410.0020.0002.19F9] # KHMER SYMBOL PRAM-BUON ROC +19FA ; [*0411.0020.0002.19FA] # KHMER SYMBOL DAP ROC +19FB ; [*0412.0020.0002.19FB] # KHMER SYMBOL DAP-MUOY ROC +19FC ; [*0413.0020.0002.19FC] # KHMER SYMBOL DAP-PII ROC +19FD ; [*0414.0020.0002.19FD] # KHMER SYMBOL DAP-BEI ROC +19FE ; [*0415.0020.0002.19FE] # KHMER SYMBOL DAP-BUON ROC +19FF ; [*0416.0020.0002.19FF] # KHMER SYMBOL DAP-PRAM ROC +1A1E ; [*0287.0020.0002.1A1E] # BUGINESE PALLAWA +1A1F ; [*0288.0020.0002.1A1F] # BUGINESE END OF SECTION +1B5A ; [*0289.0020.0002.1B5A] # BALINESE PANTI +1B5B ; [*028A.0020.0002.1B5B] # BALINESE PAMADA +1B5C ; [*026F.0020.0002.1B5C] # BALINESE WINDU +1B5D ; [*0253.0020.0002.1B5D] # BALINESE CARIK PAMUNGKAH +1B5E ; [*027E.0020.0002.1B5E] # BALINESE CARIK SIKI +1B5F ; [*027F.0020.0002.1B5F] # BALINESE CARIK PAREREN +1B60 ; [*0224.0020.0002.1B60] # BALINESE PAMENENG +1B61 ; [*0417.0020.0002.1B61] # BALINESE MUSICAL SYMBOL DONG +1B62 ; [*0418.0020.0002.1B62] # BALINESE MUSICAL SYMBOL DENG +1B63 ; [*0419.0020.0002.1B63] # BALINESE MUSICAL SYMBOL DUNG +1B64 ; [*041A.0020.0002.1B64] # BALINESE MUSICAL SYMBOL DANG +1B65 ; [*041B.0020.0002.1B65] # BALINESE MUSICAL SYMBOL DANG SURANG +1B66 ; [*041C.0020.0002.1B66] # BALINESE MUSICAL SYMBOL DING +1B67 ; [*041D.0020.0002.1B67] # BALINESE MUSICAL SYMBOL DAENG +1B68 ; [*041E.0020.0002.1B68] # BALINESE MUSICAL SYMBOL DEUNG +1B69 ; [*041F.0020.0002.1B69] # BALINESE MUSICAL SYMBOL DAING +1B6A ; [*0420.0020.0002.1B6A] # BALINESE MUSICAL SYMBOL DANG GEDE +1B6B ; [.0000.0000.0000.1B6B] # BALINESE MUSICAL SYMBOL COMBINING TEGEH +1B6C ; [.0000.0000.0000.1B6C] # BALINESE MUSICAL SYMBOL COMBINING ENDEP +1B6D ; [.0000.0000.0000.1B6D] # BALINESE MUSICAL SYMBOL COMBINING KEMPUL +1B6E ; [.0000.0000.0000.1B6E] # BALINESE MUSICAL SYMBOL COMBINING KEMPLI +1B6F ; [.0000.0000.0000.1B6F] # BALINESE MUSICAL SYMBOL COMBINING JEGOGAN +1B70 ; [.0000.0000.0000.1B70] # BALINESE MUSICAL SYMBOL COMBINING KEMPUL WITH JEGOGAN +1B71 ; [.0000.0000.0000.1B71] # BALINESE MUSICAL SYMBOL COMBINING KEMPLI WITH JEGOGAN +1B72 ; [.0000.0000.0000.1B72] # BALINESE MUSICAL SYMBOL COMBINING BENDE +1B73 ; [.0000.0000.0000.1B73] # BALINESE MUSICAL SYMBOL COMBINING GONG +1B74 ; [*0421.0020.0002.1B74] # BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG +1B75 ; [*0422.0020.0002.1B75] # BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DAG +1B76 ; [*0423.0020.0002.1B76] # BALINESE MUSICAL SYMBOL RIGHT-HAND CLOSED TUK +1B77 ; [*0424.0020.0002.1B77] # BALINESE MUSICAL SYMBOL RIGHT-HAND CLOSED TAK +1B78 ; [*0425.0020.0002.1B78] # BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PANG +1B79 ; [*0426.0020.0002.1B79] # BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PUNG +1B7A ; [*0427.0020.0002.1B7A] # BALINESE MUSICAL SYMBOL LEFT-HAND CLOSED PLAK +1B7B ; [*0428.0020.0002.1B7B] # BALINESE MUSICAL SYMBOL LEFT-HAND CLOSED PLUK +1B7C ; [*0429.0020.0002.1B7C] # BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING +1FBD ; [*0218.0020.0002.1FBD] # GREEK KORONIS; QQC +1FBF ; [*0218.0020.0002.1FBF] # GREEK PSILI +1FC0 ; [*021E.0020.0002.1FC0] # GREEK PERISPOMENI +1FC1 ; [*0215.0020.0002.00A8][.0000.0045.0002.0342] # GREEK DIALYTIKA AND PERISPOMENI; QQCM +1FCD ; [*0218.0020.0002.1FBF][.0000.0035.0002.0300] # GREEK PSILI AND VARIA; QQCM +1FCE ; [*0218.0020.0002.1FBF][.0000.0032.0002.0301] # GREEK PSILI AND OXIA; QQCM +1FCF ; [*0218.0020.0002.1FBF][.0000.0045.0002.0342] # GREEK PSILI AND PERISPOMENI; QQCM +1FDD ; [*0219.0020.0002.1FFE][.0000.0035.0002.0300] # GREEK DASIA AND VARIA; QQCM +1FDE ; [*0219.0020.0002.1FFE][.0000.0032.0002.0301] # GREEK DASIA AND OXIA; QQCM +1FDF ; [*0219.0020.0002.1FFE][.0000.0045.0002.0342] # GREEK DASIA AND PERISPOMENI; QQCM +1FED ; [*0215.0020.0002.00A8][.0000.0035.0002.0300] # GREEK DIALYTIKA AND VARIA; QQCM +1FEE ; [*0215.0020.0002.00A8][.0000.0032.0002.0301] # GREEK DIALYTIKA AND OXIA; QQCM +1FEF ; [*020D.0020.0002.1FEF] # GREEK VARIA; QQC +1FFD ; [*020E.0020.0002.1FFD] # GREEK OXIA; QQC +1FFE ; [*0219.0020.0002.1FFE] # GREEK DASIA +2000 ; [*0209.0020.0004.2000] # EN QUAD; QQK +2001 ; [*0209.0020.0004.2001] # EM QUAD; QQK +2002 ; [*0209.0020.0004.2002] # EN SPACE; QQK +2003 ; [*0209.0020.0004.2003] # EM SPACE; QQK +2004 ; [*0209.0020.0004.2004] # THREE-PER-EM SPACE; QQK +2005 ; [*0209.0020.0004.2005] # FOUR-PER-EM SPACE; QQK +2006 ; [*0209.0020.0004.2006] # SIX-PER-EM SPACE; QQK +2007 ; [*0209.0020.001B.2007] # FIGURE SPACE; QQK +2008 ; [*0209.0020.0004.2008] # PUNCTUATION SPACE; QQK +2009 ; [*0209.0020.0004.2009] # THIN SPACE; QQK +200A ; [*0209.0020.0004.200A] # HAIR SPACE; QQK +2010 ; [*0227.0020.0002.2010] # HYPHEN +2011 ; [*0227.0020.001B.2011] # NON-BREAKING HYPHEN; QQK +2012 ; [*0228.0020.0002.2012] # FIGURE DASH +2013 ; [*0229.0020.0002.2013] # EN DASH +2014 ; [*022A.0020.0002.2014] # EM DASH +2015 ; [*022B.0020.0002.2015] # HORIZONTAL BAR +2016 ; [*04C2.0020.0002.2016] # DOUBLE VERTICAL LINE +2017 ; [*021D.0020.0002.2017] # DOUBLE LOW LINE +2018 ; [*02A1.0020.0002.2018] # LEFT SINGLE QUOTATION MARK +2019 ; [*02A2.0020.0002.2019] # RIGHT SINGLE QUOTATION MARK +201A ; [*02A3.0020.0002.201A] # SINGLE LOW-9 QUOTATION MARK +201B ; [*02A4.0020.0002.201B] # SINGLE HIGH-REVERSED-9 QUOTATION MARK +201C ; [*02A8.0020.0002.201C] # LEFT DOUBLE QUOTATION MARK +201D ; [*02A9.0020.0002.201D] # RIGHT DOUBLE QUOTATION MARK +201E ; [*02AA.0020.0002.201E] # DOUBLE LOW-9 QUOTATION MARK +201F ; [*02AB.0020.0002.201F] # DOUBLE HIGH-REVERSED-9 QUOTATION MARK +2020 ; [*030B.0020.0002.2020] # DAGGER +2021 ; [*030C.0020.0002.2021] # DOUBLE DAGGER +2022 ; [*030D.0020.0002.2022] # BULLET +2023 ; [*030E.0020.0002.2023] # TRIANGULAR BULLET +2024 ; [*0266.0020.0004.2024] # ONE DOT LEADER; QQK +2025 ; [*0266.0020.0004.2025][*0266.0020.0004.2025] # TWO DOT LEADER; QQKN +2026 ; [*0266.0020.0004.2026][*0266.0020.0004.2026][*0266.0020.001F.2026] # HORIZONTAL ELLIPSIS; QQKN +2027 ; [*030F.0020.0002.2027] # HYPHENATION POINT +2028 ; [*0207.0020.0002.2028] # LINE SEPARATOR +2029 ; [*0208.0020.0002.2029] # PARAGRAPH SEPARATOR +202F ; [*0209.0020.001B.202F] # NARROW NO-BREAK SPACE; QQK +2030 ; [*0308.0020.0002.2030] # PER MILLE SIGN +2031 ; [*0309.0020.0002.2031] # PER TEN THOUSAND SIGN +2032 ; [*0313.0020.0002.2032] # PRIME +2033 ; [*0313.0020.0004.2033][*0313.0020.0004.2033] # DOUBLE PRIME; QQKN +2034 ; [*0313.0020.0004.2034][*0313.0020.0004.2034][*0313.0020.001F.2034] # TRIPLE PRIME; QQKN +2035 ; [*0314.0020.0002.2035] # REVERSED PRIME +2036 ; [*0314.0020.0004.2036][*0314.0020.0004.2036] # REVERSED DOUBLE PRIME; QQKN +2037 ; [*0314.0020.0004.2037][*0314.0020.0004.2037][*0314.0020.001F.2037] # REVERSED TRIPLE PRIME; QQKN +2038 ; [*0317.0020.0002.2038] # CARET +2039 ; [*02A5.0020.0002.2039] # SINGLE LEFT-POINTING ANGLE QUOTATION MARK +203A ; [*02A6.0020.0002.203A] # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +203B ; [*0318.0020.0002.203B] # REFERENCE MARK +203C ; [*0257.0020.0004.203C][*0257.0020.0004.203C] # DOUBLE EXCLAMATION MARK; QQKN +203D ; [*0265.0020.0002.203D] # INTERROBANG +203E ; [*0212.0020.0002.203E] # OVERLINE +203F ; [*0319.0020.0002.203F] # UNDERTIE +2040 ; [*031B.0020.0002.2040] # CHARACTER TIE +2041 ; [*031D.0020.0002.2041] # CARET INSERTION POINT +2042 ; [*031E.0020.0002.2042] # ASTERISM +2043 ; [*0310.0020.0002.2043] # HYPHEN BULLET +2044 ; [*0300.0020.0002.2044] # FRACTION SLASH +2045 ; [*02BD.0020.0002.2045] # LEFT SQUARE BRACKET WITH QUILL +2046 ; [*02BE.0020.0002.2046] # RIGHT SQUARE BRACKET WITH QUILL +2047 ; [*025C.0020.0004.2047][*025C.0020.0004.2047] # DOUBLE QUESTION MARK; QQKN +2048 ; [*025C.0020.0004.2048][*0257.0020.0004.2048] # QUESTION EXCLAMATION MARK; QQKN +2049 ; [*0257.0020.0004.2049][*025C.0020.0004.2049] # EXCLAMATION QUESTION MARK; QQKN +204A ; [*0304.0020.0002.204A] # TIRONIAN SIGN ET +204B ; [*02F7.0020.0002.204B] # REVERSED PILCROW SIGN +204C ; [*0311.0020.0002.204C] # BLACK LEFTWARDS BULLET +204D ; [*0312.0020.0002.204D] # BLACK RIGHTWARDS BULLET +204E ; [*02FC.0020.0002.204E] # LOW ASTERISK +204F ; [*0240.0020.0002.204F] # REVERSED SEMICOLON +2050 ; [*031C.0020.0002.2050] # CLOSE UP +2051 ; [*02FD.0020.0002.2051] # TWO ASTERISKS ALIGNED VERTICALLY +2052 ; [*030A.0020.0002.2052] # COMMERCIAL MINUS SIGN +2053 ; [*022C.0020.0002.2053] # SWUNG DASH +2054 ; [*031A.0020.0002.2054] # INVERTED UNDERTIE +2055 ; [*028B.0020.0002.2055] # FLOWER PUNCTUATION MARK +2056 ; [*028C.0020.0002.2056] # THREE DOT PUNCTUATION +2057 ; [*0313.0020.0004.2057][*0313.0020.0004.2057][*0313.0020.001F.2057][*0313.0020.001F.2057] # QUADRUPLE PRIME; QQKN +2058 ; [*028D.0020.0002.2058] # FOUR DOT PUNCTUATION +2059 ; [*028E.0020.0002.2059] # FIVE DOT PUNCTUATION +205A ; [*028F.0020.0002.205A] # TWO DOT PUNCTUATION +205B ; [*0290.0020.0002.205B] # FOUR DOT MARK +205C ; [*0291.0020.0002.205C] # DOTTED CROSS +205D ; [*0292.0020.0002.205D] # TRICOLON +205E ; [*0293.0020.0002.205E] # VERTICAL FOUR DOTS +205F ; [*0209.0020.0004.205F] # MEDIUM MATHEMATICAL SPACE; QQK +2061 ; [.0000.0000.0000.2061] # FUNCTION APPLICATION +2062 ; [.0000.0000.0000.2062] # INVISIBLE TIMES +2063 ; [.0000.0000.0000.2063] # INVISIBLE SEPARATOR +207A ; [*04B8.0020.0014.207A] # SUPERSCRIPT PLUS SIGN; QQK +207B ; [*04C4.0020.0014.207B] # SUPERSCRIPT MINUS; QQK +207C ; [*04BD.0020.0014.207C] # SUPERSCRIPT EQUALS SIGN; QQK +207D ; [*02B1.0020.0014.207D] # SUPERSCRIPT LEFT PARENTHESIS; QQK +207E ; [*02B2.0020.0014.207E] # SUPERSCRIPT RIGHT PARENTHESIS; QQK +208A ; [*04B8.0020.0015.208A] # SUBSCRIPT PLUS SIGN; QQK +208B ; [*04C4.0020.0015.208B] # SUBSCRIPT MINUS; QQK +208C ; [*04BD.0020.0015.208C] # SUBSCRIPT EQUALS SIGN; QQK +208D ; [*02B1.0020.0015.208D] # SUBSCRIPT LEFT PARENTHESIS; QQK +208E ; [*02B2.0020.0015.208E] # SUBSCRIPT RIGHT PARENTHESIS; QQK +2104 ; [*042A.0020.0002.2104] # CENTRE LINE SYMBOL +2108 ; [*042B.0020.0002.2108] # SCRUPLE +2114 ; [*042C.0020.0002.2114] # L B BAR SYMBOL +2117 ; [*042D.0020.0002.2117] # SOUND RECORDING COPYRIGHT +2118 ; [*042E.0020.0002.2118] # SCRIPT CAPITAL P +211E ; [*042F.0020.0002.211E] # PRESCRIPTION TAKE +211F ; [*0430.0020.0002.211F] # RESPONSE +2123 ; [*0431.0020.0002.2123] # VERSICLE +2125 ; [*0432.0020.0002.2125] # OUNCE SIGN +2127 ; [*0433.0020.0002.2127] # INVERTED OHM SIGN +2129 ; [*0434.0020.0002.2129] # TURNED GREEK SMALL LETTER IOTA +212E ; [*0435.0020.0002.212E] # ESTIMATED SYMBOL +213A ; [*0436.0020.0002.213A] # ROTATED CAPITAL Q +2140 ; [*04B7.0020.0005.2140] # DOUBLE-STRUCK N-ARY SUMMATION; QQK +2141 ; [*0437.0020.0002.2141] # TURNED SANS-SERIF CAPITAL G +2142 ; [*0438.0020.0002.2142] # TURNED SANS-SERIF CAPITAL L +2143 ; [*0439.0020.0002.2143] # REVERSED SANS-SERIF CAPITAL L +2144 ; [*043A.0020.0002.2144] # TURNED SANS-SERIF CAPITAL Y +214A ; [*043B.0020.0002.214A] # PROPERTY LINE +214B ; [*0303.0020.0002.214B] # TURNED AMPERSAND +214C ; [*043C.0020.0002.214C] # PER SIGN +214D ; [*043D.0020.0002.214D] # AKTIESELSKAB +2180 ; [*0F23.0020.0002.2180] # ROMAN NUMERAL ONE THOUSAND C D +2181 ; [*0F24.0020.0002.2181] # ROMAN NUMERAL FIVE THOUSAND +2182 ; [*0F25.0020.0002.2182] # ROMAN NUMERAL TEN THOUSAND +2190 ; [*043E.0020.0002.2190] # LEFTWARDS ARROW +2191 ; [*0440.0020.0002.2191] # UPWARDS ARROW +2192 ; [*043F.0020.0002.2192] # RIGHTWARDS ARROW +2193 ; [*0441.0020.0002.2193] # DOWNWARDS ARROW +2194 ; [*0442.0020.0002.2194] # LEFT RIGHT ARROW +2195 ; [*0443.0020.0002.2195] # UP DOWN ARROW +2196 ; [*0444.0020.0002.2196] # NORTH WEST ARROW +2197 ; [*0445.0020.0002.2197] # NORTH EAST ARROW +2198 ; [*0446.0020.0002.2198] # SOUTH EAST ARROW +2199 ; [*0447.0020.0002.2199] # SOUTH WEST ARROW +219A ; [*043E.0020.0002.2190][.0000.0054.0002.0338] # LEFTWARDS ARROW WITH STROKE; QQCM +219B ; [*043F.0020.0002.2192][.0000.0054.0002.0338] # RIGHTWARDS ARROW WITH STROKE; QQCM +219C ; [*0448.0020.0002.219C] # LEFTWARDS WAVE ARROW +219D ; [*0449.0020.0002.219D] # RIGHTWARDS WAVE ARROW +219E ; [*044A.0020.0002.219E] # LEFTWARDS TWO HEADED ARROW +219F ; [*044B.0020.0002.219F] # UPWARDS TWO HEADED ARROW +21A0 ; [*044C.0020.0002.21A0] # RIGHTWARDS TWO HEADED ARROW +21A1 ; [*044D.0020.0002.21A1] # DOWNWARDS TWO HEADED ARROW +21A2 ; [*044E.0020.0002.21A2] # LEFTWARDS ARROW WITH TAIL +21A3 ; [*044F.0020.0002.21A3] # RIGHTWARDS ARROW WITH TAIL +21A4 ; [*0450.0020.0002.21A4] # LEFTWARDS ARROW FROM BAR +21A5 ; [*0451.0020.0002.21A5] # UPWARDS ARROW FROM BAR +21A6 ; [*0452.0020.0002.21A6] # RIGHTWARDS ARROW FROM BAR +21A7 ; [*0453.0020.0002.21A7] # DOWNWARDS ARROW FROM BAR +21A8 ; [*0454.0020.0002.21A8] # UP DOWN ARROW WITH BASE +21A9 ; [*0455.0020.0002.21A9] # LEFTWARDS ARROW WITH HOOK +21AA ; [*0456.0020.0002.21AA] # RIGHTWARDS ARROW WITH HOOK +21AB ; [*0457.0020.0002.21AB] # LEFTWARDS ARROW WITH LOOP +21AC ; [*0458.0020.0002.21AC] # RIGHTWARDS ARROW WITH LOOP +21AD ; [*0459.0020.0002.21AD] # LEFT RIGHT WAVE ARROW +21AE ; [*0442.0020.0002.2194][.0000.0054.0002.0338] # LEFT RIGHT ARROW WITH STROKE; QQCM +21AF ; [*045A.0020.0002.21AF] # DOWNWARDS ZIGZAG ARROW +21B0 ; [*045B.0020.0002.21B0] # UPWARDS ARROW WITH TIP LEFTWARDS +21B1 ; [*045C.0020.0002.21B1] # UPWARDS ARROW WITH TIP RIGHTWARDS +21B2 ; [*045D.0020.0002.21B2] # DOWNWARDS ARROW WITH TIP LEFTWARDS +21B3 ; [*045E.0020.0002.21B3] # DOWNWARDS ARROW WITH TIP RIGHTWARDS +21B4 ; [*045F.0020.0002.21B4] # RIGHTWARDS ARROW WITH CORNER DOWNWARDS +21B5 ; [*0460.0020.0002.21B5] # DOWNWARDS ARROW WITH CORNER LEFTWARDS +21B6 ; [*0461.0020.0002.21B6] # ANTICLOCKWISE TOP SEMICIRCLE ARROW +21B7 ; [*0462.0020.0002.21B7] # CLOCKWISE TOP SEMICIRCLE ARROW +21B8 ; [*0463.0020.0002.21B8] # NORTH WEST ARROW TO LONG BAR +21B9 ; [*0464.0020.0002.21B9] # LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR +21BA ; [*0465.0020.0002.21BA] # ANTICLOCKWISE OPEN CIRCLE ARROW +21BB ; [*0466.0020.0002.21BB] # CLOCKWISE OPEN CIRCLE ARROW +21BC ; [*0467.0020.0002.21BC] # LEFTWARDS HARPOON WITH BARB UPWARDS +21BD ; [*0468.0020.0002.21BD] # LEFTWARDS HARPOON WITH BARB DOWNWARDS +21BE ; [*0469.0020.0002.21BE] # UPWARDS HARPOON WITH BARB RIGHTWARDS +21BF ; [*046A.0020.0002.21BF] # UPWARDS HARPOON WITH BARB LEFTWARDS +21C0 ; [*046B.0020.0002.21C0] # RIGHTWARDS HARPOON WITH BARB UPWARDS +21C1 ; [*046C.0020.0002.21C1] # RIGHTWARDS HARPOON WITH BARB DOWNWARDS +21C2 ; [*046D.0020.0002.21C2] # DOWNWARDS HARPOON WITH BARB RIGHTWARDS +21C3 ; [*046E.0020.0002.21C3] # DOWNWARDS HARPOON WITH BARB LEFTWARDS +21C4 ; [*046F.0020.0002.21C4] # RIGHTWARDS ARROW OVER LEFTWARDS ARROW +21C5 ; [*0470.0020.0002.21C5] # UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW +21C6 ; [*0471.0020.0002.21C6] # LEFTWARDS ARROW OVER RIGHTWARDS ARROW +21C7 ; [*0472.0020.0002.21C7] # LEFTWARDS PAIRED ARROWS +21C8 ; [*0473.0020.0002.21C8] # UPWARDS PAIRED ARROWS +21C9 ; [*0474.0020.0002.21C9] # RIGHTWARDS PAIRED ARROWS +21CA ; [*0475.0020.0002.21CA] # DOWNWARDS PAIRED ARROWS +21CB ; [*0476.0020.0002.21CB] # LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON +21CC ; [*0477.0020.0002.21CC] # RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON +21CD ; [*0478.0020.0002.21D0][.0000.0054.0002.0338] # LEFTWARDS DOUBLE ARROW WITH STROKE; QQCM +21CE ; [*047C.0020.0002.21D4][.0000.0054.0002.0338] # LEFT RIGHT DOUBLE ARROW WITH STROKE; QQCM +21CF ; [*047A.0020.0002.21D2][.0000.0054.0002.0338] # RIGHTWARDS DOUBLE ARROW WITH STROKE; QQCM +21D0 ; [*0478.0020.0002.21D0] # LEFTWARDS DOUBLE ARROW +21D1 ; [*0479.0020.0002.21D1] # UPWARDS DOUBLE ARROW +21D2 ; [*047A.0020.0002.21D2] # RIGHTWARDS DOUBLE ARROW +21D3 ; [*047B.0020.0002.21D3] # DOWNWARDS DOUBLE ARROW +21D4 ; [*047C.0020.0002.21D4] # LEFT RIGHT DOUBLE ARROW +21D5 ; [*047D.0020.0002.21D5] # UP DOWN DOUBLE ARROW +21D6 ; [*047E.0020.0002.21D6] # NORTH WEST DOUBLE ARROW +21D7 ; [*047F.0020.0002.21D7] # NORTH EAST DOUBLE ARROW +21D8 ; [*0480.0020.0002.21D8] # SOUTH EAST DOUBLE ARROW +21D9 ; [*0481.0020.0002.21D9] # SOUTH WEST DOUBLE ARROW +21DA ; [*0482.0020.0002.21DA] # LEFTWARDS TRIPLE ARROW +21DB ; [*0483.0020.0002.21DB] # RIGHTWARDS TRIPLE ARROW +21DC ; [*0484.0020.0002.21DC] # LEFTWARDS SQUIGGLE ARROW +21DD ; [*0485.0020.0002.21DD] # RIGHTWARDS SQUIGGLE ARROW +21DE ; [*0486.0020.0002.21DE] # UPWARDS ARROW WITH DOUBLE STROKE +21DF ; [*0487.0020.0002.21DF] # DOWNWARDS ARROW WITH DOUBLE STROKE +21E0 ; [*0488.0020.0002.21E0] # LEFTWARDS DASHED ARROW +21E1 ; [*0489.0020.0002.21E1] # UPWARDS DASHED ARROW +21E2 ; [*048A.0020.0002.21E2] # RIGHTWARDS DASHED ARROW +21E3 ; [*048B.0020.0002.21E3] # DOWNWARDS DASHED ARROW +21E4 ; [*048C.0020.0002.21E4] # LEFTWARDS ARROW TO BAR +21E5 ; [*048D.0020.0002.21E5] # RIGHTWARDS ARROW TO BAR +21E6 ; [*048E.0020.0002.21E6] # LEFTWARDS WHITE ARROW +21E7 ; [*048F.0020.0002.21E7] # UPWARDS WHITE ARROW +21E8 ; [*0490.0020.0002.21E8] # RIGHTWARDS WHITE ARROW +21E9 ; [*0491.0020.0002.21E9] # DOWNWARDS WHITE ARROW +21EA ; [*0492.0020.0002.21EA] # UPWARDS WHITE ARROW FROM BAR +21EB ; [*0493.0020.0002.21EB] # UPWARDS WHITE ARROW ON PEDESTAL +21EC ; [*0494.0020.0002.21EC] # UPWARDS WHITE ARROW ON PEDESTAL WITH HORIZONTAL BAR +21ED ; [*0495.0020.0002.21ED] # UPWARDS WHITE ARROW ON PEDESTAL WITH VERTICAL BAR +21EE ; [*0496.0020.0002.21EE] # UPWARDS WHITE DOUBLE ARROW +21EF ; [*0497.0020.0002.21EF] # UPWARDS WHITE DOUBLE ARROW ON PEDESTAL +21F0 ; [*0498.0020.0002.21F0] # RIGHTWARDS WHITE ARROW FROM WALL +21F1 ; [*0499.0020.0002.21F1] # NORTH WEST ARROW TO CORNER +21F2 ; [*049A.0020.0002.21F2] # SOUTH EAST ARROW TO CORNER +21F3 ; [*049B.0020.0002.21F3] # UP DOWN WHITE ARROW +21F4 ; [*049C.0020.0002.21F4] # RIGHT ARROW WITH SMALL CIRCLE +21F5 ; [*049D.0020.0002.21F5] # DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW +21F6 ; [*049E.0020.0002.21F6] # THREE RIGHTWARDS ARROWS +21F7 ; [*049F.0020.0002.21F7] # LEFTWARDS ARROW WITH VERTICAL STROKE +21F8 ; [*04A0.0020.0002.21F8] # RIGHTWARDS ARROW WITH VERTICAL STROKE +21F9 ; [*04A1.0020.0002.21F9] # LEFT RIGHT ARROW WITH VERTICAL STROKE +21FA ; [*04A2.0020.0002.21FA] # LEFTWARDS ARROW WITH DOUBLE VERTICAL STROKE +21FB ; [*04A3.0020.0002.21FB] # RIGHTWARDS ARROW WITH DOUBLE VERTICAL STROKE +21FC ; [*04A4.0020.0002.21FC] # LEFT RIGHT ARROW WITH DOUBLE VERTICAL STROKE +21FD ; [*04A5.0020.0002.21FD] # LEFTWARDS OPEN-HEADED ARROW +21FE ; [*04A6.0020.0002.21FE] # RIGHTWARDS OPEN-HEADED ARROW +21FF ; [*04A7.0020.0002.21FF] # LEFT RIGHT OPEN-HEADED ARROW +2200 ; [*04A8.0020.0002.2200] # FOR ALL +2201 ; [*04A9.0020.0002.2201] # COMPLEMENT +2202 ; [*04AA.0020.0002.2202] # PARTIAL DIFFERENTIAL +2203 ; [*04AB.0020.0002.2203] # THERE EXISTS +2204 ; [*04AB.0020.0002.2203][.0000.0054.0002.0338] # THERE DOES NOT EXIST; QQCM +2205 ; [*04AC.0020.0002.2205] # EMPTY SET +2206 ; [*04AD.0020.0002.2206] # INCREMENT +2207 ; [*04AE.0020.0002.2207] # NABLA +2208 ; [*04AF.0020.0002.2208] # ELEMENT OF +2209 ; [*04AF.0020.0002.2208][.0000.0054.0002.0338] # NOT AN ELEMENT OF; QQCM +220A ; [*04B0.0020.0002.220A] # SMALL ELEMENT OF +220B ; [*04B1.0020.0002.220B] # CONTAINS AS MEMBER +220C ; [*04B1.0020.0002.220B][.0000.0054.0002.0338] # DOES NOT CONTAIN AS MEMBER; QQCM +220D ; [*04B2.0020.0002.220D] # SMALL CONTAINS AS MEMBER +220E ; [*04B4.0020.0002.220E] # END OF PROOF +220F ; [*04B5.0020.0002.220F] # N-ARY PRODUCT +2210 ; [*04B6.0020.0002.2210] # N-ARY COPRODUCT +2211 ; [*04B7.0020.0002.2211] # N-ARY SUMMATION +2212 ; [*04C4.0020.0002.2212] # MINUS SIGN +2213 ; [*04C5.0020.0002.2213] # MINUS-OR-PLUS SIGN +2214 ; [*04C6.0020.0002.2214] # DOT PLUS +2215 ; [*04C7.0020.0002.2215] # DIVISION SLASH +2216 ; [*04C8.0020.0002.2216] # SET MINUS +2217 ; [*04C9.0020.0002.2217] # ASTERISK OPERATOR +2218 ; [*04CA.0020.0002.2218] # RING OPERATOR +2219 ; [*04CB.0020.0002.2219] # BULLET OPERATOR +221A ; [*04CC.0020.0002.221A] # SQUARE ROOT +221B ; [*04CD.0020.0002.221B] # CUBE ROOT +221C ; [*04CE.0020.0002.221C] # FOURTH ROOT +221D ; [*04CF.0020.0002.221D] # PROPORTIONAL TO +221E ; [*04D0.0020.0002.221E] # INFINITY +221F ; [*04D1.0020.0002.221F] # RIGHT ANGLE +2220 ; [*04D2.0020.0002.2220] # ANGLE +2221 ; [*04D3.0020.0002.2221] # MEASURED ANGLE +2222 ; [*04D4.0020.0002.2222] # SPHERICAL ANGLE +2223 ; [*04D5.0020.0002.2223] # DIVIDES +2224 ; [*04D5.0020.0002.2223][.0000.0054.0002.0338] # DOES NOT DIVIDE; QQCM +2225 ; [*04D6.0020.0002.2225] # PARALLEL TO +2226 ; [*04D6.0020.0002.2225][.0000.0054.0002.0338] # NOT PARALLEL TO; QQCM +2227 ; [*04D7.0020.0002.2227] # LOGICAL AND +2228 ; [*04D8.0020.0002.2228] # LOGICAL OR +2229 ; [*04D9.0020.0002.2229] # INTERSECTION +222A ; [*04DA.0020.0002.222A] # UNION +222B ; [*04DB.0020.0002.222B] # INTEGRAL +222C ; [*04DB.0020.0004.222C][*04DB.0020.0004.222C] # DOUBLE INTEGRAL; QQKN +222D ; [*04DB.0020.0004.222D][*04DB.0020.0004.222D][*04DB.0020.001F.222D] # TRIPLE INTEGRAL; QQKN +222E ; [*04DC.0020.0002.222E] # CONTOUR INTEGRAL +222F ; [*04DC.0020.0004.222F][*04DC.0020.0004.222F] # SURFACE INTEGRAL; QQKN +2230 ; [*04DC.0020.0004.2230][*04DC.0020.0004.2230][*04DC.0020.001F.2230] # VOLUME INTEGRAL; QQKN +2231 ; [*04DD.0020.0002.2231] # CLOCKWISE INTEGRAL +2232 ; [*04DE.0020.0002.2232] # CLOCKWISE CONTOUR INTEGRAL +2233 ; [*04DF.0020.0002.2233] # ANTICLOCKWISE CONTOUR INTEGRAL +2234 ; [*04E0.0020.0002.2234] # THEREFORE +2235 ; [*04E1.0020.0002.2235] # BECAUSE +2236 ; [*04E2.0020.0002.2236] # RATIO +2237 ; [*04E3.0020.0002.2237] # PROPORTION +2238 ; [*04E4.0020.0002.2238] # DOT MINUS +2239 ; [*04E5.0020.0002.2239] # EXCESS +223A ; [*04E6.0020.0002.223A] # GEOMETRIC PROPORTION +223B ; [*04E7.0020.0002.223B] # HOMOTHETIC +223C ; [*04E8.0020.0002.223C] # TILDE OPERATOR +223D ; [*04E9.0020.0002.223D] # REVERSED TILDE +223E ; [*04EA.0020.0002.223E] # INVERTED LAZY S +223F ; [*04EB.0020.0002.223F] # SINE WAVE +2240 ; [*04EC.0020.0002.2240] # WREATH PRODUCT +2241 ; [*04E8.0020.0002.223C][.0000.0054.0002.0338] # NOT TILDE; QQCM +2242 ; [*04ED.0020.0002.2242] # MINUS TILDE +2243 ; [*04EE.0020.0002.2243] # ASYMPTOTICALLY EQUAL TO +2244 ; [*04EE.0020.0002.2243][.0000.0054.0002.0338] # NOT ASYMPTOTICALLY EQUAL TO; QQCM +2245 ; [*04EF.0020.0002.2245] # APPROXIMATELY EQUAL TO +2246 ; [*04F0.0020.0002.2246] # APPROXIMATELY BUT NOT ACTUALLY EQUAL TO +2247 ; [*04EF.0020.0002.2245][.0000.0054.0002.0338] # NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO; QQCM +2248 ; [*04F1.0020.0002.2248] # ALMOST EQUAL TO +2249 ; [*04F1.0020.0002.2248][.0000.0054.0002.0338] # NOT ALMOST EQUAL TO; QQCM +224A ; [*04F2.0020.0002.224A] # ALMOST EQUAL OR EQUAL TO +224B ; [*04F3.0020.0002.224B] # TRIPLE TILDE +224C ; [*04F4.0020.0002.224C] # ALL EQUAL TO +224D ; [*04F5.0020.0002.224D] # EQUIVALENT TO +224E ; [*04F6.0020.0002.224E] # GEOMETRICALLY EQUIVALENT TO +224F ; [*04F7.0020.0002.224F] # DIFFERENCE BETWEEN +2250 ; [*04F8.0020.0002.2250] # APPROACHES THE LIMIT +2251 ; [*04F9.0020.0002.2251] # GEOMETRICALLY EQUAL TO +2252 ; [*04FA.0020.0002.2252] # APPROXIMATELY EQUAL TO OR THE IMAGE OF +2253 ; [*04FB.0020.0002.2253] # IMAGE OF OR APPROXIMATELY EQUAL TO +2254 ; [*04FC.0020.0002.2254] # COLON EQUALS +2255 ; [*04FD.0020.0002.2255] # EQUALS COLON +2256 ; [*04FE.0020.0002.2256] # RING IN EQUAL TO +2257 ; [*04FF.0020.0002.2257] # RING EQUAL TO +2258 ; [*0500.0020.0002.2258] # CORRESPONDS TO +2259 ; [*0501.0020.0002.2259] # ESTIMATES +225A ; [*0502.0020.0002.225A] # EQUIANGULAR TO +225B ; [*0503.0020.0002.225B] # STAR EQUALS +225C ; [*0504.0020.0002.225C] # DELTA EQUAL TO +225D ; [*0505.0020.0002.225D] # EQUAL TO BY DEFINITION +225E ; [*0506.0020.0002.225E] # MEASURED BY +225F ; [*0507.0020.0002.225F] # QUESTIONED EQUAL TO +2260 ; [*04BD.0020.0002.003D][.0000.0054.0002.0338] # NOT EQUAL TO; QQCM +2261 ; [*0508.0020.0002.2261] # IDENTICAL TO +2262 ; [*0508.0020.0002.2261][.0000.0054.0002.0338] # NOT IDENTICAL TO; QQCM +2263 ; [*0509.0020.0002.2263] # STRICTLY EQUIVALENT TO +2264 ; [*050A.0020.0002.2264] # LESS-THAN OR EQUAL TO +2265 ; [*050B.0020.0002.2265] # GREATER-THAN OR EQUAL TO +2266 ; [*050C.0020.0002.2266] # LESS-THAN OVER EQUAL TO +2267 ; [*050D.0020.0002.2267] # GREATER-THAN OVER EQUAL TO +2268 ; [*050E.0020.0002.2268] # LESS-THAN BUT NOT EQUAL TO +2269 ; [*050F.0020.0002.2269] # GREATER-THAN BUT NOT EQUAL TO +226A ; [*0510.0020.0002.226A] # MUCH LESS-THAN +226B ; [*0511.0020.0002.226B] # MUCH GREATER-THAN +226C ; [*0512.0020.0002.226C] # BETWEEN +226D ; [*04F5.0020.0002.224D][.0000.0054.0002.0338] # NOT EQUIVALENT TO; QQCM +226E ; [*04BC.0020.0002.003C][.0000.0054.0002.0338] # NOT LESS-THAN; QQCM +226F ; [*04BE.0020.0002.003E][.0000.0054.0002.0338] # NOT GREATER-THAN; QQCM +2270 ; [*050A.0020.0002.2264][.0000.0054.0002.0338] # NEITHER LESS-THAN NOR EQUAL TO; QQCM +2271 ; [*050B.0020.0002.2265][.0000.0054.0002.0338] # NEITHER GREATER-THAN NOR EQUAL TO; QQCM +2272 ; [*0513.0020.0002.2272] # LESS-THAN OR EQUIVALENT TO +2273 ; [*0514.0020.0002.2273] # GREATER-THAN OR EQUIVALENT TO +2274 ; [*0513.0020.0002.2272][.0000.0054.0002.0338] # NEITHER LESS-THAN NOR EQUIVALENT TO; QQCM +2275 ; [*0514.0020.0002.2273][.0000.0054.0002.0338] # NEITHER GREATER-THAN NOR EQUIVALENT TO; QQCM +2276 ; [*0515.0020.0002.2276] # LESS-THAN OR GREATER-THAN +2277 ; [*0516.0020.0002.2277] # GREATER-THAN OR LESS-THAN +2278 ; [*0515.0020.0002.2276][.0000.0054.0002.0338] # NEITHER LESS-THAN NOR GREATER-THAN; QQCM +2279 ; [*0516.0020.0002.2277][.0000.0054.0002.0338] # NEITHER GREATER-THAN NOR LESS-THAN; QQCM +227A ; [*0517.0020.0002.227A] # PRECEDES +227B ; [*0518.0020.0002.227B] # SUCCEEDS +227C ; [*0519.0020.0002.227C] # PRECEDES OR EQUAL TO +227D ; [*051A.0020.0002.227D] # SUCCEEDS OR EQUAL TO +227E ; [*051B.0020.0002.227E] # PRECEDES OR EQUIVALENT TO +227F ; [*051C.0020.0002.227F] # SUCCEEDS OR EQUIVALENT TO +2280 ; [*0517.0020.0002.227A][.0000.0054.0002.0338] # DOES NOT PRECEDE; QQCM +2281 ; [*0518.0020.0002.227B][.0000.0054.0002.0338] # DOES NOT SUCCEED; QQCM +2282 ; [*051D.0020.0002.2282] # SUBSET OF +2283 ; [*051E.0020.0002.2283] # SUPERSET OF +2284 ; [*051D.0020.0002.2282][.0000.0054.0002.0338] # NOT A SUBSET OF; QQCM +2285 ; [*051E.0020.0002.2283][.0000.0054.0002.0338] # NOT A SUPERSET OF; QQCM +2286 ; [*051F.0020.0002.2286] # SUBSET OF OR EQUAL TO +2287 ; [*0520.0020.0002.2287] # SUPERSET OF OR EQUAL TO +2288 ; [*051F.0020.0002.2286][.0000.0054.0002.0338] # NEITHER A SUBSET OF NOR EQUAL TO; QQCM +2289 ; [*0520.0020.0002.2287][.0000.0054.0002.0338] # NEITHER A SUPERSET OF NOR EQUAL TO; QQCM +228A ; [*0521.0020.0002.228A] # SUBSET OF WITH NOT EQUAL TO +228B ; [*0522.0020.0002.228B] # SUPERSET OF WITH NOT EQUAL TO +228C ; [*0523.0020.0002.228C] # MULTISET +228D ; [*0524.0020.0002.228D] # MULTISET MULTIPLICATION +228E ; [*0525.0020.0002.228E] # MULTISET UNION +228F ; [*0526.0020.0002.228F] # SQUARE IMAGE OF +2290 ; [*0527.0020.0002.2290] # SQUARE ORIGINAL OF +2291 ; [*0528.0020.0002.2291] # SQUARE IMAGE OF OR EQUAL TO +2292 ; [*0529.0020.0002.2292] # SQUARE ORIGINAL OF OR EQUAL TO +2293 ; [*052A.0020.0002.2293] # SQUARE CAP +2294 ; [*052B.0020.0002.2294] # SQUARE CUP +2295 ; [*052C.0020.0002.2295] # CIRCLED PLUS +2296 ; [*052D.0020.0002.2296] # CIRCLED MINUS +2297 ; [*052E.0020.0002.2297] # CIRCLED TIMES +2298 ; [*052F.0020.0002.2298] # CIRCLED DIVISION SLASH +2299 ; [*0530.0020.0002.2299] # CIRCLED DOT OPERATOR +229A ; [*0531.0020.0002.229A] # CIRCLED RING OPERATOR +229B ; [*0532.0020.0002.229B] # CIRCLED ASTERISK OPERATOR +229C ; [*0533.0020.0002.229C] # CIRCLED EQUALS +229D ; [*0534.0020.0002.229D] # CIRCLED DASH +229E ; [*0535.0020.0002.229E] # SQUARED PLUS +229F ; [*0536.0020.0002.229F] # SQUARED MINUS +22A0 ; [*0537.0020.0002.22A0] # SQUARED TIMES +22A1 ; [*0538.0020.0002.22A1] # SQUARED DOT OPERATOR +22A2 ; [*0539.0020.0002.22A2] # RIGHT TACK +22A3 ; [*053A.0020.0002.22A3] # LEFT TACK +22A4 ; [*053B.0020.0002.22A4] # DOWN TACK +22A5 ; [*053C.0020.0002.22A5] # UP TACK +22A6 ; [*053D.0020.0002.22A6] # ASSERTION +22A7 ; [*053E.0020.0002.22A7] # MODELS +22A8 ; [*053F.0020.0002.22A8] # TRUE +22A9 ; [*0540.0020.0002.22A9] # FORCES +22AA ; [*0541.0020.0002.22AA] # TRIPLE VERTICAL BAR RIGHT TURNSTILE +22AB ; [*0542.0020.0002.22AB] # DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE +22AC ; [*0539.0020.0002.22A2][.0000.0054.0002.0338] # DOES NOT PROVE; QQCM +22AD ; [*053F.0020.0002.22A8][.0000.0054.0002.0338] # NOT TRUE; QQCM +22AE ; [*0540.0020.0002.22A9][.0000.0054.0002.0338] # DOES NOT FORCE; QQCM +22AF ; [*0542.0020.0002.22AB][.0000.0054.0002.0338] # NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE; QQCM +22B0 ; [*0543.0020.0002.22B0] # PRECEDES UNDER RELATION +22B1 ; [*0544.0020.0002.22B1] # SUCCEEDS UNDER RELATION +22B2 ; [*0545.0020.0002.22B2] # NORMAL SUBGROUP OF +22B3 ; [*0546.0020.0002.22B3] # CONTAINS AS NORMAL SUBGROUP +22B4 ; [*0547.0020.0002.22B4] # NORMAL SUBGROUP OF OR EQUAL TO +22B5 ; [*0548.0020.0002.22B5] # CONTAINS AS NORMAL SUBGROUP OR EQUAL TO +22B6 ; [*0549.0020.0002.22B6] # ORIGINAL OF +22B7 ; [*054A.0020.0002.22B7] # IMAGE OF +22B8 ; [*054B.0020.0002.22B8] # MULTIMAP +22B9 ; [*054C.0020.0002.22B9] # HERMITIAN CONJUGATE MATRIX +22BA ; [*054D.0020.0002.22BA] # INTERCALATE +22BB ; [*054E.0020.0002.22BB] # XOR +22BC ; [*054F.0020.0002.22BC] # NAND +22BD ; [*0550.0020.0002.22BD] # NOR +22BE ; [*0551.0020.0002.22BE] # RIGHT ANGLE WITH ARC +22BF ; [*0552.0020.0002.22BF] # RIGHT TRIANGLE +22C0 ; [*0553.0020.0002.22C0] # N-ARY LOGICAL AND +22C1 ; [*0554.0020.0002.22C1] # N-ARY LOGICAL OR +22C2 ; [*0555.0020.0002.22C2] # N-ARY INTERSECTION +22C3 ; [*0556.0020.0002.22C3] # N-ARY UNION +22C4 ; [*0557.0020.0002.22C4] # DIAMOND OPERATOR +22C5 ; [*0558.0020.0002.22C5] # DOT OPERATOR +22C6 ; [*0559.0020.0002.22C6] # STAR OPERATOR +22C7 ; [*055A.0020.0002.22C7] # DIVISION TIMES +22C8 ; [*055B.0020.0002.22C8] # BOWTIE +22C9 ; [*055C.0020.0002.22C9] # LEFT NORMAL FACTOR SEMIDIRECT PRODUCT +22CA ; [*055D.0020.0002.22CA] # RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT +22CB ; [*055E.0020.0002.22CB] # LEFT SEMIDIRECT PRODUCT +22CC ; [*055F.0020.0002.22CC] # RIGHT SEMIDIRECT PRODUCT +22CD ; [*0560.0020.0002.22CD] # REVERSED TILDE EQUALS +22CE ; [*0561.0020.0002.22CE] # CURLY LOGICAL OR +22CF ; [*0562.0020.0002.22CF] # CURLY LOGICAL AND +22D0 ; [*0563.0020.0002.22D0] # DOUBLE SUBSET +22D1 ; [*0564.0020.0002.22D1] # DOUBLE SUPERSET +22D2 ; [*0565.0020.0002.22D2] # DOUBLE INTERSECTION +22D3 ; [*0566.0020.0002.22D3] # DOUBLE UNION +22D4 ; [*0567.0020.0002.22D4] # PITCHFORK +22D5 ; [*0568.0020.0002.22D5] # EQUAL AND PARALLEL TO +22D6 ; [*0569.0020.0002.22D6] # LESS-THAN WITH DOT +22D7 ; [*056A.0020.0002.22D7] # GREATER-THAN WITH DOT +22D8 ; [*056B.0020.0002.22D8] # VERY MUCH LESS-THAN +22D9 ; [*056C.0020.0002.22D9] # VERY MUCH GREATER-THAN +22DA ; [*056D.0020.0002.22DA] # LESS-THAN EQUAL TO OR GREATER-THAN +22DB ; [*056E.0020.0002.22DB] # GREATER-THAN EQUAL TO OR LESS-THAN +22DC ; [*056F.0020.0002.22DC] # EQUAL TO OR LESS-THAN +22DD ; [*0570.0020.0002.22DD] # EQUAL TO OR GREATER-THAN +22DE ; [*0571.0020.0002.22DE] # EQUAL TO OR PRECEDES +22DF ; [*0572.0020.0002.22DF] # EQUAL TO OR SUCCEEDS +22E0 ; [*0519.0020.0002.227C][.0000.0054.0002.0338] # DOES NOT PRECEDE OR EQUAL; QQCM +22E1 ; [*051A.0020.0002.227D][.0000.0054.0002.0338] # DOES NOT SUCCEED OR EQUAL; QQCM +22E2 ; [*0528.0020.0002.2291][.0000.0054.0002.0338] # NOT SQUARE IMAGE OF OR EQUAL TO; QQCM +22E3 ; [*0529.0020.0002.2292][.0000.0054.0002.0338] # NOT SQUARE ORIGINAL OF OR EQUAL TO; QQCM +22E4 ; [*0573.0020.0002.22E4] # SQUARE IMAGE OF OR NOT EQUAL TO +22E5 ; [*0574.0020.0002.22E5] # SQUARE ORIGINAL OF OR NOT EQUAL TO +22E6 ; [*0575.0020.0002.22E6] # LESS-THAN BUT NOT EQUIVALENT TO +22E7 ; [*0576.0020.0002.22E7] # GREATER-THAN BUT NOT EQUIVALENT TO +22E8 ; [*0577.0020.0002.22E8] # PRECEDES BUT NOT EQUIVALENT TO +22E9 ; [*0578.0020.0002.22E9] # SUCCEEDS BUT NOT EQUIVALENT TO +22EA ; [*0545.0020.0002.22B2][.0000.0054.0002.0338] # NOT NORMAL SUBGROUP OF; QQCM +22EB ; [*0546.0020.0002.22B3][.0000.0054.0002.0338] # DOES NOT CONTAIN AS NORMAL SUBGROUP; QQCM +22EC ; [*0547.0020.0002.22B4][.0000.0054.0002.0338] # NOT NORMAL SUBGROUP OF OR EQUAL TO; QQCM +22ED ; [*0548.0020.0002.22B5][.0000.0054.0002.0338] # DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL; QQCM +22EE ; [*0579.0020.0002.22EE] # VERTICAL ELLIPSIS +22EF ; [*057A.0020.0002.22EF] # MIDLINE HORIZONTAL ELLIPSIS +22F0 ; [*057B.0020.0002.22F0] # UP RIGHT DIAGONAL ELLIPSIS +22F1 ; [*057C.0020.0002.22F1] # DOWN RIGHT DIAGONAL ELLIPSIS +22F2 ; [*057D.0020.0002.22F2] # ELEMENT OF WITH LONG HORIZONTAL STROKE +22F3 ; [*057E.0020.0002.22F3] # ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE +22F4 ; [*057F.0020.0002.22F4] # SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE +22F5 ; [*0580.0020.0002.22F5] # ELEMENT OF WITH DOT ABOVE +22F6 ; [*0581.0020.0002.22F6] # ELEMENT OF WITH OVERBAR +22F7 ; [*0582.0020.0002.22F7] # SMALL ELEMENT OF WITH OVERBAR +22F8 ; [*0583.0020.0002.22F8] # ELEMENT OF WITH UNDERBAR +22F9 ; [*0584.0020.0002.22F9] # ELEMENT OF WITH TWO HORIZONTAL STROKES +22FA ; [*0585.0020.0002.22FA] # CONTAINS WITH LONG HORIZONTAL STROKE +22FB ; [*0586.0020.0002.22FB] # CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE +22FC ; [*0587.0020.0002.22FC] # SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE +22FD ; [*0588.0020.0002.22FD] # CONTAINS WITH OVERBAR +22FE ; [*0589.0020.0002.22FE] # SMALL CONTAINS WITH OVERBAR +22FF ; [*058A.0020.0002.22FF] # Z NOTATION BAG MEMBERSHIP +2300 ; [*058B.0020.0002.2300] # DIAMETER SIGN +2301 ; [*058C.0020.0002.2301] # ELECTRIC ARROW +2302 ; [*058D.0020.0002.2302] # HOUSE +2303 ; [*058E.0020.0002.2303] # UP ARROWHEAD +2304 ; [*058F.0020.0002.2304] # DOWN ARROWHEAD +2305 ; [*0590.0020.0002.2305] # PROJECTIVE +2306 ; [*0591.0020.0002.2306] # PERSPECTIVE +2307 ; [*0592.0020.0002.2307] # WAVY LINE +2308 ; [*0593.0020.0002.2308] # LEFT CEILING +2309 ; [*0594.0020.0002.2309] # RIGHT CEILING +230A ; [*0595.0020.0002.230A] # LEFT FLOOR +230B ; [*0596.0020.0002.230B] # RIGHT FLOOR +230C ; [*0597.0020.0002.230C] # BOTTOM RIGHT CROP +230D ; [*0598.0020.0002.230D] # BOTTOM LEFT CROP +230E ; [*0599.0020.0002.230E] # TOP RIGHT CROP +230F ; [*059A.0020.0002.230F] # TOP LEFT CROP +2310 ; [*059B.0020.0002.2310] # REVERSED NOT SIGN +2311 ; [*059C.0020.0002.2311] # SQUARE LOZENGE +2312 ; [*059D.0020.0002.2312] # ARC +2313 ; [*059E.0020.0002.2313] # SEGMENT +2314 ; [*059F.0020.0002.2314] # SECTOR +2315 ; [*05A0.0020.0002.2315] # TELEPHONE RECORDER +2316 ; [*05A1.0020.0002.2316] # POSITION INDICATOR +2317 ; [*05A2.0020.0002.2317] # VIEWDATA SQUARE +2318 ; [*05A3.0020.0002.2318] # PLACE OF INTEREST SIGN +2319 ; [*05A4.0020.0002.2319] # TURNED NOT SIGN +231A ; [*05A5.0020.0002.231A] # WATCH +231B ; [*05A6.0020.0002.231B] # HOURGLASS +231C ; [*05A7.0020.0002.231C] # TOP LEFT CORNER +231D ; [*05A8.0020.0002.231D] # TOP RIGHT CORNER +231E ; [*05A9.0020.0002.231E] # BOTTOM LEFT CORNER +231F ; [*05AA.0020.0002.231F] # BOTTOM RIGHT CORNER +2320 ; [*05AB.0020.0002.2320] # TOP HALF INTEGRAL +2321 ; [*05AC.0020.0002.2321] # BOTTOM HALF INTEGRAL +2322 ; [*05AD.0020.0002.2322] # FROWN +2323 ; [*05AE.0020.0002.2323] # SMILE +2324 ; [*05AF.0020.0002.2324] # UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS +2325 ; [*05B0.0020.0002.2325] # OPTION KEY +2326 ; [*05B1.0020.0002.2326] # ERASE TO THE RIGHT +2327 ; [*05B2.0020.0002.2327] # X IN A RECTANGLE BOX +2328 ; [*05B3.0020.0002.2328] # KEYBOARD +2329 ; [*02E1.0020.0002.2329] # LEFT-POINTING ANGLE BRACKET; QQC +232A ; [*02E2.0020.0002.232A] # RIGHT-POINTING ANGLE BRACKET; QQC +232B ; [*05B4.0020.0002.232B] # ERASE TO THE LEFT +232C ; [*05B5.0020.0002.232C] # BENZENE RING +232D ; [*05B6.0020.0002.232D] # CYLINDRICITY +232E ; [*05B7.0020.0002.232E] # ALL AROUND-PROFILE +232F ; [*05B8.0020.0002.232F] # SYMMETRY +2330 ; [*05B9.0020.0002.2330] # TOTAL RUNOUT +2331 ; [*05BA.0020.0002.2331] # DIMENSION ORIGIN +2332 ; [*05BB.0020.0002.2332] # CONICAL TAPER +2333 ; [*05BC.0020.0002.2333] # SLOPE +2334 ; [*05BD.0020.0002.2334] # COUNTERBORE +2335 ; [*05BE.0020.0002.2335] # COUNTERSINK +2336 ; [*05BF.0020.0002.2336] # APL FUNCTIONAL SYMBOL I-BEAM +2337 ; [*05C0.0020.0002.2337] # APL FUNCTIONAL SYMBOL SQUISH QUAD +2338 ; [*05C1.0020.0002.2338] # APL FUNCTIONAL SYMBOL QUAD EQUAL +2339 ; [*05C2.0020.0002.2339] # APL FUNCTIONAL SYMBOL QUAD DIVIDE +233A ; [*05C3.0020.0002.233A] # APL FUNCTIONAL SYMBOL QUAD DIAMOND +233B ; [*05C4.0020.0002.233B] # APL FUNCTIONAL SYMBOL QUAD JOT +233C ; [*05C5.0020.0002.233C] # APL FUNCTIONAL SYMBOL QUAD CIRCLE +233D ; [*05C6.0020.0002.233D] # APL FUNCTIONAL SYMBOL CIRCLE STILE +233E ; [*05C7.0020.0002.233E] # APL FUNCTIONAL SYMBOL CIRCLE JOT +233F ; [*05C8.0020.0002.233F] # APL FUNCTIONAL SYMBOL SLASH BAR +2340 ; [*05C9.0020.0002.2340] # APL FUNCTIONAL SYMBOL BACKSLASH BAR +2341 ; [*05CA.0020.0002.2341] # APL FUNCTIONAL SYMBOL QUAD SLASH +2342 ; [*05CB.0020.0002.2342] # APL FUNCTIONAL SYMBOL QUAD BACKSLASH +2343 ; [*05CC.0020.0002.2343] # APL FUNCTIONAL SYMBOL QUAD LESS-THAN +2344 ; [*05CD.0020.0002.2344] # APL FUNCTIONAL SYMBOL QUAD GREATER-THAN +2345 ; [*05CE.0020.0002.2345] # APL FUNCTIONAL SYMBOL LEFTWARDS VANE +2346 ; [*05CF.0020.0002.2346] # APL FUNCTIONAL SYMBOL RIGHTWARDS VANE +2347 ; [*05D0.0020.0002.2347] # APL FUNCTIONAL SYMBOL QUAD LEFTWARDS ARROW +2348 ; [*05D1.0020.0002.2348] # APL FUNCTIONAL SYMBOL QUAD RIGHTWARDS ARROW +2349 ; [*05D2.0020.0002.2349] # APL FUNCTIONAL SYMBOL CIRCLE BACKSLASH +234A ; [*05D3.0020.0002.234A] # APL FUNCTIONAL SYMBOL DOWN TACK UNDERBAR +234B ; [*05D4.0020.0002.234B] # APL FUNCTIONAL SYMBOL DELTA STILE +234C ; [*05D5.0020.0002.234C] # APL FUNCTIONAL SYMBOL QUAD DOWN CARET +234D ; [*05D6.0020.0002.234D] # APL FUNCTIONAL SYMBOL QUAD DELTA +234E ; [*05D7.0020.0002.234E] # APL FUNCTIONAL SYMBOL DOWN TACK JOT +234F ; [*05D8.0020.0002.234F] # APL FUNCTIONAL SYMBOL UPWARDS VANE +2350 ; [*05D9.0020.0002.2350] # APL FUNCTIONAL SYMBOL QUAD UPWARDS ARROW +2351 ; [*05DA.0020.0002.2351] # APL FUNCTIONAL SYMBOL UP TACK OVERBAR +2352 ; [*05DB.0020.0002.2352] # APL FUNCTIONAL SYMBOL DEL STILE +2353 ; [*05DC.0020.0002.2353] # APL FUNCTIONAL SYMBOL QUAD UP CARET +2354 ; [*05DD.0020.0002.2354] # APL FUNCTIONAL SYMBOL QUAD DEL +2355 ; [*05DE.0020.0002.2355] # APL FUNCTIONAL SYMBOL UP TACK JOT +2356 ; [*05DF.0020.0002.2356] # APL FUNCTIONAL SYMBOL DOWNWARDS VANE +2357 ; [*05E0.0020.0002.2357] # APL FUNCTIONAL SYMBOL QUAD DOWNWARDS ARROW +2358 ; [*05E1.0020.0002.2358] # APL FUNCTIONAL SYMBOL QUOTE UNDERBAR +2359 ; [*05E2.0020.0002.2359] # APL FUNCTIONAL SYMBOL DELTA UNDERBAR +235A ; [*05E3.0020.0002.235A] # APL FUNCTIONAL SYMBOL DIAMOND UNDERBAR +235B ; [*05E4.0020.0002.235B] # APL FUNCTIONAL SYMBOL JOT UNDERBAR +235C ; [*05E5.0020.0002.235C] # APL FUNCTIONAL SYMBOL CIRCLE UNDERBAR +235D ; [*05E6.0020.0002.235D] # APL FUNCTIONAL SYMBOL UP SHOE JOT +235E ; [*05E7.0020.0002.235E] # APL FUNCTIONAL SYMBOL QUOTE QUAD +235F ; [*05E8.0020.0002.235F] # APL FUNCTIONAL SYMBOL CIRCLE STAR +2360 ; [*05E9.0020.0002.2360] # APL FUNCTIONAL SYMBOL QUAD COLON +2361 ; [*05EA.0020.0002.2361] # APL FUNCTIONAL SYMBOL UP TACK DIAERESIS +2362 ; [*05EB.0020.0002.2362] # APL FUNCTIONAL SYMBOL DEL DIAERESIS +2363 ; [*05EC.0020.0002.2363] # APL FUNCTIONAL SYMBOL STAR DIAERESIS +2364 ; [*05ED.0020.0002.2364] # APL FUNCTIONAL SYMBOL JOT DIAERESIS +2365 ; [*05EE.0020.0002.2365] # APL FUNCTIONAL SYMBOL CIRCLE DIAERESIS +2366 ; [*05EF.0020.0002.2366] # APL FUNCTIONAL SYMBOL DOWN SHOE STILE +2367 ; [*05F0.0020.0002.2367] # APL FUNCTIONAL SYMBOL LEFT SHOE STILE +2368 ; [*05F1.0020.0002.2368] # APL FUNCTIONAL SYMBOL TILDE DIAERESIS +2369 ; [*05F2.0020.0002.2369] # APL FUNCTIONAL SYMBOL GREATER-THAN DIAERESIS +236A ; [*05F3.0020.0002.236A] # APL FUNCTIONAL SYMBOL COMMA BAR +236B ; [*05F4.0020.0002.236B] # APL FUNCTIONAL SYMBOL DEL TILDE +236C ; [*05F5.0020.0002.236C] # APL FUNCTIONAL SYMBOL ZILDE +236D ; [*05F6.0020.0002.236D] # APL FUNCTIONAL SYMBOL STILE TILDE +236E ; [*05F7.0020.0002.236E] # APL FUNCTIONAL SYMBOL SEMICOLON UNDERBAR +236F ; [*05F8.0020.0002.236F] # APL FUNCTIONAL SYMBOL QUAD NOT EQUAL +2370 ; [*05F9.0020.0002.2370] # APL FUNCTIONAL SYMBOL QUAD QUESTION +2371 ; [*05FA.0020.0002.2371] # APL FUNCTIONAL SYMBOL DOWN CARET TILDE +2372 ; [*05FB.0020.0002.2372] # APL FUNCTIONAL SYMBOL UP CARET TILDE +2373 ; [*05FC.0020.0002.2373] # APL FUNCTIONAL SYMBOL IOTA +2374 ; [*05FD.0020.0002.2374] # APL FUNCTIONAL SYMBOL RHO +2375 ; [*05FE.0020.0002.2375] # APL FUNCTIONAL SYMBOL OMEGA +2376 ; [*05FF.0020.0002.2376] # APL FUNCTIONAL SYMBOL ALPHA UNDERBAR +2377 ; [*0600.0020.0002.2377] # APL FUNCTIONAL SYMBOL EPSILON UNDERBAR +2378 ; [*0601.0020.0002.2378] # APL FUNCTIONAL SYMBOL IOTA UNDERBAR +2379 ; [*0602.0020.0002.2379] # APL FUNCTIONAL SYMBOL OMEGA UNDERBAR +237A ; [*0603.0020.0002.237A] # APL FUNCTIONAL SYMBOL ALPHA +237B ; [*0604.0020.0002.237B] # NOT CHECK MARK +237C ; [*0605.0020.0002.237C] # RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW +237D ; [*0606.0020.0002.237D] # SHOULDERED OPEN BOX +237E ; [*0607.0020.0002.237E] # BELL SYMBOL +237F ; [*0608.0020.0002.237F] # VERTICAL LINE WITH MIDDLE DOT +2380 ; [*0609.0020.0002.2380] # INSERTION SYMBOL +2381 ; [*060A.0020.0002.2381] # CONTINUOUS UNDERLINE SYMBOL +2382 ; [*060B.0020.0002.2382] # DISCONTINUOUS UNDERLINE SYMBOL +2383 ; [*060C.0020.0002.2383] # EMPHASIS SYMBOL +2384 ; [*060D.0020.0002.2384] # COMPOSITION SYMBOL +2385 ; [*060E.0020.0002.2385] # WHITE SQUARE WITH CENTRE VERTICAL LINE +2386 ; [*060F.0020.0002.2386] # ENTER SYMBOL +2387 ; [*0610.0020.0002.2387] # ALTERNATIVE KEY SYMBOL +2388 ; [*0611.0020.0002.2388] # HELM SYMBOL +2389 ; [*0612.0020.0002.2389] # CIRCLED HORIZONTAL BAR WITH NOTCH +238A ; [*0613.0020.0002.238A] # CIRCLED TRIANGLE DOWN +238B ; [*0614.0020.0002.238B] # BROKEN CIRCLE WITH NORTHWEST ARROW +238C ; [*0615.0020.0002.238C] # UNDO SYMBOL +238D ; [*0616.0020.0002.238D] # MONOSTABLE SYMBOL +238E ; [*0617.0020.0002.238E] # HYSTERESIS SYMBOL +238F ; [*0618.0020.0002.238F] # OPEN-CIRCUIT-OUTPUT H-TYPE SYMBOL +2390 ; [*0619.0020.0002.2390] # OPEN-CIRCUIT-OUTPUT L-TYPE SYMBOL +2391 ; [*061A.0020.0002.2391] # PASSIVE-PULL-DOWN-OUTPUT SYMBOL +2392 ; [*061B.0020.0002.2392] # PASSIVE-PULL-UP-OUTPUT SYMBOL +2393 ; [*061C.0020.0002.2393] # DIRECT CURRENT SYMBOL FORM TWO +2394 ; [*061D.0020.0002.2394] # SOFTWARE-FUNCTION SYMBOL +2395 ; [*061E.0020.0002.2395] # APL FUNCTIONAL SYMBOL QUAD +2396 ; [*061F.0020.0002.2396] # DECIMAL SEPARATOR KEY SYMBOL +2397 ; [*0620.0020.0002.2397] # PREVIOUS PAGE +2398 ; [*0621.0020.0002.2398] # NEXT PAGE +2399 ; [*0622.0020.0002.2399] # PRINT SCREEN SYMBOL +239A ; [*0623.0020.0002.239A] # CLEAR SCREEN SYMBOL +239B ; [*0624.0020.0002.239B] # LEFT PARENTHESIS UPPER HOOK +239C ; [*0625.0020.0002.239C] # LEFT PARENTHESIS EXTENSION +239D ; [*0626.0020.0002.239D] # LEFT PARENTHESIS LOWER HOOK +239E ; [*0627.0020.0002.239E] # RIGHT PARENTHESIS UPPER HOOK +239F ; [*0628.0020.0002.239F] # RIGHT PARENTHESIS EXTENSION +23A0 ; [*0629.0020.0002.23A0] # RIGHT PARENTHESIS LOWER HOOK +23A1 ; [*062A.0020.0002.23A1] # LEFT SQUARE BRACKET UPPER CORNER +23A2 ; [*062B.0020.0002.23A2] # LEFT SQUARE BRACKET EXTENSION +23A3 ; [*062C.0020.0002.23A3] # LEFT SQUARE BRACKET LOWER CORNER +23A4 ; [*062D.0020.0002.23A4] # RIGHT SQUARE BRACKET UPPER CORNER +23A5 ; [*062E.0020.0002.23A5] # RIGHT SQUARE BRACKET EXTENSION +23A6 ; [*062F.0020.0002.23A6] # RIGHT SQUARE BRACKET LOWER CORNER +23A7 ; [*0630.0020.0002.23A7] # LEFT CURLY BRACKET UPPER HOOK +23A8 ; [*0631.0020.0002.23A8] # LEFT CURLY BRACKET MIDDLE PIECE +23A9 ; [*0632.0020.0002.23A9] # LEFT CURLY BRACKET LOWER HOOK +23AA ; [*0633.0020.0002.23AA] # CURLY BRACKET EXTENSION +23AB ; [*0634.0020.0002.23AB] # RIGHT CURLY BRACKET UPPER HOOK +23AC ; [*0635.0020.0002.23AC] # RIGHT CURLY BRACKET MIDDLE PIECE +23AD ; [*0636.0020.0002.23AD] # RIGHT CURLY BRACKET LOWER HOOK +23AE ; [*0637.0020.0002.23AE] # INTEGRAL EXTENSION +23AF ; [*0638.0020.0002.23AF] # HORIZONTAL LINE EXTENSION +23B0 ; [*0639.0020.0002.23B0] # UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION +23B1 ; [*063A.0020.0002.23B1] # UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION +23B2 ; [*063B.0020.0002.23B2] # SUMMATION TOP +23B3 ; [*063C.0020.0002.23B3] # SUMMATION BOTTOM +23B4 ; [*063D.0020.0002.23B4] # TOP SQUARE BRACKET +23B5 ; [*063E.0020.0002.23B5] # BOTTOM SQUARE BRACKET +23B6 ; [*063F.0020.0002.23B6] # BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET +23B7 ; [*0640.0020.0002.23B7] # RADICAL SYMBOL BOTTOM +23B8 ; [*0641.0020.0002.23B8] # LEFT VERTICAL BOX LINE +23B9 ; [*0642.0020.0002.23B9] # RIGHT VERTICAL BOX LINE +23BA ; [*0643.0020.0002.23BA] # HORIZONTAL SCAN LINE-1 +23BB ; [*0644.0020.0002.23BB] # HORIZONTAL SCAN LINE-3 +23BC ; [*0645.0020.0002.23BC] # HORIZONTAL SCAN LINE-7 +23BD ; [*0646.0020.0002.23BD] # HORIZONTAL SCAN LINE-9 +23BE ; [*0647.0020.0002.23BE] # DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT +23BF ; [*0648.0020.0002.23BF] # DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT +23C0 ; [*0649.0020.0002.23C0] # DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE +23C1 ; [*064A.0020.0002.23C1] # DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE +23C2 ; [*064B.0020.0002.23C2] # DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE +23C3 ; [*064C.0020.0002.23C3] # DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE +23C4 ; [*064D.0020.0002.23C4] # DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE +23C5 ; [*064E.0020.0002.23C5] # DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE +23C6 ; [*064F.0020.0002.23C6] # DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE +23C7 ; [*0650.0020.0002.23C7] # DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE +23C8 ; [*0651.0020.0002.23C8] # DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE +23C9 ; [*0652.0020.0002.23C9] # DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL +23CA ; [*0653.0020.0002.23CA] # DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL +23CB ; [*0654.0020.0002.23CB] # DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT +23CC ; [*0655.0020.0002.23CC] # DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT +23CD ; [*0656.0020.0002.23CD] # SQUARE FOOT +23CE ; [*0657.0020.0002.23CE] # RETURN SYMBOL +23CF ; [*0658.0020.0002.23CF] # EJECT SYMBOL +23D0 ; [*0659.0020.0002.23D0] # VERTICAL LINE EXTENSION +23D1 ; [*065A.0020.0002.23D1] # METRICAL BREVE +23D2 ; [*065B.0020.0002.23D2] # METRICAL LONG OVER SHORT +23D3 ; [*065C.0020.0002.23D3] # METRICAL SHORT OVER LONG +23D4 ; [*065D.0020.0002.23D4] # METRICAL LONG OVER TWO SHORTS +23D5 ; [*065E.0020.0002.23D5] # METRICAL TWO SHORTS OVER LONG +23D6 ; [*065F.0020.0002.23D6] # METRICAL TWO SHORTS JOINED +23D7 ; [*0660.0020.0002.23D7] # METRICAL TRISEME +23D8 ; [*0661.0020.0002.23D8] # METRICAL TETRASEME +23D9 ; [*0662.0020.0002.23D9] # METRICAL PENTASEME +23DA ; [*0663.0020.0002.23DA] # EARTH GROUND +23DB ; [*0664.0020.0002.23DB] # FUSE +23DC ; [*0665.0020.0002.23DC] # TOP PARENTHESIS +23DD ; [*0666.0020.0002.23DD] # BOTTOM PARENTHESIS +23DE ; [*0667.0020.0002.23DE] # TOP CURLY BRACKET +23DF ; [*0668.0020.0002.23DF] # BOTTOM CURLY BRACKET +23E0 ; [*0669.0020.0002.23E0] # TOP TORTOISE SHELL BRACKET +23E1 ; [*066A.0020.0002.23E1] # BOTTOM TORTOISE SHELL BRACKET +23E2 ; [*066B.0020.0002.23E2] # WHITE TRAPEZIUM +23E3 ; [*066C.0020.0002.23E3] # BENZENE RING WITH CIRCLE +23E4 ; [*066D.0020.0002.23E4] # STRAIGHTNESS +23E5 ; [*066E.0020.0002.23E5] # FLATNESS +23E6 ; [*066F.0020.0002.23E6] # AC CURRENT +23E7 ; [*0670.0020.0002.23E7] # ELECTRICAL INTERSECTION +2400 ; [*0671.0020.0002.2400] # SYMBOL FOR NULL +2401 ; [*0672.0020.0002.2401] # SYMBOL FOR START OF HEADING +2402 ; [*0673.0020.0002.2402] # SYMBOL FOR START OF TEXT +2403 ; [*0674.0020.0002.2403] # SYMBOL FOR END OF TEXT +2404 ; [*0675.0020.0002.2404] # SYMBOL FOR END OF TRANSMISSION +2405 ; [*0676.0020.0002.2405] # SYMBOL FOR ENQUIRY +2406 ; [*0677.0020.0002.2406] # SYMBOL FOR ACKNOWLEDGE +2407 ; [*0678.0020.0002.2407] # SYMBOL FOR BELL +2408 ; [*0679.0020.0002.2408] # SYMBOL FOR BACKSPACE +2409 ; [*067A.0020.0002.2409] # SYMBOL FOR HORIZONTAL TABULATION +240A ; [*067B.0020.0002.240A] # SYMBOL FOR LINE FEED +240B ; [*067C.0020.0002.240B] # SYMBOL FOR VERTICAL TABULATION +240C ; [*067D.0020.0002.240C] # SYMBOL FOR FORM FEED +240D ; [*067E.0020.0002.240D] # SYMBOL FOR CARRIAGE RETURN +240E ; [*067F.0020.0002.240E] # SYMBOL FOR SHIFT OUT +240F ; [*0680.0020.0002.240F] # SYMBOL FOR SHIFT IN +2410 ; [*0681.0020.0002.2410] # SYMBOL FOR DATA LINK ESCAPE +2411 ; [*0682.0020.0002.2411] # SYMBOL FOR DEVICE CONTROL ONE +2412 ; [*0683.0020.0002.2412] # SYMBOL FOR DEVICE CONTROL TWO +2413 ; [*0684.0020.0002.2413] # SYMBOL FOR DEVICE CONTROL THREE +2414 ; [*0685.0020.0002.2414] # SYMBOL FOR DEVICE CONTROL FOUR +2415 ; [*0686.0020.0002.2415] # SYMBOL FOR NEGATIVE ACKNOWLEDGE +2416 ; [*0687.0020.0002.2416] # SYMBOL FOR SYNCHRONOUS IDLE +2417 ; [*0688.0020.0002.2417] # SYMBOL FOR END OF TRANSMISSION BLOCK +2418 ; [*0689.0020.0002.2418] # SYMBOL FOR CANCEL +2419 ; [*068A.0020.0002.2419] # SYMBOL FOR END OF MEDIUM +241A ; [*068B.0020.0002.241A] # SYMBOL FOR SUBSTITUTE +241B ; [*068C.0020.0002.241B] # SYMBOL FOR ESCAPE +241C ; [*068D.0020.0002.241C] # SYMBOL FOR FILE SEPARATOR +241D ; [*068E.0020.0002.241D] # SYMBOL FOR GROUP SEPARATOR +241E ; [*068F.0020.0002.241E] # SYMBOL FOR RECORD SEPARATOR +241F ; [*0690.0020.0002.241F] # SYMBOL FOR UNIT SEPARATOR +2420 ; [*0691.0020.0002.2420] # SYMBOL FOR SPACE +2421 ; [*0692.0020.0002.2421] # SYMBOL FOR DELETE +2422 ; [*0693.0020.0002.2422] # BLANK SYMBOL +2423 ; [*0694.0020.0002.2423] # OPEN BOX +2424 ; [*0695.0020.0002.2424] # SYMBOL FOR NEWLINE +2425 ; [*0696.0020.0002.2425] # SYMBOL FOR DELETE FORM TWO +2426 ; [*0697.0020.0002.2426] # SYMBOL FOR SUBSTITUTE FORM TWO +2440 ; [*0698.0020.0002.2440] # OCR HOOK +2441 ; [*0699.0020.0002.2441] # OCR CHAIR +2442 ; [*069A.0020.0002.2442] # OCR FORK +2443 ; [*069B.0020.0002.2443] # OCR INVERTED FORK +2444 ; [*069C.0020.0002.2444] # OCR BELT BUCKLE +2445 ; [*069D.0020.0002.2445] # OCR BOW TIE +2446 ; [*069E.0020.0002.2446] # OCR BRANCH BANK IDENTIFICATION +2447 ; [*069F.0020.0002.2447] # OCR AMOUNT OF CHECK +2448 ; [*06A0.0020.0002.2448] # OCR DASH +2449 ; [*06A1.0020.0002.2449] # OCR CUSTOMER ACCOUNT NUMBER +244A ; [*06A2.0020.0002.244A] # OCR DOUBLE BACKSLASH +2500 ; [*06A3.0020.0002.2500] # BOX DRAWINGS LIGHT HORIZONTAL +2501 ; [*06A4.0020.0002.2501] # BOX DRAWINGS HEAVY HORIZONTAL +2502 ; [*06A5.0020.0002.2502] # BOX DRAWINGS LIGHT VERTICAL +2503 ; [*06A6.0020.0002.2503] # BOX DRAWINGS HEAVY VERTICAL +2504 ; [*06A7.0020.0002.2504] # BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL +2505 ; [*06A8.0020.0002.2505] # BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL +2506 ; [*06A9.0020.0002.2506] # BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL +2507 ; [*06AA.0020.0002.2507] # BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL +2508 ; [*06AB.0020.0002.2508] # BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL +2509 ; [*06AC.0020.0002.2509] # BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL +250A ; [*06AD.0020.0002.250A] # BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL +250B ; [*06AE.0020.0002.250B] # BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL +250C ; [*06AF.0020.0002.250C] # BOX DRAWINGS LIGHT DOWN AND RIGHT +250D ; [*06B0.0020.0002.250D] # BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY +250E ; [*06B1.0020.0002.250E] # BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT +250F ; [*06B2.0020.0002.250F] # BOX DRAWINGS HEAVY DOWN AND RIGHT +2510 ; [*06B3.0020.0002.2510] # BOX DRAWINGS LIGHT DOWN AND LEFT +2511 ; [*06B4.0020.0002.2511] # BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY +2512 ; [*06B5.0020.0002.2512] # BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT +2513 ; [*06B6.0020.0002.2513] # BOX DRAWINGS HEAVY DOWN AND LEFT +2514 ; [*06B7.0020.0002.2514] # BOX DRAWINGS LIGHT UP AND RIGHT +2515 ; [*06B8.0020.0002.2515] # BOX DRAWINGS UP LIGHT AND RIGHT HEAVY +2516 ; [*06B9.0020.0002.2516] # BOX DRAWINGS UP HEAVY AND RIGHT LIGHT +2517 ; [*06BA.0020.0002.2517] # BOX DRAWINGS HEAVY UP AND RIGHT +2518 ; [*06BB.0020.0002.2518] # BOX DRAWINGS LIGHT UP AND LEFT +2519 ; [*06BC.0020.0002.2519] # BOX DRAWINGS UP LIGHT AND LEFT HEAVY +251A ; [*06BD.0020.0002.251A] # BOX DRAWINGS UP HEAVY AND LEFT LIGHT +251B ; [*06BE.0020.0002.251B] # BOX DRAWINGS HEAVY UP AND LEFT +251C ; [*06BF.0020.0002.251C] # BOX DRAWINGS LIGHT VERTICAL AND RIGHT +251D ; [*06C0.0020.0002.251D] # BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY +251E ; [*06C1.0020.0002.251E] # BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT +251F ; [*06C2.0020.0002.251F] # BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT +2520 ; [*06C3.0020.0002.2520] # BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT +2521 ; [*06C4.0020.0002.2521] # BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY +2522 ; [*06C5.0020.0002.2522] # BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY +2523 ; [*06C6.0020.0002.2523] # BOX DRAWINGS HEAVY VERTICAL AND RIGHT +2524 ; [*06C7.0020.0002.2524] # BOX DRAWINGS LIGHT VERTICAL AND LEFT +2525 ; [*06C8.0020.0002.2525] # BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY +2526 ; [*06C9.0020.0002.2526] # BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT +2527 ; [*06CA.0020.0002.2527] # BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT +2528 ; [*06CB.0020.0002.2528] # BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT +2529 ; [*06CC.0020.0002.2529] # BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY +252A ; [*06CD.0020.0002.252A] # BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY +252B ; [*06CE.0020.0002.252B] # BOX DRAWINGS HEAVY VERTICAL AND LEFT +252C ; [*06CF.0020.0002.252C] # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL +252D ; [*06D0.0020.0002.252D] # BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT +252E ; [*06D1.0020.0002.252E] # BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT +252F ; [*06D2.0020.0002.252F] # BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY +2530 ; [*06D3.0020.0002.2530] # BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT +2531 ; [*06D4.0020.0002.2531] # BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY +2532 ; [*06D5.0020.0002.2532] # BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY +2533 ; [*06D6.0020.0002.2533] # BOX DRAWINGS HEAVY DOWN AND HORIZONTAL +2534 ; [*06D7.0020.0002.2534] # BOX DRAWINGS LIGHT UP AND HORIZONTAL +2535 ; [*06D8.0020.0002.2535] # BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT +2536 ; [*06D9.0020.0002.2536] # BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT +2537 ; [*06DA.0020.0002.2537] # BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY +2538 ; [*06DB.0020.0002.2538] # BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT +2539 ; [*06DC.0020.0002.2539] # BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY +253A ; [*06DD.0020.0002.253A] # BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY +253B ; [*06DE.0020.0002.253B] # BOX DRAWINGS HEAVY UP AND HORIZONTAL +253C ; [*06DF.0020.0002.253C] # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL +253D ; [*06E0.0020.0002.253D] # BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT +253E ; [*06E1.0020.0002.253E] # BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT +253F ; [*06E2.0020.0002.253F] # BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY +2540 ; [*06E3.0020.0002.2540] # BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT +2541 ; [*06E4.0020.0002.2541] # BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT +2542 ; [*06E5.0020.0002.2542] # BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT +2543 ; [*06E6.0020.0002.2543] # BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT +2544 ; [*06E7.0020.0002.2544] # BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT +2545 ; [*06E8.0020.0002.2545] # BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT +2546 ; [*06E9.0020.0002.2546] # BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT +2547 ; [*06EA.0020.0002.2547] # BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY +2548 ; [*06EB.0020.0002.2548] # BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY +2549 ; [*06EC.0020.0002.2549] # BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY +254A ; [*06ED.0020.0002.254A] # BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY +254B ; [*06EE.0020.0002.254B] # BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL +254C ; [*06EF.0020.0002.254C] # BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL +254D ; [*06F0.0020.0002.254D] # BOX DRAWINGS HEAVY DOUBLE DASH HORIZONTAL +254E ; [*06F1.0020.0002.254E] # BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL +254F ; [*06F2.0020.0002.254F] # BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL +2550 ; [*06F3.0020.0002.2550] # BOX DRAWINGS DOUBLE HORIZONTAL +2551 ; [*06F4.0020.0002.2551] # BOX DRAWINGS DOUBLE VERTICAL +2552 ; [*06F5.0020.0002.2552] # BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE +2553 ; [*06F6.0020.0002.2553] # BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE +2554 ; [*06F7.0020.0002.2554] # BOX DRAWINGS DOUBLE DOWN AND RIGHT +2555 ; [*06F8.0020.0002.2555] # BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE +2556 ; [*06F9.0020.0002.2556] # BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE +2557 ; [*06FA.0020.0002.2557] # BOX DRAWINGS DOUBLE DOWN AND LEFT +2558 ; [*06FB.0020.0002.2558] # BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE +2559 ; [*06FC.0020.0002.2559] # BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE +255A ; [*06FD.0020.0002.255A] # BOX DRAWINGS DOUBLE UP AND RIGHT +255B ; [*06FE.0020.0002.255B] # BOX DRAWINGS UP SINGLE AND LEFT DOUBLE +255C ; [*06FF.0020.0002.255C] # BOX DRAWINGS UP DOUBLE AND LEFT SINGLE +255D ; [*0700.0020.0002.255D] # BOX DRAWINGS DOUBLE UP AND LEFT +255E ; [*0701.0020.0002.255E] # BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE +255F ; [*0702.0020.0002.255F] # BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE +2560 ; [*0703.0020.0002.2560] # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT +2561 ; [*0704.0020.0002.2561] # BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE +2562 ; [*0705.0020.0002.2562] # BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE +2563 ; [*0706.0020.0002.2563] # BOX DRAWINGS DOUBLE VERTICAL AND LEFT +2564 ; [*0707.0020.0002.2564] # BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE +2565 ; [*0708.0020.0002.2565] # BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE +2566 ; [*0709.0020.0002.2566] # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL +2567 ; [*070A.0020.0002.2567] # BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE +2568 ; [*070B.0020.0002.2568] # BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE +2569 ; [*070C.0020.0002.2569] # BOX DRAWINGS DOUBLE UP AND HORIZONTAL +256A ; [*070D.0020.0002.256A] # BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE +256B ; [*070E.0020.0002.256B] # BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE +256C ; [*070F.0020.0002.256C] # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL +256D ; [*0710.0020.0002.256D] # BOX DRAWINGS LIGHT ARC DOWN AND RIGHT +256E ; [*0711.0020.0002.256E] # BOX DRAWINGS LIGHT ARC DOWN AND LEFT +256F ; [*0712.0020.0002.256F] # BOX DRAWINGS LIGHT ARC UP AND LEFT +2570 ; [*0713.0020.0002.2570] # BOX DRAWINGS LIGHT ARC UP AND RIGHT +2571 ; [*0714.0020.0002.2571] # BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT +2572 ; [*0715.0020.0002.2572] # BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT +2573 ; [*0716.0020.0002.2573] # BOX DRAWINGS LIGHT DIAGONAL CROSS +2574 ; [*0717.0020.0002.2574] # BOX DRAWINGS LIGHT LEFT +2575 ; [*0718.0020.0002.2575] # BOX DRAWINGS LIGHT UP +2576 ; [*0719.0020.0002.2576] # BOX DRAWINGS LIGHT RIGHT +2577 ; [*071A.0020.0002.2577] # BOX DRAWINGS LIGHT DOWN +2578 ; [*071B.0020.0002.2578] # BOX DRAWINGS HEAVY LEFT +2579 ; [*071C.0020.0002.2579] # BOX DRAWINGS HEAVY UP +257A ; [*071D.0020.0002.257A] # BOX DRAWINGS HEAVY RIGHT +257B ; [*071E.0020.0002.257B] # BOX DRAWINGS HEAVY DOWN +257C ; [*071F.0020.0002.257C] # BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT +257D ; [*0720.0020.0002.257D] # BOX DRAWINGS LIGHT UP AND HEAVY DOWN +257E ; [*0721.0020.0002.257E] # BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT +257F ; [*0722.0020.0002.257F] # BOX DRAWINGS HEAVY UP AND LIGHT DOWN +2580 ; [*0723.0020.0002.2580] # UPPER HALF BLOCK +2581 ; [*0724.0020.0002.2581] # LOWER ONE EIGHTH BLOCK +2582 ; [*0725.0020.0002.2582] # LOWER ONE QUARTER BLOCK +2583 ; [*0726.0020.0002.2583] # LOWER THREE EIGHTHS BLOCK +2584 ; [*0727.0020.0002.2584] # LOWER HALF BLOCK +2585 ; [*0728.0020.0002.2585] # LOWER FIVE EIGHTHS BLOCK +2586 ; [*0729.0020.0002.2586] # LOWER THREE QUARTERS BLOCK +2587 ; [*072A.0020.0002.2587] # LOWER SEVEN EIGHTHS BLOCK +2588 ; [*072B.0020.0002.2588] # FULL BLOCK +2589 ; [*072C.0020.0002.2589] # LEFT SEVEN EIGHTHS BLOCK +258A ; [*072D.0020.0002.258A] # LEFT THREE QUARTERS BLOCK +258B ; [*072E.0020.0002.258B] # LEFT FIVE EIGHTHS BLOCK +258C ; [*072F.0020.0002.258C] # LEFT HALF BLOCK +258D ; [*0730.0020.0002.258D] # LEFT THREE EIGHTHS BLOCK +258E ; [*0731.0020.0002.258E] # LEFT ONE QUARTER BLOCK +258F ; [*0732.0020.0002.258F] # LEFT ONE EIGHTH BLOCK +2590 ; [*0733.0020.0002.2590] # RIGHT HALF BLOCK +2591 ; [*0734.0020.0002.2591] # LIGHT SHADE +2592 ; [*0735.0020.0002.2592] # MEDIUM SHADE +2593 ; [*0736.0020.0002.2593] # DARK SHADE +2594 ; [*0737.0020.0002.2594] # UPPER ONE EIGHTH BLOCK +2595 ; [*0738.0020.0002.2595] # RIGHT ONE EIGHTH BLOCK +2596 ; [*0739.0020.0002.2596] # QUADRANT LOWER LEFT +2597 ; [*073A.0020.0002.2597] # QUADRANT LOWER RIGHT +2598 ; [*073B.0020.0002.2598] # QUADRANT UPPER LEFT +2599 ; [*073C.0020.0002.2599] # QUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHT +259A ; [*073D.0020.0002.259A] # QUADRANT UPPER LEFT AND LOWER RIGHT +259B ; [*073E.0020.0002.259B] # QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFT +259C ; [*073F.0020.0002.259C] # QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHT +259D ; [*0740.0020.0002.259D] # QUADRANT UPPER RIGHT +259E ; [*0741.0020.0002.259E] # QUADRANT UPPER RIGHT AND LOWER LEFT +259F ; [*0742.0020.0002.259F] # QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT +25A0 ; [*0743.0020.0002.25A0] # BLACK SQUARE +25A1 ; [*0744.0020.0002.25A1] # WHITE SQUARE +25A2 ; [*0745.0020.0002.25A2] # WHITE SQUARE WITH ROUNDED CORNERS +25A3 ; [*0746.0020.0002.25A3] # WHITE SQUARE CONTAINING BLACK SMALL SQUARE +25A4 ; [*0747.0020.0002.25A4] # SQUARE WITH HORIZONTAL FILL +25A5 ; [*0748.0020.0002.25A5] # SQUARE WITH VERTICAL FILL +25A6 ; [*0749.0020.0002.25A6] # SQUARE WITH ORTHOGONAL CROSSHATCH FILL +25A7 ; [*074A.0020.0002.25A7] # SQUARE WITH UPPER LEFT TO LOWER RIGHT FILL +25A8 ; [*074B.0020.0002.25A8] # SQUARE WITH UPPER RIGHT TO LOWER LEFT FILL +25A9 ; [*074C.0020.0002.25A9] # SQUARE WITH DIAGONAL CROSSHATCH FILL +25AA ; [*074D.0020.0002.25AA] # BLACK SMALL SQUARE +25AB ; [*074E.0020.0002.25AB] # WHITE SMALL SQUARE +25AC ; [*074F.0020.0002.25AC] # BLACK RECTANGLE +25AD ; [*0750.0020.0002.25AD] # WHITE RECTANGLE +25AE ; [*0751.0020.0002.25AE] # BLACK VERTICAL RECTANGLE +25AF ; [*0752.0020.0002.25AF] # WHITE VERTICAL RECTANGLE +25B0 ; [*0753.0020.0002.25B0] # BLACK PARALLELOGRAM +25B1 ; [*0754.0020.0002.25B1] # WHITE PARALLELOGRAM +25B2 ; [*0755.0020.0002.25B2] # BLACK UP-POINTING TRIANGLE +25B3 ; [*0756.0020.0002.25B3] # WHITE UP-POINTING TRIANGLE +25B4 ; [*0757.0020.0002.25B4] # BLACK UP-POINTING SMALL TRIANGLE +25B5 ; [*0758.0020.0002.25B5] # WHITE UP-POINTING SMALL TRIANGLE +25B6 ; [*0759.0020.0002.25B6] # BLACK RIGHT-POINTING TRIANGLE +25B7 ; [*075A.0020.0002.25B7] # WHITE RIGHT-POINTING TRIANGLE +25B8 ; [*075B.0020.0002.25B8] # BLACK RIGHT-POINTING SMALL TRIANGLE +25B9 ; [*075C.0020.0002.25B9] # WHITE RIGHT-POINTING SMALL TRIANGLE +25BA ; [*075D.0020.0002.25BA] # BLACK RIGHT-POINTING POINTER +25BB ; [*075E.0020.0002.25BB] # WHITE RIGHT-POINTING POINTER +25BC ; [*075F.0020.0002.25BC] # BLACK DOWN-POINTING TRIANGLE +25BD ; [*0760.0020.0002.25BD] # WHITE DOWN-POINTING TRIANGLE +25BE ; [*0761.0020.0002.25BE] # BLACK DOWN-POINTING SMALL TRIANGLE +25BF ; [*0762.0020.0002.25BF] # WHITE DOWN-POINTING SMALL TRIANGLE +25C0 ; [*0763.0020.0002.25C0] # BLACK LEFT-POINTING TRIANGLE +25C1 ; [*0764.0020.0002.25C1] # WHITE LEFT-POINTING TRIANGLE +25C2 ; [*0765.0020.0002.25C2] # BLACK LEFT-POINTING SMALL TRIANGLE +25C3 ; [*0766.0020.0002.25C3] # WHITE LEFT-POINTING SMALL TRIANGLE +25C4 ; [*0767.0020.0002.25C4] # BLACK LEFT-POINTING POINTER +25C5 ; [*0768.0020.0002.25C5] # WHITE LEFT-POINTING POINTER +25C6 ; [*0769.0020.0002.25C6] # BLACK DIAMOND +25C7 ; [*076A.0020.0002.25C7] # WHITE DIAMOND +25C8 ; [*076B.0020.0002.25C8] # WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND +25C9 ; [*076C.0020.0002.25C9] # FISHEYE +25CA ; [*076D.0020.0002.25CA] # LOZENGE +25CB ; [*076E.0020.0002.25CB] # WHITE CIRCLE +25CC ; [*076F.0020.0002.25CC] # DOTTED CIRCLE +25CD ; [*0770.0020.0002.25CD] # CIRCLE WITH VERTICAL FILL +25CE ; [*0771.0020.0002.25CE] # BULLSEYE +25CF ; [*0772.0020.0002.25CF] # BLACK CIRCLE +25D0 ; [*0773.0020.0002.25D0] # CIRCLE WITH LEFT HALF BLACK +25D1 ; [*0774.0020.0002.25D1] # CIRCLE WITH RIGHT HALF BLACK +25D2 ; [*0775.0020.0002.25D2] # CIRCLE WITH LOWER HALF BLACK +25D3 ; [*0776.0020.0002.25D3] # CIRCLE WITH UPPER HALF BLACK +25D4 ; [*0777.0020.0002.25D4] # CIRCLE WITH UPPER RIGHT QUADRANT BLACK +25D5 ; [*0778.0020.0002.25D5] # CIRCLE WITH ALL BUT UPPER LEFT QUADRANT BLACK +25D6 ; [*0779.0020.0002.25D6] # LEFT HALF BLACK CIRCLE +25D7 ; [*077A.0020.0002.25D7] # RIGHT HALF BLACK CIRCLE +25D8 ; [*077B.0020.0002.25D8] # INVERSE BULLET +25D9 ; [*077C.0020.0002.25D9] # INVERSE WHITE CIRCLE +25DA ; [*077D.0020.0002.25DA] # UPPER HALF INVERSE WHITE CIRCLE +25DB ; [*077E.0020.0002.25DB] # LOWER HALF INVERSE WHITE CIRCLE +25DC ; [*077F.0020.0002.25DC] # UPPER LEFT QUADRANT CIRCULAR ARC +25DD ; [*0780.0020.0002.25DD] # UPPER RIGHT QUADRANT CIRCULAR ARC +25DE ; [*0781.0020.0002.25DE] # LOWER RIGHT QUADRANT CIRCULAR ARC +25DF ; [*0782.0020.0002.25DF] # LOWER LEFT QUADRANT CIRCULAR ARC +25E0 ; [*0783.0020.0002.25E0] # UPPER HALF CIRCLE +25E1 ; [*0784.0020.0002.25E1] # LOWER HALF CIRCLE +25E2 ; [*0785.0020.0002.25E2] # BLACK LOWER RIGHT TRIANGLE +25E3 ; [*0786.0020.0002.25E3] # BLACK LOWER LEFT TRIANGLE +25E4 ; [*0787.0020.0002.25E4] # BLACK UPPER LEFT TRIANGLE +25E5 ; [*0788.0020.0002.25E5] # BLACK UPPER RIGHT TRIANGLE +25E6 ; [*0789.0020.0002.25E6] # WHITE BULLET +25E7 ; [*078A.0020.0002.25E7] # SQUARE WITH LEFT HALF BLACK +25E8 ; [*078B.0020.0002.25E8] # SQUARE WITH RIGHT HALF BLACK +25E9 ; [*078C.0020.0002.25E9] # SQUARE WITH UPPER LEFT DIAGONAL HALF BLACK +25EA ; [*078D.0020.0002.25EA] # SQUARE WITH LOWER RIGHT DIAGONAL HALF BLACK +25EB ; [*078E.0020.0002.25EB] # WHITE SQUARE WITH VERTICAL BISECTING LINE +25EC ; [*078F.0020.0002.25EC] # WHITE UP-POINTING TRIANGLE WITH DOT +25ED ; [*0790.0020.0002.25ED] # UP-POINTING TRIANGLE WITH LEFT HALF BLACK +25EE ; [*0791.0020.0002.25EE] # UP-POINTING TRIANGLE WITH RIGHT HALF BLACK +25EF ; [*0792.0020.0002.25EF] # LARGE CIRCLE +25F0 ; [*0793.0020.0002.25F0] # WHITE SQUARE WITH UPPER LEFT QUADRANT +25F1 ; [*0794.0020.0002.25F1] # WHITE SQUARE WITH LOWER LEFT QUADRANT +25F2 ; [*0795.0020.0002.25F2] # WHITE SQUARE WITH LOWER RIGHT QUADRANT +25F3 ; [*0796.0020.0002.25F3] # WHITE SQUARE WITH UPPER RIGHT QUADRANT +25F4 ; [*0797.0020.0002.25F4] # WHITE CIRCLE WITH UPPER LEFT QUADRANT +25F5 ; [*0798.0020.0002.25F5] # WHITE CIRCLE WITH LOWER LEFT QUADRANT +25F6 ; [*0799.0020.0002.25F6] # WHITE CIRCLE WITH LOWER RIGHT QUADRANT +25F7 ; [*079A.0020.0002.25F7] # WHITE CIRCLE WITH UPPER RIGHT QUADRANT +25F8 ; [*079B.0020.0002.25F8] # UPPER LEFT TRIANGLE +25F9 ; [*079C.0020.0002.25F9] # UPPER RIGHT TRIANGLE +25FA ; [*079D.0020.0002.25FA] # LOWER LEFT TRIANGLE +25FB ; [*079E.0020.0002.25FB] # WHITE MEDIUM SQUARE +25FC ; [*079F.0020.0002.25FC] # BLACK MEDIUM SQUARE +25FD ; [*07A0.0020.0002.25FD] # WHITE MEDIUM SMALL SQUARE +25FE ; [*07A1.0020.0002.25FE] # BLACK MEDIUM SMALL SQUARE +25FF ; [*07A2.0020.0002.25FF] # LOWER RIGHT TRIANGLE +2600 ; [*07A3.0020.0002.2600] # BLACK SUN WITH RAYS +2601 ; [*07A4.0020.0002.2601] # CLOUD +2602 ; [*07A5.0020.0002.2602] # UMBRELLA +2603 ; [*07A6.0020.0002.2603] # SNOWMAN +2604 ; [*07A7.0020.0002.2604] # COMET +2605 ; [*07A8.0020.0002.2605] # BLACK STAR +2606 ; [*07A9.0020.0002.2606] # WHITE STAR +2607 ; [*07AA.0020.0002.2607] # LIGHTNING +2608 ; [*07AB.0020.0002.2608] # THUNDERSTORM +2609 ; [*07AC.0020.0002.2609] # SUN +260A ; [*07AD.0020.0002.260A] # ASCENDING NODE +260B ; [*07AE.0020.0002.260B] # DESCENDING NODE +260C ; [*07AF.0020.0002.260C] # CONJUNCTION +260D ; [*07B0.0020.0002.260D] # OPPOSITION +260E ; [*07B1.0020.0002.260E] # BLACK TELEPHONE +260F ; [*07B2.0020.0002.260F] # WHITE TELEPHONE +2610 ; [*07B3.0020.0002.2610] # BALLOT BOX +2611 ; [*07B4.0020.0002.2611] # BALLOT BOX WITH CHECK +2612 ; [*07B5.0020.0002.2612] # BALLOT BOX WITH X +2613 ; [*07B6.0020.0002.2613] # SALTIRE +2614 ; [*07B7.0020.0002.2614] # UMBRELLA WITH RAIN DROPS +2615 ; [*07B8.0020.0002.2615] # HOT BEVERAGE +2616 ; [*07B9.0020.0002.2616] # WHITE SHOGI PIECE +2617 ; [*07BA.0020.0002.2617] # BLACK SHOGI PIECE +2618 ; [*07BB.0020.0002.2618] # SHAMROCK +2619 ; [*07BC.0020.0002.2619] # REVERSED ROTATED FLORAL HEART BULLET +261A ; [*07BD.0020.0002.261A] # BLACK LEFT POINTING INDEX +261B ; [*07BE.0020.0002.261B] # BLACK RIGHT POINTING INDEX +261C ; [*07BF.0020.0002.261C] # WHITE LEFT POINTING INDEX +261D ; [*07C0.0020.0002.261D] # WHITE UP POINTING INDEX +261E ; [*07C1.0020.0002.261E] # WHITE RIGHT POINTING INDEX +261F ; [*07C2.0020.0002.261F] # WHITE DOWN POINTING INDEX +2620 ; [*07C3.0020.0002.2620] # SKULL AND CROSSBONES +2621 ; [*07C4.0020.0002.2621] # CAUTION SIGN +2622 ; [*07C5.0020.0002.2622] # RADIOACTIVE SIGN +2623 ; [*07C6.0020.0002.2623] # BIOHAZARD SIGN +2624 ; [*07C7.0020.0002.2624] # CADUCEUS +2625 ; [*07C8.0020.0002.2625] # ANKH +2626 ; [*07C9.0020.0002.2626] # ORTHODOX CROSS +2627 ; [*07CA.0020.0002.2627] # CHI RHO +2628 ; [*07CB.0020.0002.2628] # CROSS OF LORRAINE +2629 ; [*07CC.0020.0002.2629] # CROSS OF JERUSALEM +262A ; [*07CD.0020.0002.262A] # STAR AND CRESCENT +262B ; [*07CE.0020.0002.262B] # FARSI SYMBOL +262C ; [*07CF.0020.0002.262C] # ADI SHAKTI +262D ; [*07D0.0020.0002.262D] # HAMMER AND SICKLE +262E ; [*07D1.0020.0002.262E] # PEACE SYMBOL +262F ; [*07D2.0020.0002.262F] # YIN YANG +2630 ; [*0C17.0020.0002.2630] # TRIGRAM FOR HEAVEN +2631 ; [*0C18.0020.0002.2631] # TRIGRAM FOR LAKE +2632 ; [*0C19.0020.0002.2632] # TRIGRAM FOR FIRE +2633 ; [*0C1A.0020.0002.2633] # TRIGRAM FOR THUNDER +2634 ; [*0C1B.0020.0002.2634] # TRIGRAM FOR WIND +2635 ; [*0C1C.0020.0002.2635] # TRIGRAM FOR WATER +2636 ; [*0C1D.0020.0002.2636] # TRIGRAM FOR MOUNTAIN +2637 ; [*0C1E.0020.0002.2637] # TRIGRAM FOR EARTH +2638 ; [*07D3.0020.0002.2638] # WHEEL OF DHARMA +2639 ; [*07D4.0020.0002.2639] # WHITE FROWNING FACE +263A ; [*07D5.0020.0002.263A] # WHITE SMILING FACE +263B ; [*07D6.0020.0002.263B] # BLACK SMILING FACE +263C ; [*07D7.0020.0002.263C] # WHITE SUN WITH RAYS +263D ; [*07D8.0020.0002.263D] # FIRST QUARTER MOON +263E ; [*07D9.0020.0002.263E] # LAST QUARTER MOON +263F ; [*07DA.0020.0002.263F] # MERCURY +2640 ; [*07DB.0020.0002.2640] # FEMALE SIGN +2641 ; [*07DC.0020.0002.2641] # EARTH +2642 ; [*07DD.0020.0002.2642] # MALE SIGN +2643 ; [*07DE.0020.0002.2643] # JUPITER +2644 ; [*07DF.0020.0002.2644] # SATURN +2645 ; [*07E0.0020.0002.2645] # URANUS +2646 ; [*07E1.0020.0002.2646] # NEPTUNE +2647 ; [*07E2.0020.0002.2647] # PLUTO +2648 ; [*07E3.0020.0002.2648] # ARIES +2649 ; [*07E4.0020.0002.2649] # TAURUS +264A ; [*07E5.0020.0002.264A] # GEMINI +264B ; [*07E6.0020.0002.264B] # CANCER +264C ; [*07E7.0020.0002.264C] # LEO +264D ; [*07E8.0020.0002.264D] # VIRGO +264E ; [*07E9.0020.0002.264E] # LIBRA +264F ; [*07EA.0020.0002.264F] # SCORPIUS +2650 ; [*07EB.0020.0002.2650] # SAGITTARIUS +2651 ; [*07EC.0020.0002.2651] # CAPRICORN +2652 ; [*07ED.0020.0002.2652] # AQUARIUS +2653 ; [*07EE.0020.0002.2653] # PISCES +2654 ; [*07EF.0020.0002.2654] # WHITE CHESS KING +2655 ; [*07F0.0020.0002.2655] # WHITE CHESS QUEEN +2656 ; [*07F1.0020.0002.2656] # WHITE CHESS ROOK +2657 ; [*07F2.0020.0002.2657] # WHITE CHESS BISHOP +2658 ; [*07F3.0020.0002.2658] # WHITE CHESS KNIGHT +2659 ; [*07F4.0020.0002.2659] # WHITE CHESS PAWN +265A ; [*07F5.0020.0002.265A] # BLACK CHESS KING +265B ; [*07F6.0020.0002.265B] # BLACK CHESS QUEEN +265C ; [*07F7.0020.0002.265C] # BLACK CHESS ROOK +265D ; [*07F8.0020.0002.265D] # BLACK CHESS BISHOP +265E ; [*07F9.0020.0002.265E] # BLACK CHESS KNIGHT +265F ; [*07FA.0020.0002.265F] # BLACK CHESS PAWN +2660 ; [*07FB.0020.0002.2660] # BLACK SPADE SUIT +2661 ; [*07FC.0020.0002.2661] # WHITE HEART SUIT +2662 ; [*07FD.0020.0002.2662] # WHITE DIAMOND SUIT +2663 ; [*07FE.0020.0002.2663] # BLACK CLUB SUIT +2664 ; [*07FF.0020.0002.2664] # WHITE SPADE SUIT +2665 ; [*0800.0020.0002.2665] # BLACK HEART SUIT +2666 ; [*0801.0020.0002.2666] # BLACK DIAMOND SUIT +2667 ; [*0802.0020.0002.2667] # WHITE CLUB SUIT +2668 ; [*0803.0020.0002.2668] # HOT SPRINGS +2669 ; [*0804.0020.0002.2669] # QUARTER NOTE +266A ; [*0805.0020.0002.266A] # EIGHTH NOTE +266B ; [*0806.0020.0002.266B] # BEAMED EIGHTH NOTES +266C ; [*0807.0020.0002.266C] # BEAMED SIXTEENTH NOTES +266D ; [*0E24.0020.0002.266D] # MUSIC FLAT SIGN +266E ; [*0E25.0020.0002.266E] # MUSIC NATURAL SIGN +266F ; [*0E26.0020.0002.266F] # MUSIC SHARP SIGN +2670 ; [*0808.0020.0002.2670] # WEST SYRIAC CROSS +2671 ; [*0809.0020.0002.2671] # EAST SYRIAC CROSS +2672 ; [*080A.0020.0002.2672] # UNIVERSAL RECYCLING SYMBOL +2673 ; [*080B.0020.0002.2673] # RECYCLING SYMBOL FOR TYPE-1 PLASTICS +2674 ; [*080C.0020.0002.2674] # RECYCLING SYMBOL FOR TYPE-2 PLASTICS +2675 ; [*080D.0020.0002.2675] # RECYCLING SYMBOL FOR TYPE-3 PLASTICS +2676 ; [*080E.0020.0002.2676] # RECYCLING SYMBOL FOR TYPE-4 PLASTICS +2677 ; [*080F.0020.0002.2677] # RECYCLING SYMBOL FOR TYPE-5 PLASTICS +2678 ; [*0810.0020.0002.2678] # RECYCLING SYMBOL FOR TYPE-6 PLASTICS +2679 ; [*0811.0020.0002.2679] # RECYCLING SYMBOL FOR TYPE-7 PLASTICS +267A ; [*0812.0020.0002.267A] # RECYCLING SYMBOL FOR GENERIC MATERIALS +267B ; [*0813.0020.0002.267B] # BLACK UNIVERSAL RECYCLING SYMBOL +267C ; [*0814.0020.0002.267C] # RECYCLED PAPER SYMBOL +267D ; [*0815.0020.0002.267D] # PARTIALLY-RECYCLED PAPER SYMBOL +267E ; [*0816.0020.0002.267E] # PERMANENT PAPER SIGN +267F ; [*0817.0020.0002.267F] # WHEELCHAIR SYMBOL +2680 ; [*0818.0020.0002.2680] # DIE FACE-1 +2681 ; [*0819.0020.0002.2681] # DIE FACE-2 +2682 ; [*081A.0020.0002.2682] # DIE FACE-3 +2683 ; [*081B.0020.0002.2683] # DIE FACE-4 +2684 ; [*081C.0020.0002.2684] # DIE FACE-5 +2685 ; [*081D.0020.0002.2685] # DIE FACE-6 +2686 ; [*081E.0020.0002.2686] # WHITE CIRCLE WITH DOT RIGHT +2687 ; [*081F.0020.0002.2687] # WHITE CIRCLE WITH TWO DOTS +2688 ; [*0820.0020.0002.2688] # BLACK CIRCLE WITH WHITE DOT RIGHT +2689 ; [*0821.0020.0002.2689] # BLACK CIRCLE WITH TWO WHITE DOTS +268A ; [*0C11.0020.0002.268A] # MONOGRAM FOR YANG +268B ; [*0C12.0020.0002.268B] # MONOGRAM FOR YIN +268C ; [*0C13.0020.0002.268C] # DIGRAM FOR GREATER YANG +268D ; [*0C14.0020.0002.268D] # DIGRAM FOR LESSER YIN +268E ; [*0C15.0020.0002.268E] # DIGRAM FOR LESSER YANG +268F ; [*0C16.0020.0002.268F] # DIGRAM FOR GREATER YIN +2690 ; [*0822.0020.0002.2690] # WHITE FLAG +2691 ; [*0823.0020.0002.2691] # BLACK FLAG +2692 ; [*0824.0020.0002.2692] # HAMMER AND PICK +2693 ; [*0825.0020.0002.2693] # ANCHOR +2694 ; [*0826.0020.0002.2694] # CROSSED SWORDS +2695 ; [*0827.0020.0002.2695] # STAFF OF AESCULAPIUS +2696 ; [*0828.0020.0002.2696] # SCALES +2697 ; [*0829.0020.0002.2697] # ALEMBIC +2698 ; [*082A.0020.0002.2698] # FLOWER +2699 ; [*082B.0020.0002.2699] # GEAR +269A ; [*082C.0020.0002.269A] # STAFF OF HERMES +269B ; [*082D.0020.0002.269B] # ATOM SYMBOL +269C ; [*082E.0020.0002.269C] # FLEUR-DE-LIS +26A0 ; [*082F.0020.0002.26A0] # WARNING SIGN +26A1 ; [*0830.0020.0002.26A1] # HIGH VOLTAGE SIGN +26A2 ; [*0831.0020.0002.26A2] # DOUBLED FEMALE SIGN +26A3 ; [*0832.0020.0002.26A3] # DOUBLED MALE SIGN +26A4 ; [*0833.0020.0002.26A4] # INTERLOCKED FEMALE AND MALE SIGN +26A5 ; [*0834.0020.0002.26A5] # MALE AND FEMALE SIGN +26A6 ; [*0835.0020.0002.26A6] # MALE WITH STROKE SIGN +26A7 ; [*0836.0020.0002.26A7] # MALE WITH STROKE AND MALE AND FEMALE SIGN +26A8 ; [*0837.0020.0002.26A8] # VERTICAL MALE WITH STROKE SIGN +26A9 ; [*0838.0020.0002.26A9] # HORIZONTAL MALE WITH STROKE SIGN +26AA ; [*0839.0020.0002.26AA] # MEDIUM WHITE CIRCLE +26AB ; [*083A.0020.0002.26AB] # MEDIUM BLACK CIRCLE +26AC ; [*083B.0020.0002.26AC] # MEDIUM SMALL WHITE CIRCLE +26AD ; [*083C.0020.0002.26AD] # MARRIAGE SYMBOL +26AE ; [*083D.0020.0002.26AE] # DIVORCE SYMBOL +26AF ; [*083E.0020.0002.26AF] # UNMARRIED PARTNERSHIP SYMBOL +26B0 ; [*083F.0020.0002.26B0] # COFFIN +26B1 ; [*0840.0020.0002.26B1] # FUNERAL URN +26B2 ; [*0841.0020.0002.26B2] # NEUTER +2701 ; [*0842.0020.0002.2701] # UPPER BLADE SCISSORS +2702 ; [*0843.0020.0002.2702] # BLACK SCISSORS +2703 ; [*0844.0020.0002.2703] # LOWER BLADE SCISSORS +2704 ; [*0845.0020.0002.2704] # WHITE SCISSORS +2706 ; [*0846.0020.0002.2706] # TELEPHONE LOCATION SIGN +2707 ; [*0847.0020.0002.2707] # TAPE DRIVE +2708 ; [*0848.0020.0002.2708] # AIRPLANE +2709 ; [*0849.0020.0002.2709] # ENVELOPE +270C ; [*084A.0020.0002.270C] # VICTORY HAND +270D ; [*084B.0020.0002.270D] # WRITING HAND +270E ; [*084C.0020.0002.270E] # LOWER RIGHT PENCIL +270F ; [*084D.0020.0002.270F] # PENCIL +2710 ; [*084E.0020.0002.2710] # UPPER RIGHT PENCIL +2711 ; [*084F.0020.0002.2711] # WHITE NIB +2712 ; [*0850.0020.0002.2712] # BLACK NIB +2713 ; [*0851.0020.0002.2713] # CHECK MARK +2714 ; [*0852.0020.0002.2714] # HEAVY CHECK MARK +2715 ; [*0853.0020.0002.2715] # MULTIPLICATION X +2716 ; [*0854.0020.0002.2716] # HEAVY MULTIPLICATION X +2717 ; [*0855.0020.0002.2717] # BALLOT X +2718 ; [*0856.0020.0002.2718] # HEAVY BALLOT X +2719 ; [*0857.0020.0002.2719] # OUTLINED GREEK CROSS +271A ; [*0858.0020.0002.271A] # HEAVY GREEK CROSS +271B ; [*0859.0020.0002.271B] # OPEN CENTRE CROSS +271C ; [*085A.0020.0002.271C] # HEAVY OPEN CENTRE CROSS +271D ; [*085B.0020.0002.271D] # LATIN CROSS +271E ; [*085C.0020.0002.271E] # SHADOWED WHITE LATIN CROSS +271F ; [*085D.0020.0002.271F] # OUTLINED LATIN CROSS +2720 ; [*085E.0020.0002.2720] # MALTESE CROSS +2721 ; [*085F.0020.0002.2721] # STAR OF DAVID +2722 ; [*0860.0020.0002.2722] # FOUR TEARDROP-SPOKED ASTERISK +2723 ; [*0861.0020.0002.2723] # FOUR BALLOON-SPOKED ASTERISK +2724 ; [*0862.0020.0002.2724] # HEAVY FOUR BALLOON-SPOKED ASTERISK +2725 ; [*0863.0020.0002.2725] # FOUR CLUB-SPOKED ASTERISK +2726 ; [*0864.0020.0002.2726] # BLACK FOUR POINTED STAR +2727 ; [*0865.0020.0002.2727] # WHITE FOUR POINTED STAR +2729 ; [*0866.0020.0002.2729] # STRESS OUTLINED WHITE STAR +272A ; [*0867.0020.0002.272A] # CIRCLED WHITE STAR +272B ; [*0868.0020.0002.272B] # OPEN CENTRE BLACK STAR +272C ; [*0869.0020.0002.272C] # BLACK CENTRE WHITE STAR +272D ; [*086A.0020.0002.272D] # OUTLINED BLACK STAR +272E ; [*086B.0020.0002.272E] # HEAVY OUTLINED BLACK STAR +272F ; [*086C.0020.0002.272F] # PINWHEEL STAR +2730 ; [*086D.0020.0002.2730] # SHADOWED WHITE STAR +2731 ; [*086E.0020.0002.2731] # HEAVY ASTERISK +2732 ; [*086F.0020.0002.2732] # OPEN CENTRE ASTERISK +2733 ; [*0870.0020.0002.2733] # EIGHT SPOKED ASTERISK +2734 ; [*0871.0020.0002.2734] # EIGHT POINTED BLACK STAR +2735 ; [*0872.0020.0002.2735] # EIGHT POINTED PINWHEEL STAR +2736 ; [*0873.0020.0002.2736] # SIX POINTED BLACK STAR +2737 ; [*0874.0020.0002.2737] # EIGHT POINTED RECTILINEAR BLACK STAR +2738 ; [*0875.0020.0002.2738] # HEAVY EIGHT POINTED RECTILINEAR BLACK STAR +2739 ; [*0876.0020.0002.2739] # TWELVE POINTED BLACK STAR +273A ; [*0877.0020.0002.273A] # SIXTEEN POINTED ASTERISK +273B ; [*0878.0020.0002.273B] # TEARDROP-SPOKED ASTERISK +273C ; [*0879.0020.0002.273C] # OPEN CENTRE TEARDROP-SPOKED ASTERISK +273D ; [*087A.0020.0002.273D] # HEAVY TEARDROP-SPOKED ASTERISK +273E ; [*087B.0020.0002.273E] # SIX PETALLED BLACK AND WHITE FLORETTE +273F ; [*087C.0020.0002.273F] # BLACK FLORETTE +2740 ; [*087D.0020.0002.2740] # WHITE FLORETTE +2741 ; [*087E.0020.0002.2741] # EIGHT PETALLED OUTLINED BLACK FLORETTE +2742 ; [*087F.0020.0002.2742] # CIRCLED OPEN CENTRE EIGHT POINTED STAR +2743 ; [*0880.0020.0002.2743] # HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK +2744 ; [*0881.0020.0002.2744] # SNOWFLAKE +2745 ; [*0882.0020.0002.2745] # TIGHT TRIFOLIATE SNOWFLAKE +2746 ; [*0883.0020.0002.2746] # HEAVY CHEVRON SNOWFLAKE +2747 ; [*0884.0020.0002.2747] # SPARKLE +2748 ; [*0885.0020.0002.2748] # HEAVY SPARKLE +2749 ; [*0886.0020.0002.2749] # BALLOON-SPOKED ASTERISK +274A ; [*0887.0020.0002.274A] # EIGHT TEARDROP-SPOKED PROPELLER ASTERISK +274B ; [*0888.0020.0002.274B] # HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK +274D ; [*0889.0020.0002.274D] # SHADOWED WHITE CIRCLE +274F ; [*088A.0020.0002.274F] # LOWER RIGHT DROP-SHADOWED WHITE SQUARE +2750 ; [*088B.0020.0002.2750] # UPPER RIGHT DROP-SHADOWED WHITE SQUARE +2751 ; [*088C.0020.0002.2751] # LOWER RIGHT SHADOWED WHITE SQUARE +2752 ; [*088D.0020.0002.2752] # UPPER RIGHT SHADOWED WHITE SQUARE +2756 ; [*088E.0020.0002.2756] # BLACK DIAMOND MINUS WHITE X +2758 ; [*088F.0020.0002.2758] # LIGHT VERTICAL BAR +2759 ; [*0890.0020.0002.2759] # MEDIUM VERTICAL BAR +275A ; [*0891.0020.0002.275A] # HEAVY VERTICAL BAR +275B ; [*0892.0020.0002.275B] # HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT +275C ; [*0893.0020.0002.275C] # HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT +275D ; [*0894.0020.0002.275D] # HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT +275E ; [*0895.0020.0002.275E] # HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT +2761 ; [*0896.0020.0002.2761] # CURVED STEM PARAGRAPH SIGN ORNAMENT +2762 ; [*0897.0020.0002.2762] # HEAVY EXCLAMATION MARK ORNAMENT +2763 ; [*0898.0020.0002.2763] # HEAVY HEART EXCLAMATION MARK ORNAMENT +2764 ; [*0899.0020.0002.2764] # HEAVY BLACK HEART +2765 ; [*089A.0020.0002.2765] # ROTATED HEAVY BLACK HEART BULLET +2766 ; [*089B.0020.0002.2766] # FLORAL HEART +2767 ; [*089C.0020.0002.2767] # ROTATED FLORAL HEART BULLET +2768 ; [*089D.0020.0002.2768] # MEDIUM LEFT PARENTHESIS ORNAMENT +2769 ; [*089E.0020.0002.2769] # MEDIUM RIGHT PARENTHESIS ORNAMENT +276A ; [*089F.0020.0002.276A] # MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT +276B ; [*08A0.0020.0002.276B] # MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT +276C ; [*08A1.0020.0002.276C] # MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT +276D ; [*08A2.0020.0002.276D] # MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT +276E ; [*08A3.0020.0002.276E] # HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT +276F ; [*08A4.0020.0002.276F] # HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT +2770 ; [*08A5.0020.0002.2770] # HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT +2771 ; [*08A6.0020.0002.2771] # HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT +2772 ; [*08A7.0020.0002.2772] # LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT +2773 ; [*08A8.0020.0002.2773] # LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT +2774 ; [*08A9.0020.0002.2774] # MEDIUM LEFT CURLY BRACKET ORNAMENT +2775 ; [*08AA.0020.0002.2775] # MEDIUM RIGHT CURLY BRACKET ORNAMENT +2794 ; [*08AB.0020.0002.2794] # HEAVY WIDE-HEADED RIGHTWARDS ARROW +2798 ; [*08AC.0020.0002.2798] # HEAVY SOUTH EAST ARROW +2799 ; [*08AD.0020.0002.2799] # HEAVY RIGHTWARDS ARROW +279A ; [*08AE.0020.0002.279A] # HEAVY NORTH EAST ARROW +279B ; [*08AF.0020.0002.279B] # DRAFTING POINT RIGHTWARDS ARROW +279C ; [*08B0.0020.0002.279C] # HEAVY ROUND-TIPPED RIGHTWARDS ARROW +279D ; [*08B1.0020.0002.279D] # TRIANGLE-HEADED RIGHTWARDS ARROW +279E ; [*08B2.0020.0002.279E] # HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW +279F ; [*08B3.0020.0002.279F] # DASHED TRIANGLE-HEADED RIGHTWARDS ARROW +27A0 ; [*08B4.0020.0002.27A0] # HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW +27A1 ; [*08B5.0020.0002.27A1] # BLACK RIGHTWARDS ARROW +27A2 ; [*08B6.0020.0002.27A2] # THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD +27A3 ; [*08B7.0020.0002.27A3] # THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD +27A4 ; [*08B8.0020.0002.27A4] # BLACK RIGHTWARDS ARROWHEAD +27A5 ; [*08B9.0020.0002.27A5] # HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW +27A6 ; [*08BA.0020.0002.27A6] # HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW +27A7 ; [*08BB.0020.0002.27A7] # SQUAT BLACK RIGHTWARDS ARROW +27A8 ; [*08BC.0020.0002.27A8] # HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW +27A9 ; [*08BD.0020.0002.27A9] # RIGHT-SHADED WHITE RIGHTWARDS ARROW +27AA ; [*08BE.0020.0002.27AA] # LEFT-SHADED WHITE RIGHTWARDS ARROW +27AB ; [*08BF.0020.0002.27AB] # BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW +27AC ; [*08C0.0020.0002.27AC] # FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW +27AD ; [*08C1.0020.0002.27AD] # HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW +27AE ; [*08C2.0020.0002.27AE] # HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW +27AF ; [*08C3.0020.0002.27AF] # NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW +27B1 ; [*08C4.0020.0002.27B1] # NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW +27B2 ; [*08C5.0020.0002.27B2] # CIRCLED HEAVY WHITE RIGHTWARDS ARROW +27B3 ; [*08C6.0020.0002.27B3] # WHITE-FEATHERED RIGHTWARDS ARROW +27B4 ; [*08C7.0020.0002.27B4] # BLACK-FEATHERED SOUTH EAST ARROW +27B5 ; [*08C8.0020.0002.27B5] # BLACK-FEATHERED RIGHTWARDS ARROW +27B6 ; [*08C9.0020.0002.27B6] # BLACK-FEATHERED NORTH EAST ARROW +27B7 ; [*08CA.0020.0002.27B7] # HEAVY BLACK-FEATHERED SOUTH EAST ARROW +27B8 ; [*08CB.0020.0002.27B8] # HEAVY BLACK-FEATHERED RIGHTWARDS ARROW +27B9 ; [*08CC.0020.0002.27B9] # HEAVY BLACK-FEATHERED NORTH EAST ARROW +27BA ; [*08CD.0020.0002.27BA] # TEARDROP-BARBED RIGHTWARDS ARROW +27BB ; [*08CE.0020.0002.27BB] # HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW +27BC ; [*08CF.0020.0002.27BC] # WEDGE-TAILED RIGHTWARDS ARROW +27BD ; [*08D0.0020.0002.27BD] # HEAVY WEDGE-TAILED RIGHTWARDS ARROW +27BE ; [*08D1.0020.0002.27BE] # OPEN-OUTLINED RIGHTWARDS ARROW +27C0 ; [*08D2.0020.0002.27C0] # THREE DIMENSIONAL ANGLE +27C1 ; [*08D3.0020.0002.27C1] # WHITE TRIANGLE CONTAINING SMALL WHITE TRIANGLE +27C2 ; [*08D4.0020.0002.27C2] # PERPENDICULAR +27C3 ; [*08D5.0020.0002.27C3] # OPEN SUBSET +27C4 ; [*08D6.0020.0002.27C4] # OPEN SUPERSET +27C5 ; [*08D7.0020.0002.27C5] # LEFT S-SHAPED BAG DELIMITER +27C6 ; [*08D8.0020.0002.27C6] # RIGHT S-SHAPED BAG DELIMITER +27C7 ; [*08D9.0020.0002.27C7] # OR WITH DOT INSIDE +27C8 ; [*08DA.0020.0002.27C8] # REVERSE SOLIDUS PRECEDING SUBSET +27C9 ; [*08DB.0020.0002.27C9] # SUPERSET PRECEDING SOLIDUS +27CA ; [*08DC.0020.0002.27CA] # VERTICAL BAR WITH HORIZONTAL STROKE +27D0 ; [*08DD.0020.0002.27D0] # WHITE DIAMOND WITH CENTRED DOT +27D1 ; [*08DE.0020.0002.27D1] # AND WITH DOT +27D2 ; [*08DF.0020.0002.27D2] # ELEMENT OF OPENING UPWARDS +27D3 ; [*08E0.0020.0002.27D3] # LOWER RIGHT CORNER WITH DOT +27D4 ; [*08E1.0020.0002.27D4] # UPPER LEFT CORNER WITH DOT +27D5 ; [*08E2.0020.0002.27D5] # LEFT OUTER JOIN +27D6 ; [*08E3.0020.0002.27D6] # RIGHT OUTER JOIN +27D7 ; [*08E4.0020.0002.27D7] # FULL OUTER JOIN +27D8 ; [*08E5.0020.0002.27D8] # LARGE UP TACK +27D9 ; [*08E6.0020.0002.27D9] # LARGE DOWN TACK +27DA ; [*08E7.0020.0002.27DA] # LEFT AND RIGHT DOUBLE TURNSTILE +27DB ; [*08E8.0020.0002.27DB] # LEFT AND RIGHT TACK +27DC ; [*08E9.0020.0002.27DC] # LEFT MULTIMAP +27DD ; [*08EA.0020.0002.27DD] # LONG RIGHT TACK +27DE ; [*08EB.0020.0002.27DE] # LONG LEFT TACK +27DF ; [*08EC.0020.0002.27DF] # UP TACK WITH CIRCLE ABOVE +27E0 ; [*08ED.0020.0002.27E0] # LOZENGE DIVIDED BY HORIZONTAL RULE +27E1 ; [*08EE.0020.0002.27E1] # WHITE CONCAVE-SIDED DIAMOND +27E2 ; [*08EF.0020.0002.27E2] # WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK +27E3 ; [*08F0.0020.0002.27E3] # WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK +27E4 ; [*08F1.0020.0002.27E4] # WHITE SQUARE WITH LEFTWARDS TICK +27E5 ; [*08F2.0020.0002.27E5] # WHITE SQUARE WITH RIGHTWARDS TICK +27E6 ; [*08F3.0020.0002.27E6] # MATHEMATICAL LEFT WHITE SQUARE BRACKET +27E7 ; [*08F4.0020.0002.27E7] # MATHEMATICAL RIGHT WHITE SQUARE BRACKET +27E8 ; [*08F5.0020.0002.27E8] # MATHEMATICAL LEFT ANGLE BRACKET +27E9 ; [*08F6.0020.0002.27E9] # MATHEMATICAL RIGHT ANGLE BRACKET +27EA ; [*08F7.0020.0002.27EA] # MATHEMATICAL LEFT DOUBLE ANGLE BRACKET +27EB ; [*08F8.0020.0002.27EB] # MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET +27F0 ; [*08F9.0020.0002.27F0] # UPWARDS QUADRUPLE ARROW +27F1 ; [*08FA.0020.0002.27F1] # DOWNWARDS QUADRUPLE ARROW +27F2 ; [*08FB.0020.0002.27F2] # ANTICLOCKWISE GAPPED CIRCLE ARROW +27F3 ; [*08FC.0020.0002.27F3] # CLOCKWISE GAPPED CIRCLE ARROW +27F4 ; [*08FD.0020.0002.27F4] # RIGHT ARROW WITH CIRCLED PLUS +27F5 ; [*08FE.0020.0002.27F5] # LONG LEFTWARDS ARROW +27F6 ; [*08FF.0020.0002.27F6] # LONG RIGHTWARDS ARROW +27F7 ; [*0900.0020.0002.27F7] # LONG LEFT RIGHT ARROW +27F8 ; [*0901.0020.0002.27F8] # LONG LEFTWARDS DOUBLE ARROW +27F9 ; [*0902.0020.0002.27F9] # LONG RIGHTWARDS DOUBLE ARROW +27FA ; [*0903.0020.0002.27FA] # LONG LEFT RIGHT DOUBLE ARROW +27FB ; [*0904.0020.0002.27FB] # LONG LEFTWARDS ARROW FROM BAR +27FC ; [*0905.0020.0002.27FC] # LONG RIGHTWARDS ARROW FROM BAR +27FD ; [*0906.0020.0002.27FD] # LONG LEFTWARDS DOUBLE ARROW FROM BAR +27FE ; [*0907.0020.0002.27FE] # LONG RIGHTWARDS DOUBLE ARROW FROM BAR +27FF ; [*0908.0020.0002.27FF] # LONG RIGHTWARDS SQUIGGLE ARROW +2800 ; [*0B11.0020.0002.2800] # BRAILLE PATTERN BLANK +2801 ; [*0B12.0020.0002.2801] # BRAILLE PATTERN DOTS-1 +2802 ; [*0B13.0020.0002.2802] # BRAILLE PATTERN DOTS-2 +2803 ; [*0B14.0020.0002.2803] # BRAILLE PATTERN DOTS-12 +2804 ; [*0B15.0020.0002.2804] # BRAILLE PATTERN DOTS-3 +2805 ; [*0B16.0020.0002.2805] # BRAILLE PATTERN DOTS-13 +2806 ; [*0B17.0020.0002.2806] # BRAILLE PATTERN DOTS-23 +2807 ; [*0B18.0020.0002.2807] # BRAILLE PATTERN DOTS-123 +2808 ; [*0B19.0020.0002.2808] # BRAILLE PATTERN DOTS-4 +2809 ; [*0B1A.0020.0002.2809] # BRAILLE PATTERN DOTS-14 +280A ; [*0B1B.0020.0002.280A] # BRAILLE PATTERN DOTS-24 +280B ; [*0B1C.0020.0002.280B] # BRAILLE PATTERN DOTS-124 +280C ; [*0B1D.0020.0002.280C] # BRAILLE PATTERN DOTS-34 +280D ; [*0B1E.0020.0002.280D] # BRAILLE PATTERN DOTS-134 +280E ; [*0B1F.0020.0002.280E] # BRAILLE PATTERN DOTS-234 +280F ; [*0B20.0020.0002.280F] # BRAILLE PATTERN DOTS-1234 +2810 ; [*0B21.0020.0002.2810] # BRAILLE PATTERN DOTS-5 +2811 ; [*0B22.0020.0002.2811] # BRAILLE PATTERN DOTS-15 +2812 ; [*0B23.0020.0002.2812] # BRAILLE PATTERN DOTS-25 +2813 ; [*0B24.0020.0002.2813] # BRAILLE PATTERN DOTS-125 +2814 ; [*0B25.0020.0002.2814] # BRAILLE PATTERN DOTS-35 +2815 ; [*0B26.0020.0002.2815] # BRAILLE PATTERN DOTS-135 +2816 ; [*0B27.0020.0002.2816] # BRAILLE PATTERN DOTS-235 +2817 ; [*0B28.0020.0002.2817] # BRAILLE PATTERN DOTS-1235 +2818 ; [*0B29.0020.0002.2818] # BRAILLE PATTERN DOTS-45 +2819 ; [*0B2A.0020.0002.2819] # BRAILLE PATTERN DOTS-145 +281A ; [*0B2B.0020.0002.281A] # BRAILLE PATTERN DOTS-245 +281B ; [*0B2C.0020.0002.281B] # BRAILLE PATTERN DOTS-1245 +281C ; [*0B2D.0020.0002.281C] # BRAILLE PATTERN DOTS-345 +281D ; [*0B2E.0020.0002.281D] # BRAILLE PATTERN DOTS-1345 +281E ; [*0B2F.0020.0002.281E] # BRAILLE PATTERN DOTS-2345 +281F ; [*0B30.0020.0002.281F] # BRAILLE PATTERN DOTS-12345 +2820 ; [*0B31.0020.0002.2820] # BRAILLE PATTERN DOTS-6 +2821 ; [*0B32.0020.0002.2821] # BRAILLE PATTERN DOTS-16 +2822 ; [*0B33.0020.0002.2822] # BRAILLE PATTERN DOTS-26 +2823 ; [*0B34.0020.0002.2823] # BRAILLE PATTERN DOTS-126 +2824 ; [*0B35.0020.0002.2824] # BRAILLE PATTERN DOTS-36 +2825 ; [*0B36.0020.0002.2825] # BRAILLE PATTERN DOTS-136 +2826 ; [*0B37.0020.0002.2826] # BRAILLE PATTERN DOTS-236 +2827 ; [*0B38.0020.0002.2827] # BRAILLE PATTERN DOTS-1236 +2828 ; [*0B39.0020.0002.2828] # BRAILLE PATTERN DOTS-46 +2829 ; [*0B3A.0020.0002.2829] # BRAILLE PATTERN DOTS-146 +282A ; [*0B3B.0020.0002.282A] # BRAILLE PATTERN DOTS-246 +282B ; [*0B3C.0020.0002.282B] # BRAILLE PATTERN DOTS-1246 +282C ; [*0B3D.0020.0002.282C] # BRAILLE PATTERN DOTS-346 +282D ; [*0B3E.0020.0002.282D] # BRAILLE PATTERN DOTS-1346 +282E ; [*0B3F.0020.0002.282E] # BRAILLE PATTERN DOTS-2346 +282F ; [*0B40.0020.0002.282F] # BRAILLE PATTERN DOTS-12346 +2830 ; [*0B41.0020.0002.2830] # BRAILLE PATTERN DOTS-56 +2831 ; [*0B42.0020.0002.2831] # BRAILLE PATTERN DOTS-156 +2832 ; [*0B43.0020.0002.2832] # BRAILLE PATTERN DOTS-256 +2833 ; [*0B44.0020.0002.2833] # BRAILLE PATTERN DOTS-1256 +2834 ; [*0B45.0020.0002.2834] # BRAILLE PATTERN DOTS-356 +2835 ; [*0B46.0020.0002.2835] # BRAILLE PATTERN DOTS-1356 +2836 ; [*0B47.0020.0002.2836] # BRAILLE PATTERN DOTS-2356 +2837 ; [*0B48.0020.0002.2837] # BRAILLE PATTERN DOTS-12356 +2838 ; [*0B49.0020.0002.2838] # BRAILLE PATTERN DOTS-456 +2839 ; [*0B4A.0020.0002.2839] # BRAILLE PATTERN DOTS-1456 +283A ; [*0B4B.0020.0002.283A] # BRAILLE PATTERN DOTS-2456 +283B ; [*0B4C.0020.0002.283B] # BRAILLE PATTERN DOTS-12456 +283C ; [*0B4D.0020.0002.283C] # BRAILLE PATTERN DOTS-3456 +283D ; [*0B4E.0020.0002.283D] # BRAILLE PATTERN DOTS-13456 +283E ; [*0B4F.0020.0002.283E] # BRAILLE PATTERN DOTS-23456 +283F ; [*0B50.0020.0002.283F] # BRAILLE PATTERN DOTS-123456 +2840 ; [*0B51.0020.0002.2840] # BRAILLE PATTERN DOTS-7 +2841 ; [*0B52.0020.0002.2841] # BRAILLE PATTERN DOTS-17 +2842 ; [*0B53.0020.0002.2842] # BRAILLE PATTERN DOTS-27 +2843 ; [*0B54.0020.0002.2843] # BRAILLE PATTERN DOTS-127 +2844 ; [*0B55.0020.0002.2844] # BRAILLE PATTERN DOTS-37 +2845 ; [*0B56.0020.0002.2845] # BRAILLE PATTERN DOTS-137 +2846 ; [*0B57.0020.0002.2846] # BRAILLE PATTERN DOTS-237 +2847 ; [*0B58.0020.0002.2847] # BRAILLE PATTERN DOTS-1237 +2848 ; [*0B59.0020.0002.2848] # BRAILLE PATTERN DOTS-47 +2849 ; [*0B5A.0020.0002.2849] # BRAILLE PATTERN DOTS-147 +284A ; [*0B5B.0020.0002.284A] # BRAILLE PATTERN DOTS-247 +284B ; [*0B5C.0020.0002.284B] # BRAILLE PATTERN DOTS-1247 +284C ; [*0B5D.0020.0002.284C] # BRAILLE PATTERN DOTS-347 +284D ; [*0B5E.0020.0002.284D] # BRAILLE PATTERN DOTS-1347 +284E ; [*0B5F.0020.0002.284E] # BRAILLE PATTERN DOTS-2347 +284F ; [*0B60.0020.0002.284F] # BRAILLE PATTERN DOTS-12347 +2850 ; [*0B61.0020.0002.2850] # BRAILLE PATTERN DOTS-57 +2851 ; [*0B62.0020.0002.2851] # BRAILLE PATTERN DOTS-157 +2852 ; [*0B63.0020.0002.2852] # BRAILLE PATTERN DOTS-257 +2853 ; [*0B64.0020.0002.2853] # BRAILLE PATTERN DOTS-1257 +2854 ; [*0B65.0020.0002.2854] # BRAILLE PATTERN DOTS-357 +2855 ; [*0B66.0020.0002.2855] # BRAILLE PATTERN DOTS-1357 +2856 ; [*0B67.0020.0002.2856] # BRAILLE PATTERN DOTS-2357 +2857 ; [*0B68.0020.0002.2857] # BRAILLE PATTERN DOTS-12357 +2858 ; [*0B69.0020.0002.2858] # BRAILLE PATTERN DOTS-457 +2859 ; [*0B6A.0020.0002.2859] # BRAILLE PATTERN DOTS-1457 +285A ; [*0B6B.0020.0002.285A] # BRAILLE PATTERN DOTS-2457 +285B ; [*0B6C.0020.0002.285B] # BRAILLE PATTERN DOTS-12457 +285C ; [*0B6D.0020.0002.285C] # BRAILLE PATTERN DOTS-3457 +285D ; [*0B6E.0020.0002.285D] # BRAILLE PATTERN DOTS-13457 +285E ; [*0B6F.0020.0002.285E] # BRAILLE PATTERN DOTS-23457 +285F ; [*0B70.0020.0002.285F] # BRAILLE PATTERN DOTS-123457 +2860 ; [*0B71.0020.0002.2860] # BRAILLE PATTERN DOTS-67 +2861 ; [*0B72.0020.0002.2861] # BRAILLE PATTERN DOTS-167 +2862 ; [*0B73.0020.0002.2862] # BRAILLE PATTERN DOTS-267 +2863 ; [*0B74.0020.0002.2863] # BRAILLE PATTERN DOTS-1267 +2864 ; [*0B75.0020.0002.2864] # BRAILLE PATTERN DOTS-367 +2865 ; [*0B76.0020.0002.2865] # BRAILLE PATTERN DOTS-1367 +2866 ; [*0B77.0020.0002.2866] # BRAILLE PATTERN DOTS-2367 +2867 ; [*0B78.0020.0002.2867] # BRAILLE PATTERN DOTS-12367 +2868 ; [*0B79.0020.0002.2868] # BRAILLE PATTERN DOTS-467 +2869 ; [*0B7A.0020.0002.2869] # BRAILLE PATTERN DOTS-1467 +286A ; [*0B7B.0020.0002.286A] # BRAILLE PATTERN DOTS-2467 +286B ; [*0B7C.0020.0002.286B] # BRAILLE PATTERN DOTS-12467 +286C ; [*0B7D.0020.0002.286C] # BRAILLE PATTERN DOTS-3467 +286D ; [*0B7E.0020.0002.286D] # BRAILLE PATTERN DOTS-13467 +286E ; [*0B7F.0020.0002.286E] # BRAILLE PATTERN DOTS-23467 +286F ; [*0B80.0020.0002.286F] # BRAILLE PATTERN DOTS-123467 +2870 ; [*0B81.0020.0002.2870] # BRAILLE PATTERN DOTS-567 +2871 ; [*0B82.0020.0002.2871] # BRAILLE PATTERN DOTS-1567 +2872 ; [*0B83.0020.0002.2872] # BRAILLE PATTERN DOTS-2567 +2873 ; [*0B84.0020.0002.2873] # BRAILLE PATTERN DOTS-12567 +2874 ; [*0B85.0020.0002.2874] # BRAILLE PATTERN DOTS-3567 +2875 ; [*0B86.0020.0002.2875] # BRAILLE PATTERN DOTS-13567 +2876 ; [*0B87.0020.0002.2876] # BRAILLE PATTERN DOTS-23567 +2877 ; [*0B88.0020.0002.2877] # BRAILLE PATTERN DOTS-123567 +2878 ; [*0B89.0020.0002.2878] # BRAILLE PATTERN DOTS-4567 +2879 ; [*0B8A.0020.0002.2879] # BRAILLE PATTERN DOTS-14567 +287A ; [*0B8B.0020.0002.287A] # BRAILLE PATTERN DOTS-24567 +287B ; [*0B8C.0020.0002.287B] # BRAILLE PATTERN DOTS-124567 +287C ; [*0B8D.0020.0002.287C] # BRAILLE PATTERN DOTS-34567 +287D ; [*0B8E.0020.0002.287D] # BRAILLE PATTERN DOTS-134567 +287E ; [*0B8F.0020.0002.287E] # BRAILLE PATTERN DOTS-234567 +287F ; [*0B90.0020.0002.287F] # BRAILLE PATTERN DOTS-1234567 +2880 ; [*0B91.0020.0002.2880] # BRAILLE PATTERN DOTS-8 +2881 ; [*0B92.0020.0002.2881] # BRAILLE PATTERN DOTS-18 +2882 ; [*0B93.0020.0002.2882] # BRAILLE PATTERN DOTS-28 +2883 ; [*0B94.0020.0002.2883] # BRAILLE PATTERN DOTS-128 +2884 ; [*0B95.0020.0002.2884] # BRAILLE PATTERN DOTS-38 +2885 ; [*0B96.0020.0002.2885] # BRAILLE PATTERN DOTS-138 +2886 ; [*0B97.0020.0002.2886] # BRAILLE PATTERN DOTS-238 +2887 ; [*0B98.0020.0002.2887] # BRAILLE PATTERN DOTS-1238 +2888 ; [*0B99.0020.0002.2888] # BRAILLE PATTERN DOTS-48 +2889 ; [*0B9A.0020.0002.2889] # BRAILLE PATTERN DOTS-148 +288A ; [*0B9B.0020.0002.288A] # BRAILLE PATTERN DOTS-248 +288B ; [*0B9C.0020.0002.288B] # BRAILLE PATTERN DOTS-1248 +288C ; [*0B9D.0020.0002.288C] # BRAILLE PATTERN DOTS-348 +288D ; [*0B9E.0020.0002.288D] # BRAILLE PATTERN DOTS-1348 +288E ; [*0B9F.0020.0002.288E] # BRAILLE PATTERN DOTS-2348 +288F ; [*0BA0.0020.0002.288F] # BRAILLE PATTERN DOTS-12348 +2890 ; [*0BA1.0020.0002.2890] # BRAILLE PATTERN DOTS-58 +2891 ; [*0BA2.0020.0002.2891] # BRAILLE PATTERN DOTS-158 +2892 ; [*0BA3.0020.0002.2892] # BRAILLE PATTERN DOTS-258 +2893 ; [*0BA4.0020.0002.2893] # BRAILLE PATTERN DOTS-1258 +2894 ; [*0BA5.0020.0002.2894] # BRAILLE PATTERN DOTS-358 +2895 ; [*0BA6.0020.0002.2895] # BRAILLE PATTERN DOTS-1358 +2896 ; [*0BA7.0020.0002.2896] # BRAILLE PATTERN DOTS-2358 +2897 ; [*0BA8.0020.0002.2897] # BRAILLE PATTERN DOTS-12358 +2898 ; [*0BA9.0020.0002.2898] # BRAILLE PATTERN DOTS-458 +2899 ; [*0BAA.0020.0002.2899] # BRAILLE PATTERN DOTS-1458 +289A ; [*0BAB.0020.0002.289A] # BRAILLE PATTERN DOTS-2458 +289B ; [*0BAC.0020.0002.289B] # BRAILLE PATTERN DOTS-12458 +289C ; [*0BAD.0020.0002.289C] # BRAILLE PATTERN DOTS-3458 +289D ; [*0BAE.0020.0002.289D] # BRAILLE PATTERN DOTS-13458 +289E ; [*0BAF.0020.0002.289E] # BRAILLE PATTERN DOTS-23458 +289F ; [*0BB0.0020.0002.289F] # BRAILLE PATTERN DOTS-123458 +28A0 ; [*0BB1.0020.0002.28A0] # BRAILLE PATTERN DOTS-68 +28A1 ; [*0BB2.0020.0002.28A1] # BRAILLE PATTERN DOTS-168 +28A2 ; [*0BB3.0020.0002.28A2] # BRAILLE PATTERN DOTS-268 +28A3 ; [*0BB4.0020.0002.28A3] # BRAILLE PATTERN DOTS-1268 +28A4 ; [*0BB5.0020.0002.28A4] # BRAILLE PATTERN DOTS-368 +28A5 ; [*0BB6.0020.0002.28A5] # BRAILLE PATTERN DOTS-1368 +28A6 ; [*0BB7.0020.0002.28A6] # BRAILLE PATTERN DOTS-2368 +28A7 ; [*0BB8.0020.0002.28A7] # BRAILLE PATTERN DOTS-12368 +28A8 ; [*0BB9.0020.0002.28A8] # BRAILLE PATTERN DOTS-468 +28A9 ; [*0BBA.0020.0002.28A9] # BRAILLE PATTERN DOTS-1468 +28AA ; [*0BBB.0020.0002.28AA] # BRAILLE PATTERN DOTS-2468 +28AB ; [*0BBC.0020.0002.28AB] # BRAILLE PATTERN DOTS-12468 +28AC ; [*0BBD.0020.0002.28AC] # BRAILLE PATTERN DOTS-3468 +28AD ; [*0BBE.0020.0002.28AD] # BRAILLE PATTERN DOTS-13468 +28AE ; [*0BBF.0020.0002.28AE] # BRAILLE PATTERN DOTS-23468 +28AF ; [*0BC0.0020.0002.28AF] # BRAILLE PATTERN DOTS-123468 +28B0 ; [*0BC1.0020.0002.28B0] # BRAILLE PATTERN DOTS-568 +28B1 ; [*0BC2.0020.0002.28B1] # BRAILLE PATTERN DOTS-1568 +28B2 ; [*0BC3.0020.0002.28B2] # BRAILLE PATTERN DOTS-2568 +28B3 ; [*0BC4.0020.0002.28B3] # BRAILLE PATTERN DOTS-12568 +28B4 ; [*0BC5.0020.0002.28B4] # BRAILLE PATTERN DOTS-3568 +28B5 ; [*0BC6.0020.0002.28B5] # BRAILLE PATTERN DOTS-13568 +28B6 ; [*0BC7.0020.0002.28B6] # BRAILLE PATTERN DOTS-23568 +28B7 ; [*0BC8.0020.0002.28B7] # BRAILLE PATTERN DOTS-123568 +28B8 ; [*0BC9.0020.0002.28B8] # BRAILLE PATTERN DOTS-4568 +28B9 ; [*0BCA.0020.0002.28B9] # BRAILLE PATTERN DOTS-14568 +28BA ; [*0BCB.0020.0002.28BA] # BRAILLE PATTERN DOTS-24568 +28BB ; [*0BCC.0020.0002.28BB] # BRAILLE PATTERN DOTS-124568 +28BC ; [*0BCD.0020.0002.28BC] # BRAILLE PATTERN DOTS-34568 +28BD ; [*0BCE.0020.0002.28BD] # BRAILLE PATTERN DOTS-134568 +28BE ; [*0BCF.0020.0002.28BE] # BRAILLE PATTERN DOTS-234568 +28BF ; [*0BD0.0020.0002.28BF] # BRAILLE PATTERN DOTS-1234568 +28C0 ; [*0BD1.0020.0002.28C0] # BRAILLE PATTERN DOTS-78 +28C1 ; [*0BD2.0020.0002.28C1] # BRAILLE PATTERN DOTS-178 +28C2 ; [*0BD3.0020.0002.28C2] # BRAILLE PATTERN DOTS-278 +28C3 ; [*0BD4.0020.0002.28C3] # BRAILLE PATTERN DOTS-1278 +28C4 ; [*0BD5.0020.0002.28C4] # BRAILLE PATTERN DOTS-378 +28C5 ; [*0BD6.0020.0002.28C5] # BRAILLE PATTERN DOTS-1378 +28C6 ; [*0BD7.0020.0002.28C6] # BRAILLE PATTERN DOTS-2378 +28C7 ; [*0BD8.0020.0002.28C7] # BRAILLE PATTERN DOTS-12378 +28C8 ; [*0BD9.0020.0002.28C8] # BRAILLE PATTERN DOTS-478 +28C9 ; [*0BDA.0020.0002.28C9] # BRAILLE PATTERN DOTS-1478 +28CA ; [*0BDB.0020.0002.28CA] # BRAILLE PATTERN DOTS-2478 +28CB ; [*0BDC.0020.0002.28CB] # BRAILLE PATTERN DOTS-12478 +28CC ; [*0BDD.0020.0002.28CC] # BRAILLE PATTERN DOTS-3478 +28CD ; [*0BDE.0020.0002.28CD] # BRAILLE PATTERN DOTS-13478 +28CE ; [*0BDF.0020.0002.28CE] # BRAILLE PATTERN DOTS-23478 +28CF ; [*0BE0.0020.0002.28CF] # BRAILLE PATTERN DOTS-123478 +28D0 ; [*0BE1.0020.0002.28D0] # BRAILLE PATTERN DOTS-578 +28D1 ; [*0BE2.0020.0002.28D1] # BRAILLE PATTERN DOTS-1578 +28D2 ; [*0BE3.0020.0002.28D2] # BRAILLE PATTERN DOTS-2578 +28D3 ; [*0BE4.0020.0002.28D3] # BRAILLE PATTERN DOTS-12578 +28D4 ; [*0BE5.0020.0002.28D4] # BRAILLE PATTERN DOTS-3578 +28D5 ; [*0BE6.0020.0002.28D5] # BRAILLE PATTERN DOTS-13578 +28D6 ; [*0BE7.0020.0002.28D6] # BRAILLE PATTERN DOTS-23578 +28D7 ; [*0BE8.0020.0002.28D7] # BRAILLE PATTERN DOTS-123578 +28D8 ; [*0BE9.0020.0002.28D8] # BRAILLE PATTERN DOTS-4578 +28D9 ; [*0BEA.0020.0002.28D9] # BRAILLE PATTERN DOTS-14578 +28DA ; [*0BEB.0020.0002.28DA] # BRAILLE PATTERN DOTS-24578 +28DB ; [*0BEC.0020.0002.28DB] # BRAILLE PATTERN DOTS-124578 +28DC ; [*0BED.0020.0002.28DC] # BRAILLE PATTERN DOTS-34578 +28DD ; [*0BEE.0020.0002.28DD] # BRAILLE PATTERN DOTS-134578 +28DE ; [*0BEF.0020.0002.28DE] # BRAILLE PATTERN DOTS-234578 +28DF ; [*0BF0.0020.0002.28DF] # BRAILLE PATTERN DOTS-1234578 +28E0 ; [*0BF1.0020.0002.28E0] # BRAILLE PATTERN DOTS-678 +28E1 ; [*0BF2.0020.0002.28E1] # BRAILLE PATTERN DOTS-1678 +28E2 ; [*0BF3.0020.0002.28E2] # BRAILLE PATTERN DOTS-2678 +28E3 ; [*0BF4.0020.0002.28E3] # BRAILLE PATTERN DOTS-12678 +28E4 ; [*0BF5.0020.0002.28E4] # BRAILLE PATTERN DOTS-3678 +28E5 ; [*0BF6.0020.0002.28E5] # BRAILLE PATTERN DOTS-13678 +28E6 ; [*0BF7.0020.0002.28E6] # BRAILLE PATTERN DOTS-23678 +28E7 ; [*0BF8.0020.0002.28E7] # BRAILLE PATTERN DOTS-123678 +28E8 ; [*0BF9.0020.0002.28E8] # BRAILLE PATTERN DOTS-4678 +28E9 ; [*0BFA.0020.0002.28E9] # BRAILLE PATTERN DOTS-14678 +28EA ; [*0BFB.0020.0002.28EA] # BRAILLE PATTERN DOTS-24678 +28EB ; [*0BFC.0020.0002.28EB] # BRAILLE PATTERN DOTS-124678 +28EC ; [*0BFD.0020.0002.28EC] # BRAILLE PATTERN DOTS-34678 +28ED ; [*0BFE.0020.0002.28ED] # BRAILLE PATTERN DOTS-134678 +28EE ; [*0BFF.0020.0002.28EE] # BRAILLE PATTERN DOTS-234678 +28EF ; [*0C00.0020.0002.28EF] # BRAILLE PATTERN DOTS-1234678 +28F0 ; [*0C01.0020.0002.28F0] # BRAILLE PATTERN DOTS-5678 +28F1 ; [*0C02.0020.0002.28F1] # BRAILLE PATTERN DOTS-15678 +28F2 ; [*0C03.0020.0002.28F2] # BRAILLE PATTERN DOTS-25678 +28F3 ; [*0C04.0020.0002.28F3] # BRAILLE PATTERN DOTS-125678 +28F4 ; [*0C05.0020.0002.28F4] # BRAILLE PATTERN DOTS-35678 +28F5 ; [*0C06.0020.0002.28F5] # BRAILLE PATTERN DOTS-135678 +28F6 ; [*0C07.0020.0002.28F6] # BRAILLE PATTERN DOTS-235678 +28F7 ; [*0C08.0020.0002.28F7] # BRAILLE PATTERN DOTS-1235678 +28F8 ; [*0C09.0020.0002.28F8] # BRAILLE PATTERN DOTS-45678 +28F9 ; [*0C0A.0020.0002.28F9] # BRAILLE PATTERN DOTS-145678 +28FA ; [*0C0B.0020.0002.28FA] # BRAILLE PATTERN DOTS-245678 +28FB ; [*0C0C.0020.0002.28FB] # BRAILLE PATTERN DOTS-1245678 +28FC ; [*0C0D.0020.0002.28FC] # BRAILLE PATTERN DOTS-345678 +28FD ; [*0C0E.0020.0002.28FD] # BRAILLE PATTERN DOTS-1345678 +28FE ; [*0C0F.0020.0002.28FE] # BRAILLE PATTERN DOTS-2345678 +28FF ; [*0C10.0020.0002.28FF] # BRAILLE PATTERN DOTS-12345678 +2900 ; [*0909.0020.0002.2900] # RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE +2901 ; [*090A.0020.0002.2901] # RIGHTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE +2902 ; [*090B.0020.0002.2902] # LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE +2903 ; [*090C.0020.0002.2903] # RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE +2904 ; [*090D.0020.0002.2904] # LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE +2905 ; [*090E.0020.0002.2905] # RIGHTWARDS TWO-HEADED ARROW FROM BAR +2906 ; [*090F.0020.0002.2906] # LEFTWARDS DOUBLE ARROW FROM BAR +2907 ; [*0910.0020.0002.2907] # RIGHTWARDS DOUBLE ARROW FROM BAR +2908 ; [*0911.0020.0002.2908] # DOWNWARDS ARROW WITH HORIZONTAL STROKE +2909 ; [*0912.0020.0002.2909] # UPWARDS ARROW WITH HORIZONTAL STROKE +290A ; [*0913.0020.0002.290A] # UPWARDS TRIPLE ARROW +290B ; [*0914.0020.0002.290B] # DOWNWARDS TRIPLE ARROW +290C ; [*0915.0020.0002.290C] # LEFTWARDS DOUBLE DASH ARROW +290D ; [*0916.0020.0002.290D] # RIGHTWARDS DOUBLE DASH ARROW +290E ; [*0917.0020.0002.290E] # LEFTWARDS TRIPLE DASH ARROW +290F ; [*0918.0020.0002.290F] # RIGHTWARDS TRIPLE DASH ARROW +2910 ; [*0919.0020.0002.2910] # RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW +2911 ; [*091A.0020.0002.2911] # RIGHTWARDS ARROW WITH DOTTED STEM +2912 ; [*091B.0020.0002.2912] # UPWARDS ARROW TO BAR +2913 ; [*091C.0020.0002.2913] # DOWNWARDS ARROW TO BAR +2914 ; [*091D.0020.0002.2914] # RIGHTWARDS ARROW WITH TAIL WITH VERTICAL STROKE +2915 ; [*091E.0020.0002.2915] # RIGHTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE +2916 ; [*091F.0020.0002.2916] # RIGHTWARDS TWO-HEADED ARROW WITH TAIL +2917 ; [*0920.0020.0002.2917] # RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE +2918 ; [*0921.0020.0002.2918] # RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE +2919 ; [*0922.0020.0002.2919] # LEFTWARDS ARROW-TAIL +291A ; [*0923.0020.0002.291A] # RIGHTWARDS ARROW-TAIL +291B ; [*0924.0020.0002.291B] # LEFTWARDS DOUBLE ARROW-TAIL +291C ; [*0925.0020.0002.291C] # RIGHTWARDS DOUBLE ARROW-TAIL +291D ; [*0926.0020.0002.291D] # LEFTWARDS ARROW TO BLACK DIAMOND +291E ; [*0927.0020.0002.291E] # RIGHTWARDS ARROW TO BLACK DIAMOND +291F ; [*0928.0020.0002.291F] # LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND +2920 ; [*0929.0020.0002.2920] # RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND +2921 ; [*092A.0020.0002.2921] # NORTH WEST AND SOUTH EAST ARROW +2922 ; [*092B.0020.0002.2922] # NORTH EAST AND SOUTH WEST ARROW +2923 ; [*092C.0020.0002.2923] # NORTH WEST ARROW WITH HOOK +2924 ; [*092D.0020.0002.2924] # NORTH EAST ARROW WITH HOOK +2925 ; [*092E.0020.0002.2925] # SOUTH EAST ARROW WITH HOOK +2926 ; [*092F.0020.0002.2926] # SOUTH WEST ARROW WITH HOOK +2927 ; [*0930.0020.0002.2927] # NORTH WEST ARROW AND NORTH EAST ARROW +2928 ; [*0931.0020.0002.2928] # NORTH EAST ARROW AND SOUTH EAST ARROW +2929 ; [*0932.0020.0002.2929] # SOUTH EAST ARROW AND SOUTH WEST ARROW +292A ; [*0933.0020.0002.292A] # SOUTH WEST ARROW AND NORTH WEST ARROW +292B ; [*0934.0020.0002.292B] # RISING DIAGONAL CROSSING FALLING DIAGONAL +292C ; [*0935.0020.0002.292C] # FALLING DIAGONAL CROSSING RISING DIAGONAL +292D ; [*0936.0020.0002.292D] # SOUTH EAST ARROW CROSSING NORTH EAST ARROW +292E ; [*0937.0020.0002.292E] # NORTH EAST ARROW CROSSING SOUTH EAST ARROW +292F ; [*0938.0020.0002.292F] # FALLING DIAGONAL CROSSING NORTH EAST ARROW +2930 ; [*0939.0020.0002.2930] # RISING DIAGONAL CROSSING SOUTH EAST ARROW +2931 ; [*093A.0020.0002.2931] # NORTH EAST ARROW CROSSING NORTH WEST ARROW +2932 ; [*093B.0020.0002.2932] # NORTH WEST ARROW CROSSING NORTH EAST ARROW +2933 ; [*093C.0020.0002.2933] # WAVE ARROW POINTING DIRECTLY RIGHT +2934 ; [*093D.0020.0002.2934] # ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS +2935 ; [*093E.0020.0002.2935] # ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS +2936 ; [*093F.0020.0002.2936] # ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS +2937 ; [*0940.0020.0002.2937] # ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS +2938 ; [*0941.0020.0002.2938] # RIGHT-SIDE ARC CLOCKWISE ARROW +2939 ; [*0942.0020.0002.2939] # LEFT-SIDE ARC ANTICLOCKWISE ARROW +293A ; [*0943.0020.0002.293A] # TOP ARC ANTICLOCKWISE ARROW +293B ; [*0944.0020.0002.293B] # BOTTOM ARC ANTICLOCKWISE ARROW +293C ; [*0945.0020.0002.293C] # TOP ARC CLOCKWISE ARROW WITH MINUS +293D ; [*0946.0020.0002.293D] # TOP ARC ANTICLOCKWISE ARROW WITH PLUS +293E ; [*0947.0020.0002.293E] # LOWER RIGHT SEMICIRCULAR CLOCKWISE ARROW +293F ; [*0948.0020.0002.293F] # LOWER LEFT SEMICIRCULAR ANTICLOCKWISE ARROW +2940 ; [*0949.0020.0002.2940] # ANTICLOCKWISE CLOSED CIRCLE ARROW +2941 ; [*094A.0020.0002.2941] # CLOCKWISE CLOSED CIRCLE ARROW +2942 ; [*094B.0020.0002.2942] # RIGHTWARDS ARROW ABOVE SHORT LEFTWARDS ARROW +2943 ; [*094C.0020.0002.2943] # LEFTWARDS ARROW ABOVE SHORT RIGHTWARDS ARROW +2944 ; [*094D.0020.0002.2944] # SHORT RIGHTWARDS ARROW ABOVE LEFTWARDS ARROW +2945 ; [*094E.0020.0002.2945] # RIGHTWARDS ARROW WITH PLUS BELOW +2946 ; [*094F.0020.0002.2946] # LEFTWARDS ARROW WITH PLUS BELOW +2947 ; [*0950.0020.0002.2947] # RIGHTWARDS ARROW THROUGH X +2948 ; [*0951.0020.0002.2948] # LEFT RIGHT ARROW THROUGH SMALL CIRCLE +2949 ; [*0952.0020.0002.2949] # UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE +294A ; [*0953.0020.0002.294A] # LEFT BARB UP RIGHT BARB DOWN HARPOON +294B ; [*0954.0020.0002.294B] # LEFT BARB DOWN RIGHT BARB UP HARPOON +294C ; [*0955.0020.0002.294C] # UP BARB RIGHT DOWN BARB LEFT HARPOON +294D ; [*0956.0020.0002.294D] # UP BARB LEFT DOWN BARB RIGHT HARPOON +294E ; [*0957.0020.0002.294E] # LEFT BARB UP RIGHT BARB UP HARPOON +294F ; [*0958.0020.0002.294F] # UP BARB RIGHT DOWN BARB RIGHT HARPOON +2950 ; [*0959.0020.0002.2950] # LEFT BARB DOWN RIGHT BARB DOWN HARPOON +2951 ; [*095A.0020.0002.2951] # UP BARB LEFT DOWN BARB LEFT HARPOON +2952 ; [*095B.0020.0002.2952] # LEFTWARDS HARPOON WITH BARB UP TO BAR +2953 ; [*095C.0020.0002.2953] # RIGHTWARDS HARPOON WITH BARB UP TO BAR +2954 ; [*095D.0020.0002.2954] # UPWARDS HARPOON WITH BARB RIGHT TO BAR +2955 ; [*095E.0020.0002.2955] # DOWNWARDS HARPOON WITH BARB RIGHT TO BAR +2956 ; [*095F.0020.0002.2956] # LEFTWARDS HARPOON WITH BARB DOWN TO BAR +2957 ; [*0960.0020.0002.2957] # RIGHTWARDS HARPOON WITH BARB DOWN TO BAR +2958 ; [*0961.0020.0002.2958] # UPWARDS HARPOON WITH BARB LEFT TO BAR +2959 ; [*0962.0020.0002.2959] # DOWNWARDS HARPOON WITH BARB LEFT TO BAR +295A ; [*0963.0020.0002.295A] # LEFTWARDS HARPOON WITH BARB UP FROM BAR +295B ; [*0964.0020.0002.295B] # RIGHTWARDS HARPOON WITH BARB UP FROM BAR +295C ; [*0965.0020.0002.295C] # UPWARDS HARPOON WITH BARB RIGHT FROM BAR +295D ; [*0966.0020.0002.295D] # DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR +295E ; [*0967.0020.0002.295E] # LEFTWARDS HARPOON WITH BARB DOWN FROM BAR +295F ; [*0968.0020.0002.295F] # RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR +2960 ; [*0969.0020.0002.2960] # UPWARDS HARPOON WITH BARB LEFT FROM BAR +2961 ; [*096A.0020.0002.2961] # DOWNWARDS HARPOON WITH BARB LEFT FROM BAR +2962 ; [*096B.0020.0002.2962] # LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN +2963 ; [*096C.0020.0002.2963] # UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT +2964 ; [*096D.0020.0002.2964] # RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN +2965 ; [*096E.0020.0002.2965] # DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT +2966 ; [*096F.0020.0002.2966] # LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP +2967 ; [*0970.0020.0002.2967] # LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN +2968 ; [*0971.0020.0002.2968] # RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP +2969 ; [*0972.0020.0002.2969] # RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN +296A ; [*0973.0020.0002.296A] # LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH +296B ; [*0974.0020.0002.296B] # LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH +296C ; [*0975.0020.0002.296C] # RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH +296D ; [*0976.0020.0002.296D] # RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH +296E ; [*0977.0020.0002.296E] # UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT +296F ; [*0978.0020.0002.296F] # DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT +2970 ; [*0979.0020.0002.2970] # RIGHT DOUBLE ARROW WITH ROUNDED HEAD +2971 ; [*097A.0020.0002.2971] # EQUALS SIGN ABOVE RIGHTWARDS ARROW +2972 ; [*097B.0020.0002.2972] # TILDE OPERATOR ABOVE RIGHTWARDS ARROW +2973 ; [*097C.0020.0002.2973] # LEFTWARDS ARROW ABOVE TILDE OPERATOR +2974 ; [*097D.0020.0002.2974] # RIGHTWARDS ARROW ABOVE TILDE OPERATOR +2975 ; [*097E.0020.0002.2975] # RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO +2976 ; [*097F.0020.0002.2976] # LESS-THAN ABOVE LEFTWARDS ARROW +2977 ; [*0980.0020.0002.2977] # LEFTWARDS ARROW THROUGH LESS-THAN +2978 ; [*0981.0020.0002.2978] # GREATER-THAN ABOVE RIGHTWARDS ARROW +2979 ; [*0982.0020.0002.2979] # SUBSET ABOVE RIGHTWARDS ARROW +297A ; [*0983.0020.0002.297A] # LEFTWARDS ARROW THROUGH SUBSET +297B ; [*0984.0020.0002.297B] # SUPERSET ABOVE LEFTWARDS ARROW +297C ; [*0985.0020.0002.297C] # LEFT FISH TAIL +297D ; [*0986.0020.0002.297D] # RIGHT FISH TAIL +297E ; [*0987.0020.0002.297E] # UP FISH TAIL +297F ; [*0988.0020.0002.297F] # DOWN FISH TAIL +2980 ; [*0989.0020.0002.2980] # TRIPLE VERTICAL BAR DELIMITER +2981 ; [*098A.0020.0002.2981] # Z NOTATION SPOT +2982 ; [*098B.0020.0002.2982] # Z NOTATION TYPE COLON +2983 ; [*02C1.0020.0002.2983] # LEFT WHITE CURLY BRACKET +2984 ; [*02C2.0020.0002.2984] # RIGHT WHITE CURLY BRACKET +2985 ; [*02C3.0020.0002.2985] # LEFT WHITE PARENTHESIS +2986 ; [*02C4.0020.0002.2986] # RIGHT WHITE PARENTHESIS +2987 ; [*02C5.0020.0002.2987] # Z NOTATION LEFT IMAGE BRACKET +2988 ; [*02C6.0020.0002.2988] # Z NOTATION RIGHT IMAGE BRACKET +2989 ; [*02C7.0020.0002.2989] # Z NOTATION LEFT BINDING BRACKET +298A ; [*02C8.0020.0002.298A] # Z NOTATION RIGHT BINDING BRACKET +298B ; [*02C9.0020.0002.298B] # LEFT SQUARE BRACKET WITH UNDERBAR +298C ; [*02CA.0020.0002.298C] # RIGHT SQUARE BRACKET WITH UNDERBAR +298D ; [*02CB.0020.0002.298D] # LEFT SQUARE BRACKET WITH TICK IN TOP CORNER +298E ; [*02CC.0020.0002.298E] # RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER +298F ; [*02CD.0020.0002.298F] # LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER +2990 ; [*02CE.0020.0002.2990] # RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER +2991 ; [*02CF.0020.0002.2991] # LEFT ANGLE BRACKET WITH DOT +2992 ; [*02D0.0020.0002.2992] # RIGHT ANGLE BRACKET WITH DOT +2993 ; [*02D1.0020.0002.2993] # LEFT ARC LESS-THAN BRACKET +2994 ; [*02D2.0020.0002.2994] # RIGHT ARC GREATER-THAN BRACKET +2995 ; [*02D3.0020.0002.2995] # DOUBLE LEFT ARC GREATER-THAN BRACKET +2996 ; [*02D4.0020.0002.2996] # DOUBLE RIGHT ARC LESS-THAN BRACKET +2997 ; [*02D5.0020.0002.2997] # LEFT BLACK TORTOISE SHELL BRACKET +2998 ; [*02D6.0020.0002.2998] # RIGHT BLACK TORTOISE SHELL BRACKET +2999 ; [*098C.0020.0002.2999] # DOTTED FENCE +299A ; [*098D.0020.0002.299A] # VERTICAL ZIGZAG LINE +299B ; [*098E.0020.0002.299B] # MEASURED ANGLE OPENING LEFT +299C ; [*098F.0020.0002.299C] # RIGHT ANGLE VARIANT WITH SQUARE +299D ; [*0990.0020.0002.299D] # MEASURED RIGHT ANGLE WITH DOT +299E ; [*0991.0020.0002.299E] # ANGLE WITH S INSIDE +299F ; [*0992.0020.0002.299F] # ACUTE ANGLE +29A0 ; [*0993.0020.0002.29A0] # SPHERICAL ANGLE OPENING LEFT +29A1 ; [*0994.0020.0002.29A1] # SPHERICAL ANGLE OPENING UP +29A2 ; [*0995.0020.0002.29A2] # TURNED ANGLE +29A3 ; [*0996.0020.0002.29A3] # REVERSED ANGLE +29A4 ; [*0997.0020.0002.29A4] # ANGLE WITH UNDERBAR +29A5 ; [*0998.0020.0002.29A5] # REVERSED ANGLE WITH UNDERBAR +29A6 ; [*0999.0020.0002.29A6] # OBLIQUE ANGLE OPENING UP +29A7 ; [*099A.0020.0002.29A7] # OBLIQUE ANGLE OPENING DOWN +29A8 ; [*099B.0020.0002.29A8] # MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT +29A9 ; [*099C.0020.0002.29A9] # MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT +29AA ; [*099D.0020.0002.29AA] # MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT +29AB ; [*099E.0020.0002.29AB] # MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT +29AC ; [*099F.0020.0002.29AC] # MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP +29AD ; [*09A0.0020.0002.29AD] # MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP +29AE ; [*09A1.0020.0002.29AE] # MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN +29AF ; [*09A2.0020.0002.29AF] # MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN +29B0 ; [*09A3.0020.0002.29B0] # REVERSED EMPTY SET +29B1 ; [*09A4.0020.0002.29B1] # EMPTY SET WITH OVERBAR +29B2 ; [*09A5.0020.0002.29B2] # EMPTY SET WITH SMALL CIRCLE ABOVE +29B3 ; [*09A6.0020.0002.29B3] # EMPTY SET WITH RIGHT ARROW ABOVE +29B4 ; [*09A7.0020.0002.29B4] # EMPTY SET WITH LEFT ARROW ABOVE +29B5 ; [*09A8.0020.0002.29B5] # CIRCLE WITH HORIZONTAL BAR +29B6 ; [*09A9.0020.0002.29B6] # CIRCLED VERTICAL BAR +29B7 ; [*09AA.0020.0002.29B7] # CIRCLED PARALLEL +29B8 ; [*09AB.0020.0002.29B8] # CIRCLED REVERSE SOLIDUS +29B9 ; [*09AC.0020.0002.29B9] # CIRCLED PERPENDICULAR +29BA ; [*09AD.0020.0002.29BA] # CIRCLE DIVIDED BY HORIZONTAL BAR AND TOP HALF DIVIDED BY VERTICAL BAR +29BB ; [*09AE.0020.0002.29BB] # CIRCLE WITH SUPERIMPOSED X +29BC ; [*09AF.0020.0002.29BC] # CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN +29BD ; [*09B0.0020.0002.29BD] # UP ARROW THROUGH CIRCLE +29BE ; [*09B1.0020.0002.29BE] # CIRCLED WHITE BULLET +29BF ; [*09B2.0020.0002.29BF] # CIRCLED BULLET +29C0 ; [*09B3.0020.0002.29C0] # CIRCLED LESS-THAN +29C1 ; [*09B4.0020.0002.29C1] # CIRCLED GREATER-THAN +29C2 ; [*09B5.0020.0002.29C2] # CIRCLE WITH SMALL CIRCLE TO THE RIGHT +29C3 ; [*09B6.0020.0002.29C3] # CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT +29C4 ; [*09B7.0020.0002.29C4] # SQUARED RISING DIAGONAL SLASH +29C5 ; [*09B8.0020.0002.29C5] # SQUARED FALLING DIAGONAL SLASH +29C6 ; [*09B9.0020.0002.29C6] # SQUARED ASTERISK +29C7 ; [*09BA.0020.0002.29C7] # SQUARED SMALL CIRCLE +29C8 ; [*09BB.0020.0002.29C8] # SQUARED SQUARE +29C9 ; [*09BC.0020.0002.29C9] # TWO JOINED SQUARES +29CA ; [*09BD.0020.0002.29CA] # TRIANGLE WITH DOT ABOVE +29CB ; [*09BE.0020.0002.29CB] # TRIANGLE WITH UNDERBAR +29CC ; [*09BF.0020.0002.29CC] # S IN TRIANGLE +29CD ; [*09C0.0020.0002.29CD] # TRIANGLE WITH SERIFS AT BOTTOM +29CE ; [*09C1.0020.0002.29CE] # RIGHT TRIANGLE ABOVE LEFT TRIANGLE +29CF ; [*09C2.0020.0002.29CF] # LEFT TRIANGLE BESIDE VERTICAL BAR +29D0 ; [*09C3.0020.0002.29D0] # VERTICAL BAR BESIDE RIGHT TRIANGLE +29D1 ; [*09C4.0020.0002.29D1] # BOWTIE WITH LEFT HALF BLACK +29D2 ; [*09C5.0020.0002.29D2] # BOWTIE WITH RIGHT HALF BLACK +29D3 ; [*09C6.0020.0002.29D3] # BLACK BOWTIE +29D4 ; [*09C7.0020.0002.29D4] # TIMES WITH LEFT HALF BLACK +29D5 ; [*09C8.0020.0002.29D5] # TIMES WITH RIGHT HALF BLACK +29D6 ; [*09C9.0020.0002.29D6] # WHITE HOURGLASS +29D7 ; [*09CA.0020.0002.29D7] # BLACK HOURGLASS +29D8 ; [*09CB.0020.0002.29D8] # LEFT WIGGLY FENCE +29D9 ; [*09CC.0020.0002.29D9] # RIGHT WIGGLY FENCE +29DA ; [*09CD.0020.0002.29DA] # LEFT DOUBLE WIGGLY FENCE +29DB ; [*09CE.0020.0002.29DB] # RIGHT DOUBLE WIGGLY FENCE +29DC ; [*09CF.0020.0002.29DC] # INCOMPLETE INFINITY +29DD ; [*09D0.0020.0002.29DD] # TIE OVER INFINITY +29DE ; [*09D1.0020.0002.29DE] # INFINITY NEGATED WITH VERTICAL BAR +29DF ; [*09D2.0020.0002.29DF] # DOUBLE-ENDED MULTIMAP +29E0 ; [*09D3.0020.0002.29E0] # SQUARE WITH CONTOURED OUTLINE +29E1 ; [*09D4.0020.0002.29E1] # INCREASES AS +29E2 ; [*09D5.0020.0002.29E2] # SHUFFLE PRODUCT +29E3 ; [*09D6.0020.0002.29E3] # EQUALS SIGN AND SLANTED PARALLEL +29E4 ; [*09D7.0020.0002.29E4] # EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE +29E5 ; [*09D8.0020.0002.29E5] # IDENTICAL TO AND SLANTED PARALLEL +29E6 ; [*09D9.0020.0002.29E6] # GLEICH STARK +29E7 ; [*09DA.0020.0002.29E7] # THERMODYNAMIC +29E8 ; [*09DB.0020.0002.29E8] # DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK +29E9 ; [*09DC.0020.0002.29E9] # DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK +29EA ; [*09DD.0020.0002.29EA] # BLACK DIAMOND WITH DOWN ARROW +29EB ; [*09DE.0020.0002.29EB] # BLACK LOZENGE +29EC ; [*09DF.0020.0002.29EC] # WHITE CIRCLE WITH DOWN ARROW +29ED ; [*09E0.0020.0002.29ED] # BLACK CIRCLE WITH DOWN ARROW +29EE ; [*09E1.0020.0002.29EE] # ERROR-BARRED WHITE SQUARE +29EF ; [*09E2.0020.0002.29EF] # ERROR-BARRED BLACK SQUARE +29F0 ; [*09E3.0020.0002.29F0] # ERROR-BARRED WHITE DIAMOND +29F1 ; [*09E4.0020.0002.29F1] # ERROR-BARRED BLACK DIAMOND +29F2 ; [*09E5.0020.0002.29F2] # ERROR-BARRED WHITE CIRCLE +29F3 ; [*09E6.0020.0002.29F3] # ERROR-BARRED BLACK CIRCLE +29F4 ; [*09E7.0020.0002.29F4] # RULE-DELAYED +29F5 ; [*09E8.0020.0002.29F5] # REVERSE SOLIDUS OPERATOR +29F6 ; [*09E9.0020.0002.29F6] # SOLIDUS WITH OVERBAR +29F7 ; [*09EA.0020.0002.29F7] # REVERSE SOLIDUS WITH HORIZONTAL STROKE +29F8 ; [*09EB.0020.0002.29F8] # BIG SOLIDUS +29F9 ; [*09EC.0020.0002.29F9] # BIG REVERSE SOLIDUS +29FA ; [*09ED.0020.0002.29FA] # DOUBLE PLUS +29FB ; [*09EE.0020.0002.29FB] # TRIPLE PLUS +29FC ; [*02BF.0020.0002.29FC] # LEFT-POINTING CURVED ANGLE BRACKET +29FD ; [*02C0.0020.0002.29FD] # RIGHT-POINTING CURVED ANGLE BRACKET +29FE ; [*09EF.0020.0002.29FE] # TINY +29FF ; [*09F0.0020.0002.29FF] # MINY +2A00 ; [*09F1.0020.0002.2A00] # N-ARY CIRCLED DOT OPERATOR +2A01 ; [*09F2.0020.0002.2A01] # N-ARY CIRCLED PLUS OPERATOR +2A02 ; [*09F3.0020.0002.2A02] # N-ARY CIRCLED TIMES OPERATOR +2A03 ; [*09F4.0020.0002.2A03] # N-ARY UNION OPERATOR WITH DOT +2A04 ; [*09F5.0020.0002.2A04] # N-ARY UNION OPERATOR WITH PLUS +2A05 ; [*09F6.0020.0002.2A05] # N-ARY SQUARE INTERSECTION OPERATOR +2A06 ; [*09F7.0020.0002.2A06] # N-ARY SQUARE UNION OPERATOR +2A07 ; [*09F8.0020.0002.2A07] # TWO LOGICAL AND OPERATOR +2A08 ; [*09F9.0020.0002.2A08] # TWO LOGICAL OR OPERATOR +2A09 ; [*09FA.0020.0002.2A09] # N-ARY TIMES OPERATOR +2A0A ; [*09FB.0020.0002.2A0A] # MODULO TWO SUM +2A0B ; [*09FC.0020.0002.2A0B] # SUMMATION WITH INTEGRAL +2A0C ; [*04DB.0020.0004.2A0C][*04DB.0020.0004.2A0C][*04DB.0020.001F.2A0C][*04DB.0020.001F.2A0C] # QUADRUPLE INTEGRAL OPERATOR; QQKN +2A0D ; [*09FD.0020.0002.2A0D] # FINITE PART INTEGRAL +2A0E ; [*09FE.0020.0002.2A0E] # INTEGRAL WITH DOUBLE STROKE +2A0F ; [*09FF.0020.0002.2A0F] # INTEGRAL AVERAGE WITH SLASH +2A10 ; [*0A00.0020.0002.2A10] # CIRCULATION FUNCTION +2A11 ; [*0A01.0020.0002.2A11] # ANTICLOCKWISE INTEGRATION +2A12 ; [*0A02.0020.0002.2A12] # LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE +2A13 ; [*0A03.0020.0002.2A13] # LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE +2A14 ; [*0A04.0020.0002.2A14] # LINE INTEGRATION NOT INCLUDING THE POLE +2A15 ; [*0A05.0020.0002.2A15] # INTEGRAL AROUND A POINT OPERATOR +2A16 ; [*0A06.0020.0002.2A16] # QUATERNION INTEGRAL OPERATOR +2A17 ; [*0A07.0020.0002.2A17] # INTEGRAL WITH LEFTWARDS ARROW WITH HOOK +2A18 ; [*0A08.0020.0002.2A18] # INTEGRAL WITH TIMES SIGN +2A19 ; [*0A09.0020.0002.2A19] # INTEGRAL WITH INTERSECTION +2A1A ; [*0A0A.0020.0002.2A1A] # INTEGRAL WITH UNION +2A1B ; [*0A0B.0020.0002.2A1B] # INTEGRAL WITH OVERBAR +2A1C ; [*0A0C.0020.0002.2A1C] # INTEGRAL WITH UNDERBAR +2A1D ; [*0A0D.0020.0002.2A1D] # JOIN +2A1E ; [*0A0E.0020.0002.2A1E] # LARGE LEFT TRIANGLE OPERATOR +2A1F ; [*0A0F.0020.0002.2A1F] # Z NOTATION SCHEMA COMPOSITION +2A20 ; [*0A10.0020.0002.2A20] # Z NOTATION SCHEMA PIPING +2A21 ; [*0A11.0020.0002.2A21] # Z NOTATION SCHEMA PROJECTION +2A22 ; [*0A12.0020.0002.2A22] # PLUS SIGN WITH SMALL CIRCLE ABOVE +2A23 ; [*0A13.0020.0002.2A23] # PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE +2A24 ; [*0A14.0020.0002.2A24] # PLUS SIGN WITH TILDE ABOVE +2A25 ; [*0A15.0020.0002.2A25] # PLUS SIGN WITH DOT BELOW +2A26 ; [*0A16.0020.0002.2A26] # PLUS SIGN WITH TILDE BELOW +2A27 ; [*0A17.0020.0002.2A27] # PLUS SIGN WITH SUBSCRIPT TWO +2A28 ; [*0A18.0020.0002.2A28] # PLUS SIGN WITH BLACK TRIANGLE +2A29 ; [*0A19.0020.0002.2A29] # MINUS SIGN WITH COMMA ABOVE +2A2A ; [*0A1A.0020.0002.2A2A] # MINUS SIGN WITH DOT BELOW +2A2B ; [*0A1B.0020.0002.2A2B] # MINUS SIGN WITH FALLING DOTS +2A2C ; [*0A1C.0020.0002.2A2C] # MINUS SIGN WITH RISING DOTS +2A2D ; [*0A1D.0020.0002.2A2D] # PLUS SIGN IN LEFT HALF CIRCLE +2A2E ; [*0A1E.0020.0002.2A2E] # PLUS SIGN IN RIGHT HALF CIRCLE +2A2F ; [*0A1F.0020.0002.2A2F] # VECTOR OR CROSS PRODUCT +2A30 ; [*0A20.0020.0002.2A30] # MULTIPLICATION SIGN WITH DOT ABOVE +2A31 ; [*0A21.0020.0002.2A31] # MULTIPLICATION SIGN WITH UNDERBAR +2A32 ; [*0A22.0020.0002.2A32] # SEMIDIRECT PRODUCT WITH BOTTOM CLOSED +2A33 ; [*0A23.0020.0002.2A33] # SMASH PRODUCT +2A34 ; [*0A24.0020.0002.2A34] # MULTIPLICATION SIGN IN LEFT HALF CIRCLE +2A35 ; [*0A25.0020.0002.2A35] # MULTIPLICATION SIGN IN RIGHT HALF CIRCLE +2A36 ; [*0A26.0020.0002.2A36] # CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT +2A37 ; [*0A27.0020.0002.2A37] # MULTIPLICATION SIGN IN DOUBLE CIRCLE +2A38 ; [*0A28.0020.0002.2A38] # CIRCLED DIVISION SIGN +2A39 ; [*0A29.0020.0002.2A39] # PLUS SIGN IN TRIANGLE +2A3A ; [*0A2A.0020.0002.2A3A] # MINUS SIGN IN TRIANGLE +2A3B ; [*0A2B.0020.0002.2A3B] # MULTIPLICATION SIGN IN TRIANGLE +2A3C ; [*0A2C.0020.0002.2A3C] # INTERIOR PRODUCT +2A3D ; [*0A2D.0020.0002.2A3D] # RIGHTHAND INTERIOR PRODUCT +2A3E ; [*0A2E.0020.0002.2A3E] # Z NOTATION RELATIONAL COMPOSITION +2A3F ; [*0A2F.0020.0002.2A3F] # AMALGAMATION OR COPRODUCT +2A40 ; [*0A30.0020.0002.2A40] # INTERSECTION WITH DOT +2A41 ; [*0A31.0020.0002.2A41] # UNION WITH MINUS SIGN +2A42 ; [*0A32.0020.0002.2A42] # UNION WITH OVERBAR +2A43 ; [*0A33.0020.0002.2A43] # INTERSECTION WITH OVERBAR +2A44 ; [*0A34.0020.0002.2A44] # INTERSECTION WITH LOGICAL AND +2A45 ; [*0A35.0020.0002.2A45] # UNION WITH LOGICAL OR +2A46 ; [*0A36.0020.0002.2A46] # UNION ABOVE INTERSECTION +2A47 ; [*0A37.0020.0002.2A47] # INTERSECTION ABOVE UNION +2A48 ; [*0A38.0020.0002.2A48] # UNION ABOVE BAR ABOVE INTERSECTION +2A49 ; [*0A39.0020.0002.2A49] # INTERSECTION ABOVE BAR ABOVE UNION +2A4A ; [*0A3A.0020.0002.2A4A] # UNION BESIDE AND JOINED WITH UNION +2A4B ; [*0A3B.0020.0002.2A4B] # INTERSECTION BESIDE AND JOINED WITH INTERSECTION +2A4C ; [*0A3C.0020.0002.2A4C] # CLOSED UNION WITH SERIFS +2A4D ; [*0A3D.0020.0002.2A4D] # CLOSED INTERSECTION WITH SERIFS +2A4E ; [*0A3E.0020.0002.2A4E] # DOUBLE SQUARE INTERSECTION +2A4F ; [*0A3F.0020.0002.2A4F] # DOUBLE SQUARE UNION +2A50 ; [*0A40.0020.0002.2A50] # CLOSED UNION WITH SERIFS AND SMASH PRODUCT +2A51 ; [*0A41.0020.0002.2A51] # LOGICAL AND WITH DOT ABOVE +2A52 ; [*0A42.0020.0002.2A52] # LOGICAL OR WITH DOT ABOVE +2A53 ; [*0A43.0020.0002.2A53] # DOUBLE LOGICAL AND +2A54 ; [*0A44.0020.0002.2A54] # DOUBLE LOGICAL OR +2A55 ; [*0A45.0020.0002.2A55] # TWO INTERSECTING LOGICAL AND +2A56 ; [*0A46.0020.0002.2A56] # TWO INTERSECTING LOGICAL OR +2A57 ; [*0A47.0020.0002.2A57] # SLOPING LARGE OR +2A58 ; [*0A48.0020.0002.2A58] # SLOPING LARGE AND +2A59 ; [*0A49.0020.0002.2A59] # LOGICAL OR OVERLAPPING LOGICAL AND +2A5A ; [*0A4A.0020.0002.2A5A] # LOGICAL AND WITH MIDDLE STEM +2A5B ; [*0A4B.0020.0002.2A5B] # LOGICAL OR WITH MIDDLE STEM +2A5C ; [*0A4C.0020.0002.2A5C] # LOGICAL AND WITH HORIZONTAL DASH +2A5D ; [*0A4D.0020.0002.2A5D] # LOGICAL OR WITH HORIZONTAL DASH +2A5E ; [*0A4E.0020.0002.2A5E] # LOGICAL AND WITH DOUBLE OVERBAR +2A5F ; [*0A4F.0020.0002.2A5F] # LOGICAL AND WITH UNDERBAR +2A60 ; [*0A50.0020.0002.2A60] # LOGICAL AND WITH DOUBLE UNDERBAR +2A61 ; [*0A51.0020.0002.2A61] # SMALL VEE WITH UNDERBAR +2A62 ; [*0A52.0020.0002.2A62] # LOGICAL OR WITH DOUBLE OVERBAR +2A63 ; [*0A53.0020.0002.2A63] # LOGICAL OR WITH DOUBLE UNDERBAR +2A64 ; [*0A54.0020.0002.2A64] # Z NOTATION DOMAIN ANTIRESTRICTION +2A65 ; [*0A55.0020.0002.2A65] # Z NOTATION RANGE ANTIRESTRICTION +2A66 ; [*0A56.0020.0002.2A66] # EQUALS SIGN WITH DOT BELOW +2A67 ; [*0A57.0020.0002.2A67] # IDENTICAL WITH DOT ABOVE +2A68 ; [*0A58.0020.0002.2A68] # TRIPLE HORIZONTAL BAR WITH DOUBLE VERTICAL STROKE +2A69 ; [*0A59.0020.0002.2A69] # TRIPLE HORIZONTAL BAR WITH TRIPLE VERTICAL STROKE +2A6A ; [*0A5A.0020.0002.2A6A] # TILDE OPERATOR WITH DOT ABOVE +2A6B ; [*0A5B.0020.0002.2A6B] # TILDE OPERATOR WITH RISING DOTS +2A6C ; [*0A5C.0020.0002.2A6C] # SIMILAR MINUS SIMILAR +2A6D ; [*0A5D.0020.0002.2A6D] # CONGRUENT WITH DOT ABOVE +2A6E ; [*0A5E.0020.0002.2A6E] # EQUALS WITH ASTERISK +2A6F ; [*0A5F.0020.0002.2A6F] # ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT +2A70 ; [*0A60.0020.0002.2A70] # APPROXIMATELY EQUAL OR EQUAL TO +2A71 ; [*0A61.0020.0002.2A71] # EQUALS SIGN ABOVE PLUS SIGN +2A72 ; [*0A62.0020.0002.2A72] # PLUS SIGN ABOVE EQUALS SIGN +2A73 ; [*0A63.0020.0002.2A73] # EQUALS SIGN ABOVE TILDE OPERATOR +2A74 ; [*0241.0020.0004.2A74][*0241.0020.0004.2A74][*04BD.0020.001F.2A74] # DOUBLE COLON EQUAL; QQKN +2A75 ; [*04BD.0020.0004.2A75][*04BD.0020.0004.2A75] # TWO CONSECUTIVE EQUALS SIGNS; QQKN +2A76 ; [*04BD.0020.0004.2A76][*04BD.0020.0004.2A76][*04BD.0020.001F.2A76] # THREE CONSECUTIVE EQUALS SIGNS; QQKN +2A77 ; [*0A64.0020.0002.2A77] # EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW +2A78 ; [*0A65.0020.0002.2A78] # EQUIVALENT WITH FOUR DOTS ABOVE +2A79 ; [*0A66.0020.0002.2A79] # LESS-THAN WITH CIRCLE INSIDE +2A7A ; [*0A67.0020.0002.2A7A] # GREATER-THAN WITH CIRCLE INSIDE +2A7B ; [*0A68.0020.0002.2A7B] # LESS-THAN WITH QUESTION MARK ABOVE +2A7C ; [*0A69.0020.0002.2A7C] # GREATER-THAN WITH QUESTION MARK ABOVE +2A7D ; [*0A6A.0020.0002.2A7D] # LESS-THAN OR SLANTED EQUAL TO +2A7E ; [*0A6B.0020.0002.2A7E] # GREATER-THAN OR SLANTED EQUAL TO +2A7F ; [*0A6C.0020.0002.2A7F] # LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE +2A80 ; [*0A6D.0020.0002.2A80] # GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE +2A81 ; [*0A6E.0020.0002.2A81] # LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE +2A82 ; [*0A6F.0020.0002.2A82] # GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE +2A83 ; [*0A70.0020.0002.2A83] # LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT +2A84 ; [*0A71.0020.0002.2A84] # GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT +2A85 ; [*0A72.0020.0002.2A85] # LESS-THAN OR APPROXIMATE +2A86 ; [*0A73.0020.0002.2A86] # GREATER-THAN OR APPROXIMATE +2A87 ; [*0A74.0020.0002.2A87] # LESS-THAN AND SINGLE-LINE NOT EQUAL TO +2A88 ; [*0A75.0020.0002.2A88] # GREATER-THAN AND SINGLE-LINE NOT EQUAL TO +2A89 ; [*0A76.0020.0002.2A89] # LESS-THAN AND NOT APPROXIMATE +2A8A ; [*0A77.0020.0002.2A8A] # GREATER-THAN AND NOT APPROXIMATE +2A8B ; [*0A78.0020.0002.2A8B] # LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN +2A8C ; [*0A79.0020.0002.2A8C] # GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN +2A8D ; [*0A7A.0020.0002.2A8D] # LESS-THAN ABOVE SIMILAR OR EQUAL +2A8E ; [*0A7B.0020.0002.2A8E] # GREATER-THAN ABOVE SIMILAR OR EQUAL +2A8F ; [*0A7C.0020.0002.2A8F] # LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN +2A90 ; [*0A7D.0020.0002.2A90] # GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN +2A91 ; [*0A7E.0020.0002.2A91] # LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL +2A92 ; [*0A7F.0020.0002.2A92] # GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL +2A93 ; [*0A80.0020.0002.2A93] # LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL +2A94 ; [*0A81.0020.0002.2A94] # GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL +2A95 ; [*0A82.0020.0002.2A95] # SLANTED EQUAL TO OR LESS-THAN +2A96 ; [*0A83.0020.0002.2A96] # SLANTED EQUAL TO OR GREATER-THAN +2A97 ; [*0A84.0020.0002.2A97] # SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE +2A98 ; [*0A85.0020.0002.2A98] # SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE +2A99 ; [*0A86.0020.0002.2A99] # DOUBLE-LINE EQUAL TO OR LESS-THAN +2A9A ; [*0A87.0020.0002.2A9A] # DOUBLE-LINE EQUAL TO OR GREATER-THAN +2A9B ; [*0A88.0020.0002.2A9B] # DOUBLE-LINE SLANTED EQUAL TO OR LESS-THAN +2A9C ; [*0A89.0020.0002.2A9C] # DOUBLE-LINE SLANTED EQUAL TO OR GREATER-THAN +2A9D ; [*0A8A.0020.0002.2A9D] # SIMILAR OR LESS-THAN +2A9E ; [*0A8B.0020.0002.2A9E] # SIMILAR OR GREATER-THAN +2A9F ; [*0A8C.0020.0002.2A9F] # SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN +2AA0 ; [*0A8D.0020.0002.2AA0] # SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN +2AA1 ; [*0A8E.0020.0002.2AA1] # DOUBLE NESTED LESS-THAN +2AA2 ; [*0A8F.0020.0002.2AA2] # DOUBLE NESTED GREATER-THAN +2AA3 ; [*0A90.0020.0002.2AA3] # DOUBLE NESTED LESS-THAN WITH UNDERBAR +2AA4 ; [*0A91.0020.0002.2AA4] # GREATER-THAN OVERLAPPING LESS-THAN +2AA5 ; [*0A92.0020.0002.2AA5] # GREATER-THAN BESIDE LESS-THAN +2AA6 ; [*0A93.0020.0002.2AA6] # LESS-THAN CLOSED BY CURVE +2AA7 ; [*0A94.0020.0002.2AA7] # GREATER-THAN CLOSED BY CURVE +2AA8 ; [*0A95.0020.0002.2AA8] # LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL +2AA9 ; [*0A96.0020.0002.2AA9] # GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL +2AAA ; [*0A97.0020.0002.2AAA] # SMALLER THAN +2AAB ; [*0A98.0020.0002.2AAB] # LARGER THAN +2AAC ; [*0A99.0020.0002.2AAC] # SMALLER THAN OR EQUAL TO +2AAD ; [*0A9A.0020.0002.2AAD] # LARGER THAN OR EQUAL TO +2AAE ; [*0A9B.0020.0002.2AAE] # EQUALS SIGN WITH BUMPY ABOVE +2AAF ; [*0A9C.0020.0002.2AAF] # PRECEDES ABOVE SINGLE-LINE EQUALS SIGN +2AB0 ; [*0A9D.0020.0002.2AB0] # SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN +2AB1 ; [*0A9E.0020.0002.2AB1] # PRECEDES ABOVE SINGLE-LINE NOT EQUAL TO +2AB2 ; [*0A9F.0020.0002.2AB2] # SUCCEEDS ABOVE SINGLE-LINE NOT EQUAL TO +2AB3 ; [*0AA0.0020.0002.2AB3] # PRECEDES ABOVE EQUALS SIGN +2AB4 ; [*0AA1.0020.0002.2AB4] # SUCCEEDS ABOVE EQUALS SIGN +2AB5 ; [*0AA2.0020.0002.2AB5] # PRECEDES ABOVE NOT EQUAL TO +2AB6 ; [*0AA3.0020.0002.2AB6] # SUCCEEDS ABOVE NOT EQUAL TO +2AB7 ; [*0AA4.0020.0002.2AB7] # PRECEDES ABOVE ALMOST EQUAL TO +2AB8 ; [*0AA5.0020.0002.2AB8] # SUCCEEDS ABOVE ALMOST EQUAL TO +2AB9 ; [*0AA6.0020.0002.2AB9] # PRECEDES ABOVE NOT ALMOST EQUAL TO +2ABA ; [*0AA7.0020.0002.2ABA] # SUCCEEDS ABOVE NOT ALMOST EQUAL TO +2ABB ; [*0AA8.0020.0002.2ABB] # DOUBLE PRECEDES +2ABC ; [*0AA9.0020.0002.2ABC] # DOUBLE SUCCEEDS +2ABD ; [*0AAA.0020.0002.2ABD] # SUBSET WITH DOT +2ABE ; [*0AAB.0020.0002.2ABE] # SUPERSET WITH DOT +2ABF ; [*0AAC.0020.0002.2ABF] # SUBSET WITH PLUS SIGN BELOW +2AC0 ; [*0AAD.0020.0002.2AC0] # SUPERSET WITH PLUS SIGN BELOW +2AC1 ; [*0AAE.0020.0002.2AC1] # SUBSET WITH MULTIPLICATION SIGN BELOW +2AC2 ; [*0AAF.0020.0002.2AC2] # SUPERSET WITH MULTIPLICATION SIGN BELOW +2AC3 ; [*0AB0.0020.0002.2AC3] # SUBSET OF OR EQUAL TO WITH DOT ABOVE +2AC4 ; [*0AB1.0020.0002.2AC4] # SUPERSET OF OR EQUAL TO WITH DOT ABOVE +2AC5 ; [*0AB2.0020.0002.2AC5] # SUBSET OF ABOVE EQUALS SIGN +2AC6 ; [*0AB3.0020.0002.2AC6] # SUPERSET OF ABOVE EQUALS SIGN +2AC7 ; [*0AB4.0020.0002.2AC7] # SUBSET OF ABOVE TILDE OPERATOR +2AC8 ; [*0AB5.0020.0002.2AC8] # SUPERSET OF ABOVE TILDE OPERATOR +2AC9 ; [*0AB6.0020.0002.2AC9] # SUBSET OF ABOVE ALMOST EQUAL TO +2ACA ; [*0AB7.0020.0002.2ACA] # SUPERSET OF ABOVE ALMOST EQUAL TO +2ACB ; [*0AB8.0020.0002.2ACB] # SUBSET OF ABOVE NOT EQUAL TO +2ACC ; [*0AB9.0020.0002.2ACC] # SUPERSET OF ABOVE NOT EQUAL TO +2ACD ; [*0ABA.0020.0002.2ACD] # SQUARE LEFT OPEN BOX OPERATOR +2ACE ; [*0ABB.0020.0002.2ACE] # SQUARE RIGHT OPEN BOX OPERATOR +2ACF ; [*0ABC.0020.0002.2ACF] # CLOSED SUBSET +2AD0 ; [*0ABD.0020.0002.2AD0] # CLOSED SUPERSET +2AD1 ; [*0ABE.0020.0002.2AD1] # CLOSED SUBSET OR EQUAL TO +2AD2 ; [*0ABF.0020.0002.2AD2] # CLOSED SUPERSET OR EQUAL TO +2AD3 ; [*0AC0.0020.0002.2AD3] # SUBSET ABOVE SUPERSET +2AD4 ; [*0AC1.0020.0002.2AD4] # SUPERSET ABOVE SUBSET +2AD5 ; [*0AC2.0020.0002.2AD5] # SUBSET ABOVE SUBSET +2AD6 ; [*0AC3.0020.0002.2AD6] # SUPERSET ABOVE SUPERSET +2AD7 ; [*0AC4.0020.0002.2AD7] # SUPERSET BESIDE SUBSET +2AD8 ; [*0AC5.0020.0002.2AD8] # SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET +2AD9 ; [*0AC6.0020.0002.2AD9] # ELEMENT OF OPENING DOWNWARDS +2ADA ; [*0AC7.0020.0002.2ADA] # PITCHFORK WITH TEE TOP +2ADB ; [*0AC8.0020.0002.2ADB] # TRANSVERSAL INTERSECTION +2ADC ; [*0AC9.0020.0002.2ADD][.0000.0054.0002.0338] # FORKING; QQCM +2ADD ; [*0AC9.0020.0002.2ADD] # NONFORKING +2ADE ; [*0ACA.0020.0002.2ADE] # SHORT LEFT TACK +2ADF ; [*0ACB.0020.0002.2ADF] # SHORT DOWN TACK +2AE0 ; [*0ACC.0020.0002.2AE0] # SHORT UP TACK +2AE1 ; [*0ACD.0020.0002.2AE1] # PERPENDICULAR WITH S +2AE2 ; [*0ACE.0020.0002.2AE2] # VERTICAL BAR TRIPLE RIGHT TURNSTILE +2AE3 ; [*0ACF.0020.0002.2AE3] # DOUBLE VERTICAL BAR LEFT TURNSTILE +2AE4 ; [*0AD0.0020.0002.2AE4] # VERTICAL BAR DOUBLE LEFT TURNSTILE +2AE5 ; [*0AD1.0020.0002.2AE5] # DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE +2AE6 ; [*0AD2.0020.0002.2AE6] # LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL +2AE7 ; [*0AD3.0020.0002.2AE7] # SHORT DOWN TACK WITH OVERBAR +2AE8 ; [*0AD4.0020.0002.2AE8] # SHORT UP TACK WITH UNDERBAR +2AE9 ; [*0AD5.0020.0002.2AE9] # SHORT UP TACK ABOVE SHORT DOWN TACK +2AEA ; [*0AD6.0020.0002.2AEA] # DOUBLE DOWN TACK +2AEB ; [*0AD7.0020.0002.2AEB] # DOUBLE UP TACK +2AEC ; [*0AD8.0020.0002.2AEC] # DOUBLE STROKE NOT SIGN +2AED ; [*0AD9.0020.0002.2AED] # REVERSED DOUBLE STROKE NOT SIGN +2AEE ; [*0ADA.0020.0002.2AEE] # DOES NOT DIVIDE WITH REVERSED NEGATION SLASH +2AEF ; [*0ADB.0020.0002.2AEF] # VERTICAL LINE WITH CIRCLE ABOVE +2AF0 ; [*0ADC.0020.0002.2AF0] # VERTICAL LINE WITH CIRCLE BELOW +2AF1 ; [*0ADD.0020.0002.2AF1] # DOWN TACK WITH CIRCLE BELOW +2AF2 ; [*0ADE.0020.0002.2AF2] # PARALLEL WITH HORIZONTAL STROKE +2AF3 ; [*0ADF.0020.0002.2AF3] # PARALLEL WITH TILDE OPERATOR +2AF4 ; [*0AE0.0020.0002.2AF4] # TRIPLE VERTICAL BAR BINARY RELATION +2AF5 ; [*0AE1.0020.0002.2AF5] # TRIPLE VERTICAL BAR WITH HORIZONTAL STROKE +2AF6 ; [*0AE2.0020.0002.2AF6] # TRIPLE COLON OPERATOR +2AF7 ; [*0AE3.0020.0002.2AF7] # TRIPLE NESTED LESS-THAN +2AF8 ; [*0AE4.0020.0002.2AF8] # TRIPLE NESTED GREATER-THAN +2AF9 ; [*0AE5.0020.0002.2AF9] # DOUBLE-LINE SLANTED LESS-THAN OR EQUAL TO +2AFA ; [*0AE6.0020.0002.2AFA] # DOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TO +2AFB ; [*0AE7.0020.0002.2AFB] # TRIPLE SOLIDUS BINARY RELATION +2AFC ; [*0AE8.0020.0002.2AFC] # LARGE TRIPLE VERTICAL BAR OPERATOR +2AFD ; [*0AE9.0020.0002.2AFD] # DOUBLE SOLIDUS OPERATOR +2AFE ; [*0AEA.0020.0002.2AFE] # WHITE VERTICAL BAR +2AFF ; [*0AEB.0020.0002.2AFF] # N-ARY WHITE VERTICAL BAR +2B00 ; [*0AEC.0020.0002.2B00] # NORTH EAST WHITE ARROW +2B01 ; [*0AED.0020.0002.2B01] # NORTH WEST WHITE ARROW +2B02 ; [*0AEE.0020.0002.2B02] # SOUTH EAST WHITE ARROW +2B03 ; [*0AEF.0020.0002.2B03] # SOUTH WEST WHITE ARROW +2B04 ; [*0AF0.0020.0002.2B04] # LEFT RIGHT WHITE ARROW +2B05 ; [*0AF1.0020.0002.2B05] # LEFTWARDS BLACK ARROW +2B06 ; [*0AF2.0020.0002.2B06] # UPWARDS BLACK ARROW +2B07 ; [*0AF3.0020.0002.2B07] # DOWNWARDS BLACK ARROW +2B08 ; [*0AF4.0020.0002.2B08] # NORTH EAST BLACK ARROW +2B09 ; [*0AF5.0020.0002.2B09] # NORTH WEST BLACK ARROW +2B0A ; [*0AF6.0020.0002.2B0A] # SOUTH EAST BLACK ARROW +2B0B ; [*0AF7.0020.0002.2B0B] # SOUTH WEST BLACK ARROW +2B0C ; [*0AF8.0020.0002.2B0C] # LEFT RIGHT BLACK ARROW +2B0D ; [*0AF9.0020.0002.2B0D] # UP DOWN BLACK ARROW +2B0E ; [*0AFA.0020.0002.2B0E] # RIGHTWARDS ARROW WITH TIP DOWNWARDS +2B0F ; [*0AFB.0020.0002.2B0F] # RIGHTWARDS ARROW WITH TIP UPWARDS +2B10 ; [*0AFC.0020.0002.2B10] # LEFTWARDS ARROW WITH TIP DOWNWARDS +2B11 ; [*0AFD.0020.0002.2B11] # LEFTWARDS ARROW WITH TIP UPWARDS +2B12 ; [*0AFE.0020.0002.2B12] # SQUARE WITH TOP HALF BLACK +2B13 ; [*0AFF.0020.0002.2B13] # SQUARE WITH BOTTOM HALF BLACK +2B14 ; [*0B00.0020.0002.2B14] # SQUARE WITH UPPER RIGHT DIAGONAL HALF BLACK +2B15 ; [*0B01.0020.0002.2B15] # SQUARE WITH LOWER LEFT DIAGONAL HALF BLACK +2B16 ; [*0B02.0020.0002.2B16] # DIAMOND WITH LEFT HALF BLACK +2B17 ; [*0B03.0020.0002.2B17] # DIAMOND WITH RIGHT HALF BLACK +2B18 ; [*0B04.0020.0002.2B18] # DIAMOND WITH TOP HALF BLACK +2B19 ; [*0B05.0020.0002.2B19] # DIAMOND WITH BOTTOM HALF BLACK +2B1A ; [*0B06.0020.0002.2B1A] # DOTTED SQUARE +2B20 ; [*0B07.0020.0002.2B20] # WHITE PENTAGON +2B21 ; [*0B08.0020.0002.2B21] # WHITE HEXAGON +2B22 ; [*0B09.0020.0002.2B22] # BLACK HEXAGON +2B23 ; [*0B0A.0020.0002.2B23] # HORIZONTAL BLACK HEXAGON +2CE5 ; [*0B0B.0020.0002.2CE5] # COPTIC SYMBOL MI RO +2CE6 ; [*0B0C.0020.0002.2CE6] # COPTIC SYMBOL PI RO +2CE7 ; [*0B0D.0020.0002.2CE7] # COPTIC SYMBOL STAUROS +2CE8 ; [*0B0E.0020.0002.2CE8] # COPTIC SYMBOL TAU RO +2CE9 ; [*0B0F.0020.0002.2CE9] # COPTIC SYMBOL KHI RO +2CEA ; [*0B10.0020.0002.2CEA] # COPTIC SYMBOL SHIMA SIMA +2CF9 ; [*0270.0020.0002.2CF9] # COPTIC OLD NUBIAN FULL STOP +2CFA ; [*0263.0020.0002.2CFA] # COPTIC OLD NUBIAN DIRECT QUESTION MARK +2CFB ; [*0264.0020.0002.2CFB] # COPTIC OLD NUBIAN INDIRECT QUESTION MARK +2CFC ; [*0294.0020.0002.2CFC] # COPTIC OLD NUBIAN VERSE DIVIDER +2CFD ; [*0F26.0020.0002.2CFD] # COPTIC FRACTION ONE HALF +2CFE ; [*0271.0020.0002.2CFE] # COPTIC FULL STOP +2CFF ; [*0295.0020.0002.2CFF] # COPTIC MORPHOLOGICAL DIVIDER +2E00 ; [*031F.0020.0002.2E00] # RIGHT ANGLE SUBSTITUTION MARKER +2E01 ; [*0320.0020.0002.2E01] # RIGHT ANGLE DOTTED SUBSTITUTION MARKER +2E02 ; [*02D7.0020.0002.2E02] # LEFT SUBSTITUTION BRACKET +2E03 ; [*02D8.0020.0002.2E03] # RIGHT SUBSTITUTION BRACKET +2E04 ; [*02D9.0020.0002.2E04] # LEFT DOTTED SUBSTITUTION BRACKET +2E05 ; [*02DA.0020.0002.2E05] # RIGHT DOTTED SUBSTITUTION BRACKET +2E06 ; [*0321.0020.0002.2E06] # RAISED INTERPOLATION MARKER +2E07 ; [*0322.0020.0002.2E07] # RAISED DOTTED INTERPOLATION MARKER +2E08 ; [*0323.0020.0002.2E08] # DOTTED TRANSPOSITION MARKER +2E09 ; [*02DB.0020.0002.2E09] # LEFT TRANSPOSITION BRACKET +2E0A ; [*02DC.0020.0002.2E0A] # RIGHT TRANSPOSITION BRACKET +2E0B ; [*0324.0020.0002.2E0B] # RAISED SQUARE +2E0C ; [*02DD.0020.0002.2E0C] # LEFT RAISED OMISSION BRACKET +2E0D ; [*02DE.0020.0002.2E0D] # RIGHT RAISED OMISSION BRACKET +2E0E ; [*0325.0020.0002.2E0E] # EDITORIAL CORONIS +2E0F ; [*0326.0020.0002.2E0F] # PARAGRAPHOS +2E10 ; [*0327.0020.0002.2E10] # FORKED PARAGRAPHOS +2E11 ; [*0328.0020.0002.2E11] # REVERSED FORKED PARAGRAPHOS +2E12 ; [*0329.0020.0002.2E12] # HYPODIASTOLE +2E13 ; [*032A.0020.0002.2E13] # DOTTED OBELOS +2E14 ; [*032B.0020.0002.2E14] # DOWNWARDS ANCORA +2E15 ; [*032C.0020.0002.2E15] # UPWARDS ANCORA +2E16 ; [*032D.0020.0002.2E16] # DOTTED RIGHT-POINTING ANGLE +2E17 ; [*022D.0020.0002.2E17] # DOUBLE OBLIQUE HYPHEN +2E1C ; [*02DF.0020.0002.2E1C] # LEFT LOW PARAPHRASE BRACKET +2E1D ; [*02E0.0020.0002.2E1D] # RIGHT LOW PARAPHRASE BRACKET +2FF0 ; [*0EEB.0020.0002.2FF0] # IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT +2FF1 ; [*0EEC.0020.0002.2FF1] # IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO BELOW +2FF2 ; [*0EED.0020.0002.2FF2] # IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO MIDDLE AND RIGHT +2FF3 ; [*0EEE.0020.0002.2FF3] # IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO MIDDLE AND BELOW +2FF4 ; [*0EEF.0020.0002.2FF4] # IDEOGRAPHIC DESCRIPTION CHARACTER FULL SURROUND +2FF5 ; [*0EF0.0020.0002.2FF5] # IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM ABOVE +2FF6 ; [*0EF1.0020.0002.2FF6] # IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM BELOW +2FF7 ; [*0EF2.0020.0002.2FF7] # IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LEFT +2FF8 ; [*0EF3.0020.0002.2FF8] # IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER LEFT +2FF9 ; [*0EF4.0020.0002.2FF9] # IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER RIGHT +2FFA ; [*0EF5.0020.0002.2FFA] # IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LOWER LEFT +2FFB ; [*0EF6.0020.0002.2FFB] # IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID +3000 ; [*0209.0020.0003.3000] # IDEOGRAPHIC SPACE; QQK +3001 ; [*023B.0020.0002.3001] # IDEOGRAPHIC COMMA +3002 ; [*0272.0020.0002.3002] # IDEOGRAPHIC FULL STOP +3003 ; [*0315.0020.0002.3003] # DITTO MARK +3004 ; [*0F07.0020.0002.3004] # JAPANESE INDUSTRIAL STANDARD SYMBOL +3008 ; [*02E1.0020.0002.3008] # LEFT ANGLE BRACKET +3009 ; [*02E2.0020.0002.3009] # RIGHT ANGLE BRACKET +300A ; [*02E3.0020.0002.300A] # LEFT DOUBLE ANGLE BRACKET +300B ; [*02E4.0020.0002.300B] # RIGHT DOUBLE ANGLE BRACKET +300C ; [*02E5.0020.0002.300C] # LEFT CORNER BRACKET +300D ; [*02E6.0020.0002.300D] # RIGHT CORNER BRACKET +300E ; [*02E7.0020.0002.300E] # LEFT WHITE CORNER BRACKET +300F ; [*02E8.0020.0002.300F] # RIGHT WHITE CORNER BRACKET +3010 ; [*02E9.0020.0002.3010] # LEFT BLACK LENTICULAR BRACKET +3011 ; [*02EA.0020.0002.3011] # RIGHT BLACK LENTICULAR BRACKET +3012 ; [*0F08.0020.0002.3012] # POSTAL MARK +3013 ; [*0F09.0020.0002.3013] # GETA MARK +3014 ; [*02EB.0020.0002.3014] # LEFT TORTOISE SHELL BRACKET +3015 ; [*02EC.0020.0002.3015] # RIGHT TORTOISE SHELL BRACKET +3016 ; [*02ED.0020.0002.3016] # LEFT WHITE LENTICULAR BRACKET +3017 ; [*02EE.0020.0002.3017] # RIGHT WHITE LENTICULAR BRACKET +3018 ; [*02EF.0020.0002.3018] # LEFT WHITE TORTOISE SHELL BRACKET +3019 ; [*02F0.0020.0002.3019] # RIGHT WHITE TORTOISE SHELL BRACKET +301A ; [*02F1.0020.0002.301A] # LEFT WHITE SQUARE BRACKET +301B ; [*02F2.0020.0002.301B] # RIGHT WHITE SQUARE BRACKET +301C ; [*022E.0020.0002.301C] # WAVE DASH +301D ; [*02AC.0020.0002.301D] # REVERSED DOUBLE PRIME QUOTATION MARK +301E ; [*02AD.0020.0002.301E] # DOUBLE PRIME QUOTATION MARK +301F ; [*02AE.0020.0002.301F] # LOW DOUBLE PRIME QUOTATION MARK +3020 ; [*0F0A.0020.0002.3020] # POSTAL MARK FACE +3030 ; [*022F.0020.0002.3030] # WAVY DASH +3036 ; [*0F08.0020.0004.3036] # CIRCLED POSTAL MARK; QQK +3037 ; [*0F0B.0020.0002.3037] # IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL +303D ; [*0316.0020.0002.303D] # PART ALTERNATION MARK +303E ; [*0F0C.0020.0002.303E] # IDEOGRAPHIC VARIATION INDICATOR +303F ; [*0F0D.0020.0002.303F] # IDEOGRAPHIC HALF FILL SPACE +309B ; [*021F.0020.0002.309B] # KATAKANA-HIRAGANA VOICED SOUND MARK +309C ; [*0220.0020.0002.309C] # KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +30A0 ; [*0230.0020.0002.30A0] # KATAKANA-HIRAGANA DOUBLE HYPHEN +30FB ; [*0231.0020.0002.30FB] # KATAKANA MIDDLE DOT +3190 ; [*0F0E.0020.0002.3190] # IDEOGRAPHIC ANNOTATION LINKING MARK +3191 ; [*0F0F.0020.0002.3191] # IDEOGRAPHIC ANNOTATION REVERSE MARK +31C0 ; [*0EF7.0020.0002.31C0] # CJK STROKE T +31C1 ; [*0EF8.0020.0002.31C1] # CJK STROKE WG +31C2 ; [*0EF9.0020.0002.31C2] # CJK STROKE XG +31C3 ; [*0EFA.0020.0002.31C3] # CJK STROKE BXG +31C4 ; [*0EFB.0020.0002.31C4] # CJK STROKE SW +31C5 ; [*0EFC.0020.0002.31C5] # CJK STROKE HZZ +31C6 ; [*0EFD.0020.0002.31C6] # CJK STROKE HZG +31C7 ; [*0EFE.0020.0002.31C7] # CJK STROKE HP +31C8 ; [*0EFF.0020.0002.31C8] # CJK STROKE HZWG +31C9 ; [*0F00.0020.0002.31C9] # CJK STROKE SZWG +31CA ; [*0F01.0020.0002.31CA] # CJK STROKE HZT +31CB ; [*0F02.0020.0002.31CB] # CJK STROKE HZZP +31CC ; [*0F03.0020.0002.31CC] # CJK STROKE HPWG +31CD ; [*0F04.0020.0002.31CD] # CJK STROKE HZW +31CE ; [*0F05.0020.0002.31CE] # CJK STROKE HZZZ +31CF ; [*0F06.0020.0002.31CF] # CJK STROKE N +327F ; [*0F10.0020.0002.327F] # KOREAN STANDARD SYMBOL +4DC0 ; [*0C1F.0020.0002.4DC0] # HEXAGRAM FOR THE CREATIVE HEAVEN +4DC1 ; [*0C20.0020.0002.4DC1] # HEXAGRAM FOR THE RECEPTIVE EARTH +4DC2 ; [*0C21.0020.0002.4DC2] # HEXAGRAM FOR DIFFICULTY AT THE BEGINNING +4DC3 ; [*0C22.0020.0002.4DC3] # HEXAGRAM FOR YOUTHFUL FOLLY +4DC4 ; [*0C23.0020.0002.4DC4] # HEXAGRAM FOR WAITING +4DC5 ; [*0C24.0020.0002.4DC5] # HEXAGRAM FOR CONFLICT +4DC6 ; [*0C25.0020.0002.4DC6] # HEXAGRAM FOR THE ARMY +4DC7 ; [*0C26.0020.0002.4DC7] # HEXAGRAM FOR HOLDING TOGETHER +4DC8 ; [*0C27.0020.0002.4DC8] # HEXAGRAM FOR SMALL TAMING +4DC9 ; [*0C28.0020.0002.4DC9] # HEXAGRAM FOR TREADING +4DCA ; [*0C29.0020.0002.4DCA] # HEXAGRAM FOR PEACE +4DCB ; [*0C2A.0020.0002.4DCB] # HEXAGRAM FOR STANDSTILL +4DCC ; [*0C2B.0020.0002.4DCC] # HEXAGRAM FOR FELLOWSHIP +4DCD ; [*0C2C.0020.0002.4DCD] # HEXAGRAM FOR GREAT POSSESSION +4DCE ; [*0C2D.0020.0002.4DCE] # HEXAGRAM FOR MODESTY +4DCF ; [*0C2E.0020.0002.4DCF] # HEXAGRAM FOR ENTHUSIASM +4DD0 ; [*0C2F.0020.0002.4DD0] # HEXAGRAM FOR FOLLOWING +4DD1 ; [*0C30.0020.0002.4DD1] # HEXAGRAM FOR WORK ON THE DECAYED +4DD2 ; [*0C31.0020.0002.4DD2] # HEXAGRAM FOR APPROACH +4DD3 ; [*0C32.0020.0002.4DD3] # HEXAGRAM FOR CONTEMPLATION +4DD4 ; [*0C33.0020.0002.4DD4] # HEXAGRAM FOR BITING THROUGH +4DD5 ; [*0C34.0020.0002.4DD5] # HEXAGRAM FOR GRACE +4DD6 ; [*0C35.0020.0002.4DD6] # HEXAGRAM FOR SPLITTING APART +4DD7 ; [*0C36.0020.0002.4DD7] # HEXAGRAM FOR RETURN +4DD8 ; [*0C37.0020.0002.4DD8] # HEXAGRAM FOR INNOCENCE +4DD9 ; [*0C38.0020.0002.4DD9] # HEXAGRAM FOR GREAT TAMING +4DDA ; [*0C39.0020.0002.4DDA] # HEXAGRAM FOR MOUTH CORNERS +4DDB ; [*0C3A.0020.0002.4DDB] # HEXAGRAM FOR GREAT PREPONDERANCE +4DDC ; [*0C3B.0020.0002.4DDC] # HEXAGRAM FOR THE ABYSMAL WATER +4DDD ; [*0C3C.0020.0002.4DDD] # HEXAGRAM FOR THE CLINGING FIRE +4DDE ; [*0C3D.0020.0002.4DDE] # HEXAGRAM FOR INFLUENCE +4DDF ; [*0C3E.0020.0002.4DDF] # HEXAGRAM FOR DURATION +4DE0 ; [*0C3F.0020.0002.4DE0] # HEXAGRAM FOR RETREAT +4DE1 ; [*0C40.0020.0002.4DE1] # HEXAGRAM FOR GREAT POWER +4DE2 ; [*0C41.0020.0002.4DE2] # HEXAGRAM FOR PROGRESS +4DE3 ; [*0C42.0020.0002.4DE3] # HEXAGRAM FOR DARKENING OF THE LIGHT +4DE4 ; [*0C43.0020.0002.4DE4] # HEXAGRAM FOR THE FAMILY +4DE5 ; [*0C44.0020.0002.4DE5] # HEXAGRAM FOR OPPOSITION +4DE6 ; [*0C45.0020.0002.4DE6] # HEXAGRAM FOR OBSTRUCTION +4DE7 ; [*0C46.0020.0002.4DE7] # HEXAGRAM FOR DELIVERANCE +4DE8 ; [*0C47.0020.0002.4DE8] # HEXAGRAM FOR DECREASE +4DE9 ; [*0C48.0020.0002.4DE9] # HEXAGRAM FOR INCREASE +4DEA ; [*0C49.0020.0002.4DEA] # HEXAGRAM FOR BREAKTHROUGH +4DEB ; [*0C4A.0020.0002.4DEB] # HEXAGRAM FOR COMING TO MEET +4DEC ; [*0C4B.0020.0002.4DEC] # HEXAGRAM FOR GATHERING TOGETHER +4DED ; [*0C4C.0020.0002.4DED] # HEXAGRAM FOR PUSHING UPWARD +4DEE ; [*0C4D.0020.0002.4DEE] # HEXAGRAM FOR OPPRESSION +4DEF ; [*0C4E.0020.0002.4DEF] # HEXAGRAM FOR THE WELL +4DF0 ; [*0C4F.0020.0002.4DF0] # HEXAGRAM FOR REVOLUTION +4DF1 ; [*0C50.0020.0002.4DF1] # HEXAGRAM FOR THE CAULDRON +4DF2 ; [*0C51.0020.0002.4DF2] # HEXAGRAM FOR THE AROUSING THUNDER +4DF3 ; [*0C52.0020.0002.4DF3] # HEXAGRAM FOR THE KEEPING STILL MOUNTAIN +4DF4 ; [*0C53.0020.0002.4DF4] # HEXAGRAM FOR DEVELOPMENT +4DF5 ; [*0C54.0020.0002.4DF5] # HEXAGRAM FOR THE MARRYING MAIDEN +4DF6 ; [*0C55.0020.0002.4DF6] # HEXAGRAM FOR ABUNDANCE +4DF7 ; [*0C56.0020.0002.4DF7] # HEXAGRAM FOR THE WANDERER +4DF8 ; [*0C57.0020.0002.4DF8] # HEXAGRAM FOR THE GENTLE WIND +4DF9 ; [*0C58.0020.0002.4DF9] # HEXAGRAM FOR THE JOYOUS LAKE +4DFA ; [*0C59.0020.0002.4DFA] # HEXAGRAM FOR DISPERSION +4DFB ; [*0C5A.0020.0002.4DFB] # HEXAGRAM FOR LIMITATION +4DFC ; [*0C5B.0020.0002.4DFC] # HEXAGRAM FOR INNER TRUTH +4DFD ; [*0C5C.0020.0002.4DFD] # HEXAGRAM FOR SMALL PREPONDERANCE +4DFE ; [*0C5D.0020.0002.4DFE] # HEXAGRAM FOR AFTER COMPLETION +4DFF ; [*0C5E.0020.0002.4DFF] # HEXAGRAM FOR BEFORE COMPLETION +A490 ; [*0CB6.0020.0002.A490] # YI RADICAL QOT +A491 ; [*0CB7.0020.0002.A491] # YI RADICAL LI +A492 ; [*0CB8.0020.0002.A492] # YI RADICAL KIT +A493 ; [*0CB9.0020.0002.A493] # YI RADICAL NYIP +A494 ; [*0CBA.0020.0002.A494] # YI RADICAL CYP +A495 ; [*0CBB.0020.0002.A495] # YI RADICAL SSI +A496 ; [*0CBC.0020.0002.A496] # YI RADICAL GGOP +A497 ; [*0CBD.0020.0002.A497] # YI RADICAL GEP +A498 ; [*0CBE.0020.0002.A498] # YI RADICAL MI +A499 ; [*0CBF.0020.0002.A499] # YI RADICAL HXIT +A49A ; [*0CC0.0020.0002.A49A] # YI RADICAL LYR +A49B ; [*0CC1.0020.0002.A49B] # YI RADICAL BBUT +A49C ; [*0CC2.0020.0002.A49C] # YI RADICAL MOP +A49D ; [*0CC3.0020.0002.A49D] # YI RADICAL YO +A49E ; [*0CC4.0020.0002.A49E] # YI RADICAL PUT +A49F ; [*0CC5.0020.0002.A49F] # YI RADICAL HXUO +A4A0 ; [*0CC6.0020.0002.A4A0] # YI RADICAL TAT +A4A1 ; [*0CC7.0020.0002.A4A1] # YI RADICAL GA +A4A2 ; [*0CC8.0020.0002.A4A2] # YI RADICAL ZUP +A4A3 ; [*0CC9.0020.0002.A4A3] # YI RADICAL CYT +A4A4 ; [*0CCA.0020.0002.A4A4] # YI RADICAL DDUR +A4A5 ; [*0CCB.0020.0002.A4A5] # YI RADICAL BUR +A4A6 ; [*0CCC.0020.0002.A4A6] # YI RADICAL GGUO +A4A7 ; [*0CCD.0020.0002.A4A7] # YI RADICAL NYOP +A4A8 ; [*0CCE.0020.0002.A4A8] # YI RADICAL TU +A4A9 ; [*0CCF.0020.0002.A4A9] # YI RADICAL OP +A4AA ; [*0CD0.0020.0002.A4AA] # YI RADICAL JJUT +A4AB ; [*0CD1.0020.0002.A4AB] # YI RADICAL ZOT +A4AC ; [*0CD2.0020.0002.A4AC] # YI RADICAL PYT +A4AD ; [*0CD3.0020.0002.A4AD] # YI RADICAL HMO +A4AE ; [*0CD4.0020.0002.A4AE] # YI RADICAL YIT +A4AF ; [*0CD5.0020.0002.A4AF] # YI RADICAL VUR +A4B0 ; [*0CD6.0020.0002.A4B0] # YI RADICAL SHY +A4B1 ; [*0CD7.0020.0002.A4B1] # YI RADICAL VEP +A4B2 ; [*0CD8.0020.0002.A4B2] # YI RADICAL ZA +A4B3 ; [*0CD9.0020.0002.A4B3] # YI RADICAL JO +A4B4 ; [*0CDA.0020.0002.A4B4] # YI RADICAL NZUP +A4B5 ; [*0CDB.0020.0002.A4B5] # YI RADICAL JJY +A4B6 ; [*0CDC.0020.0002.A4B6] # YI RADICAL GOT +A4B7 ; [*0CDD.0020.0002.A4B7] # YI RADICAL JJIE +A4B8 ; [*0CDE.0020.0002.A4B8] # YI RADICAL WO +A4B9 ; [*0CDF.0020.0002.A4B9] # YI RADICAL DU +A4BA ; [*0CE0.0020.0002.A4BA] # YI RADICAL SHUR +A4BB ; [*0CE1.0020.0002.A4BB] # YI RADICAL LIE +A4BC ; [*0CE2.0020.0002.A4BC] # YI RADICAL CY +A4BD ; [*0CE3.0020.0002.A4BD] # YI RADICAL CUOP +A4BE ; [*0CE4.0020.0002.A4BE] # YI RADICAL CIP +A4BF ; [*0CE5.0020.0002.A4BF] # YI RADICAL HXOP +A4C0 ; [*0CE6.0020.0002.A4C0] # YI RADICAL SHAT +A4C1 ; [*0CE7.0020.0002.A4C1] # YI RADICAL ZUR +A4C2 ; [*0CE8.0020.0002.A4C2] # YI RADICAL SHOP +A4C3 ; [*0CE9.0020.0002.A4C3] # YI RADICAL CHE +A4C4 ; [*0CEA.0020.0002.A4C4] # YI RADICAL ZZIET +A4C5 ; [*0CEB.0020.0002.A4C5] # YI RADICAL NBIE +A4C6 ; [*0CEC.0020.0002.A4C6] # YI RADICAL KE +A700 ; [*03A2.0020.0002.A700] # MODIFIER LETTER CHINESE TONE YIN PING +A701 ; [*03A3.0020.0002.A701] # MODIFIER LETTER CHINESE TONE YANG PING +A702 ; [*03A4.0020.0002.A702] # MODIFIER LETTER CHINESE TONE YIN SHANG +A703 ; [*03A5.0020.0002.A703] # MODIFIER LETTER CHINESE TONE YANG SHANG +A704 ; [*03A6.0020.0002.A704] # MODIFIER LETTER CHINESE TONE YIN QU +A705 ; [*03A7.0020.0002.A705] # MODIFIER LETTER CHINESE TONE YANG QU +A706 ; [*03A8.0020.0002.A706] # MODIFIER LETTER CHINESE TONE YIN RU +A707 ; [*03A9.0020.0002.A707] # MODIFIER LETTER CHINESE TONE YANG RU +A708 ; [*03AA.0020.0002.A708] # MODIFIER LETTER EXTRA-HIGH DOTTED TONE BAR +A709 ; [*03AB.0020.0002.A709] # MODIFIER LETTER HIGH DOTTED TONE BAR +A70A ; [*03AC.0020.0002.A70A] # MODIFIER LETTER MID DOTTED TONE BAR +A70B ; [*03AD.0020.0002.A70B] # MODIFIER LETTER LOW DOTTED TONE BAR +A70C ; [*03AE.0020.0002.A70C] # MODIFIER LETTER EXTRA-LOW DOTTED TONE BAR +A70D ; [*03AF.0020.0002.A70D] # MODIFIER LETTER EXTRA-HIGH DOTTED LEFT-STEM TONE BAR +A70E ; [*03B0.0020.0002.A70E] # MODIFIER LETTER HIGH DOTTED LEFT-STEM TONE BAR +A70F ; [*03B1.0020.0002.A70F] # MODIFIER LETTER MID DOTTED LEFT-STEM TONE BAR +A710 ; [*03B2.0020.0002.A710] # MODIFIER LETTER LOW DOTTED LEFT-STEM TONE BAR +A711 ; [*03B3.0020.0002.A711] # MODIFIER LETTER EXTRA-LOW DOTTED LEFT-STEM TONE BAR +A712 ; [*03B4.0020.0002.A712] # MODIFIER LETTER EXTRA-HIGH LEFT-STEM TONE BAR +A713 ; [*03B5.0020.0002.A713] # MODIFIER LETTER HIGH LEFT-STEM TONE BAR +A714 ; [*03B6.0020.0002.A714] # MODIFIER LETTER MID LEFT-STEM TONE BAR +A715 ; [*03B7.0020.0002.A715] # MODIFIER LETTER LOW LEFT-STEM TONE BAR +A716 ; [*03B8.0020.0002.A716] # MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR +A717 ; [*03B9.0020.0002.A717] # MODIFIER LETTER DOT VERTICAL BAR +A718 ; [*03BA.0020.0002.A718] # MODIFIER LETTER DOT SLASH +A719 ; [*03BB.0020.0002.A719] # MODIFIER LETTER DOT HORIZONTAL BAR +A71A ; [*03BC.0020.0002.A71A] # MODIFIER LETTER LOWER RIGHT CORNER ANGLE +A720 ; [*03BD.0020.0002.A720] # MODIFIER LETTER STRESS AND HIGH TONE +A721 ; [*03BE.0020.0002.A721] # MODIFIER LETTER STRESS AND LOW TONE +A828 ; [*03D1.0020.0002.A828] # SYLOTI NAGRI POETRY MARK-1 +A829 ; [*03D2.0020.0002.A829] # SYLOTI NAGRI POETRY MARK-2 +A82A ; [*03D3.0020.0002.A82A] # SYLOTI NAGRI POETRY MARK-3 +A82B ; [*03D4.0020.0002.A82B] # SYLOTI NAGRI POETRY MARK-4 +A874 ; [*035C.0020.0002.A874] # PHAGS-PA SINGLE HEAD MARK +A875 ; [*035D.0020.0002.A875] # PHAGS-PA DOUBLE HEAD MARK +A876 ; [*0276.0020.0002.A876] # PHAGS-PA MARK SHAD +A877 ; [*0277.0020.0002.A877] # PHAGS-PA MARK DOUBLE SHAD +FB29 ; [*04B8.0020.0005.FB29] # HEBREW LETTER ALTERNATIVE PLUS SIGN; QQK +FD3E ; [*02F3.0020.0002.FD3E] # ORNATE LEFT PARENTHESIS +FD3F ; [*02F4.0020.0002.FD3F] # ORNATE RIGHT PARENTHESIS +FDFD ; [*03C4.0020.0002.FDFD] # ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM +FE10 ; [*0232.0020.0016.FE10] # PRESENTATION FORM FOR VERTICAL COMMA; QQK +FE11 ; [*023B.0020.0016.FE11] # PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC COMMA; QQK +FE12 ; [*0272.0020.0016.FE12] # PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP; QQK +FE13 ; [*0241.0020.0016.FE13] # PRESENTATION FORM FOR VERTICAL COLON; QQK +FE14 ; [*023E.0020.0016.FE14] # PRESENTATION FORM FOR VERTICAL SEMICOLON; QQK +FE15 ; [*0257.0020.0016.FE15] # PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK; QQK +FE16 ; [*025C.0020.0016.FE16] # PRESENTATION FORM FOR VERTICAL QUESTION MARK; QQK +FE17 ; [*02ED.0020.0016.FE17] # PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET; QQK +FE18 ; [*02EE.0020.0016.FE18] # PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET; QQK +FE19 ; [*0266.0020.0016.FE19][*0266.0020.0016.FE19][*0266.0020.001F.FE19] # PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS; QQKN +FE21 ; [.0000.0000.0000.FE21] # COMBINING LIGATURE RIGHT HALF +FE23 ; [.0000.0000.0000.FE23] # COMBINING DOUBLE TILDE RIGHT HALF +FE30 ; [*0266.0020.0016.FE30][*0266.0020.0016.FE30] # PRESENTATION FORM FOR VERTICAL TWO DOT LEADER; QQKN +FE31 ; [*022A.0020.0016.FE31] # PRESENTATION FORM FOR VERTICAL EM DASH; QQK +FE32 ; [*0229.0020.0016.FE32] # PRESENTATION FORM FOR VERTICAL EN DASH; QQK +FE33 ; [*021C.0020.0016.FE33] # PRESENTATION FORM FOR VERTICAL LOW LINE; QQK +FE34 ; [*021C.0020.0016.FE34] # PRESENTATION FORM FOR VERTICAL WAVY LOW LINE; QQK +FE35 ; [*02B1.0020.0016.FE35] # PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS; QQK +FE36 ; [*02B2.0020.0016.FE36] # PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS; QQK +FE37 ; [*02B5.0020.0016.FE37] # PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET; QQK +FE38 ; [*02B6.0020.0016.FE38] # PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET; QQK +FE39 ; [*02EB.0020.0016.FE39] # PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET; QQK +FE3A ; [*02EC.0020.0016.FE3A] # PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET; QQK +FE3B ; [*02E9.0020.0016.FE3B] # PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET; QQK +FE3C ; [*02EA.0020.0016.FE3C] # PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET; QQK +FE3D ; [*02E3.0020.0016.FE3D] # PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET; QQK +FE3E ; [*02E4.0020.0016.FE3E] # PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET; QQK +FE3F ; [*02E1.0020.0016.FE3F] # PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET; QQK +FE40 ; [*02E2.0020.0016.FE40] # PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET; QQK +FE41 ; [*02E5.0020.0016.FE41] # PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET; QQK +FE42 ; [*02E6.0020.0016.FE42] # PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET; QQK +FE43 ; [*02E7.0020.0016.FE43] # PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET; QQK +FE44 ; [*02E8.0020.0016.FE44] # PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET; QQK +FE45 ; [*023C.0020.0002.FE45] # SESAME DOT +FE46 ; [*023D.0020.0002.FE46] # WHITE SESAME DOT +FE47 ; [*02B3.0020.0016.FE47] # PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET; QQK +FE48 ; [*02B4.0020.0016.FE48] # PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET; QQK +FE49 ; [*0212.0020.0004.FE49] # DASHED OVERLINE; QQK +FE4A ; [*0212.0020.0004.FE4A] # CENTRELINE OVERLINE; QQK +FE4B ; [*0212.0020.0004.FE4B] # WAVY OVERLINE; QQK +FE4C ; [*0212.0020.0004.FE4C] # DOUBLE WAVY OVERLINE; QQK +FE4D ; [*021C.0020.0004.FE4D] # DASHED LOW LINE; QQK +FE4E ; [*021C.0020.0004.FE4E] # CENTRELINE LOW LINE; QQK +FE4F ; [*021C.0020.0004.FE4F] # WAVY LOW LINE; QQK +FE50 ; [*0232.0020.000F.FE50] # SMALL COMMA; QQK +FE51 ; [*023B.0020.000F.FE51] # SMALL IDEOGRAPHIC COMMA; QQK +FE52 ; [*0266.0020.000F.FE52] # SMALL FULL STOP; QQK +FE54 ; [*023E.0020.000F.FE54] # SMALL SEMICOLON; QQK +FE55 ; [*0241.0020.000F.FE55] # SMALL COLON; QQK +FE56 ; [*025C.0020.000F.FE56] # SMALL QUESTION MARK; QQK +FE57 ; [*0257.0020.000F.FE57] # SMALL EXCLAMATION MARK; QQK +FE58 ; [*022A.0020.000F.FE58] # SMALL EM DASH; QQK +FE59 ; [*02B1.0020.000F.FE59] # SMALL LEFT PARENTHESIS; QQK +FE5A ; [*02B2.0020.000F.FE5A] # SMALL RIGHT PARENTHESIS; QQK +FE5B ; [*02B5.0020.000F.FE5B] # SMALL LEFT CURLY BRACKET; QQK +FE5C ; [*02B6.0020.000F.FE5C] # SMALL RIGHT CURLY BRACKET; QQK +FE5D ; [*02EB.0020.000F.FE5D] # SMALL LEFT TORTOISE SHELL BRACKET; QQK +FE5E ; [*02EC.0020.000F.FE5E] # SMALL RIGHT TORTOISE SHELL BRACKET; QQK +FE5F ; [*0305.0020.000F.FE5F] # SMALL NUMBER SIGN; QQK +FE60 ; [*0302.0020.000F.FE60] # SMALL AMPERSAND; QQK +FE61 ; [*02FB.0020.000F.FE61] # SMALL ASTERISK; QQK +FE62 ; [*04B8.0020.000F.FE62] # SMALL PLUS SIGN; QQK +FE63 ; [*0222.0020.000F.FE63] # SMALL HYPHEN-MINUS; QQK +FE64 ; [*04BC.0020.000F.FE64] # SMALL LESS-THAN SIGN; QQK +FE65 ; [*04BE.0020.000F.FE65] # SMALL GREATER-THAN SIGN; QQK +FE66 ; [*04BD.0020.000F.FE66] # SMALL EQUALS SIGN; QQK +FE68 ; [*0301.0020.000F.FE68] # SMALL REVERSE SOLIDUS; QQK +FE6A ; [*0306.0020.000F.FE6A] # SMALL PERCENT SIGN; QQK +FE6B ; [*02FA.0020.000F.FE6B] # SMALL COMMERCIAL AT; QQK +FE73 ; [.0000.0000.0000.FE73] # ARABIC TAIL FRAGMENT +FF01 ; [*0257.0020.0003.FF01] # FULLWIDTH EXCLAMATION MARK; QQK +FF02 ; [*02A7.0020.0003.FF02] # FULLWIDTH QUOTATION MARK; QQK +FF03 ; [*0305.0020.0003.FF03] # FULLWIDTH NUMBER SIGN; QQK +FF05 ; [*0306.0020.0003.FF05] # FULLWIDTH PERCENT SIGN; QQK +FF06 ; [*0302.0020.0003.FF06] # FULLWIDTH AMPERSAND; QQK +FF07 ; [*02A0.0020.0003.FF07] # FULLWIDTH APOSTROPHE; QQK +FF08 ; [*02B1.0020.0003.FF08] # FULLWIDTH LEFT PARENTHESIS; QQK +FF09 ; [*02B2.0020.0003.FF09] # FULLWIDTH RIGHT PARENTHESIS; QQK +FF0A ; [*02FB.0020.0003.FF0A] # FULLWIDTH ASTERISK; QQK +FF0B ; [*04B8.0020.0003.FF0B] # FULLWIDTH PLUS SIGN; QQK +FF0C ; [*0232.0020.0003.FF0C] # FULLWIDTH COMMA; QQK +FF0D ; [*0222.0020.0003.FF0D] # FULLWIDTH HYPHEN-MINUS; QQK +FF0E ; [*0266.0020.0003.FF0E] # FULLWIDTH FULL STOP; QQK +FF0F ; [*02FF.0020.0003.FF0F] # FULLWIDTH SOLIDUS; QQK +FF1A ; [*0241.0020.0003.FF1A] # FULLWIDTH COLON; QQK +FF1B ; [*023E.0020.0003.FF1B] # FULLWIDTH SEMICOLON; QQK +FF1C ; [*04BC.0020.0003.FF1C] # FULLWIDTH LESS-THAN SIGN; QQK +FF1D ; [*04BD.0020.0003.FF1D] # FULLWIDTH EQUALS SIGN; QQK +FF1E ; [*04BE.0020.0003.FF1E] # FULLWIDTH GREATER-THAN SIGN; QQK +FF1F ; [*025C.0020.0003.FF1F] # FULLWIDTH QUESTION MARK; QQK +FF20 ; [*02FA.0020.0003.FF20] # FULLWIDTH COMMERCIAL AT; QQK +FF3B ; [*02B3.0020.0003.FF3B] # FULLWIDTH LEFT SQUARE BRACKET; QQK +FF3C ; [*0301.0020.0003.FF3C] # FULLWIDTH REVERSE SOLIDUS; QQK +FF3D ; [*02B4.0020.0003.FF3D] # FULLWIDTH RIGHT SQUARE BRACKET; QQK +FF3E ; [*0210.0020.0003.FF3E] # FULLWIDTH CIRCUMFLEX ACCENT; QQK +FF3F ; [*021C.0020.0003.FF3F] # FULLWIDTH LOW LINE; QQK +FF40 ; [*020D.0020.0003.FF40] # FULLWIDTH GRAVE ACCENT; QQK +FF5B ; [*02B5.0020.0003.FF5B] # FULLWIDTH LEFT CURLY BRACKET; QQK +FF5C ; [*04C0.0020.0003.FF5C] # FULLWIDTH VERTICAL LINE; QQK +FF5D ; [*02B6.0020.0003.FF5D] # FULLWIDTH RIGHT CURLY BRACKET; QQK +FF5E ; [*04C3.0020.0003.FF5E] # FULLWIDTH TILDE; QQK +FF5F ; [*02C3.0020.0003.FF5F] # FULLWIDTH LEFT WHITE PARENTHESIS; QQK +FF60 ; [*02C4.0020.0003.FF60] # FULLWIDTH RIGHT WHITE PARENTHESIS; QQK +FF61 ; [*0272.0020.0012.FF61] # HALFWIDTH IDEOGRAPHIC FULL STOP; QQK +FF62 ; [*02E5.0020.0012.FF62] # HALFWIDTH LEFT CORNER BRACKET; QQK +FF63 ; [*02E6.0020.0012.FF63] # HALFWIDTH RIGHT CORNER BRACKET; QQK +FF64 ; [*023B.0020.0012.FF64] # HALFWIDTH IDEOGRAPHIC COMMA; QQK +FF65 ; [*0231.0020.0012.FF65] # HALFWIDTH KATAKANA MIDDLE DOT; QQK +FFE2 ; [*04BF.0020.0003.FFE2] # FULLWIDTH NOT SIGN; QQK +FFE3 ; [*0211.0020.0003.FFE3] # FULLWIDTH MACRON; QQK +FFE4 ; [*04C1.0020.0003.FFE4] # FULLWIDTH BROKEN BAR; QQK +FFE8 ; [*06A5.0020.0012.FFE8] # HALFWIDTH FORMS LIGHT VERTICAL; QQK +FFE9 ; [*043E.0020.0012.FFE9] # HALFWIDTH LEFTWARDS ARROW; QQK +FFEA ; [*0440.0020.0012.FFEA] # HALFWIDTH UPWARDS ARROW; QQK +FFEB ; [*043F.0020.0012.FFEB] # HALFWIDTH RIGHTWARDS ARROW; QQK +FFEC ; [*0441.0020.0012.FFEC] # HALFWIDTH DOWNWARDS ARROW; QQK +FFED ; [*0743.0020.0012.FFED] # HALFWIDTH BLACK SQUARE; QQK +FFEE ; [*076E.0020.0012.FFEE] # HALFWIDTH WHITE CIRCLE; QQK +FFFC ; [*0F11.0020.0002.FFFC] # OBJECT REPLACEMENT CHARACTER +FFFD ; [*0F12.0020.0002.FFFD] # REPLACEMENT CHARACTER +10100 ; [*0296.0020.0002.10100] # AEGEAN WORD SEPARATOR LINE +10101 ; [*0297.0020.0002.10101] # AEGEAN WORD SEPARATOR DOT +10102 ; [*0298.0020.0002.10102] # AEGEAN CHECK MARK +10110 ; [*0F29.0020.0002.10110] # AEGEAN NUMBER TEN +10111 ; [*0F2A.0020.0002.10111] # AEGEAN NUMBER TWENTY +10112 ; [*0F2B.0020.0002.10112] # AEGEAN NUMBER THIRTY +10113 ; [*0F2C.0020.0002.10113] # AEGEAN NUMBER FORTY +10114 ; [*0F2D.0020.0002.10114] # AEGEAN NUMBER FIFTY +10115 ; [*0F2E.0020.0002.10115] # AEGEAN NUMBER SIXTY +10116 ; [*0F2F.0020.0002.10116] # AEGEAN NUMBER SEVENTY +10117 ; [*0F30.0020.0002.10117] # AEGEAN NUMBER EIGHTY +10118 ; [*0F31.0020.0002.10118] # AEGEAN NUMBER NINETY +10119 ; [*0F32.0020.0002.10119] # AEGEAN NUMBER ONE HUNDRED +1011A ; [*0F33.0020.0002.1011A] # AEGEAN NUMBER TWO HUNDRED +1011B ; [*0F34.0020.0002.1011B] # AEGEAN NUMBER THREE HUNDRED +1011C ; [*0F35.0020.0002.1011C] # AEGEAN NUMBER FOUR HUNDRED +1011D ; [*0F36.0020.0002.1011D] # AEGEAN NUMBER FIVE HUNDRED +1011E ; [*0F37.0020.0002.1011E] # AEGEAN NUMBER SIX HUNDRED +1011F ; [*0F38.0020.0002.1011F] # AEGEAN NUMBER SEVEN HUNDRED +10120 ; [*0F39.0020.0002.10120] # AEGEAN NUMBER EIGHT HUNDRED +10121 ; [*0F3A.0020.0002.10121] # AEGEAN NUMBER NINE HUNDRED +10122 ; [*0F3B.0020.0002.10122] # AEGEAN NUMBER ONE THOUSAND +10123 ; [*0F3C.0020.0002.10123] # AEGEAN NUMBER TWO THOUSAND +10124 ; [*0F3D.0020.0002.10124] # AEGEAN NUMBER THREE THOUSAND +10125 ; [*0F3E.0020.0002.10125] # AEGEAN NUMBER FOUR THOUSAND +10126 ; [*0F3F.0020.0002.10126] # AEGEAN NUMBER FIVE THOUSAND +10127 ; [*0F40.0020.0002.10127] # AEGEAN NUMBER SIX THOUSAND +10128 ; [*0F41.0020.0002.10128] # AEGEAN NUMBER SEVEN THOUSAND +10129 ; [*0F42.0020.0002.10129] # AEGEAN NUMBER EIGHT THOUSAND +1012A ; [*0F43.0020.0002.1012A] # AEGEAN NUMBER NINE THOUSAND +1012B ; [*0F44.0020.0002.1012B] # AEGEAN NUMBER TEN THOUSAND +1012C ; [*0F45.0020.0002.1012C] # AEGEAN NUMBER TWENTY THOUSAND +1012D ; [*0F46.0020.0002.1012D] # AEGEAN NUMBER THIRTY THOUSAND +1012E ; [*0F47.0020.0002.1012E] # AEGEAN NUMBER FORTY THOUSAND +1012F ; [*0F48.0020.0002.1012F] # AEGEAN NUMBER FIFTY THOUSAND +10130 ; [*0F49.0020.0002.10130] # AEGEAN NUMBER SIXTY THOUSAND +10131 ; [*0F4A.0020.0002.10131] # AEGEAN NUMBER SEVENTY THOUSAND +10132 ; [*0F4B.0020.0002.10132] # AEGEAN NUMBER EIGHTY THOUSAND +10133 ; [*0F4C.0020.0002.10133] # AEGEAN NUMBER NINETY THOUSAND +10137 ; [*0CED.0020.0002.10137] # AEGEAN WEIGHT BASE UNIT +10138 ; [*0CEE.0020.0002.10138] # AEGEAN WEIGHT FIRST SUBUNIT +10139 ; [*0CEF.0020.0002.10139] # AEGEAN WEIGHT SECOND SUBUNIT +1013A ; [*0CF0.0020.0002.1013A] # AEGEAN WEIGHT THIRD SUBUNIT +1013B ; [*0CF1.0020.0002.1013B] # AEGEAN WEIGHT FOURTH SUBUNIT +1013C ; [*0CF2.0020.0002.1013C] # AEGEAN DRY MEASURE FIRST SUBUNIT +1013D ; [*0CF3.0020.0002.1013D] # AEGEAN LIQUID MEASURE FIRST SUBUNIT +1013E ; [*0CF4.0020.0002.1013E] # AEGEAN MEASURE SECOND SUBUNIT +1013F ; [*0CF5.0020.0002.1013F] # AEGEAN MEASURE THIRD SUBUNIT +10140 ; [*0F4D.0020.0002.10140] # GREEK ACROPHONIC ATTIC ONE QUARTER +10141 ; [*0F4E.0020.0002.10141] # GREEK ACROPHONIC ATTIC ONE HALF +10144 ; [*0F4F.0020.0002.10144] # GREEK ACROPHONIC ATTIC FIFTY +10145 ; [*0F50.0020.0002.10145] # GREEK ACROPHONIC ATTIC FIVE HUNDRED +10146 ; [*0F51.0020.0002.10146] # GREEK ACROPHONIC ATTIC FIVE THOUSAND +10147 ; [*0F52.0020.0002.10147] # GREEK ACROPHONIC ATTIC FIFTY THOUSAND +10149 ; [*0F53.0020.0002.10149] # GREEK ACROPHONIC ATTIC TEN TALENTS +1014A ; [*0F54.0020.0002.1014A] # GREEK ACROPHONIC ATTIC FIFTY TALENTS +1014B ; [*0F55.0020.0002.1014B] # GREEK ACROPHONIC ATTIC ONE HUNDRED TALENTS +1014C ; [*0F56.0020.0002.1014C] # GREEK ACROPHONIC ATTIC FIVE HUNDRED TALENTS +1014D ; [*0F57.0020.0002.1014D] # GREEK ACROPHONIC ATTIC ONE THOUSAND TALENTS +1014E ; [*0F58.0020.0002.1014E] # GREEK ACROPHONIC ATTIC FIVE THOUSAND TALENTS +10150 ; [*0F59.0020.0002.10150] # GREEK ACROPHONIC ATTIC TEN STATERS +10151 ; [*0F5A.0020.0002.10151] # GREEK ACROPHONIC ATTIC FIFTY STATERS +10152 ; [*0F5B.0020.0002.10152] # GREEK ACROPHONIC ATTIC ONE HUNDRED STATERS +10153 ; [*0F5C.0020.0002.10153] # GREEK ACROPHONIC ATTIC FIVE HUNDRED STATERS +10154 ; [*0F5D.0020.0002.10154] # GREEK ACROPHONIC ATTIC ONE THOUSAND STATERS +10155 ; [*0F5E.0020.0002.10155] # GREEK ACROPHONIC ATTIC TEN THOUSAND STATERS +10156 ; [*0F5F.0020.0002.10156] # GREEK ACROPHONIC ATTIC FIFTY THOUSAND STATERS +10157 ; [*0F60.0020.0002.10157] # GREEK ACROPHONIC ATTIC TEN MNAS +10160 ; [*0F61.0020.0002.10160] # GREEK ACROPHONIC TROEZENIAN TEN +10161 ; [*0F62.0020.0002.10161] # GREEK ACROPHONIC TROEZENIAN TEN ALTERNATE FORM +10162 ; [*0F63.0020.0002.10162] # GREEK ACROPHONIC HERMIONIAN TEN +10163 ; [*0F64.0020.0002.10163] # GREEK ACROPHONIC MESSENIAN TEN +10164 ; [*0F65.0020.0002.10164] # GREEK ACROPHONIC THESPIAN TEN +10165 ; [*0F66.0020.0002.10165] # GREEK ACROPHONIC THESPIAN THIRTY +10166 ; [*0F67.0020.0002.10166] # GREEK ACROPHONIC TROEZENIAN FIFTY +10167 ; [*0F68.0020.0002.10167] # GREEK ACROPHONIC TROEZENIAN FIFTY ALTERNATE FORM +10168 ; [*0F69.0020.0002.10168] # GREEK ACROPHONIC HERMIONIAN FIFTY +10169 ; [*0F6A.0020.0002.10169] # GREEK ACROPHONIC THESPIAN FIFTY +1016A ; [*0F6B.0020.0002.1016A] # GREEK ACROPHONIC THESPIAN ONE HUNDRED +1016B ; [*0F6C.0020.0002.1016B] # GREEK ACROPHONIC THESPIAN THREE HUNDRED +1016C ; [*0F6D.0020.0002.1016C] # GREEK ACROPHONIC EPIDAUREAN FIVE HUNDRED +1016D ; [*0F6E.0020.0002.1016D] # GREEK ACROPHONIC TROEZENIAN FIVE HUNDRED +1016E ; [*0F6F.0020.0002.1016E] # GREEK ACROPHONIC THESPIAN FIVE HUNDRED +1016F ; [*0F70.0020.0002.1016F] # GREEK ACROPHONIC CARYSTIAN FIVE HUNDRED +10170 ; [*0F71.0020.0002.10170] # GREEK ACROPHONIC NAXIAN FIVE HUNDRED +10171 ; [*0F72.0020.0002.10171] # GREEK ACROPHONIC THESPIAN ONE THOUSAND +10172 ; [*0F73.0020.0002.10172] # GREEK ACROPHONIC THESPIAN FIVE THOUSAND +10174 ; [*0F74.0020.0002.10174] # GREEK ACROPHONIC STRATIAN FIFTY MNAS +10175 ; [*0F75.0020.0002.10175] # GREEK ONE HALF SIGN +10176 ; [*0F76.0020.0002.10176] # GREEK ONE HALF SIGN ALTERNATE FORM +10177 ; [*0F77.0020.0002.10177] # GREEK TWO THIRDS SIGN +10178 ; [*0F78.0020.0002.10178] # GREEK THREE QUARTERS SIGN +10179 ; [*0CF6.0020.0002.10179] # GREEK YEAR SIGN +1017A ; [*0CF7.0020.0002.1017A] # GREEK TALENT SIGN +1017B ; [*0CF8.0020.0002.1017B] # GREEK DRACHMA SIGN +1017C ; [*0CF9.0020.0002.1017C] # GREEK OBOL SIGN +1017D ; [*0CFA.0020.0002.1017D] # GREEK TWO OBOLS SIGN +1017E ; [*0CFB.0020.0002.1017E] # GREEK THREE OBOLS SIGN +1017F ; [*0CFC.0020.0002.1017F] # GREEK FOUR OBOLS SIGN +10180 ; [*0CFD.0020.0002.10180] # GREEK FIVE OBOLS SIGN +10181 ; [*0CFE.0020.0002.10181] # GREEK METRETES SIGN +10182 ; [*0CFF.0020.0002.10182] # GREEK KYATHOS BASE SIGN +10183 ; [*0D00.0020.0002.10183] # GREEK LITRA SIGN +10184 ; [*0D01.0020.0002.10184] # GREEK OUNKIA SIGN +10185 ; [*0D02.0020.0002.10185] # GREEK XESTES SIGN +10186 ; [*0D03.0020.0002.10186] # GREEK ARTABE SIGN +10187 ; [*0D04.0020.0002.10187] # GREEK AROURA SIGN +10188 ; [*0D05.0020.0002.10188] # GREEK GRAMMA SIGN +10189 ; [*0D06.0020.0002.10189] # GREEK TRYBLION BASE SIGN +10322 ; [*0F27.0020.0002.10322] # OLD ITALIC NUMERAL TEN +10323 ; [*0F28.0020.0002.10323] # OLD ITALIC NUMERAL FIFTY +1039F ; [*0299.0020.0002.1039F] # UGARITIC WORD DIVIDER +103D0 ; [*029A.0020.0002.103D0] # OLD PERSIAN WORD DIVIDER +103D3 ; [*0F79.0020.0002.103D3] # OLD PERSIAN NUMBER TEN +103D4 ; [*0F7A.0020.0002.103D4] # OLD PERSIAN NUMBER TWENTY +103D5 ; [*0F7B.0020.0002.103D5] # OLD PERSIAN NUMBER HUNDRED +10917 ; [*0F7C.0020.0002.10917] # PHOENICIAN NUMBER TEN +10918 ; [*0F7D.0020.0002.10918] # PHOENICIAN NUMBER TWENTY +10919 ; [*0F7E.0020.0002.10919] # PHOENICIAN NUMBER ONE HUNDRED +1091F ; [*029B.0020.0002.1091F] # PHOENICIAN WORD SEPARATOR +10A44 ; [*0F7F.0020.0002.10A44] # KHAROSHTHI NUMBER TEN +10A45 ; [*0F80.0020.0002.10A45] # KHAROSHTHI NUMBER TWENTY +10A46 ; [*0F81.0020.0002.10A46] # KHAROSHTHI NUMBER ONE HUNDRED +10A47 ; [*0F82.0020.0002.10A47] # KHAROSHTHI NUMBER ONE THOUSAND +10A50 ; [*035E.0020.0002.10A50] # KHAROSHTHI PUNCTUATION DOT +10A51 ; [*035F.0020.0002.10A51] # KHAROSHTHI PUNCTUATION SMALL CIRCLE +10A52 ; [*0360.0020.0002.10A52] # KHAROSHTHI PUNCTUATION CIRCLE +10A53 ; [*0361.0020.0002.10A53] # KHAROSHTHI PUNCTUATION CRESCENT BAR +10A54 ; [*0362.0020.0002.10A54] # KHAROSHTHI PUNCTUATION MANGALAM +10A55 ; [*0363.0020.0002.10A55] # KHAROSHTHI PUNCTUATION LOTUS +10A56 ; [*0280.0020.0002.10A56] # KHAROSHTHI PUNCTUATION DANDA +10A57 ; [*0281.0020.0002.10A57] # KHAROSHTHI PUNCTUATION DOUBLE DANDA +10A58 ; [*0364.0020.0002.10A58] # KHAROSHTHI PUNCTUATION LINES +12432 ; [*0F83.0020.0002.12432] # CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS DISH +12433 ; [*0F84.0020.0002.12433] # CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS MIN +12456 ; [*0F85.0020.0002.12456] # CUNEIFORM NUMERIC SIGN NIGIDAMIN +12457 ; [*0F86.0020.0002.12457] # CUNEIFORM NUMERIC SIGN NIGIDAESH +1245A ; [*0F87.0020.0002.1245A] # CUNEIFORM NUMERIC SIGN ONE THIRD DISH +1245B ; [*0F88.0020.0002.1245B] # CUNEIFORM NUMERIC SIGN TWO THIRDS DISH +1245C ; [*0F89.0020.0002.1245C] # CUNEIFORM NUMERIC SIGN FIVE SIXTHS DISH +1245D ; [*0F8A.0020.0002.1245D] # CUNEIFORM NUMERIC SIGN ONE THIRD VARIANT FORM A +1245E ; [*0F8B.0020.0002.1245E] # CUNEIFORM NUMERIC SIGN TWO THIRDS VARIANT FORM A +1245F ; [*0F8C.0020.0002.1245F] # CUNEIFORM NUMERIC SIGN ONE EIGHTH ASH +12460 ; [*0F8D.0020.0002.12460] # CUNEIFORM NUMERIC SIGN ONE QUARTER ASH +12461 ; [*0F8E.0020.0002.12461] # CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE SIXTH +12462 ; [*0F8F.0020.0002.12462] # CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE QUARTER +12470 ; [*029C.0020.0002.12470] # CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER +12471 ; [*029D.0020.0002.12471] # CUNEIFORM PUNCTUATION SIGN VERTICAL COLON +12472 ; [*029E.0020.0002.12472] # CUNEIFORM PUNCTUATION SIGN DIAGONAL COLON +12473 ; [*029F.0020.0002.12473] # CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON +1D000 ; [*0D07.0020.0002.1D000] # BYZANTINE MUSICAL SYMBOL PSILI +1D001 ; [*0D08.0020.0002.1D001] # BYZANTINE MUSICAL SYMBOL DASEIA +1D002 ; [*0D09.0020.0002.1D002] # BYZANTINE MUSICAL SYMBOL PERISPOMENI +1D003 ; [*0D0A.0020.0002.1D003] # BYZANTINE MUSICAL SYMBOL OXEIA EKFONITIKON +1D004 ; [*0D0B.0020.0002.1D004] # BYZANTINE MUSICAL SYMBOL OXEIA DIPLI +1D005 ; [*0D0C.0020.0002.1D005] # BYZANTINE MUSICAL SYMBOL VAREIA EKFONITIKON +1D006 ; [*0D0D.0020.0002.1D006] # BYZANTINE MUSICAL SYMBOL VAREIA DIPLI +1D007 ; [*0D0E.0020.0002.1D007] # BYZANTINE MUSICAL SYMBOL KATHISTI +1D008 ; [*0D0F.0020.0002.1D008] # BYZANTINE MUSICAL SYMBOL SYRMATIKI +1D009 ; [*0D10.0020.0002.1D009] # BYZANTINE MUSICAL SYMBOL PARAKLITIKI +1D00A ; [*0D11.0020.0002.1D00A] # BYZANTINE MUSICAL SYMBOL YPOKRISIS +1D00B ; [*0D12.0020.0002.1D00B] # BYZANTINE MUSICAL SYMBOL YPOKRISIS DIPLI +1D00C ; [*0D13.0020.0002.1D00C] # BYZANTINE MUSICAL SYMBOL KREMASTI +1D00D ; [*0D14.0020.0002.1D00D] # BYZANTINE MUSICAL SYMBOL APESO EKFONITIKON +1D00E ; [*0D15.0020.0002.1D00E] # BYZANTINE MUSICAL SYMBOL EXO EKFONITIKON +1D00F ; [*0D16.0020.0002.1D00F] # BYZANTINE MUSICAL SYMBOL TELEIA +1D010 ; [*0D17.0020.0002.1D010] # BYZANTINE MUSICAL SYMBOL KENTIMATA +1D011 ; [*0D18.0020.0002.1D011] # BYZANTINE MUSICAL SYMBOL APOSTROFOS +1D012 ; [*0D19.0020.0002.1D012] # BYZANTINE MUSICAL SYMBOL APOSTROFOS DIPLI +1D013 ; [*0D1A.0020.0002.1D013] # BYZANTINE MUSICAL SYMBOL SYNEVMA +1D014 ; [*0D1B.0020.0002.1D014] # BYZANTINE MUSICAL SYMBOL THITA +1D015 ; [*0D1C.0020.0002.1D015] # BYZANTINE MUSICAL SYMBOL OLIGON ARCHAION +1D016 ; [*0D1D.0020.0002.1D016] # BYZANTINE MUSICAL SYMBOL GORGON ARCHAION +1D017 ; [*0D1E.0020.0002.1D017] # BYZANTINE MUSICAL SYMBOL PSILON +1D018 ; [*0D1F.0020.0002.1D018] # BYZANTINE MUSICAL SYMBOL CHAMILON +1D019 ; [*0D20.0020.0002.1D019] # BYZANTINE MUSICAL SYMBOL VATHY +1D01A ; [*0D21.0020.0002.1D01A] # BYZANTINE MUSICAL SYMBOL ISON ARCHAION +1D01B ; [*0D22.0020.0002.1D01B] # BYZANTINE MUSICAL SYMBOL KENTIMA ARCHAION +1D01C ; [*0D23.0020.0002.1D01C] # BYZANTINE MUSICAL SYMBOL KENTIMATA ARCHAION +1D01D ; [*0D24.0020.0002.1D01D] # BYZANTINE MUSICAL SYMBOL SAXIMATA +1D01E ; [*0D25.0020.0002.1D01E] # BYZANTINE MUSICAL SYMBOL PARICHON +1D01F ; [*0D26.0020.0002.1D01F] # BYZANTINE MUSICAL SYMBOL STAVROS APODEXIA +1D020 ; [*0D27.0020.0002.1D020] # BYZANTINE MUSICAL SYMBOL OXEIAI ARCHAION +1D021 ; [*0D28.0020.0002.1D021] # BYZANTINE MUSICAL SYMBOL VAREIAI ARCHAION +1D022 ; [*0D29.0020.0002.1D022] # BYZANTINE MUSICAL SYMBOL APODERMA ARCHAION +1D023 ; [*0D2A.0020.0002.1D023] # BYZANTINE MUSICAL SYMBOL APOTHEMA +1D024 ; [*0D2B.0020.0002.1D024] # BYZANTINE MUSICAL SYMBOL KLASMA +1D025 ; [*0D2C.0020.0002.1D025] # BYZANTINE MUSICAL SYMBOL REVMA +1D026 ; [*0D2D.0020.0002.1D026] # BYZANTINE MUSICAL SYMBOL PIASMA ARCHAION +1D027 ; [*0D2E.0020.0002.1D027] # BYZANTINE MUSICAL SYMBOL TINAGMA +1D028 ; [*0D2F.0020.0002.1D028] # BYZANTINE MUSICAL SYMBOL ANATRICHISMA +1D029 ; [*0D30.0020.0002.1D029] # BYZANTINE MUSICAL SYMBOL SEISMA +1D02A ; [*0D31.0020.0002.1D02A] # BYZANTINE MUSICAL SYMBOL SYNAGMA ARCHAION +1D02B ; [*0D32.0020.0002.1D02B] # BYZANTINE MUSICAL SYMBOL SYNAGMA META STAVROU +1D02C ; [*0D33.0020.0002.1D02C] # BYZANTINE MUSICAL SYMBOL OYRANISMA ARCHAION +1D02D ; [*0D34.0020.0002.1D02D] # BYZANTINE MUSICAL SYMBOL THEMA +1D02E ; [*0D35.0020.0002.1D02E] # BYZANTINE MUSICAL SYMBOL LEMOI +1D02F ; [*0D36.0020.0002.1D02F] # BYZANTINE MUSICAL SYMBOL DYO +1D030 ; [*0D37.0020.0002.1D030] # BYZANTINE MUSICAL SYMBOL TRIA +1D031 ; [*0D38.0020.0002.1D031] # BYZANTINE MUSICAL SYMBOL TESSERA +1D032 ; [*0D39.0020.0002.1D032] # BYZANTINE MUSICAL SYMBOL KRATIMATA +1D033 ; [*0D3A.0020.0002.1D033] # BYZANTINE MUSICAL SYMBOL APESO EXO NEO +1D034 ; [*0D3B.0020.0002.1D034] # BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION +1D035 ; [*0D3C.0020.0002.1D035] # BYZANTINE MUSICAL SYMBOL IMIFTHORA +1D036 ; [*0D3D.0020.0002.1D036] # BYZANTINE MUSICAL SYMBOL TROMIKON ARCHAION +1D037 ; [*0D3E.0020.0002.1D037] # BYZANTINE MUSICAL SYMBOL KATAVA TROMIKON +1D038 ; [*0D3F.0020.0002.1D038] # BYZANTINE MUSICAL SYMBOL PELASTON +1D039 ; [*0D40.0020.0002.1D039] # BYZANTINE MUSICAL SYMBOL PSIFISTON +1D03A ; [*0D41.0020.0002.1D03A] # BYZANTINE MUSICAL SYMBOL KONTEVMA +1D03B ; [*0D42.0020.0002.1D03B] # BYZANTINE MUSICAL SYMBOL CHOREVMA ARCHAION +1D03C ; [*0D43.0020.0002.1D03C] # BYZANTINE MUSICAL SYMBOL RAPISMA +1D03D ; [*0D44.0020.0002.1D03D] # BYZANTINE MUSICAL SYMBOL PARAKALESMA ARCHAION +1D03E ; [*0D45.0020.0002.1D03E] # BYZANTINE MUSICAL SYMBOL PARAKLITIKI ARCHAION +1D03F ; [*0D46.0020.0002.1D03F] # BYZANTINE MUSICAL SYMBOL ICHADIN +1D040 ; [*0D47.0020.0002.1D040] # BYZANTINE MUSICAL SYMBOL NANA +1D041 ; [*0D48.0020.0002.1D041] # BYZANTINE MUSICAL SYMBOL PETASMA +1D042 ; [*0D49.0020.0002.1D042] # BYZANTINE MUSICAL SYMBOL KONTEVMA ALLO +1D043 ; [*0D4A.0020.0002.1D043] # BYZANTINE MUSICAL SYMBOL TROMIKON ALLO +1D044 ; [*0D4B.0020.0002.1D044] # BYZANTINE MUSICAL SYMBOL STRAGGISMATA +1D045 ; [*0D4C.0020.0002.1D045] # BYZANTINE MUSICAL SYMBOL GRONTHISMATA +1D046 ; [*0D4D.0020.0002.1D046] # BYZANTINE MUSICAL SYMBOL ISON NEO +1D047 ; [*0D4E.0020.0002.1D047] # BYZANTINE MUSICAL SYMBOL OLIGON NEO +1D048 ; [*0D4F.0020.0002.1D048] # BYZANTINE MUSICAL SYMBOL OXEIA NEO +1D049 ; [*0D50.0020.0002.1D049] # BYZANTINE MUSICAL SYMBOL PETASTI +1D04A ; [*0D51.0020.0002.1D04A] # BYZANTINE MUSICAL SYMBOL KOUFISMA +1D04B ; [*0D52.0020.0002.1D04B] # BYZANTINE MUSICAL SYMBOL PETASTOKOUFISMA +1D04C ; [*0D53.0020.0002.1D04C] # BYZANTINE MUSICAL SYMBOL KRATIMOKOUFISMA +1D04D ; [*0D54.0020.0002.1D04D] # BYZANTINE MUSICAL SYMBOL PELASTON NEO +1D04E ; [*0D55.0020.0002.1D04E] # BYZANTINE MUSICAL SYMBOL KENTIMATA NEO ANO +1D04F ; [*0D56.0020.0002.1D04F] # BYZANTINE MUSICAL SYMBOL KENTIMA NEO ANO +1D050 ; [*0D57.0020.0002.1D050] # BYZANTINE MUSICAL SYMBOL YPSILI +1D051 ; [*0D58.0020.0002.1D051] # BYZANTINE MUSICAL SYMBOL APOSTROFOS NEO +1D052 ; [*0D59.0020.0002.1D052] # BYZANTINE MUSICAL SYMBOL APOSTROFOI SYNDESMOS NEO +1D053 ; [*0D5A.0020.0002.1D053] # BYZANTINE MUSICAL SYMBOL YPORROI +1D054 ; [*0D5B.0020.0002.1D054] # BYZANTINE MUSICAL SYMBOL KRATIMOYPORROON +1D055 ; [*0D5C.0020.0002.1D055] # BYZANTINE MUSICAL SYMBOL ELAFRON +1D056 ; [*0D5D.0020.0002.1D056] # BYZANTINE MUSICAL SYMBOL CHAMILI +1D057 ; [*0D5E.0020.0002.1D057] # BYZANTINE MUSICAL SYMBOL MIKRON ISON +1D058 ; [*0D5F.0020.0002.1D058] # BYZANTINE MUSICAL SYMBOL VAREIA NEO +1D059 ; [*0D60.0020.0002.1D059] # BYZANTINE MUSICAL SYMBOL PIASMA NEO +1D05A ; [*0D61.0020.0002.1D05A] # BYZANTINE MUSICAL SYMBOL PSIFISTON NEO +1D05B ; [*0D62.0020.0002.1D05B] # BYZANTINE MUSICAL SYMBOL OMALON +1D05C ; [*0D63.0020.0002.1D05C] # BYZANTINE MUSICAL SYMBOL ANTIKENOMA +1D05D ; [*0D64.0020.0002.1D05D] # BYZANTINE MUSICAL SYMBOL LYGISMA +1D05E ; [*0D65.0020.0002.1D05E] # BYZANTINE MUSICAL SYMBOL PARAKLITIKI NEO +1D05F ; [*0D66.0020.0002.1D05F] # BYZANTINE MUSICAL SYMBOL PARAKALESMA NEO +1D060 ; [*0D67.0020.0002.1D060] # BYZANTINE MUSICAL SYMBOL ETERON PARAKALESMA +1D061 ; [*0D68.0020.0002.1D061] # BYZANTINE MUSICAL SYMBOL KYLISMA +1D062 ; [*0D69.0020.0002.1D062] # BYZANTINE MUSICAL SYMBOL ANTIKENOKYLISMA +1D063 ; [*0D6A.0020.0002.1D063] # BYZANTINE MUSICAL SYMBOL TROMIKON NEO +1D064 ; [*0D6B.0020.0002.1D064] # BYZANTINE MUSICAL SYMBOL EKSTREPTON +1D065 ; [*0D6C.0020.0002.1D065] # BYZANTINE MUSICAL SYMBOL SYNAGMA NEO +1D066 ; [*0D6D.0020.0002.1D066] # BYZANTINE MUSICAL SYMBOL SYRMA +1D067 ; [*0D6E.0020.0002.1D067] # BYZANTINE MUSICAL SYMBOL CHOREVMA NEO +1D068 ; [*0D6F.0020.0002.1D068] # BYZANTINE MUSICAL SYMBOL EPEGERMA +1D069 ; [*0D70.0020.0002.1D069] # BYZANTINE MUSICAL SYMBOL SEISMA NEO +1D06A ; [*0D71.0020.0002.1D06A] # BYZANTINE MUSICAL SYMBOL XIRON KLASMA +1D06B ; [*0D72.0020.0002.1D06B] # BYZANTINE MUSICAL SYMBOL TROMIKOPSIFISTON +1D06C ; [*0D73.0020.0002.1D06C] # BYZANTINE MUSICAL SYMBOL PSIFISTOLYGISMA +1D06D ; [*0D74.0020.0002.1D06D] # BYZANTINE MUSICAL SYMBOL TROMIKOLYGISMA +1D06E ; [*0D75.0020.0002.1D06E] # BYZANTINE MUSICAL SYMBOL TROMIKOPARAKALESMA +1D06F ; [*0D76.0020.0002.1D06F] # BYZANTINE MUSICAL SYMBOL PSIFISTOPARAKALESMA +1D070 ; [*0D77.0020.0002.1D070] # BYZANTINE MUSICAL SYMBOL TROMIKOSYNAGMA +1D071 ; [*0D78.0020.0002.1D071] # BYZANTINE MUSICAL SYMBOL PSIFISTOSYNAGMA +1D072 ; [*0D79.0020.0002.1D072] # BYZANTINE MUSICAL SYMBOL GORGOSYNTHETON +1D073 ; [*0D7A.0020.0002.1D073] # BYZANTINE MUSICAL SYMBOL ARGOSYNTHETON +1D074 ; [*0D7B.0020.0002.1D074] # BYZANTINE MUSICAL SYMBOL ETERON ARGOSYNTHETON +1D075 ; [*0D7C.0020.0002.1D075] # BYZANTINE MUSICAL SYMBOL OYRANISMA NEO +1D076 ; [*0D7D.0020.0002.1D076] # BYZANTINE MUSICAL SYMBOL THEMATISMOS ESO +1D077 ; [*0D7E.0020.0002.1D077] # BYZANTINE MUSICAL SYMBOL THEMATISMOS EXO +1D078 ; [*0D7F.0020.0002.1D078] # BYZANTINE MUSICAL SYMBOL THEMA APLOUN +1D079 ; [*0D80.0020.0002.1D079] # BYZANTINE MUSICAL SYMBOL THES KAI APOTHES +1D07A ; [*0D81.0020.0002.1D07A] # BYZANTINE MUSICAL SYMBOL KATAVASMA +1D07B ; [*0D82.0020.0002.1D07B] # BYZANTINE MUSICAL SYMBOL ENDOFONON +1D07C ; [*0D83.0020.0002.1D07C] # BYZANTINE MUSICAL SYMBOL YFEN KATO +1D07D ; [*0D84.0020.0002.1D07D] # BYZANTINE MUSICAL SYMBOL YFEN ANO +1D07E ; [*0D85.0020.0002.1D07E] # BYZANTINE MUSICAL SYMBOL STAVROS +1D07F ; [*0D86.0020.0002.1D07F] # BYZANTINE MUSICAL SYMBOL KLASMA ANO +1D080 ; [*0D87.0020.0002.1D080] # BYZANTINE MUSICAL SYMBOL DIPLI ARCHAION +1D081 ; [*0D88.0020.0002.1D081] # BYZANTINE MUSICAL SYMBOL KRATIMA ARCHAION +1D082 ; [*0D89.0020.0002.1D082] # BYZANTINE MUSICAL SYMBOL KRATIMA ALLO +1D083 ; [*0D8A.0020.0002.1D083] # BYZANTINE MUSICAL SYMBOL KRATIMA NEO +1D084 ; [*0D8B.0020.0002.1D084] # BYZANTINE MUSICAL SYMBOL APODERMA NEO +1D085 ; [*0D8C.0020.0002.1D085] # BYZANTINE MUSICAL SYMBOL APLI +1D086 ; [*0D8D.0020.0002.1D086] # BYZANTINE MUSICAL SYMBOL DIPLI +1D087 ; [*0D8E.0020.0002.1D087] # BYZANTINE MUSICAL SYMBOL TRIPLI +1D088 ; [*0D8F.0020.0002.1D088] # BYZANTINE MUSICAL SYMBOL TETRAPLI +1D089 ; [*0D90.0020.0002.1D089] # BYZANTINE MUSICAL SYMBOL KORONIS +1D08A ; [*0D91.0020.0002.1D08A] # BYZANTINE MUSICAL SYMBOL LEIMMA ENOS CHRONOU +1D08B ; [*0D92.0020.0002.1D08B] # BYZANTINE MUSICAL SYMBOL LEIMMA DYO CHRONON +1D08C ; [*0D93.0020.0002.1D08C] # BYZANTINE MUSICAL SYMBOL LEIMMA TRION CHRONON +1D08D ; [*0D94.0020.0002.1D08D] # BYZANTINE MUSICAL SYMBOL LEIMMA TESSARON CHRONON +1D08E ; [*0D95.0020.0002.1D08E] # BYZANTINE MUSICAL SYMBOL LEIMMA IMISEOS CHRONOU +1D08F ; [*0D96.0020.0002.1D08F] # BYZANTINE MUSICAL SYMBOL GORGON NEO ANO +1D090 ; [*0D97.0020.0002.1D090] # BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON ARISTERA +1D091 ; [*0D98.0020.0002.1D091] # BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON DEXIA +1D092 ; [*0D99.0020.0002.1D092] # BYZANTINE MUSICAL SYMBOL DIGORGON +1D093 ; [*0D9A.0020.0002.1D093] # BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA KATO +1D094 ; [*0D9B.0020.0002.1D094] # BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA ANO +1D095 ; [*0D9C.0020.0002.1D095] # BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON DEXIA +1D096 ; [*0D9D.0020.0002.1D096] # BYZANTINE MUSICAL SYMBOL TRIGORGON +1D097 ; [*0D9E.0020.0002.1D097] # BYZANTINE MUSICAL SYMBOL ARGON +1D098 ; [*0D9F.0020.0002.1D098] # BYZANTINE MUSICAL SYMBOL IMIDIARGON +1D099 ; [*0DA0.0020.0002.1D099] # BYZANTINE MUSICAL SYMBOL DIARGON +1D09A ; [*0DA1.0020.0002.1D09A] # BYZANTINE MUSICAL SYMBOL AGOGI POLI ARGI +1D09B ; [*0DA2.0020.0002.1D09B] # BYZANTINE MUSICAL SYMBOL AGOGI ARGOTERI +1D09C ; [*0DA3.0020.0002.1D09C] # BYZANTINE MUSICAL SYMBOL AGOGI ARGI +1D09D ; [*0DA4.0020.0002.1D09D] # BYZANTINE MUSICAL SYMBOL AGOGI METRIA +1D09E ; [*0DA5.0020.0002.1D09E] # BYZANTINE MUSICAL SYMBOL AGOGI MESI +1D09F ; [*0DA6.0020.0002.1D09F] # BYZANTINE MUSICAL SYMBOL AGOGI GORGI +1D0A0 ; [*0DA7.0020.0002.1D0A0] # BYZANTINE MUSICAL SYMBOL AGOGI GORGOTERI +1D0A1 ; [*0DA8.0020.0002.1D0A1] # BYZANTINE MUSICAL SYMBOL AGOGI POLI GORGI +1D0A2 ; [*0DA9.0020.0002.1D0A2] # BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOS ICHOS +1D0A3 ; [*0DAA.0020.0002.1D0A3] # BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI PROTOS ICHOS +1D0A4 ; [*0DAB.0020.0002.1D0A4] # BYZANTINE MUSICAL SYMBOL MARTYRIA DEYTEROS ICHOS +1D0A5 ; [*0DAC.0020.0002.1D0A5] # BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI DEYTEROS ICHOS +1D0A6 ; [*0DAD.0020.0002.1D0A6] # BYZANTINE MUSICAL SYMBOL MARTYRIA TRITOS ICHOS +1D0A7 ; [*0DAE.0020.0002.1D0A7] # BYZANTINE MUSICAL SYMBOL MARTYRIA TRIFONIAS +1D0A8 ; [*0DAF.0020.0002.1D0A8] # BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS ICHOS +1D0A9 ; [*0DB0.0020.0002.1D0A9] # BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS LEGETOS ICHOS +1D0AA ; [*0DB1.0020.0002.1D0AA] # BYZANTINE MUSICAL SYMBOL MARTYRIA LEGETOS ICHOS +1D0AB ; [*0DB2.0020.0002.1D0AB] # BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS ICHOS +1D0AC ; [*0DB3.0020.0002.1D0AC] # BYZANTINE MUSICAL SYMBOL ISAKIA TELOUS ICHIMATOS +1D0AD ; [*0DB4.0020.0002.1D0AD] # BYZANTINE MUSICAL SYMBOL APOSTROFOI TELOUS ICHIMATOS +1D0AE ; [*0DB5.0020.0002.1D0AE] # BYZANTINE MUSICAL SYMBOL FANEROSIS TETRAFONIAS +1D0AF ; [*0DB6.0020.0002.1D0AF] # BYZANTINE MUSICAL SYMBOL FANEROSIS MONOFONIAS +1D0B0 ; [*0DB7.0020.0002.1D0B0] # BYZANTINE MUSICAL SYMBOL FANEROSIS DIFONIAS +1D0B1 ; [*0DB8.0020.0002.1D0B1] # BYZANTINE MUSICAL SYMBOL MARTYRIA VARYS ICHOS +1D0B2 ; [*0DB9.0020.0002.1D0B2] # BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOVARYS ICHOS +1D0B3 ; [*0DBA.0020.0002.1D0B3] # BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS TETARTOS ICHOS +1D0B4 ; [*0DBB.0020.0002.1D0B4] # BYZANTINE MUSICAL SYMBOL GORTHMIKON N APLOUN +1D0B5 ; [*0DBC.0020.0002.1D0B5] # BYZANTINE MUSICAL SYMBOL GORTHMIKON N DIPLOUN +1D0B6 ; [*0DBD.0020.0002.1D0B6] # BYZANTINE MUSICAL SYMBOL ENARXIS KAI FTHORA VOU +1D0B7 ; [*0DBE.0020.0002.1D0B7] # BYZANTINE MUSICAL SYMBOL IMIFONON +1D0B8 ; [*0DBF.0020.0002.1D0B8] # BYZANTINE MUSICAL SYMBOL IMIFTHORON +1D0B9 ; [*0DC0.0020.0002.1D0B9] # BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION DEYTEROU ICHOU +1D0BA ; [*0DC1.0020.0002.1D0BA] # BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI PA +1D0BB ; [*0DC2.0020.0002.1D0BB] # BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NANA +1D0BC ; [*0DC3.0020.0002.1D0BC] # BYZANTINE MUSICAL SYMBOL FTHORA NAOS ICHOS +1D0BD ; [*0DC4.0020.0002.1D0BD] # BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI DI +1D0BE ; [*0DC5.0020.0002.1D0BE] # BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON DIATONON DI +1D0BF ; [*0DC6.0020.0002.1D0BF] # BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI KE +1D0C0 ; [*0DC7.0020.0002.1D0C0] # BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI ZO +1D0C1 ; [*0DC8.0020.0002.1D0C1] # BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI KATO +1D0C2 ; [*0DC9.0020.0002.1D0C2] # BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI ANO +1D0C3 ; [*0DCA.0020.0002.1D0C3] # BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA DIFONIAS +1D0C4 ; [*0DCB.0020.0002.1D0C4] # BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA MONOFONIAS +1D0C5 ; [*0DCC.0020.0002.1D0C5] # BYZANTINE MUSICAL SYMBOL FHTORA SKLIRON CHROMA VASIS +1D0C6 ; [*0DCD.0020.0002.1D0C6] # BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON CHROMA SYNAFI +1D0C7 ; [*0DCE.0020.0002.1D0C7] # BYZANTINE MUSICAL SYMBOL FTHORA NENANO +1D0C8 ; [*0DCF.0020.0002.1D0C8] # BYZANTINE MUSICAL SYMBOL CHROA ZYGOS +1D0C9 ; [*0DD0.0020.0002.1D0C9] # BYZANTINE MUSICAL SYMBOL CHROA KLITON +1D0CA ; [*0DD1.0020.0002.1D0CA] # BYZANTINE MUSICAL SYMBOL CHROA SPATHI +1D0CB ; [*0DD2.0020.0002.1D0CB] # BYZANTINE MUSICAL SYMBOL FTHORA I YFESIS TETARTIMORION +1D0CC ; [*0DD3.0020.0002.1D0CC] # BYZANTINE MUSICAL SYMBOL FTHORA ENARMONIOS ANTIFONIA +1D0CD ; [*0DD4.0020.0002.1D0CD] # BYZANTINE MUSICAL SYMBOL YFESIS TRITIMORION +1D0CE ; [*0DD5.0020.0002.1D0CE] # BYZANTINE MUSICAL SYMBOL DIESIS TRITIMORION +1D0CF ; [*0DD6.0020.0002.1D0CF] # BYZANTINE MUSICAL SYMBOL DIESIS TETARTIMORION +1D0D0 ; [*0DD7.0020.0002.1D0D0] # BYZANTINE MUSICAL SYMBOL DIESIS APLI DYO DODEKATA +1D0D1 ; [*0DD8.0020.0002.1D0D1] # BYZANTINE MUSICAL SYMBOL DIESIS MONOGRAMMOS TESSERA DODEKATA +1D0D2 ; [*0DD9.0020.0002.1D0D2] # BYZANTINE MUSICAL SYMBOL DIESIS DIGRAMMOS EX DODEKATA +1D0D3 ; [*0DDA.0020.0002.1D0D3] # BYZANTINE MUSICAL SYMBOL DIESIS TRIGRAMMOS OKTO DODEKATA +1D0D4 ; [*0DDB.0020.0002.1D0D4] # BYZANTINE MUSICAL SYMBOL YFESIS APLI DYO DODEKATA +1D0D5 ; [*0DDC.0020.0002.1D0D5] # BYZANTINE MUSICAL SYMBOL YFESIS MONOGRAMMOS TESSERA DODEKATA +1D0D6 ; [*0DDD.0020.0002.1D0D6] # BYZANTINE MUSICAL SYMBOL YFESIS DIGRAMMOS EX DODEKATA +1D0D7 ; [*0DDE.0020.0002.1D0D7] # BYZANTINE MUSICAL SYMBOL YFESIS TRIGRAMMOS OKTO DODEKATA +1D0D8 ; [*0DDF.0020.0002.1D0D8] # BYZANTINE MUSICAL SYMBOL GENIKI DIESIS +1D0D9 ; [*0DE0.0020.0002.1D0D9] # BYZANTINE MUSICAL SYMBOL GENIKI YFESIS +1D0DA ; [*0DE1.0020.0002.1D0DA] # BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MIKRI +1D0DB ; [*0DE2.0020.0002.1D0DB] # BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MEGALI +1D0DC ; [*0DE3.0020.0002.1D0DC] # BYZANTINE MUSICAL SYMBOL DIASTOLI DIPLI +1D0DD ; [*0DE4.0020.0002.1D0DD] # BYZANTINE MUSICAL SYMBOL DIASTOLI THESEOS +1D0DE ; [*0DE5.0020.0002.1D0DE] # BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS +1D0DF ; [*0DE6.0020.0002.1D0DF] # BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS DISIMOU +1D0E0 ; [*0DE7.0020.0002.1D0E0] # BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TRISIMOU +1D0E1 ; [*0DE8.0020.0002.1D0E1] # BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TETRASIMOU +1D0E2 ; [*0DE9.0020.0002.1D0E2] # BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS +1D0E3 ; [*0DEA.0020.0002.1D0E3] # BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS DISIMOU +1D0E4 ; [*0DEB.0020.0002.1D0E4] # BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TRISIMOU +1D0E5 ; [*0DEC.0020.0002.1D0E5] # BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TETRASIMOU +1D0E6 ; [*0DED.0020.0002.1D0E6] # BYZANTINE MUSICAL SYMBOL DIGRAMMA GG +1D0E7 ; [*0DEE.0020.0002.1D0E7] # BYZANTINE MUSICAL SYMBOL DIFTOGGOS OU +1D0E8 ; [*0DEF.0020.0002.1D0E8] # BYZANTINE MUSICAL SYMBOL STIGMA +1D0E9 ; [*0DF0.0020.0002.1D0E9] # BYZANTINE MUSICAL SYMBOL ARKTIKO PA +1D0EA ; [*0DF1.0020.0002.1D0EA] # BYZANTINE MUSICAL SYMBOL ARKTIKO VOU +1D0EB ; [*0DF2.0020.0002.1D0EB] # BYZANTINE MUSICAL SYMBOL ARKTIKO GA +1D0EC ; [*0DF3.0020.0002.1D0EC] # BYZANTINE MUSICAL SYMBOL ARKTIKO DI +1D0ED ; [*0DF4.0020.0002.1D0ED] # BYZANTINE MUSICAL SYMBOL ARKTIKO KE +1D0EE ; [*0DF5.0020.0002.1D0EE] # BYZANTINE MUSICAL SYMBOL ARKTIKO ZO +1D0EF ; [*0DF6.0020.0002.1D0EF] # BYZANTINE MUSICAL SYMBOL ARKTIKO NI +1D0F0 ; [*0DF7.0020.0002.1D0F0] # BYZANTINE MUSICAL SYMBOL KENTIMATA NEO MESO +1D0F1 ; [*0DF8.0020.0002.1D0F1] # BYZANTINE MUSICAL SYMBOL KENTIMA NEO MESO +1D0F2 ; [*0DF9.0020.0002.1D0F2] # BYZANTINE MUSICAL SYMBOL KENTIMATA NEO KATO +1D0F3 ; [*0DFA.0020.0002.1D0F3] # BYZANTINE MUSICAL SYMBOL KENTIMA NEO KATO +1D0F4 ; [*0DFB.0020.0002.1D0F4] # BYZANTINE MUSICAL SYMBOL KLASMA KATO +1D0F5 ; [*0DFC.0020.0002.1D0F5] # BYZANTINE MUSICAL SYMBOL GORGON NEO KATO +1D100 ; [*0DFD.0020.0002.1D100] # MUSICAL SYMBOL SINGLE BARLINE +1D101 ; [*0DFE.0020.0002.1D101] # MUSICAL SYMBOL DOUBLE BARLINE +1D102 ; [*0DFF.0020.0002.1D102] # MUSICAL SYMBOL FINAL BARLINE +1D103 ; [*0E00.0020.0002.1D103] # MUSICAL SYMBOL REVERSE FINAL BARLINE +1D104 ; [*0E01.0020.0002.1D104] # MUSICAL SYMBOL DASHED BARLINE +1D105 ; [*0E02.0020.0002.1D105] # MUSICAL SYMBOL SHORT BARLINE +1D106 ; [*0E03.0020.0002.1D106] # MUSICAL SYMBOL LEFT REPEAT SIGN +1D107 ; [*0E04.0020.0002.1D107] # MUSICAL SYMBOL RIGHT REPEAT SIGN +1D108 ; [*0E05.0020.0002.1D108] # MUSICAL SYMBOL REPEAT DOTS +1D109 ; [*0E06.0020.0002.1D109] # MUSICAL SYMBOL DAL SEGNO +1D10A ; [*0E07.0020.0002.1D10A] # MUSICAL SYMBOL DA CAPO +1D10B ; [*0E08.0020.0002.1D10B] # MUSICAL SYMBOL SEGNO +1D10C ; [*0E09.0020.0002.1D10C] # MUSICAL SYMBOL CODA +1D10D ; [*0E0A.0020.0002.1D10D] # MUSICAL SYMBOL REPEATED FIGURE-1 +1D10E ; [*0E0B.0020.0002.1D10E] # MUSICAL SYMBOL REPEATED FIGURE-2 +1D10F ; [*0E0C.0020.0002.1D10F] # MUSICAL SYMBOL REPEATED FIGURE-3 +1D110 ; [*0E0D.0020.0002.1D110] # MUSICAL SYMBOL FERMATA +1D111 ; [*0E0E.0020.0002.1D111] # MUSICAL SYMBOL FERMATA BELOW +1D112 ; [*0E0F.0020.0002.1D112] # MUSICAL SYMBOL BREATH MARK +1D113 ; [*0E10.0020.0002.1D113] # MUSICAL SYMBOL CAESURA +1D114 ; [*0E11.0020.0002.1D114] # MUSICAL SYMBOL BRACE +1D115 ; [*0E12.0020.0002.1D115] # MUSICAL SYMBOL BRACKET +1D116 ; [*0E13.0020.0002.1D116] # MUSICAL SYMBOL ONE-LINE STAFF +1D117 ; [*0E14.0020.0002.1D117] # MUSICAL SYMBOL TWO-LINE STAFF +1D118 ; [*0E15.0020.0002.1D118] # MUSICAL SYMBOL THREE-LINE STAFF +1D119 ; [*0E16.0020.0002.1D119] # MUSICAL SYMBOL FOUR-LINE STAFF +1D11A ; [*0E17.0020.0002.1D11A] # MUSICAL SYMBOL FIVE-LINE STAFF +1D11B ; [*0E18.0020.0002.1D11B] # MUSICAL SYMBOL SIX-LINE STAFF +1D11C ; [*0E19.0020.0002.1D11C] # MUSICAL SYMBOL SIX-STRING FRETBOARD +1D11D ; [*0E1A.0020.0002.1D11D] # MUSICAL SYMBOL FOUR-STRING FRETBOARD +1D11E ; [*0E1B.0020.0002.1D11E] # MUSICAL SYMBOL G CLEF +1D11F ; [*0E1C.0020.0002.1D11F] # MUSICAL SYMBOL G CLEF OTTAVA ALTA +1D120 ; [*0E1D.0020.0002.1D120] # MUSICAL SYMBOL G CLEF OTTAVA BASSA +1D121 ; [*0E1E.0020.0002.1D121] # MUSICAL SYMBOL C CLEF +1D122 ; [*0E1F.0020.0002.1D122] # MUSICAL SYMBOL F CLEF +1D123 ; [*0E20.0020.0002.1D123] # MUSICAL SYMBOL F CLEF OTTAVA ALTA +1D124 ; [*0E21.0020.0002.1D124] # MUSICAL SYMBOL F CLEF OTTAVA BASSA +1D125 ; [*0E22.0020.0002.1D125] # MUSICAL SYMBOL DRUM CLEF-1 +1D126 ; [*0E23.0020.0002.1D126] # MUSICAL SYMBOL DRUM CLEF-2 +1D12A ; [*0E27.0020.0002.1D12A] # MUSICAL SYMBOL DOUBLE SHARP +1D12B ; [*0E28.0020.0002.1D12B] # MUSICAL SYMBOL DOUBLE FLAT +1D12C ; [*0E29.0020.0002.1D12C] # MUSICAL SYMBOL FLAT UP +1D12D ; [*0E2A.0020.0002.1D12D] # MUSICAL SYMBOL FLAT DOWN +1D12E ; [*0E2B.0020.0002.1D12E] # MUSICAL SYMBOL NATURAL UP +1D12F ; [*0E2C.0020.0002.1D12F] # MUSICAL SYMBOL NATURAL DOWN +1D130 ; [*0E2D.0020.0002.1D130] # MUSICAL SYMBOL SHARP UP +1D131 ; [*0E2E.0020.0002.1D131] # MUSICAL SYMBOL SHARP DOWN +1D132 ; [*0E2F.0020.0002.1D132] # MUSICAL SYMBOL QUARTER TONE SHARP +1D133 ; [*0E30.0020.0002.1D133] # MUSICAL SYMBOL QUARTER TONE FLAT +1D134 ; [*0E31.0020.0002.1D134] # MUSICAL SYMBOL COMMON TIME +1D135 ; [*0E32.0020.0002.1D135] # MUSICAL SYMBOL CUT TIME +1D136 ; [*0E33.0020.0002.1D136] # MUSICAL SYMBOL OTTAVA ALTA +1D137 ; [*0E34.0020.0002.1D137] # MUSICAL SYMBOL OTTAVA BASSA +1D138 ; [*0E35.0020.0002.1D138] # MUSICAL SYMBOL QUINDICESIMA ALTA +1D139 ; [*0E36.0020.0002.1D139] # MUSICAL SYMBOL QUINDICESIMA BASSA +1D13A ; [*0E37.0020.0002.1D13A] # MUSICAL SYMBOL MULTI REST +1D13B ; [*0E38.0020.0002.1D13B] # MUSICAL SYMBOL WHOLE REST +1D13C ; [*0E39.0020.0002.1D13C] # MUSICAL SYMBOL HALF REST +1D13D ; [*0E3A.0020.0002.1D13D] # MUSICAL SYMBOL QUARTER REST +1D13E ; [*0E3B.0020.0002.1D13E] # MUSICAL SYMBOL EIGHTH REST +1D13F ; [*0E3C.0020.0002.1D13F] # MUSICAL SYMBOL SIXTEENTH REST +1D140 ; [*0E3D.0020.0002.1D140] # MUSICAL SYMBOL THIRTY-SECOND REST +1D141 ; [*0E3E.0020.0002.1D141] # MUSICAL SYMBOL SIXTY-FOURTH REST +1D142 ; [*0E3F.0020.0002.1D142] # MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH REST +1D143 ; [*0E40.0020.0002.1D143] # MUSICAL SYMBOL X NOTEHEAD +1D144 ; [*0E41.0020.0002.1D144] # MUSICAL SYMBOL PLUS NOTEHEAD +1D145 ; [*0E42.0020.0002.1D145] # MUSICAL SYMBOL CIRCLE X NOTEHEAD +1D146 ; [*0E43.0020.0002.1D146] # MUSICAL SYMBOL SQUARE NOTEHEAD WHITE +1D147 ; [*0E44.0020.0002.1D147] # MUSICAL SYMBOL SQUARE NOTEHEAD BLACK +1D148 ; [*0E45.0020.0002.1D148] # MUSICAL SYMBOL TRIANGLE NOTEHEAD UP WHITE +1D149 ; [*0E46.0020.0002.1D149] # MUSICAL SYMBOL TRIANGLE NOTEHEAD UP BLACK +1D14A ; [*0E47.0020.0002.1D14A] # MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT WHITE +1D14B ; [*0E48.0020.0002.1D14B] # MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT BLACK +1D14C ; [*0E49.0020.0002.1D14C] # MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT WHITE +1D14D ; [*0E4A.0020.0002.1D14D] # MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT BLACK +1D14E ; [*0E4B.0020.0002.1D14E] # MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN WHITE +1D14F ; [*0E4C.0020.0002.1D14F] # MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN BLACK +1D150 ; [*0E4D.0020.0002.1D150] # MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT WHITE +1D151 ; [*0E4E.0020.0002.1D151] # MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT BLACK +1D152 ; [*0E4F.0020.0002.1D152] # MUSICAL SYMBOL MOON NOTEHEAD WHITE +1D153 ; [*0E50.0020.0002.1D153] # MUSICAL SYMBOL MOON NOTEHEAD BLACK +1D154 ; [*0E51.0020.0002.1D154] # MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN WHITE +1D155 ; [*0E52.0020.0002.1D155] # MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN BLACK +1D156 ; [*0E53.0020.0002.1D156] # MUSICAL SYMBOL PARENTHESIS NOTEHEAD +1D157 ; [*0E54.0020.0002.1D157] # MUSICAL SYMBOL VOID NOTEHEAD +1D158 ; [*0E55.0020.0002.1D158] # MUSICAL SYMBOL NOTEHEAD BLACK +1D159 ; [*0E56.0020.0002.1D159] # MUSICAL SYMBOL NULL NOTEHEAD +1D15A ; [*0E57.0020.0002.1D15A] # MUSICAL SYMBOL CLUSTER NOTEHEAD WHITE +1D15B ; [*0E58.0020.0002.1D15B] # MUSICAL SYMBOL CLUSTER NOTEHEAD BLACK +1D15C ; [*0E59.0020.0002.1D15C] # MUSICAL SYMBOL BREVE +1D15D ; [*0E5A.0020.0002.1D15D] # MUSICAL SYMBOL WHOLE NOTE +1D15E ; [*0E54.0020.0002.1D157][.0000.0000.0000.1D165] # MUSICAL SYMBOL HALF NOTE; QQCN +1D15F ; [*0E55.0020.0002.1D158][.0000.0000.0000.1D165] # MUSICAL SYMBOL QUARTER NOTE; QQCN +1D160 ; [*0E55.0020.0002.1D158][.0000.0000.0000.1D165][.0000.0000.0000.1D16E] # MUSICAL SYMBOL EIGHTH NOTE; QQCN +1D161 ; [*0E55.0020.0002.1D158][.0000.0000.0000.1D165][.0000.0000.0000.1D16F] # MUSICAL SYMBOL SIXTEENTH NOTE; QQCN +1D162 ; [*0E55.0020.0002.1D158][.0000.0000.0000.1D165][.0000.0000.0000.1D170] # MUSICAL SYMBOL THIRTY-SECOND NOTE; QQCN +1D163 ; [*0E55.0020.0002.1D158][.0000.0000.0000.1D165][.0000.0000.0000.1D171] # MUSICAL SYMBOL SIXTY-FOURTH NOTE; QQCN +1D164 ; [*0E55.0020.0002.1D158][.0000.0000.0000.1D165][.0000.0000.0000.1D172] # MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE; QQCN +1D165 ; [.0000.0000.0000.1D165] # MUSICAL SYMBOL COMBINING STEM +1D166 ; [.0000.0000.0000.1D166] # MUSICAL SYMBOL COMBINING SPRECHGESANG STEM +1D167 ; [.0000.0000.0000.1D167] # MUSICAL SYMBOL COMBINING TREMOLO-1 +1D168 ; [.0000.0000.0000.1D168] # MUSICAL SYMBOL COMBINING TREMOLO-2 +1D169 ; [.0000.0000.0000.1D169] # MUSICAL SYMBOL COMBINING TREMOLO-3 +1D16A ; [*0E5B.0020.0002.1D16A] # MUSICAL SYMBOL FINGERED TREMOLO-1 +1D16B ; [*0E5C.0020.0002.1D16B] # MUSICAL SYMBOL FINGERED TREMOLO-2 +1D16C ; [*0E5D.0020.0002.1D16C] # MUSICAL SYMBOL FINGERED TREMOLO-3 +1D16D ; [.0000.0000.0000.1D16D] # MUSICAL SYMBOL COMBINING AUGMENTATION DOT +1D16E ; [.0000.0000.0000.1D16E] # MUSICAL SYMBOL COMBINING FLAG-1 +1D16F ; [.0000.0000.0000.1D16F] # MUSICAL SYMBOL COMBINING FLAG-2 +1D170 ; [.0000.0000.0000.1D170] # MUSICAL SYMBOL COMBINING FLAG-3 +1D171 ; [.0000.0000.0000.1D171] # MUSICAL SYMBOL COMBINING FLAG-4 +1D172 ; [.0000.0000.0000.1D172] # MUSICAL SYMBOL COMBINING FLAG-5 +1D17B ; [.0000.0000.0000.1D17B] # MUSICAL SYMBOL COMBINING ACCENT +1D17C ; [.0000.0000.0000.1D17C] # MUSICAL SYMBOL COMBINING STACCATO +1D17D ; [.0000.0000.0000.1D17D] # MUSICAL SYMBOL COMBINING TENUTO +1D17E ; [.0000.0000.0000.1D17E] # MUSICAL SYMBOL COMBINING STACCATISSIMO +1D17F ; [.0000.0000.0000.1D17F] # MUSICAL SYMBOL COMBINING MARCATO +1D180 ; [.0000.0000.0000.1D180] # MUSICAL SYMBOL COMBINING MARCATO-STACCATO +1D181 ; [.0000.0000.0000.1D181] # MUSICAL SYMBOL COMBINING ACCENT-STACCATO +1D182 ; [.0000.0000.0000.1D182] # MUSICAL SYMBOL COMBINING LOURE +1D183 ; [*0E5E.0020.0002.1D183] # MUSICAL SYMBOL ARPEGGIATO UP +1D184 ; [*0E5F.0020.0002.1D184] # MUSICAL SYMBOL ARPEGGIATO DOWN +1D185 ; [.0000.0000.0000.1D185] # MUSICAL SYMBOL COMBINING DOIT +1D186 ; [.0000.0000.0000.1D186] # MUSICAL SYMBOL COMBINING RIP +1D187 ; [.0000.0000.0000.1D187] # MUSICAL SYMBOL COMBINING FLIP +1D188 ; [.0000.0000.0000.1D188] # MUSICAL SYMBOL COMBINING SMEAR +1D189 ; [.0000.0000.0000.1D189] # MUSICAL SYMBOL COMBINING BEND +1D18A ; [.0000.0000.0000.1D18A] # MUSICAL SYMBOL COMBINING DOUBLE TONGUE +1D18B ; [.0000.0000.0000.1D18B] # MUSICAL SYMBOL COMBINING TRIPLE TONGUE +1D18C ; [*0E60.0020.0002.1D18C] # MUSICAL SYMBOL RINFORZANDO +1D18D ; [*0E61.0020.0002.1D18D] # MUSICAL SYMBOL SUBITO +1D18E ; [*0E62.0020.0002.1D18E] # MUSICAL SYMBOL Z +1D18F ; [*0E63.0020.0002.1D18F] # MUSICAL SYMBOL PIANO +1D190 ; [*0E64.0020.0002.1D190] # MUSICAL SYMBOL MEZZO +1D191 ; [*0E65.0020.0002.1D191] # MUSICAL SYMBOL FORTE +1D192 ; [*0E66.0020.0002.1D192] # MUSICAL SYMBOL CRESCENDO +1D193 ; [*0E67.0020.0002.1D193] # MUSICAL SYMBOL DECRESCENDO +1D194 ; [*0E68.0020.0002.1D194] # MUSICAL SYMBOL GRACE NOTE SLASH +1D195 ; [*0E69.0020.0002.1D195] # MUSICAL SYMBOL GRACE NOTE NO SLASH +1D196 ; [*0E6A.0020.0002.1D196] # MUSICAL SYMBOL TR +1D197 ; [*0E6B.0020.0002.1D197] # MUSICAL SYMBOL TURN +1D198 ; [*0E6C.0020.0002.1D198] # MUSICAL SYMBOL INVERTED TURN +1D199 ; [*0E6D.0020.0002.1D199] # MUSICAL SYMBOL TURN SLASH +1D19A ; [*0E6E.0020.0002.1D19A] # MUSICAL SYMBOL TURN UP +1D19B ; [*0E6F.0020.0002.1D19B] # MUSICAL SYMBOL ORNAMENT STROKE-1 +1D19C ; [*0E70.0020.0002.1D19C] # MUSICAL SYMBOL ORNAMENT STROKE-2 +1D19D ; [*0E71.0020.0002.1D19D] # MUSICAL SYMBOL ORNAMENT STROKE-3 +1D19E ; [*0E72.0020.0002.1D19E] # MUSICAL SYMBOL ORNAMENT STROKE-4 +1D19F ; [*0E73.0020.0002.1D19F] # MUSICAL SYMBOL ORNAMENT STROKE-5 +1D1A0 ; [*0E74.0020.0002.1D1A0] # MUSICAL SYMBOL ORNAMENT STROKE-6 +1D1A1 ; [*0E75.0020.0002.1D1A1] # MUSICAL SYMBOL ORNAMENT STROKE-7 +1D1A2 ; [*0E76.0020.0002.1D1A2] # MUSICAL SYMBOL ORNAMENT STROKE-8 +1D1A3 ; [*0E77.0020.0002.1D1A3] # MUSICAL SYMBOL ORNAMENT STROKE-9 +1D1A4 ; [*0E78.0020.0002.1D1A4] # MUSICAL SYMBOL ORNAMENT STROKE-10 +1D1A5 ; [*0E79.0020.0002.1D1A5] # MUSICAL SYMBOL ORNAMENT STROKE-11 +1D1A6 ; [*0E7A.0020.0002.1D1A6] # MUSICAL SYMBOL HAUPTSTIMME +1D1A7 ; [*0E7B.0020.0002.1D1A7] # MUSICAL SYMBOL NEBENSTIMME +1D1A8 ; [*0E7C.0020.0002.1D1A8] # MUSICAL SYMBOL END OF STIMME +1D1A9 ; [*0E7D.0020.0002.1D1A9] # MUSICAL SYMBOL DEGREE SLASH +1D1AA ; [.0000.0000.0000.1D1AA] # MUSICAL SYMBOL COMBINING DOWN BOW +1D1AB ; [.0000.0000.0000.1D1AB] # MUSICAL SYMBOL COMBINING UP BOW +1D1AC ; [.0000.0000.0000.1D1AC] # MUSICAL SYMBOL COMBINING HARMONIC +1D1AD ; [.0000.0000.0000.1D1AD] # MUSICAL SYMBOL COMBINING SNAP PIZZICATO +1D1AE ; [*0E7E.0020.0002.1D1AE] # MUSICAL SYMBOL PEDAL MARK +1D1AF ; [*0E7F.0020.0002.1D1AF] # MUSICAL SYMBOL PEDAL UP MARK +1D1B0 ; [*0E80.0020.0002.1D1B0] # MUSICAL SYMBOL HALF PEDAL MARK +1D1B1 ; [*0E81.0020.0002.1D1B1] # MUSICAL SYMBOL GLISSANDO UP +1D1B2 ; [*0E82.0020.0002.1D1B2] # MUSICAL SYMBOL GLISSANDO DOWN +1D1B3 ; [*0E83.0020.0002.1D1B3] # MUSICAL SYMBOL WITH FINGERNAILS +1D1B4 ; [*0E84.0020.0002.1D1B4] # MUSICAL SYMBOL DAMP +1D1B5 ; [*0E85.0020.0002.1D1B5] # MUSICAL SYMBOL DAMP ALL +1D1B6 ; [*0E86.0020.0002.1D1B6] # MUSICAL SYMBOL MAXIMA +1D1B7 ; [*0E87.0020.0002.1D1B7] # MUSICAL SYMBOL LONGA +1D1B8 ; [*0E88.0020.0002.1D1B8] # MUSICAL SYMBOL BREVIS +1D1B9 ; [*0E89.0020.0002.1D1B9] # MUSICAL SYMBOL SEMIBREVIS WHITE +1D1BA ; [*0E8A.0020.0002.1D1BA] # MUSICAL SYMBOL SEMIBREVIS BLACK +1D1BB ; [*0E89.0020.0002.1D1B9][.0000.0000.0000.1D165] # MUSICAL SYMBOL MINIMA; QQCN +1D1BC ; [*0E8A.0020.0002.1D1BA][.0000.0000.0000.1D165] # MUSICAL SYMBOL MINIMA BLACK; QQCN +1D1BD ; [*0E89.0020.0002.1D1B9][.0000.0000.0000.1D165][.0000.0000.0000.1D16E] # MUSICAL SYMBOL SEMIMINIMA WHITE; QQCN +1D1BE ; [*0E8A.0020.0002.1D1BA][.0000.0000.0000.1D165][.0000.0000.0000.1D16E] # MUSICAL SYMBOL SEMIMINIMA BLACK; QQCN +1D1BF ; [*0E89.0020.0002.1D1B9][.0000.0000.0000.1D165][.0000.0000.0000.1D16F] # MUSICAL SYMBOL FUSA WHITE; QQCN +1D1C0 ; [*0E8A.0020.0002.1D1BA][.0000.0000.0000.1D165][.0000.0000.0000.1D16F] # MUSICAL SYMBOL FUSA BLACK; QQCN +1D1C1 ; [*0E8B.0020.0002.1D1C1] # MUSICAL SYMBOL LONGA PERFECTA REST +1D1C2 ; [*0E8C.0020.0002.1D1C2] # MUSICAL SYMBOL LONGA IMPERFECTA REST +1D1C3 ; [*0E8D.0020.0002.1D1C3] # MUSICAL SYMBOL BREVIS REST +1D1C4 ; [*0E8E.0020.0002.1D1C4] # MUSICAL SYMBOL SEMIBREVIS REST +1D1C5 ; [*0E8F.0020.0002.1D1C5] # MUSICAL SYMBOL MINIMA REST +1D1C6 ; [*0E90.0020.0002.1D1C6] # MUSICAL SYMBOL SEMIMINIMA REST +1D1C7 ; [*0E91.0020.0002.1D1C7] # MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA +1D1C8 ; [*0E92.0020.0002.1D1C8] # MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE IMPERFECTA +1D1C9 ; [*0E93.0020.0002.1D1C9] # MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA DIMINUTION-1 +1D1CA ; [*0E94.0020.0002.1D1CA] # MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE PERFECTA +1D1CB ; [*0E95.0020.0002.1D1CB] # MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA +1D1CC ; [*0E96.0020.0002.1D1CC] # MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-1 +1D1CD ; [*0E97.0020.0002.1D1CD] # MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-2 +1D1CE ; [*0E98.0020.0002.1D1CE] # MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-3 +1D1CF ; [*0E99.0020.0002.1D1CF] # MUSICAL SYMBOL CROIX +1D1D0 ; [*0E9A.0020.0002.1D1D0] # MUSICAL SYMBOL GREGORIAN C CLEF +1D1D1 ; [*0E9B.0020.0002.1D1D1] # MUSICAL SYMBOL GREGORIAN F CLEF +1D1D2 ; [*0E9C.0020.0002.1D1D2] # MUSICAL SYMBOL SQUARE B +1D1D3 ; [*0E9D.0020.0002.1D1D3] # MUSICAL SYMBOL VIRGA +1D1D4 ; [*0E9E.0020.0002.1D1D4] # MUSICAL SYMBOL PODATUS +1D1D5 ; [*0E9F.0020.0002.1D1D5] # MUSICAL SYMBOL CLIVIS +1D1D6 ; [*0EA0.0020.0002.1D1D6] # MUSICAL SYMBOL SCANDICUS +1D1D7 ; [*0EA1.0020.0002.1D1D7] # MUSICAL SYMBOL CLIMACUS +1D1D8 ; [*0EA2.0020.0002.1D1D8] # MUSICAL SYMBOL TORCULUS +1D1D9 ; [*0EA3.0020.0002.1D1D9] # MUSICAL SYMBOL PORRECTUS +1D1DA ; [*0EA4.0020.0002.1D1DA] # MUSICAL SYMBOL PORRECTUS FLEXUS +1D1DB ; [*0EA5.0020.0002.1D1DB] # MUSICAL SYMBOL SCANDICUS FLEXUS +1D1DC ; [*0EA6.0020.0002.1D1DC] # MUSICAL SYMBOL TORCULUS RESUPINUS +1D1DD ; [*0EA7.0020.0002.1D1DD] # MUSICAL SYMBOL PES SUBPUNCTIS +1D200 ; [*0EA8.0020.0002.1D200] # GREEK VOCAL NOTATION SYMBOL-1 +1D201 ; [*0EA9.0020.0002.1D201] # GREEK VOCAL NOTATION SYMBOL-2 +1D202 ; [*0EAA.0020.0002.1D202] # GREEK VOCAL NOTATION SYMBOL-3 +1D203 ; [*0EAB.0020.0002.1D203] # GREEK VOCAL NOTATION SYMBOL-4 +1D204 ; [*0EAC.0020.0002.1D204] # GREEK VOCAL NOTATION SYMBOL-5 +1D205 ; [*0EAD.0020.0002.1D205] # GREEK VOCAL NOTATION SYMBOL-6 +1D206 ; [*0EAE.0020.0002.1D206] # GREEK VOCAL NOTATION SYMBOL-7 +1D207 ; [*0EAF.0020.0002.1D207] # GREEK VOCAL NOTATION SYMBOL-8 +1D208 ; [*0EB0.0020.0002.1D208] # GREEK VOCAL NOTATION SYMBOL-9 +1D209 ; [*0EB1.0020.0002.1D209] # GREEK VOCAL NOTATION SYMBOL-10 +1D20A ; [*0EB2.0020.0002.1D20A] # GREEK VOCAL NOTATION SYMBOL-11 +1D20B ; [*0EB3.0020.0002.1D20B] # GREEK VOCAL NOTATION SYMBOL-12 +1D20C ; [*0EB4.0020.0002.1D20C] # GREEK VOCAL NOTATION SYMBOL-13 +1D20D ; [*0EB5.0020.0002.1D20D] # GREEK VOCAL NOTATION SYMBOL-14 +1D20E ; [*0EB6.0020.0002.1D20E] # GREEK VOCAL NOTATION SYMBOL-15 +1D20F ; [*0EB7.0020.0002.1D20F] # GREEK VOCAL NOTATION SYMBOL-16 +1D210 ; [*0EB8.0020.0002.1D210] # GREEK VOCAL NOTATION SYMBOL-17 +1D211 ; [*0EB9.0020.0002.1D211] # GREEK VOCAL NOTATION SYMBOL-18 +1D212 ; [*0EBA.0020.0002.1D212] # GREEK VOCAL NOTATION SYMBOL-19 +1D213 ; [*0EBB.0020.0002.1D213] # GREEK VOCAL NOTATION SYMBOL-20 +1D214 ; [*0EBC.0020.0002.1D214] # GREEK VOCAL NOTATION SYMBOL-21 +1D215 ; [*0EBD.0020.0002.1D215] # GREEK VOCAL NOTATION SYMBOL-22 +1D216 ; [*0EBE.0020.0002.1D216] # GREEK VOCAL NOTATION SYMBOL-23 +1D217 ; [*0EBF.0020.0002.1D217] # GREEK VOCAL NOTATION SYMBOL-24 +1D218 ; [*0EC0.0020.0002.1D218] # GREEK VOCAL NOTATION SYMBOL-50 +1D219 ; [*0EC1.0020.0002.1D219] # GREEK VOCAL NOTATION SYMBOL-51 +1D21A ; [*0EC2.0020.0002.1D21A] # GREEK VOCAL NOTATION SYMBOL-52 +1D21B ; [*0EC3.0020.0002.1D21B] # GREEK VOCAL NOTATION SYMBOL-53 +1D21C ; [*0EC4.0020.0002.1D21C] # GREEK VOCAL NOTATION SYMBOL-54 +1D21D ; [*0EC5.0020.0002.1D21D] # GREEK INSTRUMENTAL NOTATION SYMBOL-1 +1D21E ; [*0EC6.0020.0002.1D21E] # GREEK INSTRUMENTAL NOTATION SYMBOL-2 +1D21F ; [*0EC7.0020.0002.1D21F] # GREEK INSTRUMENTAL NOTATION SYMBOL-4 +1D220 ; [*0EC8.0020.0002.1D220] # GREEK INSTRUMENTAL NOTATION SYMBOL-5 +1D221 ; [*0EC9.0020.0002.1D221] # GREEK INSTRUMENTAL NOTATION SYMBOL-7 +1D222 ; [*0ECA.0020.0002.1D222] # GREEK INSTRUMENTAL NOTATION SYMBOL-8 +1D223 ; [*0ECB.0020.0002.1D223] # GREEK INSTRUMENTAL NOTATION SYMBOL-11 +1D224 ; [*0ECC.0020.0002.1D224] # GREEK INSTRUMENTAL NOTATION SYMBOL-12 +1D225 ; [*0ECD.0020.0002.1D225] # GREEK INSTRUMENTAL NOTATION SYMBOL-13 +1D226 ; [*0ECE.0020.0002.1D226] # GREEK INSTRUMENTAL NOTATION SYMBOL-14 +1D227 ; [*0ECF.0020.0002.1D227] # GREEK INSTRUMENTAL NOTATION SYMBOL-17 +1D228 ; [*0ED0.0020.0002.1D228] # GREEK INSTRUMENTAL NOTATION SYMBOL-18 +1D229 ; [*0ED1.0020.0002.1D229] # GREEK INSTRUMENTAL NOTATION SYMBOL-19 +1D22A ; [*0ED2.0020.0002.1D22A] # GREEK INSTRUMENTAL NOTATION SYMBOL-23 +1D22B ; [*0ED3.0020.0002.1D22B] # GREEK INSTRUMENTAL NOTATION SYMBOL-24 +1D22C ; [*0ED4.0020.0002.1D22C] # GREEK INSTRUMENTAL NOTATION SYMBOL-25 +1D22D ; [*0ED5.0020.0002.1D22D] # GREEK INSTRUMENTAL NOTATION SYMBOL-26 +1D22E ; [*0ED6.0020.0002.1D22E] # GREEK INSTRUMENTAL NOTATION SYMBOL-27 +1D22F ; [*0ED7.0020.0002.1D22F] # GREEK INSTRUMENTAL NOTATION SYMBOL-29 +1D230 ; [*0ED8.0020.0002.1D230] # GREEK INSTRUMENTAL NOTATION SYMBOL-30 +1D231 ; [*0ED9.0020.0002.1D231] # GREEK INSTRUMENTAL NOTATION SYMBOL-32 +1D232 ; [*0EDA.0020.0002.1D232] # GREEK INSTRUMENTAL NOTATION SYMBOL-36 +1D233 ; [*0EDB.0020.0002.1D233] # GREEK INSTRUMENTAL NOTATION SYMBOL-37 +1D234 ; [*0EDC.0020.0002.1D234] # GREEK INSTRUMENTAL NOTATION SYMBOL-38 +1D235 ; [*0EDD.0020.0002.1D235] # GREEK INSTRUMENTAL NOTATION SYMBOL-39 +1D236 ; [*0EDE.0020.0002.1D236] # GREEK INSTRUMENTAL NOTATION SYMBOL-40 +1D237 ; [*0EDF.0020.0002.1D237] # GREEK INSTRUMENTAL NOTATION SYMBOL-42 +1D238 ; [*0EE0.0020.0002.1D238] # GREEK INSTRUMENTAL NOTATION SYMBOL-43 +1D239 ; [*0EE1.0020.0002.1D239] # GREEK INSTRUMENTAL NOTATION SYMBOL-45 +1D23A ; [*0EE2.0020.0002.1D23A] # GREEK INSTRUMENTAL NOTATION SYMBOL-47 +1D23B ; [*0EE3.0020.0002.1D23B] # GREEK INSTRUMENTAL NOTATION SYMBOL-48 +1D23C ; [*0EE4.0020.0002.1D23C] # GREEK INSTRUMENTAL NOTATION SYMBOL-49 +1D23D ; [*0EE5.0020.0002.1D23D] # GREEK INSTRUMENTAL NOTATION SYMBOL-50 +1D23E ; [*0EE6.0020.0002.1D23E] # GREEK INSTRUMENTAL NOTATION SYMBOL-51 +1D23F ; [*0EE7.0020.0002.1D23F] # GREEK INSTRUMENTAL NOTATION SYMBOL-52 +1D240 ; [*0EE8.0020.0002.1D240] # GREEK INSTRUMENTAL NOTATION SYMBOL-53 +1D241 ; [*0EE9.0020.0002.1D241] # GREEK INSTRUMENTAL NOTATION SYMBOL-54 +1D242 ; [.0000.0000.0000.1D242] # COMBINING GREEK MUSICAL TRISEME +1D243 ; [.0000.0000.0000.1D243] # COMBINING GREEK MUSICAL TETRASEME +1D244 ; [.0000.0000.0000.1D244] # COMBINING GREEK MUSICAL PENTASEME +1D245 ; [*0EEA.0020.0002.1D245] # GREEK MUSICAL LEIMMA +1D300 ; [*0C5F.0020.0002.1D300] # MONOGRAM FOR EARTH +1D301 ; [*0C60.0020.0002.1D301] # DIGRAM FOR HEAVENLY EARTH +1D302 ; [*0C61.0020.0002.1D302] # DIGRAM FOR HUMAN EARTH +1D303 ; [*0C62.0020.0002.1D303] # DIGRAM FOR EARTHLY HEAVEN +1D304 ; [*0C63.0020.0002.1D304] # DIGRAM FOR EARTHLY HUMAN +1D305 ; [*0C64.0020.0002.1D305] # DIGRAM FOR EARTH +1D306 ; [*0C65.0020.0002.1D306] # TETRAGRAM FOR CENTRE +1D307 ; [*0C66.0020.0002.1D307] # TETRAGRAM FOR FULL CIRCLE +1D308 ; [*0C67.0020.0002.1D308] # TETRAGRAM FOR MIRED +1D309 ; [*0C68.0020.0002.1D309] # TETRAGRAM FOR BARRIER +1D30A ; [*0C69.0020.0002.1D30A] # TETRAGRAM FOR KEEPING SMALL +1D30B ; [*0C6A.0020.0002.1D30B] # TETRAGRAM FOR CONTRARIETY +1D30C ; [*0C6B.0020.0002.1D30C] # TETRAGRAM FOR ASCENT +1D30D ; [*0C6C.0020.0002.1D30D] # TETRAGRAM FOR OPPOSITION +1D30E ; [*0C6D.0020.0002.1D30E] # TETRAGRAM FOR BRANCHING OUT +1D30F ; [*0C6E.0020.0002.1D30F] # TETRAGRAM FOR DEFECTIVENESS OR DISTORTION +1D310 ; [*0C6F.0020.0002.1D310] # TETRAGRAM FOR DIVERGENCE +1D311 ; [*0C70.0020.0002.1D311] # TETRAGRAM FOR YOUTHFULNESS +1D312 ; [*0C71.0020.0002.1D312] # TETRAGRAM FOR INCREASE +1D313 ; [*0C72.0020.0002.1D313] # TETRAGRAM FOR PENETRATION +1D314 ; [*0C73.0020.0002.1D314] # TETRAGRAM FOR REACH +1D315 ; [*0C74.0020.0002.1D315] # TETRAGRAM FOR CONTACT +1D316 ; [*0C75.0020.0002.1D316] # TETRAGRAM FOR HOLDING BACK +1D317 ; [*0C76.0020.0002.1D317] # TETRAGRAM FOR WAITING +1D318 ; [*0C77.0020.0002.1D318] # TETRAGRAM FOR FOLLOWING +1D319 ; [*0C78.0020.0002.1D319] # TETRAGRAM FOR ADVANCE +1D31A ; [*0C79.0020.0002.1D31A] # TETRAGRAM FOR RELEASE +1D31B ; [*0C7A.0020.0002.1D31B] # TETRAGRAM FOR RESISTANCE +1D31C ; [*0C7B.0020.0002.1D31C] # TETRAGRAM FOR EASE +1D31D ; [*0C7C.0020.0002.1D31D] # TETRAGRAM FOR JOY +1D31E ; [*0C7D.0020.0002.1D31E] # TETRAGRAM FOR CONTENTION +1D31F ; [*0C7E.0020.0002.1D31F] # TETRAGRAM FOR ENDEAVOUR +1D320 ; [*0C7F.0020.0002.1D320] # TETRAGRAM FOR DUTIES +1D321 ; [*0C80.0020.0002.1D321] # TETRAGRAM FOR CHANGE +1D322 ; [*0C81.0020.0002.1D322] # TETRAGRAM FOR DECISIVENESS +1D323 ; [*0C82.0020.0002.1D323] # TETRAGRAM FOR BOLD RESOLUTION +1D324 ; [*0C83.0020.0002.1D324] # TETRAGRAM FOR PACKING +1D325 ; [*0C84.0020.0002.1D325] # TETRAGRAM FOR LEGION +1D326 ; [*0C85.0020.0002.1D326] # TETRAGRAM FOR CLOSENESS +1D327 ; [*0C86.0020.0002.1D327] # TETRAGRAM FOR KINSHIP +1D328 ; [*0C87.0020.0002.1D328] # TETRAGRAM FOR GATHERING +1D329 ; [*0C88.0020.0002.1D329] # TETRAGRAM FOR STRENGTH +1D32A ; [*0C89.0020.0002.1D32A] # TETRAGRAM FOR PURITY +1D32B ; [*0C8A.0020.0002.1D32B] # TETRAGRAM FOR FULLNESS +1D32C ; [*0C8B.0020.0002.1D32C] # TETRAGRAM FOR RESIDENCE +1D32D ; [*0C8C.0020.0002.1D32D] # TETRAGRAM FOR LAW OR MODEL +1D32E ; [*0C8D.0020.0002.1D32E] # TETRAGRAM FOR RESPONSE +1D32F ; [*0C8E.0020.0002.1D32F] # TETRAGRAM FOR GOING TO MEET +1D330 ; [*0C8F.0020.0002.1D330] # TETRAGRAM FOR ENCOUNTERS +1D331 ; [*0C90.0020.0002.1D331] # TETRAGRAM FOR STOVE +1D332 ; [*0C91.0020.0002.1D332] # TETRAGRAM FOR GREATNESS +1D333 ; [*0C92.0020.0002.1D333] # TETRAGRAM FOR ENLARGEMENT +1D334 ; [*0C93.0020.0002.1D334] # TETRAGRAM FOR PATTERN +1D335 ; [*0C94.0020.0002.1D335] # TETRAGRAM FOR RITUAL +1D336 ; [*0C95.0020.0002.1D336] # TETRAGRAM FOR FLIGHT +1D337 ; [*0C96.0020.0002.1D337] # TETRAGRAM FOR VASTNESS OR WASTING +1D338 ; [*0C97.0020.0002.1D338] # TETRAGRAM FOR CONSTANCY +1D339 ; [*0C98.0020.0002.1D339] # TETRAGRAM FOR MEASURE +1D33A ; [*0C99.0020.0002.1D33A] # TETRAGRAM FOR ETERNITY +1D33B ; [*0C9A.0020.0002.1D33B] # TETRAGRAM FOR UNITY +1D33C ; [*0C9B.0020.0002.1D33C] # TETRAGRAM FOR DIMINISHMENT +1D33D ; [*0C9C.0020.0002.1D33D] # TETRAGRAM FOR CLOSED MOUTH +1D33E ; [*0C9D.0020.0002.1D33E] # TETRAGRAM FOR GUARDEDNESS +1D33F ; [*0C9E.0020.0002.1D33F] # TETRAGRAM FOR GATHERING IN +1D340 ; [*0C9F.0020.0002.1D340] # TETRAGRAM FOR MASSING +1D341 ; [*0CA0.0020.0002.1D341] # TETRAGRAM FOR ACCUMULATION +1D342 ; [*0CA1.0020.0002.1D342] # TETRAGRAM FOR EMBELLISHMENT +1D343 ; [*0CA2.0020.0002.1D343] # TETRAGRAM FOR DOUBT +1D344 ; [*0CA3.0020.0002.1D344] # TETRAGRAM FOR WATCH +1D345 ; [*0CA4.0020.0002.1D345] # TETRAGRAM FOR SINKING +1D346 ; [*0CA5.0020.0002.1D346] # TETRAGRAM FOR INNER +1D347 ; [*0CA6.0020.0002.1D347] # TETRAGRAM FOR DEPARTURE +1D348 ; [*0CA7.0020.0002.1D348] # TETRAGRAM FOR DARKENING +1D349 ; [*0CA8.0020.0002.1D349] # TETRAGRAM FOR DIMMING +1D34A ; [*0CA9.0020.0002.1D34A] # TETRAGRAM FOR EXHAUSTION +1D34B ; [*0CAA.0020.0002.1D34B] # TETRAGRAM FOR SEVERANCE +1D34C ; [*0CAB.0020.0002.1D34C] # TETRAGRAM FOR STOPPAGE +1D34D ; [*0CAC.0020.0002.1D34D] # TETRAGRAM FOR HARDNESS +1D34E ; [*0CAD.0020.0002.1D34E] # TETRAGRAM FOR COMPLETION +1D34F ; [*0CAE.0020.0002.1D34F] # TETRAGRAM FOR CLOSURE +1D350 ; [*0CAF.0020.0002.1D350] # TETRAGRAM FOR FAILURE +1D351 ; [*0CB0.0020.0002.1D351] # TETRAGRAM FOR AGGRAVATION +1D352 ; [*0CB1.0020.0002.1D352] # TETRAGRAM FOR COMPLIANCE +1D353 ; [*0CB2.0020.0002.1D353] # TETRAGRAM FOR ON THE VERGE +1D354 ; [*0CB3.0020.0002.1D354] # TETRAGRAM FOR DIFFICULTIES +1D355 ; [*0CB4.0020.0002.1D355] # TETRAGRAM FOR LABOURING +1D356 ; [*0CB5.0020.0002.1D356] # TETRAGRAM FOR FOSTERING +1D369 ; [*0F90.0020.0002.1D369] # COUNTING ROD TENS DIGIT ONE +1D36A ; [*0F91.0020.0002.1D36A] # COUNTING ROD TENS DIGIT TWO +1D36B ; [*0F92.0020.0002.1D36B] # COUNTING ROD TENS DIGIT THREE +1D36C ; [*0F93.0020.0002.1D36C] # COUNTING ROD TENS DIGIT FOUR +1D36D ; [*0F94.0020.0002.1D36D] # COUNTING ROD TENS DIGIT FIVE +1D36E ; [*0F95.0020.0002.1D36E] # COUNTING ROD TENS DIGIT SIX +1D36F ; [*0F96.0020.0002.1D36F] # COUNTING ROD TENS DIGIT SEVEN +1D370 ; [*0F97.0020.0002.1D370] # COUNTING ROD TENS DIGIT EIGHT +1D371 ; [*0F98.0020.0002.1D371] # COUNTING ROD TENS DIGIT NINE +1D6C1 ; [*04AE.0020.0005.1D6C1] # MATHEMATICAL BOLD NABLA; QQK +1D6DB ; [*04AA.0020.0005.1D6DB] # MATHEMATICAL BOLD PARTIAL DIFFERENTIAL; QQK +1D6FB ; [*04AE.0020.0005.1D6FB] # MATHEMATICAL ITALIC NABLA; QQK +1D715 ; [*04AA.0020.0005.1D715] # MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL; QQK +1D735 ; [*04AE.0020.0005.1D735] # MATHEMATICAL BOLD ITALIC NABLA; QQK +1D74F ; [*04AA.0020.0005.1D74F] # MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL; QQK +1D76F ; [*04AE.0020.0005.1D76F] # MATHEMATICAL SANS-SERIF BOLD NABLA; QQK +1D789 ; [*04AA.0020.0005.1D789] # MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL; QQK +1D7A9 ; [*04AE.0020.0005.1D7A9] # MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA; QQK +1D7C3 ; [*04AA.0020.0005.1D7C3] # MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL; QQK +0332 ; [.0000.0021.0002.0332] # COMBINING LOW LINE +0313 ; [.0000.0022.0002.0313] # COMBINING COMMA ABOVE +0343 ; [.0000.0022.0002.0343] # COMBINING GREEK KORONIS; QQC +0314 ; [.0000.002A.0002.0314] # COMBINING REVERSED COMMA ABOVE +0301 ; [.0000.0032.0002.0301] # COMBINING ACUTE ACCENT +0341 ; [.0000.0032.0002.0341] # COMBINING ACUTE TONE MARK; QQC +0300 ; [.0000.0035.0002.0300] # COMBINING GRAVE ACCENT +0340 ; [.0000.0035.0002.0340] # COMBINING GRAVE TONE MARK; QQC +0306 ; [.0000.0037.0002.0306] # COMBINING BREVE +0302 ; [.0000.003C.0002.0302] # COMBINING CIRCUMFLEX ACCENT +030C ; [.0000.0041.0002.030C] # COMBINING CARON +030A ; [.0000.0043.0002.030A] # COMBINING RING ABOVE +0342 ; [.0000.0045.0002.0342] # COMBINING GREEK PERISPOMENI +0308 ; [.0000.0047.0002.0308] # COMBINING DIAERESIS +0344 ; [.0000.0047.0002.0308][.0000.0032.0002.0301] # COMBINING GREEK DIALYTIKA TONOS; QQCM +030B ; [.0000.004D.0002.030B] # COMBINING DOUBLE ACUTE ACCENT +0303 ; [.0000.004E.0002.0303] # COMBINING TILDE +0307 ; [.0000.0052.0002.0307] # COMBINING DOT ABOVE +0338 ; [.0000.0054.0002.0338] # COMBINING LONG SOLIDUS OVERLAY +0327 ; [.0000.0056.0002.0327] # COMBINING CEDILLA +0328 ; [.0000.0059.0002.0328] # COMBINING OGONEK +0304 ; [.0000.005B.0002.0304] # COMBINING MACRON +0305 ; [.0000.005F.0002.0305] # COMBINING OVERLINE +0309 ; [.0000.0060.0002.0309] # COMBINING HOOK ABOVE +030D ; [.0000.0061.0002.030D] # COMBINING VERTICAL LINE ABOVE +030E ; [.0000.0062.0002.030E] # COMBINING DOUBLE VERTICAL LINE ABOVE +030F ; [.0000.0063.0002.030F] # COMBINING DOUBLE GRAVE ACCENT +0310 ; [.0000.0064.0002.0310] # COMBINING CANDRABINDU +0311 ; [.0000.0065.0002.0311] # COMBINING INVERTED BREVE +0312 ; [.0000.0066.0002.0312] # COMBINING TURNED COMMA ABOVE +0315 ; [.0000.0067.0002.0315] # COMBINING COMMA ABOVE RIGHT +0316 ; [.0000.0068.0002.0316] # COMBINING GRAVE ACCENT BELOW +0317 ; [.0000.0069.0002.0317] # COMBINING ACUTE ACCENT BELOW +0318 ; [.0000.006A.0002.0318] # COMBINING LEFT TACK BELOW +0319 ; [.0000.006B.0002.0319] # COMBINING RIGHT TACK BELOW +031A ; [.0000.006C.0002.031A] # COMBINING LEFT ANGLE ABOVE +031B ; [.0000.006D.0002.031B] # COMBINING HORN +031C ; [.0000.0073.0002.031C] # COMBINING LEFT HALF RING BELOW +031D ; [.0000.0074.0002.031D] # COMBINING UP TACK BELOW +031E ; [.0000.0075.0002.031E] # COMBINING DOWN TACK BELOW +031F ; [.0000.0076.0002.031F] # COMBINING PLUS SIGN BELOW +0320 ; [.0000.0077.0002.0320] # COMBINING MINUS SIGN BELOW +0321 ; [.0000.0078.0002.0321] # COMBINING PALATALIZED HOOK BELOW +0322 ; [.0000.0079.0002.0322] # COMBINING RETROFLEX HOOK BELOW +0323 ; [.0000.007A.0002.0323] # COMBINING DOT BELOW +0324 ; [.0000.007F.0002.0324] # COMBINING DIAERESIS BELOW +0325 ; [.0000.0080.0002.0325] # COMBINING RING BELOW +0326 ; [.0000.0081.0002.0326] # COMBINING COMMA BELOW +0329 ; [.0000.0082.0002.0329] # COMBINING VERTICAL LINE BELOW +032A ; [.0000.0083.0002.032A] # COMBINING BRIDGE BELOW +032B ; [.0000.0084.0002.032B] # COMBINING INVERTED DOUBLE ARCH BELOW +032C ; [.0000.0085.0002.032C] # COMBINING CARON BELOW +032D ; [.0000.0086.0002.032D] # COMBINING CIRCUMFLEX ACCENT BELOW +032E ; [.0000.0087.0002.032E] # COMBINING BREVE BELOW +032F ; [.0000.0088.0002.032F] # COMBINING INVERTED BREVE BELOW +0330 ; [.0000.0089.0002.0330] # COMBINING TILDE BELOW +0331 ; [.0000.008A.0002.0331] # COMBINING MACRON BELOW +0333 ; [.0000.008B.0002.0333] # COMBINING DOUBLE LOW LINE +0334 ; [.0000.008C.0002.0334] # COMBINING TILDE OVERLAY +0335 ; [.0000.008D.0002.0335] # COMBINING SHORT STROKE OVERLAY +0336 ; [.0000.008E.0002.0336] # COMBINING LONG STROKE OVERLAY +0337 ; [.0000.008F.0002.0337] # COMBINING SHORT SOLIDUS OVERLAY +0339 ; [.0000.0090.0002.0339] # COMBINING RIGHT HALF RING BELOW +033A ; [.0000.0091.0002.033A] # COMBINING INVERTED BRIDGE BELOW +033B ; [.0000.0092.0002.033B] # COMBINING SQUARE BELOW +033C ; [.0000.0093.0002.033C] # COMBINING SEAGULL BELOW +033D ; [.0000.0094.0002.033D] # COMBINING X ABOVE +033E ; [.0000.0095.0002.033E] # COMBINING VERTICAL TILDE +033F ; [.0000.0096.0002.033F] # COMBINING DOUBLE OVERLINE +0345 ; [.0000.0097.0002.0345] # COMBINING GREEK YPOGEGRAMMENI +0346 ; [.0000.0098.0002.0346] # COMBINING BRIDGE ABOVE +0347 ; [.0000.0099.0002.0347] # COMBINING EQUALS SIGN BELOW +0348 ; [.0000.009A.0002.0348] # COMBINING DOUBLE VERTICAL LINE BELOW +0349 ; [.0000.009B.0002.0349] # COMBINING LEFT ANGLE BELOW +034A ; [.0000.009C.0002.034A] # COMBINING NOT TILDE ABOVE +034B ; [.0000.009D.0002.034B] # COMBINING HOMOTHETIC ABOVE +034C ; [.0000.009E.0002.034C] # COMBINING ALMOST EQUAL TO ABOVE +034D ; [.0000.009F.0002.034D] # COMBINING LEFT RIGHT ARROW BELOW +034E ; [.0000.00A0.0002.034E] # COMBINING UPWARDS ARROW BELOW +0350 ; [.0000.00A1.0002.0350] # COMBINING RIGHT ARROWHEAD ABOVE +0351 ; [.0000.00A2.0002.0351] # COMBINING LEFT HALF RING ABOVE +0352 ; [.0000.00A3.0002.0352] # COMBINING FERMATA +0353 ; [.0000.00A4.0002.0353] # COMBINING X BELOW +0354 ; [.0000.00A5.0002.0354] # COMBINING LEFT ARROWHEAD BELOW +0355 ; [.0000.00A6.0002.0355] # COMBINING RIGHT ARROWHEAD BELOW +0356 ; [.0000.00A7.0002.0356] # COMBINING RIGHT ARROWHEAD AND UP ARROWHEAD BELOW +0357 ; [.0000.00A8.0002.0357] # COMBINING RIGHT HALF RING ABOVE +0358 ; [.0000.00A9.0002.0358] # COMBINING DOT ABOVE RIGHT +0359 ; [.0000.00AA.0002.0359] # COMBINING ASTERISK BELOW +035A ; [.0000.00AB.0002.035A] # COMBINING DOUBLE RING BELOW +035B ; [.0000.00AC.0002.035B] # COMBINING ZIGZAG ABOVE +035C ; [.0000.00AD.0002.035C] # COMBINING DOUBLE BREVE BELOW +035D ; [.0000.00AE.0002.035D] # COMBINING DOUBLE BREVE +035E ; [.0000.00AF.0002.035E] # COMBINING DOUBLE MACRON +035F ; [.0000.00B0.0002.035F] # COMBINING DOUBLE MACRON BELOW +0360 ; [.0000.00B1.0002.0360] # COMBINING DOUBLE TILDE +FE22 ; [.0000.00B1.0002.FE22] # COMBINING DOUBLE TILDE LEFT HALF; QQC +0361 ; [.0000.00B2.0002.0361] # COMBINING DOUBLE INVERTED BREVE +FE20 ; [.0000.00B2.0002.FE20] # COMBINING LIGATURE LEFT HALF; QQC +0362 ; [.0000.00B3.0002.0362] # COMBINING DOUBLE RIGHTWARDS ARROW BELOW +1DC0 ; [.0000.00B4.0002.1DC0] # COMBINING DOTTED GRAVE ACCENT +1DC1 ; [.0000.00B5.0002.1DC1] # COMBINING DOTTED ACUTE ACCENT +1DC2 ; [.0000.00B6.0002.1DC2] # COMBINING SNAKE BELOW +1DC3 ; [.0000.00B7.0002.1DC3] # COMBINING SUSPENSION MARK +1DC4 ; [.0000.00B8.0002.1DC4] # COMBINING MACRON-ACUTE +1DC5 ; [.0000.00B9.0002.1DC5] # COMBINING GRAVE-MACRON +1DC6 ; [.0000.00BA.0002.1DC6] # COMBINING MACRON-GRAVE +1DC7 ; [.0000.00BB.0002.1DC7] # COMBINING ACUTE-MACRON +1DC8 ; [.0000.00BC.0002.1DC8] # COMBINING GRAVE-ACUTE-GRAVE +1DC9 ; [.0000.00BD.0002.1DC9] # COMBINING ACUTE-GRAVE-ACUTE +1DCA ; [.0000.00BE.0002.1DCA] # COMBINING LATIN SMALL LETTER R BELOW +1DFE ; [.0000.00BF.0002.1DFE] # COMBINING LEFT ARROWHEAD ABOVE +1DFF ; [.0000.00C0.0002.1DFF] # COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW +0483 ; [.0000.00C1.0002.0483] # COMBINING CYRILLIC TITLO +0484 ; [.0000.00C2.0002.0484] # COMBINING CYRILLIC PALATALIZATION +0485 ; [.0000.00C3.0002.0485] # COMBINING CYRILLIC DASIA PNEUMATA +0486 ; [.0000.00C4.0002.0486] # COMBINING CYRILLIC PSILI PNEUMATA +05B0 ; [.0000.00C5.0002.05B0] # HEBREW POINT SHEVA +05B1 ; [.0000.00C6.0002.05B1] # HEBREW POINT HATAF SEGOL +05B2 ; [.0000.00C7.0002.05B2] # HEBREW POINT HATAF PATAH +05B3 ; [.0000.00C8.0002.05B3] # HEBREW POINT HATAF QAMATS +05B4 ; [.0000.00C9.0002.05B4] # HEBREW POINT HIRIQ +05B5 ; [.0000.00CA.0002.05B5] # HEBREW POINT TSERE +05B6 ; [.0000.00CB.0002.05B6] # HEBREW POINT SEGOL +05B7 ; [.0000.00CC.0002.05B7] # HEBREW POINT PATAH +05B8 ; [.0000.00CD.0002.05B8] # HEBREW POINT QAMATS +05C7 ; [.0000.00CE.0002.05C7] # HEBREW POINT QAMATS QATAN +05B9 ; [.0000.00CF.0002.05B9] # HEBREW POINT HOLAM +05BA ; [.0000.00D0.0002.05BA] # HEBREW POINT HOLAM HASER FOR VAV +05BB ; [.0000.00D1.0002.05BB] # HEBREW POINT QUBUTS +05C2 ; [.0000.00D2.0002.05C2] # HEBREW POINT SIN DOT +05C1 ; [.0000.00D3.0002.05C1] # HEBREW POINT SHIN DOT +05BC ; [.0000.00D4.0002.05BC] # HEBREW POINT DAGESH OR MAPIQ +05BF ; [.0000.00D7.0002.05BF] # HEBREW POINT RAFE +FB1E ; [.0000.00D8.0002.FB1E] # HEBREW POINT JUDEO-SPANISH VARIKA +064B ; [.0000.00D9.0002.064B] # ARABIC FATHATAN +FE71 ; [.0000.00D9.0018.FE71] # ARABIC TATWEEL WITH FATHATAN ABOVE; QQK +FE70 ; [.0000.00D9.001A.FE70] # ARABIC FATHATAN ISOLATED FORM; QQK +064C ; [.0000.00DA.0002.064C] # ARABIC DAMMATAN +FE72 ; [.0000.00DA.001A.FE72] # ARABIC DAMMATAN ISOLATED FORM; QQK +064D ; [.0000.00DC.0002.064D] # ARABIC KASRATAN +FE74 ; [.0000.00DC.001A.FE74] # ARABIC KASRATAN ISOLATED FORM; QQK +064E ; [.0000.00DE.0002.064E] # ARABIC FATHA +FE77 ; [.0000.00DE.0018.FE77] # ARABIC FATHA MEDIAL FORM; QQK +FE76 ; [.0000.00DE.001A.FE76] # ARABIC FATHA ISOLATED FORM; QQK +064F ; [.0000.00E0.0002.064F] # ARABIC DAMMA +FE79 ; [.0000.00E0.0018.FE79] # ARABIC DAMMA MEDIAL FORM; QQK +FE78 ; [.0000.00E0.001A.FE78] # ARABIC DAMMA ISOLATED FORM; QQK +0650 ; [.0000.00E2.0002.0650] # ARABIC KASRA +FE7B ; [.0000.00E2.0018.FE7B] # ARABIC KASRA MEDIAL FORM; QQK +FE7A ; [.0000.00E2.001A.FE7A] # ARABIC KASRA ISOLATED FORM; QQK +0651 ; [.0000.00E4.0002.0651] # ARABIC SHADDA +FCF2 ; [.0000.00E4.0018.FCF2] # ARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORM; QQKM +FCF3 ; [.0000.00E4.0018.FCF3] # ARABIC LIGATURE SHADDA WITH DAMMA MEDIAL FORM; QQKM +FCF4 ; [.0000.00E4.0018.FCF4] # ARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORM; QQKM +FE7D ; [.0000.00E4.0018.FE7D] # ARABIC SHADDA MEDIAL FORM; QQK +FC5E ; [.0000.00E4.001A.FC5E] # ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM; QQKM +FC5F ; [.0000.00E4.001A.FC5F] # ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM; QQKM +FC60 ; [.0000.00E4.001A.FC60] # ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM; QQKM +FC61 ; [.0000.00E4.001A.FC61] # ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM; QQKM +FC62 ; [.0000.00E4.001A.FC62] # ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM; QQKM +FE7C ; [.0000.00E4.001A.FE7C] # ARABIC SHADDA ISOLATED FORM; QQK +FC63 ; [.0000.00E4.001A.FC63][.0000.00F3.001A.FC63] # ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM; QQKN +0652 ; [.0000.00E6.0002.0652] # ARABIC SUKUN +FE7F ; [.0000.00E6.0018.FE7F] # ARABIC SUKUN MEDIAL FORM; QQK +FE7E ; [.0000.00E6.001A.FE7E] # ARABIC SUKUN ISOLATED FORM; QQK +0653 ; [.0000.00E7.0002.0653] # ARABIC MADDAH ABOVE +0654 ; [.0000.00E8.0002.0654] # ARABIC HAMZA ABOVE +0655 ; [.0000.00E9.0002.0655] # ARABIC HAMZA BELOW +0656 ; [.0000.00EA.0002.0656] # ARABIC SUBSCRIPT ALEF +0657 ; [.0000.00EB.0002.0657] # ARABIC INVERTED DAMMA +0658 ; [.0000.00EC.0002.0658] # ARABIC MARK NOON GHUNNA +0659 ; [.0000.00ED.0002.0659] # ARABIC ZWARAKAY +065A ; [.0000.00EE.0002.065A] # ARABIC VOWEL SIGN SMALL V ABOVE +065B ; [.0000.00EF.0002.065B] # ARABIC VOWEL SIGN INVERTED SMALL V ABOVE +065C ; [.0000.00F0.0002.065C] # ARABIC VOWEL SIGN DOT BELOW +065D ; [.0000.00F1.0002.065D] # ARABIC REVERSED DAMMA +065E ; [.0000.00F2.0002.065E] # ARABIC FATHA WITH TWO DOTS +0670 ; [.0000.00F3.0002.0670] # ARABIC LETTER SUPERSCRIPT ALEF +0711 ; [.0000.00F4.0002.0711] # SYRIAC LETTER SUPERSCRIPT ALAPH +0730 ; [.0000.00F5.0002.0730] # SYRIAC PTHAHA ABOVE +0731 ; [.0000.00F6.0002.0731] # SYRIAC PTHAHA BELOW +0732 ; [.0000.00F7.0002.0732] # SYRIAC PTHAHA DOTTED +0733 ; [.0000.00F8.0002.0733] # SYRIAC ZQAPHA ABOVE +0734 ; [.0000.00F9.0002.0734] # SYRIAC ZQAPHA BELOW +0735 ; [.0000.00FA.0002.0735] # SYRIAC ZQAPHA DOTTED +0736 ; [.0000.00FB.0002.0736] # SYRIAC RBASA ABOVE +0737 ; [.0000.00FC.0002.0737] # SYRIAC RBASA BELOW +0738 ; [.0000.00FD.0002.0738] # SYRIAC DOTTED ZLAMA HORIZONTAL +0739 ; [.0000.00FE.0002.0739] # SYRIAC DOTTED ZLAMA ANGULAR +073A ; [.0000.00FF.0002.073A] # SYRIAC HBASA ABOVE +073B ; [.0000.0100.0002.073B] # SYRIAC HBASA BELOW +073C ; [.0000.0101.0002.073C] # SYRIAC HBASA-ESASA DOTTED +073D ; [.0000.0102.0002.073D] # SYRIAC ESASA ABOVE +073E ; [.0000.0103.0002.073E] # SYRIAC ESASA BELOW +073F ; [.0000.0104.0002.073F] # SYRIAC RWAHA +0740 ; [.0000.0105.0002.0740] # SYRIAC FEMININE DOT +0741 ; [.0000.0106.0002.0741] # SYRIAC QUSHSHAYA +0742 ; [.0000.0107.0002.0742] # SYRIAC RUKKAKHA +0743 ; [.0000.0108.0002.0743] # SYRIAC TWO VERTICAL DOTS ABOVE +0744 ; [.0000.0109.0002.0744] # SYRIAC TWO VERTICAL DOTS BELOW +0745 ; [.0000.010A.0002.0745] # SYRIAC THREE DOTS ABOVE +0746 ; [.0000.010B.0002.0746] # SYRIAC THREE DOTS BELOW +0747 ; [.0000.010C.0002.0747] # SYRIAC OBLIQUE LINE ABOVE +0748 ; [.0000.010D.0002.0748] # SYRIAC OBLIQUE LINE BELOW +0749 ; [.0000.010E.0002.0749] # SYRIAC MUSIC +074A ; [.0000.010F.0002.074A] # SYRIAC BARREKH +07EB ; [.0000.0110.0002.07EB] # NKO COMBINING SHORT HIGH TONE +07EC ; [.0000.0111.0002.07EC] # NKO COMBINING SHORT LOW TONE +07ED ; [.0000.0112.0002.07ED] # NKO COMBINING SHORT RISING TONE +07EE ; [.0000.0113.0002.07EE] # NKO COMBINING LONG DESCENDING TONE +07EF ; [.0000.0114.0002.07EF] # NKO COMBINING LONG HIGH TONE +07F0 ; [.0000.0115.0002.07F0] # NKO COMBINING LONG LOW TONE +07F1 ; [.0000.0116.0002.07F1] # NKO COMBINING LONG RISING TONE +07F2 ; [.0000.0117.0002.07F2] # NKO COMBINING NASALIZATION MARK +07F3 ; [.0000.0118.0002.07F3] # NKO COMBINING DOUBLE DOT ABOVE +093C ; [.0000.0119.0002.093C] # DEVANAGARI SIGN NUKTA +0901 ; [.0000.011A.0002.0901] # DEVANAGARI SIGN CANDRABINDU +0902 ; [.0000.011B.0002.0902] # DEVANAGARI SIGN ANUSVARA +0903 ; [.0000.011C.0002.0903] # DEVANAGARI SIGN VISARGA +0951 ; [.0000.011D.0002.0951] # DEVANAGARI STRESS SIGN UDATTA +0952 ; [.0000.011E.0002.0952] # DEVANAGARI STRESS SIGN ANUDATTA +0953 ; [.0000.011F.0002.0953] # DEVANAGARI GRAVE ACCENT +0954 ; [.0000.0120.0002.0954] # DEVANAGARI ACUTE ACCENT +09BC ; [.0000.0121.0002.09BC] # BENGALI SIGN NUKTA +0981 ; [.0000.0122.0002.0981] # BENGALI SIGN CANDRABINDU +0982 ; [.0000.0123.0002.0982] # BENGALI SIGN ANUSVARA +0983 ; [.0000.0124.0002.0983] # BENGALI SIGN VISARGA +0A3C ; [.0000.0125.0002.0A3C] # GURMUKHI SIGN NUKTA +0A01 ; [.0000.0126.0002.0A01] # GURMUKHI SIGN ADAK BINDI +0A02 ; [.0000.0127.0002.0A02] # GURMUKHI SIGN BINDI +0A03 ; [.0000.0128.0002.0A03] # GURMUKHI SIGN VISARGA +0A70 ; [.0000.0129.0002.0A70] # GURMUKHI TIPPI +0A71 ; [.0000.012A.0002.0A71] # GURMUKHI ADDAK +0ABC ; [.0000.012B.0002.0ABC] # GUJARATI SIGN NUKTA +0A81 ; [.0000.012C.0002.0A81] # GUJARATI SIGN CANDRABINDU +0A82 ; [.0000.012D.0002.0A82] # GUJARATI SIGN ANUSVARA +0A83 ; [.0000.012E.0002.0A83] # GUJARATI SIGN VISARGA +0B3C ; [.0000.012F.0002.0B3C] # ORIYA SIGN NUKTA +0B01 ; [.0000.0130.0002.0B01] # ORIYA SIGN CANDRABINDU +0B02 ; [.0000.0131.0002.0B02] # ORIYA SIGN ANUSVARA +0B03 ; [.0000.0132.0002.0B03] # ORIYA SIGN VISARGA +0B82 ; [.0000.0133.0002.0B82] # TAMIL SIGN ANUSVARA +0C01 ; [.0000.0134.0002.0C01] # TELUGU SIGN CANDRABINDU +0C02 ; [.0000.0135.0002.0C02] # TELUGU SIGN ANUSVARA +0C03 ; [.0000.0136.0002.0C03] # TELUGU SIGN VISARGA +0CBC ; [.0000.0137.0002.0CBC] # KANNADA SIGN NUKTA +0C82 ; [.0000.0138.0002.0C82] # KANNADA SIGN ANUSVARA +0C83 ; [.0000.0139.0002.0C83] # KANNADA SIGN VISARGA +0D02 ; [.0000.013A.0002.0D02] # MALAYALAM SIGN ANUSVARA +0D03 ; [.0000.013B.0002.0D03] # MALAYALAM SIGN VISARGA +0D82 ; [.0000.013C.0002.0D82] # SINHALA SIGN ANUSVARAYA +0D83 ; [.0000.013D.0002.0D83] # SINHALA SIGN VISARGAYA +1B34 ; [.0000.013E.0002.1B34] # BALINESE SIGN REREKAN +1B00 ; [.0000.013F.0002.1B00] # BALINESE SIGN ULU RICEM +1B01 ; [.0000.0140.0002.1B01] # BALINESE SIGN ULU CANDRA +1B02 ; [.0000.0141.0002.1B02] # BALINESE SIGN CECEK +1B03 ; [.0000.0142.0002.1B03] # BALINESE SIGN SURANG +1B04 ; [.0000.0143.0002.1B04] # BALINESE SIGN BISAH +A80B ; [.0000.0144.0002.A80B] # SYLOTI NAGRI SIGN ANUSVARA +10A0D ; [.0000.0145.0002.10A0D] # KHAROSHTHI SIGN DOUBLE RING BELOW +10A0E ; [.0000.0146.0002.10A0E] # KHAROSHTHI SIGN ANUSVARA +10A0F ; [.0000.0147.0002.10A0F] # KHAROSHTHI SIGN VISARGA +10A38 ; [.0000.0148.0002.10A38] # KHAROSHTHI SIGN BAR ABOVE +10A39 ; [.0000.0149.0002.10A39] # KHAROSHTHI SIGN CAUDA +10A3A ; [.0000.014A.0002.10A3A] # KHAROSHTHI SIGN DOT BELOW +0E4E ; [.0000.014B.0002.0E4E] # THAI CHARACTER YAMAKKAN +0E47 ; [.0000.014C.0002.0E47] # THAI CHARACTER MAITAIKHU +0E48 ; [.0000.014D.0002.0E48] # THAI CHARACTER MAI EK +0E49 ; [.0000.014E.0002.0E49] # THAI CHARACTER MAI THO +0E4A ; [.0000.014F.0002.0E4A] # THAI CHARACTER MAI TRI +0E4B ; [.0000.0150.0002.0E4B] # THAI CHARACTER MAI CHATTAWA +0E4C ; [.0000.0151.0002.0E4C] # THAI CHARACTER THANTHAKHAT +0E4D ; [.0000.0152.0002.0E4D] # THAI CHARACTER NIKHAHIT +0EC8 ; [.0000.0153.0002.0EC8] # LAO TONE MAI EK +0EC9 ; [.0000.0154.0002.0EC9] # LAO TONE MAI THO +0ECA ; [.0000.0155.0002.0ECA] # LAO TONE MAI TI +0ECB ; [.0000.0156.0002.0ECB] # LAO TONE MAI CATAWA +0ECC ; [.0000.0157.0002.0ECC] # LAO CANCELLATION MARK +0ECD ; [.0000.0158.0002.0ECD] # LAO NIGGAHITA +0F39 ; [.0000.0159.0002.0F39] # TIBETAN MARK TSA -PHRU +0F7E ; [.0000.015A.0002.0F7E] # TIBETAN SIGN RJES SU NGA RO +0F7F ; [.0000.015B.0002.0F7F] # TIBETAN SIGN RNAM BCAD +1036 ; [.0000.015C.0002.1036] # MYANMAR SIGN ANUSVARA +1037 ; [.0000.015D.0002.1037] # MYANMAR SIGN DOT BELOW +1038 ; [.0000.015E.0002.1038] # MYANMAR SIGN VISARGA +135F ; [.0000.015F.0002.135F] # ETHIOPIC COMBINING GEMINATION MARK +17C6 ; [.0000.0160.0002.17C6] # KHMER SIGN NIKAHIT +17C7 ; [.0000.0161.0002.17C7] # KHMER SIGN REAHMUK +17C8 ; [.0000.0162.0002.17C8] # KHMER SIGN YUUKALEAPINTU +17C9 ; [.0000.0163.0002.17C9] # KHMER SIGN MUUSIKATOAN +17CA ; [.0000.0164.0002.17CA] # KHMER SIGN TRIISAP +17CB ; [.0000.0165.0002.17CB] # KHMER SIGN BANTOC +17CC ; [.0000.0166.0002.17CC] # KHMER SIGN ROBAT +17CD ; [.0000.0167.0002.17CD] # KHMER SIGN TOANDAKHIAT +17CE ; [.0000.0168.0002.17CE] # KHMER SIGN KAKABAT +17CF ; [.0000.0169.0002.17CF] # KHMER SIGN AHSDA +17D0 ; [.0000.016A.0002.17D0] # KHMER SIGN SAMYOK SANNYA +17D1 ; [.0000.016B.0002.17D1] # KHMER SIGN VIRIAM +17D3 ; [.0000.016C.0002.17D3] # KHMER SIGN BATHAMASAT +17DD ; [.0000.016D.0002.17DD] # KHMER SIGN ATTHACAN +1939 ; [.0000.016E.0002.1939] # LIMBU SIGN MUKPHRENG +193A ; [.0000.016F.0002.193A] # LIMBU SIGN KEMPHRENG +193B ; [.0000.0170.0002.193B] # LIMBU SIGN SA-I +302A ; [.0000.0171.0002.302A] # IDEOGRAPHIC LEVEL TONE MARK +302B ; [.0000.0172.0002.302B] # IDEOGRAPHIC RISING TONE MARK +302C ; [.0000.0173.0002.302C] # IDEOGRAPHIC DEPARTING TONE MARK +302D ; [.0000.0174.0002.302D] # IDEOGRAPHIC ENTERING TONE MARK +302E ; [.0000.0175.0002.302E] # HANGUL SINGLE DOT TONE MARK +302F ; [.0000.0176.0002.302F] # HANGUL DOUBLE DOT TONE MARK +3099 ; [.0000.0177.0002.3099] # COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK +FF9E ; [.0000.0177.0012.FF9E] # HALFWIDTH KATAKANA VOICED SOUND MARK; QQK +309A ; [.0000.0178.0002.309A] # COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +FF9F ; [.0000.0178.0012.FF9F] # HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK; QQK +20D0 ; [.0000.0179.0002.20D0] # COMBINING LEFT HARPOON ABOVE +20D1 ; [.0000.017A.0002.20D1] # COMBINING RIGHT HARPOON ABOVE +20D2 ; [.0000.017B.0002.20D2] # COMBINING LONG VERTICAL LINE OVERLAY +20D3 ; [.0000.017C.0002.20D3] # COMBINING SHORT VERTICAL LINE OVERLAY +20D4 ; [.0000.017D.0002.20D4] # COMBINING ANTICLOCKWISE ARROW ABOVE +20D5 ; [.0000.017E.0002.20D5] # COMBINING CLOCKWISE ARROW ABOVE +20D6 ; [.0000.017F.0002.20D6] # COMBINING LEFT ARROW ABOVE +20D7 ; [.0000.0180.0002.20D7] # COMBINING RIGHT ARROW ABOVE +20D8 ; [.0000.0181.0002.20D8] # COMBINING RING OVERLAY +20D9 ; [.0000.0182.0002.20D9] # COMBINING CLOCKWISE RING OVERLAY +20DA ; [.0000.0183.0002.20DA] # COMBINING ANTICLOCKWISE RING OVERLAY +20DB ; [.0000.0184.0002.20DB] # COMBINING THREE DOTS ABOVE +20DC ; [.0000.0185.0002.20DC] # COMBINING FOUR DOTS ABOVE +20DD ; [.0000.0186.0002.20DD] # COMBINING ENCLOSING CIRCLE +20DE ; [.0000.0187.0002.20DE] # COMBINING ENCLOSING SQUARE +20DF ; [.0000.0188.0002.20DF] # COMBINING ENCLOSING DIAMOND +20E0 ; [.0000.0189.0002.20E0] # COMBINING ENCLOSING CIRCLE BACKSLASH +20E1 ; [.0000.018A.0002.20E1] # COMBINING LEFT RIGHT ARROW ABOVE +20E2 ; [.0000.018B.0002.20E2] # COMBINING ENCLOSING SCREEN +20E3 ; [.0000.018C.0002.20E3] # COMBINING ENCLOSING KEYCAP +20E4 ; [.0000.018D.0002.20E4] # COMBINING ENCLOSING UPWARD POINTING TRIANGLE +20E5 ; [.0000.018E.0002.20E5] # COMBINING REVERSE SOLIDUS OVERLAY +20E6 ; [.0000.018F.0002.20E6] # COMBINING DOUBLE VERTICAL STROKE OVERLAY +20E7 ; [.0000.0190.0002.20E7] # COMBINING ANNUITY SYMBOL +20E8 ; [.0000.0191.0002.20E8] # COMBINING TRIPLE UNDERDOT +20E9 ; [.0000.0192.0002.20E9] # COMBINING WIDE BRIDGE ABOVE +20EA ; [.0000.0193.0002.20EA] # COMBINING LEFTWARDS ARROW OVERLAY +20EB ; [.0000.0194.0002.20EB] # COMBINING LONG DOUBLE SOLIDUS OVERLAY +20EC ; [.0000.0195.0002.20EC] # COMBINING RIGHTWARDS HARPOON WITH BARB DOWNWARDS +20ED ; [.0000.0196.0002.20ED] # COMBINING LEFTWARDS HARPOON WITH BARB DOWNWARDS +20EE ; [.0000.0197.0002.20EE] # COMBINING LEFT ARROW BELOW +20EF ; [.0000.0198.0002.20EF] # COMBINING RIGHT ARROW BELOW +02D0 ; [.0F99.0020.0002.02D0] # MODIFIER LETTER TRIANGULAR COLON +02D1 ; [.0F9A.0020.0002.02D1] # MODIFIER LETTER HALF TRIANGULAR COLON +0E46 ; [.0F9B.0020.0002.0E46] # THAI CHARACTER MAIYAMOK +0EC6 ; [.0F9C.0020.0002.0EC6] # LAO KO LA +3005 ; [.0F9D.0020.0002.3005] # IDEOGRAPHIC ITERATION MARK +303B ; [.0F9E.0020.0002.303B] # VERTICAL IDEOGRAPHIC ITERATION MARK +3031 ; [.0F9F.0020.0002.3031] # VERTICAL KANA REPEAT MARK +3032 ; [.0F9F.0020.0002.3031][.0000.0177.0002.3099] # VERTICAL KANA REPEAT WITH VOICED SOUND MARK; QQCM +3033 ; [.0FA0.0020.0002.3033] # VERTICAL KANA REPEAT MARK UPPER HALF +3034 ; [.0FA0.0020.0002.3033][.0000.0177.0002.3099] # VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF; QQCM +3035 ; [.0FA1.0020.0002.3035] # VERTICAL KANA REPEAT MARK LOWER HALF +309D ; [.0FA2.0020.0002.309D] # HIRAGANA ITERATION MARK +309E ; [.0FA2.0020.0002.309D][.0000.0177.0002.3099] # HIRAGANA VOICED ITERATION MARK; QQCM +30FC ; [.0FA3.0020.0002.30FC] # KATAKANA-HIRAGANA PROLONGED SOUND MARK +FF70 ; [.0FA3.0020.0012.FF70] # HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK; QQK +30FD ; [.0FA4.0020.0002.30FD] # KATAKANA ITERATION MARK +30FE ; [.0FA4.0020.0002.30FD][.0000.0177.0002.3099] # KATAKANA VOICED ITERATION MARK; QQCM +00A4 ; [.0FA5.0020.0002.00A4] # CURRENCY SIGN +00A2 ; [.0FA6.0020.0002.00A2] # CENT SIGN +FFE0 ; [.0FA6.0020.0003.FFE0] # FULLWIDTH CENT SIGN; QQK +0024 ; [.0FA7.0020.0002.0024] # DOLLAR SIGN +FF04 ; [.0FA7.0020.0003.FF04] # FULLWIDTH DOLLAR SIGN; QQK +FE69 ; [.0FA7.0020.000F.FE69] # SMALL DOLLAR SIGN; QQK +00A3 ; [.0FA8.0020.0002.00A3] # POUND SIGN +FFE1 ; [.0FA8.0020.0003.FFE1] # FULLWIDTH POUND SIGN; QQK +00A5 ; [.0FA9.0020.0002.00A5] # YEN SIGN +FFE5 ; [.0FA9.0020.0003.FFE5] # FULLWIDTH YEN SIGN; QQK +060B ; [.0FAA.0020.0002.060B] # AFGHANI SIGN +09F2 ; [.0FAB.0020.0002.09F2] # BENGALI RUPEE MARK +09F3 ; [.0FAC.0020.0002.09F3] # BENGALI RUPEE SIGN +0AF1 ; [.0FAD.0020.0002.0AF1] # GUJARATI RUPEE SIGN +0BF9 ; [.0FAE.0020.0002.0BF9] # TAMIL RUPEE SIGN +0E3F ; [.0FAF.0020.0002.0E3F] # THAI CURRENCY SYMBOL BAHT +17DB ; [.0FB0.0020.0002.17DB] # KHMER CURRENCY SYMBOL RIEL +20A0 ; [.0FB1.0020.0002.20A0] # EURO-CURRENCY SIGN +20A1 ; [.0FB2.0020.0002.20A1] # COLON SIGN +20A2 ; [.0FB3.0020.0002.20A2] # CRUZEIRO SIGN +20A3 ; [.0FB4.0020.0002.20A3] # FRENCH FRANC SIGN +20A4 ; [.0FB5.0020.0002.20A4] # LIRA SIGN +20A5 ; [.0FB6.0020.0002.20A5] # MILL SIGN +20A6 ; [.0FB7.0020.0002.20A6] # NAIRA SIGN +20A7 ; [.0FB8.0020.0002.20A7] # PESETA SIGN +20A9 ; [.0FB9.0020.0002.20A9] # WON SIGN +FFE6 ; [.0FB9.0020.0003.FFE6] # FULLWIDTH WON SIGN; QQK +20AA ; [.0FBA.0020.0002.20AA] # NEW SHEQEL SIGN +20AB ; [.0FBB.0020.0002.20AB] # DONG SIGN +20AC ; [.0FBC.0020.0002.20AC] # EURO SIGN +20AD ; [.0FBD.0020.0002.20AD] # KIP SIGN +20AE ; [.0FBE.0020.0002.20AE] # TUGRIK SIGN +20AF ; [.0FBF.0020.0002.20AF] # DRACHMA SIGN +20B0 ; [.0FC0.0020.0002.20B0] # GERMAN PENNY SIGN +20B1 ; [.0FC1.0020.0002.20B1] # PESO SIGN +20B2 ; [.0FC2.0020.0002.20B2] # GUARANI SIGN +20B3 ; [.0FC3.0020.0002.20B3] # AUSTRAL SIGN +20B4 ; [.0FC4.0020.0002.20B4] # HRYVNIA SIGN +20B5 ; [.0FC5.0020.0002.20B5] # CEDI SIGN +0030 ; [.0FC6.0020.0002.0030] # DIGIT ZERO +FF10 ; [.0FC6.0020.0003.FF10] # FULLWIDTH DIGIT ZERO; QQK +1D7CE ; [.0FC6.0020.0005.1D7CE] # MATHEMATICAL BOLD DIGIT ZERO; QQK +1D7D8 ; [.0FC6.0020.0005.1D7D8] # MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO; QQK +1D7E2 ; [.0FC6.0020.0005.1D7E2] # MATHEMATICAL SANS-SERIF DIGIT ZERO; QQK +1D7EC ; [.0FC6.0020.0005.1D7EC] # MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO; QQK +1D7F6 ; [.0FC6.0020.0005.1D7F6] # MATHEMATICAL MONOSPACE DIGIT ZERO; QQK +24EA ; [.0FC6.0020.0006.24EA] # CIRCLED DIGIT ZERO; QQK +24FF ; [.0FC6.0020.0006.24FF] # NEGATIVE CIRCLED DIGIT ZERO; QQK +2070 ; [.0FC6.0020.0014.2070] # SUPERSCRIPT ZERO; QQK +2080 ; [.0FC6.0020.0015.2080] # SUBSCRIPT ZERO; QQK +0660 ; [.0FC6.0020.0002.0660][.0000.019F.0002.0660] # ARABIC-INDIC DIGIT ZERO +06F0 ; [.0FC6.0020.0002.06F0][.0000.01A0.0002.06F0] # EXTENDED ARABIC-INDIC DIGIT ZERO +07C0 ; [.0FC6.0020.0002.07C0][.0000.01A1.0002.07C0] # NKO DIGIT ZERO +104A0 ; [.0FC6.0020.0002.104A0][.0000.01A3.0002.104A0] # OSMANYA DIGIT ZERO +0966 ; [.0FC6.0020.0002.0966][.0000.01A4.0002.0966] # DEVANAGARI DIGIT ZERO +09E6 ; [.0FC6.0020.0002.09E6][.0000.01A5.0002.09E6] # BENGALI DIGIT ZERO +0A66 ; [.0FC6.0020.0002.0A66][.0000.01A6.0002.0A66] # GURMUKHI DIGIT ZERO +0AE6 ; [.0FC6.0020.0002.0AE6][.0000.01A7.0002.0AE6] # GUJARATI DIGIT ZERO +0B66 ; [.0FC6.0020.0002.0B66][.0000.01A8.0002.0B66] # ORIYA DIGIT ZERO +0BE6 ; [.0FC6.0020.0002.0BE6][.0000.01A9.0002.0BE6] # TAMIL DIGIT ZERO +0C66 ; [.0FC6.0020.0002.0C66][.0000.01AA.0002.0C66] # TELUGU DIGIT ZERO +0CE6 ; [.0FC6.0020.0002.0CE6][.0000.01AB.0002.0CE6] # KANNADA DIGIT ZERO +0D66 ; [.0FC6.0020.0002.0D66][.0000.01AC.0002.0D66] # MALAYALAM DIGIT ZERO +1946 ; [.0FC6.0020.0002.1946][.0000.01AD.0002.1946] # LIMBU DIGIT ZERO +19D0 ; [.0FC6.0020.0002.19D0][.0000.01AE.0002.19D0] # NEW TAI LUE DIGIT ZERO +0E50 ; [.0FC6.0020.0002.0E50][.0000.01AF.0002.0E50] # THAI DIGIT ZERO +0ED0 ; [.0FC6.0020.0002.0ED0][.0000.01B0.0002.0ED0] # LAO DIGIT ZERO +0F20 ; [.0FC6.0020.0002.0F20][.0000.01B1.0002.0F20] # TIBETAN DIGIT ZERO +0F33 ; [.0FC6.0020.0004.0F33][.0000.01B1.0004.0F33] # TIBETAN DIGIT HALF ZERO; QQK +1040 ; [.0FC6.0020.0002.1040][.0000.01B2.0002.1040] # MYANMAR DIGIT ZERO +17E0 ; [.0FC6.0020.0002.17E0][.0000.01B3.0002.17E0] # KHMER DIGIT ZERO +17F0 ; [.0FC6.0020.0002.17F0][.0000.01B4.0002.17F0] # KHMER SYMBOL LEK ATTAK SON +1B50 ; [.0FC6.0020.0002.1B50][.0000.01B5.0002.1B50] # BALINESE DIGIT ZERO +1810 ; [.0FC6.0020.0002.1810][.0000.01B6.0002.1810] # MONGOLIAN DIGIT ZERO +3007 ; [.0FC6.0020.0002.3007][.0000.01B7.0002.3007] # IDEOGRAPHIC NUMBER ZERO +1018A ; [.0FC6.0020.0002.1018A][.0000.01B9.0002.1018A] # GREEK ZERO SIGN +3358 ; [.0FC6.0020.0004.3358][.FB40.0020.0004.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO; QQKN +0031 ; [.0FC7.0020.0002.0031] # DIGIT ONE +FF11 ; [.0FC7.0020.0003.FF11] # FULLWIDTH DIGIT ONE; QQK +2474 ; [*02B1.0020.0004.2474][.0FC7.0020.0004.2474][*02B2.0020.001F.2474] # PARENTHESIZED DIGIT ONE; QQKN +2488 ; [.0FC7.0020.0004.2488][*0266.0020.0004.2488] # DIGIT ONE FULL STOP; QQKN +1D7CF ; [.0FC7.0020.0005.1D7CF] # MATHEMATICAL BOLD DIGIT ONE; QQK +1D7D9 ; [.0FC7.0020.0005.1D7D9] # MATHEMATICAL DOUBLE-STRUCK DIGIT ONE; QQK +1D7E3 ; [.0FC7.0020.0005.1D7E3] # MATHEMATICAL SANS-SERIF DIGIT ONE; QQK +1D7ED ; [.0FC7.0020.0005.1D7ED] # MATHEMATICAL SANS-SERIF BOLD DIGIT ONE; QQK +1D7F7 ; [.0FC7.0020.0005.1D7F7] # MATHEMATICAL MONOSPACE DIGIT ONE; QQK +2460 ; [.0FC7.0020.0006.2460] # CIRCLED DIGIT ONE; QQK +24F5 ; [.0FC7.0020.0006.24F5] # DOUBLE CIRCLED DIGIT ONE; QQK +2776 ; [.0FC7.0020.0006.2776] # DINGBAT NEGATIVE CIRCLED DIGIT ONE; QQK +2780 ; [.0FC7.0020.0006.2780] # DINGBAT CIRCLED SANS-SERIF DIGIT ONE; QQK +278A ; [.0FC7.0020.0006.278A] # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE; QQK +00B9 ; [.0FC7.0020.0014.00B9] # SUPERSCRIPT ONE; QQK +2081 ; [.0FC7.0020.0015.2081] # SUBSCRIPT ONE; QQK +215F ; [.0FC7.0020.001E.215F][*0300.0020.001E.215F] # FRACTION NUMERATOR ONE; QQKN +0661 ; [.0FC7.0020.0002.0661][.0000.019F.0002.0661] # ARABIC-INDIC DIGIT ONE +06F1 ; [.0FC7.0020.0002.06F1][.0000.01A0.0002.06F1] # EXTENDED ARABIC-INDIC DIGIT ONE +07C1 ; [.0FC7.0020.0002.07C1][.0000.01A1.0002.07C1] # NKO DIGIT ONE +1369 ; [.0FC7.0020.0002.1369][.0000.01A2.0002.1369] # ETHIOPIC DIGIT ONE +104A1 ; [.0FC7.0020.0002.104A1][.0000.01A3.0002.104A1] # OSMANYA DIGIT ONE +0967 ; [.0FC7.0020.0002.0967][.0000.01A4.0002.0967] # DEVANAGARI DIGIT ONE +09E7 ; [.0FC7.0020.0002.09E7][.0000.01A5.0002.09E7] # BENGALI DIGIT ONE +09F4 ; [.0FC7.0020.0002.09F4][.0000.01A5.0002.09F4] # BENGALI CURRENCY NUMERATOR ONE +0A67 ; [.0FC7.0020.0002.0A67][.0000.01A6.0002.0A67] # GURMUKHI DIGIT ONE +0AE7 ; [.0FC7.0020.0002.0AE7][.0000.01A7.0002.0AE7] # GUJARATI DIGIT ONE +0B67 ; [.0FC7.0020.0002.0B67][.0000.01A8.0002.0B67] # ORIYA DIGIT ONE +0BE7 ; [.0FC7.0020.0002.0BE7][.0000.01A9.0002.0BE7] # TAMIL DIGIT ONE +0C67 ; [.0FC7.0020.0002.0C67][.0000.01AA.0002.0C67] # TELUGU DIGIT ONE +0CE7 ; [.0FC7.0020.0002.0CE7][.0000.01AB.0002.0CE7] # KANNADA DIGIT ONE +0D67 ; [.0FC7.0020.0002.0D67][.0000.01AC.0002.0D67] # MALAYALAM DIGIT ONE +1947 ; [.0FC7.0020.0002.1947][.0000.01AD.0002.1947] # LIMBU DIGIT ONE +19D1 ; [.0FC7.0020.0002.19D1][.0000.01AE.0002.19D1] # NEW TAI LUE DIGIT ONE +0E51 ; [.0FC7.0020.0002.0E51][.0000.01AF.0002.0E51] # THAI DIGIT ONE +0ED1 ; [.0FC7.0020.0002.0ED1][.0000.01B0.0002.0ED1] # LAO DIGIT ONE +0F21 ; [.0FC7.0020.0002.0F21][.0000.01B1.0002.0F21] # TIBETAN DIGIT ONE +0F2A ; [.0FC7.0020.0004.0F2A][.0000.01B1.0004.0F2A] # TIBETAN DIGIT HALF ONE; QQK +1041 ; [.0FC7.0020.0002.1041][.0000.01B2.0002.1041] # MYANMAR DIGIT ONE +17E1 ; [.0FC7.0020.0002.17E1][.0000.01B3.0002.17E1] # KHMER DIGIT ONE +17F1 ; [.0FC7.0020.0002.17F1][.0000.01B4.0002.17F1] # KHMER SYMBOL LEK ATTAK MUOY +1B51 ; [.0FC7.0020.0002.1B51][.0000.01B5.0002.1B51] # BALINESE DIGIT ONE +1811 ; [.0FC7.0020.0002.1811][.0000.01B6.0002.1811] # MONGOLIAN DIGIT ONE +3021 ; [.0FC7.0020.0002.3021][.0000.01B7.0002.3021] # HANGZHOU NUMERAL ONE +10107 ; [.0FC7.0020.0002.10107][.0000.01B8.0002.10107] # AEGEAN NUMBER ONE +10142 ; [.0FC7.0020.0002.10142][.0000.01B9.0002.10142] # GREEK ACROPHONIC ATTIC ONE DRACHMA +10158 ; [.0FC7.0020.0002.10158][.0000.01B9.0002.10158] # GREEK ACROPHONIC HERAEUM ONE PLETHRON +10159 ; [.0FC7.0020.0002.10159][.0000.01B9.0002.10159] # GREEK ACROPHONIC THESPIAN ONE +1015A ; [.0FC7.0020.0002.1015A][.0000.01B9.0002.1015A] # GREEK ACROPHONIC HERMIONIAN ONE +10320 ; [.0FC7.0020.0002.10320][.0000.01BA.0002.10320] # OLD ITALIC NUMERAL ONE +103D1 ; [.0FC7.0020.0002.103D1][.0000.01BB.0002.103D1] # OLD PERSIAN NUMBER ONE +12415 ; [.0FC7.0020.0002.12415][.0000.01BC.0002.12415] # CUNEIFORM NUMERIC SIGN ONE GESH2 +1241E ; [.0FC7.0020.0002.1241E][.0000.01BC.0002.1241E] # CUNEIFORM NUMERIC SIGN ONE GESHU +1242C ; [.0FC7.0020.0002.1242C][.0000.01BC.0002.1242C] # CUNEIFORM NUMERIC SIGN ONE SHARU +12434 ; [.0FC7.0020.0002.12434][.0000.01BC.0002.12434] # CUNEIFORM NUMERIC SIGN ONE BURU +1244F ; [.0FC7.0020.0002.1244F][.0000.01BC.0002.1244F] # CUNEIFORM NUMERIC SIGN ONE BAN2 +12458 ; [.0FC7.0020.0002.12458][.0000.01BC.0002.12458] # CUNEIFORM NUMERIC SIGN ONE ESHE3 +10916 ; [.0FC7.0020.0002.10916][.0000.01BD.0002.10916] # PHOENICIAN NUMBER ONE +10A40 ; [.0FC7.0020.0002.10A40][.0000.01BE.0002.10A40] # KHAROSHTHI DIGIT ONE +1D360 ; [.0FC7.0020.0002.1D360][.0000.01BF.0002.1D360] # COUNTING ROD UNIT DIGIT ONE +2491 ; [.0FC7.0020.0004.2491][.0FC6.0020.0004.2491][*0266.0020.001F.2491] # NUMBER TEN FULL STOP; QQKN +247D ; [*02B1.0020.0004.247D][.0FC7.0020.0004.247D][.0FC6.0020.001F.247D][*02B2.0020.001F.247D] # PARENTHESIZED NUMBER TEN; QQKN +2469 ; [.0FC7.0020.0006.2469][.0FC6.0020.0006.2469] # CIRCLED NUMBER TEN; QQKN +24FE ; [.0FC7.0020.0006.24FE][.0FC6.0020.0006.24FE] # DOUBLE CIRCLED NUMBER TEN; QQKN +277F ; [.0FC7.0020.0006.277F][.0FC6.0020.0006.277F] # DINGBAT NEGATIVE CIRCLED NUMBER TEN; QQKN +2789 ; [.0FC7.0020.0006.2789][.0FC6.0020.0006.2789] # DINGBAT CIRCLED SANS-SERIF NUMBER TEN; QQKN +2793 ; [.0FC7.0020.0006.2793][.0FC6.0020.0006.2793] # DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN; QQKN +33E9 ; [.0FC7.0020.0004.33E9][.0FC6.0020.0004.33E9][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TEN; QQKN +32C9 ; [.0FC7.0020.0004.32C9][.0FC6.0020.0004.32C9][.FB40.0020.001F.6708][.E708.0000.0000.6708] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR OCTOBER; QQKN +3362 ; [.0FC7.0020.0004.3362][.0FC6.0020.0004.3362][.FB40.0020.001F.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TEN; QQKN +2492 ; [.0FC7.0020.0004.2492][.0FC7.0020.0004.2492][*0266.0020.001F.2492] # NUMBER ELEVEN FULL STOP; QQKN +247E ; [*02B1.0020.0004.247E][.0FC7.0020.0004.247E][.0FC7.0020.001F.247E][*02B2.0020.001F.247E] # PARENTHESIZED NUMBER ELEVEN; QQKN +246A ; [.0FC7.0020.0006.246A][.0FC7.0020.0006.246A] # CIRCLED NUMBER ELEVEN; QQKN +24EB ; [.0FC7.0020.0006.24EB][.0FC7.0020.0006.24EB] # NEGATIVE CIRCLED NUMBER ELEVEN; QQKN +33EA ; [.0FC7.0020.0004.33EA][.0FC7.0020.0004.33EA][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ELEVEN; QQKN +32CA ; [.0FC7.0020.0004.32CA][.0FC7.0020.0004.32CA][.FB40.0020.001F.6708][.E708.0000.0000.6708] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR NOVEMBER; QQKN +3363 ; [.0FC7.0020.0004.3363][.0FC7.0020.0004.3363][.FB40.0020.001F.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ELEVEN; QQKN +2493 ; [.0FC7.0020.0004.2493][.0FC8.0020.0004.2493][*0266.0020.001F.2493] # NUMBER TWELVE FULL STOP; QQKN +247F ; [*02B1.0020.0004.247F][.0FC7.0020.0004.247F][.0FC8.0020.001F.247F][*02B2.0020.001F.247F] # PARENTHESIZED NUMBER TWELVE; QQKN +246B ; [.0FC7.0020.0006.246B][.0FC8.0020.0006.246B] # CIRCLED NUMBER TWELVE; QQKN +24EC ; [.0FC7.0020.0006.24EC][.0FC8.0020.0006.24EC] # NEGATIVE CIRCLED NUMBER TWELVE; QQKN +00BD ; [.0FC7.0020.001E.00BD][*0300.0020.001E.00BD][.0FC8.0020.001F.00BD] # VULGAR FRACTION ONE HALF; QQKN +33EB ; [.0FC7.0020.0004.33EB][.0FC8.0020.0004.33EB][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWELVE; QQKN +32CB ; [.0FC7.0020.0004.32CB][.0FC8.0020.0004.32CB][.FB40.0020.001F.6708][.E708.0000.0000.6708] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER; QQKN +3364 ; [.0FC7.0020.0004.3364][.0FC8.0020.0004.3364][.FB40.0020.001F.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWELVE; QQKN +2494 ; [.0FC7.0020.0004.2494][.0FC9.0020.0004.2494][*0266.0020.001F.2494] # NUMBER THIRTEEN FULL STOP; QQKN +2480 ; [*02B1.0020.0004.2480][.0FC7.0020.0004.2480][.0FC9.0020.001F.2480][*02B2.0020.001F.2480] # PARENTHESIZED NUMBER THIRTEEN; QQKN +246C ; [.0FC7.0020.0006.246C][.0FC9.0020.0006.246C] # CIRCLED NUMBER THIRTEEN; QQKN +24ED ; [.0FC7.0020.0006.24ED][.0FC9.0020.0006.24ED] # NEGATIVE CIRCLED NUMBER THIRTEEN; QQKN +2153 ; [.0FC7.0020.001E.2153][*0300.0020.001E.2153][.0FC9.0020.001F.2153] # VULGAR FRACTION ONE THIRD; QQKN +33EC ; [.0FC7.0020.0004.33EC][.0FC9.0020.0004.33EC][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTEEN; QQKN +3365 ; [.0FC7.0020.0004.3365][.0FC9.0020.0004.3365][.FB40.0020.001F.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THIRTEEN; QQKN +2495 ; [.0FC7.0020.0004.2495][.0FCA.0020.0004.2495][*0266.0020.001F.2495] # NUMBER FOURTEEN FULL STOP; QQKN +2481 ; [*02B1.0020.0004.2481][.0FC7.0020.0004.2481][.0FCA.0020.001F.2481][*02B2.0020.001F.2481] # PARENTHESIZED NUMBER FOURTEEN; QQKN +246D ; [.0FC7.0020.0006.246D][.0FCA.0020.0006.246D] # CIRCLED NUMBER FOURTEEN; QQKN +24EE ; [.0FC7.0020.0006.24EE][.0FCA.0020.0006.24EE] # NEGATIVE CIRCLED NUMBER FOURTEEN; QQKN +00BC ; [.0FC7.0020.001E.00BC][*0300.0020.001E.00BC][.0FCA.0020.001F.00BC] # VULGAR FRACTION ONE QUARTER; QQKN +33ED ; [.0FC7.0020.0004.33ED][.0FCA.0020.0004.33ED][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOURTEEN; QQKN +3366 ; [.0FC7.0020.0004.3366][.0FCA.0020.0004.3366][.FB40.0020.001F.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOURTEEN; QQKN +2496 ; [.0FC7.0020.0004.2496][.0FCB.0020.0004.2496][*0266.0020.001F.2496] # NUMBER FIFTEEN FULL STOP; QQKN +2482 ; [*02B1.0020.0004.2482][.0FC7.0020.0004.2482][.0FCB.0020.001F.2482][*02B2.0020.001F.2482] # PARENTHESIZED NUMBER FIFTEEN; QQKN +246E ; [.0FC7.0020.0006.246E][.0FCB.0020.0006.246E] # CIRCLED NUMBER FIFTEEN; QQKN +24EF ; [.0FC7.0020.0006.24EF][.0FCB.0020.0006.24EF] # NEGATIVE CIRCLED NUMBER FIFTEEN; QQKN +2155 ; [.0FC7.0020.001E.2155][*0300.0020.001E.2155][.0FCB.0020.001F.2155] # VULGAR FRACTION ONE FIFTH; QQKN +33EE ; [.0FC7.0020.0004.33EE][.0FCB.0020.0004.33EE][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIFTEEN; QQKN +3367 ; [.0FC7.0020.0004.3367][.0FCB.0020.0004.3367][.FB40.0020.001F.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIFTEEN; QQKN +2497 ; [.0FC7.0020.0004.2497][.0FCC.0020.0004.2497][*0266.0020.001F.2497] # NUMBER SIXTEEN FULL STOP; QQKN +2483 ; [*02B1.0020.0004.2483][.0FC7.0020.0004.2483][.0FCC.0020.001F.2483][*02B2.0020.001F.2483] # PARENTHESIZED NUMBER SIXTEEN; QQKN +246F ; [.0FC7.0020.0006.246F][.0FCC.0020.0006.246F] # CIRCLED NUMBER SIXTEEN; QQKN +24F0 ; [.0FC7.0020.0006.24F0][.0FCC.0020.0006.24F0] # NEGATIVE CIRCLED NUMBER SIXTEEN; QQKN +2159 ; [.0FC7.0020.001E.2159][*0300.0020.001E.2159][.0FCC.0020.001F.2159] # VULGAR FRACTION ONE SIXTH; QQKN +33EF ; [.0FC7.0020.0004.33EF][.0FCC.0020.0004.33EF][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIXTEEN; QQKN +3368 ; [.0FC7.0020.0004.3368][.0FCC.0020.0004.3368][.FB40.0020.001F.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIXTEEN; QQKN +2498 ; [.0FC7.0020.0004.2498][.0FCD.0020.0004.2498][*0266.0020.001F.2498] # NUMBER SEVENTEEN FULL STOP; QQKN +2484 ; [*02B1.0020.0004.2484][.0FC7.0020.0004.2484][.0FCD.0020.001F.2484][*02B2.0020.001F.2484] # PARENTHESIZED NUMBER SEVENTEEN; QQKN +2470 ; [.0FC7.0020.0006.2470][.0FCD.0020.0006.2470] # CIRCLED NUMBER SEVENTEEN; QQKN +24F1 ; [.0FC7.0020.0006.24F1][.0FCD.0020.0006.24F1] # NEGATIVE CIRCLED NUMBER SEVENTEEN; QQKN +33F0 ; [.0FC7.0020.0004.33F0][.0FCD.0020.0004.33F0][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVENTEEN; QQKN +3369 ; [.0FC7.0020.0004.3369][.0FCD.0020.0004.3369][.FB40.0020.001F.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENTEEN; QQKN +2499 ; [.0FC7.0020.0004.2499][.0FCE.0020.0004.2499][*0266.0020.001F.2499] # NUMBER EIGHTEEN FULL STOP; QQKN +2485 ; [*02B1.0020.0004.2485][.0FC7.0020.0004.2485][.0FCE.0020.001F.2485][*02B2.0020.001F.2485] # PARENTHESIZED NUMBER EIGHTEEN; QQKN +2471 ; [.0FC7.0020.0006.2471][.0FCE.0020.0006.2471] # CIRCLED NUMBER EIGHTEEN; QQKN +24F2 ; [.0FC7.0020.0006.24F2][.0FCE.0020.0006.24F2] # NEGATIVE CIRCLED NUMBER EIGHTEEN; QQKN +215B ; [.0FC7.0020.001E.215B][*0300.0020.001E.215B][.0FCE.0020.001F.215B] # VULGAR FRACTION ONE EIGHTH; QQKN +33F1 ; [.0FC7.0020.0004.33F1][.0FCE.0020.0004.33F1][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTEEN; QQKN +336A ; [.0FC7.0020.0004.336A][.0FCE.0020.0004.336A][.FB40.0020.001F.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHTEEN; QQKN +249A ; [.0FC7.0020.0004.249A][.0FCF.0020.0004.249A][*0266.0020.001F.249A] # NUMBER NINETEEN FULL STOP; QQKN +2486 ; [*02B1.0020.0004.2486][.0FC7.0020.0004.2486][.0FCF.0020.001F.2486][*02B2.0020.001F.2486] # PARENTHESIZED NUMBER NINETEEN; QQKN +2472 ; [.0FC7.0020.0006.2472][.0FCF.0020.0006.2472] # CIRCLED NUMBER NINETEEN; QQKN +24F3 ; [.0FC7.0020.0006.24F3][.0FCF.0020.0006.24F3] # NEGATIVE CIRCLED NUMBER NINETEEN; QQKN +33F2 ; [.0FC7.0020.0004.33F2][.0FCF.0020.0004.33F2][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINETEEN; QQKN +336B ; [.0FC7.0020.0004.336B][.0FCF.0020.0004.336B][.FB40.0020.001F.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINETEEN; QQKN +33E0 ; [.0FC7.0020.0004.33E0][.FB40.0020.0004.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE; QQKN +32C0 ; [.0FC7.0020.0004.32C0][.FB40.0020.0004.6708][.E708.0000.0000.6708] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY; QQKN +3359 ; [.0FC7.0020.0004.3359][.FB40.0020.0004.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ONE; QQKN +0032 ; [.0FC8.0020.0002.0032] # DIGIT TWO +FF12 ; [.0FC8.0020.0003.FF12] # FULLWIDTH DIGIT TWO; QQK +2475 ; [*02B1.0020.0004.2475][.0FC8.0020.0004.2475][*02B2.0020.001F.2475] # PARENTHESIZED DIGIT TWO; QQKN +2489 ; [.0FC8.0020.0004.2489][*0266.0020.0004.2489] # DIGIT TWO FULL STOP; QQKN +1D7D0 ; [.0FC8.0020.0005.1D7D0] # MATHEMATICAL BOLD DIGIT TWO; QQK +1D7DA ; [.0FC8.0020.0005.1D7DA] # MATHEMATICAL DOUBLE-STRUCK DIGIT TWO; QQK +1D7E4 ; [.0FC8.0020.0005.1D7E4] # MATHEMATICAL SANS-SERIF DIGIT TWO; QQK +1D7EE ; [.0FC8.0020.0005.1D7EE] # MATHEMATICAL SANS-SERIF BOLD DIGIT TWO; QQK +1D7F8 ; [.0FC8.0020.0005.1D7F8] # MATHEMATICAL MONOSPACE DIGIT TWO; QQK +2461 ; [.0FC8.0020.0006.2461] # CIRCLED DIGIT TWO; QQK +24F6 ; [.0FC8.0020.0006.24F6] # DOUBLE CIRCLED DIGIT TWO; QQK +2777 ; [.0FC8.0020.0006.2777] # DINGBAT NEGATIVE CIRCLED DIGIT TWO; QQK +2781 ; [.0FC8.0020.0006.2781] # DINGBAT CIRCLED SANS-SERIF DIGIT TWO; QQK +278B ; [.0FC8.0020.0006.278B] # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO; QQK +00B2 ; [.0FC8.0020.0014.00B2] # SUPERSCRIPT TWO; QQK +2082 ; [.0FC8.0020.0015.2082] # SUBSCRIPT TWO; QQK +0662 ; [.0FC8.0020.0002.0662][.0000.019F.0002.0662] # ARABIC-INDIC DIGIT TWO +06F2 ; [.0FC8.0020.0002.06F2][.0000.01A0.0002.06F2] # EXTENDED ARABIC-INDIC DIGIT TWO +07C2 ; [.0FC8.0020.0002.07C2][.0000.01A1.0002.07C2] # NKO DIGIT TWO +136A ; [.0FC8.0020.0002.136A][.0000.01A2.0002.136A] # ETHIOPIC DIGIT TWO +104A2 ; [.0FC8.0020.0002.104A2][.0000.01A3.0002.104A2] # OSMANYA DIGIT TWO +0968 ; [.0FC8.0020.0002.0968][.0000.01A4.0002.0968] # DEVANAGARI DIGIT TWO +09E8 ; [.0FC8.0020.0002.09E8][.0000.01A5.0002.09E8] # BENGALI DIGIT TWO +09F5 ; [.0FC8.0020.0002.09F5][.0000.01A5.0002.09F5] # BENGALI CURRENCY NUMERATOR TWO +0A68 ; [.0FC8.0020.0002.0A68][.0000.01A6.0002.0A68] # GURMUKHI DIGIT TWO +0AE8 ; [.0FC8.0020.0002.0AE8][.0000.01A7.0002.0AE8] # GUJARATI DIGIT TWO +0B68 ; [.0FC8.0020.0002.0B68][.0000.01A8.0002.0B68] # ORIYA DIGIT TWO +0BE8 ; [.0FC8.0020.0002.0BE8][.0000.01A9.0002.0BE8] # TAMIL DIGIT TWO +0C68 ; [.0FC8.0020.0002.0C68][.0000.01AA.0002.0C68] # TELUGU DIGIT TWO +0CE8 ; [.0FC8.0020.0002.0CE8][.0000.01AB.0002.0CE8] # KANNADA DIGIT TWO +0D68 ; [.0FC8.0020.0002.0D68][.0000.01AC.0002.0D68] # MALAYALAM DIGIT TWO +1948 ; [.0FC8.0020.0002.1948][.0000.01AD.0002.1948] # LIMBU DIGIT TWO +19D2 ; [.0FC8.0020.0002.19D2][.0000.01AE.0002.19D2] # NEW TAI LUE DIGIT TWO +0E52 ; [.0FC8.0020.0002.0E52][.0000.01AF.0002.0E52] # THAI DIGIT TWO +0ED2 ; [.0FC8.0020.0002.0ED2][.0000.01B0.0002.0ED2] # LAO DIGIT TWO +0F22 ; [.0FC8.0020.0002.0F22][.0000.01B1.0002.0F22] # TIBETAN DIGIT TWO +0F2B ; [.0FC8.0020.0004.0F2B][.0000.01B1.0004.0F2B] # TIBETAN DIGIT HALF TWO; QQK +1042 ; [.0FC8.0020.0002.1042][.0000.01B2.0002.1042] # MYANMAR DIGIT TWO +17E2 ; [.0FC8.0020.0002.17E2][.0000.01B3.0002.17E2] # KHMER DIGIT TWO +17F2 ; [.0FC8.0020.0002.17F2][.0000.01B4.0002.17F2] # KHMER SYMBOL LEK ATTAK PII +1B52 ; [.0FC8.0020.0002.1B52][.0000.01B5.0002.1B52] # BALINESE DIGIT TWO +1812 ; [.0FC8.0020.0002.1812][.0000.01B6.0002.1812] # MONGOLIAN DIGIT TWO +3022 ; [.0FC8.0020.0002.3022][.0000.01B7.0002.3022] # HANGZHOU NUMERAL TWO +10108 ; [.0FC8.0020.0002.10108][.0000.01B8.0002.10108] # AEGEAN NUMBER TWO +1015B ; [.0FC8.0020.0002.1015B][.0000.01B9.0002.1015B] # GREEK ACROPHONIC EPIDAUREAN TWO +1015C ; [.0FC8.0020.0002.1015C][.0000.01B9.0002.1015C] # GREEK ACROPHONIC THESPIAN TWO +1015D ; [.0FC8.0020.0002.1015D][.0000.01B9.0002.1015D] # GREEK ACROPHONIC CYRENAIC TWO DRACHMAS +1015E ; [.0FC8.0020.0002.1015E][.0000.01B9.0002.1015E] # GREEK ACROPHONIC EPIDAUREAN TWO DRACHMAS +103D2 ; [.0FC8.0020.0002.103D2][.0000.01BB.0002.103D2] # OLD PERSIAN NUMBER TWO +12400 ; [.0FC8.0020.0002.12400][.0000.01BC.0002.12400] # CUNEIFORM NUMERIC SIGN TWO ASH +12416 ; [.0FC8.0020.0002.12416][.0000.01BC.0002.12416] # CUNEIFORM NUMERIC SIGN TWO GESH2 +1241F ; [.0FC8.0020.0002.1241F][.0000.01BC.0002.1241F] # CUNEIFORM NUMERIC SIGN TWO GESHU +12423 ; [.0FC8.0020.0002.12423][.0000.01BC.0002.12423] # CUNEIFORM NUMERIC SIGN TWO SHAR2 +1242D ; [.0FC8.0020.0002.1242D][.0000.01BC.0002.1242D] # CUNEIFORM NUMERIC SIGN TWO SHARU +12435 ; [.0FC8.0020.0002.12435][.0000.01BC.0002.12435] # CUNEIFORM NUMERIC SIGN TWO BURU +1244A ; [.0FC8.0020.0002.1244A][.0000.01BC.0002.1244A] # CUNEIFORM NUMERIC SIGN TWO ASH TENU +12450 ; [.0FC8.0020.0002.12450][.0000.01BC.0002.12450] # CUNEIFORM NUMERIC SIGN TWO BAN2 +12459 ; [.0FC8.0020.0002.12459][.0000.01BC.0002.12459] # CUNEIFORM NUMERIC SIGN TWO ESHE3 +10A41 ; [.0FC8.0020.0002.10A41][.0000.01BE.0002.10A41] # KHAROSHTHI DIGIT TWO +1D361 ; [.0FC8.0020.0002.1D361][.0000.01BF.0002.1D361] # COUNTING ROD UNIT DIGIT TWO +249B ; [.0FC8.0020.0004.249B][.0FC6.0020.0004.249B][*0266.0020.001F.249B] # NUMBER TWENTY FULL STOP; QQKN +2487 ; [*02B1.0020.0004.2487][.0FC8.0020.0004.2487][.0FC6.0020.001F.2487][*02B2.0020.001F.2487] # PARENTHESIZED NUMBER TWENTY; QQKN +2473 ; [.0FC8.0020.0006.2473][.0FC6.0020.0006.2473] # CIRCLED NUMBER TWENTY; QQKN +24F4 ; [.0FC8.0020.0006.24F4][.0FC6.0020.0006.24F4] # NEGATIVE CIRCLED NUMBER TWENTY; QQKN +33F3 ; [.0FC8.0020.0004.33F3][.0FC6.0020.0004.33F3][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY; QQKN +336C ; [.0FC8.0020.0004.336C][.0FC6.0020.0004.336C][.FB40.0020.001F.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY; QQKN +3251 ; [.0FC8.0020.0006.3251][.0FC7.0020.0006.3251] # CIRCLED NUMBER TWENTY ONE; QQKN +33F4 ; [.0FC8.0020.0004.33F4][.0FC7.0020.0004.33F4][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-ONE; QQKN +336D ; [.0FC8.0020.0004.336D][.0FC7.0020.0004.336D][.FB40.0020.001F.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-ONE; QQKN +3252 ; [.0FC8.0020.0006.3252][.0FC8.0020.0006.3252] # CIRCLED NUMBER TWENTY TWO; QQKN +33F5 ; [.0FC8.0020.0004.33F5][.0FC8.0020.0004.33F5][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-TWO; QQKN +336E ; [.0FC8.0020.0004.336E][.0FC8.0020.0004.336E][.FB40.0020.001F.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-TWO; QQKN +3253 ; [.0FC8.0020.0006.3253][.0FC9.0020.0006.3253] # CIRCLED NUMBER TWENTY THREE; QQKN +2154 ; [.0FC8.0020.001E.2154][*0300.0020.001E.2154][.0FC9.0020.001F.2154] # VULGAR FRACTION TWO THIRDS; QQKN +33F6 ; [.0FC8.0020.0004.33F6][.0FC9.0020.0004.33F6][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-THREE; QQKN +336F ; [.0FC8.0020.0004.336F][.0FC9.0020.0004.336F][.FB40.0020.001F.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-THREE; QQKN +3254 ; [.0FC8.0020.0006.3254][.0FCA.0020.0006.3254] # CIRCLED NUMBER TWENTY FOUR; QQKN +33F7 ; [.0FC8.0020.0004.33F7][.0FCA.0020.0004.33F7][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FOUR; QQKN +3370 ; [.0FC8.0020.0004.3370][.0FCA.0020.0004.3370][.FB40.0020.001F.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOUR; QQKN +3255 ; [.0FC8.0020.0006.3255][.0FCB.0020.0006.3255] # CIRCLED NUMBER TWENTY FIVE; QQKN +2156 ; [.0FC8.0020.001E.2156][*0300.0020.001E.2156][.0FCB.0020.001F.2156] # VULGAR FRACTION TWO FIFTHS; QQKN +33F8 ; [.0FC8.0020.0004.33F8][.0FCB.0020.0004.33F8][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FIVE; QQKN +3256 ; [.0FC8.0020.0006.3256][.0FCC.0020.0006.3256] # CIRCLED NUMBER TWENTY SIX; QQKN +33F9 ; [.0FC8.0020.0004.33F9][.0FCC.0020.0004.33F9][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SIX; QQKN +3257 ; [.0FC8.0020.0006.3257][.0FCD.0020.0006.3257] # CIRCLED NUMBER TWENTY SEVEN; QQKN +33FA ; [.0FC8.0020.0004.33FA][.0FCD.0020.0004.33FA][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SEVEN; QQKN +3258 ; [.0FC8.0020.0006.3258][.0FCE.0020.0006.3258] # CIRCLED NUMBER TWENTY EIGHT; QQKN +33FB ; [.0FC8.0020.0004.33FB][.0FCE.0020.0004.33FB][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-EIGHT; QQKN +3259 ; [.0FC8.0020.0006.3259][.0FCF.0020.0006.3259] # CIRCLED NUMBER TWENTY NINE; QQKN +33FC ; [.0FC8.0020.0004.33FC][.0FCF.0020.0004.33FC][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-NINE; QQKN +33E1 ; [.0FC8.0020.0004.33E1][.FB40.0020.0004.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWO; QQKN +32C1 ; [.0FC8.0020.0004.32C1][.FB40.0020.0004.6708][.E708.0000.0000.6708] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR FEBRUARY; QQKN +335A ; [.0FC8.0020.0004.335A][.FB40.0020.0004.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWO; QQKN +0033 ; [.0FC9.0020.0002.0033] # DIGIT THREE +FF13 ; [.0FC9.0020.0003.FF13] # FULLWIDTH DIGIT THREE; QQK +2476 ; [*02B1.0020.0004.2476][.0FC9.0020.0004.2476][*02B2.0020.001F.2476] # PARENTHESIZED DIGIT THREE; QQKN +248A ; [.0FC9.0020.0004.248A][*0266.0020.0004.248A] # DIGIT THREE FULL STOP; QQKN +1D7D1 ; [.0FC9.0020.0005.1D7D1] # MATHEMATICAL BOLD DIGIT THREE; QQK +1D7DB ; [.0FC9.0020.0005.1D7DB] # MATHEMATICAL DOUBLE-STRUCK DIGIT THREE; QQK +1D7E5 ; [.0FC9.0020.0005.1D7E5] # MATHEMATICAL SANS-SERIF DIGIT THREE; QQK +1D7EF ; [.0FC9.0020.0005.1D7EF] # MATHEMATICAL SANS-SERIF BOLD DIGIT THREE; QQK +1D7F9 ; [.0FC9.0020.0005.1D7F9] # MATHEMATICAL MONOSPACE DIGIT THREE; QQK +2462 ; [.0FC9.0020.0006.2462] # CIRCLED DIGIT THREE; QQK +24F7 ; [.0FC9.0020.0006.24F7] # DOUBLE CIRCLED DIGIT THREE; QQK +2778 ; [.0FC9.0020.0006.2778] # DINGBAT NEGATIVE CIRCLED DIGIT THREE; QQK +2782 ; [.0FC9.0020.0006.2782] # DINGBAT CIRCLED SANS-SERIF DIGIT THREE; QQK +278C ; [.0FC9.0020.0006.278C] # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE; QQK +00B3 ; [.0FC9.0020.0014.00B3] # SUPERSCRIPT THREE; QQK +2083 ; [.0FC9.0020.0015.2083] # SUBSCRIPT THREE; QQK +0663 ; [.0FC9.0020.0002.0663][.0000.019F.0002.0663] # ARABIC-INDIC DIGIT THREE +06F3 ; [.0FC9.0020.0002.06F3][.0000.01A0.0002.06F3] # EXTENDED ARABIC-INDIC DIGIT THREE +07C3 ; [.0FC9.0020.0002.07C3][.0000.01A1.0002.07C3] # NKO DIGIT THREE +136B ; [.0FC9.0020.0002.136B][.0000.01A2.0002.136B] # ETHIOPIC DIGIT THREE +104A3 ; [.0FC9.0020.0002.104A3][.0000.01A3.0002.104A3] # OSMANYA DIGIT THREE +0969 ; [.0FC9.0020.0002.0969][.0000.01A4.0002.0969] # DEVANAGARI DIGIT THREE +09E9 ; [.0FC9.0020.0002.09E9][.0000.01A5.0002.09E9] # BENGALI DIGIT THREE +09F6 ; [.0FC9.0020.0002.09F6][.0000.01A5.0002.09F6] # BENGALI CURRENCY NUMERATOR THREE +0A69 ; [.0FC9.0020.0002.0A69][.0000.01A6.0002.0A69] # GURMUKHI DIGIT THREE +0AE9 ; [.0FC9.0020.0002.0AE9][.0000.01A7.0002.0AE9] # GUJARATI DIGIT THREE +0B69 ; [.0FC9.0020.0002.0B69][.0000.01A8.0002.0B69] # ORIYA DIGIT THREE +0BE9 ; [.0FC9.0020.0002.0BE9][.0000.01A9.0002.0BE9] # TAMIL DIGIT THREE +0C69 ; [.0FC9.0020.0002.0C69][.0000.01AA.0002.0C69] # TELUGU DIGIT THREE +0CE9 ; [.0FC9.0020.0002.0CE9][.0000.01AB.0002.0CE9] # KANNADA DIGIT THREE +0D69 ; [.0FC9.0020.0002.0D69][.0000.01AC.0002.0D69] # MALAYALAM DIGIT THREE +1949 ; [.0FC9.0020.0002.1949][.0000.01AD.0002.1949] # LIMBU DIGIT THREE +19D3 ; [.0FC9.0020.0002.19D3][.0000.01AE.0002.19D3] # NEW TAI LUE DIGIT THREE +0E53 ; [.0FC9.0020.0002.0E53][.0000.01AF.0002.0E53] # THAI DIGIT THREE +0ED3 ; [.0FC9.0020.0002.0ED3][.0000.01B0.0002.0ED3] # LAO DIGIT THREE +0F23 ; [.0FC9.0020.0002.0F23][.0000.01B1.0002.0F23] # TIBETAN DIGIT THREE +0F2C ; [.0FC9.0020.0004.0F2C][.0000.01B1.0004.0F2C] # TIBETAN DIGIT HALF THREE; QQK +1043 ; [.0FC9.0020.0002.1043][.0000.01B2.0002.1043] # MYANMAR DIGIT THREE +17E3 ; [.0FC9.0020.0002.17E3][.0000.01B3.0002.17E3] # KHMER DIGIT THREE +17F3 ; [.0FC9.0020.0002.17F3][.0000.01B4.0002.17F3] # KHMER SYMBOL LEK ATTAK BEI +1B53 ; [.0FC9.0020.0002.1B53][.0000.01B5.0002.1B53] # BALINESE DIGIT THREE +1813 ; [.0FC9.0020.0002.1813][.0000.01B6.0002.1813] # MONGOLIAN DIGIT THREE +3023 ; [.0FC9.0020.0002.3023][.0000.01B7.0002.3023] # HANGZHOU NUMERAL THREE +10109 ; [.0FC9.0020.0002.10109][.0000.01B8.0002.10109] # AEGEAN NUMBER THREE +12401 ; [.0FC9.0020.0002.12401][.0000.01BC.0002.12401] # CUNEIFORM NUMERIC SIGN THREE ASH +12408 ; [.0FC9.0020.0002.12408][.0000.01BC.0002.12408] # CUNEIFORM NUMERIC SIGN THREE DISH +12417 ; [.0FC9.0020.0002.12417][.0000.01BC.0002.12417] # CUNEIFORM NUMERIC SIGN THREE GESH2 +12420 ; [.0FC9.0020.0002.12420][.0000.01BC.0002.12420] # CUNEIFORM NUMERIC SIGN THREE GESHU +12424 ; [.0FC9.0020.0002.12424][.0000.01BC.0002.12424] # CUNEIFORM NUMERIC SIGN THREE SHAR2 +12425 ; [.0FC9.0020.0002.12425][.0000.01BC.0002.12425] # CUNEIFORM NUMERIC SIGN THREE SHAR2 VARIANT FORM +1242E ; [.0FC9.0020.0002.1242E][.0000.01BC.0002.1242E] # CUNEIFORM NUMERIC SIGN THREE SHARU +1242F ; [.0FC9.0020.0002.1242F][.0000.01BC.0002.1242F] # CUNEIFORM NUMERIC SIGN THREE SHARU VARIANT FORM +12436 ; [.0FC9.0020.0002.12436][.0000.01BC.0002.12436] # CUNEIFORM NUMERIC SIGN THREE BURU +12437 ; [.0FC9.0020.0002.12437][.0000.01BC.0002.12437] # CUNEIFORM NUMERIC SIGN THREE BURU VARIANT FORM +1243A ; [.0FC9.0020.0002.1243A][.0000.01BC.0002.1243A] # CUNEIFORM NUMERIC SIGN THREE VARIANT FORM ESH16 +1243B ; [.0FC9.0020.0002.1243B][.0000.01BC.0002.1243B] # CUNEIFORM NUMERIC SIGN THREE VARIANT FORM ESH21 +1244B ; [.0FC9.0020.0002.1244B][.0000.01BC.0002.1244B] # CUNEIFORM NUMERIC SIGN THREE ASH TENU +12451 ; [.0FC9.0020.0002.12451][.0000.01BC.0002.12451] # CUNEIFORM NUMERIC SIGN THREE BAN2 +10A42 ; [.0FC9.0020.0002.10A42][.0000.01BE.0002.10A42] # KHAROSHTHI DIGIT THREE +1D362 ; [.0FC9.0020.0002.1D362][.0000.01BF.0002.1D362] # COUNTING ROD UNIT DIGIT THREE +325A ; [.0FC9.0020.0006.325A][.0FC6.0020.0006.325A] # CIRCLED NUMBER THIRTY; QQKN +33FD ; [.0FC9.0020.0004.33FD][.0FC6.0020.0004.33FD][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY; QQKN +325B ; [.0FC9.0020.0006.325B][.0FC7.0020.0006.325B] # CIRCLED NUMBER THIRTY ONE; QQKN +33FE ; [.0FC9.0020.0004.33FE][.0FC7.0020.0004.33FE][.FB40.0020.001F.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE; QQKN +325C ; [.0FC9.0020.0006.325C][.0FC8.0020.0006.325C] # CIRCLED NUMBER THIRTY TWO; QQKN +325D ; [.0FC9.0020.0006.325D][.0FC9.0020.0006.325D] # CIRCLED NUMBER THIRTY THREE; QQKN +325E ; [.0FC9.0020.0006.325E][.0FCA.0020.0006.325E] # CIRCLED NUMBER THIRTY FOUR; QQKN +00BE ; [.0FC9.0020.001E.00BE][*0300.0020.001E.00BE][.0FCA.0020.001F.00BE] # VULGAR FRACTION THREE QUARTERS; QQKN +325F ; [.0FC9.0020.0006.325F][.0FCB.0020.0006.325F] # CIRCLED NUMBER THIRTY FIVE; QQKN +2157 ; [.0FC9.0020.001E.2157][*0300.0020.001E.2157][.0FCB.0020.001F.2157] # VULGAR FRACTION THREE FIFTHS; QQKN +32B1 ; [.0FC9.0020.0006.32B1][.0FCC.0020.0006.32B1] # CIRCLED NUMBER THIRTY SIX; QQKN +32B2 ; [.0FC9.0020.0006.32B2][.0FCD.0020.0006.32B2] # CIRCLED NUMBER THIRTY SEVEN; QQKN +32B3 ; [.0FC9.0020.0006.32B3][.0FCE.0020.0006.32B3] # CIRCLED NUMBER THIRTY EIGHT; QQKN +215C ; [.0FC9.0020.001E.215C][*0300.0020.001E.215C][.0FCE.0020.001F.215C] # VULGAR FRACTION THREE EIGHTHS; QQKN +32B4 ; [.0FC9.0020.0006.32B4][.0FCF.0020.0006.32B4] # CIRCLED NUMBER THIRTY NINE; QQKN +33E2 ; [.0FC9.0020.0004.33E2][.FB40.0020.0004.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THREE; QQKN +32C2 ; [.0FC9.0020.0004.32C2][.FB40.0020.0004.6708][.E708.0000.0000.6708] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR MARCH; QQKN +335B ; [.0FC9.0020.0004.335B][.FB40.0020.0004.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THREE; QQKN +0034 ; [.0FCA.0020.0002.0034] # DIGIT FOUR +FF14 ; [.0FCA.0020.0003.FF14] # FULLWIDTH DIGIT FOUR; QQK +2477 ; [*02B1.0020.0004.2477][.0FCA.0020.0004.2477][*02B2.0020.001F.2477] # PARENTHESIZED DIGIT FOUR; QQKN +248B ; [.0FCA.0020.0004.248B][*0266.0020.0004.248B] # DIGIT FOUR FULL STOP; QQKN +1D7D2 ; [.0FCA.0020.0005.1D7D2] # MATHEMATICAL BOLD DIGIT FOUR; QQK +1D7DC ; [.0FCA.0020.0005.1D7DC] # MATHEMATICAL DOUBLE-STRUCK DIGIT FOUR; QQK +1D7E6 ; [.0FCA.0020.0005.1D7E6] # MATHEMATICAL SANS-SERIF DIGIT FOUR; QQK +1D7F0 ; [.0FCA.0020.0005.1D7F0] # MATHEMATICAL SANS-SERIF BOLD DIGIT FOUR; QQK +1D7FA ; [.0FCA.0020.0005.1D7FA] # MATHEMATICAL MONOSPACE DIGIT FOUR; QQK +2463 ; [.0FCA.0020.0006.2463] # CIRCLED DIGIT FOUR; QQK +24F8 ; [.0FCA.0020.0006.24F8] # DOUBLE CIRCLED DIGIT FOUR; QQK +2779 ; [.0FCA.0020.0006.2779] # DINGBAT NEGATIVE CIRCLED DIGIT FOUR; QQK +2783 ; [.0FCA.0020.0006.2783] # DINGBAT CIRCLED SANS-SERIF DIGIT FOUR; QQK +278D ; [.0FCA.0020.0006.278D] # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR; QQK +2074 ; [.0FCA.0020.0014.2074] # SUPERSCRIPT FOUR; QQK +2084 ; [.0FCA.0020.0015.2084] # SUBSCRIPT FOUR; QQK +0664 ; [.0FCA.0020.0002.0664][.0000.019F.0002.0664] # ARABIC-INDIC DIGIT FOUR +06F4 ; [.0FCA.0020.0002.06F4][.0000.01A0.0002.06F4] # EXTENDED ARABIC-INDIC DIGIT FOUR +07C4 ; [.0FCA.0020.0002.07C4][.0000.01A1.0002.07C4] # NKO DIGIT FOUR +136C ; [.0FCA.0020.0002.136C][.0000.01A2.0002.136C] # ETHIOPIC DIGIT FOUR +104A4 ; [.0FCA.0020.0002.104A4][.0000.01A3.0002.104A4] # OSMANYA DIGIT FOUR +096A ; [.0FCA.0020.0002.096A][.0000.01A4.0002.096A] # DEVANAGARI DIGIT FOUR +09EA ; [.0FCA.0020.0002.09EA][.0000.01A5.0002.09EA] # BENGALI DIGIT FOUR +09F7 ; [.0FCA.0020.0002.09F7][.0000.01A5.0002.09F7] # BENGALI CURRENCY NUMERATOR FOUR +0A6A ; [.0FCA.0020.0002.0A6A][.0000.01A6.0002.0A6A] # GURMUKHI DIGIT FOUR +0AEA ; [.0FCA.0020.0002.0AEA][.0000.01A7.0002.0AEA] # GUJARATI DIGIT FOUR +0B6A ; [.0FCA.0020.0002.0B6A][.0000.01A8.0002.0B6A] # ORIYA DIGIT FOUR +0BEA ; [.0FCA.0020.0002.0BEA][.0000.01A9.0002.0BEA] # TAMIL DIGIT FOUR +0C6A ; [.0FCA.0020.0002.0C6A][.0000.01AA.0002.0C6A] # TELUGU DIGIT FOUR +0CEA ; [.0FCA.0020.0002.0CEA][.0000.01AB.0002.0CEA] # KANNADA DIGIT FOUR +0D6A ; [.0FCA.0020.0002.0D6A][.0000.01AC.0002.0D6A] # MALAYALAM DIGIT FOUR +194A ; [.0FCA.0020.0002.194A][.0000.01AD.0002.194A] # LIMBU DIGIT FOUR +19D4 ; [.0FCA.0020.0002.19D4][.0000.01AE.0002.19D4] # NEW TAI LUE DIGIT FOUR +0E54 ; [.0FCA.0020.0002.0E54][.0000.01AF.0002.0E54] # THAI DIGIT FOUR +0ED4 ; [.0FCA.0020.0002.0ED4][.0000.01B0.0002.0ED4] # LAO DIGIT FOUR +0F24 ; [.0FCA.0020.0002.0F24][.0000.01B1.0002.0F24] # TIBETAN DIGIT FOUR +0F2D ; [.0FCA.0020.0004.0F2D][.0000.01B1.0004.0F2D] # TIBETAN DIGIT HALF FOUR; QQK +1044 ; [.0FCA.0020.0002.1044][.0000.01B2.0002.1044] # MYANMAR DIGIT FOUR +17E4 ; [.0FCA.0020.0002.17E4][.0000.01B3.0002.17E4] # KHMER DIGIT FOUR +17F4 ; [.0FCA.0020.0002.17F4][.0000.01B4.0002.17F4] # KHMER SYMBOL LEK ATTAK BUON +1B54 ; [.0FCA.0020.0002.1B54][.0000.01B5.0002.1B54] # BALINESE DIGIT FOUR +1814 ; [.0FCA.0020.0002.1814][.0000.01B6.0002.1814] # MONGOLIAN DIGIT FOUR +3024 ; [.0FCA.0020.0002.3024][.0000.01B7.0002.3024] # HANGZHOU NUMERAL FOUR +1010A ; [.0FCA.0020.0002.1010A][.0000.01B8.0002.1010A] # AEGEAN NUMBER FOUR +12402 ; [.0FCA.0020.0002.12402][.0000.01BC.0002.12402] # CUNEIFORM NUMERIC SIGN FOUR ASH +12409 ; [.0FCA.0020.0002.12409][.0000.01BC.0002.12409] # CUNEIFORM NUMERIC SIGN FOUR DISH +1240F ; [.0FCA.0020.0002.1240F][.0000.01BC.0002.1240F] # CUNEIFORM NUMERIC SIGN FOUR U +12418 ; [.0FCA.0020.0002.12418][.0000.01BC.0002.12418] # CUNEIFORM NUMERIC SIGN FOUR GESH2 +12421 ; [.0FCA.0020.0002.12421][.0000.01BC.0002.12421] # CUNEIFORM NUMERIC SIGN FOUR GESHU +12426 ; [.0FCA.0020.0002.12426][.0000.01BC.0002.12426] # CUNEIFORM NUMERIC SIGN FOUR SHAR2 +12430 ; [.0FCA.0020.0002.12430][.0000.01BC.0002.12430] # CUNEIFORM NUMERIC SIGN FOUR SHARU +12438 ; [.0FCA.0020.0002.12438][.0000.01BC.0002.12438] # CUNEIFORM NUMERIC SIGN FOUR BURU +1243C ; [.0FCA.0020.0002.1243C][.0000.01BC.0002.1243C] # CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU +1243D ; [.0FCA.0020.0002.1243D][.0000.01BC.0002.1243D] # CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU4 +1243E ; [.0FCA.0020.0002.1243E][.0000.01BC.0002.1243E] # CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU A +1243F ; [.0FCA.0020.0002.1243F][.0000.01BC.0002.1243F] # CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU B +1244C ; [.0FCA.0020.0002.1244C][.0000.01BC.0002.1244C] # CUNEIFORM NUMERIC SIGN FOUR ASH TENU +12452 ; [.0FCA.0020.0002.12452][.0000.01BC.0002.12452] # CUNEIFORM NUMERIC SIGN FOUR BAN2 +12453 ; [.0FCA.0020.0002.12453][.0000.01BC.0002.12453] # CUNEIFORM NUMERIC SIGN FOUR BAN2 VARIANT FORM +10A43 ; [.0FCA.0020.0002.10A43][.0000.01BE.0002.10A43] # KHAROSHTHI DIGIT FOUR +1D363 ; [.0FCA.0020.0002.1D363][.0000.01BF.0002.1D363] # COUNTING ROD UNIT DIGIT FOUR +32B5 ; [.0FCA.0020.0006.32B5][.0FC6.0020.0006.32B5] # CIRCLED NUMBER FORTY; QQKN +32B6 ; [.0FCA.0020.0006.32B6][.0FC7.0020.0006.32B6] # CIRCLED NUMBER FORTY ONE; QQKN +32B7 ; [.0FCA.0020.0006.32B7][.0FC8.0020.0006.32B7] # CIRCLED NUMBER FORTY TWO; QQKN +32B8 ; [.0FCA.0020.0006.32B8][.0FC9.0020.0006.32B8] # CIRCLED NUMBER FORTY THREE; QQKN +32B9 ; [.0FCA.0020.0006.32B9][.0FCA.0020.0006.32B9] # CIRCLED NUMBER FORTY FOUR; QQKN +32BA ; [.0FCA.0020.0006.32BA][.0FCB.0020.0006.32BA] # CIRCLED NUMBER FORTY FIVE; QQKN +2158 ; [.0FCA.0020.001E.2158][*0300.0020.001E.2158][.0FCB.0020.001F.2158] # VULGAR FRACTION FOUR FIFTHS; QQKN +32BB ; [.0FCA.0020.0006.32BB][.0FCC.0020.0006.32BB] # CIRCLED NUMBER FORTY SIX; QQKN +32BC ; [.0FCA.0020.0006.32BC][.0FCD.0020.0006.32BC] # CIRCLED NUMBER FORTY SEVEN; QQKN +32BD ; [.0FCA.0020.0006.32BD][.0FCE.0020.0006.32BD] # CIRCLED NUMBER FORTY EIGHT; QQKN +32BE ; [.0FCA.0020.0006.32BE][.0FCF.0020.0006.32BE] # CIRCLED NUMBER FORTY NINE; QQKN +33E3 ; [.0FCA.0020.0004.33E3][.FB40.0020.0004.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOUR; QQKN +32C3 ; [.0FCA.0020.0004.32C3][.FB40.0020.0004.6708][.E708.0000.0000.6708] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR APRIL; QQKN +335C ; [.0FCA.0020.0004.335C][.FB40.0020.0004.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOUR; QQKN +0035 ; [.0FCB.0020.0002.0035] # DIGIT FIVE +FF15 ; [.0FCB.0020.0003.FF15] # FULLWIDTH DIGIT FIVE; QQK +2478 ; [*02B1.0020.0004.2478][.0FCB.0020.0004.2478][*02B2.0020.001F.2478] # PARENTHESIZED DIGIT FIVE; QQKN +248C ; [.0FCB.0020.0004.248C][*0266.0020.0004.248C] # DIGIT FIVE FULL STOP; QQKN +1D7D3 ; [.0FCB.0020.0005.1D7D3] # MATHEMATICAL BOLD DIGIT FIVE; QQK +1D7DD ; [.0FCB.0020.0005.1D7DD] # MATHEMATICAL DOUBLE-STRUCK DIGIT FIVE; QQK +1D7E7 ; [.0FCB.0020.0005.1D7E7] # MATHEMATICAL SANS-SERIF DIGIT FIVE; QQK +1D7F1 ; [.0FCB.0020.0005.1D7F1] # MATHEMATICAL SANS-SERIF BOLD DIGIT FIVE; QQK +1D7FB ; [.0FCB.0020.0005.1D7FB] # MATHEMATICAL MONOSPACE DIGIT FIVE; QQK +2464 ; [.0FCB.0020.0006.2464] # CIRCLED DIGIT FIVE; QQK +24F9 ; [.0FCB.0020.0006.24F9] # DOUBLE CIRCLED DIGIT FIVE; QQK +277A ; [.0FCB.0020.0006.277A] # DINGBAT NEGATIVE CIRCLED DIGIT FIVE; QQK +2784 ; [.0FCB.0020.0006.2784] # DINGBAT CIRCLED SANS-SERIF DIGIT FIVE; QQK +278E ; [.0FCB.0020.0006.278E] # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE; QQK +2075 ; [.0FCB.0020.0014.2075] # SUPERSCRIPT FIVE; QQK +2085 ; [.0FCB.0020.0015.2085] # SUBSCRIPT FIVE; QQK +0665 ; [.0FCB.0020.0002.0665][.0000.019F.0002.0665] # ARABIC-INDIC DIGIT FIVE +06F5 ; [.0FCB.0020.0002.06F5][.0000.01A0.0002.06F5] # EXTENDED ARABIC-INDIC DIGIT FIVE +07C5 ; [.0FCB.0020.0002.07C5][.0000.01A1.0002.07C5] # NKO DIGIT FIVE +136D ; [.0FCB.0020.0002.136D][.0000.01A2.0002.136D] # ETHIOPIC DIGIT FIVE +104A5 ; [.0FCB.0020.0002.104A5][.0000.01A3.0002.104A5] # OSMANYA DIGIT FIVE +096B ; [.0FCB.0020.0002.096B][.0000.01A4.0002.096B] # DEVANAGARI DIGIT FIVE +09EB ; [.0FCB.0020.0002.09EB][.0000.01A5.0002.09EB] # BENGALI DIGIT FIVE +0A6B ; [.0FCB.0020.0002.0A6B][.0000.01A6.0002.0A6B] # GURMUKHI DIGIT FIVE +0AEB ; [.0FCB.0020.0002.0AEB][.0000.01A7.0002.0AEB] # GUJARATI DIGIT FIVE +0B6B ; [.0FCB.0020.0002.0B6B][.0000.01A8.0002.0B6B] # ORIYA DIGIT FIVE +0BEB ; [.0FCB.0020.0002.0BEB][.0000.01A9.0002.0BEB] # TAMIL DIGIT FIVE +0C6B ; [.0FCB.0020.0002.0C6B][.0000.01AA.0002.0C6B] # TELUGU DIGIT FIVE +0CEB ; [.0FCB.0020.0002.0CEB][.0000.01AB.0002.0CEB] # KANNADA DIGIT FIVE +0D6B ; [.0FCB.0020.0002.0D6B][.0000.01AC.0002.0D6B] # MALAYALAM DIGIT FIVE +194B ; [.0FCB.0020.0002.194B][.0000.01AD.0002.194B] # LIMBU DIGIT FIVE +19D5 ; [.0FCB.0020.0002.19D5][.0000.01AE.0002.19D5] # NEW TAI LUE DIGIT FIVE +0E55 ; [.0FCB.0020.0002.0E55][.0000.01AF.0002.0E55] # THAI DIGIT FIVE +0ED5 ; [.0FCB.0020.0002.0ED5][.0000.01B0.0002.0ED5] # LAO DIGIT FIVE +0F25 ; [.0FCB.0020.0002.0F25][.0000.01B1.0002.0F25] # TIBETAN DIGIT FIVE +0F2E ; [.0FCB.0020.0004.0F2E][.0000.01B1.0004.0F2E] # TIBETAN DIGIT HALF FIVE; QQK +1045 ; [.0FCB.0020.0002.1045][.0000.01B2.0002.1045] # MYANMAR DIGIT FIVE +17E5 ; [.0FCB.0020.0002.17E5][.0000.01B3.0002.17E5] # KHMER DIGIT FIVE +17F5 ; [.0FCB.0020.0002.17F5][.0000.01B4.0002.17F5] # KHMER SYMBOL LEK ATTAK PRAM +1B55 ; [.0FCB.0020.0002.1B55][.0000.01B5.0002.1B55] # BALINESE DIGIT FIVE +1815 ; [.0FCB.0020.0002.1815][.0000.01B6.0002.1815] # MONGOLIAN DIGIT FIVE +3025 ; [.0FCB.0020.0002.3025][.0000.01B7.0002.3025] # HANGZHOU NUMERAL FIVE +1010B ; [.0FCB.0020.0002.1010B][.0000.01B8.0002.1010B] # AEGEAN NUMBER FIVE +10143 ; [.0FCB.0020.0002.10143][.0000.01B9.0002.10143] # GREEK ACROPHONIC ATTIC FIVE +10148 ; [.0FCB.0020.0002.10148][.0000.01B9.0002.10148] # GREEK ACROPHONIC ATTIC FIVE TALENTS +1014F ; [.0FCB.0020.0002.1014F][.0000.01B9.0002.1014F] # GREEK ACROPHONIC ATTIC FIVE STATERS +1015F ; [.0FCB.0020.0002.1015F][.0000.01B9.0002.1015F] # GREEK ACROPHONIC TROEZENIAN FIVE +10173 ; [.0FCB.0020.0002.10173][.0000.01B9.0002.10173] # GREEK ACROPHONIC DELPHIC FIVE MNAS +10321 ; [.0FCB.0020.0002.10321][.0000.01BA.0002.10321] # OLD ITALIC NUMERAL FIVE +12403 ; [.0FCB.0020.0002.12403][.0000.01BC.0002.12403] # CUNEIFORM NUMERIC SIGN FIVE ASH +1240A ; [.0FCB.0020.0002.1240A][.0000.01BC.0002.1240A] # CUNEIFORM NUMERIC SIGN FIVE DISH +12410 ; [.0FCB.0020.0002.12410][.0000.01BC.0002.12410] # CUNEIFORM NUMERIC SIGN FIVE U +12419 ; [.0FCB.0020.0002.12419][.0000.01BC.0002.12419] # CUNEIFORM NUMERIC SIGN FIVE GESH2 +12422 ; [.0FCB.0020.0002.12422][.0000.01BC.0002.12422] # CUNEIFORM NUMERIC SIGN FIVE GESHU +12427 ; [.0FCB.0020.0002.12427][.0000.01BC.0002.12427] # CUNEIFORM NUMERIC SIGN FIVE SHAR2 +12431 ; [.0FCB.0020.0002.12431][.0000.01BC.0002.12431] # CUNEIFORM NUMERIC SIGN FIVE SHARU +12439 ; [.0FCB.0020.0002.12439][.0000.01BC.0002.12439] # CUNEIFORM NUMERIC SIGN FIVE BURU +1244D ; [.0FCB.0020.0002.1244D][.0000.01BC.0002.1244D] # CUNEIFORM NUMERIC SIGN FIVE ASH TENU +12454 ; [.0FCB.0020.0002.12454][.0000.01BC.0002.12454] # CUNEIFORM NUMERIC SIGN FIVE BAN2 +12455 ; [.0FCB.0020.0002.12455][.0000.01BC.0002.12455] # CUNEIFORM NUMERIC SIGN FIVE BAN2 VARIANT FORM +1D364 ; [.0FCB.0020.0002.1D364][.0000.01BF.0002.1D364] # COUNTING ROD UNIT DIGIT FIVE +32BF ; [.0FCB.0020.0006.32BF][.0FC6.0020.0006.32BF] # CIRCLED NUMBER FIFTY; QQKN +215A ; [.0FCB.0020.001E.215A][*0300.0020.001E.215A][.0FCC.0020.001F.215A] # VULGAR FRACTION FIVE SIXTHS; QQKN +215D ; [.0FCB.0020.001E.215D][*0300.0020.001E.215D][.0FCE.0020.001F.215D] # VULGAR FRACTION FIVE EIGHTHS; QQKN +33E4 ; [.0FCB.0020.0004.33E4][.FB40.0020.0004.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIVE; QQKN +32C4 ; [.0FCB.0020.0004.32C4][.FB40.0020.0004.6708][.E708.0000.0000.6708] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR MAY; QQKN +335D ; [.0FCB.0020.0004.335D][.FB40.0020.0004.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIVE; QQKN +0036 ; [.0FCC.0020.0002.0036] # DIGIT SIX +FF16 ; [.0FCC.0020.0003.FF16] # FULLWIDTH DIGIT SIX; QQK +2479 ; [*02B1.0020.0004.2479][.0FCC.0020.0004.2479][*02B2.0020.001F.2479] # PARENTHESIZED DIGIT SIX; QQKN +248D ; [.0FCC.0020.0004.248D][*0266.0020.0004.248D] # DIGIT SIX FULL STOP; QQKN +1D7D4 ; [.0FCC.0020.0005.1D7D4] # MATHEMATICAL BOLD DIGIT SIX; QQK +1D7DE ; [.0FCC.0020.0005.1D7DE] # MATHEMATICAL DOUBLE-STRUCK DIGIT SIX; QQK +1D7E8 ; [.0FCC.0020.0005.1D7E8] # MATHEMATICAL SANS-SERIF DIGIT SIX; QQK +1D7F2 ; [.0FCC.0020.0005.1D7F2] # MATHEMATICAL SANS-SERIF BOLD DIGIT SIX; QQK +1D7FC ; [.0FCC.0020.0005.1D7FC] # MATHEMATICAL MONOSPACE DIGIT SIX; QQK +2465 ; [.0FCC.0020.0006.2465] # CIRCLED DIGIT SIX; QQK +24FA ; [.0FCC.0020.0006.24FA] # DOUBLE CIRCLED DIGIT SIX; QQK +277B ; [.0FCC.0020.0006.277B] # DINGBAT NEGATIVE CIRCLED DIGIT SIX; QQK +2785 ; [.0FCC.0020.0006.2785] # DINGBAT CIRCLED SANS-SERIF DIGIT SIX; QQK +278F ; [.0FCC.0020.0006.278F] # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX; QQK +2076 ; [.0FCC.0020.0014.2076] # SUPERSCRIPT SIX; QQK +2086 ; [.0FCC.0020.0015.2086] # SUBSCRIPT SIX; QQK +0666 ; [.0FCC.0020.0002.0666][.0000.019F.0002.0666] # ARABIC-INDIC DIGIT SIX +06F6 ; [.0FCC.0020.0002.06F6][.0000.01A0.0002.06F6] # EXTENDED ARABIC-INDIC DIGIT SIX +07C6 ; [.0FCC.0020.0002.07C6][.0000.01A1.0002.07C6] # NKO DIGIT SIX +136E ; [.0FCC.0020.0002.136E][.0000.01A2.0002.136E] # ETHIOPIC DIGIT SIX +104A6 ; [.0FCC.0020.0002.104A6][.0000.01A3.0002.104A6] # OSMANYA DIGIT SIX +096C ; [.0FCC.0020.0002.096C][.0000.01A4.0002.096C] # DEVANAGARI DIGIT SIX +09EC ; [.0FCC.0020.0002.09EC][.0000.01A5.0002.09EC] # BENGALI DIGIT SIX +0A6C ; [.0FCC.0020.0002.0A6C][.0000.01A6.0002.0A6C] # GURMUKHI DIGIT SIX +0AEC ; [.0FCC.0020.0002.0AEC][.0000.01A7.0002.0AEC] # GUJARATI DIGIT SIX +0B6C ; [.0FCC.0020.0002.0B6C][.0000.01A8.0002.0B6C] # ORIYA DIGIT SIX +0BEC ; [.0FCC.0020.0002.0BEC][.0000.01A9.0002.0BEC] # TAMIL DIGIT SIX +0C6C ; [.0FCC.0020.0002.0C6C][.0000.01AA.0002.0C6C] # TELUGU DIGIT SIX +0CEC ; [.0FCC.0020.0002.0CEC][.0000.01AB.0002.0CEC] # KANNADA DIGIT SIX +0D6C ; [.0FCC.0020.0002.0D6C][.0000.01AC.0002.0D6C] # MALAYALAM DIGIT SIX +194C ; [.0FCC.0020.0002.194C][.0000.01AD.0002.194C] # LIMBU DIGIT SIX +19D6 ; [.0FCC.0020.0002.19D6][.0000.01AE.0002.19D6] # NEW TAI LUE DIGIT SIX +0E56 ; [.0FCC.0020.0002.0E56][.0000.01AF.0002.0E56] # THAI DIGIT SIX +0ED6 ; [.0FCC.0020.0002.0ED6][.0000.01B0.0002.0ED6] # LAO DIGIT SIX +0F26 ; [.0FCC.0020.0002.0F26][.0000.01B1.0002.0F26] # TIBETAN DIGIT SIX +0F2F ; [.0FCC.0020.0004.0F2F][.0000.01B1.0004.0F2F] # TIBETAN DIGIT HALF SIX; QQK +1046 ; [.0FCC.0020.0002.1046][.0000.01B2.0002.1046] # MYANMAR DIGIT SIX +17E6 ; [.0FCC.0020.0002.17E6][.0000.01B3.0002.17E6] # KHMER DIGIT SIX +17F6 ; [.0FCC.0020.0002.17F6][.0000.01B4.0002.17F6] # KHMER SYMBOL LEK ATTAK PRAM-MUOY +1B56 ; [.0FCC.0020.0002.1B56][.0000.01B5.0002.1B56] # BALINESE DIGIT SIX +1816 ; [.0FCC.0020.0002.1816][.0000.01B6.0002.1816] # MONGOLIAN DIGIT SIX +3026 ; [.0FCC.0020.0002.3026][.0000.01B7.0002.3026] # HANGZHOU NUMERAL SIX +1010C ; [.0FCC.0020.0002.1010C][.0000.01B8.0002.1010C] # AEGEAN NUMBER SIX +12404 ; [.0FCC.0020.0002.12404][.0000.01BC.0002.12404] # CUNEIFORM NUMERIC SIGN SIX ASH +1240B ; [.0FCC.0020.0002.1240B][.0000.01BC.0002.1240B] # CUNEIFORM NUMERIC SIGN SIX DISH +12411 ; [.0FCC.0020.0002.12411][.0000.01BC.0002.12411] # CUNEIFORM NUMERIC SIGN SIX U +1241A ; [.0FCC.0020.0002.1241A][.0000.01BC.0002.1241A] # CUNEIFORM NUMERIC SIGN SIX GESH2 +12428 ; [.0FCC.0020.0002.12428][.0000.01BC.0002.12428] # CUNEIFORM NUMERIC SIGN SIX SHAR2 +12440 ; [.0FCC.0020.0002.12440][.0000.01BC.0002.12440] # CUNEIFORM NUMERIC SIGN SIX VARIANT FORM ASH9 +1244E ; [.0FCC.0020.0002.1244E][.0000.01BC.0002.1244E] # CUNEIFORM NUMERIC SIGN SIX ASH TENU +1D365 ; [.0FCC.0020.0002.1D365][.0000.01BF.0002.1D365] # COUNTING ROD UNIT DIGIT SIX +33E5 ; [.0FCC.0020.0004.33E5][.FB40.0020.0004.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIX; QQKN +32C5 ; [.0FCC.0020.0004.32C5][.FB40.0020.0004.6708][.E708.0000.0000.6708] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR JUNE; QQKN +335E ; [.0FCC.0020.0004.335E][.FB40.0020.0004.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIX; QQKN +0037 ; [.0FCD.0020.0002.0037] # DIGIT SEVEN +FF17 ; [.0FCD.0020.0003.FF17] # FULLWIDTH DIGIT SEVEN; QQK +247A ; [*02B1.0020.0004.247A][.0FCD.0020.0004.247A][*02B2.0020.001F.247A] # PARENTHESIZED DIGIT SEVEN; QQKN +248E ; [.0FCD.0020.0004.248E][*0266.0020.0004.248E] # DIGIT SEVEN FULL STOP; QQKN +1D7D5 ; [.0FCD.0020.0005.1D7D5] # MATHEMATICAL BOLD DIGIT SEVEN; QQK +1D7DF ; [.0FCD.0020.0005.1D7DF] # MATHEMATICAL DOUBLE-STRUCK DIGIT SEVEN; QQK +1D7E9 ; [.0FCD.0020.0005.1D7E9] # MATHEMATICAL SANS-SERIF DIGIT SEVEN; QQK +1D7F3 ; [.0FCD.0020.0005.1D7F3] # MATHEMATICAL SANS-SERIF BOLD DIGIT SEVEN; QQK +1D7FD ; [.0FCD.0020.0005.1D7FD] # MATHEMATICAL MONOSPACE DIGIT SEVEN; QQK +2466 ; [.0FCD.0020.0006.2466] # CIRCLED DIGIT SEVEN; QQK +24FB ; [.0FCD.0020.0006.24FB] # DOUBLE CIRCLED DIGIT SEVEN; QQK +277C ; [.0FCD.0020.0006.277C] # DINGBAT NEGATIVE CIRCLED DIGIT SEVEN; QQK +2786 ; [.0FCD.0020.0006.2786] # DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN; QQK +2790 ; [.0FCD.0020.0006.2790] # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN; QQK +2077 ; [.0FCD.0020.0014.2077] # SUPERSCRIPT SEVEN; QQK +2087 ; [.0FCD.0020.0015.2087] # SUBSCRIPT SEVEN; QQK +0667 ; [.0FCD.0020.0002.0667][.0000.019F.0002.0667] # ARABIC-INDIC DIGIT SEVEN +06F7 ; [.0FCD.0020.0002.06F7][.0000.01A0.0002.06F7] # EXTENDED ARABIC-INDIC DIGIT SEVEN +07C7 ; [.0FCD.0020.0002.07C7][.0000.01A1.0002.07C7] # NKO DIGIT SEVEN +136F ; [.0FCD.0020.0002.136F][.0000.01A2.0002.136F] # ETHIOPIC DIGIT SEVEN +104A7 ; [.0FCD.0020.0002.104A7][.0000.01A3.0002.104A7] # OSMANYA DIGIT SEVEN +096D ; [.0FCD.0020.0002.096D][.0000.01A4.0002.096D] # DEVANAGARI DIGIT SEVEN +09ED ; [.0FCD.0020.0002.09ED][.0000.01A5.0002.09ED] # BENGALI DIGIT SEVEN +0A6D ; [.0FCD.0020.0002.0A6D][.0000.01A6.0002.0A6D] # GURMUKHI DIGIT SEVEN +0AED ; [.0FCD.0020.0002.0AED][.0000.01A7.0002.0AED] # GUJARATI DIGIT SEVEN +0B6D ; [.0FCD.0020.0002.0B6D][.0000.01A8.0002.0B6D] # ORIYA DIGIT SEVEN +0BED ; [.0FCD.0020.0002.0BED][.0000.01A9.0002.0BED] # TAMIL DIGIT SEVEN +0C6D ; [.0FCD.0020.0002.0C6D][.0000.01AA.0002.0C6D] # TELUGU DIGIT SEVEN +0CED ; [.0FCD.0020.0002.0CED][.0000.01AB.0002.0CED] # KANNADA DIGIT SEVEN +0D6D ; [.0FCD.0020.0002.0D6D][.0000.01AC.0002.0D6D] # MALAYALAM DIGIT SEVEN +194D ; [.0FCD.0020.0002.194D][.0000.01AD.0002.194D] # LIMBU DIGIT SEVEN +19D7 ; [.0FCD.0020.0002.19D7][.0000.01AE.0002.19D7] # NEW TAI LUE DIGIT SEVEN +0E57 ; [.0FCD.0020.0002.0E57][.0000.01AF.0002.0E57] # THAI DIGIT SEVEN +0ED7 ; [.0FCD.0020.0002.0ED7][.0000.01B0.0002.0ED7] # LAO DIGIT SEVEN +0F27 ; [.0FCD.0020.0002.0F27][.0000.01B1.0002.0F27] # TIBETAN DIGIT SEVEN +0F30 ; [.0FCD.0020.0004.0F30][.0000.01B1.0004.0F30] # TIBETAN DIGIT HALF SEVEN; QQK +1047 ; [.0FCD.0020.0002.1047][.0000.01B2.0002.1047] # MYANMAR DIGIT SEVEN +17E7 ; [.0FCD.0020.0002.17E7][.0000.01B3.0002.17E7] # KHMER DIGIT SEVEN +17F7 ; [.0FCD.0020.0002.17F7][.0000.01B4.0002.17F7] # KHMER SYMBOL LEK ATTAK PRAM-PII +1B57 ; [.0FCD.0020.0002.1B57][.0000.01B5.0002.1B57] # BALINESE DIGIT SEVEN +1817 ; [.0FCD.0020.0002.1817][.0000.01B6.0002.1817] # MONGOLIAN DIGIT SEVEN +3027 ; [.0FCD.0020.0002.3027][.0000.01B7.0002.3027] # HANGZHOU NUMERAL SEVEN +1010D ; [.0FCD.0020.0002.1010D][.0000.01B8.0002.1010D] # AEGEAN NUMBER SEVEN +12405 ; [.0FCD.0020.0002.12405][.0000.01BC.0002.12405] # CUNEIFORM NUMERIC SIGN SEVEN ASH +1240C ; [.0FCD.0020.0002.1240C][.0000.01BC.0002.1240C] # CUNEIFORM NUMERIC SIGN SEVEN DISH +12412 ; [.0FCD.0020.0002.12412][.0000.01BC.0002.12412] # CUNEIFORM NUMERIC SIGN SEVEN U +1241B ; [.0FCD.0020.0002.1241B][.0000.01BC.0002.1241B] # CUNEIFORM NUMERIC SIGN SEVEN GESH2 +12429 ; [.0FCD.0020.0002.12429][.0000.01BC.0002.12429] # CUNEIFORM NUMERIC SIGN SEVEN SHAR2 +12441 ; [.0FCD.0020.0002.12441][.0000.01BC.0002.12441] # CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN3 +12442 ; [.0FCD.0020.0002.12442][.0000.01BC.0002.12442] # CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN A +12443 ; [.0FCD.0020.0002.12443][.0000.01BC.0002.12443] # CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN B +1D366 ; [.0FCD.0020.0002.1D366][.0000.01BF.0002.1D366] # COUNTING ROD UNIT DIGIT SEVEN +215E ; [.0FCD.0020.001E.215E][*0300.0020.001E.215E][.0FCE.0020.001F.215E] # VULGAR FRACTION SEVEN EIGHTHS; QQKN +33E6 ; [.0FCD.0020.0004.33E6][.FB40.0020.0004.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVEN; QQKN +32C6 ; [.0FCD.0020.0004.32C6][.FB40.0020.0004.6708][.E708.0000.0000.6708] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR JULY; QQKN +335F ; [.0FCD.0020.0004.335F][.FB40.0020.0004.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVEN; QQKN +0038 ; [.0FCE.0020.0002.0038] # DIGIT EIGHT +FF18 ; [.0FCE.0020.0003.FF18] # FULLWIDTH DIGIT EIGHT; QQK +247B ; [*02B1.0020.0004.247B][.0FCE.0020.0004.247B][*02B2.0020.001F.247B] # PARENTHESIZED DIGIT EIGHT; QQKN +248F ; [.0FCE.0020.0004.248F][*0266.0020.0004.248F] # DIGIT EIGHT FULL STOP; QQKN +1D7D6 ; [.0FCE.0020.0005.1D7D6] # MATHEMATICAL BOLD DIGIT EIGHT; QQK +1D7E0 ; [.0FCE.0020.0005.1D7E0] # MATHEMATICAL DOUBLE-STRUCK DIGIT EIGHT; QQK +1D7EA ; [.0FCE.0020.0005.1D7EA] # MATHEMATICAL SANS-SERIF DIGIT EIGHT; QQK +1D7F4 ; [.0FCE.0020.0005.1D7F4] # MATHEMATICAL SANS-SERIF BOLD DIGIT EIGHT; QQK +1D7FE ; [.0FCE.0020.0005.1D7FE] # MATHEMATICAL MONOSPACE DIGIT EIGHT; QQK +2467 ; [.0FCE.0020.0006.2467] # CIRCLED DIGIT EIGHT; QQK +24FC ; [.0FCE.0020.0006.24FC] # DOUBLE CIRCLED DIGIT EIGHT; QQK +277D ; [.0FCE.0020.0006.277D] # DINGBAT NEGATIVE CIRCLED DIGIT EIGHT; QQK +2787 ; [.0FCE.0020.0006.2787] # DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT; QQK +2791 ; [.0FCE.0020.0006.2791] # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT; QQK +2078 ; [.0FCE.0020.0014.2078] # SUPERSCRIPT EIGHT; QQK +2088 ; [.0FCE.0020.0015.2088] # SUBSCRIPT EIGHT; QQK +0668 ; [.0FCE.0020.0002.0668][.0000.019F.0002.0668] # ARABIC-INDIC DIGIT EIGHT +06F8 ; [.0FCE.0020.0002.06F8][.0000.01A0.0002.06F8] # EXTENDED ARABIC-INDIC DIGIT EIGHT +07C8 ; [.0FCE.0020.0002.07C8][.0000.01A1.0002.07C8] # NKO DIGIT EIGHT +1370 ; [.0FCE.0020.0002.1370][.0000.01A2.0002.1370] # ETHIOPIC DIGIT EIGHT +104A8 ; [.0FCE.0020.0002.104A8][.0000.01A3.0002.104A8] # OSMANYA DIGIT EIGHT +096E ; [.0FCE.0020.0002.096E][.0000.01A4.0002.096E] # DEVANAGARI DIGIT EIGHT +09EE ; [.0FCE.0020.0002.09EE][.0000.01A5.0002.09EE] # BENGALI DIGIT EIGHT +0A6E ; [.0FCE.0020.0002.0A6E][.0000.01A6.0002.0A6E] # GURMUKHI DIGIT EIGHT +0AEE ; [.0FCE.0020.0002.0AEE][.0000.01A7.0002.0AEE] # GUJARATI DIGIT EIGHT +0B6E ; [.0FCE.0020.0002.0B6E][.0000.01A8.0002.0B6E] # ORIYA DIGIT EIGHT +0BEE ; [.0FCE.0020.0002.0BEE][.0000.01A9.0002.0BEE] # TAMIL DIGIT EIGHT +0C6E ; [.0FCE.0020.0002.0C6E][.0000.01AA.0002.0C6E] # TELUGU DIGIT EIGHT +0CEE ; [.0FCE.0020.0002.0CEE][.0000.01AB.0002.0CEE] # KANNADA DIGIT EIGHT +0D6E ; [.0FCE.0020.0002.0D6E][.0000.01AC.0002.0D6E] # MALAYALAM DIGIT EIGHT +194E ; [.0FCE.0020.0002.194E][.0000.01AD.0002.194E] # LIMBU DIGIT EIGHT +19D8 ; [.0FCE.0020.0002.19D8][.0000.01AE.0002.19D8] # NEW TAI LUE DIGIT EIGHT +0E58 ; [.0FCE.0020.0002.0E58][.0000.01AF.0002.0E58] # THAI DIGIT EIGHT +0ED8 ; [.0FCE.0020.0002.0ED8][.0000.01B0.0002.0ED8] # LAO DIGIT EIGHT +0F28 ; [.0FCE.0020.0002.0F28][.0000.01B1.0002.0F28] # TIBETAN DIGIT EIGHT +0F31 ; [.0FCE.0020.0004.0F31][.0000.01B1.0004.0F31] # TIBETAN DIGIT HALF EIGHT; QQK +1048 ; [.0FCE.0020.0002.1048][.0000.01B2.0002.1048] # MYANMAR DIGIT EIGHT +17E8 ; [.0FCE.0020.0002.17E8][.0000.01B3.0002.17E8] # KHMER DIGIT EIGHT +17F8 ; [.0FCE.0020.0002.17F8][.0000.01B4.0002.17F8] # KHMER SYMBOL LEK ATTAK PRAM-BEI +1B58 ; [.0FCE.0020.0002.1B58][.0000.01B5.0002.1B58] # BALINESE DIGIT EIGHT +1818 ; [.0FCE.0020.0002.1818][.0000.01B6.0002.1818] # MONGOLIAN DIGIT EIGHT +3028 ; [.0FCE.0020.0002.3028][.0000.01B7.0002.3028] # HANGZHOU NUMERAL EIGHT +1010E ; [.0FCE.0020.0002.1010E][.0000.01B8.0002.1010E] # AEGEAN NUMBER EIGHT +12406 ; [.0FCE.0020.0002.12406][.0000.01BC.0002.12406] # CUNEIFORM NUMERIC SIGN EIGHT ASH +1240D ; [.0FCE.0020.0002.1240D][.0000.01BC.0002.1240D] # CUNEIFORM NUMERIC SIGN EIGHT DISH +12413 ; [.0FCE.0020.0002.12413][.0000.01BC.0002.12413] # CUNEIFORM NUMERIC SIGN EIGHT U +1241C ; [.0FCE.0020.0002.1241C][.0000.01BC.0002.1241C] # CUNEIFORM NUMERIC SIGN EIGHT GESH2 +1242A ; [.0FCE.0020.0002.1242A][.0000.01BC.0002.1242A] # CUNEIFORM NUMERIC SIGN EIGHT SHAR2 +12444 ; [.0FCE.0020.0002.12444][.0000.01BC.0002.12444] # CUNEIFORM NUMERIC SIGN EIGHT VARIANT FORM USSU +12445 ; [.0FCE.0020.0002.12445][.0000.01BC.0002.12445] # CUNEIFORM NUMERIC SIGN EIGHT VARIANT FORM USSU3 +1D367 ; [.0FCE.0020.0002.1D367][.0000.01BF.0002.1D367] # COUNTING ROD UNIT DIGIT EIGHT +33E7 ; [.0FCE.0020.0004.33E7][.FB40.0020.0004.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHT; QQKN +32C7 ; [.0FCE.0020.0004.32C7][.FB40.0020.0004.6708][.E708.0000.0000.6708] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR AUGUST; QQKN +3360 ; [.0FCE.0020.0004.3360][.FB40.0020.0004.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHT; QQKN +0039 ; [.0FCF.0020.0002.0039] # DIGIT NINE +FF19 ; [.0FCF.0020.0003.FF19] # FULLWIDTH DIGIT NINE; QQK +247C ; [*02B1.0020.0004.247C][.0FCF.0020.0004.247C][*02B2.0020.001F.247C] # PARENTHESIZED DIGIT NINE; QQKN +2490 ; [.0FCF.0020.0004.2490][*0266.0020.0004.2490] # DIGIT NINE FULL STOP; QQKN +1D7D7 ; [.0FCF.0020.0005.1D7D7] # MATHEMATICAL BOLD DIGIT NINE; QQK +1D7E1 ; [.0FCF.0020.0005.1D7E1] # MATHEMATICAL DOUBLE-STRUCK DIGIT NINE; QQK +1D7EB ; [.0FCF.0020.0005.1D7EB] # MATHEMATICAL SANS-SERIF DIGIT NINE; QQK +1D7F5 ; [.0FCF.0020.0005.1D7F5] # MATHEMATICAL SANS-SERIF BOLD DIGIT NINE; QQK +1D7FF ; [.0FCF.0020.0005.1D7FF] # MATHEMATICAL MONOSPACE DIGIT NINE; QQK +2468 ; [.0FCF.0020.0006.2468] # CIRCLED DIGIT NINE; QQK +24FD ; [.0FCF.0020.0006.24FD] # DOUBLE CIRCLED DIGIT NINE; QQK +277E ; [.0FCF.0020.0006.277E] # DINGBAT NEGATIVE CIRCLED DIGIT NINE; QQK +2788 ; [.0FCF.0020.0006.2788] # DINGBAT CIRCLED SANS-SERIF DIGIT NINE; QQK +2792 ; [.0FCF.0020.0006.2792] # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE; QQK +2079 ; [.0FCF.0020.0014.2079] # SUPERSCRIPT NINE; QQK +2089 ; [.0FCF.0020.0015.2089] # SUBSCRIPT NINE; QQK +0669 ; [.0FCF.0020.0002.0669][.0000.019F.0002.0669] # ARABIC-INDIC DIGIT NINE +06F9 ; [.0FCF.0020.0002.06F9][.0000.01A0.0002.06F9] # EXTENDED ARABIC-INDIC DIGIT NINE +07C9 ; [.0FCF.0020.0002.07C9][.0000.01A1.0002.07C9] # NKO DIGIT NINE +1371 ; [.0FCF.0020.0002.1371][.0000.01A2.0002.1371] # ETHIOPIC DIGIT NINE +104A9 ; [.0FCF.0020.0002.104A9][.0000.01A3.0002.104A9] # OSMANYA DIGIT NINE +096F ; [.0FCF.0020.0002.096F][.0000.01A4.0002.096F] # DEVANAGARI DIGIT NINE +09EF ; [.0FCF.0020.0002.09EF][.0000.01A5.0002.09EF] # BENGALI DIGIT NINE +0A6F ; [.0FCF.0020.0002.0A6F][.0000.01A6.0002.0A6F] # GURMUKHI DIGIT NINE +0AEF ; [.0FCF.0020.0002.0AEF][.0000.01A7.0002.0AEF] # GUJARATI DIGIT NINE +0B6F ; [.0FCF.0020.0002.0B6F][.0000.01A8.0002.0B6F] # ORIYA DIGIT NINE +0BEF ; [.0FCF.0020.0002.0BEF][.0000.01A9.0002.0BEF] # TAMIL DIGIT NINE +0C6F ; [.0FCF.0020.0002.0C6F][.0000.01AA.0002.0C6F] # TELUGU DIGIT NINE +0CEF ; [.0FCF.0020.0002.0CEF][.0000.01AB.0002.0CEF] # KANNADA DIGIT NINE +0D6F ; [.0FCF.0020.0002.0D6F][.0000.01AC.0002.0D6F] # MALAYALAM DIGIT NINE +194F ; [.0FCF.0020.0002.194F][.0000.01AD.0002.194F] # LIMBU DIGIT NINE +19D9 ; [.0FCF.0020.0002.19D9][.0000.01AE.0002.19D9] # NEW TAI LUE DIGIT NINE +0E59 ; [.0FCF.0020.0002.0E59][.0000.01AF.0002.0E59] # THAI DIGIT NINE +0ED9 ; [.0FCF.0020.0002.0ED9][.0000.01B0.0002.0ED9] # LAO DIGIT NINE +0F29 ; [.0FCF.0020.0002.0F29][.0000.01B1.0002.0F29] # TIBETAN DIGIT NINE +0F32 ; [.0FCF.0020.0004.0F32][.0000.01B1.0004.0F32] # TIBETAN DIGIT HALF NINE; QQK +1049 ; [.0FCF.0020.0002.1049][.0000.01B2.0002.1049] # MYANMAR DIGIT NINE +17E9 ; [.0FCF.0020.0002.17E9][.0000.01B3.0002.17E9] # KHMER DIGIT NINE +17F9 ; [.0FCF.0020.0002.17F9][.0000.01B4.0002.17F9] # KHMER SYMBOL LEK ATTAK PRAM-BUON +1B59 ; [.0FCF.0020.0002.1B59][.0000.01B5.0002.1B59] # BALINESE DIGIT NINE +1819 ; [.0FCF.0020.0002.1819][.0000.01B6.0002.1819] # MONGOLIAN DIGIT NINE +3029 ; [.0FCF.0020.0002.3029][.0000.01B7.0002.3029] # HANGZHOU NUMERAL NINE +1010F ; [.0FCF.0020.0002.1010F][.0000.01B8.0002.1010F] # AEGEAN NUMBER NINE +12407 ; [.0FCF.0020.0002.12407][.0000.01BC.0002.12407] # CUNEIFORM NUMERIC SIGN NINE ASH +1240E ; [.0FCF.0020.0002.1240E][.0000.01BC.0002.1240E] # CUNEIFORM NUMERIC SIGN NINE DISH +12414 ; [.0FCF.0020.0002.12414][.0000.01BC.0002.12414] # CUNEIFORM NUMERIC SIGN NINE U +1241D ; [.0FCF.0020.0002.1241D][.0000.01BC.0002.1241D] # CUNEIFORM NUMERIC SIGN NINE GESH2 +1242B ; [.0FCF.0020.0002.1242B][.0000.01BC.0002.1242B] # CUNEIFORM NUMERIC SIGN NINE SHAR2 +12446 ; [.0FCF.0020.0002.12446][.0000.01BC.0002.12446] # CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU +12447 ; [.0FCF.0020.0002.12447][.0000.01BC.0002.12447] # CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU3 +12448 ; [.0FCF.0020.0002.12448][.0000.01BC.0002.12448] # CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU4 +12449 ; [.0FCF.0020.0002.12449][.0000.01BC.0002.12449] # CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU A +1D368 ; [.0FCF.0020.0002.1D368][.0000.01BF.0002.1D368] # COUNTING ROD UNIT DIGIT NINE +33E8 ; [.0FCF.0020.0004.33E8][.FB40.0020.0004.65E5][.E5E5.0000.0000.65E5] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINE; QQKN +32C8 ; [.0FCF.0020.0004.32C8][.FB40.0020.0004.6708][.E708.0000.0000.6708] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR SEPTEMBER; QQKN +3361 ; [.0FCF.0020.0004.3361][.FB40.0020.0004.70B9][.F0B9.0000.0000.70B9] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINE; QQKN +0061 ; [.0FD0.0020.0002.0061] # LATIN SMALL LETTER A +FF41 ; [.0FD0.0020.0003.FF41] # FULLWIDTH LATIN SMALL LETTER A; QQK +0363 ; [.0FD0.0020.0004.0363] # COMBINING LATIN SMALL LETTER A; QQK +249C ; [*02B1.0020.0004.249C][.0FD0.0020.0004.249C][*02B2.0020.001F.249C] # PARENTHESIZED LATIN SMALL LETTER A; QQKN +1D41A ; [.0FD0.0020.0005.1D41A] # MATHEMATICAL BOLD SMALL A; QQK +1D44E ; [.0FD0.0020.0005.1D44E] # MATHEMATICAL ITALIC SMALL A; QQK +1D482 ; [.0FD0.0020.0005.1D482] # MATHEMATICAL BOLD ITALIC SMALL A; QQK +1D4B6 ; [.0FD0.0020.0005.1D4B6] # MATHEMATICAL SCRIPT SMALL A; QQK +1D4EA ; [.0FD0.0020.0005.1D4EA] # MATHEMATICAL BOLD SCRIPT SMALL A; QQK +1D51E ; [.0FD0.0020.0005.1D51E] # MATHEMATICAL FRAKTUR SMALL A; QQK +1D552 ; [.0FD0.0020.0005.1D552] # MATHEMATICAL DOUBLE-STRUCK SMALL A; QQK +1D586 ; [.0FD0.0020.0005.1D586] # MATHEMATICAL BOLD FRAKTUR SMALL A; QQK +1D5BA ; [.0FD0.0020.0005.1D5BA] # MATHEMATICAL SANS-SERIF SMALL A; QQK +1D5EE ; [.0FD0.0020.0005.1D5EE] # MATHEMATICAL SANS-SERIF BOLD SMALL A; QQK +1D622 ; [.0FD0.0020.0005.1D622] # MATHEMATICAL SANS-SERIF ITALIC SMALL A; QQK +1D656 ; [.0FD0.0020.0005.1D656] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A; QQK +1D68A ; [.0FD0.0020.0005.1D68A] # MATHEMATICAL MONOSPACE SMALL A; QQK +24D0 ; [.0FD0.0020.0006.24D0] # CIRCLED LATIN SMALL LETTER A; QQK +0041 ; [.0FD0.0020.0008.0041] # LATIN CAPITAL LETTER A +FF21 ; [.0FD0.0020.0009.FF21] # FULLWIDTH LATIN CAPITAL LETTER A; QQK +1D400 ; [.0FD0.0020.000B.1D400] # MATHEMATICAL BOLD CAPITAL A; QQK +1D434 ; [.0FD0.0020.000B.1D434] # MATHEMATICAL ITALIC CAPITAL A; QQK +1D468 ; [.0FD0.0020.000B.1D468] # MATHEMATICAL BOLD ITALIC CAPITAL A; QQK +1D49C ; [.0FD0.0020.000B.1D49C] # MATHEMATICAL SCRIPT CAPITAL A; QQK +1D4D0 ; [.0FD0.0020.000B.1D4D0] # MATHEMATICAL BOLD SCRIPT CAPITAL A; QQK +1D504 ; [.0FD0.0020.000B.1D504] # MATHEMATICAL FRAKTUR CAPITAL A; QQK +1D538 ; [.0FD0.0020.000B.1D538] # MATHEMATICAL DOUBLE-STRUCK CAPITAL A; QQK +1D56C ; [.0FD0.0020.000B.1D56C] # MATHEMATICAL BOLD FRAKTUR CAPITAL A; QQK +1D5A0 ; [.0FD0.0020.000B.1D5A0] # MATHEMATICAL SANS-SERIF CAPITAL A; QQK +1D5D4 ; [.0FD0.0020.000B.1D5D4] # MATHEMATICAL SANS-SERIF BOLD CAPITAL A; QQK +1D608 ; [.0FD0.0020.000B.1D608] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL A; QQK +1D63C ; [.0FD0.0020.000B.1D63C] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A; QQK +1D670 ; [.0FD0.0020.000B.1D670] # MATHEMATICAL MONOSPACE CAPITAL A; QQK +24B6 ; [.0FD0.0020.000C.24B6] # CIRCLED LATIN CAPITAL LETTER A; QQK +00AA ; [.0FD0.0020.0014.00AA] # FEMININE ORDINAL INDICATOR; QQK +1D43 ; [.0FD0.0020.0014.1D43] # MODIFIER LETTER SMALL A; QQK +2090 ; [.0FD0.0020.0015.2090] # LATIN SUBSCRIPT SMALL LETTER A; QQK +1D2C ; [.0FD0.0020.001D.1D2C] # MODIFIER LETTER CAPITAL A; QQK +00E1 ; [.0FD0.0020.0002.0061][.0000.0032.0002.0301] # LATIN SMALL LETTER A WITH ACUTE; QQCM +00C1 ; [.0FD0.0020.0008.0041][.0000.0032.0002.0301] # LATIN CAPITAL LETTER A WITH ACUTE; QQCM +00E0 ; [.0FD0.0020.0002.0061][.0000.0035.0002.0300] # LATIN SMALL LETTER A WITH GRAVE; QQCM +00C0 ; [.0FD0.0020.0008.0041][.0000.0035.0002.0300] # LATIN CAPITAL LETTER A WITH GRAVE; QQCM +0103 ; [.0FD0.0020.0002.0061][.0000.0037.0002.0306] # LATIN SMALL LETTER A WITH BREVE; QQCM +0102 ; [.0FD0.0020.0008.0041][.0000.0037.0002.0306] # LATIN CAPITAL LETTER A WITH BREVE; QQCM +1EAF ; [.0FD0.0020.0002.0061][.0000.0037.0002.0306][.0000.0032.0002.0301] # LATIN SMALL LETTER A WITH BREVE AND ACUTE; QQCM +1EAE ; [.0FD0.0020.0008.0041][.0000.0037.0002.0306][.0000.0032.0002.0301] # LATIN CAPITAL LETTER A WITH BREVE AND ACUTE; QQCM +1EB1 ; [.0FD0.0020.0002.0061][.0000.0037.0002.0306][.0000.0035.0002.0300] # LATIN SMALL LETTER A WITH BREVE AND GRAVE; QQCM +1EB0 ; [.0FD0.0020.0008.0041][.0000.0037.0002.0306][.0000.0035.0002.0300] # LATIN CAPITAL LETTER A WITH BREVE AND GRAVE; QQCM +1EB5 ; [.0FD0.0020.0002.0061][.0000.0037.0002.0306][.0000.004E.0002.0303] # LATIN SMALL LETTER A WITH BREVE AND TILDE; QQCM +1EB4 ; [.0FD0.0020.0008.0041][.0000.0037.0002.0306][.0000.004E.0002.0303] # LATIN CAPITAL LETTER A WITH BREVE AND TILDE; QQCM +1EB3 ; [.0FD0.0020.0002.0061][.0000.0037.0002.0306][.0000.0060.0002.0309] # LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE; QQCM +1EB2 ; [.0FD0.0020.0008.0041][.0000.0037.0002.0306][.0000.0060.0002.0309] # LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE; QQCM +00E2 ; [.0FD0.0020.0002.0061][.0000.003C.0002.0302] # LATIN SMALL LETTER A WITH CIRCUMFLEX; QQCM +00C2 ; [.0FD0.0020.0008.0041][.0000.003C.0002.0302] # LATIN CAPITAL LETTER A WITH CIRCUMFLEX; QQCM +1EA5 ; [.0FD0.0020.0002.0061][.0000.003C.0002.0302][.0000.0032.0002.0301] # LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE; QQCM +1EA4 ; [.0FD0.0020.0008.0041][.0000.003C.0002.0302][.0000.0032.0002.0301] # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE; QQCM +1EA7 ; [.0FD0.0020.0002.0061][.0000.003C.0002.0302][.0000.0035.0002.0300] # LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE; QQCM +1EA6 ; [.0FD0.0020.0008.0041][.0000.003C.0002.0302][.0000.0035.0002.0300] # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE; QQCM +1EAB ; [.0FD0.0020.0002.0061][.0000.003C.0002.0302][.0000.004E.0002.0303] # LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE; QQCM +1EAA ; [.0FD0.0020.0008.0041][.0000.003C.0002.0302][.0000.004E.0002.0303] # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE; QQCM +1EA9 ; [.0FD0.0020.0002.0061][.0000.003C.0002.0302][.0000.0060.0002.0309] # LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE; QQCM +1EA8 ; [.0FD0.0020.0008.0041][.0000.003C.0002.0302][.0000.0060.0002.0309] # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE; QQCM +01CE ; [.0FD0.0020.0002.0061][.0000.0041.0002.030C] # LATIN SMALL LETTER A WITH CARON; QQCM +01CD ; [.0FD0.0020.0008.0041][.0000.0041.0002.030C] # LATIN CAPITAL LETTER A WITH CARON; QQCM +00E5 ; [.0FD0.0020.0002.0061][.0000.0043.0002.030A] # LATIN SMALL LETTER A WITH RING ABOVE; QQCM +00C5 ; [.0FD0.0020.0008.0041][.0000.0043.0002.030A] # LATIN CAPITAL LETTER A WITH RING ABOVE; QQCM +212B ; [.0FD0.0020.0008.0041][.0000.0043.0002.030A] # ANGSTROM SIGN; QQCM +01FB ; [.0FD0.0020.0002.0061][.0000.0043.0002.030A][.0000.0032.0002.0301] # LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE; QQCM +01FA ; [.0FD0.0020.0008.0041][.0000.0043.0002.030A][.0000.0032.0002.0301] # LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE; QQCM +00E4 ; [.0FD0.0020.0002.0061][.0000.0047.0002.0308] # LATIN SMALL LETTER A WITH DIAERESIS; QQCM +00C4 ; [.0FD0.0020.0008.0041][.0000.0047.0002.0308] # LATIN CAPITAL LETTER A WITH DIAERESIS; QQCM +01DF ; [.0FD0.0020.0002.0061][.0000.0047.0002.0308][.0000.005B.0002.0304] # LATIN SMALL LETTER A WITH DIAERESIS AND MACRON; QQCM +01DE ; [.0FD0.0020.0008.0041][.0000.0047.0002.0308][.0000.005B.0002.0304] # LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON; QQCM +00E3 ; [.0FD0.0020.0002.0061][.0000.004E.0002.0303] # LATIN SMALL LETTER A WITH TILDE; QQCM +00C3 ; [.0FD0.0020.0008.0041][.0000.004E.0002.0303] # LATIN CAPITAL LETTER A WITH TILDE; QQCM +0227 ; [.0FD0.0020.0002.0061][.0000.0052.0002.0307] # LATIN SMALL LETTER A WITH DOT ABOVE; QQCM +0226 ; [.0FD0.0020.0008.0041][.0000.0052.0002.0307] # LATIN CAPITAL LETTER A WITH DOT ABOVE; QQCM +01E1 ; [.0FD0.0020.0002.0061][.0000.0052.0002.0307][.0000.005B.0002.0304] # LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON; QQCM +01E0 ; [.0FD0.0020.0008.0041][.0000.0052.0002.0307][.0000.005B.0002.0304] # LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON; QQCM +0105 ; [.0FD0.0020.0002.0061][.0000.0059.0002.0328] # LATIN SMALL LETTER A WITH OGONEK; QQCM +0104 ; [.0FD0.0020.0008.0041][.0000.0059.0002.0328] # LATIN CAPITAL LETTER A WITH OGONEK; QQCM +0101 ; [.0FD0.0020.0002.0061][.0000.005B.0002.0304] # LATIN SMALL LETTER A WITH MACRON; QQCM +0100 ; [.0FD0.0020.0008.0041][.0000.005B.0002.0304] # LATIN CAPITAL LETTER A WITH MACRON; QQCM +1EA3 ; [.0FD0.0020.0002.0061][.0000.0060.0002.0309] # LATIN SMALL LETTER A WITH HOOK ABOVE; QQCM +1EA2 ; [.0FD0.0020.0008.0041][.0000.0060.0002.0309] # LATIN CAPITAL LETTER A WITH HOOK ABOVE; QQCM +0201 ; [.0FD0.0020.0002.0061][.0000.0063.0002.030F] # LATIN SMALL LETTER A WITH DOUBLE GRAVE; QQCM +0200 ; [.0FD0.0020.0008.0041][.0000.0063.0002.030F] # LATIN CAPITAL LETTER A WITH DOUBLE GRAVE; QQCM +0203 ; [.0FD0.0020.0002.0061][.0000.0065.0002.0311] # LATIN SMALL LETTER A WITH INVERTED BREVE; QQCM +0202 ; [.0FD0.0020.0008.0041][.0000.0065.0002.0311] # LATIN CAPITAL LETTER A WITH INVERTED BREVE; QQCM +1EA1 ; [.0FD0.0020.0002.0061][.0000.007A.0002.0323] # LATIN SMALL LETTER A WITH DOT BELOW; QQCM +1EA0 ; [.0FD0.0020.0008.0041][.0000.007A.0002.0323] # LATIN CAPITAL LETTER A WITH DOT BELOW; QQCM +1EB7 ; [.0FD0.0020.0002.0061][.0000.007A.0002.0323][.0000.0037.0002.0306] # LATIN SMALL LETTER A WITH BREVE AND DOT BELOW; QQCM +1EB6 ; [.0FD0.0020.0008.0041][.0000.007A.0002.0323][.0000.0037.0002.0306] # LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW; QQCM +1EAD ; [.0FD0.0020.0002.0061][.0000.007A.0002.0323][.0000.003C.0002.0302] # LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW; QQCM +1EAC ; [.0FD0.0020.0008.0041][.0000.007A.0002.0323][.0000.003C.0002.0302] # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW; QQCM +1E01 ; [.0FD0.0020.0002.0061][.0000.0080.0002.0325] # LATIN SMALL LETTER A WITH RING BELOW; QQCM +1E00 ; [.0FD0.0020.0008.0041][.0000.0080.0002.0325] # LATIN CAPITAL LETTER A WITH RING BELOW; QQCM +2100 ; [.0FD0.0020.0004.2100][*02FF.0020.0004.2100][.0FFE.0020.001F.2100] # ACCOUNT OF; QQKN +00E6 ; [.0FD0.0020.0004.00E6][.0000.0199.0004.00E6][.1029.0020.001F.00E6] # LATIN SMALL LETTER AE; QQKN +00C6 ; [.0FD0.0020.000A.00C6][.0000.0199.0004.00C6][.1029.0020.001F.00C6] # LATIN CAPITAL LETTER AE; QQKN +1D2D ; [.0FD0.0020.0014.1D2D][.0000.0199.0014.1D2D][.1029.0020.001F.1D2D] # MODIFIER LETTER CAPITAL AE; QQKN +01FD ; [.0FD0.0020.0004.01FD][.0000.0199.0004.01FD][.1029.0020.001F.01FD][.0000.0032.0002.01FD] # LATIN SMALL LETTER AE WITH ACUTE; QQKN +01FC ; [.0FD0.0020.000A.01FC][.0000.0199.0004.01FC][.1029.0020.001F.01FC][.0000.0032.0002.01FC] # LATIN CAPITAL LETTER AE WITH ACUTE; QQKN +01E3 ; [.0FD0.0020.0004.01E3][.0000.0199.0004.01E3][.1029.0020.001F.01E3][.0000.005B.0002.01E3] # LATIN SMALL LETTER AE WITH MACRON; QQKN +01E2 ; [.0FD0.0020.000A.01E2][.0000.0199.0004.01E2][.1029.0020.001F.01E2][.0000.005B.0002.01E2] # LATIN CAPITAL LETTER AE WITH MACRON; QQKN +33C2 ; [.0FD0.0020.001C.33C2][*0266.0020.001C.33C2][.1110.0020.001F.33C2][*0266.0020.001F.33C2] # SQUARE AM; QQKN +33DF ; [.0FD0.0020.001D.33DF][*04C7.0020.001C.33DF][.1110.0020.001F.33DF] # SQUARE A OVER M; QQKN +2101 ; [.0FD0.0020.0004.2101][*02FF.0020.0004.2101][.11AF.0020.001F.2101] # ADDRESSED TO THE SUBJECT; QQKN +3373 ; [.0FD0.0020.001D.3373][.11EE.0020.001D.3373] # SQUARE AU; QQKN +1E9A ; [.0FD0.0020.0004.1E9A][.1298.0020.0004.1E9A] # LATIN SMALL LETTER A WITH RIGHT HALF RING; QQKN +1D00 ; [.0FD4.0020.0002.1D00] # LATIN LETTER SMALL CAPITAL A +2C65 ; [.0FD5.0020.0002.2C65] # LATIN SMALL LETTER A WITH STROKE +023A ; [.0FD5.0020.0008.023A] # LATIN CAPITAL LETTER A WITH STROKE +1D8F ; [.0FD6.0020.0002.1D8F] # LATIN SMALL LETTER A WITH RETROFLEX HOOK +1D01 ; [.0FD7.0020.0002.1D01] # LATIN LETTER SMALL CAPITAL AE +1D02 ; [.0FD8.0020.0002.1D02] # LATIN SMALL LETTER TURNED AE +1D46 ; [.0FD8.0020.0014.1D46] # MODIFIER LETTER SMALL TURNED AE; QQK +0250 ; [.0FD9.0020.0002.0250] # LATIN SMALL LETTER TURNED A +1D44 ; [.0FD9.0020.0014.1D44] # MODIFIER LETTER SMALL TURNED A; QQK +0251 ; [.0FDD.0020.0002.0251] # LATIN SMALL LETTER ALPHA +1D45 ; [.0FDD.0020.0014.1D45] # MODIFIER LETTER SMALL ALPHA; QQK +1D90 ; [.0FE1.0020.0002.1D90] # LATIN SMALL LETTER ALPHA WITH RETROFLEX HOOK +0252 ; [.0FE2.0020.0002.0252] # LATIN SMALL LETTER TURNED ALPHA +1D9B ; [.0FE2.0020.0014.1D9B] # MODIFIER LETTER SMALL TURNED ALPHA; QQK +0062 ; [.0FE6.0020.0002.0062] # LATIN SMALL LETTER B +FF42 ; [.0FE6.0020.0003.FF42] # FULLWIDTH LATIN SMALL LETTER B; QQK +249D ; [*02B1.0020.0004.249D][.0FE6.0020.0004.249D][*02B2.0020.001F.249D] # PARENTHESIZED LATIN SMALL LETTER B; QQKN +1D41B ; [.0FE6.0020.0005.1D41B] # MATHEMATICAL BOLD SMALL B; QQK +1D44F ; [.0FE6.0020.0005.1D44F] # MATHEMATICAL ITALIC SMALL B; QQK +1D483 ; [.0FE6.0020.0005.1D483] # MATHEMATICAL BOLD ITALIC SMALL B; QQK +1D4B7 ; [.0FE6.0020.0005.1D4B7] # MATHEMATICAL SCRIPT SMALL B; QQK +1D4EB ; [.0FE6.0020.0005.1D4EB] # MATHEMATICAL BOLD SCRIPT SMALL B; QQK +1D51F ; [.0FE6.0020.0005.1D51F] # MATHEMATICAL FRAKTUR SMALL B; QQK +1D553 ; [.0FE6.0020.0005.1D553] # MATHEMATICAL DOUBLE-STRUCK SMALL B; QQK +1D587 ; [.0FE6.0020.0005.1D587] # MATHEMATICAL BOLD FRAKTUR SMALL B; QQK +1D5BB ; [.0FE6.0020.0005.1D5BB] # MATHEMATICAL SANS-SERIF SMALL B; QQK +1D5EF ; [.0FE6.0020.0005.1D5EF] # MATHEMATICAL SANS-SERIF BOLD SMALL B; QQK +1D623 ; [.0FE6.0020.0005.1D623] # MATHEMATICAL SANS-SERIF ITALIC SMALL B; QQK +1D657 ; [.0FE6.0020.0005.1D657] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL B; QQK +1D68B ; [.0FE6.0020.0005.1D68B] # MATHEMATICAL MONOSPACE SMALL B; QQK +24D1 ; [.0FE6.0020.0006.24D1] # CIRCLED LATIN SMALL LETTER B; QQK +0042 ; [.0FE6.0020.0008.0042] # LATIN CAPITAL LETTER B +FF22 ; [.0FE6.0020.0009.FF22] # FULLWIDTH LATIN CAPITAL LETTER B; QQK +212C ; [.0FE6.0020.000B.212C] # SCRIPT CAPITAL B; QQK +1D401 ; [.0FE6.0020.000B.1D401] # MATHEMATICAL BOLD CAPITAL B; QQK +1D435 ; [.0FE6.0020.000B.1D435] # MATHEMATICAL ITALIC CAPITAL B; QQK +1D469 ; [.0FE6.0020.000B.1D469] # MATHEMATICAL BOLD ITALIC CAPITAL B; QQK +1D4D1 ; [.0FE6.0020.000B.1D4D1] # MATHEMATICAL BOLD SCRIPT CAPITAL B; QQK +1D505 ; [.0FE6.0020.000B.1D505] # MATHEMATICAL FRAKTUR CAPITAL B; QQK +1D539 ; [.0FE6.0020.000B.1D539] # MATHEMATICAL DOUBLE-STRUCK CAPITAL B; QQK +1D56D ; [.0FE6.0020.000B.1D56D] # MATHEMATICAL BOLD FRAKTUR CAPITAL B; QQK +1D5A1 ; [.0FE6.0020.000B.1D5A1] # MATHEMATICAL SANS-SERIF CAPITAL B; QQK +1D5D5 ; [.0FE6.0020.000B.1D5D5] # MATHEMATICAL SANS-SERIF BOLD CAPITAL B; QQK +1D609 ; [.0FE6.0020.000B.1D609] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL B; QQK +1D63D ; [.0FE6.0020.000B.1D63D] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL B; QQK +1D671 ; [.0FE6.0020.000B.1D671] # MATHEMATICAL MONOSPACE CAPITAL B; QQK +24B7 ; [.0FE6.0020.000C.24B7] # CIRCLED LATIN CAPITAL LETTER B; QQK +1D47 ; [.0FE6.0020.0014.1D47] # MODIFIER LETTER SMALL B; QQK +1D2E ; [.0FE6.0020.001D.1D2E] # MODIFIER LETTER CAPITAL B; QQK +1E03 ; [.0FE6.0020.0002.0062][.0000.0052.0002.0307] # LATIN SMALL LETTER B WITH DOT ABOVE; QQCM +1E02 ; [.0FE6.0020.0008.0042][.0000.0052.0002.0307] # LATIN CAPITAL LETTER B WITH DOT ABOVE; QQCM +1E05 ; [.0FE6.0020.0002.0062][.0000.007A.0002.0323] # LATIN SMALL LETTER B WITH DOT BELOW; QQCM +1E04 ; [.0FE6.0020.0008.0042][.0000.007A.0002.0323] # LATIN CAPITAL LETTER B WITH DOT BELOW; QQCM +1E07 ; [.0FE6.0020.0002.0062][.0000.008A.0002.0331] # LATIN SMALL LETTER B WITH LINE BELOW; QQCM +1E06 ; [.0FE6.0020.0008.0042][.0000.008A.0002.0331] # LATIN CAPITAL LETTER B WITH LINE BELOW; QQCM +3374 ; [.0FE6.0020.001C.3374][.0FD0.0020.001C.3374][.117E.0020.001F.3374] # SQUARE BAR; QQKN +33C3 ; [.0FE6.0020.001D.33C3][.116E.0020.001C.33C3] # SQUARE BQ; QQKN +0299 ; [.0FEA.0020.0002.0299] # LATIN LETTER SMALL CAPITAL B +0180 ; [.0FEE.0020.0002.0180] # LATIN SMALL LETTER B WITH STROKE +0243 ; [.0FEE.0020.0008.0243] # LATIN CAPITAL LETTER B WITH STROKE +1D2F ; [.0FF2.0020.0002.1D2F] # MODIFIER LETTER CAPITAL BARRED B +1D03 ; [.0FF3.0020.0002.1D03] # LATIN LETTER SMALL CAPITAL BARRED B +1D6C ; [.0FF4.0020.0002.1D6C] # LATIN SMALL LETTER B WITH MIDDLE TILDE +1D80 ; [.0FF5.0020.0002.1D80] # LATIN SMALL LETTER B WITH PALATAL HOOK +0253 ; [.0FF6.0020.0002.0253] # LATIN SMALL LETTER B WITH HOOK +0181 ; [.0FF6.0020.0008.0181] # LATIN CAPITAL LETTER B WITH HOOK +0183 ; [.0FFA.0020.0002.0183] # LATIN SMALL LETTER B WITH TOPBAR +0182 ; [.0FFA.0020.0008.0182] # LATIN CAPITAL LETTER B WITH TOPBAR +0063 ; [.0FFE.0020.0002.0063] # LATIN SMALL LETTER C +FF43 ; [.0FFE.0020.0003.FF43] # FULLWIDTH LATIN SMALL LETTER C; QQK +0368 ; [.0FFE.0020.0004.0368] # COMBINING LATIN SMALL LETTER C; QQK +217D ; [.0FFE.0020.0004.217D] # SMALL ROMAN NUMERAL ONE HUNDRED; QQK +249E ; [*02B1.0020.0004.249E][.0FFE.0020.0004.249E][*02B2.0020.001F.249E] # PARENTHESIZED LATIN SMALL LETTER C; QQKN +1D41C ; [.0FFE.0020.0005.1D41C] # MATHEMATICAL BOLD SMALL C; QQK +1D450 ; [.0FFE.0020.0005.1D450] # MATHEMATICAL ITALIC SMALL C; QQK +1D484 ; [.0FFE.0020.0005.1D484] # MATHEMATICAL BOLD ITALIC SMALL C; QQK +1D4B8 ; [.0FFE.0020.0005.1D4B8] # MATHEMATICAL SCRIPT SMALL C; QQK +1D4EC ; [.0FFE.0020.0005.1D4EC] # MATHEMATICAL BOLD SCRIPT SMALL C; QQK +1D520 ; [.0FFE.0020.0005.1D520] # MATHEMATICAL FRAKTUR SMALL C; QQK +1D554 ; [.0FFE.0020.0005.1D554] # MATHEMATICAL DOUBLE-STRUCK SMALL C; QQK +1D588 ; [.0FFE.0020.0005.1D588] # MATHEMATICAL BOLD FRAKTUR SMALL C; QQK +1D5BC ; [.0FFE.0020.0005.1D5BC] # MATHEMATICAL SANS-SERIF SMALL C; QQK +1D5F0 ; [.0FFE.0020.0005.1D5F0] # MATHEMATICAL SANS-SERIF BOLD SMALL C; QQK +1D624 ; [.0FFE.0020.0005.1D624] # MATHEMATICAL SANS-SERIF ITALIC SMALL C; QQK +1D658 ; [.0FFE.0020.0005.1D658] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL C; QQK +1D68C ; [.0FFE.0020.0005.1D68C] # MATHEMATICAL MONOSPACE SMALL C; QQK +24D2 ; [.0FFE.0020.0006.24D2] # CIRCLED LATIN SMALL LETTER C; QQK +0043 ; [.0FFE.0020.0008.0043] # LATIN CAPITAL LETTER C +FF23 ; [.0FFE.0020.0009.FF23] # FULLWIDTH LATIN CAPITAL LETTER C; QQK +2103 ; [*03BF.0020.0004.2103][.0FFE.0020.000A.2103] # DEGREE CELSIUS; QQKN +216D ; [.0FFE.0020.000A.216D] # ROMAN NUMERAL ONE HUNDRED; QQK +2102 ; [.0FFE.0020.000B.2102] # DOUBLE-STRUCK CAPITAL C; QQK +212D ; [.0FFE.0020.000B.212D] # BLACK-LETTER CAPITAL C; QQK +1D402 ; [.0FFE.0020.000B.1D402] # MATHEMATICAL BOLD CAPITAL C; QQK +1D436 ; [.0FFE.0020.000B.1D436] # MATHEMATICAL ITALIC CAPITAL C; QQK +1D46A ; [.0FFE.0020.000B.1D46A] # MATHEMATICAL BOLD ITALIC CAPITAL C; QQK +1D49E ; [.0FFE.0020.000B.1D49E] # MATHEMATICAL SCRIPT CAPITAL C; QQK +1D4D2 ; [.0FFE.0020.000B.1D4D2] # MATHEMATICAL BOLD SCRIPT CAPITAL C; QQK +1D56E ; [.0FFE.0020.000B.1D56E] # MATHEMATICAL BOLD FRAKTUR CAPITAL C; QQK +1D5A2 ; [.0FFE.0020.000B.1D5A2] # MATHEMATICAL SANS-SERIF CAPITAL C; QQK +1D5D6 ; [.0FFE.0020.000B.1D5D6] # MATHEMATICAL SANS-SERIF BOLD CAPITAL C; QQK +1D60A ; [.0FFE.0020.000B.1D60A] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL C; QQK +1D63E ; [.0FFE.0020.000B.1D63E] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL C; QQK +1D672 ; [.0FFE.0020.000B.1D672] # MATHEMATICAL MONOSPACE CAPITAL C; QQK +24B8 ; [.0FFE.0020.000C.24B8] # CIRCLED LATIN CAPITAL LETTER C; QQK +1D9C ; [.0FFE.0020.0014.1D9C] # MODIFIER LETTER SMALL C; QQK +0107 ; [.0FFE.0020.0002.0063][.0000.0032.0002.0301] # LATIN SMALL LETTER C WITH ACUTE; QQCM +0106 ; [.0FFE.0020.0008.0043][.0000.0032.0002.0301] # LATIN CAPITAL LETTER C WITH ACUTE; QQCM +0109 ; [.0FFE.0020.0002.0063][.0000.003C.0002.0302] # LATIN SMALL LETTER C WITH CIRCUMFLEX; QQCM +0108 ; [.0FFE.0020.0008.0043][.0000.003C.0002.0302] # LATIN CAPITAL LETTER C WITH CIRCUMFLEX; QQCM +010D ; [.0FFE.0020.0002.0063][.0000.0041.0002.030C] # LATIN SMALL LETTER C WITH CARON; QQCM +010C ; [.0FFE.0020.0008.0043][.0000.0041.0002.030C] # LATIN CAPITAL LETTER C WITH CARON; QQCM +010B ; [.0FFE.0020.0002.0063][.0000.0052.0002.0307] # LATIN SMALL LETTER C WITH DOT ABOVE; QQCM +010A ; [.0FFE.0020.0008.0043][.0000.0052.0002.0307] # LATIN CAPITAL LETTER C WITH DOT ABOVE; QQCM +00E7 ; [.0FFE.0020.0002.0063][.0000.0056.0002.0327] # LATIN SMALL LETTER C WITH CEDILLA; QQCM +00C7 ; [.0FFE.0020.0008.0043][.0000.0056.0002.0327] # LATIN CAPITAL LETTER C WITH CEDILLA; QQCM +1E09 ; [.0FFE.0020.0002.0063][.0000.0056.0002.0327][.0000.0032.0002.0301] # LATIN SMALL LETTER C WITH CEDILLA AND ACUTE; QQCM +1E08 ; [.0FFE.0020.0008.0043][.0000.0056.0002.0327][.0000.0032.0002.0301] # LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE; QQCM +3388 ; [.0FFE.0020.001C.3388][.0FD0.0020.001C.3388][.10E5.0020.001F.3388] # SQUARE CAL; QQKN +33C4 ; [.0FFE.0020.001C.33C4][.0FFE.0020.001C.33C4] # SQUARE CC; QQKN +33C5 ; [.0FFE.0020.001C.33C5][.1010.0020.001C.33C5] # SQUARE CD; QQKN +33C6 ; [.0FFE.0020.001D.33C6][*04C7.0020.001C.33C6][.10D6.0020.001F.33C6][.106A.0020.001F.33C6] # SQUARE C OVER KG; QQKN +339D ; [.0FFE.0020.001C.339D][.1110.0020.001C.339D] # SQUARE CM; QQKN +33A0 ; [.0FFE.0020.001C.33A0][.1110.0020.001C.33A0][.0FC8.0020.001F.33A0] # SQUARE CM SQUARED; QQKN +33A4 ; [.0FFE.0020.001C.33A4][.1110.0020.001C.33A4][.0FC9.0020.001F.33A4] # SQUARE CM CUBED; QQKN +2105 ; [.0FFE.0020.0004.2105][*02FF.0020.0004.2105][.113B.0020.001F.2105] # CARE OF; QQKN +33C7 ; [.0FFE.0020.001D.33C7][.113B.0020.001C.33C7][*0266.0020.001F.33C7] # SQUARE CO; QQKN +2106 ; [.0FFE.0020.0004.2106][*02FF.0020.0004.2106][.11EE.0020.001F.2106] # CADA UNA; QQKN +1D04 ; [.1002.0020.0002.1D04] # LATIN LETTER SMALL CAPITAL C +023C ; [.1003.0020.0002.023C] # LATIN SMALL LETTER C WITH STROKE +023B ; [.1003.0020.0008.023B] # LATIN CAPITAL LETTER C WITH STROKE +0188 ; [.1007.0020.0002.0188] # LATIN SMALL LETTER C WITH HOOK +0187 ; [.1007.0020.0008.0187] # LATIN CAPITAL LETTER C WITH HOOK +0255 ; [.100B.0020.0002.0255] # LATIN SMALL LETTER C WITH CURL +1D9D ; [.100B.0020.0014.1D9D] # MODIFIER LETTER SMALL C WITH CURL; QQK +2184 ; [.100F.0020.0002.2184] # LATIN SMALL LETTER REVERSED C +2183 ; [.100F.0020.0008.2183] # ROMAN NUMERAL REVERSED ONE HUNDRED +0064 ; [.1010.0020.0002.0064] # LATIN SMALL LETTER D +FF44 ; [.1010.0020.0003.FF44] # FULLWIDTH LATIN SMALL LETTER D; QQK +0369 ; [.1010.0020.0004.0369] # COMBINING LATIN SMALL LETTER D; QQK +217E ; [.1010.0020.0004.217E] # SMALL ROMAN NUMERAL FIVE HUNDRED; QQK +249F ; [*02B1.0020.0004.249F][.1010.0020.0004.249F][*02B2.0020.001F.249F] # PARENTHESIZED LATIN SMALL LETTER D; QQKN +2146 ; [.1010.0020.0005.2146] # DOUBLE-STRUCK ITALIC SMALL D; QQK +1D41D ; [.1010.0020.0005.1D41D] # MATHEMATICAL BOLD SMALL D; QQK +1D451 ; [.1010.0020.0005.1D451] # MATHEMATICAL ITALIC SMALL D; QQK +1D485 ; [.1010.0020.0005.1D485] # MATHEMATICAL BOLD ITALIC SMALL D; QQK +1D4B9 ; [.1010.0020.0005.1D4B9] # MATHEMATICAL SCRIPT SMALL D; QQK +1D4ED ; [.1010.0020.0005.1D4ED] # MATHEMATICAL BOLD SCRIPT SMALL D; QQK +1D521 ; [.1010.0020.0005.1D521] # MATHEMATICAL FRAKTUR SMALL D; QQK +1D555 ; [.1010.0020.0005.1D555] # MATHEMATICAL DOUBLE-STRUCK SMALL D; QQK +1D589 ; [.1010.0020.0005.1D589] # MATHEMATICAL BOLD FRAKTUR SMALL D; QQK +1D5BD ; [.1010.0020.0005.1D5BD] # MATHEMATICAL SANS-SERIF SMALL D; QQK +1D5F1 ; [.1010.0020.0005.1D5F1] # MATHEMATICAL SANS-SERIF BOLD SMALL D; QQK +1D625 ; [.1010.0020.0005.1D625] # MATHEMATICAL SANS-SERIF ITALIC SMALL D; QQK +1D659 ; [.1010.0020.0005.1D659] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL D; QQK +1D68D ; [.1010.0020.0005.1D68D] # MATHEMATICAL MONOSPACE SMALL D; QQK +24D3 ; [.1010.0020.0006.24D3] # CIRCLED LATIN SMALL LETTER D; QQK +0044 ; [.1010.0020.0008.0044] # LATIN CAPITAL LETTER D +FF24 ; [.1010.0020.0009.FF24] # FULLWIDTH LATIN CAPITAL LETTER D; QQK +216E ; [.1010.0020.000A.216E] # ROMAN NUMERAL FIVE HUNDRED; QQK +2145 ; [.1010.0020.000B.2145] # DOUBLE-STRUCK ITALIC CAPITAL D; QQK +1D403 ; [.1010.0020.000B.1D403] # MATHEMATICAL BOLD CAPITAL D; QQK +1D437 ; [.1010.0020.000B.1D437] # MATHEMATICAL ITALIC CAPITAL D; QQK +1D46B ; [.1010.0020.000B.1D46B] # MATHEMATICAL BOLD ITALIC CAPITAL D; QQK +1D49F ; [.1010.0020.000B.1D49F] # MATHEMATICAL SCRIPT CAPITAL D; QQK +1D4D3 ; [.1010.0020.000B.1D4D3] # MATHEMATICAL BOLD SCRIPT CAPITAL D; QQK +1D507 ; [.1010.0020.000B.1D507] # MATHEMATICAL FRAKTUR CAPITAL D; QQK +1D53B ; [.1010.0020.000B.1D53B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL D; QQK +1D56F ; [.1010.0020.000B.1D56F] # MATHEMATICAL BOLD FRAKTUR CAPITAL D; QQK +1D5A3 ; [.1010.0020.000B.1D5A3] # MATHEMATICAL SANS-SERIF CAPITAL D; QQK +1D5D7 ; [.1010.0020.000B.1D5D7] # MATHEMATICAL SANS-SERIF BOLD CAPITAL D; QQK +1D60B ; [.1010.0020.000B.1D60B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL D; QQK +1D63F ; [.1010.0020.000B.1D63F] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL D; QQK +1D673 ; [.1010.0020.000B.1D673] # MATHEMATICAL MONOSPACE CAPITAL D; QQK +24B9 ; [.1010.0020.000C.24B9] # CIRCLED LATIN CAPITAL LETTER D; QQK +1D48 ; [.1010.0020.0014.1D48] # MODIFIER LETTER SMALL D; QQK +1D30 ; [.1010.0020.001D.1D30] # MODIFIER LETTER CAPITAL D; QQK +010F ; [.1010.0020.0002.0064][.0000.0041.0002.030C] # LATIN SMALL LETTER D WITH CARON; QQCM +010E ; [.1010.0020.0008.0044][.0000.0041.0002.030C] # LATIN CAPITAL LETTER D WITH CARON; QQCM +1E0B ; [.1010.0020.0002.0064][.0000.0052.0002.0307] # LATIN SMALL LETTER D WITH DOT ABOVE; QQCM +1E0A ; [.1010.0020.0008.0044][.0000.0052.0002.0307] # LATIN CAPITAL LETTER D WITH DOT ABOVE; QQCM +1E11 ; [.1010.0020.0002.0064][.0000.0056.0002.0327] # LATIN SMALL LETTER D WITH CEDILLA; QQCM +1E10 ; [.1010.0020.0008.0044][.0000.0056.0002.0327] # LATIN CAPITAL LETTER D WITH CEDILLA; QQCM +1E0D ; [.1010.0020.0002.0064][.0000.007A.0002.0323] # LATIN SMALL LETTER D WITH DOT BELOW; QQCM +1E0C ; [.1010.0020.0008.0044][.0000.007A.0002.0323] # LATIN CAPITAL LETTER D WITH DOT BELOW; QQCM +1E13 ; [.1010.0020.0002.0064][.0000.0086.0002.032D] # LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW; QQCM +1E12 ; [.1010.0020.0008.0044][.0000.0086.0002.032D] # LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW; QQCM +1E0F ; [.1010.0020.0002.0064][.0000.008A.0002.0331] # LATIN SMALL LETTER D WITH LINE BELOW; QQCM +1E0E ; [.1010.0020.0008.0044][.0000.008A.0002.0331] # LATIN CAPITAL LETTER D WITH LINE BELOW; QQCM +0111 ; [.1010.0020.0002.0064][.0000.008D.0002.0335] # LATIN SMALL LETTER D WITH STROKE; QQCM +0110 ; [.1010.0020.0008.0044][.0000.008D.0002.0335] # LATIN CAPITAL LETTER D WITH STROKE; QQCM +00F0 ; [.1010.0020.0004.00F0][.0000.0199.0004.00F0] # LATIN SMALL LETTER ETH; QQKN +00D0 ; [.1010.0020.000A.00D0][.0000.0199.0004.00D0] # LATIN CAPITAL LETTER ETH; QQKN +1D9E ; [.1010.0020.0014.1D9E][.0000.0199.0014.1D9E] # MODIFIER LETTER SMALL ETH; QQKN +3372 ; [.1010.0020.001C.3372][.0FD0.0020.001C.3372] # SQUARE DA; QQKN +0238 ; [.1010.0020.0004.0238][.0FE6.0020.0004.0238] # LATIN SMALL LETTER DB DIGRAPH; QQKN +33C8 ; [.1010.0020.001C.33C8][.0FE6.0020.001D.33C8] # SQUARE DB; QQKN +3397 ; [.1010.0020.001C.3397][.10E5.0020.001C.3397] # SQUARE DL; QQKN +3377 ; [.1010.0020.001C.3377][.1110.0020.001C.3377] # SQUARE DM; QQKN +3378 ; [.1010.0020.001C.3378][.1110.0020.001C.3378][.0FC8.0020.001F.3378] # SQUARE DM SQUARED; QQKN +3379 ; [.1010.0020.001C.3379][.1110.0020.001C.3379][.0FC9.0020.001F.3379] # SQUARE DM CUBED; QQKN +01F3 ; [.1010.0020.0004.01F3][.1243.0020.0004.01F3] # LATIN SMALL LETTER DZ; QQKN +02A3 ; [.1010.0020.0004.02A3][.1243.0020.0004.02A3] # LATIN SMALL LETTER DZ DIGRAPH; QQKN +01F2 ; [.1010.0020.000A.01F2][.1243.0020.0004.01F2] # LATIN CAPITAL LETTER D WITH SMALL LETTER Z; QQKN +01F1 ; [.1010.0020.000A.01F1][.1243.0020.000A.01F1] # LATIN CAPITAL LETTER DZ; QQKN +01C6 ; [.1010.0020.0004.01C6][.1243.0020.0004.01C6][.0000.0041.001F.01C6] # LATIN SMALL LETTER DZ WITH CARON; QQKN +01C5 ; [.1010.0020.000A.01C5][.1243.0020.0004.01C5][.0000.0041.001F.01C5] # LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON; QQKN +01C4 ; [.1010.0020.000A.01C4][.1243.0020.000A.01C4][.0000.0041.001F.01C4] # LATIN CAPITAL LETTER DZ WITH CARON; QQKN +02A5 ; [.1010.0020.0004.02A5][.1256.0020.0004.02A5] # LATIN SMALL LETTER DZ DIGRAPH WITH CURL; QQKN +02A4 ; [.1010.0020.0004.02A4][.125F.0020.0004.02A4] # LATIN SMALL LETTER DEZH DIGRAPH; QQKN +1D05 ; [.1014.0020.0002.1D05] # LATIN LETTER SMALL CAPITAL D +1D06 ; [.1015.0020.0002.1D06] # LATIN LETTER SMALL CAPITAL ETH +1D6D ; [.1016.0020.0002.1D6D] # LATIN SMALL LETTER D WITH MIDDLE TILDE +1D81 ; [.1017.0020.0002.1D81] # LATIN SMALL LETTER D WITH PALATAL HOOK +0256 ; [.1018.0020.0002.0256] # LATIN SMALL LETTER D WITH TAIL +0189 ; [.1018.0020.0008.0189] # LATIN CAPITAL LETTER AFRICAN D +0257 ; [.101C.0020.0002.0257] # LATIN SMALL LETTER D WITH HOOK +018A ; [.101C.0020.0008.018A] # LATIN CAPITAL LETTER D WITH HOOK +1D91 ; [.1020.0020.0002.1D91] # LATIN SMALL LETTER D WITH HOOK AND TAIL +018C ; [.1021.0020.0002.018C] # LATIN SMALL LETTER D WITH TOPBAR +018B ; [.1021.0020.0008.018B] # LATIN CAPITAL LETTER D WITH TOPBAR +0221 ; [.1025.0020.0002.0221] # LATIN SMALL LETTER D WITH CURL +0065 ; [.1029.0020.0002.0065] # LATIN SMALL LETTER E +FF45 ; [.1029.0020.0003.FF45] # FULLWIDTH LATIN SMALL LETTER E; QQK +0364 ; [.1029.0020.0004.0364] # COMBINING LATIN SMALL LETTER E; QQK +24A0 ; [*02B1.0020.0004.24A0][.1029.0020.0004.24A0][*02B2.0020.001F.24A0] # PARENTHESIZED LATIN SMALL LETTER E; QQKN +212F ; [.1029.0020.0005.212F] # SCRIPT SMALL E; QQK +2147 ; [.1029.0020.0005.2147] # DOUBLE-STRUCK ITALIC SMALL E; QQK +1D41E ; [.1029.0020.0005.1D41E] # MATHEMATICAL BOLD SMALL E; QQK +1D452 ; [.1029.0020.0005.1D452] # MATHEMATICAL ITALIC SMALL E; QQK +1D486 ; [.1029.0020.0005.1D486] # MATHEMATICAL BOLD ITALIC SMALL E; QQK +1D4EE ; [.1029.0020.0005.1D4EE] # MATHEMATICAL BOLD SCRIPT SMALL E; QQK +1D522 ; [.1029.0020.0005.1D522] # MATHEMATICAL FRAKTUR SMALL E; QQK +1D556 ; [.1029.0020.0005.1D556] # MATHEMATICAL DOUBLE-STRUCK SMALL E; QQK +1D58A ; [.1029.0020.0005.1D58A] # MATHEMATICAL BOLD FRAKTUR SMALL E; QQK +1D5BE ; [.1029.0020.0005.1D5BE] # MATHEMATICAL SANS-SERIF SMALL E; QQK +1D5F2 ; [.1029.0020.0005.1D5F2] # MATHEMATICAL SANS-SERIF BOLD SMALL E; QQK +1D626 ; [.1029.0020.0005.1D626] # MATHEMATICAL SANS-SERIF ITALIC SMALL E; QQK +1D65A ; [.1029.0020.0005.1D65A] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL E; QQK +1D68E ; [.1029.0020.0005.1D68E] # MATHEMATICAL MONOSPACE SMALL E; QQK +24D4 ; [.1029.0020.0006.24D4] # CIRCLED LATIN SMALL LETTER E; QQK +0045 ; [.1029.0020.0008.0045] # LATIN CAPITAL LETTER E +FF25 ; [.1029.0020.0009.FF25] # FULLWIDTH LATIN CAPITAL LETTER E; QQK +2130 ; [.1029.0020.000B.2130] # SCRIPT CAPITAL E; QQK +1D404 ; [.1029.0020.000B.1D404] # MATHEMATICAL BOLD CAPITAL E; QQK +1D438 ; [.1029.0020.000B.1D438] # MATHEMATICAL ITALIC CAPITAL E; QQK +1D46C ; [.1029.0020.000B.1D46C] # MATHEMATICAL BOLD ITALIC CAPITAL E; QQK +1D4D4 ; [.1029.0020.000B.1D4D4] # MATHEMATICAL BOLD SCRIPT CAPITAL E; QQK +1D508 ; [.1029.0020.000B.1D508] # MATHEMATICAL FRAKTUR CAPITAL E; QQK +1D53C ; [.1029.0020.000B.1D53C] # MATHEMATICAL DOUBLE-STRUCK CAPITAL E; QQK +1D570 ; [.1029.0020.000B.1D570] # MATHEMATICAL BOLD FRAKTUR CAPITAL E; QQK +1D5A4 ; [.1029.0020.000B.1D5A4] # MATHEMATICAL SANS-SERIF CAPITAL E; QQK +1D5D8 ; [.1029.0020.000B.1D5D8] # MATHEMATICAL SANS-SERIF BOLD CAPITAL E; QQK +1D60C ; [.1029.0020.000B.1D60C] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL E; QQK +1D640 ; [.1029.0020.000B.1D640] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL E; QQK +1D674 ; [.1029.0020.000B.1D674] # MATHEMATICAL MONOSPACE CAPITAL E; QQK +24BA ; [.1029.0020.000C.24BA] # CIRCLED LATIN CAPITAL LETTER E; QQK +1D49 ; [.1029.0020.0014.1D49] # MODIFIER LETTER SMALL E; QQK +2091 ; [.1029.0020.0015.2091] # LATIN SUBSCRIPT SMALL LETTER E; QQK +1D31 ; [.1029.0020.001D.1D31] # MODIFIER LETTER CAPITAL E; QQK +00E9 ; [.1029.0020.0002.0065][.0000.0032.0002.0301] # LATIN SMALL LETTER E WITH ACUTE; QQCM +00C9 ; [.1029.0020.0008.0045][.0000.0032.0002.0301] # LATIN CAPITAL LETTER E WITH ACUTE; QQCM +00E8 ; [.1029.0020.0002.0065][.0000.0035.0002.0300] # LATIN SMALL LETTER E WITH GRAVE; QQCM +00C8 ; [.1029.0020.0008.0045][.0000.0035.0002.0300] # LATIN CAPITAL LETTER E WITH GRAVE; QQCM +0115 ; [.1029.0020.0002.0065][.0000.0037.0002.0306] # LATIN SMALL LETTER E WITH BREVE; QQCM +0114 ; [.1029.0020.0008.0045][.0000.0037.0002.0306] # LATIN CAPITAL LETTER E WITH BREVE; QQCM +00EA ; [.1029.0020.0002.0065][.0000.003C.0002.0302] # LATIN SMALL LETTER E WITH CIRCUMFLEX; QQCM +00CA ; [.1029.0020.0008.0045][.0000.003C.0002.0302] # LATIN CAPITAL LETTER E WITH CIRCUMFLEX; QQCM +1EBF ; [.1029.0020.0002.0065][.0000.003C.0002.0302][.0000.0032.0002.0301] # LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE; QQCM +1EBE ; [.1029.0020.0008.0045][.0000.003C.0002.0302][.0000.0032.0002.0301] # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE; QQCM +1EC1 ; [.1029.0020.0002.0065][.0000.003C.0002.0302][.0000.0035.0002.0300] # LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE; QQCM +1EC0 ; [.1029.0020.0008.0045][.0000.003C.0002.0302][.0000.0035.0002.0300] # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE; QQCM +1EC5 ; [.1029.0020.0002.0065][.0000.003C.0002.0302][.0000.004E.0002.0303] # LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE; QQCM +1EC4 ; [.1029.0020.0008.0045][.0000.003C.0002.0302][.0000.004E.0002.0303] # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE; QQCM +1EC3 ; [.1029.0020.0002.0065][.0000.003C.0002.0302][.0000.0060.0002.0309] # LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE; QQCM +1EC2 ; [.1029.0020.0008.0045][.0000.003C.0002.0302][.0000.0060.0002.0309] # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE; QQCM +011B ; [.1029.0020.0002.0065][.0000.0041.0002.030C] # LATIN SMALL LETTER E WITH CARON; QQCM +011A ; [.1029.0020.0008.0045][.0000.0041.0002.030C] # LATIN CAPITAL LETTER E WITH CARON; QQCM +00EB ; [.1029.0020.0002.0065][.0000.0047.0002.0308] # LATIN SMALL LETTER E WITH DIAERESIS; QQCM +00CB ; [.1029.0020.0008.0045][.0000.0047.0002.0308] # LATIN CAPITAL LETTER E WITH DIAERESIS; QQCM +1EBD ; [.1029.0020.0002.0065][.0000.004E.0002.0303] # LATIN SMALL LETTER E WITH TILDE; QQCM +1EBC ; [.1029.0020.0008.0045][.0000.004E.0002.0303] # LATIN CAPITAL LETTER E WITH TILDE; QQCM +0117 ; [.1029.0020.0002.0065][.0000.0052.0002.0307] # LATIN SMALL LETTER E WITH DOT ABOVE; QQCM +0116 ; [.1029.0020.0008.0045][.0000.0052.0002.0307] # LATIN CAPITAL LETTER E WITH DOT ABOVE; QQCM +0229 ; [.1029.0020.0002.0065][.0000.0056.0002.0327] # LATIN SMALL LETTER E WITH CEDILLA; QQCM +0228 ; [.1029.0020.0008.0045][.0000.0056.0002.0327] # LATIN CAPITAL LETTER E WITH CEDILLA; QQCM +1E1D ; [.1029.0020.0002.0065][.0000.0056.0002.0327][.0000.0037.0002.0306] # LATIN SMALL LETTER E WITH CEDILLA AND BREVE; QQCM +1E1C ; [.1029.0020.0008.0045][.0000.0056.0002.0327][.0000.0037.0002.0306] # LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE; QQCM +0119 ; [.1029.0020.0002.0065][.0000.0059.0002.0328] # LATIN SMALL LETTER E WITH OGONEK; QQCM +0118 ; [.1029.0020.0008.0045][.0000.0059.0002.0328] # LATIN CAPITAL LETTER E WITH OGONEK; QQCM +0113 ; [.1029.0020.0002.0065][.0000.005B.0002.0304] # LATIN SMALL LETTER E WITH MACRON; QQCM +0112 ; [.1029.0020.0008.0045][.0000.005B.0002.0304] # LATIN CAPITAL LETTER E WITH MACRON; QQCM +1E17 ; [.1029.0020.0002.0065][.0000.005B.0002.0304][.0000.0032.0002.0301] # LATIN SMALL LETTER E WITH MACRON AND ACUTE; QQCM +1E16 ; [.1029.0020.0008.0045][.0000.005B.0002.0304][.0000.0032.0002.0301] # LATIN CAPITAL LETTER E WITH MACRON AND ACUTE; QQCM +1E15 ; [.1029.0020.0002.0065][.0000.005B.0002.0304][.0000.0035.0002.0300] # LATIN SMALL LETTER E WITH MACRON AND GRAVE; QQCM +1E14 ; [.1029.0020.0008.0045][.0000.005B.0002.0304][.0000.0035.0002.0300] # LATIN CAPITAL LETTER E WITH MACRON AND GRAVE; QQCM +1EBB ; [.1029.0020.0002.0065][.0000.0060.0002.0309] # LATIN SMALL LETTER E WITH HOOK ABOVE; QQCM +1EBA ; [.1029.0020.0008.0045][.0000.0060.0002.0309] # LATIN CAPITAL LETTER E WITH HOOK ABOVE; QQCM +0205 ; [.1029.0020.0002.0065][.0000.0063.0002.030F] # LATIN SMALL LETTER E WITH DOUBLE GRAVE; QQCM +0204 ; [.1029.0020.0008.0045][.0000.0063.0002.030F] # LATIN CAPITAL LETTER E WITH DOUBLE GRAVE; QQCM +0207 ; [.1029.0020.0002.0065][.0000.0065.0002.0311] # LATIN SMALL LETTER E WITH INVERTED BREVE; QQCM +0206 ; [.1029.0020.0008.0045][.0000.0065.0002.0311] # LATIN CAPITAL LETTER E WITH INVERTED BREVE; QQCM +1EB9 ; [.1029.0020.0002.0065][.0000.007A.0002.0323] # LATIN SMALL LETTER E WITH DOT BELOW; QQCM +1EB8 ; [.1029.0020.0008.0045][.0000.007A.0002.0323] # LATIN CAPITAL LETTER E WITH DOT BELOW; QQCM +1EC7 ; [.1029.0020.0002.0065][.0000.007A.0002.0323][.0000.003C.0002.0302] # LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW; QQCM +1EC6 ; [.1029.0020.0008.0045][.0000.007A.0002.0323][.0000.003C.0002.0302] # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW; QQCM +1E19 ; [.1029.0020.0002.0065][.0000.0086.0002.032D] # LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW; QQCM +1E18 ; [.1029.0020.0008.0045][.0000.0086.0002.032D] # LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW; QQCM +1E1B ; [.1029.0020.0002.0065][.0000.0089.0002.0330] # LATIN SMALL LETTER E WITH TILDE BELOW; QQCM +1E1A ; [.1029.0020.0008.0045][.0000.0089.0002.0330] # LATIN CAPITAL LETTER E WITH TILDE BELOW; QQCM +32CD ; [.1029.0020.001C.32CD][.117E.0020.001C.32CD][.106A.0020.001F.32CD] # SQUARE ERG; QQKN +32CE ; [.1029.0020.001C.32CE][.1216.0020.001D.32CE] # SQUARE EV; QQKN +1D07 ; [.102D.0020.0002.1D07] # LATIN LETTER SMALL CAPITAL E +0247 ; [.102E.0020.0002.0247] # LATIN SMALL LETTER E WITH STROKE +0246 ; [.102E.0020.0008.0246] # LATIN CAPITAL LETTER E WITH STROKE +1D92 ; [.1032.0020.0002.1D92] # LATIN SMALL LETTER E WITH RETROFLEX HOOK +01DD ; [.1033.0020.0002.01DD] # LATIN SMALL LETTER TURNED E +018E ; [.1033.0020.0008.018E] # LATIN CAPITAL LETTER REVERSED E +1D32 ; [.1033.0020.001D.1D32] # MODIFIER LETTER CAPITAL REVERSED E; QQK +0259 ; [.1037.0020.0002.0259] # LATIN SMALL LETTER SCHWA +018F ; [.1037.0020.0008.018F] # LATIN CAPITAL LETTER SCHWA +1D4A ; [.1037.0020.0014.1D4A] # MODIFIER LETTER SMALL SCHWA; QQK +2094 ; [.1037.0020.0015.2094] # LATIN SUBSCRIPT SMALL LETTER SCHWA; QQK +1D95 ; [.103B.0020.0002.1D95] # LATIN SMALL LETTER SCHWA WITH RETROFLEX HOOK +025B ; [.103C.0020.0002.025B] # LATIN SMALL LETTER OPEN E +0190 ; [.103C.0020.0008.0190] # LATIN CAPITAL LETTER OPEN E +2107 ; [.103C.0020.000A.2107] # EULER CONSTANT; QQK +1D4B ; [.103C.0020.0014.1D4B] # MODIFIER LETTER SMALL OPEN E; QQK +1D93 ; [.1040.0020.0002.1D93] # LATIN SMALL LETTER OPEN E WITH RETROFLEX HOOK +0258 ; [.1041.0020.0002.0258] # LATIN SMALL LETTER REVERSED E +025A ; [.1045.0020.0002.025A] # LATIN SMALL LETTER SCHWA WITH HOOK +025C ; [.1049.0020.0002.025C] # LATIN SMALL LETTER REVERSED OPEN E +1D9F ; [.1049.0020.0014.1D9F] # MODIFIER LETTER SMALL REVERSED OPEN E; QQK +1D94 ; [.104D.0020.0002.1D94] # LATIN SMALL LETTER REVERSED OPEN E WITH RETROFLEX HOOK +1D08 ; [.104E.0020.0002.1D08] # LATIN SMALL LETTER TURNED OPEN E +1D4C ; [.104E.0020.0014.1D4C] # MODIFIER LETTER SMALL TURNED OPEN E; QQK +025D ; [.104F.0020.0002.025D] # LATIN SMALL LETTER REVERSED OPEN E WITH HOOK +025E ; [.1053.0020.0002.025E] # LATIN SMALL LETTER CLOSED REVERSED OPEN E +029A ; [.1057.0020.0002.029A] # LATIN SMALL LETTER CLOSED OPEN E +0264 ; [.105B.0020.0002.0264] # LATIN SMALL LETTER RAMS HORN +0066 ; [.105F.0020.0002.0066] # LATIN SMALL LETTER F +FF46 ; [.105F.0020.0003.FF46] # FULLWIDTH LATIN SMALL LETTER F; QQK +24A1 ; [*02B1.0020.0004.24A1][.105F.0020.0004.24A1][*02B2.0020.001F.24A1] # PARENTHESIZED LATIN SMALL LETTER F; QQKN +1D41F ; [.105F.0020.0005.1D41F] # MATHEMATICAL BOLD SMALL F; QQK +1D453 ; [.105F.0020.0005.1D453] # MATHEMATICAL ITALIC SMALL F; QQK +1D487 ; [.105F.0020.0005.1D487] # MATHEMATICAL BOLD ITALIC SMALL F; QQK +1D4BB ; [.105F.0020.0005.1D4BB] # MATHEMATICAL SCRIPT SMALL F; QQK +1D4EF ; [.105F.0020.0005.1D4EF] # MATHEMATICAL BOLD SCRIPT SMALL F; QQK +1D523 ; [.105F.0020.0005.1D523] # MATHEMATICAL FRAKTUR SMALL F; QQK +1D557 ; [.105F.0020.0005.1D557] # MATHEMATICAL DOUBLE-STRUCK SMALL F; QQK +1D58B ; [.105F.0020.0005.1D58B] # MATHEMATICAL BOLD FRAKTUR SMALL F; QQK +1D5BF ; [.105F.0020.0005.1D5BF] # MATHEMATICAL SANS-SERIF SMALL F; QQK +1D5F3 ; [.105F.0020.0005.1D5F3] # MATHEMATICAL SANS-SERIF BOLD SMALL F; QQK +1D627 ; [.105F.0020.0005.1D627] # MATHEMATICAL SANS-SERIF ITALIC SMALL F; QQK +1D65B ; [.105F.0020.0005.1D65B] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL F; QQK +1D68F ; [.105F.0020.0005.1D68F] # MATHEMATICAL MONOSPACE SMALL F; QQK +24D5 ; [.105F.0020.0006.24D5] # CIRCLED LATIN SMALL LETTER F; QQK +0046 ; [.105F.0020.0008.0046] # LATIN CAPITAL LETTER F +FF26 ; [.105F.0020.0009.FF26] # FULLWIDTH LATIN CAPITAL LETTER F; QQK +2109 ; [*03BF.0020.0004.2109][.105F.0020.000A.2109] # DEGREE FAHRENHEIT; QQKN +2131 ; [.105F.0020.000B.2131] # SCRIPT CAPITAL F; QQK +1D405 ; [.105F.0020.000B.1D405] # MATHEMATICAL BOLD CAPITAL F; QQK +1D439 ; [.105F.0020.000B.1D439] # MATHEMATICAL ITALIC CAPITAL F; QQK +1D46D ; [.105F.0020.000B.1D46D] # MATHEMATICAL BOLD ITALIC CAPITAL F; QQK +1D4D5 ; [.105F.0020.000B.1D4D5] # MATHEMATICAL BOLD SCRIPT CAPITAL F; QQK +1D509 ; [.105F.0020.000B.1D509] # MATHEMATICAL FRAKTUR CAPITAL F; QQK +1D53D ; [.105F.0020.000B.1D53D] # MATHEMATICAL DOUBLE-STRUCK CAPITAL F; QQK +1D571 ; [.105F.0020.000B.1D571] # MATHEMATICAL BOLD FRAKTUR CAPITAL F; QQK +1D5A5 ; [.105F.0020.000B.1D5A5] # MATHEMATICAL SANS-SERIF CAPITAL F; QQK +1D5D9 ; [.105F.0020.000B.1D5D9] # MATHEMATICAL SANS-SERIF BOLD CAPITAL F; QQK +1D60D ; [.105F.0020.000B.1D60D] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL F; QQK +1D641 ; [.105F.0020.000B.1D641] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL F; QQK +1D675 ; [.105F.0020.000B.1D675] # MATHEMATICAL MONOSPACE CAPITAL F; QQK +24BB ; [.105F.0020.000C.24BB] # CIRCLED LATIN CAPITAL LETTER F; QQK +1DA0 ; [.105F.0020.0014.1DA0] # MODIFIER LETTER SMALL F; QQK +1E1F ; [.105F.0020.0002.0066][.0000.0052.0002.0307] # LATIN SMALL LETTER F WITH DOT ABOVE; QQCM +1E1E ; [.105F.0020.0008.0046][.0000.0052.0002.0307] # LATIN CAPITAL LETTER F WITH DOT ABOVE; QQCM +213B ; [.105F.0020.000A.213B][.0FD0.0020.000A.213B][.122E.0020.001F.213B] # FACSIMILE SIGN; QQKN +FB00 ; [.105F.0020.0004.FB00][.105F.0020.0004.FB00] # LATIN SMALL LIGATURE FF; QQKN +FB03 ; [.105F.0020.0004.FB03][.105F.0020.0004.FB03][.10A5.0020.001F.FB03] # LATIN SMALL LIGATURE FFI; QQKN +FB04 ; [.105F.0020.0004.FB04][.105F.0020.0004.FB04][.10E5.0020.001F.FB04] # LATIN SMALL LIGATURE FFL; QQKN +FB01 ; [.105F.0020.0004.FB01][.10A5.0020.0004.FB01] # LATIN SMALL LIGATURE FI; QQKN +FB02 ; [.105F.0020.0004.FB02][.10E5.0020.0004.FB02] # LATIN SMALL LIGATURE FL; QQKN +3399 ; [.105F.0020.001C.3399][.1110.0020.001C.3399] # SQUARE FM; QQKN +02A9 ; [.105F.0020.0004.02A9][.1137.0020.0004.02A9] # LATIN SMALL LETTER FENG DIGRAPH; QQKN +1D6E ; [.1063.0020.0002.1D6E] # LATIN SMALL LETTER F WITH MIDDLE TILDE +1D82 ; [.1064.0020.0002.1D82] # LATIN SMALL LETTER F WITH PALATAL HOOK +0192 ; [.1065.0020.0002.0192] # LATIN SMALL LETTER F WITH HOOK +0191 ; [.1065.0020.0008.0191] # LATIN CAPITAL LETTER F WITH HOOK +214E ; [.1069.0020.0002.214E] # TURNED SMALL F +2132 ; [.1069.0020.0008.2132] # TURNED CAPITAL F +0067 ; [.106A.0020.0002.0067] # LATIN SMALL LETTER G +FF47 ; [.106A.0020.0003.FF47] # FULLWIDTH LATIN SMALL LETTER G; QQK +24A2 ; [*02B1.0020.0004.24A2][.106A.0020.0004.24A2][*02B2.0020.001F.24A2] # PARENTHESIZED LATIN SMALL LETTER G; QQKN +210A ; [.106A.0020.0005.210A] # SCRIPT SMALL G; QQK +1D420 ; [.106A.0020.0005.1D420] # MATHEMATICAL BOLD SMALL G; QQK +1D454 ; [.106A.0020.0005.1D454] # MATHEMATICAL ITALIC SMALL G; QQK +1D488 ; [.106A.0020.0005.1D488] # MATHEMATICAL BOLD ITALIC SMALL G; QQK +1D4F0 ; [.106A.0020.0005.1D4F0] # MATHEMATICAL BOLD SCRIPT SMALL G; QQK +1D524 ; [.106A.0020.0005.1D524] # MATHEMATICAL FRAKTUR SMALL G; QQK +1D558 ; [.106A.0020.0005.1D558] # MATHEMATICAL DOUBLE-STRUCK SMALL G; QQK +1D58C ; [.106A.0020.0005.1D58C] # MATHEMATICAL BOLD FRAKTUR SMALL G; QQK +1D5C0 ; [.106A.0020.0005.1D5C0] # MATHEMATICAL SANS-SERIF SMALL G; QQK +1D5F4 ; [.106A.0020.0005.1D5F4] # MATHEMATICAL SANS-SERIF BOLD SMALL G; QQK +1D628 ; [.106A.0020.0005.1D628] # MATHEMATICAL SANS-SERIF ITALIC SMALL G; QQK +1D65C ; [.106A.0020.0005.1D65C] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL G; QQK +1D690 ; [.106A.0020.0005.1D690] # MATHEMATICAL MONOSPACE SMALL G; QQK +24D6 ; [.106A.0020.0006.24D6] # CIRCLED LATIN SMALL LETTER G; QQK +0047 ; [.106A.0020.0008.0047] # LATIN CAPITAL LETTER G +FF27 ; [.106A.0020.0009.FF27] # FULLWIDTH LATIN CAPITAL LETTER G; QQK +1D406 ; [.106A.0020.000B.1D406] # MATHEMATICAL BOLD CAPITAL G; QQK +1D43A ; [.106A.0020.000B.1D43A] # MATHEMATICAL ITALIC CAPITAL G; QQK +1D46E ; [.106A.0020.000B.1D46E] # MATHEMATICAL BOLD ITALIC CAPITAL G; QQK +1D4A2 ; [.106A.0020.000B.1D4A2] # MATHEMATICAL SCRIPT CAPITAL G; QQK +1D4D6 ; [.106A.0020.000B.1D4D6] # MATHEMATICAL BOLD SCRIPT CAPITAL G; QQK +1D50A ; [.106A.0020.000B.1D50A] # MATHEMATICAL FRAKTUR CAPITAL G; QQK +1D53E ; [.106A.0020.000B.1D53E] # MATHEMATICAL DOUBLE-STRUCK CAPITAL G; QQK +1D572 ; [.106A.0020.000B.1D572] # MATHEMATICAL BOLD FRAKTUR CAPITAL G; QQK +1D5A6 ; [.106A.0020.000B.1D5A6] # MATHEMATICAL SANS-SERIF CAPITAL G; QQK +1D5DA ; [.106A.0020.000B.1D5DA] # MATHEMATICAL SANS-SERIF BOLD CAPITAL G; QQK +1D60E ; [.106A.0020.000B.1D60E] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL G; QQK +1D642 ; [.106A.0020.000B.1D642] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL G; QQK +1D676 ; [.106A.0020.000B.1D676] # MATHEMATICAL MONOSPACE CAPITAL G; QQK +24BC ; [.106A.0020.000C.24BC] # CIRCLED LATIN CAPITAL LETTER G; QQK +1D4D ; [.106A.0020.0014.1D4D] # MODIFIER LETTER SMALL G; QQK +1D33 ; [.106A.0020.001D.1D33] # MODIFIER LETTER CAPITAL G; QQK +01F5 ; [.106A.0020.0002.0067][.0000.0032.0002.0301] # LATIN SMALL LETTER G WITH ACUTE; QQCM +01F4 ; [.106A.0020.0008.0047][.0000.0032.0002.0301] # LATIN CAPITAL LETTER G WITH ACUTE; QQCM +011F ; [.106A.0020.0002.0067][.0000.0037.0002.0306] # LATIN SMALL LETTER G WITH BREVE; QQCM +011E ; [.106A.0020.0008.0047][.0000.0037.0002.0306] # LATIN CAPITAL LETTER G WITH BREVE; QQCM +011D ; [.106A.0020.0002.0067][.0000.003C.0002.0302] # LATIN SMALL LETTER G WITH CIRCUMFLEX; QQCM +011C ; [.106A.0020.0008.0047][.0000.003C.0002.0302] # LATIN CAPITAL LETTER G WITH CIRCUMFLEX; QQCM +01E7 ; [.106A.0020.0002.0067][.0000.0041.0002.030C] # LATIN SMALL LETTER G WITH CARON; QQCM +01E6 ; [.106A.0020.0008.0047][.0000.0041.0002.030C] # LATIN CAPITAL LETTER G WITH CARON; QQCM +0121 ; [.106A.0020.0002.0067][.0000.0052.0002.0307] # LATIN SMALL LETTER G WITH DOT ABOVE; QQCM +0120 ; [.106A.0020.0008.0047][.0000.0052.0002.0307] # LATIN CAPITAL LETTER G WITH DOT ABOVE; QQCM +0123 ; [.106A.0020.0002.0067][.0000.0056.0002.0327] # LATIN SMALL LETTER G WITH CEDILLA; QQCM +0122 ; [.106A.0020.0008.0047][.0000.0056.0002.0327] # LATIN CAPITAL LETTER G WITH CEDILLA; QQCM +1E21 ; [.106A.0020.0002.0067][.0000.005B.0002.0304] # LATIN SMALL LETTER G WITH MACRON; QQCM +1E20 ; [.106A.0020.0008.0047][.0000.005B.0002.0304] # LATIN CAPITAL LETTER G WITH MACRON; QQCM +33FF ; [.106A.0020.001C.33FF][.0FD0.0020.001C.33FF][.10E5.0020.001F.33FF] # SQUARE GAL; QQKN +3387 ; [.106A.0020.001D.3387][.0FE6.0020.001D.3387] # SQUARE GB; QQKN +3393 ; [.106A.0020.001D.3393][.108D.0020.001D.3393][.1243.0020.001F.3393] # SQUARE GHZ; QQKN +33AC ; [.106A.0020.001D.33AC][.115D.0020.001D.33AC][.0FD0.0020.001F.33AC] # SQUARE GPA; QQKN +33C9 ; [.106A.0020.001D.33C9][.1233.0020.001C.33C9] # SQUARE GY; QQKN +0261 ; [.106E.0020.0002.0261] # LATIN SMALL LETTER SCRIPT G +1DA2 ; [.106E.0020.0014.1DA2] # MODIFIER LETTER SMALL SCRIPT G; QQK +1D79 ; [.1072.0020.0002.1D79] # LATIN SMALL LETTER INSULAR G +0262 ; [.1073.0020.0002.0262] # LATIN LETTER SMALL CAPITAL G +01E5 ; [.1077.0020.0002.01E5] # LATIN SMALL LETTER G WITH STROKE +01E4 ; [.1077.0020.0008.01E4] # LATIN CAPITAL LETTER G WITH STROKE +1D83 ; [.107B.0020.0002.1D83] # LATIN SMALL LETTER G WITH PALATAL HOOK +0260 ; [.107C.0020.0002.0260] # LATIN SMALL LETTER G WITH HOOK +0193 ; [.107C.0020.0008.0193] # LATIN CAPITAL LETTER G WITH HOOK +029B ; [.1080.0020.0002.029B] # LATIN LETTER SMALL CAPITAL G WITH HOOK +1D77 ; [.1084.0020.0002.1D77] # LATIN SMALL LETTER TURNED G +0263 ; [.1085.0020.0002.0263] # LATIN SMALL LETTER GAMMA +0194 ; [.1085.0020.0008.0194] # LATIN CAPITAL LETTER GAMMA +02E0 ; [.1085.0020.0014.02E0] # MODIFIER LETTER SMALL GAMMA; QQK +01A3 ; [.1089.0020.0002.01A3] # LATIN SMALL LETTER OI +01A2 ; [.1089.0020.0008.01A2] # LATIN CAPITAL LETTER OI +0068 ; [.108D.0020.0002.0068] # LATIN SMALL LETTER H +FF48 ; [.108D.0020.0003.FF48] # FULLWIDTH LATIN SMALL LETTER H; QQK +036A ; [.108D.0020.0004.036A] # COMBINING LATIN SMALL LETTER H; QQK +24A3 ; [*02B1.0020.0004.24A3][.108D.0020.0004.24A3][*02B2.0020.001F.24A3] # PARENTHESIZED LATIN SMALL LETTER H; QQKN +210E ; [.108D.0020.0005.210E] # PLANCK CONSTANT; QQK +1D421 ; [.108D.0020.0005.1D421] # MATHEMATICAL BOLD SMALL H; QQK +1D489 ; [.108D.0020.0005.1D489] # MATHEMATICAL BOLD ITALIC SMALL H; QQK +1D4BD ; [.108D.0020.0005.1D4BD] # MATHEMATICAL SCRIPT SMALL H; QQK +1D4F1 ; [.108D.0020.0005.1D4F1] # MATHEMATICAL BOLD SCRIPT SMALL H; QQK +1D525 ; [.108D.0020.0005.1D525] # MATHEMATICAL FRAKTUR SMALL H; QQK +1D559 ; [.108D.0020.0005.1D559] # MATHEMATICAL DOUBLE-STRUCK SMALL H; QQK +1D58D ; [.108D.0020.0005.1D58D] # MATHEMATICAL BOLD FRAKTUR SMALL H; QQK +1D5C1 ; [.108D.0020.0005.1D5C1] # MATHEMATICAL SANS-SERIF SMALL H; QQK +1D5F5 ; [.108D.0020.0005.1D5F5] # MATHEMATICAL SANS-SERIF BOLD SMALL H; QQK +1D629 ; [.108D.0020.0005.1D629] # MATHEMATICAL SANS-SERIF ITALIC SMALL H; QQK +1D65D ; [.108D.0020.0005.1D65D] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL H; QQK +1D691 ; [.108D.0020.0005.1D691] # MATHEMATICAL MONOSPACE SMALL H; QQK +24D7 ; [.108D.0020.0006.24D7] # CIRCLED LATIN SMALL LETTER H; QQK +0048 ; [.108D.0020.0008.0048] # LATIN CAPITAL LETTER H +FF28 ; [.108D.0020.0009.FF28] # FULLWIDTH LATIN CAPITAL LETTER H; QQK +210B ; [.108D.0020.000B.210B] # SCRIPT CAPITAL H; QQK +210C ; [.108D.0020.000B.210C] # BLACK-LETTER CAPITAL H; QQK +210D ; [.108D.0020.000B.210D] # DOUBLE-STRUCK CAPITAL H; QQK +1D407 ; [.108D.0020.000B.1D407] # MATHEMATICAL BOLD CAPITAL H; QQK +1D43B ; [.108D.0020.000B.1D43B] # MATHEMATICAL ITALIC CAPITAL H; QQK +1D46F ; [.108D.0020.000B.1D46F] # MATHEMATICAL BOLD ITALIC CAPITAL H; QQK +1D4D7 ; [.108D.0020.000B.1D4D7] # MATHEMATICAL BOLD SCRIPT CAPITAL H; QQK +1D573 ; [.108D.0020.000B.1D573] # MATHEMATICAL BOLD FRAKTUR CAPITAL H; QQK +1D5A7 ; [.108D.0020.000B.1D5A7] # MATHEMATICAL SANS-SERIF CAPITAL H; QQK +1D5DB ; [.108D.0020.000B.1D5DB] # MATHEMATICAL SANS-SERIF BOLD CAPITAL H; QQK +1D60F ; [.108D.0020.000B.1D60F] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL H; QQK +1D643 ; [.108D.0020.000B.1D643] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL H; QQK +1D677 ; [.108D.0020.000B.1D677] # MATHEMATICAL MONOSPACE CAPITAL H; QQK +24BD ; [.108D.0020.000C.24BD] # CIRCLED LATIN CAPITAL LETTER H; QQK +02B0 ; [.108D.0020.0014.02B0] # MODIFIER LETTER SMALL H; QQK +1D34 ; [.108D.0020.001D.1D34] # MODIFIER LETTER CAPITAL H; QQK +0125 ; [.108D.0020.0002.0068][.0000.003C.0002.0302] # LATIN SMALL LETTER H WITH CIRCUMFLEX; QQCM +0124 ; [.108D.0020.0008.0048][.0000.003C.0002.0302] # LATIN CAPITAL LETTER H WITH CIRCUMFLEX; QQCM +021F ; [.108D.0020.0002.0068][.0000.0041.0002.030C] # LATIN SMALL LETTER H WITH CARON; QQCM +021E ; [.108D.0020.0008.0048][.0000.0041.0002.030C] # LATIN CAPITAL LETTER H WITH CARON; QQCM +1E27 ; [.108D.0020.0002.0068][.0000.0047.0002.0308] # LATIN SMALL LETTER H WITH DIAERESIS; QQCM +1E26 ; [.108D.0020.0008.0048][.0000.0047.0002.0308] # LATIN CAPITAL LETTER H WITH DIAERESIS; QQCM +1E23 ; [.108D.0020.0002.0068][.0000.0052.0002.0307] # LATIN SMALL LETTER H WITH DOT ABOVE; QQCM +1E22 ; [.108D.0020.0008.0048][.0000.0052.0002.0307] # LATIN CAPITAL LETTER H WITH DOT ABOVE; QQCM +1E29 ; [.108D.0020.0002.0068][.0000.0056.0002.0327] # LATIN SMALL LETTER H WITH CEDILLA; QQCM +1E28 ; [.108D.0020.0008.0048][.0000.0056.0002.0327] # LATIN CAPITAL LETTER H WITH CEDILLA; QQCM +1E25 ; [.108D.0020.0002.0068][.0000.007A.0002.0323] # LATIN SMALL LETTER H WITH DOT BELOW; QQCM +1E24 ; [.108D.0020.0008.0048][.0000.007A.0002.0323] # LATIN CAPITAL LETTER H WITH DOT BELOW; QQCM +1E2B ; [.108D.0020.0002.0068][.0000.0087.0002.032E] # LATIN SMALL LETTER H WITH BREVE BELOW; QQCM +1E2A ; [.108D.0020.0008.0048][.0000.0087.0002.032E] # LATIN CAPITAL LETTER H WITH BREVE BELOW; QQCM +1E96 ; [.108D.0020.0002.0068][.0000.008A.0002.0331] # LATIN SMALL LETTER H WITH LINE BELOW; QQCM +0127 ; [.108D.0020.0002.0068][.0000.008D.0002.0335] # LATIN SMALL LETTER H WITH STROKE; QQCM +210F ; [.108D.0020.0002.210F][.0000.008D.0002.210F] # PLANCK CONSTANT OVER TWO PI; QQKN +0126 ; [.108D.0020.0008.0048][.0000.008D.0002.0335] # LATIN CAPITAL LETTER H WITH STROKE; QQCM +33CA ; [.108D.0020.001C.33CA][.0FD0.0020.001C.33CA] # SQUARE HA; QQKN +32CC ; [.108D.0020.001D.32CC][.106A.0020.001C.32CC] # SQUARE HG; QQKN +33CB ; [.108D.0020.001D.33CB][.115D.0020.001D.33CB] # SQUARE HP; QQKN +3371 ; [.108D.0020.001C.3371][.115D.0020.001D.3371][.0FD0.0020.001F.3371] # SQUARE HPA; QQKN +3390 ; [.108D.0020.001D.3390][.1243.0020.001C.3390] # SQUARE HZ; QQKN +029C ; [.1091.0020.0002.029C] # LATIN LETTER SMALL CAPITAL H +0195 ; [.1095.0020.0002.0195] # LATIN SMALL LETTER HV +01F6 ; [.1095.0020.0008.01F6] # LATIN CAPITAL LETTER HWAIR +0266 ; [.1099.0020.0002.0266] # LATIN SMALL LETTER H WITH HOOK +02B1 ; [.1099.0020.0014.02B1] # MODIFIER LETTER SMALL H WITH HOOK; QQK +2C68 ; [.109D.0020.0002.2C68] # LATIN SMALL LETTER H WITH DESCENDER +2C67 ; [.109D.0020.0008.2C67] # LATIN CAPITAL LETTER H WITH DESCENDER +2C76 ; [.109E.0020.0002.2C76] # LATIN SMALL LETTER HALF H +2C75 ; [.109E.0020.0008.2C75] # LATIN CAPITAL LETTER HALF H +0267 ; [.109F.0020.0002.0267] # LATIN SMALL LETTER HENG WITH HOOK +02BB ; [.10A3.0020.0002.02BB] # MODIFIER LETTER TURNED COMMA +02BD ; [.10A4.0020.0002.02BD] # MODIFIER LETTER REVERSED COMMA +0069 ; [.10A5.0020.0002.0069] # LATIN SMALL LETTER I +FF49 ; [.10A5.0020.0003.FF49] # FULLWIDTH LATIN SMALL LETTER I; QQK +0365 ; [.10A5.0020.0004.0365] # COMBINING LATIN SMALL LETTER I; QQK +2170 ; [.10A5.0020.0004.2170] # SMALL ROMAN NUMERAL ONE; QQK +24A4 ; [*02B1.0020.0004.24A4][.10A5.0020.0004.24A4][*02B2.0020.001F.24A4] # PARENTHESIZED LATIN SMALL LETTER I; QQKN +2139 ; [.10A5.0020.0005.2139] # INFORMATION SOURCE; QQK +2148 ; [.10A5.0020.0005.2148] # DOUBLE-STRUCK ITALIC SMALL I; QQK +1D422 ; [.10A5.0020.0005.1D422] # MATHEMATICAL BOLD SMALL I; QQK +1D456 ; [.10A5.0020.0005.1D456] # MATHEMATICAL ITALIC SMALL I; QQK +1D48A ; [.10A5.0020.0005.1D48A] # MATHEMATICAL BOLD ITALIC SMALL I; QQK +1D4BE ; [.10A5.0020.0005.1D4BE] # MATHEMATICAL SCRIPT SMALL I; QQK +1D4F2 ; [.10A5.0020.0005.1D4F2] # MATHEMATICAL BOLD SCRIPT SMALL I; QQK +1D526 ; [.10A5.0020.0005.1D526] # MATHEMATICAL FRAKTUR SMALL I; QQK +1D55A ; [.10A5.0020.0005.1D55A] # MATHEMATICAL DOUBLE-STRUCK SMALL I; QQK +1D58E ; [.10A5.0020.0005.1D58E] # MATHEMATICAL BOLD FRAKTUR SMALL I; QQK +1D5C2 ; [.10A5.0020.0005.1D5C2] # MATHEMATICAL SANS-SERIF SMALL I; QQK +1D5F6 ; [.10A5.0020.0005.1D5F6] # MATHEMATICAL SANS-SERIF BOLD SMALL I; QQK +1D62A ; [.10A5.0020.0005.1D62A] # MATHEMATICAL SANS-SERIF ITALIC SMALL I; QQK +1D65E ; [.10A5.0020.0005.1D65E] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I; QQK +1D692 ; [.10A5.0020.0005.1D692] # MATHEMATICAL MONOSPACE SMALL I; QQK +24D8 ; [.10A5.0020.0006.24D8] # CIRCLED LATIN SMALL LETTER I; QQK +0049 ; [.10A5.0020.0008.0049] # LATIN CAPITAL LETTER I +FF29 ; [.10A5.0020.0009.FF29] # FULLWIDTH LATIN CAPITAL LETTER I; QQK +2160 ; [.10A5.0020.000A.2160] # ROMAN NUMERAL ONE; QQK +2110 ; [.10A5.0020.000B.2110] # SCRIPT CAPITAL I; QQK +2111 ; [.10A5.0020.000B.2111] # BLACK-LETTER CAPITAL I; QQK +1D408 ; [.10A5.0020.000B.1D408] # MATHEMATICAL BOLD CAPITAL I; QQK +1D43C ; [.10A5.0020.000B.1D43C] # MATHEMATICAL ITALIC CAPITAL I; QQK +1D470 ; [.10A5.0020.000B.1D470] # MATHEMATICAL BOLD ITALIC CAPITAL I; QQK +1D4D8 ; [.10A5.0020.000B.1D4D8] # MATHEMATICAL BOLD SCRIPT CAPITAL I; QQK +1D540 ; [.10A5.0020.000B.1D540] # MATHEMATICAL DOUBLE-STRUCK CAPITAL I; QQK +1D574 ; [.10A5.0020.000B.1D574] # MATHEMATICAL BOLD FRAKTUR CAPITAL I; QQK +1D5A8 ; [.10A5.0020.000B.1D5A8] # MATHEMATICAL SANS-SERIF CAPITAL I; QQK +1D5DC ; [.10A5.0020.000B.1D5DC] # MATHEMATICAL SANS-SERIF BOLD CAPITAL I; QQK +1D610 ; [.10A5.0020.000B.1D610] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL I; QQK +1D644 ; [.10A5.0020.000B.1D644] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL I; QQK +1D678 ; [.10A5.0020.000B.1D678] # MATHEMATICAL MONOSPACE CAPITAL I; QQK +24BE ; [.10A5.0020.000C.24BE] # CIRCLED LATIN CAPITAL LETTER I; QQK +2071 ; [.10A5.0020.0014.2071] # SUPERSCRIPT LATIN SMALL LETTER I; QQK +1D62 ; [.10A5.0020.0015.1D62] # LATIN SUBSCRIPT SMALL LETTER I; QQK +1D35 ; [.10A5.0020.001D.1D35] # MODIFIER LETTER CAPITAL I; QQK +00ED ; [.10A5.0020.0002.0069][.0000.0032.0002.0301] # LATIN SMALL LETTER I WITH ACUTE; QQCM +00CD ; [.10A5.0020.0008.0049][.0000.0032.0002.0301] # LATIN CAPITAL LETTER I WITH ACUTE; QQCM +00EC ; [.10A5.0020.0002.0069][.0000.0035.0002.0300] # LATIN SMALL LETTER I WITH GRAVE; QQCM +00CC ; [.10A5.0020.0008.0049][.0000.0035.0002.0300] # LATIN CAPITAL LETTER I WITH GRAVE; QQCM +012D ; [.10A5.0020.0002.0069][.0000.0037.0002.0306] # LATIN SMALL LETTER I WITH BREVE; QQCM +012C ; [.10A5.0020.0008.0049][.0000.0037.0002.0306] # LATIN CAPITAL LETTER I WITH BREVE; QQCM +00EE ; [.10A5.0020.0002.0069][.0000.003C.0002.0302] # LATIN SMALL LETTER I WITH CIRCUMFLEX; QQCM +00CE ; [.10A5.0020.0008.0049][.0000.003C.0002.0302] # LATIN CAPITAL LETTER I WITH CIRCUMFLEX; QQCM +01D0 ; [.10A5.0020.0002.0069][.0000.0041.0002.030C] # LATIN SMALL LETTER I WITH CARON; QQCM +01CF ; [.10A5.0020.0008.0049][.0000.0041.0002.030C] # LATIN CAPITAL LETTER I WITH CARON; QQCM +00EF ; [.10A5.0020.0002.0069][.0000.0047.0002.0308] # LATIN SMALL LETTER I WITH DIAERESIS; QQCM +00CF ; [.10A5.0020.0008.0049][.0000.0047.0002.0308] # LATIN CAPITAL LETTER I WITH DIAERESIS; QQCM +1E2F ; [.10A5.0020.0002.0069][.0000.0047.0002.0308][.0000.0032.0002.0301] # LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE; QQCM +1E2E ; [.10A5.0020.0008.0049][.0000.0047.0002.0308][.0000.0032.0002.0301] # LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE; QQCM +0129 ; [.10A5.0020.0002.0069][.0000.004E.0002.0303] # LATIN SMALL LETTER I WITH TILDE; QQCM +0128 ; [.10A5.0020.0008.0049][.0000.004E.0002.0303] # LATIN CAPITAL LETTER I WITH TILDE; QQCM +0130 ; [.10A5.0020.0008.0049][.0000.0052.0002.0307] # LATIN CAPITAL LETTER I WITH DOT ABOVE; QQCM +012F ; [.10A5.0020.0002.0069][.0000.0059.0002.0328] # LATIN SMALL LETTER I WITH OGONEK; QQCM +012E ; [.10A5.0020.0008.0049][.0000.0059.0002.0328] # LATIN CAPITAL LETTER I WITH OGONEK; QQCM +012B ; [.10A5.0020.0002.0069][.0000.005B.0002.0304] # LATIN SMALL LETTER I WITH MACRON; QQCM +012A ; [.10A5.0020.0008.0049][.0000.005B.0002.0304] # LATIN CAPITAL LETTER I WITH MACRON; QQCM +1EC9 ; [.10A5.0020.0002.0069][.0000.0060.0002.0309] # LATIN SMALL LETTER I WITH HOOK ABOVE; QQCM +1EC8 ; [.10A5.0020.0008.0049][.0000.0060.0002.0309] # LATIN CAPITAL LETTER I WITH HOOK ABOVE; QQCM +0209 ; [.10A5.0020.0002.0069][.0000.0063.0002.030F] # LATIN SMALL LETTER I WITH DOUBLE GRAVE; QQCM +0208 ; [.10A5.0020.0008.0049][.0000.0063.0002.030F] # LATIN CAPITAL LETTER I WITH DOUBLE GRAVE; QQCM +020B ; [.10A5.0020.0002.0069][.0000.0065.0002.0311] # LATIN SMALL LETTER I WITH INVERTED BREVE; QQCM +020A ; [.10A5.0020.0008.0049][.0000.0065.0002.0311] # LATIN CAPITAL LETTER I WITH INVERTED BREVE; QQCM +1ECB ; [.10A5.0020.0002.0069][.0000.007A.0002.0323] # LATIN SMALL LETTER I WITH DOT BELOW; QQCM +1ECA ; [.10A5.0020.0008.0049][.0000.007A.0002.0323] # LATIN CAPITAL LETTER I WITH DOT BELOW; QQCM +1E2D ; [.10A5.0020.0002.0069][.0000.0089.0002.0330] # LATIN SMALL LETTER I WITH TILDE BELOW; QQCM +1E2C ; [.10A5.0020.0008.0049][.0000.0089.0002.0330] # LATIN CAPITAL LETTER I WITH TILDE BELOW; QQCM +2171 ; [.10A5.0020.0004.2171][.10A5.0020.0004.2171] # SMALL ROMAN NUMERAL TWO; QQKN +2161 ; [.10A5.0020.000A.2161][.10A5.0020.000A.2161] # ROMAN NUMERAL TWO; QQKN +2172 ; [.10A5.0020.0004.2172][.10A5.0020.0004.2172][.10A5.0020.001F.2172] # SMALL ROMAN NUMERAL THREE; QQKN +2162 ; [.10A5.0020.000A.2162][.10A5.0020.000A.2162][.10A5.0020.001F.2162] # ROMAN NUMERAL THREE; QQKN +0133 ; [.10A5.0020.0004.0133][.10BD.0020.0004.0133] # LATIN SMALL LIGATURE IJ; QQKN +0132 ; [.10A5.0020.000A.0132][.10BD.0020.000A.0132] # LATIN CAPITAL LIGATURE IJ; QQKN +33CC ; [.10A5.0020.001C.33CC][.111B.0020.001C.33CC] # SQUARE IN; QQKN +337A ; [.10A5.0020.001D.337A][.11EE.0020.001D.337A] # SQUARE IU; QQKN +2173 ; [.10A5.0020.0004.2173][.1216.0020.0004.2173] # SMALL ROMAN NUMERAL FOUR; QQKN +2163 ; [.10A5.0020.000A.2163][.1216.0020.000A.2163] # ROMAN NUMERAL FOUR; QQKN +2178 ; [.10A5.0020.0004.2178][.122E.0020.0004.2178] # SMALL ROMAN NUMERAL NINE; QQKN +2168 ; [.10A5.0020.000A.2168][.122E.0020.000A.2168] # ROMAN NUMERAL NINE; QQKN +0131 ; [.10A9.0020.0002.0131] # LATIN SMALL LETTER DOTLESS I +1D6A4 ; [.10A9.0020.0005.1D6A4] # MATHEMATICAL ITALIC SMALL DOTLESS I; QQK +026A ; [.10AD.0020.0002.026A] # LATIN LETTER SMALL CAPITAL I +1DA6 ; [.10AD.0020.0014.1DA6] # MODIFIER LETTER SMALL CAPITAL I; QQK +1D09 ; [.10B1.0020.0002.1D09] # LATIN SMALL LETTER TURNED I +1D4E ; [.10B1.0020.0014.1D4E] # MODIFIER LETTER SMALL TURNED I; QQK +0268 ; [.10B2.0020.0002.0268] # LATIN SMALL LETTER I WITH STROKE +0197 ; [.10B2.0020.0008.0197] # LATIN CAPITAL LETTER I WITH STROKE +1DA4 ; [.10B2.0020.0014.1DA4] # MODIFIER LETTER SMALL I WITH STROKE; QQK +1D7B ; [.10B6.0020.0002.1D7B] # LATIN SMALL CAPITAL LETTER I WITH STROKE +1DA7 ; [.10B6.0020.0014.1DA7] # MODIFIER LETTER SMALL CAPITAL I WITH STROKE; QQK +1D96 ; [.10B7.0020.0002.1D96] # LATIN SMALL LETTER I WITH RETROFLEX HOOK +0269 ; [.10B8.0020.0002.0269] # LATIN SMALL LETTER IOTA +0196 ; [.10B8.0020.0008.0196] # LATIN CAPITAL LETTER IOTA +1DA5 ; [.10B8.0020.0014.1DA5] # MODIFIER LETTER SMALL IOTA; QQK +1D7C ; [.10BC.0020.0002.1D7C] # LATIN SMALL LETTER IOTA WITH STROKE +006A ; [.10BD.0020.0002.006A] # LATIN SMALL LETTER J +FF4A ; [.10BD.0020.0003.FF4A] # FULLWIDTH LATIN SMALL LETTER J; QQK +24A5 ; [*02B1.0020.0004.24A5][.10BD.0020.0004.24A5][*02B2.0020.001F.24A5] # PARENTHESIZED LATIN SMALL LETTER J; QQKN +2149 ; [.10BD.0020.0005.2149] # DOUBLE-STRUCK ITALIC SMALL J; QQK +1D423 ; [.10BD.0020.0005.1D423] # MATHEMATICAL BOLD SMALL J; QQK +1D457 ; [.10BD.0020.0005.1D457] # MATHEMATICAL ITALIC SMALL J; QQK +1D48B ; [.10BD.0020.0005.1D48B] # MATHEMATICAL BOLD ITALIC SMALL J; QQK +1D4BF ; [.10BD.0020.0005.1D4BF] # MATHEMATICAL SCRIPT SMALL J; QQK +1D4F3 ; [.10BD.0020.0005.1D4F3] # MATHEMATICAL BOLD SCRIPT SMALL J; QQK +1D527 ; [.10BD.0020.0005.1D527] # MATHEMATICAL FRAKTUR SMALL J; QQK +1D55B ; [.10BD.0020.0005.1D55B] # MATHEMATICAL DOUBLE-STRUCK SMALL J; QQK +1D58F ; [.10BD.0020.0005.1D58F] # MATHEMATICAL BOLD FRAKTUR SMALL J; QQK +1D5C3 ; [.10BD.0020.0005.1D5C3] # MATHEMATICAL SANS-SERIF SMALL J; QQK +1D5F7 ; [.10BD.0020.0005.1D5F7] # MATHEMATICAL SANS-SERIF BOLD SMALL J; QQK +1D62B ; [.10BD.0020.0005.1D62B] # MATHEMATICAL SANS-SERIF ITALIC SMALL J; QQK +1D65F ; [.10BD.0020.0005.1D65F] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J; QQK +1D693 ; [.10BD.0020.0005.1D693] # MATHEMATICAL MONOSPACE SMALL J; QQK +24D9 ; [.10BD.0020.0006.24D9] # CIRCLED LATIN SMALL LETTER J; QQK +004A ; [.10BD.0020.0008.004A] # LATIN CAPITAL LETTER J +FF2A ; [.10BD.0020.0009.FF2A] # FULLWIDTH LATIN CAPITAL LETTER J; QQK +1D409 ; [.10BD.0020.000B.1D409] # MATHEMATICAL BOLD CAPITAL J; QQK +1D43D ; [.10BD.0020.000B.1D43D] # MATHEMATICAL ITALIC CAPITAL J; QQK +1D471 ; [.10BD.0020.000B.1D471] # MATHEMATICAL BOLD ITALIC CAPITAL J; QQK +1D4A5 ; [.10BD.0020.000B.1D4A5] # MATHEMATICAL SCRIPT CAPITAL J; QQK +1D4D9 ; [.10BD.0020.000B.1D4D9] # MATHEMATICAL BOLD SCRIPT CAPITAL J; QQK +1D50D ; [.10BD.0020.000B.1D50D] # MATHEMATICAL FRAKTUR CAPITAL J; QQK +1D541 ; [.10BD.0020.000B.1D541] # MATHEMATICAL DOUBLE-STRUCK CAPITAL J; QQK +1D575 ; [.10BD.0020.000B.1D575] # MATHEMATICAL BOLD FRAKTUR CAPITAL J; QQK +1D5A9 ; [.10BD.0020.000B.1D5A9] # MATHEMATICAL SANS-SERIF CAPITAL J; QQK +1D5DD ; [.10BD.0020.000B.1D5DD] # MATHEMATICAL SANS-SERIF BOLD CAPITAL J; QQK +1D611 ; [.10BD.0020.000B.1D611] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL J; QQK +1D645 ; [.10BD.0020.000B.1D645] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL J; QQK +1D679 ; [.10BD.0020.000B.1D679] # MATHEMATICAL MONOSPACE CAPITAL J; QQK +24BF ; [.10BD.0020.000C.24BF] # CIRCLED LATIN CAPITAL LETTER J; QQK +02B2 ; [.10BD.0020.0014.02B2] # MODIFIER LETTER SMALL J; QQK +1D36 ; [.10BD.0020.001D.1D36] # MODIFIER LETTER CAPITAL J; QQK +0135 ; [.10BD.0020.0002.006A][.0000.003C.0002.0302] # LATIN SMALL LETTER J WITH CIRCUMFLEX; QQCM +0134 ; [.10BD.0020.0008.004A][.0000.003C.0002.0302] # LATIN CAPITAL LETTER J WITH CIRCUMFLEX; QQCM +01F0 ; [.10BD.0020.0002.006A][.0000.0041.0002.030C] # LATIN SMALL LETTER J WITH CARON; QQCM +0237 ; [.10C1.0020.0002.0237] # LATIN SMALL LETTER DOTLESS J +1D6A5 ; [.10C1.0020.0005.1D6A5] # MATHEMATICAL ITALIC SMALL DOTLESS J; QQK +1D0A ; [.10C5.0020.0002.1D0A] # LATIN LETTER SMALL CAPITAL J +0249 ; [.10C6.0020.0002.0249] # LATIN SMALL LETTER J WITH STROKE +0248 ; [.10C6.0020.0008.0248] # LATIN CAPITAL LETTER J WITH STROKE +029D ; [.10CA.0020.0002.029D] # LATIN SMALL LETTER J WITH CROSSED-TAIL +1DA8 ; [.10CA.0020.0014.1DA8] # MODIFIER LETTER SMALL J WITH CROSSED-TAIL; QQK +025F ; [.10CE.0020.0002.025F] # LATIN SMALL LETTER DOTLESS J WITH STROKE +1DA1 ; [.10CE.0020.0014.1DA1] # MODIFIER LETTER SMALL DOTLESS J WITH STROKE; QQK +0284 ; [.10D2.0020.0002.0284] # LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK +006B ; [.10D6.0020.0002.006B] # LATIN SMALL LETTER K +FF4B ; [.10D6.0020.0003.FF4B] # FULLWIDTH LATIN SMALL LETTER K; QQK +24A6 ; [*02B1.0020.0004.24A6][.10D6.0020.0004.24A6][*02B2.0020.001F.24A6] # PARENTHESIZED LATIN SMALL LETTER K; QQKN +1D424 ; [.10D6.0020.0005.1D424] # MATHEMATICAL BOLD SMALL K; QQK +1D458 ; [.10D6.0020.0005.1D458] # MATHEMATICAL ITALIC SMALL K; QQK +1D48C ; [.10D6.0020.0005.1D48C] # MATHEMATICAL BOLD ITALIC SMALL K; QQK +1D4C0 ; [.10D6.0020.0005.1D4C0] # MATHEMATICAL SCRIPT SMALL K; QQK +1D4F4 ; [.10D6.0020.0005.1D4F4] # MATHEMATICAL BOLD SCRIPT SMALL K; QQK +1D528 ; [.10D6.0020.0005.1D528] # MATHEMATICAL FRAKTUR SMALL K; QQK +1D55C ; [.10D6.0020.0005.1D55C] # MATHEMATICAL DOUBLE-STRUCK SMALL K; QQK +1D590 ; [.10D6.0020.0005.1D590] # MATHEMATICAL BOLD FRAKTUR SMALL K; QQK +1D5C4 ; [.10D6.0020.0005.1D5C4] # MATHEMATICAL SANS-SERIF SMALL K; QQK +1D5F8 ; [.10D6.0020.0005.1D5F8] # MATHEMATICAL SANS-SERIF BOLD SMALL K; QQK +1D62C ; [.10D6.0020.0005.1D62C] # MATHEMATICAL SANS-SERIF ITALIC SMALL K; QQK +1D660 ; [.10D6.0020.0005.1D660] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL K; QQK +1D694 ; [.10D6.0020.0005.1D694] # MATHEMATICAL MONOSPACE SMALL K; QQK +24DA ; [.10D6.0020.0006.24DA] # CIRCLED LATIN SMALL LETTER K; QQK +004B ; [.10D6.0020.0008.004B] # LATIN CAPITAL LETTER K +212A ; [.10D6.0020.0008.212A] # KELVIN SIGN; QQC +FF2B ; [.10D6.0020.0009.FF2B] # FULLWIDTH LATIN CAPITAL LETTER K; QQK +1D40A ; [.10D6.0020.000B.1D40A] # MATHEMATICAL BOLD CAPITAL K; QQK +1D43E ; [.10D6.0020.000B.1D43E] # MATHEMATICAL ITALIC CAPITAL K; QQK +1D472 ; [.10D6.0020.000B.1D472] # MATHEMATICAL BOLD ITALIC CAPITAL K; QQK +1D4A6 ; [.10D6.0020.000B.1D4A6] # MATHEMATICAL SCRIPT CAPITAL K; QQK +1D4DA ; [.10D6.0020.000B.1D4DA] # MATHEMATICAL BOLD SCRIPT CAPITAL K; QQK +1D50E ; [.10D6.0020.000B.1D50E] # MATHEMATICAL FRAKTUR CAPITAL K; QQK +1D542 ; [.10D6.0020.000B.1D542] # MATHEMATICAL DOUBLE-STRUCK CAPITAL K; QQK +1D576 ; [.10D6.0020.000B.1D576] # MATHEMATICAL BOLD FRAKTUR CAPITAL K; QQK +1D5AA ; [.10D6.0020.000B.1D5AA] # MATHEMATICAL SANS-SERIF CAPITAL K; QQK +1D5DE ; [.10D6.0020.000B.1D5DE] # MATHEMATICAL SANS-SERIF BOLD CAPITAL K; QQK +1D612 ; [.10D6.0020.000B.1D612] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL K; QQK +1D646 ; [.10D6.0020.000B.1D646] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL K; QQK +1D67A ; [.10D6.0020.000B.1D67A] # MATHEMATICAL MONOSPACE CAPITAL K; QQK +24C0 ; [.10D6.0020.000C.24C0] # CIRCLED LATIN CAPITAL LETTER K; QQK +1D4F ; [.10D6.0020.0014.1D4F] # MODIFIER LETTER SMALL K; QQK +1D37 ; [.10D6.0020.001D.1D37] # MODIFIER LETTER CAPITAL K; QQK +1E31 ; [.10D6.0020.0002.006B][.0000.0032.0002.0301] # LATIN SMALL LETTER K WITH ACUTE; QQCM +1E30 ; [.10D6.0020.0008.004B][.0000.0032.0002.0301] # LATIN CAPITAL LETTER K WITH ACUTE; QQCM +01E9 ; [.10D6.0020.0002.006B][.0000.0041.0002.030C] # LATIN SMALL LETTER K WITH CARON; QQCM +01E8 ; [.10D6.0020.0008.004B][.0000.0041.0002.030C] # LATIN CAPITAL LETTER K WITH CARON; QQCM +0137 ; [.10D6.0020.0002.006B][.0000.0056.0002.0327] # LATIN SMALL LETTER K WITH CEDILLA; QQCM +0136 ; [.10D6.0020.0008.004B][.0000.0056.0002.0327] # LATIN CAPITAL LETTER K WITH CEDILLA; QQCM +1E33 ; [.10D6.0020.0002.006B][.0000.007A.0002.0323] # LATIN SMALL LETTER K WITH DOT BELOW; QQCM +1E32 ; [.10D6.0020.0008.004B][.0000.007A.0002.0323] # LATIN CAPITAL LETTER K WITH DOT BELOW; QQCM +1E35 ; [.10D6.0020.0002.006B][.0000.008A.0002.0331] # LATIN SMALL LETTER K WITH LINE BELOW; QQCM +1E34 ; [.10D6.0020.0008.004B][.0000.008A.0002.0331] # LATIN CAPITAL LETTER K WITH LINE BELOW; QQCM +3384 ; [.10D6.0020.001C.3384][.0FD0.0020.001D.3384] # SQUARE KA; QQKN +3385 ; [.10D6.0020.001D.3385][.0FE6.0020.001D.3385] # SQUARE KB; QQKN +3389 ; [.10D6.0020.001C.3389][.0FFE.0020.001C.3389][.0FD0.0020.001F.3389][.10E5.0020.001F.3389] # SQUARE KCAL; QQKN +338F ; [.10D6.0020.001C.338F][.106A.0020.001C.338F] # SQUARE KG; QQKN +3391 ; [.10D6.0020.001C.3391][.108D.0020.001D.3391][.1243.0020.001F.3391] # SQUARE KHZ; QQKN +33CD ; [.10D6.0020.001D.33CD][.10D6.0020.001D.33CD] # SQUARE KK; QQKN +3398 ; [.10D6.0020.001C.3398][.10E5.0020.001C.3398] # SQUARE KL; QQKN +339E ; [.10D6.0020.001C.339E][.1110.0020.001C.339E] # SQUARE KM; QQKN +33CE ; [.10D6.0020.001D.33CE][.1110.0020.001D.33CE] # SQUARE KM CAPITAL; QQKN +33A2 ; [.10D6.0020.001C.33A2][.1110.0020.001C.33A2][.0FC8.0020.001F.33A2] # SQUARE KM SQUARED; QQKN +33A6 ; [.10D6.0020.001C.33A6][.1110.0020.001C.33A6][.0FC9.0020.001F.33A6] # SQUARE KM CUBED; QQKN +33AA ; [.10D6.0020.001C.33AA][.115D.0020.001D.33AA][.0FD0.0020.001F.33AA] # SQUARE KPA; QQKN +33CF ; [.10D6.0020.001C.33CF][.11CF.0020.001C.33CF] # SQUARE KT; QQKN +33B8 ; [.10D6.0020.001C.33B8][.1216.0020.001D.33B8] # SQUARE KV; QQKN +33BE ; [.10D6.0020.001C.33BE][.1225.0020.001D.33BE] # SQUARE KW; QQKN +33C0 ; [.10D6.0020.001C.33C0][.12F3.0020.001D.33C0] # SQUARE K OHM; QQKN +1D0B ; [.10DA.0020.0002.1D0B] # LATIN LETTER SMALL CAPITAL K +1D84 ; [.10DB.0020.0002.1D84] # LATIN SMALL LETTER K WITH PALATAL HOOK +0199 ; [.10DC.0020.0002.0199] # LATIN SMALL LETTER K WITH HOOK +0198 ; [.10DC.0020.0008.0198] # LATIN CAPITAL LETTER K WITH HOOK +2C6A ; [.10E0.0020.0002.2C6A] # LATIN SMALL LETTER K WITH DESCENDER +2C69 ; [.10E0.0020.0008.2C69] # LATIN CAPITAL LETTER K WITH DESCENDER +029E ; [.10E1.0020.0002.029E] # LATIN SMALL LETTER TURNED K +006C ; [.10E5.0020.0002.006C] # LATIN SMALL LETTER L +FF4C ; [.10E5.0020.0003.FF4C] # FULLWIDTH LATIN SMALL LETTER L; QQK +217C ; [.10E5.0020.0004.217C] # SMALL ROMAN NUMERAL FIFTY; QQK +24A7 ; [*02B1.0020.0004.24A7][.10E5.0020.0004.24A7][*02B2.0020.001F.24A7] # PARENTHESIZED LATIN SMALL LETTER L; QQKN +2113 ; [.10E5.0020.0005.2113] # SCRIPT SMALL L; QQK +1D425 ; [.10E5.0020.0005.1D425] # MATHEMATICAL BOLD SMALL L; QQK +1D459 ; [.10E5.0020.0005.1D459] # MATHEMATICAL ITALIC SMALL L; QQK +1D48D ; [.10E5.0020.0005.1D48D] # MATHEMATICAL BOLD ITALIC SMALL L; QQK +1D4C1 ; [.10E5.0020.0005.1D4C1] # MATHEMATICAL SCRIPT SMALL L; QQK +1D4F5 ; [.10E5.0020.0005.1D4F5] # MATHEMATICAL BOLD SCRIPT SMALL L; QQK +1D529 ; [.10E5.0020.0005.1D529] # MATHEMATICAL FRAKTUR SMALL L; QQK +1D55D ; [.10E5.0020.0005.1D55D] # MATHEMATICAL DOUBLE-STRUCK SMALL L; QQK +1D591 ; [.10E5.0020.0005.1D591] # MATHEMATICAL BOLD FRAKTUR SMALL L; QQK +1D5C5 ; [.10E5.0020.0005.1D5C5] # MATHEMATICAL SANS-SERIF SMALL L; QQK +1D5F9 ; [.10E5.0020.0005.1D5F9] # MATHEMATICAL SANS-SERIF BOLD SMALL L; QQK +1D62D ; [.10E5.0020.0005.1D62D] # MATHEMATICAL SANS-SERIF ITALIC SMALL L; QQK +1D661 ; [.10E5.0020.0005.1D661] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL L; QQK +1D695 ; [.10E5.0020.0005.1D695] # MATHEMATICAL MONOSPACE SMALL L; QQK +24DB ; [.10E5.0020.0006.24DB] # CIRCLED LATIN SMALL LETTER L; QQK +004C ; [.10E5.0020.0008.004C] # LATIN CAPITAL LETTER L +FF2C ; [.10E5.0020.0009.FF2C] # FULLWIDTH LATIN CAPITAL LETTER L; QQK +216C ; [.10E5.0020.000A.216C] # ROMAN NUMERAL FIFTY; QQK +2112 ; [.10E5.0020.000B.2112] # SCRIPT CAPITAL L; QQK +1D40B ; [.10E5.0020.000B.1D40B] # MATHEMATICAL BOLD CAPITAL L; QQK +1D43F ; [.10E5.0020.000B.1D43F] # MATHEMATICAL ITALIC CAPITAL L; QQK +1D473 ; [.10E5.0020.000B.1D473] # MATHEMATICAL BOLD ITALIC CAPITAL L; QQK +1D4DB ; [.10E5.0020.000B.1D4DB] # MATHEMATICAL BOLD SCRIPT CAPITAL L; QQK +1D50F ; [.10E5.0020.000B.1D50F] # MATHEMATICAL FRAKTUR CAPITAL L; QQK +1D543 ; [.10E5.0020.000B.1D543] # MATHEMATICAL DOUBLE-STRUCK CAPITAL L; QQK +1D577 ; [.10E5.0020.000B.1D577] # MATHEMATICAL BOLD FRAKTUR CAPITAL L; QQK +1D5AB ; [.10E5.0020.000B.1D5AB] # MATHEMATICAL SANS-SERIF CAPITAL L; QQK +1D5DF ; [.10E5.0020.000B.1D5DF] # MATHEMATICAL SANS-SERIF BOLD CAPITAL L; QQK +1D613 ; [.10E5.0020.000B.1D613] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL L; QQK +1D647 ; [.10E5.0020.000B.1D647] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL L; QQK +1D67B ; [.10E5.0020.000B.1D67B] # MATHEMATICAL MONOSPACE CAPITAL L; QQK +24C1 ; [.10E5.0020.000C.24C1] # CIRCLED LATIN CAPITAL LETTER L; QQK +02E1 ; [.10E5.0020.0014.02E1] # MODIFIER LETTER SMALL L; QQK +1D38 ; [.10E5.0020.001D.1D38] # MODIFIER LETTER CAPITAL L; QQK +013A ; [.10E5.0020.0002.006C][.0000.0032.0002.0301] # LATIN SMALL LETTER L WITH ACUTE; QQCM +0139 ; [.10E5.0020.0008.004C][.0000.0032.0002.0301] # LATIN CAPITAL LETTER L WITH ACUTE; QQCM +013E ; [.10E5.0020.0002.006C][.0000.0041.0002.030C] # LATIN SMALL LETTER L WITH CARON; QQCM +013D ; [.10E5.0020.0008.004C][.0000.0041.0002.030C] # LATIN CAPITAL LETTER L WITH CARON; QQCM +013C ; [.10E5.0020.0002.006C][.0000.0056.0002.0327] # LATIN SMALL LETTER L WITH CEDILLA; QQCM +013B ; [.10E5.0020.0008.004C][.0000.0056.0002.0327] # LATIN CAPITAL LETTER L WITH CEDILLA; QQCM +1E37 ; [.10E5.0020.0002.006C][.0000.007A.0002.0323] # LATIN SMALL LETTER L WITH DOT BELOW; QQCM +1E36 ; [.10E5.0020.0008.004C][.0000.007A.0002.0323] # LATIN CAPITAL LETTER L WITH DOT BELOW; QQCM +1E39 ; [.10E5.0020.0002.006C][.0000.007A.0002.0323][.0000.005B.0002.0304] # LATIN SMALL LETTER L WITH DOT BELOW AND MACRON; QQCM +1E38 ; [.10E5.0020.0008.004C][.0000.007A.0002.0323][.0000.005B.0002.0304] # LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON; QQCM +1E3D ; [.10E5.0020.0002.006C][.0000.0086.0002.032D] # LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW; QQCM +1E3C ; [.10E5.0020.0008.004C][.0000.0086.0002.032D] # LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW; QQCM +1E3B ; [.10E5.0020.0002.006C][.0000.008A.0002.0331] # LATIN SMALL LETTER L WITH LINE BELOW; QQCM +1E3A ; [.10E5.0020.0008.004C][.0000.008A.0002.0331] # LATIN CAPITAL LETTER L WITH LINE BELOW; QQCM +0142 ; [.10E5.0020.0002.006C][.0000.008D.0002.0335] # LATIN SMALL LETTER L WITH STROKE; QQCM +0141 ; [.10E5.0020.0008.004C][.0000.008D.0002.0335] # LATIN CAPITAL LETTER L WITH STROKE; QQCM +0140 ; [.10E5.0020.0004.0140][.0000.0199.0004.0140][*0273.0020.001F.0140] # LATIN SMALL LETTER L WITH MIDDLE DOT; QQKN +013F ; [.10E5.0020.000A.013F][.0000.0199.0004.013F][*0273.0020.001F.013F] # LATIN CAPITAL LETTER L WITH MIDDLE DOT; QQKN +01C9 ; [.10E5.0020.0004.01C9][.10BD.0020.0004.01C9] # LATIN SMALL LETTER LJ; QQKN +01C8 ; [.10E5.0020.000A.01C8][.10BD.0020.0004.01C8] # LATIN CAPITAL LETTER L WITH SMALL LETTER J; QQKN +01C7 ; [.10E5.0020.000A.01C7][.10BD.0020.000A.01C7] # LATIN CAPITAL LETTER LJ; QQKN +33D0 ; [.10E5.0020.001C.33D0][.1110.0020.001C.33D0] # SQUARE LM; QQKN +33D1 ; [.10E5.0020.001C.33D1][.111B.0020.001C.33D1] # SQUARE LN; QQKN +33D2 ; [.10E5.0020.001C.33D2][.113B.0020.001C.33D2][.106A.0020.001F.33D2] # SQUARE LOG; QQKN +02AA ; [.10E5.0020.0004.02AA][.11AF.0020.0004.02AA] # LATIN SMALL LETTER LS DIGRAPH; QQKN +32CF ; [.10E5.0020.001D.32CF][.11CF.0020.001D.32CF][.1010.0020.001F.32CF] # LIMITED LIABILITY SIGN; QQKN +33D3 ; [.10E5.0020.001C.33D3][.122E.0020.001C.33D3] # SQUARE LX; QQKN +02AB ; [.10E5.0020.0004.02AB][.1243.0020.0004.02AB] # LATIN SMALL LETTER LZ DIGRAPH; QQKN +029F ; [.10E9.0020.0002.029F] # LATIN LETTER SMALL CAPITAL L +1DAB ; [.10E9.0020.0014.1DAB] # MODIFIER LETTER SMALL CAPITAL L; QQK +1D0C ; [.10ED.0020.0002.1D0C] # LATIN LETTER SMALL CAPITAL L WITH STROKE +019A ; [.10EE.0020.0002.019A] # LATIN SMALL LETTER L WITH BAR +023D ; [.10EE.0020.0008.023D] # LATIN CAPITAL LETTER L WITH BAR +2C61 ; [.10F2.0020.0002.2C61] # LATIN SMALL LETTER L WITH DOUBLE BAR +2C60 ; [.10F2.0020.0008.2C60] # LATIN CAPITAL LETTER L WITH DOUBLE BAR +026B ; [.10F3.0020.0002.026B] # LATIN SMALL LETTER L WITH MIDDLE TILDE +2C62 ; [.10F3.0020.0008.2C62] # LATIN CAPITAL LETTER L WITH MIDDLE TILDE +026C ; [.10F7.0020.0002.026C] # LATIN SMALL LETTER L WITH BELT +1D85 ; [.10FB.0020.0002.1D85] # LATIN SMALL LETTER L WITH PALATAL HOOK +1DAA ; [.10FB.0020.0014.1DAA] # MODIFIER LETTER SMALL L WITH PALATAL HOOK; QQK +026D ; [.10FC.0020.0002.026D] # LATIN SMALL LETTER L WITH RETROFLEX HOOK +1DA9 ; [.10FC.0020.0014.1DA9] # MODIFIER LETTER SMALL L WITH RETROFLEX HOOK; QQK +0234 ; [.1100.0020.0002.0234] # LATIN SMALL LETTER L WITH CURL +026E ; [.1104.0020.0002.026E] # LATIN SMALL LETTER LEZH +019B ; [.1108.0020.0002.019B] # LATIN SMALL LETTER LAMBDA WITH STROKE +028E ; [.110C.0020.0002.028E] # LATIN SMALL LETTER TURNED Y +006D ; [.1110.0020.0002.006D] # LATIN SMALL LETTER M +FF4D ; [.1110.0020.0003.FF4D] # FULLWIDTH LATIN SMALL LETTER M; QQK +036B ; [.1110.0020.0004.036B] # COMBINING LATIN SMALL LETTER M; QQK +217F ; [.1110.0020.0004.217F] # SMALL ROMAN NUMERAL ONE THOUSAND; QQK +24A8 ; [*02B1.0020.0004.24A8][.1110.0020.0004.24A8][*02B2.0020.001F.24A8] # PARENTHESIZED LATIN SMALL LETTER M; QQKN +1D426 ; [.1110.0020.0005.1D426] # MATHEMATICAL BOLD SMALL M; QQK +1D45A ; [.1110.0020.0005.1D45A] # MATHEMATICAL ITALIC SMALL M; QQK +1D48E ; [.1110.0020.0005.1D48E] # MATHEMATICAL BOLD ITALIC SMALL M; QQK +1D4C2 ; [.1110.0020.0005.1D4C2] # MATHEMATICAL SCRIPT SMALL M; QQK +1D4F6 ; [.1110.0020.0005.1D4F6] # MATHEMATICAL BOLD SCRIPT SMALL M; QQK +1D52A ; [.1110.0020.0005.1D52A] # MATHEMATICAL FRAKTUR SMALL M; QQK +1D55E ; [.1110.0020.0005.1D55E] # MATHEMATICAL DOUBLE-STRUCK SMALL M; QQK +1D592 ; [.1110.0020.0005.1D592] # MATHEMATICAL BOLD FRAKTUR SMALL M; QQK +1D5C6 ; [.1110.0020.0005.1D5C6] # MATHEMATICAL SANS-SERIF SMALL M; QQK +1D5FA ; [.1110.0020.0005.1D5FA] # MATHEMATICAL SANS-SERIF BOLD SMALL M; QQK +1D62E ; [.1110.0020.0005.1D62E] # MATHEMATICAL SANS-SERIF ITALIC SMALL M; QQK +1D662 ; [.1110.0020.0005.1D662] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL M; QQK +1D696 ; [.1110.0020.0005.1D696] # MATHEMATICAL MONOSPACE SMALL M; QQK +24DC ; [.1110.0020.0006.24DC] # CIRCLED LATIN SMALL LETTER M; QQK +004D ; [.1110.0020.0008.004D] # LATIN CAPITAL LETTER M +FF2D ; [.1110.0020.0009.FF2D] # FULLWIDTH LATIN CAPITAL LETTER M; QQK +216F ; [.1110.0020.000A.216F] # ROMAN NUMERAL ONE THOUSAND; QQK +2133 ; [.1110.0020.000B.2133] # SCRIPT CAPITAL M; QQK +1D40C ; [.1110.0020.000B.1D40C] # MATHEMATICAL BOLD CAPITAL M; QQK +1D440 ; [.1110.0020.000B.1D440] # MATHEMATICAL ITALIC CAPITAL M; QQK +1D474 ; [.1110.0020.000B.1D474] # MATHEMATICAL BOLD ITALIC CAPITAL M; QQK +1D4DC ; [.1110.0020.000B.1D4DC] # MATHEMATICAL BOLD SCRIPT CAPITAL M; QQK +1D510 ; [.1110.0020.000B.1D510] # MATHEMATICAL FRAKTUR CAPITAL M; QQK +1D544 ; [.1110.0020.000B.1D544] # MATHEMATICAL DOUBLE-STRUCK CAPITAL M; QQK +1D578 ; [.1110.0020.000B.1D578] # MATHEMATICAL BOLD FRAKTUR CAPITAL M; QQK +1D5AC ; [.1110.0020.000B.1D5AC] # MATHEMATICAL SANS-SERIF CAPITAL M; QQK +1D5E0 ; [.1110.0020.000B.1D5E0] # MATHEMATICAL SANS-SERIF BOLD CAPITAL M; QQK +1D614 ; [.1110.0020.000B.1D614] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL M; QQK +1D648 ; [.1110.0020.000B.1D648] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL M; QQK +1D67C ; [.1110.0020.000B.1D67C] # MATHEMATICAL MONOSPACE CAPITAL M; QQK +24C2 ; [.1110.0020.000C.24C2] # CIRCLED LATIN CAPITAL LETTER M; QQK +1D50 ; [.1110.0020.0014.1D50] # MODIFIER LETTER SMALL M; QQK +1D39 ; [.1110.0020.001D.1D39] # MODIFIER LETTER CAPITAL M; QQK +1E3F ; [.1110.0020.0002.006D][.0000.0032.0002.0301] # LATIN SMALL LETTER M WITH ACUTE; QQCM +1E3E ; [.1110.0020.0008.004D][.0000.0032.0002.0301] # LATIN CAPITAL LETTER M WITH ACUTE; QQCM +1E41 ; [.1110.0020.0002.006D][.0000.0052.0002.0307] # LATIN SMALL LETTER M WITH DOT ABOVE; QQCM +1E40 ; [.1110.0020.0008.004D][.0000.0052.0002.0307] # LATIN CAPITAL LETTER M WITH DOT ABOVE; QQCM +1E43 ; [.1110.0020.0002.006D][.0000.007A.0002.0323] # LATIN SMALL LETTER M WITH DOT BELOW; QQCM +1E42 ; [.1110.0020.0008.004D][.0000.007A.0002.0323] # LATIN CAPITAL LETTER M WITH DOT BELOW; QQCM +33A1 ; [.1110.0020.001C.33A1][.0FC8.0020.001C.33A1] # SQUARE M SQUARED; QQKN +33A5 ; [.1110.0020.001C.33A5][.0FC9.0020.001C.33A5] # SQUARE M CUBED; QQKN +3383 ; [.1110.0020.001C.3383][.0FD0.0020.001D.3383] # SQUARE MA; QQKN +33D4 ; [.1110.0020.001C.33D4][.0FE6.0020.001C.33D4] # SQUARE MB SMALL; QQKN +3386 ; [.1110.0020.001D.3386][.0FE6.0020.001D.3386] # SQUARE MB; QQKN +338E ; [.1110.0020.001C.338E][.106A.0020.001C.338E] # SQUARE MG; QQKN +3392 ; [.1110.0020.001D.3392][.108D.0020.001D.3392][.1243.0020.001F.3392] # SQUARE MHZ; QQKN +33D5 ; [.1110.0020.001C.33D5][.10A5.0020.001C.33D5][.10E5.0020.001F.33D5] # SQUARE MIL; QQKN +3396 ; [.1110.0020.001C.3396][.10E5.0020.001C.3396] # SQUARE ML; QQKN +339C ; [.1110.0020.001C.339C][.1110.0020.001C.339C] # SQUARE MM; QQKN +339F ; [.1110.0020.001C.339F][.1110.0020.001C.339F][.0FC8.0020.001F.339F] # SQUARE MM SQUARED; QQKN +33A3 ; [.1110.0020.001C.33A3][.1110.0020.001C.33A3][.0FC9.0020.001F.33A3] # SQUARE MM CUBED; QQKN +33D6 ; [.1110.0020.001C.33D6][.113B.0020.001C.33D6][.10E5.0020.001F.33D6] # SQUARE MOL; QQKN +33AB ; [.1110.0020.001D.33AB][.115D.0020.001D.33AB][.0FD0.0020.001F.33AB] # SQUARE MPA; QQKN +33B3 ; [.1110.0020.001C.33B3][.11AF.0020.001C.33B3] # SQUARE MS; QQKN +33A7 ; [.1110.0020.001C.33A7][*04C7.0020.001C.33A7][.11AF.0020.001F.33A7] # SQUARE M OVER S; QQKN +33A8 ; [.1110.0020.001C.33A8][*04C7.0020.001C.33A8][.11AF.0020.001F.33A8][.0FC8.0020.001F.33A8] # SQUARE M OVER S SQUARED; QQKN +33B7 ; [.1110.0020.001C.33B7][.1216.0020.001D.33B7] # SQUARE MV; QQKN +33B9 ; [.1110.0020.001D.33B9][.1216.0020.001D.33B9] # SQUARE MV MEGA; QQKN +33BD ; [.1110.0020.001C.33BD][.1225.0020.001D.33BD] # SQUARE MW; QQKN +33BF ; [.1110.0020.001D.33BF][.1225.0020.001D.33BF] # SQUARE MW MEGA; QQKN +33C1 ; [.1110.0020.001D.33C1][.12F3.0020.001D.33C1] # SQUARE M OHM; QQKN +1D0D ; [.1114.0020.0002.1D0D] # LATIN LETTER SMALL CAPITAL M +1D6F ; [.1115.0020.0002.1D6F] # LATIN SMALL LETTER M WITH MIDDLE TILDE +1D86 ; [.1116.0020.0002.1D86] # LATIN SMALL LETTER M WITH PALATAL HOOK +0271 ; [.1117.0020.0002.0271] # LATIN SMALL LETTER M WITH HOOK +1DAC ; [.1117.0020.0014.1DAC] # MODIFIER LETTER SMALL M WITH HOOK; QQK +006E ; [.111B.0020.0002.006E] # LATIN SMALL LETTER N +FF4E ; [.111B.0020.0003.FF4E] # FULLWIDTH LATIN SMALL LETTER N; QQK +24A9 ; [*02B1.0020.0004.24A9][.111B.0020.0004.24A9][*02B2.0020.001F.24A9] # PARENTHESIZED LATIN SMALL LETTER N; QQKN +1D427 ; [.111B.0020.0005.1D427] # MATHEMATICAL BOLD SMALL N; QQK +1D45B ; [.111B.0020.0005.1D45B] # MATHEMATICAL ITALIC SMALL N; QQK +1D48F ; [.111B.0020.0005.1D48F] # MATHEMATICAL BOLD ITALIC SMALL N; QQK +1D4C3 ; [.111B.0020.0005.1D4C3] # MATHEMATICAL SCRIPT SMALL N; QQK +1D4F7 ; [.111B.0020.0005.1D4F7] # MATHEMATICAL BOLD SCRIPT SMALL N; QQK +1D52B ; [.111B.0020.0005.1D52B] # MATHEMATICAL FRAKTUR SMALL N; QQK +1D55F ; [.111B.0020.0005.1D55F] # MATHEMATICAL DOUBLE-STRUCK SMALL N; QQK +1D593 ; [.111B.0020.0005.1D593] # MATHEMATICAL BOLD FRAKTUR SMALL N; QQK +1D5C7 ; [.111B.0020.0005.1D5C7] # MATHEMATICAL SANS-SERIF SMALL N; QQK +1D5FB ; [.111B.0020.0005.1D5FB] # MATHEMATICAL SANS-SERIF BOLD SMALL N; QQK +1D62F ; [.111B.0020.0005.1D62F] # MATHEMATICAL SANS-SERIF ITALIC SMALL N; QQK +1D663 ; [.111B.0020.0005.1D663] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL N; QQK +1D697 ; [.111B.0020.0005.1D697] # MATHEMATICAL MONOSPACE SMALL N; QQK +24DD ; [.111B.0020.0006.24DD] # CIRCLED LATIN SMALL LETTER N; QQK +004E ; [.111B.0020.0008.004E] # LATIN CAPITAL LETTER N +FF2E ; [.111B.0020.0009.FF2E] # FULLWIDTH LATIN CAPITAL LETTER N; QQK +2115 ; [.111B.0020.000B.2115] # DOUBLE-STRUCK CAPITAL N; QQK +1D40D ; [.111B.0020.000B.1D40D] # MATHEMATICAL BOLD CAPITAL N; QQK +1D441 ; [.111B.0020.000B.1D441] # MATHEMATICAL ITALIC CAPITAL N; QQK +1D475 ; [.111B.0020.000B.1D475] # MATHEMATICAL BOLD ITALIC CAPITAL N; QQK +1D4A9 ; [.111B.0020.000B.1D4A9] # MATHEMATICAL SCRIPT CAPITAL N; QQK +1D4DD ; [.111B.0020.000B.1D4DD] # MATHEMATICAL BOLD SCRIPT CAPITAL N; QQK +1D511 ; [.111B.0020.000B.1D511] # MATHEMATICAL FRAKTUR CAPITAL N; QQK +1D579 ; [.111B.0020.000B.1D579] # MATHEMATICAL BOLD FRAKTUR CAPITAL N; QQK +1D5AD ; [.111B.0020.000B.1D5AD] # MATHEMATICAL SANS-SERIF CAPITAL N; QQK +1D5E1 ; [.111B.0020.000B.1D5E1] # MATHEMATICAL SANS-SERIF BOLD CAPITAL N; QQK +1D615 ; [.111B.0020.000B.1D615] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL N; QQK +1D649 ; [.111B.0020.000B.1D649] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL N; QQK +1D67D ; [.111B.0020.000B.1D67D] # MATHEMATICAL MONOSPACE CAPITAL N; QQK +24C3 ; [.111B.0020.000C.24C3] # CIRCLED LATIN CAPITAL LETTER N; QQK +207F ; [.111B.0020.0014.207F] # SUPERSCRIPT LATIN SMALL LETTER N; QQK +1D3A ; [.111B.0020.001D.1D3A] # MODIFIER LETTER CAPITAL N; QQK +0144 ; [.111B.0020.0002.006E][.0000.0032.0002.0301] # LATIN SMALL LETTER N WITH ACUTE; QQCM +0143 ; [.111B.0020.0008.004E][.0000.0032.0002.0301] # LATIN CAPITAL LETTER N WITH ACUTE; QQCM +01F9 ; [.111B.0020.0002.006E][.0000.0035.0002.0300] # LATIN SMALL LETTER N WITH GRAVE; QQCM +01F8 ; [.111B.0020.0008.004E][.0000.0035.0002.0300] # LATIN CAPITAL LETTER N WITH GRAVE; QQCM +0148 ; [.111B.0020.0002.006E][.0000.0041.0002.030C] # LATIN SMALL LETTER N WITH CARON; QQCM +0147 ; [.111B.0020.0008.004E][.0000.0041.0002.030C] # LATIN CAPITAL LETTER N WITH CARON; QQCM +00F1 ; [.111B.0020.0002.006E][.0000.004E.0002.0303] # LATIN SMALL LETTER N WITH TILDE; QQCM +00D1 ; [.111B.0020.0008.004E][.0000.004E.0002.0303] # LATIN CAPITAL LETTER N WITH TILDE; QQCM +1E45 ; [.111B.0020.0002.006E][.0000.0052.0002.0307] # LATIN SMALL LETTER N WITH DOT ABOVE; QQCM +1E44 ; [.111B.0020.0008.004E][.0000.0052.0002.0307] # LATIN CAPITAL LETTER N WITH DOT ABOVE; QQCM +0146 ; [.111B.0020.0002.006E][.0000.0056.0002.0327] # LATIN SMALL LETTER N WITH CEDILLA; QQCM +0145 ; [.111B.0020.0008.004E][.0000.0056.0002.0327] # LATIN CAPITAL LETTER N WITH CEDILLA; QQCM +1E47 ; [.111B.0020.0002.006E][.0000.007A.0002.0323] # LATIN SMALL LETTER N WITH DOT BELOW; QQCM +1E46 ; [.111B.0020.0008.004E][.0000.007A.0002.0323] # LATIN CAPITAL LETTER N WITH DOT BELOW; QQCM +1E4B ; [.111B.0020.0002.006E][.0000.0086.0002.032D] # LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW; QQCM +1E4A ; [.111B.0020.0008.004E][.0000.0086.0002.032D] # LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW; QQCM +1E49 ; [.111B.0020.0002.006E][.0000.008A.0002.0331] # LATIN SMALL LETTER N WITH LINE BELOW; QQCM +1E48 ; [.111B.0020.0008.004E][.0000.008A.0002.0331] # LATIN CAPITAL LETTER N WITH LINE BELOW; QQCM +3381 ; [.111B.0020.001C.3381][.0FD0.0020.001D.3381] # SQUARE NA; QQKN +338B ; [.111B.0020.001C.338B][.105F.0020.001D.338B] # SQUARE NF; QQKN +01CC ; [.111B.0020.0004.01CC][.10BD.0020.0004.01CC] # LATIN SMALL LETTER NJ; QQKN +01CB ; [.111B.0020.000A.01CB][.10BD.0020.0004.01CB] # LATIN CAPITAL LETTER N WITH SMALL LETTER J; QQKN +01CA ; [.111B.0020.000A.01CA][.10BD.0020.000A.01CA] # LATIN CAPITAL LETTER NJ; QQKN +339A ; [.111B.0020.001C.339A][.1110.0020.001C.339A] # SQUARE NM; QQKN +2116 ; [.111B.0020.000A.2116][.113B.0020.0004.2116] # NUMERO SIGN; QQKN +33B1 ; [.111B.0020.001C.33B1][.11AF.0020.001C.33B1] # SQUARE NS; QQKN +33B5 ; [.111B.0020.001C.33B5][.1216.0020.001D.33B5] # SQUARE NV; QQKN +33BB ; [.111B.0020.001C.33BB][.1225.0020.001D.33BB] # SQUARE NW; QQKN +0274 ; [.111F.0020.0002.0274] # LATIN LETTER SMALL CAPITAL N +1DB0 ; [.111F.0020.0014.1DB0] # MODIFIER LETTER SMALL CAPITAL N; QQK +1D3B ; [.1123.0020.0002.1D3B] # MODIFIER LETTER CAPITAL REVERSED N +1D0E ; [.1124.0020.0002.1D0E] # LATIN LETTER SMALL CAPITAL REVERSED N +1D70 ; [.1125.0020.0002.1D70] # LATIN SMALL LETTER N WITH MIDDLE TILDE +0272 ; [.1126.0020.0002.0272] # LATIN SMALL LETTER N WITH LEFT HOOK +019D ; [.1126.0020.0008.019D] # LATIN CAPITAL LETTER N WITH LEFT HOOK +1DAE ; [.1126.0020.0014.1DAE] # MODIFIER LETTER SMALL N WITH LEFT HOOK; QQK +019E ; [.112A.0020.0002.019E] # LATIN SMALL LETTER N WITH LONG RIGHT LEG +0220 ; [.112A.0020.0008.0220] # LATIN CAPITAL LETTER N WITH LONG RIGHT LEG +1D87 ; [.112E.0020.0002.1D87] # LATIN SMALL LETTER N WITH PALATAL HOOK +0273 ; [.112F.0020.0002.0273] # LATIN SMALL LETTER N WITH RETROFLEX HOOK +1DAF ; [.112F.0020.0014.1DAF] # MODIFIER LETTER SMALL N WITH RETROFLEX HOOK; QQK +0235 ; [.1133.0020.0002.0235] # LATIN SMALL LETTER N WITH CURL +014B ; [.1137.0020.0002.014B] # LATIN SMALL LETTER ENG +014A ; [.1137.0020.0008.014A] # LATIN CAPITAL LETTER ENG +1D51 ; [.1137.0020.0014.1D51] # MODIFIER LETTER SMALL ENG; QQK +006F ; [.113B.0020.0002.006F] # LATIN SMALL LETTER O +FF4F ; [.113B.0020.0003.FF4F] # FULLWIDTH LATIN SMALL LETTER O; QQK +0366 ; [.113B.0020.0004.0366] # COMBINING LATIN SMALL LETTER O; QQK +24AA ; [*02B1.0020.0004.24AA][.113B.0020.0004.24AA][*02B2.0020.001F.24AA] # PARENTHESIZED LATIN SMALL LETTER O; QQKN +2134 ; [.113B.0020.0005.2134] # SCRIPT SMALL O; QQK +1D428 ; [.113B.0020.0005.1D428] # MATHEMATICAL BOLD SMALL O; QQK +1D45C ; [.113B.0020.0005.1D45C] # MATHEMATICAL ITALIC SMALL O; QQK +1D490 ; [.113B.0020.0005.1D490] # MATHEMATICAL BOLD ITALIC SMALL O; QQK +1D4F8 ; [.113B.0020.0005.1D4F8] # MATHEMATICAL BOLD SCRIPT SMALL O; QQK +1D52C ; [.113B.0020.0005.1D52C] # MATHEMATICAL FRAKTUR SMALL O; QQK +1D560 ; [.113B.0020.0005.1D560] # MATHEMATICAL DOUBLE-STRUCK SMALL O; QQK +1D594 ; [.113B.0020.0005.1D594] # MATHEMATICAL BOLD FRAKTUR SMALL O; QQK +1D5C8 ; [.113B.0020.0005.1D5C8] # MATHEMATICAL SANS-SERIF SMALL O; QQK +1D5FC ; [.113B.0020.0005.1D5FC] # MATHEMATICAL SANS-SERIF BOLD SMALL O; QQK +1D630 ; [.113B.0020.0005.1D630] # MATHEMATICAL SANS-SERIF ITALIC SMALL O; QQK +1D664 ; [.113B.0020.0005.1D664] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL O; QQK +1D698 ; [.113B.0020.0005.1D698] # MATHEMATICAL MONOSPACE SMALL O; QQK +24DE ; [.113B.0020.0006.24DE] # CIRCLED LATIN SMALL LETTER O; QQK +004F ; [.113B.0020.0008.004F] # LATIN CAPITAL LETTER O +FF2F ; [.113B.0020.0009.FF2F] # FULLWIDTH LATIN CAPITAL LETTER O; QQK +1D40E ; [.113B.0020.000B.1D40E] # MATHEMATICAL BOLD CAPITAL O; QQK +1D442 ; [.113B.0020.000B.1D442] # MATHEMATICAL ITALIC CAPITAL O; QQK +1D476 ; [.113B.0020.000B.1D476] # MATHEMATICAL BOLD ITALIC CAPITAL O; QQK +1D4AA ; [.113B.0020.000B.1D4AA] # MATHEMATICAL SCRIPT CAPITAL O; QQK +1D4DE ; [.113B.0020.000B.1D4DE] # MATHEMATICAL BOLD SCRIPT CAPITAL O; QQK +1D512 ; [.113B.0020.000B.1D512] # MATHEMATICAL FRAKTUR CAPITAL O; QQK +1D546 ; [.113B.0020.000B.1D546] # MATHEMATICAL DOUBLE-STRUCK CAPITAL O; QQK +1D57A ; [.113B.0020.000B.1D57A] # MATHEMATICAL BOLD FRAKTUR CAPITAL O; QQK +1D5AE ; [.113B.0020.000B.1D5AE] # MATHEMATICAL SANS-SERIF CAPITAL O; QQK +1D5E2 ; [.113B.0020.000B.1D5E2] # MATHEMATICAL SANS-SERIF BOLD CAPITAL O; QQK +1D616 ; [.113B.0020.000B.1D616] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL O; QQK +1D64A ; [.113B.0020.000B.1D64A] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL O; QQK +1D67E ; [.113B.0020.000B.1D67E] # MATHEMATICAL MONOSPACE CAPITAL O; QQK +24C4 ; [.113B.0020.000C.24C4] # CIRCLED LATIN CAPITAL LETTER O; QQK +00BA ; [.113B.0020.0014.00BA] # MASCULINE ORDINAL INDICATOR; QQK +1D52 ; [.113B.0020.0014.1D52] # MODIFIER LETTER SMALL O; QQK +2092 ; [.113B.0020.0015.2092] # LATIN SUBSCRIPT SMALL LETTER O; QQK +1D3C ; [.113B.0020.001D.1D3C] # MODIFIER LETTER CAPITAL O; QQK +00F3 ; [.113B.0020.0002.006F][.0000.0032.0002.0301] # LATIN SMALL LETTER O WITH ACUTE; QQCM +00D3 ; [.113B.0020.0008.004F][.0000.0032.0002.0301] # LATIN CAPITAL LETTER O WITH ACUTE; QQCM +00F2 ; [.113B.0020.0002.006F][.0000.0035.0002.0300] # LATIN SMALL LETTER O WITH GRAVE; QQCM +00D2 ; [.113B.0020.0008.004F][.0000.0035.0002.0300] # LATIN CAPITAL LETTER O WITH GRAVE; QQCM +014F ; [.113B.0020.0002.006F][.0000.0037.0002.0306] # LATIN SMALL LETTER O WITH BREVE; QQCM +014E ; [.113B.0020.0008.004F][.0000.0037.0002.0306] # LATIN CAPITAL LETTER O WITH BREVE; QQCM +00F4 ; [.113B.0020.0002.006F][.0000.003C.0002.0302] # LATIN SMALL LETTER O WITH CIRCUMFLEX; QQCM +00D4 ; [.113B.0020.0008.004F][.0000.003C.0002.0302] # LATIN CAPITAL LETTER O WITH CIRCUMFLEX; QQCM +1ED1 ; [.113B.0020.0002.006F][.0000.003C.0002.0302][.0000.0032.0002.0301] # LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE; QQCM +1ED0 ; [.113B.0020.0008.004F][.0000.003C.0002.0302][.0000.0032.0002.0301] # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE; QQCM +1ED3 ; [.113B.0020.0002.006F][.0000.003C.0002.0302][.0000.0035.0002.0300] # LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE; QQCM +1ED2 ; [.113B.0020.0008.004F][.0000.003C.0002.0302][.0000.0035.0002.0300] # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE; QQCM +1ED7 ; [.113B.0020.0002.006F][.0000.003C.0002.0302][.0000.004E.0002.0303] # LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE; QQCM +1ED6 ; [.113B.0020.0008.004F][.0000.003C.0002.0302][.0000.004E.0002.0303] # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE; QQCM +1ED5 ; [.113B.0020.0002.006F][.0000.003C.0002.0302][.0000.0060.0002.0309] # LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE; QQCM +1ED4 ; [.113B.0020.0008.004F][.0000.003C.0002.0302][.0000.0060.0002.0309] # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE; QQCM +01D2 ; [.113B.0020.0002.006F][.0000.0041.0002.030C] # LATIN SMALL LETTER O WITH CARON; QQCM +01D1 ; [.113B.0020.0008.004F][.0000.0041.0002.030C] # LATIN CAPITAL LETTER O WITH CARON; QQCM +00F6 ; [.113B.0020.0002.006F][.0000.0047.0002.0308] # LATIN SMALL LETTER O WITH DIAERESIS; QQCM +00D6 ; [.113B.0020.0008.004F][.0000.0047.0002.0308] # LATIN CAPITAL LETTER O WITH DIAERESIS; QQCM +022B ; [.113B.0020.0002.006F][.0000.0047.0002.0308][.0000.005B.0002.0304] # LATIN SMALL LETTER O WITH DIAERESIS AND MACRON; QQCM +022A ; [.113B.0020.0008.004F][.0000.0047.0002.0308][.0000.005B.0002.0304] # LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON; QQCM +0151 ; [.113B.0020.0002.006F][.0000.004D.0002.030B] # LATIN SMALL LETTER O WITH DOUBLE ACUTE; QQCM +0150 ; [.113B.0020.0008.004F][.0000.004D.0002.030B] # LATIN CAPITAL LETTER O WITH DOUBLE ACUTE; QQCM +00F5 ; [.113B.0020.0002.006F][.0000.004E.0002.0303] # LATIN SMALL LETTER O WITH TILDE; QQCM +00D5 ; [.113B.0020.0008.004F][.0000.004E.0002.0303] # LATIN CAPITAL LETTER O WITH TILDE; QQCM +1E4D ; [.113B.0020.0002.006F][.0000.004E.0002.0303][.0000.0032.0002.0301] # LATIN SMALL LETTER O WITH TILDE AND ACUTE; QQCM +1E4C ; [.113B.0020.0008.004F][.0000.004E.0002.0303][.0000.0032.0002.0301] # LATIN CAPITAL LETTER O WITH TILDE AND ACUTE; QQCM +1E4F ; [.113B.0020.0002.006F][.0000.004E.0002.0303][.0000.0047.0002.0308] # LATIN SMALL LETTER O WITH TILDE AND DIAERESIS; QQCM +1E4E ; [.113B.0020.0008.004F][.0000.004E.0002.0303][.0000.0047.0002.0308] # LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS; QQCM +022D ; [.113B.0020.0002.006F][.0000.004E.0002.0303][.0000.005B.0002.0304] # LATIN SMALL LETTER O WITH TILDE AND MACRON; QQCM +022C ; [.113B.0020.0008.004F][.0000.004E.0002.0303][.0000.005B.0002.0304] # LATIN CAPITAL LETTER O WITH TILDE AND MACRON; QQCM +022F ; [.113B.0020.0002.006F][.0000.0052.0002.0307] # LATIN SMALL LETTER O WITH DOT ABOVE; QQCM +022E ; [.113B.0020.0008.004F][.0000.0052.0002.0307] # LATIN CAPITAL LETTER O WITH DOT ABOVE; QQCM +0231 ; [.113B.0020.0002.006F][.0000.0052.0002.0307][.0000.005B.0002.0304] # LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON; QQCM +0230 ; [.113B.0020.0008.004F][.0000.0052.0002.0307][.0000.005B.0002.0304] # LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON; QQCM +00F8 ; [.113B.0020.0002.006F][.0000.0054.0002.0338] # LATIN SMALL LETTER O WITH STROKE; QQCM +00D8 ; [.113B.0020.0008.004F][.0000.0054.0002.0338] # LATIN CAPITAL LETTER O WITH STROKE; QQCM +01FF ; [.113B.0020.0002.006F][.0000.0054.0002.0338][.0000.0032.0002.0301] # LATIN SMALL LETTER O WITH STROKE AND ACUTE; QQCM +01FE ; [.113B.0020.0008.004F][.0000.0054.0002.0338][.0000.0032.0002.0301] # LATIN CAPITAL LETTER O WITH STROKE AND ACUTE; QQCM +01EB ; [.113B.0020.0002.006F][.0000.0059.0002.0328] # LATIN SMALL LETTER O WITH OGONEK; QQCM +01EA ; [.113B.0020.0008.004F][.0000.0059.0002.0328] # LATIN CAPITAL LETTER O WITH OGONEK; QQCM +01ED ; [.113B.0020.0002.006F][.0000.0059.0002.0328][.0000.005B.0002.0304] # LATIN SMALL LETTER O WITH OGONEK AND MACRON; QQCM +01EC ; [.113B.0020.0008.004F][.0000.0059.0002.0328][.0000.005B.0002.0304] # LATIN CAPITAL LETTER O WITH OGONEK AND MACRON; QQCM +014D ; [.113B.0020.0002.006F][.0000.005B.0002.0304] # LATIN SMALL LETTER O WITH MACRON; QQCM +014C ; [.113B.0020.0008.004F][.0000.005B.0002.0304] # LATIN CAPITAL LETTER O WITH MACRON; QQCM +1E53 ; [.113B.0020.0002.006F][.0000.005B.0002.0304][.0000.0032.0002.0301] # LATIN SMALL LETTER O WITH MACRON AND ACUTE; QQCM +1E52 ; [.113B.0020.0008.004F][.0000.005B.0002.0304][.0000.0032.0002.0301] # LATIN CAPITAL LETTER O WITH MACRON AND ACUTE; QQCM +1E51 ; [.113B.0020.0002.006F][.0000.005B.0002.0304][.0000.0035.0002.0300] # LATIN SMALL LETTER O WITH MACRON AND GRAVE; QQCM +1E50 ; [.113B.0020.0008.004F][.0000.005B.0002.0304][.0000.0035.0002.0300] # LATIN CAPITAL LETTER O WITH MACRON AND GRAVE; QQCM +1ECF ; [.113B.0020.0002.006F][.0000.0060.0002.0309] # LATIN SMALL LETTER O WITH HOOK ABOVE; QQCM +1ECE ; [.113B.0020.0008.004F][.0000.0060.0002.0309] # LATIN CAPITAL LETTER O WITH HOOK ABOVE; QQCM +020D ; [.113B.0020.0002.006F][.0000.0063.0002.030F] # LATIN SMALL LETTER O WITH DOUBLE GRAVE; QQCM +020C ; [.113B.0020.0008.004F][.0000.0063.0002.030F] # LATIN CAPITAL LETTER O WITH DOUBLE GRAVE; QQCM +020F ; [.113B.0020.0002.006F][.0000.0065.0002.0311] # LATIN SMALL LETTER O WITH INVERTED BREVE; QQCM +020E ; [.113B.0020.0008.004F][.0000.0065.0002.0311] # LATIN CAPITAL LETTER O WITH INVERTED BREVE; QQCM +01A1 ; [.113B.0020.0002.006F][.0000.006D.0002.031B] # LATIN SMALL LETTER O WITH HORN; QQCM +01A0 ; [.113B.0020.0008.004F][.0000.006D.0002.031B] # LATIN CAPITAL LETTER O WITH HORN; QQCM +1EDB ; [.113B.0020.0002.006F][.0000.006D.0002.031B][.0000.0032.0002.0301] # LATIN SMALL LETTER O WITH HORN AND ACUTE; QQCM +1EDA ; [.113B.0020.0008.004F][.0000.006D.0002.031B][.0000.0032.0002.0301] # LATIN CAPITAL LETTER O WITH HORN AND ACUTE; QQCM +1EDD ; [.113B.0020.0002.006F][.0000.006D.0002.031B][.0000.0035.0002.0300] # LATIN SMALL LETTER O WITH HORN AND GRAVE; QQCM +1EDC ; [.113B.0020.0008.004F][.0000.006D.0002.031B][.0000.0035.0002.0300] # LATIN CAPITAL LETTER O WITH HORN AND GRAVE; QQCM +1EE1 ; [.113B.0020.0002.006F][.0000.006D.0002.031B][.0000.004E.0002.0303] # LATIN SMALL LETTER O WITH HORN AND TILDE; QQCM +1EE0 ; [.113B.0020.0008.004F][.0000.006D.0002.031B][.0000.004E.0002.0303] # LATIN CAPITAL LETTER O WITH HORN AND TILDE; QQCM +1EDF ; [.113B.0020.0002.006F][.0000.006D.0002.031B][.0000.0060.0002.0309] # LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE; QQCM +1EDE ; [.113B.0020.0008.004F][.0000.006D.0002.031B][.0000.0060.0002.0309] # LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE; QQCM +1EE3 ; [.113B.0020.0002.006F][.0000.006D.0002.031B][.0000.007A.0002.0323] # LATIN SMALL LETTER O WITH HORN AND DOT BELOW; QQCM +1EE2 ; [.113B.0020.0008.004F][.0000.006D.0002.031B][.0000.007A.0002.0323] # LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW; QQCM +1ECD ; [.113B.0020.0002.006F][.0000.007A.0002.0323] # LATIN SMALL LETTER O WITH DOT BELOW; QQCM +1ECC ; [.113B.0020.0008.004F][.0000.007A.0002.0323] # LATIN CAPITAL LETTER O WITH DOT BELOW; QQCM +1ED9 ; [.113B.0020.0002.006F][.0000.007A.0002.0323][.0000.003C.0002.0302] # LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW; QQCM +1ED8 ; [.113B.0020.0008.004F][.0000.007A.0002.0323][.0000.003C.0002.0302] # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW; QQCM +0153 ; [.113B.0020.0004.0153][.0000.0199.0004.0153][.1029.0020.001F.0153] # LATIN SMALL LIGATURE OE; QQKN +0152 ; [.113B.0020.000A.0152][.0000.0199.0004.0152][.1029.0020.001F.0152] # LATIN CAPITAL LIGATURE OE; QQKN +3375 ; [.113B.0020.001C.3375][.1216.0020.001D.3375] # SQUARE OV; QQKN +1D0F ; [.113F.0020.0002.1D0F] # LATIN LETTER SMALL CAPITAL O +1D11 ; [.1140.0020.0002.1D11] # LATIN SMALL LETTER SIDEWAYS O +0276 ; [.1141.0020.0002.0276] # LATIN LETTER SMALL CAPITAL OE +1D14 ; [.1145.0020.0002.1D14] # LATIN SMALL LETTER TURNED OE +1D13 ; [.1146.0020.0002.1D13] # LATIN SMALL LETTER SIDEWAYS O WITH STROKE +0254 ; [.1147.0020.0002.0254] # LATIN SMALL LETTER OPEN O +0186 ; [.1147.0020.0008.0186] # LATIN CAPITAL LETTER OPEN O +1D53 ; [.1147.0020.0014.1D53] # MODIFIER LETTER SMALL OPEN O; QQK +1D10 ; [.114B.0020.0002.1D10] # LATIN LETTER SMALL CAPITAL OPEN O +1D12 ; [.114C.0020.0002.1D12] # LATIN SMALL LETTER SIDEWAYS OPEN O +1D97 ; [.114D.0020.0002.1D97] # LATIN SMALL LETTER OPEN O WITH RETROFLEX HOOK +1D16 ; [.114E.0020.0002.1D16] # LATIN SMALL LETTER TOP HALF O +1D54 ; [.114E.0020.0014.1D54] # MODIFIER LETTER SMALL TOP HALF O; QQK +1D17 ; [.114F.0020.0002.1D17] # LATIN SMALL LETTER BOTTOM HALF O +1D55 ; [.114F.0020.0014.1D55] # MODIFIER LETTER SMALL BOTTOM HALF O; QQK +0275 ; [.1150.0020.0002.0275] # LATIN SMALL LETTER BARRED O +019F ; [.1150.0020.0008.019F] # LATIN CAPITAL LETTER O WITH MIDDLE TILDE +1DB1 ; [.1150.0020.0014.1DB1] # MODIFIER LETTER SMALL BARRED O; QQK +0277 ; [.1154.0020.0002.0277] # LATIN SMALL LETTER CLOSED OMEGA +0223 ; [.1158.0020.0002.0223] # LATIN SMALL LETTER OU +0222 ; [.1158.0020.0008.0222] # LATIN CAPITAL LETTER OU +1D3D ; [.1158.0020.001D.1D3D] # MODIFIER LETTER CAPITAL OU; QQK +1D15 ; [.115C.0020.0002.1D15] # LATIN LETTER SMALL CAPITAL OU +0070 ; [.115D.0020.0002.0070] # LATIN SMALL LETTER P +FF50 ; [.115D.0020.0003.FF50] # FULLWIDTH LATIN SMALL LETTER P; QQK +24AB ; [*02B1.0020.0004.24AB][.115D.0020.0004.24AB][*02B2.0020.001F.24AB] # PARENTHESIZED LATIN SMALL LETTER P; QQKN +1D429 ; [.115D.0020.0005.1D429] # MATHEMATICAL BOLD SMALL P; QQK +1D45D ; [.115D.0020.0005.1D45D] # MATHEMATICAL ITALIC SMALL P; QQK +1D491 ; [.115D.0020.0005.1D491] # MATHEMATICAL BOLD ITALIC SMALL P; QQK +1D4C5 ; [.115D.0020.0005.1D4C5] # MATHEMATICAL SCRIPT SMALL P; QQK +1D4F9 ; [.115D.0020.0005.1D4F9] # MATHEMATICAL BOLD SCRIPT SMALL P; QQK +1D52D ; [.115D.0020.0005.1D52D] # MATHEMATICAL FRAKTUR SMALL P; QQK +1D561 ; [.115D.0020.0005.1D561] # MATHEMATICAL DOUBLE-STRUCK SMALL P; QQK +1D595 ; [.115D.0020.0005.1D595] # MATHEMATICAL BOLD FRAKTUR SMALL P; QQK +1D5C9 ; [.115D.0020.0005.1D5C9] # MATHEMATICAL SANS-SERIF SMALL P; QQK +1D5FD ; [.115D.0020.0005.1D5FD] # MATHEMATICAL SANS-SERIF BOLD SMALL P; QQK +1D631 ; [.115D.0020.0005.1D631] # MATHEMATICAL SANS-SERIF ITALIC SMALL P; QQK +1D665 ; [.115D.0020.0005.1D665] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL P; QQK +1D699 ; [.115D.0020.0005.1D699] # MATHEMATICAL MONOSPACE SMALL P; QQK +24DF ; [.115D.0020.0006.24DF] # CIRCLED LATIN SMALL LETTER P; QQK +0050 ; [.115D.0020.0008.0050] # LATIN CAPITAL LETTER P +FF30 ; [.115D.0020.0009.FF30] # FULLWIDTH LATIN CAPITAL LETTER P; QQK +2119 ; [.115D.0020.000B.2119] # DOUBLE-STRUCK CAPITAL P; QQK +1D40F ; [.115D.0020.000B.1D40F] # MATHEMATICAL BOLD CAPITAL P; QQK +1D443 ; [.115D.0020.000B.1D443] # MATHEMATICAL ITALIC CAPITAL P; QQK +1D477 ; [.115D.0020.000B.1D477] # MATHEMATICAL BOLD ITALIC CAPITAL P; QQK +1D4AB ; [.115D.0020.000B.1D4AB] # MATHEMATICAL SCRIPT CAPITAL P; QQK +1D4DF ; [.115D.0020.000B.1D4DF] # MATHEMATICAL BOLD SCRIPT CAPITAL P; QQK +1D513 ; [.115D.0020.000B.1D513] # MATHEMATICAL FRAKTUR CAPITAL P; QQK +1D57B ; [.115D.0020.000B.1D57B] # MATHEMATICAL BOLD FRAKTUR CAPITAL P; QQK +1D5AF ; [.115D.0020.000B.1D5AF] # MATHEMATICAL SANS-SERIF CAPITAL P; QQK +1D5E3 ; [.115D.0020.000B.1D5E3] # MATHEMATICAL SANS-SERIF BOLD CAPITAL P; QQK +1D617 ; [.115D.0020.000B.1D617] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL P; QQK +1D64B ; [.115D.0020.000B.1D64B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL P; QQK +1D67F ; [.115D.0020.000B.1D67F] # MATHEMATICAL MONOSPACE CAPITAL P; QQK +24C5 ; [.115D.0020.000C.24C5] # CIRCLED LATIN CAPITAL LETTER P; QQK +1D56 ; [.115D.0020.0014.1D56] # MODIFIER LETTER SMALL P; QQK +1D3E ; [.115D.0020.001D.1D3E] # MODIFIER LETTER CAPITAL P; QQK +1E55 ; [.115D.0020.0002.0070][.0000.0032.0002.0301] # LATIN SMALL LETTER P WITH ACUTE; QQCM +1E54 ; [.115D.0020.0008.0050][.0000.0032.0002.0301] # LATIN CAPITAL LETTER P WITH ACUTE; QQCM +1E57 ; [.115D.0020.0002.0070][.0000.0052.0002.0307] # LATIN SMALL LETTER P WITH DOT ABOVE; QQCM +1E56 ; [.115D.0020.0008.0050][.0000.0052.0002.0307] # LATIN CAPITAL LETTER P WITH DOT ABOVE; QQCM +3380 ; [.115D.0020.001C.3380][.0FD0.0020.001D.3380] # SQUARE PA AMPS; QQKN +33A9 ; [.115D.0020.001D.33A9][.0FD0.0020.001C.33A9] # SQUARE PA; QQKN +3376 ; [.115D.0020.001C.3376][.0FFE.0020.001C.3376] # SQUARE PC; QQKN +338A ; [.115D.0020.001C.338A][.105F.0020.001D.338A] # SQUARE PF; QQKN +33D7 ; [.115D.0020.001D.33D7][.108D.0020.001D.33D7] # SQUARE PH; QQKN +33D8 ; [.115D.0020.001C.33D8][*0266.0020.001C.33D8][.1110.0020.001F.33D8][*0266.0020.001F.33D8] # SQUARE PM; QQKN +33D9 ; [.115D.0020.001D.33D9][.115D.0020.001D.33D9][.1110.0020.001F.33D9] # SQUARE PPM; QQKN +33DA ; [.115D.0020.001D.33DA][.117E.0020.001D.33DA] # SQUARE PR; QQKN +33B0 ; [.115D.0020.001C.33B0][.11AF.0020.001C.33B0] # SQUARE PS; QQKN +3250 ; [.115D.0020.001D.3250][.11CF.0020.001D.3250][.1029.0020.001F.3250] # PARTNERSHIP SIGN; QQKN +33B4 ; [.115D.0020.001C.33B4][.1216.0020.001D.33B4] # SQUARE PV; QQKN +33BA ; [.115D.0020.001C.33BA][.1225.0020.001D.33BA] # SQUARE PW; QQKN +1D18 ; [.1161.0020.0002.1D18] # LATIN LETTER SMALL CAPITAL P +1D7D ; [.1162.0020.0002.1D7D] # LATIN SMALL LETTER P WITH STROKE +2C63 ; [.1162.0020.0008.2C63] # LATIN CAPITAL LETTER P WITH STROKE +1D71 ; [.1163.0020.0002.1D71] # LATIN SMALL LETTER P WITH MIDDLE TILDE +1D88 ; [.1164.0020.0002.1D88] # LATIN SMALL LETTER P WITH PALATAL HOOK +01A5 ; [.1165.0020.0002.01A5] # LATIN SMALL LETTER P WITH HOOK +01A4 ; [.1165.0020.0008.01A4] # LATIN CAPITAL LETTER P WITH HOOK +0278 ; [.1169.0020.0002.0278] # LATIN SMALL LETTER PHI +1DB2 ; [.1169.0020.0014.1DB2] # MODIFIER LETTER SMALL PHI; QQK +2C77 ; [.116D.0020.0002.2C77] # LATIN SMALL LETTER TAILLESS PHI +0071 ; [.116E.0020.0002.0071] # LATIN SMALL LETTER Q +FF51 ; [.116E.0020.0003.FF51] # FULLWIDTH LATIN SMALL LETTER Q; QQK +24AC ; [*02B1.0020.0004.24AC][.116E.0020.0004.24AC][*02B2.0020.001F.24AC] # PARENTHESIZED LATIN SMALL LETTER Q; QQKN +1D42A ; [.116E.0020.0005.1D42A] # MATHEMATICAL BOLD SMALL Q; QQK +1D45E ; [.116E.0020.0005.1D45E] # MATHEMATICAL ITALIC SMALL Q; QQK +1D492 ; [.116E.0020.0005.1D492] # MATHEMATICAL BOLD ITALIC SMALL Q; QQK +1D4C6 ; [.116E.0020.0005.1D4C6] # MATHEMATICAL SCRIPT SMALL Q; QQK +1D4FA ; [.116E.0020.0005.1D4FA] # MATHEMATICAL BOLD SCRIPT SMALL Q; QQK +1D52E ; [.116E.0020.0005.1D52E] # MATHEMATICAL FRAKTUR SMALL Q; QQK +1D562 ; [.116E.0020.0005.1D562] # MATHEMATICAL DOUBLE-STRUCK SMALL Q; QQK +1D596 ; [.116E.0020.0005.1D596] # MATHEMATICAL BOLD FRAKTUR SMALL Q; QQK +1D5CA ; [.116E.0020.0005.1D5CA] # MATHEMATICAL SANS-SERIF SMALL Q; QQK +1D5FE ; [.116E.0020.0005.1D5FE] # MATHEMATICAL SANS-SERIF BOLD SMALL Q; QQK +1D632 ; [.116E.0020.0005.1D632] # MATHEMATICAL SANS-SERIF ITALIC SMALL Q; QQK +1D666 ; [.116E.0020.0005.1D666] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Q; QQK +1D69A ; [.116E.0020.0005.1D69A] # MATHEMATICAL MONOSPACE SMALL Q; QQK +24E0 ; [.116E.0020.0006.24E0] # CIRCLED LATIN SMALL LETTER Q; QQK +0051 ; [.116E.0020.0008.0051] # LATIN CAPITAL LETTER Q +FF31 ; [.116E.0020.0009.FF31] # FULLWIDTH LATIN CAPITAL LETTER Q; QQK +211A ; [.116E.0020.000B.211A] # DOUBLE-STRUCK CAPITAL Q; QQK +1D410 ; [.116E.0020.000B.1D410] # MATHEMATICAL BOLD CAPITAL Q; QQK +1D444 ; [.116E.0020.000B.1D444] # MATHEMATICAL ITALIC CAPITAL Q; QQK +1D478 ; [.116E.0020.000B.1D478] # MATHEMATICAL BOLD ITALIC CAPITAL Q; QQK +1D4AC ; [.116E.0020.000B.1D4AC] # MATHEMATICAL SCRIPT CAPITAL Q; QQK +1D4E0 ; [.116E.0020.000B.1D4E0] # MATHEMATICAL BOLD SCRIPT CAPITAL Q; QQK +1D514 ; [.116E.0020.000B.1D514] # MATHEMATICAL FRAKTUR CAPITAL Q; QQK +1D57C ; [.116E.0020.000B.1D57C] # MATHEMATICAL BOLD FRAKTUR CAPITAL Q; QQK +1D5B0 ; [.116E.0020.000B.1D5B0] # MATHEMATICAL SANS-SERIF CAPITAL Q; QQK +1D5E4 ; [.116E.0020.000B.1D5E4] # MATHEMATICAL SANS-SERIF BOLD CAPITAL Q; QQK +1D618 ; [.116E.0020.000B.1D618] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL Q; QQK +1D64C ; [.116E.0020.000B.1D64C] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Q; QQK +1D680 ; [.116E.0020.000B.1D680] # MATHEMATICAL MONOSPACE CAPITAL Q; QQK +24C6 ; [.116E.0020.000C.24C6] # CIRCLED LATIN CAPITAL LETTER Q; QQK +0239 ; [.116E.0020.0004.0239][.115D.0020.0004.0239] # LATIN SMALL LETTER QP DIGRAPH; QQKN +02A0 ; [.1172.0020.0002.02A0] # LATIN SMALL LETTER Q WITH HOOK +024B ; [.1176.0020.0002.024B] # LATIN SMALL LETTER Q WITH HOOK TAIL +024A ; [.1176.0020.0008.024A] # LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL +0138 ; [.117A.0020.0002.0138] # LATIN SMALL LETTER KRA +0072 ; [.117E.0020.0002.0072] # LATIN SMALL LETTER R +FF52 ; [.117E.0020.0003.FF52] # FULLWIDTH LATIN SMALL LETTER R; QQK +036C ; [.117E.0020.0004.036C] # COMBINING LATIN SMALL LETTER R; QQK +24AD ; [*02B1.0020.0004.24AD][.117E.0020.0004.24AD][*02B2.0020.001F.24AD] # PARENTHESIZED LATIN SMALL LETTER R; QQKN +1D42B ; [.117E.0020.0005.1D42B] # MATHEMATICAL BOLD SMALL R; QQK +1D45F ; [.117E.0020.0005.1D45F] # MATHEMATICAL ITALIC SMALL R; QQK +1D493 ; [.117E.0020.0005.1D493] # MATHEMATICAL BOLD ITALIC SMALL R; QQK +1D4C7 ; [.117E.0020.0005.1D4C7] # MATHEMATICAL SCRIPT SMALL R; QQK +1D4FB ; [.117E.0020.0005.1D4FB] # MATHEMATICAL BOLD SCRIPT SMALL R; QQK +1D52F ; [.117E.0020.0005.1D52F] # MATHEMATICAL FRAKTUR SMALL R; QQK +1D563 ; [.117E.0020.0005.1D563] # MATHEMATICAL DOUBLE-STRUCK SMALL R; QQK +1D597 ; [.117E.0020.0005.1D597] # MATHEMATICAL BOLD FRAKTUR SMALL R; QQK +1D5CB ; [.117E.0020.0005.1D5CB] # MATHEMATICAL SANS-SERIF SMALL R; QQK +1D5FF ; [.117E.0020.0005.1D5FF] # MATHEMATICAL SANS-SERIF BOLD SMALL R; QQK +1D633 ; [.117E.0020.0005.1D633] # MATHEMATICAL SANS-SERIF ITALIC SMALL R; QQK +1D667 ; [.117E.0020.0005.1D667] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL R; QQK +1D69B ; [.117E.0020.0005.1D69B] # MATHEMATICAL MONOSPACE SMALL R; QQK +24E1 ; [.117E.0020.0006.24E1] # CIRCLED LATIN SMALL LETTER R; QQK +0052 ; [.117E.0020.0008.0052] # LATIN CAPITAL LETTER R +FF32 ; [.117E.0020.0009.FF32] # FULLWIDTH LATIN CAPITAL LETTER R; QQK +211B ; [.117E.0020.000B.211B] # SCRIPT CAPITAL R; QQK +211C ; [.117E.0020.000B.211C] # BLACK-LETTER CAPITAL R; QQK +211D ; [.117E.0020.000B.211D] # DOUBLE-STRUCK CAPITAL R; QQK +1D411 ; [.117E.0020.000B.1D411] # MATHEMATICAL BOLD CAPITAL R; QQK +1D445 ; [.117E.0020.000B.1D445] # MATHEMATICAL ITALIC CAPITAL R; QQK +1D479 ; [.117E.0020.000B.1D479] # MATHEMATICAL BOLD ITALIC CAPITAL R; QQK +1D4E1 ; [.117E.0020.000B.1D4E1] # MATHEMATICAL BOLD SCRIPT CAPITAL R; QQK +1D57D ; [.117E.0020.000B.1D57D] # MATHEMATICAL BOLD FRAKTUR CAPITAL R; QQK +1D5B1 ; [.117E.0020.000B.1D5B1] # MATHEMATICAL SANS-SERIF CAPITAL R; QQK +1D5E5 ; [.117E.0020.000B.1D5E5] # MATHEMATICAL SANS-SERIF BOLD CAPITAL R; QQK +1D619 ; [.117E.0020.000B.1D619] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL R; QQK +1D64D ; [.117E.0020.000B.1D64D] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL R; QQK +1D681 ; [.117E.0020.000B.1D681] # MATHEMATICAL MONOSPACE CAPITAL R; QQK +24C7 ; [.117E.0020.000C.24C7] # CIRCLED LATIN CAPITAL LETTER R; QQK +02B3 ; [.117E.0020.0014.02B3] # MODIFIER LETTER SMALL R; QQK +1D63 ; [.117E.0020.0015.1D63] # LATIN SUBSCRIPT SMALL LETTER R; QQK +1D3F ; [.117E.0020.001D.1D3F] # MODIFIER LETTER CAPITAL R; QQK +0155 ; [.117E.0020.0002.0072][.0000.0032.0002.0301] # LATIN SMALL LETTER R WITH ACUTE; QQCM +0154 ; [.117E.0020.0008.0052][.0000.0032.0002.0301] # LATIN CAPITAL LETTER R WITH ACUTE; QQCM +0159 ; [.117E.0020.0002.0072][.0000.0041.0002.030C] # LATIN SMALL LETTER R WITH CARON; QQCM +0158 ; [.117E.0020.0008.0052][.0000.0041.0002.030C] # LATIN CAPITAL LETTER R WITH CARON; QQCM +1E59 ; [.117E.0020.0002.0072][.0000.0052.0002.0307] # LATIN SMALL LETTER R WITH DOT ABOVE; QQCM +1E58 ; [.117E.0020.0008.0052][.0000.0052.0002.0307] # LATIN CAPITAL LETTER R WITH DOT ABOVE; QQCM +0157 ; [.117E.0020.0002.0072][.0000.0056.0002.0327] # LATIN SMALL LETTER R WITH CEDILLA; QQCM +0156 ; [.117E.0020.0008.0052][.0000.0056.0002.0327] # LATIN CAPITAL LETTER R WITH CEDILLA; QQCM +0211 ; [.117E.0020.0002.0072][.0000.0063.0002.030F] # LATIN SMALL LETTER R WITH DOUBLE GRAVE; QQCM +0210 ; [.117E.0020.0008.0052][.0000.0063.0002.030F] # LATIN CAPITAL LETTER R WITH DOUBLE GRAVE; QQCM +0213 ; [.117E.0020.0002.0072][.0000.0065.0002.0311] # LATIN SMALL LETTER R WITH INVERTED BREVE; QQCM +0212 ; [.117E.0020.0008.0052][.0000.0065.0002.0311] # LATIN CAPITAL LETTER R WITH INVERTED BREVE; QQCM +1E5B ; [.117E.0020.0002.0072][.0000.007A.0002.0323] # LATIN SMALL LETTER R WITH DOT BELOW; QQCM +1E5A ; [.117E.0020.0008.0052][.0000.007A.0002.0323] # LATIN CAPITAL LETTER R WITH DOT BELOW; QQCM +1E5D ; [.117E.0020.0002.0072][.0000.007A.0002.0323][.0000.005B.0002.0304] # LATIN SMALL LETTER R WITH DOT BELOW AND MACRON; QQCM +1E5C ; [.117E.0020.0008.0052][.0000.007A.0002.0323][.0000.005B.0002.0304] # LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON; QQCM +1E5F ; [.117E.0020.0002.0072][.0000.008A.0002.0331] # LATIN SMALL LETTER R WITH LINE BELOW; QQCM +1E5E ; [.117E.0020.0008.0052][.0000.008A.0002.0331] # LATIN CAPITAL LETTER R WITH LINE BELOW; QQCM +33AD ; [.117E.0020.001C.33AD][.0FD0.0020.001C.33AD][.1010.0020.001F.33AD] # SQUARE RAD; QQKN +33AE ; [.117E.0020.001C.33AE][.0FD0.0020.001C.33AE][.1010.0020.001F.33AE][*04C7.0020.001F.33AE][.11AF.0020.001F.33AE] # SQUARE RAD OVER S; QQKN +33AF ; [.117E.0020.001C.33AF][.0FD0.0020.001C.33AF][.1010.0020.001F.33AF][*04C7.0020.001F.33AF][.11AF.0020.001F.33AF][.0FC8.0020.001F.33AF] # SQUARE RAD OVER S SQUARED; QQKN +20A8 ; [.117E.0020.000A.20A8][.11AF.0020.0004.20A8] # RUPEE SIGN; QQKN +0280 ; [.1182.0020.0002.0280] # LATIN LETTER SMALL CAPITAL R +01A6 ; [.1182.0020.0008.01A6] # LATIN LETTER YR +1D19 ; [.1186.0020.0002.1D19] # LATIN LETTER SMALL CAPITAL REVERSED R +024D ; [.1187.0020.0002.024D] # LATIN SMALL LETTER R WITH STROKE +024C ; [.1187.0020.0008.024C] # LATIN CAPITAL LETTER R WITH STROKE +1D72 ; [.118B.0020.0002.1D72] # LATIN SMALL LETTER R WITH MIDDLE TILDE +0279 ; [.118C.0020.0002.0279] # LATIN SMALL LETTER TURNED R +02B4 ; [.118C.0020.0014.02B4] # MODIFIER LETTER SMALL TURNED R; QQK +1D1A ; [.1190.0020.0002.1D1A] # LATIN LETTER SMALL CAPITAL TURNED R +027A ; [.1191.0020.0002.027A] # LATIN SMALL LETTER TURNED R WITH LONG LEG +1D89 ; [.1195.0020.0002.1D89] # LATIN SMALL LETTER R WITH PALATAL HOOK +027B ; [.1196.0020.0002.027B] # LATIN SMALL LETTER TURNED R WITH HOOK +02B5 ; [.1196.0020.0014.02B5] # MODIFIER LETTER SMALL TURNED R WITH HOOK; QQK +027C ; [.119A.0020.0002.027C] # LATIN SMALL LETTER R WITH LONG LEG +027D ; [.119E.0020.0002.027D] # LATIN SMALL LETTER R WITH TAIL +2C64 ; [.119E.0020.0008.2C64] # LATIN CAPITAL LETTER R WITH TAIL +027E ; [.11A2.0020.0002.027E] # LATIN SMALL LETTER R WITH FISHHOOK +1D73 ; [.11A6.0020.0002.1D73] # LATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TILDE +027F ; [.11A7.0020.0002.027F] # LATIN SMALL LETTER REVERSED R WITH FISHHOOK +0281 ; [.11AB.0020.0002.0281] # LATIN LETTER SMALL CAPITAL INVERTED R +02B6 ; [.11AB.0020.0014.02B6] # MODIFIER LETTER SMALL CAPITAL INVERTED R; QQK +0073 ; [.11AF.0020.0002.0073] # LATIN SMALL LETTER S +FF53 ; [.11AF.0020.0003.FF53] # FULLWIDTH LATIN SMALL LETTER S; QQK +24AE ; [*02B1.0020.0004.24AE][.11AF.0020.0004.24AE][*02B2.0020.001F.24AE] # PARENTHESIZED LATIN SMALL LETTER S; QQKN +1D42C ; [.11AF.0020.0005.1D42C] # MATHEMATICAL BOLD SMALL S; QQK +1D460 ; [.11AF.0020.0005.1D460] # MATHEMATICAL ITALIC SMALL S; QQK +1D494 ; [.11AF.0020.0005.1D494] # MATHEMATICAL BOLD ITALIC SMALL S; QQK +1D4C8 ; [.11AF.0020.0005.1D4C8] # MATHEMATICAL SCRIPT SMALL S; QQK +1D4FC ; [.11AF.0020.0005.1D4FC] # MATHEMATICAL BOLD SCRIPT SMALL S; QQK +1D530 ; [.11AF.0020.0005.1D530] # MATHEMATICAL FRAKTUR SMALL S; QQK +1D564 ; [.11AF.0020.0005.1D564] # MATHEMATICAL DOUBLE-STRUCK SMALL S; QQK +1D598 ; [.11AF.0020.0005.1D598] # MATHEMATICAL BOLD FRAKTUR SMALL S; QQK +1D5CC ; [.11AF.0020.0005.1D5CC] # MATHEMATICAL SANS-SERIF SMALL S; QQK +1D600 ; [.11AF.0020.0005.1D600] # MATHEMATICAL SANS-SERIF BOLD SMALL S; QQK +1D634 ; [.11AF.0020.0005.1D634] # MATHEMATICAL SANS-SERIF ITALIC SMALL S; QQK +1D668 ; [.11AF.0020.0005.1D668] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL S; QQK +1D69C ; [.11AF.0020.0005.1D69C] # MATHEMATICAL MONOSPACE SMALL S; QQK +24E2 ; [.11AF.0020.0006.24E2] # CIRCLED LATIN SMALL LETTER S; QQK +0053 ; [.11AF.0020.0008.0053] # LATIN CAPITAL LETTER S +FF33 ; [.11AF.0020.0009.FF33] # FULLWIDTH LATIN CAPITAL LETTER S; QQK +1D412 ; [.11AF.0020.000B.1D412] # MATHEMATICAL BOLD CAPITAL S; QQK +1D446 ; [.11AF.0020.000B.1D446] # MATHEMATICAL ITALIC CAPITAL S; QQK +1D47A ; [.11AF.0020.000B.1D47A] # MATHEMATICAL BOLD ITALIC CAPITAL S; QQK +1D4AE ; [.11AF.0020.000B.1D4AE] # MATHEMATICAL SCRIPT CAPITAL S; QQK +1D4E2 ; [.11AF.0020.000B.1D4E2] # MATHEMATICAL BOLD SCRIPT CAPITAL S; QQK +1D516 ; [.11AF.0020.000B.1D516] # MATHEMATICAL FRAKTUR CAPITAL S; QQK +1D54A ; [.11AF.0020.000B.1D54A] # MATHEMATICAL DOUBLE-STRUCK CAPITAL S; QQK +1D57E ; [.11AF.0020.000B.1D57E] # MATHEMATICAL BOLD FRAKTUR CAPITAL S; QQK +1D5B2 ; [.11AF.0020.000B.1D5B2] # MATHEMATICAL SANS-SERIF CAPITAL S; QQK +1D5E6 ; [.11AF.0020.000B.1D5E6] # MATHEMATICAL SANS-SERIF BOLD CAPITAL S; QQK +1D61A ; [.11AF.0020.000B.1D61A] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL S; QQK +1D64E ; [.11AF.0020.000B.1D64E] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL S; QQK +1D682 ; [.11AF.0020.000B.1D682] # MATHEMATICAL MONOSPACE CAPITAL S; QQK +24C8 ; [.11AF.0020.000C.24C8] # CIRCLED LATIN CAPITAL LETTER S; QQK +02E2 ; [.11AF.0020.0014.02E2] # MODIFIER LETTER SMALL S; QQK +015B ; [.11AF.0020.0002.0073][.0000.0032.0002.0301] # LATIN SMALL LETTER S WITH ACUTE; QQCM +015A ; [.11AF.0020.0008.0053][.0000.0032.0002.0301] # LATIN CAPITAL LETTER S WITH ACUTE; QQCM +1E65 ; [.11AF.0020.0002.0073][.0000.0032.0002.0301][.0000.0052.0002.0307] # LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE; QQCM +1E64 ; [.11AF.0020.0008.0053][.0000.0032.0002.0301][.0000.0052.0002.0307] # LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE; QQCM +015D ; [.11AF.0020.0002.0073][.0000.003C.0002.0302] # LATIN SMALL LETTER S WITH CIRCUMFLEX; QQCM +015C ; [.11AF.0020.0008.0053][.0000.003C.0002.0302] # LATIN CAPITAL LETTER S WITH CIRCUMFLEX; QQCM +0161 ; [.11AF.0020.0002.0073][.0000.0041.0002.030C] # LATIN SMALL LETTER S WITH CARON; QQCM +0160 ; [.11AF.0020.0008.0053][.0000.0041.0002.030C] # LATIN CAPITAL LETTER S WITH CARON; QQCM +1E67 ; [.11AF.0020.0002.0073][.0000.0041.0002.030C][.0000.0052.0002.0307] # LATIN SMALL LETTER S WITH CARON AND DOT ABOVE; QQCM +1E66 ; [.11AF.0020.0008.0053][.0000.0041.0002.030C][.0000.0052.0002.0307] # LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE; QQCM +1E61 ; [.11AF.0020.0002.0073][.0000.0052.0002.0307] # LATIN SMALL LETTER S WITH DOT ABOVE; QQCM +1E60 ; [.11AF.0020.0008.0053][.0000.0052.0002.0307] # LATIN CAPITAL LETTER S WITH DOT ABOVE; QQCM +015F ; [.11AF.0020.0002.0073][.0000.0056.0002.0327] # LATIN SMALL LETTER S WITH CEDILLA; QQCM +015E ; [.11AF.0020.0008.0053][.0000.0056.0002.0327] # LATIN CAPITAL LETTER S WITH CEDILLA; QQCM +1E63 ; [.11AF.0020.0002.0073][.0000.007A.0002.0323] # LATIN SMALL LETTER S WITH DOT BELOW; QQCM +1E62 ; [.11AF.0020.0008.0053][.0000.007A.0002.0323] # LATIN CAPITAL LETTER S WITH DOT BELOW; QQCM +1E69 ; [.11AF.0020.0002.0073][.0000.007A.0002.0323][.0000.0052.0002.0307] # LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE; QQCM +1E68 ; [.11AF.0020.0008.0053][.0000.007A.0002.0323][.0000.0052.0002.0307] # LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE; QQCM +0219 ; [.11AF.0020.0002.0073][.0000.0081.0002.0326] # LATIN SMALL LETTER S WITH COMMA BELOW; QQCM +0218 ; [.11AF.0020.0008.0053][.0000.0081.0002.0326] # LATIN CAPITAL LETTER S WITH COMMA BELOW; QQCM +017F ; [.11AF.0020.0004.017F][.0000.019A.0004.017F] # LATIN SMALL LETTER LONG S; QQKN +1E9B ; [.11AF.0020.0004.1E9B][.0000.019A.0004.1E9B][.0000.0052.0002.1E9B] # LATIN SMALL LETTER LONG S WITH DOT ABOVE; QQKN +2120 ; [.11AF.0020.0014.2120][.1110.0020.0014.2120] # SERVICE MARK; QQKN +33DB ; [.11AF.0020.001C.33DB][.117E.0020.001C.33DB] # SQUARE SR; QQKN +00DF ; [.11AF.0020.0004.00DF][.0000.0199.0004.00DF][.11AF.0020.001F.00DF] # LATIN SMALL LETTER SHARP S; QQKN +FB06 ; [.11AF.0020.0004.FB06][.11CF.0020.0004.FB06] # LATIN SMALL LIGATURE ST; QQKN +FB05 ; [.11AF.0020.0004.FB05][.0000.019A.0004.FB05][.11CF.0020.001F.FB05] # LATIN SMALL LIGATURE LONG S T; QQKN +33DC ; [.11AF.0020.001D.33DC][.1216.0020.001C.33DC] # SQUARE SV; QQKN +1D74 ; [.11B3.0020.0002.1D74] # LATIN SMALL LETTER S WITH MIDDLE TILDE +1D8A ; [.11B4.0020.0002.1D8A] # LATIN SMALL LETTER S WITH PALATAL HOOK +0282 ; [.11B5.0020.0002.0282] # LATIN SMALL LETTER S WITH HOOK +1DB3 ; [.11B5.0020.0014.1DB3] # MODIFIER LETTER SMALL S WITH HOOK; QQK +023F ; [.11B9.0020.0002.023F] # LATIN SMALL LETTER S WITH SWASH TAIL +0283 ; [.11BD.0020.0002.0283] # LATIN SMALL LETTER ESH +01A9 ; [.11BD.0020.0008.01A9] # LATIN CAPITAL LETTER ESH +1DB4 ; [.11BD.0020.0014.1DB4] # MODIFIER LETTER SMALL ESH; QQK +1D8B ; [.11C1.0020.0002.1D8B] # LATIN SMALL LETTER ESH WITH PALATAL HOOK +01AA ; [.11C2.0020.0002.01AA] # LATIN LETTER REVERSED ESH LOOP +0285 ; [.11C6.0020.0002.0285] # LATIN SMALL LETTER SQUAT REVERSED ESH +1D98 ; [.11CA.0020.0002.1D98] # LATIN SMALL LETTER ESH WITH RETROFLEX HOOK +0286 ; [.11CB.0020.0002.0286] # LATIN SMALL LETTER ESH WITH CURL +0074 ; [.11CF.0020.0002.0074] # LATIN SMALL LETTER T +FF54 ; [.11CF.0020.0003.FF54] # FULLWIDTH LATIN SMALL LETTER T; QQK +036D ; [.11CF.0020.0004.036D] # COMBINING LATIN SMALL LETTER T; QQK +24AF ; [*02B1.0020.0004.24AF][.11CF.0020.0004.24AF][*02B2.0020.001F.24AF] # PARENTHESIZED LATIN SMALL LETTER T; QQKN +1D42D ; [.11CF.0020.0005.1D42D] # MATHEMATICAL BOLD SMALL T; QQK +1D461 ; [.11CF.0020.0005.1D461] # MATHEMATICAL ITALIC SMALL T; QQK +1D495 ; [.11CF.0020.0005.1D495] # MATHEMATICAL BOLD ITALIC SMALL T; QQK +1D4C9 ; [.11CF.0020.0005.1D4C9] # MATHEMATICAL SCRIPT SMALL T; QQK +1D4FD ; [.11CF.0020.0005.1D4FD] # MATHEMATICAL BOLD SCRIPT SMALL T; QQK +1D531 ; [.11CF.0020.0005.1D531] # MATHEMATICAL FRAKTUR SMALL T; QQK +1D565 ; [.11CF.0020.0005.1D565] # MATHEMATICAL DOUBLE-STRUCK SMALL T; QQK +1D599 ; [.11CF.0020.0005.1D599] # MATHEMATICAL BOLD FRAKTUR SMALL T; QQK +1D5CD ; [.11CF.0020.0005.1D5CD] # MATHEMATICAL SANS-SERIF SMALL T; QQK +1D601 ; [.11CF.0020.0005.1D601] # MATHEMATICAL SANS-SERIF BOLD SMALL T; QQK +1D635 ; [.11CF.0020.0005.1D635] # MATHEMATICAL SANS-SERIF ITALIC SMALL T; QQK +1D669 ; [.11CF.0020.0005.1D669] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL T; QQK +1D69D ; [.11CF.0020.0005.1D69D] # MATHEMATICAL MONOSPACE SMALL T; QQK +24E3 ; [.11CF.0020.0006.24E3] # CIRCLED LATIN SMALL LETTER T; QQK +0054 ; [.11CF.0020.0008.0054] # LATIN CAPITAL LETTER T +FF34 ; [.11CF.0020.0009.FF34] # FULLWIDTH LATIN CAPITAL LETTER T; QQK +1D413 ; [.11CF.0020.000B.1D413] # MATHEMATICAL BOLD CAPITAL T; QQK +1D447 ; [.11CF.0020.000B.1D447] # MATHEMATICAL ITALIC CAPITAL T; QQK +1D47B ; [.11CF.0020.000B.1D47B] # MATHEMATICAL BOLD ITALIC CAPITAL T; QQK +1D4AF ; [.11CF.0020.000B.1D4AF] # MATHEMATICAL SCRIPT CAPITAL T; QQK +1D4E3 ; [.11CF.0020.000B.1D4E3] # MATHEMATICAL BOLD SCRIPT CAPITAL T; QQK +1D517 ; [.11CF.0020.000B.1D517] # MATHEMATICAL FRAKTUR CAPITAL T; QQK +1D54B ; [.11CF.0020.000B.1D54B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL T; QQK +1D57F ; [.11CF.0020.000B.1D57F] # MATHEMATICAL BOLD FRAKTUR CAPITAL T; QQK +1D5B3 ; [.11CF.0020.000B.1D5B3] # MATHEMATICAL SANS-SERIF CAPITAL T; QQK +1D5E7 ; [.11CF.0020.000B.1D5E7] # MATHEMATICAL SANS-SERIF BOLD CAPITAL T; QQK +1D61B ; [.11CF.0020.000B.1D61B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL T; QQK +1D64F ; [.11CF.0020.000B.1D64F] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL T; QQK +1D683 ; [.11CF.0020.000B.1D683] # MATHEMATICAL MONOSPACE CAPITAL T; QQK +24C9 ; [.11CF.0020.000C.24C9] # CIRCLED LATIN CAPITAL LETTER T; QQK +1D57 ; [.11CF.0020.0014.1D57] # MODIFIER LETTER SMALL T; QQK +1D40 ; [.11CF.0020.001D.1D40] # MODIFIER LETTER CAPITAL T; QQK +0165 ; [.11CF.0020.0002.0074][.0000.0041.0002.030C] # LATIN SMALL LETTER T WITH CARON; QQCM +0164 ; [.11CF.0020.0008.0054][.0000.0041.0002.030C] # LATIN CAPITAL LETTER T WITH CARON; QQCM +1E97 ; [.11CF.0020.0002.0074][.0000.0047.0002.0308] # LATIN SMALL LETTER T WITH DIAERESIS; QQCM +1E6B ; [.11CF.0020.0002.0074][.0000.0052.0002.0307] # LATIN SMALL LETTER T WITH DOT ABOVE; QQCM +1E6A ; [.11CF.0020.0008.0054][.0000.0052.0002.0307] # LATIN CAPITAL LETTER T WITH DOT ABOVE; QQCM +0163 ; [.11CF.0020.0002.0074][.0000.0056.0002.0327] # LATIN SMALL LETTER T WITH CEDILLA; QQCM +0162 ; [.11CF.0020.0008.0054][.0000.0056.0002.0327] # LATIN CAPITAL LETTER T WITH CEDILLA; QQCM +1E6D ; [.11CF.0020.0002.0074][.0000.007A.0002.0323] # LATIN SMALL LETTER T WITH DOT BELOW; QQCM +1E6C ; [.11CF.0020.0008.0054][.0000.007A.0002.0323] # LATIN CAPITAL LETTER T WITH DOT BELOW; QQCM +021B ; [.11CF.0020.0002.0074][.0000.0081.0002.0326] # LATIN SMALL LETTER T WITH COMMA BELOW; QQCM +021A ; [.11CF.0020.0008.0054][.0000.0081.0002.0326] # LATIN CAPITAL LETTER T WITH COMMA BELOW; QQCM +1E71 ; [.11CF.0020.0002.0074][.0000.0086.0002.032D] # LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW; QQCM +1E70 ; [.11CF.0020.0008.0054][.0000.0086.0002.032D] # LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW; QQCM +1E6F ; [.11CF.0020.0002.0074][.0000.008A.0002.0331] # LATIN SMALL LETTER T WITH LINE BELOW; QQCM +1E6E ; [.11CF.0020.0008.0054][.0000.008A.0002.0331] # LATIN CAPITAL LETTER T WITH LINE BELOW; QQCM +02A8 ; [.11CF.0020.0004.02A8][.100B.0020.0004.02A8] # LATIN SMALL LETTER TC DIGRAPH WITH CURL; QQKN +2121 ; [.11CF.0020.000A.2121][.1029.0020.000A.2121][.10E5.0020.001F.2121] # TELEPHONE SIGN; QQKN +1D7A ; [.11CF.0020.0004.1D7A][.0000.019A.0004.1D7A][.108D.0020.001F.1D7A] # LATIN SMALL LETTER TH WITH STRIKETHROUGH; QQKN +3394 ; [.11CF.0020.001D.3394][.108D.0020.001D.3394][.1243.0020.001F.3394] # SQUARE THZ; QQKN +2122 ; [.11CF.0020.0014.2122][.1110.0020.0014.2122] # TRADE MARK SIGN; QQKN +01BE ; [.11CF.0020.0004.01BE][.11AF.0020.0004.01BE] # LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE; QQKN +02A6 ; [.11CF.0020.0004.02A6][.11AF.0020.0004.02A6] # LATIN SMALL LETTER TS DIGRAPH; QQKN +02A7 ; [.11CF.0020.0004.02A7][.11BD.0020.0004.02A7] # LATIN SMALL LETTER TESH DIGRAPH; QQKN +1D1B ; [.11D3.0020.0002.1D1B] # LATIN LETTER SMALL CAPITAL T +0167 ; [.11D4.0020.0002.0167] # LATIN SMALL LETTER T WITH STROKE +0166 ; [.11D4.0020.0008.0166] # LATIN CAPITAL LETTER T WITH STROKE +2C66 ; [.11D8.0020.0002.2C66] # LATIN SMALL LETTER T WITH DIAGONAL STROKE +023E ; [.11D8.0020.0008.023E] # LATIN CAPITAL LETTER T WITH DIAGONAL STROKE +1D75 ; [.11D9.0020.0002.1D75] # LATIN SMALL LETTER T WITH MIDDLE TILDE +01AB ; [.11DA.0020.0002.01AB] # LATIN SMALL LETTER T WITH PALATAL HOOK +1DB5 ; [.11DA.0020.0014.1DB5] # MODIFIER LETTER SMALL T WITH PALATAL HOOK; QQK +01AD ; [.11DE.0020.0002.01AD] # LATIN SMALL LETTER T WITH HOOK +01AC ; [.11DE.0020.0008.01AC] # LATIN CAPITAL LETTER T WITH HOOK +0288 ; [.11E2.0020.0002.0288] # LATIN SMALL LETTER T WITH RETROFLEX HOOK +01AE ; [.11E2.0020.0008.01AE] # LATIN CAPITAL LETTER T WITH RETROFLEX HOOK +0236 ; [.11E6.0020.0002.0236] # LATIN SMALL LETTER T WITH CURL +0287 ; [.11EA.0020.0002.0287] # LATIN SMALL LETTER TURNED T +0075 ; [.11EE.0020.0002.0075] # LATIN SMALL LETTER U +FF55 ; [.11EE.0020.0003.FF55] # FULLWIDTH LATIN SMALL LETTER U; QQK +0367 ; [.11EE.0020.0004.0367] # COMBINING LATIN SMALL LETTER U; QQK +24B0 ; [*02B1.0020.0004.24B0][.11EE.0020.0004.24B0][*02B2.0020.001F.24B0] # PARENTHESIZED LATIN SMALL LETTER U; QQKN +1D42E ; [.11EE.0020.0005.1D42E] # MATHEMATICAL BOLD SMALL U; QQK +1D462 ; [.11EE.0020.0005.1D462] # MATHEMATICAL ITALIC SMALL U; QQK +1D496 ; [.11EE.0020.0005.1D496] # MATHEMATICAL BOLD ITALIC SMALL U; QQK +1D4CA ; [.11EE.0020.0005.1D4CA] # MATHEMATICAL SCRIPT SMALL U; QQK +1D4FE ; [.11EE.0020.0005.1D4FE] # MATHEMATICAL BOLD SCRIPT SMALL U; QQK +1D532 ; [.11EE.0020.0005.1D532] # MATHEMATICAL FRAKTUR SMALL U; QQK +1D566 ; [.11EE.0020.0005.1D566] # MATHEMATICAL DOUBLE-STRUCK SMALL U; QQK +1D59A ; [.11EE.0020.0005.1D59A] # MATHEMATICAL BOLD FRAKTUR SMALL U; QQK +1D5CE ; [.11EE.0020.0005.1D5CE] # MATHEMATICAL SANS-SERIF SMALL U; QQK +1D602 ; [.11EE.0020.0005.1D602] # MATHEMATICAL SANS-SERIF BOLD SMALL U; QQK +1D636 ; [.11EE.0020.0005.1D636] # MATHEMATICAL SANS-SERIF ITALIC SMALL U; QQK +1D66A ; [.11EE.0020.0005.1D66A] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL U; QQK +1D69E ; [.11EE.0020.0005.1D69E] # MATHEMATICAL MONOSPACE SMALL U; QQK +24E4 ; [.11EE.0020.0006.24E4] # CIRCLED LATIN SMALL LETTER U; QQK +0055 ; [.11EE.0020.0008.0055] # LATIN CAPITAL LETTER U +FF35 ; [.11EE.0020.0009.FF35] # FULLWIDTH LATIN CAPITAL LETTER U; QQK +1D414 ; [.11EE.0020.000B.1D414] # MATHEMATICAL BOLD CAPITAL U; QQK +1D448 ; [.11EE.0020.000B.1D448] # MATHEMATICAL ITALIC CAPITAL U; QQK +1D47C ; [.11EE.0020.000B.1D47C] # MATHEMATICAL BOLD ITALIC CAPITAL U; QQK +1D4B0 ; [.11EE.0020.000B.1D4B0] # MATHEMATICAL SCRIPT CAPITAL U; QQK +1D4E4 ; [.11EE.0020.000B.1D4E4] # MATHEMATICAL BOLD SCRIPT CAPITAL U; QQK +1D518 ; [.11EE.0020.000B.1D518] # MATHEMATICAL FRAKTUR CAPITAL U; QQK +1D54C ; [.11EE.0020.000B.1D54C] # MATHEMATICAL DOUBLE-STRUCK CAPITAL U; QQK +1D580 ; [.11EE.0020.000B.1D580] # MATHEMATICAL BOLD FRAKTUR CAPITAL U; QQK +1D5B4 ; [.11EE.0020.000B.1D5B4] # MATHEMATICAL SANS-SERIF CAPITAL U; QQK +1D5E8 ; [.11EE.0020.000B.1D5E8] # MATHEMATICAL SANS-SERIF BOLD CAPITAL U; QQK +1D61C ; [.11EE.0020.000B.1D61C] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL U; QQK +1D650 ; [.11EE.0020.000B.1D650] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL U; QQK +1D684 ; [.11EE.0020.000B.1D684] # MATHEMATICAL MONOSPACE CAPITAL U; QQK +24CA ; [.11EE.0020.000C.24CA] # CIRCLED LATIN CAPITAL LETTER U; QQK +1D58 ; [.11EE.0020.0014.1D58] # MODIFIER LETTER SMALL U; QQK +1D64 ; [.11EE.0020.0015.1D64] # LATIN SUBSCRIPT SMALL LETTER U; QQK +1D41 ; [.11EE.0020.001D.1D41] # MODIFIER LETTER CAPITAL U; QQK +00FA ; [.11EE.0020.0002.0075][.0000.0032.0002.0301] # LATIN SMALL LETTER U WITH ACUTE; QQCM +00DA ; [.11EE.0020.0008.0055][.0000.0032.0002.0301] # LATIN CAPITAL LETTER U WITH ACUTE; QQCM +00F9 ; [.11EE.0020.0002.0075][.0000.0035.0002.0300] # LATIN SMALL LETTER U WITH GRAVE; QQCM +00D9 ; [.11EE.0020.0008.0055][.0000.0035.0002.0300] # LATIN CAPITAL LETTER U WITH GRAVE; QQCM +016D ; [.11EE.0020.0002.0075][.0000.0037.0002.0306] # LATIN SMALL LETTER U WITH BREVE; QQCM +016C ; [.11EE.0020.0008.0055][.0000.0037.0002.0306] # LATIN CAPITAL LETTER U WITH BREVE; QQCM +00FB ; [.11EE.0020.0002.0075][.0000.003C.0002.0302] # LATIN SMALL LETTER U WITH CIRCUMFLEX; QQCM +00DB ; [.11EE.0020.0008.0055][.0000.003C.0002.0302] # LATIN CAPITAL LETTER U WITH CIRCUMFLEX; QQCM +01D4 ; [.11EE.0020.0002.0075][.0000.0041.0002.030C] # LATIN SMALL LETTER U WITH CARON; QQCM +01D3 ; [.11EE.0020.0008.0055][.0000.0041.0002.030C] # LATIN CAPITAL LETTER U WITH CARON; QQCM +016F ; [.11EE.0020.0002.0075][.0000.0043.0002.030A] # LATIN SMALL LETTER U WITH RING ABOVE; QQCM +016E ; [.11EE.0020.0008.0055][.0000.0043.0002.030A] # LATIN CAPITAL LETTER U WITH RING ABOVE; QQCM +00FC ; [.11EE.0020.0002.0075][.0000.0047.0002.0308] # LATIN SMALL LETTER U WITH DIAERESIS; QQCM +00DC ; [.11EE.0020.0008.0055][.0000.0047.0002.0308] # LATIN CAPITAL LETTER U WITH DIAERESIS; QQCM +01D8 ; [.11EE.0020.0002.0075][.0000.0047.0002.0308][.0000.0032.0002.0301] # LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE; QQCM +01D7 ; [.11EE.0020.0008.0055][.0000.0047.0002.0308][.0000.0032.0002.0301] # LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE; QQCM +01DC ; [.11EE.0020.0002.0075][.0000.0047.0002.0308][.0000.0035.0002.0300] # LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE; QQCM +01DB ; [.11EE.0020.0008.0055][.0000.0047.0002.0308][.0000.0035.0002.0300] # LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE; QQCM +01DA ; [.11EE.0020.0002.0075][.0000.0047.0002.0308][.0000.0041.0002.030C] # LATIN SMALL LETTER U WITH DIAERESIS AND CARON; QQCM +01D9 ; [.11EE.0020.0008.0055][.0000.0047.0002.0308][.0000.0041.0002.030C] # LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON; QQCM +01D6 ; [.11EE.0020.0002.0075][.0000.0047.0002.0308][.0000.005B.0002.0304] # LATIN SMALL LETTER U WITH DIAERESIS AND MACRON; QQCM +01D5 ; [.11EE.0020.0008.0055][.0000.0047.0002.0308][.0000.005B.0002.0304] # LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON; QQCM +0171 ; [.11EE.0020.0002.0075][.0000.004D.0002.030B] # LATIN SMALL LETTER U WITH DOUBLE ACUTE; QQCM +0170 ; [.11EE.0020.0008.0055][.0000.004D.0002.030B] # LATIN CAPITAL LETTER U WITH DOUBLE ACUTE; QQCM +0169 ; [.11EE.0020.0002.0075][.0000.004E.0002.0303] # LATIN SMALL LETTER U WITH TILDE; QQCM +0168 ; [.11EE.0020.0008.0055][.0000.004E.0002.0303] # LATIN CAPITAL LETTER U WITH TILDE; QQCM +1E79 ; [.11EE.0020.0002.0075][.0000.004E.0002.0303][.0000.0032.0002.0301] # LATIN SMALL LETTER U WITH TILDE AND ACUTE; QQCM +1E78 ; [.11EE.0020.0008.0055][.0000.004E.0002.0303][.0000.0032.0002.0301] # LATIN CAPITAL LETTER U WITH TILDE AND ACUTE; QQCM +0173 ; [.11EE.0020.0002.0075][.0000.0059.0002.0328] # LATIN SMALL LETTER U WITH OGONEK; QQCM +0172 ; [.11EE.0020.0008.0055][.0000.0059.0002.0328] # LATIN CAPITAL LETTER U WITH OGONEK; QQCM +016B ; [.11EE.0020.0002.0075][.0000.005B.0002.0304] # LATIN SMALL LETTER U WITH MACRON; QQCM +016A ; [.11EE.0020.0008.0055][.0000.005B.0002.0304] # LATIN CAPITAL LETTER U WITH MACRON; QQCM +1E7B ; [.11EE.0020.0002.0075][.0000.005B.0002.0304][.0000.0047.0002.0308] # LATIN SMALL LETTER U WITH MACRON AND DIAERESIS; QQCM +1E7A ; [.11EE.0020.0008.0055][.0000.005B.0002.0304][.0000.0047.0002.0308] # LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS; QQCM +1EE7 ; [.11EE.0020.0002.0075][.0000.0060.0002.0309] # LATIN SMALL LETTER U WITH HOOK ABOVE; QQCM +1EE6 ; [.11EE.0020.0008.0055][.0000.0060.0002.0309] # LATIN CAPITAL LETTER U WITH HOOK ABOVE; QQCM +0215 ; [.11EE.0020.0002.0075][.0000.0063.0002.030F] # LATIN SMALL LETTER U WITH DOUBLE GRAVE; QQCM +0214 ; [.11EE.0020.0008.0055][.0000.0063.0002.030F] # LATIN CAPITAL LETTER U WITH DOUBLE GRAVE; QQCM +0217 ; [.11EE.0020.0002.0075][.0000.0065.0002.0311] # LATIN SMALL LETTER U WITH INVERTED BREVE; QQCM +0216 ; [.11EE.0020.0008.0055][.0000.0065.0002.0311] # LATIN CAPITAL LETTER U WITH INVERTED BREVE; QQCM +01B0 ; [.11EE.0020.0002.0075][.0000.006D.0002.031B] # LATIN SMALL LETTER U WITH HORN; QQCM +01AF ; [.11EE.0020.0008.0055][.0000.006D.0002.031B] # LATIN CAPITAL LETTER U WITH HORN; QQCM +1EE9 ; [.11EE.0020.0002.0075][.0000.006D.0002.031B][.0000.0032.0002.0301] # LATIN SMALL LETTER U WITH HORN AND ACUTE; QQCM +1EE8 ; [.11EE.0020.0008.0055][.0000.006D.0002.031B][.0000.0032.0002.0301] # LATIN CAPITAL LETTER U WITH HORN AND ACUTE; QQCM +1EEB ; [.11EE.0020.0002.0075][.0000.006D.0002.031B][.0000.0035.0002.0300] # LATIN SMALL LETTER U WITH HORN AND GRAVE; QQCM +1EEA ; [.11EE.0020.0008.0055][.0000.006D.0002.031B][.0000.0035.0002.0300] # LATIN CAPITAL LETTER U WITH HORN AND GRAVE; QQCM +1EEF ; [.11EE.0020.0002.0075][.0000.006D.0002.031B][.0000.004E.0002.0303] # LATIN SMALL LETTER U WITH HORN AND TILDE; QQCM +1EEE ; [.11EE.0020.0008.0055][.0000.006D.0002.031B][.0000.004E.0002.0303] # LATIN CAPITAL LETTER U WITH HORN AND TILDE; QQCM +1EED ; [.11EE.0020.0002.0075][.0000.006D.0002.031B][.0000.0060.0002.0309] # LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE; QQCM +1EEC ; [.11EE.0020.0008.0055][.0000.006D.0002.031B][.0000.0060.0002.0309] # LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE; QQCM +1EF1 ; [.11EE.0020.0002.0075][.0000.006D.0002.031B][.0000.007A.0002.0323] # LATIN SMALL LETTER U WITH HORN AND DOT BELOW; QQCM +1EF0 ; [.11EE.0020.0008.0055][.0000.006D.0002.031B][.0000.007A.0002.0323] # LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW; QQCM +1EE5 ; [.11EE.0020.0002.0075][.0000.007A.0002.0323] # LATIN SMALL LETTER U WITH DOT BELOW; QQCM +1EE4 ; [.11EE.0020.0008.0055][.0000.007A.0002.0323] # LATIN CAPITAL LETTER U WITH DOT BELOW; QQCM +1E73 ; [.11EE.0020.0002.0075][.0000.007F.0002.0324] # LATIN SMALL LETTER U WITH DIAERESIS BELOW; QQCM +1E72 ; [.11EE.0020.0008.0055][.0000.007F.0002.0324] # LATIN CAPITAL LETTER U WITH DIAERESIS BELOW; QQCM +1E77 ; [.11EE.0020.0002.0075][.0000.0086.0002.032D] # LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW; QQCM +1E76 ; [.11EE.0020.0008.0055][.0000.0086.0002.032D] # LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW; QQCM +1E75 ; [.11EE.0020.0002.0075][.0000.0089.0002.0330] # LATIN SMALL LETTER U WITH TILDE BELOW; QQCM +1E74 ; [.11EE.0020.0008.0055][.0000.0089.0002.0330] # LATIN CAPITAL LETTER U WITH TILDE BELOW; QQCM +1D1C ; [.11F2.0020.0002.1D1C] # LATIN LETTER SMALL CAPITAL U +1DB8 ; [.11F2.0020.0014.1DB8] # MODIFIER LETTER SMALL CAPITAL U; QQK +1D1D ; [.11F3.0020.0002.1D1D] # LATIN SMALL LETTER SIDEWAYS U +1D59 ; [.11F3.0020.0014.1D59] # MODIFIER LETTER SMALL SIDEWAYS U; QQK +1D1E ; [.11F4.0020.0002.1D1E] # LATIN SMALL LETTER SIDEWAYS DIAERESIZED U +1D6B ; [.11F5.0020.0002.1D6B] # LATIN SMALL LETTER UE +0289 ; [.11F6.0020.0002.0289] # LATIN SMALL LETTER U BAR +0244 ; [.11F6.0020.0008.0244] # LATIN CAPITAL LETTER U BAR +1DB6 ; [.11F6.0020.0014.1DB6] # MODIFIER LETTER SMALL U BAR; QQK +1D7E ; [.11FA.0020.0002.1D7E] # LATIN SMALL CAPITAL LETTER U WITH STROKE +1D99 ; [.11FB.0020.0002.1D99] # LATIN SMALL LETTER U WITH RETROFLEX HOOK +0265 ; [.11FC.0020.0002.0265] # LATIN SMALL LETTER TURNED H +1DA3 ; [.11FC.0020.0014.1DA3] # MODIFIER LETTER SMALL TURNED H; QQK +02AE ; [.1200.0020.0002.02AE] # LATIN SMALL LETTER TURNED H WITH FISHHOOK +02AF ; [.1204.0020.0002.02AF] # LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL +026F ; [.1208.0020.0002.026F] # LATIN SMALL LETTER TURNED M +019C ; [.1208.0020.0008.019C] # LATIN CAPITAL LETTER TURNED M +1D5A ; [.1208.0020.0014.1D5A] # MODIFIER LETTER SMALL TURNED M; QQK +1D1F ; [.120C.0020.0002.1D1F] # LATIN SMALL LETTER SIDEWAYS TURNED M +0270 ; [.120D.0020.0002.0270] # LATIN SMALL LETTER TURNED M WITH LONG LEG +1DAD ; [.120D.0020.0014.1DAD] # MODIFIER LETTER SMALL TURNED M WITH LONG LEG; QQK +028A ; [.1211.0020.0002.028A] # LATIN SMALL LETTER UPSILON +01B1 ; [.1211.0020.0008.01B1] # LATIN CAPITAL LETTER UPSILON +1DB7 ; [.1211.0020.0014.1DB7] # MODIFIER LETTER SMALL UPSILON; QQK +1D7F ; [.1215.0020.0002.1D7F] # LATIN SMALL LETTER UPSILON WITH STROKE +0076 ; [.1216.0020.0002.0076] # LATIN SMALL LETTER V +FF56 ; [.1216.0020.0003.FF56] # FULLWIDTH LATIN SMALL LETTER V; QQK +036E ; [.1216.0020.0004.036E] # COMBINING LATIN SMALL LETTER V; QQK +2174 ; [.1216.0020.0004.2174] # SMALL ROMAN NUMERAL FIVE; QQK +24B1 ; [*02B1.0020.0004.24B1][.1216.0020.0004.24B1][*02B2.0020.001F.24B1] # PARENTHESIZED LATIN SMALL LETTER V; QQKN +1D42F ; [.1216.0020.0005.1D42F] # MATHEMATICAL BOLD SMALL V; QQK +1D463 ; [.1216.0020.0005.1D463] # MATHEMATICAL ITALIC SMALL V; QQK +1D497 ; [.1216.0020.0005.1D497] # MATHEMATICAL BOLD ITALIC SMALL V; QQK +1D4CB ; [.1216.0020.0005.1D4CB] # MATHEMATICAL SCRIPT SMALL V; QQK +1D4FF ; [.1216.0020.0005.1D4FF] # MATHEMATICAL BOLD SCRIPT SMALL V; QQK +1D533 ; [.1216.0020.0005.1D533] # MATHEMATICAL FRAKTUR SMALL V; QQK +1D567 ; [.1216.0020.0005.1D567] # MATHEMATICAL DOUBLE-STRUCK SMALL V; QQK +1D59B ; [.1216.0020.0005.1D59B] # MATHEMATICAL BOLD FRAKTUR SMALL V; QQK +1D5CF ; [.1216.0020.0005.1D5CF] # MATHEMATICAL SANS-SERIF SMALL V; QQK +1D603 ; [.1216.0020.0005.1D603] # MATHEMATICAL SANS-SERIF BOLD SMALL V; QQK +1D637 ; [.1216.0020.0005.1D637] # MATHEMATICAL SANS-SERIF ITALIC SMALL V; QQK +1D66B ; [.1216.0020.0005.1D66B] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL V; QQK +1D69F ; [.1216.0020.0005.1D69F] # MATHEMATICAL MONOSPACE SMALL V; QQK +24E5 ; [.1216.0020.0006.24E5] # CIRCLED LATIN SMALL LETTER V; QQK +0056 ; [.1216.0020.0008.0056] # LATIN CAPITAL LETTER V +FF36 ; [.1216.0020.0009.FF36] # FULLWIDTH LATIN CAPITAL LETTER V; QQK +2164 ; [.1216.0020.000A.2164] # ROMAN NUMERAL FIVE; QQK +1D415 ; [.1216.0020.000B.1D415] # MATHEMATICAL BOLD CAPITAL V; QQK +1D449 ; [.1216.0020.000B.1D449] # MATHEMATICAL ITALIC CAPITAL V; QQK +1D47D ; [.1216.0020.000B.1D47D] # MATHEMATICAL BOLD ITALIC CAPITAL V; QQK +1D4B1 ; [.1216.0020.000B.1D4B1] # MATHEMATICAL SCRIPT CAPITAL V; QQK +1D4E5 ; [.1216.0020.000B.1D4E5] # MATHEMATICAL BOLD SCRIPT CAPITAL V; QQK +1D519 ; [.1216.0020.000B.1D519] # MATHEMATICAL FRAKTUR CAPITAL V; QQK +1D54D ; [.1216.0020.000B.1D54D] # MATHEMATICAL DOUBLE-STRUCK CAPITAL V; QQK +1D581 ; [.1216.0020.000B.1D581] # MATHEMATICAL BOLD FRAKTUR CAPITAL V; QQK +1D5B5 ; [.1216.0020.000B.1D5B5] # MATHEMATICAL SANS-SERIF CAPITAL V; QQK +1D5E9 ; [.1216.0020.000B.1D5E9] # MATHEMATICAL SANS-SERIF BOLD CAPITAL V; QQK +1D61D ; [.1216.0020.000B.1D61D] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL V; QQK +1D651 ; [.1216.0020.000B.1D651] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL V; QQK +1D685 ; [.1216.0020.000B.1D685] # MATHEMATICAL MONOSPACE CAPITAL V; QQK +24CB ; [.1216.0020.000C.24CB] # CIRCLED LATIN CAPITAL LETTER V; QQK +1D5B ; [.1216.0020.0014.1D5B] # MODIFIER LETTER SMALL V; QQK +1D65 ; [.1216.0020.0015.1D65] # LATIN SUBSCRIPT SMALL LETTER V; QQK +1E7D ; [.1216.0020.0002.0076][.0000.004E.0002.0303] # LATIN SMALL LETTER V WITH TILDE; QQCM +1E7C ; [.1216.0020.0008.0056][.0000.004E.0002.0303] # LATIN CAPITAL LETTER V WITH TILDE; QQCM +1E7F ; [.1216.0020.0002.0076][.0000.007A.0002.0323] # LATIN SMALL LETTER V WITH DOT BELOW; QQCM +1E7E ; [.1216.0020.0008.0056][.0000.007A.0002.0323] # LATIN CAPITAL LETTER V WITH DOT BELOW; QQCM +2175 ; [.1216.0020.0004.2175][.10A5.0020.0004.2175] # SMALL ROMAN NUMERAL SIX; QQKN +2165 ; [.1216.0020.000A.2165][.10A5.0020.000A.2165] # ROMAN NUMERAL SIX; QQKN +2176 ; [.1216.0020.0004.2176][.10A5.0020.0004.2176][.10A5.0020.001F.2176] # SMALL ROMAN NUMERAL SEVEN; QQKN +2166 ; [.1216.0020.000A.2166][.10A5.0020.000A.2166][.10A5.0020.001F.2166] # ROMAN NUMERAL SEVEN; QQKN +2177 ; [.1216.0020.0004.2177][.10A5.0020.0004.2177][.10A5.0020.001F.2177][.10A5.0020.001F.2177] # SMALL ROMAN NUMERAL EIGHT; QQKN +2167 ; [.1216.0020.000A.2167][.10A5.0020.000A.2167][.10A5.0020.001F.2167][.10A5.0020.001F.2167] # ROMAN NUMERAL EIGHT; QQKN +33DE ; [.1216.0020.001D.33DE][*04C7.0020.001C.33DE][.1110.0020.001F.33DE] # SQUARE V OVER M; QQKN +1D20 ; [.121A.0020.0002.1D20] # LATIN LETTER SMALL CAPITAL V +1D8C ; [.121B.0020.0002.1D8C] # LATIN SMALL LETTER V WITH PALATAL HOOK +028B ; [.121C.0020.0002.028B] # LATIN SMALL LETTER V WITH HOOK +01B2 ; [.121C.0020.0008.01B2] # LATIN CAPITAL LETTER V WITH HOOK +1DB9 ; [.121C.0020.0014.1DB9] # MODIFIER LETTER SMALL V WITH HOOK; QQK +2C74 ; [.1220.0020.0002.2C74] # LATIN SMALL LETTER V WITH CURL +028C ; [.1221.0020.0002.028C] # LATIN SMALL LETTER TURNED V +0245 ; [.1221.0020.0008.0245] # LATIN CAPITAL LETTER TURNED V +1DBA ; [.1221.0020.0014.1DBA] # MODIFIER LETTER SMALL TURNED V; QQK +0077 ; [.1225.0020.0002.0077] # LATIN SMALL LETTER W +FF57 ; [.1225.0020.0003.FF57] # FULLWIDTH LATIN SMALL LETTER W; QQK +24B2 ; [*02B1.0020.0004.24B2][.1225.0020.0004.24B2][*02B2.0020.001F.24B2] # PARENTHESIZED LATIN SMALL LETTER W; QQKN +1D430 ; [.1225.0020.0005.1D430] # MATHEMATICAL BOLD SMALL W; QQK +1D464 ; [.1225.0020.0005.1D464] # MATHEMATICAL ITALIC SMALL W; QQK +1D498 ; [.1225.0020.0005.1D498] # MATHEMATICAL BOLD ITALIC SMALL W; QQK +1D4CC ; [.1225.0020.0005.1D4CC] # MATHEMATICAL SCRIPT SMALL W; QQK +1D500 ; [.1225.0020.0005.1D500] # MATHEMATICAL BOLD SCRIPT SMALL W; QQK +1D534 ; [.1225.0020.0005.1D534] # MATHEMATICAL FRAKTUR SMALL W; QQK +1D568 ; [.1225.0020.0005.1D568] # MATHEMATICAL DOUBLE-STRUCK SMALL W; QQK +1D59C ; [.1225.0020.0005.1D59C] # MATHEMATICAL BOLD FRAKTUR SMALL W; QQK +1D5D0 ; [.1225.0020.0005.1D5D0] # MATHEMATICAL SANS-SERIF SMALL W; QQK +1D604 ; [.1225.0020.0005.1D604] # MATHEMATICAL SANS-SERIF BOLD SMALL W; QQK +1D638 ; [.1225.0020.0005.1D638] # MATHEMATICAL SANS-SERIF ITALIC SMALL W; QQK +1D66C ; [.1225.0020.0005.1D66C] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL W; QQK +1D6A0 ; [.1225.0020.0005.1D6A0] # MATHEMATICAL MONOSPACE SMALL W; QQK +24E6 ; [.1225.0020.0006.24E6] # CIRCLED LATIN SMALL LETTER W; QQK +0057 ; [.1225.0020.0008.0057] # LATIN CAPITAL LETTER W +FF37 ; [.1225.0020.0009.FF37] # FULLWIDTH LATIN CAPITAL LETTER W; QQK +1D416 ; [.1225.0020.000B.1D416] # MATHEMATICAL BOLD CAPITAL W; QQK +1D44A ; [.1225.0020.000B.1D44A] # MATHEMATICAL ITALIC CAPITAL W; QQK +1D47E ; [.1225.0020.000B.1D47E] # MATHEMATICAL BOLD ITALIC CAPITAL W; QQK +1D4B2 ; [.1225.0020.000B.1D4B2] # MATHEMATICAL SCRIPT CAPITAL W; QQK +1D4E6 ; [.1225.0020.000B.1D4E6] # MATHEMATICAL BOLD SCRIPT CAPITAL W; QQK +1D51A ; [.1225.0020.000B.1D51A] # MATHEMATICAL FRAKTUR CAPITAL W; QQK +1D54E ; [.1225.0020.000B.1D54E] # MATHEMATICAL DOUBLE-STRUCK CAPITAL W; QQK +1D582 ; [.1225.0020.000B.1D582] # MATHEMATICAL BOLD FRAKTUR CAPITAL W; QQK +1D5B6 ; [.1225.0020.000B.1D5B6] # MATHEMATICAL SANS-SERIF CAPITAL W; QQK +1D5EA ; [.1225.0020.000B.1D5EA] # MATHEMATICAL SANS-SERIF BOLD CAPITAL W; QQK +1D61E ; [.1225.0020.000B.1D61E] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL W; QQK +1D652 ; [.1225.0020.000B.1D652] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL W; QQK +1D686 ; [.1225.0020.000B.1D686] # MATHEMATICAL MONOSPACE CAPITAL W; QQK +24CC ; [.1225.0020.000C.24CC] # CIRCLED LATIN CAPITAL LETTER W; QQK +02B7 ; [.1225.0020.0014.02B7] # MODIFIER LETTER SMALL W; QQK +1D42 ; [.1225.0020.001D.1D42] # MODIFIER LETTER CAPITAL W; QQK +1E83 ; [.1225.0020.0002.0077][.0000.0032.0002.0301] # LATIN SMALL LETTER W WITH ACUTE; QQCM +1E82 ; [.1225.0020.0008.0057][.0000.0032.0002.0301] # LATIN CAPITAL LETTER W WITH ACUTE; QQCM +1E81 ; [.1225.0020.0002.0077][.0000.0035.0002.0300] # LATIN SMALL LETTER W WITH GRAVE; QQCM +1E80 ; [.1225.0020.0008.0057][.0000.0035.0002.0300] # LATIN CAPITAL LETTER W WITH GRAVE; QQCM +0175 ; [.1225.0020.0002.0077][.0000.003C.0002.0302] # LATIN SMALL LETTER W WITH CIRCUMFLEX; QQCM +0174 ; [.1225.0020.0008.0057][.0000.003C.0002.0302] # LATIN CAPITAL LETTER W WITH CIRCUMFLEX; QQCM +1E98 ; [.1225.0020.0002.0077][.0000.0043.0002.030A] # LATIN SMALL LETTER W WITH RING ABOVE; QQCM +1E85 ; [.1225.0020.0002.0077][.0000.0047.0002.0308] # LATIN SMALL LETTER W WITH DIAERESIS; QQCM +1E84 ; [.1225.0020.0008.0057][.0000.0047.0002.0308] # LATIN CAPITAL LETTER W WITH DIAERESIS; QQCM +1E87 ; [.1225.0020.0002.0077][.0000.0052.0002.0307] # LATIN SMALL LETTER W WITH DOT ABOVE; QQCM +1E86 ; [.1225.0020.0008.0057][.0000.0052.0002.0307] # LATIN CAPITAL LETTER W WITH DOT ABOVE; QQCM +1E89 ; [.1225.0020.0002.0077][.0000.007A.0002.0323] # LATIN SMALL LETTER W WITH DOT BELOW; QQCM +1E88 ; [.1225.0020.0008.0057][.0000.007A.0002.0323] # LATIN CAPITAL LETTER W WITH DOT BELOW; QQCM +33DD ; [.1225.0020.001D.33DD][.0FE6.0020.001C.33DD] # SQUARE WB; QQKN +1D21 ; [.1229.0020.0002.1D21] # LATIN LETTER SMALL CAPITAL W +028D ; [.122A.0020.0002.028D] # LATIN SMALL LETTER TURNED W +0078 ; [.122E.0020.0002.0078] # LATIN SMALL LETTER X +FF58 ; [.122E.0020.0003.FF58] # FULLWIDTH LATIN SMALL LETTER X; QQK +036F ; [.122E.0020.0004.036F] # COMBINING LATIN SMALL LETTER X; QQK +2179 ; [.122E.0020.0004.2179] # SMALL ROMAN NUMERAL TEN; QQK +24B3 ; [*02B1.0020.0004.24B3][.122E.0020.0004.24B3][*02B2.0020.001F.24B3] # PARENTHESIZED LATIN SMALL LETTER X; QQKN +1D431 ; [.122E.0020.0005.1D431] # MATHEMATICAL BOLD SMALL X; QQK +1D465 ; [.122E.0020.0005.1D465] # MATHEMATICAL ITALIC SMALL X; QQK +1D499 ; [.122E.0020.0005.1D499] # MATHEMATICAL BOLD ITALIC SMALL X; QQK +1D4CD ; [.122E.0020.0005.1D4CD] # MATHEMATICAL SCRIPT SMALL X; QQK +1D501 ; [.122E.0020.0005.1D501] # MATHEMATICAL BOLD SCRIPT SMALL X; QQK +1D535 ; [.122E.0020.0005.1D535] # MATHEMATICAL FRAKTUR SMALL X; QQK +1D569 ; [.122E.0020.0005.1D569] # MATHEMATICAL DOUBLE-STRUCK SMALL X; QQK +1D59D ; [.122E.0020.0005.1D59D] # MATHEMATICAL BOLD FRAKTUR SMALL X; QQK +1D5D1 ; [.122E.0020.0005.1D5D1] # MATHEMATICAL SANS-SERIF SMALL X; QQK +1D605 ; [.122E.0020.0005.1D605] # MATHEMATICAL SANS-SERIF BOLD SMALL X; QQK +1D639 ; [.122E.0020.0005.1D639] # MATHEMATICAL SANS-SERIF ITALIC SMALL X; QQK +1D66D ; [.122E.0020.0005.1D66D] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL X; QQK +1D6A1 ; [.122E.0020.0005.1D6A1] # MATHEMATICAL MONOSPACE SMALL X; QQK +24E7 ; [.122E.0020.0006.24E7] # CIRCLED LATIN SMALL LETTER X; QQK +0058 ; [.122E.0020.0008.0058] # LATIN CAPITAL LETTER X +FF38 ; [.122E.0020.0009.FF38] # FULLWIDTH LATIN CAPITAL LETTER X; QQK +2169 ; [.122E.0020.000A.2169] # ROMAN NUMERAL TEN; QQK +1D417 ; [.122E.0020.000B.1D417] # MATHEMATICAL BOLD CAPITAL X; QQK +1D44B ; [.122E.0020.000B.1D44B] # MATHEMATICAL ITALIC CAPITAL X; QQK +1D47F ; [.122E.0020.000B.1D47F] # MATHEMATICAL BOLD ITALIC CAPITAL X; QQK +1D4B3 ; [.122E.0020.000B.1D4B3] # MATHEMATICAL SCRIPT CAPITAL X; QQK +1D4E7 ; [.122E.0020.000B.1D4E7] # MATHEMATICAL BOLD SCRIPT CAPITAL X; QQK +1D51B ; [.122E.0020.000B.1D51B] # MATHEMATICAL FRAKTUR CAPITAL X; QQK +1D54F ; [.122E.0020.000B.1D54F] # MATHEMATICAL DOUBLE-STRUCK CAPITAL X; QQK +1D583 ; [.122E.0020.000B.1D583] # MATHEMATICAL BOLD FRAKTUR CAPITAL X; QQK +1D5B7 ; [.122E.0020.000B.1D5B7] # MATHEMATICAL SANS-SERIF CAPITAL X; QQK +1D5EB ; [.122E.0020.000B.1D5EB] # MATHEMATICAL SANS-SERIF BOLD CAPITAL X; QQK +1D61F ; [.122E.0020.000B.1D61F] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL X; QQK +1D653 ; [.122E.0020.000B.1D653] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL X; QQK +1D687 ; [.122E.0020.000B.1D687] # MATHEMATICAL MONOSPACE CAPITAL X; QQK +24CD ; [.122E.0020.000C.24CD] # CIRCLED LATIN CAPITAL LETTER X; QQK +02E3 ; [.122E.0020.0014.02E3] # MODIFIER LETTER SMALL X; QQK +2093 ; [.122E.0020.0015.2093] # LATIN SUBSCRIPT SMALL LETTER X; QQK +1E8D ; [.122E.0020.0002.0078][.0000.0047.0002.0308] # LATIN SMALL LETTER X WITH DIAERESIS; QQCM +1E8C ; [.122E.0020.0008.0058][.0000.0047.0002.0308] # LATIN CAPITAL LETTER X WITH DIAERESIS; QQCM +1E8B ; [.122E.0020.0002.0078][.0000.0052.0002.0307] # LATIN SMALL LETTER X WITH DOT ABOVE; QQCM +1E8A ; [.122E.0020.0008.0058][.0000.0052.0002.0307] # LATIN CAPITAL LETTER X WITH DOT ABOVE; QQCM +217A ; [.122E.0020.0004.217A][.10A5.0020.0004.217A] # SMALL ROMAN NUMERAL ELEVEN; QQKN +216A ; [.122E.0020.000A.216A][.10A5.0020.000A.216A] # ROMAN NUMERAL ELEVEN; QQKN +217B ; [.122E.0020.0004.217B][.10A5.0020.0004.217B][.10A5.0020.001F.217B] # SMALL ROMAN NUMERAL TWELVE; QQKN +216B ; [.122E.0020.000A.216B][.10A5.0020.000A.216B][.10A5.0020.001F.216B] # ROMAN NUMERAL TWELVE; QQKN +1D8D ; [.1232.0020.0002.1D8D] # LATIN SMALL LETTER X WITH PALATAL HOOK +0079 ; [.1233.0020.0002.0079] # LATIN SMALL LETTER Y +FF59 ; [.1233.0020.0003.FF59] # FULLWIDTH LATIN SMALL LETTER Y; QQK +24B4 ; [*02B1.0020.0004.24B4][.1233.0020.0004.24B4][*02B2.0020.001F.24B4] # PARENTHESIZED LATIN SMALL LETTER Y; QQKN +1D432 ; [.1233.0020.0005.1D432] # MATHEMATICAL BOLD SMALL Y; QQK +1D466 ; [.1233.0020.0005.1D466] # MATHEMATICAL ITALIC SMALL Y; QQK +1D49A ; [.1233.0020.0005.1D49A] # MATHEMATICAL BOLD ITALIC SMALL Y; QQK +1D4CE ; [.1233.0020.0005.1D4CE] # MATHEMATICAL SCRIPT SMALL Y; QQK +1D502 ; [.1233.0020.0005.1D502] # MATHEMATICAL BOLD SCRIPT SMALL Y; QQK +1D536 ; [.1233.0020.0005.1D536] # MATHEMATICAL FRAKTUR SMALL Y; QQK +1D56A ; [.1233.0020.0005.1D56A] # MATHEMATICAL DOUBLE-STRUCK SMALL Y; QQK +1D59E ; [.1233.0020.0005.1D59E] # MATHEMATICAL BOLD FRAKTUR SMALL Y; QQK +1D5D2 ; [.1233.0020.0005.1D5D2] # MATHEMATICAL SANS-SERIF SMALL Y; QQK +1D606 ; [.1233.0020.0005.1D606] # MATHEMATICAL SANS-SERIF BOLD SMALL Y; QQK +1D63A ; [.1233.0020.0005.1D63A] # MATHEMATICAL SANS-SERIF ITALIC SMALL Y; QQK +1D66E ; [.1233.0020.0005.1D66E] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Y; QQK +1D6A2 ; [.1233.0020.0005.1D6A2] # MATHEMATICAL MONOSPACE SMALL Y; QQK +24E8 ; [.1233.0020.0006.24E8] # CIRCLED LATIN SMALL LETTER Y; QQK +0059 ; [.1233.0020.0008.0059] # LATIN CAPITAL LETTER Y +FF39 ; [.1233.0020.0009.FF39] # FULLWIDTH LATIN CAPITAL LETTER Y; QQK +1D418 ; [.1233.0020.000B.1D418] # MATHEMATICAL BOLD CAPITAL Y; QQK +1D44C ; [.1233.0020.000B.1D44C] # MATHEMATICAL ITALIC CAPITAL Y; QQK +1D480 ; [.1233.0020.000B.1D480] # MATHEMATICAL BOLD ITALIC CAPITAL Y; QQK +1D4B4 ; [.1233.0020.000B.1D4B4] # MATHEMATICAL SCRIPT CAPITAL Y; QQK +1D4E8 ; [.1233.0020.000B.1D4E8] # MATHEMATICAL BOLD SCRIPT CAPITAL Y; QQK +1D51C ; [.1233.0020.000B.1D51C] # MATHEMATICAL FRAKTUR CAPITAL Y; QQK +1D550 ; [.1233.0020.000B.1D550] # MATHEMATICAL DOUBLE-STRUCK CAPITAL Y; QQK +1D584 ; [.1233.0020.000B.1D584] # MATHEMATICAL BOLD FRAKTUR CAPITAL Y; QQK +1D5B8 ; [.1233.0020.000B.1D5B8] # MATHEMATICAL SANS-SERIF CAPITAL Y; QQK +1D5EC ; [.1233.0020.000B.1D5EC] # MATHEMATICAL SANS-SERIF BOLD CAPITAL Y; QQK +1D620 ; [.1233.0020.000B.1D620] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL Y; QQK +1D654 ; [.1233.0020.000B.1D654] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Y; QQK +1D688 ; [.1233.0020.000B.1D688] # MATHEMATICAL MONOSPACE CAPITAL Y; QQK +24CE ; [.1233.0020.000C.24CE] # CIRCLED LATIN CAPITAL LETTER Y; QQK +02B8 ; [.1233.0020.0014.02B8] # MODIFIER LETTER SMALL Y; QQK +00FD ; [.1233.0020.0002.0079][.0000.0032.0002.0301] # LATIN SMALL LETTER Y WITH ACUTE; QQCM +00DD ; [.1233.0020.0008.0059][.0000.0032.0002.0301] # LATIN CAPITAL LETTER Y WITH ACUTE; QQCM +1EF3 ; [.1233.0020.0002.0079][.0000.0035.0002.0300] # LATIN SMALL LETTER Y WITH GRAVE; QQCM +1EF2 ; [.1233.0020.0008.0059][.0000.0035.0002.0300] # LATIN CAPITAL LETTER Y WITH GRAVE; QQCM +0177 ; [.1233.0020.0002.0079][.0000.003C.0002.0302] # LATIN SMALL LETTER Y WITH CIRCUMFLEX; QQCM +0176 ; [.1233.0020.0008.0059][.0000.003C.0002.0302] # LATIN CAPITAL LETTER Y WITH CIRCUMFLEX; QQCM +1E99 ; [.1233.0020.0002.0079][.0000.0043.0002.030A] # LATIN SMALL LETTER Y WITH RING ABOVE; QQCM +00FF ; [.1233.0020.0002.0079][.0000.0047.0002.0308] # LATIN SMALL LETTER Y WITH DIAERESIS; QQCM +0178 ; [.1233.0020.0008.0059][.0000.0047.0002.0308] # LATIN CAPITAL LETTER Y WITH DIAERESIS; QQCM +1EF9 ; [.1233.0020.0002.0079][.0000.004E.0002.0303] # LATIN SMALL LETTER Y WITH TILDE; QQCM +1EF8 ; [.1233.0020.0008.0059][.0000.004E.0002.0303] # LATIN CAPITAL LETTER Y WITH TILDE; QQCM +1E8F ; [.1233.0020.0002.0079][.0000.0052.0002.0307] # LATIN SMALL LETTER Y WITH DOT ABOVE; QQCM +1E8E ; [.1233.0020.0008.0059][.0000.0052.0002.0307] # LATIN CAPITAL LETTER Y WITH DOT ABOVE; QQCM +0233 ; [.1233.0020.0002.0079][.0000.005B.0002.0304] # LATIN SMALL LETTER Y WITH MACRON; QQCM +0232 ; [.1233.0020.0008.0059][.0000.005B.0002.0304] # LATIN CAPITAL LETTER Y WITH MACRON; QQCM +1EF7 ; [.1233.0020.0002.0079][.0000.0060.0002.0309] # LATIN SMALL LETTER Y WITH HOOK ABOVE; QQCM +1EF6 ; [.1233.0020.0008.0059][.0000.0060.0002.0309] # LATIN CAPITAL LETTER Y WITH HOOK ABOVE; QQCM +1EF5 ; [.1233.0020.0002.0079][.0000.007A.0002.0323] # LATIN SMALL LETTER Y WITH DOT BELOW; QQCM +1EF4 ; [.1233.0020.0008.0059][.0000.007A.0002.0323] # LATIN CAPITAL LETTER Y WITH DOT BELOW; QQCM +028F ; [.1237.0020.0002.028F] # LATIN LETTER SMALL CAPITAL Y +024F ; [.123B.0020.0002.024F] # LATIN SMALL LETTER Y WITH STROKE +024E ; [.123B.0020.0008.024E] # LATIN CAPITAL LETTER Y WITH STROKE +01B4 ; [.123F.0020.0002.01B4] # LATIN SMALL LETTER Y WITH HOOK +01B3 ; [.123F.0020.0008.01B3] # LATIN CAPITAL LETTER Y WITH HOOK +007A ; [.1243.0020.0002.007A] # LATIN SMALL LETTER Z +FF5A ; [.1243.0020.0003.FF5A] # FULLWIDTH LATIN SMALL LETTER Z; QQK +24B5 ; [*02B1.0020.0004.24B5][.1243.0020.0004.24B5][*02B2.0020.001F.24B5] # PARENTHESIZED LATIN SMALL LETTER Z; QQKN +1D433 ; [.1243.0020.0005.1D433] # MATHEMATICAL BOLD SMALL Z; QQK +1D467 ; [.1243.0020.0005.1D467] # MATHEMATICAL ITALIC SMALL Z; QQK +1D49B ; [.1243.0020.0005.1D49B] # MATHEMATICAL BOLD ITALIC SMALL Z; QQK +1D4CF ; [.1243.0020.0005.1D4CF] # MATHEMATICAL SCRIPT SMALL Z; QQK +1D503 ; [.1243.0020.0005.1D503] # MATHEMATICAL BOLD SCRIPT SMALL Z; QQK +1D537 ; [.1243.0020.0005.1D537] # MATHEMATICAL FRAKTUR SMALL Z; QQK +1D56B ; [.1243.0020.0005.1D56B] # MATHEMATICAL DOUBLE-STRUCK SMALL Z; QQK +1D59F ; [.1243.0020.0005.1D59F] # MATHEMATICAL BOLD FRAKTUR SMALL Z; QQK +1D5D3 ; [.1243.0020.0005.1D5D3] # MATHEMATICAL SANS-SERIF SMALL Z; QQK +1D607 ; [.1243.0020.0005.1D607] # MATHEMATICAL SANS-SERIF BOLD SMALL Z; QQK +1D63B ; [.1243.0020.0005.1D63B] # MATHEMATICAL SANS-SERIF ITALIC SMALL Z; QQK +1D66F ; [.1243.0020.0005.1D66F] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Z; QQK +1D6A3 ; [.1243.0020.0005.1D6A3] # MATHEMATICAL MONOSPACE SMALL Z; QQK +24E9 ; [.1243.0020.0006.24E9] # CIRCLED LATIN SMALL LETTER Z; QQK +005A ; [.1243.0020.0008.005A] # LATIN CAPITAL LETTER Z +FF3A ; [.1243.0020.0009.FF3A] # FULLWIDTH LATIN CAPITAL LETTER Z; QQK +2124 ; [.1243.0020.000B.2124] # DOUBLE-STRUCK CAPITAL Z; QQK +2128 ; [.1243.0020.000B.2128] # BLACK-LETTER CAPITAL Z; QQK +1D419 ; [.1243.0020.000B.1D419] # MATHEMATICAL BOLD CAPITAL Z; QQK +1D44D ; [.1243.0020.000B.1D44D] # MATHEMATICAL ITALIC CAPITAL Z; QQK +1D481 ; [.1243.0020.000B.1D481] # MATHEMATICAL BOLD ITALIC CAPITAL Z; QQK +1D4B5 ; [.1243.0020.000B.1D4B5] # MATHEMATICAL SCRIPT CAPITAL Z; QQK +1D4E9 ; [.1243.0020.000B.1D4E9] # MATHEMATICAL BOLD SCRIPT CAPITAL Z; QQK +1D585 ; [.1243.0020.000B.1D585] # MATHEMATICAL BOLD FRAKTUR CAPITAL Z; QQK +1D5B9 ; [.1243.0020.000B.1D5B9] # MATHEMATICAL SANS-SERIF CAPITAL Z; QQK +1D5ED ; [.1243.0020.000B.1D5ED] # MATHEMATICAL SANS-SERIF BOLD CAPITAL Z; QQK +1D621 ; [.1243.0020.000B.1D621] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z; QQK +1D655 ; [.1243.0020.000B.1D655] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z; QQK +1D689 ; [.1243.0020.000B.1D689] # MATHEMATICAL MONOSPACE CAPITAL Z; QQK +24CF ; [.1243.0020.000C.24CF] # CIRCLED LATIN CAPITAL LETTER Z; QQK +1DBB ; [.1243.0020.0014.1DBB] # MODIFIER LETTER SMALL Z; QQK +017A ; [.1243.0020.0002.007A][.0000.0032.0002.0301] # LATIN SMALL LETTER Z WITH ACUTE; QQCM +0179 ; [.1243.0020.0008.005A][.0000.0032.0002.0301] # LATIN CAPITAL LETTER Z WITH ACUTE; QQCM +1E91 ; [.1243.0020.0002.007A][.0000.003C.0002.0302] # LATIN SMALL LETTER Z WITH CIRCUMFLEX; QQCM +1E90 ; [.1243.0020.0008.005A][.0000.003C.0002.0302] # LATIN CAPITAL LETTER Z WITH CIRCUMFLEX; QQCM +017E ; [.1243.0020.0002.007A][.0000.0041.0002.030C] # LATIN SMALL LETTER Z WITH CARON; QQCM +017D ; [.1243.0020.0008.005A][.0000.0041.0002.030C] # LATIN CAPITAL LETTER Z WITH CARON; QQCM +017C ; [.1243.0020.0002.007A][.0000.0052.0002.0307] # LATIN SMALL LETTER Z WITH DOT ABOVE; QQCM +017B ; [.1243.0020.0008.005A][.0000.0052.0002.0307] # LATIN CAPITAL LETTER Z WITH DOT ABOVE; QQCM +1E93 ; [.1243.0020.0002.007A][.0000.007A.0002.0323] # LATIN SMALL LETTER Z WITH DOT BELOW; QQCM +1E92 ; [.1243.0020.0008.005A][.0000.007A.0002.0323] # LATIN CAPITAL LETTER Z WITH DOT BELOW; QQCM +1E95 ; [.1243.0020.0002.007A][.0000.008A.0002.0331] # LATIN SMALL LETTER Z WITH LINE BELOW; QQCM +1E94 ; [.1243.0020.0008.005A][.0000.008A.0002.0331] # LATIN CAPITAL LETTER Z WITH LINE BELOW; QQCM +018D ; [.1243.0020.0004.018D][.1225.0020.0004.018D] # LATIN SMALL LETTER TURNED DELTA; QQKN +1D22 ; [.1247.0020.0002.1D22] # LATIN LETTER SMALL CAPITAL Z +01B6 ; [.1248.0020.0002.01B6] # LATIN SMALL LETTER Z WITH STROKE +01B5 ; [.1248.0020.0008.01B5] # LATIN CAPITAL LETTER Z WITH STROKE +1D76 ; [.124C.0020.0002.1D76] # LATIN SMALL LETTER Z WITH MIDDLE TILDE +1D8E ; [.124D.0020.0002.1D8E] # LATIN SMALL LETTER Z WITH PALATAL HOOK +0225 ; [.124E.0020.0002.0225] # LATIN SMALL LETTER Z WITH HOOK +0224 ; [.124E.0020.0008.0224] # LATIN CAPITAL LETTER Z WITH HOOK +0290 ; [.1252.0020.0002.0290] # LATIN SMALL LETTER Z WITH RETROFLEX HOOK +1DBC ; [.1252.0020.0014.1DBC] # MODIFIER LETTER SMALL Z WITH RETROFLEX HOOK; QQK +0291 ; [.1256.0020.0002.0291] # LATIN SMALL LETTER Z WITH CURL +1DBD ; [.1256.0020.0014.1DBD] # MODIFIER LETTER SMALL Z WITH CURL; QQK +0240 ; [.125A.0020.0002.0240] # LATIN SMALL LETTER Z WITH SWASH TAIL +2C6C ; [.125E.0020.0002.2C6C] # LATIN SMALL LETTER Z WITH DESCENDER +2C6B ; [.125E.0020.0008.2C6B] # LATIN CAPITAL LETTER Z WITH DESCENDER +0292 ; [.125F.0020.0002.0292] # LATIN SMALL LETTER EZH +01B7 ; [.125F.0020.0008.01B7] # LATIN CAPITAL LETTER EZH +1DBE ; [.125F.0020.0014.1DBE] # MODIFIER LETTER SMALL EZH; QQK +01EF ; [.125F.0020.0002.0292][.0000.0041.0002.030C] # LATIN SMALL LETTER EZH WITH CARON; QQCM +01EE ; [.125F.0020.0008.01B7][.0000.0041.0002.030C] # LATIN CAPITAL LETTER EZH WITH CARON; QQCM +1D23 ; [.1263.0020.0002.1D23] # LATIN LETTER SMALL CAPITAL EZH +01B9 ; [.1264.0020.0002.01B9] # LATIN SMALL LETTER EZH REVERSED +01B8 ; [.1264.0020.0008.01B8] # LATIN CAPITAL LETTER EZH REVERSED +1D9A ; [.1268.0020.0002.1D9A] # LATIN SMALL LETTER EZH WITH RETROFLEX HOOK +01BA ; [.1269.0020.0002.01BA] # LATIN SMALL LETTER EZH WITH TAIL +0293 ; [.126D.0020.0002.0293] # LATIN SMALL LETTER EZH WITH CURL +021D ; [.1271.0020.0002.021D] # LATIN SMALL LETTER YOGH +021C ; [.1271.0020.0008.021C] # LATIN CAPITAL LETTER YOGH +00FE ; [.1275.0020.0002.00FE] # LATIN SMALL LETTER THORN +00DE ; [.1275.0020.0008.00DE] # LATIN CAPITAL LETTER THORN +01BF ; [.1279.0020.0002.01BF] # LATIN LETTER WYNN +01F7 ; [.1279.0020.0008.01F7] # LATIN CAPITAL LETTER WYNN +01BB ; [.127D.0020.0002.01BB] # LATIN LETTER TWO WITH STROKE +01A8 ; [.1281.0020.0002.01A8] # LATIN SMALL LETTER TONE TWO +01A7 ; [.1281.0020.0008.01A7] # LATIN CAPITAL LETTER TONE TWO +01BD ; [.1285.0020.0002.01BD] # LATIN SMALL LETTER TONE FIVE +01BC ; [.1285.0020.0008.01BC] # LATIN CAPITAL LETTER TONE FIVE +0185 ; [.1289.0020.0002.0185] # LATIN SMALL LETTER TONE SIX +0184 ; [.1289.0020.0008.0184] # LATIN CAPITAL LETTER TONE SIX +0294 ; [.128D.0020.0002.0294] # LATIN LETTER GLOTTAL STOP +0242 ; [.1291.0020.0002.0242] # LATIN SMALL LETTER GLOTTAL STOP +0241 ; [.1291.0020.0008.0241] # LATIN CAPITAL LETTER GLOTTAL STOP +02C0 ; [.1295.0020.0002.02C0] # MODIFIER LETTER GLOTTAL STOP +02BC ; [.1296.0020.0002.02BC] # MODIFIER LETTER APOSTROPHE +0149 ; [.1296.0020.0004.0149][.111B.0020.0004.0149] # LATIN SMALL LETTER N PRECEDED BY APOSTROPHE; QQKN +02EE ; [.1297.0020.0002.02EE] # MODIFIER LETTER DOUBLE APOSTROPHE +02BE ; [.1298.0020.0002.02BE] # MODIFIER LETTER RIGHT HALF RING +0295 ; [.1299.0020.0002.0295] # LATIN LETTER PHARYNGEAL VOICED FRICATIVE +02E4 ; [.1299.0020.0014.02E4] # MODIFIER LETTER SMALL REVERSED GLOTTAL STOP; QQK +02BF ; [.129D.0020.0002.02BF] # MODIFIER LETTER LEFT HALF RING +02C1 ; [.129E.0020.0002.02C1] # MODIFIER LETTER REVERSED GLOTTAL STOP +1D24 ; [.129F.0020.0002.1D24] # LATIN LETTER VOICED LARYNGEAL SPIRANT +1D25 ; [.12A0.0020.0002.1D25] # LATIN LETTER AIN +1D5C ; [.12A0.0020.0014.1D5C] # MODIFIER LETTER SMALL AIN; QQK +02A1 ; [.12A1.0020.0002.02A1] # LATIN LETTER GLOTTAL STOP WITH STROKE +02A2 ; [.12A5.0020.0002.02A2] # LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE +0296 ; [.12A9.0020.0002.0296] # LATIN LETTER INVERTED GLOTTAL STOP +01C0 ; [.12AD.0020.0002.01C0] # LATIN LETTER DENTAL CLICK +01C1 ; [.12B1.0020.0002.01C1] # LATIN LETTER LATERAL CLICK +01C2 ; [.12B5.0020.0002.01C2] # LATIN LETTER ALVEOLAR CLICK +01C3 ; [.12B9.0020.0002.01C3] # LATIN LETTER RETROFLEX CLICK +0297 ; [.12BD.0020.0002.0297] # LATIN LETTER STRETCHED C +0298 ; [.12C1.0020.0002.0298] # LATIN LETTER BILABIAL CLICK +02AC ; [.12C5.0020.0002.02AC] # LATIN LETTER BILABIAL PERCUSSIVE +02AD ; [.12C9.0020.0002.02AD] # LATIN LETTER BIDENTAL PERCUSSIVE +03B1 ; [.12CD.0020.0002.03B1] # GREEK SMALL LETTER ALPHA +1D6C2 ; [.12CD.0020.0005.1D6C2] # MATHEMATICAL BOLD SMALL ALPHA; QQK +1D6FC ; [.12CD.0020.0005.1D6FC] # MATHEMATICAL ITALIC SMALL ALPHA; QQK +1D736 ; [.12CD.0020.0005.1D736] # MATHEMATICAL BOLD ITALIC SMALL ALPHA; QQK +1D770 ; [.12CD.0020.0005.1D770] # MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA; QQK +1D7AA ; [.12CD.0020.0005.1D7AA] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA; QQK +0391 ; [.12CD.0020.0008.0391] # GREEK CAPITAL LETTER ALPHA +1D6A8 ; [.12CD.0020.000B.1D6A8] # MATHEMATICAL BOLD CAPITAL ALPHA; QQK +1D6E2 ; [.12CD.0020.000B.1D6E2] # MATHEMATICAL ITALIC CAPITAL ALPHA; QQK +1D71C ; [.12CD.0020.000B.1D71C] # MATHEMATICAL BOLD ITALIC CAPITAL ALPHA; QQK +1D756 ; [.12CD.0020.000B.1D756] # MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA; QQK +1D790 ; [.12CD.0020.000B.1D790] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA; QQK +1F00 ; [.12CD.0020.0002.03B1][.0000.0022.0002.0313] # GREEK SMALL LETTER ALPHA WITH PSILI; QQCM +1F08 ; [.12CD.0020.0008.0391][.0000.0022.0002.0313] # GREEK CAPITAL LETTER ALPHA WITH PSILI; QQCM +1F04 ; [.12CD.0020.0002.03B1][.0000.0022.0002.0313][.0000.0032.0002.0301] # GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA; QQCM +1F0C ; [.12CD.0020.0008.0391][.0000.0022.0002.0313][.0000.0032.0002.0301] # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA; QQCM +1F84 ; [.12CD.0020.0002.03B1][.0000.0022.0002.0313][.0000.0032.0002.0301][.0000.0097.0002.0345] # GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI; QQCM +1F8C ; [.12CD.0020.0008.0391][.0000.0022.0002.0313][.0000.0032.0002.0301][.0000.0097.0002.0345] # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI; QQCM +1F02 ; [.12CD.0020.0002.03B1][.0000.0022.0002.0313][.0000.0035.0002.0300] # GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA; QQCM +1F0A ; [.12CD.0020.0008.0391][.0000.0022.0002.0313][.0000.0035.0002.0300] # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA; QQCM +1F82 ; [.12CD.0020.0002.03B1][.0000.0022.0002.0313][.0000.0035.0002.0300][.0000.0097.0002.0345] # GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI; QQCM +1F8A ; [.12CD.0020.0008.0391][.0000.0022.0002.0313][.0000.0035.0002.0300][.0000.0097.0002.0345] # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI; QQCM +1F06 ; [.12CD.0020.0002.03B1][.0000.0022.0002.0313][.0000.0045.0002.0342] # GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI; QQCM +1F0E ; [.12CD.0020.0008.0391][.0000.0022.0002.0313][.0000.0045.0002.0342] # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI; QQCM +1F86 ; [.12CD.0020.0002.03B1][.0000.0022.0002.0313][.0000.0045.0002.0342][.0000.0097.0002.0345] # GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI; QQCM +1F8E ; [.12CD.0020.0008.0391][.0000.0022.0002.0313][.0000.0045.0002.0342][.0000.0097.0002.0345] # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI; QQCM +1F80 ; [.12CD.0020.0002.03B1][.0000.0022.0002.0313][.0000.0097.0002.0345] # GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI; QQCM +1F88 ; [.12CD.0020.0008.0391][.0000.0022.0002.0313][.0000.0097.0002.0345] # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI; QQCM +1F01 ; [.12CD.0020.0002.03B1][.0000.002A.0002.0314] # GREEK SMALL LETTER ALPHA WITH DASIA; QQCM +1F09 ; [.12CD.0020.0008.0391][.0000.002A.0002.0314] # GREEK CAPITAL LETTER ALPHA WITH DASIA; QQCM +1F05 ; [.12CD.0020.0002.03B1][.0000.002A.0002.0314][.0000.0032.0002.0301] # GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA; QQCM +1F0D ; [.12CD.0020.0008.0391][.0000.002A.0002.0314][.0000.0032.0002.0301] # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA; QQCM +1F85 ; [.12CD.0020.0002.03B1][.0000.002A.0002.0314][.0000.0032.0002.0301][.0000.0097.0002.0345] # GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI; QQCM +1F8D ; [.12CD.0020.0008.0391][.0000.002A.0002.0314][.0000.0032.0002.0301][.0000.0097.0002.0345] # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI; QQCM +1F03 ; [.12CD.0020.0002.03B1][.0000.002A.0002.0314][.0000.0035.0002.0300] # GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA; QQCM +1F0B ; [.12CD.0020.0008.0391][.0000.002A.0002.0314][.0000.0035.0002.0300] # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA; QQCM +1F83 ; [.12CD.0020.0002.03B1][.0000.002A.0002.0314][.0000.0035.0002.0300][.0000.0097.0002.0345] # GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI; QQCM +1F8B ; [.12CD.0020.0008.0391][.0000.002A.0002.0314][.0000.0035.0002.0300][.0000.0097.0002.0345] # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI; QQCM +1F07 ; [.12CD.0020.0002.03B1][.0000.002A.0002.0314][.0000.0045.0002.0342] # GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI; QQCM +1F0F ; [.12CD.0020.0008.0391][.0000.002A.0002.0314][.0000.0045.0002.0342] # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI; QQCM +1F87 ; [.12CD.0020.0002.03B1][.0000.002A.0002.0314][.0000.0045.0002.0342][.0000.0097.0002.0345] # GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI; QQCM +1F8F ; [.12CD.0020.0008.0391][.0000.002A.0002.0314][.0000.0045.0002.0342][.0000.0097.0002.0345] # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI; QQCM +1F81 ; [.12CD.0020.0002.03B1][.0000.002A.0002.0314][.0000.0097.0002.0345] # GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI; QQCM +1F89 ; [.12CD.0020.0008.0391][.0000.002A.0002.0314][.0000.0097.0002.0345] # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI; QQCM +03AC ; [.12CD.0020.0002.03B1][.0000.0032.0002.0301] # GREEK SMALL LETTER ALPHA WITH TONOS; QQCM +1F71 ; [.12CD.0020.0002.03B1][.0000.0032.0002.0301] # GREEK SMALL LETTER ALPHA WITH OXIA; QQCM +0386 ; [.12CD.0020.0008.0391][.0000.0032.0002.0301] # GREEK CAPITAL LETTER ALPHA WITH TONOS; QQCM +1FBB ; [.12CD.0020.0008.0391][.0000.0032.0002.0301] # GREEK CAPITAL LETTER ALPHA WITH OXIA; QQCM +1FB4 ; [.12CD.0020.0002.03B1][.0000.0032.0002.0301][.0000.0097.0002.0345] # GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI; QQCM +1F70 ; [.12CD.0020.0002.03B1][.0000.0035.0002.0300] # GREEK SMALL LETTER ALPHA WITH VARIA; QQCM +1FBA ; [.12CD.0020.0008.0391][.0000.0035.0002.0300] # GREEK CAPITAL LETTER ALPHA WITH VARIA; QQCM +1FB2 ; [.12CD.0020.0002.03B1][.0000.0035.0002.0300][.0000.0097.0002.0345] # GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI; QQCM +1FB0 ; [.12CD.0020.0002.03B1][.0000.0037.0002.0306] # GREEK SMALL LETTER ALPHA WITH VRACHY; QQCM +1FB8 ; [.12CD.0020.0008.0391][.0000.0037.0002.0306] # GREEK CAPITAL LETTER ALPHA WITH VRACHY; QQCM +1FB6 ; [.12CD.0020.0002.03B1][.0000.0045.0002.0342] # GREEK SMALL LETTER ALPHA WITH PERISPOMENI; QQCM +1FB7 ; [.12CD.0020.0002.03B1][.0000.0045.0002.0342][.0000.0097.0002.0345] # GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI; QQCM +1FB1 ; [.12CD.0020.0002.03B1][.0000.005B.0002.0304] # GREEK SMALL LETTER ALPHA WITH MACRON; QQCM +1FB9 ; [.12CD.0020.0008.0391][.0000.005B.0002.0304] # GREEK CAPITAL LETTER ALPHA WITH MACRON; QQCM +1FB3 ; [.12CD.0020.0002.03B1][.0000.0097.0002.0345] # GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI; QQCM +1FBC ; [.12CD.0020.0008.0391][.0000.0097.0002.0345] # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI; QQCM +03B2 ; [.12CE.0020.0002.03B2] # GREEK SMALL LETTER BETA +03D0 ; [.12CE.0020.0004.03D0] # GREEK BETA SYMBOL; QQK +1D6C3 ; [.12CE.0020.0005.1D6C3] # MATHEMATICAL BOLD SMALL BETA; QQK +1D6FD ; [.12CE.0020.0005.1D6FD] # MATHEMATICAL ITALIC SMALL BETA; QQK +1D737 ; [.12CE.0020.0005.1D737] # MATHEMATICAL BOLD ITALIC SMALL BETA; QQK +1D771 ; [.12CE.0020.0005.1D771] # MATHEMATICAL SANS-SERIF BOLD SMALL BETA; QQK +1D7AB ; [.12CE.0020.0005.1D7AB] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL BETA; QQK +0392 ; [.12CE.0020.0008.0392] # GREEK CAPITAL LETTER BETA +1D6A9 ; [.12CE.0020.000B.1D6A9] # MATHEMATICAL BOLD CAPITAL BETA; QQK +1D6E3 ; [.12CE.0020.000B.1D6E3] # MATHEMATICAL ITALIC CAPITAL BETA; QQK +1D71D ; [.12CE.0020.000B.1D71D] # MATHEMATICAL BOLD ITALIC CAPITAL BETA; QQK +1D757 ; [.12CE.0020.000B.1D757] # MATHEMATICAL SANS-SERIF BOLD CAPITAL BETA; QQK +1D791 ; [.12CE.0020.000B.1D791] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL BETA; QQK +1D5D ; [.12CE.0020.0014.1D5D] # MODIFIER LETTER SMALL BETA; QQK +1D66 ; [.12CE.0020.0015.1D66] # GREEK SUBSCRIPT SMALL LETTER BETA; QQK +03B3 ; [.12CF.0020.0002.03B3] # GREEK SMALL LETTER GAMMA +213D ; [.12CF.0020.0005.213D] # DOUBLE-STRUCK SMALL GAMMA; QQK +1D6C4 ; [.12CF.0020.0005.1D6C4] # MATHEMATICAL BOLD SMALL GAMMA; QQK +1D6FE ; [.12CF.0020.0005.1D6FE] # MATHEMATICAL ITALIC SMALL GAMMA; QQK +1D738 ; [.12CF.0020.0005.1D738] # MATHEMATICAL BOLD ITALIC SMALL GAMMA; QQK +1D772 ; [.12CF.0020.0005.1D772] # MATHEMATICAL SANS-SERIF BOLD SMALL GAMMA; QQK +1D7AC ; [.12CF.0020.0005.1D7AC] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL GAMMA; QQK +0393 ; [.12CF.0020.0008.0393] # GREEK CAPITAL LETTER GAMMA +213E ; [.12CF.0020.000B.213E] # DOUBLE-STRUCK CAPITAL GAMMA; QQK +1D6AA ; [.12CF.0020.000B.1D6AA] # MATHEMATICAL BOLD CAPITAL GAMMA; QQK +1D6E4 ; [.12CF.0020.000B.1D6E4] # MATHEMATICAL ITALIC CAPITAL GAMMA; QQK +1D71E ; [.12CF.0020.000B.1D71E] # MATHEMATICAL BOLD ITALIC CAPITAL GAMMA; QQK +1D758 ; [.12CF.0020.000B.1D758] # MATHEMATICAL SANS-SERIF BOLD CAPITAL GAMMA; QQK +1D792 ; [.12CF.0020.000B.1D792] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GAMMA; QQK +1D5E ; [.12CF.0020.0014.1D5E] # MODIFIER LETTER SMALL GREEK GAMMA; QQK +1D67 ; [.12CF.0020.0015.1D67] # GREEK SUBSCRIPT SMALL LETTER GAMMA; QQK +1D26 ; [.12D0.0020.0002.1D26] # GREEK LETTER SMALL CAPITAL GAMMA +03B4 ; [.12D1.0020.0002.03B4] # GREEK SMALL LETTER DELTA +1D6C5 ; [.12D1.0020.0005.1D6C5] # MATHEMATICAL BOLD SMALL DELTA; QQK +1D6FF ; [.12D1.0020.0005.1D6FF] # MATHEMATICAL ITALIC SMALL DELTA; QQK +1D739 ; [.12D1.0020.0005.1D739] # MATHEMATICAL BOLD ITALIC SMALL DELTA; QQK +1D773 ; [.12D1.0020.0005.1D773] # MATHEMATICAL SANS-SERIF BOLD SMALL DELTA; QQK +1D7AD ; [.12D1.0020.0005.1D7AD] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL DELTA; QQK +0394 ; [.12D1.0020.0008.0394] # GREEK CAPITAL LETTER DELTA +1D6AB ; [.12D1.0020.000B.1D6AB] # MATHEMATICAL BOLD CAPITAL DELTA; QQK +1D6E5 ; [.12D1.0020.000B.1D6E5] # MATHEMATICAL ITALIC CAPITAL DELTA; QQK +1D71F ; [.12D1.0020.000B.1D71F] # MATHEMATICAL BOLD ITALIC CAPITAL DELTA; QQK +1D759 ; [.12D1.0020.000B.1D759] # MATHEMATICAL SANS-SERIF BOLD CAPITAL DELTA; QQK +1D793 ; [.12D1.0020.000B.1D793] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL DELTA; QQK +1D5F ; [.12D1.0020.0014.1D5F] # MODIFIER LETTER SMALL DELTA; QQK +03B5 ; [.12D2.0020.0002.03B5] # GREEK SMALL LETTER EPSILON +03F5 ; [.12D2.0020.0004.03F5] # GREEK LUNATE EPSILON SYMBOL; QQK +1D6C6 ; [.12D2.0020.0005.1D6C6] # MATHEMATICAL BOLD SMALL EPSILON; QQK +1D6DC ; [.12D2.0020.0005.1D6DC] # MATHEMATICAL BOLD EPSILON SYMBOL; QQK +1D700 ; [.12D2.0020.0005.1D700] # MATHEMATICAL ITALIC SMALL EPSILON; QQK +1D716 ; [.12D2.0020.0005.1D716] # MATHEMATICAL ITALIC EPSILON SYMBOL; QQK +1D73A ; [.12D2.0020.0005.1D73A] # MATHEMATICAL BOLD ITALIC SMALL EPSILON; QQK +1D750 ; [.12D2.0020.0005.1D750] # MATHEMATICAL BOLD ITALIC EPSILON SYMBOL; QQK +1D774 ; [.12D2.0020.0005.1D774] # MATHEMATICAL SANS-SERIF BOLD SMALL EPSILON; QQK +1D78A ; [.12D2.0020.0005.1D78A] # MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL; QQK +1D7AE ; [.12D2.0020.0005.1D7AE] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL EPSILON; QQK +1D7C4 ; [.12D2.0020.0005.1D7C4] # MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL; QQK +0395 ; [.12D2.0020.0008.0395] # GREEK CAPITAL LETTER EPSILON +1D6AC ; [.12D2.0020.000B.1D6AC] # MATHEMATICAL BOLD CAPITAL EPSILON; QQK +1D6E6 ; [.12D2.0020.000B.1D6E6] # MATHEMATICAL ITALIC CAPITAL EPSILON; QQK +1D720 ; [.12D2.0020.000B.1D720] # MATHEMATICAL BOLD ITALIC CAPITAL EPSILON; QQK +1D75A ; [.12D2.0020.000B.1D75A] # MATHEMATICAL SANS-SERIF BOLD CAPITAL EPSILON; QQK +1D794 ; [.12D2.0020.000B.1D794] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EPSILON; QQK +1F10 ; [.12D2.0020.0002.03B5][.0000.0022.0002.0313] # GREEK SMALL LETTER EPSILON WITH PSILI; QQCM +1F18 ; [.12D2.0020.0008.0395][.0000.0022.0002.0313] # GREEK CAPITAL LETTER EPSILON WITH PSILI; QQCM +1F14 ; [.12D2.0020.0002.03B5][.0000.0022.0002.0313][.0000.0032.0002.0301] # GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA; QQCM +1F1C ; [.12D2.0020.0008.0395][.0000.0022.0002.0313][.0000.0032.0002.0301] # GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA; QQCM +1F12 ; [.12D2.0020.0002.03B5][.0000.0022.0002.0313][.0000.0035.0002.0300] # GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA; QQCM +1F1A ; [.12D2.0020.0008.0395][.0000.0022.0002.0313][.0000.0035.0002.0300] # GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA; QQCM +1F11 ; [.12D2.0020.0002.03B5][.0000.002A.0002.0314] # GREEK SMALL LETTER EPSILON WITH DASIA; QQCM +1F19 ; [.12D2.0020.0008.0395][.0000.002A.0002.0314] # GREEK CAPITAL LETTER EPSILON WITH DASIA; QQCM +1F15 ; [.12D2.0020.0002.03B5][.0000.002A.0002.0314][.0000.0032.0002.0301] # GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA; QQCM +1F1D ; [.12D2.0020.0008.0395][.0000.002A.0002.0314][.0000.0032.0002.0301] # GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA; QQCM +1F13 ; [.12D2.0020.0002.03B5][.0000.002A.0002.0314][.0000.0035.0002.0300] # GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA; QQCM +1F1B ; [.12D2.0020.0008.0395][.0000.002A.0002.0314][.0000.0035.0002.0300] # GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA; QQCM +03AD ; [.12D2.0020.0002.03B5][.0000.0032.0002.0301] # GREEK SMALL LETTER EPSILON WITH TONOS; QQCM +1F73 ; [.12D2.0020.0002.03B5][.0000.0032.0002.0301] # GREEK SMALL LETTER EPSILON WITH OXIA; QQCM +0388 ; [.12D2.0020.0008.0395][.0000.0032.0002.0301] # GREEK CAPITAL LETTER EPSILON WITH TONOS; QQCM +1FC9 ; [.12D2.0020.0008.0395][.0000.0032.0002.0301] # GREEK CAPITAL LETTER EPSILON WITH OXIA; QQCM +1F72 ; [.12D2.0020.0002.03B5][.0000.0035.0002.0300] # GREEK SMALL LETTER EPSILON WITH VARIA; QQCM +1FC8 ; [.12D2.0020.0008.0395][.0000.0035.0002.0300] # GREEK CAPITAL LETTER EPSILON WITH VARIA; QQCM +03DD ; [.12D3.0020.0002.03DD] # GREEK SMALL LETTER DIGAMMA +1D7CB ; [.12D3.0020.0005.1D7CB] # MATHEMATICAL BOLD SMALL DIGAMMA; QQK +03DC ; [.12D3.0020.0008.03DC] # GREEK LETTER DIGAMMA +1D7CA ; [.12D3.0020.000B.1D7CA] # MATHEMATICAL BOLD CAPITAL DIGAMMA; QQK +03DB ; [.12D4.0020.0002.03DB] # GREEK SMALL LETTER STIGMA +03DA ; [.12D4.0020.0008.03DA] # GREEK LETTER STIGMA +03B6 ; [.12D5.0020.0002.03B6] # GREEK SMALL LETTER ZETA +1D6C7 ; [.12D5.0020.0005.1D6C7] # MATHEMATICAL BOLD SMALL ZETA; QQK +1D701 ; [.12D5.0020.0005.1D701] # MATHEMATICAL ITALIC SMALL ZETA; QQK +1D73B ; [.12D5.0020.0005.1D73B] # MATHEMATICAL BOLD ITALIC SMALL ZETA; QQK +1D775 ; [.12D5.0020.0005.1D775] # MATHEMATICAL SANS-SERIF BOLD SMALL ZETA; QQK +1D7AF ; [.12D5.0020.0005.1D7AF] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ZETA; QQK +0396 ; [.12D5.0020.0008.0396] # GREEK CAPITAL LETTER ZETA +1D6AD ; [.12D5.0020.000B.1D6AD] # MATHEMATICAL BOLD CAPITAL ZETA; QQK +1D6E7 ; [.12D5.0020.000B.1D6E7] # MATHEMATICAL ITALIC CAPITAL ZETA; QQK +1D721 ; [.12D5.0020.000B.1D721] # MATHEMATICAL BOLD ITALIC CAPITAL ZETA; QQK +1D75B ; [.12D5.0020.000B.1D75B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL ZETA; QQK +1D795 ; [.12D5.0020.000B.1D795] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ZETA; QQK +03B7 ; [.12D6.0020.0002.03B7] # GREEK SMALL LETTER ETA +1D6C8 ; [.12D6.0020.0005.1D6C8] # MATHEMATICAL BOLD SMALL ETA; QQK +1D702 ; [.12D6.0020.0005.1D702] # MATHEMATICAL ITALIC SMALL ETA; QQK +1D73C ; [.12D6.0020.0005.1D73C] # MATHEMATICAL BOLD ITALIC SMALL ETA; QQK +1D776 ; [.12D6.0020.0005.1D776] # MATHEMATICAL SANS-SERIF BOLD SMALL ETA; QQK +1D7B0 ; [.12D6.0020.0005.1D7B0] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ETA; QQK +0397 ; [.12D6.0020.0008.0397] # GREEK CAPITAL LETTER ETA +1D6AE ; [.12D6.0020.000B.1D6AE] # MATHEMATICAL BOLD CAPITAL ETA; QQK +1D6E8 ; [.12D6.0020.000B.1D6E8] # MATHEMATICAL ITALIC CAPITAL ETA; QQK +1D722 ; [.12D6.0020.000B.1D722] # MATHEMATICAL BOLD ITALIC CAPITAL ETA; QQK +1D75C ; [.12D6.0020.000B.1D75C] # MATHEMATICAL SANS-SERIF BOLD CAPITAL ETA; QQK +1D796 ; [.12D6.0020.000B.1D796] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ETA; QQK +1F20 ; [.12D6.0020.0002.03B7][.0000.0022.0002.0313] # GREEK SMALL LETTER ETA WITH PSILI; QQCM +1F28 ; [.12D6.0020.0008.0397][.0000.0022.0002.0313] # GREEK CAPITAL LETTER ETA WITH PSILI; QQCM +1F24 ; [.12D6.0020.0002.03B7][.0000.0022.0002.0313][.0000.0032.0002.0301] # GREEK SMALL LETTER ETA WITH PSILI AND OXIA; QQCM +1F2C ; [.12D6.0020.0008.0397][.0000.0022.0002.0313][.0000.0032.0002.0301] # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA; QQCM +1F94 ; [.12D6.0020.0002.03B7][.0000.0022.0002.0313][.0000.0032.0002.0301][.0000.0097.0002.0345] # GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI; QQCM +1F9C ; [.12D6.0020.0008.0397][.0000.0022.0002.0313][.0000.0032.0002.0301][.0000.0097.0002.0345] # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI; QQCM +1F22 ; [.12D6.0020.0002.03B7][.0000.0022.0002.0313][.0000.0035.0002.0300] # GREEK SMALL LETTER ETA WITH PSILI AND VARIA; QQCM +1F2A ; [.12D6.0020.0008.0397][.0000.0022.0002.0313][.0000.0035.0002.0300] # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA; QQCM +1F92 ; [.12D6.0020.0002.03B7][.0000.0022.0002.0313][.0000.0035.0002.0300][.0000.0097.0002.0345] # GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI; QQCM +1F9A ; [.12D6.0020.0008.0397][.0000.0022.0002.0313][.0000.0035.0002.0300][.0000.0097.0002.0345] # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI; QQCM +1F26 ; [.12D6.0020.0002.03B7][.0000.0022.0002.0313][.0000.0045.0002.0342] # GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI; QQCM +1F2E ; [.12D6.0020.0008.0397][.0000.0022.0002.0313][.0000.0045.0002.0342] # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI; QQCM +1F96 ; [.12D6.0020.0002.03B7][.0000.0022.0002.0313][.0000.0045.0002.0342][.0000.0097.0002.0345] # GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI; QQCM +1F9E ; [.12D6.0020.0008.0397][.0000.0022.0002.0313][.0000.0045.0002.0342][.0000.0097.0002.0345] # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI; QQCM +1F90 ; [.12D6.0020.0002.03B7][.0000.0022.0002.0313][.0000.0097.0002.0345] # GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI; QQCM +1F98 ; [.12D6.0020.0008.0397][.0000.0022.0002.0313][.0000.0097.0002.0345] # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI; QQCM +1F21 ; [.12D6.0020.0002.03B7][.0000.002A.0002.0314] # GREEK SMALL LETTER ETA WITH DASIA; QQCM +1F29 ; [.12D6.0020.0008.0397][.0000.002A.0002.0314] # GREEK CAPITAL LETTER ETA WITH DASIA; QQCM +1F25 ; [.12D6.0020.0002.03B7][.0000.002A.0002.0314][.0000.0032.0002.0301] # GREEK SMALL LETTER ETA WITH DASIA AND OXIA; QQCM +1F2D ; [.12D6.0020.0008.0397][.0000.002A.0002.0314][.0000.0032.0002.0301] # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA; QQCM +1F95 ; [.12D6.0020.0002.03B7][.0000.002A.0002.0314][.0000.0032.0002.0301][.0000.0097.0002.0345] # GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI; QQCM +1F9D ; [.12D6.0020.0008.0397][.0000.002A.0002.0314][.0000.0032.0002.0301][.0000.0097.0002.0345] # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI; QQCM +1F23 ; [.12D6.0020.0002.03B7][.0000.002A.0002.0314][.0000.0035.0002.0300] # GREEK SMALL LETTER ETA WITH DASIA AND VARIA; QQCM +1F2B ; [.12D6.0020.0008.0397][.0000.002A.0002.0314][.0000.0035.0002.0300] # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA; QQCM +1F93 ; [.12D6.0020.0002.03B7][.0000.002A.0002.0314][.0000.0035.0002.0300][.0000.0097.0002.0345] # GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI; QQCM +1F9B ; [.12D6.0020.0008.0397][.0000.002A.0002.0314][.0000.0035.0002.0300][.0000.0097.0002.0345] # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI; QQCM +1F27 ; [.12D6.0020.0002.03B7][.0000.002A.0002.0314][.0000.0045.0002.0342] # GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI; QQCM +1F2F ; [.12D6.0020.0008.0397][.0000.002A.0002.0314][.0000.0045.0002.0342] # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI; QQCM +1F97 ; [.12D6.0020.0002.03B7][.0000.002A.0002.0314][.0000.0045.0002.0342][.0000.0097.0002.0345] # GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI; QQCM +1F9F ; [.12D6.0020.0008.0397][.0000.002A.0002.0314][.0000.0045.0002.0342][.0000.0097.0002.0345] # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI; QQCM +1F91 ; [.12D6.0020.0002.03B7][.0000.002A.0002.0314][.0000.0097.0002.0345] # GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI; QQCM +1F99 ; [.12D6.0020.0008.0397][.0000.002A.0002.0314][.0000.0097.0002.0345] # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI; QQCM +03AE ; [.12D6.0020.0002.03B7][.0000.0032.0002.0301] # GREEK SMALL LETTER ETA WITH TONOS; QQCM +1F75 ; [.12D6.0020.0002.03B7][.0000.0032.0002.0301] # GREEK SMALL LETTER ETA WITH OXIA; QQCM +0389 ; [.12D6.0020.0008.0397][.0000.0032.0002.0301] # GREEK CAPITAL LETTER ETA WITH TONOS; QQCM +1FCB ; [.12D6.0020.0008.0397][.0000.0032.0002.0301] # GREEK CAPITAL LETTER ETA WITH OXIA; QQCM +1FC4 ; [.12D6.0020.0002.03B7][.0000.0032.0002.0301][.0000.0097.0002.0345] # GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI; QQCM +1F74 ; [.12D6.0020.0002.03B7][.0000.0035.0002.0300] # GREEK SMALL LETTER ETA WITH VARIA; QQCM +1FCA ; [.12D6.0020.0008.0397][.0000.0035.0002.0300] # GREEK CAPITAL LETTER ETA WITH VARIA; QQCM +1FC2 ; [.12D6.0020.0002.03B7][.0000.0035.0002.0300][.0000.0097.0002.0345] # GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI; QQCM +1FC6 ; [.12D6.0020.0002.03B7][.0000.0045.0002.0342] # GREEK SMALL LETTER ETA WITH PERISPOMENI; QQCM +1FC7 ; [.12D6.0020.0002.03B7][.0000.0045.0002.0342][.0000.0097.0002.0345] # GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI; QQCM +1FC3 ; [.12D6.0020.0002.03B7][.0000.0097.0002.0345] # GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI; QQCM +1FCC ; [.12D6.0020.0008.0397][.0000.0097.0002.0345] # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI; QQCM +03B8 ; [.12D7.0020.0002.03B8] # GREEK SMALL LETTER THETA +03D1 ; [.12D7.0020.0004.03D1] # GREEK THETA SYMBOL; QQK +1D6C9 ; [.12D7.0020.0005.1D6C9] # MATHEMATICAL BOLD SMALL THETA; QQK +1D6DD ; [.12D7.0020.0005.1D6DD] # MATHEMATICAL BOLD THETA SYMBOL; QQK +1D703 ; [.12D7.0020.0005.1D703] # MATHEMATICAL ITALIC SMALL THETA; QQK +1D717 ; [.12D7.0020.0005.1D717] # MATHEMATICAL ITALIC THETA SYMBOL; QQK +1D73D ; [.12D7.0020.0005.1D73D] # MATHEMATICAL BOLD ITALIC SMALL THETA; QQK +1D751 ; [.12D7.0020.0005.1D751] # MATHEMATICAL BOLD ITALIC THETA SYMBOL; QQK +1D777 ; [.12D7.0020.0005.1D777] # MATHEMATICAL SANS-SERIF BOLD SMALL THETA; QQK +1D78B ; [.12D7.0020.0005.1D78B] # MATHEMATICAL SANS-SERIF BOLD THETA SYMBOL; QQK +1D7B1 ; [.12D7.0020.0005.1D7B1] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL THETA; QQK +1D7C5 ; [.12D7.0020.0005.1D7C5] # MATHEMATICAL SANS-SERIF BOLD ITALIC THETA SYMBOL; QQK +0398 ; [.12D7.0020.0008.0398] # GREEK CAPITAL LETTER THETA +03F4 ; [.12D7.0020.000A.03F4] # GREEK CAPITAL THETA SYMBOL; QQK +1D6AF ; [.12D7.0020.000B.1D6AF] # MATHEMATICAL BOLD CAPITAL THETA; QQK +1D6B9 ; [.12D7.0020.000B.1D6B9] # MATHEMATICAL BOLD CAPITAL THETA SYMBOL; QQK +1D6E9 ; [.12D7.0020.000B.1D6E9] # MATHEMATICAL ITALIC CAPITAL THETA; QQK +1D6F3 ; [.12D7.0020.000B.1D6F3] # MATHEMATICAL ITALIC CAPITAL THETA SYMBOL; QQK +1D723 ; [.12D7.0020.000B.1D723] # MATHEMATICAL BOLD ITALIC CAPITAL THETA; QQK +1D72D ; [.12D7.0020.000B.1D72D] # MATHEMATICAL BOLD ITALIC CAPITAL THETA SYMBOL; QQK +1D75D ; [.12D7.0020.000B.1D75D] # MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA; QQK +1D767 ; [.12D7.0020.000B.1D767] # MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA SYMBOL; QQK +1D797 ; [.12D7.0020.000B.1D797] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA; QQK +1D7A1 ; [.12D7.0020.000B.1D7A1] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA SYMBOL; QQK +1DBF ; [.12D7.0020.0014.1DBF] # MODIFIER LETTER SMALL THETA; QQK +03B9 ; [.12D8.0020.0002.03B9] # GREEK SMALL LETTER IOTA +1FBE ; [.12D8.0020.0002.1FBE] # GREEK PROSGEGRAMMENI; QQC +037A ; [.12D8.0020.0004.037A] # GREEK YPOGEGRAMMENI; QQK +1D6CA ; [.12D8.0020.0005.1D6CA] # MATHEMATICAL BOLD SMALL IOTA; QQK +1D704 ; [.12D8.0020.0005.1D704] # MATHEMATICAL ITALIC SMALL IOTA; QQK +1D73E ; [.12D8.0020.0005.1D73E] # MATHEMATICAL BOLD ITALIC SMALL IOTA; QQK +1D778 ; [.12D8.0020.0005.1D778] # MATHEMATICAL SANS-SERIF BOLD SMALL IOTA; QQK +1D7B2 ; [.12D8.0020.0005.1D7B2] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL IOTA; QQK +0399 ; [.12D8.0020.0008.0399] # GREEK CAPITAL LETTER IOTA +1D6B0 ; [.12D8.0020.000B.1D6B0] # MATHEMATICAL BOLD CAPITAL IOTA; QQK +1D6EA ; [.12D8.0020.000B.1D6EA] # MATHEMATICAL ITALIC CAPITAL IOTA; QQK +1D724 ; [.12D8.0020.000B.1D724] # MATHEMATICAL BOLD ITALIC CAPITAL IOTA; QQK +1D75E ; [.12D8.0020.000B.1D75E] # MATHEMATICAL SANS-SERIF BOLD CAPITAL IOTA; QQK +1D798 ; [.12D8.0020.000B.1D798] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IOTA; QQK +1F30 ; [.12D8.0020.0002.03B9][.0000.0022.0002.0313] # GREEK SMALL LETTER IOTA WITH PSILI; QQCM +1F38 ; [.12D8.0020.0008.0399][.0000.0022.0002.0313] # GREEK CAPITAL LETTER IOTA WITH PSILI; QQCM +1F34 ; [.12D8.0020.0002.03B9][.0000.0022.0002.0313][.0000.0032.0002.0301] # GREEK SMALL LETTER IOTA WITH PSILI AND OXIA; QQCM +1F3C ; [.12D8.0020.0008.0399][.0000.0022.0002.0313][.0000.0032.0002.0301] # GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA; QQCM +1F32 ; [.12D8.0020.0002.03B9][.0000.0022.0002.0313][.0000.0035.0002.0300] # GREEK SMALL LETTER IOTA WITH PSILI AND VARIA; QQCM +1F3A ; [.12D8.0020.0008.0399][.0000.0022.0002.0313][.0000.0035.0002.0300] # GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA; QQCM +1F36 ; [.12D8.0020.0002.03B9][.0000.0022.0002.0313][.0000.0045.0002.0342] # GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI; QQCM +1F3E ; [.12D8.0020.0008.0399][.0000.0022.0002.0313][.0000.0045.0002.0342] # GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI; QQCM +1F31 ; [.12D8.0020.0002.03B9][.0000.002A.0002.0314] # GREEK SMALL LETTER IOTA WITH DASIA; QQCM +1F39 ; [.12D8.0020.0008.0399][.0000.002A.0002.0314] # GREEK CAPITAL LETTER IOTA WITH DASIA; QQCM +1F35 ; [.12D8.0020.0002.03B9][.0000.002A.0002.0314][.0000.0032.0002.0301] # GREEK SMALL LETTER IOTA WITH DASIA AND OXIA; QQCM +1F3D ; [.12D8.0020.0008.0399][.0000.002A.0002.0314][.0000.0032.0002.0301] # GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA; QQCM +1F33 ; [.12D8.0020.0002.03B9][.0000.002A.0002.0314][.0000.0035.0002.0300] # GREEK SMALL LETTER IOTA WITH DASIA AND VARIA; QQCM +1F3B ; [.12D8.0020.0008.0399][.0000.002A.0002.0314][.0000.0035.0002.0300] # GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA; QQCM +1F37 ; [.12D8.0020.0002.03B9][.0000.002A.0002.0314][.0000.0045.0002.0342] # GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI; QQCM +1F3F ; [.12D8.0020.0008.0399][.0000.002A.0002.0314][.0000.0045.0002.0342] # GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI; QQCM +03AF ; [.12D8.0020.0002.03B9][.0000.0032.0002.0301] # GREEK SMALL LETTER IOTA WITH TONOS; QQCM +1F77 ; [.12D8.0020.0002.03B9][.0000.0032.0002.0301] # GREEK SMALL LETTER IOTA WITH OXIA; QQCM +038A ; [.12D8.0020.0008.0399][.0000.0032.0002.0301] # GREEK CAPITAL LETTER IOTA WITH TONOS; QQCM +1FDB ; [.12D8.0020.0008.0399][.0000.0032.0002.0301] # GREEK CAPITAL LETTER IOTA WITH OXIA; QQCM +1F76 ; [.12D8.0020.0002.03B9][.0000.0035.0002.0300] # GREEK SMALL LETTER IOTA WITH VARIA; QQCM +1FDA ; [.12D8.0020.0008.0399][.0000.0035.0002.0300] # GREEK CAPITAL LETTER IOTA WITH VARIA; QQCM +1FD0 ; [.12D8.0020.0002.03B9][.0000.0037.0002.0306] # GREEK SMALL LETTER IOTA WITH VRACHY; QQCM +1FD8 ; [.12D8.0020.0008.0399][.0000.0037.0002.0306] # GREEK CAPITAL LETTER IOTA WITH VRACHY; QQCM +1FD6 ; [.12D8.0020.0002.03B9][.0000.0045.0002.0342] # GREEK SMALL LETTER IOTA WITH PERISPOMENI; QQCM +03CA ; [.12D8.0020.0002.03B9][.0000.0047.0002.0308] # GREEK SMALL LETTER IOTA WITH DIALYTIKA; QQCM +03AA ; [.12D8.0020.0008.0399][.0000.0047.0002.0308] # GREEK CAPITAL LETTER IOTA WITH DIALYTIKA; QQCM +0390 ; [.12D8.0020.0002.03B9][.0000.0047.0002.0308][.0000.0032.0002.0301] # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS; QQCM +1FD3 ; [.12D8.0020.0002.03B9][.0000.0047.0002.0308][.0000.0032.0002.0301] # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA; QQCM +1FD2 ; [.12D8.0020.0002.03B9][.0000.0047.0002.0308][.0000.0035.0002.0300] # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA; QQCM +1FD7 ; [.12D8.0020.0002.03B9][.0000.0047.0002.0308][.0000.0045.0002.0342] # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI; QQCM +1FD1 ; [.12D8.0020.0002.03B9][.0000.005B.0002.0304] # GREEK SMALL LETTER IOTA WITH MACRON; QQCM +1FD9 ; [.12D8.0020.0008.0399][.0000.005B.0002.0304] # GREEK CAPITAL LETTER IOTA WITH MACRON; QQCM +03F3 ; [.12D9.0020.0002.03F3] # GREEK LETTER YOT +03BA ; [.12DA.0020.0002.03BA] # GREEK SMALL LETTER KAPPA +03F0 ; [.12DA.0020.0004.03F0] # GREEK KAPPA SYMBOL; QQK +1D6CB ; [.12DA.0020.0005.1D6CB] # MATHEMATICAL BOLD SMALL KAPPA; QQK +1D6DE ; [.12DA.0020.0005.1D6DE] # MATHEMATICAL BOLD KAPPA SYMBOL; QQK +1D705 ; [.12DA.0020.0005.1D705] # MATHEMATICAL ITALIC SMALL KAPPA; QQK +1D718 ; [.12DA.0020.0005.1D718] # MATHEMATICAL ITALIC KAPPA SYMBOL; QQK +1D73F ; [.12DA.0020.0005.1D73F] # MATHEMATICAL BOLD ITALIC SMALL KAPPA; QQK +1D752 ; [.12DA.0020.0005.1D752] # MATHEMATICAL BOLD ITALIC KAPPA SYMBOL; QQK +1D779 ; [.12DA.0020.0005.1D779] # MATHEMATICAL SANS-SERIF BOLD SMALL KAPPA; QQK +1D78C ; [.12DA.0020.0005.1D78C] # MATHEMATICAL SANS-SERIF BOLD KAPPA SYMBOL; QQK +1D7B3 ; [.12DA.0020.0005.1D7B3] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL KAPPA; QQK +1D7C6 ; [.12DA.0020.0005.1D7C6] # MATHEMATICAL SANS-SERIF BOLD ITALIC KAPPA SYMBOL; QQK +039A ; [.12DA.0020.0008.039A] # GREEK CAPITAL LETTER KAPPA +1D6B1 ; [.12DA.0020.000B.1D6B1] # MATHEMATICAL BOLD CAPITAL KAPPA; QQK +1D6EB ; [.12DA.0020.000B.1D6EB] # MATHEMATICAL ITALIC CAPITAL KAPPA; QQK +1D725 ; [.12DA.0020.000B.1D725] # MATHEMATICAL BOLD ITALIC CAPITAL KAPPA; QQK +1D75F ; [.12DA.0020.000B.1D75F] # MATHEMATICAL SANS-SERIF BOLD CAPITAL KAPPA; QQK +1D799 ; [.12DA.0020.000B.1D799] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL KAPPA; QQK +03D7 ; [.12DA.0020.0004.03D7][.12CD.0020.0004.03D7][.12D8.0020.001F.03D7] # GREEK KAI SYMBOL; QQKN +03BB ; [.12DB.0020.0002.03BB] # GREEK SMALL LETTER LAMDA +1D6CC ; [.12DB.0020.0005.1D6CC] # MATHEMATICAL BOLD SMALL LAMDA; QQK +1D706 ; [.12DB.0020.0005.1D706] # MATHEMATICAL ITALIC SMALL LAMDA; QQK +1D740 ; [.12DB.0020.0005.1D740] # MATHEMATICAL BOLD ITALIC SMALL LAMDA; QQK +1D77A ; [.12DB.0020.0005.1D77A] # MATHEMATICAL SANS-SERIF BOLD SMALL LAMDA; QQK +1D7B4 ; [.12DB.0020.0005.1D7B4] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL LAMDA; QQK +039B ; [.12DB.0020.0008.039B] # GREEK CAPITAL LETTER LAMDA +1D6B2 ; [.12DB.0020.000B.1D6B2] # MATHEMATICAL BOLD CAPITAL LAMDA; QQK +1D6EC ; [.12DB.0020.000B.1D6EC] # MATHEMATICAL ITALIC CAPITAL LAMDA; QQK +1D726 ; [.12DB.0020.000B.1D726] # MATHEMATICAL BOLD ITALIC CAPITAL LAMDA; QQK +1D760 ; [.12DB.0020.000B.1D760] # MATHEMATICAL SANS-SERIF BOLD CAPITAL LAMDA; QQK +1D79A ; [.12DB.0020.000B.1D79A] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LAMDA; QQK +1D27 ; [.12DC.0020.0002.1D27] # GREEK LETTER SMALL CAPITAL LAMDA +03BC ; [.12DD.0020.0002.03BC] # GREEK SMALL LETTER MU +00B5 ; [.12DD.0020.0004.00B5] # MICRO SIGN; QQK +1D6CD ; [.12DD.0020.0005.1D6CD] # MATHEMATICAL BOLD SMALL MU; QQK +1D707 ; [.12DD.0020.0005.1D707] # MATHEMATICAL ITALIC SMALL MU; QQK +1D741 ; [.12DD.0020.0005.1D741] # MATHEMATICAL BOLD ITALIC SMALL MU; QQK +1D77B ; [.12DD.0020.0005.1D77B] # MATHEMATICAL SANS-SERIF BOLD SMALL MU; QQK +1D7B5 ; [.12DD.0020.0005.1D7B5] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL MU; QQK +039C ; [.12DD.0020.0008.039C] # GREEK CAPITAL LETTER MU +1D6B3 ; [.12DD.0020.000B.1D6B3] # MATHEMATICAL BOLD CAPITAL MU; QQK +1D6ED ; [.12DD.0020.000B.1D6ED] # MATHEMATICAL ITALIC CAPITAL MU; QQK +1D727 ; [.12DD.0020.000B.1D727] # MATHEMATICAL BOLD ITALIC CAPITAL MU; QQK +1D761 ; [.12DD.0020.000B.1D761] # MATHEMATICAL SANS-SERIF BOLD CAPITAL MU; QQK +1D79B ; [.12DD.0020.000B.1D79B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MU; QQK +3382 ; [.12DD.0020.001C.3382][.0FD0.0020.001D.3382] # SQUARE MU A; QQKN +338C ; [.12DD.0020.001C.338C][.105F.0020.001D.338C] # SQUARE MU F; QQKN +338D ; [.12DD.0020.001C.338D][.106A.0020.001C.338D] # SQUARE MU G; QQKN +3395 ; [.12DD.0020.001C.3395][.10E5.0020.001C.3395] # SQUARE MU L; QQKN +339B ; [.12DD.0020.001C.339B][.1110.0020.001C.339B] # SQUARE MU M; QQKN +33B2 ; [.12DD.0020.001C.33B2][.11AF.0020.001C.33B2] # SQUARE MU S; QQKN +33B6 ; [.12DD.0020.001C.33B6][.1216.0020.001D.33B6] # SQUARE MU V; QQKN +33BC ; [.12DD.0020.001C.33BC][.1225.0020.001D.33BC] # SQUARE MU W; QQKN +03BD ; [.12DE.0020.0002.03BD] # GREEK SMALL LETTER NU +1D6CE ; [.12DE.0020.0005.1D6CE] # MATHEMATICAL BOLD SMALL NU; QQK +1D708 ; [.12DE.0020.0005.1D708] # MATHEMATICAL ITALIC SMALL NU; QQK +1D742 ; [.12DE.0020.0005.1D742] # MATHEMATICAL BOLD ITALIC SMALL NU; QQK +1D77C ; [.12DE.0020.0005.1D77C] # MATHEMATICAL SANS-SERIF BOLD SMALL NU; QQK +1D7B6 ; [.12DE.0020.0005.1D7B6] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL NU; QQK +039D ; [.12DE.0020.0008.039D] # GREEK CAPITAL LETTER NU +1D6B4 ; [.12DE.0020.000B.1D6B4] # MATHEMATICAL BOLD CAPITAL NU; QQK +1D6EE ; [.12DE.0020.000B.1D6EE] # MATHEMATICAL ITALIC CAPITAL NU; QQK +1D728 ; [.12DE.0020.000B.1D728] # MATHEMATICAL BOLD ITALIC CAPITAL NU; QQK +1D762 ; [.12DE.0020.000B.1D762] # MATHEMATICAL SANS-SERIF BOLD CAPITAL NU; QQK +1D79C ; [.12DE.0020.000B.1D79C] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL NU; QQK +03BE ; [.12DF.0020.0002.03BE] # GREEK SMALL LETTER XI +1D6CF ; [.12DF.0020.0005.1D6CF] # MATHEMATICAL BOLD SMALL XI; QQK +1D709 ; [.12DF.0020.0005.1D709] # MATHEMATICAL ITALIC SMALL XI; QQK +1D743 ; [.12DF.0020.0005.1D743] # MATHEMATICAL BOLD ITALIC SMALL XI; QQK +1D77D ; [.12DF.0020.0005.1D77D] # MATHEMATICAL SANS-SERIF BOLD SMALL XI; QQK +1D7B7 ; [.12DF.0020.0005.1D7B7] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL XI; QQK +039E ; [.12DF.0020.0008.039E] # GREEK CAPITAL LETTER XI +1D6B5 ; [.12DF.0020.000B.1D6B5] # MATHEMATICAL BOLD CAPITAL XI; QQK +1D6EF ; [.12DF.0020.000B.1D6EF] # MATHEMATICAL ITALIC CAPITAL XI; QQK +1D729 ; [.12DF.0020.000B.1D729] # MATHEMATICAL BOLD ITALIC CAPITAL XI; QQK +1D763 ; [.12DF.0020.000B.1D763] # MATHEMATICAL SANS-SERIF BOLD CAPITAL XI; QQK +1D79D ; [.12DF.0020.000B.1D79D] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XI; QQK +03BF ; [.12E0.0020.0002.03BF] # GREEK SMALL LETTER OMICRON +1D6D0 ; [.12E0.0020.0005.1D6D0] # MATHEMATICAL BOLD SMALL OMICRON; QQK +1D70A ; [.12E0.0020.0005.1D70A] # MATHEMATICAL ITALIC SMALL OMICRON; QQK +1D744 ; [.12E0.0020.0005.1D744] # MATHEMATICAL BOLD ITALIC SMALL OMICRON; QQK +1D77E ; [.12E0.0020.0005.1D77E] # MATHEMATICAL SANS-SERIF BOLD SMALL OMICRON; QQK +1D7B8 ; [.12E0.0020.0005.1D7B8] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMICRON; QQK +039F ; [.12E0.0020.0008.039F] # GREEK CAPITAL LETTER OMICRON +1D6B6 ; [.12E0.0020.000B.1D6B6] # MATHEMATICAL BOLD CAPITAL OMICRON; QQK +1D6F0 ; [.12E0.0020.000B.1D6F0] # MATHEMATICAL ITALIC CAPITAL OMICRON; QQK +1D72A ; [.12E0.0020.000B.1D72A] # MATHEMATICAL BOLD ITALIC CAPITAL OMICRON; QQK +1D764 ; [.12E0.0020.000B.1D764] # MATHEMATICAL SANS-SERIF BOLD CAPITAL OMICRON; QQK +1D79E ; [.12E0.0020.000B.1D79E] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMICRON; QQK +1F40 ; [.12E0.0020.0002.03BF][.0000.0022.0002.0313] # GREEK SMALL LETTER OMICRON WITH PSILI; QQCM +1F48 ; [.12E0.0020.0008.039F][.0000.0022.0002.0313] # GREEK CAPITAL LETTER OMICRON WITH PSILI; QQCM +1F44 ; [.12E0.0020.0002.03BF][.0000.0022.0002.0313][.0000.0032.0002.0301] # GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA; QQCM +1F4C ; [.12E0.0020.0008.039F][.0000.0022.0002.0313][.0000.0032.0002.0301] # GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA; QQCM +1F42 ; [.12E0.0020.0002.03BF][.0000.0022.0002.0313][.0000.0035.0002.0300] # GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA; QQCM +1F4A ; [.12E0.0020.0008.039F][.0000.0022.0002.0313][.0000.0035.0002.0300] # GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA; QQCM +1F41 ; [.12E0.0020.0002.03BF][.0000.002A.0002.0314] # GREEK SMALL LETTER OMICRON WITH DASIA; QQCM +1F49 ; [.12E0.0020.0008.039F][.0000.002A.0002.0314] # GREEK CAPITAL LETTER OMICRON WITH DASIA; QQCM +1F45 ; [.12E0.0020.0002.03BF][.0000.002A.0002.0314][.0000.0032.0002.0301] # GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA; QQCM +1F4D ; [.12E0.0020.0008.039F][.0000.002A.0002.0314][.0000.0032.0002.0301] # GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA; QQCM +1F43 ; [.12E0.0020.0002.03BF][.0000.002A.0002.0314][.0000.0035.0002.0300] # GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA; QQCM +1F4B ; [.12E0.0020.0008.039F][.0000.002A.0002.0314][.0000.0035.0002.0300] # GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA; QQCM +03CC ; [.12E0.0020.0002.03BF][.0000.0032.0002.0301] # GREEK SMALL LETTER OMICRON WITH TONOS; QQCM +1F79 ; [.12E0.0020.0002.03BF][.0000.0032.0002.0301] # GREEK SMALL LETTER OMICRON WITH OXIA; QQCM +038C ; [.12E0.0020.0008.039F][.0000.0032.0002.0301] # GREEK CAPITAL LETTER OMICRON WITH TONOS; QQCM +1FF9 ; [.12E0.0020.0008.039F][.0000.0032.0002.0301] # GREEK CAPITAL LETTER OMICRON WITH OXIA; QQCM +1F78 ; [.12E0.0020.0002.03BF][.0000.0035.0002.0300] # GREEK SMALL LETTER OMICRON WITH VARIA; QQCM +1FF8 ; [.12E0.0020.0008.039F][.0000.0035.0002.0300] # GREEK CAPITAL LETTER OMICRON WITH VARIA; QQCM +03C0 ; [.12E1.0020.0002.03C0] # GREEK SMALL LETTER PI +03D6 ; [.12E1.0020.0004.03D6] # GREEK PI SYMBOL; QQK +213C ; [.12E1.0020.0005.213C] # DOUBLE-STRUCK SMALL PI; QQK +1D6D1 ; [.12E1.0020.0005.1D6D1] # MATHEMATICAL BOLD SMALL PI; QQK +1D6E1 ; [.12E1.0020.0005.1D6E1] # MATHEMATICAL BOLD PI SYMBOL; QQK +1D70B ; [.12E1.0020.0005.1D70B] # MATHEMATICAL ITALIC SMALL PI; QQK +1D71B ; [.12E1.0020.0005.1D71B] # MATHEMATICAL ITALIC PI SYMBOL; QQK +1D745 ; [.12E1.0020.0005.1D745] # MATHEMATICAL BOLD ITALIC SMALL PI; QQK +1D755 ; [.12E1.0020.0005.1D755] # MATHEMATICAL BOLD ITALIC PI SYMBOL; QQK +1D77F ; [.12E1.0020.0005.1D77F] # MATHEMATICAL SANS-SERIF BOLD SMALL PI; QQK +1D78F ; [.12E1.0020.0005.1D78F] # MATHEMATICAL SANS-SERIF BOLD PI SYMBOL; QQK +1D7B9 ; [.12E1.0020.0005.1D7B9] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PI; QQK +1D7C9 ; [.12E1.0020.0005.1D7C9] # MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL; QQK +03A0 ; [.12E1.0020.0008.03A0] # GREEK CAPITAL LETTER PI +213F ; [.12E1.0020.000B.213F] # DOUBLE-STRUCK CAPITAL PI; QQK +1D6B7 ; [.12E1.0020.000B.1D6B7] # MATHEMATICAL BOLD CAPITAL PI; QQK +1D6F1 ; [.12E1.0020.000B.1D6F1] # MATHEMATICAL ITALIC CAPITAL PI; QQK +1D72B ; [.12E1.0020.000B.1D72B] # MATHEMATICAL BOLD ITALIC CAPITAL PI; QQK +1D765 ; [.12E1.0020.000B.1D765] # MATHEMATICAL SANS-SERIF BOLD CAPITAL PI; QQK +1D79F ; [.12E1.0020.000B.1D79F] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PI; QQK +1D28 ; [.12E2.0020.0002.1D28] # GREEK LETTER SMALL CAPITAL PI +03FB ; [.12E3.0020.0002.03FB] # GREEK SMALL LETTER SAN +03FA ; [.12E3.0020.0008.03FA] # GREEK CAPITAL LETTER SAN +03DF ; [.12E4.0020.0002.03DF] # GREEK SMALL LETTER KOPPA +03DE ; [.12E4.0020.0008.03DE] # GREEK LETTER KOPPA +03D9 ; [.12E5.0020.0002.03D9] # GREEK SMALL LETTER ARCHAIC KOPPA +03D8 ; [.12E5.0020.0008.03D8] # GREEK LETTER ARCHAIC KOPPA +03C1 ; [.12E6.0020.0002.03C1] # GREEK SMALL LETTER RHO +03F1 ; [.12E6.0020.0004.03F1] # GREEK RHO SYMBOL; QQK +1D6D2 ; [.12E6.0020.0005.1D6D2] # MATHEMATICAL BOLD SMALL RHO; QQK +1D6E0 ; [.12E6.0020.0005.1D6E0] # MATHEMATICAL BOLD RHO SYMBOL; QQK +1D70C ; [.12E6.0020.0005.1D70C] # MATHEMATICAL ITALIC SMALL RHO; QQK +1D71A ; [.12E6.0020.0005.1D71A] # MATHEMATICAL ITALIC RHO SYMBOL; QQK +1D746 ; [.12E6.0020.0005.1D746] # MATHEMATICAL BOLD ITALIC SMALL RHO; QQK +1D754 ; [.12E6.0020.0005.1D754] # MATHEMATICAL BOLD ITALIC RHO SYMBOL; QQK +1D780 ; [.12E6.0020.0005.1D780] # MATHEMATICAL SANS-SERIF BOLD SMALL RHO; QQK +1D78E ; [.12E6.0020.0005.1D78E] # MATHEMATICAL SANS-SERIF BOLD RHO SYMBOL; QQK +1D7BA ; [.12E6.0020.0005.1D7BA] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL RHO; QQK +1D7C8 ; [.12E6.0020.0005.1D7C8] # MATHEMATICAL SANS-SERIF BOLD ITALIC RHO SYMBOL; QQK +03A1 ; [.12E6.0020.0008.03A1] # GREEK CAPITAL LETTER RHO +1D6B8 ; [.12E6.0020.000B.1D6B8] # MATHEMATICAL BOLD CAPITAL RHO; QQK +1D6F2 ; [.12E6.0020.000B.1D6F2] # MATHEMATICAL ITALIC CAPITAL RHO; QQK +1D72C ; [.12E6.0020.000B.1D72C] # MATHEMATICAL BOLD ITALIC CAPITAL RHO; QQK +1D766 ; [.12E6.0020.000B.1D766] # MATHEMATICAL SANS-SERIF BOLD CAPITAL RHO; QQK +1D7A0 ; [.12E6.0020.000B.1D7A0] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL RHO; QQK +1D68 ; [.12E6.0020.0015.1D68] # GREEK SUBSCRIPT SMALL LETTER RHO; QQK +1FE4 ; [.12E6.0020.0002.03C1][.0000.0022.0002.0313] # GREEK SMALL LETTER RHO WITH PSILI; QQCM +1FE5 ; [.12E6.0020.0002.03C1][.0000.002A.0002.0314] # GREEK SMALL LETTER RHO WITH DASIA; QQCM +1FEC ; [.12E6.0020.0008.03A1][.0000.002A.0002.0314] # GREEK CAPITAL LETTER RHO WITH DASIA; QQCM +1D29 ; [.12E7.0020.0002.1D29] # GREEK LETTER SMALL CAPITAL RHO +03FC ; [.12E8.0020.0002.03FC] # GREEK RHO WITH STROKE SYMBOL +03C3 ; [.12E9.0020.0002.03C3] # GREEK SMALL LETTER SIGMA +03F2 ; [.12E9.0020.0004.03F2] # GREEK LUNATE SIGMA SYMBOL; QQK +1D6D3 ; [.12E9.0020.0005.1D6D3] # MATHEMATICAL BOLD SMALL FINAL SIGMA; QQK +1D6D4 ; [.12E9.0020.0005.1D6D4] # MATHEMATICAL BOLD SMALL SIGMA; QQK +1D70D ; [.12E9.0020.0005.1D70D] # MATHEMATICAL ITALIC SMALL FINAL SIGMA; QQK +1D70E ; [.12E9.0020.0005.1D70E] # MATHEMATICAL ITALIC SMALL SIGMA; QQK +1D747 ; [.12E9.0020.0005.1D747] # MATHEMATICAL BOLD ITALIC SMALL FINAL SIGMA; QQK +1D748 ; [.12E9.0020.0005.1D748] # MATHEMATICAL BOLD ITALIC SMALL SIGMA; QQK +1D781 ; [.12E9.0020.0005.1D781] # MATHEMATICAL SANS-SERIF BOLD SMALL FINAL SIGMA; QQK +1D782 ; [.12E9.0020.0005.1D782] # MATHEMATICAL SANS-SERIF BOLD SMALL SIGMA; QQK +1D7BB ; [.12E9.0020.0005.1D7BB] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL FINAL SIGMA; QQK +1D7BC ; [.12E9.0020.0005.1D7BC] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL SIGMA; QQK +03A3 ; [.12E9.0020.0008.03A3] # GREEK CAPITAL LETTER SIGMA +03F9 ; [.12E9.0020.000A.03F9] # GREEK CAPITAL LUNATE SIGMA SYMBOL; QQK +1D6BA ; [.12E9.0020.000B.1D6BA] # MATHEMATICAL BOLD CAPITAL SIGMA; QQK +1D6F4 ; [.12E9.0020.000B.1D6F4] # MATHEMATICAL ITALIC CAPITAL SIGMA; QQK +1D72E ; [.12E9.0020.000B.1D72E] # MATHEMATICAL BOLD ITALIC CAPITAL SIGMA; QQK +1D768 ; [.12E9.0020.000B.1D768] # MATHEMATICAL SANS-SERIF BOLD CAPITAL SIGMA; QQK +1D7A2 ; [.12E9.0020.000B.1D7A2] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SIGMA; QQK +03C2 ; [.12E9.0020.0019.03C2] # GREEK SMALL LETTER FINAL SIGMA; QQK +037C ; [.12EA.0020.0002.037C] # GREEK SMALL DOTTED LUNATE SIGMA SYMBOL +03FE ; [.12EA.0020.0008.03FE] # GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL +037B ; [.12EB.0020.0002.037B] # GREEK SMALL REVERSED LUNATE SIGMA SYMBOL +03FD ; [.12EB.0020.0008.03FD] # GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL +037D ; [.12EC.0020.0002.037D] # GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL +03FF ; [.12EC.0020.0008.03FF] # GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL +03C4 ; [.12ED.0020.0002.03C4] # GREEK SMALL LETTER TAU +1D6D5 ; [.12ED.0020.0005.1D6D5] # MATHEMATICAL BOLD SMALL TAU; QQK +1D70F ; [.12ED.0020.0005.1D70F] # MATHEMATICAL ITALIC SMALL TAU; QQK +1D749 ; [.12ED.0020.0005.1D749] # MATHEMATICAL BOLD ITALIC SMALL TAU; QQK +1D783 ; [.12ED.0020.0005.1D783] # MATHEMATICAL SANS-SERIF BOLD SMALL TAU; QQK +1D7BD ; [.12ED.0020.0005.1D7BD] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL TAU; QQK +03A4 ; [.12ED.0020.0008.03A4] # GREEK CAPITAL LETTER TAU +1D6BB ; [.12ED.0020.000B.1D6BB] # MATHEMATICAL BOLD CAPITAL TAU; QQK +1D6F5 ; [.12ED.0020.000B.1D6F5] # MATHEMATICAL ITALIC CAPITAL TAU; QQK +1D72F ; [.12ED.0020.000B.1D72F] # MATHEMATICAL BOLD ITALIC CAPITAL TAU; QQK +1D769 ; [.12ED.0020.000B.1D769] # MATHEMATICAL SANS-SERIF BOLD CAPITAL TAU; QQK +1D7A3 ; [.12ED.0020.000B.1D7A3] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TAU; QQK +03C5 ; [.12EE.0020.0002.03C5] # GREEK SMALL LETTER UPSILON +1D6D6 ; [.12EE.0020.0005.1D6D6] # MATHEMATICAL BOLD SMALL UPSILON; QQK +1D710 ; [.12EE.0020.0005.1D710] # MATHEMATICAL ITALIC SMALL UPSILON; QQK +1D74A ; [.12EE.0020.0005.1D74A] # MATHEMATICAL BOLD ITALIC SMALL UPSILON; QQK +1D784 ; [.12EE.0020.0005.1D784] # MATHEMATICAL SANS-SERIF BOLD SMALL UPSILON; QQK +1D7BE ; [.12EE.0020.0005.1D7BE] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL UPSILON; QQK +03A5 ; [.12EE.0020.0008.03A5] # GREEK CAPITAL LETTER UPSILON +03D2 ; [.12EE.0020.000A.03D2] # GREEK UPSILON WITH HOOK SYMBOL; QQK +1D6BC ; [.12EE.0020.000B.1D6BC] # MATHEMATICAL BOLD CAPITAL UPSILON; QQK +1D6F6 ; [.12EE.0020.000B.1D6F6] # MATHEMATICAL ITALIC CAPITAL UPSILON; QQK +1D730 ; [.12EE.0020.000B.1D730] # MATHEMATICAL BOLD ITALIC CAPITAL UPSILON; QQK +1D76A ; [.12EE.0020.000B.1D76A] # MATHEMATICAL SANS-SERIF BOLD CAPITAL UPSILON; QQK +1D7A4 ; [.12EE.0020.000B.1D7A4] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UPSILON; QQK +1F50 ; [.12EE.0020.0002.03C5][.0000.0022.0002.0313] # GREEK SMALL LETTER UPSILON WITH PSILI; QQCM +1F54 ; [.12EE.0020.0002.03C5][.0000.0022.0002.0313][.0000.0032.0002.0301] # GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA; QQCM +1F52 ; [.12EE.0020.0002.03C5][.0000.0022.0002.0313][.0000.0035.0002.0300] # GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA; QQCM +1F56 ; [.12EE.0020.0002.03C5][.0000.0022.0002.0313][.0000.0045.0002.0342] # GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI; QQCM +1F51 ; [.12EE.0020.0002.03C5][.0000.002A.0002.0314] # GREEK SMALL LETTER UPSILON WITH DASIA; QQCM +1F59 ; [.12EE.0020.0008.03A5][.0000.002A.0002.0314] # GREEK CAPITAL LETTER UPSILON WITH DASIA; QQCM +1F55 ; [.12EE.0020.0002.03C5][.0000.002A.0002.0314][.0000.0032.0002.0301] # GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA; QQCM +1F5D ; [.12EE.0020.0008.03A5][.0000.002A.0002.0314][.0000.0032.0002.0301] # GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA; QQCM +1F53 ; [.12EE.0020.0002.03C5][.0000.002A.0002.0314][.0000.0035.0002.0300] # GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA; QQCM +1F5B ; [.12EE.0020.0008.03A5][.0000.002A.0002.0314][.0000.0035.0002.0300] # GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA; QQCM +1F57 ; [.12EE.0020.0002.03C5][.0000.002A.0002.0314][.0000.0045.0002.0342] # GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI; QQCM +1F5F ; [.12EE.0020.0008.03A5][.0000.002A.0002.0314][.0000.0045.0002.0342] # GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI; QQCM +03CD ; [.12EE.0020.0002.03C5][.0000.0032.0002.0301] # GREEK SMALL LETTER UPSILON WITH TONOS; QQCM +1F7B ; [.12EE.0020.0002.03C5][.0000.0032.0002.0301] # GREEK SMALL LETTER UPSILON WITH OXIA; QQCM +038E ; [.12EE.0020.0008.03A5][.0000.0032.0002.0301] # GREEK CAPITAL LETTER UPSILON WITH TONOS; QQCM +1FEB ; [.12EE.0020.0008.03A5][.0000.0032.0002.0301] # GREEK CAPITAL LETTER UPSILON WITH OXIA; QQCM +03D3 ; [.12EE.0020.000A.03D3][.0000.0032.0002.03D3] # GREEK UPSILON WITH ACUTE AND HOOK SYMBOL; QQKN +1F7A ; [.12EE.0020.0002.03C5][.0000.0035.0002.0300] # GREEK SMALL LETTER UPSILON WITH VARIA; QQCM +1FEA ; [.12EE.0020.0008.03A5][.0000.0035.0002.0300] # GREEK CAPITAL LETTER UPSILON WITH VARIA; QQCM +1FE0 ; [.12EE.0020.0002.03C5][.0000.0037.0002.0306] # GREEK SMALL LETTER UPSILON WITH VRACHY; QQCM +1FE8 ; [.12EE.0020.0008.03A5][.0000.0037.0002.0306] # GREEK CAPITAL LETTER UPSILON WITH VRACHY; QQCM +1FE6 ; [.12EE.0020.0002.03C5][.0000.0045.0002.0342] # GREEK SMALL LETTER UPSILON WITH PERISPOMENI; QQCM +03CB ; [.12EE.0020.0002.03C5][.0000.0047.0002.0308] # GREEK SMALL LETTER UPSILON WITH DIALYTIKA; QQCM +03AB ; [.12EE.0020.0008.03A5][.0000.0047.0002.0308] # GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA; QQCM +03D4 ; [.12EE.0020.000A.03D4][.0000.0047.0002.03D4] # GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL; QQKN +03B0 ; [.12EE.0020.0002.03C5][.0000.0047.0002.0308][.0000.0032.0002.0301] # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS; QQCM +1FE3 ; [.12EE.0020.0002.03C5][.0000.0047.0002.0308][.0000.0032.0002.0301] # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA; QQCM +1FE2 ; [.12EE.0020.0002.03C5][.0000.0047.0002.0308][.0000.0035.0002.0300] # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA; QQCM +1FE7 ; [.12EE.0020.0002.03C5][.0000.0047.0002.0308][.0000.0045.0002.0342] # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI; QQCM +1FE1 ; [.12EE.0020.0002.03C5][.0000.005B.0002.0304] # GREEK SMALL LETTER UPSILON WITH MACRON; QQCM +1FE9 ; [.12EE.0020.0008.03A5][.0000.005B.0002.0304] # GREEK CAPITAL LETTER UPSILON WITH MACRON; QQCM +03C6 ; [.12EF.0020.0002.03C6] # GREEK SMALL LETTER PHI +03D5 ; [.12EF.0020.0004.03D5] # GREEK PHI SYMBOL; QQK +1D6D7 ; [.12EF.0020.0005.1D6D7] # MATHEMATICAL BOLD SMALL PHI; QQK +1D6DF ; [.12EF.0020.0005.1D6DF] # MATHEMATICAL BOLD PHI SYMBOL; QQK +1D711 ; [.12EF.0020.0005.1D711] # MATHEMATICAL ITALIC SMALL PHI; QQK +1D719 ; [.12EF.0020.0005.1D719] # MATHEMATICAL ITALIC PHI SYMBOL; QQK +1D74B ; [.12EF.0020.0005.1D74B] # MATHEMATICAL BOLD ITALIC SMALL PHI; QQK +1D753 ; [.12EF.0020.0005.1D753] # MATHEMATICAL BOLD ITALIC PHI SYMBOL; QQK +1D785 ; [.12EF.0020.0005.1D785] # MATHEMATICAL SANS-SERIF BOLD SMALL PHI; QQK +1D78D ; [.12EF.0020.0005.1D78D] # MATHEMATICAL SANS-SERIF BOLD PHI SYMBOL; QQK +1D7BF ; [.12EF.0020.0005.1D7BF] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PHI; QQK +1D7C7 ; [.12EF.0020.0005.1D7C7] # MATHEMATICAL SANS-SERIF BOLD ITALIC PHI SYMBOL; QQK +03A6 ; [.12EF.0020.0008.03A6] # GREEK CAPITAL LETTER PHI +1D6BD ; [.12EF.0020.000B.1D6BD] # MATHEMATICAL BOLD CAPITAL PHI; QQK +1D6F7 ; [.12EF.0020.000B.1D6F7] # MATHEMATICAL ITALIC CAPITAL PHI; QQK +1D731 ; [.12EF.0020.000B.1D731] # MATHEMATICAL BOLD ITALIC CAPITAL PHI; QQK +1D76B ; [.12EF.0020.000B.1D76B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL PHI; QQK +1D7A5 ; [.12EF.0020.000B.1D7A5] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PHI; QQK +1D60 ; [.12EF.0020.0014.1D60] # MODIFIER LETTER SMALL GREEK PHI; QQK +1D69 ; [.12EF.0020.0015.1D69] # GREEK SUBSCRIPT SMALL LETTER PHI; QQK +03C7 ; [.12F0.0020.0002.03C7] # GREEK SMALL LETTER CHI +1D6D8 ; [.12F0.0020.0005.1D6D8] # MATHEMATICAL BOLD SMALL CHI; QQK +1D712 ; [.12F0.0020.0005.1D712] # MATHEMATICAL ITALIC SMALL CHI; QQK +1D74C ; [.12F0.0020.0005.1D74C] # MATHEMATICAL BOLD ITALIC SMALL CHI; QQK +1D786 ; [.12F0.0020.0005.1D786] # MATHEMATICAL SANS-SERIF BOLD SMALL CHI; QQK +1D7C0 ; [.12F0.0020.0005.1D7C0] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL CHI; QQK +03A7 ; [.12F0.0020.0008.03A7] # GREEK CAPITAL LETTER CHI +1D6BE ; [.12F0.0020.000B.1D6BE] # MATHEMATICAL BOLD CAPITAL CHI; QQK +1D6F8 ; [.12F0.0020.000B.1D6F8] # MATHEMATICAL ITALIC CAPITAL CHI; QQK +1D732 ; [.12F0.0020.000B.1D732] # MATHEMATICAL BOLD ITALIC CAPITAL CHI; QQK +1D76C ; [.12F0.0020.000B.1D76C] # MATHEMATICAL SANS-SERIF BOLD CAPITAL CHI; QQK +1D7A6 ; [.12F0.0020.000B.1D7A6] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CHI; QQK +1D61 ; [.12F0.0020.0014.1D61] # MODIFIER LETTER SMALL CHI; QQK +1D6A ; [.12F0.0020.0015.1D6A] # GREEK SUBSCRIPT SMALL LETTER CHI; QQK +03C8 ; [.12F1.0020.0002.03C8] # GREEK SMALL LETTER PSI +1D6D9 ; [.12F1.0020.0005.1D6D9] # MATHEMATICAL BOLD SMALL PSI; QQK +1D713 ; [.12F1.0020.0005.1D713] # MATHEMATICAL ITALIC SMALL PSI; QQK +1D74D ; [.12F1.0020.0005.1D74D] # MATHEMATICAL BOLD ITALIC SMALL PSI; QQK +1D787 ; [.12F1.0020.0005.1D787] # MATHEMATICAL SANS-SERIF BOLD SMALL PSI; QQK +1D7C1 ; [.12F1.0020.0005.1D7C1] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PSI; QQK +03A8 ; [.12F1.0020.0008.03A8] # GREEK CAPITAL LETTER PSI +1D6BF ; [.12F1.0020.000B.1D6BF] # MATHEMATICAL BOLD CAPITAL PSI; QQK +1D6F9 ; [.12F1.0020.000B.1D6F9] # MATHEMATICAL ITALIC CAPITAL PSI; QQK +1D733 ; [.12F1.0020.000B.1D733] # MATHEMATICAL BOLD ITALIC CAPITAL PSI; QQK +1D76D ; [.12F1.0020.000B.1D76D] # MATHEMATICAL SANS-SERIF BOLD CAPITAL PSI; QQK +1D7A7 ; [.12F1.0020.000B.1D7A7] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PSI; QQK +1D2A ; [.12F2.0020.0002.1D2A] # GREEK LETTER SMALL CAPITAL PSI +03C9 ; [.12F3.0020.0002.03C9] # GREEK SMALL LETTER OMEGA +1D6DA ; [.12F3.0020.0005.1D6DA] # MATHEMATICAL BOLD SMALL OMEGA; QQK +1D714 ; [.12F3.0020.0005.1D714] # MATHEMATICAL ITALIC SMALL OMEGA; QQK +1D74E ; [.12F3.0020.0005.1D74E] # MATHEMATICAL BOLD ITALIC SMALL OMEGA; QQK +1D788 ; [.12F3.0020.0005.1D788] # MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA; QQK +1D7C2 ; [.12F3.0020.0005.1D7C2] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA; QQK +03A9 ; [.12F3.0020.0008.03A9] # GREEK CAPITAL LETTER OMEGA +2126 ; [.12F3.0020.0008.2126] # OHM SIGN; QQC +1D6C0 ; [.12F3.0020.000B.1D6C0] # MATHEMATICAL BOLD CAPITAL OMEGA; QQK +1D6FA ; [.12F3.0020.000B.1D6FA] # MATHEMATICAL ITALIC CAPITAL OMEGA; QQK +1D734 ; [.12F3.0020.000B.1D734] # MATHEMATICAL BOLD ITALIC CAPITAL OMEGA; QQK +1D76E ; [.12F3.0020.000B.1D76E] # MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA; QQK +1D7A8 ; [.12F3.0020.000B.1D7A8] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA; QQK +1F60 ; [.12F3.0020.0002.03C9][.0000.0022.0002.0313] # GREEK SMALL LETTER OMEGA WITH PSILI; QQCM +1F68 ; [.12F3.0020.0008.03A9][.0000.0022.0002.0313] # GREEK CAPITAL LETTER OMEGA WITH PSILI; QQCM +1F64 ; [.12F3.0020.0002.03C9][.0000.0022.0002.0313][.0000.0032.0002.0301] # GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA; QQCM +1F6C ; [.12F3.0020.0008.03A9][.0000.0022.0002.0313][.0000.0032.0002.0301] # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA; QQCM +1FA4 ; [.12F3.0020.0002.03C9][.0000.0022.0002.0313][.0000.0032.0002.0301][.0000.0097.0002.0345] # GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI; QQCM +1FAC ; [.12F3.0020.0008.03A9][.0000.0022.0002.0313][.0000.0032.0002.0301][.0000.0097.0002.0345] # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI; QQCM +1F62 ; [.12F3.0020.0002.03C9][.0000.0022.0002.0313][.0000.0035.0002.0300] # GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA; QQCM +1F6A ; [.12F3.0020.0008.03A9][.0000.0022.0002.0313][.0000.0035.0002.0300] # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA; QQCM +1FA2 ; [.12F3.0020.0002.03C9][.0000.0022.0002.0313][.0000.0035.0002.0300][.0000.0097.0002.0345] # GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI; QQCM +1FAA ; [.12F3.0020.0008.03A9][.0000.0022.0002.0313][.0000.0035.0002.0300][.0000.0097.0002.0345] # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI; QQCM +1F66 ; [.12F3.0020.0002.03C9][.0000.0022.0002.0313][.0000.0045.0002.0342] # GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI; QQCM +1F6E ; [.12F3.0020.0008.03A9][.0000.0022.0002.0313][.0000.0045.0002.0342] # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI; QQCM +1FA6 ; [.12F3.0020.0002.03C9][.0000.0022.0002.0313][.0000.0045.0002.0342][.0000.0097.0002.0345] # GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI; QQCM +1FAE ; [.12F3.0020.0008.03A9][.0000.0022.0002.0313][.0000.0045.0002.0342][.0000.0097.0002.0345] # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI; QQCM +1FA0 ; [.12F3.0020.0002.03C9][.0000.0022.0002.0313][.0000.0097.0002.0345] # GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI; QQCM +1FA8 ; [.12F3.0020.0008.03A9][.0000.0022.0002.0313][.0000.0097.0002.0345] # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI; QQCM +1F61 ; [.12F3.0020.0002.03C9][.0000.002A.0002.0314] # GREEK SMALL LETTER OMEGA WITH DASIA; QQCM +1F69 ; [.12F3.0020.0008.03A9][.0000.002A.0002.0314] # GREEK CAPITAL LETTER OMEGA WITH DASIA; QQCM +1F65 ; [.12F3.0020.0002.03C9][.0000.002A.0002.0314][.0000.0032.0002.0301] # GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA; QQCM +1F6D ; [.12F3.0020.0008.03A9][.0000.002A.0002.0314][.0000.0032.0002.0301] # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA; QQCM +1FA5 ; [.12F3.0020.0002.03C9][.0000.002A.0002.0314][.0000.0032.0002.0301][.0000.0097.0002.0345] # GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI; QQCM +1FAD ; [.12F3.0020.0008.03A9][.0000.002A.0002.0314][.0000.0032.0002.0301][.0000.0097.0002.0345] # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI; QQCM +1F63 ; [.12F3.0020.0002.03C9][.0000.002A.0002.0314][.0000.0035.0002.0300] # GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA; QQCM +1F6B ; [.12F3.0020.0008.03A9][.0000.002A.0002.0314][.0000.0035.0002.0300] # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA; QQCM +1FA3 ; [.12F3.0020.0002.03C9][.0000.002A.0002.0314][.0000.0035.0002.0300][.0000.0097.0002.0345] # GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI; QQCM +1FAB ; [.12F3.0020.0008.03A9][.0000.002A.0002.0314][.0000.0035.0002.0300][.0000.0097.0002.0345] # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI; QQCM +1F67 ; [.12F3.0020.0002.03C9][.0000.002A.0002.0314][.0000.0045.0002.0342] # GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI; QQCM +1F6F ; [.12F3.0020.0008.03A9][.0000.002A.0002.0314][.0000.0045.0002.0342] # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI; QQCM +1FA7 ; [.12F3.0020.0002.03C9][.0000.002A.0002.0314][.0000.0045.0002.0342][.0000.0097.0002.0345] # GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI; QQCM +1FAF ; [.12F3.0020.0008.03A9][.0000.002A.0002.0314][.0000.0045.0002.0342][.0000.0097.0002.0345] # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI; QQCM +1FA1 ; [.12F3.0020.0002.03C9][.0000.002A.0002.0314][.0000.0097.0002.0345] # GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI; QQCM +1FA9 ; [.12F3.0020.0008.03A9][.0000.002A.0002.0314][.0000.0097.0002.0345] # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI; QQCM +03CE ; [.12F3.0020.0002.03C9][.0000.0032.0002.0301] # GREEK SMALL LETTER OMEGA WITH TONOS; QQCM +1F7D ; [.12F3.0020.0002.03C9][.0000.0032.0002.0301] # GREEK SMALL LETTER OMEGA WITH OXIA; QQCM +038F ; [.12F3.0020.0008.03A9][.0000.0032.0002.0301] # GREEK CAPITAL LETTER OMEGA WITH TONOS; QQCM +1FFB ; [.12F3.0020.0008.03A9][.0000.0032.0002.0301] # GREEK CAPITAL LETTER OMEGA WITH OXIA; QQCM +1FF4 ; [.12F3.0020.0002.03C9][.0000.0032.0002.0301][.0000.0097.0002.0345] # GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI; QQCM +1F7C ; [.12F3.0020.0002.03C9][.0000.0035.0002.0300] # GREEK SMALL LETTER OMEGA WITH VARIA; QQCM +1FFA ; [.12F3.0020.0008.03A9][.0000.0035.0002.0300] # GREEK CAPITAL LETTER OMEGA WITH VARIA; QQCM +1FF2 ; [.12F3.0020.0002.03C9][.0000.0035.0002.0300][.0000.0097.0002.0345] # GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI; QQCM +1FF6 ; [.12F3.0020.0002.03C9][.0000.0045.0002.0342] # GREEK SMALL LETTER OMEGA WITH PERISPOMENI; QQCM +1FF7 ; [.12F3.0020.0002.03C9][.0000.0045.0002.0342][.0000.0097.0002.0345] # GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI; QQCM +1FF3 ; [.12F3.0020.0002.03C9][.0000.0097.0002.0345] # GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI; QQCM +1FFC ; [.12F3.0020.0008.03A9][.0000.0097.0002.0345] # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI; QQCM +03E1 ; [.12F4.0020.0002.03E1] # GREEK SMALL LETTER SAMPI +03E0 ; [.12F4.0020.0008.03E0] # GREEK LETTER SAMPI +03F8 ; [.12F5.0020.0002.03F8] # GREEK SMALL LETTER SHO +03F7 ; [.12F5.0020.0008.03F7] # GREEK CAPITAL LETTER SHO +2C81 ; [.12F6.0020.0002.2C81] # COPTIC SMALL LETTER ALFA +2C80 ; [.12F6.0020.0008.2C80] # COPTIC CAPITAL LETTER ALFA +2C83 ; [.12F7.0020.0002.2C83] # COPTIC SMALL LETTER VIDA +2C82 ; [.12F7.0020.0008.2C82] # COPTIC CAPITAL LETTER VIDA +2C85 ; [.12F8.0020.0002.2C85] # COPTIC SMALL LETTER GAMMA +2C84 ; [.12F8.0020.0008.2C84] # COPTIC CAPITAL LETTER GAMMA +2C87 ; [.12F9.0020.0002.2C87] # COPTIC SMALL LETTER DALDA +2C86 ; [.12F9.0020.0008.2C86] # COPTIC CAPITAL LETTER DALDA +2C89 ; [.12FA.0020.0002.2C89] # COPTIC SMALL LETTER EIE +2C88 ; [.12FA.0020.0008.2C88] # COPTIC CAPITAL LETTER EIE +2CB7 ; [.12FB.0020.0002.2CB7] # COPTIC SMALL LETTER CRYPTOGRAMMIC EIE +2CB6 ; [.12FB.0020.0008.2CB6] # COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE +2C8B ; [.12FC.0020.0002.2C8B] # COPTIC SMALL LETTER SOU +2C8A ; [.12FC.0020.0008.2C8A] # COPTIC CAPITAL LETTER SOU +2C8D ; [.12FD.0020.0002.2C8D] # COPTIC SMALL LETTER ZATA +2C8C ; [.12FD.0020.0008.2C8C] # COPTIC CAPITAL LETTER ZATA +2C8F ; [.12FE.0020.0002.2C8F] # COPTIC SMALL LETTER HATE +2C8E ; [.12FE.0020.0008.2C8E] # COPTIC CAPITAL LETTER HATE +2C91 ; [.12FF.0020.0002.2C91] # COPTIC SMALL LETTER THETHE +2C90 ; [.12FF.0020.0008.2C90] # COPTIC CAPITAL LETTER THETHE +2C93 ; [.1300.0020.0002.2C93] # COPTIC SMALL LETTER IAUDA +2C92 ; [.1300.0020.0008.2C92] # COPTIC CAPITAL LETTER IAUDA +2C95 ; [.1301.0020.0002.2C95] # COPTIC SMALL LETTER KAPA +2C94 ; [.1301.0020.0008.2C94] # COPTIC CAPITAL LETTER KAPA +2CE4 ; [.1301.0020.0004.2CE4][.12F6.0020.0004.2CE4][.1300.0020.001F.2CE4] # COPTIC SYMBOL KAI; QQKN +2CB9 ; [.1302.0020.0002.2CB9] # COPTIC SMALL LETTER DIALECT-P KAPA +2CB8 ; [.1302.0020.0008.2CB8] # COPTIC CAPITAL LETTER DIALECT-P KAPA +2C97 ; [.1303.0020.0002.2C97] # COPTIC SMALL LETTER LAULA +2C96 ; [.1303.0020.0008.2C96] # COPTIC CAPITAL LETTER LAULA +2C99 ; [.1304.0020.0002.2C99] # COPTIC SMALL LETTER MI +2C98 ; [.1304.0020.0008.2C98] # COPTIC CAPITAL LETTER MI +2C9B ; [.1305.0020.0002.2C9B] # COPTIC SMALL LETTER NI +2C9A ; [.1305.0020.0008.2C9A] # COPTIC CAPITAL LETTER NI +2CBB ; [.1306.0020.0002.2CBB] # COPTIC SMALL LETTER DIALECT-P NI +2CBA ; [.1306.0020.0008.2CBA] # COPTIC CAPITAL LETTER DIALECT-P NI +2CBD ; [.1307.0020.0002.2CBD] # COPTIC SMALL LETTER CRYPTOGRAMMIC NI +2CBC ; [.1307.0020.0008.2CBC] # COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI +2C9D ; [.1308.0020.0002.2C9D] # COPTIC SMALL LETTER KSI +2C9C ; [.1308.0020.0008.2C9C] # COPTIC CAPITAL LETTER KSI +2C9F ; [.1309.0020.0002.2C9F] # COPTIC SMALL LETTER O +2C9E ; [.1309.0020.0008.2C9E] # COPTIC CAPITAL LETTER O +2CA1 ; [.130A.0020.0002.2CA1] # COPTIC SMALL LETTER PI +2CA0 ; [.130A.0020.0008.2CA0] # COPTIC CAPITAL LETTER PI +2CA3 ; [.130B.0020.0002.2CA3] # COPTIC SMALL LETTER RO +2CA2 ; [.130B.0020.0008.2CA2] # COPTIC CAPITAL LETTER RO +2CA5 ; [.130C.0020.0002.2CA5] # COPTIC SMALL LETTER SIMA +2CA4 ; [.130C.0020.0008.2CA4] # COPTIC CAPITAL LETTER SIMA +2CA7 ; [.130D.0020.0002.2CA7] # COPTIC SMALL LETTER TAU +2CA6 ; [.130D.0020.0008.2CA6] # COPTIC CAPITAL LETTER TAU +2CA9 ; [.130E.0020.0002.2CA9] # COPTIC SMALL LETTER UA +2CA8 ; [.130E.0020.0008.2CA8] # COPTIC CAPITAL LETTER UA +2CAB ; [.130F.0020.0002.2CAB] # COPTIC SMALL LETTER FI +2CAA ; [.130F.0020.0008.2CAA] # COPTIC CAPITAL LETTER FI +2CAD ; [.1310.0020.0002.2CAD] # COPTIC SMALL LETTER KHI +2CAC ; [.1310.0020.0008.2CAC] # COPTIC CAPITAL LETTER KHI +2CAF ; [.1311.0020.0002.2CAF] # COPTIC SMALL LETTER PSI +2CAE ; [.1311.0020.0008.2CAE] # COPTIC CAPITAL LETTER PSI +2CB1 ; [.1312.0020.0002.2CB1] # COPTIC SMALL LETTER OOU +2CB0 ; [.1312.0020.0008.2CB0] # COPTIC CAPITAL LETTER OOU +2CBF ; [.1313.0020.0002.2CBF] # COPTIC SMALL LETTER OLD COPTIC OOU +2CBE ; [.1313.0020.0008.2CBE] # COPTIC CAPITAL LETTER OLD COPTIC OOU +2CC1 ; [.1314.0020.0002.2CC1] # COPTIC SMALL LETTER SAMPI +2CC0 ; [.1314.0020.0008.2CC0] # COPTIC CAPITAL LETTER SAMPI +03E3 ; [.1315.0020.0002.03E3] # COPTIC SMALL LETTER SHEI +03E2 ; [.1315.0020.0008.03E2] # COPTIC CAPITAL LETTER SHEI +2CC3 ; [.1316.0020.0002.2CC3] # COPTIC SMALL LETTER CROSSED SHEI +2CC2 ; [.1316.0020.0008.2CC2] # COPTIC CAPITAL LETTER CROSSED SHEI +2CC5 ; [.1317.0020.0002.2CC5] # COPTIC SMALL LETTER OLD COPTIC SHEI +2CC4 ; [.1317.0020.0008.2CC4] # COPTIC CAPITAL LETTER OLD COPTIC SHEI +2CC7 ; [.1318.0020.0002.2CC7] # COPTIC SMALL LETTER OLD COPTIC ESH +2CC6 ; [.1318.0020.0008.2CC6] # COPTIC CAPITAL LETTER OLD COPTIC ESH +03E5 ; [.1319.0020.0002.03E5] # COPTIC SMALL LETTER FEI +03E4 ; [.1319.0020.0008.03E4] # COPTIC CAPITAL LETTER FEI +03E7 ; [.131A.0020.0002.03E7] # COPTIC SMALL LETTER KHEI +03E6 ; [.131A.0020.0008.03E6] # COPTIC CAPITAL LETTER KHEI +2CC9 ; [.131B.0020.0002.2CC9] # COPTIC SMALL LETTER AKHMIMIC KHEI +2CC8 ; [.131B.0020.0008.2CC8] # COPTIC CAPITAL LETTER AKHMIMIC KHEI +03E9 ; [.131C.0020.0002.03E9] # COPTIC SMALL LETTER HORI +03E8 ; [.131C.0020.0008.03E8] # COPTIC CAPITAL LETTER HORI +2CCB ; [.131D.0020.0002.2CCB] # COPTIC SMALL LETTER DIALECT-P HORI +2CCA ; [.131D.0020.0008.2CCA] # COPTIC CAPITAL LETTER DIALECT-P HORI +2CCD ; [.131E.0020.0002.2CCD] # COPTIC SMALL LETTER OLD COPTIC HORI +2CCC ; [.131E.0020.0008.2CCC] # COPTIC CAPITAL LETTER OLD COPTIC HORI +2CCF ; [.131F.0020.0002.2CCF] # COPTIC SMALL LETTER OLD COPTIC HA +2CCE ; [.131F.0020.0008.2CCE] # COPTIC CAPITAL LETTER OLD COPTIC HA +2CD1 ; [.1320.0020.0002.2CD1] # COPTIC SMALL LETTER L-SHAPED HA +2CD0 ; [.1320.0020.0008.2CD0] # COPTIC CAPITAL LETTER L-SHAPED HA +2CD3 ; [.1321.0020.0002.2CD3] # COPTIC SMALL LETTER OLD COPTIC HEI +2CD2 ; [.1321.0020.0008.2CD2] # COPTIC CAPITAL LETTER OLD COPTIC HEI +2CD5 ; [.1322.0020.0002.2CD5] # COPTIC SMALL LETTER OLD COPTIC HAT +2CD4 ; [.1322.0020.0008.2CD4] # COPTIC CAPITAL LETTER OLD COPTIC HAT +03EB ; [.1323.0020.0002.03EB] # COPTIC SMALL LETTER GANGIA +03EA ; [.1323.0020.0008.03EA] # COPTIC CAPITAL LETTER GANGIA +2CD7 ; [.1324.0020.0002.2CD7] # COPTIC SMALL LETTER OLD COPTIC GANGIA +2CD6 ; [.1324.0020.0008.2CD6] # COPTIC CAPITAL LETTER OLD COPTIC GANGIA +03ED ; [.1325.0020.0002.03ED] # COPTIC SMALL LETTER SHIMA +03EC ; [.1325.0020.0008.03EC] # COPTIC CAPITAL LETTER SHIMA +2CD9 ; [.1326.0020.0002.2CD9] # COPTIC SMALL LETTER OLD COPTIC DJA +2CD8 ; [.1326.0020.0008.2CD8] # COPTIC CAPITAL LETTER OLD COPTIC DJA +2CDB ; [.1327.0020.0002.2CDB] # COPTIC SMALL LETTER OLD COPTIC SHIMA +2CDA ; [.1327.0020.0008.2CDA] # COPTIC CAPITAL LETTER OLD COPTIC SHIMA +2CDD ; [.1328.0020.0002.2CDD] # COPTIC SMALL LETTER OLD NUBIAN SHIMA +2CDC ; [.1328.0020.0008.2CDC] # COPTIC CAPITAL LETTER OLD NUBIAN SHIMA +03EF ; [.1329.0020.0002.03EF] # COPTIC SMALL LETTER DEI +03EE ; [.1329.0020.0008.03EE] # COPTIC CAPITAL LETTER DEI +2CB3 ; [.132A.0020.0002.2CB3] # COPTIC SMALL LETTER DIALECT-P ALEF +2CB2 ; [.132A.0020.0008.2CB2] # COPTIC CAPITAL LETTER DIALECT-P ALEF +2CB5 ; [.132B.0020.0002.2CB5] # COPTIC SMALL LETTER OLD COPTIC AIN +2CB4 ; [.132B.0020.0008.2CB4] # COPTIC CAPITAL LETTER OLD COPTIC AIN +2CDF ; [.132C.0020.0002.2CDF] # COPTIC SMALL LETTER OLD NUBIAN NGI +2CDE ; [.132C.0020.0008.2CDE] # COPTIC CAPITAL LETTER OLD NUBIAN NGI +2CE1 ; [.132D.0020.0002.2CE1] # COPTIC SMALL LETTER OLD NUBIAN NYI +2CE0 ; [.132D.0020.0008.2CE0] # COPTIC CAPITAL LETTER OLD NUBIAN NYI +2CE3 ; [.132E.0020.0002.2CE3] # COPTIC SMALL LETTER OLD NUBIAN WAU +2CE2 ; [.132E.0020.0008.2CE2] # COPTIC CAPITAL LETTER OLD NUBIAN WAU +0430 ; [.132F.0020.0002.0430] # CYRILLIC SMALL LETTER A +0410 ; [.132F.0020.0008.0410] # CYRILLIC CAPITAL LETTER A +04D1 ; [.1333.0020.0002.04D1] # CYRILLIC SMALL LETTER A WITH BREVE +0430 0306 ; [.1333.0020.0002.04D1] # CYRILLIC SMALL LETTER A WITH BREVE +04D0 ; [.1333.0020.0008.04D0] # CYRILLIC CAPITAL LETTER A WITH BREVE +0410 0306 ; [.1333.0020.0008.04D0] # CYRILLIC CAPITAL LETTER A WITH BREVE +04D3 ; [.1337.0020.0002.04D3] # CYRILLIC SMALL LETTER A WITH DIAERESIS +0430 0308 ; [.1337.0020.0002.04D3] # CYRILLIC SMALL LETTER A WITH DIAERESIS +04D2 ; [.1337.0020.0008.04D2] # CYRILLIC CAPITAL LETTER A WITH DIAERESIS +0410 0308 ; [.1337.0020.0008.04D2] # CYRILLIC CAPITAL LETTER A WITH DIAERESIS +04D9 ; [.133B.0020.0002.04D9] # CYRILLIC SMALL LETTER SCHWA +04D8 ; [.133B.0020.0008.04D8] # CYRILLIC CAPITAL LETTER SCHWA +04DB ; [.133F.0020.0002.04DB] # CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS +04D9 0308 ; [.133F.0020.0002.04DB] # CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS +04DA ; [.133F.0020.0008.04DA] # CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS +04D8 0308 ; [.133F.0020.0008.04DA] # CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS +04D5 ; [.1343.0020.0002.04D5] # CYRILLIC SMALL LIGATURE A IE +04D4 ; [.1343.0020.0008.04D4] # CYRILLIC CAPITAL LIGATURE A IE +0431 ; [.1347.0020.0002.0431] # CYRILLIC SMALL LETTER BE +0411 ; [.1347.0020.0008.0411] # CYRILLIC CAPITAL LETTER BE +0432 ; [.134B.0020.0002.0432] # CYRILLIC SMALL LETTER VE +0412 ; [.134B.0020.0008.0412] # CYRILLIC CAPITAL LETTER VE +0433 ; [.134F.0020.0002.0433] # CYRILLIC SMALL LETTER GHE +0413 ; [.134F.0020.0008.0413] # CYRILLIC CAPITAL LETTER GHE +0491 ; [.134F.0020.0004.0491][.0000.019A.0004.0491] # CYRILLIC SMALL LETTER GHE WITH UPTURN; QQKN +0490 ; [.134F.0020.000A.0490][.0000.019A.0004.0490] # CYRILLIC CAPITAL LETTER GHE WITH UPTURN; QQKN +0493 ; [.1353.0020.0002.0493] # CYRILLIC SMALL LETTER GHE WITH STROKE +0492 ; [.1353.0020.0008.0492] # CYRILLIC CAPITAL LETTER GHE WITH STROKE +04FB ; [.1357.0020.0002.04FB] # CYRILLIC SMALL LETTER GHE WITH STROKE AND HOOK +04FA ; [.1357.0020.0008.04FA] # CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK +0495 ; [.135B.0020.0002.0495] # CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK +0494 ; [.135B.0020.0008.0494] # CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK +04F7 ; [.135F.0020.0002.04F7] # CYRILLIC SMALL LETTER GHE WITH DESCENDER +04F6 ; [.135F.0020.0008.04F6] # CYRILLIC CAPITAL LETTER GHE WITH DESCENDER +0434 ; [.1363.0020.0002.0434] # CYRILLIC SMALL LETTER DE +0414 ; [.1363.0020.0008.0414] # CYRILLIC CAPITAL LETTER DE +0501 ; [.1367.0020.0002.0501] # CYRILLIC SMALL LETTER KOMI DE +0500 ; [.1367.0020.0008.0500] # CYRILLIC CAPITAL LETTER KOMI DE +0452 ; [.1368.0020.0002.0452] # CYRILLIC SMALL LETTER DJE +0402 ; [.1368.0020.0008.0402] # CYRILLIC CAPITAL LETTER DJE +0503 ; [.136C.0020.0002.0503] # CYRILLIC SMALL LETTER KOMI DJE +0502 ; [.136C.0020.0008.0502] # CYRILLIC CAPITAL LETTER KOMI DJE +0453 ; [.136D.0020.0002.0453] # CYRILLIC SMALL LETTER GJE +0433 0301 ; [.136D.0020.0002.0453] # CYRILLIC SMALL LETTER GJE +0433 0341 ; [.136D.0020.0002.0453] # CYRILLIC SMALL LETTER GJE +0403 ; [.136D.0020.0008.0403] # CYRILLIC CAPITAL LETTER GJE +0413 0301 ; [.136D.0020.0008.0403] # CYRILLIC CAPITAL LETTER GJE +0413 0341 ; [.136D.0020.0008.0403] # CYRILLIC CAPITAL LETTER GJE +0499 ; [.1371.0020.0002.0499] # CYRILLIC SMALL LETTER ZE WITH DESCENDER +0498 ; [.1371.0020.0008.0498] # CYRILLIC CAPITAL LETTER ZE WITH DESCENDER +0435 ; [.1375.0020.0002.0435] # CYRILLIC SMALL LETTER IE +0415 ; [.1375.0020.0008.0415] # CYRILLIC CAPITAL LETTER IE +0450 ; [.1375.0020.0002.0435][.0000.0035.0002.0300] # CYRILLIC SMALL LETTER IE WITH GRAVE; QQCM +0400 ; [.1375.0020.0008.0415][.0000.0035.0002.0300] # CYRILLIC CAPITAL LETTER IE WITH GRAVE; QQCM +0451 ; [.1375.0020.0002.0435][.0000.0047.0002.0308] # CYRILLIC SMALL LETTER IO; QQCM +0401 ; [.1375.0020.0008.0415][.0000.0047.0002.0308] # CYRILLIC CAPITAL LETTER IO; QQCM +04D7 ; [.1379.0020.0002.04D7] # CYRILLIC SMALL LETTER IE WITH BREVE +0435 0306 ; [.1379.0020.0002.04D7] # CYRILLIC SMALL LETTER IE WITH BREVE +04D6 ; [.1379.0020.0008.04D6] # CYRILLIC CAPITAL LETTER IE WITH BREVE +0415 0306 ; [.1379.0020.0008.04D6] # CYRILLIC CAPITAL LETTER IE WITH BREVE +0454 ; [.137D.0020.0002.0454] # CYRILLIC SMALL LETTER UKRAINIAN IE +0404 ; [.137D.0020.0008.0404] # CYRILLIC CAPITAL LETTER UKRAINIAN IE +0436 ; [.1381.0020.0002.0436] # CYRILLIC SMALL LETTER ZHE +0416 ; [.1381.0020.0008.0416] # CYRILLIC CAPITAL LETTER ZHE +04C2 ; [.1381.0020.0002.0436][.0000.0037.0002.0306] # CYRILLIC SMALL LETTER ZHE WITH BREVE; QQCM +04C1 ; [.1381.0020.0008.0416][.0000.0037.0002.0306] # CYRILLIC CAPITAL LETTER ZHE WITH BREVE; QQCM +04DD ; [.1385.0020.0002.04DD] # CYRILLIC SMALL LETTER ZHE WITH DIAERESIS +0436 0308 ; [.1385.0020.0002.04DD] # CYRILLIC SMALL LETTER ZHE WITH DIAERESIS +04DC ; [.1385.0020.0008.04DC] # CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS +0416 0308 ; [.1385.0020.0008.04DC] # CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS +0497 ; [.1389.0020.0002.0497] # CYRILLIC SMALL LETTER ZHE WITH DESCENDER +0496 ; [.1389.0020.0008.0496] # CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER +0437 ; [.138D.0020.0002.0437] # CYRILLIC SMALL LETTER ZE +0417 ; [.138D.0020.0008.0417] # CYRILLIC CAPITAL LETTER ZE +0505 ; [.1391.0020.0002.0505] # CYRILLIC SMALL LETTER KOMI ZJE +0504 ; [.1391.0020.0008.0504] # CYRILLIC CAPITAL LETTER KOMI ZJE +0511 ; [.1392.0020.0002.0511] # CYRILLIC SMALL LETTER REVERSED ZE +0510 ; [.1392.0020.0008.0510] # CYRILLIC CAPITAL LETTER REVERSED ZE +04DF ; [.1393.0020.0002.04DF] # CYRILLIC SMALL LETTER ZE WITH DIAERESIS +0437 0308 ; [.1393.0020.0002.04DF] # CYRILLIC SMALL LETTER ZE WITH DIAERESIS +04DE ; [.1393.0020.0008.04DE] # CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS +0417 0308 ; [.1393.0020.0008.04DE] # CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS +0455 ; [.1397.0020.0002.0455] # CYRILLIC SMALL LETTER DZE +0405 ; [.1397.0020.0008.0405] # CYRILLIC CAPITAL LETTER DZE +04E1 ; [.139B.0020.0002.04E1] # CYRILLIC SMALL LETTER ABKHASIAN DZE +04E0 ; [.139B.0020.0008.04E0] # CYRILLIC CAPITAL LETTER ABKHASIAN DZE +0507 ; [.139F.0020.0002.0507] # CYRILLIC SMALL LETTER KOMI DZJE +0506 ; [.139F.0020.0008.0506] # CYRILLIC CAPITAL LETTER KOMI DZJE +0438 ; [.13A0.0020.0002.0438] # CYRILLIC SMALL LETTER I +0418 ; [.13A0.0020.0008.0418] # CYRILLIC CAPITAL LETTER I +045D ; [.13A0.0020.0002.0438][.0000.0035.0002.0300] # CYRILLIC SMALL LETTER I WITH GRAVE; QQCM +040D ; [.13A0.0020.0008.0418][.0000.0035.0002.0300] # CYRILLIC CAPITAL LETTER I WITH GRAVE; QQCM +04E3 ; [.13A0.0020.0002.0438][.0000.005B.0002.0304] # CYRILLIC SMALL LETTER I WITH MACRON; QQCM +04E2 ; [.13A0.0020.0008.0418][.0000.005B.0002.0304] # CYRILLIC CAPITAL LETTER I WITH MACRON; QQCM +048B ; [.13A4.0020.0002.048B] # CYRILLIC SMALL LETTER SHORT I WITH TAIL +048A ; [.13A4.0020.0008.048A] # CYRILLIC CAPITAL LETTER SHORT I WITH TAIL +04E5 ; [.13A8.0020.0002.04E5] # CYRILLIC SMALL LETTER I WITH DIAERESIS +0438 0308 ; [.13A8.0020.0002.04E5] # CYRILLIC SMALL LETTER I WITH DIAERESIS +04E4 ; [.13A8.0020.0008.04E4] # CYRILLIC CAPITAL LETTER I WITH DIAERESIS +0418 0308 ; [.13A8.0020.0008.04E4] # CYRILLIC CAPITAL LETTER I WITH DIAERESIS +0456 ; [.13AC.0020.0002.0456] # CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I +0406 ; [.13AC.0020.0008.0406] # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I +0457 ; [.13B0.0020.0002.0457] # CYRILLIC SMALL LETTER YI +0456 0308 ; [.13B0.0020.0002.0457] # CYRILLIC SMALL LETTER YI +0407 ; [.13B0.0020.0008.0407] # CYRILLIC CAPITAL LETTER YI +0406 0308 ; [.13B0.0020.0008.0407] # CYRILLIC CAPITAL LETTER YI +0439 ; [.13B4.0020.0002.0439] # CYRILLIC SMALL LETTER SHORT I +0438 0306 ; [.13B4.0020.0002.0439] # CYRILLIC SMALL LETTER SHORT I +0419 ; [.13B4.0020.0008.0419] # CYRILLIC CAPITAL LETTER SHORT I +0418 0306 ; [.13B4.0020.0008.0419] # CYRILLIC CAPITAL LETTER SHORT I +0458 ; [.13B8.0020.0002.0458] # CYRILLIC SMALL LETTER JE +0408 ; [.13B8.0020.0008.0408] # CYRILLIC CAPITAL LETTER JE +043A ; [.13BC.0020.0002.043A] # CYRILLIC SMALL LETTER KA +041A ; [.13BC.0020.0008.041A] # CYRILLIC CAPITAL LETTER KA +049B ; [.13C0.0020.0002.049B] # CYRILLIC SMALL LETTER KA WITH DESCENDER +049A ; [.13C0.0020.0008.049A] # CYRILLIC CAPITAL LETTER KA WITH DESCENDER +04C4 ; [.13C4.0020.0002.04C4] # CYRILLIC SMALL LETTER KA WITH HOOK +04C3 ; [.13C4.0020.0008.04C3] # CYRILLIC CAPITAL LETTER KA WITH HOOK +04A1 ; [.13C8.0020.0002.04A1] # CYRILLIC SMALL LETTER BASHKIR KA +04A0 ; [.13C8.0020.0008.04A0] # CYRILLIC CAPITAL LETTER BASHKIR KA +049F ; [.13CC.0020.0002.049F] # CYRILLIC SMALL LETTER KA WITH STROKE +049E ; [.13CC.0020.0008.049E] # CYRILLIC CAPITAL LETTER KA WITH STROKE +049D ; [.13D0.0020.0002.049D] # CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE +049C ; [.13D0.0020.0008.049C] # CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE +043B ; [.13D4.0020.0002.043B] # CYRILLIC SMALL LETTER EL +041B ; [.13D4.0020.0008.041B] # CYRILLIC CAPITAL LETTER EL +1D2B ; [.13D8.0020.0002.1D2B] # CYRILLIC LETTER SMALL CAPITAL EL +04C6 ; [.13D9.0020.0002.04C6] # CYRILLIC SMALL LETTER EL WITH TAIL +04C5 ; [.13D9.0020.0008.04C5] # CYRILLIC CAPITAL LETTER EL WITH TAIL +0513 ; [.13DD.0020.0002.0513] # CYRILLIC SMALL LETTER EL WITH HOOK +0512 ; [.13DD.0020.0008.0512] # CYRILLIC CAPITAL LETTER EL WITH HOOK +0459 ; [.13DE.0020.0002.0459] # CYRILLIC SMALL LETTER LJE +0409 ; [.13DE.0020.0008.0409] # CYRILLIC CAPITAL LETTER LJE +0509 ; [.13E2.0020.0002.0509] # CYRILLIC SMALL LETTER KOMI LJE +0508 ; [.13E2.0020.0008.0508] # CYRILLIC CAPITAL LETTER KOMI LJE +043C ; [.13E3.0020.0002.043C] # CYRILLIC SMALL LETTER EM +041C ; [.13E3.0020.0008.041C] # CYRILLIC CAPITAL LETTER EM +04CE ; [.13E7.0020.0002.04CE] # CYRILLIC SMALL LETTER EM WITH TAIL +04CD ; [.13E7.0020.0008.04CD] # CYRILLIC CAPITAL LETTER EM WITH TAIL +043D ; [.13EB.0020.0002.043D] # CYRILLIC SMALL LETTER EN +041D ; [.13EB.0020.0008.041D] # CYRILLIC CAPITAL LETTER EN +1D78 ; [.13EB.0020.0014.1D78] # MODIFIER LETTER CYRILLIC EN; QQK +04CA ; [.13EF.0020.0002.04CA] # CYRILLIC SMALL LETTER EN WITH TAIL +04C9 ; [.13EF.0020.0008.04C9] # CYRILLIC CAPITAL LETTER EN WITH TAIL +04A3 ; [.13F3.0020.0002.04A3] # CYRILLIC SMALL LETTER EN WITH DESCENDER +04A2 ; [.13F3.0020.0008.04A2] # CYRILLIC CAPITAL LETTER EN WITH DESCENDER +04C8 ; [.13F7.0020.0002.04C8] # CYRILLIC SMALL LETTER EN WITH HOOK +04C7 ; [.13F7.0020.0008.04C7] # CYRILLIC CAPITAL LETTER EN WITH HOOK +04A5 ; [.13FB.0020.0002.04A5] # CYRILLIC SMALL LIGATURE EN GHE +04A4 ; [.13FB.0020.0008.04A4] # CYRILLIC CAPITAL LIGATURE EN GHE +045A ; [.13FF.0020.0002.045A] # CYRILLIC SMALL LETTER NJE +040A ; [.13FF.0020.0008.040A] # CYRILLIC CAPITAL LETTER NJE +050B ; [.1403.0020.0002.050B] # CYRILLIC SMALL LETTER KOMI NJE +050A ; [.1403.0020.0008.050A] # CYRILLIC CAPITAL LETTER KOMI NJE +043E ; [.1404.0020.0002.043E] # CYRILLIC SMALL LETTER O +041E ; [.1404.0020.0008.041E] # CYRILLIC CAPITAL LETTER O +04E7 ; [.1408.0020.0002.04E7] # CYRILLIC SMALL LETTER O WITH DIAERESIS +043E 0308 ; [.1408.0020.0002.04E7] # CYRILLIC SMALL LETTER O WITH DIAERESIS +04E6 ; [.1408.0020.0008.04E6] # CYRILLIC CAPITAL LETTER O WITH DIAERESIS +041E 0308 ; [.1408.0020.0008.04E6] # CYRILLIC CAPITAL LETTER O WITH DIAERESIS +04E9 ; [.140C.0020.0002.04E9] # CYRILLIC SMALL LETTER BARRED O +04E8 ; [.140C.0020.0008.04E8] # CYRILLIC CAPITAL LETTER BARRED O +04EB ; [.1410.0020.0002.04EB] # CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS +04E9 0308 ; [.1410.0020.0002.04EB] # CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS +04EA ; [.1410.0020.0008.04EA] # CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS +04E8 0308 ; [.1410.0020.0008.04EA] # CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS +043F ; [.1414.0020.0002.043F] # CYRILLIC SMALL LETTER PE +041F ; [.1414.0020.0008.041F] # CYRILLIC CAPITAL LETTER PE +04A7 ; [.1418.0020.0002.04A7] # CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK +04A6 ; [.1418.0020.0008.04A6] # CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK +0481 ; [.141C.0020.0002.0481] # CYRILLIC SMALL LETTER KOPPA +0480 ; [.141C.0020.0008.0480] # CYRILLIC CAPITAL LETTER KOPPA +0440 ; [.1420.0020.0002.0440] # CYRILLIC SMALL LETTER ER +0420 ; [.1420.0020.0008.0420] # CYRILLIC CAPITAL LETTER ER +048F ; [.1424.0020.0002.048F] # CYRILLIC SMALL LETTER ER WITH TICK +048E ; [.1424.0020.0008.048E] # CYRILLIC CAPITAL LETTER ER WITH TICK +0441 ; [.1428.0020.0002.0441] # CYRILLIC SMALL LETTER ES +0421 ; [.1428.0020.0008.0421] # CYRILLIC CAPITAL LETTER ES +050D ; [.142C.0020.0002.050D] # CYRILLIC SMALL LETTER KOMI SJE +050C ; [.142C.0020.0008.050C] # CYRILLIC CAPITAL LETTER KOMI SJE +04AB ; [.142D.0020.0002.04AB] # CYRILLIC SMALL LETTER ES WITH DESCENDER +04AA ; [.142D.0020.0008.04AA] # CYRILLIC CAPITAL LETTER ES WITH DESCENDER +0442 ; [.1431.0020.0002.0442] # CYRILLIC SMALL LETTER TE +0422 ; [.1431.0020.0008.0422] # CYRILLIC CAPITAL LETTER TE +050F ; [.1435.0020.0002.050F] # CYRILLIC SMALL LETTER KOMI TJE +050E ; [.1435.0020.0008.050E] # CYRILLIC CAPITAL LETTER KOMI TJE +04AD ; [.1436.0020.0002.04AD] # CYRILLIC SMALL LETTER TE WITH DESCENDER +04AC ; [.1436.0020.0008.04AC] # CYRILLIC CAPITAL LETTER TE WITH DESCENDER +045B ; [.143A.0020.0002.045B] # CYRILLIC SMALL LETTER TSHE +040B ; [.143A.0020.0008.040B] # CYRILLIC CAPITAL LETTER TSHE +045C ; [.143E.0020.0002.045C] # CYRILLIC SMALL LETTER KJE +043A 0301 ; [.143E.0020.0002.045C] # CYRILLIC SMALL LETTER KJE +043A 0341 ; [.143E.0020.0002.045C] # CYRILLIC SMALL LETTER KJE +040C ; [.143E.0020.0008.040C] # CYRILLIC CAPITAL LETTER KJE +041A 0301 ; [.143E.0020.0008.040C] # CYRILLIC CAPITAL LETTER KJE +041A 0341 ; [.143E.0020.0008.040C] # CYRILLIC CAPITAL LETTER KJE +0443 ; [.1442.0020.0002.0443] # CYRILLIC SMALL LETTER U +0423 ; [.1442.0020.0008.0423] # CYRILLIC CAPITAL LETTER U +04EF ; [.1442.0020.0002.0443][.0000.005B.0002.0304] # CYRILLIC SMALL LETTER U WITH MACRON; QQCM +04EE ; [.1442.0020.0008.0423][.0000.005B.0002.0304] # CYRILLIC CAPITAL LETTER U WITH MACRON; QQCM +045E ; [.1446.0020.0002.045E] # CYRILLIC SMALL LETTER SHORT U +0443 0306 ; [.1446.0020.0002.045E] # CYRILLIC SMALL LETTER SHORT U +040E ; [.1446.0020.0008.040E] # CYRILLIC CAPITAL LETTER SHORT U +0423 0306 ; [.1446.0020.0008.040E] # CYRILLIC CAPITAL LETTER SHORT U +04F1 ; [.144A.0020.0002.04F1] # CYRILLIC SMALL LETTER U WITH DIAERESIS +0443 0308 ; [.144A.0020.0002.04F1] # CYRILLIC SMALL LETTER U WITH DIAERESIS +04F0 ; [.144A.0020.0008.04F0] # CYRILLIC CAPITAL LETTER U WITH DIAERESIS +0423 0308 ; [.144A.0020.0008.04F0] # CYRILLIC CAPITAL LETTER U WITH DIAERESIS +04F3 ; [.144E.0020.0002.04F3] # CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE +0443 030B ; [.144E.0020.0002.04F3] # CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE +04F2 ; [.144E.0020.0008.04F2] # CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE +0423 030B ; [.144E.0020.0008.04F2] # CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE +04AF ; [.1452.0020.0002.04AF] # CYRILLIC SMALL LETTER STRAIGHT U +04AE ; [.1452.0020.0008.04AE] # CYRILLIC CAPITAL LETTER STRAIGHT U +04B1 ; [.1456.0020.0002.04B1] # CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE +04B0 ; [.1456.0020.0008.04B0] # CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE +0479 ; [.145A.0020.0002.0479] # CYRILLIC SMALL LETTER UK +0478 ; [.145A.0020.0008.0478] # CYRILLIC CAPITAL LETTER UK +0444 ; [.145E.0020.0002.0444] # CYRILLIC SMALL LETTER EF +0424 ; [.145E.0020.0008.0424] # CYRILLIC CAPITAL LETTER EF +0445 ; [.1462.0020.0002.0445] # CYRILLIC SMALL LETTER HA +0425 ; [.1462.0020.0008.0425] # CYRILLIC CAPITAL LETTER HA +04FD ; [.1466.0020.0002.04FD] # CYRILLIC SMALL LETTER HA WITH HOOK +04FC ; [.1466.0020.0008.04FC] # CYRILLIC CAPITAL LETTER HA WITH HOOK +04FF ; [.146A.0020.0002.04FF] # CYRILLIC SMALL LETTER HA WITH STROKE +04FE ; [.146A.0020.0008.04FE] # CYRILLIC CAPITAL LETTER HA WITH STROKE +04B3 ; [.146E.0020.0002.04B3] # CYRILLIC SMALL LETTER HA WITH DESCENDER +04B2 ; [.146E.0020.0008.04B2] # CYRILLIC CAPITAL LETTER HA WITH DESCENDER +04BB ; [.1472.0020.0002.04BB] # CYRILLIC SMALL LETTER SHHA +04BA ; [.1472.0020.0008.04BA] # CYRILLIC CAPITAL LETTER SHHA +0461 ; [.1476.0020.0002.0461] # CYRILLIC SMALL LETTER OMEGA +0460 ; [.1476.0020.0008.0460] # CYRILLIC CAPITAL LETTER OMEGA +047F ; [.147A.0020.0002.047F] # CYRILLIC SMALL LETTER OT +047E ; [.147A.0020.0008.047E] # CYRILLIC CAPITAL LETTER OT +047D ; [.147E.0020.0002.047D] # CYRILLIC SMALL LETTER OMEGA WITH TITLO +047C ; [.147E.0020.0008.047C] # CYRILLIC CAPITAL LETTER OMEGA WITH TITLO +047B ; [.1482.0020.0002.047B] # CYRILLIC SMALL LETTER ROUND OMEGA +047A ; [.1482.0020.0008.047A] # CYRILLIC CAPITAL LETTER ROUND OMEGA +0446 ; [.1486.0020.0002.0446] # CYRILLIC SMALL LETTER TSE +0426 ; [.1486.0020.0008.0426] # CYRILLIC CAPITAL LETTER TSE +04B5 ; [.148A.0020.0002.04B5] # CYRILLIC SMALL LIGATURE TE TSE +04B4 ; [.148A.0020.0008.04B4] # CYRILLIC CAPITAL LIGATURE TE TSE +0447 ; [.148E.0020.0002.0447] # CYRILLIC SMALL LETTER CHE +0427 ; [.148E.0020.0008.0427] # CYRILLIC CAPITAL LETTER CHE +04F5 ; [.1492.0020.0002.04F5] # CYRILLIC SMALL LETTER CHE WITH DIAERESIS +0447 0308 ; [.1492.0020.0002.04F5] # CYRILLIC SMALL LETTER CHE WITH DIAERESIS +04F4 ; [.1492.0020.0008.04F4] # CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS +0427 0308 ; [.1492.0020.0008.04F4] # CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS +04B7 ; [.1496.0020.0002.04B7] # CYRILLIC SMALL LETTER CHE WITH DESCENDER +04B6 ; [.1496.0020.0008.04B6] # CYRILLIC CAPITAL LETTER CHE WITH DESCENDER +04CC ; [.149A.0020.0002.04CC] # CYRILLIC SMALL LETTER KHAKASSIAN CHE +04CB ; [.149A.0020.0008.04CB] # CYRILLIC CAPITAL LETTER KHAKASSIAN CHE +04B9 ; [.149E.0020.0002.04B9] # CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE +04B8 ; [.149E.0020.0008.04B8] # CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE +04BD ; [.14A2.0020.0002.04BD] # CYRILLIC SMALL LETTER ABKHASIAN CHE +04BC ; [.14A2.0020.0008.04BC] # CYRILLIC CAPITAL LETTER ABKHASIAN CHE +04BF ; [.14A6.0020.0002.04BF] # CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER +04BE ; [.14A6.0020.0008.04BE] # CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER +045F ; [.14AA.0020.0002.045F] # CYRILLIC SMALL LETTER DZHE +040F ; [.14AA.0020.0008.040F] # CYRILLIC CAPITAL LETTER DZHE +0448 ; [.14AE.0020.0002.0448] # CYRILLIC SMALL LETTER SHA +0428 ; [.14AE.0020.0008.0428] # CYRILLIC CAPITAL LETTER SHA +0449 ; [.14B2.0020.0002.0449] # CYRILLIC SMALL LETTER SHCHA +0429 ; [.14B2.0020.0008.0429] # CYRILLIC CAPITAL LETTER SHCHA +044A ; [.14B6.0020.0002.044A] # CYRILLIC SMALL LETTER HARD SIGN +042A ; [.14B6.0020.0008.042A] # CYRILLIC CAPITAL LETTER HARD SIGN +044B ; [.14BA.0020.0002.044B] # CYRILLIC SMALL LETTER YERU +042B ; [.14BA.0020.0008.042B] # CYRILLIC CAPITAL LETTER YERU +04F9 ; [.14BE.0020.0002.04F9] # CYRILLIC SMALL LETTER YERU WITH DIAERESIS +044B 0308 ; [.14BE.0020.0002.04F9] # CYRILLIC SMALL LETTER YERU WITH DIAERESIS +04F8 ; [.14BE.0020.0008.04F8] # CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS +042B 0308 ; [.14BE.0020.0008.04F8] # CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS +044C ; [.14C2.0020.0002.044C] # CYRILLIC SMALL LETTER SOFT SIGN +042C ; [.14C2.0020.0008.042C] # CYRILLIC CAPITAL LETTER SOFT SIGN +048D ; [.14C6.0020.0002.048D] # CYRILLIC SMALL LETTER SEMISOFT SIGN +048C ; [.14C6.0020.0008.048C] # CYRILLIC CAPITAL LETTER SEMISOFT SIGN +0463 ; [.14CA.0020.0002.0463] # CYRILLIC SMALL LETTER YAT +0462 ; [.14CA.0020.0008.0462] # CYRILLIC CAPITAL LETTER YAT +044D ; [.14CE.0020.0002.044D] # CYRILLIC SMALL LETTER E +042D ; [.14CE.0020.0008.042D] # CYRILLIC CAPITAL LETTER E +04ED ; [.14D2.0020.0002.04ED] # CYRILLIC SMALL LETTER E WITH DIAERESIS +044D 0308 ; [.14D2.0020.0002.04ED] # CYRILLIC SMALL LETTER E WITH DIAERESIS +04EC ; [.14D2.0020.0008.04EC] # CYRILLIC CAPITAL LETTER E WITH DIAERESIS +042D 0308 ; [.14D2.0020.0008.04EC] # CYRILLIC CAPITAL LETTER E WITH DIAERESIS +044E ; [.14D6.0020.0002.044E] # CYRILLIC SMALL LETTER YU +042E ; [.14D6.0020.0008.042E] # CYRILLIC CAPITAL LETTER YU +044F ; [.14DA.0020.0002.044F] # CYRILLIC SMALL LETTER YA +042F ; [.14DA.0020.0008.042F] # CYRILLIC CAPITAL LETTER YA +0465 ; [.14DE.0020.0002.0465] # CYRILLIC SMALL LETTER IOTIFIED E +0464 ; [.14DE.0020.0008.0464] # CYRILLIC CAPITAL LETTER IOTIFIED E +0467 ; [.14E2.0020.0002.0467] # CYRILLIC SMALL LETTER LITTLE YUS +0466 ; [.14E2.0020.0008.0466] # CYRILLIC CAPITAL LETTER LITTLE YUS +046B ; [.14E6.0020.0002.046B] # CYRILLIC SMALL LETTER BIG YUS +046A ; [.14E6.0020.0008.046A] # CYRILLIC CAPITAL LETTER BIG YUS +0469 ; [.14EA.0020.0002.0469] # CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS +0468 ; [.14EA.0020.0008.0468] # CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS +046D ; [.14EE.0020.0002.046D] # CYRILLIC SMALL LETTER IOTIFIED BIG YUS +046C ; [.14EE.0020.0008.046C] # CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS +046F ; [.14F2.0020.0002.046F] # CYRILLIC SMALL LETTER KSI +046E ; [.14F2.0020.0008.046E] # CYRILLIC CAPITAL LETTER KSI +0471 ; [.14F6.0020.0002.0471] # CYRILLIC SMALL LETTER PSI +0470 ; [.14F6.0020.0008.0470] # CYRILLIC CAPITAL LETTER PSI +0473 ; [.14FA.0020.0002.0473] # CYRILLIC SMALL LETTER FITA +0472 ; [.14FA.0020.0008.0472] # CYRILLIC CAPITAL LETTER FITA +0475 ; [.14FE.0020.0002.0475] # CYRILLIC SMALL LETTER IZHITSA +0474 ; [.14FE.0020.0008.0474] # CYRILLIC CAPITAL LETTER IZHITSA +0477 ; [.1502.0020.0002.0477] # CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT +0475 030F ; [.1502.0020.0002.0477] # CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT +0476 ; [.1502.0020.0008.0476] # CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT +0474 030F ; [.1502.0020.0008.0476] # CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT +04A9 ; [.1506.0020.0002.04A9] # CYRILLIC SMALL LETTER ABKHASIAN HA +04A8 ; [.1506.0020.0008.04A8] # CYRILLIC CAPITAL LETTER ABKHASIAN HA +04CF ; [.150A.0020.0002.04CF] # CYRILLIC SMALL LETTER PALOCHKA +04C0 ; [.150A.0020.0008.04C0] # CYRILLIC LETTER PALOCHKA +2C30 ; [.150E.0020.0002.2C30] # GLAGOLITIC SMALL LETTER AZU +2C00 ; [.150E.0020.0008.2C00] # GLAGOLITIC CAPITAL LETTER AZU +2C31 ; [.150F.0020.0002.2C31] # GLAGOLITIC SMALL LETTER BUKY +2C01 ; [.150F.0020.0008.2C01] # GLAGOLITIC CAPITAL LETTER BUKY +2C32 ; [.1510.0020.0002.2C32] # GLAGOLITIC SMALL LETTER VEDE +2C02 ; [.1510.0020.0008.2C02] # GLAGOLITIC CAPITAL LETTER VEDE +2C33 ; [.1511.0020.0002.2C33] # GLAGOLITIC SMALL LETTER GLAGOLI +2C03 ; [.1511.0020.0008.2C03] # GLAGOLITIC CAPITAL LETTER GLAGOLI +2C34 ; [.1512.0020.0002.2C34] # GLAGOLITIC SMALL LETTER DOBRO +2C04 ; [.1512.0020.0008.2C04] # GLAGOLITIC CAPITAL LETTER DOBRO +2C35 ; [.1513.0020.0002.2C35] # GLAGOLITIC SMALL LETTER YESTU +2C05 ; [.1513.0020.0008.2C05] # GLAGOLITIC CAPITAL LETTER YESTU +2C36 ; [.1514.0020.0002.2C36] # GLAGOLITIC SMALL LETTER ZHIVETE +2C06 ; [.1514.0020.0008.2C06] # GLAGOLITIC CAPITAL LETTER ZHIVETE +2C37 ; [.1515.0020.0002.2C37] # GLAGOLITIC SMALL LETTER DZELO +2C07 ; [.1515.0020.0008.2C07] # GLAGOLITIC CAPITAL LETTER DZELO +2C38 ; [.1516.0020.0002.2C38] # GLAGOLITIC SMALL LETTER ZEMLJA +2C08 ; [.1516.0020.0008.2C08] # GLAGOLITIC CAPITAL LETTER ZEMLJA +2C39 ; [.1517.0020.0002.2C39] # GLAGOLITIC SMALL LETTER IZHE +2C09 ; [.1517.0020.0008.2C09] # GLAGOLITIC CAPITAL LETTER IZHE +2C3A ; [.1518.0020.0002.2C3A] # GLAGOLITIC SMALL LETTER INITIAL IZHE +2C0A ; [.1518.0020.0008.2C0A] # GLAGOLITIC CAPITAL LETTER INITIAL IZHE +2C3B ; [.1519.0020.0002.2C3B] # GLAGOLITIC SMALL LETTER I +2C0B ; [.1519.0020.0008.2C0B] # GLAGOLITIC CAPITAL LETTER I +2C3C ; [.151A.0020.0002.2C3C] # GLAGOLITIC SMALL LETTER DJERVI +2C0C ; [.151A.0020.0008.2C0C] # GLAGOLITIC CAPITAL LETTER DJERVI +2C3D ; [.151B.0020.0002.2C3D] # GLAGOLITIC SMALL LETTER KAKO +2C0D ; [.151B.0020.0008.2C0D] # GLAGOLITIC CAPITAL LETTER KAKO +2C3E ; [.151C.0020.0002.2C3E] # GLAGOLITIC SMALL LETTER LJUDIJE +2C0E ; [.151C.0020.0008.2C0E] # GLAGOLITIC CAPITAL LETTER LJUDIJE +2C3F ; [.151D.0020.0002.2C3F] # GLAGOLITIC SMALL LETTER MYSLITE +2C0F ; [.151D.0020.0008.2C0F] # GLAGOLITIC CAPITAL LETTER MYSLITE +2C40 ; [.151E.0020.0002.2C40] # GLAGOLITIC SMALL LETTER NASHI +2C10 ; [.151E.0020.0008.2C10] # GLAGOLITIC CAPITAL LETTER NASHI +2C41 ; [.151F.0020.0002.2C41] # GLAGOLITIC SMALL LETTER ONU +2C11 ; [.151F.0020.0008.2C11] # GLAGOLITIC CAPITAL LETTER ONU +2C42 ; [.1520.0020.0002.2C42] # GLAGOLITIC SMALL LETTER POKOJI +2C12 ; [.1520.0020.0008.2C12] # GLAGOLITIC CAPITAL LETTER POKOJI +2C43 ; [.1521.0020.0002.2C43] # GLAGOLITIC SMALL LETTER RITSI +2C13 ; [.1521.0020.0008.2C13] # GLAGOLITIC CAPITAL LETTER RITSI +2C44 ; [.1522.0020.0002.2C44] # GLAGOLITIC SMALL LETTER SLOVO +2C14 ; [.1522.0020.0008.2C14] # GLAGOLITIC CAPITAL LETTER SLOVO +2C45 ; [.1523.0020.0002.2C45] # GLAGOLITIC SMALL LETTER TVRIDO +2C15 ; [.1523.0020.0008.2C15] # GLAGOLITIC CAPITAL LETTER TVRIDO +2C46 ; [.1524.0020.0002.2C46] # GLAGOLITIC SMALL LETTER UKU +2C16 ; [.1524.0020.0008.2C16] # GLAGOLITIC CAPITAL LETTER UKU +2C47 ; [.1525.0020.0002.2C47] # GLAGOLITIC SMALL LETTER FRITU +2C17 ; [.1525.0020.0008.2C17] # GLAGOLITIC CAPITAL LETTER FRITU +2C48 ; [.1526.0020.0002.2C48] # GLAGOLITIC SMALL LETTER HERU +2C18 ; [.1526.0020.0008.2C18] # GLAGOLITIC CAPITAL LETTER HERU +2C49 ; [.1527.0020.0002.2C49] # GLAGOLITIC SMALL LETTER OTU +2C19 ; [.1527.0020.0008.2C19] # GLAGOLITIC CAPITAL LETTER OTU +2C4A ; [.1528.0020.0002.2C4A] # GLAGOLITIC SMALL LETTER PE +2C1A ; [.1528.0020.0008.2C1A] # GLAGOLITIC CAPITAL LETTER PE +2C4B ; [.1529.0020.0002.2C4B] # GLAGOLITIC SMALL LETTER SHTA +2C1B ; [.1529.0020.0008.2C1B] # GLAGOLITIC CAPITAL LETTER SHTA +2C4C ; [.152A.0020.0002.2C4C] # GLAGOLITIC SMALL LETTER TSI +2C1C ; [.152A.0020.0008.2C1C] # GLAGOLITIC CAPITAL LETTER TSI +2C4D ; [.152B.0020.0002.2C4D] # GLAGOLITIC SMALL LETTER CHRIVI +2C1D ; [.152B.0020.0008.2C1D] # GLAGOLITIC CAPITAL LETTER CHRIVI +2C4E ; [.152C.0020.0002.2C4E] # GLAGOLITIC SMALL LETTER SHA +2C1E ; [.152C.0020.0008.2C1E] # GLAGOLITIC CAPITAL LETTER SHA +2C4F ; [.152D.0020.0002.2C4F] # GLAGOLITIC SMALL LETTER YERU +2C1F ; [.152D.0020.0008.2C1F] # GLAGOLITIC CAPITAL LETTER YERU +2C50 ; [.152E.0020.0002.2C50] # GLAGOLITIC SMALL LETTER YERI +2C20 ; [.152E.0020.0008.2C20] # GLAGOLITIC CAPITAL LETTER YERI +2C51 ; [.152F.0020.0002.2C51] # GLAGOLITIC SMALL LETTER YATI +2C21 ; [.152F.0020.0008.2C21] # GLAGOLITIC CAPITAL LETTER YATI +2C52 ; [.1530.0020.0002.2C52] # GLAGOLITIC SMALL LETTER SPIDERY HA +2C22 ; [.1530.0020.0008.2C22] # GLAGOLITIC CAPITAL LETTER SPIDERY HA +2C53 ; [.1531.0020.0002.2C53] # GLAGOLITIC SMALL LETTER YU +2C23 ; [.1531.0020.0008.2C23] # GLAGOLITIC CAPITAL LETTER YU +2C54 ; [.1532.0020.0002.2C54] # GLAGOLITIC SMALL LETTER SMALL YUS +2C24 ; [.1532.0020.0008.2C24] # GLAGOLITIC CAPITAL LETTER SMALL YUS +2C55 ; [.1533.0020.0002.2C55] # GLAGOLITIC SMALL LETTER SMALL YUS WITH TAIL +2C25 ; [.1533.0020.0008.2C25] # GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL +2C56 ; [.1534.0020.0002.2C56] # GLAGOLITIC SMALL LETTER YO +2C26 ; [.1534.0020.0008.2C26] # GLAGOLITIC CAPITAL LETTER YO +2C57 ; [.1535.0020.0002.2C57] # GLAGOLITIC SMALL LETTER IOTATED SMALL YUS +2C27 ; [.1535.0020.0008.2C27] # GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS +2C58 ; [.1536.0020.0002.2C58] # GLAGOLITIC SMALL LETTER BIG YUS +2C28 ; [.1536.0020.0008.2C28] # GLAGOLITIC CAPITAL LETTER BIG YUS +2C59 ; [.1537.0020.0002.2C59] # GLAGOLITIC SMALL LETTER IOTATED BIG YUS +2C29 ; [.1537.0020.0008.2C29] # GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS +2C5A ; [.1538.0020.0002.2C5A] # GLAGOLITIC SMALL LETTER FITA +2C2A ; [.1538.0020.0008.2C2A] # GLAGOLITIC CAPITAL LETTER FITA +2C5B ; [.1539.0020.0002.2C5B] # GLAGOLITIC SMALL LETTER IZHITSA +2C2B ; [.1539.0020.0008.2C2B] # GLAGOLITIC CAPITAL LETTER IZHITSA +2C5C ; [.153A.0020.0002.2C5C] # GLAGOLITIC SMALL LETTER SHTAPIC +2C2C ; [.153A.0020.0008.2C2C] # GLAGOLITIC CAPITAL LETTER SHTAPIC +2C5D ; [.153B.0020.0002.2C5D] # GLAGOLITIC SMALL LETTER TROKUTASTI A +2C2D ; [.153B.0020.0008.2C2D] # GLAGOLITIC CAPITAL LETTER TROKUTASTI A +2C5E ; [.153C.0020.0002.2C5E] # GLAGOLITIC SMALL LETTER LATINATE MYSLITE +2C2E ; [.153C.0020.0008.2C2E] # GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE +10D0 ; [.153D.0020.0002.10D0] # GEORGIAN LETTER AN +2D00 ; [.153E.0020.0002.2D00] # GEORGIAN SMALL LETTER AN +10A0 ; [.153E.0020.0008.10A0] # GEORGIAN CAPITAL LETTER AN +10D1 ; [.153F.0020.0002.10D1] # GEORGIAN LETTER BAN +2D01 ; [.1540.0020.0002.2D01] # GEORGIAN SMALL LETTER BAN +10A1 ; [.1540.0020.0008.10A1] # GEORGIAN CAPITAL LETTER BAN +10D2 ; [.1541.0020.0002.10D2] # GEORGIAN LETTER GAN +2D02 ; [.1542.0020.0002.2D02] # GEORGIAN SMALL LETTER GAN +10A2 ; [.1542.0020.0008.10A2] # GEORGIAN CAPITAL LETTER GAN +10D3 ; [.1543.0020.0002.10D3] # GEORGIAN LETTER DON +2D03 ; [.1544.0020.0002.2D03] # GEORGIAN SMALL LETTER DON +10A3 ; [.1544.0020.0008.10A3] # GEORGIAN CAPITAL LETTER DON +10D4 ; [.1545.0020.0002.10D4] # GEORGIAN LETTER EN +2D04 ; [.1546.0020.0002.2D04] # GEORGIAN SMALL LETTER EN +10A4 ; [.1546.0020.0008.10A4] # GEORGIAN CAPITAL LETTER EN +10D5 ; [.1547.0020.0002.10D5] # GEORGIAN LETTER VIN +2D05 ; [.1548.0020.0002.2D05] # GEORGIAN SMALL LETTER VIN +10A5 ; [.1548.0020.0008.10A5] # GEORGIAN CAPITAL LETTER VIN +10D6 ; [.1549.0020.0002.10D6] # GEORGIAN LETTER ZEN +2D06 ; [.154A.0020.0002.2D06] # GEORGIAN SMALL LETTER ZEN +10A6 ; [.154A.0020.0008.10A6] # GEORGIAN CAPITAL LETTER ZEN +10F1 ; [.154B.0020.0002.10F1] # GEORGIAN LETTER HE +2D21 ; [.154C.0020.0002.2D21] # GEORGIAN SMALL LETTER HE +10C1 ; [.154C.0020.0008.10C1] # GEORGIAN CAPITAL LETTER HE +10D7 ; [.154D.0020.0002.10D7] # GEORGIAN LETTER TAN +2D07 ; [.154E.0020.0002.2D07] # GEORGIAN SMALL LETTER TAN +10A7 ; [.154E.0020.0008.10A7] # GEORGIAN CAPITAL LETTER TAN +10D8 ; [.154F.0020.0002.10D8] # GEORGIAN LETTER IN +2D08 ; [.1550.0020.0002.2D08] # GEORGIAN SMALL LETTER IN +10A8 ; [.1550.0020.0008.10A8] # GEORGIAN CAPITAL LETTER IN +10D9 ; [.1551.0020.0002.10D9] # GEORGIAN LETTER KAN +2D09 ; [.1552.0020.0002.2D09] # GEORGIAN SMALL LETTER KAN +10A9 ; [.1552.0020.0008.10A9] # GEORGIAN CAPITAL LETTER KAN +10DA ; [.1553.0020.0002.10DA] # GEORGIAN LETTER LAS +2D0A ; [.1554.0020.0002.2D0A] # GEORGIAN SMALL LETTER LAS +10AA ; [.1554.0020.0008.10AA] # GEORGIAN CAPITAL LETTER LAS +10DB ; [.1555.0020.0002.10DB] # GEORGIAN LETTER MAN +2D0B ; [.1556.0020.0002.2D0B] # GEORGIAN SMALL LETTER MAN +10AB ; [.1556.0020.0008.10AB] # GEORGIAN CAPITAL LETTER MAN +10DC ; [.1557.0020.0002.10DC] # GEORGIAN LETTER NAR +10FC ; [.1557.0020.0014.10FC] # MODIFIER LETTER GEORGIAN NAR; QQK +2D0C ; [.1558.0020.0002.2D0C] # GEORGIAN SMALL LETTER NAR +10AC ; [.1558.0020.0008.10AC] # GEORGIAN CAPITAL LETTER NAR +10F2 ; [.1559.0020.0002.10F2] # GEORGIAN LETTER HIE +2D22 ; [.155A.0020.0002.2D22] # GEORGIAN SMALL LETTER HIE +10C2 ; [.155A.0020.0008.10C2] # GEORGIAN CAPITAL LETTER HIE +10DD ; [.155B.0020.0002.10DD] # GEORGIAN LETTER ON +2D0D ; [.155C.0020.0002.2D0D] # GEORGIAN SMALL LETTER ON +10AD ; [.155C.0020.0008.10AD] # GEORGIAN CAPITAL LETTER ON +10DE ; [.155D.0020.0002.10DE] # GEORGIAN LETTER PAR +2D0E ; [.155E.0020.0002.2D0E] # GEORGIAN SMALL LETTER PAR +10AE ; [.155E.0020.0008.10AE] # GEORGIAN CAPITAL LETTER PAR +10DF ; [.155F.0020.0002.10DF] # GEORGIAN LETTER ZHAR +2D0F ; [.1560.0020.0002.2D0F] # GEORGIAN SMALL LETTER ZHAR +10AF ; [.1560.0020.0008.10AF] # GEORGIAN CAPITAL LETTER ZHAR +10E0 ; [.1561.0020.0002.10E0] # GEORGIAN LETTER RAE +2D10 ; [.1562.0020.0002.2D10] # GEORGIAN SMALL LETTER RAE +10B0 ; [.1562.0020.0008.10B0] # GEORGIAN CAPITAL LETTER RAE +10E1 ; [.1563.0020.0002.10E1] # GEORGIAN LETTER SAN +2D11 ; [.1564.0020.0002.2D11] # GEORGIAN SMALL LETTER SAN +10B1 ; [.1564.0020.0008.10B1] # GEORGIAN CAPITAL LETTER SAN +10E2 ; [.1565.0020.0002.10E2] # GEORGIAN LETTER TAR +2D12 ; [.1566.0020.0002.2D12] # GEORGIAN SMALL LETTER TAR +10B2 ; [.1566.0020.0008.10B2] # GEORGIAN CAPITAL LETTER TAR +10F3 ; [.1567.0020.0002.10F3] # GEORGIAN LETTER WE +2D23 ; [.1568.0020.0002.2D23] # GEORGIAN SMALL LETTER WE +10C3 ; [.1568.0020.0008.10C3] # GEORGIAN CAPITAL LETTER WE +10E3 ; [.1569.0020.0002.10E3] # GEORGIAN LETTER UN +2D13 ; [.156A.0020.0002.2D13] # GEORGIAN SMALL LETTER UN +10B3 ; [.156A.0020.0008.10B3] # GEORGIAN CAPITAL LETTER UN +10E4 ; [.156B.0020.0002.10E4] # GEORGIAN LETTER PHAR +2D14 ; [.156C.0020.0002.2D14] # GEORGIAN SMALL LETTER PHAR +10B4 ; [.156C.0020.0008.10B4] # GEORGIAN CAPITAL LETTER PHAR +10E5 ; [.156D.0020.0002.10E5] # GEORGIAN LETTER KHAR +2D15 ; [.156E.0020.0002.2D15] # GEORGIAN SMALL LETTER KHAR +10B5 ; [.156E.0020.0008.10B5] # GEORGIAN CAPITAL LETTER KHAR +10E6 ; [.156F.0020.0002.10E6] # GEORGIAN LETTER GHAN +2D16 ; [.1570.0020.0002.2D16] # GEORGIAN SMALL LETTER GHAN +10B6 ; [.1570.0020.0008.10B6] # GEORGIAN CAPITAL LETTER GHAN +10E7 ; [.1571.0020.0002.10E7] # GEORGIAN LETTER QAR +2D17 ; [.1572.0020.0002.2D17] # GEORGIAN SMALL LETTER QAR +10B7 ; [.1572.0020.0008.10B7] # GEORGIAN CAPITAL LETTER QAR +10E8 ; [.1573.0020.0002.10E8] # GEORGIAN LETTER SHIN +2D18 ; [.1574.0020.0002.2D18] # GEORGIAN SMALL LETTER SHIN +10B8 ; [.1574.0020.0008.10B8] # GEORGIAN CAPITAL LETTER SHIN +10E9 ; [.1575.0020.0002.10E9] # GEORGIAN LETTER CHIN +2D19 ; [.1576.0020.0002.2D19] # GEORGIAN SMALL LETTER CHIN +10B9 ; [.1576.0020.0008.10B9] # GEORGIAN CAPITAL LETTER CHIN +10EA ; [.1577.0020.0002.10EA] # GEORGIAN LETTER CAN +2D1A ; [.1578.0020.0002.2D1A] # GEORGIAN SMALL LETTER CAN +10BA ; [.1578.0020.0008.10BA] # GEORGIAN CAPITAL LETTER CAN +10EB ; [.1579.0020.0002.10EB] # GEORGIAN LETTER JIL +2D1B ; [.157A.0020.0002.2D1B] # GEORGIAN SMALL LETTER JIL +10BB ; [.157A.0020.0008.10BB] # GEORGIAN CAPITAL LETTER JIL +10EC ; [.157B.0020.0002.10EC] # GEORGIAN LETTER CIL +2D1C ; [.157C.0020.0002.2D1C] # GEORGIAN SMALL LETTER CIL +10BC ; [.157C.0020.0008.10BC] # GEORGIAN CAPITAL LETTER CIL +10ED ; [.157D.0020.0002.10ED] # GEORGIAN LETTER CHAR +2D1D ; [.157E.0020.0002.2D1D] # GEORGIAN SMALL LETTER CHAR +10BD ; [.157E.0020.0008.10BD] # GEORGIAN CAPITAL LETTER CHAR +10EE ; [.157F.0020.0002.10EE] # GEORGIAN LETTER XAN +2D1E ; [.1580.0020.0002.2D1E] # GEORGIAN SMALL LETTER XAN +10BE ; [.1580.0020.0008.10BE] # GEORGIAN CAPITAL LETTER XAN +10F4 ; [.1581.0020.0002.10F4] # GEORGIAN LETTER HAR +2D24 ; [.1582.0020.0002.2D24] # GEORGIAN SMALL LETTER HAR +10C4 ; [.1582.0020.0008.10C4] # GEORGIAN CAPITAL LETTER HAR +10EF ; [.1583.0020.0002.10EF] # GEORGIAN LETTER JHAN +2D1F ; [.1584.0020.0002.2D1F] # GEORGIAN SMALL LETTER JHAN +10BF ; [.1584.0020.0008.10BF] # GEORGIAN CAPITAL LETTER JHAN +10F0 ; [.1585.0020.0002.10F0] # GEORGIAN LETTER HAE +2D20 ; [.1586.0020.0002.2D20] # GEORGIAN SMALL LETTER HAE +10C0 ; [.1586.0020.0008.10C0] # GEORGIAN CAPITAL LETTER HAE +10F5 ; [.1587.0020.0002.10F5] # GEORGIAN LETTER HOE +2D25 ; [.1588.0020.0002.2D25] # GEORGIAN SMALL LETTER HOE +10C5 ; [.1588.0020.0008.10C5] # GEORGIAN CAPITAL LETTER HOE +10F6 ; [.1589.0020.0002.10F6] # GEORGIAN LETTER FI +10F7 ; [.158A.0020.0002.10F7] # GEORGIAN LETTER YN +10F8 ; [.158B.0020.0002.10F8] # GEORGIAN LETTER ELIFI +10F9 ; [.158C.0020.0002.10F9] # GEORGIAN LETTER TURNED GAN +10FA ; [.158D.0020.0002.10FA] # GEORGIAN LETTER AIN +0561 ; [.158E.0020.0002.0561] # ARMENIAN SMALL LETTER AYB +0531 ; [.158E.0020.0008.0531] # ARMENIAN CAPITAL LETTER AYB +0562 ; [.158F.0020.0002.0562] # ARMENIAN SMALL LETTER BEN +0532 ; [.158F.0020.0008.0532] # ARMENIAN CAPITAL LETTER BEN +0563 ; [.1590.0020.0002.0563] # ARMENIAN SMALL LETTER GIM +0533 ; [.1590.0020.0008.0533] # ARMENIAN CAPITAL LETTER GIM +0564 ; [.1591.0020.0002.0564] # ARMENIAN SMALL LETTER DA +0534 ; [.1591.0020.0008.0534] # ARMENIAN CAPITAL LETTER DA +0565 ; [.1592.0020.0002.0565] # ARMENIAN SMALL LETTER ECH +0535 ; [.1592.0020.0008.0535] # ARMENIAN CAPITAL LETTER ECH +0587 ; [.1592.0020.0004.0587][.15AF.0020.0004.0587] # ARMENIAN SMALL LIGATURE ECH YIWN; QQKN +0566 ; [.1593.0020.0002.0566] # ARMENIAN SMALL LETTER ZA +0536 ; [.1593.0020.0008.0536] # ARMENIAN CAPITAL LETTER ZA +0567 ; [.1594.0020.0002.0567] # ARMENIAN SMALL LETTER EH +0537 ; [.1594.0020.0008.0537] # ARMENIAN CAPITAL LETTER EH +0568 ; [.1595.0020.0002.0568] # ARMENIAN SMALL LETTER ET +0538 ; [.1595.0020.0008.0538] # ARMENIAN CAPITAL LETTER ET +0569 ; [.1596.0020.0002.0569] # ARMENIAN SMALL LETTER TO +0539 ; [.1596.0020.0008.0539] # ARMENIAN CAPITAL LETTER TO +056A ; [.1597.0020.0002.056A] # ARMENIAN SMALL LETTER ZHE +053A ; [.1597.0020.0008.053A] # ARMENIAN CAPITAL LETTER ZHE +056B ; [.1598.0020.0002.056B] # ARMENIAN SMALL LETTER INI +053B ; [.1598.0020.0008.053B] # ARMENIAN CAPITAL LETTER INI +056C ; [.1599.0020.0002.056C] # ARMENIAN SMALL LETTER LIWN +053C ; [.1599.0020.0008.053C] # ARMENIAN CAPITAL LETTER LIWN +056D ; [.159A.0020.0002.056D] # ARMENIAN SMALL LETTER XEH +053D ; [.159A.0020.0008.053D] # ARMENIAN CAPITAL LETTER XEH +056E ; [.159B.0020.0002.056E] # ARMENIAN SMALL LETTER CA +053E ; [.159B.0020.0008.053E] # ARMENIAN CAPITAL LETTER CA +056F ; [.159C.0020.0002.056F] # ARMENIAN SMALL LETTER KEN +053F ; [.159C.0020.0008.053F] # ARMENIAN CAPITAL LETTER KEN +0570 ; [.159D.0020.0002.0570] # ARMENIAN SMALL LETTER HO +0540 ; [.159D.0020.0008.0540] # ARMENIAN CAPITAL LETTER HO +0571 ; [.159E.0020.0002.0571] # ARMENIAN SMALL LETTER JA +0541 ; [.159E.0020.0008.0541] # ARMENIAN CAPITAL LETTER JA +0572 ; [.159F.0020.0002.0572] # ARMENIAN SMALL LETTER GHAD +0542 ; [.159F.0020.0008.0542] # ARMENIAN CAPITAL LETTER GHAD +0573 ; [.15A0.0020.0002.0573] # ARMENIAN SMALL LETTER CHEH +0543 ; [.15A0.0020.0008.0543] # ARMENIAN CAPITAL LETTER CHEH +0574 ; [.15A1.0020.0002.0574] # ARMENIAN SMALL LETTER MEN +0544 ; [.15A1.0020.0008.0544] # ARMENIAN CAPITAL LETTER MEN +FB14 ; [.15A1.0020.0004.FB14][.1592.0020.0004.FB14] # ARMENIAN SMALL LIGATURE MEN ECH; QQKN +FB15 ; [.15A1.0020.0004.FB15][.1598.0020.0004.FB15] # ARMENIAN SMALL LIGATURE MEN INI; QQKN +FB17 ; [.15A1.0020.0004.FB17][.159A.0020.0004.FB17] # ARMENIAN SMALL LIGATURE MEN XEH; QQKN +FB13 ; [.15A1.0020.0004.FB13][.15A3.0020.0004.FB13] # ARMENIAN SMALL LIGATURE MEN NOW; QQKN +0575 ; [.15A2.0020.0002.0575] # ARMENIAN SMALL LETTER YI +0545 ; [.15A2.0020.0008.0545] # ARMENIAN CAPITAL LETTER YI +0576 ; [.15A3.0020.0002.0576] # ARMENIAN SMALL LETTER NOW +0546 ; [.15A3.0020.0008.0546] # ARMENIAN CAPITAL LETTER NOW +0577 ; [.15A4.0020.0002.0577] # ARMENIAN SMALL LETTER SHA +0547 ; [.15A4.0020.0008.0547] # ARMENIAN CAPITAL LETTER SHA +0578 ; [.15A5.0020.0002.0578] # ARMENIAN SMALL LETTER VO +0548 ; [.15A5.0020.0008.0548] # ARMENIAN CAPITAL LETTER VO +0579 ; [.15A6.0020.0002.0579] # ARMENIAN SMALL LETTER CHA +0549 ; [.15A6.0020.0008.0549] # ARMENIAN CAPITAL LETTER CHA +057A ; [.15A7.0020.0002.057A] # ARMENIAN SMALL LETTER PEH +054A ; [.15A7.0020.0008.054A] # ARMENIAN CAPITAL LETTER PEH +057B ; [.15A8.0020.0002.057B] # ARMENIAN SMALL LETTER JHEH +054B ; [.15A8.0020.0008.054B] # ARMENIAN CAPITAL LETTER JHEH +057C ; [.15A9.0020.0002.057C] # ARMENIAN SMALL LETTER RA +054C ; [.15A9.0020.0008.054C] # ARMENIAN CAPITAL LETTER RA +057D ; [.15AA.0020.0002.057D] # ARMENIAN SMALL LETTER SEH +054D ; [.15AA.0020.0008.054D] # ARMENIAN CAPITAL LETTER SEH +057E ; [.15AB.0020.0002.057E] # ARMENIAN SMALL LETTER VEW +054E ; [.15AB.0020.0008.054E] # ARMENIAN CAPITAL LETTER VEW +FB16 ; [.15AB.0020.0004.FB16][.15A3.0020.0004.FB16] # ARMENIAN SMALL LIGATURE VEW NOW; QQKN +057F ; [.15AC.0020.0002.057F] # ARMENIAN SMALL LETTER TIWN +054F ; [.15AC.0020.0008.054F] # ARMENIAN CAPITAL LETTER TIWN +0580 ; [.15AD.0020.0002.0580] # ARMENIAN SMALL LETTER REH +0550 ; [.15AD.0020.0008.0550] # ARMENIAN CAPITAL LETTER REH +0581 ; [.15AE.0020.0002.0581] # ARMENIAN SMALL LETTER CO +0551 ; [.15AE.0020.0008.0551] # ARMENIAN CAPITAL LETTER CO +0582 ; [.15AF.0020.0002.0582] # ARMENIAN SMALL LETTER YIWN +0552 ; [.15AF.0020.0008.0552] # ARMENIAN CAPITAL LETTER YIWN +0583 ; [.15B0.0020.0002.0583] # ARMENIAN SMALL LETTER PIWR +0553 ; [.15B0.0020.0008.0553] # ARMENIAN CAPITAL LETTER PIWR +0584 ; [.15B1.0020.0002.0584] # ARMENIAN SMALL LETTER KEH +0554 ; [.15B1.0020.0008.0554] # ARMENIAN CAPITAL LETTER KEH +0585 ; [.15B2.0020.0002.0585] # ARMENIAN SMALL LETTER OH +0555 ; [.15B2.0020.0008.0555] # ARMENIAN CAPITAL LETTER OH +0586 ; [.15B3.0020.0002.0586] # ARMENIAN SMALL LETTER FEH +0556 ; [.15B3.0020.0008.0556] # ARMENIAN CAPITAL LETTER FEH +0559 ; [.15B4.0020.0002.0559] # ARMENIAN MODIFIER LETTER LEFT HALF RING +05D0 ; [.15B5.0020.0002.05D0] # HEBREW LETTER ALEF +2135 ; [.15B5.0020.0004.2135] # ALEF SYMBOL; QQK +FB21 ; [.15B5.0020.0005.FB21] # HEBREW LETTER WIDE ALEF; QQK +FB2E ; [.15B5.0020.0002.05D0][.0000.00CC.0002.05B7] # HEBREW LETTER ALEF WITH PATAH; QQCM +FB2F ; [.15B5.0020.0002.05D0][.0000.00CD.0002.05B8] # HEBREW LETTER ALEF WITH QAMATS; QQCM +FB30 ; [.15B5.0020.0002.05D0][.0000.00D4.0002.05BC] # HEBREW LETTER ALEF WITH MAPIQ; QQCM +FB4F ; [.15B5.0020.0004.FB4F][.15C0.0020.0004.FB4F] # HEBREW LIGATURE ALEF LAMED; QQKN +05D1 ; [.15B6.0020.0002.05D1] # HEBREW LETTER BET +2136 ; [.15B6.0020.0004.2136] # BET SYMBOL; QQK +FB31 ; [.15B6.0020.0002.05D1][.0000.00D4.0002.05BC] # HEBREW LETTER BET WITH DAGESH; QQCM +FB4C ; [.15B6.0020.0002.05D1][.0000.00D7.0002.05BF] # HEBREW LETTER BET WITH RAFE; QQCM +05D2 ; [.15B7.0020.0002.05D2] # HEBREW LETTER GIMEL +2137 ; [.15B7.0020.0004.2137] # GIMEL SYMBOL; QQK +FB32 ; [.15B7.0020.0002.05D2][.0000.00D4.0002.05BC] # HEBREW LETTER GIMEL WITH DAGESH; QQCM +05D3 ; [.15B8.0020.0002.05D3] # HEBREW LETTER DALET +2138 ; [.15B8.0020.0004.2138] # DALET SYMBOL; QQK +FB22 ; [.15B8.0020.0005.FB22] # HEBREW LETTER WIDE DALET; QQK +FB33 ; [.15B8.0020.0002.05D3][.0000.00D4.0002.05BC] # HEBREW LETTER DALET WITH DAGESH; QQCM +05D4 ; [.15B9.0020.0002.05D4] # HEBREW LETTER HE +FB23 ; [.15B9.0020.0005.FB23] # HEBREW LETTER WIDE HE; QQK +FB34 ; [.15B9.0020.0002.05D4][.0000.00D4.0002.05BC] # HEBREW LETTER HE WITH MAPIQ; QQCM +05D5 ; [.15BA.0020.0002.05D5] # HEBREW LETTER VAV +FB4B ; [.15BA.0020.0002.05D5][.0000.00CF.0002.05B9] # HEBREW LETTER VAV WITH HOLAM; QQCM +FB35 ; [.15BA.0020.0002.05D5][.0000.00D4.0002.05BC] # HEBREW LETTER VAV WITH DAGESH; QQCM +05F0 ; [.15BA.0020.0004.05F0][.15BA.0020.0004.05F0] # HEBREW LIGATURE YIDDISH DOUBLE VAV; QQKN +05F1 ; [.15BA.0020.0004.05F1][.15BE.0020.0004.05F1] # HEBREW LIGATURE YIDDISH VAV YOD; QQKN +05D6 ; [.15BB.0020.0002.05D6] # HEBREW LETTER ZAYIN +FB36 ; [.15BB.0020.0002.05D6][.0000.00D4.0002.05BC] # HEBREW LETTER ZAYIN WITH DAGESH; QQCM +05D7 ; [.15BC.0020.0002.05D7] # HEBREW LETTER HET +05D8 ; [.15BD.0020.0002.05D8] # HEBREW LETTER TET +FB38 ; [.15BD.0020.0002.05D8][.0000.00D4.0002.05BC] # HEBREW LETTER TET WITH DAGESH; QQCM +05D9 ; [.15BE.0020.0002.05D9] # HEBREW LETTER YOD +FB1D ; [.15BE.0020.0002.05D9][.0000.00C9.0002.05B4] # HEBREW LETTER YOD WITH HIRIQ; QQCM +FB39 ; [.15BE.0020.0002.05D9][.0000.00D4.0002.05BC] # HEBREW LETTER YOD WITH DAGESH; QQCM +05F2 ; [.15BE.0020.0004.05F2][.15BE.0020.0004.05F2] # HEBREW LIGATURE YIDDISH DOUBLE YOD; QQKN +FB1F ; [.15BE.0020.0004.FB1F][.15BE.0020.0004.FB1F][.0000.00CC.0002.FB1F] # HEBREW LIGATURE YIDDISH YOD YOD PATAH; QQKN +05DB ; [.15BF.0020.0002.05DB] # HEBREW LETTER KAF +FB24 ; [.15BF.0020.0005.FB24] # HEBREW LETTER WIDE KAF; QQK +05DA ; [.15BF.0020.0019.05DA] # HEBREW LETTER FINAL KAF; QQK +FB3B ; [.15BF.0020.0002.05DB][.0000.00D4.0002.05BC] # HEBREW LETTER KAF WITH DAGESH; QQCM +FB3A ; [.15BF.0020.0019.FB3A][.0000.00D4.0002.FB3A] # HEBREW LETTER FINAL KAF WITH DAGESH; QQKN +FB4D ; [.15BF.0020.0002.05DB][.0000.00D7.0002.05BF] # HEBREW LETTER KAF WITH RAFE; QQCM +05DC ; [.15C0.0020.0002.05DC] # HEBREW LETTER LAMED +FB25 ; [.15C0.0020.0005.FB25] # HEBREW LETTER WIDE LAMED; QQK +FB3C ; [.15C0.0020.0002.05DC][.0000.00D4.0002.05BC] # HEBREW LETTER LAMED WITH DAGESH; QQCM +05DE ; [.15C1.0020.0002.05DE] # HEBREW LETTER MEM +FB26 ; [.15C1.0020.0005.FB26] # HEBREW LETTER WIDE FINAL MEM; QQK +05DD ; [.15C1.0020.0019.05DD] # HEBREW LETTER FINAL MEM; QQK +FB3E ; [.15C1.0020.0002.05DE][.0000.00D4.0002.05BC] # HEBREW LETTER MEM WITH DAGESH; QQCM +05E0 ; [.15C2.0020.0002.05E0] # HEBREW LETTER NUN +05DF ; [.15C2.0020.0019.05DF] # HEBREW LETTER FINAL NUN; QQK +FB40 ; [.15C2.0020.0002.05E0][.0000.00D4.0002.05BC] # HEBREW LETTER NUN WITH DAGESH; QQCM +05E1 ; [.15C3.0020.0002.05E1] # HEBREW LETTER SAMEKH +FB41 ; [.15C3.0020.0002.05E1][.0000.00D4.0002.05BC] # HEBREW LETTER SAMEKH WITH DAGESH; QQCM +05E2 ; [.15C4.0020.0002.05E2] # HEBREW LETTER AYIN +FB20 ; [.15C4.0020.0005.FB20] # HEBREW LETTER ALTERNATIVE AYIN; QQK +05E4 ; [.15C5.0020.0002.05E4] # HEBREW LETTER PE +05E3 ; [.15C5.0020.0019.05E3] # HEBREW LETTER FINAL PE; QQK +FB44 ; [.15C5.0020.0002.05E4][.0000.00D4.0002.05BC] # HEBREW LETTER PE WITH DAGESH; QQCM +FB43 ; [.15C5.0020.0019.FB43][.0000.00D4.0002.FB43] # HEBREW LETTER FINAL PE WITH DAGESH; QQKN +FB4E ; [.15C5.0020.0002.05E4][.0000.00D7.0002.05BF] # HEBREW LETTER PE WITH RAFE; QQCM +05E6 ; [.15C6.0020.0002.05E6] # HEBREW LETTER TSADI +05E5 ; [.15C6.0020.0019.05E5] # HEBREW LETTER FINAL TSADI; QQK +FB46 ; [.15C6.0020.0002.05E6][.0000.00D4.0002.05BC] # HEBREW LETTER TSADI WITH DAGESH; QQCM +05E7 ; [.15C7.0020.0002.05E7] # HEBREW LETTER QOF +FB47 ; [.15C7.0020.0002.05E7][.0000.00D4.0002.05BC] # HEBREW LETTER QOF WITH DAGESH; QQCM +05E8 ; [.15C8.0020.0002.05E8] # HEBREW LETTER RESH +FB27 ; [.15C8.0020.0005.FB27] # HEBREW LETTER WIDE RESH; QQK +FB48 ; [.15C8.0020.0002.05E8][.0000.00D4.0002.05BC] # HEBREW LETTER RESH WITH DAGESH; QQCM +05E9 ; [.15C9.0020.0002.05E9] # HEBREW LETTER SHIN +FB2B ; [.15C9.0020.0002.05E9][.0000.00D2.0002.05C2] # HEBREW LETTER SHIN WITH SIN DOT; QQCM +FB2A ; [.15C9.0020.0002.05E9][.0000.00D3.0002.05C1] # HEBREW LETTER SHIN WITH SHIN DOT; QQCM +FB49 ; [.15C9.0020.0002.05E9][.0000.00D4.0002.05BC] # HEBREW LETTER SHIN WITH DAGESH; QQCM +FB2D ; [.15C9.0020.0002.05E9][.0000.00D4.0002.05BC][.0000.00D2.0002.05C2] # HEBREW LETTER SHIN WITH DAGESH AND SIN DOT; QQCM +FB2C ; [.15C9.0020.0002.05E9][.0000.00D4.0002.05BC][.0000.00D3.0002.05C1] # HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT; QQCM +05EA ; [.15CA.0020.0002.05EA] # HEBREW LETTER TAV +FB28 ; [.15CA.0020.0005.FB28] # HEBREW LETTER WIDE TAV; QQK +FB4A ; [.15CA.0020.0002.05EA][.0000.00D4.0002.05BC] # HEBREW LETTER TAV WITH DAGESH; QQCM +10900 ; [.15CB.0020.0002.10900] # PHOENICIAN LETTER ALF +10901 ; [.15CC.0020.0002.10901] # PHOENICIAN LETTER BET +10902 ; [.15CD.0020.0002.10902] # PHOENICIAN LETTER GAML +10903 ; [.15CE.0020.0002.10903] # PHOENICIAN LETTER DELT +10904 ; [.15CF.0020.0002.10904] # PHOENICIAN LETTER HE +10905 ; [.15D0.0020.0002.10905] # PHOENICIAN LETTER WAU +10906 ; [.15D1.0020.0002.10906] # PHOENICIAN LETTER ZAI +10907 ; [.15D2.0020.0002.10907] # PHOENICIAN LETTER HET +10908 ; [.15D3.0020.0002.10908] # PHOENICIAN LETTER TET +10909 ; [.15D4.0020.0002.10909] # PHOENICIAN LETTER YOD +1090A ; [.15D5.0020.0002.1090A] # PHOENICIAN LETTER KAF +1090B ; [.15D6.0020.0002.1090B] # PHOENICIAN LETTER LAMD +1090C ; [.15D7.0020.0002.1090C] # PHOENICIAN LETTER MEM +1090D ; [.15D8.0020.0002.1090D] # PHOENICIAN LETTER NUN +1090E ; [.15D9.0020.0002.1090E] # PHOENICIAN LETTER SEMK +1090F ; [.15DA.0020.0002.1090F] # PHOENICIAN LETTER AIN +10910 ; [.15DB.0020.0002.10910] # PHOENICIAN LETTER PE +10911 ; [.15DC.0020.0002.10911] # PHOENICIAN LETTER SADE +10912 ; [.15DD.0020.0002.10912] # PHOENICIAN LETTER QOF +10913 ; [.15DE.0020.0002.10913] # PHOENICIAN LETTER ROSH +10914 ; [.15DF.0020.0002.10914] # PHOENICIAN LETTER SHIN +10915 ; [.15E0.0020.0002.10915] # PHOENICIAN LETTER TAU +0621 ; [.15E1.0020.0002.0621] # ARABIC LETTER HAMZA +0674 ; [.15E1.0020.0004.0674] # ARABIC LETTER HIGH HAMZA; QQK +FE80 ; [.15E1.0020.001A.FE80] # ARABIC LETTER HAMZA ISOLATED FORM; QQK +06FD ; [.15E1.0020.0004.06FD][.0000.019A.0004.06FD] # ARABIC SIGN SINDHI AMPERSAND; QQKN +0622 ; [.15E2.0020.0002.0622] # ARABIC LETTER ALEF WITH MADDA ABOVE +0627 0653 ; [.15E2.0020.0002.0622] # ARABIC LETTER ALEF WITH MADDA ABOVE +FE82 ; [.15E2.0020.0019.FE82] # ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM; QQK +FE81 ; [.15E2.0020.001A.FE81] # ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM; QQK +0623 ; [.15E3.0020.0002.0623] # ARABIC LETTER ALEF WITH HAMZA ABOVE +0627 0654 ; [.15E3.0020.0002.0623] # ARABIC LETTER ALEF WITH HAMZA ABOVE +FE84 ; [.15E3.0020.0019.FE84] # ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM; QQK +FE83 ; [.15E3.0020.001A.FE83] # ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM; QQK +0672 ; [.15E4.0020.0002.0672] # ARABIC LETTER ALEF WITH WAVY HAMZA ABOVE +0671 ; [.15E5.0020.0002.0671] # ARABIC LETTER ALEF WASLA +FB51 ; [.15E5.0020.0019.FB51] # ARABIC LETTER ALEF WASLA FINAL FORM; QQK +FB50 ; [.15E5.0020.001A.FB50] # ARABIC LETTER ALEF WASLA ISOLATED FORM; QQK +0624 ; [.15E6.0020.0002.0624] # ARABIC LETTER WAW WITH HAMZA ABOVE +0648 0654 ; [.15E6.0020.0002.0624] # ARABIC LETTER WAW WITH HAMZA ABOVE +FE86 ; [.15E6.0020.0019.FE86] # ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM; QQK +FE85 ; [.15E6.0020.001A.FE85] # ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM; QQK +0625 ; [.15E7.0020.0002.0625] # ARABIC LETTER ALEF WITH HAMZA BELOW +0627 0655 ; [.15E7.0020.0002.0625] # ARABIC LETTER ALEF WITH HAMZA BELOW +FE88 ; [.15E7.0020.0019.FE88] # ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM; QQK +FE87 ; [.15E7.0020.001A.FE87] # ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM; QQK +0673 ; [.15E8.0020.0002.0673] # ARABIC LETTER ALEF WITH WAVY HAMZA BELOW +0626 ; [.15E9.0020.0002.0626] # ARABIC LETTER YEH WITH HAMZA ABOVE +064A 0654 ; [.15E9.0020.0002.0626] # ARABIC LETTER YEH WITH HAMZA ABOVE +FE8B ; [.15E9.0020.0017.FE8B] # ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM; QQK +FE8C ; [.15E9.0020.0018.FE8C] # ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM; QQK +FE8A ; [.15E9.0020.0019.FE8A] # ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM; QQK +FE89 ; [.15E9.0020.001A.FE89] # ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM; QQK +FBEB ; [.15E9.0020.0019.FBEB][.15EA.0020.0019.FBEB] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF FINAL FORM; QQKN +FBEA ; [.15E9.0020.001A.FBEA][.15EA.0020.001A.FBEA] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF ISOLATED FORM; QQKN +FC97 ; [.15E9.0020.0017.FC97][.15FF.0020.0017.FC97] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM INITIAL FORM; QQKN +FC00 ; [.15E9.0020.001A.FC00][.15FF.0020.001A.FC00] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM ISOLATED FORM; QQKN +FC98 ; [.15E9.0020.0017.FC98][.1605.0020.0017.FC98] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH INITIAL FORM; QQKN +FC01 ; [.15E9.0020.001A.FC01][.1605.0020.001A.FC01] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH ISOLATED FORM; QQKN +FC99 ; [.15E9.0020.0017.FC99][.1606.0020.0017.FC99] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH INITIAL FORM; QQKN +FC64 ; [.15E9.0020.0019.FC64][.161A.0020.0019.FC64] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORM; QQKN +FC65 ; [.15E9.0020.0019.FC65][.161B.0020.0019.FC65] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN FINAL FORM; QQKN +FC9A ; [.15E9.0020.0017.FC9A][.1663.0020.0017.FC9A] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM INITIAL FORM; QQKN +FCDF ; [.15E9.0020.0018.FCDF][.1663.0020.0018.FCDF] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM MEDIAL FORM; QQKN +FC66 ; [.15E9.0020.0019.FC66][.1663.0020.0019.FC66] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM FINAL FORM; QQKN +FC02 ; [.15E9.0020.001A.FC02][.1663.0020.001A.FC02] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM ISOLATED FORM; QQKN +FC67 ; [.15E9.0020.0019.FC67][.1666.0020.0019.FC67] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON FINAL FORM; QQKN +FC9B ; [.15E9.0020.0017.FC9B][.166F.0020.0017.FC9B] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH INITIAL FORM; QQKN +FCE0 ; [.15E9.0020.0018.FCE0][.166F.0020.0018.FCE0] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH MEDIAL FORM; QQKN +FBED ; [.15E9.0020.0019.FBED][.1674.0020.0019.FBED] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE FINAL FORM; QQKN +FBEC ; [.15E9.0020.001A.FBEC][.1674.0020.001A.FBEC] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE ISOLATED FORM; QQKN +FBEF ; [.15E9.0020.0019.FBEF][.1675.0020.0019.FBEF] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW FINAL FORM; QQKN +FBEE ; [.15E9.0020.001A.FBEE][.1675.0020.001A.FBEE] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW ISOLATED FORM; QQKN +FBF3 ; [.15E9.0020.0019.FBF3][.1678.0020.0019.FBF3] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE FINAL FORM; QQKN +FBF2 ; [.15E9.0020.001A.FBF2][.1678.0020.001A.FBF2] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE ISOLATED FORM; QQKN +FBF1 ; [.15E9.0020.0019.FBF1][.1679.0020.0019.FBF1] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U FINAL FORM; QQKN +FBF0 ; [.15E9.0020.001A.FBF0][.1679.0020.001A.FBF0] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U ISOLATED FORM; QQKN +FBF5 ; [.15E9.0020.0019.FBF5][.167A.0020.0019.FBF5] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU FINAL FORM; QQKN +FBF4 ; [.15E9.0020.001A.FBF4][.167A.0020.001A.FBF4] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU ISOLATED FORM; QQKN +FBFB ; [.15E9.0020.0017.FBFB][.167F.0020.0017.FBFB] # ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA INITIAL FORM; QQKN +FBFA ; [.15E9.0020.0019.FBFA][.167F.0020.0019.FBFA] # ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM; QQKN +FC68 ; [.15E9.0020.0019.FC68][.167F.0020.0019.FC68] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM; QQKN +FBF9 ; [.15E9.0020.001A.FBF9][.167F.0020.001A.FBF9] # ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM; QQKN +FC03 ; [.15E9.0020.001A.FC03][.167F.0020.001A.FC03] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM; QQKN +FC69 ; [.15E9.0020.0019.FC69][.1680.0020.0019.FC69] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH FINAL FORM; QQKN +FC04 ; [.15E9.0020.001A.FC04][.1680.0020.001A.FC04] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH ISOLATED FORM; QQKN +FBF8 ; [.15E9.0020.0017.FBF8][.1684.0020.0017.FBF8] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E INITIAL FORM; QQKN +FBF7 ; [.15E9.0020.0019.FBF7][.1684.0020.0019.FBF7] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E FINAL FORM; QQKN +FBF6 ; [.15E9.0020.001A.FBF6][.1684.0020.001A.FBF6] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E ISOLATED FORM; QQKN +0627 ; [.15EA.0020.0002.0627] # ARABIC LETTER ALEF +FE8E ; [.15EA.0020.0019.FE8E] # ARABIC LETTER ALEF FINAL FORM; QQK +FE8D ; [.15EA.0020.001A.FE8D] # ARABIC LETTER ALEF ISOLATED FORM; QQK +FD3C ; [.15EA.0020.0019.FD3C][.0000.00D9.0019.FD3C] # ARABIC LIGATURE ALEF WITH FATHATAN FINAL FORM; QQKN +FD3D ; [.15EA.0020.001A.FD3D][.0000.00D9.001A.FD3D] # ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM; QQKN +0675 ; [.15EA.0020.0004.0675][.15E1.0020.0004.0675] # ARABIC LETTER HIGH HAMZA ALEF; QQKN +FDF3 ; [.15EA.0020.001A.FDF3][.164D.0020.001A.FDF3][.15EC.0020.001F.FDF3][.161A.0020.001F.FDF3] # ARABIC LIGATURE AKBAR ISOLATED FORM; QQKN +FDF2 ; [.15EA.0020.001A.FDF2][.165D.0020.001A.FDF2][.165D.0020.001F.FDF2][.166F.0020.001F.FDF2] # ARABIC LIGATURE ALLAH ISOLATED FORM; QQKN +066E ; [.15EB.0020.0002.066E] # ARABIC LETTER DOTLESS BEH +0628 ; [.15EC.0020.0002.0628] # ARABIC LETTER BEH +FE91 ; [.15EC.0020.0017.FE91] # ARABIC LETTER BEH INITIAL FORM; QQK +FE92 ; [.15EC.0020.0018.FE92] # ARABIC LETTER BEH MEDIAL FORM; QQK +FE90 ; [.15EC.0020.0019.FE90] # ARABIC LETTER BEH FINAL FORM; QQK +FE8F ; [.15EC.0020.001A.FE8F] # ARABIC LETTER BEH ISOLATED FORM; QQK +FC9C ; [.15EC.0020.0017.FC9C][.15FF.0020.0017.FC9C] # ARABIC LIGATURE BEH WITH JEEM INITIAL FORM; QQKN +FC05 ; [.15EC.0020.001A.FC05][.15FF.0020.001A.FC05] # ARABIC LIGATURE BEH WITH JEEM ISOLATED FORM; QQKN +FC9D ; [.15EC.0020.0017.FC9D][.1605.0020.0017.FC9D] # ARABIC LIGATURE BEH WITH HAH INITIAL FORM; QQKN +FC06 ; [.15EC.0020.001A.FC06][.1605.0020.001A.FC06] # ARABIC LIGATURE BEH WITH HAH ISOLATED FORM; QQKN +FDC2 ; [.15EC.0020.0019.FDC2][.1605.0020.0019.FDC2][.1680.0020.001F.FDC2] # ARABIC LIGATURE BEH WITH HAH WITH YEH FINAL FORM; QQKN +FC9E ; [.15EC.0020.0017.FC9E][.1606.0020.0017.FC9E] # ARABIC LIGATURE BEH WITH KHAH INITIAL FORM; QQKN +FC07 ; [.15EC.0020.001A.FC07][.1606.0020.001A.FC07] # ARABIC LIGATURE BEH WITH KHAH ISOLATED FORM; QQKN +FD9E ; [.15EC.0020.0019.FD9E][.1606.0020.0019.FD9E][.1680.0020.001F.FD9E] # ARABIC LIGATURE BEH WITH KHAH WITH YEH FINAL FORM; QQKN +FC6A ; [.15EC.0020.0019.FC6A][.161A.0020.0019.FC6A] # ARABIC LIGATURE BEH WITH REH FINAL FORM; QQKN +FC6B ; [.15EC.0020.0019.FC6B][.161B.0020.0019.FC6B] # ARABIC LIGATURE BEH WITH ZAIN FINAL FORM; QQKN +FC9F ; [.15EC.0020.0017.FC9F][.1663.0020.0017.FC9F] # ARABIC LIGATURE BEH WITH MEEM INITIAL FORM; QQKN +FCE1 ; [.15EC.0020.0018.FCE1][.1663.0020.0018.FCE1] # ARABIC LIGATURE BEH WITH MEEM MEDIAL FORM; QQKN +FC6C ; [.15EC.0020.0019.FC6C][.1663.0020.0019.FC6C] # ARABIC LIGATURE BEH WITH MEEM FINAL FORM; QQKN +FC08 ; [.15EC.0020.001A.FC08][.1663.0020.001A.FC08] # ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM; QQKN +FC6D ; [.15EC.0020.0019.FC6D][.1666.0020.0019.FC6D] # ARABIC LIGATURE BEH WITH NOON FINAL FORM; QQKN +FCA0 ; [.15EC.0020.0017.FCA0][.166F.0020.0017.FCA0] # ARABIC LIGATURE BEH WITH HEH INITIAL FORM; QQKN +FCE2 ; [.15EC.0020.0018.FCE2][.166F.0020.0018.FCE2] # ARABIC LIGATURE BEH WITH HEH MEDIAL FORM; QQKN +FC6E ; [.15EC.0020.0019.FC6E][.167F.0020.0019.FC6E] # ARABIC LIGATURE BEH WITH ALEF MAKSURA FINAL FORM; QQKN +FC09 ; [.15EC.0020.001A.FC09][.167F.0020.001A.FC09] # ARABIC LIGATURE BEH WITH ALEF MAKSURA ISOLATED FORM; QQKN +FC6F ; [.15EC.0020.0019.FC6F][.1680.0020.0019.FC6F] # ARABIC LIGATURE BEH WITH YEH FINAL FORM; QQKN +FC0A ; [.15EC.0020.001A.FC0A][.1680.0020.001A.FC0A] # ARABIC LIGATURE BEH WITH YEH ISOLATED FORM; QQKN +067B ; [.15ED.0020.0002.067B] # ARABIC LETTER BEEH +FB54 ; [.15ED.0020.0017.FB54] # ARABIC LETTER BEEH INITIAL FORM; QQK +FB55 ; [.15ED.0020.0018.FB55] # ARABIC LETTER BEEH MEDIAL FORM; QQK +FB53 ; [.15ED.0020.0019.FB53] # ARABIC LETTER BEEH FINAL FORM; QQK +FB52 ; [.15ED.0020.001A.FB52] # ARABIC LETTER BEEH ISOLATED FORM; QQK +067E ; [.15EE.0020.0002.067E] # ARABIC LETTER PEH +FB58 ; [.15EE.0020.0017.FB58] # ARABIC LETTER PEH INITIAL FORM; QQK +FB59 ; [.15EE.0020.0018.FB59] # ARABIC LETTER PEH MEDIAL FORM; QQK +FB57 ; [.15EE.0020.0019.FB57] # ARABIC LETTER PEH FINAL FORM; QQK +FB56 ; [.15EE.0020.001A.FB56] # ARABIC LETTER PEH ISOLATED FORM; QQK +0680 ; [.15EF.0020.0002.0680] # ARABIC LETTER BEHEH +FB5C ; [.15EF.0020.0017.FB5C] # ARABIC LETTER BEHEH INITIAL FORM; QQK +FB5D ; [.15EF.0020.0018.FB5D] # ARABIC LETTER BEHEH MEDIAL FORM; QQK +FB5B ; [.15EF.0020.0019.FB5B] # ARABIC LETTER BEHEH FINAL FORM; QQK +FB5A ; [.15EF.0020.001A.FB5A] # ARABIC LETTER BEHEH ISOLATED FORM; QQK +0750 ; [.15F0.0020.0002.0750] # ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW +0751 ; [.15F1.0020.0002.0751] # ARABIC LETTER BEH WITH DOT BELOW AND THREE DOTS ABOVE +0752 ; [.15F2.0020.0002.0752] # ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW +0753 ; [.15F3.0020.0002.0753] # ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW AND TWO DOTS ABOVE +0754 ; [.15F4.0020.0002.0754] # ARABIC LETTER BEH WITH TWO DOTS BELOW AND DOT ABOVE +0755 ; [.15F5.0020.0002.0755] # ARABIC LETTER BEH WITH INVERTED SMALL V BELOW +0756 ; [.15F6.0020.0002.0756] # ARABIC LETTER BEH WITH SMALL V +0629 ; [.15F7.0020.0002.0629] # ARABIC LETTER TEH MARBUTA +FE94 ; [.15F7.0020.0019.FE94] # ARABIC LETTER TEH MARBUTA FINAL FORM; QQK +FE93 ; [.15F7.0020.001A.FE93] # ARABIC LETTER TEH MARBUTA ISOLATED FORM; QQK +062A ; [.15F8.0020.0002.062A] # ARABIC LETTER TEH +FE97 ; [.15F8.0020.0017.FE97] # ARABIC LETTER TEH INITIAL FORM; QQK +FE98 ; [.15F8.0020.0018.FE98] # ARABIC LETTER TEH MEDIAL FORM; QQK +FE96 ; [.15F8.0020.0019.FE96] # ARABIC LETTER TEH FINAL FORM; QQK +FE95 ; [.15F8.0020.001A.FE95] # ARABIC LETTER TEH ISOLATED FORM; QQK +FCA1 ; [.15F8.0020.0017.FCA1][.15FF.0020.0017.FCA1] # ARABIC LIGATURE TEH WITH JEEM INITIAL FORM; QQKN +FC0B ; [.15F8.0020.001A.FC0B][.15FF.0020.001A.FC0B] # ARABIC LIGATURE TEH WITH JEEM ISOLATED FORM; QQKN +FD50 ; [.15F8.0020.0017.FD50][.15FF.0020.0017.FD50][.1663.0020.001F.FD50] # ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM; QQKN +FDA0 ; [.15F8.0020.0019.FDA0][.15FF.0020.0019.FDA0][.167F.0020.001F.FDA0] # ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA FINAL FORM; QQKN +FD9F ; [.15F8.0020.0019.FD9F][.15FF.0020.0019.FD9F][.1680.0020.001F.FD9F] # ARABIC LIGATURE TEH WITH JEEM WITH YEH FINAL FORM; QQKN +FCA2 ; [.15F8.0020.0017.FCA2][.1605.0020.0017.FCA2] # ARABIC LIGATURE TEH WITH HAH INITIAL FORM; QQKN +FC0C ; [.15F8.0020.001A.FC0C][.1605.0020.001A.FC0C] # ARABIC LIGATURE TEH WITH HAH ISOLATED FORM; QQKN +FD52 ; [.15F8.0020.0017.FD52][.1605.0020.0017.FD52][.15FF.0020.001F.FD52] # ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORM; QQKN +FD51 ; [.15F8.0020.0019.FD51][.1605.0020.0019.FD51][.15FF.0020.001F.FD51] # ARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM; QQKN +FD53 ; [.15F8.0020.0017.FD53][.1605.0020.0017.FD53][.1663.0020.001F.FD53] # ARABIC LIGATURE TEH WITH HAH WITH MEEM INITIAL FORM; QQKN +FCA3 ; [.15F8.0020.0017.FCA3][.1606.0020.0017.FCA3] # ARABIC LIGATURE TEH WITH KHAH INITIAL FORM; QQKN +FC0D ; [.15F8.0020.001A.FC0D][.1606.0020.001A.FC0D] # ARABIC LIGATURE TEH WITH KHAH ISOLATED FORM; QQKN +FD54 ; [.15F8.0020.0017.FD54][.1606.0020.0017.FD54][.1663.0020.001F.FD54] # ARABIC LIGATURE TEH WITH KHAH WITH MEEM INITIAL FORM; QQKN +FDA2 ; [.15F8.0020.0019.FDA2][.1606.0020.0019.FDA2][.167F.0020.001F.FDA2] # ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA FINAL FORM; QQKN +FDA1 ; [.15F8.0020.0019.FDA1][.1606.0020.0019.FDA1][.1680.0020.001F.FDA1] # ARABIC LIGATURE TEH WITH KHAH WITH YEH FINAL FORM; QQKN +FC70 ; [.15F8.0020.0019.FC70][.161A.0020.0019.FC70] # ARABIC LIGATURE TEH WITH REH FINAL FORM; QQKN +FC71 ; [.15F8.0020.0019.FC71][.161B.0020.0019.FC71] # ARABIC LIGATURE TEH WITH ZAIN FINAL FORM; QQKN +FCA4 ; [.15F8.0020.0017.FCA4][.1663.0020.0017.FCA4] # ARABIC LIGATURE TEH WITH MEEM INITIAL FORM; QQKN +FCE3 ; [.15F8.0020.0018.FCE3][.1663.0020.0018.FCE3] # ARABIC LIGATURE TEH WITH MEEM MEDIAL FORM; QQKN +FC72 ; [.15F8.0020.0019.FC72][.1663.0020.0019.FC72] # ARABIC LIGATURE TEH WITH MEEM FINAL FORM; QQKN +FC0E ; [.15F8.0020.001A.FC0E][.1663.0020.001A.FC0E] # ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM; QQKN +FD55 ; [.15F8.0020.0017.FD55][.1663.0020.0017.FD55][.15FF.0020.001F.FD55] # ARABIC LIGATURE TEH WITH MEEM WITH JEEM INITIAL FORM; QQKN +FD56 ; [.15F8.0020.0017.FD56][.1663.0020.0017.FD56][.1605.0020.001F.FD56] # ARABIC LIGATURE TEH WITH MEEM WITH HAH INITIAL FORM; QQKN +FD57 ; [.15F8.0020.0017.FD57][.1663.0020.0017.FD57][.1606.0020.001F.FD57] # ARABIC LIGATURE TEH WITH MEEM WITH KHAH INITIAL FORM; QQKN +FDA4 ; [.15F8.0020.0019.FDA4][.1663.0020.0019.FDA4][.167F.0020.001F.FDA4] # ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA FINAL FORM; QQKN +FDA3 ; [.15F8.0020.0019.FDA3][.1663.0020.0019.FDA3][.1680.0020.001F.FDA3] # ARABIC LIGATURE TEH WITH MEEM WITH YEH FINAL FORM; QQKN +FC73 ; [.15F8.0020.0019.FC73][.1666.0020.0019.FC73] # ARABIC LIGATURE TEH WITH NOON FINAL FORM; QQKN +FCA5 ; [.15F8.0020.0017.FCA5][.166F.0020.0017.FCA5] # ARABIC LIGATURE TEH WITH HEH INITIAL FORM; QQKN +FCE4 ; [.15F8.0020.0018.FCE4][.166F.0020.0018.FCE4] # ARABIC LIGATURE TEH WITH HEH MEDIAL FORM; QQKN +FC74 ; [.15F8.0020.0019.FC74][.167F.0020.0019.FC74] # ARABIC LIGATURE TEH WITH ALEF MAKSURA FINAL FORM; QQKN +FC0F ; [.15F8.0020.001A.FC0F][.167F.0020.001A.FC0F] # ARABIC LIGATURE TEH WITH ALEF MAKSURA ISOLATED FORM; QQKN +FC75 ; [.15F8.0020.0019.FC75][.1680.0020.0019.FC75] # ARABIC LIGATURE TEH WITH YEH FINAL FORM; QQKN +FC10 ; [.15F8.0020.001A.FC10][.1680.0020.001A.FC10] # ARABIC LIGATURE TEH WITH YEH ISOLATED FORM; QQKN +062B ; [.15F9.0020.0002.062B] # ARABIC LETTER THEH +FE9B ; [.15F9.0020.0017.FE9B] # ARABIC LETTER THEH INITIAL FORM; QQK +FE9C ; [.15F9.0020.0018.FE9C] # ARABIC LETTER THEH MEDIAL FORM; QQK +FE9A ; [.15F9.0020.0019.FE9A] # ARABIC LETTER THEH FINAL FORM; QQK +FE99 ; [.15F9.0020.001A.FE99] # ARABIC LETTER THEH ISOLATED FORM; QQK +FC11 ; [.15F9.0020.001A.FC11][.15FF.0020.001A.FC11] # ARABIC LIGATURE THEH WITH JEEM ISOLATED FORM; QQKN +FC76 ; [.15F9.0020.0019.FC76][.161A.0020.0019.FC76] # ARABIC LIGATURE THEH WITH REH FINAL FORM; QQKN +FC77 ; [.15F9.0020.0019.FC77][.161B.0020.0019.FC77] # ARABIC LIGATURE THEH WITH ZAIN FINAL FORM; QQKN +FCA6 ; [.15F9.0020.0017.FCA6][.1663.0020.0017.FCA6] # ARABIC LIGATURE THEH WITH MEEM INITIAL FORM; QQKN +FCE5 ; [.15F9.0020.0018.FCE5][.1663.0020.0018.FCE5] # ARABIC LIGATURE THEH WITH MEEM MEDIAL FORM; QQKN +FC78 ; [.15F9.0020.0019.FC78][.1663.0020.0019.FC78] # ARABIC LIGATURE THEH WITH MEEM FINAL FORM; QQKN +FC12 ; [.15F9.0020.001A.FC12][.1663.0020.001A.FC12] # ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM; QQKN +FC79 ; [.15F9.0020.0019.FC79][.1666.0020.0019.FC79] # ARABIC LIGATURE THEH WITH NOON FINAL FORM; QQKN +FCE6 ; [.15F9.0020.0018.FCE6][.166F.0020.0018.FCE6] # ARABIC LIGATURE THEH WITH HEH MEDIAL FORM; QQKN +FC7A ; [.15F9.0020.0019.FC7A][.167F.0020.0019.FC7A] # ARABIC LIGATURE THEH WITH ALEF MAKSURA FINAL FORM; QQKN +FC13 ; [.15F9.0020.001A.FC13][.167F.0020.001A.FC13] # ARABIC LIGATURE THEH WITH ALEF MAKSURA ISOLATED FORM; QQKN +FC7B ; [.15F9.0020.0019.FC7B][.1680.0020.0019.FC7B] # ARABIC LIGATURE THEH WITH YEH FINAL FORM; QQKN +FC14 ; [.15F9.0020.001A.FC14][.1680.0020.001A.FC14] # ARABIC LIGATURE THEH WITH YEH ISOLATED FORM; QQKN +0679 ; [.15FA.0020.0002.0679] # ARABIC LETTER TTEH +FB68 ; [.15FA.0020.0017.FB68] # ARABIC LETTER TTEH INITIAL FORM; QQK +FB69 ; [.15FA.0020.0018.FB69] # ARABIC LETTER TTEH MEDIAL FORM; QQK +FB67 ; [.15FA.0020.0019.FB67] # ARABIC LETTER TTEH FINAL FORM; QQK +FB66 ; [.15FA.0020.001A.FB66] # ARABIC LETTER TTEH ISOLATED FORM; QQK +067A ; [.15FB.0020.0002.067A] # ARABIC LETTER TTEHEH +FB60 ; [.15FB.0020.0017.FB60] # ARABIC LETTER TTEHEH INITIAL FORM; QQK +FB61 ; [.15FB.0020.0018.FB61] # ARABIC LETTER TTEHEH MEDIAL FORM; QQK +FB5F ; [.15FB.0020.0019.FB5F] # ARABIC LETTER TTEHEH FINAL FORM; QQK +FB5E ; [.15FB.0020.001A.FB5E] # ARABIC LETTER TTEHEH ISOLATED FORM; QQK +067C ; [.15FC.0020.0002.067C] # ARABIC LETTER TEH WITH RING +067D ; [.15FD.0020.0002.067D] # ARABIC LETTER TEH WITH THREE DOTS ABOVE DOWNWARDS +067F ; [.15FE.0020.0002.067F] # ARABIC LETTER TEHEH +FB64 ; [.15FE.0020.0017.FB64] # ARABIC LETTER TEHEH INITIAL FORM; QQK +FB65 ; [.15FE.0020.0018.FB65] # ARABIC LETTER TEHEH MEDIAL FORM; QQK +FB63 ; [.15FE.0020.0019.FB63] # ARABIC LETTER TEHEH FINAL FORM; QQK +FB62 ; [.15FE.0020.001A.FB62] # ARABIC LETTER TEHEH ISOLATED FORM; QQK +062C ; [.15FF.0020.0002.062C] # ARABIC LETTER JEEM +FE9F ; [.15FF.0020.0017.FE9F] # ARABIC LETTER JEEM INITIAL FORM; QQK +FEA0 ; [.15FF.0020.0018.FEA0] # ARABIC LETTER JEEM MEDIAL FORM; QQK +FE9E ; [.15FF.0020.0019.FE9E] # ARABIC LETTER JEEM FINAL FORM; QQK +FE9D ; [.15FF.0020.001A.FE9D] # ARABIC LETTER JEEM ISOLATED FORM; QQK +FCA7 ; [.15FF.0020.0017.FCA7][.1605.0020.0017.FCA7] # ARABIC LIGATURE JEEM WITH HAH INITIAL FORM; QQKN +FC15 ; [.15FF.0020.001A.FC15][.1605.0020.001A.FC15] # ARABIC LIGATURE JEEM WITH HAH ISOLATED FORM; QQKN +FDA6 ; [.15FF.0020.0019.FDA6][.1605.0020.0019.FDA6][.167F.0020.001F.FDA6] # ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA FINAL FORM; QQKN +FDBE ; [.15FF.0020.0019.FDBE][.1605.0020.0019.FDBE][.1680.0020.001F.FDBE] # ARABIC LIGATURE JEEM WITH HAH WITH YEH FINAL FORM; QQKN +FDFB ; [.15FF.0020.001A.FDFB][.165D.0020.001A.FDFB][*0209.0020.001F.FDFB][.15FF.0020.001F.FDFB][.165D.0020.001F.FDFB][.15EA.0020.001F.FDFB][.165D.0020.001F.FDFB][.166F.0020.001F.FDFB] # ARABIC LIGATURE JALLAJALALOUHOU; QQKN +FCA8 ; [.15FF.0020.0017.FCA8][.1663.0020.0017.FCA8] # ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM; QQKN +FC16 ; [.15FF.0020.001A.FC16][.1663.0020.001A.FC16] # ARABIC LIGATURE JEEM WITH MEEM ISOLATED FORM; QQKN +FD59 ; [.15FF.0020.0017.FD59][.1663.0020.0017.FD59][.1605.0020.001F.FD59] # ARABIC LIGATURE JEEM WITH MEEM WITH HAH INITIAL FORM; QQKN +FD58 ; [.15FF.0020.0019.FD58][.1663.0020.0019.FD58][.1605.0020.001F.FD58] # ARABIC LIGATURE JEEM WITH MEEM WITH HAH FINAL FORM; QQKN +FDA7 ; [.15FF.0020.0019.FDA7][.1663.0020.0019.FDA7][.167F.0020.001F.FDA7] # ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA FINAL FORM; QQKN +FDA5 ; [.15FF.0020.0019.FDA5][.1663.0020.0019.FDA5][.1680.0020.001F.FDA5] # ARABIC LIGATURE JEEM WITH MEEM WITH YEH FINAL FORM; QQKN +FD1D ; [.15FF.0020.0019.FD1D][.167F.0020.0019.FD1D] # ARABIC LIGATURE JEEM WITH ALEF MAKSURA FINAL FORM; QQKN +FD01 ; [.15FF.0020.001A.FD01][.167F.0020.001A.FD01] # ARABIC LIGATURE JEEM WITH ALEF MAKSURA ISOLATED FORM; QQKN +FD1E ; [.15FF.0020.0019.FD1E][.1680.0020.0019.FD1E] # ARABIC LIGATURE JEEM WITH YEH FINAL FORM; QQKN +FD02 ; [.15FF.0020.001A.FD02][.1680.0020.001A.FD02] # ARABIC LIGATURE JEEM WITH YEH ISOLATED FORM; QQKN +0683 ; [.1600.0020.0002.0683] # ARABIC LETTER NYEH +FB78 ; [.1600.0020.0017.FB78] # ARABIC LETTER NYEH INITIAL FORM; QQK +FB79 ; [.1600.0020.0018.FB79] # ARABIC LETTER NYEH MEDIAL FORM; QQK +FB77 ; [.1600.0020.0019.FB77] # ARABIC LETTER NYEH FINAL FORM; QQK +FB76 ; [.1600.0020.001A.FB76] # ARABIC LETTER NYEH ISOLATED FORM; QQK +0684 ; [.1601.0020.0002.0684] # ARABIC LETTER DYEH +FB74 ; [.1601.0020.0017.FB74] # ARABIC LETTER DYEH INITIAL FORM; QQK +FB75 ; [.1601.0020.0018.FB75] # ARABIC LETTER DYEH MEDIAL FORM; QQK +FB73 ; [.1601.0020.0019.FB73] # ARABIC LETTER DYEH FINAL FORM; QQK +FB72 ; [.1601.0020.001A.FB72] # ARABIC LETTER DYEH ISOLATED FORM; QQK +0686 ; [.1602.0020.0002.0686] # ARABIC LETTER TCHEH +FB7C ; [.1602.0020.0017.FB7C] # ARABIC LETTER TCHEH INITIAL FORM; QQK +FB7D ; [.1602.0020.0018.FB7D] # ARABIC LETTER TCHEH MEDIAL FORM; QQK +FB7B ; [.1602.0020.0019.FB7B] # ARABIC LETTER TCHEH FINAL FORM; QQK +FB7A ; [.1602.0020.001A.FB7A] # ARABIC LETTER TCHEH ISOLATED FORM; QQK +06BF ; [.1603.0020.0002.06BF] # ARABIC LETTER TCHEH WITH DOT ABOVE +0687 ; [.1604.0020.0002.0687] # ARABIC LETTER TCHEHEH +FB80 ; [.1604.0020.0017.FB80] # ARABIC LETTER TCHEHEH INITIAL FORM; QQK +FB81 ; [.1604.0020.0018.FB81] # ARABIC LETTER TCHEHEH MEDIAL FORM; QQK +FB7F ; [.1604.0020.0019.FB7F] # ARABIC LETTER TCHEHEH FINAL FORM; QQK +FB7E ; [.1604.0020.001A.FB7E] # ARABIC LETTER TCHEHEH ISOLATED FORM; QQK +062D ; [.1605.0020.0002.062D] # ARABIC LETTER HAH +FEA3 ; [.1605.0020.0017.FEA3] # ARABIC LETTER HAH INITIAL FORM; QQK +FEA4 ; [.1605.0020.0018.FEA4] # ARABIC LETTER HAH MEDIAL FORM; QQK +FEA2 ; [.1605.0020.0019.FEA2] # ARABIC LETTER HAH FINAL FORM; QQK +FEA1 ; [.1605.0020.001A.FEA1] # ARABIC LETTER HAH ISOLATED FORM; QQK +FCA9 ; [.1605.0020.0017.FCA9][.15FF.0020.0017.FCA9] # ARABIC LIGATURE HAH WITH JEEM INITIAL FORM; QQKN +FC17 ; [.1605.0020.001A.FC17][.15FF.0020.001A.FC17] # ARABIC LIGATURE HAH WITH JEEM ISOLATED FORM; QQKN +FDBF ; [.1605.0020.0019.FDBF][.15FF.0020.0019.FDBF][.1680.0020.001F.FDBF] # ARABIC LIGATURE HAH WITH JEEM WITH YEH FINAL FORM; QQKN +FCAA ; [.1605.0020.0017.FCAA][.1663.0020.0017.FCAA] # ARABIC LIGATURE HAH WITH MEEM INITIAL FORM; QQKN +FC18 ; [.1605.0020.001A.FC18][.1663.0020.001A.FC18] # ARABIC LIGATURE HAH WITH MEEM ISOLATED FORM; QQKN +FD5B ; [.1605.0020.0019.FD5B][.1663.0020.0019.FD5B][.167F.0020.001F.FD5B] # ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA FINAL FORM; QQKN +FD5A ; [.1605.0020.0019.FD5A][.1663.0020.0019.FD5A][.1680.0020.001F.FD5A] # ARABIC LIGATURE HAH WITH MEEM WITH YEH FINAL FORM; QQKN +FD1B ; [.1605.0020.0019.FD1B][.167F.0020.0019.FD1B] # ARABIC LIGATURE HAH WITH ALEF MAKSURA FINAL FORM; QQKN +FCFF ; [.1605.0020.001A.FCFF][.167F.0020.001A.FCFF] # ARABIC LIGATURE HAH WITH ALEF MAKSURA ISOLATED FORM; QQKN +FD1C ; [.1605.0020.0019.FD1C][.1680.0020.0019.FD1C] # ARABIC LIGATURE HAH WITH YEH FINAL FORM; QQKN +FD00 ; [.1605.0020.001A.FD00][.1680.0020.001A.FD00] # ARABIC LIGATURE HAH WITH YEH ISOLATED FORM; QQKN +062E ; [.1606.0020.0002.062E] # ARABIC LETTER KHAH +FEA7 ; [.1606.0020.0017.FEA7] # ARABIC LETTER KHAH INITIAL FORM; QQK +FEA8 ; [.1606.0020.0018.FEA8] # ARABIC LETTER KHAH MEDIAL FORM; QQK +FEA6 ; [.1606.0020.0019.FEA6] # ARABIC LETTER KHAH FINAL FORM; QQK +FEA5 ; [.1606.0020.001A.FEA5] # ARABIC LETTER KHAH ISOLATED FORM; QQK +FCAB ; [.1606.0020.0017.FCAB][.15FF.0020.0017.FCAB] # ARABIC LIGATURE KHAH WITH JEEM INITIAL FORM; QQKN +FC19 ; [.1606.0020.001A.FC19][.15FF.0020.001A.FC19] # ARABIC LIGATURE KHAH WITH JEEM ISOLATED FORM; QQKN +FC1A ; [.1606.0020.001A.FC1A][.1605.0020.001A.FC1A] # ARABIC LIGATURE KHAH WITH HAH ISOLATED FORM; QQKN +FCAC ; [.1606.0020.0017.FCAC][.1663.0020.0017.FCAC] # ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM; QQKN +FC1B ; [.1606.0020.001A.FC1B][.1663.0020.001A.FC1B] # ARABIC LIGATURE KHAH WITH MEEM ISOLATED FORM; QQKN +FD1F ; [.1606.0020.0019.FD1F][.167F.0020.0019.FD1F] # ARABIC LIGATURE KHAH WITH ALEF MAKSURA FINAL FORM; QQKN +FD03 ; [.1606.0020.001A.FD03][.167F.0020.001A.FD03] # ARABIC LIGATURE KHAH WITH ALEF MAKSURA ISOLATED FORM; QQKN +FD20 ; [.1606.0020.0019.FD20][.1680.0020.0019.FD20] # ARABIC LIGATURE KHAH WITH YEH FINAL FORM; QQKN +FD04 ; [.1606.0020.001A.FD04][.1680.0020.001A.FD04] # ARABIC LIGATURE KHAH WITH YEH ISOLATED FORM; QQKN +0681 ; [.1607.0020.0002.0681] # ARABIC LETTER HAH WITH HAMZA ABOVE +0682 ; [.1608.0020.0002.0682] # ARABIC LETTER HAH WITH TWO DOTS VERTICAL ABOVE +0685 ; [.1609.0020.0002.0685] # ARABIC LETTER HAH WITH THREE DOTS ABOVE +0757 ; [.160A.0020.0002.0757] # ARABIC LETTER HAH WITH TWO DOTS ABOVE +0758 ; [.160B.0020.0002.0758] # ARABIC LETTER HAH WITH THREE DOTS POINTING UPWARDS BELOW +062F ; [.160C.0020.0002.062F] # ARABIC LETTER DAL +FEAA ; [.160C.0020.0019.FEAA] # ARABIC LETTER DAL FINAL FORM; QQK +FEA9 ; [.160C.0020.001A.FEA9] # ARABIC LETTER DAL ISOLATED FORM; QQK +0630 ; [.160D.0020.0002.0630] # ARABIC LETTER THAL +FEAC ; [.160D.0020.0019.FEAC] # ARABIC LETTER THAL FINAL FORM; QQK +FEAB ; [.160D.0020.001A.FEAB] # ARABIC LETTER THAL ISOLATED FORM; QQK +FC5B ; [.160D.0020.001A.FC5B][.0000.00F3.001A.FC5B] # ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF ISOLATED FORM; QQKN +0688 ; [.160E.0020.0002.0688] # ARABIC LETTER DDAL +FB89 ; [.160E.0020.0019.FB89] # ARABIC LETTER DDAL FINAL FORM; QQK +FB88 ; [.160E.0020.001A.FB88] # ARABIC LETTER DDAL ISOLATED FORM; QQK +0689 ; [.160F.0020.0002.0689] # ARABIC LETTER DAL WITH RING +068A ; [.1610.0020.0002.068A] # ARABIC LETTER DAL WITH DOT BELOW +068B ; [.1611.0020.0002.068B] # ARABIC LETTER DAL WITH DOT BELOW AND SMALL TAH +068C ; [.1612.0020.0002.068C] # ARABIC LETTER DAHAL +FB85 ; [.1612.0020.0019.FB85] # ARABIC LETTER DAHAL FINAL FORM; QQK +FB84 ; [.1612.0020.001A.FB84] # ARABIC LETTER DAHAL ISOLATED FORM; QQK +068D ; [.1613.0020.0002.068D] # ARABIC LETTER DDAHAL +FB83 ; [.1613.0020.0019.FB83] # ARABIC LETTER DDAHAL FINAL FORM; QQK +FB82 ; [.1613.0020.001A.FB82] # ARABIC LETTER DDAHAL ISOLATED FORM; QQK +068E ; [.1614.0020.0002.068E] # ARABIC LETTER DUL +FB87 ; [.1614.0020.0019.FB87] # ARABIC LETTER DUL FINAL FORM; QQK +FB86 ; [.1614.0020.001A.FB86] # ARABIC LETTER DUL ISOLATED FORM; QQK +068F ; [.1615.0020.0002.068F] # ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARDS +0690 ; [.1616.0020.0002.0690] # ARABIC LETTER DAL WITH FOUR DOTS ABOVE +06EE ; [.1617.0020.0002.06EE] # ARABIC LETTER DAL WITH INVERTED V +0759 ; [.1618.0020.0002.0759] # ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW AND SMALL TAH +075A ; [.1619.0020.0002.075A] # ARABIC LETTER DAL WITH INVERTED SMALL V BELOW +0631 ; [.161A.0020.0002.0631] # ARABIC LETTER REH +FEAE ; [.161A.0020.0019.FEAE] # ARABIC LETTER REH FINAL FORM; QQK +FEAD ; [.161A.0020.001A.FEAD] # ARABIC LETTER REH ISOLATED FORM; QQK +FC5C ; [.161A.0020.001A.FC5C][.0000.00F3.001A.FC5C] # ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF ISOLATED FORM; QQKN +FDF6 ; [.161A.0020.001A.FDF6][.1629.0020.001A.FDF6][.1675.0020.001F.FDF6][.165D.0020.001F.FDF6] # ARABIC LIGATURE RASOUL ISOLATED FORM; QQKN +FDFC ; [.161A.0020.001A.FDFC][.1681.0020.001A.FDFC][.15EA.0020.001F.FDFC][.165D.0020.001F.FDFC] # RIAL SIGN; QQKN +0632 ; [.161B.0020.0002.0632] # ARABIC LETTER ZAIN +FEB0 ; [.161B.0020.0019.FEB0] # ARABIC LETTER ZAIN FINAL FORM; QQK +FEAF ; [.161B.0020.001A.FEAF] # ARABIC LETTER ZAIN ISOLATED FORM; QQK +0691 ; [.161C.0020.0002.0691] # ARABIC LETTER RREH +FB8D ; [.161C.0020.0019.FB8D] # ARABIC LETTER RREH FINAL FORM; QQK +FB8C ; [.161C.0020.001A.FB8C] # ARABIC LETTER RREH ISOLATED FORM; QQK +0692 ; [.161D.0020.0002.0692] # ARABIC LETTER REH WITH SMALL V +0693 ; [.161E.0020.0002.0693] # ARABIC LETTER REH WITH RING +0694 ; [.161F.0020.0002.0694] # ARABIC LETTER REH WITH DOT BELOW +0695 ; [.1620.0020.0002.0695] # ARABIC LETTER REH WITH SMALL V BELOW +0696 ; [.1621.0020.0002.0696] # ARABIC LETTER REH WITH DOT BELOW AND DOT ABOVE +0697 ; [.1622.0020.0002.0697] # ARABIC LETTER REH WITH TWO DOTS ABOVE +0698 ; [.1623.0020.0002.0698] # ARABIC LETTER JEH +FB8B ; [.1623.0020.0019.FB8B] # ARABIC LETTER JEH FINAL FORM; QQK +FB8A ; [.1623.0020.001A.FB8A] # ARABIC LETTER JEH ISOLATED FORM; QQK +0699 ; [.1624.0020.0002.0699] # ARABIC LETTER REH WITH FOUR DOTS ABOVE +06EF ; [.1625.0020.0002.06EF] # ARABIC LETTER REH WITH INVERTED V +075B ; [.1626.0020.0002.075B] # ARABIC LETTER REH WITH STROKE +076B ; [.1627.0020.0002.076B] # ARABIC LETTER REH WITH TWO DOTS VERTICALLY ABOVE +076C ; [.1628.0020.0002.076C] # ARABIC LETTER REH WITH HAMZA ABOVE +0633 ; [.1629.0020.0002.0633] # ARABIC LETTER SEEN +FEB3 ; [.1629.0020.0017.FEB3] # ARABIC LETTER SEEN INITIAL FORM; QQK +FEB4 ; [.1629.0020.0018.FEB4] # ARABIC LETTER SEEN MEDIAL FORM; QQK +FEB2 ; [.1629.0020.0019.FEB2] # ARABIC LETTER SEEN FINAL FORM; QQK +FEB1 ; [.1629.0020.001A.FEB1] # ARABIC LETTER SEEN ISOLATED FORM; QQK +FCAD ; [.1629.0020.0017.FCAD][.15FF.0020.0017.FCAD] # ARABIC LIGATURE SEEN WITH JEEM INITIAL FORM; QQKN +FD34 ; [.1629.0020.0018.FD34][.15FF.0020.0018.FD34] # ARABIC LIGATURE SEEN WITH JEEM MEDIAL FORM; QQKN +FC1C ; [.1629.0020.001A.FC1C][.15FF.0020.001A.FC1C] # ARABIC LIGATURE SEEN WITH JEEM ISOLATED FORM; QQKN +FD5D ; [.1629.0020.0017.FD5D][.15FF.0020.0017.FD5D][.1605.0020.001F.FD5D] # ARABIC LIGATURE SEEN WITH JEEM WITH HAH INITIAL FORM; QQKN +FD5E ; [.1629.0020.0019.FD5E][.15FF.0020.0019.FD5E][.167F.0020.001F.FD5E] # ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA FINAL FORM; QQKN +FCAE ; [.1629.0020.0017.FCAE][.1605.0020.0017.FCAE] # ARABIC LIGATURE SEEN WITH HAH INITIAL FORM; QQKN +FD35 ; [.1629.0020.0018.FD35][.1605.0020.0018.FD35] # ARABIC LIGATURE SEEN WITH HAH MEDIAL FORM; QQKN +FC1D ; [.1629.0020.001A.FC1D][.1605.0020.001A.FC1D] # ARABIC LIGATURE SEEN WITH HAH ISOLATED FORM; QQKN +FD5C ; [.1629.0020.0017.FD5C][.1605.0020.0017.FD5C][.15FF.0020.001F.FD5C] # ARABIC LIGATURE SEEN WITH HAH WITH JEEM INITIAL FORM; QQKN +FCAF ; [.1629.0020.0017.FCAF][.1606.0020.0017.FCAF] # ARABIC LIGATURE SEEN WITH KHAH INITIAL FORM; QQKN +FD36 ; [.1629.0020.0018.FD36][.1606.0020.0018.FD36] # ARABIC LIGATURE SEEN WITH KHAH MEDIAL FORM; QQKN +FC1E ; [.1629.0020.001A.FC1E][.1606.0020.001A.FC1E] # ARABIC LIGATURE SEEN WITH KHAH ISOLATED FORM; QQKN +FDA8 ; [.1629.0020.0019.FDA8][.1606.0020.0019.FDA8][.167F.0020.001F.FDA8] # ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA FINAL FORM; QQKN +FDC6 ; [.1629.0020.0019.FDC6][.1606.0020.0019.FDC6][.1680.0020.001F.FDC6] # ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM; QQKN +FD2A ; [.1629.0020.0019.FD2A][.161A.0020.0019.FD2A] # ARABIC LIGATURE SEEN WITH REH FINAL FORM; QQKN +FD0E ; [.1629.0020.001A.FD0E][.161A.0020.001A.FD0E] # ARABIC LIGATURE SEEN WITH REH ISOLATED FORM; QQKN +FCB0 ; [.1629.0020.0017.FCB0][.1663.0020.0017.FCB0] # ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM; QQKN +FCE7 ; [.1629.0020.0018.FCE7][.1663.0020.0018.FCE7] # ARABIC LIGATURE SEEN WITH MEEM MEDIAL FORM; QQKN +FC1F ; [.1629.0020.001A.FC1F][.1663.0020.001A.FC1F] # ARABIC LIGATURE SEEN WITH MEEM ISOLATED FORM; QQKN +FD61 ; [.1629.0020.0017.FD61][.1663.0020.0017.FD61][.15FF.0020.001F.FD61] # ARABIC LIGATURE SEEN WITH MEEM WITH JEEM INITIAL FORM; QQKN +FD60 ; [.1629.0020.0017.FD60][.1663.0020.0017.FD60][.1605.0020.001F.FD60] # ARABIC LIGATURE SEEN WITH MEEM WITH HAH INITIAL FORM; QQKN +FD5F ; [.1629.0020.0019.FD5F][.1663.0020.0019.FD5F][.1605.0020.001F.FD5F] # ARABIC LIGATURE SEEN WITH MEEM WITH HAH FINAL FORM; QQKN +FD63 ; [.1629.0020.0017.FD63][.1663.0020.0017.FD63][.1663.0020.001F.FD63] # ARABIC LIGATURE SEEN WITH MEEM WITH MEEM INITIAL FORM; QQKN +FD62 ; [.1629.0020.0019.FD62][.1663.0020.0019.FD62][.1663.0020.001F.FD62] # ARABIC LIGATURE SEEN WITH MEEM WITH MEEM FINAL FORM; QQKN +FD31 ; [.1629.0020.0017.FD31][.166F.0020.0017.FD31] # ARABIC LIGATURE SEEN WITH HEH INITIAL FORM; QQKN +FCE8 ; [.1629.0020.0018.FCE8][.166F.0020.0018.FCE8] # ARABIC LIGATURE SEEN WITH HEH MEDIAL FORM; QQKN +FD17 ; [.1629.0020.0019.FD17][.167F.0020.0019.FD17] # ARABIC LIGATURE SEEN WITH ALEF MAKSURA FINAL FORM; QQKN +FCFB ; [.1629.0020.001A.FCFB][.167F.0020.001A.FCFB] # ARABIC LIGATURE SEEN WITH ALEF MAKSURA ISOLATED FORM; QQKN +FD18 ; [.1629.0020.0019.FD18][.1680.0020.0019.FD18] # ARABIC LIGATURE SEEN WITH YEH FINAL FORM; QQKN +FCFC ; [.1629.0020.001A.FCFC][.1680.0020.001A.FCFC] # ARABIC LIGATURE SEEN WITH YEH ISOLATED FORM; QQKN +0634 ; [.162A.0020.0002.0634] # ARABIC LETTER SHEEN +FEB7 ; [.162A.0020.0017.FEB7] # ARABIC LETTER SHEEN INITIAL FORM; QQK +FEB8 ; [.162A.0020.0018.FEB8] # ARABIC LETTER SHEEN MEDIAL FORM; QQK +FEB6 ; [.162A.0020.0019.FEB6] # ARABIC LETTER SHEEN FINAL FORM; QQK +FEB5 ; [.162A.0020.001A.FEB5] # ARABIC LETTER SHEEN ISOLATED FORM; QQK +FD2D ; [.162A.0020.0017.FD2D][.15FF.0020.0017.FD2D] # ARABIC LIGATURE SHEEN WITH JEEM INITIAL FORM; QQKN +FD37 ; [.162A.0020.0018.FD37][.15FF.0020.0018.FD37] # ARABIC LIGATURE SHEEN WITH JEEM MEDIAL FORM; QQKN +FD25 ; [.162A.0020.0019.FD25][.15FF.0020.0019.FD25] # ARABIC LIGATURE SHEEN WITH JEEM FINAL FORM; QQKN +FD09 ; [.162A.0020.001A.FD09][.15FF.0020.001A.FD09] # ARABIC LIGATURE SHEEN WITH JEEM ISOLATED FORM; QQKN +FD69 ; [.162A.0020.0019.FD69][.15FF.0020.0019.FD69][.1680.0020.001F.FD69] # ARABIC LIGATURE SHEEN WITH JEEM WITH YEH FINAL FORM; QQKN +FD2E ; [.162A.0020.0017.FD2E][.1605.0020.0017.FD2E] # ARABIC LIGATURE SHEEN WITH HAH INITIAL FORM; QQKN +FD38 ; [.162A.0020.0018.FD38][.1605.0020.0018.FD38] # ARABIC LIGATURE SHEEN WITH HAH MEDIAL FORM; QQKN +FD26 ; [.162A.0020.0019.FD26][.1605.0020.0019.FD26] # ARABIC LIGATURE SHEEN WITH HAH FINAL FORM; QQKN +FD0A ; [.162A.0020.001A.FD0A][.1605.0020.001A.FD0A] # ARABIC LIGATURE SHEEN WITH HAH ISOLATED FORM; QQKN +FD68 ; [.162A.0020.0017.FD68][.1605.0020.0017.FD68][.1663.0020.001F.FD68] # ARABIC LIGATURE SHEEN WITH HAH WITH MEEM INITIAL FORM; QQKN +FD67 ; [.162A.0020.0019.FD67][.1605.0020.0019.FD67][.1663.0020.001F.FD67] # ARABIC LIGATURE SHEEN WITH HAH WITH MEEM FINAL FORM; QQKN +FDAA ; [.162A.0020.0019.FDAA][.1605.0020.0019.FDAA][.1680.0020.001F.FDAA] # ARABIC LIGATURE SHEEN WITH HAH WITH YEH FINAL FORM; QQKN +FD2F ; [.162A.0020.0017.FD2F][.1606.0020.0017.FD2F] # ARABIC LIGATURE SHEEN WITH KHAH INITIAL FORM; QQKN +FD39 ; [.162A.0020.0018.FD39][.1606.0020.0018.FD39] # ARABIC LIGATURE SHEEN WITH KHAH MEDIAL FORM; QQKN +FD27 ; [.162A.0020.0019.FD27][.1606.0020.0019.FD27] # ARABIC LIGATURE SHEEN WITH KHAH FINAL FORM; QQKN +FD0B ; [.162A.0020.001A.FD0B][.1606.0020.001A.FD0B] # ARABIC LIGATURE SHEEN WITH KHAH ISOLATED FORM; QQKN +FD29 ; [.162A.0020.0019.FD29][.161A.0020.0019.FD29] # ARABIC LIGATURE SHEEN WITH REH FINAL FORM; QQKN +FD0D ; [.162A.0020.001A.FD0D][.161A.0020.001A.FD0D] # ARABIC LIGATURE SHEEN WITH REH ISOLATED FORM; QQKN +FD30 ; [.162A.0020.0017.FD30][.1663.0020.0017.FD30] # ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM; QQKN +FCE9 ; [.162A.0020.0018.FCE9][.1663.0020.0018.FCE9] # ARABIC LIGATURE SHEEN WITH MEEM MEDIAL FORM; QQKN +FD28 ; [.162A.0020.0019.FD28][.1663.0020.0019.FD28] # ARABIC LIGATURE SHEEN WITH MEEM FINAL FORM; QQKN +FD0C ; [.162A.0020.001A.FD0C][.1663.0020.001A.FD0C] # ARABIC LIGATURE SHEEN WITH MEEM ISOLATED FORM; QQKN +FD6B ; [.162A.0020.0017.FD6B][.1663.0020.0017.FD6B][.1606.0020.001F.FD6B] # ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH INITIAL FORM; QQKN +FD6A ; [.162A.0020.0019.FD6A][.1663.0020.0019.FD6A][.1606.0020.001F.FD6A] # ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH FINAL FORM; QQKN +FD6D ; [.162A.0020.0017.FD6D][.1663.0020.0017.FD6D][.1663.0020.001F.FD6D] # ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM INITIAL FORM; QQKN +FD6C ; [.162A.0020.0019.FD6C][.1663.0020.0019.FD6C][.1663.0020.001F.FD6C] # ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM FINAL FORM; QQKN +FD32 ; [.162A.0020.0017.FD32][.166F.0020.0017.FD32] # ARABIC LIGATURE SHEEN WITH HEH INITIAL FORM; QQKN +FCEA ; [.162A.0020.0018.FCEA][.166F.0020.0018.FCEA] # ARABIC LIGATURE SHEEN WITH HEH MEDIAL FORM; QQKN +FD19 ; [.162A.0020.0019.FD19][.167F.0020.0019.FD19] # ARABIC LIGATURE SHEEN WITH ALEF MAKSURA FINAL FORM; QQKN +FCFD ; [.162A.0020.001A.FCFD][.167F.0020.001A.FCFD] # ARABIC LIGATURE SHEEN WITH ALEF MAKSURA ISOLATED FORM; QQKN +FD1A ; [.162A.0020.0019.FD1A][.1680.0020.0019.FD1A] # ARABIC LIGATURE SHEEN WITH YEH FINAL FORM; QQKN +FCFE ; [.162A.0020.001A.FCFE][.1680.0020.001A.FCFE] # ARABIC LIGATURE SHEEN WITH YEH ISOLATED FORM; QQKN +069A ; [.162B.0020.0002.069A] # ARABIC LETTER SEEN WITH DOT BELOW AND DOT ABOVE +069B ; [.162C.0020.0002.069B] # ARABIC LETTER SEEN WITH THREE DOTS BELOW +069C ; [.162D.0020.0002.069C] # ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE +06FA ; [.162E.0020.0002.06FA] # ARABIC LETTER SHEEN WITH DOT BELOW +075C ; [.162F.0020.0002.075C] # ARABIC LETTER SEEN WITH FOUR DOTS ABOVE +076D ; [.1630.0020.0002.076D] # ARABIC LETTER SEEN WITH TWO DOTS VERTICALLY ABOVE +0635 ; [.1631.0020.0002.0635] # ARABIC LETTER SAD +FEBB ; [.1631.0020.0017.FEBB] # ARABIC LETTER SAD INITIAL FORM; QQK +FEBC ; [.1631.0020.0018.FEBC] # ARABIC LETTER SAD MEDIAL FORM; QQK +FEBA ; [.1631.0020.0019.FEBA] # ARABIC LETTER SAD FINAL FORM; QQK +FEB9 ; [.1631.0020.001A.FEB9] # ARABIC LETTER SAD ISOLATED FORM; QQK +FCB1 ; [.1631.0020.0017.FCB1][.1605.0020.0017.FCB1] # ARABIC LIGATURE SAD WITH HAH INITIAL FORM; QQKN +FC20 ; [.1631.0020.001A.FC20][.1605.0020.001A.FC20] # ARABIC LIGATURE SAD WITH HAH ISOLATED FORM; QQKN +FD65 ; [.1631.0020.0017.FD65][.1605.0020.0017.FD65][.1605.0020.001F.FD65] # ARABIC LIGATURE SAD WITH HAH WITH HAH INITIAL FORM; QQKN +FD64 ; [.1631.0020.0019.FD64][.1605.0020.0019.FD64][.1605.0020.001F.FD64] # ARABIC LIGATURE SAD WITH HAH WITH HAH FINAL FORM; QQKN +FDA9 ; [.1631.0020.0019.FDA9][.1605.0020.0019.FDA9][.1680.0020.001F.FDA9] # ARABIC LIGATURE SAD WITH HAH WITH YEH FINAL FORM; QQKN +FCB2 ; [.1631.0020.0017.FCB2][.1606.0020.0017.FCB2] # ARABIC LIGATURE SAD WITH KHAH INITIAL FORM; QQKN +FD2B ; [.1631.0020.0019.FD2B][.161A.0020.0019.FD2B] # ARABIC LIGATURE SAD WITH REH FINAL FORM; QQKN +FD0F ; [.1631.0020.001A.FD0F][.161A.0020.001A.FD0F] # ARABIC LIGATURE SAD WITH REH ISOLATED FORM; QQKN +FDF5 ; [.1631.0020.001A.FDF5][.165D.0020.001A.FDF5][.1639.0020.001F.FDF5][.1663.0020.001F.FDF5] # ARABIC LIGATURE SALAM ISOLATED FORM; QQKN +FDF9 ; [.1631.0020.001A.FDF9][.165D.0020.001A.FDF9][.167F.0020.001F.FDF9] # ARABIC LIGATURE SALLA ISOLATED FORM; QQKN +FDFA ; [.1631.0020.001A.FDFA][.165D.0020.001A.FDFA][.167F.0020.001F.FDFA][*0209.0020.001F.FDFA][.15EA.0020.001F.FDFA][.165D.0020.001F.FDFA][.165D.0020.001F.FDFA][.166F.0020.001F.FDFA][*0209.0020.001F.FDFA][.1639.0020.001F.FDFA][.165D.0020.001F.FDFA][.1680.0020.001F.FDFA][.166F.0020.001F.FDFA][*0209.0020.001F.FDFA][.1675.0020.001F.FDFA][.1629.0020.001F.FDFA][.165D.0020.001F.FDFA][.1663.0020.001F.FDFA] # ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM; QQKN +FDF0 ; [.1631.0020.001A.FDF0][.165D.0020.001A.FDF0][.1686.0020.001F.FDF0] # ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM; QQKN +FCB3 ; [.1631.0020.0017.FCB3][.1663.0020.0017.FCB3] # ARABIC LIGATURE SAD WITH MEEM INITIAL FORM; QQKN +FC21 ; [.1631.0020.001A.FC21][.1663.0020.001A.FC21] # ARABIC LIGATURE SAD WITH MEEM ISOLATED FORM; QQKN +FDC5 ; [.1631.0020.0017.FDC5][.1663.0020.0017.FDC5][.1663.0020.001F.FDC5] # ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM; QQKN +FD66 ; [.1631.0020.0019.FD66][.1663.0020.0019.FD66][.1663.0020.001F.FD66] # ARABIC LIGATURE SAD WITH MEEM WITH MEEM FINAL FORM; QQKN +FD21 ; [.1631.0020.0019.FD21][.167F.0020.0019.FD21] # ARABIC LIGATURE SAD WITH ALEF MAKSURA FINAL FORM; QQKN +FD05 ; [.1631.0020.001A.FD05][.167F.0020.001A.FD05] # ARABIC LIGATURE SAD WITH ALEF MAKSURA ISOLATED FORM; QQKN +FD22 ; [.1631.0020.0019.FD22][.1680.0020.0019.FD22] # ARABIC LIGATURE SAD WITH YEH FINAL FORM; QQKN +FD06 ; [.1631.0020.001A.FD06][.1680.0020.001A.FD06] # ARABIC LIGATURE SAD WITH YEH ISOLATED FORM; QQKN +0636 ; [.1632.0020.0002.0636] # ARABIC LETTER DAD +FEBF ; [.1632.0020.0017.FEBF] # ARABIC LETTER DAD INITIAL FORM; QQK +FEC0 ; [.1632.0020.0018.FEC0] # ARABIC LETTER DAD MEDIAL FORM; QQK +FEBE ; [.1632.0020.0019.FEBE] # ARABIC LETTER DAD FINAL FORM; QQK +FEBD ; [.1632.0020.001A.FEBD] # ARABIC LETTER DAD ISOLATED FORM; QQK +FCB4 ; [.1632.0020.0017.FCB4][.15FF.0020.0017.FCB4] # ARABIC LIGATURE DAD WITH JEEM INITIAL FORM; QQKN +FC22 ; [.1632.0020.001A.FC22][.15FF.0020.001A.FC22] # ARABIC LIGATURE DAD WITH JEEM ISOLATED FORM; QQKN +FCB5 ; [.1632.0020.0017.FCB5][.1605.0020.0017.FCB5] # ARABIC LIGATURE DAD WITH HAH INITIAL FORM; QQKN +FC23 ; [.1632.0020.001A.FC23][.1605.0020.001A.FC23] # ARABIC LIGATURE DAD WITH HAH ISOLATED FORM; QQKN +FD6E ; [.1632.0020.0019.FD6E][.1605.0020.0019.FD6E][.167F.0020.001F.FD6E] # ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA FINAL FORM; QQKN +FDAB ; [.1632.0020.0019.FDAB][.1605.0020.0019.FDAB][.1680.0020.001F.FDAB] # ARABIC LIGATURE DAD WITH HAH WITH YEH FINAL FORM; QQKN +FCB6 ; [.1632.0020.0017.FCB6][.1606.0020.0017.FCB6] # ARABIC LIGATURE DAD WITH KHAH INITIAL FORM; QQKN +FC24 ; [.1632.0020.001A.FC24][.1606.0020.001A.FC24] # ARABIC LIGATURE DAD WITH KHAH ISOLATED FORM; QQKN +FD70 ; [.1632.0020.0017.FD70][.1606.0020.0017.FD70][.1663.0020.001F.FD70] # ARABIC LIGATURE DAD WITH KHAH WITH MEEM INITIAL FORM; QQKN +FD6F ; [.1632.0020.0019.FD6F][.1606.0020.0019.FD6F][.1663.0020.001F.FD6F] # ARABIC LIGATURE DAD WITH KHAH WITH MEEM FINAL FORM; QQKN +FD2C ; [.1632.0020.0019.FD2C][.161A.0020.0019.FD2C] # ARABIC LIGATURE DAD WITH REH FINAL FORM; QQKN +FD10 ; [.1632.0020.001A.FD10][.161A.0020.001A.FD10] # ARABIC LIGATURE DAD WITH REH ISOLATED FORM; QQKN +FCB7 ; [.1632.0020.0017.FCB7][.1663.0020.0017.FCB7] # ARABIC LIGATURE DAD WITH MEEM INITIAL FORM; QQKN +FC25 ; [.1632.0020.001A.FC25][.1663.0020.001A.FC25] # ARABIC LIGATURE DAD WITH MEEM ISOLATED FORM; QQKN +FD23 ; [.1632.0020.0019.FD23][.167F.0020.0019.FD23] # ARABIC LIGATURE DAD WITH ALEF MAKSURA FINAL FORM; QQKN +FD07 ; [.1632.0020.001A.FD07][.167F.0020.001A.FD07] # ARABIC LIGATURE DAD WITH ALEF MAKSURA ISOLATED FORM; QQKN +FD24 ; [.1632.0020.0019.FD24][.1680.0020.0019.FD24] # ARABIC LIGATURE DAD WITH YEH FINAL FORM; QQKN +FD08 ; [.1632.0020.001A.FD08][.1680.0020.001A.FD08] # ARABIC LIGATURE DAD WITH YEH ISOLATED FORM; QQKN +069D ; [.1633.0020.0002.069D] # ARABIC LETTER SAD WITH TWO DOTS BELOW +069E ; [.1634.0020.0002.069E] # ARABIC LETTER SAD WITH THREE DOTS ABOVE +06FB ; [.1635.0020.0002.06FB] # ARABIC LETTER DAD WITH DOT BELOW +0637 ; [.1636.0020.0002.0637] # ARABIC LETTER TAH +FEC3 ; [.1636.0020.0017.FEC3] # ARABIC LETTER TAH INITIAL FORM; QQK +FEC4 ; [.1636.0020.0018.FEC4] # ARABIC LETTER TAH MEDIAL FORM; QQK +FEC2 ; [.1636.0020.0019.FEC2] # ARABIC LETTER TAH FINAL FORM; QQK +FEC1 ; [.1636.0020.001A.FEC1] # ARABIC LETTER TAH ISOLATED FORM; QQK +FCB8 ; [.1636.0020.0017.FCB8][.1605.0020.0017.FCB8] # ARABIC LIGATURE TAH WITH HAH INITIAL FORM; QQKN +FC26 ; [.1636.0020.001A.FC26][.1605.0020.001A.FC26] # ARABIC LIGATURE TAH WITH HAH ISOLATED FORM; QQKN +FD33 ; [.1636.0020.0017.FD33][.1663.0020.0017.FD33] # ARABIC LIGATURE TAH WITH MEEM INITIAL FORM; QQKN +FD3A ; [.1636.0020.0018.FD3A][.1663.0020.0018.FD3A] # ARABIC LIGATURE TAH WITH MEEM MEDIAL FORM; QQKN +FC27 ; [.1636.0020.001A.FC27][.1663.0020.001A.FC27] # ARABIC LIGATURE TAH WITH MEEM ISOLATED FORM; QQKN +FD72 ; [.1636.0020.0017.FD72][.1663.0020.0017.FD72][.1605.0020.001F.FD72] # ARABIC LIGATURE TAH WITH MEEM WITH HAH INITIAL FORM; QQKN +FD71 ; [.1636.0020.0019.FD71][.1663.0020.0019.FD71][.1605.0020.001F.FD71] # ARABIC LIGATURE TAH WITH MEEM WITH HAH FINAL FORM; QQKN +FD73 ; [.1636.0020.0017.FD73][.1663.0020.0017.FD73][.1663.0020.001F.FD73] # ARABIC LIGATURE TAH WITH MEEM WITH MEEM INITIAL FORM; QQKN +FD74 ; [.1636.0020.0019.FD74][.1663.0020.0019.FD74][.1680.0020.001F.FD74] # ARABIC LIGATURE TAH WITH MEEM WITH YEH FINAL FORM; QQKN +FD11 ; [.1636.0020.0019.FD11][.167F.0020.0019.FD11] # ARABIC LIGATURE TAH WITH ALEF MAKSURA FINAL FORM; QQKN +FCF5 ; [.1636.0020.001A.FCF5][.167F.0020.001A.FCF5] # ARABIC LIGATURE TAH WITH ALEF MAKSURA ISOLATED FORM; QQKN +FD12 ; [.1636.0020.0019.FD12][.1680.0020.0019.FD12] # ARABIC LIGATURE TAH WITH YEH FINAL FORM; QQKN +FCF6 ; [.1636.0020.001A.FCF6][.1680.0020.001A.FCF6] # ARABIC LIGATURE TAH WITH YEH ISOLATED FORM; QQKN +0638 ; [.1637.0020.0002.0638] # ARABIC LETTER ZAH +FEC7 ; [.1637.0020.0017.FEC7] # ARABIC LETTER ZAH INITIAL FORM; QQK +FEC8 ; [.1637.0020.0018.FEC8] # ARABIC LETTER ZAH MEDIAL FORM; QQK +FEC6 ; [.1637.0020.0019.FEC6] # ARABIC LETTER ZAH FINAL FORM; QQK +FEC5 ; [.1637.0020.001A.FEC5] # ARABIC LETTER ZAH ISOLATED FORM; QQK +FCB9 ; [.1637.0020.0017.FCB9][.1663.0020.0017.FCB9] # ARABIC LIGATURE ZAH WITH MEEM INITIAL FORM; QQKN +FD3B ; [.1637.0020.0018.FD3B][.1663.0020.0018.FD3B] # ARABIC LIGATURE ZAH WITH MEEM MEDIAL FORM; QQKN +FC28 ; [.1637.0020.001A.FC28][.1663.0020.001A.FC28] # ARABIC LIGATURE ZAH WITH MEEM ISOLATED FORM; QQKN +069F ; [.1638.0020.0002.069F] # ARABIC LETTER TAH WITH THREE DOTS ABOVE +0639 ; [.1639.0020.0002.0639] # ARABIC LETTER AIN +FECB ; [.1639.0020.0017.FECB] # ARABIC LETTER AIN INITIAL FORM; QQK +FECC ; [.1639.0020.0018.FECC] # ARABIC LETTER AIN MEDIAL FORM; QQK +FECA ; [.1639.0020.0019.FECA] # ARABIC LETTER AIN FINAL FORM; QQK +FEC9 ; [.1639.0020.001A.FEC9] # ARABIC LETTER AIN ISOLATED FORM; QQK +FCBA ; [.1639.0020.0017.FCBA][.15FF.0020.0017.FCBA] # ARABIC LIGATURE AIN WITH JEEM INITIAL FORM; QQKN +FC29 ; [.1639.0020.001A.FC29][.15FF.0020.001A.FC29] # ARABIC LIGATURE AIN WITH JEEM ISOLATED FORM; QQKN +FDC4 ; [.1639.0020.0017.FDC4][.15FF.0020.0017.FDC4][.1663.0020.001F.FDC4] # ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM; QQKN +FD75 ; [.1639.0020.0019.FD75][.15FF.0020.0019.FD75][.1663.0020.001F.FD75] # ARABIC LIGATURE AIN WITH JEEM WITH MEEM FINAL FORM; QQKN +FDF7 ; [.1639.0020.001A.FDF7][.165D.0020.001A.FDF7][.1680.0020.001F.FDF7][.166F.0020.001F.FDF7] # ARABIC LIGATURE ALAYHE ISOLATED FORM; QQKN +FCBB ; [.1639.0020.0017.FCBB][.1663.0020.0017.FCBB] # ARABIC LIGATURE AIN WITH MEEM INITIAL FORM; QQKN +FC2A ; [.1639.0020.001A.FC2A][.1663.0020.001A.FC2A] # ARABIC LIGATURE AIN WITH MEEM ISOLATED FORM; QQKN +FD77 ; [.1639.0020.0017.FD77][.1663.0020.0017.FD77][.1663.0020.001F.FD77] # ARABIC LIGATURE AIN WITH MEEM WITH MEEM INITIAL FORM; QQKN +FD76 ; [.1639.0020.0019.FD76][.1663.0020.0019.FD76][.1663.0020.001F.FD76] # ARABIC LIGATURE AIN WITH MEEM WITH MEEM FINAL FORM; QQKN +FD78 ; [.1639.0020.0019.FD78][.1663.0020.0019.FD78][.167F.0020.001F.FD78] # ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA FINAL FORM; QQKN +FDB6 ; [.1639.0020.0019.FDB6][.1663.0020.0019.FDB6][.1680.0020.001F.FDB6] # ARABIC LIGATURE AIN WITH MEEM WITH YEH FINAL FORM; QQKN +FD13 ; [.1639.0020.0019.FD13][.167F.0020.0019.FD13] # ARABIC LIGATURE AIN WITH ALEF MAKSURA FINAL FORM; QQKN +FCF7 ; [.1639.0020.001A.FCF7][.167F.0020.001A.FCF7] # ARABIC LIGATURE AIN WITH ALEF MAKSURA ISOLATED FORM; QQKN +FD14 ; [.1639.0020.0019.FD14][.1680.0020.0019.FD14] # ARABIC LIGATURE AIN WITH YEH FINAL FORM; QQKN +FCF8 ; [.1639.0020.001A.FCF8][.1680.0020.001A.FCF8] # ARABIC LIGATURE AIN WITH YEH ISOLATED FORM; QQKN +063A ; [.163A.0020.0002.063A] # ARABIC LETTER GHAIN +FECF ; [.163A.0020.0017.FECF] # ARABIC LETTER GHAIN INITIAL FORM; QQK +FED0 ; [.163A.0020.0018.FED0] # ARABIC LETTER GHAIN MEDIAL FORM; QQK +FECE ; [.163A.0020.0019.FECE] # ARABIC LETTER GHAIN FINAL FORM; QQK +FECD ; [.163A.0020.001A.FECD] # ARABIC LETTER GHAIN ISOLATED FORM; QQK +FCBC ; [.163A.0020.0017.FCBC][.15FF.0020.0017.FCBC] # ARABIC LIGATURE GHAIN WITH JEEM INITIAL FORM; QQKN +FC2B ; [.163A.0020.001A.FC2B][.15FF.0020.001A.FC2B] # ARABIC LIGATURE GHAIN WITH JEEM ISOLATED FORM; QQKN +FCBD ; [.163A.0020.0017.FCBD][.1663.0020.0017.FCBD] # ARABIC LIGATURE GHAIN WITH MEEM INITIAL FORM; QQKN +FC2C ; [.163A.0020.001A.FC2C][.1663.0020.001A.FC2C] # ARABIC LIGATURE GHAIN WITH MEEM ISOLATED FORM; QQKN +FD79 ; [.163A.0020.0019.FD79][.1663.0020.0019.FD79][.1663.0020.001F.FD79] # ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM FINAL FORM; QQKN +FD7B ; [.163A.0020.0019.FD7B][.1663.0020.0019.FD7B][.167F.0020.001F.FD7B] # ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA FINAL FORM; QQKN +FD7A ; [.163A.0020.0019.FD7A][.1663.0020.0019.FD7A][.1680.0020.001F.FD7A] # ARABIC LIGATURE GHAIN WITH MEEM WITH YEH FINAL FORM; QQKN +FD15 ; [.163A.0020.0019.FD15][.167F.0020.0019.FD15] # ARABIC LIGATURE GHAIN WITH ALEF MAKSURA FINAL FORM; QQKN +FCF9 ; [.163A.0020.001A.FCF9][.167F.0020.001A.FCF9] # ARABIC LIGATURE GHAIN WITH ALEF MAKSURA ISOLATED FORM; QQKN +FD16 ; [.163A.0020.0019.FD16][.1680.0020.0019.FD16] # ARABIC LIGATURE GHAIN WITH YEH FINAL FORM; QQKN +FCFA ; [.163A.0020.001A.FCFA][.1680.0020.001A.FCFA] # ARABIC LIGATURE GHAIN WITH YEH ISOLATED FORM; QQKN +06A0 ; [.163B.0020.0002.06A0] # ARABIC LETTER AIN WITH THREE DOTS ABOVE +06FC ; [.163C.0020.0002.06FC] # ARABIC LETTER GHAIN WITH DOT BELOW +075D ; [.163D.0020.0002.075D] # ARABIC LETTER AIN WITH TWO DOTS ABOVE +075E ; [.163E.0020.0002.075E] # ARABIC LETTER AIN WITH THREE DOTS POINTING DOWNWARDS ABOVE +075F ; [.163F.0020.0002.075F] # ARABIC LETTER AIN WITH TWO DOTS VERTICALLY ABOVE +0641 ; [.1640.0020.0002.0641] # ARABIC LETTER FEH +FED3 ; [.1640.0020.0017.FED3] # ARABIC LETTER FEH INITIAL FORM; QQK +FED4 ; [.1640.0020.0018.FED4] # ARABIC LETTER FEH MEDIAL FORM; QQK +FED2 ; [.1640.0020.0019.FED2] # ARABIC LETTER FEH FINAL FORM; QQK +FED1 ; [.1640.0020.001A.FED1] # ARABIC LETTER FEH ISOLATED FORM; QQK +FCBE ; [.1640.0020.0017.FCBE][.15FF.0020.0017.FCBE] # ARABIC LIGATURE FEH WITH JEEM INITIAL FORM; QQKN +FC2D ; [.1640.0020.001A.FC2D][.15FF.0020.001A.FC2D] # ARABIC LIGATURE FEH WITH JEEM ISOLATED FORM; QQKN +FCBF ; [.1640.0020.0017.FCBF][.1605.0020.0017.FCBF] # ARABIC LIGATURE FEH WITH HAH INITIAL FORM; QQKN +FC2E ; [.1640.0020.001A.FC2E][.1605.0020.001A.FC2E] # ARABIC LIGATURE FEH WITH HAH ISOLATED FORM; QQKN +FCC0 ; [.1640.0020.0017.FCC0][.1606.0020.0017.FCC0] # ARABIC LIGATURE FEH WITH KHAH INITIAL FORM; QQKN +FC2F ; [.1640.0020.001A.FC2F][.1606.0020.001A.FC2F] # ARABIC LIGATURE FEH WITH KHAH ISOLATED FORM; QQKN +FD7D ; [.1640.0020.0017.FD7D][.1606.0020.0017.FD7D][.1663.0020.001F.FD7D] # ARABIC LIGATURE FEH WITH KHAH WITH MEEM INITIAL FORM; QQKN +FD7C ; [.1640.0020.0019.FD7C][.1606.0020.0019.FD7C][.1663.0020.001F.FD7C] # ARABIC LIGATURE FEH WITH KHAH WITH MEEM FINAL FORM; QQKN +FCC1 ; [.1640.0020.0017.FCC1][.1663.0020.0017.FCC1] # ARABIC LIGATURE FEH WITH MEEM INITIAL FORM; QQKN +FC30 ; [.1640.0020.001A.FC30][.1663.0020.001A.FC30] # ARABIC LIGATURE FEH WITH MEEM ISOLATED FORM; QQKN +FDC1 ; [.1640.0020.0019.FDC1][.1663.0020.0019.FDC1][.1680.0020.001F.FDC1] # ARABIC LIGATURE FEH WITH MEEM WITH YEH FINAL FORM; QQKN +FC7C ; [.1640.0020.0019.FC7C][.167F.0020.0019.FC7C] # ARABIC LIGATURE FEH WITH ALEF MAKSURA FINAL FORM; QQKN +FC31 ; [.1640.0020.001A.FC31][.167F.0020.001A.FC31] # ARABIC LIGATURE FEH WITH ALEF MAKSURA ISOLATED FORM; QQKN +FC7D ; [.1640.0020.0019.FC7D][.1680.0020.0019.FC7D] # ARABIC LIGATURE FEH WITH YEH FINAL FORM; QQKN +FC32 ; [.1640.0020.001A.FC32][.1680.0020.001A.FC32] # ARABIC LIGATURE FEH WITH YEH ISOLATED FORM; QQKN +06A1 ; [.1641.0020.0002.06A1] # ARABIC LETTER DOTLESS FEH +06A2 ; [.1642.0020.0002.06A2] # ARABIC LETTER FEH WITH DOT MOVED BELOW +06A3 ; [.1643.0020.0002.06A3] # ARABIC LETTER FEH WITH DOT BELOW +06A4 ; [.1644.0020.0002.06A4] # ARABIC LETTER VEH +FB6C ; [.1644.0020.0017.FB6C] # ARABIC LETTER VEH INITIAL FORM; QQK +FB6D ; [.1644.0020.0018.FB6D] # ARABIC LETTER VEH MEDIAL FORM; QQK +FB6B ; [.1644.0020.0019.FB6B] # ARABIC LETTER VEH FINAL FORM; QQK +FB6A ; [.1644.0020.001A.FB6A] # ARABIC LETTER VEH ISOLATED FORM; QQK +06A5 ; [.1645.0020.0002.06A5] # ARABIC LETTER FEH WITH THREE DOTS BELOW +06A6 ; [.1646.0020.0002.06A6] # ARABIC LETTER PEHEH +FB70 ; [.1646.0020.0017.FB70] # ARABIC LETTER PEHEH INITIAL FORM; QQK +FB71 ; [.1646.0020.0018.FB71] # ARABIC LETTER PEHEH MEDIAL FORM; QQK +FB6F ; [.1646.0020.0019.FB6F] # ARABIC LETTER PEHEH FINAL FORM; QQK +FB6E ; [.1646.0020.001A.FB6E] # ARABIC LETTER PEHEH ISOLATED FORM; QQK +0760 ; [.1647.0020.0002.0760] # ARABIC LETTER FEH WITH TWO DOTS BELOW +0761 ; [.1648.0020.0002.0761] # ARABIC LETTER FEH WITH THREE DOTS POINTING UPWARDS BELOW +066F ; [.1649.0020.0002.066F] # ARABIC LETTER DOTLESS QAF +0642 ; [.164A.0020.0002.0642] # ARABIC LETTER QAF +FED7 ; [.164A.0020.0017.FED7] # ARABIC LETTER QAF INITIAL FORM; QQK +FED8 ; [.164A.0020.0018.FED8] # ARABIC LETTER QAF MEDIAL FORM; QQK +FED6 ; [.164A.0020.0019.FED6] # ARABIC LETTER QAF FINAL FORM; QQK +FED5 ; [.164A.0020.001A.FED5] # ARABIC LETTER QAF ISOLATED FORM; QQK +FCC2 ; [.164A.0020.0017.FCC2][.1605.0020.0017.FCC2] # ARABIC LIGATURE QAF WITH HAH INITIAL FORM; QQKN +FC33 ; [.164A.0020.001A.FC33][.1605.0020.001A.FC33] # ARABIC LIGATURE QAF WITH HAH ISOLATED FORM; QQKN +FDF1 ; [.164A.0020.001A.FDF1][.165D.0020.001A.FDF1][.1686.0020.001F.FDF1] # ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM; QQKN +FCC3 ; [.164A.0020.0017.FCC3][.1663.0020.0017.FCC3] # ARABIC LIGATURE QAF WITH MEEM INITIAL FORM; QQKN +FC34 ; [.164A.0020.001A.FC34][.1663.0020.001A.FC34] # ARABIC LIGATURE QAF WITH MEEM ISOLATED FORM; QQKN +FDB4 ; [.164A.0020.0017.FDB4][.1663.0020.0017.FDB4][.1605.0020.001F.FDB4] # ARABIC LIGATURE QAF WITH MEEM WITH HAH INITIAL FORM; QQKN +FD7E ; [.164A.0020.0019.FD7E][.1663.0020.0019.FD7E][.1605.0020.001F.FD7E] # ARABIC LIGATURE QAF WITH MEEM WITH HAH FINAL FORM; QQKN +FD7F ; [.164A.0020.0019.FD7F][.1663.0020.0019.FD7F][.1663.0020.001F.FD7F] # ARABIC LIGATURE QAF WITH MEEM WITH MEEM FINAL FORM; QQKN +FDB2 ; [.164A.0020.0019.FDB2][.1663.0020.0019.FDB2][.1680.0020.001F.FDB2] # ARABIC LIGATURE QAF WITH MEEM WITH YEH FINAL FORM; QQKN +FC7E ; [.164A.0020.0019.FC7E][.167F.0020.0019.FC7E] # ARABIC LIGATURE QAF WITH ALEF MAKSURA FINAL FORM; QQKN +FC35 ; [.164A.0020.001A.FC35][.167F.0020.001A.FC35] # ARABIC LIGATURE QAF WITH ALEF MAKSURA ISOLATED FORM; QQKN +FC7F ; [.164A.0020.0019.FC7F][.1680.0020.0019.FC7F] # ARABIC LIGATURE QAF WITH YEH FINAL FORM; QQKN +FC36 ; [.164A.0020.001A.FC36][.1680.0020.001A.FC36] # ARABIC LIGATURE QAF WITH YEH ISOLATED FORM; QQKN +06A7 ; [.164B.0020.0002.06A7] # ARABIC LETTER QAF WITH DOT ABOVE +06A8 ; [.164C.0020.0002.06A8] # ARABIC LETTER QAF WITH THREE DOTS ABOVE +0643 ; [.164D.0020.0002.0643] # ARABIC LETTER KAF +FEDB ; [.164D.0020.0017.FEDB] # ARABIC LETTER KAF INITIAL FORM; QQK +FEDC ; [.164D.0020.0018.FEDC] # ARABIC LETTER KAF MEDIAL FORM; QQK +FEDA ; [.164D.0020.0019.FEDA] # ARABIC LETTER KAF FINAL FORM; QQK +FED9 ; [.164D.0020.001A.FED9] # ARABIC LETTER KAF ISOLATED FORM; QQK +FC80 ; [.164D.0020.0019.FC80][.15EA.0020.0019.FC80] # ARABIC LIGATURE KAF WITH ALEF FINAL FORM; QQKN +FC37 ; [.164D.0020.001A.FC37][.15EA.0020.001A.FC37] # ARABIC LIGATURE KAF WITH ALEF ISOLATED FORM; QQKN +FCC4 ; [.164D.0020.0017.FCC4][.15FF.0020.0017.FCC4] # ARABIC LIGATURE KAF WITH JEEM INITIAL FORM; QQKN +FC38 ; [.164D.0020.001A.FC38][.15FF.0020.001A.FC38] # ARABIC LIGATURE KAF WITH JEEM ISOLATED FORM; QQKN +FCC5 ; [.164D.0020.0017.FCC5][.1605.0020.0017.FCC5] # ARABIC LIGATURE KAF WITH HAH INITIAL FORM; QQKN +FC39 ; [.164D.0020.001A.FC39][.1605.0020.001A.FC39] # ARABIC LIGATURE KAF WITH HAH ISOLATED FORM; QQKN +FCC6 ; [.164D.0020.0017.FCC6][.1606.0020.0017.FCC6] # ARABIC LIGATURE KAF WITH KHAH INITIAL FORM; QQKN +FC3A ; [.164D.0020.001A.FC3A][.1606.0020.001A.FC3A] # ARABIC LIGATURE KAF WITH KHAH ISOLATED FORM; QQKN +FCC7 ; [.164D.0020.0017.FCC7][.165D.0020.0017.FCC7] # ARABIC LIGATURE KAF WITH LAM INITIAL FORM; QQKN +FCEB ; [.164D.0020.0018.FCEB][.165D.0020.0018.FCEB] # ARABIC LIGATURE KAF WITH LAM MEDIAL FORM; QQKN +FC81 ; [.164D.0020.0019.FC81][.165D.0020.0019.FC81] # ARABIC LIGATURE KAF WITH LAM FINAL FORM; QQKN +FC3B ; [.164D.0020.001A.FC3B][.165D.0020.001A.FC3B] # ARABIC LIGATURE KAF WITH LAM ISOLATED FORM; QQKN +FCC8 ; [.164D.0020.0017.FCC8][.1663.0020.0017.FCC8] # ARABIC LIGATURE KAF WITH MEEM INITIAL FORM; QQKN +FCEC ; [.164D.0020.0018.FCEC][.1663.0020.0018.FCEC] # ARABIC LIGATURE KAF WITH MEEM MEDIAL FORM; QQKN +FC82 ; [.164D.0020.0019.FC82][.1663.0020.0019.FC82] # ARABIC LIGATURE KAF WITH MEEM FINAL FORM; QQKN +FC3C ; [.164D.0020.001A.FC3C][.1663.0020.001A.FC3C] # ARABIC LIGATURE KAF WITH MEEM ISOLATED FORM; QQKN +FDC3 ; [.164D.0020.0017.FDC3][.1663.0020.0017.FDC3][.1663.0020.001F.FDC3] # ARABIC LIGATURE KAF WITH MEEM WITH MEEM INITIAL FORM; QQKN +FDBB ; [.164D.0020.0019.FDBB][.1663.0020.0019.FDBB][.1663.0020.001F.FDBB] # ARABIC LIGATURE KAF WITH MEEM WITH MEEM FINAL FORM; QQKN +FDB7 ; [.164D.0020.0019.FDB7][.1663.0020.0019.FDB7][.1680.0020.001F.FDB7] # ARABIC LIGATURE KAF WITH MEEM WITH YEH FINAL FORM; QQKN +FC83 ; [.164D.0020.0019.FC83][.167F.0020.0019.FC83] # ARABIC LIGATURE KAF WITH ALEF MAKSURA FINAL FORM; QQKN +FC3D ; [.164D.0020.001A.FC3D][.167F.0020.001A.FC3D] # ARABIC LIGATURE KAF WITH ALEF MAKSURA ISOLATED FORM; QQKN +FC84 ; [.164D.0020.0019.FC84][.1680.0020.0019.FC84] # ARABIC LIGATURE KAF WITH YEH FINAL FORM; QQKN +FC3E ; [.164D.0020.001A.FC3E][.1680.0020.001A.FC3E] # ARABIC LIGATURE KAF WITH YEH ISOLATED FORM; QQKN +06A9 ; [.164E.0020.0002.06A9] # ARABIC LETTER KEHEH +FB90 ; [.164E.0020.0017.FB90] # ARABIC LETTER KEHEH INITIAL FORM; QQK +FB91 ; [.164E.0020.0018.FB91] # ARABIC LETTER KEHEH MEDIAL FORM; QQK +FB8F ; [.164E.0020.0019.FB8F] # ARABIC LETTER KEHEH FINAL FORM; QQK +FB8E ; [.164E.0020.001A.FB8E] # ARABIC LETTER KEHEH ISOLATED FORM; QQK +06AA ; [.164F.0020.0002.06AA] # ARABIC LETTER SWASH KAF +06AB ; [.1650.0020.0002.06AB] # ARABIC LETTER KAF WITH RING +06AC ; [.1651.0020.0002.06AC] # ARABIC LETTER KAF WITH DOT ABOVE +06AD ; [.1652.0020.0002.06AD] # ARABIC LETTER NG +FBD5 ; [.1652.0020.0017.FBD5] # ARABIC LETTER NG INITIAL FORM; QQK +FBD6 ; [.1652.0020.0018.FBD6] # ARABIC LETTER NG MEDIAL FORM; QQK +FBD4 ; [.1652.0020.0019.FBD4] # ARABIC LETTER NG FINAL FORM; QQK +FBD3 ; [.1652.0020.001A.FBD3] # ARABIC LETTER NG ISOLATED FORM; QQK +06AE ; [.1653.0020.0002.06AE] # ARABIC LETTER KAF WITH THREE DOTS BELOW +06AF ; [.1654.0020.0002.06AF] # ARABIC LETTER GAF +FB94 ; [.1654.0020.0017.FB94] # ARABIC LETTER GAF INITIAL FORM; QQK +FB95 ; [.1654.0020.0018.FB95] # ARABIC LETTER GAF MEDIAL FORM; QQK +FB93 ; [.1654.0020.0019.FB93] # ARABIC LETTER GAF FINAL FORM; QQK +FB92 ; [.1654.0020.001A.FB92] # ARABIC LETTER GAF ISOLATED FORM; QQK +06B0 ; [.1655.0020.0002.06B0] # ARABIC LETTER GAF WITH RING +06B1 ; [.1656.0020.0002.06B1] # ARABIC LETTER NGOEH +FB9C ; [.1656.0020.0017.FB9C] # ARABIC LETTER NGOEH INITIAL FORM; QQK +FB9D ; [.1656.0020.0018.FB9D] # ARABIC LETTER NGOEH MEDIAL FORM; QQK +FB9B ; [.1656.0020.0019.FB9B] # ARABIC LETTER NGOEH FINAL FORM; QQK +FB9A ; [.1656.0020.001A.FB9A] # ARABIC LETTER NGOEH ISOLATED FORM; QQK +06B2 ; [.1657.0020.0002.06B2] # ARABIC LETTER GAF WITH TWO DOTS BELOW +06B3 ; [.1658.0020.0002.06B3] # ARABIC LETTER GUEH +FB98 ; [.1658.0020.0017.FB98] # ARABIC LETTER GUEH INITIAL FORM; QQK +FB99 ; [.1658.0020.0018.FB99] # ARABIC LETTER GUEH MEDIAL FORM; QQK +FB97 ; [.1658.0020.0019.FB97] # ARABIC LETTER GUEH FINAL FORM; QQK +FB96 ; [.1658.0020.001A.FB96] # ARABIC LETTER GUEH ISOLATED FORM; QQK +06B4 ; [.1659.0020.0002.06B4] # ARABIC LETTER GAF WITH THREE DOTS ABOVE +0762 ; [.165A.0020.0002.0762] # ARABIC LETTER KEHEH WITH DOT ABOVE +0763 ; [.165B.0020.0002.0763] # ARABIC LETTER KEHEH WITH THREE DOTS ABOVE +0764 ; [.165C.0020.0002.0764] # ARABIC LETTER KEHEH WITH THREE DOTS POINTING UPWARDS BELOW +0644 ; [.165D.0020.0002.0644] # ARABIC LETTER LAM +FEDF ; [.165D.0020.0017.FEDF] # ARABIC LETTER LAM INITIAL FORM; QQK +FEE0 ; [.165D.0020.0018.FEE0] # ARABIC LETTER LAM MEDIAL FORM; QQK +FEDE ; [.165D.0020.0019.FEDE] # ARABIC LETTER LAM FINAL FORM; QQK +FEDD ; [.165D.0020.001A.FEDD] # ARABIC LETTER LAM ISOLATED FORM; QQK +FEF6 ; [.165D.0020.0019.FEF6][.15E2.0020.0019.FEF6] # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM; QQKN +FEF5 ; [.165D.0020.001A.FEF5][.15E2.0020.001A.FEF5] # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM; QQKN +FEF8 ; [.165D.0020.0019.FEF8][.15E3.0020.0019.FEF8] # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM; QQKN +FEF7 ; [.165D.0020.001A.FEF7][.15E3.0020.001A.FEF7] # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM; QQKN +FEFA ; [.165D.0020.0019.FEFA][.15E7.0020.0019.FEFA] # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM; QQKN +FEF9 ; [.165D.0020.001A.FEF9][.15E7.0020.001A.FEF9] # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM; QQKN +FEFC ; [.165D.0020.0019.FEFC][.15EA.0020.0019.FEFC] # ARABIC LIGATURE LAM WITH ALEF FINAL FORM; QQKN +FEFB ; [.165D.0020.001A.FEFB][.15EA.0020.001A.FEFB] # ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM; QQKN +FCC9 ; [.165D.0020.0017.FCC9][.15FF.0020.0017.FCC9] # ARABIC LIGATURE LAM WITH JEEM INITIAL FORM; QQKN +FC3F ; [.165D.0020.001A.FC3F][.15FF.0020.001A.FC3F] # ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM; QQKN +FD83 ; [.165D.0020.0017.FD83][.15FF.0020.0017.FD83][.15FF.0020.001F.FD83] # ARABIC LIGATURE LAM WITH JEEM WITH JEEM INITIAL FORM; QQKN +FD84 ; [.165D.0020.0019.FD84][.15FF.0020.0019.FD84][.15FF.0020.001F.FD84] # ARABIC LIGATURE LAM WITH JEEM WITH JEEM FINAL FORM; QQKN +FDBA ; [.165D.0020.0017.FDBA][.15FF.0020.0017.FDBA][.1663.0020.001F.FDBA] # ARABIC LIGATURE LAM WITH JEEM WITH MEEM INITIAL FORM; QQKN +FDBC ; [.165D.0020.0019.FDBC][.15FF.0020.0019.FDBC][.1663.0020.001F.FDBC] # ARABIC LIGATURE LAM WITH JEEM WITH MEEM FINAL FORM; QQKN +FDAC ; [.165D.0020.0019.FDAC][.15FF.0020.0019.FDAC][.1680.0020.001F.FDAC] # ARABIC LIGATURE LAM WITH JEEM WITH YEH FINAL FORM; QQKN +FCCA ; [.165D.0020.0017.FCCA][.1605.0020.0017.FCCA] # ARABIC LIGATURE LAM WITH HAH INITIAL FORM; QQKN +FC40 ; [.165D.0020.001A.FC40][.1605.0020.001A.FC40] # ARABIC LIGATURE LAM WITH HAH ISOLATED FORM; QQKN +FDB5 ; [.165D.0020.0017.FDB5][.1605.0020.0017.FDB5][.1663.0020.001F.FDB5] # ARABIC LIGATURE LAM WITH HAH WITH MEEM INITIAL FORM; QQKN +FD80 ; [.165D.0020.0019.FD80][.1605.0020.0019.FD80][.1663.0020.001F.FD80] # ARABIC LIGATURE LAM WITH HAH WITH MEEM FINAL FORM; QQKN +FD82 ; [.165D.0020.0019.FD82][.1605.0020.0019.FD82][.167F.0020.001F.FD82] # ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA FINAL FORM; QQKN +FD81 ; [.165D.0020.0019.FD81][.1605.0020.0019.FD81][.1680.0020.001F.FD81] # ARABIC LIGATURE LAM WITH HAH WITH YEH FINAL FORM; QQKN +FCCB ; [.165D.0020.0017.FCCB][.1606.0020.0017.FCCB] # ARABIC LIGATURE LAM WITH KHAH INITIAL FORM; QQKN +FC41 ; [.165D.0020.001A.FC41][.1606.0020.001A.FC41] # ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM; QQKN +FD86 ; [.165D.0020.0017.FD86][.1606.0020.0017.FD86][.1663.0020.001F.FD86] # ARABIC LIGATURE LAM WITH KHAH WITH MEEM INITIAL FORM; QQKN +FD85 ; [.165D.0020.0019.FD85][.1606.0020.0019.FD85][.1663.0020.001F.FD85] # ARABIC LIGATURE LAM WITH KHAH WITH MEEM FINAL FORM; QQKN +FCCC ; [.165D.0020.0017.FCCC][.1663.0020.0017.FCCC] # ARABIC LIGATURE LAM WITH MEEM INITIAL FORM; QQKN +FCED ; [.165D.0020.0018.FCED][.1663.0020.0018.FCED] # ARABIC LIGATURE LAM WITH MEEM MEDIAL FORM; QQKN +FC85 ; [.165D.0020.0019.FC85][.1663.0020.0019.FC85] # ARABIC LIGATURE LAM WITH MEEM FINAL FORM; QQKN +FC42 ; [.165D.0020.001A.FC42][.1663.0020.001A.FC42] # ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM; QQKN +FD88 ; [.165D.0020.0017.FD88][.1663.0020.0017.FD88][.1605.0020.001F.FD88] # ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM; QQKN +FD87 ; [.165D.0020.0019.FD87][.1663.0020.0019.FD87][.1605.0020.001F.FD87] # ARABIC LIGATURE LAM WITH MEEM WITH HAH FINAL FORM; QQKN +FDAD ; [.165D.0020.0019.FDAD][.1663.0020.0019.FDAD][.1680.0020.001F.FDAD] # ARABIC LIGATURE LAM WITH MEEM WITH YEH FINAL FORM; QQKN +FCCD ; [.165D.0020.0017.FCCD][.166F.0020.0017.FCCD] # ARABIC LIGATURE LAM WITH HEH INITIAL FORM; QQKN +FC86 ; [.165D.0020.0019.FC86][.167F.0020.0019.FC86] # ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM; QQKN +FC43 ; [.165D.0020.001A.FC43][.167F.0020.001A.FC43] # ARABIC LIGATURE LAM WITH ALEF MAKSURA ISOLATED FORM; QQKN +FC87 ; [.165D.0020.0019.FC87][.1680.0020.0019.FC87] # ARABIC LIGATURE LAM WITH YEH FINAL FORM; QQKN +FC44 ; [.165D.0020.001A.FC44][.1680.0020.001A.FC44] # ARABIC LIGATURE LAM WITH YEH ISOLATED FORM; QQKN +06B5 ; [.165E.0020.0002.06B5] # ARABIC LETTER LAM WITH SMALL V +06B6 ; [.165F.0020.0002.06B6] # ARABIC LETTER LAM WITH DOT ABOVE +06B7 ; [.1660.0020.0002.06B7] # ARABIC LETTER LAM WITH THREE DOTS ABOVE +06B8 ; [.1661.0020.0002.06B8] # ARABIC LETTER LAM WITH THREE DOTS BELOW +076A ; [.1662.0020.0002.076A] # ARABIC LETTER LAM WITH BAR +0645 ; [.1663.0020.0002.0645] # ARABIC LETTER MEEM +FEE3 ; [.1663.0020.0017.FEE3] # ARABIC LETTER MEEM INITIAL FORM; QQK +FEE4 ; [.1663.0020.0018.FEE4] # ARABIC LETTER MEEM MEDIAL FORM; QQK +FEE2 ; [.1663.0020.0019.FEE2] # ARABIC LETTER MEEM FINAL FORM; QQK +FEE1 ; [.1663.0020.001A.FEE1] # ARABIC LETTER MEEM ISOLATED FORM; QQK +06FE ; [.1663.0020.0004.06FE][.0000.019A.0004.06FE] # ARABIC SIGN SINDHI POSTPOSITION MEN; QQKN +FC88 ; [.1663.0020.0019.FC88][.15EA.0020.0019.FC88] # ARABIC LIGATURE MEEM WITH ALEF FINAL FORM; QQKN +FCCE ; [.1663.0020.0017.FCCE][.15FF.0020.0017.FCCE] # ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM; QQKN +FC45 ; [.1663.0020.001A.FC45][.15FF.0020.001A.FC45] # ARABIC LIGATURE MEEM WITH JEEM ISOLATED FORM; QQKN +FD8C ; [.1663.0020.0017.FD8C][.15FF.0020.0017.FD8C][.1605.0020.001F.FD8C] # ARABIC LIGATURE MEEM WITH JEEM WITH HAH INITIAL FORM; QQKN +FD92 ; [.1663.0020.0017.FD92][.15FF.0020.0017.FD92][.1606.0020.001F.FD92] # ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM; QQKN +FD8D ; [.1663.0020.0017.FD8D][.15FF.0020.0017.FD8D][.1663.0020.001F.FD8D] # ARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORM; QQKN +FDC0 ; [.1663.0020.0019.FDC0][.15FF.0020.0019.FDC0][.1680.0020.001F.FDC0] # ARABIC LIGATURE MEEM WITH JEEM WITH YEH FINAL FORM; QQKN +FCCF ; [.1663.0020.0017.FCCF][.1605.0020.0017.FCCF] # ARABIC LIGATURE MEEM WITH HAH INITIAL FORM; QQKN +FC46 ; [.1663.0020.001A.FC46][.1605.0020.001A.FC46] # ARABIC LIGATURE MEEM WITH HAH ISOLATED FORM; QQKN +FD89 ; [.1663.0020.0017.FD89][.1605.0020.0017.FD89][.15FF.0020.001F.FD89] # ARABIC LIGATURE MEEM WITH HAH WITH JEEM INITIAL FORM; QQKN +FD8A ; [.1663.0020.0017.FD8A][.1605.0020.0017.FD8A][.1663.0020.001F.FD8A] # ARABIC LIGATURE MEEM WITH HAH WITH MEEM INITIAL FORM; QQKN +FDF4 ; [.1663.0020.001A.FDF4][.1605.0020.001A.FDF4][.1663.0020.001F.FDF4][.160C.0020.001F.FDF4] # ARABIC LIGATURE MOHAMMAD ISOLATED FORM; QQKN +FD8B ; [.1663.0020.0019.FD8B][.1605.0020.0019.FD8B][.1680.0020.001F.FD8B] # ARABIC LIGATURE MEEM WITH HAH WITH YEH FINAL FORM; QQKN +FCD0 ; [.1663.0020.0017.FCD0][.1606.0020.0017.FCD0] # ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM; QQKN +FC47 ; [.1663.0020.001A.FC47][.1606.0020.001A.FC47] # ARABIC LIGATURE MEEM WITH KHAH ISOLATED FORM; QQKN +FD8E ; [.1663.0020.0017.FD8E][.1606.0020.0017.FD8E][.15FF.0020.001F.FD8E] # ARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORM; QQKN +FD8F ; [.1663.0020.0017.FD8F][.1606.0020.0017.FD8F][.1663.0020.001F.FD8F] # ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM; QQKN +FDB9 ; [.1663.0020.0019.FDB9][.1606.0020.0019.FDB9][.1680.0020.001F.FDB9] # ARABIC LIGATURE MEEM WITH KHAH WITH YEH FINAL FORM; QQKN +FCD1 ; [.1663.0020.0017.FCD1][.1663.0020.0017.FCD1] # ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM; QQKN +FC89 ; [.1663.0020.0019.FC89][.1663.0020.0019.FC89] # ARABIC LIGATURE MEEM WITH MEEM FINAL FORM; QQKN +FC48 ; [.1663.0020.001A.FC48][.1663.0020.001A.FC48] # ARABIC LIGATURE MEEM WITH MEEM ISOLATED FORM; QQKN +FDB1 ; [.1663.0020.0019.FDB1][.1663.0020.0019.FDB1][.1680.0020.001F.FDB1] # ARABIC LIGATURE MEEM WITH MEEM WITH YEH FINAL FORM; QQKN +FC49 ; [.1663.0020.001A.FC49][.167F.0020.001A.FC49] # ARABIC LIGATURE MEEM WITH ALEF MAKSURA ISOLATED FORM; QQKN +FC4A ; [.1663.0020.001A.FC4A][.1680.0020.001A.FC4A] # ARABIC LIGATURE MEEM WITH YEH ISOLATED FORM; QQKN +0765 ; [.1664.0020.0002.0765] # ARABIC LETTER MEEM WITH DOT ABOVE +0766 ; [.1665.0020.0002.0766] # ARABIC LETTER MEEM WITH DOT BELOW +0646 ; [.1666.0020.0002.0646] # ARABIC LETTER NOON +FEE7 ; [.1666.0020.0017.FEE7] # ARABIC LETTER NOON INITIAL FORM; QQK +FEE8 ; [.1666.0020.0018.FEE8] # ARABIC LETTER NOON MEDIAL FORM; QQK +FEE6 ; [.1666.0020.0019.FEE6] # ARABIC LETTER NOON FINAL FORM; QQK +FEE5 ; [.1666.0020.001A.FEE5] # ARABIC LETTER NOON ISOLATED FORM; QQK +FCD2 ; [.1666.0020.0017.FCD2][.15FF.0020.0017.FCD2] # ARABIC LIGATURE NOON WITH JEEM INITIAL FORM; QQKN +FC4B ; [.1666.0020.001A.FC4B][.15FF.0020.001A.FC4B] # ARABIC LIGATURE NOON WITH JEEM ISOLATED FORM; QQKN +FDB8 ; [.1666.0020.0017.FDB8][.15FF.0020.0017.FDB8][.1605.0020.001F.FDB8] # ARABIC LIGATURE NOON WITH JEEM WITH HAH INITIAL FORM; QQKN +FDBD ; [.1666.0020.0019.FDBD][.15FF.0020.0019.FDBD][.1605.0020.001F.FDBD] # ARABIC LIGATURE NOON WITH JEEM WITH HAH FINAL FORM; QQKN +FD98 ; [.1666.0020.0017.FD98][.15FF.0020.0017.FD98][.1663.0020.001F.FD98] # ARABIC LIGATURE NOON WITH JEEM WITH MEEM INITIAL FORM; QQKN +FD97 ; [.1666.0020.0019.FD97][.15FF.0020.0019.FD97][.1663.0020.001F.FD97] # ARABIC LIGATURE NOON WITH JEEM WITH MEEM FINAL FORM; QQKN +FD99 ; [.1666.0020.0019.FD99][.15FF.0020.0019.FD99][.167F.0020.001F.FD99] # ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA FINAL FORM; QQKN +FDC7 ; [.1666.0020.0019.FDC7][.15FF.0020.0019.FDC7][.1680.0020.001F.FDC7] # ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM; QQKN +FCD3 ; [.1666.0020.0017.FCD3][.1605.0020.0017.FCD3] # ARABIC LIGATURE NOON WITH HAH INITIAL FORM; QQKN +FC4C ; [.1666.0020.001A.FC4C][.1605.0020.001A.FC4C] # ARABIC LIGATURE NOON WITH HAH ISOLATED FORM; QQKN +FD95 ; [.1666.0020.0017.FD95][.1605.0020.0017.FD95][.1663.0020.001F.FD95] # ARABIC LIGATURE NOON WITH HAH WITH MEEM INITIAL FORM; QQKN +FD96 ; [.1666.0020.0019.FD96][.1605.0020.0019.FD96][.167F.0020.001F.FD96] # ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA FINAL FORM; QQKN +FDB3 ; [.1666.0020.0019.FDB3][.1605.0020.0019.FDB3][.1680.0020.001F.FDB3] # ARABIC LIGATURE NOON WITH HAH WITH YEH FINAL FORM; QQKN +FCD4 ; [.1666.0020.0017.FCD4][.1606.0020.0017.FCD4] # ARABIC LIGATURE NOON WITH KHAH INITIAL FORM; QQKN +FC4D ; [.1666.0020.001A.FC4D][.1606.0020.001A.FC4D] # ARABIC LIGATURE NOON WITH KHAH ISOLATED FORM; QQKN +FC8A ; [.1666.0020.0019.FC8A][.161A.0020.0019.FC8A] # ARABIC LIGATURE NOON WITH REH FINAL FORM; QQKN +FC8B ; [.1666.0020.0019.FC8B][.161B.0020.0019.FC8B] # ARABIC LIGATURE NOON WITH ZAIN FINAL FORM; QQKN +FCD5 ; [.1666.0020.0017.FCD5][.1663.0020.0017.FCD5] # ARABIC LIGATURE NOON WITH MEEM INITIAL FORM; QQKN +FCEE ; [.1666.0020.0018.FCEE][.1663.0020.0018.FCEE] # ARABIC LIGATURE NOON WITH MEEM MEDIAL FORM; QQKN +FC8C ; [.1666.0020.0019.FC8C][.1663.0020.0019.FC8C] # ARABIC LIGATURE NOON WITH MEEM FINAL FORM; QQKN +FC4E ; [.1666.0020.001A.FC4E][.1663.0020.001A.FC4E] # ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM; QQKN +FD9B ; [.1666.0020.0019.FD9B][.1663.0020.0019.FD9B][.167F.0020.001F.FD9B] # ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA FINAL FORM; QQKN +FD9A ; [.1666.0020.0019.FD9A][.1663.0020.0019.FD9A][.1680.0020.001F.FD9A] # ARABIC LIGATURE NOON WITH MEEM WITH YEH FINAL FORM; QQKN +FC8D ; [.1666.0020.0019.FC8D][.1666.0020.0019.FC8D] # ARABIC LIGATURE NOON WITH NOON FINAL FORM; QQKN +FCD6 ; [.1666.0020.0017.FCD6][.166F.0020.0017.FCD6] # ARABIC LIGATURE NOON WITH HEH INITIAL FORM; QQKN +FCEF ; [.1666.0020.0018.FCEF][.166F.0020.0018.FCEF] # ARABIC LIGATURE NOON WITH HEH MEDIAL FORM; QQKN +FC8E ; [.1666.0020.0019.FC8E][.167F.0020.0019.FC8E] # ARABIC LIGATURE NOON WITH ALEF MAKSURA FINAL FORM; QQKN +FC4F ; [.1666.0020.001A.FC4F][.167F.0020.001A.FC4F] # ARABIC LIGATURE NOON WITH ALEF MAKSURA ISOLATED FORM; QQKN +FC8F ; [.1666.0020.0019.FC8F][.1680.0020.0019.FC8F] # ARABIC LIGATURE NOON WITH YEH FINAL FORM; QQKN +FC50 ; [.1666.0020.001A.FC50][.1680.0020.001A.FC50] # ARABIC LIGATURE NOON WITH YEH ISOLATED FORM; QQKN +06BA ; [.1667.0020.0002.06BA] # ARABIC LETTER NOON GHUNNA +FB9F ; [.1667.0020.0019.FB9F] # ARABIC LETTER NOON GHUNNA FINAL FORM; QQK +FB9E ; [.1667.0020.001A.FB9E] # ARABIC LETTER NOON GHUNNA ISOLATED FORM; QQK +06BB ; [.1668.0020.0002.06BB] # ARABIC LETTER RNOON +FBA2 ; [.1668.0020.0017.FBA2] # ARABIC LETTER RNOON INITIAL FORM; QQK +FBA3 ; [.1668.0020.0018.FBA3] # ARABIC LETTER RNOON MEDIAL FORM; QQK +FBA1 ; [.1668.0020.0019.FBA1] # ARABIC LETTER RNOON FINAL FORM; QQK +FBA0 ; [.1668.0020.001A.FBA0] # ARABIC LETTER RNOON ISOLATED FORM; QQK +06BC ; [.1669.0020.0002.06BC] # ARABIC LETTER NOON WITH RING +06BD ; [.166A.0020.0002.06BD] # ARABIC LETTER NOON WITH THREE DOTS ABOVE +06B9 ; [.166B.0020.0002.06B9] # ARABIC LETTER NOON WITH DOT BELOW +0767 ; [.166C.0020.0002.0767] # ARABIC LETTER NOON WITH TWO DOTS BELOW +0768 ; [.166D.0020.0002.0768] # ARABIC LETTER NOON WITH SMALL TAH +0769 ; [.166E.0020.0002.0769] # ARABIC LETTER NOON WITH SMALL V +0647 ; [.166F.0020.0002.0647] # ARABIC LETTER HEH +FEEB ; [.166F.0020.0017.FEEB] # ARABIC LETTER HEH INITIAL FORM; QQK +FEEC ; [.166F.0020.0018.FEEC] # ARABIC LETTER HEH MEDIAL FORM; QQK +FEEA ; [.166F.0020.0019.FEEA] # ARABIC LETTER HEH FINAL FORM; QQK +FEE9 ; [.166F.0020.001A.FEE9] # ARABIC LETTER HEH ISOLATED FORM; QQK +FCD9 ; [.166F.0020.0017.FCD9][.0000.00F3.0017.FCD9] # ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF INITIAL FORM; QQKN +FCD7 ; [.166F.0020.0017.FCD7][.15FF.0020.0017.FCD7] # ARABIC LIGATURE HEH WITH JEEM INITIAL FORM; QQKN +FC51 ; [.166F.0020.001A.FC51][.15FF.0020.001A.FC51] # ARABIC LIGATURE HEH WITH JEEM ISOLATED FORM; QQKN +FCD8 ; [.166F.0020.0017.FCD8][.1663.0020.0017.FCD8] # ARABIC LIGATURE HEH WITH MEEM INITIAL FORM; QQKN +FC52 ; [.166F.0020.001A.FC52][.1663.0020.001A.FC52] # ARABIC LIGATURE HEH WITH MEEM ISOLATED FORM; QQKN +FD93 ; [.166F.0020.0017.FD93][.1663.0020.0017.FD93][.15FF.0020.001F.FD93] # ARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORM; QQKN +FD94 ; [.166F.0020.0017.FD94][.1663.0020.0017.FD94][.1663.0020.001F.FD94] # ARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORM; QQKN +FC53 ; [.166F.0020.001A.FC53][.167F.0020.001A.FC53] # ARABIC LIGATURE HEH WITH ALEF MAKSURA ISOLATED FORM; QQKN +FC54 ; [.166F.0020.001A.FC54][.1680.0020.001A.FC54] # ARABIC LIGATURE HEH WITH YEH ISOLATED FORM; QQKN +06BE ; [.1670.0020.0002.06BE] # ARABIC LETTER HEH DOACHASHMEE +FBAC ; [.1670.0020.0017.FBAC] # ARABIC LETTER HEH DOACHASHMEE INITIAL FORM; QQK +FBAD ; [.1670.0020.0018.FBAD] # ARABIC LETTER HEH DOACHASHMEE MEDIAL FORM; QQK +FBAB ; [.1670.0020.0019.FBAB] # ARABIC LETTER HEH DOACHASHMEE FINAL FORM; QQK +FBAA ; [.1670.0020.001A.FBAA] # ARABIC LETTER HEH DOACHASHMEE ISOLATED FORM; QQK +06C1 ; [.1671.0020.0002.06C1] # ARABIC LETTER HEH GOAL +FBA8 ; [.1671.0020.0017.FBA8] # ARABIC LETTER HEH GOAL INITIAL FORM; QQK +FBA9 ; [.1671.0020.0018.FBA9] # ARABIC LETTER HEH GOAL MEDIAL FORM; QQK +FBA7 ; [.1671.0020.0019.FBA7] # ARABIC LETTER HEH GOAL FINAL FORM; QQK +FBA6 ; [.1671.0020.001A.FBA6] # ARABIC LETTER HEH GOAL ISOLATED FORM; QQK +06C2 ; [.1671.0020.0002.06C1][.0000.00E8.0002.0654] # ARABIC LETTER HEH GOAL WITH HAMZA ABOVE; QQCM +06C3 ; [.1672.0020.0002.06C3] # ARABIC LETTER TEH MARBUTA GOAL +06FF ; [.1673.0020.0002.06FF] # ARABIC LETTER HEH WITH INVERTED V +06D5 ; [.1674.0020.0002.06D5] # ARABIC LETTER AE +06C0 ; [.1674.0020.0002.06D5][.0000.00E8.0002.0654] # ARABIC LETTER HEH WITH YEH ABOVE; QQCM +FBA5 ; [.1674.0020.0019.FBA5][.0000.00E8.0019.FBA5] # ARABIC LETTER HEH WITH YEH ABOVE FINAL FORM; QQKN +FBA4 ; [.1674.0020.001A.FBA4][.0000.00E8.001A.FBA4] # ARABIC LETTER HEH WITH YEH ABOVE ISOLATED FORM; QQKN +0648 ; [.1675.0020.0002.0648] # ARABIC LETTER WAW +06E5 ; [.1675.0020.0004.06E5] # ARABIC SMALL WAW; QQK +FEEE ; [.1675.0020.0019.FEEE] # ARABIC LETTER WAW FINAL FORM; QQK +FEED ; [.1675.0020.001A.FEED] # ARABIC LETTER WAW ISOLATED FORM; QQK +0676 ; [.1675.0020.0004.0676][.15E1.0020.0004.0676] # ARABIC LETTER HIGH HAMZA WAW; QQKN +FDF8 ; [.1675.0020.001A.FDF8][.1629.0020.001A.FDF8][.165D.0020.001F.FDF8][.1663.0020.001F.FDF8] # ARABIC LIGATURE WASALLAM ISOLATED FORM; QQKN +06C4 ; [.1676.0020.0002.06C4] # ARABIC LETTER WAW WITH RING +06C5 ; [.1677.0020.0002.06C5] # ARABIC LETTER KIRGHIZ OE +FBE1 ; [.1677.0020.0019.FBE1] # ARABIC LETTER KIRGHIZ OE FINAL FORM; QQK +FBE0 ; [.1677.0020.001A.FBE0] # ARABIC LETTER KIRGHIZ OE ISOLATED FORM; QQK +06C6 ; [.1678.0020.0002.06C6] # ARABIC LETTER OE +FBDA ; [.1678.0020.0019.FBDA] # ARABIC LETTER OE FINAL FORM; QQK +FBD9 ; [.1678.0020.001A.FBD9] # ARABIC LETTER OE ISOLATED FORM; QQK +06C7 ; [.1679.0020.0002.06C7] # ARABIC LETTER U +FBD8 ; [.1679.0020.0019.FBD8] # ARABIC LETTER U FINAL FORM; QQK +FBD7 ; [.1679.0020.001A.FBD7] # ARABIC LETTER U ISOLATED FORM; QQK +0677 ; [.1679.0020.0004.0677][.15E1.0020.0004.0677] # ARABIC LETTER U WITH HAMZA ABOVE; QQKN +FBDD ; [.1679.0020.001A.FBDD][.15E1.0020.001A.FBDD] # ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM; QQKN +06C8 ; [.167A.0020.0002.06C8] # ARABIC LETTER YU +FBDC ; [.167A.0020.0019.FBDC] # ARABIC LETTER YU FINAL FORM; QQK +FBDB ; [.167A.0020.001A.FBDB] # ARABIC LETTER YU ISOLATED FORM; QQK +06C9 ; [.167B.0020.0002.06C9] # ARABIC LETTER KIRGHIZ YU +FBE3 ; [.167B.0020.0019.FBE3] # ARABIC LETTER KIRGHIZ YU FINAL FORM; QQK +FBE2 ; [.167B.0020.001A.FBE2] # ARABIC LETTER KIRGHIZ YU ISOLATED FORM; QQK +06CA ; [.167C.0020.0002.06CA] # ARABIC LETTER WAW WITH TWO DOTS ABOVE +06CB ; [.167D.0020.0002.06CB] # ARABIC LETTER VE +FBDF ; [.167D.0020.0019.FBDF] # ARABIC LETTER VE FINAL FORM; QQK +FBDE ; [.167D.0020.001A.FBDE] # ARABIC LETTER VE ISOLATED FORM; QQK +06CF ; [.167E.0020.0002.06CF] # ARABIC LETTER WAW WITH DOT ABOVE +0649 ; [.167F.0020.0002.0649] # ARABIC LETTER ALEF MAKSURA +FBE8 ; [.167F.0020.0017.FBE8] # ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM; QQK +FBE9 ; [.167F.0020.0018.FBE9] # ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA MEDIAL FORM; QQK +FEF0 ; [.167F.0020.0019.FEF0] # ARABIC LETTER ALEF MAKSURA FINAL FORM; QQK +FEEF ; [.167F.0020.001A.FEEF] # ARABIC LETTER ALEF MAKSURA ISOLATED FORM; QQK +FC90 ; [.167F.0020.0019.FC90][.0000.00F3.0019.FC90] # ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF FINAL FORM; QQKN +FC5D ; [.167F.0020.001A.FC5D][.0000.00F3.001A.FC5D] # ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED FORM; QQKN +064A ; [.1680.0020.0002.064A] # ARABIC LETTER YEH +06E6 ; [.1680.0020.0004.06E6] # ARABIC SMALL YEH; QQK +FEF3 ; [.1680.0020.0017.FEF3] # ARABIC LETTER YEH INITIAL FORM; QQK +FEF4 ; [.1680.0020.0018.FEF4] # ARABIC LETTER YEH MEDIAL FORM; QQK +FEF2 ; [.1680.0020.0019.FEF2] # ARABIC LETTER YEH FINAL FORM; QQK +FEF1 ; [.1680.0020.001A.FEF1] # ARABIC LETTER YEH ISOLATED FORM; QQK +0678 ; [.1680.0020.0004.0678][.15E1.0020.0004.0678] # ARABIC LETTER HIGH HAMZA YEH; QQKN +FCDA ; [.1680.0020.0017.FCDA][.15FF.0020.0017.FCDA] # ARABIC LIGATURE YEH WITH JEEM INITIAL FORM; QQKN +FC55 ; [.1680.0020.001A.FC55][.15FF.0020.001A.FC55] # ARABIC LIGATURE YEH WITH JEEM ISOLATED FORM; QQKN +FDAF ; [.1680.0020.0019.FDAF][.15FF.0020.0019.FDAF][.1680.0020.001F.FDAF] # ARABIC LIGATURE YEH WITH JEEM WITH YEH FINAL FORM; QQKN +FCDB ; [.1680.0020.0017.FCDB][.1605.0020.0017.FCDB] # ARABIC LIGATURE YEH WITH HAH INITIAL FORM; QQKN +FC56 ; [.1680.0020.001A.FC56][.1605.0020.001A.FC56] # ARABIC LIGATURE YEH WITH HAH ISOLATED FORM; QQKN +FDAE ; [.1680.0020.0019.FDAE][.1605.0020.0019.FDAE][.1680.0020.001F.FDAE] # ARABIC LIGATURE YEH WITH HAH WITH YEH FINAL FORM; QQKN +FCDC ; [.1680.0020.0017.FCDC][.1606.0020.0017.FCDC] # ARABIC LIGATURE YEH WITH KHAH INITIAL FORM; QQKN +FC57 ; [.1680.0020.001A.FC57][.1606.0020.001A.FC57] # ARABIC LIGATURE YEH WITH KHAH ISOLATED FORM; QQKN +FC91 ; [.1680.0020.0019.FC91][.161A.0020.0019.FC91] # ARABIC LIGATURE YEH WITH REH FINAL FORM; QQKN +FC92 ; [.1680.0020.0019.FC92][.161B.0020.0019.FC92] # ARABIC LIGATURE YEH WITH ZAIN FINAL FORM; QQKN +FCDD ; [.1680.0020.0017.FCDD][.1663.0020.0017.FCDD] # ARABIC LIGATURE YEH WITH MEEM INITIAL FORM; QQKN +FCF0 ; [.1680.0020.0018.FCF0][.1663.0020.0018.FCF0] # ARABIC LIGATURE YEH WITH MEEM MEDIAL FORM; QQKN +FC93 ; [.1680.0020.0019.FC93][.1663.0020.0019.FC93] # ARABIC LIGATURE YEH WITH MEEM FINAL FORM; QQKN +FC58 ; [.1680.0020.001A.FC58][.1663.0020.001A.FC58] # ARABIC LIGATURE YEH WITH MEEM ISOLATED FORM; QQKN +FD9D ; [.1680.0020.0017.FD9D][.1663.0020.0017.FD9D][.1663.0020.001F.FD9D] # ARABIC LIGATURE YEH WITH MEEM WITH MEEM INITIAL FORM; QQKN +FD9C ; [.1680.0020.0019.FD9C][.1663.0020.0019.FD9C][.1663.0020.001F.FD9C] # ARABIC LIGATURE YEH WITH MEEM WITH MEEM FINAL FORM; QQKN +FDB0 ; [.1680.0020.0019.FDB0][.1663.0020.0019.FDB0][.1680.0020.001F.FDB0] # ARABIC LIGATURE YEH WITH MEEM WITH YEH FINAL FORM; QQKN +FC94 ; [.1680.0020.0019.FC94][.1666.0020.0019.FC94] # ARABIC LIGATURE YEH WITH NOON FINAL FORM; QQKN +FCDE ; [.1680.0020.0017.FCDE][.166F.0020.0017.FCDE] # ARABIC LIGATURE YEH WITH HEH INITIAL FORM; QQKN +FCF1 ; [.1680.0020.0018.FCF1][.166F.0020.0018.FCF1] # ARABIC LIGATURE YEH WITH HEH MEDIAL FORM; QQKN +FC95 ; [.1680.0020.0019.FC95][.167F.0020.0019.FC95] # ARABIC LIGATURE YEH WITH ALEF MAKSURA FINAL FORM; QQKN +FC59 ; [.1680.0020.001A.FC59][.167F.0020.001A.FC59] # ARABIC LIGATURE YEH WITH ALEF MAKSURA ISOLATED FORM; QQKN +FC96 ; [.1680.0020.0019.FC96][.1680.0020.0019.FC96] # ARABIC LIGATURE YEH WITH YEH FINAL FORM; QQKN +FC5A ; [.1680.0020.001A.FC5A][.1680.0020.001A.FC5A] # ARABIC LIGATURE YEH WITH YEH ISOLATED FORM; QQKN +06CC ; [.1681.0020.0002.06CC] # ARABIC LETTER FARSI YEH +FBFE ; [.1681.0020.0017.FBFE] # ARABIC LETTER FARSI YEH INITIAL FORM; QQK +FBFF ; [.1681.0020.0018.FBFF] # ARABIC LETTER FARSI YEH MEDIAL FORM; QQK +FBFD ; [.1681.0020.0019.FBFD] # ARABIC LETTER FARSI YEH FINAL FORM; QQK +FBFC ; [.1681.0020.001A.FBFC] # ARABIC LETTER FARSI YEH ISOLATED FORM; QQK +06CD ; [.1682.0020.0002.06CD] # ARABIC LETTER YEH WITH TAIL +06CE ; [.1683.0020.0002.06CE] # ARABIC LETTER YEH WITH SMALL V +06D0 ; [.1684.0020.0002.06D0] # ARABIC LETTER E +FBE6 ; [.1684.0020.0017.FBE6] # ARABIC LETTER E INITIAL FORM; QQK +FBE7 ; [.1684.0020.0018.FBE7] # ARABIC LETTER E MEDIAL FORM; QQK +FBE5 ; [.1684.0020.0019.FBE5] # ARABIC LETTER E FINAL FORM; QQK +FBE4 ; [.1684.0020.001A.FBE4] # ARABIC LETTER E ISOLATED FORM; QQK +06D1 ; [.1685.0020.0002.06D1] # ARABIC LETTER YEH WITH THREE DOTS BELOW +06D2 ; [.1686.0020.0002.06D2] # ARABIC LETTER YEH BARREE +FBAF ; [.1686.0020.0019.FBAF] # ARABIC LETTER YEH BARREE FINAL FORM; QQK +FBAE ; [.1686.0020.001A.FBAE] # ARABIC LETTER YEH BARREE ISOLATED FORM; QQK +06D3 ; [.1686.0020.0002.06D2][.0000.00E8.0002.0654] # ARABIC LETTER YEH BARREE WITH HAMZA ABOVE; QQCM +FBB1 ; [.1686.0020.0019.FBB1][.0000.00E8.0019.FBB1] # ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM; QQKN +FBB0 ; [.1686.0020.001A.FBB0][.0000.00E8.001A.FBB0] # ARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORM; QQKN +0710 ; [.1687.0020.0002.0710] # SYRIAC LETTER ALAPH +0712 ; [.1688.0020.0002.0712] # SYRIAC LETTER BETH +072D ; [.1688.0020.0004.072D][.0000.019C.0004.072D] # SYRIAC LETTER PERSIAN BHETH; QQKN +0713 ; [.1689.0020.0002.0713] # SYRIAC LETTER GAMAL +0714 ; [.1689.0020.0004.0714][.0000.019A.0004.0714] # SYRIAC LETTER GAMAL GARSHUNI; QQKN +072E ; [.1689.0020.0004.072E][.0000.019C.0004.072E] # SYRIAC LETTER PERSIAN GHAMAL; QQKN +0716 ; [.168A.0020.0002.0716] # SYRIAC LETTER DOTLESS DALATH RISH +0715 ; [.168B.0020.0002.0715] # SYRIAC LETTER DALATH +072F ; [.168B.0020.0004.072F][.0000.019C.0004.072F] # SYRIAC LETTER PERSIAN DHALATH; QQKN +0717 ; [.168C.0020.0002.0717] # SYRIAC LETTER HE +0718 ; [.168D.0020.0002.0718] # SYRIAC LETTER WAW +0719 ; [.168E.0020.0002.0719] # SYRIAC LETTER ZAIN +074D ; [.168F.0020.0002.074D] # SYRIAC LETTER SOGDIAN ZHAIN +071A ; [.1690.0020.0002.071A] # SYRIAC LETTER HETH +071B ; [.1691.0020.0002.071B] # SYRIAC LETTER TETH +071C ; [.1691.0020.0004.071C][.0000.019A.0004.071C] # SYRIAC LETTER TETH GARSHUNI; QQKN +071D ; [.1692.0020.0002.071D] # SYRIAC LETTER YUDH +071E ; [.1693.0020.0002.071E] # SYRIAC LETTER YUDH HE +071F ; [.1694.0020.0002.071F] # SYRIAC LETTER KAPH +074E ; [.1695.0020.0002.074E] # SYRIAC LETTER SOGDIAN KHAPH +0720 ; [.1696.0020.0002.0720] # SYRIAC LETTER LAMADH +0721 ; [.1697.0020.0002.0721] # SYRIAC LETTER MIM +0722 ; [.1698.0020.0002.0722] # SYRIAC LETTER NUN +0723 ; [.1699.0020.0002.0723] # SYRIAC LETTER SEMKATH +0724 ; [.1699.0020.0019.0724] # SYRIAC LETTER FINAL SEMKATH; QQK +0725 ; [.169A.0020.0002.0725] # SYRIAC LETTER E +0726 ; [.169B.0020.0002.0726] # SYRIAC LETTER PE +0727 ; [.169B.0020.0004.0727][.0000.019A.0004.0727] # SYRIAC LETTER REVERSED PE; QQKN +074F ; [.169C.0020.0002.074F] # SYRIAC LETTER SOGDIAN FE +0728 ; [.169D.0020.0002.0728] # SYRIAC LETTER SADHE +0729 ; [.169E.0020.0002.0729] # SYRIAC LETTER QAPH +072A ; [.169F.0020.0002.072A] # SYRIAC LETTER RISH +072B ; [.16A0.0020.0002.072B] # SYRIAC LETTER SHIN +072C ; [.16A1.0020.0002.072C] # SYRIAC LETTER TAW +0780 ; [.16A2.0020.0002.0780] # THAANA LETTER HAA +0799 ; [.16A3.0020.0002.0799] # THAANA LETTER HHAA +079A ; [.16A4.0020.0002.079A] # THAANA LETTER KHAA +0781 ; [.16A5.0020.0002.0781] # THAANA LETTER SHAVIYANI +0782 ; [.16A6.0020.0002.0782] # THAANA LETTER NOONU +0783 ; [.16A7.0020.0002.0783] # THAANA LETTER RAA +079C ; [.16A8.0020.0002.079C] # THAANA LETTER ZAA +0784 ; [.16A9.0020.0002.0784] # THAANA LETTER BAA +0785 ; [.16AA.0020.0002.0785] # THAANA LETTER LHAVIYANI +0786 ; [.16AB.0020.0002.0786] # THAANA LETTER KAAFU +0787 ; [.16AC.0020.0002.0787] # THAANA LETTER ALIFU +07A2 ; [.16AD.0020.0002.07A2] # THAANA LETTER AINU +07A3 ; [.16AE.0020.0002.07A3] # THAANA LETTER GHAINU +0788 ; [.16AF.0020.0002.0788] # THAANA LETTER VAAVU +07A5 ; [.16B0.0020.0002.07A5] # THAANA LETTER WAAVU +0789 ; [.16B1.0020.0002.0789] # THAANA LETTER MEEMU +078A ; [.16B2.0020.0002.078A] # THAANA LETTER FAAFU +078B ; [.16B3.0020.0002.078B] # THAANA LETTER DHAALU +079B ; [.16B4.0020.0002.079B] # THAANA LETTER THAALU +078C ; [.16B5.0020.0002.078C] # THAANA LETTER THAA +0798 ; [.16B6.0020.0002.0798] # THAANA LETTER TTAA +07A0 ; [.16B7.0020.0002.07A0] # THAANA LETTER TO +07A1 ; [.16B8.0020.0002.07A1] # THAANA LETTER ZO +078D ; [.16B9.0020.0002.078D] # THAANA LETTER LAAMU +078E ; [.16BA.0020.0002.078E] # THAANA LETTER GAAFU +07A4 ; [.16BB.0020.0002.07A4] # THAANA LETTER QAAFU +078F ; [.16BC.0020.0002.078F] # THAANA LETTER GNAVIYANI +0790 ; [.16BD.0020.0002.0790] # THAANA LETTER SEENU +079D ; [.16BE.0020.0002.079D] # THAANA LETTER SHEENU +079E ; [.16BF.0020.0002.079E] # THAANA LETTER SAADHU +079F ; [.16C0.0020.0002.079F] # THAANA LETTER DAADHU +0791 ; [.16C1.0020.0002.0791] # THAANA LETTER DAVIYANI +0792 ; [.16C2.0020.0002.0792] # THAANA LETTER ZAVIYANI +0793 ; [.16C3.0020.0002.0793] # THAANA LETTER TAVIYANI +0794 ; [.16C4.0020.0002.0794] # THAANA LETTER YAA +0795 ; [.16C5.0020.0002.0795] # THAANA LETTER PAVIYANI +0796 ; [.16C6.0020.0002.0796] # THAANA LETTER JAVIYANI +0797 ; [.16C7.0020.0002.0797] # THAANA LETTER CHAVIYANI +07B1 ; [.16C8.0020.0002.07B1] # THAANA LETTER NAA +07A6 ; [.16C9.0020.0002.07A6] # THAANA ABAFILI +07A7 ; [.16CA.0020.0002.07A7] # THAANA AABAAFILI +07A8 ; [.16CB.0020.0002.07A8] # THAANA IBIFILI +07A9 ; [.16CC.0020.0002.07A9] # THAANA EEBEEFILI +07AA ; [.16CD.0020.0002.07AA] # THAANA UBUFILI +07AB ; [.16CE.0020.0002.07AB] # THAANA OOBOOFILI +07AC ; [.16CF.0020.0002.07AC] # THAANA EBEFILI +07AD ; [.16D0.0020.0002.07AD] # THAANA EYBEYFILI +07AE ; [.16D1.0020.0002.07AE] # THAANA OBOFILI +07AF ; [.16D2.0020.0002.07AF] # THAANA OABOAFILI +07B0 ; [.16D3.0020.0002.07B0] # THAANA SUKUN +07CA ; [.16D4.0020.0002.07CA] # NKO LETTER A +07CB ; [.16D5.0020.0002.07CB] # NKO LETTER EE +07CC ; [.16D6.0020.0002.07CC] # NKO LETTER I +07CD ; [.16D7.0020.0002.07CD] # NKO LETTER E +07CE ; [.16D8.0020.0002.07CE] # NKO LETTER U +07CF ; [.16D9.0020.0002.07CF] # NKO LETTER OO +07D0 ; [.16DA.0020.0002.07D0] # NKO LETTER O +07D1 ; [.16DB.0020.0002.07D1] # NKO LETTER DAGBASINNA +07D2 ; [.16DC.0020.0002.07D2] # NKO LETTER N +07D3 ; [.16DD.0020.0002.07D3] # NKO LETTER BA +07D4 ; [.16DE.0020.0002.07D4] # NKO LETTER PA +07D5 ; [.16DF.0020.0002.07D5] # NKO LETTER TA +07D6 ; [.16E0.0020.0002.07D6] # NKO LETTER JA +07E8 ; [.16E0.0020.0004.07E8][.0000.0199.0004.07E8] # NKO LETTER JONA JA; QQKN +07D7 ; [.16E1.0020.0002.07D7] # NKO LETTER CHA +07E9 ; [.16E1.0020.0004.07E9][.0000.0199.0004.07E9] # NKO LETTER JONA CHA; QQKN +07D8 ; [.16E2.0020.0002.07D8] # NKO LETTER DA +07D9 ; [.16E3.0020.0002.07D9] # NKO LETTER RA +07EA ; [.16E3.0020.0004.07EA][.0000.0199.0004.07EA] # NKO LETTER JONA RA; QQKN +07DA ; [.16E4.0020.0002.07DA] # NKO LETTER RRA +07DB ; [.16E5.0020.0002.07DB] # NKO LETTER SA +07DC ; [.16E6.0020.0002.07DC] # NKO LETTER GBA +07DD ; [.16E7.0020.0002.07DD] # NKO LETTER FA +07DE ; [.16E8.0020.0002.07DE] # NKO LETTER KA +07DF ; [.16E9.0020.0002.07DF] # NKO LETTER LA +07E0 ; [.16EA.0020.0002.07E0] # NKO LETTER NA WOLOSO +07E1 ; [.16EB.0020.0002.07E1] # NKO LETTER MA +07E2 ; [.16EC.0020.0002.07E2] # NKO LETTER NYA +07E3 ; [.16ED.0020.0002.07E3] # NKO LETTER NA +07E4 ; [.16EE.0020.0002.07E4] # NKO LETTER HA +07E5 ; [.16EF.0020.0002.07E5] # NKO LETTER WA +07E6 ; [.16F0.0020.0002.07E6] # NKO LETTER YA +07E7 ; [.16F1.0020.0002.07E7] # NKO LETTER NYA WOLOSO +07F4 ; [.16F2.0020.0002.07F4] # NKO HIGH TONE APOSTROPHE +07F5 ; [.16F3.0020.0002.07F5] # NKO LOW TONE APOSTROPHE +2D30 ; [.16F4.0020.0002.2D30] # TIFINAGH LETTER YA +2D31 ; [.16F5.0020.0002.2D31] # TIFINAGH LETTER YAB +2D32 ; [.16F6.0020.0002.2D32] # TIFINAGH LETTER YABH +2D33 ; [.16F7.0020.0002.2D33] # TIFINAGH LETTER YAG +2D34 ; [.16F8.0020.0002.2D34] # TIFINAGH LETTER YAGHH +2D35 ; [.16F9.0020.0002.2D35] # TIFINAGH LETTER BERBER ACADEMY YAJ +2D36 ; [.16FA.0020.0002.2D36] # TIFINAGH LETTER YAJ +2D37 ; [.16FB.0020.0002.2D37] # TIFINAGH LETTER YAD +2D38 ; [.16FC.0020.0002.2D38] # TIFINAGH LETTER YADH +2D39 ; [.16FD.0020.0002.2D39] # TIFINAGH LETTER YADD +2D3A ; [.16FE.0020.0002.2D3A] # TIFINAGH LETTER YADDH +2D3B ; [.16FF.0020.0002.2D3B] # TIFINAGH LETTER YEY +2D3C ; [.1700.0020.0002.2D3C] # TIFINAGH LETTER YAF +2D3D ; [.1701.0020.0002.2D3D] # TIFINAGH LETTER YAK +2D3E ; [.1702.0020.0002.2D3E] # TIFINAGH LETTER TUAREG YAK +2D3F ; [.1703.0020.0002.2D3F] # TIFINAGH LETTER YAKHH +2D40 ; [.1704.0020.0002.2D40] # TIFINAGH LETTER YAH +2D41 ; [.1705.0020.0002.2D41] # TIFINAGH LETTER BERBER ACADEMY YAH +2D42 ; [.1706.0020.0002.2D42] # TIFINAGH LETTER TUAREG YAH +2D43 ; [.1707.0020.0002.2D43] # TIFINAGH LETTER YAHH +2D44 ; [.1708.0020.0002.2D44] # TIFINAGH LETTER YAA +2D45 ; [.1709.0020.0002.2D45] # TIFINAGH LETTER YAKH +2D46 ; [.170A.0020.0002.2D46] # TIFINAGH LETTER TUAREG YAKH +2D47 ; [.170B.0020.0002.2D47] # TIFINAGH LETTER YAQ +2D48 ; [.170C.0020.0002.2D48] # TIFINAGH LETTER TUAREG YAQ +2D49 ; [.170D.0020.0002.2D49] # TIFINAGH LETTER YI +2D4A ; [.170E.0020.0002.2D4A] # TIFINAGH LETTER YAZH +2D4B ; [.170F.0020.0002.2D4B] # TIFINAGH LETTER AHAGGAR YAZH +2D4C ; [.1710.0020.0002.2D4C] # TIFINAGH LETTER TUAREG YAZH +2D4D ; [.1711.0020.0002.2D4D] # TIFINAGH LETTER YAL +2D4E ; [.1712.0020.0002.2D4E] # TIFINAGH LETTER YAM +2D4F ; [.1713.0020.0002.2D4F] # TIFINAGH LETTER YAN +2D50 ; [.1714.0020.0002.2D50] # TIFINAGH LETTER TUAREG YAGN +2D51 ; [.1715.0020.0002.2D51] # TIFINAGH LETTER TUAREG YANG +2D52 ; [.1716.0020.0002.2D52] # TIFINAGH LETTER YAP +2D53 ; [.1717.0020.0002.2D53] # TIFINAGH LETTER YU +2D54 ; [.1718.0020.0002.2D54] # TIFINAGH LETTER YAR +2D55 ; [.1719.0020.0002.2D55] # TIFINAGH LETTER YARR +2D56 ; [.171A.0020.0002.2D56] # TIFINAGH LETTER YAGH +2D57 ; [.171B.0020.0002.2D57] # TIFINAGH LETTER TUAREG YAGH +2D58 ; [.171C.0020.0002.2D58] # TIFINAGH LETTER AYER YAGH +2D59 ; [.171D.0020.0002.2D59] # TIFINAGH LETTER YAS +2D5A ; [.171E.0020.0002.2D5A] # TIFINAGH LETTER YASS +2D5B ; [.171F.0020.0002.2D5B] # TIFINAGH LETTER YASH +2D5C ; [.1720.0020.0002.2D5C] # TIFINAGH LETTER YAT +2D5D ; [.1721.0020.0002.2D5D] # TIFINAGH LETTER YATH +2D5E ; [.1722.0020.0002.2D5E] # TIFINAGH LETTER YACH +2D5F ; [.1723.0020.0002.2D5F] # TIFINAGH LETTER YATT +2D60 ; [.1724.0020.0002.2D60] # TIFINAGH LETTER YAV +2D61 ; [.1725.0020.0002.2D61] # TIFINAGH LETTER YAW +2D62 ; [.1726.0020.0002.2D62] # TIFINAGH LETTER YAY +2D63 ; [.1727.0020.0002.2D63] # TIFINAGH LETTER YAZ +2D64 ; [.1728.0020.0002.2D64] # TIFINAGH LETTER TAWELLEMET YAZ +2D65 ; [.1729.0020.0002.2D65] # TIFINAGH LETTER YAZZ +2D6F ; [.172A.0020.0002.2D6F] # TIFINAGH MODIFIER LETTER LABIALIZATION MARK +1200 ; [.172B.0020.0002.1200] # ETHIOPIC SYLLABLE HA +1201 ; [.172C.0020.0002.1201] # ETHIOPIC SYLLABLE HU +1202 ; [.172D.0020.0002.1202] # ETHIOPIC SYLLABLE HI +1203 ; [.172E.0020.0002.1203] # ETHIOPIC SYLLABLE HAA +1204 ; [.172F.0020.0002.1204] # ETHIOPIC SYLLABLE HEE +1205 ; [.1730.0020.0002.1205] # ETHIOPIC SYLLABLE HE +1206 ; [.1731.0020.0002.1206] # ETHIOPIC SYLLABLE HO +1207 ; [.1732.0020.0002.1207] # ETHIOPIC SYLLABLE HOA +1208 ; [.1733.0020.0002.1208] # ETHIOPIC SYLLABLE LA +1209 ; [.1734.0020.0002.1209] # ETHIOPIC SYLLABLE LU +120A ; [.1735.0020.0002.120A] # ETHIOPIC SYLLABLE LI +120B ; [.1736.0020.0002.120B] # ETHIOPIC SYLLABLE LAA +120C ; [.1737.0020.0002.120C] # ETHIOPIC SYLLABLE LEE +120D ; [.1738.0020.0002.120D] # ETHIOPIC SYLLABLE LE +120E ; [.1739.0020.0002.120E] # ETHIOPIC SYLLABLE LO +120F ; [.173A.0020.0002.120F] # ETHIOPIC SYLLABLE LWA +2D80 ; [.173B.0020.0002.2D80] # ETHIOPIC SYLLABLE LOA +1210 ; [.173C.0020.0002.1210] # ETHIOPIC SYLLABLE HHA +1211 ; [.173D.0020.0002.1211] # ETHIOPIC SYLLABLE HHU +1212 ; [.173E.0020.0002.1212] # ETHIOPIC SYLLABLE HHI +1213 ; [.173F.0020.0002.1213] # ETHIOPIC SYLLABLE HHAA +1214 ; [.1740.0020.0002.1214] # ETHIOPIC SYLLABLE HHEE +1215 ; [.1741.0020.0002.1215] # ETHIOPIC SYLLABLE HHE +1216 ; [.1742.0020.0002.1216] # ETHIOPIC SYLLABLE HHO +1217 ; [.1743.0020.0002.1217] # ETHIOPIC SYLLABLE HHWA +1218 ; [.1744.0020.0002.1218] # ETHIOPIC SYLLABLE MA +1219 ; [.1745.0020.0002.1219] # ETHIOPIC SYLLABLE MU +121A ; [.1746.0020.0002.121A] # ETHIOPIC SYLLABLE MI +121B ; [.1747.0020.0002.121B] # ETHIOPIC SYLLABLE MAA +121C ; [.1748.0020.0002.121C] # ETHIOPIC SYLLABLE MEE +121D ; [.1749.0020.0002.121D] # ETHIOPIC SYLLABLE ME +121E ; [.174A.0020.0002.121E] # ETHIOPIC SYLLABLE MO +121F ; [.174B.0020.0002.121F] # ETHIOPIC SYLLABLE MWA +1380 ; [.174C.0020.0002.1380] # ETHIOPIC SYLLABLE SEBATBEIT MWA +1381 ; [.174D.0020.0002.1381] # ETHIOPIC SYLLABLE MWI +1382 ; [.174E.0020.0002.1382] # ETHIOPIC SYLLABLE MWEE +1383 ; [.174F.0020.0002.1383] # ETHIOPIC SYLLABLE MWE +2D81 ; [.1750.0020.0002.2D81] # ETHIOPIC SYLLABLE MOA +1220 ; [.1751.0020.0002.1220] # ETHIOPIC SYLLABLE SZA +1221 ; [.1752.0020.0002.1221] # ETHIOPIC SYLLABLE SZU +1222 ; [.1753.0020.0002.1222] # ETHIOPIC SYLLABLE SZI +1223 ; [.1754.0020.0002.1223] # ETHIOPIC SYLLABLE SZAA +1224 ; [.1755.0020.0002.1224] # ETHIOPIC SYLLABLE SZEE +1225 ; [.1756.0020.0002.1225] # ETHIOPIC SYLLABLE SZE +1226 ; [.1757.0020.0002.1226] # ETHIOPIC SYLLABLE SZO +1227 ; [.1758.0020.0002.1227] # ETHIOPIC SYLLABLE SZWA +1228 ; [.1759.0020.0002.1228] # ETHIOPIC SYLLABLE RA +1229 ; [.175A.0020.0002.1229] # ETHIOPIC SYLLABLE RU +122A ; [.175B.0020.0002.122A] # ETHIOPIC SYLLABLE RI +122B ; [.175C.0020.0002.122B] # ETHIOPIC SYLLABLE RAA +122C ; [.175D.0020.0002.122C] # ETHIOPIC SYLLABLE REE +122D ; [.175E.0020.0002.122D] # ETHIOPIC SYLLABLE RE +122E ; [.175F.0020.0002.122E] # ETHIOPIC SYLLABLE RO +122F ; [.1760.0020.0002.122F] # ETHIOPIC SYLLABLE RWA +2D82 ; [.1761.0020.0002.2D82] # ETHIOPIC SYLLABLE ROA +1230 ; [.1762.0020.0002.1230] # ETHIOPIC SYLLABLE SA +1231 ; [.1763.0020.0002.1231] # ETHIOPIC SYLLABLE SU +1232 ; [.1764.0020.0002.1232] # ETHIOPIC SYLLABLE SI +1233 ; [.1765.0020.0002.1233] # ETHIOPIC SYLLABLE SAA +1234 ; [.1766.0020.0002.1234] # ETHIOPIC SYLLABLE SEE +1235 ; [.1767.0020.0002.1235] # ETHIOPIC SYLLABLE SE +1236 ; [.1768.0020.0002.1236] # ETHIOPIC SYLLABLE SO +1237 ; [.1769.0020.0002.1237] # ETHIOPIC SYLLABLE SWA +2D83 ; [.176A.0020.0002.2D83] # ETHIOPIC SYLLABLE SOA +1238 ; [.176B.0020.0002.1238] # ETHIOPIC SYLLABLE SHA +1239 ; [.176C.0020.0002.1239] # ETHIOPIC SYLLABLE SHU +123A ; [.176D.0020.0002.123A] # ETHIOPIC SYLLABLE SHI +123B ; [.176E.0020.0002.123B] # ETHIOPIC SYLLABLE SHAA +123C ; [.176F.0020.0002.123C] # ETHIOPIC SYLLABLE SHEE +123D ; [.1770.0020.0002.123D] # ETHIOPIC SYLLABLE SHE +123E ; [.1771.0020.0002.123E] # ETHIOPIC SYLLABLE SHO +123F ; [.1772.0020.0002.123F] # ETHIOPIC SYLLABLE SHWA +2D84 ; [.1773.0020.0002.2D84] # ETHIOPIC SYLLABLE SHOA +1240 ; [.1774.0020.0002.1240] # ETHIOPIC SYLLABLE QA +1241 ; [.1775.0020.0002.1241] # ETHIOPIC SYLLABLE QU +1242 ; [.1776.0020.0002.1242] # ETHIOPIC SYLLABLE QI +1243 ; [.1777.0020.0002.1243] # ETHIOPIC SYLLABLE QAA +1244 ; [.1778.0020.0002.1244] # ETHIOPIC SYLLABLE QEE +1245 ; [.1779.0020.0002.1245] # ETHIOPIC SYLLABLE QE +1246 ; [.177A.0020.0002.1246] # ETHIOPIC SYLLABLE QO +1247 ; [.177B.0020.0002.1247] # ETHIOPIC SYLLABLE QOA +1248 ; [.177C.0020.0002.1248] # ETHIOPIC SYLLABLE QWA +124A ; [.177D.0020.0002.124A] # ETHIOPIC SYLLABLE QWI +124B ; [.177E.0020.0002.124B] # ETHIOPIC SYLLABLE QWAA +124C ; [.177F.0020.0002.124C] # ETHIOPIC SYLLABLE QWEE +124D ; [.1780.0020.0002.124D] # ETHIOPIC SYLLABLE QWE +1250 ; [.1781.0020.0002.1250] # ETHIOPIC SYLLABLE QHA +1251 ; [.1782.0020.0002.1251] # ETHIOPIC SYLLABLE QHU +1252 ; [.1783.0020.0002.1252] # ETHIOPIC SYLLABLE QHI +1253 ; [.1784.0020.0002.1253] # ETHIOPIC SYLLABLE QHAA +1254 ; [.1785.0020.0002.1254] # ETHIOPIC SYLLABLE QHEE +1255 ; [.1786.0020.0002.1255] # ETHIOPIC SYLLABLE QHE +1256 ; [.1787.0020.0002.1256] # ETHIOPIC SYLLABLE QHO +1258 ; [.1788.0020.0002.1258] # ETHIOPIC SYLLABLE QHWA +125A ; [.1789.0020.0002.125A] # ETHIOPIC SYLLABLE QHWI +125B ; [.178A.0020.0002.125B] # ETHIOPIC SYLLABLE QHWAA +125C ; [.178B.0020.0002.125C] # ETHIOPIC SYLLABLE QHWEE +125D ; [.178C.0020.0002.125D] # ETHIOPIC SYLLABLE QHWE +1260 ; [.178D.0020.0002.1260] # ETHIOPIC SYLLABLE BA +1261 ; [.178E.0020.0002.1261] # ETHIOPIC SYLLABLE BU +1262 ; [.178F.0020.0002.1262] # ETHIOPIC SYLLABLE BI +1263 ; [.1790.0020.0002.1263] # ETHIOPIC SYLLABLE BAA +1264 ; [.1791.0020.0002.1264] # ETHIOPIC SYLLABLE BEE +1265 ; [.1792.0020.0002.1265] # ETHIOPIC SYLLABLE BE +1266 ; [.1793.0020.0002.1266] # ETHIOPIC SYLLABLE BO +1267 ; [.1794.0020.0002.1267] # ETHIOPIC SYLLABLE BWA +1384 ; [.1795.0020.0002.1384] # ETHIOPIC SYLLABLE SEBATBEIT BWA +1385 ; [.1796.0020.0002.1385] # ETHIOPIC SYLLABLE BWI +1386 ; [.1797.0020.0002.1386] # ETHIOPIC SYLLABLE BWEE +1387 ; [.1798.0020.0002.1387] # ETHIOPIC SYLLABLE BWE +2D85 ; [.1799.0020.0002.2D85] # ETHIOPIC SYLLABLE BOA +1268 ; [.179A.0020.0002.1268] # ETHIOPIC SYLLABLE VA +1269 ; [.179B.0020.0002.1269] # ETHIOPIC SYLLABLE VU +126A ; [.179C.0020.0002.126A] # ETHIOPIC SYLLABLE VI +126B ; [.179D.0020.0002.126B] # ETHIOPIC SYLLABLE VAA +126C ; [.179E.0020.0002.126C] # ETHIOPIC SYLLABLE VEE +126D ; [.179F.0020.0002.126D] # ETHIOPIC SYLLABLE VE +126E ; [.17A0.0020.0002.126E] # ETHIOPIC SYLLABLE VO +126F ; [.17A1.0020.0002.126F] # ETHIOPIC SYLLABLE VWA +1270 ; [.17A2.0020.0002.1270] # ETHIOPIC SYLLABLE TA +1271 ; [.17A3.0020.0002.1271] # ETHIOPIC SYLLABLE TU +1272 ; [.17A4.0020.0002.1272] # ETHIOPIC SYLLABLE TI +1273 ; [.17A5.0020.0002.1273] # ETHIOPIC SYLLABLE TAA +1274 ; [.17A6.0020.0002.1274] # ETHIOPIC SYLLABLE TEE +1275 ; [.17A7.0020.0002.1275] # ETHIOPIC SYLLABLE TE +1276 ; [.17A8.0020.0002.1276] # ETHIOPIC SYLLABLE TO +1277 ; [.17A9.0020.0002.1277] # ETHIOPIC SYLLABLE TWA +2D86 ; [.17AA.0020.0002.2D86] # ETHIOPIC SYLLABLE TOA +1278 ; [.17AB.0020.0002.1278] # ETHIOPIC SYLLABLE CA +1279 ; [.17AC.0020.0002.1279] # ETHIOPIC SYLLABLE CU +127A ; [.17AD.0020.0002.127A] # ETHIOPIC SYLLABLE CI +127B ; [.17AE.0020.0002.127B] # ETHIOPIC SYLLABLE CAA +127C ; [.17AF.0020.0002.127C] # ETHIOPIC SYLLABLE CEE +127D ; [.17B0.0020.0002.127D] # ETHIOPIC SYLLABLE CE +127E ; [.17B1.0020.0002.127E] # ETHIOPIC SYLLABLE CO +127F ; [.17B2.0020.0002.127F] # ETHIOPIC SYLLABLE CWA +2D87 ; [.17B3.0020.0002.2D87] # ETHIOPIC SYLLABLE COA +1280 ; [.17B4.0020.0002.1280] # ETHIOPIC SYLLABLE XA +1281 ; [.17B5.0020.0002.1281] # ETHIOPIC SYLLABLE XU +1282 ; [.17B6.0020.0002.1282] # ETHIOPIC SYLLABLE XI +1283 ; [.17B7.0020.0002.1283] # ETHIOPIC SYLLABLE XAA +1284 ; [.17B8.0020.0002.1284] # ETHIOPIC SYLLABLE XEE +1285 ; [.17B9.0020.0002.1285] # ETHIOPIC SYLLABLE XE +1286 ; [.17BA.0020.0002.1286] # ETHIOPIC SYLLABLE XO +1287 ; [.17BB.0020.0002.1287] # ETHIOPIC SYLLABLE XOA +1288 ; [.17BC.0020.0002.1288] # ETHIOPIC SYLLABLE XWA +128A ; [.17BD.0020.0002.128A] # ETHIOPIC SYLLABLE XWI +128B ; [.17BE.0020.0002.128B] # ETHIOPIC SYLLABLE XWAA +128C ; [.17BF.0020.0002.128C] # ETHIOPIC SYLLABLE XWEE +128D ; [.17C0.0020.0002.128D] # ETHIOPIC SYLLABLE XWE +1290 ; [.17C1.0020.0002.1290] # ETHIOPIC SYLLABLE NA +1291 ; [.17C2.0020.0002.1291] # ETHIOPIC SYLLABLE NU +1292 ; [.17C3.0020.0002.1292] # ETHIOPIC SYLLABLE NI +1293 ; [.17C4.0020.0002.1293] # ETHIOPIC SYLLABLE NAA +1294 ; [.17C5.0020.0002.1294] # ETHIOPIC SYLLABLE NEE +1295 ; [.17C6.0020.0002.1295] # ETHIOPIC SYLLABLE NE +1296 ; [.17C7.0020.0002.1296] # ETHIOPIC SYLLABLE NO +1297 ; [.17C8.0020.0002.1297] # ETHIOPIC SYLLABLE NWA +2D88 ; [.17C9.0020.0002.2D88] # ETHIOPIC SYLLABLE NOA +1298 ; [.17CA.0020.0002.1298] # ETHIOPIC SYLLABLE NYA +1299 ; [.17CB.0020.0002.1299] # ETHIOPIC SYLLABLE NYU +129A ; [.17CC.0020.0002.129A] # ETHIOPIC SYLLABLE NYI +129B ; [.17CD.0020.0002.129B] # ETHIOPIC SYLLABLE NYAA +129C ; [.17CE.0020.0002.129C] # ETHIOPIC SYLLABLE NYEE +129D ; [.17CF.0020.0002.129D] # ETHIOPIC SYLLABLE NYE +129E ; [.17D0.0020.0002.129E] # ETHIOPIC SYLLABLE NYO +129F ; [.17D1.0020.0002.129F] # ETHIOPIC SYLLABLE NYWA +2D89 ; [.17D2.0020.0002.2D89] # ETHIOPIC SYLLABLE NYOA +12A0 ; [.17D3.0020.0002.12A0] # ETHIOPIC SYLLABLE GLOTTAL A +12A1 ; [.17D4.0020.0002.12A1] # ETHIOPIC SYLLABLE GLOTTAL U +12A2 ; [.17D5.0020.0002.12A2] # ETHIOPIC SYLLABLE GLOTTAL I +12A3 ; [.17D6.0020.0002.12A3] # ETHIOPIC SYLLABLE GLOTTAL AA +12A4 ; [.17D7.0020.0002.12A4] # ETHIOPIC SYLLABLE GLOTTAL EE +12A5 ; [.17D8.0020.0002.12A5] # ETHIOPIC SYLLABLE GLOTTAL E +12A6 ; [.17D9.0020.0002.12A6] # ETHIOPIC SYLLABLE GLOTTAL O +12A7 ; [.17DA.0020.0002.12A7] # ETHIOPIC SYLLABLE GLOTTAL WA +2D8A ; [.17DB.0020.0002.2D8A] # ETHIOPIC SYLLABLE GLOTTAL OA +12A8 ; [.17DC.0020.0002.12A8] # ETHIOPIC SYLLABLE KA +12A9 ; [.17DD.0020.0002.12A9] # ETHIOPIC SYLLABLE KU +12AA ; [.17DE.0020.0002.12AA] # ETHIOPIC SYLLABLE KI +12AB ; [.17DF.0020.0002.12AB] # ETHIOPIC SYLLABLE KAA +12AC ; [.17E0.0020.0002.12AC] # ETHIOPIC SYLLABLE KEE +12AD ; [.17E1.0020.0002.12AD] # ETHIOPIC SYLLABLE KE +12AE ; [.17E2.0020.0002.12AE] # ETHIOPIC SYLLABLE KO +12AF ; [.17E3.0020.0002.12AF] # ETHIOPIC SYLLABLE KOA +12B0 ; [.17E4.0020.0002.12B0] # ETHIOPIC SYLLABLE KWA +12B2 ; [.17E5.0020.0002.12B2] # ETHIOPIC SYLLABLE KWI +12B3 ; [.17E6.0020.0002.12B3] # ETHIOPIC SYLLABLE KWAA +12B4 ; [.17E7.0020.0002.12B4] # ETHIOPIC SYLLABLE KWEE +12B5 ; [.17E8.0020.0002.12B5] # ETHIOPIC SYLLABLE KWE +12B8 ; [.17E9.0020.0002.12B8] # ETHIOPIC SYLLABLE KXA +12B9 ; [.17EA.0020.0002.12B9] # ETHIOPIC SYLLABLE KXU +12BA ; [.17EB.0020.0002.12BA] # ETHIOPIC SYLLABLE KXI +12BB ; [.17EC.0020.0002.12BB] # ETHIOPIC SYLLABLE KXAA +12BC ; [.17ED.0020.0002.12BC] # ETHIOPIC SYLLABLE KXEE +12BD ; [.17EE.0020.0002.12BD] # ETHIOPIC SYLLABLE KXE +12BE ; [.17EF.0020.0002.12BE] # ETHIOPIC SYLLABLE KXO +12C0 ; [.17F0.0020.0002.12C0] # ETHIOPIC SYLLABLE KXWA +12C2 ; [.17F1.0020.0002.12C2] # ETHIOPIC SYLLABLE KXWI +12C3 ; [.17F2.0020.0002.12C3] # ETHIOPIC SYLLABLE KXWAA +12C4 ; [.17F3.0020.0002.12C4] # ETHIOPIC SYLLABLE KXWEE +12C5 ; [.17F4.0020.0002.12C5] # ETHIOPIC SYLLABLE KXWE +12C8 ; [.17F5.0020.0002.12C8] # ETHIOPIC SYLLABLE WA +12C9 ; [.17F6.0020.0002.12C9] # ETHIOPIC SYLLABLE WU +12CA ; [.17F7.0020.0002.12CA] # ETHIOPIC SYLLABLE WI +12CB ; [.17F8.0020.0002.12CB] # ETHIOPIC SYLLABLE WAA +12CC ; [.17F9.0020.0002.12CC] # ETHIOPIC SYLLABLE WEE +12CD ; [.17FA.0020.0002.12CD] # ETHIOPIC SYLLABLE WE +12CE ; [.17FB.0020.0002.12CE] # ETHIOPIC SYLLABLE WO +12CF ; [.17FC.0020.0002.12CF] # ETHIOPIC SYLLABLE WOA +12D0 ; [.17FD.0020.0002.12D0] # ETHIOPIC SYLLABLE PHARYNGEAL A +12D1 ; [.17FE.0020.0002.12D1] # ETHIOPIC SYLLABLE PHARYNGEAL U +12D2 ; [.17FF.0020.0002.12D2] # ETHIOPIC SYLLABLE PHARYNGEAL I +12D3 ; [.1800.0020.0002.12D3] # ETHIOPIC SYLLABLE PHARYNGEAL AA +12D4 ; [.1801.0020.0002.12D4] # ETHIOPIC SYLLABLE PHARYNGEAL EE +12D5 ; [.1802.0020.0002.12D5] # ETHIOPIC SYLLABLE PHARYNGEAL E +12D6 ; [.1803.0020.0002.12D6] # ETHIOPIC SYLLABLE PHARYNGEAL O +12D8 ; [.1804.0020.0002.12D8] # ETHIOPIC SYLLABLE ZA +12D9 ; [.1805.0020.0002.12D9] # ETHIOPIC SYLLABLE ZU +12DA ; [.1806.0020.0002.12DA] # ETHIOPIC SYLLABLE ZI +12DB ; [.1807.0020.0002.12DB] # ETHIOPIC SYLLABLE ZAA +12DC ; [.1808.0020.0002.12DC] # ETHIOPIC SYLLABLE ZEE +12DD ; [.1809.0020.0002.12DD] # ETHIOPIC SYLLABLE ZE +12DE ; [.180A.0020.0002.12DE] # ETHIOPIC SYLLABLE ZO +12DF ; [.180B.0020.0002.12DF] # ETHIOPIC SYLLABLE ZWA +2D8B ; [.180C.0020.0002.2D8B] # ETHIOPIC SYLLABLE ZOA +12E0 ; [.180D.0020.0002.12E0] # ETHIOPIC SYLLABLE ZHA +12E1 ; [.180E.0020.0002.12E1] # ETHIOPIC SYLLABLE ZHU +12E2 ; [.180F.0020.0002.12E2] # ETHIOPIC SYLLABLE ZHI +12E3 ; [.1810.0020.0002.12E3] # ETHIOPIC SYLLABLE ZHAA +12E4 ; [.1811.0020.0002.12E4] # ETHIOPIC SYLLABLE ZHEE +12E5 ; [.1812.0020.0002.12E5] # ETHIOPIC SYLLABLE ZHE +12E6 ; [.1813.0020.0002.12E6] # ETHIOPIC SYLLABLE ZHO +12E7 ; [.1814.0020.0002.12E7] # ETHIOPIC SYLLABLE ZHWA +12E8 ; [.1815.0020.0002.12E8] # ETHIOPIC SYLLABLE YA +12E9 ; [.1816.0020.0002.12E9] # ETHIOPIC SYLLABLE YU +12EA ; [.1817.0020.0002.12EA] # ETHIOPIC SYLLABLE YI +12EB ; [.1818.0020.0002.12EB] # ETHIOPIC SYLLABLE YAA +12EC ; [.1819.0020.0002.12EC] # ETHIOPIC SYLLABLE YEE +12ED ; [.181A.0020.0002.12ED] # ETHIOPIC SYLLABLE YE +12EE ; [.181B.0020.0002.12EE] # ETHIOPIC SYLLABLE YO +12EF ; [.181C.0020.0002.12EF] # ETHIOPIC SYLLABLE YOA +12F0 ; [.181D.0020.0002.12F0] # ETHIOPIC SYLLABLE DA +12F1 ; [.181E.0020.0002.12F1] # ETHIOPIC SYLLABLE DU +12F2 ; [.181F.0020.0002.12F2] # ETHIOPIC SYLLABLE DI +12F3 ; [.1820.0020.0002.12F3] # ETHIOPIC SYLLABLE DAA +12F4 ; [.1821.0020.0002.12F4] # ETHIOPIC SYLLABLE DEE +12F5 ; [.1822.0020.0002.12F5] # ETHIOPIC SYLLABLE DE +12F6 ; [.1823.0020.0002.12F6] # ETHIOPIC SYLLABLE DO +12F7 ; [.1824.0020.0002.12F7] # ETHIOPIC SYLLABLE DWA +2D8C ; [.1825.0020.0002.2D8C] # ETHIOPIC SYLLABLE DOA +12F8 ; [.1826.0020.0002.12F8] # ETHIOPIC SYLLABLE DDA +12F9 ; [.1827.0020.0002.12F9] # ETHIOPIC SYLLABLE DDU +12FA ; [.1828.0020.0002.12FA] # ETHIOPIC SYLLABLE DDI +12FB ; [.1829.0020.0002.12FB] # ETHIOPIC SYLLABLE DDAA +12FC ; [.182A.0020.0002.12FC] # ETHIOPIC SYLLABLE DDEE +12FD ; [.182B.0020.0002.12FD] # ETHIOPIC SYLLABLE DDE +12FE ; [.182C.0020.0002.12FE] # ETHIOPIC SYLLABLE DDO +12FF ; [.182D.0020.0002.12FF] # ETHIOPIC SYLLABLE DDWA +2D8D ; [.182E.0020.0002.2D8D] # ETHIOPIC SYLLABLE DDOA +1300 ; [.182F.0020.0002.1300] # ETHIOPIC SYLLABLE JA +1301 ; [.1830.0020.0002.1301] # ETHIOPIC SYLLABLE JU +1302 ; [.1831.0020.0002.1302] # ETHIOPIC SYLLABLE JI +1303 ; [.1832.0020.0002.1303] # ETHIOPIC SYLLABLE JAA +1304 ; [.1833.0020.0002.1304] # ETHIOPIC SYLLABLE JEE +1305 ; [.1834.0020.0002.1305] # ETHIOPIC SYLLABLE JE +1306 ; [.1835.0020.0002.1306] # ETHIOPIC SYLLABLE JO +1307 ; [.1836.0020.0002.1307] # ETHIOPIC SYLLABLE JWA +2D8E ; [.1837.0020.0002.2D8E] # ETHIOPIC SYLLABLE JOA +1308 ; [.1838.0020.0002.1308] # ETHIOPIC SYLLABLE GA +1309 ; [.1839.0020.0002.1309] # ETHIOPIC SYLLABLE GU +130A ; [.183A.0020.0002.130A] # ETHIOPIC SYLLABLE GI +130B ; [.183B.0020.0002.130B] # ETHIOPIC SYLLABLE GAA +130C ; [.183C.0020.0002.130C] # ETHIOPIC SYLLABLE GEE +130D ; [.183D.0020.0002.130D] # ETHIOPIC SYLLABLE GE +130E ; [.183E.0020.0002.130E] # ETHIOPIC SYLLABLE GO +130F ; [.183F.0020.0002.130F] # ETHIOPIC SYLLABLE GOA +1310 ; [.1840.0020.0002.1310] # ETHIOPIC SYLLABLE GWA +1312 ; [.1841.0020.0002.1312] # ETHIOPIC SYLLABLE GWI +1313 ; [.1842.0020.0002.1313] # ETHIOPIC SYLLABLE GWAA +1314 ; [.1843.0020.0002.1314] # ETHIOPIC SYLLABLE GWEE +1315 ; [.1844.0020.0002.1315] # ETHIOPIC SYLLABLE GWE +1318 ; [.1845.0020.0002.1318] # ETHIOPIC SYLLABLE GGA +1319 ; [.1846.0020.0002.1319] # ETHIOPIC SYLLABLE GGU +131A ; [.1847.0020.0002.131A] # ETHIOPIC SYLLABLE GGI +131B ; [.1848.0020.0002.131B] # ETHIOPIC SYLLABLE GGAA +131C ; [.1849.0020.0002.131C] # ETHIOPIC SYLLABLE GGEE +131D ; [.184A.0020.0002.131D] # ETHIOPIC SYLLABLE GGE +131E ; [.184B.0020.0002.131E] # ETHIOPIC SYLLABLE GGO +131F ; [.184C.0020.0002.131F] # ETHIOPIC SYLLABLE GGWAA +2D93 ; [.184D.0020.0002.2D93] # ETHIOPIC SYLLABLE GGWA +2D94 ; [.184E.0020.0002.2D94] # ETHIOPIC SYLLABLE GGWI +2D95 ; [.184F.0020.0002.2D95] # ETHIOPIC SYLLABLE GGWEE +2D96 ; [.1850.0020.0002.2D96] # ETHIOPIC SYLLABLE GGWE +1320 ; [.1851.0020.0002.1320] # ETHIOPIC SYLLABLE THA +1321 ; [.1852.0020.0002.1321] # ETHIOPIC SYLLABLE THU +1322 ; [.1853.0020.0002.1322] # ETHIOPIC SYLLABLE THI +1323 ; [.1854.0020.0002.1323] # ETHIOPIC SYLLABLE THAA +1324 ; [.1855.0020.0002.1324] # ETHIOPIC SYLLABLE THEE +1325 ; [.1856.0020.0002.1325] # ETHIOPIC SYLLABLE THE +1326 ; [.1857.0020.0002.1326] # ETHIOPIC SYLLABLE THO +1327 ; [.1858.0020.0002.1327] # ETHIOPIC SYLLABLE THWA +2D8F ; [.1859.0020.0002.2D8F] # ETHIOPIC SYLLABLE THOA +1328 ; [.185A.0020.0002.1328] # ETHIOPIC SYLLABLE CHA +1329 ; [.185B.0020.0002.1329] # ETHIOPIC SYLLABLE CHU +132A ; [.185C.0020.0002.132A] # ETHIOPIC SYLLABLE CHI +132B ; [.185D.0020.0002.132B] # ETHIOPIC SYLLABLE CHAA +132C ; [.185E.0020.0002.132C] # ETHIOPIC SYLLABLE CHEE +132D ; [.185F.0020.0002.132D] # ETHIOPIC SYLLABLE CHE +132E ; [.1860.0020.0002.132E] # ETHIOPIC SYLLABLE CHO +132F ; [.1861.0020.0002.132F] # ETHIOPIC SYLLABLE CHWA +2D90 ; [.1862.0020.0002.2D90] # ETHIOPIC SYLLABLE CHOA +1330 ; [.1863.0020.0002.1330] # ETHIOPIC SYLLABLE PHA +1331 ; [.1864.0020.0002.1331] # ETHIOPIC SYLLABLE PHU +1332 ; [.1865.0020.0002.1332] # ETHIOPIC SYLLABLE PHI +1333 ; [.1866.0020.0002.1333] # ETHIOPIC SYLLABLE PHAA +1334 ; [.1867.0020.0002.1334] # ETHIOPIC SYLLABLE PHEE +1335 ; [.1868.0020.0002.1335] # ETHIOPIC SYLLABLE PHE +1336 ; [.1869.0020.0002.1336] # ETHIOPIC SYLLABLE PHO +1337 ; [.186A.0020.0002.1337] # ETHIOPIC SYLLABLE PHWA +2D91 ; [.186B.0020.0002.2D91] # ETHIOPIC SYLLABLE PHOA +1338 ; [.186C.0020.0002.1338] # ETHIOPIC SYLLABLE TSA +1339 ; [.186D.0020.0002.1339] # ETHIOPIC SYLLABLE TSU +133A ; [.186E.0020.0002.133A] # ETHIOPIC SYLLABLE TSI +133B ; [.186F.0020.0002.133B] # ETHIOPIC SYLLABLE TSAA +133C ; [.1870.0020.0002.133C] # ETHIOPIC SYLLABLE TSEE +133D ; [.1871.0020.0002.133D] # ETHIOPIC SYLLABLE TSE +133E ; [.1872.0020.0002.133E] # ETHIOPIC SYLLABLE TSO +133F ; [.1873.0020.0002.133F] # ETHIOPIC SYLLABLE TSWA +1340 ; [.1874.0020.0002.1340] # ETHIOPIC SYLLABLE TZA +1341 ; [.1875.0020.0002.1341] # ETHIOPIC SYLLABLE TZU +1342 ; [.1876.0020.0002.1342] # ETHIOPIC SYLLABLE TZI +1343 ; [.1877.0020.0002.1343] # ETHIOPIC SYLLABLE TZAA +1344 ; [.1878.0020.0002.1344] # ETHIOPIC SYLLABLE TZEE +1345 ; [.1879.0020.0002.1345] # ETHIOPIC SYLLABLE TZE +1346 ; [.187A.0020.0002.1346] # ETHIOPIC SYLLABLE TZO +1347 ; [.187B.0020.0002.1347] # ETHIOPIC SYLLABLE TZOA +1348 ; [.187C.0020.0002.1348] # ETHIOPIC SYLLABLE FA +1349 ; [.187D.0020.0002.1349] # ETHIOPIC SYLLABLE FU +134A ; [.187E.0020.0002.134A] # ETHIOPIC SYLLABLE FI +134B ; [.187F.0020.0002.134B] # ETHIOPIC SYLLABLE FAA +134C ; [.1880.0020.0002.134C] # ETHIOPIC SYLLABLE FEE +134D ; [.1881.0020.0002.134D] # ETHIOPIC SYLLABLE FE +134E ; [.1882.0020.0002.134E] # ETHIOPIC SYLLABLE FO +134F ; [.1883.0020.0002.134F] # ETHIOPIC SYLLABLE FWA +1388 ; [.1884.0020.0002.1388] # ETHIOPIC SYLLABLE SEBATBEIT FWA +1389 ; [.1885.0020.0002.1389] # ETHIOPIC SYLLABLE FWI +138A ; [.1886.0020.0002.138A] # ETHIOPIC SYLLABLE FWEE +138B ; [.1887.0020.0002.138B] # ETHIOPIC SYLLABLE FWE +1350 ; [.1888.0020.0002.1350] # ETHIOPIC SYLLABLE PA +1351 ; [.1889.0020.0002.1351] # ETHIOPIC SYLLABLE PU +1352 ; [.188A.0020.0002.1352] # ETHIOPIC SYLLABLE PI +1353 ; [.188B.0020.0002.1353] # ETHIOPIC SYLLABLE PAA +1354 ; [.188C.0020.0002.1354] # ETHIOPIC SYLLABLE PEE +1355 ; [.188D.0020.0002.1355] # ETHIOPIC SYLLABLE PE +1356 ; [.188E.0020.0002.1356] # ETHIOPIC SYLLABLE PO +1357 ; [.188F.0020.0002.1357] # ETHIOPIC SYLLABLE PWA +138C ; [.1890.0020.0002.138C] # ETHIOPIC SYLLABLE SEBATBEIT PWA +138D ; [.1891.0020.0002.138D] # ETHIOPIC SYLLABLE PWI +138E ; [.1892.0020.0002.138E] # ETHIOPIC SYLLABLE PWEE +138F ; [.1893.0020.0002.138F] # ETHIOPIC SYLLABLE PWE +2D92 ; [.1894.0020.0002.2D92] # ETHIOPIC SYLLABLE POA +1358 ; [.1895.0020.0002.1358] # ETHIOPIC SYLLABLE RYA +1359 ; [.1896.0020.0002.1359] # ETHIOPIC SYLLABLE MYA +135A ; [.1897.0020.0002.135A] # ETHIOPIC SYLLABLE FYA +2DA0 ; [.1898.0020.0002.2DA0] # ETHIOPIC SYLLABLE SSA +2DA1 ; [.1899.0020.0002.2DA1] # ETHIOPIC SYLLABLE SSU +2DA2 ; [.189A.0020.0002.2DA2] # ETHIOPIC SYLLABLE SSI +2DA3 ; [.189B.0020.0002.2DA3] # ETHIOPIC SYLLABLE SSAA +2DA4 ; [.189C.0020.0002.2DA4] # ETHIOPIC SYLLABLE SSEE +2DA5 ; [.189D.0020.0002.2DA5] # ETHIOPIC SYLLABLE SSE +2DA6 ; [.189E.0020.0002.2DA6] # ETHIOPIC SYLLABLE SSO +2DA8 ; [.189F.0020.0002.2DA8] # ETHIOPIC SYLLABLE CCA +2DA9 ; [.18A0.0020.0002.2DA9] # ETHIOPIC SYLLABLE CCU +2DAA ; [.18A1.0020.0002.2DAA] # ETHIOPIC SYLLABLE CCI +2DAB ; [.18A2.0020.0002.2DAB] # ETHIOPIC SYLLABLE CCAA +2DAC ; [.18A3.0020.0002.2DAC] # ETHIOPIC SYLLABLE CCEE +2DAD ; [.18A4.0020.0002.2DAD] # ETHIOPIC SYLLABLE CCE +2DAE ; [.18A5.0020.0002.2DAE] # ETHIOPIC SYLLABLE CCO +2DB0 ; [.18A6.0020.0002.2DB0] # ETHIOPIC SYLLABLE ZZA +2DB1 ; [.18A7.0020.0002.2DB1] # ETHIOPIC SYLLABLE ZZU +2DB2 ; [.18A8.0020.0002.2DB2] # ETHIOPIC SYLLABLE ZZI +2DB3 ; [.18A9.0020.0002.2DB3] # ETHIOPIC SYLLABLE ZZAA +2DB4 ; [.18AA.0020.0002.2DB4] # ETHIOPIC SYLLABLE ZZEE +2DB5 ; [.18AB.0020.0002.2DB5] # ETHIOPIC SYLLABLE ZZE +2DB6 ; [.18AC.0020.0002.2DB6] # ETHIOPIC SYLLABLE ZZO +2DB8 ; [.18AD.0020.0002.2DB8] # ETHIOPIC SYLLABLE CCHA +2DB9 ; [.18AE.0020.0002.2DB9] # ETHIOPIC SYLLABLE CCHU +2DBA ; [.18AF.0020.0002.2DBA] # ETHIOPIC SYLLABLE CCHI +2DBB ; [.18B0.0020.0002.2DBB] # ETHIOPIC SYLLABLE CCHAA +2DBC ; [.18B1.0020.0002.2DBC] # ETHIOPIC SYLLABLE CCHEE +2DBD ; [.18B2.0020.0002.2DBD] # ETHIOPIC SYLLABLE CCHE +2DBE ; [.18B3.0020.0002.2DBE] # ETHIOPIC SYLLABLE CCHO +2DC0 ; [.18B4.0020.0002.2DC0] # ETHIOPIC SYLLABLE QYA +2DC1 ; [.18B5.0020.0002.2DC1] # ETHIOPIC SYLLABLE QYU +2DC2 ; [.18B6.0020.0002.2DC2] # ETHIOPIC SYLLABLE QYI +2DC3 ; [.18B7.0020.0002.2DC3] # ETHIOPIC SYLLABLE QYAA +2DC4 ; [.18B8.0020.0002.2DC4] # ETHIOPIC SYLLABLE QYEE +2DC5 ; [.18B9.0020.0002.2DC5] # ETHIOPIC SYLLABLE QYE +2DC6 ; [.18BA.0020.0002.2DC6] # ETHIOPIC SYLLABLE QYO +2DC8 ; [.18BB.0020.0002.2DC8] # ETHIOPIC SYLLABLE KYA +2DC9 ; [.18BC.0020.0002.2DC9] # ETHIOPIC SYLLABLE KYU +2DCA ; [.18BD.0020.0002.2DCA] # ETHIOPIC SYLLABLE KYI +2DCB ; [.18BE.0020.0002.2DCB] # ETHIOPIC SYLLABLE KYAA +2DCC ; [.18BF.0020.0002.2DCC] # ETHIOPIC SYLLABLE KYEE +2DCD ; [.18C0.0020.0002.2DCD] # ETHIOPIC SYLLABLE KYE +2DCE ; [.18C1.0020.0002.2DCE] # ETHIOPIC SYLLABLE KYO +2DD0 ; [.18C2.0020.0002.2DD0] # ETHIOPIC SYLLABLE XYA +2DD1 ; [.18C3.0020.0002.2DD1] # ETHIOPIC SYLLABLE XYU +2DD2 ; [.18C4.0020.0002.2DD2] # ETHIOPIC SYLLABLE XYI +2DD3 ; [.18C5.0020.0002.2DD3] # ETHIOPIC SYLLABLE XYAA +2DD4 ; [.18C6.0020.0002.2DD4] # ETHIOPIC SYLLABLE XYEE +2DD5 ; [.18C7.0020.0002.2DD5] # ETHIOPIC SYLLABLE XYE +2DD6 ; [.18C8.0020.0002.2DD6] # ETHIOPIC SYLLABLE XYO +2DD8 ; [.18C9.0020.0002.2DD8] # ETHIOPIC SYLLABLE GYA +2DD9 ; [.18CA.0020.0002.2DD9] # ETHIOPIC SYLLABLE GYU +2DDA ; [.18CB.0020.0002.2DDA] # ETHIOPIC SYLLABLE GYI +2DDB ; [.18CC.0020.0002.2DDB] # ETHIOPIC SYLLABLE GYAA +2DDC ; [.18CD.0020.0002.2DDC] # ETHIOPIC SYLLABLE GYEE +2DDD ; [.18CE.0020.0002.2DDD] # ETHIOPIC SYLLABLE GYE +2DDE ; [.18CF.0020.0002.2DDE] # ETHIOPIC SYLLABLE GYO +0950 ; [.18D0.0020.0002.0950] # DEVANAGARI OM +0904 ; [.18D1.0020.0002.0904] # DEVANAGARI LETTER SHORT A +0905 ; [.18D2.0020.0002.0905] # DEVANAGARI LETTER A +0906 ; [.18D3.0020.0002.0906] # DEVANAGARI LETTER AA +0907 ; [.18D4.0020.0002.0907] # DEVANAGARI LETTER I +0908 ; [.18D5.0020.0002.0908] # DEVANAGARI LETTER II +0909 ; [.18D6.0020.0002.0909] # DEVANAGARI LETTER U +090A ; [.18D7.0020.0002.090A] # DEVANAGARI LETTER UU +090B ; [.18D8.0020.0002.090B] # DEVANAGARI LETTER VOCALIC R +0960 ; [.18D9.0020.0002.0960] # DEVANAGARI LETTER VOCALIC RR +090C ; [.18DA.0020.0002.090C] # DEVANAGARI LETTER VOCALIC L +0961 ; [.18DB.0020.0002.0961] # DEVANAGARI LETTER VOCALIC LL +090D ; [.18DC.0020.0002.090D] # DEVANAGARI LETTER CANDRA E +090E ; [.18DD.0020.0002.090E] # DEVANAGARI LETTER SHORT E +090F ; [.18DE.0020.0002.090F] # DEVANAGARI LETTER E +0910 ; [.18DF.0020.0002.0910] # DEVANAGARI LETTER AI +0911 ; [.18E0.0020.0002.0911] # DEVANAGARI LETTER CANDRA O +0912 ; [.18E1.0020.0002.0912] # DEVANAGARI LETTER SHORT O +0913 ; [.18E2.0020.0002.0913] # DEVANAGARI LETTER O +0914 ; [.18E3.0020.0002.0914] # DEVANAGARI LETTER AU +0915 ; [.18E4.0020.0002.0915] # DEVANAGARI LETTER KA +0958 ; [.18E4.0020.0002.0915][.0000.0119.0002.093C] # DEVANAGARI LETTER QA; QQCM +0916 ; [.18E5.0020.0002.0916] # DEVANAGARI LETTER KHA +0959 ; [.18E5.0020.0002.0916][.0000.0119.0002.093C] # DEVANAGARI LETTER KHHA; QQCM +0917 ; [.18E6.0020.0002.0917] # DEVANAGARI LETTER GA +095A ; [.18E6.0020.0002.0917][.0000.0119.0002.093C] # DEVANAGARI LETTER GHHA; QQCM +097B ; [.18E7.0020.0002.097B] # DEVANAGARI LETTER GGA +0918 ; [.18E8.0020.0002.0918] # DEVANAGARI LETTER GHA +0919 ; [.18E9.0020.0002.0919] # DEVANAGARI LETTER NGA +091A ; [.18EA.0020.0002.091A] # DEVANAGARI LETTER CA +091B ; [.18EB.0020.0002.091B] # DEVANAGARI LETTER CHA +091C ; [.18EC.0020.0002.091C] # DEVANAGARI LETTER JA +095B ; [.18EC.0020.0002.091C][.0000.0119.0002.093C] # DEVANAGARI LETTER ZA; QQCM +097C ; [.18ED.0020.0002.097C] # DEVANAGARI LETTER JJA +091D ; [.18EE.0020.0002.091D] # DEVANAGARI LETTER JHA +091E ; [.18EF.0020.0002.091E] # DEVANAGARI LETTER NYA +091F ; [.18F0.0020.0002.091F] # DEVANAGARI LETTER TTA +0920 ; [.18F1.0020.0002.0920] # DEVANAGARI LETTER TTHA +0921 ; [.18F2.0020.0002.0921] # DEVANAGARI LETTER DDA +095C ; [.18F2.0020.0002.0921][.0000.0119.0002.093C] # DEVANAGARI LETTER DDDHA; QQCM +097E ; [.18F3.0020.0002.097E] # DEVANAGARI LETTER DDDA +0922 ; [.18F4.0020.0002.0922] # DEVANAGARI LETTER DDHA +095D ; [.18F4.0020.0002.0922][.0000.0119.0002.093C] # DEVANAGARI LETTER RHA; QQCM +0923 ; [.18F5.0020.0002.0923] # DEVANAGARI LETTER NNA +0924 ; [.18F6.0020.0002.0924] # DEVANAGARI LETTER TA +0925 ; [.18F7.0020.0002.0925] # DEVANAGARI LETTER THA +0926 ; [.18F8.0020.0002.0926] # DEVANAGARI LETTER DA +0927 ; [.18F9.0020.0002.0927] # DEVANAGARI LETTER DHA +0928 ; [.18FA.0020.0002.0928] # DEVANAGARI LETTER NA +0929 ; [.18FA.0020.0002.0928][.0000.0119.0002.093C] # DEVANAGARI LETTER NNNA; QQCM +092A ; [.18FB.0020.0002.092A] # DEVANAGARI LETTER PA +092B ; [.18FC.0020.0002.092B] # DEVANAGARI LETTER PHA +095E ; [.18FC.0020.0002.092B][.0000.0119.0002.093C] # DEVANAGARI LETTER FA; QQCM +092C ; [.18FD.0020.0002.092C] # DEVANAGARI LETTER BA +097F ; [.18FE.0020.0002.097F] # DEVANAGARI LETTER BBA +092D ; [.18FF.0020.0002.092D] # DEVANAGARI LETTER BHA +092E ; [.1900.0020.0002.092E] # DEVANAGARI LETTER MA +092F ; [.1901.0020.0002.092F] # DEVANAGARI LETTER YA +095F ; [.1901.0020.0002.092F][.0000.0119.0002.093C] # DEVANAGARI LETTER YYA; QQCM +0930 ; [.1902.0020.0002.0930] # DEVANAGARI LETTER RA +0931 ; [.1902.0020.0002.0930][.0000.0119.0002.093C] # DEVANAGARI LETTER RRA; QQCM +0932 ; [.1903.0020.0002.0932] # DEVANAGARI LETTER LA +0933 ; [.1904.0020.0002.0933] # DEVANAGARI LETTER LLA +0934 ; [.1904.0020.0002.0933][.0000.0119.0002.093C] # DEVANAGARI LETTER LLLA; QQCM +0935 ; [.1905.0020.0002.0935] # DEVANAGARI LETTER VA +0936 ; [.1906.0020.0002.0936] # DEVANAGARI LETTER SHA +0937 ; [.1907.0020.0002.0937] # DEVANAGARI LETTER SSA +0938 ; [.1908.0020.0002.0938] # DEVANAGARI LETTER SA +0939 ; [.1909.0020.0002.0939] # DEVANAGARI LETTER HA +093D ; [.190A.0020.0002.093D] # DEVANAGARI SIGN AVAGRAHA +097D ; [.190B.0020.0002.097D] # DEVANAGARI LETTER GLOTTAL STOP +093E ; [.190C.0020.0002.093E] # DEVANAGARI VOWEL SIGN AA +093F ; [.190D.0020.0002.093F] # DEVANAGARI VOWEL SIGN I +0940 ; [.190E.0020.0002.0940] # DEVANAGARI VOWEL SIGN II +0941 ; [.190F.0020.0002.0941] # DEVANAGARI VOWEL SIGN U +0942 ; [.1910.0020.0002.0942] # DEVANAGARI VOWEL SIGN UU +0943 ; [.1911.0020.0002.0943] # DEVANAGARI VOWEL SIGN VOCALIC R +0944 ; [.1912.0020.0002.0944] # DEVANAGARI VOWEL SIGN VOCALIC RR +0962 ; [.1913.0020.0002.0962] # DEVANAGARI VOWEL SIGN VOCALIC L +0963 ; [.1914.0020.0002.0963] # DEVANAGARI VOWEL SIGN VOCALIC LL +0945 ; [.1915.0020.0002.0945] # DEVANAGARI VOWEL SIGN CANDRA E +0946 ; [.1916.0020.0002.0946] # DEVANAGARI VOWEL SIGN SHORT E +0947 ; [.1917.0020.0002.0947] # DEVANAGARI VOWEL SIGN E +0948 ; [.1918.0020.0002.0948] # DEVANAGARI VOWEL SIGN AI +0949 ; [.1919.0020.0002.0949] # DEVANAGARI VOWEL SIGN CANDRA O +094A ; [.191A.0020.0002.094A] # DEVANAGARI VOWEL SIGN SHORT O +094B ; [.191B.0020.0002.094B] # DEVANAGARI VOWEL SIGN O +094C ; [.191C.0020.0002.094C] # DEVANAGARI VOWEL SIGN AU +094D ; [.191D.0020.0002.094D] # DEVANAGARI SIGN VIRAMA +0985 ; [.191E.0020.0002.0985] # BENGALI LETTER A +0986 ; [.191F.0020.0002.0986] # BENGALI LETTER AA +0987 ; [.1920.0020.0002.0987] # BENGALI LETTER I +0988 ; [.1921.0020.0002.0988] # BENGALI LETTER II +0989 ; [.1922.0020.0002.0989] # BENGALI LETTER U +098A ; [.1923.0020.0002.098A] # BENGALI LETTER UU +098B ; [.1924.0020.0002.098B] # BENGALI LETTER VOCALIC R +09E0 ; [.1925.0020.0002.09E0] # BENGALI LETTER VOCALIC RR +098C ; [.1926.0020.0002.098C] # BENGALI LETTER VOCALIC L +09E1 ; [.1927.0020.0002.09E1] # BENGALI LETTER VOCALIC LL +098F ; [.1928.0020.0002.098F] # BENGALI LETTER E +0990 ; [.1929.0020.0002.0990] # BENGALI LETTER AI +0993 ; [.192A.0020.0002.0993] # BENGALI LETTER O +0994 ; [.192B.0020.0002.0994] # BENGALI LETTER AU +0995 ; [.192C.0020.0002.0995] # BENGALI LETTER KA +0996 ; [.192D.0020.0002.0996] # BENGALI LETTER KHA +0997 ; [.192E.0020.0002.0997] # BENGALI LETTER GA +0998 ; [.192F.0020.0002.0998] # BENGALI LETTER GHA +0999 ; [.1930.0020.0002.0999] # BENGALI LETTER NGA +099A ; [.1931.0020.0002.099A] # BENGALI LETTER CA +099B ; [.1932.0020.0002.099B] # BENGALI LETTER CHA +099C ; [.1933.0020.0002.099C] # BENGALI LETTER JA +099D ; [.1934.0020.0002.099D] # BENGALI LETTER JHA +099E ; [.1935.0020.0002.099E] # BENGALI LETTER NYA +099F ; [.1936.0020.0002.099F] # BENGALI LETTER TTA +09A0 ; [.1937.0020.0002.09A0] # BENGALI LETTER TTHA +09A1 ; [.1938.0020.0002.09A1] # BENGALI LETTER DDA +09DC ; [.1938.0020.0002.09A1][.0000.0121.0002.09BC] # BENGALI LETTER RRA; QQCM +09A2 ; [.1939.0020.0002.09A2] # BENGALI LETTER DDHA +09DD ; [.1939.0020.0002.09A2][.0000.0121.0002.09BC] # BENGALI LETTER RHA; QQCM +09A3 ; [.193A.0020.0002.09A3] # BENGALI LETTER NNA +09A4 ; [.193B.0020.0002.09A4] # BENGALI LETTER TA +09CE ; [.193B.0020.0004.09CE][.195C.0020.0004.09CE] # BENGALI LETTER KHANDA TA; QQKN +09A5 ; [.193C.0020.0002.09A5] # BENGALI LETTER THA +09A6 ; [.193D.0020.0002.09A6] # BENGALI LETTER DA +09A7 ; [.193E.0020.0002.09A7] # BENGALI LETTER DHA +09A8 ; [.193F.0020.0002.09A8] # BENGALI LETTER NA +09AA ; [.1940.0020.0002.09AA] # BENGALI LETTER PA +09AB ; [.1941.0020.0002.09AB] # BENGALI LETTER PHA +09AC ; [.1942.0020.0002.09AC] # BENGALI LETTER BA +09AD ; [.1943.0020.0002.09AD] # BENGALI LETTER BHA +09AE ; [.1944.0020.0002.09AE] # BENGALI LETTER MA +09AF ; [.1945.0020.0002.09AF] # BENGALI LETTER YA +09DF ; [.1945.0020.0002.09AF][.0000.0121.0002.09BC] # BENGALI LETTER YYA; QQCM +09B0 ; [.1946.0020.0002.09B0] # BENGALI LETTER RA +09F0 ; [.1947.0020.0002.09F0] # BENGALI LETTER RA WITH MIDDLE DIAGONAL +09B2 ; [.1948.0020.0002.09B2] # BENGALI LETTER LA +09F1 ; [.1949.0020.0002.09F1] # BENGALI LETTER RA WITH LOWER DIAGONAL +09B6 ; [.194A.0020.0002.09B6] # BENGALI LETTER SHA +09B7 ; [.194B.0020.0002.09B7] # BENGALI LETTER SSA +09B8 ; [.194C.0020.0002.09B8] # BENGALI LETTER SA +09B9 ; [.194D.0020.0002.09B9] # BENGALI LETTER HA +09BD ; [.194E.0020.0002.09BD] # BENGALI SIGN AVAGRAHA +09BE ; [.194F.0020.0002.09BE] # BENGALI VOWEL SIGN AA +09BF ; [.1950.0020.0002.09BF] # BENGALI VOWEL SIGN I +09C0 ; [.1951.0020.0002.09C0] # BENGALI VOWEL SIGN II +09C1 ; [.1952.0020.0002.09C1] # BENGALI VOWEL SIGN U +09C2 ; [.1953.0020.0002.09C2] # BENGALI VOWEL SIGN UU +09C3 ; [.1954.0020.0002.09C3] # BENGALI VOWEL SIGN VOCALIC R +09C4 ; [.1955.0020.0002.09C4] # BENGALI VOWEL SIGN VOCALIC RR +09E2 ; [.1956.0020.0002.09E2] # BENGALI VOWEL SIGN VOCALIC L +09E3 ; [.1957.0020.0002.09E3] # BENGALI VOWEL SIGN VOCALIC LL +09C7 ; [.1958.0020.0002.09C7] # BENGALI VOWEL SIGN E +09C8 ; [.1959.0020.0002.09C8] # BENGALI VOWEL SIGN AI +09CB ; [.195A.0020.0002.09CB] # BENGALI VOWEL SIGN O +09C7 09BE ; [.195A.0020.0002.09CB] # BENGALI VOWEL SIGN O +09CC ; [.195B.0020.0002.09CC] # BENGALI VOWEL SIGN AU +09C7 09D7 ; [.195B.0020.0002.09CC] # BENGALI VOWEL SIGN AU +09CD ; [.195C.0020.0002.09CD] # BENGALI SIGN VIRAMA +09D7 ; [.195D.0020.0002.09D7] # BENGALI AU LENGTH MARK +0A74 ; [.195E.0020.0002.0A74] # GURMUKHI EK ONKAR +0A73 ; [.195F.0020.0002.0A73] # GURMUKHI URA +0A09 ; [.1960.0020.0002.0A09] # GURMUKHI LETTER U +0A0A ; [.1961.0020.0002.0A0A] # GURMUKHI LETTER UU +0A13 ; [.1962.0020.0002.0A13] # GURMUKHI LETTER OO +0A05 ; [.1963.0020.0002.0A05] # GURMUKHI LETTER A +0A06 ; [.1964.0020.0002.0A06] # GURMUKHI LETTER AA +0A10 ; [.1965.0020.0002.0A10] # GURMUKHI LETTER AI +0A14 ; [.1966.0020.0002.0A14] # GURMUKHI LETTER AU +0A72 ; [.1967.0020.0002.0A72] # GURMUKHI IRI +0A07 ; [.1968.0020.0002.0A07] # GURMUKHI LETTER I +0A08 ; [.1969.0020.0002.0A08] # GURMUKHI LETTER II +0A0F ; [.196A.0020.0002.0A0F] # GURMUKHI LETTER EE +0A38 ; [.196B.0020.0002.0A38] # GURMUKHI LETTER SA +0A36 ; [.196B.0020.0002.0A38][.0000.0125.0002.0A3C] # GURMUKHI LETTER SHA; QQCM +0A39 ; [.196C.0020.0002.0A39] # GURMUKHI LETTER HA +0A15 ; [.196D.0020.0002.0A15] # GURMUKHI LETTER KA +0A16 ; [.196E.0020.0002.0A16] # GURMUKHI LETTER KHA +0A59 ; [.196E.0020.0002.0A16][.0000.0125.0002.0A3C] # GURMUKHI LETTER KHHA; QQCM +0A17 ; [.196F.0020.0002.0A17] # GURMUKHI LETTER GA +0A5A ; [.196F.0020.0002.0A17][.0000.0125.0002.0A3C] # GURMUKHI LETTER GHHA; QQCM +0A18 ; [.1970.0020.0002.0A18] # GURMUKHI LETTER GHA +0A19 ; [.1971.0020.0002.0A19] # GURMUKHI LETTER NGA +0A1A ; [.1972.0020.0002.0A1A] # GURMUKHI LETTER CA +0A1B ; [.1973.0020.0002.0A1B] # GURMUKHI LETTER CHA +0A1C ; [.1974.0020.0002.0A1C] # GURMUKHI LETTER JA +0A5B ; [.1974.0020.0002.0A1C][.0000.0125.0002.0A3C] # GURMUKHI LETTER ZA; QQCM +0A1D ; [.1975.0020.0002.0A1D] # GURMUKHI LETTER JHA +0A1E ; [.1976.0020.0002.0A1E] # GURMUKHI LETTER NYA +0A1F ; [.1977.0020.0002.0A1F] # GURMUKHI LETTER TTA +0A20 ; [.1978.0020.0002.0A20] # GURMUKHI LETTER TTHA +0A21 ; [.1979.0020.0002.0A21] # GURMUKHI LETTER DDA +0A22 ; [.197A.0020.0002.0A22] # GURMUKHI LETTER DDHA +0A23 ; [.197B.0020.0002.0A23] # GURMUKHI LETTER NNA +0A24 ; [.197C.0020.0002.0A24] # GURMUKHI LETTER TA +0A25 ; [.197D.0020.0002.0A25] # GURMUKHI LETTER THA +0A26 ; [.197E.0020.0002.0A26] # GURMUKHI LETTER DA +0A27 ; [.197F.0020.0002.0A27] # GURMUKHI LETTER DHA +0A28 ; [.1980.0020.0002.0A28] # GURMUKHI LETTER NA +0A2A ; [.1981.0020.0002.0A2A] # GURMUKHI LETTER PA +0A2B ; [.1982.0020.0002.0A2B] # GURMUKHI LETTER PHA +0A5E ; [.1982.0020.0002.0A2B][.0000.0125.0002.0A3C] # GURMUKHI LETTER FA; QQCM +0A2C ; [.1983.0020.0002.0A2C] # GURMUKHI LETTER BA +0A2D ; [.1984.0020.0002.0A2D] # GURMUKHI LETTER BHA +0A2E ; [.1985.0020.0002.0A2E] # GURMUKHI LETTER MA +0A2F ; [.1986.0020.0002.0A2F] # GURMUKHI LETTER YA +0A30 ; [.1987.0020.0002.0A30] # GURMUKHI LETTER RA +0A32 ; [.1988.0020.0002.0A32] # GURMUKHI LETTER LA +0A33 ; [.1988.0020.0002.0A32][.0000.0125.0002.0A3C] # GURMUKHI LETTER LLA; QQCM +0A35 ; [.1989.0020.0002.0A35] # GURMUKHI LETTER VA +0A5C ; [.198A.0020.0002.0A5C] # GURMUKHI LETTER RRA +0A3E ; [.198B.0020.0002.0A3E] # GURMUKHI VOWEL SIGN AA +0A3F ; [.198C.0020.0002.0A3F] # GURMUKHI VOWEL SIGN I +0A40 ; [.198D.0020.0002.0A40] # GURMUKHI VOWEL SIGN II +0A41 ; [.198E.0020.0002.0A41] # GURMUKHI VOWEL SIGN U +0A42 ; [.198F.0020.0002.0A42] # GURMUKHI VOWEL SIGN UU +0A47 ; [.1990.0020.0002.0A47] # GURMUKHI VOWEL SIGN EE +0A48 ; [.1991.0020.0002.0A48] # GURMUKHI VOWEL SIGN AI +0A4B ; [.1992.0020.0002.0A4B] # GURMUKHI VOWEL SIGN OO +0A4C ; [.1993.0020.0002.0A4C] # GURMUKHI VOWEL SIGN AU +0A4D ; [.1994.0020.0002.0A4D] # GURMUKHI SIGN VIRAMA +0AD0 ; [.1995.0020.0002.0AD0] # GUJARATI OM +0A85 ; [.1996.0020.0002.0A85] # GUJARATI LETTER A +0A86 ; [.1997.0020.0002.0A86] # GUJARATI LETTER AA +0A87 ; [.1998.0020.0002.0A87] # GUJARATI LETTER I +0A88 ; [.1999.0020.0002.0A88] # GUJARATI LETTER II +0A89 ; [.199A.0020.0002.0A89] # GUJARATI LETTER U +0A8A ; [.199B.0020.0002.0A8A] # GUJARATI LETTER UU +0A8B ; [.199C.0020.0002.0A8B] # GUJARATI LETTER VOCALIC R +0AE0 ; [.199D.0020.0002.0AE0] # GUJARATI LETTER VOCALIC RR +0A8C ; [.199E.0020.0002.0A8C] # GUJARATI LETTER VOCALIC L +0AE1 ; [.199F.0020.0002.0AE1] # GUJARATI LETTER VOCALIC LL +0A8D ; [.19A0.0020.0002.0A8D] # GUJARATI VOWEL CANDRA E +0A8F ; [.19A1.0020.0002.0A8F] # GUJARATI LETTER E +0A90 ; [.19A2.0020.0002.0A90] # GUJARATI LETTER AI +0A91 ; [.19A3.0020.0002.0A91] # GUJARATI VOWEL CANDRA O +0A93 ; [.19A4.0020.0002.0A93] # GUJARATI LETTER O +0A94 ; [.19A5.0020.0002.0A94] # GUJARATI LETTER AU +0A95 ; [.19A6.0020.0002.0A95] # GUJARATI LETTER KA +0A96 ; [.19A7.0020.0002.0A96] # GUJARATI LETTER KHA +0A97 ; [.19A8.0020.0002.0A97] # GUJARATI LETTER GA +0A98 ; [.19A9.0020.0002.0A98] # GUJARATI LETTER GHA +0A99 ; [.19AA.0020.0002.0A99] # GUJARATI LETTER NGA +0A9A ; [.19AB.0020.0002.0A9A] # GUJARATI LETTER CA +0A9B ; [.19AC.0020.0002.0A9B] # GUJARATI LETTER CHA +0A9C ; [.19AD.0020.0002.0A9C] # GUJARATI LETTER JA +0A9D ; [.19AE.0020.0002.0A9D] # GUJARATI LETTER JHA +0A9E ; [.19AF.0020.0002.0A9E] # GUJARATI LETTER NYA +0A9F ; [.19B0.0020.0002.0A9F] # GUJARATI LETTER TTA +0AA0 ; [.19B1.0020.0002.0AA0] # GUJARATI LETTER TTHA +0AA1 ; [.19B2.0020.0002.0AA1] # GUJARATI LETTER DDA +0AA2 ; [.19B3.0020.0002.0AA2] # GUJARATI LETTER DDHA +0AA3 ; [.19B4.0020.0002.0AA3] # GUJARATI LETTER NNA +0AA4 ; [.19B5.0020.0002.0AA4] # GUJARATI LETTER TA +0AA5 ; [.19B6.0020.0002.0AA5] # GUJARATI LETTER THA +0AA6 ; [.19B7.0020.0002.0AA6] # GUJARATI LETTER DA +0AA7 ; [.19B8.0020.0002.0AA7] # GUJARATI LETTER DHA +0AA8 ; [.19B9.0020.0002.0AA8] # GUJARATI LETTER NA +0AAA ; [.19BA.0020.0002.0AAA] # GUJARATI LETTER PA +0AAB ; [.19BB.0020.0002.0AAB] # GUJARATI LETTER PHA +0AAC ; [.19BC.0020.0002.0AAC] # GUJARATI LETTER BA +0AAD ; [.19BD.0020.0002.0AAD] # GUJARATI LETTER BHA +0AAE ; [.19BE.0020.0002.0AAE] # GUJARATI LETTER MA +0AAF ; [.19BF.0020.0002.0AAF] # GUJARATI LETTER YA +0AB0 ; [.19C0.0020.0002.0AB0] # GUJARATI LETTER RA +0AB2 ; [.19C1.0020.0002.0AB2] # GUJARATI LETTER LA +0AB3 ; [.19C2.0020.0002.0AB3] # GUJARATI LETTER LLA +0AB5 ; [.19C3.0020.0002.0AB5] # GUJARATI LETTER VA +0AB6 ; [.19C4.0020.0002.0AB6] # GUJARATI LETTER SHA +0AB7 ; [.19C5.0020.0002.0AB7] # GUJARATI LETTER SSA +0AB8 ; [.19C6.0020.0002.0AB8] # GUJARATI LETTER SA +0AB9 ; [.19C7.0020.0002.0AB9] # GUJARATI LETTER HA +0ABD ; [.19C8.0020.0002.0ABD] # GUJARATI SIGN AVAGRAHA +0ABE ; [.19C9.0020.0002.0ABE] # GUJARATI VOWEL SIGN AA +0ABF ; [.19CA.0020.0002.0ABF] # GUJARATI VOWEL SIGN I +0AC0 ; [.19CB.0020.0002.0AC0] # GUJARATI VOWEL SIGN II +0AC1 ; [.19CC.0020.0002.0AC1] # GUJARATI VOWEL SIGN U +0AC2 ; [.19CD.0020.0002.0AC2] # GUJARATI VOWEL SIGN UU +0AC3 ; [.19CE.0020.0002.0AC3] # GUJARATI VOWEL SIGN VOCALIC R +0AC4 ; [.19CF.0020.0002.0AC4] # GUJARATI VOWEL SIGN VOCALIC RR +0AE2 ; [.19D0.0020.0002.0AE2] # GUJARATI VOWEL SIGN VOCALIC L +0AE3 ; [.19D1.0020.0002.0AE3] # GUJARATI VOWEL SIGN VOCALIC LL +0AC5 ; [.19D2.0020.0002.0AC5] # GUJARATI VOWEL SIGN CANDRA E +0AC7 ; [.19D3.0020.0002.0AC7] # GUJARATI VOWEL SIGN E +0AC8 ; [.19D4.0020.0002.0AC8] # GUJARATI VOWEL SIGN AI +0AC9 ; [.19D5.0020.0002.0AC9] # GUJARATI VOWEL SIGN CANDRA O +0ACB ; [.19D6.0020.0002.0ACB] # GUJARATI VOWEL SIGN O +0ACC ; [.19D7.0020.0002.0ACC] # GUJARATI VOWEL SIGN AU +0ACD ; [.19D8.0020.0002.0ACD] # GUJARATI SIGN VIRAMA +0B05 ; [.19D9.0020.0002.0B05] # ORIYA LETTER A +0B06 ; [.19DA.0020.0002.0B06] # ORIYA LETTER AA +0B07 ; [.19DB.0020.0002.0B07] # ORIYA LETTER I +0B08 ; [.19DC.0020.0002.0B08] # ORIYA LETTER II +0B09 ; [.19DD.0020.0002.0B09] # ORIYA LETTER U +0B0A ; [.19DE.0020.0002.0B0A] # ORIYA LETTER UU +0B0B ; [.19DF.0020.0002.0B0B] # ORIYA LETTER VOCALIC R +0B60 ; [.19E0.0020.0002.0B60] # ORIYA LETTER VOCALIC RR +0B0C ; [.19E1.0020.0002.0B0C] # ORIYA LETTER VOCALIC L +0B61 ; [.19E2.0020.0002.0B61] # ORIYA LETTER VOCALIC LL +0B0F ; [.19E3.0020.0002.0B0F] # ORIYA LETTER E +0B10 ; [.19E4.0020.0002.0B10] # ORIYA LETTER AI +0B13 ; [.19E5.0020.0002.0B13] # ORIYA LETTER O +0B14 ; [.19E6.0020.0002.0B14] # ORIYA LETTER AU +0B15 ; [.19E7.0020.0002.0B15] # ORIYA LETTER KA +0B16 ; [.19E8.0020.0002.0B16] # ORIYA LETTER KHA +0B17 ; [.19E9.0020.0002.0B17] # ORIYA LETTER GA +0B18 ; [.19EA.0020.0002.0B18] # ORIYA LETTER GHA +0B19 ; [.19EB.0020.0002.0B19] # ORIYA LETTER NGA +0B1A ; [.19EC.0020.0002.0B1A] # ORIYA LETTER CA +0B1B ; [.19ED.0020.0002.0B1B] # ORIYA LETTER CHA +0B1C ; [.19EE.0020.0002.0B1C] # ORIYA LETTER JA +0B1D ; [.19EF.0020.0002.0B1D] # ORIYA LETTER JHA +0B1E ; [.19F0.0020.0002.0B1E] # ORIYA LETTER NYA +0B1F ; [.19F1.0020.0002.0B1F] # ORIYA LETTER TTA +0B20 ; [.19F2.0020.0002.0B20] # ORIYA LETTER TTHA +0B21 ; [.19F3.0020.0002.0B21] # ORIYA LETTER DDA +0B5C ; [.19F3.0020.0002.0B21][.0000.012F.0002.0B3C] # ORIYA LETTER RRA; QQCM +0B22 ; [.19F4.0020.0002.0B22] # ORIYA LETTER DDHA +0B5D ; [.19F4.0020.0002.0B22][.0000.012F.0002.0B3C] # ORIYA LETTER RHA; QQCM +0B23 ; [.19F5.0020.0002.0B23] # ORIYA LETTER NNA +0B24 ; [.19F6.0020.0002.0B24] # ORIYA LETTER TA +0B25 ; [.19F7.0020.0002.0B25] # ORIYA LETTER THA +0B26 ; [.19F8.0020.0002.0B26] # ORIYA LETTER DA +0B27 ; [.19F9.0020.0002.0B27] # ORIYA LETTER DHA +0B28 ; [.19FA.0020.0002.0B28] # ORIYA LETTER NA +0B2A ; [.19FB.0020.0002.0B2A] # ORIYA LETTER PA +0B2B ; [.19FC.0020.0002.0B2B] # ORIYA LETTER PHA +0B2C ; [.19FD.0020.0002.0B2C] # ORIYA LETTER BA +0B2D ; [.19FE.0020.0002.0B2D] # ORIYA LETTER BHA +0B2E ; [.19FF.0020.0002.0B2E] # ORIYA LETTER MA +0B2F ; [.1A00.0020.0002.0B2F] # ORIYA LETTER YA +0B5F ; [.1A01.0020.0002.0B5F] # ORIYA LETTER YYA +0B30 ; [.1A02.0020.0002.0B30] # ORIYA LETTER RA +0B32 ; [.1A03.0020.0002.0B32] # ORIYA LETTER LA +0B33 ; [.1A04.0020.0002.0B33] # ORIYA LETTER LLA +0B35 ; [.1A05.0020.0002.0B35] # ORIYA LETTER VA +0B71 ; [.1A06.0020.0002.0B71] # ORIYA LETTER WA +0B36 ; [.1A07.0020.0002.0B36] # ORIYA LETTER SHA +0B37 ; [.1A08.0020.0002.0B37] # ORIYA LETTER SSA +0B38 ; [.1A09.0020.0002.0B38] # ORIYA LETTER SA +0B39 ; [.1A0A.0020.0002.0B39] # ORIYA LETTER HA +0B3D ; [.1A0B.0020.0002.0B3D] # ORIYA SIGN AVAGRAHA +0B3E ; [.1A0C.0020.0002.0B3E] # ORIYA VOWEL SIGN AA +0B3F ; [.1A0D.0020.0002.0B3F] # ORIYA VOWEL SIGN I +0B40 ; [.1A0E.0020.0002.0B40] # ORIYA VOWEL SIGN II +0B41 ; [.1A0F.0020.0002.0B41] # ORIYA VOWEL SIGN U +0B42 ; [.1A10.0020.0002.0B42] # ORIYA VOWEL SIGN UU +0B43 ; [.1A11.0020.0002.0B43] # ORIYA VOWEL SIGN VOCALIC R +0B47 ; [.1A12.0020.0002.0B47] # ORIYA VOWEL SIGN E +0B48 ; [.1A13.0020.0002.0B48] # ORIYA VOWEL SIGN AI +0B47 0B56 ; [.1A13.0020.0002.0B48] # ORIYA VOWEL SIGN AI +0B4B ; [.1A14.0020.0002.0B4B] # ORIYA VOWEL SIGN O +0B47 0B3E ; [.1A14.0020.0002.0B4B] # ORIYA VOWEL SIGN O +0B4C ; [.1A15.0020.0002.0B4C] # ORIYA VOWEL SIGN AU +0B47 0B57 ; [.1A15.0020.0002.0B4C] # ORIYA VOWEL SIGN AU +0B4D ; [.1A16.0020.0002.0B4D] # ORIYA SIGN VIRAMA +0B56 ; [.1A17.0020.0002.0B56] # ORIYA AI LENGTH MARK +0B57 ; [.1A18.0020.0002.0B57] # ORIYA AU LENGTH MARK +0B83 ; [.1A19.0020.0002.0B83] # TAMIL SIGN VISARGA +0B85 ; [.1A1A.0020.0002.0B85] # TAMIL LETTER A +0B86 ; [.1A1B.0020.0002.0B86] # TAMIL LETTER AA +0B87 ; [.1A1C.0020.0002.0B87] # TAMIL LETTER I +0B88 ; [.1A1D.0020.0002.0B88] # TAMIL LETTER II +0B89 ; [.1A1E.0020.0002.0B89] # TAMIL LETTER U +0B8A ; [.1A1F.0020.0002.0B8A] # TAMIL LETTER UU +0B8E ; [.1A20.0020.0002.0B8E] # TAMIL LETTER E +0B8F ; [.1A21.0020.0002.0B8F] # TAMIL LETTER EE +0B90 ; [.1A22.0020.0002.0B90] # TAMIL LETTER AI +0B92 ; [.1A23.0020.0002.0B92] # TAMIL LETTER O +0B93 ; [.1A24.0020.0002.0B93] # TAMIL LETTER OO +0B94 ; [.1A25.0020.0002.0B94] # TAMIL LETTER AU +0B92 0BD7 ; [.1A25.0020.0002.0B94] # TAMIL LETTER AU +0B95 ; [.1A26.0020.0002.0B95] # TAMIL LETTER KA +0B99 ; [.1A27.0020.0002.0B99] # TAMIL LETTER NGA +0B9A ; [.1A28.0020.0002.0B9A] # TAMIL LETTER CA +0B9C ; [.1A29.0020.0002.0B9C] # TAMIL LETTER JA +0B9E ; [.1A2A.0020.0002.0B9E] # TAMIL LETTER NYA +0B9F ; [.1A2B.0020.0002.0B9F] # TAMIL LETTER TTA +0BA3 ; [.1A2C.0020.0002.0BA3] # TAMIL LETTER NNA +0BA4 ; [.1A2D.0020.0002.0BA4] # TAMIL LETTER TA +0BA8 ; [.1A2E.0020.0002.0BA8] # TAMIL LETTER NA +0BA9 ; [.1A2F.0020.0002.0BA9] # TAMIL LETTER NNNA +0BAA ; [.1A30.0020.0002.0BAA] # TAMIL LETTER PA +0BAE ; [.1A31.0020.0002.0BAE] # TAMIL LETTER MA +0BAF ; [.1A32.0020.0002.0BAF] # TAMIL LETTER YA +0BB0 ; [.1A33.0020.0002.0BB0] # TAMIL LETTER RA +0BB1 ; [.1A34.0020.0002.0BB1] # TAMIL LETTER RRA +0BB2 ; [.1A35.0020.0002.0BB2] # TAMIL LETTER LA +0BB3 ; [.1A36.0020.0002.0BB3] # TAMIL LETTER LLA +0BB4 ; [.1A37.0020.0002.0BB4] # TAMIL LETTER LLLA +0BB5 ; [.1A38.0020.0002.0BB5] # TAMIL LETTER VA +0BB6 ; [.1A39.0020.0002.0BB6] # TAMIL LETTER SHA +0BB7 ; [.1A3A.0020.0002.0BB7] # TAMIL LETTER SSA +0BB8 ; [.1A3B.0020.0002.0BB8] # TAMIL LETTER SA +0BB9 ; [.1A3C.0020.0002.0BB9] # TAMIL LETTER HA +0BBE ; [.1A3D.0020.0002.0BBE] # TAMIL VOWEL SIGN AA +0BBF ; [.1A3E.0020.0002.0BBF] # TAMIL VOWEL SIGN I +0BC0 ; [.1A3F.0020.0002.0BC0] # TAMIL VOWEL SIGN II +0BC1 ; [.1A40.0020.0002.0BC1] # TAMIL VOWEL SIGN U +0BC2 ; [.1A41.0020.0002.0BC2] # TAMIL VOWEL SIGN UU +0BC6 ; [.1A42.0020.0002.0BC6] # TAMIL VOWEL SIGN E +0BC7 ; [.1A43.0020.0002.0BC7] # TAMIL VOWEL SIGN EE +0BC8 ; [.1A44.0020.0002.0BC8] # TAMIL VOWEL SIGN AI +0BCA ; [.1A45.0020.0002.0BCA] # TAMIL VOWEL SIGN O +0BC6 0BBE ; [.1A45.0020.0002.0BCA] # TAMIL VOWEL SIGN O +0BCB ; [.1A46.0020.0002.0BCB] # TAMIL VOWEL SIGN OO +0BC7 0BBE ; [.1A46.0020.0002.0BCB] # TAMIL VOWEL SIGN OO +0BCC ; [.1A47.0020.0002.0BCC] # TAMIL VOWEL SIGN AU +0BC6 0BD7 ; [.1A47.0020.0002.0BCC] # TAMIL VOWEL SIGN AU +0BCD ; [.1A48.0020.0002.0BCD] # TAMIL SIGN VIRAMA +0BD7 ; [.1A49.0020.0002.0BD7] # TAMIL AU LENGTH MARK +0C05 ; [.1A4A.0020.0002.0C05] # TELUGU LETTER A +0C06 ; [.1A4B.0020.0002.0C06] # TELUGU LETTER AA +0C07 ; [.1A4C.0020.0002.0C07] # TELUGU LETTER I +0C08 ; [.1A4D.0020.0002.0C08] # TELUGU LETTER II +0C09 ; [.1A4E.0020.0002.0C09] # TELUGU LETTER U +0C0A ; [.1A4F.0020.0002.0C0A] # TELUGU LETTER UU +0C0B ; [.1A50.0020.0002.0C0B] # TELUGU LETTER VOCALIC R +0C60 ; [.1A51.0020.0002.0C60] # TELUGU LETTER VOCALIC RR +0C0C ; [.1A52.0020.0002.0C0C] # TELUGU LETTER VOCALIC L +0C61 ; [.1A53.0020.0002.0C61] # TELUGU LETTER VOCALIC LL +0C0E ; [.1A54.0020.0002.0C0E] # TELUGU LETTER E +0C0F ; [.1A55.0020.0002.0C0F] # TELUGU LETTER EE +0C10 ; [.1A56.0020.0002.0C10] # TELUGU LETTER AI +0C12 ; [.1A57.0020.0002.0C12] # TELUGU LETTER O +0C13 ; [.1A58.0020.0002.0C13] # TELUGU LETTER OO +0C14 ; [.1A59.0020.0002.0C14] # TELUGU LETTER AU +0C15 ; [.1A5A.0020.0002.0C15] # TELUGU LETTER KA +0C16 ; [.1A5B.0020.0002.0C16] # TELUGU LETTER KHA +0C17 ; [.1A5C.0020.0002.0C17] # TELUGU LETTER GA +0C18 ; [.1A5D.0020.0002.0C18] # TELUGU LETTER GHA +0C19 ; [.1A5E.0020.0002.0C19] # TELUGU LETTER NGA +0C1A ; [.1A5F.0020.0002.0C1A] # TELUGU LETTER CA +0C1B ; [.1A60.0020.0002.0C1B] # TELUGU LETTER CHA +0C1C ; [.1A61.0020.0002.0C1C] # TELUGU LETTER JA +0C1D ; [.1A62.0020.0002.0C1D] # TELUGU LETTER JHA +0C1E ; [.1A63.0020.0002.0C1E] # TELUGU LETTER NYA +0C1F ; [.1A64.0020.0002.0C1F] # TELUGU LETTER TTA +0C20 ; [.1A65.0020.0002.0C20] # TELUGU LETTER TTHA +0C21 ; [.1A66.0020.0002.0C21] # TELUGU LETTER DDA +0C22 ; [.1A67.0020.0002.0C22] # TELUGU LETTER DDHA +0C23 ; [.1A68.0020.0002.0C23] # TELUGU LETTER NNA +0C24 ; [.1A69.0020.0002.0C24] # TELUGU LETTER TA +0C25 ; [.1A6A.0020.0002.0C25] # TELUGU LETTER THA +0C26 ; [.1A6B.0020.0002.0C26] # TELUGU LETTER DA +0C27 ; [.1A6C.0020.0002.0C27] # TELUGU LETTER DHA +0C28 ; [.1A6D.0020.0002.0C28] # TELUGU LETTER NA +0C2A ; [.1A6E.0020.0002.0C2A] # TELUGU LETTER PA +0C2B ; [.1A6F.0020.0002.0C2B] # TELUGU LETTER PHA +0C2C ; [.1A70.0020.0002.0C2C] # TELUGU LETTER BA +0C2D ; [.1A71.0020.0002.0C2D] # TELUGU LETTER BHA +0C2E ; [.1A72.0020.0002.0C2E] # TELUGU LETTER MA +0C2F ; [.1A73.0020.0002.0C2F] # TELUGU LETTER YA +0C30 ; [.1A74.0020.0002.0C30] # TELUGU LETTER RA +0C31 ; [.1A75.0020.0002.0C31] # TELUGU LETTER RRA +0C32 ; [.1A76.0020.0002.0C32] # TELUGU LETTER LA +0C33 ; [.1A77.0020.0002.0C33] # TELUGU LETTER LLA +0C35 ; [.1A78.0020.0002.0C35] # TELUGU LETTER VA +0C36 ; [.1A79.0020.0002.0C36] # TELUGU LETTER SHA +0C37 ; [.1A7A.0020.0002.0C37] # TELUGU LETTER SSA +0C38 ; [.1A7B.0020.0002.0C38] # TELUGU LETTER SA +0C39 ; [.1A7C.0020.0002.0C39] # TELUGU LETTER HA +0C3E ; [.1A7D.0020.0002.0C3E] # TELUGU VOWEL SIGN AA +0C3F ; [.1A7E.0020.0002.0C3F] # TELUGU VOWEL SIGN I +0C40 ; [.1A7F.0020.0002.0C40] # TELUGU VOWEL SIGN II +0C41 ; [.1A80.0020.0002.0C41] # TELUGU VOWEL SIGN U +0C42 ; [.1A81.0020.0002.0C42] # TELUGU VOWEL SIGN UU +0C43 ; [.1A82.0020.0002.0C43] # TELUGU VOWEL SIGN VOCALIC R +0C44 ; [.1A83.0020.0002.0C44] # TELUGU VOWEL SIGN VOCALIC RR +0C46 ; [.1A84.0020.0002.0C46] # TELUGU VOWEL SIGN E +0C47 ; [.1A85.0020.0002.0C47] # TELUGU VOWEL SIGN EE +0C48 ; [.1A86.0020.0002.0C48] # TELUGU VOWEL SIGN AI +0C46 0C56 ; [.1A86.0020.0002.0C48] # TELUGU VOWEL SIGN AI +0C4A ; [.1A87.0020.0002.0C4A] # TELUGU VOWEL SIGN O +0C4B ; [.1A88.0020.0002.0C4B] # TELUGU VOWEL SIGN OO +0C4C ; [.1A89.0020.0002.0C4C] # TELUGU VOWEL SIGN AU +0C4D ; [.1A8A.0020.0002.0C4D] # TELUGU SIGN VIRAMA +0C55 ; [.1A8B.0020.0002.0C55] # TELUGU LENGTH MARK +0C56 ; [.1A8C.0020.0002.0C56] # TELUGU AI LENGTH MARK +0C85 ; [.1A8D.0020.0002.0C85] # KANNADA LETTER A +0C86 ; [.1A8E.0020.0002.0C86] # KANNADA LETTER AA +0C87 ; [.1A8F.0020.0002.0C87] # KANNADA LETTER I +0C88 ; [.1A90.0020.0002.0C88] # KANNADA LETTER II +0C89 ; [.1A91.0020.0002.0C89] # KANNADA LETTER U +0C8A ; [.1A92.0020.0002.0C8A] # KANNADA LETTER UU +0C8B ; [.1A93.0020.0002.0C8B] # KANNADA LETTER VOCALIC R +0CE0 ; [.1A94.0020.0002.0CE0] # KANNADA LETTER VOCALIC RR +0C8C ; [.1A95.0020.0002.0C8C] # KANNADA LETTER VOCALIC L +0CE1 ; [.1A96.0020.0002.0CE1] # KANNADA LETTER VOCALIC LL +0C8E ; [.1A97.0020.0002.0C8E] # KANNADA LETTER E +0C8F ; [.1A98.0020.0002.0C8F] # KANNADA LETTER EE +0C90 ; [.1A99.0020.0002.0C90] # KANNADA LETTER AI +0C92 ; [.1A9A.0020.0002.0C92] # KANNADA LETTER O +0C93 ; [.1A9B.0020.0002.0C93] # KANNADA LETTER OO +0C94 ; [.1A9C.0020.0002.0C94] # KANNADA LETTER AU +0C95 ; [.1A9D.0020.0002.0C95] # KANNADA LETTER KA +0C96 ; [.1A9E.0020.0002.0C96] # KANNADA LETTER KHA +0C97 ; [.1A9F.0020.0002.0C97] # KANNADA LETTER GA +0C98 ; [.1AA0.0020.0002.0C98] # KANNADA LETTER GHA +0C99 ; [.1AA1.0020.0002.0C99] # KANNADA LETTER NGA +0C9A ; [.1AA2.0020.0002.0C9A] # KANNADA LETTER CA +0C9B ; [.1AA3.0020.0002.0C9B] # KANNADA LETTER CHA +0C9C ; [.1AA4.0020.0002.0C9C] # KANNADA LETTER JA +0C9D ; [.1AA5.0020.0002.0C9D] # KANNADA LETTER JHA +0C9E ; [.1AA6.0020.0002.0C9E] # KANNADA LETTER NYA +0C9F ; [.1AA7.0020.0002.0C9F] # KANNADA LETTER TTA +0CA0 ; [.1AA8.0020.0002.0CA0] # KANNADA LETTER TTHA +0CA1 ; [.1AA9.0020.0002.0CA1] # KANNADA LETTER DDA +0CA2 ; [.1AAA.0020.0002.0CA2] # KANNADA LETTER DDHA +0CA3 ; [.1AAB.0020.0002.0CA3] # KANNADA LETTER NNA +0CA4 ; [.1AAC.0020.0002.0CA4] # KANNADA LETTER TA +0CA5 ; [.1AAD.0020.0002.0CA5] # KANNADA LETTER THA +0CA6 ; [.1AAE.0020.0002.0CA6] # KANNADA LETTER DA +0CA7 ; [.1AAF.0020.0002.0CA7] # KANNADA LETTER DHA +0CA8 ; [.1AB0.0020.0002.0CA8] # KANNADA LETTER NA +0CAA ; [.1AB1.0020.0002.0CAA] # KANNADA LETTER PA +0CAB ; [.1AB2.0020.0002.0CAB] # KANNADA LETTER PHA +0CAC ; [.1AB3.0020.0002.0CAC] # KANNADA LETTER BA +0CAD ; [.1AB4.0020.0002.0CAD] # KANNADA LETTER BHA +0CAE ; [.1AB5.0020.0002.0CAE] # KANNADA LETTER MA +0CAF ; [.1AB6.0020.0002.0CAF] # KANNADA LETTER YA +0CB0 ; [.1AB7.0020.0002.0CB0] # KANNADA LETTER RA +0CB1 ; [.1AB8.0020.0002.0CB1] # KANNADA LETTER RRA +0CB2 ; [.1AB9.0020.0002.0CB2] # KANNADA LETTER LA +0CB5 ; [.1ABA.0020.0002.0CB5] # KANNADA LETTER VA +0CB6 ; [.1ABB.0020.0002.0CB6] # KANNADA LETTER SHA +0CB7 ; [.1ABC.0020.0002.0CB7] # KANNADA LETTER SSA +0CB8 ; [.1ABD.0020.0002.0CB8] # KANNADA LETTER SA +0CB9 ; [.1ABE.0020.0002.0CB9] # KANNADA LETTER HA +0CB3 ; [.1ABF.0020.0002.0CB3] # KANNADA LETTER LLA +0CDE ; [.1AC0.0020.0002.0CDE] # KANNADA LETTER FA +0CBD ; [.1AC1.0020.0002.0CBD] # KANNADA SIGN AVAGRAHA +0CBE ; [.1AC2.0020.0002.0CBE] # KANNADA VOWEL SIGN AA +0CBF ; [.1AC3.0020.0002.0CBF] # KANNADA VOWEL SIGN I +0CC0 ; [.1AC4.0020.0002.0CC0] # KANNADA VOWEL SIGN II +0CBF 0CD5 ; [.1AC4.0020.0002.0CC0] # KANNADA VOWEL SIGN II +0CC1 ; [.1AC5.0020.0002.0CC1] # KANNADA VOWEL SIGN U +0CC2 ; [.1AC6.0020.0002.0CC2] # KANNADA VOWEL SIGN UU +0CC3 ; [.1AC7.0020.0002.0CC3] # KANNADA VOWEL SIGN VOCALIC R +0CC4 ; [.1AC8.0020.0002.0CC4] # KANNADA VOWEL SIGN VOCALIC RR +0CE2 ; [.1AC9.0020.0002.0CE2] # KANNADA VOWEL SIGN VOCALIC L +0CE3 ; [.1ACA.0020.0002.0CE3] # KANNADA VOWEL SIGN VOCALIC LL +0CC6 ; [.1ACB.0020.0002.0CC6] # KANNADA VOWEL SIGN E +0CC7 ; [.1ACC.0020.0002.0CC7] # KANNADA VOWEL SIGN EE +0CC6 0CD5 ; [.1ACC.0020.0002.0CC7] # KANNADA VOWEL SIGN EE +0CC8 ; [.1ACD.0020.0002.0CC8] # KANNADA VOWEL SIGN AI +0CC6 0CD6 ; [.1ACD.0020.0002.0CC8] # KANNADA VOWEL SIGN AI +0CCA ; [.1ACE.0020.0002.0CCA] # KANNADA VOWEL SIGN O +0CC6 0CC2 ; [.1ACE.0020.0002.0CCA] # KANNADA VOWEL SIGN O +0CCB ; [.1ACF.0020.0002.0CCB] # KANNADA VOWEL SIGN OO +0CC6 0CC2 0CD5 ; [.1ACF.0020.0002.0CCB] # KANNADA VOWEL SIGN OO +0CCA 0CD5 ; [.1ACF.0020.0002.0CCB] # KANNADA VOWEL SIGN OO +0CCC ; [.1AD0.0020.0002.0CCC] # KANNADA VOWEL SIGN AU +0CCD ; [.1AD1.0020.0002.0CCD] # KANNADA SIGN VIRAMA +0CD5 ; [.1AD2.0020.0002.0CD5] # KANNADA LENGTH MARK +0CD6 ; [.1AD3.0020.0002.0CD6] # KANNADA AI LENGTH MARK +0D05 ; [.1AD4.0020.0002.0D05] # MALAYALAM LETTER A +0D06 ; [.1AD5.0020.0002.0D06] # MALAYALAM LETTER AA +0D07 ; [.1AD6.0020.0002.0D07] # MALAYALAM LETTER I +0D08 ; [.1AD7.0020.0002.0D08] # MALAYALAM LETTER II +0D09 ; [.1AD8.0020.0002.0D09] # MALAYALAM LETTER U +0D0A ; [.1AD9.0020.0002.0D0A] # MALAYALAM LETTER UU +0D0B ; [.1ADA.0020.0002.0D0B] # MALAYALAM LETTER VOCALIC R +0D60 ; [.1ADB.0020.0002.0D60] # MALAYALAM LETTER VOCALIC RR +0D0C ; [.1ADC.0020.0002.0D0C] # MALAYALAM LETTER VOCALIC L +0D61 ; [.1ADD.0020.0002.0D61] # MALAYALAM LETTER VOCALIC LL +0D0E ; [.1ADE.0020.0002.0D0E] # MALAYALAM LETTER E +0D0F ; [.1ADF.0020.0002.0D0F] # MALAYALAM LETTER EE +0D10 ; [.1AE0.0020.0002.0D10] # MALAYALAM LETTER AI +0D12 ; [.1AE1.0020.0002.0D12] # MALAYALAM LETTER O +0D13 ; [.1AE2.0020.0002.0D13] # MALAYALAM LETTER OO +0D14 ; [.1AE3.0020.0002.0D14] # MALAYALAM LETTER AU +0D15 ; [.1AE4.0020.0002.0D15] # MALAYALAM LETTER KA +0D16 ; [.1AE5.0020.0002.0D16] # MALAYALAM LETTER KHA +0D17 ; [.1AE6.0020.0002.0D17] # MALAYALAM LETTER GA +0D18 ; [.1AE7.0020.0002.0D18] # MALAYALAM LETTER GHA +0D19 ; [.1AE8.0020.0002.0D19] # MALAYALAM LETTER NGA +0D1A ; [.1AE9.0020.0002.0D1A] # MALAYALAM LETTER CA +0D1B ; [.1AEA.0020.0002.0D1B] # MALAYALAM LETTER CHA +0D1C ; [.1AEB.0020.0002.0D1C] # MALAYALAM LETTER JA +0D1D ; [.1AEC.0020.0002.0D1D] # MALAYALAM LETTER JHA +0D1E ; [.1AED.0020.0002.0D1E] # MALAYALAM LETTER NYA +0D1F ; [.1AEE.0020.0002.0D1F] # MALAYALAM LETTER TTA +0D20 ; [.1AEF.0020.0002.0D20] # MALAYALAM LETTER TTHA +0D21 ; [.1AF0.0020.0002.0D21] # MALAYALAM LETTER DDA +0D22 ; [.1AF1.0020.0002.0D22] # MALAYALAM LETTER DDHA +0D23 ; [.1AF2.0020.0002.0D23] # MALAYALAM LETTER NNA +0D24 ; [.1AF3.0020.0002.0D24] # MALAYALAM LETTER TA +0D25 ; [.1AF4.0020.0002.0D25] # MALAYALAM LETTER THA +0D26 ; [.1AF5.0020.0002.0D26] # MALAYALAM LETTER DA +0D27 ; [.1AF6.0020.0002.0D27] # MALAYALAM LETTER DHA +0D28 ; [.1AF7.0020.0002.0D28] # MALAYALAM LETTER NA +0D2A ; [.1AF8.0020.0002.0D2A] # MALAYALAM LETTER PA +0D2B ; [.1AF9.0020.0002.0D2B] # MALAYALAM LETTER PHA +0D2C ; [.1AFA.0020.0002.0D2C] # MALAYALAM LETTER BA +0D2D ; [.1AFB.0020.0002.0D2D] # MALAYALAM LETTER BHA +0D2E ; [.1AFC.0020.0002.0D2E] # MALAYALAM LETTER MA +0D2F ; [.1AFD.0020.0002.0D2F] # MALAYALAM LETTER YA +0D30 ; [.1AFE.0020.0002.0D30] # MALAYALAM LETTER RA +0D31 ; [.1AFF.0020.0002.0D31] # MALAYALAM LETTER RRA +0D32 ; [.1B00.0020.0002.0D32] # MALAYALAM LETTER LA +0D33 ; [.1B01.0020.0002.0D33] # MALAYALAM LETTER LLA +0D34 ; [.1B02.0020.0002.0D34] # MALAYALAM LETTER LLLA +0D35 ; [.1B03.0020.0002.0D35] # MALAYALAM LETTER VA +0D36 ; [.1B04.0020.0002.0D36] # MALAYALAM LETTER SHA +0D37 ; [.1B05.0020.0002.0D37] # MALAYALAM LETTER SSA +0D38 ; [.1B06.0020.0002.0D38] # MALAYALAM LETTER SA +0D39 ; [.1B07.0020.0002.0D39] # MALAYALAM LETTER HA +0D3E ; [.1B08.0020.0002.0D3E] # MALAYALAM VOWEL SIGN AA +0D3F ; [.1B09.0020.0002.0D3F] # MALAYALAM VOWEL SIGN I +0D40 ; [.1B0A.0020.0002.0D40] # MALAYALAM VOWEL SIGN II +0D41 ; [.1B0B.0020.0002.0D41] # MALAYALAM VOWEL SIGN U +0D42 ; [.1B0C.0020.0002.0D42] # MALAYALAM VOWEL SIGN UU +0D43 ; [.1B0D.0020.0002.0D43] # MALAYALAM VOWEL SIGN VOCALIC R +0D46 ; [.1B0E.0020.0002.0D46] # MALAYALAM VOWEL SIGN E +0D47 ; [.1B0F.0020.0002.0D47] # MALAYALAM VOWEL SIGN EE +0D48 ; [.1B10.0020.0002.0D48] # MALAYALAM VOWEL SIGN AI +0D4A ; [.1B11.0020.0002.0D4A] # MALAYALAM VOWEL SIGN O +0D46 0D3E ; [.1B11.0020.0002.0D4A] # MALAYALAM VOWEL SIGN O +0D4B ; [.1B12.0020.0002.0D4B] # MALAYALAM VOWEL SIGN OO +0D47 0D3E ; [.1B12.0020.0002.0D4B] # MALAYALAM VOWEL SIGN OO +0D4C ; [.1B13.0020.0002.0D4C] # MALAYALAM VOWEL SIGN AU +0D46 0D57 ; [.1B13.0020.0002.0D4C] # MALAYALAM VOWEL SIGN AU +0D57 ; [.1B14.0020.0002.0D57] # MALAYALAM AU LENGTH MARK +0D4D ; [.1B15.0020.0002.0D4D] # MALAYALAM SIGN VIRAMA +0D85 ; [.1B16.0020.0002.0D85] # SINHALA LETTER AYANNA +0D86 ; [.1B17.0020.0002.0D86] # SINHALA LETTER AAYANNA +0D87 ; [.1B18.0020.0002.0D87] # SINHALA LETTER AEYANNA +0D88 ; [.1B19.0020.0002.0D88] # SINHALA LETTER AEEYANNA +0D89 ; [.1B1A.0020.0002.0D89] # SINHALA LETTER IYANNA +0D8A ; [.1B1B.0020.0002.0D8A] # SINHALA LETTER IIYANNA +0D8B ; [.1B1C.0020.0002.0D8B] # SINHALA LETTER UYANNA +0D8C ; [.1B1D.0020.0002.0D8C] # SINHALA LETTER UUYANNA +0D8D ; [.1B1E.0020.0002.0D8D] # SINHALA LETTER IRUYANNA +0D8E ; [.1B1F.0020.0002.0D8E] # SINHALA LETTER IRUUYANNA +0D8F ; [.1B20.0020.0002.0D8F] # SINHALA LETTER ILUYANNA +0D90 ; [.1B21.0020.0002.0D90] # SINHALA LETTER ILUUYANNA +0D91 ; [.1B22.0020.0002.0D91] # SINHALA LETTER EYANNA +0D92 ; [.1B23.0020.0002.0D92] # SINHALA LETTER EEYANNA +0D93 ; [.1B24.0020.0002.0D93] # SINHALA LETTER AIYANNA +0D94 ; [.1B25.0020.0002.0D94] # SINHALA LETTER OYANNA +0D95 ; [.1B26.0020.0002.0D95] # SINHALA LETTER OOYANNA +0D96 ; [.1B27.0020.0002.0D96] # SINHALA LETTER AUYANNA +0D9A ; [.1B28.0020.0002.0D9A] # SINHALA LETTER ALPAPRAANA KAYANNA +0D9B ; [.1B29.0020.0002.0D9B] # SINHALA LETTER MAHAAPRAANA KAYANNA +0D9C ; [.1B2A.0020.0002.0D9C] # SINHALA LETTER ALPAPRAANA GAYANNA +0D9D ; [.1B2B.0020.0002.0D9D] # SINHALA LETTER MAHAAPRAANA GAYANNA +0D9E ; [.1B2C.0020.0002.0D9E] # SINHALA LETTER KANTAJA NAASIKYAYA +0D9F ; [.1B2D.0020.0002.0D9F] # SINHALA LETTER SANYAKA GAYANNA +0DA0 ; [.1B2E.0020.0002.0DA0] # SINHALA LETTER ALPAPRAANA CAYANNA +0DA1 ; [.1B2F.0020.0002.0DA1] # SINHALA LETTER MAHAAPRAANA CAYANNA +0DA2 ; [.1B30.0020.0002.0DA2] # SINHALA LETTER ALPAPRAANA JAYANNA +0DA3 ; [.1B31.0020.0002.0DA3] # SINHALA LETTER MAHAAPRAANA JAYANNA +0DA4 ; [.1B32.0020.0002.0DA4] # SINHALA LETTER TAALUJA NAASIKYAYA +0DA5 ; [.1B33.0020.0002.0DA5] # SINHALA LETTER TAALUJA SANYOOGA NAAKSIKYAYA +0DA6 ; [.1B34.0020.0002.0DA6] # SINHALA LETTER SANYAKA JAYANNA +0DA7 ; [.1B35.0020.0002.0DA7] # SINHALA LETTER ALPAPRAANA TTAYANNA +0DA8 ; [.1B36.0020.0002.0DA8] # SINHALA LETTER MAHAAPRAANA TTAYANNA +0DA9 ; [.1B37.0020.0002.0DA9] # SINHALA LETTER ALPAPRAANA DDAYANNA +0DAA ; [.1B38.0020.0002.0DAA] # SINHALA LETTER MAHAAPRAANA DDAYANNA +0DAB ; [.1B39.0020.0002.0DAB] # SINHALA LETTER MUURDHAJA NAYANNA +0DAC ; [.1B3A.0020.0002.0DAC] # SINHALA LETTER SANYAKA DDAYANNA +0DAD ; [.1B3B.0020.0002.0DAD] # SINHALA LETTER ALPAPRAANA TAYANNA +0DAE ; [.1B3C.0020.0002.0DAE] # SINHALA LETTER MAHAAPRAANA TAYANNA +0DAF ; [.1B3D.0020.0002.0DAF] # SINHALA LETTER ALPAPRAANA DAYANNA +0DB0 ; [.1B3E.0020.0002.0DB0] # SINHALA LETTER MAHAAPRAANA DAYANNA +0DB1 ; [.1B3F.0020.0002.0DB1] # SINHALA LETTER DANTAJA NAYANNA +0DB3 ; [.1B40.0020.0002.0DB3] # SINHALA LETTER SANYAKA DAYANNA +0DB4 ; [.1B41.0020.0002.0DB4] # SINHALA LETTER ALPAPRAANA PAYANNA +0DB5 ; [.1B42.0020.0002.0DB5] # SINHALA LETTER MAHAAPRAANA PAYANNA +0DB6 ; [.1B43.0020.0002.0DB6] # SINHALA LETTER ALPAPRAANA BAYANNA +0DB7 ; [.1B44.0020.0002.0DB7] # SINHALA LETTER MAHAAPRAANA BAYANNA +0DB8 ; [.1B45.0020.0002.0DB8] # SINHALA LETTER MAYANNA +0DB9 ; [.1B46.0020.0002.0DB9] # SINHALA LETTER AMBA BAYANNA +0DBA ; [.1B47.0020.0002.0DBA] # SINHALA LETTER YAYANNA +0DBB ; [.1B48.0020.0002.0DBB] # SINHALA LETTER RAYANNA +0DBD ; [.1B49.0020.0002.0DBD] # SINHALA LETTER DANTAJA LAYANNA +0DC0 ; [.1B4A.0020.0002.0DC0] # SINHALA LETTER VAYANNA +0DC1 ; [.1B4B.0020.0002.0DC1] # SINHALA LETTER TAALUJA SAYANNA +0DC2 ; [.1B4C.0020.0002.0DC2] # SINHALA LETTER MUURDHAJA SAYANNA +0DC3 ; [.1B4D.0020.0002.0DC3] # SINHALA LETTER DANTAJA SAYANNA +0DC4 ; [.1B4E.0020.0002.0DC4] # SINHALA LETTER HAYANNA +0DC5 ; [.1B4F.0020.0002.0DC5] # SINHALA LETTER MUURDHAJA LAYANNA +0DC6 ; [.1B50.0020.0002.0DC6] # SINHALA LETTER FAYANNA +0DCA ; [.1B51.0020.0002.0DCA] # SINHALA SIGN AL-LAKUNA +0DCF ; [.1B52.0020.0002.0DCF] # SINHALA VOWEL SIGN AELA-PILLA +0DD0 ; [.1B53.0020.0002.0DD0] # SINHALA VOWEL SIGN KETTI AEDA-PILLA +0DD1 ; [.1B54.0020.0002.0DD1] # SINHALA VOWEL SIGN DIGA AEDA-PILLA +0DD2 ; [.1B55.0020.0002.0DD2] # SINHALA VOWEL SIGN KETTI IS-PILLA +0DD3 ; [.1B56.0020.0002.0DD3] # SINHALA VOWEL SIGN DIGA IS-PILLA +0DD4 ; [.1B57.0020.0002.0DD4] # SINHALA VOWEL SIGN KETTI PAA-PILLA +0DD6 ; [.1B58.0020.0002.0DD6] # SINHALA VOWEL SIGN DIGA PAA-PILLA +0DD8 ; [.1B59.0020.0002.0DD8] # SINHALA VOWEL SIGN GAETTA-PILLA +0DD9 ; [.1B5A.0020.0002.0DD9] # SINHALA VOWEL SIGN KOMBUVA +0DDA ; [.1B5B.0020.0002.0DDA] # SINHALA VOWEL SIGN DIGA KOMBUVA +0DD9 0DCA ; [.1B5B.0020.0002.0DDA] # SINHALA VOWEL SIGN DIGA KOMBUVA +0DDB ; [.1B5C.0020.0002.0DDB] # SINHALA VOWEL SIGN KOMBU DEKA +0DDC ; [.1B5D.0020.0002.0DDC] # SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA +0DD9 0DCF ; [.1B5D.0020.0002.0DDC] # SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA +0DDD ; [.1B5E.0020.0002.0DDD] # SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA +0DD9 0DCF 0DCA ; [.1B5E.0020.0002.0DDD] # SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA +0DDC 0DCA ; [.1B5E.0020.0002.0DDD] # SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA +0DDE ; [.1B5F.0020.0002.0DDE] # SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA +0DD9 0DDF ; [.1B5F.0020.0002.0DDE] # SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA +0DDF ; [.1B60.0020.0002.0DDF] # SINHALA VOWEL SIGN GAYANUKITTA +0DF2 ; [.1B61.0020.0002.0DF2] # SINHALA VOWEL SIGN DIGA GAETTA-PILLA +0DF3 ; [.1B62.0020.0002.0DF3] # SINHALA VOWEL SIGN DIGA GAYANUKITTA +A800 ; [.1B63.0020.0002.A800] # SYLOTI NAGRI LETTER A +A801 ; [.1B64.0020.0002.A801] # SYLOTI NAGRI LETTER I +A802 ; [.1B65.0020.0002.A802] # SYLOTI NAGRI SIGN DVISVARA +A803 ; [.1B66.0020.0002.A803] # SYLOTI NAGRI LETTER U +A804 ; [.1B67.0020.0002.A804] # SYLOTI NAGRI LETTER E +A805 ; [.1B68.0020.0002.A805] # SYLOTI NAGRI LETTER O +A806 ; [.1B69.0020.0002.A806] # SYLOTI NAGRI SIGN HASANTA +A807 ; [.1B6A.0020.0002.A807] # SYLOTI NAGRI LETTER KO +A808 ; [.1B6B.0020.0002.A808] # SYLOTI NAGRI LETTER KHO +A809 ; [.1B6C.0020.0002.A809] # SYLOTI NAGRI LETTER GO +A80A ; [.1B6D.0020.0002.A80A] # SYLOTI NAGRI LETTER GHO +A80C ; [.1B6E.0020.0002.A80C] # SYLOTI NAGRI LETTER CO +A80D ; [.1B6F.0020.0002.A80D] # SYLOTI NAGRI LETTER CHO +A80E ; [.1B70.0020.0002.A80E] # SYLOTI NAGRI LETTER JO +A80F ; [.1B71.0020.0002.A80F] # SYLOTI NAGRI LETTER JHO +A810 ; [.1B72.0020.0002.A810] # SYLOTI NAGRI LETTER TTO +A811 ; [.1B73.0020.0002.A811] # SYLOTI NAGRI LETTER TTHO +A812 ; [.1B74.0020.0002.A812] # SYLOTI NAGRI LETTER DDO +A813 ; [.1B75.0020.0002.A813] # SYLOTI NAGRI LETTER DDHO +A814 ; [.1B76.0020.0002.A814] # SYLOTI NAGRI LETTER TO +A815 ; [.1B77.0020.0002.A815] # SYLOTI NAGRI LETTER THO +A816 ; [.1B78.0020.0002.A816] # SYLOTI NAGRI LETTER DO +A817 ; [.1B79.0020.0002.A817] # SYLOTI NAGRI LETTER DHO +A818 ; [.1B7A.0020.0002.A818] # SYLOTI NAGRI LETTER NO +A819 ; [.1B7B.0020.0002.A819] # SYLOTI NAGRI LETTER PO +A81A ; [.1B7C.0020.0002.A81A] # SYLOTI NAGRI LETTER PHO +A81B ; [.1B7D.0020.0002.A81B] # SYLOTI NAGRI LETTER BO +A81C ; [.1B7E.0020.0002.A81C] # SYLOTI NAGRI LETTER BHO +A81D ; [.1B7F.0020.0002.A81D] # SYLOTI NAGRI LETTER MO +A81E ; [.1B80.0020.0002.A81E] # SYLOTI NAGRI LETTER RO +A81F ; [.1B81.0020.0002.A81F] # SYLOTI NAGRI LETTER LO +A820 ; [.1B82.0020.0002.A820] # SYLOTI NAGRI LETTER RRO +A821 ; [.1B83.0020.0002.A821] # SYLOTI NAGRI LETTER SO +A822 ; [.1B84.0020.0002.A822] # SYLOTI NAGRI LETTER HO +A823 ; [.1B85.0020.0002.A823] # SYLOTI NAGRI VOWEL SIGN A +A824 ; [.1B86.0020.0002.A824] # SYLOTI NAGRI VOWEL SIGN I +A825 ; [.1B87.0020.0002.A825] # SYLOTI NAGRI VOWEL SIGN U +A826 ; [.1B88.0020.0002.A826] # SYLOTI NAGRI VOWEL SIGN E +A827 ; [.1B89.0020.0002.A827] # SYLOTI NAGRI VOWEL SIGN OO +10A00 ; [.1B8A.0020.0002.10A00] # KHAROSHTHI LETTER A +10A01 ; [.1B8B.0020.0002.10A01] # KHAROSHTHI VOWEL SIGN I +10A02 ; [.1B8C.0020.0002.10A02] # KHAROSHTHI VOWEL SIGN U +10A03 ; [.1B8D.0020.0002.10A03] # KHAROSHTHI VOWEL SIGN VOCALIC R +10A05 ; [.1B8E.0020.0002.10A05] # KHAROSHTHI VOWEL SIGN E +10A06 ; [.1B8F.0020.0002.10A06] # KHAROSHTHI VOWEL SIGN O +10A0C ; [.1B90.0020.0002.10A0C] # KHAROSHTHI VOWEL LENGTH MARK +10A10 ; [.1B91.0020.0002.10A10] # KHAROSHTHI LETTER KA +10A11 ; [.1B92.0020.0002.10A11] # KHAROSHTHI LETTER KHA +10A12 ; [.1B93.0020.0002.10A12] # KHAROSHTHI LETTER GA +10A13 ; [.1B94.0020.0002.10A13] # KHAROSHTHI LETTER GHA +10A15 ; [.1B95.0020.0002.10A15] # KHAROSHTHI LETTER CA +10A16 ; [.1B96.0020.0002.10A16] # KHAROSHTHI LETTER CHA +10A17 ; [.1B97.0020.0002.10A17] # KHAROSHTHI LETTER JA +10A19 ; [.1B98.0020.0002.10A19] # KHAROSHTHI LETTER NYA +10A1A ; [.1B99.0020.0002.10A1A] # KHAROSHTHI LETTER TTA +10A1B ; [.1B9A.0020.0002.10A1B] # KHAROSHTHI LETTER TTHA +10A1C ; [.1B9B.0020.0002.10A1C] # KHAROSHTHI LETTER DDA +10A1D ; [.1B9C.0020.0002.10A1D] # KHAROSHTHI LETTER DDHA +10A1E ; [.1B9D.0020.0002.10A1E] # KHAROSHTHI LETTER NNA +10A1F ; [.1B9E.0020.0002.10A1F] # KHAROSHTHI LETTER TA +10A20 ; [.1B9F.0020.0002.10A20] # KHAROSHTHI LETTER THA +10A21 ; [.1BA0.0020.0002.10A21] # KHAROSHTHI LETTER DA +10A22 ; [.1BA1.0020.0002.10A22] # KHAROSHTHI LETTER DHA +10A23 ; [.1BA2.0020.0002.10A23] # KHAROSHTHI LETTER NA +10A24 ; [.1BA3.0020.0002.10A24] # KHAROSHTHI LETTER PA +10A25 ; [.1BA4.0020.0002.10A25] # KHAROSHTHI LETTER PHA +10A26 ; [.1BA5.0020.0002.10A26] # KHAROSHTHI LETTER BA +10A27 ; [.1BA6.0020.0002.10A27] # KHAROSHTHI LETTER BHA +10A28 ; [.1BA7.0020.0002.10A28] # KHAROSHTHI LETTER MA +10A29 ; [.1BA8.0020.0002.10A29] # KHAROSHTHI LETTER YA +10A2A ; [.1BA9.0020.0002.10A2A] # KHAROSHTHI LETTER RA +10A2B ; [.1BAA.0020.0002.10A2B] # KHAROSHTHI LETTER LA +10A2C ; [.1BAB.0020.0002.10A2C] # KHAROSHTHI LETTER VA +10A2D ; [.1BAC.0020.0002.10A2D] # KHAROSHTHI LETTER SHA +10A2E ; [.1BAD.0020.0002.10A2E] # KHAROSHTHI LETTER SSA +10A2F ; [.1BAE.0020.0002.10A2F] # KHAROSHTHI LETTER SA +10A30 ; [.1BAF.0020.0002.10A30] # KHAROSHTHI LETTER ZA +10A31 ; [.1BB0.0020.0002.10A31] # KHAROSHTHI LETTER HA +10A32 ; [.1BB1.0020.0002.10A32] # KHAROSHTHI LETTER KKA +10A33 ; [.1BB2.0020.0002.10A33] # KHAROSHTHI LETTER TTTHA +10A3F ; [.1BB3.0020.0002.10A3F] # KHAROSHTHI VIRAMA +0E01 ; [.1BB4.0020.0002.0E01] # THAI CHARACTER KO KAI +0E40 0E01 ; [.1BB4.0020.0002.0E01][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER KO KAI> +0E41 0E01 ; [.1BB4.0020.0002.0E01][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER KO KAI> +0E42 0E01 ; [.1BB4.0020.0002.0E01][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER KO KAI> +0E43 0E01 ; [.1BB4.0020.0002.0E01][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER KO KAI> +0E44 0E01 ; [.1BB4.0020.0002.0E01][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER KO KAI> +0E02 ; [.1BB5.0020.0002.0E02] # THAI CHARACTER KHO KHAI +0E40 0E02 ; [.1BB5.0020.0002.0E02][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER KHO KHAI> +0E41 0E02 ; [.1BB5.0020.0002.0E02][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER KHO KHAI> +0E42 0E02 ; [.1BB5.0020.0002.0E02][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER KHO KHAI> +0E43 0E02 ; [.1BB5.0020.0002.0E02][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER KHO KHAI> +0E44 0E02 ; [.1BB5.0020.0002.0E02][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER KHO KHAI> +0E03 ; [.1BB6.0020.0002.0E03] # THAI CHARACTER KHO KHUAT +0E40 0E03 ; [.1BB6.0020.0002.0E03][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER KHO KHUAT> +0E41 0E03 ; [.1BB6.0020.0002.0E03][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER KHO KHUAT> +0E42 0E03 ; [.1BB6.0020.0002.0E03][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER KHO KHUAT> +0E43 0E03 ; [.1BB6.0020.0002.0E03][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER KHO KHUAT> +0E44 0E03 ; [.1BB6.0020.0002.0E03][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER KHO KHUAT> +0E04 ; [.1BB7.0020.0002.0E04] # THAI CHARACTER KHO KHWAI +0E40 0E04 ; [.1BB7.0020.0002.0E04][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER KHO KHWAI> +0E41 0E04 ; [.1BB7.0020.0002.0E04][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER KHO KHWAI> +0E42 0E04 ; [.1BB7.0020.0002.0E04][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER KHO KHWAI> +0E43 0E04 ; [.1BB7.0020.0002.0E04][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER KHO KHWAI> +0E44 0E04 ; [.1BB7.0020.0002.0E04][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER KHO KHWAI> +0E05 ; [.1BB8.0020.0002.0E05] # THAI CHARACTER KHO KHON +0E40 0E05 ; [.1BB8.0020.0002.0E05][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER KHO KHON> +0E41 0E05 ; [.1BB8.0020.0002.0E05][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER KHO KHON> +0E42 0E05 ; [.1BB8.0020.0002.0E05][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER KHO KHON> +0E43 0E05 ; [.1BB8.0020.0002.0E05][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER KHO KHON> +0E44 0E05 ; [.1BB8.0020.0002.0E05][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER KHO KHON> +0E06 ; [.1BB9.0020.0002.0E06] # THAI CHARACTER KHO RAKHANG +0E40 0E06 ; [.1BB9.0020.0002.0E06][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER KHO RAKHANG> +0E41 0E06 ; [.1BB9.0020.0002.0E06][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER KHO RAKHANG> +0E42 0E06 ; [.1BB9.0020.0002.0E06][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER KHO RAKHANG> +0E43 0E06 ; [.1BB9.0020.0002.0E06][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER KHO RAKHANG> +0E44 0E06 ; [.1BB9.0020.0002.0E06][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER KHO RAKHANG> +0E07 ; [.1BBA.0020.0002.0E07] # THAI CHARACTER NGO NGU +0E40 0E07 ; [.1BBA.0020.0002.0E07][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER NGO NGU> +0E41 0E07 ; [.1BBA.0020.0002.0E07][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER NGO NGU> +0E42 0E07 ; [.1BBA.0020.0002.0E07][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER NGO NGU> +0E43 0E07 ; [.1BBA.0020.0002.0E07][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER NGO NGU> +0E44 0E07 ; [.1BBA.0020.0002.0E07][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER NGO NGU> +0E08 ; [.1BBB.0020.0002.0E08] # THAI CHARACTER CHO CHAN +0E40 0E08 ; [.1BBB.0020.0002.0E08][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER CHO CHAN> +0E41 0E08 ; [.1BBB.0020.0002.0E08][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER CHO CHAN> +0E42 0E08 ; [.1BBB.0020.0002.0E08][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER CHO CHAN> +0E43 0E08 ; [.1BBB.0020.0002.0E08][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER CHO CHAN> +0E44 0E08 ; [.1BBB.0020.0002.0E08][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER CHO CHAN> +0E09 ; [.1BBC.0020.0002.0E09] # THAI CHARACTER CHO CHING +0E40 0E09 ; [.1BBC.0020.0002.0E09][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER CHO CHING> +0E41 0E09 ; [.1BBC.0020.0002.0E09][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER CHO CHING> +0E42 0E09 ; [.1BBC.0020.0002.0E09][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER CHO CHING> +0E43 0E09 ; [.1BBC.0020.0002.0E09][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER CHO CHING> +0E44 0E09 ; [.1BBC.0020.0002.0E09][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER CHO CHING> +0E0A ; [.1BBD.0020.0002.0E0A] # THAI CHARACTER CHO CHANG +0E40 0E0A ; [.1BBD.0020.0002.0E0A][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER CHO CHANG> +0E41 0E0A ; [.1BBD.0020.0002.0E0A][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER CHO CHANG> +0E42 0E0A ; [.1BBD.0020.0002.0E0A][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER CHO CHANG> +0E43 0E0A ; [.1BBD.0020.0002.0E0A][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER CHO CHANG> +0E44 0E0A ; [.1BBD.0020.0002.0E0A][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER CHO CHANG> +0E0B ; [.1BBE.0020.0002.0E0B] # THAI CHARACTER SO SO +0E40 0E0B ; [.1BBE.0020.0002.0E0B][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER SO SO> +0E41 0E0B ; [.1BBE.0020.0002.0E0B][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER SO SO> +0E42 0E0B ; [.1BBE.0020.0002.0E0B][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER SO SO> +0E43 0E0B ; [.1BBE.0020.0002.0E0B][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER SO SO> +0E44 0E0B ; [.1BBE.0020.0002.0E0B][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER SO SO> +0E0C ; [.1BBF.0020.0002.0E0C] # THAI CHARACTER CHO CHOE +0E40 0E0C ; [.1BBF.0020.0002.0E0C][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER CHO CHOE> +0E41 0E0C ; [.1BBF.0020.0002.0E0C][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER CHO CHOE> +0E42 0E0C ; [.1BBF.0020.0002.0E0C][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER CHO CHOE> +0E43 0E0C ; [.1BBF.0020.0002.0E0C][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER CHO CHOE> +0E44 0E0C ; [.1BBF.0020.0002.0E0C][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER CHO CHOE> +0E0D ; [.1BC0.0020.0002.0E0D] # THAI CHARACTER YO YING +0E40 0E0D ; [.1BC0.0020.0002.0E0D][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER YO YING> +0E41 0E0D ; [.1BC0.0020.0002.0E0D][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER YO YING> +0E42 0E0D ; [.1BC0.0020.0002.0E0D][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER YO YING> +0E43 0E0D ; [.1BC0.0020.0002.0E0D][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER YO YING> +0E44 0E0D ; [.1BC0.0020.0002.0E0D][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER YO YING> +0E0E ; [.1BC1.0020.0002.0E0E] # THAI CHARACTER DO CHADA +0E40 0E0E ; [.1BC1.0020.0002.0E0E][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER DO CHADA> +0E41 0E0E ; [.1BC1.0020.0002.0E0E][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER DO CHADA> +0E42 0E0E ; [.1BC1.0020.0002.0E0E][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER DO CHADA> +0E43 0E0E ; [.1BC1.0020.0002.0E0E][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER DO CHADA> +0E44 0E0E ; [.1BC1.0020.0002.0E0E][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER DO CHADA> +0E0F ; [.1BC2.0020.0002.0E0F] # THAI CHARACTER TO PATAK +0E40 0E0F ; [.1BC2.0020.0002.0E0F][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER TO PATAK> +0E41 0E0F ; [.1BC2.0020.0002.0E0F][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER TO PATAK> +0E42 0E0F ; [.1BC2.0020.0002.0E0F][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER TO PATAK> +0E43 0E0F ; [.1BC2.0020.0002.0E0F][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER TO PATAK> +0E44 0E0F ; [.1BC2.0020.0002.0E0F][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER TO PATAK> +0E10 ; [.1BC3.0020.0002.0E10] # THAI CHARACTER THO THAN +0E40 0E10 ; [.1BC3.0020.0002.0E10][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER THO THAN> +0E41 0E10 ; [.1BC3.0020.0002.0E10][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER THO THAN> +0E42 0E10 ; [.1BC3.0020.0002.0E10][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER THO THAN> +0E43 0E10 ; [.1BC3.0020.0002.0E10][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER THO THAN> +0E44 0E10 ; [.1BC3.0020.0002.0E10][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER THO THAN> +0E11 ; [.1BC4.0020.0002.0E11] # THAI CHARACTER THO NANGMONTHO +0E40 0E11 ; [.1BC4.0020.0002.0E11][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER THO NANGMONTHO> +0E41 0E11 ; [.1BC4.0020.0002.0E11][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER THO NANGMONTHO> +0E42 0E11 ; [.1BC4.0020.0002.0E11][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER THO NANGMONTHO> +0E43 0E11 ; [.1BC4.0020.0002.0E11][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER THO NANGMONTHO> +0E44 0E11 ; [.1BC4.0020.0002.0E11][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER THO NANGMONTHO> +0E12 ; [.1BC5.0020.0002.0E12] # THAI CHARACTER THO PHUTHAO +0E40 0E12 ; [.1BC5.0020.0002.0E12][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER THO PHUTHAO> +0E41 0E12 ; [.1BC5.0020.0002.0E12][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER THO PHUTHAO> +0E42 0E12 ; [.1BC5.0020.0002.0E12][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER THO PHUTHAO> +0E43 0E12 ; [.1BC5.0020.0002.0E12][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER THO PHUTHAO> +0E44 0E12 ; [.1BC5.0020.0002.0E12][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER THO PHUTHAO> +0E13 ; [.1BC6.0020.0002.0E13] # THAI CHARACTER NO NEN +0E40 0E13 ; [.1BC6.0020.0002.0E13][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER NO NEN> +0E41 0E13 ; [.1BC6.0020.0002.0E13][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER NO NEN> +0E42 0E13 ; [.1BC6.0020.0002.0E13][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER NO NEN> +0E43 0E13 ; [.1BC6.0020.0002.0E13][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER NO NEN> +0E44 0E13 ; [.1BC6.0020.0002.0E13][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER NO NEN> +0E14 ; [.1BC7.0020.0002.0E14] # THAI CHARACTER DO DEK +0E40 0E14 ; [.1BC7.0020.0002.0E14][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER DO DEK> +0E41 0E14 ; [.1BC7.0020.0002.0E14][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER DO DEK> +0E42 0E14 ; [.1BC7.0020.0002.0E14][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER DO DEK> +0E43 0E14 ; [.1BC7.0020.0002.0E14][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER DO DEK> +0E44 0E14 ; [.1BC7.0020.0002.0E14][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER DO DEK> +0E15 ; [.1BC8.0020.0002.0E15] # THAI CHARACTER TO TAO +0E40 0E15 ; [.1BC8.0020.0002.0E15][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER TO TAO> +0E41 0E15 ; [.1BC8.0020.0002.0E15][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER TO TAO> +0E42 0E15 ; [.1BC8.0020.0002.0E15][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER TO TAO> +0E43 0E15 ; [.1BC8.0020.0002.0E15][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER TO TAO> +0E44 0E15 ; [.1BC8.0020.0002.0E15][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER TO TAO> +0E16 ; [.1BC9.0020.0002.0E16] # THAI CHARACTER THO THUNG +0E40 0E16 ; [.1BC9.0020.0002.0E16][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER THO THUNG> +0E41 0E16 ; [.1BC9.0020.0002.0E16][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER THO THUNG> +0E42 0E16 ; [.1BC9.0020.0002.0E16][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER THO THUNG> +0E43 0E16 ; [.1BC9.0020.0002.0E16][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER THO THUNG> +0E44 0E16 ; [.1BC9.0020.0002.0E16][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER THO THUNG> +0E17 ; [.1BCA.0020.0002.0E17] # THAI CHARACTER THO THAHAN +0E40 0E17 ; [.1BCA.0020.0002.0E17][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER THO THAHAN> +0E41 0E17 ; [.1BCA.0020.0002.0E17][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER THO THAHAN> +0E42 0E17 ; [.1BCA.0020.0002.0E17][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER THO THAHAN> +0E43 0E17 ; [.1BCA.0020.0002.0E17][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER THO THAHAN> +0E44 0E17 ; [.1BCA.0020.0002.0E17][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER THO THAHAN> +0E18 ; [.1BCB.0020.0002.0E18] # THAI CHARACTER THO THONG +0E40 0E18 ; [.1BCB.0020.0002.0E18][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER THO THONG> +0E41 0E18 ; [.1BCB.0020.0002.0E18][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER THO THONG> +0E42 0E18 ; [.1BCB.0020.0002.0E18][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER THO THONG> +0E43 0E18 ; [.1BCB.0020.0002.0E18][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER THO THONG> +0E44 0E18 ; [.1BCB.0020.0002.0E18][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER THO THONG> +0E19 ; [.1BCC.0020.0002.0E19] # THAI CHARACTER NO NU +0E40 0E19 ; [.1BCC.0020.0002.0E19][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER NO NU> +0E41 0E19 ; [.1BCC.0020.0002.0E19][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER NO NU> +0E42 0E19 ; [.1BCC.0020.0002.0E19][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER NO NU> +0E43 0E19 ; [.1BCC.0020.0002.0E19][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER NO NU> +0E44 0E19 ; [.1BCC.0020.0002.0E19][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER NO NU> +0E1A ; [.1BCD.0020.0002.0E1A] # THAI CHARACTER BO BAIMAI +0E40 0E1A ; [.1BCD.0020.0002.0E1A][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER BO BAIMAI> +0E41 0E1A ; [.1BCD.0020.0002.0E1A][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER BO BAIMAI> +0E42 0E1A ; [.1BCD.0020.0002.0E1A][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER BO BAIMAI> +0E43 0E1A ; [.1BCD.0020.0002.0E1A][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER BO BAIMAI> +0E44 0E1A ; [.1BCD.0020.0002.0E1A][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER BO BAIMAI> +0E1B ; [.1BCE.0020.0002.0E1B] # THAI CHARACTER PO PLA +0E40 0E1B ; [.1BCE.0020.0002.0E1B][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER PO PLA> +0E41 0E1B ; [.1BCE.0020.0002.0E1B][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER PO PLA> +0E42 0E1B ; [.1BCE.0020.0002.0E1B][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER PO PLA> +0E43 0E1B ; [.1BCE.0020.0002.0E1B][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER PO PLA> +0E44 0E1B ; [.1BCE.0020.0002.0E1B][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER PO PLA> +0E1C ; [.1BCF.0020.0002.0E1C] # THAI CHARACTER PHO PHUNG +0E40 0E1C ; [.1BCF.0020.0002.0E1C][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER PHO PHUNG> +0E41 0E1C ; [.1BCF.0020.0002.0E1C][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER PHO PHUNG> +0E42 0E1C ; [.1BCF.0020.0002.0E1C][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER PHO PHUNG> +0E43 0E1C ; [.1BCF.0020.0002.0E1C][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER PHO PHUNG> +0E44 0E1C ; [.1BCF.0020.0002.0E1C][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER PHO PHUNG> +0E1D ; [.1BD0.0020.0002.0E1D] # THAI CHARACTER FO FA +0E40 0E1D ; [.1BD0.0020.0002.0E1D][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER FO FA> +0E41 0E1D ; [.1BD0.0020.0002.0E1D][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER FO FA> +0E42 0E1D ; [.1BD0.0020.0002.0E1D][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER FO FA> +0E43 0E1D ; [.1BD0.0020.0002.0E1D][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER FO FA> +0E44 0E1D ; [.1BD0.0020.0002.0E1D][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER FO FA> +0E1E ; [.1BD1.0020.0002.0E1E] # THAI CHARACTER PHO PHAN +0E40 0E1E ; [.1BD1.0020.0002.0E1E][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER PHO PHAN> +0E41 0E1E ; [.1BD1.0020.0002.0E1E][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER PHO PHAN> +0E42 0E1E ; [.1BD1.0020.0002.0E1E][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER PHO PHAN> +0E43 0E1E ; [.1BD1.0020.0002.0E1E][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER PHO PHAN> +0E44 0E1E ; [.1BD1.0020.0002.0E1E][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER PHO PHAN> +0E1F ; [.1BD2.0020.0002.0E1F] # THAI CHARACTER FO FAN +0E40 0E1F ; [.1BD2.0020.0002.0E1F][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER FO FAN> +0E41 0E1F ; [.1BD2.0020.0002.0E1F][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER FO FAN> +0E42 0E1F ; [.1BD2.0020.0002.0E1F][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER FO FAN> +0E43 0E1F ; [.1BD2.0020.0002.0E1F][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER FO FAN> +0E44 0E1F ; [.1BD2.0020.0002.0E1F][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER FO FAN> +0E20 ; [.1BD3.0020.0002.0E20] # THAI CHARACTER PHO SAMPHAO +0E40 0E20 ; [.1BD3.0020.0002.0E20][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER PHO SAMPHAO> +0E41 0E20 ; [.1BD3.0020.0002.0E20][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER PHO SAMPHAO> +0E42 0E20 ; [.1BD3.0020.0002.0E20][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER PHO SAMPHAO> +0E43 0E20 ; [.1BD3.0020.0002.0E20][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER PHO SAMPHAO> +0E44 0E20 ; [.1BD3.0020.0002.0E20][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER PHO SAMPHAO> +0E21 ; [.1BD4.0020.0002.0E21] # THAI CHARACTER MO MA +0E40 0E21 ; [.1BD4.0020.0002.0E21][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER MO MA> +0E41 0E21 ; [.1BD4.0020.0002.0E21][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER MO MA> +0E42 0E21 ; [.1BD4.0020.0002.0E21][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER MO MA> +0E43 0E21 ; [.1BD4.0020.0002.0E21][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER MO MA> +0E44 0E21 ; [.1BD4.0020.0002.0E21][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER MO MA> +0E22 ; [.1BD5.0020.0002.0E22] # THAI CHARACTER YO YAK +0E40 0E22 ; [.1BD5.0020.0002.0E22][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER YO YAK> +0E41 0E22 ; [.1BD5.0020.0002.0E22][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER YO YAK> +0E42 0E22 ; [.1BD5.0020.0002.0E22][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER YO YAK> +0E43 0E22 ; [.1BD5.0020.0002.0E22][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER YO YAK> +0E44 0E22 ; [.1BD5.0020.0002.0E22][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER YO YAK> +0E23 ; [.1BD6.0020.0002.0E23] # THAI CHARACTER RO RUA +0E40 0E23 ; [.1BD6.0020.0002.0E23][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER RO RUA> +0E41 0E23 ; [.1BD6.0020.0002.0E23][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER RO RUA> +0E42 0E23 ; [.1BD6.0020.0002.0E23][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER RO RUA> +0E43 0E23 ; [.1BD6.0020.0002.0E23][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER RO RUA> +0E44 0E23 ; [.1BD6.0020.0002.0E23][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER RO RUA> +0E24 ; [.1BD7.0020.0002.0E24] # THAI CHARACTER RU +0E40 0E24 ; [.1BD7.0020.0002.0E24][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER RU> +0E41 0E24 ; [.1BD7.0020.0002.0E24][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER RU> +0E42 0E24 ; [.1BD7.0020.0002.0E24][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER RU> +0E43 0E24 ; [.1BD7.0020.0002.0E24][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER RU> +0E44 0E24 ; [.1BD7.0020.0002.0E24][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER RU> +0E25 ; [.1BD8.0020.0002.0E25] # THAI CHARACTER LO LING +0E40 0E25 ; [.1BD8.0020.0002.0E25][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER LO LING> +0E41 0E25 ; [.1BD8.0020.0002.0E25][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER LO LING> +0E42 0E25 ; [.1BD8.0020.0002.0E25][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER LO LING> +0E43 0E25 ; [.1BD8.0020.0002.0E25][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER LO LING> +0E44 0E25 ; [.1BD8.0020.0002.0E25][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER LO LING> +0E26 ; [.1BD9.0020.0002.0E26] # THAI CHARACTER LU +0E40 0E26 ; [.1BD9.0020.0002.0E26][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER LU> +0E41 0E26 ; [.1BD9.0020.0002.0E26][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER LU> +0E42 0E26 ; [.1BD9.0020.0002.0E26][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER LU> +0E43 0E26 ; [.1BD9.0020.0002.0E26][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER LU> +0E44 0E26 ; [.1BD9.0020.0002.0E26][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER LU> +0E27 ; [.1BDA.0020.0002.0E27] # THAI CHARACTER WO WAEN +0E40 0E27 ; [.1BDA.0020.0002.0E27][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER WO WAEN> +0E41 0E27 ; [.1BDA.0020.0002.0E27][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER WO WAEN> +0E42 0E27 ; [.1BDA.0020.0002.0E27][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER WO WAEN> +0E43 0E27 ; [.1BDA.0020.0002.0E27][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER WO WAEN> +0E44 0E27 ; [.1BDA.0020.0002.0E27][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER WO WAEN> +0E28 ; [.1BDB.0020.0002.0E28] # THAI CHARACTER SO SALA +0E40 0E28 ; [.1BDB.0020.0002.0E28][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER SO SALA> +0E41 0E28 ; [.1BDB.0020.0002.0E28][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER SO SALA> +0E42 0E28 ; [.1BDB.0020.0002.0E28][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER SO SALA> +0E43 0E28 ; [.1BDB.0020.0002.0E28][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER SO SALA> +0E44 0E28 ; [.1BDB.0020.0002.0E28][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER SO SALA> +0E29 ; [.1BDC.0020.0002.0E29] # THAI CHARACTER SO RUSI +0E40 0E29 ; [.1BDC.0020.0002.0E29][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER SO RUSI> +0E41 0E29 ; [.1BDC.0020.0002.0E29][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER SO RUSI> +0E42 0E29 ; [.1BDC.0020.0002.0E29][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER SO RUSI> +0E43 0E29 ; [.1BDC.0020.0002.0E29][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER SO RUSI> +0E44 0E29 ; [.1BDC.0020.0002.0E29][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER SO RUSI> +0E2A ; [.1BDD.0020.0002.0E2A] # THAI CHARACTER SO SUA +0E40 0E2A ; [.1BDD.0020.0002.0E2A][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER SO SUA> +0E41 0E2A ; [.1BDD.0020.0002.0E2A][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER SO SUA> +0E42 0E2A ; [.1BDD.0020.0002.0E2A][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER SO SUA> +0E43 0E2A ; [.1BDD.0020.0002.0E2A][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER SO SUA> +0E44 0E2A ; [.1BDD.0020.0002.0E2A][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER SO SUA> +0E2B ; [.1BDE.0020.0002.0E2B] # THAI CHARACTER HO HIP +0E40 0E2B ; [.1BDE.0020.0002.0E2B][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER HO HIP> +0E41 0E2B ; [.1BDE.0020.0002.0E2B][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER HO HIP> +0E42 0E2B ; [.1BDE.0020.0002.0E2B][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER HO HIP> +0E43 0E2B ; [.1BDE.0020.0002.0E2B][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER HO HIP> +0E44 0E2B ; [.1BDE.0020.0002.0E2B][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER HO HIP> +0E2C ; [.1BDF.0020.0002.0E2C] # THAI CHARACTER LO CHULA +0E40 0E2C ; [.1BDF.0020.0002.0E2C][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER LO CHULA> +0E41 0E2C ; [.1BDF.0020.0002.0E2C][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER LO CHULA> +0E42 0E2C ; [.1BDF.0020.0002.0E2C][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER LO CHULA> +0E43 0E2C ; [.1BDF.0020.0002.0E2C][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER LO CHULA> +0E44 0E2C ; [.1BDF.0020.0002.0E2C][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER LO CHULA> +0E2D ; [.1BE0.0020.0002.0E2D] # THAI CHARACTER O ANG +0E40 0E2D ; [.1BE0.0020.0002.0E2D][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER O ANG> +0E41 0E2D ; [.1BE0.0020.0002.0E2D][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER O ANG> +0E42 0E2D ; [.1BE0.0020.0002.0E2D][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER O ANG> +0E43 0E2D ; [.1BE0.0020.0002.0E2D][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER O ANG> +0E44 0E2D ; [.1BE0.0020.0002.0E2D][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER O ANG> +0E2E ; [.1BE1.0020.0002.0E2E] # THAI CHARACTER HO NOKHUK +0E40 0E2E ; [.1BE1.0020.0002.0E2E][.1BEE.0020.001F.0E40] # <THAI CHARACTER SARA E, THAI CHARACTER HO NOKHUK> +0E41 0E2E ; [.1BE1.0020.0002.0E2E][.1BEF.0020.001F.0E41] # <THAI CHARACTER SARA AE, THAI CHARACTER HO NOKHUK> +0E42 0E2E ; [.1BE1.0020.0002.0E2E][.1BF0.0020.001F.0E42] # <THAI CHARACTER SARA O, THAI CHARACTER HO NOKHUK> +0E43 0E2E ; [.1BE1.0020.0002.0E2E][.1BF1.0020.001F.0E43] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER HO NOKHUK> +0E44 0E2E ; [.1BE1.0020.0002.0E2E][.1BF2.0020.001F.0E44] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER HO NOKHUK> +0E2F ; [.1BE2.0020.0002.0E2F] # THAI CHARACTER PAIYANNOI +0E30 ; [.1BE3.0020.0002.0E30] # THAI CHARACTER SARA A +0E31 ; [.1BE4.0020.0002.0E31] # THAI CHARACTER MAI HAN-AKAT +0E32 ; [.1BE5.0020.0002.0E32] # THAI CHARACTER SARA AA +0E33 ; [.1BE6.0020.0002.0E33] # THAI CHARACTER SARA AM +0E4D 0E32 ; [.1BE6.0020.0002.0E33] # THAI CHARACTER SARA AM +0E34 ; [.1BE7.0020.0002.0E34] # THAI CHARACTER SARA I +0E35 ; [.1BE8.0020.0002.0E35] # THAI CHARACTER SARA II +0E36 ; [.1BE9.0020.0002.0E36] # THAI CHARACTER SARA UE +0E37 ; [.1BEA.0020.0002.0E37] # THAI CHARACTER SARA UEE +0E38 ; [.1BEB.0020.0002.0E38] # THAI CHARACTER SARA U +0E39 ; [.1BEC.0020.0002.0E39] # THAI CHARACTER SARA UU +0E3A ; [.1BED.0020.0002.0E3A] # THAI CHARACTER PHINTHU +0E40 ; [.1BEE.0020.0002.0E40] # THAI CHARACTER SARA E +0E41 ; [.1BEF.0020.0002.0E41] # THAI CHARACTER SARA AE +0E42 ; [.1BF0.0020.0002.0E42] # THAI CHARACTER SARA O +0E43 ; [.1BF1.0020.0002.0E43] # THAI CHARACTER SARA AI MAIMUAN +0E44 ; [.1BF2.0020.0002.0E44] # THAI CHARACTER SARA AI MAIMALAI +0E45 ; [.1BF3.0020.0002.0E45] # THAI CHARACTER LAKKHANGYAO +0E81 ; [.1BF4.0020.0002.0E81] # LAO LETTER KO +0EC0 0E81 ; [.1BF4.0020.0002.0E81][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER KO> +0EC1 0E81 ; [.1BF4.0020.0002.0E81][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER KO> +0EC2 0E81 ; [.1BF4.0020.0002.0E81][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER KO> +0EC3 0E81 ; [.1BF4.0020.0002.0E81][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER KO> +0EC4 0E81 ; [.1BF4.0020.0002.0E81][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER KO> +0E82 ; [.1BF5.0020.0002.0E82] # LAO LETTER KHO SUNG +0EC0 0E82 ; [.1BF5.0020.0002.0E82][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER KHO SUNG> +0EC1 0E82 ; [.1BF5.0020.0002.0E82][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER KHO SUNG> +0EC2 0E82 ; [.1BF5.0020.0002.0E82][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER KHO SUNG> +0EC3 0E82 ; [.1BF5.0020.0002.0E82][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER KHO SUNG> +0EC4 0E82 ; [.1BF5.0020.0002.0E82][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER KHO SUNG> +0E84 ; [.1BF6.0020.0002.0E84] # LAO LETTER KHO TAM +0EC0 0E84 ; [.1BF6.0020.0002.0E84][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER KHO TAM> +0EC1 0E84 ; [.1BF6.0020.0002.0E84][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER KHO TAM> +0EC2 0E84 ; [.1BF6.0020.0002.0E84][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER KHO TAM> +0EC3 0E84 ; [.1BF6.0020.0002.0E84][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER KHO TAM> +0EC4 0E84 ; [.1BF6.0020.0002.0E84][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER KHO TAM> +0E87 ; [.1BF7.0020.0002.0E87] # LAO LETTER NGO +0EC0 0E87 ; [.1BF7.0020.0002.0E87][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER NGO> +0EC1 0E87 ; [.1BF7.0020.0002.0E87][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER NGO> +0EC2 0E87 ; [.1BF7.0020.0002.0E87][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER NGO> +0EC3 0E87 ; [.1BF7.0020.0002.0E87][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER NGO> +0EC4 0E87 ; [.1BF7.0020.0002.0E87][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER NGO> +0E88 ; [.1BF8.0020.0002.0E88] # LAO LETTER CO +0EC0 0E88 ; [.1BF8.0020.0002.0E88][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER CO> +0EC1 0E88 ; [.1BF8.0020.0002.0E88][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER CO> +0EC2 0E88 ; [.1BF8.0020.0002.0E88][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER CO> +0EC3 0E88 ; [.1BF8.0020.0002.0E88][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER CO> +0EC4 0E88 ; [.1BF8.0020.0002.0E88][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER CO> +0E8A ; [.1BF9.0020.0002.0E8A] # LAO LETTER SO TAM +0EC0 0E8A ; [.1BF9.0020.0002.0E8A][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER SO TAM> +0EC1 0E8A ; [.1BF9.0020.0002.0E8A][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER SO TAM> +0EC2 0E8A ; [.1BF9.0020.0002.0E8A][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER SO TAM> +0EC3 0E8A ; [.1BF9.0020.0002.0E8A][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER SO TAM> +0EC4 0E8A ; [.1BF9.0020.0002.0E8A][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER SO TAM> +0E8D ; [.1BFA.0020.0002.0E8D] # LAO LETTER NYO +0EC0 0E8D ; [.1BFA.0020.0002.0E8D][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER NYO> +0EC1 0E8D ; [.1BFA.0020.0002.0E8D][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER NYO> +0EC2 0E8D ; [.1BFA.0020.0002.0E8D][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER NYO> +0EC3 0E8D ; [.1BFA.0020.0002.0E8D][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER NYO> +0EC4 0E8D ; [.1BFA.0020.0002.0E8D][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER NYO> +0E94 ; [.1BFB.0020.0002.0E94] # LAO LETTER DO +0EC0 0E94 ; [.1BFB.0020.0002.0E94][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER DO> +0EC1 0E94 ; [.1BFB.0020.0002.0E94][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER DO> +0EC2 0E94 ; [.1BFB.0020.0002.0E94][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER DO> +0EC3 0E94 ; [.1BFB.0020.0002.0E94][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER DO> +0EC4 0E94 ; [.1BFB.0020.0002.0E94][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER DO> +0E95 ; [.1BFC.0020.0002.0E95] # LAO LETTER TO +0EC0 0E95 ; [.1BFC.0020.0002.0E95][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER TO> +0EC1 0E95 ; [.1BFC.0020.0002.0E95][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER TO> +0EC2 0E95 ; [.1BFC.0020.0002.0E95][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER TO> +0EC3 0E95 ; [.1BFC.0020.0002.0E95][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER TO> +0EC4 0E95 ; [.1BFC.0020.0002.0E95][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER TO> +0E96 ; [.1BFD.0020.0002.0E96] # LAO LETTER THO SUNG +0EC0 0E96 ; [.1BFD.0020.0002.0E96][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER THO SUNG> +0EC1 0E96 ; [.1BFD.0020.0002.0E96][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER THO SUNG> +0EC2 0E96 ; [.1BFD.0020.0002.0E96][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER THO SUNG> +0EC3 0E96 ; [.1BFD.0020.0002.0E96][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER THO SUNG> +0EC4 0E96 ; [.1BFD.0020.0002.0E96][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER THO SUNG> +0E97 ; [.1BFE.0020.0002.0E97] # LAO LETTER THO TAM +0EC0 0E97 ; [.1BFE.0020.0002.0E97][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER THO TAM> +0EC1 0E97 ; [.1BFE.0020.0002.0E97][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER THO TAM> +0EC2 0E97 ; [.1BFE.0020.0002.0E97][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER THO TAM> +0EC3 0E97 ; [.1BFE.0020.0002.0E97][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER THO TAM> +0EC4 0E97 ; [.1BFE.0020.0002.0E97][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER THO TAM> +0E99 ; [.1BFF.0020.0002.0E99] # LAO LETTER NO +0EC0 0E99 ; [.1BFF.0020.0002.0E99][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER NO> +0EC1 0E99 ; [.1BFF.0020.0002.0E99][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER NO> +0EC2 0E99 ; [.1BFF.0020.0002.0E99][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER NO> +0EC3 0E99 ; [.1BFF.0020.0002.0E99][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER NO> +0EC4 0E99 ; [.1BFF.0020.0002.0E99][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER NO> +0E9A ; [.1C00.0020.0002.0E9A] # LAO LETTER BO +0EC0 0E9A ; [.1C00.0020.0002.0E9A][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER BO> +0EC1 0E9A ; [.1C00.0020.0002.0E9A][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER BO> +0EC2 0E9A ; [.1C00.0020.0002.0E9A][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER BO> +0EC3 0E9A ; [.1C00.0020.0002.0E9A][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER BO> +0EC4 0E9A ; [.1C00.0020.0002.0E9A][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER BO> +0E9B ; [.1C01.0020.0002.0E9B] # LAO LETTER PO +0EC0 0E9B ; [.1C01.0020.0002.0E9B][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER PO> +0EC1 0E9B ; [.1C01.0020.0002.0E9B][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER PO> +0EC2 0E9B ; [.1C01.0020.0002.0E9B][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER PO> +0EC3 0E9B ; [.1C01.0020.0002.0E9B][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER PO> +0EC4 0E9B ; [.1C01.0020.0002.0E9B][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER PO> +0E9C ; [.1C02.0020.0002.0E9C] # LAO LETTER PHO SUNG +0EC0 0E9C ; [.1C02.0020.0002.0E9C][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER PHO SUNG> +0EC1 0E9C ; [.1C02.0020.0002.0E9C][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER PHO SUNG> +0EC2 0E9C ; [.1C02.0020.0002.0E9C][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER PHO SUNG> +0EC3 0E9C ; [.1C02.0020.0002.0E9C][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER PHO SUNG> +0EC4 0E9C ; [.1C02.0020.0002.0E9C][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER PHO SUNG> +0E9D ; [.1C03.0020.0002.0E9D] # LAO LETTER FO TAM +0EC0 0E9D ; [.1C03.0020.0002.0E9D][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER FO TAM> +0EC1 0E9D ; [.1C03.0020.0002.0E9D][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER FO TAM> +0EC2 0E9D ; [.1C03.0020.0002.0E9D][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER FO TAM> +0EC3 0E9D ; [.1C03.0020.0002.0E9D][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER FO TAM> +0EC4 0E9D ; [.1C03.0020.0002.0E9D][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER FO TAM> +0E9E ; [.1C04.0020.0002.0E9E] # LAO LETTER PHO TAM +0EC0 0E9E ; [.1C04.0020.0002.0E9E][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER PHO TAM> +0EC1 0E9E ; [.1C04.0020.0002.0E9E][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER PHO TAM> +0EC2 0E9E ; [.1C04.0020.0002.0E9E][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER PHO TAM> +0EC3 0E9E ; [.1C04.0020.0002.0E9E][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER PHO TAM> +0EC4 0E9E ; [.1C04.0020.0002.0E9E][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER PHO TAM> +0E9F ; [.1C05.0020.0002.0E9F] # LAO LETTER FO SUNG +0EC0 0E9F ; [.1C05.0020.0002.0E9F][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER FO SUNG> +0EC1 0E9F ; [.1C05.0020.0002.0E9F][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER FO SUNG> +0EC2 0E9F ; [.1C05.0020.0002.0E9F][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER FO SUNG> +0EC3 0E9F ; [.1C05.0020.0002.0E9F][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER FO SUNG> +0EC4 0E9F ; [.1C05.0020.0002.0E9F][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER FO SUNG> +0EA1 ; [.1C06.0020.0002.0EA1] # LAO LETTER MO +0EC0 0EA1 ; [.1C06.0020.0002.0EA1][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER MO> +0EC1 0EA1 ; [.1C06.0020.0002.0EA1][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER MO> +0EC2 0EA1 ; [.1C06.0020.0002.0EA1][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER MO> +0EC3 0EA1 ; [.1C06.0020.0002.0EA1][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER MO> +0EC4 0EA1 ; [.1C06.0020.0002.0EA1][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER MO> +0EA2 ; [.1C07.0020.0002.0EA2] # LAO LETTER YO +0EC0 0EA2 ; [.1C07.0020.0002.0EA2][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER YO> +0EC1 0EA2 ; [.1C07.0020.0002.0EA2][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER YO> +0EC2 0EA2 ; [.1C07.0020.0002.0EA2][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER YO> +0EC3 0EA2 ; [.1C07.0020.0002.0EA2][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER YO> +0EC4 0EA2 ; [.1C07.0020.0002.0EA2][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER YO> +0EA3 ; [.1C08.0020.0002.0EA3] # LAO LETTER LO LING +0EC0 0EA3 ; [.1C08.0020.0002.0EA3][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER LO LING> +0EC1 0EA3 ; [.1C08.0020.0002.0EA3][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER LO LING> +0EC2 0EA3 ; [.1C08.0020.0002.0EA3][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER LO LING> +0EC3 0EA3 ; [.1C08.0020.0002.0EA3][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER LO LING> +0EC4 0EA3 ; [.1C08.0020.0002.0EA3][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER LO LING> +0EA5 ; [.1C09.0020.0002.0EA5] # LAO LETTER LO LOOT +0EC0 0EA5 ; [.1C09.0020.0002.0EA5][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER LO LOOT> +0EC1 0EA5 ; [.1C09.0020.0002.0EA5][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER LO LOOT> +0EC2 0EA5 ; [.1C09.0020.0002.0EA5][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER LO LOOT> +0EC3 0EA5 ; [.1C09.0020.0002.0EA5][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER LO LOOT> +0EC4 0EA5 ; [.1C09.0020.0002.0EA5][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER LO LOOT> +0EA7 ; [.1C0A.0020.0002.0EA7] # LAO LETTER WO +0EC0 0EA7 ; [.1C0A.0020.0002.0EA7][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER WO> +0EC1 0EA7 ; [.1C0A.0020.0002.0EA7][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER WO> +0EC2 0EA7 ; [.1C0A.0020.0002.0EA7][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER WO> +0EC3 0EA7 ; [.1C0A.0020.0002.0EA7][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER WO> +0EC4 0EA7 ; [.1C0A.0020.0002.0EA7][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER WO> +0EAA ; [.1C0B.0020.0002.0EAA] # LAO LETTER SO SUNG +0EC0 0EAA ; [.1C0B.0020.0002.0EAA][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER SO SUNG> +0EC1 0EAA ; [.1C0B.0020.0002.0EAA][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER SO SUNG> +0EC2 0EAA ; [.1C0B.0020.0002.0EAA][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER SO SUNG> +0EC3 0EAA ; [.1C0B.0020.0002.0EAA][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER SO SUNG> +0EC4 0EAA ; [.1C0B.0020.0002.0EAA][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER SO SUNG> +0EAB ; [.1C0C.0020.0002.0EAB] # LAO LETTER HO SUNG +0EDC ; [.1C0C.0020.0004.0EDC][.1BFF.0020.0004.0EDC] # LAO HO NO; QQKN +0EC0 0EDC ; [.1C0C.0020.0004.0EDC][.1BFF.0020.0004.0EDC][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO HO NO> +0EC1 0EDC ; [.1C0C.0020.0004.0EDC][.1BFF.0020.0004.0EDC][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO HO NO> +0EC2 0EDC ; [.1C0C.0020.0004.0EDC][.1BFF.0020.0004.0EDC][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO HO NO> +0EC3 0EDC ; [.1C0C.0020.0004.0EDC][.1BFF.0020.0004.0EDC][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO HO NO> +0EC4 0EDC ; [.1C0C.0020.0004.0EDC][.1BFF.0020.0004.0EDC][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO HO NO> +0EDD ; [.1C0C.0020.0004.0EDD][.1C06.0020.0004.0EDD] # LAO HO MO; QQKN +0EC0 0EDD ; [.1C0C.0020.0004.0EDD][.1C06.0020.0004.0EDD][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO HO MO> +0EC1 0EDD ; [.1C0C.0020.0004.0EDD][.1C06.0020.0004.0EDD][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO HO MO> +0EC2 0EDD ; [.1C0C.0020.0004.0EDD][.1C06.0020.0004.0EDD][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO HO MO> +0EC3 0EDD ; [.1C0C.0020.0004.0EDD][.1C06.0020.0004.0EDD][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO HO MO> +0EC4 0EDD ; [.1C0C.0020.0004.0EDD][.1C06.0020.0004.0EDD][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO HO MO> +0EC0 0EAB ; [.1C0C.0020.0002.0EAB][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER HO SUNG> +0EC1 0EAB ; [.1C0C.0020.0002.0EAB][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER HO SUNG> +0EC2 0EAB ; [.1C0C.0020.0002.0EAB][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER HO SUNG> +0EC3 0EAB ; [.1C0C.0020.0002.0EAB][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER HO SUNG> +0EC4 0EAB ; [.1C0C.0020.0002.0EAB][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER HO SUNG> +0EAD ; [.1C0D.0020.0002.0EAD] # LAO LETTER O +0EC0 0EAD ; [.1C0D.0020.0002.0EAD][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER O> +0EC1 0EAD ; [.1C0D.0020.0002.0EAD][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER O> +0EC2 0EAD ; [.1C0D.0020.0002.0EAD][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER O> +0EC3 0EAD ; [.1C0D.0020.0002.0EAD][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER O> +0EC4 0EAD ; [.1C0D.0020.0002.0EAD][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER O> +0EAE ; [.1C0E.0020.0002.0EAE] # LAO LETTER HO TAM +0EC0 0EAE ; [.1C0E.0020.0002.0EAE][.1C1D.0020.001F.0EC0] # <LAO VOWEL SIGN E, LAO LETTER HO TAM> +0EC1 0EAE ; [.1C0E.0020.0002.0EAE][.1C1E.0020.001F.0EC1] # <LAO VOWEL SIGN EI, LAO LETTER HO TAM> +0EC2 0EAE ; [.1C0E.0020.0002.0EAE][.1C1F.0020.001F.0EC2] # <LAO VOWEL SIGN O, LAO LETTER HO TAM> +0EC3 0EAE ; [.1C0E.0020.0002.0EAE][.1C20.0020.001F.0EC3] # <LAO VOWEL SIGN AY, LAO LETTER HO TAM> +0EC4 0EAE ; [.1C0E.0020.0002.0EAE][.1C21.0020.001F.0EC4] # <LAO VOWEL SIGN AI, LAO LETTER HO TAM> +0EAF ; [.1C0F.0020.0002.0EAF] # LAO ELLIPSIS +0EB0 ; [.1C10.0020.0002.0EB0] # LAO VOWEL SIGN A +0EB1 ; [.1C11.0020.0002.0EB1] # LAO VOWEL SIGN MAI KAN +0EB2 ; [.1C12.0020.0002.0EB2] # LAO VOWEL SIGN AA +0EB3 ; [.1C13.0020.0002.0EB3] # LAO VOWEL SIGN AM +0ECD 0EB2 ; [.1C13.0020.0002.0EB3] # LAO VOWEL SIGN AM +0EB4 ; [.1C14.0020.0002.0EB4] # LAO VOWEL SIGN I +0EB5 ; [.1C15.0020.0002.0EB5] # LAO VOWEL SIGN II +0EB6 ; [.1C16.0020.0002.0EB6] # LAO VOWEL SIGN Y +0EB7 ; [.1C17.0020.0002.0EB7] # LAO VOWEL SIGN YY +0EB8 ; [.1C18.0020.0002.0EB8] # LAO VOWEL SIGN U +0EB9 ; [.1C19.0020.0002.0EB9] # LAO VOWEL SIGN UU +0EBB ; [.1C1A.0020.0002.0EBB] # LAO VOWEL SIGN MAI KON +0EBC ; [.1C1B.0020.0002.0EBC] # LAO SEMIVOWEL SIGN LO +0EBD ; [.1C1C.0020.0002.0EBD] # LAO SEMIVOWEL SIGN NYO +0EC0 ; [.1C1D.0020.0002.0EC0] # LAO VOWEL SIGN E +0EC1 ; [.1C1E.0020.0002.0EC1] # LAO VOWEL SIGN EI +0EC2 ; [.1C1F.0020.0002.0EC2] # LAO VOWEL SIGN O +0EC3 ; [.1C20.0020.0002.0EC3] # LAO VOWEL SIGN AY +0EC4 ; [.1C21.0020.0002.0EC4] # LAO VOWEL SIGN AI +0F40 ; [.1C22.0020.0002.0F40] # TIBETAN LETTER KA +0F69 ; [.1C22.0020.0002.0F40][.1C61.0020.0002.0FB5] # TIBETAN LETTER KSSA; QQCN +0F90 ; [.1C23.0020.0002.0F90] # TIBETAN SUBJOINED LETTER KA +0FB9 ; [.1C23.0020.0002.0F90][.1C61.0020.0002.0FB5] # TIBETAN SUBJOINED LETTER KSSA; QQCN +0F41 ; [.1C24.0020.0002.0F41] # TIBETAN LETTER KHA +0F91 ; [.1C25.0020.0002.0F91] # TIBETAN SUBJOINED LETTER KHA +0F42 ; [.1C26.0020.0002.0F42] # TIBETAN LETTER GA +0F43 ; [.1C26.0020.0002.0F42][.1C65.0020.0002.0FB7] # TIBETAN LETTER GHA; QQCN +0F92 ; [.1C27.0020.0002.0F92] # TIBETAN SUBJOINED LETTER GA +0F93 ; [.1C27.0020.0002.0F92][.1C65.0020.0002.0FB7] # TIBETAN SUBJOINED LETTER GHA; QQCN +0F44 ; [.1C28.0020.0002.0F44] # TIBETAN LETTER NGA +0F94 ; [.1C29.0020.0002.0F94] # TIBETAN SUBJOINED LETTER NGA +0F45 ; [.1C2A.0020.0002.0F45] # TIBETAN LETTER CA +0F95 ; [.1C2B.0020.0002.0F95] # TIBETAN SUBJOINED LETTER CA +0F46 ; [.1C2C.0020.0002.0F46] # TIBETAN LETTER CHA +0F96 ; [.1C2D.0020.0002.0F96] # TIBETAN SUBJOINED LETTER CHA +0F47 ; [.1C2E.0020.0002.0F47] # TIBETAN LETTER JA +0F97 ; [.1C2F.0020.0002.0F97] # TIBETAN SUBJOINED LETTER JA +0F49 ; [.1C30.0020.0002.0F49] # TIBETAN LETTER NYA +0F99 ; [.1C31.0020.0002.0F99] # TIBETAN SUBJOINED LETTER NYA +0F4A ; [.1C32.0020.0002.0F4A] # TIBETAN LETTER TTA +0F9A ; [.1C33.0020.0002.0F9A] # TIBETAN SUBJOINED LETTER TTA +0F4B ; [.1C34.0020.0002.0F4B] # TIBETAN LETTER TTHA +0F9B ; [.1C35.0020.0002.0F9B] # TIBETAN SUBJOINED LETTER TTHA +0F4C ; [.1C36.0020.0002.0F4C] # TIBETAN LETTER DDA +0F4D ; [.1C36.0020.0002.0F4C][.1C65.0020.0002.0FB7] # TIBETAN LETTER DDHA; QQCN +0F9C ; [.1C37.0020.0002.0F9C] # TIBETAN SUBJOINED LETTER DDA +0F9D ; [.1C37.0020.0002.0F9C][.1C65.0020.0002.0FB7] # TIBETAN SUBJOINED LETTER DDHA; QQCN +0F4E ; [.1C38.0020.0002.0F4E] # TIBETAN LETTER NNA +0F9E ; [.1C39.0020.0002.0F9E] # TIBETAN SUBJOINED LETTER NNA +0F4F ; [.1C3A.0020.0002.0F4F] # TIBETAN LETTER TA +0F9F ; [.1C3B.0020.0002.0F9F] # TIBETAN SUBJOINED LETTER TA +0F50 ; [.1C3C.0020.0002.0F50] # TIBETAN LETTER THA +0FA0 ; [.1C3D.0020.0002.0FA0] # TIBETAN SUBJOINED LETTER THA +0F51 ; [.1C3E.0020.0002.0F51] # TIBETAN LETTER DA +0F52 ; [.1C3E.0020.0002.0F51][.1C65.0020.0002.0FB7] # TIBETAN LETTER DHA; QQCN +0FA1 ; [.1C3F.0020.0002.0FA1] # TIBETAN SUBJOINED LETTER DA +0FA2 ; [.1C3F.0020.0002.0FA1][.1C65.0020.0002.0FB7] # TIBETAN SUBJOINED LETTER DHA; QQCN +0F53 ; [.1C40.0020.0002.0F53] # TIBETAN LETTER NA +0FA3 ; [.1C41.0020.0002.0FA3] # TIBETAN SUBJOINED LETTER NA +0F54 ; [.1C42.0020.0002.0F54] # TIBETAN LETTER PA +0FA4 ; [.1C43.0020.0002.0FA4] # TIBETAN SUBJOINED LETTER PA +0F55 ; [.1C44.0020.0002.0F55] # TIBETAN LETTER PHA +0FA5 ; [.1C45.0020.0002.0FA5] # TIBETAN SUBJOINED LETTER PHA +0F56 ; [.1C46.0020.0002.0F56] # TIBETAN LETTER BA +0F57 ; [.1C46.0020.0002.0F56][.1C65.0020.0002.0FB7] # TIBETAN LETTER BHA; QQCN +0FA6 ; [.1C47.0020.0002.0FA6] # TIBETAN SUBJOINED LETTER BA +0FA7 ; [.1C47.0020.0002.0FA6][.1C65.0020.0002.0FB7] # TIBETAN SUBJOINED LETTER BHA; QQCN +0F58 ; [.1C48.0020.0002.0F58] # TIBETAN LETTER MA +0FA8 ; [.1C49.0020.0002.0FA8] # TIBETAN SUBJOINED LETTER MA +0F59 ; [.1C4A.0020.0002.0F59] # TIBETAN LETTER TSA +0FA9 ; [.1C4B.0020.0002.0FA9] # TIBETAN SUBJOINED LETTER TSA +0F5A ; [.1C4C.0020.0002.0F5A] # TIBETAN LETTER TSHA +0FAA ; [.1C4D.0020.0002.0FAA] # TIBETAN SUBJOINED LETTER TSHA +0F5B ; [.1C4E.0020.0002.0F5B] # TIBETAN LETTER DZA +0F5C ; [.1C4E.0020.0002.0F5B][.1C65.0020.0002.0FB7] # TIBETAN LETTER DZHA; QQCN +0FAB ; [.1C4F.0020.0002.0FAB] # TIBETAN SUBJOINED LETTER DZA +0FAC ; [.1C4F.0020.0002.0FAB][.1C65.0020.0002.0FB7] # TIBETAN SUBJOINED LETTER DZHA; QQCN +0F5D ; [.1C50.0020.0002.0F5D] # TIBETAN LETTER WA +0FAD ; [.1C51.0020.0002.0FAD] # TIBETAN SUBJOINED LETTER WA +0FBA ; [.1C51.0020.0004.0FBA][.0000.019A.0004.0FBA] # TIBETAN SUBJOINED LETTER FIXED-FORM WA; QQKN +0F5E ; [.1C52.0020.0002.0F5E] # TIBETAN LETTER ZHA +0FAE ; [.1C53.0020.0002.0FAE] # TIBETAN SUBJOINED LETTER ZHA +0F5F ; [.1C54.0020.0002.0F5F] # TIBETAN LETTER ZA +0FAF ; [.1C55.0020.0002.0FAF] # TIBETAN SUBJOINED LETTER ZA +0F60 ; [.1C56.0020.0002.0F60] # TIBETAN LETTER -A +0FB0 ; [.1C57.0020.0002.0FB0] # TIBETAN SUBJOINED LETTER -A +0F61 ; [.1C58.0020.0002.0F61] # TIBETAN LETTER YA +0FB1 ; [.1C59.0020.0002.0FB1] # TIBETAN SUBJOINED LETTER YA +0FBB ; [.1C59.0020.0004.0FBB][.0000.019A.0004.0FBB] # TIBETAN SUBJOINED LETTER FIXED-FORM YA; QQKN +0F62 ; [.1C5A.0020.0002.0F62] # TIBETAN LETTER RA +0F6A ; [.1C5A.0020.0004.0F6A][.0000.019A.0004.0F6A] # TIBETAN LETTER FIXED-FORM RA; QQKN +0FB2 ; [.1C5B.0020.0002.0FB2] # TIBETAN SUBJOINED LETTER RA +0FBC ; [.1C5B.0020.0004.0FBC][.0000.019A.0004.0FBC] # TIBETAN SUBJOINED LETTER FIXED-FORM RA; QQKN +0F63 ; [.1C5C.0020.0002.0F63] # TIBETAN LETTER LA +0FB3 ; [.1C5D.0020.0002.0FB3] # TIBETAN SUBJOINED LETTER LA +0F64 ; [.1C5E.0020.0002.0F64] # TIBETAN LETTER SHA +0FB4 ; [.1C5F.0020.0002.0FB4] # TIBETAN SUBJOINED LETTER SHA +0F65 ; [.1C60.0020.0002.0F65] # TIBETAN LETTER SSA +0FB5 ; [.1C61.0020.0002.0FB5] # TIBETAN SUBJOINED LETTER SSA +0F66 ; [.1C62.0020.0002.0F66] # TIBETAN LETTER SA +0FB6 ; [.1C63.0020.0002.0FB6] # TIBETAN SUBJOINED LETTER SA +0F67 ; [.1C64.0020.0002.0F67] # TIBETAN LETTER HA +0FB7 ; [.1C65.0020.0002.0FB7] # TIBETAN SUBJOINED LETTER HA +0F68 ; [.1C66.0020.0002.0F68] # TIBETAN LETTER A +0F00 ; [.1C66.0020.0004.0F00][.1C79.0020.0004.0F00][.0000.015A.001F.0F00] # TIBETAN SYLLABLE OM; QQKN +0FB8 ; [.1C67.0020.0002.0FB8] # TIBETAN SUBJOINED LETTER A +0F88 ; [.1C68.0020.0002.0F88] # TIBETAN SIGN LCE TSA CAN +0F89 ; [.1C69.0020.0002.0F89] # TIBETAN SIGN MCHU CAN +0F8A ; [.1C6A.0020.0002.0F8A] # TIBETAN SIGN GRU CAN RGYINGS +0F8B ; [.1C6B.0020.0002.0F8B] # TIBETAN SIGN GRU MED RGYINGS +0F71 ; [.1C6C.0020.0002.0F71] # TIBETAN VOWEL SIGN AA +0F72 ; [.1C6D.0020.0002.0F72] # TIBETAN VOWEL SIGN I +0F73 ; [.1C6E.0020.0002.0F73] # TIBETAN VOWEL SIGN II +0F71 0F72 ; [.1C6E.0020.0002.0F73] # TIBETAN VOWEL SIGN II +0F80 ; [.1C6F.0020.0002.0F80] # TIBETAN VOWEL SIGN REVERSED I +0F81 ; [.1C70.0020.0002.0F81] # TIBETAN VOWEL SIGN REVERSED II +0F71 0F80 ; [.1C70.0020.0002.0F81] # TIBETAN VOWEL SIGN REVERSED II +0F74 ; [.1C71.0020.0002.0F74] # TIBETAN VOWEL SIGN U +0F75 ; [.1C72.0020.0002.0F75] # TIBETAN VOWEL SIGN UU +0F71 0F74 ; [.1C72.0020.0002.0F75] # TIBETAN VOWEL SIGN UU +0F76 ; [.1C73.0020.0002.0F76] # TIBETAN VOWEL SIGN VOCALIC R +0FB2 0F80 ; [.1C73.0020.0002.0F76] # TIBETAN VOWEL SIGN VOCALIC R +0F77 ; [.1C74.0020.0002.0F77] # TIBETAN VOWEL SIGN VOCALIC RR +0FB2 0F71 0F80 ; [.1C74.0020.0002.0F77] # TIBETAN VOWEL SIGN VOCALIC RR +0FB2 0F81 ; [.1C74.0020.0002.0F77] # TIBETAN VOWEL SIGN VOCALIC RR +0F78 ; [.1C75.0020.0002.0F78] # TIBETAN VOWEL SIGN VOCALIC L +0FB3 0F80 ; [.1C75.0020.0002.0F78] # TIBETAN VOWEL SIGN VOCALIC L +0F79 ; [.1C76.0020.0002.0F79] # TIBETAN VOWEL SIGN VOCALIC LL +0FB3 0F71 0F80 ; [.1C76.0020.0002.0F79] # TIBETAN VOWEL SIGN VOCALIC LL +0FB3 0F81 ; [.1C76.0020.0002.0F79] # TIBETAN VOWEL SIGN VOCALIC LL +0F7A ; [.1C77.0020.0002.0F7A] # TIBETAN VOWEL SIGN E +0F7B ; [.1C78.0020.0002.0F7B] # TIBETAN VOWEL SIGN EE +0F7C ; [.1C79.0020.0002.0F7C] # TIBETAN VOWEL SIGN O +0F7D ; [.1C7A.0020.0002.0F7D] # TIBETAN VOWEL SIGN OO +0F84 ; [.1C7B.0020.0002.0F84] # TIBETAN MARK HALANTA +A840 ; [.1C7C.0020.0002.A840] # PHAGS-PA LETTER KA +A841 ; [.1C7D.0020.0002.A841] # PHAGS-PA LETTER KHA +A842 ; [.1C7E.0020.0002.A842] # PHAGS-PA LETTER GA +A843 ; [.1C7F.0020.0002.A843] # PHAGS-PA LETTER NGA +A844 ; [.1C80.0020.0002.A844] # PHAGS-PA LETTER CA +A845 ; [.1C81.0020.0002.A845] # PHAGS-PA LETTER CHA +A846 ; [.1C82.0020.0002.A846] # PHAGS-PA LETTER JA +A847 ; [.1C83.0020.0002.A847] # PHAGS-PA LETTER NYA +A869 ; [.1C84.0020.0002.A869] # PHAGS-PA LETTER TTA +A86A ; [.1C85.0020.0002.A86A] # PHAGS-PA LETTER TTHA +A86B ; [.1C86.0020.0002.A86B] # PHAGS-PA LETTER DDA +A86C ; [.1C87.0020.0002.A86C] # PHAGS-PA LETTER NNA +A848 ; [.1C88.0020.0002.A848] # PHAGS-PA LETTER TA +A849 ; [.1C89.0020.0002.A849] # PHAGS-PA LETTER THA +A84A ; [.1C8A.0020.0002.A84A] # PHAGS-PA LETTER DA +A84B ; [.1C8B.0020.0002.A84B] # PHAGS-PA LETTER NA +A84C ; [.1C8C.0020.0002.A84C] # PHAGS-PA LETTER PA +A84D ; [.1C8D.0020.0002.A84D] # PHAGS-PA LETTER PHA +A84E ; [.1C8E.0020.0002.A84E] # PHAGS-PA LETTER BA +A84F ; [.1C8F.0020.0002.A84F] # PHAGS-PA LETTER MA +A850 ; [.1C90.0020.0002.A850] # PHAGS-PA LETTER TSA +A851 ; [.1C91.0020.0002.A851] # PHAGS-PA LETTER TSHA +A852 ; [.1C92.0020.0002.A852] # PHAGS-PA LETTER DZA +A853 ; [.1C93.0020.0002.A853] # PHAGS-PA LETTER WA +A867 ; [.1C94.0020.0002.A867] # PHAGS-PA SUBJOINED LETTER WA +A854 ; [.1C95.0020.0002.A854] # PHAGS-PA LETTER ZHA +A855 ; [.1C96.0020.0002.A855] # PHAGS-PA LETTER ZA +A856 ; [.1C97.0020.0002.A856] # PHAGS-PA LETTER SMALL A +A857 ; [.1C98.0020.0002.A857] # PHAGS-PA LETTER YA +A868 ; [.1C99.0020.0002.A868] # PHAGS-PA SUBJOINED LETTER YA +A86D ; [.1C9A.0020.0002.A86D] # PHAGS-PA LETTER ALTERNATE YA +A858 ; [.1C9B.0020.0002.A858] # PHAGS-PA LETTER RA +A871 ; [.1C9C.0020.0002.A871] # PHAGS-PA SUBJOINED LETTER RA +A872 ; [.1C9D.0020.0002.A872] # PHAGS-PA SUPERFIXED LETTER RA +A859 ; [.1C9E.0020.0002.A859] # PHAGS-PA LETTER LA +A85A ; [.1C9F.0020.0002.A85A] # PHAGS-PA LETTER SHA +A86E ; [.1CA0.0020.0002.A86E] # PHAGS-PA LETTER VOICELESS SHA +A85B ; [.1CA1.0020.0002.A85B] # PHAGS-PA LETTER SA +A85C ; [.1CA2.0020.0002.A85C] # PHAGS-PA LETTER HA +A86F ; [.1CA3.0020.0002.A86F] # PHAGS-PA LETTER VOICED HA +A870 ; [.1CA4.0020.0002.A870] # PHAGS-PA LETTER ASPIRATED FA +A85D ; [.1CA5.0020.0002.A85D] # PHAGS-PA LETTER A +A862 ; [.1CA6.0020.0002.A862] # PHAGS-PA LETTER QA +A863 ; [.1CA7.0020.0002.A863] # PHAGS-PA LETTER XA +A864 ; [.1CA8.0020.0002.A864] # PHAGS-PA LETTER FA +A865 ; [.1CA9.0020.0002.A865] # PHAGS-PA LETTER GGA +A85E ; [.1CAA.0020.0002.A85E] # PHAGS-PA LETTER I +A85F ; [.1CAB.0020.0002.A85F] # PHAGS-PA LETTER U +A860 ; [.1CAC.0020.0002.A860] # PHAGS-PA LETTER E +A861 ; [.1CAD.0020.0002.A861] # PHAGS-PA LETTER O +A866 ; [.1CAE.0020.0002.A866] # PHAGS-PA LETTER EE +A873 ; [.1CAF.0020.0002.A873] # PHAGS-PA LETTER CANDRABINDU +1900 ; [.1CB0.0020.0002.1900] # LIMBU VOWEL-CARRIER LETTER +1901 ; [.1CB1.0020.0002.1901] # LIMBU LETTER KA +1902 ; [.1CB2.0020.0002.1902] # LIMBU LETTER KHA +1903 ; [.1CB3.0020.0002.1903] # LIMBU LETTER GA +1904 ; [.1CB4.0020.0002.1904] # LIMBU LETTER GHA +1905 ; [.1CB5.0020.0002.1905] # LIMBU LETTER NGA +1906 ; [.1CB6.0020.0002.1906] # LIMBU LETTER CA +1907 ; [.1CB7.0020.0002.1907] # LIMBU LETTER CHA +1908 ; [.1CB8.0020.0002.1908] # LIMBU LETTER JA +1909 ; [.1CB9.0020.0002.1909] # LIMBU LETTER JHA +190A ; [.1CBA.0020.0002.190A] # LIMBU LETTER YAN +190B ; [.1CBB.0020.0002.190B] # LIMBU LETTER TA +190C ; [.1CBC.0020.0002.190C] # LIMBU LETTER THA +190D ; [.1CBD.0020.0002.190D] # LIMBU LETTER DA +190E ; [.1CBE.0020.0002.190E] # LIMBU LETTER DHA +190F ; [.1CBF.0020.0002.190F] # LIMBU LETTER NA +1910 ; [.1CC0.0020.0002.1910] # LIMBU LETTER PA +1911 ; [.1CC1.0020.0002.1911] # LIMBU LETTER PHA +1912 ; [.1CC2.0020.0002.1912] # LIMBU LETTER BA +1913 ; [.1CC3.0020.0002.1913] # LIMBU LETTER BHA +1914 ; [.1CC4.0020.0002.1914] # LIMBU LETTER MA +1915 ; [.1CC5.0020.0002.1915] # LIMBU LETTER YA +1916 ; [.1CC6.0020.0002.1916] # LIMBU LETTER RA +1917 ; [.1CC7.0020.0002.1917] # LIMBU LETTER LA +1918 ; [.1CC8.0020.0002.1918] # LIMBU LETTER WA +1919 ; [.1CC9.0020.0002.1919] # LIMBU LETTER SHA +191A ; [.1CCA.0020.0002.191A] # LIMBU LETTER SSA +191B ; [.1CCB.0020.0002.191B] # LIMBU LETTER SA +191C ; [.1CCC.0020.0002.191C] # LIMBU LETTER HA +1920 ; [.1CCD.0020.0002.1920] # LIMBU VOWEL SIGN A +1921 ; [.1CCE.0020.0002.1921] # LIMBU VOWEL SIGN I +1922 ; [.1CCF.0020.0002.1922] # LIMBU VOWEL SIGN U +1923 ; [.1CD0.0020.0002.1923] # LIMBU VOWEL SIGN EE +1924 ; [.1CD1.0020.0002.1924] # LIMBU VOWEL SIGN AI +1925 ; [.1CD2.0020.0002.1925] # LIMBU VOWEL SIGN OO +1926 ; [.1CD3.0020.0002.1926] # LIMBU VOWEL SIGN AU +1927 ; [.1CD4.0020.0002.1927] # LIMBU VOWEL SIGN E +1928 ; [.1CD5.0020.0002.1928] # LIMBU VOWEL SIGN O +1929 ; [.1CD6.0020.0002.1929] # LIMBU SUBJOINED LETTER YA +192A ; [.1CD7.0020.0002.192A] # LIMBU SUBJOINED LETTER RA +192B ; [.1CD8.0020.0002.192B] # LIMBU SUBJOINED LETTER WA +1930 ; [.1CD9.0020.0002.1930] # LIMBU SMALL LETTER KA +1931 ; [.1CDA.0020.0002.1931] # LIMBU SMALL LETTER NGA +1932 ; [.1CDB.0020.0002.1932] # LIMBU SMALL LETTER ANUSVARA +1933 ; [.1CDC.0020.0002.1933] # LIMBU SMALL LETTER TA +1934 ; [.1CDD.0020.0002.1934] # LIMBU SMALL LETTER NA +1935 ; [.1CDE.0020.0002.1935] # LIMBU SMALL LETTER PA +1936 ; [.1CDF.0020.0002.1936] # LIMBU SMALL LETTER MA +1937 ; [.1CE0.0020.0002.1937] # LIMBU SMALL LETTER RA +1938 ; [.1CE1.0020.0002.1938] # LIMBU SMALL LETTER LA +1700 ; [.1CE2.0020.0002.1700] # TAGALOG LETTER A +1701 ; [.1CE3.0020.0002.1701] # TAGALOG LETTER I +1702 ; [.1CE4.0020.0002.1702] # TAGALOG LETTER U +1703 ; [.1CE5.0020.0002.1703] # TAGALOG LETTER KA +1704 ; [.1CE6.0020.0002.1704] # TAGALOG LETTER GA +1705 ; [.1CE7.0020.0002.1705] # TAGALOG LETTER NGA +1706 ; [.1CE8.0020.0002.1706] # TAGALOG LETTER TA +1707 ; [.1CE9.0020.0002.1707] # TAGALOG LETTER DA +1708 ; [.1CEA.0020.0002.1708] # TAGALOG LETTER NA +1709 ; [.1CEB.0020.0002.1709] # TAGALOG LETTER PA +170A ; [.1CEC.0020.0002.170A] # TAGALOG LETTER BA +170B ; [.1CED.0020.0002.170B] # TAGALOG LETTER MA +170C ; [.1CEE.0020.0002.170C] # TAGALOG LETTER YA +170E ; [.1CEF.0020.0002.170E] # TAGALOG LETTER LA +170F ; [.1CF0.0020.0002.170F] # TAGALOG LETTER WA +1710 ; [.1CF1.0020.0002.1710] # TAGALOG LETTER SA +1711 ; [.1CF2.0020.0002.1711] # TAGALOG LETTER HA +1712 ; [.1CF3.0020.0002.1712] # TAGALOG VOWEL SIGN I +1713 ; [.1CF4.0020.0002.1713] # TAGALOG VOWEL SIGN U +1714 ; [.1CF5.0020.0002.1714] # TAGALOG SIGN VIRAMA +1720 ; [.1CF6.0020.0002.1720] # HANUNOO LETTER A +1721 ; [.1CF7.0020.0002.1721] # HANUNOO LETTER I +1722 ; [.1CF8.0020.0002.1722] # HANUNOO LETTER U +1723 ; [.1CF9.0020.0002.1723] # HANUNOO LETTER KA +1724 ; [.1CFA.0020.0002.1724] # HANUNOO LETTER GA +1725 ; [.1CFB.0020.0002.1725] # HANUNOO LETTER NGA +1726 ; [.1CFC.0020.0002.1726] # HANUNOO LETTER TA +1727 ; [.1CFD.0020.0002.1727] # HANUNOO LETTER DA +1728 ; [.1CFE.0020.0002.1728] # HANUNOO LETTER NA +1729 ; [.1CFF.0020.0002.1729] # HANUNOO LETTER PA +172A ; [.1D00.0020.0002.172A] # HANUNOO LETTER BA +172B ; [.1D01.0020.0002.172B] # HANUNOO LETTER MA +172C ; [.1D02.0020.0002.172C] # HANUNOO LETTER YA +172D ; [.1D03.0020.0002.172D] # HANUNOO LETTER RA +172E ; [.1D04.0020.0002.172E] # HANUNOO LETTER LA +172F ; [.1D05.0020.0002.172F] # HANUNOO LETTER WA +1730 ; [.1D06.0020.0002.1730] # HANUNOO LETTER SA +1731 ; [.1D07.0020.0002.1731] # HANUNOO LETTER HA +1732 ; [.1D08.0020.0002.1732] # HANUNOO VOWEL SIGN I +1733 ; [.1D09.0020.0002.1733] # HANUNOO VOWEL SIGN U +1734 ; [.1D0A.0020.0002.1734] # HANUNOO SIGN PAMUDPOD +1740 ; [.1D0B.0020.0002.1740] # BUHID LETTER A +1741 ; [.1D0C.0020.0002.1741] # BUHID LETTER I +1742 ; [.1D0D.0020.0002.1742] # BUHID LETTER U +1743 ; [.1D0E.0020.0002.1743] # BUHID LETTER KA +1744 ; [.1D0F.0020.0002.1744] # BUHID LETTER GA +1745 ; [.1D10.0020.0002.1745] # BUHID LETTER NGA +1746 ; [.1D11.0020.0002.1746] # BUHID LETTER TA +1747 ; [.1D12.0020.0002.1747] # BUHID LETTER DA +1748 ; [.1D13.0020.0002.1748] # BUHID LETTER NA +1749 ; [.1D14.0020.0002.1749] # BUHID LETTER PA +174A ; [.1D15.0020.0002.174A] # BUHID LETTER BA +174B ; [.1D16.0020.0002.174B] # BUHID LETTER MA +174C ; [.1D17.0020.0002.174C] # BUHID LETTER YA +174D ; [.1D18.0020.0002.174D] # BUHID LETTER RA +174E ; [.1D19.0020.0002.174E] # BUHID LETTER LA +174F ; [.1D1A.0020.0002.174F] # BUHID LETTER WA +1750 ; [.1D1B.0020.0002.1750] # BUHID LETTER SA +1751 ; [.1D1C.0020.0002.1751] # BUHID LETTER HA +1752 ; [.1D1D.0020.0002.1752] # BUHID VOWEL SIGN I +1753 ; [.1D1E.0020.0002.1753] # BUHID VOWEL SIGN U +1760 ; [.1D1F.0020.0002.1760] # TAGBANWA LETTER A +1761 ; [.1D20.0020.0002.1761] # TAGBANWA LETTER I +1762 ; [.1D21.0020.0002.1762] # TAGBANWA LETTER U +1763 ; [.1D22.0020.0002.1763] # TAGBANWA LETTER KA +1764 ; [.1D23.0020.0002.1764] # TAGBANWA LETTER GA +1765 ; [.1D24.0020.0002.1765] # TAGBANWA LETTER NGA +1766 ; [.1D25.0020.0002.1766] # TAGBANWA LETTER TA +1767 ; [.1D26.0020.0002.1767] # TAGBANWA LETTER DA +1768 ; [.1D27.0020.0002.1768] # TAGBANWA LETTER NA +1769 ; [.1D28.0020.0002.1769] # TAGBANWA LETTER PA +176A ; [.1D29.0020.0002.176A] # TAGBANWA LETTER BA +176B ; [.1D2A.0020.0002.176B] # TAGBANWA LETTER MA +176C ; [.1D2B.0020.0002.176C] # TAGBANWA LETTER YA +176E ; [.1D2C.0020.0002.176E] # TAGBANWA LETTER LA +176F ; [.1D2D.0020.0002.176F] # TAGBANWA LETTER WA +1770 ; [.1D2E.0020.0002.1770] # TAGBANWA LETTER SA +1772 ; [.1D2F.0020.0002.1772] # TAGBANWA VOWEL SIGN I +1773 ; [.1D30.0020.0002.1773] # TAGBANWA VOWEL SIGN U +1A00 ; [.1D31.0020.0002.1A00] # BUGINESE LETTER KA +1A01 ; [.1D32.0020.0002.1A01] # BUGINESE LETTER GA +1A02 ; [.1D33.0020.0002.1A02] # BUGINESE LETTER NGA +1A03 ; [.1D34.0020.0002.1A03] # BUGINESE LETTER NGKA +1A04 ; [.1D35.0020.0002.1A04] # BUGINESE LETTER PA +1A05 ; [.1D36.0020.0002.1A05] # BUGINESE LETTER BA +1A06 ; [.1D37.0020.0002.1A06] # BUGINESE LETTER MA +1A07 ; [.1D38.0020.0002.1A07] # BUGINESE LETTER MPA +1A08 ; [.1D39.0020.0002.1A08] # BUGINESE LETTER TA +1A09 ; [.1D3A.0020.0002.1A09] # BUGINESE LETTER DA +1A0A ; [.1D3B.0020.0002.1A0A] # BUGINESE LETTER NA +1A0B ; [.1D3C.0020.0002.1A0B] # BUGINESE LETTER NRA +1A0C ; [.1D3D.0020.0002.1A0C] # BUGINESE LETTER CA +1A0D ; [.1D3E.0020.0002.1A0D] # BUGINESE LETTER JA +1A0E ; [.1D3F.0020.0002.1A0E] # BUGINESE LETTER NYA +1A0F ; [.1D40.0020.0002.1A0F] # BUGINESE LETTER NYCA +1A10 ; [.1D41.0020.0002.1A10] # BUGINESE LETTER YA +1A11 ; [.1D42.0020.0002.1A11] # BUGINESE LETTER RA +1A12 ; [.1D43.0020.0002.1A12] # BUGINESE LETTER LA +1A13 ; [.1D44.0020.0002.1A13] # BUGINESE LETTER VA +1A14 ; [.1D45.0020.0002.1A14] # BUGINESE LETTER SA +1A15 ; [.1D46.0020.0002.1A15] # BUGINESE LETTER A +1A16 ; [.1D47.0020.0002.1A16] # BUGINESE LETTER HA +1A17 ; [.1D48.0020.0002.1A17] # BUGINESE VOWEL SIGN I +1A18 ; [.1D49.0020.0002.1A18] # BUGINESE VOWEL SIGN U +1A19 ; [.1D4A.0020.0002.1A19] # BUGINESE VOWEL SIGN E +1A1A ; [.1D4B.0020.0002.1A1A] # BUGINESE VOWEL SIGN O +1A1B ; [.1D4C.0020.0002.1A1B] # BUGINESE VOWEL SIGN AE +1000 ; [.1D4D.0020.0002.1000] # MYANMAR LETTER KA +1001 ; [.1D4E.0020.0002.1001] # MYANMAR LETTER KHA +1002 ; [.1D4F.0020.0002.1002] # MYANMAR LETTER GA +1003 ; [.1D50.0020.0002.1003] # MYANMAR LETTER GHA +1004 ; [.1D51.0020.0002.1004] # MYANMAR LETTER NGA +1005 ; [.1D52.0020.0002.1005] # MYANMAR LETTER CA +1006 ; [.1D53.0020.0002.1006] # MYANMAR LETTER CHA +1007 ; [.1D54.0020.0002.1007] # MYANMAR LETTER JA +1008 ; [.1D55.0020.0002.1008] # MYANMAR LETTER JHA +1009 ; [.1D56.0020.0002.1009] # MYANMAR LETTER NYA +100A ; [.1D57.0020.0002.100A] # MYANMAR LETTER NNYA +100B ; [.1D58.0020.0002.100B] # MYANMAR LETTER TTA +100C ; [.1D59.0020.0002.100C] # MYANMAR LETTER TTHA +100D ; [.1D5A.0020.0002.100D] # MYANMAR LETTER DDA +100E ; [.1D5B.0020.0002.100E] # MYANMAR LETTER DDHA +100F ; [.1D5C.0020.0002.100F] # MYANMAR LETTER NNA +1010 ; [.1D5D.0020.0002.1010] # MYANMAR LETTER TA +1011 ; [.1D5E.0020.0002.1011] # MYANMAR LETTER THA +1012 ; [.1D5F.0020.0002.1012] # MYANMAR LETTER DA +1013 ; [.1D60.0020.0002.1013] # MYANMAR LETTER DHA +1014 ; [.1D61.0020.0002.1014] # MYANMAR LETTER NA +1015 ; [.1D62.0020.0002.1015] # MYANMAR LETTER PA +1016 ; [.1D63.0020.0002.1016] # MYANMAR LETTER PHA +1017 ; [.1D64.0020.0002.1017] # MYANMAR LETTER BA +1018 ; [.1D65.0020.0002.1018] # MYANMAR LETTER BHA +1019 ; [.1D66.0020.0002.1019] # MYANMAR LETTER MA +101A ; [.1D67.0020.0002.101A] # MYANMAR LETTER YA +101B ; [.1D68.0020.0002.101B] # MYANMAR LETTER RA +101C ; [.1D69.0020.0002.101C] # MYANMAR LETTER LA +101D ; [.1D6A.0020.0002.101D] # MYANMAR LETTER WA +1050 ; [.1D6B.0020.0002.1050] # MYANMAR LETTER SHA +1051 ; [.1D6C.0020.0002.1051] # MYANMAR LETTER SSA +101E ; [.1D6D.0020.0002.101E] # MYANMAR LETTER SA +101F ; [.1D6E.0020.0002.101F] # MYANMAR LETTER HA +1020 ; [.1D6F.0020.0002.1020] # MYANMAR LETTER LLA +1021 ; [.1D70.0020.0002.1021] # MYANMAR LETTER A +1023 ; [.1D71.0020.0002.1023] # MYANMAR LETTER I +1024 ; [.1D72.0020.0002.1024] # MYANMAR LETTER II +1025 ; [.1D73.0020.0002.1025] # MYANMAR LETTER U +1026 ; [.1D74.0020.0002.1026] # MYANMAR LETTER UU +1025 102E ; [.1D74.0020.0002.1026] # MYANMAR LETTER UU +1027 ; [.1D75.0020.0002.1027] # MYANMAR LETTER E +1029 ; [.1D76.0020.0002.1029] # MYANMAR LETTER O +102A ; [.1D77.0020.0002.102A] # MYANMAR LETTER AU +1052 ; [.1D78.0020.0002.1052] # MYANMAR LETTER VOCALIC R +1053 ; [.1D79.0020.0002.1053] # MYANMAR LETTER VOCALIC RR +1054 ; [.1D7A.0020.0002.1054] # MYANMAR LETTER VOCALIC L +1055 ; [.1D7B.0020.0002.1055] # MYANMAR LETTER VOCALIC LL +102C ; [.1D7C.0020.0002.102C] # MYANMAR VOWEL SIGN AA +102D ; [.1D7D.0020.0002.102D] # MYANMAR VOWEL SIGN I +102E ; [.1D7E.0020.0002.102E] # MYANMAR VOWEL SIGN II +102F ; [.1D7F.0020.0002.102F] # MYANMAR VOWEL SIGN U +1030 ; [.1D80.0020.0002.1030] # MYANMAR VOWEL SIGN UU +1031 ; [.1D81.0020.0002.1031] # MYANMAR VOWEL SIGN E +1032 ; [.1D82.0020.0002.1032] # MYANMAR VOWEL SIGN AI +1056 ; [.1D83.0020.0002.1056] # MYANMAR VOWEL SIGN VOCALIC R +1057 ; [.1D84.0020.0002.1057] # MYANMAR VOWEL SIGN VOCALIC RR +1058 ; [.1D85.0020.0002.1058] # MYANMAR VOWEL SIGN VOCALIC L +1059 ; [.1D86.0020.0002.1059] # MYANMAR VOWEL SIGN VOCALIC LL +1039 ; [.1D87.0020.0002.1039] # MYANMAR SIGN VIRAMA +1780 ; [.1D88.0020.0002.1780] # KHMER LETTER KA +1781 ; [.1D89.0020.0002.1781] # KHMER LETTER KHA +1782 ; [.1D8A.0020.0002.1782] # KHMER LETTER KO +1783 ; [.1D8B.0020.0002.1783] # KHMER LETTER KHO +1784 ; [.1D8C.0020.0002.1784] # KHMER LETTER NGO +1785 ; [.1D8D.0020.0002.1785] # KHMER LETTER CA +1786 ; [.1D8E.0020.0002.1786] # KHMER LETTER CHA +1787 ; [.1D8F.0020.0002.1787] # KHMER LETTER CO +1788 ; [.1D90.0020.0002.1788] # KHMER LETTER CHO +1789 ; [.1D91.0020.0002.1789] # KHMER LETTER NYO +178A ; [.1D92.0020.0002.178A] # KHMER LETTER DA +178B ; [.1D93.0020.0002.178B] # KHMER LETTER TTHA +178C ; [.1D94.0020.0002.178C] # KHMER LETTER DO +178D ; [.1D95.0020.0002.178D] # KHMER LETTER TTHO +178E ; [.1D96.0020.0002.178E] # KHMER LETTER NNO +178F ; [.1D97.0020.0002.178F] # KHMER LETTER TA +1790 ; [.1D98.0020.0002.1790] # KHMER LETTER THA +1791 ; [.1D99.0020.0002.1791] # KHMER LETTER TO +1792 ; [.1D9A.0020.0002.1792] # KHMER LETTER THO +1793 ; [.1D9B.0020.0002.1793] # KHMER LETTER NO +1794 ; [.1D9C.0020.0002.1794] # KHMER LETTER BA +1795 ; [.1D9D.0020.0002.1795] # KHMER LETTER PHA +1796 ; [.1D9E.0020.0002.1796] # KHMER LETTER PO +1797 ; [.1D9F.0020.0002.1797] # KHMER LETTER PHO +1798 ; [.1DA0.0020.0002.1798] # KHMER LETTER MO +1799 ; [.1DA1.0020.0002.1799] # KHMER LETTER YO +179A ; [.1DA2.0020.0002.179A] # KHMER LETTER RO +179B ; [.1DA3.0020.0002.179B] # KHMER LETTER LO +179C ; [.1DA4.0020.0002.179C] # KHMER LETTER VO +179D ; [.1DA5.0020.0002.179D] # KHMER LETTER SHA +179E ; [.1DA6.0020.0002.179E] # KHMER LETTER SSO +179F ; [.1DA7.0020.0002.179F] # KHMER LETTER SA +17A0 ; [.1DA8.0020.0002.17A0] # KHMER LETTER HA +17A1 ; [.1DA9.0020.0002.17A1] # KHMER LETTER LA +17A2 ; [.1DAA.0020.0002.17A2] # KHMER LETTER QA +17DC ; [.1DAB.0020.0002.17DC] # KHMER SIGN AVAKRAHASANYA +17A3 ; [.1DAC.0020.0002.17A3] # KHMER INDEPENDENT VOWEL QAQ +17A4 ; [.1DAD.0020.0002.17A4] # KHMER INDEPENDENT VOWEL QAA +17A5 ; [.1DAE.0020.0002.17A5] # KHMER INDEPENDENT VOWEL QI +17A6 ; [.1DAF.0020.0002.17A6] # KHMER INDEPENDENT VOWEL QII +17A7 ; [.1DB0.0020.0002.17A7] # KHMER INDEPENDENT VOWEL QU +17A8 ; [.1DB1.0020.0002.17A8] # KHMER INDEPENDENT VOWEL QUK +17A9 ; [.1DB2.0020.0002.17A9] # KHMER INDEPENDENT VOWEL QUU +17AA ; [.1DB3.0020.0002.17AA] # KHMER INDEPENDENT VOWEL QUUV +17AB ; [.1DB4.0020.0002.17AB] # KHMER INDEPENDENT VOWEL RY +17AC ; [.1DB5.0020.0002.17AC] # KHMER INDEPENDENT VOWEL RYY +17AD ; [.1DB6.0020.0002.17AD] # KHMER INDEPENDENT VOWEL LY +17AE ; [.1DB7.0020.0002.17AE] # KHMER INDEPENDENT VOWEL LYY +17AF ; [.1DB8.0020.0002.17AF] # KHMER INDEPENDENT VOWEL QE +17B0 ; [.1DB9.0020.0002.17B0] # KHMER INDEPENDENT VOWEL QAI +17B1 ; [.1DBA.0020.0002.17B1] # KHMER INDEPENDENT VOWEL QOO TYPE ONE +17B2 ; [.1DBB.0020.0002.17B2] # KHMER INDEPENDENT VOWEL QOO TYPE TWO +17B3 ; [.1DBC.0020.0002.17B3] # KHMER INDEPENDENT VOWEL QAU +17B4 ; [.1DBD.0020.0002.17B4] # KHMER VOWEL INHERENT AQ +17B5 ; [.1DBE.0020.0002.17B5] # KHMER VOWEL INHERENT AA +17B6 ; [.1DBF.0020.0002.17B6] # KHMER VOWEL SIGN AA +17B7 ; [.1DC0.0020.0002.17B7] # KHMER VOWEL SIGN I +17B8 ; [.1DC1.0020.0002.17B8] # KHMER VOWEL SIGN II +17B9 ; [.1DC2.0020.0002.17B9] # KHMER VOWEL SIGN Y +17BA ; [.1DC3.0020.0002.17BA] # KHMER VOWEL SIGN YY +17BB ; [.1DC4.0020.0002.17BB] # KHMER VOWEL SIGN U +17BC ; [.1DC5.0020.0002.17BC] # KHMER VOWEL SIGN UU +17BD ; [.1DC6.0020.0002.17BD] # KHMER VOWEL SIGN UA +17BE ; [.1DC7.0020.0002.17BE] # KHMER VOWEL SIGN OE +17BF ; [.1DC8.0020.0002.17BF] # KHMER VOWEL SIGN YA +17C0 ; [.1DC9.0020.0002.17C0] # KHMER VOWEL SIGN IE +17C1 ; [.1DCA.0020.0002.17C1] # KHMER VOWEL SIGN E +17C2 ; [.1DCB.0020.0002.17C2] # KHMER VOWEL SIGN AE +17C3 ; [.1DCC.0020.0002.17C3] # KHMER VOWEL SIGN AI +17C4 ; [.1DCD.0020.0002.17C4] # KHMER VOWEL SIGN OO +17C5 ; [.1DCE.0020.0002.17C5] # KHMER VOWEL SIGN AU +17D2 ; [.1DCF.0020.0002.17D2] # KHMER SIGN COENG +1950 ; [.1DD0.0020.0002.1950] # TAI LE LETTER KA +1951 ; [.1DD1.0020.0002.1951] # TAI LE LETTER XA +1952 ; [.1DD2.0020.0002.1952] # TAI LE LETTER NGA +1953 ; [.1DD3.0020.0002.1953] # TAI LE LETTER TSA +1954 ; [.1DD4.0020.0002.1954] # TAI LE LETTER SA +1955 ; [.1DD5.0020.0002.1955] # TAI LE LETTER YA +1956 ; [.1DD6.0020.0002.1956] # TAI LE LETTER TA +1957 ; [.1DD7.0020.0002.1957] # TAI LE LETTER THA +1958 ; [.1DD8.0020.0002.1958] # TAI LE LETTER LA +1959 ; [.1DD9.0020.0002.1959] # TAI LE LETTER PA +195A ; [.1DDA.0020.0002.195A] # TAI LE LETTER PHA +195B ; [.1DDB.0020.0002.195B] # TAI LE LETTER MA +195C ; [.1DDC.0020.0002.195C] # TAI LE LETTER FA +195D ; [.1DDD.0020.0002.195D] # TAI LE LETTER VA +195E ; [.1DDE.0020.0002.195E] # TAI LE LETTER HA +195F ; [.1DDF.0020.0002.195F] # TAI LE LETTER QA +1960 ; [.1DE0.0020.0002.1960] # TAI LE LETTER KHA +1961 ; [.1DE1.0020.0002.1961] # TAI LE LETTER TSHA +1962 ; [.1DE2.0020.0002.1962] # TAI LE LETTER NA +1963 ; [.1DE3.0020.0002.1963] # TAI LE LETTER A +1964 ; [.1DE4.0020.0002.1964] # TAI LE LETTER I +1965 ; [.1DE5.0020.0002.1965] # TAI LE LETTER EE +1966 ; [.1DE6.0020.0002.1966] # TAI LE LETTER EH +1967 ; [.1DE7.0020.0002.1967] # TAI LE LETTER U +1968 ; [.1DE8.0020.0002.1968] # TAI LE LETTER OO +1969 ; [.1DE9.0020.0002.1969] # TAI LE LETTER O +196A ; [.1DEA.0020.0002.196A] # TAI LE LETTER UE +196B ; [.1DEB.0020.0002.196B] # TAI LE LETTER E +196C ; [.1DEC.0020.0002.196C] # TAI LE LETTER AUE +196D ; [.1DED.0020.0002.196D] # TAI LE LETTER AI +1970 ; [.1DEE.0020.0002.1970] # TAI LE LETTER TONE-2 +1971 ; [.1DEF.0020.0002.1971] # TAI LE LETTER TONE-3 +1972 ; [.1DF0.0020.0002.1972] # TAI LE LETTER TONE-4 +1973 ; [.1DF1.0020.0002.1973] # TAI LE LETTER TONE-5 +1974 ; [.1DF2.0020.0002.1974] # TAI LE LETTER TONE-6 +1980 ; [.1DF3.0020.0002.1980] # NEW TAI LUE LETTER HIGH QA +1981 ; [.1DF4.0020.0002.1981] # NEW TAI LUE LETTER LOW QA +1982 ; [.1DF5.0020.0002.1982] # NEW TAI LUE LETTER HIGH KA +1983 ; [.1DF6.0020.0002.1983] # NEW TAI LUE LETTER HIGH XA +1984 ; [.1DF7.0020.0002.1984] # NEW TAI LUE LETTER HIGH NGA +1985 ; [.1DF8.0020.0002.1985] # NEW TAI LUE LETTER LOW KA +1986 ; [.1DF9.0020.0002.1986] # NEW TAI LUE LETTER LOW XA +1987 ; [.1DFA.0020.0002.1987] # NEW TAI LUE LETTER LOW NGA +1988 ; [.1DFB.0020.0002.1988] # NEW TAI LUE LETTER HIGH TSA +1989 ; [.1DFC.0020.0002.1989] # NEW TAI LUE LETTER HIGH SA +198A ; [.1DFD.0020.0002.198A] # NEW TAI LUE LETTER HIGH YA +198B ; [.1DFE.0020.0002.198B] # NEW TAI LUE LETTER LOW TSA +198C ; [.1DFF.0020.0002.198C] # NEW TAI LUE LETTER LOW SA +198D ; [.1E00.0020.0002.198D] # NEW TAI LUE LETTER LOW YA +198E ; [.1E01.0020.0002.198E] # NEW TAI LUE LETTER HIGH TA +198F ; [.1E02.0020.0002.198F] # NEW TAI LUE LETTER HIGH THA +1990 ; [.1E03.0020.0002.1990] # NEW TAI LUE LETTER HIGH NA +1991 ; [.1E04.0020.0002.1991] # NEW TAI LUE LETTER LOW TA +1992 ; [.1E05.0020.0002.1992] # NEW TAI LUE LETTER LOW THA +1993 ; [.1E06.0020.0002.1993] # NEW TAI LUE LETTER LOW NA +1994 ; [.1E07.0020.0002.1994] # NEW TAI LUE LETTER HIGH PA +1995 ; [.1E08.0020.0002.1995] # NEW TAI LUE LETTER HIGH PHA +1996 ; [.1E09.0020.0002.1996] # NEW TAI LUE LETTER HIGH MA +1997 ; [.1E0A.0020.0002.1997] # NEW TAI LUE LETTER LOW PA +1998 ; [.1E0B.0020.0002.1998] # NEW TAI LUE LETTER LOW PHA +1999 ; [.1E0C.0020.0002.1999] # NEW TAI LUE LETTER LOW MA +199A ; [.1E0D.0020.0002.199A] # NEW TAI LUE LETTER HIGH FA +199B ; [.1E0E.0020.0002.199B] # NEW TAI LUE LETTER HIGH VA +199C ; [.1E0F.0020.0002.199C] # NEW TAI LUE LETTER HIGH LA +19DE ; [.1E0F.0020.0004.19DE][.1E23.0020.0004.19DE] # NEW TAI LUE SIGN LAE; QQKN +19DF ; [.1E0F.0020.0004.19DF][.1E23.0020.0004.19DF][.1E2E.0020.001F.19DF] # NEW TAI LUE SIGN LAEV; QQKN +199D ; [.1E10.0020.0002.199D] # NEW TAI LUE LETTER LOW FA +199E ; [.1E11.0020.0002.199E] # NEW TAI LUE LETTER LOW VA +199F ; [.1E12.0020.0002.199F] # NEW TAI LUE LETTER LOW LA +19A0 ; [.1E13.0020.0002.19A0] # NEW TAI LUE LETTER HIGH HA +19A1 ; [.1E14.0020.0002.19A1] # NEW TAI LUE LETTER HIGH DA +19A2 ; [.1E15.0020.0002.19A2] # NEW TAI LUE LETTER HIGH BA +19A3 ; [.1E16.0020.0002.19A3] # NEW TAI LUE LETTER LOW HA +19A4 ; [.1E17.0020.0002.19A4] # NEW TAI LUE LETTER LOW DA +19A5 ; [.1E18.0020.0002.19A5] # NEW TAI LUE LETTER LOW BA +19A6 ; [.1E19.0020.0002.19A6] # NEW TAI LUE LETTER HIGH KVA +19A7 ; [.1E1A.0020.0002.19A7] # NEW TAI LUE LETTER HIGH XVA +19A8 ; [.1E1B.0020.0002.19A8] # NEW TAI LUE LETTER LOW KVA +19A9 ; [.1E1C.0020.0002.19A9] # NEW TAI LUE LETTER LOW XVA +19B0 ; [.1E1D.0020.0002.19B0] # NEW TAI LUE VOWEL SIGN VOWEL SHORTENER +19B1 ; [.1E1E.0020.0002.19B1] # NEW TAI LUE VOWEL SIGN AA +19B2 ; [.1E1F.0020.0002.19B2] # NEW TAI LUE VOWEL SIGN II +19B3 ; [.1E20.0020.0002.19B3] # NEW TAI LUE VOWEL SIGN U +19B4 ; [.1E21.0020.0002.19B4] # NEW TAI LUE VOWEL SIGN UU +19B5 ; [.1E22.0020.0002.19B5] # NEW TAI LUE VOWEL SIGN E +19B6 ; [.1E23.0020.0002.19B6] # NEW TAI LUE VOWEL SIGN AE +19B7 ; [.1E24.0020.0002.19B7] # NEW TAI LUE VOWEL SIGN O +19B8 ; [.1E25.0020.0002.19B8] # NEW TAI LUE VOWEL SIGN OA +19B9 ; [.1E26.0020.0002.19B9] # NEW TAI LUE VOWEL SIGN UE +19BA ; [.1E27.0020.0002.19BA] # NEW TAI LUE VOWEL SIGN AY +19BB ; [.1E28.0020.0002.19BB] # NEW TAI LUE VOWEL SIGN AAY +19BC ; [.1E29.0020.0002.19BC] # NEW TAI LUE VOWEL SIGN UY +19BD ; [.1E2A.0020.0002.19BD] # NEW TAI LUE VOWEL SIGN OY +19BE ; [.1E2B.0020.0002.19BE] # NEW TAI LUE VOWEL SIGN OAY +19BF ; [.1E2C.0020.0002.19BF] # NEW TAI LUE VOWEL SIGN UEY +19C0 ; [.1E2D.0020.0002.19C0] # NEW TAI LUE VOWEL SIGN IY +19C1 ; [.1E2E.0020.0002.19C1] # NEW TAI LUE LETTER FINAL V +19C2 ; [.1E2F.0020.0002.19C2] # NEW TAI LUE LETTER FINAL NG +19C3 ; [.1E30.0020.0002.19C3] # NEW TAI LUE LETTER FINAL N +19C4 ; [.1E31.0020.0002.19C4] # NEW TAI LUE LETTER FINAL M +19C5 ; [.1E32.0020.0002.19C5] # NEW TAI LUE LETTER FINAL K +19C6 ; [.1E33.0020.0002.19C6] # NEW TAI LUE LETTER FINAL D +19C7 ; [.1E34.0020.0002.19C7] # NEW TAI LUE LETTER FINAL B +19C8 ; [.1E35.0020.0002.19C8] # NEW TAI LUE TONE MARK-1 +19C9 ; [.1E36.0020.0002.19C9] # NEW TAI LUE TONE MARK-2 +1B05 ; [.1E37.0020.0002.1B05] # BALINESE LETTER AKARA +1B06 ; [.1E38.0020.0002.1B06] # BALINESE LETTER AKARA TEDUNG +1B05 1B35 ; [.1E38.0020.0002.1B06] # BALINESE LETTER AKARA TEDUNG +1B07 ; [.1E39.0020.0002.1B07] # BALINESE LETTER IKARA +1B08 ; [.1E3A.0020.0002.1B08] # BALINESE LETTER IKARA TEDUNG +1B07 1B35 ; [.1E3A.0020.0002.1B08] # BALINESE LETTER IKARA TEDUNG +1B09 ; [.1E3B.0020.0002.1B09] # BALINESE LETTER UKARA +1B0A ; [.1E3C.0020.0002.1B0A] # BALINESE LETTER UKARA TEDUNG +1B09 1B35 ; [.1E3C.0020.0002.1B0A] # BALINESE LETTER UKARA TEDUNG +1B0B ; [.1E3D.0020.0002.1B0B] # BALINESE LETTER RA REPA +1B0C ; [.1E3E.0020.0002.1B0C] # BALINESE LETTER RA REPA TEDUNG +1B0B 1B35 ; [.1E3E.0020.0002.1B0C] # BALINESE LETTER RA REPA TEDUNG +1B0D ; [.1E3F.0020.0002.1B0D] # BALINESE LETTER LA LENGA +1B0E ; [.1E40.0020.0002.1B0E] # BALINESE LETTER LA LENGA TEDUNG +1B0D 1B35 ; [.1E40.0020.0002.1B0E] # BALINESE LETTER LA LENGA TEDUNG +1B0F ; [.1E41.0020.0002.1B0F] # BALINESE LETTER EKARA +1B10 ; [.1E42.0020.0002.1B10] # BALINESE LETTER AIKARA +1B11 ; [.1E43.0020.0002.1B11] # BALINESE LETTER OKARA +1B12 ; [.1E44.0020.0002.1B12] # BALINESE LETTER OKARA TEDUNG +1B11 1B35 ; [.1E44.0020.0002.1B12] # BALINESE LETTER OKARA TEDUNG +1B13 ; [.1E45.0020.0002.1B13] # BALINESE LETTER KA +1B45 ; [.1E46.0020.0002.1B45] # BALINESE LETTER KAF SASAK +1B46 ; [.1E47.0020.0002.1B46] # BALINESE LETTER KHOT SASAK +1B14 ; [.1E48.0020.0002.1B14] # BALINESE LETTER KA MAHAPRANA +1B15 ; [.1E49.0020.0002.1B15] # BALINESE LETTER GA +1B16 ; [.1E4A.0020.0002.1B16] # BALINESE LETTER GA GORA +1B17 ; [.1E4B.0020.0002.1B17] # BALINESE LETTER NGA +1B18 ; [.1E4C.0020.0002.1B18] # BALINESE LETTER CA +1B19 ; [.1E4D.0020.0002.1B19] # BALINESE LETTER CA LACA +1B1A ; [.1E4E.0020.0002.1B1A] # BALINESE LETTER JA +1B1B ; [.1E4F.0020.0002.1B1B] # BALINESE LETTER JA JERA +1B1C ; [.1E50.0020.0002.1B1C] # BALINESE LETTER NYA +1B1D ; [.1E51.0020.0002.1B1D] # BALINESE LETTER TA LATIK +1B1E ; [.1E52.0020.0002.1B1E] # BALINESE LETTER TA MURDA MAHAPRANA +1B1F ; [.1E53.0020.0002.1B1F] # BALINESE LETTER DA MURDA ALPAPRANA +1B20 ; [.1E54.0020.0002.1B20] # BALINESE LETTER DA MURDA MAHAPRANA +1B21 ; [.1E55.0020.0002.1B21] # BALINESE LETTER NA RAMBAT +1B22 ; [.1E56.0020.0002.1B22] # BALINESE LETTER TA +1B47 ; [.1E57.0020.0002.1B47] # BALINESE LETTER TZIR SASAK +1B23 ; [.1E58.0020.0002.1B23] # BALINESE LETTER TA TAWA +1B24 ; [.1E59.0020.0002.1B24] # BALINESE LETTER DA +1B25 ; [.1E5A.0020.0002.1B25] # BALINESE LETTER DA MADU +1B26 ; [.1E5B.0020.0002.1B26] # BALINESE LETTER NA +1B27 ; [.1E5C.0020.0002.1B27] # BALINESE LETTER PA +1B48 ; [.1E5D.0020.0002.1B48] # BALINESE LETTER EF SASAK +1B28 ; [.1E5E.0020.0002.1B28] # BALINESE LETTER PA KAPAL +1B29 ; [.1E5F.0020.0002.1B29] # BALINESE LETTER BA +1B2A ; [.1E60.0020.0002.1B2A] # BALINESE LETTER BA KEMBANG +1B2B ; [.1E61.0020.0002.1B2B] # BALINESE LETTER MA +1B2C ; [.1E62.0020.0002.1B2C] # BALINESE LETTER YA +1B2D ; [.1E63.0020.0002.1B2D] # BALINESE LETTER RA +1B2E ; [.1E64.0020.0002.1B2E] # BALINESE LETTER LA +1B2F ; [.1E65.0020.0002.1B2F] # BALINESE LETTER WA +1B49 ; [.1E66.0020.0002.1B49] # BALINESE LETTER VE SASAK +1B30 ; [.1E67.0020.0002.1B30] # BALINESE LETTER SA SAGA +1B31 ; [.1E68.0020.0002.1B31] # BALINESE LETTER SA SAPA +1B32 ; [.1E69.0020.0002.1B32] # BALINESE LETTER SA +1B4A ; [.1E6A.0020.0002.1B4A] # BALINESE LETTER ZAL SASAK +1B4B ; [.1E6B.0020.0002.1B4B] # BALINESE LETTER ASYURA SASAK +1B33 ; [.1E6C.0020.0002.1B33] # BALINESE LETTER HA +1B35 ; [.1E6D.0020.0002.1B35] # BALINESE VOWEL SIGN TEDUNG +1B36 ; [.1E6E.0020.0002.1B36] # BALINESE VOWEL SIGN ULU +1B37 ; [.1E6F.0020.0002.1B37] # BALINESE VOWEL SIGN ULU SARI +1B38 ; [.1E70.0020.0002.1B38] # BALINESE VOWEL SIGN SUKU +1B39 ; [.1E71.0020.0002.1B39] # BALINESE VOWEL SIGN SUKU ILUT +1B3A ; [.1E72.0020.0002.1B3A] # BALINESE VOWEL SIGN RA REPA +1B3B ; [.1E73.0020.0002.1B3B] # BALINESE VOWEL SIGN RA REPA TEDUNG +1B3A 1B35 ; [.1E73.0020.0002.1B3B] # BALINESE VOWEL SIGN RA REPA TEDUNG +1B3C ; [.1E74.0020.0002.1B3C] # BALINESE VOWEL SIGN LA LENGA +1B3D ; [.1E75.0020.0002.1B3D] # BALINESE VOWEL SIGN LA LENGA TEDUNG +1B3C 1B35 ; [.1E75.0020.0002.1B3D] # BALINESE VOWEL SIGN LA LENGA TEDUNG +1B3E ; [.1E76.0020.0002.1B3E] # BALINESE VOWEL SIGN TALING +1B3F ; [.1E77.0020.0002.1B3F] # BALINESE VOWEL SIGN TALING REPA +1B40 ; [.1E78.0020.0002.1B40] # BALINESE VOWEL SIGN TALING TEDUNG +1B3E 1B35 ; [.1E78.0020.0002.1B40] # BALINESE VOWEL SIGN TALING TEDUNG +1B41 ; [.1E79.0020.0002.1B41] # BALINESE VOWEL SIGN TALING REPA TEDUNG +1B3F 1B35 ; [.1E79.0020.0002.1B41] # BALINESE VOWEL SIGN TALING REPA TEDUNG +1B42 ; [.1E7A.0020.0002.1B42] # BALINESE VOWEL SIGN PEPET +1B43 ; [.1E7B.0020.0002.1B43] # BALINESE VOWEL SIGN PEPET TEDUNG +1B42 1B35 ; [.1E7B.0020.0002.1B43] # BALINESE VOWEL SIGN PEPET TEDUNG +1B44 ; [.1E7C.0020.0002.1B44] # BALINESE ADEG ADEG +1880 ; [.1E7D.0020.0002.1880] # MONGOLIAN LETTER ALI GALI ANUSVARA ONE +1881 ; [.1E7E.0020.0002.1881] # MONGOLIAN LETTER ALI GALI VISARGA ONE +1882 ; [.1E7F.0020.0002.1882] # MONGOLIAN LETTER ALI GALI DAMARU +1883 ; [.1E80.0020.0002.1883] # MONGOLIAN LETTER ALI GALI UBADAMA +1884 ; [.1E81.0020.0002.1884] # MONGOLIAN LETTER ALI GALI INVERTED UBADAMA +1885 ; [.1E82.0020.0002.1885] # MONGOLIAN LETTER ALI GALI BALUDA +1886 ; [.1E83.0020.0002.1886] # MONGOLIAN LETTER ALI GALI THREE BALUDA +1843 ; [.1E84.0020.0002.1843] # MONGOLIAN LETTER TODO LONG VOWEL SIGN +1820 ; [.1E85.0020.0002.1820] # MONGOLIAN LETTER A +1887 ; [.1E86.0020.0002.1887] # MONGOLIAN LETTER ALI GALI A +1821 ; [.1E87.0020.0002.1821] # MONGOLIAN LETTER E +1844 ; [.1E88.0020.0002.1844] # MONGOLIAN LETTER TODO E +185D ; [.1E89.0020.0002.185D] # MONGOLIAN LETTER SIBE E +1822 ; [.1E8A.0020.0002.1822] # MONGOLIAN LETTER I +1845 ; [.1E8B.0020.0002.1845] # MONGOLIAN LETTER TODO I +185E ; [.1E8C.0020.0002.185E] # MONGOLIAN LETTER SIBE I +1873 ; [.1E8D.0020.0002.1873] # MONGOLIAN LETTER MANCHU I +1888 ; [.1E8E.0020.0002.1888] # MONGOLIAN LETTER ALI GALI I +185F ; [.1E8F.0020.0002.185F] # MONGOLIAN LETTER SIBE IY +1823 ; [.1E90.0020.0002.1823] # MONGOLIAN LETTER O +1846 ; [.1E91.0020.0002.1846] # MONGOLIAN LETTER TODO O +1824 ; [.1E92.0020.0002.1824] # MONGOLIAN LETTER U +1847 ; [.1E93.0020.0002.1847] # MONGOLIAN LETTER TODO U +1861 ; [.1E94.0020.0002.1861] # MONGOLIAN LETTER SIBE U +1825 ; [.1E95.0020.0002.1825] # MONGOLIAN LETTER OE +1848 ; [.1E96.0020.0002.1848] # MONGOLIAN LETTER TODO OE +1826 ; [.1E97.0020.0002.1826] # MONGOLIAN LETTER UE +1849 ; [.1E98.0020.0002.1849] # MONGOLIAN LETTER TODO UE +1860 ; [.1E99.0020.0002.1860] # MONGOLIAN LETTER SIBE UE +1827 ; [.1E9A.0020.0002.1827] # MONGOLIAN LETTER EE +1828 ; [.1E9B.0020.0002.1828] # MONGOLIAN LETTER NA +1829 ; [.1E9C.0020.0002.1829] # MONGOLIAN LETTER ANG +184A ; [.1E9D.0020.0002.184A] # MONGOLIAN LETTER TODO ANG +1862 ; [.1E9E.0020.0002.1862] # MONGOLIAN LETTER SIBE ANG +188A ; [.1E9F.0020.0002.188A] # MONGOLIAN LETTER ALI GALI NGA +189B ; [.1EA0.0020.0002.189B] # MONGOLIAN LETTER MANCHU ALI GALI NGA +182A ; [.1EA1.0020.0002.182A] # MONGOLIAN LETTER BA +184B ; [.1EA2.0020.0002.184B] # MONGOLIAN LETTER TODO BA +182B ; [.1EA3.0020.0002.182B] # MONGOLIAN LETTER PA +184C ; [.1EA4.0020.0002.184C] # MONGOLIAN LETTER TODO PA +1866 ; [.1EA5.0020.0002.1866] # MONGOLIAN LETTER SIBE PA +182C ; [.1EA6.0020.0002.182C] # MONGOLIAN LETTER QA +184D ; [.1EA7.0020.0002.184D] # MONGOLIAN LETTER TODO QA +182D ; [.1EA8.0020.0002.182D] # MONGOLIAN LETTER GA +184E ; [.1EA9.0020.0002.184E] # MONGOLIAN LETTER TODO GA +1864 ; [.1EAA.0020.0002.1864] # MONGOLIAN LETTER SIBE GA +189A ; [.1EAB.0020.0002.189A] # MONGOLIAN LETTER MANCHU ALI GALI GHA +1865 ; [.1EAC.0020.0002.1865] # MONGOLIAN LETTER SIBE HA +182E ; [.1EAD.0020.0002.182E] # MONGOLIAN LETTER MA +184F ; [.1EAE.0020.0002.184F] # MONGOLIAN LETTER TODO MA +182F ; [.1EAF.0020.0002.182F] # MONGOLIAN LETTER LA +1830 ; [.1EB0.0020.0002.1830] # MONGOLIAN LETTER SA +1831 ; [.1EB1.0020.0002.1831] # MONGOLIAN LETTER SHA +1867 ; [.1EB2.0020.0002.1867] # MONGOLIAN LETTER SIBE SHA +189C ; [.1EB3.0020.0002.189C] # MONGOLIAN LETTER MANCHU ALI GALI CA +189D ; [.1EB4.0020.0002.189D] # MONGOLIAN LETTER MANCHU ALI GALI JHA +18A2 ; [.1EB5.0020.0002.18A2] # MONGOLIAN LETTER MANCHU ALI GALI SSA +18A4 ; [.1EB6.0020.0002.18A4] # MONGOLIAN LETTER MANCHU ALI GALI ZHA +18A5 ; [.1EB7.0020.0002.18A5] # MONGOLIAN LETTER MANCHU ALI GALI ZA +1832 ; [.1EB8.0020.0002.1832] # MONGOLIAN LETTER TA +1850 ; [.1EB9.0020.0002.1850] # MONGOLIAN LETTER TODO TA +1868 ; [.1EBA.0020.0002.1868] # MONGOLIAN LETTER SIBE TA +1833 ; [.1EBB.0020.0002.1833] # MONGOLIAN LETTER DA +1851 ; [.1EBC.0020.0002.1851] # MONGOLIAN LETTER TODO DA +1869 ; [.1EBD.0020.0002.1869] # MONGOLIAN LETTER SIBE DA +1834 ; [.1EBE.0020.0002.1834] # MONGOLIAN LETTER CHA +1852 ; [.1EBF.0020.0002.1852] # MONGOLIAN LETTER TODO CHA +1871 ; [.1EC0.0020.0002.1871] # MONGOLIAN LETTER SIBE CHA +185C ; [.1EC1.0020.0002.185C] # MONGOLIAN LETTER TODO DZA +188B ; [.1EC2.0020.0002.188B] # MONGOLIAN LETTER ALI GALI CA +1835 ; [.1EC3.0020.0002.1835] # MONGOLIAN LETTER JA +1853 ; [.1EC4.0020.0002.1853] # MONGOLIAN LETTER TODO JA +186A ; [.1EC5.0020.0002.186A] # MONGOLIAN LETTER SIBE JA +1877 ; [.1EC6.0020.0002.1877] # MONGOLIAN LETTER MANCHU ZHA +1836 ; [.1EC7.0020.0002.1836] # MONGOLIAN LETTER YA +1855 ; [.1EC8.0020.0002.1855] # MONGOLIAN LETTER TODO YA +1872 ; [.1EC9.0020.0002.1872] # MONGOLIAN LETTER SIBE ZHA +1837 ; [.1ECA.0020.0002.1837] # MONGOLIAN LETTER RA +1875 ; [.1ECB.0020.0002.1875] # MONGOLIAN LETTER MANCHU RA +1838 ; [.1ECC.0020.0002.1838] # MONGOLIAN LETTER WA +1856 ; [.1ECD.0020.0002.1856] # MONGOLIAN LETTER TODO WA +1839 ; [.1ECE.0020.0002.1839] # MONGOLIAN LETTER FA +186B ; [.1ECF.0020.0002.186B] # MONGOLIAN LETTER SIBE FA +1876 ; [.1ED0.0020.0002.1876] # MONGOLIAN LETTER MANCHU FA +183A ; [.1ED1.0020.0002.183A] # MONGOLIAN LETTER KA +1857 ; [.1ED2.0020.0002.1857] # MONGOLIAN LETTER TODO KA +1863 ; [.1ED3.0020.0002.1863] # MONGOLIAN LETTER SIBE KA +1874 ; [.1ED4.0020.0002.1874] # MONGOLIAN LETTER MANCHU KA +1889 ; [.1ED5.0020.0002.1889] # MONGOLIAN LETTER ALI GALI KA +183B ; [.1ED6.0020.0002.183B] # MONGOLIAN LETTER KHA +183C ; [.1ED7.0020.0002.183C] # MONGOLIAN LETTER TSA +1854 ; [.1ED8.0020.0002.1854] # MONGOLIAN LETTER TODO TSA +186E ; [.1ED9.0020.0002.186E] # MONGOLIAN LETTER SIBE TSA +183D ; [.1EDA.0020.0002.183D] # MONGOLIAN LETTER ZA +186F ; [.1EDB.0020.0002.186F] # MONGOLIAN LETTER SIBE ZA +1858 ; [.1EDC.0020.0002.1858] # MONGOLIAN LETTER TODO GAA +186C ; [.1EDD.0020.0002.186C] # MONGOLIAN LETTER SIBE GAA +183E ; [.1EDE.0020.0002.183E] # MONGOLIAN LETTER HAA +1859 ; [.1EDF.0020.0002.1859] # MONGOLIAN LETTER TODO HAA +186D ; [.1EE0.0020.0002.186D] # MONGOLIAN LETTER SIBE HAA +183F ; [.1EE1.0020.0002.183F] # MONGOLIAN LETTER ZRA +1840 ; [.1EE2.0020.0002.1840] # MONGOLIAN LETTER LHA +1841 ; [.1EE3.0020.0002.1841] # MONGOLIAN LETTER ZHI +1842 ; [.1EE4.0020.0002.1842] # MONGOLIAN LETTER CHI +185A ; [.1EE5.0020.0002.185A] # MONGOLIAN LETTER TODO JIA +185B ; [.1EE6.0020.0002.185B] # MONGOLIAN LETTER TODO NIA +1870 ; [.1EE7.0020.0002.1870] # MONGOLIAN LETTER SIBE RAA +188C ; [.1EE8.0020.0002.188C] # MONGOLIAN LETTER ALI GALI TTA +189E ; [.1EE9.0020.0002.189E] # MONGOLIAN LETTER MANCHU ALI GALI TTA +188D ; [.1EEA.0020.0002.188D] # MONGOLIAN LETTER ALI GALI TTHA +188E ; [.1EEB.0020.0002.188E] # MONGOLIAN LETTER ALI GALI DDA +189F ; [.1EEC.0020.0002.189F] # MONGOLIAN LETTER MANCHU ALI GALI DDHA +188F ; [.1EED.0020.0002.188F] # MONGOLIAN LETTER ALI GALI NNA +1890 ; [.1EEE.0020.0002.1890] # MONGOLIAN LETTER ALI GALI TA +1898 ; [.1EEF.0020.0002.1898] # MONGOLIAN LETTER TODO ALI GALI TA +18A0 ; [.1EF0.0020.0002.18A0] # MONGOLIAN LETTER MANCHU ALI GALI TA +1891 ; [.1EF1.0020.0002.1891] # MONGOLIAN LETTER ALI GALI DA +18A1 ; [.1EF2.0020.0002.18A1] # MONGOLIAN LETTER MANCHU ALI GALI DHA +1892 ; [.1EF3.0020.0002.1892] # MONGOLIAN LETTER ALI GALI PA +1893 ; [.1EF4.0020.0002.1893] # MONGOLIAN LETTER ALI GALI PHA +18A8 ; [.1EF5.0020.0002.18A8] # MONGOLIAN LETTER MANCHU ALI GALI BHA +1894 ; [.1EF6.0020.0002.1894] # MONGOLIAN LETTER ALI GALI SSA +18A3 ; [.1EF7.0020.0002.18A3] # MONGOLIAN LETTER MANCHU ALI GALI CYA +1895 ; [.1EF8.0020.0002.1895] # MONGOLIAN LETTER ALI GALI ZHA +1899 ; [.1EF9.0020.0002.1899] # MONGOLIAN LETTER TODO ALI GALI ZHA +1896 ; [.1EFA.0020.0002.1896] # MONGOLIAN LETTER ALI GALI ZA +1897 ; [.1EFB.0020.0002.1897] # MONGOLIAN LETTER ALI GALI AH +18A6 ; [.1EFC.0020.0002.18A6] # MONGOLIAN LETTER ALI GALI HALF U +18A7 ; [.1EFD.0020.0002.18A7] # MONGOLIAN LETTER ALI GALI HALF YA +18A9 ; [.1EFE.0020.0002.18A9] # MONGOLIAN LETTER ALI GALI DAGALGA +13A0 ; [.1EFF.0020.0002.13A0] # CHEROKEE LETTER A +13A1 ; [.1F00.0020.0002.13A1] # CHEROKEE LETTER E +13A2 ; [.1F01.0020.0002.13A2] # CHEROKEE LETTER I +13A3 ; [.1F02.0020.0002.13A3] # CHEROKEE LETTER O +13A4 ; [.1F03.0020.0002.13A4] # CHEROKEE LETTER U +13A5 ; [.1F04.0020.0002.13A5] # CHEROKEE LETTER V +13A6 ; [.1F05.0020.0002.13A6] # CHEROKEE LETTER GA +13A7 ; [.1F06.0020.0002.13A7] # CHEROKEE LETTER KA +13A8 ; [.1F07.0020.0002.13A8] # CHEROKEE LETTER GE +13A9 ; [.1F08.0020.0002.13A9] # CHEROKEE LETTER GI +13AA ; [.1F09.0020.0002.13AA] # CHEROKEE LETTER GO +13AB ; [.1F0A.0020.0002.13AB] # CHEROKEE LETTER GU +13AC ; [.1F0B.0020.0002.13AC] # CHEROKEE LETTER GV +13AD ; [.1F0C.0020.0002.13AD] # CHEROKEE LETTER HA +13AE ; [.1F0D.0020.0002.13AE] # CHEROKEE LETTER HE +13AF ; [.1F0E.0020.0002.13AF] # CHEROKEE LETTER HI +13B0 ; [.1F0F.0020.0002.13B0] # CHEROKEE LETTER HO +13B1 ; [.1F10.0020.0002.13B1] # CHEROKEE LETTER HU +13B2 ; [.1F11.0020.0002.13B2] # CHEROKEE LETTER HV +13B3 ; [.1F12.0020.0002.13B3] # CHEROKEE LETTER LA +13B4 ; [.1F13.0020.0002.13B4] # CHEROKEE LETTER LE +13B5 ; [.1F14.0020.0002.13B5] # CHEROKEE LETTER LI +13B6 ; [.1F15.0020.0002.13B6] # CHEROKEE LETTER LO +13B7 ; [.1F16.0020.0002.13B7] # CHEROKEE LETTER LU +13B8 ; [.1F17.0020.0002.13B8] # CHEROKEE LETTER LV +13B9 ; [.1F18.0020.0002.13B9] # CHEROKEE LETTER MA +13BA ; [.1F19.0020.0002.13BA] # CHEROKEE LETTER ME +13BB ; [.1F1A.0020.0002.13BB] # CHEROKEE LETTER MI +13BC ; [.1F1B.0020.0002.13BC] # CHEROKEE LETTER MO +13BD ; [.1F1C.0020.0002.13BD] # CHEROKEE LETTER MU +13BE ; [.1F1D.0020.0002.13BE] # CHEROKEE LETTER NA +13BF ; [.1F1E.0020.0002.13BF] # CHEROKEE LETTER HNA +13C0 ; [.1F1F.0020.0002.13C0] # CHEROKEE LETTER NAH +13C1 ; [.1F20.0020.0002.13C1] # CHEROKEE LETTER NE +13C2 ; [.1F21.0020.0002.13C2] # CHEROKEE LETTER NI +13C3 ; [.1F22.0020.0002.13C3] # CHEROKEE LETTER NO +13C4 ; [.1F23.0020.0002.13C4] # CHEROKEE LETTER NU +13C5 ; [.1F24.0020.0002.13C5] # CHEROKEE LETTER NV +13C6 ; [.1F25.0020.0002.13C6] # CHEROKEE LETTER QUA +13C7 ; [.1F26.0020.0002.13C7] # CHEROKEE LETTER QUE +13C8 ; [.1F27.0020.0002.13C8] # CHEROKEE LETTER QUI +13C9 ; [.1F28.0020.0002.13C9] # CHEROKEE LETTER QUO +13CA ; [.1F29.0020.0002.13CA] # CHEROKEE LETTER QUU +13CB ; [.1F2A.0020.0002.13CB] # CHEROKEE LETTER QUV +13CC ; [.1F2B.0020.0002.13CC] # CHEROKEE LETTER SA +13CD ; [.1F2C.0020.0002.13CD] # CHEROKEE LETTER S +13CE ; [.1F2D.0020.0002.13CE] # CHEROKEE LETTER SE +13CF ; [.1F2E.0020.0002.13CF] # CHEROKEE LETTER SI +13D0 ; [.1F2F.0020.0002.13D0] # CHEROKEE LETTER SO +13D1 ; [.1F30.0020.0002.13D1] # CHEROKEE LETTER SU +13D2 ; [.1F31.0020.0002.13D2] # CHEROKEE LETTER SV +13D3 ; [.1F32.0020.0002.13D3] # CHEROKEE LETTER DA +13D4 ; [.1F33.0020.0002.13D4] # CHEROKEE LETTER TA +13D5 ; [.1F34.0020.0002.13D5] # CHEROKEE LETTER DE +13D6 ; [.1F35.0020.0002.13D6] # CHEROKEE LETTER TE +13D7 ; [.1F36.0020.0002.13D7] # CHEROKEE LETTER DI +13D8 ; [.1F37.0020.0002.13D8] # CHEROKEE LETTER TI +13D9 ; [.1F38.0020.0002.13D9] # CHEROKEE LETTER DO +13DA ; [.1F39.0020.0002.13DA] # CHEROKEE LETTER DU +13DB ; [.1F3A.0020.0002.13DB] # CHEROKEE LETTER DV +13DC ; [.1F3B.0020.0002.13DC] # CHEROKEE LETTER DLA +13DD ; [.1F3C.0020.0002.13DD] # CHEROKEE LETTER TLA +13DE ; [.1F3D.0020.0002.13DE] # CHEROKEE LETTER TLE +13DF ; [.1F3E.0020.0002.13DF] # CHEROKEE LETTER TLI +13E0 ; [.1F3F.0020.0002.13E0] # CHEROKEE LETTER TLO +13E1 ; [.1F40.0020.0002.13E1] # CHEROKEE LETTER TLU +13E2 ; [.1F41.0020.0002.13E2] # CHEROKEE LETTER TLV +13E3 ; [.1F42.0020.0002.13E3] # CHEROKEE LETTER TSA +13E4 ; [.1F43.0020.0002.13E4] # CHEROKEE LETTER TSE +13E5 ; [.1F44.0020.0002.13E5] # CHEROKEE LETTER TSI +13E6 ; [.1F45.0020.0002.13E6] # CHEROKEE LETTER TSO +13E7 ; [.1F46.0020.0002.13E7] # CHEROKEE LETTER TSU +13E8 ; [.1F47.0020.0002.13E8] # CHEROKEE LETTER TSV +13E9 ; [.1F48.0020.0002.13E9] # CHEROKEE LETTER WA +13EA ; [.1F49.0020.0002.13EA] # CHEROKEE LETTER WE +13EB ; [.1F4A.0020.0002.13EB] # CHEROKEE LETTER WI +13EC ; [.1F4B.0020.0002.13EC] # CHEROKEE LETTER WO +13ED ; [.1F4C.0020.0002.13ED] # CHEROKEE LETTER WU +13EE ; [.1F4D.0020.0002.13EE] # CHEROKEE LETTER WV +13EF ; [.1F4E.0020.0002.13EF] # CHEROKEE LETTER YA +13F0 ; [.1F4F.0020.0002.13F0] # CHEROKEE LETTER YE +13F1 ; [.1F50.0020.0002.13F1] # CHEROKEE LETTER YI +13F2 ; [.1F51.0020.0002.13F2] # CHEROKEE LETTER YO +13F3 ; [.1F52.0020.0002.13F3] # CHEROKEE LETTER YU +13F4 ; [.1F53.0020.0002.13F4] # CHEROKEE LETTER YV +1401 ; [.1F54.0020.0002.1401] # CANADIAN SYLLABICS E +1402 ; [.1F55.0020.0002.1402] # CANADIAN SYLLABICS AAI +1403 ; [.1F56.0020.0002.1403] # CANADIAN SYLLABICS I +1404 ; [.1F57.0020.0002.1404] # CANADIAN SYLLABICS II +1405 ; [.1F58.0020.0002.1405] # CANADIAN SYLLABICS O +1406 ; [.1F59.0020.0002.1406] # CANADIAN SYLLABICS OO +1407 ; [.1F5A.0020.0002.1407] # CANADIAN SYLLABICS Y-CREE OO +1408 ; [.1F5B.0020.0002.1408] # CANADIAN SYLLABICS CARRIER EE +1409 ; [.1F5C.0020.0002.1409] # CANADIAN SYLLABICS CARRIER I +140A ; [.1F5D.0020.0002.140A] # CANADIAN SYLLABICS A +140B ; [.1F5E.0020.0002.140B] # CANADIAN SYLLABICS AA +140C ; [.1F5F.0020.0002.140C] # CANADIAN SYLLABICS WE +140D ; [.1F60.0020.0002.140D] # CANADIAN SYLLABICS WEST-CREE WE +140E ; [.1F61.0020.0002.140E] # CANADIAN SYLLABICS WI +140F ; [.1F62.0020.0002.140F] # CANADIAN SYLLABICS WEST-CREE WI +1410 ; [.1F63.0020.0002.1410] # CANADIAN SYLLABICS WII +1411 ; [.1F64.0020.0002.1411] # CANADIAN SYLLABICS WEST-CREE WII +1412 ; [.1F65.0020.0002.1412] # CANADIAN SYLLABICS WO +1413 ; [.1F66.0020.0002.1413] # CANADIAN SYLLABICS WEST-CREE WO +1414 ; [.1F67.0020.0002.1414] # CANADIAN SYLLABICS WOO +1415 ; [.1F68.0020.0002.1415] # CANADIAN SYLLABICS WEST-CREE WOO +1416 ; [.1F69.0020.0002.1416] # CANADIAN SYLLABICS NASKAPI WOO +1417 ; [.1F6A.0020.0002.1417] # CANADIAN SYLLABICS WA +1418 ; [.1F6B.0020.0002.1418] # CANADIAN SYLLABICS WEST-CREE WA +1419 ; [.1F6C.0020.0002.1419] # CANADIAN SYLLABICS WAA +141A ; [.1F6D.0020.0002.141A] # CANADIAN SYLLABICS WEST-CREE WAA +141B ; [.1F6E.0020.0002.141B] # CANADIAN SYLLABICS NASKAPI WAA +141C ; [.1F6F.0020.0002.141C] # CANADIAN SYLLABICS AI +141D ; [.1F70.0020.0002.141D] # CANADIAN SYLLABICS Y-CREE W +141E ; [.1F71.0020.0002.141E] # CANADIAN SYLLABICS GLOTTAL STOP +141F ; [.1F72.0020.0002.141F] # CANADIAN SYLLABICS FINAL ACUTE +1420 ; [.1F73.0020.0002.1420] # CANADIAN SYLLABICS FINAL GRAVE +1421 ; [.1F74.0020.0002.1421] # CANADIAN SYLLABICS FINAL BOTTOM HALF RING +1422 ; [.1F75.0020.0002.1422] # CANADIAN SYLLABICS FINAL TOP HALF RING +1423 ; [.1F76.0020.0002.1423] # CANADIAN SYLLABICS FINAL RIGHT HALF RING +1424 ; [.1F77.0020.0002.1424] # CANADIAN SYLLABICS FINAL RING +1425 ; [.1F78.0020.0002.1425] # CANADIAN SYLLABICS FINAL DOUBLE ACUTE +1426 ; [.1F79.0020.0002.1426] # CANADIAN SYLLABICS FINAL DOUBLE SHORT VERTICAL STROKES +1427 ; [.1F7A.0020.0002.1427] # CANADIAN SYLLABICS FINAL MIDDLE DOT +1428 ; [.1F7B.0020.0002.1428] # CANADIAN SYLLABICS FINAL SHORT HORIZONTAL STROKE +1429 ; [.1F7C.0020.0002.1429] # CANADIAN SYLLABICS FINAL PLUS +142A ; [.1F7D.0020.0002.142A] # CANADIAN SYLLABICS FINAL DOWN TACK +142B ; [.1F7E.0020.0002.142B] # CANADIAN SYLLABICS EN +142C ; [.1F7F.0020.0002.142C] # CANADIAN SYLLABICS IN +142D ; [.1F80.0020.0002.142D] # CANADIAN SYLLABICS ON +142E ; [.1F81.0020.0002.142E] # CANADIAN SYLLABICS AN +142F ; [.1F82.0020.0002.142F] # CANADIAN SYLLABICS PE +1430 ; [.1F83.0020.0002.1430] # CANADIAN SYLLABICS PAAI +1431 ; [.1F84.0020.0002.1431] # CANADIAN SYLLABICS PI +1432 ; [.1F85.0020.0002.1432] # CANADIAN SYLLABICS PII +1433 ; [.1F86.0020.0002.1433] # CANADIAN SYLLABICS PO +1434 ; [.1F87.0020.0002.1434] # CANADIAN SYLLABICS POO +1435 ; [.1F88.0020.0002.1435] # CANADIAN SYLLABICS Y-CREE POO +1436 ; [.1F89.0020.0002.1436] # CANADIAN SYLLABICS CARRIER HEE +1437 ; [.1F8A.0020.0002.1437] # CANADIAN SYLLABICS CARRIER HI +1438 ; [.1F8B.0020.0002.1438] # CANADIAN SYLLABICS PA +1439 ; [.1F8C.0020.0002.1439] # CANADIAN SYLLABICS PAA +143A ; [.1F8D.0020.0002.143A] # CANADIAN SYLLABICS PWE +143B ; [.1F8E.0020.0002.143B] # CANADIAN SYLLABICS WEST-CREE PWE +143C ; [.1F8F.0020.0002.143C] # CANADIAN SYLLABICS PWI +143D ; [.1F90.0020.0002.143D] # CANADIAN SYLLABICS WEST-CREE PWI +143E ; [.1F91.0020.0002.143E] # CANADIAN SYLLABICS PWII +143F ; [.1F92.0020.0002.143F] # CANADIAN SYLLABICS WEST-CREE PWII +1440 ; [.1F93.0020.0002.1440] # CANADIAN SYLLABICS PWO +1441 ; [.1F94.0020.0002.1441] # CANADIAN SYLLABICS WEST-CREE PWO +1442 ; [.1F95.0020.0002.1442] # CANADIAN SYLLABICS PWOO +1443 ; [.1F96.0020.0002.1443] # CANADIAN SYLLABICS WEST-CREE PWOO +1444 ; [.1F97.0020.0002.1444] # CANADIAN SYLLABICS PWA +1445 ; [.1F98.0020.0002.1445] # CANADIAN SYLLABICS WEST-CREE PWA +1446 ; [.1F99.0020.0002.1446] # CANADIAN SYLLABICS PWAA +1447 ; [.1F9A.0020.0002.1447] # CANADIAN SYLLABICS WEST-CREE PWAA +1448 ; [.1F9B.0020.0002.1448] # CANADIAN SYLLABICS Y-CREE PWAA +1449 ; [.1F9C.0020.0002.1449] # CANADIAN SYLLABICS P +144A ; [.1F9D.0020.0002.144A] # CANADIAN SYLLABICS WEST-CREE P +144B ; [.1F9E.0020.0002.144B] # CANADIAN SYLLABICS CARRIER H +144C ; [.1F9F.0020.0002.144C] # CANADIAN SYLLABICS TE +144D ; [.1FA0.0020.0002.144D] # CANADIAN SYLLABICS TAAI +144E ; [.1FA1.0020.0002.144E] # CANADIAN SYLLABICS TI +144F ; [.1FA2.0020.0002.144F] # CANADIAN SYLLABICS TII +1450 ; [.1FA3.0020.0002.1450] # CANADIAN SYLLABICS TO +1451 ; [.1FA4.0020.0002.1451] # CANADIAN SYLLABICS TOO +1452 ; [.1FA5.0020.0002.1452] # CANADIAN SYLLABICS Y-CREE TOO +1453 ; [.1FA6.0020.0002.1453] # CANADIAN SYLLABICS CARRIER DEE +1454 ; [.1FA7.0020.0002.1454] # CANADIAN SYLLABICS CARRIER DI +1455 ; [.1FA8.0020.0002.1455] # CANADIAN SYLLABICS TA +1456 ; [.1FA9.0020.0002.1456] # CANADIAN SYLLABICS TAA +1457 ; [.1FAA.0020.0002.1457] # CANADIAN SYLLABICS TWE +1458 ; [.1FAB.0020.0002.1458] # CANADIAN SYLLABICS WEST-CREE TWE +1459 ; [.1FAC.0020.0002.1459] # CANADIAN SYLLABICS TWI +145A ; [.1FAD.0020.0002.145A] # CANADIAN SYLLABICS WEST-CREE TWI +145B ; [.1FAE.0020.0002.145B] # CANADIAN SYLLABICS TWII +145C ; [.1FAF.0020.0002.145C] # CANADIAN SYLLABICS WEST-CREE TWII +145D ; [.1FB0.0020.0002.145D] # CANADIAN SYLLABICS TWO +145E ; [.1FB1.0020.0002.145E] # CANADIAN SYLLABICS WEST-CREE TWO +145F ; [.1FB2.0020.0002.145F] # CANADIAN SYLLABICS TWOO +1460 ; [.1FB3.0020.0002.1460] # CANADIAN SYLLABICS WEST-CREE TWOO +1461 ; [.1FB4.0020.0002.1461] # CANADIAN SYLLABICS TWA +1462 ; [.1FB5.0020.0002.1462] # CANADIAN SYLLABICS WEST-CREE TWA +1463 ; [.1FB6.0020.0002.1463] # CANADIAN SYLLABICS TWAA +1464 ; [.1FB7.0020.0002.1464] # CANADIAN SYLLABICS WEST-CREE TWAA +1465 ; [.1FB8.0020.0002.1465] # CANADIAN SYLLABICS NASKAPI TWAA +1466 ; [.1FB9.0020.0002.1466] # CANADIAN SYLLABICS T +1467 ; [.1FBA.0020.0002.1467] # CANADIAN SYLLABICS TTE +1468 ; [.1FBB.0020.0002.1468] # CANADIAN SYLLABICS TTI +1469 ; [.1FBC.0020.0002.1469] # CANADIAN SYLLABICS TTO +146A ; [.1FBD.0020.0002.146A] # CANADIAN SYLLABICS TTA +146B ; [.1FBE.0020.0002.146B] # CANADIAN SYLLABICS KE +146C ; [.1FBF.0020.0002.146C] # CANADIAN SYLLABICS KAAI +146D ; [.1FC0.0020.0002.146D] # CANADIAN SYLLABICS KI +146E ; [.1FC1.0020.0002.146E] # CANADIAN SYLLABICS KII +146F ; [.1FC2.0020.0002.146F] # CANADIAN SYLLABICS KO +1470 ; [.1FC3.0020.0002.1470] # CANADIAN SYLLABICS KOO +1471 ; [.1FC4.0020.0002.1471] # CANADIAN SYLLABICS Y-CREE KOO +1472 ; [.1FC5.0020.0002.1472] # CANADIAN SYLLABICS KA +1473 ; [.1FC6.0020.0002.1473] # CANADIAN SYLLABICS KAA +1474 ; [.1FC7.0020.0002.1474] # CANADIAN SYLLABICS KWE +1475 ; [.1FC8.0020.0002.1475] # CANADIAN SYLLABICS WEST-CREE KWE +1476 ; [.1FC9.0020.0002.1476] # CANADIAN SYLLABICS KWI +1477 ; [.1FCA.0020.0002.1477] # CANADIAN SYLLABICS WEST-CREE KWI +1478 ; [.1FCB.0020.0002.1478] # CANADIAN SYLLABICS KWII +1479 ; [.1FCC.0020.0002.1479] # CANADIAN SYLLABICS WEST-CREE KWII +147A ; [.1FCD.0020.0002.147A] # CANADIAN SYLLABICS KWO +147B ; [.1FCE.0020.0002.147B] # CANADIAN SYLLABICS WEST-CREE KWO +147C ; [.1FCF.0020.0002.147C] # CANADIAN SYLLABICS KWOO +147D ; [.1FD0.0020.0002.147D] # CANADIAN SYLLABICS WEST-CREE KWOO +147E ; [.1FD1.0020.0002.147E] # CANADIAN SYLLABICS KWA +147F ; [.1FD2.0020.0002.147F] # CANADIAN SYLLABICS WEST-CREE KWA +1480 ; [.1FD3.0020.0002.1480] # CANADIAN SYLLABICS KWAA +1481 ; [.1FD4.0020.0002.1481] # CANADIAN SYLLABICS WEST-CREE KWAA +1482 ; [.1FD5.0020.0002.1482] # CANADIAN SYLLABICS NASKAPI KWAA +1483 ; [.1FD6.0020.0002.1483] # CANADIAN SYLLABICS K +1484 ; [.1FD7.0020.0002.1484] # CANADIAN SYLLABICS KW +1485 ; [.1FD8.0020.0002.1485] # CANADIAN SYLLABICS SOUTH-SLAVEY KEH +1486 ; [.1FD9.0020.0002.1486] # CANADIAN SYLLABICS SOUTH-SLAVEY KIH +1487 ; [.1FDA.0020.0002.1487] # CANADIAN SYLLABICS SOUTH-SLAVEY KOH +1488 ; [.1FDB.0020.0002.1488] # CANADIAN SYLLABICS SOUTH-SLAVEY KAH +1489 ; [.1FDC.0020.0002.1489] # CANADIAN SYLLABICS CE +148A ; [.1FDD.0020.0002.148A] # CANADIAN SYLLABICS CAAI +148B ; [.1FDE.0020.0002.148B] # CANADIAN SYLLABICS CI +148C ; [.1FDF.0020.0002.148C] # CANADIAN SYLLABICS CII +148D ; [.1FE0.0020.0002.148D] # CANADIAN SYLLABICS CO +148E ; [.1FE1.0020.0002.148E] # CANADIAN SYLLABICS COO +148F ; [.1FE2.0020.0002.148F] # CANADIAN SYLLABICS Y-CREE COO +1490 ; [.1FE3.0020.0002.1490] # CANADIAN SYLLABICS CA +1491 ; [.1FE4.0020.0002.1491] # CANADIAN SYLLABICS CAA +1492 ; [.1FE5.0020.0002.1492] # CANADIAN SYLLABICS CWE +1493 ; [.1FE6.0020.0002.1493] # CANADIAN SYLLABICS WEST-CREE CWE +1494 ; [.1FE7.0020.0002.1494] # CANADIAN SYLLABICS CWI +1495 ; [.1FE8.0020.0002.1495] # CANADIAN SYLLABICS WEST-CREE CWI +1496 ; [.1FE9.0020.0002.1496] # CANADIAN SYLLABICS CWII +1497 ; [.1FEA.0020.0002.1497] # CANADIAN SYLLABICS WEST-CREE CWII +1498 ; [.1FEB.0020.0002.1498] # CANADIAN SYLLABICS CWO +1499 ; [.1FEC.0020.0002.1499] # CANADIAN SYLLABICS WEST-CREE CWO +149A ; [.1FED.0020.0002.149A] # CANADIAN SYLLABICS CWOO +149B ; [.1FEE.0020.0002.149B] # CANADIAN SYLLABICS WEST-CREE CWOO +149C ; [.1FEF.0020.0002.149C] # CANADIAN SYLLABICS CWA +149D ; [.1FF0.0020.0002.149D] # CANADIAN SYLLABICS WEST-CREE CWA +149E ; [.1FF1.0020.0002.149E] # CANADIAN SYLLABICS CWAA +149F ; [.1FF2.0020.0002.149F] # CANADIAN SYLLABICS WEST-CREE CWAA +14A0 ; [.1FF3.0020.0002.14A0] # CANADIAN SYLLABICS NASKAPI CWAA +14A1 ; [.1FF4.0020.0002.14A1] # CANADIAN SYLLABICS C +14A2 ; [.1FF5.0020.0002.14A2] # CANADIAN SYLLABICS SAYISI TH +14A3 ; [.1FF6.0020.0002.14A3] # CANADIAN SYLLABICS ME +14A4 ; [.1FF7.0020.0002.14A4] # CANADIAN SYLLABICS MAAI +14A5 ; [.1FF8.0020.0002.14A5] # CANADIAN SYLLABICS MI +14A6 ; [.1FF9.0020.0002.14A6] # CANADIAN SYLLABICS MII +14A7 ; [.1FFA.0020.0002.14A7] # CANADIAN SYLLABICS MO +14A8 ; [.1FFB.0020.0002.14A8] # CANADIAN SYLLABICS MOO +14A9 ; [.1FFC.0020.0002.14A9] # CANADIAN SYLLABICS Y-CREE MOO +14AA ; [.1FFD.0020.0002.14AA] # CANADIAN SYLLABICS MA +14AB ; [.1FFE.0020.0002.14AB] # CANADIAN SYLLABICS MAA +14AC ; [.1FFF.0020.0002.14AC] # CANADIAN SYLLABICS MWE +14AD ; [.2000.0020.0002.14AD] # CANADIAN SYLLABICS WEST-CREE MWE +14AE ; [.2001.0020.0002.14AE] # CANADIAN SYLLABICS MWI +14AF ; [.2002.0020.0002.14AF] # CANADIAN SYLLABICS WEST-CREE MWI +14B0 ; [.2003.0020.0002.14B0] # CANADIAN SYLLABICS MWII +14B1 ; [.2004.0020.0002.14B1] # CANADIAN SYLLABICS WEST-CREE MWII +14B2 ; [.2005.0020.0002.14B2] # CANADIAN SYLLABICS MWO +14B3 ; [.2006.0020.0002.14B3] # CANADIAN SYLLABICS WEST-CREE MWO +14B4 ; [.2007.0020.0002.14B4] # CANADIAN SYLLABICS MWOO +14B5 ; [.2008.0020.0002.14B5] # CANADIAN SYLLABICS WEST-CREE MWOO +14B6 ; [.2009.0020.0002.14B6] # CANADIAN SYLLABICS MWA +14B7 ; [.200A.0020.0002.14B7] # CANADIAN SYLLABICS WEST-CREE MWA +14B8 ; [.200B.0020.0002.14B8] # CANADIAN SYLLABICS MWAA +14B9 ; [.200C.0020.0002.14B9] # CANADIAN SYLLABICS WEST-CREE MWAA +14BA ; [.200D.0020.0002.14BA] # CANADIAN SYLLABICS NASKAPI MWAA +14BB ; [.200E.0020.0002.14BB] # CANADIAN SYLLABICS M +14BC ; [.200F.0020.0002.14BC] # CANADIAN SYLLABICS WEST-CREE M +14BD ; [.2010.0020.0002.14BD] # CANADIAN SYLLABICS MH +14BE ; [.2011.0020.0002.14BE] # CANADIAN SYLLABICS ATHAPASCAN M +14BF ; [.2012.0020.0002.14BF] # CANADIAN SYLLABICS SAYISI M +14C0 ; [.2013.0020.0002.14C0] # CANADIAN SYLLABICS NE +14C1 ; [.2014.0020.0002.14C1] # CANADIAN SYLLABICS NAAI +14C2 ; [.2015.0020.0002.14C2] # CANADIAN SYLLABICS NI +14C3 ; [.2016.0020.0002.14C3] # CANADIAN SYLLABICS NII +14C4 ; [.2017.0020.0002.14C4] # CANADIAN SYLLABICS NO +14C5 ; [.2018.0020.0002.14C5] # CANADIAN SYLLABICS NOO +14C6 ; [.2019.0020.0002.14C6] # CANADIAN SYLLABICS Y-CREE NOO +14C7 ; [.201A.0020.0002.14C7] # CANADIAN SYLLABICS NA +14C8 ; [.201B.0020.0002.14C8] # CANADIAN SYLLABICS NAA +14C9 ; [.201C.0020.0002.14C9] # CANADIAN SYLLABICS NWE +14CA ; [.201D.0020.0002.14CA] # CANADIAN SYLLABICS WEST-CREE NWE +14CB ; [.201E.0020.0002.14CB] # CANADIAN SYLLABICS NWA +14CC ; [.201F.0020.0002.14CC] # CANADIAN SYLLABICS WEST-CREE NWA +14CD ; [.2020.0020.0002.14CD] # CANADIAN SYLLABICS NWAA +14CE ; [.2021.0020.0002.14CE] # CANADIAN SYLLABICS WEST-CREE NWAA +14CF ; [.2022.0020.0002.14CF] # CANADIAN SYLLABICS NASKAPI NWAA +14D0 ; [.2023.0020.0002.14D0] # CANADIAN SYLLABICS N +14D1 ; [.2024.0020.0002.14D1] # CANADIAN SYLLABICS CARRIER NG +14D2 ; [.2025.0020.0002.14D2] # CANADIAN SYLLABICS NH +14D3 ; [.2026.0020.0002.14D3] # CANADIAN SYLLABICS LE +14D4 ; [.2027.0020.0002.14D4] # CANADIAN SYLLABICS LAAI +14D5 ; [.2028.0020.0002.14D5] # CANADIAN SYLLABICS LI +14D6 ; [.2029.0020.0002.14D6] # CANADIAN SYLLABICS LII +14D7 ; [.202A.0020.0002.14D7] # CANADIAN SYLLABICS LO +14D8 ; [.202B.0020.0002.14D8] # CANADIAN SYLLABICS LOO +14D9 ; [.202C.0020.0002.14D9] # CANADIAN SYLLABICS Y-CREE LOO +14DA ; [.202D.0020.0002.14DA] # CANADIAN SYLLABICS LA +14DB ; [.202E.0020.0002.14DB] # CANADIAN SYLLABICS LAA +14DC ; [.202F.0020.0002.14DC] # CANADIAN SYLLABICS LWE +14DD ; [.2030.0020.0002.14DD] # CANADIAN SYLLABICS WEST-CREE LWE +14DE ; [.2031.0020.0002.14DE] # CANADIAN SYLLABICS LWI +14DF ; [.2032.0020.0002.14DF] # CANADIAN SYLLABICS WEST-CREE LWI +14E0 ; [.2033.0020.0002.14E0] # CANADIAN SYLLABICS LWII +14E1 ; [.2034.0020.0002.14E1] # CANADIAN SYLLABICS WEST-CREE LWII +14E2 ; [.2035.0020.0002.14E2] # CANADIAN SYLLABICS LWO +14E3 ; [.2036.0020.0002.14E3] # CANADIAN SYLLABICS WEST-CREE LWO +14E4 ; [.2037.0020.0002.14E4] # CANADIAN SYLLABICS LWOO +14E5 ; [.2038.0020.0002.14E5] # CANADIAN SYLLABICS WEST-CREE LWOO +14E6 ; [.2039.0020.0002.14E6] # CANADIAN SYLLABICS LWA +14E7 ; [.203A.0020.0002.14E7] # CANADIAN SYLLABICS WEST-CREE LWA +14E8 ; [.203B.0020.0002.14E8] # CANADIAN SYLLABICS LWAA +14E9 ; [.203C.0020.0002.14E9] # CANADIAN SYLLABICS WEST-CREE LWAA +14EA ; [.203D.0020.0002.14EA] # CANADIAN SYLLABICS L +14EB ; [.203E.0020.0002.14EB] # CANADIAN SYLLABICS WEST-CREE L +14EC ; [.203F.0020.0002.14EC] # CANADIAN SYLLABICS MEDIAL L +14ED ; [.2040.0020.0002.14ED] # CANADIAN SYLLABICS SE +14EE ; [.2041.0020.0002.14EE] # CANADIAN SYLLABICS SAAI +14EF ; [.2042.0020.0002.14EF] # CANADIAN SYLLABICS SI +14F0 ; [.2043.0020.0002.14F0] # CANADIAN SYLLABICS SII +14F1 ; [.2044.0020.0002.14F1] # CANADIAN SYLLABICS SO +14F2 ; [.2045.0020.0002.14F2] # CANADIAN SYLLABICS SOO +14F3 ; [.2046.0020.0002.14F3] # CANADIAN SYLLABICS Y-CREE SOO +14F4 ; [.2047.0020.0002.14F4] # CANADIAN SYLLABICS SA +14F5 ; [.2048.0020.0002.14F5] # CANADIAN SYLLABICS SAA +14F6 ; [.2049.0020.0002.14F6] # CANADIAN SYLLABICS SWE +14F7 ; [.204A.0020.0002.14F7] # CANADIAN SYLLABICS WEST-CREE SWE +14F8 ; [.204B.0020.0002.14F8] # CANADIAN SYLLABICS SWI +14F9 ; [.204C.0020.0002.14F9] # CANADIAN SYLLABICS WEST-CREE SWI +14FA ; [.204D.0020.0002.14FA] # CANADIAN SYLLABICS SWII +14FB ; [.204E.0020.0002.14FB] # CANADIAN SYLLABICS WEST-CREE SWII +14FC ; [.204F.0020.0002.14FC] # CANADIAN SYLLABICS SWO +14FD ; [.2050.0020.0002.14FD] # CANADIAN SYLLABICS WEST-CREE SWO +14FE ; [.2051.0020.0002.14FE] # CANADIAN SYLLABICS SWOO +14FF ; [.2052.0020.0002.14FF] # CANADIAN SYLLABICS WEST-CREE SWOO +1500 ; [.2053.0020.0002.1500] # CANADIAN SYLLABICS SWA +1501 ; [.2054.0020.0002.1501] # CANADIAN SYLLABICS WEST-CREE SWA +1502 ; [.2055.0020.0002.1502] # CANADIAN SYLLABICS SWAA +1503 ; [.2056.0020.0002.1503] # CANADIAN SYLLABICS WEST-CREE SWAA +1504 ; [.2057.0020.0002.1504] # CANADIAN SYLLABICS NASKAPI SWAA +1505 ; [.2058.0020.0002.1505] # CANADIAN SYLLABICS S +1506 ; [.2059.0020.0002.1506] # CANADIAN SYLLABICS ATHAPASCAN S +1507 ; [.205A.0020.0002.1507] # CANADIAN SYLLABICS SW +1508 ; [.205B.0020.0002.1508] # CANADIAN SYLLABICS BLACKFOOT S +1509 ; [.205C.0020.0002.1509] # CANADIAN SYLLABICS MOOSE-CREE SK +150A ; [.205D.0020.0002.150A] # CANADIAN SYLLABICS NASKAPI SKW +150B ; [.205E.0020.0002.150B] # CANADIAN SYLLABICS NASKAPI S-W +150C ; [.205F.0020.0002.150C] # CANADIAN SYLLABICS NASKAPI SPWA +150D ; [.2060.0020.0002.150D] # CANADIAN SYLLABICS NASKAPI STWA +150E ; [.2061.0020.0002.150E] # CANADIAN SYLLABICS NASKAPI SKWA +150F ; [.2062.0020.0002.150F] # CANADIAN SYLLABICS NASKAPI SCWA +1510 ; [.2063.0020.0002.1510] # CANADIAN SYLLABICS SHE +1511 ; [.2064.0020.0002.1511] # CANADIAN SYLLABICS SHI +1512 ; [.2065.0020.0002.1512] # CANADIAN SYLLABICS SHII +1513 ; [.2066.0020.0002.1513] # CANADIAN SYLLABICS SHO +1514 ; [.2067.0020.0002.1514] # CANADIAN SYLLABICS SHOO +1515 ; [.2068.0020.0002.1515] # CANADIAN SYLLABICS SHA +1516 ; [.2069.0020.0002.1516] # CANADIAN SYLLABICS SHAA +1517 ; [.206A.0020.0002.1517] # CANADIAN SYLLABICS SHWE +1518 ; [.206B.0020.0002.1518] # CANADIAN SYLLABICS WEST-CREE SHWE +1519 ; [.206C.0020.0002.1519] # CANADIAN SYLLABICS SHWI +151A ; [.206D.0020.0002.151A] # CANADIAN SYLLABICS WEST-CREE SHWI +151B ; [.206E.0020.0002.151B] # CANADIAN SYLLABICS SHWII +151C ; [.206F.0020.0002.151C] # CANADIAN SYLLABICS WEST-CREE SHWII +151D ; [.2070.0020.0002.151D] # CANADIAN SYLLABICS SHWO +151E ; [.2071.0020.0002.151E] # CANADIAN SYLLABICS WEST-CREE SHWO +151F ; [.2072.0020.0002.151F] # CANADIAN SYLLABICS SHWOO +1520 ; [.2073.0020.0002.1520] # CANADIAN SYLLABICS WEST-CREE SHWOO +1521 ; [.2074.0020.0002.1521] # CANADIAN SYLLABICS SHWA +1522 ; [.2075.0020.0002.1522] # CANADIAN SYLLABICS WEST-CREE SHWA +1523 ; [.2076.0020.0002.1523] # CANADIAN SYLLABICS SHWAA +1524 ; [.2077.0020.0002.1524] # CANADIAN SYLLABICS WEST-CREE SHWAA +1525 ; [.2078.0020.0002.1525] # CANADIAN SYLLABICS SH +1526 ; [.2079.0020.0002.1526] # CANADIAN SYLLABICS YE +1527 ; [.207A.0020.0002.1527] # CANADIAN SYLLABICS YAAI +1528 ; [.207B.0020.0002.1528] # CANADIAN SYLLABICS YI +1529 ; [.207C.0020.0002.1529] # CANADIAN SYLLABICS YII +152A ; [.207D.0020.0002.152A] # CANADIAN SYLLABICS YO +152B ; [.207E.0020.0002.152B] # CANADIAN SYLLABICS YOO +152C ; [.207F.0020.0002.152C] # CANADIAN SYLLABICS Y-CREE YOO +152D ; [.2080.0020.0002.152D] # CANADIAN SYLLABICS YA +152E ; [.2081.0020.0002.152E] # CANADIAN SYLLABICS YAA +152F ; [.2082.0020.0002.152F] # CANADIAN SYLLABICS YWE +1530 ; [.2083.0020.0002.1530] # CANADIAN SYLLABICS WEST-CREE YWE +1531 ; [.2084.0020.0002.1531] # CANADIAN SYLLABICS YWI +1532 ; [.2085.0020.0002.1532] # CANADIAN SYLLABICS WEST-CREE YWI +1533 ; [.2086.0020.0002.1533] # CANADIAN SYLLABICS YWII +1534 ; [.2087.0020.0002.1534] # CANADIAN SYLLABICS WEST-CREE YWII +1535 ; [.2088.0020.0002.1535] # CANADIAN SYLLABICS YWO +1536 ; [.2089.0020.0002.1536] # CANADIAN SYLLABICS WEST-CREE YWO +1537 ; [.208A.0020.0002.1537] # CANADIAN SYLLABICS YWOO +1538 ; [.208B.0020.0002.1538] # CANADIAN SYLLABICS WEST-CREE YWOO +1539 ; [.208C.0020.0002.1539] # CANADIAN SYLLABICS YWA +153A ; [.208D.0020.0002.153A] # CANADIAN SYLLABICS WEST-CREE YWA +153B ; [.208E.0020.0002.153B] # CANADIAN SYLLABICS YWAA +153C ; [.208F.0020.0002.153C] # CANADIAN SYLLABICS WEST-CREE YWAA +153D ; [.2090.0020.0002.153D] # CANADIAN SYLLABICS NASKAPI YWAA +153E ; [.2091.0020.0002.153E] # CANADIAN SYLLABICS Y +153F ; [.2092.0020.0002.153F] # CANADIAN SYLLABICS BIBLE-CREE Y +1540 ; [.2093.0020.0002.1540] # CANADIAN SYLLABICS WEST-CREE Y +1541 ; [.2094.0020.0002.1541] # CANADIAN SYLLABICS SAYISI YI +1542 ; [.2095.0020.0002.1542] # CANADIAN SYLLABICS RE +1543 ; [.2096.0020.0002.1543] # CANADIAN SYLLABICS R-CREE RE +1544 ; [.2097.0020.0002.1544] # CANADIAN SYLLABICS WEST-CREE LE +1545 ; [.2098.0020.0002.1545] # CANADIAN SYLLABICS RAAI +1546 ; [.2099.0020.0002.1546] # CANADIAN SYLLABICS RI +1547 ; [.209A.0020.0002.1547] # CANADIAN SYLLABICS RII +1548 ; [.209B.0020.0002.1548] # CANADIAN SYLLABICS RO +1549 ; [.209C.0020.0002.1549] # CANADIAN SYLLABICS ROO +154A ; [.209D.0020.0002.154A] # CANADIAN SYLLABICS WEST-CREE LO +154B ; [.209E.0020.0002.154B] # CANADIAN SYLLABICS RA +154C ; [.209F.0020.0002.154C] # CANADIAN SYLLABICS RAA +154D ; [.20A0.0020.0002.154D] # CANADIAN SYLLABICS WEST-CREE LA +154E ; [.20A1.0020.0002.154E] # CANADIAN SYLLABICS RWAA +154F ; [.20A2.0020.0002.154F] # CANADIAN SYLLABICS WEST-CREE RWAA +1550 ; [.20A3.0020.0002.1550] # CANADIAN SYLLABICS R +1551 ; [.20A4.0020.0002.1551] # CANADIAN SYLLABICS WEST-CREE R +1552 ; [.20A5.0020.0002.1552] # CANADIAN SYLLABICS MEDIAL R +1553 ; [.20A6.0020.0002.1553] # CANADIAN SYLLABICS FE +1554 ; [.20A7.0020.0002.1554] # CANADIAN SYLLABICS FAAI +1555 ; [.20A8.0020.0002.1555] # CANADIAN SYLLABICS FI +1556 ; [.20A9.0020.0002.1556] # CANADIAN SYLLABICS FII +1557 ; [.20AA.0020.0002.1557] # CANADIAN SYLLABICS FO +1558 ; [.20AB.0020.0002.1558] # CANADIAN SYLLABICS FOO +1559 ; [.20AC.0020.0002.1559] # CANADIAN SYLLABICS FA +155A ; [.20AD.0020.0002.155A] # CANADIAN SYLLABICS FAA +155B ; [.20AE.0020.0002.155B] # CANADIAN SYLLABICS FWAA +155C ; [.20AF.0020.0002.155C] # CANADIAN SYLLABICS WEST-CREE FWAA +155D ; [.20B0.0020.0002.155D] # CANADIAN SYLLABICS F +155E ; [.20B1.0020.0002.155E] # CANADIAN SYLLABICS THE +155F ; [.20B2.0020.0002.155F] # CANADIAN SYLLABICS N-CREE THE +1560 ; [.20B3.0020.0002.1560] # CANADIAN SYLLABICS THI +1561 ; [.20B4.0020.0002.1561] # CANADIAN SYLLABICS N-CREE THI +1562 ; [.20B5.0020.0002.1562] # CANADIAN SYLLABICS THII +1563 ; [.20B6.0020.0002.1563] # CANADIAN SYLLABICS N-CREE THII +1564 ; [.20B7.0020.0002.1564] # CANADIAN SYLLABICS THO +1565 ; [.20B8.0020.0002.1565] # CANADIAN SYLLABICS THOO +1566 ; [.20B9.0020.0002.1566] # CANADIAN SYLLABICS THA +1567 ; [.20BA.0020.0002.1567] # CANADIAN SYLLABICS THAA +1568 ; [.20BB.0020.0002.1568] # CANADIAN SYLLABICS THWAA +1569 ; [.20BC.0020.0002.1569] # CANADIAN SYLLABICS WEST-CREE THWAA +156A ; [.20BD.0020.0002.156A] # CANADIAN SYLLABICS TH +156B ; [.20BE.0020.0002.156B] # CANADIAN SYLLABICS TTHE +156C ; [.20BF.0020.0002.156C] # CANADIAN SYLLABICS TTHI +156D ; [.20C0.0020.0002.156D] # CANADIAN SYLLABICS TTHO +156E ; [.20C1.0020.0002.156E] # CANADIAN SYLLABICS TTHA +156F ; [.20C2.0020.0002.156F] # CANADIAN SYLLABICS TTH +1570 ; [.20C3.0020.0002.1570] # CANADIAN SYLLABICS TYE +1571 ; [.20C4.0020.0002.1571] # CANADIAN SYLLABICS TYI +1572 ; [.20C5.0020.0002.1572] # CANADIAN SYLLABICS TYO +1573 ; [.20C6.0020.0002.1573] # CANADIAN SYLLABICS TYA +1574 ; [.20C7.0020.0002.1574] # CANADIAN SYLLABICS NUNAVIK HE +1575 ; [.20C8.0020.0002.1575] # CANADIAN SYLLABICS NUNAVIK HI +1576 ; [.20C9.0020.0002.1576] # CANADIAN SYLLABICS NUNAVIK HII +1577 ; [.20CA.0020.0002.1577] # CANADIAN SYLLABICS NUNAVIK HO +1578 ; [.20CB.0020.0002.1578] # CANADIAN SYLLABICS NUNAVIK HOO +1579 ; [.20CC.0020.0002.1579] # CANADIAN SYLLABICS NUNAVIK HA +157A ; [.20CD.0020.0002.157A] # CANADIAN SYLLABICS NUNAVIK HAA +157B ; [.20CE.0020.0002.157B] # CANADIAN SYLLABICS NUNAVIK H +157D ; [.20CF.0020.0002.157D] # CANADIAN SYLLABICS HK +166F ; [.20D0.0020.0002.166F] # CANADIAN SYLLABICS QAI +157E ; [.20D1.0020.0002.157E] # CANADIAN SYLLABICS QAAI +157F ; [.20D2.0020.0002.157F] # CANADIAN SYLLABICS QI +1580 ; [.20D3.0020.0002.1580] # CANADIAN SYLLABICS QII +1581 ; [.20D4.0020.0002.1581] # CANADIAN SYLLABICS QO +1582 ; [.20D5.0020.0002.1582] # CANADIAN SYLLABICS QOO +1583 ; [.20D6.0020.0002.1583] # CANADIAN SYLLABICS QA +1584 ; [.20D7.0020.0002.1584] # CANADIAN SYLLABICS QAA +1585 ; [.20D8.0020.0002.1585] # CANADIAN SYLLABICS Q +1586 ; [.20D9.0020.0002.1586] # CANADIAN SYLLABICS TLHE +1587 ; [.20DA.0020.0002.1587] # CANADIAN SYLLABICS TLHI +1588 ; [.20DB.0020.0002.1588] # CANADIAN SYLLABICS TLHO +1589 ; [.20DC.0020.0002.1589] # CANADIAN SYLLABICS TLHA +158A ; [.20DD.0020.0002.158A] # CANADIAN SYLLABICS WEST-CREE RE +158B ; [.20DE.0020.0002.158B] # CANADIAN SYLLABICS WEST-CREE RI +158C ; [.20DF.0020.0002.158C] # CANADIAN SYLLABICS WEST-CREE RO +158D ; [.20E0.0020.0002.158D] # CANADIAN SYLLABICS WEST-CREE RA +1670 ; [.20E1.0020.0002.1670] # CANADIAN SYLLABICS NGAI +158E ; [.20E2.0020.0002.158E] # CANADIAN SYLLABICS NGAAI +158F ; [.20E3.0020.0002.158F] # CANADIAN SYLLABICS NGI +1590 ; [.20E4.0020.0002.1590] # CANADIAN SYLLABICS NGII +1591 ; [.20E5.0020.0002.1591] # CANADIAN SYLLABICS NGO +1592 ; [.20E6.0020.0002.1592] # CANADIAN SYLLABICS NGOO +1593 ; [.20E7.0020.0002.1593] # CANADIAN SYLLABICS NGA +1594 ; [.20E8.0020.0002.1594] # CANADIAN SYLLABICS NGAA +1595 ; [.20E9.0020.0002.1595] # CANADIAN SYLLABICS NG +1671 ; [.20EA.0020.0002.1671] # CANADIAN SYLLABICS NNGI +1672 ; [.20EB.0020.0002.1672] # CANADIAN SYLLABICS NNGII +1673 ; [.20EC.0020.0002.1673] # CANADIAN SYLLABICS NNGO +1674 ; [.20ED.0020.0002.1674] # CANADIAN SYLLABICS NNGOO +1675 ; [.20EE.0020.0002.1675] # CANADIAN SYLLABICS NNGA +1676 ; [.20EF.0020.0002.1676] # CANADIAN SYLLABICS NNGAA +1596 ; [.20F0.0020.0002.1596] # CANADIAN SYLLABICS NNG +1597 ; [.20F1.0020.0002.1597] # CANADIAN SYLLABICS SAYISI SHE +1598 ; [.20F2.0020.0002.1598] # CANADIAN SYLLABICS SAYISI SHI +1599 ; [.20F3.0020.0002.1599] # CANADIAN SYLLABICS SAYISI SHO +159A ; [.20F4.0020.0002.159A] # CANADIAN SYLLABICS SAYISI SHA +159B ; [.20F5.0020.0002.159B] # CANADIAN SYLLABICS WOODS-CREE THE +159C ; [.20F6.0020.0002.159C] # CANADIAN SYLLABICS WOODS-CREE THI +159D ; [.20F7.0020.0002.159D] # CANADIAN SYLLABICS WOODS-CREE THO +159E ; [.20F8.0020.0002.159E] # CANADIAN SYLLABICS WOODS-CREE THA +159F ; [.20F9.0020.0002.159F] # CANADIAN SYLLABICS WOODS-CREE TH +15A0 ; [.20FA.0020.0002.15A0] # CANADIAN SYLLABICS LHI +15A1 ; [.20FB.0020.0002.15A1] # CANADIAN SYLLABICS LHII +15A2 ; [.20FC.0020.0002.15A2] # CANADIAN SYLLABICS LHO +15A3 ; [.20FD.0020.0002.15A3] # CANADIAN SYLLABICS LHOO +15A4 ; [.20FE.0020.0002.15A4] # CANADIAN SYLLABICS LHA +15A5 ; [.20FF.0020.0002.15A5] # CANADIAN SYLLABICS LHAA +15A6 ; [.2100.0020.0002.15A6] # CANADIAN SYLLABICS LH +157C ; [.2101.0020.0002.157C] # CANADIAN SYLLABICS NUNAVUT H +15A7 ; [.2102.0020.0002.15A7] # CANADIAN SYLLABICS TH-CREE THE +15A8 ; [.2103.0020.0002.15A8] # CANADIAN SYLLABICS TH-CREE THI +15A9 ; [.2104.0020.0002.15A9] # CANADIAN SYLLABICS TH-CREE THII +15AA ; [.2105.0020.0002.15AA] # CANADIAN SYLLABICS TH-CREE THO +15AB ; [.2106.0020.0002.15AB] # CANADIAN SYLLABICS TH-CREE THOO +15AC ; [.2107.0020.0002.15AC] # CANADIAN SYLLABICS TH-CREE THA +15AD ; [.2108.0020.0002.15AD] # CANADIAN SYLLABICS TH-CREE THAA +15AE ; [.2109.0020.0002.15AE] # CANADIAN SYLLABICS TH-CREE TH +15AF ; [.210A.0020.0002.15AF] # CANADIAN SYLLABICS AIVILIK B +15B0 ; [.210B.0020.0002.15B0] # CANADIAN SYLLABICS BLACKFOOT E +15B1 ; [.210C.0020.0002.15B1] # CANADIAN SYLLABICS BLACKFOOT I +15B2 ; [.210D.0020.0002.15B2] # CANADIAN SYLLABICS BLACKFOOT O +15B3 ; [.210E.0020.0002.15B3] # CANADIAN SYLLABICS BLACKFOOT A +15B4 ; [.210F.0020.0002.15B4] # CANADIAN SYLLABICS BLACKFOOT WE +15B5 ; [.2110.0020.0002.15B5] # CANADIAN SYLLABICS BLACKFOOT WI +15B6 ; [.2111.0020.0002.15B6] # CANADIAN SYLLABICS BLACKFOOT WO +15B7 ; [.2112.0020.0002.15B7] # CANADIAN SYLLABICS BLACKFOOT WA +15B8 ; [.2113.0020.0002.15B8] # CANADIAN SYLLABICS BLACKFOOT NE +15B9 ; [.2114.0020.0002.15B9] # CANADIAN SYLLABICS BLACKFOOT NI +15BA ; [.2115.0020.0002.15BA] # CANADIAN SYLLABICS BLACKFOOT NO +15BB ; [.2116.0020.0002.15BB] # CANADIAN SYLLABICS BLACKFOOT NA +15BC ; [.2117.0020.0002.15BC] # CANADIAN SYLLABICS BLACKFOOT KE +15BD ; [.2118.0020.0002.15BD] # CANADIAN SYLLABICS BLACKFOOT KI +15BE ; [.2119.0020.0002.15BE] # CANADIAN SYLLABICS BLACKFOOT KO +15BF ; [.211A.0020.0002.15BF] # CANADIAN SYLLABICS BLACKFOOT KA +15C0 ; [.211B.0020.0002.15C0] # CANADIAN SYLLABICS SAYISI HE +15C1 ; [.211C.0020.0002.15C1] # CANADIAN SYLLABICS SAYISI HI +15C2 ; [.211D.0020.0002.15C2] # CANADIAN SYLLABICS SAYISI HO +15C3 ; [.211E.0020.0002.15C3] # CANADIAN SYLLABICS SAYISI HA +15C4 ; [.211F.0020.0002.15C4] # CANADIAN SYLLABICS CARRIER GHU +15C5 ; [.2120.0020.0002.15C5] # CANADIAN SYLLABICS CARRIER GHO +15C6 ; [.2121.0020.0002.15C6] # CANADIAN SYLLABICS CARRIER GHE +15C7 ; [.2122.0020.0002.15C7] # CANADIAN SYLLABICS CARRIER GHEE +15C8 ; [.2123.0020.0002.15C8] # CANADIAN SYLLABICS CARRIER GHI +15C9 ; [.2124.0020.0002.15C9] # CANADIAN SYLLABICS CARRIER GHA +15CA ; [.2125.0020.0002.15CA] # CANADIAN SYLLABICS CARRIER RU +15CB ; [.2126.0020.0002.15CB] # CANADIAN SYLLABICS CARRIER RO +15CC ; [.2127.0020.0002.15CC] # CANADIAN SYLLABICS CARRIER RE +15CD ; [.2128.0020.0002.15CD] # CANADIAN SYLLABICS CARRIER REE +15CE ; [.2129.0020.0002.15CE] # CANADIAN SYLLABICS CARRIER RI +15CF ; [.212A.0020.0002.15CF] # CANADIAN SYLLABICS CARRIER RA +15D0 ; [.212B.0020.0002.15D0] # CANADIAN SYLLABICS CARRIER WU +15D1 ; [.212C.0020.0002.15D1] # CANADIAN SYLLABICS CARRIER WO +15D2 ; [.212D.0020.0002.15D2] # CANADIAN SYLLABICS CARRIER WE +15D3 ; [.212E.0020.0002.15D3] # CANADIAN SYLLABICS CARRIER WEE +15D4 ; [.212F.0020.0002.15D4] # CANADIAN SYLLABICS CARRIER WI +15D5 ; [.2130.0020.0002.15D5] # CANADIAN SYLLABICS CARRIER WA +15D6 ; [.2131.0020.0002.15D6] # CANADIAN SYLLABICS CARRIER HWU +15D7 ; [.2132.0020.0002.15D7] # CANADIAN SYLLABICS CARRIER HWO +15D8 ; [.2133.0020.0002.15D8] # CANADIAN SYLLABICS CARRIER HWE +15D9 ; [.2134.0020.0002.15D9] # CANADIAN SYLLABICS CARRIER HWEE +15DA ; [.2135.0020.0002.15DA] # CANADIAN SYLLABICS CARRIER HWI +15DB ; [.2136.0020.0002.15DB] # CANADIAN SYLLABICS CARRIER HWA +15DC ; [.2137.0020.0002.15DC] # CANADIAN SYLLABICS CARRIER THU +15DD ; [.2138.0020.0002.15DD] # CANADIAN SYLLABICS CARRIER THO +15DE ; [.2139.0020.0002.15DE] # CANADIAN SYLLABICS CARRIER THE +15DF ; [.213A.0020.0002.15DF] # CANADIAN SYLLABICS CARRIER THEE +15E0 ; [.213B.0020.0002.15E0] # CANADIAN SYLLABICS CARRIER THI +15E1 ; [.213C.0020.0002.15E1] # CANADIAN SYLLABICS CARRIER THA +15E2 ; [.213D.0020.0002.15E2] # CANADIAN SYLLABICS CARRIER TTU +15E3 ; [.213E.0020.0002.15E3] # CANADIAN SYLLABICS CARRIER TTO +15E4 ; [.213F.0020.0002.15E4] # CANADIAN SYLLABICS CARRIER TTE +15E5 ; [.2140.0020.0002.15E5] # CANADIAN SYLLABICS CARRIER TTEE +15E6 ; [.2141.0020.0002.15E6] # CANADIAN SYLLABICS CARRIER TTI +15E7 ; [.2142.0020.0002.15E7] # CANADIAN SYLLABICS CARRIER TTA +15E8 ; [.2143.0020.0002.15E8] # CANADIAN SYLLABICS CARRIER PU +15E9 ; [.2144.0020.0002.15E9] # CANADIAN SYLLABICS CARRIER PO +15EA ; [.2145.0020.0002.15EA] # CANADIAN SYLLABICS CARRIER PE +15EB ; [.2146.0020.0002.15EB] # CANADIAN SYLLABICS CARRIER PEE +15EC ; [.2147.0020.0002.15EC] # CANADIAN SYLLABICS CARRIER PI +15ED ; [.2148.0020.0002.15ED] # CANADIAN SYLLABICS CARRIER PA +15EE ; [.2149.0020.0002.15EE] # CANADIAN SYLLABICS CARRIER P +15EF ; [.214A.0020.0002.15EF] # CANADIAN SYLLABICS CARRIER GU +15F0 ; [.214B.0020.0002.15F0] # CANADIAN SYLLABICS CARRIER GO +15F1 ; [.214C.0020.0002.15F1] # CANADIAN SYLLABICS CARRIER GE +15F2 ; [.214D.0020.0002.15F2] # CANADIAN SYLLABICS CARRIER GEE +15F3 ; [.214E.0020.0002.15F3] # CANADIAN SYLLABICS CARRIER GI +15F4 ; [.214F.0020.0002.15F4] # CANADIAN SYLLABICS CARRIER GA +15F5 ; [.2150.0020.0002.15F5] # CANADIAN SYLLABICS CARRIER KHU +15F6 ; [.2151.0020.0002.15F6] # CANADIAN SYLLABICS CARRIER KHO +15F7 ; [.2152.0020.0002.15F7] # CANADIAN SYLLABICS CARRIER KHE +15F8 ; [.2153.0020.0002.15F8] # CANADIAN SYLLABICS CARRIER KHEE +15F9 ; [.2154.0020.0002.15F9] # CANADIAN SYLLABICS CARRIER KHI +15FA ; [.2155.0020.0002.15FA] # CANADIAN SYLLABICS CARRIER KHA +15FB ; [.2156.0020.0002.15FB] # CANADIAN SYLLABICS CARRIER KKU +15FC ; [.2157.0020.0002.15FC] # CANADIAN SYLLABICS CARRIER KKO +15FD ; [.2158.0020.0002.15FD] # CANADIAN SYLLABICS CARRIER KKE +15FE ; [.2159.0020.0002.15FE] # CANADIAN SYLLABICS CARRIER KKEE +15FF ; [.215A.0020.0002.15FF] # CANADIAN SYLLABICS CARRIER KKI +1600 ; [.215B.0020.0002.1600] # CANADIAN SYLLABICS CARRIER KKA +1601 ; [.215C.0020.0002.1601] # CANADIAN SYLLABICS CARRIER KK +1602 ; [.215D.0020.0002.1602] # CANADIAN SYLLABICS CARRIER NU +1603 ; [.215E.0020.0002.1603] # CANADIAN SYLLABICS CARRIER NO +1604 ; [.215F.0020.0002.1604] # CANADIAN SYLLABICS CARRIER NE +1605 ; [.2160.0020.0002.1605] # CANADIAN SYLLABICS CARRIER NEE +1606 ; [.2161.0020.0002.1606] # CANADIAN SYLLABICS CARRIER NI +1607 ; [.2162.0020.0002.1607] # CANADIAN SYLLABICS CARRIER NA +1608 ; [.2163.0020.0002.1608] # CANADIAN SYLLABICS CARRIER MU +1609 ; [.2164.0020.0002.1609] # CANADIAN SYLLABICS CARRIER MO +160A ; [.2165.0020.0002.160A] # CANADIAN SYLLABICS CARRIER ME +160B ; [.2166.0020.0002.160B] # CANADIAN SYLLABICS CARRIER MEE +160C ; [.2167.0020.0002.160C] # CANADIAN SYLLABICS CARRIER MI +160D ; [.2168.0020.0002.160D] # CANADIAN SYLLABICS CARRIER MA +160E ; [.2169.0020.0002.160E] # CANADIAN SYLLABICS CARRIER YU +160F ; [.216A.0020.0002.160F] # CANADIAN SYLLABICS CARRIER YO +1610 ; [.216B.0020.0002.1610] # CANADIAN SYLLABICS CARRIER YE +1611 ; [.216C.0020.0002.1611] # CANADIAN SYLLABICS CARRIER YEE +1612 ; [.216D.0020.0002.1612] # CANADIAN SYLLABICS CARRIER YI +1613 ; [.216E.0020.0002.1613] # CANADIAN SYLLABICS CARRIER YA +1614 ; [.216F.0020.0002.1614] # CANADIAN SYLLABICS CARRIER JU +1615 ; [.2170.0020.0002.1615] # CANADIAN SYLLABICS SAYISI JU +1616 ; [.2171.0020.0002.1616] # CANADIAN SYLLABICS CARRIER JO +1617 ; [.2172.0020.0002.1617] # CANADIAN SYLLABICS CARRIER JE +1618 ; [.2173.0020.0002.1618] # CANADIAN SYLLABICS CARRIER JEE +1619 ; [.2174.0020.0002.1619] # CANADIAN SYLLABICS CARRIER JI +161A ; [.2175.0020.0002.161A] # CANADIAN SYLLABICS SAYISI JI +161B ; [.2176.0020.0002.161B] # CANADIAN SYLLABICS CARRIER JA +161C ; [.2177.0020.0002.161C] # CANADIAN SYLLABICS CARRIER JJU +161D ; [.2178.0020.0002.161D] # CANADIAN SYLLABICS CARRIER JJO +161E ; [.2179.0020.0002.161E] # CANADIAN SYLLABICS CARRIER JJE +161F ; [.217A.0020.0002.161F] # CANADIAN SYLLABICS CARRIER JJEE +1620 ; [.217B.0020.0002.1620] # CANADIAN SYLLABICS CARRIER JJI +1621 ; [.217C.0020.0002.1621] # CANADIAN SYLLABICS CARRIER JJA +1622 ; [.217D.0020.0002.1622] # CANADIAN SYLLABICS CARRIER LU +1623 ; [.217E.0020.0002.1623] # CANADIAN SYLLABICS CARRIER LO +1624 ; [.217F.0020.0002.1624] # CANADIAN SYLLABICS CARRIER LE +1625 ; [.2180.0020.0002.1625] # CANADIAN SYLLABICS CARRIER LEE +1626 ; [.2181.0020.0002.1626] # CANADIAN SYLLABICS CARRIER LI +1627 ; [.2182.0020.0002.1627] # CANADIAN SYLLABICS CARRIER LA +1628 ; [.2183.0020.0002.1628] # CANADIAN SYLLABICS CARRIER DLU +1629 ; [.2184.0020.0002.1629] # CANADIAN SYLLABICS CARRIER DLO +162A ; [.2185.0020.0002.162A] # CANADIAN SYLLABICS CARRIER DLE +162B ; [.2186.0020.0002.162B] # CANADIAN SYLLABICS CARRIER DLEE +162C ; [.2187.0020.0002.162C] # CANADIAN SYLLABICS CARRIER DLI +162D ; [.2188.0020.0002.162D] # CANADIAN SYLLABICS CARRIER DLA +162E ; [.2189.0020.0002.162E] # CANADIAN SYLLABICS CARRIER LHU +162F ; [.218A.0020.0002.162F] # CANADIAN SYLLABICS CARRIER LHO +1630 ; [.218B.0020.0002.1630] # CANADIAN SYLLABICS CARRIER LHE +1631 ; [.218C.0020.0002.1631] # CANADIAN SYLLABICS CARRIER LHEE +1632 ; [.218D.0020.0002.1632] # CANADIAN SYLLABICS CARRIER LHI +1633 ; [.218E.0020.0002.1633] # CANADIAN SYLLABICS CARRIER LHA +1634 ; [.218F.0020.0002.1634] # CANADIAN SYLLABICS CARRIER TLHU +1635 ; [.2190.0020.0002.1635] # CANADIAN SYLLABICS CARRIER TLHO +1636 ; [.2191.0020.0002.1636] # CANADIAN SYLLABICS CARRIER TLHE +1637 ; [.2192.0020.0002.1637] # CANADIAN SYLLABICS CARRIER TLHEE +1638 ; [.2193.0020.0002.1638] # CANADIAN SYLLABICS CARRIER TLHI +1639 ; [.2194.0020.0002.1639] # CANADIAN SYLLABICS CARRIER TLHA +163A ; [.2195.0020.0002.163A] # CANADIAN SYLLABICS CARRIER TLU +163B ; [.2196.0020.0002.163B] # CANADIAN SYLLABICS CARRIER TLO +163C ; [.2197.0020.0002.163C] # CANADIAN SYLLABICS CARRIER TLE +163D ; [.2198.0020.0002.163D] # CANADIAN SYLLABICS CARRIER TLEE +163E ; [.2199.0020.0002.163E] # CANADIAN SYLLABICS CARRIER TLI +163F ; [.219A.0020.0002.163F] # CANADIAN SYLLABICS CARRIER TLA +1640 ; [.219B.0020.0002.1640] # CANADIAN SYLLABICS CARRIER ZU +1641 ; [.219C.0020.0002.1641] # CANADIAN SYLLABICS CARRIER ZO +1642 ; [.219D.0020.0002.1642] # CANADIAN SYLLABICS CARRIER ZE +1643 ; [.219E.0020.0002.1643] # CANADIAN SYLLABICS CARRIER ZEE +1644 ; [.219F.0020.0002.1644] # CANADIAN SYLLABICS CARRIER ZI +1645 ; [.21A0.0020.0002.1645] # CANADIAN SYLLABICS CARRIER ZA +1646 ; [.21A1.0020.0002.1646] # CANADIAN SYLLABICS CARRIER Z +1647 ; [.21A2.0020.0002.1647] # CANADIAN SYLLABICS CARRIER INITIAL Z +1648 ; [.21A3.0020.0002.1648] # CANADIAN SYLLABICS CARRIER DZU +1649 ; [.21A4.0020.0002.1649] # CANADIAN SYLLABICS CARRIER DZO +164A ; [.21A5.0020.0002.164A] # CANADIAN SYLLABICS CARRIER DZE +164B ; [.21A6.0020.0002.164B] # CANADIAN SYLLABICS CARRIER DZEE +164C ; [.21A7.0020.0002.164C] # CANADIAN SYLLABICS CARRIER DZI +164D ; [.21A8.0020.0002.164D] # CANADIAN SYLLABICS CARRIER DZA +164E ; [.21A9.0020.0002.164E] # CANADIAN SYLLABICS CARRIER SU +164F ; [.21AA.0020.0002.164F] # CANADIAN SYLLABICS CARRIER SO +1650 ; [.21AB.0020.0002.1650] # CANADIAN SYLLABICS CARRIER SE +1651 ; [.21AC.0020.0002.1651] # CANADIAN SYLLABICS CARRIER SEE +1652 ; [.21AD.0020.0002.1652] # CANADIAN SYLLABICS CARRIER SI +1653 ; [.21AE.0020.0002.1653] # CANADIAN SYLLABICS CARRIER SA +1654 ; [.21AF.0020.0002.1654] # CANADIAN SYLLABICS CARRIER SHU +1655 ; [.21B0.0020.0002.1655] # CANADIAN SYLLABICS CARRIER SHO +1656 ; [.21B1.0020.0002.1656] # CANADIAN SYLLABICS CARRIER SHE +1657 ; [.21B2.0020.0002.1657] # CANADIAN SYLLABICS CARRIER SHEE +1658 ; [.21B3.0020.0002.1658] # CANADIAN SYLLABICS CARRIER SHI +1659 ; [.21B4.0020.0002.1659] # CANADIAN SYLLABICS CARRIER SHA +165A ; [.21B5.0020.0002.165A] # CANADIAN SYLLABICS CARRIER SH +165B ; [.21B6.0020.0002.165B] # CANADIAN SYLLABICS CARRIER TSU +165C ; [.21B7.0020.0002.165C] # CANADIAN SYLLABICS CARRIER TSO +165D ; [.21B8.0020.0002.165D] # CANADIAN SYLLABICS CARRIER TSE +165E ; [.21B9.0020.0002.165E] # CANADIAN SYLLABICS CARRIER TSEE +165F ; [.21BA.0020.0002.165F] # CANADIAN SYLLABICS CARRIER TSI +1660 ; [.21BB.0020.0002.1660] # CANADIAN SYLLABICS CARRIER TSA +1661 ; [.21BC.0020.0002.1661] # CANADIAN SYLLABICS CARRIER CHU +1662 ; [.21BD.0020.0002.1662] # CANADIAN SYLLABICS CARRIER CHO +1663 ; [.21BE.0020.0002.1663] # CANADIAN SYLLABICS CARRIER CHE +1664 ; [.21BF.0020.0002.1664] # CANADIAN SYLLABICS CARRIER CHEE +1665 ; [.21C0.0020.0002.1665] # CANADIAN SYLLABICS CARRIER CHI +1666 ; [.21C1.0020.0002.1666] # CANADIAN SYLLABICS CARRIER CHA +1667 ; [.21C2.0020.0002.1667] # CANADIAN SYLLABICS CARRIER TTSU +1668 ; [.21C3.0020.0002.1668] # CANADIAN SYLLABICS CARRIER TTSO +1669 ; [.21C4.0020.0002.1669] # CANADIAN SYLLABICS CARRIER TTSE +166A ; [.21C5.0020.0002.166A] # CANADIAN SYLLABICS CARRIER TTSEE +166B ; [.21C6.0020.0002.166B] # CANADIAN SYLLABICS CARRIER TTSI +166C ; [.21C7.0020.0002.166C] # CANADIAN SYLLABICS CARRIER TTSA +1681 ; [.21C8.0020.0002.1681] # OGHAM LETTER BEITH +1682 ; [.21C9.0020.0002.1682] # OGHAM LETTER LUIS +1683 ; [.21CA.0020.0002.1683] # OGHAM LETTER FEARN +1684 ; [.21CB.0020.0002.1684] # OGHAM LETTER SAIL +1685 ; [.21CC.0020.0002.1685] # OGHAM LETTER NION +1686 ; [.21CD.0020.0002.1686] # OGHAM LETTER UATH +1687 ; [.21CE.0020.0002.1687] # OGHAM LETTER DAIR +1688 ; [.21CF.0020.0002.1688] # OGHAM LETTER TINNE +1689 ; [.21D0.0020.0002.1689] # OGHAM LETTER COLL +168A ; [.21D1.0020.0002.168A] # OGHAM LETTER CEIRT +168B ; [.21D2.0020.0002.168B] # OGHAM LETTER MUIN +168C ; [.21D3.0020.0002.168C] # OGHAM LETTER GORT +168D ; [.21D4.0020.0002.168D] # OGHAM LETTER NGEADAL +168E ; [.21D5.0020.0002.168E] # OGHAM LETTER STRAIF +168F ; [.21D6.0020.0002.168F] # OGHAM LETTER RUIS +1690 ; [.21D7.0020.0002.1690] # OGHAM LETTER AILM +1691 ; [.21D8.0020.0002.1691] # OGHAM LETTER ONN +1692 ; [.21D9.0020.0002.1692] # OGHAM LETTER UR +1693 ; [.21DA.0020.0002.1693] # OGHAM LETTER EADHADH +1694 ; [.21DB.0020.0002.1694] # OGHAM LETTER IODHADH +1695 ; [.21DC.0020.0002.1695] # OGHAM LETTER EABHADH +1696 ; [.21DD.0020.0002.1696] # OGHAM LETTER OR +1697 ; [.21DE.0020.0002.1697] # OGHAM LETTER UILLEANN +1698 ; [.21DF.0020.0002.1698] # OGHAM LETTER IFIN +1699 ; [.21E0.0020.0002.1699] # OGHAM LETTER EAMHANCHOLL +169A ; [.21E1.0020.0002.169A] # OGHAM LETTER PEITH +16A0 ; [.21E2.0020.0002.16A0] # RUNIC LETTER FEHU FEOH FE F +16A1 ; [.21E2.0020.0004.16A1][.0000.0199.0004.16A1] # RUNIC LETTER V; QQKN +16A2 ; [.21E3.0020.0002.16A2] # RUNIC LETTER URUZ UR U +16A4 ; [.21E3.0020.0004.16A4][.0000.0199.0004.16A4] # RUNIC LETTER Y; QQKN +16A5 ; [.21E3.0020.0004.16A5][.0000.019A.0004.16A5] # RUNIC LETTER W; QQKN +16A6 ; [.21E4.0020.0002.16A6] # RUNIC LETTER THURISAZ THURS THORN +16A7 ; [.21E4.0020.0004.16A7][.0000.0199.0004.16A7] # RUNIC LETTER ETH; QQKN +16F0 ; [.21E4.0020.0004.16F0][.21E4.0020.0004.16F0] # RUNIC BELGTHOR SYMBOL; QQKN +16A8 ; [.21E5.0020.0002.16A8] # RUNIC LETTER ANSUZ A +16A9 ; [.21E5.0020.0004.16A9][.0000.0199.0004.16A9] # RUNIC LETTER OS O; QQKN +16AC ; [.21E5.0020.0004.16AC][.0000.019A.0004.16AC] # RUNIC LETTER LONG-BRANCH-OSS O; QQKN +16AD ; [.21E5.0020.0004.16AD][.0000.019C.0004.16AD] # RUNIC LETTER SHORT-TWIG-OSS O; QQKN +16AE ; [.21E5.0020.0004.16AE][.0000.019D.0004.16AE] # RUNIC LETTER O; QQKN +16AF ; [.21E6.0020.0002.16AF] # RUNIC LETTER OE +16B0 ; [.21E7.0020.0002.16B0] # RUNIC LETTER ON +16B1 ; [.21E8.0020.0002.16B1] # RUNIC LETTER RAIDO RAD REID R +16B2 ; [.21E9.0020.0002.16B2] # RUNIC LETTER KAUNA +16B3 ; [.21E9.0020.0004.16B3][.0000.0199.0004.16B3] # RUNIC LETTER CEN; QQKN +16B4 ; [.21E9.0020.0004.16B4][.0000.019A.0004.16B4] # RUNIC LETTER KAUN K; QQKN +16B5 ; [.21E9.0020.0004.16B5][.0000.019C.0004.16B5] # RUNIC LETTER G; QQKN +16B6 ; [.21E9.0020.0004.16B6][.0000.019D.0004.16B6] # RUNIC LETTER ENG; QQKN +16B7 ; [.21EA.0020.0002.16B7] # RUNIC LETTER GEBO GYFU G +16B9 ; [.21EB.0020.0002.16B9] # RUNIC LETTER WUNJO WYNN W +16E9 ; [.21EB.0020.0004.16E9][.0000.0199.0004.16E9] # RUNIC LETTER Q; QQKN +16BA ; [.21EC.0020.0002.16BA] # RUNIC LETTER HAGLAZ H +16BB ; [.21EC.0020.0004.16BB][.0000.0199.0004.16BB] # RUNIC LETTER HAEGL H; QQKN +16BC ; [.21EC.0020.0004.16BC][.0000.019A.0004.16BC] # RUNIC LETTER LONG-BRANCH-HAGALL H; QQKN +16BD ; [.21EC.0020.0004.16BD][.0000.019C.0004.16BD] # RUNIC LETTER SHORT-TWIG-HAGALL H; QQKN +16BE ; [.21ED.0020.0002.16BE] # RUNIC LETTER NAUDIZ NYD NAUD N +16BF ; [.21ED.0020.0004.16BF][.0000.0199.0004.16BF] # RUNIC LETTER SHORT-TWIG-NAUD N; QQKN +16C0 ; [.21ED.0020.0004.16C0][.0000.019A.0004.16C0] # RUNIC LETTER DOTTED-N; QQKN +16C1 ; [.21EE.0020.0002.16C1] # RUNIC LETTER ISAZ IS ISS I +16C2 ; [.21EE.0020.0004.16C2][.0000.0199.0004.16C2] # RUNIC LETTER E; QQKN +16C3 ; [.21EF.0020.0002.16C3] # RUNIC LETTER JERAN J +16C4 ; [.21EF.0020.0004.16C4][.0000.0199.0004.16C4] # RUNIC LETTER GER; QQKN +16C5 ; [.21F0.0020.0002.16C5] # RUNIC LETTER LONG-BRANCH-AR AE +16C6 ; [.21F0.0020.0004.16C6][.0000.0199.0004.16C6] # RUNIC LETTER SHORT-TWIG-AR A; QQKN +16EE ; [.21F0.0020.0004.16EE][.21F9.0020.0004.16EE] # RUNIC ARLAUG SYMBOL; QQKN +16C7 ; [.21F1.0020.0002.16C7] # RUNIC LETTER IWAZ EOH +16C8 ; [.21F2.0020.0002.16C8] # RUNIC LETTER PERTHO PEORTH P +16D5 ; [.21F2.0020.0004.16D5][.0000.0199.0004.16D5] # RUNIC LETTER OPEN-P; QQKN +16C9 ; [.21F3.0020.0002.16C9] # RUNIC LETTER ALGIZ EOLHX +16CA ; [.21F4.0020.0002.16CA] # RUNIC LETTER SOWILO S +16CB ; [.21F4.0020.0004.16CB][.0000.0199.0004.16CB] # RUNIC LETTER SIGEL LONG-BRANCH-SOL S; QQKN +16EA ; [.21F4.0020.0004.16EA][.0000.019A.0004.16EA] # RUNIC LETTER X; QQKN +16CC ; [.21F4.0020.0004.16CC][.0000.019C.0004.16CC] # RUNIC LETTER SHORT-TWIG-SOL S; QQKN +16CD ; [.21F4.0020.0004.16CD][.0000.019D.0004.16CD] # RUNIC LETTER C; QQKN +16CE ; [.21F4.0020.0004.16CE][.0000.019E.0004.16CE] # RUNIC LETTER Z; QQKN +16CF ; [.21F5.0020.0002.16CF] # RUNIC LETTER TIWAZ TIR TYR T +16D0 ; [.21F5.0020.0004.16D0][.0000.0199.0004.16D0] # RUNIC LETTER SHORT-TWIG-TYR T; QQKN +16D1 ; [.21F5.0020.0004.16D1][.0000.019A.0004.16D1] # RUNIC LETTER D; QQKN +16D2 ; [.21F6.0020.0002.16D2] # RUNIC LETTER BERKANAN BEORC BJARKAN B +16D3 ; [.21F6.0020.0004.16D3][.0000.0199.0004.16D3] # RUNIC LETTER SHORT-TWIG-BJARKAN B; QQKN +16D4 ; [.21F6.0020.0004.16D4][.0000.019A.0004.16D4] # RUNIC LETTER DOTTED-P; QQKN +16D6 ; [.21F7.0020.0002.16D6] # RUNIC LETTER EHWAZ EH E +16D7 ; [.21F8.0020.0002.16D7] # RUNIC LETTER MANNAZ MAN M +16D8 ; [.21F8.0020.0004.16D8][.0000.0199.0004.16D8] # RUNIC LETTER LONG-BRANCH-MADR M; QQKN +16D9 ; [.21F8.0020.0004.16D9][.0000.019A.0004.16D9] # RUNIC LETTER SHORT-TWIG-MADR M; QQKN +16EF ; [.21F8.0020.0004.16EF][.0000.0199.0004.16EF][.21F8.0020.001F.16EF][.0000.0199.001F.16EF] # RUNIC TVIMADUR SYMBOL; QQKN +16DA ; [.21F9.0020.0002.16DA] # RUNIC LETTER LAUKAZ LAGU LOGR L +16DB ; [.21F9.0020.0004.16DB][.0000.0199.0004.16DB] # RUNIC LETTER DOTTED-L; QQKN +16DC ; [.21FA.0020.0002.16DC] # RUNIC LETTER INGWAZ +16DD ; [.21FA.0020.0004.16DD][.0000.0199.0004.16DD] # RUNIC LETTER ING; QQKN +16DE ; [.21FB.0020.0002.16DE] # RUNIC LETTER DAGAZ DAEG D +16DF ; [.21FC.0020.0002.16DF] # RUNIC LETTER OTHALAN ETHEL O +16AA ; [.21FD.0020.0002.16AA] # RUNIC LETTER AC A +16AB ; [.21FE.0020.0002.16AB] # RUNIC LETTER AESC +16A3 ; [.21FF.0020.0002.16A3] # RUNIC LETTER YR +16E0 ; [.2200.0020.0002.16E0] # RUNIC LETTER EAR +16E3 ; [.2201.0020.0002.16E3] # RUNIC LETTER CALC +16B8 ; [.2202.0020.0002.16B8] # RUNIC LETTER GAR +16E4 ; [.2203.0020.0002.16E4] # RUNIC LETTER CEALC +16E1 ; [.2204.0020.0002.16E1] # RUNIC LETTER IOR +16E2 ; [.2205.0020.0002.16E2] # RUNIC LETTER CWEORTH +16E5 ; [.2206.0020.0002.16E5] # RUNIC LETTER STAN +16E6 ; [.2207.0020.0002.16E6] # RUNIC LETTER LONG-BRANCH-YR +16E7 ; [.2207.0020.0004.16E7][.0000.0199.0004.16E7] # RUNIC LETTER SHORT-TWIG-YR; QQKN +16E8 ; [.2207.0020.0004.16E8][.0000.019A.0004.16E8] # RUNIC LETTER ICELANDIC-YR; QQKN +1100 ; [.2208.0020.0002.1100] # HANGUL CHOSEONG KIYEOK +3131 ; [.2208.0020.0004.3131] # HANGUL LETTER KIYEOK; QQK +3200 ; [*02B1.0020.0004.3200][.2208.0020.0004.3200][*02B2.0020.001F.3200] # PARENTHESIZED HANGUL KIYEOK; QQKN +3260 ; [.2208.0020.0006.3260] # CIRCLED HANGUL KIYEOK; QQK +FFA1 ; [.2208.0020.0012.FFA1] # HALFWIDTH HANGUL LETTER KIYEOK; QQK +320E ; [*02B1.0020.0004.320E][.2208.0020.0004.320E][.2264.0020.001F.320E][*02B2.0020.001F.320E] # PARENTHESIZED HANGUL KIYEOK A; QQKN +326E ; [.2208.0020.0006.326E][.2264.0020.0006.326E] # CIRCLED HANGUL KIYEOK A; QQKN +1101 ; [.2209.0020.0002.1101] # HANGUL CHOSEONG SSANGKIYEOK +3132 ; [.2209.0020.0004.3132] # HANGUL LETTER SSANGKIYEOK; QQK +FFA2 ; [.2209.0020.0012.FFA2] # HALFWIDTH HANGUL LETTER SSANGKIYEOK; QQK +1102 ; [.220A.0020.0002.1102] # HANGUL CHOSEONG NIEUN +3134 ; [.220A.0020.0004.3134] # HANGUL LETTER NIEUN; QQK +3201 ; [*02B1.0020.0004.3201][.220A.0020.0004.3201][*02B2.0020.001F.3201] # PARENTHESIZED HANGUL NIEUN; QQKN +3261 ; [.220A.0020.0006.3261] # CIRCLED HANGUL NIEUN; QQK +FFA4 ; [.220A.0020.0012.FFA4] # HALFWIDTH HANGUL LETTER NIEUN; QQK +320F ; [*02B1.0020.0004.320F][.220A.0020.0004.320F][.2264.0020.001F.320F][*02B2.0020.001F.320F] # PARENTHESIZED HANGUL NIEUN A; QQKN +326F ; [.220A.0020.0006.326F][.2264.0020.0006.326F] # CIRCLED HANGUL NIEUN A; QQKN +1103 ; [.220B.0020.0002.1103] # HANGUL CHOSEONG TIKEUT +3137 ; [.220B.0020.0004.3137] # HANGUL LETTER TIKEUT; QQK +3202 ; [*02B1.0020.0004.3202][.220B.0020.0004.3202][*02B2.0020.001F.3202] # PARENTHESIZED HANGUL TIKEUT; QQKN +3262 ; [.220B.0020.0006.3262] # CIRCLED HANGUL TIKEUT; QQK +FFA7 ; [.220B.0020.0012.FFA7] # HALFWIDTH HANGUL LETTER TIKEUT; QQK +3210 ; [*02B1.0020.0004.3210][.220B.0020.0004.3210][.2264.0020.001F.3210][*02B2.0020.001F.3210] # PARENTHESIZED HANGUL TIKEUT A; QQKN +3270 ; [.220B.0020.0006.3270][.2264.0020.0006.3270] # CIRCLED HANGUL TIKEUT A; QQKN +1104 ; [.220C.0020.0002.1104] # HANGUL CHOSEONG SSANGTIKEUT +3138 ; [.220C.0020.0004.3138] # HANGUL LETTER SSANGTIKEUT; QQK +FFA8 ; [.220C.0020.0012.FFA8] # HALFWIDTH HANGUL LETTER SSANGTIKEUT; QQK +1105 ; [.220D.0020.0002.1105] # HANGUL CHOSEONG RIEUL +3139 ; [.220D.0020.0004.3139] # HANGUL LETTER RIEUL; QQK +3203 ; [*02B1.0020.0004.3203][.220D.0020.0004.3203][*02B2.0020.001F.3203] # PARENTHESIZED HANGUL RIEUL; QQKN +3263 ; [.220D.0020.0006.3263] # CIRCLED HANGUL RIEUL; QQK +FFA9 ; [.220D.0020.0012.FFA9] # HALFWIDTH HANGUL LETTER RIEUL; QQK +3211 ; [*02B1.0020.0004.3211][.220D.0020.0004.3211][.2264.0020.001F.3211][*02B2.0020.001F.3211] # PARENTHESIZED HANGUL RIEUL A; QQKN +3271 ; [.220D.0020.0006.3271][.2264.0020.0006.3271] # CIRCLED HANGUL RIEUL A; QQKN +1106 ; [.220E.0020.0002.1106] # HANGUL CHOSEONG MIEUM +3141 ; [.220E.0020.0004.3141] # HANGUL LETTER MIEUM; QQK +3204 ; [*02B1.0020.0004.3204][.220E.0020.0004.3204][*02B2.0020.001F.3204] # PARENTHESIZED HANGUL MIEUM; QQKN +3264 ; [.220E.0020.0006.3264] # CIRCLED HANGUL MIEUM; QQK +FFB1 ; [.220E.0020.0012.FFB1] # HALFWIDTH HANGUL LETTER MIEUM; QQK +3212 ; [*02B1.0020.0004.3212][.220E.0020.0004.3212][.2264.0020.001F.3212][*02B2.0020.001F.3212] # PARENTHESIZED HANGUL MIEUM A; QQKN +3272 ; [.220E.0020.0006.3272][.2264.0020.0006.3272] # CIRCLED HANGUL MIEUM A; QQKN +1107 ; [.220F.0020.0002.1107] # HANGUL CHOSEONG PIEUP +3142 ; [.220F.0020.0004.3142] # HANGUL LETTER PIEUP; QQK +3205 ; [*02B1.0020.0004.3205][.220F.0020.0004.3205][*02B2.0020.001F.3205] # PARENTHESIZED HANGUL PIEUP; QQKN +3265 ; [.220F.0020.0006.3265] # CIRCLED HANGUL PIEUP; QQK +FFB2 ; [.220F.0020.0012.FFB2] # HALFWIDTH HANGUL LETTER PIEUP; QQK +3213 ; [*02B1.0020.0004.3213][.220F.0020.0004.3213][.2264.0020.001F.3213][*02B2.0020.001F.3213] # PARENTHESIZED HANGUL PIEUP A; QQKN +3273 ; [.220F.0020.0006.3273][.2264.0020.0006.3273] # CIRCLED HANGUL PIEUP A; QQKN +1108 ; [.2210.0020.0002.1108] # HANGUL CHOSEONG SSANGPIEUP +3143 ; [.2210.0020.0004.3143] # HANGUL LETTER SSANGPIEUP; QQK +FFB3 ; [.2210.0020.0012.FFB3] # HALFWIDTH HANGUL LETTER SSANGPIEUP; QQK +1109 ; [.2211.0020.0002.1109] # HANGUL CHOSEONG SIOS +3145 ; [.2211.0020.0004.3145] # HANGUL LETTER SIOS; QQK +3206 ; [*02B1.0020.0004.3206][.2211.0020.0004.3206][*02B2.0020.001F.3206] # PARENTHESIZED HANGUL SIOS; QQKN +3266 ; [.2211.0020.0006.3266] # CIRCLED HANGUL SIOS; QQK +FFB5 ; [.2211.0020.0012.FFB5] # HALFWIDTH HANGUL LETTER SIOS; QQK +3214 ; [*02B1.0020.0004.3214][.2211.0020.0004.3214][.2264.0020.001F.3214][*02B2.0020.001F.3214] # PARENTHESIZED HANGUL SIOS A; QQKN +3274 ; [.2211.0020.0006.3274][.2264.0020.0006.3274] # CIRCLED HANGUL SIOS A; QQKN +110A ; [.2212.0020.0002.110A] # HANGUL CHOSEONG SSANGSIOS +3146 ; [.2212.0020.0004.3146] # HANGUL LETTER SSANGSIOS; QQK +FFB6 ; [.2212.0020.0012.FFB6] # HALFWIDTH HANGUL LETTER SSANGSIOS; QQK +110B ; [.2213.0020.0002.110B] # HANGUL CHOSEONG IEUNG +3147 ; [.2213.0020.0004.3147] # HANGUL LETTER IEUNG; QQK +3207 ; [*02B1.0020.0004.3207][.2213.0020.0004.3207][*02B2.0020.001F.3207] # PARENTHESIZED HANGUL IEUNG; QQKN +3267 ; [.2213.0020.0006.3267] # CIRCLED HANGUL IEUNG; QQK +FFB7 ; [.2213.0020.0012.FFB7] # HALFWIDTH HANGUL LETTER IEUNG; QQK +3215 ; [*02B1.0020.0004.3215][.2213.0020.0004.3215][.2264.0020.001F.3215][*02B2.0020.001F.3215] # PARENTHESIZED HANGUL IEUNG A; QQKN +3275 ; [.2213.0020.0006.3275][.2264.0020.0006.3275] # CIRCLED HANGUL IEUNG A; QQKN +321D ; [*02B1.0020.0004.321D][.2213.0020.0004.321D][.226C.0020.001F.321D][.2214.0020.001F.321D][.2268.0020.001F.321D][.22A9.0020.001F.321D][*02B2.0020.001F.321D] # PARENTHESIZED KOREAN CHARACTER OJEON; QQKN +321E ; [*02B1.0020.0004.321E][.2213.0020.0004.321E][.226C.0020.001F.321E][.221A.0020.001F.321E][.2271.0020.001F.321E][*02B2.0020.001F.321E] # PARENTHESIZED KOREAN CHARACTER O HU; QQKN +327E ; [.2213.0020.0006.327E][.2271.0020.0006.327E] # CIRCLED HANGUL IEUNG U; QQKN +110C ; [.2214.0020.0002.110C] # HANGUL CHOSEONG CIEUC +3148 ; [.2214.0020.0004.3148] # HANGUL LETTER CIEUC; QQK +3208 ; [*02B1.0020.0004.3208][.2214.0020.0004.3208][*02B2.0020.001F.3208] # PARENTHESIZED HANGUL CIEUC; QQKN +3268 ; [.2214.0020.0006.3268] # CIRCLED HANGUL CIEUC; QQK +FFB8 ; [.2214.0020.0012.FFB8] # HALFWIDTH HANGUL LETTER CIEUC; QQK +3216 ; [*02B1.0020.0004.3216][.2214.0020.0004.3216][.2264.0020.001F.3216][*02B2.0020.001F.3216] # PARENTHESIZED HANGUL CIEUC A; QQKN +3276 ; [.2214.0020.0006.3276][.2264.0020.0006.3276] # CIRCLED HANGUL CIEUC A; QQKN +321C ; [*02B1.0020.0004.321C][.2214.0020.0004.321C][.2271.0020.001F.321C][*02B2.0020.001F.321C] # PARENTHESIZED HANGUL CIEUC U; QQKN +327D ; [.2214.0020.0006.327D][.2271.0020.0006.327D][.2213.0020.001F.327D][.2277.0020.001F.327D] # CIRCLED KOREAN CHARACTER JUEUI; QQKN +110D ; [.2215.0020.0002.110D] # HANGUL CHOSEONG SSANGCIEUC +3149 ; [.2215.0020.0004.3149] # HANGUL LETTER SSANGCIEUC; QQK +FFB9 ; [.2215.0020.0012.FFB9] # HALFWIDTH HANGUL LETTER SSANGCIEUC; QQK +110E ; [.2216.0020.0002.110E] # HANGUL CHOSEONG CHIEUCH +314A ; [.2216.0020.0004.314A] # HANGUL LETTER CHIEUCH; QQK +3209 ; [*02B1.0020.0004.3209][.2216.0020.0004.3209][*02B2.0020.001F.3209] # PARENTHESIZED HANGUL CHIEUCH; QQKN +3269 ; [.2216.0020.0006.3269] # CIRCLED HANGUL CHIEUCH; QQK +FFBA ; [.2216.0020.0012.FFBA] # HALFWIDTH HANGUL LETTER CHIEUCH; QQK +3217 ; [*02B1.0020.0004.3217][.2216.0020.0004.3217][.2264.0020.001F.3217][*02B2.0020.001F.3217] # PARENTHESIZED HANGUL CHIEUCH A; QQKN +3277 ; [.2216.0020.0006.3277][.2264.0020.0006.3277] # CIRCLED HANGUL CHIEUCH A; QQKN +327C ; [.2216.0020.0006.327C][.2264.0020.0006.327C][.22B5.0020.001F.327C][.2208.0020.001F.327C][.226C.0020.001F.327C] # CIRCLED KOREAN CHARACTER CHAMKO; QQKN +110F ; [.2217.0020.0002.110F] # HANGUL CHOSEONG KHIEUKH +314B ; [.2217.0020.0004.314B] # HANGUL LETTER KHIEUKH; QQK +320A ; [*02B1.0020.0004.320A][.2217.0020.0004.320A][*02B2.0020.001F.320A] # PARENTHESIZED HANGUL KHIEUKH; QQKN +326A ; [.2217.0020.0006.326A] # CIRCLED HANGUL KHIEUKH; QQK +FFBB ; [.2217.0020.0012.FFBB] # HALFWIDTH HANGUL LETTER KHIEUKH; QQK +3218 ; [*02B1.0020.0004.3218][.2217.0020.0004.3218][.2264.0020.001F.3218][*02B2.0020.001F.3218] # PARENTHESIZED HANGUL KHIEUKH A; QQKN +3278 ; [.2217.0020.0006.3278][.2264.0020.0006.3278] # CIRCLED HANGUL KHIEUKH A; QQKN +1110 ; [.2218.0020.0002.1110] # HANGUL CHOSEONG THIEUTH +314C ; [.2218.0020.0004.314C] # HANGUL LETTER THIEUTH; QQK +320B ; [*02B1.0020.0004.320B][.2218.0020.0004.320B][*02B2.0020.001F.320B] # PARENTHESIZED HANGUL THIEUTH; QQKN +326B ; [.2218.0020.0006.326B] # CIRCLED HANGUL THIEUTH; QQK +FFBC ; [.2218.0020.0012.FFBC] # HALFWIDTH HANGUL LETTER THIEUTH; QQK +3219 ; [*02B1.0020.0004.3219][.2218.0020.0004.3219][.2264.0020.001F.3219][*02B2.0020.001F.3219] # PARENTHESIZED HANGUL THIEUTH A; QQKN +3279 ; [.2218.0020.0006.3279][.2264.0020.0006.3279] # CIRCLED HANGUL THIEUTH A; QQKN +1111 ; [.2219.0020.0002.1111] # HANGUL CHOSEONG PHIEUPH +314D ; [.2219.0020.0004.314D] # HANGUL LETTER PHIEUPH; QQK +320C ; [*02B1.0020.0004.320C][.2219.0020.0004.320C][*02B2.0020.001F.320C] # PARENTHESIZED HANGUL PHIEUPH; QQKN +326C ; [.2219.0020.0006.326C] # CIRCLED HANGUL PHIEUPH; QQK +FFBD ; [.2219.0020.0012.FFBD] # HALFWIDTH HANGUL LETTER PHIEUPH; QQK +321A ; [*02B1.0020.0004.321A][.2219.0020.0004.321A][.2264.0020.001F.321A][*02B2.0020.001F.321A] # PARENTHESIZED HANGUL PHIEUPH A; QQKN +327A ; [.2219.0020.0006.327A][.2264.0020.0006.327A] # CIRCLED HANGUL PHIEUPH A; QQKN +1112 ; [.221A.0020.0002.1112] # HANGUL CHOSEONG HIEUH +314E ; [.221A.0020.0004.314E] # HANGUL LETTER HIEUH; QQK +320D ; [*02B1.0020.0004.320D][.221A.0020.0004.320D][*02B2.0020.001F.320D] # PARENTHESIZED HANGUL HIEUH; QQKN +326D ; [.221A.0020.0006.326D] # CIRCLED HANGUL HIEUH; QQK +FFBE ; [.221A.0020.0012.FFBE] # HALFWIDTH HANGUL LETTER HIEUH; QQK +321B ; [*02B1.0020.0004.321B][.221A.0020.0004.321B][.2264.0020.001F.321B][*02B2.0020.001F.321B] # PARENTHESIZED HANGUL HIEUH A; QQKN +327B ; [.221A.0020.0006.327B][.2264.0020.0006.327B] # CIRCLED HANGUL HIEUH A; QQKN +1113 ; [.221B.0020.0002.1113] # HANGUL CHOSEONG NIEUN-KIYEOK +1114 ; [.221C.0020.0002.1114] # HANGUL CHOSEONG SSANGNIEUN +3165 ; [.221C.0020.0004.3165] # HANGUL LETTER SSANGNIEUN; QQK +1115 ; [.221D.0020.0002.1115] # HANGUL CHOSEONG NIEUN-TIKEUT +3166 ; [.221D.0020.0004.3166] # HANGUL LETTER NIEUN-TIKEUT; QQK +1116 ; [.221E.0020.0002.1116] # HANGUL CHOSEONG NIEUN-PIEUP +1117 ; [.221F.0020.0002.1117] # HANGUL CHOSEONG TIKEUT-KIYEOK +1118 ; [.2220.0020.0002.1118] # HANGUL CHOSEONG RIEUL-NIEUN +1119 ; [.2221.0020.0002.1119] # HANGUL CHOSEONG SSANGRIEUL +111A ; [.2222.0020.0002.111A] # HANGUL CHOSEONG RIEUL-HIEUH +3140 ; [.2222.0020.0004.3140] # HANGUL LETTER RIEUL-HIEUH; QQK +FFB0 ; [.2222.0020.0012.FFB0] # HALFWIDTH HANGUL LETTER RIEUL-HIEUH; QQK +111B ; [.2223.0020.0002.111B] # HANGUL CHOSEONG KAPYEOUNRIEUL +111C ; [.2224.0020.0002.111C] # HANGUL CHOSEONG MIEUM-PIEUP +316E ; [.2224.0020.0004.316E] # HANGUL LETTER MIEUM-PIEUP; QQK +111D ; [.2225.0020.0002.111D] # HANGUL CHOSEONG KAPYEOUNMIEUM +3171 ; [.2225.0020.0004.3171] # HANGUL LETTER KAPYEOUNMIEUM; QQK +111E ; [.2226.0020.0002.111E] # HANGUL CHOSEONG PIEUP-KIYEOK +3172 ; [.2226.0020.0004.3172] # HANGUL LETTER PIEUP-KIYEOK; QQK +111F ; [.2227.0020.0002.111F] # HANGUL CHOSEONG PIEUP-NIEUN +1120 ; [.2228.0020.0002.1120] # HANGUL CHOSEONG PIEUP-TIKEUT +3173 ; [.2228.0020.0004.3173] # HANGUL LETTER PIEUP-TIKEUT; QQK +1121 ; [.2229.0020.0002.1121] # HANGUL CHOSEONG PIEUP-SIOS +3144 ; [.2229.0020.0004.3144] # HANGUL LETTER PIEUP-SIOS; QQK +FFB4 ; [.2229.0020.0012.FFB4] # HALFWIDTH HANGUL LETTER PIEUP-SIOS; QQK +1122 ; [.222A.0020.0002.1122] # HANGUL CHOSEONG PIEUP-SIOS-KIYEOK +3174 ; [.222A.0020.0004.3174] # HANGUL LETTER PIEUP-SIOS-KIYEOK; QQK +1123 ; [.222B.0020.0002.1123] # HANGUL CHOSEONG PIEUP-SIOS-TIKEUT +3175 ; [.222B.0020.0004.3175] # HANGUL LETTER PIEUP-SIOS-TIKEUT; QQK +1124 ; [.222C.0020.0002.1124] # HANGUL CHOSEONG PIEUP-SIOS-PIEUP +1125 ; [.222D.0020.0002.1125] # HANGUL CHOSEONG PIEUP-SSANGSIOS +1126 ; [.222E.0020.0002.1126] # HANGUL CHOSEONG PIEUP-SIOS-CIEUC +1127 ; [.222F.0020.0002.1127] # HANGUL CHOSEONG PIEUP-CIEUC +3176 ; [.222F.0020.0004.3176] # HANGUL LETTER PIEUP-CIEUC; QQK +1128 ; [.2230.0020.0002.1128] # HANGUL CHOSEONG PIEUP-CHIEUCH +1129 ; [.2231.0020.0002.1129] # HANGUL CHOSEONG PIEUP-THIEUTH +3177 ; [.2231.0020.0004.3177] # HANGUL LETTER PIEUP-THIEUTH; QQK +112A ; [.2232.0020.0002.112A] # HANGUL CHOSEONG PIEUP-PHIEUPH +112B ; [.2233.0020.0002.112B] # HANGUL CHOSEONG KAPYEOUNPIEUP +3178 ; [.2233.0020.0004.3178] # HANGUL LETTER KAPYEOUNPIEUP; QQK +112C ; [.2234.0020.0002.112C] # HANGUL CHOSEONG KAPYEOUNSSANGPIEUP +3179 ; [.2234.0020.0004.3179] # HANGUL LETTER KAPYEOUNSSANGPIEUP; QQK +112D ; [.2235.0020.0002.112D] # HANGUL CHOSEONG SIOS-KIYEOK +317A ; [.2235.0020.0004.317A] # HANGUL LETTER SIOS-KIYEOK; QQK +112E ; [.2236.0020.0002.112E] # HANGUL CHOSEONG SIOS-NIEUN +317B ; [.2236.0020.0004.317B] # HANGUL LETTER SIOS-NIEUN; QQK +112F ; [.2237.0020.0002.112F] # HANGUL CHOSEONG SIOS-TIKEUT +317C ; [.2237.0020.0004.317C] # HANGUL LETTER SIOS-TIKEUT; QQK +1130 ; [.2238.0020.0002.1130] # HANGUL CHOSEONG SIOS-RIEUL +1131 ; [.2239.0020.0002.1131] # HANGUL CHOSEONG SIOS-MIEUM +1132 ; [.223A.0020.0002.1132] # HANGUL CHOSEONG SIOS-PIEUP +317D ; [.223A.0020.0004.317D] # HANGUL LETTER SIOS-PIEUP; QQK +1133 ; [.223B.0020.0002.1133] # HANGUL CHOSEONG SIOS-PIEUP-KIYEOK +1134 ; [.223C.0020.0002.1134] # HANGUL CHOSEONG SIOS-SSANGSIOS +1135 ; [.223D.0020.0002.1135] # HANGUL CHOSEONG SIOS-IEUNG +1136 ; [.223E.0020.0002.1136] # HANGUL CHOSEONG SIOS-CIEUC +317E ; [.223E.0020.0004.317E] # HANGUL LETTER SIOS-CIEUC; QQK +1137 ; [.223F.0020.0002.1137] # HANGUL CHOSEONG SIOS-CHIEUCH +1138 ; [.2240.0020.0002.1138] # HANGUL CHOSEONG SIOS-KHIEUKH +1139 ; [.2241.0020.0002.1139] # HANGUL CHOSEONG SIOS-THIEUTH +113A ; [.2242.0020.0002.113A] # HANGUL CHOSEONG SIOS-PHIEUPH +113B ; [.2243.0020.0002.113B] # HANGUL CHOSEONG SIOS-HIEUH +113C ; [.2244.0020.0002.113C] # HANGUL CHOSEONG CHITUEUMSIOS +113D ; [.2245.0020.0002.113D] # HANGUL CHOSEONG CHITUEUMSSANGSIOS +113E ; [.2246.0020.0002.113E] # HANGUL CHOSEONG CEONGCHIEUMSIOS +113F ; [.2247.0020.0002.113F] # HANGUL CHOSEONG CEONGCHIEUMSSANGSIOS +1140 ; [.2248.0020.0002.1140] # HANGUL CHOSEONG PANSIOS +317F ; [.2248.0020.0004.317F] # HANGUL LETTER PANSIOS; QQK +1141 ; [.2249.0020.0002.1141] # HANGUL CHOSEONG IEUNG-KIYEOK +1142 ; [.224A.0020.0002.1142] # HANGUL CHOSEONG IEUNG-TIKEUT +1143 ; [.224B.0020.0002.1143] # HANGUL CHOSEONG IEUNG-MIEUM +1144 ; [.224C.0020.0002.1144] # HANGUL CHOSEONG IEUNG-PIEUP +1145 ; [.224D.0020.0002.1145] # HANGUL CHOSEONG IEUNG-SIOS +1146 ; [.224E.0020.0002.1146] # HANGUL CHOSEONG IEUNG-PANSIOS +1147 ; [.224F.0020.0002.1147] # HANGUL CHOSEONG SSANGIEUNG +3180 ; [.224F.0020.0004.3180] # HANGUL LETTER SSANGIEUNG; QQK +1148 ; [.2250.0020.0002.1148] # HANGUL CHOSEONG IEUNG-CIEUC +1149 ; [.2251.0020.0002.1149] # HANGUL CHOSEONG IEUNG-CHIEUCH +114A ; [.2252.0020.0002.114A] # HANGUL CHOSEONG IEUNG-THIEUTH +114B ; [.2253.0020.0002.114B] # HANGUL CHOSEONG IEUNG-PHIEUPH +114C ; [.2254.0020.0002.114C] # HANGUL CHOSEONG YESIEUNG +3181 ; [.2254.0020.0004.3181] # HANGUL LETTER YESIEUNG; QQK +114D ; [.2255.0020.0002.114D] # HANGUL CHOSEONG CIEUC-IEUNG +114E ; [.2256.0020.0002.114E] # HANGUL CHOSEONG CHITUEUMCIEUC +114F ; [.2257.0020.0002.114F] # HANGUL CHOSEONG CHITUEUMSSANGCIEUC +1150 ; [.2258.0020.0002.1150] # HANGUL CHOSEONG CEONGCHIEUMCIEUC +1151 ; [.2259.0020.0002.1151] # HANGUL CHOSEONG CEONGCHIEUMSSANGCIEUC +1152 ; [.225A.0020.0002.1152] # HANGUL CHOSEONG CHIEUCH-KHIEUKH +1153 ; [.225B.0020.0002.1153] # HANGUL CHOSEONG CHIEUCH-HIEUH +1154 ; [.225C.0020.0002.1154] # HANGUL CHOSEONG CHITUEUMCHIEUCH +1155 ; [.225D.0020.0002.1155] # HANGUL CHOSEONG CEONGCHIEUMCHIEUCH +1156 ; [.225E.0020.0002.1156] # HANGUL CHOSEONG PHIEUPH-PIEUP +1157 ; [.225F.0020.0002.1157] # HANGUL CHOSEONG KAPYEOUNPHIEUPH +3184 ; [.225F.0020.0004.3184] # HANGUL LETTER KAPYEOUNPHIEUPH; QQK +1158 ; [.2260.0020.0002.1158] # HANGUL CHOSEONG SSANGHIEUH +3185 ; [.2260.0020.0004.3185] # HANGUL LETTER SSANGHIEUH; QQK +1159 ; [.2261.0020.0002.1159] # HANGUL CHOSEONG YEORINHIEUH +3186 ; [.2261.0020.0004.3186] # HANGUL LETTER YEORINHIEUH; QQK +115F ; [.2262.0020.0002.115F] # HANGUL CHOSEONG FILLER +1160 ; [.2263.0020.0002.1160] # HANGUL JUNGSEONG FILLER +3164 ; [.2263.0020.0004.3164] # HANGUL FILLER; QQK +FFA0 ; [.2263.0020.0012.FFA0] # HALFWIDTH HANGUL FILLER; QQK +1161 ; [.2264.0020.0002.1161] # HANGUL JUNGSEONG A +314F ; [.2264.0020.0004.314F] # HANGUL LETTER A; QQK +FFC2 ; [.2264.0020.0012.FFC2] # HALFWIDTH HANGUL LETTER A; QQK +1162 ; [.2265.0020.0002.1162] # HANGUL JUNGSEONG AE +3150 ; [.2265.0020.0004.3150] # HANGUL LETTER AE; QQK +FFC3 ; [.2265.0020.0012.FFC3] # HALFWIDTH HANGUL LETTER AE; QQK +1163 ; [.2266.0020.0002.1163] # HANGUL JUNGSEONG YA +3151 ; [.2266.0020.0004.3151] # HANGUL LETTER YA; QQK +FFC4 ; [.2266.0020.0012.FFC4] # HALFWIDTH HANGUL LETTER YA; QQK +1164 ; [.2267.0020.0002.1164] # HANGUL JUNGSEONG YAE +3152 ; [.2267.0020.0004.3152] # HANGUL LETTER YAE; QQK +FFC5 ; [.2267.0020.0012.FFC5] # HALFWIDTH HANGUL LETTER YAE; QQK +1165 ; [.2268.0020.0002.1165] # HANGUL JUNGSEONG EO +3153 ; [.2268.0020.0004.3153] # HANGUL LETTER EO; QQK +FFC6 ; [.2268.0020.0012.FFC6] # HALFWIDTH HANGUL LETTER EO; QQK +1166 ; [.2269.0020.0002.1166] # HANGUL JUNGSEONG E +3154 ; [.2269.0020.0004.3154] # HANGUL LETTER E; QQK +FFC7 ; [.2269.0020.0012.FFC7] # HALFWIDTH HANGUL LETTER E; QQK +1167 ; [.226A.0020.0002.1167] # HANGUL JUNGSEONG YEO +3155 ; [.226A.0020.0004.3155] # HANGUL LETTER YEO; QQK +FFCA ; [.226A.0020.0012.FFCA] # HALFWIDTH HANGUL LETTER YEO; QQK +1168 ; [.226B.0020.0002.1168] # HANGUL JUNGSEONG YE +3156 ; [.226B.0020.0004.3156] # HANGUL LETTER YE; QQK +FFCB ; [.226B.0020.0012.FFCB] # HALFWIDTH HANGUL LETTER YE; QQK +1169 ; [.226C.0020.0002.1169] # HANGUL JUNGSEONG O +3157 ; [.226C.0020.0004.3157] # HANGUL LETTER O; QQK +FFCC ; [.226C.0020.0012.FFCC] # HALFWIDTH HANGUL LETTER O; QQK +116A ; [.226D.0020.0002.116A] # HANGUL JUNGSEONG WA +3158 ; [.226D.0020.0004.3158] # HANGUL LETTER WA; QQK +FFCD ; [.226D.0020.0012.FFCD] # HALFWIDTH HANGUL LETTER WA; QQK +116B ; [.226E.0020.0002.116B] # HANGUL JUNGSEONG WAE +3159 ; [.226E.0020.0004.3159] # HANGUL LETTER WAE; QQK +FFCE ; [.226E.0020.0012.FFCE] # HALFWIDTH HANGUL LETTER WAE; QQK +116C ; [.226F.0020.0002.116C] # HANGUL JUNGSEONG OE +315A ; [.226F.0020.0004.315A] # HANGUL LETTER OE; QQK +FFCF ; [.226F.0020.0012.FFCF] # HALFWIDTH HANGUL LETTER OE; QQK +116D ; [.2270.0020.0002.116D] # HANGUL JUNGSEONG YO +315B ; [.2270.0020.0004.315B] # HANGUL LETTER YO; QQK +FFD2 ; [.2270.0020.0012.FFD2] # HALFWIDTH HANGUL LETTER YO; QQK +116E ; [.2271.0020.0002.116E] # HANGUL JUNGSEONG U +315C ; [.2271.0020.0004.315C] # HANGUL LETTER U; QQK +FFD3 ; [.2271.0020.0012.FFD3] # HALFWIDTH HANGUL LETTER U; QQK +116F ; [.2272.0020.0002.116F] # HANGUL JUNGSEONG WEO +315D ; [.2272.0020.0004.315D] # HANGUL LETTER WEO; QQK +FFD4 ; [.2272.0020.0012.FFD4] # HALFWIDTH HANGUL LETTER WEO; QQK +1170 ; [.2273.0020.0002.1170] # HANGUL JUNGSEONG WE +315E ; [.2273.0020.0004.315E] # HANGUL LETTER WE; QQK +FFD5 ; [.2273.0020.0012.FFD5] # HALFWIDTH HANGUL LETTER WE; QQK +1171 ; [.2274.0020.0002.1171] # HANGUL JUNGSEONG WI +315F ; [.2274.0020.0004.315F] # HANGUL LETTER WI; QQK +FFD6 ; [.2274.0020.0012.FFD6] # HALFWIDTH HANGUL LETTER WI; QQK +1172 ; [.2275.0020.0002.1172] # HANGUL JUNGSEONG YU +3160 ; [.2275.0020.0004.3160] # HANGUL LETTER YU; QQK +FFD7 ; [.2275.0020.0012.FFD7] # HALFWIDTH HANGUL LETTER YU; QQK +1173 ; [.2276.0020.0002.1173] # HANGUL JUNGSEONG EU +3161 ; [.2276.0020.0004.3161] # HANGUL LETTER EU; QQK +FFDA ; [.2276.0020.0012.FFDA] # HALFWIDTH HANGUL LETTER EU; QQK +1174 ; [.2277.0020.0002.1174] # HANGUL JUNGSEONG YI +3162 ; [.2277.0020.0004.3162] # HANGUL LETTER YI; QQK +FFDB ; [.2277.0020.0012.FFDB] # HALFWIDTH HANGUL LETTER YI; QQK +1175 ; [.2278.0020.0002.1175] # HANGUL JUNGSEONG I +3163 ; [.2278.0020.0004.3163] # HANGUL LETTER I; QQK +FFDC ; [.2278.0020.0012.FFDC] # HALFWIDTH HANGUL LETTER I; QQK +1176 ; [.2279.0020.0002.1176] # HANGUL JUNGSEONG A-O +1177 ; [.227A.0020.0002.1177] # HANGUL JUNGSEONG A-U +1178 ; [.227B.0020.0002.1178] # HANGUL JUNGSEONG YA-O +1179 ; [.227C.0020.0002.1179] # HANGUL JUNGSEONG YA-YO +117A ; [.227D.0020.0002.117A] # HANGUL JUNGSEONG EO-O +117B ; [.227E.0020.0002.117B] # HANGUL JUNGSEONG EO-U +117C ; [.227F.0020.0002.117C] # HANGUL JUNGSEONG EO-EU +117D ; [.2280.0020.0002.117D] # HANGUL JUNGSEONG YEO-O +117E ; [.2281.0020.0002.117E] # HANGUL JUNGSEONG YEO-U +117F ; [.2282.0020.0002.117F] # HANGUL JUNGSEONG O-EO +1180 ; [.2283.0020.0002.1180] # HANGUL JUNGSEONG O-E +1181 ; [.2284.0020.0002.1181] # HANGUL JUNGSEONG O-YE +1182 ; [.2285.0020.0002.1182] # HANGUL JUNGSEONG O-O +1183 ; [.2286.0020.0002.1183] # HANGUL JUNGSEONG O-U +1184 ; [.2287.0020.0002.1184] # HANGUL JUNGSEONG YO-YA +3187 ; [.2287.0020.0004.3187] # HANGUL LETTER YO-YA; QQK +1185 ; [.2288.0020.0002.1185] # HANGUL JUNGSEONG YO-YAE +3188 ; [.2288.0020.0004.3188] # HANGUL LETTER YO-YAE; QQK +1186 ; [.2289.0020.0002.1186] # HANGUL JUNGSEONG YO-YEO +1187 ; [.228A.0020.0002.1187] # HANGUL JUNGSEONG YO-O +1188 ; [.228B.0020.0002.1188] # HANGUL JUNGSEONG YO-I +3189 ; [.228B.0020.0004.3189] # HANGUL LETTER YO-I; QQK +1189 ; [.228C.0020.0002.1189] # HANGUL JUNGSEONG U-A +118A ; [.228D.0020.0002.118A] # HANGUL JUNGSEONG U-AE +118B ; [.228E.0020.0002.118B] # HANGUL JUNGSEONG U-EO-EU +118C ; [.228F.0020.0002.118C] # HANGUL JUNGSEONG U-YE +118D ; [.2290.0020.0002.118D] # HANGUL JUNGSEONG U-U +118E ; [.2291.0020.0002.118E] # HANGUL JUNGSEONG YU-A +118F ; [.2292.0020.0002.118F] # HANGUL JUNGSEONG YU-EO +1190 ; [.2293.0020.0002.1190] # HANGUL JUNGSEONG YU-E +1191 ; [.2294.0020.0002.1191] # HANGUL JUNGSEONG YU-YEO +318A ; [.2294.0020.0004.318A] # HANGUL LETTER YU-YEO; QQK +1192 ; [.2295.0020.0002.1192] # HANGUL JUNGSEONG YU-YE +318B ; [.2295.0020.0004.318B] # HANGUL LETTER YU-YE; QQK +1193 ; [.2296.0020.0002.1193] # HANGUL JUNGSEONG YU-U +1194 ; [.2297.0020.0002.1194] # HANGUL JUNGSEONG YU-I +318C ; [.2297.0020.0004.318C] # HANGUL LETTER YU-I; QQK +1195 ; [.2298.0020.0002.1195] # HANGUL JUNGSEONG EU-U +1196 ; [.2299.0020.0002.1196] # HANGUL JUNGSEONG EU-EU +1197 ; [.229A.0020.0002.1197] # HANGUL JUNGSEONG YI-U +1198 ; [.229B.0020.0002.1198] # HANGUL JUNGSEONG I-A +1199 ; [.229C.0020.0002.1199] # HANGUL JUNGSEONG I-YA +119A ; [.229D.0020.0002.119A] # HANGUL JUNGSEONG I-O +119B ; [.229E.0020.0002.119B] # HANGUL JUNGSEONG I-U +119C ; [.229F.0020.0002.119C] # HANGUL JUNGSEONG I-EU +119D ; [.22A0.0020.0002.119D] # HANGUL JUNGSEONG I-ARAEA +119E ; [.22A1.0020.0002.119E] # HANGUL JUNGSEONG ARAEA +318D ; [.22A1.0020.0004.318D] # HANGUL LETTER ARAEA; QQK +119F ; [.22A2.0020.0002.119F] # HANGUL JUNGSEONG ARAEA-EO +11A0 ; [.22A3.0020.0002.11A0] # HANGUL JUNGSEONG ARAEA-U +11A1 ; [.22A4.0020.0002.11A1] # HANGUL JUNGSEONG ARAEA-I +318E ; [.22A4.0020.0004.318E] # HANGUL LETTER ARAEAE; QQK +11A2 ; [.22A5.0020.0002.11A2] # HANGUL JUNGSEONG SSANGARAEA +11A8 ; [.22A6.0020.0002.11A8] # HANGUL JONGSEONG KIYEOK +11A9 ; [.22A7.0020.0002.11A9] # HANGUL JONGSEONG SSANGKIYEOK +11AA ; [.22A8.0020.0002.11AA] # HANGUL JONGSEONG KIYEOK-SIOS +3133 ; [.22A8.0020.0004.3133] # HANGUL LETTER KIYEOK-SIOS; QQK +FFA3 ; [.22A8.0020.0012.FFA3] # HALFWIDTH HANGUL LETTER KIYEOK-SIOS; QQK +11AB ; [.22A9.0020.0002.11AB] # HANGUL JONGSEONG NIEUN +11AC ; [.22AA.0020.0002.11AC] # HANGUL JONGSEONG NIEUN-CIEUC +3135 ; [.22AA.0020.0004.3135] # HANGUL LETTER NIEUN-CIEUC; QQK +FFA5 ; [.22AA.0020.0012.FFA5] # HALFWIDTH HANGUL LETTER NIEUN-CIEUC; QQK +11AD ; [.22AB.0020.0002.11AD] # HANGUL JONGSEONG NIEUN-HIEUH +3136 ; [.22AB.0020.0004.3136] # HANGUL LETTER NIEUN-HIEUH; QQK +FFA6 ; [.22AB.0020.0012.FFA6] # HALFWIDTH HANGUL LETTER NIEUN-HIEUH; QQK +11AE ; [.22AC.0020.0002.11AE] # HANGUL JONGSEONG TIKEUT +11AF ; [.22AD.0020.0002.11AF] # HANGUL JONGSEONG RIEUL +11B0 ; [.22AE.0020.0002.11B0] # HANGUL JONGSEONG RIEUL-KIYEOK +313A ; [.22AE.0020.0004.313A] # HANGUL LETTER RIEUL-KIYEOK; QQK +FFAA ; [.22AE.0020.0012.FFAA] # HALFWIDTH HANGUL LETTER RIEUL-KIYEOK; QQK +11B1 ; [.22AF.0020.0002.11B1] # HANGUL JONGSEONG RIEUL-MIEUM +313B ; [.22AF.0020.0004.313B] # HANGUL LETTER RIEUL-MIEUM; QQK +FFAB ; [.22AF.0020.0012.FFAB] # HALFWIDTH HANGUL LETTER RIEUL-MIEUM; QQK +11B2 ; [.22B0.0020.0002.11B2] # HANGUL JONGSEONG RIEUL-PIEUP +313C ; [.22B0.0020.0004.313C] # HANGUL LETTER RIEUL-PIEUP; QQK +FFAC ; [.22B0.0020.0012.FFAC] # HALFWIDTH HANGUL LETTER RIEUL-PIEUP; QQK +11B3 ; [.22B1.0020.0002.11B3] # HANGUL JONGSEONG RIEUL-SIOS +313D ; [.22B1.0020.0004.313D] # HANGUL LETTER RIEUL-SIOS; QQK +FFAD ; [.22B1.0020.0012.FFAD] # HALFWIDTH HANGUL LETTER RIEUL-SIOS; QQK +11B4 ; [.22B2.0020.0002.11B4] # HANGUL JONGSEONG RIEUL-THIEUTH +313E ; [.22B2.0020.0004.313E] # HANGUL LETTER RIEUL-THIEUTH; QQK +FFAE ; [.22B2.0020.0012.FFAE] # HALFWIDTH HANGUL LETTER RIEUL-THIEUTH; QQK +11B5 ; [.22B3.0020.0002.11B5] # HANGUL JONGSEONG RIEUL-PHIEUPH +313F ; [.22B3.0020.0004.313F] # HANGUL LETTER RIEUL-PHIEUPH; QQK +FFAF ; [.22B3.0020.0012.FFAF] # HALFWIDTH HANGUL LETTER RIEUL-PHIEUPH; QQK +11B6 ; [.22B4.0020.0002.11B6] # HANGUL JONGSEONG RIEUL-HIEUH +11B7 ; [.22B5.0020.0002.11B7] # HANGUL JONGSEONG MIEUM +11B8 ; [.22B6.0020.0002.11B8] # HANGUL JONGSEONG PIEUP +11B9 ; [.22B7.0020.0002.11B9] # HANGUL JONGSEONG PIEUP-SIOS +11BA ; [.22B8.0020.0002.11BA] # HANGUL JONGSEONG SIOS +11BB ; [.22B9.0020.0002.11BB] # HANGUL JONGSEONG SSANGSIOS +11BC ; [.22BA.0020.0002.11BC] # HANGUL JONGSEONG IEUNG +11BD ; [.22BB.0020.0002.11BD] # HANGUL JONGSEONG CIEUC +11BE ; [.22BC.0020.0002.11BE] # HANGUL JONGSEONG CHIEUCH +11BF ; [.22BD.0020.0002.11BF] # HANGUL JONGSEONG KHIEUKH +11C0 ; [.22BE.0020.0002.11C0] # HANGUL JONGSEONG THIEUTH +11C1 ; [.22BF.0020.0002.11C1] # HANGUL JONGSEONG PHIEUPH +11C2 ; [.22C0.0020.0002.11C2] # HANGUL JONGSEONG HIEUH +11C3 ; [.22C1.0020.0002.11C3] # HANGUL JONGSEONG KIYEOK-RIEUL +11C4 ; [.22C2.0020.0002.11C4] # HANGUL JONGSEONG KIYEOK-SIOS-KIYEOK +11C5 ; [.22C3.0020.0002.11C5] # HANGUL JONGSEONG NIEUN-KIYEOK +11C6 ; [.22C4.0020.0002.11C6] # HANGUL JONGSEONG NIEUN-TIKEUT +11C7 ; [.22C5.0020.0002.11C7] # HANGUL JONGSEONG NIEUN-SIOS +3167 ; [.22C5.0020.0004.3167] # HANGUL LETTER NIEUN-SIOS; QQK +11C8 ; [.22C6.0020.0002.11C8] # HANGUL JONGSEONG NIEUN-PANSIOS +3168 ; [.22C6.0020.0004.3168] # HANGUL LETTER NIEUN-PANSIOS; QQK +11C9 ; [.22C7.0020.0002.11C9] # HANGUL JONGSEONG NIEUN-THIEUTH +11CA ; [.22C8.0020.0002.11CA] # HANGUL JONGSEONG TIKEUT-KIYEOK +11CB ; [.22C9.0020.0002.11CB] # HANGUL JONGSEONG TIKEUT-RIEUL +11CC ; [.22CA.0020.0002.11CC] # HANGUL JONGSEONG RIEUL-KIYEOK-SIOS +3169 ; [.22CA.0020.0004.3169] # HANGUL LETTER RIEUL-KIYEOK-SIOS; QQK +11CD ; [.22CB.0020.0002.11CD] # HANGUL JONGSEONG RIEUL-NIEUN +11CE ; [.22CC.0020.0002.11CE] # HANGUL JONGSEONG RIEUL-TIKEUT +316A ; [.22CC.0020.0004.316A] # HANGUL LETTER RIEUL-TIKEUT; QQK +11CF ; [.22CD.0020.0002.11CF] # HANGUL JONGSEONG RIEUL-TIKEUT-HIEUH +11D0 ; [.22CE.0020.0002.11D0] # HANGUL JONGSEONG SSANGRIEUL +11D1 ; [.22CF.0020.0002.11D1] # HANGUL JONGSEONG RIEUL-MIEUM-KIYEOK +11D2 ; [.22D0.0020.0002.11D2] # HANGUL JONGSEONG RIEUL-MIEUM-SIOS +11D3 ; [.22D1.0020.0002.11D3] # HANGUL JONGSEONG RIEUL-PIEUP-SIOS +316B ; [.22D1.0020.0004.316B] # HANGUL LETTER RIEUL-PIEUP-SIOS; QQK +11D4 ; [.22D2.0020.0002.11D4] # HANGUL JONGSEONG RIEUL-PIEUP-HIEUH +11D5 ; [.22D3.0020.0002.11D5] # HANGUL JONGSEONG RIEUL-KAPYEOUNPIEUP +11D6 ; [.22D4.0020.0002.11D6] # HANGUL JONGSEONG RIEUL-SSANGSIOS +11D7 ; [.22D5.0020.0002.11D7] # HANGUL JONGSEONG RIEUL-PANSIOS +316C ; [.22D5.0020.0004.316C] # HANGUL LETTER RIEUL-PANSIOS; QQK +11D8 ; [.22D6.0020.0002.11D8] # HANGUL JONGSEONG RIEUL-KHIEUKH +11D9 ; [.22D7.0020.0002.11D9] # HANGUL JONGSEONG RIEUL-YEORINHIEUH +316D ; [.22D7.0020.0004.316D] # HANGUL LETTER RIEUL-YEORINHIEUH; QQK +11DA ; [.22D8.0020.0002.11DA] # HANGUL JONGSEONG MIEUM-KIYEOK +11DB ; [.22D9.0020.0002.11DB] # HANGUL JONGSEONG MIEUM-RIEUL +11DC ; [.22DA.0020.0002.11DC] # HANGUL JONGSEONG MIEUM-PIEUP +11DD ; [.22DB.0020.0002.11DD] # HANGUL JONGSEONG MIEUM-SIOS +316F ; [.22DB.0020.0004.316F] # HANGUL LETTER MIEUM-SIOS; QQK +11DE ; [.22DC.0020.0002.11DE] # HANGUL JONGSEONG MIEUM-SSANGSIOS +11DF ; [.22DD.0020.0002.11DF] # HANGUL JONGSEONG MIEUM-PANSIOS +3170 ; [.22DD.0020.0004.3170] # HANGUL LETTER MIEUM-PANSIOS; QQK +11E0 ; [.22DE.0020.0002.11E0] # HANGUL JONGSEONG MIEUM-CHIEUCH +11E1 ; [.22DF.0020.0002.11E1] # HANGUL JONGSEONG MIEUM-HIEUH +11E2 ; [.22E0.0020.0002.11E2] # HANGUL JONGSEONG KAPYEOUNMIEUM +11E3 ; [.22E1.0020.0002.11E3] # HANGUL JONGSEONG PIEUP-RIEUL +11E4 ; [.22E2.0020.0002.11E4] # HANGUL JONGSEONG PIEUP-PHIEUPH +11E5 ; [.22E3.0020.0002.11E5] # HANGUL JONGSEONG PIEUP-HIEUH +11E6 ; [.22E4.0020.0002.11E6] # HANGUL JONGSEONG KAPYEOUNPIEUP +11E7 ; [.22E5.0020.0002.11E7] # HANGUL JONGSEONG SIOS-KIYEOK +11E8 ; [.22E6.0020.0002.11E8] # HANGUL JONGSEONG SIOS-TIKEUT +11E9 ; [.22E7.0020.0002.11E9] # HANGUL JONGSEONG SIOS-RIEUL +11EA ; [.22E8.0020.0002.11EA] # HANGUL JONGSEONG SIOS-PIEUP +11EB ; [.22E9.0020.0002.11EB] # HANGUL JONGSEONG PANSIOS +11EC ; [.22EA.0020.0002.11EC] # HANGUL JONGSEONG IEUNG-KIYEOK +11ED ; [.22EB.0020.0002.11ED] # HANGUL JONGSEONG IEUNG-SSANGKIYEOK +11EE ; [.22EC.0020.0002.11EE] # HANGUL JONGSEONG SSANGIEUNG +11EF ; [.22ED.0020.0002.11EF] # HANGUL JONGSEONG IEUNG-KHIEUKH +11F0 ; [.22EE.0020.0002.11F0] # HANGUL JONGSEONG YESIEUNG +11F1 ; [.22EF.0020.0002.11F1] # HANGUL JONGSEONG YESIEUNG-SIOS +3182 ; [.22EF.0020.0004.3182] # HANGUL LETTER YESIEUNG-SIOS; QQK +11F2 ; [.22F0.0020.0002.11F2] # HANGUL JONGSEONG YESIEUNG-PANSIOS +3183 ; [.22F0.0020.0004.3183] # HANGUL LETTER YESIEUNG-PANSIOS; QQK +11F3 ; [.22F1.0020.0002.11F3] # HANGUL JONGSEONG PHIEUPH-PIEUP +11F4 ; [.22F2.0020.0002.11F4] # HANGUL JONGSEONG KAPYEOUNPHIEUPH +11F5 ; [.22F3.0020.0002.11F5] # HANGUL JONGSEONG HIEUH-NIEUN +11F6 ; [.22F4.0020.0002.11F6] # HANGUL JONGSEONG HIEUH-RIEUL +11F7 ; [.22F5.0020.0002.11F7] # HANGUL JONGSEONG HIEUH-MIEUM +11F8 ; [.22F6.0020.0002.11F8] # HANGUL JONGSEONG HIEUH-PIEUP +11F9 ; [.22F7.0020.0002.11F9] # HANGUL JONGSEONG YEORINHIEUH +3041 ; [.22F8.0020.000D.3041] # HIRAGANA LETTER SMALL A +3042 ; [.22F8.0020.000E.3042] # HIRAGANA LETTER A +30A1 ; [.22F8.0020.000F.30A1] # KATAKANA LETTER SMALL A +FF67 ; [.22F8.0020.0010.FF67] # HALFWIDTH KATAKANA LETTER SMALL A; QQK +30A2 ; [.22F8.0020.0011.30A2] # KATAKANA LETTER A +FF71 ; [.22F8.0020.0012.FF71] # HALFWIDTH KATAKANA LETTER A; QQK +32D0 ; [.22F8.0020.0013.32D0] # CIRCLED KATAKANA A; QQK +3303 ; [.22F8.0020.001C.3303][.0FA3.0020.001C.3303][.2320.0020.001F.3303] # SQUARE AARU; QQKN +3300 ; [.22F8.0020.001C.3300][.2311.0020.001C.3300][.0000.0178.001F.3300][.0FA3.0020.001F.3300][.230B.0020.001F.3300] # SQUARE APAATO; QQKN +3301 ; [.22F8.0020.001C.3301][.2320.0020.001C.3301][.2313.0020.001F.3301][.22F8.0020.001F.3301] # SQUARE ARUHUA; QQKN +3302 ; [.22F8.0020.001C.3302][.2327.0020.001C.3302][.2314.0020.001F.3302][.0000.0178.001F.3302][.22F8.0020.001F.3302] # SQUARE ANPEA; QQKN +3043 ; [.22F9.0020.000D.3043] # HIRAGANA LETTER SMALL I +3044 ; [.22F9.0020.000E.3044] # HIRAGANA LETTER I +30A3 ; [.22F9.0020.000F.30A3] # KATAKANA LETTER SMALL I +FF68 ; [.22F9.0020.0010.FF68] # HALFWIDTH KATAKANA LETTER SMALL I; QQK +30A4 ; [.22F9.0020.0011.30A4] # KATAKANA LETTER I +FF72 ; [.22F9.0020.0012.FF72] # HALFWIDTH KATAKANA LETTER I; QQK +32D1 ; [.22F9.0020.0013.32D1] # CIRCLED KATAKANA I; QQK +3304 ; [.22F9.0020.001C.3304][.230D.0020.001C.3304][.2327.0020.001F.3304][.22FF.0020.001F.3304][.0000.0177.001F.3304] # SQUARE ININGU; QQKN +3305 ; [.22F9.0020.001C.3305][.2327.0020.001C.3305][.2308.0020.001F.3305] # SQUARE INTI; QQKN +3045 ; [.22FA.0020.000D.3045] # HIRAGANA LETTER SMALL U +3046 ; [.22FA.0020.000E.3046] # HIRAGANA LETTER U +30A5 ; [.22FA.0020.000F.30A5] # KATAKANA LETTER SMALL U +FF69 ; [.22FA.0020.0010.FF69] # HALFWIDTH KATAKANA LETTER SMALL U; QQK +30A6 ; [.22FA.0020.0011.30A6] # KATAKANA LETTER U +FF73 ; [.22FA.0020.0012.FF73] # HALFWIDTH KATAKANA LETTER U; QQK +32D2 ; [.22FA.0020.0013.32D2] # CIRCLED KATAKANA U; QQK +3094 ; [.22FA.0020.000E.3046][.0000.0177.0002.3099] # HIRAGANA LETTER VU; QQCM +30F4 ; [.22FA.0020.0011.30A6][.0000.0177.0002.3099] # KATAKANA LETTER VU; QQCM +3306 ; [.22FA.0020.001C.3306][.22FC.0020.001C.3306][.2327.0020.001F.3306] # SQUARE UON; QQKN +3047 ; [.22FB.0020.000D.3047] # HIRAGANA LETTER SMALL E +3048 ; [.22FB.0020.000E.3048] # HIRAGANA LETTER E +30A7 ; [.22FB.0020.000F.30A7] # KATAKANA LETTER SMALL E +FF6A ; [.22FB.0020.0010.FF6A] # HALFWIDTH KATAKANA LETTER SMALL E; QQK +30A8 ; [.22FB.0020.0011.30A8] # KATAKANA LETTER E +FF74 ; [.22FB.0020.0012.FF74] # HALFWIDTH KATAKANA LETTER E; QQK +32D3 ; [.22FB.0020.0013.32D3] # CIRCLED KATAKANA E; QQK +3308 ; [.22FB.0020.001C.3308][.0FA3.0020.001C.3308][.22FD.0020.001F.3308][.0FA3.0020.001F.3308] # SQUARE EEKAA; QQKN +3307 ; [.22FB.0020.001C.3307][.2304.0020.001C.3307][.22FF.0020.001F.3307][.0FA3.0020.001F.3307][.230B.0020.001F.3307][.0000.0177.001F.3307] # SQUARE ESUKUUDO; QQKN +3049 ; [.22FC.0020.000D.3049] # HIRAGANA LETTER SMALL O +304A ; [.22FC.0020.000E.304A] # HIRAGANA LETTER O +30A9 ; [.22FC.0020.000F.30A9] # KATAKANA LETTER SMALL O +FF6B ; [.22FC.0020.0010.FF6B] # HALFWIDTH KATAKANA LETTER SMALL O; QQK +30AA ; [.22FC.0020.0011.30AA] # KATAKANA LETTER O +FF75 ; [.22FC.0020.0012.FF75] # HALFWIDTH KATAKANA LETTER O; QQK +32D4 ; [.22FC.0020.0013.32D4] # CIRCLED KATAKANA O; QQK +330A ; [.22FC.0020.001C.330A][.0FA3.0020.001C.330A][.2318.0020.001F.330A] # SQUARE OOMU; QQKN +3309 ; [.22FC.0020.001C.3309][.2327.0020.001C.3309][.2304.0020.001F.3309] # SQUARE ONSU; QQKN +3095 ; [.22FD.0020.000D.3095] # HIRAGANA LETTER SMALL KA +304B ; [.22FD.0020.000E.304B] # HIRAGANA LETTER KA +30F5 ; [.22FD.0020.000F.30F5] # KATAKANA LETTER SMALL KA +30AB ; [.22FD.0020.0011.30AB] # KATAKANA LETTER KA +FF76 ; [.22FD.0020.0012.FF76] # HALFWIDTH KATAKANA LETTER KA; QQK +32D5 ; [.22FD.0020.0013.32D5] # CIRCLED KATAKANA KA; QQK +304C ; [.22FD.0020.000E.304B][.0000.0177.0002.3099] # HIRAGANA LETTER GA; QQCM +30AC ; [.22FD.0020.0011.30AB][.0000.0177.0002.3099] # KATAKANA LETTER GA; QQCM +330B ; [.22FD.0020.001C.330B][.22F9.0020.001C.330B][.231F.0020.001F.330B] # SQUARE KAIRI; QQKN +330C ; [.22FD.0020.001C.330C][.231E.0020.001C.330C][.2309.0020.001F.330C][.230B.0020.001F.330C] # SQUARE KARATTO; QQKN +330D ; [.22FD.0020.001C.330D][.2322.0020.001C.330D][.231F.0020.001F.330D][.0FA3.0020.001F.330D] # SQUARE KARORII; QQKN +330E ; [.22FD.0020.001C.330E][.0000.0177.001C.330E][.2322.0020.001F.330E][.2327.0020.001F.330E] # SQUARE GARON; QQKN +330F ; [.22FD.0020.001C.330F][.0000.0177.001C.330F][.2327.0020.001F.330F][.2316.0020.001F.330F] # SQUARE GANMA; QQKN +304D ; [.22FE.0020.000E.304D] # HIRAGANA LETTER KI +30AD ; [.22FE.0020.0011.30AD] # KATAKANA LETTER KI +FF77 ; [.22FE.0020.0012.FF77] # HALFWIDTH KATAKANA LETTER KI; QQK +32D6 ; [.22FE.0020.0013.32D6] # CIRCLED KATAKANA KI; QQK +304E ; [.22FE.0020.000E.304D][.0000.0177.0002.3099] # HIRAGANA LETTER GI; QQCM +30AE ; [.22FE.0020.0011.30AD][.0000.0177.0002.3099] # KATAKANA LETTER GI; QQCM +3310 ; [.22FE.0020.001C.3310][.0000.0177.001C.3310][.22FD.0020.001F.3310][.0000.0177.001F.3310] # SQUARE GIGA; QQKN +3311 ; [.22FE.0020.001C.3311][.0000.0177.001C.3311][.230D.0020.001F.3311][.0FA3.0020.001F.3311] # SQUARE GINII; QQKN +3312 ; [.22FE.0020.001C.3312][.231C.0020.001C.3312][.231F.0020.001F.3312][.0FA3.0020.001F.3312] # SQUARE KYURII; QQKN +3313 ; [.22FE.0020.001C.3313][.0000.0177.001C.3313][.2320.0020.001F.3313][.2307.0020.001F.3313][.0000.0177.001F.3313][.0FA3.0020.001F.3313] # SQUARE GIRUDAA; QQKN +3314 ; [.22FE.0020.001C.3314][.2322.0020.001C.3314] # SQUARE KIRO; QQKN +3315 ; [.22FE.0020.001C.3315][.2322.0020.001C.3315][.22FF.0020.001F.3315][.0000.0177.001F.3315][.231E.0020.001F.3315][.2318.0020.001F.3315] # SQUARE KIROGURAMU; QQKN +3316 ; [.22FE.0020.001C.3316][.2322.0020.001C.3316][.2319.0020.001F.3316][.0FA3.0020.001F.3316][.230B.0020.001F.3316][.2320.0020.001F.3316] # SQUARE KIROMEETORU; QQKN +3317 ; [.22FE.0020.001C.3317][.2322.0020.001C.3317][.2323.0020.001F.3317][.2309.0020.001F.3317][.230B.0020.001F.3317] # SQUARE KIROWATTO; QQKN +304F ; [.22FF.0020.000E.304F] # HIRAGANA LETTER KU +31F0 ; [.22FF.0020.000F.31F0] # KATAKANA LETTER SMALL KU +30AF ; [.22FF.0020.0011.30AF] # KATAKANA LETTER KU +FF78 ; [.22FF.0020.0012.FF78] # HALFWIDTH KATAKANA LETTER KU; QQK +32D7 ; [.22FF.0020.0013.32D7] # CIRCLED KATAKANA KU; QQK +3050 ; [.22FF.0020.000E.304F][.0000.0177.0002.3099] # HIRAGANA LETTER GU; QQCM +30B0 ; [.22FF.0020.0011.30AF][.0000.0177.0002.3099] # KATAKANA LETTER GU; QQCM +3318 ; [.22FF.0020.001C.3318][.0000.0177.001C.3318][.231E.0020.001F.3318][.2318.0020.001F.3318] # SQUARE GURAMU; QQKN +3319 ; [.22FF.0020.001C.3319][.0000.0177.001C.3319][.231E.0020.001F.3319][.2318.0020.001F.3319][.230B.0020.001F.3319][.2327.0020.001F.3319] # SQUARE GURAMUTON; QQKN +331A ; [.22FF.0020.001C.331A][.2320.0020.001C.331A][.2305.0020.001F.331A][.0000.0177.001F.331A][.22F9.0020.001F.331A][.2322.0020.001F.331A] # SQUARE KURUZEIRO; QQKN +331B ; [.22FF.0020.001C.331B][.2322.0020.001C.331B][.0FA3.0020.001F.331B][.230F.0020.001F.331B] # SQUARE KUROONE; QQKN +3096 ; [.2300.0020.000D.3096] # HIRAGANA LETTER SMALL KE +3051 ; [.2300.0020.000E.3051] # HIRAGANA LETTER KE +30F6 ; [.2300.0020.000F.30F6] # KATAKANA LETTER SMALL KE +30B1 ; [.2300.0020.0011.30B1] # KATAKANA LETTER KE +FF79 ; [.2300.0020.0012.FF79] # HALFWIDTH KATAKANA LETTER KE; QQK +32D8 ; [.2300.0020.0013.32D8] # CIRCLED KATAKANA KE; QQK +3052 ; [.2300.0020.000E.3051][.0000.0177.0002.3099] # HIRAGANA LETTER GE; QQCM +30B2 ; [.2300.0020.0011.30B1][.0000.0177.0002.3099] # KATAKANA LETTER GE; QQCM +331C ; [.2300.0020.001C.331C][.0FA3.0020.001C.331C][.2304.0020.001F.331C] # SQUARE KEESU; QQKN +3053 ; [.2301.0020.000E.3053] # HIRAGANA LETTER KO +30B3 ; [.2301.0020.0011.30B3] # KATAKANA LETTER KO +FF7A ; [.2301.0020.0012.FF7A] # HALFWIDTH KATAKANA LETTER KO; QQK +32D9 ; [.2301.0020.0013.32D9] # CIRCLED KATAKANA KO; QQK +3054 ; [.2301.0020.000E.3053][.0000.0177.0002.3099] # HIRAGANA LETTER GO; QQCM +30B4 ; [.2301.0020.0011.30B3][.0000.0177.0002.3099] # KATAKANA LETTER GO; QQCM +331E ; [.2301.0020.001C.331E][.0FA3.0020.001C.331E][.2315.0020.001F.331E][.0000.0178.001F.331E] # SQUARE KOOPO; QQKN +30FF ; [.2301.0020.0016.30FF][.230B.0020.0016.30FF] # KATAKANA DIGRAPH KOTO; QQKN +331D ; [.2301.0020.001C.331D][.2320.0020.001C.331D][.230C.0020.001F.331D] # SQUARE KORUNA; QQKN +3055 ; [.2302.0020.000E.3055] # HIRAGANA LETTER SA +30B5 ; [.2302.0020.0011.30B5] # KATAKANA LETTER SA +FF7B ; [.2302.0020.0012.FF7B] # HALFWIDTH KATAKANA LETTER SA; QQK +32DA ; [.2302.0020.0013.32DA] # CIRCLED KATAKANA SA; QQK +3056 ; [.2302.0020.000E.3055][.0000.0177.0002.3099] # HIRAGANA LETTER ZA; QQCM +30B6 ; [.2302.0020.0011.30B5][.0000.0177.0002.3099] # KATAKANA LETTER ZA; QQCM +331F ; [.2302.0020.001C.331F][.22F9.0020.001C.331F][.22FF.0020.001F.331F][.2320.0020.001F.331F] # SQUARE SAIKURU; QQKN +3320 ; [.2302.0020.001C.3320][.2327.0020.001C.3320][.2308.0020.001F.3320][.0FA3.0020.001F.3320][.2318.0020.001F.3320] # SQUARE SANTIIMU; QQKN +3057 ; [.2303.0020.000E.3057] # HIRAGANA LETTER SI +31F1 ; [.2303.0020.000F.31F1] # KATAKANA LETTER SMALL SI +30B7 ; [.2303.0020.0011.30B7] # KATAKANA LETTER SI +FF7C ; [.2303.0020.0012.FF7C] # HALFWIDTH KATAKANA LETTER SI; QQK +32DB ; [.2303.0020.0013.32DB] # CIRCLED KATAKANA SI; QQK +3058 ; [.2303.0020.000E.3057][.0000.0177.0002.3099] # HIRAGANA LETTER ZI; QQCM +30B8 ; [.2303.0020.0011.30B7][.0000.0177.0002.3099] # KATAKANA LETTER ZI; QQCM +3006 ; [.2303.0020.0004.3006][.2319.0020.0004.3006] # IDEOGRAPHIC CLOSING MARK; QQKN +3321 ; [.2303.0020.001C.3321][.231F.0020.001C.3321][.2327.0020.001F.3321][.22FF.0020.001F.3321][.0000.0177.001F.3321] # SQUARE SIRINGU; QQKN +3059 ; [.2304.0020.000E.3059] # HIRAGANA LETTER SU +31F2 ; [.2304.0020.000F.31F2] # KATAKANA LETTER SMALL SU +30B9 ; [.2304.0020.0011.30B9] # KATAKANA LETTER SU +FF7D ; [.2304.0020.0012.FF7D] # HALFWIDTH KATAKANA LETTER SU; QQK +32DC ; [.2304.0020.0013.32DC] # CIRCLED KATAKANA SU; QQK +305A ; [.2304.0020.000E.3059][.0000.0177.0002.3099] # HIRAGANA LETTER ZU; QQCM +30BA ; [.2304.0020.0011.30B9][.0000.0177.0002.3099] # KATAKANA LETTER ZU; QQCM +305B ; [.2305.0020.000E.305B] # HIRAGANA LETTER SE +30BB ; [.2305.0020.0011.30BB] # KATAKANA LETTER SE +FF7E ; [.2305.0020.0012.FF7E] # HALFWIDTH KATAKANA LETTER SE; QQK +32DD ; [.2305.0020.0013.32DD] # CIRCLED KATAKANA SE; QQK +305C ; [.2305.0020.000E.305B][.0000.0177.0002.3099] # HIRAGANA LETTER ZE; QQCM +30BC ; [.2305.0020.0011.30BB][.0000.0177.0002.3099] # KATAKANA LETTER ZE; QQCM +3322 ; [.2305.0020.001C.3322][.2327.0020.001C.3322][.2308.0020.001F.3322] # SQUARE SENTI; QQKN +3323 ; [.2305.0020.001C.3323][.2327.0020.001C.3323][.230B.0020.001F.3323] # SQUARE SENTO; QQKN +305D ; [.2306.0020.000E.305D] # HIRAGANA LETTER SO +30BD ; [.2306.0020.0011.30BD] # KATAKANA LETTER SO +FF7F ; [.2306.0020.0012.FF7F] # HALFWIDTH KATAKANA LETTER SO; QQK +32DE ; [.2306.0020.0013.32DE] # CIRCLED KATAKANA SO; QQK +305E ; [.2306.0020.000E.305D][.0000.0177.0002.3099] # HIRAGANA LETTER ZO; QQCM +30BE ; [.2306.0020.0011.30BD][.0000.0177.0002.3099] # KATAKANA LETTER ZO; QQCM +305F ; [.2307.0020.000E.305F] # HIRAGANA LETTER TA +30BF ; [.2307.0020.0011.30BF] # KATAKANA LETTER TA +FF80 ; [.2307.0020.0012.FF80] # HALFWIDTH KATAKANA LETTER TA; QQK +32DF ; [.2307.0020.0013.32DF] # CIRCLED KATAKANA TA; QQK +3060 ; [.2307.0020.000E.305F][.0000.0177.0002.3099] # HIRAGANA LETTER DA; QQCM +30C0 ; [.2307.0020.0011.30BF][.0000.0177.0002.3099] # KATAKANA LETTER DA; QQCM +3324 ; [.2307.0020.001C.3324][.0000.0177.001C.3324][.0FA3.0020.001F.3324][.2304.0020.001F.3324] # SQUARE DAASU; QQKN +3061 ; [.2308.0020.000E.3061] # HIRAGANA LETTER TI +30C1 ; [.2308.0020.0011.30C1] # KATAKANA LETTER TI +FF81 ; [.2308.0020.0012.FF81] # HALFWIDTH KATAKANA LETTER TI; QQK +32E0 ; [.2308.0020.0013.32E0] # CIRCLED KATAKANA TI; QQK +3062 ; [.2308.0020.000E.3061][.0000.0177.0002.3099] # HIRAGANA LETTER DI; QQCM +30C2 ; [.2308.0020.0011.30C1][.0000.0177.0002.3099] # KATAKANA LETTER DI; QQCM +3063 ; [.2309.0020.000D.3063] # HIRAGANA LETTER SMALL TU +3064 ; [.2309.0020.000E.3064] # HIRAGANA LETTER TU +30C3 ; [.2309.0020.000F.30C3] # KATAKANA LETTER SMALL TU +FF6F ; [.2309.0020.0010.FF6F] # HALFWIDTH KATAKANA LETTER SMALL TU; QQK +30C4 ; [.2309.0020.0011.30C4] # KATAKANA LETTER TU +FF82 ; [.2309.0020.0012.FF82] # HALFWIDTH KATAKANA LETTER TU; QQK +32E1 ; [.2309.0020.0013.32E1] # CIRCLED KATAKANA TU; QQK +3065 ; [.2309.0020.000E.3064][.0000.0177.0002.3099] # HIRAGANA LETTER DU; QQCM +30C5 ; [.2309.0020.0011.30C4][.0000.0177.0002.3099] # KATAKANA LETTER DU; QQCM +3066 ; [.230A.0020.000E.3066] # HIRAGANA LETTER TE +30C6 ; [.230A.0020.0011.30C6] # KATAKANA LETTER TE +FF83 ; [.230A.0020.0012.FF83] # HALFWIDTH KATAKANA LETTER TE; QQK +32E2 ; [.230A.0020.0013.32E2] # CIRCLED KATAKANA TE; QQK +3067 ; [.230A.0020.000E.3066][.0000.0177.0002.3099] # HIRAGANA LETTER DE; QQCM +30C7 ; [.230A.0020.0011.30C6][.0000.0177.0002.3099] # KATAKANA LETTER DE; QQCM +3325 ; [.230A.0020.001C.3325][.0000.0177.001C.3325][.2303.0020.001F.3325] # SQUARE DESI; QQKN +3068 ; [.230B.0020.000E.3068] # HIRAGANA LETTER TO +31F3 ; [.230B.0020.000F.31F3] # KATAKANA LETTER SMALL TO +30C8 ; [.230B.0020.0011.30C8] # KATAKANA LETTER TO +FF84 ; [.230B.0020.0012.FF84] # HALFWIDTH KATAKANA LETTER TO; QQK +32E3 ; [.230B.0020.0013.32E3] # CIRCLED KATAKANA TO; QQK +3069 ; [.230B.0020.000E.3068][.0000.0177.0002.3099] # HIRAGANA LETTER DO; QQCM +30C9 ; [.230B.0020.0011.30C8][.0000.0177.0002.3099] # KATAKANA LETTER DO; QQCM +3326 ; [.230B.0020.001C.3326][.0000.0177.001C.3326][.2320.0020.001F.3326] # SQUARE DORU; QQKN +3327 ; [.230B.0020.001C.3327][.2327.0020.001C.3327] # SQUARE TON; QQKN +306A ; [.230C.0020.000E.306A] # HIRAGANA LETTER NA +30CA ; [.230C.0020.0011.30CA] # KATAKANA LETTER NA +FF85 ; [.230C.0020.0012.FF85] # HALFWIDTH KATAKANA LETTER NA; QQK +32E4 ; [.230C.0020.0013.32E4] # CIRCLED KATAKANA NA; QQK +3328 ; [.230C.0020.001C.3328][.2310.0020.001C.3328] # SQUARE NANO; QQKN +306B ; [.230D.0020.000E.306B] # HIRAGANA LETTER NI +30CB ; [.230D.0020.0011.30CB] # KATAKANA LETTER NI +FF86 ; [.230D.0020.0012.FF86] # HALFWIDTH KATAKANA LETTER NI; QQK +32E5 ; [.230D.0020.0013.32E5] # CIRCLED KATAKANA NI; QQK +306C ; [.230E.0020.000E.306C] # HIRAGANA LETTER NU +31F4 ; [.230E.0020.000F.31F4] # KATAKANA LETTER SMALL NU +30CC ; [.230E.0020.0011.30CC] # KATAKANA LETTER NU +FF87 ; [.230E.0020.0012.FF87] # HALFWIDTH KATAKANA LETTER NU; QQK +32E6 ; [.230E.0020.0013.32E6] # CIRCLED KATAKANA NU; QQK +306D ; [.230F.0020.000E.306D] # HIRAGANA LETTER NE +30CD ; [.230F.0020.0011.30CD] # KATAKANA LETTER NE +FF88 ; [.230F.0020.0012.FF88] # HALFWIDTH KATAKANA LETTER NE; QQK +32E7 ; [.230F.0020.0013.32E7] # CIRCLED KATAKANA NE; QQK +306E ; [.2310.0020.000E.306E] # HIRAGANA LETTER NO +30CE ; [.2310.0020.0011.30CE] # KATAKANA LETTER NO +FF89 ; [.2310.0020.0012.FF89] # HALFWIDTH KATAKANA LETTER NO; QQK +32E8 ; [.2310.0020.0013.32E8] # CIRCLED KATAKANA NO; QQK +3329 ; [.2310.0020.001C.3329][.2309.0020.001C.3329][.230B.0020.001F.3329] # SQUARE NOTTO; QQKN +306F ; [.2311.0020.000E.306F] # HIRAGANA LETTER HA +31F5 ; [.2311.0020.000F.31F5] # KATAKANA LETTER SMALL HA +30CF ; [.2311.0020.0011.30CF] # KATAKANA LETTER HA +FF8A ; [.2311.0020.0012.FF8A] # HALFWIDTH KATAKANA LETTER HA; QQK +32E9 ; [.2311.0020.0013.32E9] # CIRCLED KATAKANA HA; QQK +3070 ; [.2311.0020.000E.306F][.0000.0177.0002.3099] # HIRAGANA LETTER BA; QQCM +30D0 ; [.2311.0020.0011.30CF][.0000.0177.0002.3099] # KATAKANA LETTER BA; QQCM +3071 ; [.2311.0020.000E.306F][.0000.0178.0002.309A] # HIRAGANA LETTER PA; QQCM +30D1 ; [.2311.0020.0011.30CF][.0000.0178.0002.309A] # KATAKANA LETTER PA; QQCM +332B ; [.2311.0020.001C.332B][.0000.0178.001C.332B][.0FA3.0020.001F.332B][.2305.0020.001F.332B][.2327.0020.001F.332B][.230B.0020.001F.332B] # SQUARE PAASENTO; QQKN +332C ; [.2311.0020.001C.332C][.0000.0178.001C.332C][.0FA3.0020.001F.332C][.2309.0020.001F.332C] # SQUARE PAATU; QQKN +332D ; [.2311.0020.001C.332D][.0000.0177.001C.332D][.0FA3.0020.001F.332D][.2321.0020.001F.332D][.2320.0020.001F.332D] # SQUARE BAARERU; QQKN +332A ; [.2311.0020.001C.332A][.22F9.0020.001C.332A][.2309.0020.001F.332A] # SQUARE HAITU; QQKN +3072 ; [.2312.0020.000E.3072] # HIRAGANA LETTER HI +31F6 ; [.2312.0020.000F.31F6] # KATAKANA LETTER SMALL HI +30D2 ; [.2312.0020.0011.30D2] # KATAKANA LETTER HI +FF8B ; [.2312.0020.0012.FF8B] # HALFWIDTH KATAKANA LETTER HI; QQK +32EA ; [.2312.0020.0013.32EA] # CIRCLED KATAKANA HI; QQK +3073 ; [.2312.0020.000E.3072][.0000.0177.0002.3099] # HIRAGANA LETTER BI; QQCM +30D3 ; [.2312.0020.0011.30D2][.0000.0177.0002.3099] # KATAKANA LETTER BI; QQCM +3074 ; [.2312.0020.000E.3072][.0000.0178.0002.309A] # HIRAGANA LETTER PI; QQCM +30D4 ; [.2312.0020.0011.30D2][.0000.0178.0002.309A] # KATAKANA LETTER PI; QQCM +332E ; [.2312.0020.001C.332E][.0000.0178.001C.332E][.22F8.0020.001F.332E][.2304.0020.001F.332E][.230B.0020.001F.332E][.2320.0020.001F.332E] # SQUARE PIASUTORU; QQKN +332F ; [.2312.0020.001C.332F][.0000.0178.001C.332F][.22FF.0020.001F.332F][.2320.0020.001F.332F] # SQUARE PIKURU; QQKN +3330 ; [.2312.0020.001C.3330][.0000.0178.001C.3330][.2301.0020.001F.3330] # SQUARE PIKO; QQKN +3331 ; [.2312.0020.001C.3331][.0000.0177.001C.3331][.2320.0020.001F.3331] # SQUARE BIRU; QQKN +3075 ; [.2313.0020.000E.3075] # HIRAGANA LETTER HU +31F7 ; [.2313.0020.000F.31F7] # KATAKANA LETTER SMALL HU +30D5 ; [.2313.0020.0011.30D5] # KATAKANA LETTER HU +FF8C ; [.2313.0020.0012.FF8C] # HALFWIDTH KATAKANA LETTER HU; QQK +32EB ; [.2313.0020.0013.32EB] # CIRCLED KATAKANA HU; QQK +3076 ; [.2313.0020.000E.3075][.0000.0177.0002.3099] # HIRAGANA LETTER BU; QQCM +30D6 ; [.2313.0020.0011.30D5][.0000.0177.0002.3099] # KATAKANA LETTER BU; QQCM +3077 ; [.2313.0020.000E.3075][.0000.0178.0002.309A] # HIRAGANA LETTER PU; QQCM +30D7 ; [.2313.0020.0011.30D5][.0000.0178.0002.309A] # KATAKANA LETTER PU; QQCM +3332 ; [.2313.0020.001C.3332][.22F8.0020.001C.3332][.231E.0020.001F.3332][.2309.0020.001F.3332][.230B.0020.001F.3332][.0000.0177.001F.3332] # SQUARE HUARADDO; QQKN +3333 ; [.2313.0020.001C.3333][.22F9.0020.001C.3333][.0FA3.0020.001F.3333][.230B.0020.001F.3333] # SQUARE HUIITO; QQKN +3334 ; [.2313.0020.001C.3334][.0000.0177.001C.3334][.2309.0020.001F.3334][.2303.0020.001F.3334][.22FB.0020.001F.3334][.2320.0020.001F.3334] # SQUARE BUSSYERU; QQKN +3335 ; [.2313.0020.001C.3335][.231E.0020.001C.3335][.2327.0020.001F.3335] # SQUARE HURAN; QQKN +3078 ; [.2314.0020.000E.3078] # HIRAGANA LETTER HE +31F8 ; [.2314.0020.000F.31F8] # KATAKANA LETTER SMALL HE +30D8 ; [.2314.0020.0011.30D8] # KATAKANA LETTER HE +FF8D ; [.2314.0020.0012.FF8D] # HALFWIDTH KATAKANA LETTER HE; QQK +32EC ; [.2314.0020.0013.32EC] # CIRCLED KATAKANA HE; QQK +3079 ; [.2314.0020.000E.3078][.0000.0177.0002.3099] # HIRAGANA LETTER BE; QQCM +30D9 ; [.2314.0020.0011.30D8][.0000.0177.0002.3099] # KATAKANA LETTER BE; QQCM +307A ; [.2314.0020.000E.3078][.0000.0178.0002.309A] # HIRAGANA LETTER PE; QQCM +30DA ; [.2314.0020.0011.30D8][.0000.0178.0002.309A] # KATAKANA LETTER PE; QQCM +333B ; [.2314.0020.001C.333B][.0000.0178.001C.333B][.0FA3.0020.001F.333B][.2303.0020.001F.333B][.0000.0177.001F.333B] # SQUARE PEEZI; QQKN +333C ; [.2314.0020.001C.333C][.0000.0177.001C.333C][.0FA3.0020.001F.333C][.2307.0020.001F.333C] # SQUARE BEETA; QQKN +3336 ; [.2314.0020.001C.3336][.22FF.0020.001C.3336][.2307.0020.001F.3336][.0FA3.0020.001F.3336][.2320.0020.001F.3336] # SQUARE HEKUTAARU; QQKN +3337 ; [.2314.0020.001C.3337][.0000.0178.001C.3337][.2306.0020.001F.3337] # SQUARE PESO; QQKN +3338 ; [.2314.0020.001C.3338][.0000.0178.001C.3338][.230D.0020.001F.3338][.2312.0020.001F.3338] # SQUARE PENIHI; QQKN +3339 ; [.2314.0020.001C.3339][.2320.0020.001C.3339][.2309.0020.001F.3339] # SQUARE HERUTU; QQKN +333A ; [.2314.0020.001C.333A][.0000.0178.001C.333A][.2327.0020.001F.333A][.2304.0020.001F.333A] # SQUARE PENSU; QQKN +307B ; [.2315.0020.000E.307B] # HIRAGANA LETTER HO +31F9 ; [.2315.0020.000F.31F9] # KATAKANA LETTER SMALL HO +30DB ; [.2315.0020.0011.30DB] # KATAKANA LETTER HO +FF8E ; [.2315.0020.0012.FF8E] # HALFWIDTH KATAKANA LETTER HO; QQK +32ED ; [.2315.0020.0013.32ED] # CIRCLED KATAKANA HO; QQK +307C ; [.2315.0020.000E.307B][.0000.0177.0002.3099] # HIRAGANA LETTER BO; QQCM +30DC ; [.2315.0020.0011.30DB][.0000.0177.0002.3099] # KATAKANA LETTER BO; QQCM +307D ; [.2315.0020.000E.307B][.0000.0178.0002.309A] # HIRAGANA LETTER PO; QQCM +30DD ; [.2315.0020.0011.30DB][.0000.0178.0002.309A] # KATAKANA LETTER PO; QQCM +3341 ; [.2315.0020.001C.3341][.0FA3.0020.001C.3341][.2320.0020.001F.3341] # SQUARE HOORU; QQKN +3342 ; [.2315.0020.001C.3342][.0FA3.0020.001C.3342][.2327.0020.001F.3342] # SQUARE HOON; QQKN +333D ; [.2315.0020.001C.333D][.0000.0178.001C.333D][.22F9.0020.001F.333D][.2327.0020.001F.333D][.230B.0020.001F.333D] # SQUARE POINTO; QQKN +333E ; [.2315.0020.001C.333E][.0000.0177.001C.333E][.2320.0020.001F.333E][.230B.0020.001F.333E] # SQUARE BORUTO; QQKN +333F ; [.2315.0020.001C.333F][.2327.0020.001C.333F] # SQUARE HON; QQKN +3340 ; [.2315.0020.001C.3340][.0000.0178.001C.3340][.2327.0020.001F.3340][.230B.0020.001F.3340][.0000.0177.001F.3340] # SQUARE PONDO; QQKN +307E ; [.2316.0020.000E.307E] # HIRAGANA LETTER MA +30DE ; [.2316.0020.0011.30DE] # KATAKANA LETTER MA +FF8F ; [.2316.0020.0012.FF8F] # HALFWIDTH KATAKANA LETTER MA; QQK +32EE ; [.2316.0020.0013.32EE] # CIRCLED KATAKANA MA; QQK +3343 ; [.2316.0020.001C.3343][.22F9.0020.001C.3343][.22FF.0020.001F.3343][.2322.0020.001F.3343] # SQUARE MAIKURO; QQKN +3344 ; [.2316.0020.001C.3344][.22F9.0020.001C.3344][.2320.0020.001F.3344] # SQUARE MAIRU; QQKN +303C ; [.2316.0020.0004.303C][.2304.0020.0004.303C] # MASU MARK; QQKN +3345 ; [.2316.0020.001C.3345][.2309.0020.001C.3345][.2311.0020.001F.3345] # SQUARE MAHHA; QQKN +3346 ; [.2316.0020.001C.3346][.2320.0020.001C.3346][.22FF.0020.001F.3346] # SQUARE MARUKU; QQKN +3347 ; [.2316.0020.001C.3347][.2327.0020.001C.3347][.2303.0020.001F.3347][.231D.0020.001F.3347][.2327.0020.001F.3347] # SQUARE MANSYON; QQKN +307F ; [.2317.0020.000E.307F] # HIRAGANA LETTER MI +30DF ; [.2317.0020.0011.30DF] # KATAKANA LETTER MI +FF90 ; [.2317.0020.0012.FF90] # HALFWIDTH KATAKANA LETTER MI; QQK +32EF ; [.2317.0020.0013.32EF] # CIRCLED KATAKANA MI; QQK +3348 ; [.2317.0020.001C.3348][.22FF.0020.001C.3348][.2322.0020.001F.3348][.2327.0020.001F.3348] # SQUARE MIKURON; QQKN +3349 ; [.2317.0020.001C.3349][.231F.0020.001C.3349] # SQUARE MIRI; QQKN +334A ; [.2317.0020.001C.334A][.231F.0020.001C.334A][.2311.0020.001F.334A][.0000.0177.001F.334A][.0FA3.0020.001F.334A][.2320.0020.001F.334A] # SQUARE MIRIBAARU; QQKN +3080 ; [.2318.0020.000E.3080] # HIRAGANA LETTER MU +31FA ; [.2318.0020.000F.31FA] # KATAKANA LETTER SMALL MU +30E0 ; [.2318.0020.0011.30E0] # KATAKANA LETTER MU +FF91 ; [.2318.0020.0012.FF91] # HALFWIDTH KATAKANA LETTER MU; QQK +32F0 ; [.2318.0020.0013.32F0] # CIRCLED KATAKANA MU; QQK +3081 ; [.2319.0020.000E.3081] # HIRAGANA LETTER ME +30E1 ; [.2319.0020.0011.30E1] # KATAKANA LETTER ME +FF92 ; [.2319.0020.0012.FF92] # HALFWIDTH KATAKANA LETTER ME; QQK +32F1 ; [.2319.0020.0013.32F1] # CIRCLED KATAKANA ME; QQK +334D ; [.2319.0020.001C.334D][.0FA3.0020.001C.334D][.230B.0020.001F.334D][.2320.0020.001F.334D] # SQUARE MEETORU; QQKN +334B ; [.2319.0020.001C.334B][.22FD.0020.001C.334B][.0000.0177.001F.334B] # SQUARE MEGA; QQKN +334C ; [.2319.0020.001C.334C][.22FD.0020.001C.334C][.0000.0177.001F.334C][.230B.0020.001F.334C][.2327.0020.001F.334C] # SQUARE MEGATON; QQKN +3082 ; [.231A.0020.000E.3082] # HIRAGANA LETTER MO +30E2 ; [.231A.0020.0011.30E2] # KATAKANA LETTER MO +FF93 ; [.231A.0020.0012.FF93] # HALFWIDTH KATAKANA LETTER MO; QQK +32F2 ; [.231A.0020.0013.32F2] # CIRCLED KATAKANA MO; QQK +3083 ; [.231B.0020.000D.3083] # HIRAGANA LETTER SMALL YA +3084 ; [.231B.0020.000E.3084] # HIRAGANA LETTER YA +30E3 ; [.231B.0020.000F.30E3] # KATAKANA LETTER SMALL YA +FF6C ; [.231B.0020.0010.FF6C] # HALFWIDTH KATAKANA LETTER SMALL YA; QQK +30E4 ; [.231B.0020.0011.30E4] # KATAKANA LETTER YA +FF94 ; [.231B.0020.0012.FF94] # HALFWIDTH KATAKANA LETTER YA; QQK +32F3 ; [.231B.0020.0013.32F3] # CIRCLED KATAKANA YA; QQK +334E ; [.231B.0020.001C.334E][.0FA3.0020.001C.334E][.230B.0020.001F.334E][.0000.0177.001F.334E] # SQUARE YAADO; QQKN +334F ; [.231B.0020.001C.334F][.0FA3.0020.001C.334F][.2320.0020.001F.334F] # SQUARE YAARU; QQKN +3085 ; [.231C.0020.000D.3085] # HIRAGANA LETTER SMALL YU +3086 ; [.231C.0020.000E.3086] # HIRAGANA LETTER YU +30E5 ; [.231C.0020.000F.30E5] # KATAKANA LETTER SMALL YU +FF6D ; [.231C.0020.0010.FF6D] # HALFWIDTH KATAKANA LETTER SMALL YU; QQK +30E6 ; [.231C.0020.0011.30E6] # KATAKANA LETTER YU +FF95 ; [.231C.0020.0012.FF95] # HALFWIDTH KATAKANA LETTER YU; QQK +32F4 ; [.231C.0020.0013.32F4] # CIRCLED KATAKANA YU; QQK +3350 ; [.231C.0020.001C.3350][.22F8.0020.001C.3350][.2327.0020.001F.3350] # SQUARE YUAN; QQKN +3087 ; [.231D.0020.000D.3087] # HIRAGANA LETTER SMALL YO +3088 ; [.231D.0020.000E.3088] # HIRAGANA LETTER YO +30E7 ; [.231D.0020.000F.30E7] # KATAKANA LETTER SMALL YO +FF6E ; [.231D.0020.0010.FF6E] # HALFWIDTH KATAKANA LETTER SMALL YO; QQK +30E8 ; [.231D.0020.0011.30E8] # KATAKANA LETTER YO +FF96 ; [.231D.0020.0012.FF96] # HALFWIDTH KATAKANA LETTER YO; QQK +32F5 ; [.231D.0020.0013.32F5] # CIRCLED KATAKANA YO; QQK +309F ; [.231D.0020.0016.309F][.231F.0020.0016.309F] # HIRAGANA DIGRAPH YORI; QQKN +3089 ; [.231E.0020.000E.3089] # HIRAGANA LETTER RA +31FB ; [.231E.0020.000F.31FB] # KATAKANA LETTER SMALL RA +30E9 ; [.231E.0020.0011.30E9] # KATAKANA LETTER RA +FF97 ; [.231E.0020.0012.FF97] # HALFWIDTH KATAKANA LETTER RA; QQK +32F6 ; [.231E.0020.0013.32F6] # CIRCLED KATAKANA RA; QQK +308A ; [.231F.0020.000E.308A] # HIRAGANA LETTER RI +31FC ; [.231F.0020.000F.31FC] # KATAKANA LETTER SMALL RI +30EA ; [.231F.0020.0011.30EA] # KATAKANA LETTER RI +FF98 ; [.231F.0020.0012.FF98] # HALFWIDTH KATAKANA LETTER RI; QQK +32F7 ; [.231F.0020.0013.32F7] # CIRCLED KATAKANA RI; QQK +3351 ; [.231F.0020.001C.3351][.2309.0020.001C.3351][.230B.0020.001F.3351][.2320.0020.001F.3351] # SQUARE RITTORU; QQKN +3352 ; [.231F.0020.001C.3352][.231E.0020.001C.3352] # SQUARE RIRA; QQKN +308B ; [.2320.0020.000E.308B] # HIRAGANA LETTER RU +31FD ; [.2320.0020.000F.31FD] # KATAKANA LETTER SMALL RU +30EB ; [.2320.0020.0011.30EB] # KATAKANA LETTER RU +FF99 ; [.2320.0020.0012.FF99] # HALFWIDTH KATAKANA LETTER RU; QQK +32F8 ; [.2320.0020.0013.32F8] # CIRCLED KATAKANA RU; QQK +3354 ; [.2320.0020.001C.3354][.0FA3.0020.001C.3354][.2313.0020.001F.3354][.0000.0177.001F.3354][.2320.0020.001F.3354] # SQUARE RUUBURU; QQKN +3353 ; [.2320.0020.001C.3353][.2312.0020.001C.3353][.0000.0178.001F.3353][.0FA3.0020.001F.3353] # SQUARE RUPII; QQKN +308C ; [.2321.0020.000E.308C] # HIRAGANA LETTER RE +31FE ; [.2321.0020.000F.31FE] # KATAKANA LETTER SMALL RE +30EC ; [.2321.0020.0011.30EC] # KATAKANA LETTER RE +FF9A ; [.2321.0020.0012.FF9A] # HALFWIDTH KATAKANA LETTER RE; QQK +32F9 ; [.2321.0020.0013.32F9] # CIRCLED KATAKANA RE; QQK +3355 ; [.2321.0020.001C.3355][.2318.0020.001C.3355] # SQUARE REMU; QQKN +3356 ; [.2321.0020.001C.3356][.2327.0020.001C.3356][.230B.0020.001F.3356][.2300.0020.001F.3356][.0000.0177.001F.3356][.2327.0020.001F.3356] # SQUARE RENTOGEN; QQKN +308D ; [.2322.0020.000E.308D] # HIRAGANA LETTER RO +31FF ; [.2322.0020.000F.31FF] # KATAKANA LETTER SMALL RO +30ED ; [.2322.0020.0011.30ED] # KATAKANA LETTER RO +FF9B ; [.2322.0020.0012.FF9B] # HALFWIDTH KATAKANA LETTER RO; QQK +32FA ; [.2322.0020.0013.32FA] # CIRCLED KATAKANA RO; QQK +308E ; [.2323.0020.000D.308E] # HIRAGANA LETTER SMALL WA +308F ; [.2323.0020.000E.308F] # HIRAGANA LETTER WA +30EE ; [.2323.0020.000F.30EE] # KATAKANA LETTER SMALL WA +30EF ; [.2323.0020.0011.30EF] # KATAKANA LETTER WA +FF9C ; [.2323.0020.0012.FF9C] # HALFWIDTH KATAKANA LETTER WA; QQK +32FB ; [.2323.0020.0013.32FB] # CIRCLED KATAKANA WA; QQK +30F7 ; [.2323.0020.0011.30EF][.0000.0177.0002.3099] # KATAKANA LETTER VA; QQCM +3357 ; [.2323.0020.001C.3357][.2309.0020.001C.3357][.230B.0020.001F.3357] # SQUARE WATTO; QQKN +3090 ; [.2324.0020.000E.3090] # HIRAGANA LETTER WI +30F0 ; [.2324.0020.0011.30F0] # KATAKANA LETTER WI +32FC ; [.2324.0020.0013.32FC] # CIRCLED KATAKANA WI; QQK +30F8 ; [.2324.0020.0011.30F0][.0000.0177.0002.3099] # KATAKANA LETTER VI; QQCM +3091 ; [.2325.0020.000E.3091] # HIRAGANA LETTER WE +30F1 ; [.2325.0020.0011.30F1] # KATAKANA LETTER WE +32FD ; [.2325.0020.0013.32FD] # CIRCLED KATAKANA WE; QQK +30F9 ; [.2325.0020.0011.30F1][.0000.0177.0002.3099] # KATAKANA LETTER VE; QQCM +3092 ; [.2326.0020.000E.3092] # HIRAGANA LETTER WO +30F2 ; [.2326.0020.0011.30F2] # KATAKANA LETTER WO +FF66 ; [.2326.0020.0012.FF66] # HALFWIDTH KATAKANA LETTER WO; QQK +32FE ; [.2326.0020.0013.32FE] # CIRCLED KATAKANA WO; QQK +30FA ; [.2326.0020.0011.30F2][.0000.0177.0002.3099] # KATAKANA LETTER VO; QQCM +3093 ; [.2327.0020.000E.3093] # HIRAGANA LETTER N +30F3 ; [.2327.0020.0011.30F3] # KATAKANA LETTER N +FF9D ; [.2327.0020.0012.FF9D] # HALFWIDTH KATAKANA LETTER N; QQK +3105 ; [.2328.0020.0002.3105] # BOPOMOFO LETTER B +31A0 ; [.2328.0020.0004.31A0][.0000.019A.0004.31A0] # BOPOMOFO LETTER BU; QQKN +3106 ; [.2329.0020.0002.3106] # BOPOMOFO LETTER P +31B4 ; [.2329.0020.0019.31B4] # BOPOMOFO FINAL LETTER P; QQK +3107 ; [.232A.0020.0002.3107] # BOPOMOFO LETTER M +3108 ; [.232B.0020.0002.3108] # BOPOMOFO LETTER F +312A ; [.232C.0020.0002.312A] # BOPOMOFO LETTER V +3109 ; [.232D.0020.0002.3109] # BOPOMOFO LETTER D +310A ; [.232E.0020.0002.310A] # BOPOMOFO LETTER T +31B5 ; [.232E.0020.0019.31B5] # BOPOMOFO FINAL LETTER T; QQK +310B ; [.232F.0020.0002.310B] # BOPOMOFO LETTER N +310C ; [.2330.0020.0002.310C] # BOPOMOFO LETTER L +310D ; [.2331.0020.0002.310D] # BOPOMOFO LETTER G +31A3 ; [.2331.0020.0004.31A3][.0000.019A.0004.31A3] # BOPOMOFO LETTER GU; QQKN +310E ; [.2332.0020.0002.310E] # BOPOMOFO LETTER K +31B6 ; [.2332.0020.0019.31B6] # BOPOMOFO FINAL LETTER K; QQK +312B ; [.2333.0020.0002.312B] # BOPOMOFO LETTER NG +31AD ; [.2334.0020.0002.31AD] # BOPOMOFO LETTER NGG +310F ; [.2335.0020.0002.310F] # BOPOMOFO LETTER H +31B7 ; [.2335.0020.0019.31B7] # BOPOMOFO FINAL LETTER H; QQK +3110 ; [.2336.0020.0002.3110] # BOPOMOFO LETTER J +31A2 ; [.2336.0020.0004.31A2][.0000.019A.0004.31A2] # BOPOMOFO LETTER JI; QQKN +3111 ; [.2337.0020.0002.3111] # BOPOMOFO LETTER Q +3112 ; [.2338.0020.0002.3112] # BOPOMOFO LETTER X +312C ; [.2339.0020.0002.312C] # BOPOMOFO LETTER GN +3113 ; [.233A.0020.0002.3113] # BOPOMOFO LETTER ZH +3114 ; [.233B.0020.0002.3114] # BOPOMOFO LETTER CH +3115 ; [.233C.0020.0002.3115] # BOPOMOFO LETTER SH +3116 ; [.233D.0020.0002.3116] # BOPOMOFO LETTER R +3117 ; [.233E.0020.0002.3117] # BOPOMOFO LETTER Z +31A1 ; [.233E.0020.0004.31A1][.0000.019A.0004.31A1] # BOPOMOFO LETTER ZI; QQKN +3118 ; [.233F.0020.0002.3118] # BOPOMOFO LETTER C +3119 ; [.2340.0020.0002.3119] # BOPOMOFO LETTER S +311A ; [.2341.0020.0002.311A] # BOPOMOFO LETTER A +31A9 ; [.2341.0020.0004.31A9][.0000.019A.0004.31A9] # BOPOMOFO LETTER ANN; QQKN +311B ; [.2342.0020.0002.311B] # BOPOMOFO LETTER O +31A7 ; [.2342.0020.0004.31A7][.0000.019A.0004.31A7] # BOPOMOFO LETTER ONN; QQKN +31A6 ; [.2343.0020.0002.31A6] # BOPOMOFO LETTER OO +311C ; [.2344.0020.0002.311C] # BOPOMOFO LETTER E +311D ; [.2345.0020.0002.311D] # BOPOMOFO LETTER EH +31A4 ; [.2346.0020.0002.31A4] # BOPOMOFO LETTER EE +31A5 ; [.2346.0020.0004.31A5][.0000.019A.0004.31A5] # BOPOMOFO LETTER ENN; QQKN +311E ; [.2347.0020.0002.311E] # BOPOMOFO LETTER AI +31AE ; [.2347.0020.0004.31AE][.0000.019A.0004.31AE] # BOPOMOFO LETTER AINN; QQKN +311F ; [.2348.0020.0002.311F] # BOPOMOFO LETTER EI +3120 ; [.2349.0020.0002.3120] # BOPOMOFO LETTER AU +31AF ; [.2349.0020.0004.31AF][.0000.019A.0004.31AF] # BOPOMOFO LETTER AUNN; QQKN +3121 ; [.234A.0020.0002.3121] # BOPOMOFO LETTER OU +3122 ; [.234B.0020.0002.3122] # BOPOMOFO LETTER AN +3123 ; [.234C.0020.0002.3123] # BOPOMOFO LETTER EN +3124 ; [.234D.0020.0002.3124] # BOPOMOFO LETTER ANG +31B2 ; [.234E.0020.0002.31B2] # BOPOMOFO LETTER ONG +3125 ; [.234F.0020.0002.3125] # BOPOMOFO LETTER ENG +31B0 ; [.2350.0020.0002.31B0] # BOPOMOFO LETTER AM +31B1 ; [.2351.0020.0002.31B1] # BOPOMOFO LETTER OM +31AC ; [.2352.0020.0002.31AC] # BOPOMOFO LETTER IM +3126 ; [.2353.0020.0002.3126] # BOPOMOFO LETTER ER +3127 ; [.2354.0020.0002.3127] # BOPOMOFO LETTER I +31AA ; [.2354.0020.0004.31AA][.0000.019A.0004.31AA] # BOPOMOFO LETTER INN; QQKN +31B3 ; [.2354.0020.0016.31B3][.0000.019A.0016.31B3] # BOPOMOFO LETTER INNN; QQKN +3128 ; [.2355.0020.0002.3128] # BOPOMOFO LETTER U +31AB ; [.2355.0020.0004.31AB][.0000.019A.0004.31AB] # BOPOMOFO LETTER UNN; QQKN +31A8 ; [.2355.0020.0004.31A8][.0000.019C.0004.31A8] # BOPOMOFO LETTER IR; QQKN +3129 ; [.2356.0020.0002.3129] # BOPOMOFO LETTER IU +A000 ; [.2357.0020.0002.A000] # YI SYLLABLE IT +A001 ; [.2358.0020.0002.A001] # YI SYLLABLE IX +A002 ; [.2359.0020.0002.A002] # YI SYLLABLE I +A003 ; [.235A.0020.0002.A003] # YI SYLLABLE IP +A004 ; [.235B.0020.0002.A004] # YI SYLLABLE IET +A005 ; [.235C.0020.0002.A005] # YI SYLLABLE IEX +A006 ; [.235D.0020.0002.A006] # YI SYLLABLE IE +A007 ; [.235E.0020.0002.A007] # YI SYLLABLE IEP +A008 ; [.235F.0020.0002.A008] # YI SYLLABLE AT +A009 ; [.2360.0020.0002.A009] # YI SYLLABLE AX +A00A ; [.2361.0020.0002.A00A] # YI SYLLABLE A +A00B ; [.2362.0020.0002.A00B] # YI SYLLABLE AP +A00C ; [.2363.0020.0002.A00C] # YI SYLLABLE UOX +A00D ; [.2364.0020.0002.A00D] # YI SYLLABLE UO +A00E ; [.2365.0020.0002.A00E] # YI SYLLABLE UOP +A00F ; [.2366.0020.0002.A00F] # YI SYLLABLE OT +A010 ; [.2367.0020.0002.A010] # YI SYLLABLE OX +A011 ; [.2368.0020.0002.A011] # YI SYLLABLE O +A012 ; [.2369.0020.0002.A012] # YI SYLLABLE OP +A013 ; [.236A.0020.0002.A013] # YI SYLLABLE EX +A014 ; [.236B.0020.0002.A014] # YI SYLLABLE E +A015 ; [.236C.0020.0002.A015] # YI SYLLABLE WU +A016 ; [.236D.0020.0002.A016] # YI SYLLABLE BIT +A017 ; [.236E.0020.0002.A017] # YI SYLLABLE BIX +A018 ; [.236F.0020.0002.A018] # YI SYLLABLE BI +A019 ; [.2370.0020.0002.A019] # YI SYLLABLE BIP +A01A ; [.2371.0020.0002.A01A] # YI SYLLABLE BIET +A01B ; [.2372.0020.0002.A01B] # YI SYLLABLE BIEX +A01C ; [.2373.0020.0002.A01C] # YI SYLLABLE BIE +A01D ; [.2374.0020.0002.A01D] # YI SYLLABLE BIEP +A01E ; [.2375.0020.0002.A01E] # YI SYLLABLE BAT +A01F ; [.2376.0020.0002.A01F] # YI SYLLABLE BAX +A020 ; [.2377.0020.0002.A020] # YI SYLLABLE BA +A021 ; [.2378.0020.0002.A021] # YI SYLLABLE BAP +A022 ; [.2379.0020.0002.A022] # YI SYLLABLE BUOX +A023 ; [.237A.0020.0002.A023] # YI SYLLABLE BUO +A024 ; [.237B.0020.0002.A024] # YI SYLLABLE BUOP +A025 ; [.237C.0020.0002.A025] # YI SYLLABLE BOT +A026 ; [.237D.0020.0002.A026] # YI SYLLABLE BOX +A027 ; [.237E.0020.0002.A027] # YI SYLLABLE BO +A028 ; [.237F.0020.0002.A028] # YI SYLLABLE BOP +A029 ; [.2380.0020.0002.A029] # YI SYLLABLE BEX +A02A ; [.2381.0020.0002.A02A] # YI SYLLABLE BE +A02B ; [.2382.0020.0002.A02B] # YI SYLLABLE BEP +A02C ; [.2383.0020.0002.A02C] # YI SYLLABLE BUT +A02D ; [.2384.0020.0002.A02D] # YI SYLLABLE BUX +A02E ; [.2385.0020.0002.A02E] # YI SYLLABLE BU +A02F ; [.2386.0020.0002.A02F] # YI SYLLABLE BUP +A030 ; [.2387.0020.0002.A030] # YI SYLLABLE BURX +A031 ; [.2388.0020.0002.A031] # YI SYLLABLE BUR +A032 ; [.2389.0020.0002.A032] # YI SYLLABLE BYT +A033 ; [.238A.0020.0002.A033] # YI SYLLABLE BYX +A034 ; [.238B.0020.0002.A034] # YI SYLLABLE BY +A035 ; [.238C.0020.0002.A035] # YI SYLLABLE BYP +A036 ; [.238D.0020.0002.A036] # YI SYLLABLE BYRX +A037 ; [.238E.0020.0002.A037] # YI SYLLABLE BYR +A038 ; [.238F.0020.0002.A038] # YI SYLLABLE PIT +A039 ; [.2390.0020.0002.A039] # YI SYLLABLE PIX +A03A ; [.2391.0020.0002.A03A] # YI SYLLABLE PI +A03B ; [.2392.0020.0002.A03B] # YI SYLLABLE PIP +A03C ; [.2393.0020.0002.A03C] # YI SYLLABLE PIEX +A03D ; [.2394.0020.0002.A03D] # YI SYLLABLE PIE +A03E ; [.2395.0020.0002.A03E] # YI SYLLABLE PIEP +A03F ; [.2396.0020.0002.A03F] # YI SYLLABLE PAT +A040 ; [.2397.0020.0002.A040] # YI SYLLABLE PAX +A041 ; [.2398.0020.0002.A041] # YI SYLLABLE PA +A042 ; [.2399.0020.0002.A042] # YI SYLLABLE PAP +A043 ; [.239A.0020.0002.A043] # YI SYLLABLE PUOX +A044 ; [.239B.0020.0002.A044] # YI SYLLABLE PUO +A045 ; [.239C.0020.0002.A045] # YI SYLLABLE PUOP +A046 ; [.239D.0020.0002.A046] # YI SYLLABLE POT +A047 ; [.239E.0020.0002.A047] # YI SYLLABLE POX +A048 ; [.239F.0020.0002.A048] # YI SYLLABLE PO +A049 ; [.23A0.0020.0002.A049] # YI SYLLABLE POP +A04A ; [.23A1.0020.0002.A04A] # YI SYLLABLE PUT +A04B ; [.23A2.0020.0002.A04B] # YI SYLLABLE PUX +A04C ; [.23A3.0020.0002.A04C] # YI SYLLABLE PU +A04D ; [.23A4.0020.0002.A04D] # YI SYLLABLE PUP +A04E ; [.23A5.0020.0002.A04E] # YI SYLLABLE PURX +A04F ; [.23A6.0020.0002.A04F] # YI SYLLABLE PUR +A050 ; [.23A7.0020.0002.A050] # YI SYLLABLE PYT +A051 ; [.23A8.0020.0002.A051] # YI SYLLABLE PYX +A052 ; [.23A9.0020.0002.A052] # YI SYLLABLE PY +A053 ; [.23AA.0020.0002.A053] # YI SYLLABLE PYP +A054 ; [.23AB.0020.0002.A054] # YI SYLLABLE PYRX +A055 ; [.23AC.0020.0002.A055] # YI SYLLABLE PYR +A056 ; [.23AD.0020.0002.A056] # YI SYLLABLE BBIT +A057 ; [.23AE.0020.0002.A057] # YI SYLLABLE BBIX +A058 ; [.23AF.0020.0002.A058] # YI SYLLABLE BBI +A059 ; [.23B0.0020.0002.A059] # YI SYLLABLE BBIP +A05A ; [.23B1.0020.0002.A05A] # YI SYLLABLE BBIET +A05B ; [.23B2.0020.0002.A05B] # YI SYLLABLE BBIEX +A05C ; [.23B3.0020.0002.A05C] # YI SYLLABLE BBIE +A05D ; [.23B4.0020.0002.A05D] # YI SYLLABLE BBIEP +A05E ; [.23B5.0020.0002.A05E] # YI SYLLABLE BBAT +A05F ; [.23B6.0020.0002.A05F] # YI SYLLABLE BBAX +A060 ; [.23B7.0020.0002.A060] # YI SYLLABLE BBA +A061 ; [.23B8.0020.0002.A061] # YI SYLLABLE BBAP +A062 ; [.23B9.0020.0002.A062] # YI SYLLABLE BBUOX +A063 ; [.23BA.0020.0002.A063] # YI SYLLABLE BBUO +A064 ; [.23BB.0020.0002.A064] # YI SYLLABLE BBUOP +A065 ; [.23BC.0020.0002.A065] # YI SYLLABLE BBOT +A066 ; [.23BD.0020.0002.A066] # YI SYLLABLE BBOX +A067 ; [.23BE.0020.0002.A067] # YI SYLLABLE BBO +A068 ; [.23BF.0020.0002.A068] # YI SYLLABLE BBOP +A069 ; [.23C0.0020.0002.A069] # YI SYLLABLE BBEX +A06A ; [.23C1.0020.0002.A06A] # YI SYLLABLE BBE +A06B ; [.23C2.0020.0002.A06B] # YI SYLLABLE BBEP +A06C ; [.23C3.0020.0002.A06C] # YI SYLLABLE BBUT +A06D ; [.23C4.0020.0002.A06D] # YI SYLLABLE BBUX +A06E ; [.23C5.0020.0002.A06E] # YI SYLLABLE BBU +A06F ; [.23C6.0020.0002.A06F] # YI SYLLABLE BBUP +A070 ; [.23C7.0020.0002.A070] # YI SYLLABLE BBURX +A071 ; [.23C8.0020.0002.A071] # YI SYLLABLE BBUR +A072 ; [.23C9.0020.0002.A072] # YI SYLLABLE BBYT +A073 ; [.23CA.0020.0002.A073] # YI SYLLABLE BBYX +A074 ; [.23CB.0020.0002.A074] # YI SYLLABLE BBY +A075 ; [.23CC.0020.0002.A075] # YI SYLLABLE BBYP +A076 ; [.23CD.0020.0002.A076] # YI SYLLABLE NBIT +A077 ; [.23CE.0020.0002.A077] # YI SYLLABLE NBIX +A078 ; [.23CF.0020.0002.A078] # YI SYLLABLE NBI +A079 ; [.23D0.0020.0002.A079] # YI SYLLABLE NBIP +A07A ; [.23D1.0020.0002.A07A] # YI SYLLABLE NBIEX +A07B ; [.23D2.0020.0002.A07B] # YI SYLLABLE NBIE +A07C ; [.23D3.0020.0002.A07C] # YI SYLLABLE NBIEP +A07D ; [.23D4.0020.0002.A07D] # YI SYLLABLE NBAT +A07E ; [.23D5.0020.0002.A07E] # YI SYLLABLE NBAX +A07F ; [.23D6.0020.0002.A07F] # YI SYLLABLE NBA +A080 ; [.23D7.0020.0002.A080] # YI SYLLABLE NBAP +A081 ; [.23D8.0020.0002.A081] # YI SYLLABLE NBOT +A082 ; [.23D9.0020.0002.A082] # YI SYLLABLE NBOX +A083 ; [.23DA.0020.0002.A083] # YI SYLLABLE NBO +A084 ; [.23DB.0020.0002.A084] # YI SYLLABLE NBOP +A085 ; [.23DC.0020.0002.A085] # YI SYLLABLE NBUT +A086 ; [.23DD.0020.0002.A086] # YI SYLLABLE NBUX +A087 ; [.23DE.0020.0002.A087] # YI SYLLABLE NBU +A088 ; [.23DF.0020.0002.A088] # YI SYLLABLE NBUP +A089 ; [.23E0.0020.0002.A089] # YI SYLLABLE NBURX +A08A ; [.23E1.0020.0002.A08A] # YI SYLLABLE NBUR +A08B ; [.23E2.0020.0002.A08B] # YI SYLLABLE NBYT +A08C ; [.23E3.0020.0002.A08C] # YI SYLLABLE NBYX +A08D ; [.23E4.0020.0002.A08D] # YI SYLLABLE NBY +A08E ; [.23E5.0020.0002.A08E] # YI SYLLABLE NBYP +A08F ; [.23E6.0020.0002.A08F] # YI SYLLABLE NBYRX +A090 ; [.23E7.0020.0002.A090] # YI SYLLABLE NBYR +A091 ; [.23E8.0020.0002.A091] # YI SYLLABLE HMIT +A092 ; [.23E9.0020.0002.A092] # YI SYLLABLE HMIX +A093 ; [.23EA.0020.0002.A093] # YI SYLLABLE HMI +A094 ; [.23EB.0020.0002.A094] # YI SYLLABLE HMIP +A095 ; [.23EC.0020.0002.A095] # YI SYLLABLE HMIEX +A096 ; [.23ED.0020.0002.A096] # YI SYLLABLE HMIE +A097 ; [.23EE.0020.0002.A097] # YI SYLLABLE HMIEP +A098 ; [.23EF.0020.0002.A098] # YI SYLLABLE HMAT +A099 ; [.23F0.0020.0002.A099] # YI SYLLABLE HMAX +A09A ; [.23F1.0020.0002.A09A] # YI SYLLABLE HMA +A09B ; [.23F2.0020.0002.A09B] # YI SYLLABLE HMAP +A09C ; [.23F3.0020.0002.A09C] # YI SYLLABLE HMUOX +A09D ; [.23F4.0020.0002.A09D] # YI SYLLABLE HMUO +A09E ; [.23F5.0020.0002.A09E] # YI SYLLABLE HMUOP +A09F ; [.23F6.0020.0002.A09F] # YI SYLLABLE HMOT +A0A0 ; [.23F7.0020.0002.A0A0] # YI SYLLABLE HMOX +A0A1 ; [.23F8.0020.0002.A0A1] # YI SYLLABLE HMO +A0A2 ; [.23F9.0020.0002.A0A2] # YI SYLLABLE HMOP +A0A3 ; [.23FA.0020.0002.A0A3] # YI SYLLABLE HMUT +A0A4 ; [.23FB.0020.0002.A0A4] # YI SYLLABLE HMUX +A0A5 ; [.23FC.0020.0002.A0A5] # YI SYLLABLE HMU +A0A6 ; [.23FD.0020.0002.A0A6] # YI SYLLABLE HMUP +A0A7 ; [.23FE.0020.0002.A0A7] # YI SYLLABLE HMURX +A0A8 ; [.23FF.0020.0002.A0A8] # YI SYLLABLE HMUR +A0A9 ; [.2400.0020.0002.A0A9] # YI SYLLABLE HMYX +A0AA ; [.2401.0020.0002.A0AA] # YI SYLLABLE HMY +A0AB ; [.2402.0020.0002.A0AB] # YI SYLLABLE HMYP +A0AC ; [.2403.0020.0002.A0AC] # YI SYLLABLE HMYRX +A0AD ; [.2404.0020.0002.A0AD] # YI SYLLABLE HMYR +A0AE ; [.2405.0020.0002.A0AE] # YI SYLLABLE MIT +A0AF ; [.2406.0020.0002.A0AF] # YI SYLLABLE MIX +A0B0 ; [.2407.0020.0002.A0B0] # YI SYLLABLE MI +A0B1 ; [.2408.0020.0002.A0B1] # YI SYLLABLE MIP +A0B2 ; [.2409.0020.0002.A0B2] # YI SYLLABLE MIEX +A0B3 ; [.240A.0020.0002.A0B3] # YI SYLLABLE MIE +A0B4 ; [.240B.0020.0002.A0B4] # YI SYLLABLE MIEP +A0B5 ; [.240C.0020.0002.A0B5] # YI SYLLABLE MAT +A0B6 ; [.240D.0020.0002.A0B6] # YI SYLLABLE MAX +A0B7 ; [.240E.0020.0002.A0B7] # YI SYLLABLE MA +A0B8 ; [.240F.0020.0002.A0B8] # YI SYLLABLE MAP +A0B9 ; [.2410.0020.0002.A0B9] # YI SYLLABLE MUOT +A0BA ; [.2411.0020.0002.A0BA] # YI SYLLABLE MUOX +A0BB ; [.2412.0020.0002.A0BB] # YI SYLLABLE MUO +A0BC ; [.2413.0020.0002.A0BC] # YI SYLLABLE MUOP +A0BD ; [.2414.0020.0002.A0BD] # YI SYLLABLE MOT +A0BE ; [.2415.0020.0002.A0BE] # YI SYLLABLE MOX +A0BF ; [.2416.0020.0002.A0BF] # YI SYLLABLE MO +A0C0 ; [.2417.0020.0002.A0C0] # YI SYLLABLE MOP +A0C1 ; [.2418.0020.0002.A0C1] # YI SYLLABLE MEX +A0C2 ; [.2419.0020.0002.A0C2] # YI SYLLABLE ME +A0C3 ; [.241A.0020.0002.A0C3] # YI SYLLABLE MUT +A0C4 ; [.241B.0020.0002.A0C4] # YI SYLLABLE MUX +A0C5 ; [.241C.0020.0002.A0C5] # YI SYLLABLE MU +A0C6 ; [.241D.0020.0002.A0C6] # YI SYLLABLE MUP +A0C7 ; [.241E.0020.0002.A0C7] # YI SYLLABLE MURX +A0C8 ; [.241F.0020.0002.A0C8] # YI SYLLABLE MUR +A0C9 ; [.2420.0020.0002.A0C9] # YI SYLLABLE MYT +A0CA ; [.2421.0020.0002.A0CA] # YI SYLLABLE MYX +A0CB ; [.2422.0020.0002.A0CB] # YI SYLLABLE MY +A0CC ; [.2423.0020.0002.A0CC] # YI SYLLABLE MYP +A0CD ; [.2424.0020.0002.A0CD] # YI SYLLABLE FIT +A0CE ; [.2425.0020.0002.A0CE] # YI SYLLABLE FIX +A0CF ; [.2426.0020.0002.A0CF] # YI SYLLABLE FI +A0D0 ; [.2427.0020.0002.A0D0] # YI SYLLABLE FIP +A0D1 ; [.2428.0020.0002.A0D1] # YI SYLLABLE FAT +A0D2 ; [.2429.0020.0002.A0D2] # YI SYLLABLE FAX +A0D3 ; [.242A.0020.0002.A0D3] # YI SYLLABLE FA +A0D4 ; [.242B.0020.0002.A0D4] # YI SYLLABLE FAP +A0D5 ; [.242C.0020.0002.A0D5] # YI SYLLABLE FOX +A0D6 ; [.242D.0020.0002.A0D6] # YI SYLLABLE FO +A0D7 ; [.242E.0020.0002.A0D7] # YI SYLLABLE FOP +A0D8 ; [.242F.0020.0002.A0D8] # YI SYLLABLE FUT +A0D9 ; [.2430.0020.0002.A0D9] # YI SYLLABLE FUX +A0DA ; [.2431.0020.0002.A0DA] # YI SYLLABLE FU +A0DB ; [.2432.0020.0002.A0DB] # YI SYLLABLE FUP +A0DC ; [.2433.0020.0002.A0DC] # YI SYLLABLE FURX +A0DD ; [.2434.0020.0002.A0DD] # YI SYLLABLE FUR +A0DE ; [.2435.0020.0002.A0DE] # YI SYLLABLE FYT +A0DF ; [.2436.0020.0002.A0DF] # YI SYLLABLE FYX +A0E0 ; [.2437.0020.0002.A0E0] # YI SYLLABLE FY +A0E1 ; [.2438.0020.0002.A0E1] # YI SYLLABLE FYP +A0E2 ; [.2439.0020.0002.A0E2] # YI SYLLABLE VIT +A0E3 ; [.243A.0020.0002.A0E3] # YI SYLLABLE VIX +A0E4 ; [.243B.0020.0002.A0E4] # YI SYLLABLE VI +A0E5 ; [.243C.0020.0002.A0E5] # YI SYLLABLE VIP +A0E6 ; [.243D.0020.0002.A0E6] # YI SYLLABLE VIET +A0E7 ; [.243E.0020.0002.A0E7] # YI SYLLABLE VIEX +A0E8 ; [.243F.0020.0002.A0E8] # YI SYLLABLE VIE +A0E9 ; [.2440.0020.0002.A0E9] # YI SYLLABLE VIEP +A0EA ; [.2441.0020.0002.A0EA] # YI SYLLABLE VAT +A0EB ; [.2442.0020.0002.A0EB] # YI SYLLABLE VAX +A0EC ; [.2443.0020.0002.A0EC] # YI SYLLABLE VA +A0ED ; [.2444.0020.0002.A0ED] # YI SYLLABLE VAP +A0EE ; [.2445.0020.0002.A0EE] # YI SYLLABLE VOT +A0EF ; [.2446.0020.0002.A0EF] # YI SYLLABLE VOX +A0F0 ; [.2447.0020.0002.A0F0] # YI SYLLABLE VO +A0F1 ; [.2448.0020.0002.A0F1] # YI SYLLABLE VOP +A0F2 ; [.2449.0020.0002.A0F2] # YI SYLLABLE VEX +A0F3 ; [.244A.0020.0002.A0F3] # YI SYLLABLE VEP +A0F4 ; [.244B.0020.0002.A0F4] # YI SYLLABLE VUT +A0F5 ; [.244C.0020.0002.A0F5] # YI SYLLABLE VUX +A0F6 ; [.244D.0020.0002.A0F6] # YI SYLLABLE VU +A0F7 ; [.244E.0020.0002.A0F7] # YI SYLLABLE VUP +A0F8 ; [.244F.0020.0002.A0F8] # YI SYLLABLE VURX +A0F9 ; [.2450.0020.0002.A0F9] # YI SYLLABLE VUR +A0FA ; [.2451.0020.0002.A0FA] # YI SYLLABLE VYT +A0FB ; [.2452.0020.0002.A0FB] # YI SYLLABLE VYX +A0FC ; [.2453.0020.0002.A0FC] # YI SYLLABLE VY +A0FD ; [.2454.0020.0002.A0FD] # YI SYLLABLE VYP +A0FE ; [.2455.0020.0002.A0FE] # YI SYLLABLE VYRX +A0FF ; [.2456.0020.0002.A0FF] # YI SYLLABLE VYR +A100 ; [.2457.0020.0002.A100] # YI SYLLABLE DIT +A101 ; [.2458.0020.0002.A101] # YI SYLLABLE DIX +A102 ; [.2459.0020.0002.A102] # YI SYLLABLE DI +A103 ; [.245A.0020.0002.A103] # YI SYLLABLE DIP +A104 ; [.245B.0020.0002.A104] # YI SYLLABLE DIEX +A105 ; [.245C.0020.0002.A105] # YI SYLLABLE DIE +A106 ; [.245D.0020.0002.A106] # YI SYLLABLE DIEP +A107 ; [.245E.0020.0002.A107] # YI SYLLABLE DAT +A108 ; [.245F.0020.0002.A108] # YI SYLLABLE DAX +A109 ; [.2460.0020.0002.A109] # YI SYLLABLE DA +A10A ; [.2461.0020.0002.A10A] # YI SYLLABLE DAP +A10B ; [.2462.0020.0002.A10B] # YI SYLLABLE DUOX +A10C ; [.2463.0020.0002.A10C] # YI SYLLABLE DUO +A10D ; [.2464.0020.0002.A10D] # YI SYLLABLE DOT +A10E ; [.2465.0020.0002.A10E] # YI SYLLABLE DOX +A10F ; [.2466.0020.0002.A10F] # YI SYLLABLE DO +A110 ; [.2467.0020.0002.A110] # YI SYLLABLE DOP +A111 ; [.2468.0020.0002.A111] # YI SYLLABLE DEX +A112 ; [.2469.0020.0002.A112] # YI SYLLABLE DE +A113 ; [.246A.0020.0002.A113] # YI SYLLABLE DEP +A114 ; [.246B.0020.0002.A114] # YI SYLLABLE DUT +A115 ; [.246C.0020.0002.A115] # YI SYLLABLE DUX +A116 ; [.246D.0020.0002.A116] # YI SYLLABLE DU +A117 ; [.246E.0020.0002.A117] # YI SYLLABLE DUP +A118 ; [.246F.0020.0002.A118] # YI SYLLABLE DURX +A119 ; [.2470.0020.0002.A119] # YI SYLLABLE DUR +A11A ; [.2471.0020.0002.A11A] # YI SYLLABLE TIT +A11B ; [.2472.0020.0002.A11B] # YI SYLLABLE TIX +A11C ; [.2473.0020.0002.A11C] # YI SYLLABLE TI +A11D ; [.2474.0020.0002.A11D] # YI SYLLABLE TIP +A11E ; [.2475.0020.0002.A11E] # YI SYLLABLE TIEX +A11F ; [.2476.0020.0002.A11F] # YI SYLLABLE TIE +A120 ; [.2477.0020.0002.A120] # YI SYLLABLE TIEP +A121 ; [.2478.0020.0002.A121] # YI SYLLABLE TAT +A122 ; [.2479.0020.0002.A122] # YI SYLLABLE TAX +A123 ; [.247A.0020.0002.A123] # YI SYLLABLE TA +A124 ; [.247B.0020.0002.A124] # YI SYLLABLE TAP +A125 ; [.247C.0020.0002.A125] # YI SYLLABLE TUOT +A126 ; [.247D.0020.0002.A126] # YI SYLLABLE TUOX +A127 ; [.247E.0020.0002.A127] # YI SYLLABLE TUO +A128 ; [.247F.0020.0002.A128] # YI SYLLABLE TUOP +A129 ; [.2480.0020.0002.A129] # YI SYLLABLE TOT +A12A ; [.2481.0020.0002.A12A] # YI SYLLABLE TOX +A12B ; [.2482.0020.0002.A12B] # YI SYLLABLE TO +A12C ; [.2483.0020.0002.A12C] # YI SYLLABLE TOP +A12D ; [.2484.0020.0002.A12D] # YI SYLLABLE TEX +A12E ; [.2485.0020.0002.A12E] # YI SYLLABLE TE +A12F ; [.2486.0020.0002.A12F] # YI SYLLABLE TEP +A130 ; [.2487.0020.0002.A130] # YI SYLLABLE TUT +A131 ; [.2488.0020.0002.A131] # YI SYLLABLE TUX +A132 ; [.2489.0020.0002.A132] # YI SYLLABLE TU +A133 ; [.248A.0020.0002.A133] # YI SYLLABLE TUP +A134 ; [.248B.0020.0002.A134] # YI SYLLABLE TURX +A135 ; [.248C.0020.0002.A135] # YI SYLLABLE TUR +A136 ; [.248D.0020.0002.A136] # YI SYLLABLE DDIT +A137 ; [.248E.0020.0002.A137] # YI SYLLABLE DDIX +A138 ; [.248F.0020.0002.A138] # YI SYLLABLE DDI +A139 ; [.2490.0020.0002.A139] # YI SYLLABLE DDIP +A13A ; [.2491.0020.0002.A13A] # YI SYLLABLE DDIEX +A13B ; [.2492.0020.0002.A13B] # YI SYLLABLE DDIE +A13C ; [.2493.0020.0002.A13C] # YI SYLLABLE DDIEP +A13D ; [.2494.0020.0002.A13D] # YI SYLLABLE DDAT +A13E ; [.2495.0020.0002.A13E] # YI SYLLABLE DDAX +A13F ; [.2496.0020.0002.A13F] # YI SYLLABLE DDA +A140 ; [.2497.0020.0002.A140] # YI SYLLABLE DDAP +A141 ; [.2498.0020.0002.A141] # YI SYLLABLE DDUOX +A142 ; [.2499.0020.0002.A142] # YI SYLLABLE DDUO +A143 ; [.249A.0020.0002.A143] # YI SYLLABLE DDUOP +A144 ; [.249B.0020.0002.A144] # YI SYLLABLE DDOT +A145 ; [.249C.0020.0002.A145] # YI SYLLABLE DDOX +A146 ; [.249D.0020.0002.A146] # YI SYLLABLE DDO +A147 ; [.249E.0020.0002.A147] # YI SYLLABLE DDOP +A148 ; [.249F.0020.0002.A148] # YI SYLLABLE DDEX +A149 ; [.24A0.0020.0002.A149] # YI SYLLABLE DDE +A14A ; [.24A1.0020.0002.A14A] # YI SYLLABLE DDEP +A14B ; [.24A2.0020.0002.A14B] # YI SYLLABLE DDUT +A14C ; [.24A3.0020.0002.A14C] # YI SYLLABLE DDUX +A14D ; [.24A4.0020.0002.A14D] # YI SYLLABLE DDU +A14E ; [.24A5.0020.0002.A14E] # YI SYLLABLE DDUP +A14F ; [.24A6.0020.0002.A14F] # YI SYLLABLE DDURX +A150 ; [.24A7.0020.0002.A150] # YI SYLLABLE DDUR +A151 ; [.24A8.0020.0002.A151] # YI SYLLABLE NDIT +A152 ; [.24A9.0020.0002.A152] # YI SYLLABLE NDIX +A153 ; [.24AA.0020.0002.A153] # YI SYLLABLE NDI +A154 ; [.24AB.0020.0002.A154] # YI SYLLABLE NDIP +A155 ; [.24AC.0020.0002.A155] # YI SYLLABLE NDIEX +A156 ; [.24AD.0020.0002.A156] # YI SYLLABLE NDIE +A157 ; [.24AE.0020.0002.A157] # YI SYLLABLE NDAT +A158 ; [.24AF.0020.0002.A158] # YI SYLLABLE NDAX +A159 ; [.24B0.0020.0002.A159] # YI SYLLABLE NDA +A15A ; [.24B1.0020.0002.A15A] # YI SYLLABLE NDAP +A15B ; [.24B2.0020.0002.A15B] # YI SYLLABLE NDOT +A15C ; [.24B3.0020.0002.A15C] # YI SYLLABLE NDOX +A15D ; [.24B4.0020.0002.A15D] # YI SYLLABLE NDO +A15E ; [.24B5.0020.0002.A15E] # YI SYLLABLE NDOP +A15F ; [.24B6.0020.0002.A15F] # YI SYLLABLE NDEX +A160 ; [.24B7.0020.0002.A160] # YI SYLLABLE NDE +A161 ; [.24B8.0020.0002.A161] # YI SYLLABLE NDEP +A162 ; [.24B9.0020.0002.A162] # YI SYLLABLE NDUT +A163 ; [.24BA.0020.0002.A163] # YI SYLLABLE NDUX +A164 ; [.24BB.0020.0002.A164] # YI SYLLABLE NDU +A165 ; [.24BC.0020.0002.A165] # YI SYLLABLE NDUP +A166 ; [.24BD.0020.0002.A166] # YI SYLLABLE NDURX +A167 ; [.24BE.0020.0002.A167] # YI SYLLABLE NDUR +A168 ; [.24BF.0020.0002.A168] # YI SYLLABLE HNIT +A169 ; [.24C0.0020.0002.A169] # YI SYLLABLE HNIX +A16A ; [.24C1.0020.0002.A16A] # YI SYLLABLE HNI +A16B ; [.24C2.0020.0002.A16B] # YI SYLLABLE HNIP +A16C ; [.24C3.0020.0002.A16C] # YI SYLLABLE HNIET +A16D ; [.24C4.0020.0002.A16D] # YI SYLLABLE HNIEX +A16E ; [.24C5.0020.0002.A16E] # YI SYLLABLE HNIE +A16F ; [.24C6.0020.0002.A16F] # YI SYLLABLE HNIEP +A170 ; [.24C7.0020.0002.A170] # YI SYLLABLE HNAT +A171 ; [.24C8.0020.0002.A171] # YI SYLLABLE HNAX +A172 ; [.24C9.0020.0002.A172] # YI SYLLABLE HNA +A173 ; [.24CA.0020.0002.A173] # YI SYLLABLE HNAP +A174 ; [.24CB.0020.0002.A174] # YI SYLLABLE HNUOX +A175 ; [.24CC.0020.0002.A175] # YI SYLLABLE HNUO +A176 ; [.24CD.0020.0002.A176] # YI SYLLABLE HNOT +A177 ; [.24CE.0020.0002.A177] # YI SYLLABLE HNOX +A178 ; [.24CF.0020.0002.A178] # YI SYLLABLE HNOP +A179 ; [.24D0.0020.0002.A179] # YI SYLLABLE HNEX +A17A ; [.24D1.0020.0002.A17A] # YI SYLLABLE HNE +A17B ; [.24D2.0020.0002.A17B] # YI SYLLABLE HNEP +A17C ; [.24D3.0020.0002.A17C] # YI SYLLABLE HNUT +A17D ; [.24D4.0020.0002.A17D] # YI SYLLABLE NIT +A17E ; [.24D5.0020.0002.A17E] # YI SYLLABLE NIX +A17F ; [.24D6.0020.0002.A17F] # YI SYLLABLE NI +A180 ; [.24D7.0020.0002.A180] # YI SYLLABLE NIP +A181 ; [.24D8.0020.0002.A181] # YI SYLLABLE NIEX +A182 ; [.24D9.0020.0002.A182] # YI SYLLABLE NIE +A183 ; [.24DA.0020.0002.A183] # YI SYLLABLE NIEP +A184 ; [.24DB.0020.0002.A184] # YI SYLLABLE NAX +A185 ; [.24DC.0020.0002.A185] # YI SYLLABLE NA +A186 ; [.24DD.0020.0002.A186] # YI SYLLABLE NAP +A187 ; [.24DE.0020.0002.A187] # YI SYLLABLE NUOX +A188 ; [.24DF.0020.0002.A188] # YI SYLLABLE NUO +A189 ; [.24E0.0020.0002.A189] # YI SYLLABLE NUOP +A18A ; [.24E1.0020.0002.A18A] # YI SYLLABLE NOT +A18B ; [.24E2.0020.0002.A18B] # YI SYLLABLE NOX +A18C ; [.24E3.0020.0002.A18C] # YI SYLLABLE NO +A18D ; [.24E4.0020.0002.A18D] # YI SYLLABLE NOP +A18E ; [.24E5.0020.0002.A18E] # YI SYLLABLE NEX +A18F ; [.24E6.0020.0002.A18F] # YI SYLLABLE NE +A190 ; [.24E7.0020.0002.A190] # YI SYLLABLE NEP +A191 ; [.24E8.0020.0002.A191] # YI SYLLABLE NUT +A192 ; [.24E9.0020.0002.A192] # YI SYLLABLE NUX +A193 ; [.24EA.0020.0002.A193] # YI SYLLABLE NU +A194 ; [.24EB.0020.0002.A194] # YI SYLLABLE NUP +A195 ; [.24EC.0020.0002.A195] # YI SYLLABLE NURX +A196 ; [.24ED.0020.0002.A196] # YI SYLLABLE NUR +A197 ; [.24EE.0020.0002.A197] # YI SYLLABLE HLIT +A198 ; [.24EF.0020.0002.A198] # YI SYLLABLE HLIX +A199 ; [.24F0.0020.0002.A199] # YI SYLLABLE HLI +A19A ; [.24F1.0020.0002.A19A] # YI SYLLABLE HLIP +A19B ; [.24F2.0020.0002.A19B] # YI SYLLABLE HLIEX +A19C ; [.24F3.0020.0002.A19C] # YI SYLLABLE HLIE +A19D ; [.24F4.0020.0002.A19D] # YI SYLLABLE HLIEP +A19E ; [.24F5.0020.0002.A19E] # YI SYLLABLE HLAT +A19F ; [.24F6.0020.0002.A19F] # YI SYLLABLE HLAX +A1A0 ; [.24F7.0020.0002.A1A0] # YI SYLLABLE HLA +A1A1 ; [.24F8.0020.0002.A1A1] # YI SYLLABLE HLAP +A1A2 ; [.24F9.0020.0002.A1A2] # YI SYLLABLE HLUOX +A1A3 ; [.24FA.0020.0002.A1A3] # YI SYLLABLE HLUO +A1A4 ; [.24FB.0020.0002.A1A4] # YI SYLLABLE HLUOP +A1A5 ; [.24FC.0020.0002.A1A5] # YI SYLLABLE HLOX +A1A6 ; [.24FD.0020.0002.A1A6] # YI SYLLABLE HLO +A1A7 ; [.24FE.0020.0002.A1A7] # YI SYLLABLE HLOP +A1A8 ; [.24FF.0020.0002.A1A8] # YI SYLLABLE HLEX +A1A9 ; [.2500.0020.0002.A1A9] # YI SYLLABLE HLE +A1AA ; [.2501.0020.0002.A1AA] # YI SYLLABLE HLEP +A1AB ; [.2502.0020.0002.A1AB] # YI SYLLABLE HLUT +A1AC ; [.2503.0020.0002.A1AC] # YI SYLLABLE HLUX +A1AD ; [.2504.0020.0002.A1AD] # YI SYLLABLE HLU +A1AE ; [.2505.0020.0002.A1AE] # YI SYLLABLE HLUP +A1AF ; [.2506.0020.0002.A1AF] # YI SYLLABLE HLURX +A1B0 ; [.2507.0020.0002.A1B0] # YI SYLLABLE HLUR +A1B1 ; [.2508.0020.0002.A1B1] # YI SYLLABLE HLYT +A1B2 ; [.2509.0020.0002.A1B2] # YI SYLLABLE HLYX +A1B3 ; [.250A.0020.0002.A1B3] # YI SYLLABLE HLY +A1B4 ; [.250B.0020.0002.A1B4] # YI SYLLABLE HLYP +A1B5 ; [.250C.0020.0002.A1B5] # YI SYLLABLE HLYRX +A1B6 ; [.250D.0020.0002.A1B6] # YI SYLLABLE HLYR +A1B7 ; [.250E.0020.0002.A1B7] # YI SYLLABLE LIT +A1B8 ; [.250F.0020.0002.A1B8] # YI SYLLABLE LIX +A1B9 ; [.2510.0020.0002.A1B9] # YI SYLLABLE LI +A1BA ; [.2511.0020.0002.A1BA] # YI SYLLABLE LIP +A1BB ; [.2512.0020.0002.A1BB] # YI SYLLABLE LIET +A1BC ; [.2513.0020.0002.A1BC] # YI SYLLABLE LIEX +A1BD ; [.2514.0020.0002.A1BD] # YI SYLLABLE LIE +A1BE ; [.2515.0020.0002.A1BE] # YI SYLLABLE LIEP +A1BF ; [.2516.0020.0002.A1BF] # YI SYLLABLE LAT +A1C0 ; [.2517.0020.0002.A1C0] # YI SYLLABLE LAX +A1C1 ; [.2518.0020.0002.A1C1] # YI SYLLABLE LA +A1C2 ; [.2519.0020.0002.A1C2] # YI SYLLABLE LAP +A1C3 ; [.251A.0020.0002.A1C3] # YI SYLLABLE LUOT +A1C4 ; [.251B.0020.0002.A1C4] # YI SYLLABLE LUOX +A1C5 ; [.251C.0020.0002.A1C5] # YI SYLLABLE LUO +A1C6 ; [.251D.0020.0002.A1C6] # YI SYLLABLE LUOP +A1C7 ; [.251E.0020.0002.A1C7] # YI SYLLABLE LOT +A1C8 ; [.251F.0020.0002.A1C8] # YI SYLLABLE LOX +A1C9 ; [.2520.0020.0002.A1C9] # YI SYLLABLE LO +A1CA ; [.2521.0020.0002.A1CA] # YI SYLLABLE LOP +A1CB ; [.2522.0020.0002.A1CB] # YI SYLLABLE LEX +A1CC ; [.2523.0020.0002.A1CC] # YI SYLLABLE LE +A1CD ; [.2524.0020.0002.A1CD] # YI SYLLABLE LEP +A1CE ; [.2525.0020.0002.A1CE] # YI SYLLABLE LUT +A1CF ; [.2526.0020.0002.A1CF] # YI SYLLABLE LUX +A1D0 ; [.2527.0020.0002.A1D0] # YI SYLLABLE LU +A1D1 ; [.2528.0020.0002.A1D1] # YI SYLLABLE LUP +A1D2 ; [.2529.0020.0002.A1D2] # YI SYLLABLE LURX +A1D3 ; [.252A.0020.0002.A1D3] # YI SYLLABLE LUR +A1D4 ; [.252B.0020.0002.A1D4] # YI SYLLABLE LYT +A1D5 ; [.252C.0020.0002.A1D5] # YI SYLLABLE LYX +A1D6 ; [.252D.0020.0002.A1D6] # YI SYLLABLE LY +A1D7 ; [.252E.0020.0002.A1D7] # YI SYLLABLE LYP +A1D8 ; [.252F.0020.0002.A1D8] # YI SYLLABLE LYRX +A1D9 ; [.2530.0020.0002.A1D9] # YI SYLLABLE LYR +A1DA ; [.2531.0020.0002.A1DA] # YI SYLLABLE GIT +A1DB ; [.2532.0020.0002.A1DB] # YI SYLLABLE GIX +A1DC ; [.2533.0020.0002.A1DC] # YI SYLLABLE GI +A1DD ; [.2534.0020.0002.A1DD] # YI SYLLABLE GIP +A1DE ; [.2535.0020.0002.A1DE] # YI SYLLABLE GIET +A1DF ; [.2536.0020.0002.A1DF] # YI SYLLABLE GIEX +A1E0 ; [.2537.0020.0002.A1E0] # YI SYLLABLE GIE +A1E1 ; [.2538.0020.0002.A1E1] # YI SYLLABLE GIEP +A1E2 ; [.2539.0020.0002.A1E2] # YI SYLLABLE GAT +A1E3 ; [.253A.0020.0002.A1E3] # YI SYLLABLE GAX +A1E4 ; [.253B.0020.0002.A1E4] # YI SYLLABLE GA +A1E5 ; [.253C.0020.0002.A1E5] # YI SYLLABLE GAP +A1E6 ; [.253D.0020.0002.A1E6] # YI SYLLABLE GUOT +A1E7 ; [.253E.0020.0002.A1E7] # YI SYLLABLE GUOX +A1E8 ; [.253F.0020.0002.A1E8] # YI SYLLABLE GUO +A1E9 ; [.2540.0020.0002.A1E9] # YI SYLLABLE GUOP +A1EA ; [.2541.0020.0002.A1EA] # YI SYLLABLE GOT +A1EB ; [.2542.0020.0002.A1EB] # YI SYLLABLE GOX +A1EC ; [.2543.0020.0002.A1EC] # YI SYLLABLE GO +A1ED ; [.2544.0020.0002.A1ED] # YI SYLLABLE GOP +A1EE ; [.2545.0020.0002.A1EE] # YI SYLLABLE GET +A1EF ; [.2546.0020.0002.A1EF] # YI SYLLABLE GEX +A1F0 ; [.2547.0020.0002.A1F0] # YI SYLLABLE GE +A1F1 ; [.2548.0020.0002.A1F1] # YI SYLLABLE GEP +A1F2 ; [.2549.0020.0002.A1F2] # YI SYLLABLE GUT +A1F3 ; [.254A.0020.0002.A1F3] # YI SYLLABLE GUX +A1F4 ; [.254B.0020.0002.A1F4] # YI SYLLABLE GU +A1F5 ; [.254C.0020.0002.A1F5] # YI SYLLABLE GUP +A1F6 ; [.254D.0020.0002.A1F6] # YI SYLLABLE GURX +A1F7 ; [.254E.0020.0002.A1F7] # YI SYLLABLE GUR +A1F8 ; [.254F.0020.0002.A1F8] # YI SYLLABLE KIT +A1F9 ; [.2550.0020.0002.A1F9] # YI SYLLABLE KIX +A1FA ; [.2551.0020.0002.A1FA] # YI SYLLABLE KI +A1FB ; [.2552.0020.0002.A1FB] # YI SYLLABLE KIP +A1FC ; [.2553.0020.0002.A1FC] # YI SYLLABLE KIEX +A1FD ; [.2554.0020.0002.A1FD] # YI SYLLABLE KIE +A1FE ; [.2555.0020.0002.A1FE] # YI SYLLABLE KIEP +A1FF ; [.2556.0020.0002.A1FF] # YI SYLLABLE KAT +A200 ; [.2557.0020.0002.A200] # YI SYLLABLE KAX +A201 ; [.2558.0020.0002.A201] # YI SYLLABLE KA +A202 ; [.2559.0020.0002.A202] # YI SYLLABLE KAP +A203 ; [.255A.0020.0002.A203] # YI SYLLABLE KUOX +A204 ; [.255B.0020.0002.A204] # YI SYLLABLE KUO +A205 ; [.255C.0020.0002.A205] # YI SYLLABLE KUOP +A206 ; [.255D.0020.0002.A206] # YI SYLLABLE KOT +A207 ; [.255E.0020.0002.A207] # YI SYLLABLE KOX +A208 ; [.255F.0020.0002.A208] # YI SYLLABLE KO +A209 ; [.2560.0020.0002.A209] # YI SYLLABLE KOP +A20A ; [.2561.0020.0002.A20A] # YI SYLLABLE KET +A20B ; [.2562.0020.0002.A20B] # YI SYLLABLE KEX +A20C ; [.2563.0020.0002.A20C] # YI SYLLABLE KE +A20D ; [.2564.0020.0002.A20D] # YI SYLLABLE KEP +A20E ; [.2565.0020.0002.A20E] # YI SYLLABLE KUT +A20F ; [.2566.0020.0002.A20F] # YI SYLLABLE KUX +A210 ; [.2567.0020.0002.A210] # YI SYLLABLE KU +A211 ; [.2568.0020.0002.A211] # YI SYLLABLE KUP +A212 ; [.2569.0020.0002.A212] # YI SYLLABLE KURX +A213 ; [.256A.0020.0002.A213] # YI SYLLABLE KUR +A214 ; [.256B.0020.0002.A214] # YI SYLLABLE GGIT +A215 ; [.256C.0020.0002.A215] # YI SYLLABLE GGIX +A216 ; [.256D.0020.0002.A216] # YI SYLLABLE GGI +A217 ; [.256E.0020.0002.A217] # YI SYLLABLE GGIEX +A218 ; [.256F.0020.0002.A218] # YI SYLLABLE GGIE +A219 ; [.2570.0020.0002.A219] # YI SYLLABLE GGIEP +A21A ; [.2571.0020.0002.A21A] # YI SYLLABLE GGAT +A21B ; [.2572.0020.0002.A21B] # YI SYLLABLE GGAX +A21C ; [.2573.0020.0002.A21C] # YI SYLLABLE GGA +A21D ; [.2574.0020.0002.A21D] # YI SYLLABLE GGAP +A21E ; [.2575.0020.0002.A21E] # YI SYLLABLE GGUOT +A21F ; [.2576.0020.0002.A21F] # YI SYLLABLE GGUOX +A220 ; [.2577.0020.0002.A220] # YI SYLLABLE GGUO +A221 ; [.2578.0020.0002.A221] # YI SYLLABLE GGUOP +A222 ; [.2579.0020.0002.A222] # YI SYLLABLE GGOT +A223 ; [.257A.0020.0002.A223] # YI SYLLABLE GGOX +A224 ; [.257B.0020.0002.A224] # YI SYLLABLE GGO +A225 ; [.257C.0020.0002.A225] # YI SYLLABLE GGOP +A226 ; [.257D.0020.0002.A226] # YI SYLLABLE GGET +A227 ; [.257E.0020.0002.A227] # YI SYLLABLE GGEX +A228 ; [.257F.0020.0002.A228] # YI SYLLABLE GGE +A229 ; [.2580.0020.0002.A229] # YI SYLLABLE GGEP +A22A ; [.2581.0020.0002.A22A] # YI SYLLABLE GGUT +A22B ; [.2582.0020.0002.A22B] # YI SYLLABLE GGUX +A22C ; [.2583.0020.0002.A22C] # YI SYLLABLE GGU +A22D ; [.2584.0020.0002.A22D] # YI SYLLABLE GGUP +A22E ; [.2585.0020.0002.A22E] # YI SYLLABLE GGURX +A22F ; [.2586.0020.0002.A22F] # YI SYLLABLE GGUR +A230 ; [.2587.0020.0002.A230] # YI SYLLABLE MGIEX +A231 ; [.2588.0020.0002.A231] # YI SYLLABLE MGIE +A232 ; [.2589.0020.0002.A232] # YI SYLLABLE MGAT +A233 ; [.258A.0020.0002.A233] # YI SYLLABLE MGAX +A234 ; [.258B.0020.0002.A234] # YI SYLLABLE MGA +A235 ; [.258C.0020.0002.A235] # YI SYLLABLE MGAP +A236 ; [.258D.0020.0002.A236] # YI SYLLABLE MGUOX +A237 ; [.258E.0020.0002.A237] # YI SYLLABLE MGUO +A238 ; [.258F.0020.0002.A238] # YI SYLLABLE MGUOP +A239 ; [.2590.0020.0002.A239] # YI SYLLABLE MGOT +A23A ; [.2591.0020.0002.A23A] # YI SYLLABLE MGOX +A23B ; [.2592.0020.0002.A23B] # YI SYLLABLE MGO +A23C ; [.2593.0020.0002.A23C] # YI SYLLABLE MGOP +A23D ; [.2594.0020.0002.A23D] # YI SYLLABLE MGEX +A23E ; [.2595.0020.0002.A23E] # YI SYLLABLE MGE +A23F ; [.2596.0020.0002.A23F] # YI SYLLABLE MGEP +A240 ; [.2597.0020.0002.A240] # YI SYLLABLE MGUT +A241 ; [.2598.0020.0002.A241] # YI SYLLABLE MGUX +A242 ; [.2599.0020.0002.A242] # YI SYLLABLE MGU +A243 ; [.259A.0020.0002.A243] # YI SYLLABLE MGUP +A244 ; [.259B.0020.0002.A244] # YI SYLLABLE MGURX +A245 ; [.259C.0020.0002.A245] # YI SYLLABLE MGUR +A246 ; [.259D.0020.0002.A246] # YI SYLLABLE HXIT +A247 ; [.259E.0020.0002.A247] # YI SYLLABLE HXIX +A248 ; [.259F.0020.0002.A248] # YI SYLLABLE HXI +A249 ; [.25A0.0020.0002.A249] # YI SYLLABLE HXIP +A24A ; [.25A1.0020.0002.A24A] # YI SYLLABLE HXIET +A24B ; [.25A2.0020.0002.A24B] # YI SYLLABLE HXIEX +A24C ; [.25A3.0020.0002.A24C] # YI SYLLABLE HXIE +A24D ; [.25A4.0020.0002.A24D] # YI SYLLABLE HXIEP +A24E ; [.25A5.0020.0002.A24E] # YI SYLLABLE HXAT +A24F ; [.25A6.0020.0002.A24F] # YI SYLLABLE HXAX +A250 ; [.25A7.0020.0002.A250] # YI SYLLABLE HXA +A251 ; [.25A8.0020.0002.A251] # YI SYLLABLE HXAP +A252 ; [.25A9.0020.0002.A252] # YI SYLLABLE HXUOT +A253 ; [.25AA.0020.0002.A253] # YI SYLLABLE HXUOX +A254 ; [.25AB.0020.0002.A254] # YI SYLLABLE HXUO +A255 ; [.25AC.0020.0002.A255] # YI SYLLABLE HXUOP +A256 ; [.25AD.0020.0002.A256] # YI SYLLABLE HXOT +A257 ; [.25AE.0020.0002.A257] # YI SYLLABLE HXOX +A258 ; [.25AF.0020.0002.A258] # YI SYLLABLE HXO +A259 ; [.25B0.0020.0002.A259] # YI SYLLABLE HXOP +A25A ; [.25B1.0020.0002.A25A] # YI SYLLABLE HXEX +A25B ; [.25B2.0020.0002.A25B] # YI SYLLABLE HXE +A25C ; [.25B3.0020.0002.A25C] # YI SYLLABLE HXEP +A25D ; [.25B4.0020.0002.A25D] # YI SYLLABLE NGIEX +A25E ; [.25B5.0020.0002.A25E] # YI SYLLABLE NGIE +A25F ; [.25B6.0020.0002.A25F] # YI SYLLABLE NGIEP +A260 ; [.25B7.0020.0002.A260] # YI SYLLABLE NGAT +A261 ; [.25B8.0020.0002.A261] # YI SYLLABLE NGAX +A262 ; [.25B9.0020.0002.A262] # YI SYLLABLE NGA +A263 ; [.25BA.0020.0002.A263] # YI SYLLABLE NGAP +A264 ; [.25BB.0020.0002.A264] # YI SYLLABLE NGUOT +A265 ; [.25BC.0020.0002.A265] # YI SYLLABLE NGUOX +A266 ; [.25BD.0020.0002.A266] # YI SYLLABLE NGUO +A267 ; [.25BE.0020.0002.A267] # YI SYLLABLE NGOT +A268 ; [.25BF.0020.0002.A268] # YI SYLLABLE NGOX +A269 ; [.25C0.0020.0002.A269] # YI SYLLABLE NGO +A26A ; [.25C1.0020.0002.A26A] # YI SYLLABLE NGOP +A26B ; [.25C2.0020.0002.A26B] # YI SYLLABLE NGEX +A26C ; [.25C3.0020.0002.A26C] # YI SYLLABLE NGE +A26D ; [.25C4.0020.0002.A26D] # YI SYLLABLE NGEP +A26E ; [.25C5.0020.0002.A26E] # YI SYLLABLE HIT +A26F ; [.25C6.0020.0002.A26F] # YI SYLLABLE HIEX +A270 ; [.25C7.0020.0002.A270] # YI SYLLABLE HIE +A271 ; [.25C8.0020.0002.A271] # YI SYLLABLE HAT +A272 ; [.25C9.0020.0002.A272] # YI SYLLABLE HAX +A273 ; [.25CA.0020.0002.A273] # YI SYLLABLE HA +A274 ; [.25CB.0020.0002.A274] # YI SYLLABLE HAP +A275 ; [.25CC.0020.0002.A275] # YI SYLLABLE HUOT +A276 ; [.25CD.0020.0002.A276] # YI SYLLABLE HUOX +A277 ; [.25CE.0020.0002.A277] # YI SYLLABLE HUO +A278 ; [.25CF.0020.0002.A278] # YI SYLLABLE HUOP +A279 ; [.25D0.0020.0002.A279] # YI SYLLABLE HOT +A27A ; [.25D1.0020.0002.A27A] # YI SYLLABLE HOX +A27B ; [.25D2.0020.0002.A27B] # YI SYLLABLE HO +A27C ; [.25D3.0020.0002.A27C] # YI SYLLABLE HOP +A27D ; [.25D4.0020.0002.A27D] # YI SYLLABLE HEX +A27E ; [.25D5.0020.0002.A27E] # YI SYLLABLE HE +A27F ; [.25D6.0020.0002.A27F] # YI SYLLABLE HEP +A280 ; [.25D7.0020.0002.A280] # YI SYLLABLE WAT +A281 ; [.25D8.0020.0002.A281] # YI SYLLABLE WAX +A282 ; [.25D9.0020.0002.A282] # YI SYLLABLE WA +A283 ; [.25DA.0020.0002.A283] # YI SYLLABLE WAP +A284 ; [.25DB.0020.0002.A284] # YI SYLLABLE WUOX +A285 ; [.25DC.0020.0002.A285] # YI SYLLABLE WUO +A286 ; [.25DD.0020.0002.A286] # YI SYLLABLE WUOP +A287 ; [.25DE.0020.0002.A287] # YI SYLLABLE WOX +A288 ; [.25DF.0020.0002.A288] # YI SYLLABLE WO +A289 ; [.25E0.0020.0002.A289] # YI SYLLABLE WOP +A28A ; [.25E1.0020.0002.A28A] # YI SYLLABLE WEX +A28B ; [.25E2.0020.0002.A28B] # YI SYLLABLE WE +A28C ; [.25E3.0020.0002.A28C] # YI SYLLABLE WEP +A28D ; [.25E4.0020.0002.A28D] # YI SYLLABLE ZIT +A28E ; [.25E5.0020.0002.A28E] # YI SYLLABLE ZIX +A28F ; [.25E6.0020.0002.A28F] # YI SYLLABLE ZI +A290 ; [.25E7.0020.0002.A290] # YI SYLLABLE ZIP +A291 ; [.25E8.0020.0002.A291] # YI SYLLABLE ZIEX +A292 ; [.25E9.0020.0002.A292] # YI SYLLABLE ZIE +A293 ; [.25EA.0020.0002.A293] # YI SYLLABLE ZIEP +A294 ; [.25EB.0020.0002.A294] # YI SYLLABLE ZAT +A295 ; [.25EC.0020.0002.A295] # YI SYLLABLE ZAX +A296 ; [.25ED.0020.0002.A296] # YI SYLLABLE ZA +A297 ; [.25EE.0020.0002.A297] # YI SYLLABLE ZAP +A298 ; [.25EF.0020.0002.A298] # YI SYLLABLE ZUOX +A299 ; [.25F0.0020.0002.A299] # YI SYLLABLE ZUO +A29A ; [.25F1.0020.0002.A29A] # YI SYLLABLE ZUOP +A29B ; [.25F2.0020.0002.A29B] # YI SYLLABLE ZOT +A29C ; [.25F3.0020.0002.A29C] # YI SYLLABLE ZOX +A29D ; [.25F4.0020.0002.A29D] # YI SYLLABLE ZO +A29E ; [.25F5.0020.0002.A29E] # YI SYLLABLE ZOP +A29F ; [.25F6.0020.0002.A29F] # YI SYLLABLE ZEX +A2A0 ; [.25F7.0020.0002.A2A0] # YI SYLLABLE ZE +A2A1 ; [.25F8.0020.0002.A2A1] # YI SYLLABLE ZEP +A2A2 ; [.25F9.0020.0002.A2A2] # YI SYLLABLE ZUT +A2A3 ; [.25FA.0020.0002.A2A3] # YI SYLLABLE ZUX +A2A4 ; [.25FB.0020.0002.A2A4] # YI SYLLABLE ZU +A2A5 ; [.25FC.0020.0002.A2A5] # YI SYLLABLE ZUP +A2A6 ; [.25FD.0020.0002.A2A6] # YI SYLLABLE ZURX +A2A7 ; [.25FE.0020.0002.A2A7] # YI SYLLABLE ZUR +A2A8 ; [.25FF.0020.0002.A2A8] # YI SYLLABLE ZYT +A2A9 ; [.2600.0020.0002.A2A9] # YI SYLLABLE ZYX +A2AA ; [.2601.0020.0002.A2AA] # YI SYLLABLE ZY +A2AB ; [.2602.0020.0002.A2AB] # YI SYLLABLE ZYP +A2AC ; [.2603.0020.0002.A2AC] # YI SYLLABLE ZYRX +A2AD ; [.2604.0020.0002.A2AD] # YI SYLLABLE ZYR +A2AE ; [.2605.0020.0002.A2AE] # YI SYLLABLE CIT +A2AF ; [.2606.0020.0002.A2AF] # YI SYLLABLE CIX +A2B0 ; [.2607.0020.0002.A2B0] # YI SYLLABLE CI +A2B1 ; [.2608.0020.0002.A2B1] # YI SYLLABLE CIP +A2B2 ; [.2609.0020.0002.A2B2] # YI SYLLABLE CIET +A2B3 ; [.260A.0020.0002.A2B3] # YI SYLLABLE CIEX +A2B4 ; [.260B.0020.0002.A2B4] # YI SYLLABLE CIE +A2B5 ; [.260C.0020.0002.A2B5] # YI SYLLABLE CIEP +A2B6 ; [.260D.0020.0002.A2B6] # YI SYLLABLE CAT +A2B7 ; [.260E.0020.0002.A2B7] # YI SYLLABLE CAX +A2B8 ; [.260F.0020.0002.A2B8] # YI SYLLABLE CA +A2B9 ; [.2610.0020.0002.A2B9] # YI SYLLABLE CAP +A2BA ; [.2611.0020.0002.A2BA] # YI SYLLABLE CUOX +A2BB ; [.2612.0020.0002.A2BB] # YI SYLLABLE CUO +A2BC ; [.2613.0020.0002.A2BC] # YI SYLLABLE CUOP +A2BD ; [.2614.0020.0002.A2BD] # YI SYLLABLE COT +A2BE ; [.2615.0020.0002.A2BE] # YI SYLLABLE COX +A2BF ; [.2616.0020.0002.A2BF] # YI SYLLABLE CO +A2C0 ; [.2617.0020.0002.A2C0] # YI SYLLABLE COP +A2C1 ; [.2618.0020.0002.A2C1] # YI SYLLABLE CEX +A2C2 ; [.2619.0020.0002.A2C2] # YI SYLLABLE CE +A2C3 ; [.261A.0020.0002.A2C3] # YI SYLLABLE CEP +A2C4 ; [.261B.0020.0002.A2C4] # YI SYLLABLE CUT +A2C5 ; [.261C.0020.0002.A2C5] # YI SYLLABLE CUX +A2C6 ; [.261D.0020.0002.A2C6] # YI SYLLABLE CU +A2C7 ; [.261E.0020.0002.A2C7] # YI SYLLABLE CUP +A2C8 ; [.261F.0020.0002.A2C8] # YI SYLLABLE CURX +A2C9 ; [.2620.0020.0002.A2C9] # YI SYLLABLE CUR +A2CA ; [.2621.0020.0002.A2CA] # YI SYLLABLE CYT +A2CB ; [.2622.0020.0002.A2CB] # YI SYLLABLE CYX +A2CC ; [.2623.0020.0002.A2CC] # YI SYLLABLE CY +A2CD ; [.2624.0020.0002.A2CD] # YI SYLLABLE CYP +A2CE ; [.2625.0020.0002.A2CE] # YI SYLLABLE CYRX +A2CF ; [.2626.0020.0002.A2CF] # YI SYLLABLE CYR +A2D0 ; [.2627.0020.0002.A2D0] # YI SYLLABLE ZZIT +A2D1 ; [.2628.0020.0002.A2D1] # YI SYLLABLE ZZIX +A2D2 ; [.2629.0020.0002.A2D2] # YI SYLLABLE ZZI +A2D3 ; [.262A.0020.0002.A2D3] # YI SYLLABLE ZZIP +A2D4 ; [.262B.0020.0002.A2D4] # YI SYLLABLE ZZIET +A2D5 ; [.262C.0020.0002.A2D5] # YI SYLLABLE ZZIEX +A2D6 ; [.262D.0020.0002.A2D6] # YI SYLLABLE ZZIE +A2D7 ; [.262E.0020.0002.A2D7] # YI SYLLABLE ZZIEP +A2D8 ; [.262F.0020.0002.A2D8] # YI SYLLABLE ZZAT +A2D9 ; [.2630.0020.0002.A2D9] # YI SYLLABLE ZZAX +A2DA ; [.2631.0020.0002.A2DA] # YI SYLLABLE ZZA +A2DB ; [.2632.0020.0002.A2DB] # YI SYLLABLE ZZAP +A2DC ; [.2633.0020.0002.A2DC] # YI SYLLABLE ZZOX +A2DD ; [.2634.0020.0002.A2DD] # YI SYLLABLE ZZO +A2DE ; [.2635.0020.0002.A2DE] # YI SYLLABLE ZZOP +A2DF ; [.2636.0020.0002.A2DF] # YI SYLLABLE ZZEX +A2E0 ; [.2637.0020.0002.A2E0] # YI SYLLABLE ZZE +A2E1 ; [.2638.0020.0002.A2E1] # YI SYLLABLE ZZEP +A2E2 ; [.2639.0020.0002.A2E2] # YI SYLLABLE ZZUX +A2E3 ; [.263A.0020.0002.A2E3] # YI SYLLABLE ZZU +A2E4 ; [.263B.0020.0002.A2E4] # YI SYLLABLE ZZUP +A2E5 ; [.263C.0020.0002.A2E5] # YI SYLLABLE ZZURX +A2E6 ; [.263D.0020.0002.A2E6] # YI SYLLABLE ZZUR +A2E7 ; [.263E.0020.0002.A2E7] # YI SYLLABLE ZZYT +A2E8 ; [.263F.0020.0002.A2E8] # YI SYLLABLE ZZYX +A2E9 ; [.2640.0020.0002.A2E9] # YI SYLLABLE ZZY +A2EA ; [.2641.0020.0002.A2EA] # YI SYLLABLE ZZYP +A2EB ; [.2642.0020.0002.A2EB] # YI SYLLABLE ZZYRX +A2EC ; [.2643.0020.0002.A2EC] # YI SYLLABLE ZZYR +A2ED ; [.2644.0020.0002.A2ED] # YI SYLLABLE NZIT +A2EE ; [.2645.0020.0002.A2EE] # YI SYLLABLE NZIX +A2EF ; [.2646.0020.0002.A2EF] # YI SYLLABLE NZI +A2F0 ; [.2647.0020.0002.A2F0] # YI SYLLABLE NZIP +A2F1 ; [.2648.0020.0002.A2F1] # YI SYLLABLE NZIEX +A2F2 ; [.2649.0020.0002.A2F2] # YI SYLLABLE NZIE +A2F3 ; [.264A.0020.0002.A2F3] # YI SYLLABLE NZIEP +A2F4 ; [.264B.0020.0002.A2F4] # YI SYLLABLE NZAT +A2F5 ; [.264C.0020.0002.A2F5] # YI SYLLABLE NZAX +A2F6 ; [.264D.0020.0002.A2F6] # YI SYLLABLE NZA +A2F7 ; [.264E.0020.0002.A2F7] # YI SYLLABLE NZAP +A2F8 ; [.264F.0020.0002.A2F8] # YI SYLLABLE NZUOX +A2F9 ; [.2650.0020.0002.A2F9] # YI SYLLABLE NZUO +A2FA ; [.2651.0020.0002.A2FA] # YI SYLLABLE NZOX +A2FB ; [.2652.0020.0002.A2FB] # YI SYLLABLE NZOP +A2FC ; [.2653.0020.0002.A2FC] # YI SYLLABLE NZEX +A2FD ; [.2654.0020.0002.A2FD] # YI SYLLABLE NZE +A2FE ; [.2655.0020.0002.A2FE] # YI SYLLABLE NZUX +A2FF ; [.2656.0020.0002.A2FF] # YI SYLLABLE NZU +A300 ; [.2657.0020.0002.A300] # YI SYLLABLE NZUP +A301 ; [.2658.0020.0002.A301] # YI SYLLABLE NZURX +A302 ; [.2659.0020.0002.A302] # YI SYLLABLE NZUR +A303 ; [.265A.0020.0002.A303] # YI SYLLABLE NZYT +A304 ; [.265B.0020.0002.A304] # YI SYLLABLE NZYX +A305 ; [.265C.0020.0002.A305] # YI SYLLABLE NZY +A306 ; [.265D.0020.0002.A306] # YI SYLLABLE NZYP +A307 ; [.265E.0020.0002.A307] # YI SYLLABLE NZYRX +A308 ; [.265F.0020.0002.A308] # YI SYLLABLE NZYR +A309 ; [.2660.0020.0002.A309] # YI SYLLABLE SIT +A30A ; [.2661.0020.0002.A30A] # YI SYLLABLE SIX +A30B ; [.2662.0020.0002.A30B] # YI SYLLABLE SI +A30C ; [.2663.0020.0002.A30C] # YI SYLLABLE SIP +A30D ; [.2664.0020.0002.A30D] # YI SYLLABLE SIEX +A30E ; [.2665.0020.0002.A30E] # YI SYLLABLE SIE +A30F ; [.2666.0020.0002.A30F] # YI SYLLABLE SIEP +A310 ; [.2667.0020.0002.A310] # YI SYLLABLE SAT +A311 ; [.2668.0020.0002.A311] # YI SYLLABLE SAX +A312 ; [.2669.0020.0002.A312] # YI SYLLABLE SA +A313 ; [.266A.0020.0002.A313] # YI SYLLABLE SAP +A314 ; [.266B.0020.0002.A314] # YI SYLLABLE SUOX +A315 ; [.266C.0020.0002.A315] # YI SYLLABLE SUO +A316 ; [.266D.0020.0002.A316] # YI SYLLABLE SUOP +A317 ; [.266E.0020.0002.A317] # YI SYLLABLE SOT +A318 ; [.266F.0020.0002.A318] # YI SYLLABLE SOX +A319 ; [.2670.0020.0002.A319] # YI SYLLABLE SO +A31A ; [.2671.0020.0002.A31A] # YI SYLLABLE SOP +A31B ; [.2672.0020.0002.A31B] # YI SYLLABLE SEX +A31C ; [.2673.0020.0002.A31C] # YI SYLLABLE SE +A31D ; [.2674.0020.0002.A31D] # YI SYLLABLE SEP +A31E ; [.2675.0020.0002.A31E] # YI SYLLABLE SUT +A31F ; [.2676.0020.0002.A31F] # YI SYLLABLE SUX +A320 ; [.2677.0020.0002.A320] # YI SYLLABLE SU +A321 ; [.2678.0020.0002.A321] # YI SYLLABLE SUP +A322 ; [.2679.0020.0002.A322] # YI SYLLABLE SURX +A323 ; [.267A.0020.0002.A323] # YI SYLLABLE SUR +A324 ; [.267B.0020.0002.A324] # YI SYLLABLE SYT +A325 ; [.267C.0020.0002.A325] # YI SYLLABLE SYX +A326 ; [.267D.0020.0002.A326] # YI SYLLABLE SY +A327 ; [.267E.0020.0002.A327] # YI SYLLABLE SYP +A328 ; [.267F.0020.0002.A328] # YI SYLLABLE SYRX +A329 ; [.2680.0020.0002.A329] # YI SYLLABLE SYR +A32A ; [.2681.0020.0002.A32A] # YI SYLLABLE SSIT +A32B ; [.2682.0020.0002.A32B] # YI SYLLABLE SSIX +A32C ; [.2683.0020.0002.A32C] # YI SYLLABLE SSI +A32D ; [.2684.0020.0002.A32D] # YI SYLLABLE SSIP +A32E ; [.2685.0020.0002.A32E] # YI SYLLABLE SSIEX +A32F ; [.2686.0020.0002.A32F] # YI SYLLABLE SSIE +A330 ; [.2687.0020.0002.A330] # YI SYLLABLE SSIEP +A331 ; [.2688.0020.0002.A331] # YI SYLLABLE SSAT +A332 ; [.2689.0020.0002.A332] # YI SYLLABLE SSAX +A333 ; [.268A.0020.0002.A333] # YI SYLLABLE SSA +A334 ; [.268B.0020.0002.A334] # YI SYLLABLE SSAP +A335 ; [.268C.0020.0002.A335] # YI SYLLABLE SSOT +A336 ; [.268D.0020.0002.A336] # YI SYLLABLE SSOX +A337 ; [.268E.0020.0002.A337] # YI SYLLABLE SSO +A338 ; [.268F.0020.0002.A338] # YI SYLLABLE SSOP +A339 ; [.2690.0020.0002.A339] # YI SYLLABLE SSEX +A33A ; [.2691.0020.0002.A33A] # YI SYLLABLE SSE +A33B ; [.2692.0020.0002.A33B] # YI SYLLABLE SSEP +A33C ; [.2693.0020.0002.A33C] # YI SYLLABLE SSUT +A33D ; [.2694.0020.0002.A33D] # YI SYLLABLE SSUX +A33E ; [.2695.0020.0002.A33E] # YI SYLLABLE SSU +A33F ; [.2696.0020.0002.A33F] # YI SYLLABLE SSUP +A340 ; [.2697.0020.0002.A340] # YI SYLLABLE SSYT +A341 ; [.2698.0020.0002.A341] # YI SYLLABLE SSYX +A342 ; [.2699.0020.0002.A342] # YI SYLLABLE SSY +A343 ; [.269A.0020.0002.A343] # YI SYLLABLE SSYP +A344 ; [.269B.0020.0002.A344] # YI SYLLABLE SSYRX +A345 ; [.269C.0020.0002.A345] # YI SYLLABLE SSYR +A346 ; [.269D.0020.0002.A346] # YI SYLLABLE ZHAT +A347 ; [.269E.0020.0002.A347] # YI SYLLABLE ZHAX +A348 ; [.269F.0020.0002.A348] # YI SYLLABLE ZHA +A349 ; [.26A0.0020.0002.A349] # YI SYLLABLE ZHAP +A34A ; [.26A1.0020.0002.A34A] # YI SYLLABLE ZHUOX +A34B ; [.26A2.0020.0002.A34B] # YI SYLLABLE ZHUO +A34C ; [.26A3.0020.0002.A34C] # YI SYLLABLE ZHUOP +A34D ; [.26A4.0020.0002.A34D] # YI SYLLABLE ZHOT +A34E ; [.26A5.0020.0002.A34E] # YI SYLLABLE ZHOX +A34F ; [.26A6.0020.0002.A34F] # YI SYLLABLE ZHO +A350 ; [.26A7.0020.0002.A350] # YI SYLLABLE ZHOP +A351 ; [.26A8.0020.0002.A351] # YI SYLLABLE ZHET +A352 ; [.26A9.0020.0002.A352] # YI SYLLABLE ZHEX +A353 ; [.26AA.0020.0002.A353] # YI SYLLABLE ZHE +A354 ; [.26AB.0020.0002.A354] # YI SYLLABLE ZHEP +A355 ; [.26AC.0020.0002.A355] # YI SYLLABLE ZHUT +A356 ; [.26AD.0020.0002.A356] # YI SYLLABLE ZHUX +A357 ; [.26AE.0020.0002.A357] # YI SYLLABLE ZHU +A358 ; [.26AF.0020.0002.A358] # YI SYLLABLE ZHUP +A359 ; [.26B0.0020.0002.A359] # YI SYLLABLE ZHURX +A35A ; [.26B1.0020.0002.A35A] # YI SYLLABLE ZHUR +A35B ; [.26B2.0020.0002.A35B] # YI SYLLABLE ZHYT +A35C ; [.26B3.0020.0002.A35C] # YI SYLLABLE ZHYX +A35D ; [.26B4.0020.0002.A35D] # YI SYLLABLE ZHY +A35E ; [.26B5.0020.0002.A35E] # YI SYLLABLE ZHYP +A35F ; [.26B6.0020.0002.A35F] # YI SYLLABLE ZHYRX +A360 ; [.26B7.0020.0002.A360] # YI SYLLABLE ZHYR +A361 ; [.26B8.0020.0002.A361] # YI SYLLABLE CHAT +A362 ; [.26B9.0020.0002.A362] # YI SYLLABLE CHAX +A363 ; [.26BA.0020.0002.A363] # YI SYLLABLE CHA +A364 ; [.26BB.0020.0002.A364] # YI SYLLABLE CHAP +A365 ; [.26BC.0020.0002.A365] # YI SYLLABLE CHUOT +A366 ; [.26BD.0020.0002.A366] # YI SYLLABLE CHUOX +A367 ; [.26BE.0020.0002.A367] # YI SYLLABLE CHUO +A368 ; [.26BF.0020.0002.A368] # YI SYLLABLE CHUOP +A369 ; [.26C0.0020.0002.A369] # YI SYLLABLE CHOT +A36A ; [.26C1.0020.0002.A36A] # YI SYLLABLE CHOX +A36B ; [.26C2.0020.0002.A36B] # YI SYLLABLE CHO +A36C ; [.26C3.0020.0002.A36C] # YI SYLLABLE CHOP +A36D ; [.26C4.0020.0002.A36D] # YI SYLLABLE CHET +A36E ; [.26C5.0020.0002.A36E] # YI SYLLABLE CHEX +A36F ; [.26C6.0020.0002.A36F] # YI SYLLABLE CHE +A370 ; [.26C7.0020.0002.A370] # YI SYLLABLE CHEP +A371 ; [.26C8.0020.0002.A371] # YI SYLLABLE CHUX +A372 ; [.26C9.0020.0002.A372] # YI SYLLABLE CHU +A373 ; [.26CA.0020.0002.A373] # YI SYLLABLE CHUP +A374 ; [.26CB.0020.0002.A374] # YI SYLLABLE CHURX +A375 ; [.26CC.0020.0002.A375] # YI SYLLABLE CHUR +A376 ; [.26CD.0020.0002.A376] # YI SYLLABLE CHYT +A377 ; [.26CE.0020.0002.A377] # YI SYLLABLE CHYX +A378 ; [.26CF.0020.0002.A378] # YI SYLLABLE CHY +A379 ; [.26D0.0020.0002.A379] # YI SYLLABLE CHYP +A37A ; [.26D1.0020.0002.A37A] # YI SYLLABLE CHYRX +A37B ; [.26D2.0020.0002.A37B] # YI SYLLABLE CHYR +A37C ; [.26D3.0020.0002.A37C] # YI SYLLABLE RRAX +A37D ; [.26D4.0020.0002.A37D] # YI SYLLABLE RRA +A37E ; [.26D5.0020.0002.A37E] # YI SYLLABLE RRUOX +A37F ; [.26D6.0020.0002.A37F] # YI SYLLABLE RRUO +A380 ; [.26D7.0020.0002.A380] # YI SYLLABLE RROT +A381 ; [.26D8.0020.0002.A381] # YI SYLLABLE RROX +A382 ; [.26D9.0020.0002.A382] # YI SYLLABLE RRO +A383 ; [.26DA.0020.0002.A383] # YI SYLLABLE RROP +A384 ; [.26DB.0020.0002.A384] # YI SYLLABLE RRET +A385 ; [.26DC.0020.0002.A385] # YI SYLLABLE RREX +A386 ; [.26DD.0020.0002.A386] # YI SYLLABLE RRE +A387 ; [.26DE.0020.0002.A387] # YI SYLLABLE RREP +A388 ; [.26DF.0020.0002.A388] # YI SYLLABLE RRUT +A389 ; [.26E0.0020.0002.A389] # YI SYLLABLE RRUX +A38A ; [.26E1.0020.0002.A38A] # YI SYLLABLE RRU +A38B ; [.26E2.0020.0002.A38B] # YI SYLLABLE RRUP +A38C ; [.26E3.0020.0002.A38C] # YI SYLLABLE RRURX +A38D ; [.26E4.0020.0002.A38D] # YI SYLLABLE RRUR +A38E ; [.26E5.0020.0002.A38E] # YI SYLLABLE RRYT +A38F ; [.26E6.0020.0002.A38F] # YI SYLLABLE RRYX +A390 ; [.26E7.0020.0002.A390] # YI SYLLABLE RRY +A391 ; [.26E8.0020.0002.A391] # YI SYLLABLE RRYP +A392 ; [.26E9.0020.0002.A392] # YI SYLLABLE RRYRX +A393 ; [.26EA.0020.0002.A393] # YI SYLLABLE RRYR +A394 ; [.26EB.0020.0002.A394] # YI SYLLABLE NRAT +A395 ; [.26EC.0020.0002.A395] # YI SYLLABLE NRAX +A396 ; [.26ED.0020.0002.A396] # YI SYLLABLE NRA +A397 ; [.26EE.0020.0002.A397] # YI SYLLABLE NRAP +A398 ; [.26EF.0020.0002.A398] # YI SYLLABLE NROX +A399 ; [.26F0.0020.0002.A399] # YI SYLLABLE NRO +A39A ; [.26F1.0020.0002.A39A] # YI SYLLABLE NROP +A39B ; [.26F2.0020.0002.A39B] # YI SYLLABLE NRET +A39C ; [.26F3.0020.0002.A39C] # YI SYLLABLE NREX +A39D ; [.26F4.0020.0002.A39D] # YI SYLLABLE NRE +A39E ; [.26F5.0020.0002.A39E] # YI SYLLABLE NREP +A39F ; [.26F6.0020.0002.A39F] # YI SYLLABLE NRUT +A3A0 ; [.26F7.0020.0002.A3A0] # YI SYLLABLE NRUX +A3A1 ; [.26F8.0020.0002.A3A1] # YI SYLLABLE NRU +A3A2 ; [.26F9.0020.0002.A3A2] # YI SYLLABLE NRUP +A3A3 ; [.26FA.0020.0002.A3A3] # YI SYLLABLE NRURX +A3A4 ; [.26FB.0020.0002.A3A4] # YI SYLLABLE NRUR +A3A5 ; [.26FC.0020.0002.A3A5] # YI SYLLABLE NRYT +A3A6 ; [.26FD.0020.0002.A3A6] # YI SYLLABLE NRYX +A3A7 ; [.26FE.0020.0002.A3A7] # YI SYLLABLE NRY +A3A8 ; [.26FF.0020.0002.A3A8] # YI SYLLABLE NRYP +A3A9 ; [.2700.0020.0002.A3A9] # YI SYLLABLE NRYRX +A3AA ; [.2701.0020.0002.A3AA] # YI SYLLABLE NRYR +A3AB ; [.2702.0020.0002.A3AB] # YI SYLLABLE SHAT +A3AC ; [.2703.0020.0002.A3AC] # YI SYLLABLE SHAX +A3AD ; [.2704.0020.0002.A3AD] # YI SYLLABLE SHA +A3AE ; [.2705.0020.0002.A3AE] # YI SYLLABLE SHAP +A3AF ; [.2706.0020.0002.A3AF] # YI SYLLABLE SHUOX +A3B0 ; [.2707.0020.0002.A3B0] # YI SYLLABLE SHUO +A3B1 ; [.2708.0020.0002.A3B1] # YI SYLLABLE SHUOP +A3B2 ; [.2709.0020.0002.A3B2] # YI SYLLABLE SHOT +A3B3 ; [.270A.0020.0002.A3B3] # YI SYLLABLE SHOX +A3B4 ; [.270B.0020.0002.A3B4] # YI SYLLABLE SHO +A3B5 ; [.270C.0020.0002.A3B5] # YI SYLLABLE SHOP +A3B6 ; [.270D.0020.0002.A3B6] # YI SYLLABLE SHET +A3B7 ; [.270E.0020.0002.A3B7] # YI SYLLABLE SHEX +A3B8 ; [.270F.0020.0002.A3B8] # YI SYLLABLE SHE +A3B9 ; [.2710.0020.0002.A3B9] # YI SYLLABLE SHEP +A3BA ; [.2711.0020.0002.A3BA] # YI SYLLABLE SHUT +A3BB ; [.2712.0020.0002.A3BB] # YI SYLLABLE SHUX +A3BC ; [.2713.0020.0002.A3BC] # YI SYLLABLE SHU +A3BD ; [.2714.0020.0002.A3BD] # YI SYLLABLE SHUP +A3BE ; [.2715.0020.0002.A3BE] # YI SYLLABLE SHURX +A3BF ; [.2716.0020.0002.A3BF] # YI SYLLABLE SHUR +A3C0 ; [.2717.0020.0002.A3C0] # YI SYLLABLE SHYT +A3C1 ; [.2718.0020.0002.A3C1] # YI SYLLABLE SHYX +A3C2 ; [.2719.0020.0002.A3C2] # YI SYLLABLE SHY +A3C3 ; [.271A.0020.0002.A3C3] # YI SYLLABLE SHYP +A3C4 ; [.271B.0020.0002.A3C4] # YI SYLLABLE SHYRX +A3C5 ; [.271C.0020.0002.A3C5] # YI SYLLABLE SHYR +A3C6 ; [.271D.0020.0002.A3C6] # YI SYLLABLE RAT +A3C7 ; [.271E.0020.0002.A3C7] # YI SYLLABLE RAX +A3C8 ; [.271F.0020.0002.A3C8] # YI SYLLABLE RA +A3C9 ; [.2720.0020.0002.A3C9] # YI SYLLABLE RAP +A3CA ; [.2721.0020.0002.A3CA] # YI SYLLABLE RUOX +A3CB ; [.2722.0020.0002.A3CB] # YI SYLLABLE RUO +A3CC ; [.2723.0020.0002.A3CC] # YI SYLLABLE RUOP +A3CD ; [.2724.0020.0002.A3CD] # YI SYLLABLE ROT +A3CE ; [.2725.0020.0002.A3CE] # YI SYLLABLE ROX +A3CF ; [.2726.0020.0002.A3CF] # YI SYLLABLE RO +A3D0 ; [.2727.0020.0002.A3D0] # YI SYLLABLE ROP +A3D1 ; [.2728.0020.0002.A3D1] # YI SYLLABLE REX +A3D2 ; [.2729.0020.0002.A3D2] # YI SYLLABLE RE +A3D3 ; [.272A.0020.0002.A3D3] # YI SYLLABLE REP +A3D4 ; [.272B.0020.0002.A3D4] # YI SYLLABLE RUT +A3D5 ; [.272C.0020.0002.A3D5] # YI SYLLABLE RUX +A3D6 ; [.272D.0020.0002.A3D6] # YI SYLLABLE RU +A3D7 ; [.272E.0020.0002.A3D7] # YI SYLLABLE RUP +A3D8 ; [.272F.0020.0002.A3D8] # YI SYLLABLE RURX +A3D9 ; [.2730.0020.0002.A3D9] # YI SYLLABLE RUR +A3DA ; [.2731.0020.0002.A3DA] # YI SYLLABLE RYT +A3DB ; [.2732.0020.0002.A3DB] # YI SYLLABLE RYX +A3DC ; [.2733.0020.0002.A3DC] # YI SYLLABLE RY +A3DD ; [.2734.0020.0002.A3DD] # YI SYLLABLE RYP +A3DE ; [.2735.0020.0002.A3DE] # YI SYLLABLE RYRX +A3DF ; [.2736.0020.0002.A3DF] # YI SYLLABLE RYR +A3E0 ; [.2737.0020.0002.A3E0] # YI SYLLABLE JIT +A3E1 ; [.2738.0020.0002.A3E1] # YI SYLLABLE JIX +A3E2 ; [.2739.0020.0002.A3E2] # YI SYLLABLE JI +A3E3 ; [.273A.0020.0002.A3E3] # YI SYLLABLE JIP +A3E4 ; [.273B.0020.0002.A3E4] # YI SYLLABLE JIET +A3E5 ; [.273C.0020.0002.A3E5] # YI SYLLABLE JIEX +A3E6 ; [.273D.0020.0002.A3E6] # YI SYLLABLE JIE +A3E7 ; [.273E.0020.0002.A3E7] # YI SYLLABLE JIEP +A3E8 ; [.273F.0020.0002.A3E8] # YI SYLLABLE JUOT +A3E9 ; [.2740.0020.0002.A3E9] # YI SYLLABLE JUOX +A3EA ; [.2741.0020.0002.A3EA] # YI SYLLABLE JUO +A3EB ; [.2742.0020.0002.A3EB] # YI SYLLABLE JUOP +A3EC ; [.2743.0020.0002.A3EC] # YI SYLLABLE JOT +A3ED ; [.2744.0020.0002.A3ED] # YI SYLLABLE JOX +A3EE ; [.2745.0020.0002.A3EE] # YI SYLLABLE JO +A3EF ; [.2746.0020.0002.A3EF] # YI SYLLABLE JOP +A3F0 ; [.2747.0020.0002.A3F0] # YI SYLLABLE JUT +A3F1 ; [.2748.0020.0002.A3F1] # YI SYLLABLE JUX +A3F2 ; [.2749.0020.0002.A3F2] # YI SYLLABLE JU +A3F3 ; [.274A.0020.0002.A3F3] # YI SYLLABLE JUP +A3F4 ; [.274B.0020.0002.A3F4] # YI SYLLABLE JURX +A3F5 ; [.274C.0020.0002.A3F5] # YI SYLLABLE JUR +A3F6 ; [.274D.0020.0002.A3F6] # YI SYLLABLE JYT +A3F7 ; [.274E.0020.0002.A3F7] # YI SYLLABLE JYX +A3F8 ; [.274F.0020.0002.A3F8] # YI SYLLABLE JY +A3F9 ; [.2750.0020.0002.A3F9] # YI SYLLABLE JYP +A3FA ; [.2751.0020.0002.A3FA] # YI SYLLABLE JYRX +A3FB ; [.2752.0020.0002.A3FB] # YI SYLLABLE JYR +A3FC ; [.2753.0020.0002.A3FC] # YI SYLLABLE QIT +A3FD ; [.2754.0020.0002.A3FD] # YI SYLLABLE QIX +A3FE ; [.2755.0020.0002.A3FE] # YI SYLLABLE QI +A3FF ; [.2756.0020.0002.A3FF] # YI SYLLABLE QIP +A400 ; [.2757.0020.0002.A400] # YI SYLLABLE QIET +A401 ; [.2758.0020.0002.A401] # YI SYLLABLE QIEX +A402 ; [.2759.0020.0002.A402] # YI SYLLABLE QIE +A403 ; [.275A.0020.0002.A403] # YI SYLLABLE QIEP +A404 ; [.275B.0020.0002.A404] # YI SYLLABLE QUOT +A405 ; [.275C.0020.0002.A405] # YI SYLLABLE QUOX +A406 ; [.275D.0020.0002.A406] # YI SYLLABLE QUO +A407 ; [.275E.0020.0002.A407] # YI SYLLABLE QUOP +A408 ; [.275F.0020.0002.A408] # YI SYLLABLE QOT +A409 ; [.2760.0020.0002.A409] # YI SYLLABLE QOX +A40A ; [.2761.0020.0002.A40A] # YI SYLLABLE QO +A40B ; [.2762.0020.0002.A40B] # YI SYLLABLE QOP +A40C ; [.2763.0020.0002.A40C] # YI SYLLABLE QUT +A40D ; [.2764.0020.0002.A40D] # YI SYLLABLE QUX +A40E ; [.2765.0020.0002.A40E] # YI SYLLABLE QU +A40F ; [.2766.0020.0002.A40F] # YI SYLLABLE QUP +A410 ; [.2767.0020.0002.A410] # YI SYLLABLE QURX +A411 ; [.2768.0020.0002.A411] # YI SYLLABLE QUR +A412 ; [.2769.0020.0002.A412] # YI SYLLABLE QYT +A413 ; [.276A.0020.0002.A413] # YI SYLLABLE QYX +A414 ; [.276B.0020.0002.A414] # YI SYLLABLE QY +A415 ; [.276C.0020.0002.A415] # YI SYLLABLE QYP +A416 ; [.276D.0020.0002.A416] # YI SYLLABLE QYRX +A417 ; [.276E.0020.0002.A417] # YI SYLLABLE QYR +A418 ; [.276F.0020.0002.A418] # YI SYLLABLE JJIT +A419 ; [.2770.0020.0002.A419] # YI SYLLABLE JJIX +A41A ; [.2771.0020.0002.A41A] # YI SYLLABLE JJI +A41B ; [.2772.0020.0002.A41B] # YI SYLLABLE JJIP +A41C ; [.2773.0020.0002.A41C] # YI SYLLABLE JJIET +A41D ; [.2774.0020.0002.A41D] # YI SYLLABLE JJIEX +A41E ; [.2775.0020.0002.A41E] # YI SYLLABLE JJIE +A41F ; [.2776.0020.0002.A41F] # YI SYLLABLE JJIEP +A420 ; [.2777.0020.0002.A420] # YI SYLLABLE JJUOX +A421 ; [.2778.0020.0002.A421] # YI SYLLABLE JJUO +A422 ; [.2779.0020.0002.A422] # YI SYLLABLE JJUOP +A423 ; [.277A.0020.0002.A423] # YI SYLLABLE JJOT +A424 ; [.277B.0020.0002.A424] # YI SYLLABLE JJOX +A425 ; [.277C.0020.0002.A425] # YI SYLLABLE JJO +A426 ; [.277D.0020.0002.A426] # YI SYLLABLE JJOP +A427 ; [.277E.0020.0002.A427] # YI SYLLABLE JJUT +A428 ; [.277F.0020.0002.A428] # YI SYLLABLE JJUX +A429 ; [.2780.0020.0002.A429] # YI SYLLABLE JJU +A42A ; [.2781.0020.0002.A42A] # YI SYLLABLE JJUP +A42B ; [.2782.0020.0002.A42B] # YI SYLLABLE JJURX +A42C ; [.2783.0020.0002.A42C] # YI SYLLABLE JJUR +A42D ; [.2784.0020.0002.A42D] # YI SYLLABLE JJYT +A42E ; [.2785.0020.0002.A42E] # YI SYLLABLE JJYX +A42F ; [.2786.0020.0002.A42F] # YI SYLLABLE JJY +A430 ; [.2787.0020.0002.A430] # YI SYLLABLE JJYP +A431 ; [.2788.0020.0002.A431] # YI SYLLABLE NJIT +A432 ; [.2789.0020.0002.A432] # YI SYLLABLE NJIX +A433 ; [.278A.0020.0002.A433] # YI SYLLABLE NJI +A434 ; [.278B.0020.0002.A434] # YI SYLLABLE NJIP +A435 ; [.278C.0020.0002.A435] # YI SYLLABLE NJIET +A436 ; [.278D.0020.0002.A436] # YI SYLLABLE NJIEX +A437 ; [.278E.0020.0002.A437] # YI SYLLABLE NJIE +A438 ; [.278F.0020.0002.A438] # YI SYLLABLE NJIEP +A439 ; [.2790.0020.0002.A439] # YI SYLLABLE NJUOX +A43A ; [.2791.0020.0002.A43A] # YI SYLLABLE NJUO +A43B ; [.2792.0020.0002.A43B] # YI SYLLABLE NJOT +A43C ; [.2793.0020.0002.A43C] # YI SYLLABLE NJOX +A43D ; [.2794.0020.0002.A43D] # YI SYLLABLE NJO +A43E ; [.2795.0020.0002.A43E] # YI SYLLABLE NJOP +A43F ; [.2796.0020.0002.A43F] # YI SYLLABLE NJUX +A440 ; [.2797.0020.0002.A440] # YI SYLLABLE NJU +A441 ; [.2798.0020.0002.A441] # YI SYLLABLE NJUP +A442 ; [.2799.0020.0002.A442] # YI SYLLABLE NJURX +A443 ; [.279A.0020.0002.A443] # YI SYLLABLE NJUR +A444 ; [.279B.0020.0002.A444] # YI SYLLABLE NJYT +A445 ; [.279C.0020.0002.A445] # YI SYLLABLE NJYX +A446 ; [.279D.0020.0002.A446] # YI SYLLABLE NJY +A447 ; [.279E.0020.0002.A447] # YI SYLLABLE NJYP +A448 ; [.279F.0020.0002.A448] # YI SYLLABLE NJYRX +A449 ; [.27A0.0020.0002.A449] # YI SYLLABLE NJYR +A44A ; [.27A1.0020.0002.A44A] # YI SYLLABLE NYIT +A44B ; [.27A2.0020.0002.A44B] # YI SYLLABLE NYIX +A44C ; [.27A3.0020.0002.A44C] # YI SYLLABLE NYI +A44D ; [.27A4.0020.0002.A44D] # YI SYLLABLE NYIP +A44E ; [.27A5.0020.0002.A44E] # YI SYLLABLE NYIET +A44F ; [.27A6.0020.0002.A44F] # YI SYLLABLE NYIEX +A450 ; [.27A7.0020.0002.A450] # YI SYLLABLE NYIE +A451 ; [.27A8.0020.0002.A451] # YI SYLLABLE NYIEP +A452 ; [.27A9.0020.0002.A452] # YI SYLLABLE NYUOX +A453 ; [.27AA.0020.0002.A453] # YI SYLLABLE NYUO +A454 ; [.27AB.0020.0002.A454] # YI SYLLABLE NYUOP +A455 ; [.27AC.0020.0002.A455] # YI SYLLABLE NYOT +A456 ; [.27AD.0020.0002.A456] # YI SYLLABLE NYOX +A457 ; [.27AE.0020.0002.A457] # YI SYLLABLE NYO +A458 ; [.27AF.0020.0002.A458] # YI SYLLABLE NYOP +A459 ; [.27B0.0020.0002.A459] # YI SYLLABLE NYUT +A45A ; [.27B1.0020.0002.A45A] # YI SYLLABLE NYUX +A45B ; [.27B2.0020.0002.A45B] # YI SYLLABLE NYU +A45C ; [.27B3.0020.0002.A45C] # YI SYLLABLE NYUP +A45D ; [.27B4.0020.0002.A45D] # YI SYLLABLE XIT +A45E ; [.27B5.0020.0002.A45E] # YI SYLLABLE XIX +A45F ; [.27B6.0020.0002.A45F] # YI SYLLABLE XI +A460 ; [.27B7.0020.0002.A460] # YI SYLLABLE XIP +A461 ; [.27B8.0020.0002.A461] # YI SYLLABLE XIET +A462 ; [.27B9.0020.0002.A462] # YI SYLLABLE XIEX +A463 ; [.27BA.0020.0002.A463] # YI SYLLABLE XIE +A464 ; [.27BB.0020.0002.A464] # YI SYLLABLE XIEP +A465 ; [.27BC.0020.0002.A465] # YI SYLLABLE XUOX +A466 ; [.27BD.0020.0002.A466] # YI SYLLABLE XUO +A467 ; [.27BE.0020.0002.A467] # YI SYLLABLE XOT +A468 ; [.27BF.0020.0002.A468] # YI SYLLABLE XOX +A469 ; [.27C0.0020.0002.A469] # YI SYLLABLE XO +A46A ; [.27C1.0020.0002.A46A] # YI SYLLABLE XOP +A46B ; [.27C2.0020.0002.A46B] # YI SYLLABLE XYT +A46C ; [.27C3.0020.0002.A46C] # YI SYLLABLE XYX +A46D ; [.27C4.0020.0002.A46D] # YI SYLLABLE XY +A46E ; [.27C5.0020.0002.A46E] # YI SYLLABLE XYP +A46F ; [.27C6.0020.0002.A46F] # YI SYLLABLE XYRX +A470 ; [.27C7.0020.0002.A470] # YI SYLLABLE XYR +A471 ; [.27C8.0020.0002.A471] # YI SYLLABLE YIT +A472 ; [.27C9.0020.0002.A472] # YI SYLLABLE YIX +A473 ; [.27CA.0020.0002.A473] # YI SYLLABLE YI +A474 ; [.27CB.0020.0002.A474] # YI SYLLABLE YIP +A475 ; [.27CC.0020.0002.A475] # YI SYLLABLE YIET +A476 ; [.27CD.0020.0002.A476] # YI SYLLABLE YIEX +A477 ; [.27CE.0020.0002.A477] # YI SYLLABLE YIE +A478 ; [.27CF.0020.0002.A478] # YI SYLLABLE YIEP +A479 ; [.27D0.0020.0002.A479] # YI SYLLABLE YUOT +A47A ; [.27D1.0020.0002.A47A] # YI SYLLABLE YUOX +A47B ; [.27D2.0020.0002.A47B] # YI SYLLABLE YUO +A47C ; [.27D3.0020.0002.A47C] # YI SYLLABLE YUOP +A47D ; [.27D4.0020.0002.A47D] # YI SYLLABLE YOT +A47E ; [.27D5.0020.0002.A47E] # YI SYLLABLE YOX +A47F ; [.27D6.0020.0002.A47F] # YI SYLLABLE YO +A480 ; [.27D7.0020.0002.A480] # YI SYLLABLE YOP +A481 ; [.27D8.0020.0002.A481] # YI SYLLABLE YUT +A482 ; [.27D9.0020.0002.A482] # YI SYLLABLE YUX +A483 ; [.27DA.0020.0002.A483] # YI SYLLABLE YU +A484 ; [.27DB.0020.0002.A484] # YI SYLLABLE YUP +A485 ; [.27DC.0020.0002.A485] # YI SYLLABLE YURX +A486 ; [.27DD.0020.0002.A486] # YI SYLLABLE YUR +A487 ; [.27DE.0020.0002.A487] # YI SYLLABLE YYT +A488 ; [.27DF.0020.0002.A488] # YI SYLLABLE YYX +A489 ; [.27E0.0020.0002.A489] # YI SYLLABLE YY +A48A ; [.27E1.0020.0002.A48A] # YI SYLLABLE YYP +A48B ; [.27E2.0020.0002.A48B] # YI SYLLABLE YYRX +A48C ; [.27E3.0020.0002.A48C] # YI SYLLABLE YYR +10300 ; [.27E4.0020.0002.10300] # OLD ITALIC LETTER A +10301 ; [.27E5.0020.0002.10301] # OLD ITALIC LETTER BE +10302 ; [.27E6.0020.0002.10302] # OLD ITALIC LETTER KE +10303 ; [.27E7.0020.0002.10303] # OLD ITALIC LETTER DE +10304 ; [.27E8.0020.0002.10304] # OLD ITALIC LETTER E +10305 ; [.27E9.0020.0002.10305] # OLD ITALIC LETTER VE +10306 ; [.27EA.0020.0002.10306] # OLD ITALIC LETTER ZE +10307 ; [.27EB.0020.0002.10307] # OLD ITALIC LETTER HE +10308 ; [.27EC.0020.0002.10308] # OLD ITALIC LETTER THE +10309 ; [.27ED.0020.0002.10309] # OLD ITALIC LETTER I +1030A ; [.27EE.0020.0002.1030A] # OLD ITALIC LETTER KA +1030B ; [.27EF.0020.0002.1030B] # OLD ITALIC LETTER EL +1030C ; [.27F0.0020.0002.1030C] # OLD ITALIC LETTER EM +1030D ; [.27F1.0020.0002.1030D] # OLD ITALIC LETTER EN +1030E ; [.27F2.0020.0002.1030E] # OLD ITALIC LETTER ESH +1030F ; [.27F3.0020.0002.1030F] # OLD ITALIC LETTER O +10310 ; [.27F4.0020.0002.10310] # OLD ITALIC LETTER PE +10311 ; [.27F5.0020.0002.10311] # OLD ITALIC LETTER SHE +10312 ; [.27F6.0020.0002.10312] # OLD ITALIC LETTER KU +10313 ; [.27F7.0020.0002.10313] # OLD ITALIC LETTER ER +10314 ; [.27F8.0020.0002.10314] # OLD ITALIC LETTER ES +10315 ; [.27F9.0020.0002.10315] # OLD ITALIC LETTER TE +10316 ; [.27FA.0020.0002.10316] # OLD ITALIC LETTER U +10317 ; [.27FB.0020.0002.10317] # OLD ITALIC LETTER EKS +10318 ; [.27FC.0020.0002.10318] # OLD ITALIC LETTER PHE +10319 ; [.27FD.0020.0002.10319] # OLD ITALIC LETTER KHE +1031A ; [.27FE.0020.0002.1031A] # OLD ITALIC LETTER EF +1031B ; [.27FF.0020.0002.1031B] # OLD ITALIC LETTER ERS +1031C ; [.2800.0020.0002.1031C] # OLD ITALIC LETTER CHE +1031D ; [.2801.0020.0002.1031D] # OLD ITALIC LETTER II +1031E ; [.2802.0020.0002.1031E] # OLD ITALIC LETTER UU +10330 ; [.2803.0020.0002.10330] # GOTHIC LETTER AHSA +10331 ; [.2804.0020.0002.10331] # GOTHIC LETTER BAIRKAN +10332 ; [.2805.0020.0002.10332] # GOTHIC LETTER GIBA +10333 ; [.2806.0020.0002.10333] # GOTHIC LETTER DAGS +10334 ; [.2807.0020.0002.10334] # GOTHIC LETTER AIHVUS +10335 ; [.2808.0020.0002.10335] # GOTHIC LETTER QAIRTHRA +10336 ; [.2809.0020.0002.10336] # GOTHIC LETTER IUJA +10337 ; [.280A.0020.0002.10337] # GOTHIC LETTER HAGL +10338 ; [.280B.0020.0002.10338] # GOTHIC LETTER THIUTH +10339 ; [.280C.0020.0002.10339] # GOTHIC LETTER EIS +1033A ; [.280D.0020.0002.1033A] # GOTHIC LETTER KUSMA +1033B ; [.280E.0020.0002.1033B] # GOTHIC LETTER LAGUS +1033C ; [.280F.0020.0002.1033C] # GOTHIC LETTER MANNA +1033D ; [.2810.0020.0002.1033D] # GOTHIC LETTER NAUTHS +1033E ; [.2811.0020.0002.1033E] # GOTHIC LETTER JER +1033F ; [.2812.0020.0002.1033F] # GOTHIC LETTER URUS +10340 ; [.2813.0020.0002.10340] # GOTHIC LETTER PAIRTHRA +10341 ; [.2814.0020.0002.10341] # GOTHIC LETTER NINETY +10342 ; [.2815.0020.0002.10342] # GOTHIC LETTER RAIDA +10343 ; [.2816.0020.0002.10343] # GOTHIC LETTER SAUIL +10344 ; [.2817.0020.0002.10344] # GOTHIC LETTER TEIWS +10345 ; [.2818.0020.0002.10345] # GOTHIC LETTER WINJA +10346 ; [.2819.0020.0002.10346] # GOTHIC LETTER FAIHU +10347 ; [.281A.0020.0002.10347] # GOTHIC LETTER IGGWS +10348 ; [.281B.0020.0002.10348] # GOTHIC LETTER HWAIR +10349 ; [.281C.0020.0002.10349] # GOTHIC LETTER OTHAL +1034A ; [.281D.0020.0002.1034A] # GOTHIC LETTER NINE HUNDRED +10428 ; [.281E.0020.0002.10428] # DESERET SMALL LETTER LONG I +10400 ; [.281E.0020.0008.10400] # DESERET CAPITAL LETTER LONG I +10429 ; [.281F.0020.0002.10429] # DESERET SMALL LETTER LONG E +10401 ; [.281F.0020.0008.10401] # DESERET CAPITAL LETTER LONG E +1042A ; [.2820.0020.0002.1042A] # DESERET SMALL LETTER LONG A +10402 ; [.2820.0020.0008.10402] # DESERET CAPITAL LETTER LONG A +1042B ; [.2821.0020.0002.1042B] # DESERET SMALL LETTER LONG AH +10403 ; [.2821.0020.0008.10403] # DESERET CAPITAL LETTER LONG AH +1042C ; [.2822.0020.0002.1042C] # DESERET SMALL LETTER LONG O +10404 ; [.2822.0020.0008.10404] # DESERET CAPITAL LETTER LONG O +1042D ; [.2823.0020.0002.1042D] # DESERET SMALL LETTER LONG OO +10405 ; [.2823.0020.0008.10405] # DESERET CAPITAL LETTER LONG OO +1042E ; [.2824.0020.0002.1042E] # DESERET SMALL LETTER SHORT I +10406 ; [.2824.0020.0008.10406] # DESERET CAPITAL LETTER SHORT I +1042F ; [.2825.0020.0002.1042F] # DESERET SMALL LETTER SHORT E +10407 ; [.2825.0020.0008.10407] # DESERET CAPITAL LETTER SHORT E +10430 ; [.2826.0020.0002.10430] # DESERET SMALL LETTER SHORT A +10408 ; [.2826.0020.0008.10408] # DESERET CAPITAL LETTER SHORT A +10431 ; [.2827.0020.0002.10431] # DESERET SMALL LETTER SHORT AH +10409 ; [.2827.0020.0008.10409] # DESERET CAPITAL LETTER SHORT AH +10432 ; [.2828.0020.0002.10432] # DESERET SMALL LETTER SHORT O +1040A ; [.2828.0020.0008.1040A] # DESERET CAPITAL LETTER SHORT O +10433 ; [.2829.0020.0002.10433] # DESERET SMALL LETTER SHORT OO +1040B ; [.2829.0020.0008.1040B] # DESERET CAPITAL LETTER SHORT OO +10434 ; [.282A.0020.0002.10434] # DESERET SMALL LETTER AY +1040C ; [.282A.0020.0008.1040C] # DESERET CAPITAL LETTER AY +10435 ; [.282B.0020.0002.10435] # DESERET SMALL LETTER OW +1040D ; [.282B.0020.0008.1040D] # DESERET CAPITAL LETTER OW +10436 ; [.282C.0020.0002.10436] # DESERET SMALL LETTER WU +1040E ; [.282C.0020.0008.1040E] # DESERET CAPITAL LETTER WU +10437 ; [.282D.0020.0002.10437] # DESERET SMALL LETTER YEE +1040F ; [.282D.0020.0008.1040F] # DESERET CAPITAL LETTER YEE +10438 ; [.282E.0020.0002.10438] # DESERET SMALL LETTER H +10410 ; [.282E.0020.0008.10410] # DESERET CAPITAL LETTER H +10439 ; [.282F.0020.0002.10439] # DESERET SMALL LETTER PEE +10411 ; [.282F.0020.0008.10411] # DESERET CAPITAL LETTER PEE +1043A ; [.2830.0020.0002.1043A] # DESERET SMALL LETTER BEE +10412 ; [.2830.0020.0008.10412] # DESERET CAPITAL LETTER BEE +1043B ; [.2831.0020.0002.1043B] # DESERET SMALL LETTER TEE +10413 ; [.2831.0020.0008.10413] # DESERET CAPITAL LETTER TEE +1043C ; [.2832.0020.0002.1043C] # DESERET SMALL LETTER DEE +10414 ; [.2832.0020.0008.10414] # DESERET CAPITAL LETTER DEE +1043D ; [.2833.0020.0002.1043D] # DESERET SMALL LETTER CHEE +10415 ; [.2833.0020.0008.10415] # DESERET CAPITAL LETTER CHEE +1043E ; [.2834.0020.0002.1043E] # DESERET SMALL LETTER JEE +10416 ; [.2834.0020.0008.10416] # DESERET CAPITAL LETTER JEE +1043F ; [.2835.0020.0002.1043F] # DESERET SMALL LETTER KAY +10417 ; [.2835.0020.0008.10417] # DESERET CAPITAL LETTER KAY +10440 ; [.2836.0020.0002.10440] # DESERET SMALL LETTER GAY +10418 ; [.2836.0020.0008.10418] # DESERET CAPITAL LETTER GAY +10441 ; [.2837.0020.0002.10441] # DESERET SMALL LETTER EF +10419 ; [.2837.0020.0008.10419] # DESERET CAPITAL LETTER EF +10442 ; [.2838.0020.0002.10442] # DESERET SMALL LETTER VEE +1041A ; [.2838.0020.0008.1041A] # DESERET CAPITAL LETTER VEE +10443 ; [.2839.0020.0002.10443] # DESERET SMALL LETTER ETH +1041B ; [.2839.0020.0008.1041B] # DESERET CAPITAL LETTER ETH +10444 ; [.283A.0020.0002.10444] # DESERET SMALL LETTER THEE +1041C ; [.283A.0020.0008.1041C] # DESERET CAPITAL LETTER THEE +10445 ; [.283B.0020.0002.10445] # DESERET SMALL LETTER ES +1041D ; [.283B.0020.0008.1041D] # DESERET CAPITAL LETTER ES +10446 ; [.283C.0020.0002.10446] # DESERET SMALL LETTER ZEE +1041E ; [.283C.0020.0008.1041E] # DESERET CAPITAL LETTER ZEE +10447 ; [.283D.0020.0002.10447] # DESERET SMALL LETTER ESH +1041F ; [.283D.0020.0008.1041F] # DESERET CAPITAL LETTER ESH +10448 ; [.283E.0020.0002.10448] # DESERET SMALL LETTER ZHEE +10420 ; [.283E.0020.0008.10420] # DESERET CAPITAL LETTER ZHEE +10449 ; [.283F.0020.0002.10449] # DESERET SMALL LETTER ER +10421 ; [.283F.0020.0008.10421] # DESERET CAPITAL LETTER ER +1044A ; [.2840.0020.0002.1044A] # DESERET SMALL LETTER EL +10422 ; [.2840.0020.0008.10422] # DESERET CAPITAL LETTER EL +1044B ; [.2841.0020.0002.1044B] # DESERET SMALL LETTER EM +10423 ; [.2841.0020.0008.10423] # DESERET CAPITAL LETTER EM +1044C ; [.2842.0020.0002.1044C] # DESERET SMALL LETTER EN +10424 ; [.2842.0020.0008.10424] # DESERET CAPITAL LETTER EN +1044D ; [.2843.0020.0002.1044D] # DESERET SMALL LETTER ENG +10425 ; [.2843.0020.0008.10425] # DESERET CAPITAL LETTER ENG +1044E ; [.2844.0020.0002.1044E] # DESERET SMALL LETTER OI +10426 ; [.2844.0020.0008.10426] # DESERET CAPITAL LETTER OI +1044F ; [.2845.0020.0002.1044F] # DESERET SMALL LETTER EW +10427 ; [.2845.0020.0008.10427] # DESERET CAPITAL LETTER EW +10450 ; [.2846.0020.0002.10450] # SHAVIAN LETTER PEEP +10451 ; [.2847.0020.0002.10451] # SHAVIAN LETTER TOT +10452 ; [.2848.0020.0002.10452] # SHAVIAN LETTER KICK +10453 ; [.2849.0020.0002.10453] # SHAVIAN LETTER FEE +10454 ; [.284A.0020.0002.10454] # SHAVIAN LETTER THIGH +10455 ; [.284B.0020.0002.10455] # SHAVIAN LETTER SO +10456 ; [.284C.0020.0002.10456] # SHAVIAN LETTER SURE +10457 ; [.284D.0020.0002.10457] # SHAVIAN LETTER CHURCH +10458 ; [.284E.0020.0002.10458] # SHAVIAN LETTER YEA +10459 ; [.284F.0020.0002.10459] # SHAVIAN LETTER HUNG +1045A ; [.2850.0020.0002.1045A] # SHAVIAN LETTER BIB +1045B ; [.2851.0020.0002.1045B] # SHAVIAN LETTER DEAD +1045C ; [.2852.0020.0002.1045C] # SHAVIAN LETTER GAG +1045D ; [.2853.0020.0002.1045D] # SHAVIAN LETTER VOW +1045E ; [.2854.0020.0002.1045E] # SHAVIAN LETTER THEY +1045F ; [.2855.0020.0002.1045F] # SHAVIAN LETTER ZOO +10460 ; [.2856.0020.0002.10460] # SHAVIAN LETTER MEASURE +10461 ; [.2857.0020.0002.10461] # SHAVIAN LETTER JUDGE +10462 ; [.2858.0020.0002.10462] # SHAVIAN LETTER WOE +10463 ; [.2859.0020.0002.10463] # SHAVIAN LETTER HA-HA +10464 ; [.285A.0020.0002.10464] # SHAVIAN LETTER LOLL +10465 ; [.285B.0020.0002.10465] # SHAVIAN LETTER MIME +10466 ; [.285C.0020.0002.10466] # SHAVIAN LETTER IF +10467 ; [.285D.0020.0002.10467] # SHAVIAN LETTER EGG +10468 ; [.285E.0020.0002.10468] # SHAVIAN LETTER ASH +10469 ; [.285F.0020.0002.10469] # SHAVIAN LETTER ADO +1046A ; [.2860.0020.0002.1046A] # SHAVIAN LETTER ON +1046B ; [.2861.0020.0002.1046B] # SHAVIAN LETTER WOOL +1046C ; [.2862.0020.0002.1046C] # SHAVIAN LETTER OUT +1046D ; [.2863.0020.0002.1046D] # SHAVIAN LETTER AH +1046E ; [.2864.0020.0002.1046E] # SHAVIAN LETTER ROAR +1046F ; [.2865.0020.0002.1046F] # SHAVIAN LETTER NUN +10470 ; [.2866.0020.0002.10470] # SHAVIAN LETTER EAT +10471 ; [.2867.0020.0002.10471] # SHAVIAN LETTER AGE +10472 ; [.2868.0020.0002.10472] # SHAVIAN LETTER ICE +10473 ; [.2869.0020.0002.10473] # SHAVIAN LETTER UP +10474 ; [.286A.0020.0002.10474] # SHAVIAN LETTER OAK +10475 ; [.286B.0020.0002.10475] # SHAVIAN LETTER OOZE +10476 ; [.286C.0020.0002.10476] # SHAVIAN LETTER OIL +10477 ; [.286D.0020.0002.10477] # SHAVIAN LETTER AWE +10478 ; [.286E.0020.0002.10478] # SHAVIAN LETTER ARE +10479 ; [.286F.0020.0002.10479] # SHAVIAN LETTER OR +1047A ; [.2870.0020.0002.1047A] # SHAVIAN LETTER AIR +1047B ; [.2871.0020.0002.1047B] # SHAVIAN LETTER ERR +1047C ; [.2872.0020.0002.1047C] # SHAVIAN LETTER ARRAY +1047D ; [.2873.0020.0002.1047D] # SHAVIAN LETTER EAR +1047E ; [.2874.0020.0002.1047E] # SHAVIAN LETTER IAN +1047F ; [.2875.0020.0002.1047F] # SHAVIAN LETTER YEW +10480 ; [.2876.0020.0002.10480] # OSMANYA LETTER ALEF +10481 ; [.2877.0020.0002.10481] # OSMANYA LETTER BA +10482 ; [.2878.0020.0002.10482] # OSMANYA LETTER TA +10483 ; [.2879.0020.0002.10483] # OSMANYA LETTER JA +10484 ; [.287A.0020.0002.10484] # OSMANYA LETTER XA +10485 ; [.287B.0020.0002.10485] # OSMANYA LETTER KHA +10486 ; [.287C.0020.0002.10486] # OSMANYA LETTER DEEL +10487 ; [.287D.0020.0002.10487] # OSMANYA LETTER RA +10488 ; [.287E.0020.0002.10488] # OSMANYA LETTER SA +10489 ; [.287F.0020.0002.10489] # OSMANYA LETTER SHIIN +1048A ; [.2880.0020.0002.1048A] # OSMANYA LETTER DHA +1048B ; [.2881.0020.0002.1048B] # OSMANYA LETTER CAYN +1048C ; [.2882.0020.0002.1048C] # OSMANYA LETTER GA +1048D ; [.2883.0020.0002.1048D] # OSMANYA LETTER FA +1048E ; [.2884.0020.0002.1048E] # OSMANYA LETTER QAAF +1048F ; [.2885.0020.0002.1048F] # OSMANYA LETTER KAAF +10490 ; [.2886.0020.0002.10490] # OSMANYA LETTER LAAN +10491 ; [.2887.0020.0002.10491] # OSMANYA LETTER MIIN +10492 ; [.2888.0020.0002.10492] # OSMANYA LETTER NUUN +10493 ; [.2889.0020.0002.10493] # OSMANYA LETTER WAW +10494 ; [.288A.0020.0002.10494] # OSMANYA LETTER HA +10495 ; [.288B.0020.0002.10495] # OSMANYA LETTER YA +10496 ; [.288C.0020.0002.10496] # OSMANYA LETTER A +10497 ; [.288D.0020.0002.10497] # OSMANYA LETTER E +10498 ; [.288E.0020.0002.10498] # OSMANYA LETTER I +10499 ; [.288F.0020.0002.10499] # OSMANYA LETTER O +1049A ; [.2890.0020.0002.1049A] # OSMANYA LETTER U +1049B ; [.2891.0020.0002.1049B] # OSMANYA LETTER AA +1049C ; [.2892.0020.0002.1049C] # OSMANYA LETTER EE +1049D ; [.2893.0020.0002.1049D] # OSMANYA LETTER OO +10000 ; [.2894.0020.0002.10000] # LINEAR B SYLLABLE B008 A +10001 ; [.2895.0020.0002.10001] # LINEAR B SYLLABLE B038 E +10002 ; [.2896.0020.0002.10002] # LINEAR B SYLLABLE B028 I +10003 ; [.2897.0020.0002.10003] # LINEAR B SYLLABLE B061 O +10004 ; [.2898.0020.0002.10004] # LINEAR B SYLLABLE B010 U +10005 ; [.2899.0020.0002.10005] # LINEAR B SYLLABLE B001 DA +10006 ; [.289A.0020.0002.10006] # LINEAR B SYLLABLE B045 DE +10007 ; [.289B.0020.0002.10007] # LINEAR B SYLLABLE B007 DI +10008 ; [.289C.0020.0002.10008] # LINEAR B SYLLABLE B014 DO +10009 ; [.289D.0020.0002.10009] # LINEAR B SYLLABLE B051 DU +1000A ; [.289E.0020.0002.1000A] # LINEAR B SYLLABLE B057 JA +1000B ; [.289F.0020.0002.1000B] # LINEAR B SYLLABLE B046 JE +1000D ; [.28A0.0020.0002.1000D] # LINEAR B SYLLABLE B036 JO +1000E ; [.28A1.0020.0002.1000E] # LINEAR B SYLLABLE B065 JU +1000F ; [.28A2.0020.0002.1000F] # LINEAR B SYLLABLE B077 KA +10010 ; [.28A3.0020.0002.10010] # LINEAR B SYLLABLE B044 KE +10011 ; [.28A4.0020.0002.10011] # LINEAR B SYLLABLE B067 KI +10012 ; [.28A5.0020.0002.10012] # LINEAR B SYLLABLE B070 KO +10013 ; [.28A6.0020.0002.10013] # LINEAR B SYLLABLE B081 KU +10014 ; [.28A7.0020.0002.10014] # LINEAR B SYLLABLE B080 MA +10015 ; [.28A8.0020.0002.10015] # LINEAR B SYLLABLE B013 ME +10016 ; [.28A9.0020.0002.10016] # LINEAR B SYLLABLE B073 MI +10017 ; [.28AA.0020.0002.10017] # LINEAR B SYLLABLE B015 MO +10018 ; [.28AB.0020.0002.10018] # LINEAR B SYLLABLE B023 MU +10019 ; [.28AC.0020.0002.10019] # LINEAR B SYLLABLE B006 NA +1001A ; [.28AD.0020.0002.1001A] # LINEAR B SYLLABLE B024 NE +1001B ; [.28AE.0020.0002.1001B] # LINEAR B SYLLABLE B030 NI +1001C ; [.28AF.0020.0002.1001C] # LINEAR B SYLLABLE B052 NO +1001D ; [.28B0.0020.0002.1001D] # LINEAR B SYLLABLE B055 NU +1001E ; [.28B1.0020.0002.1001E] # LINEAR B SYLLABLE B003 PA +1001F ; [.28B2.0020.0002.1001F] # LINEAR B SYLLABLE B072 PE +10020 ; [.28B3.0020.0002.10020] # LINEAR B SYLLABLE B039 PI +10021 ; [.28B4.0020.0002.10021] # LINEAR B SYLLABLE B011 PO +10022 ; [.28B5.0020.0002.10022] # LINEAR B SYLLABLE B050 PU +10023 ; [.28B6.0020.0002.10023] # LINEAR B SYLLABLE B016 QA +10024 ; [.28B7.0020.0002.10024] # LINEAR B SYLLABLE B078 QE +10025 ; [.28B8.0020.0002.10025] # LINEAR B SYLLABLE B021 QI +10026 ; [.28B9.0020.0002.10026] # LINEAR B SYLLABLE B032 QO +10028 ; [.28BA.0020.0002.10028] # LINEAR B SYLLABLE B060 RA +10029 ; [.28BB.0020.0002.10029] # LINEAR B SYLLABLE B027 RE +1002A ; [.28BC.0020.0002.1002A] # LINEAR B SYLLABLE B053 RI +1002B ; [.28BD.0020.0002.1002B] # LINEAR B SYLLABLE B002 RO +1002C ; [.28BE.0020.0002.1002C] # LINEAR B SYLLABLE B026 RU +1002D ; [.28BF.0020.0002.1002D] # LINEAR B SYLLABLE B031 SA +1002E ; [.28C0.0020.0002.1002E] # LINEAR B SYLLABLE B009 SE +1002F ; [.28C1.0020.0002.1002F] # LINEAR B SYLLABLE B041 SI +10030 ; [.28C2.0020.0002.10030] # LINEAR B SYLLABLE B012 SO +10031 ; [.28C3.0020.0002.10031] # LINEAR B SYLLABLE B058 SU +10032 ; [.28C4.0020.0002.10032] # LINEAR B SYLLABLE B059 TA +10033 ; [.28C5.0020.0002.10033] # LINEAR B SYLLABLE B004 TE +10034 ; [.28C6.0020.0002.10034] # LINEAR B SYLLABLE B037 TI +10035 ; [.28C7.0020.0002.10035] # LINEAR B SYLLABLE B005 TO +10036 ; [.28C8.0020.0002.10036] # LINEAR B SYLLABLE B069 TU +10037 ; [.28C9.0020.0002.10037] # LINEAR B SYLLABLE B054 WA +10038 ; [.28CA.0020.0002.10038] # LINEAR B SYLLABLE B075 WE +10039 ; [.28CB.0020.0002.10039] # LINEAR B SYLLABLE B040 WI +1003A ; [.28CC.0020.0002.1003A] # LINEAR B SYLLABLE B042 WO +1003C ; [.28CD.0020.0002.1003C] # LINEAR B SYLLABLE B017 ZA +1003D ; [.28CE.0020.0002.1003D] # LINEAR B SYLLABLE B074 ZE +1003F ; [.28CF.0020.0002.1003F] # LINEAR B SYLLABLE B020 ZO +10040 ; [.28D0.0020.0002.10040] # LINEAR B SYLLABLE B025 A2 +10041 ; [.28D1.0020.0002.10041] # LINEAR B SYLLABLE B043 A3 +10042 ; [.28D2.0020.0002.10042] # LINEAR B SYLLABLE B085 AU +10043 ; [.28D3.0020.0002.10043] # LINEAR B SYLLABLE B071 DWE +10044 ; [.28D4.0020.0002.10044] # LINEAR B SYLLABLE B090 DWO +10045 ; [.28D5.0020.0002.10045] # LINEAR B SYLLABLE B048 NWA +10046 ; [.28D6.0020.0002.10046] # LINEAR B SYLLABLE B029 PU2 +10047 ; [.28D7.0020.0002.10047] # LINEAR B SYLLABLE B062 PTE +10048 ; [.28D8.0020.0002.10048] # LINEAR B SYLLABLE B076 RA2 +10049 ; [.28D9.0020.0002.10049] # LINEAR B SYLLABLE B033 RA3 +1004A ; [.28DA.0020.0002.1004A] # LINEAR B SYLLABLE B068 RO2 +1004B ; [.28DB.0020.0002.1004B] # LINEAR B SYLLABLE B066 TA2 +1004C ; [.28DC.0020.0002.1004C] # LINEAR B SYLLABLE B087 TWE +1004D ; [.28DD.0020.0002.1004D] # LINEAR B SYLLABLE B091 TWO +10050 ; [.28DE.0020.0002.10050] # LINEAR B SYMBOL B018 +10051 ; [.28DF.0020.0002.10051] # LINEAR B SYMBOL B019 +10052 ; [.28E0.0020.0002.10052] # LINEAR B SYMBOL B022 +10053 ; [.28E1.0020.0002.10053] # LINEAR B SYMBOL B034 +10054 ; [.28E2.0020.0002.10054] # LINEAR B SYMBOL B047 +10055 ; [.28E3.0020.0002.10055] # LINEAR B SYMBOL B049 +10056 ; [.28E4.0020.0002.10056] # LINEAR B SYMBOL B056 +10057 ; [.28E5.0020.0002.10057] # LINEAR B SYMBOL B063 +10058 ; [.28E6.0020.0002.10058] # LINEAR B SYMBOL B064 +10059 ; [.28E7.0020.0002.10059] # LINEAR B SYMBOL B079 +1005A ; [.28E8.0020.0002.1005A] # LINEAR B SYMBOL B082 +1005B ; [.28E9.0020.0002.1005B] # LINEAR B SYMBOL B083 +1005C ; [.28EA.0020.0002.1005C] # LINEAR B SYMBOL B086 +1005D ; [.28EB.0020.0002.1005D] # LINEAR B SYMBOL B089 +10080 ; [.28EC.0020.0002.10080] # LINEAR B IDEOGRAM B100 MAN +10081 ; [.28ED.0020.0002.10081] # LINEAR B IDEOGRAM B102 WOMAN +10082 ; [.28EE.0020.0002.10082] # LINEAR B IDEOGRAM B104 DEER +10083 ; [.28EF.0020.0002.10083] # LINEAR B IDEOGRAM B105 EQUID +10084 ; [.28F0.0020.0002.10084] # LINEAR B IDEOGRAM B105F MARE +10085 ; [.28F1.0020.0002.10085] # LINEAR B IDEOGRAM B105M STALLION +10086 ; [.28F2.0020.0002.10086] # LINEAR B IDEOGRAM B106F EWE +10087 ; [.28F3.0020.0002.10087] # LINEAR B IDEOGRAM B106M RAM +10088 ; [.28F4.0020.0002.10088] # LINEAR B IDEOGRAM B107F SHE-GOAT +10089 ; [.28F5.0020.0002.10089] # LINEAR B IDEOGRAM B107M HE-GOAT +1008A ; [.28F6.0020.0002.1008A] # LINEAR B IDEOGRAM B108F SOW +1008B ; [.28F7.0020.0002.1008B] # LINEAR B IDEOGRAM B108M BOAR +1008C ; [.28F8.0020.0002.1008C] # LINEAR B IDEOGRAM B109F COW +1008D ; [.28F9.0020.0002.1008D] # LINEAR B IDEOGRAM B109M BULL +1008E ; [.28FA.0020.0002.1008E] # LINEAR B IDEOGRAM B120 WHEAT +1008F ; [.28FB.0020.0002.1008F] # LINEAR B IDEOGRAM B121 BARLEY +10090 ; [.28FC.0020.0002.10090] # LINEAR B IDEOGRAM B122 OLIVE +10091 ; [.28FD.0020.0002.10091] # LINEAR B IDEOGRAM B123 SPICE +10092 ; [.28FE.0020.0002.10092] # LINEAR B IDEOGRAM B125 CYPERUS +10093 ; [.28FF.0020.0002.10093] # LINEAR B MONOGRAM B127 KAPO +10094 ; [.2900.0020.0002.10094] # LINEAR B MONOGRAM B128 KANAKO +10095 ; [.2901.0020.0002.10095] # LINEAR B IDEOGRAM B130 OIL +10096 ; [.2902.0020.0002.10096] # LINEAR B IDEOGRAM B131 WINE +10097 ; [.2903.0020.0002.10097] # LINEAR B IDEOGRAM B132 +10098 ; [.2904.0020.0002.10098] # LINEAR B MONOGRAM B133 AREPA +10099 ; [.2905.0020.0002.10099] # LINEAR B MONOGRAM B135 MERI +1009A ; [.2906.0020.0002.1009A] # LINEAR B IDEOGRAM B140 BRONZE +1009B ; [.2907.0020.0002.1009B] # LINEAR B IDEOGRAM B141 GOLD +1009C ; [.2908.0020.0002.1009C] # LINEAR B IDEOGRAM B142 +1009D ; [.2909.0020.0002.1009D] # LINEAR B IDEOGRAM B145 WOOL +1009E ; [.290A.0020.0002.1009E] # LINEAR B IDEOGRAM B146 +1009F ; [.290B.0020.0002.1009F] # LINEAR B IDEOGRAM B150 +100A0 ; [.290C.0020.0002.100A0] # LINEAR B IDEOGRAM B151 HORN +100A1 ; [.290D.0020.0002.100A1] # LINEAR B IDEOGRAM B152 +100A2 ; [.290E.0020.0002.100A2] # LINEAR B IDEOGRAM B153 +100A3 ; [.290F.0020.0002.100A3] # LINEAR B IDEOGRAM B154 +100A4 ; [.2910.0020.0002.100A4] # LINEAR B MONOGRAM B156 TURO2 +100A5 ; [.2911.0020.0002.100A5] # LINEAR B IDEOGRAM B157 +100A6 ; [.2912.0020.0002.100A6] # LINEAR B IDEOGRAM B158 +100A7 ; [.2913.0020.0002.100A7] # LINEAR B IDEOGRAM B159 CLOTH +100A8 ; [.2914.0020.0002.100A8] # LINEAR B IDEOGRAM B160 +100A9 ; [.2915.0020.0002.100A9] # LINEAR B IDEOGRAM B161 +100AA ; [.2916.0020.0002.100AA] # LINEAR B IDEOGRAM B162 GARMENT +100AB ; [.2917.0020.0002.100AB] # LINEAR B IDEOGRAM B163 ARMOUR +100AC ; [.2918.0020.0002.100AC] # LINEAR B IDEOGRAM B164 +100AD ; [.2919.0020.0002.100AD] # LINEAR B IDEOGRAM B165 +100AE ; [.291A.0020.0002.100AE] # LINEAR B IDEOGRAM B166 +100AF ; [.291B.0020.0002.100AF] # LINEAR B IDEOGRAM B167 +100B0 ; [.291C.0020.0002.100B0] # LINEAR B IDEOGRAM B168 +100B1 ; [.291D.0020.0002.100B1] # LINEAR B IDEOGRAM B169 +100B2 ; [.291E.0020.0002.100B2] # LINEAR B IDEOGRAM B170 +100B3 ; [.291F.0020.0002.100B3] # LINEAR B IDEOGRAM B171 +100B4 ; [.2920.0020.0002.100B4] # LINEAR B IDEOGRAM B172 +100B5 ; [.2921.0020.0002.100B5] # LINEAR B IDEOGRAM B173 MONTH +100B6 ; [.2922.0020.0002.100B6] # LINEAR B IDEOGRAM B174 +100B7 ; [.2923.0020.0002.100B7] # LINEAR B IDEOGRAM B176 TREE +100B8 ; [.2924.0020.0002.100B8] # LINEAR B IDEOGRAM B177 +100B9 ; [.2925.0020.0002.100B9] # LINEAR B IDEOGRAM B178 +100BA ; [.2926.0020.0002.100BA] # LINEAR B IDEOGRAM B179 +100BB ; [.2927.0020.0002.100BB] # LINEAR B IDEOGRAM B180 +100BC ; [.2928.0020.0002.100BC] # LINEAR B IDEOGRAM B181 +100BD ; [.2929.0020.0002.100BD] # LINEAR B IDEOGRAM B182 +100BE ; [.292A.0020.0002.100BE] # LINEAR B IDEOGRAM B183 +100BF ; [.292B.0020.0002.100BF] # LINEAR B IDEOGRAM B184 +100C0 ; [.292C.0020.0002.100C0] # LINEAR B IDEOGRAM B185 +100C1 ; [.292D.0020.0002.100C1] # LINEAR B IDEOGRAM B189 +100C2 ; [.292E.0020.0002.100C2] # LINEAR B IDEOGRAM B190 +100C3 ; [.292F.0020.0002.100C3] # LINEAR B IDEOGRAM B191 HELMET +100C4 ; [.2930.0020.0002.100C4] # LINEAR B IDEOGRAM B220 FOOTSTOOL +100C5 ; [.2931.0020.0002.100C5] # LINEAR B IDEOGRAM B225 BATHTUB +100C6 ; [.2932.0020.0002.100C6] # LINEAR B IDEOGRAM B230 SPEAR +100C7 ; [.2933.0020.0002.100C7] # LINEAR B IDEOGRAM B231 ARROW +100C8 ; [.2934.0020.0002.100C8] # LINEAR B IDEOGRAM B232 +100C9 ; [.2935.0020.0002.100C9] # LINEAR B IDEOGRAM B233 SWORD +100CA ; [.2936.0020.0002.100CA] # LINEAR B IDEOGRAM B234 +100CB ; [.2937.0020.0002.100CB] # LINEAR B IDEOGRAM B236 +100CC ; [.2938.0020.0002.100CC] # LINEAR B IDEOGRAM B240 WHEELED CHARIOT +100CD ; [.2939.0020.0002.100CD] # LINEAR B IDEOGRAM B241 CHARIOT +100CE ; [.293A.0020.0002.100CE] # LINEAR B IDEOGRAM B242 CHARIOT FRAME +100CF ; [.293B.0020.0002.100CF] # LINEAR B IDEOGRAM B243 WHEEL +100D0 ; [.293C.0020.0002.100D0] # LINEAR B IDEOGRAM B245 +100D1 ; [.293D.0020.0002.100D1] # LINEAR B IDEOGRAM B246 +100D2 ; [.293E.0020.0002.100D2] # LINEAR B MONOGRAM B247 DIPTE +100D3 ; [.293F.0020.0002.100D3] # LINEAR B IDEOGRAM B248 +100D4 ; [.2940.0020.0002.100D4] # LINEAR B IDEOGRAM B249 +100D5 ; [.2941.0020.0002.100D5] # LINEAR B IDEOGRAM B251 +100D6 ; [.2942.0020.0002.100D6] # LINEAR B IDEOGRAM B252 +100D7 ; [.2943.0020.0002.100D7] # LINEAR B IDEOGRAM B253 +100D8 ; [.2944.0020.0002.100D8] # LINEAR B IDEOGRAM B254 DART +100D9 ; [.2945.0020.0002.100D9] # LINEAR B IDEOGRAM B255 +100DA ; [.2946.0020.0002.100DA] # LINEAR B IDEOGRAM B256 +100DB ; [.2947.0020.0002.100DB] # LINEAR B IDEOGRAM B257 +100DC ; [.2948.0020.0002.100DC] # LINEAR B IDEOGRAM B258 +100DD ; [.2949.0020.0002.100DD] # LINEAR B IDEOGRAM B259 +100DE ; [.294A.0020.0002.100DE] # LINEAR B IDEOGRAM VESSEL B155 +100DF ; [.294B.0020.0002.100DF] # LINEAR B IDEOGRAM VESSEL B200 +100E0 ; [.294C.0020.0002.100E0] # LINEAR B IDEOGRAM VESSEL B201 +100E1 ; [.294D.0020.0002.100E1] # LINEAR B IDEOGRAM VESSEL B202 +100E2 ; [.294E.0020.0002.100E2] # LINEAR B IDEOGRAM VESSEL B203 +100E3 ; [.294F.0020.0002.100E3] # LINEAR B IDEOGRAM VESSEL B204 +100E4 ; [.2950.0020.0002.100E4] # LINEAR B IDEOGRAM VESSEL B205 +100E5 ; [.2951.0020.0002.100E5] # LINEAR B IDEOGRAM VESSEL B206 +100E6 ; [.2952.0020.0002.100E6] # LINEAR B IDEOGRAM VESSEL B207 +100E7 ; [.2953.0020.0002.100E7] # LINEAR B IDEOGRAM VESSEL B208 +100E8 ; [.2954.0020.0002.100E8] # LINEAR B IDEOGRAM VESSEL B209 +100E9 ; [.2955.0020.0002.100E9] # LINEAR B IDEOGRAM VESSEL B210 +100EA ; [.2956.0020.0002.100EA] # LINEAR B IDEOGRAM VESSEL B211 +100EB ; [.2957.0020.0002.100EB] # LINEAR B IDEOGRAM VESSEL B212 +100EC ; [.2958.0020.0002.100EC] # LINEAR B IDEOGRAM VESSEL B213 +100ED ; [.2959.0020.0002.100ED] # LINEAR B IDEOGRAM VESSEL B214 +100EE ; [.295A.0020.0002.100EE] # LINEAR B IDEOGRAM VESSEL B215 +100EF ; [.295B.0020.0002.100EF] # LINEAR B IDEOGRAM VESSEL B216 +100F0 ; [.295C.0020.0002.100F0] # LINEAR B IDEOGRAM VESSEL B217 +100F1 ; [.295D.0020.0002.100F1] # LINEAR B IDEOGRAM VESSEL B218 +100F2 ; [.295E.0020.0002.100F2] # LINEAR B IDEOGRAM VESSEL B219 +100F3 ; [.295F.0020.0002.100F3] # LINEAR B IDEOGRAM VESSEL B221 +100F4 ; [.2960.0020.0002.100F4] # LINEAR B IDEOGRAM VESSEL B222 +100F5 ; [.2961.0020.0002.100F5] # LINEAR B IDEOGRAM VESSEL B226 +100F6 ; [.2962.0020.0002.100F6] # LINEAR B IDEOGRAM VESSEL B227 +100F7 ; [.2963.0020.0002.100F7] # LINEAR B IDEOGRAM VESSEL B228 +100F8 ; [.2964.0020.0002.100F8] # LINEAR B IDEOGRAM VESSEL B229 +100F9 ; [.2965.0020.0002.100F9] # LINEAR B IDEOGRAM VESSEL B250 +100FA ; [.2966.0020.0002.100FA] # LINEAR B IDEOGRAM VESSEL B305 +10800 ; [.2967.0020.0002.10800] # CYPRIOT SYLLABLE A +10801 ; [.2968.0020.0002.10801] # CYPRIOT SYLLABLE E +10802 ; [.2969.0020.0002.10802] # CYPRIOT SYLLABLE I +10803 ; [.296A.0020.0002.10803] # CYPRIOT SYLLABLE O +10804 ; [.296B.0020.0002.10804] # CYPRIOT SYLLABLE U +10805 ; [.296C.0020.0002.10805] # CYPRIOT SYLLABLE JA +10808 ; [.296D.0020.0002.10808] # CYPRIOT SYLLABLE JO +1080A ; [.296E.0020.0002.1080A] # CYPRIOT SYLLABLE KA +1080B ; [.296F.0020.0002.1080B] # CYPRIOT SYLLABLE KE +1080C ; [.2970.0020.0002.1080C] # CYPRIOT SYLLABLE KI +1080D ; [.2971.0020.0002.1080D] # CYPRIOT SYLLABLE KO +1080E ; [.2972.0020.0002.1080E] # CYPRIOT SYLLABLE KU +1080F ; [.2973.0020.0002.1080F] # CYPRIOT SYLLABLE LA +10810 ; [.2974.0020.0002.10810] # CYPRIOT SYLLABLE LE +10811 ; [.2975.0020.0002.10811] # CYPRIOT SYLLABLE LI +10812 ; [.2976.0020.0002.10812] # CYPRIOT SYLLABLE LO +10813 ; [.2977.0020.0002.10813] # CYPRIOT SYLLABLE LU +10814 ; [.2978.0020.0002.10814] # CYPRIOT SYLLABLE MA +10815 ; [.2979.0020.0002.10815] # CYPRIOT SYLLABLE ME +10816 ; [.297A.0020.0002.10816] # CYPRIOT SYLLABLE MI +10817 ; [.297B.0020.0002.10817] # CYPRIOT SYLLABLE MO +10818 ; [.297C.0020.0002.10818] # CYPRIOT SYLLABLE MU +10819 ; [.297D.0020.0002.10819] # CYPRIOT SYLLABLE NA +1081A ; [.297E.0020.0002.1081A] # CYPRIOT SYLLABLE NE +1081B ; [.297F.0020.0002.1081B] # CYPRIOT SYLLABLE NI +1081C ; [.2980.0020.0002.1081C] # CYPRIOT SYLLABLE NO +1081D ; [.2981.0020.0002.1081D] # CYPRIOT SYLLABLE NU +1081E ; [.2982.0020.0002.1081E] # CYPRIOT SYLLABLE PA +1081F ; [.2983.0020.0002.1081F] # CYPRIOT SYLLABLE PE +10820 ; [.2984.0020.0002.10820] # CYPRIOT SYLLABLE PI +10821 ; [.2985.0020.0002.10821] # CYPRIOT SYLLABLE PO +10822 ; [.2986.0020.0002.10822] # CYPRIOT SYLLABLE PU +10823 ; [.2987.0020.0002.10823] # CYPRIOT SYLLABLE RA +10824 ; [.2988.0020.0002.10824] # CYPRIOT SYLLABLE RE +10825 ; [.2989.0020.0002.10825] # CYPRIOT SYLLABLE RI +10826 ; [.298A.0020.0002.10826] # CYPRIOT SYLLABLE RO +10827 ; [.298B.0020.0002.10827] # CYPRIOT SYLLABLE RU +10828 ; [.298C.0020.0002.10828] # CYPRIOT SYLLABLE SA +10829 ; [.298D.0020.0002.10829] # CYPRIOT SYLLABLE SE +1082A ; [.298E.0020.0002.1082A] # CYPRIOT SYLLABLE SI +1082B ; [.298F.0020.0002.1082B] # CYPRIOT SYLLABLE SO +1082C ; [.2990.0020.0002.1082C] # CYPRIOT SYLLABLE SU +1082D ; [.2991.0020.0002.1082D] # CYPRIOT SYLLABLE TA +1082E ; [.2992.0020.0002.1082E] # CYPRIOT SYLLABLE TE +1082F ; [.2993.0020.0002.1082F] # CYPRIOT SYLLABLE TI +10830 ; [.2994.0020.0002.10830] # CYPRIOT SYLLABLE TO +10831 ; [.2995.0020.0002.10831] # CYPRIOT SYLLABLE TU +10832 ; [.2996.0020.0002.10832] # CYPRIOT SYLLABLE WA +10833 ; [.2997.0020.0002.10833] # CYPRIOT SYLLABLE WE +10834 ; [.2998.0020.0002.10834] # CYPRIOT SYLLABLE WI +10835 ; [.2999.0020.0002.10835] # CYPRIOT SYLLABLE WO +10837 ; [.299A.0020.0002.10837] # CYPRIOT SYLLABLE XA +10838 ; [.299B.0020.0002.10838] # CYPRIOT SYLLABLE XE +1083C ; [.299C.0020.0002.1083C] # CYPRIOT SYLLABLE ZA +1083F ; [.299D.0020.0002.1083F] # CYPRIOT SYLLABLE ZO +10380 ; [.299E.0020.0002.10380] # UGARITIC LETTER ALPA +10381 ; [.299F.0020.0002.10381] # UGARITIC LETTER BETA +10382 ; [.29A0.0020.0002.10382] # UGARITIC LETTER GAMLA +10383 ; [.29A1.0020.0002.10383] # UGARITIC LETTER KHA +10384 ; [.29A2.0020.0002.10384] # UGARITIC LETTER DELTA +10385 ; [.29A3.0020.0002.10385] # UGARITIC LETTER HO +10386 ; [.29A4.0020.0002.10386] # UGARITIC LETTER WO +10387 ; [.29A5.0020.0002.10387] # UGARITIC LETTER ZETA +10388 ; [.29A6.0020.0002.10388] # UGARITIC LETTER HOTA +10389 ; [.29A7.0020.0002.10389] # UGARITIC LETTER TET +1038A ; [.29A8.0020.0002.1038A] # UGARITIC LETTER YOD +1038B ; [.29A9.0020.0002.1038B] # UGARITIC LETTER KAF +1038C ; [.29AA.0020.0002.1038C] # UGARITIC LETTER SHIN +1038D ; [.29AB.0020.0002.1038D] # UGARITIC LETTER LAMDA +1038E ; [.29AC.0020.0002.1038E] # UGARITIC LETTER MEM +1038F ; [.29AD.0020.0002.1038F] # UGARITIC LETTER DHAL +10390 ; [.29AE.0020.0002.10390] # UGARITIC LETTER NUN +10391 ; [.29AF.0020.0002.10391] # UGARITIC LETTER ZU +10392 ; [.29B0.0020.0002.10392] # UGARITIC LETTER SAMKA +10393 ; [.29B1.0020.0002.10393] # UGARITIC LETTER AIN +10394 ; [.29B2.0020.0002.10394] # UGARITIC LETTER PU +10395 ; [.29B3.0020.0002.10395] # UGARITIC LETTER SADE +10396 ; [.29B4.0020.0002.10396] # UGARITIC LETTER QOPA +10397 ; [.29B5.0020.0002.10397] # UGARITIC LETTER RASHA +10398 ; [.29B6.0020.0002.10398] # UGARITIC LETTER THANNA +10399 ; [.29B7.0020.0002.10399] # UGARITIC LETTER GHAIN +1039A ; [.29B8.0020.0002.1039A] # UGARITIC LETTER TO +1039B ; [.29B9.0020.0002.1039B] # UGARITIC LETTER I +1039C ; [.29BA.0020.0002.1039C] # UGARITIC LETTER U +1039D ; [.29BB.0020.0002.1039D] # UGARITIC LETTER SSU +103A0 ; [.29BC.0020.0002.103A0] # OLD PERSIAN SIGN A +103A1 ; [.29BD.0020.0002.103A1] # OLD PERSIAN SIGN I +103A2 ; [.29BE.0020.0002.103A2] # OLD PERSIAN SIGN U +103A3 ; [.29BF.0020.0002.103A3] # OLD PERSIAN SIGN KA +103A4 ; [.29C0.0020.0002.103A4] # OLD PERSIAN SIGN KU +103A5 ; [.29C1.0020.0002.103A5] # OLD PERSIAN SIGN GA +103A6 ; [.29C2.0020.0002.103A6] # OLD PERSIAN SIGN GU +103A7 ; [.29C3.0020.0002.103A7] # OLD PERSIAN SIGN XA +103A8 ; [.29C4.0020.0002.103A8] # OLD PERSIAN SIGN CA +103A9 ; [.29C5.0020.0002.103A9] # OLD PERSIAN SIGN JA +103AA ; [.29C6.0020.0002.103AA] # OLD PERSIAN SIGN JI +103AB ; [.29C7.0020.0002.103AB] # OLD PERSIAN SIGN TA +103AC ; [.29C8.0020.0002.103AC] # OLD PERSIAN SIGN TU +103AD ; [.29C9.0020.0002.103AD] # OLD PERSIAN SIGN DA +103AE ; [.29CA.0020.0002.103AE] # OLD PERSIAN SIGN DI +103AF ; [.29CB.0020.0002.103AF] # OLD PERSIAN SIGN DU +103B0 ; [.29CC.0020.0002.103B0] # OLD PERSIAN SIGN THA +103B1 ; [.29CD.0020.0002.103B1] # OLD PERSIAN SIGN PA +103B2 ; [.29CE.0020.0002.103B2] # OLD PERSIAN SIGN BA +103B3 ; [.29CF.0020.0002.103B3] # OLD PERSIAN SIGN FA +103B4 ; [.29D0.0020.0002.103B4] # OLD PERSIAN SIGN NA +103B5 ; [.29D1.0020.0002.103B5] # OLD PERSIAN SIGN NU +103B6 ; [.29D2.0020.0002.103B6] # OLD PERSIAN SIGN MA +103B7 ; [.29D3.0020.0002.103B7] # OLD PERSIAN SIGN MI +103B8 ; [.29D4.0020.0002.103B8] # OLD PERSIAN SIGN MU +103B9 ; [.29D5.0020.0002.103B9] # OLD PERSIAN SIGN YA +103BA ; [.29D6.0020.0002.103BA] # OLD PERSIAN SIGN VA +103BB ; [.29D7.0020.0002.103BB] # OLD PERSIAN SIGN VI +103BC ; [.29D8.0020.0002.103BC] # OLD PERSIAN SIGN RA +103BD ; [.29D9.0020.0002.103BD] # OLD PERSIAN SIGN RU +103BE ; [.29DA.0020.0002.103BE] # OLD PERSIAN SIGN LA +103BF ; [.29DB.0020.0002.103BF] # OLD PERSIAN SIGN SA +103C0 ; [.29DC.0020.0002.103C0] # OLD PERSIAN SIGN ZA +103C1 ; [.29DD.0020.0002.103C1] # OLD PERSIAN SIGN SHA +103C2 ; [.29DE.0020.0002.103C2] # OLD PERSIAN SIGN SSA +103C3 ; [.29DF.0020.0002.103C3] # OLD PERSIAN SIGN HA +103C8 ; [.29E0.0020.0002.103C8] # OLD PERSIAN SIGN AURAMAZDAA +103C9 ; [.29E1.0020.0002.103C9] # OLD PERSIAN SIGN AURAMAZDAA-2 +103CA ; [.29E2.0020.0002.103CA] # OLD PERSIAN SIGN AURAMAZDAAHA +103CB ; [.29E3.0020.0002.103CB] # OLD PERSIAN SIGN XSHAAYATHIYA +103CC ; [.29E4.0020.0002.103CC] # OLD PERSIAN SIGN DAHYAAUSH +103CD ; [.29E5.0020.0002.103CD] # OLD PERSIAN SIGN DAHYAAUSH-2 +103CE ; [.29E6.0020.0002.103CE] # OLD PERSIAN SIGN BAGA +103CF ; [.29E7.0020.0002.103CF] # OLD PERSIAN SIGN BUUMISH +12000 ; [.29E8.0020.0002.12000] # CUNEIFORM SIGN A +12001 ; [.29E9.0020.0002.12001] # CUNEIFORM SIGN A TIMES A +12002 ; [.29EA.0020.0002.12002] # CUNEIFORM SIGN A TIMES BAD +12003 ; [.29EB.0020.0002.12003] # CUNEIFORM SIGN A TIMES GAN2 TENU +12004 ; [.29EC.0020.0002.12004] # CUNEIFORM SIGN A TIMES HA +12005 ; [.29ED.0020.0002.12005] # CUNEIFORM SIGN A TIMES IGI +12006 ; [.29EE.0020.0002.12006] # CUNEIFORM SIGN A TIMES LAGAR GUNU +12007 ; [.29EF.0020.0002.12007] # CUNEIFORM SIGN A TIMES MUSH +12008 ; [.29F0.0020.0002.12008] # CUNEIFORM SIGN A TIMES SAG +12009 ; [.29F1.0020.0002.12009] # CUNEIFORM SIGN A2 +1200A ; [.29F2.0020.0002.1200A] # CUNEIFORM SIGN AB +1200B ; [.29F3.0020.0002.1200B] # CUNEIFORM SIGN AB TIMES ASH2 +1200C ; [.29F4.0020.0002.1200C] # CUNEIFORM SIGN AB TIMES DUN3 GUNU +1200D ; [.29F5.0020.0002.1200D] # CUNEIFORM SIGN AB TIMES GAL +1200E ; [.29F6.0020.0002.1200E] # CUNEIFORM SIGN AB TIMES GAN2 TENU +1200F ; [.29F7.0020.0002.1200F] # CUNEIFORM SIGN AB TIMES HA +12010 ; [.29F8.0020.0002.12010] # CUNEIFORM SIGN AB TIMES IGI GUNU +12011 ; [.29F9.0020.0002.12011] # CUNEIFORM SIGN AB TIMES IMIN +12012 ; [.29FA.0020.0002.12012] # CUNEIFORM SIGN AB TIMES LAGAB +12013 ; [.29FB.0020.0002.12013] # CUNEIFORM SIGN AB TIMES SHESH +12014 ; [.29FC.0020.0002.12014] # CUNEIFORM SIGN AB TIMES U PLUS U PLUS U +12015 ; [.29FD.0020.0002.12015] # CUNEIFORM SIGN AB GUNU +12016 ; [.29FE.0020.0002.12016] # CUNEIFORM SIGN AB2 +12017 ; [.29FF.0020.0002.12017] # CUNEIFORM SIGN AB2 TIMES BALAG +12018 ; [.2A00.0020.0002.12018] # CUNEIFORM SIGN AB2 TIMES GAN2 TENU +12019 ; [.2A01.0020.0002.12019] # CUNEIFORM SIGN AB2 TIMES ME PLUS EN +1201A ; [.2A02.0020.0002.1201A] # CUNEIFORM SIGN AB2 TIMES SHA3 +1201B ; [.2A03.0020.0002.1201B] # CUNEIFORM SIGN AB2 TIMES TAK4 +1201C ; [.2A04.0020.0002.1201C] # CUNEIFORM SIGN AD +1201D ; [.2A05.0020.0002.1201D] # CUNEIFORM SIGN AK +1201E ; [.2A06.0020.0002.1201E] # CUNEIFORM SIGN AK TIMES ERIN2 +1201F ; [.2A07.0020.0002.1201F] # CUNEIFORM SIGN AK TIMES SHITA PLUS GISH +12020 ; [.2A08.0020.0002.12020] # CUNEIFORM SIGN AL +12021 ; [.2A09.0020.0002.12021] # CUNEIFORM SIGN AL TIMES AL +12022 ; [.2A0A.0020.0002.12022] # CUNEIFORM SIGN AL TIMES DIM2 +12023 ; [.2A0B.0020.0002.12023] # CUNEIFORM SIGN AL TIMES GISH +12024 ; [.2A0C.0020.0002.12024] # CUNEIFORM SIGN AL TIMES HA +12025 ; [.2A0D.0020.0002.12025] # CUNEIFORM SIGN AL TIMES KAD3 +12026 ; [.2A0E.0020.0002.12026] # CUNEIFORM SIGN AL TIMES KI +12027 ; [.2A0F.0020.0002.12027] # CUNEIFORM SIGN AL TIMES SHE +12028 ; [.2A10.0020.0002.12028] # CUNEIFORM SIGN AL TIMES USH +12029 ; [.2A11.0020.0002.12029] # CUNEIFORM SIGN ALAN +1202A ; [.2A12.0020.0002.1202A] # CUNEIFORM SIGN ALEPH +1202B ; [.2A13.0020.0002.1202B] # CUNEIFORM SIGN AMAR +1202C ; [.2A14.0020.0002.1202C] # CUNEIFORM SIGN AMAR TIMES SHE +1202D ; [.2A15.0020.0002.1202D] # CUNEIFORM SIGN AN +1202E ; [.2A16.0020.0002.1202E] # CUNEIFORM SIGN AN OVER AN +1202F ; [.2A17.0020.0002.1202F] # CUNEIFORM SIGN AN THREE TIMES +12030 ; [.2A18.0020.0002.12030] # CUNEIFORM SIGN AN PLUS NAGA OPPOSING AN PLUS NAGA +12031 ; [.2A19.0020.0002.12031] # CUNEIFORM SIGN AN PLUS NAGA SQUARED +12032 ; [.2A1A.0020.0002.12032] # CUNEIFORM SIGN ANSHE +12033 ; [.2A1B.0020.0002.12033] # CUNEIFORM SIGN APIN +12034 ; [.2A1C.0020.0002.12034] # CUNEIFORM SIGN ARAD +12035 ; [.2A1D.0020.0002.12035] # CUNEIFORM SIGN ARAD TIMES KUR +12036 ; [.2A1E.0020.0002.12036] # CUNEIFORM SIGN ARKAB +12037 ; [.2A1F.0020.0002.12037] # CUNEIFORM SIGN ASAL2 +12038 ; [.2A20.0020.0002.12038] # CUNEIFORM SIGN ASH +12039 ; [.2A21.0020.0002.12039] # CUNEIFORM SIGN ASH ZIDA TENU +1203A ; [.2A22.0020.0002.1203A] # CUNEIFORM SIGN ASH KABA TENU +1203B ; [.2A23.0020.0002.1203B] # CUNEIFORM SIGN ASH OVER ASH TUG2 OVER TUG2 TUG2 OVER TUG2 PAP +1203C ; [.2A24.0020.0002.1203C] # CUNEIFORM SIGN ASH OVER ASH OVER ASH +1203D ; [.2A25.0020.0002.1203D] # CUNEIFORM SIGN ASH OVER ASH OVER ASH CROSSING ASH OVER ASH OVER ASH +1203E ; [.2A26.0020.0002.1203E] # CUNEIFORM SIGN ASH2 +1203F ; [.2A27.0020.0002.1203F] # CUNEIFORM SIGN ASHGAB +12040 ; [.2A28.0020.0002.12040] # CUNEIFORM SIGN BA +12041 ; [.2A29.0020.0002.12041] # CUNEIFORM SIGN BAD +12042 ; [.2A2A.0020.0002.12042] # CUNEIFORM SIGN BAG3 +12043 ; [.2A2B.0020.0002.12043] # CUNEIFORM SIGN BAHAR2 +12044 ; [.2A2C.0020.0002.12044] # CUNEIFORM SIGN BAL +12045 ; [.2A2D.0020.0002.12045] # CUNEIFORM SIGN BAL OVER BAL +12046 ; [.2A2E.0020.0002.12046] # CUNEIFORM SIGN BALAG +12047 ; [.2A2F.0020.0002.12047] # CUNEIFORM SIGN BAR +12048 ; [.2A30.0020.0002.12048] # CUNEIFORM SIGN BARA2 +12049 ; [.2A31.0020.0002.12049] # CUNEIFORM SIGN BI +1204A ; [.2A32.0020.0002.1204A] # CUNEIFORM SIGN BI TIMES A +1204B ; [.2A33.0020.0002.1204B] # CUNEIFORM SIGN BI TIMES GAR +1204C ; [.2A34.0020.0002.1204C] # CUNEIFORM SIGN BI TIMES IGI GUNU +1204D ; [.2A35.0020.0002.1204D] # CUNEIFORM SIGN BU +1204E ; [.2A36.0020.0002.1204E] # CUNEIFORM SIGN BU OVER BU AB +1204F ; [.2A37.0020.0002.1204F] # CUNEIFORM SIGN BU OVER BU UN +12050 ; [.2A38.0020.0002.12050] # CUNEIFORM SIGN BU CROSSING BU +12051 ; [.2A39.0020.0002.12051] # CUNEIFORM SIGN BULUG +12052 ; [.2A3A.0020.0002.12052] # CUNEIFORM SIGN BULUG OVER BULUG +12053 ; [.2A3B.0020.0002.12053] # CUNEIFORM SIGN BUR +12054 ; [.2A3C.0020.0002.12054] # CUNEIFORM SIGN BUR2 +12055 ; [.2A3D.0020.0002.12055] # CUNEIFORM SIGN DA +12056 ; [.2A3E.0020.0002.12056] # CUNEIFORM SIGN DAG +12057 ; [.2A3F.0020.0002.12057] # CUNEIFORM SIGN DAG KISIM5 TIMES A PLUS MASH +12058 ; [.2A40.0020.0002.12058] # CUNEIFORM SIGN DAG KISIM5 TIMES AMAR +12059 ; [.2A41.0020.0002.12059] # CUNEIFORM SIGN DAG KISIM5 TIMES BALAG +1205A ; [.2A42.0020.0002.1205A] # CUNEIFORM SIGN DAG KISIM5 TIMES BI +1205B ; [.2A43.0020.0002.1205B] # CUNEIFORM SIGN DAG KISIM5 TIMES GA +1205C ; [.2A44.0020.0002.1205C] # CUNEIFORM SIGN DAG KISIM5 TIMES GA PLUS MASH +1205D ; [.2A45.0020.0002.1205D] # CUNEIFORM SIGN DAG KISIM5 TIMES GI +1205E ; [.2A46.0020.0002.1205E] # CUNEIFORM SIGN DAG KISIM5 TIMES GIR2 +1205F ; [.2A47.0020.0002.1205F] # CUNEIFORM SIGN DAG KISIM5 TIMES GUD +12060 ; [.2A48.0020.0002.12060] # CUNEIFORM SIGN DAG KISIM5 TIMES HA +12061 ; [.2A49.0020.0002.12061] # CUNEIFORM SIGN DAG KISIM5 TIMES IR +12062 ; [.2A4A.0020.0002.12062] # CUNEIFORM SIGN DAG KISIM5 TIMES IR PLUS LU +12063 ; [.2A4B.0020.0002.12063] # CUNEIFORM SIGN DAG KISIM5 TIMES KAK +12064 ; [.2A4C.0020.0002.12064] # CUNEIFORM SIGN DAG KISIM5 TIMES LA +12065 ; [.2A4D.0020.0002.12065] # CUNEIFORM SIGN DAG KISIM5 TIMES LU +12066 ; [.2A4E.0020.0002.12066] # CUNEIFORM SIGN DAG KISIM5 TIMES LU PLUS MASH2 +12067 ; [.2A4F.0020.0002.12067] # CUNEIFORM SIGN DAG KISIM5 TIMES LUM +12068 ; [.2A50.0020.0002.12068] # CUNEIFORM SIGN DAG KISIM5 TIMES NE +12069 ; [.2A51.0020.0002.12069] # CUNEIFORM SIGN DAG KISIM5 TIMES PAP PLUS PAP +1206A ; [.2A52.0020.0002.1206A] # CUNEIFORM SIGN DAG KISIM5 TIMES SI +1206B ; [.2A53.0020.0002.1206B] # CUNEIFORM SIGN DAG KISIM5 TIMES TAK4 +1206C ; [.2A54.0020.0002.1206C] # CUNEIFORM SIGN DAG KISIM5 TIMES U2 PLUS GIR2 +1206D ; [.2A55.0020.0002.1206D] # CUNEIFORM SIGN DAG KISIM5 TIMES USH +1206E ; [.2A56.0020.0002.1206E] # CUNEIFORM SIGN DAM +1206F ; [.2A57.0020.0002.1206F] # CUNEIFORM SIGN DAR +12070 ; [.2A58.0020.0002.12070] # CUNEIFORM SIGN DARA3 +12071 ; [.2A59.0020.0002.12071] # CUNEIFORM SIGN DARA4 +12072 ; [.2A5A.0020.0002.12072] # CUNEIFORM SIGN DI +12073 ; [.2A5B.0020.0002.12073] # CUNEIFORM SIGN DIB +12074 ; [.2A5C.0020.0002.12074] # CUNEIFORM SIGN DIM +12075 ; [.2A5D.0020.0002.12075] # CUNEIFORM SIGN DIM TIMES SHE +12076 ; [.2A5E.0020.0002.12076] # CUNEIFORM SIGN DIM2 +12077 ; [.2A5F.0020.0002.12077] # CUNEIFORM SIGN DIN +12078 ; [.2A60.0020.0002.12078] # CUNEIFORM SIGN DIN KASKAL U GUNU DISH +12079 ; [.2A61.0020.0002.12079] # CUNEIFORM SIGN DISH +1207A ; [.2A62.0020.0002.1207A] # CUNEIFORM SIGN DU +1207B ; [.2A63.0020.0002.1207B] # CUNEIFORM SIGN DU OVER DU +1207C ; [.2A64.0020.0002.1207C] # CUNEIFORM SIGN DU GUNU +1207D ; [.2A65.0020.0002.1207D] # CUNEIFORM SIGN DU SHESHIG +1207E ; [.2A66.0020.0002.1207E] # CUNEIFORM SIGN DUB +1207F ; [.2A67.0020.0002.1207F] # CUNEIFORM SIGN DUB TIMES ESH2 +12080 ; [.2A68.0020.0002.12080] # CUNEIFORM SIGN DUB2 +12081 ; [.2A69.0020.0002.12081] # CUNEIFORM SIGN DUG +12082 ; [.2A6A.0020.0002.12082] # CUNEIFORM SIGN DUGUD +12083 ; [.2A6B.0020.0002.12083] # CUNEIFORM SIGN DUH +12084 ; [.2A6C.0020.0002.12084] # CUNEIFORM SIGN DUN +12085 ; [.2A6D.0020.0002.12085] # CUNEIFORM SIGN DUN3 +12086 ; [.2A6E.0020.0002.12086] # CUNEIFORM SIGN DUN3 GUNU +12087 ; [.2A6F.0020.0002.12087] # CUNEIFORM SIGN DUN3 GUNU GUNU +12088 ; [.2A70.0020.0002.12088] # CUNEIFORM SIGN DUN4 +12089 ; [.2A71.0020.0002.12089] # CUNEIFORM SIGN DUR2 +1208A ; [.2A72.0020.0002.1208A] # CUNEIFORM SIGN E +1208B ; [.2A73.0020.0002.1208B] # CUNEIFORM SIGN E TIMES PAP +1208C ; [.2A74.0020.0002.1208C] # CUNEIFORM SIGN E OVER E NUN OVER NUN +1208D ; [.2A75.0020.0002.1208D] # CUNEIFORM SIGN E2 +1208E ; [.2A76.0020.0002.1208E] # CUNEIFORM SIGN E2 TIMES A PLUS HA PLUS DA +1208F ; [.2A77.0020.0002.1208F] # CUNEIFORM SIGN E2 TIMES GAR +12090 ; [.2A78.0020.0002.12090] # CUNEIFORM SIGN E2 TIMES MI +12091 ; [.2A79.0020.0002.12091] # CUNEIFORM SIGN E2 TIMES SAL +12092 ; [.2A7A.0020.0002.12092] # CUNEIFORM SIGN E2 TIMES SHE +12093 ; [.2A7B.0020.0002.12093] # CUNEIFORM SIGN E2 TIMES U +12094 ; [.2A7C.0020.0002.12094] # CUNEIFORM SIGN EDIN +12095 ; [.2A7D.0020.0002.12095] # CUNEIFORM SIGN EGIR +12096 ; [.2A7E.0020.0002.12096] # CUNEIFORM SIGN EL +12097 ; [.2A7F.0020.0002.12097] # CUNEIFORM SIGN EN +12098 ; [.2A80.0020.0002.12098] # CUNEIFORM SIGN EN TIMES GAN2 +12099 ; [.2A81.0020.0002.12099] # CUNEIFORM SIGN EN TIMES GAN2 TENU +1209A ; [.2A82.0020.0002.1209A] # CUNEIFORM SIGN EN TIMES ME +1209B ; [.2A83.0020.0002.1209B] # CUNEIFORM SIGN EN CROSSING EN +1209C ; [.2A84.0020.0002.1209C] # CUNEIFORM SIGN EN OPPOSING EN +1209D ; [.2A85.0020.0002.1209D] # CUNEIFORM SIGN EN SQUARED +1209E ; [.2A86.0020.0002.1209E] # CUNEIFORM SIGN EREN +1209F ; [.2A87.0020.0002.1209F] # CUNEIFORM SIGN ERIN2 +120A0 ; [.2A88.0020.0002.120A0] # CUNEIFORM SIGN ESH2 +120A1 ; [.2A89.0020.0002.120A1] # CUNEIFORM SIGN EZEN +120A2 ; [.2A8A.0020.0002.120A2] # CUNEIFORM SIGN EZEN TIMES A +120A3 ; [.2A8B.0020.0002.120A3] # CUNEIFORM SIGN EZEN TIMES A PLUS LAL +120A4 ; [.2A8C.0020.0002.120A4] # CUNEIFORM SIGN EZEN TIMES A PLUS LAL TIMES LAL +120A5 ; [.2A8D.0020.0002.120A5] # CUNEIFORM SIGN EZEN TIMES AN +120A6 ; [.2A8E.0020.0002.120A6] # CUNEIFORM SIGN EZEN TIMES BAD +120A7 ; [.2A8F.0020.0002.120A7] # CUNEIFORM SIGN EZEN TIMES DUN3 GUNU +120A8 ; [.2A90.0020.0002.120A8] # CUNEIFORM SIGN EZEN TIMES DUN3 GUNU GUNU +120A9 ; [.2A91.0020.0002.120A9] # CUNEIFORM SIGN EZEN TIMES HA +120AA ; [.2A92.0020.0002.120AA] # CUNEIFORM SIGN EZEN TIMES HA GUNU +120AB ; [.2A93.0020.0002.120AB] # CUNEIFORM SIGN EZEN TIMES IGI GUNU +120AC ; [.2A94.0020.0002.120AC] # CUNEIFORM SIGN EZEN TIMES KASKAL +120AD ; [.2A95.0020.0002.120AD] # CUNEIFORM SIGN EZEN TIMES KASKAL SQUARED +120AE ; [.2A96.0020.0002.120AE] # CUNEIFORM SIGN EZEN TIMES KU3 +120AF ; [.2A97.0020.0002.120AF] # CUNEIFORM SIGN EZEN TIMES LA +120B0 ; [.2A98.0020.0002.120B0] # CUNEIFORM SIGN EZEN TIMES LAL TIMES LAL +120B1 ; [.2A99.0020.0002.120B1] # CUNEIFORM SIGN EZEN TIMES LI +120B2 ; [.2A9A.0020.0002.120B2] # CUNEIFORM SIGN EZEN TIMES LU +120B3 ; [.2A9B.0020.0002.120B3] # CUNEIFORM SIGN EZEN TIMES U2 +120B4 ; [.2A9C.0020.0002.120B4] # CUNEIFORM SIGN EZEN TIMES UD +120B5 ; [.2A9D.0020.0002.120B5] # CUNEIFORM SIGN GA +120B6 ; [.2A9E.0020.0002.120B6] # CUNEIFORM SIGN GA GUNU +120B7 ; [.2A9F.0020.0002.120B7] # CUNEIFORM SIGN GA2 +120B8 ; [.2AA0.0020.0002.120B8] # CUNEIFORM SIGN GA2 TIMES A PLUS DA PLUS HA +120B9 ; [.2AA1.0020.0002.120B9] # CUNEIFORM SIGN GA2 TIMES A PLUS HA +120BA ; [.2AA2.0020.0002.120BA] # CUNEIFORM SIGN GA2 TIMES A PLUS IGI +120BB ; [.2AA3.0020.0002.120BB] # CUNEIFORM SIGN GA2 TIMES AB2 TENU PLUS TAB +120BC ; [.2AA4.0020.0002.120BC] # CUNEIFORM SIGN GA2 TIMES AN +120BD ; [.2AA5.0020.0002.120BD] # CUNEIFORM SIGN GA2 TIMES ASH +120BE ; [.2AA6.0020.0002.120BE] # CUNEIFORM SIGN GA2 TIMES ASH2 PLUS GAL +120BF ; [.2AA7.0020.0002.120BF] # CUNEIFORM SIGN GA2 TIMES BAD +120C0 ; [.2AA8.0020.0002.120C0] # CUNEIFORM SIGN GA2 TIMES BAR PLUS RA +120C1 ; [.2AA9.0020.0002.120C1] # CUNEIFORM SIGN GA2 TIMES BUR +120C2 ; [.2AAA.0020.0002.120C2] # CUNEIFORM SIGN GA2 TIMES BUR PLUS RA +120C3 ; [.2AAB.0020.0002.120C3] # CUNEIFORM SIGN GA2 TIMES DA +120C4 ; [.2AAC.0020.0002.120C4] # CUNEIFORM SIGN GA2 TIMES DI +120C5 ; [.2AAD.0020.0002.120C5] # CUNEIFORM SIGN GA2 TIMES DIM TIMES SHE +120C6 ; [.2AAE.0020.0002.120C6] # CUNEIFORM SIGN GA2 TIMES DUB +120C7 ; [.2AAF.0020.0002.120C7] # CUNEIFORM SIGN GA2 TIMES EL +120C8 ; [.2AB0.0020.0002.120C8] # CUNEIFORM SIGN GA2 TIMES EL PLUS LA +120C9 ; [.2AB1.0020.0002.120C9] # CUNEIFORM SIGN GA2 TIMES EN +120CA ; [.2AB2.0020.0002.120CA] # CUNEIFORM SIGN GA2 TIMES EN TIMES GAN2 TENU +120CB ; [.2AB3.0020.0002.120CB] # CUNEIFORM SIGN GA2 TIMES GAN2 TENU +120CC ; [.2AB4.0020.0002.120CC] # CUNEIFORM SIGN GA2 TIMES GAR +120CD ; [.2AB5.0020.0002.120CD] # CUNEIFORM SIGN GA2 TIMES GI +120CE ; [.2AB6.0020.0002.120CE] # CUNEIFORM SIGN GA2 TIMES GI4 +120CF ; [.2AB7.0020.0002.120CF] # CUNEIFORM SIGN GA2 TIMES GI4 PLUS A +120D0 ; [.2AB8.0020.0002.120D0] # CUNEIFORM SIGN GA2 TIMES GIR2 PLUS SU +120D1 ; [.2AB9.0020.0002.120D1] # CUNEIFORM SIGN GA2 TIMES HA PLUS LU PLUS ESH2 +120D2 ; [.2ABA.0020.0002.120D2] # CUNEIFORM SIGN GA2 TIMES HAL +120D3 ; [.2ABB.0020.0002.120D3] # CUNEIFORM SIGN GA2 TIMES HAL PLUS LA +120D4 ; [.2ABC.0020.0002.120D4] # CUNEIFORM SIGN GA2 TIMES HI PLUS LI +120D5 ; [.2ABD.0020.0002.120D5] # CUNEIFORM SIGN GA2 TIMES HUB2 +120D6 ; [.2ABE.0020.0002.120D6] # CUNEIFORM SIGN GA2 TIMES IGI GUNU +120D7 ; [.2ABF.0020.0002.120D7] # CUNEIFORM SIGN GA2 TIMES ISH PLUS HU PLUS ASH +120D8 ; [.2AC0.0020.0002.120D8] # CUNEIFORM SIGN GA2 TIMES KAK +120D9 ; [.2AC1.0020.0002.120D9] # CUNEIFORM SIGN GA2 TIMES KASKAL +120DA ; [.2AC2.0020.0002.120DA] # CUNEIFORM SIGN GA2 TIMES KID +120DB ; [.2AC3.0020.0002.120DB] # CUNEIFORM SIGN GA2 TIMES KID PLUS LAL +120DC ; [.2AC4.0020.0002.120DC] # CUNEIFORM SIGN GA2 TIMES KU3 PLUS AN +120DD ; [.2AC5.0020.0002.120DD] # CUNEIFORM SIGN GA2 TIMES LA +120DE ; [.2AC6.0020.0002.120DE] # CUNEIFORM SIGN GA2 TIMES ME PLUS EN +120DF ; [.2AC7.0020.0002.120DF] # CUNEIFORM SIGN GA2 TIMES MI +120E0 ; [.2AC8.0020.0002.120E0] # CUNEIFORM SIGN GA2 TIMES NUN +120E1 ; [.2AC9.0020.0002.120E1] # CUNEIFORM SIGN GA2 TIMES NUN OVER NUN +120E2 ; [.2ACA.0020.0002.120E2] # CUNEIFORM SIGN GA2 TIMES PA +120E3 ; [.2ACB.0020.0002.120E3] # CUNEIFORM SIGN GA2 TIMES SAL +120E4 ; [.2ACC.0020.0002.120E4] # CUNEIFORM SIGN GA2 TIMES SAR +120E5 ; [.2ACD.0020.0002.120E5] # CUNEIFORM SIGN GA2 TIMES SHE +120E6 ; [.2ACE.0020.0002.120E6] # CUNEIFORM SIGN GA2 TIMES SHE PLUS TUR +120E7 ; [.2ACF.0020.0002.120E7] # CUNEIFORM SIGN GA2 TIMES SHID +120E8 ; [.2AD0.0020.0002.120E8] # CUNEIFORM SIGN GA2 TIMES SUM +120E9 ; [.2AD1.0020.0002.120E9] # CUNEIFORM SIGN GA2 TIMES TAK4 +120EA ; [.2AD2.0020.0002.120EA] # CUNEIFORM SIGN GA2 TIMES U +120EB ; [.2AD3.0020.0002.120EB] # CUNEIFORM SIGN GA2 TIMES UD +120EC ; [.2AD4.0020.0002.120EC] # CUNEIFORM SIGN GA2 TIMES UD PLUS DU +120ED ; [.2AD5.0020.0002.120ED] # CUNEIFORM SIGN GA2 OVER GA2 +120EE ; [.2AD6.0020.0002.120EE] # CUNEIFORM SIGN GABA +120EF ; [.2AD7.0020.0002.120EF] # CUNEIFORM SIGN GABA CROSSING GABA +120F0 ; [.2AD8.0020.0002.120F0] # CUNEIFORM SIGN GAD +120F1 ; [.2AD9.0020.0002.120F1] # CUNEIFORM SIGN GAD OVER GAD GAR OVER GAR +120F2 ; [.2ADA.0020.0002.120F2] # CUNEIFORM SIGN GAL +120F3 ; [.2ADB.0020.0002.120F3] # CUNEIFORM SIGN GAL GAD OVER GAD GAR OVER GAR +120F4 ; [.2ADC.0020.0002.120F4] # CUNEIFORM SIGN GALAM +120F5 ; [.2ADD.0020.0002.120F5] # CUNEIFORM SIGN GAM +120F6 ; [.2ADE.0020.0002.120F6] # CUNEIFORM SIGN GAN +120F7 ; [.2ADF.0020.0002.120F7] # CUNEIFORM SIGN GAN2 +120F8 ; [.2AE0.0020.0002.120F8] # CUNEIFORM SIGN GAN2 TENU +120F9 ; [.2AE1.0020.0002.120F9] # CUNEIFORM SIGN GAN2 OVER GAN2 +120FA ; [.2AE2.0020.0002.120FA] # CUNEIFORM SIGN GAN2 CROSSING GAN2 +120FB ; [.2AE3.0020.0002.120FB] # CUNEIFORM SIGN GAR +120FC ; [.2AE4.0020.0002.120FC] # CUNEIFORM SIGN GAR3 +120FD ; [.2AE5.0020.0002.120FD] # CUNEIFORM SIGN GASHAN +120FE ; [.2AE6.0020.0002.120FE] # CUNEIFORM SIGN GESHTIN +120FF ; [.2AE7.0020.0002.120FF] # CUNEIFORM SIGN GESHTIN TIMES KUR +12100 ; [.2AE8.0020.0002.12100] # CUNEIFORM SIGN GI +12101 ; [.2AE9.0020.0002.12101] # CUNEIFORM SIGN GI TIMES E +12102 ; [.2AEA.0020.0002.12102] # CUNEIFORM SIGN GI TIMES U +12103 ; [.2AEB.0020.0002.12103] # CUNEIFORM SIGN GI CROSSING GI +12104 ; [.2AEC.0020.0002.12104] # CUNEIFORM SIGN GI4 +12105 ; [.2AED.0020.0002.12105] # CUNEIFORM SIGN GI4 OVER GI4 +12106 ; [.2AEE.0020.0002.12106] # CUNEIFORM SIGN GI4 CROSSING GI4 +12107 ; [.2AEF.0020.0002.12107] # CUNEIFORM SIGN GIDIM +12108 ; [.2AF0.0020.0002.12108] # CUNEIFORM SIGN GIR2 +12109 ; [.2AF1.0020.0002.12109] # CUNEIFORM SIGN GIR2 GUNU +1210A ; [.2AF2.0020.0002.1210A] # CUNEIFORM SIGN GIR3 +1210B ; [.2AF3.0020.0002.1210B] # CUNEIFORM SIGN GIR3 TIMES A PLUS IGI +1210C ; [.2AF4.0020.0002.1210C] # CUNEIFORM SIGN GIR3 TIMES GAN2 TENU +1210D ; [.2AF5.0020.0002.1210D] # CUNEIFORM SIGN GIR3 TIMES IGI +1210E ; [.2AF6.0020.0002.1210E] # CUNEIFORM SIGN GIR3 TIMES LU PLUS IGI +1210F ; [.2AF7.0020.0002.1210F] # CUNEIFORM SIGN GIR3 TIMES PA +12110 ; [.2AF8.0020.0002.12110] # CUNEIFORM SIGN GISAL +12111 ; [.2AF9.0020.0002.12111] # CUNEIFORM SIGN GISH +12112 ; [.2AFA.0020.0002.12112] # CUNEIFORM SIGN GISH CROSSING GISH +12113 ; [.2AFB.0020.0002.12113] # CUNEIFORM SIGN GISH TIMES BAD +12114 ; [.2AFC.0020.0002.12114] # CUNEIFORM SIGN GISH TIMES TAK4 +12115 ; [.2AFD.0020.0002.12115] # CUNEIFORM SIGN GISH TENU +12116 ; [.2AFE.0020.0002.12116] # CUNEIFORM SIGN GU +12117 ; [.2AFF.0020.0002.12117] # CUNEIFORM SIGN GU CROSSING GU +12118 ; [.2B00.0020.0002.12118] # CUNEIFORM SIGN GU2 +12119 ; [.2B01.0020.0002.12119] # CUNEIFORM SIGN GU2 TIMES KAK +1211A ; [.2B02.0020.0002.1211A] # CUNEIFORM SIGN GU2 TIMES KAK TIMES IGI GUNU +1211B ; [.2B03.0020.0002.1211B] # CUNEIFORM SIGN GU2 TIMES NUN +1211C ; [.2B04.0020.0002.1211C] # CUNEIFORM SIGN GU2 TIMES SAL PLUS TUG2 +1211D ; [.2B05.0020.0002.1211D] # CUNEIFORM SIGN GU2 GUNU +1211E ; [.2B06.0020.0002.1211E] # CUNEIFORM SIGN GUD +1211F ; [.2B07.0020.0002.1211F] # CUNEIFORM SIGN GUD TIMES A PLUS KUR +12120 ; [.2B08.0020.0002.12120] # CUNEIFORM SIGN GUD TIMES KUR +12121 ; [.2B09.0020.0002.12121] # CUNEIFORM SIGN GUD OVER GUD LUGAL +12122 ; [.2B0A.0020.0002.12122] # CUNEIFORM SIGN GUL +12123 ; [.2B0B.0020.0002.12123] # CUNEIFORM SIGN GUM +12124 ; [.2B0C.0020.0002.12124] # CUNEIFORM SIGN GUM TIMES SHE +12125 ; [.2B0D.0020.0002.12125] # CUNEIFORM SIGN GUR +12126 ; [.2B0E.0020.0002.12126] # CUNEIFORM SIGN GUR7 +12127 ; [.2B0F.0020.0002.12127] # CUNEIFORM SIGN GURUN +12128 ; [.2B10.0020.0002.12128] # CUNEIFORM SIGN GURUSH +12129 ; [.2B11.0020.0002.12129] # CUNEIFORM SIGN HA +1212A ; [.2B12.0020.0002.1212A] # CUNEIFORM SIGN HA TENU +1212B ; [.2B13.0020.0002.1212B] # CUNEIFORM SIGN HA GUNU +1212C ; [.2B14.0020.0002.1212C] # CUNEIFORM SIGN HAL +1212D ; [.2B15.0020.0002.1212D] # CUNEIFORM SIGN HI +1212E ; [.2B16.0020.0002.1212E] # CUNEIFORM SIGN HI TIMES ASH +1212F ; [.2B17.0020.0002.1212F] # CUNEIFORM SIGN HI TIMES ASH2 +12130 ; [.2B18.0020.0002.12130] # CUNEIFORM SIGN HI TIMES BAD +12131 ; [.2B19.0020.0002.12131] # CUNEIFORM SIGN HI TIMES DISH +12132 ; [.2B1A.0020.0002.12132] # CUNEIFORM SIGN HI TIMES GAD +12133 ; [.2B1B.0020.0002.12133] # CUNEIFORM SIGN HI TIMES KIN +12134 ; [.2B1C.0020.0002.12134] # CUNEIFORM SIGN HI TIMES NUN +12135 ; [.2B1D.0020.0002.12135] # CUNEIFORM SIGN HI TIMES SHE +12136 ; [.2B1E.0020.0002.12136] # CUNEIFORM SIGN HI TIMES U +12137 ; [.2B1F.0020.0002.12137] # CUNEIFORM SIGN HU +12138 ; [.2B20.0020.0002.12138] # CUNEIFORM SIGN HUB2 +12139 ; [.2B21.0020.0002.12139] # CUNEIFORM SIGN HUB2 TIMES AN +1213A ; [.2B22.0020.0002.1213A] # CUNEIFORM SIGN HUB2 TIMES HAL +1213B ; [.2B23.0020.0002.1213B] # CUNEIFORM SIGN HUB2 TIMES KASKAL +1213C ; [.2B24.0020.0002.1213C] # CUNEIFORM SIGN HUB2 TIMES LISH +1213D ; [.2B25.0020.0002.1213D] # CUNEIFORM SIGN HUB2 TIMES UD +1213E ; [.2B26.0020.0002.1213E] # CUNEIFORM SIGN HUL2 +1213F ; [.2B27.0020.0002.1213F] # CUNEIFORM SIGN I +12140 ; [.2B28.0020.0002.12140] # CUNEIFORM SIGN I A +12141 ; [.2B29.0020.0002.12141] # CUNEIFORM SIGN IB +12142 ; [.2B2A.0020.0002.12142] # CUNEIFORM SIGN IDIM +12143 ; [.2B2B.0020.0002.12143] # CUNEIFORM SIGN IDIM OVER IDIM BUR +12144 ; [.2B2C.0020.0002.12144] # CUNEIFORM SIGN IDIM OVER IDIM SQUARED +12145 ; [.2B2D.0020.0002.12145] # CUNEIFORM SIGN IG +12146 ; [.2B2E.0020.0002.12146] # CUNEIFORM SIGN IGI +12147 ; [.2B2F.0020.0002.12147] # CUNEIFORM SIGN IGI DIB +12148 ; [.2B30.0020.0002.12148] # CUNEIFORM SIGN IGI RI +12149 ; [.2B31.0020.0002.12149] # CUNEIFORM SIGN IGI OVER IGI SHIR OVER SHIR UD OVER UD +1214A ; [.2B32.0020.0002.1214A] # CUNEIFORM SIGN IGI GUNU +1214B ; [.2B33.0020.0002.1214B] # CUNEIFORM SIGN IL +1214C ; [.2B34.0020.0002.1214C] # CUNEIFORM SIGN IL TIMES GAN2 TENU +1214D ; [.2B35.0020.0002.1214D] # CUNEIFORM SIGN IL2 +1214E ; [.2B36.0020.0002.1214E] # CUNEIFORM SIGN IM +1214F ; [.2B37.0020.0002.1214F] # CUNEIFORM SIGN IM TIMES TAK4 +12150 ; [.2B38.0020.0002.12150] # CUNEIFORM SIGN IM CROSSING IM +12151 ; [.2B39.0020.0002.12151] # CUNEIFORM SIGN IM OPPOSING IM +12152 ; [.2B3A.0020.0002.12152] # CUNEIFORM SIGN IM SQUARED +12153 ; [.2B3B.0020.0002.12153] # CUNEIFORM SIGN IMIN +12154 ; [.2B3C.0020.0002.12154] # CUNEIFORM SIGN IN +12155 ; [.2B3D.0020.0002.12155] # CUNEIFORM SIGN IR +12156 ; [.2B3E.0020.0002.12156] # CUNEIFORM SIGN ISH +12157 ; [.2B3F.0020.0002.12157] # CUNEIFORM SIGN KA +12158 ; [.2B40.0020.0002.12158] # CUNEIFORM SIGN KA TIMES A +12159 ; [.2B41.0020.0002.12159] # CUNEIFORM SIGN KA TIMES AD +1215A ; [.2B42.0020.0002.1215A] # CUNEIFORM SIGN KA TIMES AD PLUS KU3 +1215B ; [.2B43.0020.0002.1215B] # CUNEIFORM SIGN KA TIMES ASH2 +1215C ; [.2B44.0020.0002.1215C] # CUNEIFORM SIGN KA TIMES BAD +1215D ; [.2B45.0020.0002.1215D] # CUNEIFORM SIGN KA TIMES BALAG +1215E ; [.2B46.0020.0002.1215E] # CUNEIFORM SIGN KA TIMES BAR +1215F ; [.2B47.0020.0002.1215F] # CUNEIFORM SIGN KA TIMES BI +12160 ; [.2B48.0020.0002.12160] # CUNEIFORM SIGN KA TIMES ERIN2 +12161 ; [.2B49.0020.0002.12161] # CUNEIFORM SIGN KA TIMES ESH2 +12162 ; [.2B4A.0020.0002.12162] # CUNEIFORM SIGN KA TIMES GA +12163 ; [.2B4B.0020.0002.12163] # CUNEIFORM SIGN KA TIMES GAL +12164 ; [.2B4C.0020.0002.12164] # CUNEIFORM SIGN KA TIMES GAN2 TENU +12165 ; [.2B4D.0020.0002.12165] # CUNEIFORM SIGN KA TIMES GAR +12166 ; [.2B4E.0020.0002.12166] # CUNEIFORM SIGN KA TIMES GAR PLUS SHA3 PLUS A +12167 ; [.2B4F.0020.0002.12167] # CUNEIFORM SIGN KA TIMES GI +12168 ; [.2B50.0020.0002.12168] # CUNEIFORM SIGN KA TIMES GIR2 +12169 ; [.2B51.0020.0002.12169] # CUNEIFORM SIGN KA TIMES GISH PLUS SAR +1216A ; [.2B52.0020.0002.1216A] # CUNEIFORM SIGN KA TIMES GISH CROSSING GISH +1216B ; [.2B53.0020.0002.1216B] # CUNEIFORM SIGN KA TIMES GU +1216C ; [.2B54.0020.0002.1216C] # CUNEIFORM SIGN KA TIMES GUR7 +1216D ; [.2B55.0020.0002.1216D] # CUNEIFORM SIGN KA TIMES IGI +1216E ; [.2B56.0020.0002.1216E] # CUNEIFORM SIGN KA TIMES IM +1216F ; [.2B57.0020.0002.1216F] # CUNEIFORM SIGN KA TIMES KAK +12170 ; [.2B58.0020.0002.12170] # CUNEIFORM SIGN KA TIMES KI +12171 ; [.2B59.0020.0002.12171] # CUNEIFORM SIGN KA TIMES KID +12172 ; [.2B5A.0020.0002.12172] # CUNEIFORM SIGN KA TIMES LI +12173 ; [.2B5B.0020.0002.12173] # CUNEIFORM SIGN KA TIMES LU +12174 ; [.2B5C.0020.0002.12174] # CUNEIFORM SIGN KA TIMES ME +12175 ; [.2B5D.0020.0002.12175] # CUNEIFORM SIGN KA TIMES ME PLUS DU +12176 ; [.2B5E.0020.0002.12176] # CUNEIFORM SIGN KA TIMES ME PLUS GI +12177 ; [.2B5F.0020.0002.12177] # CUNEIFORM SIGN KA TIMES ME PLUS TE +12178 ; [.2B60.0020.0002.12178] # CUNEIFORM SIGN KA TIMES MI +12179 ; [.2B61.0020.0002.12179] # CUNEIFORM SIGN KA TIMES MI PLUS NUNUZ +1217A ; [.2B62.0020.0002.1217A] # CUNEIFORM SIGN KA TIMES NE +1217B ; [.2B63.0020.0002.1217B] # CUNEIFORM SIGN KA TIMES NUN +1217C ; [.2B64.0020.0002.1217C] # CUNEIFORM SIGN KA TIMES PI +1217D ; [.2B65.0020.0002.1217D] # CUNEIFORM SIGN KA TIMES RU +1217E ; [.2B66.0020.0002.1217E] # CUNEIFORM SIGN KA TIMES SA +1217F ; [.2B67.0020.0002.1217F] # CUNEIFORM SIGN KA TIMES SAR +12180 ; [.2B68.0020.0002.12180] # CUNEIFORM SIGN KA TIMES SHA +12181 ; [.2B69.0020.0002.12181] # CUNEIFORM SIGN KA TIMES SHE +12182 ; [.2B6A.0020.0002.12182] # CUNEIFORM SIGN KA TIMES SHID +12183 ; [.2B6B.0020.0002.12183] # CUNEIFORM SIGN KA TIMES SHU +12184 ; [.2B6C.0020.0002.12184] # CUNEIFORM SIGN KA TIMES SIG +12185 ; [.2B6D.0020.0002.12185] # CUNEIFORM SIGN KA TIMES SUHUR +12186 ; [.2B6E.0020.0002.12186] # CUNEIFORM SIGN KA TIMES TAR +12187 ; [.2B6F.0020.0002.12187] # CUNEIFORM SIGN KA TIMES U +12188 ; [.2B70.0020.0002.12188] # CUNEIFORM SIGN KA TIMES U2 +12189 ; [.2B71.0020.0002.12189] # CUNEIFORM SIGN KA TIMES UD +1218A ; [.2B72.0020.0002.1218A] # CUNEIFORM SIGN KA TIMES UMUM TIMES PA +1218B ; [.2B73.0020.0002.1218B] # CUNEIFORM SIGN KA TIMES USH +1218C ; [.2B74.0020.0002.1218C] # CUNEIFORM SIGN KA TIMES ZI +1218D ; [.2B75.0020.0002.1218D] # CUNEIFORM SIGN KA2 +1218E ; [.2B76.0020.0002.1218E] # CUNEIFORM SIGN KA2 CROSSING KA2 +1218F ; [.2B77.0020.0002.1218F] # CUNEIFORM SIGN KAB +12190 ; [.2B78.0020.0002.12190] # CUNEIFORM SIGN KAD2 +12191 ; [.2B79.0020.0002.12191] # CUNEIFORM SIGN KAD3 +12192 ; [.2B7A.0020.0002.12192] # CUNEIFORM SIGN KAD4 +12193 ; [.2B7B.0020.0002.12193] # CUNEIFORM SIGN KAD5 +12194 ; [.2B7C.0020.0002.12194] # CUNEIFORM SIGN KAD5 OVER KAD5 +12195 ; [.2B7D.0020.0002.12195] # CUNEIFORM SIGN KAK +12196 ; [.2B7E.0020.0002.12196] # CUNEIFORM SIGN KAK TIMES IGI GUNU +12197 ; [.2B7F.0020.0002.12197] # CUNEIFORM SIGN KAL +12198 ; [.2B80.0020.0002.12198] # CUNEIFORM SIGN KAL TIMES BAD +12199 ; [.2B81.0020.0002.12199] # CUNEIFORM SIGN KAL CROSSING KAL +1219A ; [.2B82.0020.0002.1219A] # CUNEIFORM SIGN KAM2 +1219B ; [.2B83.0020.0002.1219B] # CUNEIFORM SIGN KAM4 +1219C ; [.2B84.0020.0002.1219C] # CUNEIFORM SIGN KASKAL +1219D ; [.2B85.0020.0002.1219D] # CUNEIFORM SIGN KASKAL LAGAB TIMES U OVER LAGAB TIMES U +1219E ; [.2B86.0020.0002.1219E] # CUNEIFORM SIGN KASKAL OVER KASKAL LAGAB TIMES U OVER LAGAB TIMES U +1219F ; [.2B87.0020.0002.1219F] # CUNEIFORM SIGN KESH2 +121A0 ; [.2B88.0020.0002.121A0] # CUNEIFORM SIGN KI +121A1 ; [.2B89.0020.0002.121A1] # CUNEIFORM SIGN KI TIMES BAD +121A2 ; [.2B8A.0020.0002.121A2] # CUNEIFORM SIGN KI TIMES U +121A3 ; [.2B8B.0020.0002.121A3] # CUNEIFORM SIGN KI TIMES UD +121A4 ; [.2B8C.0020.0002.121A4] # CUNEIFORM SIGN KID +121A5 ; [.2B8D.0020.0002.121A5] # CUNEIFORM SIGN KIN +121A6 ; [.2B8E.0020.0002.121A6] # CUNEIFORM SIGN KISAL +121A7 ; [.2B8F.0020.0002.121A7] # CUNEIFORM SIGN KISH +121A8 ; [.2B90.0020.0002.121A8] # CUNEIFORM SIGN KISIM5 +121A9 ; [.2B91.0020.0002.121A9] # CUNEIFORM SIGN KISIM5 OVER KISIM5 +121AA ; [.2B92.0020.0002.121AA] # CUNEIFORM SIGN KU +121AB ; [.2B93.0020.0002.121AB] # CUNEIFORM SIGN KU OVER HI TIMES ASH2 KU OVER HI TIMES ASH2 +121AC ; [.2B94.0020.0002.121AC] # CUNEIFORM SIGN KU3 +121AD ; [.2B95.0020.0002.121AD] # CUNEIFORM SIGN KU4 +121AE ; [.2B96.0020.0002.121AE] # CUNEIFORM SIGN KU4 VARIANT FORM +121AF ; [.2B97.0020.0002.121AF] # CUNEIFORM SIGN KU7 +121B0 ; [.2B98.0020.0002.121B0] # CUNEIFORM SIGN KUL +121B1 ; [.2B99.0020.0002.121B1] # CUNEIFORM SIGN KUL GUNU +121B2 ; [.2B9A.0020.0002.121B2] # CUNEIFORM SIGN KUN +121B3 ; [.2B9B.0020.0002.121B3] # CUNEIFORM SIGN KUR +121B4 ; [.2B9C.0020.0002.121B4] # CUNEIFORM SIGN KUR OPPOSING KUR +121B5 ; [.2B9D.0020.0002.121B5] # CUNEIFORM SIGN KUSHU2 +121B6 ; [.2B9E.0020.0002.121B6] # CUNEIFORM SIGN KWU318 +121B7 ; [.2B9F.0020.0002.121B7] # CUNEIFORM SIGN LA +121B8 ; [.2BA0.0020.0002.121B8] # CUNEIFORM SIGN LAGAB +121B9 ; [.2BA1.0020.0002.121B9] # CUNEIFORM SIGN LAGAB TIMES A +121BA ; [.2BA2.0020.0002.121BA] # CUNEIFORM SIGN LAGAB TIMES A PLUS DA PLUS HA +121BB ; [.2BA3.0020.0002.121BB] # CUNEIFORM SIGN LAGAB TIMES A PLUS GAR +121BC ; [.2BA4.0020.0002.121BC] # CUNEIFORM SIGN LAGAB TIMES A PLUS LAL +121BD ; [.2BA5.0020.0002.121BD] # CUNEIFORM SIGN LAGAB TIMES AL +121BE ; [.2BA6.0020.0002.121BE] # CUNEIFORM SIGN LAGAB TIMES AN +121BF ; [.2BA7.0020.0002.121BF] # CUNEIFORM SIGN LAGAB TIMES ASH ZIDA TENU +121C0 ; [.2BA8.0020.0002.121C0] # CUNEIFORM SIGN LAGAB TIMES BAD +121C1 ; [.2BA9.0020.0002.121C1] # CUNEIFORM SIGN LAGAB TIMES BI +121C2 ; [.2BAA.0020.0002.121C2] # CUNEIFORM SIGN LAGAB TIMES DAR +121C3 ; [.2BAB.0020.0002.121C3] # CUNEIFORM SIGN LAGAB TIMES EN +121C4 ; [.2BAC.0020.0002.121C4] # CUNEIFORM SIGN LAGAB TIMES GA +121C5 ; [.2BAD.0020.0002.121C5] # CUNEIFORM SIGN LAGAB TIMES GAR +121C6 ; [.2BAE.0020.0002.121C6] # CUNEIFORM SIGN LAGAB TIMES GUD +121C7 ; [.2BAF.0020.0002.121C7] # CUNEIFORM SIGN LAGAB TIMES GUD PLUS GUD +121C8 ; [.2BB0.0020.0002.121C8] # CUNEIFORM SIGN LAGAB TIMES HA +121C9 ; [.2BB1.0020.0002.121C9] # CUNEIFORM SIGN LAGAB TIMES HAL +121CA ; [.2BB2.0020.0002.121CA] # CUNEIFORM SIGN LAGAB TIMES HI TIMES NUN +121CB ; [.2BB3.0020.0002.121CB] # CUNEIFORM SIGN LAGAB TIMES IGI GUNU +121CC ; [.2BB4.0020.0002.121CC] # CUNEIFORM SIGN LAGAB TIMES IM +121CD ; [.2BB5.0020.0002.121CD] # CUNEIFORM SIGN LAGAB TIMES IM PLUS HA +121CE ; [.2BB6.0020.0002.121CE] # CUNEIFORM SIGN LAGAB TIMES IM PLUS LU +121CF ; [.2BB7.0020.0002.121CF] # CUNEIFORM SIGN LAGAB TIMES KI +121D0 ; [.2BB8.0020.0002.121D0] # CUNEIFORM SIGN LAGAB TIMES KIN +121D1 ; [.2BB9.0020.0002.121D1] # CUNEIFORM SIGN LAGAB TIMES KU3 +121D2 ; [.2BBA.0020.0002.121D2] # CUNEIFORM SIGN LAGAB TIMES KUL +121D3 ; [.2BBB.0020.0002.121D3] # CUNEIFORM SIGN LAGAB TIMES KUL PLUS HI PLUS A +121D4 ; [.2BBC.0020.0002.121D4] # CUNEIFORM SIGN LAGAB TIMES LAGAB +121D5 ; [.2BBD.0020.0002.121D5] # CUNEIFORM SIGN LAGAB TIMES LISH +121D6 ; [.2BBE.0020.0002.121D6] # CUNEIFORM SIGN LAGAB TIMES LU +121D7 ; [.2BBF.0020.0002.121D7] # CUNEIFORM SIGN LAGAB TIMES LUL +121D8 ; [.2BC0.0020.0002.121D8] # CUNEIFORM SIGN LAGAB TIMES ME +121D9 ; [.2BC1.0020.0002.121D9] # CUNEIFORM SIGN LAGAB TIMES ME PLUS EN +121DA ; [.2BC2.0020.0002.121DA] # CUNEIFORM SIGN LAGAB TIMES MUSH +121DB ; [.2BC3.0020.0002.121DB] # CUNEIFORM SIGN LAGAB TIMES NE +121DC ; [.2BC4.0020.0002.121DC] # CUNEIFORM SIGN LAGAB TIMES SHE PLUS SUM +121DD ; [.2BC5.0020.0002.121DD] # CUNEIFORM SIGN LAGAB TIMES SHITA PLUS GISH PLUS ERIN2 +121DE ; [.2BC6.0020.0002.121DE] # CUNEIFORM SIGN LAGAB TIMES SHITA PLUS GISH TENU +121DF ; [.2BC7.0020.0002.121DF] # CUNEIFORM SIGN LAGAB TIMES SHU2 +121E0 ; [.2BC8.0020.0002.121E0] # CUNEIFORM SIGN LAGAB TIMES SHU2 PLUS SHU2 +121E1 ; [.2BC9.0020.0002.121E1] # CUNEIFORM SIGN LAGAB TIMES SUM +121E2 ; [.2BCA.0020.0002.121E2] # CUNEIFORM SIGN LAGAB TIMES TAG +121E3 ; [.2BCB.0020.0002.121E3] # CUNEIFORM SIGN LAGAB TIMES TAK4 +121E4 ; [.2BCC.0020.0002.121E4] # CUNEIFORM SIGN LAGAB TIMES TE PLUS A PLUS SU PLUS NA +121E5 ; [.2BCD.0020.0002.121E5] # CUNEIFORM SIGN LAGAB TIMES U +121E6 ; [.2BCE.0020.0002.121E6] # CUNEIFORM SIGN LAGAB TIMES U PLUS A +121E7 ; [.2BCF.0020.0002.121E7] # CUNEIFORM SIGN LAGAB TIMES U PLUS U PLUS U +121E8 ; [.2BD0.0020.0002.121E8] # CUNEIFORM SIGN LAGAB TIMES U2 PLUS ASH +121E9 ; [.2BD1.0020.0002.121E9] # CUNEIFORM SIGN LAGAB TIMES UD +121EA ; [.2BD2.0020.0002.121EA] # CUNEIFORM SIGN LAGAB TIMES USH +121EB ; [.2BD3.0020.0002.121EB] # CUNEIFORM SIGN LAGAB SQUARED +121EC ; [.2BD4.0020.0002.121EC] # CUNEIFORM SIGN LAGAR +121ED ; [.2BD5.0020.0002.121ED] # CUNEIFORM SIGN LAGAR TIMES SHE +121EE ; [.2BD6.0020.0002.121EE] # CUNEIFORM SIGN LAGAR TIMES SHE PLUS SUM +121EF ; [.2BD7.0020.0002.121EF] # CUNEIFORM SIGN LAGAR GUNU +121F0 ; [.2BD8.0020.0002.121F0] # CUNEIFORM SIGN LAGAR GUNU OVER LAGAR GUNU SHE +121F1 ; [.2BD9.0020.0002.121F1] # CUNEIFORM SIGN LAHSHU +121F2 ; [.2BDA.0020.0002.121F2] # CUNEIFORM SIGN LAL +121F3 ; [.2BDB.0020.0002.121F3] # CUNEIFORM SIGN LAL TIMES LAL +121F4 ; [.2BDC.0020.0002.121F4] # CUNEIFORM SIGN LAM +121F5 ; [.2BDD.0020.0002.121F5] # CUNEIFORM SIGN LAM TIMES KUR +121F6 ; [.2BDE.0020.0002.121F6] # CUNEIFORM SIGN LAM TIMES KUR PLUS RU +121F7 ; [.2BDF.0020.0002.121F7] # CUNEIFORM SIGN LI +121F8 ; [.2BE0.0020.0002.121F8] # CUNEIFORM SIGN LIL +121F9 ; [.2BE1.0020.0002.121F9] # CUNEIFORM SIGN LIMMU2 +121FA ; [.2BE2.0020.0002.121FA] # CUNEIFORM SIGN LISH +121FB ; [.2BE3.0020.0002.121FB] # CUNEIFORM SIGN LU +121FC ; [.2BE4.0020.0002.121FC] # CUNEIFORM SIGN LU TIMES BAD +121FD ; [.2BE5.0020.0002.121FD] # CUNEIFORM SIGN LU2 +121FE ; [.2BE6.0020.0002.121FE] # CUNEIFORM SIGN LU2 TIMES AL +121FF ; [.2BE7.0020.0002.121FF] # CUNEIFORM SIGN LU2 TIMES BAD +12200 ; [.2BE8.0020.0002.12200] # CUNEIFORM SIGN LU2 TIMES ESH2 +12201 ; [.2BE9.0020.0002.12201] # CUNEIFORM SIGN LU2 TIMES ESH2 TENU +12202 ; [.2BEA.0020.0002.12202] # CUNEIFORM SIGN LU2 TIMES GAN2 TENU +12203 ; [.2BEB.0020.0002.12203] # CUNEIFORM SIGN LU2 TIMES HI TIMES BAD +12204 ; [.2BEC.0020.0002.12204] # CUNEIFORM SIGN LU2 TIMES IM +12205 ; [.2BED.0020.0002.12205] # CUNEIFORM SIGN LU2 TIMES KAD2 +12206 ; [.2BEE.0020.0002.12206] # CUNEIFORM SIGN LU2 TIMES KAD3 +12207 ; [.2BEF.0020.0002.12207] # CUNEIFORM SIGN LU2 TIMES KAD3 PLUS ASH +12208 ; [.2BF0.0020.0002.12208] # CUNEIFORM SIGN LU2 TIMES KI +12209 ; [.2BF1.0020.0002.12209] # CUNEIFORM SIGN LU2 TIMES LA PLUS ASH +1220A ; [.2BF2.0020.0002.1220A] # CUNEIFORM SIGN LU2 TIMES LAGAB +1220B ; [.2BF3.0020.0002.1220B] # CUNEIFORM SIGN LU2 TIMES ME PLUS EN +1220C ; [.2BF4.0020.0002.1220C] # CUNEIFORM SIGN LU2 TIMES NE +1220D ; [.2BF5.0020.0002.1220D] # CUNEIFORM SIGN LU2 TIMES NU +1220E ; [.2BF6.0020.0002.1220E] # CUNEIFORM SIGN LU2 TIMES SI PLUS ASH +1220F ; [.2BF7.0020.0002.1220F] # CUNEIFORM SIGN LU2 TIMES SIK2 PLUS BU +12210 ; [.2BF8.0020.0002.12210] # CUNEIFORM SIGN LU2 TIMES TUG2 +12211 ; [.2BF9.0020.0002.12211] # CUNEIFORM SIGN LU2 TENU +12212 ; [.2BFA.0020.0002.12212] # CUNEIFORM SIGN LU2 CROSSING LU2 +12213 ; [.2BFB.0020.0002.12213] # CUNEIFORM SIGN LU2 OPPOSING LU2 +12214 ; [.2BFC.0020.0002.12214] # CUNEIFORM SIGN LU2 SQUARED +12215 ; [.2BFD.0020.0002.12215] # CUNEIFORM SIGN LU2 SHESHIG +12216 ; [.2BFE.0020.0002.12216] # CUNEIFORM SIGN LU3 +12217 ; [.2BFF.0020.0002.12217] # CUNEIFORM SIGN LUGAL +12218 ; [.2C00.0020.0002.12218] # CUNEIFORM SIGN LUGAL OVER LUGAL +12219 ; [.2C01.0020.0002.12219] # CUNEIFORM SIGN LUGAL OPPOSING LUGAL +1221A ; [.2C02.0020.0002.1221A] # CUNEIFORM SIGN LUGAL SHESHIG +1221B ; [.2C03.0020.0002.1221B] # CUNEIFORM SIGN LUH +1221C ; [.2C04.0020.0002.1221C] # CUNEIFORM SIGN LUL +1221D ; [.2C05.0020.0002.1221D] # CUNEIFORM SIGN LUM +1221E ; [.2C06.0020.0002.1221E] # CUNEIFORM SIGN LUM OVER LUM +1221F ; [.2C07.0020.0002.1221F] # CUNEIFORM SIGN LUM OVER LUM GAR OVER GAR +12220 ; [.2C08.0020.0002.12220] # CUNEIFORM SIGN MA +12221 ; [.2C09.0020.0002.12221] # CUNEIFORM SIGN MA TIMES TAK4 +12222 ; [.2C0A.0020.0002.12222] # CUNEIFORM SIGN MA GUNU +12223 ; [.2C0B.0020.0002.12223] # CUNEIFORM SIGN MA2 +12224 ; [.2C0C.0020.0002.12224] # CUNEIFORM SIGN MAH +12225 ; [.2C0D.0020.0002.12225] # CUNEIFORM SIGN MAR +12226 ; [.2C0E.0020.0002.12226] # CUNEIFORM SIGN MASH +12227 ; [.2C0F.0020.0002.12227] # CUNEIFORM SIGN MASH2 +12228 ; [.2C10.0020.0002.12228] # CUNEIFORM SIGN ME +12229 ; [.2C11.0020.0002.12229] # CUNEIFORM SIGN MES +1222A ; [.2C12.0020.0002.1222A] # CUNEIFORM SIGN MI +1222B ; [.2C13.0020.0002.1222B] # CUNEIFORM SIGN MIN +1222C ; [.2C14.0020.0002.1222C] # CUNEIFORM SIGN MU +1222D ; [.2C15.0020.0002.1222D] # CUNEIFORM SIGN MU OVER MU +1222E ; [.2C16.0020.0002.1222E] # CUNEIFORM SIGN MUG +1222F ; [.2C17.0020.0002.1222F] # CUNEIFORM SIGN MUG GUNU +12230 ; [.2C18.0020.0002.12230] # CUNEIFORM SIGN MUNSUB +12231 ; [.2C19.0020.0002.12231] # CUNEIFORM SIGN MURGU2 +12232 ; [.2C1A.0020.0002.12232] # CUNEIFORM SIGN MUSH +12233 ; [.2C1B.0020.0002.12233] # CUNEIFORM SIGN MUSH TIMES A +12234 ; [.2C1C.0020.0002.12234] # CUNEIFORM SIGN MUSH TIMES KUR +12235 ; [.2C1D.0020.0002.12235] # CUNEIFORM SIGN MUSH TIMES ZA +12236 ; [.2C1E.0020.0002.12236] # CUNEIFORM SIGN MUSH OVER MUSH +12237 ; [.2C1F.0020.0002.12237] # CUNEIFORM SIGN MUSH OVER MUSH TIMES A PLUS NA +12238 ; [.2C20.0020.0002.12238] # CUNEIFORM SIGN MUSH CROSSING MUSH +12239 ; [.2C21.0020.0002.12239] # CUNEIFORM SIGN MUSH3 +1223A ; [.2C22.0020.0002.1223A] # CUNEIFORM SIGN MUSH3 TIMES A +1223B ; [.2C23.0020.0002.1223B] # CUNEIFORM SIGN MUSH3 TIMES A PLUS DI +1223C ; [.2C24.0020.0002.1223C] # CUNEIFORM SIGN MUSH3 TIMES DI +1223D ; [.2C25.0020.0002.1223D] # CUNEIFORM SIGN MUSH3 GUNU +1223E ; [.2C26.0020.0002.1223E] # CUNEIFORM SIGN NA +1223F ; [.2C27.0020.0002.1223F] # CUNEIFORM SIGN NA2 +12240 ; [.2C28.0020.0002.12240] # CUNEIFORM SIGN NAGA +12241 ; [.2C29.0020.0002.12241] # CUNEIFORM SIGN NAGA INVERTED +12242 ; [.2C2A.0020.0002.12242] # CUNEIFORM SIGN NAGA TIMES SHU TENU +12243 ; [.2C2B.0020.0002.12243] # CUNEIFORM SIGN NAGA OPPOSING NAGA +12244 ; [.2C2C.0020.0002.12244] # CUNEIFORM SIGN NAGAR +12245 ; [.2C2D.0020.0002.12245] # CUNEIFORM SIGN NAM NUTILLU +12246 ; [.2C2E.0020.0002.12246] # CUNEIFORM SIGN NAM +12247 ; [.2C2F.0020.0002.12247] # CUNEIFORM SIGN NAM2 +12248 ; [.2C30.0020.0002.12248] # CUNEIFORM SIGN NE +12249 ; [.2C31.0020.0002.12249] # CUNEIFORM SIGN NE TIMES A +1224A ; [.2C32.0020.0002.1224A] # CUNEIFORM SIGN NE TIMES UD +1224B ; [.2C33.0020.0002.1224B] # CUNEIFORM SIGN NE SHESHIG +1224C ; [.2C34.0020.0002.1224C] # CUNEIFORM SIGN NI +1224D ; [.2C35.0020.0002.1224D] # CUNEIFORM SIGN NI TIMES E +1224E ; [.2C36.0020.0002.1224E] # CUNEIFORM SIGN NI2 +1224F ; [.2C37.0020.0002.1224F] # CUNEIFORM SIGN NIM +12250 ; [.2C38.0020.0002.12250] # CUNEIFORM SIGN NIM TIMES GAN2 TENU +12251 ; [.2C39.0020.0002.12251] # CUNEIFORM SIGN NIM TIMES GAR PLUS GAN2 TENU +12252 ; [.2C3A.0020.0002.12252] # CUNEIFORM SIGN NINDA2 +12253 ; [.2C3B.0020.0002.12253] # CUNEIFORM SIGN NINDA2 TIMES AN +12254 ; [.2C3C.0020.0002.12254] # CUNEIFORM SIGN NINDA2 TIMES ASH +12255 ; [.2C3D.0020.0002.12255] # CUNEIFORM SIGN NINDA2 TIMES ASH PLUS ASH +12256 ; [.2C3E.0020.0002.12256] # CUNEIFORM SIGN NINDA2 TIMES GUD +12257 ; [.2C3F.0020.0002.12257] # CUNEIFORM SIGN NINDA2 TIMES ME PLUS GAN2 TENU +12258 ; [.2C40.0020.0002.12258] # CUNEIFORM SIGN NINDA2 TIMES NE +12259 ; [.2C41.0020.0002.12259] # CUNEIFORM SIGN NINDA2 TIMES NUN +1225A ; [.2C42.0020.0002.1225A] # CUNEIFORM SIGN NINDA2 TIMES SHE +1225B ; [.2C43.0020.0002.1225B] # CUNEIFORM SIGN NINDA2 TIMES SHE PLUS A AN +1225C ; [.2C44.0020.0002.1225C] # CUNEIFORM SIGN NINDA2 TIMES SHE PLUS ASH +1225D ; [.2C45.0020.0002.1225D] # CUNEIFORM SIGN NINDA2 TIMES SHE PLUS ASH PLUS ASH +1225E ; [.2C46.0020.0002.1225E] # CUNEIFORM SIGN NINDA2 TIMES U2 PLUS ASH +1225F ; [.2C47.0020.0002.1225F] # CUNEIFORM SIGN NINDA2 TIMES USH +12260 ; [.2C48.0020.0002.12260] # CUNEIFORM SIGN NISAG +12261 ; [.2C49.0020.0002.12261] # CUNEIFORM SIGN NU +12262 ; [.2C4A.0020.0002.12262] # CUNEIFORM SIGN NU11 +12263 ; [.2C4B.0020.0002.12263] # CUNEIFORM SIGN NUN +12264 ; [.2C4C.0020.0002.12264] # CUNEIFORM SIGN NUN LAGAR TIMES GAR +12265 ; [.2C4D.0020.0002.12265] # CUNEIFORM SIGN NUN LAGAR TIMES MASH +12266 ; [.2C4E.0020.0002.12266] # CUNEIFORM SIGN NUN LAGAR TIMES SAL +12267 ; [.2C4F.0020.0002.12267] # CUNEIFORM SIGN NUN LAGAR TIMES SAL OVER NUN LAGAR TIMES SAL +12268 ; [.2C50.0020.0002.12268] # CUNEIFORM SIGN NUN LAGAR TIMES USH +12269 ; [.2C51.0020.0002.12269] # CUNEIFORM SIGN NUN TENU +1226A ; [.2C52.0020.0002.1226A] # CUNEIFORM SIGN NUN OVER NUN +1226B ; [.2C53.0020.0002.1226B] # CUNEIFORM SIGN NUN CROSSING NUN +1226C ; [.2C54.0020.0002.1226C] # CUNEIFORM SIGN NUN CROSSING NUN LAGAR OVER LAGAR +1226D ; [.2C55.0020.0002.1226D] # CUNEIFORM SIGN NUNUZ +1226E ; [.2C56.0020.0002.1226E] # CUNEIFORM SIGN NUNUZ AB2 TIMES ASHGAB +1226F ; [.2C57.0020.0002.1226F] # CUNEIFORM SIGN NUNUZ AB2 TIMES BI +12270 ; [.2C58.0020.0002.12270] # CUNEIFORM SIGN NUNUZ AB2 TIMES DUG +12271 ; [.2C59.0020.0002.12271] # CUNEIFORM SIGN NUNUZ AB2 TIMES GUD +12272 ; [.2C5A.0020.0002.12272] # CUNEIFORM SIGN NUNUZ AB2 TIMES IGI GUNU +12273 ; [.2C5B.0020.0002.12273] # CUNEIFORM SIGN NUNUZ AB2 TIMES KAD3 +12274 ; [.2C5C.0020.0002.12274] # CUNEIFORM SIGN NUNUZ AB2 TIMES LA +12275 ; [.2C5D.0020.0002.12275] # CUNEIFORM SIGN NUNUZ AB2 TIMES NE +12276 ; [.2C5E.0020.0002.12276] # CUNEIFORM SIGN NUNUZ AB2 TIMES SILA3 +12277 ; [.2C5F.0020.0002.12277] # CUNEIFORM SIGN NUNUZ AB2 TIMES U2 +12278 ; [.2C60.0020.0002.12278] # CUNEIFORM SIGN NUNUZ KISIM5 TIMES BI +12279 ; [.2C61.0020.0002.12279] # CUNEIFORM SIGN NUNUZ KISIM5 TIMES BI U +1227A ; [.2C62.0020.0002.1227A] # CUNEIFORM SIGN PA +1227B ; [.2C63.0020.0002.1227B] # CUNEIFORM SIGN PAD +1227C ; [.2C64.0020.0002.1227C] # CUNEIFORM SIGN PAN +1227D ; [.2C65.0020.0002.1227D] # CUNEIFORM SIGN PAP +1227E ; [.2C66.0020.0002.1227E] # CUNEIFORM SIGN PESH2 +1227F ; [.2C67.0020.0002.1227F] # CUNEIFORM SIGN PI +12280 ; [.2C68.0020.0002.12280] # CUNEIFORM SIGN PI TIMES A +12281 ; [.2C69.0020.0002.12281] # CUNEIFORM SIGN PI TIMES AB +12282 ; [.2C6A.0020.0002.12282] # CUNEIFORM SIGN PI TIMES BI +12283 ; [.2C6B.0020.0002.12283] # CUNEIFORM SIGN PI TIMES BU +12284 ; [.2C6C.0020.0002.12284] # CUNEIFORM SIGN PI TIMES E +12285 ; [.2C6D.0020.0002.12285] # CUNEIFORM SIGN PI TIMES I +12286 ; [.2C6E.0020.0002.12286] # CUNEIFORM SIGN PI TIMES IB +12287 ; [.2C6F.0020.0002.12287] # CUNEIFORM SIGN PI TIMES U +12288 ; [.2C70.0020.0002.12288] # CUNEIFORM SIGN PI TIMES U2 +12289 ; [.2C71.0020.0002.12289] # CUNEIFORM SIGN PI CROSSING PI +1228A ; [.2C72.0020.0002.1228A] # CUNEIFORM SIGN PIRIG +1228B ; [.2C73.0020.0002.1228B] # CUNEIFORM SIGN PIRIG TIMES KAL +1228C ; [.2C74.0020.0002.1228C] # CUNEIFORM SIGN PIRIG TIMES UD +1228D ; [.2C75.0020.0002.1228D] # CUNEIFORM SIGN PIRIG TIMES ZA +1228E ; [.2C76.0020.0002.1228E] # CUNEIFORM SIGN PIRIG OPPOSING PIRIG +1228F ; [.2C77.0020.0002.1228F] # CUNEIFORM SIGN RA +12290 ; [.2C78.0020.0002.12290] # CUNEIFORM SIGN RAB +12291 ; [.2C79.0020.0002.12291] # CUNEIFORM SIGN RI +12292 ; [.2C7A.0020.0002.12292] # CUNEIFORM SIGN RU +12293 ; [.2C7B.0020.0002.12293] # CUNEIFORM SIGN SA +12294 ; [.2C7C.0020.0002.12294] # CUNEIFORM SIGN SAG NUTILLU +12295 ; [.2C7D.0020.0002.12295] # CUNEIFORM SIGN SAG +12296 ; [.2C7E.0020.0002.12296] # CUNEIFORM SIGN SAG TIMES A +12297 ; [.2C7F.0020.0002.12297] # CUNEIFORM SIGN SAG TIMES DU +12298 ; [.2C80.0020.0002.12298] # CUNEIFORM SIGN SAG TIMES DUB +12299 ; [.2C81.0020.0002.12299] # CUNEIFORM SIGN SAG TIMES HA +1229A ; [.2C82.0020.0002.1229A] # CUNEIFORM SIGN SAG TIMES KAK +1229B ; [.2C83.0020.0002.1229B] # CUNEIFORM SIGN SAG TIMES KUR +1229C ; [.2C84.0020.0002.1229C] # CUNEIFORM SIGN SAG TIMES LUM +1229D ; [.2C85.0020.0002.1229D] # CUNEIFORM SIGN SAG TIMES MI +1229E ; [.2C86.0020.0002.1229E] # CUNEIFORM SIGN SAG TIMES NUN +1229F ; [.2C87.0020.0002.1229F] # CUNEIFORM SIGN SAG TIMES SAL +122A0 ; [.2C88.0020.0002.122A0] # CUNEIFORM SIGN SAG TIMES SHID +122A1 ; [.2C89.0020.0002.122A1] # CUNEIFORM SIGN SAG TIMES TAB +122A2 ; [.2C8A.0020.0002.122A2] # CUNEIFORM SIGN SAG TIMES U2 +122A3 ; [.2C8B.0020.0002.122A3] # CUNEIFORM SIGN SAG TIMES UB +122A4 ; [.2C8C.0020.0002.122A4] # CUNEIFORM SIGN SAG TIMES UM +122A5 ; [.2C8D.0020.0002.122A5] # CUNEIFORM SIGN SAG TIMES UR +122A6 ; [.2C8E.0020.0002.122A6] # CUNEIFORM SIGN SAG TIMES USH +122A7 ; [.2C8F.0020.0002.122A7] # CUNEIFORM SIGN SAG OVER SAG +122A8 ; [.2C90.0020.0002.122A8] # CUNEIFORM SIGN SAG GUNU +122A9 ; [.2C91.0020.0002.122A9] # CUNEIFORM SIGN SAL +122AA ; [.2C92.0020.0002.122AA] # CUNEIFORM SIGN SAL LAGAB TIMES ASH2 +122AB ; [.2C93.0020.0002.122AB] # CUNEIFORM SIGN SANGA2 +122AC ; [.2C94.0020.0002.122AC] # CUNEIFORM SIGN SAR +122AD ; [.2C95.0020.0002.122AD] # CUNEIFORM SIGN SHA +122AE ; [.2C96.0020.0002.122AE] # CUNEIFORM SIGN SHA3 +122AF ; [.2C97.0020.0002.122AF] # CUNEIFORM SIGN SHA3 TIMES A +122B0 ; [.2C98.0020.0002.122B0] # CUNEIFORM SIGN SHA3 TIMES BAD +122B1 ; [.2C99.0020.0002.122B1] # CUNEIFORM SIGN SHA3 TIMES GISH +122B2 ; [.2C9A.0020.0002.122B2] # CUNEIFORM SIGN SHA3 TIMES NE +122B3 ; [.2C9B.0020.0002.122B3] # CUNEIFORM SIGN SHA3 TIMES SHU2 +122B4 ; [.2C9C.0020.0002.122B4] # CUNEIFORM SIGN SHA3 TIMES TUR +122B5 ; [.2C9D.0020.0002.122B5] # CUNEIFORM SIGN SHA3 TIMES U +122B6 ; [.2C9E.0020.0002.122B6] # CUNEIFORM SIGN SHA3 TIMES U PLUS A +122B7 ; [.2C9F.0020.0002.122B7] # CUNEIFORM SIGN SHA6 +122B8 ; [.2CA0.0020.0002.122B8] # CUNEIFORM SIGN SHAB6 +122B9 ; [.2CA1.0020.0002.122B9] # CUNEIFORM SIGN SHAR2 +122BA ; [.2CA2.0020.0002.122BA] # CUNEIFORM SIGN SHE +122BB ; [.2CA3.0020.0002.122BB] # CUNEIFORM SIGN SHE HU +122BC ; [.2CA4.0020.0002.122BC] # CUNEIFORM SIGN SHE OVER SHE GAD OVER GAD GAR OVER GAR +122BD ; [.2CA5.0020.0002.122BD] # CUNEIFORM SIGN SHE OVER SHE TAB OVER TAB GAR OVER GAR +122BE ; [.2CA6.0020.0002.122BE] # CUNEIFORM SIGN SHEG9 +122BF ; [.2CA7.0020.0002.122BF] # CUNEIFORM SIGN SHEN +122C0 ; [.2CA8.0020.0002.122C0] # CUNEIFORM SIGN SHESH +122C1 ; [.2CA9.0020.0002.122C1] # CUNEIFORM SIGN SHESH2 +122C2 ; [.2CAA.0020.0002.122C2] # CUNEIFORM SIGN SHESHLAM +122C3 ; [.2CAB.0020.0002.122C3] # CUNEIFORM SIGN SHID +122C4 ; [.2CAC.0020.0002.122C4] # CUNEIFORM SIGN SHID TIMES A +122C5 ; [.2CAD.0020.0002.122C5] # CUNEIFORM SIGN SHID TIMES IM +122C6 ; [.2CAE.0020.0002.122C6] # CUNEIFORM SIGN SHIM +122C7 ; [.2CAF.0020.0002.122C7] # CUNEIFORM SIGN SHIM TIMES A +122C8 ; [.2CB0.0020.0002.122C8] # CUNEIFORM SIGN SHIM TIMES BAL +122C9 ; [.2CB1.0020.0002.122C9] # CUNEIFORM SIGN SHIM TIMES BULUG +122CA ; [.2CB2.0020.0002.122CA] # CUNEIFORM SIGN SHIM TIMES DIN +122CB ; [.2CB3.0020.0002.122CB] # CUNEIFORM SIGN SHIM TIMES GAR +122CC ; [.2CB4.0020.0002.122CC] # CUNEIFORM SIGN SHIM TIMES IGI +122CD ; [.2CB5.0020.0002.122CD] # CUNEIFORM SIGN SHIM TIMES IGI GUNU +122CE ; [.2CB6.0020.0002.122CE] # CUNEIFORM SIGN SHIM TIMES KUSHU2 +122CF ; [.2CB7.0020.0002.122CF] # CUNEIFORM SIGN SHIM TIMES LUL +122D0 ; [.2CB8.0020.0002.122D0] # CUNEIFORM SIGN SHIM TIMES MUG +122D1 ; [.2CB9.0020.0002.122D1] # CUNEIFORM SIGN SHIM TIMES SAL +122D2 ; [.2CBA.0020.0002.122D2] # CUNEIFORM SIGN SHINIG +122D3 ; [.2CBB.0020.0002.122D3] # CUNEIFORM SIGN SHIR +122D4 ; [.2CBC.0020.0002.122D4] # CUNEIFORM SIGN SHIR TENU +122D5 ; [.2CBD.0020.0002.122D5] # CUNEIFORM SIGN SHIR OVER SHIR BUR OVER BUR +122D6 ; [.2CBE.0020.0002.122D6] # CUNEIFORM SIGN SHITA +122D7 ; [.2CBF.0020.0002.122D7] # CUNEIFORM SIGN SHU +122D8 ; [.2CC0.0020.0002.122D8] # CUNEIFORM SIGN SHU OVER INVERTED SHU +122D9 ; [.2CC1.0020.0002.122D9] # CUNEIFORM SIGN SHU2 +122DA ; [.2CC2.0020.0002.122DA] # CUNEIFORM SIGN SHUBUR +122DB ; [.2CC3.0020.0002.122DB] # CUNEIFORM SIGN SI +122DC ; [.2CC4.0020.0002.122DC] # CUNEIFORM SIGN SI GUNU +122DD ; [.2CC5.0020.0002.122DD] # CUNEIFORM SIGN SIG +122DE ; [.2CC6.0020.0002.122DE] # CUNEIFORM SIGN SIG4 +122DF ; [.2CC7.0020.0002.122DF] # CUNEIFORM SIGN SIG4 OVER SIG4 SHU2 +122E0 ; [.2CC8.0020.0002.122E0] # CUNEIFORM SIGN SIK2 +122E1 ; [.2CC9.0020.0002.122E1] # CUNEIFORM SIGN SILA3 +122E2 ; [.2CCA.0020.0002.122E2] # CUNEIFORM SIGN SU +122E3 ; [.2CCB.0020.0002.122E3] # CUNEIFORM SIGN SU OVER SU +122E4 ; [.2CCC.0020.0002.122E4] # CUNEIFORM SIGN SUD +122E5 ; [.2CCD.0020.0002.122E5] # CUNEIFORM SIGN SUD2 +122E6 ; [.2CCE.0020.0002.122E6] # CUNEIFORM SIGN SUHUR +122E7 ; [.2CCF.0020.0002.122E7] # CUNEIFORM SIGN SUM +122E8 ; [.2CD0.0020.0002.122E8] # CUNEIFORM SIGN SUMASH +122E9 ; [.2CD1.0020.0002.122E9] # CUNEIFORM SIGN SUR +122EA ; [.2CD2.0020.0002.122EA] # CUNEIFORM SIGN SUR9 +122EB ; [.2CD3.0020.0002.122EB] # CUNEIFORM SIGN TA +122EC ; [.2CD4.0020.0002.122EC] # CUNEIFORM SIGN TA ASTERISK +122ED ; [.2CD5.0020.0002.122ED] # CUNEIFORM SIGN TA TIMES HI +122EE ; [.2CD6.0020.0002.122EE] # CUNEIFORM SIGN TA TIMES MI +122EF ; [.2CD7.0020.0002.122EF] # CUNEIFORM SIGN TA GUNU +122F0 ; [.2CD8.0020.0002.122F0] # CUNEIFORM SIGN TAB +122F1 ; [.2CD9.0020.0002.122F1] # CUNEIFORM SIGN TAB OVER TAB NI OVER NI DISH OVER DISH +122F2 ; [.2CDA.0020.0002.122F2] # CUNEIFORM SIGN TAB SQUARED +122F3 ; [.2CDB.0020.0002.122F3] # CUNEIFORM SIGN TAG +122F4 ; [.2CDC.0020.0002.122F4] # CUNEIFORM SIGN TAG TIMES BI +122F5 ; [.2CDD.0020.0002.122F5] # CUNEIFORM SIGN TAG TIMES GUD +122F6 ; [.2CDE.0020.0002.122F6] # CUNEIFORM SIGN TAG TIMES SHE +122F7 ; [.2CDF.0020.0002.122F7] # CUNEIFORM SIGN TAG TIMES SHU +122F8 ; [.2CE0.0020.0002.122F8] # CUNEIFORM SIGN TAG TIMES TUG2 +122F9 ; [.2CE1.0020.0002.122F9] # CUNEIFORM SIGN TAG TIMES UD +122FA ; [.2CE2.0020.0002.122FA] # CUNEIFORM SIGN TAK4 +122FB ; [.2CE3.0020.0002.122FB] # CUNEIFORM SIGN TAR +122FC ; [.2CE4.0020.0002.122FC] # CUNEIFORM SIGN TE +122FD ; [.2CE5.0020.0002.122FD] # CUNEIFORM SIGN TE GUNU +122FE ; [.2CE6.0020.0002.122FE] # CUNEIFORM SIGN TI +122FF ; [.2CE7.0020.0002.122FF] # CUNEIFORM SIGN TI TENU +12300 ; [.2CE8.0020.0002.12300] # CUNEIFORM SIGN TIL +12301 ; [.2CE9.0020.0002.12301] # CUNEIFORM SIGN TIR +12302 ; [.2CEA.0020.0002.12302] # CUNEIFORM SIGN TIR TIMES TAK4 +12303 ; [.2CEB.0020.0002.12303] # CUNEIFORM SIGN TIR OVER TIR +12304 ; [.2CEC.0020.0002.12304] # CUNEIFORM SIGN TIR OVER TIR GAD OVER GAD GAR OVER GAR +12305 ; [.2CED.0020.0002.12305] # CUNEIFORM SIGN TU +12306 ; [.2CEE.0020.0002.12306] # CUNEIFORM SIGN TUG2 +12307 ; [.2CEF.0020.0002.12307] # CUNEIFORM SIGN TUK +12308 ; [.2CF0.0020.0002.12308] # CUNEIFORM SIGN TUM +12309 ; [.2CF1.0020.0002.12309] # CUNEIFORM SIGN TUR +1230A ; [.2CF2.0020.0002.1230A] # CUNEIFORM SIGN TUR OVER TUR ZA OVER ZA +1230B ; [.2CF3.0020.0002.1230B] # CUNEIFORM SIGN U +1230C ; [.2CF4.0020.0002.1230C] # CUNEIFORM SIGN U GUD +1230D ; [.2CF5.0020.0002.1230D] # CUNEIFORM SIGN U U U +1230E ; [.2CF6.0020.0002.1230E] # CUNEIFORM SIGN U OVER U PA OVER PA GAR OVER GAR +1230F ; [.2CF7.0020.0002.1230F] # CUNEIFORM SIGN U OVER U SUR OVER SUR +12310 ; [.2CF8.0020.0002.12310] # CUNEIFORM SIGN U OVER U U REVERSED OVER U REVERSED +12311 ; [.2CF9.0020.0002.12311] # CUNEIFORM SIGN U2 +12312 ; [.2CFA.0020.0002.12312] # CUNEIFORM SIGN UB +12313 ; [.2CFB.0020.0002.12313] # CUNEIFORM SIGN UD +12314 ; [.2CFC.0020.0002.12314] # CUNEIFORM SIGN UD KUSHU2 +12315 ; [.2CFD.0020.0002.12315] # CUNEIFORM SIGN UD TIMES BAD +12316 ; [.2CFE.0020.0002.12316] # CUNEIFORM SIGN UD TIMES MI +12317 ; [.2CFF.0020.0002.12317] # CUNEIFORM SIGN UD TIMES U PLUS U PLUS U +12318 ; [.2D00.0020.0002.12318] # CUNEIFORM SIGN UD TIMES U PLUS U PLUS U GUNU +12319 ; [.2D01.0020.0002.12319] # CUNEIFORM SIGN UD GUNU +1231A ; [.2D02.0020.0002.1231A] # CUNEIFORM SIGN UD SHESHIG +1231B ; [.2D03.0020.0002.1231B] # CUNEIFORM SIGN UD SHESHIG TIMES BAD +1231C ; [.2D04.0020.0002.1231C] # CUNEIFORM SIGN UDUG +1231D ; [.2D05.0020.0002.1231D] # CUNEIFORM SIGN UM +1231E ; [.2D06.0020.0002.1231E] # CUNEIFORM SIGN UM TIMES LAGAB +1231F ; [.2D07.0020.0002.1231F] # CUNEIFORM SIGN UM TIMES ME PLUS DA +12320 ; [.2D08.0020.0002.12320] # CUNEIFORM SIGN UM TIMES SHA3 +12321 ; [.2D09.0020.0002.12321] # CUNEIFORM SIGN UM TIMES U +12322 ; [.2D0A.0020.0002.12322] # CUNEIFORM SIGN UMBIN +12323 ; [.2D0B.0020.0002.12323] # CUNEIFORM SIGN UMUM +12324 ; [.2D0C.0020.0002.12324] # CUNEIFORM SIGN UMUM TIMES KASKAL +12325 ; [.2D0D.0020.0002.12325] # CUNEIFORM SIGN UMUM TIMES PA +12326 ; [.2D0E.0020.0002.12326] # CUNEIFORM SIGN UN +12327 ; [.2D0F.0020.0002.12327] # CUNEIFORM SIGN UN GUNU +12328 ; [.2D10.0020.0002.12328] # CUNEIFORM SIGN UR +12329 ; [.2D11.0020.0002.12329] # CUNEIFORM SIGN UR CROSSING UR +1232A ; [.2D12.0020.0002.1232A] # CUNEIFORM SIGN UR SHESHIG +1232B ; [.2D13.0020.0002.1232B] # CUNEIFORM SIGN UR2 +1232C ; [.2D14.0020.0002.1232C] # CUNEIFORM SIGN UR2 TIMES A PLUS HA +1232D ; [.2D15.0020.0002.1232D] # CUNEIFORM SIGN UR2 TIMES A PLUS NA +1232E ; [.2D16.0020.0002.1232E] # CUNEIFORM SIGN UR2 TIMES AL +1232F ; [.2D17.0020.0002.1232F] # CUNEIFORM SIGN UR2 TIMES HA +12330 ; [.2D18.0020.0002.12330] # CUNEIFORM SIGN UR2 TIMES NUN +12331 ; [.2D19.0020.0002.12331] # CUNEIFORM SIGN UR2 TIMES U2 +12332 ; [.2D1A.0020.0002.12332] # CUNEIFORM SIGN UR2 TIMES U2 PLUS ASH +12333 ; [.2D1B.0020.0002.12333] # CUNEIFORM SIGN UR2 TIMES U2 PLUS BI +12334 ; [.2D1C.0020.0002.12334] # CUNEIFORM SIGN UR4 +12335 ; [.2D1D.0020.0002.12335] # CUNEIFORM SIGN URI +12336 ; [.2D1E.0020.0002.12336] # CUNEIFORM SIGN URI3 +12337 ; [.2D1F.0020.0002.12337] # CUNEIFORM SIGN URU +12338 ; [.2D20.0020.0002.12338] # CUNEIFORM SIGN URU TIMES A +12339 ; [.2D21.0020.0002.12339] # CUNEIFORM SIGN URU TIMES ASHGAB +1233A ; [.2D22.0020.0002.1233A] # CUNEIFORM SIGN URU TIMES BAR +1233B ; [.2D23.0020.0002.1233B] # CUNEIFORM SIGN URU TIMES DUN +1233C ; [.2D24.0020.0002.1233C] # CUNEIFORM SIGN URU TIMES GA +1233D ; [.2D25.0020.0002.1233D] # CUNEIFORM SIGN URU TIMES GAL +1233E ; [.2D26.0020.0002.1233E] # CUNEIFORM SIGN URU TIMES GAN2 TENU +1233F ; [.2D27.0020.0002.1233F] # CUNEIFORM SIGN URU TIMES GAR +12340 ; [.2D28.0020.0002.12340] # CUNEIFORM SIGN URU TIMES GU +12341 ; [.2D29.0020.0002.12341] # CUNEIFORM SIGN URU TIMES HA +12342 ; [.2D2A.0020.0002.12342] # CUNEIFORM SIGN URU TIMES IGI +12343 ; [.2D2B.0020.0002.12343] # CUNEIFORM SIGN URU TIMES IM +12344 ; [.2D2C.0020.0002.12344] # CUNEIFORM SIGN URU TIMES ISH +12345 ; [.2D2D.0020.0002.12345] # CUNEIFORM SIGN URU TIMES KI +12346 ; [.2D2E.0020.0002.12346] # CUNEIFORM SIGN URU TIMES LUM +12347 ; [.2D2F.0020.0002.12347] # CUNEIFORM SIGN URU TIMES MIN +12348 ; [.2D30.0020.0002.12348] # CUNEIFORM SIGN URU TIMES PA +12349 ; [.2D31.0020.0002.12349] # CUNEIFORM SIGN URU TIMES SHE +1234A ; [.2D32.0020.0002.1234A] # CUNEIFORM SIGN URU TIMES SIG4 +1234B ; [.2D33.0020.0002.1234B] # CUNEIFORM SIGN URU TIMES TU +1234C ; [.2D34.0020.0002.1234C] # CUNEIFORM SIGN URU TIMES U PLUS GUD +1234D ; [.2D35.0020.0002.1234D] # CUNEIFORM SIGN URU TIMES UD +1234E ; [.2D36.0020.0002.1234E] # CUNEIFORM SIGN URU TIMES URUDA +1234F ; [.2D37.0020.0002.1234F] # CUNEIFORM SIGN URUDA +12350 ; [.2D38.0020.0002.12350] # CUNEIFORM SIGN URUDA TIMES U +12351 ; [.2D39.0020.0002.12351] # CUNEIFORM SIGN USH +12352 ; [.2D3A.0020.0002.12352] # CUNEIFORM SIGN USH TIMES A +12353 ; [.2D3B.0020.0002.12353] # CUNEIFORM SIGN USH TIMES KU +12354 ; [.2D3C.0020.0002.12354] # CUNEIFORM SIGN USH TIMES KUR +12355 ; [.2D3D.0020.0002.12355] # CUNEIFORM SIGN USH TIMES TAK4 +12356 ; [.2D3E.0020.0002.12356] # CUNEIFORM SIGN USHX +12357 ; [.2D3F.0020.0002.12357] # CUNEIFORM SIGN USH2 +12358 ; [.2D40.0020.0002.12358] # CUNEIFORM SIGN USHUMX +12359 ; [.2D41.0020.0002.12359] # CUNEIFORM SIGN UTUKI +1235A ; [.2D42.0020.0002.1235A] # CUNEIFORM SIGN UZ3 +1235B ; [.2D43.0020.0002.1235B] # CUNEIFORM SIGN UZ3 TIMES KASKAL +1235C ; [.2D44.0020.0002.1235C] # CUNEIFORM SIGN UZU +1235D ; [.2D45.0020.0002.1235D] # CUNEIFORM SIGN ZA +1235E ; [.2D46.0020.0002.1235E] # CUNEIFORM SIGN ZA TENU +1235F ; [.2D47.0020.0002.1235F] # CUNEIFORM SIGN ZA SQUARED TIMES KUR +12360 ; [.2D48.0020.0002.12360] # CUNEIFORM SIGN ZAG +12361 ; [.2D49.0020.0002.12361] # CUNEIFORM SIGN ZAMX +12362 ; [.2D4A.0020.0002.12362] # CUNEIFORM SIGN ZE2 +12363 ; [.2D4B.0020.0002.12363] # CUNEIFORM SIGN ZI +12364 ; [.2D4C.0020.0002.12364] # CUNEIFORM SIGN ZI OVER ZI +12365 ; [.2D4D.0020.0002.12365] # CUNEIFORM SIGN ZI3 +12366 ; [.2D4E.0020.0002.12366] # CUNEIFORM SIGN ZIB +12367 ; [.2D4F.0020.0002.12367] # CUNEIFORM SIGN ZIB KABA TENU +12368 ; [.2D50.0020.0002.12368] # CUNEIFORM SIGN ZIG +12369 ; [.2D51.0020.0002.12369] # CUNEIFORM SIGN ZIZ2 +1236A ; [.2D52.0020.0002.1236A] # CUNEIFORM SIGN ZU +1236B ; [.2D53.0020.0002.1236B] # CUNEIFORM SIGN ZU5 +1236C ; [.2D54.0020.0002.1236C] # CUNEIFORM SIGN ZU5 TIMES A +1236D ; [.2D55.0020.0002.1236D] # CUNEIFORM SIGN ZUBUR +1236E ; [.2D56.0020.0002.1236E] # CUNEIFORM SIGN ZUM +2F00 ; [.FB40.0020.0004.4E00][.CE00.0000.0000.4E00] # KANGXI RADICAL ONE; QQK +3220 ; [*02B1.0020.0004.3220][.FB40.0020.0004.4E00][.CE00.0000.0000.4E00][*02B2.0020.001F.3220] # PARENTHESIZED IDEOGRAPH ONE; QQKN +3280 ; [.FB40.0020.0006.4E00][.CE00.0000.0000.4E00] # CIRCLED IDEOGRAPH ONE; QQK +3192 ; [.FB40.0020.0014.4E00][.CE00.0000.0000.4E00] # IDEOGRAPHIC ANNOTATION ONE MARK; QQK +319C ; [.FB40.0020.0014.4E01][.CE01.0000.0000.4E01] # IDEOGRAPHIC ANNOTATION FOURTH MARK; QQK +3226 ; [*02B1.0020.0004.3226][.FB40.0020.0004.4E03][.CE03.0000.0000.4E03][*02B2.0020.001F.3226] # PARENTHESIZED IDEOGRAPH SEVEN; QQKN +3286 ; [.FB40.0020.0006.4E03][.CE03.0000.0000.4E03] # CIRCLED IDEOGRAPH SEVEN; QQK +3222 ; [*02B1.0020.0004.3222][.FB40.0020.0004.4E09][.CE09.0000.0000.4E09][*02B2.0020.001F.3222] # PARENTHESIZED IDEOGRAPH THREE; QQKN +3282 ; [.FB40.0020.0006.4E09][.CE09.0000.0000.4E09] # CIRCLED IDEOGRAPH THREE; QQK +3194 ; [.FB40.0020.0014.4E09][.CE09.0000.0000.4E09] # IDEOGRAPHIC ANNOTATION THREE MARK; QQK +32A4 ; [.FB40.0020.0006.4E0A][.CE0A.0000.0000.4E0A] # CIRCLED IDEOGRAPH HIGH; QQK +3196 ; [.FB40.0020.0014.4E0A][.CE0A.0000.0000.4E0A] # IDEOGRAPHIC ANNOTATION TOP MARK; QQK +32A6 ; [.FB40.0020.0006.4E0B][.CE0B.0000.0000.4E0B] # CIRCLED IDEOGRAPH LOW; QQK +3198 ; [.FB40.0020.0014.4E0B][.CE0B.0000.0000.4E0B] # IDEOGRAPHIC ANNOTATION BOTTOM MARK; QQK +F967 ; [.FB40.0020.0002.4E0D][.CE0D.0000.0000.4E0D] # CJK COMPATIBILITY IDEOGRAPH-F967; QQC +319B ; [.FB40.0020.0014.4E19][.CE19.0000.0000.4E19] # IDEOGRAPHIC ANNOTATION THIRD MARK; QQK +FA70 ; [.FB40.0020.0002.4E26][.CE26.0000.0000.4E26] # CJK COMPATIBILITY IDEOGRAPH-FA70; QQC +2F01 ; [.FB40.0020.0004.4E28][.CE28.0000.0000.4E28] # KANGXI RADICAL LINE; QQK +2EA6 ; [.FB40.0020.0004.4E2C][.CE2C.0000.0000.4E2C] # CJK RADICAL SIMPLIFIED HALF TREE TRUNK; QQK +32A5 ; [.FB40.0020.0006.4E2D][.CE2D.0000.0000.4E2D] # CIRCLED IDEOGRAPH CENTRE; QQK +3197 ; [.FB40.0020.0014.4E2D][.CE2D.0000.0000.4E2D] # IDEOGRAPHIC ANNOTATION MIDDLE MARK; QQK +F905 ; [.FB40.0020.0002.4E32][.CE32.0000.0000.4E32] # CJK COMPATIBILITY IDEOGRAPH-F905; QQC +2F02 ; [.FB40.0020.0004.4E36][.CE36.0000.0000.4E36] # KANGXI RADICAL DOT; QQK +2E80 ; [.FB40.0020.0004.4E36][.CE36.0000.0000.4E36][.0000.0199.001F.2E80] # CJK RADICAL REPEAT; QQKN +2F801 ; [.FB40.0020.0002.4E38][.CE38.0000.0000.4E38] # CJK COMPATIBILITY IDEOGRAPH-2F801; QQC +F95E ; [.FB40.0020.0002.4E39][.CE39.0000.0000.4E39] # CJK COMPATIBILITY IDEOGRAPH-F95E; QQC +2F800 ; [.FB40.0020.0002.4E3D][.CE3D.0000.0000.4E3D] # CJK COMPATIBILITY IDEOGRAPH-2F800; QQC +2F03 ; [.FB40.0020.0004.4E3F][.CE3F.0000.0000.4E3F] # KANGXI RADICAL SLASH; QQK +2F802 ; [.FB40.0020.0002.4E41][.CE41.0000.0000.4E41] # CJK COMPATIBILITY IDEOGRAPH-2F802; QQC +2F04 ; [.FB40.0020.0004.4E59][.CE59.0000.0000.4E59] # KANGXI RADICAL SECOND; QQK +319A ; [.FB40.0020.0014.4E59][.CE59.0000.0000.4E59] # IDEOGRAPHIC ANNOTATION SECOND MARK; QQK +2E84 ; [.FB40.0020.0004.4E59][.CE59.0000.0000.4E59][.0000.0199.001F.2E84] # CJK RADICAL SECOND THREE; QQKN +2E83 ; [.FB40.0020.0004.4E5A][.CE5A.0000.0000.4E5A] # CJK RADICAL SECOND TWO; QQK +2E82 ; [.FB40.0020.0004.4E5B][.CE5B.0000.0000.4E5B] # CJK RADICAL SECOND ONE; QQK +3228 ; [*02B1.0020.0004.3228][.FB40.0020.0004.4E5D][.CE5D.0000.0000.4E5D][*02B2.0020.001F.3228] # PARENTHESIZED IDEOGRAPH NINE; QQKN +3288 ; [.FB40.0020.0006.4E5D][.CE5D.0000.0000.4E5D] # CIRCLED IDEOGRAPH NINE; QQK +F91B ; [.FB40.0020.0002.4E82][.CE82.0000.0000.4E82] # CJK COMPATIBILITY IDEOGRAPH-F91B; QQC +2F05 ; [.FB40.0020.0004.4E85][.CE85.0000.0000.4E85] # KANGXI RADICAL HOOK; QQK +F9BA ; [.FB40.0020.0002.4E86][.CE86.0000.0000.4E86] # CJK COMPATIBILITY IDEOGRAPH-F9BA; QQC +2F06 ; [.FB40.0020.0004.4E8C][.CE8C.0000.0000.4E8C] # KANGXI RADICAL TWO; QQK +3221 ; [*02B1.0020.0004.3221][.FB40.0020.0004.4E8C][.CE8C.0000.0000.4E8C][*02B2.0020.001F.3221] # PARENTHESIZED IDEOGRAPH TWO; QQKN +3281 ; [.FB40.0020.0006.4E8C][.CE8C.0000.0000.4E8C] # CIRCLED IDEOGRAPH TWO; QQK +3193 ; [.FB40.0020.0014.4E8C][.CE8C.0000.0000.4E8C] # IDEOGRAPHIC ANNOTATION TWO MARK; QQK +3224 ; [*02B1.0020.0004.3224][.FB40.0020.0004.4E94][.CE94.0000.0000.4E94][*02B2.0020.001F.3224] # PARENTHESIZED IDEOGRAPH FIVE; QQKN +3284 ; [.FB40.0020.0006.4E94][.CE94.0000.0000.4E94] # CIRCLED IDEOGRAPH FIVE; QQK +2F07 ; [.FB40.0020.0004.4EA0][.CEA0.0000.0000.4EA0] # KANGXI RADICAL LID; QQK +F977 ; [.FB40.0020.0002.4EAE][.CEAE.0000.0000.4EAE] # CJK COMPATIBILITY IDEOGRAPH-F977; QQC +2F08 ; [.FB40.0020.0004.4EBA][.CEBA.0000.0000.4EBA] # KANGXI RADICAL MAN; QQK +319F ; [.FB40.0020.0014.4EBA][.CEBA.0000.0000.4EBA] # IDEOGRAPHIC ANNOTATION MAN MARK; QQK +2E85 ; [.FB40.0020.0004.4EBB][.CEBB.0000.0000.4EBB] # CJK RADICAL PERSON; QQK +F9FD ; [.FB40.0020.0002.4EC0][.CEC0.0000.0000.4EC0] # CJK COMPATIBILITY IDEOGRAPH-F9FD; QQC +2F819 ; [.FB40.0020.0002.4ECC][.CECC.0000.0000.4ECC] # CJK COMPATIBILITY IDEOGRAPH-2F819; QQC +3239 ; [*02B1.0020.0004.3239][.FB40.0020.0004.4EE3][.CEE3.0000.0000.4EE3][*02B2.0020.001F.3239] # PARENTHESIZED IDEOGRAPH REPRESENT; QQKN +F9A8 ; [.FB40.0020.0002.4EE4][.CEE4.0000.0000.4EE4] # CJK COMPATIBILITY IDEOGRAPH-F9A8; QQC +323D ; [*02B1.0020.0004.323D][.FB40.0020.0004.4F01][.CF01.0000.0000.4F01][*02B2.0020.001F.323D] # PARENTHESIZED IDEOGRAPH ENTERPRISE; QQKN +32AD ; [.FB40.0020.0006.4F01][.CF01.0000.0000.4F01] # CIRCLED IDEOGRAPH ENTERPRISE; QQK +3241 ; [*02B1.0020.0004.3241][.FB40.0020.0004.4F11][.CF11.0000.0000.4F11][*02B2.0020.001F.3241] # PARENTHESIZED IDEOGRAPH REST; QQKN +32A1 ; [.FB40.0020.0006.4F11][.CF11.0000.0000.4F11] # CIRCLED IDEOGRAPH REST; QQK +2F804 ; [.FB40.0020.0002.4F60][.CF60.0000.0000.4F60] # CJK COMPATIBILITY IDEOGRAPH-2F804; QQC +FA73 ; [.FB40.0020.0002.4F80][.CF80.0000.0000.4F80] # CJK COMPATIBILITY IDEOGRAPH-FA73; QQC +F92D ; [.FB40.0020.0002.4F86][.CF86.0000.0000.4F86] # CJK COMPATIBILITY IDEOGRAPH-F92D; QQC +F9B5 ; [.FB40.0020.0002.4F8B][.CF8B.0000.0000.4F8B] # CJK COMPATIBILITY IDEOGRAPH-F9B5; QQC +FA30 ; [.FB40.0020.0002.4FAE][.CFAE.0000.0000.4FAE] # CJK COMPATIBILITY IDEOGRAPH-FA30; QQC +2F805 ; [.FB40.0020.0002.4FAE][.CFAE.0000.0000.4FAE] # CJK COMPATIBILITY IDEOGRAPH-2F805; QQC +2F806 ; [.FB40.0020.0002.4FBB][.CFBB.0000.0000.4FBB] # CJK COMPATIBILITY IDEOGRAPH-2F806; QQC +F965 ; [.FB40.0020.0002.4FBF][.CFBF.0000.0000.4FBF] # CJK COMPATIBILITY IDEOGRAPH-F965; QQC +2F807 ; [.FB40.0020.0002.5002][.D002.0000.0000.5002] # CJK COMPATIBILITY IDEOGRAPH-2F807; QQC +F9D4 ; [.FB40.0020.0002.502B][.D02B.0000.0000.502B] # CJK COMPATIBILITY IDEOGRAPH-F9D4; QQC +2F808 ; [.FB40.0020.0002.507A][.D07A.0000.0000.507A] # CJK COMPATIBILITY IDEOGRAPH-2F808; QQC +2F809 ; [.FB40.0020.0002.5099][.D099.0000.0000.5099] # CJK COMPATIBILITY IDEOGRAPH-2F809; QQC +2F80B ; [.FB40.0020.0002.50CF][.D0CF.0000.0000.50CF] # CJK COMPATIBILITY IDEOGRAPH-2F80B; QQC +F9BB ; [.FB40.0020.0002.50DA][.D0DA.0000.0000.50DA] # CJK COMPATIBILITY IDEOGRAPH-F9BB; QQC +FA31 ; [.FB40.0020.0002.50E7][.D0E7.0000.0000.50E7] # CJK COMPATIBILITY IDEOGRAPH-FA31; QQC +2F80A ; [.FB40.0020.0002.50E7][.D0E7.0000.0000.50E7] # CJK COMPATIBILITY IDEOGRAPH-2F80A; QQC +329D ; [.FB40.0020.0006.512A][.D12A.0000.0000.512A] # CIRCLED IDEOGRAPH EXCELLENT; QQK +2F09 ; [.FB40.0020.0004.513F][.D13F.0000.0000.513F] # KANGXI RADICAL LEGS; QQK +FA0C ; [.FB40.0020.0002.5140][.D140.0000.0000.5140] # CJK COMPATIBILITY IDEOGRAPH-FA0C; QQC +FA74 ; [.FB40.0020.0002.5145][.D145.0000.0000.5145] # CJK COMPATIBILITY IDEOGRAPH-FA74; QQC +FA32 ; [.FB40.0020.0002.514D][.D14D.0000.0000.514D] # CJK COMPATIBILITY IDEOGRAPH-FA32; QQC +2F80E ; [.FB40.0020.0002.514D][.D14D.0000.0000.514D] # CJK COMPATIBILITY IDEOGRAPH-2F80E; QQC +2F80F ; [.FB40.0020.0002.5154][.D154.0000.0000.5154] # CJK COMPATIBILITY IDEOGRAPH-2F80F; QQC +2F810 ; [.FB40.0020.0002.5164][.D164.0000.0000.5164] # CJK COMPATIBILITY IDEOGRAPH-2F810; QQC +2F0A ; [.FB40.0020.0004.5165][.D165.0000.0000.5165] # KANGXI RADICAL ENTER; QQK +2F814 ; [.FB40.0020.0002.5167][.D167.0000.0000.5167] # CJK COMPATIBILITY IDEOGRAPH-2F814; QQC +FA72 ; [.FB40.0020.0002.5168][.D168.0000.0000.5168] # CJK COMPATIBILITY IDEOGRAPH-FA72; QQC +F978 ; [.FB40.0020.0002.5169][.D169.0000.0000.5169] # CJK COMPATIBILITY IDEOGRAPH-F978; QQC +2F0B ; [.FB40.0020.0004.516B][.D16B.0000.0000.516B] # KANGXI RADICAL EIGHT; QQK +3227 ; [*02B1.0020.0004.3227][.FB40.0020.0004.516B][.D16B.0000.0000.516B][*02B2.0020.001F.3227] # PARENTHESIZED IDEOGRAPH EIGHT; QQKN +3287 ; [.FB40.0020.0006.516B][.D16B.0000.0000.516B] # CIRCLED IDEOGRAPH EIGHT; QQK +F9D1 ; [.FB40.0020.0002.516D][.D16D.0000.0000.516D] # CJK COMPATIBILITY IDEOGRAPH-F9D1; QQC +3225 ; [*02B1.0020.0004.3225][.FB40.0020.0004.516D][.D16D.0000.0000.516D][*02B2.0020.001F.3225] # PARENTHESIZED IDEOGRAPH SIX; QQKN +3285 ; [.FB40.0020.0006.516D][.D16D.0000.0000.516D] # CIRCLED IDEOGRAPH SIX; QQK +2F811 ; [.FB40.0020.0002.5177][.D177.0000.0000.5177] # CJK COMPATIBILITY IDEOGRAPH-2F811; QQC +FA75 ; [.FB40.0020.0002.5180][.D180.0000.0000.5180] # CJK COMPATIBILITY IDEOGRAPH-FA75; QQC +2F0C ; [.FB40.0020.0004.5182][.D182.0000.0000.5182] # KANGXI RADICAL DOWN BOX; QQK +2E86 ; [.FB40.0020.0004.5182][.D182.0000.0000.5182][.0000.0199.001F.2E86] # CJK RADICAL BOX; QQKN +2F815 ; [.FB40.0020.0002.518D][.D18D.0000.0000.518D] # CJK COMPATIBILITY IDEOGRAPH-2F815; QQC +2F8D2 ; [.FB40.0020.0002.5192][.D192.0000.0000.5192] # CJK COMPATIBILITY IDEOGRAPH-2F8D2; QQC +2F8D3 ; [.FB40.0020.0002.5195][.D195.0000.0000.5195] # CJK COMPATIBILITY IDEOGRAPH-2F8D3; QQC +2F0D ; [.FB40.0020.0004.5196][.D196.0000.0000.5196] # KANGXI RADICAL COVER; QQK +2F817 ; [.FB40.0020.0002.5197][.D197.0000.0000.5197] # CJK COMPATIBILITY IDEOGRAPH-2F817; QQC +32A2 ; [.FB40.0020.0006.5199][.D199.0000.0000.5199] # CIRCLED IDEOGRAPH COPY; QQK +2F818 ; [.FB40.0020.0002.51A4][.D1A4.0000.0000.51A4] # CJK COMPATIBILITY IDEOGRAPH-2F818; QQC +2F0E ; [.FB40.0020.0004.51AB][.D1AB.0000.0000.51AB] # KANGXI RADICAL ICE; QQK +2F81A ; [.FB40.0020.0002.51AC][.D1AC.0000.0000.51AC] # CJK COMPATIBILITY IDEOGRAPH-2F81A; QQC +FA71 ; [.FB40.0020.0002.51B5][.D1B5.0000.0000.51B5] # CJK COMPATIBILITY IDEOGRAPH-FA71; QQC +2F81B ; [.FB40.0020.0002.51B5][.D1B5.0000.0000.51B5] # CJK COMPATIBILITY IDEOGRAPH-2F81B; QQC +F92E ; [.FB40.0020.0002.51B7][.D1B7.0000.0000.51B7] # CJK COMPATIBILITY IDEOGRAPH-F92E; QQC +F979 ; [.FB40.0020.0002.51C9][.D1C9.0000.0000.51C9] # CJK COMPATIBILITY IDEOGRAPH-F979; QQC +F955 ; [.FB40.0020.0002.51CC][.D1CC.0000.0000.51CC] # CJK COMPATIBILITY IDEOGRAPH-F955; QQC +F954 ; [.FB40.0020.0002.51DC][.D1DC.0000.0000.51DC] # CJK COMPATIBILITY IDEOGRAPH-F954; QQC +FA15 ; [.FB40.0020.0002.51DE][.D1DE.0000.0000.51DE] # CJK COMPATIBILITY IDEOGRAPH-FA15; QQC +2F0F ; [.FB40.0020.0004.51E0][.D1E0.0000.0000.51E0] # KANGXI RADICAL TABLE; QQK +2E87 ; [.FB40.0020.0004.51E0][.D1E0.0000.0000.51E0][.0000.0199.001F.2E87] # CJK RADICAL TABLE; QQKN +2F81D ; [.FB40.0020.0002.51F5][.D1F5.0000.0000.51F5] # CJK COMPATIBILITY IDEOGRAPH-2F81D; QQC +2F10 ; [.FB40.0020.0004.51F5][.D1F5.0000.0000.51F5] # KANGXI RADICAL OPEN BOX; QQK +2F11 ; [.FB40.0020.0004.5200][.D200.0000.0000.5200] # KANGXI RADICAL KNIFE; QQK +2E88 ; [.FB40.0020.0004.5200][.D200.0000.0000.5200][.0000.0199.001F.2E88] # CJK RADICAL KNIFE ONE; QQKN +2E89 ; [.FB40.0020.0004.5202][.D202.0000.0000.5202] # CJK RADICAL KNIFE TWO; QQK +2F81E ; [.FB40.0020.0002.5203][.D203.0000.0000.5203] # CJK COMPATIBILITY IDEOGRAPH-2F81E; QQC +FA00 ; [.FB40.0020.0002.5207][.D207.0000.0000.5207] # CJK COMPATIBILITY IDEOGRAPH-FA00; QQC +2F850 ; [.FB40.0020.0002.5207][.D207.0000.0000.5207] # CJK COMPATIBILITY IDEOGRAPH-2F850; QQC +F99C ; [.FB40.0020.0002.5217][.D217.0000.0000.5217] # CJK COMPATIBILITY IDEOGRAPH-F99C; QQC +F9DD ; [.FB40.0020.0002.5229][.D229.0000.0000.5229] # CJK COMPATIBILITY IDEOGRAPH-F9DD; QQC +F9FF ; [.FB40.0020.0002.523A][.D23A.0000.0000.523A] # CJK COMPATIBILITY IDEOGRAPH-F9FF; QQC +2F820 ; [.FB40.0020.0002.523B][.D23B.0000.0000.523B] # CJK COMPATIBILITY IDEOGRAPH-2F820; QQC +2F821 ; [.FB40.0020.0002.5246][.D246.0000.0000.5246] # CJK COMPATIBILITY IDEOGRAPH-2F821; QQC +2F822 ; [.FB40.0020.0002.5272][.D272.0000.0000.5272] # CJK COMPATIBILITY IDEOGRAPH-2F822; QQC +2F823 ; [.FB40.0020.0002.5277][.D277.0000.0000.5277] # CJK COMPATIBILITY IDEOGRAPH-2F823; QQC +F9C7 ; [.FB40.0020.0002.5289][.D289.0000.0000.5289] # CJK COMPATIBILITY IDEOGRAPH-F9C7; QQC +F98A ; [.FB40.0020.0002.529B][.D29B.0000.0000.529B] # CJK COMPATIBILITY IDEOGRAPH-F98A; QQC +2F12 ; [.FB40.0020.0004.529B][.D29B.0000.0000.529B] # KANGXI RADICAL POWER; QQK +F99D ; [.FB40.0020.0002.52A3][.D2A3.0000.0000.52A3] # CJK COMPATIBILITY IDEOGRAPH-F99D; QQC +2F992 ; [.FB40.0020.0002.52B3][.D2B3.0000.0000.52B3] # CJK COMPATIBILITY IDEOGRAPH-2F992; QQC +3238 ; [*02B1.0020.0004.3238][.FB40.0020.0004.52B4][.D2B4.0000.0000.52B4][*02B2.0020.001F.3238] # PARENTHESIZED IDEOGRAPH LABOR; QQKN +3298 ; [.FB40.0020.0006.52B4][.D2B4.0000.0000.52B4] # CIRCLED IDEOGRAPH LABOR; QQK +FA76 ; [.FB40.0020.0002.52C7][.D2C7.0000.0000.52C7] # CJK COMPATIBILITY IDEOGRAPH-FA76; QQC +2F825 ; [.FB40.0020.0002.52C7][.D2C7.0000.0000.52C7] # CJK COMPATIBILITY IDEOGRAPH-2F825; QQC +FA33 ; [.FB40.0020.0002.52C9][.D2C9.0000.0000.52C9] # CJK COMPATIBILITY IDEOGRAPH-FA33; QQC +2F826 ; [.FB40.0020.0002.52C9][.D2C9.0000.0000.52C9] # CJK COMPATIBILITY IDEOGRAPH-2F826; QQC +F952 ; [.FB40.0020.0002.52D2][.D2D2.0000.0000.52D2] # CJK COMPATIBILITY IDEOGRAPH-F952; QQC +F92F ; [.FB40.0020.0002.52DE][.D2DE.0000.0000.52DE] # CJK COMPATIBILITY IDEOGRAPH-F92F; QQC +FA34 ; [.FB40.0020.0002.52E4][.D2E4.0000.0000.52E4] # CJK COMPATIBILITY IDEOGRAPH-FA34; QQC +2F827 ; [.FB40.0020.0002.52E4][.D2E4.0000.0000.52E4] # CJK COMPATIBILITY IDEOGRAPH-2F827; QQC +F97F ; [.FB40.0020.0002.52F5][.D2F5.0000.0000.52F5] # CJK COMPATIBILITY IDEOGRAPH-F97F; QQC +2F13 ; [.FB40.0020.0004.52F9][.D2F9.0000.0000.52F9] # KANGXI RADICAL WRAP; QQK +FA77 ; [.FB40.0020.0002.52FA][.D2FA.0000.0000.52FA] # CJK COMPATIBILITY IDEOGRAPH-FA77; QQC +2F828 ; [.FB40.0020.0002.52FA][.D2FA.0000.0000.52FA] # CJK COMPATIBILITY IDEOGRAPH-2F828; QQC +2F829 ; [.FB40.0020.0002.5305][.D305.0000.0000.5305] # CJK COMPATIBILITY IDEOGRAPH-2F829; QQC +2F82A ; [.FB40.0020.0002.5306][.D306.0000.0000.5306] # CJK COMPATIBILITY IDEOGRAPH-2F82A; QQC +2F14 ; [.FB40.0020.0004.5315][.D315.0000.0000.5315] # KANGXI RADICAL SPOON; QQK +F963 ; [.FB40.0020.0002.5317][.D317.0000.0000.5317] # CJK COMPATIBILITY IDEOGRAPH-F963; QQC +2F82B ; [.FB40.0020.0002.5317][.D317.0000.0000.5317] # CJK COMPATIBILITY IDEOGRAPH-2F82B; QQC +2F15 ; [.FB40.0020.0004.531A][.D31A.0000.0000.531A] # KANGXI RADICAL RIGHT OPEN BOX; QQK +2F16 ; [.FB40.0020.0004.5338][.D338.0000.0000.5338] # KANGXI RADICAL HIDING ENCLOSURE; QQK +32A9 ; [.FB40.0020.0006.533B][.D33B.0000.0000.533B] # CIRCLED IDEOGRAPH MEDICINE; QQK +F9EB ; [.FB40.0020.0002.533F][.D33F.0000.0000.533F] # CJK COMPATIBILITY IDEOGRAPH-F9EB; QQC +2F17 ; [.FB40.0020.0004.5341][.D341.0000.0000.5341] # KANGXI RADICAL TEN; QQK +3038 ; [.FB40.0020.0004.5341][.D341.0000.0000.5341] # HANGZHOU NUMERAL TEN; QQK +3229 ; [*02B1.0020.0004.3229][.FB40.0020.0004.5341][.D341.0000.0000.5341][*02B2.0020.001F.3229] # PARENTHESIZED IDEOGRAPH TEN; QQKN +3289 ; [.FB40.0020.0006.5341][.D341.0000.0000.5341] # CIRCLED IDEOGRAPH TEN; QQK +3039 ; [.FB40.0020.0004.5344][.D344.0000.0000.5344] # HANGZHOU NUMERAL TWENTY; QQK +303A ; [.FB40.0020.0004.5345][.D345.0000.0000.5345] # HANGZHOU NUMERAL THIRTY; QQK +2F82C ; [.FB40.0020.0002.5349][.D349.0000.0000.5349] # CJK COMPATIBILITY IDEOGRAPH-2F82C; QQC +FA35 ; [.FB40.0020.0002.5351][.D351.0000.0000.5351] # CJK COMPATIBILITY IDEOGRAPH-FA35; QQC +2F82D ; [.FB40.0020.0002.5351][.D351.0000.0000.5351] # CJK COMPATIBILITY IDEOGRAPH-2F82D; QQC +323F ; [*02B1.0020.0004.323F][.FB40.0020.0004.5354][.D354.0000.0000.5354][*02B2.0020.001F.323F] # PARENTHESIZED IDEOGRAPH ALLIANCE; QQKN +32AF ; [.FB40.0020.0006.5354][.D354.0000.0000.5354] # CIRCLED IDEOGRAPH ALLIANCE; QQK +2F82E ; [.FB40.0020.0002.535A][.D35A.0000.0000.535A] # CJK COMPATIBILITY IDEOGRAPH-2F82E; QQC +2F18 ; [.FB40.0020.0004.535C][.D35C.0000.0000.535C] # KANGXI RADICAL DIVINATION; QQK +2E8A ; [.FB40.0020.0004.535C][.D35C.0000.0000.535C][.0000.0199.001F.2E8A] # CJK RADICAL DIVINATION; QQKN +2F19 ; [.FB40.0020.0004.5369][.D369.0000.0000.5369] # KANGXI RADICAL SEAL; QQK +2E8B ; [.FB40.0020.0004.5369][.D369.0000.0000.5369][.0000.0199.001F.2E8B] # CJK RADICAL SEAL; QQKN +329E ; [.FB40.0020.0006.5370][.D370.0000.0000.5370] # CIRCLED IDEOGRAPH PRINT; QQK +2F82F ; [.FB40.0020.0002.5373][.D373.0000.0000.5373] # CJK COMPATIBILITY IDEOGRAPH-2F82F; QQC +F91C ; [.FB40.0020.0002.5375][.D375.0000.0000.5375] # CJK COMPATIBILITY IDEOGRAPH-F91C; QQC +2F830 ; [.FB40.0020.0002.537D][.D37D.0000.0000.537D] # CJK COMPATIBILITY IDEOGRAPH-2F830; QQC +2F831 ; [.FB40.0020.0002.537F][.D37F.0000.0000.537F] # CJK COMPATIBILITY IDEOGRAPH-2F831; QQC +2F832 ; [.FB40.0020.0002.537F][.D37F.0000.0000.537F] # CJK COMPATIBILITY IDEOGRAPH-2F832; QQC +2F833 ; [.FB40.0020.0002.537F][.D37F.0000.0000.537F] # CJK COMPATIBILITY IDEOGRAPH-2F833; QQC +2F1A ; [.FB40.0020.0004.5382][.D382.0000.0000.5382] # KANGXI RADICAL CLIFF; QQK +2E81 ; [.FB40.0020.0004.5382][.D382.0000.0000.5382][.0000.0199.001F.2E81] # CJK RADICAL CLIFF; QQKN +2F1B ; [.FB40.0020.0004.53B6][.D3B6.0000.0000.53B6] # KANGXI RADICAL PRIVATE; QQK +F96B ; [.FB40.0020.0002.53C3][.D3C3.0000.0000.53C3] # CJK COMPATIBILITY IDEOGRAPH-F96B; QQC +2F1C ; [.FB40.0020.0004.53C8][.D3C8.0000.0000.53C8] # KANGXI RADICAL AGAIN; QQK +2F836 ; [.FB40.0020.0002.53CA][.D3CA.0000.0000.53CA] # CJK COMPATIBILITY IDEOGRAPH-2F836; QQC +2F837 ; [.FB40.0020.0002.53DF][.D3DF.0000.0000.53DF] # CJK COMPATIBILITY IDEOGRAPH-2F837; QQC +2F1D ; [.FB40.0020.0004.53E3][.D3E3.0000.0000.53E3] # KANGXI RADICAL MOUTH; QQK +F906 ; [.FB40.0020.0002.53E5][.D3E5.0000.0000.53E5] # CJK COMPATIBILITY IDEOGRAPH-F906; QQC +2F839 ; [.FB40.0020.0002.53EB][.D3EB.0000.0000.53EB] # CJK COMPATIBILITY IDEOGRAPH-2F839; QQC +2F83A ; [.FB40.0020.0002.53F1][.D3F1.0000.0000.53F1] # CJK COMPATIBILITY IDEOGRAPH-2F83A; QQC +32A8 ; [.FB40.0020.0006.53F3][.D3F3.0000.0000.53F3] # CIRCLED IDEOGRAPH RIGHT; QQK +2F83B ; [.FB40.0020.0002.5406][.D406.0000.0000.5406] # CJK COMPATIBILITY IDEOGRAPH-2F83B; QQC +3234 ; [*02B1.0020.0004.3234][.FB40.0020.0004.540D][.D40D.0000.0000.540D][*02B2.0020.001F.3234] # PARENTHESIZED IDEOGRAPH NAME; QQKN +3294 ; [.FB40.0020.0006.540D][.D40D.0000.0000.540D] # CIRCLED IDEOGRAPH NAME; QQK +F9DE ; [.FB40.0020.0002.540F][.D40F.0000.0000.540F] # CJK COMPATIBILITY IDEOGRAPH-F9DE; QQC +F9ED ; [.FB40.0020.0002.541D][.D41D.0000.0000.541D] # CJK COMPATIBILITY IDEOGRAPH-F9ED; QQC +2F83D ; [.FB40.0020.0002.5438][.D438.0000.0000.5438] # CJK COMPATIBILITY IDEOGRAPH-2F83D; QQC +F980 ; [.FB40.0020.0002.5442][.D442.0000.0000.5442] # CJK COMPATIBILITY IDEOGRAPH-F980; QQC +2F83E ; [.FB40.0020.0002.5448][.D448.0000.0000.5448] # CJK COMPATIBILITY IDEOGRAPH-2F83E; QQC +2F83F ; [.FB40.0020.0002.5468][.D468.0000.0000.5468] # CJK COMPATIBILITY IDEOGRAPH-2F83F; QQC +323A ; [*02B1.0020.0004.323A][.FB40.0020.0004.547C][.D47C.0000.0000.547C][*02B2.0020.001F.323A] # PARENTHESIZED IDEOGRAPH CALL; QQKN +2F83C ; [.FB40.0020.0002.549E][.D49E.0000.0000.549E] # CJK COMPATIBILITY IDEOGRAPH-2F83C; QQC +2F840 ; [.FB40.0020.0002.54A2][.D4A2.0000.0000.54A2] # CJK COMPATIBILITY IDEOGRAPH-2F840; QQC +F99E ; [.FB40.0020.0002.54BD][.D4BD.0000.0000.54BD] # CJK COMPATIBILITY IDEOGRAPH-F99E; QQC +2F841 ; [.FB40.0020.0002.54F6][.D4F6.0000.0000.54F6] # CJK COMPATIBILITY IDEOGRAPH-2F841; QQC +2F842 ; [.FB40.0020.0002.5510][.D510.0000.0000.5510] # CJK COMPATIBILITY IDEOGRAPH-2F842; QQC +2F843 ; [.FB40.0020.0002.5553][.D553.0000.0000.5553] # CJK COMPATIBILITY IDEOGRAPH-2F843; QQC +FA79 ; [.FB40.0020.0002.5555][.D555.0000.0000.5555] # CJK COMPATIBILITY IDEOGRAPH-FA79; QQC +2F844 ; [.FB40.0020.0002.5563][.D563.0000.0000.5563] # CJK COMPATIBILITY IDEOGRAPH-2F844; QQC +2F845 ; [.FB40.0020.0002.5584][.D584.0000.0000.5584] # CJK COMPATIBILITY IDEOGRAPH-2F845; QQC +2F846 ; [.FB40.0020.0002.5584][.D584.0000.0000.5584] # CJK COMPATIBILITY IDEOGRAPH-2F846; QQC +F90B ; [.FB40.0020.0002.5587][.D587.0000.0000.5587] # CJK COMPATIBILITY IDEOGRAPH-F90B; QQC +FA7A ; [.FB40.0020.0002.5599][.D599.0000.0000.5599] # CJK COMPATIBILITY IDEOGRAPH-FA7A; QQC +2F847 ; [.FB40.0020.0002.5599][.D599.0000.0000.5599] # CJK COMPATIBILITY IDEOGRAPH-2F847; QQC +FA36 ; [.FB40.0020.0002.559D][.D59D.0000.0000.559D] # CJK COMPATIBILITY IDEOGRAPH-FA36; QQC +FA78 ; [.FB40.0020.0002.559D][.D59D.0000.0000.559D] # CJK COMPATIBILITY IDEOGRAPH-FA78; QQC +2F848 ; [.FB40.0020.0002.55AB][.D5AB.0000.0000.55AB] # CJK COMPATIBILITY IDEOGRAPH-2F848; QQC +2F849 ; [.FB40.0020.0002.55B3][.D5B3.0000.0000.55B3] # CJK COMPATIBILITY IDEOGRAPH-2F849; QQC +FA0D ; [.FB40.0020.0002.55C0][.D5C0.0000.0000.55C0] # CJK COMPATIBILITY IDEOGRAPH-FA0D; QQC +2F84A ; [.FB40.0020.0002.55C2][.D5C2.0000.0000.55C2] # CJK COMPATIBILITY IDEOGRAPH-2F84A; QQC +FA7B ; [.FB40.0020.0002.55E2][.D5E2.0000.0000.55E2] # CJK COMPATIBILITY IDEOGRAPH-FA7B; QQC +FA37 ; [.FB40.0020.0002.5606][.D606.0000.0000.5606] # CJK COMPATIBILITY IDEOGRAPH-FA37; QQC +2F84C ; [.FB40.0020.0002.5606][.D606.0000.0000.5606] # CJK COMPATIBILITY IDEOGRAPH-2F84C; QQC +2F84E ; [.FB40.0020.0002.5651][.D651.0000.0000.5651] # CJK COMPATIBILITY IDEOGRAPH-2F84E; QQC +FA38 ; [.FB40.0020.0002.5668][.D668.0000.0000.5668] # CJK COMPATIBILITY IDEOGRAPH-FA38; QQC +2F84F ; [.FB40.0020.0002.5674][.D674.0000.0000.5674] # CJK COMPATIBILITY IDEOGRAPH-2F84F; QQC +2F1E ; [.FB40.0020.0004.56D7][.D6D7.0000.0000.56D7] # KANGXI RADICAL ENCLOSURE; QQK +3223 ; [*02B1.0020.0004.3223][.FB40.0020.0004.56DB][.D6DB.0000.0000.56DB][*02B2.0020.001F.3223] # PARENTHESIZED IDEOGRAPH FOUR; QQKN +3283 ; [.FB40.0020.0006.56DB][.D6DB.0000.0000.56DB] # CIRCLED IDEOGRAPH FOUR; QQK +3195 ; [.FB40.0020.0014.56DB][.D6DB.0000.0000.56DB] # IDEOGRAPHIC ANNOTATION FOUR MARK; QQK +F9A9 ; [.FB40.0020.0002.56F9][.D6F9.0000.0000.56F9] # CJK COMPATIBILITY IDEOGRAPH-F9A9; QQC +2F84B ; [.FB40.0020.0002.5716][.D716.0000.0000.5716] # CJK COMPATIBILITY IDEOGRAPH-2F84B; QQC +2F84D ; [.FB40.0020.0002.5717][.D717.0000.0000.5717] # CJK COMPATIBILITY IDEOGRAPH-2F84D; QQC +2F1F ; [.FB40.0020.0004.571F][.D71F.0000.0000.571F] # KANGXI RADICAL EARTH; QQK +322F ; [*02B1.0020.0004.322F][.FB40.0020.0004.571F][.D71F.0000.0000.571F][*02B2.0020.001F.322F] # PARENTHESIZED IDEOGRAPH EARTH; QQKN +328F ; [.FB40.0020.0006.571F][.D71F.0000.0000.571F] # CIRCLED IDEOGRAPH EARTH; QQK +319E ; [.FB40.0020.0014.5730][.D730.0000.0000.5730] # IDEOGRAPHIC ANNOTATION EARTH MARK; QQK +2F855 ; [.FB40.0020.0002.578B][.D78B.0000.0000.578B] # CJK COMPATIBILITY IDEOGRAPH-2F855; QQC +2F852 ; [.FB40.0020.0002.57CE][.D7CE.0000.0000.57CE] # CJK COMPATIBILITY IDEOGRAPH-2F852; QQC +2F853 ; [.FB40.0020.0002.57F4][.D7F4.0000.0000.57F4] # CJK COMPATIBILITY IDEOGRAPH-2F853; QQC +2F854 ; [.FB40.0020.0002.580D][.D80D.0000.0000.580D] # CJK COMPATIBILITY IDEOGRAPH-2F854; QQC +2F857 ; [.FB40.0020.0002.5831][.D831.0000.0000.5831] # CJK COMPATIBILITY IDEOGRAPH-2F857; QQC +2F856 ; [.FB40.0020.0002.5832][.D832.0000.0000.5832] # CJK COMPATIBILITY IDEOGRAPH-2F856; QQC +FA39 ; [.FB40.0020.0002.5840][.D840.0000.0000.5840] # CJK COMPATIBILITY IDEOGRAPH-FA39; QQC +FA10 ; [.FB40.0020.0002.585A][.D85A.0000.0000.585A] # CJK COMPATIBILITY IDEOGRAPH-FA10; QQC +FA7C ; [.FB40.0020.0002.585A][.D85A.0000.0000.585A] # CJK COMPATIBILITY IDEOGRAPH-FA7C; QQC +F96C ; [.FB40.0020.0002.585E][.D85E.0000.0000.585E] # CJK COMPATIBILITY IDEOGRAPH-F96C; QQC +FA3A ; [.FB40.0020.0002.58A8][.D8A8.0000.0000.58A8] # CJK COMPATIBILITY IDEOGRAPH-FA3A; QQC +2F858 ; [.FB40.0020.0002.58AC][.D8AC.0000.0000.58AC] # CJK COMPATIBILITY IDEOGRAPH-2F858; QQC +FA7D ; [.FB40.0020.0002.58B3][.D8B3.0000.0000.58B3] # CJK COMPATIBILITY IDEOGRAPH-FA7D; QQC +F94A ; [.FB40.0020.0002.58D8][.D8D8.0000.0000.58D8] # CJK COMPATIBILITY IDEOGRAPH-F94A; QQC +F942 ; [.FB40.0020.0002.58DF][.D8DF.0000.0000.58DF] # CJK COMPATIBILITY IDEOGRAPH-F942; QQC +2F20 ; [.FB40.0020.0004.58EB][.D8EB.0000.0000.58EB] # KANGXI RADICAL SCHOLAR; QQK +2F851 ; [.FB40.0020.0002.58EE][.D8EE.0000.0000.58EE] # CJK COMPATIBILITY IDEOGRAPH-2F851; QQC +2F85A ; [.FB40.0020.0002.58F2][.D8F2.0000.0000.58F2] # CJK COMPATIBILITY IDEOGRAPH-2F85A; QQC +2F85B ; [.FB40.0020.0002.58F7][.D8F7.0000.0000.58F7] # CJK COMPATIBILITY IDEOGRAPH-2F85B; QQC +2F21 ; [.FB40.0020.0004.5902][.D902.0000.0000.5902] # KANGXI RADICAL GO; QQK +2F85C ; [.FB40.0020.0002.5906][.D906.0000.0000.5906] # CJK COMPATIBILITY IDEOGRAPH-2F85C; QQC +2F22 ; [.FB40.0020.0004.590A][.D90A.0000.0000.590A] # KANGXI RADICAL GO SLOWLY; QQK +2F23 ; [.FB40.0020.0004.5915][.D915.0000.0000.5915] # KANGXI RADICAL EVENING; QQK +2F85D ; [.FB40.0020.0002.591A][.D91A.0000.0000.591A] # CJK COMPATIBILITY IDEOGRAPH-2F85D; QQC +32B0 ; [.FB40.0020.0006.591C][.D91C.0000.0000.591C] # CIRCLED IDEOGRAPH NIGHT; QQK +2F85E ; [.FB40.0020.0002.5922][.D922.0000.0000.5922] # CJK COMPATIBILITY IDEOGRAPH-2F85E; QQC +2F24 ; [.FB40.0020.0004.5927][.D927.0000.0000.5927] # KANGXI RADICAL BIG; QQK +337D ; [.FB40.0020.001C.5927][.D927.0000.0000.5927][.FB40.0020.001F.6B63][.EB63.0000.0000.6B63] # SQUARE ERA NAME TAISYOU; QQKN +319D ; [.FB40.0020.0014.5929][.D929.0000.0000.5929] # IDEOGRAPHIC ANNOTATION HEAVEN MARK; QQK +FA7E ; [.FB40.0020.0002.5944][.D944.0000.0000.5944] # CJK COMPATIBILITY IDEOGRAPH-FA7E; QQC +F90C ; [.FB40.0020.0002.5948][.D948.0000.0000.5948] # CJK COMPATIBILITY IDEOGRAPH-F90C; QQC +F909 ; [.FB40.0020.0002.5951][.D951.0000.0000.5951] # CJK COMPATIBILITY IDEOGRAPH-F909; QQC +FA7F ; [.FB40.0020.0002.5954][.D954.0000.0000.5954] # CJK COMPATIBILITY IDEOGRAPH-FA7F; QQC +2F85F ; [.FB40.0020.0002.5962][.D962.0000.0000.5962] # CJK COMPATIBILITY IDEOGRAPH-2F85F; QQC +F981 ; [.FB40.0020.0002.5973][.D973.0000.0000.5973] # CJK COMPATIBILITY IDEOGRAPH-F981; QQC +2F25 ; [.FB40.0020.0004.5973][.D973.0000.0000.5973] # KANGXI RADICAL WOMAN; QQK +329B ; [.FB40.0020.0006.5973][.D973.0000.0000.5973] # CIRCLED IDEOGRAPH FEMALE; QQK +2F865 ; [.FB40.0020.0002.59D8][.D9D8.0000.0000.59D8] # CJK COMPATIBILITY IDEOGRAPH-2F865; QQC +2F862 ; [.FB40.0020.0002.59EC][.D9EC.0000.0000.59EC] # CJK COMPATIBILITY IDEOGRAPH-2F862; QQC +2F863 ; [.FB40.0020.0002.5A1B][.DA1B.0000.0000.5A1B] # CJK COMPATIBILITY IDEOGRAPH-2F863; QQC +2F864 ; [.FB40.0020.0002.5A27][.DA27.0000.0000.5A27] # CJK COMPATIBILITY IDEOGRAPH-2F864; QQC +FA80 ; [.FB40.0020.0002.5A62][.DA62.0000.0000.5A62] # CJK COMPATIBILITY IDEOGRAPH-FA80; QQC +2F866 ; [.FB40.0020.0002.5A66][.DA66.0000.0000.5A66] # CJK COMPATIBILITY IDEOGRAPH-2F866; QQC +2F986 ; [.FB40.0020.0002.5AB5][.DAB5.0000.0000.5AB5] # CJK COMPATIBILITY IDEOGRAPH-2F986; QQC +2F869 ; [.FB40.0020.0002.5B08][.DB08.0000.0000.5B08] # CJK COMPATIBILITY IDEOGRAPH-2F869; QQC +FA81 ; [.FB40.0020.0002.5B28][.DB28.0000.0000.5B28] # CJK COMPATIBILITY IDEOGRAPH-FA81; QQC +2F86A ; [.FB40.0020.0002.5B3E][.DB3E.0000.0000.5B3E] # CJK COMPATIBILITY IDEOGRAPH-2F86A; QQC +2F86B ; [.FB40.0020.0002.5B3E][.DB3E.0000.0000.5B3E] # CJK COMPATIBILITY IDEOGRAPH-2F86B; QQC +2F26 ; [.FB40.0020.0004.5B50][.DB50.0000.0000.5B50] # KANGXI RADICAL CHILD; QQK +323B ; [*02B1.0020.0004.323B][.FB40.0020.0004.5B66][.DB66.0000.0000.5B66][*02B2.0020.001F.323B] # PARENTHESIZED IDEOGRAPH STUDY; QQKN +32AB ; [.FB40.0020.0006.5B66][.DB66.0000.0000.5B66] # CIRCLED IDEOGRAPH STUDY; QQK +2F27 ; [.FB40.0020.0004.5B80][.DB80.0000.0000.5B80] # KANGXI RADICAL ROOF; QQK +FA04 ; [.FB40.0020.0002.5B85][.DB85.0000.0000.5B85] # CJK COMPATIBILITY IDEOGRAPH-FA04; QQC +32AA ; [.FB40.0020.0006.5B97][.DB97.0000.0000.5B97] # CIRCLED IDEOGRAPH RELIGION; QQK +2F86D ; [.FB40.0020.0002.5BC3][.DBC3.0000.0000.5BC3] # CJK COMPATIBILITY IDEOGRAPH-2F86D; QQC +2F86E ; [.FB40.0020.0002.5BD8][.DBD8.0000.0000.5BD8] # CJK COMPATIBILITY IDEOGRAPH-2F86E; QQC +F95F ; [.FB40.0020.0002.5BE7][.DBE7.0000.0000.5BE7] # CJK COMPATIBILITY IDEOGRAPH-F95F; QQC +F9AA ; [.FB40.0020.0002.5BE7][.DBE7.0000.0000.5BE7] # CJK COMPATIBILITY IDEOGRAPH-F9AA; QQC +2F86F ; [.FB40.0020.0002.5BE7][.DBE7.0000.0000.5BE7] # CJK COMPATIBILITY IDEOGRAPH-2F86F; QQC +F9BC ; [.FB40.0020.0002.5BEE][.DBEE.0000.0000.5BEE] # CJK COMPATIBILITY IDEOGRAPH-F9BC; QQC +2F870 ; [.FB40.0020.0002.5BF3][.DBF3.0000.0000.5BF3] # CJK COMPATIBILITY IDEOGRAPH-2F870; QQC +2F28 ; [.FB40.0020.0004.5BF8][.DBF8.0000.0000.5BF8] # KANGXI RADICAL INCH; QQK +2F872 ; [.FB40.0020.0002.5BFF][.DBFF.0000.0000.5BFF] # CJK COMPATIBILITY IDEOGRAPH-2F872; QQC +2F873 ; [.FB40.0020.0002.5C06][.DC06.0000.0000.5C06] # CJK COMPATIBILITY IDEOGRAPH-2F873; QQC +2F29 ; [.FB40.0020.0004.5C0F][.DC0F.0000.0000.5C0F] # KANGXI RADICAL SMALL; QQK +2E8C ; [.FB40.0020.0004.5C0F][.DC0F.0000.0000.5C0F][.0000.0199.001F.2E8C] # CJK RADICAL SMALL ONE; QQKN +2E8D ; [.FB40.0020.0004.5C0F][.DC0F.0000.0000.5C0F][.0000.019A.001F.2E8D] # CJK RADICAL SMALL TWO; QQKN +2F875 ; [.FB40.0020.0002.5C22][.DC22.0000.0000.5C22] # CJK COMPATIBILITY IDEOGRAPH-2F875; QQC +2E90 ; [.FB40.0020.0004.5C22][.DC22.0000.0000.5C22] # CJK RADICAL LAME THREE; QQK +2F2A ; [.FB40.0020.0004.5C22][.DC22.0000.0000.5C22] # KANGXI RADICAL LAME; QQK +2E8E ; [.FB40.0020.0004.5C22][.DC22.0000.0000.5C22][.0000.0199.001F.2E8E] # CJK RADICAL LAME ONE; QQKN +2E8F ; [.FB40.0020.0004.5C23][.DC23.0000.0000.5C23] # CJK RADICAL LAME TWO; QQK +2E91 ; [.FB40.0020.0004.5C23][.DC23.0000.0000.5C23][.0000.0199.001F.2E91] # CJK RADICAL LAME FOUR; QQKN +2F2B ; [.FB40.0020.0004.5C38][.DC38.0000.0000.5C38] # KANGXI RADICAL CORPSE; QQK +F9BD ; [.FB40.0020.0002.5C3F][.DC3F.0000.0000.5C3F] # CJK COMPATIBILITY IDEOGRAPH-F9BD; QQC +2F877 ; [.FB40.0020.0002.5C60][.DC60.0000.0000.5C60] # CJK COMPATIBILITY IDEOGRAPH-2F877; QQC +F94B ; [.FB40.0020.0002.5C62][.DC62.0000.0000.5C62] # CJK COMPATIBILITY IDEOGRAPH-F94B; QQC +FA3B ; [.FB40.0020.0002.5C64][.DC64.0000.0000.5C64] # CJK COMPATIBILITY IDEOGRAPH-FA3B; QQC +F9DF ; [.FB40.0020.0002.5C65][.DC65.0000.0000.5C65] # CJK COMPATIBILITY IDEOGRAPH-F9DF; QQC +FA3C ; [.FB40.0020.0002.5C6E][.DC6E.0000.0000.5C6E] # CJK COMPATIBILITY IDEOGRAPH-FA3C; QQC +2F878 ; [.FB40.0020.0002.5C6E][.DC6E.0000.0000.5C6E] # CJK COMPATIBILITY IDEOGRAPH-2F878; QQC +2F2C ; [.FB40.0020.0004.5C6E][.DC6E.0000.0000.5C6E] # KANGXI RADICAL SPROUT; QQK +2F2D ; [.FB40.0020.0004.5C71][.DC71.0000.0000.5C71] # KANGXI RADICAL MOUNTAIN; QQK +2F87A ; [.FB40.0020.0002.5C8D][.DC8D.0000.0000.5C8D] # CJK COMPATIBILITY IDEOGRAPH-2F87A; QQC +2F879 ; [.FB40.0020.0002.5CC0][.DCC0.0000.0000.5CC0] # CJK COMPATIBILITY IDEOGRAPH-2F879; QQC +F9D5 ; [.FB40.0020.0002.5D19][.DD19.0000.0000.5D19] # CJK COMPATIBILITY IDEOGRAPH-F9D5; QQC +2F87C ; [.FB40.0020.0002.5D43][.DD43.0000.0000.5D43] # CJK COMPATIBILITY IDEOGRAPH-2F87C; QQC +F921 ; [.FB40.0020.0002.5D50][.DD50.0000.0000.5D50] # CJK COMPATIBILITY IDEOGRAPH-F921; QQC +2F87F ; [.FB40.0020.0002.5D6B][.DD6B.0000.0000.5D6B] # CJK COMPATIBILITY IDEOGRAPH-2F87F; QQC +2F87E ; [.FB40.0020.0002.5D6E][.DD6E.0000.0000.5D6E] # CJK COMPATIBILITY IDEOGRAPH-2F87E; QQC +2F880 ; [.FB40.0020.0002.5D7C][.DD7C.0000.0000.5D7C] # CJK COMPATIBILITY IDEOGRAPH-2F880; QQC +2F9F4 ; [.FB40.0020.0002.5DB2][.DDB2.0000.0000.5DB2] # CJK COMPATIBILITY IDEOGRAPH-2F9F4; QQC +F9AB ; [.FB40.0020.0002.5DBA][.DDBA.0000.0000.5DBA] # CJK COMPATIBILITY IDEOGRAPH-F9AB; QQC +2F2E ; [.FB40.0020.0004.5DDB][.DDDB.0000.0000.5DDB] # KANGXI RADICAL RIVER; QQK +2F881 ; [.FB40.0020.0002.5DE1][.DDE1.0000.0000.5DE1] # CJK COMPATIBILITY IDEOGRAPH-2F881; QQC +2F882 ; [.FB40.0020.0002.5DE2][.DDE2.0000.0000.5DE2] # CJK COMPATIBILITY IDEOGRAPH-2F882; QQC +2F2F ; [.FB40.0020.0004.5DE5][.DDE5.0000.0000.5DE5] # KANGXI RADICAL WORK; QQK +32A7 ; [.FB40.0020.0006.5DE6][.DDE6.0000.0000.5DE6] # CIRCLED IDEOGRAPH LEFT; QQK +2F30 ; [.FB40.0020.0004.5DF1][.DDF1.0000.0000.5DF1] # KANGXI RADICAL ONESELF; QQK +2E92 ; [.FB40.0020.0004.5DF3][.DDF3.0000.0000.5DF3] # CJK RADICAL SNAKE; QQK +2F884 ; [.FB40.0020.0002.5DFD][.DDFD.0000.0000.5DFD] # CJK COMPATIBILITY IDEOGRAPH-2F884; QQC +2F31 ; [.FB40.0020.0004.5DFE][.DDFE.0000.0000.5DFE] # KANGXI RADICAL TURBAN; QQK +2F885 ; [.FB40.0020.0002.5E28][.DE28.0000.0000.5E28] # CJK COMPATIBILITY IDEOGRAPH-2F885; QQC +2F886 ; [.FB40.0020.0002.5E3D][.DE3D.0000.0000.5E3D] # CJK COMPATIBILITY IDEOGRAPH-2F886; QQC +2F887 ; [.FB40.0020.0002.5E69][.DE69.0000.0000.5E69] # CJK COMPATIBILITY IDEOGRAPH-2F887; QQC +2F32 ; [.FB40.0020.0004.5E72][.DE72.0000.0000.5E72] # KANGXI RADICAL DRY; QQK +337B ; [.FB40.0020.001C.5E73][.DE73.0000.0000.5E73][.FB40.0020.001F.6210][.E210.0000.0000.6210] # SQUARE ERA NAME HEISEI; QQKN +F98E ; [.FB40.0020.0002.5E74][.DE74.0000.0000.5E74] # CJK COMPATIBILITY IDEOGRAPH-F98E; QQC +2E93 ; [.FB40.0020.0004.5E7A][.DE7A.0000.0000.5E7A] # CJK RADICAL THREAD; QQK +2F33 ; [.FB40.0020.0004.5E7A][.DE7A.0000.0000.5E7A] # KANGXI RADICAL SHORT THREAD; QQK +2F34 ; [.FB40.0020.0004.5E7F][.DE7F.0000.0000.5E7F] # KANGXI RADICAL DOTTED CLIFF; QQK +FA01 ; [.FB40.0020.0002.5EA6][.DEA6.0000.0000.5EA6] # CJK COMPATIBILITY IDEOGRAPH-FA01; QQC +2F88B ; [.FB40.0020.0002.5EB0][.DEB0.0000.0000.5EB0] # CJK COMPATIBILITY IDEOGRAPH-2F88B; QQC +2F88C ; [.FB40.0020.0002.5EB3][.DEB3.0000.0000.5EB3] # CJK COMPATIBILITY IDEOGRAPH-2F88C; QQC +2F88D ; [.FB40.0020.0002.5EB6][.DEB6.0000.0000.5EB6] # CJK COMPATIBILITY IDEOGRAPH-2F88D; QQC +F9A2 ; [.FB40.0020.0002.5EC9][.DEC9.0000.0000.5EC9] # CJK COMPATIBILITY IDEOGRAPH-F9A2; QQC +F928 ; [.FB40.0020.0002.5ECA][.DECA.0000.0000.5ECA] # CJK COMPATIBILITY IDEOGRAPH-F928; QQC +2F88E ; [.FB40.0020.0002.5ECA][.DECA.0000.0000.5ECA] # CJK COMPATIBILITY IDEOGRAPH-2F88E; QQC +FA82 ; [.FB40.0020.0002.5ED2][.DED2.0000.0000.5ED2] # CJK COMPATIBILITY IDEOGRAPH-FA82; QQC +FA0B ; [.FB40.0020.0002.5ED3][.DED3.0000.0000.5ED3] # CJK COMPATIBILITY IDEOGRAPH-FA0B; QQC +FA83 ; [.FB40.0020.0002.5ED9][.DED9.0000.0000.5ED9] # CJK COMPATIBILITY IDEOGRAPH-FA83; QQC +F982 ; [.FB40.0020.0002.5EEC][.DEEC.0000.0000.5EEC] # CJK COMPATIBILITY IDEOGRAPH-F982; QQC +2F35 ; [.FB40.0020.0004.5EF4][.DEF4.0000.0000.5EF4] # KANGXI RADICAL LONG STRIDE; QQK +2F890 ; [.FB40.0020.0002.5EFE][.DEFE.0000.0000.5EFE] # CJK COMPATIBILITY IDEOGRAPH-2F890; QQC +2F36 ; [.FB40.0020.0004.5EFE][.DEFE.0000.0000.5EFE] # KANGXI RADICAL TWO HANDS; QQK +F943 ; [.FB40.0020.0002.5F04][.DF04.0000.0000.5F04] # CJK COMPATIBILITY IDEOGRAPH-F943; QQC +2F37 ; [.FB40.0020.0004.5F0B][.DF0B.0000.0000.5F0B] # KANGXI RADICAL SHOOT; QQK +2F38 ; [.FB40.0020.0004.5F13][.DF13.0000.0000.5F13] # KANGXI RADICAL BOW; QQK +2F894 ; [.FB40.0020.0002.5F22][.DF22.0000.0000.5F22] # CJK COMPATIBILITY IDEOGRAPH-2F894; QQC +2F895 ; [.FB40.0020.0002.5F22][.DF22.0000.0000.5F22] # CJK COMPATIBILITY IDEOGRAPH-2F895; QQC +2F39 ; [.FB40.0020.0004.5F50][.DF50.0000.0000.5F50] # KANGXI RADICAL SNOUT; QQK +2E95 ; [.FB40.0020.0004.5F50][.DF50.0000.0000.5F50][.0000.0199.001F.2E95] # CJK RADICAL SNOUT TWO; QQKN +2E94 ; [.FB40.0020.0004.5F51][.DF51.0000.0000.5F51] # CJK RADICAL SNOUT ONE; QQK +2F874 ; [.FB40.0020.0002.5F53][.DF53.0000.0000.5F53] # CJK COMPATIBILITY IDEOGRAPH-2F874; QQC +2F3A ; [.FB40.0020.0004.5F61][.DF61.0000.0000.5F61] # KANGXI RADICAL BRISTLE; QQK +2F899 ; [.FB40.0020.0002.5F62][.DF62.0000.0000.5F62] # CJK COMPATIBILITY IDEOGRAPH-2F899; QQC +FA84 ; [.FB40.0020.0002.5F69][.DF69.0000.0000.5F69] # CJK COMPATIBILITY IDEOGRAPH-FA84; QQC +2F89A ; [.FB40.0020.0002.5F6B][.DF6B.0000.0000.5F6B] # CJK COMPATIBILITY IDEOGRAPH-2F89A; QQC +2F3B ; [.FB40.0020.0004.5F73][.DF73.0000.0000.5F73] # KANGXI RADICAL STEP; QQK +F9D8 ; [.FB40.0020.0002.5F8B][.DF8B.0000.0000.5F8B] # CJK COMPATIBILITY IDEOGRAPH-F9D8; QQC +2F89C ; [.FB40.0020.0002.5F9A][.DF9A.0000.0000.5F9A] # CJK COMPATIBILITY IDEOGRAPH-2F89C; QQC +F966 ; [.FB40.0020.0002.5FA9][.DFA9.0000.0000.5FA9] # CJK COMPATIBILITY IDEOGRAPH-F966; QQC +FA85 ; [.FB40.0020.0002.5FAD][.DFAD.0000.0000.5FAD] # CJK COMPATIBILITY IDEOGRAPH-FA85; QQC +2F3C ; [.FB40.0020.0004.5FC3][.DFC3.0000.0000.5FC3] # KANGXI RADICAL HEART; QQK +2E97 ; [.FB40.0020.0004.5FC3][.DFC3.0000.0000.5FC3][.0000.0199.001F.2E97] # CJK RADICAL HEART TWO; QQKN +2E96 ; [.FB40.0020.0004.5FC4][.DFC4.0000.0000.5FC4] # CJK RADICAL HEART ONE; QQK +2F89D ; [.FB40.0020.0002.5FCD][.DFCD.0000.0000.5FCD] # CJK COMPATIBILITY IDEOGRAPH-2F89D; QQC +2F89E ; [.FB40.0020.0002.5FD7][.DFD7.0000.0000.5FD7] # CJK COMPATIBILITY IDEOGRAPH-2F89E; QQC +F9A3 ; [.FB40.0020.0002.5FF5][.DFF5.0000.0000.5FF5] # CJK COMPATIBILITY IDEOGRAPH-F9A3; QQC +2F89F ; [.FB40.0020.0002.5FF9][.DFF9.0000.0000.5FF9] # CJK COMPATIBILITY IDEOGRAPH-2F89F; QQC +F960 ; [.FB40.0020.0002.6012][.E012.0000.0000.6012] # CJK COMPATIBILITY IDEOGRAPH-F960; QQC +F9AC ; [.FB40.0020.0002.601C][.E01C.0000.0000.601C] # CJK COMPATIBILITY IDEOGRAPH-F9AC; QQC +2F8A0 ; [.FB40.0020.0002.6081][.E081.0000.0000.6081] # CJK COMPATIBILITY IDEOGRAPH-2F8A0; QQC +FA3D ; [.FB40.0020.0002.6094][.E094.0000.0000.6094] # CJK COMPATIBILITY IDEOGRAPH-FA3D; QQC +2F8A3 ; [.FB40.0020.0002.6094][.E094.0000.0000.6094] # CJK COMPATIBILITY IDEOGRAPH-2F8A3; QQC +2F8A5 ; [.FB40.0020.0002.60C7][.E0C7.0000.0000.60C7] # CJK COMPATIBILITY IDEOGRAPH-2F8A5; QQC +FA86 ; [.FB40.0020.0002.60D8][.E0D8.0000.0000.60D8] # CJK COMPATIBILITY IDEOGRAPH-FA86; QQC +F9B9 ; [.FB40.0020.0002.60E1][.E0E1.0000.0000.60E1] # CJK COMPATIBILITY IDEOGRAPH-F9B9; QQC +FA88 ; [.FB40.0020.0002.6108][.E108.0000.0000.6108] # CJK COMPATIBILITY IDEOGRAPH-FA88; QQC +F9D9 ; [.FB40.0020.0002.6144][.E144.0000.0000.6144] # CJK COMPATIBILITY IDEOGRAPH-F9D9; QQC +2F8A6 ; [.FB40.0020.0002.6148][.E148.0000.0000.6148] # CJK COMPATIBILITY IDEOGRAPH-2F8A6; QQC +2F8A7 ; [.FB40.0020.0002.614C][.E14C.0000.0000.614C] # CJK COMPATIBILITY IDEOGRAPH-2F8A7; QQC +2F8A9 ; [.FB40.0020.0002.614C][.E14C.0000.0000.614C] # CJK COMPATIBILITY IDEOGRAPH-2F8A9; QQC +FA87 ; [.FB40.0020.0002.614E][.E14E.0000.0000.614E] # CJK COMPATIBILITY IDEOGRAPH-FA87; QQC +2F8A8 ; [.FB40.0020.0002.614E][.E14E.0000.0000.614E] # CJK COMPATIBILITY IDEOGRAPH-2F8A8; QQC +FA8A ; [.FB40.0020.0002.6160][.E160.0000.0000.6160] # CJK COMPATIBILITY IDEOGRAPH-FA8A; QQC +FA3E ; [.FB40.0020.0002.6168][.E168.0000.0000.6168] # CJK COMPATIBILITY IDEOGRAPH-FA3E; QQC +2F8AA ; [.FB40.0020.0002.617A][.E17A.0000.0000.617A] # CJK COMPATIBILITY IDEOGRAPH-2F8AA; QQC +FA3F ; [.FB40.0020.0002.618E][.E18E.0000.0000.618E] # CJK COMPATIBILITY IDEOGRAPH-FA3F; QQC +FA89 ; [.FB40.0020.0002.618E][.E18E.0000.0000.618E] # CJK COMPATIBILITY IDEOGRAPH-FA89; QQC +2F8AB ; [.FB40.0020.0002.618E][.E18E.0000.0000.618E] # CJK COMPATIBILITY IDEOGRAPH-2F8AB; QQC +F98F ; [.FB40.0020.0002.6190][.E190.0000.0000.6190] # CJK COMPATIBILITY IDEOGRAPH-F98F; QQC +2F8AD ; [.FB40.0020.0002.61A4][.E1A4.0000.0000.61A4] # CJK COMPATIBILITY IDEOGRAPH-2F8AD; QQC +2F8AE ; [.FB40.0020.0002.61AF][.E1AF.0000.0000.61AF] # CJK COMPATIBILITY IDEOGRAPH-2F8AE; QQC +2F8AC ; [.FB40.0020.0002.61B2][.E1B2.0000.0000.61B2] # CJK COMPATIBILITY IDEOGRAPH-2F8AC; QQC +2F8AF ; [.FB40.0020.0002.61DE][.E1DE.0000.0000.61DE] # CJK COMPATIBILITY IDEOGRAPH-2F8AF; QQC +FA40 ; [.FB40.0020.0002.61F2][.E1F2.0000.0000.61F2] # CJK COMPATIBILITY IDEOGRAPH-FA40; QQC +FA8B ; [.FB40.0020.0002.61F2][.E1F2.0000.0000.61F2] # CJK COMPATIBILITY IDEOGRAPH-FA8B; QQC +2F8B0 ; [.FB40.0020.0002.61F2][.E1F2.0000.0000.61F2] # CJK COMPATIBILITY IDEOGRAPH-2F8B0; QQC +F90D ; [.FB40.0020.0002.61F6][.E1F6.0000.0000.61F6] # CJK COMPATIBILITY IDEOGRAPH-F90D; QQC +2F8B1 ; [.FB40.0020.0002.61F6][.E1F6.0000.0000.61F6] # CJK COMPATIBILITY IDEOGRAPH-2F8B1; QQC +F990 ; [.FB40.0020.0002.6200][.E200.0000.0000.6200] # CJK COMPATIBILITY IDEOGRAPH-F990; QQC +2F3D ; [.FB40.0020.0004.6208][.E208.0000.0000.6208] # KANGXI RADICAL HALBERD; QQK +2F8B2 ; [.FB40.0020.0002.6210][.E210.0000.0000.6210] # CJK COMPATIBILITY IDEOGRAPH-2F8B2; QQC +2F8B3 ; [.FB40.0020.0002.621B][.E21B.0000.0000.621B] # CJK COMPATIBILITY IDEOGRAPH-2F8B3; QQC +F9D2 ; [.FB40.0020.0002.622E][.E22E.0000.0000.622E] # CJK COMPATIBILITY IDEOGRAPH-F9D2; QQC +FA8C ; [.FB40.0020.0002.6234][.E234.0000.0000.6234] # CJK COMPATIBILITY IDEOGRAPH-FA8C; QQC +2F3E ; [.FB40.0020.0004.6236][.E236.0000.0000.6236] # KANGXI RADICAL DOOR; QQK +2F3F ; [.FB40.0020.0004.624B][.E24B.0000.0000.624B] # KANGXI RADICAL HAND; QQK +2E98 ; [.FB40.0020.0004.624C][.E24C.0000.0000.624C] # CJK RADICAL HAND; QQK +2F8B4 ; [.FB40.0020.0002.625D][.E25D.0000.0000.625D] # CJK COMPATIBILITY IDEOGRAPH-2F8B4; QQC +2F8B5 ; [.FB40.0020.0002.62B1][.E2B1.0000.0000.62B1] # CJK COMPATIBILITY IDEOGRAPH-2F8B5; QQC +F925 ; [.FB40.0020.0002.62C9][.E2C9.0000.0000.62C9] # CJK COMPATIBILITY IDEOGRAPH-F925; QQC +F95B ; [.FB40.0020.0002.62CF][.E2CF.0000.0000.62CF] # CJK COMPATIBILITY IDEOGRAPH-F95B; QQC +FA02 ; [.FB40.0020.0002.62D3][.E2D3.0000.0000.62D3] # CJK COMPATIBILITY IDEOGRAPH-FA02; QQC +2F8B6 ; [.FB40.0020.0002.62D4][.E2D4.0000.0000.62D4] # CJK COMPATIBILITY IDEOGRAPH-2F8B6; QQC +2F8BA ; [.FB40.0020.0002.62FC][.E2FC.0000.0000.62FC] # CJK COMPATIBILITY IDEOGRAPH-2F8BA; QQC +F973 ; [.FB40.0020.0002.62FE][.E2FE.0000.0000.62FE] # CJK COMPATIBILITY IDEOGRAPH-F973; QQC +2F8B9 ; [.FB40.0020.0002.633D][.E33D.0000.0000.633D] # CJK COMPATIBILITY IDEOGRAPH-2F8B9; QQC +2F8B7 ; [.FB40.0020.0002.6350][.E350.0000.0000.6350] # CJK COMPATIBILITY IDEOGRAPH-2F8B7; QQC +2F8BB ; [.FB40.0020.0002.6368][.E368.0000.0000.6368] # CJK COMPATIBILITY IDEOGRAPH-2F8BB; QQC +F9A4 ; [.FB40.0020.0002.637B][.E37B.0000.0000.637B] # CJK COMPATIBILITY IDEOGRAPH-F9A4; QQC +2F8BC ; [.FB40.0020.0002.6383][.E383.0000.0000.6383] # CJK COMPATIBILITY IDEOGRAPH-2F8BC; QQC +F975 ; [.FB40.0020.0002.63A0][.E3A0.0000.0000.63A0] # CJK COMPATIBILITY IDEOGRAPH-F975; QQC +2F8C1 ; [.FB40.0020.0002.63A9][.E3A9.0000.0000.63A9] # CJK COMPATIBILITY IDEOGRAPH-2F8C1; QQC +FA8D ; [.FB40.0020.0002.63C4][.E3C4.0000.0000.63C4] # CJK COMPATIBILITY IDEOGRAPH-FA8D; QQC +2F8C0 ; [.FB40.0020.0002.63C5][.E3C5.0000.0000.63C5] # CJK COMPATIBILITY IDEOGRAPH-2F8C0; QQC +2F8BD ; [.FB40.0020.0002.63E4][.E3E4.0000.0000.63E4] # CJK COMPATIBILITY IDEOGRAPH-2F8BD; QQC +FA8E ; [.FB40.0020.0002.641C][.E41C.0000.0000.641C] # CJK COMPATIBILITY IDEOGRAPH-FA8E; QQC +2F8BF ; [.FB40.0020.0002.6422][.E422.0000.0000.6422] # CJK COMPATIBILITY IDEOGRAPH-2F8BF; QQC +FA8F ; [.FB40.0020.0002.6452][.E452.0000.0000.6452] # CJK COMPATIBILITY IDEOGRAPH-FA8F; QQC +2F8C3 ; [.FB40.0020.0002.6469][.E469.0000.0000.6469] # CJK COMPATIBILITY IDEOGRAPH-2F8C3; QQC +2F8C6 ; [.FB40.0020.0002.6477][.E477.0000.0000.6477] # CJK COMPATIBILITY IDEOGRAPH-2F8C6; QQC +2F8C4 ; [.FB40.0020.0002.647E][.E47E.0000.0000.647E] # CJK COMPATIBILITY IDEOGRAPH-2F8C4; QQC +F991 ; [.FB40.0020.0002.649A][.E49A.0000.0000.649A] # CJK COMPATIBILITY IDEOGRAPH-F991; QQC +2F8C5 ; [.FB40.0020.0002.649D][.E49D.0000.0000.649D] # CJK COMPATIBILITY IDEOGRAPH-2F8C5; QQC +F930 ; [.FB40.0020.0002.64C4][.E4C4.0000.0000.64C4] # CJK COMPATIBILITY IDEOGRAPH-F930; QQC +2F40 ; [.FB40.0020.0004.652F][.E52F.0000.0000.652F] # KANGXI RADICAL BRANCH; QQK +2F41 ; [.FB40.0020.0004.6534][.E534.0000.0000.6534] # KANGXI RADICAL RAP; QQK +2E99 ; [.FB40.0020.0004.6535][.E535.0000.0000.6535] # CJK RADICAL RAP; QQK +FA41 ; [.FB40.0020.0002.654F][.E54F.0000.0000.654F] # CJK COMPATIBILITY IDEOGRAPH-FA41; QQC +2F8C8 ; [.FB40.0020.0002.654F][.E54F.0000.0000.654F] # CJK COMPATIBILITY IDEOGRAPH-2F8C8; QQC +FA90 ; [.FB40.0020.0002.6556][.E556.0000.0000.6556] # CJK COMPATIBILITY IDEOGRAPH-FA90; QQC +2F8C9 ; [.FB40.0020.0002.656C][.E56C.0000.0000.656C] # CJK COMPATIBILITY IDEOGRAPH-2F8C9; QQC +F969 ; [.FB40.0020.0002.6578][.E578.0000.0000.6578] # CJK COMPATIBILITY IDEOGRAPH-F969; QQC +2F42 ; [.FB40.0020.0004.6587][.E587.0000.0000.6587] # KANGXI RADICAL SCRIPT; QQK +2F43 ; [.FB40.0020.0004.6597][.E597.0000.0000.6597] # KANGXI RADICAL DIPPER; QQK +F9BE ; [.FB40.0020.0002.6599][.E599.0000.0000.6599] # CJK COMPATIBILITY IDEOGRAPH-F9BE; QQC +2F44 ; [.FB40.0020.0004.65A4][.E5A4.0000.0000.65A4] # KANGXI RADICAL AXE; QQK +2F45 ; [.FB40.0020.0004.65B9][.E5B9.0000.0000.65B9] # KANGXI RADICAL SQUARE; QQK +F983 ; [.FB40.0020.0002.65C5][.E5C5.0000.0000.65C5] # CJK COMPATIBILITY IDEOGRAPH-F983; QQC +2F46 ; [.FB40.0020.0004.65E0][.E5E0.0000.0000.65E0] # KANGXI RADICAL NOT; QQK +2E9B ; [.FB40.0020.0004.65E1][.E5E1.0000.0000.65E1] # CJK RADICAL CHOKE; QQK +FA42 ; [.FB40.0020.0002.65E2][.E5E2.0000.0000.65E2] # CJK COMPATIBILITY IDEOGRAPH-FA42; QQC +2F8CB ; [.FB40.0020.0002.65E3][.E5E3.0000.0000.65E3] # CJK COMPATIBILITY IDEOGRAPH-2F8CB; QQC +2F47 ; [.FB40.0020.0004.65E5][.E5E5.0000.0000.65E5] # KANGXI RADICAL SUN; QQK +3230 ; [*02B1.0020.0004.3230][.FB40.0020.0004.65E5][.E5E5.0000.0000.65E5][*02B2.0020.001F.3230] # PARENTHESIZED IDEOGRAPH SUN; QQKN +3290 ; [.FB40.0020.0006.65E5][.E5E5.0000.0000.65E5] # CIRCLED IDEOGRAPH SUN; QQK +2E9C ; [.FB40.0020.0004.65E5][.E5E5.0000.0000.65E5][.0000.0199.001F.2E9C] # CJK RADICAL SUN; QQKN +337E ; [.FB40.0020.001C.660E][.E60E.0000.0000.660E][.FB40.0020.001F.6CBB][.ECBB.0000.0000.6CBB] # SQUARE ERA NAME MEIZI; QQKN +F9E0 ; [.FB40.0020.0002.6613][.E613.0000.0000.6613] # CJK COMPATIBILITY IDEOGRAPH-F9E0; QQC +337C ; [.FB40.0020.001C.662D][.E62D.0000.0000.662D][.FB40.0020.001F.548C][.D48C.0000.0000.548C] # SQUARE ERA NAME SYOUWA; QQKN +2F8CD ; [.FB40.0020.0002.6649][.E649.0000.0000.6649] # CJK COMPATIBILITY IDEOGRAPH-2F8CD; QQC +FA12 ; [.FB40.0020.0002.6674][.E674.0000.0000.6674] # CJK COMPATIBILITY IDEOGRAPH-FA12; QQC +FA91 ; [.FB40.0020.0002.6674][.E674.0000.0000.6674] # CJK COMPATIBILITY IDEOGRAPH-FA91; QQC +F9C5 ; [.FB40.0020.0002.6688][.E688.0000.0000.6688] # CJK COMPATIBILITY IDEOGRAPH-F9C5; QQC +FA43 ; [.FB40.0020.0002.6691][.E691.0000.0000.6691] # CJK COMPATIBILITY IDEOGRAPH-FA43; QQC +2F8CF ; [.FB40.0020.0002.6691][.E691.0000.0000.6691] # CJK COMPATIBILITY IDEOGRAPH-2F8CF; QQC +2F8D5 ; [.FB40.0020.0002.669C][.E69C.0000.0000.669C] # CJK COMPATIBILITY IDEOGRAPH-2F8D5; QQC +FA06 ; [.FB40.0020.0002.66B4][.E6B4.0000.0000.66B4] # CJK COMPATIBILITY IDEOGRAPH-FA06; QQC +F98B ; [.FB40.0020.0002.66C6][.E6C6.0000.0000.66C6] # CJK COMPATIBILITY IDEOGRAPH-F98B; QQC +2F48 ; [.FB40.0020.0004.66F0][.E6F0.0000.0000.66F0] # KANGXI RADICAL SAY; QQK +F901 ; [.FB40.0020.0002.66F4][.E6F4.0000.0000.66F4] # CJK COMPATIBILITY IDEOGRAPH-F901; QQC +2F8CC ; [.FB40.0020.0002.66F8][.E6F8.0000.0000.66F8] # CJK COMPATIBILITY IDEOGRAPH-2F8CC; QQC +2F8D4 ; [.FB40.0020.0002.6700][.E700.0000.0000.6700] # CJK COMPATIBILITY IDEOGRAPH-2F8D4; QQC +2F49 ; [.FB40.0020.0004.6708][.E708.0000.0000.6708] # KANGXI RADICAL MOON; QQK +322A ; [*02B1.0020.0004.322A][.FB40.0020.0004.6708][.E708.0000.0000.6708][*02B2.0020.001F.322A] # PARENTHESIZED IDEOGRAPH MOON; QQKN +328A ; [.FB40.0020.0006.6708][.E708.0000.0000.6708] # CIRCLED IDEOGRAPH MOON; QQK +2E9D ; [.FB40.0020.0004.6708][.E708.0000.0000.6708][.0000.0199.001F.2E9D] # CJK RADICAL MOON; QQKN +3232 ; [*02B1.0020.0004.3232][.FB40.0020.0004.6709][.E709.0000.0000.6709][*02B2.0020.001F.3232] # PARENTHESIZED IDEOGRAPH HAVE; QQKN +3292 ; [.FB40.0020.0006.6709][.E709.0000.0000.6709] # CIRCLED IDEOGRAPH HAVE; QQK +F929 ; [.FB40.0020.0002.6717][.E717.0000.0000.6717] # CJK COMPATIBILITY IDEOGRAPH-F929; QQC +FA92 ; [.FB40.0020.0002.6717][.E717.0000.0000.6717] # CJK COMPATIBILITY IDEOGRAPH-FA92; QQC +2F8D8 ; [.FB40.0020.0002.6717][.E717.0000.0000.6717] # CJK COMPATIBILITY IDEOGRAPH-2F8D8; QQC +FA93 ; [.FB40.0020.0002.671B][.E71B.0000.0000.671B] # CJK COMPATIBILITY IDEOGRAPH-FA93; QQC +2F8D9 ; [.FB40.0020.0002.671B][.E71B.0000.0000.671B] # CJK COMPATIBILITY IDEOGRAPH-2F8D9; QQC +2F8DA ; [.FB40.0020.0002.6721][.E721.0000.0000.6721] # CJK COMPATIBILITY IDEOGRAPH-2F8DA; QQC +2F4A ; [.FB40.0020.0004.6728][.E728.0000.0000.6728] # KANGXI RADICAL TREE; QQK +322D ; [*02B1.0020.0004.322D][.FB40.0020.0004.6728][.E728.0000.0000.6728][*02B2.0020.001F.322D] # PARENTHESIZED IDEOGRAPH WOOD; QQKN +328D ; [.FB40.0020.0006.6728][.E728.0000.0000.6728] # CIRCLED IDEOGRAPH WOOD; QQK +F9E1 ; [.FB40.0020.0002.674E][.E74E.0000.0000.674E] # CJK COMPATIBILITY IDEOGRAPH-F9E1; QQC +2F8DC ; [.FB40.0020.0002.6753][.E753.0000.0000.6753] # CJK COMPATIBILITY IDEOGRAPH-2F8DC; QQC +FA94 ; [.FB40.0020.0002.6756][.E756.0000.0000.6756] # CJK COMPATIBILITY IDEOGRAPH-FA94; QQC +2F8DB ; [.FB40.0020.0002.675E][.E75E.0000.0000.675E] # CJK COMPATIBILITY IDEOGRAPH-2F8DB; QQC +F9C8 ; [.FB40.0020.0002.677B][.E77B.0000.0000.677B] # CJK COMPATIBILITY IDEOGRAPH-F9C8; QQC +2F8E0 ; [.FB40.0020.0002.6785][.E785.0000.0000.6785] # CJK COMPATIBILITY IDEOGRAPH-2F8E0; QQC +F9F4 ; [.FB40.0020.0002.6797][.E797.0000.0000.6797] # CJK COMPATIBILITY IDEOGRAPH-F9F4; QQC +F9C9 ; [.FB40.0020.0002.67F3][.E7F3.0000.0000.67F3] # CJK COMPATIBILITY IDEOGRAPH-F9C9; QQC +2F8DF ; [.FB40.0020.0002.67FA][.E7FA.0000.0000.67FA] # CJK COMPATIBILITY IDEOGRAPH-2F8DF; QQC +F9DA ; [.FB40.0020.0002.6817][.E817.0000.0000.6817] # CJK COMPATIBILITY IDEOGRAPH-F9DA; QQC +2F8E5 ; [.FB40.0020.0002.681F][.E81F.0000.0000.681F] # CJK COMPATIBILITY IDEOGRAPH-2F8E5; QQC +3231 ; [*02B1.0020.0004.3231][.FB40.0020.0004.682A][.E82A.0000.0000.682A][*02B2.0020.001F.3231] # PARENTHESIZED IDEOGRAPH STOCK; QQKN +3291 ; [.FB40.0020.0006.682A][.E82A.0000.0000.682A] # CIRCLED IDEOGRAPH STOCK; QQK +337F ; [.FB40.0020.001C.682A][.E82A.0000.0000.682A][.FB40.0020.001F.5F0F][.DF0F.0000.0000.5F0F][.FB40.0020.001F.4F1A][.CF1A.0000.0000.4F1A][.FB40.0020.001F.793E][.F93E.0000.0000.793E] # SQUARE CORPORATION; QQKN +2F8E1 ; [.FB40.0020.0002.6852][.E852.0000.0000.6852] # CJK COMPATIBILITY IDEOGRAPH-2F8E1; QQC +F97A ; [.FB40.0020.0002.6881][.E881.0000.0000.6881] # CJK COMPATIBILITY IDEOGRAPH-F97A; QQC +FA44 ; [.FB40.0020.0002.6885][.E885.0000.0000.6885] # CJK COMPATIBILITY IDEOGRAPH-FA44; QQC +2F8E2 ; [.FB40.0020.0002.6885][.E885.0000.0000.6885] # CJK COMPATIBILITY IDEOGRAPH-2F8E2; QQC +2F8E4 ; [.FB40.0020.0002.688E][.E88E.0000.0000.688E] # CJK COMPATIBILITY IDEOGRAPH-2F8E4; QQC +F9E2 ; [.FB40.0020.0002.68A8][.E8A8.0000.0000.68A8] # CJK COMPATIBILITY IDEOGRAPH-F9E2; QQC +2F8E6 ; [.FB40.0020.0002.6914][.E914.0000.0000.6914] # CJK COMPATIBILITY IDEOGRAPH-2F8E6; QQC +2F8E8 ; [.FB40.0020.0002.6942][.E942.0000.0000.6942] # CJK COMPATIBILITY IDEOGRAPH-2F8E8; QQC +2F8E9 ; [.FB40.0020.0002.69A3][.E9A3.0000.0000.69A3] # CJK COMPATIBILITY IDEOGRAPH-2F8E9; QQC +2F8EA ; [.FB40.0020.0002.69EA][.E9EA.0000.0000.69EA] # CJK COMPATIBILITY IDEOGRAPH-2F8EA; QQC +F914 ; [.FB40.0020.0002.6A02][.EA02.0000.0000.6A02] # CJK COMPATIBILITY IDEOGRAPH-F914; QQC +F95C ; [.FB40.0020.0002.6A02][.EA02.0000.0000.6A02] # CJK COMPATIBILITY IDEOGRAPH-F95C; QQC +F9BF ; [.FB40.0020.0002.6A02][.EA02.0000.0000.6A02] # CJK COMPATIBILITY IDEOGRAPH-F9BF; QQC +F94C ; [.FB40.0020.0002.6A13][.EA13.0000.0000.6A13] # CJK COMPATIBILITY IDEOGRAPH-F94C; QQC +2F8EB ; [.FB40.0020.0002.6AA8][.EAA8.0000.0000.6AA8] # CJK COMPATIBILITY IDEOGRAPH-2F8EB; QQC +F931 ; [.FB40.0020.0002.6AD3][.EAD3.0000.0000.6AD3] # CJK COMPATIBILITY IDEOGRAPH-F931; QQC +2F8ED ; [.FB40.0020.0002.6ADB][.EADB.0000.0000.6ADB] # CJK COMPATIBILITY IDEOGRAPH-2F8ED; QQC +F91D ; [.FB40.0020.0002.6B04][.EB04.0000.0000.6B04] # CJK COMPATIBILITY IDEOGRAPH-F91D; QQC +2F4B ; [.FB40.0020.0004.6B20][.EB20.0000.0000.6B20] # KANGXI RADICAL LACK; QQK +2F8EF ; [.FB40.0020.0002.6B21][.EB21.0000.0000.6B21] # CJK COMPATIBILITY IDEOGRAPH-2F8EF; QQC +2F8F1 ; [.FB40.0020.0002.6B54][.EB54.0000.0000.6B54] # CJK COMPATIBILITY IDEOGRAPH-2F8F1; QQC +2F4C ; [.FB40.0020.0004.6B62][.EB62.0000.0000.6B62] # KANGXI RADICAL STOP; QQK +32A3 ; [.FB40.0020.0006.6B63][.EB63.0000.0000.6B63] # CIRCLED IDEOGRAPH CORRECT; QQK +2F8F3 ; [.FB40.0020.0002.6B72][.EB72.0000.0000.6B72] # CJK COMPATIBILITY IDEOGRAPH-2F8F3; QQC +F98C ; [.FB40.0020.0002.6B77][.EB77.0000.0000.6B77] # CJK COMPATIBILITY IDEOGRAPH-F98C; QQC +FA95 ; [.FB40.0020.0002.6B79][.EB79.0000.0000.6B79] # CJK COMPATIBILITY IDEOGRAPH-FA95; QQC +2F4D ; [.FB40.0020.0004.6B79][.EB79.0000.0000.6B79] # KANGXI RADICAL DEATH; QQK +2E9E ; [.FB40.0020.0004.6B7A][.EB7A.0000.0000.6B7A][.0000.0199.001F.2E9E] # CJK RADICAL DEATH; QQKN +2F8F4 ; [.FB40.0020.0002.6B9F][.EB9F.0000.0000.6B9F] # CJK COMPATIBILITY IDEOGRAPH-2F8F4; QQC +F9A5 ; [.FB40.0020.0002.6BAE][.EBAE.0000.0000.6BAE] # CJK COMPATIBILITY IDEOGRAPH-F9A5; QQC +2F4E ; [.FB40.0020.0004.6BB3][.EBB3.0000.0000.6BB3] # KANGXI RADICAL WEAPON; QQK +F970 ; [.FB40.0020.0002.6BBA][.EBBA.0000.0000.6BBA] # CJK COMPATIBILITY IDEOGRAPH-F970; QQC +FA96 ; [.FB40.0020.0002.6BBA][.EBBA.0000.0000.6BBA] # CJK COMPATIBILITY IDEOGRAPH-FA96; QQC +2F8F5 ; [.FB40.0020.0002.6BBA][.EBBA.0000.0000.6BBA] # CJK COMPATIBILITY IDEOGRAPH-2F8F5; QQC +2F8F6 ; [.FB40.0020.0002.6BBB][.EBBB.0000.0000.6BBB] # CJK COMPATIBILITY IDEOGRAPH-2F8F6; QQC +2F4F ; [.FB40.0020.0004.6BCB][.EBCB.0000.0000.6BCB] # KANGXI RADICAL DO NOT; QQK +2E9F ; [.FB40.0020.0004.6BCD][.EBCD.0000.0000.6BCD] # CJK RADICAL MOTHER; QQK +2F50 ; [.FB40.0020.0004.6BD4][.EBD4.0000.0000.6BD4] # KANGXI RADICAL COMPARE; QQK +2F51 ; [.FB40.0020.0004.6BDB][.EBDB.0000.0000.6BDB] # KANGXI RADICAL FUR; QQK +2F52 ; [.FB40.0020.0004.6C0F][.EC0F.0000.0000.6C0F] # KANGXI RADICAL CLAN; QQK +2EA0 ; [.FB40.0020.0004.6C11][.EC11.0000.0000.6C11] # CJK RADICAL CIVILIAN; QQK +2F53 ; [.FB40.0020.0004.6C14][.EC14.0000.0000.6C14] # KANGXI RADICAL STEAM; QQK +2F54 ; [.FB40.0020.0004.6C34][.EC34.0000.0000.6C34] # KANGXI RADICAL WATER; QQK +322C ; [*02B1.0020.0004.322C][.FB40.0020.0004.6C34][.EC34.0000.0000.6C34][*02B2.0020.001F.322C] # PARENTHESIZED IDEOGRAPH WATER; QQKN +328C ; [.FB40.0020.0006.6C34][.EC34.0000.0000.6C34] # CIRCLED IDEOGRAPH WATER; QQK +2EA1 ; [.FB40.0020.0004.6C35][.EC35.0000.0000.6C35] # CJK RADICAL WATER ONE; QQK +2EA2 ; [.FB40.0020.0004.6C3A][.EC3A.0000.0000.6C3A] # CJK RADICAL WATER TWO; QQK +2F8FA ; [.FB40.0020.0002.6C4E][.EC4E.0000.0000.6C4E] # CJK COMPATIBILITY IDEOGRAPH-2F8FA; QQC +2F8FE ; [.FB40.0020.0002.6C67][.EC67.0000.0000.6C67] # CJK COMPATIBILITY IDEOGRAPH-2F8FE; QQC +F972 ; [.FB40.0020.0002.6C88][.EC88.0000.0000.6C88] # CJK COMPATIBILITY IDEOGRAPH-F972; QQC +2F8FC ; [.FB40.0020.0002.6CBF][.ECBF.0000.0000.6CBF] # CJK COMPATIBILITY IDEOGRAPH-2F8FC; QQC +F968 ; [.FB40.0020.0002.6CCC][.ECCC.0000.0000.6CCC] # CJK COMPATIBILITY IDEOGRAPH-F968; QQC +2F8FD ; [.FB40.0020.0002.6CCD][.ECCD.0000.0000.6CCD] # CJK COMPATIBILITY IDEOGRAPH-2F8FD; QQC +F9E3 ; [.FB40.0020.0002.6CE5][.ECE5.0000.0000.6CE5] # CJK COMPATIBILITY IDEOGRAPH-F9E3; QQC +329F ; [.FB40.0020.0006.6CE8][.ECE8.0000.0000.6CE8] # CIRCLED IDEOGRAPH ATTENTION; QQK +2F8FF ; [.FB40.0020.0002.6D16][.ED16.0000.0000.6D16] # CJK COMPATIBILITY IDEOGRAPH-2F8FF; QQC +F915 ; [.FB40.0020.0002.6D1B][.ED1B.0000.0000.6D1B] # CJK COMPATIBILITY IDEOGRAPH-F915; QQC +FA05 ; [.FB40.0020.0002.6D1E][.ED1E.0000.0000.6D1E] # CJK COMPATIBILITY IDEOGRAPH-FA05; QQC +2F907 ; [.FB40.0020.0002.6D34][.ED34.0000.0000.6D34] # CJK COMPATIBILITY IDEOGRAPH-2F907; QQC +2F900 ; [.FB40.0020.0002.6D3E][.ED3E.0000.0000.6D3E] # CJK COMPATIBILITY IDEOGRAPH-2F900; QQC +F9CA ; [.FB40.0020.0002.6D41][.ED41.0000.0000.6D41] # CJK COMPATIBILITY IDEOGRAPH-F9CA; QQC +FA97 ; [.FB40.0020.0002.6D41][.ED41.0000.0000.6D41] # CJK COMPATIBILITY IDEOGRAPH-FA97; QQC +2F902 ; [.FB40.0020.0002.6D41][.ED41.0000.0000.6D41] # CJK COMPATIBILITY IDEOGRAPH-2F902; QQC +2F903 ; [.FB40.0020.0002.6D69][.ED69.0000.0000.6D69] # CJK COMPATIBILITY IDEOGRAPH-2F903; QQC +F92A ; [.FB40.0020.0002.6D6A][.ED6A.0000.0000.6D6A] # CJK COMPATIBILITY IDEOGRAPH-F92A; QQC +FA45 ; [.FB40.0020.0002.6D77][.ED77.0000.0000.6D77] # CJK COMPATIBILITY IDEOGRAPH-FA45; QQC +2F901 ; [.FB40.0020.0002.6D77][.ED77.0000.0000.6D77] # CJK COMPATIBILITY IDEOGRAPH-2F901; QQC +2F904 ; [.FB40.0020.0002.6D78][.ED78.0000.0000.6D78] # CJK COMPATIBILITY IDEOGRAPH-2F904; QQC +2F905 ; [.FB40.0020.0002.6D85][.ED85.0000.0000.6D85] # CJK COMPATIBILITY IDEOGRAPH-2F905; QQC +F9F5 ; [.FB40.0020.0002.6DCB][.EDCB.0000.0000.6DCB] # CJK COMPATIBILITY IDEOGRAPH-F9F5; QQC +F94D ; [.FB40.0020.0002.6DDA][.EDDA.0000.0000.6DDA] # CJK COMPATIBILITY IDEOGRAPH-F94D; QQC +F9D6 ; [.FB40.0020.0002.6DEA][.EDEA.0000.0000.6DEA] # CJK COMPATIBILITY IDEOGRAPH-F9D6; QQC +2F90E ; [.FB40.0020.0002.6DF9][.EDF9.0000.0000.6DF9] # CJK COMPATIBILITY IDEOGRAPH-2F90E; QQC +FA46 ; [.FB40.0020.0002.6E1A][.EE1A.0000.0000.6E1A] # CJK COMPATIBILITY IDEOGRAPH-FA46; QQC +2F908 ; [.FB40.0020.0002.6E2F][.EE2F.0000.0000.6E2F] # CJK COMPATIBILITY IDEOGRAPH-2F908; QQC +2F909 ; [.FB40.0020.0002.6E6E][.EE6E.0000.0000.6E6E] # CJK COMPATIBILITY IDEOGRAPH-2F909; QQC +F9CB ; [.FB40.0020.0002.6E9C][.EE9C.0000.0000.6E9C] # CJK COMPATIBILITY IDEOGRAPH-F9CB; QQC +F9EC ; [.FB40.0020.0002.6EBA][.EEBA.0000.0000.6EBA] # CJK COMPATIBILITY IDEOGRAPH-F9EC; QQC +2F90C ; [.FB40.0020.0002.6EC7][.EEC7.0000.0000.6EC7] # CJK COMPATIBILITY IDEOGRAPH-2F90C; QQC +FA99 ; [.FB40.0020.0002.6ECB][.EECB.0000.0000.6ECB] # CJK COMPATIBILITY IDEOGRAPH-FA99; QQC +2F90B ; [.FB40.0020.0002.6ECB][.EECB.0000.0000.6ECB] # CJK COMPATIBILITY IDEOGRAPH-2F90B; QQC +F904 ; [.FB40.0020.0002.6ED1][.EED1.0000.0000.6ED1] # CJK COMPATIBILITY IDEOGRAPH-F904; QQC +FA98 ; [.FB40.0020.0002.6EDB][.EEDB.0000.0000.6EDB] # CJK COMPATIBILITY IDEOGRAPH-FA98; QQC +F94E ; [.FB40.0020.0002.6F0F][.EF0F.0000.0000.6F0F] # CJK COMPATIBILITY IDEOGRAPH-F94E; QQC +FA47 ; [.FB40.0020.0002.6F22][.EF22.0000.0000.6F22] # CJK COMPATIBILITY IDEOGRAPH-FA47; QQC +FA9A ; [.FB40.0020.0002.6F22][.EF22.0000.0000.6F22] # CJK COMPATIBILITY IDEOGRAPH-FA9A; QQC +F992 ; [.FB40.0020.0002.6F23][.EF23.0000.0000.6F23] # CJK COMPATIBILITY IDEOGRAPH-F992; QQC +2F90F ; [.FB40.0020.0002.6F6E][.EF6E.0000.0000.6F6E] # CJK COMPATIBILITY IDEOGRAPH-2F90F; QQC +2F912 ; [.FB40.0020.0002.6FC6][.EFC6.0000.0000.6FC6] # CJK COMPATIBILITY IDEOGRAPH-2F912; QQC +F922 ; [.FB40.0020.0002.6FEB][.EFEB.0000.0000.6FEB] # CJK COMPATIBILITY IDEOGRAPH-F922; QQC +F984 ; [.FB40.0020.0002.6FFE][.EFFE.0000.0000.6FFE] # CJK COMPATIBILITY IDEOGRAPH-F984; QQC +2F915 ; [.FB40.0020.0002.701B][.F01B.0000.0000.701B] # CJK COMPATIBILITY IDEOGRAPH-2F915; QQC +FA9B ; [.FB40.0020.0002.701E][.F01E.0000.0000.701E] # CJK COMPATIBILITY IDEOGRAPH-FA9B; QQC +2F914 ; [.FB40.0020.0002.701E][.F01E.0000.0000.701E] # CJK COMPATIBILITY IDEOGRAPH-2F914; QQC +2F913 ; [.FB40.0020.0002.7039][.F039.0000.0000.7039] # CJK COMPATIBILITY IDEOGRAPH-2F913; QQC +2F917 ; [.FB40.0020.0002.704A][.F04A.0000.0000.704A] # CJK COMPATIBILITY IDEOGRAPH-2F917; QQC +2F55 ; [.FB40.0020.0004.706B][.F06B.0000.0000.706B] # KANGXI RADICAL FIRE; QQK +322B ; [*02B1.0020.0004.322B][.FB40.0020.0004.706B][.F06B.0000.0000.706B][*02B2.0020.001F.322B] # PARENTHESIZED IDEOGRAPH FIRE; QQKN +328B ; [.FB40.0020.0006.706B][.F06B.0000.0000.706B] # CIRCLED IDEOGRAPH FIRE; QQK +2EA3 ; [.FB40.0020.0004.706C][.F06C.0000.0000.706C] # CJK RADICAL FIRE; QQK +2F835 ; [.FB40.0020.0002.7070][.F070.0000.0000.7070] # CJK COMPATIBILITY IDEOGRAPH-2F835; QQC +2F919 ; [.FB40.0020.0002.7077][.F077.0000.0000.7077] # CJK COMPATIBILITY IDEOGRAPH-2F919; QQC +2F918 ; [.FB40.0020.0002.707D][.F07D.0000.0000.707D] # CJK COMPATIBILITY IDEOGRAPH-2F918; QQC +F9FB ; [.FB40.0020.0002.7099][.F099.0000.0000.7099] # CJK COMPATIBILITY IDEOGRAPH-F9FB; QQC +2F91A ; [.FB40.0020.0002.70AD][.F0AD.0000.0000.70AD] # CJK COMPATIBILITY IDEOGRAPH-2F91A; QQC +F99F ; [.FB40.0020.0002.70C8][.F0C8.0000.0000.70C8] # CJK COMPATIBILITY IDEOGRAPH-F99F; QQC +F916 ; [.FB40.0020.0002.70D9][.F0D9.0000.0000.70D9] # CJK COMPATIBILITY IDEOGRAPH-F916; QQC +2F91C ; [.FB40.0020.0002.7145][.F145.0000.0000.7145] # CJK COMPATIBILITY IDEOGRAPH-2F91C; QQC +F993 ; [.FB40.0020.0002.7149][.F149.0000.0000.7149] # CJK COMPATIBILITY IDEOGRAPH-F993; QQC +FA48 ; [.FB40.0020.0002.716E][.F16E.0000.0000.716E] # CJK COMPATIBILITY IDEOGRAPH-FA48; QQC +FA9C ; [.FB40.0020.0002.716E][.F16E.0000.0000.716E] # CJK COMPATIBILITY IDEOGRAPH-FA9C; QQC +2F91E ; [.FB40.0020.0002.719C][.F19C.0000.0000.719C] # CJK COMPATIBILITY IDEOGRAPH-2F91E; QQC +F9C0 ; [.FB40.0020.0002.71CE][.F1CE.0000.0000.71CE] # CJK COMPATIBILITY IDEOGRAPH-F9C0; QQC +F9EE ; [.FB40.0020.0002.71D0][.F1D0.0000.0000.71D0] # CJK COMPATIBILITY IDEOGRAPH-F9EE; QQC +F932 ; [.FB40.0020.0002.7210][.F210.0000.0000.7210] # CJK COMPATIBILITY IDEOGRAPH-F932; QQC +F91E ; [.FB40.0020.0002.721B][.F21B.0000.0000.721B] # CJK COMPATIBILITY IDEOGRAPH-F91E; QQC +2F920 ; [.FB40.0020.0002.7228][.F228.0000.0000.7228] # CJK COMPATIBILITY IDEOGRAPH-2F920; QQC +2F56 ; [.FB40.0020.0004.722A][.F22A.0000.0000.722A] # KANGXI RADICAL CLAW; QQK +FA49 ; [.FB40.0020.0002.722B][.F22B.0000.0000.722B] # CJK COMPATIBILITY IDEOGRAPH-FA49; QQC +2EA4 ; [.FB40.0020.0004.722B][.F22B.0000.0000.722B] # CJK RADICAL PAW ONE; QQK +2EA5 ; [.FB40.0020.0004.722B][.F22B.0000.0000.722B][.0000.0199.001F.2EA5] # CJK RADICAL PAW TWO; QQKN +FA9E ; [.FB40.0020.0002.7235][.F235.0000.0000.7235] # CJK COMPATIBILITY IDEOGRAPH-FA9E; QQC +2F921 ; [.FB40.0020.0002.7235][.F235.0000.0000.7235] # CJK COMPATIBILITY IDEOGRAPH-2F921; QQC +2F57 ; [.FB40.0020.0004.7236][.F236.0000.0000.7236] # KANGXI RADICAL FATHER; QQK +2F58 ; [.FB40.0020.0004.723B][.F23B.0000.0000.723B] # KANGXI RADICAL DOUBLE X; QQK +2F59 ; [.FB40.0020.0004.723F][.F23F.0000.0000.723F] # KANGXI RADICAL HALF TREE TRUNK; QQK +2F5A ; [.FB40.0020.0004.7247][.F247.0000.0000.7247] # KANGXI RADICAL SLICE; QQK +2F922 ; [.FB40.0020.0002.7250][.F250.0000.0000.7250] # CJK COMPATIBILITY IDEOGRAPH-2F922; QQC +2F5B ; [.FB40.0020.0004.7259][.F259.0000.0000.7259] # KANGXI RADICAL FANG; QQK +2F5C ; [.FB40.0020.0004.725B][.F25B.0000.0000.725B] # KANGXI RADICAL COW; QQK +2EA7 ; [.FB40.0020.0004.725B][.F25B.0000.0000.725B][.0000.0199.001F.2EA7] # CJK RADICAL COW; QQKN +F946 ; [.FB40.0020.0002.7262][.F262.0000.0000.7262] # CJK COMPATIBILITY IDEOGRAPH-F946; QQC +3235 ; [*02B1.0020.0004.3235][.FB40.0020.0004.7279][.F279.0000.0000.7279][*02B2.0020.001F.3235] # PARENTHESIZED IDEOGRAPH SPECIAL; QQKN +3295 ; [.FB40.0020.0006.7279][.F279.0000.0000.7279] # CIRCLED IDEOGRAPH SPECIAL; QQK +2F924 ; [.FB40.0020.0002.7280][.F280.0000.0000.7280] # CJK COMPATIBILITY IDEOGRAPH-2F924; QQC +2F925 ; [.FB40.0020.0002.7295][.F295.0000.0000.7295] # CJK COMPATIBILITY IDEOGRAPH-2F925; QQC +2F5D ; [.FB40.0020.0004.72AC][.F2AC.0000.0000.72AC] # KANGXI RADICAL DOG; QQK +2EA8 ; [.FB40.0020.0004.72AD][.F2AD.0000.0000.72AD] # CJK RADICAL DOG; QQK +FA9F ; [.FB40.0020.0002.72AF][.F2AF.0000.0000.72AF] # CJK COMPATIBILITY IDEOGRAPH-FA9F; QQC +F9FA ; [.FB40.0020.0002.72C0][.F2C0.0000.0000.72C0] # CJK COMPATIBILITY IDEOGRAPH-F9FA; QQC +F92B ; [.FB40.0020.0002.72FC][.F2FC.0000.0000.72FC] # CJK COMPATIBILITY IDEOGRAPH-F92B; QQC +FA16 ; [.FB40.0020.0002.732A][.F32A.0000.0000.732A] # CJK COMPATIBILITY IDEOGRAPH-FA16; QQC +FAA0 ; [.FB40.0020.0002.732A][.F32A.0000.0000.732A] # CJK COMPATIBILITY IDEOGRAPH-FAA0; QQC +F9A7 ; [.FB40.0020.0002.7375][.F375.0000.0000.7375] # CJK COMPATIBILITY IDEOGRAPH-F9A7; QQC +2F928 ; [.FB40.0020.0002.737A][.F37A.0000.0000.737A] # CJK COMPATIBILITY IDEOGRAPH-2F928; QQC +2F5E ; [.FB40.0020.0004.7384][.F384.0000.0000.7384] # KANGXI RADICAL PROFOUND; QQK +F961 ; [.FB40.0020.0002.7387][.F387.0000.0000.7387] # CJK COMPATIBILITY IDEOGRAPH-F961; QQC +F9DB ; [.FB40.0020.0002.7387][.F387.0000.0000.7387] # CJK COMPATIBILITY IDEOGRAPH-F9DB; QQC +2F5F ; [.FB40.0020.0004.7389][.F389.0000.0000.7389] # KANGXI RADICAL JADE; QQK +2F929 ; [.FB40.0020.0002.738B][.F38B.0000.0000.738B] # CJK COMPATIBILITY IDEOGRAPH-2F929; QQC +2EA9 ; [.FB40.0020.0004.738B][.F38B.0000.0000.738B][.0000.0199.001F.2EA9] # CJK RADICAL JADE; QQKN +2F92B ; [.FB40.0020.0002.73A5][.F3A5.0000.0000.73A5] # CJK COMPATIBILITY IDEOGRAPH-2F92B; QQC +F9AD ; [.FB40.0020.0002.73B2][.F3B2.0000.0000.73B2] # CJK COMPATIBILITY IDEOGRAPH-F9AD; QQC +F917 ; [.FB40.0020.0002.73DE][.F3DE.0000.0000.73DE] # CJK COMPATIBILITY IDEOGRAPH-F917; QQC +F9E4 ; [.FB40.0020.0002.7406][.F406.0000.0000.7406] # CJK COMPATIBILITY IDEOGRAPH-F9E4; QQC +F9CC ; [.FB40.0020.0002.7409][.F409.0000.0000.7409] # CJK COMPATIBILITY IDEOGRAPH-F9CC; QQC +FA4A ; [.FB40.0020.0002.7422][.F422.0000.0000.7422] # CJK COMPATIBILITY IDEOGRAPH-FA4A; QQC +2F92E ; [.FB40.0020.0002.7447][.F447.0000.0000.7447] # CJK COMPATIBILITY IDEOGRAPH-2F92E; QQC +2F92F ; [.FB40.0020.0002.745C][.F45C.0000.0000.745C] # CJK COMPATIBILITY IDEOGRAPH-2F92F; QQC +F9AE ; [.FB40.0020.0002.7469][.F469.0000.0000.7469] # CJK COMPATIBILITY IDEOGRAPH-F9AE; QQC +FAA1 ; [.FB40.0020.0002.7471][.F471.0000.0000.7471] # CJK COMPATIBILITY IDEOGRAPH-FAA1; QQC +2F930 ; [.FB40.0020.0002.7471][.F471.0000.0000.7471] # CJK COMPATIBILITY IDEOGRAPH-2F930; QQC +2F931 ; [.FB40.0020.0002.7485][.F485.0000.0000.7485] # CJK COMPATIBILITY IDEOGRAPH-2F931; QQC +F994 ; [.FB40.0020.0002.7489][.F489.0000.0000.7489] # CJK COMPATIBILITY IDEOGRAPH-F994; QQC +F9EF ; [.FB40.0020.0002.7498][.F498.0000.0000.7498] # CJK COMPATIBILITY IDEOGRAPH-F9EF; QQC +2F932 ; [.FB40.0020.0002.74CA][.F4CA.0000.0000.74CA] # CJK COMPATIBILITY IDEOGRAPH-2F932; QQC +2F60 ; [.FB40.0020.0004.74DC][.F4DC.0000.0000.74DC] # KANGXI RADICAL MELON; QQK +2F61 ; [.FB40.0020.0004.74E6][.F4E6.0000.0000.74E6] # KANGXI RADICAL TILE; QQK +FAA2 ; [.FB40.0020.0002.7506][.F506.0000.0000.7506] # CJK COMPATIBILITY IDEOGRAPH-FAA2; QQC +2F62 ; [.FB40.0020.0004.7518][.F518.0000.0000.7518] # KANGXI RADICAL SWEET; QQK +2F63 ; [.FB40.0020.0004.751F][.F51F.0000.0000.751F] # KANGXI RADICAL LIFE; QQK +2F934 ; [.FB40.0020.0002.7524][.F524.0000.0000.7524] # CJK COMPATIBILITY IDEOGRAPH-2F934; QQC +2F64 ; [.FB40.0020.0004.7528][.F528.0000.0000.7528] # KANGXI RADICAL USE; QQK +2F65 ; [.FB40.0020.0004.7530][.F530.0000.0000.7530] # KANGXI RADICAL FIELD; QQK +3199 ; [.FB40.0020.0014.7532][.F532.0000.0000.7532] # IDEOGRAPHIC ANNOTATION FIRST MARK; QQK +329A ; [.FB40.0020.0006.7537][.F537.0000.0000.7537] # CIRCLED IDEOGRAPH MALE; QQK +FAA3 ; [.FB40.0020.0002.753B][.F53B.0000.0000.753B] # CJK COMPATIBILITY IDEOGRAPH-FAA3; QQC +2F936 ; [.FB40.0020.0002.753E][.F53E.0000.0000.753E] # CJK COMPATIBILITY IDEOGRAPH-2F936; QQC +F9CD ; [.FB40.0020.0002.7559][.F559.0000.0000.7559] # CJK COMPATIBILITY IDEOGRAPH-F9CD; QQC +F976 ; [.FB40.0020.0002.7565][.F565.0000.0000.7565] # CJK COMPATIBILITY IDEOGRAPH-F976; QQC +F962 ; [.FB40.0020.0002.7570][.F570.0000.0000.7570] # CJK COMPATIBILITY IDEOGRAPH-F962; QQC +2F938 ; [.FB40.0020.0002.7570][.F570.0000.0000.7570] # CJK COMPATIBILITY IDEOGRAPH-2F938; QQC +2F66 ; [.FB40.0020.0004.758B][.F58B.0000.0000.758B] # KANGXI RADICAL BOLT OF CLOTH; QQK +2EAA ; [.FB40.0020.0004.758B][.F58B.0000.0000.758B][.0000.0199.001F.2EAA] # CJK RADICAL BOLT OF CLOTH; QQKN +2F67 ; [.FB40.0020.0004.7592][.F592.0000.0000.7592] # KANGXI RADICAL SICKNESS; QQK +F9E5 ; [.FB40.0020.0002.75E2][.F5E2.0000.0000.75E2] # CJK COMPATIBILITY IDEOGRAPH-F9E5; QQC +2F93A ; [.FB40.0020.0002.7610][.F610.0000.0000.7610] # CJK COMPATIBILITY IDEOGRAPH-2F93A; QQC +FAA4 ; [.FB40.0020.0002.761D][.F61D.0000.0000.761D] # CJK COMPATIBILITY IDEOGRAPH-FAA4; QQC +FAA5 ; [.FB40.0020.0002.761F][.F61F.0000.0000.761F] # CJK COMPATIBILITY IDEOGRAPH-FAA5; QQC +F9C1 ; [.FB40.0020.0002.7642][.F642.0000.0000.7642] # CJK COMPATIBILITY IDEOGRAPH-F9C1; QQC +F90E ; [.FB40.0020.0002.7669][.F669.0000.0000.7669] # CJK COMPATIBILITY IDEOGRAPH-F90E; QQC +2F68 ; [.FB40.0020.0004.7676][.F676.0000.0000.7676] # KANGXI RADICAL DOTTED TENT; QQK +2F69 ; [.FB40.0020.0004.767D][.F67D.0000.0000.767D] # KANGXI RADICAL WHITE; QQK +2F6A ; [.FB40.0020.0004.76AE][.F6AE.0000.0000.76AE] # KANGXI RADICAL SKIN; QQK +2F6B ; [.FB40.0020.0004.76BF][.F6BF.0000.0000.76BF] # KANGXI RADICAL DISH; QQK +FA17 ; [.FB40.0020.0002.76CA][.F6CA.0000.0000.76CA] # CJK COMPATIBILITY IDEOGRAPH-FA17; QQC +FAA6 ; [.FB40.0020.0002.76CA][.F6CA.0000.0000.76CA] # CJK COMPATIBILITY IDEOGRAPH-FAA6; QQC +FAA7 ; [.FB40.0020.0002.76DB][.F6DB.0000.0000.76DB] # CJK COMPATIBILITY IDEOGRAPH-FAA7; QQC +323C ; [*02B1.0020.0004.323C][.FB40.0020.0004.76E3][.F6E3.0000.0000.76E3][*02B2.0020.001F.323C] # PARENTHESIZED IDEOGRAPH SUPERVISE; QQKN +32AC ; [.FB40.0020.0006.76E3][.F6E3.0000.0000.76E3] # CIRCLED IDEOGRAPH SUPERVISE; QQK +F933 ; [.FB40.0020.0002.76E7][.F6E7.0000.0000.76E7] # CJK COMPATIBILITY IDEOGRAPH-F933; QQC +2F6C ; [.FB40.0020.0004.76EE][.F6EE.0000.0000.76EE] # KANGXI RADICAL EYE; QQK +2EAB ; [.FB40.0020.0004.76EE][.F6EE.0000.0000.76EE][.0000.0199.001F.2EAB] # CJK RADICAL EYE; QQKN +FAA8 ; [.FB40.0020.0002.76F4][.F6F4.0000.0000.76F4] # CJK COMPATIBILITY IDEOGRAPH-FAA8; QQC +2F940 ; [.FB40.0020.0002.76F4][.F6F4.0000.0000.76F4] # CJK COMPATIBILITY IDEOGRAPH-2F940; QQC +F96D ; [.FB40.0020.0002.7701][.F701.0000.0000.7701] # CJK COMPATIBILITY IDEOGRAPH-F96D; QQC +2F945 ; [.FB40.0020.0002.771E][.F71E.0000.0000.771E] # CJK COMPATIBILITY IDEOGRAPH-2F945; QQC +2F946 ; [.FB40.0020.0002.771F][.F71F.0000.0000.771F] # CJK COMPATIBILITY IDEOGRAPH-2F946; QQC +2F947 ; [.FB40.0020.0002.771F][.F71F.0000.0000.771F] # CJK COMPATIBILITY IDEOGRAPH-2F947; QQC +FAAA ; [.FB40.0020.0002.7740][.F740.0000.0000.7740] # CJK COMPATIBILITY IDEOGRAPH-FAAA; QQC +FAA9 ; [.FB40.0020.0002.774A][.F74A.0000.0000.774A] # CJK COMPATIBILITY IDEOGRAPH-FAA9; QQC +2F948 ; [.FB40.0020.0002.774A][.F74A.0000.0000.774A] # CJK COMPATIBILITY IDEOGRAPH-2F948; QQC +2F94A ; [.FB40.0020.0002.778B][.F78B.0000.0000.778B] # CJK COMPATIBILITY IDEOGRAPH-2F94A; QQC +FA9D ; [.FB40.0020.0002.77A7][.F7A7.0000.0000.77A7] # CJK COMPATIBILITY IDEOGRAPH-FA9D; QQC +2F6D ; [.FB40.0020.0004.77DB][.F7DB.0000.0000.77DB] # KANGXI RADICAL SPEAR; QQK +2F6E ; [.FB40.0020.0004.77E2][.F7E2.0000.0000.77E2] # KANGXI RADICAL ARROW; QQK +2F6F ; [.FB40.0020.0004.77F3][.F7F3.0000.0000.77F3] # KANGXI RADICAL STONE; QQK +2F94E ; [.FB40.0020.0002.784E][.F84E.0000.0000.784E] # CJK COMPATIBILITY IDEOGRAPH-2F94E; QQC +F9CE ; [.FB40.0020.0002.786B][.F86B.0000.0000.786B] # CJK COMPATIBILITY IDEOGRAPH-F9CE; QQC +F93B ; [.FB40.0020.0002.788C][.F88C.0000.0000.788C] # CJK COMPATIBILITY IDEOGRAPH-F93B; QQC +2F94F ; [.FB40.0020.0002.788C][.F88C.0000.0000.788C] # CJK COMPATIBILITY IDEOGRAPH-2F94F; QQC +FA4B ; [.FB40.0020.0002.7891][.F891.0000.0000.7891] # CJK COMPATIBILITY IDEOGRAPH-FA4B; QQC +F947 ; [.FB40.0020.0002.78CA][.F8CA.0000.0000.78CA] # CJK COMPATIBILITY IDEOGRAPH-F947; QQC +FAAB ; [.FB40.0020.0002.78CC][.F8CC.0000.0000.78CC] # CJK COMPATIBILITY IDEOGRAPH-FAAB; QQC +2F950 ; [.FB40.0020.0002.78CC][.F8CC.0000.0000.78CC] # CJK COMPATIBILITY IDEOGRAPH-2F950; QQC +F964 ; [.FB40.0020.0002.78FB][.F8FB.0000.0000.78FB] # CJK COMPATIBILITY IDEOGRAPH-F964; QQC +F985 ; [.FB40.0020.0002.792A][.F92A.0000.0000.792A] # CJK COMPATIBILITY IDEOGRAPH-F985; QQC +2F70 ; [.FB40.0020.0004.793A][.F93A.0000.0000.793A] # KANGXI RADICAL SPIRIT; QQK +2EAC ; [.FB40.0020.0004.793A][.F93A.0000.0000.793A][.0000.0199.001F.2EAC] # CJK RADICAL SPIRIT ONE; QQKN +2EAD ; [.FB40.0020.0004.793B][.F93B.0000.0000.793B] # CJK RADICAL SPIRIT TWO; QQK +FA18 ; [.FB40.0020.0002.793C][.F93C.0000.0000.793C] # CJK COMPATIBILITY IDEOGRAPH-FA18; QQC +FA4C ; [.FB40.0020.0002.793E][.F93E.0000.0000.793E] # CJK COMPATIBILITY IDEOGRAPH-FA4C; QQC +3233 ; [*02B1.0020.0004.3233][.FB40.0020.0004.793E][.F93E.0000.0000.793E][*02B2.0020.001F.3233] # PARENTHESIZED IDEOGRAPH SOCIETY; QQKN +3293 ; [.FB40.0020.0006.793E][.F93E.0000.0000.793E] # CIRCLED IDEOGRAPH SOCIETY; QQK +FA4E ; [.FB40.0020.0002.7948][.F948.0000.0000.7948] # CJK COMPATIBILITY IDEOGRAPH-FA4E; QQC +FA4D ; [.FB40.0020.0002.7949][.F949.0000.0000.7949] # CJK COMPATIBILITY IDEOGRAPH-FA4D; QQC +FA4F ; [.FB40.0020.0002.7950][.F950.0000.0000.7950] # CJK COMPATIBILITY IDEOGRAPH-FA4F; QQC +FA50 ; [.FB40.0020.0002.7956][.F956.0000.0000.7956] # CJK COMPATIBILITY IDEOGRAPH-FA50; QQC +2F953 ; [.FB40.0020.0002.7956][.F956.0000.0000.7956] # CJK COMPATIBILITY IDEOGRAPH-2F953; QQC +FA51 ; [.FB40.0020.0002.795D][.F95D.0000.0000.795D] # CJK COMPATIBILITY IDEOGRAPH-FA51; QQC +3237 ; [*02B1.0020.0004.3237][.FB40.0020.0004.795D][.F95D.0000.0000.795D][*02B2.0020.001F.3237] # PARENTHESIZED IDEOGRAPH CONGRATULATION; QQKN +3297 ; [.FB40.0020.0006.795D][.F95D.0000.0000.795D] # CIRCLED IDEOGRAPH CONGRATULATION; QQK +FA19 ; [.FB40.0020.0002.795E][.F95E.0000.0000.795E] # CJK COMPATIBILITY IDEOGRAPH-FA19; QQC +FA1A ; [.FB40.0020.0002.7965][.F965.0000.0000.7965] # CJK COMPATIBILITY IDEOGRAPH-FA1A; QQC +3240 ; [*02B1.0020.0004.3240][.FB40.0020.0004.796D][.F96D.0000.0000.796D][*02B2.0020.001F.3240] # PARENTHESIZED IDEOGRAPH FESTIVAL; QQKN +F93C ; [.FB40.0020.0002.797F][.F97F.0000.0000.797F] # CJK COMPATIBILITY IDEOGRAPH-F93C; QQC +FA52 ; [.FB40.0020.0002.798D][.F98D.0000.0000.798D] # CJK COMPATIBILITY IDEOGRAPH-FA52; QQC +FA53 ; [.FB40.0020.0002.798E][.F98E.0000.0000.798E] # CJK COMPATIBILITY IDEOGRAPH-FA53; QQC +FA1B ; [.FB40.0020.0002.798F][.F98F.0000.0000.798F] # CJK COMPATIBILITY IDEOGRAPH-FA1B; QQC +2F956 ; [.FB40.0020.0002.798F][.F98F.0000.0000.798F] # CJK COMPATIBILITY IDEOGRAPH-2F956; QQC +F9B6 ; [.FB40.0020.0002.79AE][.F9AE.0000.0000.79AE] # CJK COMPATIBILITY IDEOGRAPH-F9B6; QQC +2F71 ; [.FB40.0020.0004.79B8][.F9B8.0000.0000.79B8] # KANGXI RADICAL TRACK; QQK +2F72 ; [.FB40.0020.0004.79BE][.F9BE.0000.0000.79BE] # KANGXI RADICAL GRAIN; QQK +F995 ; [.FB40.0020.0002.79CA][.F9CA.0000.0000.79CA] # CJK COMPATIBILITY IDEOGRAPH-F995; QQC +3299 ; [.FB40.0020.0006.79D8][.F9D8.0000.0000.79D8] # CIRCLED IDEOGRAPH SECRET; QQK +2F957 ; [.FB40.0020.0002.79EB][.F9EB.0000.0000.79EB] # CJK COMPATIBILITY IDEOGRAPH-2F957; QQC +F956 ; [.FB40.0020.0002.7A1C][.FA1C.0000.0000.7A1C] # CJK COMPATIBILITY IDEOGRAPH-F956; QQC +FA54 ; [.FB40.0020.0002.7A40][.FA40.0000.0000.7A40] # CJK COMPATIBILITY IDEOGRAPH-FA54; QQC +2F959 ; [.FB40.0020.0002.7A40][.FA40.0000.0000.7A40] # CJK COMPATIBILITY IDEOGRAPH-2F959; QQC +2F95A ; [.FB40.0020.0002.7A4A][.FA4A.0000.0000.7A4A] # CJK COMPATIBILITY IDEOGRAPH-2F95A; QQC +2F95B ; [.FB40.0020.0002.7A4F][.FA4F.0000.0000.7A4F] # CJK COMPATIBILITY IDEOGRAPH-2F95B; QQC +2F73 ; [.FB40.0020.0004.7A74][.FA74.0000.0000.7A74] # KANGXI RADICAL CAVE; QQK +FA55 ; [.FB40.0020.0002.7A81][.FA81.0000.0000.7A81] # CJK COMPATIBILITY IDEOGRAPH-FA55; QQC +FAAC ; [.FB40.0020.0002.7AB1][.FAB1.0000.0000.7AB1] # CJK COMPATIBILITY IDEOGRAPH-FAAC; QQC +F9F7 ; [.FB40.0020.0002.7ACB][.FACB.0000.0000.7ACB] # CJK COMPATIBILITY IDEOGRAPH-F9F7; QQC +2F74 ; [.FB40.0020.0004.7ACB][.FACB.0000.0000.7ACB] # KANGXI RADICAL STAND; QQK +2F95F ; [.FB40.0020.0002.7AEE][.FAEE.0000.0000.7AEE] # CJK COMPATIBILITY IDEOGRAPH-2F95F; QQC +2F75 ; [.FB40.0020.0004.7AF9][.FAF9.0000.0000.7AF9] # KANGXI RADICAL BAMBOO; QQK +2EAE ; [.FB40.0020.0004.7AF9][.FAF9.0000.0000.7AF9][.0000.0199.001F.2EAE] # CJK RADICAL BAMBOO; QQKN +F9F8 ; [.FB40.0020.0002.7B20][.FB20.0000.0000.7B20] # CJK COMPATIBILITY IDEOGRAPH-F9F8; QQC +FA56 ; [.FB40.0020.0002.7BC0][.FBC0.0000.0000.7BC0] # CJK COMPATIBILITY IDEOGRAPH-FA56; QQC +FAAD ; [.FB40.0020.0002.7BC0][.FBC0.0000.0000.7BC0] # CJK COMPATIBILITY IDEOGRAPH-FAAD; QQC +2F962 ; [.FB40.0020.0002.7BC6][.FBC6.0000.0000.7BC6] # CJK COMPATIBILITY IDEOGRAPH-2F962; QQC +2F963 ; [.FB40.0020.0002.7BC9][.FBC9.0000.0000.7BC9] # CJK COMPATIBILITY IDEOGRAPH-2F963; QQC +F9A6 ; [.FB40.0020.0002.7C3E][.FC3E.0000.0000.7C3E] # CJK COMPATIBILITY IDEOGRAPH-F9A6; QQC +F944 ; [.FB40.0020.0002.7C60][.FC60.0000.0000.7C60] # CJK COMPATIBILITY IDEOGRAPH-F944; QQC +2F76 ; [.FB40.0020.0004.7C73][.FC73.0000.0000.7C73] # KANGXI RADICAL RICE; QQK +FAAE ; [.FB40.0020.0002.7C7B][.FC7B.0000.0000.7C7B] # CJK COMPATIBILITY IDEOGRAPH-FAAE; QQC +F9F9 ; [.FB40.0020.0002.7C92][.FC92.0000.0000.7C92] # CJK COMPATIBILITY IDEOGRAPH-F9F9; QQC +FA1D ; [.FB40.0020.0002.7CBE][.FCBE.0000.0000.7CBE] # CJK COMPATIBILITY IDEOGRAPH-FA1D; QQC +2F966 ; [.FB40.0020.0002.7CD2][.FCD2.0000.0000.7CD2] # CJK COMPATIBILITY IDEOGRAPH-2F966; QQC +FA03 ; [.FB40.0020.0002.7CD6][.FCD6.0000.0000.7CD6] # CJK COMPATIBILITY IDEOGRAPH-FA03; QQC +2F969 ; [.FB40.0020.0002.7CE3][.FCE3.0000.0000.7CE3] # CJK COMPATIBILITY IDEOGRAPH-2F969; QQC +F97B ; [.FB40.0020.0002.7CE7][.FCE7.0000.0000.7CE7] # CJK COMPATIBILITY IDEOGRAPH-F97B; QQC +2F968 ; [.FB40.0020.0002.7CE8][.FCE8.0000.0000.7CE8] # CJK COMPATIBILITY IDEOGRAPH-2F968; QQC +2F77 ; [.FB40.0020.0004.7CF8][.FCF8.0000.0000.7CF8] # KANGXI RADICAL SILK; QQK +2EAF ; [.FB40.0020.0004.7CF9][.FCF9.0000.0000.7CF9] # CJK RADICAL SILK; QQK +2F96A ; [.FB40.0020.0002.7D00][.FD00.0000.0000.7D00] # CJK COMPATIBILITY IDEOGRAPH-2F96A; QQC +F9CF ; [.FB40.0020.0002.7D10][.FD10.0000.0000.7D10] # CJK COMPATIBILITY IDEOGRAPH-F9CF; QQC +F96A ; [.FB40.0020.0002.7D22][.FD22.0000.0000.7D22] # CJK COMPATIBILITY IDEOGRAPH-F96A; QQC +F94F ; [.FB40.0020.0002.7D2F][.FD2F.0000.0000.7D2F] # CJK COMPATIBILITY IDEOGRAPH-F94F; QQC +FAAF ; [.FB40.0020.0002.7D5B][.FD5B.0000.0000.7D5B] # CJK COMPATIBILITY IDEOGRAPH-FAAF; QQC +2F96C ; [.FB40.0020.0002.7D63][.FD63.0000.0000.7D63] # CJK COMPATIBILITY IDEOGRAPH-2F96C; QQC +F93D ; [.FB40.0020.0002.7DA0][.FDA0.0000.0000.7DA0] # CJK COMPATIBILITY IDEOGRAPH-F93D; QQC +F957 ; [.FB40.0020.0002.7DBE][.FDBE.0000.0000.7DBE] # CJK COMPATIBILITY IDEOGRAPH-F957; QQC +2F96E ; [.FB40.0020.0002.7DC7][.FDC7.0000.0000.7DC7] # CJK COMPATIBILITY IDEOGRAPH-2F96E; QQC +F996 ; [.FB40.0020.0002.7DF4][.FDF4.0000.0000.7DF4] # CJK COMPATIBILITY IDEOGRAPH-F996; QQC +FA57 ; [.FB40.0020.0002.7DF4][.FDF4.0000.0000.7DF4] # CJK COMPATIBILITY IDEOGRAPH-FA57; QQC +FAB0 ; [.FB40.0020.0002.7DF4][.FDF4.0000.0000.7DF4] # CJK COMPATIBILITY IDEOGRAPH-FAB0; QQC +2F96F ; [.FB40.0020.0002.7E02][.FE02.0000.0000.7E02] # CJK COMPATIBILITY IDEOGRAPH-2F96F; QQC +FA58 ; [.FB40.0020.0002.7E09][.FE09.0000.0000.7E09] # CJK COMPATIBILITY IDEOGRAPH-FA58; QQC +F950 ; [.FB40.0020.0002.7E37][.FE37.0000.0000.7E37] # CJK COMPATIBILITY IDEOGRAPH-F950; QQC +FA59 ; [.FB40.0020.0002.7E41][.FE41.0000.0000.7E41] # CJK COMPATIBILITY IDEOGRAPH-FA59; QQC +2F970 ; [.FB40.0020.0002.7E45][.FE45.0000.0000.7E45] # CJK COMPATIBILITY IDEOGRAPH-2F970; QQC +2EB0 ; [.FB40.0020.0004.7E9F][.FE9F.0000.0000.7E9F] # CJK RADICAL C-SIMPLIFIED SILK; QQK +2F78 ; [.FB40.0020.0004.7F36][.FF36.0000.0000.7F36] # KANGXI RADICAL JAR; QQK +FAB1 ; [.FB40.0020.0002.7F3E][.FF3E.0000.0000.7F3E] # CJK COMPATIBILITY IDEOGRAPH-FAB1; QQC +2F79 ; [.FB40.0020.0004.7F51][.FF51.0000.0000.7F51] # KANGXI RADICAL NET; QQK +2EB2 ; [.FB40.0020.0004.7F52][.FF52.0000.0000.7F52] # CJK RADICAL NET TWO; QQK +2EB5 ; [.FB40.0020.0004.7F52][.FF52.0000.0000.7F52][.0000.0199.001F.2EB5] # CJK RADICAL MESH; QQKN +2EB1 ; [.FB40.0020.0004.7F53][.FF53.0000.0000.7F53] # CJK RADICAL NET ONE; QQK +2EB3 ; [.FB40.0020.0004.7F53][.FF53.0000.0000.7F53][.0000.0199.001F.2EB3] # CJK RADICAL NET THREE; QQKN +2EB4 ; [.FB40.0020.0004.7F53][.FF53.0000.0000.7F53][.0000.019A.001F.2EB4] # CJK RADICAL NET FOUR; QQKN +FA5A ; [.FB40.0020.0002.7F72][.FF72.0000.0000.7F72] # CJK COMPATIBILITY IDEOGRAPH-FA5A; QQC +F9E6 ; [.FB40.0020.0002.7F79][.FF79.0000.0000.7F79] # CJK COMPATIBILITY IDEOGRAPH-F9E6; QQC +2F976 ; [.FB40.0020.0002.7F7A][.FF7A.0000.0000.7F7A] # CJK COMPATIBILITY IDEOGRAPH-2F976; QQC +F90F ; [.FB40.0020.0002.7F85][.FF85.0000.0000.7F85] # CJK COMPATIBILITY IDEOGRAPH-F90F; QQC +2F7A ; [.FB40.0020.0004.7F8A][.FF8A.0000.0000.7F8A] # KANGXI RADICAL SHEEP; QQK +2EB6 ; [.FB40.0020.0004.7F8A][.FF8A.0000.0000.7F8A][.0000.0199.001F.2EB6] # CJK RADICAL SHEEP; QQKN +2EB7 ; [.FB40.0020.0004.7F8A][.FF8A.0000.0000.7F8A][.0000.019A.001F.2EB7] # CJK RADICAL RAM; QQKN +2EB8 ; [.FB40.0020.0004.7F8B][.FF8B.0000.0000.7F8B] # CJK RADICAL EWE; QQK +2F978 ; [.FB40.0020.0002.7F95][.FF95.0000.0000.7F95] # CJK COMPATIBILITY IDEOGRAPH-2F978; QQC +F9AF ; [.FB40.0020.0002.7F9A][.FF9A.0000.0000.7F9A] # CJK COMPATIBILITY IDEOGRAPH-F9AF; QQC +FA1E ; [.FB40.0020.0002.7FBD][.FFBD.0000.0000.7FBD] # CJK COMPATIBILITY IDEOGRAPH-FA1E; QQC +2F7B ; [.FB40.0020.0004.7FBD][.FFBD.0000.0000.7FBD] # KANGXI RADICAL FEATHER; QQK +2F979 ; [.FB40.0020.0002.7FFA][.FFFA.0000.0000.7FFA] # CJK COMPATIBILITY IDEOGRAPH-2F979; QQC +F934 ; [.FB41.0020.0002.8001][.8001.0000.0000.8001] # CJK COMPATIBILITY IDEOGRAPH-F934; QQC +2F7C ; [.FB41.0020.0004.8001][.8001.0000.0000.8001] # KANGXI RADICAL OLD; QQK +2EB9 ; [.FB41.0020.0004.8002][.8002.0000.0000.8002] # CJK RADICAL OLD; QQK +FA5B ; [.FB41.0020.0002.8005][.8005.0000.0000.8005] # CJK COMPATIBILITY IDEOGRAPH-FA5B; QQC +FAB2 ; [.FB41.0020.0002.8005][.8005.0000.0000.8005] # CJK COMPATIBILITY IDEOGRAPH-FAB2; QQC +2F97A ; [.FB41.0020.0002.8005][.8005.0000.0000.8005] # CJK COMPATIBILITY IDEOGRAPH-2F97A; QQC +2F7D ; [.FB41.0020.0004.800C][.800C.0000.0000.800C] # KANGXI RADICAL AND; QQK +2F7E ; [.FB41.0020.0004.8012][.8012.0000.0000.8012] # KANGXI RADICAL PLOW; QQK +2F7F ; [.FB41.0020.0004.8033][.8033.0000.0000.8033] # KANGXI RADICAL EAR; QQK +F9B0 ; [.FB41.0020.0002.8046][.8046.0000.0000.8046] # CJK COMPATIBILITY IDEOGRAPH-F9B0; QQC +2F97D ; [.FB41.0020.0002.8060][.8060.0000.0000.8060] # CJK COMPATIBILITY IDEOGRAPH-2F97D; QQC +F997 ; [.FB41.0020.0002.806F][.806F.0000.0000.806F] # CJK COMPATIBILITY IDEOGRAPH-F997; QQC +2F97F ; [.FB41.0020.0002.8070][.8070.0000.0000.8070] # CJK COMPATIBILITY IDEOGRAPH-2F97F; QQC +F945 ; [.FB41.0020.0002.807E][.807E.0000.0000.807E] # CJK COMPATIBILITY IDEOGRAPH-F945; QQC +2F80 ; [.FB41.0020.0004.807F][.807F.0000.0000.807F] # KANGXI RADICAL BRUSH; QQK +2EBB ; [.FB41.0020.0004.807F][.807F.0000.0000.807F][.0000.0199.001F.2EBB] # CJK RADICAL BRUSH TWO; QQKN +2EBA ; [.FB41.0020.0004.8080][.8080.0000.0000.8080] # CJK RADICAL BRUSH ONE; QQK +2F81 ; [.FB41.0020.0004.8089][.8089.0000.0000.8089] # KANGXI RADICAL MEAT; QQK +2EBC ; [.FB41.0020.0004.8089][.8089.0000.0000.8089][.0000.0199.001F.2EBC] # CJK RADICAL MEAT; QQKN +F953 ; [.FB41.0020.0002.808B][.808B.0000.0000.808B] # CJK COMPATIBILITY IDEOGRAPH-F953; QQC +2F8D6 ; [.FB41.0020.0002.80AD][.80AD.0000.0000.80AD] # CJK COMPATIBILITY IDEOGRAPH-2F8D6; QQC +2F982 ; [.FB41.0020.0002.80B2][.80B2.0000.0000.80B2] # CJK COMPATIBILITY IDEOGRAPH-2F982; QQC +2F983 ; [.FB41.0020.0002.8103][.8103.0000.0000.8103] # CJK COMPATIBILITY IDEOGRAPH-2F983; QQC +2F985 ; [.FB41.0020.0002.813E][.813E.0000.0000.813E] # CJK COMPATIBILITY IDEOGRAPH-2F985; QQC +F926 ; [.FB41.0020.0002.81D8][.81D8.0000.0000.81D8] # CJK COMPATIBILITY IDEOGRAPH-F926; QQC +2F82 ; [.FB41.0020.0004.81E3][.81E3.0000.0000.81E3] # KANGXI RADICAL MINISTER; QQK +F9F6 ; [.FB41.0020.0002.81E8][.81E8.0000.0000.81E8] # CJK COMPATIBILITY IDEOGRAPH-F9F6; QQC +2F83 ; [.FB41.0020.0004.81EA][.81EA.0000.0000.81EA] # KANGXI RADICAL SELF; QQK +3242 ; [*02B1.0020.0004.3242][.FB41.0020.0004.81EA][.81EA.0000.0000.81EA][*02B2.0020.001F.3242] # PARENTHESIZED IDEOGRAPH SELF; QQKN +FA5C ; [.FB41.0020.0002.81ED][.81ED.0000.0000.81ED] # CJK COMPATIBILITY IDEOGRAPH-FA5C; QQC +2F84 ; [.FB41.0020.0004.81F3][.81F3.0000.0000.81F3] # KANGXI RADICAL ARRIVE; QQK +3243 ; [*02B1.0020.0004.3243][.FB41.0020.0004.81F3][.81F3.0000.0000.81F3][*02B2.0020.001F.3243] # PARENTHESIZED IDEOGRAPH REACH; QQKN +2F85 ; [.FB41.0020.0004.81FC][.81FC.0000.0000.81FC] # KANGXI RADICAL MORTAR; QQK +2EBD ; [.FB41.0020.0004.81FC][.81FC.0000.0000.81FC][.0000.0199.001F.2EBD] # CJK RADICAL MORTAR; QQKN +2F893 ; [.FB41.0020.0002.8201][.8201.0000.0000.8201] # CJK COMPATIBILITY IDEOGRAPH-2F893; QQC +2F98B ; [.FB41.0020.0002.8201][.8201.0000.0000.8201] # CJK COMPATIBILITY IDEOGRAPH-2F98B; QQC +2F98C ; [.FB41.0020.0002.8204][.8204.0000.0000.8204] # CJK COMPATIBILITY IDEOGRAPH-2F98C; QQC +2F86 ; [.FB41.0020.0004.820C][.820C.0000.0000.820C] # KANGXI RADICAL TONGUE; QQK +2F87 ; [.FB41.0020.0004.821B][.821B.0000.0000.821B] # KANGXI RADICAL OPPOSE; QQK +2F88 ; [.FB41.0020.0004.821F][.821F.0000.0000.821F] # KANGXI RADICAL BOAT; QQK +2F89 ; [.FB41.0020.0004.826E][.826E.0000.0000.826E] # KANGXI RADICAL STOPPING; QQK +F97C ; [.FB41.0020.0002.826F][.826F.0000.0000.826F] # CJK COMPATIBILITY IDEOGRAPH-F97C; QQC +2F8A ; [.FB41.0020.0004.8272][.8272.0000.0000.8272] # KANGXI RADICAL COLOR; QQK +2F8B ; [.FB41.0020.0004.8278][.8278.0000.0000.8278] # KANGXI RADICAL GRASS; QQK +FA5D ; [.FB41.0020.0002.8279][.8279.0000.0000.8279] # CJK COMPATIBILITY IDEOGRAPH-FA5D; QQC +FA5E ; [.FB41.0020.0002.8279][.8279.0000.0000.8279] # CJK COMPATIBILITY IDEOGRAPH-FA5E; QQC +2EBE ; [.FB41.0020.0004.8279][.8279.0000.0000.8279] # CJK RADICAL GRASS ONE; QQK +2EBF ; [.FB41.0020.0004.8279][.8279.0000.0000.8279][.0000.0199.001F.2EBF] # CJK RADICAL GRASS TWO; QQKN +2EC0 ; [.FB41.0020.0004.8279][.8279.0000.0000.8279][.0000.019A.001F.2EC0] # CJK RADICAL GRASS THREE; QQKN +2F990 ; [.FB41.0020.0002.828B][.828B.0000.0000.828B] # CJK COMPATIBILITY IDEOGRAPH-2F990; QQC +2F98F ; [.FB41.0020.0002.8291][.8291.0000.0000.8291] # CJK COMPATIBILITY IDEOGRAPH-2F98F; QQC +2F991 ; [.FB41.0020.0002.829D][.829D.0000.0000.829D] # CJK COMPATIBILITY IDEOGRAPH-2F991; QQC +2F993 ; [.FB41.0020.0002.82B1][.82B1.0000.0000.82B1] # CJK COMPATIBILITY IDEOGRAPH-2F993; QQC +2F994 ; [.FB41.0020.0002.82B3][.82B3.0000.0000.82B3] # CJK COMPATIBILITY IDEOGRAPH-2F994; QQC +2F995 ; [.FB41.0020.0002.82BD][.82BD.0000.0000.82BD] # CJK COMPATIBILITY IDEOGRAPH-2F995; QQC +F974 ; [.FB41.0020.0002.82E5][.82E5.0000.0000.82E5] # CJK COMPATIBILITY IDEOGRAPH-F974; QQC +2F998 ; [.FB41.0020.0002.82E5][.82E5.0000.0000.82E5] # CJK COMPATIBILITY IDEOGRAPH-2F998; QQC +2F996 ; [.FB41.0020.0002.82E6][.82E6.0000.0000.82E6] # CJK COMPATIBILITY IDEOGRAPH-2F996; QQC +2F999 ; [.FB41.0020.0002.831D][.831D.0000.0000.831D] # CJK COMPATIBILITY IDEOGRAPH-2F999; QQC +2F99C ; [.FB41.0020.0002.8323][.8323.0000.0000.8323] # CJK COMPATIBILITY IDEOGRAPH-2F99C; QQC +F9FE ; [.FB41.0020.0002.8336][.8336.0000.0000.8336] # CJK COMPATIBILITY IDEOGRAPH-F9FE; QQC +FAB3 ; [.FB41.0020.0002.8352][.8352.0000.0000.8352] # CJK COMPATIBILITY IDEOGRAPH-FAB3; QQC +2F9A0 ; [.FB41.0020.0002.8353][.8353.0000.0000.8353] # CJK COMPATIBILITY IDEOGRAPH-2F9A0; QQC +2F99A ; [.FB41.0020.0002.8363][.8363.0000.0000.8363] # CJK COMPATIBILITY IDEOGRAPH-2F99A; QQC +2F99B ; [.FB41.0020.0002.83AD][.83AD.0000.0000.83AD] # CJK COMPATIBILITY IDEOGRAPH-2F99B; QQC +2F99D ; [.FB41.0020.0002.83BD][.83BD.0000.0000.83BD] # CJK COMPATIBILITY IDEOGRAPH-2F99D; QQC +F93E ; [.FB41.0020.0002.83C9][.83C9.0000.0000.83C9] # CJK COMPATIBILITY IDEOGRAPH-F93E; QQC +2F9A1 ; [.FB41.0020.0002.83CA][.83CA.0000.0000.83CA] # CJK COMPATIBILITY IDEOGRAPH-2F9A1; QQC +2F9A2 ; [.FB41.0020.0002.83CC][.83CC.0000.0000.83CC] # CJK COMPATIBILITY IDEOGRAPH-2F9A2; QQC +2F9A3 ; [.FB41.0020.0002.83DC][.83DC.0000.0000.83DC] # CJK COMPATIBILITY IDEOGRAPH-2F9A3; QQC +2F99E ; [.FB41.0020.0002.83E7][.83E7.0000.0000.83E7] # CJK COMPATIBILITY IDEOGRAPH-2F99E; QQC +FAB4 ; [.FB41.0020.0002.83EF][.83EF.0000.0000.83EF] # CJK COMPATIBILITY IDEOGRAPH-FAB4; QQC +F958 ; [.FB41.0020.0002.83F1][.83F1.0000.0000.83F1] # CJK COMPATIBILITY IDEOGRAPH-F958; QQC +F918 ; [.FB41.0020.0002.843D][.843D.0000.0000.843D] # CJK COMPATIBILITY IDEOGRAPH-F918; QQC +F96E ; [.FB41.0020.0002.8449][.8449.0000.0000.8449] # CJK COMPATIBILITY IDEOGRAPH-F96E; QQC +FA5F ; [.FB41.0020.0002.8457][.8457.0000.0000.8457] # CJK COMPATIBILITY IDEOGRAPH-FA5F; QQC +2F99F ; [.FB41.0020.0002.8457][.8457.0000.0000.8457] # CJK COMPATIBILITY IDEOGRAPH-2F99F; QQC +F999 ; [.FB41.0020.0002.84EE][.84EE.0000.0000.84EE] # CJK COMPATIBILITY IDEOGRAPH-F999; QQC +2F9A8 ; [.FB41.0020.0002.84F1][.84F1.0000.0000.84F1] # CJK COMPATIBILITY IDEOGRAPH-2F9A8; QQC +2F9A9 ; [.FB41.0020.0002.84F3][.84F3.0000.0000.84F3] # CJK COMPATIBILITY IDEOGRAPH-2F9A9; QQC +F9C2 ; [.FB41.0020.0002.84FC][.84FC.0000.0000.84FC] # CJK COMPATIBILITY IDEOGRAPH-F9C2; QQC +2F9AA ; [.FB41.0020.0002.8516][.8516.0000.0000.8516] # CJK COMPATIBILITY IDEOGRAPH-2F9AA; QQC +2F9AC ; [.FB41.0020.0002.8564][.8564.0000.0000.8564] # CJK COMPATIBILITY IDEOGRAPH-2F9AC; QQC +F923 ; [.FB41.0020.0002.85CD][.85CD.0000.0000.85CD] # CJK COMPATIBILITY IDEOGRAPH-F923; QQC +F9F0 ; [.FB41.0020.0002.85FA][.85FA.0000.0000.85FA] # CJK COMPATIBILITY IDEOGRAPH-F9F0; QQC +F935 ; [.FB41.0020.0002.8606][.8606.0000.0000.8606] # CJK COMPATIBILITY IDEOGRAPH-F935; QQC +FA20 ; [.FB41.0020.0002.8612][.8612.0000.0000.8612] # CJK COMPATIBILITY IDEOGRAPH-FA20; QQC +F91F ; [.FB41.0020.0002.862D][.862D.0000.0000.862D] # CJK COMPATIBILITY IDEOGRAPH-F91F; QQC +F910 ; [.FB41.0020.0002.863F][.863F.0000.0000.863F] # CJK COMPATIBILITY IDEOGRAPH-F910; QQC +2F8C ; [.FB41.0020.0004.864D][.864D.0000.0000.864D] # KANGXI RADICAL TIGER; QQK +2EC1 ; [.FB41.0020.0004.864E][.864E.0000.0000.864E] # CJK RADICAL TIGER; QQK +2F9B3 ; [.FB41.0020.0002.8650][.8650.0000.0000.8650] # CJK COMPATIBILITY IDEOGRAPH-2F9B3; QQC +F936 ; [.FB41.0020.0002.865C][.865C.0000.0000.865C] # CJK COMPATIBILITY IDEOGRAPH-F936; QQC +2F9B4 ; [.FB41.0020.0002.865C][.865C.0000.0000.865C] # CJK COMPATIBILITY IDEOGRAPH-2F9B4; QQC +2F9B5 ; [.FB41.0020.0002.8667][.8667.0000.0000.8667] # CJK COMPATIBILITY IDEOGRAPH-2F9B5; QQC +2F9B6 ; [.FB41.0020.0002.8669][.8669.0000.0000.8669] # CJK COMPATIBILITY IDEOGRAPH-2F9B6; QQC +2F8D ; [.FB41.0020.0004.866B][.866B.0000.0000.866B] # KANGXI RADICAL INSECT; QQK +2F9B8 ; [.FB41.0020.0002.8688][.8688.0000.0000.8688] # CJK COMPATIBILITY IDEOGRAPH-2F9B8; QQC +2F9B7 ; [.FB41.0020.0002.86A9][.86A9.0000.0000.86A9] # CJK COMPATIBILITY IDEOGRAPH-2F9B7; QQC +2F9BA ; [.FB41.0020.0002.86E2][.86E2.0000.0000.86E2] # CJK COMPATIBILITY IDEOGRAPH-2F9BA; QQC +2F9B9 ; [.FB41.0020.0002.870E][.870E.0000.0000.870E] # CJK COMPATIBILITY IDEOGRAPH-2F9B9; QQC +2F9BC ; [.FB41.0020.0002.8728][.8728.0000.0000.8728] # CJK COMPATIBILITY IDEOGRAPH-2F9BC; QQC +2F9BD ; [.FB41.0020.0002.876B][.876B.0000.0000.876B] # CJK COMPATIBILITY IDEOGRAPH-2F9BD; QQC +FAB5 ; [.FB41.0020.0002.8779][.8779.0000.0000.8779] # CJK COMPATIBILITY IDEOGRAPH-FAB5; QQC +2F9BB ; [.FB41.0020.0002.8779][.8779.0000.0000.8779] # CJK COMPATIBILITY IDEOGRAPH-2F9BB; QQC +2F9BE ; [.FB41.0020.0002.8786][.8786.0000.0000.8786] # CJK COMPATIBILITY IDEOGRAPH-2F9BE; QQC +F911 ; [.FB41.0020.0002.87BA][.87BA.0000.0000.87BA] # CJK COMPATIBILITY IDEOGRAPH-F911; QQC +2F9C0 ; [.FB41.0020.0002.87E1][.87E1.0000.0000.87E1] # CJK COMPATIBILITY IDEOGRAPH-2F9C0; QQC +2F9C1 ; [.FB41.0020.0002.8801][.8801.0000.0000.8801] # CJK COMPATIBILITY IDEOGRAPH-2F9C1; QQC +F927 ; [.FB41.0020.0002.881F][.881F.0000.0000.881F] # CJK COMPATIBILITY IDEOGRAPH-F927; QQC +2F8E ; [.FB41.0020.0004.8840][.8840.0000.0000.8840] # KANGXI RADICAL BLOOD; QQK +FA08 ; [.FB41.0020.0002.884C][.884C.0000.0000.884C] # CJK COMPATIBILITY IDEOGRAPH-FA08; QQC +2F8F ; [.FB41.0020.0004.884C][.884C.0000.0000.884C] # KANGXI RADICAL WALK ENCLOSURE; QQK +2F9C3 ; [.FB41.0020.0002.8860][.8860.0000.0000.8860] # CJK COMPATIBILITY IDEOGRAPH-2F9C3; QQC +2F9C4 ; [.FB41.0020.0002.8863][.8863.0000.0000.8863] # CJK COMPATIBILITY IDEOGRAPH-2F9C4; QQC +2F90 ; [.FB41.0020.0004.8863][.8863.0000.0000.8863] # KANGXI RADICAL CLOTHES; QQK +2EC2 ; [.FB41.0020.0004.8864][.8864.0000.0000.8864] # CJK RADICAL CLOTHES; QQK +F9A0 ; [.FB41.0020.0002.88C2][.88C2.0000.0000.88C2] # CJK COMPATIBILITY IDEOGRAPH-F9A0; QQC +F9E7 ; [.FB41.0020.0002.88CF][.88CF.0000.0000.88CF] # CJK COMPATIBILITY IDEOGRAPH-F9E7; QQC +2F9C6 ; [.FB41.0020.0002.88D7][.88D7.0000.0000.88D7] # CJK COMPATIBILITY IDEOGRAPH-2F9C6; QQC +2F9C7 ; [.FB41.0020.0002.88DE][.88DE.0000.0000.88DE] # CJK COMPATIBILITY IDEOGRAPH-2F9C7; QQC +F9E8 ; [.FB41.0020.0002.88E1][.88E1.0000.0000.88E1] # CJK COMPATIBILITY IDEOGRAPH-F9E8; QQC +F912 ; [.FB41.0020.0002.88F8][.88F8.0000.0000.88F8] # CJK COMPATIBILITY IDEOGRAPH-F912; QQC +2F9C9 ; [.FB41.0020.0002.88FA][.88FA.0000.0000.88FA] # CJK COMPATIBILITY IDEOGRAPH-2F9C9; QQC +FA60 ; [.FB41.0020.0002.8910][.8910.0000.0000.8910] # CJK COMPATIBILITY IDEOGRAPH-FA60; QQC +FAB6 ; [.FB41.0020.0002.8941][.8941.0000.0000.8941] # CJK COMPATIBILITY IDEOGRAPH-FAB6; QQC +F924 ; [.FB41.0020.0002.8964][.8964.0000.0000.8964] # CJK COMPATIBILITY IDEOGRAPH-F924; QQC +2F91 ; [.FB41.0020.0004.897E][.897E.0000.0000.897E] # KANGXI RADICAL WEST; QQK +2EC4 ; [.FB41.0020.0004.897F][.897F.0000.0000.897F] # CJK RADICAL WEST TWO; QQK +2EC3 ; [.FB41.0020.0004.8980][.8980.0000.0000.8980] # CJK RADICAL WEST ONE; QQK +FAB7 ; [.FB41.0020.0002.8986][.8986.0000.0000.8986] # CJK COMPATIBILITY IDEOGRAPH-FAB7; QQC +FA0A ; [.FB41.0020.0002.898B][.898B.0000.0000.898B] # CJK COMPATIBILITY IDEOGRAPH-FA0A; QQC +2F92 ; [.FB41.0020.0004.898B][.898B.0000.0000.898B] # KANGXI RADICAL SEE; QQK +FA61 ; [.FB41.0020.0002.8996][.8996.0000.0000.8996] # CJK COMPATIBILITY IDEOGRAPH-FA61; QQC +FAB8 ; [.FB41.0020.0002.8996][.8996.0000.0000.8996] # CJK COMPATIBILITY IDEOGRAPH-FAB8; QQC +2EC5 ; [.FB41.0020.0004.89C1][.89C1.0000.0000.89C1] # CJK RADICAL C-SIMPLIFIED SEE; QQK +2EC6 ; [.FB41.0020.0004.89D2][.89D2.0000.0000.89D2] # CJK RADICAL SIMPLIFIED HORN; QQK +2F93 ; [.FB41.0020.0004.89D2][.89D2.0000.0000.89D2] # KANGXI RADICAL HORN; QQK +2EC7 ; [.FB41.0020.0004.89D2][.89D2.0000.0000.89D2][.0000.0199.001F.2EC7] # CJK RADICAL HORN; QQKN +2F94 ; [.FB41.0020.0004.8A00][.8A00.0000.0000.8A00] # KANGXI RADICAL SPEECH; QQK +2F9CF ; [.FB41.0020.0002.8AA0][.8AA0.0000.0000.8AA0] # CJK COMPATIBILITY IDEOGRAPH-2F9CF; QQC +F96F ; [.FB41.0020.0002.8AAA][.8AAA.0000.0000.8AAA] # CJK COMPATIBILITY IDEOGRAPH-F96F; QQC +F9A1 ; [.FB41.0020.0002.8AAA][.8AAA.0000.0000.8AAA] # CJK COMPATIBILITY IDEOGRAPH-F9A1; QQC +FAB9 ; [.FB41.0020.0002.8ABF][.8ABF.0000.0000.8ABF] # CJK COMPATIBILITY IDEOGRAPH-FAB9; QQC +FABB ; [.FB41.0020.0002.8ACB][.8ACB.0000.0000.8ACB] # CJK COMPATIBILITY IDEOGRAPH-FABB; QQC +F97D ; [.FB41.0020.0002.8AD2][.8AD2.0000.0000.8AD2] # CJK COMPATIBILITY IDEOGRAPH-F97D; QQC +F941 ; [.FB41.0020.0002.8AD6][.8AD6.0000.0000.8AD6] # CJK COMPATIBILITY IDEOGRAPH-F941; QQC +FABE ; [.FB41.0020.0002.8AED][.8AED.0000.0000.8AED] # CJK COMPATIBILITY IDEOGRAPH-FABE; QQC +2F9D0 ; [.FB41.0020.0002.8AED][.8AED.0000.0000.8AED] # CJK COMPATIBILITY IDEOGRAPH-2F9D0; QQC +FA22 ; [.FB41.0020.0002.8AF8][.8AF8.0000.0000.8AF8] # CJK COMPATIBILITY IDEOGRAPH-FA22; QQC +FABA ; [.FB41.0020.0002.8AF8][.8AF8.0000.0000.8AF8] # CJK COMPATIBILITY IDEOGRAPH-FABA; QQC +F95D ; [.FB41.0020.0002.8AFE][.8AFE.0000.0000.8AFE] # CJK COMPATIBILITY IDEOGRAPH-F95D; QQC +FABD ; [.FB41.0020.0002.8AFE][.8AFE.0000.0000.8AFE] # CJK COMPATIBILITY IDEOGRAPH-FABD; QQC +FA62 ; [.FB41.0020.0002.8B01][.8B01.0000.0000.8B01] # CJK COMPATIBILITY IDEOGRAPH-FA62; QQC +FABC ; [.FB41.0020.0002.8B01][.8B01.0000.0000.8B01] # CJK COMPATIBILITY IDEOGRAPH-FABC; QQC +FA63 ; [.FB41.0020.0002.8B39][.8B39.0000.0000.8B39] # CJK COMPATIBILITY IDEOGRAPH-FA63; QQC +FABF ; [.FB41.0020.0002.8B39][.8B39.0000.0000.8B39] # CJK COMPATIBILITY IDEOGRAPH-FABF; QQC +F9FC ; [.FB41.0020.0002.8B58][.8B58.0000.0000.8B58] # CJK COMPATIBILITY IDEOGRAPH-F9FC; QQC +F95A ; [.FB41.0020.0002.8B80][.8B80.0000.0000.8B80] # CJK COMPATIBILITY IDEOGRAPH-F95A; QQC +FAC0 ; [.FB41.0020.0002.8B8A][.8B8A.0000.0000.8B8A] # CJK COMPATIBILITY IDEOGRAPH-FAC0; QQC +2F9D1 ; [.FB41.0020.0002.8B8A][.8B8A.0000.0000.8B8A] # CJK COMPATIBILITY IDEOGRAPH-2F9D1; QQC +2EC8 ; [.FB41.0020.0004.8BA0][.8BA0.0000.0000.8BA0] # CJK RADICAL C-SIMPLIFIED SPEECH; QQK +2F95 ; [.FB41.0020.0004.8C37][.8C37.0000.0000.8C37] # KANGXI RADICAL VALLEY; QQK +2F96 ; [.FB41.0020.0004.8C46][.8C46.0000.0000.8C46] # KANGXI RADICAL BEAN; QQK +F900 ; [.FB41.0020.0002.8C48][.8C48.0000.0000.8C48] # CJK COMPATIBILITY IDEOGRAPH-F900; QQC +2F9D2 ; [.FB41.0020.0002.8C55][.8C55.0000.0000.8C55] # CJK COMPATIBILITY IDEOGRAPH-2F9D2; QQC +2F97 ; [.FB41.0020.0004.8C55][.8C55.0000.0000.8C55] # KANGXI RADICAL PIG; QQK +2F98 ; [.FB41.0020.0004.8C78][.8C78.0000.0000.8C78] # KANGXI RADICAL BADGER; QQK +2F99 ; [.FB41.0020.0004.8C9D][.8C9D.0000.0000.8C9D] # KANGXI RADICAL SHELL; QQK +3236 ; [*02B1.0020.0004.3236][.FB41.0020.0004.8CA1][.8CA1.0000.0000.8CA1][*02B2.0020.001F.3236] # PARENTHESIZED IDEOGRAPH FINANCIAL; QQKN +3296 ; [.FB41.0020.0006.8CA1][.8CA1.0000.0000.8CA1] # CIRCLED IDEOGRAPH FINANCIAL; QQK +2F9D4 ; [.FB41.0020.0002.8CAB][.8CAB.0000.0000.8CAB] # CJK COMPATIBILITY IDEOGRAPH-2F9D4; QQC +2F9D5 ; [.FB41.0020.0002.8CC1][.8CC1.0000.0000.8CC1] # CJK COMPATIBILITY IDEOGRAPH-2F9D5; QQC +F948 ; [.FB41.0020.0002.8CC2][.8CC2.0000.0000.8CC2] # CJK COMPATIBILITY IDEOGRAPH-F948; QQC +323E ; [*02B1.0020.0004.323E][.FB41.0020.0004.8CC7][.8CC7.0000.0000.8CC7][*02B2.0020.001F.323E] # PARENTHESIZED IDEOGRAPH RESOURCE; QQKN +32AE ; [.FB41.0020.0006.8CC7][.8CC7.0000.0000.8CC7] # CIRCLED IDEOGRAPH RESOURCE; QQK +F903 ; [.FB41.0020.0002.8CC8][.8CC8.0000.0000.8CC8] # CJK COMPATIBILITY IDEOGRAPH-F903; QQC +FA64 ; [.FB41.0020.0002.8CD3][.8CD3.0000.0000.8CD3] # CJK COMPATIBILITY IDEOGRAPH-FA64; QQC +FA65 ; [.FB41.0020.0002.8D08][.8D08.0000.0000.8D08] # CJK COMPATIBILITY IDEOGRAPH-FA65; QQC +FAC1 ; [.FB41.0020.0002.8D08][.8D08.0000.0000.8D08] # CJK COMPATIBILITY IDEOGRAPH-FAC1; QQC +2F9D6 ; [.FB41.0020.0002.8D1B][.8D1B.0000.0000.8D1B] # CJK COMPATIBILITY IDEOGRAPH-2F9D6; QQC +2EC9 ; [.FB41.0020.0004.8D1D][.8D1D.0000.0000.8D1D] # CJK RADICAL C-SIMPLIFIED SHELL; QQK +2F9A ; [.FB41.0020.0004.8D64][.8D64.0000.0000.8D64] # KANGXI RADICAL RED; QQK +2F9B ; [.FB41.0020.0004.8D70][.8D70.0000.0000.8D70] # KANGXI RADICAL RUN; QQK +2F9D7 ; [.FB41.0020.0002.8D77][.8D77.0000.0000.8D77] # CJK COMPATIBILITY IDEOGRAPH-2F9D7; QQC +2F9C ; [.FB41.0020.0004.8DB3][.8DB3.0000.0000.8DB3] # KANGXI RADICAL FOOT; QQK +2ECA ; [.FB41.0020.0004.8DB3][.8DB3.0000.0000.8DB3][.0000.0199.001F.2ECA] # CJK RADICAL FOOT; QQKN +2F9DB ; [.FB41.0020.0002.8DBC][.8DBC.0000.0000.8DBC] # CJK COMPATIBILITY IDEOGRAPH-2F9DB; QQC +2F9DA ; [.FB41.0020.0002.8DCB][.8DCB.0000.0000.8DCB] # CJK COMPATIBILITY IDEOGRAPH-2F9DA; QQC +F937 ; [.FB41.0020.0002.8DEF][.8DEF.0000.0000.8DEF] # CJK COMPATIBILITY IDEOGRAPH-F937; QQC +2F9DC ; [.FB41.0020.0002.8DF0][.8DF0.0000.0000.8DF0] # CJK COMPATIBILITY IDEOGRAPH-2F9DC; QQC +2F9D ; [.FB41.0020.0004.8EAB][.8EAB.0000.0000.8EAB] # KANGXI RADICAL BODY; QQK +F902 ; [.FB41.0020.0002.8ECA][.8ECA.0000.0000.8ECA] # CJK COMPATIBILITY IDEOGRAPH-F902; QQC +2F9E ; [.FB41.0020.0004.8ECA][.8ECA.0000.0000.8ECA] # KANGXI RADICAL CART; QQK +2F9DE ; [.FB41.0020.0002.8ED4][.8ED4.0000.0000.8ED4] # CJK COMPATIBILITY IDEOGRAPH-2F9DE; QQC +F998 ; [.FB41.0020.0002.8F26][.8F26.0000.0000.8F26] # CJK COMPATIBILITY IDEOGRAPH-F998; QQC +F9D7 ; [.FB41.0020.0002.8F2A][.8F2A.0000.0000.8F2A] # CJK COMPATIBILITY IDEOGRAPH-F9D7; QQC +FAC2 ; [.FB41.0020.0002.8F38][.8F38.0000.0000.8F38] # CJK COMPATIBILITY IDEOGRAPH-FAC2; QQC +2F9DF ; [.FB41.0020.0002.8F38][.8F38.0000.0000.8F38] # CJK COMPATIBILITY IDEOGRAPH-2F9DF; QQC +FA07 ; [.FB41.0020.0002.8F3B][.8F3B.0000.0000.8F3B] # CJK COMPATIBILITY IDEOGRAPH-FA07; QQC +F98D ; [.FB41.0020.0002.8F62][.8F62.0000.0000.8F62] # CJK COMPATIBILITY IDEOGRAPH-F98D; QQC +2ECB ; [.FB41.0020.0004.8F66][.8F66.0000.0000.8F66] # CJK RADICAL C-SIMPLIFIED CART; QQK +2F9F ; [.FB41.0020.0004.8F9B][.8F9B.0000.0000.8F9B] # KANGXI RADICAL BITTER; QQK +2F98D ; [.FB41.0020.0002.8F9E][.8F9E.0000.0000.8F9E] # CJK COMPATIBILITY IDEOGRAPH-2F98D; QQC +F971 ; [.FB41.0020.0002.8FB0][.8FB0.0000.0000.8FB0] # CJK COMPATIBILITY IDEOGRAPH-F971; QQC +2FA0 ; [.FB41.0020.0004.8FB0][.8FB0.0000.0000.8FB0] # KANGXI RADICAL MORNING; QQK +2FA1 ; [.FB41.0020.0004.8FB5][.8FB5.0000.0000.8FB5] # KANGXI RADICAL WALK; QQK +FA66 ; [.FB41.0020.0002.8FB6][.8FB6.0000.0000.8FB6] # CJK COMPATIBILITY IDEOGRAPH-FA66; QQC +2ECC ; [.FB41.0020.0004.8FB6][.8FB6.0000.0000.8FB6] # CJK RADICAL SIMPLIFIED WALK; QQK +2ECD ; [.FB41.0020.0004.8FB6][.8FB6.0000.0000.8FB6][.0000.0199.001F.2ECD] # CJK RADICAL WALK ONE; QQKN +2ECE ; [.FB41.0020.0004.8FB6][.8FB6.0000.0000.8FB6][.0000.019A.001F.2ECE] # CJK RADICAL WALK TWO; QQKN +F99A ; [.FB41.0020.0002.9023][.9023.0000.0000.9023] # CJK COMPATIBILITY IDEOGRAPH-F99A; QQC +FA25 ; [.FB41.0020.0002.9038][.9038.0000.0000.9038] # CJK COMPATIBILITY IDEOGRAPH-FA25; QQC +FA67 ; [.FB41.0020.0002.9038][.9038.0000.0000.9038] # CJK COMPATIBILITY IDEOGRAPH-FA67; QQC +329C ; [.FB41.0020.0006.9069][.9069.0000.0000.9069] # CIRCLED IDEOGRAPH SUITABLE; QQK +FAC3 ; [.FB41.0020.0002.9072][.9072.0000.0000.9072] # CJK COMPATIBILITY IDEOGRAPH-FAC3; QQC +F9C3 ; [.FB41.0020.0002.907C][.907C.0000.0000.907C] # CJK COMPATIBILITY IDEOGRAPH-F9C3; QQC +F913 ; [.FB41.0020.0002.908F][.908F.0000.0000.908F] # CJK COMPATIBILITY IDEOGRAPH-F913; QQC +2FA2 ; [.FB41.0020.0004.9091][.9091.0000.0000.9091] # KANGXI RADICAL CITY; QQK +2ECF ; [.FB41.0020.0004.9091][.9091.0000.0000.9091][.0000.0199.001F.2ECF] # CJK RADICAL CITY; QQKN +2F9E2 ; [.FB41.0020.0002.9094][.9094.0000.0000.9094] # CJK COMPATIBILITY IDEOGRAPH-2F9E2; QQC +F92C ; [.FB41.0020.0002.90CE][.90CE.0000.0000.90CE] # CJK COMPATIBILITY IDEOGRAPH-F92C; QQC +2F9E3 ; [.FB41.0020.0002.90F1][.90F1.0000.0000.90F1] # CJK COMPATIBILITY IDEOGRAPH-2F9E3; QQC +FA26 ; [.FB41.0020.0002.90FD][.90FD.0000.0000.90FD] # CJK COMPATIBILITY IDEOGRAPH-FA26; QQC +2F9E4 ; [.FB41.0020.0002.9111][.9111.0000.0000.9111] # CJK COMPATIBILITY IDEOGRAPH-2F9E4; QQC +2F9E6 ; [.FB41.0020.0002.911B][.911B.0000.0000.911B] # CJK COMPATIBILITY IDEOGRAPH-2F9E6; QQC +2FA3 ; [.FB41.0020.0004.9149][.9149.0000.0000.9149] # KANGXI RADICAL WINE; QQK +F919 ; [.FB41.0020.0002.916A][.916A.0000.0000.916A] # CJK COMPATIBILITY IDEOGRAPH-F919; QQC +FAC4 ; [.FB41.0020.0002.9199][.9199.0000.0000.9199] # CJK COMPATIBILITY IDEOGRAPH-FAC4; QQC +F9B7 ; [.FB41.0020.0002.91B4][.91B4.0000.0000.91B4] # CJK COMPATIBILITY IDEOGRAPH-F9B7; QQC +2FA4 ; [.FB41.0020.0004.91C6][.91C6.0000.0000.91C6] # KANGXI RADICAL DISTINGUISH; QQK +F9E9 ; [.FB41.0020.0002.91CC][.91CC.0000.0000.91CC] # CJK COMPATIBILITY IDEOGRAPH-F9E9; QQC +2FA5 ; [.FB41.0020.0004.91CC][.91CC.0000.0000.91CC] # KANGXI RADICAL VILLAGE; QQK +F97E ; [.FB41.0020.0002.91CF][.91CF.0000.0000.91CF] # CJK COMPATIBILITY IDEOGRAPH-F97E; QQC +F90A ; [.FB41.0020.0002.91D1][.91D1.0000.0000.91D1] # CJK COMPATIBILITY IDEOGRAPH-F90A; QQC +2FA6 ; [.FB41.0020.0004.91D1][.91D1.0000.0000.91D1] # KANGXI RADICAL GOLD; QQK +322E ; [*02B1.0020.0004.322E][.FB41.0020.0004.91D1][.91D1.0000.0000.91D1][*02B2.0020.001F.322E] # PARENTHESIZED IDEOGRAPH METAL; QQKN +328E ; [.FB41.0020.0006.91D1][.91D1.0000.0000.91D1] # CIRCLED IDEOGRAPH METAL; QQK +F9B1 ; [.FB41.0020.0002.9234][.9234.0000.0000.9234] # CJK COMPATIBILITY IDEOGRAPH-F9B1; QQC +2F9E7 ; [.FB41.0020.0002.9238][.9238.0000.0000.9238] # CJK COMPATIBILITY IDEOGRAPH-2F9E7; QQC +FAC5 ; [.FB41.0020.0002.9276][.9276.0000.0000.9276] # CJK COMPATIBILITY IDEOGRAPH-FAC5; QQC +2F9EA ; [.FB41.0020.0002.927C][.927C.0000.0000.927C] # CJK COMPATIBILITY IDEOGRAPH-2F9EA; QQC +2F9E8 ; [.FB41.0020.0002.92D7][.92D7.0000.0000.92D7] # CJK COMPATIBILITY IDEOGRAPH-2F9E8; QQC +2F9E9 ; [.FB41.0020.0002.92D8][.92D8.0000.0000.92D8] # CJK COMPATIBILITY IDEOGRAPH-2F9E9; QQC +F93F ; [.FB41.0020.0002.9304][.9304.0000.0000.9304] # CJK COMPATIBILITY IDEOGRAPH-F93F; QQC +F99B ; [.FB41.0020.0002.934A][.934A.0000.0000.934A] # CJK COMPATIBILITY IDEOGRAPH-F99B; QQC +2F9EB ; [.FB41.0020.0002.93F9][.93F9.0000.0000.93F9] # CJK COMPATIBILITY IDEOGRAPH-2F9EB; QQC +2F9EC ; [.FB41.0020.0002.9415][.9415.0000.0000.9415] # CJK COMPATIBILITY IDEOGRAPH-2F9EC; QQC +2ED0 ; [.FB41.0020.0004.9485][.9485.0000.0000.9485] # CJK RADICAL C-SIMPLIFIED GOLD; QQK +2ED1 ; [.FB41.0020.0004.9577][.9577.0000.0000.9577] # CJK RADICAL LONG ONE; QQK +2FA7 ; [.FB41.0020.0004.9577][.9577.0000.0000.9577] # KANGXI RADICAL LONG; QQK +2ED2 ; [.FB41.0020.0004.9578][.9578.0000.0000.9578] # CJK RADICAL LONG TWO; QQK +2ED3 ; [.FB41.0020.0004.957F][.957F.0000.0000.957F] # CJK RADICAL C-SIMPLIFIED LONG; QQK +2FA8 ; [.FB41.0020.0004.9580][.9580.0000.0000.9580] # KANGXI RADICAL GATE; QQK +2F9EE ; [.FB41.0020.0002.958B][.958B.0000.0000.958B] # CJK COMPATIBILITY IDEOGRAPH-2F9EE; QQC +F986 ; [.FB41.0020.0002.95AD][.95AD.0000.0000.95AD] # CJK COMPATIBILITY IDEOGRAPH-F986; QQC +2F9F0 ; [.FB41.0020.0002.95B7][.95B7.0000.0000.95B7] # CJK COMPATIBILITY IDEOGRAPH-2F9F0; QQC +2ED4 ; [.FB41.0020.0004.95E8][.95E8.0000.0000.95E8] # CJK RADICAL C-SIMPLIFIED GATE; QQK +2FA9 ; [.FB41.0020.0004.961C][.961C.0000.0000.961C] # KANGXI RADICAL MOUND; QQK +2ED5 ; [.FB41.0020.0004.961C][.961C.0000.0000.961C][.0000.0199.001F.2ED5] # CJK RADICAL MOUND ONE; QQKN +2ED6 ; [.FB41.0020.0004.961D][.961D.0000.0000.961D] # CJK RADICAL MOUND TWO; QQK +F9C6 ; [.FB41.0020.0002.962E][.962E.0000.0000.962E] # CJK COMPATIBILITY IDEOGRAPH-F9C6; QQC +F951 ; [.FB41.0020.0002.964B][.964B.0000.0000.964B] # CJK COMPATIBILITY IDEOGRAPH-F951; QQC +FA09 ; [.FB41.0020.0002.964D][.964D.0000.0000.964D] # CJK COMPATIBILITY IDEOGRAPH-FA09; QQC +F959 ; [.FB41.0020.0002.9675][.9675.0000.0000.9675] # CJK COMPATIBILITY IDEOGRAPH-F959; QQC +F9D3 ; [.FB41.0020.0002.9678][.9678.0000.0000.9678] # CJK COMPATIBILITY IDEOGRAPH-F9D3; QQC +FAC6 ; [.FB41.0020.0002.967C][.967C.0000.0000.967C] # CJK COMPATIBILITY IDEOGRAPH-FAC6; QQC +F9DC ; [.FB41.0020.0002.9686][.9686.0000.0000.9686] # CJK COMPATIBILITY IDEOGRAPH-F9DC; QQC +F9F1 ; [.FB41.0020.0002.96A3][.96A3.0000.0000.96A3] # CJK COMPATIBILITY IDEOGRAPH-F9F1; QQC +2FAA ; [.FB41.0020.0004.96B6][.96B6.0000.0000.96B6] # KANGXI RADICAL SLAVE; QQK +F9B8 ; [.FB41.0020.0002.96B8][.96B8.0000.0000.96B8] # CJK COMPATIBILITY IDEOGRAPH-F9B8; QQC +2FAB ; [.FB41.0020.0004.96B9][.96B9.0000.0000.96B9] # KANGXI RADICAL SHORT TAILED BIRD; QQK +2F9F3 ; [.FB41.0020.0002.96C3][.96C3.0000.0000.96C3] # CJK COMPATIBILITY IDEOGRAPH-2F9F3; QQC +F9EA ; [.FB41.0020.0002.96E2][.96E2.0000.0000.96E2] # CJK COMPATIBILITY IDEOGRAPH-F9EA; QQC +FA68 ; [.FB41.0020.0002.96E3][.96E3.0000.0000.96E3] # CJK COMPATIBILITY IDEOGRAPH-FA68; QQC +FAC7 ; [.FB41.0020.0002.96E3][.96E3.0000.0000.96E3] # CJK COMPATIBILITY IDEOGRAPH-FAC7; QQC +2FAC ; [.FB41.0020.0004.96E8][.96E8.0000.0000.96E8] # KANGXI RADICAL RAIN; QQK +2ED7 ; [.FB41.0020.0004.96E8][.96E8.0000.0000.96E8][.0000.0199.001F.2ED7] # CJK RADICAL RAIN; QQKN +F9B2 ; [.FB41.0020.0002.96F6][.96F6.0000.0000.96F6] # CJK COMPATIBILITY IDEOGRAPH-F9B2; QQC +F949 ; [.FB41.0020.0002.96F7][.96F7.0000.0000.96F7] # CJK COMPATIBILITY IDEOGRAPH-F949; QQC +2F9F5 ; [.FB41.0020.0002.9723][.9723.0000.0000.9723] # CJK COMPATIBILITY IDEOGRAPH-2F9F5; QQC +F938 ; [.FB41.0020.0002.9732][.9732.0000.0000.9732] # CJK COMPATIBILITY IDEOGRAPH-F938; QQC +F9B3 ; [.FB41.0020.0002.9748][.9748.0000.0000.9748] # CJK COMPATIBILITY IDEOGRAPH-F9B3; QQC +2FAD ; [.FB41.0020.0004.9751][.9751.0000.0000.9751] # KANGXI RADICAL BLUE; QQK +2ED8 ; [.FB41.0020.0004.9752][.9752.0000.0000.9752] # CJK RADICAL BLUE; QQK +FA1C ; [.FB41.0020.0002.9756][.9756.0000.0000.9756] # CJK COMPATIBILITY IDEOGRAPH-FA1C; QQC +FAC8 ; [.FB41.0020.0002.9756][.9756.0000.0000.9756] # CJK COMPATIBILITY IDEOGRAPH-FAC8; QQC +2FAE ; [.FB41.0020.0004.975E][.975E.0000.0000.975E] # KANGXI RADICAL WRONG; QQK +2FAF ; [.FB41.0020.0004.9762][.9762.0000.0000.9762] # KANGXI RADICAL FACE; QQK +2FB0 ; [.FB41.0020.0004.9769][.9769.0000.0000.9769] # KANGXI RADICAL LEATHER; QQK +2FB1 ; [.FB41.0020.0004.97CB][.97CB.0000.0000.97CB] # KANGXI RADICAL TANNED LEATHER; QQK +FAC9 ; [.FB41.0020.0002.97DB][.97DB.0000.0000.97DB] # CJK COMPATIBILITY IDEOGRAPH-FAC9; QQC +2F9FA ; [.FB41.0020.0002.97E0][.97E0.0000.0000.97E0] # CJK COMPATIBILITY IDEOGRAPH-2F9FA; QQC +2ED9 ; [.FB41.0020.0004.97E6][.97E6.0000.0000.97E6] # CJK RADICAL C-SIMPLIFIED TANNED LEATHER; QQK +2FB2 ; [.FB41.0020.0004.97ED][.97ED.0000.0000.97ED] # KANGXI RADICAL LEEK; QQK +2FB3 ; [.FB41.0020.0004.97F3][.97F3.0000.0000.97F3] # KANGXI RADICAL SOUND; QQK +FA69 ; [.FB41.0020.0002.97FF][.97FF.0000.0000.97FF] # CJK COMPATIBILITY IDEOGRAPH-FA69; QQC +FACA ; [.FB41.0020.0002.97FF][.97FF.0000.0000.97FF] # CJK COMPATIBILITY IDEOGRAPH-FACA; QQC +2FB4 ; [.FB41.0020.0004.9801][.9801.0000.0000.9801] # KANGXI RADICAL LEAF; QQK +32A0 ; [.FB41.0020.0006.9805][.9805.0000.0000.9805] # CIRCLED IDEOGRAPH ITEM; QQK +FACB ; [.FB41.0020.0002.980B][.980B.0000.0000.980B] # CJK COMPATIBILITY IDEOGRAPH-FACB; QQC +2F9FE ; [.FB41.0020.0002.980B][.980B.0000.0000.980B] # CJK COMPATIBILITY IDEOGRAPH-2F9FE; QQC +2F9FF ; [.FB41.0020.0002.980B][.980B.0000.0000.980B] # CJK COMPATIBILITY IDEOGRAPH-2F9FF; QQC +F9B4 ; [.FB41.0020.0002.9818][.9818.0000.0000.9818] # CJK COMPATIBILITY IDEOGRAPH-F9B4; QQC +2FA00 ; [.FB41.0020.0002.9829][.9829.0000.0000.9829] # CJK COMPATIBILITY IDEOGRAPH-2FA00; QQC +FA6A ; [.FB41.0020.0002.983B][.983B.0000.0000.983B] # CJK COMPATIBILITY IDEOGRAPH-FA6A; QQC +FACC ; [.FB41.0020.0002.983B][.983B.0000.0000.983B] # CJK COMPATIBILITY IDEOGRAPH-FACC; QQC +F9D0 ; [.FB41.0020.0002.985E][.985E.0000.0000.985E] # CJK COMPATIBILITY IDEOGRAPH-F9D0; QQC +2EDA ; [.FB41.0020.0004.9875][.9875.0000.0000.9875] # CJK RADICAL C-SIMPLIFIED LEAF; QQK +2FB5 ; [.FB41.0020.0004.98A8][.98A8.0000.0000.98A8] # KANGXI RADICAL WIND; QQK +2EDB ; [.FB41.0020.0004.98CE][.98CE.0000.0000.98CE] # CJK RADICAL C-SIMPLIFIED WIND; QQK +2FB6 ; [.FB41.0020.0004.98DB][.98DB.0000.0000.98DB] # KANGXI RADICAL FLY; QQK +2EDC ; [.FB41.0020.0004.98DE][.98DE.0000.0000.98DE] # CJK RADICAL C-SIMPLIFIED FLY; QQK +2EDD ; [.FB41.0020.0004.98DF][.98DF.0000.0000.98DF] # CJK RADICAL EAT ONE; QQK +2FB7 ; [.FB41.0020.0004.98DF][.98DF.0000.0000.98DF] # KANGXI RADICAL EAT; QQK +2EDF ; [.FB41.0020.0004.98E0][.98E0.0000.0000.98E0] # CJK RADICAL EAT THREE; QQK +2EDE ; [.FB41.0020.0004.98E0][.98E0.0000.0000.98E0][.0000.0199.001F.2EDE] # CJK RADICAL EAT TWO; QQKN +2FA02 ; [.FB41.0020.0002.98E2][.98E2.0000.0000.98E2] # CJK COMPATIBILITY IDEOGRAPH-2FA02; QQC +FA2A ; [.FB41.0020.0002.98EF][.98EF.0000.0000.98EF] # CJK COMPATIBILITY IDEOGRAPH-FA2A; QQC +FA2B ; [.FB41.0020.0002.98FC][.98FC.0000.0000.98FC] # CJK COMPATIBILITY IDEOGRAPH-FA2B; QQC +FA2C ; [.FB41.0020.0002.9928][.9928.0000.0000.9928] # CJK COMPATIBILITY IDEOGRAPH-FA2C; QQC +2FA04 ; [.FB41.0020.0002.9929][.9929.0000.0000.9929] # CJK COMPATIBILITY IDEOGRAPH-2FA04; QQC +2EE0 ; [.FB41.0020.0004.9963][.9963.0000.0000.9963] # CJK RADICAL C-SIMPLIFIED EAT; QQK +2FB8 ; [.FB41.0020.0004.9996][.9996.0000.0000.9996] # KANGXI RADICAL HEAD; QQK +2EE1 ; [.FB41.0020.0004.9996][.9996.0000.0000.9996][.0000.0199.001F.2EE1] # CJK RADICAL HEAD; QQKN +2FB9 ; [.FB41.0020.0004.9999][.9999.0000.0000.9999] # KANGXI RADICAL FRAGRANT; QQK +2FA05 ; [.FB41.0020.0002.99A7][.99A7.0000.0000.99A7] # CJK COMPATIBILITY IDEOGRAPH-2FA05; QQC +2FBA ; [.FB41.0020.0004.99AC][.99AC.0000.0000.99AC] # KANGXI RADICAL HORSE; QQK +2FA06 ; [.FB41.0020.0002.99C2][.99C2.0000.0000.99C2] # CJK COMPATIBILITY IDEOGRAPH-2FA06; QQC +F91A ; [.FB41.0020.0002.99F1][.99F1.0000.0000.99F1] # CJK COMPATIBILITY IDEOGRAPH-F91A; QQC +2FA07 ; [.FB41.0020.0002.99FE][.99FE.0000.0000.99FE] # CJK COMPATIBILITY IDEOGRAPH-2FA07; QQC +F987 ; [.FB41.0020.0002.9A6A][.9A6A.0000.0000.9A6A] # CJK COMPATIBILITY IDEOGRAPH-F987; QQC +2EE2 ; [.FB41.0020.0004.9A6C][.9A6C.0000.0000.9A6C] # CJK RADICAL C-SIMPLIFIED HORSE; QQK +2FBB ; [.FB41.0020.0004.9AA8][.9AA8.0000.0000.9AA8] # KANGXI RADICAL BONE; QQK +2EE3 ; [.FB41.0020.0004.9AA8][.9AA8.0000.0000.9AA8][.0000.0199.001F.2EE3] # CJK RADICAL BONE; QQKN +2FBC ; [.FB41.0020.0004.9AD8][.9AD8.0000.0000.9AD8] # KANGXI RADICAL TALL; QQK +2FBD ; [.FB41.0020.0004.9ADF][.9ADF.0000.0000.9ADF] # KANGXI RADICAL HAIR; QQK +FACD ; [.FB41.0020.0002.9B12][.9B12.0000.0000.9B12] # CJK COMPATIBILITY IDEOGRAPH-FACD; QQC +2FA0A ; [.FB41.0020.0002.9B12][.9B12.0000.0000.9B12] # CJK COMPATIBILITY IDEOGRAPH-2FA0A; QQC +2FBE ; [.FB41.0020.0004.9B25][.9B25.0000.0000.9B25] # KANGXI RADICAL FIGHT; QQK +2FBF ; [.FB41.0020.0004.9B2F][.9B2F.0000.0000.9B2F] # KANGXI RADICAL SACRIFICIAL WINE; QQK +2FC0 ; [.FB41.0020.0004.9B32][.9B32.0000.0000.9B32] # KANGXI RADICAL CAULDRON; QQK +2FC1 ; [.FB41.0020.0004.9B3C][.9B3C.0000.0000.9B3C] # KANGXI RADICAL GHOST; QQK +2EE4 ; [.FB41.0020.0004.9B3C][.9B3C.0000.0000.9B3C][.0000.0199.001F.2EE4] # CJK RADICAL GHOST; QQKN +2FC2 ; [.FB41.0020.0004.9B5A][.9B5A.0000.0000.9B5A] # KANGXI RADICAL FISH; QQK +F939 ; [.FB41.0020.0002.9B6F][.9B6F.0000.0000.9B6F] # CJK COMPATIBILITY IDEOGRAPH-F939; QQC +2FA0B ; [.FB41.0020.0002.9C40][.9C40.0000.0000.9C40] # CJK COMPATIBILITY IDEOGRAPH-2FA0B; QQC +F9F2 ; [.FB41.0020.0002.9C57][.9C57.0000.0000.9C57] # CJK COMPATIBILITY IDEOGRAPH-F9F2; QQC +2EE5 ; [.FB41.0020.0004.9C7C][.9C7C.0000.0000.9C7C] # CJK RADICAL C-SIMPLIFIED FISH; QQK +2FC3 ; [.FB41.0020.0004.9CE5][.9CE5.0000.0000.9CE5] # KANGXI RADICAL BIRD; QQK +2FA0C ; [.FB41.0020.0002.9CFD][.9CFD.0000.0000.9CFD] # CJK COMPATIBILITY IDEOGRAPH-2FA0C; QQC +2FA0F ; [.FB41.0020.0002.9D67][.9D67.0000.0000.9D67] # CJK COMPATIBILITY IDEOGRAPH-2FA0F; QQC +FA2D ; [.FB41.0020.0002.9DB4][.9DB4.0000.0000.9DB4] # CJK COMPATIBILITY IDEOGRAPH-FA2D; QQC +F93A ; [.FB41.0020.0002.9DFA][.9DFA.0000.0000.9DFA] # CJK COMPATIBILITY IDEOGRAPH-F93A; QQC +F920 ; [.FB41.0020.0002.9E1E][.9E1E.0000.0000.9E1E] # CJK COMPATIBILITY IDEOGRAPH-F920; QQC +2EE6 ; [.FB41.0020.0004.9E1F][.9E1F.0000.0000.9E1F] # CJK RADICAL C-SIMPLIFIED BIRD; QQK +2FC4 ; [.FB41.0020.0004.9E75][.9E75.0000.0000.9E75] # KANGXI RADICAL SALT; QQK +2EE7 ; [.FB41.0020.0004.9E75][.9E75.0000.0000.9E75][.0000.0199.001F.2EE7] # CJK RADICAL C-SIMPLIFIED SALT; QQKN +F940 ; [.FB41.0020.0002.9E7F][.9E7F.0000.0000.9E7F] # CJK COMPATIBILITY IDEOGRAPH-F940; QQC +2FC5 ; [.FB41.0020.0004.9E7F][.9E7F.0000.0000.9E7F] # KANGXI RADICAL DEER; QQK +F988 ; [.FB41.0020.0002.9E97][.9E97.0000.0000.9E97] # CJK COMPATIBILITY IDEOGRAPH-F988; QQC +F9F3 ; [.FB41.0020.0002.9E9F][.9E9F.0000.0000.9E9F] # CJK COMPATIBILITY IDEOGRAPH-F9F3; QQC +2FC6 ; [.FB41.0020.0004.9EA5][.9EA5.0000.0000.9EA5] # KANGXI RADICAL WHEAT; QQK +2EE8 ; [.FB41.0020.0004.9EA6][.9EA6.0000.0000.9EA6] # CJK RADICAL SIMPLIFIED WHEAT; QQK +2FA15 ; [.FB41.0020.0002.9EBB][.9EBB.0000.0000.9EBB] # CJK COMPATIBILITY IDEOGRAPH-2FA15; QQC +2FC7 ; [.FB41.0020.0004.9EBB][.9EBB.0000.0000.9EBB] # KANGXI RADICAL HEMP; QQK +2FC8 ; [.FB41.0020.0004.9EC3][.9EC3.0000.0000.9EC3] # KANGXI RADICAL YELLOW; QQK +2EE9 ; [.FB41.0020.0004.9EC4][.9EC4.0000.0000.9EC4] # CJK RADICAL SIMPLIFIED YELLOW; QQK +2FC9 ; [.FB41.0020.0004.9ECD][.9ECD.0000.0000.9ECD] # KANGXI RADICAL MILLET; QQK +F989 ; [.FB41.0020.0002.9ECE][.9ECE.0000.0000.9ECE] # CJK COMPATIBILITY IDEOGRAPH-F989; QQC +2FCA ; [.FB41.0020.0004.9ED1][.9ED1.0000.0000.9ED1] # KANGXI RADICAL BLACK; QQK +2FA17 ; [.FB41.0020.0002.9EF9][.9EF9.0000.0000.9EF9] # CJK COMPATIBILITY IDEOGRAPH-2FA17; QQC +2FCB ; [.FB41.0020.0004.9EF9][.9EF9.0000.0000.9EF9] # KANGXI RADICAL EMBROIDERY; QQK +2FCC ; [.FB41.0020.0004.9EFD][.9EFD.0000.0000.9EFD] # KANGXI RADICAL FROG; QQK +2FA18 ; [.FB41.0020.0002.9EFE][.9EFE.0000.0000.9EFE] # CJK COMPATIBILITY IDEOGRAPH-2FA18; QQC +2EEA ; [.FB41.0020.0004.9EFE][.9EFE.0000.0000.9EFE] # CJK RADICAL C-SIMPLIFIED FROG; QQK +2FA19 ; [.FB41.0020.0002.9F05][.9F05.0000.0000.9F05] # CJK COMPATIBILITY IDEOGRAPH-2FA19; QQC +2FCD ; [.FB41.0020.0004.9F0E][.9F0E.0000.0000.9F0E] # KANGXI RADICAL TRIPOD; QQK +2FA1A ; [.FB41.0020.0002.9F0F][.9F0F.0000.0000.9F0F] # CJK COMPATIBILITY IDEOGRAPH-2FA1A; QQC +2FCE ; [.FB41.0020.0004.9F13][.9F13.0000.0000.9F13] # KANGXI RADICAL DRUM; QQK +2FA1B ; [.FB41.0020.0002.9F16][.9F16.0000.0000.9F16] # CJK COMPATIBILITY IDEOGRAPH-2FA1B; QQC +2FCF ; [.FB41.0020.0004.9F20][.9F20.0000.0000.9F20] # KANGXI RADICAL RAT; QQK +2FA1C ; [.FB41.0020.0002.9F3B][.9F3B.0000.0000.9F3B] # CJK COMPATIBILITY IDEOGRAPH-2FA1C; QQC +2FD0 ; [.FB41.0020.0004.9F3B][.9F3B.0000.0000.9F3B] # KANGXI RADICAL NOSE; QQK +FAD8 ; [.FB41.0020.0002.9F43][.9F43.0000.0000.9F43] # CJK COMPATIBILITY IDEOGRAPH-FAD8; QQC +2FD1 ; [.FB41.0020.0004.9F4A][.9F4A.0000.0000.9F4A] # KANGXI RADICAL EVEN; QQK +2EEB ; [.FB41.0020.0004.9F4A][.9F4A.0000.0000.9F4A][.0000.0199.001F.2EEB] # CJK RADICAL J-SIMPLIFIED EVEN; QQKN +2EEC ; [.FB41.0020.0004.9F50][.9F50.0000.0000.9F50] # CJK RADICAL C-SIMPLIFIED EVEN; QQK +2FD2 ; [.FB41.0020.0004.9F52][.9F52.0000.0000.9F52] # KANGXI RADICAL TOOTH; QQK +2EED ; [.FB41.0020.0004.9F52][.9F52.0000.0000.9F52][.0000.0199.001F.2EED] # CJK RADICAL J-SIMPLIFIED TOOTH; QQKN +2EEE ; [.FB41.0020.0004.9F7F][.9F7F.0000.0000.9F7F] # CJK RADICAL C-SIMPLIFIED TOOTH; QQK +F9C4 ; [.FB41.0020.0002.9F8D][.9F8D.0000.0000.9F8D] # CJK COMPATIBILITY IDEOGRAPH-F9C4; QQC +2FD3 ; [.FB41.0020.0004.9F8D][.9F8D.0000.0000.9F8D] # KANGXI RADICAL DRAGON; QQK +2EEF ; [.FB41.0020.0004.9F8D][.9F8D.0000.0000.9F8D][.0000.0199.001F.2EEF] # CJK RADICAL J-SIMPLIFIED DRAGON; QQKN +FAD9 ; [.FB41.0020.0002.9F8E][.9F8E.0000.0000.9F8E] # CJK COMPATIBILITY IDEOGRAPH-FAD9; QQC +2EF0 ; [.FB41.0020.0004.9F99][.9F99.0000.0000.9F99] # CJK RADICAL C-SIMPLIFIED DRAGON; QQK +F907 ; [.FB41.0020.0002.9F9C][.9F9C.0000.0000.9F9C] # CJK COMPATIBILITY IDEOGRAPH-F907; QQC +F908 ; [.FB41.0020.0002.9F9C][.9F9C.0000.0000.9F9C] # CJK COMPATIBILITY IDEOGRAPH-F908; QQC +FACE ; [.FB41.0020.0002.9F9C][.9F9C.0000.0000.9F9C] # CJK COMPATIBILITY IDEOGRAPH-FACE; QQC +2FD4 ; [.FB41.0020.0004.9F9C][.9F9C.0000.0000.9F9C] # KANGXI RADICAL TURTLE; QQK +2EF1 ; [.FB41.0020.0004.9F9C][.9F9C.0000.0000.9F9C][.0000.0199.001F.2EF1] # CJK RADICAL TURTLE; QQKN +2EF2 ; [.FB41.0020.0004.9F9C][.9F9C.0000.0000.9F9C][.0000.019A.001F.2EF2] # CJK RADICAL J-SIMPLIFIED TURTLE; QQKN +2EF3 ; [.FB41.0020.0004.9F9F][.9F9F.0000.0000.9F9F] # CJK RADICAL C-SIMPLIFIED TURTLE; QQK +2FD5 ; [.FB41.0020.0004.9FA0][.9FA0.0000.0000.9FA0] # KANGXI RADICAL FLUTE; QQK +FA0E ; [.FB41.0020.0002.FA0E][.FA0E.0000.0000.FA0E] # CJK COMPATIBILITY IDEOGRAPH-FA0E +FA0F ; [.FB41.0020.0002.FA0F][.FA0F.0000.0000.FA0F] # CJK COMPATIBILITY IDEOGRAPH-FA0F +FA11 ; [.FB41.0020.0002.FA11][.FA11.0000.0000.FA11] # CJK COMPATIBILITY IDEOGRAPH-FA11 +FA13 ; [.FB41.0020.0002.FA13][.FA13.0000.0000.FA13] # CJK COMPATIBILITY IDEOGRAPH-FA13 +FA14 ; [.FB41.0020.0002.FA14][.FA14.0000.0000.FA14] # CJK COMPATIBILITY IDEOGRAPH-FA14 +FA1F ; [.FB41.0020.0002.FA1F][.FA1F.0000.0000.FA1F] # CJK COMPATIBILITY IDEOGRAPH-FA1F +FA21 ; [.FB41.0020.0002.FA21][.FA21.0000.0000.FA21] # CJK COMPATIBILITY IDEOGRAPH-FA21 +FA23 ; [.FB41.0020.0002.FA23][.FA23.0000.0000.FA23] # CJK COMPATIBILITY IDEOGRAPH-FA23 +FA24 ; [.FB41.0020.0002.FA24][.FA24.0000.0000.FA24] # CJK COMPATIBILITY IDEOGRAPH-FA24 +FA27 ; [.FB41.0020.0002.FA27][.FA27.0000.0000.FA27] # CJK COMPATIBILITY IDEOGRAPH-FA27 +FA28 ; [.FB41.0020.0002.FA28][.FA28.0000.0000.FA28] # CJK COMPATIBILITY IDEOGRAPH-FA28 +FA29 ; [.FB41.0020.0002.FA29][.FA29.0000.0000.FA29] # CJK COMPATIBILITY IDEOGRAPH-FA29 +2F80C ; [.FB80.0020.0002.349E][.B49E.0000.0000.349E] # CJK COMPATIBILITY IDEOGRAPH-2F80C; QQC +2F813 ; [.FB80.0020.0002.34B9][.B4B9.0000.0000.34B9] # CJK COMPATIBILITY IDEOGRAPH-2F813; QQC +2F9CA ; [.FB80.0020.0002.34BB][.B4BB.0000.0000.34BB] # CJK COMPATIBILITY IDEOGRAPH-2F9CA; QQC +2F81F ; [.FB80.0020.0002.34DF][.B4DF.0000.0000.34DF] # CJK COMPATIBILITY IDEOGRAPH-2F81F; QQC +2F824 ; [.FB80.0020.0002.3515][.B515.0000.0000.3515] # CJK COMPATIBILITY IDEOGRAPH-2F824; QQC +2F867 ; [.FB80.0020.0002.36EE][.B6EE.0000.0000.36EE] # CJK COMPATIBILITY IDEOGRAPH-2F867; QQC +2F868 ; [.FB80.0020.0002.36FC][.B6FC.0000.0000.36FC] # CJK COMPATIBILITY IDEOGRAPH-2F868; QQC +2F876 ; [.FB80.0020.0002.3781][.B781.0000.0000.3781] # CJK COMPATIBILITY IDEOGRAPH-2F876; QQC +2F883 ; [.FB80.0020.0002.382F][.B82F.0000.0000.382F] # CJK COMPATIBILITY IDEOGRAPH-2F883; QQC +2F888 ; [.FB80.0020.0002.3862][.B862.0000.0000.3862] # CJK COMPATIBILITY IDEOGRAPH-2F888; QQC +2F88A ; [.FB80.0020.0002.387C][.B87C.0000.0000.387C] # CJK COMPATIBILITY IDEOGRAPH-2F88A; QQC +2F896 ; [.FB80.0020.0002.38C7][.B8C7.0000.0000.38C7] # CJK COMPATIBILITY IDEOGRAPH-2F896; QQC +2F89B ; [.FB80.0020.0002.38E3][.B8E3.0000.0000.38E3] # CJK COMPATIBILITY IDEOGRAPH-2F89B; QQC +2F8A2 ; [.FB80.0020.0002.391C][.B91C.0000.0000.391C] # CJK COMPATIBILITY IDEOGRAPH-2F8A2; QQC +2F8A1 ; [.FB80.0020.0002.393A][.B93A.0000.0000.393A] # CJK COMPATIBILITY IDEOGRAPH-2F8A1; QQC +2F8C2 ; [.FB80.0020.0002.3A2E][.BA2E.0000.0000.3A2E] # CJK COMPATIBILITY IDEOGRAPH-2F8C2; QQC +2F8C7 ; [.FB80.0020.0002.3A6C][.BA6C.0000.0000.3A6C] # CJK COMPATIBILITY IDEOGRAPH-2F8C7; QQC +2F8D1 ; [.FB80.0020.0002.3AE4][.BAE4.0000.0000.3AE4] # CJK COMPATIBILITY IDEOGRAPH-2F8D1; QQC +2F8D0 ; [.FB80.0020.0002.3B08][.BB08.0000.0000.3B08] # CJK COMPATIBILITY IDEOGRAPH-2F8D0; QQC +2F8CE ; [.FB80.0020.0002.3B19][.BB19.0000.0000.3B19] # CJK COMPATIBILITY IDEOGRAPH-2F8CE; QQC +2F8DE ; [.FB80.0020.0002.3B49][.BB49.0000.0000.3B49] # CJK COMPATIBILITY IDEOGRAPH-2F8DE; QQC +FAD2 ; [.FB80.0020.0002.3B9D][.BB9D.0000.0000.3B9D] # CJK COMPATIBILITY IDEOGRAPH-FAD2; QQC +2F8E7 ; [.FB80.0020.0002.3B9D][.BB9D.0000.0000.3B9D] # CJK COMPATIBILITY IDEOGRAPH-2F8E7; QQC +2F8EE ; [.FB80.0020.0002.3C18][.BC18.0000.0000.3C18] # CJK COMPATIBILITY IDEOGRAPH-2F8EE; QQC +2F8F2 ; [.FB80.0020.0002.3C4E][.BC4E.0000.0000.3C4E] # CJK COMPATIBILITY IDEOGRAPH-2F8F2; QQC +2F90A ; [.FB80.0020.0002.3D33][.BD33.0000.0000.3D33] # CJK COMPATIBILITY IDEOGRAPH-2F90A; QQC +2F916 ; [.FB80.0020.0002.3D96][.BD96.0000.0000.3D96] # CJK COMPATIBILITY IDEOGRAPH-2F916; QQC +2F92A ; [.FB80.0020.0002.3EAC][.BEAC.0000.0000.3EAC] # CJK COMPATIBILITY IDEOGRAPH-2F92A; QQC +2F92C ; [.FB80.0020.0002.3EB8][.BEB8.0000.0000.3EB8] # CJK COMPATIBILITY IDEOGRAPH-2F92C; QQC +2F92D ; [.FB80.0020.0002.3EB8][.BEB8.0000.0000.3EB8] # CJK COMPATIBILITY IDEOGRAPH-2F92D; QQC +2F933 ; [.FB80.0020.0002.3F1B][.BF1B.0000.0000.3F1B] # CJK COMPATIBILITY IDEOGRAPH-2F933; QQC +2F93E ; [.FB80.0020.0002.3FFC][.BFFC.0000.0000.3FFC] # CJK COMPATIBILITY IDEOGRAPH-2F93E; QQC +2F93F ; [.FB80.0020.0002.4008][.C008.0000.0000.4008] # CJK COMPATIBILITY IDEOGRAPH-2F93F; QQC +FAD3 ; [.FB80.0020.0002.4018][.C018.0000.0000.4018] # CJK COMPATIBILITY IDEOGRAPH-FAD3; QQC +FAD4 ; [.FB80.0020.0002.4039][.C039.0000.0000.4039] # CJK COMPATIBILITY IDEOGRAPH-FAD4; QQC +2F949 ; [.FB80.0020.0002.4039][.C039.0000.0000.4039] # CJK COMPATIBILITY IDEOGRAPH-2F949; QQC +2F94B ; [.FB80.0020.0002.4046][.C046.0000.0000.4046] # CJK COMPATIBILITY IDEOGRAPH-2F94B; QQC +2F94C ; [.FB80.0020.0002.4096][.C096.0000.0000.4096] # CJK COMPATIBILITY IDEOGRAPH-2F94C; QQC +2F951 ; [.FB80.0020.0002.40E3][.C0E3.0000.0000.40E3] # CJK COMPATIBILITY IDEOGRAPH-2F951; QQC +2F958 ; [.FB80.0020.0002.412F][.C12F.0000.0000.412F] # CJK COMPATIBILITY IDEOGRAPH-2F958; QQC +2F960 ; [.FB80.0020.0002.4202][.C202.0000.0000.4202] # CJK COMPATIBILITY IDEOGRAPH-2F960; QQC +2F964 ; [.FB80.0020.0002.4227][.C227.0000.0000.4227] # CJK COMPATIBILITY IDEOGRAPH-2F964; QQC +2F967 ; [.FB80.0020.0002.42A0][.C2A0.0000.0000.42A0] # CJK COMPATIBILITY IDEOGRAPH-2F967; QQC +2F96D ; [.FB80.0020.0002.4301][.C301.0000.0000.4301] # CJK COMPATIBILITY IDEOGRAPH-2F96D; QQC +2F971 ; [.FB80.0020.0002.4334][.C334.0000.0000.4334] # CJK COMPATIBILITY IDEOGRAPH-2F971; QQC +2F974 ; [.FB80.0020.0002.4359][.C359.0000.0000.4359] # CJK COMPATIBILITY IDEOGRAPH-2F974; QQC +2F981 ; [.FB80.0020.0002.43D5][.C3D5.0000.0000.43D5] # CJK COMPATIBILITY IDEOGRAPH-2F981; QQC +2F8D7 ; [.FB80.0020.0002.43D9][.C3D9.0000.0000.43D9] # CJK COMPATIBILITY IDEOGRAPH-2F8D7; QQC +2F984 ; [.FB80.0020.0002.440B][.C40B.0000.0000.440B] # CJK COMPATIBILITY IDEOGRAPH-2F984; QQC +2F98E ; [.FB80.0020.0002.446B][.C46B.0000.0000.446B] # CJK COMPATIBILITY IDEOGRAPH-2F98E; QQC +2F9A7 ; [.FB80.0020.0002.452B][.C52B.0000.0000.452B] # CJK COMPATIBILITY IDEOGRAPH-2F9A7; QQC +2F9AE ; [.FB80.0020.0002.455D][.C55D.0000.0000.455D] # CJK COMPATIBILITY IDEOGRAPH-2F9AE; QQC +2F9AF ; [.FB80.0020.0002.4561][.C561.0000.0000.4561] # CJK COMPATIBILITY IDEOGRAPH-2F9AF; QQC +2F9B2 ; [.FB80.0020.0002.456B][.C56B.0000.0000.456B] # CJK COMPATIBILITY IDEOGRAPH-2F9B2; QQC +2F9BF ; [.FB80.0020.0002.45D7][.C5D7.0000.0000.45D7] # CJK COMPATIBILITY IDEOGRAPH-2F9BF; QQC +2F9C2 ; [.FB80.0020.0002.45F9][.C5F9.0000.0000.45F9] # CJK COMPATIBILITY IDEOGRAPH-2F9C2; QQC +2F9C8 ; [.FB80.0020.0002.4635][.C635.0000.0000.4635] # CJK COMPATIBILITY IDEOGRAPH-2F9C8; QQC +2F9CD ; [.FB80.0020.0002.46BE][.C6BE.0000.0000.46BE] # CJK COMPATIBILITY IDEOGRAPH-2F9CD; QQC +2F9CE ; [.FB80.0020.0002.46C7][.C6C7.0000.0000.46C7] # CJK COMPATIBILITY IDEOGRAPH-2F9CE; QQC +2F9EF ; [.FB80.0020.0002.4995][.C995.0000.0000.4995] # CJK COMPATIBILITY IDEOGRAPH-2F9EF; QQC +2F9F2 ; [.FB80.0020.0002.49E6][.C9E6.0000.0000.49E6] # CJK COMPATIBILITY IDEOGRAPH-2F9F2; QQC +2F9F8 ; [.FB80.0020.0002.4A6E][.CA6E.0000.0000.4A6E] # CJK COMPATIBILITY IDEOGRAPH-2F9F8; QQC +2F9F9 ; [.FB80.0020.0002.4A76][.CA76.0000.0000.4A76] # CJK COMPATIBILITY IDEOGRAPH-2F9F9; QQC +2F9FC ; [.FB80.0020.0002.4AB2][.CAB2.0000.0000.4AB2] # CJK COMPATIBILITY IDEOGRAPH-2F9FC; QQC +2FA03 ; [.FB80.0020.0002.4B33][.CB33.0000.0000.4B33] # CJK COMPATIBILITY IDEOGRAPH-2FA03; QQC +2FA08 ; [.FB80.0020.0002.4BCE][.CBCE.0000.0000.4BCE] # CJK COMPATIBILITY IDEOGRAPH-2FA08; QQC +2FA0D ; [.FB80.0020.0002.4CCE][.CCCE.0000.0000.4CCE] # CJK COMPATIBILITY IDEOGRAPH-2FA0D; QQC +2FA0E ; [.FB80.0020.0002.4CED][.CCED.0000.0000.4CED] # CJK COMPATIBILITY IDEOGRAPH-2FA0E; QQC +2FA11 ; [.FB80.0020.0002.4CF8][.CCF8.0000.0000.4CF8] # CJK COMPATIBILITY IDEOGRAPH-2FA11; QQC +2FA16 ; [.FB80.0020.0002.4D56][.CD56.0000.0000.4D56] # CJK COMPATIBILITY IDEOGRAPH-2FA16; QQC +2F803 ; [.FB84.0020.0002.20122][.8122.0000.0000.20122] # CJK COMPATIBILITY IDEOGRAPH-2F803; QQC +2F812 ; [.FB84.0020.0002.2051C][.851C.0000.0000.2051C] # CJK COMPATIBILITY IDEOGRAPH-2F812; QQC +2F91B ; [.FB84.0020.0002.20525][.8525.0000.0000.20525] # CJK COMPATIBILITY IDEOGRAPH-2F91B; QQC +2F816 ; [.FB84.0020.0002.2054B][.854B.0000.0000.2054B] # CJK COMPATIBILITY IDEOGRAPH-2F816; QQC +2F80D ; [.FB84.0020.0002.2063A][.863A.0000.0000.2063A] # CJK COMPATIBILITY IDEOGRAPH-2F80D; QQC +2F9D9 ; [.FB84.0020.0002.20804][.8804.0000.0000.20804] # CJK COMPATIBILITY IDEOGRAPH-2F9D9; QQC +2F9DD ; [.FB84.0020.0002.208DE][.88DE.0000.0000.208DE] # CJK COMPATIBILITY IDEOGRAPH-2F9DD; QQC +2F834 ; [.FB84.0020.0002.20A2C][.8A2C.0000.0000.20A2C] # CJK COMPATIBILITY IDEOGRAPH-2F834; QQC +2F838 ; [.FB84.0020.0002.20B63][.8B63.0000.0000.20B63] # CJK COMPATIBILITY IDEOGRAPH-2F838; QQC +2F859 ; [.FB84.0020.0002.214E4][.94E4.0000.0000.214E4] # CJK COMPATIBILITY IDEOGRAPH-2F859; QQC +2F860 ; [.FB84.0020.0002.216A8][.96A8.0000.0000.216A8] # CJK COMPATIBILITY IDEOGRAPH-2F860; QQC +2F861 ; [.FB84.0020.0002.216EA][.96EA.0000.0000.216EA] # CJK COMPATIBILITY IDEOGRAPH-2F861; QQC +2F86C ; [.FB84.0020.0002.219C8][.99C8.0000.0000.219C8] # CJK COMPATIBILITY IDEOGRAPH-2F86C; QQC +2F871 ; [.FB84.0020.0002.21B18][.9B18.0000.0000.21B18] # CJK COMPATIBILITY IDEOGRAPH-2F871; QQC +2F8F8 ; [.FB84.0020.0002.21D0B][.9D0B.0000.0000.21D0B] # CJK COMPATIBILITY IDEOGRAPH-2F8F8; QQC +2F87B ; [.FB84.0020.0002.21DE4][.9DE4.0000.0000.21DE4] # CJK COMPATIBILITY IDEOGRAPH-2F87B; QQC +2F87D ; [.FB84.0020.0002.21DE6][.9DE6.0000.0000.21DE6] # CJK COMPATIBILITY IDEOGRAPH-2F87D; QQC +2F889 ; [.FB84.0020.0002.22183][.A183.0000.0000.22183] # CJK COMPATIBILITY IDEOGRAPH-2F889; QQC +2F939 ; [.FB84.0020.0002.2219F][.A19F.0000.0000.2219F] # CJK COMPATIBILITY IDEOGRAPH-2F939; QQC +2F891 ; [.FB84.0020.0002.22331][.A331.0000.0000.22331] # CJK COMPATIBILITY IDEOGRAPH-2F891; QQC +2F892 ; [.FB84.0020.0002.22331][.A331.0000.0000.22331] # CJK COMPATIBILITY IDEOGRAPH-2F892; QQC +2F8A4 ; [.FB84.0020.0002.226D4][.A6D4.0000.0000.226D4] # CJK COMPATIBILITY IDEOGRAPH-2F8A4; QQC +FAD0 ; [.FB84.0020.0002.22844][.A844.0000.0000.22844] # CJK COMPATIBILITY IDEOGRAPH-FAD0; QQC +FACF ; [.FB84.0020.0002.2284A][.A84A.0000.0000.2284A] # CJK COMPATIBILITY IDEOGRAPH-FACF; QQC +2F8B8 ; [.FB84.0020.0002.22B0C][.AB0C.0000.0000.22B0C] # CJK COMPATIBILITY IDEOGRAPH-2F8B8; QQC +2F8BE ; [.FB84.0020.0002.22BF1][.ABF1.0000.0000.22BF1] # CJK COMPATIBILITY IDEOGRAPH-2F8BE; QQC +2F8CA ; [.FB84.0020.0002.2300A][.B00A.0000.0000.2300A] # CJK COMPATIBILITY IDEOGRAPH-2F8CA; QQC +2F897 ; [.FB84.0020.0002.232B8][.B2B8.0000.0000.232B8] # CJK COMPATIBILITY IDEOGRAPH-2F897; QQC +2F980 ; [.FB84.0020.0002.2335F][.B35F.0000.0000.2335F] # CJK COMPATIBILITY IDEOGRAPH-2F980; QQC +2F989 ; [.FB84.0020.0002.23393][.B393.0000.0000.23393] # CJK COMPATIBILITY IDEOGRAPH-2F989; QQC +2F98A ; [.FB84.0020.0002.2339C][.B39C.0000.0000.2339C] # CJK COMPATIBILITY IDEOGRAPH-2F98A; QQC +2F8DD ; [.FB84.0020.0002.233C3][.B3C3.0000.0000.233C3] # CJK COMPATIBILITY IDEOGRAPH-2F8DD; QQC +FAD1 ; [.FB84.0020.0002.233D5][.B3D5.0000.0000.233D5] # CJK COMPATIBILITY IDEOGRAPH-FAD1; QQC +2F8E3 ; [.FB84.0020.0002.2346D][.B46D.0000.0000.2346D] # CJK COMPATIBILITY IDEOGRAPH-2F8E3; QQC +2F8EC ; [.FB84.0020.0002.236A3][.B6A3.0000.0000.236A3] # CJK COMPATIBILITY IDEOGRAPH-2F8EC; QQC +2F8F0 ; [.FB84.0020.0002.238A7][.B8A7.0000.0000.238A7] # CJK COMPATIBILITY IDEOGRAPH-2F8F0; QQC +2F8F7 ; [.FB84.0020.0002.23A8D][.BA8D.0000.0000.23A8D] # CJK COMPATIBILITY IDEOGRAPH-2F8F7; QQC +2F8F9 ; [.FB84.0020.0002.23AFA][.BAFA.0000.0000.23AFA] # CJK COMPATIBILITY IDEOGRAPH-2F8F9; QQC +2F8FB ; [.FB84.0020.0002.23CBC][.BCBC.0000.0000.23CBC] # CJK COMPATIBILITY IDEOGRAPH-2F8FB; QQC +2F906 ; [.FB84.0020.0002.23D1E][.BD1E.0000.0000.23D1E] # CJK COMPATIBILITY IDEOGRAPH-2F906; QQC +2F90D ; [.FB84.0020.0002.23ED1][.BED1.0000.0000.23ED1] # CJK COMPATIBILITY IDEOGRAPH-2F90D; QQC +2F910 ; [.FB84.0020.0002.23F5E][.BF5E.0000.0000.23F5E] # CJK COMPATIBILITY IDEOGRAPH-2F910; QQC +2F911 ; [.FB84.0020.0002.23F8E][.BF8E.0000.0000.23F8E] # CJK COMPATIBILITY IDEOGRAPH-2F911; QQC +2F91D ; [.FB84.0020.0002.24263][.C263.0000.0000.24263] # CJK COMPATIBILITY IDEOGRAPH-2F91D; QQC +2F91F ; [.FB84.0020.0002.243AB][.C3AB.0000.0000.243AB] # CJK COMPATIBILITY IDEOGRAPH-2F91F; QQC +2F923 ; [.FB84.0020.0002.24608][.C608.0000.0000.24608] # CJK COMPATIBILITY IDEOGRAPH-2F923; QQC +2F926 ; [.FB84.0020.0002.24735][.C735.0000.0000.24735] # CJK COMPATIBILITY IDEOGRAPH-2F926; QQC +2F927 ; [.FB84.0020.0002.24814][.C814.0000.0000.24814] # CJK COMPATIBILITY IDEOGRAPH-2F927; QQC +2F935 ; [.FB84.0020.0002.24C36][.CC36.0000.0000.24C36] # CJK COMPATIBILITY IDEOGRAPH-2F935; QQC +2F937 ; [.FB84.0020.0002.24C92][.CC92.0000.0000.24C92] # CJK COMPATIBILITY IDEOGRAPH-2F937; QQC +2F93B ; [.FB84.0020.0002.24FA1][.CFA1.0000.0000.24FA1] # CJK COMPATIBILITY IDEOGRAPH-2F93B; QQC +2F93C ; [.FB84.0020.0002.24FB8][.CFB8.0000.0000.24FB8] # CJK COMPATIBILITY IDEOGRAPH-2F93C; QQC +2F93D ; [.FB84.0020.0002.25044][.D044.0000.0000.25044] # CJK COMPATIBILITY IDEOGRAPH-2F93D; QQC +2F942 ; [.FB84.0020.0002.250F2][.D0F2.0000.0000.250F2] # CJK COMPATIBILITY IDEOGRAPH-2F942; QQC +2F941 ; [.FB84.0020.0002.250F3][.D0F3.0000.0000.250F3] # CJK COMPATIBILITY IDEOGRAPH-2F941; QQC +2F943 ; [.FB84.0020.0002.25119][.D119.0000.0000.25119] # CJK COMPATIBILITY IDEOGRAPH-2F943; QQC +2F944 ; [.FB84.0020.0002.25133][.D133.0000.0000.25133] # CJK COMPATIBILITY IDEOGRAPH-2F944; QQC +FAD5 ; [.FB84.0020.0002.25249][.D249.0000.0000.25249] # CJK COMPATIBILITY IDEOGRAPH-FAD5; QQC +2F94D ; [.FB84.0020.0002.2541D][.D41D.0000.0000.2541D] # CJK COMPATIBILITY IDEOGRAPH-2F94D; QQC +2F952 ; [.FB84.0020.0002.25626][.D626.0000.0000.25626] # CJK COMPATIBILITY IDEOGRAPH-2F952; QQC +2F954 ; [.FB84.0020.0002.2569A][.D69A.0000.0000.2569A] # CJK COMPATIBILITY IDEOGRAPH-2F954; QQC +2F955 ; [.FB84.0020.0002.256C5][.D6C5.0000.0000.256C5] # CJK COMPATIBILITY IDEOGRAPH-2F955; QQC +2F95C ; [.FB84.0020.0002.2597C][.D97C.0000.0000.2597C] # CJK COMPATIBILITY IDEOGRAPH-2F95C; QQC +2F95D ; [.FB84.0020.0002.25AA7][.DAA7.0000.0000.25AA7] # CJK COMPATIBILITY IDEOGRAPH-2F95D; QQC +2F95E ; [.FB84.0020.0002.25AA7][.DAA7.0000.0000.25AA7] # CJK COMPATIBILITY IDEOGRAPH-2F95E; QQC +2F961 ; [.FB84.0020.0002.25BAB][.DBAB.0000.0000.25BAB] # CJK COMPATIBILITY IDEOGRAPH-2F961; QQC +2F965 ; [.FB84.0020.0002.25C80][.DC80.0000.0000.25C80] # CJK COMPATIBILITY IDEOGRAPH-2F965; QQC +FAD6 ; [.FB84.0020.0002.25CD0][.DCD0.0000.0000.25CD0] # CJK COMPATIBILITY IDEOGRAPH-FAD6; QQC +2F96B ; [.FB84.0020.0002.25F86][.DF86.0000.0000.25F86] # CJK COMPATIBILITY IDEOGRAPH-2F96B; QQC +2F898 ; [.FB84.0020.0002.261DA][.E1DA.0000.0000.261DA] # CJK COMPATIBILITY IDEOGRAPH-2F898; QQC +2F972 ; [.FB84.0020.0002.26228][.E228.0000.0000.26228] # CJK COMPATIBILITY IDEOGRAPH-2F972; QQC +2F973 ; [.FB84.0020.0002.26247][.E247.0000.0000.26247] # CJK COMPATIBILITY IDEOGRAPH-2F973; QQC +2F975 ; [.FB84.0020.0002.262D9][.E2D9.0000.0000.262D9] # CJK COMPATIBILITY IDEOGRAPH-2F975; QQC +2F977 ; [.FB84.0020.0002.2633E][.E33E.0000.0000.2633E] # CJK COMPATIBILITY IDEOGRAPH-2F977; QQC +2F97B ; [.FB84.0020.0002.264DA][.E4DA.0000.0000.264DA] # CJK COMPATIBILITY IDEOGRAPH-2F97B; QQC +2F97C ; [.FB84.0020.0002.26523][.E523.0000.0000.26523] # CJK COMPATIBILITY IDEOGRAPH-2F97C; QQC +2F97E ; [.FB84.0020.0002.265A8][.E5A8.0000.0000.265A8] # CJK COMPATIBILITY IDEOGRAPH-2F97E; QQC +2F987 ; [.FB84.0020.0002.267A7][.E7A7.0000.0000.267A7] # CJK COMPATIBILITY IDEOGRAPH-2F987; QQC +2F988 ; [.FB84.0020.0002.267B5][.E7B5.0000.0000.267B5] # CJK COMPATIBILITY IDEOGRAPH-2F988; QQC +2F997 ; [.FB84.0020.0002.26B3C][.EB3C.0000.0000.26B3C] # CJK COMPATIBILITY IDEOGRAPH-2F997; QQC +2F9A4 ; [.FB84.0020.0002.26C36][.EC36.0000.0000.26C36] # CJK COMPATIBILITY IDEOGRAPH-2F9A4; QQC +2F9A6 ; [.FB84.0020.0002.26CD5][.ECD5.0000.0000.26CD5] # CJK COMPATIBILITY IDEOGRAPH-2F9A6; QQC +2F9A5 ; [.FB84.0020.0002.26D6B][.ED6B.0000.0000.26D6B] # CJK COMPATIBILITY IDEOGRAPH-2F9A5; QQC +2F9AD ; [.FB84.0020.0002.26F2C][.EF2C.0000.0000.26F2C] # CJK COMPATIBILITY IDEOGRAPH-2F9AD; QQC +2F9B0 ; [.FB84.0020.0002.26FB1][.EFB1.0000.0000.26FB1] # CJK COMPATIBILITY IDEOGRAPH-2F9B0; QQC +2F9B1 ; [.FB84.0020.0002.270D2][.F0D2.0000.0000.270D2] # CJK COMPATIBILITY IDEOGRAPH-2F9B1; QQC +2F9AB ; [.FB84.0020.0002.273CA][.F3CA.0000.0000.273CA] # CJK COMPATIBILITY IDEOGRAPH-2F9AB; QQC +2F9C5 ; [.FB84.0020.0002.27667][.F667.0000.0000.27667] # CJK COMPATIBILITY IDEOGRAPH-2F9C5; QQC +2F9CB ; [.FB84.0020.0002.278AE][.F8AE.0000.0000.278AE] # CJK COMPATIBILITY IDEOGRAPH-2F9CB; QQC +2F9CC ; [.FB84.0020.0002.27966][.F966.0000.0000.27966] # CJK COMPATIBILITY IDEOGRAPH-2F9CC; QQC +2F9D3 ; [.FB84.0020.0002.27CA8][.FCA8.0000.0000.27CA8] # CJK COMPATIBILITY IDEOGRAPH-2F9D3; QQC +FAD7 ; [.FB84.0020.0002.27ED3][.FED3.0000.0000.27ED3] # CJK COMPATIBILITY IDEOGRAPH-FAD7; QQC +2F9D8 ; [.FB84.0020.0002.27F2F][.FF2F.0000.0000.27F2F] # CJK COMPATIBILITY IDEOGRAPH-2F9D8; QQC +2F9E0 ; [.FB85.0020.0002.285D2][.85D2.0000.0000.285D2] # CJK COMPATIBILITY IDEOGRAPH-2F9E0; QQC +2F9E1 ; [.FB85.0020.0002.285ED][.85ED.0000.0000.285ED] # CJK COMPATIBILITY IDEOGRAPH-2F9E1; QQC +2F9E5 ; [.FB85.0020.0002.2872E][.872E.0000.0000.2872E] # CJK COMPATIBILITY IDEOGRAPH-2F9E5; QQC +2F9ED ; [.FB85.0020.0002.28BFA][.8BFA.0000.0000.28BFA] # CJK COMPATIBILITY IDEOGRAPH-2F9ED; QQC +2F9F1 ; [.FB85.0020.0002.28D77][.8D77.0000.0000.28D77] # CJK COMPATIBILITY IDEOGRAPH-2F9F1; QQC +2F9F6 ; [.FB85.0020.0002.29145][.9145.0000.0000.29145] # CJK COMPATIBILITY IDEOGRAPH-2F9F6; QQC +2F81C ; [.FB85.0020.0002.291DF][.91DF.0000.0000.291DF] # CJK COMPATIBILITY IDEOGRAPH-2F81C; QQC +2F9F7 ; [.FB85.0020.0002.2921A][.921A.0000.0000.2921A] # CJK COMPATIBILITY IDEOGRAPH-2F9F7; QQC +2F9FB ; [.FB85.0020.0002.2940A][.940A.0000.0000.2940A] # CJK COMPATIBILITY IDEOGRAPH-2F9FB; QQC +2F9FD ; [.FB85.0020.0002.29496][.9496.0000.0000.29496] # CJK COMPATIBILITY IDEOGRAPH-2F9FD; QQC +2FA01 ; [.FB85.0020.0002.295B6][.95B6.0000.0000.295B6] # CJK COMPATIBILITY IDEOGRAPH-2FA01; QQC +2FA09 ; [.FB85.0020.0002.29B30][.9B30.0000.0000.29B30] # CJK COMPATIBILITY IDEOGRAPH-2FA09; QQC +2FA10 ; [.FB85.0020.0002.2A0CE][.A0CE.0000.0000.2A0CE] # CJK COMPATIBILITY IDEOGRAPH-2FA10; QQC +2FA12 ; [.FB85.0020.0002.2A105][.A105.0000.0000.2A105] # CJK COMPATIBILITY IDEOGRAPH-2FA12; QQC +2FA13 ; [.FB85.0020.0002.2A20E][.A20E.0000.0000.2A20E] # CJK COMPATIBILITY IDEOGRAPH-2FA13; QQC +2FA14 ; [.FB85.0020.0002.2A291][.A291.0000.0000.2A291] # CJK COMPATIBILITY IDEOGRAPH-2FA14; QQC +2F88F ; [.FB85.0020.0002.2A392][.A392.0000.0000.2A392] # CJK COMPATIBILITY IDEOGRAPH-2F88F; QQC +2FA1D ; [.FB85.0020.0002.2A600][.A600.0000.0000.2A600] # CJK COMPATIBILITY IDEOGRAPH-2FA1D; QQC diff --git a/Master/tlpkg/tlperl/lib/Unicode/Collate/keys.txt b/Master/tlpkg/tlperl/lib/Unicode/Collate/keys.txt new file mode 100644 index 00000000000..aaa2d2a5a77 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Unicode/Collate/keys.txt @@ -0,0 +1,864 @@ +#### This file is generated from allkeys-3.1.1.txt (unicode.org) +#### by deleting many many entries. +#### +#### This table is intended ONLY for doing a test +#### of Unicode/Collate.pm, a Perl module. +#### +#### The entries contained here ARE: +#### 0000..007F # Basic Latin +#### 0080..00FF # Latin-1 Supplement +#### 0300..036F # Combining Diacritical Marks +#### 1100..11FF # Hangul Jamo +#### 2000..206F # General Punctuation +#### 3040..309F # Hiragana +#### 30A0..30FF # Katakana +#### +#### To fetch the original file, access to this: +#### http://www.unicode.org/reports/tr10/allkeys.txt +#### +@version 3.1.1 +0000 ; [.0000.0000.0000.0000] # [0000] NULL (in 6429) +0001 ; [.0000.0000.0000.0000] # [0001] START OF HEADING (in 6429) +0002 ; [.0000.0000.0000.0000] # [0002] START OF TEXT (in 6429) +0003 ; [.0000.0000.0000.0000] # [0003] END OF TEXT (in 6429) +0004 ; [.0000.0000.0000.0000] # [0004] END OF TRANSMISSION (in 6429) +0005 ; [.0000.0000.0000.0000] # [0005] ENQUIRY (in 6429) +0006 ; [.0000.0000.0000.0000] # [0006] ACKNOWLEDGE (in 6429) +0007 ; [.0000.0000.0000.0000] # [0007] BELL (in 6429) +0008 ; [.0000.0000.0000.0000] # [0008] BACKSPACE (in 6429) +000E ; [.0000.0000.0000.0000] # [000E] SHIFT OUT (in 6429) +000F ; [.0000.0000.0000.0000] # [000F] SHIFT IN (in 6429) +0010 ; [.0000.0000.0000.0000] # [0010] DATA LINK ESCAPE (in 6429) +0011 ; [.0000.0000.0000.0000] # [0011] DEVICE CONTROL ONE (in 6429) +0012 ; [.0000.0000.0000.0000] # [0012] DEVICE CONTROL TWO (in 6429) +0013 ; [.0000.0000.0000.0000] # [0013] DEVICE CONTROL THREE (in 6429) +0014 ; [.0000.0000.0000.0000] # [0014] DEVICE CONTROL FOUR (in 6429) +0015 ; [.0000.0000.0000.0000] # [0015] NEGATIVE ACKNOWLEDGE (in 6429) +0016 ; [.0000.0000.0000.0000] # [0016] SYNCHRONOUS IDLE (in 6429) +0017 ; [.0000.0000.0000.0000] # [0017] END OF TRANSMISSION BLOCK (in 6429) +0018 ; [.0000.0000.0000.0000] # [0018] CANCEL (in 6429) +0019 ; [.0000.0000.0000.0000] # [0019] END OF MEDIUM (in 6429) +001A ; [.0000.0000.0000.0000] # [001A] SUBSTITUTE (in 6429) +001B ; [.0000.0000.0000.0000] # [001B] ESCAPE (in 6429) +001C ; [.0000.0000.0000.0000] # [001C] FILE SEPARATOR (in 6429) +001D ; [.0000.0000.0000.0000] # [001D] GROUP SEPARATOR (in 6429) +001E ; [.0000.0000.0000.0000] # [001E] RECORD SEPARATOR (in 6429) +001F ; [.0000.0000.0000.0000] # [001F] UNIT SEPARATOR (in 6429) +007F ; [.0000.0000.0000.0000] # [007F] DELETE (in 6429) +0080 ; [.0000.0000.0000.0000] # [0080] <control> +0081 ; [.0000.0000.0000.0000] # [0081] <control> +0082 ; [.0000.0000.0000.0000] # [0082] BREAK PERMITTED HERE (in 6429) +0083 ; [.0000.0000.0000.0000] # [0083] NO BREAK HERE (in 6429) +0084 ; [.0000.0000.0000.0000] # [0084] <control> +0086 ; [.0000.0000.0000.0000] # [0086] START OF SELECTED AREA (in 6429) +0087 ; [.0000.0000.0000.0000] # [0087] END OF SELECTED AREA (in 6429) +0088 ; [.0000.0000.0000.0000] # [0088] CHARACTER TABULATION SET (in 6429) +0089 ; [.0000.0000.0000.0000] # [0089] CHARACTER TABULATION WITH JUSTIFICATION (in 6429) +008A ; [.0000.0000.0000.0000] # [008A] LINE TABULATION SET (in 6429) +008B ; [.0000.0000.0000.0000] # [008B] PARTIAL LINE FORWARD (in 6429) +008C ; [.0000.0000.0000.0000] # [008C] PARTIAL LINE BACKWARD (in 6429) +008D ; [.0000.0000.0000.0000] # [008D] PARTIAL LINE FEED (in 6429) +008E ; [.0000.0000.0000.0000] # [008E] SINGLE SHIFT TWO (in 6429) +008F ; [.0000.0000.0000.0000] # [008F] SINGLE SHIFT THREE (in 6429) +0090 ; [.0000.0000.0000.0000] # [0090] DEVICE CONTROL STRING (in 6429) +0091 ; [.0000.0000.0000.0000] # [0091] PRIVATE USE ONE (in 6429) +0092 ; [.0000.0000.0000.0000] # [0092] PRIVATE USE TWO (in 6429) +0093 ; [.0000.0000.0000.0000] # [0093] SET TRANSMIT STATE (in 6429) +0094 ; [.0000.0000.0000.0000] # [0094] CANCEL CHARACTER (in 6429) +0095 ; [.0000.0000.0000.0000] # [0095] MESSAGE WAITING (in 6429) +0096 ; [.0000.0000.0000.0000] # [0096] START OF GUARDED AREA (in 6429) +0097 ; [.0000.0000.0000.0000] # [0097] END OF GUARDED AREA (in 6429) +0098 ; [.0000.0000.0000.0000] # [0098] START OF STRING (in 6429) +0099 ; [.0000.0000.0000.0000] # [0099] <control> +009A ; [.0000.0000.0000.0000] # [009A] SINGLE CHARACTER INTRODUCER (in 6429) +009B ; [.0000.0000.0000.0000] # [009B] CONTROL SEQUENCE INTRODUCER (in 6429) +009C ; [.0000.0000.0000.0000] # [009C] STRING TERMINATOR (in 6429) +009D ; [.0000.0000.0000.0000] # [009D] OPERATING SYSTEM COMMAND (in 6429) +009E ; [.0000.0000.0000.0000] # [009E] PRIVACY MESSAGE (in 6429) +009F ; [.0000.0000.0000.0000] # [009F] APPLICATION PROGRAM COMMAND (in 6429) +200B ; [.0000.0000.0000.0000] # [200B] ZERO WIDTH SPACE +200C ; [.0000.0000.0000.0000] # [200C] ZERO WIDTH NON-JOINER +200D ; [.0000.0000.0000.0000] # [200D] ZERO WIDTH JOINER +200E ; [.0000.0000.0000.0000] # [200E] LEFT-TO-RIGHT MARK +200F ; [.0000.0000.0000.0000] # [200F] RIGHT-TO-LEFT MARK +202A ; [.0000.0000.0000.0000] # [202A] LEFT-TO-RIGHT EMBEDDING +202B ; [.0000.0000.0000.0000] # [202B] RIGHT-TO-LEFT EMBEDDING +202C ; [.0000.0000.0000.0000] # [202C] POP DIRECTIONAL FORMATTING +202D ; [.0000.0000.0000.0000] # [202D] LEFT-TO-RIGHT OVERRIDE +202E ; [.0000.0000.0000.0000] # [202E] RIGHT-TO-LEFT OVERRIDE +206A ; [.0000.0000.0000.0000] # [206A] INHIBIT SYMMETRIC SWAPPING +206B ; [.0000.0000.0000.0000] # [206B] ACTIVATE SYMMETRIC SWAPPING +206C ; [.0000.0000.0000.0000] # [206C] INHIBIT ARABIC FORM SHAPING +206D ; [.0000.0000.0000.0000] # [206D] ACTIVATE ARABIC FORM SHAPING +206E ; [.0000.0000.0000.0000] # [206E] NATIONAL DIGIT SHAPES +206F ; [.0000.0000.0000.0000] # [206F] NOMINAL DIGIT SHAPES +0009 ; [*0201.0020.0002.0009] # HORIZONTAL TABULATION (in 6429) +000A ; [*0202.0020.0002.000A] # LINE FEED (in 6429) +000B ; [*0203.0020.0002.000B] # VERTICAL TABULATION (in 6429) +000C ; [*0204.0020.0002.000C] # FORM FEED (in 6429) +000D ; [*0205.0020.0002.000D] # CARRIAGE RETURN (in 6429) +0020 ; [*0209.0020.0002.0020] # SPACE +0021 ; [*024B.0020.0002.0021] # EXCLAMATION MARK +0022 ; [*0270.0020.0002.0022] # QUOTATION MARK +0023 ; [*02A9.0020.0002.0023] # NUMBER SIGN +0025 ; [*02AA.0020.0002.0025] # PERCENT SIGN +0026 ; [*02A7.0020.0002.0026] # AMPERSAND +0027 ; [*0269.0020.0002.0027] # APOSTROPHE +0028 ; [*027A.0020.0002.0028] # LEFT PARENTHESIS +0029 ; [*027B.0020.0002.0029] # RIGHT PARENTHESIS +002A ; [*02A2.0020.0002.002A] # ASTERISK +002B ; [*039F.0020.0002.002B] # PLUS SIGN +002C ; [*022D.0020.0002.002C] # COMMA +002D ; [*0221.0020.0002.002D] # HYPHEN-MINUS +002E ; [*0255.0020.0002.002E] # FULL STOP +002F ; [*02A4.0020.0002.002F] # SOLIDUS +003A ; [*0237.0020.0002.003A] # COLON +003B ; [*0235.0020.0002.003B] # SEMICOLON +003C ; [*03A3.0020.0002.003C] # LESS-THAN SIGN +003D ; [*03A4.0020.0002.003D] # EQUALS SIGN +003E ; [*03A5.0020.0002.003E] # GREATER-THAN SIGN +003F ; [*024E.0020.0002.003F] # QUESTION MARK +0040 ; [*02A1.0020.0002.0040] # COMMERCIAL AT +005B ; [*027C.0020.0002.005B] # LEFT SQUARE BRACKET +005C ; [*02A6.0020.0002.005C] # REVERSE SOLIDUS +005D ; [*027D.0020.0002.005D] # RIGHT SQUARE BRACKET +005E ; [*020F.0020.0002.005E] # CIRCUMFLEX ACCENT +005F ; [*021B.0020.0002.005F] # LOW LINE +0060 ; [*020C.0020.0002.0060] # GRAVE ACCENT +007B ; [*027E.0020.0002.007B] # LEFT CURLY BRACKET +007C ; [*03A7.0020.0002.007C] # VERTICAL LINE +007D ; [*027F.0020.0002.007D] # RIGHT CURLY BRACKET +007E ; [*03AA.0020.0002.007E] # TILDE +0085 ; [*0206.0020.0002.0085] # NEXT LINE (in 6429) +00A0 ; [*0209.0020.001B.00A0] # NO-BREAK SPACE; QQK +00A1 ; [*024C.0020.0002.00A1] # INVERTED EXCLAMATION MARK +00A6 ; [*03A8.0020.0002.00A6] # BROKEN BAR +00A7 ; [*029C.0020.0002.00A7] # SECTION SIGN +00A8 ; [*0214.0020.0002.00A8] # DIAERESIS +00A9 ; [*029F.0020.0002.00A9] # COPYRIGHT SIGN +00AB ; [*0278.0020.0002.00AB] # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +00AC ; [*03A6.0020.0002.00AC] # NOT SIGN +00AD ; [*0220.0020.0002.00AD] # SOFT HYPHEN +00AE ; [*02A0.0020.0002.00AE] # REGISTERED SIGN +00AF ; [*0210.0020.0002.00AF] # MACRON +00B0 ; [*030A.0020.0002.00B0] # DEGREE SIGN +00B1 ; [*03A0.0020.0002.00B1] # PLUS-MINUS SIGN +00B4 ; [*020D.0020.0002.00B4] # ACUTE ACCENT +00B6 ; [*029D.0020.0002.00B6] # PILCROW SIGN +00B7 ; [*025F.0020.0002.00B7] # MIDDLE DOT +00B8 ; [*0219.0020.0002.00B8] # CEDILLA +00BB ; [*0279.0020.0002.00BB] # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +00BF ; [*024F.0020.0002.00BF] # INVERTED QUESTION MARK +00D7 ; [*03A2.0020.0002.00D7] # MULTIPLICATION SIGN +00F7 ; [*03A1.0020.0002.00F7] # DIVISION SIGN +2000 ; [*0209.0020.0004.2000] # EN QUAD; QQK +2001 ; [*0209.0020.0004.2001] # EM QUAD; QQK +2002 ; [*0209.0020.0004.2002] # EN SPACE; QQK +2003 ; [*0209.0020.0004.2003] # EM SPACE; QQK +2004 ; [*0209.0020.0004.2004] # THREE-PER-EM SPACE; QQK +2005 ; [*0209.0020.0004.2005] # FOUR-PER-EM SPACE; QQK +2006 ; [*0209.0020.0004.2006] # SIX-PER-EM SPACE; QQK +2007 ; [*0209.0020.001B.2007] # FIGURE SPACE; QQK +2008 ; [*0209.0020.0004.2008] # PUNCTUATION SPACE; QQK +2009 ; [*0209.0020.0004.2009] # THIN SPACE; QQK +200A ; [*0209.0020.0004.200A] # HAIR SPACE; QQK +2010 ; [*0225.0020.0002.2010] # HYPHEN +2011 ; [*0225.0020.001B.2011] # NON-BREAKING HYPHEN; QQK +2012 ; [*0226.0020.0002.2012] # FIGURE DASH +2013 ; [*0227.0020.0002.2013] # EN DASH +2014 ; [*0228.0020.0002.2014] # EM DASH +2015 ; [*0229.0020.0002.2015] # HORIZONTAL BAR +2016 ; [*03A9.0020.0002.2016] # DOUBLE VERTICAL LINE +2017 ; [*021C.0020.0002.2017] # DOUBLE LOW LINE +2018 ; [*026A.0020.0002.2018] # LEFT SINGLE QUOTATION MARK +2019 ; [*026B.0020.0002.2019] # RIGHT SINGLE QUOTATION MARK +201A ; [*026C.0020.0002.201A] # SINGLE LOW-9 QUOTATION MARK +201B ; [*026D.0020.0002.201B] # SINGLE HIGH-REVERSED-9 QUOTATION MARK +201C ; [*0271.0020.0002.201C] # LEFT DOUBLE QUOTATION MARK +201D ; [*0272.0020.0002.201D] # RIGHT DOUBLE QUOTATION MARK +201E ; [*0273.0020.0002.201E] # DOUBLE LOW-9 QUOTATION MARK +201F ; [*0274.0020.0002.201F] # DOUBLE HIGH-REVERSED-9 QUOTATION MARK +2020 ; [*02AE.0020.0002.2020] # DAGGER +2021 ; [*02AF.0020.0002.2021] # DOUBLE DAGGER +2022 ; [*02B0.0020.0002.2022] # BULLET +2023 ; [*02B1.0020.0002.2023] # TRIANGULAR BULLET +2024 ; [*0255.0020.0004.2024] # ONE DOT LEADER; QQK +2025 ; [*0255.0020.0004.2025][*0255.0020.0004.2025] # TWO DOT LEADER; QQKN +2026 ; [*0255.0020.0004.2026][*0255.0020.0004.2026][*0255.0020.001F.2026] # HORIZONTAL ELLIPSIS; QQKN +2027 ; [*02B2.0020.0002.2027] # HYPHENATION POINT +2028 ; [*0207.0020.0002.2028] # LINE SEPARATOR +2029 ; [*0208.0020.0002.2029] # PARAGRAPH SEPARATOR +202F ; [*0209.0020.001B.202F] # NARROW NO-BREAK SPACE; QQK +2030 ; [*02AC.0020.0002.2030] # PER MILLE SIGN +2031 ; [*02AD.0020.0002.2031] # PER TEN THOUSAND SIGN +2032 ; [*02B6.0020.0002.2032] # PRIME +2033 ; [*02B6.0020.0004.2033][*02B6.0020.0004.2033] # DOUBLE PRIME; QQKN +2034 ; [*02B6.0020.0004.2034][*02B6.0020.0004.2034][*02B6.0020.001F.2034] # TRIPLE PRIME; QQKN +2035 ; [*02B7.0020.0002.2035] # REVERSED PRIME +2036 ; [*02B7.0020.0004.2036][*02B7.0020.0004.2036] # REVERSED DOUBLE PRIME; QQKN +2037 ; [*02B7.0020.0004.2037][*02B7.0020.0004.2037][*02B7.0020.001F.2037] # REVERSED TRIPLE PRIME; QQKN +2038 ; [*02B9.0020.0002.2038] # CARET +2039 ; [*026E.0020.0002.2039] # SINGLE LEFT-POINTING ANGLE QUOTATION MARK +203A ; [*026F.0020.0002.203A] # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +203B ; [*02BA.0020.0002.203B] # REFERENCE MARK +203C ; [*024B.0020.0004.203C][*024B.0020.0004.203C] # DOUBLE EXCLAMATION MARK; QQKN +203D ; [*0254.0020.0002.203D] # INTERROBANG +203E ; [*0211.0020.0002.203E] # OVERLINE +203F ; [*02BB.0020.0002.203F] # UNDERTIE +2040 ; [*02BC.0020.0002.2040] # CHARACTER TIE +2041 ; [*02BD.0020.0002.2041] # CARET INSERTION POINT +2042 ; [*02BE.0020.0002.2042] # ASTERISM +2043 ; [*02B3.0020.0002.2043] # HYPHEN BULLET +2044 ; [*02A5.0020.0002.2044] # FRACTION SLASH +2045 ; [*0286.0020.0002.2045] # LEFT SQUARE BRACKET WITH QUILL +2046 ; [*0287.0020.0002.2046] # RIGHT SQUARE BRACKET WITH QUILL +2048 ; [*024E.0020.0004.2048][*024B.0020.0004.2048] # QUESTION EXCLAMATION MARK; QQKN +2049 ; [*024B.0020.0004.2049][*024E.0020.0004.2049] # EXCLAMATION QUESTION MARK; QQKN +204A ; [*02A8.0020.0002.204A] # TIRONIAN SIGN ET +204B ; [*029E.0020.0002.204B] # REVERSED PILCROW SIGN +204C ; [*02B4.0020.0002.204C] # BLACK LEFTWARDS BULLET +204D ; [*02B5.0020.0002.204D] # BLACK RIGHTWARDS BULLET +309B ; [*021E.0020.0002.309B] # KATAKANA-HIRAGANA VOICED SOUND MARK +309C ; [*021F.0020.0002.309C] # KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +30FB ; [*022C.0020.0002.30FB] # KATAKANA MIDDLE DOT +0332 ; [.0000.0021.0002.0332] # COMBINING LOW LINE +0313 ; [.0000.0022.0002.0313] # COMBINING COMMA ABOVE +0343 ; [.0000.0022.0002.0343] # COMBINING GREEK KORONIS; QQC +0314 ; [.0000.002A.0002.0314] # COMBINING REVERSED COMMA ABOVE +0301 ; [.0000.0032.0002.0301] # COMBINING ACUTE ACCENT +0341 ; [.0000.0032.0002.0341] # COMBINING ACUTE TONE MARK; QQC +0300 ; [.0000.0035.0002.0300] # COMBINING GRAVE ACCENT +0340 ; [.0000.0035.0002.0340] # COMBINING GRAVE TONE MARK; QQC +0306 ; [.0000.0037.0002.0306] # COMBINING BREVE +0302 ; [.0000.003C.0002.0302] # COMBINING CIRCUMFLEX ACCENT +030C ; [.0000.0041.0002.030C] # COMBINING CARON +030A ; [.0000.0043.0002.030A] # COMBINING RING ABOVE +0342 ; [.0000.0045.0002.0342] # COMBINING GREEK PERISPOMENI +0308 ; [.0000.0047.0002.0308] # COMBINING DIAERESIS +0344 ; [.0000.0047.0002.0308][.0000.0032.0002.0301] # COMBINING GREEK DIALYTIKA TONOS; QQCM +030B ; [.0000.004D.0002.030B] # COMBINING DOUBLE ACUTE ACCENT +0303 ; [.0000.004E.0002.0303] # COMBINING TILDE +0307 ; [.0000.0052.0002.0307] # COMBINING DOT ABOVE +0338 ; [.0000.0054.0002.0338] # COMBINING LONG SOLIDUS OVERLAY +0327 ; [.0000.0055.0002.0327] # COMBINING CEDILLA +0328 ; [.0000.0058.0002.0328] # COMBINING OGONEK +0304 ; [.0000.005A.0002.0304] # COMBINING MACRON +0305 ; [.0000.005E.0002.0305] # COMBINING OVERLINE +0309 ; [.0000.005F.0002.0309] # COMBINING HOOK ABOVE +030D ; [.0000.0060.0002.030D] # COMBINING VERTICAL LINE ABOVE +030E ; [.0000.0061.0002.030E] # COMBINING DOUBLE VERTICAL LINE ABOVE +030F ; [.0000.0062.0002.030F] # COMBINING DOUBLE GRAVE ACCENT +0310 ; [.0000.0063.0002.0310] # COMBINING CANDRABINDU +0311 ; [.0000.0064.0002.0311] # COMBINING INVERTED BREVE +0312 ; [.0000.0065.0002.0312] # COMBINING TURNED COMMA ABOVE +0315 ; [.0000.0066.0002.0315] # COMBINING COMMA ABOVE RIGHT +0316 ; [.0000.0067.0002.0316] # COMBINING GRAVE ACCENT BELOW +0317 ; [.0000.0068.0002.0317] # COMBINING ACUTE ACCENT BELOW +0318 ; [.0000.0069.0002.0318] # COMBINING LEFT TACK BELOW +0319 ; [.0000.006A.0002.0319] # COMBINING RIGHT TACK BELOW +031A ; [.0000.006B.0002.031A] # COMBINING LEFT ANGLE ABOVE +031B ; [.0000.006C.0002.031B] # COMBINING HORN +031C ; [.0000.0072.0002.031C] # COMBINING LEFT HALF RING BELOW +031D ; [.0000.0073.0002.031D] # COMBINING UP TACK BELOW +031E ; [.0000.0074.0002.031E] # COMBINING DOWN TACK BELOW +031F ; [.0000.0075.0002.031F] # COMBINING PLUS SIGN BELOW +0320 ; [.0000.0076.0002.0320] # COMBINING MINUS SIGN BELOW +0321 ; [.0000.0077.0002.0321] # COMBINING PALATALIZED HOOK BELOW +0322 ; [.0000.0078.0002.0322] # COMBINING RETROFLEX HOOK BELOW +0323 ; [.0000.0079.0002.0323] # COMBINING DOT BELOW +0324 ; [.0000.007E.0002.0324] # COMBINING DIAERESIS BELOW +0325 ; [.0000.007F.0002.0325] # COMBINING RING BELOW +0326 ; [.0000.0080.0002.0326] # COMBINING COMMA BELOW +0329 ; [.0000.0081.0002.0329] # COMBINING VERTICAL LINE BELOW +032A ; [.0000.0082.0002.032A] # COMBINING BRIDGE BELOW +032B ; [.0000.0083.0002.032B] # COMBINING INVERTED DOUBLE ARCH BELOW +032C ; [.0000.0084.0002.032C] # COMBINING CARON BELOW +032D ; [.0000.0085.0002.032D] # COMBINING CIRCUMFLEX ACCENT BELOW +032E ; [.0000.0086.0002.032E] # COMBINING BREVE BELOW +032F ; [.0000.0087.0002.032F] # COMBINING INVERTED BREVE BELOW +0330 ; [.0000.0088.0002.0330] # COMBINING TILDE BELOW +0331 ; [.0000.0089.0002.0331] # COMBINING MACRON BELOW +0333 ; [.0000.008A.0002.0333] # COMBINING DOUBLE LOW LINE +0334 ; [.0000.008B.0002.0334] # COMBINING TILDE OVERLAY +0335 ; [.0000.008C.0002.0335] # COMBINING SHORT STROKE OVERLAY +0336 ; [.0000.008D.0002.0336] # COMBINING LONG STROKE OVERLAY +0337 ; [.0000.008E.0002.0337] # COMBINING SHORT SOLIDUS OVERLAY +0339 ; [.0000.008F.0002.0339] # COMBINING RIGHT HALF RING BELOW +033A ; [.0000.0090.0002.033A] # COMBINING INVERTED BRIDGE BELOW +033B ; [.0000.0091.0002.033B] # COMBINING SQUARE BELOW +033C ; [.0000.0092.0002.033C] # COMBINING SEAGULL BELOW +033D ; [.0000.0093.0002.033D] # COMBINING X ABOVE +033E ; [.0000.0094.0002.033E] # COMBINING VERTICAL TILDE +033F ; [.0000.0095.0002.033F] # COMBINING DOUBLE OVERLINE +0345 ; [.0000.0096.0002.0345] # COMBINING GREEK YPOGEGRAMMENI +0346 ; [.0000.0097.0002.0346] # COMBINING BRIDGE ABOVE +0347 ; [.0000.0098.0002.0347] # COMBINING EQUALS SIGN BELOW +0348 ; [.0000.0099.0002.0348] # COMBINING DOUBLE VERTICAL LINE BELOW +0349 ; [.0000.009A.0002.0349] # COMBINING LEFT ANGLE BELOW +034A ; [.0000.009B.0002.034A] # COMBINING NOT TILDE ABOVE +034B ; [.0000.009C.0002.034B] # COMBINING HOMOTHETIC ABOVE +034C ; [.0000.009D.0002.034C] # COMBINING ALMOST EQUAL TO ABOVE +034D ; [.0000.009E.0002.034D] # COMBINING LEFT RIGHT ARROW BELOW +034E ; [.0000.009F.0002.034E] # COMBINING UPWARDS ARROW BELOW +0360 ; [.0000.00A0.0002.0360] # COMBINING DOUBLE TILDE +0361 ; [.0000.00A1.0002.0361] # COMBINING DOUBLE INVERTED BREVE +0362 ; [.0000.00A2.0002.0362] # COMBINING DOUBLE RIGHTWARDS ARROW BELOW +3099 ; [.0000.013D.0002.3099] # COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK +309A ; [.0000.013E.0002.309A] # COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +309D ; [.09DB.0020.0002.309D] # HIRAGANA ITERATION MARK +309E ; [.09DB.0020.0002.309D][.0000.013D.0002.3099] # HIRAGANA VOICED ITERATION MARK; QQCM +30FC ; [.09DC.0020.0002.30FC] # KATAKANA-HIRAGANA PROLONGED SOUND MARK +30FD ; [.09DD.0020.0002.30FD] # KATAKANA ITERATION MARK +30FE ; [.09DD.0020.0002.30FD][.0000.013D.0002.3099] # KATAKANA VOICED ITERATION MARK; QQCM +00A4 ; [.09DE.0020.0002.00A4] # CURRENCY SIGN +00A2 ; [.09DF.0020.0002.00A2] # CENT SIGN +0024 ; [.09E0.0020.0002.0024] # DOLLAR SIGN +00A3 ; [.09E1.0020.0002.00A3] # POUND SIGN +00A5 ; [.09E2.0020.0002.00A5] # YEN SIGN +0030 ; [.0A0B.0020.0002.0030] # DIGIT ZERO +0031 ; [.0A0C.0020.0002.0031] # DIGIT ONE +00B9 ; [.0A0C.0020.0014.00B9] # SUPERSCRIPT ONE; QQK +00BD ; [.0A0C.0020.001E.00BD][*02A5.0020.001E.00BD][.0A0D.0020.001F.00BD] # VULGAR FRACTION ONE HALF; QQKN +00BC ; [.0A0C.0020.001E.00BC][*02A5.0020.001E.00BC][.0A0F.0020.001F.00BC] # VULGAR FRACTION ONE QUARTER; QQKN +0032 ; [.0A0D.0020.0002.0032] # DIGIT TWO +00B2 ; [.0A0D.0020.0014.00B2] # SUPERSCRIPT TWO; QQK +0033 ; [.0A0E.0020.0002.0033] # DIGIT THREE +00B3 ; [.0A0E.0020.0014.00B3] # SUPERSCRIPT THREE; QQK +00BE ; [.0A0E.0020.001E.00BE][*02A5.0020.001E.00BE][.0A0F.0020.001F.00BE] # VULGAR FRACTION THREE QUARTERS; QQKN +0034 ; [.0A0F.0020.0002.0034] # DIGIT FOUR +0035 ; [.0A10.0020.0002.0035] # DIGIT FIVE +0036 ; [.0A11.0020.0002.0036] # DIGIT SIX +0037 ; [.0A12.0020.0002.0037] # DIGIT SEVEN +0038 ; [.0A13.0020.0002.0038] # DIGIT EIGHT +0039 ; [.0A14.0020.0002.0039] # DIGIT NINE +0061 ; [.0A15.0020.0002.0061] # LATIN SMALL LETTER A +0041 ; [.0A15.0020.0008.0041] # LATIN CAPITAL LETTER A +00AA ; [.0A15.0020.0014.00AA] # FEMININE ORDINAL INDICATOR; QQK +00E1 ; [.0A15.0020.0002.0061][.0000.0032.0002.0301] # LATIN SMALL LETTER A WITH ACUTE; QQCM +00C1 ; [.0A15.0020.0008.0041][.0000.0032.0002.0301] # LATIN CAPITAL LETTER A WITH ACUTE; QQCM +00E0 ; [.0A15.0020.0002.0061][.0000.0035.0002.0300] # LATIN SMALL LETTER A WITH GRAVE; QQCM +00C0 ; [.0A15.0020.0008.0041][.0000.0035.0002.0300] # LATIN CAPITAL LETTER A WITH GRAVE; QQCM +00E2 ; [.0A15.0020.0002.0061][.0000.003C.0002.0302] # LATIN SMALL LETTER A WITH CIRCUMFLEX; QQCM +00C2 ; [.0A15.0020.0008.0041][.0000.003C.0002.0302] # LATIN CAPITAL LETTER A WITH CIRCUMFLEX; QQCM +00E5 ; [.0A15.0020.0002.0061][.0000.0043.0002.030A] # LATIN SMALL LETTER A WITH RING ABOVE; QQCM +00C5 ; [.0A15.0020.0008.0041][.0000.0043.0002.030A] # LATIN CAPITAL LETTER A WITH RING ABOVE; QQCM +00E4 ; [.0A15.0020.0002.0061][.0000.0047.0002.0308] # LATIN SMALL LETTER A WITH DIAERESIS; QQCM +00C4 ; [.0A15.0020.0008.0041][.0000.0047.0002.0308] # LATIN CAPITAL LETTER A WITH DIAERESIS; QQCM +00E3 ; [.0A15.0020.0002.0061][.0000.004E.0002.0303] # LATIN SMALL LETTER A WITH TILDE; QQCM +00C3 ; [.0A15.0020.0008.0041][.0000.004E.0002.0303] # LATIN CAPITAL LETTER A WITH TILDE; QQCM +00E6 ; [.0A19.0020.0002.00E6] # LATIN SMALL LETTER AE +00C6 ; [.0A19.0020.0008.00C6] # LATIN CAPITAL LETTER AE +0062 ; [.0A29.0020.0002.0062] # LATIN SMALL LETTER B +0042 ; [.0A29.0020.0008.0042] # LATIN CAPITAL LETTER B +0063 ; [.0A3D.0020.0002.0063] # LATIN SMALL LETTER C +0043 ; [.0A3D.0020.0008.0043] # LATIN CAPITAL LETTER C +00E7 ; [.0A3D.0020.0002.0063][.0000.0055.0002.0327] # LATIN SMALL LETTER C WITH CEDILLA; QQCM +00C7 ; [.0A3D.0020.0008.0043][.0000.0055.0002.0327] # LATIN CAPITAL LETTER C WITH CEDILLA; QQCM +0064 ; [.0A49.0020.0002.0064] # LATIN SMALL LETTER D +0044 ; [.0A49.0020.0008.0044] # LATIN CAPITAL LETTER D +00F0 ; [.0A5D.0020.0002.00F0] # LATIN SMALL LETTER ETH +00D0 ; [.0A5D.0020.0008.00D0] # LATIN CAPITAL LETTER ETH +0065 ; [.0A65.0020.0002.0065] # LATIN SMALL LETTER E +0045 ; [.0A65.0020.0008.0045] # LATIN CAPITAL LETTER E +00E9 ; [.0A65.0020.0002.0065][.0000.0032.0002.0301] # LATIN SMALL LETTER E WITH ACUTE; QQCM +00C9 ; [.0A65.0020.0008.0045][.0000.0032.0002.0301] # LATIN CAPITAL LETTER E WITH ACUTE; QQCM +00E8 ; [.0A65.0020.0002.0065][.0000.0035.0002.0300] # LATIN SMALL LETTER E WITH GRAVE; QQCM +00C8 ; [.0A65.0020.0008.0045][.0000.0035.0002.0300] # LATIN CAPITAL LETTER E WITH GRAVE; QQCM +00EA ; [.0A65.0020.0002.0065][.0000.003C.0002.0302] # LATIN SMALL LETTER E WITH CIRCUMFLEX; QQCM +00CA ; [.0A65.0020.0008.0045][.0000.003C.0002.0302] # LATIN CAPITAL LETTER E WITH CIRCUMFLEX; QQCM +00EB ; [.0A65.0020.0002.0065][.0000.0047.0002.0308] # LATIN SMALL LETTER E WITH DIAERESIS; QQCM +00CB ; [.0A65.0020.0008.0045][.0000.0047.0002.0308] # LATIN CAPITAL LETTER E WITH DIAERESIS; QQCM +0066 ; [.0A91.0020.0002.0066] # LATIN SMALL LETTER F +0046 ; [.0A91.0020.0008.0046] # LATIN CAPITAL LETTER F +0067 ; [.0A99.0020.0002.0067] # LATIN SMALL LETTER G +0047 ; [.0A99.0020.0008.0047] # LATIN CAPITAL LETTER G +0068 ; [.0AB9.0020.0002.0068] # LATIN SMALL LETTER H +0048 ; [.0AB9.0020.0008.0048] # LATIN CAPITAL LETTER H +0069 ; [.0AD3.0020.0002.0069] # LATIN SMALL LETTER I +0049 ; [.0AD3.0020.0008.0049] # LATIN CAPITAL LETTER I +00ED ; [.0AD3.0020.0002.0069][.0000.0032.0002.0301] # LATIN SMALL LETTER I WITH ACUTE; QQCM +00CD ; [.0AD3.0020.0008.0049][.0000.0032.0002.0301] # LATIN CAPITAL LETTER I WITH ACUTE; QQCM +00EC ; [.0AD3.0020.0002.0069][.0000.0035.0002.0300] # LATIN SMALL LETTER I WITH GRAVE; QQCM +00CC ; [.0AD3.0020.0008.0049][.0000.0035.0002.0300] # LATIN CAPITAL LETTER I WITH GRAVE; QQCM +00EE ; [.0AD3.0020.0002.0069][.0000.003C.0002.0302] # LATIN SMALL LETTER I WITH CIRCUMFLEX; QQCM +00CE ; [.0AD3.0020.0008.0049][.0000.003C.0002.0302] # LATIN CAPITAL LETTER I WITH CIRCUMFLEX; QQCM +00EF ; [.0AD3.0020.0002.0069][.0000.0047.0002.0308] # LATIN SMALL LETTER I WITH DIAERESIS; QQCM +00CF ; [.0AD3.0020.0008.0049][.0000.0047.0002.0308] # LATIN CAPITAL LETTER I WITH DIAERESIS; QQCM +006A ; [.0AE7.0020.0002.006A] # LATIN SMALL LETTER J +004A ; [.0AE7.0020.0008.004A] # LATIN CAPITAL LETTER J +006B ; [.0AF7.0020.0002.006B] # LATIN SMALL LETTER K +004B ; [.0AF7.0020.0008.004B] # LATIN CAPITAL LETTER K +006C ; [.0B03.0020.0002.006C] # LATIN SMALL LETTER L +004C ; [.0B03.0020.0008.004C] # LATIN CAPITAL LETTER L +006D ; [.0B2B.0020.0002.006D] # LATIN SMALL LETTER M +004D ; [.0B2B.0020.0008.004D] # LATIN CAPITAL LETTER M +006E ; [.0B33.0020.0002.006E] # LATIN SMALL LETTER N +004E ; [.0B33.0020.0008.004E] # LATIN CAPITAL LETTER N +00F1 ; [.0B33.0020.0002.006E][.0000.004E.0002.0303] # LATIN SMALL LETTER N WITH TILDE; QQCM +00D1 ; [.0B33.0020.0008.004E][.0000.004E.0002.0303] # LATIN CAPITAL LETTER N WITH TILDE; QQCM +006F ; [.0B4B.0020.0002.006F] # LATIN SMALL LETTER O +004F ; [.0B4B.0020.0008.004F] # LATIN CAPITAL LETTER O +00BA ; [.0B4B.0020.0014.00BA] # MASCULINE ORDINAL INDICATOR; QQK +00F3 ; [.0B4B.0020.0002.006F][.0000.0032.0002.0301] # LATIN SMALL LETTER O WITH ACUTE; QQCM +00D3 ; [.0B4B.0020.0008.004F][.0000.0032.0002.0301] # LATIN CAPITAL LETTER O WITH ACUTE; QQCM +00F2 ; [.0B4B.0020.0002.006F][.0000.0035.0002.0300] # LATIN SMALL LETTER O WITH GRAVE; QQCM +00D2 ; [.0B4B.0020.0008.004F][.0000.0035.0002.0300] # LATIN CAPITAL LETTER O WITH GRAVE; QQCM +00F4 ; [.0B4B.0020.0002.006F][.0000.003C.0002.0302] # LATIN SMALL LETTER O WITH CIRCUMFLEX; QQCM +00D4 ; [.0B4B.0020.0008.004F][.0000.003C.0002.0302] # LATIN CAPITAL LETTER O WITH CIRCUMFLEX; QQCM +00F6 ; [.0B4B.0020.0002.006F][.0000.0047.0002.0308] # LATIN SMALL LETTER O WITH DIAERESIS; QQCM +00D6 ; [.0B4B.0020.0008.004F][.0000.0047.0002.0308] # LATIN CAPITAL LETTER O WITH DIAERESIS; QQCM +00F5 ; [.0B4B.0020.0002.006F][.0000.004E.0002.0303] # LATIN SMALL LETTER O WITH TILDE; QQCM +00D5 ; [.0B4B.0020.0008.004F][.0000.004E.0002.0303] # LATIN CAPITAL LETTER O WITH TILDE; QQCM +00F8 ; [.0B53.0020.0002.00F8] # LATIN SMALL LETTER O WITH STROKE +00D8 ; [.0B53.0020.0008.00D8] # LATIN CAPITAL LETTER O WITH STROKE +0070 ; [.0B67.0020.0002.0070] # LATIN SMALL LETTER P +0050 ; [.0B67.0020.0008.0050] # LATIN CAPITAL LETTER P +0071 ; [.0B73.0020.0002.0071] # LATIN SMALL LETTER Q +0051 ; [.0B73.0020.0008.0051] # LATIN CAPITAL LETTER Q +0072 ; [.0B7F.0020.0002.0072] # LATIN SMALL LETTER R +0052 ; [.0B7F.0020.0008.0052] # LATIN CAPITAL LETTER R +0073 ; [.0BA7.0020.0002.0073] # LATIN SMALL LETTER S +0053 ; [.0BA7.0020.0008.0053] # LATIN CAPITAL LETTER S +00DF ; [.0BA7.0020.0004.00DF][.0000.0153.0004.00DF][.0BA7.0020.001F.00DF] # LATIN SMALL LETTER SHARP S; QQKN +0074 ; [.0BBF.0020.0002.0074] # LATIN SMALL LETTER T +0054 ; [.0BBF.0020.0008.0054] # LATIN CAPITAL LETTER T +0075 ; [.0BD7.0020.0002.0075] # LATIN SMALL LETTER U +0055 ; [.0BD7.0020.0008.0055] # LATIN CAPITAL LETTER U +00FA ; [.0BD7.0020.0002.0075][.0000.0032.0002.0301] # LATIN SMALL LETTER U WITH ACUTE; QQCM +00DA ; [.0BD7.0020.0008.0055][.0000.0032.0002.0301] # LATIN CAPITAL LETTER U WITH ACUTE; QQCM +00F9 ; [.0BD7.0020.0002.0075][.0000.0035.0002.0300] # LATIN SMALL LETTER U WITH GRAVE; QQCM +00D9 ; [.0BD7.0020.0008.0055][.0000.0035.0002.0300] # LATIN CAPITAL LETTER U WITH GRAVE; QQCM +00FB ; [.0BD7.0020.0002.0075][.0000.003C.0002.0302] # LATIN SMALL LETTER U WITH CIRCUMFLEX; QQCM +00DB ; [.0BD7.0020.0008.0055][.0000.003C.0002.0302] # LATIN CAPITAL LETTER U WITH CIRCUMFLEX; QQCM +00FC ; [.0BD7.0020.0002.0075][.0000.0047.0002.0308] # LATIN SMALL LETTER U WITH DIAERESIS; QQCM +00DC ; [.0BD7.0020.0008.0055][.0000.0047.0002.0308] # LATIN CAPITAL LETTER U WITH DIAERESIS; QQCM +0076 ; [.0BEF.0020.0002.0076] # LATIN SMALL LETTER V +0056 ; [.0BEF.0020.0008.0056] # LATIN CAPITAL LETTER V +0077 ; [.0BFB.0020.0002.0077] # LATIN SMALL LETTER W +0057 ; [.0BFB.0020.0008.0057] # LATIN CAPITAL LETTER W +0078 ; [.0C03.0020.0002.0078] # LATIN SMALL LETTER X +0058 ; [.0C03.0020.0008.0058] # LATIN CAPITAL LETTER X +0079 ; [.0C07.0020.0002.0079] # LATIN SMALL LETTER Y +0059 ; [.0C07.0020.0008.0059] # LATIN CAPITAL LETTER Y +00FD ; [.0C07.0020.0002.0079][.0000.0032.0002.0301] # LATIN SMALL LETTER Y WITH ACUTE; QQCM +00DD ; [.0C07.0020.0008.0059][.0000.0032.0002.0301] # LATIN CAPITAL LETTER Y WITH ACUTE; QQCM +00FF ; [.0C07.0020.0002.0079][.0000.0047.0002.0308] # LATIN SMALL LETTER Y WITH DIAERESIS; QQCM +007A ; [.0C13.0020.0002.007A] # LATIN SMALL LETTER Z +005A ; [.0C13.0020.0008.005A] # LATIN CAPITAL LETTER Z +00FE ; [.0C3B.0020.0002.00FE] # LATIN SMALL LETTER THORN +00DE ; [.0C3B.0020.0008.00DE] # LATIN CAPITAL LETTER THORN +00B5 ; [.0C9F.0020.0004.00B5] # MICRO SIGN; QQK +1100 ; [.1831.0020.0002.1100] # HANGUL CHOSEONG KIYEOK +1101 ; [.1832.0020.0002.1101] # HANGUL CHOSEONG SSANGKIYEOK +1102 ; [.1833.0020.0002.1102] # HANGUL CHOSEONG NIEUN +1103 ; [.1834.0020.0002.1103] # HANGUL CHOSEONG TIKEUT +1104 ; [.1835.0020.0002.1104] # HANGUL CHOSEONG SSANGTIKEUT +1105 ; [.1836.0020.0002.1105] # HANGUL CHOSEONG RIEUL +1106 ; [.1837.0020.0002.1106] # HANGUL CHOSEONG MIEUM +1107 ; [.1838.0020.0002.1107] # HANGUL CHOSEONG PIEUP +1108 ; [.1839.0020.0002.1108] # HANGUL CHOSEONG SSANGPIEUP +1109 ; [.183A.0020.0002.1109] # HANGUL CHOSEONG SIOS +110A ; [.183B.0020.0002.110A] # HANGUL CHOSEONG SSANGSIOS +110B ; [.183C.0020.0002.110B] # HANGUL CHOSEONG IEUNG +110C ; [.183D.0020.0002.110C] # HANGUL CHOSEONG CIEUC +110D ; [.183E.0020.0002.110D] # HANGUL CHOSEONG SSANGCIEUC +110E ; [.183F.0020.0002.110E] # HANGUL CHOSEONG CHIEUCH +110F ; [.1840.0020.0002.110F] # HANGUL CHOSEONG KHIEUKH +1110 ; [.1841.0020.0002.1110] # HANGUL CHOSEONG THIEUTH +1111 ; [.1842.0020.0002.1111] # HANGUL CHOSEONG PHIEUPH +1112 ; [.1843.0020.0002.1112] # HANGUL CHOSEONG HIEUH +1113 ; [.1844.0020.0002.1113] # HANGUL CHOSEONG NIEUN-KIYEOK +1114 ; [.1845.0020.0002.1114] # HANGUL CHOSEONG SSANGNIEUN +1115 ; [.1846.0020.0002.1115] # HANGUL CHOSEONG NIEUN-TIKEUT +1116 ; [.1847.0020.0002.1116] # HANGUL CHOSEONG NIEUN-PIEUP +1117 ; [.1848.0020.0002.1117] # HANGUL CHOSEONG TIKEUT-KIYEOK +1118 ; [.1849.0020.0002.1118] # HANGUL CHOSEONG RIEUL-NIEUN +1119 ; [.184A.0020.0002.1119] # HANGUL CHOSEONG SSANGRIEUL +111A ; [.184B.0020.0002.111A] # HANGUL CHOSEONG RIEUL-HIEUH +111B ; [.184C.0020.0002.111B] # HANGUL CHOSEONG KAPYEOUNRIEUL +111C ; [.184D.0020.0002.111C] # HANGUL CHOSEONG MIEUM-PIEUP +111D ; [.184E.0020.0002.111D] # HANGUL CHOSEONG KAPYEOUNMIEUM +111E ; [.184F.0020.0002.111E] # HANGUL CHOSEONG PIEUP-KIYEOK +111F ; [.1850.0020.0002.111F] # HANGUL CHOSEONG PIEUP-NIEUN +1120 ; [.1851.0020.0002.1120] # HANGUL CHOSEONG PIEUP-TIKEUT +1121 ; [.1852.0020.0002.1121] # HANGUL CHOSEONG PIEUP-SIOS +1122 ; [.1853.0020.0002.1122] # HANGUL CHOSEONG PIEUP-SIOS-KIYEOK +1123 ; [.1854.0020.0002.1123] # HANGUL CHOSEONG PIEUP-SIOS-TIKEUT +1124 ; [.1855.0020.0002.1124] # HANGUL CHOSEONG PIEUP-SIOS-PIEUP +1125 ; [.1856.0020.0002.1125] # HANGUL CHOSEONG PIEUP-SSANGSIOS +1126 ; [.1857.0020.0002.1126] # HANGUL CHOSEONG PIEUP-SIOS-CIEUC +1127 ; [.1858.0020.0002.1127] # HANGUL CHOSEONG PIEUP-CIEUC +1128 ; [.1859.0020.0002.1128] # HANGUL CHOSEONG PIEUP-CHIEUCH +1129 ; [.185A.0020.0002.1129] # HANGUL CHOSEONG PIEUP-THIEUTH +112A ; [.185B.0020.0002.112A] # HANGUL CHOSEONG PIEUP-PHIEUPH +112B ; [.185C.0020.0002.112B] # HANGUL CHOSEONG KAPYEOUNPIEUP +112C ; [.185D.0020.0002.112C] # HANGUL CHOSEONG KAPYEOUNSSANGPIEUP +112D ; [.185E.0020.0002.112D] # HANGUL CHOSEONG SIOS-KIYEOK +112E ; [.185F.0020.0002.112E] # HANGUL CHOSEONG SIOS-NIEUN +112F ; [.1860.0020.0002.112F] # HANGUL CHOSEONG SIOS-TIKEUT +1130 ; [.1861.0020.0002.1130] # HANGUL CHOSEONG SIOS-RIEUL +1131 ; [.1862.0020.0002.1131] # HANGUL CHOSEONG SIOS-MIEUM +1132 ; [.1863.0020.0002.1132] # HANGUL CHOSEONG SIOS-PIEUP +1133 ; [.1864.0020.0002.1133] # HANGUL CHOSEONG SIOS-PIEUP-KIYEOK +1134 ; [.1865.0020.0002.1134] # HANGUL CHOSEONG SIOS-SSANGSIOS +1135 ; [.1866.0020.0002.1135] # HANGUL CHOSEONG SIOS-IEUNG +1136 ; [.1867.0020.0002.1136] # HANGUL CHOSEONG SIOS-CIEUC +1137 ; [.1868.0020.0002.1137] # HANGUL CHOSEONG SIOS-CHIEUCH +1138 ; [.1869.0020.0002.1138] # HANGUL CHOSEONG SIOS-KHIEUKH +1139 ; [.186A.0020.0002.1139] # HANGUL CHOSEONG SIOS-THIEUTH +113A ; [.186B.0020.0002.113A] # HANGUL CHOSEONG SIOS-PHIEUPH +113B ; [.186C.0020.0002.113B] # HANGUL CHOSEONG SIOS-HIEUH +113C ; [.186D.0020.0002.113C] # HANGUL CHOSEONG CHITUEUMSIOS +113D ; [.186E.0020.0002.113D] # HANGUL CHOSEONG CHITUEUMSSANGSIOS +113E ; [.186F.0020.0002.113E] # HANGUL CHOSEONG CEONGCHIEUMSIOS +113F ; [.1870.0020.0002.113F] # HANGUL CHOSEONG CEONGCHIEUMSSANGSIOS +1140 ; [.1871.0020.0002.1140] # HANGUL CHOSEONG PANSIOS +1141 ; [.1872.0020.0002.1141] # HANGUL CHOSEONG IEUNG-KIYEOK +1142 ; [.1873.0020.0002.1142] # HANGUL CHOSEONG IEUNG-TIKEUT +1143 ; [.1874.0020.0002.1143] # HANGUL CHOSEONG IEUNG-MIEUM +1144 ; [.1875.0020.0002.1144] # HANGUL CHOSEONG IEUNG-PIEUP +1145 ; [.1876.0020.0002.1145] # HANGUL CHOSEONG IEUNG-SIOS +1146 ; [.1877.0020.0002.1146] # HANGUL CHOSEONG IEUNG-PANSIOS +1147 ; [.1878.0020.0002.1147] # HANGUL CHOSEONG SSANGIEUNG +1148 ; [.1879.0020.0002.1148] # HANGUL CHOSEONG IEUNG-CIEUC +1149 ; [.187A.0020.0002.1149] # HANGUL CHOSEONG IEUNG-CHIEUCH +114A ; [.187B.0020.0002.114A] # HANGUL CHOSEONG IEUNG-THIEUTH +114B ; [.187C.0020.0002.114B] # HANGUL CHOSEONG IEUNG-PHIEUPH +114C ; [.187D.0020.0002.114C] # HANGUL CHOSEONG YESIEUNG +114D ; [.187E.0020.0002.114D] # HANGUL CHOSEONG CIEUC-IEUNG +114E ; [.187F.0020.0002.114E] # HANGUL CHOSEONG CHITUEUMCIEUC +114F ; [.1880.0020.0002.114F] # HANGUL CHOSEONG CHITUEUMSSANGCIEUC +1150 ; [.1881.0020.0002.1150] # HANGUL CHOSEONG CEONGCHIEUMCIEUC +1151 ; [.1882.0020.0002.1151] # HANGUL CHOSEONG CEONGCHIEUMSSANGCIEUC +1152 ; [.1883.0020.0002.1152] # HANGUL CHOSEONG CHIEUCH-KHIEUKH +1153 ; [.1884.0020.0002.1153] # HANGUL CHOSEONG CHIEUCH-HIEUH +1154 ; [.1885.0020.0002.1154] # HANGUL CHOSEONG CHITUEUMCHIEUCH +1155 ; [.1886.0020.0002.1155] # HANGUL CHOSEONG CEONGCHIEUMCHIEUCH +1156 ; [.1887.0020.0002.1156] # HANGUL CHOSEONG PHIEUPH-PIEUP +1157 ; [.1888.0020.0002.1157] # HANGUL CHOSEONG KAPYEOUNPHIEUPH +1158 ; [.1889.0020.0002.1158] # HANGUL CHOSEONG SSANGHIEUH +1159 ; [.188A.0020.0002.1159] # HANGUL CHOSEONG YEORINHIEUH +115F ; [.188B.0020.0002.115F] # HANGUL CHOSEONG FILLER +1160 ; [.188C.0020.0002.1160] # HANGUL JUNGSEONG FILLER +1161 ; [.188D.0020.0002.1161] # HANGUL JUNGSEONG A +1162 ; [.188E.0020.0002.1162] # HANGUL JUNGSEONG AE +1163 ; [.188F.0020.0002.1163] # HANGUL JUNGSEONG YA +1164 ; [.1890.0020.0002.1164] # HANGUL JUNGSEONG YAE +1165 ; [.1891.0020.0002.1165] # HANGUL JUNGSEONG EO +1166 ; [.1892.0020.0002.1166] # HANGUL JUNGSEONG E +1167 ; [.1893.0020.0002.1167] # HANGUL JUNGSEONG YEO +1168 ; [.1894.0020.0002.1168] # HANGUL JUNGSEONG YE +1169 ; [.1895.0020.0002.1169] # HANGUL JUNGSEONG O +116A ; [.1896.0020.0002.116A] # HANGUL JUNGSEONG WA +116B ; [.1897.0020.0002.116B] # HANGUL JUNGSEONG WAE +116C ; [.1898.0020.0002.116C] # HANGUL JUNGSEONG OE +116D ; [.1899.0020.0002.116D] # HANGUL JUNGSEONG YO +116E ; [.189A.0020.0002.116E] # HANGUL JUNGSEONG U +116F ; [.189B.0020.0002.116F] # HANGUL JUNGSEONG WEO +1170 ; [.189C.0020.0002.1170] # HANGUL JUNGSEONG WE +1171 ; [.189D.0020.0002.1171] # HANGUL JUNGSEONG WI +1172 ; [.189E.0020.0002.1172] # HANGUL JUNGSEONG YU +1173 ; [.189F.0020.0002.1173] # HANGUL JUNGSEONG EU +1174 ; [.18A0.0020.0002.1174] # HANGUL JUNGSEONG YI +1175 ; [.18A1.0020.0002.1175] # HANGUL JUNGSEONG I +1176 ; [.18A2.0020.0002.1176] # HANGUL JUNGSEONG A-O +1177 ; [.18A3.0020.0002.1177] # HANGUL JUNGSEONG A-U +1178 ; [.18A4.0020.0002.1178] # HANGUL JUNGSEONG YA-O +1179 ; [.18A5.0020.0002.1179] # HANGUL JUNGSEONG YA-YO +117A ; [.18A6.0020.0002.117A] # HANGUL JUNGSEONG EO-O +117B ; [.18A7.0020.0002.117B] # HANGUL JUNGSEONG EO-U +117C ; [.18A8.0020.0002.117C] # HANGUL JUNGSEONG EO-EU +117D ; [.18A9.0020.0002.117D] # HANGUL JUNGSEONG YEO-O +117E ; [.18AA.0020.0002.117E] # HANGUL JUNGSEONG YEO-U +117F ; [.18AB.0020.0002.117F] # HANGUL JUNGSEONG O-EO +1180 ; [.18AC.0020.0002.1180] # HANGUL JUNGSEONG O-E +1181 ; [.18AD.0020.0002.1181] # HANGUL JUNGSEONG O-YE +1182 ; [.18AE.0020.0002.1182] # HANGUL JUNGSEONG O-O +1183 ; [.18AF.0020.0002.1183] # HANGUL JUNGSEONG O-U +1184 ; [.18B0.0020.0002.1184] # HANGUL JUNGSEONG YO-YA +1185 ; [.18B1.0020.0002.1185] # HANGUL JUNGSEONG YO-YAE +1186 ; [.18B2.0020.0002.1186] # HANGUL JUNGSEONG YO-YEO +1187 ; [.18B3.0020.0002.1187] # HANGUL JUNGSEONG YO-O +1188 ; [.18B4.0020.0002.1188] # HANGUL JUNGSEONG YO-I +1189 ; [.18B5.0020.0002.1189] # HANGUL JUNGSEONG U-A +118A ; [.18B6.0020.0002.118A] # HANGUL JUNGSEONG U-AE +118B ; [.18B7.0020.0002.118B] # HANGUL JUNGSEONG U-EO-EU +118C ; [.18B8.0020.0002.118C] # HANGUL JUNGSEONG U-YE +118D ; [.18B9.0020.0002.118D] # HANGUL JUNGSEONG U-U +118E ; [.18BA.0020.0002.118E] # HANGUL JUNGSEONG YU-A +118F ; [.18BB.0020.0002.118F] # HANGUL JUNGSEONG YU-EO +1190 ; [.18BC.0020.0002.1190] # HANGUL JUNGSEONG YU-E +1191 ; [.18BD.0020.0002.1191] # HANGUL JUNGSEONG YU-YEO +1192 ; [.18BE.0020.0002.1192] # HANGUL JUNGSEONG YU-YE +1193 ; [.18BF.0020.0002.1193] # HANGUL JUNGSEONG YU-U +1194 ; [.18C0.0020.0002.1194] # HANGUL JUNGSEONG YU-I +1195 ; [.18C1.0020.0002.1195] # HANGUL JUNGSEONG EU-U +1196 ; [.18C2.0020.0002.1196] # HANGUL JUNGSEONG EU-EU +1197 ; [.18C3.0020.0002.1197] # HANGUL JUNGSEONG YI-U +1198 ; [.18C4.0020.0002.1198] # HANGUL JUNGSEONG I-A +1199 ; [.18C5.0020.0002.1199] # HANGUL JUNGSEONG I-YA +119A ; [.18C6.0020.0002.119A] # HANGUL JUNGSEONG I-O +119B ; [.18C7.0020.0002.119B] # HANGUL JUNGSEONG I-U +119C ; [.18C8.0020.0002.119C] # HANGUL JUNGSEONG I-EU +119D ; [.18C9.0020.0002.119D] # HANGUL JUNGSEONG I-ARAEA +119E ; [.18CA.0020.0002.119E] # HANGUL JUNGSEONG ARAEA +119F ; [.18CB.0020.0002.119F] # HANGUL JUNGSEONG ARAEA-EO +11A0 ; [.18CC.0020.0002.11A0] # HANGUL JUNGSEONG ARAEA-U +11A1 ; [.18CD.0020.0002.11A1] # HANGUL JUNGSEONG ARAEA-I +11A2 ; [.18CE.0020.0002.11A2] # HANGUL JUNGSEONG SSANGARAEA +11A8 ; [.18CF.0020.0002.11A8] # HANGUL JONGSEONG KIYEOK +11A9 ; [.18D0.0020.0002.11A9] # HANGUL JONGSEONG SSANGKIYEOK +11AA ; [.18D1.0020.0002.11AA] # HANGUL JONGSEONG KIYEOK-SIOS +11AB ; [.18D2.0020.0002.11AB] # HANGUL JONGSEONG NIEUN +11AC ; [.18D3.0020.0002.11AC] # HANGUL JONGSEONG NIEUN-CIEUC +11AD ; [.18D4.0020.0002.11AD] # HANGUL JONGSEONG NIEUN-HIEUH +11AE ; [.18D5.0020.0002.11AE] # HANGUL JONGSEONG TIKEUT +11AF ; [.18D6.0020.0002.11AF] # HANGUL JONGSEONG RIEUL +11B0 ; [.18D7.0020.0002.11B0] # HANGUL JONGSEONG RIEUL-KIYEOK +11B1 ; [.18D8.0020.0002.11B1] # HANGUL JONGSEONG RIEUL-MIEUM +11B2 ; [.18D9.0020.0002.11B2] # HANGUL JONGSEONG RIEUL-PIEUP +11B3 ; [.18DA.0020.0002.11B3] # HANGUL JONGSEONG RIEUL-SIOS +11B4 ; [.18DB.0020.0002.11B4] # HANGUL JONGSEONG RIEUL-THIEUTH +11B5 ; [.18DC.0020.0002.11B5] # HANGUL JONGSEONG RIEUL-PHIEUPH +11B6 ; [.18DD.0020.0002.11B6] # HANGUL JONGSEONG RIEUL-HIEUH +11B7 ; [.18DE.0020.0002.11B7] # HANGUL JONGSEONG MIEUM +11B8 ; [.18DF.0020.0002.11B8] # HANGUL JONGSEONG PIEUP +11B9 ; [.18E0.0020.0002.11B9] # HANGUL JONGSEONG PIEUP-SIOS +11BA ; [.18E1.0020.0002.11BA] # HANGUL JONGSEONG SIOS +11BB ; [.18E2.0020.0002.11BB] # HANGUL JONGSEONG SSANGSIOS +11BC ; [.18E3.0020.0002.11BC] # HANGUL JONGSEONG IEUNG +11BD ; [.18E4.0020.0002.11BD] # HANGUL JONGSEONG CIEUC +11BE ; [.18E5.0020.0002.11BE] # HANGUL JONGSEONG CHIEUCH +11BF ; [.18E6.0020.0002.11BF] # HANGUL JONGSEONG KHIEUKH +11C0 ; [.18E7.0020.0002.11C0] # HANGUL JONGSEONG THIEUTH +11C1 ; [.18E8.0020.0002.11C1] # HANGUL JONGSEONG PHIEUPH +11C2 ; [.18E9.0020.0002.11C2] # HANGUL JONGSEONG HIEUH +11C3 ; [.18EA.0020.0002.11C3] # HANGUL JONGSEONG KIYEOK-RIEUL +11C4 ; [.18EB.0020.0002.11C4] # HANGUL JONGSEONG KIYEOK-SIOS-KIYEOK +11C5 ; [.18EC.0020.0002.11C5] # HANGUL JONGSEONG NIEUN-KIYEOK +11C6 ; [.18ED.0020.0002.11C6] # HANGUL JONGSEONG NIEUN-TIKEUT +11C7 ; [.18EE.0020.0002.11C7] # HANGUL JONGSEONG NIEUN-SIOS +11C8 ; [.18EF.0020.0002.11C8] # HANGUL JONGSEONG NIEUN-PANSIOS +11C9 ; [.18F0.0020.0002.11C9] # HANGUL JONGSEONG NIEUN-THIEUTH +11CA ; [.18F1.0020.0002.11CA] # HANGUL JONGSEONG TIKEUT-KIYEOK +11CB ; [.18F2.0020.0002.11CB] # HANGUL JONGSEONG TIKEUT-RIEUL +11CC ; [.18F3.0020.0002.11CC] # HANGUL JONGSEONG RIEUL-KIYEOK-SIOS +11CD ; [.18F4.0020.0002.11CD] # HANGUL JONGSEONG RIEUL-NIEUN +11CE ; [.18F5.0020.0002.11CE] # HANGUL JONGSEONG RIEUL-TIKEUT +11CF ; [.18F6.0020.0002.11CF] # HANGUL JONGSEONG RIEUL-TIKEUT-HIEUH +11D0 ; [.18F7.0020.0002.11D0] # HANGUL JONGSEONG SSANGRIEUL +11D1 ; [.18F8.0020.0002.11D1] # HANGUL JONGSEONG RIEUL-MIEUM-KIYEOK +11D2 ; [.18F9.0020.0002.11D2] # HANGUL JONGSEONG RIEUL-MIEUM-SIOS +11D3 ; [.18FA.0020.0002.11D3] # HANGUL JONGSEONG RIEUL-PIEUP-SIOS +11D4 ; [.18FB.0020.0002.11D4] # HANGUL JONGSEONG RIEUL-PIEUP-HIEUH +11D5 ; [.18FC.0020.0002.11D5] # HANGUL JONGSEONG RIEUL-KAPYEOUNPIEUP +11D6 ; [.18FD.0020.0002.11D6] # HANGUL JONGSEONG RIEUL-SSANGSIOS +11D7 ; [.18FE.0020.0002.11D7] # HANGUL JONGSEONG RIEUL-PANSIOS +11D8 ; [.18FF.0020.0002.11D8] # HANGUL JONGSEONG RIEUL-KHIEUKH +11D9 ; [.1900.0020.0002.11D9] # HANGUL JONGSEONG RIEUL-YEORINHIEUH +11DA ; [.1901.0020.0002.11DA] # HANGUL JONGSEONG MIEUM-KIYEOK +11DB ; [.1902.0020.0002.11DB] # HANGUL JONGSEONG MIEUM-RIEUL +11DC ; [.1903.0020.0002.11DC] # HANGUL JONGSEONG MIEUM-PIEUP +11DD ; [.1904.0020.0002.11DD] # HANGUL JONGSEONG MIEUM-SIOS +11DE ; [.1905.0020.0002.11DE] # HANGUL JONGSEONG MIEUM-SSANGSIOS +11DF ; [.1906.0020.0002.11DF] # HANGUL JONGSEONG MIEUM-PANSIOS +11E0 ; [.1907.0020.0002.11E0] # HANGUL JONGSEONG MIEUM-CHIEUCH +11E1 ; [.1908.0020.0002.11E1] # HANGUL JONGSEONG MIEUM-HIEUH +11E2 ; [.1909.0020.0002.11E2] # HANGUL JONGSEONG KAPYEOUNMIEUM +11E3 ; [.190A.0020.0002.11E3] # HANGUL JONGSEONG PIEUP-RIEUL +11E4 ; [.190B.0020.0002.11E4] # HANGUL JONGSEONG PIEUP-PHIEUPH +11E5 ; [.190C.0020.0002.11E5] # HANGUL JONGSEONG PIEUP-HIEUH +11E6 ; [.190D.0020.0002.11E6] # HANGUL JONGSEONG KAPYEOUNPIEUP +11E7 ; [.190E.0020.0002.11E7] # HANGUL JONGSEONG SIOS-KIYEOK +11E8 ; [.190F.0020.0002.11E8] # HANGUL JONGSEONG SIOS-TIKEUT +11E9 ; [.1910.0020.0002.11E9] # HANGUL JONGSEONG SIOS-RIEUL +11EA ; [.1911.0020.0002.11EA] # HANGUL JONGSEONG SIOS-PIEUP +11EB ; [.1912.0020.0002.11EB] # HANGUL JONGSEONG PANSIOS +11EC ; [.1913.0020.0002.11EC] # HANGUL JONGSEONG IEUNG-KIYEOK +11ED ; [.1914.0020.0002.11ED] # HANGUL JONGSEONG IEUNG-SSANGKIYEOK +11EE ; [.1915.0020.0002.11EE] # HANGUL JONGSEONG SSANGIEUNG +11EF ; [.1916.0020.0002.11EF] # HANGUL JONGSEONG IEUNG-KHIEUKH +11F0 ; [.1917.0020.0002.11F0] # HANGUL JONGSEONG YESIEUNG +11F1 ; [.1918.0020.0002.11F1] # HANGUL JONGSEONG YESIEUNG-SIOS +11F2 ; [.1919.0020.0002.11F2] # HANGUL JONGSEONG YESIEUNG-PANSIOS +11F3 ; [.191A.0020.0002.11F3] # HANGUL JONGSEONG PHIEUPH-PIEUP +11F4 ; [.191B.0020.0002.11F4] # HANGUL JONGSEONG KAPYEOUNPHIEUPH +11F5 ; [.191C.0020.0002.11F5] # HANGUL JONGSEONG HIEUH-NIEUN +11F6 ; [.191D.0020.0002.11F6] # HANGUL JONGSEONG HIEUH-RIEUL +11F7 ; [.191E.0020.0002.11F7] # HANGUL JONGSEONG HIEUH-MIEUM +11F8 ; [.191F.0020.0002.11F8] # HANGUL JONGSEONG HIEUH-PIEUP +11F9 ; [.1920.0020.0002.11F9] # HANGUL JONGSEONG YEORINHIEUH +3041 ; [.1921.0020.000D.3041] # HIRAGANA LETTER SMALL A +3042 ; [.1921.0020.000E.3042] # HIRAGANA LETTER A +30A1 ; [.1921.0020.000F.30A1] # KATAKANA LETTER SMALL A +30A2 ; [.1921.0020.0011.30A2] # KATAKANA LETTER A +3043 ; [.1922.0020.000D.3043] # HIRAGANA LETTER SMALL I +3044 ; [.1922.0020.000E.3044] # HIRAGANA LETTER I +30A3 ; [.1922.0020.000F.30A3] # KATAKANA LETTER SMALL I +30A4 ; [.1922.0020.0011.30A4] # KATAKANA LETTER I +3045 ; [.1923.0020.000D.3045] # HIRAGANA LETTER SMALL U +3046 ; [.1923.0020.000E.3046] # HIRAGANA LETTER U +30A5 ; [.1923.0020.000F.30A5] # KATAKANA LETTER SMALL U +30A6 ; [.1923.0020.0011.30A6] # KATAKANA LETTER U +3094 ; [.1923.0020.000E.3046][.0000.013D.0002.3099] # HIRAGANA LETTER VU; QQCM +30F4 ; [.1923.0020.0011.30A6][.0000.013D.0002.3099] # KATAKANA LETTER VU; QQCM +3047 ; [.1924.0020.000D.3047] # HIRAGANA LETTER SMALL E +3048 ; [.1924.0020.000E.3048] # HIRAGANA LETTER E +30A7 ; [.1924.0020.000F.30A7] # KATAKANA LETTER SMALL E +30A8 ; [.1924.0020.0011.30A8] # KATAKANA LETTER E +3049 ; [.1925.0020.000D.3049] # HIRAGANA LETTER SMALL O +304A ; [.1925.0020.000E.304A] # HIRAGANA LETTER O +30A9 ; [.1925.0020.000F.30A9] # KATAKANA LETTER SMALL O +30AA ; [.1925.0020.0011.30AA] # KATAKANA LETTER O +304B ; [.1926.0020.000E.304B] # HIRAGANA LETTER KA +30F5 ; [.1926.0020.000F.30F5] # KATAKANA LETTER SMALL KA +30AB ; [.1926.0020.0011.30AB] # KATAKANA LETTER KA +304C ; [.1926.0020.000E.304B][.0000.013D.0002.3099] # HIRAGANA LETTER GA; QQCM +30AC ; [.1926.0020.0011.30AB][.0000.013D.0002.3099] # KATAKANA LETTER GA; QQCM +304D ; [.1927.0020.000E.304D] # HIRAGANA LETTER KI +30AD ; [.1927.0020.0011.30AD] # KATAKANA LETTER KI +304E ; [.1927.0020.000E.304D][.0000.013D.0002.3099] # HIRAGANA LETTER GI; QQCM +30AE ; [.1927.0020.0011.30AD][.0000.013D.0002.3099] # KATAKANA LETTER GI; QQCM +304F ; [.1928.0020.000E.304F] # HIRAGANA LETTER KU +30AF ; [.1928.0020.0011.30AF] # KATAKANA LETTER KU +3050 ; [.1928.0020.000E.304F][.0000.013D.0002.3099] # HIRAGANA LETTER GU; QQCM +30B0 ; [.1928.0020.0011.30AF][.0000.013D.0002.3099] # KATAKANA LETTER GU; QQCM +3051 ; [.1929.0020.000E.3051] # HIRAGANA LETTER KE +30F6 ; [.1929.0020.000F.30F6] # KATAKANA LETTER SMALL KE +30B1 ; [.1929.0020.0011.30B1] # KATAKANA LETTER KE +3052 ; [.1929.0020.000E.3051][.0000.013D.0002.3099] # HIRAGANA LETTER GE; QQCM +30B2 ; [.1929.0020.0011.30B1][.0000.013D.0002.3099] # KATAKANA LETTER GE; QQCM +3053 ; [.192A.0020.000E.3053] # HIRAGANA LETTER KO +30B3 ; [.192A.0020.0011.30B3] # KATAKANA LETTER KO +3054 ; [.192A.0020.000E.3053][.0000.013D.0002.3099] # HIRAGANA LETTER GO; QQCM +30B4 ; [.192A.0020.0011.30B3][.0000.013D.0002.3099] # KATAKANA LETTER GO; QQCM +3055 ; [.192B.0020.000E.3055] # HIRAGANA LETTER SA +30B5 ; [.192B.0020.0011.30B5] # KATAKANA LETTER SA +3056 ; [.192B.0020.000E.3055][.0000.013D.0002.3099] # HIRAGANA LETTER ZA; QQCM +30B6 ; [.192B.0020.0011.30B5][.0000.013D.0002.3099] # KATAKANA LETTER ZA; QQCM +3057 ; [.192C.0020.000E.3057] # HIRAGANA LETTER SI +30B7 ; [.192C.0020.0011.30B7] # KATAKANA LETTER SI +3058 ; [.192C.0020.000E.3057][.0000.013D.0002.3099] # HIRAGANA LETTER ZI; QQCM +30B8 ; [.192C.0020.0011.30B7][.0000.013D.0002.3099] # KATAKANA LETTER ZI; QQCM +3059 ; [.192D.0020.000E.3059] # HIRAGANA LETTER SU +30B9 ; [.192D.0020.0011.30B9] # KATAKANA LETTER SU +305A ; [.192D.0020.000E.3059][.0000.013D.0002.3099] # HIRAGANA LETTER ZU; QQCM +30BA ; [.192D.0020.0011.30B9][.0000.013D.0002.3099] # KATAKANA LETTER ZU; QQCM +305B ; [.192E.0020.000E.305B] # HIRAGANA LETTER SE +30BB ; [.192E.0020.0011.30BB] # KATAKANA LETTER SE +305C ; [.192E.0020.000E.305B][.0000.013D.0002.3099] # HIRAGANA LETTER ZE; QQCM +30BC ; [.192E.0020.0011.30BB][.0000.013D.0002.3099] # KATAKANA LETTER ZE; QQCM +305D ; [.192F.0020.000E.305D] # HIRAGANA LETTER SO +30BD ; [.192F.0020.0011.30BD] # KATAKANA LETTER SO +305E ; [.192F.0020.000E.305D][.0000.013D.0002.3099] # HIRAGANA LETTER ZO; QQCM +30BE ; [.192F.0020.0011.30BD][.0000.013D.0002.3099] # KATAKANA LETTER ZO; QQCM +305F ; [.1930.0020.000E.305F] # HIRAGANA LETTER TA +30BF ; [.1930.0020.0011.30BF] # KATAKANA LETTER TA +3060 ; [.1930.0020.000E.305F][.0000.013D.0002.3099] # HIRAGANA LETTER DA; QQCM +30C0 ; [.1930.0020.0011.30BF][.0000.013D.0002.3099] # KATAKANA LETTER DA; QQCM +3061 ; [.1931.0020.000E.3061] # HIRAGANA LETTER TI +30C1 ; [.1931.0020.0011.30C1] # KATAKANA LETTER TI +3062 ; [.1931.0020.000E.3061][.0000.013D.0002.3099] # HIRAGANA LETTER DI; QQCM +30C2 ; [.1931.0020.0011.30C1][.0000.013D.0002.3099] # KATAKANA LETTER DI; QQCM +3063 ; [.1932.0020.000D.3063] # HIRAGANA LETTER SMALL TU +3064 ; [.1932.0020.000E.3064] # HIRAGANA LETTER TU +30C3 ; [.1932.0020.000F.30C3] # KATAKANA LETTER SMALL TU +30C4 ; [.1932.0020.0011.30C4] # KATAKANA LETTER TU +3065 ; [.1932.0020.000E.3064][.0000.013D.0002.3099] # HIRAGANA LETTER DU; QQCM +30C5 ; [.1932.0020.0011.30C4][.0000.013D.0002.3099] # KATAKANA LETTER DU; QQCM +3066 ; [.1933.0020.000E.3066] # HIRAGANA LETTER TE +30C6 ; [.1933.0020.0011.30C6] # KATAKANA LETTER TE +3067 ; [.1933.0020.000E.3066][.0000.013D.0002.3099] # HIRAGANA LETTER DE; QQCM +30C7 ; [.1933.0020.0011.30C6][.0000.013D.0002.3099] # KATAKANA LETTER DE; QQCM +3068 ; [.1934.0020.000E.3068] # HIRAGANA LETTER TO +30C8 ; [.1934.0020.0011.30C8] # KATAKANA LETTER TO +3069 ; [.1934.0020.000E.3068][.0000.013D.0002.3099] # HIRAGANA LETTER DO; QQCM +30C9 ; [.1934.0020.0011.30C8][.0000.013D.0002.3099] # KATAKANA LETTER DO; QQCM +306A ; [.1935.0020.000E.306A] # HIRAGANA LETTER NA +30CA ; [.1935.0020.0011.30CA] # KATAKANA LETTER NA +306B ; [.1936.0020.000E.306B] # HIRAGANA LETTER NI +30CB ; [.1936.0020.0011.30CB] # KATAKANA LETTER NI +306C ; [.1937.0020.000E.306C] # HIRAGANA LETTER NU +30CC ; [.1937.0020.0011.30CC] # KATAKANA LETTER NU +306D ; [.1938.0020.000E.306D] # HIRAGANA LETTER NE +30CD ; [.1938.0020.0011.30CD] # KATAKANA LETTER NE +306E ; [.1939.0020.000E.306E] # HIRAGANA LETTER NO +30CE ; [.1939.0020.0011.30CE] # KATAKANA LETTER NO +306F ; [.193A.0020.000E.306F] # HIRAGANA LETTER HA +30CF ; [.193A.0020.0011.30CF] # KATAKANA LETTER HA +3070 ; [.193A.0020.000E.306F][.0000.013D.0002.3099] # HIRAGANA LETTER BA; QQCM +30D0 ; [.193A.0020.0011.30CF][.0000.013D.0002.3099] # KATAKANA LETTER BA; QQCM +3071 ; [.193A.0020.000E.306F][.0000.013E.0002.309A] # HIRAGANA LETTER PA; QQCM +30D1 ; [.193A.0020.0011.30CF][.0000.013E.0002.309A] # KATAKANA LETTER PA; QQCM +3072 ; [.193B.0020.000E.3072] # HIRAGANA LETTER HI +30D2 ; [.193B.0020.0011.30D2] # KATAKANA LETTER HI +3073 ; [.193B.0020.000E.3072][.0000.013D.0002.3099] # HIRAGANA LETTER BI; QQCM +30D3 ; [.193B.0020.0011.30D2][.0000.013D.0002.3099] # KATAKANA LETTER BI; QQCM +3074 ; [.193B.0020.000E.3072][.0000.013E.0002.309A] # HIRAGANA LETTER PI; QQCM +30D4 ; [.193B.0020.0011.30D2][.0000.013E.0002.309A] # KATAKANA LETTER PI; QQCM +3075 ; [.193C.0020.000E.3075] # HIRAGANA LETTER HU +30D5 ; [.193C.0020.0011.30D5] # KATAKANA LETTER HU +3076 ; [.193C.0020.000E.3075][.0000.013D.0002.3099] # HIRAGANA LETTER BU; QQCM +30D6 ; [.193C.0020.0011.30D5][.0000.013D.0002.3099] # KATAKANA LETTER BU; QQCM +3077 ; [.193C.0020.000E.3075][.0000.013E.0002.309A] # HIRAGANA LETTER PU; QQCM +30D7 ; [.193C.0020.0011.30D5][.0000.013E.0002.309A] # KATAKANA LETTER PU; QQCM +3078 ; [.193D.0020.000E.3078] # HIRAGANA LETTER HE +30D8 ; [.193D.0020.0011.30D8] # KATAKANA LETTER HE +3079 ; [.193D.0020.000E.3078][.0000.013D.0002.3099] # HIRAGANA LETTER BE; QQCM +30D9 ; [.193D.0020.0011.30D8][.0000.013D.0002.3099] # KATAKANA LETTER BE; QQCM +307A ; [.193D.0020.000E.3078][.0000.013E.0002.309A] # HIRAGANA LETTER PE; QQCM +30DA ; [.193D.0020.0011.30D8][.0000.013E.0002.309A] # KATAKANA LETTER PE; QQCM +307B ; [.193E.0020.000E.307B] # HIRAGANA LETTER HO +30DB ; [.193E.0020.0011.30DB] # KATAKANA LETTER HO +307C ; [.193E.0020.000E.307B][.0000.013D.0002.3099] # HIRAGANA LETTER BO; QQCM +30DC ; [.193E.0020.0011.30DB][.0000.013D.0002.3099] # KATAKANA LETTER BO; QQCM +307D ; [.193E.0020.000E.307B][.0000.013E.0002.309A] # HIRAGANA LETTER PO; QQCM +30DD ; [.193E.0020.0011.30DB][.0000.013E.0002.309A] # KATAKANA LETTER PO; QQCM +307E ; [.193F.0020.000E.307E] # HIRAGANA LETTER MA +30DE ; [.193F.0020.0011.30DE] # KATAKANA LETTER MA +307F ; [.1940.0020.000E.307F] # HIRAGANA LETTER MI +30DF ; [.1940.0020.0011.30DF] # KATAKANA LETTER MI +3080 ; [.1941.0020.000E.3080] # HIRAGANA LETTER MU +30E0 ; [.1941.0020.0011.30E0] # KATAKANA LETTER MU +3081 ; [.1942.0020.000E.3081] # HIRAGANA LETTER ME +30E1 ; [.1942.0020.0011.30E1] # KATAKANA LETTER ME +3082 ; [.1943.0020.000E.3082] # HIRAGANA LETTER MO +30E2 ; [.1943.0020.0011.30E2] # KATAKANA LETTER MO +3083 ; [.1944.0020.000D.3083] # HIRAGANA LETTER SMALL YA +3084 ; [.1944.0020.000E.3084] # HIRAGANA LETTER YA +30E3 ; [.1944.0020.000F.30E3] # KATAKANA LETTER SMALL YA +30E4 ; [.1944.0020.0011.30E4] # KATAKANA LETTER YA +3085 ; [.1945.0020.000D.3085] # HIRAGANA LETTER SMALL YU +3086 ; [.1945.0020.000E.3086] # HIRAGANA LETTER YU +30E5 ; [.1945.0020.000F.30E5] # KATAKANA LETTER SMALL YU +30E6 ; [.1945.0020.0011.30E6] # KATAKANA LETTER YU +3087 ; [.1946.0020.000D.3087] # HIRAGANA LETTER SMALL YO +3088 ; [.1946.0020.000E.3088] # HIRAGANA LETTER YO +30E7 ; [.1946.0020.000F.30E7] # KATAKANA LETTER SMALL YO +30E8 ; [.1946.0020.0011.30E8] # KATAKANA LETTER YO +3089 ; [.1947.0020.000E.3089] # HIRAGANA LETTER RA +30E9 ; [.1947.0020.0011.30E9] # KATAKANA LETTER RA +308A ; [.1948.0020.000E.308A] # HIRAGANA LETTER RI +30EA ; [.1948.0020.0011.30EA] # KATAKANA LETTER RI +308B ; [.1949.0020.000E.308B] # HIRAGANA LETTER RU +30EB ; [.1949.0020.0011.30EB] # KATAKANA LETTER RU +308C ; [.194A.0020.000E.308C] # HIRAGANA LETTER RE +30EC ; [.194A.0020.0011.30EC] # KATAKANA LETTER RE +308D ; [.194B.0020.000E.308D] # HIRAGANA LETTER RO +30ED ; [.194B.0020.0011.30ED] # KATAKANA LETTER RO +308E ; [.194C.0020.000D.308E] # HIRAGANA LETTER SMALL WA +308F ; [.194C.0020.000E.308F] # HIRAGANA LETTER WA +30EE ; [.194C.0020.000F.30EE] # KATAKANA LETTER SMALL WA +30EF ; [.194C.0020.0011.30EF] # KATAKANA LETTER WA +30F7 ; [.194C.0020.0011.30EF][.0000.013D.0002.3099] # KATAKANA LETTER VA; QQCM +3090 ; [.194D.0020.000E.3090] # HIRAGANA LETTER WI +30F0 ; [.194D.0020.0011.30F0] # KATAKANA LETTER WI +30F8 ; [.194D.0020.0011.30F0][.0000.013D.0002.3099] # KATAKANA LETTER VI; QQCM +3091 ; [.194E.0020.000E.3091] # HIRAGANA LETTER WE +30F1 ; [.194E.0020.0011.30F1] # KATAKANA LETTER WE +30F9 ; [.194E.0020.0011.30F1][.0000.013D.0002.3099] # KATAKANA LETTER VE; QQCM +3092 ; [.194F.0020.000E.3092] # HIRAGANA LETTER WO +30F2 ; [.194F.0020.0011.30F2] # KATAKANA LETTER WO +30FA ; [.194F.0020.0011.30F2][.0000.013D.0002.3099] # KATAKANA LETTER VO; QQCM +3093 ; [.1950.0020.000E.3093] # HIRAGANA LETTER N +30F3 ; [.1950.0020.0011.30F3] # KATAKANA LETTER N diff --git a/Master/tlpkg/tlperl/lib/Unicode/Normalize.pm b/Master/tlpkg/tlperl/lib/Unicode/Normalize.pm new file mode 100644 index 00000000000..ad5ff82a836 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Unicode/Normalize.pm @@ -0,0 +1,520 @@ +package Unicode::Normalize; + +BEGIN { + unless ("A" eq pack('U', 0x41)) { + die "Unicode::Normalize cannot stringify a Unicode code point\n"; + } +} + +use 5.006; +use strict; +use warnings; +use Carp; + +no warnings 'utf8'; + +our $VERSION = '1.03'; +our $PACKAGE = __PACKAGE__; + +require Exporter; +require DynaLoader; + +our @ISA = qw(Exporter DynaLoader); +our @EXPORT = qw( NFC NFD NFKC NFKD ); +our @EXPORT_OK = qw( + normalize decompose reorder compose + checkNFD checkNFKD checkNFC checkNFKC check + getCanon getCompat getComposite getCombinClass + isExclusion isSingleton isNonStDecomp isComp2nd isComp_Ex + isNFD_NO isNFC_NO isNFC_MAYBE isNFKD_NO isNFKC_NO isNFKC_MAYBE + FCD checkFCD FCC checkFCC composeContiguous + splitOnLastStarter +); +our %EXPORT_TAGS = ( + all => [ @EXPORT, @EXPORT_OK ], + normalize => [ @EXPORT, qw/normalize decompose reorder compose/ ], + check => [ qw/checkNFD checkNFKD checkNFC checkNFKC check/ ], + fast => [ qw/FCD checkFCD FCC checkFCC composeContiguous/ ], +); + +###### + +bootstrap Unicode::Normalize $VERSION; + +###### + +## +## utilites for tests +## + +sub pack_U { + return pack('U*', @_); +} + +sub unpack_U { + return unpack('U*', shift(@_).pack('U*')); +} + + +## +## normalization forms +## + +sub FCD ($) { + my $str = shift; + return checkFCD($str) ? $str : NFD($str); +} + +our %formNorm = ( + NFC => \&NFC, C => \&NFC, + NFD => \&NFD, D => \&NFD, + NFKC => \&NFKC, KC => \&NFKC, + NFKD => \&NFKD, KD => \&NFKD, + FCD => \&FCD, FCC => \&FCC, +); + +sub normalize($$) +{ + my $form = shift; + my $str = shift; + if (exists $formNorm{$form}) { + return $formNorm{$form}->($str); + } + croak($PACKAGE."::normalize: invalid form name: $form"); +} + + +## +## quick check +## + +our %formCheck = ( + NFC => \&checkNFC, C => \&checkNFC, + NFD => \&checkNFD, D => \&checkNFD, + NFKC => \&checkNFKC, KC => \&checkNFKC, + NFKD => \&checkNFKD, KD => \&checkNFKD, + FCD => \&checkFCD, FCC => \&checkFCC, +); + +sub check($$) +{ + my $form = shift; + my $str = shift; + if (exists $formCheck{$form}) { + return $formCheck{$form}->($str); + } + croak($PACKAGE."::check: invalid form name: $form"); +} + +1; +__END__ + +=head1 NAME + +Unicode::Normalize - Unicode Normalization Forms + +=head1 SYNOPSIS + +(1) using function names exported by default: + + use Unicode::Normalize; + + $NFD_string = NFD($string); # Normalization Form D + $NFC_string = NFC($string); # Normalization Form C + $NFKD_string = NFKD($string); # Normalization Form KD + $NFKC_string = NFKC($string); # Normalization Form KC + +(2) using function names exported on request: + + use Unicode::Normalize 'normalize'; + + $NFD_string = normalize('D', $string); # Normalization Form D + $NFC_string = normalize('C', $string); # Normalization Form C + $NFKD_string = normalize('KD', $string); # Normalization Form KD + $NFKC_string = normalize('KC', $string); # Normalization Form KC + +=head1 DESCRIPTION + +Parameters: + +C<$string> is used as a string under character semantics (see F<perlunicode>). + +C<$code_point> should be an unsigned integer representing a Unicode code point. + +Note: Between XSUB and pure Perl, there is an incompatibility +about the interpretation of C<$code_point> as a decimal number. +XSUB converts C<$code_point> to an unsigned integer, but pure Perl does not. +Do not use a floating point nor a negative sign in C<$code_point>. + +=head2 Normalization Forms + +=over 4 + +=item C<$NFD_string = NFD($string)> + +It returns the Normalization Form D (formed by canonical decomposition). + +=item C<$NFC_string = NFC($string)> + +It returns the Normalization Form C (formed by canonical decomposition +followed by canonical composition). + +=item C<$NFKD_string = NFKD($string)> + +It returns the Normalization Form KD (formed by compatibility decomposition). + +=item C<$NFKC_string = NFKC($string)> + +It returns the Normalization Form KC (formed by compatibility decomposition +followed by B<canonical> composition). + +=item C<$FCD_string = FCD($string)> + +If the given string is in FCD ("Fast C or D" form; cf. UTN #5), +it returns the string without modification; otherwise it returns an FCD string. + +Note: FCD is not always unique, then plural forms may be equivalent +each other. C<FCD()> will return one of these equivalent forms. + +=item C<$FCC_string = FCC($string)> + +It returns the FCC form ("Fast C Contiguous"; cf. UTN #5). + +Note: FCC is unique, as well as four normalization forms (NF*). + +=item C<$normalized_string = normalize($form_name, $string)> + +It returns the normalization form of C<$form_name>. + +As C<$form_name>, one of the following names must be given. + + 'C' or 'NFC' for Normalization Form C (UAX #15) + 'D' or 'NFD' for Normalization Form D (UAX #15) + 'KC' or 'NFKC' for Normalization Form KC (UAX #15) + 'KD' or 'NFKD' for Normalization Form KD (UAX #15) + + 'FCD' for "Fast C or D" Form (UTN #5) + 'FCC' for "Fast C Contiguous" (UTN #5) + +=back + +=head2 Decomposition and Composition + +=over 4 + +=item C<$decomposed_string = decompose($string [, $useCompatMapping])> + +It returns the concatenation of the decomposition of each character +in the string. + +If the second parameter (a boolean) is omitted or false, +the decomposition is canonical decomposition; +if the second parameter (a boolean) is true, +the decomposition is compatibility decomposition. + +The string returned is not always in NFD/NFKD. Reordering may be required. + + $NFD_string = reorder(decompose($string)); # eq. to NFD() + $NFKD_string = reorder(decompose($string, TRUE)); # eq. to NFKD() + +=item C<$reordered_string = reorder($string)> + +It returns the result of reordering the combining characters +according to Canonical Ordering Behavior. + +For example, when you have a list of NFD/NFKD strings, +you can get the concatenated NFD/NFKD string from them, by saying + + $concat_NFD = reorder(join '', @NFD_strings); + $concat_NFKD = reorder(join '', @NFKD_strings); + +=item C<$composed_string = compose($string)> + +It returns the result of canonical composition +without applying any decomposition. + +For example, when you have a NFD/NFKD string, +you can get its NFC/NFKC string, by saying + + $NFC_string = compose($NFD_string); + $NFKC_string = compose($NFKD_string); + +=back + +=head2 Quick Check + +(see Annex 8, UAX #15; and F<DerivedNormalizationProps.txt>) + +The following functions check whether the string is in that normalization form. + +The result returned will be one of the following: + + YES The string is in that normalization form. + NO The string is not in that normalization form. + MAYBE Dubious. Maybe yes, maybe no. + +=over 4 + +=item C<$result = checkNFD($string)> + +It returns true (C<1>) if C<YES>; false (C<empty string>) if C<NO>. + +=item C<$result = checkNFC($string)> + +It returns true (C<1>) if C<YES>; false (C<empty string>) if C<NO>; +C<undef> if C<MAYBE>. + +=item C<$result = checkNFKD($string)> + +It returns true (C<1>) if C<YES>; false (C<empty string>) if C<NO>. + +=item C<$result = checkNFKC($string)> + +It returns true (C<1>) if C<YES>; false (C<empty string>) if C<NO>; +C<undef> if C<MAYBE>. + +=item C<$result = checkFCD($string)> + +It returns true (C<1>) if C<YES>; false (C<empty string>) if C<NO>. + +=item C<$result = checkFCC($string)> + +It returns true (C<1>) if C<YES>; false (C<empty string>) if C<NO>; +C<undef> if C<MAYBE>. + +Note: If a string is not in FCD, it must not be in FCC. +So C<checkFCC($not_FCD_string)> should return C<NO>. + +=item C<$result = check($form_name, $string)> + +It returns true (C<1>) if C<YES>; false (C<empty string>) if C<NO>; +C<undef> if C<MAYBE>. + +As C<$form_name>, one of the following names must be given. + + 'C' or 'NFC' for Normalization Form C (UAX #15) + 'D' or 'NFD' for Normalization Form D (UAX #15) + 'KC' or 'NFKC' for Normalization Form KC (UAX #15) + 'KD' or 'NFKD' for Normalization Form KD (UAX #15) + + 'FCD' for "Fast C or D" Form (UTN #5) + 'FCC' for "Fast C Contiguous" (UTN #5) + +=back + +B<Note> + +In the cases of NFD, NFKD, and FCD, the answer must be +either C<YES> or C<NO>. The answer C<MAYBE> may be returned +in the cases of NFC, NFKC, and FCC. + +A C<MAYBE> string should contain at least one combining character +or the like. For example, C<COMBINING ACUTE ACCENT> has +the MAYBE_NFC/MAYBE_NFKC property. + +Both C<checkNFC("A\N{COMBINING ACUTE ACCENT}")> +and C<checkNFC("B\N{COMBINING ACUTE ACCENT}")> will return C<MAYBE>. +C<"A\N{COMBINING ACUTE ACCENT}"> is not in NFC +(its NFC is C<"\N{LATIN CAPITAL LETTER A WITH ACUTE}">), +while C<"B\N{COMBINING ACUTE ACCENT}"> is in NFC. + +If you want to check exactly, compare the string with its NFC/NFKC/FCC. + + if ($string eq NFC($string)) { + # $string is exactly normalized in NFC; + } else { + # $string is not normalized in NFC; + } + + if ($string eq NFKC($string)) { + # $string is exactly normalized in NFKC; + } else { + # $string is not normalized in NFKC; + } + +=head2 Character Data + +These functions are interface of character data used internally. +If you want only to get Unicode normalization forms, you don't need +call them yourself. + +=over 4 + +=item C<$canonical_decomposition = getCanon($code_point)> + +If the character is canonically decomposable (including Hangul Syllables), +it returns the (full) canonical decomposition as a string. +Otherwise it returns C<undef>. + +B<Note:> According to the Unicode standard, the canonical decomposition +of the character that is not canonically decomposable is same as +the character itself. + +=item C<$compatibility_decomposition = getCompat($code_point)> + +If the character is compatibility decomposable (including Hangul Syllables), +it returns the (full) compatibility decomposition as a string. +Otherwise it returns C<undef>. + +B<Note:> According to the Unicode standard, the compatibility decomposition +of the character that is not compatibility decomposable is same as +the character itself. + +=item C<$code_point_composite = getComposite($code_point_here, $code_point_next)> + +If two characters here and next (as code points) are composable +(including Hangul Jamo/Syllables and Composition Exclusions), +it returns the code point of the composite. + +If they are not composable, it returns C<undef>. + +=item C<$combining_class = getCombinClass($code_point)> + +It returns the combining class (as an integer) of the character. + +=item C<$may_be_composed_with_prev_char = isComp2nd($code_point)> + +It returns a boolean whether the character of the specified codepoint +may be composed with the previous one in a certain composition +(including Hangul Compositions, but excluding +Composition Exclusions and Non-Starter Decompositions). + +=item C<$is_exclusion = isExclusion($code_point)> + +It returns a boolean whether the code point is a composition exclusion. + +=item C<$is_singleton = isSingleton($code_point)> + +It returns a boolean whether the code point is a singleton + +=item C<$is_non_starter_decomposition = isNonStDecomp($code_point)> + +It returns a boolean whether the code point has Non-Starter Decomposition. + +=item C<$is_Full_Composition_Exclusion = isComp_Ex($code_point)> + +It returns a boolean of the derived property Comp_Ex +(Full_Composition_Exclusion). This property is generated from +Composition Exclusions + Singletons + Non-Starter Decompositions. + +=item C<$NFD_is_NO = isNFD_NO($code_point)> + +It returns a boolean of the derived property NFD_NO +(NFD_Quick_Check=No). + +=item C<$NFC_is_NO = isNFC_NO($code_point)> + +It returns a boolean of the derived property NFC_NO +(NFC_Quick_Check=No). + +=item C<$NFC_is_MAYBE = isNFC_MAYBE($code_point)> + +It returns a boolean of the derived property NFC_MAYBE +(NFC_Quick_Check=Maybe). + +=item C<$NFKD_is_NO = isNFKD_NO($code_point)> + +It returns a boolean of the derived property NFKD_NO +(NFKD_Quick_Check=No). + +=item C<$NFKC_is_NO = isNFKC_NO($code_point)> + +It returns a boolean of the derived property NFKC_NO +(NFKC_Quick_Check=No). + +=item C<$NFKC_is_MAYBE = isNFKC_MAYBE($code_point)> + +It returns a boolean of the derived property NFKC_MAYBE +(NFKC_Quick_Check=Maybe). + +=back + +=head1 EXPORT + +C<NFC>, C<NFD>, C<NFKC>, C<NFKD>: by default. + +C<normalize> and other some functions: on request. + +=head1 CAVEATS + +=over 4 + +=item Perl's version vs. Unicode version + +Since this module refers to perl core's Unicode database in the directory +F</lib/unicore> (or formerly F</lib/unicode>), the Unicode version of +normalization implemented by this module depends on your perl's version. + + perl's version implemented Unicode version + 5.6.1 3.0.1 + 5.7.2 3.1.0 + 5.7.3 3.1.1 (normalization is same as 3.1.0) + 5.8.0 3.2.0 + 5.8.1-5.8.3 4.0.0 + 5.8.4-5.8.6 4.0.1 (normalization is same as 4.0.0) + 5.8.7-5.8.8 4.1.0 + 5.10.0 5.0.0 + 5.8.9 5.1.0 + +=item Correction of decomposition mapping + +In older Unicode versions, a small number of characters (all of which are +CJK compatibility ideographs as far as they have been found) may have +an erroneous decomposition mapping (see F<NormalizationCorrections.txt>). +Anyhow, this module will neither refer to F<NormalizationCorrections.txt> +nor provide any specific version of normalization. Therefore this module +running on an older perl with an older Unicode database may use +the erroneous decomposition mapping blindly conforming to the Unicode database. + +=item Revised definition of canonical composition + +In Unicode 4.1.0, the definition D2 of canonical composition (which +affects NFC and NFKC) has been changed (see Public Review Issue #29 +and recent UAX #15). This module has used the newer definition +since the version 0.07 (Oct 31, 2001). +This module will not support the normalization according to the older +definition, even if the Unicode version implemented by perl is +lower than 4.1.0. + +=back + +=head1 AUTHOR + +SADAHIRO Tomoyuki <SADAHIRO@cpan.org> + +Copyright(C) 2001-2007, SADAHIRO Tomoyuki. Japan. All rights reserved. + +This module is free software; you can redistribute it +and/or modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +=over 4 + +=item http://www.unicode.org/reports/tr15/ + +Unicode Normalization Forms - UAX #15 + +=item http://www.unicode.org/Public/UNIDATA/CompositionExclusions.txt + +Composition Exclusion Table + +=item http://www.unicode.org/Public/UNIDATA/DerivedNormalizationProps.txt + +Derived Normalization Properties + +=item http://www.unicode.org/Public/UNIDATA/NormalizationCorrections.txt + +Normalization Corrections + +=item http://www.unicode.org/review/pr-29.html + +Public Review Issue #29: Normalization Issue + +=item http://www.unicode.org/notes/tn5/ + +Canonical Equivalence in Applications - UTN #5 + +=back + +=cut diff --git a/Master/tlpkg/tlperl/lib/Unicode/UCD.pm b/Master/tlpkg/tlperl/lib/Unicode/UCD.pm new file mode 100644 index 00000000000..c6ee8e05fe2 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Unicode/UCD.pm @@ -0,0 +1,1230 @@ +package Unicode::UCD; + +use strict; +use warnings; + +our $VERSION = '0.27'; + +use Storable qw(dclone); + +require Exporter; + +our @ISA = qw(Exporter); + +our @EXPORT_OK = qw(charinfo + charblock charscript + charblocks charscripts + charinrange + general_categories bidi_types + compexcl + casefold casespec + namedseq); + +use Carp; + +=head1 NAME + +Unicode::UCD - Unicode character database + +=head1 SYNOPSIS + + use Unicode::UCD 'charinfo'; + my $charinfo = charinfo($codepoint); + + use Unicode::UCD 'casefold'; + my $casefold = casefold(0xFB00); + + use Unicode::UCD 'casespec'; + my $casespec = casespec(0xFB00); + + use Unicode::UCD 'charblock'; + my $charblock = charblock($codepoint); + + use Unicode::UCD 'charscript'; + my $charscript = charscript($codepoint); + + use Unicode::UCD 'charblocks'; + my $charblocks = charblocks(); + + use Unicode::UCD 'charscripts'; + my $charscripts = charscripts(); + + use Unicode::UCD qw(charscript charinrange); + my $range = charscript($script); + print "looks like $script\n" if charinrange($range, $codepoint); + + use Unicode::UCD qw(general_categories bidi_types); + my $categories = general_categories(); + my $types = bidi_types(); + + use Unicode::UCD 'compexcl'; + my $compexcl = compexcl($codepoint); + + use Unicode::UCD 'namedseq'; + my $namedseq = namedseq($named_sequence_name); + + my $unicode_version = Unicode::UCD::UnicodeVersion(); + +=head1 DESCRIPTION + +The Unicode::UCD module offers a series of functions that +provide a simple interface to the Unicode +Character Database. + +=head2 code point argument + +Some of the functions are called with a I<code point argument>, which is either +a decimal or a hexadecimal scalar designating a Unicode code point, or C<U+> +followed by hexadecimals designating a Unicode code point. In other words, if +you want a code point to be interpreted as a hexadecimal number, you must +prefix it with either C<0x> or C<U+>, because a string like e.g. C<123> will be +interpreted as a decimal code point. Also note that Unicode is B<not> limited +to 16 bits (the number of Unicode code points is open-ended, in theory +unlimited): you may have more than 4 hexdigits. +=cut + +my $UNICODEFH; +my $BLOCKSFH; +my $SCRIPTSFH; +my $VERSIONFH; +my $COMPEXCLFH; +my $CASEFOLDFH; +my $CASESPECFH; +my $NAMEDSEQFH; + +sub openunicode { + my ($rfh, @path) = @_; + my $f; + unless (defined $$rfh) { + for my $d (@INC) { + use File::Spec; + $f = File::Spec->catfile($d, "unicore", @path); + last if open($$rfh, $f); + undef $f; + } + croak __PACKAGE__, ": failed to find ", + File::Spec->catfile(@path), " in @INC" + unless defined $f; + } + return $f; +} + +=head2 B<charinfo()> + + use Unicode::UCD 'charinfo'; + + my $charinfo = charinfo(0x41); + +This returns information about the input L</code point argument> +as a reference to a hash of fields as defined by the Unicode +standard. If the L</code point argument> is not assigned in the standard +(i.e., has the general category C<Cn> meaning C<Unassigned>) +or is a non-character (meaning it is guaranteed to never be assigned in +the standard), +B<undef> is returned. + +Fields that aren't applicable to the particular code point argument exist in the +returned hash, and are empty. + +The keys in the hash with the meanings of their values are: + +=over + +=item B<code> + +the input L</code point argument> expressed in hexadecimal, with leading zeros +added if necessary to make it contain at least four hexdigits + +=item B<name> + +name of I<code>, all IN UPPER CASE. +Some control-type code points do not have names. +This field will be empty for C<Surrogate> and C<Private Use> code points, +and for the others without a name, +it will contain a description enclosed in angle brackets, like +C<E<lt>controlE<gt>>. + + +=item B<category> + +The short name of the general category of I<code>. +This will match one of the keys in the hash returned by L</general_categories()>. + +=item B<combining> + +the combining class number for I<code> used in the Canonical Ordering Algorithm. +For Unicode 5.1, this is described in Section 3.11 C<Canonical Ordering Behavior> +available at +L<http://www.unicode.org/versions/Unicode5.1.0/> + +=item B<bidi> + +bidirectional type of I<code>. +This will match one of the keys in the hash returned by L</bidi_types()>. + +=item B<decomposition> + +is empty if I<code> has no decomposition; or is one or more codes +(separated by spaces) that taken in order represent a decomposition for +I<code>. Each has at least four hexdigits. +The codes may be preceded by a word enclosed in angle brackets then a space, +like C<E<lt>compatE<gt> >, giving the type of decomposition + +=item B<decimal> + +if I<code> is a decimal digit this is its integer numeric value + +=item B<digit> + +if I<code> represents a whole number, this is its integer numeric value + +=item B<numeric> + +if I<code> represents a whole or rational number, this is its numeric value. +Rational values are expressed as a string like C<1/4>. + +=item B<mirrored> + +C<Y> or C<N> designating if I<code> is mirrored in bidirectional text + +=item B<unicode10> + +name of I<code> in the Unicode 1.0 standard if one +existed for this code point and is different from the current name + +=item B<comment> + +ISO 10646 comment field. +It appears in parentheses in the ISO 10646 names list, +or contains an asterisk to indicate there is +a note for this code point in Annex P of that standard. + +=item B<upper> + +is empty if there is no single code point uppercase mapping for I<code>; +otherwise it is that mapping expressed as at least four hexdigits. +(L</casespec()> should be used in addition to B<charinfo()> +for case mappings when the calling program can cope with multiple code point +mappings.) + +=item B<lower> + +is empty if there is no single code point lowercase mapping for I<code>; +otherwise it is that mapping expressed as at least four hexdigits. +(L</casespec()> should be used in addition to B<charinfo()> +for case mappings when the calling program can cope with multiple code point +mappings.) + +=item B<title> + +is empty if there is no single code point titlecase mapping for I<code>; +otherwise it is that mapping expressed as at least four hexdigits. +(L</casespec()> should be used in addition to B<charinfo()> +for case mappings when the calling program can cope with multiple code point +mappings.) + +=item B<block> + +block I<code> belongs to (used in \p{In...}). +See L</Blocks versus Scripts>. + + +=item B<script> + +script I<code> belongs to. +See L</Blocks versus Scripts>. + +=back + +Note that you cannot do (de)composition and casing based solely on the +I<decomposition>, I<combining>, I<lower>, I<upper>, and I<title> fields; +you will need also the L</compexcl()>, and L</casespec()> functions. + +=cut + +# NB: This function is duplicated in charnames.pm +sub _getcode { + my $arg = shift; + + if ($arg =~ /^[1-9]\d*$/) { + return $arg; + } elsif ($arg =~ /^(?:[Uu]\+|0[xX])?([[:xdigit:]]+)$/) { + return hex($1); + } + + return; +} + +# Lingua::KO::Hangul::Util not part of the standard distribution +# but it will be used if available. + +eval { require Lingua::KO::Hangul::Util }; +my $hasHangulUtil = ! $@; +if ($hasHangulUtil) { + Lingua::KO::Hangul::Util->import(); +} + +sub hangul_decomp { # internal: called from charinfo + if ($hasHangulUtil) { + my @tmp = decomposeHangul(shift); + return sprintf("%04X %04X", @tmp) if @tmp == 2; + return sprintf("%04X %04X %04X", @tmp) if @tmp == 3; + } + return; +} + +sub hangul_charname { # internal: called from charinfo + return sprintf("HANGUL SYLLABLE-%04X", shift); +} + +sub han_charname { # internal: called from charinfo + return sprintf("CJK UNIFIED IDEOGRAPH-%04X", shift); +} + +# Overwritten by data in file +my %first_last = ( + 'CJK Ideograph Extension A' => [ 0x3400, 0x4DB5 ], + 'CJK Ideograph' => [ 0x4E00, 0x9FA5 ], + 'CJK Ideograph Extension B' => [ 0x20000, 0x2A6D6 ], +); + +get_charinfo_ranges(); + +sub get_charinfo_ranges { + my @blocks = keys %first_last; + + my $fh; + openunicode( \$fh, 'UnicodeData.txt' ); + if( defined $fh ){ + while( my $line = <$fh> ){ + next unless $line =~ /(?:First|Last)/; + if( grep{ $line =~ /[^;]+;<$_\s*,\s*(?:First|Last)>/ }@blocks ){ + my ($number,$block,$type); + ($number,$block) = split /;/, $line; + $block =~ s/<|>//g; + ($block,$type) = split /, /, $block; + my $index = $type eq 'First' ? 0 : 1; + $first_last{ $block }->[$index] = hex $number; + } + } + } +} + +my @CharinfoRanges = ( +# block name +# [ first, last, coderef to name, coderef to decompose ], +# CJK Ideographs Extension A + [ @{ $first_last{'CJK Ideograph Extension A'} }, \&han_charname, undef ], +# CJK Ideographs + [ @{ $first_last{'CJK Ideograph'} }, \&han_charname, undef ], +# Hangul Syllables + [ 0xAC00, 0xD7A3, $hasHangulUtil ? \&getHangulName : \&hangul_charname, \&hangul_decomp ], +# Non-Private Use High Surrogates + [ 0xD800, 0xDB7F, undef, undef ], +# Private Use High Surrogates + [ 0xDB80, 0xDBFF, undef, undef ], +# Low Surrogates + [ 0xDC00, 0xDFFF, undef, undef ], +# The Private Use Area + [ 0xE000, 0xF8FF, undef, undef ], +# CJK Ideographs Extension B + [ @{ $first_last{'CJK Ideograph Extension B'} }, \&han_charname, undef ], +# Plane 15 Private Use Area + [ 0xF0000, 0xFFFFD, undef, undef ], +# Plane 16 Private Use Area + [ 0x100000, 0x10FFFD, undef, undef ], +); + +sub charinfo { + my $arg = shift; + my $code = _getcode($arg); + croak __PACKAGE__, "::charinfo: unknown code '$arg'" + unless defined $code; + my $hexk = sprintf("%06X", $code); + my($rcode,$rname,$rdec); + foreach my $range (@CharinfoRanges){ + if ($range->[0] <= $code && $code <= $range->[1]) { + $rcode = $hexk; + $rcode =~ s/^0+//; + $rcode = sprintf("%04X", hex($rcode)); + $rname = $range->[2] ? $range->[2]->($code) : ''; + $rdec = $range->[3] ? $range->[3]->($code) : ''; + $hexk = sprintf("%06X", $range->[0]); # replace by the first + last; + } + } + openunicode(\$UNICODEFH, "UnicodeData.txt"); + if (defined $UNICODEFH) { + use Search::Dict 1.02; + if (look($UNICODEFH, "$hexk;", { xfrm => sub { $_[0] =~ /^([^;]+);(.+)/; sprintf "%06X;$2", hex($1) } } ) >= 0) { + my $line = <$UNICODEFH>; + return unless defined $line; + chomp $line; + my %prop; + @prop{qw( + code name category + combining bidi decomposition + decimal digit numeric + mirrored unicode10 comment + upper lower title + )} = split(/;/, $line, -1); + $hexk =~ s/^0+//; + $hexk = sprintf("%04X", hex($hexk)); + if ($prop{code} eq $hexk) { + $prop{block} = charblock($code); + $prop{script} = charscript($code); + if(defined $rname){ + $prop{code} = $rcode; + $prop{name} = $rname; + $prop{decomposition} = $rdec; + } + return \%prop; + } + } + } + return; +} + +sub _search { # Binary search in a [[lo,hi,prop],[...],...] table. + my ($table, $lo, $hi, $code) = @_; + + return if $lo > $hi; + + my $mid = int(($lo+$hi) / 2); + + if ($table->[$mid]->[0] < $code) { + if ($table->[$mid]->[1] >= $code) { + return $table->[$mid]->[2]; + } else { + _search($table, $mid + 1, $hi, $code); + } + } elsif ($table->[$mid]->[0] > $code) { + _search($table, $lo, $mid - 1, $code); + } else { + return $table->[$mid]->[2]; + } +} + +sub charinrange { + my ($range, $arg) = @_; + my $code = _getcode($arg); + croak __PACKAGE__, "::charinrange: unknown code '$arg'" + unless defined $code; + _search($range, 0, $#$range, $code); +} + +=head2 B<charblock()> + + use Unicode::UCD 'charblock'; + + my $charblock = charblock(0x41); + my $charblock = charblock(1234); + my $charblock = charblock(0x263a); + my $charblock = charblock("U+263a"); + + my $range = charblock('Armenian'); + +With a L</code point argument> charblock() returns the I<block> the code point +belongs to, e.g. C<Basic Latin>. +If the code point is unassigned, this returns the block it would belong to if +it were assigned (which it may in future versions of the Unicode Standard). + +See also L</Blocks versus Scripts>. + +If supplied with an argument that can't be a code point, charblock() tries +to do the opposite and interpret the argument as a code point block. The +return value is a I<range>: an anonymous list of lists that contain +I<start-of-range>, I<end-of-range> code point pairs. You can test whether +a code point is in a range using the L</charinrange()> function. If the +argument is not a known code point block, B<undef> is returned. + +=cut + +my @BLOCKS; +my %BLOCKS; + +sub _charblocks { + unless (@BLOCKS) { + if (openunicode(\$BLOCKSFH, "Blocks.txt")) { + local $_; + while (<$BLOCKSFH>) { + if (/^([0-9A-F]+)\.\.([0-9A-F]+);\s+(.+)/) { + my ($lo, $hi) = (hex($1), hex($2)); + my $subrange = [ $lo, $hi, $3 ]; + push @BLOCKS, $subrange; + push @{$BLOCKS{$3}}, $subrange; + } + } + close($BLOCKSFH); + } + } +} + +sub charblock { + my $arg = shift; + + _charblocks() unless @BLOCKS; + + my $code = _getcode($arg); + + if (defined $code) { + _search(\@BLOCKS, 0, $#BLOCKS, $code); + } else { + if (exists $BLOCKS{$arg}) { + return dclone $BLOCKS{$arg}; + } else { + return; + } + } +} + +=head2 B<charscript()> + + use Unicode::UCD 'charscript'; + + my $charscript = charscript(0x41); + my $charscript = charscript(1234); + my $charscript = charscript("U+263a"); + + my $range = charscript('Thai'); + +With a L</code point argument> charscript() returns the I<script> the +code point belongs to, e.g. C<Latin>, C<Greek>, C<Han>. +If the code point is unassigned, it returns B<undef> + +If supplied with an argument that can't be a code point, charscript() tries +to do the opposite and interpret the argument as a code point script. The +return value is a I<range>: an anonymous list of lists that contain +I<start-of-range>, I<end-of-range> code point pairs. You can test whether a +code point is in a range using the L</charinrange()> function. If the +argument is not a known code point script, B<undef> is returned. + +See also L</Blocks versus Scripts>. + +=cut + +my @SCRIPTS; +my %SCRIPTS; + +sub _charscripts { + unless (@SCRIPTS) { + if (openunicode(\$SCRIPTSFH, "Scripts.txt")) { + local $_; + while (<$SCRIPTSFH>) { + if (/^([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s+;\s+(\w+)/) { + my ($lo, $hi) = (hex($1), $2 ? hex($2) : hex($1)); + my $script = lc($3); + $script =~ s/\b(\w)/uc($1)/ge; + my $subrange = [ $lo, $hi, $script ]; + push @SCRIPTS, $subrange; + push @{$SCRIPTS{$script}}, $subrange; + } + } + close($SCRIPTSFH); + @SCRIPTS = sort { $a->[0] <=> $b->[0] } @SCRIPTS; + } + } +} + +sub charscript { + my $arg = shift; + + _charscripts() unless @SCRIPTS; + + my $code = _getcode($arg); + + if (defined $code) { + _search(\@SCRIPTS, 0, $#SCRIPTS, $code); + } else { + if (exists $SCRIPTS{$arg}) { + return dclone $SCRIPTS{$arg}; + } else { + return; + } + } +} + +=head2 B<charblocks()> + + use Unicode::UCD 'charblocks'; + + my $charblocks = charblocks(); + +charblocks() returns a reference to a hash with the known block names +as the keys, and the code point ranges (see L</charblock()>) as the values. + +See also L</Blocks versus Scripts>. + +=cut + +sub charblocks { + _charblocks() unless %BLOCKS; + return dclone \%BLOCKS; +} + +=head2 B<charscripts()> + + use Unicode::UCD 'charscripts'; + + my $charscripts = charscripts(); + +charscripts() returns a reference to a hash with the known script +names as the keys, and the code point ranges (see L</charscript()>) as +the values. + +See also L</Blocks versus Scripts>. + +=cut + +sub charscripts { + _charscripts() unless %SCRIPTS; + return dclone \%SCRIPTS; +} + +=head2 B<charinrange()> + +In addition to using the C<\p{In...}> and C<\P{In...}> constructs, you +can also test whether a code point is in the I<range> as returned by +L</charblock()> and L</charscript()> or as the values of the hash returned +by L</charblocks()> and L</charscripts()> by using charinrange(): + + use Unicode::UCD qw(charscript charinrange); + + $range = charscript('Hiragana'); + print "looks like hiragana\n" if charinrange($range, $codepoint); + +=cut + +my %GENERAL_CATEGORIES = + ( + 'L' => 'Letter', + 'LC' => 'CasedLetter', + 'Lu' => 'UppercaseLetter', + 'Ll' => 'LowercaseLetter', + 'Lt' => 'TitlecaseLetter', + 'Lm' => 'ModifierLetter', + 'Lo' => 'OtherLetter', + 'M' => 'Mark', + 'Mn' => 'NonspacingMark', + 'Mc' => 'SpacingMark', + 'Me' => 'EnclosingMark', + 'N' => 'Number', + 'Nd' => 'DecimalNumber', + 'Nl' => 'LetterNumber', + 'No' => 'OtherNumber', + 'P' => 'Punctuation', + 'Pc' => 'ConnectorPunctuation', + 'Pd' => 'DashPunctuation', + 'Ps' => 'OpenPunctuation', + 'Pe' => 'ClosePunctuation', + 'Pi' => 'InitialPunctuation', + 'Pf' => 'FinalPunctuation', + 'Po' => 'OtherPunctuation', + 'S' => 'Symbol', + 'Sm' => 'MathSymbol', + 'Sc' => 'CurrencySymbol', + 'Sk' => 'ModifierSymbol', + 'So' => 'OtherSymbol', + 'Z' => 'Separator', + 'Zs' => 'SpaceSeparator', + 'Zl' => 'LineSeparator', + 'Zp' => 'ParagraphSeparator', + 'C' => 'Other', + 'Cc' => 'Control', + 'Cf' => 'Format', + 'Cs' => 'Surrogate', + 'Co' => 'PrivateUse', + 'Cn' => 'Unassigned', + ); + +sub general_categories { + return dclone \%GENERAL_CATEGORIES; +} + +=head2 B<general_categories()> + + use Unicode::UCD 'general_categories'; + + my $categories = general_categories(); + +This returns a reference to a hash which has short +general category names (such as C<Lu>, C<Nd>, C<Zs>, C<S>) as keys and long +names (such as C<UppercaseLetter>, C<DecimalNumber>, C<SpaceSeparator>, +C<Symbol>) as values. The hash is reversible in case you need to go +from the long names to the short names. The general category is the +one returned from +L</charinfo()> under the C<category> key. + +=cut + +my %BIDI_TYPES = + ( + 'L' => 'Left-to-Right', + 'LRE' => 'Left-to-Right Embedding', + 'LRO' => 'Left-to-Right Override', + 'R' => 'Right-to-Left', + 'AL' => 'Right-to-Left Arabic', + 'RLE' => 'Right-to-Left Embedding', + 'RLO' => 'Right-to-Left Override', + 'PDF' => 'Pop Directional Format', + 'EN' => 'European Number', + 'ES' => 'European Number Separator', + 'ET' => 'European Number Terminator', + 'AN' => 'Arabic Number', + 'CS' => 'Common Number Separator', + 'NSM' => 'Non-Spacing Mark', + 'BN' => 'Boundary Neutral', + 'B' => 'Paragraph Separator', + 'S' => 'Segment Separator', + 'WS' => 'Whitespace', + 'ON' => 'Other Neutrals', + ); + +=head2 B<bidi_types()> + + use Unicode::UCD 'bidi_types'; + + my $categories = bidi_types(); + +This returns a reference to a hash which has the short +bidi (bidirectional) type names (such as C<L>, C<R>) as keys and long +names (such as C<Left-to-Right>, C<Right-to-Left>) as values. The +hash is reversible in case you need to go from the long names to the +short names. The bidi type is the one returned from +L</charinfo()> +under the C<bidi> key. For the exact meaning of the various bidi classes +the Unicode TR9 is recommended reading: +L<http://www.unicode.org/reports/tr9/> +(as of Unicode 5.0.0) + +=cut + +sub bidi_types { + return dclone \%BIDI_TYPES; +} + +=head2 B<compexcl()> + + use Unicode::UCD 'compexcl'; + + my $compexcl = compexcl(0x09dc); + +This returns B<true> if the +L</code point argument> should not be produced by composition normalization, +B<AND> if that fact is not otherwise determinable from the Unicode data base. +It currently does not return B<true> if the code point has a decomposition +consisting of another single code point, nor if its decomposition starts +with a code point whose combining class is non-zero. Code points that meet +either of these conditions should also not be produced by composition +normalization. + +It returns B<false> otherwise. + +=cut + +my %COMPEXCL; + +sub _compexcl { + unless (%COMPEXCL) { + if (openunicode(\$COMPEXCLFH, "CompositionExclusions.txt")) { + local $_; + while (<$COMPEXCLFH>) { + if (/^([0-9A-F]+)\s+\#\s+/) { + my $code = hex($1); + $COMPEXCL{$code} = undef; + } + } + close($COMPEXCLFH); + } + } +} + +sub compexcl { + my $arg = shift; + my $code = _getcode($arg); + croak __PACKAGE__, "::compexcl: unknown code '$arg'" + unless defined $code; + + _compexcl() unless %COMPEXCL; + + return exists $COMPEXCL{$code}; +} + +=head2 B<casefold()> + + use Unicode::UCD 'casefold'; + + my $casefold = casefold(0xDF); + if (defined $casefold) { + my @full_fold_hex = split / /, $casefold->{'full'}; + my $full_fold_string = + join "", map {chr(hex($_))} @full_fold_hex; + my @turkic_fold_hex = + split / /, ($casefold->{'turkic'} ne "") + ? $casefold->{'turkic'} + : $casefold->{'full'}; + my $turkic_fold_string = + join "", map {chr(hex($_))} @turkic_fold_hex; + } + if (defined $casefold && $casefold->{'simple'} ne "") { + my $simple_fold_hex = $casefold->{'simple'}; + my $simple_fold_string = chr(hex($simple_fold_hex)); + } + +This returns the (almost) locale-independent case folding of the +character specified by the L</code point argument>. + +If there is no case folding for that code point, B<undef> is returned. + +If there is a case folding for that code point, a reference to a hash +with the following fields is returned: + +=over + +=item B<code> + +the input L</code point argument> expressed in hexadecimal, with leading zeros +added if necessary to make it contain at least four hexdigits + +=item B<full> + +one or more codes (separated by spaces) that taken in order give the +code points for the case folding for I<code>. +Each has at least four hexdigits. + +=item B<simple> + +is empty, or is exactly one code with at least four hexdigits which can be used +as an alternative case folding when the calling program cannot cope with the +fold being a sequence of multiple code points. If I<full> is just one code +point, then I<simple> equals I<full>. If there is no single code point folding +defined for I<code>, then I<simple> is the empty string. Otherwise, it is an +inferior, but still better-than-nothing alternative folding to I<full>. + +=item B<mapping> + +is the same as I<simple> if I<simple> is not empty, and it is the same as I<full> +otherwise. It can be considered to be the simplest possible folding for +I<code>. It is defined primarily for backwards compatibility. + +=item B<status> + +is C<C> (for C<common>) if the best possible fold is a single code point +(I<simple> equals I<full> equals I<mapping>). It is C<S> if there are distinct +folds, I<simple> and I<full> (I<mapping> equals I<simple>). And it is C<F> if +there only a I<full> fold (I<mapping> equals I<full>; I<simple> is empty). Note +that this +describes the contents of I<mapping>. It is defined primarily for backwards +compatibility. + +On versions 3.1 and earlier of Unicode, I<status> can also be +C<I> which is the same as C<C> but is a special case for dotted uppercase I and +dotless lowercase i: + +=over + +=item B<*> + +If you use this C<I> mapping, the result is case-insensitive, +but dotless and dotted I's are not distinguished + +=item B<*> + +If you exclude this C<I> mapping, the result is not fully case-insensitive, but +dotless and dotted I's are distinguished + +=back + +=item B<turkic> + +contains any special folding for Turkic languages. For versions of Unicode +starting with 3.2, this field is empty unless I<code> has a different folding +in Turkic languages, in which case it is one or more codes (separated by +spaces) that taken in order give the code points for the case folding for +I<code> in those languages. +Each code has at least four hexdigits. +Note that this folding does not maintain canonical equivalence without +additional processing. + +For versions of Unicode 3.1 and earlier, this field is empty unless there is a +special folding for Turkic languages, in which case I<status> is C<I>, and +I<mapping>, I<full>, I<simple>, and I<turkic> are all equal. + +=back + +Programs that want complete generality and the best folding results should use +the folding contained in the I<full> field. But note that the fold for some +code points will be a sequence of multiple code points. + +Programs that can't cope with the fold mapping being multiple code points can +use the folding contained in the I<simple> field, with the loss of some +generality. In Unicode 5.1, about 7% of the defined foldings have no single +code point folding. + +The I<mapping> and I<status> fields are provided for backwards compatibility for +existing programs. They contain the same values as in previous versions of +this function. + +Locale is not completely independent. The I<turkic> field contains results to +use when the locale is a Turkic language. + +For more information about case mappings see +L<http://www.unicode.org/unicode/reports/tr21> + +=cut + +my %CASEFOLD; + +sub _casefold { + unless (%CASEFOLD) { + if (openunicode(\$CASEFOLDFH, "CaseFolding.txt")) { + local $_; + while (<$CASEFOLDFH>) { + if (/^([0-9A-F]+); ([CFIST]); ([0-9A-F]+(?: [0-9A-F]+)*);/) { + my $code = hex($1); + $CASEFOLD{$code}{'code'} = $1; + $CASEFOLD{$code}{'turkic'} = "" unless + defined $CASEFOLD{$code}{'turkic'}; + if ($2 eq 'C' || $2 eq 'I') { # 'I' is only on 3.1 and + # earlier Unicodes + # Both entries there (I + # only checked 3.1) are + # the same as C, and + # there are no other + # entries for those + # codepoints, so treat + # as if C, but override + # the turkic one for + # 'I'. + $CASEFOLD{$code}{'status'} = $2; + $CASEFOLD{$code}{'full'} = $CASEFOLD{$code}{'simple'} = + $CASEFOLD{$code}{'mapping'} = $3; + $CASEFOLD{$code}{'turkic'} = $3 if $2 eq 'I'; + } elsif ($2 eq 'F') { + $CASEFOLD{$code}{'full'} = $3; + unless (defined $CASEFOLD{$code}{'simple'}) { + $CASEFOLD{$code}{'simple'} = ""; + $CASEFOLD{$code}{'mapping'} = $3; + $CASEFOLD{$code}{'status'} = $2; + } + } elsif ($2 eq 'S') { + + + # There can't be a simple without a full, and simple + # overrides all but full + + $CASEFOLD{$code}{'simple'} = $3; + $CASEFOLD{$code}{'mapping'} = $3; + $CASEFOLD{$code}{'status'} = $2; + } elsif ($2 eq 'T') { + $CASEFOLD{$code}{'turkic'} = $3; + } # else can't happen because only [CIFST] are possible + } + } + close($CASEFOLDFH); + } + } +} + +sub casefold { + my $arg = shift; + my $code = _getcode($arg); + croak __PACKAGE__, "::casefold: unknown code '$arg'" + unless defined $code; + + _casefold() unless %CASEFOLD; + + return $CASEFOLD{$code}; +} + +=head2 B<casespec()> + + use Unicode::UCD 'casespec'; + + my $casespec = casespec(0xFB00); + +This returns the potentially locale-dependent case mappings of the L</code point +argument>. The mappings may be longer than a single code point (which the basic +Unicode case mappings as returned by L</charinfo()> never are). + +If there are no case mappings for the L</code point argument>, or if all three +possible mappings (I<lower>, I<title> and I<upper>) result in single code +points and are locale independent and unconditional, B<undef> is returned +(which means that the case mappings, if any, for the code point are those +returned by L</charinfo()>). + +Otherwise, a reference to a hash giving the mappings (or a reference to a hash +of such hashes, explained below) is returned with the following keys and their +meanings: + +The keys in the bottom layer hash with the meanings of their values are: + +=over + +=item B<code> + +the input L</code point argument> expressed in hexadecimal, with leading zeros +added if necessary to make it contain at least four hexdigits + +=item B<lower> + +one or more codes (separated by spaces) that taken in order give the +code points for the lower case of I<code>. +Each has at least four hexdigits. + +=item B<title> + +one or more codes (separated by spaces) that taken in order give the +code points for the title case of I<code>. +Each has at least four hexdigits. + +=item B<lower> + +one or more codes (separated by spaces) that taken in order give the +code points for the upper case of I<code>. +Each has at least four hexdigits. + +=item B<condition> + +the conditions for the mappings to be valid. +If B<undef>, the mappings are always valid. +When defined, this field is a list of conditions, +all of which must be true for the mappings to be valid. +The list consists of one or more +I<locales> (see below) +and/or I<contexts> (explained in the next paragraph), +separated by spaces. +(Other than as used to separate elements, spaces are to be ignored.) +Case distinctions in the condition list are not significant. +Conditions preceded by "NON_" represent the negation of the condition. + +A I<context> is one of those defined in the Unicode standard. +For Unicode 5.1, they are defined in Section 3.13 C<Default Case Operations> +available at +L<http://www.unicode.org/versions/Unicode5.1.0/>. +These are for context-sensitive casing. + +=back + +The hash described above is returned for locale-independent casing, where +at least one of the mappings has length longer than one. If B<undef> is +returned, the code point may have mappings, but if so, all are length one, +and are returned by L</charinfo()>. +Note that when this function does return a value, it will be for the complete +set of mappings for a code point, even those whose length is one. + +If there are additional casing rules that apply only in certain locales, +an additional key for each will be defined in the returned hash. Each such key +will be its locale name, defined as a 2-letter ISO 3166 country code, possibly +followed by a "_" and a 2-letter ISO language code (possibly followed by a "_" +and a variant code). You can find the lists of all possible locales, see +L<Locale::Country> and L<Locale::Language>. +(In Unicode 5.1, the only locales returned by this function +are C<lt>, C<tr>, and C<az>.) + +Each locale key is a reference to a hash that has the form above, and gives +the casing rules for that particular locale, which take precedence over the +locale-independent ones when in that locale. + +If the only casing for a code point is locale-dependent, then the returned +hash will not have any of the base keys, like C<code>, C<upper>, etc., but +will contain only locale keys. + +For more information about case mappings see +L<http://www.unicode.org/unicode/reports/tr21/> + +=cut + +my %CASESPEC; + +sub _casespec { + unless (%CASESPEC) { + if (openunicode(\$CASESPECFH, "SpecialCasing.txt")) { + local $_; + while (<$CASESPECFH>) { + if (/^([0-9A-F]+); ([0-9A-F]+(?: [0-9A-F]+)*)?; ([0-9A-F]+(?: [0-9A-F]+)*)?; ([0-9A-F]+(?: [0-9A-F]+)*)?; (\w+(?: \w+)*)?/) { + my ($hexcode, $lower, $title, $upper, $condition) = + ($1, $2, $3, $4, $5); + my $code = hex($hexcode); + if (exists $CASESPEC{$code}) { + if (exists $CASESPEC{$code}->{code}) { + my ($oldlower, + $oldtitle, + $oldupper, + $oldcondition) = + @{$CASESPEC{$code}}{qw(lower + title + upper + condition)}; + if (defined $oldcondition) { + my ($oldlocale) = + ($oldcondition =~ /^([a-z][a-z](?:_\S+)?)/); + delete $CASESPEC{$code}; + $CASESPEC{$code}->{$oldlocale} = + { code => $hexcode, + lower => $oldlower, + title => $oldtitle, + upper => $oldupper, + condition => $oldcondition }; + } + } + my ($locale) = + ($condition =~ /^([a-z][a-z](?:_\S+)?)/); + $CASESPEC{$code}->{$locale} = + { code => $hexcode, + lower => $lower, + title => $title, + upper => $upper, + condition => $condition }; + } else { + $CASESPEC{$code} = + { code => $hexcode, + lower => $lower, + title => $title, + upper => $upper, + condition => $condition }; + } + } + } + close($CASESPECFH); + } + } +} + +sub casespec { + my $arg = shift; + my $code = _getcode($arg); + croak __PACKAGE__, "::casespec: unknown code '$arg'" + unless defined $code; + + _casespec() unless %CASESPEC; + + return ref $CASESPEC{$code} ? dclone $CASESPEC{$code} : $CASESPEC{$code}; +} + +=head2 B<namedseq()> + + use Unicode::UCD 'namedseq'; + + my $namedseq = namedseq("KATAKANA LETTER AINU P"); + my @namedseq = namedseq("KATAKANA LETTER AINU P"); + my %namedseq = namedseq(); + +If used with a single argument in a scalar context, returns the string +consisting of the code points of the named sequence, or B<undef> if no +named sequence by that name exists. If used with a single argument in +a list context, it returns the list of the ordinals of the code points. If used +with no +arguments in a list context, returns a hash with the names of the +named sequences as the keys and the named sequences as strings as +the values. Otherwise, it returns B<undef> or an empty list depending +on the context. + +This function only operates on officially approved (not provisional) named +sequences. + +=cut + +my %NAMEDSEQ; + +sub _namedseq { + unless (%NAMEDSEQ) { + if (openunicode(\$NAMEDSEQFH, "NamedSequences.txt")) { + local $_; + while (<$NAMEDSEQFH>) { + if (/^(.+)\s*;\s*([0-9A-F]+(?: [0-9A-F]+)*)$/) { + my ($n, $s) = ($1, $2); + my @s = map { chr(hex($_)) } split(' ', $s); + $NAMEDSEQ{$n} = join("", @s); + } + } + close($NAMEDSEQFH); + } + } +} + +sub namedseq { + _namedseq() unless %NAMEDSEQ; + my $wantarray = wantarray(); + if (defined $wantarray) { + if ($wantarray) { + if (@_ == 0) { + return %NAMEDSEQ; + } elsif (@_ == 1) { + my $s = $NAMEDSEQ{ $_[0] }; + return defined $s ? map { ord($_) } split('', $s) : (); + } + } elsif (@_ == 1) { + return $NAMEDSEQ{ $_[0] }; + } + } + return; +} + +=head2 Unicode::UCD::UnicodeVersion + +This returns the version of the Unicode Character Database, in other words, the +version of the Unicode standard the database implements. The version is a +string of numbers delimited by dots (C<'.'>). + +=cut + +my $UNICODEVERSION; + +sub UnicodeVersion { + unless (defined $UNICODEVERSION) { + openunicode(\$VERSIONFH, "version"); + chomp($UNICODEVERSION = <$VERSIONFH>); + close($VERSIONFH); + croak __PACKAGE__, "::VERSION: strange version '$UNICODEVERSION'" + unless $UNICODEVERSION =~ /^\d+(?:\.\d+)+$/; + } + return $UNICODEVERSION; +} + +=head2 B<Blocks versus Scripts> + +The difference between a block and a script is that scripts are closer +to the linguistic notion of a set of code points required to present +languages, while block is more of an artifact of the Unicode code point +numbering and separation into blocks of (mostly) 256 code points. + +For example the Latin B<script> is spread over several B<blocks>, such +as C<Basic Latin>, C<Latin 1 Supplement>, C<Latin Extended-A>, and +C<Latin Extended-B>. On the other hand, the Latin script does not +contain all the characters of the C<Basic Latin> block (also known as +ASCII): it includes only the letters, and not, for example, the digits +or the punctuation. + +For blocks see L<http://www.unicode.org/Public/UNIDATA/Blocks.txt> + +For scripts see UTR #24: L<http://www.unicode.org/unicode/reports/tr24/> + +=head2 B<Matching Scripts and Blocks> + +Scripts are matched with the regular-expression construct +C<\p{...}> (e.g. C<\p{Tibetan}> matches characters of the Tibetan script), +while C<\p{In...}> is used for blocks (e.g. C<\p{InTibetan}> matches +any of the 256 code points in the Tibetan block). + + +=head2 Implementation Note + +The first use of charinfo() opens a read-only filehandle to the Unicode +Character Database (the database is included in the Perl distribution). +The filehandle is then kept open for further queries. In other words, +if you are wondering where one of your filehandles went, that's where. + +=head1 BUGS + +Does not yet support EBCDIC platforms. + +L</compexcl()> should give a complete list of excluded code points. + +=head1 AUTHOR + +Jarkko Hietaniemi + +=cut + +1; |