#!/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')