summaryrefslogtreecommitdiff
path: root/scripts/context/ruby/base/tex.rb
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/context/ruby/base/tex.rb')
-rw-r--r--scripts/context/ruby/base/tex.rb2299
1 files changed, 2299 insertions, 0 deletions
diff --git a/scripts/context/ruby/base/tex.rb b/scripts/context/ruby/base/tex.rb
new file mode 100644
index 000000000..84025693b
--- /dev/null
+++ b/scripts/context/ruby/base/tex.rb
@@ -0,0 +1,2299 @@
+# module : base/tex
+# copyright : PRAGMA Advanced Document Engineering
+# version : 2005
+# author : Hans Hagen
+#
+# project : ConTeXt / eXaMpLe
+# concept : Hans Hagen
+# info : j.hagen@xs4all.nl
+# www : www.pragma-ade.com
+
+# todo:
+#
+# - write systemcall for mpost to file so that it can be run faster
+# - use -8bit and -progname
+#
+
+# report ?
+
+require 'fileutils'
+
+require 'base/variables'
+require 'base/kpse'
+require 'base/system'
+require 'base/state'
+require 'base/pdf'
+require 'base/file'
+require 'base/ctx'
+require 'base/mp'
+
+class String
+
+ def standard?
+ begin
+ self == 'standard'
+ rescue
+ false
+ end
+ end
+
+end
+
+# class String
+ # def utf_bom?
+ # self.match(/^\357\273\277/o).length>0 rescue false
+ # end
+# end
+
+class Array
+
+ def standard?
+ begin
+ self.include?('standard')
+ rescue
+ false
+ end
+ end
+
+ def join_path
+ self.join(File::PATH_SEPARATOR)
+ end
+
+end
+
+class TEX
+
+ # The make-part of this class was made on a rainy day while listening
+ # to "10.000 clowns on a rainy day" by Jan Akkerman. Unfortunately the
+ # make method is not as swinging as this live cd.
+
+ include Variables
+
+ @@texengines = Hash.new
+ @@mpsengines = Hash.new
+ @@backends = Hash.new
+ @@mappaths = Hash.new
+ @@runoptions = Hash.new
+ @@tcxflag = Hash.new
+ @@draftoptions = Hash.new
+ @@synctexcoptions = Hash.new
+ @@texformats = Hash.new
+ @@mpsformats = Hash.new
+ @@prognames = Hash.new
+ @@texmakestr = Hash.new
+ @@texprocstr = Hash.new
+ @@mpsmakestr = Hash.new
+ @@mpsprocstr = Hash.new
+ @@texmethods = Hash.new
+ @@mpsmethods = Hash.new
+ @@pdftex = 'pdftex' # new default, pdfetex is gone
+ @@luafiles = "luafiles.tmp"
+ @@luatarget = "lua/context"
+
+ @@platformslash = if System.unix? then "\\\\" else "\\" end
+
+ ['tex','etex','pdftex','pdfetex','standard'] .each do |e| @@texengines[e] = 'pdftex' end
+ ['aleph','omega'] .each do |e| @@texengines[e] = 'aleph' end
+ ['xetex'] .each do |e| @@texengines[e] = 'xetex' end
+ ['petex'] .each do |e| @@texengines[e] = 'petex' end
+ ['luatex'] .each do |e| @@texengines[e] = 'luatex' end
+
+ ['metapost','mpost', 'standard'] .each do |e| @@mpsengines[e] = 'mpost' end
+
+ ['pdfetex','pdftex','pdf','pdftex','standard'] .each do |b| @@backends[b] = 'pdftex' end
+ ['dvipdfmx','dvipdfm','dpx','dpm'] .each do |b| @@backends[b] = 'dvipdfmx' end
+ ['xetex','xtx'] .each do |b| @@backends[b] = 'xetex' end
+ ['petex'] .each do |b| @@backends[b] = 'dvipdfmx' end
+ ['aleph'] .each do |b| @@backends[b] = 'dvipdfmx' end
+ ['dvips','ps','dvi'] .each do |b| @@backends[b] = 'dvips' end
+ ['dvipsone'] .each do |b| @@backends[b] = 'dvipsone' end
+ ['acrobat','adobe','distiller'] .each do |b| @@backends[b] = 'acrobat' end
+ ['xdv','xdv2pdf'] .each do |b| @@backends[b] = 'xdv2pdf' end
+
+ ['tex','standard'] .each do |b| @@mappaths[b] = 'dvips' end
+ ['pdftex','pdfetex'] .each do |b| @@mappaths[b] = 'pdftex' end
+ ['aleph','omega','xetex','petex'] .each do |b| @@mappaths[b] = 'dvipdfmx' end
+ ['dvipdfm', 'dvipdfmx', 'xdvipdfmx'] .each do |b| @@mappaths[b] = 'dvipdfmx' end
+ ['xdv','xdv2pdf'] .each do |b| @@mappaths[b] = 'dvips' end
+
+ # todo norwegian (no)
+
+ ['plain'] .each do |f| @@texformats[f] = 'plain' end
+ ['cont-en','en','english','context','standard'].each do |f| @@texformats[f] = 'cont-en' end
+ ['cont-nl','nl','dutch'] .each do |f| @@texformats[f] = 'cont-nl' end
+ ['cont-de','de','german'] .each do |f| @@texformats[f] = 'cont-de' end
+ ['cont-it','it','italian'] .each do |f| @@texformats[f] = 'cont-it' end
+ ['cont-fr','fr','french'] .each do |f| @@texformats[f] = 'cont-fr' end
+ ['cont-cs','cs','cont-cz','cz','czech'] .each do |f| @@texformats[f] = 'cont-cs' end
+ ['cont-ro','ro','romanian'] .each do |f| @@texformats[f] = 'cont-ro' end
+ ['cont-gb','gb','cont-uk','uk','british'] .each do |f| @@texformats[f] = 'cont-gb' end
+ ['cont-pe','pe','persian'] .each do |f| @@texformats[f] = 'cont-pe' end
+ ['cont-xp','xp','experimental'] .each do |f| @@texformats[f] = 'cont-xp' end
+ ['mptopdf'] .each do |f| @@texformats[f] = 'mptopdf' end
+
+ ['latex'] .each do |f| @@texformats[f] = 'latex.ltx' end
+
+ ['plain','mpost'] .each do |f| @@mpsformats[f] = 'mpost' end
+ ['metafun','context','standard'] .each do |f| @@mpsformats[f] = 'metafun' end
+
+ ['pdftex','pdfetex','aleph','omega','petex',
+ 'xetex','luatex'] .each do |p| @@prognames[p] = 'context' end
+ ['mpost'] .each do |p| @@prognames[p] = 'metafun' end
+ ['latex','pdflatex'] .each do |p| @@prognames[p] = 'latex' end
+
+ ['plain','default','standard','mptopdf'] .each do |f| @@texmethods[f] = 'plain' end
+ ['cont-en','cont-nl','cont-de','cont-it',
+ 'cont-fr','cont-cs','cont-ro','cont-gb',
+ 'cont-pe','cont-xp'] .each do |f| @@texmethods[f] = 'context' end
+ ['latex','pdflatex'] .each do |f| @@texmethods[f] = 'latex' end
+
+ ['plain','default','standard'] .each do |f| @@mpsmethods[f] = 'plain' end
+ ['metafun'] .each do |f| @@mpsmethods[f] = 'metafun' end
+
+ @@texmakestr['plain'] = @@platformslash + "dump"
+ @@mpsmakestr['plain'] = @@platformslash + "dump"
+
+ ['cont-en','cont-nl','cont-de','cont-it',
+ 'cont-fr','cont-cs','cont-ro','cont-gb',
+ 'cont-pe','cont-xp'] .each do |f| @@texprocstr[f] = @@platformslash + "emergencyend" end
+
+ @@runoptions['aleph'] = ['--8bit']
+ @@runoptions['luatex'] = ['--file-line-error']
+ @@runoptions['mpost'] = ['--8bit']
+ @@runoptions['pdfetex'] = ['--8bit'] # obsolete
+ @@runoptions['pdftex'] = ['--8bit'] # pdftex is now pdfetex
+ # @@runoptions['petex'] = []
+ @@runoptions['xetex'] = ['--8bit','-output-driver="xdvipdfmx -E -d 4 -V 5"']
+ @@draftoptions['pdftex'] = ['--draftmode']
+ @@synctexcoptions['pdftex'] = ['--synctex=1']
+ @@synctexcoptions['luatex'] = ['--synctex=1']
+ @@synctexcoptions['xetex'] = ['--synctex=1']
+
+ @@tcxflag['aleph'] = true
+ @@tcxflag['luatex'] = false
+ @@tcxflag['mpost'] = false
+ @@tcxflag['pdfetex'] = true
+ @@tcxflag['pdftex'] = true
+ @@tcxflag['petex'] = false
+ @@tcxflag['xetex'] = false
+
+ @@mainbooleanvars = [
+ 'batchmode', 'nonstopmode', 'fast', 'final',
+ 'paranoid', 'notparanoid', 'nobanner', 'once', 'allpatterns', 'draft',
+ 'nompmode', 'nomprun', 'automprun', 'combine',
+ 'nomapfiles', 'local',
+ 'arrange', 'noarrange',
+ 'forcexml', 'foxet',
+ 'alpha', 'beta', 'luatex',
+ 'mpyforce', 'forcempy',
+ 'forcetexutil', 'texutil',
+ 'globalfile', 'autopath',
+ 'purge', 'purgeall', 'keep', 'autopdf', 'xpdf', 'simplerun', 'verbose',
+ 'nooptionfile', 'nobackend', 'noctx', 'utfbom',
+ 'mkii','mkiv',
+ 'synctex',
+ ]
+ @@mainstringvars = [
+ 'modefile', 'result', 'suffix', 'response', 'path',
+ 'filters', 'usemodules', 'environments', 'separation', 'setuppath',
+ 'arguments', 'input', 'output', 'randomseed', 'modes', 'mode', 'filename',
+ 'ctxfile', 'printformat', 'paperformat', 'paperoffset',
+ 'timeout', 'passon'
+ ]
+ @@mainstandardvars = [
+ 'mainlanguage', 'bodyfont', 'language'
+ ]
+ @@mainknownvars = [
+ 'engine', 'distribution', 'texformats', 'mpsformats', 'progname', 'interface',
+ 'runs', 'backend'
+ ]
+
+ @@extrabooleanvars = []
+ @@extrastringvars = []
+
+ def booleanvars
+ [@@mainbooleanvars,@@extrabooleanvars].flatten.uniq
+ end
+ def stringvars
+ [@@mainstringvars,@@extrastringvars].flatten.uniq
+ end
+ def standardvars
+ [@@mainstandardvars].flatten.uniq
+ end
+ def knownvars
+ [@@mainknownvars].flatten.uniq
+ end
+ def allbooleanvars
+ [@@mainbooleanvars,@@extrabooleanvars].flatten.uniq
+ end
+ def allstringvars
+ [@@mainstringvars,@@extrastringvars,@@mainstandardvars,@@mainknownvars].flatten.uniq
+ end
+
+ def setextrastringvars(vars)
+ # @@extrastringvars << vars -- problems in 1.9
+ @@extrastringvars = [@@extrastringvars,vars].flatten
+ end
+ def setextrabooleanvars(vars)
+ # @@extrabooleanvars << vars -- problems in 1.9
+ @@extrabooleanvars = [@@extrabooleanvars,vars].flatten
+ end
+
+ # def jobvariables(names=nil)
+ # if [names ||[]].flatten.size == 0 then
+ # names = [allbooleanvars,allstringvars].flatten
+ # end
+ # data = Hash.new
+ # names.each do |name|
+ # if allbooleanvars.include?(name) then
+ # data[name] = if getvariable(name) then "yes" else "no" end
+ # else
+ # data[name] = getvariable(name)
+ # end
+ # end
+ # data
+ # end
+
+ # def setjobvariables(names=nil)
+ # assignments = Array.new
+ # jobvariables(names).each do |k,v|
+ # assignments << "#{k}=\{#{v}\}"
+ # end
+ # "\setvariables[exe][#{assignments.join(", ")}]"
+ # end
+
+ @@temprunfile = 'texexec'
+ @@temptexfile = 'texexec.tex'
+
+ def initialize(logger=nil)
+ if @logger = logger then
+ def report(str='')
+ @logger.report(str)
+ end
+ else
+ def report(str='')
+ puts(str)
+ end
+ end
+ @cleanups = Array.new
+ @variables = Hash.new
+ @startuptime = Time.now
+ # options
+ booleanvars.each do |k|
+ setvariable(k,false)
+ end
+ stringvars.each do |k|
+ setvariable(k,'')
+ end
+ standardvars.each do |k|
+ setvariable(k,'standard')
+ end
+ setvariable('distribution', Kpse.distribution)
+ setvariable('texformats', defaulttexformats)
+ setvariable('mpsformats', defaultmpsformats)
+ setvariable('progname', 'standard') # or ''
+ setvariable('interface', 'standard')
+ setvariable('engine', 'standard') # replaced by tex/mpsengine
+ setvariable('backend', 'pdftex')
+ setvariable('runs', '8')
+ setvariable('randomseed', rand(1440).to_s) # we want the same seed for one run
+ # files
+ setvariable('files', [])
+ # defaults
+ setvariable('texengine', 'standard')
+ setvariable('mpsengine', 'standard')
+ setvariable('backend', 'standard')
+ setvariable('error', '')
+ end
+
+ def error?
+ not getvariable('error').empty?
+ end
+
+ def runtime
+ Time.now - @startuptime
+ end
+
+ def reportruntime
+ report("runtime: #{runtime}")
+ end
+
+ def runcommand(something)
+ command = [something].flatten.join(' ')
+ report("running: #{command}") if getvariable('verbose')
+ system(command)
+ end
+
+ def inspect(name=nil)
+ if ! name || name.empty? then
+ name = [booleanvars,stringvars,standardvars,knownvars]
+ end
+ str = '' # allocate
+ [name].flatten.each do |n|
+ if str = getvariable(n) then
+ str = str.join(" ") if str.class == Array
+ unless (str.class == String) && str.empty? then
+ report("option '#{n}' is set to '#{str}'")
+ end
+ end
+ end
+ end
+
+ def tempfilename(suffix='')
+ @@temprunfile + if suffix.empty? then '' else ".#{suffix}" end
+ end
+
+ def cleanup
+ @cleanups.each do |name|
+ begin
+ File.delete(name) if FileTest.file?(name)
+ rescue
+ report("unable to delete #{name}")
+ end
+ end
+ end
+
+ def cleanuptemprunfiles
+ begin
+ Dir.glob("#{@@temprunfile}*").each do |name|
+ if File.file?(name) && (File.splitname(name)[1] !~ /(pdf|dvi)/o) then
+ File.delete(name) rescue false
+ end
+ end
+ rescue
+ end
+ ['mpgraph.mp'].each do |file|
+ (File.delete(file) if (FileTest.size?(file) rescue 10) < 10) rescue false
+ end
+ end
+
+ def backends() @@backends.keys.sort end
+
+ def texengines() @@texengines.keys.sort end
+ def mpsengines() @@mpsengines.keys.sort end
+ def texformats() @@texformats.keys.sort end
+ def mpsformats() @@mpsformats.keys.sort end
+
+ def defaulttexformats() ['en','nl','mptopdf'] end
+ def defaultmpsformats() ['metafun'] end
+
+ def texmakeextras(format) @@texmakestr[format] || '' end
+ def mpsmakeextras(format) @@mpsmakestr[format] || '' end
+ def texprocextras(format) @@texprocstr[format] || '' end
+ def mpsprocextras(format) @@mpsprocstr[format] || '' end
+
+ def texmethod(format) @@texmethods[str] || @@texmethods['standard'] end
+ def mpsmethod(format) @@mpsmethods[str] || @@mpsmethods['standard'] end
+
+ def runoptions(engine)
+ options = if getvariable('draft') then @@draftoptions[engine] else [] end
+ options = if getvariable('synctex') then @@synctexcoptions[engine] else [] end
+ begin
+ if str = getvariable('passon') then
+ options = [options,str.split(' ')].flatten
+ end
+ rescue
+ end
+ if @@runoptions.key?(engine) then
+ [options,@@runoptions[engine]].flatten.join(' ')
+ else
+ options.join(' ')
+ end
+ end
+
+ # private
+
+ def cleanuplater(name)
+ begin
+ @cleanups.push(File.expand_path(name))
+ rescue
+ @cleanups.push(name)
+ end
+ end
+
+ def openedfile(name)
+ begin
+ f = File.open(name,'w')
+ rescue
+ report("file '#{File.expand_path(name)}' cannot be opened for writing")
+ return nil
+ else
+ cleanuplater(name) if f
+ return f
+ end
+ end
+
+ def prefixed(format,engine)
+ # format
+ case engine
+ when /etex|pdftex|pdfetex|aleph|xetex|luatex/io then
+ "*#{format}"
+ else
+ format
+ end
+ end
+
+ def quoted(str)
+ if str =~ /^[^\"].* / then "\"#{str}\"" else str end
+ end
+
+ def getarrayvariable(str='')
+ str = getvariable(str)
+ if str.class == String then str.split(',') else str.flatten end
+ end
+
+ def validtexformat(str) validsomething(str,@@texformats,'tex') end
+ def validmpsformat(str) validsomething(str,@@mpsformats,'mp' ) end
+ def validtexengine(str) validsomething(str,@@texengines,'pdftex') end
+ def validmpsengine(str) validsomething(str,@@mpsengines,'mpost' ) end
+
+ def validtexmethod(str) [validsomething(str,@@texmethods)].flatten.first end
+ def validmpsmethod(str) [validsomething(str,@@mpsmethods)].flatten.first end
+
+ def validsomething(str,something,type=nil)
+ if str then
+ list = [str].flatten.collect do |s|
+ if something[s] then
+ something[s]
+ elsif type && s =~ /\.#{type}$/ then
+ s
+ else
+ nil
+ end
+ end .compact.uniq
+ if list.length>0 then
+ if str.class == String then list.first else list end
+ else
+ false
+ end
+ else
+ false
+ end
+ end
+
+ def validbackend(str)
+ if str && @@backends.key?(str) then
+ @@backends[str]
+ else
+ @@backends['standard']
+ end
+ end
+
+ def validprogname(str)
+ if str then
+ [str].flatten.each do |s|
+ s = s.sub(/\.\S*/,"")
+ return @@prognames[s] if @@prognames.key?(s)
+ end
+ return str[0].sub(/\.\S*/,"")
+ else
+ return nil
+ end
+ end
+
+ # we no longer support the & syntax
+
+ def formatflag(engine=nil,format=nil)
+ case getvariable('distribution')
+ when 'standard' then prefix = "--fmt"
+ when /web2c/io then prefix = web2cformatflag(engine)
+ when /miktex/io then prefix = "--undump"
+ else return ""
+ end
+ if format then
+ "#{prefix}=#{format.sub(/\.\S+$/,"")}"
+ else
+ prefix
+ end
+ end
+
+ def web2cformatflag(engine=nil)
+ # funny that we've standardized on the fmt suffix (at the cost of
+ # upward compatibility problems) but stuck to the bas/mem/fmt flags
+ if engine then
+ case validmpsengine(engine)
+ when /mpost/ then "-mem"
+ when /mfont/ then "-bas"
+ else "-fmt"
+ end
+ else
+ "-fmt"
+ end
+ end
+
+ def prognameflag(progname=nil)
+ case getvariable('distribution')
+ when 'standard' then prefix = "-progname"
+ when /web2c/io then prefix = "-progname"
+ when /miktex/io then prefix = "-alias"
+ else return ""
+ end
+ if progname and not progname.empty? then
+ "#{prefix}=#{progname}"
+ else
+ prefix
+ end
+ end
+
+ def iniflag() # should go to kpse and kpse should become texenv
+ if Kpse.miktex? then
+ "-initialize"
+ else
+ "--ini"
+ end
+ end
+ def tcxflag(engine)
+ if @@tcxflag[engine] then
+ file = "natural.tcx"
+ if Kpse.miktex? then
+ "-tcx=#{file}"
+ else
+ "-translate-file=#{file}"
+ end
+ else
+ ""
+ end
+ end
+
+ def filestate(file)
+ File.mtime(file).strftime("%d/%m/%Y %H:%M:%S")
+ end
+
+ # will go to context/process context/listing etc
+
+ def contextversion # ook elders gebruiken
+ filename = Kpse.found('context.tex')
+ version = 'unknown'
+ begin
+ if FileTest.file?(filename) && IO.read(filename).match(/\\contextversion\{(\d+\.\d+\.\d+.*?)\}/) then
+ version = $1
+ end
+ rescue
+ end
+ return version
+ end
+
+ def cleanupluafiles
+ File.delete(@@luafiles) rescue false
+ end
+
+ def compileluafiles
+ begin
+ Dir.glob("lua/context/*.luc").each do |luc|
+ File.delete(luc) rescue false
+ end
+ rescue
+ end
+ if data = (IO.readlines(@@luafiles) rescue nil) then
+ report("compiling lua files (using #{File.expand_path(@@luafiles)})")
+ begin
+ FileUtils.makedirs(@@luatarget) rescue false
+ data.each do |line|
+ luafile = line.chomp
+ lucfile = File.basename(luafile).gsub(/\..*?$/,'') + ".luc"
+ if runcommand(["luac","-s","-o",quoted(File.join(Dir.getwd,@@luatarget,lucfile)),quoted(luafile)]) then
+ report("#{File.basename(luafile)} converted to #{File.basename(lucfile)}")
+ else
+ report("#{File.basename(luafile)} not converted to #{File.basename(lucfile)}")
+ end
+ end
+ rescue
+ report("fatal error in compilation")
+ end
+ else
+ report("no lua compilations needed")
+ end
+ File.delete(@@luafiles) rescue false
+ end
+
+ # we need engine methods
+
+ def makeformats
+
+ checktestversion
+
+ report("using search method '#{Kpse.searchmethod}'")
+ if getvariable('fast') then
+ report('using existing database')
+ else
+ report('updating file database')
+ Kpse.update # obsolete here
+ if getvariable('luatex') then
+ begin
+ runcommand(["luatools","--generate","--verbose"])
+ rescue
+ report("run 'luatools --generate' manualy")
+ exit
+ end
+ end
+ end
+ # goody
+ if getvariable('texformats') == 'standard' then
+ setvariable('texformats',[getvariable('interface')]) unless getvariable('interface').empty?
+ end
+ # prepare
+ texformats = validtexformat(getarrayvariable('texformats'))
+ mpsformats = validmpsformat(getarrayvariable('mpsformats'))
+ texengine = validtexengine(getvariable('texengine'))
+ mpsengine = validmpsengine(getvariable('mpsengine'))
+ # save current path
+ savedpath = Dir.getwd
+ # generate tex formats
+ unless texformats || mpsformats then
+ report('provide valid format (name.tex, name.mp, ...) or format id (metafun, en, nl, ...)')
+ setvariable('error','no format specified')
+ end
+ if texformats && texengine then
+ report("using tex engine #{texengine}")
+ texformatpath = if getvariable('local') then '.' else Kpse.formatpath(texengine,true) end
+ # can be empty, to do
+ report("using tex format path #{texformatpath}")
+ Dir.chdir(texformatpath) rescue false
+ if FileTest.writable?(texformatpath) then
+ # from now on we no longer support this; we load
+ # all patterns and if someone wants another
+ # interface language ... cook up a fmt or usr file
+ #
+ # if texformats.length > 0 then
+ # makeuserfile
+ # makeresponsefile
+ # end
+ if texengine == 'luatex' then
+ cleanupluafiles
+ texformats.each do |texformat|
+ report("generating tex format #{texformat}")
+ flags = ['--ini','--compile']
+ flags << '--verbose' if getvariable('verbose')
+ flags << '--mkii' if getvariable('mkii')
+ run_luatools("#{flags.join(" ")} #{texformat}")
+ end
+ compileluafiles
+ else
+ texformats.each do |texformat|
+ report("generating tex format #{texformat}")
+ progname = validprogname([getvariable('progname'),texformat,texengine])
+ runcommand([quoted(texengine),prognameflag(progname),iniflag,tcxflag(texengine),prefixed(texformat,texengine),texmakeextras(texformat)])
+ end
+ end
+ else
+ report("unable to make format due to lack of permissions")
+ texformatpath = ''
+ setvariable('error','no permissions to write')
+ end
+ if not mpsformats then
+ # we want metafun to be in sync
+ setvariable('mpsformats',defaultmpsformats)
+ mpsformats = validmpsformat(getarrayvariable('mpsformats'))
+ end
+ else
+ texformatpath = ''
+ end
+ # generate mps formats
+ if mpsformats && mpsengine then
+ report("using mp engine #{mpsengine}")
+ mpsformatpath = if getvariable('local') then '.' else Kpse.formatpath(mpsengine,false) end
+ report("using mps format path #{mpsformatpath}")
+ Dir.chdir(mpsformatpath) rescue false
+ if FileTest.writable?(mpsformatpath) then
+ mpsformats.each do |mpsformat|
+ report("generating mps format #{mpsformat}")
+ progname = validprogname([getvariable('progname'),mpsformat,mpsengine])
+ # if not runcommand([quoted(mpsengine),prognameflag(progname),iniflag,tcxflag(mpsengine),runoptions(mpsengine),mpsformat,mpsmakeextras(mpsformat)]) then
+ if not runcommand([quoted(mpsengine),prognameflag(progname),iniflag,runoptions(mpsengine),mpsformat,mpsmakeextras(mpsformat)]) then
+ setvariable('error','no format made')
+ end
+ end
+ else
+ report("unable to make format due to lack of permissions")
+ mpsformatpath = ''
+ setvariable('error','file permission problem')
+ end
+ else
+ mpsformatpath = ''
+ end
+ # check for problems
+ report("")
+ report("tex engine path: #{texformatpath}") unless texformatpath.empty?
+ report("mps engine path: #{mpsformatpath}") unless mpsformatpath.empty?
+ report("")
+ [['fmt','tex'],['mem','mps']].each do |f|
+ [[texformatpath,'global'],[mpsformatpath,'global'],[savedpath,'current']].each do |p|
+ begin
+ Dir.chdir(p[0])
+ rescue
+ else
+ Dir.glob("*.#{f[0]}").each do |file|
+ report("#{f[1]}: #{filestate(file)} > #{File.expand_path(file)} (#{File.size(file)})")
+ end
+ end
+ end
+ end
+ begin
+ lucdir = File.join(texformatpath,@@luatarget)
+ Dir.chdir(lucdir)
+ rescue
+ else
+ Dir.glob("*.luc").each do |file|
+ report("luc: #{filestate(file)} > #{File.expand_path(file)} (#{File.size(file)})")
+ end
+ end
+ # to be sure, go back to current path
+ begin
+ Dir.chdir(savedpath)
+ rescue
+ end
+ # finalize
+ cleanup
+ report("")
+ reportruntime
+ end
+
+ def checkcontext
+
+ # todo : report texmf.cnf en problems
+
+ # basics
+ report("current distribution: #{Kpse.distribution}")
+ report("context source date: #{contextversion}")
+ formatpaths = Kpse.formatpaths
+ globpattern = "**/{#{formatpaths.join(',')}}/*/*.{fmt,efmt,ofmt,xfmt,mem}"
+ report("format path: #{formatpaths.join(' ')}")
+ # utilities
+ report('start of analysis')
+ results = Array.new
+ # ['texexec','texutil','ctxtools'].each do |program|
+ ['texexec'].each do |program|
+ result = `texmfstart #{program} --help`
+ result.sub!(/.*?(#{program}[^\n]+)\n.*/mi) do $1 end
+ results.push("#{result}")
+ end
+ # formats
+ cleanuptemprunfiles
+ if formats = Dir.glob(globpattern) then
+ formats.sort.each do |name|
+ cleanuptemprunfiles
+ if f = open(tempfilename('tex'),'w') then
+ # kind of aleph-run-out-of-par safe
+ f << "\\starttext\n"
+ f << " \\relax test \\relax\n"
+ f << "\\stoptext\n"
+ f << "\\endinput\n"
+ f.close
+ if FileTest.file?(tempfilename('tex')) then
+ format = File.basename(name)
+ engine = if name =~ /(pdftex|pdfetex|aleph|xetex|luatex)[\/\\]#{format}/ then $1 else '' end
+ if engine.empty? then
+ engineflag = ""
+ else
+ engineflag = "--engine=#{$1}"
+ end
+ case format
+ when /cont\-([a-z]+)/ then
+ interface = $1.sub(/cont\-/,'')
+ results.push('')
+ results.push("testing interface #{interface}")
+ flags = ['--noctx','--process','--batch','--once',"--interface=#{interface}",engineflag]
+ # result = Kpse.pipescript('texexec',tempfilename,flags)
+ result = runtexexec([tempfilename], flags, 1)
+ if FileTest.file?("#{@@temprunfile}.log") then
+ logdata = IO.read("#{@@temprunfile}.log")
+ if logdata =~ /^\s*This is (.*?)[\s\,]+(.*?)$/moi then
+ if validtexengine($1.downcase) then
+ results.push("#{$1} #{$2.gsub(/\(format.*$/,'')}".strip)
+ end
+ end
+ if logdata =~ /^\s*(ConTeXt)\s+(.*int:\s+[a-z]+.*?)\s*$/moi then
+ results.push("#{$1} #{$2}".gsub(/\s+/,' ').strip)
+ end
+ else
+ results.push("format #{format} does not work")
+ end
+ when /metafun/ then
+ # todo
+ when /mptopdf/ then
+ # todo
+ end
+ else
+ results.push("error in creating #{tempfilename('tex')}")
+ end
+ end
+ cleanuptemprunfiles
+ end
+ end
+ report('end of analysis')
+ report
+ results.each do |line|
+ report(line)
+ end
+ cleanuptemprunfiles
+
+ end
+
+ private
+
+ def makeuserfile # not used in luatex (yet)
+ language = getvariable('language')
+ mainlanguage = getvariable('mainlanguage')
+ bodyfont = getvariable('bodyfont')
+ if f = openedfile("cont-fmt.tex") then
+ f << "\\unprotect\n"
+ case language
+ when 'all' then
+ f << "\\preloadallpatterns\n"
+ when '' then
+ f << "% no language presets\n"
+ when 'standard'
+ f << "% using defaults\n"
+ else
+ languages = language.split(',')
+ languages.each do |l|
+ f << "\\installlanguage[\\s!#{l}][\\c!state=\\v!start]\n"
+ end
+ mainlanguage = languages.first
+ end
+ unless mainlanguage == 'standard' then
+ f << "\\setupcurrentlanguage[\\s!#{mainlanguage}]\n";
+ end
+ unless bodyfont == 'standard' then
+ # ~ will become obsolete when lmr is used
+ f << "\\definetypescriptsynonym[cmr][#{bodyfont}]"
+ # ~ is already obsolete for some years now
+ f << "\\definefilesynonym[font-cmr][font-#{bodyfont}]\n"
+ end
+ f << "\\protect\n"
+ f << "\\endinput\n"
+ f.close
+ end
+ end
+
+ def makeresponsefile
+ interface = getvariable('interface')
+ if f = openedfile("mult-def.tex") then
+ case interface
+ when 'standard' then
+ f << "% using default response interface"
+ else
+ f << "\\def\\currentresponses\{#{interface}\}\n"
+ end
+ f << "\\endinput\n"
+ f.close
+ end
+ end
+
+ private # will become baee/context
+
+ @@preamblekeys = [
+ ['tex','texengine'],
+ ['engine','texengine'],
+ ['program','texengine'],
+ ['translate','tcxfilter'],
+ ['tcx','tcxfilter'],
+ ['output','backend'],
+ ['mode','mode'],
+ ['ctx','ctxfile'],
+ ['version','contextversion'],
+ ['format','texformats'],
+ ['interface','texformats'],
+ ]
+
+ @@re_utf_bom = /^\357\273\277/o
+
+ def scantexpreamble(filename)
+ begin
+ if FileTest.file?(filename) and tex = File.open(filename,'rb') then
+ bomdone = false
+ while str = tex.gets and str.chomp! do
+ unless bomdone then
+ if str.sub!(@@re_utf_bom, '')
+ report("utf mode forced (bom found)")
+ setvariable('utfbom',true)
+ end
+ bomdone = true
+ end
+ if str =~ /^\%\s*(.*)/o then
+ # we only accept lines with key=value pairs
+ vars, ok = Hash.new, true
+ $1.split(/\s+/o).each do |s|
+ k, v = s.split('=')
+ if k && v then
+ vars[k] = v
+ else
+ ok = false
+ break
+ end
+ end
+ if ok then
+ # we have a valid line
+
+ @@preamblekeys.each do |v|
+ setvariable(v[1],vars[v[0]]) if vars.key?(v[0]) && vars[v[0]]
+ end
+
+if getvariable('given.backend') == "standard" or getvariable('given.backend') == "" then
+ setvariable('backend',@@backends[getvariable('texengine')] || 'standard')
+end
+ break
+ end
+ else
+ break
+ end
+ end
+ tex.close
+ end
+ rescue
+ # well, let's not worry too much
+ end
+ end
+
+ def scantexcontent(filename)
+ if FileTest.file?(filename) and tex = File.open(filename,'rb') then
+ while str = tex.gets do
+ case str.chomp
+ when /^\%/o then
+ # next
+ # when /\\(starttekst|stoptekst|startonderdeel|startdocument|startoverzicht)/o then
+ when /\\(starttekst|stoptekst|startonderdeel|startoverzicht)/o then
+ setvariable('texformats','nl') ; break
+ when /\\(stelle|verwende|umgebung|benutze)/o then
+ setvariable('texformats','de') ; break
+ when /\\(stel|gebruik|omgeving)/o then
+ setvariable('texformats','nl') ; break
+ when /\\(use|setup|environment)/o then
+ setvariable('texformats','en') ; break
+ when /\\(usa|imposta|ambiente)/o then
+ setvariable('texformats','it') ; break
+ when /(height|width|style)=/o then
+ setvariable('texformats','en') ; break
+ when /(hoehe|breite|schrift)=/o then
+ setvariable('texformats','de') ; break
+ when /(hoogte|breedte|letter)=/o then
+ setvariable('texformats','nl') ; break
+ when /(altezza|ampiezza|stile)=/o then
+ setvariable('texformats','it') ; break
+ when /externfiguur/o then
+ setvariable('texformats','nl') ; break
+ when /externalfigure/o then
+ setvariable('texformats','en') ; break
+ when /externeabbildung/o then
+ setvariable('texformats','de') ; break
+ when /figuraesterna/o then
+ setvariable('texformats','it') ; break
+ end
+ end
+ tex.close
+ end
+
+ end
+
+ private # will become base/context
+
+ def pushresult(filename,resultname)
+ fname = File.unsuffixed(filename)
+ rname = File.unsuffixed(resultname)
+ if ! rname.empty? && (rname != fname) then
+ report("outputfile #{rname}")
+ ['tuo','tuc','log','dvi','pdf'].each do |s|
+ File.silentrename(File.suffixed(fname,s),File.suffixed('texexec',s))
+ end
+ ['tuo','tuc'].each do |s|
+ File.silentrename(File.suffixed(rname,s),File.suffixed(fname,s)) if FileTest.file?(File.suffixed(rname,s))
+ end
+ end
+ end
+
+ def popresult(filename,resultname)
+ fname = File.unsuffixed(filename)
+ rname = File.unsuffixed(resultname)
+ if ! rname.empty? && (rname != fname) then
+ report("renaming #{fname} to #{rname}")
+ ['tuo','tuc','log','dvi','pdf'].each do |s|
+ File.silentrename(File.suffixed(fname,s),File.suffixed(rname,s))
+ end
+ report("restoring #{fname}")
+ unless $fname == 'texexec' then
+ ['tuo','tuc','log','dvi','pdf'].each do |s|
+ File.silentrename(File.suffixed('texexec',s),File.suffixed(fname,s))
+ end
+ end
+ end
+ end
+
+ def makestubfile(rawname,rawbase,forcexml=false)
+ if tmp = openedfile(File.suffixed(rawbase,'run')) then
+ tmp << "\\starttext\n"
+ if forcexml then
+ # tmp << checkxmlfile(rawname)
+ if getvariable('mkiv') then
+ tmp << "\\xmlprocess{\\xmldocument}{#{rawname}}{}\n"
+ else
+ tmp << "\\processXMLfilegrouped{#{rawname}}\n"
+ end
+ else
+ tmp << "\\processfile{#{rawname}}\n"
+ end
+ tmp << "\\stoptext\n"
+ tmp.close
+ return "run"
+ else
+ return File.splitname(rawname)[1]
+ end
+ end
+
+ # def checkxmlfile(rawname)
+ # tmp = ''
+ # if FileTest.file?(rawname) && (xml = File.open(rawname)) then
+ # xml.each do |line|
+ # case line
+ # when /<\?context\-directive\s+(\S+)\s+(\S+)\s+(\S+)\s*(.*?)\s*\?>/o then
+ # category, key, value, rest = $1, $2, $3, $4
+ # case category
+ # when 'job' then
+ # case key
+ # when 'control' then
+ # setvariable(value,if rest.empty? then true else rest end)
+ # when 'mode', 'modes' then
+ # tmp << "\\enablemode[#{value}]\n"
+ # when 'stylefile', 'environment' then
+ # tmp << "\\environment #{value}\n"
+ # when 'module' then
+ # tmp << "\\usemodule[#{value}]\n"
+ # when 'interface' then
+ # contextinterface = value
+ # when 'ctxfile' then
+ # setvariable('ctxfile', value)
+ # report("using source driven ctxfile #{value}")
+ # end
+ # end
+ # when /<[a-z]+/io then # beware of order, first pi test
+ # break
+ # end
+ # end
+ # xml.close
+ # end
+ # return tmp
+ # end
+
+ def extendvariable(name,value)
+ set = getvariable(name).split(',')
+ set << value
+ str = set.uniq.join(',')
+ setvariable(name,str)
+ end
+
+ def checkxmlfile(rawname)
+ if FileTest.file?(rawname) && (xml = File.open(rawname,'rb')) then
+ xml.each do |line|
+ case line
+ when /<\?context\-directive\s+(\S+)\s+(\S+)\s+(\S+)\s*(.*?)\s*\?>/o then
+ category, key, value, rest = $1, $2, $3, $4
+ case category
+ when 'job' then
+ case key
+ when 'control' then
+ setvariable(value,if rest.empty? then true else rest end)
+ when /^(mode)(s|)$/ then
+ extendvariable('modes',value)
+ when /^(stylefile|environment)(s|)$/ then
+ extendvariable('environments',value)
+ when /^(use|)(module)(s|)$/ then
+ extendvariable('usemodules',value)
+ when /^(filter)(s|)$/ then
+ extendvariable('filters',value)
+ when 'interface' then
+ contextinterface = value
+ when 'ctxfile' then
+ setvariable('ctxfile', value)
+ report("using source driven ctxfile #{value}")
+ end
+ end
+ when /<[a-z]+/io then # beware of order, first pi test
+ break
+ end
+ end
+ xml.close
+ end
+ end
+
+end
+
+class TEX
+
+ def timedrun(delay, &block)
+ delay = delay.to_i rescue 0
+ if delay > 0 then
+ begin
+ report("job started with timeout '#{delay}'")
+ timeout(delay) do
+ yield block
+ end
+ rescue TimeoutError
+ report("job aborted due to timeout '#{delay}'")
+ setvariable('error','timeout')
+ rescue
+ report("job aborted due to error")
+ setvariable('error','fatal error')
+ else
+ report("job finished within timeout '#{delay}'")
+ end
+ else
+ yield block
+ end
+ end
+
+ def processtex # much to do: mp, xml, runs etc
+ setvariable('texformats',[getvariable('interface')]) unless getvariable('interface').empty?
+ getarrayvariable('files').each do |filename|
+ setvariable('filename',filename)
+ report("processing document '#{filename}'")
+ timedrun(getvariable('timeout')) do
+ processfile
+ end
+ end
+ reportruntime
+ end
+
+ def processmptex
+ getarrayvariable('files').each do |filename|
+ setvariable('filename',filename)
+ report("processing graphic '#{filename}'")
+ runtexmp(filename)
+ end
+ reportruntime
+ end
+
+ private
+
+ def load_map_files(filename) # tui basename
+ # c \usedmapfile{=}{lm-texnansi}
+ begin
+ str = ""
+ IO.read(filename).scan(/^c\s+\\usedmapfile\{(.*?)\}\{(.*?)\}\s*$/o) do
+ str << "\\loadmapfile[#{$2}.map]\n"
+ end
+ rescue
+ return ""
+ else
+ return str
+ end
+ end
+
+ public
+
+ # def run_luatools(args)
+ # dirty trick: we know that the lua path is relative to the ruby path; of course this
+ # will not work well when stubs are used
+ # [(ENV["_CTX_K_S_texexec_"] or ENV["_CTX_K_S_THREAD_"] or ENV["TEXMFSTART.THREAD"]), File.dirname($0)].each do |path|
+ # if path then
+ # script = "#{path}/../lua/luatools.lua"
+ # if FileTest.file?(script) then
+ # return runcommand("luatex --luaonly #{script} #{args}")
+ # end
+ # end
+ # end
+ # return runcommand("texmfstart luatools #{args}")
+ # end
+
+ def run_luatools(args)
+ return runcommand("luatools #{args}")
+ end
+
+ def processmpgraphic
+ getarrayvariable('files').each do |filename|
+ setvariable('filename',filename)
+ report("processing graphic '#{filename}'")
+ runtexmp(filename,'',false) # no purge
+ mapspecs = load_map_files(File.suffixed(filename,'temp','tui'))
+ unless getvariable('keep') then
+ # not enough: purge_mpx_files(filename)
+ Dir.glob(File.suffixed(filename,'temp*','*')).each do |fname|
+ File.delete(fname) unless File.basename(filename) == File.basename(fname)
+ end
+ end
+ begin
+ data = IO.read(File.suffixed(filename,'log'))
+ basename = filename.sub(/\.mp$/, '')
+ if data =~ /output files* written\:\s*(.*)$/moi then
+ files, number, range, list = $1.split(/\s+/), 0, false, []
+ files.each do |fname|
+ if fname =~ /^.*\.(\d+)$/ then
+ if range then
+ (number+1 .. $1.to_i).each do |i|
+ list << i
+ end
+ range = false
+ else
+ number = $1.to_i
+ list << number
+ end
+ elsif fname =~ /\.\./ then
+ range = true
+ else
+ range = false
+ next
+ end
+ end
+ begin
+ if getvariable('combine') then
+ fullname = "#{basename}.#{number}"
+ File.open("texexec.tex",'w') do |f|
+ f << "\\setupoutput[pdftex]\n"
+ f << "\\setupcolors[state=start]\n"
+ f << mapspecs
+ f << "\\starttext\n"
+ list.each do |number|
+ f << "\\startTEXpage\n"
+ f << "\\convertMPtoPDF{#{fullname}}{1}{1}"
+ f << "\\stopTEXpage\n"
+ end
+ f << "\\stoptext\n"
+ end
+ report("converting graphic '#{fullname}'")
+ runtex("texexec.tex")
+ pdffile = File.suffixed(basename,'pdf')
+ File.silentrename("texexec.pdf",pdffile)
+ report ("#{basename}.* converted to #{pdffile}")
+ else
+ list.each do |number|
+ begin
+ fullname = "#{basename}.#{number}"
+ File.open("texexec.tex",'w') do |f|
+ f << "\\setupoutput[pdftex]\n"
+ f << "\\setupcolors[state=start]\n"
+ f << mapspecs
+ f << "\\starttext\n"
+ f << "\\startTEXpage\n"
+ f << "\\convertMPtoPDF{#{fullname}}{1}{1}"
+ f << "\\stopTEXpage\n"
+ f << "\\stoptext\n"
+ end
+ report("converting graphic '#{fullname}'")
+ runtex("texexec.tex")
+ if files.length>1 then
+ pdffile = File.suffixed(basename,number.to_s,'pdf')
+ else
+ pdffile = File.suffixed(basename,'pdf')
+ end
+ File.silentrename("texexec.pdf",pdffile)
+ report ("#{fullname} converted to #{pdffile}")
+ end
+ end
+ end
+ rescue
+ report ("error when converting #{fullname} (#{$!})")
+ end
+ end
+ rescue
+ report("error in converting #{filename}")
+ end
+ end
+ reportruntime
+ end
+
+ def processmpstatic
+ if filename = getvariable('filename') then
+ filename += ".mp" unless filename =~ /\..+?$/
+ if FileTest.file?(filename) then
+ begin
+ data = IO.read(filename)
+ File.open("texexec.tex",'w') do |f|
+ f << "\\setupoutput[pdftex]\n"
+ f << "\\setupcolors[state=start]\n"
+ data.sub!(/^%mpenvironment\:\s*(.*?)$/moi) do
+ f << $1
+ "\n"
+ end
+ f << "\\starttext\n"
+ f << "\\startMPpage\n"
+ f << data.gsub(/end\.*\s*$/m, '') # a bit of a hack
+ f << "\\stopMPpage\n"
+ f << "\\stoptext\n"
+ end
+ report("converting static '#{filename}'")
+ runtex("texexec.tex")
+ pdffile = File.suffixed(filename,'pdf')
+ File.silentrename("texexec.pdf",pdffile)
+ report ("#{filename} converted to #{pdffile}")
+ rescue
+ report("error in converting #{filename} (#{$!}")
+ end
+ end
+ end
+ reportruntime
+ end
+
+ def processmpxtex
+ getarrayvariable('files').each do |filename|
+ setvariable('filename',filename)
+ report("processing text of graphic '#{filename}'")
+ processmpx(filename,false,true,true)
+ end
+ reportruntime
+ end
+
+ def deleteoptionfile(rawname)
+ ['top','top.keep'].each do |suffix|
+ begin
+ File.delete(File.suffixed(rawname,suffix))
+ rescue
+ end
+ end
+ end
+
+ def makeoptionfile(rawname, jobname, jobsuffix, finalrun, fastdisabled, kindofrun, currentrun=1)
+ begin
+ # jobsuffix = orisuffix
+ if topname = File.suffixed(rawname,'top') and opt = File.open(topname,'w') then
+ report("writing option file #{topname}")
+ # local handies
+ opt << "\% #{topname}\n"
+ opt << "\\unprotect\n"
+ #
+ # feedback and basic control
+ #
+ if getvariable('batchmode') then
+ opt << "\\batchmode\n"
+ end
+ if getvariable('nonstopmode') then
+ opt << "\\nonstopmode\n"
+ end
+ if getvariable('paranoid') then
+ opt << "\\def\\maxreadlevel{1}\n"
+ end
+ if getvariable('nomapfiles') then
+ opt << "\\disablemapfiles\n"
+ end
+ if getvariable('nompmode') || getvariable('nomprun') || getvariable('automprun') then
+ opt << "\\runMPgraphicsfalse\n"
+ end
+ if getvariable('utfbom') then
+ opt << "\\enableregime[utf]"
+ end
+ progname = validprogname(['metafun']) # [getvariable('progname'),mpsformat,mpsengine]
+ opt << "\\def\\MPOSTformatswitch\{#{prognameflag(progname)} #{formatflag('mpost')}=\}\n"
+ #
+ # process info
+ #
+ opt << "\\setupsystem[\\c!n=#{kindofrun},\\c!m=#{currentrun}]\n"
+ if (str = File.unixfied(getvariable('modefile'))) && ! str.empty? then
+ opt << "\\readlocfile{#{str}}{}{}\n"
+ end
+ if (str = File.unixfied(getvariable('result'))) && ! str.empty? then
+ opt << "\\setupsystem[file=#{str}]\n"
+ elsif (str = getvariable('suffix')) && ! str.empty? then
+ opt << "\\setupsystem[file=#{jobname}.#{str}]\n"
+ end
+ opt << "\\setupsystem[\\c!method=2]\n" # 1=oldtexexec 2=newtexexec (obsolete)
+ opt << "\\setupsystem[\\c!type=#{Tool.ruby_platform()}]\n"
+ if (str = File.unixfied(getvariable('path'))) && ! str.empty? then
+ opt << "\\usepath[#{str}]\n" unless str.empty?
+ end
+ if (str = getvariable('mainlanguage').downcase) && ! str.empty? && ! str.standard? then
+ opt << "\\setuplanguage[#{str}]\n"
+ end
+ if (str = getvariable('arguments')) && ! str.empty? then
+ opt << "\\setupenv[#{str}]\n"
+ end
+ if (str = getvariable('setuppath')) && ! str.empty? then
+ opt << "\\setupsystem[\\c!directory=\{#{str}\}]\n"
+ end
+ if (str = getvariable('randomseed')) && ! str.empty? then
+ report("using randomseed #{str}")
+ opt << "\\setupsystem[\\c!random=#{str}]\n"
+ end
+ if (str = getvariable('input')) && ! str.empty? then
+ opt << "\\setupsystem[inputfile=#{str}]\n"
+ else
+ opt << "\\setupsystem[inputfile=#{rawname}]\n"
+ end
+ #
+ # modes
+ #
+ # we handle both "--mode" and "--modes", else "--mode" is mapped onto "--modefile"
+ if (str = getvariable('modes')) && ! str.empty? then
+ opt << "\\enablemode[#{str}]\n"
+ end
+ if (str = getvariable('mode')) && ! str.empty? then
+ opt << "\\enablemode[#{str}]\n"
+ end
+ #
+ # options
+ #
+ opt << "\\startsetups *runtime:options\n"
+ if str = validbackend(getvariable('backend')) then
+ opt << "\\setupoutput[#{str}]\n"
+ elsif str = validbackend(getvariable('output')) then
+ opt << "\\setupoutput[#{str}]\n"
+ end
+ if getvariable('color') then
+ opt << "\\setupcolors[\\c!state=\\v!start]\n"
+ end
+ if (str = getvariable('separation')) && ! str.empty? then
+ opt << "\\setupcolors[\\c!split=#{str}]\n"
+ end
+ if (str = getvariable('paperformat')) && ! str.empty? && ! str.standard? then
+ if str =~ /^([a-z]+\d+)([a-z]+\d+)$/io then # A5A4 A4A3 A2A1 ...
+ opt << "\\setuppapersize[#{$1.upcase}][#{$2.upcase}]\n"
+ else # ...*...
+ pf = str.upcase.split(/[x\*]/o)
+ pf << pf[0] if pf.size == 1
+ opt << "\\setuppapersize[#{pf[0]}][#{pf[1]}]\n"
+ end
+ end
+ if (str = getvariable('background')) && ! str.empty? then
+ opt << "\\defineoverlay[whatever][{\\externalfigure[#{str}][\\c!factor=\\v!max]}]\n"
+ opt << "\\setupbackgrounds[\\v!page][\\c!background=whatever]\n"
+ end
+ if getvariable('centerpage') then
+ opt << "\\setuplayout[\\c!location=\\v!middle,\\c!marking=\\v!on]\n"
+ end
+ if getvariable('noarrange') then
+ opt << "\\setuparranging[\\v!disable]\n"
+ elsif getvariable('arrange') then
+ arrangement = Array.new
+ if finalrun then
+ arrangement << "\\v!doublesided" unless getvariable('noduplex')
+ case getvariable('printformat')
+ when '' then arrangement << "\\v!normal"
+ when /.*up/oi then arrangement << ["2UP","\\v!rotated"]
+ when /.*down/oi then arrangement << ["2DOWN","\\v!rotated"]
+ when /.*side/oi then arrangement << ["2SIDE","\\v!rotated"]
+ end
+ else
+ arrangement << "\\v!disable"
+ end
+ opt << "\\setuparranging[#{arrangement.flatten.join(',')}]\n" if arrangement.size > 0
+ end
+ if (str = getvariable('pages')) && ! str.empty? then
+ if str.downcase == 'odd' then
+ opt << "\\chardef\\whichpagetoshipout=1\n"
+ elsif str.downcase == 'even' then
+ opt << "\\chardef\\whichpagetoshipout=2\n"
+ else
+ pagelist = Array.new
+ str.split(/\,/).each do |page|
+ pagerange = page.split(/\D+/o)
+ if pagerange.size > 1 then
+ pagerange.first.to_i.upto(pagerange.last.to_i) do |p|
+ pagelist << p.to_s
+ end
+ else
+ pagelist << page
+ end
+ end
+ opt << "\\def\\pagestoshipout\{#{pagelist.join(',')}\}\n";
+ end
+ end
+ opt << "\\stopsetups\n"
+ #
+ # styles and modules
+ #
+ opt << "\\startsetups *runtime:modules\n"
+ begin getvariable('filters' ).split(',').uniq.each do |f| opt << "\\useXMLfilter[#{f}]\n" end ; rescue ; end
+ begin getvariable('usemodules' ).split(',').uniq.each do |m| opt << "\\usemodule [#{m}]\n" end ; rescue ; end
+ begin getvariable('environments').split(',').uniq.each do |e| opt << "\\environment #{e} \n" end ; rescue ; end
+ opt << "\\stopsetups\n"
+ #
+ opt << "\\protect \\endinput\n"
+ #
+ opt.close
+ else
+ report("unable to write option file #{topname}")
+ end
+ rescue
+ report("fatal error in writing option file #{topname} (#{$!})")
+ end
+ end
+
+ def takeprecautions
+ ENV['MPXCOMAND'] = '0' # else loop
+ if getvariable('paranoid') then
+ ENV['SHELL_ESCAPE'] = ENV['SHELL_ESCAPE'] || 'f'
+ ENV['OPENOUT_ANY'] = ENV['OPENOUT_ANY'] || 'p'
+ ENV['OPENIN_ANY'] = ENV['OPENIN_ANY'] || 'p'
+ elsif getvariable('notparanoid') then
+ ENV['SHELL_ESCAPE'] = ENV['SHELL_ESCAPE'] || 't'
+ ENV['OPENOUT_ANY'] = ENV['OPENOUT_ANY'] || 'a'
+ ENV['OPENIN_ANY'] = ENV['OPENIN_ANY'] || 'a'
+ end
+ if ENV['OPENIN_ANY'] && (ENV['OPENIN_ANY'] == 'p') then # first test redundant
+ setvariable('paranoid', true)
+ end
+ if ENV.key?('SHELL_ESCAPE') && (ENV['SHELL_ESCAPE'] == 'f') then
+ setvariable('automprun',true)
+ end
+ done = false
+ ['TXRESOURCES','MPRESOURCES','MFRESOURCES'].each do |res|
+ [getvariable('runpath'),getvariable('path')].each do |pat|
+ unless pat.empty? then
+ if ENV.key?(res) then
+ # ENV[res] = if ENV[res].empty? then pat else pat + ":" + ENV[res] end
+if ENV[res].empty? then
+ ENV[res] = pat
+elsif ENV[res] == pat || ENV[res] =~ /^#{pat}\:/ || ENV[res] =~ /\:#{pat}\:/ then
+ # skip
+else
+ ENV[res] = pat + ":" + ENV[res]
+end
+ else
+ ENV[res] = pat
+ end
+ report("setting #{res} to #{ENV[res]}") unless done
+ end
+ end
+ done = true
+ end
+ end
+
+ def checktestversion
+ #
+ # one can set TEXMFALPHA and TEXMFBETA for test versions
+ # but keep in mind that the format as well as the test files
+ # then need the --alpha or --beta flag
+ #
+ done, tree = false, ''
+ ['alpha', 'beta'].each do |what|
+ if getvariable(what) then
+ if ENV["TEXMF#{what.upcase}"] then
+ done, tree = true, ENV["TEXMF#{what.upcase}"]
+ elsif ENV["TEXMFLOCAL"] then
+ done, tree = true, File.join(File.dirname(ENV['TEXMFLOCAL']), "texmf-#{what}")
+ end
+ end
+ break if done
+ end
+ if done then
+ tree = tree.strip
+ ENV['TEXMFPROJECT'] = tree
+ report("using test tree '#{tree}'")
+ ['MP', 'MF', 'TX'].each do |ctx|
+ ENV['CTXDEV#{ctx}PATH'] = ''
+ end
+ unless (FileTest.file?(File.join(tree,'ls-r')) || FileTest.file?(File.join(tree,'ls-R'))) then
+ report("no ls-r/ls-R file for tree '#{tree}' (run: mktexlsr #{tree})")
+ end
+ end
+ # puts `kpsewhich --expand-path=$TEXMF`
+ # exit
+ end
+
+ def runtex(filename)
+ checktestversion
+ texengine = validtexengine(getvariable('texengine'))
+ texformat = validtexformat(getarrayvariable('texformats').first)
+ report("tex engine: #{texengine}")
+ report("tex format: #{texformat}")
+ if texengine && texformat then
+ fixbackendvars(@@mappaths[texengine])
+ if texengine == "luatex" then
+ # currently we use luatools to start luatex but some day we should
+ # find a clever way to directly call luatex (problem is that we need
+ # to feed the explicit location of the format and lua initialization
+ # file)
+ run_luatools("--fmt=#{texformat} #{filename}")
+ else
+ progname = validprogname([getvariable('progname'),texformat,texengine])
+ runcommand([quoted(texengine),prognameflag(progname),formatflag(texengine,texformat),tcxflag(texengine),runoptions(texengine),filename,texprocextras(texformat)])
+ end
+ # true
+ else
+ false
+ end
+ end
+
+ def runmp(mpname,mpx=false)
+ checktestversion
+ mpsengine = validmpsengine(getvariable('mpsengine'))
+ mpsformat = validmpsformat(getarrayvariable('mpsformats').first)
+ if mpsengine && mpsformat then
+ ENV["MPXCOMMAND"] = "0" unless mpx
+ progname = validprogname([getvariable('progname'),mpsformat,mpsengine])
+ mpname.gsub!(/\.mp$/,"") # temp bug in mp
+ # runcommand([quoted(mpsengine),prognameflag(progname),formatflag(mpsengine,mpsformat),tcxflag(mpsengine),runoptions(mpsengine),mpname,mpsprocextras(mpsformat)])
+ runcommand([quoted(mpsengine),prognameflag(progname),formatflag(mpsengine,mpsformat),runoptions(mpsengine),mpname,mpsprocextras(mpsformat)])
+ true
+ else
+ false
+ end
+ end
+
+ def runtexmp(filename,filetype='',purge=true)
+ checktestversion
+ mpname = File.suffixed(filename,filetype,'mp')
+ if File.atleast?(mpname,10) then
+ # first run needed
+ File.silentdelete(File.suffixed(mpname,'mpt'))
+ doruntexmp(mpname,nil,true,purge)
+ mpgraphics = checkmpgraphics(mpname)
+ mplabels = checkmplabels(mpname)
+ if mpgraphics || mplabels then
+ # second run needed
+ doruntexmp(mpname,mplabels,true,purge)
+ else
+ # no labels
+ end
+ end
+ end
+
+ def runtexmpjob(filename,filetype='')
+ checktestversion
+ mpname = File.suffixed(filename,filetype,'mp')
+ if File.atleast?(mpname,25) && (data = File.silentread(mpname)) then
+ textranslation = if data =~ /^\%\s+translate.*?\=([\w\d\-]+)/io then $1 else '' end
+ mpjobname = if data =~ /collected graphics of job \"(.+?)\"/io then $1 else '' end
+ if ! mpjobname.empty? and File.unsuffixed(filename) =~ /#{mpjobname}/ then # don't optimize
+ options = Array.new
+ options.push("--mptex")
+ options.push("--nomp")
+ options.push("--mpyforce") if getvariable('forcempy') || getvariable('mpyforce')
+ options.push("--translate=#{textranslation}") unless textranslation.empty?
+ options.push("--batch") if getvariable('batchmode')
+ options.push("--nonstop") if getvariable('nonstopmode')
+ options.push("--output=ps") # options.push("--dvi")
+ options.push("--nobackend")
+ return runtexexec(mpname,options,2)
+ end
+ end
+ return false
+ end
+
+ def runtexutil(filename=[], options=['--ref','--ij','--high'], old=false)
+ [filename].flatten.each do |fname|
+ if old then
+ Kpse.runscript('texutil',fname,options)
+ else
+ begin
+ logger = Logger.new('TeXUtil')
+ if tu = TeXUtil::Converter.new(logger) and tu.loaded(fname) then
+ ok = tu.processed && tu.saved && tu.finalized
+ end
+ rescue
+ Kpse.runscript('texutil',fname,options)
+ end
+ end
+ end
+ end
+
+ def runluacheck(jobname)
+ if false then
+ # test-pos.tex / 6 meg tua file: 18.6 runtime
+ old, new = File.suffixed(jobname,'tua'), File.suffixed(jobname,'tuc')
+ if FileTest.file?(old) then
+ report("converting #{old} into #{new}")
+ system("luac -s -o #{new} #{old}")
+ end
+ else
+ # test-pos.tex / 6 meg tua file: 17.5 runtime
+ old, new = File.suffixed(jobname,'tua'), File.suffixed(jobname,'tuc')
+ if FileTest.file?(old) then
+ report("renaming #{old} into #{new}")
+ File.rename(old,new) rescue false
+ end
+ end
+ end
+
+ # 1=tex 2=mptex 3=mpxtex 4=mpgraphic 5=mpstatic
+
+ def runtexexec(filename=[], options=[], mode=nil)
+ begin
+ if mode and job = TEX.new(@logger) then
+ options.each do |option|
+ case option
+ when /^\-*(.*?)\=(.*)$/o then
+ job.setvariable($1,$2)
+ when /^\-*(.*?)$/o then
+ job.setvariable($1,true)
+ end
+ end
+ job.setvariable("files",filename)
+ case mode
+ when 1 then job.processtex
+ when 2 then job.processmptex
+ when 3 then job.processmpxtex
+ when 4 then job.processmpgraphic
+ when 5 then job.processmpstatic
+ end
+ job.inspect && Kpse.inspect if getvariable('verbose')
+ return true
+ else
+ Kpse.runscript('texexec',filename,options)
+ end
+ rescue
+ Kpse.runscript('texexec',filename,options)
+ end
+ end
+
+ def fixbackendvars(backend)
+ if backend then
+ ENV['backend'] = backend ;
+ ENV['progname'] = backend unless validtexengine(backend)
+ ENV['TEXFONTMAPS'] = ['.',"\$TEXMF/fonts/{data,map}/{#{backend},pdftex,dvips,}//",'./fonts//'].join_path
+ report("fixing backend map path for #{backend}: #{ENV['TEXFONTMAPS']}") if getvariable('verbose')
+ else
+ report("unable to fix backend map path") if getvariable('verbose')
+ end
+ end
+
+ def runbackend(rawname)
+ unless getvariable('nobackend') then
+ case validbackend(getvariable('backend'))
+ when 'dvipdfmx' then
+ fixbackendvars('dvipdfm')
+ runcommand("dvipdfmx -d 4 -V 5 #{File.unsuffixed(rawname)}")
+ when 'xetex' then
+ # xetex now runs its own backend
+ xdvfile = File.suffixed(rawname,'xdv')
+ if FileTest.file?(xdvfile) then
+ fixbackendvars('dvipdfm')
+ runcommand("xdvipdfmx -q -d 4 -V 5 -E #{xdvfile}")
+ end
+ when 'xdv2pdf' then
+ xdvfile = File.suffixed(rawname,'xdv')
+ if FileTest.file?(xdvfile) then
+ fixbackendvars('xdv2pdf')
+ runcommand("xdv2pdf #{xdvfile}")
+ end
+ when 'dvips' then
+ fixbackendvars('dvips')
+ mapfiles = ''
+ begin
+ if tuifile = File.suffixed(rawname,'tui') and FileTest.file?(tuifile) then
+ IO.read(tuifile).scan(/^c \\usedmapfile\{.\}\{(.*?)\}\s*$/o) do
+ mapfiles += "-u +#{$1} " ;
+ end
+ end
+ rescue
+ mapfiles = ''
+ end
+ runcommand("dvips #{mapfiles} #{File.unsuffixed(rawname)}")
+ when 'pdftex' then
+ # no need for postprocessing
+ else
+ report("no postprocessing needed")
+ end
+ end
+ end
+
+ def processfile
+
+ takeprecautions
+ report("using search method '#{Kpse.searchmethod}'") if getvariable('verbose')
+
+ rawname = getvariable('filename')
+ jobname = getvariable('filename')
+
+ if getvariable('autopath') then
+ jobname = File.basename(jobname)
+ inppath = File.dirname(jobname)
+ else
+ inppath = ''
+ end
+
+ jobname, jobsuffix = File.splitname(jobname,'tex')
+
+ jobname = File.unixfied(jobname)
+ inppath = File.unixfied(inppath)
+
+ orisuffix = jobsuffix # still needed ?
+
+ if jobsuffix =~ /^(htm|html|xhtml|xml|fo|fox|rlg|exa)$/io then
+ setvariable('forcexml',true)
+ end
+
+ dummyfile = false
+
+ # fuzzy code snippet: (we kunnen kpse: prefix gebruiken)
+
+ unless FileTest.file?(File.suffixed(jobname,jobsuffix)) then
+ if FileTest.file?(rawname + '.tex') then
+ jobname = rawname.dup
+ jobsuffix = 'tex'
+ end
+ end
+
+ # we can have funny names, like 2005.10.10 (given without suffix)
+
+ rawname = jobname + '.' + jobsuffix
+ rawpath = File.dirname(rawname)
+ rawbase = File.basename(rawname)
+
+ unless FileTest.file?(rawname) then
+ inppath.split(',').each do |ip|
+ break if dummyfile = FileTest.file?(File.join(ip,rawname))
+ end
+ end
+
+ forcexml = getvariable('forcexml')
+
+ if dummyfile || forcexml then # after ctx?
+ jobsuffix = makestubfile(rawname,rawbase,forcexml)
+ checkxmlfile(rawname)
+ end
+
+ # preprocess files
+
+ unless getvariable('noctx') then
+ ctx = CtxRunner.new(rawname,@logger)
+ if pth = getvariable('path') then
+ pth.split(',').each do |p|
+ ctx.register_path(p)
+ end
+ end
+ if getvariable('ctxfile').empty? then
+ if rawname == rawbase then
+ ctx.manipulate(File.suffixed(rawname,'ctx'),'jobname.ctx')
+ else
+ ctx.manipulate(File.suffixed(rawname,'ctx'),File.join(rawpath,'jobname.ctx'))
+ end
+ else
+ ctx.manipulate(File.suffixed(getvariable('ctxfile'),'ctx'))
+ end
+ ctx.savelog(File.suffixed(rawbase,'ctl'))
+
+ envs = ctx.environments
+ mods = ctx.modules
+ flags = ctx.flags
+ mdes = ctx.modes
+
+ flags.each do |f|
+ f.sub!(/^\-+/,'')
+ if f =~ /^(.*?)=(.*)$/ then
+ setvariable($1,$2)
+ else
+ setvariable(f,true)
+ end
+ end
+
+ report("using flags #{flags.join(' ')}") if flags.size > 0
+
+ # merge environment and module specs
+
+ envs << getvariable('environments') unless getvariable('environments').empty?
+ mods << getvariable('usemodules') unless getvariable('usemodules') .empty?
+ mdes << getvariable('modes') unless getvariable('modes') .empty?
+
+ envs = envs.uniq.join(',')
+ mods = mods.uniq.join(',')
+ mdes = mdes.uniq.join(',')
+
+ report("using search method '#{Kpse.searchmethod}'") if getvariable('verbose')
+
+ report("using environments #{envs}") if envs.length > 0
+ report("using modules #{mods}") if mods.length > 0
+ report("using modes #{mdes}") if mdes.length > 0
+
+ setvariable('environments', envs)
+ setvariable('usemodules', mods)
+ setvariable('modes', mdes)
+ end
+
+ # end of preprocessing and merging
+
+ setvariable('nomprun',true) if orisuffix == 'mpx' # else cylic run
+ PDFview.setmethod('xpdf') if getvariable('xpdf')
+ PDFview.closeall if getvariable('autopdf')
+
+ runonce = getvariable('once')
+ finalrun = getvariable('final') || (getvariable('arrange') && ! getvariable('noarrange'))
+ suffix = getvariable('suffix')
+ result = getvariable('result')
+ globalfile = getvariable('globalfile')
+ forcexml = getvariable('forcexml') # can be set in ctx file
+
+if dummyfile || forcexml then # after ctx?
+ jobsuffix = makestubfile(rawname,rawbase,forcexml)
+ checkxmlfile(rawname)
+end
+
+ result = File.unixfied(result)
+
+ if globalfile || FileTest.file?(rawname) then
+
+ if not dummyfile and not globalfile and not forcexml then
+ scantexpreamble(rawname)
+ scantexcontent(rawname) if getvariable('texformats').standard?
+ end
+ result = File.suffixed(rawname,suffix) unless suffix.empty?
+
+ pushresult(rawbase,result)
+
+ method = validtexmethod(validtexformat(getvariable('texformats')))
+
+ report("tex processing method: #{method}")
+
+ case method
+
+ when 'context' then
+ if getvariable('simplerun') || runonce then
+ makeoptionfile(rawbase,jobname,orisuffix,true,true,3,1) unless getvariable('nooptionfile')
+ ok = runtex(if dummyfile || forcexml then rawbase else rawname end)
+ if ok then
+ ok = runtexutil(rawbase) if getvariable('texutil') || getvariable('forcetexutil')
+ runluacheck(rawbase)
+ runbackend(rawbase)
+ popresult(rawbase,result)
+ end
+ if getvariable('keep') then
+ ['top','log','run'].each do |suffix|
+ File.silentrename(File.suffixed(rawbase,suffix),File.suffixed(rawbase,suffix+'.keep'))
+ end
+ end
+ else
+# goto tmp/jobname when present
+ mprundone, ok, stoprunning = false, true, false
+ texruns, nofruns = 0, getvariable('runs').to_i
+ state = FileState.new
+ ['tub','tuo','tuc'].each do |s|
+ state.register(File.suffixed(rawbase,s))
+ end
+ if getvariable('automprun') then # check this
+ ['mprun','mpgraph'].each do |s|
+ state.register(File.suffixed(rawbase,s,'mp'),'randomseed')
+ end
+ end
+ while ! stoprunning && (texruns < nofruns) && ok do
+ texruns += 1
+ report("TeX run #{texruns}")
+ unless getvariable('nooptionfile') then
+ if texruns == nofruns then
+ makeoptionfile(rawbase,jobname,orisuffix,false,false,4,texruns) # last
+ elsif texruns == 1 then
+ makeoptionfile(rawbase,jobname,orisuffix,false,false,1,texruns) # first
+ else
+ makeoptionfile(rawbase,jobname,orisuffix,false,false,2,texruns) # unknown
+ end
+ end
+# goto .
+
+ ok = runtex(File.suffixed(if dummyfile || forcexml then rawbase else rawname end,jobsuffix))
+
+if getvariable('texengine') == "xetex" then
+ ok = true
+end
+
+############################
+
+# goto tmp/jobname when present
+ if ok && (nofruns > 1) then
+ unless getvariable('nompmode') then
+ mprundone = runtexmpjob(rawbase, "mpgraph")
+ mprundone = runtexmpjob(rawbase, "mprun")
+ end
+ ok = runtexutil(rawbase)
+ runluacheck(rawbase)
+ state.update
+ stoprunning = state.stable?
+ end
+ end
+ if not ok then
+ setvariable('error','error in tex file')
+ end
+ if (nofruns == 1) && getvariable('texutil') then
+ ok = runtexutil(rawbase)
+ runluacheck(rawbase)
+ end
+ if ok && finalrun && (nofruns > 1) then
+ makeoptionfile(rawbase,jobname,orisuffix,true,finalrun,4,texruns) unless getvariable('nooptionfile')
+ report("final TeX run #{texruns}")
+# goto .
+ ok = runtex(File.suffixed(if dummyfile || forcexml then rawbase else rawname end,jobsuffix))
+# goto tmp/jobname when present
+ end
+ if getvariable('keep') then
+ ['top','log','run'].each do |suffix|
+ File.silentrename(File.suffixed(rawbase,suffix),File.suffixed(rawbase,suffix+'.keep'))
+ end
+ else
+ File.silentrename(File.suffixed(rawbase,'top'),File.suffixed(rawbase,'tmp'))
+ end
+ # ['tmp','top','log'].each do |s| # previous tuo file / runtime option file / log file
+ # File.silentdelete(File.suffixed(rawbase,s))
+ # end
+ if ok then
+# goto .
+ runbackend(rawbase)
+ popresult(rawbase,result)
+# goto tmp/jobname when present
+# skip next
+ end
+ if true then # autopurge
+ begin
+ File.open(File.suffixed(rawbase, 'tuo'),'rb') do |f|
+ ok = 0
+ f.each do |line|
+ case ok
+ when 1 then
+ # next line is empty
+ ok = 2
+ when 2 then
+ if line =~ /^\%\s+\>\s+(.*?)\s+(\d+)/moi then
+ filename, n = $1, $2
+ done = File.delete(filename) rescue false
+ if done && getvariable('verbose') then
+ report("deleting #{filename} (#{n} times used)")
+ end
+ else
+ break
+ end
+ else
+ if line =~ /^\%\s+temporary files\:\s+(\d+)/moi then
+ if $1.to_i == 0 then
+ break
+ else
+ ok = 1
+ end
+ end
+ end
+ end
+ end
+ rescue
+ # report("fatal error #{$!}")
+ end
+ end
+ end
+
+ Kpse.runscript('ctxtools',rawbase,'--purge') if getvariable('purge')
+ Kpse.runscript('ctxtools',rawbase,'--purge --all') if getvariable('purgeall')
+
+ # runcommand('mtxrun','--script','ctxtools',rawbase,'--purge') if getvariable('purge')
+ # runcommand('mtxrun','--script','ctxtools',rawbase,'--purge --all') if getvariable('purgeall')
+
+ when 'latex' then
+
+ ok = runtex(rawname)
+
+ else
+
+ ok = runtex(rawname)
+
+ end
+
+ if (dummyfile or forcexml) and FileTest.file?(rawbase) then
+ begin
+ File.delete(File.suffixed(rawbase,'run'))
+ rescue
+ report("unable to delete stub file")
+ end
+ end
+
+ if ok and getvariable('autopdf') then
+ PDFview.open(File.suffixed(if result.empty? then rawbase else result end,'pdf'))
+ end
+
+ else
+ report("nothing to process")
+ end
+
+ end
+
+ # The labels are collected in the mergebe hash. Here we merge the relevant labels
+ # into beginfig/endfig. We could as well do this in metafun itself. Maybe some
+ # day ... (it may cost a bit of string space but that is cheap nowadays).
+
+ def doruntexmp(mpname,mergebe=nil,context=true,purge=true)
+ texfound = false
+ mpname = File.suffixed(mpname,'mp')
+ mpcopy = File.suffixed(mpname,'mp.copy')
+ mpkeep = File.suffixed(mpname,'mp.keep')
+ setvariable('mp.file',mpname)
+ setvariable('mp.line','')
+ setvariable('mp.error','')
+ if mpdata = File.silentread(mpname) then
+ # mpdata.gsub!(/^\%.*\n/o,'')
+ File.silentrename(mpname,mpcopy)
+ texfound = mergebe || (mpdata =~ /btex .*? etex/mo)
+ if mp = openedfile(mpname) then
+ if mergebe then
+ mpdata.gsub!(/beginfig\s*\((\d+)\)\s*\;(.+?)endfig\s*\;/mo) do
+ n, str = $1, $2
+ if str =~ /^(.*?)(verbatimtex.*?etex)\s*\;(.*)$/mo then
+ "beginfig(#{n})\;\n#{$1}#{$2}\;\n#{mergebe[n]}\n#{$3}\;endfig\;\n"
+ else
+ "beginfig(#{n})\;\n#{mergebe[n]}\n#{str}\;endfig\;\n"
+ end
+ end
+ unless mpdata =~ /beginfig\s*\(\s*0\s*\)/o then
+ mp << mergebe['0'] if mergebe.key?('0')
+ end
+ end
+ # mp << MPTools::splitmplines(mpdata)
+ mp << mpdata
+ mp << "\n"
+ # mp << "end"
+ # mp << "\n"
+ mp.close
+ end
+ processmpx(mpname,true,true,purge) if texfound
+ if getvariable('batchmode') then
+ options = ' --interaction=batch'
+ elsif getvariable('nonstopmode') then
+ options = ' --interaction=nonstop'
+ else
+ options = ''
+ end
+ # todo plain|mpost|metafun
+ begin
+ ok = runmp(mpname)
+ rescue
+ end
+ if f = File.silentopen(File.suffixed(mpname,'log')) then
+ while str = f.gets do
+ if str =~ /^l\.(\d+)\s(.*?)\n/o then
+ setvariable('mp.line',$1)
+ setvariable('mp.error',$2)
+ break
+ end
+ end
+ f.close
+ end
+ File.silentrename(mpname, mpkeep)
+ File.silentrename(mpcopy, mpname)
+ end
+ end
+
+ # todo: use internal mptotext function and/or turn all btex/etex into textexts
+
+ def processmpx(mpname,force=false,context=true,purge=true)
+ unless force then
+ mpname = File.suffixed(mpname,'mp')
+ if File.atleast?(mpname,10) && (data = File.silentread(mpname)) then
+ if data =~ /(btex|etex|verbatimtex|textext)/o then
+ force = true
+ end
+ end
+ end
+ if force then
+ begin
+ mptex = File.suffixed(mpname,'temp','tex')
+ mpdvi = File.suffixed(mpname,'temp','dvi')
+ mplog = File.suffixed(mpname,'temp','log')
+ mpmpx = File.suffixed(mpname,'mpx')
+ File.silentdelete(mptex)
+ if true then
+ report("using internal mptotex converter")
+ ok = MPTools::mptotex(mpname,mptex,'context')
+ else
+ command = "mpto #{mpname} > #{mptex}"
+ report(command) if getvariable('verbose')
+ ok = system(command)
+ end
+ # not "ok && ..." because of potential problem with return code and redirect (>)
+ if FileTest.file?(mptex) && File.appended(mptex, "\\end\n") then
+ # to be replaced by runtexexec([filenames],options,1)
+ if localjob = TEX.new(@logger) then
+ localjob.setvariable('files',mptex)
+ localjob.setvariable('backend','dvips')
+ localjob.setvariable('engine',getvariable('engine')) unless getvariable('engine').empty?
+ localjob.setvariable('once',true)
+ localjob.setvariable('nobackend',true)
+ if context then
+ localjob.setvariable('texformats',[getvariable('interface')]) unless getvariable('interface').empty?
+ elsif getvariable('interface').empty? then
+ localjob.setvariable('texformats',['plain'])
+ else
+ localjob.setvariable('texformats',[getvariable('interface')])
+ end
+ localjob.processtex
+ ok = true # todo
+ else
+ ok = false
+ end
+ # so far
+ command = "dvitomp #{mpdvi} #{mpmpx}"
+ report(command) if getvariable('verbose')
+ ok = ok && FileTest.file?(mpdvi) && system(command)
+ purge_mpx_files(mpname) if purge
+ end
+ rescue
+ # error in processing mpx file
+ end
+ end
+ end
+
+ def purge_mpx_files(mpname)
+ unless getvariable('keep') then
+ ['tex', 'log', 'tui', 'tuo', 'tuc', 'top'].each do |suffix|
+ File.silentdelete(File.suffixed(mpname,'temp',suffix))
+ end
+ end
+ end
+
+ def checkmpgraphics(mpname)
+ # in practice the checksums will differ because of multiple instances
+ # ok, we could save the mpy/mpo files by number, but not now
+ mpoptions = ''
+ if getvariable('makempy') then
+ mpoptions += " --makempy "
+ end
+ mponame = File.suffixed(mpname,'mpo')
+ mpyname = File.suffixed(mpname,'mpy')
+ pdfname = File.suffixed(mpname,'pdf')
+ tmpname = File.suffixed(mpname,'tmp')
+ if getvariable('mpyforce') || getvariable('forcempy') then
+ mpoptions += " --force "
+ else
+ return false unless File.atleast?(mponame,32)
+ mpochecksum = FileState.new.checksum(mponame)
+ return false if mpochecksum.empty?
+ # where does the checksum get into the file?
+ # maybe let texexec do it?
+ # solution: add one if not present or update when different
+ begin
+ mpydata = IO.read(mpyname)
+ if mpydata then
+ if mpydata =~ /^\%\s*mpochecksum\s*\:\s*([A-Z0-9]+)$/mo then
+ checksum = $1
+ if mpochecksum == checksum then
+ return false
+ end
+ end
+ end
+ rescue
+ # no file
+ end
+ end
+ # return Kpse.runscript('makempy',mpname)
+ # only pdftex
+ flags = ['--noctx','--process','--batch','--once']
+ result = runtexexec([mponame], flags, 1)
+ runcommand(["pstoedit","-ssp -dt -f mpost", pdfname,tmpname])
+ tmpdata = IO.read(tmpname)
+ if tmpdata then
+ if mpy = openedfile(mpyname) then
+ mpy << "% mpochecksum: #{mpochecksum}\n"
+ tmpdata.scan(/beginfig(.*?)endfig/mo) do |s|
+ mpy << "begingraphictextfig#{s}endgraphictextfig\n"
+ end
+ mpy.close()
+ end
+ end
+ File.silentdelete(tmpname)
+ File.silentdelete(pdfname)
+ return true
+ end
+
+ def checkmplabels(mpname)
+ mpname = File.suffixed(mpname,'mpt')
+ if File.atleast?(mpname,10) && (mp = File.silentopen(mpname)) then
+ labels = Hash.new
+ while str = mp.gets do
+ t = if str =~ /^%\s*setup\s*:\s*(.*)$/o then $1 else '' end
+ if str =~ /^%\s*figure\s*(\d+)\s*:\s*(.*)$/o then
+ labels[$1] = labels[$1] || ''
+ unless t.empty? then
+ labels[$1] += "#{t}\n"
+ t = ''
+ end
+ labels[$1] += "#{$2}\n"
+ end
+ end
+ mp.close
+ if labels.size>0 then
+ return labels
+ else
+ return nil
+ end
+ end
+ return nil
+ end
+
+end