ABI Compliance Checker 1.98.8
diff --git a/abi-compliance-checker.pl b/abi-compliance-checker.pl
index ea8d832..c9687b3 100755
--- a/abi-compliance-checker.pl
+++ b/abi-compliance-checker.pl
@@ -1,12 +1,12 @@
 #!/usr/bin/perl
 ###########################################################################
-# ABI Compliance Checker (ACC) 1.98.7
+# ABI Compliance Checker (ACC) 1.98.8
 # A tool for checking backward compatibility of a C/C++ library API
 #
 # Copyright (C) 2009-2010 The Linux Foundation
 # 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) 2011-2013 ROSA Laboratory
 #
 # Written by Andrey Ponomarenko
 #
@@ -57,9 +57,8 @@
 use Cwd qw(abs_path cwd realpath);
 use Data::Dumper;
 use Config;
-use Fcntl;
 
-my $TOOL_VERSION = "1.98.7";
+my $TOOL_VERSION = "1.98.8";
 my $ABI_DUMP_VERSION = "2.20";
 my $OLDEST_SUPPORTED_VERSION = "1.18";
 my $XML_REPORT_VERSION = "1.0";
@@ -87,7 +86,7 @@
 $SkipHeadersPath, $CppCompat, $LogMode, $StdOut, $ListAffected, $ReportFormat,
 $UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath,
 $SourceReportPath, $UseXML, $Browse, $OpenReport, $SortDump, $DumpFormat,
-$ExtraInfo, $ExtraDump, $Force);
+$ExtraInfo, $ExtraDump, $Force, $Tolerance, $Tolerant);
 
 my $CmdName = get_filename($0);
 my %OS_LibExt = (
@@ -263,7 +262,9 @@
   "open!" => \$OpenReport,
   "extra-info=s" => \$ExtraInfo,
   "extra-dump!" => \$ExtraDump,
-  "force!" => \$Force
+  "force!" => \$Force,
+  "tolerance=s" => \$Tolerance,
+  "tolerant!" => \$Tolerant
 ) or ERR_MESSAGE();
 
 sub ERR_MESSAGE()
@@ -742,6 +743,19 @@
       
   -force
       Try to use this option if the tool doesn't work.
+      
+  -tolerance LEVEL
+      Apply a set of heuristics to successfully compile input
+      header files. You can enable several tolerance levels by
+      joining them into one string (e.g. 13, 124, etc.).
+      Levels:
+          1 - skip non-Linux headers (e.g. win32_*.h, etc.)
+          2 - skip internal headers (e.g. *_p.h, impl/*.h, etc.)
+          3 - skip headers that iclude non-Linux headers
+          4 - skip headers included by others
+          
+  -tolerant
+      Enable highest tolerance level [1234].
 
 REPORT:
     Compatibility report will be generated to:
@@ -966,8 +980,8 @@
   "union_type" => "Union",
   "var_decl" => "Other",
   "void_type" => "Intrinsic",
-  # "nop_expr" => "Other",
-  # "addr_expr" => "Other",
+  "nop_expr" => "Other", #
+  "addr_expr" => "Other", #
   "offset_type" => "Other" );
 
 my %CppKeywords_C = map {$_=>1} (
@@ -1032,7 +1046,8 @@
 
 my %CppKeywords_A = map {$_=>1} (
     "this",
-    "throw"
+    "throw",
+    "template"
 );
 
 foreach (keys(%CppKeywords_C),
@@ -1332,9 +1347,11 @@
 
 my $STDCXX_TESTING = 0;
 my $GLIBC_TESTING = 0;
+my $CPP_HEADERS = 0;
 
 my $CheckHeadersOnly = $CheckHeadersOnly_Opt;
 my $CheckObjectsOnly = $CheckObjectsOnly_Opt;
+
 my $TargetComponent;
 
 my $CheckUndefined = 0;
@@ -1471,6 +1488,7 @@
 my %RegisteredDirs;
 my %Header_ErrorRedirect;
 my %Header_Includes;
+my %Header_Includes_R;
 my %Header_ShouldNotBeUsed;
 my %RecursiveIncludes;
 my %Header_Include_Prefix;
@@ -1557,6 +1575,7 @@
 # Recursion locks
 my @RecurLib;
 my @RecurTypes;
+my @RecurTypes_Diff;
 my @RecurInclude;
 my @RecurConstant;
 
@@ -1576,8 +1595,8 @@
 
 # Problem descriptions
 my %CompatProblems;
-my %ProblemsWithConstants;
-my %ImplProblems;
+my %CompatProblems_Constants;
+my %CompatProblems_Impl;
 my %TotalAffected;
 
 # Reports
@@ -1936,6 +1955,7 @@
         if(not -d $Path) {
             exitStatus("Access_Error", "can't access directory \'$Path\'");
         }
+        $Path = get_abs_path($Path);
         $Path = path_format($Path, $OSgroup);
         push_U($SystemPaths{"include"}, $Path);
     }
@@ -1944,6 +1964,7 @@
         if(not -d $Path) {
             exitStatus("Access_Error", "can't access directory \'$Path\'");
         }
+        $Path = get_abs_path($Path);
         $Path = path_format($Path, $OSgroup);
         push_U($SystemPaths{"lib"}, $Path);
     }
@@ -1952,6 +1973,7 @@
         if(not -d $Path) {
             exitStatus("Access_Error", "can't access directory \'$Path\'");
         }
+        $Path = get_abs_path($Path);
         $Path = path_format($Path, $OSgroup);
         push_U($SystemPaths{"bin"}, $Path);
         $TargetTools{$Path}=1;
@@ -1965,6 +1987,7 @@
         if(not -d $Path) {
             exitStatus("Access_Error", "can't access directory \'$Path\'");
         }
+        $Path = get_abs_path($Path);
         $Path = path_format($Path, $OSgroup);
         push(@{$Descriptor{$LibVersion}{"IncludePaths"}}, $Path);
     }
@@ -1974,24 +1997,30 @@
         if(not -d $Path) {
             exitStatus("Access_Error", "can't access directory \'$Path\'");
         }
+        $Path = get_abs_path($Path);
         $Path = path_format($Path, $OSgroup);
         push(@{$Descriptor{$LibVersion}{"AddIncludePaths"}}, $Path);
     }
     foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
-    {
-        # skip some auto-generated include paths
+    { # skip some auto-generated include paths
+        if(not is_abs($Path))
+        {
+            if(my $P = abs_path($Path)) {
+                $Path = $P;
+            }
+        }
         $Skip_Include_Paths{$LibVersion}{path_format($Path)} = 1;
     }
     foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
-    {
-        # skip direct including of some headers
+    { # skip direct including of some headers
         my ($CPath, $Type) = classifyPath($Path);
         $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
     }
     $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
     foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"}))
     {
-        if(index($Option, "-Wl")==-1) {
+        if($Option!~/\A\-(Wl|l|L)/)
+        { # skip linker options
             $CompilerOptions{$LibVersion} .= " ".$Option;
         }
     }
@@ -2193,7 +2222,7 @@
     {
         my $Value = $Constants{$Version}{$Constant}{"Value"};
         if(defined $EnumConstants{$Version}{$Value}) {
-            $Constants{$Version}{$Constant}{"Value"} = $EnumConstants{$Version}{$Constant}{"Value"};
+            $Constants{$Version}{$Constant}{"Value"} = $EnumConstants{$Version}{$Value}{"Value"};
         }
     }
 }
@@ -2745,6 +2774,12 @@
             { # anon typedef to anon type: ._N
                 return ();
             }
+            
+            if($LibInfo{$Version}{"info"}{$TypeDeclId}=~/ artificial /i)
+            { # artificial typedef of "struct X" to "X"
+                $TypeAttr{"Artificial"} = 1;
+            }
+            
             if(my $NS = getNameSpace($TypeDeclId))
             {
                 my $TypeName = $TypeAttr{"Name"};
@@ -2779,7 +2814,7 @@
                     }
                 }
             }
-            if($TypeAttr{"Name"} ne $BTAttr{"Name"}
+            if($TypeAttr{"Name"} ne $BTAttr{"Name"} and not $TypeAttr{"Artificial"}
             and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/)
             {
                 if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}})
@@ -2795,11 +2830,6 @@
                 }
             }
             ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId);
-            
-            if($LibInfo{$Version}{"info"}{$TypeDeclId}=~/ artificial /i)
-            { # artificial typedef of "struct X" to "X"
-                $TypeAttr{"Artificial"} = 1;
-            }
         }
         if(not $TypeAttr{"Size"})
         {
@@ -3703,10 +3733,18 @@
             foreach my $Pos (keys(%{$TypeAttr{"Memb"}}))
             {
                 my $MName = $TypeAttr{"Memb"}{$Pos}{"name"};
+                my $MVal = $TypeAttr{"Memb"}{$Pos}{"value"};
                 $EnumConstants{$Version}{$MName} = {
-                    "Value"=>$TypeAttr{"Memb"}{$Pos}{"value"},
+                    "Value"=>$MVal,
                     "Header"=>$TypeAttr{"Header"}
                 };
+                if(isAnon($TypeAttr{"Name"}))
+                {
+                    %{$Constants{$Version}{$MName}} = (
+                        "Value" => $MVal,
+                        "Header" => $TypeAttr{"Header"}
+                    );
+                }
             }
         }
     }
@@ -4456,22 +4494,14 @@
         {
             if(defined $LibInfo{$Version}{"info_type"}{$1}
             and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr")
-            { # char const* data = "str"
-              # NOTE: disabled
-                if(my $NopExpr = $LibInfo{$Version}{"info"}{$1})
+            {
+                if(my $Nop = getTreeAttr_Op($1))
                 {
-                    if($NopExpr=~/op 0[ ]*:[ ]*@(\d+) /)
+                    if(defined $LibInfo{$Version}{"info_type"}{$Nop}
+                    and $LibInfo{$Version}{"info_type"}{$Nop} eq "addr_expr")
                     {
-                        if(defined $LibInfo{$Version}{"info_type"}{$1}
-                        and $LibInfo{$Version}{"info_type"}{$1} eq "addr_expr")
-                        {
-                            if(my $AddrExpr = $LibInfo{$Version}{"info"}{$1})
-                            {
-                                if($AddrExpr=~/op 0[ ]*:[ ]*@(\d+) /)
-                                {
-                                    return getInitVal($1, $TypeId);
-                                }
-                            }
+                        if(my $Addr = getTreeAttr_Op($1)) {
+                            return getInitVal($Addr, $TypeId);
                         }
                     }
                 }
@@ -4725,18 +4755,6 @@
             return;
         }
     }
-    if(not $CheckHeadersOnly)
-    {
-        if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
-        and not $SymbolInfo{$Version}{$InfoId}{"Class"}
-        and link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps"))
-        { # functions (C++): not mangled in library, but are mangled in TU dump
-            if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
-            or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) {
-                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
-            }
-        }
-    }
     if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
     { # extern "C"
         $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
@@ -4772,6 +4790,34 @@
             }
         }
     }
+    if(not $CheckHeadersOnly
+    and $SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
+    and not $SymbolInfo{$Version}{$InfoId}{"Class"})
+    {
+        my $Incorrect = 0;
+        
+        if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
+        {
+            if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")==0
+            and not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
+            { # mangled in the TU dump, but not mangled in the library
+                $Incorrect = 1;
+            }
+        }
+        else
+        {
+            if($SymbolInfo{$Version}{$InfoId}{"Lang"} ne "C")
+            { # all C++ functions are not mangled in the TU dump
+                $Incorrect = 1;
+            }
+        }
+        if($Incorrect)
+        {
+            if(link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps")) {
+                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
+            }
+        }
+    }
     if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
     { # can't detect symbol name
         delete($SymbolInfo{$Version}{$InfoId});
@@ -5153,6 +5199,10 @@
         { # default arguments
             if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId})
             {
+                if($PurpType eq "nop_expr")
+                { # func ( const char* arg = (const char*)(void*)0 )
+                    $PurpId = getTreeAttr_Op($PurpId);
+                }
                 my $Val = getInitVal($PurpId, $ParamTypeId);
                 if(defined $Val) {
                     $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = $Val;
@@ -5286,6 +5336,17 @@
     return "";
 }
 
+sub getTreeAttr_Op($)
+{
+    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
+    {
+        if($Info=~/op 0[ ]*:[ ]*@(\d+) /) {
+            return $1;
+        }
+    }
+    return "";
+}
+
 sub getTreeAttr_Valu($)
 {
     if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
@@ -5603,6 +5664,19 @@
     {
         detect_header_includes($Header_Path, $LibVersion);
         
+        if(defined $Tolerance and $Tolerance=~/3/)
+        { # 3 - skip headers that include non-Linux headers
+            if($OSgroup ne "windows")
+            {
+                foreach my $Inc (keys(%{$Header_Includes{$LibVersion}{$Header_Path}}))
+                {
+                    if(specificHeader($Inc, "windows")) {
+                        return "";
+                    }
+                }
+            }
+        }
+        
         if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
         { # redirect
             if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"}
@@ -5625,8 +5699,9 @@
         
         if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
         or $Header!~/\.(\w+)\Z/)
-        { # hpp, hh
+        { # hpp, hh, etc.
             setLanguage($LibVersion, "C++");
+            $CPP_HEADERS = 1;
         }
         
         if($CheckHeadersOnly
@@ -5640,7 +5715,7 @@
     return "";
 }
 
-sub register_directory($$$)
+sub registerDir($$$)
 {
     my ($Dir, $WithDeps, $LibVersion) = @_;
     $Dir=~s/[\/\\]+\Z//g;
@@ -5693,7 +5768,7 @@
     { # search for "lib/include/" directory
         my $LibDir = $Dir;
         if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
-            register_directory($LibDir, $WithDeps, $LibVersion);
+            registerDir($LibDir, $WithDeps, $LibVersion);
         }
     }
 }
@@ -5800,12 +5875,20 @@
 sub sortHeaders($$)
 {
     my ($H1, $H2) = @_;
+    
     $H1=~s/\.[a-z]+\Z//ig;
     $H2=~s/\.[a-z]+\Z//ig;
-    my ($HDir1, $Hname1) = separate_path($H1);
-    my ($HDir2, $Hname2) = separate_path($H2);
+    
+    my $Hname1 = get_filename($H1);
+    my $Hname2 = get_filename($H2);
+    my $HDir1 = get_dirname($H1);
+    my $HDir2 = get_dirname($H2);
     my $Dirname1 = get_filename($HDir1);
     my $Dirname2 = get_filename($HDir2);
+    
+    $HDir1=~s/\A.*[\/\\]+([^\/\\]+[\/\\]+[^\/\\]+)\Z/$1/;
+    $HDir2=~s/\A.*[\/\\]+([^\/\\]+[\/\\]+[^\/\\]+)\Z/$1/;
+    
     if($_[0] eq $_[1]
     or $H1 eq $H2) {
         return 0;
@@ -5846,19 +5929,22 @@
     { # include/alsa/asoundlib.h
         return 1;
     }
-    elsif(checkRelevance($H1)
-    and not checkRelevance($H2))
-    { # libebook/e-book.h
-        return -1;
-    }
-    elsif(checkRelevance($H2)
-    and not checkRelevance($H1))
-    { # libebook/e-book.h
-        return 1;
-    }
     else
     {
-        return (lc($H1) cmp lc($H2));
+        my $R1 = checkRelevance($H1);
+        my $R2 = checkRelevance($H2);
+        if($R1 and not $R2)
+        { # libebook/e-book.h
+            return -1;
+        }
+        elsif($R2 and not $R1)
+        { # libebook/e-book.h
+            return 1;
+        }
+        else
+        {
+            return (lc($H1) cmp lc($H2));
+        }
     }
 }
 
@@ -5894,7 +5980,7 @@
         elsif(-d $Path)
         {
             $Path = get_abs_path($Path);
-            register_directory($Path, 0, $LibVersion);
+            registerDir($Path, 0, $LibVersion);
             if(grep {$IPath eq $_} @{$Descriptor{$LibVersion}{"AddIncludePaths"}}) {
                 push(@{$Add_Include_Paths{$LibVersion}}, $Path);
             }
@@ -5914,7 +6000,7 @@
         $Path = get_abs_path($Path);
         $Path = path_format($Path, $OSgroup);
         if(-d $Path) {
-            register_directory($Path, 1, $LibVersion);
+            registerDir($Path, 1, $LibVersion);
         }
         elsif(-f $Path)
         {
@@ -5922,12 +6008,12 @@
             if(not grep { $Dir eq $_ } (@{$SystemPaths{"include"}})
             and not $LocalIncludes{$Dir})
             {
-                register_directory($Dir, 1, $LibVersion);
+                registerDir($Dir, 1, $LibVersion);
                 if(my $OutDir = get_dirname($Dir))
                 { # registering the outer directory
                     if(not grep { $OutDir eq $_ } (@{$SystemPaths{"include"}})
                     and not $LocalIncludes{$OutDir}) {
-                        register_directory($OutDir, 0, $LibVersion);
+                        registerDir($OutDir, 0, $LibVersion);
                     }
                 }
             }
@@ -5972,6 +6058,18 @@
             exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
         }
     }
+    
+    if(defined $Tolerance and $Tolerance=~/4/)
+    { # 4 - skip headers included by others
+        foreach my $Path (keys(%{$Registered_Headers{$LibVersion}}))
+        {
+            if(defined $Header_Includes_R{$LibVersion}{$Path})
+            {
+                delete($Registered_Headers{$LibVersion}{$Path});
+            }
+        }
+    }
+    
     if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
     { # preparing preamble headers
         foreach my $Header (split(/\s*\n\s*/, $HList))
@@ -6023,7 +6121,7 @@
     
     foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
     { # ordering headers according to descriptor
-        my $PairName=$Include_Order{$LibVersion}{$HeaderName};
+        my $PairName = $Include_Order{$LibVersion}{$HeaderName};
         my ($Pos, $PairPos) = (-1, -1);
         my ($Path, $PairPath) = ();
         my @Paths = keys(%{$Registered_Headers{$LibVersion}});
@@ -6120,6 +6218,14 @@
         foreach my $Include (keys(%{$Inc}))
         { # detect includes
             $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
+            
+            if(defined $Tolerance and $Tolerance=~/4/)
+            {
+                if(my $HPath = identifyHeader($Include, $LibVersion))
+                {
+                    $Header_Includes_R{$LibVersion}{$HPath}{$Path} = 1;
+                }
+            }
         }
     }
 }
@@ -6328,21 +6434,28 @@
 
 sub checkRelevance($)
 {
-    my ($Path) = @_;
+    my $Path = $_[0];
     return 0 if(not $Path);
+    
     if($SystemRoot) {
         $Path = cut_path_prefix($Path, $SystemRoot);
     }
-    my ($Dir, $Name) = separate_path($Path);
+    
+    my $Name = lc(get_filename($Path));
+    my $Dir = lc(get_dirname($Path));
+    
     $Name=~s/\.\w+\Z//g; # remove extension (.h)
-    my @Tokens = split(/[_\d\W]+/, $Name);
-    foreach (@Tokens)
+    
+    foreach my $Token (split(/[_\d\W]+/, $Name))
     {
-        next if(not $_);
-        if($Dir=~/(\A|lib|[_\d\W])\Q$_\E([_\d\W]|lib|\Z)/i
-        or length($_)>=4 and $Dir=~/\Q$_\E/i)
+        my $Len = length($Token);
+        next if($Len<=1);
+        if($Dir=~/(\A|lib|[_\d\W])\Q$Token\E([_\d\W]|lib|\Z)/)
+        { # include/evolution-data-server-1.4/libebook/e-book.h
+            return 1;
+        }
+        if($Len>=4 and index($Dir, $Token)!=-1)
         { # include/gupnp-1.0/libgupnp/gupnp-context.h
-          # include/evolution-data-server-1.4/libebook/e-book.h
             return 1;
         }
     }
@@ -6668,7 +6781,15 @@
             {
                 if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
                 { # short unsigned int (may include spaces)
-                    return $1;
+                    my $Str = $1;
+                    if($CppMode{$Version}
+                    and $Str=~/\Ac99_(.+)\Z/)
+                    {
+                        if($CppKeywords_A{$1}) {
+                            $Str=$1;
+                        }
+                    }
+                    return $Str;
                 }
             }
         }
@@ -6930,24 +7051,24 @@
     { # non-public global data
         return get_SignatureNoInfo($Symbol, $LibVersion);
     }
-    my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
+    my ($Signature, @Param_Types_FromUnmangledName) = ();
     my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
     if($Symbol=~/\A(_Z|\?)/)
     {
         if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) {
-            $Func_Signature = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".(($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})?"~":"").$ShortName;
+            $Signature = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".(($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})?"~":"").$ShortName;
         }
         elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) {
-            $Func_Signature = $NameSpace."::".$ShortName;
+            $Signature = $NameSpace."::".$ShortName;
         }
         else {
-            $Func_Signature = $ShortName;
+            $Signature = $ShortName;
         }
         my ($Short, $Params) = split_Signature($tr_name{$MnglName});
         @Param_Types_FromUnmangledName = separate_Params($Params, 0, 1);
     }
     else {
-        $Func_Signature = $MnglName;
+        $Signature = $MnglName;
     }
     my @ParamArray = ();
     foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
@@ -6961,8 +7082,9 @@
         }
         foreach my $Typedef (keys(%ChangedTypedef))
         {
-            my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
-            $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g;
+            if(my $Base = $Typedef_BaseName{$LibVersion}{$Typedef}) {
+                $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g;
+            }
         }
         if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) {
             push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
@@ -6973,37 +7095,37 @@
     }
     if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}
     or $GlobalDataObject{$LibVersion}{$Symbol}) {
-        $Func_Signature .= " [data]";
+        $Signature .= " [data]";
     }
     else
     {
         if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
         { # add [in-charge]
-            $Func_Signature .= " ".$ChargeLevel;
+            $Signature .= " ".$ChargeLevel;
         }
-        $Func_Signature .= " (".join(", ", @ParamArray).")";
+        $Signature .= " (".join(", ", @ParamArray).")";
         if($CompleteSignature{$LibVersion}{$Symbol}{"Const"}
         or $Symbol=~/\A_ZN(V|)K/) {
-            $Func_Signature .= " const";
+            $Signature .= " const";
         }
         if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"}
         or $Symbol=~/\A_ZN(K|)V/) {
-            $Func_Signature .= " volatile";
+            $Signature .= " volatile";
         }
         if($CompleteSignature{$LibVersion}{$Symbol}{"Static"}
         and $Symbol=~/\A(_Z|\?)/)
         { # for static methods
-            $Func_Signature .= " [static]";
+            $Signature .= " [static]";
         }
     }
     if(defined $ShowRetVal
     and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) {
-        $Func_Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"};
+        $Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"};
     }
     if($SymbolVersion) {
-        $Func_Signature .= $VersionSpec.$SymbolVersion;
+        $Signature .= $VersionSpec.$SymbolVersion;
     }
-    return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Func_Signature);
+    return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Signature);
 }
 
 sub create_member_decl($$)
@@ -7600,13 +7722,178 @@
     close(CTAGS);
 }
 
+sub preChange($$)
+{
+    my ($HeaderPath, $IncStr) = @_;
+    
+    my $PreprocessCmd = getCompileCmd($HeaderPath, "-E", $IncStr);
+    my $Content = undef;
+    
+    if($OStarget eq "windows"
+    and get_dumpmachine($GCC_PATH)=~/mingw/i
+    and $MinGWMode{$Version}!=-1)
+    { # modify headers to compile by MinGW
+        if(not $Content)
+        { # preprocessing
+            $Content = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
+        }
+        if($Content=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
+        { # __asm { ... }
+            $MinGWMode{$Version}=1;
+        }
+        if($Content=~s/\s+(\/ \/.*?)\n/\n/g)
+        { # comments after preprocessing
+            $MinGWMode{$Version}=1;
+        }
+        if($Content=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
+        { # 0xffui8
+            $MinGWMode{$Version}=1;
+        }
+        
+        if($MinGWMode{$Version}) {
+            printMsg("INFO", "Using MinGW compatibility mode");
+        }
+    }
+    
+    if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
+    and $CppMode{$Version}!=-1 and not $CppCompat and not $CPP_HEADERS)
+    { # rename C++ keywords in C code
+      # disable this code by -cpp-compatible option
+        if(not $Content)
+        { # preprocessing
+            $Content = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
+        }
+        my $RegExp_C = join("|", keys(%CppKeywords_C));
+        my $RegExp_F = join("|", keys(%CppKeywords_F));
+        my $RegExp_O = join("|", keys(%CppKeywords_O));
+        
+        my $Detected = undef;
+        
+        while($Content=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
+        { # MATCH:
+          # int foo(int new, int class, int (*new)(int));
+          # unsigned private: 8;
+          # DO NOT MATCH:
+          # #pragma GCC visibility push(default)
+            $CppMode{$Version} = 1;
+            $Detected = "$1$2$3$4" if(not defined $Detected);
+        }
+        if($Content=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
+        { # MATCH:
+          # int delete(...);
+          # int explicit(...);
+          # DO NOT MATCH:
+          # void operator delete(...)
+            $CppMode{$Version} = 1;
+            $Detected = "$1$2$3" if(not defined $Detected);
+        }
+        if($Content=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
+        { # MATCH:
+          # int bool;
+          # DO NOT MATCH:
+          # bool X;
+          # return *this;
+          # throw;
+            $CppMode{$Version} = 1;
+            $Detected = "$1$2$3" if(not defined $Detected);
+        }
+        if($Content=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
+        { # MATCH:
+          # int operator(...);
+          # DO NOT MATCH:
+          # int operator()(...);
+            $CppMode{$Version} = 1;
+            $Detected = "$1$2$3" if(not defined $Detected);
+        }
+        if($Content=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
+        { # MATCH:
+          # int foo(int operator);
+          # int foo(int operator, int other);
+          # DO NOT MATCH:
+          # int operator,(...);
+            $CppMode{$Version} = 1;
+            $Detected = "$1$2$3" if(not defined $Detected);
+        }
+        if($Content=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
+        { # MATCH:
+          # int foo(gboolean *bool);
+          # DO NOT MATCH:
+          # void setTabEnabled(int index, bool);
+            $CppMode{$Version} = 1;
+            $Detected = "$1$2$3" if(not defined $Detected);
+        }
+        if($Content=~s/(\w)(\s*[^\w\(\,\s]\s*|\s+)(this|throw)(\s*[\,\)])/$1$2c99_$3$4/g)
+        { # MATCH:
+          # int foo(int* this);
+          # int bar(int this);
+          # int baz(int throw);
+          # DO NOT MATCH:
+          # foo(X, this);
+            $CppMode{$Version} = 1;
+            $Detected = "$1$2$3$4" if(not defined $Detected);
+        }
+        if($Content=~s/(struct |extern )(template) /$1c99_$2 /g)
+        { # MATCH:
+          # struct template {...};
+          # extern template foo(...);
+            $CppMode{$Version} = 1;
+            $Detected = "$1$2" if(not defined $Detected);
+        }
+        
+        if($CppMode{$Version} == 1)
+        {
+            if($Debug)
+            {
+                $Detected=~s/\A\s+//g;
+                printMsg("INFO", "Detected code: \"$Detected\"");
+            }
+        }
+        
+        # remove typedef enum NAME NAME;
+        my @FwdTypedefs = $Content=~/typedef\s+enum\s+(\w+)\s+(\w+);/g;
+        my $N = 0;
+        while($N<=$#FwdTypedefs-1)
+        {
+            my $S = $FwdTypedefs[$N];
+            if($S eq $FwdTypedefs[$N+1])
+            {
+                $Content=~s/typedef\s+enum\s+\Q$S\E\s+\Q$S\E;//g;
+                $CppMode{$Version}=1;
+            }
+            $N+=2;
+        }
+        
+        if($CppMode{$Version}==1) {
+            printMsg("INFO", "Using C++ compatibility mode");
+        }
+    }
+        
+    if($CppMode{$Version}==1
+    or $MinGWMode{$Version}==1)
+    {
+        my $IPath = $TMP_DIR."/dump$Version.i";
+        writeFile($IPath, $Content);
+        return $IPath;
+    }
+    
+    return undef;
+}
+
 sub getDump()
 {
     if(not $GCC_PATH) {
         exitStatus("Error", "internal error - GCC path is not set");
     }
+    
+    my @Headers = keys(%{$Registered_Headers{$Version}});
+    @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
+    
+    my $IncludeString = getIncString(getIncPaths(@{$Include_Preamble{$Version}}, @Headers), "GCC");
+    
     my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h";
-    my $MHeaderPath = $TmpHeaderPath;
+    my $HeaderPath = $TmpHeaderPath;
+    
+    # write tmp-header
     open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
     if(my $AddDefines = $Descriptor{$Version}{"Defines"})
     {
@@ -7617,8 +7904,6 @@
     foreach my $HPath (@{$Include_Preamble{$Version}}) {
         print TMP_HEADER "  #include \"".path_format($HPath, "unix")."\"\n";
     }
-    my @Headers = keys(%{$Registered_Headers{$Version}});
-    @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
     foreach my $HPath (@Headers)
     {
         if(not grep {$HPath eq $_} (@{$Include_Preamble{$Version}})) {
@@ -7626,7 +7911,6 @@
         }
     }
     close(TMP_HEADER);
-    my $IncludeString = getIncString(getIncPaths(@{$Include_Preamble{$Version}}, @Headers), "GCC");
     
     if($ExtraInfo)
     { # extra information for other tools
@@ -7678,149 +7962,10 @@
         checkCTags($Pre);
     }
     
-    my $MContent = "";
-    my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
-    if($OStarget eq "windows"
-    and get_dumpmachine($GCC_PATH)=~/mingw/i
-    and $MinGWMode{$Version}!=-1)
-    { # modify headers to compile by MinGW
-        if(not $MContent)
-        { # preprocessing
-            $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
-        }
-        if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
-        { # __asm { ... }
-            $MinGWMode{$Version}=1;
-        }
-        if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
-        { # comments after preprocessing
-            $MinGWMode{$Version}=1;
-        }
-        if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
-        { # 0xffui8
-            $MinGWMode{$Version}=1;
-        }
-        if($MinGWMode{$Version})
-        {
-            printMsg("INFO", "Using MinGW compatibility mode");
-            $MHeaderPath = $TMP_DIR."/dump$Version.i";
-        }
+    if(my $PrePath = preChange($TmpHeaderPath, $IncludeString))
+    { # try to correct the preprocessor output
+        $HeaderPath = $PrePath;
     }
-    if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
-    and $CppMode{$Version}!=-1 and not $CppCompat)
-    { # rename C++ keywords in C code
-      # disable this code by -cpp-compatible option
-        if(not $MContent)
-        { # preprocessing
-            $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
-        }
-        my $RegExp_C = join("|", keys(%CppKeywords_C));
-        my $RegExp_F = join("|", keys(%CppKeywords_F));
-        my $RegExp_O = join("|", keys(%CppKeywords_O));
-        
-        my $Detected = undef;
-        
-        while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
-        { # MATCH:
-          # int foo(int new, int class, int (*new)(int));
-          # unsigned private: 8;
-          # DO NOT MATCH:
-          # #pragma GCC visibility push(default)
-            $CppMode{$Version} = 1;
-            $Detected = "$1$2$3$4" if(not defined $Detected);
-        }
-        if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
-        { # MATCH:
-          # int delete(...);
-          # int explicit(...);
-          # DO NOT MATCH:
-          # void operator delete(...)
-            $CppMode{$Version} = 1;
-            $Detected = "$1$2$3" if(not defined $Detected);
-        }
-        if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
-        { # MATCH:
-          # int bool;
-          # DO NOT MATCH:
-          # bool X;
-          # return *this;
-          # throw;
-            $CppMode{$Version} = 1;
-            $Detected = "$1$2$3" if(not defined $Detected);
-        }
-        if($MContent=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
-        { # MATCH:
-          # int operator(...);
-          # DO NOT MATCH:
-          # int operator()(...);
-            $CppMode{$Version} = 1;
-            $Detected = "$1$2$3" if(not defined $Detected);
-        }
-        if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
-        { # MATCH:
-          # int foo(int operator);
-          # int foo(int operator, int other);
-          # DO NOT MATCH:
-          # int operator,(...);
-            $CppMode{$Version} = 1;
-            $Detected = "$1$2$3" if(not defined $Detected);
-        }
-        if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
-        { # MATCH:
-          # int foo(gboolean *bool);
-          # DO NOT MATCH:
-          # void setTabEnabled(int index, bool);
-            $CppMode{$Version} = 1;
-            $Detected = "$1$2$3" if(not defined $Detected);
-        }
-        if($MContent=~s/(\w)(\s*[^\w\(\,\s]\s*|\s+)(this|throw)(\s*[\,\)])/$1$2c99_$3$4/g)
-        { # MATCH:
-          # int foo(int* this);
-          # int bar(int this);
-          # int baz(int throw);
-          # DO NOT MATCH:
-          # foo(X, this);
-            $CppMode{$Version} = 1;
-            $Detected = "$1$2$3$4" if(not defined $Detected);
-        }
-        
-        if($CppMode{$Version} == 1)
-        {
-            if($Debug)
-            {
-                $Detected=~s/\A\s+//g;
-                printMsg("INFO", "Detected code: \"$Detected\"");
-            }
-        }
-        
-        # remove typedef enum NAME NAME;
-        my @FwdTypedefs = $MContent=~/typedef\s+enum\s+(\w+)\s+(\w+);/g;
-        my $N = 0;
-        while($N<=$#FwdTypedefs-1)
-        {
-            my $S = $FwdTypedefs[$N];
-            if($S eq $FwdTypedefs[$N+1])
-            {
-                $MContent=~s/typedef\s+enum\s+\Q$S\E\s+\Q$S\E;//g;
-                $CppMode{$Version}=1;
-            }
-            $N+=2;
-        }
-        
-        if($CppMode{$Version}==1)
-        { # try to change C++ "keyword" to "c99_keyword"
-            printMsg("INFO", "Using C++ compatibility mode");
-            $MHeaderPath = $TMP_DIR."/dump$Version.i";
-        }
-    }
-    if($CppMode{$Version}==1
-    or $MinGWMode{$Version}==1)
-    { # compile the corrected preprocessor output
-        writeFile($MHeaderPath, $MContent);
-    }
-    
-    # clean memory
-    undef $MContent;
     
     if($COMMON_LANGUAGE{$Version} eq "C++")
     { # add classes and namespaces to the dump
@@ -7829,7 +7974,7 @@
         or $MinGWMode{$Version}==1) {
             $CHdump .= " -fpreprocessed";
         }
-        my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
+        my $ClassHierarchyCmd = getCompileCmd($HeaderPath, $CHdump, $IncludeString);
         chdir($TMP_DIR);
         system($ClassHierarchyCmd." >null 2>&1");
         chdir($ORIG_DIR);
@@ -7876,7 +8021,7 @@
         # add namespaces and classes
         if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
         { # GCC on all supported platforms does not include namespaces to the dump by default
-            appendFile($MHeaderPath, "\n  // add namespaces\n".$NS_Add);
+            appendFile($HeaderPath, "\n  // add namespaces\n".$NS_Add);
         }
         # some GCC versions don't include class methods to the TU dump by default
         my ($AddClass, $ClassNum) = ("", 0);
@@ -7914,7 +8059,7 @@
             $AddClass .= "  $CName* tmp_add_class_".($ClassNum++).";\n";
         }
         if($AddClass) {
-            appendFile($MHeaderPath, "\n  // add classes\n".$AddClass);
+            appendFile($HeaderPath, "\n  // add classes\n".$AddClass);
         }
     }
     writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
@@ -7924,7 +8069,7 @@
     or $MinGWMode{$Version}==1) {
         $TUdump .= " -fpreprocessed";
     }
-    my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
+    my $SyntaxTreeCmd = getCompileCmd($HeaderPath, $TUdump, $IncludeString);
     writeLog($Version, "The GCC parameters:\n  $SyntaxTreeCmd\n\n");
     chdir($TMP_DIR);
     system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1");
@@ -7998,7 +8143,7 @@
     }
     chdir($ORIG_DIR);
     unlink($TmpHeaderPath);
-    unlink($MHeaderPath);
+    unlink($HeaderPath);
     
     if(my @TUs = cmd_find($TMP_DIR,"f","*.tu",1)) {
         return $TUs[0];
@@ -8127,11 +8272,14 @@
         }
         my @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
         if($Name)
-        { # FIXME: how to search file names in MS shell?
-            if(not $UseRegex) {
+        {
+            if(not $UseRegex)
+            { # FIXME: how to search file names in MS shell?
+              # wildcard to regexp
                 $Name=~s/\*/.*/g;
+                $Name='\A'.$Name.'\Z';
             }
-            @Files = grep { /\A$Name\Z/i } @Files;
+            @Files = grep { /$Name/i } @Files;
         }
         my @AbsPaths = ();
         foreach my $File (@Files)
@@ -8174,13 +8322,13 @@
             $Cmd .= " -name \"$Name\"";
         }
         my $Res = `$Cmd 2>\"$TMP_DIR/null\"`;
-        if($?) {
+        if($? and $!) {
             printMsg("ERROR", "problem with \'find\' utility ($?): $!");
         }
         my @Files = split(/\n/, $Res);
         if($Name and $UseRegex)
         { # regex
-            @Files = grep { /\A$Name\Z/ } @Files;
+            @Files = grep { /$Name/ } @Files;
         }
         return @Files;
     }
@@ -8876,6 +9024,12 @@
     if(my $Header = $SInfo->{"Header"}) {
         $Target = (is_target_header($Header, 1) or is_target_header($Header, 2));
     }
+    if($ExtendedCheck)
+    {
+        if(index($Symbol,"external_func_")==0) {
+            $Target = 1;
+        }
+    }
     if($CheckHeadersOnly)
     {
         if($Target)
@@ -9125,11 +9279,13 @@
 sub addExtension($)
 {
     my $LibVersion = $_[0];
-    foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
+    foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
     {
         if(selectType($Tid, $LibVersion))
         {
-            my $Symbol = "external_func_".$TypeInfo{$LibVersion}{$Tid}{"Name"};
+            my $TName = $TypeInfo{$LibVersion}{$Tid}{"Name"};
+            $TName=~s/\A(struct|union|class|enum) //;
+            my $Symbol = "external_func_".$TName;
             
             %{$CompleteSignature{$LibVersion}{$Symbol}} = (
                 "Header" => "extended.h",
@@ -9138,14 +9294,14 @@
                 "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } }
             );
             
-            $ExtendedSymbols{$Symbol}=1;
-            $CheckedSymbols{"Binary"}{$Symbol}=1;
-            $CheckedSymbols{"Source"}{$Symbol}=1;
+            $ExtendedSymbols{$Symbol} = 1;
+            $CheckedSymbols{"Binary"}{$Symbol} = 1;
+            $CheckedSymbols{"Source"}{$Symbol} = 1;
         }
     }
-    $ExtendedSymbols{"external_func_0"}=1;
-    $CheckedSymbols{"Binary"}{"external_func_0"}=1;
-    $CheckedSymbols{"Source"}{"external_func_0"}=1;
+    $ExtendedSymbols{"external_func_0"} = 1;
+    $CheckedSymbols{"Binary"}{"external_func_0"} = 1;
+    $CheckedSymbols{"Source"}{"external_func_0"} = 1;
 }
 
 sub findMethod($$$)
@@ -10358,9 +10514,9 @@
     return $CompatRules{$Level}{$Kind}{"Severity"};
 }
 
-sub isRecurType($$)
+sub isRecurType($$$)
 {
-    foreach (@RecurTypes)
+    foreach (@{$_[2]})
     {
         if( $_->{"T1"} eq $_[0]
         and $_->{"T2"} eq $_[1] )
@@ -10371,13 +10527,13 @@
     return 0;
 }
 
-sub pushType($$)
+sub pushType($$$)
 {
-    my %TypeIDs=(
-        "T1" => $_[0], #Tid1
-        "T2" => $_[1] #Tid2
+    my %IDs = (
+        "T1" => $_[0],
+        "T2" => $_[1]
     );
-    push(@RecurTypes, \%TypeIDs);
+    push(@{$_[2]}, \%IDs);
 }
 
 sub isRenamed($$$$$)
@@ -10498,7 +10654,7 @@
     { # including a case when "class Class { ... };" changed to "class Class;"
         return ();
     }
-    if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}))
+    if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}, \@RecurTypes))
     { # skip recursive declarations
         return ();
     }
@@ -10540,11 +10696,25 @@
                     "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
                     "New_Size"=>$Type2{"Size"}*$BYTE_SIZE  );
             }
-            %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
-                "Target"=>$Typedef_1{"Name"},
-                "Type_Name"=>$Typedef_1{"Name"},
-                "Old_Value"=>$Base_1{"Name"},
-                "New_Value"=>$Base_2{"Name"}  );
+            my %Base1_Pure = get_PureType($Base_1{"Tid"}, $TypeInfo{1});
+            my %Base2_Pure = get_PureType($Base_2{"Tid"}, $TypeInfo{2});
+            if(diffTypes($Base1_Pure{"Tid"}, $Base2_Pure{"Tid"}, $Level))
+            {
+                %{$SubProblems{"Typedef_BaseType_Format"}{$Typedef_1{"Name"}}}=(
+                    "Target"=>$Typedef_1{"Name"},
+                    "Type_Name"=>$Typedef_1{"Name"},
+                    "Old_Value"=>$Base_1{"Name"},
+                    "New_Value"=>$Base_2{"Name"}  );
+            }
+            else
+            {
+                %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
+                    "Target"=>$Typedef_1{"Name"},
+                    "Type_Name"=>$Typedef_1{"Name"},
+                    "Old_Value"=>$Base_1{"Name"},
+                    "New_Value"=>$Base_2{"Name"}  );
+            }
+            
         }
     }
     if(nonComparable(\%Type1_Pure, \%Type2_Pure))
@@ -10573,7 +10743,7 @@
         %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
         return %SubProblems;
     }
-    pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"});
+    pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}, \@RecurTypes);
     if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
     or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
     and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
@@ -10782,6 +10952,14 @@
         next if(not $Member_Name);
         if(my $RenamedTo = $RenamedField{$Member_Pos})
         { # renamed
+            if(defined $Constants{2}{$Member_Name})
+            {
+                if($Constants{2}{$Member_Name}{"Value"} eq $RenamedTo)
+                { # define OLD NEW
+                    next; # Safe
+                }
+            }
+            
             if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
             {
                 if(isPublic(\%Type1_Pure, $Member_Pos))
@@ -11536,7 +11714,7 @@
             $Diff=~s/\n\@\@/\n \n\@\@/g;
             unlink("$TMP_DIR/impl1");
             unlink("$TMP_DIR/impl2");
-            %{$ImplProblems{$Interface}}=(
+            %{$CompatProblems_Impl{$Interface}}=(
                 "Diff" => get_CodeView($Diff)  );
         }
     }
@@ -12046,7 +12224,7 @@
     return "Function";
 }
 
-sub mergeSignatures($)
+sub mergeSymbols($)
 {
     my $Level = $_[0];
     my %SubProblems = ();
@@ -13252,11 +13430,30 @@
     return $TName_Tid{$Version}{formatName($TypeName, "T")};
 }
 
-sub checkFormatChange($$$)
+sub diffTypes($$$)
+{
+    if(defined $Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]}) {
+        return $Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]};
+    }
+    if(isRecurType($_[0], $_[1], \@RecurTypes_Diff))
+    { # skip recursive declarations
+        return 0;
+    }
+    
+    pushType($_[0], $_[1], \@RecurTypes_Diff);
+    my $Diff = diffTypes_I(@_);
+    pop(@RecurTypes_Diff);
+    
+    return ($Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]} = $Diff);
+}
+
+sub diffTypes_I($$$)
 {
     my ($Type1_Id, $Type2_Id, $Level) = @_;
+    
     my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
     my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
+    
     if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
     { # equal types
         return 0;
@@ -13270,6 +13467,7 @@
     { # compared in detectTypeChange()
         return 0;
     }
+    
     my %FloatType = map {$_=>1} (
         "float",
         "double",
@@ -13336,19 +13534,7 @@
             else
             {
                 foreach my $Pos (@Membs1)
-                { # compare elements by type name
-                    my $MT1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
-                    my $MT2 = $TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
-                    
-                    $MT1 = uncover_typedefs($MT1, 1);
-                    $MT2 = uncover_typedefs($MT2, 2);
-                    
-                    if($MT1 ne $MT2)
-                    { # different types
-                        if(not isAnon($MT1) and not isAnon($MT2)) {
-                            return 1;
-                        }
-                    }
+                {
                     if($Level eq "Source")
                     {
                         if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
@@ -13356,9 +13542,37 @@
                             return 1;
                         }
                     }
+                    
+                    my %MT1 = %{$TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}};
+                    my %MT2 = %{$TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}};
+                    
+                    if($MT1{"Name"} ne $MT2{"Name"}
+                    or isAnon($MT1{"Name"}) or isAnon($MT2{"Name"}))
+                    {
+                        my $PL1 = get_PLevel($MT1{"Tid"}, 1);
+                        my $PL2 = get_PLevel($MT2{"Tid"}, 2);
+                        
+                        if($PL1 ne $PL2)
+                        { # different pointer level
+                            return 1;
+                        }
+                        
+                        # compare base types
+                        my %BT1 = get_BaseType($MT1{"Tid"}, 1);
+                        my %BT2 = get_BaseType($MT2{"Tid"}, 2);
+                        
+                        if(diffTypes($BT1{"Tid"}, $BT2{"Tid"}, $Level))
+                        { # different types
+                            return 1;
+                        }
+                    }
                 }
             }
         }
+        else
+        {
+            # TODO: arrays, etc.
+        }
     }
     return 0;
 }
@@ -13406,8 +13620,8 @@
         if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
         {
             if($Level eq "Binary"
-            and $Type1_Base{"Size"} ne $Type2_Base{"Size"}
-            and $Type1_Base{"Size"} and $Type2_Base{"Size"})
+            and $Type1_Base{"Size"} and $Type2_Base{"Size"}
+            and $Type1_Base{"Size"} ne $Type2_Base{"Size"})
             {
                 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
                     "Old_Value"=>$Type1_Base{"Name"},
@@ -13418,7 +13632,7 @@
             }
             else
             {
-                if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
+                if(diffTypes($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
                 { # format change
                     %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
                         "Old_Value"=>$Type1_Base{"Name"},
@@ -13474,7 +13688,7 @@
                 }
                 else
                 {
-                    if(checkFormatChange($Type1_Id, $Type2_Id, $Level))
+                    if(diffTypes($Type1_Id, $Type2_Id, $Level))
                     { # format change
                         %{$LocalProblems{$Prefix."_Type_Format"}}=(
                             "Old_Value"=>$Type1{"Name"},
@@ -13557,14 +13771,16 @@
             $Changed = 1;
         }
     }
+    
+    my $TN1 = $TypeInfo{1}{$Tid1}{"Name"};
+    my $TN2 = $TypeInfo{2}{$Tid2}{"Name"};
+    
     if($Changed)
     { # different formats
         if($UseOldDumps)
         { # old dumps
             return 0;
         }
-        my $TN1 = $TypeInfo{1}{$Tid1}{"Name"};
-        my $TN2 = $TypeInfo{2}{$Tid2}{"Name"};
         
         my $TT1 = $TypeInfo{1}{$Tid1}{"Type"};
         my $TT2 = $TypeInfo{2}{$Tid2}{"Type"};
@@ -13611,6 +13827,23 @@
             }
         }
     }
+    else
+    {
+        # typedef struct {...} type_t
+        # typedef struct type_t {...} type_t
+        if(index($TN1, " ".$TN2)!=-1)
+        {
+            if($TN1=~/\A(struct|union|enum) \Q$TN2\E\Z/) {
+                return 0;
+            }
+        }
+        if(index($TN2, " ".$TN1)!=-1)
+        {
+            if($TN2=~/\A(struct|union|enum) \Q$TN1\E\Z/) {
+                return 0;
+            }
+        }
+    }
     return 1;
 }
 
@@ -13658,9 +13891,10 @@
     $Str=~s/</&lt;/g;
     $Str=~s/\-\>/&#45;&gt;/g; # &minus;
     $Str=~s/>/&gt;/g;
-    $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
+    $Str=~s/([^ ]) ([^ ])/$1\@SP\@$2/g;
+    $Str=~s/([^ ]) ([^ ])/$1\@SP\@$2/g;
     $Str=~s/ /&#160;/g; # &nbsp;
-    $Str=~s/\@ALONE_SP\@/ /g;
+    $Str=~s/\@SP\@/ /g;
     $Str=~s/\n/<br\/>/g;
     $Str=~s/\"/&quot;/g;
     $Str=~s/\'/&#39;/g;
@@ -13753,7 +13987,7 @@
     if(not $SCenter)
     { # global data
         $Signature = htmlSpecChars($Signature);
-        $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
+        $Signature=~s!(\[data\])!<span class='attr'>$1</span>!g;
         $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
         if($Return and $ShowReturn) {
             $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
@@ -13777,7 +14011,8 @@
         elsif($Part=~/(\w+)[\,\)]*\Z/i) {
             $ParamName = $1;
         }
-        if(not $ParamName) {
+        if(not $ParamName)
+        {
             push(@Parts, $Part_Styled);
             next;
         }
@@ -13819,8 +14054,11 @@
     }
     $Signature=~s!\[\]![&#160;]!g;
     $Signature=~s!operator=!operator&#160;=!g;
-    $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='sym_kind'>$1</span>!g;
-    return $Signature.(($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
+    $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='attr'>$1</span>!g;
+    if($SymbolVersion) {
+        $Signature .= "<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>";
+    }
+    return $Signature;
 }
 
 sub split_Signature($)
@@ -14193,7 +14431,7 @@
 {
     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) = (0,0,0,0,0,0,0,0,0,0,0);
+    $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,
@@ -14214,6 +14452,21 @@
             }
         }
     }
+    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 $Interface (sort keys(%{$CompatProblems{$Level}}))
     {
         foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
@@ -14328,30 +14581,38 @@
         $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low;
     }
     
-    if($C_Problems_Low = keys(%{$ProblemsWithConstants{$Level}}))
+    foreach my $Constant (keys(%{$CompatProblems_Constants{$Level}}))
     {
-        if(defined $CompatRules{$Level}{"Changed_Constant"})
+        foreach my $Kind (keys(%{$CompatProblems_Constants{$Level}{$Constant}}))
         {
-            if($StrictCompat) {
-                $RESULT{$Level}{"Problems"} += $C_Problems_Low;
+            my $Severity = getProblemSeverity($Level, $Kind);
+            if($Severity eq "Safe")
+            {
+                $C_Other+=1;
             }
-            else {
-                $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
+            elsif($Severity eq "Low")
+            {
+                $C_Problems_Low+=1;
             }
         }
-        else
-        {
-            printMsg("WARNING", "unknown rule \"Changed_Constant\" (\"$Level\")");
-            $C_Problems_Low = 0;
+    }
+    
+    if($C_Problems_Low)
+    {
+        if($StrictCompat) {
+            $RESULT{$Level}{"Problems"} += $C_Problems_Low;
+        }
+        else {
+            $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
         }
     }
     if($CheckImpl and $Level eq "Binary")
     {
         if($StrictCompat) {
-            $RESULT{$Level}{"Problems"} += keys(%ImplProblems);
+            $RESULT{$Level}{"Problems"} += keys(%CompatProblems_Impl);
         }
         else {
-            $RESULT{$Level}{"Warnings"} += keys(%ImplProblems);
+            $RESULT{$Level}{"Warnings"} += keys(%CompatProblems_Impl);
         }
     }
     if($RESULT{$Level}{"Problems"}
@@ -14439,7 +14700,7 @@
         if($CheckImpl and $Level eq "Binary")
         {
             $Problem_Summary .= "  <impl>\n";
-            $Problem_Summary .= "    <low>".keys(%ImplProblems)."</low>\n";
+            $Problem_Summary .= "    <low>".keys(%CompatProblems_Impl)."</low>\n";
             $Problem_Summary .= "  </impl>\n";
         }
         $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
@@ -14605,14 +14866,8 @@
         $Problem_Summary .= "<tr><td>Low</td><td".getStyle("I", "L", $I_Problems_Low).">$IL_Link</td></tr>\n";
         
         my $ChangedConstants_Link = "0";
-        if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
-        {
-            if($JoinReport) {
-                $ChangedConstants_Link = "<a href='#".$Level."_Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
-            }
-            else {
-                $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
-            }
+        if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low) {
+            $ChangedConstants_Link = "<a href='#".get_Anchor("Constant", $Level, "Low")."' style='color:Blue;'>$C_Problems_Low</a>";
         }
         $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
         $META_DATA .= "changed_constants:$C_Problems_Low;";
@@ -14621,10 +14876,10 @@
         if($CheckImpl and $Level eq "Binary")
         {
             my $ChangedImpl_Link = "0";
-            $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
+            $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%CompatProblems_Impl)."</a>" if(keys(%CompatProblems_Impl)>0);
             $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
-            $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
-            $Problem_Summary .= "<tr><th>Problems with<br/>Implementation</th><td>Low</td><td".getStyle("Imp", "L", int(keys(%ImplProblems))).">$ChangedImpl_Link</td></tr>\n";
+            $META_DATA .= "changed_implementation:".keys(%CompatProblems_Impl).";";
+            $Problem_Summary .= "<tr><th>Problems with<br/>Implementation</th><td>Low</td><td".getStyle("Imp", "L", int(keys(%CompatProblems_Impl))).">$ChangedImpl_Link</td></tr>\n";
         }
         # Safe Changes
         if($T_Other and not $CheckObjectsOnly)
@@ -14639,6 +14894,12 @@
             $Problem_Summary .= "<tr><th>Other Changes<br/>in Symbols</th><td>-</td><td".getStyle("I", "S", $I_Other).">$IS_Link</td></tr>\n";
         }
         
+        if($C_Other and not $CheckObjectsOnly)
+        {
+            my $CS_Link = "<a href='#".get_Anchor("Constant", $Level, "Safe")."' style='color:Blue;'>$C_Other</a>";
+            $Problem_Summary .= "<tr><th>Other Changes<br/>in Constants</th><td>-</td><td".getStyle("C", "S", $C_Other).">$CS_Link</td></tr>\n";
+        }
+        
         $META_DATA .= "tool_version:$TOOL_VERSION";
         $Problem_Summary .= "</table>\n";
         # $TestInfo = getLegend().$TestInfo;
@@ -14712,18 +14973,32 @@
     return $num;
 }
 
-sub get_Report_ChangedConstants($)
+sub get_Report_ChangedConstants($$)
 {
-    my $Level = $_[0];
+    my ($TargetSeverity, $Level) = @_;
     my $CHANGED_CONSTANTS = "";
+    
     my %ReportMap = ();
-    foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
-        $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
+    foreach my $Constant (keys(%{$CompatProblems_Constants{$Level}}))
+    {
+        my $Header = $Constants{1}{$Constant}{"Header"};
+        if(not $Header)
+        { # added
+            $Header = $Constants{2}{$Constant}{"Header"}
+        }
+        
+        foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$CompatProblems_Constants{$Level}{$Constant}}))
+        {
+            if(not defined $CompatRules{$Level}{$Kind}) {
+                next;
+            }
+            if($TargetSeverity ne getProblemSeverity($Level, $Kind)) {
+                next;
+            }
+            $ReportMap{$Header}{$Constant}{$Kind} = 1;
+        }
     }
-    my $Kind = "Changed_Constant";
-    if(not defined $CompatRules{$Level}{$Kind}) {
-        return "";
-    }
+    
     if($ReportFormat eq "xml")
     { # XML
         foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
@@ -14732,14 +15007,17 @@
             foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
             {
                 $CHANGED_CONSTANTS .= "    <constant name=\"$Constant\">\n";
-                my $Change = $CompatRules{$Level}{$Kind}{"Change"};
-                my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
-                my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
-                $CHANGED_CONSTANTS .= "      <problem id=\"$Kind\">\n";
-                $CHANGED_CONSTANTS .= "        <change".getXmlParams($Change, $ProblemsWithConstants{$Level}{$Constant}).">$Change</change>\n";
-                $CHANGED_CONSTANTS .= "        <effect".getXmlParams($Effect, $ProblemsWithConstants{$Level}{$Constant}).">$Effect</effect>\n";
-                $CHANGED_CONSTANTS .= "        <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Level}{$Constant}).">$Overcome</overcome>\n";
-                $CHANGED_CONSTANTS .= "      </problem>\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 .= "      <problem id=\"$Kind\">\n";
+                    $CHANGED_CONSTANTS .= "        <change".getXmlParams($Change, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Change</change>\n";
+                    $CHANGED_CONSTANTS .= "        <effect".getXmlParams($Effect, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Effect</effect>\n";
+                    $CHANGED_CONSTANTS .= "        <overcome".getXmlParams($Overcome, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Overcome</overcome>\n";
+                    $CHANGED_CONSTANTS .= "      </problem>\n";
+                }
                 $CHANGED_CONSTANTS .= "    </constant>\n";
             }
             $CHANGED_CONSTANTS .= "    </header>\n";
@@ -14752,25 +15030,35 @@
         foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
         {
             $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
-            foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
+            foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
             {
-                $Number += 1;
-                my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
-                my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
-                my $Report = "<tr><th>1</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
-                $Report = $ContentDivStart."<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>".$Report."</table><br/>$ContentDivEnd\n";
-                $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
-                $CHANGED_CONSTANTS .= insertIDs($Report);
+                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 .= "<tr><th>1</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
+                    $Number += 1;
+                }
+                if($Report)
+                {
+                    $Report = $ContentDivStart."<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>".$Report."</table><br/>$ContentDivEnd\n";
+                    $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Constant.$ContentSpanEnd."<br/>\n".$Report;
+                    $Report = insertIDs($Report);
+                }
+                $CHANGED_CONSTANTS .= $Report;
             }
             $CHANGED_CONSTANTS .= "<br/>\n";
         }
         if($CHANGED_CONSTANTS)
         {
-            my $Anchor = "<a name='Changed_Constants'></a>";
-            if($JoinReport) {
-                $Anchor = "<a name='".$Level."_Changed_Constants'></a>";
+            my $Title = "Problems with Constants, $TargetSeverity Severity";
+            if($TargetSeverity eq "Safe")
+            { # Safe Changes
+                $Title = "Other Changes in Constants";
             }
-            $CHANGED_CONSTANTS = $Anchor."<h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
+            $CHANGED_CONSTANTS = "<a name='".get_Anchor("Constant", $Level, $TargetSeverity)."'></a><h2>$Title ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
         }
     }
     return $CHANGED_CONSTANTS;
@@ -14780,7 +15068,7 @@
 {
     my $CHANGED_IMPLEMENTATION = "";
     my %ReportMap = ();
-    foreach my $Interface (sort keys(%ImplProblems))
+    foreach my $Interface (sort keys(%CompatProblems_Impl))
     {
         my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
         my $DyLib = $Symbol_Library{1}{$Interface};
@@ -14806,7 +15094,7 @@
                     if($NameSpace) {
                         $Signature=~s/\b\Q$NameSpace\E::\b//g;
                     }
-                    $CHANGED_IMPLEMENTATION .= $ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Interface</b>]</span>".$ImplProblems{$Interface}{"Diff"}."<br/><br/>".$ContentDivEnd."\n";
+                    $CHANGED_IMPLEMENTATION .= $ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Interface</b>]</span>".$CompatProblems_Impl{$Interface}{"Diff"}."<br/><br/>".$ContentDivEnd."\n";
                 }
                 $CHANGED_IMPLEMENTATION .= "<br/>\n";
             }
@@ -14819,7 +15107,7 @@
     }
     
     # clean memory
-    %ImplProblems = ();
+    %CompatProblems_Impl = ();
     
     return $CHANGED_IMPLEMENTATION;
 }
@@ -15868,7 +16156,7 @@
         }
     }
     if($ExtendedSymbols{$Symbol}) {
-        push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
+        push(@Sentence, " This is a symbol from an external library that may use the \'$TargetLibraryName\' library and change the ABI after recompiling.");
     }
     return join(" ", @Sentence);
 }
@@ -15885,8 +16173,9 @@
         my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"};
         foreach my $Typedef (keys(%ChangedTypedef))
         {
-            my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
-            $TypeName=~s/\b\Q$Typedef\E\b/$Base/g;
+            if(my $Base = $Typedef_BaseName{$LibVersion}{$Typedef}) {
+                $TypeName=~s/\b\Q$Typedef\E\b/$Base/g;
+            }
         }
         $Report .= "    <param pos=\"$Pos\">\n";
         $Report .= "      <name>".$Name."</name>\n";
@@ -16036,7 +16325,7 @@
         and $OSgroup ne "macos")
         {
             if($Cmd!~/lynx|links/) {
-                $Cmd .= "  >\"$TMP_DIR/null\" 2>&1 &";
+                $Cmd .= "  >\"/dev/null\" 2>&1 &";
             }
         }
         system($Cmd);
@@ -16179,7 +16468,7 @@
     }
     if($Priority eq "Low")
     {
-        $Report .= get_Report_ChangedConstants($Level);
+        $Report .= get_Report_ChangedConstants("Low", $Level);
         if($ReportFormat eq "html")
         {
             if($CheckImpl and $Level eq "Binary") {
@@ -16187,6 +16476,10 @@
             }
         }
     }
+    if($Priority eq "Safe")
+    {
+        $Report .= get_Report_ChangedConstants("Safe", $Level);
+    }
     if($ReportFormat eq "html")
     {
         if($Report)
@@ -16427,6 +16720,52 @@
     "Version"
 );
 
+sub constantFilter($$$)
+{
+    my ($Name, $Value, $Level) = @_;
+    
+    if($Level eq "Binary")
+    {
+        foreach (keys(%IgnoreConstant))
+        {
+            if($Name=~/(\A|_)$_(_|\Z)/)
+            { # version
+                return 1;
+            }
+            if(/\A[A-Z].*[a-z]\Z/)
+            {
+                if($Name=~/(\A|[a-z])$_([A-Z]|\Z)/)
+                { # version
+                    return 1;
+                }
+            }
+        }
+        if($Name=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
+        { # version
+            return 1;
+        }
+        if($Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Value=~/[\/\\]\w+[\/\\]\w+/)
+        { # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
+            return 1;
+        }
+        if($Value=~/\A\(*[a-z_]+(\s+|\|)/i)
+        { # static int gcry_pth_init ( void) { return ...
+          # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
+            return 1;
+        }
+        if($Value=~/\(/i and $Value!~/\A[\"\']/i)
+        { # foo(p)
+            return 1;
+        }
+        if($Value=~/\A[a-z]+\w*\Z/i)
+        { # asn1_node_st
+            return 1;
+        }
+    }
+    
+    return 0;
+}
+
 sub mergeConstants($)
 {
     my $Level = $_[0];
@@ -16436,64 +16775,48 @@
         { # skipped by the user
             next;
         }
-        if(not defined $Constants{2}{$Constant}{"Value"}
-        or $Constants{2}{$Constant}{"Value"} eq "")
-        { # empty value
-            next;
-        }
+        
         my $Header = $Constants{1}{$Constant}{"Header"};
         if(not is_target_header($Header, 1)
         and not is_target_header($Header, 2))
         { # user-defined header
             next;
         }
-        my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
-        $Old_Value = $Old_Value_Pure = uncoverConstant(1, $Constant);
-        $New_Value = $New_Value_Pure = uncoverConstant(2, $Constant);
+        
+        my $Old_Value = uncoverConstant(1, $Constant);
+        
+        if(constantFilter($Constant, $Old_Value, $Level))
+        { # separate binary and source problems
+            next;
+        }
+        
+        if(not defined $Constants{2}{$Constant}{"Value"})
+        { # removed
+            %{$CompatProblems_Constants{$Level}{$Constant}{"Removed_Constant"}} = (
+                "Target"=>$Constant,
+                "Old_Value"=>$Old_Value  );
+            next;
+        }
+        
+        if($Constants{2}{$Constant}{"Value"} eq "")
+        { # empty value
+          # TODO: implement a rule
+            next;
+        }
+        
+        my $New_Value = uncoverConstant(2, $Constant);
+        
+        my $Old_Value_Pure = $Old_Value;
+        my $New_Value_Pure = $New_Value;
+        
         $Old_Value_Pure=~s/(\W)\s+/$1/g;
         $Old_Value_Pure=~s/\s+(\W)/$1/g;
         $New_Value_Pure=~s/(\W)\s+/$1/g;
         $New_Value_Pure=~s/\s+(\W)/$1/g;
+        
         next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
         if($New_Value_Pure ne $Old_Value_Pure)
         { # different values
-            if($Level eq "Binary")
-            {
-                foreach (keys(%IgnoreConstant))
-                {
-                    if($Constant=~/(\A|_)$_(_|\Z)/)
-                    { # ignore library version
-                        next;
-                    }
-                    if(/\A[A-Z].*[a-z]\Z/)
-                    {
-                        if($Constant=~/(\A|[a-z])$_([A-Z]|\Z)/)
-                        { # ignore library version
-                            next;
-                        }
-                    }
-                }
-                if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
-                { # ignore library version
-                    next;
-                }
-                if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
-                { # ignoring path defines:
-                  #  /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
-                    next;
-                }
-                if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
-                { # ignore source defines:
-                  #  static int gcry_pth_init ( void) { return ...
-                  #  (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
-                    next;
-                }
-                if($Old_Value=~/\(/i and $Old_Value!~/\A[\"\']/i)
-                { # ignore source defines:
-                  #  foo(p)
-                    next;
-                }
-            }
             if(convert_integer($Old_Value) eq convert_integer($New_Value))
             { # 0x0001 and 0x1, 0x1 and 1 equal constants
                 next;
@@ -16506,12 +16829,44 @@
             { # NULL => 0
                 next;
             }
-            %{$ProblemsWithConstants{$Level}{$Constant}} = (
+            %{$CompatProblems_Constants{$Level}{$Constant}{"Changed_Constant"}} = (
                 "Target"=>$Constant,
                 "Old_Value"=>$Old_Value,
                 "New_Value"=>$New_Value  );
         }
     }
+    
+    foreach my $Constant (keys(%{$Constants{2}}))
+    {
+        if(not defined $Constants{1}{$Constant}{"Value"})
+        {
+            if($SkipConstants{2}{$Constant})
+            { # skipped by the user
+                next;
+            }
+            
+            my $Header = $Constants{2}{$Constant}{"Header"};
+            if(not is_target_header($Header, 1)
+            and not is_target_header($Header, 2))
+            { # user-defined header
+                next;
+            }
+            
+            my $New_Value = uncoverConstant(2, $Constant);
+            if(not defined $New_Value or $New_Value eq "") {
+                next;
+            }
+            
+            if(constantFilter($Constant, $New_Value, $Level))
+            { # separate binary and source problems
+                next;
+            }
+            
+            %{$CompatProblems_Constants{$Level}{$Constant}{"Added_Constant"}} = (
+                "Target"=>$Constant,
+                "New_Value"=>$New_Value  );
+        }
+    }
 }
 
 sub convert_integer($)
@@ -16664,7 +17019,8 @@
     "move_panel" => "libpanel",
     "XOpenDisplay" => "libX11",
     "resize_term" => "libncurses",
-    "clock_gettime" => "librt"
+    "clock_gettime" => "librt",
+    "crypt" => "libcrypt"
 );
 
 sub find_SymbolLibs($$)
@@ -17557,7 +17913,7 @@
         next if(not -d $DevelPath);
         # search for all header files in the /usr/include
         # with or without extension (ncurses.h, QtCore, ...)
-        @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f"));
+        push(@SysHeaders, cmd_find($DevelPath,"f"));
         foreach my $Link (cmd_find($DevelPath,"l"))
         { # add symbolic links
             if(-f $Link) {
@@ -17568,14 +17924,13 @@
     foreach my $DevelPath (@{$SystemPaths{"lib"}})
     { # search for config headers in the /usr/lib
         next if(not -d $DevelPath);
-        foreach (cmd_find($DevelPath,"f"))
+        foreach (cmd_find($DevelPath,"f",'\.h(pp|xx)?\Z|\/include\/',"",1))
         {
-            if(not /\/(gcc|jvm|syslinux|kbd|parrot|xemacs)/)
-            {
-                if(/\.h\Z|\/include\//) {
-                    push(@SysHeaders, $_);
-                }
+            if(/\/(gcc|jvm|syslinux|kbd|parrot|xemacs)/)
+            { # skip useless headers
+                next;
             }
+            push(@SysHeaders, $_);
         }
     }
     get_prefixes_I(\@SysHeaders, \%SystemHeaders);
@@ -17610,7 +17965,7 @@
     return sort @Paths;
 }
 
-sub skip_lib($$)
+sub skipLib($$)
 {
     my ($Path, $LibVersion) = @_;
     return 1 if(not $Path or not $LibVersion);
@@ -17640,16 +17995,122 @@
     return 0;
 }
 
+sub specificHeader($$)
+{
+    my ($Header, $Spec) = @_;
+    my $Name = get_filename($Header);
+    
+    if($Spec eq "windows")
+    {# MS Windows
+        return 1 if($Name=~/(\A|[._-])(win|wince|wnt)(\d\d|[._-]|\Z)/i);
+        return 1 if($Name=~/([._-]w|win)(32|64)/i);
+        return 1 if($Name=~/\A(Win|Windows)[A-Z]/);
+        return 1 if($Name=~/\A(w|win|windows)(32|64|\.)/i);
+        my @Dirs = (
+            "win32",
+            "win64",
+            "win",
+            "windows",
+            "msvcrt"
+        ); # /gsf-win32/
+        if(my $DIRs = join("|", @Dirs)) {
+            return 1 if($Header=~/[\/\\](|[^\/\\]+[._-])($DIRs)(|[._-][^\/\\]+)([\/\\]|\Z)/i);
+        }
+    }
+    elsif($Spec eq "macos")
+    { # Mac OS
+        return 1 if($Name=~/(\A|[_-])mac[._-]/i);
+    }
+    
+    return 0;
+}
+
+sub skipAlienHeader($)
+{
+    my $Path = $_[0];
+    my $Name = get_filename($Path);
+    my $Dir = get_dirname($Path);
+    
+    if($Tolerance=~/2/)
+    { # 2 - skip internal headers
+        my @Terms = (
+            "p",
+            "priv",
+            "int",
+            "impl",
+            "implementation",
+            "internal",
+            "private",
+            "old",
+            "compat",
+            "debug",
+            "test",
+            "gen"
+        );
+        
+        my @Dirs = (
+            "private",
+            "priv",
+            "port",
+            "impl",
+            "internal",
+            "detail",
+            "details",
+            "old",
+            "compat",
+            "debug",
+            "config",
+            "compiler",
+            "platform",
+            "test"
+        );
+        
+        if(my $TERMs = join("|", @Terms)) {
+            return 1 if($Name=~/(\A|[._-])($TERMs)([._-]|\Z)/i);
+        }
+        if(my $DIRs = join("|", @Dirs)) {
+            return 1 if($Dir=~/(\A|[\/\\])(|[^\/\\]+[._-])($DIRs)(|[._-][^\/\\]+)([\/\\]|\Z)/i);
+        }
+        
+        return 1 if($Name=~/[a-z](Imp|Impl|I|P)(\.|\Z)/);
+    }
+    
+    if($Tolerance=~/1/)
+    { # 1 - skip non-Linux headers
+        if($OSgroup ne "windows")
+        {
+            if(specificHeader($Path, "windows")) {
+                return 1;
+            }
+        }
+        if($OSgroup ne "macos")
+        {
+            if(specificHeader($Path, "macos")) {
+                return 1;
+            }
+        }
+    }
+    
+    # valid
+    return 0;
+}
+
 sub skipHeader($$)
 {
     my ($Path, $LibVersion) = @_;
     return 1 if(not $Path or not $LibVersion);
-    if(not keys(%{$SkipHeaders{$LibVersion}})) {
-        return 0;
-    }
     if(defined $Cache{"skipHeader"}{$Path}) {
         return $Cache{"skipHeader"}{$Path};
     }
+    if(defined $Tolerance and $Tolerance=~/1|2/)
+    { # --tolerant
+        if(skipAlienHeader($Path)) {
+            return ($Cache{"skipHeader"}{$Path} = 1);
+        }
+    }
+    if(not keys(%{$SkipHeaders{$LibVersion}})) {
+        return 0;
+    }
     return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_));
 }
 
@@ -17683,6 +18144,7 @@
             }
         }
     }
+    
     return 0;
 }
 
@@ -17700,7 +18162,7 @@
     foreach my $Path (find_libs($Dir,"",1))
     {
         next if(ignore_path($Path));
-        next if(skip_lib($Path, $LibVersion));
+        next if(skipLib($Path, $LibVersion));
         registerObject($Path, $LibVersion);
     }
     $RegisteredObject_Dirs{$LibVersion}{$Dir} = 1;
@@ -17751,7 +18213,7 @@
 sub getSOPaths_Dest($$)
 {
     my ($Dest, $LibVersion) = @_;
-    if(skip_lib($Dest, $LibVersion)) {
+    if(skipLib($Dest, $LibVersion)) {
         return ();
     }
     if(-f $Dest)
@@ -17784,7 +18246,7 @@
             foreach my $Path (find_libs($Dest,"",""))
             {
                 next if(ignore_path($Path));
-                next if(skip_lib($Path, $LibVersion));
+                next if(skipLib($Path, $LibVersion));
                 registerObject($Path, $LibVersion);
                 $Libs{realpath($Path)}=1;
             }
@@ -17793,7 +18255,7 @@
                 foreach my $Path (cmd_find($Dest,"f"))
                 {
                     next if(ignore_path($Path));
-                    next if(skip_lib($Path, $LibVersion));
+                    next if(skipLib($Path, $LibVersion));
                     if(get_filename($Path)!~/\./
                     and cmd_file($Path)=~/(shared|dynamic)\s+library/i)
                     {
@@ -18235,7 +18697,8 @@
                 }
             }
         }
-        if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
+        if($TInfo{"Type"} eq "Typedef" and not $TInfo{"Artificial"}
+        and defined $TInfo{"BaseType"})
         {
             if(my $BTid = $TInfo{"BaseType"}{"Tid"})
             {
@@ -18246,7 +18709,7 @@
                 }
                 if($TInfo{"Name"} eq $BName)
                 { # typedef to "class Class"
-                    # should not be registered in TName_Tid
+                  # should not be registered in TName_Tid
                     next;
                 }
                 if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) {
@@ -18377,7 +18840,7 @@
 {
     my ($Path, $Type, $MaxDepth) = @_;
     # FIXME: correct the search pattern
-    return cmd_find($Path, $Type, ".*\\.".$LIB_EXT."[0-9.]*", $MaxDepth, 1);
+    return cmd_find($Path, $Type, '\.'.$LIB_EXT.'[0-9.]*\Z', $MaxDepth, 1);
 }
 
 sub createDescriptor($$)
@@ -18718,7 +19181,7 @@
         { # try to find gcc-X.Y
             foreach my $Path (@{$SystemPaths{"bin"}})
             {
-                if(my @GCCs = cmd_find($Path, "", ".*/gcc-[0-9.]*", 1, 1))
+                if(my @GCCs = cmd_find($Path, "", '/gcc-[0-9.]*\Z', 1, 1))
                 { # select the latest version
                     @GCCs = sort {$b cmp $a} @GCCs;
                     if(check_gcc($GCCs[0], "3"))
@@ -19554,23 +20017,33 @@
     initLogging(1);
     detect_default_paths("inc|lib|bin|gcc"); # complete analysis
     
-    # check the archive utilities
-    if($OSgroup eq "windows")
-    { # using zip
-        my $ZipCmd = get_CmdPath("zip");
-        if(not $ZipCmd) {
-            exitStatus("Not_Found", "can't find \"zip\"");
-        }
+    my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi";
+    $DumpPath .= ".".$AR_EXT; # gzipped by default
+    if($OutputDumpPath)
+    { # user defined path
+        $DumpPath = $OutputDumpPath;
     }
-    else
-    { # using tar and gzip
-        my $TarCmd = get_CmdPath("tar");
-        if(not $TarCmd) {
-            exitStatus("Not_Found", "can't find \"tar\"");
+    my $Archive = ($DumpPath=~s/\Q.$AR_EXT\E\Z//g);
+    
+    if(not $Archive and not $StdOut)
+    { # check archive utilities
+        if($OSgroup eq "windows")
+        { # using zip
+            my $ZipCmd = get_CmdPath("zip");
+            if(not $ZipCmd) {
+                exitStatus("Not_Found", "can't find \"zip\"");
+            }
         }
-        my $GzipCmd = get_CmdPath("gzip");
-        if(not $GzipCmd) {
-            exitStatus("Not_Found", "can't find \"gzip\"");
+        else
+        { # using tar and gzip
+            my $TarCmd = get_CmdPath("tar");
+            if(not $TarCmd) {
+                exitStatus("Not_Found", "can't find \"tar\"");
+            }
+            my $GzipCmd = get_CmdPath("gzip");
+            if(not $GzipCmd) {
+                exitStatus("Not_Found", "can't find \"gzip\"");
+            }
         }
     }
     
@@ -19696,13 +20169,6 @@
     }
     else
     { # write to gzipped file
-        my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi";
-        $DumpPath .= ".".$AR_EXT; # gzipped by default
-        if($OutputDumpPath)
-        { # user defined path
-            $DumpPath = $OutputDumpPath;
-        }
-        my $Archive = ($DumpPath=~s/\Q.$AR_EXT\E\Z//g);
         my ($DDir, $DName) = separate_path($DumpPath);
         my $DPath = $TMP_DIR."/".$DName;
         if(not $Archive) {
@@ -20317,7 +20783,7 @@
     }
     if(not $CheckObjectsOnly)
     {
-        mergeSignatures($Level);
+        mergeSymbols($Level);
         if(keys(%{$CheckedSymbols{$Level}})) {
             mergeConstants($Level);
         }
@@ -20469,6 +20935,10 @@
     { # --test && --use-dumps == --test-dump
         $TestDump = 1;
     }
+    if($Tolerant)
+    { # enable all
+        $Tolerance = 1234;
+    }
     if($Help)
     {
         HELP_MESSAGE();