summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorHans Hagen <pragma@wxs.nl>2005-08-15 00:00:00 +0200
committerHans Hagen <pragma@wxs.nl>2005-08-15 00:00:00 +0200
commitf8482bca2d7d031de38b8c751aadf5e2523f1a52 (patch)
treee4d206aab12d18e9a7b3e449e2c87ac0e9e7f9da /scripts
parent94afc97dd44b93da18e681e265b3c2b8666cd3e6 (diff)
downloadcontext-f8482bca2d7d031de38b8c751aadf5e2523f1a52.tar.gz
stable 2005.08.15
Diffstat (limited to 'scripts')
-rw-r--r--scripts/context/perl/texutil.pl4
-rw-r--r--scripts/context/ruby/base/file.rb10
-rw-r--r--scripts/context/ruby/base/kpsefast.rb776
-rw-r--r--scripts/context/ruby/base/tex.rb4
-rw-r--r--scripts/context/ruby/base/texutil.rb113
-rw-r--r--scripts/context/ruby/textools.rb131
-rw-r--r--scripts/context/ruby/tmftools.rb131
7 files changed, 1083 insertions, 86 deletions
diff --git a/scripts/context/perl/texutil.pl b/scripts/context/perl/texutil.pl
index d5e6ef9ea..0a0d29753 100644
--- a/scripts/context/perl/texutil.pl
+++ b/scripts/context/perl/texutil.pl
@@ -1486,7 +1486,7 @@ if (($SavedHow ne $PageHow) && ($PageHow ne "")) {
print TUO "\\registerfrom$SavedLine" }
elsif ($RegisterState eq $RegStat{"t"})
{ FlushSavedLine ;
- print TUO "\\registerto$SavedLine" }
+ print TUO "\\registerto$SavedLine" ; $SavedHow = '' ; }
else
{ if ($CollapseEntries)
{ if ($SavedEntry ne $NextEntry)
@@ -1495,7 +1495,7 @@ if (($SavedHow ne $PageHow) && ($PageHow ne "")) {
{ $SavedTo = $SavedLine }
$SavedEntry = $NextEntry }
else
- { print TUO "\\registerpage$SavedLine" }
+ { print TUO "\\registerpage$SavedLine" ; $SavedHow = '' ; }
}
++$NOfSanePages ;
$LastPage = $Page ;
diff --git a/scripts/context/ruby/base/file.rb b/scripts/context/ruby/base/file.rb
index f6189043c..16a1be09b 100644
--- a/scripts/context/ruby/base/file.rb
+++ b/scripts/context/ruby/base/file.rb
@@ -1,3 +1,13 @@
+# module : base/file
+# copyright : PRAGMA Advanced Document Engineering
+# version : 2002-2005
+# author : Hans Hagen
+#
+# project : ConTeXt / eXaMpLe
+# concept : Hans Hagen
+# info : j.hagen@xs4all.nl
+# www : www.pragma-ade.com
+
require 'ftools'
class File
diff --git a/scripts/context/ruby/base/kpsefast.rb b/scripts/context/ruby/base/kpsefast.rb
new file mode 100644
index 000000000..a519a6be6
--- /dev/null
+++ b/scripts/context/ruby/base/kpsefast.rb
@@ -0,0 +1,776 @@
+# module : base/kpsefast
+# 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: multiple cnf files
+
+class File
+
+ def File.locate_file(path,name)
+ begin
+ files = Dir.entries(path)
+ if files.include?(name) then
+ fullname = File.join(path,name)
+ return fullname if FileTest.file?(fullname)
+ end
+ files.each do |p|
+ fullname = File.join(path,p)
+ if p != '.' and p != '..' and FileTest.directory?(fullname) and result = locate_file(fullname,name) then
+ return result
+ end
+ end
+ rescue
+ # bad path
+ end
+ return nil
+ end
+
+ def File.glob_file(pattern)
+ return Dir.glob(pattern).first
+ end
+
+end
+
+class KPSEFAST
+
+ # formats are an incredible inconsistent mess
+
+ @@suffixes = Hash.new
+ @@formats = Hash.new
+ @@suffixmap = Hash.new
+
+ @@suffixes['gf'] = ['.<resolution>gf'] # todo
+ @@suffixes['pk'] = ['.<resolution>pk'] # todo
+ @@suffixes['tfm'] = ['.tfm']
+ @@suffixes['afm'] = ['.afm']
+ @@suffixes['base'] = ['.base']
+ @@suffixes['bib'] = ['.bib']
+ @@suffixes['bst'] = ['.bst']
+ @@suffixes['cnf'] = ['.cnf']
+ @@suffixes['ls-R'] = ['ls-R', 'ls-r']
+ @@suffixes['fmt'] = ['.fmt', '.efmt', '.efm', '.ofmt', '.ofm', '.oft', '.eofmt', '.eoft', '.eof', '.pfmt', '.pfm', '.epfmt', '.epf', '.xpfmt', '.xpf', '.afmt', '.afm']
+ @@suffixes['map'] = ['.map']
+ @@suffixes['mem'] = ['.mem']
+ @@suffixes['mf'] = ['.mf']
+ @@suffixes['mfpool'] = ['.pool']
+ @@suffixes['mft'] = ['.mft']
+ @@suffixes['mp'] = ['.mp']
+ @@suffixes['mppool'] = ['.pool']
+ @@suffixes['ocp'] = ['.ocp']
+ @@suffixes['ofm'] = ['.ofm', '.tfm']
+ @@suffixes['opl'] = ['.opl']
+ @@suffixes['otp'] = ['.otp']
+ @@suffixes['ovf'] = ['.ovf']
+ @@suffixes['ovp'] = ['.ovp']
+ @@suffixes['graphic/figure'] = ['.eps', '.epsi']
+ @@suffixes['tex'] = ['.tex']
+ @@suffixes['texpool'] = ['.pool']
+ @@suffixes['PostScript header'] = ['.pro']
+ @@suffixes['type1 fonts'] = ['.pfa', '.pfb']
+ @@suffixes['vf'] = ['.vf']
+ @@suffixes['ist'] = ['.ist']
+ @@suffixes['truetype fonts'] = ['.ttf', '.ttc']
+ @@suffixes['web'] = ['.web', '.ch']
+ @@suffixes['cweb'] = ['.w', '.web', '.ch']
+ @@suffixes['enc files'] = ['.enc']
+ @@suffixes['cmap files'] = ['.cmap']
+ @@suffixes['subfont definition files'] = ['.sfd']
+ @@suffixes['lig files'] = ['.lig']
+ @@suffixes['bitmap font'] = []
+ @@suffixes['MetaPost support'] = []
+ @@suffixes['TeX system documentation'] = []
+ @@suffixes['TeX system sources'] = []
+ @@suffixes['Troff fonts'] = []
+ @@suffixes['dvips config'] = []
+ @@suffixes['type42 fonts'] = []
+ @@suffixes['web2c files'] = []
+ @@suffixes['other text files'] = []
+ @@suffixes['other binary files'] = []
+ @@suffixes['misc fonts'] = []
+ @@suffixes['opentype fonts'] = []
+ @@suffixes['pdftex config'] = []
+ @@suffixes['texmfscripts'] = []
+
+ # replacements
+
+ @@suffixes['fmt'] = ['.fmt']
+ @@suffixes['type1 fonts'] = ['.pfa', '.pfb', '.pfm']
+ @@suffixes['tex'] = ['.tex', '.xml']
+ @@suffixes['texmfscripts'] = ['rb','lua','py','pl']
+
+ @@suffixes.keys.each do |k| @@suffixes[k].each do |s| @@suffixmap[s] = k end end
+
+ # TTF2TFMINPUTS
+ # MISCFONTS
+ # TEXCONFIG
+ # DVIPDFMINPUTS
+ # OTFFONTS
+
+ @@formats['gf'] = ''
+ @@formats['pk'] = ''
+ @@formats['tfm'] = 'TFMFONTS'
+ @@formats['afm'] = 'AFMFONTS'
+ @@formats['base'] = 'MFBASES'
+ @@formats['bib'] = ''
+ @@formats['bst'] = ''
+ @@formats['cnf'] = ''
+ @@formats['ls-R'] = ''
+ @@formats['fmt'] = ''
+ @@formats['map'] = 'TEXFONTMAPS'
+ @@formats['mem'] = 'MPMEMS'
+ @@formats['mf'] = 'MFINPUTS'
+ @@formats['mfpool'] = 'MFPOOL'
+ @@formats['mft'] = ''
+ @@formats['mp'] = 'MPINPUTS'
+ @@formats['mppool'] = 'MPPOOL'
+ @@formats['ocp'] = 'OCPINPUTS'
+ @@formats['ofm'] = 'OFMFONTS'
+ @@formats['opl'] = 'OPLFONTS'
+ @@formats['otp'] = 'OTPINPUTS'
+ @@formats['ovf'] = 'OVFFONTS'
+ @@formats['ovp'] = 'OVPFONTS'
+ @@formats['graphic/figure'] = ''
+ @@formats['tex'] = 'TEXINPUTS'
+ @@formats['texpool'] = 'TEXPOOL'
+ @@formats['PostScript header'] = 'TEXPSHEADERS'
+ @@formats['type1 fonts'] = 'T1FONTS'
+ @@formats['vf'] = 'VFFONTS'
+ @@formats['ist'] = ''
+ @@formats['truetype fonts'] = 'TTFONTS'
+ @@formats['web'] = ''
+ @@formats['cweb'] = ''
+ @@formats['enc files'] = 'ENCFONTS'
+ @@formats['cmap files'] = 'CMAPFONTS'
+ @@formats['subfont definition files'] = 'SFDFONTS'
+ @@formats['lig files'] = 'LIGFONTS'
+ @@formats['bitmap font'] = ''
+ @@formats['MetaPost support'] = ''
+ @@formats['TeX system documentation'] = ''
+ @@formats['TeX system sources'] = ''
+ @@formats['Troff fonts'] = ''
+ @@formats['dvips config'] = ''
+ @@formats['type42 fonts'] = 'T42FONTS'
+ @@formats['web2c files'] = 'WEB2C'
+ @@formats['other text files'] = ''
+ @@formats['other binary files'] = ''
+ @@formats['misc fonts'] = ''
+ @@formats['opentype fonts'] = 'OPENTYPEFONTS'
+ @@formats['pdftex config'] = 'PDFTEXCONFIG'
+ @@formats['texmfscripts'] = 'TEXMFSCRIPTS'
+
+ attr_accessor :progname, :engine, :format, :rootpath, :treepath,
+ :verbose, :remember, :scandisk, :diskcache, :renewcache
+
+ @@cacheversion = '1'
+
+ def initialize
+ @rootpath = ''
+ @treepath = ''
+ @progname = 'kpsewhich'
+ @engine = 'pdfetex'
+ @variables = Hash.new
+ @expansions = Hash.new
+ @files = Hash.new
+ @found = Hash.new
+ @kpsevars = Hash.new
+ @lsrfiles = Array.new
+ @verbose = true
+ @remember = true
+ @scandisk = true
+ @diskcache = true
+ @renewcache = false
+ @isolate = false
+
+ @diskcache = false
+ @cachepath = nil
+ @cachefile = 'tmftools.log'
+ end
+
+ def load_cnf
+ unless @treepath.empty? then
+ unless @rootpath.empty? then
+ @treepath = @treepath.split(',').collect do |p| File.join(@rootpath,p) end.join(',')
+ end
+ ENV['TEXMF'] = @treepath
+ ENV['TEXMFCNF'] = File.join(@treepath.split(',').first,'texmf/web2c')
+ end
+ unless @rootpath.empty? then
+ ENV['TEXMFCNF'] = File.join(@rootpath,'texmf/web2c')
+ ENV['SELFAUTOPARENT'] = @rootpath
+ @isolate = true
+ end
+ filenames = [File.join(ENV['TEXMFCNF'] || '.','texmf.cnf')]
+ # <root>/texmf/web2c/texmf.cnf
+ @rootpath = filenames.first
+ 3.times do
+ @rootpath = File.dirname(@rootpath)
+ end
+ filenames.collect! do |f|
+ f.gsub("\\", '/')
+ end
+ filenames.each do |fname|
+ if FileTest.file?(fname) and f = File.open(fname) then
+ while line = f.gets do
+ loop do
+ # concatenate lines ending with \
+ break unless line.sub!(/\\\s*$/o) do
+ f.gets || ''
+ end
+ end
+ case line
+ when /^[\%\#]/o then
+ # comment
+ when /^\s*(.*?)\s*\=\s*(.*?)\s*$/o then
+ key, value = $1, $2
+ unless @variables.key?(key) then
+ value.sub!(/\%.*$/,'')
+ value.sub!(/\~/, "$HOME")
+ @variables[key] = value
+ end
+ @kpsevars[key] = true
+ end
+ end
+ f.close
+ end
+ end
+ end
+
+ def load_lsr
+ @lsrfiles = []
+ simplified_list(expansion('TEXMF')).each do |p|
+ ['ls-R','ls-r'].each do |f|
+ filename = File.join(p,f)
+ if FileTest.file?(filename) then
+ @lsrfiles << [filename,File.size(filename)]
+ break
+ end
+ end
+ end
+ @files = Hash.new
+ if @diskcache then
+ ['HOME','TEMP','TMP','TMPDIR'].each do |key|
+ if ENV[key] then
+ if FileTest.directory?(ENV[key]) then
+ @cachepath = ENV[key]
+ @cachefile = [@rootpath.gsub(/[^A-Z0-9]/io, '-').gsub(/\-+/,'-'),File.basename(@cachefile)].join('-')
+ break
+ end
+ end
+ end
+ if @cachepath and not @renewcache and FileTest.file?(File.join(@cachepath,@cachefile)) then
+ begin
+ if f = File.open(File.join(@cachepath,@cachefile)) then
+ cacheversion = Marshal.load(f)
+ if cacheversion == @@cacheversion then
+ lsrfiles = Marshal.load(f)
+ if lsrfiles == @lsrfiles then
+ @files = Marshal.load(f)
+ end
+ end
+ f.close
+ end
+ rescue
+ @files = Hash.new
+ end
+ end
+ end
+ return if @files.size > 0
+ @lsrfiles.each do |filedata|
+ filename, filesize = filedata
+ filepath = File.dirname(filename)
+ begin
+ path = '.'
+ data = IO.readlines(filename)
+ if data[0].chomp =~ /% ls\-R \-\- filename database for kpathsea\; do not change this line\./io then
+ data.each do |line|
+ case line
+ when /^[a-zA-Z0-9]/o then
+ line.chomp!
+ if @files[line] then
+ @files[line] << path
+ else
+ @files[line] = [path]
+ end
+ when /^\.\/(.*?)\:$/o then
+ path = File.join(filepath,$1)
+ end
+ end
+ end
+ rescue
+ # sorry
+ end
+ end
+ if @diskcache and @cachepath and f = File.open(File.join(@cachepath,@cachefile),'wb') then
+ f << Marshal.dump(@@cacheversion)
+ f << Marshal.dump(@lsrfiles)
+ f << Marshal.dump(@files)
+ f.close
+ end
+ end
+
+ def expand_variables
+ @expansions = Hash.new
+ if @isolate then
+ @variables['TEXMFCNF'] = ENV['TEXMFCNF'].dup
+ @variables['SELFAUTOPARENT'] = ENV['SELFAUTOPARENT'].dup
+ else
+ ENV.keys.each do |e|
+ if e =~ /^([a-zA-Z]+)\_(.*)\s*$/o then
+ @expansions["#{$1}.#{$2}"] = ENV[e].dup
+ else
+ @expansions[e] = ENV[e].dup
+ end
+ end
+ end
+ @variables.keys.each do |k|
+ @expansions[k] = @variables[k].dup unless @expansions[k]
+ end
+ loop do
+ busy = false
+ @expansions.keys.each do |k|
+ @expansions[k].gsub!(/\$([a-zA-Z0-9\_\-]*)/o) do
+ busy = true
+ @expansions[$1] || ''
+ end
+ @expansions[k].gsub!(/\$\{([a-zA-Z0-9\_\-]*)\}/o) do
+ busy = true
+ @expansions[$1] || ''
+ end
+ end
+ break unless busy
+ end
+ @expansions.keys.each do |k|
+ @expansions[k] = @expansions[k].gsub("\\", '/')
+ end
+ end
+
+ def variable(name='')
+ (name and not name.empty? and @variables[name.sub('$','')]) or ''
+ end
+
+ def expansion(name='')
+ (name and not name.empty? and @expansions[name.sub('$','')]) or ''
+ end
+
+ def variable?(name='')
+ name and not name.empty? and @variables.key?(name.sub('$',''))
+ end
+
+ def expansion?(name='')
+ name and not name.empty? and @expansions.key?(name.sub('$',''))
+ end
+
+ def simplified_list(str)
+ lst = str.gsub(/^\{/o,'').gsub(/\}$/o,'').split(",")
+ lst.collect do |l|
+ l.sub(/^[\!]*/,'').sub(/[\/\\]*$/o,'')
+ end
+ end
+
+ def original_variable(variable)
+ if variable?("#{@progname}.#{variable}") then
+ variable("#{@progname}.#{variable}")
+ elsif variable?(variable) then
+ variable(variable)
+ else
+ ''
+ end
+ end
+
+ def expanded_variable(variable)
+ if expansion?("#{variable}.#{@progname}") then
+ expansion("#{variable}.#{@progname}")
+ elsif expansion?(variable) then
+ expansion(variable)
+ else
+ ''
+ end
+ end
+
+ def original_path(filename='')
+ _expanded_path_(original_variable(var_of_format_or_suffix(filename)).split(";"))
+ end
+
+ def expanded_path(filename='')
+ _expanded_path_(expanded_variable(var_of_format_or_suffix(filename)).split(";"))
+ end
+
+ def _expanded_path_(pathlist)
+ i, n = 0, 0
+ pathlist.collect! do |mainpath|
+ mainpath.gsub(/([\{\}])/o) do
+ if $1 == "{" then
+ i += 1 ; n = i if i > n ; "<#{i}>"
+ else
+ i -= 1 ; "</#{i+1}>"
+ end
+ end
+ end
+ n.times do |i|
+ loop do
+ more = false
+ newlist = []
+ pathlist.each do |path|
+ unless path.sub!(/^(.*?)<(#{n-i})>(.*?)<\/\2>(.*?)$/) do
+ pre, mid, post = $1, $3, $4
+ mid.gsub!(/\,$/,',.')
+ mid.split(',').each do |m|
+ more = true
+ if m == '.' then
+ newlist << "#{pre}#{post}"
+ else
+ newlist << "#{pre}#{m}#{post}"
+ end
+ end
+ end then
+ newlist << path
+ end
+ end
+ if more then
+ pathlist = [newlist].flatten # copy -)
+ else
+ break
+ end
+ end
+ end
+ pathlist = pathlist.uniq.collect do |path|
+ p = path.gsub(/^\/+/o) do '' end
+ # p.gsub!(/(.)\/\/(.)/o) do "#{$1}/#{$2}" end
+ # p.gsub!(/\/\/+$/o) do '//' end
+ p.gsub!(/\/\/+/o) do '//' end
+ p
+ end
+ pathlist
+ end
+
+ # todo: ignore case
+
+ def var_of_format(str)
+ @@formats[str] || ''
+ end
+
+ def var_of_suffix(str) # includes .
+ if @@suffixmap.key?(str) then @@formats[@@suffixmap[str]] else '' end
+ end
+
+ def var_of_format_or_suffix(str)
+ if @@formats.key?(@format) then
+ @@formats[@format]
+ elsif @@suffixmap.key?(File.extname(str)) then # extname includes .
+ @@formats[@@suffixmap[File.extname(str)]] # extname includes .
+ else
+ ''
+ end
+ end
+
+end
+
+class KPSEFAST
+
+ # test things
+
+ def list_variables(kpseonly=true)
+ @variables.keys.sort.each do |k|
+ if kpseonly then
+ puts("#{k} = #{@variables[k]}") if @kpsevars[k]
+ else
+ puts("#{if @kpsevars[k] then 'K' else 'E' end} #{k} = #{@variables[k]}")
+ end
+ end
+ end
+
+ def list_expansions(kpseonly=true)
+ @expansions.keys.sort.each do |k|
+ if kpseonly then
+ puts("#{k} = #{@expansions[k]}") if @kpsevars[k]
+ else
+ puts("#{if @kpsevars[k] then 'K' else 'E' end} #{k} = #{@expansions[k]}")
+ end
+ end
+ end
+
+ def list_lsr
+ puts("files = #{@files.size}")
+ end
+
+ def set_test_patterns
+ @variables["KPSE_TEST_PATTERN_A"] = "foo/{1,2}/bar//"
+ @variables["KPSE_TEST_PATTERN_B"] = "!!x{A,B{1,2}}y"
+ @variables["KPSE_TEST_PATTERN_C"] = "x{A,B//{1,2}}y"
+ @variables["KPSE_TEST_PATTERN_D"] = "x{A,B//{1,2,}}//y"
+ end
+
+ def show_test_patterns
+ ['A','B','D'].each do |i|
+ puts ""
+ puts @variables ["KPSE_TEST_PATTERN_#{i}"]
+ puts ""
+ puts expand_path("KPSE_TEST_PATTERN_#{i}").split(File::PATH_SEPARATOR)
+ puts ""
+ end
+ end
+
+end
+
+class KPSEFAST
+
+ # kpse stuff
+
+ def expand_braces(str) # output variable and brace expansion of STRING.
+ _expanded_path_(original_variable(str).split(";")).join(File::PATH_SEPARATOR)
+ end
+
+ def expand_path(str) # output complete path expansion of STRING.
+ _expanded_path_(expanded_variable(str).split(";")).join(File::PATH_SEPARATOR)
+ end
+
+ def expand_var(str) # output variable expansion of STRING.
+ expanded_variable(str)
+ end
+
+ def show_path(str) # output search path for file type NAME
+ expanded_path(var_of_format(str)).join(File::PATH_SEPARATOR)
+ end
+
+ def var_value(str) # output the value of variable $STRING.
+ original_variable(str)
+ end
+
+end
+
+class KPSEFAST
+
+ def find_file(filename)
+ find_files(filename,true)
+ end
+
+ def find_files(filename,first=false)
+ if @remember then
+ stamp = "#{filename}--#{@format}--#{@engine}--#{@progname}"
+ return @found[stamp] if @found.key?(stamp)
+ end
+ pathlist = expanded_path(filename)
+ result = []
+ filelist = if @files.key?(filename) then @files[filename].uniq else nil end
+ done = false
+ pathlist.each do |path|
+ doscan = if path =~ /^\!\!/o then false else true end
+ recurse = if path =~ /\/\/$/o then true else false end
+ pathname = path.dup
+ pathname.gsub!(/^\!+/o, '')
+ done = false
+ if not done and filelist then
+ # checking for exact match
+ if filelist.include?(pathname) then
+ result << pathname
+ done = true
+ end
+ if not done and recurse then
+ # checking for fuzzy //
+ pathname.gsub!(/\/+$/o, '/.*')
+ # pathname.gsub!(/\/\//o,'/[\/]*/')
+ pathname.gsub!(/\/\//o,'/.*?/')
+ re = /^#{pathname}/
+ filelist.each do |f|
+ if re =~ f then
+ result << f # duplicates will be filtered later
+ done = true
+ end
+ break if done
+ end
+ end
+ end
+ if not done and doscan then
+ # checking for path itself
+ pname = pathname.sub(/\.\*$/,'')
+ if not pname =~ /\*/o and FileTest.file?(File.join(pname,filename)) then
+ result << pname
+ done = true
+ end
+ end
+ break if done and first
+ end
+ if not done and @scandisk then
+ pathlist.each do |path|
+ pathname = path.dup
+ unless pathname.gsub!(/^\!+/o, '') then # !! prevents scan
+ recurse = pathname.gsub!(/\/+$/o, '')
+ complex = pathname.gsub!(/\/\//o,'/*/')
+ if recurse then
+ if complex then
+ if ok = File.glob_file("#{pathname}/**/#{filename}") then
+ result << File.dirname(ok)
+ done = true
+ end
+ elsif ok = File.locate_file(pathname,filename) then
+ result << File.dirname(ok)
+ done = true
+ end
+ elsif complex then
+ if ok = File.glob_file("#{pathname}/#{filename}") then
+ result << File.dirname(ok)
+ done = true
+ end
+ elsif FileTest.file?(File.join(pathname,filename)) then
+ result << pathname
+ done = true
+ end
+ break if done and first
+ end
+ end
+ end
+ result = result.uniq.collect do |pathname|
+ File.join(pathname,filename)
+ end
+ @found[stamp] = result if @remember
+ return result # redundant
+ end
+
+end
+
+class KPSEFAST
+
+ class FileData
+ attr_accessor :tag, :name, :size, :date
+ def initialize(tag=0,name=nil,size=nil,date=nil)
+ @tag, @name, @size, @date = tag, name, size, date
+ end
+ def FileData.sizes(a)
+ a.collect do |aa|
+ aa.size
+ end
+ end
+ def report
+ case @tag
+ when 1
+ "deleted | #{@size.to_s.rjust(8)} | #{@date.strftime('%m/%d/%Y %I:%M')} | #{@name}"
+ when 2
+ "present | #{@size.to_s.rjust(8)} | #{@date.strftime('%m/%d/%Y %I:%M')} | #{@name}"
+ when 3
+ "obsolete | #{' '*8} | #{' '*16} | #{@name}"
+ end
+ end
+ end
+
+ def analyze_files(filter='',strict=false,sort='',delete=false)
+ puts("command = #{ARGV.join(' ')}")
+ puts("files = #{@files.size}")
+ puts("filter = #{filter}")
+ puts('')
+ if filter.gsub!(/^not:/,'') then
+ def the_same(filter,filename)
+ not filter or filter.empty? or /#{filter}/ !~ filename
+ end
+ else
+ def the_same(filter,filename)
+ not filter or filter.empty? or /#{filter}/ =~ filename
+ end
+ end
+ @files.keys.each do |name|
+ if @files[name].size > 1 then
+ data = Array.new
+ @files[name].each do |path|
+ filename = File.join(path,name)
+ # if not filter or filter.empty? or /#{filter}/ =~ filename then
+ if the_same(filter,filename) then
+ if FileTest.file?(filename) then
+ if delete then
+ data << FileData.new(1,filename,File.size(filename),File.mtime(filename))
+ begin
+ File.delete(filename) if delete
+ rescue
+ end
+ else
+ data << FileData.new(2,filename,File.size(filename),File.mtime(filename))
+ end
+ else
+ data << FileData.new(3,filename)
+ end
+ end
+ end
+ if data.length > 1 then
+ if strict then
+ # if data.collect do |d| d.size end.uniq! then
+ # data.sort! do |a,b| b.size <=> a.size end
+ # data.each do |d| puts d.report end
+ # puts ''
+ # end
+ data.sort! do |a,b| b.size <=> a.size end
+ bunch = Array.new
+ done = false
+ data.each do |d|
+ if bunch.size == 0 then
+ bunch << d
+ elsif bunch[0].size == d.size then
+ bunch << d
+ else
+ if bunch.size > 1 then
+ bunch.each do |b|
+ puts b.report
+ end
+ done = true
+ end
+ bunch = [d]
+ end
+ end
+ puts '' if done
+ else
+ case sort
+ when 'size' then data.sort! do |a,b| a.size <=> b.size end
+ when 'revsize' then data.sort! do |a,b| b.size <=> a.size end
+ when 'date' then data.sort! do |a,b| a.date <=> b.date end
+ when 'revdate' then data.sort! do |a,b| b.date <=> a.date end
+ end
+ data.each do |d| puts d.report end
+ puts ''
+ end
+ end
+ end
+ end
+ end
+
+end
+
+if false then
+
+ k = KPSEFAST.new # (root)
+ k.set_test_patterns
+ k.load_cnf
+ k.expand_variables
+ k.load_lsr
+
+ k.show_test_patterns
+ # puts k.list_variables
+ # puts k.list_expansions
+ # k.list_lsr
+ # puts k.expansion("$TEXMF")
+ # puts k.expanded_path("TEXINPUTS","context")
+
+ # k.progname, k.engine, k.format = 'context', 'pdfetex', 'tfm'
+ # k.scandisk = false # == must_exist
+ # k.expand_variables
+
+ # 10.times do |i| puts k.find_file('texnansi-lmr10.tfm') end
+
+ # puts "expand braces $TEXMF"
+ # puts k.expand_braces("$TEXMF")
+ # puts "expand path $TEXMF"
+ # puts k.expand_path("$TEXMF")
+ # puts "expand var $TEXMF"
+ # puts k.expand_var("$TEXMF")
+ # puts "expand path $TEXMF"
+ # puts k.show_path('tfm')
+ # puts "expand value $TEXINPUTS"
+ # puts k.var_value("$TEXINPUTS")
+ # puts "expand value $TEXINPUTS.context"
+ # puts k.var_value("$TEXINPUTS.context")
+
+ exit
+
+end
diff --git a/scripts/context/ruby/base/tex.rb b/scripts/context/ruby/base/tex.rb
index e2013b87e..75970bcd8 100644
--- a/scripts/context/ruby/base/tex.rb
+++ b/scripts/context/ruby/base/tex.rb
@@ -118,7 +118,7 @@ class TEX
@@booleanvars = [
'batchmode', 'nonstopmode', 'fast', 'fastdisabled', 'silentmode', 'final',
- 'paranoid', 'notparanoid', 'nobanner', 'once', 'allpatterrns',
+ 'paranoid', 'notparanoid', 'nobanner', 'once', 'allpatterns',
'nompmode', 'nomprun', 'automprun',
'nomapfiles', 'local',
'arrange', 'noarrange',
@@ -873,7 +873,7 @@ class TEX
if getvariable('fast') && ! getvariable('fastdisabled') then
opt << "\\fastmode\n"
end
- if getvariable('silent') then
+ if getvariable('silentmode') then
opt << "\\silentmode\n"
end
if (str = getvariable('separation')) && ! str.empty? then
diff --git a/scripts/context/ruby/base/texutil.rb b/scripts/context/ruby/base/texutil.rb
index 083e11bdb..47c613474 100644
--- a/scripts/context/ruby/base/texutil.rb
+++ b/scripts/context/ruby/base/texutil.rb
@@ -127,12 +127,13 @@ class TeXUtil
class Sorter
def initialize(max=12)
- @rep, @map, @exp = Hash.new, Hash.new, Hash.new
+ @rep, @map, @exp, @div = Hash.new, Hash.new, Hash.new, Hash.new
@max = max
@rexa, @rexb = nil, nil
end
def replacer(from,to='') # and expand
+ @max = [@max,to.length+1].max if to
@rep[from.escaped] = to || ''
end
@@ -140,6 +141,7 @@ class TeXUtil
# sorter.reducer('ij', 'y')
def reducer(from,to='')
+ @max = [@max,to.length+1].max if to
@map[from] = to || ''
end
@@ -147,9 +149,17 @@ class TeXUtil
# sorter.expander('ijligature', 'y')
def expander(from,to=nil)
+ from, to = converted(from), converted(to)
+ @max = [@max,to.length+1].max if to
@exp[from] = to || from || ''
end
+ def division(from,to=nil)
+ from, to = converted(from), converted(to)
+ @max = [@max,to.length+1].max if to
+ @div[from] = to || from || ''
+ end
+
# shortcut("\\ab\\cd\\e\\f", 'iacute')
# shortcut("\\\'\\i", 'iacute')
# shortcut("\\\'i", 'iacute')
@@ -172,9 +182,14 @@ class TeXUtil
end
def remap(str)
- str.gsub(@rexa) do
+ s = str.dup
+ s.gsub!(/(\d+)/o) do
+ $1.rjust(10,'a') # rest is b .. k
+ end
+ s.gsub!(@rexa) do
@rep[$1.escaped]
- end.gsub(@rexb) do
+ end
+ s.gsub!(@rexb) do
token = $1.sub(/\\/o, '')
if @exp.key?(token) then
@exp[token].ljust(@max,' ')
@@ -184,15 +199,20 @@ class TeXUtil
''
end
end
+ s
end
- def preset(shortcuts=[],expansions=[],reductions=[])
- 'a'.upto('z') do |c|
- expander(c)
- end
+ def preset(shortcuts=[],expansions=[],reductions=[],divisions=[])
+ # maybe we should move this to sort-def.tex
+ 'a'.upto('z') do |c| expander(c) ; division(c) end
+ expander('1','b') ; expander('2','c') ; expander('3','e') ; expander('4','f')
+ expander('5','g') ; expander('6','h') ; expander('7','i') ; expander('8','i')
+ expander('9','j') ; expander('0','a') ; expander('-','-') ;
+ # end potential move
shortcuts.each do |s| shortcut(s[0],s[1]) end
expansions.each do |e| expander(e[0],e[1]) end
reductions.each do |r| reducer(r[0],r[1]) end
+ divisions.each do |d| division(d[0],d[1]) end
end
def simplify(str)
@@ -216,6 +236,33 @@ class TeXUtil
return s
end
+ def getdivision(str)
+ @div[str] || str
+ end
+
+ def division?(str)
+ @div.key?(str)
+ end
+
+ private
+
+ def converted(str)
+ if str then
+ str.gsub(/([\+\-]*\d+)/o) do
+ n = $1.to_i
+ if n > 0 then
+ 'z'*n
+ elsif n < 0 then
+ '-'*(-n) # '-' precedes 'a'
+ else
+ ''
+ end
+ end
+ else
+ nil
+ end
+ end
+
end
class Plugin
@@ -328,6 +375,7 @@ class TeXUtil
class Synonym
+ @@debug = false
@@debug = true
def initialize(t, c, k, d)
@@ -386,7 +434,7 @@ class TeXUtil
def MySynonyms::processor(logger)
sorter = Sorter.new
- sorter.preset(eval("MyKeys").shortcuts,eval("MyKeys").expansions,eval("MyKeys").reductions)
+ sorter.preset(eval("MyKeys").shortcuts,eval("MyKeys").expansions,eval("MyKeys").reductions,eval("MyKeys").divisions)
sorter.prepare
@@synonyms.keys.each do |s|
@@synonyms[s].each_index do |i|
@@ -406,6 +454,7 @@ class TeXUtil
class Register
+ @@debug = false
@@debug = true
@@howto = /^(.*?)\:\:(.*)$/o
@@ -474,30 +523,43 @@ class TeXUtil
@@savedhowto, @@savedfrom, @@savedto, @@savedentry = '', '', '', ''
end
- def Register.flush(list,handle)
- #
+ def Register.flush(list,handle,sorter)
+ # a bit messy, quite old mechanism, maybe some day ...
# alphaclass can go, now flushed per class
- #
if list.size > 0 then
@nofentries, @nofpages = 0, 0
current, previous, howto = Array.new, Array.new, Array.new
lastpage, lastrealpage = '', ''
alphaclass, alpha = '', ''
@@savedhowto, @@savedfrom, @@savedto, @@savedentry = '', '', '', ''
-
if @@debug then
list.each do |entry|
- handle << "% [#{entry.sortkey[0,1]}] [#{entry.sortkey.gsub(/#{@@split}/o,'] [')}]\n"
+ handle << "% [#{entry.sortkey.gsub(/#{@@split}/o,'] [')}]\n"
end
end
list.each do |entry|
- testalpha = entry.sortkey[0,1].downcase
+ if entry.sortkey =~ /^(\S+)/o then
+ if sorter.division?($1) then
+ testalpha = sorter.getdivision($1)
+ else
+ testalpha = entry.sortkey[0,1].downcase
+ end
+ else
+ testalpha = entry.sortkey[0,1].downcase
+ end
if testalpha != alpha.downcase or alphaclass != entry.class then
alpha = testalpha
alphaclass = entry.class
if alpha != ' ' then
flushsavedline(handle)
- character = alpha.sub(/([^a-zA-Z])/o) do "\\" + $1 end
+ if alpha =~ /^[a-zA-Z]$/o then
+ character = alpha.dup
+ elsif alpha.length > 1 then
+ # character = "\\getvalue\{#{alpha}\}"
+ character = "\\#{alpha}"
+ else
+ character = "\\#{alpha}"
+ end
handle << "\\registerentry{#{entry.type}}{#{character}}\n"
end
end
@@ -556,6 +618,7 @@ class TeXUtil
elsif entry.state == 3 then # to
Register.flushsavedline(handle)
handle << "\\registerto#{savedline}\n"
+ @@savedhowto = '' # test
elsif @@collapse then
if savedentry != nextentry then
savedFrom = savedline
@@ -564,6 +627,7 @@ class TeXUtil
end
else
handle << "\\registerpage#{savedline}\n"
+ @@savedhowto = '' # test
end
@nofpages += 1
lastpage, lastrealpage = entry.page, entry.realpage
@@ -576,9 +640,11 @@ class TeXUtil
end
@@registers = Hash.new
+ @@sorter = Sorter.new
def MyRegisters::reset(logger)
@@registers = Hash.new
+ @@sorter = Sorter.new
end
def MyRegisters::reader(logger,data)
@@ -602,19 +668,18 @@ class TeXUtil
if @@registers.size > 0 then
@@registers.keys.sort.each do |s|
handle << logger.banner("registers: #{s} #{@@registers[s].size}")
- Register.flush(@@registers[s],handle)
+ Register.flush(@@registers[s],handle,@@sorter)
# report("register #{@@registers[s].class}: #{@@registers[s].@nofentries} entries and #{@@registers[s].@nofpages} pages")
end
end
end
def MyRegisters::processor(logger)
- sorter = Sorter.new
- sorter.preset(eval("MyKeys").shortcuts,eval("MyKeys").expansions,eval("MyKeys").reductions)
- sorter.prepare
+ @@sorter.preset(eval("MyKeys").shortcuts,eval("MyKeys").expansions,eval("MyKeys").reductions,eval("MyKeys").divisions)
+ @@sorter.prepare
@@registers.keys.each do |s|
@@registers[s].each_index do |i|
- @@registers[s][i].build(sorter)
+ @@registers[s][i].build(@@sorter)
end
@@registers[s] = @@registers[s].sort
end
@@ -668,6 +733,7 @@ class TeXUtil
@@shortcuts = Array.new
@@expansions = Array.new
@@reductions = Array.new
+ @@divisions = Array.new
def MyKeys::shortcuts
@@shortcuts
@@ -678,6 +744,9 @@ class TeXUtil
def MyKeys::reductions
@@reductions
end
+ def MyKeys::divisions
+ @@divisions
+ end
def MyKeys::reset(logger)
@@shortcuts = Array.new
@@ -692,6 +761,7 @@ class TeXUtil
when 's' then @@shortcuts.push(data)
when 'e' then @@expansions.push(data)
when 'r' then @@reductions.push(data)
+ when 'd' then @@divisions.push(data)
end
end
@@ -699,9 +769,10 @@ class TeXUtil
end
def MyKeys::processor(logger)
- logger.report("shortcuts: #{@@shortcuts.size}") # logger.report(@@shortcuts.inspect)
+ logger.report("shortcuts : #{@@shortcuts.size}") # logger.report(@@shortcuts.inspect)
logger.report("expansions: #{@@expansions.size}") # logger.report(@@expansions.inspect)
logger.report("reductions: #{@@reductions.size}") # logger.report(@@reductions.inspect)
+ logger.report("divisions : #{@@divisions.size}") # logger.report(@@divisions.inspect)
end
end
diff --git a/scripts/context/ruby/textools.rb b/scripts/context/ruby/textools.rb
index 50b72241a..bf0639328 100644
--- a/scripts/context/ruby/textools.rb
+++ b/scripts/context/ruby/textools.rb
@@ -727,10 +727,10 @@ class Commands
nocheck = @commandline.option('nocheck')
merge = @commandline.option('merge')
- prune = @commandline.option('prune')
+ delete = @commandline.option('delete')
force = @commandline.option('force')
- root = @commandline.argument('first')
- path = @commandline.argument('second')
+ root = @commandline.argument('first').gsub(/\\/,'/')
+ path = @commandline.argument('second').gsub(/\\/,'/')
if FileTest.directory?(root) then
report("scanning #{root}")
@@ -745,6 +745,12 @@ class Commands
report("no files")
return
end
+ rootfiles.collect! do |rf|
+ rf.gsub(/\\/o, '/').sub(/#{root}\//o, '')
+ end
+ rootfiles = rootfiles.delete_if do |rf|
+ FileTest.directory?(File.join(root,rf))
+ end
if FileTest.directory?(path) then
report("scanning #{path}")
@@ -759,83 +765,85 @@ class Commands
report("no files")
return
end
-
- roothash = Hash.new
- pathhash = Hash.new
-
- rootfiles.each do |f|
- if File.file?(f) then
- fd, fb = File.dirname(f), File.basename(f)
- roothash[fb] = if roothash.key?(fb) then nil else fd end
- end
+ pathfiles.collect! do |pf|
+ pf.gsub(/\\/o, '/').sub(/#{path}\//o, '')
end
-
- pathfiles.each do |f|
- if File.file?(f) then
- fd, fb = File.dirname(f), File.basename(f)
- pathhash[fb] = if pathhash.key?(fb) then nil else fd end
- end
+ pathfiles = pathfiles.delete_if do |pf|
+ FileTest.directory?(File.join(path,pf))
end
- donehash = Hash.new
- copied = Array.new
+ root = File.expand_path(root)
+ path = File.expand_path(path)
+
+ donepaths = Hash.new
+ copiedfiles = Hash.new
- pathhash.keys.each do |f|
- if pathhash[f] and roothash[f] then
- p = File.expand_path(File.join(pathhash[f],f)) # destination
- r = File.expand_path(File.join(roothash[f],f))
+ # update existing files, assume similar paths
+
+ report("")
+ pathfiles.each do |f| # destination
+ p = File.join(path,f)
+ if rootfiles.include?(f) then
+ r = File.join(root,f)
if p != r then
- if not FileTest.file?(p) then
- if merge then
- report("merging '#{r}' to '#{p}'")
- begin
- File.copy(r,p) if force
- copied << p
- rescue
- report("merging failed")
- else
- donehash[File.dirname(r)] = File.dirname(p)
- end
- else
- report("not merging '#{r}'")
- end
- elsif nocheck or File.mtime(p) < File.mtime(r) then
+ if nocheck or File.mtime(p) < File.mtime(r) then
+ copiedfiles[File.expand_path(p)] = true
report("updating '#{r}' to '#{p}'")
begin
+ begin File.makedirs(File.dirname(p)) if force ; rescue ; end
File.copy(r,p) if force
- copied << p
rescue
report("updating failed")
- else
- donehash[File.dirname(r)] = File.dirname(p)
end
else
report("not updating '#{r}'")
- report("old > #{File.mtime(p)}")
- report("new > #{File.mtime(r)}")
end
end
end
end
+ # merging non existing files
+
report("")
- donehash.keys.sort.each do |d|
- rootfiles = Dir.glob("#{d}/**/*")
- pathfiles = Dir.glob("#{donehash[d]}/**/*")
- pathfiles.collect! do |file| File.expand_path(file) end
- rootfiles.collect! do |file| File.expand_path(file) end
- difference = pathfiles - rootfiles - copied
- if difference.length > 0 then
- length = 0
- difference.each do |file|
- if l = File.basename(file).length and l > length then length = l end
+ rootfiles.each do |f|
+ donepaths[File.dirname(f)] = true
+ r = File.join(root,f)
+ if not pathfiles.include?(f) then
+ p = File.join(path,f)
+ if p != r then
+ if merge then
+ copiedfiles[File.expand_path(p)] = true
+ report("merging '#{r}' to '#{p}'")
+ begin
+ begin File.makedirs(File.dirname(p)) if force ; rescue ; end
+ File.copy(r,p) if force
+ rescue
+ report("merging failed")
+ end
+ else
+ report("not merging '#{r}'")
+ end
end
- report("")
- difference.sort.each do |file|
- if prune then
- report("deleting '#{file.ljust(length)}'")
+ end
+ end
+
+ # deleting obsolete files
+
+ report("")
+ donepaths.keys.sort.each do |d|
+ pathfiles = Dir.glob("#{path}/#{d}/**/*")
+ pathfiles.each do |p|
+ r = File.join(root,d,File.basename(p))
+ if FileTest.file?(p) and not FileTest.file?(r) and not copiedfiles.key?(File.expand_path(p)) then
+ if delete then
+ report("deleting '#{p}'")
+ begin
+ File.delete(p) if force
+ rescue
+ report("deleting failed")
+ end
else
- report("keeping '#{file.ljust(length)}'")
+ report("not deleting '#{p}'")
end
end
end
@@ -858,7 +866,7 @@ commandline.registeraction('fixafmfiles' , '[pattern] [--recurse]')
commandline.registeraction('mactodos' , '[pattern] [--recurse]')
commandline.registeraction('fixtexmftrees' , '[texmfroot] [--force]')
commandline.registeraction('replacefile' , 'filename [--force]')
-commandline.registeraction('updatetree' , 'fromroot toroot [--force --nocheck --merge --prune]')
+commandline.registeraction('updatetree' , 'fromroot toroot [--force --nocheck --merge --delete]')
commandline.registeraction('downcasefilenames', '[--recurse] [--force]') # not yet documented
commandline.registeraction('stripformfeeds' , '[--recurse] [--force]') # not yet documented
commandline.registeraction('showfont' , 'filename')
@@ -868,7 +876,8 @@ commandline.registeraction('version')
commandline.registerflag('recurse')
commandline.registerflag('force')
-commandline.registerflag('prune')
+commandline.registerflag('merge')
+commandline.registerflag('delete')
commandline.registerflag('nocheck')
commandline.expand
diff --git a/scripts/context/ruby/tmftools.rb b/scripts/context/ruby/tmftools.rb
new file mode 100644
index 000000000..305a52370
--- /dev/null
+++ b/scripts/context/ruby/tmftools.rb
@@ -0,0 +1,131 @@
+#!/usr/bin/env ruby
+
+# program : tmftools
+# copyright : PRAGMA Advanced Document Engineering
+# version : 2005
+# author : Hans Hagen
+#
+# project : ConTeXt
+# concept : Hans Hagen
+# info : j.hagen@xs4all.nl
+# www : www.pragma-ade.com
+
+# The script based alternative is not slower than the kpse one.
+# Loading is a bit faster when the log file is used.
+
+# tmftools [some of the kpsewhich switches]
+
+# tmftools --analyze
+# tmftools --analyze > kpsewhat.log
+# tmftools --analyze --strict > kpsewhat.log
+# tmftools --analyze --delete --force "texmf-local/fonts/.*/somename"
+
+# the real thing
+
+banner = ['TMFTools', 'version 1.0.0 (experimental, no help yet)', '2005', 'PRAGMA ADE/POD']
+
+unless defined? ownpath
+ ownpath = $0.sub(/[\\\/][a-z0-9\-]*?\.rb/i,'')
+ $: << ownpath
+end
+
+require 'base/switch'
+require 'base/logger'
+require 'base/kpsefast'
+
+class Commands
+
+ include CommandBase
+
+ def init_kpse
+ k = KPSEFAST.new
+ k.rootpath = @commandline.option('rootpath')
+ k.treepath = @commandline.option('treepath')
+ k.progname = @commandline.option('progname')
+ k.engine = @commandline.option('engine')
+ k.format = @commandline.option('format')
+ k.diskcache = @commandline.option('diskcache')
+ k.renewcache = @commandline.option('renewcache')
+ k.load_cnf
+ k.expand_variables
+ k.load_lsr
+ return k
+ end
+
+ def main
+ if option = @commandline.option('expand-braces') and not option.empty? then
+ puts init_kpse.expand_braces(option)
+ elsif option = @commandline.option('expand-path') and not option.empty? then
+ puts init_kpse.expand_path(option)
+ elsif option = @commandline.option('expand-var') and not option.empty? then
+ if option == '*' then
+ init_kpse.list_expansions()
+ else
+ puts init_kpse.expand_var(option)
+ end
+ elsif option = @commandline.option('show-path') and not option.empty? then
+ puts init_kpse.show_path(option)
+ elsif option = @commandline.option('var-value') and not option.empty? then
+ if option == '*' then
+ init_kpse.list_variables()
+ else
+ puts init_kpse.expand_var(option)
+ end
+ elsif @commandline.arguments.size > 0 then
+ kpse = init_kpse
+ @commandline.arguments.each do |option|
+ puts kpse.find_file(option)
+ end
+ else
+ help
+ end
+ end
+
+ def analyze
+ pattern = @commandline.argument('first')
+ strict = @commandline.option('strict')
+ sort = @commandline.option('sort')
+ delete = @commandline.option('delete') and @commandline.option('force')
+ init_kpse.analyze_files(pattern, strict, sort, delete)
+ end
+
+end
+
+logger = Logger.new(banner.shift)
+commandline = CommandLine.new
+
+# kpsewhich compatible options
+
+commandline.registervalue('expand-braces','')
+commandline.registervalue('expand-path','')
+commandline.registervalue('expand-var','')
+commandline.registervalue('show-path','')
+commandline.registervalue('var-value','')
+
+commandline.registervalue('engine','')
+commandline.registervalue('progname','')
+commandline.registervalue('format','')
+
+# additional goodies
+
+commandline.registervalue('rootpath','')
+commandline.registervalue('treepath','')
+commandline.registervalue('sort','')
+
+commandline.registerflag('diskcache')
+commandline.registerflag('renewcache')
+commandline.registerflag('strict')
+commandline.registerflag('delete')
+commandline.registerflag('force')
+
+commandline.registeraction('analyze')
+
+# general purpose options
+
+commandline.registerflag('verbose')
+commandline.registeraction('help')
+commandline.registeraction('version')
+
+commandline.expand
+
+Commands.new(commandline,logger,banner).send(commandline.action || 'main')