#!/usr/bin/env ruby # program : rlxtools # copyright : PRAGMA Advanced Document Engineering # version : 2004-2005 # author : Hans Hagen # # project : ConTeXt / eXaMpLe # concept : Hans Hagen # info : j.hagen@xs4all.nl # www : www.pragma-ade.com banner = ['RlxTools', 'version 1.0.1', '2004/2005', 'PRAGMA ADE/POD'] $: << File.expand_path(File.dirname($0)) ; $: << File.join($:.last,'lib') ; $:.uniq! require 'base/switch' require 'base/logger' require 'base/system' require 'base/kpse' require 'fileutils' # require 'ftools' require 'rexml/document' class Commands include CommandBase # # # # # texmfstart # --verbose # --iftouched=/,/ # pstopdf # --method=5 # --inputpath= # --outputpath=/ # # # # # # # # # figure # found # cow.pdf # pdf # . # lowres # lowres/ # 276.03125pt # 200.75pt # # def manipulate procname = @commandline.argument('first') || '' filename = @commandline.argument('second') || '' procname = Kpse.found(procname) if procname.empty? || ! FileTest.file?(procname) then report('provide valid manipulator file') elsif filename.empty? || ! FileTest.file?(filename) then report('provide valid resource log file') else begin data = REXML::Document.new(File.new(filename)) rescue report('provide valid resource log file (xml error)') return end begin proc = REXML::Document.new(File.new(procname)) rescue report('provide valid manipulator file (xml error)') return end report("manipulator file: #{procname}") report("resourcelog file: #{filename}") begin nofrecords, nofdone = 0, 0 REXML::XPath.each(data.root,"/rl:library/rl:usage") do |usage| nofrecords += 1 variables = Hash.new usage.elements.each do |e| variables[e.name] = e.text.to_s end report("processing record #{nofrecords} (#{variables['file'] || 'noname'}: #{variables.size} entries)") if conversion = variables['conversion'] then report("testing for conversion #{conversion}") if suffix = variables['suffix'] then suffix.downcase! if ! suffix.empty? && variables['file'] && variables['file'] !~ /\.([a-z]+)$/i then variables['file'] += ".#{suffix}" end if file = variables['file'] then report("conversion #{conversion} for suffix #{suffix} for file #{file}") else report("conversion #{conversion} for suffix #{suffix}") end pattern = "@name='#{conversion}' and @suffix='#{suffix}'" if steps = REXML::XPath.first(proc.root,"/rl:manipulators/rl:manipulator[#{pattern}]") then localsteps = steps.deep_clone ['rl:old','rl:new'].each do |tag| REXML::XPath.each(localsteps,tag) do |extras| REXML::XPath.each(extras,"rl:value") do |value| if name = value.attributes['name'] then substitute(value,variables[name.to_s] || '') end end end end old = REXML::XPath.first(localsteps,"rl:old") new = REXML::XPath.first(localsteps,"rl:new") if old && new then old, new = justtext(old.to_s), justtext(new.to_s) variables['old'], variables['new'] = old, new begin [old,new].each do |d| File.makedirs(File.dirname(d)) end rescue report("error during path creation") end report("old file #{old}") report("new file #{new}") level = if File.needsupdate(old,new) then 2 else 0 end else level = 1 end if level>0 then REXML::XPath.each(localsteps,"rl:step") do |command| REXML::XPath.each(command,"rl:old") do |value| replace(value,old) end REXML::XPath.each(command,"rl:new") do |value| replace(value,new) end REXML::XPath.each(command,"rl:value") do |value| if name = value.attributes['name'] then substitute(value,variables[name.to_s]) end end str = justtext(command.to_s) # str.gsub!(/(\.\/)+/io, '') report("command #{str}") System.run(str) unless @commandline.option('test') report("synchronizing #{old} and #{new}") File.syncmtimes(old,new) if level > 1 nofdone += 1 end else report("no need for a manipulation") end else report("no manipulator found") end else report("no suffix specified") end else report("no conversion needed") end end if nofdone > 0 then jobname = filename.gsub(/\.(.*?)$/,'') # not 'tuo' here tuoname = jobname + '.tuo' if FileTest.file?(tuoname) && (f = File.open(tuoname,'a')) then f.puts("%\n% number of rlx manipulations: #{nofdone}\n") f.close end end rescue report("error in manipulating files: #{$!}") end begin logname = "#{filename}.log" File.delete(logname) if FileTest.file?(logname) File.copy(filename,logname) rescue end end end private def justtext(str) str = str.to_s str.gsub!(/<[^>]*?>/o, '') str.gsub!(/\s+/o, ' ') str.gsub!(/</o, '<') str.gsub!(/>/o, '>') str.gsub!(/&/o, '&') str.gsub!(/"/o, '"') str.gsub!(/[\/\\]+/o, '/') return str.strip end def substitute(value,str='') if str then begin if value.attributes.key?('method') then str = filtered(str.to_s,value.attributes['method'].to_s) end if str.empty? && value.attributes.key?('default') then str = value.attributes['default'].to_s end value.insert_after(value,REXML::Text.new(str.to_s)) rescue Exception end end end def replace(value,str) if str then begin value.insert_after(value,REXML::Text.new(str.to_s)) rescue Exception end end end def filtered(str,method) str = str.to_s # to be sure case method when 'name' then # no path, no suffix case str when /^.*[\\\/](.+?)\..*?$/o then $1 when /^.*[\\\/](.+?)$/o then $1 when /^(.*)\..*?$/o then $1 else str end when 'path' then if str =~ /^(.+)([\\\/])(.*?)$/o then $1 else '' end when 'suffix' then if str =~ /^.*\.(.*?)$/o then $1 else '' end when 'nosuffix' then if str =~ /^(.*)\..*?$/o then $1 else str end when 'nopath' then if str =~ /^.*[\\\/](.*?)$/o then $1 else str end else str end end end class Commands include CommandBase @@xmlbanner = "" def identify(resultfile='rlxtools.rli') if @commandline.option('collect') then begin File.open(resultfile,'w') do |f| f << "#{@@xmlbanner}\n" f << "\n" @commandline.arguments.each do |filename| if state = do_identify(filename) then report("#{filename} is identified") f << state else report("unable to identify #{filename}") end end f << "\n" report("result saved in #{resultfile}") end rescue report("error in writing result") end else @commandline.arguments.each do |filename| if state = do_identify(filename) then begin File.open(filename+'.rli','w') do |f| f << "#{@@xmlbanner}\n" f << state end rescue report("error in identifying #{filename}") else report("#{filename} is identified") end else report("unable to identify #{filename}") end end end end private def do_identify(filename,centimeters=false) begin str = nil if FileTest.file?(filename) then # todo: use pdfinto for pdf files, identify is bugged if centimeters then result = `identify -units PixelsPerCentimeter -format \"x=%x,y=%y,w=%w,h=%h,b=%b\" #{filename}`.chomp.split(',') else result = `identify -units PixelsPerInch -format \"x=%x,y=%y,w=%w,h=%h,b=%b\" #{filename}`.chomp.split(',') end tags = Hash.new result.each do |r| if rr = r.split("=") then tags[rr[0]] = rr[1] end end size = (tags['b']||0).to_i width = unified(tags['w']||0,tags['x']||'1') height = unified(tags['h']||0,tags['y']||'1') if size > 0 then str = '' str << "\n" str << " #{size}\n" str << " #{File.dirname(filename).sub(/\\/o,'/')}\n" str << " #{width}\n" str << " #{height}\n" str << "\n" end else str = nil end rescue str = nil end return str end def unified(dim,res) case res when /([\d\.]+)\s*PixelsPerInch/io then sprintf("%.4fin",dim.to_f/$1.to_f) when /([\d\.]+)\s*PixelsPerCentimeter/io then sprintf("%.4fcm",dim.to_f/$1.to_f) when /([\d\.]+)\s*PixelsPerMillimeter/io then sprintf("%.4fmm",dim.to_f/$1.to_f) when /([\d\.]+)\s*PixelsPerPoint/io then sprintf("%.4fbp",dim.to_f/$1.to_f) else sprintf("%.4fbp",dim.to_f) end end end logger = Logger.new(banner.shift) commandline = CommandLine.new commandline.registeraction('manipulate', '[--test] manipulatorfile resourselog') commandline.registeraction('identify' , '[--collect] filename') commandline.registeraction('help') commandline.registeraction('version') commandline.registerflag('test') commandline.registerflag('collect') commandline.expand Commands.new(commandline,logger,banner).send(commandline.action || 'help')