#!/usr/bin/env ruby # program : texmfstart # copyright : PRAGMA Advanced Document Engineering # version : 1.9.0 - 2003/2006 # 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 # --ifchanged=a,b => only if checksum changed # # file: path: bin: # texmfstart --exec bin:scite *.tex # we don't depend on other libs $: << File.expand_path(File.dirname($0)) ; $: << File.join($:.last,'lib') ; $:.uniq! require "rbconfig" require "md5" # kpse_merge_done: require 'base/kpseremote' # kpse_merge_done: require 'base/kpsedirect' # kpse_merge_done: require 'base/kpsefast' # kpse_merge_done: require 'base/merge' # kpse_merge_start # kpse_merge_file: 'C:/data/develop/context/ruby/base/kpseremote.rb' # kpse_merge_done: require 'base/kpsefast' case ENV['KPSEMETHOD'] when /soap/o then # kpse_merge_done: require 'base/kpse/soap' when /drb/o then # kpse_merge_done: require 'base/kpse/drb' else # kpse_merge_done: require 'base/kpse/drb' end class KpseRemote @@port = ENV['KPSEPORT'] || 7000 @@method = ENV['KPSEMETHOD'] || 'drb' def KpseRemote::available? @@method && @@port end def KpseRemote::start_server(port=nil) kpse = KpseServer.new(port || @@port) kpse.start end def KpseRemote::start_client(port=nil) # keeps object in server kpseclient = KpseClient.new(port || @@port) kpseclient.start kpse = kpseclient.object tree = kpse.choose(KpseUtil::identify, KpseUtil::environment) [kpse, tree] end def KpseRemote::fetch(port=nil) # no need for defining methods but slower, send whole object kpseclient = KpseClient.new(port || @@port) kpseclient.start kpseclient.object.fetch(KpseUtil::identify, KpseUtil::environment) rescue nil end def initialize(port=nil) if KpseRemote::available? then begin @kpse, @tree = KpseRemote::start_client(port) rescue @kpse, @tree = nil, nil end else @kpse, @tree = nil, nil end end def progname=(value) @kpse.set(@tree,'progname',value) end def format=(value) @kpse.set(@tree,'format',value) end def engine=(value) @kpse.set(@tree,'engine',value) end def progname @kpse.get(@tree,'progname') end def format @kpse.get(@tree,'format') end def engine @kpse.get(@tree,'engine') end def load @kpse.load(KpseUtil::identify, KpseUtil::environment) end def okay? @kpse && @tree end def set(key,value) @kpse.set(@tree,key,value) end def load_cnf @kpse.load_cnf(@tree) end def load_lsr @kpse.load_lsr(@tree) end def expand_variables @kpse.expand_variables(@tree) end def expand_braces(str) clean_name(@kpse.expand_braces(@tree,str)) end def expand_path(str) clean_name(@kpse.expand_path(@tree,str)) end def expand_var(str) clean_name(@kpse.expand_var(@tree,str)) end def show_path(str) clean_name(@kpse.show_path(@tree,str)) end def var_value(str) clean_name(@kpse.var_value(@tree,str)) end def find_file(filename) clean_name(@kpse.find_file(@tree,filename)) end def find_files(filename,first=false) # dodo: each filename @kpse.find_files(@tree,filename,first) end private def clean_name(str) str.gsub(/\\/,'/') end end # kpse_merge_file: 'C:/data/develop/context/ruby/base/kpsefast.rb' # module : base/kpsefast # copyright : PRAGMA Advanced Document Engineering # version : 2005 # author : Hans Hagen # # project : ConTeXt / eXaMpLe # concept : Hans Hagen # info : j.hagen@xs4all.nl # todo: multiple cnf files # class String def split_path if self =~ /\;/o || self =~ /^[a-z]\:/io then self.split(";") else self.split(":") end end end class Array def join_path self.join(File::PATH_SEPARATOR) end end class File def File.locate_file(path,name) begin files = Dir.entries(path) if files.include?(name) then fullname = File.join(path,name) return fullname if FileTest.file?(fullname) end files.each do |p| fullname = File.join(path,p) if p != '.' and p != '..' and FileTest.directory?(fullname) and result = locate_file(fullname,name) then return result end end rescue # bad path end return nil end def File.glob_file(pattern) return Dir.glob(pattern).first end end module KpseUtil # to be adapted, see loading cnf file @@texmftrees = ['texmf-local','texmf.local','../..','texmf'] # '../..' is for gwtex @@texmfcnf = 'texmf.cnf' def KpseUtil::identify # we mainly need to identify the local tex stuff and wse assume that # the texmfcnf variable is set; otherwise we need to expand the # TEXMF variable and that takes time since it may involve more ownpath = File.expand_path($0) if ownpath.gsub!(/texmf.*?$/o, '') then ENV['SELFAUTOPARENT'] = ownpath else ENV['SELFAUTOPARENT'] = '.' # fall back # may be too tricky: # # (ENV['PATH'] ||'').split_path.each do |p| # if p.gsub!(/texmf.*?$/o, '') then # ENV['SELFAUTOPARENT'] = p # break # end # end end filenames = Array.new if ENV['TEXMFCNF'] && ! ENV['TEXMFCNF'].empty? then ENV['TEXMFCNF'].to_s.split_path.each do |path| filenames << File.join(path,@@texmfcnf) end elsif ENV['SELFAUTOPARENT'] == '.' then filenames << File.join('.',@@texmfcnf) else @@texmftrees.each do |tree| filenames << File.join(ENV['SELFAUTOPARENT'],tree,'web2c',@@texmfcnf) end end loop do busy = false filenames.collect! do |f| f.gsub(/\$([a-zA-Z0-9\_\-]+)/o) do if (! ENV[$1]) || (ENV[$1] == $1) then "$#{$1}" else busy = true ENV[$1] end end end break unless busy end filenames.delete_if do |f| ! FileTest.file?(f) end return filenames end def KpseUtil::environment Hash.new.merge(ENV) end end class KpseFast # formats are an incredible inconsistent mess @@suffixes = Hash.new @@formats = Hash.new @@suffixmap = Hash.new @@texmfcnf = 'texmf.cnf' @@suffixes['gf'] = ['.gf'] # todo @@suffixes['pk'] = ['.pk'] # todo @@suffixes['tfm'] = ['.tfm'] @@suffixes['afm'] = ['.afm'] @@suffixes['base'] = ['.base'] @@suffixes['bib'] = ['.bib'] @@suffixes['bst'] = ['.bst'] @@suffixes['cnf'] = ['.cnf'] @@suffixes['ls-R'] = ['ls-R', 'ls-r'] @@suffixes['fmt'] = ['.fmt', '.efmt', '.efm', '.ofmt', '.ofm', '.oft', '.eofmt', '.eoft', '.eof', '.pfmt', '.pfm', '.epfmt', '.epf', '.xpfmt', '.xpf', '.afmt', '.afm'] @@suffixes['map'] = ['.map'] @@suffixes['mem'] = ['.mem'] @@suffixes['mf'] = ['.mf'] @@suffixes['mfpool'] = ['.pool'] @@suffixes['mft'] = ['.mft'] @@suffixes['mp'] = ['.mp'] @@suffixes['mppool'] = ['.pool'] @@suffixes['ocp'] = ['.ocp'] @@suffixes['ofm'] = ['.ofm', '.tfm'] @@suffixes['opl'] = ['.opl'] @@suffixes['otp'] = ['.otp'] @@suffixes['ovf'] = ['.ovf'] @@suffixes['ovp'] = ['.ovp'] @@suffixes['graphic/figure'] = ['.eps', '.epsi'] @@suffixes['tex'] = ['.tex'] @@suffixes['texpool'] = ['.pool'] @@suffixes['PostScript header'] = ['.pro'] @@suffixes['type1 fonts'] = ['.pfa', '.pfb'] @@suffixes['vf'] = ['.vf'] @@suffixes['ist'] = ['.ist'] @@suffixes['truetype fonts'] = ['.ttf', '.ttc'] @@suffixes['web'] = ['.web', '.ch'] @@suffixes['cweb'] = ['.w', '.web', '.ch'] @@suffixes['enc files'] = ['.enc'] @@suffixes['cmap files'] = ['.cmap'] @@suffixes['subfont definition files'] = ['.sfd'] @@suffixes['lig files'] = ['.lig'] @@suffixes['bitmap font'] = [] @@suffixes['MetaPost support'] = [] @@suffixes['TeX system documentation'] = [] @@suffixes['TeX system sources'] = [] @@suffixes['Troff fonts'] = [] @@suffixes['dvips config'] = [] @@suffixes['type42 fonts'] = [] @@suffixes['web2c files'] = [] @@suffixes['other text files'] = [] @@suffixes['other binary files'] = [] @@suffixes['misc fonts'] = [] @@suffixes['opentype fonts'] = [] @@suffixes['pdftex config'] = [] @@suffixes['texmfscripts'] = [] # replacements @@suffixes['fmt'] = ['.fmt'] @@suffixes['type1 fonts'] = ['.pfa', '.pfb', '.pfm'] @@suffixes['tex'] = ['.tex', '.xml'] @@suffixes['texmfscripts'] = ['rb','lua','py','pl'] @@suffixes.keys.each do |k| @@suffixes[k].each do |s| @@suffixmap[s] = k end end # TTF2TFMINPUTS # MISCFONTS # TEXCONFIG # DVIPDFMINPUTS # OTFFONTS @@formats['gf'] = '' @@formats['pk'] = '' @@formats['tfm'] = 'TFMFONTS' @@formats['afm'] = 'AFMFONTS' @@formats['base'] = 'MFBASES' @@formats['bib'] = '' @@formats['bst'] = '' @@formats['cnf'] = '' @@formats['ls-R'] = '' @@formats['fmt'] = 'TEXFORMATS' @@formats['map'] = 'TEXFONTMAPS' @@formats['mem'] = 'MPMEMS' @@formats['mf'] = 'MFINPUTS' @@formats['mfpool'] = 'MFPOOL' @@formats['mft'] = '' @@formats['mp'] = 'MPINPUTS' @@formats['mppool'] = 'MPPOOL' @@formats['ocp'] = 'OCPINPUTS' @@formats['ofm'] = 'OFMFONTS' @@formats['opl'] = 'OPLFONTS' @@formats['otp'] = 'OTPINPUTS' @@formats['ovf'] = 'OVFFONTS' @@formats['ovp'] = 'OVPFONTS' @@formats['graphic/figure'] = '' @@formats['tex'] = 'TEXINPUTS' @@formats['texpool'] = 'TEXPOOL' @@formats['PostScript header'] = 'TEXPSHEADERS' @@formats['type1 fonts'] = 'T1FONTS' @@formats['vf'] = 'VFFONTS' @@formats['ist'] = '' @@formats['truetype fonts'] = 'TTFONTS' @@formats['web'] = '' @@formats['cweb'] = '' @@formats['enc files'] = 'ENCFONTS' @@formats['cmap files'] = 'CMAPFONTS' @@formats['subfont definition files'] = 'SFDFONTS' @@formats['lig files'] = 'LIGFONTS' @@formats['bitmap font'] = '' @@formats['MetaPost support'] = '' @@formats['TeX system documentation'] = '' @@formats['TeX system sources'] = '' @@formats['Troff fonts'] = '' @@formats['dvips config'] = '' @@formats['type42 fonts'] = 'T42FONTS' @@formats['web2c files'] = 'WEB2C' @@formats['other text files'] = '' @@formats['other binary files'] = '' @@formats['misc fonts'] = '' @@formats['opentype fonts'] = 'OPENTYPEFONTS' @@formats['pdftex config'] = 'PDFTEXCONFIG' @@formats['texmfscripts'] = 'TEXMFSCRIPTS' attr_accessor :progname, :engine, :format, :rootpath, :treepath, :verbose, :remember, :scandisk, :diskcache, :renewcache @@cacheversion = '1' def initialize @rootpath = '' @treepath = '' @progname = 'kpsewhich' @engine = 'pdfetex' @variables = Hash.new @expansions = Hash.new @files = Hash.new @found = Hash.new @kpsevars = Hash.new @lsrfiles = Array.new @cnffiles = Array.new @verbose = true @remember = true @scandisk = true @diskcache = true @renewcache = false @isolate = false @diskcache = false @cachepath = nil @cachefile = 'tmftools.log' @environment = ENV end def set(key,value) case key when 'progname' then @progname = value when 'engine' then @engine = value when 'format' then @format = value end end def push_environment(env) @environment = env end # {$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c} # # $SELFAUTOLOC : /usr/tex/bin/platform # $SELFAUTODIR : /usr/tex/bin # $SELFAUTOPARENT : /usr/tex # # since we live in scriptpath we need a slightly different method def load_cnf(filenames=nil) unless filenames then ownpath = File.expand_path($0) if ownpath.gsub!(/texmf.*?$/o, '') then @environment['SELFAUTOPARENT'] = ownpath else @environment['SELFAUTOPARENT'] = '.' end unless @treepath.empty? then unless @rootpath.empty? then @treepath = @treepath.split(',').collect do |p| File.join(@rootpath,p) end.join(',') end @environment['TEXMF'] = @treepath # only the first one @environment['TEXMFCNF'] = File.join(@treepath.split(',').first,'texmf/web2c') end unless @rootpath.empty? then @environment['TEXMFCNF'] = File.join(@rootpath,'texmf/web2c') @environment['SELFAUTOPARENT'] = @rootpath @isolate = true end filenames = Array.new if @environment['TEXMFCNF'] and not @environment['TEXMFCNF'].empty? then @environment['TEXMFCNF'].to_s.split_path.each do |path| filenames << File.join(path,@@texmfcnf) end elsif @environment['SELFAUTOPARENT'] == '.' then filenames << File.join('.',@@texmfcnf) else ['texmf-local','texmf'].each do |tree| filenames << File.join(@environment['SELFAUTOPARENT'],tree,'web2c',@@texmfcnf) end end end # /texmf/web2c/texmf.cnf filenames = _expanded_path_(filenames) @rootpath = filenames.first 3.times do @rootpath = File.dirname(@rootpath) end filenames.collect! do |f| f.gsub("\\", '/') end filenames.each do |fname| if FileTest.file?(fname) and f = File.open(fname) then @cnffiles << fname while line = f.gets do loop do # concatenate lines ending with \ break unless line.sub!(/\\\s*$/o) do f.gets || '' end end case line when /^[\%\#]/o then # comment when /^\s*(.*?)\s*\=\s*(.*?)\s*$/o then key, value = $1, $2 unless @variables.key?(key) then value.sub!(/\%.*$/,'') value.sub!(/\~/, "$HOME") @variables[key] = value end @kpsevars[key] = true end end f.close end end end def load_lsr @lsrfiles = [] simplified_list(expansion('TEXMF')).each do |p| ['ls-R','ls-r'].each do |f| filename = File.join(p,f) if FileTest.file?(filename) then @lsrfiles << [filename,File.size(filename)] break end end end @files = Hash.new if @diskcache then ['HOME','TEMP','TMP','TMPDIR'].each do |key| if @environment[key] then if FileTest.directory?(@environment[key]) then @cachepath = @environment[key] @cachefile = [@rootpath.gsub(/[^A-Z0-9]/io, '-').gsub(/\-+/,'-'),File.basename(@cachefile)].join('-') break end end end if @cachepath and not @renewcache and FileTest.file?(File.join(@cachepath,@cachefile)) then begin if f = File.open(File.join(@cachepath,@cachefile)) then cacheversion = Marshal.load(f) if cacheversion == @@cacheversion then lsrfiles = Marshal.load(f) if lsrfiles == @lsrfiles then @files = Marshal.load(f) end end f.close end rescue @files = Hash.new end end end return if @files.size > 0 @lsrfiles.each do |filedata| filename, filesize = filedata filepath = File.dirname(filename) begin path = '.' data = IO.readlines(filename) if data[0].chomp =~ /% ls\-R \-\- filename database for kpathsea\; do not change this line\./io then data.each do |line| case line when /^[a-zA-Z0-9]/o then line.chomp! if @files[line] then @files[line] << path else @files[line] = [path] end when /^\.\/(.*?)\:$/o then path = File.join(filepath,$1) end end end rescue # sorry end end if @diskcache and @cachepath and f = File.open(File.join(@cachepath,@cachefile),'wb') then f << Marshal.dump(@@cacheversion) f << Marshal.dump(@lsrfiles) f << Marshal.dump(@files) f.close end end def expand_variables @expansions = Hash.new if @isolate then @variables['TEXMFCNF'] = @environment['TEXMFCNF'].dup @variables['SELFAUTOPARENT'] = @environment['SELFAUTOPARENT'].dup else @environment.keys.each do |e| if e =~ /^([a-zA-Z]+)\_(.*)\s*$/o then @expansions["#{$1}.#{$2}"] = (@environment[e] ||'').dup else @expansions[e] = (@environment[e] ||'').dup end end end @variables.keys.each do |k| @expansions[k] = @variables[k].dup unless @expansions[k] end loop do busy = false @expansions.keys.each do |k| @expansions[k].gsub!(/\$([a-zA-Z0-9\_\-]*)/o) do busy = true @expansions[$1] || '' end @expansions[k].gsub!(/\$\{([a-zA-Z0-9\_\-]*)\}/o) do busy = true @expansions[$1] || '' end end break unless busy end @expansions.keys.each do |k| @expansions[k] = @expansions[k].gsub("\\", '/') end end def variable(name='') (name and not name.empty? and @variables[name.sub('$','')]) or '' end def expansion(name='') (name and not name.empty? and @expansions[name.sub('$','')]) or '' end def variable?(name='') name and not name.empty? and @variables.key?(name.sub('$','')) end def expansion?(name='') name and not name.empty? and @expansions.key?(name.sub('$','')) end def simplified_list(str) lst = str.gsub(/^\{/o,'').gsub(/\}$/o,'').split(",") lst.collect do |l| l.sub(/^[\!]*/,'').sub(/[\/\\]*$/o,'') end end def original_variable(variable) if variable?("#{@progname}.#{variable}") then variable("#{@progname}.#{variable}") elsif variable?(variable) then variable(variable) else '' end end def expanded_variable(variable) if expansion?("#{variable}.#{@progname}") then expansion("#{variable}.#{@progname}") elsif expansion?(variable) then expansion(variable) else '' end end def original_path(filename='') _expanded_path_(original_variable(var_of_format_or_suffix(filename)).split(";")) end def expanded_path(filename='') _expanded_path_(expanded_variable(var_of_format_or_suffix(filename)).split(";")) end def _expanded_path_(pathlist) i, n = 0, 0 pathlist.collect! do |mainpath| mainpath.gsub(/([\{\}])/o) do if $1 == "{" then i += 1 ; n = i if i > n ; "<#{i}>" else i -= 1 ; "" end end end n.times do |i| loop do more = false newlist = [] pathlist.each do |path| unless path.sub!(/^(.*?)<(#{n-i})>(.*?)<\/\2>(.*?)$/) do pre, mid, post = $1, $3, $4 mid.gsub!(/\,$/,',.') mid.split(',').each do |m| more = true if m == '.' then newlist << "#{pre}#{post}" else newlist << "#{pre}#{m}#{post}" end end end then newlist << path end end if more then pathlist = [newlist].flatten # copy -) else break end end end pathlist = pathlist.uniq.collect do |path| p = path # p.gsub(/^\/+/o) do '' end # p.gsub!(/(.)\/\/(.)/o) do "#{$1}/#{$2}" end # p.gsub!(/\/\/+$/o) do '//' end p.gsub!(/\/\/+/o) do '//' end p end pathlist end # todo: ignore case def var_of_format(str) @@formats[str] || '' end def var_of_suffix(str) # includes . if @@suffixmap.key?(str) then @@formats[@@suffixmap[str]] else '' end end def var_of_format_or_suffix(str) if @@formats.key?(str) then @@formats[str] elsif @@suffixmap.key?(File.extname(str)) then # extname includes . @@formats[@@suffixmap[File.extname(str)]] # extname includes . else '' end end end class KpseFast # test things def list_variables(kpseonly=true) @variables.keys.sort.each do |k| if kpseonly then puts("#{k} = #{@variables[k]}") if @kpsevars[k] else puts("#{if @kpsevars[k] then 'K' else 'E' end} #{k} = #{@variables[k]}") end end end def list_expansions(kpseonly=true) @expansions.keys.sort.each do |k| if kpseonly then puts("#{k} = #{@expansions[k]}") if @kpsevars[k] else puts("#{if @kpsevars[k] then 'K' else 'E' end} #{k} = #{@expansions[k]}") end end end def list_lsr puts("files = #{@files.size}") end def set_test_patterns @variables["KPSE_TEST_PATTERN_A"] = "foo/{1,2}/bar//" @variables["KPSE_TEST_PATTERN_B"] = "!!x{A,B{1,2}}y" @variables["KPSE_TEST_PATTERN_C"] = "x{A,B//{1,2}}y" @variables["KPSE_TEST_PATTERN_D"] = "x{A,B//{1,2,}}//y" end def show_test_patterns ['A','B','D'].each do |i| puts "" puts @variables ["KPSE_TEST_PATTERN_#{i}"] puts "" puts expand_path("KPSE_TEST_PATTERN_#{i}").split_path puts "" end end end class KpseFast # kpse stuff def expand_braces(str) # output variable and brace expansion of STRING. _expanded_path_(original_variable(str).split_path).join_path end def expand_path(str) # output complete path expansion of STRING. _expanded_path_(expanded_variable(str).split_path).join_path end def expand_var(str) # output variable expansion of STRING. expanded_variable(str) end def show_path(str) # output search path for file type NAME expanded_path(str).join_path end def var_value(str) # output the value of variable $STRING. original_variable(str) end end class KpseFast def _is_cnf_?(filename) filename == File.basename((@cnffiles.first rescue @@texmfcnf) || @@texmfcnf) end def find_file(filename) if _is_cnf_?(filename) then @cnffiles.first rescue '' else [find_files(filename,true)].flatten.first || '' end end def find_files(filename,first=false) if _is_cnf_?(filename) then result = @cnffiles.dup else if @remember then # stamp = "#{filename}--#{@format}--#{@engine}--#{@progname}" stamp = "#{filename}--#{@engine}--#{@progname}" return @found[stamp] if @found.key?(stamp) end pathlist = expanded_path(filename) result = [] filelist = if @files.key?(filename) then @files[filename].uniq else nil end done = false if pathlist.size == 0 then if FileTest.file?(filename) then done = true result << '.' end else pathlist.each do |path| doscan = if path =~ /^\!\!/o then false else true end recurse = if path =~ /\/\/$/o then true else false end pathname = path.dup pathname.gsub!(/^\!+/o, '') done = false if not done and filelist then # checking for exact match if filelist.include?(pathname) then result << pathname done = true end if not done and recurse then # checking for fuzzy // pathname.gsub!(/\/+$/o, '/.*') # pathname.gsub!(/\/\//o,'/[\/]*/') pathname.gsub!(/\/\//o,'/.*?/') re = /^#{pathname}/ filelist.each do |f| if re =~ f then result << f # duplicates will be filtered later done = true end break if done end end end if not done and doscan then # checking for path itself pname = pathname.sub(/\.\*$/,'') if not pname =~ /\*/o and FileTest.file?(File.join(pname,filename)) then result << pname done = true end end break if done and first end end if not done and @scandisk then pathlist.each do |path| pathname = path.dup unless pathname.gsub!(/^\!+/o, '') then # !! prevents scan recurse = pathname.gsub!(/\/+$/o, '') complex = pathname.gsub!(/\/\//o,'/*/') if recurse then if complex then if ok = File.glob_file("#{pathname}/**/#{filename}") then result << File.dirname(ok) done = true end elsif ok = File.locate_file(pathname,filename) then result << File.dirname(ok) done = true end elsif complex then if ok = File.glob_file("#{pathname}/#{filename}") then result << File.dirname(ok) done = true end elsif FileTest.file?(File.join(pathname,filename)) then result << pathname done = true end break if done and first end end end result = result.uniq.collect do |pathname| File.join(pathname,filename) end @found[stamp] = result if @remember end return result # redundant end end class KpseFast class FileData attr_accessor :tag, :name, :size, :date def initialize(tag=0,name=nil,size=nil,date=nil) @tag, @name, @size, @date = tag, name, size, date end def FileData.sizes(a) a.collect do |aa| aa.size end end def report case @tag when 1 then "deleted | #{@size.to_s.rjust(8)} | #{@date.strftime('%m/%d/%Y %I:%M')} | #{@name}" when 2 then "present | #{@size.to_s.rjust(8)} | #{@date.strftime('%m/%d/%Y %I:%M')} | #{@name}" when 3 then "obsolete | #{' '*8} | #{' '*16} | #{@name}" end end end def analyze_files(filter='',strict=false,sort='',delete=false) puts("command line = #{ARGV.join(' ')}") puts("number of files = #{@files.size}") puts("filter pattern = #{filter}") puts("loaded cnf files = #{@cnffiles.join(' ')}") puts('') if filter.gsub!(/^not:/,'') then def the_same(filter,filename) not filter or filter.empty? or /#{filter}/ !~ filename end else def the_same(filter,filename) not filter or filter.empty? or /#{filter}/ =~ filename end end @files.keys.each do |name| if @files[name].size > 1 then data = Array.new @files[name].each do |path| filename = File.join(path,name) # if not filter or filter.empty? or /#{filter}/ =~ filename then if the_same(filter,filename) then if FileTest.file?(filename) then if delete then data << FileData.new(1,filename,File.size(filename),File.mtime(filename)) begin File.delete(filename) if delete rescue end else data << FileData.new(2,filename,File.size(filename),File.mtime(filename)) end else # data << FileData.new(3,filename) end end end if data.length > 1 then if strict then # if data.collect do |d| d.size end.uniq! then # data.sort! do |a,b| b.size <=> a.size end # data.each do |d| puts d.report end # puts '' # end data.sort! do |a,b| if a.size and b.size then b.size <=> a.size else 0 end end bunch = Array.new done = false data.each do |d| if bunch.size == 0 then bunch << d elsif bunch[0].size == d.size then bunch << d else if bunch.size > 1 then bunch.each do |b| puts b.report end done = true end bunch = [d] end end puts '' if done else case sort when 'size' then data.sort! do |a,b| a.size <=> b.size end when 'revsize' then data.sort! do |a,b| b.size <=> a.size end when 'date' then data.sort! do |a,b| a.date <=> b.date end when 'revdate' then data.sort! do |a,b| b.date <=> a.date end end data.each do |d| puts d.report end puts '' end end end end end end # k = KpseFast.new # (root) # k.set_test_patterns # k.load_cnf # k.expand_variables # k.load_lsr # k.show_test_patterns # puts k.list_variables # puts k.list_expansions # k.list_lsr # puts k.expansion("$TEXMF") # puts k.expanded_path("TEXINPUTS","context") # k.progname, k.engine, k.format = 'context', 'pdfetex', 'tfm' # k.scandisk = false # == must_exist # k.expand_variables # 10.times do |i| puts k.find_file('texnansi-lmr10.tfm') end # puts "expand braces $TEXMF" # puts k.expand_braces("$TEXMF") # puts "expand path $TEXMF" # puts k.expand_path("$TEXMF") # puts "expand var $TEXMF" # puts k.expand_var("$TEXMF") # puts "expand path $TEXMF" # puts k.show_path('tfm') # puts "expand value $TEXINPUTS" # puts k.var_value("$TEXINPUTS") # puts "expand value $TEXINPUTS.context" # puts k.var_value("$TEXINPUTS.context") # exit # kpse_merge_file: 'C:/data/develop/context/ruby/base/kpse/drb.rb' require 'drb' # kpse_merge_done: require 'base/kpse/trees' class KpseServer attr_accessor :port def initialize(port=7000) @port = port end def start puts "starting drb service at port #{@port}" DRb.start_service("druby://localhost:#{@port}", KpseTrees.new) trap(:INT) do DRb.stop_service end DRb.thread.join end def stop # todo end end class KpseClient attr_accessor :port def initialize(port=7000) @port = port @kpse = nil end def start # only needed when callbacks are used / slow, due to Socket::getaddrinfo # DRb.start_service end def object @kpse = DRbObject.new(nil,"druby://localhost:#{@port}") end end # SERVER_URI="druby://localhost:8787" # # # Start a local DRbServer to handle callbacks. # # # # Not necessary for this small example, but will be required # # as soon as we pass a non-marshallable object as an argument # # to a dRuby call. # DRb.start_service # # kpse_merge_file: 'C:/data/develop/context/ruby/base/kpse/trees.rb' require 'monitor' # kpse_merge_done: require 'base/kpsefast' class KpseTrees < Monitor def initialize @trees = Hash.new end def pattern(filenames) filenames.join('|').gsub(/\\+/o,'/').downcase end def choose(filenames,environment) current = pattern(filenames) load(filenames,environment) unless @trees[current] puts "enabling tree #{current}" current end def fetch(filenames,environment) # will send whole object ! current = pattern(filenames) load(filenames,environment) unless @trees[current] puts "fetching tree #{current}" @trees[current] end def load(filenames,environment) current = pattern(filenames) puts "loading tree #{current}" @trees[current] = KpseFast.new @trees[current].push_environment(environment) @trees[current].load_cnf(filenames) @trees[current].expand_variables @trees[current].load_lsr end def set(tree,key,value) case key when 'progname' then @trees[tree].progname = value when 'engine' then @trees[tree].engine = value when 'format' then @trees[tree].format = value end end def get(tree,key) case key when 'progname' then @trees[tree].progname when 'engine' then @trees[tree].engine when 'format' then @trees[tree].format end end def load_cnf(tree) @trees[tree].load_cnf end def load_lsr(tree) @trees[tree].load_lsr end def expand_variables(tree) @trees[tree].expand_variables end def expand_braces(tree,str) @trees[tree].expand_braces(str) end def expand_path(tree,str) @trees[tree].expand_path(str) end def expand_var(tree,str) @trees[tree].expand_var(str) end def show_path(tree,str) @trees[tree].show_path(str) end def var_value(tree,str) @trees[tree].var_value(str) end def find_file(tree,filename) @trees[tree].find_file(filename) end def find_files(tree,filename,first) @trees[tree].find_files(filename,first) end end # kpse_merge_file: 'C:/data/develop/context/ruby/base/kpsedirect.rb' class KpseDirect attr_accessor :progname, :format, :engine def initialize @progname, @format, @engine = '', '', '' end def expand_path(str) clean_name(`kpsewhich -expand-path=#{str}`.chomp) end def expand_var(str) clean_name(`kpsewhich -expand-var=#{str}`.chomp) end def find_file(str) clean_name(`kpsewhich #{_progname_} #{_format_} #{str}`.chomp) end def _progname_ if @progname.empty? then '' else "-progname=#{@progname}" end end def _format_ if @format.empty? then '' else "-format=\"#{@format}\"" end end private def clean_name(str) str.gsub(/\\/,'/') end end # kpse_merge_file: 'C:/data/develop/context/ruby/base/merge.rb' # module : base/merge # copyright : PRAGMA Advanced Document Engineering # version : 2006 # author : Hans Hagen # # project : ConTeXt / eXaMpLe # concept : Hans Hagen # info : j.hagen@xs4all.nl # this module will package all the used modules in the file itself # so that we can relocate the file at wish, usage: # # merge: # # unless SelfMerge::ok? && SelfMerge::merge then # puts("merging should happen on the path were the base inserts reside") # end # # cleanup: # # unless SelfMerge::cleanup then # puts("merging should happen on the path were the base inserts reside") module SelfMerge @@kpsemergestart = "\# kpse_merge_start" @@kpsemergestop = "\# kpse_merge_stop" @@kpsemergefile = "\# kpse_merge_file: " @@kpsemergedone = "\# kpse_merge_done: " @@filename = File.basename($0) @@ownpath = File.expand_path(File.dirname($0)) @@modroot = '(base|graphics|rslb|www)' # needed in regex in order not to mess up SelfMerge @@modules = $".collect do |file| File.expand_path(file) end @@modules.delete_if do |file| file !~ /^#{@@ownpath}\/#{@@modroot}.*$/ end def SelfMerge::ok? begin @@modules.each do |file| return false unless FileTest.file?(file) end rescue return false else return true end end def SelfMerge::merge begin if SelfMerge::ok? && rbfile = IO.read(@@filename) then begin inserts = "#{@@kpsemergestart}\n\n" @@modules.each do |file| inserts << "#{@@kpsemergefile}'#{file}'\n\n" inserts << IO.read(file).gsub(/^#.*?\n$/,'') inserts << "\n\n" end inserts << "#{@@kpsemergestop}\n\n" # no gsub! else we end up in SelfMerge rbfile.sub!(/#{@@kpsemergestart}\s*#{@@kpsemergestop}/mois) do inserts end rbfile.gsub!(/^(.*)(require [\"\'].*?#{@@modroot}.*)$/) do pre, post = $1, $2 if pre =~ /#{@@kpsemergedone}/ then "#{pre}#{post}" else "#{pre}#{@@kpsemergedone}#{post}" end end rescue return false else begin File.open(@@filename,'w') do |f| f << rbfile end rescue return false end end end rescue return false else return true end end def SelfMerge::cleanup begin if rbfile = IO.read(@@filename) then begin rbfile.sub!(/#{@@kpsemergestart}(.*)#{@@kpsemergestop}\s*/mois) do "#{@@kpsemergestart}\n\n#{@@kpsemergestop}\n\n" end rbfile.gsub!(/^(.*#{@@kpsemergedone}.*)$/) do str = $1 if str =~ /require [\"\']/ then str.gsub(/#{@@kpsemergedone}/, '') else str end end rescue return false else begin File.open(@@filename,'w') do |f| f << rbfile end rescue return false end end end rescue return false else return true end end def SelfMerge::replace if SelfMerge::ok? then SelfMerge::cleanup SelfMerge::merge end end end # kpse_merge_stop $mswindows = Config::CONFIG['host_os'] =~ /mswin/ $separator = File::PATH_SEPARATOR $version = "2.0.2" $ownpath = File.dirname($0) if $mswindows then require "win32ole" require "Win32API" end # exit if defined?(REQUIRE2LIB) $stdout.sync = true $stderr.sync = true $applications = Hash.new $suffixinputs = Hash.new $predefined = Hash.new $suffixinputs['pl'] = 'PERLINPUTS' $suffixinputs['rb'] = 'RUBYINPUTS' $suffixinputs['py'] = 'PYTHONINPUTS' $suffixinputs['lua'] = 'LUAINPUTS' $suffixinputs['jar'] = 'JAVAINPUTS' $suffixinputs['pdf'] = 'PDFINPUTS' $predefined['texexec'] = 'texexec.rb' $predefined['texutil'] = 'texutil.rb' $predefined['texfont'] = 'texfont.pl' $predefined['texshow'] = 'texshow.pl' $predefined['makempy'] = 'makempy.pl' $predefined['mptopdf'] = 'mptopdf.pl' $predefined['pstopdf'] = 'pstopdf.rb' $predefined['examplex'] = 'examplex.rb' $predefined['concheck'] = 'concheck.rb' $predefined['runtools'] = 'runtools.rb' $predefined['textools'] = 'textools.rb' $predefined['tmftools'] = 'tmftools.rb' $predefined['ctxtools'] = 'ctxtools.rb' $predefined['rlxtools'] = 'rlxtools.rb' $predefined['pdftools'] = 'pdftools.rb' $predefined['mpstools'] = 'mpstools.rb' $predefined['exatools'] = 'exatools.rb' $predefined['xmltools'] = 'xmltools.rb' $predefined['luatools'] = 'luatools.lua' $predefined['mtxtools'] = 'mtxtools.rb' $predefined['newpstopdf'] = 'pstopdf.rb' $predefined['newtexexec'] = 'texexec.rb' $predefined['pdftrimwhite'] = 'pdftrimwhite.pl' $makelist = [ # context 'texexec', 'texutil', 'texfont', # mp/ps 'pstopdf', 'mptopdf', 'makempy', # misc 'ctxtools', 'pdftools', 'xmltools', 'textools', 'mpstools', 'tmftools', 'exatools', 'runtools', 'rlxtools', 'luatools', 'mtxtools', # # no, 'texmfstart' ] $scriptlist = 'rb|pl|py|lua|jar' $documentlist = 'pdf|ps|eps|htm|html' $editor = ENV['TEXMFSTART_EDITOR'] || ENV['EDITOR'] || ENV['editor'] || 'scite' $crossover = true # to other tex tools, else only local $kpse = nil def set_applications(page=1) $applications['unknown'] = '' $applications['perl'] = $applications['pl'] = 'perl' $applications['ruby'] = $applications['rb'] = 'ruby' $applications['python'] = $applications['py'] = 'python' $applications['lua'] = $applications['lua'] = 'lua' $applications['java'] = $applications['jar'] = 'java' 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'] end set_applications() def check_kpse if $kpse then # already done else begin if KpseRemote::available? then $kpse = KpseRemote.new if $kpse.okay? then puts("kpse : remote") if $verbose else $kpse = KpseDirect.new puts("kpse : direct (forced)") if $verbose end else $kpse = KpseDirect.new puts("kpse : direct") if $verbose end rescue puts("kpse : direct (fallback)") if $verbose end end end if $mswindows then 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 longpathname (filename) dowith_pathname(filename,GetLongPathName) end def shortpathname (filename) dowith_pathname(filename,GetShortPathName) end else def longpathname (filename) filename end def shortpathname (filename) filename end end class File # def File.needsupdate(oldname,newname) # begin # if $mswindows then # return File.stat(oldname).mtime > File.stat(newname).mtime # else # return File.stat(oldname).mtime != File.stat(newname).mtime # end # rescue # return true # end # end @@update_eps = 1 def File.needsupdate(oldname,newname) begin oldtime = File.stat(oldname).mtime.to_i newtime = File.stat(newname).mtime.to_i if newtime >= oldtime then return false elsif oldtime-newtime < @@update_eps then return false else return true end rescue return true end end def File.syncmtimes(oldname,newname) return begin if $mswindows then # does not work (yet) / gives future timestamp # t = File.mtime(oldname) # i'm not sure if the time is frozen, so we do it here # File.utime(0,t,oldname,newname) else t = File.mtime(oldname) # i'm not sure if the time is frozen, so we do it here File.utime(0,t,oldname,newname) end rescue end end def File.timestamp(name) begin "#{File.stat(name).mtime}" rescue return 'unknown' end end end 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 = 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 # env|environment # rel|relative # loc|locate|kpse|path|file def expanded(arg) # no "other text files", too restricted arg.gsub(/(env|environment)\:([a-zA-Z\-\_\.0-9]+)/o) do method, original, resolved = $1, $2, '' if resolved = ENV[original] then report("environment variable #{original} expands to #{resolved}") unless $report resolved else report("environment variable #{original} cannot be resolved") unless $report original end end . gsub(/(rel|relative)\:([a-zA-Z\-\_\.0-9]+)/o) do method, original, resolved = $1, $2, '' ['.','..','../..'].each do |r| if FileTest.file?(File.join(r,original)) then resolved = File.join(r,original) break end end if resolved.empty? then original else resolved end end . gsub(/(kpse|loc|locate|file|path)\:([a-zA-Z\-\_\.0-9]+)/o) do method, original, resolved = $1, $2, '' if $program && ! $program.empty? then # pstrings = ["-progname=#{$program}"] pstrings = [$program] else # pstrings = ['','-progname=context'] pstrings = ['','context'] end # auto suffix with texinputs as fall back if ENV["_CTX_K_V_#{original}_"] then resolved = ENV["_CTX_K_V_#{original}_"] report("environment provides #{original} as #{resolved}") unless $report resolved else check_kpse pstrings.each do |pstr| if resolved.empty? then # command = "kpsewhich #{pstr} #{original}" # report("running #{command}") report("locating '#{original}' in program space '#{pstr}'") begin # resolved = `#{command}`.chomp $kpse.progname = pstr $kpse.format = '' resolved = $kpse.find_file(original).gsub(/\\/,'/') rescue resolved = '' end end # elsewhere in the tree if resolved.empty? then # command = "kpsewhich #{pstr} -format=\"other text files\" #{original}" # report("running #{command}") report("locating '#{original}' in program space '#{pstr}' using format 'other text files'") begin # resolved = `#{command}`.chomp $kpse.progname = pstr $kpse.format = 'other text files' resolved = $kpse.find_file(original).gsub(/\\/,'/') rescue resolved = '' end end end if resolved.empty? then original = File.dirname(original) if method =~ /path/ report("#{original} is not resolved") unless $report ENV["_CTX_K_V_#{original}_"] = original if $crossover original else resolved = File.dirname(resolved) if method =~ /path/ report("#{original} is resolved to #{resolved}") unless $report ENV["_CTX_K_V_#{original}_"] = resolved if $crossover resolved end end end end def changeddir?(path) if path.empty? then return true else begin Dir.chdir(path) if ! path.empty? rescue report("unable to change to directory: #{path}") else report("changed to directory: #{path}") end return File.expand_path(Dir.getwd) == File.expand_path(path) end end def runcommand(command) if $locate then command = command.split(' ').collect do |c| if c =~ /\//o then begin cc = File.expand_path(c) c = cc if FileTest.file?(cc) rescue end end c end . join(' ') print command # to stdout and no newline elsif $execute then report("using 'exec' instead of 'system' call: #{command}") exec(command) if changeddir?($path) else report("using 'system' call: #{command}") system(command) if changeddir?($path) end end def runoneof(application,fullname,browserpermitted) if browserpermitted && launch(fullname) then return true else report("starting #{$filename}") unless $report output("\n") if $report && $verbose applications = $applications[application.downcase] if ! applications then output("problems with determining application type") return true elsif applications.class == Array then if $report then output([fullname,expanded($arguments)].join(' ')) return true else applications.each do |a| return true if runcommand([a,fullname,expanded($arguments)].join(' ')) end end elsif applications.empty? then if $report then output([fullname,expanded($arguments)].join(' ')) return true else return runcommand([fullname,expanded($arguments)].join(' ')) end else if $report then output([applications,fullname,expanded($arguments)].join(' ')) return true else return runcommand([applications,fullname,expanded($arguments)].join(' ')) end end return false end end def report(str) $stdout.puts(str) if $verbose end def output(str) $stdout.puts(str) end def usage print "version : #{$version} - 2003/2006 - 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 --iftouched --ifchanged\n") print(" --program --file --page --arguments --batch --edit --report --clear\n") print(" --make --lmake --wmake --path --stubpath --indirect --before --after\n") print(" --tree --autotree --environment --showenv\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.rb arg-1 arg-2\n") print(" texmfstart --direct xsltproc kpse:somefile.xsl somefile.xml\n") print(" texmfstart --direct ruby rel:wn-cleanup-1.rb oldfile.xml newfile.xml\n") print(" texmfstart bin:xsltproc env:somepreset path:somefile.xsl somefile.xml\n") print(" texmfstart --iftouched=normal,lowres downsample.rb normal lowres\n") print(" texmfstart --ifchanged=somefile.dat --direct processit somefile.dat\n") print(" texmfstart bin:scite kpse:texmf.cnf\n") print(" texmfstart --exec bin:scite *.tex\n") print(" texmfstart --edit texmf.cnf\n") print(" texmfstart --edit kpse:texmf.cnf\n") print(" texmfstart --serve\n") print("\n") print(" texmfstart --stubpath=/usr/local/bin [--make --remove] --verbose all\n") print(" texmfstart --stubpath=auto [--make --remove] all\n") print("\n") check_kpse end # somehow registration does not work out (at least not under windows) def tag(name) if $crossover then "_CTX_K_S_#{name}_" else "TEXMFSTART.#{name}" end end def registered?(filename) return ENV[tag(filename)] != nil end def registered(filename) return ENV[tag(filename)] || 'unknown' end def register(filename,fullname) if fullname && ! fullname.empty? then # && FileTest.file?(fullname) ENV[tag(filename)] = fullname report("registering '#{filename}' as '#{fullname}'") return true else return false end end def find(filename,program) begin filename = filename.sub(/script:/o, '') # so we have bin: and script: and nothing 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 and the callerpath [ ['.','current'], [$ownpath,'caller'], ["#{$ownpath}/../#{suffixlist[0]}",'caller'], [registered("THREAD"),'thread'], ["#{registered("THREAD")}/../#{suffixlist[0]}",'thread'], ].each do |p| if p && ! p.empty? && ! (p[0] == 'unknown') then suffixlist.each do |suffix| fname = "#{filename}.#{suffix}" fullname = File.expand_path(File.join(p[0],fname)) report("locating '#{fname}' in #{p[1]} path '#{p[0]}'") if FileTest.file?(fullname) && register(filename,fullname) then report("'#{fname}' located in #{p[1]} path") return shortpathname(fullname) end end end end # now we consult environment settings fullname = nil check_kpse $kpse.progname = program 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 environment = $kpse.expand_path("\$#{$suffixinputs[suffix]}") 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 $kpse.format = 'texmfscripts' fullname = $kpse.find_file("#{filename}.#{suffix}").gsub(/\\/,'/') 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 $kpse.format = 'other text files' fullname = $kpse.find_file("#{filename}.#{suffix}").gsub(/\\/,'/') rescue report("kpsewhich cannot locate '#{filename}' in suffix space '#{suffix}' (2)") fullname = nil else return shortpathname(fullname) if register(filename,fullname) end end return shortpathname(fullname) if register(filename,fullname) # let's take a look at the path paths = ENV['PATH'].split($separator) suffixlist.each do |s| paths.each do |p| suffixedname = "#{filename}.#{s}" report("checking #{p} for #{filename}") if FileTest.file?(File.join(p,suffixedname)) then fullname = File.join(p,suffixedname) return shortpathname(fullname) if register(filename,fullname) end end end # 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 texroot = $kpse.expand_var("$SELFAUTOPARENT") 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}.#{suffixlist.join('|')}' 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 textrees = $kpse.expand_var("$TEXMF") 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 rescue error, trace = $!, $@.join("\n") report("fatal error: #{error}\n#{trace}") # report("fatal error") end end def run(fullname) if ! fullname || fullname.empty? then output("the file '#{$filename}' is not found") elsif FileTest.file?(fullname) then begin case fullname when /\.(#{$scriptlist})$/i then return runoneof($1,fullname,false) when /\.(#{$documentlist})$/i 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|binary)\:/, ''),expanded($arguments)].join(' ')) rescue return false end end def edit(filename) begin return runcommand([$editor,expanded(filename),expanded($arguments)].join(' ')) rescue return false end end def make(filename,windows=false,linux=false,remove=false) basename = File.basename(filename).gsub(/\.[^.]+?$/, '') if $stubpath == 'auto' then basename = File.dirname($0) + '/' + basename else basename = $stubpath + '/' + basename unless $stubpath.empty? end if filename == 'texmfstart' then program = 'ruby' command = 'kpsewhich --format=texmfscripts --progname=context texmfstart.rb' filename = `#{command}`.chomp.gsub(/\\/, '/') if filename.empty? then report("failure: #{command}") return elsif not remove then if windows then ['bat','exe'].each do |suffix| if FileTest.file?("#{basename}.#{suffix}") then report("windows stub '#{basename}.#{suffix}' skipped (already present)") return end end elsif linux && FileTest.file?(basename) then report("unix stub '#{basename}' skipped (already present)") return end end else program = nil if filename =~ /[\\\/]/ && filename =~ /\.(#{$scriptlist})$/ then program = $applications[$1] end filename = "\"#{filename}\"" if filename =~ /\s/ program = 'texmfstart' if $indirect || ! program || program.empty? end begin callname = $predefined[filename.sub(/\.*?$/,'')] || filename if remove then if windows && (File.delete(basename+'.bat') rescue false) then report("windows stub '#{basename}.bat' removed (calls #{callname})") elsif linux && (File.delete(basename) rescue false) then report("unix stub '#{basename}' removed (calls #{callname})") end else if windows && f = open(basename+'.bat','w') then f.binmode f.write("@echo off\015\012") f.write("#{program} #{callname} %*\015\012") f.close report("windows stub '#{basename}.bat' made (calls #{callname})") elsif linux && f = open(basename,'w') then f.binmode f.write("#!/bin/sh\012") f.write("#{program} #{callname} \"$@\"\012") f.close report("unix stub '#{basename}' made (calls #{callname})") end end rescue report("failed to make stub '#{basename}' #{$!}") return false else return true end end def process(&block) if $iftouched then files = $directives['iftouched'].split(',') oldname, newname = files[0], files[1] if oldname && newname && File.needsupdate(oldname,newname) then report("file #{oldname}: #{File.timestamp(oldname)}") report("file #{newname}: #{File.timestamp(newname)}") report("file is touched, processing started") yield File.syncmtimes(oldname,newname) else report("file #{oldname} is untouched") end elsif $ifchanged then filename = $directives['ifchanged'] checkname = filename + ".md5" oldchecksum, newchecksum = "old", "new" begin newchecksum = MD5.new(IO.read(filename)).hexdigest.upcase rescue newchecksum = "new" else begin oldchecksum = IO.read(checkname).chomp rescue oldchecksum = "old" end end if $verbose then report("old checksum #{filename}: #{oldchecksum}") report("new checksum #{filename}: #{newchecksum}") end if oldchecksum != newchecksum then report("file is changed, processing started") begin File.open(checkname,'w') do |f| f << newchecksum end rescue end yield else report("file #{filename} is unchanged") end else yield end end def checkenvironment(tree) report('') ENV['TMP'] = ENV['TMP'] || ENV['TEMP'] || ENV['TMPDIR'] || ENV['HOME'] case RUBY_PLATFORM when /(mswin|bccwin|mingw|cygwin)/i then ENV['TEXOS'] = ENV['TEXOS'] || 'texmf-mswin' when /(linux)/i then ENV['TEXOS'] = ENV['TEXOS'] || 'texmf-linux' when /(darwin|rhapsody|nextstep)/i then ENV['TEXOS'] = ENV['TEXOS'] || 'texmf-macosx' # when /(netbsd|unix)/i then # todo else # todo end ENV['TEXOS'] = "#{ENV['TEXOS'].sub(/^[\\\/]*/, '').sub(/[\\\/]*$/, '')}" ENV['TEXPATH'] = tree.sub(/\/+$/,'') # + '/' ENV['TEXMFOS'] = "#{ENV['TEXPATH']}/#{ENV['TEXOS']}" report('') report("preset : TEXPATH => #{ENV['TEXPATH']}") report("preset : TEXOS => #{ENV['TEXOS']}") report("preset : TEXMFOS => #{ENV['TEXMFOS']}") report("preset : TMP => #{ENV['TMP']}") report('') end def loadfile(filename) begin IO.readlines(filename).each do |line| case line.chomp when /^[\#\%]/ then # comment when /^(.*?)\s*(\>|\=|\<)\s*(.*)\s*$/ then # = assign | > prepend | < append key, how, value = $1, $2, $3 begin # $SAFE = 0 value.gsub!(/\%(.*?)\%/) do ENV[$1] || '' end # value.gsub!(/\;/,$separator) if key =~ /PATH/i then case how when '=', '<<' then ENV[key] = value when '?', '??' then ENV[key] = ENV[key] || value when '<', '+=' then ENV[key] = (ENV[key] || '') + $separator + value when '>', '=+' then ENV[key] = value + $separator + (ENV[key] ||'') end rescue report("user set failed : #{key} (#{$!})") else report("user set : #{key} => #{ENV[key]}") end end end rescue report("error in reading file '#{filename}'") end end def loadtree(tree) begin unless tree.empty? then if File.directory?(tree) then setuptex = File.join(tree,'setuptex.tmf') else setuptex = tree.dup end if FileTest.file?(setuptex) then report("tex tree definition: #{setuptex}") checkenvironment(File.dirname(setuptex)) loadfile(setuptex) else report("no setup file '#{setuptex}'") end end rescue # maybe tree is empty or boolean (no arg given) end end def loadenvironment(environment) begin unless environment.empty? then filename = if $path.empty? then environment else File.expand_path(File.join($path,environment)) end if FileTest.file?(filename) then report("environment : #{environment}") loadfile(filename) else report("no environment file '#{environment}'") end end rescue report("problem while loading '#{environment}'") end end def show_environment if $showenv then keys = ENV.keys.sort size = 0 keys.each do |k| size = k.size if k.size > size end report('') keys.each do |k| report("#{k.rjust(size)} => #{ENV[k]}") end report('') end end def execute(arguments) arguments = arguments.split(/\s+/) if arguments.class == String $directives = hashed(arguments) $help = $directives['help'] || false $batch = $directives['batch'] || false $filename = $directives['file'] || '' $program = $directives['program'] || 'context' $direct = $directives['direct'] || false $edit = $directives['edit'] || false $page = $directives['page'] || 1 $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 $autotree = if $directives['autotree'] then (ENV['TEXMFSTART_TREE'] || ENV['TEXMFSTARTTREE'] || '') else '' end $path = $directives['path'] || '' $tree = $directives['tree'] || $autotree || '' $environment = $directives['environment'] || '' $make = $directives['make'] || false $remove = $directives['remove'] || $directives['delete'] || false $unix = $directives['unix'] || false $windows = $directives['windows'] || $directives['mswin'] || false $stubpath = $directives['stubpath'] || '' $indirect = $directives['indirect'] || false $before = $directives['before'] || '' $after = $directives['after'] || '' $iftouched = $directives['iftouched'] || false $ifchanged = $directives['ifchanged'] || false $openoffice = $directives['oo'] || false $crossover = false if $directives['clear'] $showenv = $directives['showenv'] || false $verbose = true if $showenv $serve = $directives['serve'] || false $verbose = true if (ENV['_CTX_VERBOSE_'] =~ /(y|yes|t|true|on)/io) && ! $locate && ! $report set_applications($page) # private: $selfmerge = $directives['selfmerge'] || false $selfcleanup = $directives['selfclean'] || $directives['selfcleanup'] || false ENV['_CTX_VERBOSE_'] = 'yes' if $verbose if $openoffice then if ENV['OOPATH'] then if FileTest.directory?(ENV['OOPATH']) then report("using open office python") 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']}") else report("environment variable 'OOPATH' does not exist") end else report("environment variable 'OOPATH' is not set") end end if $selfmerge then output("ruby libraries are cleaned up") if SelfMerge::cleanup output("ruby libraries are merged") if SelfMerge::merge elsif $selfcleanup then output("ruby libraries are cleaned up") if SelfMerge::cleanup elsif $serve then if ENV['KPSEMETHOD'] && ENV['KPSEPORT'] then # # kpse_merge_done: require 'base/kpseremote' begin KpseRemote::start_server rescue end else usage puts("") puts("message : set 'KPSEMETHOD' and 'KPSEPORT' variables") end elsif $help || ! $filename || $filename.empty? then usage loadtree($tree) loadenvironment($environment) show_environment() elsif $batch && $filename && ! $filename.empty? then # todo, take commands from file and avoid multiple starts and checks else report("texmfstart version #{$version}") loadtree($tree) loadenvironment($environment) show_environment() if $make || $remove then if $filename == 'all' then makelist = $makelist else makelist = [$filename] end makelist.each do |filename| if $windows then make(filename,true,false,$remove) elsif $unix then make(filename,false,true,$remove) else make(filename,$mswindows,!$mswindows,$remove) end end elsif $browser && $filename =~ /^http\:\/\// then launch($filename) else begin process do if $direct || $filename =~ /^bin\:/ then direct($filename) elsif $edit && ! $editor.empty? then edit($filename) else # script: or no prefix command = find(shortpathname($filename),$program) if command then register("THREAD",File.dirname(File.expand_path(command))) run(command) else report('unable to locate program') end end end rescue report('fatal error in starting process') end end end end execute(ARGV) exit (if ($?.to_i rescue 0) > 0 then 1 else 0 end)