File: //usr/share/texmf/scripts/context/ruby/texmfstart.rb
#!/usr/bin/env ruby
# program : texmfstart
# copyright : PRAGMA Advanced Document Engineering
# version : 1.05 - 2003/2004
# author : Hans Hagen
#
# project : ConTeXt / eXaMpLe
# info : j.hagen@xs4all.nl
# www : www.pragma-pod.com / www.pragma-ade.com
# no special requirements, i.e. no exa modules/classes used
# texmfstart [switches] filename [optional arguments]
#
# ruby2exe texmfstart --help -> avoids stub test
#
# Of couse I can make this into a nice class, which i'll undoubtely will
# do when I feel the need. In that case it will be part of a bigger game.
# turning this into a service would be nice, so some day ...
# --locate => provides location
# --exec => exec instead of system
# --iftouched=a,b => only if timestamp a<>b
require "rbconfig"
$mswindows = Config::CONFIG['host_os'] =~ /mswin/
$separator = File::PATH_SEPARATOR
$version = "1.5.2"
if $mswindows then
require "win32ole"
require "Win32API"
GetShortPathName = Win32API.new('kernel32', 'GetShortPathName', ['P','P','N'], 'N')
GetLongPathName = Win32API.new('kernel32', 'GetLongPathName', ['P','P','N'], 'N')
def dowith_pathname (filename,filemethod)
filename = filename.gsub(/\\/o,'/') # no gsub! because filename can be frozen
case filename
when /\;/o then
# could be a path spec
return filename
when /\s+/o then
# danger lurking
buffer = ' ' * 260
length = filemethod.call(filename,buffer,buffer.size)
if length>0 then
return buffer.slice(0..length-1)
else
# when the path or file does not exist, nothing is returned
# so we try to handle the path separately from the basename
basename = File.basename(filename)
pathname = File.dirname(filename)
length = filemethod.call(pathname,buffer,260)
if length>0 then
return buffer.slice(0..length-1) + '/' + basename
else
return filename
end
end
else
# no danger
return filename
end
end
def shortpathname (filename)
dowith_pathname(filename,GetShortPathName)
end
def longpathname (filename)
dowith_pathname(filename,GetLongPathName)
end
else
def shortpathname (filename)
filename
end
def longpathname (filename)
filename
end
end
class File
def File.needsupdate(oldname,newname)
begin
return File.stat(oldname).mtime != File.stat(newname).mtime
rescue
return true
end
end
def File.syncmtimes(oldname,newname)
begin
t = File.mtime(oldname) # i'm not sure if the time is frozen, so we do it here
File.utime(0,t,oldname,newname)
rescue
end
end
end
$applications = Hash.new
$suffixinputs = Hash.new
$predefined = Hash.new
$suffixinputs['pl'] = 'PERLINPUTS'
$suffixinputs['rb'] = 'RUBYINPUTS'
$suffixinputs['py'] = 'PYTHONINPUTS'
$suffixinputs['jar'] = 'JAVAINPUTS'
$suffixinputs['pdf'] = 'PDFINPUTS'
$predefined['texexec'] = 'texexec.pl'
$predefined['texutil'] = 'texutil.pl'
$predefined['texfont'] = 'texfont.pl'
$predefined['examplex'] = 'examplex.rb'
$predefined['concheck'] = 'concheck.rb'
$predefined['textools'] = 'textools.rb'
$predefined['ctxtools'] = 'ctxtools.rb'
$predefined['pdftools'] = 'pdftools.rb'
$predefined['exatools'] = 'exatools.rb'
$predefined['xmltools'] = 'xmltools.rb'
$predefined['pstopdf'] = 'pstopdf.rb'
$scriptlist = 'rb|pl|py|jar'
$documentlist = 'pdf|ps|eps|htm|html'
def hashed (arr=[])
arg = if arr.class == String then arr.split(' ') else arr.dup end
hsh = Hash.new
if arg.length > 0
hsh['arguments'] = ''
done = false
arg.each do |s|
if done then
hsh['arguments'] += ' ' + s
else
kvl = s.split('=')
if kvl[0].sub!(/^\-+/,'') then
hsh[kvl[0]] = if kvl.length > 1 then kvl[1] else true end
else
hsh['file'] = s
done = true
end
end
end
end
return hsh
end
def launch(filename)
if $browser && $mswindows then
filename.gsub!(/\.[\/\\]/) do
Dir.getwd + '/'
end
report("launching #{filename}")
ie = WIN32OLE.new("InternetExplorer.Application")
ie.visible = true
ie.navigate(filename)
return true
else
return false
end
end
def expanded(arg) # no "other text files", too restricted
arg.gsub(/kpse\:(\S+)/o) do
original, resolved = $1, ''
if $program && ! $program.empty? then
pstr = "-progname=#{$program}"
else
pstr = ''
end
# auto suffix with texinputs as fall back
begin
resolved = `kpsewhich #{pstr} #{original}`.chomp
rescue
resolved = ''
end
# elsewhere in the tree
if resolved.empty? then
begin
resolved = `kpsewhich #{pstr} -format="other text files" #{original}`.chomp
rescue
resolved = ''
end
end
if resolved.empty? then
report("#{original} is not resolved") unless $report
original
else
report("#{original} is resolved to #{resolved}") unless $report
resolved
end
end
end
def runcommand(command)
if $locate then
print(command)
elsif $execute then
report("using 'exec' instead of 'system' call: #{command}") if $verbose
begin
Dir.chdir($path) if ! $path.empty?
rescue
report("unable to chdir to: #{$path}") if $verbose
end
exec(command)
else
report("using 'system' call: #{command}") if $verbose
begin
Dir.chdir($path) if ! $path.empty?
rescue
report("unable to chdir to: #{$path}") if $verbose
end
system(command)
end
end
def runoneof(application,fullname,browserpermitted)
if browserpermitted && launch(fullname) then
return true
else
report("starting #{$filename}") unless $report
print "\n" if $report && $verbose
applications = $applications[application]
if applications.class == Array then
if $report then
print [fullname,expanded($arguments)].join(' ')
return true
else
applications.each do |a|
if runcommand([a,fullname,expanded($arguments)].join(' ')) then
return true
end
end
end
elsif applications.empty? then
if $report then
print [fullname,expanded($arguments)].join(' ')
return true
else
return runcommand([fullname,expanded($arguments)].join(' '))
end
else
if $report then
print [applications,fullname,expanded($arguments)].join(' ')
return true
else
return runcommand([applications,fullname,expanded($arguments)].join(' '))
end
end
return false
end
end
def report(str)
print str + "\n" if $verbose ;
end
def usage
print "version : #{$version} - 2003/2004 - www.pragma-ade.com\n"
print("\n")
print("usage : texmfstart [switches] filename [optional arguments]\n")
print("\n")
print("switches : --verbose --report --browser --direct --execute --locate\n")
print(" --program --file --page --arguments\n")
print(" --make --lmake --wmake\n")
print("\n")
print("example : texmfstart pstopdf.rb cow.eps\n")
print(" texmfstart --locate examplex.rb\n")
print(" texmfstart --execute examplex.rb\n")
print(" texmfstart --browser examplap.pdf\n")
print(" texmfstart showcase.pdf\n")
print(" texmfstart --page=2 --file=showcase.pdf\n")
print(" texmfstart --program=yourtex yourscript.pl arg-1 arg-2\n")
print(" texmfstart --direct xsltproc kpse:somefile.xsl somefile.xml\n")
print(" texmfstart bin:xsltproc kpse:somefile.xsl somefile.xml\n")
print(" texmfstart --iftouched=normal,lowres downsample.rb normal lowres\n")
end
# somehow registration does not work out (at least not under windows)
def registered?(filename)
return ENV["texmfstart.#{filename}"] != nil
end
def registered(filename)
return ENV["texmfstart.#{filename}"]
end
def register(filename,fullname)
if fullname && ! fullname.empty? then # && FileTest.file?(fullname)
ENV["texmfstart.#{filename}"] = fullname
return true
else
return false
end
end
def find(filename,program)
if $predefined.key?(filename) then
report("expanding '#{filename}' to '#{$predefined[filename]}'")
filename = $predefined[filename]
end
if registered?(filename) then
report("already located '#{filename}'")
return registered(filename)
end
# create suffix list
if filename =~ /^(.*)\.(.+)$/ then
filename = $1
suffixlist = [$2]
else
suffixlist = [$scriptlist.split('|'),$documentlist.split('|')].flatten
end
# first we honor a given path
if filename =~ /[\\\/]/ then
report("trying to honor '#{filename}'")
suffixlist.each do |suffix|
fullname = filename+'.'+suffix
if FileTest.file?(fullname) && register(filename,fullname)
return shortpathname(fullname)
end
end
end
filename.sub!(/^.*[\\\/]/, '')
# next we look at the current path
suffixlist.each do |suffix|
report("locating '#{filename}.#{suffix}' in currentpath")
fullname = './'+filename+'.'+suffix
if FileTest.file?(fullname) && register(filename,fullname) then
report("'#{filename}.#{suffix}' located in currentpath")
return shortpathname(fullname)
end
end
# now we consult environment settings
fullname = nil
suffixlist.each do |suffix|
begin
break unless $suffixinputs[suffix]
environment = ENV[$suffixinputs[suffix]] || ENV[$suffixinputs[suffix]+".#{$program}"]
if ! environment || environment.empty? then
begin
environment = `kpsewhich -expand-path=\$#{$suffixinputs[suffix]}`.chomp
rescue
environment = nil
else
if environment && ! environment.empty? then
report("using kpsewhich variable #{$suffixinputs[suffix]}")
end
end
elsif environment && ! environment.empty? then
report("using environment variable #{$suffixinputs[suffix]}")
end
if environment && ! environment.empty? then
environment.split($separator).each do |e|
e.strip!
e = '.' if e == '\.' # somehow . gets escaped
e += '/' unless e =~ /[\\\/]$/
fullname = e + filename + '.' + suffix
report("testing '#{fullname}'")
if FileTest.file?(fullname) then
break
else
fullname = nil
end
end
end
rescue
report("environment string '#{$suffixinputs[suffix]}' cannot be used to locate '#{filename}'")
fullname = nil
else
return shortpathname(fullname) if register(filename,fullname)
end
end
return shortpathname(fullname) if register(filename,fullname)
# then we fall back on kpsewhich
suffixlist.each do |suffix|
# TDS script scripts location as per 2004
if suffix =~ /(#{$scriptlist})/ then
begin
report("using 'kpsewhich' to locate '#{filename}' in suffix space '#{suffix}' (1)")
fullname = `kpsewhich -progname=#{program} -format=texmfscripts #{filename}.#{suffix}`.chomp
rescue
report("kpsewhich cannot locate '#{filename}' in suffix space '#{suffix}' (1)")
fullname = nil
else
return shortpathname(fullname) if register(filename,fullname)
end
end
# old TDS location: .../texmf/context/...
begin
report("using 'kpsewhich' to locate '#{filename}' in suffix space '#{suffix}' (2)")
fullname = `kpsewhich -progname=#{program} -format="other text files" #{filename}.#{suffix}`.chomp
rescue
report("kpsewhich cannot locate '#{filename}' in suffix space '#{suffix}' (2)")
fullname = nil
else
return shortpathname(fullname) if register(filename,fullname)
end
end
return fullname if register(filename,fullname)
# bad luck, we need to search the tree ourselves
if (suffixlist.length == 1) && (suffixlist.first =~ /(#{$documentlist})/) then
report("aggressively locating '#{filename}' in document trees")
begin
texroot = `kpsewhich -expand-var=$SELFAUTOPARENT`.chomp
rescue
texroot = ''
else
texroot.sub!(/[\\\/][^\\\/]*?$/, '')
end
if not texroot.empty? then
sffxlst = suffixlist.join(',')
begin
report("locating '#{filename}' in document tree '#{texroot}/doc*'")
if (result = Dir.glob("#{texroot}/doc*/**/#{filename}.{#{sffxlst}}")) && result && result[0] && FileTest.file?(result[0]) then
fullname = result[0]
end
rescue
report("locating '#{filename}.#{suffix}' in tree '#{texroot}' aborted")
end
end
return shortpathname(fullname) if register(filename,fullname)
end
report("aggressively locating '#{filename}' in tex trees")
begin
textrees = `kpsewhich -expand-var=$TEXMF`.chomp
rescue
textrees = ''
end
if not textrees.empty? then
textrees.gsub!(/[\{\}\!]/, '')
textrees = textrees.split(',')
if (suffixlist.length == 1) && (suffixlist.first =~ /(#{$documentlist})/) then
speedup = ['doc**','**']
else
speedup = ['**']
end
sffxlst = suffixlist.join(',')
speedup.each do |speed|
textrees.each do |tt|
tt.gsub!(/[\\\/]$/, '')
if FileTest.directory?(tt) then
begin
report("locating '#{filename}' in tree '#{tt}/#{speed}/#{filename}.{#{sffxlst}}'")
if (result = Dir.glob("#{tt}/#{speed}/#{filename}.{#{sffxlst}}")) && result && result[0] && FileTest.file?(result[0]) then
fullname = result[0]
break
end
rescue
report("locating '#{filename}' in tree '#{tt}' aborted")
next
end
end
end
break if fullname && ! fullname.empty?
end
end
if register(filename,fullname) then
return shortpathname(fullname)
else
return ''
end
end
def run(fullname)
if ! fullname || fullname.empty? then
report("the file '#{$filename}' is not found")
elsif FileTest.file?(fullname) then
begin
case fullname
when /\.(#{$scriptlist})$/ then
return runoneof($1,fullname,false)
when /\.(#{$documentlist})$/ then
return runoneof($1,fullname,true)
else
return runoneof('unknown',fullname,false)
end
rescue
report("starting '#{$filename}' in program space '#{$program}' fails")
end
else
report("the file '#{$filename}' in program space '#{$program}' is not accessible")
end
return false
end
def direct(fullname)
begin
return runcommand([fullname.sub(/^bin\:/, ''),expanded($arguments)].join(' '))
rescue
return false
end
end
def make(filename,windows=false,linux=false)
basename = filename.dup
basename.sub!(/\.[^.]+?$/, '')
basename.sub!(/^.*[\\\/]/, '')
basename = $stubpath + '/' + basename unless $stubpath.empty?
if basename == filename then
report('nothing made')
else
program = nil
if filename =~ /[\\\/]/ && filename =~ /\.(#{$scriptlist})$/ then
program = $applications[$1]
end
filename = "\"#{filename}\"" if filename =~ /\s/
program = 'texmfstart' if $indirect || ! program || program.empty?
begin
if windows && f = open(basename+'.bat','w') then
f.binmode
f.write("@echo off\015\012")
f.write("#{program} #{filename} %*\015\012")
f.close
report("windows stub '#{basename}.bat' made")
elsif linux && f = open(basename,'w') then
f.binmode
f.write("#!/bin/sh\012")
f.write("#{program} #{filename} $@\012")
f.close
report("unix stub '#{basename}' made")
end
rescue
report("failed to make stub '#{basename}'")
else
return true
end
end
return false
end
$stdout.sync = true
$directives = hashed(ARGV)
$help = $directives['help'] || false
$filename = $directives['file'] || ''
$program = $directives['program'] || 'context'
$direct = $directives['direct'] || false
$page = $directives['page'] || 0
$browser = $directives['browser'] || false
$report = $directives['report'] || false
$verbose = $directives['verbose'] || false
$arguments = $directives['arguments'] || ''
$execute = $directives['execute'] || $directives['exec'] || false
$locate = $directives['locate'] || false
$path = $directives['path'] || ''
$make = $directives['make'] || false
$unix = $directives['unix'] || false
$windows = $directives['windows'] || false
$stubpath = $directives['stubpath'] || ''
$indirect = $directives['indirect'] || false
$iftouched = $directives['iftouched'] || false
$openoffice = $directives['oo'] || false
$applications['unknown'] = ''
$applications['perl'] = $applications['pl'] = 'perl'
$applications['ruby'] = $applications['rb'] = 'ruby'
$applications['python'] = $applications['py'] = 'python'
$applications['java'] = $applications['jar'] = 'java'
if $openoffice then
if ENV['OOPATH'] then
if FileTest.directory?(ENV['OOPATH']) then
report("using open office python") if $verbose
if $mswindows then
$applications['python'] = $applications['py'] = "\"#{File.join(ENV['OOPATH'],'program','python.bat')}\""
else
$applications['python'] = $applications['py'] = File.join(ENV['OOPATH'],'python')
end
report("python path #{$applications['python']}") if $verbose
else
report("environment variable 'OOPATH' does not exist") if $verbose
end
else
report("environment variable 'OOPATH' is not set") if $verbose
end
end
if $mswindows then
$applications['pdf'] = ['',"pdfopen --page #{$page} --file",'acroread']
$applications['html'] = ['','netscape','mozilla','opera','iexplore']
$applications['ps'] = ['','gview32','gv','gswin32','gs']
else
$applications['pdf'] = ["pdfopen --page #{$page} --file",'acroread']
$applications['html'] = ['netscape','mozilla','opera']
$applications['ps'] = ['gview','gv','gs']
end
$applications['htm'] = $applications['html']
$applications['eps'] = $applications['ps']
def process(&block)
if $iftouched then
files = $directives['iftouched'].split(',')
oldname, newname = files[0], files[1]
if oldname && newname && File.needsupdate(oldname,newname) then
yield
File.syncmtimes(oldname,newname)
end
else
yield
end
end
# system("perl -V")
if $help || ! $filename || $filename.empty? then
usage
else
report("texmfstart version #{$version}") if $verbose
if $make then
if $windows then
make($filename,true,false)
elsif $unix then
make($filename,false,true)
else
make($filename,$mswindows,!$mswindows)
end
elsif $browser && $filename =~ /^http\:\/\// then
launch($filename)
else
process do
if $direct || $filename =~ /^bin\:/ then
direct($filename)
else
run(find(shortpathname($filename),$program))
end
end
end
end