From 8c4f0fbddf73041e3a8c0fb9fd127de72a7ef33d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Sat, 20 Aug 2011 02:00:47 +0000 Subject: multi-updmap: allow setting of options in the top config file git-svn-id: svn://tug.org/texlive/trunk@23611 c570f23f-e606-0410-a88d-b1316a301751 --- Master/tlpkg/dev/multi-updmap.pl | 308 +++++++++++++++++++++++++++++++-------- 1 file changed, 244 insertions(+), 64 deletions(-) (limited to 'Master') diff --git a/Master/tlpkg/dev/multi-updmap.pl b/Master/tlpkg/dev/multi-updmap.pl index 7680da76339..2d93452b621 100644 --- a/Master/tlpkg/dev/multi-updmap.pl +++ b/Master/tlpkg/dev/multi-updmap.pl @@ -43,6 +43,8 @@ my $prg = TeXLive::TLUtils::basename($0); use Data::Dumper; my %opts = ( quiet => 0, nohash => 0, nomkmap => 0 ); +my $alldata; + my @cmdline_options = ( "cnffile=s@", "copy", @@ -120,21 +122,22 @@ sub main { my ($top_config_file) = @{$opts{'cnffile'}}; my $bakFile = $top_config_file; $bakFile =~ s/\.cfg$/.bak/; - ©File($top_config_file, $bakFile); + my $changed = 0; my $cmd; - my $data = read_updmap_files(@{$opts{'cnffile'}}); + read_updmap_files(@{$opts{'cnffile'}}); if ($opts{'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"); + ©File($top_config_file, $bakFile); system($editor, $top_config_file); + $changed = files_are_different($bakFile, $top_config_file); } elsif ($opts{'setoption'}) { $cmd = 'setOption'; - warning("NOT IMPLEMENTED setoption!\n"); - exit 1; + $changed = setOptions (@{$opts{'setoption'}}); } elsif ($opts{'enable'}) { $cmd = 'enableMap'; warning("NOT IMPLEMENTED enable!\n"); @@ -145,16 +148,16 @@ sub main { exit 1; } - if ($cmd && !$opts{'force'} && files_are_equal($bakFile, $top_config_file)) { + if ($cmd && !$opts{'force'} && !$changed) { print "$top_config_file unchanged. Map files not recreated.\n" if !$opts{'quiet'}; } else { if (!$opts{'nomkmap'}) { setupOutputDir("dvips"); setupOutputDir("pdftex"); - mkMaps($data); + mkMaps(); } - unlink ($bakFile); + unlink ($bakFile) if (-r $bakFile); } my $updLSR = &mktexupd(); @@ -169,10 +172,10 @@ sub main { sub mkMaps { warning("NOT IMPLEMENTED mkMaps ... dumping data structure for now!\n"); $Data::Dumper::Indent = 1; - my $data = read_updmap_files(@{$opts{'cnffile'}}); - $data = read_map_files($data); - $data = merge_data($data); - print Data::Dumper->Dump([$data], [qw(mapdata)]); + read_updmap_files(@{$opts{'cnffile'}}); + read_map_files(); + merge_data(); + print Data::Dumper->Dump([$alldata], [qw(mapdata)]); } @@ -227,6 +230,131 @@ sub setupOutputDir { return $od; } +############################################################################### +# 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 setOptions { + my (@options) = @_; + for (my $i = 0; $i < @options; $i++) { + my $o = $options[$i]; + + my ($key,$val) = split (/=/, $o, 2); + + die "$prg: unexpected empty key or val for options (@options), goodbye.\n" + if !$key || !$val; + &setOption ($key, $val); + } + return save_updmap($alldata->{'top_config'}); +} + +# returns 1 if actually saved due to changes +sub save_updmap { + my $fn = shift; + my %upd = %{$alldata->{'updmap'}{$fn}}; + if ($upd{'changed'}) { + open (FN, ">$fn") || die "$prg: can't write to $fn: $!"; + # 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; + } + } + } + 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; + } + } + } + my @lines = @{$upd{'lines'}}; + 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 $t = $upd{'maps'}{$m}{'type'}; + my $p = ($upd{'maps'}{$m}{'status'} eq "disabled" ? "#! " : ""); + print FN "$p$t $m\n"; + } else { + print "$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; + } + return 0; +} + +############################################################################### +# 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) = @_; + + if ($opt eq "LW35") { + if ($val !~ m/^(URWkb|URW|ADOBE|ADOBEkb)$/) { + die "$0: Invalid value $val for option $opt.\n"; + } + } elsif ($opt =~ +m/^(dvipsPreferOutline|dvipsDownloadBase35|(pdftex|dvipdfm)DownloadBase14)$/) { + if ($val !~ m/^(true|false)$/) { + die "$0: Invalid value $val for option $opt; should be \"true\" or \"false\".\n"; + } + } else { + die "$0: Unsupported option $opt.\n"; + } + + # silently accept this old option name, just in case. + return if $opt eq "dvipdfmDownloadBase14"; + + #print "Setting option $opt to $val...\n" if !$quiet; + my $tc = $alldata->{'top_config'}; + if (!defined($alldata->{'updmap'}{$tc})) { + die "$prg: top config file $tc has not been read."; + } + if (defined($alldata->{'updmap'}{$tc}{'setting'}{$opt}{'val'})) { + 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; + } +} + + ############################################################################# # showOptions(item) # show Options for an item @@ -255,11 +383,11 @@ m/(dvipsPreferOutline|(dvipdfm|pdftex)DownloadBase14|dvipsDownloadBase35)/) { # Maptype Mapname 'enabled'|'disabled' 'in' updmap_cfg_filename # sub listMaps { - my $data = read_updmap_files(@{$opts{'cnffile'}}); - for my $m (keys %{$data->{'maps'}}) { - my $origin = $data->{'maps'}{$m}{'origin'}; - print $data->{'updmap'}{$origin}{'maps'}{$m}{'type'}, " $m ", - $data->{'updmap'}{$origin}{'maps'}{$m}{'status'}, " in $origin\n"; + read_updmap_files(@{$opts{'cnffile'}}); + 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"; } } @@ -287,6 +415,47 @@ sub copyFile { utime($t[8], $t[9], $dst); } +############################################################################### +# 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; + + 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 = (); + 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)); +} + + ################################################################# # # reading updmap-cfg files and the actual map files @@ -296,53 +465,61 @@ sub copyFile { # we only read what is necessary (speed!) # # initialized by read_updmap_files -# $data->{'order'} = [ list of updmap in decreasing priority ] -# $data->{'updmap'}{$full_path_name_of_updmap}{'setting'}{$key} = $val -# $data->{'updmap'}{$full_path_name_of_updmap}{'maps'}{$mapname}{'type'} +# $alldata->{'top_config'} = first element of the following list, where +# all the changes are executed +# $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'|'disabled' -# $data->{'updmap'}{$full_path_name_of_updmap}{'maps'}{$mapname}{'status'} +# $alldata->{'updmap'}{$full_path_name_of_updmap}{'maps'}{$mapname}{'status'} # = 'enabled'|'disabled' -# $data->{'maps'}{$m}{'origin'} = $updmap_path_name +# $alldata->{'updmap'}{$full_path_name_of_updmap}{'maps'}{$mapname}{'line'} = $i +# $alldata->{'maps'}{$m}{'origin'} = $updmap_path_name # # initialized by read_map_files -# $data->{'maps'}{$m}{'fonts'}{$font} = $rest +# $alldata->{'maps'}{$m}{'fonts'}{$font} = $rest # # initialized by merge_data -# $data->{'merged'}{'setting'}{$key} = $val -# $data->{'merged'}{'allMaps'}{'fonts'}{$fontdef} = $rest -# $data->{'merged'}{'noMixedMaps'}{'fonts'}{$fontdef} = $rest +# $alldata->{'merged'}{'setting'}{$key} = $val +# $alldata->{'merged'}{'allMaps'}{'fonts'}{$fontdef} = $rest +# $alldata->{'merged'}{'noMixedMaps'}{'fonts'}{$fontdef} = $rest # sub read_updmap_files { my (@l) = @_; - my %data; 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'}}) { - $data{'updmap'}{$l}{'setting'}{$k} = $updmap->{'setting'}{$k}; + $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'}}) { - $data{'updmap'}{$l}{'maps'}{$k}{'type'} = $updmap->{'maps'}{$k}{'type'}; - $data{'updmap'}{$l}{'maps'}{$k}{'status'} = $updmap->{'maps'}{$k}{'status'}; + $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'}; } } } - $data{'order'} = \@l; + $alldata->{'order'} = \@l; + # get the first config file where we will do all the changes + $alldata->{'top_config'} = $l[0]; # 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). # Again, we have to do that in reverse order for my $l (reverse @l) { - if (defined($data{'updmap'}{$l}{'maps'})) { - for my $m (keys %{$data{'updmap'}{$l}{'maps'}}) { - $data{'maps'}{$m}{'origin'} = $l; + if (defined($alldata->{'updmap'}{$l}{'maps'})) { + for my $m (keys %{$alldata->{'updmap'}{$l}{'maps'}}) { + $alldata->{'maps'}{$m}{'origin'} = $l; } } } - return \%data; } sub read_updmap_file { @@ -351,9 +528,14 @@ sub read_updmap_file { log("Cannot read $fn: $!"); return; } - my $i = 0; + # we count lines from 0 ..!!!! + my $i = -1; my %data; - while () { + my @lines = ; + chomp(@lines); + $data{'lines'} = [ @lines ]; + close(FN) || warn("Cannot close $fn: $!"); + for (@lines) { $i++; chomp; next if /^\s*$/; @@ -374,6 +556,7 @@ sub read_updmap_file { } $data{'maps'}{$c}{'status'} = 'disabled'; $data{'maps'}{$c}{'type'} = $b; + $data{'maps'}{$c}{'line'} = $i; } } next; @@ -384,7 +567,8 @@ sub read_updmap_file { if (defined($settings{$a})) { my @possible_values = @{$settings{$a}}; if (scalar(grep($_ eq $b, @possible_values))) { - $data{'setting'}{$a} = $b; + $data{'setting'}{$a}{'val'} = $b; + $data{'setting'}{$a}{'line'} = $i; } else { warning("updmap: unknown setting for $a: $b, ignored!\n"); } @@ -394,35 +578,33 @@ sub read_updmap_file { } else { $data{'maps'}{$b}{'type'} = $a; $data{'maps'}{$b}{'status'} = 'enabled'; + $data{'maps'}{$b}{'line'} = $i; } } else { warning("updmap: unrecognized line $i in $fn: $_\n"); } } - close(FN) || warn("Cannot close $fn: $!"); return \%data; } sub read_map_files { - my $data = shift; - if (!defined($data->{'updmap'})) { - return $data; + if (!defined($alldata->{'updmap'})) { + return $alldata; } - for my $f (keys %{$data->{'updmap'}}) { - next if !defined($data->{'updmap'}{$f}{'maps'}); - for my $m (keys %{$data->{'updmap'}{$f}{'maps'}}) { - # we do not read a map file multiple times, if $data{'maps'}{$m} is + for my $f (keys %{$alldata->{'updmap'}}) { + next if !defined($alldata->{'updmap'}{$f}{'maps'}); + for my $m (keys %{$alldata->{'updmap'}{$f}{'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($data->{'maps'}{$m}{'fonts'}); + next if defined($alldata->{'maps'}{$m}{'fonts'}); my $ret = read_map_file($m); if (defined($ret)) { for my $font (keys %$ret) { - $data->{'maps'}{$m}{'fonts'}{$font} = $ret->{$font}; + $alldata->{'maps'}{$m}{'fonts'}{$font} = $ret->{$font}; } } } } - return $data; } sub read_map_file { @@ -447,11 +629,10 @@ sub read_map_file { # merging the various font definitions # sub merge_data { - my $data = shift; - my @l = @{$data->{'order'}}; + my @l = @{$alldata->{'order'}}; # # for security clean out everything that was there - %{$data->{'merged'}} = (); + %{$alldata->{'merged'}} = (); # # first read in the settings # we read it in *reverse* order and simple fill up the combined data @@ -459,27 +640,26 @@ sub merge_data { # the first in the original list will win! for my $l (reverse @l) { # merge settings - if (defined($data->{'updmap'}{$l}{'setting'})) { - for my $k (keys %{$data->{'updmap'}{$l}{'setting'}}) { - $data->{'merged'}{'setting'}{$k} = $data->{'updmap'}{$l}{'setting'}{$k}; + if (defined($alldata->{'updmap'}{$l}{'setting'})) { + for my $k (keys %{$alldata->{'updmap'}{$l}{'setting'}}) { + $alldata->{'merged'}{'setting'}{$k} = $alldata->{'updmap'}{$l}{'setting'}{$k}{'val'}; } } } # # now merge the data # - for my $m (keys %{$data->{'maps'}}) { - my $origin = $data->{'maps'}{$m}{'origin'}; - next if ($data->{'updmap'}{$origin}{'maps'}{$m}{'status'} eq "disabled"); - for my $f (keys %{$data->{'maps'}{$m}{'fonts'}}) { - $data->{'merged'}{'allMaps'}{'fonts'}{$f} = - $data->{'maps'}{$m}{'fonts'}{$f}; - $data->{'merged'}{'noMixedMaps'}{'fonts'}{$f} = - $data->{'maps'}{$m}{'fonts'}{$f} - if ($data->{'updmap'}{$origin}{'maps'}{$m}{'type'} eq "Map"); + for my $m (keys %{$alldata->{'maps'}}) { + my $origin = $alldata->{'maps'}{$m}{'origin'}; + next if ($alldata->{'updmap'}{$origin}{'maps'}{$m}{'status'} eq "disabled"); + for my $f (keys %{$alldata->{'maps'}{$m}{'fonts'}}) { + $alldata->{'merged'}{'allMaps'}{'fonts'}{$f} = + $alldata->{'maps'}{$m}{'fonts'}{$f}; + $alldata->{'merged'}{'noMixedMaps'}{'fonts'}{$f} = + $alldata->{'maps'}{$m}{'fonts'}{$f} + if ($alldata->{'updmap'}{$origin}{'maps'}{$m}{'type'} eq "Map"); } } - return $data; } sub warning { -- cgit v1.2.3