diff options
author | Karl Berry <karl@freefriends.org> | 2006-11-16 01:02:47 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2006-11-16 01:02:47 +0000 |
commit | 3c85b55e2f245fb7edac7e445f107e6d0bb423ae (patch) | |
tree | c62b7f80edafe0455310d08e09f4218127bf9e87 /Master/texmf-dist/scripts/context/ruby/base/tex.rb | |
parent | e5ecff27a26ef59e1dbe9702677687fd7107be3a (diff) |
context update
git-svn-id: svn://tug.org/texlive/trunk@2444 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/scripts/context/ruby/base/tex.rb')
-rw-r--r-- | Master/texmf-dist/scripts/context/ruby/base/tex.rb | 1283 |
1 files changed, 881 insertions, 402 deletions
diff --git a/Master/texmf-dist/scripts/context/ruby/base/tex.rb b/Master/texmf-dist/scripts/context/ruby/base/tex.rb index 2cc9d25422e..a6403dcde2b 100644 --- a/Master/texmf-dist/scripts/context/ruby/base/tex.rb +++ b/Master/texmf-dist/scripts/context/ruby/base/tex.rb @@ -8,8 +8,11 @@ # info : j.hagen@xs4all.nl # www : www.pragma-ade.com -# todo: write systemcall for mpost to file so that it can be run -# faster +# todo: +# +# - write systemcall for mpost to file so that it can be run faster +# - use -8bit and -progname +# # report ? @@ -20,6 +23,7 @@ require 'base/state' require 'base/pdf' require 'base/file' require 'base/ctx' +require 'base/mp' class String @@ -33,6 +37,12 @@ class String end +# class String + # def utf_bom? + # self.match(/^\357\273\277/o).length>0 rescue false + # end +# end + class Array def standard? @@ -43,6 +53,10 @@ class Array end end + def join_path + self.join(File::PATH_SEPARATOR) + end + end class TEX @@ -56,6 +70,7 @@ class TEX @@texengines = Hash.new @@mpsengines = Hash.new @@backends = Hash.new + @@mappaths = Hash.new @@runoptions = Hash.new @@texformats = Hash.new @@mpsformats = Hash.new @@ -68,11 +83,32 @@ class TEX @@texmethods = Hash.new @@mpsmethods = Hash.new - ['tex','pdftex','pdfetex','standard'] .each do |e| @@texengines[e] = 'pdfetex' end + @@pdftex = 'pdftex' # new default, pdfetex is gone + + ENV['PATH'].split(File::PATH_SEPARATOR).each do |p| + if System.unix? then + pp, pe = "#{p}/pdftex" , "#{p}/pdfetex" + else + pp, pe = "#{p}/pdftex.exe", "#{p}/pdfetex.exe" + end + if FileTest.file?(pe) then + # we assume no update + @@pdftex = 'pdfetex' + break + elsif FileTest.file?(pp) then + # we assume an update + @@pdftex = 'pdftex' + break + end + end + + ['etex','pdfetex','standard'] .each do |e| @@texengines[e] = @@pdftex end + ['tex','pdftex'] .each do |e| @@texengines[e] = 'pdftex' end ['aleph','omega'] .each do |e| @@texengines[e] = 'aleph' end ['xetex'] .each do |e| @@texengines[e] = 'xetex' end + ['luatex'] .each do |e| @@texengines[e] = 'luatex' end - ['metapost','mpost','standard'] .each do |e| @@mpsengines[e] = 'mpost' 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 @@ -80,6 +116,13 @@ class TEX ['dvips','ps'] .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'] .each do |b| @@mappaths[b] = 'dvipdfm' end + ['dvipdfm', 'dvipdfmx', 'xdvipdfmx'] .each do |b| @@mappaths[b] = 'dvipdfm' end + ['xdv','xdv2pdf'] .each do |b| @@mappaths[b] = 'dvips' end # todo norwegian (no) @@ -88,6 +131,7 @@ class TEX ['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-cz','cz','czech'] .each do |f| @@texformats[f] = 'cont-cz' end ['cont-ro','ro','romanian'] .each do |f| @@texformats[f] = 'cont-ro' end ['cont-uk','uk','brittish'] .each do |f| @@texformats[f] = 'cont-uk' end @@ -98,12 +142,13 @@ class TEX ['plain','mpost'] .each do |f| @@mpsformats[f] = 'plain' end ['metafun','context','standard'] .each do |f| @@mpsformats[f] = 'metafun' end - ['pdfetex','aleph','omega'] .each do |p| @@prognames[p] = 'context' end + ['pdftex','pdfetex','aleph','omega', + 'xetex','luatex'] .each do |p| @@prognames[p] = 'context' end ['mpost'] .each do |p| @@prognames[p] = 'metafun' end ['plain','default','standard','mptopdf'] .each do |f| @@texmethods[f] = 'plain' end ['cont-en','cont-nl','cont-de','cont-it', - 'cont-cz','cont-ro','cont-uk'] .each do |f| @@texmethods[f] = 'context' end + 'cont-fr','cont-cz','cont-ro','cont-uk'] .each do |f| @@texmethods[f] = 'context' end ['latex'] .each do |f| @@texmethods[f] = 'latex' end ['plain','default','standard'] .each do |f| @@mpsmethods[f] = 'plain' end @@ -113,28 +158,35 @@ class TEX @@mpsmakestr['plain'] = "\\dump" ['cont-en','cont-nl','cont-de','cont-it', - 'cont-cz','cont-ro','cont-uk'] .each do |f| @@texprocstr[f] = "\\emergencyend" end + 'cont-fr','cont-cz','cont-ro','cont-uk'] .each do |f| @@texprocstr[f] = "\\emergencyend" end - @@runoptions['xetex'] = ['--no-pdf'] + # @@runoptions['xetex'] = ['--output-driver \\\"-d 4 -V 5\\\"'] # we need the pos pass + @@runoptions['xetex'] = ['--8bit -no-pdf'] # from now on we assume (x)dvipdfmx to be used + @@runoptions['pdfetex'] = ['--8bit '] + @@runoptions['pdftex'] = ['--8bit '] # pdftex is now pdfetex + @@runoptions['luatex'] = ['--8bit '] + @@runoptions['aleph'] = ['--8bit '] @@booleanvars = [ 'batchmode', 'nonstopmode', 'fast', 'fastdisabled', 'silentmode', 'final', 'paranoid', 'notparanoid', 'nobanner', 'once', 'allpatterns', - 'nompmode', 'nomprun', 'automprun', + 'nompmode', 'nomprun', 'automprun', 'combine', 'nomapfiles', 'local', 'arrange', 'noarrange', 'forcexml', 'foxet', + 'alpha', 'beta', 'mpyforce', 'forcempy', 'forcetexutil', 'texutil', 'globalfile', 'autopath', - 'purge', 'purgeall', 'autopdf', 'simplerun', 'verbose', - 'nooptionfile' + 'purge', 'purgeall', 'keep', 'autopdf', 'xpdf', 'simplerun', 'verbose', + 'nooptionfile', 'nobackend', 'noctx', 'utfbom' ] @@stringvars = [ 'modefile', 'result', 'suffix', 'response', 'path', 'filters', 'usemodules', 'environments', 'separation', 'setuppath', - 'arguments', 'input', 'output', 'randomseed', 'modes', 'filename', - 'modefile', 'ctxfile' + 'arguments', 'input', 'output', 'randomseed', 'modes', 'mode', 'filename', + 'ctxfile', 'printformat', 'paperformat', 'paperoffset', + 'timeout' ] @@standardvars = [ 'mainlanguage', 'bodyfont', 'language' @@ -148,16 +200,22 @@ class TEX @@extrastringvars = [] def booleanvars - [@@booleanvars,@@extrabooleanvars].flatten + [@@booleanvars,@@extrabooleanvars].flatten.uniq end def stringvars - [@@stringvars,@@extrastringvars].flatten + [@@stringvars,@@extrastringvars].flatten.uniq end def standardvars - @@standardvars + [@@standardvars].flatten.uniq end def knownvars - @@knownvars + [@@knownvars].flatten.uniq + end + def allbooleanvars + [@@booleanvars,@@extrabooleanvars].flatten.uniq + end + def allstringvars + [@@stringvars,@@extrastringvars,@@standardvars,@@knownvars].flatten.uniq end def setextrastringvars(vars) @@ -201,13 +259,18 @@ class TEX setvariable('engine', 'standard') # replaced by tex/mpsengine setvariable('backend', 'pdftex') setvariable('runs', '8') - setvariable('randomseed', rand(1440).to_s) + 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 @@ -218,10 +281,17 @@ class TEX 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 unless (str.class == String) && str.empty? then @@ -249,11 +319,14 @@ class TEX begin Dir.glob("#{@@temprunfile}*").each do |name| if File.file?(name) && (File.splitname(name)[1] !~ /(pdf|dvi)/o) then - begin File.delete(name) ; rescue ; end + 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 @@ -301,11 +374,12 @@ class TEX end def prefixed(format,engine) + # format case engine - when /etex|eetex|pdfetex|pdfeetex|pdfxtex|xpdfetex|eomega|aleph|xetex/io then - "*#{format}" - else - format + when /etex|pdftex|pdfetex|aleph|xetex|luatex/io then + "*#{format}" + else + format end end @@ -318,18 +392,24 @@ class TEX if str.class == String then str.split(',') else str.flatten end end - def validtexformat(str) validsomething(str,@@texformats) end - def validmpsformat(str) validsomething(str,@@mpsformats) end - def validtexengine(str) validsomething(str,@@texengines) end - def validmpsengine(str) validsomething(str,@@mpsengines) end + def validtexformat(str) validsomething(str,@@texformats,'tex') end + def validmpsformat(str) validsomething(str,@@mpsformats,'mp' ) end + def validtexengine(str) validsomething(str,@@texengines,'pdfetex') 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) + def validsomething(str,something,type=nil) if str then list = [str].flatten.collect do |s| - something[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 @@ -384,20 +464,20 @@ class TEX # 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" + when /mpost/ then "-mem" + when /mfont/ then "-bas" + else "-fmt" end else - "--fmt" + "-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" + when 'standard' then prefix = "-progname" + when /web2c/io then prefix = "-progname" + when /miktex/io then prefix = "-alias" else return "" end if progname then @@ -422,7 +502,7 @@ class TEX if Kpse.miktex? then "-tcx=#{file}" else - "--translate-file=#{file}" + "-translate-file=#{file}" end end @@ -436,7 +516,7 @@ class TEX filename = Kpse.found('context.tex') version = 'unknown' begin - if FileTest.file?(filename) && IO.read(filename).match(/\\contextversion\{(\d+\.\d+\.\d+)\}/) then + if FileTest.file?(filename) && IO.read(filename).match(/\\contextversion\{(\d+\.\d+\.\d+.*?)\}/) then version = $1 end rescue @@ -445,6 +525,10 @@ class TEX end def makeformats + + checktestversion + + report("using search method '#{Kpse.searchmethod}'") if getvariable('fast') then report('using existing database') else @@ -463,24 +547,27 @@ class TEX # 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, ...)') + end if texformats && texengine && (progname = validprogname(getvariable('progname'),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}") - begin - Dir.chdir(texformatpath) - rescue - end - if texformats.length > 0 then - makeuserfile - makeresponsefile - end - texformats.each do |texformat| - report("generating tex format #{texformat}") - command = [quoted(texengine),prognameflag(progname),iniflag,tcxflag,prefixed(texformat,texengine),texmakeextras(texformat)].join(' ') - report(command) if getvariable('verbose') - system(command) + Dir.chdir(texformatpath) rescue false + if FileTest.writable?(texformatpath) then + if texformats.length > 0 then + makeuserfile + makeresponsefile + end + texformats.each do |texformat| + report("generating tex format #{texformat}") + runcommand([quoted(texengine),prognameflag(progname),iniflag,tcxflag,prefixed(texformat,texengine),texmakeextras(texformat)]) + end + else + report("unable to make format due to lack of permissions") + texformatpath = '' end else texformatpath = '' @@ -490,15 +577,16 @@ class TEX report("using mp engine #{mpsengine}") mpsformatpath = if getvariable('local') then '.' else Kpse.formatpath(mpsengine,false) end report("using mps format path #{mpsformatpath}") - begin - Dir.chdir(mpsformatpath) - rescue - end - mpsformats.each do |mpsformat| - report("generating mps format #{mpsformat}") - command = [quoted(mpsengine),prognameflag(progname),iniflag,tcxflag,mpsformat,mpsmakeextras(mpsformat)].join(' ') - report(command) if getvariable('verbose') - system(command) + Dir.chdir(mpsformatpath) rescue false + if FileTest.writable?(mpsformatpath) then + mpsformats.each do |mpsformat| + report("generating mps format #{mpsformat}") + # runcommand([quoted(mpsengine),prognameflag(progname),iniflag,tcxflag,mpsformat,mpsmakeextras(mpsformat)]) + runcommand([quoted(mpsengine),iniflag,tcxflag,mpsformat,mpsmakeextras(mpsformat)]) + end + else + report("unable to make format due to lack of permissions") + mpsformatpath = '' end else mpsformatpath = '' @@ -560,7 +648,7 @@ class TEX f.close if FileTest.file?(tempfilename('tex')) then format = File.basename(name) - engine = if name =~ /(pdfetex|aleph|xetex)[\/\\]#{format}/ then $1 else '' end + engine = if name =~ /(pdftex|pdfetex|aleph|xetex|luatex)[\/\\]#{format}/ then $1 else '' end if engine.empty? then engineflag = "" else @@ -571,8 +659,8 @@ class TEX interface = $1.sub(/cont\-/,'') results.push('') results.push("testing interface #{interface}") - flags = ['--process','--batch','--once',"--interface=#{interface}",engineflag] - # result = Kpse.pipescript('newtexexec',tempfilename,flags) + 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") @@ -663,6 +751,7 @@ class TEX @@preamblekeys = [ ['tex','texengine'], + ['engine','texengine'], ['program','texengine'], ['translate','tcxfilter'], ['tcx','tcxfilter'], @@ -670,22 +759,42 @@ class TEX ['mode','mode'], ['ctx','ctxfile'], ['version','contextversion'], - ['format','texformat'], - ['interface','texformat'] + ['format','texformats'], + ['interface','texformats'], ] + @@re_utf_bom = /^\357\273\277/o + def scantexpreamble(filename) begin if FileTest.file?(filename) and tex = File.open(filename) 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 - vars = Hash.new + # we only accept lines with key=value pairs + vars, ok = Hash.new, true $1.split(/\s+/o).each do |s| k, v = s.split('=') - vars[k] = v + if k && v then + vars[k] = v + else + ok = false + break + end end - @@preamblekeys.each do |v| - setvariable(v[1],vars[v[0]]) if vars.key?(v[0]) + 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 + break end else break @@ -699,37 +808,37 @@ class TEX end def scantexcontent(filename) - if FileTest.file?(filename) and tex = File.open(filename) then + if FileTest.file?(filename) and tex = File.open(filename) then while str = tex.gets do case str.chomp when /^\%/o then # next when /\\(starttekst|stoptekst|startonderdeel|startdocument|startoverzicht)/o then - setvariable('texformat','nl') ; break + setvariable('texformats','nl') ; break when /\\(stelle|verwende|umgebung|benutze)/o then - setvariable('texformat','de') ; break + setvariable('texformats','de') ; break when /\\(stel|gebruik|omgeving)/o then - setvariable('texformat','nl') ; break + setvariable('texformats','nl') ; break when /\\(use|setup|environment)/o then - setvariable('texformat','en') ; break + setvariable('texformats','en') ; break when /\\(usa|imposta|ambiente)/o then - setvariable('texformat','it') ; break + setvariable('texformats','it') ; break when /(height|width|style)=/o then - setvariable('texformat','en') ; break + setvariable('texformats','en') ; break when /(hoehe|breite|schrift)=/o then - setvariable('texformat','de') ; break + setvariable('texformats','de') ; break when /(hoogte|breedte|letter)=/o then - setvariable('texformat','nl') ; break + setvariable('texformats','nl') ; break when /(altezza|ampiezza|stile)=/o then - setvariable('texformat','it') ; break + setvariable('texformats','it') ; break when /externfiguur/o then - setvariable('texformat','nl') ; break + setvariable('texformats','nl') ; break when /externalfigure/o then - setvariable('texformat','en') ; break + setvariable('texformats','en') ; break when /externeabbildung/o then - setvariable('texformat','de') ; break + setvariable('texformats','de') ; break when /figuraesterna/o then - setvariable('texformat','it') ; break + setvariable('texformats','it') ; break end end tex.close @@ -770,36 +879,11 @@ class TEX end end - def makestubfile(rawname,forcexml=false) - if tmp = File.open(File.suffixed(rawname,'run'),'w') then + def makestubfile(rawname,rawbase,forcexml=false) + if tmp = openedfile(File.suffixed(rawbase,'run')) then tmp << "\\starttext\n" if forcexml then - 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 - end - end - when /<[a-z]+/io then # beware of order, first pi test - break - end - end - xml.close - end + # tmp << checkxmlfile(rawname) tmp << "\\processXMLfilegrouped{#{rawname}}\n" else tmp << "\\processfile{#{rawname}}\n" @@ -812,16 +896,113 @@ class TEX 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)) 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}'") + rescue + report("job aborted due to 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}'") - processfile + timedrun(getvariable('timeout')) do + processfile + end end reportruntime end @@ -835,152 +1016,284 @@ class TEX 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 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*(.*)$/mois 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 processmpxtex getarrayvariable('files').each do |filename| setvariable('filename',filename) report("processing text of graphic '#{filename}'") - processmpx(filename,true) + processmpx(filename,false,true,true) end reportruntime end def deleteoptionfile(rawname) - begin - File.delete(File.suffixed(rawname,'top')) - rescue + ['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) - # jobsuffix = orisuffix - if topname = File.suffixed(rawname,'top') and opt = File.open(topname,'w') then - # local handies - opt << "\% #{topname}\n" - opt << "\\unprotect\n" - opt << "\\setupsystem[\\c!n=#{kindofrun}]\n" - opt << "\\def\\MPOSTformatswitch\{#{prognameflag('metafun')} #{formatflag('mpost')}=\}\n" - 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 (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 - 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 = validbackend(getvariable('backend')) then - opt << "\\setupoutput[#{str}]\n" - end - if getvariable('color') then - opt << "\\setupcolors[\\c!state=\\v!start]\n" - end - if getvariable('nompmode') || getvariable('nomprun') || getvariable('automprun') then - opt << "\\runMPgraphicsfalse\n" - end - if getvariable('fast') && ! getvariable('fastdisabled') then - opt << "\\fastmode\n" - end - if getvariable('silentmode') then - opt << "\\silentmode\n" - end - if (str = getvariable('separation')) && ! str.empty? then - opt << "\\setupcolors[\\c!split=#{str}]\n" - end - if (str = getvariable('setuppath')) && ! str.empty? then - opt << "\\setupsystem[\\c!directory=\{#{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 pd.size == 1 - opt << "\\setuppapersize[#{pf[0]}][#{pf[1]}]\n" + 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" + if getvariable('utfbom') then + opt << "\\enableregime[utf]" 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('nomapfiles') then - opt << "\\disablemapfiles\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 printformat - when '' then arrangement << "\\v!normal" - when /.*up/oi then arrangement << "\\v!rotated" - when /.*down/oi then arrangement << ["2DOWN","\\v!rotated"] - when /.*side/oi then arrangement << ["2SIDE","\\v!rotated"] + opt << "\\setupsystem[\\c!n=#{kindofrun},\\c!m=#{currentrun}]\n" + opt << "\\def\\MPOSTformatswitch\{#{prognameflag('metafun')} #{formatflag('mpost')}=\}\n" + 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 (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 = 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 getvariable('nompmode') || getvariable('nomprun') || getvariable('automprun') then + opt << "\\runMPgraphicsfalse\n" + end + if getvariable('fast') && ! getvariable('fastdisabled') then + opt << "\\fastmode\n" + end + if getvariable('silentmode') then + opt << "\\silentmode\n" + end + if (str = getvariable('separation')) && ! str.empty? then + opt << "\\setupcolors[\\c!split=#{str}]\n" + end + if (str = getvariable('setuppath')) && ! str.empty? then + opt << "\\setupsystem[\\c!directory=\{#{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 - else - arrangement << "\\v!disable" end - opt << "\\setuparranging[#{arrangement.flatten.join(',')}]\n" if arrangement.size > 0 - end - if (str = getvariable('modes')) && ! str.empty? then - opt << "\\enablemode[#{modes}]\n" - end - if (str = getvariable('arguments')) && ! str.empty? then - opt << "\\setupenv[#{str}]\n" - end - if (str = getvariable('randomseed')) && ! str.empty? then - 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 - 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" + 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('nomapfiles') then + opt << "\\disablemapfiles\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 + # 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 + if (str = getvariable('arguments')) && ! str.empty? then + opt << "\\setupenv[#{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 - pagelist = Array.new - str.split(/\,/).each do |page| - pagerange = page.split(/(\:|\.\.)/o ) - if pagerange.size > 1 then - pagerange.first.to_i.upto(pagerange.last.to_i) do |p| - pagelist << p.to_s + opt << "\\setupsystem[inputfile=#{rawname}]\n" + 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 - else - pagelist << page end + opt << "\\def\\pagestoshipout\{#{pagelist.join(',')}\}\n"; end - opt << "\\def\\pagestoshipout\{pagelist.join(',')\}\n"; end + opt << "\\protect\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 + # this will become: + # begin getvariable('environments').split(',').uniq.each do |e| opt << "\\useenvironment[#{e}]\n" end ; rescue ; end + opt << "\\endinput\n" + opt.close + else + report("unable to write option file #{topname}") end - opt << "\\protect\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 - # this will become: - # begin getvariable('environments').split(',').uniq.each do |e| opt << "\\useenvironment[#{e}]\n" end ; rescue ; end - opt << "\\endinput\n" - opt.close + rescue + report("fatal error in writing option file #{topname} (#{$!})") end end @@ -1001,6 +1314,7 @@ class TEX 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 @@ -1009,12 +1323,47 @@ class TEX 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) progname = validprogname(getvariable('progname')) @@ -1022,45 +1371,51 @@ class TEX report("tex format: #{texformat}") report("progname: #{progname}") if texengine && texformat && progname then - command = [quoted(texengine),prognameflag(progname),formatflag(texengine,texformat),runoptions(texengine),filename,texprocextras(texformat)].join(' ') - report(command) if getvariable('verbose') - system(command) + fixbackendvars(@@mappaths[texengine]) + runcommand([quoted(texengine),prognameflag(progname),formatflag(texengine,texformat),tcxflag,runoptions(texengine),filename,texprocextras(texformat)]) + # true else false end end - def runmp(filename) + def runmp(mpname,mpx=false) + checktestversion mpsengine = validmpsengine(getvariable('mpsengine')) mpsformat = validmpsformat(getarrayvariable('mpsformats').first) progname = validprogname(getvariable('progname')) if mpsengine && mpsformat && progname then - command = [quoted(mpsengine),prognameflag(progname),formatflag(mpsengine,mpsformat),runoptions(mpsengine),filename,mpsprocextras(mpsformat)].join(' ') - report(command) if getvariable('verbose') - system(command) + ENV["MPXCOMMAND"] = "0" unless mpx + # runcommand([quoted(mpsengine),prognameflag(progname),formatflag(mpsengine,mpsformat),tcxflag,runoptions(mpsengine),filename,mpsprocextras(mpsformat)]) + runcommand([quoted(mpsengine),formatflag(mpsengine,mpsformat),tcxflag,runoptions(mpsengine),mpname,mpsprocextras(mpsformat)]) + true else false end end - def runtexmp(filename,filetype='') - mpfile = File.suffixed(filename,filetype,'mp') - if File.atleast?(mpfile,25) then + def runtexmp(filename,filetype='',purge=true) + checktestversion + mpname = File.suffixed(filename,filetype,'mp') + if File.atleast?(mpname,25) then # first run needed - File.silentdelete(File.suffixed(mpfile,'mpt')) - doruntexmp(mpfile,false) - mpgraphics = checkmpgraphics(mpfile) - mplabels = checkmplabels(mpfile) + 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(mpfile,mplabels) + doruntexmp(mpname,mplabels,true,purge) + else + # no labels end end end def runtexmpjob(filename,filetype='') - mpfile = File.suffixed(filename,filetype,'mp') - if File.atleast?(mpfile,25) && (data = File.silentread(mpfile)) then + 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 @@ -1071,8 +1426,9 @@ class TEX options.push("--translate=#{textranslation}") unless textranslation.empty? options.push("--batch") if getvariable('batchmode') options.push("--nonstop") if getvariable('nonstopmode') - options.push("--output=ps") - return runtexexec(mpfile,options,2) + options.push("--output=ps") # options.push("--dvi") + options.push("--nobackend") + return runtexexec(mpname,options,2) end end return false @@ -1086,7 +1442,7 @@ class TEX begin logger = Logger.new('TeXUtil') if tu = TeXUtil::Converter.new(logger) and tu.loaded(fname) then - tu.saved if tu.processed + ok = tu.processed && tu.saved && tu.finalized end rescue Kpse.runscript('texutil',fname,options) @@ -1095,16 +1451,17 @@ class TEX end end - # 1=tex 2=mptex 3=mpxtex + # 1=tex 2=mptex 3=mpxtex 4=mpgraphic def runtexexec(filename=[], options=[], mode=nil) begin if mode and job = TEX.new(@logger) then options.each do |option| - if option=~ /^\-*(.*?)\=(.*)$/o then - job.setvariable($1,$2) - else - job.setvariable(option,true) + case option + when /^\-*(.*?)\=(.*)$/o then + job.setvariable($1,$2) + when /^\-*(.*?)$/o then + job.setvariable($1,true) end end job.setvariable("files",filename) @@ -1112,6 +1469,7 @@ class TEX when 1 then job.processtex when 2 then job.processmptex when 3 then job.processmpxtex + when 4 then job.processmpgraphic end job.inspect && Kpse.inspect if getvariable('verbose') return true @@ -1124,49 +1482,65 @@ class TEX end def fixbackendvars(backend) - ENV['backend'] = backend ; - ENV['progname'] = backend unless validtexengine(backend) - ENV['TEXFONTMAPS'] = ".;\$TEXMF/fonts/map/{#{backend},pdftex,dvips,}//" + if backend then + report("fixing backend map path for #{backend}") if getvariable('verbose') + ENV['backend'] = backend ; + ENV['progname'] = backend unless validtexengine(backend) + ENV['TEXFONTMAPS'] = ['.',"\$TEXMF/fonts/map/{#{backend},pdftex,dvips,}//",'./fonts//'].join_path + else + report("unable to fix backend map path") if getvariable('verbose') + end end def runbackend(rawname) - case validbackend(getvariable('backend')) - when 'dvipdfmx' then - fixbackendvars('dvipdfm') - system("dvipdfmx -d 4 #{File.unsuffixed(rawname)}") - when 'xetex' then - fixbackendvars('xetex') - system("xdv2pdf #{File.suffixed(jrawname,'xdv')}") - 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 + 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 -d 4 -V 5 #{xdvfile}") end - rescue + 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 = '' - end - system("dvips #{mapfiles} #{File.unsuffixed(rawname)}") - when 'pdftex' then - # no need for postprocessing - else - report("no postprocessing needed") + 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 - - rawname = getvariable('filename') - - jobname = getvariable('filename') - suffix = getvariable('suffix') - result = getvariable('result') - + report("using search method '#{Kpse.searchmethod}'") if getvariable('verbose') + rawname = getvariable('filename') + jobname = getvariable('filename') + suffix = getvariable('suffix') + result = getvariable('result') + forcexml = getvariable('forcexml') runonce = getvariable('once') finalrun = getvariable('final') || (getvariable('arrange') && ! getvariable('noarrange')) globalfile = getvariable('globalfile') @@ -1188,9 +1562,13 @@ class TEX setvariable('nomprun',true) if orisuffix == 'mpx' # else cylic run + PDFview.setmethod('xpdf') if getvariable('xpdf') + PDFview.closeall if getvariable('autopdf') - forcexml = jobsuffix.match(/^(xml|fo|fox|rlg|exa)$/io) # nil or match + if jobsuffix =~ /^(htm|html|xhtml|xml|fo|fox|rlg|exa)$/io then + forcexml = true + end dummyfile = false @@ -1207,53 +1585,66 @@ class TEX 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 + if dummyfile || forcexml then + jobsuffix = makestubfile(rawname,rawbase,forcexml) + checkxmlfile(rawname) + end + + # preprocess files - ctx = CtxRunner.new(rawname,@logger) - if getvariable('ctxfile').empty? then - ctx.manipulate(File.suffixed(rawname,'ctx'),'jobname.ctx') - else - ctx.manipulate(File.suffixed(getvariable('ctxfile'),'ctx')) - end - ctx.savelog(File.suffixed(rawname,'ctl')) + unless getvariable('noctx') then + ctx = CtxRunner.new(rawname,@logger) + 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 + envs = ctx.environments + mods = ctx.modules - # merge environment and module specs + # merge environment and module specs - envs << getvariable('environments') unless getvariable('environments').empty? - mods << getvariable('modules') unless getvariable('modules') .empty? + envs << getvariable('environments') unless getvariable('environments').empty? + mods << getvariable('modules') unless getvariable('modules') .empty? - envs = envs.uniq.join(',') - mods = mods.uniq.join(',') + envs = envs.uniq.join(',') + mods = mods.uniq.join(',') - report("using environments #{envs}") if envs.length > 0 - report("using modules #{mods}") if mods.length > 0 + 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 - setvariable('environments', envs) - setvariable('modules', mods) + setvariable('environments', envs) + setvariable('modules', mods) + end # end of preprocessing and merging - jobsuffix = makestubfile(rawname,forcexml) if dummyfile || forcexml - if globalfile || FileTest.file?(rawname) then if not dummyfile and not globalfile then scantexpreamble(rawname) scantexcontent(rawname) if getvariable('texformats').standard? end - result = File.suffixed(rawname,suffix) unless suffix.empty? - pushresult(rawname,result) + pushresult(rawbase,result) method = validtexmethod(validtexformat(getvariable('texformats'))) @@ -1263,64 +1654,114 @@ class TEX when 'context' then if getvariable('simplerun') || runonce then - makeoptionfile(rawname,jobname,orisuffix,true,true,3) unless getvariable('nooptionfile') - ok = runtex(rawname) + 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(rawname) if getvariable('texutil') || getvariable('forcetexutil') - runbackend(rawname) - popresult(rawname,result) + ok = runtexutil(rawbase) if getvariable('texutil') || getvariable('forcetexutil') + 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 - File.silentdelete(File.suffixed(rawname,'tmp')) - File.silentrename(File.suffixed(rawname,'top'),File.suffixed(rawname,'tmp')) else mprundone, ok, stoprunning = false, true, false texruns, nofruns = 0, getvariable('runs').to_i state = FileState.new ['tub','tuo'].each do |s| - state.register(File.suffixed(rawname,s)) + state.register(File.suffixed(rawbase,s)) end if getvariable('automprun') then # check this ['mprun','mpgraph'].each do |s| - state.register(File.suffixed(rawname,s,'mp'),'randomseed') + state.register(File.suffixed(rawbase,s,'mp'),'randomseed') end end while ! stoprunning && (texruns < nofruns) && ok do texruns += 1 report("TeX run #{texruns}") - if texruns == 1 then - makeoptionfile(rawname,jobname,orisuffix,false,false,1) unless getvariable('nooptionfile') - else - makeoptionfile(rawname,jobname,orisuffix,false,false,2) unless getvariable('nooptionfile') + 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 - ok = runtex(File.suffixed(rawname,jobsuffix)) + ok = runtex(File.suffixed(if dummyfile || forcexml then rawbase else rawname end,jobsuffix)) if ok && (nofruns > 1) then unless getvariable('nompmode') then - mprundone = runtexmpjob(rawname, "mpgraph") - mprundone = runtexmpjob(rawname, "mprun") + mprundone = runtexmpjob(rawbase, "mpgraph") + mprundone = runtexmpjob(rawbase, "mprun") end - ok = runtexutil(rawname) + ok = runtexutil(rawbase) state.update stoprunning = state.stable? end end - ok = runtexutil(rawname) if (nofruns == 1) && getvariable('texutil') + if not ok then + setvariable('error','error in tex file') + end + ok = runtexutil(rawbase) if (nofruns == 1) && getvariable('texutil') if ok && finalrun && (nofruns > 1) then - makeoptionfile(rawname,jobname,orisuffix,true,finalrun,4) unless getvariable('nooptionfile') + makeoptionfile(rawbase,jobname,orisuffix,true,finalrun,4,texruns) unless getvariable('nooptionfile') report("final TeX run #{texruns}") - ok = runtex(File.suffixed(rawname,jobsuffix)) + ok = runtex(File.suffixed(if dummyfile || forcexml then rawbase else rawname end,jobsuffix)) end - ['tmp','top'].each do |s| # previous tuo file / runtime option file - File.silentdelete(File.suffixed(rawname,s)) + 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 - File.silentrename(File.suffixed(rawname,'top'),File.suffixed(rawname,'tmp')) + # ['tmp','top','log'].each do |s| # previous tuo file / runtime option file / log file + # File.silentdelete(File.suffixed(rawbase,s)) + # end if ok then - runbackend(rawname) - popresult(rawname,result) + runbackend(rawbase) + popresult(rawbase,result) + end + if true then # autopurge + begin + File.open(File.suffixed(rawbase, 'tuo')) 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+)/mois 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+)/mois 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',rawname,'--purge') if getvariable('purge') - Kpse.runscript('ctxtools',rawname,'--purgeall') if getvariable('purgeall') + Kpse.runscript('ctxtools',rawbase,'--purge') if getvariable('purge') + Kpse.runscript('ctxtools',rawbase,'--purge --all') if getvariable('purgeall') when 'latex' then @@ -1332,63 +1773,61 @@ class TEX end - if (dummyfile or forcexml) and FileTest.file?(rawname) then + if (dummyfile or forcexml) and FileTest.file?(rawbase) then begin - File.delete(File.suffixed(rawname,'run')) + 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 rawname else result end,'pdf')) + PDFview.open(File.suffixed(if result.empty? then rawbase else result end,'pdf')) end + else + report("nothing to process") end end - # mp specific + # 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=true,context=true) + def doruntexmp(mpname,mergebe=nil,context=true,purge=true) texfound = false - mpbetex = Hash.new - mpfile = File.suffixed(mpname,'mp') - mpcopy = File.suffixed(mpname,'copy','mp') - setvariable('mp.file',mpfile) + 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(mpfile) then + if mpdata = File.silentread(mpname) then mpdata.gsub!(/^\#.*\n/o,'') - File.silentrename(mpfile,mpcopy) - texfound = mergebe || mpdata =~ /btex .*? etex/o - if mp = File.silentopen(mpfile,'w') then - mpdata.gsub!(/(btex.*?)\;(.*?etex)/o) do "#{$1}@@@#{$2}" end - mpdata.gsub!(/(\".*?)\;(.*?\")/o) do "#{$1}@@@#{$2}" end - mpdata.gsub!(/\;/o, "\;\n") - mpdata.gsub!(/\n+/o, "\n") - mpdata.gsub!(/(btex.*?)@@@(.*?etex)/o) do "#{$1}\;#{$2}" end - mpdata.gsub!(/(\".*?)@@@(.*?\")/o) do "#{$1};#{$2}" end + 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*\;/o) do + mpdata.gsub!(/beginfig\s*\((\d+)\)\s*\;(.+?)endfig\s*\;/mo) do n, str = $1, $2 - if str =~ /(.*?)(verbatimtex.*?etex)\s*\;(.*)/o then - "beginfig(#{n})\;\n$1$2\;\n#{mpbetex(n)}\n$3\;endfig\;\n" + if str =~ /^(.*?)(verbatimtex.*?etex)\s*\;(.*)$/mo then + "beginfig(#{n})\;\n#{$1}#{$2}\;\n#{mergebe[n]}\n#{$3}\;endfig\;\n" else - "beginfig(#{n})\;\n#{mpbetex(n)}\n#{str}\;endfig\;\n" + "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 - unless mpdata =~ /beginfig\s*\(\s*0\s*\)/o then - mp << mpbetex[0] if mpbetex.key?(0) - end - mp << mpdata # ?? + mp << MPTools::splitmplines(mpdata) mp << "\n" mp << "end" mp << "\n" mp.close end - processmpx(mpname) if texfound + processmpx(mpname,true,true,purge) if texfound if getvariable('batchmode') then options = ' --interaction=batch' elsif getvariable('nonstopmode') then @@ -1398,7 +1837,7 @@ class TEX end # todo plain|mpost|metafun ok = runmp(mpname) - if f = File.silentopen(File.suffixed(mpfile,'log')) then + 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) @@ -1408,32 +1847,63 @@ class TEX end f.close end - File.silentrename(mpfile,"mptrace.tmp") - File.silentrename(mpcopy, mpfile) + File.silentrename(mpname, mpkeep) + File.silentrename(mpcopy, mpname) end end - def processmpx(mpname,context=true) - mpname = File.suffixed(mpname,'mp') - if File.atleast?(mpname,10) && (data = File.silentread(mpname)) then + # 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 - if data =~ /(btex|etex|verbatimtex)/o then - mptex = File.suffixed(mpname,'temp','tex') - mpdvi = File.suffixed(mpname,'temp','dvi') - mplog = File.suffixed(mpname,'temp','log') - mpmpx = File.suffixed(mpname,'temp','mpx') - ok = system("mpto #{mpname} > #{mptex}") - if ok && File.appended(mptex, "\\end\n") then + 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 - ok = RunConTeXtFile(mptex) + localjob.setvariable('texformats',[getvariable('interface')]) unless getvariable('interface').empty? + elsif getvariable('interface').empty? then + localjob.setvariable('texformats',['plain']) else - ok = RunSomeTeXFile(mptex) - end - ok = ok && FileTest.file?(mpdvi) && system("dvitomp #{mpdvi} #{mpmpx}") - [mptex,mpdvi,mplog].each do |mpfil| - File.silentdelete(mpfil) + 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 @@ -1441,6 +1911,14 @@ class TEX end end + def purge_mpx_files(mpname) + unless getvariable('keep') then + ['tex', 'log', 'tui', 'tuo', 'top'].each do |suffix| + File.silentdelete(File.suffixed(mpname,'temp',suffix)) + end + end + end + def checkmpgraphics(mpname) mpoptions = '' if getvariable('makempy') then @@ -1452,12 +1930,12 @@ class TEX mponame = File.suffixed(mpname,'mpo') mpyname = File.suffixed(mpname,'mpy') return false unless File.atleast?(mponame,32) - mpochecksum = State.new.checksum(mponame) + 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 - if f = File.open(mpyname) then + if f = File.silentopen(mpyname) then str = f.gets.chomp f.close if str =~ /^\%\s*mpochecksum\s*\:\s*(\d+)/o then @@ -1470,24 +1948,25 @@ class TEX def checkmplabels(mpname) mpname = File.suffixed(mpname,'mpt') - if File.atleast?(mpname,10) && (mp = File.open(mpname)) then + if File.atleast?(mpname,10) && (mp = File.silentopen(mpname)) then labels = Hash.new while str = mp.gets do - if str =~ /%\s*setup\s*:\s*(.*)/o then - t = $1 - else - t = '' - end - if str =~ /%\s*figure\s*(\d+)\s*:\s*(.*)/o then + 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" + labels[$1] += "#{$2}\n" end end mp.close - return labels if labels.size>0 + if labels.size>0 then + return labels + else + return nil + end end return nil end |