diff options
Diffstat (limited to 'Master/texmf-dist/scripts/epspdf/epspdfrc.rb')
-rwxr-xr-x | Master/texmf-dist/scripts/epspdf/epspdfrc.rb | 415 |
1 files changed, 242 insertions, 173 deletions
diff --git a/Master/texmf-dist/scripts/epspdf/epspdfrc.rb b/Master/texmf-dist/scripts/epspdf/epspdfrc.rb index aa64309a822..acdbd9ac5e4 100755 --- a/Master/texmf-dist/scripts/epspdf/epspdfrc.rb +++ b/Master/texmf-dist/scripts/epspdf/epspdfrc.rb @@ -1,20 +1,16 @@ +EPVERSION = '0.4.0' +COPYRIGHT = '2006, 2008, 2009' + # epspdf conversion utility, configuration module ##### -# Copyright (C) 2006, 2008 Siep Kroonenberg +# Copyright (C) 2006, 2008, 2009 Siep Kroonenberg # n dot s dot kroonenberg at rug dot nl # # This program is free software, licensed under the GNU GPL, >=2.0. # This software comes with absolutely NO WARRANTY. Use at your own risk! ##### -# This version has been adapted for TeX Live. The adaptations only -# concern Windows. If TL is set then pdftops and -# ghostscript are set to the version included in TeXLive, settings are -# stored in HKCU\software\epspdftl (rather than epspdf) and the logfile -# is %USERPROFILE%\epspdftl.log, rather than epspdf.log. -# A future version should offer a dynamic way of settingt his option. - # Settings are stored in a settings hash, with some methods added # for less unwieldy notation. # @@ -43,112 +39,145 @@ else 'unix' end -TL = ENV.has_key?('TLROOT') if ARCH == 'w32' + # registry and API calls require 'dl/win32' require 'win32/registry' include Win32 # this lets us abbreviate Win32::Registry to Registry + # lay groundwork for short_name function ShortPName = Win32API.new( 'kernel32', 'GetShortPathName', ['P','P','N'], 'N' ) - TLROOT = ENV['TLROOT'] + # shellopen function + ShellEx = Win32API.new( + 'shell32','ShellExecute', ['L','P','P','P','P','L'], 'L' ) + #FindEx = Win32API.new( + # 'shell32','FindExecutable', ['P','P','P'], 'L' ) + # from winuser.h: + SW_SHOWNORMAL = 1 end -# for Windows, use short names within backquotes -# to avoid quotes within backquotes - +# need short_name function to get around limitations of w2k quoting def short_name( fn ) + #puts "Calculate short name for #{fn}\n" return fn if ARCH != 'w32' - fn.gsub!( /\\/, '/' ) + fn.gsub!( /\//, "\\" ) buffer = ' ' * 260 length = ShortPName.call( fn, buffer, buffer.size ) - return ( length > 0 ) ? buffer.slice(0..length-1) : fn + fn = buffer.slice(0..length-1) if length > 0 + fn.gsub!( /\\/, '/' ) + return fn +end + +def shell_open( fn ) + return nil if ARCH != 'w32' + result = ShellEx.call( 0, 0, fn, 0, 0, SW_SHOWNORMAL ) end +def shell_open_with( fn ) + return nil if ARCH != 'w32' + result = ShellEx.call( 0, 0, "RUNDLL32.EXE", "shell32.dll,OpenAs_RunDLL #{fn}", + 0, SW_SHOWNORMAL ) +end + +# interpret error value for shell_open +# values <=32 indicate error +# constants defined in winerror.h, shellapi.h + +def shell_error_string ( e ) + if e > 32 + returl nil + else + return case e + when 0: "Out of memory or resources" + #define ERROR_FILE_NOT_FOUND 2L + #define SE_ERR_FNF 2 + when 2: "File not found" + #define ERROR_PATH_NOT_FOUND 3L + #define SE_ERR_PNF 3 + when 3: "Path not found" + #define SE_ERR_ACCESSDENIED 5 + when 5: "Access denied" + #define SE_ERR_OOM 8 + when 8: "Not enough memory" + #define ERROR_BAD_FORMAT 11L + when 11: "Invalid exe" + #define SE_ERR_SHARE 26 + when 26: "Sharing violation" + #define SE_ERR_ASSOCINCOMPLETE 27 + when 27: "Invalid file association" + #define SE_ERR_DDETIMEOUT 28 + when 28: "DDE timeout" + #define SE_ERR_DDEFAIL 29 + when 29: "DDE fail" + #define SE_ERR_DDEBUSY 30 + when 30: "DDE busy" + #define SE_ERR_NOASSOC 31 + when 31: "No file association" + #define SE_ERR_DLLNOTFOUND 32 + when 32: "DLL not found" + else "Unspecified error" + end # case + end # else +end # def + # system-dependent location of logfile LOGFILE = case ARCH when 'w32' - TL ? "#{ENV['USERPROFILE']}\\epspdftl.log" : "#{ENV['USERPROFILE']}\\epspdf.log" else - "#{ENV['HOME']}//epspdf.log" + "#{ENV['HOME']}/epspdf.log" end LOGFILE_OLD = LOGFILE + '.old' # system-dependent locations of saved settings -RC_FILE = "#{ENV['HOME']}/.epspdfrc" -REG_K = TL ? 'epspdftl' : 'epspdf' -REG_KEY = TL ? 'SOFTWARE\\epspdftl' : 'SOFTWARE\\epspdf' +RC_FILE = "#{ENV['HOME']}/.epspdfrc" # not used under Windows +REG_K = 'epspdf' +REG_KEY = 'SOFTWARE\\epspdf' # hash of saved settings from rc file or registry $rc_settings = {} -# find open command for extension (w32 only) - -def open_with( ext ) - ext = '' unless ext - answer = nil - if ARCH == 'w32' - begin # open cl = HKCR\ext safely - Registry::HKEY_CLASSES_ROOT.open( - (ext =~ /^\./ ? ext : '.'+ext) ) do |cl| - begin # read ftype safely - ftype = cl.read_s( nil ) - begin # open cmd = HKCR\ftype\shell... safely - Registry::HKEY_CLASSES_ROOT.open( - ftype + '\\shell\\open\\command' ) do |cmd| - begin # read answer safely - answer = cmd.read_s( nil ) - if answer =~ /^"([^"]+)".*/ - answer = $1 - elsif answer =~ /^([^ ]+) .*/ - answer = $1 - end - answer = nil unless answer and test( ?s, answer ) - rescue # answer not read - end # read answer safely - end # HKCR\ftype\shell... do |cmd| - rescue # cmd not opened - end # open cmd = HKCR\ftype\shell... safely - rescue # ftype not read - end # read ftype safely - end # HKCR\ext do |cl| - rescue # cl not opened - end # open cl = HKCR\ext safely - end # w32 - answer -end - # test whether a string is a valid program call # 'which' also works with explicit paths. # 'which' returns an error for non-executable files. +# Linux/Unix OS X: for testing existence of gs, pdftops and ps/pdf viewers +# Mac OS X: for testing existence of gs and pdftops +# Windows: function not usable and not used def is_a_program( s ) case ARCH when 'w32' nil else - ( system "which #{s} >/dev/null" ) ? 1 : nil + ( system "which #{s} >/dev/null 2>&1" ) ? 1 : nil end end # is_a_program -# Parse version info from a prog from the xpdf suite. -# This is used as validity test. - -def xpdf_version( arg ) - retval = nil - arg = short_name( arg ) if ARCH == 'w32' - version_output = `#{arg} -v 2>&1` - if version_output and not version_output.empty? - vo = version_output.split(/\r\n?|\n/) - vo.grep(/version/i) { |a| - a =~ /^\D*(\d+\.\w*)\b/ - retval = $& # matched part; nil if no match - } +# for Windows, use the registry or the following function instead: + +def find_on_path( s ) + # for now, Windows-only; parameter s with or without path + if ARCH != 'w32' + return nil end - retval + ENV['PATH'].gsub( "\\", "/" ).split( /;/ ).each do |d| + d = File.expand_path( d ) # this seems a syntactic operation + s_full = d.sub( /\/$/, '' ) + '/' + s + if test( ?d, d ) and test( ?f, s_full ) + return s_full + end + ENV['PATHEXT'].split( /;/ ).each do |e| + # components of PATHEXT should include leading dot + s_full = d.sub( /\/$/, '' ) + '/' + s + e + if test( ?f, s_full ) + return s_full + end + end # do |e| + end # do |d| + return nil end class Setting @@ -167,30 +196,56 @@ PDF_VERSIONS = [ '1.2', '1.3', '1.4', 'default' ] $settings = { # converters + # ghostscript: under windows it must be told about its directories, + # so we don't want users to mess with it. + # If they really want to, they can manually edit PATH and set GS_LIB 'gs_prog' => Setting.new( nil, 'auto', nil ), - 'gs_version' => Setting.new( nil, 'auto', nil ), + #'gs_version' => Setting.new( nil, 'auto', nil ), 'pdftops_prog' => Setting.new( nil, ARCH=='w32' ? 'config' : 'auto', nil ), - # viewers + # epspdftk: viewers 'pdf_viewers' => Setting.new( nil, ARCH=='unix' ? 'auto' : nil, nil ), 'ps_viewers' => Setting.new( nil, ARCH=='unix' ? 'auto' : nil, nil ), 'pdf_viewer' => Setting.new( nil, ARCH=='unix' ? 'config' : 'auto', nil ), 'ps_viewer' => Setting.new( nil, ARCH=='unix' ? 'config' : 'auto', nil ), + # epspdftk: initial dir + 'defaultDir' => Setting.new( nil, 'config', nil ), # conversion options 'ignore_pdftops' => Setting.new( '0', 'config', 'Ignore pdftops even if available; 1=yes, empty or 0=no(default)' ), 'pdf_target' => Setting.new( 'prepress', 'config', 'Target: screen, ebook, print, prepress (default) or default' ), - 'pdf_version' => Setting.new( '1.4', 'config', - 'Pdf version: e.g 1.4 or 1.2 (fewer features, more compatibility)' + - ' or unspecified' ), + 'pdf_version' => Setting.new( 'default', 'config', + 'Pdf version: e.g 1.4 or 1.2 or default' ), 'pdf_custom' => Setting.new( '', 'config', 'additional options for [e]ps to pdf conversion' ), - 'ps_options' => Setting.new( '-level2', 'config', - 'options for pdftops; default -level2' ), + 'ps_options' => Setting.new( '-level3', 'config', + 'options for pdftops; default -level3' ), + 'ignore_hires_bb' => Setting.new( '0', 'config', + 'Ignore hi-res boundingbox for pdf generation;' + + ' 1=yes, empty or 0=no(default)' ), 'bb_spread' => Setting.new( '1', 'config', - 'margin to be added to computed boundingbox; default 1' ) + 'margin to be added to computed lores boundingbox; default 1' ) } +# Using pdftops or a hires boundingbox should be the norm, not the exception. +# We emphasize this by naming the corresponding options ignore_pdftops and +# ignore_hires_bb, and letting them default to false. + +def reverse_of( x ) + case x + when /t(rue)?|y(es)?|1/i + false + when /f(alse)?|n(o)?|0/i + true + when 1 + false + when 0 + true + else + true + end +end + class << $settings # create shortcut methods $settings.x and $settings.x= @@ -201,47 +256,15 @@ class << $settings eval "def #{k}=(v) ; self[\'#{k}\'].val=v ; end" } - # use_pdftops is a boolean counterpart and inverse - # of the stored string attribute ignore_pdftops + # use_pdftops and use_hires_bb are a boolean counterparts and inverses + # of the stored string attributes ignore_pdftops and ignore_hires_bb - def use_pdftops - case self['ignore_pdftops'].val - when /t(rue)?|y(es)?|1/i - false - when /f(alse)?|n(o)?|0/i - true - when 1 - false - when 0 - true - else - true - end + def use_hires_bb + reverse_of( self['ignore_hires_bb'].val ) end - # we want use_pdftops = nil = default = true but - # we also want use_pdftops = nil <=> use_pdftops = false - # we give the second one priority. - - def use_pdftops=( x ) - self['ignore_pdftops'].val = case x - when /t(rue)?|y(es)?|1/i - '0' - when /f(alse)?|n(o)?|0/i - '1' - when 1 - '0' - when 0 - '1' - when false - '1' - when nil # try to avoid this assignment - '1' - when true - '0' - else - '1' - end + def use_pdftops + reverse_of( self['ignore_pdftops'].val ) end def accept_pdf_viewer( s ) @@ -337,7 +360,7 @@ class << $settings end else File.open( RC_FILE, 'w' ) do |f| - f.write( "# This file will be overwritten by epspdf_tk[.rb]" \ + f.write( "# This file will be overwritten by epspdf[tk][.rb]" \ + $/ ) $settings.each do |key, st| if st.type == 'config' @@ -355,26 +378,40 @@ class << $settings def get_settings # phase 1: autodetect - # w32: gs_prog, gs_version, pdf_viewer, ps_viewer - # gs: search registry settings; the highest version wins. - # viewers: check file type registry entry for valid open commands - # w32/TL: gs_prog, gs_version, pdf_viewer, ps_viewer - # gs: from TL - # viewers: check file type registry entry for valid open commands - # unix: gs_prog, gs_version, pdftops_prog, pdf_viewers, ps_viewers - # osx: gs_prog, gs_version, pdftops_prog + # w32: gs_prog, pdf_viewer, ps_viewer + # gs: search path; search registry settings (user and system); + # search tex installation. The first one wins. + # viewers: check file type registry entry for valid open commands + # unix: gs_prog, pdftops_prog, pdf_viewers, ps_viewers + # osx: gs_prog, pdftops_prog # viewers: use Preview; don't check anything # unix/osx are done together, except that for osx # the viewers code is skipped. + # Windows: test for TeX, because it may come with a hidden + # ghostscript. TeX may also come with pdftops.exe, but pdftops + # would then be on the searchpath and not require special treatment. + + texbindir = ( ARCH == 'w32' ) ? find_on_path( 'tex' ) : nil + texbindir = short_name( File.dirname( texbindir ) ) if texbindir + case ARCH when 'w32' - if !TL then # else use built-in texlive versions - # check registry for latest valid version of Ghostscript - # tentative values; HKLM and HKCU may provide different values - try_gs_version = nil + # ghostscript: + # 1. check searchpath + # 2. check registry for latest valid version of Ghostscript + # 3. check tex installation + # TeX Live- and MikTeX versions need environment variables + # no need to remember: it will be the last thing we try + # searchpath + self.gs_prog = find_on_path( 'gswin32c' ) + + if not self.gs_prog + try_gs_version = 0 try_gs_prog = nil + this_gs_prog = nil + # tentative values; HKLM and HKCU may provide different values [Registry::HKEY_LOCAL_MACHINE, Registry::HKEY_CURRENT_USER].each { |hk| puts hk.to_s if $DEBUG @@ -384,55 +421,75 @@ class << $settings puts key.to_s if $DEBUG if key =~ /ghostscript/i gh = hk.open('SOFTWARE\\' + key) - gh.each_key { |skey, wtime| - if skey =~ /^\d+\.\d+$/ # version number - if skey.to_f > try_gs_version.to_f - this_gs = hk.open('SOFTWARE\\' + key + '\\' + skey) + gh.each_key { |this_gs_version, wtime| + if this_gs_version =~ /^\d+\.\d+/ # version number + if this_gs_version.to_f > try_gs_version.to_f + this_gs = hk.open('SOFTWARE\\' + key + + '\\' + this_gs_version) this_gs_prog = this_gs['GS_DLL'].sub( /([\\\/])([^\\\/]+)$/, '\1gswin32c.exe') if test(?e,this_gs_prog) - try_gs_version = skey + try_gs_version = this_gs_version try_gs_prog = this_gs_prog end # if ?e (exist) - end # skey.to_f > try_gs_version.to_f - end # if skey =~ /^\d+\.\d+$/ + end # this_gs_version.to_f > try_gs_version.to_f + end # if this_gs_version =~ /^\d+\.\d+$/ } # gh.each_key end # if key =~ /ghostscript/i } # sof.each_key } # hk.open |sof| } # [HKCU, HKLM].each - self.gs_version = try_gs_version - self.gs_prog = try_gs_prog - end - - # viewers - self.pdf_viewer = open_with( 'pdf' ) - self.ps_viewer = open_with( 'ps' ) + self.gs_prog = this_gs_prog if this_gs_prog + end # if not self.gs_prog + if texbindir and ! self.gs_prog + # TeX Live >= 2008: + # hidden gs in texbindir/../../tlpkg/tlgs + texroot = File.dirname( File.dirname( File.expand_path( texbindir ))) + gsroot = texroot + '/tlpkg/tlgs' + this_gs_prog = gsroot + '/bin/gswin32c.exe' + if test( ?f, this_gs_prog ) + self.gs_prog = this_gs_prog + ENV['GS_LIB'] = "#{gsroot}/lib;#{gsroot}/fonts;#{gsroot}/Resource" + else # test for MikTeX hidden ghostscript + # http://blog.miktex.org/post/2005/04/ + # Starting-mgsexe-at-the-DOS-Prompt.aspx + # That's because mgs.exe doesn't use the original registry keys + # and environment variables. For example, mgs.exe queries + # MIKTEX_GS_LIB instead of GS_LIB. You can start mgs.exe + # at the DOS-prompt if you set MIKTEX_GS_LIB as follows: + # MIKTEX_GS_LIB=C:\texmf\ghostscript\base;C:\texmf\fonts + this_gs_prog = texbindir + '/mgs.exe' + if test( ?f, this_gs_prog ) and + test( ?d, "#{texroot}/ghostscript/base" ) + self.gs_prog = this_gs_prog + ENV['MIKTEX_GS_LIB'] = + "#{texroot}/ghostscript/base;#{texroot}/fonts" + end # ?f, this_gs_prog + end # try MikTeX hidden Ghostscript + end # texbindir and ! self.gs_prog + fail( "No ghostscript" ) unless self.gs_prog + self.gs_prog = short_name( self.gs_prog ) + + # pdftops: just check the searchpath + self.pdftops_prog = find_on_path( 'pdftops' ) when /unix|osx/ # gs - answer = `gs --version` - if answer and not answer.empty? - self.gs_prog = 'gs' - self.gs_version = answer.chomp - else - self.gs_prog = nil - self.gs_version = nil - end + self.gs_prog = is_a_program( 'gs' ) ? 'gs' : nil # pdftops - self.pdftops_prog = xpdf_version( 'pdftops' ) ? 'pdftops' : nil + self.pdftops_prog = is_a_program( 'pdftops' ) ? 'pdftops' : nil # viewers if ARCH == 'unix' - vw = %w{ gpdf xpdf acroread evince ggv gv kghostview } + vw = %w{ evince gpdf xpdf acroread epdfview gv gsview okular } vw.delete_if { |x| not is_a_program( x ) } vw = nil if vw.empty? self.pdf_viewers = vw self.pdf_viewer = vw ? vw[0] : nil if vw vw2 = vw.dup # copy the elements rather than the array ref - [ 'gpdf', 'xpdf', 'acroread' ].each { |pg| + [ 'gpdf', 'xpdf', 'acroread', 'epdfview' ].each { |pg| vw2.delete( pg ) if vw2.index( pg ) } vw2 = nil if vw2.empty? @@ -440,7 +497,8 @@ class << $settings self.ps_viewer = vw2 ? vw2[ 0 ] : nil end # if vw end # if unix - end # case + + end # case ARCH # built-in defaults already set during initialization of $settings @@ -452,21 +510,10 @@ class << $settings case ARCH when 'w32' - $rc_settings[ 'pdftops_prog' ] = ( - TL ? (TLROOT.gsub( /\//, '\\' ) + '\\bin\\win32\\pdftops.exe') : - "z:\\aps\\staff\\ber\\miktex\\xpdf\\pdftops.exe" ) unless - ( $rc_settings[ 'pdftops_prog' ] and - ! $rc_settings[ 'pdftops_prog' ].empty? ) - ptop = $rc_settings[ 'pdftops_prog' ] - if xpdf_version( ptop ) then - self.pdftops_prog = ptop - end - if TL - self.gs_prog = TLROOT.gsub( /\//, '\\' ) + - '\\tlpkg\\tlgs\\bin\\gswin32c.exe' - self.gs_version = - ( `#{short_name( self.gs_prog )} --version` ).chomp - end + self.pdftops_prog = $rc_settings[ 'pdftops_prog' ] if + $rc_settings[ 'pdftops_prog' ] and + ! $rc_settings[ 'pdftops_prog' ].empty? and + test( ?f, $rc_settings[ 'pdftops_prog' ] ) when 'unix' if v = $rc_settings[ 'pdf_viewer' ] and is_a_program( v ) self.pdf_viewer = v @@ -482,22 +529,44 @@ class << $settings end # if end # case ARCH + if ( $rc_settings[ 'defaultDir' ] and + ( not $rc_settings[ 'defaultDir' ].strip.empty? ) and + test( ?d, $rc_settings[ 'defaultDir' ] ) ) + self.defaultDir = File.expand_path( $rc_settings[ 'defaultDir' ] ) + else + self.defaultDir = Dir.getwd + end + #print "defaultDir set to #{self.defaultDir} by epspdfrc.getsettings" + + # no validity checks for pdf- and ps output options. # reminder: self.s shortcut for self['s'].val [ 'pdf_target', 'pdf_version', 'pdf_custom', 'ps_options' ].each { |p| self[ p ].val = $rc_settings[ p ] if $rc_settings[ p ] } if $rc_settings.has_key?( 'ignore_pdftops' ) - $settings.ignore_pdftops = case $rc_settings[ 'ignore_pdftops' ] + self.ignore_pdftops = case $rc_settings[ 'ignore_pdftops' ] + when /1|yes|true|y|t/i + '1' + when /0|no|false|n|f/i + '0' + end + else + self.ignore_pdftops = '0' + end + + if $rc_settings.has_key?( 'ignore_hires_bb' ) + self.ignore_hires_bb = case $rc_settings[ 'ignore_hires_bb' ] when /1|yes|true|y|t/i '1' when /0|no|false|n|f/i '0' end else - $settings.ignore_pdftops = '0' + self.ignore_hires_bb = '0' end + # bb_spread has an effect only if ignore_hires_bb self.bb_spread = $rc_settings[ 'bb_spread' ] if $rc_settings.has_key?( 'bb_spread' ) and $rc_settings[ 'bb_spread' ] =~ /^[+-]?[\d]+$/ |