#!/usr/bin/env ruby #-- # Last Change: Tue May 16 18:13:36 2006 #++ =begin rdoc == pldiff -- show the differences between two (v)pl files. Usage: pldiff [options] file file file can be tfm, pl, vpl or vf files. -d, --delta DELTA Don't report differences whithin +/- DELTA percent -c, --ignore-comments ignore comments -k, --ignore-kern ignore difference in kerning information -m, --mapenc ENC assume encoding ENC for destination encoding -t, --texenc ENC assume encoding ENC for source encoding (TeX side) -e, --encoding ENC assume encoding ENC for both in and out -s, --skip-characters only look at fontdimen and main data -h, --help Show this help --- Author:: Patrick Gundlach License:: Copyright (c) 2005 Patrick Gundlach. Released under the terms of the GNU General Public License =end # :enddoc: require 'optparse' require 'ostruct' require 'rfil/tex/kpathsea' require 'rfil/tex/enc' require 'rfil/tex/tfm' require 'rfil/tex/vf' include RFIL def showmap(mapary) str = "" if mapary mapary.each { |entry| str << " | " << entry.join(" ") << "\n" } end str end def plopen(filename) case filename when /\.tfm$/ return TFM.new.read_tfm(filename) when /\.vf$/ # change to that dir first currentdir=Dir.getwd dirname=File.dirname(filename) Dir.chdir(dirname) fn=File.basename(filename) vf=VF.new.read_vf(filename) Dir.chdir(currentdir) return vf when /\.pl$/ return TFM.new.read_pl(filename) when /\.vpl$/ return TFM.new.read_pl(filename) else puts "Unknown format: #{filename}" exit 1 end end include TeX options=OpenStruct.new kpse=Kpathsea.new ARGV.options { |opts| opts.banner = "Usage: #{File.basename($0)} [options] file file" opts.separator "file can be tfm, pl, vpl or vf files." opts.on("--delta","-d DELTA", Float, "Don't report differences whithin +/- DELTA percent") { |d| options.delta=d } opts.on("--ignore-comments", "-c", "ignore comments") { |i| options.ignore_comments=true } opts.on("--ignore-kern", "-k", "ignore difference in kerning information") { |k| options.ignore_kern=true } opts.on("--mapenc", "-m ENC", "assume encoding ENC for destination encoding") {|e| options.mapencoding=e } opts.on("--texenc", "-t ENC", "assume encoding ENC for source encoding (TeX side)") {|e| options.texencoding=e } opts.on("--encoding", "-e ENC", "assume encoding ENC for both in and out") {|e| options.encoding=e } opts.on("--skip-characters", "-s", "only look at fontdimen and main data") {|s| options.skip=true } opts.on_tail("--help", "-h", "Show this help") { puts opts; exit 0 } opts.separator "" opts.parse! } # untested: if options.encoding kpse.open_file(options.encoding,"enc") { |f| options.encoding = ENC.new(f) } options.mapencoding=options.encoding options.texencoding=options.encoding end if options.mapencoding.instance_of?(String) kpse.open_file(options.mapencoding,"enc") { |f| options.mapencoding = ENC.new(f) } end if options.texencoding.instance_of?(String) kpse.open_file(options.texencoding,"enc") { |f| options.texencoding = ENC.new(f) } end if ARGV.size != 2 puts "#{File.basename($0)}: Need exactly two file arguments." puts "Try `#{File.basename($0)} --help' for more information." exit 0 end p1 = plopen(ARGV[0]) p2 = plopen(ARGV[1]) percent = options.delta ? options.delta/50.0 : 0 [:fontfamily,:codingscheme,:designsize].each { |sym| if p1.send(sym) != p2.send(sym) puts "#{sym} differ: #{p1.send(sym)} vs #{p2.send(sym)}" end } fd1 = p1.params fd2 = p2.params str = "" if fd1.size != fd2.size str << "Difference in number of parameters (fontdimen)" end paramname=%w( X SLANT SPACE STRETCH SHRINK XHEIGHT QUAD EXTRASPACE ) if p1.codingscheme=="TeX math symbols" paramname += %w(NUM1 NUM2 NUM3 DENOM1 DENOM2 SUP1 SUP2 SUP3 SUB1 SUB2 SUPDROP) elsif p1.codingscheme=="TeX math extension" paramname += %w(DEFAULT_RULE_THICKNESS BIG_OP_SPACING1 BIG_OP_SPACING2 BIG_OP_SPACING3 BIG_OP_SPACING4 BIG_OP_SPACING5) end for i in 1..fd1.size next if fd1[i] == fd2[i] if fd1[i]==nil str << "Difference in #{paramname[i]}: nil vs. #{fd2[i]}" << "\n" elsif fd2[i]==nil str << "Difference in #{paramname[i]}: #{fd1[i]} vs. nil" << "\n" elsif (fd1[i] - fd2[i] ).abs > fd1[i] * percent str << "Difference in #{paramname[i]}: #{fd1[i]} vs. #{fd2[i]}" << "\n" end end if str.size > 0 puts "--------------------" puts "fondimen difference:" puts str puts "--------------------" end exit if options.skip==true str= "" 0.upto(255) do |i| a=p1.chars[i] b=p2.chars[i] next unless a and b l1=a[:lig_kern] ? p1.lig_kern[a[:lig_kern]] : nil l2=b[:lig_kern] ? p2.lig_kern[b[:lig_kern]] : nil next if a==b and l1==l2 if a==nil str << "#{i}: no character at this slot in font 1" << "\n" elsif b==nil str << "#{i}: no character at this slot in font 2" << "\n" else chr="" [:charwd, :charht, :chardp, :charic].each { |dim| next if a[dim].to_f==b[dim].to_f if a[dim]==nil chr << " Difference in #{dim}: nil vs. #{b[dim]}" << "\n" elsif b[dim]==nil chr << " Difference in #{dim}: #{b[dim]} vs. nil" << "\n" elsif (a[dim] - b[dim]).abs > a[dim] * percent chr << " Difference in #{dim}: #{a[dim]} vs. #{b[dim]}" << "\n" end } if l1 != l2 and options.ignore_kern != true chr << " Difference in kern information" << "\n" if l1==nil str << " no lig/kern information for first font \n" elsif l2==nil str << " no lig/kern information for second font \n" else chr << " in font1 but not in font 2:" << (l1 - l2).join(" ").to_s << "\n" chr << " in font2 but not in font 1:" << (l2 - l1).join(" ").to_s << "\n" end end # if a[:ligkern] and b[:ligkern] # if a[:ligkern][:lig] != b[:ligkern][:lig] # chr << " Difference in lig information" << "\n" # if a[:ligkern][:lig] # a[:ligkern][:lig].each { |lig| # chr << " | " << lig.inspect << "\n" # } # else # chr << "nil" # end # chr << " vs.\n" # if b[:ligkern][:lig] # b[:ligkern][:lig].each { |lig| # chr << " | " << lig.inspect << "\n" # } # else # chr << "nil" # end # end # if a[:ligkern][:krn] # (a[:ligkern][:krn] - b[:ligkern][:krn]).each { |lig| # if options.mapencoding # chr << " | [#{options.mapencoding[lig[0]]} #{lig[1]}]\n" # else # chr << " | " << lig.inspect << "\n" # end # } # else # chr << "nil" # end # chr << " vs.\n" # if b[:ligkern][:krn] # (b[:ligkern][:krn] - a[:ligkern][:krn]).each { |lig| # if options.mapencoding # chr << " | [#{options.mapencoding[lig[0]]} #{lig[1]}]\n" # else # chr << " | " << lig.inspect << "\n" # end # } # else # chr << "nil" # end #end # end if a[:dvi] != b[:dvi] chr << " Difference in map\n" chr << showmap(a[:map]) chr << " vs.\n" chr << showmap(b[:map]) end if chr.length > 0 str << "#{i}: " if options.texencoding str << options.texencoding[i] end str << "\n" str << chr end end end if str.length > 0 puts "Character entries:" puts "------------------" puts str end