summaryrefslogtreecommitdiff
path: root/Master/tlpkg/dev
diff options
context:
space:
mode:
authorNorbert Preining <preining@logic.at>2012-01-12 05:03:20 +0000
committerNorbert Preining <preining@logic.at>2012-01-12 05:03:20 +0000
commitbcfe3e9f5280b8f27815952cd799ab3190cf8471 (patch)
tree0f3742d67fb523a80e0513a903e5cb35cf82c5c3 /Master/tlpkg/dev
parentd18f5545bff4fd3d6315a4752fad5f6c34fd0266 (diff)
Since the current multi updmap integration patches are develop independetly
of the multi-source, we keep a quilt repository that makes it easier to keep things in sync git-svn-id: svn://tug.org/texlive/trunk@25079 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/tlpkg/dev')
-rw-r--r--Master/tlpkg/dev/quilt-patches/dev.multi-source-support-v2.patch2167
-rw-r--r--Master/tlpkg/dev/quilt-patches/dev.multi-updmap4209
-rw-r--r--Master/tlpkg/dev/quilt-patches/series2
3 files changed, 6378 insertions, 0 deletions
diff --git a/Master/tlpkg/dev/quilt-patches/dev.multi-source-support-v2.patch b/Master/tlpkg/dev/quilt-patches/dev.multi-source-support-v2.patch
new file mode 100644
index 00000000000..4acee6a8263
--- /dev/null
+++ b/Master/tlpkg/dev/quilt-patches/dev.multi-source-support-v2.patch
@@ -0,0 +1,2167 @@
+---
+ texmf/scripts/texlive/tlmgr.pl | 897 ++++++++++++++++++++++++++++++++++-------
+ tlpkg/TeXLive/TLPDB.pm | 669 +++++++++++++++++++++++++++---
+ 2 files changed, 1369 insertions(+), 197 deletions(-)
+
+Index: tlpkg/TeXLive/TLPDB.pm
+===================================================================
+--- tlpkg/TeXLive/TLPDB.pm.orig 2011-07-02 15:31:51.000000000 +0900
++++ tlpkg/TeXLive/TLPDB.pm 2012-01-12 12:51:17.000000000 +0900
+@@ -70,20 +70,31 @@
+ $tlpdb->settings;
+ $tlpdb->setting($key, [$value]);
+ $tlpdb->sizes_of_packages($opt_src, $opt_doc [, @packs ]);
+- $tlpdb->install_package($pkg, $dest_tlpdb, $nopostinstall, $fallbacktlpdb);
++ $tlpdb->install_package($pkg, $dest_tlpdb);
+ $tlpdb->remove_package($pkg, %options);
+
+-
+ TeXLive::TLPDB->listdir([$dir]);
+ $tlpdb->generate_listfiles([$destdir]);
+
++ $tlpdb->make_virtual;
++ $tlpdb->is_virtual;
++ $tlpdb->virtual_add_tlpdb($tlpdb, $tag);
++ $tlpdb->virtual_remove_tlpdb($tag);
++ $tlpdb->virtual_get_package($pkg, $tag);
++ $tlpdb->candidates($pkg);
++ $tlpdb->virtual_candidate($pkg);
++ $tlpdb->virtual_pinning( [@tlpkpins ] );
++
+ =head1 DESCRIPTION
+
+ =cut
+
+-use TeXLive::TLConfig;
++use TeXLive::TLConfig qw($CategoriesRegexp $DefaultCategory $InfraLocation
++ $DatabaseName $MetaCategoriesRegexp $Archive
++ %TLPDBOptions %TLPDBSettings
++ $RelocPrefix $RelocTree);
+ use TeXLive::TLUtils qw(dirname mkdirhier member win32 info log debug ddebug
+- tlwarn basename download_file merge_into);
++ tlwarn basename download_file merge_into tldie);
+ use TeXLive::TLPOBJ;
+ use TeXLive::TLWinGoo;
+
+@@ -161,6 +172,10 @@
+
+ sub add_tlpobj {
+ my ($self,$tlp) = @_;
++ if ($self->is_virtual) {
++ tlwarn("cannot add tlpobj to a virtual tlpdb\n");
++ return 0;
++ }
+ $self->{'tlps'}{$tlp->name} = $tlp;
+ }
+
+@@ -209,6 +224,10 @@
+
+ sub remove_tlpobj {
+ my ($self,$pkg) = @_;
++ if ($self->is_virtual) {
++ tlwarn("cannot remove tlpobj from a virtual tlpdb\n");
++ return 0;
++ }
+ if (defined($self->{'tlps'}{$pkg})) {
+ delete $self->{'tlps'}{$pkg};
+ } else {
+@@ -229,6 +248,10 @@
+
+ sub from_file {
+ my ($self, $path) = @_;
++ if ($self->is_virtual) {
++ tlwarn("cannot initialize from file a virtual tlpdb\n");
++ return 0;
++ }
+ if (@_ != 2) {
+ die "$0: from_file needs filename for initialization";
+ }
+@@ -362,6 +385,10 @@
+
+ sub writeout {
+ my $self = shift;
++ if ($self->is_virtual) {
++ tlwarn("cannot write out a virtual tlpdb\n");
++ return 0;
++ }
+ my $fd = (@_ ? $_[0] : STDOUT);
+ foreach (sort keys %{$self->{'tlps'}}) {
+ ddebug("writeout: tlpname=$_ ", $self->{'tlps'}{$_}->name, "\n");
+@@ -381,6 +408,10 @@
+
+ sub save {
+ my $self = shift;
++ if ($self->is_virtual) {
++ tlwarn("cannot save a virtual tlpdb\n");
++ return 0;
++ }
+ my $path = $self->location;
+ mkdirhier(dirname($path));
+ my $tmppath = "$path.tmp";
+@@ -402,6 +433,9 @@
+
+ sub media {
+ my $self = shift ;
++ if ($self->is_virtual) {
++ return "virtual";
++ }
+ return $self->{'media'};
+ }
+
+@@ -417,6 +451,18 @@
+
+ sub available_architectures {
+ my $self = shift;
++ my @archs;
++ if ($self->is_virtual) {
++ for my $k (keys %{$self->{'tlpdbs'}}) {
++ push @archs, $self->{'tlpdbs'}{$k}->available_architectures;
++ }
++ } else {
++ return $self->_available_architectures;
++ }
++}
++
++sub _available_architectures {
++ my $self = shift;
+ my @archs = $self->setting("available_architectures");
+ if (! @archs) {
+ # fall back to the old method checking tex\.*
+@@ -444,6 +490,10 @@
+
+ sub add_tlpcontainer {
+ my ($self, $package, $ziplocation, $archrefs, $dest) = @_;
++ if ($self->is_virtual) {
++ tlwarn("cannot add tlp container to a virtual tlpdb\n");
++ return 0;
++ }
+ my @archs;
+ if (defined($archrefs)) {
+ @archs = @$archrefs;
+@@ -508,6 +558,29 @@
+ =cut
+
+ sub get_package {
++ my ($self,$pkg,$tag) = @_;
++ if ($self->is_virtual) {
++ if (defined($tag)) {
++ if (defined($self->{'packages'}{$pkg}{'tags'}{$tag})) {
++ return $self->{'packages'}{$pkg}{'tags'}{$tag}{'tlp'};
++ } else {
++ debug("TLPDB::get_package: package $pkg not found in repository $tag\n");
++ return;
++ }
++ } else {
++ $tag = $self->{'packages'}{$pkg}{'target'};
++ if (defined($tag)) {
++ return $self->{'packages'}{$pkg}{'tags'}{$tag}{'tlp'};
++ } else {
++ return;
++ }
++ }
++ } else {
++ return $self->_get_package($pkg);
++ }
++}
++
++sub _get_package {
+ my ($self,$pkg) = @_;
+ if (defined($self->{'tlps'}{$pkg})) {
+ my $ret = $self->{'tlps'}{$pkg};
+@@ -519,6 +592,35 @@
+
+ =pod
+
++=item C<< $tlpdb->media_of_package($pkg [, $tag]);
++
++returns the media type of the package. In the virtual case a tag can
++be given and the media of that repository is used, otherwise the
++media of the virtual candidate is given.
++
++=cut
++
++sub media_of_package {
++ my ($self, $pkg, $tag) = @_;
++ if ($self->is_virtual) {
++ if (defined($tag)) {
++ if (defined($self->{'tlpdbs'}{$tag})) {
++ return $self->{'tlpdbs'}{$tag}->media;
++ } else {
++ tlwarn ("tag $tag is not known.\n");
++ return;
++ }
++ } else {
++ my (undef,undef,undef,$maxtlpdb) = $self->virtual_candidate($pkg);
++ return $maxtlpdb->media;
++ }
++ } else {
++ return $self->media;
++ }
++}
++
++=pod
++
+ =item C<< $tlpdb->list_packages >>
+
+ The C<list_packages> function returns the list of all included packages.
+@@ -527,6 +629,34 @@
+
+ sub list_packages {
+ my $self = shift;
++ my $arg = shift;
++ my $showall = 0;
++ if (defined($arg) && ($arg eq "-all")) {
++ $showall = 1;
++ }
++ if ($self->is_virtual) {
++ if ($showall) {
++ return (sort keys %{$self->{'packages'}});
++ }
++ # we have to be careful here: If a package
++ # is only present in a subsidiary repository
++ # and the package is *not* explicitely
++ # pinned to it, it will not be installable.
++ # This is what we want. But in this case
++ # we don't want it to be listed by default.
++ #
++ my @pps;
++ for my $p (keys %{$self->{'packages'}}) {
++ push @pps, $p if (defined($self->{'packages'}{$p}{'target'}));
++ }
++ return (sort @pps);
++ } else {
++ return $self->_list_packages;
++ }
++}
++
++sub _list_packages {
++ my $self = shift;
+ return (sort keys %{$self->{'tlps'}});
+ }
+
+@@ -544,6 +674,11 @@
+ The next (or first) argument is the target TLPDB, then a list of
+ packages.
+
++In the virtual case,
++if a package name is tagged with C<@repository-tag> then all the
++dependencies will still be expanded between all included databases.
++Only in case of .ARCH dependencies the repository-tag is sticky.
++
+ We return the closure of the package list with respect to the depends
+ operator. (Sorry, that was for mathematicians.)
+
+@@ -567,7 +702,8 @@
+ my %install = ();
+ my @archs = $totlpdb->available_architectures;
+ for my $p (@_) {
+- $install{$p} = 1;
++ my ($pp, $aa) = split('@', $p);
++ $install{$pp} = (defined($aa) ? $aa : 0);;
+ }
+ my $changed = 1;
+ while ($changed) {
+@@ -576,7 +712,7 @@
+ ddebug("pre_select = @pre_select\n");
+ for my $p (@pre_select) {
+ next if ($p =~ m/^00texlive/);
+- my $pkg = $self->get_package($p);
++ my $pkg = $self->get_package($p, ($install{$p}?$install{$p}:undef));
+ if (!defined($pkg)) {
+ debug("W: $p is mentioned somewhere but not available, disabling\n");
+ $install{$p} = 0;
+@@ -602,16 +738,19 @@
+ if ($p_dep =~ m/^(.*)\.ARCH$/) {
+ my $foo = "$1";
+ foreach $a (@archs) {
+- $install{"$foo.$a"} = 1 if defined($self->get_package("$foo.$a"));
++ # install .ARCH packages from the same sub repository as the
++ # main packages
++ $install{"$foo.$a"} = $install{$foo}
++ if defined($self->get_package("$foo.$a"));
+ }
+ } elsif ($p_dep =~ m/^(.*)\.win32$/) {
+ # a win32 package should *only* be installed if we are installing
+ # the win32 arch
+ if (grep(/^win32$/,@archs)) {
+- $install{$p_dep} = 1;
++ $install{$p_dep} = 0;
+ }
+ } else {
+- $install{$p_dep} = 1 unless $only_arch;
++ $install{$p_dep} = 0 unless $only_arch;
+ }
+ }
+ }
+@@ -623,7 +762,9 @@
+ $changed = 1;
+ }
+ }
+- return(keys %install);
++ # create return list
++ return map { $install{$_} eq "0"?$_:"$_\@" . $install{$_} } keys %install;
++ #return(keys %install);
+ }
+
+ =pod
+@@ -635,6 +776,7 @@
+
+ =cut
+
++# TODO adapt for searching in *all* tags ???
+ sub find_file {
+ my ($self,$fn) = @_;
+ my @ret;
+@@ -868,6 +1010,10 @@
+
+ sub root {
+ my $self = shift;
++ if ($self->is_virtual) {
++ tlwarn("cannot set/edit root of a virtual tlpdb\n");
++ return 0;
++ }
+ if (@_) { $self->{'root'} = shift }
+ return $self->{'root'};
+ }
+@@ -886,7 +1032,11 @@
+ =cut
+
+ sub location {
+- my $self = shift;
++ my $self = shift;
++ if ($self->is_virtual) {
++ tlwarn("cannot get location of a virtual tlpdb\n");
++ return 0;
++ }
+ return "$self->{'root'}/$InfraLocation/$DatabaseName";
+ }
+
+@@ -937,8 +1087,14 @@
+
+ sub config_src_container {
+ my $self = shift;
+- if (defined($self->{'tlps'}{'00texlive.config'})) {
+- foreach my $d ($self->{'tlps'}{'00texlive.config'}->depends) {
++ my $tlp;
++ if ($self->is_virtual) {
++ $tlp = $self->{'tlpdbs'}{'main'}->get_package('00texlive.config');
++ } else {
++ $tlp = $self->{'tlps'}{'00texlive.config'};
++ }
++ if (defined($tlp)) {
++ foreach my $d ($tlp->depends) {
+ if ($d =~ m!^container_split_src_files/(.*)$!) {
+ return "$1";
+ }
+@@ -958,8 +1114,14 @@
+
+ sub config_doc_container {
+ my $self = shift;
+- if (defined($self->{'tlps'}{'00texlive.config'})) {
+- foreach my $d ($self->{'tlps'}{'00texlive.config'}->depends) {
++ my $tlp;
++ if ($self->is_virtual) {
++ $tlp = $self->{'tlpdbs'}{'main'}->get_package('00texlive.config');
++ } else {
++ $tlp = $self->{'tlps'}{'00texlive.config'};
++ }
++ if (defined($tlp)) {
++ foreach my $d ($tlp->depends) {
+ if ($d =~ m!^container_split_doc_files/(.*)$!) {
+ return "$1";
+ }
+@@ -978,8 +1140,14 @@
+
+ sub config_container_format {
+ my $self = shift;
+- if (defined($self->{'tlps'}{'00texlive.config'})) {
+- foreach my $d ($self->{'tlps'}{'00texlive.config'}->depends) {
++ my $tlp;
++ if ($self->is_virtual) {
++ $tlp = $self->{'tlpdbs'}{'main'}->get_package('00texlive.config');
++ } else {
++ $tlp = $self->{'tlps'}{'00texlive.config'};
++ }
++ if (defined($tlp)) {
++ foreach my $d ($tlp->depends) {
+ if ($d =~ m!^container_format/(.*)$!) {
+ return "$1";
+ }
+@@ -998,8 +1166,14 @@
+
+ sub config_release {
+ my $self = shift;
+- if (defined($self->{'tlps'}{'00texlive.config'})) {
+- foreach my $d ($self->{'tlps'}{'00texlive.config'}->depends) {
++ my $tlp;
++ if ($self->is_virtual) {
++ $tlp = $self->{'tlpdbs'}{'main'}->get_package('00texlive.config');
++ } else {
++ $tlp = $self->{'tlps'}{'00texlive.config'};
++ }
++ if (defined($tlp)) {
++ foreach my $d ($tlp->depends) {
+ if ($d =~ m!^release/(.*)$!) {
+ return "$1";
+ }
+@@ -1018,8 +1192,14 @@
+
+ sub config_minrelease {
+ my $self = shift;
+- if (defined($self->{'tlps'}{'00texlive.config'})) {
+- foreach my $d ($self->{'tlps'}{'00texlive.config'}->depends) {
++ my $tlp;
++ if ($self->is_virtual) {
++ $tlp = $self->{'tlpdbs'}{'main'}->get_package('00texlive.config');
++ } else {
++ $tlp = $self->{'tlps'}{'00texlive.config'};
++ }
++ if (defined($tlp)) {
++ foreach my $d ($tlp->depends) {
+ if ($d =~ m!^minrelease/(.*)$!) {
+ return "$1";
+ }
+@@ -1039,8 +1219,14 @@
+
+ sub config_revision {
+ my $self = shift;
+- if (defined($self->{'tlps'}{'00texlive.config'})) {
+- foreach my $d ($self->{'tlps'}{'00texlive.config'}->depends) {
++ my $tlp;
++ if ($self->is_virtual) {
++ $tlp = $self->{'tlpdbs'}{'main'}->get_package('00texlive.config');
++ } else {
++ $tlp = $self->{'tlps'}{'00texlive.config'};
++ }
++ if (defined($tlp)) {
++ foreach my $d ($tlp->depends) {
+ if ($d =~ m!^revision/(.*)$!) {
+ return "$1";
+ }
+@@ -1066,12 +1252,12 @@
+ sub sizes_of_packages {
+ my ($self, $opt_src, $opt_doc, @packs) = @_;
+ @packs || ( @packs = $self->list_packages() );
+- my $media = $self->media;
+ my %tlpsizes;
+ my %tlpobjs;
+ my $totalsize;
+ foreach my $p (@packs) {
+ $tlpobjs{$p} = $self->get_package($p);
++ my $media = $self->media_of_package($p);
+ if (!defined($tlpobjs{$p})) {
+ warn "STRANGE: $p not to be found in ", $self->root;
+ next;
+@@ -1095,7 +1281,7 @@
+ $size += $tlpobj->srccontainersize if $opt_src;
+ $size += $tlpobj->doccontainersize if $opt_doc;
+ } else {
+- # we have to add the respective sizes, that is checking for
++ # we have to add the respective sizes, that is checking for
+ # installation of src and doc file
+ $size = $tlpobj->runsize;
+ $size += $tlpobj->srcsize if $opt_src;
+@@ -1110,31 +1296,46 @@
+
+ =pod
+
+-=item C<< $tlpdb->install_package($pkg, $dest_tlpdb, $nopostinstall, $fallbacktlpdb) >>
++=item C<< $tlpdb->install_package($pkg, $dest_tlpdb [, $tag]) >>
+
+ Installs the package $pkg into $dest_tlpdb.
++If C<$tag> is present and the tlpdb is virtual, tries to install $pkg
++from the repository tagged with $tag.
+
+ =cut
+
+ sub install_package {
+- my ($self, $pkg, $totlpdb, $nopostinstall, $fallbackmedia) = @_;
++ my ($self, $pkg, $totlpdb, $tag) = @_;
++ if ($self->is_virtual) {
++ if (defined($tag)) {
++ if (defined($self->{'packages'}{$pkg}{'tags'}{$tag})) {
++ return $self->{'tlpdbs'}{$tag}->install_package($pkg, $totlpdb);
++ } else {
++ tlwarn("package $pkg not found in repository $tag\n");
++ return;
++ }
++ } else {
++ my ($maxtag, $maxrev, $maxtlp, $maxtlpdb) = $self->virtual_candidate($pkg);
++ return $maxtlpdb->install_package($pkg, $totlpdb);
++ }
++ } else {
++ if (defined($tag)) {
++ tlwarn("not a virtual database, ignoring tag $tag on installation of $pkg\n");
++ }
++ return $self->not_virtual_install_package($pkg, $totlpdb);
++ }
++ return;
++}
++
++sub not_virtual_install_package {
++ my ($self, $pkg, $totlpdb) = @_;
+ my $fromtlpdb = $self;
+ my $ret;
+ die("TLPDB not initialized, cannot find tlpdb!") unless (defined($fromtlpdb));
+ my $tlpobj = $fromtlpdb->get_package($pkg);
+ if (!defined($tlpobj)) {
+- if (defined($fallbackmedia)) {
+- if ($ret = $fallbackmedia->install_package($pkg,$totlpdb, $nopostinstall)) {
+- debug("installed $pkg from fallback\n");
+- return $ret;
+- } else {
+- tlwarn("$0: Cannot find package $pkg (in fallback, either)\n");
+- return 0;
+- }
+- } else {
+- tlwarn("$0: Cannot find package $pkg\n");
+- return 0;
+- }
++ tlwarn("$0: Cannot find package $pkg\n");
++ return 0;
+ } else {
+ my $container_src_split = $fromtlpdb->config_src_container;
+ my $container_doc_split = $fromtlpdb->config_doc_container;
+@@ -1182,7 +1383,7 @@
+ next;
+ }
+ } elsif (&media eq 'NET') {
+- $container = "$root/$Archive/$pkg.$DefaultContainerExtension";
++ $container = "$root/$Archive/$pkg.$TeXLive::TLConfig::DefaultContainerExtension";
+ }
+ $self->_install_package ($container, $reloc, \@installfiles, $totlpdb)
+ || return(0);
+@@ -1256,23 +1457,21 @@
+ $totlpdb->save;
+ # compute the return value
+ TeXLive::TLUtils::announce_execute_actions("enable", $tlpobj);
+- if (!$nopostinstall) {
+- # do the postinstallation actions
+- #
+- # Run the post installation code in the postaction tlpsrc entries
+- # in case we are on w32 and the admin did install for himself only
+- # we switch off admin mode
+- if (win32() && admin() && !$totlpdb->option("w32_multi_user")) {
+- non_admin();
+- }
+- # for now desktop_integration maps to both installation
+- # of desktop shortcuts and menu items, but we can split them later
+- &TeXLive::TLUtils::do_postaction("install", $tlpobj,
+- $totlpdb->option("file_assocs"),
+- $totlpdb->option("desktop_integration"),
+- $totlpdb->option("desktop_integration"),
+- $totlpdb->option("post_code"));
++ # do the postinstallation actions
++ #
++ # Run the post installation code in the postaction tlpsrc entries
++ # in case we are on w32 and the admin did install for himself only
++ # we switch off admin mode
++ if (win32() && admin() && !$totlpdb->option("w32_multi_user")) {
++ non_admin();
+ }
++ # for now desktop_integration maps to both installation
++ # of desktop shortcuts and menu items, but we can split them later
++ &TeXLive::TLUtils::do_postaction("install", $tlpobj,
++ $totlpdb->option("file_assocs"),
++ $totlpdb->option("desktop_integration"),
++ $totlpdb->option("desktop_integration"),
++ $totlpdb->option("post_code"));
+ }
+ return 1;
+ }
+@@ -1525,7 +1724,7 @@
+ # the postaction code part cannot be evaluated now since the
+ # files are already removed.
+ # Again, desktop integration maps to desktop and menu links
+- if (!$nopostinstall) {
++ if (!$opts{'nopostinstall'}) {
+ &TeXLive::TLUtils::do_postaction("remove", $tlp,
+ $localtlpdb->option("file_assocs"),
+ $localtlpdb->option("desktop_integration"),
+@@ -1557,7 +1756,12 @@
+ sub _set_value_pkg {
+ my ($self,$pkgname,$pre,$key,$value) = @_;
+ my $k = "$pre$key";
+- my $pkg = $self->{'tlps'}{$pkgname};
++ my $pkg;
++ if ($self->is_virtual) {
++ $pkg = $self->{'tlpdbs'}{'main'}->get_package($pkgname);
++ } else {
++ $pkg = $self->{'tlps'}{$pkgname};
++ }
+ my @newdeps;
+ if (!defined($pkg)) {
+ $pkg = new TeXLive::TLPOBJ;
+@@ -1595,8 +1799,14 @@
+ sub _value_pkg {
+ my ($self,$pkg,$pre,$key) = @_;
+ my $k = "$pre$key";
+- if (defined($self->{'tlps'}{$pkg})) {
+- foreach my $d ($self->{'tlps'}{$pkg}->depends) {
++ my $tlp;
++ if ($self->is_virtual) {
++ $tlp = $self->{'tlpdbs'}{'main'}->get_package($pkg);
++ } else {
++ $tlp = $self->{'tlps'}{$pkg};
++ }
++ if (defined($tlp)) {
++ foreach my $d ($tlp->depends) {
+ if ($d =~ m!^$k:(.*)$!) {
+ return "$1";
+ }
+@@ -1709,7 +1919,12 @@
+ my ($self, $pre, $hr) = @_;
+ my @allowed = keys %$hr;
+ my %ret;
+- my $pkg = $self->{'tlps'}{'00texlive.installation'};
++ my $pkg;
++ if ($self->is_virtual) {
++ $pkg = $self->{'tlpdbs'}{'main'}->get_package('00texlive.installation');
++ } else {
++ $pkg = $self->{'tlps'}{'00texlive.installation'};
++ }
+ if (defined($pkg)) {
+ foreach my $d ($pkg->depends) {
+ if ($d =~ m!^$pre([^:]*):(.*)!) {
+@@ -1858,6 +2073,338 @@
+
+ =back
+
++=head1 VIRTUAL DATABASES
++
++The purpose of virtual databases is to collect several data sources
++and present them in one way. The normal functions will always return
++the best candidate for the set of functions.
++
++More docs to be written
++
++=cut
++
++#
++# packages are saved:
++# $self->{'packages'}{$pkgname}{'tags'}{$tag}{'revision'} = $rev
++# $self->{'packages'}{$pkgname}{'tags'}{$tag}{'tlp'} = $tlp
++# $self->{'packages'}{$pkgname}{'target'} = $target_tag
++#
++
++sub is_virtual {
++ my $self = shift;
++ if (defined($self->{'virtual'}) && $self->{'virtual'}) {
++ return 1;
++ }
++ return 0;
++}
++
++sub make_virtual {
++ my $self = shift;
++ if (!$self->is_virtual) {
++ if ($self->list_packages) {
++ tlerror("Cannot convert a initialized tlpdb to virtual for now!\n");
++ return 0;
++ }
++ $self->{'virtual'} = 1;
++ }
++ return 1;
++}
++
++sub virtual_add_tlpdb {
++ my ($self, $tlpdb, $tag) = @_;
++ if (!$self->is_virtual) {
++ tlerror("Cannot add tlpdb to a non-virtual tlpdb!\n");
++ return 0;
++ }
++ $self->{'tlpdbs'}{$tag} = $tlpdb;
++ for my $p ($tlpdb->list_packages) {
++ my $tlp = $tlpdb->get_package($p);
++ $self->{'packages'}{$p}{'tags'}{$tag}{'revision'} = $tlp->revision;
++ $self->{'packages'}{$p}{'tags'}{$tag}{'tlp'} = $tlp;
++ }
++ $self->check_evaluate_pinning();
++ return 1;
++}
++
++sub virtual_remove_tlpdb {
++ my ($self, $tag) = @_;
++ if (!$self->is_virtual) {
++ tlerror("Cannot remove tlpdb from a non-virtual tlpdb!\n");
++ return 0;
++ }
++ if (!defined($self->{'tlpdbs'}{$tag})) {
++ tlwarn("TLPDB virtual_remove_tlpdb: unknown tag $tag\n");
++ return 0;
++ }
++ for my $p ($self->{'tlpdbs'}{$tag}->list_packages) {
++ delete $self->{'packages'}{$p}{'tags'}{$tag};
++ }
++ delete $self->{'tlpdbs'}{$tag};
++ $self->check_evaluate_pinning();
++ return 1;
++}
++
++sub virtual_get_package {
++ my ($self, $pkg, $tag) = @_;
++ if (defined($self->{'packages'}{$pkg}{'tags'}{$tag})) {
++ return $self->{'packages'}{$pkg}{'tags'}{$tag}{'tlp'};
++ } else {
++ tlwarn("pkg $pkg not found in tag $tag\n");
++ return;
++ }
++}
++
++=item C<< $tlpdb->candidates ( $pkg ) >>
++
++Returns the list of candidates for the given package in the
++format
++
++ tag/revision
++
++If the returned list is empty, then the database was not virtual and
++no install candidate was found.
++
++If the returned list contains undef as first element, the database
++is virtual, and no install candidate was found.
++
++The remaining elements in the list are all repositories that provide
++that package.
++
++Note that there might not be an install candidate, but still the
++package is provided by a sub-repository. This can happen if a package
++is present only in the sub-repository and there is no explicit pin
++for that package in the pinning file.
++
++=cut
++
++sub is_repository {
++ my $self = shift;
++ my $tag = shift;
++ if (!$self->is_virtual) {
++ return ( ($tag eq $self->{'root'}) ? 1 : 0 );
++ }
++ return ( defined($self->{'tlpdbs'}{$tag}) ? 1 : 0 );
++}
++
++
++# returns a list of tag/rev
++sub candidates {
++ my $self = shift;
++ my $pkg = shift;
++ my @ret = ();
++ if ($self->is_virtual) {
++ if (defined($self->{'packages'}{$pkg})) {
++ my $t = $self->{'packages'}{$pkg}{'target'};
++ if (defined($t)) {
++ push @ret, "$t/" . $self->{'packages'}{$pkg}{'tags'}{$t}{'revision'};
++ } else {
++ $t = "";
++ # no target found, but maybe available somewhere else,
++ # we return undef as first one
++ push @ret, undef;
++ }
++ # make sure that we always check for main as repo
++ my @repos = keys %{$self->{'packages'}{$pkg}};
++ for my $r (sort keys %{$self->{'packages'}{$pkg}{'tags'}}) {
++ push @ret, "$r/" . $self->{'packages'}{$pkg}{'tags'}{$r}{'revision'}
++ if ($t ne $r);
++ }
++ }
++ } else {
++ my $tlp = $self->get_package($pkg);
++ if (defined($tlp)) {
++ push @ret, "main/" . $tlp->revision;
++ }
++ }
++ return @ret;
++}
++
++=item C<< $tlpdb->candidate ( ) >>
++
++Returns either a list of four undef, if no install candidate is found,
++or the following information on the install candidate as list: the tag
++name of the repository, the revision number of the package in the
++candidate repository, the tlpobj of the package in the candidate
++repository, and the candidate repository's TLPDB itself.
++
++=cut
++
++#
++sub virtual_candidate {
++ my ($self, $pkg) = @_;
++ my $t = $self->{'packages'}{$pkg}{'target'};
++ if (defined($t)) {
++ return ($t, $self->{'packages'}{$pkg}{'tags'}{$t}{'revision'},
++ $self->{'packages'}{$pkg}{'tags'}{$t}{'tlp'}, $self->{'tlpdbs'}{$t});
++ }
++ return(undef,undef,undef,undef);
++}
++
++=item C<< $tlpdb->virtual_pinning ( [@pinning_data] ) >>
++
++Without any argument returns the pinning data, or undef. Be reminded that an
++empty pinning data will behave differently to no pinning data.
++
++With an argument it must be a list of pins, where each pin
++must be one hash ref with the following keys:
++C<repo> the tag of the repository,
++C<glob> the glob for matching a package
++C<re> the regexp which corresponds to the glob
++C<line> the line where the glob was found (for warning purpose).
++
++=cut
++
++sub virtual_pinning {
++ my $self = shift;
++ my (@pins) = @_;
++ if (!$self->is_virtual) {
++ tlerror("Not-virtual databases cannot have pinning data.\n");
++ return 0;
++ }
++ if (!@pins) {
++ if (!defined($self->{'pindata'})) {
++ my @foo = ();
++ $self->{'pindata'} = \@foo;
++ }
++ return (@{$self->{'pindata'}});
++ } else {
++ $self->{'pindata'} = \@pins;
++ $self->check_evaluate_pinning();
++ return ($self->{'pindata'});
++ }
++}
++
++# $pin{'repo'} = $repo;
++# $pin{'glob'} = $glob;
++# $pin{'re'} = $re;
++# $pin{'line'} = $line; # for debug/warning purpose
++sub make_pin_data_from_line {
++ my $self = shift;
++ my $l = shift;
++ my ($a, $b) = split(/:/, $l);
++ my @ret;
++ my %m;
++ $m{'repo'} = $a;
++ $m{'line'} = $l;
++ # split the package globs
++ for (split(/,/, $b)) {
++ my %mm = %m;
++ $mm{'glob'} = $_;
++ $mm{'re'} = glob_to_regex($_);
++ push @ret, \%mm;
++ }
++ return @ret;
++}
++
++sub check_evaluate_pinning {
++ my $self = shift;
++ my @pins = (defined($self->{'pindata'}) ? @{$self->{'pindata'}} : ());
++ #
++ # run through the pin lines and make sure that all the conditions
++ # and requirements are obeyed
++ my %pkgs = %{$self->{'packages'}};
++ # main:*
++ my ($mainpin) = $self->make_pin_data_from_line("main:*");
++ # the default main:* is always considered to be matched
++ $mainpin->{'hit'} = 1;
++ push @pins, $mainpin;
++ for my $pkg (keys %pkgs) {
++ PINS: for my $pp (@pins) {
++ my $pre = $pp->{'re'};
++ if (($pkg =~ m/$pre/) &&
++ (defined($self->{'packages'}{$pkg}{'tags'}{$pp->{'repo'}}))) {
++ $self->{'packages'}{$pkg}{'target'} = $pp->{'repo'};
++ # register that this pin was hit
++ $pp->{'hit'} = 1;
++ last PINS;
++ }
++ }
++ }
++ # check that all pinning lines where hit
++ for my $p (@pins) {
++ next if defined($p->{'hit'});
++ tlwarn("pinning warning: the entry in line\n ", $p->{'line'},
++ "\nconcerning the package pattern ", $p->{'glob'},
++ "\nis not matched by any package!\n");
++ }
++}
++
++
++# implementation copied from Text/Glob.pm (copyright Richard Clamp).
++# changes made:
++# remove $strict_leading_dot and $strict_wildcard_slash if calls
++# and execute the code unconditionally, as we do not change the
++# default settings of 1 of these two variables.
++sub glob_to_regex {
++ my $glob = shift;
++ my $regex = glob_to_regex_string($glob);
++ return qr/^$regex$/;
++}
++
++sub glob_to_regex_string
++{
++ my $glob = shift;
++ my ($regex, $in_curlies, $escaping);
++ local $_;
++ my $first_byte = 1;
++ for ($glob =~ m/(.)/gs) {
++ if ($first_byte) {
++ $regex .= '(?=[^\.])' unless $_ eq '.';
++ $first_byte = 0;
++ }
++ if ($_ eq '/') {
++ $first_byte = 1;
++ }
++ if ($_ eq '.' || $_ eq '(' || $_ eq ')' || $_ eq '|' ||
++ $_ eq '+' || $_ eq '^' || $_ eq '$' || $_ eq '@' || $_ eq '%' ) {
++ $regex .= "\\$_";
++ }
++ elsif ($_ eq '*') {
++ $regex .= $escaping ? "\\*" : "[^/]*";
++ }
++ elsif ($_ eq '?') {
++ $regex .= $escaping ? "\\?" : "[^/]";
++ }
++ elsif ($_ eq '{') {
++ $regex .= $escaping ? "\\{" : "(";
++ ++$in_curlies unless $escaping;
++ }
++ elsif ($_ eq '}' && $in_curlies) {
++ $regex .= $escaping ? "}" : ")";
++ --$in_curlies unless $escaping;
++ }
++ elsif ($_ eq ',' && $in_curlies) {
++ $regex .= $escaping ? "," : "|";
++ }
++ elsif ($_ eq "\\") {
++ if ($escaping) {
++ $regex .= "\\\\";
++ $escaping = 0;
++ }
++ else {
++ $escaping = 1;
++ }
++ next;
++ }
++ else {
++ $regex .= $_;
++ $escaping = 0;
++ }
++ $escaping = 0;
++ }
++ print "# $glob $regex\n" if debug;
++
++ return $regex;
++}
++
++sub match_glob {
++ print "# ", join(', ', map { "'$_'" } @_), "\n" if debug;
++ my $glob = shift;
++ my $regex = glob_to_regex $glob;
++ local $_;
++ grep { $_ =~ $regex } @_;
++}
++
+ =pod
+
+ =head1 OPTIONS
+Index: texmf/scripts/texlive/tlmgr.pl
+===================================================================
+--- texmf/scripts/texlive/tlmgr.pl.orig 2011-10-27 23:06:37.000000000 +0900
++++ texmf/scripts/texlive/tlmgr.pl 2012-01-12 12:51:18.000000000 +0900
+@@ -124,6 +124,7 @@
+ "package-logfile" => "=s",
+ "persistent-downloads" => "!",
+ "no-execute-actions" => 1,
++ "pin-file" => "=s",
+ "pause" => 1,
+ "print-platform|print-arch" => 1,
+ "version" => 1,
+@@ -135,6 +136,8 @@
+ "option" => { },
+ "conf" => { },
+ "version" => { },
++ "repository" => { },
++ "candidate" => { },
+ "backup" => { "backupdir" => "=s",
+ "clean" => ":-99",
+ "all" => 1,
+@@ -504,6 +507,12 @@
+ } elsif ($action =~ m/^option$/i) {
+ action_option();
+ finish(0);
++ } elsif ($action =~ m/^repository$/i) {
++ action_repository();
++ finish(0);
++ } elsif ($action =~ m/^candidates$/i) {
++ action_candidates();
++ finish(0);
+ } elsif ($action =~ m/^list$/i) {
+ action_list();
+ finish(0);
+@@ -533,7 +542,7 @@
+ action_dumptlpdb();
+ finish(0);
+ } elsif ($action =~ m/^show$/i) {
+- action_show();
++ action_show(@ARGV);
+ finish(0);
+ } elsif ($action =~ m/^remove$/i) {
+ action_remove();
+@@ -1145,7 +1154,8 @@
+ tlwarn("tlmgr: Cannot load taxonomy file, showing taxonomies not supported.\n");
+ }
+ }
+- foreach my $pkg (@ARGV) {
++ foreach my $ppp (@_) {
++ my ($pkg, $tag) = split '@', $ppp, 2;
+ my $tlpdb = $localtlpdb;
+ my $tlp = $localtlpdb->get_package($pkg);
+ my $installed = 0;
+@@ -1153,126 +1163,179 @@
+ if (!$remotetlpdb) {
+ init_tlmedia();
+ }
+- $tlp = $remotetlpdb->get_package($pkg);
+- $tlpdb = $remotetlpdb;
+- } else {
+- $installed = 1;
+- }
+- if ($tlp) {
+- my @colls;
+- if ($tlp->category ne "Collection" && $tlp->category ne "Scheme") {
+- @colls = $localtlpdb->needed_by($pkg);
+- if (!@colls) {
+- # not referenced in the local tlpdb, so try the remote here, too
+- if (!$remotetlpdb) {
+- init_tlmedia();
++ if (defined($tag)) {
++ if (!$remotetlpdb->is_virtual) {
++ tlwarn("tlmgr: specifying implicite tags is not allowed for non-virtual databases!\n");
++ next;
++ } else {
++ if (!$remotetlpdb->is_repository($tag)) {
++ tlwarn("tlmgr: no such repository tag defined: $tag\n");
++ next;
+ }
+- @colls = $remotetlpdb->needed_by($pkg);
+ }
+ }
+- # some packages might depend on other packages, so do not
+- # include arbitrary package in the list of collections, but
+- # only collectons:
+- @colls = grep {m;^collection-;} @colls;
+- print "package: ", $tlp->name, "\n";
+- print "category: ", $tlp->category, "\n";
+- print "shortdesc: ", $tlp->shortdesc, "\n" if ($tlp->shortdesc);
+- print "longdesc: ", $tlp->longdesc, "\n" if ($tlp->longdesc);
+- print "installed: ", ($installed ? "Yes" : "No"), "\n";
+- print "revision: ", $tlp->revision, "\n" if ($installed);
+- print "cat-version: ", $tlp->cataloguedata->{'version'}, "\n"
+- if $tlp->cataloguedata->{'version'};
+- print "cat-date: ", $tlp->cataloguedata->{'date'}, "\n"
+- if $tlp->cataloguedata->{'date'};
+- print "cat-license: ", $tlp->cataloguedata->{'license'}, "\n"
+- if $tlp->cataloguedata->{'license'};
+- print "collection: ", @colls, "\n" if (@colls);
+- if ($opts{"keyword"} || $opts{"taxonomy"}) {
+- print "keywords: ";
+- if (defined($taxonomy->{'by-package'}{'keyword'}{$pkg})) {
+- print join(', ',@{$taxonomy->{'by-package'}{'keyword'}{$pkg}}), "\n";
+- } else {
+- print "(none found)\n";
++ $tlp = $remotetlpdb->get_package($pkg, $tag);
++ if (!$tlp) {
++ if (defined($tag)) {
++ # we already searched for the package in a specific tag, don't retry
++ # all candidates!
++ tlwarn("tlmgr: Cannot find package $pkg in repository $tag\n");
++ next;
+ }
+- }
+- if ($opts{"functionality"} || $opts{"taxonomy"}) {
+- print "function: ";
+- if (defined($taxonomy->{'by-package'}{'functionality'}{$pkg})) {
+- print join(', ',@{$taxonomy->{'by-package'}{'functionality'}{$pkg}}), "\n";
+- } else {
+- print "(none found)\n";
++ if ($remotetlpdb->is_virtual) {
++ # we might have a package that is available in a
++ # subsidiary repository, but not installable
++ # because it is not pinned
++ # we will list it but warn about this fact
++ my @cand = $remotetlpdb->candidates($pkg);
++ if (@cand) {
++ my $first = shift @cand;
++ if (defined($first)) {
++ tlwarn("strange, we have a first candidate but no tlp: $pkg\n");
++ next;
++ }
++ # already shifted away the first element
++ if ($#cand >= 0) {
++ # recursively showing all tags, but warn
++ print "package: ", $pkg, "\n";
++ print "WARNING: This package is not pinned but present in subsidiary repositories\n";
++ print "WARNING: As long as it is not pinned it is not installable.\n";
++ print "WARNING: Listing all available copies of the package.\n";
++ my @aaa;
++ for my $a (@cand) {
++ my ($t,$r) = split(/\//, $a, 2);
++ push @aaa, "$pkg" . '@' . $t;
++ }
++ action_show(@aaa);
++ next;
++ } else {
++ tlwarn("strange, package listed but no residual candidates: $pkg\n");
++ next;
++ }
++ } else {
++ tlwarn("strange, package listed but no candidates: $pkg\n");
++ next;
++ }
+ }
++ tlwarn("tlmgr: cannot find package $pkg\n");
++ next;
+ }
+- if ($opts{"characterization"} || $opts{"taxonomy"}) {
+- print "primary characterization: ";
+- if (defined($taxonomy->{'by-package'}{'primary'}{$pkg})) {
+- print $taxonomy->{'by-package'}{'primary'}{$pkg}, "\n";
+- } else {
+- print "(none found)\n";
+- }
+- print "secondary characterization: ";
+- if (defined($taxonomy->{'by-package'}{'secondary'}{$pkg})) {
+- print $taxonomy->{'by-package'}{'secondary'}{$pkg}, "\n";
+- } else {
+- print "(none found)\n";
+- }
++ $tlpdb = $remotetlpdb;
++ } else {
++ $installed = 1;
++ }
++ my @colls;
++ if ($tlp->category ne "Collection" && $tlp->category ne "Scheme") {
++ @colls = $localtlpdb->needed_by($pkg);
++ if (!@colls) {
++ # not referenced in the local tlpdb, so try the remote here, too
++ if (!$remotetlpdb) {
++ init_tlmedia();
++ }
++ @colls = $remotetlpdb->needed_by($pkg);
++ }
++ }
++ # some packages might depend on other packages, so do not
++ # include arbitrary package in the list of collections, but
++ # only collectons:
++ @colls = grep {m;^collection-;} @colls;
++ print "package: ", $tlp->name, "\n";
++ print "repository: ", $tag, "\n" if (defined($tag));
++ print "category: ", $tlp->category, "\n";
++ print "shortdesc: ", $tlp->shortdesc, "\n" if ($tlp->shortdesc);
++ print "longdesc: ", $tlp->longdesc, "\n" if ($tlp->longdesc);
++ print "installed: ", ($installed ? "Yes" : "No"), "\n";
++ print "revision: ", $tlp->revision, "\n" if ($installed);
++ print "cat-version: ", $tlp->cataloguedata->{'version'}, "\n"
++ if $tlp->cataloguedata->{'version'};
++ print "cat-date: ", $tlp->cataloguedata->{'date'}, "\n"
++ if $tlp->cataloguedata->{'date'};
++ print "cat-license: ", $tlp->cataloguedata->{'license'}, "\n"
++ if $tlp->cataloguedata->{'license'};
++ print "collection: ", @colls, "\n" if (@colls);
++ if ($opts{"keyword"} || $opts{"taxonomy"}) {
++ print "keywords: ";
++ if (defined($taxonomy->{'by-package'}{'keyword'}{$pkg})) {
++ print join(', ',@{$taxonomy->{'by-package'}{'keyword'}{$pkg}}), "\n";
++ } else {
++ print "(none found)\n";
++ }
++ }
++ if ($opts{"functionality"} || $opts{"taxonomy"}) {
++ print "function: ";
++ if (defined($taxonomy->{'by-package'}{'functionality'}{$pkg})) {
++ print join(', ',@{$taxonomy->{'by-package'}{'functionality'}{$pkg}}), "\n";
++ } else {
++ print "(none found)\n";
++ }
++ }
++ if ($opts{"characterization"} || $opts{"taxonomy"}) {
++ print "primary characterization: ";
++ if (defined($taxonomy->{'by-package'}{'primary'}{$pkg})) {
++ print $taxonomy->{'by-package'}{'primary'}{$pkg}, "\n";
++ } else {
++ print "(none found)\n";
++ }
++ print "secondary characterization: ";
++ if (defined($taxonomy->{'by-package'}{'secondary'}{$pkg})) {
++ print $taxonomy->{'by-package'}{'secondary'}{$pkg}, "\n";
++ } else {
++ print "(none found)\n";
+ }
+- if ($opts{"list"}) {
+- if ($tlp->category eq "Collection" || $tlp->category eq "Scheme") {
+- # in the case of collections of schemes we list the deps
+- my @deps = $tlp->depends;
+- if (@deps) {
+- print "depends:\n";
+- for my $d (@deps) {
+- print "\t$d\n";
+- }
++ }
++ if ($opts{"list"}) {
++ if ($tlp->category eq "Collection" || $tlp->category eq "Scheme") {
++ # in the case of collections of schemes we list the deps
++ my @deps = $tlp->depends;
++ if (@deps) {
++ print "depends:\n";
++ for my $d (@deps) {
++ print "\t$d\n";
+ }
+ }
+- print "Included files, by type:\n";
+- # if the package has a .ARCH dependency we also list the files for
+- # those packages
+- my @todo = $tlpdb->expand_dependencies("-only-arch", $tlpdb, ($pkg));
+- for my $d (sort @todo) {
+- my $foo = $tlpdb->get_package($d);
+- if (!$foo) {
+- tlwarn ("\nShould not happen, no dependent package $d\n");
+- next;
+- }
+- if ($d ne $pkg) {
+- print "depending package $d:\n";
+- }
+- if ($foo->runfiles) {
+- print "run files:\n";
+- for my $f (sort $foo->runfiles) { print " $f\n"; }
+- }
+- if ($foo->srcfiles) {
+- print "source files:\n";
+- for my $f (sort $foo->srcfiles) { print " $f\n"; }
+- }
+- if ($foo->docfiles) {
+- print "doc files:\n";
+- for my $f (sort $foo->docfiles) {
+- print " $f";
+- my $dfd = $foo->docfiledata;
+- if (defined($dfd->{$f})) {
+- for my $k (keys %{$dfd->{$f}}) {
+- print " $k=\"", $dfd->{$f}->{$k}, '"';
+- }
++ }
++ print "Included files, by type:\n";
++ # if the package has a .ARCH dependency we also list the files for
++ # those packages
++ my @todo = $tlpdb->expand_dependencies("-only-arch", $tlpdb, ($pkg));
++ for my $d (sort @todo) {
++ my $foo = $tlpdb->get_package($d);
++ if (!$foo) {
++ tlwarn ("\nShould not happen, no dependent package $d\n");
++ next;
++ }
++ if ($d ne $pkg) {
++ print "depending package $d:\n";
++ }
++ if ($foo->runfiles) {
++ print "run files:\n";
++ for my $f (sort $foo->runfiles) { print " $f\n"; }
++ }
++ if ($foo->srcfiles) {
++ print "source files:\n";
++ for my $f (sort $foo->srcfiles) { print " $f\n"; }
++ }
++ if ($foo->docfiles) {
++ print "doc files:\n";
++ for my $f (sort $foo->docfiles) {
++ print " $f";
++ my $dfd = $foo->docfiledata;
++ if (defined($dfd->{$f})) {
++ for my $k (keys %{$dfd->{$f}}) {
++ print " $k=\"", $dfd->{$f}->{$k}, '"';
+ }
+- print "\n";
+ }
++ print "\n";
+ }
+- # in case we have them
+- if ($foo->allbinfiles) {
+- print "bin files (all platforms):\n";
+- for my $f (sort $foo->allbinfiles) { print " $f\n"; }
+- }
++ }
++ # in case we have them
++ if ($foo->allbinfiles) {
++ print "bin files (all platforms):\n";
++ for my $f (sort $foo->allbinfiles) { print " $f\n"; }
+ }
+ }
+- print "\n";
+- } else {
+- printf STDERR "tlmgr: cannot find $pkg\n";
+ }
++ print "\n";
+ }
+ return;
+ }
+@@ -2048,7 +2111,12 @@
+ # intersection, don't check A\B and B\A
+ next if $newpkgs_full{$p};
+ next if $removals_full{$p};
+- next if ($remotetlpdb->get_package($p)->category ne "Collection");
++ my $remotetlp = $remotetlpdb->get_package($p);
++ if (!defined($remotetlp)) {
++ tlwarn("Strange, $p mentioned but not found anywhere!\n");
++ next;
++ }
++ next if ($remotetlp->category ne "Collection");
+ my $tlp = $localtlpdb->get_package($p);
+ if (!defined($tlp)) {
+ if ($opts{"reinstall-forcibly-removed"}) {
+@@ -2149,17 +2217,38 @@
+ $ret = 1;
+ shift;
+ }
+- my ($pkg, $flag, $lrev, $rrev, @args) = @_;
++ my ($pkg, $flag, $lrev, $rrev, $size, $runtime, $esttot, $tag) = @_;
+ $lrev ||= "-";
+ $rrev ||= "-";
+ $flag ||= "?";
+- my $str = "$pkg\t$flag\t$lrev\t$rrev\t";
+- $str .= join("\t", @args) if (@args);
++ $size ||= "-";
++ $runtime ||= "-";
++ $esttot ||= "-";
++ $tag ||= "-";
++ my $str = join("\t", $pkg, $flag, $lrev, $rrev, $size, $runtime, $esttot, $tag);
+ $str .= "\n";
+ return($str) if $ret;
+ print $str;
+ }
+
++sub upd_info {
++ my ($pkg, $kb, $lrev, $mrev, $txt) = @_;
++ my $flen = 25;
++ my $kbstr = ($kb >= 0 ? " [${kb}k]" : "");
++ my $kbstrlen = length($kbstr);
++ my $pkglen = length($pkg);
++ my $is = sprintf("%-10s ", "$txt:");
++ if ($pkglen + $kbstrlen > $flen) {
++ $is .= "$pkg$kbstr: ";
++ } else {
++ $is .= sprintf ('%*2$s', $pkg, -($flen-$kbstrlen));
++ $is .= "$kbstr: ";
++ }
++ $is .= sprintf("local: %6s, source: %8s",
++ $lrev, $mrev);
++ info("$is\n");
++}
++
+ sub action_update {
+ init_local_db(1);
+ $opts{"no-depends"} = 1 if $opts{"no-depends-at-all"};
+@@ -2414,20 +2503,36 @@
+ next;
+ }
+ my $rev = $tlp->revision;
+- my $mediatlp = $remotetlpdb->get_package($pkg);
++ my $mediatlp;
++ my $maxtag;
++ if ($remotetlpdb->is_virtual) {
++ ($maxtag, undef, $mediatlp, undef) =
++ $remotetlpdb->virtual_candidate($pkg);
++ } else {
++ $mediatlp = $remotetlpdb->get_package($pkg);
++ }
+ if (!defined($mediatlp)) {
+ debug("$pkg cannot be found in $location\n");
+ next;
+ }
+ my $mediarev = $mediatlp->revision;
++ my $mediarevstr = $mediarev;
++ my @addargs = ();
++ if ($remotetlpdb->is_virtual) {
++ push @addargs, $maxtag;
++ $mediarevstr .= "\@$maxtag";
++ }
+ if ($rev < $mediarev) {
+ $updated{$pkg} = 0; # will be changed to one on successful update
+ } elsif ($rev > $mediarev) {
+ if ($::machinereadable) {
+ push @addlines,
+- machine_line("-ret", $pkg, $FLAG_REVERSED_UPDATE, $rev, $mediarev, "-");
++ machine_line("-ret", $pkg, $FLAG_REVERSED_UPDATE, $rev, $mediarev, "-", @addargs);
+ } else {
+- info("$pkg: local: $rev, source: $mediarev (reverse, keep)\n");
++ if ($opts{"list"}) {
++ # not issueing anything if we keep a package
++ upd_info($pkg, -1, $rev, $mediarevstr, "keep");
++ }
+ }
+ }
+ }
+@@ -2525,6 +2630,8 @@
+ }
+ }
+
++ # parameters for field width
++ my $totalnrdigits = length("$totalnr");
+
+ #
+ # ORDER OF PACKAGE ACTIONS
+@@ -2557,7 +2664,7 @@
+ if ($::machinereadable) {
+ machine_line($p, $FLAG_REMOVE, $rev, "-", "-", "-");
+ } else {
+- info("$p: local: $rev, source: <absent> (auto-remove)\n");
++ upd_info($p, -1, $rev, "<absent>", "a-remove");
+ }
+ $currnr++;
+ } else {
+@@ -2569,7 +2676,8 @@
+ if ($::machinereadable) {
+ machine_line($p, $FLAG_REMOVE, $rev, "-", "-", "-");
+ } else {
+- info("[$currnr/$totalnr] auto-remove: $p\n");
++ info("[" . sprintf ('%*2$s', $currnr, $totalnrdigits) .
++ "/$totalnr] auto-remove: $p ... ");
+ }
+ if (!$opts{"dry-run"}) {
+ if ($opts{"backup"}) {
+@@ -2585,6 +2693,7 @@
+ $localtlpdb->remove_package($p);
+ logpackage("remove: $p");
+ }
++ info("done\n") unless $::machinereadable;
+ $currnr++;
+ }
+ }
+@@ -2678,19 +2787,39 @@
+ my $unwind_package;
+ my $remove_unwind_container = 0;
+ my $rev = $tlp->revision;
+- my $mediatlp = $remotetlpdb->get_package($pkg);
++ my $mediatlp;
++ my $maxtag;
++ if ($remotetlpdb->is_virtual) {
++ ($maxtag, undef, $mediatlp, undef) =
++ $remotetlpdb->virtual_candidate($pkg);
++ } else {
++ $mediatlp = $remotetlpdb->get_package($pkg);
++ }
+ if (!defined($mediatlp)) {
+ debug("$pkg cannot be found in $location\n");
+ next;
+ }
+ my $mediarev = $mediatlp->revision;
++ my $mediarevstr = $mediarev;
++ my @addargs = ();
++ if ($remotetlpdb->is_virtual) {
++ push @addargs, $maxtag;
++ $mediarevstr .= "\@$maxtag";
++ }
+ $nrupdated++;
+ if ($opts{"list"}) {
+ if ($::machinereadable) {
+- machine_line($pkg, $FLAG_UPDATE, $rev, $mediarev, $sizes{$pkg});
++ machine_line($pkg, $FLAG_UPDATE, $rev, $mediarev, $sizes{$pkg}, "-", "-", @addargs);
+ } else {
+ my $kb = int($sizes{$pkg} / 1024) + 1;
+- info("$pkg [${kb}k]: local: $rev, source: $mediarev (update)\n");
++ upd_info($pkg, $kb, $rev, $mediarevstr, "update");
++ if ($remotetlpdb->is_virtual) {
++ my @cand = $remotetlpdb->candidates($pkg);
++ shift @cand; # remove the top element
++ if (@cand) {
++ print "\tother candidates: @cand\n";
++ }
++ }
+ }
+ $updated{$pkg} = 1;
+ next;
+@@ -2731,10 +2860,11 @@
+ }
+
+ if ($::machinereadable) {
+- machine_line($pkg, $FLAG_UPDATE, $rev, $mediarev, $sizes{$pkg}, $estrem, $esttot);
++ machine_line($pkg, $FLAG_UPDATE, $rev, $mediarev, $sizes{$pkg}, $estrem, $esttot, @addargs);
+ } else {
+ my $kb = int ($sizes{$pkg} / 1024) + 1;
+- info("[$currnr/$totalnr, $estrem/$esttot] update: $pkg [${kb}k] ($rev -> $mediarev)");
++ info("[" . sprintf ('%*2$s', $currnr, $totalnrdigits) .
++ "/$totalnr, $estrem/$esttot] update: $pkg [${kb}k] ($rev -> $mediarevstr)");
+ }
+ $donesize += $sizes{$pkg};
+ $currnr++;
+@@ -2777,7 +2907,7 @@
+ }
+ if ($remotetlpdb->install_package($pkg, $localtlpdb)) {
+ # installation succeeded because we got a reference
+- logpackage("update: $pkg ($rev -> $mediarev)");
++ logpackage("update: $pkg ($rev -> $mediarevstr)");
+ unlink($unwind_package) if $remove_unwind_container;
+ # remember successful update
+ $updated{$pkg} = 1;
+@@ -2805,7 +2935,7 @@
+ # now in fact we should do some cleanup, removing files and
+ # dirs from the new package before re-installing the old one.
+ # TODO
+- logpackage("failed update: $pkg ($rev -> $mediarev)");
++ logpackage("failed update: $pkg ($rev -> $mediarevstr)");
+ tlwarn("\n\nInstallation of new version of $pkg did fail, trying to unwind.\n");
+ if (win32()) {
+ # w32 is notorious for not releasing a file immediately
+@@ -2846,12 +2976,25 @@
+ unless $::machinereadable;
+ } else {
+ # install new packages
+- my $mediatlp = $remotetlpdb->get_package($pkg);
++ my $mediatlp;
++ my $maxtag;
++ if ($remotetlpdb->is_virtual) {
++ ($maxtag, undef, $mediatlp, undef) =
++ $remotetlpdb->virtual_candidate($pkg);
++ } else {
++ $mediatlp = $remotetlpdb->get_package($pkg);
++ }
+ if (!defined($mediatlp)) {
+ tlwarn("\nShould not happen: $pkg not found in $location\n");
+ next;
+ }
+ my $mediarev = $mediatlp->revision;
++ my $mediarevstr = $mediarev;
++ my @addargs;
++ if ($remotetlpdb->is_virtual) {
++ $mediarevstr .= "\@$maxtag";
++ push @addargs, $maxtag;
++ }
+ my ($estrem, $esttot);
+ if (!$opts{"list"}) {
+ ($estrem, $esttot) = TeXLive::TLUtils::time_estimate($totalsize,
+@@ -2861,14 +3004,16 @@
+ my @maargs = ($pkg, $FLAG_AUTOINSTALL, "-", $mediatlp->revision, $sizes{$pkg});
+ if (!$opts{"list"}) {
+ push @maargs, $estrem, $esttot;
++ } else {
++ push @maargs, undef, undef;
+ }
+- machine_line(@maargs);
++ machine_line(@maargs, @addargs);
+ } else {
+ my $kb = int($sizes{$pkg} / 1024) + 1;
+ if ($opts{"list"}) {
+- info("$pkg [${kb}k]: local: <absent>, source: " . $mediatlp->revision . " (auto-install)\n");
++ upd_info($pkg, $kb, "<absent>", $mediarevstr, "a-install");
+ } else {
+- info("[$currnr/$totalnr, $estrem/$esttot] auto-install: $pkg [${kb}k]\n");
++ info("[$currnr/$totalnr, $estrem/$esttot] auto-install: $pkg ($mediarevstr) [${kb}k]\n");
+ }
+ }
+ $currnr++;
+@@ -2876,7 +3021,7 @@
+ next if ($opts{"dry-run"} || $opts{"list"});
+ if ($remotetlpdb->install_package($pkg, $localtlpdb)) {
+ # installation succeeded because we got a reference
+- logpackage("auto-install new: $pkg ($mediarev)");
++ logpackage("auto-install new: $pkg ($mediarevstr)");
+ $nrupdated++;
+ } else {
+ tlwarn("$0: couldn't install new package $pkg\n");
+@@ -3023,6 +3168,7 @@
+ if (!(@new || @updated)) {
+ info("tlmgr: no updates available\n");
+ if ($remotetlpdb->media ne "NET"
++ && $remotetlpdb->media ne "virtual"
+ && !$opts{"dry-run"}
+ && !$opts{"repository"}
+ ) {
+@@ -3101,6 +3247,14 @@
+ @packs = $remotetlpdb->expand_dependencies($localtlpdb, @packs) unless $opts{"no-depends"};
+ }
+ #
++ # expand dependencies returns a list pkg@tag in case of a virtual
++ # remote db.
++ my %packs;
++ for my $p (@packs) {
++ my ($pp, $aa) = split('@', $p);
++ $packs{$pp} = (defined($aa) ? $aa : 0);
++ }
++ #
+ # installation order of packages:
+ # first all normal packages, then collections, then schemes
+ # isn't already installed, but the collection already updated, it will
+@@ -3108,7 +3262,7 @@
+ my @inst_packs;
+ my @inst_colls;
+ my @inst_schemes;
+- for my $pkg (sort @packs) {
++ for my $pkg (sort keys %packs) {
+ # we do name checking here, not to load all tlpobj again and again
+ if ($pkg =~ m/^scheme-/) {
+ push @inst_schemes, $pkg;
+@@ -3127,7 +3281,11 @@
+ my @todo;
+ for my $pkg (@inst_packs, @inst_colls, @inst_schemes) {
+ my $pkgrev = 0;
+- my $mediatlp = $remotetlpdb->get_package($pkg);
++ # if the package name is asked from a specific repository, use
++ # that one, otherwise leave the decision to $remotetlpdb by not
++ # giving a final argument
++ my $mediatlp = $remotetlpdb->get_package($pkg,
++ ($packs{$pkg} ? $packs{$pkg} : undef));
+ if (!defined($mediatlp)) {
+ tlwarn("package $pkg not present in package repository.\n");
+ next;
+@@ -3175,13 +3333,26 @@
+ my ($estrem, $esttot) = TeXLive::TLUtils::time_estimate($totalsize,
+ $donesize, $starttime);
+ my $kb = int($sizes{$pkg} / 1024) + 1;
++ my @addargs = ();
++ my $tagstr = "";
++ if ($remotetlpdb->is_virtual) {
++ if ($packs{$pkg} ne "0") {
++ push @addargs, $packs{$pkg};
++ $tagstr = " \@" . $packs{$pkg};
++ } else {
++ my ($maxtag,undef,undef,undef) = $remotetlpdb->virtual_candidate($pkg);
++ push @addargs, $maxtag;
++ $tagstr = " \@" . $maxtag;
++ }
++ }
+ if ($::machinereadable) {
+- machine_line($pkg, $flag, "-", $revs{$pkg}, $sizes{$pkg}, $estrem, $esttot);
++ machine_line($pkg, $flag, "-", $revs{$pkg}, $sizes{$pkg}, $estrem, $esttot, @addargs);
+ } else {
+- info("[$currnr/$totalnr, $estrem/$esttot] ${re}install: $pkg [${kb}k]\n");
++ info("[$currnr/$totalnr, $estrem/$esttot] ${re}install: $pkg$tagstr [${kb}k]\n");
+ }
+ if (!$opts{"dry-run"}) {
+- $remotetlpdb->install_package($pkg, $localtlpdb);
++ $remotetlpdb->install_package($pkg, $localtlpdb,
++ ($packs{$pkg} ? $packs{$pkg} : undef) );
+ logpackage("${re}install: $pkg");
+ }
+ $donesize += $sizes{$pkg};
+@@ -3204,7 +3375,7 @@
+ # we list them, otherwise we go direct into tlmgr show $pkg mode
+ if ($what !~ m/^(collection|scheme)/i) {
+ tlwarn("(switching to show mode)\n");
+- action_show();
++ action_show(@ARGV);
+ return;
+ }
+ } else {
+@@ -3223,7 +3394,11 @@
+ } elsif ($what =~ m/^scheme/i) {
+ @whattolist = $tlm->schemes;
+ } else {
+- @whattolist = $tlm->list_packages;
++ if ($remotetlpdb->is_virtual) {
++ @whattolist = $tlm->list_packages("-all");
++ } else {
++ @whattolist = $tlm->list_packages;
++ }
+ }
+ foreach (@whattolist) {
+ next if ($_ =~ m/^00texlive/);
+@@ -3232,12 +3407,198 @@
+ } else {
+ print " ";
+ }
+- my $foo = $tlm->get_package($_)->shortdesc;
++ my $tlp = $tlm->get_package($_);
++ if (!$tlp) {
++ if ($remotetlpdb->is_virtual) {
++ # we might have the case that a package is present in a
++ # subsidiary repository, but not pinned, so it will
++ # not be found by ->get_package
++ # In this case we list all repositories shipping it,
++ # but warn that it is not pinned and thus not reachable.
++ my @cand = $remotetlpdb->candidates($_);
++ if (@cand) {
++ my $first = shift @cand;
++ if (defined($first)) {
++ tlwarn("strange, we have a first candidate but no tlp: $_\n");
++ next;
++ }
++ # already shifted away the first element
++ if ($#cand >= 0) {
++ print "$_: --- no installable candidate found, \n";
++ print " but present in subsidiary repositories without a pin.\n";
++ print " This package is not reachable without pinning.\n";
++ print " Repositories containing this package:\n";
++ for my $a (@cand) {
++ my ($t,$r) = split(/\//, $a, 2);
++ my $tlp = $remotetlpdb->get_package($_, $t);
++ my $foo = $tlp->shortdesc;
++ print " $t: ", defined($foo) ? $foo : "(shortdesc missing)" , "\n";
++ }
++ next;
++ } else {
++ tlwarn("strange, package listed but no residual candidates: $_\n");
++ next;
++ }
++ } else {
++ tlwarn("strange, package listed but no candidates: $_\n");
++ next;
++ }
++ } else {
++ tlwarn("strange, package cannot be found in remote tlpdb: $_\n");
++ next;
++ }
++ }
++ my $foo = $tlp->shortdesc;
+ print "$_: ", defined($foo) ? $foo : "(shortdesc missing)" , "\n";
+ }
+ return;
+ }
+
++# REPOSITORY
++#
++# this action manages the list of repositories
++# tlmgr repository list -> lists repositories
++# tlmgr repository add path [tag] -> add repository with optional tag
++# tlmgr repository remove [path|tag] -> removes repository or tag
++# tlmgr repository set path[#tag] [path[#tag] ...] -> sets the list
++#
++
++sub array_to_repository {
++ my %r = @_;
++ my @ret;
++ for my $k (keys %r) {
++ my $v = $r{$k};
++ if ($k eq $v) {
++ push @ret, $k;
++ } else {
++ push @ret, "$v#$k";
++ }
++ }
++ return "@ret";
++}
++sub repository_to_array {
++ my $r = shift;
++ my %r;
++ for my $rr (split ' ', $r) {
++ if ($rr =~ m/^([^#]+)#(.*)$/) {
++ $r{$2} = $1;
++ } else {
++ $r{$rr} = $rr;
++ }
++ }
++ return %r;
++}
++sub action_repository {
++ init_local_db();
++ my $what = shift @ARGV;
++ $what = "list" if !defined($what);
++ my %repos = repository_to_array($localtlpdb->option("location"));
++ if ($what =~ m/^list$/i) {
++ print "List of repositories (with tags if set):\n";
++ for my $k (keys %repos) {
++ my $v = $repos{$k};
++ print "\t$v";
++ if ($k ne $v) {
++ print " ($k)";
++ }
++ print "\n";
++ }
++ return;
++ }
++ if ($what eq "add") {
++ my $p = shift @ARGV;
++ if (!defined($p)) {
++ tlwarn("You need to give a new repository aas argument to add\n");
++ return;
++ }
++ my $t = shift @ARGV;
++ $t = $p if (!defined($t));
++ if (defined($repos{$t})) {
++ tlwarn("This repository or its tag is already defined, no action\n");
++ return;
++ }
++ # TODO more checks needed?
++ # if there was till now only *one* repository and that without
++ # a tag, we give that one the "main" tag which is necessary
++ # for proper operation!
++ my @tags = keys %repos;
++ if ($#tags == 0) {
++ # we have only one repository, check if it has the main tag
++ my $maintag = $tags[0];
++ if ($maintag ne 'main') {
++ $repos{'main'} = $repos{$maintag};
++ delete $repos{$maintag};
++ }
++ }
++ $repos{$t} = $p;
++ $localtlpdb->option("location", array_to_repository(%repos));
++ $localtlpdb->save;
++ return;
++ }
++ if ($what eq "remove") {
++ my $p = shift @ARGV;
++ if (!defined($p)) {
++ tlwarn("Which repository should be removed?\n");
++ return;
++ }
++ my $found = 0;
++ for my $k (keys %repos) {
++ if ($k eq $p || $repos{$k} eq $p) {
++ $found = 1;
++ delete $repos{$k};
++ }
++ }
++ if (!$found) {
++ tlwarn("Cannot find the repository $p\n");
++ } else {
++ $localtlpdb->option("location", array_to_repository(%repos));
++ $localtlpdb->save;
++ }
++ return;
++ }
++ if ($what eq "set") {
++ # TODO TODO
++ # we have to make sure that there is ONE main repository!!!
++ %repos = repository_to_array("@ARGV");
++ $localtlpdb->option("location", array_to_repository(%repos));
++ $localtlpdb->save;
++ return;
++ }
++ # we are still here, unknown command to repository
++ tlwarn("tlmgr: unknown directive to tlmgr repository: $what\n");
++ return;
++}
++
++sub action_candidates {
++ my $what = shift @ARGV;
++ if (!defined($what)) {
++ tlwarn("tlmgr: action candidates needs a package name as argument\n");
++ return;
++ }
++ init_local_db();
++ init_tlmedia();
++ my @cand = $remotetlpdb->candidates($what);
++ if (@cand) {
++ my $first = shift @cand;
++ if (defined($first)) {
++ my ($t,$r) = split(/\//, $first, 2);
++ print "Install candidate for $what from $t ($r)\n";
++ } else {
++ print "No install candidate for $what found.\n";
++ }
++ # already shifted away the first element
++ if ($#cand >= 0) {
++ print "Other repositories providing this package:\n";
++ for my $a (@cand) {
++ my ($t,$r) = split(/\//, $a, 2);
++ print "$t ($r)\n";
++ }
++ }
++ } else {
++ print "Package $what not found.\n";
++ }
++ return;
++}
+
+ # OPTION
+ #
+@@ -4601,6 +4962,82 @@
+ #
+ sub init_tlmedia
+ {
++ # first check if $location contains multiple locations
++ # in this case we go to virtual mode
++ #my %repos = repository_to_array($localtlpdb->option("location"));
++ my %repos = repository_to_array($location);
++ my @tags = keys %repos;
++ # if we have only one repo, but this one contains a name tag #....
++ # then we remove it and save the local tlpdb
++ if ($#tags == 0 && ($location =~ m/#/)) {
++ $location = $repos{$tags[0]};
++ $localtlpdb->option("location", $location);
++ $localtlpdb->save;
++ %repos = repository_to_array($location);
++ }
++ # check if we are only one tag/repo
++ if ($#tags == 0) {
++ # go to normal mode
++ _init_tlmedia();
++ return;
++ }
++ # we are still here, so we have more tags
++
++ # check that there is a main repository
++ if (!TeXLive::TLUtils::member('main', @tags)) {
++ tldie("Cannot find main repository, you have to tag one as main!\n");
++ }
++
++ # TODO TODO
++ # - abstract the set up of a single media tlpdb
++ # - make clear how to check for a already loaded remotetlpdb
++ $remotetlpdb = TeXLive::TLPDB->new();
++ $remotetlpdb->make_virtual;
++
++ my $locstr = $repos{'main'};
++ my $tlmdb = setup_one_remotetlpdb($locstr);
++ $remotetlpdb->virtual_add_tlpdb($tlmdb, "main");
++ for my $t (@tags) {
++ if ($t ne 'main') {
++ my $tlmdb = setup_one_remotetlpdb($repos{$t});
++ $remotetlpdb->virtual_add_tlpdb($tlmdb, $t);
++ $locstr .= " $repos{$t}";
++ }
++ }
++
++ # now check/setup pinning
++ # TODO for now no default pinning file!
++ if ($opts{"pin-file"}) {
++ my @pins = read_pinning_file($opts{"pin-file"});
++ if (@pins) {
++ $remotetlpdb->virtual_pinning(@pins);
++ }
++ } else {
++ # check for pinning file in TEXMFLOCAL/tlpkg/pinning.txt
++ chomp (my $TEXMFLOCAL = `kpsewhich -var-value=TEXMFLOCAL`);
++ debug("trying to load pinning file $TEXMFLOCAL/tlpkg/pinning.txt\n");
++ if (-r "$TEXMFLOCAL/tlpkg/pinning.txt") {
++ my @pins = read_pinning_file("$TEXMFLOCAL/tlpkg/pinning.txt");
++ if (@pins) {
++ info("tlmgr: using pinning file $TEXMFLOCAL/tlpkg/pinning.txt\n");
++ $remotetlpdb->virtual_pinning(@pins);
++ }
++ }
++ }
++
++
++ # this "location-url" line should not be changed since GUI programs
++ # depend on it:
++ print "location-url\t$locstr\n" if $::machinereadable;
++ info("tlmgr: package repository $locstr\n");
++
++}
++
++
++
++
++sub _init_tlmedia
++{
+ if (defined($remotetlpdb) && ($remotetlpdb->root eq $location)) {
+ # nothing to be done
+ return;
+@@ -4614,10 +5051,28 @@
+ $location =~ s,^$TeXLiveServerURL,$mirrorbase,;
+ }
+
++ $remotetlpdb = setup_one_remotetlpdb($location);
+ # this "location-url" line should not be changed since GUI programs
+ # depend on it:
+ print "location-url\t$location\n" if $::machinereadable;
+ info("tlmgr: package repository $location\n");
++}
++
++sub setup_one_remotetlpdb
++{
++ my $location = shift;
++ my $remotetlpdb;
++
++ # TODO
++ # check if that is already loaded!!!
++
++ # choose a mirror if we are asked.
++ if ($location =~ m/^ctan$/i) {
++ $location = give_ctan_mirror();
++ } elsif ($location =~ m,^$TeXLiveServerURL,) {
++ my $mirrorbase = TeXLive::TLUtils::give_ctan_mirror_base();
++ $location =~ s,^$TeXLiveServerURL,$mirrorbase,;
++ }
+
+ # if we talk about a net location try to download the hash of the tlpdb
+ # - if that is possible, check for the locally saved file and if the hash
+@@ -4763,8 +5218,30 @@
+ close($tlfh);
+ }
+ }
++
++ return($remotetlpdb);
+ }
+
++sub read_pinning_file {
++ my $pf = shift;
++ my @pins;
++ my $pfh;
++ if (!open($pfh, "<$pf")) {
++ tlwarn("Pinning file $pf cannot be read: $!\n");
++ return;
++ }
++ debug("Reading pinning file $pf\n");
++ while (my $l = TeXLive::TLUtils::get_full_line($pfh)) {
++ chomp($l);
++ # comments and empty lines are allowed
++ next if ($l =~ m/^\s*#/);
++ next if ($l =~ m/^\s*$/);
++ my ($a, $b) = split(/:/, $l);
++ push @pins, $remotetlpdb->make_pin_data_from_line($l);
++ }
++ close($pfh);
++ return @pins;
++}
+
+
+ # finish handles the -pause option (wait for input from stdin),
+@@ -5561,6 +6038,42 @@
+
+ =back
+
++=head2 repositoy
++
++=over 4
++
++=item B<repository list>
++
++=item B<repository add I<path> [I<tag>]>
++
++=item B<repository remove I<path|tag>>
++
++=item B<repository set I<path>[#I<tag>] [I<path>[#I<tag>] ...]>
++
++This action manages the list of repositories. See L</"MULTIPLE REPOSITORIES">
++below for detailed explanations.
++
++The first form list all configured repositories and the respective tags
++if set. The second form adds a repository (and optionally attaching a
++tag) to the list of repositories. The third from removes a repository,
++either by full path/url, or by tag. The last form sets the list
++of repositories to the items given on the command line, not keeping
++previous settings. Be reminded that one of the repositories has to
++be tagged as B<main>, otherwise all operations will fail.
++
++=back
++
++=head2 candidates
++
++=over 4
++
++=item B<candidates I<pkg>>
++
++Shows the list of available candidates for package I<pkg>. See
++L</"MULTIPLE REPOSITORIES"> below for details.
++
++
++=back
+
+ =head2 option
+
+@@ -6198,6 +6711,118 @@
+ GUI and a simplified GUI with only the important and mostly used
+ settings.
+
++=head1 MULTIPLE REPOSITORIES
++
++Most packages are distributed via the main TeX Live repository, but
++sometimes local repositories are used to provide local packages
++(like commercial fonts, internal styles), as well as alternative
++package repositories for packages that cannot be included in
++proper TeX Live due to license or other reasons.
++
++Without multiple repository support using these additional repositories
++needed an extra invocation and temporarily setting the installation
++source to this additional repository. By setting up all the
++repositories as sources of packages one does not need to
++use multiple invocations of tlmgr anymore.
++
++B<Warning:> Although support for multiple repositories has been
++tested extensively, it does not guarantee proper operation. If you
++want to be sure not to break anything, consider continuing
++using multiple invocations of tlmgr.
++
++When using multiple repositories, one has to be the main repository,
++which distributes most of the TeX Live packages. If you convert
++from a single repository installation to a multiple repository
++installation (by calling tlmgr repository add), the previously
++set repository will be set as the main repository.
++
++By default, even if multiple repositories are configured, packages
++are B<only> installed from the main repository, as long as
++packages are not explicitely pinned to a different repository.
++That also means by simply adding another repository you will
++B<not> be able to install the packages from there, you first
++have to specify which packages should be taken from a
++different repository by specifying some pinning rules.
++
++=head2 Pinning
++
++Pinning a package is done by editing (adding) a file
++
++ TEXMFLOCAL/tlpkg/pinning.txt
++
++which contains lines
++
++ repo:pkg[,pkg]
++
++In this line the C<repo> is either the full URL saved in the
++list or repositories, or one of the tags given. The C<pkg>
++are shell style globs for packages.
++
++By default everything is pinned to the main repository, so
++you can imagine that at the end of the file pinning.txt there
++is a line
++
++ main:*
++
++If a package C<foo> is pinned to a repository, any package
++C<foo> in any other repository, even if it has a higher
++revision number, will not be considered as installable
++candidate.
++
++=head2 Usage example with tlcontrib
++
++- check current repository:
++
++ $ tlmgr repository list
++ List of repositories (with tags if set):
++ /var/www/norbert/tlnet
++
++- add tlcontrib repository (and give it a short name)
++
++ $ tlmgr repository add http://tlcontrib.metatex.org/2011 tlcontrib
++
++- check repositories:
++
++ $ tlmgr repository list
++ List of repositories (with tags if set):
++ http://tlcontrib.metatex.org/2011 (tlcontrib)
++ /var/www/norbert/tlnet (main)
++
++
++- add a pinning to get cowfont from tlcontrib:
++
++ $ mkdir -p `kpsewhich -var-value TEXMFLOCAL`/tlpkg
++ $ echo "tlcontrib:cowfont" > `kpsewhich -var-value TEXMFLOCAL`/tlpkg/pinning.txt
++
++- check that we can find cowfont:
++
++ $ tlmgr show cowfont
++ tlmgr: using pinning file .../tlpkg/pinning.txt
++ tlmgr: package repository /var/www/norbert/tlnet http://tlcontrib.metatex.org/2011
++ package: cowfont
++ category: Package
++ ...
++
++- install cowfont and context (which is needed!)
++
++ $ tlmgr install context cowfont
++ tlmgr: using pinning file .../tlpkg/pinning.txt
++ tlmgr: package repository /var/www/norbert/tlnet http://tlcontrib.metatex.org/2011
++ [1/11, ??:??/??:??] install: context.x86_64-linux @main [84k]
++ [2/11, 00:00/00:00] install: context @main [4274k]
++ [3/11, 00:01/00:02] install: cowfont @tlcontrib [655k]
++ [4/11, 00:05/00:09] install: metapost.x86_64-linux @main [198k]
++ [5/11, 00:05/00:09] install: metapost @main [72k]
++ [6/11, 00:05/00:09] install: mptopdf.x86_64-linux @main [1k]
++ [7/11, 00:06/00:11] install: mptopdf @main [37k]
++ [8/11, 00:06/00:11] install: stmaryrd @main [163k]
++ [9/11, 00:07/00:12] install: xetex.x86_64-linux @main [4442k]
++ [10/11, 00:08/00:08] install: xetex @main [46k]
++ [11/11, 00:08/00:08] install: xetexconfig @main [13k]
++ ...
++
++In the last part you see that the cowfont is installed from
++the tlcontrib part (@tlcontrib).
+
+ =head1 TAXONOMIES
+
diff --git a/Master/tlpkg/dev/quilt-patches/dev.multi-updmap b/Master/tlpkg/dev/quilt-patches/dev.multi-updmap
new file mode 100644
index 00000000000..551bb33f852
--- /dev/null
+++ b/Master/tlpkg/dev/quilt-patches/dev.multi-updmap
@@ -0,0 +1,4209 @@
+---
+ install-tl | 7
+ texmf-dist/web2c/updmap.cfg | 230 +++
+ texmf/scripts/tetex/updmap.pl | 3017 ++++++++++++++++++++++++-----------------
+ texmf/scripts/texlive/tlmgr.pl | 131 -
+ texmf/web2c/updmap-hdr.cfg | 107 -
+ texmf/web2c/updmap.cfg | 256 ---
+ tlpkg/TeXLive/TLUtils.pm | 67
+ 7 files changed, 2071 insertions(+), 1744 deletions(-)
+
+Index: Master/texmf/web2c/updmap.cfg
+===================================================================
+--- Master.orig/texmf/web2c/updmap.cfg 2012-01-12 12:54:40.000000000 +0900
++++ Master/texmf/web2c/updmap.cfg 2012-01-12 12:55:09.000000000 +0900
+@@ -1,31 +1,7 @@
+-# Generated by /home/texlive/karl/Master/bin/i386-linux/tlmgr on Mon Jan 9 04:29:26 2012
+-# $Id: updmap-hdr.cfg 24398 2011-10-26 01:07:22Z preining $
+-#
+-# The full updmap.cfg is generated by concatenating updmap-hdr.cfg with
+-# all the Map and MixedMap lines from an installation, possibly
+-# appending a local configuration file.
+-#
+-# To make local customizations to the map files, please use of the
+-# following methods:
+-#
+-# 1) call
+-# updmap-sys --enable Map=foo.map
+-# for each map file. (Or MixedMap instead of Map, if your font has
+-# both Metafont and outline definitions.) See the updmap --help
+-# documentation.
+-#
+-# 2) add your local map entries to the file
+-# TEXMFLOCAL/web2c/updmap-local.cfg
+-# and then call
+-# tlmgr generate updmap
+-# which will concatenate updmap-local.cfg to the end of the final
+-# updmap.cfg. (You can override the local.cfg file location with the
+-# --localcfg option; see tlmgr --help.)
+-#
+-# If you use either of these methods, your local adaptations will be
+-# preserved when tlmgr updates the installation or this config file.
+-# Manual edits to updmap.cfg may be lost on update.
+-
++#
++# updmap.cfg
++# TEXMFMAIN
++# only the options are defined here
+
+ ################################################################
+ # OPTIONS
+@@ -100,227 +76,3 @@
+ # map file used.
+ kanjiEmbed noEmbed
+
+-################################################################
+-# Map files.
+-################################################################
+-#
+-# There are two possible entries: Map and MixedMap. Both have one additional
+-# argument: the filename of the map file. MixedMap ("mixed" means that
+-# the font is available as bitmap and as outline) lines will not be used
+-# in the default map of dvips if dvipsPreferOutline is false. Inactive
+-# Map files should be marked by "#! " (without the quotes), not just #.
+-#
+-
+-Map OrnementsADF.map
+-Map ArrowsADF.map
+-Map BulletsADF.map
+-MixedMap allrunes.map
+-Map euler.map
+-MixedMap cm.map
+-MixedMap cmextra.map
+-MixedMap cyrillic.map
+-MixedMap latxfont.map
+-MixedMap symbols.map
+-Map uaq.map
+-Map antt.map
+-Map arabi.map
+-MixedMap arabtex.map
+-Map archaicprw.map
+-Map arev.map
+-Map bkaiu.map
+-Map bsmiu.map
+-Map gbsnu.map
+-Map gkaiu.map
+-Map ascii.map
+-Map augie.map
+-Map auncial.map
+-Map aurical.map
+-Map ybv.map
+-MixedMap bbold.map
+-Map belleek.map
+-Map bera.map
+-Map ybd.map
+-Map sqrcaps.map
+-Map boondox.map
+-Map pbsi.map
+-Map burmese.map
+-Map calligra.map
+-Map cantarell.map
+-Map cmin.map
+-MixedMap cbgreek-full.map
+-MixedMap ccpl.map
+-Map ccicons.map
+-Map clm.map
+-Map chemarrow.map
+-Map cjhebrew.map
+-MixedMap cmtext-bsr-interpolated.map
+-Map cm-lgc.map
+-MixedMap cm-super-t1.map
+-MixedMap cm-super-t2a.map
+-MixedMap cm-super-t2b.map
+-MixedMap cm-super-t2c.map
+-MixedMap cm-super-ts1.map
+-MixedMap cm-super-x2.map
+-Map cmcyr.map
+-MixedMap cmll.map
+-Map comfortaa.map
+-Map original-context-symbol.map
+-MixedMap csother.map
+-MixedMap cstext.map
+-Map cyklop.map
+-Map dejavu-type1.map
+-Map dictsym.map
+-Map dstroke.map
+-Map droid.map
+-Map dutchcal.map
+-Map yes.map
+-Map epigrafica.map
+-Map epiolmec.map
+-MixedMap esint.map
+-Map ESSTIX.map
+-Map esvect.map
+-MixedMap ethiop.map
+-MixedMap eurosym.map
+-Map fdsymbol.map
+-Map fge.map
+-Map foekfont.map
+-Map fonetika.map
+-Map fourier-utopia-expert.map
+-Map fourier.map
+-Map frcursive.map
+-Map garuda-c90.map
+-Map gfsartemisia.map
+-Map gfsbaskerville.map
+-Map gfsbodoni.map
+-Map gfscomplutum.map
+-Map gfsdidot.map
+-Map gfsneohellenic.map
+-Map gfsporson.map
+-Map gfssolomos.map
+-Map yfrak.map
+-Map ugq.map
+-Map grverb.map
+-MixedMap hfbright.map
+-MixedMap iby.map
+-Map fi4.map
+-Map Acorn.map
+-Map AnnSton.map
+-Map ArtNouv.map
+-Map ArtNouvc.map
+-Map Carrickc.map
+-Map Eichenla.map
+-Map Eileen.map
+-Map EileenBl.map
+-Map Elzevier.map
+-Map GotIn.map
+-Map GoudyIn.map
+-Map Kinigcap.map
+-Map Konanur.map
+-Map Kramer.map
+-Map MorrisIn.map
+-Map Nouveaud.map
+-Map Romantik.map
+-Map Rothdn.map
+-Map RoyalIn.map
+-Map Sanremo.map
+-Map Starburst.map
+-Map Typocaps.map
+-Map Zallman.map
+-Map iwona.map
+-KanjiMap otf-@kanjiEmbed@.map
+-KanjiMap otf-cktx.map
+-Map kerkis.map
+-Map knitfont.map
+-Map kpfonts.map
+-Map kurier.map
+-Map lato.map
+-Map libertine.map
+-Map yly.map
+-Map linearA.map
+-Map l7x-urwvn.map
+-Map lm.map
+-MixedMap lxfonts.map
+-MixedMap manfnt.map
+-Map marvosym.map
+-Map mathabx.map
+-Map mdbch.map
+-Map mdput.map
+-Map mdugm.map
+-Map mdsymbol.map
+-Map troff-updmap.map
+-MixedMap mflogo.map
+-Map MnSymbol.map
+-MixedMap mongolian.map
+-MixedMap musix.map
+-Map norasi-c90.map
+-Map cherokee.map
+-Map ocrb.map
+-Map oinuit.map
+-Map omega.map
+-Map opensans.map
+-Map paratype-type1.map
+-Map phaistos.map
+-MixedMap pigpen.map
+-MixedMap plother.map
+-MixedMap pltext.map
+-Map ap.map
+-Map prodint.map
+-Map charter.map
+-Map fpls.map
+-Map pazo.map
+-Map utopia.map
+-KanjiMap morisawa.map
+-KanjiMap ptex-@kanjiEmbed@.map
+-Map pxfonts.map
+-Map pxtx.map
+-Map recycle.map
+-Map yrd.map
+-MixedMap rsfs.map
+-Map rsfso.map
+-Map skt.map
+-MixedMap semaf.map
+-Map SkakNew.map
+-Map starfont.map
+-Map icelandic.map
+-MixedMap stmaryrd.map
+-Map tabvar.map
+-Map mathpple.map
+-Map qag.map
+-Map qbk.map
+-Map qcr.map
+-Map qcs.map
+-Map qhv.map
+-Map qpl.map
+-Map qtm.map
+-Map qzc.map
+-Map tfrupee.map
+-MixedMap tipa.map
+-MixedMap trajan.map
+-Map txfonts.map
+-Map gptimes.map
+-Map umj.map
+-MixedMap dvng.map
+-Map yv1.map
+-Map yv2.map
+-Map yv3.map
+-Map yvo.map
+-Map yvt.map
+-Map arevvn.map
+-Map chartervn.map
+-Map cmbrightvn.map
+-Map concretevn.map
+-Map grotesqvn.map
+-Map txttvn.map
+-Map urwvn.map
+-MixedMap vnrother.map
+-MixedMap vnrtext.map
+-Map vntopia.map
+-Map dgj.map
+-Map dmj.map
+-Map mc2j.map
+-Map mcj.map
+-Map mr2j.map
+-Map mrj.map
+-MixedMap wasy.map
+-MixedMap xypic.map
+-MixedMap yhmath.map
+Index: Master/texmf-dist/web2c/updmap.cfg
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ Master/texmf-dist/web2c/updmap.cfg 2012-01-12 12:56:10.000000000 +0900
+@@ -0,0 +1,230 @@
++#
++# updmap.cfg
++# TEXMFDIST
++# only contains the actual maps
++# settings are in TEXMFMAIN
++
++################################################################
++# Map files.
++################################################################
++#
++# There are two possible entries: Map and MixedMap. Both have one additional
++# argument: the filename of the map file. MixedMap ("mixed" means that
++# the font is available as bitmap and as outline) lines will not be used
++# in the default map of dvips if dvipsPreferOutline is false. Inactive
++# Map files should be marked by "#! " (without the quotes), not just #.
++#
++
++Map OrnementsADF.map
++Map ArrowsADF.map
++Map BulletsADF.map
++MixedMap allrunes.map
++Map euler.map
++MixedMap cm.map
++MixedMap cmextra.map
++MixedMap cyrillic.map
++MixedMap latxfont.map
++MixedMap symbols.map
++Map uaq.map
++Map antt.map
++Map arabi.map
++MixedMap arabtex.map
++Map archaicprw.map
++Map arev.map
++Map bkaiu.map
++Map bsmiu.map
++Map gbsnu.map
++Map gkaiu.map
++Map ascii.map
++Map augie.map
++Map auncial.map
++Map aurical.map
++Map ybv.map
++MixedMap bbold.map
++Map belleek.map
++Map bera.map
++Map ybd.map
++Map sqrcaps.map
++Map boondox.map
++Map pbsi.map
++Map burmese.map
++Map calligra.map
++Map cantarell.map
++Map cmin.map
++MixedMap cbgreek-full.map
++MixedMap ccpl.map
++Map ccicons.map
++Map clm.map
++Map chemarrow.map
++Map cjhebrew.map
++MixedMap cmtext-bsr-interpolated.map
++Map cm-lgc.map
++MixedMap cm-super-t1.map
++MixedMap cm-super-t2a.map
++MixedMap cm-super-t2b.map
++MixedMap cm-super-t2c.map
++MixedMap cm-super-ts1.map
++MixedMap cm-super-x2.map
++Map cmcyr.map
++MixedMap cmll.map
++Map comfortaa.map
++Map original-context-symbol.map
++MixedMap csother.map
++MixedMap cstext.map
++Map cyklop.map
++Map dejavu-type1.map
++Map dictsym.map
++Map dstroke.map
++Map droid.map
++Map dutchcal.map
++Map yes.map
++Map epigrafica.map
++Map epiolmec.map
++MixedMap esint.map
++Map ESSTIX.map
++Map esvect.map
++MixedMap ethiop.map
++MixedMap eurosym.map
++Map fdsymbol.map
++Map fge.map
++Map foekfont.map
++Map fonetika.map
++Map fourier-utopia-expert.map
++Map fourier.map
++Map frcursive.map
++Map garuda-c90.map
++Map gfsartemisia.map
++Map gfsbaskerville.map
++Map gfsbodoni.map
++Map gfscomplutum.map
++Map gfsdidot.map
++Map gfsneohellenic.map
++Map gfsporson.map
++Map gfssolomos.map
++Map yfrak.map
++Map ugq.map
++Map grverb.map
++MixedMap hfbright.map
++MixedMap iby.map
++Map fi4.map
++Map Acorn.map
++Map AnnSton.map
++Map ArtNouv.map
++Map ArtNouvc.map
++Map Carrickc.map
++Map Eichenla.map
++Map Eileen.map
++Map EileenBl.map
++Map Elzevier.map
++Map GotIn.map
++Map GoudyIn.map
++Map Kinigcap.map
++Map Konanur.map
++Map Kramer.map
++Map MorrisIn.map
++Map Nouveaud.map
++Map Romantik.map
++Map Rothdn.map
++Map RoyalIn.map
++Map Sanremo.map
++Map Starburst.map
++Map Typocaps.map
++Map Zallman.map
++Map iwona.map
++KanjiMap otf-@kanjiEmbed@.map
++KanjiMap otf-cktx.map
++Map kerkis.map
++Map knitfont.map
++Map kpfonts.map
++Map kurier.map
++Map lato.map
++Map libertine.map
++Map yly.map
++Map linearA.map
++Map l7x-urwvn.map
++Map lm.map
++MixedMap lxfonts.map
++MixedMap manfnt.map
++Map marvosym.map
++Map mathabx.map
++Map mdbch.map
++Map mdput.map
++Map mdugm.map
++Map mdsymbol.map
++Map troff-updmap.map
++MixedMap mflogo.map
++Map MnSymbol.map
++MixedMap mongolian.map
++MixedMap musix.map
++Map norasi-c90.map
++Map cherokee.map
++Map ocrb.map
++Map oinuit.map
++Map omega.map
++Map opensans.map
++Map paratype-type1.map
++Map phaistos.map
++MixedMap pigpen.map
++MixedMap plother.map
++MixedMap pltext.map
++Map ap.map
++Map prodint.map
++Map charter.map
++Map fpls.map
++Map pazo.map
++Map utopia.map
++KanjiMap morisawa.map
++KanjiMap ptex-@kanjiEmbed@.map
++Map pxfonts.map
++Map pxtx.map
++Map recycle.map
++Map yrd.map
++MixedMap rsfs.map
++Map rsfso.map
++Map skt.map
++MixedMap semaf.map
++Map SkakNew.map
++Map starfont.map
++Map icelandic.map
++MixedMap stmaryrd.map
++Map tabvar.map
++Map mathpple.map
++Map qag.map
++Map qbk.map
++Map qcr.map
++Map qcs.map
++Map qhv.map
++Map qpl.map
++Map qtm.map
++Map qzc.map
++Map tfrupee.map
++MixedMap tipa.map
++MixedMap trajan.map
++Map txfonts.map
++Map gptimes.map
++Map umj.map
++MixedMap dvng.map
++Map yv1.map
++Map yv2.map
++Map yv3.map
++Map yvo.map
++Map yvt.map
++Map arevvn.map
++Map chartervn.map
++Map cmbrightvn.map
++Map concretevn.map
++Map grotesqvn.map
++Map txttvn.map
++Map urwvn.map
++MixedMap vnrother.map
++MixedMap vnrtext.map
++Map vntopia.map
++Map dgj.map
++Map dmj.map
++Map mc2j.map
++Map mcj.map
++Map mr2j.map
++Map mrj.map
++MixedMap wasy.map
++MixedMap xypic.map
++MixedMap yhmath.map
+Index: Master/texmf/scripts/texlive/tlmgr.pl
+===================================================================
+--- Master.orig/texmf/scripts/texlive/tlmgr.pl 2012-01-12 12:54:40.000000000 +0900
++++ Master/texmf/scripts/texlive/tlmgr.pl 2012-01-12 13:42:40.000000000 +0900
+@@ -624,47 +624,21 @@
+ chomp(my $TEXMFSYSVAR = `kpsewhich -var-value=TEXMFSYSVAR`);
+ chomp(my $TEXMFSYSCONFIG = `kpsewhich -var-value=TEXMFSYSCONFIG`);
+ chomp(my $TEXMFLOCAL = `kpsewhich -var-value=TEXMFLOCAL`);
++ chomp(my $TEXMFDIST = `kpsewhich -var-value=TEXMFDIST`);
+
+ #
+ # maps handling
+- # if enabled and disabled -> do nothing
+- # if only enabled -> enable it
+- # if only disabled -> disable it
+- # if the option "generate_updmap" is set, then simply ignore all that
+- # and run the equivalent of tlmgr generate updmap
+ {
+ my $updmap_run_needed = 0;
+- my %do_enable;
+- my %do_disable;
+ for my $m (keys %{$::execute_actions{'enable'}{'maps'}}) {
+ $updmap_run_needed = 1;
+- $do_enable{$m} = 1;
+ }
+ for my $m (keys %{$::execute_actions{'disable'}{'maps'}}) {
+ $updmap_run_needed = 1;
+- if (defined($do_enable{$m})) {
+- # we are upgrading because it is disabled and enabled, so
+- # delete the entry in do_enable, it is already
+- delete $do_enable{$m};
+- } else {
+- # not new installed, so simply removed
+- $do_disable{$m} = 1;
+- }
+- }
+- if ($updmap_run_needed && $localtlpdb->option("generate_updmap")) {
+- my $dest = "$TEXMFSYSCONFIG/web2c/updmap.cfg";
+- my $localcfg = "$TEXMFLOCAL/web2c/updmap-local.cfg";
+- info("tlmgr: generate_updmap writing new $dest\n");
+- TeXLive::TLUtils::create_updmap($localtlpdb, $dest, $localcfg);
+- } else {
+- for my $m (keys %do_disable) {
+- $errors += do_cmd_and_check("updmap-sys --nomkmap --nohash --disable $m");
+- }
+- for my $m (keys %do_enable) {
+- my $str = "updmap-sys --nomkmap --nohash --enable " .
+- $::execute_actions{'enable'}{'maps'}{$m} . "=$m";
+- $errors += do_cmd_and_check($str);
+- }
++ }
++ if ($updmap_run_needed) {
++ my $dest = "$TEXMFDIST/web2c/updmap.cfg";
++ TeXLive::TLUtils::create_updmap($localtlpdb, $dest);
+ }
+ $errors += do_cmd_and_check("updmap-sys") if $updmap_run_needed;
+ }
+@@ -3918,17 +3892,15 @@
+ init_local_db();
+
+ # we create fmtutil.cnf, language.dat, language.def in TEXMFSYSVAR and
+- # updmap.cfg in TEXMFSYSCONFIG. The reason is that calls to
+- # updmap-sys (as is done by the tlmgr update call when packages with
+- # maps are installed) will create the updmap.cfg file in
+- # TEXMFSYSCONFIG. It would start from the version in TEXMFSYSVAR, but
+- # after that the TEXMFSYSCONFIG takes precedence and thus the
+- # mechanism explained in updmap.cfg header would not work. We don't
+- # want that. So just use TEXMFSYSCONFIG from the start.
++ # updmap.cfg in TEXMFDIST. The reason is that we are now using an
++ # implementation of updmap that supports multiple updmap files.
++ # Local adaptions should not be made there, but only in TEXMFLOCAL
++ # or TEXMF(SYS)CONFIG updmap.cfg
+ #
+ chomp (my $TEXMFSYSVAR = `kpsewhich -var-value=TEXMFSYSVAR`);
+ chomp (my $TEXMFSYSCONFIG = `kpsewhich -var-value=TEXMFSYSCONFIG`);
+ chomp (my $TEXMFLOCAL = `kpsewhich -var-value=TEXMFLOCAL`);
++ chomp (my $TEXMFDIST = `kpsewhich -var-value=TEXMFDIST`);
+
+ # we do generate all config files, treat $opts{"dest"} as pattern
+ # and make it append the respective extensions
+@@ -4006,10 +3978,9 @@
+ }
+
+ } elsif ($what =~ m/^updmap$/i) {
+- my $dest = $opts{"dest"} || "$TEXMFSYSCONFIG/web2c/updmap.cfg";
+- my $localcfg = $opts{"localcfg"} || "$TEXMFLOCAL/web2c/updmap-local.cfg";
++ my $dest = $opts{"dest"} || "$TEXMFDIST/web2c/updmap.cfg";
+ debug("$0: writing new updmap.cfg to $dest\n");
+- TeXLive::TLUtils::create_updmap($localtlpdb, $dest, $localcfg);
++ TeXLive::TLUtils::create_updmap($localtlpdb, $dest);
+
+ if ($opts{"rebuild-sys"}) {
+ do_cmd_and_check("updmap-sys");
+@@ -6110,7 +6081,6 @@
+ sys_bin (directory to which executables are linked by the path action)
+ sys_man (directory to which man pages are linked by the path action)
+ sys_info (directory to which Info files are linked by the path action)
+- generate_updmap (run the equivalent of tlmgr generate updmap on changes)
+ desktop_integration (Windows-only: create Start menu shortcuts)
+ fileassocs (Windows-only: change file associations)
+ multiuser (Windows-only: install for all users)
+@@ -6166,9 +6136,6 @@
+ Unix-like systems to control the generation of links for executables,
+ info files and man pages. See the C<path> action for details.
+
+-For the C<generate_updmap> option, see the C<updmap> section in
+-L<generate|/"generate [I<option>]... I<what>">.
+-
+ The last three options control behaviour on Windows installations. If
+ C<desktop_integration> is set, then some packages will install items in
+ a sub-folder of the Start menu for C<tlmgr gui>, documentation, etc. If
+@@ -6558,31 +6525,20 @@
+ =back
+
+ The C<generate> action overwrites any manual changes made in the
+-respective files: it recreates them from scratch.
++respective files: it recreates them from scratch based on the
++information of the installed packages, plus local adaptions.
+
+-For C<fmtutil> and the language files, this is normal, and both the TeX
+-Live installer and C<tlmgr> routinely call C<generate> for them.
++The TeX Live installer and C<tlmgr> routinely call C<generate> for
++all of these files.
+
+-For C<updmap>, however, C<tlmgr> does I<not> use C<generate> by default,
+-because the result would be to disable all maps which have been manually
+-installed via S<C<updmap-sys --enable>>, e.g., for proprietary or local
+-fonts, which has been the standard method for adding fonts to TeX
+-installations for years. Rather, the C<generate> action only
+-incorporates the changes in the C<--localcfg> file mentioned below.
+-
+-Notwithstanding the above, if you only use the fonts and font packages
+-within TeX Live, and rigorously maintain your local fonts (if any) using
+-C<updmap-local.cfg>, there is nothing wrong with using C<generate
+-updmap>. It can be helpful in moving from release to release,
+-especially. We use it ourselves to generate the C<updmap.cfg> file in
+-the live source repository. If you want to commit yourself to using
+-C<updmap-local.cfg>, you can set the C<generate_updmap> option and
+-C<tlmgr> will run C<generate updmap> for you on update.
+-
+-In any case, C<tlmgr> updates and maintains the final C<updmap.cfg> in
+-C<TEXMFSYSCONFIG> (while the other generated files are in
+-C<TEXMFSYSVAR>), because that is the location that C<updmap-sys> (via
+-C<tcfmgr>) historically uses.
++For managing your own fonts, please see the documentation of
++updmap, which supports multiple updmap.cfg files. So by simply
++editing TEXMFLOCAL's updmap.cfg they will be accounted for.
++
++In any case, C<tlmgr> updates and maintains C<updmap.cfg> in
++C<TEXMFDIST> (while the other generated files are in
++C<TEXMFSYSVAR>), because that is the location where the fonts
++are installed.
+
+ In more detail: C<generate> remakes any of the five config files
+ C<language.dat>, C<language.def>, C<language.dat.lua>, C<fmtutil.cnf>,
+@@ -6590,26 +6546,27 @@
+ locally-maintained files.
+
+ The locally-maintained files are C<language-local.dat>,
+-C<language-local.def>, C<language-local.dat.lua>, C<fmtutil-local.cnf>,
+-or C<updmap-local.cfg>, searched for in C<TEXMFLOCAL> in the respective
+-directories. If they are present, the final file is made by starting
++C<language-local.def>, C<language-local.dat.lua>, or C<fmtutil-local.cnf>,
++searched for in C<TEXMFLOCAL> in the respective directories.
++The formerly supported C<updmap-local.cfg> is not supported anymore,
++since C<updmap> now supports multiple updmap.cfg files, so local
++additions can be put into an updmap.cfg file in TEXMFLOCAL.
++If local additions are present, the final file is made by starting
+ with the main file, omitting any entries that the local file specifies
+ to be disabled, and finally appending the local file.
+
+ Local files specify entries to be disabled with a comment line, namely
+ one of these:
+
+- #!NAME
+ %!NAME
+ --!NAME
+
+-where C<fmtutil.cnf> and C<updmap.cfg> use C<#>, C<language.dat> and
++where C<fmtutil.cnf> uses C<#>, C<language.dat> and
+ C<language.def> use C<%>, and C<language.dat.lua> use C<-->. In any
+-case, the I<name> is the respective format name, map file name (include
+-the C<.map> extension), or hyphenation pattern identifier. Examples:
++case, the I<name> is the respective format name, or hyphenation pattern
++identifier. Examples:
+
+ #!pdflatex
+- #!lm.map
+ %!german
+ --!usenglishmax
+
+@@ -6622,20 +6579,9 @@
+ syntax as the master files.
+
+ The form C<generate language> recreates both the C<language.dat>, the
+-C<language.def> and the C<language.dat.lua>files, while the forms with
++C<language.def> and the C<language.dat.lua> files, while the forms with
+ extension recreates only the given language file.
+
+-Special consideration for updmap.cfg: in addition to font map files,
+-this file specifies the setting of five options: C<dvipsPreferOutline>,
+-C<LW35>, C<dvipsDownloadBase35>, C<pdftexDownloadBase14>, and
+-C<dvipdfmDownloadBase14>. The defaults for these as set in
+-C<updmap-hdr.cfg> are usually fine. If you want to change them, you can
+-include changed settings for any or all of these five options in your
+-C<updmap-local.cfg> file and they will be respected by C<generate
+-updmap>. For example:
+-
+- dvipsDownloadBase35 true
+-
+ Options:
+
+ =over 4
+@@ -6643,7 +6589,7 @@
+ =item B<--dest> I<output_file>
+
+ specifies the output file (defaults to the respective location in
+-C<TEXMFSYSVAR> for C<language*> and C<fmtutil>, and C<TEXMFSYSCONFIG>
++C<TEXMFSYSVAR> for C<language*> and C<fmtutil>, and C<TEXMFSYSDIST>
+ for C<updmap>). If C<--dest> is given to C<generate language>, it serves
+ as a basename onto which C<.dat> will be appended for the name of the
+ C<language.dat> output file, C<.def> will be
+@@ -6681,13 +6627,6 @@
+ web2c/fmtutil.cnf (and fmtutil-local.cnf);
+ web2c/updmap.cfg (and updmap-local.cfg).
+
+-Final repetition: as explained above, C<tlmgr> does I<not> use
+-C<generate updmap> for font map files. Therefore, if you want to make
+-use of C<updmap-local.cfg>, you must run C<tlmgr generate updmap>
+-and C<updmap-sys> yourself after making any local changes. If you
+-make yourself responsible for rigorously using C<updmap-local.cfg>), set
+-C<option generate_updmap>).
+-
+
+ =head1 CONFIGURATION FILE
+
+Index: Master/texmf/web2c/updmap-hdr.cfg
+===================================================================
+--- Master.orig/texmf/web2c/updmap-hdr.cfg 2011-10-26 10:07:22.000000000 +0900
++++ Master/texmf/web2c/updmap-hdr.cfg 2012-01-12 13:42:09.000000000 +0900
+@@ -1,8 +1,8 @@
+ # $Id: updmap-hdr.cfg 24398 2011-10-26 01:07:22Z preining $
+ #
+-# The full updmap.cfg is generated by concatenating updmap-hdr.cfg with
+-# all the Map and MixedMap lines from an installation, possibly
+-# appending a local configuration file.
++# The updmap.cfg in this tree (TEXMFDIST) is generated by tlmgr by
++# concatenating updmap-hdr.cfg with all the Map and MixedMap lines
++# from an installation.
+ #
+ # To make local customizations to the map files, please use of the
+ # following methods:
+@@ -11,102 +11,11 @@
+ # updmap-sys --enable Map=foo.map
+ # for each map file. (Or MixedMap instead of Map, if your font has
+ # both Metafont and outline definitions.) See the updmap --help
+-# documentation.
++# documentation. This will add lines to the updmap.cfg file in
++# TEXMFSYSCONFIG (creating it if necessary).
+ #
+-# 2) add your local map entries to the file
+-# TEXMFLOCAL/web2c/updmap-local.cfg
+-# and then call
+-# tlmgr generate updmap
+-# which will concatenate updmap-local.cfg to the end of the final
+-# updmap.cfg. (You can override the local.cfg file location with the
+-# --localcfg option; see tlmgr --help.)
++# 2) put all your additional fonts into TEXMFLOCAL and edit
++# TEXMFLOCAL/web2c/updmap.cfg.
+ #
+-# If you use either of these methods, your local adaptations will be
+-# preserved when tlmgr updates the installation or this config file.
+-# Manual edits to updmap.cfg may be lost on update.
+-
+-
+-################################################################
+-# OPTIONS
+-################################################################
+-
++# Manual edits to this updmap.cfg will be lost on update.
+ #
+-# dvipsPreferOutline
+-#
+-# Should dvips (by default) prefer bitmap fonts or outline fonts
+-# if both are available? Independent of this setting, outlines
+-# can be forced by putting "p psfonts_t1.map" into a config file
+-# that dvips reads. Bitmaps (for the fonts in question) can
+-# be forced by putting "p psfonts_pk.map" into a config file.
+-# We provide such config files which can be enabled via
+-# dvips -Poutline ... resp. dvips -Ppk ...
+-#
+-# Valid settings for dvipsPreferOutline are true / false:
+-dvipsPreferOutline true
+-
+-#
+-# LW35
+-#
+-# Which fonts for the "Basic 35 Laserwriter Fonts" do you want to use and
+-# how are the filenames chosen? Valid settings:
+-# URW: URW fonts with "vendor" filenames (e.g. n019064l.pfb)
+-# URWkb: URW fonts with "berry" filenames (e.g. uhvbo8ac.pfb)
+-# ADOBE: Adobe fonts with "vendor" filenames (e.g. hvnbo___.pfb)
+-# ADOBEkb: Adobe fonts with "berry" filenames (e.g. phvbo8an.pfb)
+-LW35 URWkb
+-
+-#
+-# dvipsDownloadBase35
+-#
+-# Should dvips (by default) download the standard 35 LaserWriter fonts
+-# with the document (then set dvipsDownloadBase35 true) or should these
+-# fonts be used from the ps interpreter / printer?
+-# Whatever the default is, the user can override it by specifying
+-# dvips -Pdownload35 ... resp. dvips -Pbuiltin35 ... to either download
+-# the LW35 fonts resp. use the built-in fonts.
+-#
+-# Valid settings are true / false:
+-dvipsDownloadBase35 true
+-
+-#
+-# pdftexDownloadBase14
+-#
+-# Should pdftex download the base 14 pdf fonts? Since some configurations
+-# (ps / pdf tools / printers) use bad default fonts, it is safer to download
+-# the fonts. The pdf files will get bigger, though.
+-# Valid settings are true (download the fonts) or false (don't download
+-# the fonts). Adobe recommends embedding all fonts.
+-pdftexDownloadBase14 true
+-
+-#
+-# dvipdfmDownloadBase14
+-#
+-# Should dvipdfm download the base 14 pdf fonts? Since some configurations
+-# (ps / pdf tools / printers) use bad default fonts, it is safer to download
+-# the fonts. The pdf files will get bigger, though.
+-# Valid settings are true (download the fonts) or false (don't download
+-# the fonts).
+-dvipdfmDownloadBase14 true
+-
+-#
+-# kanjiEmbed
+-#
+-# updmap generates a file kanjix.map for usage with dvipdfmx. Using this
+-# option one can switch between not embedding any kanji font, and several
+-# available.
+-# Valid setting is any string. At updmap run time the @kanjiEmbed@ substring
+-# in a map file name will be replaced with this settings, and the respective
+-# map file used.
+-kanjiEmbed noEmbed
+-
+-################################################################
+-# Map files.
+-################################################################
+-#
+-# There are two possible entries: Map and MixedMap. Both have one additional
+-# argument: the filename of the map file. MixedMap ("mixed" means that
+-# the font is available as bitmap and as outline) lines will not be used
+-# in the default map of dvips if dvipsPreferOutline is false. Inactive
+-# Map files should be marked by "#! " (without the quotes), not just #.
+-#
+-
+Index: Master/tlpkg/TeXLive/TLUtils.pm
+===================================================================
+--- Master.orig/tlpkg/TeXLive/TLUtils.pm 2012-01-05 11:07:33.000000000 +0900
++++ Master/tlpkg/TeXLive/TLUtils.pm 2012-01-12 13:04:16.000000000 +0900
+@@ -2575,67 +2575,10 @@
+ }
+
+ sub create_updmap {
+- my ($tlpdb,$dest,$localconf) = @_;
+- my @tlpdblines = $tlpdb->updmap_cfg_lines(
+- get_disabled_local_configs($localconf, '#'));
+- # we do not use _create_config_files here because we want to
+- # parse the $localconf file for the five options in updmap.cfg
+- #_create_config_files($tlpdb, "texmf/web2c/updmap-hdr.cfg", $dest,
+- # $localconf, 0, '#', \@tlpdblines);
+- my $headfile = "texmf/web2c/updmap-hdr.cfg";
+- my $root = $tlpdb->root;
+- my @lines;
+- my @localconflines;
+- my %configs;
+- if (-r "$localconf") {
+- #
+- # this should be done more intelligently, but for now only add those
+- # lines without any duplication check ...
+- open FOO, "<$localconf"
+- or die "strange, -r ok but cannot open $localconf: $!";
+- my @bla = <FOO>;
+- close(FOO);
+- for my $l (@bla) {
+- my ($k, $v, @rest) = split(' ', $l);
+- if (check_updmap_config_value($k, $v, $localconf)) {
+- $configs{$k} = $v;
+- } else {
+- push @localconflines, $l;
+- }
+- }
+- }
+- #
+- # read the -hdr file and replace the options if given in the local
+- # config file
+- open(INFILE,"<$root/$headfile") or die("Cannot open $root/$headfile");
+- for my $l (<INFILE>) {
+- my ($k, $v, @rest) = split(' ', $l);
+- if (check_updmap_config_value($k, $v, "$root/$headfile")) {
+- if (defined($configs{$k})) {
+- push @lines, "$k $configs{$k}\n";
+- } else {
+- push @lines, $l;
+- }
+- } else {
+- push @lines, $l;
+- }
+- }
+- close (INFILE);
+-
+- # add the lines from the tlpdb
+- push @lines, @tlpdblines;
+-
+- # add additional local config lines
+- push @lines, @localconflines;
+-
+- if ($#lines >= 0) {
+- open(OUTFILE,">$dest")
+- or die("Cannot open $dest for writing: $!");
+-
+- printf OUTFILE "# Generated by %s on %s\n", "$0", scalar localtime;
+- print OUTFILE @lines;
+- close(OUTFILE) || warn "close(>$dest) failed: $!";
+- }
++ my ($tlpdb,$dest) = @_;
++ my @tlpdblines = $tlpdb->updmap_cfg_lines();
++ _create_config_files($tlpdb, "texmf/web2c/updmap-hdr.cfg", $dest,
++ undef, 0, '#', \@tlpdblines);
+ }
+
+ sub check_updmap_config_value {
+@@ -2703,7 +2646,7 @@
+ my @lines = <INFILE>;
+ push @lines, @$tlpdblinesref;
+ close (INFILE);
+- if (-r "$localconf") {
++ if (defined($localconf) && -r $localconf) {
+ #
+ # this should be done more intelligently, but for now only add those
+ # lines without any duplication check ...
+Index: Master/install-tl
+===================================================================
+--- Master.orig/install-tl 2011-10-07 07:50:55.000000000 +0900
++++ Master/install-tl 2012-01-12 13:27:39.000000000 +0900
+@@ -861,11 +861,10 @@
+ "$TEXMFSYSVAR/web2c/fmtutil.cnf",
+ "$TEXMFLOCAL/web2c/fmtutil-local.cnf");
+
+- mkdirhier "$vars{'TEXMFSYSCONFIG'}/web2c";
+- info("writing updmap.cfg to $TEXMFSYSCONFIG/web2c/updmap.cfg\n");
++ mkdirhier "$TEXDIR/texmf-dist/web2c";
++ info("writing updmap.cfg to $TEXDIR/texmf-dist/web2c/updmap.cfg\n");
+ TeXLive::TLUtils::create_updmap ($usedtlpdb,
+- "$TEXMFSYSCONFIG/web2c/updmap.cfg",
+- "$TEXMFLOCAL/web2c/updmap-local.cfg");
++ "$TEXDIR/texmf-dist/web2c/updmap.cfg");
+
+ info("writing language.dat to $TEXMFSYSVAR/tex/generic/config/language.dat\n");
+ TeXLive::TLUtils::create_language_dat($usedtlpdb,
+Index: Master/texmf/scripts/tetex/updmap.pl
+===================================================================
+--- Master.orig/texmf/scripts/tetex/updmap.pl 2011-11-16 07:55:48.000000000 +0900
++++ Master/texmf/scripts/tetex/updmap.pl 2012-01-12 13:48:49.000000000 +0900
+@@ -1,390 +1,452 @@
+-#! /usr/bin/env perl
+-# updmap: utility to maintain map files for outline fonts.
+-#
+-# Copyright 2002-2011 Thomas Esser.
+-# Fabrice Popineau wrote the Perl version.
++#!/usr/bin/env perl
++# mupdmap: utility to maintain map files for outline fonts.
++# $Id: mupdmap.pl 25074 2012-01-12 02:48:37Z preining $
++#
++# Copyright 2011, 2012 Norbert Preining
++# This file is licensed under the GNU General Public License version 2
++# or any later version.
++#
++# History:
++# Original shell script (C) 2002 Thomas Esser
++# first perl variant (C) Fabrice Popineau
++# later adaptions by Reinhard Kotucha and Karl Berry
++# the original versions were licensed under the following agreement:
+ # Anyone may freely use, modify, and/or distribute this file, without
+ # limitation.
++#
++# TODO
++# - check all other invocations
++#
++# TODO after inclusion in TL:
++# - remove the special code that excludes TEXMFMAIN and reorder the rest,
++# should not be necessary anymore
++# - after TL2012? Maybe remove support for reading updmap-local.cfg
++#
++
++my $TEXMFROOT;
+
+ BEGIN {
+ $^W=1;
+- chomp($TEXMFROOT = `kpsewhich -var-value=TEXMFROOT`);
++ $TEXMFROOT = `kpsewhich -var-value=TEXMFROOT`;
++ if ($?) {
++ print STDERR "(m)updmap: Cannot find TEXMFROOT, aborting!\n";
++ exit 1;
++ }
++ chomp($TEXMFROOT);
+ unshift (@INC, "$TEXMFROOT/tlpkg");
+ }
+
+-my $version = '$Id: updmap.pl 24602 2011-11-15 22:55:34Z preining $';
+-
+-use strict;
+-use TeXLive::TLUtils qw(mkdirhier mktexupd win32);
+-use Getopt::Long;
+-$Getopt::Long::autoabbrev=0;
+-Getopt::Long::Configure (qw(ignore_case_always));
+-
+-my $short_progname = "updmap";
+-
+-my $cnfFile;
+-my $cnfFileShort;
+-my $outputdir;
+-my $dvipsoutputdir;
+-my $pdftexoutputdir;
+-my $dvipdfmoutputdir;
+-my $pxdvioutputdir;
+-my $quiet;
+-my $nohash;
+-my $nomkmap;
+-my (@psADOBE, @fileADOBE, @fileADOBEkb, @fileURW);
+-
+-my $enableItem;
+-my @setoptions = ();
+-my @showoptions = ();
+-my @disableItem = ();
+-my $listmaps;
+-my $listavailablemaps;
+-my $syncwithtrees;
+-
+-my $opt_edit;
+-my $opt_force;
+-my $opt_help;
+-my $dry_run;
+-my $TEXMFMAIN;
+-my $TEXMFVAR;
+-
+-my $mode;
+-my $dvipsPreferOutline;
+-my $dvipsDownloadBase35;
+-my $pdftexDownloadBase14;
+-my $pxdviUse;
+-my $kanjiEmbed;
+-
+-my $dvips35;
+-my $pdftex35;
+-my $ps2pk35;
+-
+-my $newcnf;
+-my $copy;
+-my %link;
+-my %maps;
+-my @missing;
+-my $writelog = 0;
+-my $cache = 0; # don't change!
+-my $pdftexStripEnc = 0;
+-
+-# initialize mktexupd
+-my $updLSR=&mktexupd();
+-$updLSR->{mustexist}(0);
+-
+-my @cfg = ();
+-
+-&main;
+-exit 0;
+-
+-
+-# return program name + version string.
+-sub version {
+- my $ret = sprintf "%s (TeX Live) version %s\n", $short_progname, $version;
+- return $ret;
+-}
+-
+-###############################################################################
+-# help()
+-# display help message and exit
+-#
+-sub help {
+- my $usage= <<"EOF";
+-Usage: $short_progname [OPTION] ... [COMMAND]
+- or: $short_progname-sys [OPTION] ... [COMMAND]
+-
+-Update the default font map files used by pdftex, dvips, and dvipdfm(x),
+-(and optionally pxdvi) as determined by the configuration file updmap.cfg
+-(the one returned by running "kpsewhich updmap.cfg").
+-
+-Among other things, these map files are used to determine which fonts
+-should be used as bitmaps and which as outlines, and to determine which
+-fonts are included in the output.
+-
+-By default, the TeX filename database (ls-R) is also updated.
+-
+-Options:
+- --cnffile FILE read FILE for the updmap configuration
+- --dvipdfmoutputdir DIR specify output directory (dvipdfm syntax)
+- --dvipsoutputdir DIR specify output directory (dvips syntax)
+- --pdftexoutputdir DIR specify output directory (pdftex syntax)
+- --pxdvioutputdir DIR specify output directory (pxdvi syntax)
+- --outputdir DIR specify output directory (for all files)
+- --copy cp generic files rather than using symlinks
+- --force recreate files even if config hasn't changed
+- --nomkmap do not recreate map files
+- --nohash do not run texhash
+- -n, --dry-run only show the configuration, no output
+- --quiet, --silent reduce verbosity
+-
+-Commands:
+- --help show this message and exit
+- --version show version information and exit
+- --showoptions ITEM show alternatives for options
+- --setoption OPTION VALUE set option, where OPTION is one of:
+- LW35, dvipsPreferOutline, dvipsDownloadBase35,
+- pdftexDownloadBase14, pxdviUse, or kanjiEmbed
+- --setoption OPTION=VALUE as above, just different syntax
+- --enable MAPTYPE MAPFILE add "MAPTYPE MAPFILE" to updmap.cfg,
+- where MAPTYPE is one of: Map, MixedMap, KanjiMap
+- --enable Map=MAPFILE add \"Map MAPFILE\" to updmap.cfg
+- --enable MixedMap=MAPFILE add \"MixedMap MAPFILE\" to updmap.cfg
+- --enable KanjiMap=MAPFILE add \"KanjiMap MAPFILE\" to updmap.cfg
+- --disable MAPFILE disable MAPFILE, whether Map, MixedMap,
+- or KanjiMap
+- --listmaps list all active and inactive maps
+- --listavailablemaps same as --listmaps, but without
+- unavailable map files
+- --syncwithtrees disable unavailable map files in updmap.cfg
+-
+-Explanation of the map types: the (only) difference between Map and
+-MixedMap is that MixedMap entries are not added to psfonts_pk.map.
+-The purpose is to help users with printers that render Type 1 outline
+-fonts worse than mode-tuned Type 1 bitmap fonts. So, MixedMap is used
+-for fonts that are available as both Type 1 and Metafont.
+-
+-Explanation of the --setoption possibilities:
+-
+- dvipsPreferOutline true|false (default true)
+- Whether dvips uses bitmaps or outlines, when both are available.
+- dvipsDownloadBase35 true|false (default false)
+- Whether dvips includes the standard 35 PostScript fonts in its output.
+- pdftexDownloadBase14 true|false (default true)
+- Whether pdftex includes the standard 14 PDF fonts in its output.
+- pxdviUse true|false (default false)
+- Whether maps for pxdvi (Japanese-patched xdvi) is under control of updmap.
+- LW35 URWkb|URW|ADOBEkb|ADOBE (default URWkb)
+- Adapt the font and file names of the standard 35 PostScript fonts.
+- URWkb URW fonts with "berry" filenames (e.g. uhvbo8ac.pfb)
+- URW URW fonts with "vendor" filenames (e.g. n019064l.pfb)
+- ADOBEkb Adobe fonts with "berry" filenames (e.g. phvbo8an.pfb)
+- ADOBE Adobe fonts with "vendor" filenames (e.g. hvnbo___.pfb)
+- kanjiEmbed (any string)
+
+- These options are only read and acted on by updmap; dvips, pdftex, etc.,
+- do not know anything about them. They work by changing the default map
+- file which the programs read, so they can be overridden by specifying
+- command-line options or configuration files to the programs, as
+- explained at the beginning of updmap.cfg.
++my $version = '$Id: mupdmap.pl 25074 2012-01-12 02:48:37Z preining $';
+
+-Explanation of trees and files normally used:
++use Getopt::Long qw(:config no_autoabbrev ignore_case_always);
++use strict;
++use TeXLive::TLUtils qw(mkdirhier mktexupd win32 basename dirname
++ sort_uniq member);
+
+- updmap both reads and writes TEXMFCONFIG/web2c/updmap.cfg, according to
+- the actions specified.
++#use Data::Dumper;
++#$Data::Dumper::Indent = 1;
+
+- updmap writes the map files for dvips (psfonts.map) and pdftex
+- (pdftex.map) to the TEXMFVAR/fonts/map/updmap/{dvips,pdftex}/
+- directories.
++chomp(my $TEXMFMAIN = `kpsewhich --var-value=TEXMFMAIN`);
++chomp(my $TEXMFVAR = `kpsewhich -var-value=TEXMFVAR`);
++chomp(my $TEXMFCONFIG = `kpsewhich -var-value=TEXMFCONFIG`);
++
++# make sure that on windows *everything* is in lower case for comparison
++if (win32()) {
++ $TEXMFMAIN = lc($TEXMFMAIN);
++ $TEXMFVAR = lc($TEXMFVAR);
++ $TEXMFCONFIG = lc($TEXMFCONFIG);
++ $TEXMFROOT = lc($TEXMFROOT);
++}
++
++my $prg = basename($0);
++
++my %opts = ( quiet => 0, nohash => 0, nomkmap => 0 );
++my $alldata;
++my $updLSR;
++
++my @cmdline_options = (
++ "oldmode",
++ "cnffile=s@",
++ "copy",
++ "disable=s@",
++ "dvipdfmoutputdir=s",
++ "dvipsoutputdir=s",
++ # the following does not work, Getopt::Long looses the first
++ # entry in a multi setting, treat it separately in processOptions
++ # furthermore, it is not supported by older perls, so do it differently
++ #"enable=s{1,2}",
++ "edit",
++ "force",
++ "listavailablemaps",
++ "listmaps|l",
++ "nohash",
++ "nomkmap",
++ "dry-run|n",
++ "outputdir=s",
++ "pdftexoutputdir=s",
++ "pxdvioutputdir=s",
++ "quiet|silent|q",
++ # the following is a correct specification of an option according
++ # to the manual, but it does not work!
++ # we will treat that option by itself in processOptions
++ # furthermore, it is not supported by older perls, so do it differently
++ #"setoption=s@{1,2}",
++ "showoptions=s@",
++ "showoption=s@",
++ "syncwithtrees",
++ "version",
++ "help|h",
++ # some debugging invocations
++ "_readsave=s",
++ "_listupdmap",
++ );
++
++my %settings = (
++ dvipsPreferOutline => {
++ type => "binary",
++ default => "true",
++ },
++ LW35 => {
++ type => "string",
++ possible => [ qw/URW URWkb ADOBE ADOBEkb/ ],
++ default => "URWkb",
++ },
++ dvipsDownloadBase35 => {
++ type => "binary",
++ default => "true",
++ },
++ pdftexDownloadBase14 => {
++ type => "binary",
++ default => "true",
++ },
++ dvipdfmDownloadBase14 => {
++ type => "binary",
++ default => "true",
++ },
++ pxdviUse => {
++ type => "binary",
++ default => "false",
++ },
++ kanjiEmbed => {
++ type => "any",
++ default => "noEmbed",
++ },
++);
+
+- The log file is written to TEXMFVAR/web2c/updmap.log.
++&main();
+
+- When updmap-sys is run, TEXMFSYSCONFIG and TEXMFSYSVAR are used
+- instead. This is the only difference between updmap-sys and updmap.
++###############
+
+- Other locations can be used if overridden on the command line, or these
+- trees don't exist, or you are not using the original TeX Live.
++sub main {
++ processOptions();
+
+- To see the precise locations of the various files that
+- will be read and written, give the -n option (or read the man page).
++ help() if $opts{'help'};
+
+-For step-by-step instructions on making new fonts known to TeX, read
+-http://tug.org/fonts/fontinstall.html. For even more terse
+-instructions, read the beginning of updmap.cfg.
++ if ($opts{'_readsave'}) {
++ read_updmap_files($opts{'_readsave'});
++ print "READING DONE ============================\n";
++ #print Dumper($alldata);
++ $alldata->{'updmap'}{$opts{'_readsave'}}{'changed'} = 1;
++ save_updmap($opts{'_readsave'});
++ exit 0;
++ }
+
+-Report bugs to: tex-k\@tug.org
+-TeX Live home page: <http://tug.org/texlive/>
+-EOF
+-;
+- print &version();
+- print $usage;
+- exit 0;
+-}
++ if ($opts{'showoptions'}) {
++ for my $o (@{$opts{'showoptions'}}) {
++ if (defined($settings{$o})) {
++ if ($settings{$o}{'type'} eq "binary") {
++ print "true false\n";
++ } elsif ($settings{$o}{'type'} eq "string") {
++ print "@{$settings{$o}{'possible'}}\n";
++ } elsif ($settings{$o}{'type'} eq "any") {
++ print "(any string)\n";
++ } else {
++ print "strange: unknown type of option $o\nplease report\n";
++ }
++ } else {
++ print "$prg: unknown option: $o\n";
++ }
++ }
++ exit 0;
++ }
+
++ # config file for changes
++ my $changes_config_file;
+
+-
+-###############################################################################
+-# processOptions()
+-# process cmd line options
+-#
+-sub processOptions {
++ # determine which config files should be used
++ # replaces the former "setupCfgFile"
+ #
+- # We parse the command line twice. The first time is to handle
+- # --setoption, which might take either one or two following values.
+- # the second to handle everything else. The Getopt::Long feature to
+- # handle this is only supported in 5.8.8 (released in 2006) or later,
+- # and a few people run older perls.
+- #
+- my $oldconfig = Getopt::Long::Configure(qw(pass_through));
+- #
+- sub read_for_set_options {
+- my ($setopt, $val) = @_;
+- # check if = occurs in $val, if not, get the next argument
+- if ($val =~ m/=/) {
+- push (@setoptions, $val);
++ # we also determine here where changes will be saved to
++ if ($opts{'cnffile'}) {
++ for my $f (@{$opts{'cnffile'}}) {
++ if (! -f $f) {
++ die "$prg: Config file \"$f\" not found.";
++ }
++ }
++ # in case that config files are given on the command line, the first
++ # in the list is the one where changes will be written to.
++ ($changes_config_file) = @{$opts{'cnffile'}};
++ } else {
++ my @all_files = `kpsewhich -all updmap.cfg`;
++ chomp(@all_files);
++ my @used_files;
++ #
++ # in --oldmode we ignore texmf/web2c/updmap.cfg and reorder some
++ # order to get things right
++ # without --oldmode everything will be used as default to, i.e.
++ # the order is given by kpsewhich -all updmap.cfg
++ if (!$opts{"oldmode"}) {
++ push @used_files, @all_files;
+ } else {
+- my $vv = shift @ARGV;
+- die "$0: --setoption $val given with no value; try --help.\n"
+- if !defined($vv);
+- push (@setoptions, "$val=$vv");
++ # --oldmode
++ for my $f (@all_files) {
++ # make sure that all file names are lower case on windows for comparison
++ $f = lc($f) if win32();
++ if ($f =~ m!$TEXMFROOT/texmf/web2c/updmap.cfg!) {
++ warning("Ignoring $f, it is only a sample file!\n");
++ } else {
++ push @used_files, $f;
++ }
++ }
++ }
++ #
++ # reorder used files: since we ship and manage with tlmgr
++ # the file in TEXMFSYSCONFIG, and TEXMFLOCAL has *lower* priority
++ # then TEXMFSYSCONFIG, we move a TEXMFLOCAL-updmap.cfg if found
++ # after TEXMFCONFIG TEXMFVAR and TEXMFHOME
++ chomp(my $TEXMFLOCAL =`kpsewhich --var-value=TEXMFLOCAL`);
++ chomp(my $TEXMFHOME =`kpsewhich --var-value=TEXMFHOME`);
++ if (win32()) {
++ $TEXMFLOCAL = lc($TEXMFLOCAL);
++ $TEXMFHOME = lc($TEXMFHOME);
++ }
++ my $found = 0;
++ my $TMLabs = Cwd::abs_path($TEXMFLOCAL);
++ if ($TMLabs) {
++ for my $f (@used_files) {
++ my $absf = Cwd::abs_path($f); #should always work
++ if ($absf =~ m/^$TMLabs/) {
++ $found = 1;
++ last;
++ }
++ }
++ }
++ my $old_updmap_local_found = 0;
++ if (-r "$TMLabs/web2c/updmap-local.cfg") {
++ $old_updmap_local_found = 1;
++ warning("Old configuration file TEXMFLOCAL/web2c/updmap-local.cfg found!\n");
++ if ($found) {
++ warning("Will read this file *instead* of TEXMFLOCAL/web2c/updmap.cfg!!!\n");
++ } else {
++ # if TEXMFLOCAL updmap.cfg does not exist, we have to make sure
++ # that the replacement is added to the list of updmap files
++ push @used_files, "$TMLabs/web2c/updmap-local.cfg";
++ }
++ warning("Please consider moving the information from updmap-local.cfg to TEXMFLOCAL/web2c/updmap.cfg\n");
++ }
++ if ($found || $old_updmap_local_found) {
++ my @tmp;
++ my $local_pushed = 0;
++ for my $f (@used_files) {
++ if ($f =~ m!$TEXMFCONFIG|$TEXMFVAR|$TEXMFHOME!) {
++ push @tmp, $f;
++ } else {
++ if (!$local_pushed) {
++ # should we use the return value of grep here, but we know
++ # what we will find?!?!
++ if ($old_updmap_local_found) {
++ push @tmp, "$TEXMFLOCAL/web2c/updmap-local.cfg";
++ } else {
++ push @tmp, "$TEXMFLOCAL/web2c/updmap.cfg";
++ }
++ $local_pushed = 1;
++ }
++ # push the original
++ push @tmp, $f unless ($f =~ m!$TEXMFLOCAL!);
++ }
++ }
++ @used_files = @tmp;
++ }
++ @{$opts{'cnffile'}} = @used_files;
++ # determine the config file that we will use for changes
++ # if in the list of used files contains either one from
++ # TEXMFHOME or TEXMFCONFIG (which is TEXMFSYSCONFIG in the -sys case)
++ # then use the *top* file (which will be either one of the two),
++ # if none of the two exists, create a file in TEXMFCONFIG and use it
++ my $use_top = 0;
++ for my $f (@used_files) {
++ if ($f =~ m!($TEXMFHOME|$TEXMFCONFIG)/web2c/updmap.cfg!) {
++ $use_top = 1;
++ last;
++ }
++ }
++ if ($use_top) {
++ ($changes_config_file) = @used_files;
++ } else {
++ # add the empty config file
++ my $dn = "$TEXMFCONFIG/web2c";
++ $changes_config_file = "$dn/updmap.cfg";
+ }
+ }
+- GetOptions("setoption=s@" => \&read_for_set_options)
+- || die "$0: could not read for --setoption; try --help.\n";
+-
+- # restore old getopt config and read everything else.
+- Getopt::Long::Configure($oldconfig);
+- unless (&GetOptions (
+- "cnffile=s" => \$cnfFile,
+- "copy" => \$copy,
+- "disable=s" => \@disableItem,
+- "dvipdfmoutputdir=s" => \$dvipdfmoutputdir,
+- "dvipsoutputdir=s" => \$dvipsoutputdir,
+- "enable=s" => \$enableItem,
+- "edit" => \$opt_edit,
+- "force" => \$opt_force,
+- "listavailablemaps" => \$listavailablemaps,
+- "l|listmaps" => \$listmaps,
+- "nohash" => \$nohash,
+- "nomkmap" => \$nomkmap,
+- "n|dry-run" => \$dry_run,
+- "outputdir=s" => \$outputdir,
+- "pdftexoutputdir=s" => \$pdftexoutputdir,
+- "pxdvioutputdir=s" => \$pxdvioutputdir,
+- "q|quiet|silent" => \$quiet,
+- "setoption" =>
+- sub {die "$0: --setoption needs an option and value; try --help.\n"},
+- "showoptions=s" => \@showoptions,
+- "syncwithtrees" => \$syncwithtrees,
+- "version" => sub { print &version(); exit(0); },
+- "h|help" => \$opt_help)) {
+- die "Try \"$0 --help\" for more information.\n";
+- }
+-
+- if (@ARGV) {
+- warn "$0: Ignoring unexpected non-option argument(s): @ARGV.\n";
+- }
+-
+- if ($outputdir) {
+- $dvipsoutputdir = $outputdir if (! $dvipsoutputdir);
+- $pdftexoutputdir = $outputdir if (! $pdftexoutputdir);
+- $dvipdfmoutputdir = $outputdir if (! $dvipdfmoutputdir);
+- $pxdvioutputdir = $outputdir if (! $pxdvioutputdir);
+- }
+- if ($cnfFile && ! -f $cnfFile) {
+- die "$0: Config file \"$cnfFile\" not found.\n";
+- }
+- if ($dvipsoutputdir && ! $dry_run && ! -d $dvipsoutputdir) {
+- &mkdirhier ($dvipsoutputdir);
+- }
+- if ($dvipdfmoutputdir && ! $dry_run && ! -d $dvipdfmoutputdir) {
+- &mkdirhier ($dvipdfmoutputdir);
+- }
+- if ($pdftexoutputdir && ! $dry_run && ! -d $pdftexoutputdir) {
+- &mkdirhier ($pdftexoutputdir);
++ print "$prg is using the following updmap.cfg files (in precedence order):\n";
++ for my $f (@{$opts{'cnffile'}}) {
++ print " $f\n";
+ }
+- if ($pxdvioutputdir && ! $dry_run && ! -d $pxdvioutputdir) {
+- &mkdirhier ($pxdvioutputdir);
++ $alldata->{'changes_config'} = $changes_config_file;
++
++ if ($opts{'_listupdmap'}) {
++ exit 0;
+ }
+-}
+
+-
+-###############################################################################
+-# equalize_file(filename[, comment_char])
+-# read a file and return its processed content as a string.
+-# look into the source code for more details.
+-#
+-sub equalize_file {
+- my $file=shift;
+- my $comment=shift;
+- my @temp;
++ read_updmap_files(@{$opts{'cnffile'}});
+
+- open IN, "$file";
+- my @lines = (<IN>);
+- close IN;
+- chomp(@lines);
++ if ($opts{'showoption'}) {
++ for my $o (@{$opts{'showoption'}}) {
++ if (defined($settings{$o})) {
++ my ($v, $vo) = get_cfg($o);
++ print "$o: $v ($vo)\n";
++ } else {
++ print "$prg: unknown option: $o\n";
++ }
++ }
++ exit 0;
++ }
+
+- for (@lines) {
+- s/\s*${comment}.*// if (defined $comment); # remove comments
+- next if /^\s*$/; # remove empty lines
+- s/\s+/ /g; # replace multiple whitespace chars by a single one
+- push @temp, $_;
++ if ($opts{'listmaps'}) {
++ for my $m (keys %{$alldata->{'maps'}}) {
++ my $origin = $alldata->{'maps'}{$m}{'origin'};
++ print $alldata->{'updmap'}{$origin}{'maps'}{$m}{'type'}, " $m ",
++ $alldata->{'updmap'}{$origin}{'maps'}{$m}{'status'}, " in $origin\n";
++ }
++ exit 0;
+ }
+- return join('X', sort(@temp));
+-}
+
+-###############################################################################
+-# files_are_different(file_A, file_B[, comment_char])
+-# compare two equalized files.
+-#
+-sub files_are_different {
+- my $file_A=shift;
+- my $file_B=shift;
+- my $comment=shift;
+- my $retval=0;
++ # we do changes always in the used config file with the highest
++ # priority
++ my $bakFile = $changes_config_file;
++ $bakFile =~ s/\.cfg$/.bak/;
++ my $changed = 0;
+
+- my $A=equalize_file("$file_A", $comment);
+- my $B=equalize_file("$file_B", $comment);
+- $retval=1 unless ($A eq $B);
+- return $retval;
+-}
++ if ($opts{'syncwithtrees'}) {
++ my @missing = read_map_files();
++ if (@missing) {
++ print "Missing map files found, disabling them in $changes_config_file\n";
++ for my $m (@missing) {
++ $changed ||= disableMap($m);
++ }
++ # the original script did not run any update of the map files here,
++ # should we do that?
++ }
++ exit 0;
++ }
+
+-###############################################################################
+-# files_are_equal(file_A, file_B[, comment_char])
+-# compare two equalized files. Same as files_are_different() with
+-# return value inverted.
+-#
+-sub files_are_equal {
+- return (&files_are_different (@_))? 0:1;
+-}
++ my $cmd;
++ if ($opts{'edit'}) {
++ if ($opts{"dry-run"}) {
++ printf STDERR "No, are you joking, you want to edit with --dry-run?\n";
++ printf STDERR "Not doing that, bye bye!\n";
++ exit 1;
++ }
++ # it's not a good idea to edit updmap.cfg manually these days,
++ # but for compatibility we'll silently keep the option.
++ $cmd = 'edit';
++ my $editor = $ENV{'VISUAL'} || $ENV{'EDITOR'};
++ $editor ||= (&win32 ? "notepad" : "vi");
++ if (-r $changes_config_file) {
++ &copyFile($changes_config_file, $bakFile);
++ } else {
++ touch($bakFile);
++ touch($changes_config_file);
++ }
++ system($editor, $changes_config_file);
++ $changed = files_are_different($bakFile, $changes_config_file);
++ } elsif ($opts{'setoption'}) {
++ $cmd = 'setOption';
++ $changed = setOptions (@{$opts{'setoption'}});
++ } elsif ($opts{'enable'} || $opts{'disable'}) {
++ $cmd = 'enableMap';
++ $changed ||= enable_disable_maps(@{$opts{'enable'}}, @{$opts{'disable'}});
++ }
+
+-###############################################################################
+-# files_are_identical(file_A, file_B)
+-# compare two files. Same as cmp(1).
+-#
+-sub files_are_identical {
+- my $file_A=shift;
+- my $file_B=shift;
+- my $retval=0;
++ # what does this?
++ $updLSR = &mktexupd();
++ $updLSR->{mustexist}(0);
+
+- open IN, "$file_A";
+- my $A=(<IN>);
+- close IN;
+- open IN, "$file_B";
+- my $B=(<IN>);
+- close IN;
++ if ($cmd && !$opts{'force'} && !$changed) {
++ print "$changes_config_file unchanged. Map files not recreated.\n"
++ if !$opts{'quiet'};
++ } else {
++ if (!$opts{'nomkmap'}) {
++ # before we continue we have to make sure that a newly created config
++ # file is acually used. So we have to push the $changes_config_file
++ # onto the list of available files. Since it is already properly
++ # initialized and the merging is done later, all settings should be
++ # honored
++ my @aaa = @{$alldata->{'order'}};
++ unshift @aaa, $changes_config_file;
++ $alldata->{'order'} = [ @aaa ];
++ setupOutputDir("dvips");
++ setupOutputDir("pdftex");
++ setupOutputDir("dvipdfmx");
++ setupOutputDir("dvipdfm");
++ setupOutputDir("pxdvi");
++ my @missing = read_map_files();
++ if (@missing) {
++ print STDERR "\nERROR: The following map file(s) couldn't be found:\n";
++ for my $m (@missing) {
++ my $orig = $alldata->{'maps'}{$m}{'origin'};
++ print STDERR "\t$m (in $orig)\n";
++ }
++ print STDERR "\n\tDid you run mktexlsr?\n\n" .
++ "\tYou can disable non-existent map entries using the option\n".
++ "\t --syncwithtrees.\n\n";
++ exit 1;
++ }
++ merge_data();
++ # for inspecting the output
++ #print STDERR Data::Dumper->Dump([$alldata], [qw(mapdata)]);
++ #print Dumper($alldata);
++ mkMaps();
++ }
++ unlink ($bakFile) if (-r $bakFile);
++ }
+
+- $retval=1 if ($A eq $B);
+- return $retval;
++ if (!$opts{'nohash'}) {
++ print "$prg: Updating ls-R files.\n" if !$opts{'quiet'};
++ $updLSR->{exec}() unless $opts{"dry-run"};
++ }
+ }
+
+-###############################################################################
+-# getLines()
++##################################################################
+ #
+-###############################################################################
+-sub getLines {
++#
++
++sub getFonts {
++ my ($first, @rest) = @_;
++ my $getall = 0;
++ my @maps = ();
++ if ($first eq "-all") {
++ $getall = 1;
++ @maps = @rest;
++ } else {
++ @maps = ($first, @rest);
++ }
+ my @lines = ();
+- foreach my $fname (@_) {
+- next if (! $fname);
+- if (! exists $maps{"$fname"}) {
+- open FILE, "<$fname" or die "$0: can't get lines from $fname: $!";
+- my @file=<FILE>;
+- close FILE;
+- if ($writelog) {
+- print LOG ("\n$fname:\n");
+- foreach my $line (@file) {
+- next if $line =~ /^\s*%/; # comment
+- next if $line =~ /^\s*#/; # comment
+- next if $line =~ /^\s*$/; # empty line
+- my $tfm;
+- ($tfm)=split ' ', $line;
+- print LOG "$tfm\n";
++ for my $m (@maps) {
++ if (defined($alldata->{'maps'}{$m})) {
++ print LOG "\n" . $alldata->{'maps'}{$m}{'fullpath'} . ":\n" unless $opts{'dry-run'};
++ push @lines, "% $m";
++ for my $k (sort keys %{$alldata->{'maps'}{$m}{'fonts'}}) {
++ if ($getall || $alldata->{'fonts'}{$k}{'origin'} eq $m) {
++ if (defined($alldata->{'maps'}{$m}{'fonts'}{$k})) {
++ push @lines, "$k " . $alldata->{'maps'}{$m}{'fonts'}{$k};
++ } else {
++ print "undefined fonts for $k in $m ?!?!?\n";
++ }
++ print LOG "$k\n" unless $opts{'dry-run'};
+ }
+ }
+- $maps{"$fname"} = [ @file ] if ($cache);
+- push @lines, @file;
+- } else {
+- push @lines, @{$maps{"$fname"}};
+ }
+ }
+ chomp @lines;
+@@ -397,50 +459,33 @@
+ #
+ sub writeLines {
+ my ($fname, @lines) = @_;
++ return if $opts{"dry-run"};
+ map { ($_ !~ m/\n$/ ? s/$/\n/ : $_ ) } @lines;
+- open FILE, ">$fname" or die "$0: can't write lines to $fname: $!";
++ open FILE, ">$fname" or die "$prg: can't write lines to $fname: $!";
+ print FILE @lines;
+ close FILE;
+ }
+
+ ###############################################################################
+-# copyFile()
+-# copy file $src to $dst, sets $dst creation and mod time
++# to_pdftex()
++# if $pdftexStripEnc is set, strip "PS_Encoding_Name ReEncodeFont"
++# from map entries; they are ignored by pdftex. But since the sh
++# incarnation of updmap included them, and we want to minimize
++# differences, this is not done by default.
+ #
+-sub copyFile {
+- my ($src, $dst) = @_;
+- my $dir;
+- ($dir=$dst)=~s/(.*)\/.*/$1/;
+- mkdirhier $dir;
+-
+- $src eq $dst && return "can't copy $src to itself!\n";
+-
+- open IN, "<$src" or die "$0: can't open source file $src for copying: $!";
+- open OUT, ">$dst";
+-
+- binmode(IN);
+- binmode(OUT);
+- print OUT <IN>;
+- close(OUT);
+- close(IN);
+- my @t = stat($src);
+- utime($t[8], $t[9], $dst);
+-}
+-
+-###############################################################################
+-# SymlinkOrCopy(dir, src, dest)
+-# create symlinks if possible, otherwise copy files
+-#
+-sub SymlinkOrCopy {
+- my ($dir, $src, $dest) = @_;
+- if (&win32 || $copy) { # always copy
+- &copyFile("$dir/$src", "$dir/$dest");
+- } else { # symlink if supported by fs, copy otherwise
+- system("cd \"$dir\" && ln -s $src $dest 2>/dev/null || "
+- . "cp -p \"$dir/$src\" \"$dir/$dest\"");
++sub to_pdftex {
++ my $pdftexStripEnc = 0;
++ return @_ unless $pdftexStripEnc;
++ my @in = @_;
++ my @out;
++ foreach my $line (@in) {
++ if ($line =~ /^(.*\s+)(\S+\s+ReEncodeFont\s)(.*)/) {
++ $line = "$1$3";
++ $line =~ s/\s+\"\s+\"\s+/ /;
++ }
++ push @out, $line;
+ }
+- # remember for "Files generated" in &mkMaps.
+- $link{"$dest"}="$src";
++ return @out;
+ }
+
+ ###############################################################################
+@@ -448,35 +493,208 @@
+ # set symlink for psfonts.map according to dvipsPreferOutline variable
+ #
+ sub setupSymlinks {
++ my ($dvipsPreferOutline, $dvipsoutputdir, $pdftexDownloadBase14, $pdftexoutputdir) = @_;
+ my $src;
++ my %link;
++ my @link;
+
+- if ($dvipsPreferOutline) {
++ if ($dvipsPreferOutline eq "true") {
+ $src = "psfonts_t1.map";
+ } else {
+ $src = "psfonts_pk.map";
+ }
+- unlink "$dvipsoutputdir/psfonts.map";
+- &SymlinkOrCopy("$dvipsoutputdir", "$src", "psfonts.map");
++ unlink "$dvipsoutputdir/psfonts.map" unless $opts{"dry-run"};
++ push @link, &SymlinkOrCopy("$dvipsoutputdir", "$src", "psfonts.map");
+
+- if ($pdftexDownloadBase14) {
++ if ($pdftexDownloadBase14 eq "true") {
+ $src = "pdftex_dl14.map";
+ } else {
+ $src = "pdftex_ndl14.map";
+ }
+- unlink "$pdftexoutputdir/pdftex.map";
+- &SymlinkOrCopy("$pdftexoutputdir", "$src", "pdftex.map");
++ unlink "$pdftexoutputdir/pdftex.map" unless $opts{"dry-run"};
++ push @link, &SymlinkOrCopy("$pdftexoutputdir", "$src", "pdftex.map");
++ %link = @link;
++ return \%link;
++}
++
++###############################################################################
++# SymlinkOrCopy(dir, src, dest)
++# create symlinks if possible, otherwise copy files
++#
++sub SymlinkOrCopy {
++ my ($dir, $src, $dest) = @_;
++ return ($src, $dest) if $opts{"dry-run"};
++ if (&win32 || $opts{'copy'}) { # always copy
++ &copyFile("$dir/$src", "$dir/$dest");
++ } else { # symlink if supported by fs, copy otherwise
++ system("cd \"$dir\" && ln -s $src $dest 2>/dev/null || "
++ . "cp -p \"$dir/$src\" \"$dir/$dest\"");
++ }
++ # remember for "Files generated" in &mkMaps.
++ return ($dest, $src);
+ }
+
+-
++
+ ###############################################################################
+-# transLW35(args ...)
++# transLW35(mode args ...)
+ # transform fontname and filenames according to transformation specified
+ # by mode. Possible values:
+ # URW|URWkb|ADOBE|ADOBEkb
+ #
+ sub transLW35 {
+- my ($name) = @_;
+- my @lines = &getLines($name);
++ my ($mode, @lines) = @_;
++
++ my @psADOBE = (
++ 's/ URWGothicL-Demi / AvantGarde-Demi /',
++ 's/ URWGothicL-DemiObli / AvantGarde-DemiOblique /',
++ 's/ URWGothicL-Book / AvantGarde-Book /',
++ 's/ URWGothicL-BookObli / AvantGarde-BookOblique /',
++ 's/ URWBookmanL-DemiBold / Bookman-Demi /',
++ 's/ URWBookmanL-DemiBoldItal / Bookman-DemiItalic /',
++ 's/ URWBookmanL-Ligh / Bookman-Light /',
++ 's/ URWBookmanL-LighItal / Bookman-LightItalic /',
++ 's/ NimbusMonL-Bold / Courier-Bold /',
++ 's/ NimbusMonL-BoldObli / Courier-BoldOblique /',
++ 's/ NimbusMonL-Regu / Courier /',
++ 's/ NimbusMonL-ReguObli / Courier-Oblique /',
++ 's/ NimbusSanL-Bold / Helvetica-Bold /',
++ 's/ NimbusSanL-BoldCond / Helvetica-Narrow-Bold /',
++ 's/ NimbusSanL-BoldItal / Helvetica-BoldOblique /',
++ 's/ NimbusSanL-BoldCondItal / Helvetica-Narrow-BoldOblique /',
++ 's/ NimbusSanL-Regu / Helvetica /',
++ 's/ NimbusSanL-ReguCond / Helvetica-Narrow /',
++ 's/ NimbusSanL-ReguItal / Helvetica-Oblique /',
++ 's/ NimbusSanL-ReguCondItal / Helvetica-Narrow-Oblique /',
++ 's/ CenturySchL-Bold / NewCenturySchlbk-Bold /',
++ 's/ CenturySchL-BoldItal / NewCenturySchlbk-BoldItalic /',
++ 's/ CenturySchL-Roma / NewCenturySchlbk-Roman /',
++ 's/ CenturySchL-Ital / NewCenturySchlbk-Italic /',
++ 's/ URWPalladioL-Bold / Palatino-Bold /',
++ 's/ URWPalladioL-BoldItal / Palatino-BoldItalic /',
++ 's/ URWPalladioL-Roma / Palatino-Roman /',
++ 's/ URWPalladioL-Ital / Palatino-Italic /',
++ 's/ StandardSymL / Symbol /',
++ 's/ NimbusRomNo9L-Medi / Times-Bold /',
++ 's/ NimbusRomNo9L-MediItal / Times-BoldItalic /',
++ 's/ NimbusRomNo9L-Regu / Times-Roman /',
++ 's/ NimbusRomNo9L-ReguItal / Times-Italic /',
++ 's/ URWChanceryL-MediItal / ZapfChancery-MediumItalic /',
++ 's/ Dingbats / ZapfDingbats /',
++ );
++
++ my @fileADOBEkb = (
++ 's/\buagd8a.pfb\b/pagd8a.pfb/',
++ 's/\buagdo8a.pfb\b/pagdo8a.pfb/',
++ 's/\buagk8a.pfb\b/pagk8a.pfb/',
++ 's/\buagko8a.pfb\b/pagko8a.pfb/',
++ 's/\bubkd8a.pfb\b/pbkd8a.pfb/',
++ 's/\bubkdi8a.pfb\b/pbkdi8a.pfb/',
++ 's/\bubkl8a.pfb\b/pbkl8a.pfb/',
++ 's/\bubkli8a.pfb\b/pbkli8a.pfb/',
++ 's/\bucrb8a.pfb\b/pcrb8a.pfb/',
++ 's/\bucrbo8a.pfb\b/pcrbo8a.pfb/',
++ 's/\bucrr8a.pfb\b/pcrr8a.pfb/',
++ 's/\bucrro8a.pfb\b/pcrro8a.pfb/',
++ 's/\buhvb8a.pfb\b/phvb8a.pfb/',
++ 's/\buhvb8ac.pfb\b/phvb8an.pfb/',
++ 's/\buhvbo8a.pfb\b/phvbo8a.pfb/',
++ 's/\buhvbo8ac.pfb\b/phvbo8an.pfb/',
++ 's/\buhvr8a.pfb\b/phvr8a.pfb/',
++ 's/\buhvr8ac.pfb\b/phvr8an.pfb/',
++ 's/\buhvro8a.pfb\b/phvro8a.pfb/',
++ 's/\buhvro8ac.pfb\b/phvro8an.pfb/',
++ 's/\buncb8a.pfb\b/pncb8a.pfb/',
++ 's/\buncbi8a.pfb\b/pncbi8a.pfb/',
++ 's/\buncr8a.pfb\b/pncr8a.pfb/',
++ 's/\buncri8a.pfb\b/pncri8a.pfb/',
++ 's/\buplb8a.pfb\b/pplb8a.pfb/',
++ 's/\buplbi8a.pfb\b/pplbi8a.pfb/',
++ 's/\buplr8a.pfb\b/pplr8a.pfb/',
++ 's/\buplri8a.pfb\b/pplri8a.pfb/',
++ 's/\busyr.pfb\b/psyr.pfb/',
++ 's/\butmb8a.pfb\b/ptmb8a.pfb/',
++ 's/\butmbi8a.pfb\b/ptmbi8a.pfb/',
++ 's/\butmr8a.pfb\b/ptmr8a.pfb/',
++ 's/\butmri8a.pfb\b/ptmri8a.pfb/',
++ 's/\buzcmi8a.pfb\b/pzcmi8a.pfb/',
++ 's/\buzdr.pfb\b/pzdr.pfb/',
++ );
++
++ my @fileURW = (
++ 's/\buagd8a.pfb\b/a010015l.pfb/',
++ 's/\buagdo8a.pfb\b/a010035l.pfb/',
++ 's/\buagk8a.pfb\b/a010013l.pfb/',
++ 's/\buagko8a.pfb\b/a010033l.pfb/',
++ 's/\bubkd8a.pfb\b/b018015l.pfb/',
++ 's/\bubkdi8a.pfb\b/b018035l.pfb/',
++ 's/\bubkl8a.pfb\b/b018012l.pfb/',
++ 's/\bubkli8a.pfb\b/b018032l.pfb/',
++ 's/\bucrb8a.pfb\b/n022004l.pfb/',
++ 's/\bucrbo8a.pfb\b/n022024l.pfb/',
++ 's/\bucrr8a.pfb\b/n022003l.pfb/',
++ 's/\bucrro8a.pfb\b/n022023l.pfb/',
++ 's/\buhvb8a.pfb\b/n019004l.pfb/',
++ 's/\buhvb8ac.pfb\b/n019044l.pfb/',
++ 's/\buhvbo8a.pfb\b/n019024l.pfb/',
++ 's/\buhvbo8ac.pfb\b/n019064l.pfb/',
++ 's/\buhvr8a.pfb\b/n019003l.pfb/',
++ 's/\buhvr8ac.pfb\b/n019043l.pfb/',
++ 's/\buhvro8a.pfb\b/n019023l.pfb/',
++ 's/\buhvro8ac.pfb\b/n019063l.pfb/',
++ 's/\buncb8a.pfb\b/c059016l.pfb/',
++ 's/\buncbi8a.pfb\b/c059036l.pfb/',
++ 's/\buncr8a.pfb\b/c059013l.pfb/',
++ 's/\buncri8a.pfb\b/c059033l.pfb/',
++ 's/\buplb8a.pfb\b/p052004l.pfb/',
++ 's/\buplbi8a.pfb\b/p052024l.pfb/',
++ 's/\buplr8a.pfb\b/p052003l.pfb/',
++ 's/\buplri8a.pfb\b/p052023l.pfb/',
++ 's/\busyr.pfb\b/s050000l.pfb/',
++ 's/\butmb8a.pfb\b/n021004l.pfb/',
++ 's/\butmbi8a.pfb\b/n021024l.pfb/',
++ 's/\butmr8a.pfb\b/n021003l.pfb/',
++ 's/\butmri8a.pfb\b/n021023l.pfb/',
++ 's/\buzcmi8a.pfb\b/z003034l.pfb/',
++ 's/\buzdr.pfb\b/d050000l.pfb/',
++ );
++
++ my @fileADOBE = (
++ 's/\buagd8a.pfb\b/agd_____.pfb/',
++ 's/\buagdo8a.pfb\b/agdo____.pfb/',
++ 's/\buagk8a.pfb\b/agw_____.pfb/',
++ 's/\buagko8a.pfb\b/agwo____.pfb/',
++ 's/\bubkd8a.pfb\b/bkd_____.pfb/',
++ 's/\bubkdi8a.pfb\b/bkdi____.pfb/',
++ 's/\bubkl8a.pfb\b/bkl_____.pfb/',
++ 's/\bubkli8a.pfb\b/bkli____.pfb/',
++ 's/\bucrb8a.pfb\b/cob_____.pfb/',
++ 's/\bucrbo8a.pfb\b/cobo____.pfb/',
++ 's/\bucrr8a.pfb\b/com_____.pfb/',
++ 's/\bucrro8a.pfb\b/coo_____.pfb/',
++ 's/\buhvb8a.pfb\b/hvb_____.pfb/',
++ 's/\buhvb8ac.pfb\b/hvnb____.pfb/',
++ 's/\buhvbo8a.pfb\b/hvbo____.pfb/',
++ 's/\buhvbo8ac.pfb\b/hvnbo___.pfb/',
++ 's/\buhvr8a.pfb\b/hv______.pfb/',
++ 's/\buhvr8ac.pfb\b/hvn_____.pfb/',
++ 's/\buhvro8a.pfb\b/hvo_____.pfb/',
++ 's/\buhvro8ac.pfb\b/hvno____.pfb/',
++ 's/\buncb8a.pfb\b/ncb_____.pfb/',
++ 's/\buncbi8a.pfb\b/ncbi____.pfb/',
++ 's/\buncr8a.pfb\b/ncr_____.pfb/',
++ 's/\buncri8a.pfb\b/nci_____.pfb/',
++ 's/\buplb8a.pfb\b/pob_____.pfb/',
++ 's/\buplbi8a.pfb\b/pobi____.pfb/',
++ 's/\buplr8a.pfb\b/por_____.pfb/',
++ 's/\buplri8a.pfb\b/poi_____.pfb/',
++ 's/\busyr.pfb\b/sy______.pfb/',
++ 's/\butmb8a.pfb\b/tib_____.pfb/',
++ 's/\butmbi8a.pfb\b/tibi____.pfb/',
++ 's/\butmr8a.pfb\b/tir_____.pfb/',
++ 's/\butmri8a.pfb\b/tii_____.pfb/',
++ 's/\buzcmi8a.pfb\b/zcmi____.pfb/',
++ 's/\buzdr.pfb\b/zd______.pfb/',
++ );
+
+ if ($mode eq "" || $mode eq "URWkb") {
+ # do nothing
+@@ -497,963 +715,1300 @@
+ }
+
+ ###############################################################################
+-# locateWeb2c (file ...)
+-# apply kpsewhich with format 'web2c files'
+-#
+-sub locateWeb2c {
+- my @files = @_;
+- return @files if ($#files < 0);
+-
+- @files = split (/\n/, `kpsewhich --format="web2c files" @files`);
+- if (wantarray) {
+- return @files;
+- }
+- else {
+- return $files[0];
++# cidx2dvips()
++# reads from stdin, writes to stdout. It transforms "cid-x"-like syntax into
++# "dvips"-like syntax.
++###############################################################################
++sub cidx2dvips {
++ my ($s) = @_;
++ my @d;
++ foreach (@$s) {
++ if (m/^%/) {
++ push(@d, $_);
++ next;
++ }
++ s/,BoldItalic/ -s .3/;
++ s/,Bold//;
++ s/,Italic/ -s .3/;
++ s/\s\s*/ /g;
++ if ($_ =~ /.*[@\:\/,]/) {next;}
++ elsif ($_ =~ /^[^ ][^ ]* unicode /) {next;}
++ s/^([^ ][^ ]* [^ ][^ ]* [^ ][^ ]*)\.[Oo][Tt][Ff]/$1/;
++ s/^([^ ][^ ]* [^ ][^ ]* [^ ][^ ]*)\.[Tt][Tt][FfCc]/$1/;
++ s/$/ %/;
++ s/^(([^ ]*).*)/$1$2/;
++ s/^([^ ][^ ]* ([^ ][^ ]*) !*([^ ][^ ]*).*)/$1 $3-$2/;
++ s/^(.* -e ([.0-9-][.0-9-]*).*)/$1 "$2 ExtendFont"/;
++ s/^(.* -s ([.0-9-][.0-9-]*).*)/$1 "$2 SlantFont"/;
++ s/.*%//;
++ push(@d, $_);
++ }
++ return @d
++}
++
++sub get_cfg {
++ my ($v) = @_;
++ if (defined($alldata->{'merged'}{'setting'}{$v})) {
++ return ( $alldata->{'merged'}{'setting'}{$v}{'val'},
++ $alldata->{'merged'}{'setting'}{$v}{'origin'} );
++ } else {
++ return ($settings{$v}{'default'}, "default");
+ }
+ }
+
+-###############################################################################
+-# locateMap (file ...)
+-# apply kpsewhich with format 'map'
+-#
+-sub locateMap {
+- my @maps = @_;
+- return @maps if ($#maps < 0);
++sub mkMaps {
++ my $logfile;
+
+- my @files = `kpsewhich --format=map @maps`;
+- chomp @files;
++ $logfile = "$TEXMFVAR/web2c/updmap.log";
+
+- foreach my $map (@maps) {
+- push @missing, $map if (! grep /\/$map(\.map)?$/, @files);
++ if (! $opts{'dry-run'}) {
++ mkdirhier("$TEXMFVAR/web2c");
++ open LOG, ">$logfile"
++ or die "$prg: Can't open log file \"$logfile\": $!";
++ print LOG &version();
++ printf LOG "%s\n\n", scalar localtime();
++ print LOG "Using the following config files:\n";
++ for (@{$opts{'cnffile'}}) {
++ print LOG " $_\n";
++ }
+ }
+-
+- if (wantarray) {
+- return @files;
+- } else {
+- return $files[0];
++ sub print_and_log {
++ my $str=shift;
++ print $str if !$opts{'quiet'};
++ print LOG $str unless $opts{'dry-run'};
++ }
++ sub only_log {
++ print LOG shift unless $opts{'dry-run'};
+ }
+-}
+
+-
+-###############################################################################
+-# cfgval(variable)
+-# read variable ($1) from config file
+-#
+-sub cfgval {
+- my ($variable) = @_;
+- my $value;
++ my ($mode, $mode_origin) = get_cfg('LW35');
++ my ($dvipsPreferOutline, $dvipsPreferOutline_origin) =
++ get_cfg('dvipsPreferOutline');
++ my ($dvipsDownloadBase35, $dvipsDownloadBase35_origin) =
++ get_cfg('dvipsDownloadBase35');
++ my ($pdftexDownloadBase14, $pdftexDownloadBase14_origin) =
++ get_cfg('pdftexDownloadBase14');
++ my ($pxdviUse, $pxdviUse_origin) = get_cfg('pxdviUse');
++ my ($kanjiEmbed, $kanjiEmbed_origin) = get_cfg('kanjiEmbed');
++
++ print_and_log ("\n$prg is creating new map files"
++ . "\nusing the following configuration:"
++ . "\n LW35 font names : "
++ . "$mode ($mode_origin)"
++ . "\n prefer outlines : "
++ . "$dvipsPreferOutline ($dvipsPreferOutline_origin)"
++ . "\n texhash enabled : "
++ . ($opts{'nohash'} ? "false" : "true")
++ . "\n download standard fonts (dvips) : "
++ . "$dvipsDownloadBase35 ($dvipsDownloadBase35_origin)"
++ . "\n download standard fonts (pdftex) : "
++ . "$pdftexDownloadBase14 ($pdftexDownloadBase14_origin)"
++ . "\n kanjiEmbed replacement string : "
++ . "$kanjiEmbed ($kanjiEmbed_origin)"
++ . "\n create a mapfile for pxdvi : "
++ . "$pxdviUse ($pxdviUse_origin)"
++ . "\n\n");
+
+- if ($#cfg < 0) {
+- open FILE, "<$cnfFile" or die "$0: can't open configuration file $cnfFile: $!";
+- while (<FILE>) {
+- s/\s*$//; # strip trailing spaces
+- push @cfg, $_;
++ print_and_log ("Scanning for LW35 support files");
++ my $dvips35 = $alldata->{'maps'}{"dvips35.map"}{'fullpath'};
++ my $pdftex35 = $alldata->{'maps'}{"pdftex35.map"}{'fullpath'};
++ my $ps2pk35 = $alldata->{'maps'}{"ps2pk35.map"}{'fullpath'};
++ my $LW35 = "\n$dvips35\n$pdftex35\n$ps2pk35\n\n";
++ only_log ("\n");
++ only_log ($LW35);
++ print_and_log (" [ 3 files]\n");
++ only_log ("\n");
++
++ print_and_log ("Scanning for MixedMap entries");
++ my @mixedmaps;
++ my @notmixedmaps;
++ my @kanjimaps;
++ for my $m (keys %{$alldata->{'maps'}}) {
++ my $origin = $alldata->{'maps'}{$m}{'origin'};
++ next if !defined($origin);
++ next if ($alldata->{'updmap'}{$origin}{'maps'}{$m}{'status'} eq "disabled");
++ push @mixedmaps, $m
++ if ($alldata->{'updmap'}{$origin}{'maps'}{$m}{'type'} eq "MixedMap");
++ push @notmixedmaps, $m
++ if ($alldata->{'updmap'}{$origin}{'maps'}{$m}{'type'} eq "Map");
++ push @kanjimaps, $m
++ if ($alldata->{'updmap'}{$origin}{'maps'}{$m}{'type'} eq "KanjiMap");
++ }
++
++ @mixedmaps = sort @mixedmaps;
++ @notmixedmaps = sort @notmixedmaps;
++ @kanjimaps = sort @kanjimaps;
++ only_log("\n");
++ foreach my $m (sort @mixedmaps) {
++ if (defined($alldata->{'maps'}{$m}{'fullpath'})) {
++ only_log($alldata->{'maps'}{$m}{'fullpath'} . "\n");
++ } else {
++ only_log("$m (full path not set?)\n");
+ }
+- close FILE;
+- chomp (@cfg);
+ }
+- for my $line (@cfg) {
+- if ($line =~ m/^\s*${variable}[\s=]+(.*)\s*$/) {
+- $value = $1;
+- if ($value =~ m/^(true|yes|t|y|1)$/) {
+- $value = 1;
+- }
+- elsif ($value =~ m/^(false|no|f|n|0)$/) {
+- $value = 0;
+- }
+- last;
++ only_log("\n");
++ print_and_log (sprintf(" [%3d files]\n", scalar @mixedmaps));
++ only_log("\n");
++
++ print_and_log ("Scanning for KanjiMap entries");
++ only_log("\n");
++ foreach my $m (@kanjimaps) {
++ if (defined($alldata->{'maps'}{$m}{'fullpath'})) {
++ only_log($alldata->{'maps'}{$m}{'fullpath'} . "\n");
++ } else {
++ only_log("$m (full path not set?)\n");
+ }
+ }
+- return $value;
+-}
+-
+-###############################################################################
+-# configReplace(file, pattern, line)
+-# The first line in file that matches pattern gets replaced by line.
+-# line will be added at the end of the file if pattern does not match.
+-#
+-sub configReplace {
+- my ($file, $pat, $line) = @_;
+- my @lines = &getLines($file);
+- my $found = 0;
+- map {
+- if (/$pat/) {
+- $found = 1; $_ = $line;
+- }
+- } @lines;
+- if (! $found) {
+- push @lines, $line;
+- }
+- &writeLines($file, @lines);
+-}
+-
+-###############################################################################
+-# setOption (@options)
+-# parse @options for "key=value" (one element of @options)
+-# or "key", "value" (two elements of @options) pairs.
+-# (These were the values provided to --setoption.)
+-#
+-sub setOptions {
+- my (@options) = @_;
+- for (my $i = 0; $i < @options; $i++) {
+- my $o = $options[$i];
+-
+- my ($key,$val);
+- if ($o =~ /=/) {
+- ($key,$val) = split (/=/, $o, 2);
++ only_log("\n");
++ print_and_log (sprintf(" [%3d files]\n", scalar @kanjimaps));
++ only_log("\n");
++
++ print_and_log ("Scanning for Map entries");
++ only_log("\n");
++ foreach my $m (@notmixedmaps) {
++ if (defined($alldata->{'maps'}{$m}{'fullpath'})) {
++ only_log($alldata->{'maps'}{$m}{'fullpath'} . "\n");
+ } else {
+- $key = $o;
+- die "$0: no value for --setoption $key, goodbye.\n"
+- if $i + 1 >= @options;
+- $val = $options[$i + 1];
+- $i++;
++ only_log("$m (full path not set?)\n");
+ }
+-
+- die "$0: unexpected empty key or val for options (@options), goodbye.\n"
+- if !$key || !$val;
+- &setOption ($key, $val);
+ }
+-}
+-
+-###############################################################################
+-# setOption (option, value)
+-# sets option to value in the config file (replacing the existing setting
+-# or by adding a new line to the config file).
+-#
+-sub setOption {
+- my ($opt, $val) = @_;
++ only_log("\n");
++ print_and_log (sprintf(" [%3d files]\n\n", scalar @notmixedmaps));
++ only_log("\n");
+
+- if ($opt eq "LW35") {
+- if ($val !~ m/^(URWkb|URW|ADOBE|ADOBEkb)$/) {
+- die "$0: Invalid value $val for option $opt; try --help.\n";
+- }
+- } elsif ($opt =~
+-m/^(dvipsPreferOutline|dvipsDownloadBase35|(pdftex|dvipdfm)DownloadBase14|pxdviUse)$/) {
+- if ($val !~ m/^(true|false)$/) {
+- die "$0: Invalid value $val for option $opt; should be \"true\" or \"false\".\n";
+- }
+- } elsif ($opt eq "kanjiEmbed"){
+- # do nothing
+- } else {
+- die "$0: Unsupported option $opt (value given: $val).\n";
++ # Create psfonts_t1.map, psfonts_pk.map, ps2pk.map and pdftex.map:
++ my $dvipsoutputdir = $opts{'dvipsoutputdir'};
++ my $pdftexoutputdir = $opts{'pdftexoutputdir'};
++ my $dvipdfmoutputdir = $opts{'dvipdfmoutputdir'};
++ my $pxdvioutputdir = $opts{'pxdvioutputdir'};
++ if (!$opts{'dry-run'}) {
++ my @managed_files = ("$dvipsoutputdir/download35.map",
++ "$dvipsoutputdir/builtin35.map",
++ "$dvipsoutputdir/psfonts_t1.map",
++ "$dvipsoutputdir/psfonts_pk.map",
++ "$pdftexoutputdir/pdftex_dl14.map",
++ "$pdftexoutputdir/pdftex_ndl14.map",
++ "$dvipdfmoutputdir/kanjix.map",
++ "$dvipsoutputdir/ps2pk.map");
++ push @managed_files, "$pxdvioutputdir/xdvi-ptex.map"
++ if ($pxdviUse eq "true");
++ for my $file (@managed_files) {
++ open FILE, ">$file";
++ print FILE "% $file:\
++% maintained by updmap[-sys] (multi).\
++% Don't change this file directly. Use updmap[-sys] instead.\
++% See the updmap documentation.\
++% A log of the run that created this file is available here:\
++% $logfile\
++";
++ close FILE;
++ }
+ }
+
+- # silently accept this old option name, just in case.
+- return if $opt eq "dvipdfmDownloadBase14";
+-
+- #print "Setting option $opt to $val...\n" if !$quiet;
+- &configReplace("$cnfFile", "^" . "$opt" . "\\s", "$opt $val");
+-}
++ my @kanjimaps_fonts = getFonts(@kanjimaps);
++ @kanjimaps_fonts = &normalizeLines(@kanjimaps_fonts);
++ my @ps2pk_fonts = getFonts('-all', "ps2pk35.map");
++ my @dvips35_fonts = getFonts('-all', "dvips35.map");
++ my @pdftex35_fonts = getFonts('-all', "pdftex35.map");
++ my @mixedmaps_fonts = getFonts(@mixedmaps);
++ my @notmixedmaps_fonts = getFonts(@notmixedmaps);
+
+-###############################################################################
+-# showOptions(item)
+-# show Options for an item
+-#
+-sub showOptions {
+- foreach my $item (@_) {
+- if ($item eq "LW35") {
+- print "URWkb URW ADOBE ADOBEkb\n";
+- }
+- elsif ($item =~
+-m/(dvipsPreferOutline|(dvipdfm|pdftex)DownloadBase14|dvipsDownloadBase35|pxdviUse)/) {
+- print "true false\n";
+- }
+- elsif ($item eq "kanjiEmbed") {
+- print "(any string)\n";
+- }
+- else {
+- print "Unknown item \"$item\"; should be one of LW35, dvipsPreferOutline,\n"
+- . " dvipsDownloadBase35, pdftexDownloadBase14, pxdviUse or kanjiEmbed\n";
+- }
++ print "Generating output for dvipdfm...\n" if !$opts{'quiet'};
++ &writeLines(">$dvipdfmoutputdir/kanjix.map", @kanjimaps_fonts);
++
++ if ($pxdviUse eq "true") {
++ # we use the very same data as for kanjix.map, but generate
++ # a different file, so that in case a user wants to hand-craft it
++ print "Generating output for pxdvi...\n" if !$opts{'quiet'};
++ &writeLines(">$pxdvioutputdir/xdvi-ptex.map", @kanjimaps_fonts);
+ }
+- exit 0
+-}
+
+-
+-###############################################################################
+-# enableMap (type, map)
+-# enables an entry in the config file for map with a given type.
+-#
+-sub enableMap {
+- my ($type, $map) = @_;
+
+- if ($type !~ m/^(Map|MixedMap|KanjiMap)$/) {
+- die "$0: Invalid mapType $type\n";
++ print "Generating output for ps2pk...\n" if !$opts{'quiet'};
++ my @ps2pk_map;
++ push @ps2pk_map, "% ps2pk35.map";
++ push @ps2pk_map, transLW35($mode, @ps2pk_fonts);
++ push @ps2pk_map, @mixedmaps_fonts;
++ push @ps2pk_map, @notmixedmaps_fonts;
++ &writeLines(">$dvipsoutputdir/ps2pk.map",
++ normalizeLines(@ps2pk_map));
++
++ print "Generating output for dvips...\n" if !$opts{'quiet'};
++ my @download35_map;
++ push @download35_map, "% ps2pk35.map";
++ push @download35_map, transLW35($mode, @ps2pk_fonts);
++ &writeLines(">$dvipsoutputdir/download35.map",
++ normalizeLines(@download35_map));
++
++ my @builtin35_map;
++ push @builtin35_map, "% dvips35.map";
++ push @builtin35_map, transLW35($mode, @dvips35_fonts);
++ &writeLines(">$dvipsoutputdir/builtin35.map",
++ normalizeLines(@builtin35_map));
++
++ my @dftdvips_fonts = ($dvipsDownloadBase35 ? @ps2pk_fonts : @dvips35_fonts);
++
++ my @psfonts_t1_map;
++ if ($dvipsDownloadBase35) {
++ push @psfonts_t1_map, "% ps2pk35.map",
++ @dftdvips_fonts = @ps2pk_fonts;
++ } else {
++ push @psfonts_t1_map, "% dvips35.map";
++ @dftdvips_fonts = @dvips35_fonts;
+ }
+- # a map can only have one type, so we carefully disable everything
+- # about map here:
+- &disableMap("$map");
++ push @psfonts_t1_map, transLW35($mode, @dftdvips_fonts);
++ my @tmpkanji2 = cidx2dvips(\@kanjimaps_fonts);
++ push @psfonts_t1_map, @mixedmaps_fonts;
++ push @psfonts_t1_map, @notmixedmaps_fonts;
++ push @psfonts_t1_map, @tmpkanji2;
++ &writeLines(">$dvipsoutputdir/psfonts_t1.map",
++ normalizeLines(@psfonts_t1_map));
+
+- # now enable with the right type:
+- &configReplace("$cnfFile", "^#!\\s*" . "$type" . "\\s*$map", "$type $map");
+-}
++ my @psfonts_pk_map;
++ push @psfonts_pk_map, transLW35($mode, @dftdvips_fonts);
++ push @psfonts_pk_map, @notmixedmaps_fonts;
++ push @psfonts_pk_map, @tmpkanji2;
++ &writeLines(">$dvipsoutputdir/psfonts_pk.map",
++ normalizeLines(@psfonts_pk_map));
+
+-###############################################################################
+-# disableMap (map)
+-# disables map in config file (any type)
+-#
+-sub disableMap {
+- my ($map) = @_;
+- my %count = ();
+- my $type;
++ print "Generating output for pdftex...\n" if !$opts{'quiet'};
++ # remove PaintType due to Sebastian's request
++ my @pdftexmaps_ndl;
++ push @pdftexmaps_ndl, "% pdftex35.map";
++ push @pdftexmaps_ndl, transLW35($mode, @pdftex35_fonts);
++ push @pdftexmaps_ndl, @mixedmaps_fonts;
++ push @pdftexmaps_ndl, @notmixedmaps_fonts;
++ @pdftexmaps_ndl = grep { $_ !~ m/(^%\|PaintType)/ } @pdftexmaps_ndl;
++
++ my @pdftexmaps_dl;
++ push @pdftexmaps_dl, "% ps2pk35.map";
++ push @pdftexmaps_dl, transLW35($mode, @ps2pk_fonts);
++ push @pdftexmaps_dl, @mixedmaps_fonts;
++ push @pdftexmaps_dl, @notmixedmaps_fonts;
++ @pdftexmaps_dl = grep { $_ !~ m/(^%\|PaintType)/ } @pdftexmaps_dl;
+
+- my @mapType = grep {
+- my @fields = split;
+- if ($fields[0] and $fields[0] =~ /^(MixedMap|Map|KanjiMap)$/
+- and $fields[1] eq $map and ++$count{$fields[0]}) {
+- $_ = $fields[0];
+- }
+- else {
+- $_ = '';
+- }
+- } &getLines($cnfFile);
++ my @pdftex_ndl14_map = @pdftexmaps_ndl;
++ @pdftex_ndl14_map = &normalizeLines(@pdftex_ndl14_map);
++ @pdftex_ndl14_map = &to_pdftex(@pdftex_ndl14_map);
++ &writeLines(">$pdftexoutputdir/pdftex_ndl14.map", @pdftex_ndl14_map);
+
+- foreach $type (@mapType) {
+- &configReplace("$cnfFile", "^$type" . "\\s*$map", "#! $type $map");
+- }
+-}
++ my @pdftex_dl14_map = @pdftexmaps_dl;
++ @pdftex_dl14_map = &normalizeLines(@pdftex_dl14_map);
++ @pdftex_dl14_map = &to_pdftex(@pdftex_dl14_map);
++ &writeLines(">$pdftexoutputdir/pdftex_dl14.map", @pdftex_dl14_map);
+
+-###############################################################################
+-# setupDestDir()
+-# find an output directory if none specified on cmd line. First choice is
+-# $TEXMFVAR/fonts/map/updmap (if TEXMFVAR is set), next is relative to
+-# config file location. Fallback is $TEXMFMAIN/fonts/map/updmap.
+-#
+-sub setupOutputDir {
+- my($od, $driver) = @_;
++ our $link = &setupSymlinks($dvipsPreferOutline, $dvipsoutputdir, $pdftexDownloadBase14, $pdftexoutputdir);
++
++ print_and_log ("\nFiles generated:\n");
++ sub dir {
++ my ($d, $f, $target)=@_;
++ our $link;
++ if (-e "$d/$f") {
++ my @stat=lstat("$d/$f");
++ my ($s,$m,$h,$D,$M,$Y)=localtime($stat[9]);
++ my $timestamp=sprintf ("%04d-%02d-%02d %02d:%02d:%02d",
++ $Y+1900, $M+1, $D, $h, $m, $s);
++ my $date=sprintf "%12d %s %s", $stat[7], $timestamp, $f;
++ print_and_log ($date);
+
+- if (!$od) {
+- my $rel = "fonts/map/$driver/updmap";
+- my $tf;
+- # Try TEXMFVAR tree. Use it if variable is set and $rel can
+- # be written.
+- chomp($tf = `kpsewhich --var-value=TEXMFVAR`);
+- if ($tf) {
+- &mkdirhier("$tf/$rel");
+- if (! -w "$tf/$rel") {
+- die "$0: Directory \"$tf/$rel\" isn't writable.\n";
++ if (-l "$d/$f") {
++ my $lnk=sprintf " -> %s\n", readlink ("$d/$f");
++ print_and_log ($lnk);
++ } elsif ($f eq $target) {
++ if (&files_are_identical("$d/$f", "$d/" . $link->{$target})) {
++ print_and_log (" = $link->{$target}\n");
++ } else {
++ print_and_log (" = ?????\n"); # This shouldn't happen.
++ }
++ } else {
++ print_and_log ("\n");
+ }
++ } else {
++ print STDERR "Warning: File $d/$f doesn't exist.\n";
++ print LOG "Warning: File $d/$f doesn't exist.\n"
++ unless $opts{'dry-run'};
+ }
+- $od = "$tf/$rel";
+ }
+- &mkdirhier($od);
+- print "$driver output dir: \"$od\"\n" if !$quiet;
+- return $od;
+-}
+-
+-sub setupDestDir {
+- $dvipsoutputdir = &setupOutputDir($dvipsoutputdir, "dvips");
+- $pdftexoutputdir = &setupOutputDir($pdftexoutputdir, "pdftex");
+- $dvipdfmoutputdir = &setupOutputDir($dvipdfmoutputdir, "dvipdfm");
+- $pxdvioutputdir = &setupOutputDir($pxdvioutputdir, "pxdvi");
+-}
+
+-###############################################################################
+-# setupCfgFile()
+-# find config file if none specified on cmd line.
+-#
+-sub setupCfgFile {
+- if (! $cnfFile) {
+- my $tf = `kpsewhich --var-value=TEXMFCONFIG`;
+- chomp($tf);
+- if ($tf && ! -f "$tf/web2c/$cnfFileShort") {
+- &mkdirhier("$tf/web2c") if (! -d "$tf/web2c");
+- if (-d "$tf/web2c" && -w "$tf/web2c") {
+- unlink "$tf/web2c/$cnfFileShort";
+- my $original_cfg=`kpsewhich updmap.cfg`;
+- chomp($original_cfg);
+- print("copy $original_cfg => $tf/web2c/$cnfFileShort\n") if !$quiet;
+- $newcnf="$tf/web2c/$cnfFileShort";
+- &copyFile("$original_cfg", "$tf/web2c/$cnfFileShort");
+- $updLSR->{add}("$tf/web2c/$cnfFileShort");
+- }
+- }
+- $cnfFile = "$tf/web2c/updmap.cfg";
+- if (-s $cnfFile) {
+- print "Config file: \"$cnfFile\"\n" if !$quiet;
+- } else {
+- die "$0: Config file updmap.cfg not found.\n";
++ my $d;
++ $d = "$dvipsoutputdir";
++ print_and_log(" $d:\n");
++ foreach my $f ('builtin35.map', 'download35.map', 'psfonts_pk.map',
++ 'psfonts_t1.map', 'ps2pk.map', 'psfonts.map') {
++ dir ($d, $f, 'psfonts.map');
++ $updLSR->{add}("$d/$f") unless $opts{'dry-run'};
++ }
++ $d = "$pdftexoutputdir";
++ print_and_log(" $d:\n");
++ foreach my $f ('pdftex_dl14.map', 'pdftex_ndl14.map', 'pdftex.map') {
++ dir ($d, $f, 'pdftex.map');
++ $updLSR->{add}("$d/$f") unless $opts{'dry-run'};
++ }
++ $d="$dvipdfmoutputdir";
++ print_and_log(" $d:\n");
++ foreach my $f ('kanjix.map') {
++ dir ($d, $f, '');
++ $updLSR->{add}("$d/$f") unless $opts{'dry-run'};
++ }
++ if ($pxdviUse eq "true") {
++ $d="$pxdvioutputdir";
++ print_and_log(" $d:\n");
++ foreach my $f ('xdvi-ptex.map') {
++ dir ($d, $f, '');
++ $updLSR->{add}("$d/$f") unless $opts{'dry-run'};
+ }
+ }
++ close LOG unless $opts{'dry-run'};
++ print "\nTranscript written on \"$logfile\".\n" if !$opts{'quiet'};
++
+ }
+
+-###############################################################################
+-# catMaps(regex)
+-# filter config file by regex for map lines and extract the map filenames.
+-# These are then looked up (by kpsewhich in locateMap) and the content of
+-# all map files is send to stdout.
+-#
+-sub catMaps {
+- my ($map) = @_;
+- my %count = ( );
+- my @maps = grep { $_ =~ m/$map/ } @cfg;
+- map{
+- $_ =~ s/\#.*//;
+- $_ =~ s/\@kanjiEmbed@/$kanjiEmbed/;
+- $_ =~ s/\s*([^\s]*)\s*([^\s]*)/$2/;
+- } @maps;
+- @maps = sort(@maps);
+- @maps = grep { ++$count{$_} < 2; } @maps;
+
+- @maps = &locateMap(@maps);
+- return @maps;
++sub locateMap {
++ my $map = shift;
++ my $ret = `kpsewhich --format=map $map`;
++ chomp($ret);
++ return $ret;
+ }
+
+-###############################################################################
+-# listMaps()
+-# list all maps mentioned in the config file
+-#
+-sub listMaps {
+- my $what=shift;
+- my @mapfiles;
+- my @paths;
+- $kanjiEmbed = &cfgval("kanjiEmbed");
+- $kanjiEmbed = "noEmbed" unless (defined $kanjiEmbed);
+-
+- my @lines = grep {
+- if ($what eq 'sync') {
+- $_ =~ m/^(Mixed|Kanji)?Map/
++sub processOptions {
++ # first process the stupid setoption= s@{1,2} which is not accepted
++ # furthermore, try to work around missing s{1,2} support in older perls
++ my $oldconfig = Getopt::Long::Configure(qw(pass_through));
++ our @setoptions;
++ our @enable;
++ sub read_one_or_two {
++ my ($opt, $val) = @_;
++ our @setoptions;
++ our @enable;
++ # check if = occirs in $val, if not, get the next argument
++ if ($val =~ m/=/) {
++ if ($opt eq "setoption") {
++ push @setoptions, $val;
++ } else {
++ push @enable, $val;
++ }
+ } else {
+- $_ =~ m/^(\#! *)?(Mixed|Kanji)?Map/
+- }
+- } &getLines($cnfFile);
+-
+- if ($what eq 'list') {
+- # --listmaps
+- map { print "$_\n"; } @lines;
+- } else {
+- map { $_ =~ s/\@kanjiEmbed@/$kanjiEmbed/ } @lines;
+- @mapfiles=grep { $_ =~ s/^(\#! *)?(Mixed|Kanji)?Map\s+// } @lines;
+- @paths=&locateMap(@mapfiles);
+-
+- if ($what eq 'avail') {
+- # --listavailablemaps
+- map {
+- my $entry="$_";
+- # that was disabled, but I don't understand why (NP)
+- print "$entry\n" if (grep { $_ =~ m/\/$entry/ } @paths);
+- } @lines;
+- } elsif ($what eq 'sync') {
+- # --syncwithtrees
+- map {
+- my $entry="$_";
+- unless (grep { $_ =~ m/\/$entry/ } @paths) {
+- &disableMap($entry);
+- print " $entry disabled\n" if !$quiet;
+- }
+- } @lines;
++ my $vv = shift @ARGV;
++ die "Try \"$prg --help\" for more information.\n"
++ if !defined($vv);
++ if ($opt eq "setoption") {
++ push @setoptions, "$val=$vv";
++ } else {
++ push @enable, "$val=$vv";
++ }
+ }
+ }
+-}
++ GetOptions("setoption=s@" => \&read_one_or_two,
++ "enable=s@" => \&read_one_or_two) or
++ die "Try \"$prg --help\" for more information.\n";
+
+-###############################################################################
+-# normalizeLines()
+-# remove comments, whitespace is exactly one space, no empty lines,
+-# no whitespace at end of line, one space before and after "
+-#
+-sub normalizeLines {
+- my @lines = @_;
+- my %count = ();
++ @{$opts{'setoption'}} = @setoptions if (@setoptions);
++ @{$opts{'enable'}} = @enable if (@enable);
+
+- @lines = grep { $_ !~ m/^[*#;%]/ } @lines;
+- map {$_ =~ s/\s+/ /gx } @lines;
+- @lines = grep { $_ !~ m/^\s*$/x } @lines;
+- map { $_ =~ s/\s$//x ;
+- $_ =~ s/\s*\"\s*/ \" /gx;
+- $_ =~ s/\" ([^\"]*) \"/\"$1\"/gx;
+- } @lines;
++ Getopt::Long::Configure($oldconfig);
+
+- @lines = grep {++$count{$_} < 2 } (sort @lines);
++ # now continue with normal option handling
+
+- return @lines;
++ GetOptions(\%opts, @cmdline_options) or
++ die "Try \"$prg --help\" for more information.\n";
+ }
+
+-###############################################################################
+-# to_pdftex()
+-# if $pdftexStripEnc is set, strip "PS_Encoding_Name ReEncodeFont"
+-# from map entries; they are ignored by pdftex. But since the sh
+-# incarnation of updmap included them, and we want to minimize
+-# differences, this is not done by default.
+-#
+-sub to_pdftex {
+- return @_ unless $pdftexStripEnc;
+- my @in = @_;
+- my @out;
+- foreach my $line (@in) {
+- if ($line =~ /^(.*\s+)(\S+\s+ReEncodeFont\s)(.*)/) {
+- $line = "$1$3";
+- $line =~ s/\s+\"\s+\"\s+/ /;
++# determines the output dir for driver from cmd line, or if not given
++# from TEXMFVAR
++sub setupOutputDir {
++ my $driver = shift;
++ if (!$opts{$driver . "outputdir"}) {
++ if ($opts{'outputdir'}) {
++ $opts{$driver . "outputdir"} = $opts{'outputdir'};
++ } else {
++ $opts{$driver . "outputdir"} = "$TEXMFVAR/fonts/map/$driver/updmap";
+ }
+- push @out, $line;
+ }
+- return @out;
+-}
+-
+-###############################################################################
+-# cidx2dvips()
+-# reads from stdin, writes to stdout. It transforms "cid-x"-like syntax into
+-# "dvips"-like syntax.
+-###############################################################################
+-sub cidx2dvips {
+- my ($s) = @_;
+- my @d;
+- foreach (@$s) {
+- s/,BoldItalic/ -s .3/;
+- s/,Bold//;
+- s/,Italic/ -s .3/;
+- s/\s\s*/ /g;
+- if ($_ =~ /.*[@\:\/,]/) {next;}
+- elsif ($_ =~ /^[^ ][^ ]* unicode /) {next;}
+- s/^([^ ][^ ]* [^ ][^ ]* [^ ][^ ]*)\.[Oo][Tt][Ff]/$1/;
+- s/^([^ ][^ ]* [^ ][^ ]* [^ ][^ ]*)\.[Tt][Tt][FfCc]/$1/;
+- s/$/ %/;
+- s/^(([^ ]*).*)/$1$2/;
+- s/^([^ ][^ ]* ([^ ][^ ]*) !*([^ ][^ ]*).*)/$1 $3-$2/;
+- s/^(.* -e ([.0-9-][.0-9-]*).*)/$1 "$2 ExtendFont"/;
+- s/^(.* -s ([.0-9-][.0-9-]*).*)/$1 "$2 SlantFont"/;
+- s/.*%//;
+- push(@d, $_);
++ my $od = $opts{$driver . "outputdir"};
++ if (!$opts{"dry-run"}) {
++ &mkdirhier($od);
++ if (! -w $od) {
++ die "$prg: Directory \"$od\" isn't writable: $!";
+ }
+- return @d
++ }
++ print "$driver output dir: \"$od\"\n" if !$opts{'quiet'};
++ return $od;
+ }
+
+-
+ ###############################################################################
+-# mkMaps()
+-# the main task of this script: create the output files
++# setOption (@options)
++# parse @options for "key=value" (one element of @options)
++# we can only have "key=value" since that is the way it was prepared
++# in process_options
++# (These were the values provided to --setoption.)
+ #
+-sub mkMaps {
+- my @lines;
+- my $logfile;
++sub setOptions {
++ my (@options) = @_;
++ for (my $i = 0; $i < @options; $i++) {
++ my $o = $options[$i];
+
+- $cache=1;
++ my ($key,$val) = split (/=/, $o, 2);
+
+- if (! $dry_run) {
+- my $TEXMFVAR = `kpsewhich --var-value=TEXMFVAR`;
+- chomp($TEXMFVAR);
+- $logfile = "$TEXMFVAR/web2c/updmap.log";
+- mkdirhier "$TEXMFVAR/web2c";
+- open LOG, ">$logfile"
+- or die "$0: Can't open log file \"$logfile\": $!";
+- $writelog=1;
+- print LOG &version();
+- printf LOG "%s\n\n", scalar localtime();
+- print LOG "Using config file \"$cnfFile\".\n";
+- }
+- sub wlog () {
+- my $str=shift;
+- if ($dry_run) {
+- print $str;
+- } else {
+- print $str if !$quiet;
+- print LOG $str;
+- }
++ die "$prg: unexpected empty key or val for options (@options), goodbye.\n"
++ if !$key || !$val;
++ &setOption ($key, $val);
+ }
+- sub newline() {
+- if ($dry_run) {
+- print "\n";
++ return save_updmap($alldata->{'changes_config'});
++}
++
++sub enable_disable_maps {
++ my (@what) = @_;
++ my $tc = $alldata->{'changes_config'};
++ die "$prg: top config file $tc has not been read."
++ if (!defined($alldata->{'updmap'}{$tc}));
++ my $changed = 0;
++ for my $w (@what) {
++ if ($w =~ m/=/) {
++ # this is --enable MapType=MapName
++ my ($type, $map) = split ('=', $w);
++ enable_map($tc, $type, $map);
+ } else {
+- print LOG "\n";
++ # this is --disable MapName
++ disable_map($tc, $w);
+ }
+ }
++ return save_updmap($tc);
++}
+
+- $mode = &cfgval("LW35");
+- $mode = "URWkb" unless (defined $mode);
+-
+- $dvipsPreferOutline = &cfgval("dvipsPreferOutline");
+- $dvipsPreferOutline = 1 unless (defined $dvipsPreferOutline);
+-
+- $dvipsDownloadBase35 = &cfgval("dvipsDownloadBase35");
+- $dvipsDownloadBase35 = 1 unless (defined $dvipsDownloadBase35);
+-
+- $pdftexDownloadBase14 = &cfgval("pdftexDownloadBase14");
+- $pdftexDownloadBase14 = 1 unless (defined $pdftexDownloadBase14);
+-
+- $kanjiEmbed = &cfgval("kanjiEmbed");
+- $kanjiEmbed = "noEmbed" unless (defined $kanjiEmbed);
+-
+- $pxdviUse = &cfgval("pxdviUse");
+- $pxdviUse = 0 unless (defined $pxdviUse);
++sub enable_map {
++ my ($tc, $type, $map) = @_;
+
+- &wlog ("\n$0 "
+- . ($dry_run ? "would create" : "is creating") . " new map files"
+- . "\nusing the following configuration:"
+- . "\n LW35 font names : "
+- . $mode
+- . "\n prefer outlines : "
+- . ($dvipsPreferOutline ? "true" : "false")
+- . "\n texhash enabled : "
+- . ($nohash ? "false" : "true")
+- . "\n download standard fonts (dvips) : "
+- . ($dvipsDownloadBase35 ? "true" : "false")
+- . "\n download standard fonts (pdftex) : "
+- . ($pdftexDownloadBase14 ? "true" : "false")
+- . "\n create a mapfile for pxdvi : "
+- . ($pxdviUse ? "true" : "false")
+- . "\n\n");
++ die "$prg: invalid mapType $type" if ($type !~ m/^(Map|MixedMap|KanjiMap)$/);
+
+- &wlog ("Scanning for LW35 support files");
+- $dvips35 = &locateMap("dvips35.map");
+- $pdftex35 = &locateMap("pdftex35.map");
+- $ps2pk35 = &locateMap("ps2pk35.map");
+- my $LW35 = "\n$dvips35\n$pdftex35\n$ps2pk35\n\n";
+- if ($dry_run) {
+- print $LW35;
++ if (defined($alldata->{'updmap'}{$tc}{'maps'}{$map})) {
++ # the map data has already been read in, no special precautions necessary
++ if (($alldata->{'updmap'}{$tc}{'maps'}{$map}{'status'} eq "enabled") &&
++ ($alldata->{'updmap'}{$tc}{'maps'}{$map}{'type'} eq $type)) {
++ # nothing to do here ... be happy!
++ return;
++ } else {
++ $alldata->{'updmap'}{$tc}{'maps'}{$map}{'status'} = "enabled";
++ $alldata->{'updmap'}{$tc}{'maps'}{$map}{'type'} = $type;
++ $alldata->{'maps'}{$map}{'origin'} = $tc;
++ $alldata->{'maps'}{$map}{'status'} = "enabled";
++ $alldata->{'updmap'}{$tc}{'changed'} = 1;
++ }
+ } else {
+- print LOG $LW35;
++ # add a new map file!
++ $alldata->{'updmap'}{$tc}{'maps'}{$map}{'type'} = $type;
++ $alldata->{'updmap'}{$tc}{'maps'}{$map}{'status'} = "enabled";
++ $alldata->{'updmap'}{$tc}{'maps'}{$map}{'line'} = -1;
++ $alldata->{'updmap'}{$tc}{'changed'} = 1;
++ $alldata->{'maps'}{$map}{'origin'} = $tc;
++ $alldata->{'maps'}{$map}{'status'} = "enabled";
+ }
+- printf " [%3d files]\n", 3 unless ($quiet || $dry_run);
++}
+
+- &wlog ("Scanning for MixedMap entries");
+- &newline;
+- my @tmp1 = &catMaps('^MixedMap');
+- foreach my $line (@tmp1) {
+- if ($dry_run) {
+- print "$line\n";
++sub disable_map {
++ my ($tc, $map) = @_;
++
++ if (defined($alldata->{'updmap'}{$tc}{'maps'}{$map})) {
++ # the map data has already been read in, no special precautions necessary
++ if ($alldata->{'updmap'}{$tc}{'maps'}{$map}{'status'} eq "disabled") {
++ # nothing to do here ... be happy!
+ } else {
+- print LOG "$line\n";
++ $alldata->{'updmap'}{$tc}{'maps'}{$map}{'status'} = "disabled";
++ $alldata->{'maps'}{$map}{'origin'} = $tc;
++ $alldata->{'maps'}{$map}{'status'} = "disabled";
++ $alldata->{'updmap'}{$tc}{'changed'} = 1;
+ }
++ } else {
++ # disable a Map type that might be activated in a lower ranked updmap.cfg
++ if (!defined($alldata->{'maps'}{$map})) {
++ warning("Map is not present anywhere, why should I disable it?\n");
++ return;
++ }
++ my $orig = $alldata->{'maps'}{$map}{'origin'};
++ # add a new entry to the top level where we disable it
++ # copy over the type from the last entry
++ $alldata->{'updmap'}{$tc}{'maps'}{$map}{'type'} =
++ $alldata->{'updmap'}{$orig}{'maps'}{$map}{'type'};
++ $alldata->{'updmap'}{$tc}{'maps'}{$map}{'status'} = "disabled";
++ $alldata->{'updmap'}{$tc}{'maps'}{$map}{'line'} = -1;
++ # rewrite the origin
++ $alldata->{'maps'}{$map}{'origin'} = $tc;
++ $alldata->{'maps'}{$map}{'status'} = "disabled";
++ # go on for writing
++ $alldata->{'updmap'}{$tc}{'changed'} = 1;
+ }
+- &newline;
+- printf " [%3d files]\n", scalar @tmp1
+- unless ($quiet || $dry_run);
+-
+- &wlog ("Scanning for KanjiMap entries");
+- &newline;
+- my @tmpkanji0 = &catMaps('^KanjiMap');
+- foreach my $line (@tmpkanji0) {
+- if ($dry_run) {
+- print "$line\n";
+- } else {
+- print LOG "$line\n";
++}
++
++
++# returns 1 if actually saved due to changes
++sub save_updmap {
++ my $fn = shift;
++ return if $opts{'dry-run'};
++ my %upd = %{$alldata->{'updmap'}{$fn}};
++ if ($upd{'changed'}) {
++ mkdirhier(dirname($fn));
++ open (FN, ">$fn") || die "$prg: can't write to $fn: $!";
++ my @lines = @{$upd{'lines'}};
++ if (!@lines) {
++ print "Creating new config file $fn\n";
++ }
++ # collect the lines with data
++ my %line_to_setting;
++ my %line_to_map;
++ my @add_setting;
++ my @add_map;
++ if (defined($upd{'setting'})) {
++ for my $k (keys %{$upd{'setting'}}) {
++ if ($upd{'setting'}{$k}{'line'} == -1) {
++ push @add_setting, $k;
++ } else {
++ $line_to_setting{$upd{'setting'}{$k}{'line'}} = $k;
++ }
++ }
+ }
+- }
+- &newline;
+- printf " [%3d files]\n", scalar @tmpkanji0
+- unless ($quiet || $dry_run);
+-
+- &wlog ("Scanning for Map entries");
+- &newline();
+- my @tmp2 = &catMaps('^Map');
+- foreach my $line (@tmp2) {
+- if ($dry_run) {
+- print "$line\n";
+- } else {
+- print LOG "$line\n";
++ if (defined($upd{'maps'})) {
++ for my $k (keys %{$upd{'maps'}}) {
++ if ($upd{'maps'}{$k}{'line'} == -1) {
++ push @add_map, $k;
++ } else {
++ $line_to_map{$upd{'maps'}{$k}{'line'}} = $k;
++ }
++ }
+ }
++ for my $i (0..$#lines) {
++ if (defined($line_to_setting{$i})) {
++ my $k = $line_to_setting{$i};
++ my $v = $upd{'setting'}{$k}{'val'};
++ print FN "$k $v\n";
++ } elsif (defined($line_to_map{$i})) {
++ my $m = $line_to_map{$i};
++ my $rm;
++ if (defined($upd{'maps'}{$m}{'original'})) {
++ # we have the case that @noEmbed@ was replaced by the respective
++ # setting. Before writing out we have to replace this back with
++ # the original line!A
++ $rm = $upd{'maps'}{$m}{'original'};
++ } else {
++ $rm = $m;
++ }
++ my $t = $upd{'maps'}{$m}{'type'};
++ my $p = ($upd{'maps'}{$m}{'status'} eq "disabled" ? "#! " : "");
++ print FN "$p$t $rm\n";
++ } else {
++ print FN "$lines[$i]\n";
++ }
++ }
++ # add the new settings and maps
++ for my $k (@add_setting) {
++ my $v = $upd{'setting'}{$k}{'val'};
++ print FN "$k $v\n";
++ }
++ for my $m (@add_map) {
++ my $t = $upd{'maps'}{$m}{'type'};
++ my $p = ($upd{'maps'}{$m}{'status'} eq "disabled" ? "#! " : "");
++ print FN "$p$t $m\n";
++ }
++ close(FN) || warn("Cannot close file handle for $fn: $!");
++ delete $alldata->{'updmap'}{$fn}{'changed'};
++ return 1;
+ }
+- &newline;
+- printf " [%3d files]\n\n", scalar @tmp2
+- unless ($quiet || $dry_run);
+-
+- if (@missing > 0) {
+- print STDERR "\nERROR: The following map file(s) couldn't be found:\n\t";
+- print STDERR join(' ', @missing);
+- print STDERR "\n\n\tDid you run mktexlsr?\n\n" .
+- "\tYou can delete non-existent map entries using the option\n".
+- "\t --syncwithtrees.\n\n";
+- exit (1);
+- }
+- exit(0) if $dry_run;
++ return 0;
++}
+
+- # Create psfonts_t1.map, psfonts_pk.map, ps2pk.map and pdftex.map:
+- my @managed_files = ("$dvipsoutputdir/download35.map",
+- "$dvipsoutputdir/builtin35.map",
+- "$dvipsoutputdir/psfonts_t1.map",
+- "$dvipsoutputdir/psfonts_pk.map",
+- "$pdftexoutputdir/pdftex_dl14.map",
+- "$pdftexoutputdir/pdftex_ndl14.map",
+- "$dvipdfmoutputdir/kanjix.map",
+- "$dvipsoutputdir/ps2pk.map");
+- if ($pxdviUse) {
+- push @managed_files, "$pxdvioutputdir/xdvi-ptex.map";
+- }
+- for my $file (@managed_files) {
+- open FILE, ">$file";
+- print FILE "% $file:\
+-% maintained by updmap[-sys].\
+-% Don't change this file directly. Use updmap[-sys] instead.\
+-% See texmf/web2c/$cnfFileShort and the updmap documentation.\
+-% A log of the run that created this file is available here:\
+-% $logfile\
+-";
+- close FILE;
++######################
++# check for correct option value
++#
++sub check_option {
++ my ($opt, $val) = @_;
++ if ((($settings{$opt}{'type'} eq "binary") &&
++ $val ne "true" && $val ne "false") ||
++ (($settings{$opt}{'type'} eq "string") &&
++ !member($val, @{$settings{$opt}{'possible'}}))) {
++ return 0;
+ }
++ return 1;
++}
+
+- print "Generating output for dvipdfm...\n" if !$quiet;
+- my @tmpkanji1;
+- push @tmpkanji1, &getLines(@tmpkanji0);
+- @tmpkanji1 = &normalizeLines(@tmpkanji1);
+- &writeLines(">$dvipdfmoutputdir/kanjix.map",
+- @tmpkanji1);
+-
+- if ($pxdviUse) {
+- # we use the very same data as for kanjix.map, but generate
+- # a different file, so that in case a user wants to hand-craft it
+- print "Generating output for pxdvi...\n" if !$quiet;
+- &writeLines(">$pxdvioutputdir/xdvi-ptex.map",
+- @tmpkanji1);
+- }
+-
+- print "Generating output for ps2pk...\n" if !$quiet;
+- my @ps2pk_map = &transLW35($ps2pk35);
+- push @ps2pk_map, &getLines(@tmp1);
+- push @ps2pk_map, &getLines(@tmp2);
+- &writeLines(">$dvipsoutputdir/ps2pk.map",
+- &normalizeLines(@ps2pk_map));
+-
+- print "Generating output for dvips...\n" if !$quiet;
+- my @download35_map = &transLW35($ps2pk35);
+- &writeLines(">$dvipsoutputdir/download35.map",
+- &normalizeLines(@download35_map));
+-
+- my @builtin35_map = &transLW35($dvips35);
+- &writeLines(">$dvipsoutputdir/builtin35.map",
+- &normalizeLines(@builtin35_map));
+-
+- my $dftdvips = ($dvipsDownloadBase35 ? $ps2pk35 : $dvips35);
+-
+- my @psfonts_t1_map = &transLW35($dftdvips);
+- my @tmpkanji2 = &cidx2dvips(\@tmpkanji1);
+- push @psfonts_t1_map, &getLines(@tmp1);
+- push @psfonts_t1_map, &getLines(@tmp2);
+- push @psfonts_t1_map, @tmpkanji2;
+- &writeLines(">$dvipsoutputdir/psfonts_t1.map",
+- &normalizeLines(@psfonts_t1_map));
+-
+- my @psfonts_pk_map = &transLW35($dftdvips);
+- push @psfonts_pk_map, &getLines(@tmp2);
+- push @psfonts_pk_map, @tmpkanji2;
+- &writeLines(">$dvipsoutputdir/psfonts_pk.map",
+- &normalizeLines(@psfonts_pk_map));
++###############################################################################
++# setOption (conf_file, option, value)
++# sets option to value in the config file (replacing the existing setting
++# or by adding a new line to the config file).
++#
++sub setOption {
++ my ($opt, $val) = @_;
+
+- print "Generating output for pdftex...\n" if !$quiet;
+- # remove PaintType due to Sebastian's request
+- my @tmp3 = &transLW35($pdftex35);
+- push @tmp3, &getLines(@tmp1);
+- push @tmp3, &getLines(@tmp2);
+- @tmp3 = grep { $_ !~ m/(^%|PaintType)/ } @tmp3;
+-
+- my @tmp7 = &transLW35($ps2pk35);
+- push @tmp7, &getLines(@tmp1);
+- push @tmp7, &getLines(@tmp2);
+- @tmp7 = grep { $_ !~ m/(^%|PaintType)/ } @tmp7;
++ die "$prg: Unsupported option $opt." if (!defined($settings{$opt}));
++ die "$0: Invalid value $val for option $opt."
++ if (!check_option($opt, $val));
+
+- my @pdftex_ndl14_map = @tmp3;
+- @pdftex_ndl14_map = &normalizeLines(@pdftex_ndl14_map);
+- @pdftex_ndl14_map = &to_pdftex(@pdftex_ndl14_map);
+- &writeLines(">$pdftexoutputdir/pdftex_ndl14.map", @pdftex_ndl14_map);
++ # silently accept this old option name, just in case.
++ return if $opt eq "dvipdfmDownloadBase14";
+
+- my @pdftex_dl14_map = @tmp7;
+- @pdftex_dl14_map = &normalizeLines(@pdftex_dl14_map);
+- @pdftex_dl14_map = &to_pdftex(@pdftex_dl14_map);
+- &writeLines(">$pdftexoutputdir/pdftex_dl14.map", @pdftex_dl14_map);
++ #print "Setting option $opt to $val...\n" if !$opts{'quiet'};
++ my $tc = $alldata->{'changes_config'};
+
+- &setupSymlinks;
++ die "$prg: top config file $tc has not been read."
++ if (!defined($alldata->{'updmap'}{$tc}));
+
+- &wlog ("\nFiles generated:\n");
+- sub dir {
+- my ($d, $f, $target)=@_;
+- if (-e "$d/$f") {
+- my @stat=lstat("$d/$f");
+- my ($s,$m,$h,$D,$M,$Y)=localtime($stat[9]);
+- my $timestamp=sprintf ("%04d-%02d-%02d %02d:%02d:%02d",
+- $Y+1900, $M+1, $D, $h, $m, $s);
+- my $date=sprintf "%12d %s %s", $stat[7], $timestamp, $f;
+- &wlog ($date);
+-
+- if (-l "$d/$f") {
+- my $lnk=sprintf " -> %s\n", readlink ("$d/$f");
+- &wlog ($lnk);
+- } elsif ($f eq $target) {
+- if (&files_are_identical("$d/$f", "$d/$link{$target}")) {
+- &wlog (" = $link{$target}\n");
+- } else {
+- &wlog (" = ?????\n"); # This shouldn't happen.
+- }
+- } else {
+- &wlog ("\n");
+- }
+- } else {
+- print STDERR "Warning: File $d/$f doesn't exist.\n";
+- print LOG "Warning: File $d/$f doesn't exist.\n";
+- }
+- }
+- my $d;
+- $d="$dvipsoutputdir"; &wlog (" $d:\n");
+- foreach my $f ('builtin35.map', 'download35.map', 'psfonts_pk.map',
+- 'psfonts_t1.map', 'ps2pk.map', 'psfonts.map') {
+- dir ($d, $f, 'psfonts.map');
+- $updLSR->{add}("$d/$f");
+- }
+- $d="$pdftexoutputdir"; &wlog (" $d:\n");
+- foreach my $f ('pdftex_dl14.map', 'pdftex_ndl14.map', 'pdftex.map') {
+- dir ($d, $f, 'pdftex.map');
+- $updLSR->{add}("$d/$f");
+- }
+- $d="$dvipdfmoutputdir"; &wlog (" $d:\n");
+- foreach my $f ('kanjix.map') {
+- dir ($d, $f, '');
+- $updLSR->{add}("$d/$f");
+- }
+- if ($pxdviUse) {
+- $d="$pxdvioutputdir"; &wlog (" $d:\n");
+- foreach my $f ('xdvi-ptex.map') {
+- dir ($d, $f, '');
+- $updLSR->{add}("$d/$f");
++ if (defined($alldata->{'updmap'}{$tc}{'setting'}{$opt}{'val'})) {
++ # the value is already set, do nothing
++ if ($alldata->{'updmap'}{$tc}{'setting'}{$opt}{'val'} eq $val) {
++ return;
+ }
++ $alldata->{'updmap'}{$tc}{'setting'}{$opt}{'val'} = $val;
++ $alldata->{'updmap'}{$tc}{'changed'} = 1;
++ } else {
++ $alldata->{'updmap'}{$tc}{'setting'}{$opt}{'val'} = $val;
++ $alldata->{'updmap'}{$tc}{'setting'}{$opt}{'line'} = -1;
++ $alldata->{'updmap'}{$tc}{'changed'} = 1;
+ }
+- close LOG;
+- print "\nTranscript written on \"$logfile\".\n" if !$quiet;
+ }
+
+-
++
+ ###############################################################################
+-# initVars()
+-# initialize global variables
++# copyFile()
++# copy file $src to $dst, sets $dst creation and mod time
+ #
+-sub initVars {
+- $quiet = 0;
+- $nohash = 0;
+- $nomkmap = 0;
+- $cnfFile = "";
+- $cnfFileShort = "updmap.cfg";
+- $outputdir = "";
+- chomp($TEXMFMAIN =`kpsewhich --var-value=TEXMFMAIN`);
++sub copyFile {
++ my ($src, $dst) = @_;
++ my $dir;
++ ($dir=$dst)=~s/(.*)\/.*/$1/;
++ mkdirhier($dir);
+
+- @psADOBE = (
+- 's/ URWGothicL-Demi / AvantGarde-Demi /',
+- 's/ URWGothicL-DemiObli / AvantGarde-DemiOblique /',
+- 's/ URWGothicL-Book / AvantGarde-Book /',
+- 's/ URWGothicL-BookObli / AvantGarde-BookOblique /',
+- 's/ URWBookmanL-DemiBold / Bookman-Demi /',
+- 's/ URWBookmanL-DemiBoldItal / Bookman-DemiItalic /',
+- 's/ URWBookmanL-Ligh / Bookman-Light /',
+- 's/ URWBookmanL-LighItal / Bookman-LightItalic /',
+- 's/ NimbusMonL-Bold / Courier-Bold /',
+- 's/ NimbusMonL-BoldObli / Courier-BoldOblique /',
+- 's/ NimbusMonL-Regu / Courier /',
+- 's/ NimbusMonL-ReguObli / Courier-Oblique /',
+- 's/ NimbusSanL-Bold / Helvetica-Bold /',
+- 's/ NimbusSanL-BoldCond / Helvetica-Narrow-Bold /',
+- 's/ NimbusSanL-BoldItal / Helvetica-BoldOblique /',
+- 's/ NimbusSanL-BoldCondItal / Helvetica-Narrow-BoldOblique /',
+- 's/ NimbusSanL-Regu / Helvetica /',
+- 's/ NimbusSanL-ReguCond / Helvetica-Narrow /',
+- 's/ NimbusSanL-ReguItal / Helvetica-Oblique /',
+- 's/ NimbusSanL-ReguCondItal / Helvetica-Narrow-Oblique /',
+- 's/ CenturySchL-Bold / NewCenturySchlbk-Bold /',
+- 's/ CenturySchL-BoldItal / NewCenturySchlbk-BoldItalic /',
+- 's/ CenturySchL-Roma / NewCenturySchlbk-Roman /',
+- 's/ CenturySchL-Ital / NewCenturySchlbk-Italic /',
+- 's/ URWPalladioL-Bold / Palatino-Bold /',
+- 's/ URWPalladioL-BoldItal / Palatino-BoldItalic /',
+- 's/ URWPalladioL-Roma / Palatino-Roman /',
+- 's/ URWPalladioL-Ital / Palatino-Italic /',
+- 's/ StandardSymL / Symbol /',
+- 's/ NimbusRomNo9L-Medi / Times-Bold /',
+- 's/ NimbusRomNo9L-MediItal / Times-BoldItalic /',
+- 's/ NimbusRomNo9L-Regu / Times-Roman /',
+- 's/ NimbusRomNo9L-ReguItal / Times-Italic /',
+- 's/ URWChanceryL-MediItal / ZapfChancery-MediumItalic /',
+- 's/ Dingbats / ZapfDingbats /',
+- );
++ $src eq $dst && return "can't copy $src to itself!\n";
+
+- @fileADOBEkb = (
+- 's/\buagd8a.pfb\b/pagd8a.pfb/',
+- 's/\buagdo8a.pfb\b/pagdo8a.pfb/',
+- 's/\buagk8a.pfb\b/pagk8a.pfb/',
+- 's/\buagko8a.pfb\b/pagko8a.pfb/',
+- 's/\bubkd8a.pfb\b/pbkd8a.pfb/',
+- 's/\bubkdi8a.pfb\b/pbkdi8a.pfb/',
+- 's/\bubkl8a.pfb\b/pbkl8a.pfb/',
+- 's/\bubkli8a.pfb\b/pbkli8a.pfb/',
+- 's/\bucrb8a.pfb\b/pcrb8a.pfb/',
+- 's/\bucrbo8a.pfb\b/pcrbo8a.pfb/',
+- 's/\bucrr8a.pfb\b/pcrr8a.pfb/',
+- 's/\bucrro8a.pfb\b/pcrro8a.pfb/',
+- 's/\buhvb8a.pfb\b/phvb8a.pfb/',
+- 's/\buhvb8ac.pfb\b/phvb8an.pfb/',
+- 's/\buhvbo8a.pfb\b/phvbo8a.pfb/',
+- 's/\buhvbo8ac.pfb\b/phvbo8an.pfb/',
+- 's/\buhvr8a.pfb\b/phvr8a.pfb/',
+- 's/\buhvr8ac.pfb\b/phvr8an.pfb/',
+- 's/\buhvro8a.pfb\b/phvro8a.pfb/',
+- 's/\buhvro8ac.pfb\b/phvro8an.pfb/',
+- 's/\buncb8a.pfb\b/pncb8a.pfb/',
+- 's/\buncbi8a.pfb\b/pncbi8a.pfb/',
+- 's/\buncr8a.pfb\b/pncr8a.pfb/',
+- 's/\buncri8a.pfb\b/pncri8a.pfb/',
+- 's/\buplb8a.pfb\b/pplb8a.pfb/',
+- 's/\buplbi8a.pfb\b/pplbi8a.pfb/',
+- 's/\buplr8a.pfb\b/pplr8a.pfb/',
+- 's/\buplri8a.pfb\b/pplri8a.pfb/',
+- 's/\busyr.pfb\b/psyr.pfb/',
+- 's/\butmb8a.pfb\b/ptmb8a.pfb/',
+- 's/\butmbi8a.pfb\b/ptmbi8a.pfb/',
+- 's/\butmr8a.pfb\b/ptmr8a.pfb/',
+- 's/\butmri8a.pfb\b/ptmri8a.pfb/',
+- 's/\buzcmi8a.pfb\b/pzcmi8a.pfb/',
+- 's/\buzdr.pfb\b/pzdr.pfb/',
+- );
++ open IN, "<$src" or die "$0: can't open source file $src for copying: $!";
++ open OUT, ">$dst";
+
+- @fileURW = (
+- 's/\buagd8a.pfb\b/a010015l.pfb/',
+- 's/\buagdo8a.pfb\b/a010035l.pfb/',
+- 's/\buagk8a.pfb\b/a010013l.pfb/',
+- 's/\buagko8a.pfb\b/a010033l.pfb/',
+- 's/\bubkd8a.pfb\b/b018015l.pfb/',
+- 's/\bubkdi8a.pfb\b/b018035l.pfb/',
+- 's/\bubkl8a.pfb\b/b018012l.pfb/',
+- 's/\bubkli8a.pfb\b/b018032l.pfb/',
+- 's/\bucrb8a.pfb\b/n022004l.pfb/',
+- 's/\bucrbo8a.pfb\b/n022024l.pfb/',
+- 's/\bucrr8a.pfb\b/n022003l.pfb/',
+- 's/\bucrro8a.pfb\b/n022023l.pfb/',
+- 's/\buhvb8a.pfb\b/n019004l.pfb/',
+- 's/\buhvb8ac.pfb\b/n019044l.pfb/',
+- 's/\buhvbo8a.pfb\b/n019024l.pfb/',
+- 's/\buhvbo8ac.pfb\b/n019064l.pfb/',
+- 's/\buhvr8a.pfb\b/n019003l.pfb/',
+- 's/\buhvr8ac.pfb\b/n019043l.pfb/',
+- 's/\buhvro8a.pfb\b/n019023l.pfb/',
+- 's/\buhvro8ac.pfb\b/n019063l.pfb/',
+- 's/\buncb8a.pfb\b/c059016l.pfb/',
+- 's/\buncbi8a.pfb\b/c059036l.pfb/',
+- 's/\buncr8a.pfb\b/c059013l.pfb/',
+- 's/\buncri8a.pfb\b/c059033l.pfb/',
+- 's/\buplb8a.pfb\b/p052004l.pfb/',
+- 's/\buplbi8a.pfb\b/p052024l.pfb/',
+- 's/\buplr8a.pfb\b/p052003l.pfb/',
+- 's/\buplri8a.pfb\b/p052023l.pfb/',
+- 's/\busyr.pfb\b/s050000l.pfb/',
+- 's/\butmb8a.pfb\b/n021004l.pfb/',
+- 's/\butmbi8a.pfb\b/n021024l.pfb/',
+- 's/\butmr8a.pfb\b/n021003l.pfb/',
+- 's/\butmri8a.pfb\b/n021023l.pfb/',
+- 's/\buzcmi8a.pfb\b/z003034l.pfb/',
+- 's/\buzdr.pfb\b/d050000l.pfb/',
+- );
+-
+- @fileADOBE = (
+- 's/\buagd8a.pfb\b/agd_____.pfb/',
+- 's/\buagdo8a.pfb\b/agdo____.pfb/',
+- 's/\buagk8a.pfb\b/agw_____.pfb/',
+- 's/\buagko8a.pfb\b/agwo____.pfb/',
+- 's/\bubkd8a.pfb\b/bkd_____.pfb/',
+- 's/\bubkdi8a.pfb\b/bkdi____.pfb/',
+- 's/\bubkl8a.pfb\b/bkl_____.pfb/',
+- 's/\bubkli8a.pfb\b/bkli____.pfb/',
+- 's/\bucrb8a.pfb\b/cob_____.pfb/',
+- 's/\bucrbo8a.pfb\b/cobo____.pfb/',
+- 's/\bucrr8a.pfb\b/com_____.pfb/',
+- 's/\bucrro8a.pfb\b/coo_____.pfb/',
+- 's/\buhvb8a.pfb\b/hvb_____.pfb/',
+- 's/\buhvb8ac.pfb\b/hvnb____.pfb/',
+- 's/\buhvbo8a.pfb\b/hvbo____.pfb/',
+- 's/\buhvbo8ac.pfb\b/hvnbo___.pfb/',
+- 's/\buhvr8a.pfb\b/hv______.pfb/',
+- 's/\buhvr8ac.pfb\b/hvn_____.pfb/',
+- 's/\buhvro8a.pfb\b/hvo_____.pfb/',
+- 's/\buhvro8ac.pfb\b/hvno____.pfb/',
+- 's/\buncb8a.pfb\b/ncb_____.pfb/',
+- 's/\buncbi8a.pfb\b/ncbi____.pfb/',
+- 's/\buncr8a.pfb\b/ncr_____.pfb/',
+- 's/\buncri8a.pfb\b/nci_____.pfb/',
+- 's/\buplb8a.pfb\b/pob_____.pfb/',
+- 's/\buplbi8a.pfb\b/pobi____.pfb/',
+- 's/\buplr8a.pfb\b/por_____.pfb/',
+- 's/\buplri8a.pfb\b/poi_____.pfb/',
+- 's/\busyr.pfb\b/sy______.pfb/',
+- 's/\butmb8a.pfb\b/tib_____.pfb/',
+- 's/\butmbi8a.pfb\b/tibi____.pfb/',
+- 's/\butmr8a.pfb\b/tir_____.pfb/',
+- 's/\butmri8a.pfb\b/tii_____.pfb/',
+- 's/\buzcmi8a.pfb\b/zcmi____.pfb/',
+- 's/\buzdr.pfb\b/zd______.pfb/',
+- );
++ binmode(IN);
++ binmode(OUT);
++ print OUT <IN>;
++ close(OUT);
++ close(IN);
++ my @t = stat($src);
++ utime($t[8], $t[9], $dst);
+ }
+
+-
+ ###############################################################################
+-# main()
++# files_are_identical(file_A, file_B)
++# compare two files. Same as cmp(1).
+ #
+-sub main {
+- &initVars;
+- &processOptions;
++sub files_are_identical {
++ my $file_A=shift;
++ my $file_B=shift;
++ my $retval=0;
+
+- &help if ($opt_help);
++ open IN, "$file_A";
++ my $A=(<IN>);
++ close IN;
++ open IN, "$file_B";
++ my $B=(<IN>);
++ close IN;
+
+- if (@showoptions) {
+- &showOptions(@showoptions);
+- exit 0;
+- }
++ $retval=1 if ($A eq $B);
++ return $retval;
++}
+
+- &setupCfgFile;
++###############################################################################
++# files_are_different(file_A, file_B[, comment_char])
++# compare two equalized files.
++#
++sub files_are_different {
++ my $file_A=shift;
++ my $file_B=shift;
++ my $comment=shift;
++ my $retval=0;
+
+- if ($listmaps) {
+- &listMaps ('list');
+- exit 0;
+- }
+- if ($listavailablemaps) {
+- &listMaps ('avail');
+- exit 0;
+- }
+- if ($syncwithtrees) {
+- &listMaps ('sync');
+- exit 0;
++ my $A=equalize_file("$file_A", $comment);
++ my $B=equalize_file("$file_B", $comment);
++ $retval=1 unless ($A eq $B);
++ return $retval;
++}
++
++###############################################################################
++# equalize_file(filename[, comment_char])
++# read a file and return its processed content as a string.
++# look into the source code for more details.
++#
++sub equalize_file {
++ my $file=shift;
++ my $comment=shift;
++ my @temp;
++
++ open IN, "$file";
++ my @lines = (<IN>);
++ close IN;
++ chomp(@lines);
++
++ for (@lines) {
++ s/\s*${comment}.*// if (defined $comment); # remove comments
++ next if /^\s*$/; # remove empty lines
++ s/\s+/ /g; # replace multiple whitespace chars by a single one
++ push @temp, $_;
+ }
++ return join('X', sort(@temp));
++}
+
+- my $bakFile = $cnfFile;
+- $bakFile =~ s/\.cfg$/.bak/;
+- &copyFile($cnfFile, $bakFile);
++###############################################################################
++# normalizeLines()
++# not the original function, we want it to keep comments, that are
++# anyway only the file names we are adding!
++# whitespace is exactly one space, no empty lines,
++# no whitespace at end of line, one space before and after "
++#
++sub normalizeLines {
++ my @lines = @_;
++ my %count = ();
++
++ # @lines = grep { $_ !~ m/^[*#;%]/ } @lines;
++ map {$_ =~ s/\s+/ /gx } @lines;
++ @lines = grep { $_ !~ m/^\s*$/x } @lines;
++ map { $_ =~ s/\s$//x ;
++ $_ =~ s/\s*\"\s*/ \" /gx;
++ $_ =~ s/\" ([^\"]*) \"/\"$1\"/gx;
++ } @lines;
+
+- my $cmd = '';
++ # @lines = grep {++$count{$_} < 2 } (sort @lines);
++ @lines = grep {++$count{$_} < 2 } (@lines);
+
+- if ($opt_edit) {
+- # it's not a good idea to edit updmap.cfg manually these days,
+- # but for compatibility we'll silently keep the option.
+- $cmd = 'edit';
+- my $editor = $ENV{'VISUAL'} || $ENV{'EDITOR'};
+- $editor ||= (&win32 ? "notepad" : "vi");
+- system($editor, $cnfFile);
++ return @lines;
++}
+
+- } elsif (@setoptions) {
+- $cmd = 'setOption';
+- &setOptions (@setoptions);
+
+- } elsif ($enableItem) {
+- $cmd = 'enableMap';
+- if ($enableItem =~ /=/) {
+- &enableMap(split('=', $enableItem));
++#################################################################
++#
++# reading updmap-cfg files and the actual map files
++#
++# the following hash saves *all* the information and is passed around
++# we do not fill everything from the very beginning to make sure that
++# we only read what is necessary (speed!)
++#
++# initialized by main
++# $alldata->{'changes_config'} = the config file where changes are saved
++#
++# initialized by read_updmap_files
++# $alldata->{'order'} = [ list of updmap in decreasing priority ]
++# $alldata->{'updmap'}{$full_path_name_of_updmap}{'lines'} = \@lines
++# $alldata->{'updmap'}{$full_path_name_of_updmap}{'setting'}{$key}{'val'} = $val
++# $alldata->{'updmap'}{$full_path_name_of_updmap}{'setting'}{$key}{'line'} = $i
++# $alldata->{'updmap'}{$full_path_name_of_updmap}{'maps'}{$mapname}{'type'}
++# = 'Map'|'MixedMap'|'KanjiMap'|'disabled'
++# $alldata->{'updmap'}{$full_path_name_of_updmap}{'maps'}{$mapname}{'status'}
++# = 'enabled'|'disabled'
++# $alldata->{'updmap'}{$full_path_name_of_updmap}{'maps'}{$mapname}{'line'} = $i
++# $alldata->{'maps'}{$m}{'origin'} = $updmap_path_name
++# $alldata->{'maps'}{$m}{'status'} = enabled | disabled
++#
++# initialized by read_map_files
++# $alldata->{'maps'}{$m}{'fonts'}{$font} = $definition
++# $alldata->{'fonts'}{$f}{'origin'} = $map
++#
++# initialized by merge_data
++# $alldata->{'merged'}{'setting'}{$key}{'val'} = $val
++# $alldata->{'merged'}{'setting'}{$key}{'origin'} = $origin_updmap_cfg
++# $alldata->{'merged'}{'allMaps'}{'fonts'}{$fontdef} = $rest
++# $alldata->{'merged'}{'noMixedMaps'}{'fonts'}{$fontdef} = $rest
++# $alldata->{'merged'}{'KanjiMaps'}{'fonts'}{$fontdef} = $rest
++#
++
++sub read_updmap_files {
++ my (@l) = @_;
++ for my $l (@l) {
++ my $updmap = read_updmap_file($l);
++ $alldata->{'updmap'}{$l}{'lines'} = $updmap->{'lines'};
++ if (defined($updmap->{'setting'})) {
++ for my $k (keys %{$updmap->{'setting'}}) {
++ $alldata->{'updmap'}{$l}{'setting'}{$k}{'val'} = $updmap->{'setting'}{$k}{'val'};
++ $alldata->{'updmap'}{$l}{'setting'}{$k}{'line'} = $updmap->{'setting'}{$k}{'line'};
++ }
++ }
++ if (defined($updmap->{'maps'})) {
++ for my $k (keys %{$updmap->{'maps'}}) {
++ $alldata->{'updmap'}{$l}{'maps'}{$k}{'type'} = $updmap->{'maps'}{$k}{'type'};
++ $alldata->{'updmap'}{$l}{'maps'}{$k}{'status'} = $updmap->{'maps'}{$k}{'status'};
++ $alldata->{'updmap'}{$l}{'maps'}{$k}{'line'} = $updmap->{'maps'}{$k}{'line'};
++ }
++ }
++ }
++ # in case the changes_config is a new one read it in and initialize it here
++ my $cc = $alldata->{'changes_config'};
++ if (! -r $cc) {
++ $alldata->{'updmap'}{$cc}{'lines'} = [ ];
++ }
++ #
++ $alldata->{'order'} = \@l;
++ #
++ # merge the settings so that we can check for kanjiEmbed
++ #
++ merge_settings();
++ #
++ my ($kanjiEmbed, $kanjiEmbed_origin) = get_cfg('kanjiEmbed');
++ #
++ # go through all map files and check that the text is properly replaced
++ #
++ for my $l (@l) {
++ for my $m (keys %{$alldata->{'updmap'}{$l}{'maps'}}) {
++ if ($m =~ m/\@kanjiEmbed@/) {
++ my $newm = $m;
++ $newm =~ s/\@kanjiEmbed@/$kanjiEmbed/;
++ # now we have to update various linked items
++ $alldata->{'updmap'}{$l}{'maps'}{$newm}{'type'} =
++ $alldata->{'updmap'}{$l}{'maps'}{$m}{'type'};
++ $alldata->{'updmap'}{$l}{'maps'}{$newm}{'status'} =
++ $alldata->{'updmap'}{$l}{'maps'}{$m}{'status'};
++ $alldata->{'updmap'}{$l}{'maps'}{$newm}{'line'} =
++ $alldata->{'updmap'}{$l}{'maps'}{$m}{'line'};
++ $alldata->{'updmap'}{$l}{'maps'}{$newm}{'original'} = $m;
++ delete $alldata->{'updmap'}{$l}{'maps'}{$m};
++ }
++ }
++ }
++ #
++ # first round determine which maps should be used and which type, as
++ # different updmap.cfg files might specify different types of maps
++ # (MixedMap or Map or KanjiMap).
++ # Again, we have to do that in reverse order
++ for my $l (reverse @l) {
++ if (defined($alldata->{'updmap'}{$l}{'maps'})) {
++ for my $m (keys %{$alldata->{'updmap'}{$l}{'maps'}}) {
++ $alldata->{'maps'}{$m}{'origin'} = $l;
++ $alldata->{'maps'}{$m}{'status'} = $alldata->{'updmap'}{$l}{'maps'}{$m}{'status'};
++ }
++ }
++ }
++}
++
++sub read_updmap_file {
++ my $fn = shift;
++ my $is_old_local = ($fn =~ m/updmap-local.cfg/ ? 1 : 0);
++ my %data;
++ if (!open(FN,"<$fn")) {
++ die ("Cannot read $fn: $!");
++ }
++ # we count lines from 0 ..!!!!
++ my $i = -1;
++ my @lines = <FN>;
++ chomp(@lines);
++ $data{'lines'} = [ @lines ];
++ close(FN) || warn("Cannot close $fn: $!");
++ for (@lines) {
++ $i++;
++ chomp;
++ if ($is_old_local) {
++ # in case we read an old updmap-local.cfg we have to make sure
++ # that the disable lines
++ # ^#!foo.map
++ # are rewritten to proper disable lines
++ # ^#! Map foo.map
++ # we are guessing here the type of the map (namely Map)
++ $_ =~ s/^#!([^ ])/#! Map $1/;
++ }
++ next if /^\s*$/;
++ next if /^\s*#$/;
++ next if /^\s*#[^!]/;
++ next if /^\s*##/;
++ next if /^#![^ ]/;
++ # allow for commands on the line itself
++ s/([^#].*)#.*$/$1/;
++ my ($a, $b, @rest) = split ' ';
++ if ($a eq "#!") {
++ if ($b eq "Map" || $b eq "MixedMap" || $b eq "KanjiMap") {
++ my $c = shift @rest;
++ if (!defined($c)) {
++ warning("updmap: apparently not a real disable line, ignored: $_\n");
++ } else {
++ if (defined($data{'maps'}{$c})) {
++ warning("updmap: double mentioning of $c in $fn\n");
++ }
++ $data{'maps'}{$c}{'status'} = 'disabled';
++ $data{'maps'}{$c}{'type'} = $b;
++ $data{'maps'}{$c}{'line'} = $i;
++ }
++ }
++ next;
++ }
++ if (@rest) {
++ warning("updmap: line $i in $fn contains a syntax error, more than two words!\n");
++ }
++ if (defined($settings{$a})) {
++ if (check_option($a, $b)) {
++ $data{'setting'}{$a}{'val'} = $b;
++ $data{'setting'}{$a}{'line'} = $i;
++ } else {
++ warning("updmap: unknown setting for $a: $b, ignored!\n");
++ }
++ } elsif ($a eq "Map" || $a eq "MixedMap" || $a eq "KanjiMap") {
++ if (defined($data{'maps'}{$b}) && $data{'maps'}{$b}{'type'} ne $a) {
++ warning("updmap: double mentioning of $b with conflicting types in $fn\n");
++ } else {
++ $data{'maps'}{$b}{'type'} = $a;
++ $data{'maps'}{$b}{'status'} = 'enabled';
++ $data{'maps'}{$b}{'line'} = $i;
++ }
+ } else {
+- &enableMap($enableItem, shift @ARGV);
++ warning("updmap: unrecognized line $i in $fn: $_\n");
+ }
++ }
++ return \%data;
++}
+
+- } elsif (@disableItem) {
+- $cmd = 'disableMap';
+- foreach my $m (@disableItem) {
+- &disableMap($m);
++sub read_map_files {
++ if (!defined($alldata->{'updmap'})) {
++ return;
++ }
++ my @missing;
++ my @l = @{$alldata->{'order'}};
++ # first collect all the map files we are interested in
++ # and determine whether they exist, and get their full path
++ my @maps;
++ for my $f (@l) {
++ next if !defined($alldata->{'updmap'}{$f}{'maps'});
++ for my $m (keys %{$alldata->{'updmap'}{$f}{'maps'}}) {
++ # only read a map file if its final status is enabled!
++ push @maps, $m if ($alldata->{'maps'}{$m}{'status'} eq 'enabled');
++ }
++ }
++ for my $m (qw/dvips35.map pdftex35.map ps2pk35.map/) {
++ push @maps, $m;
++ $alldata->{'maps'}{$m}{'status'} = 'enabled';
++ }
++ @maps = sort_uniq(@maps);
++ my @fullpath = `kpsewhich --format=map @maps`;
++ chomp @fullpath;
++ foreach my $map (@maps) {
++ my ($ff) = grep /\/$map(\.map)?$/, @fullpath;
++ if ($ff) {
++ $alldata->{'maps'}{$map}{'fullpath'} = $ff;
++ } else {
++ # if the map file is not found, then push it onto the list of
++ # missing map files, since we know that it is enabled
++ push @missing, $map;
+ }
+ }
+
+- if ($cmd && !$opt_force && &files_are_equal($bakFile, $cnfFile)) {
+- print "$cnfFile unchanged. Map files not recreated.\n" if !$quiet;
+- } else {
+- if (! $nomkmap) {
+- &setupDestDir;
+- &mkMaps;
++ #
++ # read in the three basic fonts definition maps
++ for my $m (qw/dvips35.map pdftex35.map ps2pk35.map/) {
++ my $ret = read_map_file($alldata->{'maps'}{$m}{'fullpath'});
++ my @ff = ();
++ for my $font (keys %$ret) {
++ $alldata->{'fonts'}{$font}{'origin'} = $m;
++ $alldata->{'maps'}{$m}{'fonts'}{$font} = $ret->{$font};
++ }
++ }
++ # we read the updmap in reverse directions, since we
++ # replace the origin field of font definition always with the
++ # top one
++ for my $f (reverse @l) {
++ my @maps = keys %{$alldata->{'updmap'}{$f}{'maps'}};
++ for my $m (@maps) {
++ # we do not read a map file multiple times, if $alldata{'maps'}{$m} is
++ # defined we expect that it was read and do skip it
++ next if defined($alldata->{'maps'}{$m}{'fonts'});
++ # we do not read a map files content if it is disabled
++ next if ($alldata->{'maps'}{$m}{'status'} eq 'disabled');
++ if (!defined($alldata->{'maps'}{$m}{'fullpath'})) {
++ # we have already pushed these map files onto the list of missing
++ # map files, so do nothing here
++ next;
++ }
++ my $ret = read_map_file($alldata->{'maps'}{$m}{'fullpath'});
++ if (defined($ret)) {
++ for my $font (keys %$ret) {
++ if (defined($alldata->{'fonts'}{$font})) {
++ # we got another definition, warn on that
++ # if the origin is not defined by now, the font is defined
++ # multiple times in the same map file, otherwise it is
++ # defined in another map file already
++ if (defined($alldata->{'fonts'}{$font}{'origin'})) {
++ my $fontorig = $alldata->{'fonts'}{$font}{'origin'};
++ my $maporig = $alldata->{'maps'}{$fontorig}{'origin'};
++ warning("$prg: font $font is defined multiple times:\n");
++ warning("$prg: $fontorig (from $maporig)\n");
++ warning("$prg: $m (from $f) (used)\n");
++ } else {
++ warning("$prg: font $font is multiply defined in $m, using an arbitrary instance!\n");
++ }
++ }
++ $alldata->{'fonts'}{$font}{'origin'} = $m;
++ $alldata->{'maps'}{$m}{'fonts'}{$font} = $ret->{$font};
++ }
++ }
+ }
+- unlink ($bakFile);
+ }
++ return (@missing);
++}
+
+- unless ($nohash) {
+- print "$0: Updating ls-R files.\n" if !$quiet;
+- $updLSR->{exec}()
++sub read_map_file {
++ my $fn = shift;
++ my @lines;
++ if (!open(MF,"<$fn")) {
++ warn("cannot open $fn: $!");
++ return;
++ }
++ @lines = <MF>;
++ close(MF);
++ chomp(@lines);
++ my %data;
++ for (@lines) {
++ next if /^\s*#/;
++ next if /^\s*%/;
++ next if /^\s*$/;
++ my ($a, $b) = split(' ', $_, 2);
++ $data{$a} = $b;
+ }
++ return \%data;
++}
++
++#
++# merge and update the setting
++#
++sub merge_settings {
++ my @l = @{$alldata->{'order'}};
++ #
++ # for security clean out everything that was there
++ %{$alldata->{'merged'}} = ();
++ #
++ # first read in the settings
++ # we read it in *reverse* order and simple fill up the combined data
++ # thus if there are multiple definitions/settings, the one coming from
++ # the first in the original list will win!
++ for my $l (reverse @l) {
++ # merge settings
++ if (defined($alldata->{'updmap'}{$l}{'setting'})) {
++ for my $k (keys %{$alldata->{'updmap'}{$l}{'setting'}}) {
++ $alldata->{'merged'}{'setting'}{$k}{'val'} = $alldata->{'updmap'}{$l}{'setting'}{$k}{'val'};
++ $alldata->{'merged'}{'setting'}{$k}{'origin'} = $l;
++ }
++ }
++ }
++ #
++}
++
++#
++# merging the various font definitions
++#
++sub merge_data {
++ my @l = @{$alldata->{'order'}};
++ #
++ # now merge the data
++ #
++ for my $m (keys %{$alldata->{'maps'}}) {
++ my $origin = $alldata->{'maps'}{$m}{'origin'};
++ next if !defined($origin);
++ next if ($alldata->{'updmap'}{$origin}{'maps'}{$m}{'status'} eq "disabled");
++ for my $f (keys %{$alldata->{'maps'}{$m}{'fonts'}}) {
++ # use the font definition only for those fonts where the origin matches
++ if ($alldata->{'fonts'}{$f}{'origin'} eq $m) {
++ $alldata->{'merged'}{'allMaps'}{'fonts'}{$f} =
++ $alldata->{'maps'}{$m}{'fonts'}{$f}
++ if ($alldata->{'updmap'}{$origin}{'maps'}{$m}{'type'} ne "KanjiMap");
++ $alldata->{'merged'}{'noMixedMaps'}{'fonts'}{$f} =
++ $alldata->{'maps'}{$m}{'fonts'}{$f}
++ if ($alldata->{'updmap'}{$origin}{'maps'}{$m}{'type'} eq "Map");
++ $alldata->{'merged'}{'KanjiMap'}{'fonts'}{$f} =
++ $alldata->{'maps'}{$m}{'fonts'}{$f}
++ if ($alldata->{'updmap'}{$origin}{'maps'}{$m}{'type'} eq "KanjiMap");
++ }
++ }
++ }
++}
++
++sub warning {
++ print STDERR @_;
++}
++
++#
++# help, version etc etc
++#
++
++sub version {
++ my $ret = sprintf "%s (TeX Live, multi) version %s\n", $prg, $version;
++ return $ret;
++}
++
++sub help {
++ my $usage = <<"EOF";
++Usage: $prg [OPTION] ... [COMMAND]
++ or: $prg-sys [OPTION] ... [COMMAND]
++
++Update the default font map files used by pdftex, dvips, and dvipdfm(x),
++(and optionally pxdvi) as determined by all configuration files updmap.cfg
++(the ones returned by running "kpsewhich --all updmap.cfg", but see below).
++
++Among other things, these map files are used to determine which fonts
++should be used as bitmaps and which as outlines, and to determine which
++fonts are included in the output.
++
++By default, the TeX filename database (ls-R) is also updated.
++
++Options:
++ --cnffile FILE read FILE for the updmap configuration
++ (can be given multiple times, in which case
++ all the files are used)
++ --dvipdfmoutputdir DIR specify output directory (dvipdfm syntax)
++ --dvipsoutputdir DIR specify output directory (dvips syntax)
++ --pdftexoutputdir DIR specify output directory (pdftex syntax)
++ --pxdvioutputdir DIR specify output directory (pxdvi syntax)
++ --outputdir DIR specify output directory (for all files)
++ --copy cp generic files rather than using symlinks
++ --force recreate files even if config hasn't changed
++ --nomkmap do not recreate map files
++ --nohash do not run texhash
++ -n, --dry-run only show the configuration, no output
++ --quiet, --silent reduce verbosity
++
++Commands:
++ --help show this message and exit
++ --version show version information and exit
++ --showoptions OPTION show possible settings for OPTION
++ --showoption OPTION show the current setting of OPTION
++ --setoption OPTION VALUE set OPTION to value
++ --setoption OPTION=VALUE as above, just different syntax
++ --enable MAPTYPE MAPFILE add "MAPTYPE MAPFILE" to updmap.cfg,
++ where MAPTYPE is either Map, MixedMap, KanjiMap
++ --enable Map=MAPFILE add \"Map MAPFILE\" to updmap.cfg
++ --enable MixedMap=MAPFILE add \"MixedMap MAPFILE\" to updmap.cfg
++ --enable KanjiMap=MAPFILE add \"KanjiMap MAPFILE\" to updmap.cfg
++ --disable MAPFILE disable MAPFILE, whether Map, MixedMap, or KanjiMap
++ --listmaps list all active and inactive maps
++ --listavailablemaps same as --listmaps, but without
++ unavailable map files
++ --syncwithtrees disable unavailable map files in updmap.cfg
++
++Explanation of the map types: the (only) difference between Map and
++MixedMap is that MixedMap entries are not added to psfonts_pk.map.
++KanjiMap entries are added to psfonts_t1.map and kanjix.map.
++The purpose is to help users with printers that render Type 1 outline
++fonts worse than mode-tuned Type 1 bitmap fonts. So, MixedMap is used
++for fonts that are available as both Type 1 and Metafont.
++
++Explanation of the possible OPTIONS (showoptions, showoptions, setoption):
++
++ dvipsPreferOutline true|false (default true)
++ Whether dvips uses bitmaps or outlines, when both are available.
++ dvipsDownloadBase35 true|false (default false)
++ Whether dvips includes the standard 35 PostScript fonts in its output.
++ pdftexDownloadBase14 true|false (default true)
++ Whether pdftex includes the standard 14 PDF fonts in its output.
++ pxdviUse true|false (default false)
++ Whether maps for pxdvi (Japanese-patched xdvi) is under control of updmap.
++ LW35 URWkb|URW|ADOBEkb|ADOBE (default URWkb)
++ Adapt the font and file names of the standard 35 PostScript fonts.
++ URWkb URW fonts with "berry" filenames (e.g. uhvbo8ac.pfb)
++ URW URW fonts with "vendor" filenames (e.g. n019064l.pfb)
++ ADOBEkb Adobe fonts with "berry" filenames (e.g. phvbo8an.pfb)
++ ADOBE Adobe fonts with "vendor" filenames (e.g. hvnbo___.pfb)
++ kanjiEmbed (any string)
++
++ These options are only read and acted on by updmap; dvips, pdftex, etc.,
++ do not know anything about them. They work by changing the default map
++ file which the programs read, so they can be overridden by specifying
++ command-line options or configuration files to the programs, as
++ explained at the beginning of updmap.cfg.
++
++Explanation of trees and files normally used:
++
++NEEDS TO BE FIXED TODO TODO TODO AFTER FINAL INCLUSION
++
++BEHAVIOUR HOW IT IS NOW
++
++ updmap reads all the updmap.cfg found by
++ kpsewhich -all updmap.cfg
++ or those given on the command line with --cnffile. If kpsewhich is
++ used to determine the list of config files, there is one caveat: An
++ occurrence of updmap.cfg in TEXMFLOCAL is moved up in the priority
++ list just after files from TEXMFCONFIG, TEXMFVAR and TEXMFHOME. This
++ allows system administrator to override settings in
++ TEXMFSYSCONFIG/web2c/updmap.cfg which is used by tlmgr to manage
++ the installed options.
++
++BEHAVIOUR HOW IT SHOULD BE AFTER INCLUSION
++
++ updmap reads all the updmap.cfg files found by
++ kpsewhich -all updmap.cfg
++ in the order returned by kpsewhich. There is one exception to keep
++ upgradability from earlier versions of TeX Live: If there is a file
++ TEXMFLOCAL/web2c/updmap-local.cfg (which was formerly used by tlmgr
++ to merge local fonts), then a (not necessarily existing) file
++ TEXMFLOCAL/web2c/updmap.cfg is ignored and the updmap-local.cfg is
++ used instead. In this case updmap recognizes also the syntax for
++ disabling map files in the updmap-local.cfg (this syntax was different
++ to what is used now!).
++
++ According to the actions updmap might write to one of the given files or
++ create a new updmap.cfg, see below for details.
++
++ If multiple updmap.cfg files are found, all the map files mentioned
++ in all the updmap.cfg files are merged.
++
++ CAVEATS with multiple updmap.cfg files
++ * where changes are saved
++ If config files are given on the cmd line, then the first given will
++ be used to save changes (by --setoption, --enable or --disable).
++ If the config files are taken from kpsewhich, then the algorithm is
++ more complex:
++ - if one of \$TEXMFHOME/web2c/updmap.cfg or \$TEXMFCONFIG/web2c/updmap.cfg
++ appears in the list of used files, then the one given *first* by
++ kpsewhich --all, or equivalently, the one given by kpsewhich updmap.cfg,
++ is used
++ - if none of the above two are present, a new config file is created
++ in \$TEXMFCONFIG/web2c/updmap.cfg (in case there are actual changes)
++ and used
++
++ * multiple font definitions
++ If a font is defined multiple times in different maps, then the
++ definition of the map file that comes from the highest priority
++ updmap.cfg file is used.
++ If a font is defined multiple times in the same map file, an
++ arbitrary definition is used.
++ In both cases warnings are issued.
++
++ * disabling map files
++ updmap.cfg files with higher priority can disable map files that
++ are mentioned in lower priority updmap.cfg files by disabling
++ them, i.e., writing
++ \#! Map mapname.map
++ or
++ \#! MixedMap mapname.map
++ into the higher prioprity updmap.cfg file.
++
++ As an example take a user with a copy of the commercial MTPRO fonts.
++ He wants to disable the belleek version of the fonts, that is
++ disable the map belleek.map. The user should create a updmap.cfg file
++ in \$TEXMFCONFIG/web2c/updmap.cfg with the content
++ #! Map belleek.map
++ Map mt-plus.map
++ Map mt-yy.map
++ and call $prg.
++
++ updmap writes the map files for dvips (psfonts.map) and pdftex
++ (pdftex.map) to the TEXMFVAR/fonts/map/updmap/{dvips,pdftex}/
++ directories.
++
++ The log file is written to TEXMFVAR/web2c/updmap.log.
++
++ When updmap-sys is run, TEXMFSYSCONFIG and TEXMFSYSVAR are used
++ instead. This is the only difference between updmap-sys and updmap.
++
++ Other locations can be used if overridden on the command line, or these
++ trees don't exist, or you are not using the original TeX Live.
++
++ To see the precise locations of the various files that
++ will be read and written, give the -n option (or read the man page).
++
++For step-by-step instructions on making new fonts known to TeX, read
++http://tug.org/fonts/fontinstall.html. For even more terse
++instructions, read the beginning of updmap.cfg.
++
++Report bugs to: tex-k\@tug.org
++TeX Live home page: <http://tug.org/texlive/>
++EOF
++;
++ print &version();
++ print $usage;
++ exit 0;
+ }
+-__END__
+
+ ### Local Variables:
+ ### perl-indent-level: 2
diff --git a/Master/tlpkg/dev/quilt-patches/series b/Master/tlpkg/dev/quilt-patches/series
new file mode 100644
index 00000000000..5297f57d7da
--- /dev/null
+++ b/Master/tlpkg/dev/quilt-patches/series
@@ -0,0 +1,2 @@
+dev.multi-source-support-v2.patch -p0
+dev.multi-updmap