#! /usr/bin/env perl # updmap: utility to maintain map files for outline fonts. # # Thomas Esser, (C) 2002. # Fabrice Popineau, for the Perl version. # Anyone may freely use, modify, and/or distribute this file, without # limitation. BEGIN { $^W=1; chomp($TEXMFROOT = `kpsewhich -var-value=TEXMFROOT`); unshift (@INC, "$TEXMFROOT/tlpkg"); } my $version = '$Id$'; 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 $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 $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), 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 --dvipsoutputdir DIR specify output directory (dvips syntax) --pdftexoutputdir DIR specify output directory (pdftex 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, or pdftexDownloadBase14 --setoption OPTION=VALUE as above, just different syntax --enable MAPTYPE MAPFILE add "MAPTYPE MAPFILE" to updmap.cfg, where MAPTYPE is either Map or MixedMap --enable Map=MAPFILE add \"Map MAPFILE\" to updmap.cfg --enable MixedMap=MAPFILE add \"MixedMap MAPFILE\" to updmap.cfg --disable MAPFILE disable MAPFILE, whether Map or MixedMap --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. 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) 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: updmap both reads and writes TEXMFCONFIG/web2c/updmap.cfg, according to the actions specified. 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: EOF ; print &version(); print $usage; exit 0; } ############################################################################### # processOptions() # process cmd line options # sub processOptions { unless (&GetOptions ( "cnffile=s" => \$cnfFile, "copy" => \$copy, "disable=s" => \@disableItem, "dvipdfmoutputdir=s" => sub {print "$0: ignoring --dvipdfmoutputdir\n"}, "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, "q|quiet|silent" => \$quiet, "setoption=s{1,2}" => \@setoptions, "showoptions=s" => \@showoptions, "syncwithtrees" => \$syncwithtrees, "version" => sub { print &version(); exit(0); }, "h|help" => \$opt_help)) { die "Try \"$0 --help\" for more information.\n"; } if ($outputdir) { $dvipsoutputdir = $outputdir if (! $dvipsoutputdir); $pdftexoutputdir = $outputdir if (! $pdftexoutputdir); } if ($cnfFile && ! -f $cnfFile) { die "$0: Config file \"$cnfFile\" not found.\n"; } if ($dvipsoutputdir && ! $dry_run && ! -d $dvipsoutputdir) { &mkdirhier ($dvipsoutputdir); } if ($pdftexoutputdir && ! $dry_run && ! -d $pdftexoutputdir) { &mkdirhier ($pdftexoutputdir); } } ############################################################################### # 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)); } ############################################################################### # 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; } ############################################################################### # 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; } ############################################################################### # 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; open IN, "$file_A"; my $A=(); close IN; open IN, "$file_B"; my $B=(); close IN; $retval=1 if ($A eq $B); return $retval; } ############################################################################### # getLines() # ############################################################################### sub getLines { 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=; 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"; } } $maps{"$fname"} = [ @file ] if ($cache); push @lines, @file; } else { push @lines, @{$maps{"$fname"}}; } } chomp @lines; return @lines; } ############################################################################### # writeLines() # write the lines in $filename # sub writeLines { my ($fname, @lines) = @_; map { ($_ !~ m/\n$/ ? s/$/\n/ : $_ ) } @lines; open FILE, ">$fname" or die "$0: can't write lines to $fname: $!"; print FILE @lines; close FILE; } ############################################################################### # copyFile() # copy file $src to $dst, sets $dst creation and mod time # 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 ; 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 ©File("$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. $link{"$dest"}="$src"; } ############################################################################### # setupSymlinks() # set symlink for psfonts.map according to dvipsPreferOutline variable # sub setupSymlinks { my $src; if ($dvipsPreferOutline) { $src = "psfonts_t1.map"; } else { $src = "psfonts_pk.map"; } unlink "$dvipsoutputdir/psfonts.map"; &SymlinkOrCopy("$dvipsoutputdir", "$src", "psfonts.map"); if ($pdftexDownloadBase14) { $src = "pdftex_dl14.map"; } else { $src = "pdftex_ndl14.map"; } unlink "$pdftexoutputdir/pdftex.map"; &SymlinkOrCopy("$pdftexoutputdir", "$src", "pdftex.map"); } ############################################################################### # transLW35(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); if ($mode eq "" || $mode eq "URWkb") { # do nothing } elsif ($mode eq "URW") { for my $r (@fileURW) { map { eval($r); } @lines; } } elsif ($mode eq "ADOBE" || $mode eq "ADOBEkb") { for my $r (@psADOBE) { map { eval($r); } @lines; } my @filemode = eval ("\@file" . $mode); for my $r (@filemode) { map { eval($r); } @lines; } } return @lines; } ############################################################################### # 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]; } } ############################################################################### # locateMap (file ...) # apply kpsewhich with format 'dvips config' # sub locateMap { my @maps = @_; my @files; return @maps if ($#maps < 0); @files = `kpsewhich --format=map @maps`; chomp @files; foreach my $map (@maps) { push @missing, $map if (! grep /\/$map$/, @files); } if (wantarray) { return @files; } else { return $files[0]; } } ############################################################################### # cfgval(variable) # read variable ($1) from config file # sub cfgval { my ($variable) = @_; my $value; if ($#cfg < 0) { open FILE, "<$cnfFile" or die "$0: can't open configuration file $cnfFile: $!"; while () { s/\s*$//; # strip trailing spaces push @cfg, $_; } 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; } } 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); } else { $key = $o; die "$0: no value for --setoption $key, goodbye.\n" if $i + 1 >= @options; $val = $options[$i + 1]; $i++; } 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) = @_; 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; &configReplace("$cnfFile", "^" . "$opt" . "\\s", "$opt $val"); } ############################################################################### # 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)/) { print "true false\n"; } else { print "Unknown item \"$item\"; should be one of LW35, dvipsPreferOutline,\n" . " dvipsDownloadBase35, or pdftexDownloadBase14\n"; } } 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)$/) { die "$0: Invalid mapType $type\n"; } # a map can only have one type, so we carefully disable everything # about map here: &disableMap("$map"); # now enable with the right type: &configReplace("$cnfFile", "^#!\\s*" . "$type" . "\\s*$map", "$type $map"); } ############################################################################### # disableMap (map) # disables map in config file (any type) # sub disableMap { my ($map) = @_; my %count = (); my $type; my @mapType = grep { my @fields = split; if ($fields[0] and $fields[0] =~ /^(MixedMap|Map)$/ and $fields[1] eq $map and ++$count{$fields[0]}) { $_ = $fields[0]; } else { $_ = ''; } } &getLines($cnfFile); foreach $type (@mapType) { &configReplace("$cnfFile", "^$type" . "\\s*$map", "#! $type $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) = @_; 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"; } } $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"); } ############################################################################### # 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"; ©File("$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"; } } } ############################################################################### # 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/\s*([^\s]*)\s*([^\s]*)/$2/; } @maps; @maps = sort(@maps); @maps = grep { ++$count{$_} < 2; } @maps; @maps = &locateMap(@maps); return @maps; } ############################################################################### # listMaps() # list all maps mentioned in the config file # sub listMaps { my $what=shift; my @mapfiles; my @paths; my @lines = grep { if ($what eq 'sync') { $_ =~ m/^(Mixed)?Map/ } else { $_ =~ m/^(\#! *)?(Mixed)?Map/ } } &getLines($cnfFile); if ($what eq 'list') { # --listmaps map { print "$_\n"; } @lines; } else { @mapfiles=grep { $_ =~ s/^(\#! *)?(Mixed)?Map\s+// } @lines; @paths=&locateMap(@mapfiles); if ($what eq 'avail') { # --listavailablemaps map { my $entry="$_"; # 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; } } } ############################################################################### # 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 = (); @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; @lines = grep {++$count{$_} < 2 } (sort @lines); return @lines; } ############################################################################### # 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+/ /; } push @out, $line; } return @out; } ############################################################################### # mkMaps() # the main task of this script: create the output files # sub mkMaps { my @lines; my $logfile; $cache=1; 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; } } sub newline() { if ($dry_run) { print "\n"; } else { print LOG "\n"; } } $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); &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\n"); &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; } else { print LOG $LW35; } 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"; } else { print LOG "$line\n"; } } &newline; printf " [%3d files]\n", scalar @tmp1 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"; } } &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; # Create psfonts_t1.map, psfonts_pk.map, ps2pk.map and pdftex.map: for my $file ("$dvipsoutputdir/download35.map", "$dvipsoutputdir/builtin35.map", "$dvipsoutputdir/psfonts_t1.map", "$dvipsoutputdir/psfonts_pk.map", "$pdftexoutputdir/pdftex_dl14.map", "$pdftexoutputdir/pdftex_ndl14.map", "$dvipsoutputdir/ps2pk.map") { 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; } 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); push @psfonts_t1_map, &getLines(@tmp1); push @psfonts_t1_map, &getLines(@tmp2); &writeLines(">$dvipsoutputdir/psfonts_t1.map", &normalizeLines(@psfonts_t1_map)); my @psfonts_pk_map = &transLW35($dftdvips); push @psfonts_pk_map, &getLines(@tmp2); &writeLines(">$dvipsoutputdir/psfonts_pk.map", &normalizeLines(@psfonts_pk_map)); 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; 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); 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); &setupSymlinks; &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"); } close LOG; print "\nTranscript written on \"$logfile\".\n" if !$quiet; } ############################################################################### # initVars() # initialize global variables # sub initVars { $quiet = 0; $nohash = 0; $nomkmap = 0; $cnfFile = ""; $cnfFileShort = "updmap.cfg"; $outputdir = ""; chomp($TEXMFMAIN =`kpsewhich --var-value=TEXMFMAIN`); @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 /', ); @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/', ); @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/', ); } ############################################################################### # main() # sub main { &initVars; &processOptions; &help if ($opt_help); if (@showoptions) { &showOptions(@showoptions); exit 0; } &setupCfgFile; if ($listmaps) { &listMaps ('list'); exit 0; } if ($listavailablemaps) { &listMaps ('avail'); exit 0; } if ($syncwithtrees) { &listMaps ('sync'); exit 0; } my $bakFile = $cnfFile; $bakFile =~ s/\.cfg$/.bak/; ©File($cnfFile, $bakFile); my $cmd = ''; 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); } elsif (@setoptions) { $cmd = 'setOption'; &setOptions (@setoptions); } elsif ($enableItem) { $cmd = 'enableMap'; if ($enableItem =~ /=/) { &enableMap(split('=', $enableItem)); } else { &enableMap($enableItem, shift @ARGV); } } elsif (@disableItem) { $cmd = 'disableMap'; foreach my $m (@disableItem) { &disableMap($m); } } if ($cmd && !$opt_force && &files_are_equal($bakFile, $cnfFile)) { print "$cnfFile unchanged. Map files not recreated.\n" if !$quiet; } else { if (! $nomkmap) { &setupDestDir; &mkMaps; } unlink ($bakFile); } unless ($nohash) { print "$0: Updating ls-R files.\n" if !$quiet; $updLSR->{exec}() } } __END__ ### Local Variables: ### perl-indent-level: 2 ### tab-width: 2 ### indent-tabs-mode: nil ### End: # vim:set tabstop=2 expandtab: #