- return 0;
- }
-
- return 1;
-}
-
-sub showArch($)
-{
- my $Arch = $_[0];
- if($Arch eq "arm"
- or $Arch eq "mips") {
- return uc($Arch);
- }
- return $Arch;
-}
-
-sub getReportTitle($)
-{
- my $Level = $_[0];
-
- my $ArchInfo = " on ".showArch($In::ABI{1}{"Arch"})."";
- if($In::ABI{1}{"Arch"} ne $In::ABI{2}{"Arch"}
- or $Level eq "Source")
- { # don't show architecture in the header
- $ArchInfo = "";
- }
- my $Title = "";
- if($Level eq "Source") {
- $Title .= "Source compatibility";
- }
- elsif($Level eq "Binary") {
- $Title .= "Binary compatibility";
- }
- else {
- $Title .= "API compatibility";
- }
-
- my $V1 = $In::Desc{1}{"Version"};
- my $V2 = $In::Desc{2}{"Version"};
-
- if($UsedDump{1}{"DWARF"} and $UsedDump{2}{"DWARF"})
- {
- my $M1 = $In::ABI{1}{"LibraryName"};
- my $M2 = $In::ABI{2}{"LibraryName"};
-
- my $M1S = $M1;
- my $M2S = $M2;
-
- $M1S=~s/(\.so|\.ko)\..+/$1/ig;
- $M2S=~s/(\.so|\.ko)\..+/$1/ig;
-
- if($M1S eq $M2S
- and $V1 ne "X" and $V2 ne "Y")
- {
- $Title .= " report for the $M1S ".$In::Opt{"TargetComponent"};
- $Title .= " between ".$V1." and ".$V2." versions";
- }
- else
- {
- $Title .= " report between $M1 (".$V1.")";
- $Title .= " and $M2 (".$V2.") objects";
- }
- }
- else
- {
- $Title .= " report for the ".$In::Opt{"TargetTitle"}." ".$In::Opt{"TargetComponent"};
- $Title .= " between ".$V1." and ".$V2." versions";
- }
-
- $Title .= $ArchInfo;
-
- if($In::Opt{"AppPath"}) {
- $Title .= " (relating to the portability of application ".getFilename($In::Opt{"AppPath"}).")";
- }
- $Title = "".$Title."
\n";
- return $Title;
-}
-
-sub getCheckedHeaders($)
-{
- my $LVer = $_[0];
-
- my @Headers = ();
-
- foreach my $Path (keys(%{$In::ABI{$LVer}{"Headers"}}))
- {
- my $Name = getFilename($Path);
-
- if(not isTargetHeader($Name, $LVer)) {
- next;
- }
-
- if(skipHeader($Name, $LVer)) {
- next;
- }
-
- push(@Headers, $Path);
- }
-
- return @Headers;
-}
-
-sub getSourceInfo()
-{
- my ($CheckedHeaders, $CheckedSources, $CheckedLibs) = ("", "");
-
- if(my @Headers = getCheckedHeaders(1))
- {
- $CheckedHeaders = "";
- if($In::Opt{"OldStyle"}) {
- $CheckedHeaders .= "Header Files (".($#Headers+1).")
";
- }
- else {
- $CheckedHeaders .= "Header Files ".($#Headers+1)."
";
- }
- $CheckedHeaders .= "
\n";
- $CheckedHeaders .= "\n";
- foreach my $Path (sort {lc($a) cmp lc($b)} @Headers) {
- $CheckedHeaders .= getFilename($Path)."
\n";
- }
- $CheckedHeaders .= "
\n";
- $CheckedHeaders .= "
$TOP_REF
\n";
- }
-
- if(my @Sources = keys(%{$In::ABI{1}{"Sources"}}))
- {
- $CheckedSources = "";
- if($In::Opt{"OldStyle"}) {
- $CheckedSources .= "Source Files (".($#Sources+1).")
";
- }
- else {
- $CheckedSources .= "Source Files ".($#Sources+1)."
";
- }
- $CheckedSources .= "
\n";
- $CheckedSources .= "\n";
- foreach my $Path (sort {lc($a) cmp lc($b)} @Sources) {
- $CheckedSources .= getFilename($Path)."
\n";
- }
- $CheckedSources .= "
\n";
- $CheckedSources .= "
$TOP_REF
\n";
- }
-
- if(not $In::Opt{"CheckHeadersOnly"})
- {
- $CheckedLibs = "";
- if($In::Opt{"OldStyle"}) {
- $CheckedLibs .= "".getObjTitle()." (".keys(%{$In::ABI{1}{"Symbols"}}).")
";
- }
- else {
- $CheckedLibs .= "".getObjTitle()." ".keys(%{$In::ABI{1}{"Symbols"}})."
";
- }
- $CheckedLibs .= "
\n";
- $CheckedLibs .= "\n";
- foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$In::ABI{1}{"Symbols"}})) {
- $CheckedLibs .= $Library."
\n";
- }
- $CheckedLibs .= "
\n";
- $CheckedLibs .= "
$TOP_REF
\n";
- }
-
- return $CheckedHeaders.$CheckedSources.$CheckedLibs;
-}
-
-sub getObjTitle()
-{
- if(defined $UsedDump{1}{"DWARF"}) {
- return "Objects";
- }
-
- return "Libraries";
-}
-
-sub getTypeProblemsCount($$)
-{
- my ($TargetSeverity, $Level) = @_;
- my $Count = 0;
-
- foreach my $Type_Name (sort keys(%{$TypeChanges{$Level}}))
- {
- my %Kinds_Target = ();
- foreach my $Kind (keys(%{$TypeChanges{$Level}{$Type_Name}}))
- {
- if($CompatRules{$Level}{$Kind}{"Severity"} ne $TargetSeverity) {
- next;
- }
-
- foreach my $Loc (keys(%{$TypeChanges{$Level}{$Type_Name}{$Kind}}))
- {
- my $Target = $TypeChanges{$Level}{$Type_Name}{$Kind}{$Loc}{"Target"};
-
- if($Kinds_Target{$Kind}{$Target}) {
- next;
- }
-
- $Kinds_Target{$Kind}{$Target} = 1;
- $Count += 1;
- }
- }
- }
- return $Count;
-}
-
-sub getSummary($)
-{
- my $Level = $_[0];
- my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
- $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other, $C_Other) = (0,0,0,0,0,0,0,0,0,0,0,0);
- %{$RESULT{$Level}} = (
- "Problems"=>0,
- "Warnings"=>0,
- "Affected"=>0);
- # check rules
- foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
- {
- foreach my $Kind (keys(%{$CompatProblems{$Level}{$Symbol}}))
- {
- if(not defined $CompatRules{$Level}{$Kind})
- { # unknown rule
- if(not $UnknownRules{$Level}{$Kind})
- { # only one warning
- printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
- $UnknownRules{$Level}{$Kind}=1;
- }
- delete($CompatProblems{$Level}{$Symbol}{$Kind});
- }
- }
- }
- foreach my $Constant (sort keys(%{$CompatProblems_Constants{$Level}}))
- {
- foreach my $Kind (keys(%{$CompatProblems_Constants{$Level}{$Constant}}))
- {
- if(not defined $CompatRules{$Level}{$Kind})
- { # unknown rule
- if(not $UnknownRules{$Level}{$Kind})
- { # only one warning
- printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
- $UnknownRules{$Level}{$Kind}=1;
- }
- delete($CompatProblems_Constants{$Level}{$Constant}{$Kind});
- }
- }
- }
- foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
- {
- foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
- {
- if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
- {
- my $Severity = $CompatRules{$Level}{$Kind}{"Severity"};
- foreach my $Loc (sort keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}}))
- {
- if($Kind eq "Added_Symbol") {
- $Added += 1;
- }
- elsif($Kind eq "Removed_Symbol")
- {
- $Removed += 1;
- $TotalAffected{$Level}{$Symbol} = $Severity;
- }
- else
- {
- if($Severity eq "Safe") {
- $I_Other += 1;
- }
- elsif($Severity eq "High") {
- $I_Problems_High += 1;
- }
- elsif($Severity eq "Medium") {
- $I_Problems_Medium += 1;
- }
- elsif($Severity eq "Low") {
- $I_Problems_Low += 1;
- }
- if(($Severity ne "Low" or $In::Opt{"StrictCompat"})
- and $Severity ne "Safe") {
- $TotalAffected{$Level}{$Symbol} = $Severity;
- }
- }
- }
- }
- }
- }
-
- my %MethodTypeIndex = ();
-
- foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
- {
- foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
- {
- if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
- {
- my $Severity = $CompatRules{$Level}{$Kind}{"Severity"};
- if(($Severity ne "Low" or $In::Opt{"StrictCompat"})
- and $Severity ne "Safe")
- {
- if(my $Sev = $TotalAffected{$Level}{$Symbol})
- {
- if($Severity_Val{$Severity}>$Severity_Val{$Sev}) {
- $TotalAffected{$Level}{$Symbol} = $Severity;
- }
- }
- else {
- $TotalAffected{$Level}{$Symbol} = $Severity;
- }
- }
-
- my $LSK = $CompatProblems{$Level}{$Symbol}{$Kind};
- my (@Locs1, @Locs2) = ();
- foreach my $Loc (sort keys(%{$LSK}))
- {
- if(index($Loc, "retval")==0 or index($Loc, "this")==0) {
- push(@Locs2, $Loc);
- }
- else {
- push(@Locs1, $Loc);
- }
- }
-
- foreach my $Loc (@Locs1, @Locs2)
- {
- my $Type = $LSK->{$Loc}{"Type_Name"};
- my $Target = $LSK->{$Loc}{"Target"};
-
- if(defined $MethodTypeIndex{$Symbol}{$Type}{$Kind}{$Target})
- { # one location for one type and target
- next;
- }
- $MethodTypeIndex{$Symbol}{$Type}{$Kind}{$Target} = 1;
-
- $TypeChanges{$Level}{$Type}{$Kind}{$Loc} = $LSK->{$Loc};
- $TypeProblemsIndex{$Level}{$Type}{$Kind}{$Loc}{$Symbol} = 1;
- }
- }
- }
- }
-
- # clean memory
- %MethodTypeIndex = ();
-
- $T_Problems_High = getTypeProblemsCount("High", $Level);
- $T_Problems_Medium = getTypeProblemsCount("Medium", $Level);
- $T_Problems_Low = getTypeProblemsCount("Low", $Level);
- $T_Other = getTypeProblemsCount("Safe", $Level);
-
- # changed and removed public symbols
- my $SCount = keys(%{$CheckedSymbols{$Level}});
- if($In::Opt{"ExtendedCheck"})
- { # don't count external_func_0 for constants
- $SCount-=1;
- }
- if($SCount)
- {
- my %Weight = (
- "High" => 100,
- "Medium" => 50,
- "Low" => 25
- );
- foreach (keys(%{$TotalAffected{$Level}})) {
- $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
- }
- $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
- }
- else {
- $RESULT{$Level}{"Affected"} = 0;
- }
-
- $RESULT{$Level}{"Affected"} = showNum($RESULT{$Level}{"Affected"});
- if($RESULT{$Level}{"Affected"}>=100) {
- $RESULT{$Level}{"Affected"} = 100;
- }
-
- $RESULT{$Level}{"Problems"} += $Removed;
- $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High;
- $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
- if($In::Opt{"StrictCompat"}) {
- $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low;
- }
- else {
- $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low;
- }
-
- foreach my $Constant (keys(%{$CompatProblems_Constants{$Level}}))
- {
- foreach my $Kind (keys(%{$CompatProblems_Constants{$Level}{$Constant}}))
- {
- my $Severity = $CompatRules{$Level}{$Kind}{"Severity"};
- if($Severity eq "Safe")
- {
- $C_Other+=1;
- }
- elsif($Severity eq "Low")
- {
- $C_Problems_Low+=1;
- }
- }
- }
-
- if($C_Problems_Low)
- {
- if($In::Opt{"StrictCompat"}) {
- $RESULT{$Level}{"Problems"} += $C_Problems_Low;
- }
- else {
- $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
- }
- }
- if($RESULT{$Level}{"Problems"}
- and $RESULT{$Level}{"Affected"}) {
- $RESULT{$Level}{"Verdict"} = "incompatible";
- }
- else {
- $RESULT{$Level}{"Verdict"} = "compatible";
- }
-
- my $TotalTypes = keys(%{$CheckedTypes{$Level}});
- if(not $TotalTypes)
- { # list all the types
- $TotalTypes = keys(%{$TName_Tid{1}});
- }
-
- my $TotalSymbols = keys(%{$CheckedSymbols{$Level}});
-
- if($In::Opt{"ExtendedCheck"}) {
- $TotalSymbols -= keys(%ExtendedSymbols);
- }
-
- my $AnyChanged = ($Added or $Removed or $I_Problems_High or $I_Problems_Medium or $I_Problems_Low or $T_Problems_High or
- $C_Problems_Low or $T_Problems_Medium or $T_Problems_Low or $I_Other or $T_Other or $C_Other);
-
- my ($Arch1, $Arch2) = ($In::ABI{1}{"Arch"}, $In::ABI{2}{"Arch"});
- my ($GccV1, $GccV2) = ($In::ABI{1}{"GccVersion"}, $In::ABI{2}{"GccVersion"});
- my ($ClangV1, $ClangV2) = ($In::ABI{1}{"ClangVersion"}, $In::ABI{2}{"ClangVersion"});
-
- my ($TestInfo, $TestResults, $Problem_Summary) = ();
-
- if($In::Opt{"ReportFormat"} eq "xml")
- { # XML
- # test info
- $TestInfo .= " ".$In::Opt{"TargetLib"}."\n";
- $TestInfo .= " \n";
- $TestInfo .= " ".$In::Desc{1}{"Version"}."\n";
- $TestInfo .= " $Arch1\n";
- if($GccV1) {
- $TestInfo .= " $GccV1\n";
- }
- elsif($ClangV1) {
- $TestInfo .= " $ClangV1\n";
- }
- $TestInfo .= " \n";
-
- $TestInfo .= " \n";
- $TestInfo .= " ".$In::Desc{2}{"Version"}."\n";
- $TestInfo .= " $Arch2\n";
- if($GccV2) {
- $TestInfo .= " $GccV2\n";
- }
- elsif($ClangV2) {
- $TestInfo .= " $ClangV2\n";
- }
- $TestInfo .= " \n";
- $TestInfo = "\n".$TestInfo."\n\n";
-
- # test results
- if(my @Headers = keys(%{$In::ABI{1}{"Headers"}}))
- {
- $TestResults .= " \n";
- foreach my $Name (sort {lc($a) cmp lc($b)} @Headers) {
- $TestResults .= " ".getFilename($Name)."\n";
- }
- $TestResults .= " \n";
- }
-
- if(my @Sources = keys(%{$In::ABI{1}{"Sources"}}))
- {
- $TestResults .= " \n";
- foreach my $Name (sort {lc($a) cmp lc($b)} @Sources) {
- $TestResults .= " ".getFilename($Name)."\n";
- }
- $TestResults .= " \n";
- }
-
- $TestResults .= " \n";
- foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$In::ABI{1}{"Symbols"}}))
- {
- $TestResults .= " $Library\n";
- }
- $TestResults .= " \n";
-
- $TestResults .= " ".$TotalSymbols."\n";
- $TestResults .= " ".$TotalTypes."\n";
-
- $TestResults .= " ".$RESULT{$Level}{"Verdict"}."\n";
- $TestResults .= " ".$RESULT{$Level}{"Affected"}."\n";
- $TestResults = "\n".$TestResults."\n\n";
-
- # problem summary
- $Problem_Summary .= " ".$Added."\n";
- $Problem_Summary .= " ".$Removed."\n";
-
- $Problem_Summary .= " \n";
- $Problem_Summary .= " $T_Problems_High\n";
- $Problem_Summary .= " $T_Problems_Medium\n";
- $Problem_Summary .= " $T_Problems_Low\n";
- $Problem_Summary .= " $T_Other\n";
- $Problem_Summary .= " \n";
-
- $Problem_Summary .= " \n";
- $Problem_Summary .= " $I_Problems_High\n";
- $Problem_Summary .= " $I_Problems_Medium\n";
- $Problem_Summary .= " $I_Problems_Low\n";
- $Problem_Summary .= " $I_Other\n";
- $Problem_Summary .= " \n";
-
- $Problem_Summary .= " \n";
- $Problem_Summary .= " $C_Problems_Low\n";
- $Problem_Summary .= " \n";
-
- $Problem_Summary = "\n".$Problem_Summary."\n\n";
-
- return ($TestInfo.$TestResults.$Problem_Summary, "", $AnyChanged);
- }
- else
- { # HTML
- # test info
- $TestInfo = "Test Info
\n";
- $TestInfo .= "\n";
-
- if($In::Opt{"TargetComponent"} eq "library") {
- $TestInfo .= "| Library Name | ".$In::Opt{"TargetTitle"}." |
\n";
- }
- else {
- $TestInfo .= "| Module Name | ".$In::Opt{"TargetTitle"}." |
\n";
- }
-
- my (@VInf1, @VInf2, $AddTestInfo) = ();
-
- # CPU arch
- if($Arch1 eq $Arch2)
- { # go to the separate section
- $AddTestInfo .= "| Arch | ".showArch($Arch1)." |
\n";
- }
- else
- { # go to the version number
- push(@VInf1, showArch($Arch1));
- push(@VInf2, showArch($Arch2));
- }
-
- if($Level eq "Binary"
- and $In::Opt{"Target"} ne "windows")
- {
- if($GccV1 and $GccV2)
- { # GCC version
- if($GccV1 eq $GccV2)
- { # go to the separate section
- $AddTestInfo .= "| GCC Version | $GccV1 |
\n";
- }
- else
- { # go to the version number
- push(@VInf1, "gcc ".$GccV1);
- push(@VInf2, "gcc ".$GccV2);
- }
- }
- elsif($ClangV1 and $ClangV2)
- { # Clang version
- if($ClangV1 eq $ClangV2)
- { # go to the separate section
- $AddTestInfo .= "| Clang Version | $ClangV1 |
\n";
- }
- else
- { # go to the version number
- push(@VInf1, "clang ".$ClangV1);
- push(@VInf2, "clang ".$ClangV2);
- }
- }
- elsif($GccV1 and $ClangV2)
- {
- push(@VInf1, "gcc ".$GccV1);
- push(@VInf2, "clang ".$ClangV2);
- }
- elsif($ClangV1 and $GccV2)
- {
- push(@VInf1, "clang ".$ClangV1);
- push(@VInf2, "gcc ".$GccV2);
- }
- }
- # show long version names with GCC version and CPU architecture name (if different)
- $TestInfo .= "| Version #1 | ".$In::Desc{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")." |
\n";
- $TestInfo .= "| Version #2 | ".$In::Desc{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")." |
\n";
- $TestInfo .= $AddTestInfo;
-
- if($In::Opt{"ExtendedCheck"}) {
- $TestInfo .= "| Mode | Extended |
\n";
- }
- if($In::Opt{"JoinReport"})
- {
- if($Level eq "Binary") {
- $TestInfo .= "| Subject | Binary Compatibility |
\n"; # Run-time
- }
- elsif($Level eq "Source") {
- $TestInfo .= "| Subject | Source Compatibility |
\n"; # Build-time
- }
- }
- $TestInfo .= "
\n";
-
- # test results
- $TestResults = "Test Results
\n";
- $TestResults .= "";
-
- if(my @Headers = getCheckedHeaders(1))
- {
- my $Headers_Link = "".($#Headers + 1)."";
- $TestResults .= "| Total Header Files | ".$Headers_Link." |
\n";
- }
-
- if(my @Sources = keys(%{$In::ABI{1}{"Sources"}}))
- {
- my $Src_Link = "".($#Sources + 1)."";
- $TestResults .= "| Total Source Files | ".$Src_Link." |
\n";
- }
-
- if(not $In::Opt{"ExtendedCheck"})
- {
- my $Libs_Link = "0";
- $Libs_Link = "".keys(%{$In::ABI{1}{"Symbols"}})."" if(keys(%{$In::ABI{1}{"Symbols"}})>0);
- $TestResults .= "| Total ".getObjTitle()." | ".($In::Opt{"CheckHeadersOnly"}?"0 (not analyzed)":$Libs_Link)." |
\n";
- }
-
- $TestResults .= "| Total Symbols / Types | ".$TotalSymbols." / ".$TotalTypes." |
\n";
-
- my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";";
- if($In::Opt{"JoinReport"}) {
- $META_DATA = "kind:".lc($Level).";".$META_DATA;
- }
-
- my $BC_Rate = showNum(100 - $RESULT{$Level}{"Affected"});
-
- $TestResults .= "| Compatibility | \n";
- if($RESULT{$Level}{"Verdict"} eq "incompatible")
- {
- my $Cl = "incompatible";
- if($BC_Rate>=90) {
- $Cl = "warning";
- }
- elsif($BC_Rate>=80) {
- $Cl = "almost_compatible";
- }
-
- $TestResults .= "".$BC_Rate."% | \n";
- }
- else {
- $TestResults .= "100% | \n";
- }
- $TestResults .= "
\n";
- $TestResults .= "
\n";
-
- $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
- # problem summary
- $Problem_Summary = "Problem Summary
\n";
- $Problem_Summary .= "";
- $Problem_Summary .= " | Severity | Count |
";
-
- my $Added_Link = "0";
- if($Added>0)
- {
- if($In::Opt{"JoinReport"}) {
- $Added_Link = "$Added";
- }
- else {
- $Added_Link = "$Added";
- }
- }
- $META_DATA .= "added:$Added;";
- $Problem_Summary .= "| Added Symbols | - | $Added_Link |
\n";
-
- my $Removed_Link = "0";
- if($Removed>0)
- {
- if($In::Opt{"JoinReport"}) {
- $Removed_Link = "$Removed"
- }
- else {
- $Removed_Link = "$Removed"
- }
- }
- $META_DATA .= "removed:$Removed;";
- $Problem_Summary .= "| Removed Symbols | ";
- $Problem_Summary .= "High | $Removed_Link |
\n";
-
- my $TH_Link = "0";
- $TH_Link = "$T_Problems_High" if($T_Problems_High>0);
- $META_DATA .= "type_problems_high:$T_Problems_High;";
- $Problem_Summary .= "Problems with Data Types | ";
- $Problem_Summary .= "High | $TH_Link |
\n";
-
- my $TM_Link = "0";
- $TM_Link = "$T_Problems_Medium" if($T_Problems_Medium>0);
- $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
- $Problem_Summary .= "| Medium | $TM_Link |
\n";
-
- my $TL_Link = "0";
- $TL_Link = "$T_Problems_Low" if($T_Problems_Low>0);
- $META_DATA .= "type_problems_low:$T_Problems_Low;";
- $Problem_Summary .= "| Low | $TL_Link |
\n";
-
- my $IH_Link = "0";
- $IH_Link = "$I_Problems_High" if($I_Problems_High>0);
- $META_DATA .= "interface_problems_high:$I_Problems_High;";
- $Problem_Summary .= "Problems with Symbols | ";
- $Problem_Summary .= "High | $IH_Link |
\n";
-
- my $IM_Link = "0";
- $IM_Link = "$I_Problems_Medium" if($I_Problems_Medium>0);
- $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
- $Problem_Summary .= "| Medium | $IM_Link |
\n";
-
- my $IL_Link = "0";
- $IL_Link = "$I_Problems_Low" if($I_Problems_Low>0);
- $META_DATA .= "interface_problems_low:$I_Problems_Low;";
- $Problem_Summary .= "| Low | $IL_Link |
\n";
-
- my $ChangedConstants_Link = "0";
- if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low) {
- $ChangedConstants_Link = "$C_Problems_Low";
- }
- $META_DATA .= "changed_constants:$C_Problems_Low;";
- $Problem_Summary .= "Problems with Constants | Low | $ChangedConstants_Link |
\n";
-
- # Safe Changes
- if($T_Other)
- {
- my $TS_Link = "$T_Other";
- $Problem_Summary .= "Other Changes in Data Types | - | $TS_Link |
\n";
- $META_DATA .= "type_changes_other:$T_Other;";
- }
-
- if($I_Other)
- {
- my $IS_Link = "$I_Other";
- $Problem_Summary .= "Other Changes in Symbols | - | $IS_Link |
\n";
- $META_DATA .= "interface_changes_other:$I_Other;";
- }
-
- if($C_Other)
- {
- my $CS_Link = "$C_Other";
- $Problem_Summary .= "Other Changes in Constants | - | $CS_Link |
\n";
- $META_DATA .= "constant_changes_other:$C_Other;";
- }
-
- $META_DATA .= "tool_version:$TOOL_VERSION";
- $Problem_Summary .= "
\n";
-
- return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA, $AnyChanged);
- }
-}
-
-sub getStyle($$$)
-{
- my ($Subj, $Act, $Num) = @_;
- my %Style = (
- "Added"=>"new",
- "Removed"=>"failed",
- "Safe"=>"passed",
- "Low"=>"warning",
- "Medium"=>"failed",
- "High"=>"failed"
- );
-
- if($Num>0) {
- return " class='".$Style{$Act}."'";
- }
-
- return "";
-}
-
-sub getReportChangedConstants($$)
-{
- my ($TargetSeverity, $Level) = @_;
- my $CHANGED_CONSTANTS = "";
-
- my %ReportMap = ();
- foreach my $Constant (keys(%{$CompatProblems_Constants{$Level}}))
- {
- my $Header = $Constants{1}{$Constant}{"Header"};
- if(not $Header) {
- $Header = $Constants{1}{$Constant}{"Source"};
- }
- if(not $Header)
- { # added
- $Header = $Constants{2}{$Constant}{"Header"};
- if(not $Header) {
- $Header = $Constants{2}{$Constant}{"Source"}
- }
- }
-
- foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$CompatProblems_Constants{$Level}{$Constant}}))
- {
- if(not defined $CompatRules{$Level}{$Kind}) {
- next;
- }
- if($TargetSeverity ne $CompatRules{$Level}{$Kind}{"Severity"}) {
- next;
- }
- $ReportMap{$Header}{$Constant}{$Kind} = 1;
- }
- }
-
- if($In::Opt{"ReportFormat"} eq "xml")
- { # XML
- foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
- {
- $CHANGED_CONSTANTS .= " \n";
- foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
- {
- $CHANGED_CONSTANTS .= " \n";
- foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}{$Constant}}))
- {
- my $Change = $CompatRules{$Level}{$Kind}{"Change"};
- my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
- my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
-
- $CHANGED_CONSTANTS .= " \n";
- $CHANGED_CONSTANTS .= " $Change\n";
- $CHANGED_CONSTANTS .= " $Effect\n";
- if($Overcome) {
- $CHANGED_CONSTANTS .= " $Overcome\n";
- }
- $CHANGED_CONSTANTS .= " \n";
- }
- $CHANGED_CONSTANTS .= " \n";
- }
- $CHANGED_CONSTANTS .= " \n";
- }
- $CHANGED_CONSTANTS = "\n".$CHANGED_CONSTANTS."\n\n";
- }
- else
- { # HTML
- my $ProblemsNum = 0;
- foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
- {
- $CHANGED_CONSTANTS .= "$HeaderName
\n";
- foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
- {
- my $Report = "";
-
- foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}{$Constant}}))
- {
- my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $CompatProblems_Constants{$Level}{$Constant}{$Kind});
- my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
- $Report .= "\n| 1 | \n".$Change." | \n$Effect | \n
\n";
- $ProblemsNum += 1;
- }
- if($Report)
- {
- $Report = $ContentDivStart."\n\n | \nChange | \nEffect | \n
\n".$Report."
\n
\n$ContentDivEnd\n";
- $Report = $ContentSpanStart."[+] ".$Constant.$ContentSpanEnd."
\n".$Report;
- $Report = insertIDs($Report);
- }
- $CHANGED_CONSTANTS .= $Report;
- }
- $CHANGED_CONSTANTS .= "
\n";
- }
- if($CHANGED_CONSTANTS)
- {
- my $Title = "Problems with Constants, $TargetSeverity Severity";
- if($TargetSeverity eq "Safe")
- { # Safe Changes
- $Title = "Other Changes in Constants";
- }
- if($In::Opt{"OldStyle"}) {
- $CHANGED_CONSTANTS = "$Title ($ProblemsNum)
\n".$CHANGED_CONSTANTS;
- }
- else {
- $CHANGED_CONSTANTS = "$Title $ProblemsNum
\n".$CHANGED_CONSTANTS;
- }
- $CHANGED_CONSTANTS = "\n".$CHANGED_CONSTANTS.$TOP_REF."
\n";
- }
- }
- return $CHANGED_CONSTANTS;
-}
-
-sub getTitle($$$)
-{
- my ($Header, $Library, $NameSpace) = @_;
- my $Title = "";
-
- if($Header and $Library)
- {
- $Title .= "$Header";
- $Title .= ", $Library
\n";
- }
- elsif($Library) {
- $Title .= "$Library
\n";
- }
- elsif($Header) {
- $Title .= "$Header
\n";
- }
-
- if($NameSpace) {
- $Title .= "namespace $NameSpace
\n";
- }
-
- return $Title;
-}
-
-sub getReportAdded($)
-{
- my $Level = $_[0];
- my $ADDED_INTERFACES = "";
- my %ReportMap = ();
- foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
- {
- foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
- {
- if($Kind eq "Added_Symbol")
- {
- my $HeaderName = $CompSign{2}{$Symbol}{"Header"};
- if(not $HeaderName) {
- $HeaderName = $CompSign{2}{$Symbol}{"Source"};
- }
-
- my $DyLib = $In::ABI{2}{"SymLib"}{$Symbol};
- if($Level eq "Source" and $In::Opt{"ReportFormat"} eq "html")
- { # do not show library name in the HTML report
- $DyLib = "";
- }
- $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
- }
- }
- }
- if($In::Opt{"ReportFormat"} eq "xml")
- { # XML
- foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
- {
- $ADDED_INTERFACES .= " \n";
- foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
- {
- $ADDED_INTERFACES .= " \n";
- foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
- $ADDED_INTERFACES .= " $Symbol\n";
- }
- $ADDED_INTERFACES .= " \n";
- }
- $ADDED_INTERFACES .= " \n";
- }
- $ADDED_INTERFACES = "\n".$ADDED_INTERFACES."\n\n";
- }
- else
- { # HTML
- my $Added_Number = 0;
- foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
- {
- foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
- {
- my %NameSpaceSymbols = ();
- foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
- $NameSpaceSymbols{selectSymbolNs($Symbol, 2)}{$Symbol} = 1;
- }
- foreach my $NameSpace (sort keys(%NameSpaceSymbols))
- {
- $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
- my @SortedInterfaces = sort {lc($CompSign{2}{$a}{"Unmangled"}) cmp lc($CompSign{2}{$b}{"Unmangled"})} sort {lc($a) cmp lc($b)} keys(%{$NameSpaceSymbols{$NameSpace}});
- foreach my $Symbol (@SortedInterfaces)
- {
- $Added_Number += 1;
- my $Signature = highLight_ItalicColor($Symbol, 2);
- if($NameSpace) {
- $Signature = cutNs($Signature, $NameSpace);
- }
-
- if($Symbol=~/\A(_Z|\?)/) {
- $ADDED_INTERFACES .= insertIDs($ContentSpanStart.$Signature.$ContentSpanEnd."
\n".$ContentDivStart."$Symbol\n
\n
\n".$ContentDivEnd."\n");
- }
- else {
- $ADDED_INTERFACES .= "".$Signature."
\n";
- }
- }
- $ADDED_INTERFACES .= "
\n";
- }
- }
- }
- if($ADDED_INTERFACES)
- {
- my $Anchor = "";
- if($In::Opt{"JoinReport"}) {
- $Anchor = "";
- }
- if($In::Opt{"OldStyle"}) {
- $ADDED_INTERFACES = "Added Symbols ($Added_Number)
\n".$ADDED_INTERFACES;
- }
- else {
- $ADDED_INTERFACES = "Added Symbols $Added_Number
\n".$ADDED_INTERFACES;
- }
- $ADDED_INTERFACES = $Anchor.$ADDED_INTERFACES.$TOP_REF."
\n";
- }
- }
- return $ADDED_INTERFACES;
-}
-
-sub getReportRemoved($)
-{
- my $Level = $_[0];
- my $REMOVED_INTERFACES = "";
- my %ReportMap = ();
- foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
- {
- foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
- {
- if($Kind eq "Removed_Symbol")
- {
- my $HeaderName = $CompSign{1}{$Symbol}{"Header"};
- if(not $HeaderName) {
- $HeaderName = $CompSign{1}{$Symbol}{"Source"};
- }
-
- my $DyLib = $In::ABI{1}{"SymLib"}{$Symbol};
- if($Level eq "Source" and $In::Opt{"ReportFormat"} eq "html")
- { # do not show library name in HTML report
- $DyLib = "";
- }
- $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
- }
- }
- }
- if($In::Opt{"ReportFormat"} eq "xml")
- { # XML
- foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
- {
- $REMOVED_INTERFACES .= " \n";
- foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
- {
- $REMOVED_INTERFACES .= " \n";
- foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
- $REMOVED_INTERFACES .= " $Symbol\n";
- }
- $REMOVED_INTERFACES .= " \n";
- }
- $REMOVED_INTERFACES .= " \n";
- }
- $REMOVED_INTERFACES = "\n".$REMOVED_INTERFACES."\n\n";
- }
- else
- { # HTML
- my $Removed_Number = 0;
- foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
- {
- foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
- {
- my %NameSpaceSymbols = ();
- foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
- $NameSpaceSymbols{selectSymbolNs($Interface, 1)}{$Interface} = 1;
- }
- foreach my $NameSpace (sort keys(%NameSpaceSymbols))
- {
- $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
- my @SortedInterfaces = sort {lc($CompSign{1}{$a}{"Unmangled"}) cmp lc($CompSign{1}{$b}{"Unmangled"})} sort {lc($a) cmp lc($b)} keys(%{$NameSpaceSymbols{$NameSpace}});
- foreach my $Symbol (@SortedInterfaces)
- {
- $Removed_Number += 1;
- my $Signature = highLight_ItalicColor($Symbol, 1);
- if($NameSpace) {
- $Signature = cutNs($Signature, $NameSpace);
- }
- if($Symbol=~/\A(_Z|\?)/) {
- $REMOVED_INTERFACES .= insertIDs($ContentSpanStart.$Signature.$ContentSpanEnd."
\n".$ContentDivStart."$Symbol\n
\n
\n".$ContentDivEnd."\n");
- }
- else {
- $REMOVED_INTERFACES .= "".$Signature."
\n";
- }
- }
- }
- $REMOVED_INTERFACES .= "
\n";
- }
- }
- if($REMOVED_INTERFACES)
- {
- my $Anchor = "";
- if($In::Opt{"JoinReport"}) {
- $Anchor = "";
- }
- if($In::Opt{"OldStyle"}) {
- $REMOVED_INTERFACES = "Removed Symbols ($Removed_Number)
\n".$REMOVED_INTERFACES;
- }
- else {
- $REMOVED_INTERFACES = "Removed Symbols $Removed_Number
\n".$REMOVED_INTERFACES;
- }
-
- $REMOVED_INTERFACES = $Anchor.$REMOVED_INTERFACES.$TOP_REF."
\n";
- }
- }
- return $REMOVED_INTERFACES;
-}
-
-sub getXmlParams($$)
-{
- my ($Content, $Problem) = @_;
-
- my %XMLparams = ();
- foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
- {
- my $Macro = "\@".lc($Attr);
- if($Content=~/\Q$Macro\E/)
- {
- my $Value = $Problem->{$Attr};
-
- if($Attr eq "Param_Pos") {
- $Value = showPos($Value);
- }
-
- $XMLparams{lc($Attr)} = $Value;
- }
- }
- my @PString = ();
- foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
- push(@PString, $P."=\"".xmlSpecChars($XMLparams{$P})."\"");
- }
- if(@PString) {
- return " ".join(" ", @PString);
- }
- return "";
-}
-
-sub addMarkup($)
-{
- my $Content = $_[0];
-
- # auto-markup
- $Content=~s/\n[ ]*//; # spaces
- $Content=~s!(\@\w+\s*\(\@\w+\))!$1!g; # @old_type (@old_size)
- $Content=~s!(... \(\w+\))!$1!g; # ... (va_list)
- $Content=~s!(.+?)!$1!g;
- $Content=~s!([2-9]\))!
$1!g; # 1), 2), ...
-
- if($Content=~/\ANOTE:/)
- { # notes
- $Content=~s!(NOTE):!$1:!g;
- }
- else {
- $Content=~s!(NOTE):!
$1:!g;
- }
- $Content=~s! (out)-! $1-!g; # out-parameters
-
- my @Keywords = (
- "void",
- "const",
- "static",
- "restrict",
- "volatile",
- "register",
- "virtual"
- );
- my $MKeys = join("|", @Keywords);
- foreach (@Keywords) {
- $MKeys .= "|non-".$_;
- }
- $Content=~s!(added\s*|to\s*|from\s*|became\s*)($MKeys)([^\w-]|\Z)!$1$2$3!ig; # intrinsic types, modifiers
-
- # Markdown
- $Content=~s!\*\*([\w\-]+?)\*\*!$1!ig;
- $Content=~s!\*([\w\-]+?)\*!$1!ig;
-
- return $Content;
-}
-
-sub applyMacroses($$$$)
-{
- my ($Level, $Kind, $Content, $Problem) = @_;
-
- $Problem->{"Word_Size"} = $In::ABI{2}{"WordSize"};
- $Content = addMarkup($Content);
-
- # macros
- foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
- {
- my $Macro = "\@".lc($Attr);
- my $Value = $Problem->{$Attr};
- if(not defined $Value
- or $Value eq "") {
- next;
- }
-
- if(index($Content, $Macro)==-1) {
- next;
- }
-
- if($Attr eq "Param_Pos") {
- $Value = showPos($Value);
- }
-
- if($Value=~/\s/) {
- $Value = "".specChars($Value)."";
- }
- elsif($Value=~/\A\d+\Z/
- and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
- { # bits to bytes
- if($Value % $BYTE)
- { # bits
- if($Value==1) {
- $Value = "".$Value." bit";
- }
- else {
- $Value = "".$Value." bits";
- }
- }
- else
- { # bytes
- $Value /= $BYTE;
- if($Value==1) {
- $Value = "".$Value." byte";
- }
- else {
- $Value = "".$Value." bytes";
- }
- }
- }
- else
- {
- my $Fmt = "Class|Name|Qual|HTML|Desc";
- if($Kind!~/Overridden/) {
- $Fmt = "Name|Qual|HTML|Desc";
- }
-
- my $V1 = (defined $CompSign{1}{$Value} and defined $CompSign{1}{$Value}{"ShortName"});
- my $V2 = (defined $CompSign{2}{$Value} and defined $CompSign{2}{$Value}{"ShortName"});
-
- if($Kind!~/Symbol_Became|Symbol_Changed|Method_Became/
- and ($V1 or $V2))
- { # symbols
- if($V1) {
- $Value = blackName(getSignature($Value, 1, $Fmt));
- }
- else {
- $Value = blackName(getSignature($Value, 2, $Fmt));
- }
- }
- else
- {
- $Value = "".specChars($Value)."";
- }
- }
- $Content=~s/\Q$Macro\E/$Value/g;
- }
-
- if($Content=~/(\A|[^\@\w])\@\w/)
- {
- if(not $IncompleteRules{$Level}{$Kind})
- { # only one warning
- printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
- $IncompleteRules{$Level}{$Kind} = 1;
- }
- }
- return $Content;
-}
-
-sub getReportSymbolProblems($$)
-{
- my ($TargetSeverity, $Level) = @_;
- my $INTERFACE_PROBLEMS = "";
- my (%ReportMap, %SymbolChanges) = ();
-
- foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
- {
- my ($SN, $SS, $SV) = symbolParts($Symbol);
- if($SV and defined $CompatProblems{$Level}{$SN}) {
- next;
- }
-
- if(not defined $CompSign{1}{$Symbol})
- { # added symbols
- next;
- }
-
- my $HeaderName = $CompSign{1}{$Symbol}{"Header"};
- if(not $HeaderName) {
- $HeaderName = $CompSign{1}{$Symbol}{"Source"};
- }
-
- my $DyLib = $In::ABI{1}{"SymLib"}{$Symbol};
- if(not $DyLib and my $VSym = $In::ABI{1}{"SymbolVersion"}{$Symbol})
- { # Symbol with Version
- $DyLib = $In::ABI{1}{"SymLib"}{$VSym};
- }
- if(not $DyLib)
- { # const global data
- $DyLib = "";
- }
- if($Level eq "Source" and $In::Opt{"ReportFormat"} eq "html")
- { # do not show library name in HTML report
- $DyLib = "";
- }
-
- foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
- {
- if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
- and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol")
- {
- my $Severity = $CompatRules{$Level}{$Kind}{"Severity"};
- if($Severity eq $TargetSeverity)
- {
- $SymbolChanges{$Symbol}{$Kind} = $CompatProblems{$Level}{$Symbol}{$Kind};
- $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
- }
- }
- }
- }
-
- if($In::Opt{"ReportFormat"} eq "xml")
- { # XML
- foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
- {
- $INTERFACE_PROBLEMS .= " \n";
- foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
- {
- $INTERFACE_PROBLEMS .= " \n";
-
- my @SortedInterfaces = sort {lc($CompSign{1}{$a}{"Unmangled"}) cmp lc($CompSign{1}{$b}{"Unmangled"})} sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}{$DyLib}});
- foreach my $Symbol (@SortedInterfaces)
- {
- $INTERFACE_PROBLEMS .= " \n";
- foreach my $Kind (sort keys(%{$SymbolChanges{$Symbol}}))
- {
- foreach my $Loc (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
- {
- my $ProblemAttr = $SymbolChanges{$Symbol}{$Kind}{$Loc};
-
- $INTERFACE_PROBLEMS .= " \n";
- my $Change = $CompatRules{$Level}{$Kind}{"Change"};
- $INTERFACE_PROBLEMS .= " $Change\n";
- my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
- $INTERFACE_PROBLEMS .= " $Effect\n";
- if(my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"}) {
- $INTERFACE_PROBLEMS .= " $Overcome\n";
- }
- $INTERFACE_PROBLEMS .= " \n";
- }
- }
- $INTERFACE_PROBLEMS .= " \n";
- }
- $INTERFACE_PROBLEMS .= " \n";
- }
- $INTERFACE_PROBLEMS .= " \n";
- }
- $INTERFACE_PROBLEMS = "\n".$INTERFACE_PROBLEMS."\n\n";
- }
- else
- { # HTML
- my $ProblemsNum = 0;
- foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
- {
- foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
- {
- my (%NameSpaceSymbols, %NewSignature) = ();
- foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
- $NameSpaceSymbols{selectSymbolNs($Symbol, 1)}{$Symbol} = 1;
- }
- foreach my $NameSpace (sort keys(%NameSpaceSymbols))
- {
- $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
-
- my @SortedInterfaces = sort {lc($CompSign{1}{$a}{"Unmangled"}) cmp lc($CompSign{1}{$b}{"Unmangled"})} sort {lc($a) cmp lc($b)} keys(%{$NameSpaceSymbols{$NameSpace}});
- foreach my $Symbol (@SortedInterfaces)
- {
- my $SYMBOL_REPORT = "";
- my $ProblemNum = 1;
- foreach my $Kind (sort keys(%{$SymbolChanges{$Symbol}}))
- {
- foreach my $Loc (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
- {
- my $ProblemAttr = $SymbolChanges{$Symbol}{$Kind}{$Loc};
-
- if(my $NSign = $ProblemAttr->{"New_Signature"}) {
- $NewSignature{$Symbol} = $NSign;
- }
-
- if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemAttr))
- {
- my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, $ProblemAttr);
- $SYMBOL_REPORT .= "\n| $ProblemNum | \n".$Change." | \n".$Effect." | \n
\n";
- $ProblemNum += 1;
- $ProblemsNum += 1;
- }
- }
- }
- $ProblemNum -= 1;
- if($SYMBOL_REPORT)
- {
- my $ShowSymbol = highLight_ItalicColor($Symbol, 1);
-
- if($NameSpace)
- {
- $SYMBOL_REPORT = cutNs($SYMBOL_REPORT, $NameSpace);
- $ShowSymbol = cutNs($ShowSymbol, $NameSpace);
- }
-
- $INTERFACE_PROBLEMS .= $ContentSpanStart."[+] ".$ShowSymbol;
- if($In::Opt{"OldStyle"}) {
- $INTERFACE_PROBLEMS .= " ($ProblemNum)";
- }
- else {
- $INTERFACE_PROBLEMS .= " $ProblemNum ";
- }
- $INTERFACE_PROBLEMS .= $ContentSpanEnd."
\n";
- $INTERFACE_PROBLEMS .= $ContentDivStart."\n";
-
- if(my $NSign = $NewSignature{$Symbol})
- { # argument list changed to
- $NSign = highLight_ItalicColor($NSign, 2);
- if($NameSpace) {
- $NSign = cutNs($NSign, $NameSpace);
- }
- $INTERFACE_PROBLEMS .= "\n⇣\n
\n".$NSign."
\n";
- }
-
- if($Symbol=~/\A(_Z|\?)/) {
- $INTERFACE_PROBLEMS .= "$Symbol
\n";
- }
-
- $INTERFACE_PROBLEMS .= "\n\n | \nChange | \nEffect | \n
\n$SYMBOL_REPORT
\n
\n";
- $INTERFACE_PROBLEMS .= $ContentDivEnd;
- }
- }
- $INTERFACE_PROBLEMS .= "
\n";
- }
- }
- }
-
- if($INTERFACE_PROBLEMS)
- {
- $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS);
- my $Title = "Problems with Symbols, $TargetSeverity Severity";
- if($TargetSeverity eq "Safe")
- { # Safe Changes
- $Title = "Other Changes in Symbols";
- }
- if($In::Opt{"OldStyle"}) {
- $INTERFACE_PROBLEMS = "$Title ($ProblemsNum)
\n".$INTERFACE_PROBLEMS;
- }
- else {
- $INTERFACE_PROBLEMS = "$Title $ProblemsNum
\n".$INTERFACE_PROBLEMS;
- }
- $INTERFACE_PROBLEMS = "\n".$INTERFACE_PROBLEMS.$TOP_REF."
\n";
- }
- }
- return $INTERFACE_PROBLEMS;
-}
-
-sub cutNs($$)
-{
- my ($N, $Ns) = @_;
- $N=~s/\b\Q$Ns\E:://g;
- return $N;
-}
-
-sub getReportTypeProblems($$)
-{
- my ($TargetSeverity, $Level) = @_;
- my $TYPE_PROBLEMS = "";
-
- my %ReportMap = ();
- my %TypeChanges_Sev = ();
-
- foreach my $TypeName (keys(%{$TypeChanges{$Level}}))
- {
- my $Tid = $TName_Tid{1}{$TypeName};
- my $HeaderName = $TypeInfo{1}{$Tid}{"Header"};
- if(not $HeaderName) {
- $HeaderName = $TypeInfo{1}{$Tid}{"Source"};
- }
-
- foreach my $Kind (keys(%{$TypeChanges{$Level}{$TypeName}}))
- {
- if($CompatRules{$Level}{$Kind}{"Severity"} ne $TargetSeverity) {
- next;
- }
-
- foreach my $Loc (keys(%{$TypeChanges{$Level}{$TypeName}{$Kind}}))
- {
- $ReportMap{$HeaderName}{$TypeName} = 1;
- $TypeChanges_Sev{$TypeName}{$Kind}{$Loc} = $TypeChanges{$Level}{$TypeName}{$Kind}{$Loc};
- }
- }
- }
-
- if($In::Opt{"ReportFormat"} eq "xml")
- { # XML
- foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
- {
- $TYPE_PROBLEMS .= " \n";
- foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
- {
- my (%Kinds_Locations, %Kinds_Target) = ();
- $TYPE_PROBLEMS .= " \n";
- foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges_Sev{$TypeName}}))
- {
- foreach my $Loc (sort {cmpLocations($b, $a)} sort keys(%{$TypeChanges_Sev{$TypeName}{$Kind}}))
- {
- $Kinds_Locations{$Kind}{$Loc} = 1;
-
- my $Target = $TypeChanges_Sev{$TypeName}{$Kind}{$Loc}{"Target"};
- if($Kinds_Target{$Kind}{$Target}) {
- next;
- }
- $Kinds_Target{$Kind}{$Target} = 1;
-
- my $ProblemAttr = $TypeChanges_Sev{$TypeName}{$Kind}{$Loc};
- $TYPE_PROBLEMS .= " \n";
- my $Change = $CompatRules{$Level}{$Kind}{"Change"};
- $TYPE_PROBLEMS .= " $Change\n";
- my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
- $TYPE_PROBLEMS .= " $Effect\n";
- if(my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"}) {
- $TYPE_PROBLEMS .= " $Overcome\n";
- }
- $TYPE_PROBLEMS .= " \n";
- }
- }
- $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, \%Kinds_Locations);
- if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%Kinds_Locations)) {
- $TYPE_PROBLEMS .= showVTables($TypeName);
- }
- $TYPE_PROBLEMS .= " \n";
- }
- $TYPE_PROBLEMS .= " \n";
- }
- $TYPE_PROBLEMS = "\n".$TYPE_PROBLEMS."\n\n";
- }
- else
- { # HTML
- my $ProblemsNum = 0;
- foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
- {
- my (%NameSpace_Type) = ();
- foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
- $NameSpace_Type{selectTypeNs($TypeName, 1)}{$TypeName} = 1;
- }
- foreach my $NameSpace (sort keys(%NameSpace_Type))
- {
- $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
- my @SortedTypes = sort {lc(showType($a, 0, 1)) cmp lc(showType($b, 0, 1))} keys(%{$NameSpace_Type{$NameSpace}});
- foreach my $TypeName (@SortedTypes)
- {
- my $ProblemNum = 1;
- my $TYPE_REPORT = "";
- my (%Kinds_Locations, %Kinds_Target) = ();
-
- foreach my $Kind (sort {(index($b, "Size")!=-1) cmp (index($a, "Size")!=-1)} sort keys(%{$TypeChanges_Sev{$TypeName}}))
- {
- foreach my $Loc (sort {cmpLocations($b, $a)} sort keys(%{$TypeChanges_Sev{$TypeName}{$Kind}}))
- {
- $Kinds_Locations{$Kind}{$Loc} = 1;
-
- my $Target = $TypeChanges_Sev{$TypeName}{$Kind}{$Loc}{"Target"};
- if($Kinds_Target{$Kind}{$Target}) {
- next;
- }
- $Kinds_Target{$Kind}{$Target} = 1;
-
- my $ProblemAttr = $TypeChanges_Sev{$TypeName}{$Kind}{$Loc};
- if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemAttr))
- {
- my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, $ProblemAttr);
- $TYPE_REPORT .= "\n| $ProblemNum | \n".$Change." | \n$Effect | \n
\n";
- $ProblemNum += 1;
- $ProblemsNum += 1;
- }
- }
- }
- $ProblemNum -= 1;
- if($TYPE_REPORT)
- {
- my $Affected = getAffectedSymbols($Level, $TypeName, \%Kinds_Locations);
- my $ShowVTables = "";
- if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%Kinds_Locations)) {
- $ShowVTables = showVTables($TypeName);
- }
-
- my $ShowType = showType($TypeName, 1, 1);
-
- if($NameSpace)
- {
- $TYPE_REPORT = cutNs($TYPE_REPORT, $NameSpace);
- $ShowType = cutNs($ShowType, $NameSpace);
- $Affected = cutNs($Affected, $NameSpace);
- $ShowVTables = cutNs($ShowVTables, $NameSpace);
- }
-
- $TYPE_PROBLEMS .= $ContentSpanStart."[+] ".$ShowType;
- if($In::Opt{"OldStyle"}) {
- $TYPE_PROBLEMS .= " ($ProblemNum)";
- }
- else {
- $TYPE_PROBLEMS .= " $ProblemNum ";
- }
- $TYPE_PROBLEMS .= $ContentSpanEnd;
- $TYPE_PROBLEMS .= "
\n".$ContentDivStart."\n";
- $TYPE_PROBLEMS .= " | \nChange | \n";
- $TYPE_PROBLEMS .= "Effect |
".$TYPE_REPORT."
\n";
- $TYPE_PROBLEMS .= $ShowVTables.$Affected."
".$ContentDivEnd."\n";
- }
- }
- $TYPE_PROBLEMS .= "
\n";
- }
- }
-
- if($TYPE_PROBLEMS)
- {
- $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
- my $Title = "Problems with Data Types, $TargetSeverity Severity";
- if($TargetSeverity eq "Safe")
- { # Safe Changes
- $Title = "Other Changes in Data Types";
- }
- if($In::Opt{"OldStyle"}) {
- $TYPE_PROBLEMS = "$Title ($ProblemsNum)
\n".$TYPE_PROBLEMS;
- }
- else {
- $TYPE_PROBLEMS = "$Title $ProblemsNum
\n".$TYPE_PROBLEMS;
- }
- $TYPE_PROBLEMS = "\n".$TYPE_PROBLEMS.$TOP_REF."
\n";
- }
- }
- return $TYPE_PROBLEMS;
-}
-
-sub showType($$$)
-{
- my ($Name, $Html, $LVer) = @_;
- my $TType = $TypeInfo{$LVer}{$TName_Tid{$LVer}{$Name}}{"Type"};
- $TType = lc($TType);
- if($TType=~/struct|union|enum/) {
- $Name=~s/\A\Q$TType\E //g;
- }
- if($Html) {
- $Name = "".$TType." ".specChars($Name);
- }
- else {
- $Name = $TType." ".$Name;
- }
- return $Name;
-}
-
-sub getAnchor($$$)
-{
- my ($Kind, $Level, $Severity) = @_;
- if($In::Opt{"JoinReport"})
- {
- if($Severity eq "Safe") {
- return "Other_".$Level."_Changes_In_".$Kind."s";
- }
- else {
- return $Kind."_".$Level."_Problems_".$Severity;
- }
- }
- else
- {
- if($Severity eq "Safe") {
- return "Other_Changes_In_".$Kind."s";
- }
- else {
- return $Kind."_Problems_".$Severity;
- }
- }
-}
-
-sub showVTables($)
-{
- my $TypeName = $_[0];
- my $TypeId1 = $TName_Tid{1}{$TypeName};
- my %Type1 = getType($TypeId1, 1);
- if(defined $Type1{"VTable"}
- and keys(%{$Type1{"VTable"}}))
- {
- my $TypeId2 = $TName_Tid{2}{$TypeName};
- my %Type2 = getType($TypeId2, 2);
- if(defined $Type2{"VTable"}
- and keys(%{$Type2{"VTable"}}))
- {
- my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
- my %Entries = ();
- foreach my $Index (sort {$a<=>$b} (keys(%Indexes)))
- {
- $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index});
- $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index});
- }
- my $VTABLES = "";
- if($In::Opt{"ReportFormat"} eq "xml")
- { # XML
- $VTABLES .= " \n";
- foreach my $Index (sort {$a<=>$b} (keys(%Entries)))
- {
- $VTABLES .= " \n";
- $VTABLES .= " ".xmlSpecChars($Entries{$Index}{"E1"})."\n";
- $VTABLES .= " ".xmlSpecChars($Entries{$Index}{"E2"})."\n";
- $VTABLES .= " \n";
- }
- $VTABLES .= " \n\n";
- }
- else
- { # HTML
- $VTABLES .= "";
- $VTABLES .= "| Offset | ";
- $VTABLES .= "Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries | ";
- $VTABLES .= "Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries |
";
- foreach my $Index (sort {$a<=>$b} (keys(%Entries)))
- {
- my ($Color1, $Color2) = ("", "");
-
- my $E1 = $Entries{$Index}{"E1"};
- my $E2 = $Entries{$Index}{"E2"};
-
- if($E1 ne $E2
- and $E1!~/ 0x/
- and $E2!~/ 0x/)
- {
- if($Entries{$Index}{"E1"})
- {
- $Color1 = " class='failed'";
- $Color2 = " class='failed'";
- }
- else {
- $Color2 = " class='warning'";
- }
- }
- $VTABLES .= "| ".$Index." | \n";
- $VTABLES .= "".specChars($Entries{$Index}{"E1"})." | \n";
- $VTABLES .= "".specChars($Entries{$Index}{"E2"})." |
\n";
- }
- $VTABLES .= "
\n";
- $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
- $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."
\n".$VTABLES;
- }
- return $VTABLES;
- }
- }
- return "";
-}
-
-sub simpleVEntry($)
-{
- my $VEntry = $_[0];
- if(not defined $VEntry
- or $VEntry eq "") {
- return "";
- }
-
- $VEntry=~s/ \[.+?\]\Z//; # support for ABI Dumper
- $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
- $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
- if($VEntry=~/\A_ZThn.+\Z/) {
- $VEntry = "non-virtual thunk";
- }
- $VEntry=~s/\A\(int \(\*\)\(...\)\)\s*([a-z_])/$1/i;
- # support for old GCC versions
- $VEntry=~s/\A0u\Z/(int (*)(...))0/;
- $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
- $VEntry=~s/\A&_Z\Z/& _Z/;
- $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
- return $VEntry;
-}
-
-sub adjustParamPos($$$)
-{
- my ($Pos, $Symbol, $LVer) = @_;
- if(defined $CompSign{$LVer}{$Symbol})
- {
- if(not $CompSign{$LVer}{$Symbol}{"Static"}
- and $CompSign{$LVer}{$Symbol}{"Class"})
- {
- return $Pos-1;
- }
-
- return $Pos;
- }
-
- return undef;
-}
-
-sub getParamPos($$$)
-{
- my ($Name, $Symbol, $LVer) = @_;
-
- if(defined $CompSign{$LVer}{$Symbol}
- and defined $CompSign{$LVer}{$Symbol}{"Param"})
- {
- my $Info = $CompSign{$LVer}{$Symbol};
- foreach (keys(%{$Info->{"Param"}}))
- {
- if($Info->{"Param"}{$_}{"name"} eq $Name)
- {
- return $_;
- }
- }
- }
-
- return undef;
-}
-
-sub getParamName($)
-{
- my $Loc = $_[0];
- $Loc=~s/\->.*//g;
- return $Loc;
-}
-
-sub getAffectedSymbols($$$)
-{
- my ($Level, $Target_TypeName, $Kinds_Locations) = @_;
-
- my $LIMIT = 10;
- if(defined $In::Opt{"AffectLimit"}) {
- $LIMIT = $In::Opt{"AffectLimit"};
- }
-
- my %SymSel = ();
-
- foreach my $Kind (sort keys(%{$Kinds_Locations}))
- {
- my @Locs = sort {(index($a, "retval")!=-1) cmp (index($b, "retval")!=-1)} sort {length($a)<=>length($b)} sort keys(%{$Kinds_Locations->{$Kind}});
-
- foreach my $Loc (@Locs)
- {
- foreach my $Symbol (keys(%{$TypeProblemsIndex{$Level}{$Target_TypeName}{$Kind}{$Loc}}))
- {
- if(index($Symbol, "_Z")==0
- and $Symbol=~/(C4|C2|D4|D2|D0)[EI]/)
- { # duplicated problems for C2/C4 constructors, D2/D4 and D0 destructors
- next;
- }
-
- if(index($Symbol, "\@")!=-1
- or index($Symbol, "\$")!=-1)
- {
- my ($SN, $SS, $SV) = symbolParts($Symbol);
-
- if($Level eq "Source")
- { # remove symbol version
- $Symbol = $SN;
- }
-
- if($SV and defined $CompatProblems{$Level}{$SN})
- { # duplicated problems for versioned symbols
- next;
- }
- }
-
- if(not defined $SymSel{$Symbol})
- {
- $SymSel{$Symbol}{"Kind"} = $Kind;
- $SymSel{$Symbol}{"Loc"} = $Loc;
- }
- }
- }
- }
-
- my $Affected = "";
- my $SNum = 0;
-
- if($In::Opt{"ReportFormat"} eq "xml")
- { # XML
- $Affected .= " \n";
-
- foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%SymSel))
- {
- my $Kind = $SymSel{$Symbol}{"Kind"};
- my $Loc = $SymSel{$Symbol}{"Loc"};
-
- my $PName = getParamName($Loc);
- my $Des = getAffectDesc($Level, $Symbol, $Kind, $Loc);
-
- my $Target = "";
- if($PName)
- {
- $Target .= " param=\"$PName\"";
- $Des=~s/parameter $PName /parameter \@param /;
- }
- elsif($Loc=~/\Aretval(\-|\Z)/i) {
- $Target .= " affected=\"retval\"";
- }
- elsif($Loc=~/\Athis(\-|\Z)/i) {
- $Target .= " affected=\"this\"";
- }
-
- if($Des=~s/\AField ([^\s]+) /Field \@field /) {
- $Target .= " field=\"$1\"";
- }
-
- $Affected .= " \n";
- $Affected .= " ".xmlSpecChars($Des)."\n";
- $Affected .= " \n";
-
- if(++$SNum>=$LIMIT) {
- last;
- }
- }
- $Affected .= " \n";
- }
- else
- { # HTML
- foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%SymSel))
- {
- my $Kind = $SymSel{$Symbol}{"Kind"};
- my $Loc = $SymSel{$Symbol}{"Loc"};
-
- my $Des = getAffectDesc($Level, $Symbol, $Kind, $Loc);
- my $PName = getParamName($Loc);
- my $Pos = adjustParamPos(getParamPos($PName, $Symbol, 1), $Symbol, 1);
-
- $Affected .= "".getSignature($Symbol, 1, "Class|Name|Param|HTML|Italic|Target=".$Pos)."
\n";
- $Affected .= "".specChars($Des)."
\n";
-
- if(++$SNum>=$LIMIT) {
- last;
- }
- }
-
- my $Total = keys(%SymSel);
-
- if($Total>$LIMIT) {
- $Affected .= " ...\n
\n"; # and others ...
- }
-
- $Affected = "".$Affected."
\n";
- if($Affected)
- {
-
- my $Per = showNum($Total*100/keys(%{$CheckedSymbols{$Level}}));
- $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
- $Affected = $ContentSpanStart_Affected."[+] affected symbols: $Total ($Per\%)".$ContentSpanEnd.$Affected;
- }
- }
-
- return $Affected;
-}
-
-sub cmpLocations($$)
-{
- my ($L1, $L2) = @_;
- if((index($L2, "retval")==0 or index($L2, "this")==0)
- and (index($L1, "retval")!=0 and index($L1, "this")!=0))
- {
- if(index($L1, "->")==-1) {
- return 1;
- }
- elsif(index($L2, "->")!=-1) {
- return 1;
- }
- }
- return 0;
-}
-
-sub getAffectDesc($$$$)
-{
- my ($Level, $Symbol, $Kind, $Loc) = @_;
-
- if($ExtendedSymbols{$Symbol}) {
- return "This is a symbol from an external library that may use subject library and change the ABI after recompiling.";
- }
-
- my $PAttr = $CompatProblems{$Level}{$Symbol}{$Kind}{$Loc};
-
- $Loc=~s/\A(.*)\-\>(.+?)\Z/$1/; # without the latest affected field
-
- my @Sentence = ();
-
- if($Kind eq "Overridden_Virtual_Method"
- or $Kind eq "Overridden_Virtual_Method_B") {
- push(@Sentence, "The method '".$PAttr->{"New_Value"}."' will be called instead of this method.");
- }
- elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
- {
- my %SymInfo = %{$CompSign{1}{$Symbol}};
-
- if($Loc eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
- {
- my $MType = "method";
- if($SymInfo{"Constructor"}) {
- $MType = "constructor";
- }
- elsif($SymInfo{"Destructor"}) {
- $MType = "destructor";
- }
-
- my $ClassName = $TypeInfo{1}{$SymInfo{"Class"}}{"Name"};
-
- if($ClassName eq $PAttr->{"Type_Name"}) {
- push(@Sentence, "This $MType is from \'".$PAttr->{"Type_Name"}."\' class.");
- }
- else {
- push(@Sentence, "This $MType is from derived class \'".$ClassName."\'.");
- }
- }
- else
- {
- my $TypeID = undef;
-
- if($Loc=~/retval/)
- { # return value
- if(index($Loc, "->")!=-1) {
- push(@Sentence, "Field \'".$Loc."\' in the return value");
- }
- else {
- push(@Sentence, "Return value");
- }
-
- $TypeID = $SymInfo{"Return"};
- }
- elsif($Loc=~/this/)
- { # "this" pointer
- if(index($Loc, "->")!=-1) {
- push(@Sentence, "Field \'".$Loc."\' in the object of this method");
- }
- else {
- push(@Sentence, "\'this\' pointer");
- }
-
- $TypeID = $SymInfo{"Class"};
- }
- else
- { # parameters
- my $PName = getParamName($Loc);
- my $PPos = getParamPos($PName, $Symbol, 1);
-
- if(index($Loc, "->")!=-1) {
- push(@Sentence, "Field \'".$Loc."\' in ".showPos(adjustParamPos($PPos, $Symbol, 1))." parameter");
- }
- else {
- push(@Sentence, showPos(adjustParamPos($PPos, $Symbol, 1))." parameter");
- }
- if($PName) {
- push(@Sentence, "\'".$PName."\'");
- }
-
- $TypeID = $SymInfo{"Param"}{$PPos}{"type"};
- }
-
- if($Loc!~/this/)
- {
- if(my %PureType = getPureType($TypeID, 1))
- {
- if($PureType{"Type"} eq "Pointer") {
- push(@Sentence, "(pointer)");
- }
- elsif($PureType{"Type"} eq "Ref") {
- push(@Sentence, "(reference)");
- }
- }
- }
-
- if($Loc eq "this") {
- push(@Sentence, "has base type \'".$PAttr->{"Type_Name"}."\'.");
- }
- else
- {
- my $Loc_T = $Loc;
- $Loc_T=~s/\A\w+(\->|\Z)//; # location in type
-
- my $TypeID_Problem = $TypeID;
- if($Loc_T) {
- $TypeID_Problem = getFieldType($Loc_T, $TypeID, 1);
- }
-
- if($TypeInfo{1}{$TypeID_Problem}{"Name"} eq $PAttr->{"Type_Name"}) {
- push(@Sentence, "is of type \'".$PAttr->{"Type_Name"}."\'.");
- }
- else {
- push(@Sentence, "has base type \'".$PAttr->{"Type_Name"}."\'.");
- }
- }
- }
- }
-
- my $Sent = join(" ", @Sentence);
-
- $Sent=~s/->/./g;
-
- if($In::Opt{"ReportFormat"} eq "xml") {
- $Sent=~s/'//g;
- }
-
- return $Sent;
-}
-
-sub getFieldType($$$)
-{
- my ($Loc, $TypeId, $LVer) = @_;
-
- my @Fields = split(/\->/, $Loc);
-
- foreach my $Name (@Fields)
- {
- my %Info = getBaseType($TypeId, $LVer);
-
- foreach my $Pos (keys(%{$Info{"Memb"}}))
- {
- if($Info{"Memb"}{$Pos}{"name"} eq $Name)
- {
- $TypeId = $Info{"Memb"}{$Pos}{"type"};
- last;
- }
- }
- }
-
- return $TypeId;
-}
-
-sub writeReport($$)
-{
- my ($Level, $Report) = @_;
- if($In::Opt{"ReportFormat"} eq "xml") {
- $Report = "\n".$Report;
- }
- if($In::Opt{"StdOut"})
- { # --stdout option
- print STDOUT $Report;
- }
- else
- {
- my $RPath = getReportPath($Level);
- mkpath(getDirname($RPath));
-
- open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n");
- print REPORT $Report;
- close(REPORT);
- }
-}
-
-sub getReport($)
-{
- my $Level = $_[0];
- if($In::Opt{"ReportFormat"} eq "xml")
- { # XML
- if($Level eq "Join")
- {
- my $Report = "\n";
- $Report .= getReport("Binary");
- $Report .= getReport("Source");
- $Report .= "\n";
- return $Report;
- }
- else
- {
- my $Report = "\n\n";
- my ($Summary, $MetaData, $AnyChanged) = getSummary($Level);
- $Report .= $Summary."\n";
- $Report .= getReportProblems_All($Level);
- $Report .= "\n";
- return $Report;
- }
- }
- else
- { # HTML
- my $CssStyles = readModule("Styles", "Report.css");
- my $JScripts = readModule("Scripts", "Sections.js");
- if($Level eq "Join")
- {
- $CssStyles .= "\n".readModule("Styles", "Tabs.css");
- $JScripts .= "\n".readModule("Scripts", "Tabs.js");
- my $Title = $In::Opt{"TargetTitle"}.": ".$In::Desc{1}{"Version"}." to ".$In::Desc{2}{"Version"}." compatibility report";
- my $Keywords = $In::Opt{"TargetTitle"}.", compatibility, API, ABI, report";
- my $Des = "API/ABI compatibility report for the ".$In::Opt{"TargetTitle"}." ".$In::Opt{"TargetComponent"}." between ".$In::Desc{1}{"Version"}." and ".$In::Desc{2}{"Version"}." versions";
- my ($BSummary, $BMetaData, $BAnyChanged) = getSummary("Binary");
- my ($SSummary, $SMetaData, $SAnyChanged) = getSummary("Source");
- my $Report = "\n\n".composeHTML_Head($Title, $Keywords, $Des, $CssStyles, $JScripts, ($BAnyChanged or $SAnyChanged))."";
- $Report .= getReportTitle("Join")."
-
- ";
- $Report .= "\n$BSummary\n".getReportProblems_All("Binary").getSourceInfo()."
";
- $Report .= "\n$SSummary\n".getReportProblems_All("Source").getSourceInfo()."
";
- $Report .= getReportFooter();
- $Report .= "\n