|
Server : Apache/2.2.2 (Fedora) System : Linux App1.pathumtani.go.th 2.6.20-1.2320.fc5smp #1 SMP Tue Jun 12 19:40:16 EDT 2007 i686 User : apache ( 48) PHP Version : 5.2.9 Disable Function : NONE Directory : /proc/self/root/usr/share/texmf/scripts/context/ruby/ |
Upload File : |
# Program : concheck (tex & context syntax checker)
# Copyright : PRAGMA ADE / Hasselt NL / www.pragma-ade.com
# Author : Hans Hagen
# Version : 1.1 / 2003.08.18
# remarks:
#
# - the error messages are formatted like tex's messages so that scite can see them
# - begin and end tags are only tested on a per line basis because we assume clean sources
# - maybe i'll add begin{something} ... end{something} checking
# # example validation file
#
# begin interface en
#
# 1 text
# 4 Question
# 0 endinput
# 0 setupsomething
# 0 chapter
#
# end interface en
# nicer
# class Interface
# def initialize (language = 'unknown')
# @valid = Array.new
# @language = language
# end
# def register (left, right)
# @valid.push([left,right])
# end
# end
# $interfaces = Hash.new
# $interfaces['en'] = Interface.new('english')
# $interfaces['nl'] = Interface.new('dutch')
# $interfaces['en'].add('\\\\start','\\\\stop')
# $interfaces['en'].add('\\\\begin','\\\\end')
# $interfaces['en'].add('\\\\Start','\\\\Stop')
# $interfaces['en'].add('\\\\Begin','\\\\End')
# $interfaces['nl'].add('\\\\start','\\\\stop')
# $interfaces['nl'].add('\\\\beginvan','\\\\eindvan')
# $interfaces['nl'].add('\\\\Start','\\\\Stop')
# $interfaces['nl'].add('\\\\BeginVan','\\\\Eindvan')
# rest todo
$valid = Hash.new
$valid['en'] = Array.new
$valid['nl'] = Array.new
#$valid['en'].push(['',''])
$valid['en'].push(['\\\\start','\\\\stop'])
$valid['en'].push(['\\\\begin','\\\\end'])
$valid['en'].push(['\\\\Start','\\\\Stop'])
$valid['en'].push(['\\\\Begin','\\\\End'])
#$valid['nl'].push(['',''])
$valid['nl'].push(['\\\\start','\\\\stop'])
$valid['nl'].push(['\\\\beginvan','\\\\eindvan'])
$valid['nl'].push(['\\\\Start','\\\\Stop'])
$valid['nl'].push(['\\\\BeginVan','\\\\Eindvan'])
$valid_tex = "\\\\end\(input|insert|csname|linechar|graf|buffer|strut\)"
$valid_mp = "(enddef||end||endinput)"
$start_verbatim = Hash.new
$stop_verbatim = Hash.new
$start_verbatim['en'] = '\\\\starttyping'
$start_verbatim['nl'] = '\\\\starttypen'
$stop_verbatim['en'] = '\\\\stoptyping'
$stop_verbatim['nl'] = '\\\\stoptypen'
def message(str, filename=nil, line=nil, column=nil)
if filename then
if line then
if column then
puts("error in file #{filename} at line #{line} in column #{column}: #{str}\n")
else
puts("error in file #{filename} at line #{line}: #{str}\n")
end
else
puts("file #{filename}: #{str}\n")
end
else
puts(str+"\n")
end
end
def load_file (filename='')
begin
data = IO.readlines(filename)
data.collect! do |d|
if d =~ /^\s*%/o then
''
elsif d =~ /(.*?[^\\])%.*$/o then
$1
else
d
end
end
rescue
message("provide proper filename")
return nil
end
# print data.to_s + "\n"
return data
end
def guess_interface(data)
if data.first =~ /^%.*interface\=(.*)\s*/ then
return $1
else
data.each do |line|
case line
when /\\(starttekst|stoptekst|startonderdeel|startdocument|startoverzicht)/o then return 'nl'
when /\\(stelle|verwende|umgebung|benutze)/o then return 'de'
when /\\(stel|gebruik|omgeving)/ then return 'nl'
when /\\(use|setup|environment)/ then return 'en'
when /\\(usa|imposta|ambiente)/ then return 'it'
when /(height|width|style)=/ then return 'en'
when /(hoehe|breite|schrift)=/ then return 'de'
when /(hoogte|breedte|letter)=/ then return 'nl'
when /(altezza|ampiezza|stile)=/ then return 'it'
when /externfiguur/ then return 'nl'
when /externalfigure/ then return 'en'
when /externeabbildung/ then return 'de'
when /figuraesterna/ then return 'it'
end
end
return 'en'
end
end
def cleanup_data(data, interface='en')
verbatim = 0
re_start = /^\s*#{$start_verbatim[interface]}/
re_stop = /^\s*#{$stop_verbatim[interface]}/
data.collect! do |d|
if d =~ re_start then
verbatim += 1
if verbatim>1 then
''
else
d
end
elsif d =~ re_stop then
verbatim -= 1
if verbatim>0 then
''
else
d
end
elsif verbatim > 0 then
''
else
d
end
end
return data
end
def load_valid(data, interface=nil)
if data && (data.first =~ /^%.*valid\=(.*)\s*/)
filename = $1
filename = '../' + filename unless test(?f,filename)
filename = '../' + filename unless test(?f,filename)
if test(?f,filename) then
interface = guess_interface(data) unless interface
if $valid.has_key?(interface) then
interface = $valid[interface]
else
interface = $valid['en']
end
begin
message("loading validation file",filename)
validkeys = Hash.new
line = 1
IO.readlines(filename).each do |l|
if l =~ /\s+[\#\%]/io then
# ignore line
elsif l =~ /^\s*(begin|end)\s+interface\s+([a-z][a-z])/o then
# not yet supported
elsif l =~ /^\s*(\d+)\s+([a-zA-Z]*)$/o then
type, key = $1.to_i, $2.strip
if interface[type] then
validkeys[interface[type].first+key] = true
validkeys[interface[type].last+key] = true
else
error_message(filename,line,nil,'wrong definition')
end
end
line += 1
end
if validkeys then
message("#{validkeys.length} validation keys loaded",filename)
end
return validkeys
rescue
message("invalid validation file",filename)
end
else
message("unknown validation file", filename)
end
else
message("no extra validation file specified")
end
return nil
end
def some_chr_error(data, filename, left, right)
levels = Array.new
for line in 0..data.length-1 do
str = data[line]
column = 0
while column<str.length do
case str[column].chr
when "\%" then
break
when "\\" then
column += 2
when left then
levels.push([line,column])
column += 1
when right then
if levels.pop
column += 1
else
message("missing #{left} for #{right}",filename,line+1,column+1)
return true
end
else
column += 1
end
end
end
if levels && levels.length>0 then
levels.each do |l|
column = l.pop
line = l.pop
message("missing #{right} for #{left}",filename,line+1,column+1)
end
return true
else
return false
end
end
def some_wrd_error(data, filename, start, stop, ignore)
levels = Array.new
len = 0
re_start = /[^\%]*(#{start})([a-zA-Z]*)/
re_stop = /[^\%]*(#{stop})([a-zA-Z]*)/
re_ignore = /#{ignore}.*/
str_start = start.gsub(/\\+/,'\\')
str_stop = stop.gsub(/\\+/,'\\')
line = 0
while line<data.length do
dataline = data[line].split(/[^\\A-Za-z]/)
if dataline.length>0 then
# todo: more on one line
dataline.each do |dataword|
case dataword
when re_ignore then
# just go on
when re_start then
levels.push([line,$2])
# print ' '*levels.length + '>' + $2 + "\n"
when re_stop then
# print ' '*levels.length + '<' + $2 + "\n"
if levels && levels.last && (levels.last[1] == $2) then
levels.pop
elsif levels && levels.last then
message("#{str_stop}#{levels.last[1]} expected instead of #{str_stop}#{$2}",filename,line+1)
return true
else
message("missing #{str_start}#{$2} for #{str_stop}#{$2}",filename,line+1)
return true
end
else
# just go on
end
end
end
line += 1
end
if levels && levels.length>0 then
levels.each do |l|
text = l.pop
line = l.pop
message("missing #{str_stop}#{text} for #{str_start}#{text}",filename,line+1)
end
return true
else
return false
end
end
def some_sym_error (data, filename, symbol,template=false)
saved = Array.new
inside = false
level = 0
for line in 0..data.length-1 do
str = data[line]
column = 0
while column<str.length do
case str[column].chr
when "[" then
level += 1 if template
when "]" then
level -= 1 if template && level > 0
when "\%" then
break
when "\\" then
column += 1
when symbol then
if level == 0 then
inside = ! inside
saved = [line,column]
else
# we're in some kind of template or so
end
else
# go on
end
column += 1
end
end
if inside && saved && level == 0 then
column = saved.pop
line = saved.pop
message("missing #{symbol} for #{symbol}",filename,line+1)
return true
else
return false
end
end
def some_key_error(data, filename, valid)
return if (! valid) || (valid.length == 0)
error = false
# data.foreach do |line| ... end
for line in 0..data.length-1 do
data[line].scan(/\\([a-zA-Z]+)/io) do
unless valid.has_key?($1) then
message("unknown command \\#{$1}",filename,line+1)
error = true
end
end
end
return error
end
# todo : language dependent
def check_file_tex (filename)
if data = load_file(filename) then
message("checking tex file", filename)
interface = guess_interface(data)
valid = load_valid(data,interface)
data = cleanup_data(data,interface)
# data.each do |d| print d end
$valid[interface].each do |v|
return false if some_wrd_error(data, filename, v[0], v[1] ,$valid_tex)
end
# return false if some_wrd_error(data, filename, '\\\\start' , '\\\\stop' , $valid_tex)
# return false if some_wrd_error(data, filename, '\\\\Start' , '\\\\Stop' , $valid_tex)
# return false if some_wrd_error(data, filename, '\\\\beginvan', '\\\\eindvan', $valid_tex)
# return false if some_wrd_error(data, filename, '\\\\begin' , '\\\\end|\\\\eind', $valid_tex)
return false if some_sym_error(data, filename, '$', false)
return false if some_sym_error(data, filename, '|', true)
return false if some_chr_error(data, filename, '{', '}')
return false if some_chr_error(data, filename, '[', ']')
return false if some_chr_error(data, filename, '(', ')')
return false if some_key_error(data, filename, valid)
message("no errors in tex code", filename)
return true
else
return false
end
end
def check_file_mp (filename)
if data = load_file(filename) then
message("checking metapost file", filename)
interface = guess_interface(data)
valid = load_valid(data,interface)
$valid[interface].each do |v|
return false if some_wrd_error(data, filename, v[0], v[1] ,$valid_tex)
end
# return false if some_wrd_error(data, filename, '', 'begin', 'end', $valid_mp)
return false if some_chr_error(data, filename, '{', '}')
return false if some_chr_error(data, filename, '[', ']')
return false if some_chr_error(data, filename, '(', ')')
return false if some_key_error(data, filename, valid)
message("no errors in metapost code", filename)
return true
else
return true
end
end
def check_file_text(filename='')
if data = load_file(filename) then
for line in 0..data.length-1 do
# case data[line]
# when /\s([\:\;\,\.\?\!])/ then
# message("space before #{$1}",filename,line+1)
# when /\D([\:\;\,\.\?\!])\S/ then
# message("no space after #{$1}",filename,line+1)
# end
if data[line] =~ /\s([\:\;\,\.\?\!])/ then
message("space before #{$1}",filename,line+1)
else
data[line].gsub!(/\[.*?\]/o, '')
data[line].gsub!(/\(.*?\)/o, '')
data[line].gsub!(/\[.*?$/o, '')
data[line].gsub!(/^.*?\]/o, '')
if data[line] =~ /\D([\:\;\,\.\?\!])\S/ then
message("no space after #{$1}",filename,line+1)
end
end
end
end
end
def check_file(filename='')
case filename
when '' then
message("provide filename")
return false
when /\.tex$/i then
return check_file_tex(filename) # && check_file_text(filename)
when /\.mp$/i then
return check_file_mp(filename)
else
message("only tex and metapost files are checked")
return false
end
end
if filename = ARGV[0] then
if check_file(filename) then
exit 0
else
exit 1
end
else
exit 1
end