########################################################################### # Module for ABI Compliance Checker to create ABI dumps in XML format # # Copyright (C) 2009-2011 Institute for System Programming, RAS # Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies) # Copyright (C) 2011-2012 ROSA Laboratory # Copyright (C) 2012-2015 Andrey Ponomarenko's ABI Laboratory # # Written by Andrey Ponomarenko # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License or the GNU Lesser # General Public License as published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # and the GNU Lesser General Public License along with this program. # If not, see <http://www.gnu.org/licenses/>. ########################################################################### use strict; my $TAG_ID = 0; my $INDENT = " "; sub createXmlDump($) { my $ABI = $_[0]; my $ABI_DUMP = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; $ABI_DUMP .= "<ABI_dump version=\"".$ABI->{"ABI_DUMP_VERSION"}."\""; $ABI_DUMP .= " xml_format=\"".$ABI->{"XML_ABI_DUMP_VERSION"}."\""; $ABI_DUMP .= " acc=\"".$ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"}."\">\n"; $ABI_DUMP .= addTag("library", $ABI->{"LibraryName"}); $ABI_DUMP .= addTag("library_version", $ABI->{"LibraryVersion"}); $ABI_DUMP .= addTag("language", $ABI->{"Language"}); $ABI_DUMP .= addTag("gcc", $ABI->{"GccVersion"}); $ABI_DUMP .= addTag("architecture", $ABI->{"Arch"}); $ABI_DUMP .= addTag("target", $ABI->{"Target"}); $ABI_DUMP .= addTag("word_size", $ABI->{"WordSize"}); if($ABI->{"Mode"}) { $ABI_DUMP .= addTag("mode", $ABI->{"Mode"}); } if($ABI->{"SrcBin"}) { $ABI_DUMP .= addTag("kind", "SrcBin"); } elsif($ABI->{"BinOnly"}) { $ABI_DUMP .= addTag("kind", "BinOnly"); } if(my @Headers = keys(%{$ABI->{"Headers"}})) { @Headers = sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} @Headers; $ABI_DUMP .= openTag("headers"); foreach my $Name (@Headers) { $ABI_DUMP .= addTag("name", $Name); } $ABI_DUMP .= closeTag("headers"); } if(my @NameSpaces = keys(%{$ABI->{"NameSpaces"}})) { $ABI_DUMP .= openTag("namespaces"); foreach my $NameSpace (sort {lc($a) cmp lc($b)} @NameSpaces) { $ABI_DUMP .= addTag("name", $NameSpace); } $ABI_DUMP .= closeTag("namespaces"); } if(my @TypeInfo = keys(%{$ABI->{"TypeInfo"}})) { $ABI_DUMP .= openTag("type_info"); foreach my $ID (sort {$a<=>$b} @TypeInfo) { my %TInfo = %{$ABI->{"TypeInfo"}{$ID}}; $ABI_DUMP .= openTag("data_type"); $ABI_DUMP .= addTag("id", $ID); foreach my $Attr ("Name", "Type", "Size", "Header", "Line", "NameSpace", "Class", "Return", "Algn") { if(defined $TInfo{$Attr}) { $ABI_DUMP .= addTag(lc($Attr), $TInfo{$Attr}); } } if($TInfo{"Private"}) { $ABI_DUMP .= addTag("access", "private"); } if($TInfo{"Protected"}) { $ABI_DUMP .= addTag("access", "protected"); } if(my @Positions = keys(%{$TInfo{"Memb"}})) { $ABI_DUMP .= openTag("members"); foreach my $Pos (sort { $a<=>$b } @Positions) { $ABI_DUMP .= openTag("field"); $ABI_DUMP .= addTag("name", $TInfo{"Memb"}{$Pos}{"name"}); if(my $MTid = $TInfo{"Memb"}{$Pos}{"type"}) { $ABI_DUMP .= addTag("type", $MTid); } if(my $Access = $TInfo{"Memb"}{$Pos}{"access"}) { $ABI_DUMP .= addTag("access", $Access); } my $Val = $TInfo{"Memb"}{$Pos}{"value"}; if(defined $Val) { $ABI_DUMP .= addTag("value", $Val); } if(my $Align = $TInfo{"Memb"}{$Pos}{"algn"}) { $ABI_DUMP .= addTag("algn", $Align); } if(my $Bitfield = $TInfo{"Memb"}{$Pos}{"bitfield"}) { $ABI_DUMP .= addTag("bitfield", $Bitfield); } if($TInfo{"Memb"}{$Pos}{"mutable"}) { $ABI_DUMP .= addTag("spec", "mutable"); } $ABI_DUMP .= addTag("pos", $Pos); $ABI_DUMP .= closeTag("field"); } $ABI_DUMP .= closeTag("members"); } if(my @Positions = keys(%{$TInfo{"Param"}})) { $ABI_DUMP .= openTag("parameters"); foreach my $Pos (sort { $a<=>$b } @Positions) { $ABI_DUMP .= openTag("param"); if(my $PTid = $TInfo{"Param"}{$Pos}{"type"}) { $ABI_DUMP .= addTag("type", $PTid); } $ABI_DUMP .= addTag("pos", $Pos); $ABI_DUMP .= closeTag("param"); } $ABI_DUMP .= closeTag("parameters"); } if(my @Positions = keys(%{$TInfo{"TParam"}})) { $ABI_DUMP .= openTag("template_parameters"); foreach my $Pos (sort { $a<=>$b } @Positions) { $ABI_DUMP .= openTag("param"); $ABI_DUMP .= addTag("name", $TInfo{"TParam"}{$Pos}{"name"}); $ABI_DUMP .= addTag("pos", $Pos); $ABI_DUMP .= closeTag("param"); } $ABI_DUMP .= closeTag("template_parameters"); } if(my @Offsets = keys(%{$TInfo{"VTable"}})) { $ABI_DUMP .= openTag("vtable"); foreach my $Offset (sort { $a<=>$b } @Offsets) { $ABI_DUMP .= openTag("entry"); $ABI_DUMP .= addTag("offset", $Offset); $ABI_DUMP .= addTag("value", $TInfo{"VTable"}{$Offset}); $ABI_DUMP .= closeTag("entry"); } $ABI_DUMP .= closeTag("vtable"); } if(my $BTid = $TInfo{"BaseType"}) { $ABI_DUMP .= addTag("base_type", $BTid); } if(my @BaseIDs = keys(%{$TInfo{"Base"}})) { @BaseIDs = sort { $TInfo{"Base"}{$a}{"pos"}<=>$TInfo{"Base"}{$b}{"pos"} } @BaseIDs; $ABI_DUMP .= openTag("base"); foreach my $BaseID (@BaseIDs) { $ABI_DUMP .= openTag("class"); $ABI_DUMP .= addTag("id", $BaseID); if(my $Access = $TInfo{"Base"}{$BaseID}{"access"}) { $ABI_DUMP .= addTag("access", $Access); } if(my $Virt = $TInfo{"Base"}{$BaseID}{"virtual"}) { $ABI_DUMP .= addTag("inherit", "virtual"); } $ABI_DUMP .= addTag("pos", $TInfo{"Base"}{$BaseID}{"pos"}); $ABI_DUMP .= closeTag("class"); } $ABI_DUMP .= closeTag("base"); } if($TInfo{"Copied"}) { $ABI_DUMP .= addTag("note", "copied"); } if($TInfo{"Spec"}) { $ABI_DUMP .= addTag("note", "specialization"); } if($TInfo{"Forward"}) { $ABI_DUMP .= addTag("note", "forward"); } $ABI_DUMP .= closeTag("data_type"); } $ABI_DUMP .= closeTag("type_info"); } if(my @Constants = keys(%{$ABI->{"Constants"}})) { $ABI_DUMP .= openTag("constants"); foreach my $Constant (@Constants) { my %CInfo = %{$ABI->{"Constants"}{$Constant}}; $ABI_DUMP .= openTag("constant"); $ABI_DUMP .= addTag("name", $Constant); $ABI_DUMP .= addTag("value", $CInfo{"Value"}); $ABI_DUMP .= addTag("header", $CInfo{"Header"}); $ABI_DUMP .= closeTag("constant"); } $ABI_DUMP .= closeTag("constants"); } if(my @SymbolInfo = keys(%{$ABI->{"SymbolInfo"}})) { my %TR = ( "MnglName" => "mangled", "ShortName" => "short" ); $ABI_DUMP .= openTag("symbol_info"); foreach my $ID (sort {$a<=>$b} @SymbolInfo) { my %SInfo = %{$ABI->{"SymbolInfo"}{$ID}}; $ABI_DUMP .= openTag("symbol"); $ABI_DUMP .= addTag("id", $ID); foreach my $Attr ("MnglName", "ShortName", "Class", "Header", "Line", "Return", "NameSpace", "Value") { if(defined $SInfo{$Attr}) { my $Tag = $Attr; if($TR{$Attr}) { $Tag = $TR{$Attr}; } $ABI_DUMP .= addTag(lc($Tag), $SInfo{$Attr}); } } if($SInfo{"Constructor"}) { $ABI_DUMP .= addTag("kind", "constructor"); } if($SInfo{"Destructor"}) { $ABI_DUMP .= addTag("kind", "destructor"); } if($SInfo{"Data"}) { $ABI_DUMP .= addTag("kind", "data"); } if($SInfo{"Virt"}) { $ABI_DUMP .= addTag("spec", "virtual"); } elsif($SInfo{"PureVirt"}) { $ABI_DUMP .= addTag("spec", "pure virtual"); } elsif($SInfo{"Static"}) { $ABI_DUMP .= addTag("spec", "static"); } if($SInfo{"InLine"}) { $ABI_DUMP .= addTag("spec", "inline"); } if($SInfo{"Const"}) { $ABI_DUMP .= addTag("spec", "const"); } if($SInfo{"Volatile"}) { $ABI_DUMP .= addTag("spec", "volatile"); } if($SInfo{"Private"}) { $ABI_DUMP .= addTag("access", "private"); } if($SInfo{"Protected"}) { $ABI_DUMP .= addTag("access", "protected"); } if($SInfo{"Artificial"}) { $ABI_DUMP .= addTag("note", "artificial"); } if(my $Lang = $SInfo{"Lang"}) { $ABI_DUMP .= addTag("lang", $Lang); } if(my @Positions = keys(%{$SInfo{"Param"}})) { $ABI_DUMP .= openTag("parameters"); foreach my $Pos (sort { $a<=>$b } @Positions) { $ABI_DUMP .= openTag("param"); if(my $PName = $SInfo{"Param"}{$Pos}{"name"}) { $ABI_DUMP .= addTag("name", $PName); } if(my $PTid = $SInfo{"Param"}{$Pos}{"type"}) { $ABI_DUMP .= addTag("type", $PTid); } my $Default = $SInfo{"Param"}{$Pos}{"default"}; if(defined $Default) { $ABI_DUMP .= addTag("default", $Default); } if(my $Align = $SInfo{"Param"}{$Pos}{"algn"}) { $ABI_DUMP .= addTag("algn", $Align); } if(defined $SInfo{"Param"}{$Pos}{"reg"}) { $ABI_DUMP .= addTag("call", "register"); } $ABI_DUMP .= addTag("pos", $Pos); $ABI_DUMP .= closeTag("param"); } $ABI_DUMP .= closeTag("parameters"); } if(my @Positions = keys(%{$SInfo{"TParam"}})) { $ABI_DUMP .= openTag("template_parameters"); foreach my $Pos (sort { $a<=>$b } @Positions) { $ABI_DUMP .= openTag("param"); $ABI_DUMP .= addTag("name", $SInfo{"TParam"}{$Pos}{"name"}); $ABI_DUMP .= closeTag("param"); } $ABI_DUMP .= closeTag("template_parameters"); } $ABI_DUMP .= closeTag("symbol"); } $ABI_DUMP .= closeTag("symbol_info"); } if(my @Libs = keys(%{$ABI->{"Symbols"}})) { $ABI_DUMP .= openTag("symbols"); foreach my $Lib (sort {lc($a) cmp lc($b)} @Libs) { $ABI_DUMP .= openTag("library", "name", $Lib); foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%{$ABI->{"Symbols"}{$Lib}})) { if((my $Size = $ABI->{"Symbols"}{$Lib}{$Symbol})<0) { # data $ABI_DUMP .= addTag("symbol", $Symbol, "size", -$Size); } else { # functions $ABI_DUMP .= addTag("symbol", $Symbol); } } $ABI_DUMP .= closeTag("library"); } $ABI_DUMP .= closeTag("symbols"); } if(my @DepLibs = keys(%{$ABI->{"DepSymbols"}})) { $ABI_DUMP .= openTag("dep_symbols"); foreach my $Lib (sort {lc($a) cmp lc($b)} @DepLibs) { $ABI_DUMP .= openTag("library", "name", $Lib); foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%{$ABI->{"DepSymbols"}{$Lib}})) { if((my $Size = $ABI->{"DepSymbols"}{$Lib}{$Symbol})<0) { # data $ABI_DUMP .= addTag("symbol", $Symbol, "size", -$Size); } else { # functions $ABI_DUMP .= addTag("symbol", $Symbol); } } $ABI_DUMP .= closeTag("library"); } $ABI_DUMP .= closeTag("dep_symbols"); } if(my @VSymbols = keys(%{$ABI->{"SymbolVersion"}})) { $ABI_DUMP .= openTag("symbol_version"); foreach my $Symbol (sort {lc($a) cmp lc($b)} @VSymbols) { $ABI_DUMP .= openTag("symbol"); $ABI_DUMP .= addTag("name", $Symbol); $ABI_DUMP .= addTag("version", $ABI->{"SymbolVersion"}{$Symbol}); $ABI_DUMP .= closeTag("symbol"); } $ABI_DUMP .= closeTag("symbol_version"); } if(my @SkipTypes = keys(%{$ABI->{"SkipTypes"}})) { $ABI_DUMP .= openTag("skip_types"); foreach my $Name (sort {lc($a) cmp lc($b)} @SkipTypes) { $ABI_DUMP .= addTag("name", $Name); } $ABI_DUMP .= closeTag("skip_types"); } if(my @SkipSymbols = keys(%{$ABI->{"SkipSymbols"}})) { $ABI_DUMP .= openTag("skip_symbols"); foreach my $Name (sort {lc($a) cmp lc($b)} @SkipSymbols) { $ABI_DUMP .= addTag("name", $Name); } $ABI_DUMP .= closeTag("skip_symbols"); } if(my @SkipNameSpaces = keys(%{$ABI->{"SkipNameSpaces"}})) { $ABI_DUMP .= openTag("skip_namespaces"); foreach my $Name (sort {lc($a) cmp lc($b)} @SkipNameSpaces) { $ABI_DUMP .= addTag("name", $Name); } $ABI_DUMP .= closeTag("skip_namespaces"); } if(my @SkipHeaders = keys(%{$ABI->{"SkipHeaders"}})) { $ABI_DUMP .= openTag("skip_headers"); foreach my $Name (sort {lc($a) cmp lc($b)} @SkipHeaders) { $ABI_DUMP .= addTag("name", $Name); } $ABI_DUMP .= closeTag("skip_headers"); } if(my @TargetHeaders = keys(%{$ABI->{"TargetHeaders"}})) { $ABI_DUMP .= openTag("target_headers"); foreach my $Name (sort {lc($a) cmp lc($b)} @TargetHeaders) { $ABI_DUMP .= addTag("name", $Name); } $ABI_DUMP .= closeTag("target_headers"); } $ABI_DUMP .= "</ABI_dump>\n"; checkTags(); return $ABI_DUMP; } sub readXmlDump($) { my $ABI_DUMP = readFile($_[0]); my %ABI = {}; $ABI{"LibraryName"} = parseTag(\$ABI_DUMP, "library"); $ABI{"LibraryVersion"} = parseTag(\$ABI_DUMP, "library_version"); $ABI{"Language"} = parseTag(\$ABI_DUMP, "language"); $ABI{"GccVersion"} = parseTag(\$ABI_DUMP, "gcc"); $ABI{"Arch"} = parseTag(\$ABI_DUMP, "architecture"); $ABI{"Target"} = parseTag(\$ABI_DUMP, "target"); $ABI{"WordSize"} = parseTag(\$ABI_DUMP, "word_size"); my $Pos = 0; if(my $Headers = parseTag(\$ABI_DUMP, "headers")) { while(my $Name = parseTag(\$Headers, "name")) { $ABI{"Headers"}{$Name} = $Pos++; } } if(my $NameSpaces = parseTag(\$ABI_DUMP, "namespaces")) { while(my $Name = parseTag(\$NameSpaces, "name")) { $ABI{"NameSpaces"}{$Name} = 1; } } if(my $TypeInfo = parseTag(\$ABI_DUMP, "type_info")) { while(my $DataType = parseTag(\$TypeInfo, "data_type")) { my %TInfo = (); my $ID = parseTag(\$DataType, "id"); if(my $Members = parseTag(\$DataType, "members")) { $Pos = 0; while(my $Field = parseTag(\$Members, "field")) { my %MInfo = (); $MInfo{"name"} = parseTag(\$Field, "name"); if(my $Tid = parseTag(\$Field, "type")) { $MInfo{"type"} = $Tid; } if(my $Access = parseTag(\$Field, "access")) { $MInfo{"access"} = $Access; } my $Val = parseTag(\$Field, "value"); if(defined $Val) { $MInfo{"value"} = $Val; } if(my $Align = parseTag(\$Field, "algn")) { $MInfo{"algn"} = $Align; } if(my $Bitfield = parseTag(\$Field, "bitfield")) { $MInfo{"bitfield"} = $Bitfield; } if(my $Spec = parseTag(\$Field, "spec")) { $MInfo{$Spec} = 1; } $TInfo{"Memb"}{$Pos++} = \%MInfo; } } if(my $Parameters = parseTag(\$DataType, "parameters")) { $Pos = 0; while(my $Parameter = parseTag(\$Parameters, "param")) { my %PInfo = (); if(my $Tid = parseTag(\$Parameter, "type")) { $PInfo{"type"} = $Tid; } $TInfo{"Param"}{$Pos++} = \%PInfo; } } if(my $TParams = parseTag(\$DataType, "template_parameters")) { $Pos = 0; while(my $TParam = parseTag(\$TParams, "param")) { $TInfo{"TParam"}{$Pos++}{"name"} = parseTag(\$TParam, "name"); } } if(my $VTable = parseTag(\$DataType, "vtable")) { $Pos = 0; while(my $Entry = parseTag(\$VTable, "entry")) { $TInfo{"VTable"}{parseTag(\$Entry, "offset")} = parseTag(\$Entry, "value"); } } if(my $BTid = parseTag(\$DataType, "base_type")) { $TInfo{"BaseType"} = $BTid; } if(my $Base = parseTag(\$DataType, "base")) { $Pos = 0; while(my $Class = parseTag(\$Base, "class")) { my %CInfo = (); $CInfo{"pos"} = parseTag(\$Class, "pos"); if(my $Access = parseTag(\$Class, "access")) { $CInfo{"access"} = $Access; } if(my $Inherit = parseTag(\$Class, "inherit")) { if($Inherit eq "virtual") { $CInfo{"virtual"} = 1; } } $TInfo{"Base"}{parseTag(\$Class, "id")} = \%CInfo; } } while(my $Note = parseTag(\$DataType, "note")) { if($Note eq "copied") { $TInfo{"Copied"} = 1; } elsif($Note eq "specialization") { $TInfo{"Spec"} = 1; } elsif($Note eq "forward") { $TInfo{"Forward"} = 1; } } foreach my $Attr ("Name", "Type", "Size", "Header", "Line", "NameSpace", "Class", "Return", "Algn") { my $Val = parseTag(\$DataType, lc($Attr)); if(defined $Val) { $TInfo{$Attr} = $Val; } } if(my $Access = parseTag(\$DataType, "access")) { $TInfo{ucfirst($Access)} = 1; } $ABI{"TypeInfo"}{$ID} = \%TInfo; } } if(my $Constants = parseTag(\$ABI_DUMP, "constants")) { while(my $Constant = parseTag(\$Constants, "constant")) { if(my $Name = parseTag(\$Constant, "name")) { my %CInfo = (); $CInfo{"Value"} = parseTag(\$Constant, "value"); $CInfo{"Header"} = parseTag(\$Constant, "header"); $ABI{"Constants"}{$Name} = \%CInfo; } } } if(my $SymbolInfo = parseTag(\$ABI_DUMP, "symbol_info")) { my %TR = ( "MnglName"=>"mangled", "ShortName"=>"short" ); while(my $Symbol = parseTag(\$SymbolInfo, "symbol")) { my %SInfo = (); my $ID = parseTag(\$Symbol, "id"); if(my $Parameters = parseTag(\$Symbol, "parameters")) { $Pos = 0; while(my $Parameter = parseTag(\$Parameters, "param")) { my %PInfo = (); if(my $PName = parseTag(\$Parameter, "name")) { $PInfo{"name"} = $PName; } if(my $PTid = parseTag(\$Parameter, "type")) { $PInfo{"type"} = $PTid; } my $Default = parseTag(\$Parameter, "default", "spaces"); if(defined $Default) { $PInfo{"default"} = $Default; } if(my $Align = parseTag(\$Parameter, "algn")) { $PInfo{"algn"} = $Align; } if(my $Call = parseTag(\$Parameter, "call")) { if($Call eq "register") { $PInfo{"reg"} = 1; } } $SInfo{"Param"}{$Pos++} = \%PInfo; } } if(my $TParams = parseTag(\$Symbol, "template_parameters")) { $Pos = 0; while(my $TParam = parseTag(\$TParams, "param")) { $SInfo{"TParam"}{$Pos++}{"name"} = parseTag(\$TParam, "name"); } } foreach my $Attr ("MnglName", "ShortName", "Class", "Header", "Line", "Return", "NameSpace", "Value") { my $Tag = lc($Attr); if($TR{$Attr}) { $Tag = $TR{$Attr}; } my $Val = parseTag(\$Symbol, $Tag); if(defined $Val) { $SInfo{$Attr} = $Val; } } if(my $Kind = parseTag(\$Symbol, "kind")) { $SInfo{ucfirst($Kind)} = 1; } while(my $Spec = parseTag(\$Symbol, "spec")) { if($Spec eq "virtual") { $SInfo{"Virt"} = 1; } elsif($Spec eq "pure virtual") { $SInfo{"PureVirt"} = 1; } elsif($Spec eq "inline") { $SInfo{"InLine"} = 1; } else { # const, volatile, static $SInfo{ucfirst($Spec)} = 1; } } if(my $Access = parseTag(\$Symbol, "access")) { $SInfo{ucfirst($Access)} = 1; } if(my $Note = parseTag(\$Symbol, "note")) { $SInfo{ucfirst($Note)} = 1; } if(my $Lang = parseTag(\$Symbol, "lang")) { $SInfo{"Lang"} = $Lang; } $ABI{"SymbolInfo"}{$ID} = \%SInfo; } } if(my $Symbols = parseTag(\$ABI_DUMP, "symbols")) { my %LInfo = (); while(my $LibSymbols = parseTag_E(\$Symbols, "library", \%LInfo)) { my %SInfo = (); while(my $Symbol = parseTag_E(\$LibSymbols, "symbol", \%SInfo)) { if(my $Size = $SInfo{"size"}) { $ABI{"Symbols"}{$LInfo{"name"}}{$Symbol} = -$Size; } else { $ABI{"Symbols"}{$LInfo{"name"}}{$Symbol} = 1; } %SInfo = (); } %LInfo = (); } } if(my $DepSymbols = parseTag(\$ABI_DUMP, "dep_symbols")) { my %LInfo = (); while(my $LibSymbols = parseTag_E(\$DepSymbols, "library", \%LInfo)) { my %SInfo = (); while(my $Symbol = parseTag_E(\$LibSymbols, "symbol", \%SInfo)) { if(my $Size = $SInfo{"size"}) { $ABI{"DepSymbols"}{$LInfo{"name"}}{$Symbol} = -$Size; } else { $ABI{"DepSymbols"}{$LInfo{"name"}}{$Symbol} = 1; } %SInfo = (); } %LInfo = (); } } $ABI{"SymbolVersion"} = {}; if(my $SymbolVersion = parseTag(\$ABI_DUMP, "symbol_version")) { while(my $Symbol = parseTag(\$SymbolVersion, "symbol")) { $ABI{"SymbolVersion"}{parseTag(\$Symbol, "name")} = parseTag(\$Symbol, "version"); } } $ABI{"SkipTypes"} = {}; if(my $SkipTypes = parseTag(\$ABI_DUMP, "skip_types")) { while(my $Name = parseTag(\$SkipTypes, "name")) { $ABI{"SkipTypes"}{$Name} = 1; } } $ABI{"SkipSymbols"} = {}; if(my $SkipSymbols = parseTag(\$ABI_DUMP, "skip_symbols")) { while(my $Name = parseTag(\$SkipSymbols, "name")) { $ABI{"SkipSymbols"}{$Name} = 1; } } $ABI{"SkipNameSpaces"} = {}; if(my $SkipNameSpaces = parseTag(\$ABI_DUMP, "skip_namespaces")) { while(my $Name = parseTag(\$SkipNameSpaces, "name")) { $ABI{"SkipNameSpaces"}{$Name} = 1; } } $ABI{"SkipHeaders"} = {}; if(my $SkipHeaders = parseTag(\$ABI_DUMP, "skip_headers")) { while(my $Name = parseTag(\$SkipHeaders, "name")) { $ABI{"SkipHeaders"}{$Name} = 1; } } if(my $TargetHeaders = parseTag(\$ABI_DUMP, "target_headers")) { while(my $Name = parseTag(\$TargetHeaders, "name")) { $ABI{"TargetHeaders"}{$Name} = 1; } } if(my $Mode = parseTag(\$ABI_DUMP, "mode")) { $ABI{"Mode"} = $Mode; } if(my $Kind = parseTag(\$ABI_DUMP, "kind")) { if($Kind eq "BinOnly") { $ABI{"BinOnly"} = 1; } elsif($Kind eq "SrcBin") { $ABI{"SrcBin"} = 1; } } my %RInfo = (); parseTag_E(\$ABI_DUMP, "ABI_dump", \%RInfo); $ABI{"ABI_DUMP_VERSION"} = $RInfo{"version"}; $ABI{"XML_ABI_DUMP_VERSION"} = $RInfo{"xml_format"}; $ABI{"ABI_COMPLIANCE_CHECKER_VERSION"} = $RInfo{"acc"}; return \%ABI; } sub parseTag_E($$$) { my ($CodeRef, $Tag, $Info) = @_; if(not $Tag or not $CodeRef or not $Info) { return undef; } if(${$CodeRef}=~s/\<\Q$Tag\E(\s+([^<>]+)|)\>((.|\n)*?)\<\/\Q$Tag\E\>//) { my ($Ext, $Content) = ($2, $3); $Content=~s/\A\s+//g; $Content=~s/\s+\Z//g; if($Ext) { while($Ext=~s/(\w+)\=\"([^\"]*)\"//) { my ($K, $V) = ($1, $2); $Info->{$K} = xmlSpecChars_R($V); } } if(substr($Content, 0, 1) ne "<") { $Content = xmlSpecChars_R($Content); } return $Content; } return undef; } sub addTag(@) { my $Tag = shift(@_); my $Val = shift(@_); my @Ext = @_; my $Content = openTag($Tag, @Ext); chomp($Content); $Content .= xmlSpecChars($Val); $Content .= "</$Tag>\n"; $TAG_ID-=1; return $Content; } sub openTag(@) { my $Tag = shift(@_); my @Ext = @_; my $Content = ""; foreach (1 .. $TAG_ID) { $Content .= $INDENT; } $TAG_ID+=1; if(@Ext) { $Content .= "<".$Tag; my $P = 0; while($P<=$#Ext-1) { $Content .= " ".$Ext[$P]; $Content .= "=\"".xmlSpecChars($Ext[$P+1])."\""; $P+=2; } $Content .= ">\n"; } else { $Content .= "<".$Tag.">\n"; } return $Content; } sub closeTag($) { my $Tag = $_[0]; my $Content = ""; $TAG_ID-=1; foreach (1 .. $TAG_ID) { $Content .= $INDENT; } $Content .= "</".$Tag.">\n"; return $Content; } sub checkTags() { if($TAG_ID!=0) { printMsg("WARNING", "the number of opened tags is not equal to number of closed tags"); } } return 1;