File ghostscript-cjk-config of Package ghostscript-cjk

#! /usr/bin/perl -w                        # -*- mode: perl coding: utf-8 -*-
#
# Tue Mar 15 12:05:45 2005  Mike FABIAN  <mfabian@suse.de>
#
########################################################################
# create a man-page with:
#
#     pod2man --section 1 --center=" " ghostscript-cjk-config | gzip -9 -c > ghostscript-cjk-config.1.gz
#     cp ghostscript-cjk-config.1.gz /usr/share/man/man1/ghostscript-cjk-config.1.gz

=head1 NAME

ghostscript-cjk-config - setup the available fonts for use with ghostscript-cjk

=head1 SYNOPSIS

ghostscript-cjk-config [B<OPTION>]...

=head1 OPTIONS

=over 4

=item B<-h>, B<--help>

Display a short help message and exit.

=back

=head1 DESCRIPTION

setup the available fonts for use with ghostscript-cjk

=head1 AUTHOR

Mike FABIAN <I<mfabian@suse.de>>, 2005.

=cut

######################################################################

use strict;
use utf8;
use English;
use Getopt::Long;

######################################################################
# global variables:

my $script_start_time = time();

my $cvs_id = '$Id: ghostscript-cjk-config,v 1.8 2005/03/17 11:29:45 mfabian Exp $';
my $cvs_date = '$Date: 2005/03/17 11:29:45 $';
$cvs_date =~ /^\$[[:alpha:]]+: (.*) \$$/;
my $version = $1;

my $original_wd;
chomp ($original_wd = `pwd`);

# external binaries:
my $fc_list_bin = search_executable ("/usr/bin/fc-list", "/usr/X11R6/bin/fc-list");
my $ftdump_bin = search_executable ("/usr/bin/ftdump");

# directories:
my $xfontdir = "/usr/X11R6/lib/X11/fonts/truetype";
my $gsresourcedir = "/usr/share/ghostscript/Resource";

# only for Ghostscript 8.x
my $autogen_tag = "autogenerated by ghostscript-cjk-config";

my $cidfmap_header = ""
  . "%!\n"
  . "% The map is a set of records, which must use one of the two formats :\n"
  . "%\n"
  . "% 1. A substitution of a CIF font with another CID font :\n"
  . "%\n"
  . "%    /substituted /original ;\n"
  . "%\n"
  . "%    Where 'substituted' is a name being used in a document,\n"
  . "%    'original' is a name of an available resource.\n"
  . "%\n"
  . "% 2. A substutution of a CIF font with a True Type font :\n"
  . "%\n"
  . "%    /substituted << /FileType /TrueType /Path (path) /SubfontID 1 /CSI [(ordering) supplement] >> ;\n"
  . "%\n"
  . "%    Where 'substituted' is a name being used in a document,\n"
  . "%    'path' is a path to a True Type font file,\n"
  . "%    'ordering' is a value of Ordering required for CIDSystemInfo dictionary,\n"
  . "%    'supplement' is a value of Supplement required for CIDSystemInfo dictionary.\n"
  . "%\n"
  . "% Examples :\n"
  . "%    \n"
  . "%   /ShinGo-Bold   /HeiseiKakuGo-W5 ;\n"
  . "%   /Ryumin-Medium << /FileType /TrueType /Path (/usr/X11R6/lib/X11/fonts/truetype/sazanami-mincho.ttf) /SubfontID 0 /CSI [(Japan1) 2] >> ;\n"
  . "%\n"
  . "% When there are two entries for the same substitution, the first one\n"
  . "% will win.\n"
  . "% Therefore, if you want to add manually tuned substitutions,\n"
  . "% add them above all autogenerated entries.\n"
  . "% Each autogenerated entry is marked by a comment:\n"
  . "%     '% $autogen_tag'\n"
  . "%\n";

my %cidfmap_auto = ();

# only for Ghostscript 7.x
my %install_scripts = (
		       "alias-aj1.sh"    , "Adobe-Japan1",
		       "alias-aj2.sh"    , "Adobe-Japan2",
		       "alias-ak1.sh"    , "Adobe-Korea1",
		       "alias-ac1.sh"    , "Adobe-CNS1",
		       "alias-ag1.sh"    , "Adobe-GB1"
		       );

# wrapper files to fake bold and italic:
# (only for Ghostscript 7.x)

my $fake_tag = "faked by ghostscript-cjk-config";

my $fake_bold_wrapper_template = ""
  . "%!PS-Adobe-3.0 Resource-CIDFont\n"
  . "%%BeginResource: CIDFont (__Font-Faked__)\n"
  . "%% $fake_tag\n"
  . "/__Font-Faked__\n"
  . "/__Font-Original__ /CIDFont findresource\n"
  . "16 dict begin\n"
  . "  /basecidfont exch def\n"
  . "  /basefont-H /.basefont-H /Identity-H [ basecidfont ] composefont def\n"
  . "  /basefont-V /.basefont-V /Identity-V [ basecidfont ] composefont def\n"
  . "  /CIDFontName dup basecidfont exch get def\n"
  . "  /CIDFontType 1 def\n"
  . "  /CIDSystemInfo dup basecidfont exch get def\n"
  . "  /FontInfo dup basecidfont exch get def\n"
  . "  /FontMatrix [ 1 0 0 1 0 0 ] def\n"
  . "  /FontBBox [\n"
  . "    basecidfont /FontBBox get cvx exec\n"
  . "    4 2 roll basecidfont /FontMatrix get transform\n"
  . "    4 2 roll basecidfont /FontMatrix get transform\n"
  . "  ] def\n"
  . "  /cid 2 string def\n"
  . "  /BuildGlyph {\n"
  . "    gsave\n"
  . "    exch begin\n"
  . "      dup 256 idiv cid exch 0 exch put\n"
  . "      256 mod cid exch 1 exch put\n"
  . "      rootfont /WMode known { rootfont /WMode get 1 eq } { false } ifelse\n"
  . "      { basefont-V } { basefont-H } ifelse setfont\n"
  . "      .03 setlinewidth 1 setlinejoin\n"
  . "      newpath\n"
  . "      0 0 moveto cid false charpath stroke\n"
  . "      0 0 moveto cid show\n"
  . "      currentpoint setcharwidth\n"
  . "    end\n"
  . "    grestore\n"
  . "  } bind def\n"
  . "  currentdict\n"
  . "end\n"
  . "/CIDFont defineresource pop\n"
  . "%%EndResource\n"
  . "%%EOF\n";

my $fake_italic_wrapper_template = ""
  . "%!PS-Adobe-3.0 Resource-CIDFont\n"
  . "%%BeginResource: CIDFont (__Font-Faked__)\n"
  . "%% $fake_tag\n"
  . "/__Font-Faked__\n"
  . "/__Font-Original__ /CIDFont findresource\n"
  . "dup length dict begin { 1 index /FontMatrix eq { [1 0 .3 1 0 0] matrix concatmatrix def } { def } ifelse } forall currentdict end\n"
  . "/CIDFont defineresource pop\n"
  . "%%EndResource\n"
  . "%%EOF\n";

my $fake_bolditalic_wrapper_template = ""
  . "%!PS-Adobe-3.0 Resource-CIDFont\n"
  . "%%BeginResource: CIDFont (__Font-Faked__)\n"
  . "%% $fake_tag\n"
  . "/__Font-Faked__\n"
  . "/__Font-Original__ /CIDFont findresource\n"
  . "16 dict begin\n"
  . "  /basecidfont exch def\n"
  . "  /basefont-H /.basefont-H /Identity-H [ basecidfont ] composefont def\n"
  . "  /basefont-V /.basefont-V /Identity-V [ basecidfont ] composefont def\n"
  . "  /CIDFontName dup basecidfont exch get def\n"
  . "  /CIDFontType 1 def\n"
  . "  /CIDSystemInfo dup basecidfont exch get def\n"
  . "  /FontInfo dup basecidfont exch get def\n"
  . "  /FontMatrix [ 1 0 0 1 0 0 ] def\n"
  . "  /FontBBox [\n"
  . "    basecidfont /FontBBox get cvx exec\n"
  . "    4 2 roll basecidfont /FontMatrix get transform\n"
  . "    4 2 roll basecidfont /FontMatrix get transform\n"
  . "  ] def\n"
  . "  /cid 2 string def\n"
  . "  /BuildGlyph {\n"
  . "    gsave\n"
  . "    exch begin\n"
  . "      dup 256 idiv cid exch 0 exch put\n"
  . "      256 mod cid exch 1 exch put\n"
  . "      rootfont /WMode known { rootfont /WMode get 1 eq } { false } ifelse\n"
  . "      { basefont-V } { basefont-H } ifelse setfont\n"
  . "      .03 setlinewidth 1 setlinejoin\n"
  . "      newpath\n"
  . "      0 0 moveto cid false charpath stroke\n"
  . "      0 0 moveto cid show\n"
  . "      currentpoint setcharwidth\n"
  . "    end\n"
  . "    grestore\n"
  . "  } bind def\n"
  . "  currentdict\n"
  . "end\n"
  . "dup length dict begin { 1 index /FontMatrix eq { [1 0 .3 1 0 0] matrix concatmatrix def } { def } ifelse } forall currentdict end\n"
  . "/CIDFont defineresource pop\n"
  . "%%EndResource\n"
  . "%%EOF\n";

my $cmap_wrapper_template = ""
  . "%!PS-Adobe-3.0 Resource-Font\n"
  . "%%Creator: $fake_tag\n"
  . "%%DocumentNeededResources: __CMap__ (CMap)\n"
  . "%%IncludeResource: __CMap__ (CMap)\n"
  . "%%BeginResource: Font (__Font__-__CMap__)\n"
  . "(__Font__-__CMap__)\n"
  . "(__CMap__) /CMap findresource\n"
  . "[(__Font__) /CIDFont findresource]\n"
  . "composefont pop\n"
  . "%%EndResource\n"
  . "%%EOF\n";

my @cmaps = ("78-EUC-H",
	     "78-EUC-V",
	     "78-H",
	     "78-RKSJ-H",
	     "78-RKSJ-V",
	     "78-V",
	     "78ms-RKSJ-H",
	     "78ms-RKSJ-V",
	     "83pv-RKSJ-H",
	     "90ms-RKSJ-H",
	     "90ms-RKSJ-UCS2",
	     "90ms-RKSJ-V",
	     "90msp-RKSJ-H",
	     "90msp-RKSJ-V",
	     "90pv-RKSJ-H",
	     "90pv-RKSJ-UCS2",
	     "90pv-RKSJ-UCS2C",
	     "90pv-RKSJ-V",
	     "Add-H",
	     "Add-RKSJ-H",
	     "Add-RKSJ-V",
	     "Add-V",
	     "Adobe-CNS1-0",
	     "Adobe-CNS1-1",
	     "Adobe-CNS1-2",
	     "Adobe-CNS1-3",
	     "Adobe-CNS1-4",
	     "Adobe-CNS1-B5pc",
	     "Adobe-CNS1-ETen-B5",
	     "Adobe-CNS1-H-CID",
	     "Adobe-CNS1-H-Host",
	     "Adobe-CNS1-H-Mac",
	     "Adobe-CNS1-UCS2",
	     "Adobe-GB1-0",
	     "Adobe-GB1-1",
	     "Adobe-GB1-2",
	     "Adobe-GB1-3",
	     "Adobe-GB1-4",
	     "Adobe-GB1-GBK-EUC",
	     "Adobe-GB1-GBpc-EUC",
	     "Adobe-GB1-H-CID",
	     "Adobe-GB1-H-Host",
	     "Adobe-GB1-H-Mac",
	     "Adobe-GB1-UCS2",
	     "Adobe-Japan1-0",
	     "Adobe-Japan1-1",
	     "Adobe-Japan1-2",
	     "Adobe-Japan1-3",
	     "Adobe-Japan1-4",
	     "Adobe-Japan1-90ms-RKSJ",
	     "Adobe-Japan1-90pv-RKSJ",
	     "Adobe-Japan1-H-CID",
	     "Adobe-Japan1-H-Host",
	     "Adobe-Japan1-H-Mac",
	     "Adobe-Japan1-PS-H",
	     "Adobe-Japan1-PS-V",
	     "Adobe-Japan1-UCS2",
	     "Adobe-Japan2-0",
	     "Adobe-Korea1-0",
	     "Adobe-Korea1-1",
	     "Adobe-Korea1-2",
	     "Adobe-Korea1-H-CID",
	     "Adobe-Korea1-H-Host",
	     "Adobe-Korea1-H-Mac",
	     "Adobe-Korea1-KSCms-UHC",
	     "Adobe-Korea1-KSCpc-EUC",
	     "Adobe-Korea1-UCS2",
	     "B5-H",
	     "B5-V",
	     "B5pc-H",
	     "B5pc-UCS2",
	     "B5pc-UCS2C",
	     "B5pc-V",
	     "CNS-EUC-H",
	     "CNS-EUC-V",
	     "CNS01-RKSJ-H",
	     "CNS02-RKSJ-H",
	     "CNS03-RKSJ-H",
	     "CNS04-RKSJ-H",
	     "CNS05-RKSJ-H",
	     "CNS06-RKSJ-H",
	     "CNS07-RKSJ-H",
	     "CNS1-H",
	     "CNS1-V",
	     "CNS15-RKSJ-H",
	     "CNS2-H",
	     "CNS2-V",
	     "ETHK-B5-H",
	     "ETHK-B5-V",
	     "ETen-B5-H",
	     "ETen-B5-UCS2",
	     "ETen-B5-V",
	     "ETenms-B5-H",
	     "ETenms-B5-V",
	     "EUC-H",
	     "EUC-V",
	     "Ext-H",
	     "Ext-RKSJ-H",
	     "Ext-RKSJ-V",
	     "Ext-V",
	     "GB-EUC-H",
	     "GB-EUC-V",
	     "GB-H",
	     "GB-RKSJ-H",
	     "GB-V",
	     "GBK-EUC-H",
	     "GBK-EUC-UCS2",
	     "GBK-EUC-V",
	     "GBK2K-H",
	     "GBK2K-V",
	     "GBKp-EUC-H",
	     "GBKp-EUC-V",
	     "GBT-EUC-H",
	     "GBT-EUC-V",
	     "GBT-H",
	     "GBT-RKSJ-H",
	     "GBT-V",
	     "GBTpc-EUC-H",
	     "GBTpc-EUC-V",
	     "GBpc-EUC-H",
	     "GBpc-EUC-UCS2",
	     "GBpc-EUC-UCS2C",
	     "GBpc-EUC-V",
	     "H",
	     "HK-RKSJ-H",
	     "HKdla-B5-H",
	     "HKdla-B5-V",
	     "HKdlb-B5-H",
	     "HKdlb-B5-V",
	     "HKgccs-B5-H",
	     "HKgccs-B5-V",
	     "HKm314-B5-H",
	     "HKm314-B5-V",
	     "HKm471-B5-H",
	     "HKm471-B5-V",
	     "HKscs-B5-H",
	     "HKscs-B5-V",
	     "Hankaku",
	     "Hiragana",
	     "Hojo-EUC-H",
	     "Hojo-EUC-V",
	     "Hojo-H",
	     "Hojo-RKSJ-H",
	     "Hojo-V",
	     "Identity-H",
	     "Identity-V",
	     "KSC-EUC-H",
	     "KSC-EUC-V",
	     "KSC-H",
	     "KSC-Johab-H",
	     "KSC-Johab-V",
	     "KSC-RKSJ-H",
	     "KSC-V",
	     "KSC2-RKSJ-H",
	     "KSCms-UHC-H",
	     "KSCms-UHC-HW-H",
	     "KSCms-UHC-HW-V",
	     "KSCms-UHC-UCS2",
	     "KSCms-UHC-V",
	     "KSCpc-EUC-H",
	     "KSCpc-EUC-UCS2",
	     "KSCpc-EUC-UCS2C",
	     "KSCpc-EUC-V",
	     "Katakana",
	     "NWP-H",
	     "NWP-V",
	     "RKSJ-H",
	     "RKSJ-V",
	     "Roman",
	     "TCVN-RKSJ-H",
	     "UCS2-90ms-RKSJ",
	     "UCS2-90pv-RKSJ",
	     "UCS2-B5pc",
	     "UCS2-ETen-B5",
	     "UCS2-GBK-EUC",
	     "UCS2-GBpc-EUC",
	     "UCS2-KSCms-UHC",
	     "UCS2-KSCpc-EUC",
	     "UniCNS-UCS2-H",
	     "UniCNS-UCS2-V",
	     "UniCNS-UTF16-H",
	     "UniCNS-UTF16-V",
	     "UniCNS-UTF32-H",
	     "UniCNS-UTF32-V",
	     "UniCNS-UTF8-H",
	     "UniCNS-UTF8-V",
	     "UniGB-UCS2-H",
	     "UniGB-UCS2-V",
	     "UniGB-UTF8-H",
	     "UniGB-UTF8-V",
	     "UniHojo-UCS2-H",
	     "UniHojo-UCS2-V",
	     "UniHojo-UTF16-H",
	     "UniHojo-UTF16-V",
	     "UniHojo-UTF32-H",
	     "UniHojo-UTF32-V",
	     "UniHojo-UTF8-H",
	     "UniHojo-UTF8-V",
	     "UniJIS-UCS2-H",
	     "UniJIS-UCS2-HW-H",
	     "UniJIS-UCS2-HW-V",
	     "UniJIS-UCS2-V",
	     "UniJIS-UTF8-H",
	     "UniJIS-UTF8-V",
	     "UniJISPro-UCS2-HW-V",
	     "UniJISPro-UCS2-V",
	     "UniJISPro-UTF8-V",
	     "UniKS-UCS2-H",
	     "UniKS-UCS2-V",
	     "UniKS-UTF16-H",
	     "UniKS-UTF16-V",
	     "UniKS-UTF32-H",
	     "UniKS-UTF32-V",
	     "UniKS-UTF8-H",
	     "UniKS-UTF8-V",
	     "V",
	     "WP-Symbol");

# command line options:

my $OPT_VERBOSITY;
my $OPT_VERSION;
my $OPT_HELP;
my $OPT_FORCE;
my $OPT_REMOVE_FAKES;

######################################################################
sub install_ps_name {
  # only for Ghostscript 7.x
  #
  # installs the first existing font from the list using the supplied
  # PostScript-name.
  #
  my ($install_script, $postscript_name, @font_list) = @_;
  if ( -x "$gsresourcedir/$install_script" ) {
    for my $font (@font_list) {
      my $font_full_path;
      if ($font !~ /\//) {
	$font_full_path = "$xfontdir/$font";
      }
      else {
	$font_full_path = $font;
      }
      if ( -f "$font_full_path" ) {
	if ( -f "$gsresourcedir/CIDFont/$postscript_name" ) {
	  open (FONT, "$gsresourcedir/CIDFont/$postscript_name")
	    || die "can't open file $gsresourcedir/CIDFont/$postscript_name: $!";
	  while (<FONT>) {
	    if ($ARG =~ /$font_full_path/) {
	      my $registry_ordering = $install_scripts{$install_script};
	      if ( -f "$gsresourcedir/Font/$postscript_name-$registry_ordering-0") {
		# this font is already installed, save some time and don't
		# do it again
		close (FONT);
		return;
	      }
	    }
	  }
	  close (FONT);
	}
	chdir "$gsresourcedir";
	print "+${postscript_name}=${font_full_path}\n";
	my_system (" ./$install_script uninstall $postscript_name > /dev/null");
	my_system (" ./$install_script install $postscript_name=$font_full_path > /dev/null");
	return;
      }
    }
  }
}

######################################################################
sub install {
  # only for Ghostscript 7.x
  
  my ($install_script, @font_list) = @_;
  for my $font (@font_list) {
    my $font_full_path;
    if ($font !~ /\//) {
      $font_full_path = "$xfontdir/$font";
    }
    else {
      $font_full_path = $font;
    }
    if ( -f  "$font_full_path" && $ftdump_bin ) {
      my $postscript_name = get_ps_name_from_file_name ("$font_full_path");
      if ($postscript_name ne "") {
	install_ps_name ($install_script, $postscript_name, $font_full_path);
      }
    }
  }
}

######################################################################
sub get_ps_name_from_file_name {
  my ($font) = @_;

  # quote " in font names:
  $font =~ s/\"/\\\"/g;
  open (FONT, "ftdump \"$font\" 2>/dev/null |");
  # Apparently there are some fonts which have non-ASCII PostScript names.
  # If we are running in a UTF-8 locale, Perl will complain
  #    "Malformed UTF-8 character"
  # when reading the ftdump output of such a font.
  # Avoid that error by using the layer ":bytes" for this file handle.
  binmode FONT, ":bytes";
  my $postscript = "";
  while (<FONT>) {
    # the following regexp should work with ftdump from
    # either Freetype-1 or Freetype-2
    if ($ARG =~ /postscript.*:\s+([[:alnum:]\-.]+?)\s*$/i) {
      $postscript = $1;
      if ($postscript eq "UNAVAILABLE") {
	$postscript = "";
      }
      last;
    }
  }
  close (FONT);
  return ($postscript);
}

######################################################################
sub add_cidfmap_auto_entry {
  my ($postscript, $font_file, $face_number, $ordering, $supplement) = @_;
  my $entry = "/$postscript << /FileType /TrueType /Path ($font_file) /SubfontID $face_number /CSI [($ordering) $supplement] >> ; % $autogen_tag \n";
  if ($OPT_VERBOSITY >= 1) {
    print "entry: $entry";
  }
  $cidfmap_auto{$entry} = 1;
}

######################################################################
sub add_cidfmap_auto_entry_for_postscript_name {
  my ($postscript, $ordering, $supplement, @family_names) = @_;
  for my $family_name (@family_names) {
    if ($OPT_VERBOSITY >= 1) {
      print "searching for family name \"$family_name\" ...\n";
    }
    open (FONT_LIST, "fc-list \"$family_name\" file index|");
    binmode FONT_LIST, ":bytes";
    while (<FONT_LIST>) {
      my $font_file = "";
      my $face_number = -1;
      $ARG =~ /(.*):[[:space:]]*:index=([0-9]+)[[:space:]]*$/;
      $font_file = $1;
      $face_number = $2;
      if ($OPT_VERBOSITY >=1) {
	print "fc-list output: $ARG";
	print " -> font_file=$font_file, face_number=$face_number\n";
      }
      # resolve symlink:
      while (-l $font_file) {
	$font_file = readlink ($font_file);
      }
      if (-r $font_file &&
	  $font_file =~ /\.ttf$|\.ttc$|\.otf/i && $face_number >= 0) {
	add_cidfmap_auto_entry($postscript,
			       $font_file,
			       $face_number,
			       $ordering, $supplement);
	if ($OPT_VERBOSITY >= 1) {
	  print "\"$postscript\" entry for \"$family_name\" created sucessfully\n";
	}
	return;
      }
    }
    close (FONT_LIST);

  }
}

######################################################################
sub add_all_cidfmap_auto_entries_from_file_name {
  # generate config entries for using the "real" PostScript name
  # for all faces found in the file $font_file

  my ($font_file, $ordering, $supplement) = @_;
  # resolve symlink:
  while (-l $font_file) {
    $font_file = readlink ($font_file);
  }
  if (-r $font_file ) {
    # quote " in font names:
    my $font_file_quoted;
    ($font_file_quoted = $font_file) =~ s/\"/\\\"/g;
    open (FONT, "ftdump \"$font_file_quoted\" 2>/dev/null |");
    # Apparently there are some fonts which have non-ASCII PostScript names.
    # If we are running in a UTF-8 locale, Perl will complain
    #    "Malformed UTF-8 character"
    # when reading the ftdump output of such a font.
    # Avoid that error by using the layer ":bytes" for this file handle.
    binmode FONT, ":bytes";
    
    my $postscript = "";
    my $family = "";
    my $style = "";
    my $face_number = -1;

    while (<FONT>) {
      if ($ARG =~ /face.*number.*:\s*([0-9]+)\s*/i) {
	$face_number = $1;
	$postscript = "";
	$family = "";
	$style = "";
      }
      # the following regexp should work with ftdump from
      # either Freetype-1 or Freetype-2
      if ($ARG =~ /postscript.*:\s+([[:alnum:]\-]+?)\s*$/i) {
	$postscript = $1;
	if ($postscript eq "UNAVAILABLE") {
	  $postscript = "";
	}
      }
      if ($ARG =~ /family.*:\s+([[:alnum:]].*[[:alnum:]])\s*$/i) {
	$family = $1;
      }
      if ($ARG =~ /style.*:\s+([[:alnum:]].*[[:alnum:]])\s*$/i) {
	$style = $1;
      }
      if ($face_number >= 0 && $postscript ne "" && $family ne "" && $style ne "") {
	add_cidfmap_auto_entry($postscript,
			       $font_file,
			       $face_number,
			       $ordering, $supplement);
	$face_number = -1;
      }
    }
    close (FONT);
  }
}

######################################################################
sub update_cidfmap {

  for my $cidfmap_dir (glob ("/etc/ghostscript/[0-9]*")) {
    if (-e $cidfmap_dir) {
      my $file = "$cidfmap_dir/cidfmap";
      my $cidfmap_user = "";
      if (-r $file) {
	open (CIDFMAP, "<$file") || die "can't open file $file: $!";
	if ($OPT_VERBOSITY >= 1) {
	  printf "reading user data from $file ...\n";
	}
	while (<CIDFMAP>) {
	  # skip autogenerated data
	  if ($ARG =~ /$autogen_tag/) {
	    next;
	  }
	  # skip empty lines
	  if ($ARG =~ /^[[:space:]]*$/) {
	    next;
	  }
	  if ($ARG =~ /([^%]*)%?.*/) { # strip comments
	    $ARG = $1;
	  }
	  $cidfmap_user .= $ARG;
	}
	close (CIDFMAP);
      }
      open (CIDFMAP, ">$file") || die "can't open file $file: $!";
      print CIDFMAP $cidfmap_header;
      print CIDFMAP "\n\n% manually edited entries:\n";
      print CIDFMAP $cidfmap_user;
      print CIDFMAP "\n\n% autogenerated entries:\n";
      for my $entry (sort (keys %cidfmap_auto)) {
	print CIDFMAP $entry;
      }
      close (CIDFMAP);
    }
  }
}

######################################################################
sub generate_fake_bold_and_italic_fonts {

  # this doesn't work anymore with Ghotscript 8.x
  return;
  
  chdir "$gsresourcedir/CIDFont" ||die "Can't cd to $gsresourcedir/CIDFont: $!\n";
  for my $font (glob ("*")) {
    my $font_bold = $font;
    my $font_italic = $font;
    my $font_bolditalic = $font;
    
    if ($font_bold !~ /Bold/i && $font_bold !~ /Italic/i) {
      for my $style (("Light", "Medium", "Regular")) {
	if ($font_bold =~ /${style}/i) {
	  $font_bold =~ s/${style}/Bold/i;
	  last;
	}
      }
      if ($font_bold !~ /Bold/i) {
	$font_bold = $font_bold . "-Bold";
      }
    }
    
    if ($font_italic !~ /Bold/i && $font_italic !~ /Italic/i) {
      for my $style (("Light", "Medium", "Regular")) {
	if ($font_italic =~ /${style}/i) {
	  $font_italic =~ s/${style}/Italic/i;
	  last;
	}
      }
      if ($font_italic !~ /Italic/i) {
	$font_italic = $font_italic . "-Italic";
      }
    }

    if ($font_bolditalic !~ /Bold/i && $font_bolditalic !~ /Italic/i) {
      for my $style (("Light", "Medium", "Regular")) {
	if ($font_bolditalic =~ /${style}/i) {
	  $font_bolditalic =~ s/${style}/BoldItalic/i;
	  last;
	}
      }
      if ($font_bolditalic !~ /BoldItalic/i) {
	$font_bolditalic = $font_bolditalic . "-BoldItalic";
      }
    }

    if ("$font_bold" ne "$font") {
      generate_fake ("$font", "$font_bold", "$fake_bold_wrapper_template");
    }
    if ("$font_italic" ne "$font") {
      generate_fake ("$font", "$font_italic", "$fake_italic_wrapper_template");
    }
    if ("$font_bolditalic" ne "$font") {
      generate_fake ("$font", "$font_bolditalic", "$fake_bolditalic_wrapper_template");
    }

  }
}

######################################################################
sub generate_fake {
  my ($font_original, $font_faked, $wrapper) = @_;

  # this doesn't work anymore with Ghostscript 8.x
  return;
  
  $wrapper =~ s/__Font-Original__/$font_original/g;
  $wrapper =~ s/__Font-Faked__/$font_faked/g;
  if ( ! -f "$gsresourcedir/CIDFont/$font_faked" ) {
    open (WRAPPER, "> $gsresourcedir/CIDFont/$font_faked")
      || die "cannot open $gsresourcedir/CIDFont/$font_faked for writing: $!";
    printf WRAPPER "%s", $wrapper;
    close (WRAPPER);
  }
  
  # find out which wrappers for which CMaps exist for the original font
  # and generate wrappers for the same CMaps for the faked font as well:
  chdir "$gsresourcedir/Font" ||die "Can't cd to $gsresourcedir/Font: $!\n";
  for my $font (glob ("$font_original-*")) {
    my $cmap;
    ($cmap = $font) =~ s/$font_original-(.*)/$1/;
    # $cmap might contain more than just the CMap here
    # as there may be other fonts whose name starts just like $font_original
    # but is longer.
    # Check if we have found a really existing CMap:
    if (grep (/$cmap/, @cmaps)) {
      # now generate a wrapper file if it doesn't exist yet:
      if ( ! -f "$gsresourcedir/Font/$font_faked-$cmap" ) {
	if ($OPT_VERBOSITY >= 1) {
	  printf "creating $gsresourcedir/Font/$font_faked-$cmap\n";
	}
	open (WRAPPER, "> $gsresourcedir/Font/$font_faked-$cmap")
	  || die "cannot open $gsresourcedir/Font/$font_faked-$cmap for writing: $!";
	my $cmap_wrapper = $cmap_wrapper_template;
	$cmap_wrapper =~ s/__CMap__/$cmap/g;
	$cmap_wrapper =~ s/__Font__/$font_faked/g;
	printf WRAPPER "%s", $cmap_wrapper;
	close (WRAPPER);
      }
    }
  }

}

######################################################################
sub clean_up {
  # only for Ghostscript 7.x
  for my $font (glob ("$gsresourcedir/CIDFont/*")) {
    my $postscript_name;
    ($postscript_name = $font) =~ s/.*\/([^\/]+)/$1/;
    if ( -f "$font") {
      open (FONT, "$font") || die "can't open file $font: $!";
      while (<FONT>) {
	if ($ARG =~ /\((.+)\)[[:space:]]+\.openttcidfont/) {
	  my $ttfont = $1;
	  if ( ! -f "$ttfont" ) {
	    print "deleting $postscript_name\n";
	    my_system ("rm -f \"$gsresourcedir\"/{CIDFont,Font}/\"$postscript_name\"");
	    my_system ("rm -f \"$gsresourcedir\"/{CIDFont,Font}/\"$postscript_name-Bold\"");
	    my_system ("rm -f \"$gsresourcedir\"/{CIDFont,Font}/\"$postscript_name-BoldItalic\"");
	    my_system ("rm -f \"$gsresourcedir\"/{CIDFont,Font}/\"$postscript_name-Italic\"");
	  }
	}
      }
    close (FONT);
  }
  }
}

######################################################################
sub list_font_files {
  my ($language) = @_;
  my %font_files = ();
  open (FONT_LIST, "fc-list :lang=$language:outline=true file |");
  binmode FONT_LIST, ":bytes";
  while (<FONT_LIST>) {
    $ARG =~ s/(.*):[[:space:]]*$/$1/;
    if ($ARG =~ /\.ttf$|\.ttc$|\.otf/i) {
      if (-l $ARG ) {
	# resolve symlink:
	$font_files{readlink ($ARG)} = 1;
      }
      else {
	$font_files{$ARG} = 1;
      }
    }
  }
  close (FONT_LIST);
  return (sort (keys %font_files));
}

######################################################################
sub remove_fakes {
  # remove wrappers for fake bold and italic
  my $cwd;
  for my $dir (("$gsresourcedir/CIDFont", "$gsresourcedir/Font")) {
    chdir "$dir" || die "Can't cd to $dir: $!\n";
    for my $file (glob ("*")) {
      if (! my_system ("grep -q \"$fake_tag\" $file")) {
	if ($OPT_VERBOSITY >= 1) {
	  print "$file is faked, remove it\n";
	}
	unlink($file);
      }
    }
  }
  chdir $original_wd || die "Can't cd to $original_wd: $!\n";
}

######################################################################
sub remove_old_gs_cjk_wrappers {
  # the wrapper files created by the gs-cjk project do not work
  # anymore with Ghostscript 8.x, so they should be removed.
  my $cwd;
  for my $dir (("$gsresourcedir/CIDFont", "$gsresourcedir/Font")) {
    chdir "$dir" || die "Can't cd to $dir: $!\n";
    for my $file (glob ("*")) {
      if (! my_system ("grep -q \"Creator: aliascid.ps\" $file")) {
	if ($OPT_VERBOSITY >= 1) {
	  print "$file created by gs-cjk won't work anymore with Ghostscript 8.x. Remove it.\n";
	}
	unlink($file);
      }
    }
  }
  chdir $original_wd || die "Can't cd to $original_wd: $!\n";
}

######################################################################
sub search_executable {
  for my $file (@_) {
    if (-x $file) {
      return $file;
    }
  }
  return "";
}

######################################################################
sub my_system {
  my ($command) = @_;
  if ($OPT_VERBOSITY >= 1)  {
    print "executing: $command\n";
  }
  return system ($command);
}

######################################################################
sub usage {
  print "Usage: ghostscript-cjk-config [option] ...\n";
  print "-v, --verbosity number   print some progress messages to standard output.\n";
  print "    --version            display version and exit.\n";
  print "-h, --help               display this help and exit.\n";
  print "    --force              force update of all generated files.\n";
  print "-r, --remove-fakes       remove generated wrappers to fake bold and italic.\n";
  exit 1;
}

######################################################################
# main:

# Process command line options
my %opt;
unless (GetOptions(\%opt,
		   'verbosity=i',      \$OPT_VERBOSITY,
		   'version',          \$OPT_VERSION,
		   'help|h',           \$OPT_HELP,
		   'force',            \$OPT_FORCE,
		   'remove-fakes|r',   \$OPT_REMOVE_FAKES,
		  )) {
  &usage ();
  exit 1;
}

if (!defined $OPT_VERBOSITY)    { $OPT_VERBOSITY = 0; }
if (!defined $OPT_VERSION)      { $OPT_VERSION = 0; }
if (!defined $OPT_HELP)         { $OPT_HELP = 0; }
if (!defined $OPT_FORCE)        { $OPT_FORCE = 0; }
if (!defined $OPT_REMOVE_FAKES) { $OPT_REMOVE_FAKES = 1; }

if ($OPT_VERSION) {
  print "ghostscript-cjk-config $version\n";
  exit 0;
}

if ($OPT_HELP) {
  &usage ();
  exit 0;
}

# check if we are started as root
# only one of UID and USER must be set correctly

if ($UID != 0 && $ENV{USER} !~ /root/) {
    print "*** Error: You must be root to start $0\n";
    usage();
    exit 1;
}


# remove files which cannot work anymore with Ghostscript 8.x
# so that no useless junk remains after an update:
remove_old_gs_cjk_wrappers();
remove_fakes();

# generate config entries for all fonts using their "real" PostScript name:

if ($ftdump_bin && $fc_list_bin) {
  for my $file (list_font_files ("ja")) {
    add_all_cidfmap_auto_entries_from_file_name ("$file", "Japan1", "2");
  }
  for my $file (list_font_files ("ko")) {
    add_all_cidfmap_auto_entries_from_file_name ("$file", "Korea1", "2");
  }
  for my $file (list_font_files ("zh-tw")) {
    add_all_cidfmap_auto_entries_from_file_name ("$file", "CNS1", "2");
  }
  for my $file (list_font_files ("zh-cn")) {
    add_all_cidfmap_auto_entries_from_file_name ("$file", "GB1", "2");
  }
}

# generate config entries for standard PostScript names:

add_cidfmap_auto_entry_for_postscript_name ("Ryumin-Light", "Japan1", "2",
					    # "HG\\-MinchoL\\-Sun", # does not work yet
					    "MS Mincho",
					    "MS PMincho",
					    "HGMinchoL",
					    "HGPMinchoL",
					    "TLMincho",
					    "IPAMincho",
					    "IPAPMincho",
					    "Sazanami Mincho",
					    "Kochi Mincho");

add_cidfmap_auto_entry_for_postscript_name ("Adobe-Japan1", "Japan1", "2",
					    # "HG\\-MinchoL\\-Sun", # does not work yet
					    "MS Mincho",
					    "MS PMincho",
					    "HGMinchoL",
					    "HGPMinchoL",
					    "TLMincho",
					    "IPAMincho",
					    "IPAPMincho",
					    "Sazanami Mincho",
					    "Kochi Mincho");

add_cidfmap_auto_entry_for_postscript_name ("GothicBBB-Medium", "Japan1", "2",
					    # "HG\\-GothicB\\-Sun", # does not work yet
					    "MS Gothic",
					    "MS PGothic",
					    "MS UI Gothic",
					    "HGGothicB",
					    "HGPGothicB",
					    "TLGothic",
					    "IPAGothic",
					    "IPAPGothic",
					    "IPAUIGothic",
					    "Sazanami Gothic",
					    "Kochi Gothic");

add_cidfmap_auto_entry_for_postscript_name ("Adobe-Korea1", "Korea1", "2",
					    "Baekmuk Gulim",
					    "Baekmuk Dotum");

add_cidfmap_auto_entry_for_postscript_name ("GB-Song-Medium", "GB1", "2",
					    "FZSongTi",
					    "AR PL SungtiL GB",
					    "HanyiSong");

add_cidfmap_auto_entry_for_postscript_name ("Adobe-GB1", "GB1", "2",
					    "FZSongTi",
					    "AR PL SungtiL GB",
					    "HanyiSong");

add_cidfmap_auto_entry_for_postscript_name ("GB-Kai-Medium", "GB1", "2",
					    "FZKaiTi",
					    "AR PL KaitiM GB");

add_cidfmap_auto_entry_for_postscript_name ("GB-FangSong-Medium", "GB1", "2",
					    "FZFangSong");

add_cidfmap_auto_entry_for_postscript_name ("GB-Hei-Medium", "GB1", "2",
					    "FZHeiTi");

add_cidfmap_auto_entry_for_postscript_name ("B5-Song-Medium", "CNS1", "2",
					    "FZMingTiB",
					    "FZMingTi",
					    "AR PL Mingti2L Big5");

add_cidfmap_auto_entry_for_postscript_name ("Adobe-CNS1", "CNS1", "2",
					    "FZMingTiB",
					    "FZMingTi",
					    "AR PL Mingti2L Big5");

add_cidfmap_auto_entry_for_postscript_name ("B5-Kai-Medium", "CNS1", "2",
					    "FZKaiTiB",
					    "AR PL KaitiM Big5");

update_cidfmap ();

chdir $original_wd ||die "Can't cd to $original_wd: $!\n";

exit 0;

openSUSE Build Service is sponsored by