mirror of https://github.com/CGAL/cgal
382 lines
10 KiB
Ruby
Executable File
382 lines
10 KiB
Ruby
Executable File
#!/usr/bin/ruby
|
|
|
|
require 'xml/libxml'
|
|
|
|
class Logger
|
|
def initialize
|
|
@level = 4 # FATAL > ERROR > WARN > INFO > MOREINFO > DEBUG
|
|
end
|
|
|
|
def debug( msg )
|
|
log( 0, msg )
|
|
end
|
|
|
|
def moreinfo( msg )
|
|
log( 1, msg )
|
|
end
|
|
|
|
def info( msg )
|
|
log( 2, msg )
|
|
end
|
|
|
|
def warn( msg )
|
|
log( 3, "! Warning: " + msg )
|
|
end
|
|
|
|
def error( msg )
|
|
log( 4, "!! Error: " + msg )
|
|
end
|
|
|
|
def fatal( msg )
|
|
puts "!!! Fatal: " + msg
|
|
end
|
|
|
|
def log( l, msg )
|
|
if l >= @level then
|
|
puts msg
|
|
end
|
|
end
|
|
|
|
def decrease_level( n )
|
|
@level -= n
|
|
end
|
|
end
|
|
|
|
def internal_test
|
|
s=normalize_function_declaration( "template<class XX, typename YY=bla<blubb> >void bla(XX a, XX b, YY c)" )
|
|
fail unless s=="void bla($0,$0,$1)"
|
|
s=normalize_function_declaration( "template<class XX, typename YY=bla<blubb> > void bla(XX a, XX b, xYYz c)" )
|
|
fail unless s=="void bla($0,$0,xYYz)"
|
|
|
|
s=normalize_function_declaration( "template< class ForwardIterator1, class ForwardIterator2, class Callback > void box_intersection_all_pairs_d( ForwardIterator1 begin1, ForwardIterator1 end1, ForwardIterator2 begin2, ForwardIterator2 end2, Callback callback, Box_intersection_d::Topology topology = Box_intersection_d<bla<blubb>::blubber>::CLOSED);" )
|
|
fail unless s=="void box_intersection_all_pairs_d($0,$0,$1,$1,$2,Box_intersection_d::Topology);"
|
|
end
|
|
|
|
# input: "template<class XX>void bla(XX t)"
|
|
# result: void bla($1 t)
|
|
def normalize_template_parameters( decl )
|
|
typemap=Hash.new
|
|
if decl =~ /^template\s*/ then
|
|
decl=$'
|
|
outer, inner, rest = split_nesting_levels( '<', '>', decl )
|
|
$log.debug "outer: #{outer} inner: #{inner} rest: #{rest}"
|
|
decl=rest.sub( /^\s*>/, "" )
|
|
counter = 0
|
|
protected_split( '<', '>', ',', inner ).each do |x|
|
|
x=x.gsub( /(class|typename)/, "" )
|
|
x=x.gsub( /=.*$/, "" ).strip
|
|
$log.debug "typemap[#{x}]=$#{counter}"
|
|
typemap[x]="$#{counter}"
|
|
counter+=1
|
|
end
|
|
end
|
|
return decl, typemap
|
|
end
|
|
|
|
def normalize_declaration( decl )
|
|
decl = decl.gsub( /\s+/, ' ' );
|
|
decl = decl.gsub( /(\w) ([&()=:;,<>])/, '\1\2' );
|
|
decl = decl.gsub( /([()=:;,<>]) (\w)/, '\1\2' );
|
|
decl = decl.gsub( /([()=:;,<>]) ([&();,])/, '\1\2' );
|
|
decl = decl.gsub( /([();,]) ([()=:;,<>])/, '\1\2' );
|
|
return decl.strip
|
|
end
|
|
|
|
|
|
def normalize_function_declaration( decl )
|
|
decl = normalize_declaration( decl )
|
|
decl,typemap = normalize_template_parameters( decl )
|
|
if decl =~ /([^(]+[(])/ then
|
|
decl=$1+remove_argnames($',typemap)
|
|
end
|
|
end
|
|
|
|
# input: s="xxxx<<dskd>dsad>dssd<x>"
|
|
# returns: outer="xxxx<>dssd<>" inner="<dskd>dsad",x
|
|
def split_nesting_levels( openchar, closechar, s, nesting_level = 0 )
|
|
inner = ""
|
|
outer = ""
|
|
rest = ""
|
|
closed = false
|
|
s.each_byte do |c|
|
|
if closed then
|
|
rest << c
|
|
next
|
|
end
|
|
char = ""
|
|
char << c
|
|
if char == closechar then
|
|
nesting_level -= 1
|
|
closed = true
|
|
end
|
|
if nesting_level <= 0 then
|
|
outer << char
|
|
else
|
|
inner << char
|
|
end
|
|
if char == openchar then nesting_level += 1 end
|
|
end
|
|
return outer, inner, rest
|
|
end
|
|
|
|
# input s="a, b=c<d>::e<f<g> >, h,y"
|
|
# returns:
|
|
# part: a
|
|
# part: b=c<d>::e<f<g> >
|
|
# part: h
|
|
# part: y
|
|
def protected_split( openchar, closechar, splitchar, s, nesting_level = 0 )
|
|
result_array = Array.new
|
|
part = ""
|
|
char = ""
|
|
s.each_byte do |c|
|
|
char = ""
|
|
char << c
|
|
if char == closechar then nesting_level -= 1 end
|
|
if char == openchar then nesting_level += 1 end
|
|
if char == splitchar then
|
|
if nesting_level == 0 then
|
|
#puts "new part: #{part}"
|
|
result_array << part
|
|
part = ""
|
|
end
|
|
else
|
|
part << char
|
|
end
|
|
end
|
|
if char != splitchar then
|
|
result_array << part
|
|
end
|
|
return result_array
|
|
end
|
|
|
|
|
|
def split_typename( decl )
|
|
nesting_level = 0
|
|
position = 0
|
|
result = ""
|
|
decl.each_byte do |c|
|
|
char = ""
|
|
char << c
|
|
#puts decl.slice( position, decl.length )
|
|
case char
|
|
when '<' then nesting_level += 1
|
|
when '>' then nesting_level -= 1
|
|
when /[,)]/
|
|
if nesting_level == 0 then
|
|
return result, decl.slice( position, decl.length )
|
|
end
|
|
end
|
|
result << c
|
|
position += 1
|
|
end
|
|
return result, ""
|
|
end
|
|
|
|
def remove_argnames( decl, typemap )
|
|
result = ""
|
|
until decl =~ /^[)]/ || decl == "" do
|
|
type_with_default, decl = split_typename( decl )
|
|
$log.debug "type with default: #{type_with_default}"
|
|
# remove default
|
|
if type_with_default =~ /^([^=]+)=/ then
|
|
type = $1
|
|
else
|
|
type = type_with_default
|
|
end
|
|
# remove argname (preserving declarators like * and [])
|
|
if type =~ /\s*(\*+)?\s*\w+(\[\w+\])?$/ then
|
|
type = $`
|
|
type += $1 if $1 != nil
|
|
type += $2 if $2 != nil
|
|
end
|
|
if typemap.has_key?( type ) then
|
|
type = typemap[type]
|
|
end
|
|
result << type
|
|
if( decl =~ /,/ ) then
|
|
result << ","
|
|
decl = $'
|
|
end
|
|
$log.debug "type: [#{type}] \t ......rest: #{decl}"
|
|
end
|
|
return result + decl
|
|
end
|
|
|
|
|
|
#def match_and_consume( s, regex_string )
|
|
# printf " match: [#{regex_string}] .. "
|
|
# regex = Regexp.new( regex_string )
|
|
# if s =~ regex then
|
|
# s = s.sub( regex, "" )
|
|
# #puts "ok! remaining #{s}"
|
|
# return true
|
|
# end
|
|
# return false
|
|
#end
|
|
|
|
|
|
# convenience class
|
|
#class Declaration
|
|
# def initialize( name )
|
|
# @name = name
|
|
# end
|
|
#
|
|
# def match( regex_string )
|
|
# name = match_and_consume( name, regex_string )
|
|
# end
|
|
#
|
|
#end
|
|
|
|
class Doxygen
|
|
def initialize( filename )
|
|
@doxy_xml=XML::Document.file(filename)
|
|
@items = {}
|
|
end
|
|
|
|
def member_matches_texname?( memberdef, texname, strip_const_from_return_types )
|
|
is_const=""
|
|
if memberdef['const'] == 'yes' then
|
|
is_const = "const"
|
|
end
|
|
argsstring=get_xpath_content(memberdef,'argsstring')
|
|
type=get_xpath_content(memberdef,'type')
|
|
if strip_const_from_return_types then
|
|
type=type.gsub( /_const_/, "_" )
|
|
end
|
|
name=get_xpath_content(memberdef,'name')
|
|
templateparamlist=""
|
|
memberdef.find( 'templateparamlist/param' ).each do |param|
|
|
declname=get_xpath_content(param,'declname')
|
|
templateparamlist += declname+","
|
|
end
|
|
if templateparamlist != "" then
|
|
templateparamlist.gsub!( /,$/, "" )
|
|
templateparamlist = "template<#{templateparamlist}>"
|
|
end
|
|
doxyname=templateparamlist+"#{type} #{name}#{argsstring};"
|
|
doxyname=normalize_function_declaration( doxyname )
|
|
$log.moreinfo " doxyname: #{doxyname}"
|
|
return doxyname == texname
|
|
end
|
|
|
|
def find_member( compoundname, memberkind, texname )
|
|
$log.moreinfo "-- raw texname: "+texname
|
|
texname=normalize_function_declaration( texname )
|
|
$log.moreinfo "- find_member"
|
|
$log.moreinfo "-- compoundname: #{compoundname}"
|
|
$log.moreinfo "-- memberkind: #{memberkind}"
|
|
$log.moreinfo "-- texname: #{texname}"
|
|
xpath_ckind='(@kind=\'struct\' or @kind=\'class\' or @kind=\'namespace\')'
|
|
xpath_cname="(compoundname=\'#{compoundname}\')"
|
|
xpath_mkind="(@kind=\'#{memberkind}\')"
|
|
#xpath_mname="(name=\'#{membername}\')"
|
|
xpath_compound="/doxygen/compounddef[#{xpath_ckind} and #{xpath_cname}]"
|
|
xpath_member="/sectiondef/memberdef[#{xpath_mkind}]" # and #{xpath_mname}
|
|
xpath_query="#{xpath_compound}#{xpath_member}"
|
|
#puts "xpath query: #{xpath_query}"
|
|
|
|
for strip_const_from_return_type in [false,true]
|
|
@doxy_xml.find( xpath_query ).each do |memberdef|
|
|
if member_matches_texname?( memberdef, texname, strip_const_from_return_type )
|
|
return memberdef
|
|
end
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
end
|
|
|
|
class Tex
|
|
def initialize( filename, doxy )
|
|
@tex_xml = XML::Document.file( filename )
|
|
@doxy = doxy
|
|
end
|
|
|
|
def list_all_refpages()
|
|
@tex_xml.find('/manual_tools_output/package').each do |package|
|
|
$log.info "package: #{package['id']}"
|
|
package.find('refpage[refcat!=\'Concept\']').each do |refpage|
|
|
scope=get_xpath_content(refpage,'globalscope')
|
|
refcat=get_xpath_content(refpage,'refcat')
|
|
compoundname = "#{scope}#{refpage['id']}" # if applicable
|
|
case refcat
|
|
when /Function/ then compoundname=scope.gsub( /::$/, '' )
|
|
end
|
|
|
|
$log.info "refpage id: #{refpage['id']} \tscope: #{scope} \trefcat: #{refcat}"
|
|
refpage.find('item').each do |item|
|
|
name=get_xpath_content(item,'name')
|
|
kind=get_xpath_content(item,'kind')
|
|
comment=get_xpath_content(item,'comment')
|
|
#puts " item name: #{name}"
|
|
#puts " item kind: #{kind}"
|
|
#puts " item comment: #{comment}"
|
|
|
|
$log.moreinfo "compoundname: #{compoundname}"
|
|
|
|
if kind == "memberfunction" || kind == "constructor" then
|
|
kind="function"
|
|
elsif kind == "nested_type" then
|
|
kind="typedef"
|
|
end
|
|
|
|
memberdef=@doxy.find_member( compoundname , kind, name )
|
|
if memberdef == nil then
|
|
$log.error "did not find doxygen equivalent for \"#{name}\" in \"#{compoundname}\""
|
|
else
|
|
definition=get_xpath_content(memberdef,'definition')
|
|
$log.info "OK! found memberdef: #{definition}"
|
|
end
|
|
end # each item
|
|
end # each refpage
|
|
end # each package
|
|
end # def list_all_refpages
|
|
|
|
end
|
|
|
|
def get_xpath_content( node, xpath )
|
|
s=node.find( xpath ).to_a.first.to_s
|
|
if s == nil then
|
|
return ""
|
|
else
|
|
return s.strip
|
|
end
|
|
end
|
|
|
|
|
|
$log = Logger.new
|
|
|
|
for x in 0...ARGV.length do
|
|
case ARGV[x]
|
|
when /^-v(.*)$/
|
|
if $1 != nil then
|
|
$log.decrease_level( $1.length )
|
|
end
|
|
$log.decrease_level( 1 )
|
|
when /^-doxy$/
|
|
x += 1
|
|
fail "-doxy needs an argument" unless x < ARGV.length
|
|
doxyfilename = ARGV[x]
|
|
when /^-tex$/
|
|
x += 1
|
|
fail "-tex needs an argument" unless x < ARGV.length
|
|
texfilename = ARGV[x]
|
|
end
|
|
end
|
|
|
|
fail "-doxy and -tex are required" if texfilename == nil || doxyfilename == nil
|
|
|
|
doxy = Doxygen.new( doxyfilename )
|
|
tex = Tex.new( texfilename, doxy )
|
|
|
|
tex.list_all_refpages
|
|
|
|
#s = remove_argnames( "long int bla=CGAL::my_default_value<xxx<yyy>::bla>,bool blubb)" )
|
|
#s = remove_argnames( "void bla(type<param> bla,bool blubb,float x)const;" )
|
|
#s = normalize_declaration( "void bla(NT values[D],int *bla = default);" )
|
|
#puts "result: #{s}"
|
|
|
|
#puts normalize_function_declaration( "template<class XX, typename YY=bla<blubb> >void bla(XX a, XX b, YY c)" #)
|
|
|