Improved a module to compare operating systems. Added -mingw-compatible and -skip-unidentified options. Improved support for C++ keywords in C code. The -cpp-compatible option is now enabled by default. Improved support for Windows. Improved support for MinGW.
diff --git a/abi-compliance-checker.pl b/abi-compliance-checker.pl
index 14b83a7..0dece16 100644
--- a/abi-compliance-checker.pl
+++ b/abi-compliance-checker.pl
@@ -85,14 +85,14 @@
 $OutputReportPath, $OutputDumpPath, $ShowRetVal, $SystemRoot_Opt, $DumpSystem,
 $CmpSystems, $TargetLibsPath, $Debug, $CrossPrefix, $UseStaticLibs, $NoStdInc,
 $TargetComponent_Opt, $TargetSysInfo, $TargetHeader, $ExtendedCheck, $Quiet,
-$SkipHeadersPath, $CppCompat, $LogMode, $StdOut, $ListAffected, $ReportFormat,
+$SkipHeadersPath, $CxxCompat, $LogMode, $StdOut, $ListAffected, $ReportFormat,
 $UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath,
 $SourceReportPath, $UseXML, $SortDump, $DumpFormat,
 $ExtraInfo, $ExtraDump, $Force, $Tolerance, $Tolerant, $SkipSymbolsListPath,
-$CheckInfo, $Quick, $AffectLimit, $AllAffected, $CppIncompat,
+$CheckInfo, $Quick, $AffectLimit, $AllAffected, $CxxIncompat,
 $SkipInternalSymbols, $SkipInternalTypes, $TargetArch, $GccOptions,
 $TypesListPath, $SkipTypesListPath, $CheckPrivateABI, $CountSymbols, $OldStyle,
-$DisableQuickEmptyReport, $SkipTypedefUncover);
+$DisableQuickEmptyReport, $SkipTypedefUncover, $MinGWCompat, $SkipUnidentified);
 
 my $CmdName = get_filename($0);
 my %OS_LibExt = (
@@ -228,8 +228,9 @@
   "test!" => \$TestTool,
   "test-dump!" => \$TestDump,
   "debug!" => \$Debug,
-  "cpp-compatible!" => \$CppCompat,
-  "cpp-incompatible!" => \$CppIncompat,
+  "cpp-compatible!" => \$CxxCompat,
+  "cxx-incompatible|cpp-incompatible!" => \$CxxIncompat,
+  "mingw-compatible!" => \$MinGWCompat,
   "p|params=s" => \$ParamNamesPath,
   "relpath1|relpath=s" => \$RelativeDirectory{1},
   "relpath2=s" => \$RelativeDirectory{2},
@@ -250,6 +251,7 @@
   "force!" => \$Force,
   "tolerance=s" => \$Tolerance,
   "tolerant!" => \$Tolerant,
+  "skip-unidentified!" => \$SkipUnidentified,
   "check!" => \$CheckInfo,
   "quick!" => \$Quick,
   "disable-quick-empty-report!" => \$DisableQuickEmptyReport,
@@ -550,9 +552,11 @@
       ABI of operating systems and configure the dumping process.
 
   -cmp-systems -d1 sys_dumps/NAME1/ARCH -d2 sys_dumps/NAME2/ARCH
-      Compare two system ABI dumps. Create compatibility reports for each
-      library and the common HTML report including the summary of test
-      results for all checked libraries. Report will be generated to:
+      Compare two ABI dumps of a system. Create compatibility reports for
+      each system library and the common HTML report including the summary
+      of test results for all checked libraries.
+      
+      Summary report will be generated to:
           sys_compat_reports/NAME1_to_NAME2/ARCH
 
   -libs-list PATH
@@ -631,7 +635,7 @@
 
   -test-dump
       Test ability to create, read and compare ABI dumps.
-      
+
   -debug
       Debugging mode. Print debug info on the screen. Save intermediate
       analysis stages in the debug directory:
@@ -640,12 +644,16 @@
       Also consider using --dump option for debugging the tool.
 
   -cpp-compatible
-      If your header files are written in C language and can be compiled
-      by the G++ compiler (i.e. don't use C++ keywords), then you can tell
-      the tool about this and speedup the analysis.
-      
-  -cpp-incompatible
-      Set this option if input C header files use C++ keywords.
+      Do nothing.
+
+  -cxx-incompatible
+      Set this option if input C header files use C++ keywords. The tool
+      will try to replace such keywords at preprocessor stage and replace
+      them back in the final TU dump.
+  
+  -mingw-compatible
+      If input header files are compatible with the MinGW GCC compiler,
+      then you can tell the tool about this and speedup the analysis .
 
   -p|-params PATH
       Path to file with the function parameter names. It can be used
@@ -659,7 +667,7 @@
   -relpath PATH
       Replace {RELPATH} macros to PATH in the XML-descriptor used
       for dumping the library ABI (see -dump option).
-  
+
   -relpath1 PATH
       Replace {RELPATH} macros to PATH in the 1st XML-descriptor (-d1).
 
@@ -737,7 +745,8 @@
       from the translation unit.
       
   -force
-      Try to use this option if the tool doesn't work.
+      Try to enable this option if the tool checked zero
+      types and symbols in header files.
       
   -tolerance LEVEL
       Apply a set of heuristics to successfully compile input
@@ -751,7 +760,12 @@
           
   -tolerant
       Enable highest tolerance level [1234].
-      
+  
+  -skip-unidentified
+      Skip header files in 'headers' and 'include_preamble' sections
+      of the XML descriptor that cannot be found. This is useful if
+      you are trying to use the same descriptor for different targets.
+  
   -check
       Check completeness of the ABI dump.
       
@@ -1372,6 +1386,7 @@
 my %Library_Needed= (
   "1"=>{},
   "2"=>{} );
+my $DisabledMSVCUnmangling = undef;
 
 # Extra Info
 my %UndefinedSymbols;
@@ -6492,7 +6507,7 @@
                 $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
             }
         }
-        else {
+        elsif(not defined $SkipUnidentified) {
             exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
         }
     }
@@ -6520,7 +6535,7 @@
                 next if(skipHeader($Header_Path, $LibVersion));
                 push_U($Include_Preamble{$LibVersion}, $Header_Path);
             }
-            else {
+            elsif($SkipUnidentified) {
                 exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
             }
         }
@@ -7343,9 +7358,21 @@
 {
     if($_[0]=~/\A\?/)
     { # MSVC mangling
+        if(defined $DisabledMSVCUnmangling) {
+            return @_;
+        }
         my $UndNameCmd = get_CmdPath("undname");
-        if(not $UndNameCmd) {
-            exitStatus("Not_Found", "can't find \"undname\"");
+        if(not $UndNameCmd)
+        {
+            if($OSgroup eq "windows") {
+                exitStatus("Not_Found", "can't find \"undname\"");
+            }
+            elsif(not defined $DisabledMSVCUnmangling)
+            {
+                printMsg("WARNING", "can't find \"undname\", disable MSVC unmangling");
+                $DisabledMSVCUnmangling = 1;
+                return @_;
+            }
         }
         writeFile("$TMP_DIR/unmangle", join("\n", @_));
         return split(/\n/, `$UndNameCmd 0x8386 \"$TMP_DIR/unmangle\"`);
@@ -7887,6 +7914,7 @@
             "-D__possibly_notnullterminated=\" \"",
             "-D__nullterminated=\" \"",
             "-D__nullnullterminated=\" \"",
+            "-D__assume=\" \"",
             "-D__w64=\" \"",
             "-D__ptr32=\" \"",
             "-D__ptr64=\" \"",
@@ -7918,17 +7946,21 @@
             "-DSORTPP_PASS");
         if($Arch eq "x86")
         {
+            $MinGW_Opts{"-D_X86_=300"}=1;
             $MinGW_Opts{"-D_M_IX86=300"}=1;
         }
         elsif($Arch eq "x86_64")
         {
+            $MinGW_Opts{"-D_AMD64_=300"}=1;
             $MinGW_Opts{"-D_M_AMD64=300"}=1;
             $MinGW_Opts{"-D_M_X64=300"}=1;
         }
-        elsif($Arch eq "ia64") {
+        elsif($Arch eq "ia64")
+        {
+            $MinGW_Opts{"-D_IA64_=300"}=1;
             $MinGW_Opts{"-D_M_IA64=300"}=1;
         }
-        return join(" ", keys(%MinGW_Opts));
+        return join(" ", sort keys(%MinGW_Opts));
     }
     return "";
 }
@@ -8189,7 +8221,7 @@
     my $PreprocessCmd = getCompileCmd($HeaderPath, "-E", $IncStr);
     my $Content = undef;
     
-    if($OStarget eq "windows"
+    if(not defined $MinGWCompat and $OStarget eq "windows"
     and get_dumpmachine($GCC_PATH)=~/mingw/i
     and $MinGWMode{$Version}!=-1)
     { # modify headers to compile by MinGW
@@ -8215,29 +8247,48 @@
         }
     }
     
-    if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
-    and $CppMode{$Version}!=-1 and not $CppCompat and not $CPP_HEADERS)
+    if(defined $CxxIncompat and ($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
+    and $CppMode{$Version}!=-1 and not $CPP_HEADERS)
     { # rename C++ keywords in C code
-      # disable this code by -cpp-compatible option
+        printMsg("INFO", "Checking the code for C++ keywords");
         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;
+        my $Sentence_O = undef;
+        my $Sentence_N = undef;
+        my $Regex = undef;
         
-        while($Content=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*([\,\)\;\.\[]|\-\>|\:\s*\d))/$1$2c99_$3$4/g)
+        $Regex = qr/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*([\,\)\;\.\[]|\-\>|\:\s*\d))/;
+        while($Content=~/$Regex/)
         { # MATCH:
           # int foo(int new, int class, int (*new)(int));
           # int foo(char template[], char*);
           # unsigned private: 8;
           # DO NOT MATCH:
           # #pragma GCC visibility push(default)
-            $CppMode{$Version} = 1;
-            $Detected = "$1$2$3$4" if(not defined $Detected);
+            $Sentence_O = "$1$2$3$4";
+            $Sentence_N = "$1$2c99_$3$4";
+            
+            if($Sentence_O=~/\s+decltype\(/)
+            { # C++
+              # decltype(nullptr)
+                last;
+            }
+            else
+            {
+                $Content=~s/$Regex/$Sentence_N/g;
+                $CppMode{$Version} = 1;
+                if(not defined $Detected) {
+                    $Detected = $Sentence_O;
+                }
+            }
         }
         if($Content=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
         { # MATCH:
@@ -8331,6 +8382,9 @@
         if($CppMode{$Version}==1) {
             printMsg("INFO", "Using C++ compatibility mode");
         }
+        else {
+            printMsg("INFO", "C++ keywords in the C code are not found");
+        }
     }
         
     if($CppMode{$Version}==1
@@ -8546,24 +8600,8 @@
     { # failed to compile, but the TU dump still can be created
         if($Errors = readFile($TMP_DIR."/tu_errors"))
         { # try to recompile
-          # FIXME: handle other errors and try to recompile
-            if($CppMode{$Version}==1
-            and index($Errors, "c99_")!=-1
-            and not defined $CppIncompat)
-            { # disable c99 mode and try again
-                $CppMode{$Version}=-1;
-                
-                if($Debug)
-                {
-                    # printMsg("INFO", $Errors);
-                }
-                
-                printMsg("INFO", "Disabling C++ compatibility mode");
-                resetLogging($Version);
-                $TMP_DIR = tempdir(CLEANUP=>1);
-                return getDump();
-            }
-            elsif($AutoPreambleMode{$Version}!=-1
+          # FIXME: handle errors and try to recompile
+            if($AutoPreambleMode{$Version}!=-1
             and my $AddHeaders = detectPreamble($Errors, $Version))
             { # add auto preamble headers and try again
                 $AutoPreambleMode{$Version}=-1;
@@ -8595,17 +8633,17 @@
                     return getDump();
                 }
                 else {
-                    printMsg("WARNING", "Probably c++0x construction detected");
+                    printMsg("WARNING", "Probably c++0x element detected");
                 }
                 
             }
-            elsif($MinGWMode{$Version}==1)
-            { # disable MinGW mode and try again
-                $MinGWMode{$Version}=-1;
-                resetLogging($Version);
-                $TMP_DIR = tempdir(CLEANUP=>1);
-                return getDump();
-            }
+            #elsif($MinGWMode{$Version}==1)
+            #{ # disable MinGW mode and try again
+            #    $MinGWMode{$Version}=-1;
+            #    resetLogging($Version);
+            #    $TMP_DIR = tempdir(CLEANUP=>1);
+            #    return getDump();
+            #}
             writeLog($Version, $Errors);
         }
         else {
@@ -22825,7 +22863,8 @@
     "CrossGcc"=>$CrossGcc,
     "UseStaticLibs"=>$UseStaticLibs,
     "NoStdInc"=>$NoStdInc,
-    "CppCompat"=>$CppCompat,
+    "CxxIncompat"=>$CxxIncompat,
+    "SkipUnidentified"=>$SkipUnidentified,
     
     "BinaryOnly" => $BinaryOnly,
     "SourceOnly" => $SourceOnly